1 #include <string.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <signal.h>
5 #include <stdio.h>	/* for reading stdout.tmp etc. */
6 #include "../config.h"
7 #include <allegro.h>
8 #ifdef UNIX
9 #include <xalleg.h>	/* _xwin.application_name,
10 			   _xwin.application_class */
11 #endif
12 #include "textgfx.h"
13 #include "alleg.h"
14 #include "../options.h"
15 #include "../lang.h"
16 #include "../version.h"
17 #include "../input/keyboard.h"
18 
19 #if defined ALLEGRO_WITH_XWINDOWS && defined ALLEGRO_USE_CONSTRUCTOR
20 #include "allegro_icon.h"
21 extern void *allegro_icon;
22 CONSTRUCTOR_FUNCTION(static void _set_allegro_icon());
_set_allegro_icon()23 static void _set_allegro_icon()
24 {
25 	allegro_icon = icon_xpm;
26 }
27 #endif
28 
29 void blockstyle_from_option(const struct option *o);
30 int ibmgfx(int ch);
31 
32 unsigned textgfx_flags = HEIGHT_24L;
33 
34 char term_width = 80;
35 char term_height = 25;
36 
37 static char curs_x = 0;
38 static char curs_y = 0;
39 char margin_x = 0;
40 
41 int win_x = 0;
42 int win_y = 0;
43 
44 BITMAP *virt_screen = NULL;
45 int refresh_needed = 0;
46 char blit_rect[4] = {0};
47 
48 int close_button_pressed = 0;
49 
50 static FONT *font8x16;
51 static int vgacolors[16];
52 static unsigned char bg_color;
53 static unsigned char fg_color;
54 
55 #ifdef UNIX
56 static struct sigaction allegro_sigint_handler;
57 #endif
58 
gettermsize()59 void gettermsize() {}
settermwidth(int w)60 void settermwidth(int w) {}
settermheight(int h)61 void settermheight(int h) {}
62 
gettermoptions()63 void gettermoptions()
64 {
65 	struct option *o = getoptions("term");
66 	for (; o; o = o->next) {
67 		if (!strcmp(opt_key(o), "drawing")) {
68 			if (o->val.integ)
69 				textgfx_flags |= ASCII;
70 		} else if (!strcmp(opt_key(o), "color")) {
71 			if (!o->val.integ)
72 				textgfx_flags |= MONOCHROME;
73 		} else
74 			blockstyle_from_option(o);
75 	}
76 	reset_block_chars();
77 }
78 
79 #ifdef UNIX
sigint_handler(int sig)80 static void sigint_handler(int sig)
81 {
82 	textgfx_end();
83 	allegro_sigint_handler.sa_handler(sig);
84 }
85 #endif
86 
load_pc8x16_font()87 static void load_pc8x16_font()
88 {
89 	char fname[256];
90 	int n;
91 	char *p;
92 	get_executable_name(fname, sizeof(fname));
93 	n = strlen(fname);
94 	do n--;
95 	while (fname[n] !='\\' && fname[n] !='/');
96 	fname[n] = '\0';
97 	append_filename(fname, fname, "pc8x16.fnt", sizeof(fname));
98 	font8x16 = load_font(fname, NULL, NULL);
99 	if (font8x16)
100 		return;
101 	p = getenv("ALLEGRO");
102 	if (p) {
103 		strncpy(fname, p, sizeof(fname));
104 		append_filename(fname, fname, "vitetris", sizeof(fname));
105 		set_allegro_resource_path(5, fname);
106 	}
107 #ifdef UNIX
108 	set_allegro_resource_path(4, "/usr/share/allegro/vitetris");
109 	set_allegro_resource_path(3, "/usr/share/allegro");
110 	set_allegro_resource_path(2, "/usr/local/share/allegro/vitetris");
111 	set_allegro_resource_path(1, "/usr/local/share/allegro");
112 #endif
113 	if (find_allegro_resource(fname, "pc8x16.fnt", 0,0,0,0,0,
114 							sizeof(fname)) == 0)
115 		font8x16 = load_font(fname, NULL, NULL);
116 }
117 
close_btn()118 static void close_btn()
119 {
120 	close_button_pressed = 1;
121 }
122 
lost_focus()123 static void lost_focus()
124 {
125 	textgfx_flags |= LOST_FOCUS;
126 	clear_keybuf();
127 }
128 
got_focus_back()129 static void got_focus_back()
130 {
131 	textgfx_flags &= ~LOST_FOCUS;
132 	kb_flushinp();
133 	refresh_needed = 1;
134 	refreshscreen();
135 }
136 
setgfxmode(int fullscreen)137 static int setgfxmode(int fullscreen)
138 {
139 	if (!fullscreen &&
140 	    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 512, 400, 0, 0) == 0) {
141 		term_width = 64;
142 		set_display_switch_mode(SWITCH_BACKGROUND);
143 		set_display_switch_callback(SWITCH_OUT, lost_focus);
144 		return 1;
145 	}
146 	if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) == 0) {
147 		term_width = 80;
148 		set_display_switch_mode(SWITCH_PAUSE);
149 		return 1;
150 	}
151 	if (get_color_depth() != 8) {
152 		set_color_depth(8);
153 		return setgfxmode(fullscreen);
154 	}
155 	set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
156 	allegro_message("Unable to set any graphics mode:\n"
157 			"%s\n", allegro_error);
158 	return 0;
159 }
160 
set_screen(int fullscreen)161 BITMAP *set_screen(int fullscreen)
162 {
163 	const unsigned char
164 	vgargb[16][3] = {
165 		  0,  0,  0,	/* 0 black */
166 		170,  0,  0,	/* 1 red */
167 		  0,170,  0, 	/* 2 green */
168 		170, 85,  0, 	/* 3 yellow */
169 		  0,  0,170,	/* 4 blue */
170 		170,  0,170,	/* 5 magenta */
171 		  0,170,170,	/* 6 cyan */
172 		170,170,170,	/* 7 white */
173 		 85, 85, 85,
174 		255, 85, 85,
175 		 85,255, 85,
176 		255,255, 85,
177 		 85, 85,255,
178 		255, 85,255,
179 		 85,255,255,
180 		255,255,255
181 	};
182 	const unsigned char *rgb;
183 	if (!setgfxmode(fullscreen))
184 		exit(1);
185 	clear_bitmap(screen);
186 	if (set_display_switch_callback(SWITCH_IN, got_focus_back) == -1)
187 		set_display_switch_mode(SWITCH_PAUSE);
188 	BITMAP *bmp = create_bitmap(8 * term_width, 400);
189 	clear_bitmap(bmp);
190 	set_clip_state(bmp, 0);
191 	set_clip_state(screen, 0);
192 	int i;
193 	for (i=0; i<16; i++) {
194 		rgb = &vgargb[i][0];
195 		vgacolors[i] = makecol(rgb[0], rgb[1], rgb[2]);
196 	}
197 	return bmp;
198 }
199 
200 #if WIN32 && !ALLEGRO_USE_CONSOLE
printline(char * line)201 static int printline(char *line)
202 {
203 	int n = strlen(line);
204 	int c = 0;
205 	if (line[n-1] == '\n')
206 		line[--n] = '\0';
207 	if (n > 64 && is_windowed_mode()) {
208 		c = line[64];
209 		line[64] = '\0';
210 	}
211 	printstr(line);
212 	if (!c || curs_y == 24)
213 		return 0;
214 	line[64] = c;
215 	curs_y++;
216 	printstr(line + 64);
217 	return 1;
218 }
219 #endif
220 
textgfx_init()221 void textgfx_init()
222 {
223 #ifdef UNIX
224 	strcpy(_xwin.application_name, "vitetris");
225 	strcpy(_xwin.application_class, "Vitetris");
226 #endif
227 	if (install_allegro(SYSTEM_AUTODETECT, &errno, NULL) != 0)
228 		exit(1);
229 #ifdef UNIX
230 	sigaction(SIGINT, NULL, &allegro_sigint_handler);
231 	signal(SIGINT, sigint_handler);
232 #endif
233 	load_pc8x16_font();
234 	set_window_title(VITETRIS_VER);
235 	set_close_button_callback(close_btn);
236 #ifndef UNIX
237 	/* Seems to cause seg fault later quite randomly on Linux  */
238 	int depth = desktop_color_depth();
239 	if (depth != 0)
240 		set_color_depth(depth);
241 #endif
242 	virt_screen = set_screen(getopt_int("", "fullscreen"));
243 	lang |= LATIN1;
244 	if (!font8x16) {
245 		font8x16 = font;
246 		textgfx_flags |= ASCII;
247 	}
248 	setattr_normal();
249 #if WIN32 && !ALLEGRO_USE_CONSOLE
250 	if (exists("stdout.tmp")) {
251 		FILE *fp;
252 		freopen("stdout2.tmp", "w", stdout);
253 		fp = fopen("stdout.tmp", "r");
254 		if (fp) {
255 			char line[80];
256 			int i;
257 			for (i=0; i < 25 && fgets(line, 80, fp); i++) {
258 				setcurs(0, i);
259 				i += printline(line);
260 			}
261 			fclose(fp);
262 			if (i) {
263 				refreshscreen();
264 				if (!strncmp(line, "Press ", 6)) {
265 					install_keyboard();
266 					clear_keybuf();
267 					readkey();
268 					remove_keyboard();
269 				}
270 			}
271 		}
272 		freopen("stdout.tmp", "w", stdout);
273 		delete_file("stdout2.tmp");
274 	}
275 #endif
276 }
277 
textgfx_end()278 void textgfx_end()
279 {
280 	if (!virt_screen)
281 		return;
282 	destroy_bitmap(virt_screen);
283 	virt_screen = NULL;
284 	if (font8x16 != font)
285 		destroy_font(font8x16);
286 	allegro_exit();
287 }
288 
toggle_fullscreen()289 void toggle_fullscreen()
290 {
291 	BITMAP *bmp = set_screen(is_windowed_mode());
292 	if (bmp->w == virt_screen->w)
293 		destroy_bitmap(bmp);
294 	else {
295 		if (bmp->w > virt_screen->w) {
296 			int h = 400;
297 			if (in_menu) {
298 				blit(virt_screen, screen, 0, 384, 0, 464,
299 							  512, 16);
300 				h = 384;
301 			}
302 			blit(virt_screen, bmp, 0, 0, 64, 0, 512, h);
303 			curs_x += 8;
304 		} else {
305 			blit(virt_screen, bmp, 64, 0, 0, 0, 512, 400);
306 			curs_x -= 8;
307 		}
308 		margin_x = getmargin_x();
309 		destroy_bitmap(virt_screen);
310 		virt_screen = bmp;
311 	}
312 	refresh_needed = 1;
313 	refreshscreen();
314 }
315 
setcurs(int x,int y)316 void setcurs(int x, int y)
317 {
318 	x += win_x + margin_x;
319 	y += win_y;
320 	curs_x = x;
321 	curs_y = y;
322 }
323 
movefwd(int n)324 void movefwd(int n)
325 {
326 	curs_x += n;
327 }
328 
newln(int x)329 void newln(int x)
330 {
331 	x += win_x + margin_x;
332 	curs_x = x;
333 	curs_y++;
334 }
335 
setcurs_end()336 void setcurs_end()
337 {
338 	curs_x = 0;
339 	curs_y = 24;
340 }
341 
is_outside_screen(int x,int y)342 int is_outside_screen(int x, int y)
343 {
344 	return x + win_x + margin_x >= term_width ||
345 	       y + win_y >= 25;
346 }
347 
get_xy(int * x,int * y)348 void get_xy(int *x, int *y)
349 {
350 	*x = curs_x - win_x - margin_x;
351 	*y = curs_y - win_y;
352 }
353 
refreshscreen()354 void refreshscreen()
355 {
356 	int y = 0;
357 	if (!refresh_needed)
358 		return;
359 	if (!is_windowed_mode())
360 		y = 40;
361 	acquire_screen();
362 	blit(virt_screen, screen, 0, 0, 0, y, 8*term_width, 400);
363 	release_screen();
364 	refresh_needed = 0;
365 	memset(blit_rect, 0, 4);
366 }
367 
update_blit_rect(char x,char y,char x2)368 static void update_blit_rect(char x, char y, char x2)
369 {
370 	if (x < blit_rect[0] || !blit_rect[0])
371 		blit_rect[0] = x;
372 	if (y < blit_rect[1] || !blit_rect[1])
373 		blit_rect[1] = y;
374 	if (x2 > blit_rect[2])
375 		blit_rect[2] = x2;
376 	if (y > blit_rect[3])
377 		blit_rect[3] = y;
378 }
379 
cleartoeol()380 void cleartoeol()
381 {
382 	int y = 16*curs_y;
383 	int maxx = term_width-1;
384 	rectfill(virt_screen, 8*curs_x, y, 8*maxx, y+15, 0);
385 	refresh_needed = 1;
386 	update_blit_rect(curs_x, curs_y, maxx);
387 }
388 
set_color_pair(int clr)389 void set_color_pair(int clr)
390 {
391 	int bg = 0;
392 	int bold = 1;
393 	if (_MONOCHROME) {
394 		if (clr == MAGENTA_FG)
395 			setattr_bold();
396 		return;
397 	}
398 	if (clr & 64) {
399 		bg = clr & 7;
400 		clr = clr>>3 & 7;
401 	} else
402 		switch (clr) {
403 		case MAGENTA_FG:
404 			clr = 5;
405 			break;
406 		case WHITE_ON_BLUE:
407 			clr = 7;
408 			bg = 4;
409 			break;
410 		case BOARD_BG_COLOR:
411 			clr = 4;
412 			bold = 0;
413 			break;
414 		case BOARD_FRAME_COLOR:
415 			clr = 4;
416 			bold = 0;
417 			break;
418 		case RED_FG:
419 			clr = 1;
420 			break;
421 		case YELLOW_ON_BLUE:
422 			clr = 3;
423 			bg = 4;
424 			break;
425 		case YELLOW_ON_GREEN:
426 			clr = 3;
427 			bg = 2;
428 			break;
429 		default:
430 			if (clr & 16)
431 				clr &= 7;
432 			else
433 				bg = clr;
434 		}
435 	if (textgfx_flags & BLACK_BRACKETS && bg == clr) {
436 		clr = 0;
437 		bold = 0;
438 	}
439 	if (!_TT_BLOCKS)
440 		bg_color = bg;
441 	if (bold)
442 		clr |= 8;
443 	fg_color = clr;
444 }
445 
setattr_normal()446 void setattr_normal()
447 {
448 	bg_color = 0;
449 	fg_color = 7;
450 }
451 
setattr_standout()452 void setattr_standout()
453 {
454 	bg_color = fg_color;
455 	fg_color = 0;
456 }
457 
setattr_bold()458 void setattr_bold()
459 {
460 	if ((textgfx_flags & TT_MONO) != TT_MONO && fg_color < 8)
461 		fg_color |= 8;
462 }
463 
setattr_underline()464 void setattr_underline() {}
465 
to_cp437(int ch)466 static int to_cp437(int ch)
467 {
468 	const char *latin1 = "��������";
469 	const char *cp437 = "\x8F\x8E\x99\x9A\x86\x84\x94\x82";
470 	const char *p;
471 	p = strchr(latin1, ch);
472 	if (p)
473 		return (unsigned char) cp437[p-latin1];
474 	return '?';
475 }
476 
text_out(const char * s,int n)477 static void text_out(const char *s, int n)
478 {
479 	int x = 8 *curs_x;
480 	int y = 16*curs_y;
481 	int bg = vgacolors[bg_color];
482 	int fg = vgacolors[fg_color];
483 
484 	if (*s == '|' && n == 1) {
485 		rectfill(virt_screen, x, y, x+7, y+15, bg);
486 		rectfill(virt_screen, x+3, y, x+4, y+12, fg);
487 	} else {
488 		if (font == font8x16) {
489 			rectfill(virt_screen, x, y, x+(8*n)-1, y+15, bg);
490 			y += 4;
491 		}
492 		textout_ex(virt_screen, font8x16, s, x, y, fg, bg);
493 	}
494 	refresh_needed = 1;
495 	update_blit_rect(curs_x, curs_y, curs_x+n-1);
496 	curs_x += n;
497 }
498 
put_ch(int ch)499 void put_ch(int ch)
500 {
501 	char s[2] = "";
502 	int trans = 0;
503 	if (ch == '\b') {
504 		curs_x--;
505 		return;
506 	}
507 	if (ch < 0)
508 		ch = (unsigned char) ch;
509 	if (ch & 0x80)
510 		ch = to_cp437(ch);
511 	if (ch == TEXTURE2 && textgfx_flags & (TT_BLOCKS | BLACK_BRACKETS))
512 		ch = ' ';
513 	if (ch & 0x100) {
514 		if (_ASCII) {
515 			putch_ascii(ch);
516 			return;
517 		}
518 		ch = (unsigned char) ibmgfx(ch);
519 		if (ch < 32)
520 			trans = 32;
521 	}
522 	if (ch == 0xFA)
523 		trans = -0x80;
524 	else if (ch >= 0x80)
525 		trans = -0x60;
526 	if (trans) {
527 		transpose_font(font8x16, trans);
528 		s[0] = ch + trans;
529 		text_out(s, 1);
530 		transpose_font(font8x16, -trans);
531 	} else {
532 		s[0] = ch;
533 		text_out(s, 1);
534 	}
535 }
536 
printstr(const char * str)537 int printstr(const char *str)
538 {
539 	if (!str[0])
540 		return 0;
541 	while (str[0] && curs_x < term_width) {
542 		putch(str[0]);
543 		str++;
544 	}
545 	return 1;
546 }
547 
printint(const char * fmt,int d)548 void printint(const char *fmt, int d)
549 {
550 	char buf[80];
551 	int n = usprintf(buf, fmt, d);
552 	text_out(buf, n);
553 }
554 
printlong(const char * fmt,long d)555 void printlong(const char *fmt, long d)
556 {
557 	char buf[80];
558 	int n = usprintf(buf, fmt, d);
559 	text_out(buf, n);
560 }
561 
default_bgdot()562 int default_bgdot()
563 {
564 	return BULLET;
565 }
566