1 #include <windows.h>
2 #include <stddef.h>
3 #include <stdio.h>
4 #include <math.h>
5 
6 #include "graphics.h"
7 
8 #define MAX_PAGES 16
9 
10 static HDC hdc[4];
11 
12 static HPEN hPen;
13 static HRGN hRgn;
14 static HFONT hFont;
15 static NPLOGPALETTE pPalette;
16 static PAINTSTRUCT ps;
17 static HWND hWnd;
18 static HBRUSH hBrush[USER_FILL+1];
19 static HBRUSH hBackgroundBrush;
20 
21 static HPALETTE hPalette;
22 static HBITMAP hBitmap[MAX_PAGES];
23 static HBITMAP hPutimageBitmap;
24 
25 static int timeout_expired;
26 
27 #define PEN_CACHE_SIZE   8
28 #define FONT_CACHE_SIZE  8
29 #define BG               16
30 #define TIMER_ID         1
31 
32 //
33 // When XOR or NOT write modes are used for drawing high BG bit is cleared, so
34 // drawing colors should be adjusted to preserve this bit
35 //
36 #define ADJUSTED_MODE(mode) ((mode) == XOR_PUT || (mode) == NOT_PUT)
37 
38 int bgiemu_handle_redraw = TRUE;
39 int bgiemu_default_mode = VGAHI; //VGAMAX;
40 
41 static int screen_width;
42 static int screen_height;
43 static int window_width;
44 static int window_height;
45 
46 static int line_style_cnv[] = {
47     PS_SOLID, PS_DOT, PS_DASHDOT, PS_DASH,
48     PS_DASHDOTDOT /* if user style lines are not supported */
49 };
50 static int write_mode_cnv[] =
51   {R2_COPYPEN, R2_XORPEN, R2_MERGEPEN, R2_MASKPEN, R2_NOTCOPYPEN};
52 static int bitblt_mode_cnv[] =
53   {SRCCOPY, SRCINVERT, SRCPAINT, SRCAND, NOTSRCCOPY};
54 
55 static int font_weight[] =
56 {
57     FW_BOLD,    // DefaultFont
58     FW_NORMAL,  // TriplexFont
59     FW_NORMAL,  // SmallFont
60     FW_NORMAL,  // SansSerifFont
61     FW_NORMAL,  // GothicFont
62     FW_NORMAL,  // ScriptFont
63     FW_NORMAL,  // SimplexFont
64     FW_NORMAL,  // TriplexScriptFont
65     FW_NORMAL,  // ComplexFont
66     FW_NORMAL,  // EuropeanFont
67     FW_BOLD     // BoldFont
68 };
69 
70 static int font_family[] =
71 {
72     FIXED_PITCH|FF_DONTCARE,     // DefaultFont
73     VARIABLE_PITCH|FF_ROMAN,     // TriplexFont
74     VARIABLE_PITCH|FF_MODERN,    // SmallFont
75     VARIABLE_PITCH|FF_DONTCARE,  // SansSerifFont
76     VARIABLE_PITCH|FF_SWISS,     // GothicFont
77     VARIABLE_PITCH|FF_SCRIPT,    // ScriptFont
78     VARIABLE_PITCH|FF_DONTCARE,  // SimplexFont
79     VARIABLE_PITCH|FF_SCRIPT,    // TriplexScriptFont
80     VARIABLE_PITCH|FF_DONTCARE,  // ComplexFont
81     VARIABLE_PITCH|FF_DONTCARE,  // EuropeanFont
82     VARIABLE_PITCH|FF_DONTCARE   // BoldFont
83   };
84 
85 static char* font_name[] =
86 {
87     "Console",          // DefaultFont
88     "Times New Roman",  // TriplexFont
89     "Small Fonts",      // SmallFont
90     "MS Sans Serif",    // SansSerifFont
91     "Arial",            // GothicFont
92     "Script",           // ScriptFont
93     "Times New Roman",  // SimplexFont
94     "Script",           // TriplexScriptFont
95     "Courier New",      // ComplexFont
96     "Times New Roman",  // EuropeanFont
97     "Courier New Bold", // BoldFont
98 };
99 
100 static int text_halign_cnv[] = {TA_LEFT, TA_CENTER, TA_RIGHT};
101 static int text_valign_cnv[] = {TA_BOTTOM, TA_BASELINE, TA_TOP};
102 
103 static palettetype current_palette;
104 
105 static struct { int width; int height; } font_metrics[][11] = {
106 {{0,0},{8,8},{16,16},{24,24},{32,32},{40,40},{48,48},{56,56},{64,64},{72,72},{80,80}}, // DefaultFont
107 {{0,0},{13,18},{14,20},{16,23},{22,31},{29,41},{36,51},{44,62},{55,77},{66,93},{88,124}}, // TriplexFont
108 {{0,0},{3,5},{4,6},{4,6},{6,9},{8,12},{10,15},{12,18},{15,22},{18,27},{24,36}}, // SmallFont
109 {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // SansSerifFont
110 {{0,0},{13,19},{14,21},{16,24},{22,32},{29,42},{36,53},{44,64},{55,80},{66,96},{88,128}}, // GothicFont
111 // I am not sure about metrics of following fonts
112 {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // ScriptFont
113 {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // SimplexFont
114 {{0,0},{13,18},{14,20},{16,23},{22,31},{29,41},{36,51},{44,62},{55,77},{66,93},{88,124}}, // TriplexScriptFont
115 {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // ComplexFont
116 {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // EuropeanFont
117 {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}} // BoldFont
118 };
119 
120 struct BGIimage {
121     short width;
122     short height;
123     int   reserved; // let bits be aligned to DWORD boundary
124     char  bits[1];
125 };
126 
127 struct BGIbitmapinfo {
128     BITMAPINFOHEADER hdr;
129     short            color_table[16];
130 };
131 
132 static BGIbitmapinfo bminfo = {
133     {sizeof(BITMAPINFOHEADER), 0, 0, 1, 4, BI_RGB}
134 };
135 
136 static int* image_bits;
137 
138 static int normal_font_size[] = { 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};
139 
140 static linesettingstype line_settings;
141 static fillsettingstype fill_settings;
142 
143 static int color;
144 static int bkcolor;
145 static int text_color;
146 
147 static int aspect_ratio_x, aspect_ratio_y;
148 
149 static textsettingstype text_settings;
150 
151 static viewporttype view_settings;
152 
153 static int font_mul_x, font_div_x, font_mul_y, font_div_y;
154 
155 static enum { ALIGN_NOT_SET, UPDATE_CP, NOT_UPDATE_CP } text_align_mode;
156 
157 #define BORDER_WIDTH  8
158 #define BORDER_HEIGHT 27
159 
160 static int write_mode;
161 
162 static int visual_page;
163 static int active_page;
164 
165 static arccoordstype ac;
166 
167 class char_queue {
168   protected:
169     char* buf;
170     int   put_pos;
171     int   get_pos;
172     int   buf_size;
173   public:
put(char ch)174     void  put(char ch) {
175 	buf[put_pos] = ch;
176 	if (++put_pos == buf_size) {
177 	    put_pos = 0;
178 	}
179 	if (put_pos == get_pos) { // queue is full
180 	    (void)get(); // loose one character
181 	}
182     }
get()183     char get() {
184 	char ch = buf[get_pos];
185 	if (++get_pos == buf_size) {
186 	    get_pos = 0;
187 	}
188 	return ch;
189     }
is_empty()190     bool is_empty() {
191 	return get_pos == put_pos;
192     }
char_queue(int buf_size=256)193     char_queue(int buf_size = 256) {
194 	put_pos = get_pos = 0;
195 	this->buf_size = buf_size;
196 	buf = new char[buf_size];
197     }
~char_queue()198     ~char_queue() {
199 	delete[] buf;
200     }
201 };
202 
203 static char_queue kbd_queue;
204 
convert_userbits(DWORD buf[32],unsigned pattern)205 inline int convert_userbits(DWORD buf[32], unsigned pattern)
206 {
207     int i = 0, j;
208     pattern &= 0xFFFF;
209 
210     while (true) {
211 	for (j = 0; pattern & 1; j++) pattern >>= 1;
212 	buf[i++] = j;
213 	if (pattern == 0) {
214 	    buf[i++] = 16 - j;
215 	    return i;
216 	}
217 	for (j = 0; !(pattern & 1); j++) pattern >>= 1;
218 	buf[i++] = j;
219     }
220 }
221 
222 
223 class l2elem {
224   public:
225     l2elem* next;
226     l2elem* prev;
227 
link_after(l2elem * after)228     void link_after(l2elem* after) {
229 	(next = after->next)->prev = this;
230 	(prev = after)->next = this;
231     }
unlink()232     void unlink() {
233 	prev->next = next;
234 	next->prev = prev;
235     }
prune()236     void prune() {
237 	next = prev = this;
238     }
239 };
240 
241 class l2list : public l2elem {
242   public:
l2list()243     l2list() { prune(); }
244 };
245 
246 class pen_cache : public l2list {
247     class pen_cache_item : public l2elem {
248       public:
249     	HPEN pen;
250         int  color;
251 	int  width;
252 	int  style;
253 	unsigned pattern;
254     };
255     pen_cache_item* free;
256     pen_cache_item  cache[PEN_CACHE_SIZE];
257 
258   public:
pen_cache()259     pen_cache() {
260 	for (int i = 0; i < PEN_CACHE_SIZE-1; i++) {
261 	    cache[i].next = &cache[i+1];
262 	}
263 	cache[PEN_CACHE_SIZE-1].next = NULL;
264 	free = cache;
265     }
select(int color)266     void select(int color)
267     {
268 	for (l2elem* elem = next; elem != this; elem = elem->next) {
269 	    pen_cache_item* ci = (pen_cache_item*)elem;
270 	    if (ci->color == color &&
271 		ci->style == line_settings.linestyle &&
272 		ci->width == line_settings.thickness &&
273 		(line_settings.linestyle != USERBIT_LINE
274 		 || line_settings.upattern == ci->pattern))
275 	    {
276 		ci->unlink(); // LRU discipline
277 		ci->link_after(this);
278 
279 		if (hPen != ci->pen) {
280 		    hPen = ci->pen;
281 		    SelectObject(hdc[0], hPen);
282 		    SelectObject(hdc[1], hPen);
283 		}
284 		return;
285 	    }
286 	}
287 	hPen = NULL;
288 	if (line_settings.linestyle == USERBIT_LINE) {
289 	    LOGBRUSH lb;
290 	    lb.lbColor = PALETTEINDEX(color);
291 	    lb.lbStyle = BS_SOLID;
292 	    DWORD style[32];
293 	    hPen = ExtCreatePen(PS_GEOMETRIC|PS_USERSTYLE,
294 				line_settings.thickness, &lb,
295 				convert_userbits(style,line_settings.upattern),
296 				style);
297 	}
298 	if (hPen == NULL) {
299 	    hPen = CreatePen(line_style_cnv[line_settings.linestyle],
300 			     line_settings.thickness,
301 			     PALETTEINDEX(color));
302 	}
303 	SelectObject(hdc[0], hPen);
304 	SelectObject(hdc[1], hPen);
305 
306 	pen_cache_item* p;
307 	if (free == NULL) {
308 	    p = (pen_cache_item*)prev;
309 	    p->unlink();
310 	    DeleteObject(p->pen);
311 	} else {
312 	    p = free;
313 	    free = (pen_cache_item*)p->next;
314 	}
315 	p->pen   = hPen;
316 	p->color = color;
317 	p->width = line_settings.thickness;
318 	p->style = line_settings.linestyle;
319 	p->pattern = line_settings.upattern;
320 	p->link_after(this);
321     }
322 };
323 
324 
325 static pen_cache pcache;
326 
327 
328 
329 class font_cache : public l2list {
330     class font_cache_item : public l2elem {
331       public:
332     	HFONT font;
333         int   type;
334 	int   direction;
335 	int   width, height;
336     };
337     font_cache_item* free;
338     font_cache_item  cache[FONT_CACHE_SIZE];
339 
340   public:
font_cache()341     font_cache() {
342 	for (int i = 0; i < FONT_CACHE_SIZE-1; i++) {
343 	    cache[i].next = &cache[i+1];
344 	}
345 	cache[FONT_CACHE_SIZE-1].next = NULL;
346 	free = cache;
347     }
select(int type,int direction,int width,int height)348     void select(int type, int direction, int width, int height)
349     {
350 	for (l2elem* elem = next; elem != this; elem = elem->next) {
351 	    font_cache_item* ci = (font_cache_item*)elem;
352 	    if (ci->type == type &&
353 		ci->direction == direction &&
354 		ci->width == width &&
355 		ci->height == height)
356 	    {
357 		ci->unlink();
358 		ci->link_after(this);
359 
360 		if (hFont != ci->font) {
361 		    hFont = ci->font;
362 		    SelectObject(hdc[0], hFont);
363 		    SelectObject(hdc[1], hFont);
364 		}
365 		return;
366 	    }
367 	}
368 	hFont = CreateFont(-height,
369 			   width,
370 			   direction*900,
371 			   (direction&1)*900,
372 			   font_weight[type],
373 			   FALSE,
374 			   FALSE,
375 			   FALSE,
376 			   DEFAULT_CHARSET,
377 			   OUT_DEFAULT_PRECIS,
378 			   CLIP_DEFAULT_PRECIS,
379 			   DEFAULT_QUALITY,
380 			   font_family[type],
381 			   font_name[type]);
382 	SelectObject(hdc[0], hFont);
383 	SelectObject(hdc[1], hFont);
384 
385 	font_cache_item* p;
386 	if (free == NULL) {
387 	    p = (font_cache_item*)prev;
388 	    p->unlink();
389 	    DeleteObject(p->font);
390 	} else {
391 	    p = free;
392 	    free = (font_cache_item*)p->next;
393 	}
394 	p->font = hFont;
395 	p->type = type;
396 	p->width = width;
397 	p->height = height;
398 	p->direction = direction;
399 	p->link_after(this);
400     }
401 };
402 
403 
404 static font_cache fcache;
405 
406 
407 #define FLAGS         PC_NOCOLLAPSE
408 #define PALETTE_SIZE  256
409 
410 static PALETTEENTRY BGIcolor[16] = {
411 { 0, 0, 0, FLAGS },
412 { 0, 0, 255, FLAGS },
413 { 0, 255, 0, FLAGS },
414 { 0, 255, 255, FLAGS },
415 { 255, 0, 0, FLAGS },
416 { 255, 0, 255, FLAGS },
417 { 165, 42, 42, FLAGS },
418 { 211, 211, 211, FLAGS },
419 { 47, 79, 79, FLAGS },
420 { 173, 216, 230, FLAGS },
421 { 32, 178, 170, FLAGS },
422 { 224, 255, 255, FLAGS },
423 { 240, 128, 128, FLAGS },
424 { 219, 112, 147, FLAGS },
425 { 255, 255, 0, FLAGS },
426 { 255, 255, 255, FLAGS }
427 };
428 
429 static PALETTEENTRY BGIpalette[16];
430 
431 static short SolidBrushBitmap[8] =
432   {~0xFF, ~0xFF, ~0xFF, ~0xFF, ~0xFF, ~0xFF, ~0xFF, ~0xFF};
433 static short LineBrushBitmap[8] =
434   {~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0xFF};
435 static short LtslashBrushBitmap[8] =
436   {~0x01, ~0x02, ~0x04, ~0x08, ~0x10, ~0x20, ~0x40, ~0x80};
437 static short SlashBrushBitmap[8] =
438   {~0x81, ~0x03, ~0x06, ~0x0C, ~0x18, ~0x30, ~0x60, ~0xC0};
439 static short BkslashBrushBitmap[8] =
440   {~0xC0, ~0x60, ~0x30, ~0x18, ~0x0C, ~0x06, ~0x03, ~0x81};
441 static short LtbkslashBrushBitmap[8] =
442   {~0x80, ~0x40, ~0x20, ~0x10, ~0x08, ~0x04, ~0x02, ~0x01};
443 static short HatchBrushBitmap[8] =
444   {~0x01, ~0x01, ~0x01, ~0x01, ~0x01, ~0x01, ~0x01, ~0xFF};
445 static short XhatchBrushBitmap[8] =
446   {~0x81, ~0x42, ~0x24, ~0x18, ~0x18, ~0x24, ~0x42, ~0x81};
447 static short InterleaveBrushBitmap[8] =
448   {~0x55, ~0xAA, ~0x55, ~0xAA, ~0x55, ~0xAA, ~0x55, ~0xAA};
449 static short WidedotBrushBitmap[8] =
450   {~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0x01};
451 static short ClosedotBrushBitmap[8] =
452   {~0x44, ~0x00, ~0x11, ~0x00, ~0x44, ~0x00, ~0x11, ~0x00};
453 
grapherrormsg(int code)454 char* grapherrormsg(int code) {
455     static char buf[256];
456     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
457     	          NULL, code, 0,
458     	          buf, sizeof buf, NULL);
459     return buf;
460 }
461 
462 static int gdi_error_code;
463 
graphresult()464 int graphresult()
465 {
466     return gdi_error_code;
467 }
468 
setcolor(int c)469 void setcolor(int c)
470 {
471     c &= MAXCOLORS;
472     color = c;
473     SetTextColor(hdc[0], PALETTEINDEX(c+BG));
474     SetTextColor(hdc[1], PALETTEINDEX(c+BG));
475 }
476 
getmaxcolor()477 int getmaxcolor()
478 {
479     return WHITE;
480 }
481 
getmaxmode()482 int getmaxmode()
483 {
484     return VGAMAX;
485 }
486 
getmodename(int mode)487 char* getmodename(int mode)
488 {
489     static char mode_str[32];
490     sprintf(mode_str, "%d x %d %s", window_width, window_height,
491 	    mode < 2 ? "EGA" : "VGA");
492     return mode_str;
493 }
494 
getx()495 int getx()
496 {
497     POINT pos;
498     GetCurrentPositionEx(hdc[active_page == visual_page ? 0 : 1], &pos);
499     return pos.x;
500 }
501 
gety()502 int gety()
503 {
504     POINT pos;
505     GetCurrentPositionEx(hdc[active_page == visual_page ? 0 : 1], &pos);
506     return pos.y;
507 }
508 
getmaxx()509 int getmaxx()
510 {
511     return window_width-1;
512 }
513 
getmaxy()514 int getmaxy()
515 {
516     return window_height-1;
517 }
518 
519 
getcolor()520 int getcolor()
521 {
522     return color;
523 }
524 
getdrivername()525 char* getdrivername()
526 {
527     return "EGAVGA";
528 }
529 
setlinestyle(int style,unsigned int pattern,int thickness)530 void setlinestyle(int style, unsigned int pattern, int thickness)
531 {
532     line_settings.linestyle = style;
533     line_settings.thickness = thickness;
534     line_settings.upattern  = pattern;
535 }
536 
getlinesettings(linesettingstype * ls)537 void getlinesettings(linesettingstype* ls)
538 {
539     *ls = line_settings;
540 }
541 
setwritemode(int mode)542 void setwritemode(int mode)
543 {
544     write_mode = mode;
545 }
546 
setpalette(int index,int color)547 void setpalette(int index, int color)
548 {
549     color &= MAXCOLORS;
550     BGIpalette[index] = BGIcolor[color];
551     current_palette.colors[index] = color;
552     SetPaletteEntries(hPalette, BG+index, 1, &BGIpalette[index]);
553     RealizePalette(hdc[0]);
554     if (index == 0) {
555 	bkcolor = 0;
556     }
557 }
558 
setrgbpalette(int index,int red,int green,int blue)559 void setrgbpalette(int index, int red, int green, int blue)
560 {
561     BGIpalette[index].peRed = red & 0xFC;
562     BGIpalette[index].peGreen = green & 0xFC;
563     BGIpalette[index].peBlue = blue & 0xFC;
564     SetPaletteEntries(hPalette, BG+index, 1, &BGIpalette[index]);
565     RealizePalette(hdc[0]);
566     if (index == 0) {
567 	bkcolor = 0;
568     }
569 }
570 
setallpalette(palettetype * pal)571 void setallpalette(palettetype* pal)
572 {
573     for (int i = 0; i < pal->size; i++) {
574 	current_palette.colors[i] = pal->colors[i] & MAXCOLORS;
575 	BGIpalette[i] = BGIcolor[pal->colors[i] & MAXCOLORS];
576     }
577     SetPaletteEntries(hPalette, BG, pal->size, BGIpalette);
578     RealizePalette(hdc[0]);
579     bkcolor = 0;
580 }
581 
getdefaultpalette()582 palettetype* getdefaultpalette()
583 {
584     static palettetype default_palette = { 16,
585       { BLACK, BLUE, GREEN, CYAN, RED, MAGENT, BROWN, LIGHTGRAY, DARKGRAY,
586         LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE
587       }};
588     return &default_palette;
589 }
590 
getpalette(palettetype * pal)591 void getpalette(palettetype* pal)
592 {
593     *pal = current_palette;
594 }
595 
getpalettesize()596 int getpalettesize()
597 {
598     return MAXCOLORS+1;
599 }
600 
setbkcolor(int color)601 void setbkcolor(int color)
602 {
603     color &= MAXCOLORS;
604     BGIpalette[0] = BGIcolor[color];
605     SetPaletteEntries(hPalette, BG, 1, &BGIpalette[0]);
606     RealizePalette(hdc[0]);
607     bkcolor = color;
608 }
609 
getbkcolor()610 int getbkcolor()
611 {
612     return bkcolor;
613 }
614 
setfillstyle(int style,int color)615 void setfillstyle(int style, int color)
616 {
617     fill_settings.pattern = style;
618     fill_settings.color = color & MAXCOLORS;
619     SelectObject(hdc[0], hBrush[style]);
620     SelectObject(hdc[1], hBrush[style]);
621 }
622 
getfillsettings(fillsettingstype * fs)623 void getfillsettings(fillsettingstype* fs)
624 {
625     *fs = fill_settings;
626 }
627 
628 static fillpatterntype userfillpattern =
629 {-1, -1, -1, -1, -1, -1, -1, -1};
630 
setfillpattern(char const * upattern,int color)631 void setfillpattern(char const* upattern, int color)
632 {
633     static HBITMAP hFillBitmap;
634     static short bitmap_data[8];
635     for (int i = 0; i < 8; i++) {
636 	bitmap_data[i] = (unsigned char)~upattern[i];
637 	userfillpattern[i] = upattern[i];
638     }
639     HBITMAP h = CreateBitmap(8, 8, 1, 1, bitmap_data);
640     HBRUSH hb = CreatePatternBrush(h);
641     DeleteObject(hBrush[USER_FILL]);
642     if (hFillBitmap) {
643 	DeleteObject(hFillBitmap);
644     }
645     hFillBitmap = h;
646     hBrush[USER_FILL] = hb;
647     SelectObject(hdc[0], hb);
648     SelectObject(hdc[1], hb);
649     fill_settings.color = color & MAXCOLORS;
650     fill_settings.pattern = USER_FILL;
651 }
652 
getfillpattern(fillpatterntype fp)653 void getfillpattern(fillpatterntype fp)
654 {
655     memcpy(fp, userfillpattern, sizeof userfillpattern);
656 }
657 
658 
select_fill_color()659 inline void select_fill_color()
660 {
661     if (text_color != fill_settings.color) {
662 	text_color = fill_settings.color;
663 	SetTextColor(hdc[0], PALETTEINDEX(text_color+BG));
664 	SetTextColor(hdc[1], PALETTEINDEX(text_color+BG));
665     }
666 }
667 
setusercharsize(int multx,int divx,int multy,int divy)668 void setusercharsize(int multx, int divx, int multy, int divy)
669 {
670     font_mul_x = multx;
671     font_div_x = divx;
672     font_mul_y = multy;
673     font_div_y = divy;
674     text_settings.charsize = 0;
675 }
676 
moveto(int x,int y)677 void moveto(int x, int y)
678 {
679     if (bgiemu_handle_redraw || visual_page != active_page) {
680 	MoveToEx(hdc[1], x, y, NULL);
681     }
682     if (visual_page == active_page) {
683 	MoveToEx(hdc[0], x, y, NULL);
684     }
685 }
686 
moverel(int dx,int dy)687 void moverel(int dx, int dy)
688 {
689     POINT pos;
690     GetCurrentPositionEx(hdc[1], &pos);
691     moveto(pos.x + dx, pos.y + dy);
692 }
693 
select_font()694 static void select_font()
695 {
696     if (text_settings.charsize == 0) {
697 	fcache.select(text_settings.font, text_settings.direction,
698 		      font_metrics[text_settings.font]
699 		                  [normal_font_size[text_settings.font]].width
700 		                  *font_mul_x/font_div_x,
701 		      font_metrics[text_settings.font]
702 		                  [normal_font_size[text_settings.font]].height
703 		                  *font_mul_y/font_div_y);
704     } else {
705 	fcache.select(text_settings.font, text_settings.direction,
706 	    font_metrics[text_settings.font][text_settings.charsize].width,
707 	    font_metrics[text_settings.font][text_settings.charsize].height);
708     }
709 }
710 
text_output(int x,int y,const char * str)711 static void text_output(int x, int y, const char* str)
712 {
713     select_font();
714     if (text_color != color) {
715 	text_color = color;
716 	SetTextColor(hdc[0], PALETTEINDEX(text_color+BG));
717 	SetTextColor(hdc[1], PALETTEINDEX(text_color+BG));
718     }
719     if (bgiemu_handle_redraw || visual_page != active_page) {
720         TextOut(hdc[1], x, y, str, strlen(str));
721     }
722     if (visual_page == active_page) {
723         TextOut(hdc[0], x, y, str, strlen(str));
724     }
725 }
726 
727 
settextstyle(int font,int direction,int char_size)728 void settextstyle(int font, int direction, int char_size)
729 {
730     if (char_size > 10) {
731 	char_size = 10;
732     }
733     text_settings.direction = direction;
734     text_settings.font = font;
735     text_settings.charsize = char_size;
736     text_align_mode = ALIGN_NOT_SET;
737 }
738 
settextjustify(int horiz,int vert)739 void settextjustify(int horiz, int vert)
740 {
741     text_settings.horiz = horiz;
742     text_settings.vert = vert;
743     text_align_mode = ALIGN_NOT_SET;
744 }
745 
gettextsettings(textsettingstype * ts)746 void gettextsettings(textsettingstype* ts)
747 {
748     *ts = text_settings;
749 }
750 
751 
textheight(const char * str)752 int textheight(const char* str)
753 {
754     SIZE ss;
755     select_font();
756     GetTextExtentPoint32(hdc[0], str, strlen(str), &ss);
757     return ss.cy;
758 }
759 
textwidth(const char * str)760 int textwidth(const char* str)
761 {
762     SIZE ss;
763     select_font();
764     GetTextExtentPoint32(hdc[0], str, strlen(str), &ss);
765     return ss.cx;
766 }
767 
outtext(const char * str)768 void outtext(const char* str)
769 {
770     if (text_align_mode != UPDATE_CP) {
771 	text_align_mode = UPDATE_CP;
772 	int align = (text_settings.direction == HORIZ_DIR)
773 	            ? (TA_UPDATECP |
774 		       text_halign_cnv[text_settings.horiz] |
775 		       text_valign_cnv[text_settings.vert])
776 	            : (TA_UPDATECP |
777 		       text_valign_cnv[text_settings.horiz] |
778 		       text_halign_cnv[text_settings.vert]);
779 	SetTextAlign(hdc[0], align);
780 	SetTextAlign(hdc[1], align);
781     }
782     text_output(0, 0, str);
783 }
784 
outtextxy(int x,int y,const char * str)785 void outtextxy(int x, int y, const char* str)
786 {
787     if (text_align_mode != NOT_UPDATE_CP) {
788 	text_align_mode = NOT_UPDATE_CP;
789 	int align = (text_settings.direction == HORIZ_DIR)
790 	            ? (TA_NOUPDATECP |
791 		       text_halign_cnv[text_settings.horiz] |
792 		       text_valign_cnv[text_settings.vert])
793 	            : (TA_NOUPDATECP |
794 		       text_valign_cnv[text_settings.horiz] |
795 		       text_halign_cnv[text_settings.vert]);
796 	SetTextAlign(hdc[0], align);
797 	SetTextAlign(hdc[1], align);
798     }
799     text_output(x, y, str);
800 }
801 
setviewport(int x1,int y1,int x2,int y2,int clip)802 void setviewport(int x1, int y1, int x2, int y2, int clip)
803 {
804     view_settings.left = x1;
805     view_settings.top = y1;
806     view_settings.right = x2;
807     view_settings.bottom = y2;
808     view_settings.clip = clip;
809 
810     if (hRgn) {
811 	DeleteObject(hRgn);
812     }
813     hRgn = clip ? CreateRectRgn(x1, y1, x2, y2) : NULL;
814     SelectClipRgn(hdc[1], hRgn);
815     SetViewportOrgEx(hdc[1], x1, y1, NULL);
816 
817     SelectClipRgn(hdc[0], hRgn);
818     SetViewportOrgEx(hdc[0], x1, y1, NULL);
819 
820     moveto(0,0);
821 }
822 
getviewsettings(viewporttype * viewport)823 void getviewsettings(viewporttype *viewport)
824 {
825      *viewport = view_settings;
826 }
827 
828 const double pi = 3.14159265358979323846;
829 
arc_coords(double angle,double rx,double ry,int & x,int & y)830 inline void arc_coords(double angle, double rx, double ry, int& x, int& y)
831 {
832     if (rx == 0 || ry == 0) {
833 	x = y = 0;
834 	return;
835     }
836     double s = sin(angle*pi/180.0);
837     double c = cos(angle*pi/180.0);
838     if (fabs(s) < fabs(c)) {
839 	double tg = s/c;
840 	double xr = sqrt((double)rx*rx*ry*ry/(ry*ry+rx*rx*tg*tg));
841 	x = int((c >= 0) ? xr : -xr);
842 	y = int((s >= 0) ? -xr*tg : xr*tg);
843     } else {
844 	double ctg = c/s;
845 	double yr = sqrt((double)rx*rx*ry*ry/(rx*rx+ry*ry*ctg*ctg));
846         x = int((c >= 0) ? yr*ctg : -yr*ctg);
847 	y = int((s >= 0) ? -yr : yr);
848     }
849 }
850 
ellipse(int x,int y,int start_angle,int end_angle,int rx,int ry)851 void ellipse(int x, int y, int start_angle, int end_angle,
852 		       int rx, int ry)
853 {
854     ac.x = x;
855     ac.y = y;
856     arc_coords(start_angle, rx, ry, ac.xstart, ac.ystart);
857     arc_coords(end_angle,  rx, ry, ac.xend, ac.yend);
858     ac.xstart += x; ac.ystart += y;
859     ac.xend += x; ac.yend += y;
860 
861     pcache.select(color+BG);
862     if (bgiemu_handle_redraw || visual_page != active_page) {
863         Arc(hdc[1], x-rx, y-ry, x+rx, y+ry,
864 	    ac.xstart, ac.ystart, ac.xend, ac.yend);
865     }
866     if (visual_page == active_page) {
867 	Arc(hdc[0], x-rx, y-ry, x+rx, y+ry,
868 	    ac.xstart, ac.ystart, ac.xend, ac.yend);
869     }
870 }
871 
fillellipse(int x,int y,int rx,int ry)872 void fillellipse(int x, int y, int rx, int ry)
873 {
874     pcache.select(color+BG);
875     select_fill_color();
876     if (bgiemu_handle_redraw || visual_page != active_page) {
877 	Ellipse(hdc[1], x-rx, y-ry, x+rx, y+ry);
878     }
879     if (visual_page == active_page) {
880 	Ellipse(hdc[0], x-rx, y-ry, x+rx, y+ry);
881     }
882 }
883 
allocate_new_graphic_page(int page)884 static void allocate_new_graphic_page(int page)
885 {
886     RECT scr;
887     scr.left = -view_settings.left;
888     scr.top = -view_settings.top;
889     scr.right = screen_width-view_settings.left-1;
890     scr.bottom = screen_height-view_settings.top-1;
891     hBitmap[page] = CreateCompatibleBitmap(hdc[0],screen_width,screen_height);
892     SelectObject(hdc[1], hBitmap[page]);
893     SelectClipRgn(hdc[1], NULL);
894     FillRect(hdc[1], &scr, hBackgroundBrush);
895     SelectClipRgn(hdc[1], hRgn);
896 }
897 
setactivepage(int page)898 void setactivepage(int page)
899 {
900     if (hBitmap[page] == NULL) {
901 	allocate_new_graphic_page(page);
902     } else {
903 	SelectObject(hdc[1], hBitmap[page]);
904     }
905     if (!bgiemu_handle_redraw && active_page == visual_page) {
906 	POINT pos;
907 	GetCurrentPositionEx(hdc[0], &pos);
908 	MoveToEx(hdc[1], pos.x, pos.y, NULL);
909     }
910     active_page = page;
911 }
912 
913 
setvisualpage(int page)914 void setvisualpage(int page)
915 {
916     POINT pos;
917     if (hdc[page] == NULL) {
918 	allocate_new_graphic_page(page);
919     }
920     if (!bgiemu_handle_redraw && active_page == visual_page) {
921 	SelectObject(hdc[1], hBitmap[visual_page]);
922 	SelectClipRgn(hdc[1], NULL);
923         BitBlt(hdc[1], -view_settings.left, -view_settings.top,
924 	       window_width, window_height,
925 	       hdc[0], -view_settings.left, -view_settings.top,
926 	       SRCCOPY);
927 	SelectClipRgn(hdc[1], hRgn);
928 	GetCurrentPositionEx(hdc[0], &pos);
929 	MoveToEx(hdc[1], pos.x, pos.y, NULL);
930     }
931     SelectClipRgn(hdc[0], NULL);
932     SelectClipRgn(hdc[1], NULL);
933     SelectObject(hdc[1], hBitmap[page]);
934     BitBlt(hdc[0], -view_settings.left,
935 	   -view_settings.top, window_width, window_height,
936 	   hdc[1], -view_settings.left, -view_settings.top, SRCCOPY);
937     SelectClipRgn(hdc[0], hRgn);
938     SelectClipRgn(hdc[1], hRgn);
939 
940     if (page != active_page) {
941 	SelectObject(hdc[1], hBitmap[active_page]);
942     }
943     if (active_page != visual_page) {
944 	GetCurrentPositionEx(hdc[1], &pos);
945 	MoveToEx(hdc[0], pos.x, pos.y, NULL);
946     }
947     visual_page = page;
948 }
949 
950 
setaspectratio(int ax,int ay)951 void setaspectratio(int ax, int ay)
952 {
953     aspect_ratio_x = ax;
954     aspect_ratio_y = ay;
955 }
956 
getaspectratio(int * ax,int * ay)957 void getaspectratio(int* ax, int* ay)
958 {
959     *ax = aspect_ratio_x;
960     *ay = aspect_ratio_y;
961 }
962 
circle(int x,int y,int radius)963 void circle(int x, int y, int radius)
964 {
965     pcache.select(color+BG);
966     int ry = (unsigned)radius*aspect_ratio_x/aspect_ratio_y;
967     int rx = radius;
968     if (bgiemu_handle_redraw || visual_page != active_page) {
969 	Arc(hdc[1], x-rx, y-ry, x+rx, y+ry, x+rx, y, x+rx, y);
970     }
971     if (visual_page == active_page) {
972         Arc(hdc[0], x-rx, y-ry, x+rx, y+ry, x+rx, y, x+rx, y);
973     }
974 }
975 
arc(int x,int y,int start_angle,int end_angle,int radius)976 void arc(int x, int y, int start_angle, int end_angle, int radius)
977 {
978     ac.x = x;
979     ac.y = y;
980     ac.xstart = x + int(radius*cos(start_angle*pi/180.0));
981     ac.ystart = y - int(radius*sin(start_angle*pi/180.0));
982     ac.xend = x + int(radius*cos(end_angle*pi/180.0));
983     ac.yend = y - int(radius*sin(end_angle*pi/180.0));
984 
985     if (bgiemu_handle_redraw || visual_page != active_page) {
986         Arc(hdc[1], x-radius, y-radius, x+radius, y+radius,
987 	ac.xstart, ac.ystart, ac.xend, ac.yend);
988     }
989     if (visual_page == active_page) {
990 	Arc(hdc[0], x-radius, y-radius, x+radius, y+radius,
991 	    ac.xstart, ac.ystart, ac.xend, ac.yend);
992     }
993 }
994 
getarccoords(arccoordstype * arccoords)995 void getarccoords(arccoordstype *arccoords)
996 {
997     *arccoords = ac;
998 }
999 
pieslice(int x,int y,int start_angle,int end_angle,int radius)1000 void pieslice(int x, int y, int start_angle, int end_angle,
1001 	      int radius)
1002 {
1003     pcache.select(color+BG);
1004     select_fill_color();
1005     ac.x = x;
1006     ac.y = y;
1007     ac.xstart = x + int(radius*cos(start_angle*pi/180.0));
1008     ac.ystart = y - int(radius*sin(start_angle*pi/180.0));
1009     ac.xend = x + int(radius*cos(end_angle*pi/180.0));
1010     ac.yend = y - int(radius*sin(end_angle*pi/180.0));
1011 
1012     if (bgiemu_handle_redraw || visual_page != active_page) {
1013 	Pie(hdc[1], x-radius, y-radius, x+radius, y+radius,
1014 	    ac.xstart, ac.ystart, ac.xend, ac.yend);
1015     }
1016     if (visual_page == active_page) {
1017 	Pie(hdc[0], x-radius, y-radius, x+radius, y+radius,
1018     	    ac.xstart, ac.ystart, ac.xend, ac.yend);
1019     }
1020 }
1021 
1022 
sector(int x,int y,int start_angle,int end_angle,int rx,int ry)1023 void sector(int x, int y, int start_angle, int end_angle,
1024 		      int rx, int ry)
1025 {
1026     ac.x = x;
1027     ac.y = y;
1028     arc_coords(start_angle, rx, ry, ac.xstart, ac.ystart);
1029     arc_coords(end_angle, rx, ry, ac.xend, ac.yend);
1030     ac.xstart += x; ac.ystart += y;
1031     ac.xend += x; ac.yend += y;
1032 
1033     pcache.select(color+BG);
1034     if (bgiemu_handle_redraw || visual_page != active_page) {
1035         Pie(hdc[1], x-rx, y-ry, x+rx, y+ry,
1036 	    ac.xstart, ac.ystart, ac.xend, ac.yend);
1037     }
1038     if (visual_page == active_page) {
1039 	Pie(hdc[0], x-rx, y-ry, x+rx, y+ry,
1040     	    ac.xstart, ac.ystart, ac.xend, ac.yend);
1041     }
1042 }
1043 
bar(int left,int top,int right,int bottom)1044 void bar(int left, int top, int right, int bottom)
1045 {
1046     RECT r;
1047     if (left > right) {	/* Turbo C corrects for badly ordered corners */
1048 	r.left = right;
1049 	r.right = left;
1050     } else {
1051 	r.left = left;
1052 	r.right = right;
1053     }
1054     if (bottom < top) {	/* Turbo C corrects for badly ordered corners */
1055 	r.top = bottom;
1056 	r.bottom = top;
1057     } else {
1058 	r.top = top;
1059 	r.bottom = bottom;
1060     }
1061     select_fill_color();
1062     if (bgiemu_handle_redraw || visual_page != active_page) {
1063 	FillRect(hdc[1], &r, hBrush[fill_settings.pattern]);
1064     }
1065     if (visual_page == active_page) {
1066 	FillRect(hdc[0], &r, hBrush[fill_settings.pattern]);
1067     }
1068 }
1069 
1070 
bar3d(int left,int top,int right,int bottom,int depth,int topflag)1071 void bar3d(int left, int top, int right, int bottom, int depth, int topflag)
1072 {
1073     int temp;
1074     const double tan30 = 1.0/1.73205080756887729352;
1075     if (left > right) {     /* Turbo C corrects for badly ordered corners */
1076 	temp = left;
1077 	left = right;
1078 	right = temp;
1079     }
1080     if (bottom < top) {
1081 	temp = bottom;
1082 	bottom = top;
1083 	top = temp;
1084     }
1085     bar(left+line_settings.thickness, top+line_settings.thickness,
1086 	right-line_settings.thickness+1, bottom-line_settings.thickness+1);
1087 
1088     if (write_mode != COPY_PUT) {
1089 	SetROP2(hdc[0], write_mode_cnv[write_mode]);
1090 	SetROP2(hdc[1], write_mode_cnv[write_mode]);
1091     }
1092     pcache.select(ADJUSTED_MODE(write_mode) ? color : color + BG);
1093     int dy = int(depth*tan30);
1094     POINT p[11];
1095     p[0].x = right, p[0].y = bottom;
1096     p[1].x = right, p[1].y = top;
1097     p[2].x = left,  p[2].y = top;
1098     p[3].x = left,  p[3].y = bottom;
1099     p[4].x = right, p[4].y = bottom;
1100     p[5].x = right+depth, p[5].y = bottom-dy;
1101     p[6].x = right+depth, p[6].y = top-dy;
1102     p[7].x = right, p[7].y = top;
1103 
1104     if (topflag) {
1105 	p[8].x = right+depth, p[8].y = top-dy;
1106 	p[9].x = left+depth, p[9].y = top-dy;
1107 	p[10].x = left, p[10].y = top;
1108     }
1109     if (bgiemu_handle_redraw || visual_page != active_page) {
1110 	Polyline(hdc[1], p, topflag ? 11 : 8);
1111     }
1112     if (visual_page == active_page) {
1113 	Polyline(hdc[0], p, topflag ? 11 : 8);
1114     }
1115     if (write_mode != COPY_PUT) {
1116 	SetROP2(hdc[0], R2_COPYPEN);
1117 	SetROP2(hdc[1], R2_COPYPEN);
1118     }
1119 }
1120 
lineto(int x,int y)1121 void lineto(int x, int y)
1122 {
1123     if (write_mode != COPY_PUT) {
1124 	SetROP2(hdc[0], write_mode_cnv[write_mode]);
1125 	SetROP2(hdc[1], write_mode_cnv[write_mode]);
1126     }
1127     pcache.select(ADJUSTED_MODE(write_mode) ? color : color + BG);
1128     if (bgiemu_handle_redraw || visual_page != active_page) {
1129 	LineTo(hdc[1], x, y);
1130     }
1131     if (visual_page == active_page) {
1132 	LineTo(hdc[0], x, y);
1133     }
1134     if (write_mode != COPY_PUT) {
1135 	SetROP2(hdc[0], R2_COPYPEN);
1136 	SetROP2(hdc[1], R2_COPYPEN);
1137     }
1138 }
1139 
linerel(int dx,int dy)1140 void linerel(int dx, int dy)
1141 {
1142     POINT pos;
1143     GetCurrentPositionEx(hdc[1], &pos);
1144     lineto(pos.x + dx, pos.y + dy);
1145 }
1146 
drawpoly(int n_points,int * points)1147 void drawpoly(int n_points, int* points)
1148 {
1149     if (write_mode != COPY_PUT) {
1150 	SetROP2(hdc[0], write_mode_cnv[write_mode]);
1151 	SetROP2(hdc[1], write_mode_cnv[write_mode]);
1152     }
1153     pcache.select(ADJUSTED_MODE(write_mode) ? color : color + BG);
1154 
1155     if (bgiemu_handle_redraw || visual_page != active_page) {
1156 	Polyline(hdc[1], (POINT*)points, n_points);
1157     }
1158     if (visual_page == active_page) {
1159 	Polyline(hdc[0], (POINT*)points, n_points);
1160     }
1161 
1162     if (write_mode != COPY_PUT) {
1163 	SetROP2(hdc[0], R2_COPYPEN);
1164 	SetROP2(hdc[1], R2_COPYPEN);
1165     }
1166 }
1167 
line(int x0,int y0,int x1,int y1)1168 void line(int x0, int y0, int x1, int y1)
1169 {
1170     POINT line[2];
1171     line[0].x = x0;
1172     line[0].y = y0;
1173     line[1].x = x1;
1174     line[1].y = y1;
1175     drawpoly(2, (int*)&line);
1176 }
1177 
rectangle(int left,int top,int right,int bottom)1178 void rectangle(int left, int top, int right, int bottom)
1179 {
1180     POINT rect[5];
1181     rect[0].x = left, rect[0].y = top;
1182     rect[1].x = right, rect[1].y = top;
1183     rect[2].x = right, rect[2].y = bottom;
1184     rect[3].x = left, rect[3].y = bottom;
1185     rect[4].x = left, rect[4].y = top;
1186     drawpoly(5, (int*)&rect);
1187 }
1188 
fillpoly(int n_points,int * points)1189 void fillpoly(int n_points, int* points)
1190 {
1191     pcache.select(color+BG);
1192     select_fill_color();
1193     if (bgiemu_handle_redraw || visual_page != active_page) {
1194         Polygon(hdc[1], (POINT*)points, n_points);
1195     }
1196     if (visual_page == active_page) {
1197 	Polygon(hdc[0], (POINT*)points, n_points);
1198     }
1199 }
1200 
floodfill(int x,int y,int border)1201 void floodfill(int x, int y, int border)
1202 {
1203     select_fill_color();
1204     if (bgiemu_handle_redraw || visual_page != active_page) {
1205 	FloodFill(hdc[1], x, y, PALETTEINDEX(border+BG));
1206     }
1207     if (visual_page == active_page) {
1208 	FloodFill(hdc[0], x, y, PALETTEINDEX(border+BG));
1209     }
1210 }
1211 
1212 
1213 
handle_input(bool wait=0)1214 static bool handle_input(bool wait = 0)
1215 {
1216     MSG lpMsg;
1217     if (wait ? GetMessage(&lpMsg, NULL, 0, 0)
1218 	     : PeekMessage(&lpMsg, NULL, 0, 0, PM_REMOVE))
1219     {
1220 	TranslateMessage(&lpMsg);
1221 	DispatchMessage(&lpMsg);
1222 	return true;
1223     }
1224     return false;
1225 }
1226 
1227 
delay(unsigned msec)1228 void delay(unsigned msec)
1229 {
1230     timeout_expired = false;
1231     SetTimer(hWnd, TIMER_ID, msec, NULL);
1232     while (!timeout_expired) handle_input(true);
1233 }
1234 
1235 
kbhit()1236 int kbhit()
1237 {
1238     while (handle_input(false));
1239     return !kbd_queue.is_empty();
1240 }
1241 
getch()1242 int getch()
1243 {
1244     while (kbd_queue.is_empty()) handle_input(true);
1245     return (unsigned char)kbd_queue.get();
1246 }
1247 
cleardevice()1248 void cleardevice()
1249 {
1250     RECT scr;
1251     scr.left = -view_settings.left;
1252     scr.top = -view_settings.top;
1253     scr.right = screen_width-view_settings.left-1;
1254     scr.bottom = screen_height-view_settings.top-1;
1255 
1256     if (bgiemu_handle_redraw || visual_page != active_page) {
1257 	if (hRgn != NULL) {
1258 	    SelectClipRgn(hdc[1], NULL);
1259 	}
1260 	FillRect(hdc[1], &scr, hBackgroundBrush);
1261 	if (hRgn != NULL) {
1262 	    SelectClipRgn(hdc[1], hRgn);
1263 	}
1264     }
1265     if (visual_page == active_page) {
1266 	if (hRgn != NULL) {
1267 	    SelectClipRgn(hdc[0], NULL);
1268 	}
1269 	FillRect(hdc[0], &scr, hBackgroundBrush);
1270 	if (hRgn != NULL) {
1271 	    SelectClipRgn(hdc[0], hRgn);
1272 	}
1273     }
1274     moveto(0,0);
1275 }
1276 
clearviewport()1277 void clearviewport()
1278 {
1279     RECT scr;
1280     scr.left = 0;
1281     scr.top = 0;
1282     scr.right = view_settings.right-view_settings.left;
1283     scr.bottom = view_settings.bottom-view_settings.top;
1284     if (bgiemu_handle_redraw || visual_page != active_page) {
1285         FillRect(hdc[1], &scr, hBackgroundBrush);
1286     }
1287     if (visual_page == active_page) {
1288 	FillRect(hdc[0], &scr, hBackgroundBrush);
1289     }
1290     moveto(0,0);
1291 }
1292 
detectgraph(int * graphdriver,int * graphmode)1293 void detectgraph(int *graphdriver, int *graphmode)
1294 {
1295     *graphdriver = VGA;
1296     *graphmode = bgiemu_default_mode;
1297 }
1298 
getgraphmode()1299 int getgraphmode()
1300 {
1301     return bgiemu_default_mode;
1302 }
1303 
setgraphmode(int)1304 void setgraphmode(int) {}
1305 
putimage(int x,int y,void * image,int bitblt)1306 void putimage(int x, int y, void* image, int bitblt)
1307 {
1308     BGIimage* bi = (BGIimage*)image;
1309     static int putimage_width, putimage_height;
1310 
1311     if (hPutimageBitmap == NULL ||
1312 	putimage_width < bi->width || putimage_height < bi->height)
1313     {
1314 	if (putimage_width < bi->width) {
1315 	    putimage_width = (bi->width+7) & ~7;
1316 	}
1317 	if (putimage_height < bi->height) {
1318 	    putimage_height = bi->height;
1319 	}
1320 	HBITMAP h = CreateCompatibleBitmap(hdc[0], putimage_width,
1321 					   putimage_height);
1322 	SelectObject(hdc[2], h);
1323 	if (hPutimageBitmap) {
1324 	    DeleteObject(hPutimageBitmap);
1325 	}
1326 	hPutimageBitmap = h;
1327     }
1328     int mask = ADJUSTED_MODE(bitblt) ? 0 : BG;
1329     for (int i = 0; i <= MAXCOLORS; i++) {
1330 	bminfo.color_table[i] = i + mask;
1331     }
1332     bminfo.hdr.biHeight = bi->height;
1333     bminfo.hdr.biWidth = bi->width;
1334     SetDIBits(hdc[2], hPutimageBitmap, 0, bi->height, bi->bits,
1335 	      (BITMAPINFO*)&bminfo, DIB_PAL_COLORS);
1336     if (bgiemu_handle_redraw || visual_page != active_page) {
1337 	BitBlt(hdc[1], x, y, bi->width, bi->height, hdc[2], 0, 0,
1338 	       bitblt_mode_cnv[bitblt]);
1339     }
1340     if (visual_page == active_page) {
1341         BitBlt(hdc[0], x, y, bi->width, bi->height, hdc[2], 0, 0,
1342 	       bitblt_mode_cnv[bitblt]);
1343     }
1344 }
1345 
imagesize(int x1,int y1,int x2,int y2)1346 unsigned int imagesize(int x1, int y1, int x2, int y2)
1347 {
1348     return 8 + (((x2-x1+8) & ~7) >> 1)*(y2-y1+1);
1349 }
1350 
getimage(int x1,int y1,int x2,int y2,void * image)1351 void getimage(int x1, int y1, int x2, int y2, void* image)
1352 {
1353     BGIimage* bi = (BGIimage*)image;
1354     int* image_bits;
1355     bi->width = x2-x1+1;
1356     bi->height = y2-y1+1;
1357     bminfo.hdr.biHeight = bi->height;
1358     bminfo.hdr.biWidth = bi->width;
1359     for (int i = 0; i <= MAXCOLORS; i++) {
1360 	bminfo.color_table[i] = i + BG;
1361     }
1362     HBITMAP hb = CreateDIBSection(hdc[3], (BITMAPINFO*)&bminfo,
1363 	DIB_PAL_COLORS, (void**)&image_bits, 0, 0);
1364     HBITMAP hdb = (HBITMAP)SelectObject(hdc[3], hb);
1365     BitBlt(hdc[3], 0, 0, bi->width, bi->height,
1366 	   hdc[visual_page != active_page || bgiemu_handle_redraw ? 1 : 0],
1367 	   x1, y1, SRCCOPY);
1368     GdiFlush();
1369     memcpy(bi->bits, image_bits, (((bi->width+7) & ~7) >> 1)*bi->height);
1370     SelectObject(hdc[3], hdb);
1371     DeleteObject(hb);
1372 }
1373 
getpixel(int x,int y)1374 unsigned int getpixel(int x, int y)
1375 {
1376     int color;
1377     COLORREF rgb = GetPixel(hdc[visual_page != active_page
1378 			       || bgiemu_handle_redraw ? 1 : 0], x, y);
1379 
1380     if (rgb == CLR_INVALID) {
1381 	return -1;
1382     }
1383     int red = GetRValue(rgb);
1384     int blue = GetBValue(rgb);
1385     int green = GetGValue(rgb);
1386     for (color = 0; color <= MAXCOLORS; color++) {
1387 	if (BGIpalette[color].peRed == red &&
1388 	    BGIpalette[color].peGreen == green &&
1389 	    BGIpalette[color].peBlue == blue)
1390 	{
1391 	    return color;
1392 	}
1393     }
1394     return -1;
1395 }
1396 
putpixel(int x,int y,int c)1397 void putpixel(int x, int y, int c)
1398 {
1399     c &= MAXCOLORS;
1400     if (bgiemu_handle_redraw || visual_page != active_page) {
1401 	SetPixel(hdc[1], x, y, PALETTEINDEX(c+BG));
1402     }
1403     if (visual_page == active_page) {
1404 	SetPixel(hdc[0], x, y, PALETTEINDEX(c+BG));
1405     }
1406 }
1407 
1408 
WndProc(HWND hWnd,UINT messg,WPARAM wParam,LPARAM lParam)1409 LRESULT CALLBACK WndProc(HWND hWnd, UINT messg,
1410 			 WPARAM wParam, LPARAM lParam)
1411 {
1412     int i;
1413     static bool palette_changed = false;
1414 
1415     switch (messg) {
1416       case WM_PAINT:
1417 	if (hdc[0] == 0) {
1418 	    hdc[0] = BeginPaint(hWnd, &ps);
1419             SelectPalette(hdc[0], hPalette, FALSE);
1420 	    RealizePalette(hdc[0]);
1421 	    hdc[1] = CreateCompatibleDC(hdc[0]);
1422             SelectPalette(hdc[1], hPalette, FALSE);
1423 	    hdc[2] = CreateCompatibleDC(hdc[0]);
1424             SelectPalette(hdc[2], hPalette, FALSE);
1425 	    hdc[3] = CreateCompatibleDC(hdc[0]);
1426             SelectPalette(hdc[3], hPalette, FALSE);
1427 
1428 	    screen_width = GetDeviceCaps(hdc[0], HORZRES);
1429 	    screen_height = GetDeviceCaps(hdc[0], VERTRES);
1430 	    hBitmap[active_page] =
1431 		CreateCompatibleBitmap(hdc[0], screen_width, screen_height);
1432 	    SelectObject(hdc[1], hBitmap[active_page]);
1433 
1434 	    SetTextColor(hdc[0], PALETTEINDEX(text_color+BG));
1435 	    SetTextColor(hdc[1], PALETTEINDEX(text_color+BG));
1436 	    SetBkColor(hdc[0], PALETTEINDEX(BG));
1437 	    SetBkColor(hdc[1], PALETTEINDEX(BG));
1438 
1439 	    SelectObject(hdc[0], hBrush[fill_settings.pattern]);
1440 	    SelectObject(hdc[1], hBrush[fill_settings.pattern]);
1441 
1442 	    RECT scr;
1443 	    scr.left = -view_settings.left;
1444 	    scr.top = -view_settings.top;
1445 	    scr.right = screen_width-view_settings.left-1;
1446 	    scr.bottom = screen_height-view_settings.top-1;
1447 	    FillRect(hdc[1], &scr, hBackgroundBrush);
1448 	}
1449 	if (hRgn != NULL) {
1450 	    SelectClipRgn(hdc[0], NULL);
1451 	}
1452 	if (visual_page != active_page) {
1453 	    SelectObject(hdc[1], hBitmap[visual_page]);
1454 	}
1455         BitBlt(hdc[0], -view_settings.left,
1456 	       -view_settings.top, window_width, window_height,
1457 	       hdc[1], -view_settings.left, -view_settings.top,
1458 	       SRCCOPY);
1459 	if (hRgn != NULL) {
1460 	    SelectClipRgn(hdc[0], hRgn);
1461 	}
1462 	if (visual_page != active_page) {
1463 	    SelectObject(hdc[1], hBitmap[active_page]);
1464 	}
1465 	ValidateRect(hWnd, NULL);
1466 	break;
1467       case WM_SETFOCUS:
1468 	if (palette_changed) {
1469 	    HPALETTE new_palette = CreatePalette(pPalette);
1470 	    SelectPalette(hdc[0], new_palette, FALSE);
1471 	    RealizePalette(hdc[0]);
1472 	    SelectPalette(hdc[1], new_palette, FALSE);
1473 	    SelectPalette(hdc[2], new_palette, FALSE);
1474 	    SelectPalette(hdc[3], new_palette, FALSE);
1475 	    DeleteObject(hPalette);
1476 	    hPalette = new_palette;
1477 	    palette_changed = false;
1478 	}
1479 	break;
1480       case WM_PALETTECHANGED:
1481 	RealizePalette(hdc[0]);
1482 	UpdateColors(hdc[0]);
1483 	palette_changed = true;
1484 	break;
1485       case WM_DESTROY:
1486         EndPaint(hWnd, &ps);
1487 	hdc[0] = 0;
1488 	DeleteObject(hdc[1]);
1489 	DeleteObject(hdc[2]);
1490 	DeleteObject(hdc[3]);
1491 	if (hPutimageBitmap) {
1492 	    DeleteObject(hPutimageBitmap);
1493 	    hPutimageBitmap = NULL;
1494 	}
1495 	for (i = 0; i < MAX_PAGES; i++) {
1496 	    if (hBitmap[i] != NULL) {
1497 		DeleteObject(hBitmap[i]);
1498 		hBitmap[i] = 0;
1499 	    }
1500 	}
1501 	DeleteObject(hPalette);
1502 	hPalette = 0;
1503 	PostQuitMessage(0);
1504 	break;
1505       case WM_SIZE:
1506 	window_width = LOWORD(lParam);
1507 	window_height = HIWORD(lParam);
1508 	break;
1509       case WM_TIMER:
1510 	KillTimer(hWnd, TIMER_ID);
1511 	timeout_expired = true;
1512 	break;
1513       case WM_CHAR:
1514 	kbd_queue.put((TCHAR) wParam);
1515 	break;
1516       default:
1517 	return DefWindowProc(hWnd, messg, wParam, lParam);
1518     }
1519     return 0;
1520 }
1521 
closegraph()1522 void closegraph()
1523 {
1524     if (hWnd != NULL) {
1525 	DestroyWindow(hWnd);
1526 	hWnd = NULL;
1527 	while(handle_input(true));
1528     }
1529 }
1530 
1531 
detect_mode(int * gd,int * gm)1532 static void detect_mode(int* gd, int* gm)
1533 {
1534     switch (*gd) {
1535       case CGA:
1536 	window_height = 200;
1537 	switch (*gm) {
1538   	  case CGAC0:
1539 	  case CGAC1:
1540 	  case CGAC2:
1541 	  case CGAC3:
1542 	    window_width = 320;
1543 	    break;
1544 	  case CGAHI:
1545 	    window_width = 640;
1546 	    break;
1547 	  default:
1548 	    window_width = 320;
1549 	    break;
1550 	}
1551 	break;
1552       case MCGA:
1553 	window_height = 200;
1554 	switch (*gm) {
1555 	  case MCGAC0:
1556 	  case MCGAC1:
1557 	  case MCGAC2:
1558 	  case MCGAC3:
1559 	    window_width = 320;
1560 	    break;
1561 	  case MCGAMED:
1562   	    window_width = 640;
1563 	    break;
1564 	  case MCGAHI:
1565 	    window_width = 640;
1566 	    window_height = 480;
1567 	    break;
1568 	  default:
1569 	    window_width = 320;
1570 	    break;
1571 	}
1572 	break;
1573       case EGA:
1574 	window_width = 640;
1575 	switch (*gm) {
1576 	  case EGALO:
1577 	    window_height = 200;
1578 	    break;
1579 	  case EGAHI:
1580 	    window_height = 350;
1581 	    break;
1582 	  default:
1583 	    window_height = 350;
1584 	    break;
1585 	}
1586 	break;
1587       case EGA64:
1588         window_width = 640;
1589 	switch (*gm) {
1590 	  case EGA64LO:
1591 	    window_height = 200;
1592 	    break;
1593 	  case EGA64HI:
1594 	    window_height = 350;
1595 	    break;
1596 	  default:
1597 	    window_height = 350;
1598 	    break;
1599 	}
1600 	break;
1601       case EGAMONO:
1602 	window_width = 640;
1603 	window_height = 350;
1604 	break;
1605       case HERCMONO:
1606 	window_width = 720;
1607 	window_height = 348;
1608 	break;
1609       case ATT400:
1610 	window_height = 200;
1611 	switch (*gm) {
1612 	  case ATT400C0:
1613 	  case ATT400C1:
1614 	  case ATT400C2:
1615 	  case ATT400C3:
1616 	    window_width = 320;
1617 	    break;
1618 	  case ATT400MED:
1619 	    window_width = 640;
1620 	    break;
1621 	  case ATT400HI:
1622 	    window_width = 640;
1623 	    window_height = 400;
1624 	    break;
1625 	  default:
1626 	    window_width = 320;
1627 	    break;
1628 	}
1629 	break;
1630       default:
1631       case DETECT:
1632 	*gd = VGA;
1633 	*gm = bgiemu_default_mode;
1634       case VGA:
1635         window_width = 640;
1636         switch (*gm) {
1637           case VGALO:
1638 	    window_height = 200;
1639 	    break;
1640 	  case VGAMED:
1641 	    window_height = 350;
1642 	    break;
1643 	  case VGAHI:
1644 	    window_height = 480;
1645 	    break;
1646 	  default:
1647 	    window_height = 480;
1648 	    break;
1649 	}
1650 	break;
1651       case PC3270:
1652 	window_width = 720;
1653 	window_height = 350;
1654 	break;
1655       case IBM8514:
1656 	switch (*gm) {
1657   	  case IBM8514LO:
1658  	    window_width = 640;
1659 	    window_height = 480;
1660 	    break;
1661 	  case IBM8514HI:
1662 	    window_width = 1024;
1663 	    window_height = 768;
1664 	    break;
1665 	  default:
1666 	    window_width = 1024;
1667 	    window_height = 768;
1668 	    break;
1669 	}
1670 	break;
1671     }
1672 }
1673 
set_defaults()1674 static void set_defaults()
1675 {
1676     color = text_color = WHITE;
1677     bkcolor = 0;
1678     line_settings.thickness = 1;
1679     line_settings.linestyle = SOLID_LINE;
1680     line_settings.upattern = ~0;
1681     fill_settings.pattern = SOLID_FILL;
1682     fill_settings.color = WHITE;
1683     write_mode = COPY_PUT;
1684 
1685     text_settings.direction = HORIZ_DIR;
1686     text_settings.font = DEFAULT_FONT;
1687     text_settings.charsize = 1;
1688     text_settings.horiz = LEFT_TEXT;
1689     text_settings.vert = TOP_TEXT;
1690     text_align_mode = ALIGN_NOT_SET;
1691 
1692     active_page = visual_page = 0;
1693 
1694     view_settings.left = 0;
1695     view_settings.top = 0;
1696     view_settings.right = window_width-1;
1697     view_settings.bottom = window_height-1;
1698 
1699     aspect_ratio_x = aspect_ratio_y = 10000;
1700 }
1701 
initgraph(int * device,int * mode,char const *)1702 void initgraph(int* device, int* mode, char const* /*pathtodriver*/)
1703 {
1704     int index;
1705     static WNDCLASS wcApp;
1706 
1707     gdi_error_code = grOk;
1708 
1709     if (wcApp.lpszClassName == NULL) {
1710 	wcApp.lpszClassName = "BGIlibrary";
1711 	wcApp.hInstance = 0;
1712 	wcApp.lpfnWndProc = WndProc;
1713 	wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);
1714 	wcApp.hIcon = 0;
1715 	wcApp.lpszMenuName = 0;
1716 	wcApp.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
1717 	wcApp.style = CS_SAVEBITS;
1718 	wcApp.cbClsExtra = 0;
1719 	wcApp.cbWndExtra = 0;
1720 
1721 	if (!RegisterClass(&wcApp)) {
1722 	    gdi_error_code = GetLastError();
1723 	    return;
1724 	}
1725 
1726 	pPalette = (NPLOGPALETTE)LocalAlloc(LMEM_FIXED,
1727 	    sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*PALETTE_SIZE);
1728 
1729 	pPalette->palVersion = 0x300;
1730 	pPalette->palNumEntries = PALETTE_SIZE;
1731 	memset(pPalette->palPalEntry, 0, sizeof(PALETTEENTRY)*PALETTE_SIZE);
1732 	for (index = 0; index < BG; index++) {
1733 	    pPalette->palPalEntry[index].peFlags = PC_EXPLICIT;
1734 	    pPalette->palPalEntry[index].peRed = index;
1735 	    pPalette->palPalEntry[PALETTE_SIZE-BG+index].peFlags = PC_EXPLICIT;
1736 	    pPalette->palPalEntry[PALETTE_SIZE-BG+index].peRed =
1737 		PALETTE_SIZE-BG+index;
1738 	}
1739 	hBackgroundBrush = CreateSolidBrush(PALETTEINDEX(BG));
1740 	hBrush[EMPTY_FILL] = (HBRUSH)GetStockObject(NULL_BRUSH);
1741 	hBrush[SOLID_FILL] =
1742 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, SolidBrushBitmap));
1743 	hBrush[LINE_FILL] =
1744 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, LineBrushBitmap));
1745 	hBrush[LTSLASH_FILL] =
1746 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, LtslashBrushBitmap));
1747 	hBrush[SLASH_FILL] =
1748 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, SlashBrushBitmap));
1749 	hBrush[BKSLASH_FILL] =
1750 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, BkslashBrushBitmap));
1751 	hBrush[LTBKSLASH_FILL] =
1752 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, LtbkslashBrushBitmap));
1753 	hBrush[HATCH_FILL] =
1754 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, HatchBrushBitmap));
1755 	hBrush[XHATCH_FILL] =
1756 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, XhatchBrushBitmap));
1757 	hBrush[INTERLEAVE_FILL] =
1758 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, InterleaveBrushBitmap));
1759 	hBrush[WIDE_DOT_FILL] =
1760 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, WidedotBrushBitmap));
1761 	hBrush[CLOSE_DOT_FILL] =
1762 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, ClosedotBrushBitmap));
1763 	hBrush[USER_FILL] =
1764 	    CreatePatternBrush(CreateBitmap(8, 8, 1, 1, SolidBrushBitmap));
1765     }
1766     memcpy(BGIpalette, BGIcolor, sizeof BGIpalette);
1767     current_palette.size = MAXCOLORS+1;
1768     for (index = 10; index <= MAXCOLORS; index++) {
1769 	pPalette->palPalEntry[index] = BGIcolor[0];
1770     }
1771     for (index = 0; index <= MAXCOLORS; index++) {
1772 	current_palette.colors[index] = index;
1773 	pPalette->palPalEntry[index+BG] = BGIcolor[index];
1774     }
1775     hPalette = CreatePalette(pPalette);
1776     detect_mode(device, mode);
1777     set_defaults();
1778 
1779     hWnd = CreateWindow("BGIlibrary", "Windows BGI",
1780 			WS_OVERLAPPEDWINDOW,
1781 		        0, 0, window_width+BORDER_WIDTH,
1782 			window_height+BORDER_HEIGHT,
1783 			(HWND)NULL,  (HMENU)NULL,
1784 	    		0, NULL);
1785     if (hWnd == NULL) {
1786 	gdi_error_code = GetLastError();
1787 	return;
1788     }
1789     ShowWindow(hWnd, *mode == VGAMAX ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL);
1790     UpdateWindow(hWnd);
1791 }
1792 
1793 
graphdefaults()1794 void graphdefaults()
1795 {
1796     set_defaults();
1797 
1798     for (int i = 0; i <= MAXCOLORS; i++) {
1799 	current_palette.colors[i] = i;
1800 	BGIpalette[i] = BGIcolor[i];
1801     }
1802     SetPaletteEntries(hPalette, BG, MAXCOLORS+1, BGIpalette);
1803     RealizePalette(hdc[0]);
1804 
1805     SetTextColor(hdc[0], PALETTEINDEX(text_color+BG));
1806     SetTextColor(hdc[1], PALETTEINDEX(text_color+BG));
1807     SetBkColor(hdc[0], PALETTEINDEX(BG));
1808     SetBkColor(hdc[1], PALETTEINDEX(BG));
1809 
1810     SelectClipRgn(hdc[0], NULL);
1811     SelectClipRgn(hdc[1], NULL);
1812     SetViewportOrgEx(hdc[0], 0, 0, NULL);
1813     SetViewportOrgEx(hdc[1], 0, 0, NULL);
1814 
1815     SelectObject(hdc[0], hBrush[fill_settings.pattern]);
1816     SelectObject(hdc[1], hBrush[fill_settings.pattern]);
1817 
1818     moveto(0,0);
1819 }
1820 
restorecrtmode()1821 void restorecrtmode() {}
1822