<> <> <> DIRECTORY CGPath USING [Copy], GL, Graphics USING [ClipArea, ClipBox, Concat, Context, ContextRep, DrawArea, DrawBox, DrawImage, DrawRope, DrawStroke, DrawTo, GraphicsProcs, NewContext, nullMark, Save, Restore, SetColor, SetCP, SetFat, SetDefaultFont, SetPaintMode, Translate], GraphicsBasic USING [Box, Color, FontRef, ImageRef, Mark, PaintMode, Path, StrokeEnds, Texture, YMode], GraphicsOps USING [Disable, DrawTexturedBox, MoveDeviceRectangle, SetYMode], Rope USING [Concat, FromChar, ROPE]; GLImpl: CEDAR MONITOR IMPORTS CGPath, Graphics, GraphicsOps, Rope EXPORTS GL = { <> <> Context: TYPE = REF ContextRec; ContextRec: TYPE = RECORD [ context: Graphics.Context _ NIL, head, tail: List _ NIL ]; <> CommandType: TYPE = {LockNode, SetCP, DrawTo, DrawStroke, DrawArea, DrawBox, DrawImage, Translate, Concat, SetColor, SetPaintMode, SetFat, SetDefaultFont, DrawChars, ClipArea, ClipBox, Save, Restore, DrawBits, SetYMode, DrawTexturedBox, Disable, MoveDeviceRectangle }; <<>> <> List: PUBLIC TYPE = REF ListRec; ListRec: PUBLIC TYPE = RECORD [ next: List, -- pointer to the next mode in the graphics list command: SELECT commandType: CommandType FROM LockNode => [locked:BOOLEAN, notInUse:CONDITION], SetCP => [x,y: REAL, rel: BOOLEAN], DrawTo => [x,y: REAL, rel: BOOLEAN], DrawStroke => [path: GraphicsBasic.Path, width: REAL, closed: BOOLEAN, ends: GraphicsBasic.StrokeEnds], DrawArea => [path: GraphicsBasic.Path, parityFill: BOOLEAN], DrawBox => [box: GraphicsBasic.Box], DrawImage => [image: GraphicsBasic.ImageRef, raw: BOOLEAN], Translate => [tx,ty: REAL, round: BOOLEAN], Concat => [m11,m12,m21,m22: REAL], SetColor => [color: GraphicsBasic.Color], SetPaintMode => [mode: GraphicsBasic.PaintMode], SetFat => [fat: BOOLEAN], SetDefaultFont => [font: GraphicsBasic.FontRef], DrawChars => [font: GraphicsBasic.FontRef, rope: Rope.ROPE], --N.B., this doesn't match call args ClipArea => [path: GraphicsBasic.Path, parityFill: BOOLEAN, exclude: BOOLEAN], ClipBox => [box: GraphicsBasic.Box, exclude: BOOLEAN], Save => [mark: CARDINAL], Restore => [mark: CARDINAL], DrawBits => [base: LONG POINTER, raster: CARDINAL, bitsPerPixel: [0..16), x, y, w, h: CARDINAL, xorigin, yorigin: INTEGER], SetYMode => [mode: GraphicsBasic.YMode], DrawTexturedBox => [box: GraphicsBasic.Box, texture: GraphicsBasic.Texture], Disable => [], MoveDeviceRectangle => [width, height, fromX, fromY, toX, toY: NAT] ENDCASE ]; <<>> <> <<>> <> glProcs: REF Graphics.GraphicsProcs _ NEW[Graphics.GraphicsProcs _ [ GetCP: AmbushGetCP, SetCP: AmbushSetCP, DrawTo: AmbushDrawTo, DrawStroke: AmbushDrawStroke, DrawArea: AmbushDrawArea, DrawBox:AmbushDrawBox, DrawImage: AmbushDrawImage, Translate: AmbushTranslate, Concat: AmbushConcat, WorldToUser: AmbushWorldToUser, UserToWorld: AmbushUserToWorld, SetColor: AmbushSetColor, GetColor: AmbushGetColor, SetPaintMode: AmbushSetPaintMode, SetFat: AmbushSetFat, GetDefaultFont: AmbushGetDefaultFont, SetDefaultFont: AmbushSetDefaultFont, DrawChars: AmbushDrawChars, ClipArea: AmbushClipArea, ClipBox: AmbushClipBox, IsPointVisible: AmbushIsPointVisible, IsRectangular: AmbushIsRectangular, GetBounds: AmbushGetBounds, Visible: AmbushVisible, Save: AmbushSave, Restore: AmbushRestore, DrawBits: AmbushDrawBits, UserToDevice: AmbushUserToDevice, DeviceToUser: AmbushDeviceToUser, GetYMode: AmbushGetYMode, SetYMode: AmbushSetYMode, DrawTexturedBox: AmbushDrawTexturedBox, Disable: AmbushDisable, MoveDeviceRectangle: AmbushMoveDeviceRectangle ]]; <> Start: PUBLIC PROC[oldList: List _ NIL] RETURNS[dc:Graphics.Context] = { <> << >> context: Context; tail: List; newDc: Graphics.Context _ Graphics.NewContext[]; -- get a new screen context IF oldList = NIL THEN oldList _ NEW[LockNode ListRec]; -- client wants new list Lock[oldList]; -- prevent other reads or writes GraphicsOps.Disable[newDc]; -- only want its variables not its output FOR tail _ oldList, tail.next WHILE tail.next # NIL DO --find the tail for appends ENDLOOP; <> context _ NEW[ContextRec _ [context: newDc, head: oldList, tail: tail]]; <> dc _ NEW[Graphics.ContextRep _ [procs:glProcs, data:context]]; }; End: PUBLIC PROC[dc: Graphics.Context] RETURNS [list: List] = { <> <<>> IF dc.procs # glProcs THEN RETURN[NIL]; list _ NARROW[dc.data, Context].head; UnLock[list]; -- free it up for the next client }; Draw: PUBLIC PROC[context: Graphics.Context, list: List] = TRUSTED { <> <<>> head:List _ list; Lock[head]; -- prevent other reads or writes WHILE list # NIL DO -- execute each node on the list WITH node:list SELECT FROM SetCP => Graphics.SetCP[context, node.x, node.y, node.rel]; DrawTo => Graphics.DrawTo[context, node.x, node.y, node.rel]; DrawStroke => Graphics.DrawStroke[context, node.path, node.width, node.closed, node.ends]; DrawArea => Graphics.DrawArea[context, node.path, node.parityFill]; DrawBox => Graphics.DrawBox[context, node.box]; DrawImage => Graphics.DrawImage[context, node.image, node.raw]; Translate => Graphics.Translate[context, node.tx, node.ty, node.round]; Concat => Graphics.Concat[context, node.m11, node.m12, node.m21, node.m22]; SetColor => Graphics.SetColor[context, node.color]; SetPaintMode => [] _ Graphics.SetPaintMode[context, node.mode]; SetFat => [] _ Graphics.SetFat[context, node.fat]; SetDefaultFont => Graphics.SetDefaultFont[context, node.font]; DrawChars => Graphics.DrawRope[self: context, rope: node.rope, font: node.font]; ClipArea => Graphics.ClipArea[context, node.path, node.parityFill, node.exclude]; ClipBox => Graphics.ClipBox[context, node.box, node.exclude]; Save => [] _ Graphics.Save[context]; Restore => Graphics.Restore[context]; < >> <> SetYMode => GraphicsOps.SetYMode[context, node.mode]; DrawTexturedBox => GraphicsOps.DrawTexturedBox[context, node.box, node.texture]; Disable => GraphicsOps.Disable[context]; MoveDeviceRectangle => GraphicsOps.MoveDeviceRectangle[context, node.width, node.height, node.fromX, node.fromY, node.toX, node.toY]; ENDCASE; list _ list.next; ENDLOOP; UnLock[head]; -- free it up for the next client }; <> <<>> Lock: ENTRY PROC[list: List] = TRUSTED { <> WITH node:list SELECT FROM LockNode => { WHILE node.locked DO WAIT node.notInUse; ENDLOOP; node.locked _ TRUE; }; ENDCASE => ERROR; }; UnLock: ENTRY PROC[list: List] = TRUSTED { <> WITH node:list SELECT FROM LockNode => { node.locked _ FALSE; NOTIFY node.notInUse; }; ENDCASE => ERROR; }; <> <<>> AmbushGetCP: PUBLIC PROC[self: Graphics.Context, rounded: BOOLEAN] RETURNS[x,y: REAL] = { glContext: Context _ NARROW[self.data]; RETURN glContext.context.procs.GetCP[glContext.context, rounded]; }; AmbushSetCP: PUBLIC PROCEDURE[self: Graphics.Context, x,y: REAL, rel: BOOLEAN _ FALSE] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.SetCP[glContext.context, x, y, rel]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: SetCP [x: x, y: y, rel: rel]]]; }; AmbushDrawTo: PUBLIC PROCEDURE[self: Graphics.Context, x,y: REAL, rel: BOOLEAN _ FALSE] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.DrawTo[glContext.context, x, y, rel]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: DrawTo [x: x, y: y, rel: rel]]]; }; AmbushDrawStroke: PUBLIC PROCEDURE[self: Graphics.Context, path: GraphicsBasic.Path, width: REAL, closed: BOOLEAN, ends: GraphicsBasic.StrokeEnds] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.DrawStroke[glContext.context, path, width, closed, ends]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command:DrawStroke [path: CGPath.Copy[path], width: width, closed: closed, ends: ends]]]; }; AmbushDrawArea: PUBLIC PROCEDURE[self: Graphics.Context, path: GraphicsBasic.Path, parityFill: BOOLEAN _ FALSE] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.DrawArea[glContext.context, path, parityFill]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command:DrawArea [path: CGPath.Copy[path], parityFill: parityFill]]]; }; AmbushDrawBox: PUBLIC PROCEDURE[self: Graphics.Context, box: GraphicsBasic.Box] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.DrawBox[glContext.context, box]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: DrawBox [box: box]]]; }; AmbushDrawImage: PUBLIC PROCEDURE[self: Graphics.Context, image: GraphicsBasic.ImageRef, raw: BOOLEAN] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.DrawImage[glContext.context, image, raw]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: DrawImage [image: image, raw: raw]]]; }; AmbushTranslate: PUBLIC PROC[self: Graphics.Context, tx,ty: REAL, round: BOOLEAN _ FALSE] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.Translate[glContext.context, tx, ty, round]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: Translate [tx: tx, ty: ty, round: round]]]; }; AmbushConcat: PUBLIC PROCEDURE[self: Graphics.Context, m11,m12,m21,m22: REAL] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.Concat[glContext.context, m11, m12, m21, m22]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: Concat [m11: m11, m12: m12, m21: m21, m22: m22]]]; }; AmbushWorldToUser: PUBLIC PROC[self: Graphics.Context, wx,wy: REAL] RETURNS[x,y: REAL] = { glContext: Context _ NARROW[self.data]; RETURN glContext.context.procs.WorldToUser[glContext.context, wx, wy]; }; AmbushUserToWorld: PUBLIC PROC[self: Graphics.Context, x,y: REAL] RETURNS[wx,wy: REAL] = { glContext: Context _ NARROW[self.data]; RETURN glContext.context.procs.UserToWorld[glContext.context, x, y]; }; AmbushSetColor: PUBLIC PROCEDURE[self: Graphics.Context, color: GraphicsBasic.Color] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.SetColor[glContext.context, color]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: SetColor [color: color]]]; }; AmbushGetColor: PUBLIC PROC[self: Graphics.Context] RETURNS[GraphicsBasic.Color] = { glContext: Context _ NARROW[self.data]; RETURN glContext.context.procs.GetColor[glContext.context]; }; AmbushSetPaintMode: PUBLIC PROC[self: Graphics.Context, mode: GraphicsBasic.PaintMode] RETURNS[GraphicsBasic.PaintMode] = { glContext: Context _ NARROW[self.data]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: SetPaintMode [mode: mode]]]; RETURN glContext.context.procs.SetPaintMode[glContext.context, mode]; }; AmbushSetFat: PUBLIC PROCEDURE[self: Graphics.Context, fat: BOOLEAN] RETURNS[BOOLEAN] = { glContext: Context _ NARROW[self.data]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: SetFat [fat: fat]]]; RETURN glContext.context.procs.SetFat[glContext.context, fat]; }; AmbushGetDefaultFont: PUBLIC PROC[self: Graphics.Context] RETURNS[GraphicsBasic.FontRef] = { glContext: Context _ NARROW[self.data]; RETURN glContext.context.procs.GetDefaultFont[glContext.context]; }; AmbushSetDefaultFont: PUBLIC PROC[self: Graphics.Context, font: GraphicsBasic.FontRef] = { glContext: Context _ NARROW[self.data]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: SetDefaultFont [font: font]]]; glContext.context.procs.SetDefaultFont[glContext.context, font]; }; <<>> AmbushDrawChars: PUBLIC PROC[self: Graphics.Context, font: GraphicsBasic.FontRef, map: PROC[SAFE PROC[CHAR] RETURNS[BOOL]]] = { glContext: Context _ NARROW[self.data]; r: Rope.ROPE; MakeRope: SAFE PROC[c: CHAR] RETURNS[BOOL] = CHECKED { r _ Rope.Concat[r, Rope.FromChar[c]]; RETURN[FALSE]}; map[MakeRope]; glContext.context.procs.DrawChars[glContext.context, font, map]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: DrawChars [font: font, rope: r]]]; }; AmbushClipArea: PUBLIC PROCEDURE[self: Graphics.Context, path: GraphicsBasic.Path, parityFill: BOOLEAN, exclude: BOOLEAN] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.ClipArea[glContext.context, path, parityFill, exclude]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: ClipArea [path: CGPath.Copy[path], parityFill: parityFill, exclude: exclude]]]; }; AmbushClipBox: PUBLIC PROCEDURE[self: Graphics.Context, box: GraphicsBasic.Box, exclude: BOOLEAN _ FALSE] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.ClipBox[glContext.context, box, exclude]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: ClipBox [box: box, exclude: exclude]]]; }; AmbushIsPointVisible: PUBLIC PROC[self: Graphics.Context, x,y: REAL] RETURNS[BOOLEAN] = { glContext: Context _ NARROW[self.data]; RETURN[glContext.context.procs.IsPointVisible[glContext.context, x, y]]; }; AmbushIsRectangular: PUBLIC PROC[self: Graphics.Context] RETURNS[BOOLEAN] = { glContext: Context _ NARROW[self.data]; RETURN[glContext.context.procs.IsRectangular[glContext.context]]; }; AmbushGetBounds: PUBLIC PROC[self: Graphics.Context] RETURNS[GraphicsBasic.Box] = { glContext: Context _ NARROW[self.data]; RETURN[glContext.context.procs.GetBounds[glContext.context]]; }; AmbushVisible: PUBLIC PROC[self: Graphics.Context] RETURNS[BOOLEAN] = { glContext: Context _ NARROW[self.data]; RETURN[glContext.context.procs.Visible[glContext.context]]; }; <<>> AmbushSave: PUBLIC PROCEDURE[self: Graphics.Context] RETURNS[GraphicsBasic.Mark] = { glContext: Context _ NARROW[self.data]; mark: GraphicsBasic.Mark _ glContext.context.procs.Save[glContext.context]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: Save [mark: 0]]]; RETURN[mark]; }; AmbushRestore: PUBLIC PROCEDURE[self: Graphics.Context, mark: GraphicsBasic.Mark _ Graphics.nullMark] = { <<>> glContext: Context _ NARROW[self.data]; glContext.context.procs.Restore[glContext.context, mark]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: Restore [mark: 0]]]; }; AmbushDrawBits: PUBLIC UNSAFE PROC[self: Graphics.Context, base: LONG POINTER, raster: CARDINAL, bitsPerPixel: [0..16), x, y, w, h: CARDINAL, xorigin, yorigin: INTEGER] = TRUSTED { glContext: Context _ NARROW[self.data]; glContext.context.procs.DrawBits[glContext.context, base, raster, bitsPerPixel, x, y, w, h, xorigin, yorigin]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: DrawBits [base: base, raster: raster, bitsPerPixel: bitsPerPixel, x: x, y: y, w: w, h: h, xorigin: xorigin, yorigin: yorigin]]]; }; AmbushUserToDevice: PUBLIC PROC[self: Graphics.Context, x, y: REAL, rel: BOOLEAN] RETURNS[tx, ty: REAL] = { glContext: Context _ NARROW[self.data]; RETURN glContext.context.procs.UserToDevice[glContext.context, x, y, rel]; }; AmbushDeviceToUser: PUBLIC PROC[self: Graphics.Context, tx, ty: REAL, rel: BOOLEAN] RETURNS[x, y: REAL] = { glContext: Context _ NARROW[self.data]; RETURN glContext.context.procs.DeviceToUser[glContext.context, tx, ty, rel]; }; AmbushGetYMode: PUBLIC PROC[self: Graphics.Context] RETURNS[GraphicsBasic.YMode] = { glContext: Context _ NARROW[self.data]; RETURN[glContext.context.procs.GetYMode[glContext.context]]; }; AmbushSetYMode: PUBLIC PROC[self: Graphics.Context, mode: GraphicsBasic.YMode] = { glContext: Context _ NARROW[self.data]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: SetYMode [mode: mode]]]; glContext.context.procs.SetYMode[glContext.context, mode]; }; AmbushDrawTexturedBox: PUBLIC PROC[self: Graphics.Context, box: GraphicsBasic.Box, texture: GraphicsBasic.Texture] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.DrawTexturedBox[glContext.context, box, texture]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: DrawTexturedBox [box: box, texture: texture]]]; }; AmbushDisable: PUBLIC PROC[self: Graphics.Context] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.Disable[glContext.context]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: Disable []]]; }; AmbushMoveDeviceRectangle: PUBLIC PROC[self: Graphics.Context, width, height, fromX, fromY, toX, toY: NAT] = { glContext: Context _ NARROW[self.data]; glContext.context.procs.MoveDeviceRectangle[glContext.context, width, height, fromX, fromY, toX, toY]; glContext.tail _ glContext.tail.next _ NEW[ListRec _ [command: MoveDeviceRectangle[width: width, height: height, fromX: fromX, fromY: fromY, toX: toX, toY: toY]]]; }; }.