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