summaryrefslogtreecommitdiff
path: root/ipl/gprocs/bitplane.icn
blob: 71e3d524b3826727f34ca1a4e56bdff0c3b88ddc (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
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
############################################################################
#
#	File:     bitplane.icn
#
#	Subject:  Procedures for bitplane manipulation
#
#	Author:   Gregg M. Townsend
#
#	Date:     May 2, 2001
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#	These procedures allow a window to be treated as a series of
#	overlapping, independent layers, subject to some fairly severe
#	restrictions.
#
#	AlcPlane(W n)		allocates planes.
#
#	FrontPlane(W bp, color)	moves a layer to the front.
#
#	BackPlane(W bp, color)	moves a layer to the back.
#
#	PlaneOp(W bp, op)	initializes layer operations.
#
#	Deplane(W color)	restores a window to normal.
#
############################################################################
#
#     These procedures allow drawing and erasing in individual bitplanes of
#  a window.  One way to use bitplanes is to think of them as transparent
#  panes in front of a solid background.  Each pane can be drawn with a
#  single color, obscuring the panes beyond (and the background).  A pane
#  can also be erased, wholly or selectively, exposing what is beyond; and
#  a pane need not be visible to be drawn or erased.  Panes can be restacked
#  in a different order, and the color of a pane (or the background) can be
#  changed.
#
#     For example, the pane in back could be drawn with a city map.  The
#  pane in front of that could be used to lay out bus routes, and the paths
#  could be erased and rerouted without having to redraw the map.  Using a
#  third plane in front of those, buses could be moved along the routes
#  without having to redraw either the routes or the map behind them.
#
#     Bitplanes that are allocated together and interact with each other
#  form a bitplane group.  A bitplane group need not fill the window;
#  indeed, it can be used in discontiguous portions of a window or even
#  in multiple windows on the same display.  On the other hand, multiple
#  bitplane groups can be used different parts of the same window.
#
#     Bitplanes are implemented using Icon's mutable colors, and they
#  are gluttonous of color map entries.  A set of n bitplanes requires
#  at least 2^n color map entries, so the practical limit of n is 5 or 6.
#  On the other hand, sets of 2 or 3 bitplanes are relatively cheap and
#  using several of them is not unreasonable.
#
#     Each bitplane group is identified by a base index b, which is the
#  index of the mutable color representing the background.  The individual
#  bitplanes are referenced as b+1, b+2, b+4 etc. using powers of two.
#  Other indices between b and b+2^n (exclusive) control the colors used
#  used when multiple bitplanes are drawn.  The FrontPlane and BackPlane
#  procedures provides simple control of these, and more sophisticated
#  effects (such as making a bitplane partially transparent) are possible
#  by setting them individually.
#
#
#
#  AlcPlane([win,] n) -- alc colors for n bitplanes
#
#     AlcPlane allocates a set of 2^n mutable colors chosen to be suitable
#  for the bitplane manipulations described below.  The colors are
#  consecutively indexed, and the base value b (the most negative index
#  value) is returned.  The base color is initialized to the current
#  background color, and the others are initialized to the foreground color.
#
#     A sequence of AlcPlane calls with different values of n is more
#  likely to succeed if the larger sets are allocated first.
#
#
#
#  FrontPlane([win,] bp, color) -- move indexed plane to "front"
#
#     FrontPlane sets the pixels in a bitplane to the given color and
#  moves the bitplane in front of the others in the set.  The color is
#  optional.
#
#     bp is the index (base+1, base+2, base+4, or whatever) denoting a
#  particular bitplane.  The move-to-the-front effect is accomplished by
#  calling Color() for all colors in the bitplane group whose index
#  after subtracting the base includes the particular bit.
#
#
#
#  BackPlane([win,] bp, color) -- move indexed plane to "back"
#
#     BackPlane sets the pixels in a bitplane to the given color and
#  moves the bitplane in back of the others in the set.  The color is
#  optional.
#
#     bp is the index (base+1, base+2, base+4, or whatever) denoting a
#  particular bitplane.  The move-to-the-back effect is accomplished by
#  calling Color() for all colors in the bitplane group whose index
#  after subtracting the base includes the particular bit.
#
#     A plane can be effectively rendered invisible by calling
#  BackPlane(win, bp, base);  this moves it to the back and sets
#  its color to the color of the background plane.
#
#
#
#  PlaneOp([win,] bp, op) -- set graphics context for plane operation
#
#     PlaneOp initializes the graphics context for drawing or erasing in
#  a particular bitplane.  bp is a bitplane index, as for FrontPlane;
#  multiple bits can be set to draw or erase several bitplanes
#  simultaneously.  op is usually one of two strings:
#
#	"set"	to draw the bits in a bitplane
#	"clear"	to erase the bits in a bitplane
#
#  Subsequent drawing operations will affect only the bits in the selected
#  bitplane.  Foreground operations are used for both drawing and erasure:
#  use FillRectangle, not EraseArea.
#
#     After calling PlaneOp with "set" or "clear", be SURE to draw only
#  in portions of the screen previously initialized with pixel values
#  from the same bitplane group.  Drawing anywhere else is liable to
#  produce strange, unwanted results.  Deplane (below) resets the window
#  for normal operation.
#
#     The op parameter can also be "copy", in which case the previous
#  contents of the window are immaterial and the drawn pixels are
#  initialized with the bitplanes specified.
#
#
#  Deplane([win,] color) -- restore normal drawop and set foreground
#
#     Deplane is called to restore normal drawing operations after setting
#  or clearing bits in a particular bitplane.  The foreground color can be
#  changed optionally.
#
#
#
#  Example:
#
#	b := AlcPlane(win, 3)			# get 3 planes
#	Color(win, b, "white")			# background will be white
#	FrontPlane(win, 1, "gray")		# city map will be gray
#	FrontPlane(win, 2, "navy")		# routes will be dark blue
#	FrontPlane(win, 4, "red")		# buses will be red
#	Fg(win, b)
#	DrawRectangle(win, x, y, w, h)		# initialize background
#	PlaneOp(win, b+1, "set")
#	drawmap()				# draw map
#	repeat {
#	   PlaneOp(win, b+2, "clear")
#	   DrawRectangle(x, y, w, h)		# clear old routes
#	   PlaneOp(win, b+2, "set")
#	   drawroutes()				# draw new routes
#	   while routes_ok() do
#	      runbuses()			# run buses using plane b+4
#	   }
#
#
#
#  Caveats
#
#     AlcPlane must repeatedly ask for new mutable colors until it gets a
#  set that is suitable.  Unwanted colors cannot be returned or freed, so
#  some color table entries are usually wasted.
#
#     No more than 7 bitplanes can be requested, and even that is chancy.
#
#     These routines will be confused by multiple displays.  Multiple
#  windows on a single display, or multiple bitplane sets in a window,
#  are no problem.
#
#     These routines depend on the internals of Icon, specifically the
#  mapping of window-system pixel values to mutable color indices.
#
#     The use of unusual "and" and "or" drawops makes the code hard to
#  understand.
#
############################################################################
#
#  Requires:  Version 9 graphics
#
############################################################################


global Plane_Mask


#  AlcPlane(win, n) -- allocate 2^n colors for bitplanes and return base b

procedure AlcPlane(win, n)		#: allocate colors for bitplane
   local ncolors, mask, b, seqlen, prev, fg, clist

   if type(win) ~== "window" then {
      n := win
      win := &window
      }

   if n < 1 | n > 7 then
      runerr(205, n)
   fg := Fg(win)

   ncolors := 2 ^ n
   mask := ncolors - 1

   # need to get ncolors colors in sequence, with the last one having the
   # low order n bits (of the actual pixel value) set

   # alternatives on Color are in case current fg/bg would cause failure

   b := NewColor(win, fg | "black") | fail
   clist := [b]
   seqlen := 1
   while seqlen < ncolors | iand(-1 - b, mask) ~= mask do {
      prev := b
      b := NewColor(win, fg | "black") | fail
      push(clist, b)
      if prev - b ~= 1 then
         seqlen := 1
      else
         seqlen +:= 1
      }

   # discard unwanted colors
   every 1 to ncolors do
      pop(clist)
   if *clist > 0 then {
      push(clist, win)
      FreeColor ! clist
      }

   # set base color to background and return result
   Color(win, b, Bg(win) | "white")
   /Plane_Mask := table()
   every Plane_Mask [b to b + mask] := mask
   return b
end



#  FrontPlane(win, bp, color) -- move indexed plane to "front", set color

procedure FrontPlane(win, bp, color)	#: move bitplane to front
   local mask, base, bits, i

   if type(win) ~== "window" then {
      win :=: bp :=: color
      win := &window
      }

   mask := \Plane_Mask[bp] | runerr(205, bp)
   base := iand(icom(mask), bp)
   bits := bp - base
   /color := bp
   every i := base to base + mask do
      if iand(i, bits) = bits then
         Color(win, i, color)
   return win
end



#  BackPlane(win, bp, color) -- move indexed plane to "back", set color

procedure BackPlane(win, bp, color)	#: move bitplane to back
   local mask, base, bits, i

   if type(win) ~== "window" then {
      win :=: bp :=: color
      win := &window
      }

   mask := \Plane_Mask[bp] | runerr(205, bp)
   base := iand(icom(mask), bp)
   bits := bp - base
   Color(win, bp, \color)			# set color if specified
   every i := base to base + mask do
      if iand(i, bits) = bits & i ~= bp then
         Color(win, i, ixor(i, bits))		# set color as if plane unset
   return win
end



#  PlaneOp(win, bp, op) -- set graphics context for plane operation

procedure PlaneOp(win, bp, op)		#: set context for bitplane operation
   local mask, base, bits, i

   if type(win) ~== "window" then {
      win :=: bp :=: op
      win := &window
      }

   mask := \Plane_Mask[bp] | runerr(205, bp)
   base := iand(icom(mask), bp)
   bits := bp - base

   case op of {
      "copy": {
         WAttrib(win, "drawop=copy")
         Fg(win, bp)
         }
      "set": {
         i := base + bits
         WAttrib(win, "drawop=and")
         Fg(win, i)
         }
      "clear": {
         i := base + (mask - bits)
         WAttrib(win, "drawop=or")
         Fg(win, i)
         }
      default:
         runerr(205, op)
      }
   return win
end



#  Deplane(win, color) -- restore normal drawop and set fg to color

procedure Deplane(win, color)

   if type(win) ~== "window" then {
      color := win
      win := &window
      }
   WAttrib(win, "drawop=copy")
   Fg(win, \color)
   return win
end