-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathKaypro2Front.cs
314 lines (284 loc) · 15.9 KB
/
Kaypro2Front.cs
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
/*
Copyright 2019 Tamas Bolner
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System;
using System.Drawing;
namespace SteelSeriesAnimGif {
public class Kaypro2Font {
public class ConvertedText {
public byte[,] Data { get; }
public int Length { get; }
public ConvertedText(byte[,] data, int length) {
this.Data = data;
this.Length = length;
}
}
/*
Kaypro II (1982) characters
Extracted from the video ROM by Tamas Bolner
for the Java project CRTerm: https://github.com/bolner/CRTerm
*/
public static readonly byte[] bits = new byte[] {
0x0C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 0
0x00, 0x00, 0x00, 0x0D, 0x12, 0x12, 0x0D, 0x00, // Char 1
0x00, 0x00, 0x1C, 0x12, 0x1C, 0x12, 0x1C, 0x10, // Char 2
0x00, 0x00, 0x01, 0x1A, 0x04, 0x0B, 0x10, 0x00, // Char 3
0x00, 0x08, 0x10, 0x0C, 0x12, 0x12, 0x0C, 0x00, // Char 4
0x00, 0x00, 0x0C, 0x10, 0x1C, 0x10, 0x0C, 0x00, // Char 5
0x04, 0x04, 0x0E, 0x15, 0x15, 0x0E, 0x04, 0x04, // Char 6
0x00, 0x00, 0x00, 0x09, 0x15, 0x02, 0x02, 0x04, // Char 7
0x00, 0x0E, 0x11, 0x1F, 0x1F, 0x11, 0x0E, 0x00, // Char 8
0x00, 0x00, 0x00, 0x08, 0x08, 0x0A, 0x04, 0x00, // Char 9
0x00, 0x00, 0x00, 0x0F, 0x12, 0x12, 0x0C, 0x00, // Char 10
0x00, 0x00, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x00, // Char 11
0x00, 0x00, 0x10, 0x08, 0x04, 0x0A, 0x11, 0x00, // Char 12
0x00, 0x00, 0x00, 0x12, 0x12, 0x1C, 0x10, 0x10, // Char 13
0x00, 0x00, 0x11, 0x09, 0x09, 0x06, 0x04, 0x00, // Char 14
0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x0E, 0x00, // Char 15
0x00, 0x00, 0x00, 0x0F, 0x1A, 0x0A, 0x0A, 0x00, // Char 16
0x00, 0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x01, // Char 17
0x00, 0x00, 0x06, 0x09, 0x09, 0x0E, 0x08, 0x08, // Char 18
0x1F, 0x08, 0x04, 0x02, 0x04, 0x08, 0x1F, 0x00, // Char 19
0x00, 0x00, 0x00, 0x0F, 0x14, 0x04, 0x04, 0x00, // Char 20
0x00, 0x0A, 0x15, 0x05, 0x04, 0x04, 0x04, 0x00, // Char 21
0x04, 0x15, 0x15, 0x0E, 0x04, 0x04, 0x04, 0x00, // Char 22
0x00, 0x00, 0x02, 0x1F, 0x04, 0x1F, 0x08, 0x00, // Char 23
0x00, 0x00, 0x1F, 0x00, 0x0E, 0x00, 0x1F, 0x00, // Char 24
0x00, 0x00, 0x0E, 0x11, 0x11, 0x0A, 0x1B, 0x00, // Char 25
0x00, 0x10, 0x16, 0x0E, 0x04, 0x02, 0x02, 0x0C, // Char 26
0x06, 0x08, 0x08, 0x10, 0x08, 0x08, 0x06, 0x00, // Char 27
0x04, 0x04, 0x04, 0x00, 0x04, 0x04, 0x04, 0x00, // Char 28
0x0C, 0x02, 0x02, 0x01, 0x02, 0x02, 0x0C, 0x00, // Char 29
0x00, 0x00, 0x00, 0x08, 0x15, 0x02, 0x00, 0x00, // Char 30
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, // Char 31
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 32
0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04, 0x00, // Char 33
0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 34
0x0A, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x0A, 0x00, // Char 35
0x04, 0x0F, 0x14, 0x0E, 0x05, 0x1E, 0x04, 0x00, // Char 36
0x18, 0x19, 0x02, 0x04, 0x08, 0x13, 0x03, 0x00, // Char 37
0x08, 0x14, 0x14, 0x08, 0x15, 0x12, 0x0D, 0x00, // Char 38
0x06, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 39
0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02, 0x00, // Char 40
0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, // Char 41
0x04, 0x15, 0x0E, 0x04, 0x0E, 0x15, 0x04, 0x00, // Char 42
0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00, 0x00, // Char 43
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x04, // Char 44
0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, // Char 45
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, // Char 46
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, // Char 47
0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E, 0x00, // Char 48
0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E, 0x00, // Char 49
0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F, 0x00, // Char 50
0x0E, 0x11, 0x01, 0x06, 0x01, 0x11, 0x0E, 0x00, // Char 51
0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02, 0x00, // Char 52
0x1F, 0x10, 0x10, 0x1E, 0x01, 0x01, 0x1E, 0x00, // Char 53
0x0E, 0x10, 0x10, 0x1E, 0x11, 0x11, 0x0E, 0x00, // Char 54
0x1F, 0x11, 0x02, 0x04, 0x08, 0x08, 0x08, 0x00, // Char 55
0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E, 0x00, // Char 56
0x0E, 0x11, 0x11, 0x0F, 0x01, 0x01, 0x0E, 0x00, // Char 57
0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00, 0x00, // Char 58
0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x08, // Char 59
0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x00, // Char 60
0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00, 0x00, // Char 61
0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x00, // Char 62
0x0E, 0x11, 0x11, 0x02, 0x04, 0x00, 0x04, 0x00, // Char 63
0x0E, 0x11, 0x15, 0x1B, 0x16, 0x10, 0x0E, 0x00, // Char 64
0x04, 0x0A, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x00, // Char 65
0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E, 0x00, // Char 66
0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E, 0x00, // Char 67
0x1E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1E, 0x00, // Char 68
0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F, 0x00, // Char 69
0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10, 0x00, // Char 70
0x0E, 0x11, 0x10, 0x13, 0x11, 0x11, 0x0E, 0x00, // Char 71
0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11, 0x00, // Char 72
0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E, 0x00, // Char 73
0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x0E, 0x00, // Char 74
0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11, 0x00, // Char 75
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, // Char 76
0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11, 0x00, // Char 77
0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11, 0x00, // Char 78
0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E, 0x00, // Char 79
0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10, 0x00, // Char 80
0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D, 0x00, // Char 81
0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11, 0x00, // Char 82
0x0E, 0x11, 0x10, 0x0E, 0x01, 0x11, 0x0E, 0x00, // Char 83
0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, // Char 84
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E, 0x00, // Char 85
0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04, 0x00, // Char 86
0x11, 0x11, 0x11, 0x15, 0x15, 0x1B, 0x11, 0x00, // Char 87
0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11, 0x00, // Char 88
0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x00, // Char 89
0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F, 0x00, // Char 90
0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0E, 0x00, // Char 91
0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, // Char 92
0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, // Char 93
0x04, 0x0A, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 94
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, // Char 95
0x0C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 96
0x00, 0x00, 0x0E, 0x01, 0x0F, 0x11, 0x0F, 0x00, // Char 97
0x10, 0x10, 0x1E, 0x11, 0x11, 0x11, 0x1E, 0x00, // Char 98
0x00, 0x00, 0x0E, 0x11, 0x10, 0x10, 0x0E, 0x00, // Char 99
0x01, 0x01, 0x0F, 0x11, 0x11, 0x11, 0x0F, 0x00, // Char 100
0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0E, 0x00, // Char 101
0x06, 0x09, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x00, // Char 102
0x00, 0x00, 0x0E, 0x11, 0x11, 0x0F, 0x01, 0x0E, // Char 103
0x10, 0x10, 0x1E, 0x11, 0x11, 0x11, 0x11, 0x00, // Char 104
0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x0E, 0x00, // Char 105
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x11, 0x0E, // Char 106
0x08, 0x08, 0x09, 0x0A, 0x0C, 0x0A, 0x09, 0x00, // Char 107
0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E, 0x00, // Char 108
0x00, 0x00, 0x1A, 0x15, 0x15, 0x15, 0x15, 0x00, // Char 109
0x00, 0x00, 0x1E, 0x11, 0x11, 0x11, 0x11, 0x00, // Char 110
0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E, 0x00, // Char 111
0x00, 0x00, 0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, // Char 112
0x00, 0x00, 0x0F, 0x11, 0x11, 0x0F, 0x01, 0x01, // Char 113
0x00, 0x00, 0x16, 0x09, 0x08, 0x08, 0x08, 0x00, // Char 114
0x00, 0x00, 0x0E, 0x10, 0x0E, 0x01, 0x0E, 0x00, // Char 115
0x08, 0x08, 0x1C, 0x08, 0x08, 0x09, 0x06, 0x00, // Char 116
0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x0E, 0x00, // Char 117
0x00, 0x00, 0x11, 0x11, 0x0A, 0x0A, 0x04, 0x00, // Char 118
0x00, 0x00, 0x11, 0x11, 0x15, 0x1F, 0x0A, 0x00, // Char 119
0x00, 0x00, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x00, // Char 120
0x00, 0x00, 0x11, 0x11, 0x11, 0x0F, 0x01, 0x0E, // Char 121
0x00, 0x00, 0x1F, 0x02, 0x04, 0x08, 0x1F, 0x00, // Char 122
0x06, 0x08, 0x08, 0x10, 0x08, 0x08, 0x06, 0x00, // Char 123
0x04, 0x04, 0x04, 0x00, 0x04, 0x04, 0x04, 0x00, // Char 124
0x0C, 0x02, 0x02, 0x01, 0x02, 0x02, 0x0C, 0x00, // Char 125
0x00, 0x00, 0x08, 0x15, 0x02, 0x00, 0x00, 0x00, // Char 126
0x0A, 0x15, 0x0A, 0x15, 0x0A, 0x15, 0x0A, 0x00 // Char 127
};
/// <summary>
/// Output a character on the given bitmap image.
/// </summary>
/// <param name="bitmap">Render target</param>
/// <param name="code">Kaypro II character set code</param>
/// <param name="x">X coordinate of upper-left point</param>
/// <param name="y">Y coordinate of upper-left point</param>
/// <param name="color">Render color</param>
/// <param name="size">Size multiplier. Default = 1</param>
public static void DrawCharacter(Bitmap bitmap, int code, int x, int y, Color color, int size) {
if (code < 0 || code > 127) {
code = 32; // Space
}
for(int dx = 2; dx < 8; dx++) {
for(int dy = 0; dy < 8; dy++) {
int x1 = x + (dx - 2) * size;
int y1 = y + dy * size;
if (x1 < 0 || x1 >= bitmap.Width || y1 < 0 || y1 >= bitmap.Height) {
// Out of bounds
continue;
}
bool isSet = (Kaypro2Font.bits[code * 8 + dy] & (byte)(0x80 >> dx)) > 0;
for (int mx = 0; mx < size; mx++) {
for (int my = 0; my < size; my++) {
if (isSet) {
bitmap.SetPixel(x1 + mx, y1 + my, color);
} else {
bitmap.SetPixel(x1 + mx, y1 + my, Color.Black);
}
}
}
}
}
}
/// <summary>
/// Generates a character map of the Kaypro II character set
/// for the documentation.
/// </summary>
/// <returns>A bitmap, to be saved to disk.</returns>
public static Bitmap GenerateChart() {
var bmp = new Bitmap(760, 1000);
using(var graphics = Graphics.FromImage(bmp))
using(var brush = new SolidBrush(Color.Aquamarine))
using(var pen = new Pen(Color.DarkSlateGray, 3.5f))
using(var font = new Font("Arial", 12)) {
for (int nx = 0; nx < 8; nx++) {
for (int ny = 0; ny < 16; ny++) {
graphics.DrawRectangle(pen, (float)(nx * 90 + 19.5), (float)(ny * 60 + 19.5), 32.0f, 32.0f);
graphics.DrawString((ny * 8 + nx).ToString("D3"), font, brush, nx * 90 + 60, ny * 60 + 30);
}
}
}
for (int nx = 0; nx < 8; nx++) {
for (int ny = 0; ny < 16; ny++) {
Kaypro2Font.DrawCharacter(bmp, ny * 8 + nx, nx * 90 + 20, ny * 60 + 20, Color.White, 4);
}
}
return bmp;
}
/// <summary>
/// Converts a text into a byte array that
/// contains the Kaypro II character codes.
/// The text can contain escape codes with decimal
/// ASCII codes. For example:
/// "\065" for the letter "A"
/// </summary>
/// <param name="text">Input text to be decoded</param>
/// <returns>A 32*N byte array. If the input text is wider than 32, then it is cropped.</returns>
public static ConvertedText ConvertText(string text) {
int x = 0;
int y = 0;
int escRemain = 0;
int escCode = 0;
string[] lines = text.Split(
new[] { "\r\n", "\r", "\n" },
StringSplitOptions.None
);
byte[,] data = new byte[32, lines.Length];
for (int i = 0; i < 32; i++) {
for (int j = 0; j < lines.Length; j++) {
data[i, j] = 32; // Initialize with the space character
}
}
foreach(string line in lines) {
if (y >= lines.Length) {
break;
}
foreach(char c in line) {
if (x >=32) {
if (escRemain > 0) {
throw new Exception($"Invalid escape code on line {y + 1}:\n\n{line}\n");
}
break;
}
if (escRemain > 0) {
int value = c - 48;
if (value < 0 || value > 9) {
throw new Exception($"Invalid escape code on line {y + 1}:\n\n{line}\n");
}
escCode += value * (int)Math.Pow(10, escRemain - 1);
escRemain--;
if (escRemain == 0) {
if (escCode < 0 || escCode > 127) {
throw new Exception($"Invalid escape code on line {y + 1}:\n\n{line}\n");
}
data[x, y] = (byte)escCode;
x++;
}
}
else if (c == '\\') {
escRemain = 3;
escCode = 0;
}
else {
data[x, y] = (byte)c;
x++;
}
}
y++;
x = 0;
}
return new Kaypro2Font.ConvertedText(data, y);
}
}
}