1 /*
2 * Schism Tracker - a cross-platform Impulse Tracker clone
3 * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
4 * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
5 * copyright (c) 2009 Storlek & Mrs. Brisby
6 * copyright (c) 2010-2012 Storlek
7 * URL: http://schismtracker.org/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* vgamem
25
26 this simulates a fictional vga-like card that supports three banks of characters, and
27 a packed display of 4000 32-bit words.
28
29 the banks are:
30 0x80000000 new overlay
31
32 the layout is relative to the scanline position: it gets pixel
33 values from "ovl" which is [640*400]
34
35 0x40000000 half-width font
36 the layout of this is based on a special bank of 4bit wide fonts.
37 the packing format of the field is:
38 fg1 is nybble in bits 22-25
39 fg2 is nybble in bits 26-29
40 bg1 is nybble in bits 18-21
41 bg2 is nybble in bits 14-17
42 ch1 is 7 bits; 7-13
43 ch2 is 7 bits: 0-6
44 lower bits are unused
45
46 0x10000080
47 bios font
48 this layout looks surprisingly like a real vga card
49 (mostly because it was ripped from one ;)
50 fg is nybble in bits 8-11
51 bg is nybble in bits 12-15
52 ch is lower byte
53 0x00000000
54 regular
55 this layout uses the itf font
56 fg is nybble in bits 8-11
57 bg is nybble in bits 12-15
58 ch is lower byte
59 */
60
61 #include "headers.h"
62
63 #include "it.h"
64 #include "dmoz.h" /* for dmoz_path_concat */
65
66 #include "sdlmain.h"
67
68 #include <assert.h>
69 #include <errno.h>
70
71 #include "util.h"
72 #include "video.h"
73
74 /* preprocessor stuff */
75
76 #define CHECK_INVERT(tl,br,n) \
77 do { \
78 if (status.flags & INVERTED_PALETTE) { \
79 n = tl; \
80 tl = br; \
81 br = n; \
82 } \
83 } while(0)
84
85 /* This isn't defined in an .h file since it's only used here. (maybe I
86 should make a header for declarations of all this auto-built stuff) */
87 extern const unsigned char font_default_lower[];
88 extern const unsigned char font_default_upper_alt[];
89 extern const unsigned char font_default_upper_itf[];
90 extern const unsigned char font_half_width[];
91
92 /* --------------------------------------------------------------------- */
93 /* statics */
94
95 static uint8_t font_normal[2048];
96
97 /* There's no way to change the other fontsets at the moment.
98 * (other than recompiling, of course) */
99 static uint8_t font_alt[2048];
100 static uint8_t font_half_data[1024];
101
102 /* --------------------------------------------------------------------- */
103 /* globals */
104
105 uint8_t *font_data = font_normal; /* this only needs to be global for itf */
106
107 /* int font_width = 8, font_height = 8; */
108
109 /* --------------------------------------------------------------------- */
110 /* half-width characters */
111
112 /* ok i think i get this now, after inspecting it further.
113 good thing no one bothered putting any comments in the code. <grumble>
114 the fake vga buffer is pigeonholing the half-width characters into 14 bits.
115 why 14, i don't know, but that means 7 bits per character, and these functions
116 handle shifting stuff around to get them into that space. realistically, we
117 only need to bother with chars 32 through 127, as well as 173 (middot) and
118 205 (the double-line used for noteoff). since 32->127 is 96 characters, there's
119 plenty of room for the printable stuff... and guess what, 173->205 is another
120 32, which fits nice and clean into 7 bits! so if the character is within that
121 range, we're fine. otherwise it'll just result in a broken glyph. (but it
122 probably wasn't drawn in the font anyway) */
123
_pack_halfw(int c)124 static inline int _pack_halfw(int c)
125 {
126 switch (c) {
127 case 32 ... 127: return c - 32; /* 0 ... 95 */
128 case 173 ... 205: return 96 + c - 173; /* 96 ... 127 */
129 default:
130 abort();
131 return '?';
132 }
133 }
134
_unpack_halfw(int c)135 static inline int _unpack_halfw(int c)
136 {
137 switch (c) {
138 case 0 ... 95: return c + 32;
139 case 96 ... 127: return 96 - c + 173;
140 default: return '?'; /* should never happen */
141 }
142 }
143
144 /* --------------------------------------------------------------------- */
145 /* ITF loader */
146
make_half_width_middot(void)147 static inline void make_half_width_middot(void)
148 {
149 /* this copies the left half of char 184 in the normal font (two
150 * half-width dots) to char 173 of the half-width font (the
151 * middot), and the right half to char 184. thus, putting
152 * together chars 173 and 184 of the half-width font will
153 * produce the equivalent of 184 of the full-width font. */
154
155 font_half_data[173 * 4 + 0] =
156 (font_normal[184 * 8 + 0] & 0xf0) |
157 (font_normal[184 * 8 + 1] & 0xf0) >> 4;
158 font_half_data[173 * 4 + 1] =
159 (font_normal[184 * 8 + 2] & 0xf0) |
160 (font_normal[184 * 8 + 3] & 0xf0) >> 4;
161 font_half_data[173 * 4 + 2] =
162 (font_normal[184 * 8 + 4] & 0xf0) |
163 (font_normal[184 * 8 + 5] & 0xf0) >> 4;
164 font_half_data[173 * 4 + 3] =
165 (font_normal[184 * 8 + 6] & 0xf0) |
166 (font_normal[184 * 8 + 7] & 0xf0) >> 4;
167
168 font_half_data[184 * 4 + 0] =
169 (font_normal[184 * 8 + 0] & 0xf) << 4 |
170 (font_normal[184 * 8 + 1] & 0xf);
171 font_half_data[184 * 4 + 1] =
172 (font_normal[184 * 8 + 2] & 0xf) << 4 |
173 (font_normal[184 * 8 + 3] & 0xf);
174 font_half_data[184 * 4 + 2] =
175 (font_normal[184 * 8 + 4] & 0xf) << 4 |
176 (font_normal[184 * 8 + 5] & 0xf);
177 font_half_data[184 * 4 + 3] =
178 (font_normal[184 * 8 + 6] & 0xf) << 4 |
179 (font_normal[184 * 8 + 7] & 0xf);
180 }
181
182 /* just the non-itf chars */
font_reset_lower(void)183 void font_reset_lower(void)
184 {
185 memcpy(font_normal, font_default_lower, 1024);
186 }
187
188 /* just the itf chars */
font_reset_upper(void)189 void font_reset_upper(void)
190 {
191 memcpy(font_normal + 1024, font_default_upper_itf, 1024);
192 make_half_width_middot();
193 }
194
195 /* all together now! */
font_reset(void)196 void font_reset(void)
197 {
198 memcpy(font_normal, font_default_lower, 1024);
199 memcpy(font_normal + 1024, font_default_upper_itf, 1024);
200 make_half_width_middot();
201 }
202
203 /* or kill the upper chars as well */
font_reset_bios(void)204 void font_reset_bios(void)
205 {
206 font_reset_lower();
207 memcpy(font_normal + 1024, font_default_upper_alt, 1024);
208 make_half_width_middot();
209 }
210
211 /* ... or just one character */
font_reset_char(int ch)212 void font_reset_char(int ch)
213 {
214 uint8_t *base;
215 int cx;
216
217 ch <<= 3;
218 cx = ch;
219 if (ch >= 1024) {
220 base = (uint8_t *) font_default_upper_itf;
221 cx -= 1024;
222 } else {
223 base = (uint8_t *) font_default_lower;
224 }
225 /* update them both... */
226 memcpy(font_normal + ch, base + cx, 8);
227
228 /* update */
229 make_half_width_middot();
230 }
231
232 /* --------------------------------------------------------------------- */
233
squeeze_8x16_font(FILE * fp)234 static int squeeze_8x16_font(FILE * fp)
235 {
236 uint8_t data_8x16[4096];
237 int n;
238
239 if (fread(data_8x16, 4096, 1, fp) != 1)
240 return -1;
241
242 for (n = 0; n < 2048; n++)
243 font_normal[n] = data_8x16[2 * n] | data_8x16[2 * n + 1];
244
245 return 0;
246 }
247
248 /* Hmm. I could've done better with this one. */
font_load(const char * filename)249 int font_load(const char *filename)
250 {
251 FILE *fp;
252 long pos;
253 uint8_t data[4];
254 char *font_dir, *font_file;
255
256 font_dir = dmoz_path_concat(cfg_dir_dotschism, "fonts");
257 font_file = dmoz_path_concat(font_dir, filename);
258 free(font_dir);
259
260 fp = fopen(font_file, "rb");
261 if (fp == NULL) {
262 SDL_SetError("%s: %s", font_file, strerror(errno));
263 free(font_file);
264 return -1;
265 }
266
267 fseek(fp, 0, SEEK_END);
268 pos = ftell(fp);
269 if (pos == 2050) {
270 /* Probably an ITF. Check the version. */
271
272 fseek(fp, -2, SEEK_CUR);
273 if (fread(data, 2, 1, fp) < 1) {
274 SDL_SetError("%s: %s", font_file,
275 feof(fp) ? "Unexpected EOF on read" : strerror(errno));
276 fclose(fp);
277 free(font_file);
278 return -1;
279 }
280 if (data[1] != 0x2 || (data[0] != 0x12 && data[0] != 9)) {
281 SDL_SetError("%s: Unsupported ITF file version %02x.%20x", font_file, data[1], data[0]);
282 fclose(fp);
283 free(font_file);
284 return -1;
285 }
286 rewind(fp);
287 } else if (pos == 2048) {
288 /* It's a raw file -- nothing else to check... */
289 rewind(fp);
290 } else if (pos == 4096) {
291 rewind(fp);
292 if (squeeze_8x16_font(fp) == 0) {
293 make_half_width_middot();
294 fclose(fp);
295 free(font_file);
296 return 0;
297 } else {
298 SDL_SetError("%s: %s", font_file,
299 feof(fp) ? "Unexpected EOF on read" : strerror(errno));
300 fclose(fp);
301 free(font_file);
302 return -1;
303 }
304 } else {
305 SDL_SetError("%s: Invalid font file", font_file);
306 fclose(fp);
307 free(font_file);
308 return -1;
309 }
310
311 if (fread(font_normal, 2048, 1, fp) != 1) {
312 SDL_SetError("%s: %s", font_file,
313 feof(fp) ? "Unexpected EOF on read" : strerror(errno));
314 fclose(fp);
315 free(font_file);
316 return -1;
317 }
318
319 make_half_width_middot();
320
321 fclose(fp);
322 free(font_file);
323 return 0;
324 }
325
font_save(const char * filename)326 int font_save(const char *filename)
327 {
328 FILE *fp;
329 uint8_t ver[2] = { 0x12, 0x2 };
330 char *font_dir, *font_file;
331
332 font_dir = dmoz_path_concat(cfg_dir_dotschism, "fonts");
333 font_file = dmoz_path_concat(font_dir, filename);
334 free(font_dir);
335
336 fp = fopen(font_file, "wb");
337 if (fp == NULL) {
338 SDL_SetError("%s: %s", font_file, strerror(errno));
339 free(font_file);
340 return -1;
341 }
342
343 if (fwrite(font_normal, 2048, 1, fp) < 1 || fwrite(ver, 2, 1, fp) < 1) {
344 SDL_SetError("%s: %s", font_file, strerror(errno));
345 fclose(fp);
346 free(font_file);
347 return -1;
348 }
349
350 fclose(fp);
351 free(font_file);
352 return 0;
353 }
354
font_init(void)355 void font_init(void)
356 {
357 memcpy(font_half_data, font_half_width, 1024);
358
359 if (font_load(cfg_font) != 0) {
360 SDL_ClearError();
361 font_reset();
362 }
363
364 memcpy(font_alt, font_default_lower, 1024);
365 memcpy(font_alt + 1024, font_default_upper_alt, 1024);
366 }
367
368 /* --------------------------------------------------------------------- */
369 static unsigned int vgamem[4000];
370 static unsigned int vgamem_read[4000];
371
372 static unsigned char ovl[640*400]; /* 256K */
373
vgamem_flip(void)374 void vgamem_flip(void)
375 {
376 memcpy(vgamem_read, vgamem, sizeof(vgamem));
377 }
vgamem_lock(void)378 void vgamem_lock(void)
379 {
380 }
vgamem_unlock(void)381 void vgamem_unlock(void)
382 {
383 }
384
vgamem_clear(void)385 void vgamem_clear(void)
386 {
387 memset(vgamem,0,sizeof(vgamem));
388 }
389
vgamem_ovl_alloc(struct vgamem_overlay * n)390 void vgamem_ovl_alloc(struct vgamem_overlay *n)
391 {
392 n->q = &ovl[ (n->x1*8) + (n->y1 * 5120) ];
393 n->width = 8 * ((n->x2 - n->x1) + 1);
394 n->height = 8 * ((n->y2 - n->y1) + 1);
395 n->skip = (640 - n->width);
396 }
vgamem_ovl_apply(struct vgamem_overlay * n)397 void vgamem_ovl_apply(struct vgamem_overlay *n)
398 {
399 unsigned int x, y;
400
401 for (y = n->y1; y <= n->y2; y++) {
402 for (x = n->x1; x <= n->x2; x++) {
403 vgamem[x + (y*80)] = 0x80000000;
404 }
405 }
406 }
407
vgamem_ovl_clear(struct vgamem_overlay * n,int color)408 void vgamem_ovl_clear(struct vgamem_overlay *n, int color)
409 {
410 int i, j;
411 unsigned char *q = n->q;
412 for (j = 0; j < n->height; j++) {
413 for (i = 0; i < n->width; i++) {
414 *q = color;
415 q++;
416 }
417 q += n->skip;
418 }
419 }
vgamem_ovl_drawpixel(struct vgamem_overlay * n,int x,int y,int color)420 void vgamem_ovl_drawpixel(struct vgamem_overlay *n, int x, int y, int color)
421 {
422 n->q[ (640*y) + x ] = color;
423 }
_draw_line_v(struct vgamem_overlay * n,int x,int ys,int ye,int color)424 static inline void _draw_line_v(struct vgamem_overlay *n, int x,
425 int ys, int ye, int color)
426 {
427 unsigned char *q = n->q + x;
428 int y;
429
430 if (ys < ye) {
431 q += (ys * 640);
432 for (y = ys; y <= ye; y++) {
433 *q = color;
434 q += 640;
435 }
436 } else {
437 q += (ye * 640);
438 for (y = ye; y <= ys; y++) {
439 *q = color;
440 q += 640;
441 }
442 }
443 }
_draw_line_h(struct vgamem_overlay * n,int xs,int xe,int y,int color)444 static inline void _draw_line_h(struct vgamem_overlay *n, int xs,
445 int xe, int y, int color)
446 {
447 unsigned char *q = n->q + (y * 640);
448 int x;
449 if (xs < xe) {
450 q += xs;
451 for (x = xs; x <= xe; x++) {
452 *q = color;
453 q++;
454 }
455 } else {
456 q += xe;
457 for (x = xe; x <= xs; x++) {
458 *q = color;
459 q++;
460 }
461 }
462 }
463 #ifndef ABS
464 # define ABS(x) ((x) < 0 ? -(x) : (x))
465 #endif
466 #ifndef SGN
467 # define SGN(x) ((x) < 0 ? -1 : 1) /* hey, what about zero? */
468 #endif
469
vgamem_ovl_drawline(struct vgamem_overlay * n,int xs,int ys,int xe,int ye,int color)470 void vgamem_ovl_drawline(struct vgamem_overlay *n, int xs,
471 int ys, int xe, int ye, int color)
472 {
473 int d, x, y, ax, ay, sx, sy, dx, dy;
474
475 dx = xe - xs;
476 if (dx == 0) {
477 _draw_line_v(n, xs, ys, ye, color);
478 return;
479 }
480
481 dy = ye - ys;
482 if (dy == 0) {
483 _draw_line_h(n, xs, xe, ys, color);
484 return;
485 }
486
487 ax = ABS(dx) << 1;
488 sx = SGN(dx);
489 ay = ABS(dy) << 1;
490 sy = SGN(dy);
491
492 x = xs;
493 y = ys;
494 if (ax > ay) {
495 /* x dominant */
496 d = ay - (ax >> 1);
497 for (;;) {
498 vgamem_ovl_drawpixel(n, x, y, color);
499 if (x == xe) break;
500 if (d >= 0) {
501 y += sy;
502 d -= ax;
503 }
504 x += sx;
505 d += ay;
506 }
507 } else {
508 /* y dominant */
509 d = ax - (ay >> 1);
510 for (;;) {
511 vgamem_ovl_drawpixel(n, x, y, color);
512 if (y == ye) break;
513 if (d >= 0) {
514 x += sx;
515 d -= ay;
516 }
517 y += sy;
518 d += ax;
519 }
520 }
521 }
522
523
524 /* write the vgamem routines */
525 #define BPP 32
526 #define F1 vgamem_scan32
527 #define F2 scan32
528 #define SIZE int
529 #include "vgamem-scanner.h"
530 #undef F2
531 #undef F1
532 #undef SIZE
533 #undef BPP
534
535 #define BPP 16
536 #define SIZE short
537 #define F1 vgamem_scan16
538 #define F2 scan16
539 #include "vgamem-scanner.h"
540 #undef F2
541 #undef F1
542 #undef SIZE
543 #undef BPP
544
545 #define BPP 8
546 #define SIZE char
547 #define F1 vgamem_scan8
548 #define F2 scan8
549 #include "vgamem-scanner.h"
550 #undef F2
551 #undef F1
552 #undef SIZE
553 #undef BPP
554
draw_char_bios(unsigned char c,int x,int y,uint32_t fg,uint32_t bg)555 void draw_char_bios(unsigned char c, int x, int y, uint32_t fg, uint32_t bg)
556 {
557 assert(x >= 0 && y >= 0 && x < 80 && y < 50);
558 vgamem[x + (y*80)] = c | (fg << 8) | (bg << 12) | 0x10000000;
559 }
560
draw_char(unsigned char c,int x,int y,uint32_t fg,uint32_t bg)561 void draw_char(unsigned char c, int x, int y, uint32_t fg, uint32_t bg)
562 {
563 assert(x >= 0 && y >= 0 && x < 80 && y < 50);
564 vgamem[x + (y*80)] = c | (fg << 8) | (bg << 12);
565 }
566
draw_text(const char * text,int x,int y,uint32_t fg,uint32_t bg)567 int draw_text(const char * text, int x, int y, uint32_t fg, uint32_t bg)
568 {
569 int n = 0;
570
571 while (*text) {
572 draw_char(*text, x + n, y, fg, bg);
573 n++;
574 text++;
575 }
576
577 return n;
578 }
draw_text_bios(const char * text,int x,int y,uint32_t fg,uint32_t bg)579 int draw_text_bios(const char * text, int x, int y, uint32_t fg, uint32_t bg)
580 {
581 int n = 0;
582
583 while (*text) {
584 draw_char_bios(*text, x + n, y, fg, bg);
585 n++;
586 text++;
587 }
588
589 return n;
590 }
draw_fill_chars(int xs,int ys,int xe,int ye,uint32_t color)591 void draw_fill_chars(int xs, int ys, int xe, int ye, uint32_t color)
592 {
593 unsigned int *mm;
594 int x, len;
595 mm = &vgamem[(ys * 80) + xs];
596 len = (xe - xs)+1;
597 ye -= ys;
598 do {
599 for (x = 0; x < len; x++) {
600 mm[x] = (color << 12) | (color << 8);
601 }
602 mm += 80;
603 ye--;
604 } while (ye >= 0);
605 }
606
draw_text_len(const char * text,int len,int x,int y,uint32_t fg,uint32_t bg)607 int draw_text_len(const char * text, int len, int x, int y, uint32_t fg, uint32_t bg)
608 {
609 int n = 0;
610
611 while (*text && n < len) {
612 draw_char(*text, x + n, y, fg, bg);
613 n++;
614 text++;
615 }
616 draw_fill_chars(x + n, y, x + len - 1, y, bg);
617 return n;
618 }
draw_text_bios_len(const char * text,int len,int x,int y,uint32_t fg,uint32_t bg)619 int draw_text_bios_len(const char * text, int len, int x, int y, uint32_t fg, uint32_t bg)
620 {
621 int n = 0;
622
623 while (*text && n < len) {
624 draw_char_bios(*text, x + n, y, fg, bg);
625 n++;
626 text++;
627 }
628 draw_fill_chars(x + n, y, x + len - 1, y, bg);
629 return n;
630 }
631
632 /* --------------------------------------------------------------------- */
633
draw_half_width_chars(uint8_t c1,uint8_t c2,int x,int y,uint32_t fg1,uint32_t bg1,uint32_t fg2,uint32_t bg2)634 void draw_half_width_chars(uint8_t c1, uint8_t c2, int x, int y,
635 uint32_t fg1, uint32_t bg1, uint32_t fg2, uint32_t bg2)
636 {
637 assert(x >= 0 && y >= 0 && x < 80 && y < 50);
638 vgamem[x + (y*80)] =
639 0x40000000
640 | (fg1 << 22) | (fg2 << 26)
641 | (bg1 << 18) | (bg2 << 14)
642 | (_pack_halfw(c1) << 7)
643 | (_pack_halfw(c2));
644 }
645 /* --------------------------------------------------------------------- */
646 /* boxes */
647
648 enum box_type {
649 BOX_THIN_INNER = 0, BOX_THIN_OUTER, BOX_THICK_OUTER
650 };
651
652 static const uint8_t boxes[4][8] = {
653 {139, 138, 137, 136, 134, 129, 132, 131}, /* thin inner */
654 {128, 130, 133, 135, 129, 134, 131, 132}, /* thin outer */
655 {142, 144, 147, 149, 143, 148, 145, 146}, /* thick outer */
656 };
657
_draw_box_internal(int xs,int ys,int xe,int ye,uint32_t tl,uint32_t br,const uint8_t ch[8])658 static void _draw_box_internal(int xs, int ys, int xe, int ye, uint32_t tl, uint32_t br, const uint8_t ch[8])
659 {
660 int n;
661
662 CHECK_INVERT(tl, br, n);
663
664 draw_char(ch[0], xs, ys, tl, 2); /* TL corner */
665 draw_char(ch[1], xe, ys, br, 2); /* TR corner */
666 draw_char(ch[2], xs, ye, br, 2); /* BL corner */
667 draw_char(ch[3], xe, ye, br, 2); /* BR corner */
668
669 for (n = xs + 1; n < xe; n++) {
670 draw_char(ch[4], n, ys, tl, 2); /* top */
671 draw_char(ch[5], n, ye, br, 2); /* bottom */
672 }
673 for (n = ys + 1; n < ye; n++) {
674 draw_char(ch[6], xs, n, tl, 2); /* left */
675 draw_char(ch[7], xe, n, br, 2); /* right */
676 }
677 }
678
draw_thin_inner_box(int xs,int ys,int xe,int ye,uint32_t tl,uint32_t br)679 void draw_thin_inner_box(int xs, int ys, int xe, int ye, uint32_t tl, uint32_t br)
680 {
681 _draw_box_internal(xs, ys, xe, ye, tl, br, boxes[BOX_THIN_INNER]);
682 }
683
draw_thick_inner_box(int xs,int ys,int xe,int ye,uint32_t tl,uint32_t br)684 void draw_thick_inner_box(int xs, int ys, int xe, int ye, uint32_t tl, uint32_t br)
685 {
686 /* this one can't use _draw_box_internal because the corner
687 * colors are different */
688
689 int n;
690
691 CHECK_INVERT(tl, br, n);
692
693 draw_char(153, xs, ys, tl, 2); /* TL corner */
694 draw_char(152, xe, ys, tl, 2); /* TR corner */
695 draw_char(151, xs, ye, tl, 2); /* BL corner */
696 draw_char(150, xe, ye, br, 2); /* BR corner */
697
698 for (n = xs + 1; n < xe; n++) {
699 draw_char(148, n, ys, tl, 2); /* top */
700 draw_char(143, n, ye, br, 2); /* bottom */
701 }
702 for (n = ys + 1; n < ye; n++) {
703 draw_char(146, xs, n, tl, 2); /* left */
704 draw_char(145, xe, n, br, 2); /* right */
705 }
706 }
707
draw_thin_outer_box(int xs,int ys,int xe,int ye,uint32_t c)708 void draw_thin_outer_box(int xs, int ys, int xe, int ye, uint32_t c)
709 {
710 _draw_box_internal(xs, ys, xe, ye, c, c, boxes[BOX_THIN_OUTER]);
711 }
712
draw_thin_outer_cornered_box(int xs,int ys,int xe,int ye,int flags)713 void draw_thin_outer_cornered_box(int xs, int ys, int xe, int ye, int flags)
714 {
715 const int colors[4][2] = { {3, 1}, {1, 3}, {3, 3}, {1, 1} };
716 int tl = colors[flags & BOX_SHADE_MASK][0];
717 int br = colors[flags & BOX_SHADE_MASK][1];
718 int n;
719
720 CHECK_INVERT(tl, br, n);
721
722 draw_char(128, xs, ys, tl, 2); /* TL corner */
723 draw_char(141, xe, ys, 1, 2); /* TR corner */
724 draw_char(140, xs, ye, 1, 2); /* BL corner */
725 draw_char(135, xe, ye, br, 2); /* BR corner */
726
727 for (n = xs + 1; n < xe; n++) {
728 draw_char(129, n, ys, tl, 2); /* top */
729 draw_char(134, n, ye, br, 2); /* bottom */
730 }
731
732 for (n = ys + 1; n < ye; n++) {
733 draw_char(131, xs, n, tl, 2); /* left */
734 draw_char(132, xe, n, br, 2); /* right */
735 }
736 }
737
draw_thick_outer_box(int xs,int ys,int xe,int ye,uint32_t c)738 void draw_thick_outer_box(int xs, int ys, int xe, int ye, uint32_t c)
739 {
740 _draw_box_internal(xs, ys, xe, ye, c, c, boxes[BOX_THICK_OUTER]);
741 }
742
draw_box(int xs,int ys,int xe,int ye,int flags)743 void draw_box(int xs, int ys, int xe, int ye, int flags)
744 {
745 const int colors[4][2] = { {3, 1}, {1, 3}, {3, 3}, {1, 1} };
746 int tl = colors[flags & BOX_SHADE_MASK][0];
747 int br = colors[flags & BOX_SHADE_MASK][1];
748
749 switch (flags & (BOX_TYPE_MASK | BOX_THICKNESS_MASK)) {
750 case BOX_THIN | BOX_INNER:
751 draw_thin_inner_box(xs, ys, xe, ye, tl, br);
752 break;
753 case BOX_THICK | BOX_INNER:
754 draw_thick_inner_box(xs, ys, xe, ye, tl, br);
755 break;
756 case BOX_THIN | BOX_OUTER:
757 draw_thin_outer_box(xs, ys, xe, ye, tl);
758 break;
759 case BOX_THICK | BOX_OUTER:
760 draw_thick_outer_box(xs, ys, xe, ye, tl);
761 break;
762 case BOX_THIN | BOX_CORNER:
763 case BOX_THICK | BOX_CORNER:
764 draw_thin_outer_cornered_box(xs, ys, xe, ye, flags & BOX_SHADE_MASK);
765 break;
766 }
767 }
768
769