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
|
/*
* title: uni.c
* abstract: Uniterm Terminal Window interface for Metafont.
* author: T.R.Hageman, Groningen, The Netherlands.
* created: May 1990
* modified:
* description:
* Uniterm (Simon Poole's terminal emulator for the Atari ST)
* emulates a `smart' Tektronix 4014 graphics terminal,
* and allows selective erasing of the graphics screen.
* (I do not know whether this is a standard feature of smart Teks
* or an invention of Mr. Poole)
*
* This file is offered as an alternative to the "standard"
* tektronix driver (which I find rather slow...)
*
* {{a possible way to improve the standard TEK driver would be to
* remember the (merged) transition lists instead converting to
* a bit map and back again.}}
*---*/
#define EXTERN extern
#include "../mfd.h"
#ifdef UNITERMWIN /* Whole file */
#define WIDTH 1024
#define HEIGHT 780
/*
* Send a vector to the graphics terminal
* (in a slightly optimized way).
*/
static void
sendvector(x, y)
register unsigned x, y;
{
static int Hi_Y, Lo_Y, Hi_X; /* remembered values */
register int Lo_Y_sent = 0;
register int t;
#ifdef DEBUG
if (x >= WIDTH) /* clip... */
x = WIDTH - 1;
if (y >= HEIGHT)
y = HEIGHT - 1;
#endif
/*
* Send Hi_Y only if it has changed.
*/
if ((t = 0x20|(y >> 5)) != Hi_Y) {
Hi_Y = t, putchar(t);
}
/*
* Likewise, send Lo_Y only if it has changed.
* (and remember that it has been sent)
*/
if ((t = 0x60|(y & 0x1f)) != Lo_Y) {
Lo_Y_sent = 1;
Lo_Y = t, putchar(t);
}
/*
* A slight complication here. If Hi_X has changed,
* we must send Lo_Y too, but only if we didn't already send it.
*/
if ((t = 0x20|(x >> 5)) != Hi_X) {
if (!Lo_Y_sent)
putchar(Lo_Y);
Hi_X = t, putchar(t);
}
/*
* Lo_X is always sent, so don't bother to remember it.
*/
t = 0x40|(x & 0x1f), putchar(t);
}
/*
* Tektronix has origin in lower-left corner, whereas MetaFont
* has its origin in the upper-left corner.
* The next macro hides this.
*/
#define VECTOR(col,row) sendvector((unsigned)(col),(unsigned)(HEIGHT-1-(row)))
/*
* GS - `Dark' vectors are in fact invisible, i.e., a move.
* (Also switches from text- to graphics screen.)
*/
#define DARK() putchar('\35')
/*
* CAN - Switch from graphics- to text screen.
*/
#define TEXT_SCREEN() putchar('\30')
/*
* ESC STX(ETX) - Enable(disable) block-fill mode.
*/
#define BLOCK(on) (putchar('\33'),putchar(2+!(on)))
/*
* ESC / 0(1) d - Set black(white) ink.
*/
#define INK(on) (putchar('\33'), putchar('\57'), \
putchar('\61'-(on)), putchar('\144'))
/*
* US - Switch to `alpha mode'
*/
#define ALPHA_MODE() putchar('\37')
/*
* ESC FF - clear graphics&alpha screen.
*/
#define ALPHA_CLS(); (putchar('\33'), putchar('\14'))
int
mf_uniterm_initscreen(void)
{
ALPHA_CLS();
TEXT_SCREEN();
return 1;
}
void
mf_uniterm_updatescreen(void)
{
DARK();
VECTOR(0,HEIGHT-1);
fflush(stdout);
TEXT_SCREEN(); /* switch to text mode */
}
void
mf_uniterm_blankrectangle (screencol left,
screencol right,
screenrow top,
screenrow bottom)
{
if (top==0 && left==0 && bottom>=HEIGHT-1 && right>=WIDTH-1) {
ALPHA_CLS();
return;
}
DARK();
VECTOR(left, top);
BLOCK(1); /* setup block erase mode */
INK(0); /* use white ink */
VECTOR(right-1, bottom-1); /* this draws the block */
BLOCK(0); /* back to (black) linedraw mode */
INK(1); /* black ink */
}
void
mf_uniterm_paintrow (screenrow row,
pixelcolor init_color,
register transspec transition_vector,
register screencol vector_size)
{
register int blank = !init_color;
#if 0
/* This is the basic */
DARK();
VECTOR(*transition_vector++, row); /* move to first transition */
do {
INK(blank ^= 1);
VECTOR(*transition_vector++ - 1, row);
} while (--vector_size > 0);
#endif
register screencol col;
/* However, we optimize the amount of output a bit by blanking
out the row first (since each INK command takes 4 bytes) */
DARK();
if (blank) {
VECTOR(transition_vector[((vector_size-1)&~1)+1] - 1, row);
INK(0);
VECTOR(*transition_vector++, row);
INK(1);
if (vector_size==1)
return;
}
else {
if (vector_size > 1) {
VECTOR(transition_vector[vector_size & ~1] - 1, row);
INK(0);
VECTOR(transition_vector[1], row);
INK(1);
DARK();
}
VECTOR(*transition_vector++, row);
}
do {
col = *transition_vector++;
if ((blank ^= 1) == 0)
DARK(); /* white -> black; move to first black pixel */
else
col--; /* black -> white; blacken to col-1 */
VECTOR(col, row);
} while (--vector_size > 0);
}
#else
int uniterm_dummy;
#endif /* UNITERMWIN */
|