summaryrefslogtreecommitdiff
path: root/module/draw.m
blob: a9dabd8fa8dfbce701ff50b66a1b2e50b39689bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
Draw: module
{
	PATH:	con	"$Draw";

	# predefined colors; pass to Display.color
	Opaque:	con int 16rFFFFFFFF;
	Transparent:	con int 16r00000000;		# only useful for Display.newimage
	Black:	con int 16r000000FF;
	White:	con int 16rFFFFFFFF;
	Red:	con int 16rFF0000FF;
	Green:	con int 16r00FF00FF;
	Blue:	con int 16r0000FFFF;
	Cyan:	con int 16r00FFFFFF;
	Magenta:	con int 16rFF00FFFF;
	Yellow:	con int 16rFFFF00FF;
	Grey:	con int 16rEEEEEEFF;
	Paleyellow:	con int 16rFFFFAAFF;
	Darkyellow:	con int 16rEEEE9EFF;
	Darkgreen:	con int 16r448844FF;
	Palegreen:	con int 16rAAFFAAFF;
	Medgreen:	con int 16r88CC88FF;
	Darkblue:	con int 16r000055FF;
	Palebluegreen:	con int 16rAAFFFFFF;
	Paleblue:	con int 16r0000BBFF;
	Bluegreen:	con int 16r008888FF;
	Greygreen:	con int 16r55AAAAFF;
	Palegreygreen:	con int 16r9EEEEEFF;
	Yellowgreen:	con int 16r99994CFF;
	Medblue:	con int 16r000099FF;
	Greyblue:	con int 16r005DBBFF;
	Palegreyblue:	con int 16r4993DDFF;
	Purpleblue:	con int 16r8888CCFF;

	Notacolor:	con int 16rFFFFFF00;
	Nofill:		con Notacolor;

	# end styles for line
	Endsquare:	con 0;
	Enddisc:	con 1;
	Endarrow:	con 2;

	# flush control
	Flushoff:	con 0;
	Flushon:	con 1;
	Flushnow:	con 2;

	# image backing store
	Refbackup:	con 0;
	Refnone:	con 1;

	# compositing operators
	SinD:	con 1<<3;
	DinS:	con 1<<2;
	SoutD:	con 1<<1;
	DoutS:	con 1<<0;

	S:		con SinD|SoutD;
	SoverD:	con SinD|SoutD|DoutS;
	SatopD:	con SinD|DoutS;
	SxorD:	con SoutD|DoutS;

	D:		con DinS|DoutS;
	DoverS:	con DinS|DoutS|SoutD;
	DatopS:	con DinS|SoutD;
	DxorS:	con DoutS|SoutD;

	Clear:	con 0;

	# Image channels descriptor
	Chans: adt
	{
		desc:	int;		# descriptor packed into an int

		# interpret standard channel string
		mk:	fn(s: string): Chans;
		# standard printable form
		text:	fn(c: self Chans): string;
		# equality
		eq:	fn(c: self Chans, d: Chans): int;
		# bits per pixel
		depth:	fn(c: self Chans): int;
	};

	CRed, CGreen, CBlue, CGrey, CAlpha, CMap, CIgnore: con iota;

	GREY1: con Chans((CGrey<<4) | 1);
	GREY2: con Chans((CGrey<<4) | 2);
	GREY4: con Chans((CGrey<<4) | 4);
	GREY8: con Chans((CGrey<<4) | 8);
	CMAP8: con Chans((CMap<<4) | 8);
	RGB15: con Chans(((CIgnore<<4)|1)<<24 | ((CRed<<4)|5)<<16 | ((CGreen<<4)|5)<<8 | ((CBlue<<4)|5));
	RGB16: con Chans(((CRed<<4)|5)<<16 | ((CGreen<<4)|6)<<8 | ((CBlue<<4)|5));
	RGB24: con Chans(((CRed<<4)|8)<<16 | ((CGreen<<4)|8)<<8 | ((CBlue<<4)|8));
	RGBA32: con Chans((((CRed<<4)|8)<<24 | ((CGreen<<4)|8)<<16 | ((CBlue<<4)|8))<<8 | ((CAlpha<<4)|8));
	ARGB32: con Chans(((CAlpha<<4)|8)<<24 | ((CRed<<4)|8)<<16 | ((CGreen<<4)|8)<<8 | ((CBlue<<4)|8));	# stupid VGAs
	XRGB32: con Chans(((CIgnore<<4)|8)<<24 | ((CRed<<4)|8)<<16 | ((CGreen<<4)|8)<<8 | ((CBlue<<4)|8));	# stupid VGAs

	# Coordinate of a pixel on display
	Point: adt
	{
		x:	int;
		y:	int;

		# arithmetic
		add:	fn(p: self Point, q: Point): Point;
		sub:	fn(p: self Point, q: Point): Point;
		mul:	fn(p: self Point, i: int): Point;
		div:	fn(p: self Point, i: int): Point;
		# equality
		eq:	fn(p: self Point, q: Point): int;
		# inside rectangle
		in:	fn(p: self Point, r: Rect): int;
	};

	# Rectangle of pixels on the display; min <= max
	Rect: adt
	{
		min:	Point;	# upper left corner
		max:	Point;	# lower right corner

		# make sure min <= max
		canon:		fn(r: self Rect): Rect;
		# extent
		dx:		fn(r: self Rect): int;
		dy:		fn(r: self Rect): int;
		size:		fn(r: self Rect): Point;
		# equality
		eq:		fn(r: self Rect, s: Rect): int;
		# intersection and clipping
		Xrect:		fn(r: self Rect, s: Rect): int;
		inrect:		fn(r: self Rect, s: Rect): int;
		clip:		fn(r: self Rect, s: Rect): (Rect, int);
		contains:	fn(r: self Rect, p: Point): int;
		combine:	fn(r: self Rect, s: Rect): Rect;
		# arithmetic
		addpt:		fn(r: self Rect, p: Point): Rect;
		subpt:		fn(r: self Rect, p: Point): Rect;
		inset:		fn(r: self Rect, n: int): Rect;
	};

	# a picture; if made by Screen.newwindow, a window.  always attached to a Display
	Image: adt
	{
		# these data are local copies, but repl and clipr
		# are monitored by the runtime and may be modified as desired.
		r:	Rect;		# rectangle in data area, local coords
		clipr:	Rect;		# clipping region
		depth:	int;		# number of bits per pixel
		chans:	Chans;
		repl:	int;		# whether data area replicates to tile the plane
		display:	ref Display; # where Image resides
		screen:		ref Screen;	 # nil if not window
		iname:	string;

		# graphics operators
		drawop:		fn(dst: self ref Image, r: Rect, src: ref Image, matte: ref Image, p: Point, op: int);
		draw:		fn(dst: self ref Image, r: Rect, src: ref Image, matte: ref Image, p: Point);
		gendrawop:		fn(dst: self ref Image, r: Rect, src: ref Image, p0: Point, matte: ref Image, p1: Point, op: int);
		gendraw:		fn(dst: self ref Image, r: Rect, src: ref Image, p0: Point, matte: ref Image, p1: Point);
		lineop:		fn(dst: self ref Image, p0,p1: Point, end0,end1,radius: int, src: ref Image, sp: Point, op: int);
		line:		fn(dst: self ref Image, p0,p1: Point, end0,end1,radius: int, src: ref Image, sp: Point);
		polyop:		fn(dst: self ref Image, p: array of Point, end0,end1,radius: int, src: ref Image, sp: Point, op: int);
		poly:		fn(dst: self ref Image, p: array of Point, end0,end1,radius: int, src: ref Image, sp: Point);
		bezsplineop:		fn(dst: self ref Image, p: array of Point, end0,end1,radius: int, src: ref Image, sp: Point, op: int);
		bezspline:		fn(dst: self ref Image, p: array of Point, end0,end1,radius: int, src: ref Image, sp: Point);
		fillpolyop:	fn(dst: self ref Image, p: array of Point, wind: int, src: ref Image, sp: Point, op: int);
		fillpoly:	fn(dst: self ref Image, p: array of Point, wind: int, src: ref Image, sp: Point);
		fillbezsplineop:	fn(dst: self ref Image, p: array of Point, wind: int, src: ref Image, sp: Point, op: int);
		fillbezspline:	fn(dst: self ref Image, p: array of Point, wind: int, src: ref Image, sp: Point);
		ellipseop:	fn(dst: self ref Image, c: Point, a, b, thick: int, src: ref Image, sp: Point, op: int);
		ellipse:	fn(dst: self ref Image, c: Point, a, b, thick: int, src: ref Image, sp: Point);
		fillellipseop:	fn(dst: self ref Image, c: Point, a, b: int, src: ref Image, sp: Point, op: int);
		fillellipse:	fn(dst: self ref Image, c: Point, a, b: int, src: ref Image, sp: Point);
		arcop:	fn(dst: self ref Image, c: Point, a, b, thick: int, src: ref Image, sp: Point, alpha, phi: int, op: int);
		arc:	fn(dst: self ref Image, c: Point, a, b, thick: int, src: ref Image, sp: Point, alpha, phi: int);
		fillarcop:	fn(dst: self ref Image, c: Point, a, b: int, src: ref Image, sp: Point, alpha, phi: int, op: int);
		fillarc:	fn(dst: self ref Image, c: Point, a, b: int, src: ref Image, sp: Point, alpha, phi: int);
		bezierop:	fn(dst: self ref Image, a,b,c,d: Point, end0,end1,radius: int, src: ref Image, sp: Point, op: int);
		bezier:	fn(dst: self ref Image, a,b,c,d: Point, end0,end1,radius: int, src: ref Image, sp: Point);
		fillbezierop:	fn(dst: self ref Image, a,b,c,d: Point, wind:int, src: ref Image, sp: Point, op: int);
		fillbezier:	fn(dst: self ref Image, a,b,c,d: Point, wind:int, src: ref Image, sp: Point);
		textop:		fn(dst: self ref Image, p: Point, src: ref Image, sp: Point, font: ref Font, str: string, op: int): Point;
		text:		fn(dst: self ref Image, p: Point, src: ref Image, sp: Point, font: ref Font, str: string): Point;
		textbgop:		fn(dst: self ref Image, p: Point, src: ref Image, sp: Point, font: ref Font, str: string, bg: ref Image, bgp: Point, op: int): Point;
		textbg:		fn(dst: self ref Image, p: Point, src: ref Image, sp: Point, font: ref Font, str: string, bg: ref Image, bgp: Point): Point;
		border:	fn(dst: self ref Image, r: Rect, i: int, src: ref Image, sp: Point);
		arrow:		fn(a,b,c: int): int;
		# direct access to pixels
		readpixels:	fn(src: self ref Image, r: Rect, data: array of byte): int;
		writepixels:	fn(dst: self ref Image, r: Rect, data: array of byte): int;
		# publishing
		name:	fn(src: self ref Image, name: string, in: int): int;
		# windowing
		top:		fn(win: self ref Image);
		bottom:		fn(win: self ref Image);
		flush:		fn(win: self ref Image, func: int);
		origin:		fn(win: self ref Image, log, scr: Point): int;
	};

	# a frame buffer, holding a connection to /dev/draw
	Display: adt
	{
		image:	ref Image;	# holds the contents of the display
		white:	ref Image;
		black:	ref Image;
		opaque:	ref Image;
		transparent:	ref Image;

		# allocate and start refresh slave
		allocate:	fn(dev: string): ref Display;
		startrefresh:	fn(d: self ref Display);
		# attach to existing Screen
		publicscreen:	fn(d: self ref Display, id: int): ref Screen;
		getwindow:	fn(d: self ref Display, winname: string, screen: ref Screen, image: ref Image, backup: int): (ref Screen, ref Image);
		# image creation
		newimage:	fn(d: self ref Display, r: Rect, chans: Chans, repl, color: int): ref Image;
		color:		fn(d: self ref Display, color: int): ref Image;
		colormix:		fn(d: self ref Display, c1: int, c2: int): ref Image;
		rgb:		fn(d: self ref Display, r, g, b: int): ref Image;
		# attach to named Image
		namedimage:	fn(d: self ref Display, name: string): ref Image;
		# I/O to files
		open:		fn(d: self ref Display, name: string): ref Image;
		readimage:	fn(d: self ref Display, fd: ref Sys->FD): ref Image;
		writeimage:	fn(d: self ref Display, fd: ref Sys->FD, i: ref Image): int;
		# color map
		rgb2cmap:	fn(d: self ref Display, r, g, b: int): int;
		cmap2rgb:	fn(d: self ref Display, c: int): (int, int, int);
		cmap2rgba:	fn(d: self ref Display, c: int): int;
	};

	# a mapping between characters and pictures; always attached to a Display
	Font: adt
	{
		name:	string;		# *default* or a file name (this may change)
		height:	int;		# interline spacing of font
		ascent:	int;		# distance from baseline to top
		display:	ref Display;	# where Font resides

		# read from file or construct from local description
		open:		fn(d: ref Display, name: string): ref Font;
		build:		fn(d: ref Display, name, desc: string): ref Font;
		# string extents
		width:		fn(f: self ref Font, str: string): int;
		bbox:		fn(f: self ref Font, str: string): Rect;
	};

	# a collection of windows; always attached to a Display
	Screen: adt
	{
		id:		int;		# for export when public
		image:		ref Image;	# root of window tree
		fill:		ref Image;	# picture to use when repainting
		display:	ref Display;	# where Screen resides

		# create; see also Display.publicscreen
		allocate:	fn(image, fill: ref Image, public: int): ref Screen;
		# allocate a new window
		newwindow:	fn(screen: self ref Screen, r: Rect, backing: int, color: int): ref Image;
		# raise or lower a group of windows
		top:		fn(screen: self ref Screen, wins: array of ref Image);
		bottom:		fn(screen: self ref Screen, wins: array of ref Image);
	};

	# the state of a pointer device, e.g. a mouse or stylus
	Pointer: adt
	{
		buttons:	int;	# bits 1 2 4 ... represent state of buttons left to right; 1 means pressed
		xy:		Point;	# position
		msec:	int;	# millisecond time stamp
	};

	# graphics context
	Context: adt
	{
		display: 	ref Display;		# frame buffer on which windows reside
		screen:		ref Screen;			# place to make windows (mux only)
		wm:	chan of (string, chan of (string, ref Wmcontext));		# connect to window manager
	};

	# connection to window manager for one or more windows (as Images)
	Wmcontext: adt
	{
		kbd: 		chan of int;		# incoming characters from keyboard
		ptr: 		chan of ref Pointer;	# incoming stream of mouse positions
		ctl:		chan of string;		# commands from wm to application
		wctl:		chan of string;		# commands from application to wm
		images:	chan of ref Image;	# exchange of images
		connfd:	ref Sys->FD;		# connection control
		ctxt:		ref Context;
	};

	# functions that don't fit well in any adt
	setalpha:	fn(c: int, a: int): int;
	bytesperline:	fn(r: Rect, d: int): int;
	icossin:	fn(deg: int): (int, int);
	icossin2:	fn(p: Point): (int, int);
};