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