<> <> <> <> <> <> <<>> <> <<>> DIRECTORY Atom, CardTab, CodeTimer, Convert, Feedback, FeedbackTypes, GGBasicTypes, GGCoreOps, GGEvent, GGFileIn, GGFileOut, GGFont, GGInterfaceTypes, GGModelTypes, GGParseIn, GGParseOut, GGScene, GGSegmentTypes, GGSelect, GGSlice, GGSliceOps, GGState, GGUIUtility, GGUtility, Imager, ImagerColor, ImagerColorPrivate, ImagerTransformation, IO, Real, RefTab, Rope, SimpleFeedback, SymTab, ViewerClasses; GGFileImpl: CEDAR PROGRAM IMPORTS Atom, CardTab, CodeTimer, Convert, Feedback, GGCoreOps, GGEvent, GGFont, GGParseIn, GGParseOut, GGScene, GGSelect, GGSlice, GGSliceOps, GGState, GGUIUtility, GGUtility, Imager, ImagerColor, ImagerColorPrivate, IO, Real, RefTab, Rope, SimpleFeedback, SymTab EXPORTS GGFileIn, GGFileOut = BEGIN Camera: TYPE = GGModelTypes.Camera; Caret: TYPE = GGInterfaceTypes.Caret; Color: TYPE = Imager.Color; DefaultData: TYPE = GGModelTypes.DefaultData; MsgRouter: TYPE = FeedbackTypes.MsgRouter; FontData: TYPE = GGModelTypes.FontData; GGData: TYPE = GGInterfaceTypes.GGData; Point: TYPE = GGBasicTypes.Point; ROPE: TYPE = Rope.ROPE; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGSegmentTypes.Segment; SegmentClass: TYPE = GGSegmentTypes.SegmentClass; Slice: TYPE = GGModelTypes.Slice; SliceClass: TYPE = GGModelTypes.SliceClass; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; StrokeEnd: TYPE = Imager.StrokeEnd; StrokeJoint: TYPE = Imager.StrokeJoint; Traj: TYPE = GGModelTypes.Traj; Transformation: TYPE = ImagerTransformation.Transformation; Viewer: TYPE = ViewerClasses.Viewer; OutputPixelArrayTable: TYPE = REF OutputPixelArrayTableObj; OutputPixelArrayTableObj: TYPE = RECORD [ nextIndex: NAT ¬ 0, table: RefTab.Ref ¬ NIL -- a mapping from pixel arrays to small integers ]; OutputColorTable: TYPE = REF OutputColorTableObj; OutputColorTableObj: TYPE = RECORD [ pixelArrayTable: OutputPixelArrayTable, nextColorIndex: NAT ¬ 0, constantOp: CardTab.Ref, -- keys off the intensity constantSpecial: RefTab.Ref, -- keys off the REF sampled: RefTab.Ref -- keys off the REF, used for sampled colors and sampled blacks ]; InputPixelArrayTable: TYPE = REF InputPixelArrayTableObj; InputPixelArrayTableObj: TYPE = RECORD [ table: CardTab.Ref ¬ NIL -- a mapping from small integers to pixel arrays ]; InputColorTable: TYPE = REF InputColorTableObj; InputColorTableObj: TYPE = RECORD [ pixelArrayTable: InputPixelArrayTable, colors: CardTab.Ref ¬ NIL -- a mapping from small integers to colors ]; CreateOutputColorTable: PROC [] RETURNS [ct: OutputColorTable] = { ct ¬ NEW[OutputColorTableObj]; ct.pixelArrayTable ¬ NEW[OutputPixelArrayTableObj]; ct.pixelArrayTable.table ¬ RefTab.Create[mod: 17]; ct.constantOp ¬ CardTab.Create[mod: 17]; ct.constantSpecial ¬ RefTab.Create[mod: 11]; ct.sampled ¬ RefTab.Create[mod: 5]; }; NatRef: TYPE = REF NAT; PickANumber: PROC [ct: OutputColorTable] RETURNS [natRef: NatRef] = { natRef ¬ NEW[NAT ¬ ct.nextColorIndex]; ct.nextColorIndex ¬ ct.nextColorIndex + 1; }; FindColorInIntensityTable: PROC [op: ImagerColor.OpConstantColor, table: CardTab.Ref] RETURNS [found: BOOL ¬ FALSE, nat: NAT ¬ 0] = { intensity: REAL ¬ ImagerColorPrivate.IntensityFromColor[op]; key: CARD ¬ Real.Floor[intensity*32767]; }; AddColorToOutputTable: PROC [color: Imager.Color, ct: OutputColorTable] = { gray: ImagerColor.OpConstantColor ¬ ImagerColor.ColorFromGray[1]; IF color=NIL THEN { <> } ELSE { WITH color SELECT FROM op: ImagerColor.OpConstantColor => { IF gray.colorOperator=op.colorOperator THEN { -- "MakeGray" } ELSE { --put out an RGB r, g, b: REAL; [r,g,b] ¬ GGCoreOps.ExtractRGB[op]; }; }; special: ImagerColor.SpecialColor => { <> }; sampledBlack: ImagerColor.SampledBlack => { }; sampledColor: ImagerColor.SampledColor => { }; ENDCASE => ERROR; -- Gargoyle doesn't know about this type of color }; }; <> FileinSceneAndOptions: PUBLIC PROC [f: IO.STREAM, ggData: GGData, alignmentsOnly: BOOL, selectSlices: BOOL, closeStreamWhenDone: BOOL _ TRUE] RETURNS [success: BOOL ¬ FALSE, sceneName: ROPE] = { <> ENABLE GGParseIn.SyntaxError => { Feedback.PutFL[ggData.router, oneLiner, $Error, "position: %g, wasThere: %g, notThere: %g", LIST[[integer[position]], [rope[wasThere]], [rope[notThere]]] ]; GOTO Abort; }; scene: Scene ¬ ggData.scene; version: REAL; count: NAT; entity: Slice; finger, newEntities: LIST OF Slice; [sceneName, version] ¬ ReadHeaderAndOptions[f, ggData, IF alignmentsOnly THEN alignments ELSE all]; <> GGParseIn.ReadRope[f, "Entities:"]; GGParseIn.ReadChar[f, '[]; count ¬ GGParseIn.ReadNAT[f]; GGParseIn.ReadRope[f, "]:"]; GGParseIn.ReadWhiteSpace[f]; [newEntities, finger] ¬ GGUtility.StartSliceList[]; FOR i: NAT IN[1..count] DO entity ¬ FileinEntity[f, version, ggData.router, ggData.camera]; IF entity#NIL THEN [newEntities, finger] ¬ GGUtility.AddSlice[entity, newEntities, finger]; IF ggData.aborted[filein] THEN { ggData.aborted[filein] ¬ FALSE; GGUIUtility.SafeClose[f, ggData.router]; RETURN[FALSE, NIL]; -- signals a failed read }; ENDLOOP; IF closeStreamWhenDone THEN GGUIUtility.SafeClose[f, ggData.router]; GGSelect.DeselectAll[scene, normal]; GGScene.AddSlices[scene, newEntities]; IF selectSlices THEN FOR sliceList: LIST OF Slice ¬ newEntities, sliceList.rest UNTIL sliceList=NIL DO GGSelect.SelectEntireSlice[sliceList.first, scene, normal]; ENDLOOP; RETURN[TRUE, sceneName]; EXITS Abort => {}; -- RETURN[FALSE, NIL]; }; FileinSceneOnly: PUBLIC PROC [f: IO.STREAM, scene: Scene, selectSlices: BOOL, camera: Camera, closeStreamWhenDone: BOOL _ TRUE] RETURNS [success: BOOL ¬ FALSE, sceneName: Rope.ROPE] = { <> ENABLE GGParseIn.SyntaxError => { SimpleFeedback.PutFL[$Gargoyle, oneLiner, $Error, "position: %g, wasThere: %g, notThere: %g", LIST[[integer[position]], [rope[wasThere]], [rope[notThere]]] ]; GOTO Abort; }; version: REAL; count: NAT; entity: Slice; finger, newEntities: LIST OF Slice; <> GGParseIn.ReadRope[f, "Gargoyle file for scene: "]; sceneName ¬ GGParseIn.ReadLine[f]; GGParseIn.ReadRope[f, "Produced by version"]; version ¬ GGParseIn.ReadReal[f]; version ¬ Real.Round[version*100.0]/100.0; -- compensate for fuzzy ReadReal of version <> <= 8607.17 THEN SkipOptions[f];>> <= 9207.29 THEN ReadSceneFields[f, version, scene];>> IF version >= 8607.17 THEN ReadSceneFields[f, version, scene]; <> GGParseIn.ReadRope[f, "Entities:"]; GGParseIn.ReadChar[f, '[]; count ¬ GGParseIn.ReadNAT[f]; GGParseIn.ReadRope[f, "]:"]; GGParseIn.ReadWhiteSpace[f]; [newEntities, finger] ¬ GGUtility.StartSliceList[]; FOR i: NAT IN[1..count] DO entity ¬ FileinEntity[f, version, NIL, camera]; IF entity#NIL THEN [newEntities, finger] ¬ GGUtility.AddSlice[entity, newEntities, finger]; ENDLOOP; IF closeStreamWhenDone THEN GGUIUtility.SafeClose[f]; GGSelect.DeselectAll[scene, normal]; GGScene.AddSlices[scene, newEntities]; IF selectSlices THEN FOR sliceList: LIST OF Slice ¬ newEntities, sliceList.rest UNTIL sliceList=NIL DO GGSelect.SelectEntireSlice[sliceList.first, scene, normal]; ENDLOOP; RETURN[TRUE, sceneName]; EXITS Abort => {}; -- RETURN[FALSE, NIL]; }; FileinOptionsOnly: PUBLIC PROC [f: IO.STREAM, ggData: GGData, alignmentsOnly: BOOL, closeStreamWhenDone: BOOL _ TRUE] RETURNS [success: BOOL ¬ FALSE, sceneName: Rope.ROPE] = { <> ENABLE GGParseIn.SyntaxError => { Feedback.PutFL[ggData.router, oneLiner, $Error, "position: %g, wasThere: %g, notThere: %g", LIST[[integer[position]], [rope[wasThere]], [rope[notThere]]] ]; GOTO Abort; }; version: REAL; [sceneName, version] ¬ ReadHeaderAndOptions[f, ggData, IF alignmentsOnly THEN alignments ELSE all]; IF closeStreamWhenDone THEN GGUIUtility.SafeClose[f, ggData.router]; RETURN[TRUE, sceneName]; EXITS Abort => {}; -- RETURN[FALSE, NIL]; }; ReadHeaderAndOptions: PROC [f: IO.STREAM, ggData: GGData, type: OptionType] RETURNS [sceneName: Rope.ROPE, version: REAL] = { <> GGParseIn.ReadRope[f, "Gargoyle file for scene: "]; sceneName ¬ GGParseIn.ReadLine[f]; GGParseIn.ReadRope[f, "Produced by version"]; version ¬ GGParseIn.ReadReal[f]; version ¬ Real.Round[version*100.0]/100.0; -- compensate for fuzzy ReadReal of version <> CodeTimer.StartInt[$ReadOptions, $Gargoyle]; IF version >= 8607.17 THEN ReadOptions[f, version, ggData, type] ELSE GGEvent.StandardAlignments[ggData, LIST[NIL]]; CodeTimer.StopInt[$ReadOptions, $Gargoyle]; }; ReadSceneFields: PROC [f: IO.STREAM, version: REAL, scene: Scene] = { keyWord, option: Rope.ROPE; good: BOOL; nextChar: CHAR; twoCRsFound: BOOL ¬ FALSE; <> UNTIL twoCRsFound DO [keyWord, good] ¬ GGParseIn.ReadKeyWord[f]; IF NOT good THEN { nextChar ¬ IO.PeekChar[f]; IF IsEndLine[nextChar] THEN { [] ¬ IO.GetChar[f]; twoCRsFound ¬ TRUE; }; LOOP}; good ¬ GGParseIn.ReadHorizontalBlank[f]; IF NOT good THEN { nextChar ¬ IO.PeekChar[f]; IF IsEndLine[nextChar] THEN { [] ¬ IO.GetChar[f]; twoCRsFound ¬ TRUE; }; LOOP}; option ¬ GGParseIn.ReadLine[f]; ProcessSceneField[keyWord, option, version, scene]; nextChar ¬ IO.PeekChar[f]; IF IsEndLine[nextChar] THEN { [] ¬ IO.GetChar[f]; twoCRsFound ¬ TRUE; }; ENDLOOP; }; ReadOptions: PROC [f: IO.STREAM, version: REAL, ggData: GGData, type: OptionType] = { keyWord, option: Rope.ROPE; good: BOOL; nextChar: CHAR; twoCRsFound: BOOL ¬ FALSE; <> GGState.SetPalette[ggData, FALSE]; <> UNTIL twoCRsFound DO [keyWord, good] ¬ GGParseIn.ReadKeyWord[f]; IF NOT good THEN { nextChar ¬ IO.PeekChar[f]; IF IsEndLine[nextChar] THEN { [] ¬ IO.GetChar[f]; twoCRsFound ¬ TRUE; }; LOOP}; good ¬ GGParseIn.ReadHorizontalBlank[f]; IF NOT good THEN { nextChar ¬ IO.PeekChar[f]; IF IsEndLine[nextChar] THEN { [] ¬ IO.GetChar[f]; twoCRsFound ¬ TRUE; }; LOOP}; option ¬ GGParseIn.ReadLine[f]; ProcessOption[keyWord, option, version, ggData, type]; nextChar ¬ IO.PeekChar[f]; IF IsEndLine[nextChar] THEN { [] ¬ IO.GetChar[f]; twoCRsFound ¬ TRUE; }; ENDLOOP; }; ReadListOfAtom: PUBLIC PROC [f: IO.STREAM] RETURNS [atomList: LIST OF ATOM] = { cr: Rope.ROPE = Rope.FromChar[IO.CR]; lf: Rope.ROPE = Rope.FromChar[IO.LF]; rightParen: Rope.ROPE = Rope.FromChar[')]; rightBracket: Rope.ROPE = Rope.FromChar[']]; AtomsOnOneLineOrParenProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = { SELECT char FROM IO.LF, IO.CR, '), '] =>RETURN [break]; IO.SP, IO.TAB, ', , '; => RETURN [sepr]; ENDCASE => RETURN [other]; }; rope: Rope.ROPE; end: BOOL ¬ FALSE; [] ¬ IO.SkipWhitespace[f, TRUE]; atomList ¬ NIL; WHILE TRUE DO [rope, ----] ¬ IO.GetTokenRope[f, AtomsOnOneLineOrParenProc !IO.EndOfStream => {end ¬ TRUE; CONTINUE}]; IF end OR rope = NIL THEN RETURN; IF Rope.Equal[rope, cr] OR Rope.Equal[rope, lf] THEN RETURN; IF Rope.Equal[rope, rightParen] THEN { f.Backup[')]; RETURN; }; IF Rope.Equal[rope, rightBracket] THEN { f.Backup[']]; RETURN; }; atomList ¬ AppendAtomToAtomList[Atom.MakeAtom[rope], atomList]; ENDLOOP; }; AppendAtomToAtomList: PROC [atom: ATOM, list: LIST OF ATOM] RETURNS [LIST OF ATOM] = { <> z: LIST OF ATOM ¬ list; IF z = NIL THEN RETURN[CONS[atom,NIL]]; UNTIL z.rest = NIL DO z ¬ z.rest; ENDLOOP; z.rest ¬ CONS[atom,NIL]; RETURN[list]; }; OptionType: TYPE = {alignments, normal, sceneField, all, none}; optionTable: SymTab.Ref; OptionData: TYPE = REF OptionDataObj; OptionDataObj: TYPE = RECORD [ process: ProcessOptionProc _ NIL, processScene: ProcessSceneFieldProc _ NIL, type: OptionType ]; FindOption: PROC [name: ROPE] RETURNS [optionData: OptionData _ NIL] = { found: BOOL; val: REF; [found, val] _ SymTab.Fetch[optionTable, name]; IF found THEN optionData _ NARROW[val]; }; RegisterAllOptions: PROC [] = { RegisterOption: PROC [name: ROPE, process: ProcessOptionProc, type: OptionType] = { optionData: OptionData; optionData _ NEW[OptionDataObj _ [process: process, processScene: NIL, type: type]]; [] _ SymTab.Store[optionTable, name, optionData]; }; RegisterSceneField: PROC [name: ROPE, process: ProcessSceneFieldProc] = { optionData: OptionData; optionData _ NEW[OptionDataObj _ [process: NIL, processScene: process, type: sceneField]]; [] _ SymTab.Store[optionTable, name, optionData]; }; optionTable _ SymTab.Create[29]; RegisterOption["ViewTransform", ProcessViewTransform, normal]; RegisterOption["PaletteForFillColor", ProcessPaletteForFillColor, normal]; RegisterOption["PaletteForStrokeColor", ProcessPaletteForStrokeColor, normal]; RegisterOption["Palette", ProcessPalette, normal]; RegisterOption["Scripts", ProcessScripts, normal]; RegisterOption["Slope", ProcessSlope, alignments]; RegisterOption["Angle", ProcessAngle, alignments]; RegisterOption["Radius", ProcessRadius, alignments]; RegisterOption["LineDistance", ProcessLineDistance, alignments]; RegisterOption["Anchor", ProcessAnchor, alignments]; RegisterOption["Midpoints", ProcessMidpoints, normal]; RegisterOption["Heuristics", ProcessHeuristics, normal]; RegisterOption["ShowAlignments", ProcessShowAlignments, normal]; RegisterOption["ShowColors", ProcessShowColors, normal]; RegisterOption["Gravity", ProcessGravity, normal]; RegisterOption["ScaleUnit", ProcessScaleUnit, normal]; RegisterOption["DisplayStyle", ProcessDisplayStyle, normal]; RegisterOption["GravityExtent", ProcessGravityExtent, normal]; RegisterOption["GravityType", ProcessGravityType, normal]; RegisterOption["DefaultFont", ProcessDefaultFont, normal]; RegisterOption["Defaults", ProcessDefaults, normal]; RegisterOption["Dashed", ProcessDashed, normal]; RegisterOption["Shadows", ProcessShadows, normal]; RegisterOption["Active", ProcessActive, normal]; RegisterSceneField["BackgroundColor", ProcessBackgroundColor]; }; ProcessSceneField: PROC [keyWord, option: Rope.ROPE, version: REAL, scene: Scene] = { optionStream: IO.STREAM; optionData: OptionData; optionStream ¬ IO.RIS[option]; optionData _ FindOption[keyWord]; IF optionData = NIL THEN { <> SimpleFeedback.PutF[$Gargoyle, oneLiner, $Error, "Unknown keyword in gargoyle file: %g", [rope[keyWord]]]; } ELSE { IF optionData.type # sceneField THEN RETURN; optionData.processScene[keyWord, scene, optionStream, version]; }; }; ProcessOption: PROC [keyWord, option: Rope.ROPE, version: REAL, ggData: GGData, types: OptionType] = { optionStream: IO.STREAM; optionData: OptionData; IF types = none THEN RETURN; optionStream ¬ IO.RIS[option]; optionData _ FindOption[keyWord]; IF optionData = NIL THEN { <> SimpleFeedback.PutF[$Gargoyle, oneLiner, $Error, "Unknown keyword in gargoyle file: %g", [rope[keyWord]]]; } ELSE { IF types = sceneField AND NOT optionData.type = sceneField THEN RETURN; IF types = alignments AND NOT optionData.type = alignments THEN RETURN; IF types = normal AND NOT optionData.type = normal THEN RETURN; IF optionData.type = sceneField THEN optionData.processScene[keyWord, ggData.scene, optionStream, version] ELSE optionData.process[keyWord, ggData, optionStream, version]; }; }; ProcessOptionProc: TYPE = PROC [keyWord: ROPE, ggData: GGData, optionStream: IO.STREAM, version: REAL]; ProcessSceneFieldProc: TYPE = PROC [keyWord: ROPE, scene: Scene, optionStream: IO.STREAM, version: REAL]; ProcessViewTransform: ProcessOptionProc = { clientToViewer: Transformation _ GGParseIn.ReadTransformation[optionStream]; GGState.SetBiScrollersTransform[ggData, clientToViewer]; }; ProcessPaletteForFillColor: ProcessOptionProc = { active: BOOL ¬ GGParseIn.ReadBool[optionStream]; IF active THEN GGState.SetPalette[ggData, TRUE]; }; ProcessPaletteForStrokeColor: ProcessOptionProc = { active: BOOL ¬ GGParseIn.ReadBool[optionStream]; IF active THEN GGState.SetPalette[ggData, TRUE]; }; ProcessPalette: ProcessOptionProc = { active: BOOL ¬ GGParseIn.ReadBool[optionStream]; IF active THEN GGState.SetPalette[ggData, TRUE]; }; ProcessScripts: ProcessOptionProc = { names: LIST OF Rope.ROPE ¬ GGParseIn.ReadListOfRope[optionStream]; ggData.debug.autoScriptNames ¬ GGCoreOps.NewRopeListt[]; FOR list: LIST OF Rope.ROPE ¬ names, list.rest UNTIL list = NIL DO GGCoreOps.AppendRope[list.first, ggData.debug.autoScriptNames]; ENDLOOP; }; ProcessSlope: ProcessOptionProc = { IF version>=8706.16 THEN { -- slope values and ON states values: LIST OF REAL; on: LIST OF BOOL; [----, values, on] ¬ GGParseIn.ReadScalarButtonValues[optionStream, version]; GGState.AddSlopeList[ggData, values, on]; } ELSE { -- slope values only values, ptr: LIST OF REAL; optionList: LIST OF ROPE; value: REAL; optionList ¬ GGParseIn.ReadListOfRope[optionStream]; [values, ptr] ¬ GGCoreOps.StartRealList[]; FOR list: LIST OF Rope.ROPE ¬ optionList, list.rest UNTIL list = NIL DO value ¬ Convert.RealFromRope[list.first]; [values, ptr] ¬ GGCoreOps.AddReal[value, values, ptr]; ENDLOOP; GGState.AddSlopeList[ggData, values, NIL]; }; }; ProcessAngle: ProcessOptionProc = { IF version>=8706.16 THEN { -- angle values and ON states values: LIST OF REAL; on: LIST OF BOOL; [----, values, on] ¬ GGParseIn.ReadScalarButtonValues[optionStream, version]; GGState.AddAngleList[ggData, values, on]; } ELSE { -- angle values only values, ptr: LIST OF REAL; value: REAL; optionList: LIST OF ROPE; optionList ¬ GGParseIn.ReadListOfRope[optionStream]; [values, ptr] ¬ GGCoreOps.StartRealList[]; FOR list: LIST OF Rope.ROPE ¬ optionList, list.rest UNTIL list = NIL DO value ¬ Convert.RealFromRope[list.first]; [values, ptr] ¬ GGCoreOps.AddReal[value, values, ptr]; ENDLOOP; GGState.AddAngleList[ggData, values, NIL]; }; }; ProcessRadius: ProcessOptionProc = { IF version>=8706.16 THEN { -- radius values and ON states values: LIST OF REAL; on: LIST OF BOOL; names: LIST OF Rope.ROPE; [names, values, on] ¬ GGParseIn.ReadScalarButtonValues[optionStream, version]; GGState.AddRadiusList[ggData, names, values, on]; } ELSE { -- radius values only values, ptr: LIST OF REAL; value: REAL; optionList: LIST OF ROPE; optionList ¬ GGParseIn.ReadListOfRope[optionStream]; [values, ptr] ¬ GGCoreOps.StartRealList[]; FOR list: LIST OF Rope.ROPE ¬ optionList, list.rest UNTIL list = NIL DO value ¬ Convert.RealFromRope[list.first]; [values, ptr] ¬ GGCoreOps.AddReal[value, values, ptr]; ENDLOOP; GGState.AddRadiusList[ggData, NIL, values, NIL]; }; }; ProcessLineDistance: ProcessOptionProc = { IF version>=8706.16 THEN { -- LineDistance values and ON states values: LIST OF REAL; on: LIST OF BOOL; names: LIST OF Rope.ROPE; [names, values, on] ¬ GGParseIn.ReadScalarButtonValues[optionStream, version]; GGState.AddLineDistanceList[ggData, names, values, on]; } ELSE { -- LineDistance values only values, ptr: LIST OF REAL; value: REAL; optionList: LIST OF ROPE; optionList ¬ GGParseIn.ReadListOfRope[optionStream]; [values, ptr] ¬ GGCoreOps.StartRealList[]; FOR list: LIST OF Rope.ROPE ¬ optionList, list.rest UNTIL list = NIL DO value ¬ Convert.RealFromRope[list.first]; [values, ptr] ¬ GGCoreOps.AddReal[value, values, ptr]; ENDLOOP; GGState.AddLineDistanceList[ggData, NIL, values, NIL]; }; }; ProcessAnchor: ProcessOptionProc = { anchored: BOOL; anchored ¬ GGParseIn.ReadBool[optionStream]; IF anchored THEN { point: Point ¬ GGParseIn.ReadPoint[optionStream]; ggData.anchor­ ¬ [exists: TRUE, point: point, chair: NIL, attractor: NIL]; } ELSE ggData.anchor.exists ¬ FALSE; }; ProcessMidpoints: ProcessOptionProc = { on: BOOL; on ¬ GGParseIn.ReadBool[optionStream]; GGState.SetMidpoints[ggData, on]; }; ProcessHeuristics: ProcessOptionProc = { on: BOOL; on ¬ GGParseIn.ReadBool[optionStream]; GGState.SetHeuristics[ggData, on]; }; ProcessShowAlignments: ProcessOptionProc = { on: BOOL; on ¬ GGParseIn.ReadBool[optionStream]; GGState.SetShowAlignments[ggData, on]; }; ProcessShowColors: ProcessOptionProc = { on: BOOL; on ¬ GGParseIn.ReadBool[optionStream]; <> }; ProcessGravity: ProcessOptionProc = { on: BOOL; on ¬ GGParseIn.ReadBool[optionStream]; GGState.SetGravity[ggData, on]; }; ProcessScaleUnit: ProcessOptionProc = { real: REAL ¬ GGParseIn.ReadReal[optionStream]; IF real>0.0 THEN GGState.SetScaleUnit[ggData, real, NIL]; }; ProcessDisplayStyle: ProcessOptionProc = { rope: Rope.ROPE ¬ GGParseIn.ReadWord[optionStream]; GGState.SetDisplayStyle[ggData, GGUIUtility.DisplayStyleFromRope[rope]]; }; ProcessGravityExtent: ProcessOptionProc = { real: REAL ¬ GGParseIn.ReadReal[optionStream]; GGState.SetGravityExtent[ggData, real]; }; ProcessGravityType: ProcessOptionProc = { rope: Rope.ROPE ¬ GGParseIn.ReadWord[optionStream]; GGState.SetGravityType[ggData, GGUIUtility.GravityTypeFromRope[rope]]; }; ProcessDefaultFont: ProcessOptionProc = { fontData: FontData ¬ GGFont.CreateFontData[]; -- assure non-NIL font data fontData ¬ GGFont.ParseFontData[data: fontData, inStream: optionStream, literalP: TRUE, transformP: TRUE, storedSizeP: TRUE, designSizeP: TRUE ! GGFont.ParseError => CONTINUE;]; fontData.substituteOK ¬ TRUE; -- bad hack here. Avoids a bogus default font GGState.SetDefaultFont[ggData, fontData]; }; ProcessDefaults: ProcessOptionProc = { strokeJoint, strokeEnd: Rope.ROPE; ggData.defaults.fillColor ¬ GGParseIn.ReadColor[optionStream, version]; ggData.defaults.strokeColor ¬ GGParseIn.ReadColor[optionStream, version]; ggData.defaults.strokeWidth ¬ GGParseIn.ReadReal[optionStream]; strokeJoint ¬ GGParseIn.ReadWord[optionStream]; ggData.defaults.strokeJoint ¬ SELECT TRUE FROM Rope.Equal[strokeJoint, "miter", FALSE] => miter, Rope.Equal[strokeJoint, "bevel", FALSE] => bevel, ENDCASE => round; strokeEnd ¬ GGParseIn.ReadWord[optionStream]; ggData.defaults.strokeEnd ¬ SELECT TRUE FROM Rope.Equal[strokeEnd, "square", FALSE] => square, Rope.Equal[strokeEnd, "butt", FALSE] => butt, ENDCASE => round; }; ProcessDashed: ProcessOptionProc = { dashed: BOOL; dashed ¬ GGParseIn.ReadBool[optionStream]; ggData.defaults.dashed ¬ dashed; IF ggData.defaults.dashed THEN { ggData.defaults.pattern ¬ GGParseIn.ReadArrayOfReal[optionStream]; ggData.defaults.offset ¬ GGParseIn.ReadReal[optionStream]; ggData.defaults.length ¬ GGParseIn.ReadReal[optionStream]; }; }; ProcessShadows: ProcessOptionProc = { shadowed: BOOL; ggData.defaults.textColor ¬ GGParseIn.ReadColor[optionStream, version]; IF ggData.defaults.textColor=NIL THEN ggData.defaults.textColor ¬ Imager.black; <> shadowed ¬ GGParseIn.ReadBool[optionStream]; ggData.defaults.dropShadowOn ¬ shadowed; IF ggData.defaults.dropShadowOn THEN { ggData.defaults.dropShadowOffset ¬ GGParseIn.ReadPoint[optionStream]; ggData.defaults.dropShadowColor ¬ GGParseIn.ReadColor[optionStream, version]; }; }; ProcessActive: ProcessOptionProc = { active: BOOL; active ¬ GGParseIn.ReadBool[optionStream]; GGState.SetActive[ggData, active]; }; ProcessBackgroundColor: ProcessSceneFieldProc = { color: Imager.Color ¬ GGParseIn.ReadColor[optionStream, version]; GGScene.SetBackgroundColor[scene, color]; }; SkipOptions: PROC [f: IO.STREAM] = { keyWord, option: Rope.ROPE; good: BOOL; nextChar: CHAR; twoCRsFound: BOOL ¬ FALSE; UNTIL twoCRsFound DO [keyWord, good] ¬ GGParseIn.ReadKeyWord[f]; IF NOT good THEN { nextChar ¬ IO.PeekChar[f]; IF IsEndLine[nextChar] THEN { [] ¬ IO.GetChar[f]; twoCRsFound ¬ TRUE; }; LOOP}; good ¬ GGParseIn.ReadHorizontalBlank[f]; IF NOT good THEN { nextChar ¬ IO.PeekChar[f]; IF IsEndLine[nextChar] THEN { [] ¬ IO.GetChar[f]; twoCRsFound ¬ TRUE; }; LOOP}; option ¬ GGParseIn.ReadLine[f]; <> nextChar ¬ IO.PeekChar[f]; IF IsEndLine[nextChar] THEN { [] ¬ IO.GetChar[f]; twoCRsFound ¬ TRUE; }; ENDLOOP; }; FileinEntity: PROC [f: IO.STREAM, version: REAL, router: MsgRouter, camera: Camera] RETURNS [entity: Slice] = { nextWord: Rope.ROPE; IF version > 8605.22 THEN { IF version >= 8705.14 THEN { entity ¬ GGSliceOps.FileinSlice[f, version, router, camera]; } ELSE { nextWord ¬ GGParseIn.ReadWord[f]; SELECT TRUE FROM Rope.Equal[nextWord, "Outline:"] => { class: SliceClass ¬ GGSlice.FetchSliceClass[$Outline]; entity ¬ class.filein[f, version, router, camera]; }; Rope.Equal[nextWord, "Slice"] => { entity ¬ GGSliceOps.FileinSlice[f, version, router, camera]; }; ENDCASE => ERROR } } ELSE { nextWord ¬ GGParseIn.ReadWord[f]; SELECT TRUE FROM Rope.Equal[nextWord, "Outline:"] => { class: SliceClass ¬ GGSlice.FetchSliceClass[$Outline]; entity ¬ class.filein[f, version, router, camera]; }; Rope.Equal[nextWord, "Cluster"] => { entity ¬ GGSliceOps.FileinSlice[f, version, router, camera]; }; ENDCASE => ERROR; }; }; <> FileoutSceneAndOptions: PUBLIC PROC [f: IO.STREAM, ggData: GGData, fileName: Rope.ROPE, scene: Scene ¬ NIL] = { sceneOut: Scene ¬ IF scene#NIL THEN scene ELSE ggData.scene; sliceCount: NAT ¬ GGScene.CountSlices[sceneOut, first]; DoFileOut: PROC [slice: Slice] RETURNS [done: BOOL ¬ FALSE] = { f.PutChar[IO.LF]; -- CR before each top-Level slice GGSliceOps.FileoutSlice[f, slice]; }; f.PutF1["Gargoyle file for scene: %g\n", [rope[fileName]]]; f.PutF1["Produced by version %g\n\n", [rope[GGUtility.versionRope]]]; FileoutOptions[f, ggData]; FileoutSceneFields[f, ggData.scene]; f.PutChar[IO.LF]; f.PutF1["Entities: [%g]:\n\n", [integer[sliceCount]]]; [] ¬ GGScene.WalkSlices[sceneOut, first, DoFileOut]; }; FileoutSceneOnly: PUBLIC PROC [f: IO.STREAM, scene: Scene, fileName: Rope.ROPE] = { sliceCount: NAT ¬ GGScene.CountSlices[scene, first]; DoFileOut: PROC [slice: Slice] RETURNS [done: BOOL ¬ FALSE] = { f.PutChar[IO.LF]; GGSliceOps.FileoutSlice[f, slice]; }; f.PutF1["Gargoyle file for scene: %g\n", [rope[fileName]]]; f.PutF1["Produced by version %g\n\n", [rope[GGUtility.versionRope]]]; FileoutSceneFields[f, scene]; f.PutChar[IO.LF]; f.PutF1["Entities: [%g]:\n\n", [integer[sliceCount]]]; [] ¬ GGScene.WalkSlices[scene, first, DoFileOut]; }; FileoutSceneFields: PROC [f: IO.STREAM, scene: Scene] = { f.PutRope["BackgroundColor: "]; GGParseOut.WriteColor[f, GGScene.GetBackgroundColor[scene]]; f.PutChar[IO.LF]; }; FileoutOptions: PROC [f: IO.STREAM, ggData: GGData] = { values: LIST OF REAL; on: LIST OF BOOL; names: LIST OF Rope.ROPE; defaults: DefaultData; anchor: Caret; f.PutRope["ViewTransform: "]; GGParseOut.WriteTransformation[f, GGState.GetBiScrollersTransform[ggData]]; f.PutChar[IO.LF]; f.PutRope["Scripts: "]; GGParseOut.WriteListOfRope[f, ggData.debug.autoScriptNames.list]; f.PutChar[IO.LF]; f.PutRope["Slope: "]; [values, on] ¬ GGState.GetSlopeAlignments[ggData]; GGParseOut.WriteScalarButtonValues[f, NIL, values, on]; f.PutChar[IO.LF]; f.PutRope["Angle: "]; [values, on] ¬ GGState.GetAngleAlignments[ggData]; GGParseOut.WriteScalarButtonValues[f, NIL, values, on]; f.PutChar[IO.LF]; f.PutRope["Radius: "]; [names, values, on] ¬ GGState.GetRadiusAlignments[ggData]; GGParseOut.WriteScalarButtonValues[f, names, values, on]; f.PutChar[IO.LF]; f.PutRope["LineDistance: "]; [names, values, on] ¬ GGState.GetLineDistanceAlignments[ggData]; GGParseOut.WriteScalarButtonValues[f, names, values, on]; f.PutRope["\nMidpoints: "]; GGParseOut.WriteBool[f, GGState.GetMidpoints[ggData]]; f.PutRope["\nHeuristics: "]; GGParseOut.WriteBool[f, GGState.GetHeuristics[ggData]]; f.PutRope["\nShowAlignments: "]; GGParseOut.WriteBool[f, GGState.GetShowAlignments[ggData]]; f.PutF1["\nScaleUnit: %g", [real[GGState.GetScaleUnit[ggData]]] ]; f.PutF1["\nDisplayStyle: %g", [rope[GGUIUtility.DisplayStyleToRope[GGState.GetDisplayStyle[ggData]] ]] ]; f.PutRope["\nGravity: "]; GGParseOut.WriteBool[f, GGState.GetGravity[ggData]]; f.PutF1["\nGravityExtent: %g", [real[GGState.GetGravityExtent[ggData]]] ]; f.PutF1["\nGravityType: %g", [rope[GGUIUtility.GravityTypeToRope[GGState.GetGravityType[ggData]] ]] ]; defaults ¬ GGState.GetDefaults[ggData]; f.PutF1["\nDefaultFont: %g ", [rope[defaults.font.literal]] ]; GGParseOut.WriteFactoredTransformationVEC[f, defaults.font.transform]; f.PutF[" %g %g", [real[defaults.font.storedSize]], [real[defaults.font.designSize]] ]; f.PutRope["\nDefaults: "]; GGParseOut.WriteColor[f, defaults.fillColor]; f.PutChar[' ]; -- put a SPACE GGParseOut.WriteColor[f, defaults.strokeColor]; f.PutF1[" %g", [real[defaults.strokeWidth]] ]; f.PutF1[" %g", [rope[SELECT defaults.strokeJoint FROM bevel => "bevel", miter => "miter", ENDCASE => "round" ]] ]; f.PutF1[" %g", [rope[SELECT defaults.strokeEnd FROM square => "square", butt => "butt", ENDCASE => "round" ]] ]; f.PutRope["\nDashed: "]; GGParseOut.WriteBool[f, defaults.dashed]; IF defaults.dashed THEN { f.PutChar[' ]; -- put a SPACE GGParseOut.WriteArrayOfReal[f, defaults.pattern]; f.PutF[" %g %g", [real[defaults.offset]], [real[defaults.length]] ]; }; f.PutChar[' ]; -- put a SPACE f.PutRope["\nShadows: "]; GGParseOut.WriteColor[f, defaults.textColor]; GGParseOut.WriteBool[f, defaults.dropShadowOn]; IF defaults.dropShadowOn THEN { f.PutChar[' ]; -- put a SPACE GGParseOut.WritePoint[f, defaults.dropShadowOffset]; GGParseOut.WriteColor[f, defaults.dropShadowColor]; }; anchor ¬ GGState.GetAnchor[ggData]; f.PutRope["\nAnchor: "]; GGParseOut.WriteBool[f, IF anchor=NIL THEN FALSE ELSE anchor.exists]; IF anchor.exists THEN { f.PutChar[' ]; -- put a SPACE GGParseOut.WritePoint[f, anchor.point]; }; f.PutRope["\nPalette: "]; GGParseOut.WriteBool[f, GGState.GetPalette[ggData]]; f.PutRope["\nActive: "]; GGParseOut.WriteBool[f, GGState.GetActive[ggData]]; f.PutChar[IO.LF]; }; IsEndLine: PROC [c: CHAR] RETURNS [BOOL] = { RETURN[c=IO.CR OR c=IO.LF]; }; RegisterAllOptions[]; END.