DIRECTORY Basics USING [ BITSHIFT, BITOR, BITAND ], BasicTime USING [ PulsesToSeconds, GetClockPulses ], Atom USING [ DottedPair, DottedPairNode, PropList, PutPropOnList, GetPropFromList, RemPropFromList ], CedarProcess USING [ CheckAbort, DoWithPriority ], ViewerIO USING [ CreateViewerStreams ], Terminal USING [ Virtual, GetColorMode, SetColor, GetColor, WaitForBWVerticalRetrace, ColorMode, GetRedMap, GetGreenMap, GetBlueMap, SetRedMap, SetGreenMap, SetBlueMap ], IO USING [ STREAM, PutF, PutRope, Flush, Close, GetLineRope, rope, time ], UserCredentials USING [ Get ], FS USING [ StreamOpen ], Rope USING [ ROPE, Index, Cat, Equal ] , Convert USING [ RopeFromReal, RopeFromCard ], Real USING [ Float, FixC, RoundC, FixI ], RealFns USING [ Sin, Cos, Power ], QuickViewer USING [ DrawInViewer, QuickView ], Imager USING [ Context, Rectangle, SetColor, Font, MaskRectangle, SetFont, SetXY, ShowRope ], ImagerColor USING [ ColorFromRGB, RGBFromHSL, RGB ], ImagerFont USING [ Find, Scale ], ImagerInterpress USING [ Close, Create, DoPage, Ref ], NamedColors USING [ RopeToHSL ], Pixels USING [ PixelBuffer, Extent, BYTE, ValueOp, Transfer, GetSampleSet, SampleSet, PutPixel, GetScanSeg, PutScanSeg, SampleSetSequence, SubMapSequence], Plane3d USING [ DistanceToPt ], ScanConvert USING [ GetColorProc, MappedRGB, DitheredRGB, PutLine ], ThreeDBasics USING [ ClipState, Context, NoneOut, OutCode, NatSequence, Pair, Quad, RGB, Rectangle, ShadingSequence, ShadingValue, ShapeInstance, ShapeSequence, Triple, Vertex, VertexSequence, VtxToRealSeqProc ], ThreeDScenes USING [ AddAlphaBuffer, AddDepthBuffer, AddShape, Create, DisplayFromImagerContext, DisplayFromVM, Error, FillInBackGround, FillViewPort, FindShape, GetShading, InitShades, NewShape, PlaceShape, PutShading, ReadScene, WriteScene, SetView, ShadingProcs, XfmPtToEyeSpace, XfmPtToDisplay ], ThreeDSurfaces USING [ Patch, PtrPatch, ShowObjects, ShowWireFrameObjects, PtrPatchSequence, ReadShape, CloneShape, GetPolyNormals, PatchProcs, PatchDisplayProc, RegisterSurfaceType ], Tilers USING [ FancyTiler], SolidTextures USING [ RopeToProc, GetLerpedVals ], AISAnimation USING [ GetAIS, PutAIS, StoreFiles ], Animation3D USING [ MoveInOrbit, MoveOnLine ], StandardPatches USING [ BezierExpand, BezierSubdivide, BezierDisplay, BezierDisplayLines ], ThreeDMisc USING [ ]; ThreeDMiscImpl: CEDAR MONITOR IMPORTS AISAnimation, Animation3D, Atom, Basics, BasicTime, CedarProcess, Convert, FS, Imager, ImagerColor, ImagerFont, ImagerInterpress, IO, NamedColors, Pixels, Plane3d, QuickViewer, Real, RealFns, Rope, ScanConvert, SolidTextures, StandardPatches, Terminal, ThreeDScenes, ThreeDSurfaces, Tilers, ViewerIO, UserCredentials EXPORTS ThreeDMisc ~ BEGIN Context: TYPE ~ ThreeDBasics.Context; Pair: TYPE ~ ThreeDBasics.Pair; -- RECORD [ x, y: REAL]; Triple: TYPE ~ ThreeDBasics.Triple; RGB: TYPE ~ ThreeDBasics.RGB; IntRGB: TYPE ~ RECORD[ r, g, b: CARDINAL]; IntRGBSequence: TYPE ~RECORD [ SEQUENCE length: NAT OF IntRGB ]; Rectangle: TYPE ~ ThreeDBasics.Rectangle; NatSequence: TYPE ~ ThreeDBasics.NatSequence; ClipState: TYPE ~ ThreeDBasics.ClipState; RGBtoPixelValue: PUBLIC PROC[context: REF Context, clr: RGB, values: Pixels.SampleSet _ NIL] RETURNS[ Pixels.SampleSet ] ~ { base: NAT _ IF context.alphaBuffer THEN 1 ELSE 0; IF values = NIL THEN values _ Pixels.GetSampleSet[5]; values[0] _ 0; SELECT context.renderMode FROM $FullColor, $Dorado24 => { values[0] _ Real.RoundC[clr.R*255.0]; values[1] _ Real.RoundC[clr.G*255.0]; values[2] _ Real.RoundC[clr.B*255.0]; values.length _ 3; }; $Grey => { values[0] _ Real.RoundC[(clr.R + clr.G + clr.B) / 3.0 * 255.0]; values.length _ 1; }; $Dithered, $PseudoColor => { values[0] _ ScanConvert.MappedRGB[ context.renderMode, [ Real.RoundC[clr.R*255.0], Real.RoundC[clr.G*255.0], Real.RoundC[clr.B*255.0] ] ]; values.length _ 1; }; ENDCASE => SIGNAL ThreeDScenes.Error[[$MisMatch, "Improper renderMode"]]; RETURN[values]; }; PutPixel: PUBLIC PROC[context: REF Context, x, y: NAT, clr: RGB] ~ { clrValues: Pixels.SampleSet _ RGBtoPixelValue[context, clr]; Pixels.PutPixel[context.display, x, y, clrValues]; }; ClipLineWithPlane: PUBLIC PROC[plane: ThreeDBasics.Quad, p1, p2: Triple] RETURNS[ insidePt, clippedPt: Triple, state: 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] ~ { clrValues: Pixels.SampleSet _ RGBtoPixelValue[context, clr]; p1, p2: Triple; code1, code2, orOfCodes : ThreeDBasics.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] ], ThreeDBasics.OutCode ]; IF orOfCodes # ThreeDBasics.NoneOut -- not all inside? THEN { andOfCodes: ThreeDBasics.OutCode _ LOOPHOLE[ Basics.BITAND[LOOPHOLE[code1], LOOPHOLE[code2] ], ThreeDBasics.OutCode ]; IF andOfCodes # ThreeDBasics.NoneOut -- all outside? THEN RETURN[] ELSE { -- clipping needed, do it clipState: 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, NIL, p1]; -- xfm to screen p2 _ ThreeDScenes.XfmPtToDisplay[context, NIL, p2]; 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 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] ~ { timeX10: REAL _ 10.0 * (BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]] - startTime); RETURN[ Rope.Cat[ Convert.RopeFromReal[ Real.FixC[timeX10] / 10.0 ], " secs. " ] ]; }; CurrentTime: PROC[] RETURNS[REAL] ~ { RETURN[ BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]] ]; }; UpdateDisplay: PUBLIC PROC[context: REF Context] RETURNS[changed: BOOLEAN] ~ { GetDisplay: PROC[ imagerCtx: Imager.Context ] ~ { ThreeDScenes.DisplayFromImagerContext[context, imagerCtx]; IF context.depthBuffer THEN ThreeDScenes.AddDepthBuffer[context]; IF context.alphaBuffer THEN ThreeDScenes.AddAlphaBuffer[context]; }; changed _ FALSE; IF context.viewer # NIL THEN { view: REF QuickViewer.QuickView _ NARROW[context.viewer]; IF view.changed THEN { view.changed _ FALSE; changed _ TRUE; QuickViewer.DrawInViewer[view, GetDisplay]; -- gets up-to-date imager context FOR i: NAT IN [0..context.shapes.length) DO context.shapes[i].vtcesInValid _ TRUE; context.shapes[i].shadingInValid _ TRUE; ENDLOOP; ThreeDScenes.SetView[ -- get new screen dimensions into transformations context: context, eyePoint: context.eyePoint, ptOfInterest: context.ptOfInterest, fieldOfView: context.fieldOfView, rollAngle: context.rollAngle, upDirection: context.upDirection, hitherLimit: context.hitherLimit, yonLimit: context.yonLimit ]; }; }; }; CopyContextData: PUBLIC PROC [dstCtx, srcCtx: REF 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; FOR list: Atom.PropList _ srcCtx.props, list.rest UNTIL list = NIL DO -- make new proplist element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; dstCtx.props _ CONS[element, dstCtx.props]; ENDLOOP; }; CopyDisplayData: PUBLIC PROC [dstCtx, srcCtx: REF Context] ~ { dstCtx.display _ srcCtx.display; dstCtx.display.pixels _ NEW[ Pixels.SubMapSequence[srcCtx.display.pixels.length] ]; FOR i: NAT IN [0..srcCtx.display.pixels.length) DO dstCtx.display.pixels[i] _ srcCtx.display.pixels[i]; ENDLOOP; dstCtx.display.props _ NIL; -- make new proplist FOR list: Atom.PropList _ srcCtx.display.props, list.rest UNTIL list = NIL DO element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; dstCtx.display.props _ CONS[element, dstCtx.display.props]; ENDLOOP; dstCtx.alphaBuffer _ srcCtx.alphaBuffer; dstCtx.depthBuffer _ srcCtx.depthBuffer; }; 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"]]; }; RegisterSurfaceDisplayProc: PUBLIC PROC[context: REF Context, type: ATOM, proc: ThreeDSurfaces.PatchDisplayProc, lines: BOOLEAN _ FALSE ] ~ { procRecord: REF ThreeDSurfaces.PatchProcs _ NARROW[ Atom.GetPropFromList[context.props, type] ]; IF lines THEN procRecord.displayLines _ proc ELSE procRecord.display _ proc; ThreeDSurfaces.RegisterSurfaceType[ context, type, procRecord]; }; 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 Context, clr: RGB] RETURNS[Pixels.BYTE] ~ { value: NAT _ ScanConvert.MappedRGB[context.renderMode, clr]; RETURN[value]; }; SetNamedColor: PUBLIC PROC [imagerCtx: Imager.Context, color: Rope.ROPE] ~ { clr: RGB _ ImagerColor.RGBFromHSL[ NamedColors.RopeToHSL[color] ]; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[clr] ]; }; SetRGBColor: PUBLIC PROC [imagerCtx: Imager.Context, clr: RGB] ~ { Imager.SetColor[ imagerCtx, 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 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; }; ShowMapOnLog: PUBLIC PROC [context: REF Context, vt: Terminal.Virtual] ~ { RopeFromQuad: PROC[ i, r, g, b: CARD] RETURNS[ Rope.ROPE ] ~ { output: Rope.ROPE _ Rope.Cat[ " \t ", Convert.RopeFromCard[i], " ", Convert.RopeFromCard[r], " " ]; output _ Rope.Cat[ output, Convert.RopeFromCard[g], " ", Convert.RopeFromCard[b] ]; RETURN[ output ]; }; log: IO.STREAM _ NARROW[ Atom.GetPropFromList[context.props, $Log] ]; state: Terminal.ColorMode _ vt.GetColorMode[]; maxVal: REAL _ IF state.full THEN 255.0 ELSE Real.Float[Basics.BITSHIFT[1, state.bitsPerPixelChannelA] - 1]; FOR i: NAT IN [ 0 .. Real.FixC[maxVal] ] DO -- linear ramp exponentiated jr, jg, jb: CARD; IF Terminal.GetColorMode[vt].full THEN { jr _ vt.GetRedMap[i]; jg _ vt.GetGreenMap[i]; jb _ vt.GetBlueMap[i]; } ELSE [jr, jg, jb] _ vt.GetColor[i]; IF log # NIL THEN { log.PutRope[ RopeFromQuad[ i, jr, jg, jb ] ]; IF (i/4) * 4 = i THEN log.PutRope["\n"]; FlushLog[context]; }; 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 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] ]; SELECT context.renderMode FROM $FullColor, $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 $FullColor, $Dorado24 => { scanSeg[0][x] _ expTableR[scanSeg[0][x]]; scanSeg[1][x] _ expTableG[scanSeg[1][x]]; scanSeg[2][x] _ expTableB[scanSeg[2][x]]; }; $Grey => scanSeg[0][x] _ expTableG[scanSeg[0][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 Context, percent: REAL] ~ { Action: PROC[] ~ { scanSeg: REF Pixels.SampleSetSequence _ NIL; maxValue: REAL _ 255.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 $FullColor, $Dorado24 => { scale: REAL; redVal: CARDINAL _ scanSeg[0][x]; grnVal: CARDINAL _ scanSeg[1][x]; bluVal: CARDINAL _ scanSeg[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[0][x] _ redVal; scanSeg[1][x] _ grnVal; scanSeg[2][x] _ bluVal; }; ENDCASE => SIGNAL ThreeDScenes.Error[[$MisMatch, "Only for full color"]]; 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.]]; 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 Context, x, y: REAL, rope: Rope.ROPE, color: Rope.ROPE _ NIL, fontRope: Rope.ROPE _ NIL, size: REAL _ 20] ~ { DoRope: PROC[imagerCtx: Imager.Context] ~ { font: Imager.Font; IF color = NIL THEN color _ "Vivid Yellow"; SetNamedColor[imagerCtx, color ]; 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]; }; QuickViewer.DrawInViewer[ -- gets up-to-date imager context NARROW[context.viewer], DoRope ]; }; DitherImage: PUBLIC PROC[dstContext, rgbContext: REF 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[$PseudoColor, 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 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 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]; 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 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 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; }; SetBackgroundColor: PUBLIC PROC [context: REF Context, color: Rope.ROPE] ~ { bkgrdColor: REF RGB _ NEW[ RGB _ ImagerColor.RGBFromHSL[ NamedColors.RopeToHSL[color] ] ]; context.props _ Atom.PutPropOnList[context.props, $BackGround, bkgrdColor]; -- set color }; SetBackgroundImage: PUBLIC PROC [context: REF Context, aisFile: Rope.ROPE] ~ { bkGrdCtx: REF Context _ ThreeDScenes.Create[]; ThreeDScenes.DisplayFromVM[ bkGrdCtx, Real.RoundC[context.viewPort.w], Real.RoundC[context.viewPort.h], context.renderMode ]; IF context.depthBuffer THEN ThreeDScenes.AddDepthBuffer[bkGrdCtx]; IF context.alphaBuffer THEN ThreeDScenes.AddAlphaBuffer[bkGrdCtx]; [] _ AISAnimation.GetAIS[bkGrdCtx, aisFile]; context.props _ Atom.PutPropOnList[context.props, $BackGround, NEW[Pixels.PixelBuffer _ bkGrdCtx.display] ]; }; SetBackgroundContext: PUBLIC PROC [context, bkGrdCtx: REF Context ] ~ { context.props _ Atom.PutPropOnList[context.props, $BackGround, NEW[Pixels.PixelBuffer _ bkGrdCtx.display] ]; }; GetBackgroundColor: PUBLIC PROC [context: REF 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 ThreeDBasics.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 ThreeDBasics.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 ThreeDBasics.ShapeInstance _ ThreeDScenes.NewShape[shapeName]; vtcesPerSide: NAT _ squaresPerSide + 1; shape.numSurfaces _ squaresPerSide * squaresPerSide; shape.vertex _ NEW[ ThreeDBasics.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[ThreeDBasics.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 IF surface[i] = NIL THEN surface[i] _ NEW[ThreeDSurfaces.PtrPatch]; surface[i].vtxPtr _ NEW[NatSequence[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.] ] ~ { shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.NewShape[shapeName]; cloneShape: REF ThreeDBasics.ShapeInstance _ NIL; shape.fileName _ PrependWorkingDirectory[context, fileName]; FOR i: NAT IN [0..context.shapes.length) DO -- same data as another shape? IF Rope.Equal[shape.fileName, context.shapes[i].fileName] THEN cloneShape _ context.shapes[i]; ENDLOOP; IF cloneShape # NIL -- save data reads if previously read THEN ThreeDSurfaces.CloneShape[ shape, cloneShape ] ELSE ThreeDSurfaces.ReadShape[ shape, shape.fileName ]; ThreeDScenes.PlaceShape[shape, position]; context.shapes _ ThreeDScenes.AddShape[context.shapes, shape]; IF Atom.GetPropFromList[context.props, shape.type] = NIL THEN RegisterSurfaceType[context, shape.type]; }; SetFacetedColor: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, color: RGB] ~ { shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; IF shape # NIL THEN { patchInfo: REF ThreeDBasics.ShadingSequence _ NARROW[ ThreeDScenes.GetShading[ shape, $PatchColors ] ]; IF patchInfo = NIL THEN patchInfo _ NEW[ThreeDBasics.ShadingSequence[shape.numSurfaces] ] ELSE IF ThreeDScenes.GetShading[ shape, $PatchColorsInFile ] # NIL THEN SIGNAL ThreeDScenes.Error[[$MisMatch, "Patches individually colored"]]; FOR i: NAT IN [0..shape.numSurfaces) DO patchInfo[i] _ NEW[ ThreeDBasics.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 ]; ThreeDSurfaces.GetPolyNormals[shape ! ThreeDScenes.Error => IF reason.code = $MisMatch THEN CONTINUE ]; }; }; SetSmoothColor: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, color: RGB] ~ { shape: REF ThreeDBasics.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, $VertexColorsInFile ] # NIL THEN SIGNAL ThreeDScenes.Error[[$MisMatch, "Vertices individually colored"]]; shape.shade _ ThreeDScenes.InitShades[ shape ]; -- color vtces }; }; SetLinesColor: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, color: RGB] ~ { shape: REF ThreeDBasics.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, $VertexColorsInFile ] # 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 ThreeDBasics.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 ThreeDBasics.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 ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; shadeProc: ScanConvert.GetColorProc _ SolidTextures.RopeToProc[procName]; storeProc: ThreeDBasics.VtxToRealSeqProc _ SolidTextures.GetLerpedVals; ThreeDScenes.PutShading[ shape, $ShadingProcs, NEW[ ThreeDScenes.ShadingProcs _ [ storeProc, shadeProc ] ] ]; }; GetShadingProcs: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, storeProc: ThreeDBasics.VtxToRealSeqProc, shadeProc: ScanConvert.GetColorProc] ~{ shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; ThreeDScenes.PutShading[ shape, $ShadingProcs, NEW[ ThreeDScenes.ShadingProcs _ [ storeProc, shadeProc ] ] ]; }; CombineBoxes: PUBLIC PROC[context: REF Context] ~ { -- get combined bounding box context.extentCovered _ [LAST[NAT], 0, LAST[NAT], 0]; FOR i: NAT IN [0..context.shapes.length) DO IF context.shapes[i] # NIL AND Atom.GetPropFromList[context.shapes[i].props, $Hidden] = NIL AND context.shapes[i].surface # NIL AND context.shapes[i].clipState # out THEN { IF context.extentCovered.left > context.shapes[i].screenExtent.left THEN context.extentCovered.left _ context.shapes[i].screenExtent.left; IF context.extentCovered.right < context.shapes[i].screenExtent.right THEN context.extentCovered.right _ context.shapes[i].screenExtent.right; IF context.extentCovered.bottom > context.shapes[i].screenExtent.bottom THEN context.extentCovered.bottom _ context.shapes[i].screenExtent.bottom; IF context.extentCovered.top < context.shapes[i].screenExtent.top THEN context.extentCovered.top _ context.shapes[i].screenExtent.top; }; ENDLOOP; }; 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.PutF[ output, " -- %g - Created by: %g at %g\n\n", IO.rope[fileName], IO.rope[UserCredentials.Get[].name], IO.time[] ]; 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, streamOptions: [FALSE, TRUE, TRUE, TRUE, TRUE], 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 Context _ ThreeDScenes.Create[]; bufferCtx.display _ context.display; bufferCtx.renderMode _ context.renderMode; bufferCtx.alphaBuffer _ context.alphaBuffer; bufferCtx.props _ Atom.PutPropOnList[bufferCtx.props, $WDir, wDir]; bufferCtx.props _ Atom.PutPropOnList[bufferCtx.props, $Log, log]; time _ CurrentTime[]; RestoreFromFile[bufferCtx, fileName]; IF log # NIL THEN log.PutRope[ Rope.Cat[ "Setup Time: ", ElapsedTime[time], "\n"] ]; MakeFrame[bufferCtx]; bufferCtx _ NIL; }; MakeFrame: PUBLIC PROC[context: REF Context] ~ { time: REAL _ CurrentTime[]; log: IO.STREAM _ NARROW[ Atom.GetPropFromList[context.props, $Log] ]; [] _ UpdateDisplay[context]; 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[ " Frame Time: ", ElapsedTime[time], "\n\n"] ]; FlushLog[context]; }; }; MakeHiResFrame: PUBLIC PROC[context: REF Context, width, height: NAT, name: Rope.ROPE] ~ { log: IO.STREAM _ NARROW[ Atom.GetPropFromList[context.props, $Log] ]; hiResCtxt: REF Context _ ThreeDScenes.Create[]; ThreeDScenes.DisplayFromVM[hiResCtxt, width, height]; -- get display memory IF context.alphaBuffer THEN ThreeDScenes.AddAlphaBuffer[hiResCtxt]; IF context.depthBuffer THEN ThreeDScenes.AddDepthBuffer[hiResCtxt]; 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; MakeFrame[hiResCtxt]; AISAnimation.PutAIS[hiResCtxt, name ]; -- store resulting image }; MakeInterpressPage: PUBLIC PROC[context: REF Context, fileName: Rope.ROPE] ~ { ipCtxt: REF Context _ ThreeDScenes.Create[]; ipRef: ImagerInterpress.Ref _ ImagerInterpress.Create[ PrependWorkingDirectory[context, fileName] ]; scale: REAL _ 1.0 / (72.0 * 39.37); -- meters per pt. Action: PROC[imagerCtx: Imager.Context] ~ { bkgrdClr: REF RGB _ NARROW[ Atom.GetPropFromList[ipCtxt.props, $BackGround] ! ANY => SIGNAL ThreeDScenes.Error[[$MisMatch, "Interpress needs constant background"]] ]; ipCtxt.props _ Atom.PutPropOnList[ipCtxt.props, $ImagerCtx, imagerCtx]; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[bkgrdClr^] ]; Imager.MaskRectangle[ imagerCtx, ipCtxt.viewPort ]; ThreeDSurfaces.ShowObjects[ ipCtxt ]; }; CopyContextData[ipCtxt, context]; ipCtxt.renderMode _ $Interpress; ipCtxt.alphaBuffer _ FALSE; ipCtxt.depthBuffer _ FALSE; ImagerInterpress.DoPage[ipRef, Action, scale]; ImagerInterpress.Close[ipRef]; }; ShowShapes: PUBLIC PROC[context: REF Context] ~ { Action: PROC ~ { ThreeDSurfaces.ShowObjects[ context: context, frontToBack: context.alphaBuffer ] }; CedarProcess.DoWithPriority[background, Action]; }; ShowWireFrameShapes: PUBLIC PROC[context: REF Context] ~ { Action: PROC ~ { ThreeDSurfaces.ShowWireFrameObjects[ context ]; }; CedarProcess.DoWithPriority[background, Action]; }; OrbitEye: PUBLIC PROC[context: REF Context, lookingFrom, lookingAt, axis: Triple, framesPerRev: NAT, filename: Rope.ROPE _ NIL, numFrames: NAT _ 32767, startAt: NAT _ 0] ~ { frameNo: NAT _ startAt; bufContext, ditherContext: REF Context _ NIL; GetBufferContext: PROC[context: REF Context] RETURNS[bufContext: REF Context] ~ { IF context.renderMode # $Bitmap AND context.renderMode # $Dithered THEN { bufContext _ ThreeDScenes.Create[]; ThreeDScenes.DisplayFromVM[ bufContext, Real.FixC[context.viewPort.w], Real.FixC[context.viewPort.h], context.renderMode ]; IF context.alphaBuffer THEN ThreeDScenes.AddAlphaBuffer[bufContext]; IF context.depthBuffer THEN ThreeDScenes.AddDepthBuffer[bufContext]; CopyContextData[dstCtx: bufContext, srcCtx: context]; context.props _ Atom.PutPropOnList[context.props, $BufferContext, bufContext]; } ELSE { -- using Imager, no double buffer bufContext _ context; context.props _ Atom.RemPropFromList[context.props, $BufferContext]; }; }; NewFrame: ENTRY PROC[lookingFrom, lookingAt: Triple] ~ { ENABLE UNWIND => NULL; changed: BOOLEAN _ UpdateDisplay[context]; IF changed THEN bufContext _ GetBufferContext[context]; ThreeDScenes.SetView[ bufContext, lookingFrom, lookingAt]; MakeFrame[bufContext]; IF bufContext # context THEN { -- double buffering, make sure display is current DoTransfer: PROCEDURE [imagerCtx: Imager.Context] ~ { Pixels.Transfer[context.display, bufContext.display]; }; QuickViewer.DrawInViewer[NARROW[context.viewer], DoTransfer]; }; IF context.stopMe THEN ERROR ABORTED; CedarProcess.CheckAbort[]; -- check for external abort request before proceeding IF filename # NIL THEN -- if storing frames IF context.renderMode = $Dorado24 OR context.renderMode = $FullColor THEN { -- dither to 8 bits per pixel for storage savings DitherImage[ditherContext, context]; AISAnimation.StoreFiles[ditherContext, filename, frameNo]; } ELSE AISAnimation.StoreFiles[context, filename, frameNo]; frameNo _ frameNo + 1; }; IF filename = NIL -- double buffer if not storing files THEN bufContext _ GetBufferContext[context] ELSE { -- no double buffer if storing files bufContext _ context; IF context.renderMode = $Dorado24 OR context.renderMode = $FullColor THEN { ditherContext _ ThreeDScenes.Create[]; ThreeDScenes.DisplayFromVM[bufContext, context.display.width, context.display.height, $PseudoColor ]; }; }; Animation3D.MoveInOrbit[ lookingFrom, lookingAt, axis, NewFrame, framesPerRev, numFrames, startAt ]; }; MakeFramesFromTo: PUBLIC PROC[context: REF 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. ˆThreeDMiscImpl.mesa Last Edited by: Crow, December 16, 1986 5:43:41 pm PST Types Utility Procedures Draw 3D lines, clipped Don't copy display, most uses want a separate one Colors and Text Rotates color map entries in given range Adjust the values in the display memory for TRC or ? (only for full-color or grey) Adjust the values in the display memory for Saturation (only for full-color) { forest, savannah, rock, snow } AIS Files and Texture Generation Bresenham-like walk across image, areas averaged down View and Lighting control Shape Manipulation Maintain data but don't display Scene Manipulation Frame Generation and Animation Κ,“˜headšœ™Jšœ6™6defaultšΟk ˜ Jš œ œ œœœ˜-Jšœ œ%˜6Jšœ œd˜rJšœœ ˜4Jšœ œ˜*Jšœ œΆ˜ΗJšœœœ+˜AJšœ˜Jšœœ ˜Jšœœ˜Jšœ œœ˜,Jšœ œ ˜0Jšœ œ˜-Jšœ œ˜%Jšœœ˜0Jšœ œZ˜iJšœœœ˜6Jšœ œ˜#Jšœœ ˜7Lšœœ˜"Jšœ œœ…˜±Jšœ œ˜"Jšœœ3˜FJšœœ@œ˜ρJšœœΡ˜δJšœœΆ˜ΛJšœ œ˜Jšœœ˜4Jšœœ ˜3Jšœœ˜0JšœœO˜eJšœ œ˜——head2šΟnœœ˜JšœMœ3œΈ˜ΕJšœ ˜J˜Jšœ˜J˜—head3šΠbi™Iunitšœ œ˜%Jšœœ Οc˜BLšœœ˜#Jšœœœ˜Jšœœœ œ˜*Jš œœœœ œœ ˜@Jšœ œ˜)Jšœ œ˜-Jšœ œ˜)J˜J˜—šΟb™šžœœœ œœ)œœ˜L˜Jš œœœœœ˜1Jšœ œœ!˜5Jšœ˜šœœ˜šœ˜Jšœ%˜%Jšœ%˜%Jšœ%˜%Jšœ˜Jšœ˜—šœ ˜ Jšœ?˜?Jšœ˜J˜—šœ˜ašœ"˜"Pšœ˜PšœQ˜QPšœ˜—Jšœ˜Jšœ˜—Jšœœ8˜J—Jšœ ˜J˜—š žœœœ œœœ˜DJšœ<˜Pšœ˜Pšœ˜Pšœ(˜(Pšœ"˜"Pšœ*˜*Pšœ$˜$Pšœ(˜(Pšœ(˜(Pšœ˜Pšœ(˜(Pšœ"˜"Pšœ.˜.Pšœ(˜(Pšœ"˜"Pšœ1™1Pšœ"˜"Pšœ&˜&Pšœ(˜(Pšœ0˜0Pšœ*˜*š œ/œœœ ˜ZJšœœ$˜BJšœœ˜+Jšœ˜—Pšœ˜—šžœœœœ ˜>Pšœ ˜ Pšœœ8˜Sšœœœ#˜2Pšœ4˜4Pšœ˜—Jšœœ  ˜8šœ7œœ˜MJšœœ$˜BJšœœ ˜;Jšœ˜—Pšœ(˜(Pšœ(˜(P˜—šžœ œ œœ˜FIcodešœ œœ˜Kšœ˜Lšœœ˜šœ ˜ Lšœ2˜2Lšœ8˜8Lšœ3˜3Lšœ=˜=QšœB˜BQ˜—Qšœœ>˜O—P˜—šžœœœ œœ8œœ˜•Lšœ œœ<˜nšœ˜ Lšœ˜#Lšœ˜—Qšœ?˜?Q˜—šžœœœ œ œœœ˜CJšœœœ˜šœ*˜*Jšœ˜Jšœ@˜@J˜—Jšœ=˜=Pšœ˜Pšœ˜—šžœœœ œ ˜0Jšœœœœ,˜CPšœœœœ ˜ Pšœ˜—šžœœœ œ ˜0Jšœœœœ,˜CPšœœœœ ˜ Pšœ˜—š žœœ œœœœ˜3Pšœ  œ œ˜3Pšœ˜——š‘™šΠbnœœœ œœ œœ˜[Pšœœ2˜˜>šœœœœ˜+Pšœ/˜/Pšœ˜—Pšœ˜—P˜P˜—šžœ œ œ ˜6Pšœ œ'˜;Pšœœœ+˜PPšœ œ˜'Pšœ œ/˜APšœ œ˜(šœœœ ˜Pšœœ˜'Pšœœ"˜-Pšœœœ˜+Pšœœœ˜-PšœK˜KPšœ˜—Pšœ˜P˜—šž œ œ œ#˜Jš ž œœœœœ˜>Jšœ œa˜rJšœU˜UJšœ ˜Jšœ˜—Jšœœœœ.˜EPšœ.˜.šœœœ ˜Pšœ˜ Pšœœ%˜D—š œœœœ ˜NLšœ œ˜šœ ˜"šœ˜Lšœ˜Lšœ˜Lšœ˜Lšœ˜—Lšœ ˜$—šœœœ˜Jšœ-˜-Jšœœ˜(Jšœ˜J˜—Jšœ˜—J˜J˜—šž œ œ.œ˜PPšœ.˜.šœœœ ˜Pšœ˜ Pšœœ%˜D—Pš œ œœœœ˜IPš œ œœœœ˜IPš œ œœœœ˜IP˜š œœœœ ˜NJšœl˜lJšœk˜kJšœi˜išœ ˜"LšœN˜RLšœ ˜$—Jšœ˜—P˜P˜—š žœœœ œœœ˜KPšœœœ˜4Pšœ'œ˜/Pšœ.˜.šœœœ ˜Pšœ˜ Pšœœ%˜D—šœ œ˜Pšœ$œœ˜IPšœ$œœ˜IPšœ$œœ˜IPšœ˜Pšœ˜Pšœ˜—Jšœ-˜-šœœœ˜+Lšœ˜Lšœ œœ ˜!šœœœ˜,Lšœ5˜9Lšœ˜—Lšœk˜kJšœh˜hJšœh˜hšœ ˜"LšœN˜RLšœ ˜$—Pšœ˜—J˜—š žœœœ œœ˜EJ™Ršžœœ˜Jšœ œœ˜,Jšœ œ ˜Pšœ œœ˜5Pšœ œœ˜5Pšœ œœ˜5šœ˜šœœœœ ˜3JšœJ˜JJšœJ˜JJšœJ˜JJšœ˜—šœ ˜ Jšœœ0˜9šœœœ ˜JšœC˜CJšœ˜—Jšœ˜—Jšœœ8˜I—šœœœ*˜9Pšœ]˜]šœœœ*˜9šœœ˜šœ˜Pšœ)˜)Pšœ)˜)Pšœ)˜)P˜—Jšœ4˜4Jšœœ8˜I—Pšœ˜—PšœS˜SPšœ˜—P˜—Jšœ0˜0J˜J˜—š žœœœ œœ˜FJ™Lšžœœ˜Jšœ œœ˜,Jšœ œ ˜šœœœ*˜9Pšœ]˜]šœœœ*˜9šœœ˜šœ˜Pšœœ˜ Pšœœ˜!Pšœœ˜!Pšœœ˜!Pšœœœ˜,Pšœœœ˜,Pšœœœ ˜6Pš œœœœœ˜*Pšœ+˜+Pšœ8˜8Pšœ7˜7Pšœ7˜7Pšœ˜Pšœ˜Pšœ˜P˜—Jšœœ8˜I—Pšœ˜—PšœS˜SPšœ˜—P˜—Jšœ0˜0J˜J˜—šžœ œ˜<š ž œœ œœœ˜.Jšœ;˜AJ˜—š œœœ œ ˜3Jšœœ˜Jšœ+˜+Jšœ˜—š œœœ œ  ˜;šœ˜Jšœ˜Jšœœ ˜%Jšœœ˜J˜—Jšœ˜—Pšœ˜Pšœ˜P™—šžœ œ 1˜mšœ œœœ=˜]J™ —Jšœœ˜Jšœ œ˜Jšœœ  ˜#Pšœœ˜Pšœ8œ˜@Pšœœ˜.Pšœ"˜"Pšœ+˜+š œœœœ %˜AJšœ œ;˜JJšœ˜š œœœœ ˜7Jšœ œ˜ Jšœ0˜0Jšœ,˜,Jšœ,˜,Jšœ(˜(Jšœ&˜&Jšœ˜Jšœ˜—Jšœ˜—Jšœl˜lJšœm˜m˜J™——Jš žœœœ œœ œ˜Iš œœœœœœ ˜Nšžœœ˜+Pšœ˜Pšœ œœ˜+Jšœ!˜!Pšœ œœ.˜DPšœ!˜!Pšœ$˜$Lšœ ˜ Pšœ ˜ Pšœ!˜!P˜—šœ! !˜BJšœ˜Jšœ˜Jšœ˜—P˜Pšœ˜P˜——š‘ ™ šž œ œœ ˜Ašžœœ˜Jšœœ œ1˜KJšœœ œ1˜LJšœœœ˜:šœ(˜*JšœœF˜Q—šœœœ ˜Pšœq˜qPšœr˜ršœœœ ˜Jšœ}˜}Jšœ˜—Pšœa˜aJšœ˜—J˜—Jšœ4 ˜RJ˜—J˜šžœœœœ ˜DJ™5šžœœ˜Jšœ œ&˜2Jšœ œ&˜2Jšœ œ&˜2Jšœ œ&˜2Jšœ œœ˜7Jšœ œ˜Jšœ œ˜Jšœœœ˜;Jšœ œ5˜Bš œœœœ  ˜:Pš œœœœ œ˜HPšœ˜—Jšœ˜Jš œœœœœ˜9š œœœœ $˜JPšœL˜LJšœ˜Jšœ ˜ š œœœœ ˜Ešœœœ˜'Pšœ= ˜OPšœ˜—Jšœ* ˜?šœ œ˜Jšœ1œœœ˜MJšœ˜—Jšœ˜Jšœ˜—šœ œ ˜7šœœœœ˜šœœœ˜'Pšœ1˜1Pšœ˜—Pšœ˜Pšœ˜—PšœD˜Dš œœœœ  ˜:Pš œœœœ œ˜HPšœ˜—Pšœ '˜FPšœœœœ˜0P˜—Jšœ 6˜RJšœ˜—J˜—Jšœ4 ˜RJ˜—šž œ œ œ'œ˜UPšœœB˜NJšœ œ ˜Jšœ œ}˜‰šœœœ*˜9Pšœ œ˜,Jšœœ%˜BJšœW˜WPšœ˜—šœœœ*˜9PšœS˜SPšœ˜—Pšœ˜J˜—š žœ œ œ4œœœ˜‘šžœœ˜Pšœ œ ˜JšœœA˜Mšœœœ*˜9Jšœ œu˜šœœ˜šœ œ˜Jšœu˜u—Jšœ˜ —Jšœœ˜)Jšœœ˜6šœœœ*œ˜:JšœœO˜ZJšœœ˜6šœ˜J˜A—Jšœ˜—PšœS˜SJšœ˜—J˜—Jšœ4 ˜RJ˜J˜—š žœ œ œœ)œ˜mJšœœœ˜@Jšœ˜JšœZ˜ZJšœZ˜ZJšœZ˜ZJšœZ˜ZJšœ!˜!Jšœ˜J˜——š‘™ šžœ œ œœ˜IJš œœœœœF˜fJšœJ˜Jšœœœ˜+Jšœ#œ˜(Jšœ˜—Q˜Q˜— šžœ œ œœ˜LJš œ œœœœF˜dJšœL  ˜XQ˜Q˜— šžœ œ œœ˜NJšœ œ!˜.šœ&˜&JšœB˜BJšœ˜J˜—Jšœœ'˜BJšœœ'˜BJšœ,˜,JšœKœ*˜xQ˜— šžœ œœ˜GJšœKœ*˜xQ˜— š žœœœ œ œ œ˜OJšœœ5 ˜TJšœœœ œœœœ˜KQ˜Q˜——š‘™šžœ œ œœ˜APš ™Jšœœh˜rPšœ>˜>Pšœ˜—š žœ œ œœ  ˜PJšœœh˜rPšœ9˜9Pšœ˜—š ž œ œ œœœ˜[Lšœ œ!˜-Jšœœ?˜IJšœœ˜'Jšœ4˜4Jšœœ?˜QJšœ˜Lšœœœ8˜KPšœ œœ"˜Ešœœœ˜)šœœœ˜Jšœ œ#˜0Jšœœ˜+Jšœ: ˜IJšœœ  ˜IJšœB œ˜[J˜—Jšœ˜—šœœœ˜'Jšœ œ! ˜LJšœœœœ˜CJšœœ˜(Jšœ˜Jšœ!˜!Jšœ&˜&Jšœ5˜5Jšœ0˜0Jšœ˜—Jšœ>˜>Jšœ˜J˜—š ž œœœ œœœ0˜‡Jšœœ?˜IJšœ œœ˜1Jšœ<˜<š œœœœ ˜Lšœ8˜:Jšœ ˜$—Jšœ˜—šœœ %˜@Jšœ/˜3Jšœ3˜7—Jšœ)˜)Jšœ>˜> šœ3œ˜9Qšœ*˜.—J˜J˜—š žœ œ œœ œ˜XJšœœh˜ršœ ˜šœ˜šœ œ œ˜5Jšœ.˜.Jšœ˜—šœ œ˜Jšœ œ2˜Fšœœ8˜BJšœœA˜L——šœœœœ˜(Jšœœ˜0Jšœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœ0˜0Jšœ(œœ ˜;Jšœ:˜:JšœHœœœ˜sJšœ˜——J˜J˜—š žœœœ œœ œ˜WJšœœh˜ršœ œ˜šœ˜Jšœ/˜/Jšœ(œœ ˜;šœ9˜>JšœœB˜M—Jšœ0 ˜>Jšœ˜——J˜J˜—š ž œœœ œœ œ˜VJšœœh˜ršœ œ˜šœ˜Jšœ.˜.Jšœ(œœ ˜;šœ9˜>JšœœB˜M—Jšœ0 ˜>Jšœ˜——J˜J˜—š ž œ œ œœ œ˜ZJšœœh˜rJš œ œœ,œœ˜WJ˜J˜—š žœ œ œœœ˜VJšœœh˜ršœ œœ˜Jšœ0œœ˜Aš œœœœœœ˜BJšœœœ˜2Jšœ˜—Jšœ˜—Jšœ˜—šžœ œ œ$œ˜WJšœœf˜pJšœI˜IJšœG˜GJšœ/ œ;˜wJšœ˜—šžœ œ œœj˜±Jšœœf˜pJšœ/ œ;˜wJ˜J˜——š‘™š ž œœœ œ ˜PIfdefaultš œœœœœ˜5 šœœœœ˜,šœœœ: œœœ#œ˜±šœB˜DJšœB˜F—šœD˜FJšœD˜H—šœF˜HJšœF˜J—šœ@˜BJšœ@˜D—Jšœ˜—Jšœ˜—J˜—šž œ œ œœ˜FLšœ œ$œ˜8LšœœœœD˜Zšœ3˜5Lšœ˜Lšœ"˜$Lšœ˜ L˜—Lšœ)˜)Lšœ˜Lšœ˜—šžœ œ œœ˜KLšœ œ$œ˜8šœœœœ6˜KLš œœœœœœ˜<—Lšœœ ˜4Lšœ'˜'Lšœ˜Lšœ˜—šžœ œ œœ˜MPšœ œœ/˜GJšœœ˜ Jšœœœœ.˜EPšœ œ!˜/Pšœ$˜$Pšœ*˜*Pšœ,˜,PšœC˜CPšœA˜AJšœ˜Lšœ%˜%JšœœœD˜ULšœ˜Lšœ œ˜Lšœ˜——š‘™šž œœœ œ ˜0Jšœœ˜Jšœœœœ.˜EJšœ˜šœ˜Pšœ4  ˜XPšœ- ˜C—šœœœ˜2Jšœ˜!Jšœ˜—Jšœœ) ˜Všœœœ˜JšœE˜EJšœ˜J˜—J˜—š žœœœ œ&œ œ˜gJšœœœœ.˜EPšœ œ!˜/Pšœ8 ˜MPšœœ(˜CPšœœ(˜CPšœ4˜4PšœU˜UJšœ˜šœœœœ˜.Jšœ#œ˜(Jšœ˜—Jšœ˜Jšœ- ˜EJšœ˜—š žœœœ œœ˜NPšœœ!˜,Jšœq˜qJšœœ ˜;šžœœ˜+šœ œœœ˜Jšœ/˜/JšœœœT˜cJšœ˜—JšœG˜GJšœB˜BPšœ3˜3Pšœ%˜%Pšœ˜—Jšœ!˜!Jšœ ˜ Jšœœ˜Jšœœ˜Jšœ.˜.Jšœ˜Jšœ˜—šž œ œ œ ˜1šžœœ˜šœœ ˜Pšœ˜Pšœœ ˜ P˜—Jšœ˜—Jšœ0˜0J˜J˜—šžœ œ œ ˜:šžœœ˜Pšœ/˜/P˜—Jšœ0˜0Jšœ˜J˜—šžœ œ œFœœœ œœ ˜½Pšœ œ ˜Pšœœ œ˜-š žœœ œ œ œ˜Ršœœ ˜Cšœ˜Pšœ#˜#Pšœ‡˜‡Pšœœ)˜DPšœœ)˜DPšœ5˜5PšœN˜NP˜—šœ !˜*Pšœ˜PšœD˜DP˜——P˜—šžœœœ$˜8Jšœœœ˜Jšœ œ˜*Pšœ œ(˜7Jšœ:˜:Pšœ˜šœœ 1˜Ršž œ œ"˜7Pšœ5˜5Jšœ˜—Pšœœ˜=P˜—Pšœœœœ˜%Pšœ 5˜Ršœ œœ ˜.šœ œ!˜Ešœ  1˜>Jšœ$˜$Jšœ:˜:P˜—Jšœ5˜9——Pšœ˜P˜—šœ œ ,˜?Pšœ'˜+šœ  $˜2Pšœ˜šœ œ ˜Dšœ˜Pšœ&˜&šœ'˜'Pšœ/˜/Pšœ ˜ Pšœ˜—P˜——P˜——Pšœm˜mJšœ˜—šžœ œ œdœ œœœ˜ΓPšœ œ ˜šžœœ$˜2Jšœ7˜7Pšœ˜Pšœ 5˜RPšœ˜šœ œœ˜Jšœ4˜4—P˜—Pšœs˜sJ˜J˜—Jš˜——…—²ξβ