#include #include #include #include #include "graphics.h" #define MAX_PAGES 16 static HDC hdc[4]; static HPEN hPen; static HRGN hRgn; static HFONT hFont; static NPLOGPALETTE pPalette; static PAINTSTRUCT ps; static HWND hWnd; static HBRUSH hBrush[USER_FILL+1]; static HBRUSH hBackgroundBrush; static HPALETTE hPalette; static HBITMAP hBitmap[MAX_PAGES]; static HBITMAP hPutimageBitmap; static int timeout_expired; #define PEN_CACHE_SIZE 8 #define FONT_CACHE_SIZE 8 #define BG 16 #define TIMER_ID 1 // // When XOR or NOT write modes are used for drawing high BG bit is cleared, so // drawing colors should be adjusted to preserve this bit // #define ADJUSTED_MODE(mode) ((mode) == XOR_PUT || (mode) == NOT_PUT) int bgiemu_handle_redraw = TRUE; int bgiemu_default_mode = VGAHI; //VGAMAX; static int screen_width; static int screen_height; static int window_width; static int window_height; static int line_style_cnv[] = { PS_SOLID, PS_DOT, PS_DASHDOT, PS_DASH, PS_DASHDOTDOT /* if user style lines are not supported */ }; static int write_mode_cnv[] = {R2_COPYPEN, R2_XORPEN, R2_MERGEPEN, R2_MASKPEN, R2_NOTCOPYPEN}; static int bitblt_mode_cnv[] = {SRCCOPY, SRCINVERT, SRCPAINT, SRCAND, NOTSRCCOPY}; static int font_weight[] = { FW_BOLD, // DefaultFont FW_NORMAL, // TriplexFont FW_NORMAL, // SmallFont FW_NORMAL, // SansSerifFont FW_NORMAL, // GothicFont FW_NORMAL, // ScriptFont FW_NORMAL, // SimplexFont FW_NORMAL, // TriplexScriptFont FW_NORMAL, // ComplexFont FW_NORMAL, // EuropeanFont FW_BOLD // BoldFont }; static int font_family[] = { FIXED_PITCH|FF_DONTCARE, // DefaultFont VARIABLE_PITCH|FF_ROMAN, // TriplexFont VARIABLE_PITCH|FF_MODERN, // SmallFont VARIABLE_PITCH|FF_DONTCARE, // SansSerifFont VARIABLE_PITCH|FF_SWISS, // GothicFont VARIABLE_PITCH|FF_SCRIPT, // ScriptFont VARIABLE_PITCH|FF_DONTCARE, // SimplexFont VARIABLE_PITCH|FF_SCRIPT, // TriplexScriptFont VARIABLE_PITCH|FF_DONTCARE, // ComplexFont VARIABLE_PITCH|FF_DONTCARE, // EuropeanFont VARIABLE_PITCH|FF_DONTCARE // BoldFont }; static char* font_name[] = { "Console", // DefaultFont "Times New Roman", // TriplexFont "Small Fonts", // SmallFont "MS Sans Serif", // SansSerifFont "Arial", // GothicFont "Script", // ScriptFont "Times New Roman", // SimplexFont "Script", // TriplexScriptFont "Courier New", // ComplexFont "Times New Roman", // EuropeanFont "Courier New Bold", // BoldFont }; static int text_halign_cnv[] = {TA_LEFT, TA_CENTER, TA_RIGHT}; static int text_valign_cnv[] = {TA_BOTTOM, TA_BASELINE, TA_TOP}; static palettetype current_palette; static struct { int width; int height; } font_metrics[][11] = { {{0,0},{8,8},{16,16},{24,24},{32,32},{40,40},{48,48},{56,56},{64,64},{72,72},{80,80}}, // DefaultFont {{0,0},{13,18},{14,20},{16,23},{22,31},{29,41},{36,51},{44,62},{55,77},{66,93},{88,124}}, // TriplexFont {{0,0},{3,5},{4,6},{4,6},{6,9},{8,12},{10,15},{12,18},{15,22},{18,27},{24,36}}, // SmallFont {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // SansSerifFont {{0,0},{13,19},{14,21},{16,24},{22,32},{29,42},{36,53},{44,64},{55,80},{66,96},{88,128}}, // GothicFont // I am not sure about metrics of following fonts {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // ScriptFont {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // SimplexFont {{0,0},{13,18},{14,20},{16,23},{22,31},{29,41},{36,51},{44,62},{55,77},{66,93},{88,124}}, // TriplexScriptFont {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // ComplexFont {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // EuropeanFont {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}} // BoldFont }; struct BGIimage { short width; short height; int reserved; // let bits be aligned to DWORD boundary char bits[1]; }; struct BGIbitmapinfo { BITMAPINFOHEADER hdr; short color_table[16]; }; static BGIbitmapinfo bminfo = { {sizeof(BITMAPINFOHEADER), 0, 0, 1, 4, BI_RGB} }; static int* image_bits; static int normal_font_size[] = { 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; static linesettingstype line_settings; static fillsettingstype fill_settings; static int color; static int bkcolor; static int text_color; static int aspect_ratio_x, aspect_ratio_y; static textsettingstype text_settings; static viewporttype view_settings; static int font_mul_x, font_div_x, font_mul_y, font_div_y; static enum { ALIGN_NOT_SET, UPDATE_CP, NOT_UPDATE_CP } text_align_mode; #define BORDER_WIDTH 8 #define BORDER_HEIGHT 27 static int write_mode; static int visual_page; static int active_page; static arccoordstype ac; class char_queue { protected: char* buf; int put_pos; int get_pos; int buf_size; public: void put(char ch) { buf[put_pos] = ch; if (++put_pos == buf_size) { put_pos = 0; } if (put_pos == get_pos) { // queue is full (void)get(); // loose one character } } char get() { char ch = buf[get_pos]; if (++get_pos == buf_size) { get_pos = 0; } return ch; } bool is_empty() { return get_pos == put_pos; } char_queue(int buf_size = 256) { put_pos = get_pos = 0; this->buf_size = buf_size; buf = new char[buf_size]; } ~char_queue() { delete[] buf; } }; static char_queue kbd_queue; inline int convert_userbits(DWORD buf[32], unsigned pattern) { int i = 0, j; pattern &= 0xFFFF; while (true) { for (j = 0; pattern & 1; j++) pattern >>= 1; buf[i++] = j; if (pattern == 0) { buf[i++] = 16 - j; return i; } for (j = 0; !(pattern & 1); j++) pattern >>= 1; buf[i++] = j; } } class l2elem { public: l2elem* next; l2elem* prev; void link_after(l2elem* after) { (next = after->next)->prev = this; (prev = after)->next = this; } void unlink() { prev->next = next; next->prev = prev; } void prune() { next = prev = this; } }; class l2list : public l2elem { public: l2list() { prune(); } }; class pen_cache : public l2list { class pen_cache_item : public l2elem { public: HPEN pen; int color; int width; int style; unsigned pattern; }; pen_cache_item* free; pen_cache_item cache[PEN_CACHE_SIZE]; public: pen_cache() { for (int i = 0; i < PEN_CACHE_SIZE-1; i++) { cache[i].next = &cache[i+1]; } cache[PEN_CACHE_SIZE-1].next = NULL; free = cache; } void select(int color) { for (l2elem* elem = next; elem != this; elem = elem->next) { pen_cache_item* ci = (pen_cache_item*)elem; if (ci->color == color && ci->style == line_settings.linestyle && ci->width == line_settings.thickness && (line_settings.linestyle != USERBIT_LINE || line_settings.upattern == ci->pattern)) { ci->unlink(); // LRU discipline ci->link_after(this); if (hPen != ci->pen) { hPen = ci->pen; SelectObject(hdc[0], hPen); SelectObject(hdc[1], hPen); } return; } } hPen = NULL; if (line_settings.linestyle == USERBIT_LINE) { LOGBRUSH lb; lb.lbColor = PALETTEINDEX(color); lb.lbStyle = BS_SOLID; DWORD style[32]; hPen = ExtCreatePen(PS_GEOMETRIC|PS_USERSTYLE, line_settings.thickness, &lb, convert_userbits(style,line_settings.upattern), style); } if (hPen == NULL) { hPen = CreatePen(line_style_cnv[line_settings.linestyle], line_settings.thickness, PALETTEINDEX(color)); } SelectObject(hdc[0], hPen); SelectObject(hdc[1], hPen); pen_cache_item* p; if (free == NULL) { p = (pen_cache_item*)prev; p->unlink(); DeleteObject(p->pen); } else { p = free; free = (pen_cache_item*)p->next; } p->pen = hPen; p->color = color; p->width = line_settings.thickness; p->style = line_settings.linestyle; p->pattern = line_settings.upattern; p->link_after(this); } }; static pen_cache pcache; class font_cache : public l2list { class font_cache_item : public l2elem { public: HFONT font; int type; int direction; int width, height; }; font_cache_item* free; font_cache_item cache[FONT_CACHE_SIZE]; public: font_cache() { for (int i = 0; i < FONT_CACHE_SIZE-1; i++) { cache[i].next = &cache[i+1]; } cache[FONT_CACHE_SIZE-1].next = NULL; free = cache; } void select(int type, int direction, int width, int height) { for (l2elem* elem = next; elem != this; elem = elem->next) { font_cache_item* ci = (font_cache_item*)elem; if (ci->type == type && ci->direction == direction && ci->width == width && ci->height == height) { ci->unlink(); ci->link_after(this); if (hFont != ci->font) { hFont = ci->font; SelectObject(hdc[0], hFont); SelectObject(hdc[1], hFont); } return; } } hFont = CreateFont(-height, width, direction*900, (direction&1)*900, font_weight[type], FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, font_family[type], font_name[type]); SelectObject(hdc[0], hFont); SelectObject(hdc[1], hFont); font_cache_item* p; if (free == NULL) { p = (font_cache_item*)prev; p->unlink(); DeleteObject(p->font); } else { p = free; free = (font_cache_item*)p->next; } p->font = hFont; p->type = type; p->width = width; p->height = height; p->direction = direction; p->link_after(this); } }; static font_cache fcache; #define FLAGS PC_NOCOLLAPSE #define PALETTE_SIZE 256 static PALETTEENTRY BGIcolor[16] = { { 0, 0, 0, FLAGS }, { 0, 0, 255, FLAGS }, { 0, 255, 0, FLAGS }, { 0, 255, 255, FLAGS }, { 255, 0, 0, FLAGS }, { 255, 0, 255, FLAGS }, { 165, 42, 42, FLAGS }, { 211, 211, 211, FLAGS }, { 47, 79, 79, FLAGS }, { 173, 216, 230, FLAGS }, { 32, 178, 170, FLAGS }, { 224, 255, 255, FLAGS }, { 240, 128, 128, FLAGS }, { 219, 112, 147, FLAGS }, { 255, 255, 0, FLAGS }, { 255, 255, 255, FLAGS } }; static PALETTEENTRY BGIpalette[16]; static short SolidBrushBitmap[8] = {~0xFF, ~0xFF, ~0xFF, ~0xFF, ~0xFF, ~0xFF, ~0xFF, ~0xFF}; static short LineBrushBitmap[8] = {~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0xFF}; static short LtslashBrushBitmap[8] = {~0x01, ~0x02, ~0x04, ~0x08, ~0x10, ~0x20, ~0x40, ~0x80}; static short SlashBrushBitmap[8] = {~0x81, ~0x03, ~0x06, ~0x0C, ~0x18, ~0x30, ~0x60, ~0xC0}; static short BkslashBrushBitmap[8] = {~0xC0, ~0x60, ~0x30, ~0x18, ~0x0C, ~0x06, ~0x03, ~0x81}; static short LtbkslashBrushBitmap[8] = {~0x80, ~0x40, ~0x20, ~0x10, ~0x08, ~0x04, ~0x02, ~0x01}; static short HatchBrushBitmap[8] = {~0x01, ~0x01, ~0x01, ~0x01, ~0x01, ~0x01, ~0x01, ~0xFF}; static short XhatchBrushBitmap[8] = {~0x81, ~0x42, ~0x24, ~0x18, ~0x18, ~0x24, ~0x42, ~0x81}; static short InterleaveBrushBitmap[8] = {~0x55, ~0xAA, ~0x55, ~0xAA, ~0x55, ~0xAA, ~0x55, ~0xAA}; static short WidedotBrushBitmap[8] = {~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0x00, ~0x01}; static short ClosedotBrushBitmap[8] = {~0x44, ~0x00, ~0x11, ~0x00, ~0x44, ~0x00, ~0x11, ~0x00}; char* grapherrormsg(int code) { static char buf[256]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buf, sizeof buf, NULL); return buf; } static int gdi_error_code; int graphresult() { return gdi_error_code; } void setcolor(int c) { c &= MAXCOLORS; color = c; SetTextColor(hdc[0], PALETTEINDEX(c+BG)); SetTextColor(hdc[1], PALETTEINDEX(c+BG)); } int getmaxcolor() { return WHITE; } int getmaxmode() { return VGAMAX; } char* getmodename(int mode) { static char mode_str[32]; sprintf(mode_str, "%d x %d %s", window_width, window_height, mode < 2 ? "EGA" : "VGA"); return mode_str; } int getx() { POINT pos; GetCurrentPositionEx(hdc[active_page == visual_page ? 0 : 1], &pos); return pos.x; } int gety() { POINT pos; GetCurrentPositionEx(hdc[active_page == visual_page ? 0 : 1], &pos); return pos.y; } int getmaxx() { return window_width-1; } int getmaxy() { return window_height-1; } int getcolor() { return color; } char* getdrivername() { return "EGAVGA"; } void setlinestyle(int style, unsigned int pattern, int thickness) { line_settings.linestyle = style; line_settings.thickness = thickness; line_settings.upattern = pattern; } void getlinesettings(linesettingstype* ls) { *ls = line_settings; } void setwritemode(int mode) { write_mode = mode; } void setpalette(int index, int color) { color &= MAXCOLORS; BGIpalette[index] = BGIcolor[color]; current_palette.colors[index] = color; SetPaletteEntries(hPalette, BG+index, 1, &BGIpalette[index]); RealizePalette(hdc[0]); if (index == 0) { bkcolor = 0; } } void setrgbpalette(int index, int red, int green, int blue) { BGIpalette[index].peRed = red & 0xFC; BGIpalette[index].peGreen = green & 0xFC; BGIpalette[index].peBlue = blue & 0xFC; SetPaletteEntries(hPalette, BG+index, 1, &BGIpalette[index]); RealizePalette(hdc[0]); if (index == 0) { bkcolor = 0; } } void setallpalette(palettetype* pal) { for (int i = 0; i < pal->size; i++) { current_palette.colors[i] = pal->colors[i] & MAXCOLORS; BGIpalette[i] = BGIcolor[pal->colors[i] & MAXCOLORS]; } SetPaletteEntries(hPalette, BG, pal->size, BGIpalette); RealizePalette(hdc[0]); bkcolor = 0; } palettetype* getdefaultpalette() { static palettetype default_palette = { 16, { BLACK, BLUE, GREEN, CYAN, RED, MAGENT, BROWN, LIGHTGRAY, DARKGRAY, LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE }}; return &default_palette; } void getpalette(palettetype* pal) { *pal = current_palette; } int getpalettesize() { return MAXCOLORS+1; } void setbkcolor(int color) { color &= MAXCOLORS; BGIpalette[0] = BGIcolor[color]; SetPaletteEntries(hPalette, BG, 1, &BGIpalette[0]); RealizePalette(hdc[0]); bkcolor = color; } int getbkcolor() { return bkcolor; } void setfillstyle(int style, int color) { fill_settings.pattern = style; fill_settings.color = color & MAXCOLORS; SelectObject(hdc[0], hBrush[style]); SelectObject(hdc[1], hBrush[style]); } void getfillsettings(fillsettingstype* fs) { *fs = fill_settings; } static fillpatterntype userfillpattern = {-1, -1, -1, -1, -1, -1, -1, -1}; void setfillpattern(char const* upattern, int color) { static HBITMAP hFillBitmap; static short bitmap_data[8]; for (int i = 0; i < 8; i++) { bitmap_data[i] = (unsigned char)~upattern[i]; userfillpattern[i] = upattern[i]; } HBITMAP h = CreateBitmap(8, 8, 1, 1, bitmap_data); HBRUSH hb = CreatePatternBrush(h); DeleteObject(hBrush[USER_FILL]); if (hFillBitmap) { DeleteObject(hFillBitmap); } hFillBitmap = h; hBrush[USER_FILL] = hb; SelectObject(hdc[0], hb); SelectObject(hdc[1], hb); fill_settings.color = color & MAXCOLORS; fill_settings.pattern = USER_FILL; } void getfillpattern(fillpatterntype fp) { memcpy(fp, userfillpattern, sizeof userfillpattern); } inline void select_fill_color() { if (text_color != fill_settings.color) { text_color = fill_settings.color; SetTextColor(hdc[0], PALETTEINDEX(text_color+BG)); SetTextColor(hdc[1], PALETTEINDEX(text_color+BG)); } } void setusercharsize(int multx, int divx, int multy, int divy) { font_mul_x = multx; font_div_x = divx; font_mul_y = multy; font_div_y = divy; text_settings.charsize = 0; } void moveto(int x, int y) { if (bgiemu_handle_redraw || visual_page != active_page) { MoveToEx(hdc[1], x, y, NULL); } if (visual_page == active_page) { MoveToEx(hdc[0], x, y, NULL); } } void moverel(int dx, int dy) { POINT pos; GetCurrentPositionEx(hdc[1], &pos); moveto(pos.x + dx, pos.y + dy); } static void select_font() { if (text_settings.charsize == 0) { fcache.select(text_settings.font, text_settings.direction, font_metrics[text_settings.font] [normal_font_size[text_settings.font]].width *font_mul_x/font_div_x, font_metrics[text_settings.font] [normal_font_size[text_settings.font]].height *font_mul_y/font_div_y); } else { fcache.select(text_settings.font, text_settings.direction, font_metrics[text_settings.font][text_settings.charsize].width, font_metrics[text_settings.font][text_settings.charsize].height); } } static void text_output(int x, int y, const char* str) { select_font(); if (text_color != color) { text_color = color; SetTextColor(hdc[0], PALETTEINDEX(text_color+BG)); SetTextColor(hdc[1], PALETTEINDEX(text_color+BG)); } if (bgiemu_handle_redraw || visual_page != active_page) { TextOut(hdc[1], x, y, str, strlen(str)); } if (visual_page == active_page) { TextOut(hdc[0], x, y, str, strlen(str)); } } void settextstyle(int font, int direction, int char_size) { if (char_size > 10) { char_size = 10; } text_settings.direction = direction; text_settings.font = font; text_settings.charsize = char_size; text_align_mode = ALIGN_NOT_SET; } void settextjustify(int horiz, int vert) { text_settings.horiz = horiz; text_settings.vert = vert; text_align_mode = ALIGN_NOT_SET; } void gettextsettings(textsettingstype* ts) { *ts = text_settings; } int textheight(const char* str) { SIZE ss; select_font(); GetTextExtentPoint32(hdc[0], str, strlen(str), &ss); return ss.cy; } int textwidth(const char* str) { SIZE ss; select_font(); GetTextExtentPoint32(hdc[0], str, strlen(str), &ss); return ss.cx; } void outtext(const char* str) { if (text_align_mode != UPDATE_CP) { text_align_mode = UPDATE_CP; int align = (text_settings.direction == HORIZ_DIR) ? (TA_UPDATECP | text_halign_cnv[text_settings.horiz] | text_valign_cnv[text_settings.vert]) : (TA_UPDATECP | text_valign_cnv[text_settings.horiz] | text_halign_cnv[text_settings.vert]); SetTextAlign(hdc[0], align); SetTextAlign(hdc[1], align); } text_output(0, 0, str); } void outtextxy(int x, int y, const char* str) { if (text_align_mode != NOT_UPDATE_CP) { text_align_mode = NOT_UPDATE_CP; int align = (text_settings.direction == HORIZ_DIR) ? (TA_NOUPDATECP | text_halign_cnv[text_settings.horiz] | text_valign_cnv[text_settings.vert]) : (TA_NOUPDATECP | text_valign_cnv[text_settings.horiz] | text_halign_cnv[text_settings.vert]); SetTextAlign(hdc[0], align); SetTextAlign(hdc[1], align); } text_output(x, y, str); } void setviewport(int x1, int y1, int x2, int y2, int clip) { view_settings.left = x1; view_settings.top = y1; view_settings.right = x2; view_settings.bottom = y2; view_settings.clip = clip; if (hRgn) { DeleteObject(hRgn); } hRgn = clip ? CreateRectRgn(x1, y1, x2, y2) : NULL; SelectClipRgn(hdc[1], hRgn); SetViewportOrgEx(hdc[1], x1, y1, NULL); SelectClipRgn(hdc[0], hRgn); SetViewportOrgEx(hdc[0], x1, y1, NULL); moveto(0,0); } void getviewsettings(viewporttype *viewport) { *viewport = view_settings; } const double pi = 3.14159265358979323846; inline void arc_coords(double angle, double rx, double ry, int& x, int& y) { if (rx == 0 || ry == 0) { x = y = 0; return; } double s = sin(angle*pi/180.0); double c = cos(angle*pi/180.0); if (fabs(s) < fabs(c)) { double tg = s/c; double xr = sqrt((double)rx*rx*ry*ry/(ry*ry+rx*rx*tg*tg)); x = int((c >= 0) ? xr : -xr); y = int((s >= 0) ? -xr*tg : xr*tg); } else { double ctg = c/s; double yr = sqrt((double)rx*rx*ry*ry/(rx*rx+ry*ry*ctg*ctg)); x = int((c >= 0) ? yr*ctg : -yr*ctg); y = int((s >= 0) ? -yr : yr); } } void ellipse(int x, int y, int start_angle, int end_angle, int rx, int ry) { ac.x = x; ac.y = y; arc_coords(start_angle, rx, ry, ac.xstart, ac.ystart); arc_coords(end_angle, rx, ry, ac.xend, ac.yend); ac.xstart += x; ac.ystart += y; ac.xend += x; ac.yend += y; pcache.select(color+BG); if (bgiemu_handle_redraw || visual_page != active_page) { Arc(hdc[1], x-rx, y-ry, x+rx, y+ry, ac.xstart, ac.ystart, ac.xend, ac.yend); } if (visual_page == active_page) { Arc(hdc[0], x-rx, y-ry, x+rx, y+ry, ac.xstart, ac.ystart, ac.xend, ac.yend); } } void fillellipse(int x, int y, int rx, int ry) { pcache.select(color+BG); select_fill_color(); if (bgiemu_handle_redraw || visual_page != active_page) { Ellipse(hdc[1], x-rx, y-ry, x+rx, y+ry); } if (visual_page == active_page) { Ellipse(hdc[0], x-rx, y-ry, x+rx, y+ry); } } static void allocate_new_graphic_page(int page) { RECT scr; scr.left = -view_settings.left; scr.top = -view_settings.top; scr.right = screen_width-view_settings.left-1; scr.bottom = screen_height-view_settings.top-1; hBitmap[page] = CreateCompatibleBitmap(hdc[0],screen_width,screen_height); SelectObject(hdc[1], hBitmap[page]); SelectClipRgn(hdc[1], NULL); FillRect(hdc[1], &scr, hBackgroundBrush); SelectClipRgn(hdc[1], hRgn); } void setactivepage(int page) { if (hBitmap[page] == NULL) { allocate_new_graphic_page(page); } else { SelectObject(hdc[1], hBitmap[page]); } if (!bgiemu_handle_redraw && active_page == visual_page) { POINT pos; GetCurrentPositionEx(hdc[0], &pos); MoveToEx(hdc[1], pos.x, pos.y, NULL); } active_page = page; } void setvisualpage(int page) { POINT pos; if (hdc[page] == NULL) { allocate_new_graphic_page(page); } if (!bgiemu_handle_redraw && active_page == visual_page) { SelectObject(hdc[1], hBitmap[visual_page]); SelectClipRgn(hdc[1], NULL); BitBlt(hdc[1], -view_settings.left, -view_settings.top, window_width, window_height, hdc[0], -view_settings.left, -view_settings.top, SRCCOPY); SelectClipRgn(hdc[1], hRgn); GetCurrentPositionEx(hdc[0], &pos); MoveToEx(hdc[1], pos.x, pos.y, NULL); } SelectClipRgn(hdc[0], NULL); SelectClipRgn(hdc[1], NULL); SelectObject(hdc[1], hBitmap[page]); BitBlt(hdc[0], -view_settings.left, -view_settings.top, window_width, window_height, hdc[1], -view_settings.left, -view_settings.top, SRCCOPY); SelectClipRgn(hdc[0], hRgn); SelectClipRgn(hdc[1], hRgn); if (page != active_page) { SelectObject(hdc[1], hBitmap[active_page]); } if (active_page != visual_page) { GetCurrentPositionEx(hdc[1], &pos); MoveToEx(hdc[0], pos.x, pos.y, NULL); } visual_page = page; } void setaspectratio(int ax, int ay) { aspect_ratio_x = ax; aspect_ratio_y = ay; } void getaspectratio(int* ax, int* ay) { *ax = aspect_ratio_x; *ay = aspect_ratio_y; } void circle(int x, int y, int radius) { pcache.select(color+BG); int ry = (unsigned)radius*aspect_ratio_x/aspect_ratio_y; int rx = radius; if (bgiemu_handle_redraw || visual_page != active_page) { Arc(hdc[1], x-rx, y-ry, x+rx, y+ry, x+rx, y, x+rx, y); } if (visual_page == active_page) { Arc(hdc[0], x-rx, y-ry, x+rx, y+ry, x+rx, y, x+rx, y); } } void arc(int x, int y, int start_angle, int end_angle, int radius) { ac.x = x; ac.y = y; ac.xstart = x + int(radius*cos(start_angle*pi/180.0)); ac.ystart = y - int(radius*sin(start_angle*pi/180.0)); ac.xend = x + int(radius*cos(end_angle*pi/180.0)); ac.yend = y - int(radius*sin(end_angle*pi/180.0)); if (bgiemu_handle_redraw || visual_page != active_page) { Arc(hdc[1], x-radius, y-radius, x+radius, y+radius, ac.xstart, ac.ystart, ac.xend, ac.yend); } if (visual_page == active_page) { Arc(hdc[0], x-radius, y-radius, x+radius, y+radius, ac.xstart, ac.ystart, ac.xend, ac.yend); } } void getarccoords(arccoordstype *arccoords) { *arccoords = ac; } void pieslice(int x, int y, int start_angle, int end_angle, int radius) { pcache.select(color+BG); select_fill_color(); ac.x = x; ac.y = y; ac.xstart = x + int(radius*cos(start_angle*pi/180.0)); ac.ystart = y - int(radius*sin(start_angle*pi/180.0)); ac.xend = x + int(radius*cos(end_angle*pi/180.0)); ac.yend = y - int(radius*sin(end_angle*pi/180.0)); if (bgiemu_handle_redraw || visual_page != active_page) { Pie(hdc[1], x-radius, y-radius, x+radius, y+radius, ac.xstart, ac.ystart, ac.xend, ac.yend); } if (visual_page == active_page) { Pie(hdc[0], x-radius, y-radius, x+radius, y+radius, ac.xstart, ac.ystart, ac.xend, ac.yend); } } void sector(int x, int y, int start_angle, int end_angle, int rx, int ry) { ac.x = x; ac.y = y; arc_coords(start_angle, rx, ry, ac.xstart, ac.ystart); arc_coords(end_angle, rx, ry, ac.xend, ac.yend); ac.xstart += x; ac.ystart += y; ac.xend += x; ac.yend += y; pcache.select(color+BG); if (bgiemu_handle_redraw || visual_page != active_page) { Pie(hdc[1], x-rx, y-ry, x+rx, y+ry, ac.xstart, ac.ystart, ac.xend, ac.yend); } if (visual_page == active_page) { Pie(hdc[0], x-rx, y-ry, x+rx, y+ry, ac.xstart, ac.ystart, ac.xend, ac.yend); } } void bar(int left, int top, int right, int bottom) { RECT r; if (left > right) { /* Turbo C corrects for badly ordered corners */ r.left = right; r.right = left; } else { r.left = left; r.right = right; } if (bottom < top) { /* Turbo C corrects for badly ordered corners */ r.top = bottom; r.bottom = top; } else { r.top = top; r.bottom = bottom; } select_fill_color(); if (bgiemu_handle_redraw || visual_page != active_page) { FillRect(hdc[1], &r, hBrush[fill_settings.pattern]); } if (visual_page == active_page) { FillRect(hdc[0], &r, hBrush[fill_settings.pattern]); } } void bar3d(int left, int top, int right, int bottom, int depth, int topflag) { int temp; const double tan30 = 1.0/1.73205080756887729352; if (left > right) { /* Turbo C corrects for badly ordered corners */ temp = left; left = right; right = temp; } if (bottom < top) { temp = bottom; bottom = top; top = temp; } bar(left+line_settings.thickness, top+line_settings.thickness, right-line_settings.thickness+1, bottom-line_settings.thickness+1); if (write_mode != COPY_PUT) { SetROP2(hdc[0], write_mode_cnv[write_mode]); SetROP2(hdc[1], write_mode_cnv[write_mode]); } pcache.select(ADJUSTED_MODE(write_mode) ? color : color + BG); int dy = int(depth*tan30); POINT p[11]; p[0].x = right, p[0].y = bottom; p[1].x = right, p[1].y = top; p[2].x = left, p[2].y = top; p[3].x = left, p[3].y = bottom; p[4].x = right, p[4].y = bottom; p[5].x = right+depth, p[5].y = bottom-dy; p[6].x = right+depth, p[6].y = top-dy; p[7].x = right, p[7].y = top; if (topflag) { p[8].x = right+depth, p[8].y = top-dy; p[9].x = left+depth, p[9].y = top-dy; p[10].x = left, p[10].y = top; } if (bgiemu_handle_redraw || visual_page != active_page) { Polyline(hdc[1], p, topflag ? 11 : 8); } if (visual_page == active_page) { Polyline(hdc[0], p, topflag ? 11 : 8); } if (write_mode != COPY_PUT) { SetROP2(hdc[0], R2_COPYPEN); SetROP2(hdc[1], R2_COPYPEN); } } void lineto(int x, int y) { if (write_mode != COPY_PUT) { SetROP2(hdc[0], write_mode_cnv[write_mode]); SetROP2(hdc[1], write_mode_cnv[write_mode]); } pcache.select(ADJUSTED_MODE(write_mode) ? color : color + BG); if (bgiemu_handle_redraw || visual_page != active_page) { LineTo(hdc[1], x, y); } if (visual_page == active_page) { LineTo(hdc[0], x, y); } if (write_mode != COPY_PUT) { SetROP2(hdc[0], R2_COPYPEN); SetROP2(hdc[1], R2_COPYPEN); } } void linerel(int dx, int dy) { POINT pos; GetCurrentPositionEx(hdc[1], &pos); lineto(pos.x + dx, pos.y + dy); } void drawpoly(int n_points, int* points) { if (write_mode != COPY_PUT) { SetROP2(hdc[0], write_mode_cnv[write_mode]); SetROP2(hdc[1], write_mode_cnv[write_mode]); } pcache.select(ADJUSTED_MODE(write_mode) ? color : color + BG); if (bgiemu_handle_redraw || visual_page != active_page) { Polyline(hdc[1], (POINT*)points, n_points); } if (visual_page == active_page) { Polyline(hdc[0], (POINT*)points, n_points); } if (write_mode != COPY_PUT) { SetROP2(hdc[0], R2_COPYPEN); SetROP2(hdc[1], R2_COPYPEN); } } void line(int x0, int y0, int x1, int y1) { POINT line[2]; line[0].x = x0; line[0].y = y0; line[1].x = x1; line[1].y = y1; drawpoly(2, (int*)&line); } void rectangle(int left, int top, int right, int bottom) { POINT rect[5]; rect[0].x = left, rect[0].y = top; rect[1].x = right, rect[1].y = top; rect[2].x = right, rect[2].y = bottom; rect[3].x = left, rect[3].y = bottom; rect[4].x = left, rect[4].y = top; drawpoly(5, (int*)&rect); } void fillpoly(int n_points, int* points) { pcache.select(color+BG); select_fill_color(); if (bgiemu_handle_redraw || visual_page != active_page) { Polygon(hdc[1], (POINT*)points, n_points); } if (visual_page == active_page) { Polygon(hdc[0], (POINT*)points, n_points); } } void floodfill(int x, int y, int border) { select_fill_color(); if (bgiemu_handle_redraw || visual_page != active_page) { FloodFill(hdc[1], x, y, PALETTEINDEX(border+BG)); } if (visual_page == active_page) { FloodFill(hdc[0], x, y, PALETTEINDEX(border+BG)); } } static bool handle_input(bool wait = 0) { MSG lpMsg; if (wait ? GetMessage(&lpMsg, NULL, 0, 0) : PeekMessage(&lpMsg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&lpMsg); DispatchMessage(&lpMsg); return true; } return false; } void delay(unsigned msec) { timeout_expired = false; SetTimer(hWnd, TIMER_ID, msec, NULL); while (!timeout_expired) handle_input(true); } int kbhit() { while (handle_input(false)); return !kbd_queue.is_empty(); } int getch() { while (kbd_queue.is_empty()) handle_input(true); return (unsigned char)kbd_queue.get(); } void cleardevice() { RECT scr; scr.left = -view_settings.left; scr.top = -view_settings.top; scr.right = screen_width-view_settings.left-1; scr.bottom = screen_height-view_settings.top-1; if (bgiemu_handle_redraw || visual_page != active_page) { if (hRgn != NULL) { SelectClipRgn(hdc[1], NULL); } FillRect(hdc[1], &scr, hBackgroundBrush); if (hRgn != NULL) { SelectClipRgn(hdc[1], hRgn); } } if (visual_page == active_page) { if (hRgn != NULL) { SelectClipRgn(hdc[0], NULL); } FillRect(hdc[0], &scr, hBackgroundBrush); if (hRgn != NULL) { SelectClipRgn(hdc[0], hRgn); } } moveto(0,0); } void clearviewport() { RECT scr; scr.left = 0; scr.top = 0; scr.right = view_settings.right-view_settings.left; scr.bottom = view_settings.bottom-view_settings.top; if (bgiemu_handle_redraw || visual_page != active_page) { FillRect(hdc[1], &scr, hBackgroundBrush); } if (visual_page == active_page) { FillRect(hdc[0], &scr, hBackgroundBrush); } moveto(0,0); } void detectgraph(int *graphdriver, int *graphmode) { *graphdriver = VGA; *graphmode = bgiemu_default_mode; } int getgraphmode() { return bgiemu_default_mode; } void setgraphmode(int) {} void putimage(int x, int y, void* image, int bitblt) { BGIimage* bi = (BGIimage*)image; static int putimage_width, putimage_height; if (hPutimageBitmap == NULL || putimage_width < bi->width || putimage_height < bi->height) { if (putimage_width < bi->width) { putimage_width = (bi->width+7) & ~7; } if (putimage_height < bi->height) { putimage_height = bi->height; } HBITMAP h = CreateCompatibleBitmap(hdc[0], putimage_width, putimage_height); SelectObject(hdc[2], h); if (hPutimageBitmap) { DeleteObject(hPutimageBitmap); } hPutimageBitmap = h; } int mask = ADJUSTED_MODE(bitblt) ? 0 : BG; for (int i = 0; i <= MAXCOLORS; i++) { bminfo.color_table[i] = i + mask; } bminfo.hdr.biHeight = bi->height; bminfo.hdr.biWidth = bi->width; SetDIBits(hdc[2], hPutimageBitmap, 0, bi->height, bi->bits, (BITMAPINFO*)&bminfo, DIB_PAL_COLORS); if (bgiemu_handle_redraw || visual_page != active_page) { BitBlt(hdc[1], x, y, bi->width, bi->height, hdc[2], 0, 0, bitblt_mode_cnv[bitblt]); } if (visual_page == active_page) { BitBlt(hdc[0], x, y, bi->width, bi->height, hdc[2], 0, 0, bitblt_mode_cnv[bitblt]); } } unsigned int imagesize(int x1, int y1, int x2, int y2) { return 8 + (((x2-x1+8) & ~7) >> 1)*(y2-y1+1); } void getimage(int x1, int y1, int x2, int y2, void* image) { BGIimage* bi = (BGIimage*)image; int* image_bits; bi->width = x2-x1+1; bi->height = y2-y1+1; bminfo.hdr.biHeight = bi->height; bminfo.hdr.biWidth = bi->width; for (int i = 0; i <= MAXCOLORS; i++) { bminfo.color_table[i] = i + BG; } HBITMAP hb = CreateDIBSection(hdc[3], (BITMAPINFO*)&bminfo, DIB_PAL_COLORS, (void**)&image_bits, 0, 0); HBITMAP hdb = (HBITMAP)SelectObject(hdc[3], hb); BitBlt(hdc[3], 0, 0, bi->width, bi->height, hdc[visual_page != active_page || bgiemu_handle_redraw ? 1 : 0], x1, y1, SRCCOPY); GdiFlush(); memcpy(bi->bits, image_bits, (((bi->width+7) & ~7) >> 1)*bi->height); SelectObject(hdc[3], hdb); DeleteObject(hb); } unsigned int getpixel(int x, int y) { int color; COLORREF rgb = GetPixel(hdc[visual_page != active_page || bgiemu_handle_redraw ? 1 : 0], x, y); if (rgb == CLR_INVALID) { return -1; } int red = GetRValue(rgb); int blue = GetBValue(rgb); int green = GetGValue(rgb); for (color = 0; color <= MAXCOLORS; color++) { if (BGIpalette[color].peRed == red && BGIpalette[color].peGreen == green && BGIpalette[color].peBlue == blue) { return color; } } return -1; } void putpixel(int x, int y, int c) { c &= MAXCOLORS; if (bgiemu_handle_redraw || visual_page != active_page) { SetPixel(hdc[1], x, y, PALETTEINDEX(c+BG)); } if (visual_page == active_page) { SetPixel(hdc[0], x, y, PALETTEINDEX(c+BG)); } } LRESULT CALLBACK WndProc(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) { int i; static bool palette_changed = false; switch (messg) { case WM_PAINT: if (hdc[0] == 0) { hdc[0] = BeginPaint(hWnd, &ps); SelectPalette(hdc[0], hPalette, FALSE); RealizePalette(hdc[0]); hdc[1] = CreateCompatibleDC(hdc[0]); SelectPalette(hdc[1], hPalette, FALSE); hdc[2] = CreateCompatibleDC(hdc[0]); SelectPalette(hdc[2], hPalette, FALSE); hdc[3] = CreateCompatibleDC(hdc[0]); SelectPalette(hdc[3], hPalette, FALSE); screen_width = GetDeviceCaps(hdc[0], HORZRES); screen_height = GetDeviceCaps(hdc[0], VERTRES); hBitmap[active_page] = CreateCompatibleBitmap(hdc[0], screen_width, screen_height); SelectObject(hdc[1], hBitmap[active_page]); SetTextColor(hdc[0], PALETTEINDEX(text_color+BG)); SetTextColor(hdc[1], PALETTEINDEX(text_color+BG)); SetBkColor(hdc[0], PALETTEINDEX(BG)); SetBkColor(hdc[1], PALETTEINDEX(BG)); SelectObject(hdc[0], hBrush[fill_settings.pattern]); SelectObject(hdc[1], hBrush[fill_settings.pattern]); RECT scr; scr.left = -view_settings.left; scr.top = -view_settings.top; scr.right = screen_width-view_settings.left-1; scr.bottom = screen_height-view_settings.top-1; FillRect(hdc[1], &scr, hBackgroundBrush); } if (hRgn != NULL) { SelectClipRgn(hdc[0], NULL); } if (visual_page != active_page) { SelectObject(hdc[1], hBitmap[visual_page]); } BitBlt(hdc[0], -view_settings.left, -view_settings.top, window_width, window_height, hdc[1], -view_settings.left, -view_settings.top, SRCCOPY); if (hRgn != NULL) { SelectClipRgn(hdc[0], hRgn); } if (visual_page != active_page) { SelectObject(hdc[1], hBitmap[active_page]); } ValidateRect(hWnd, NULL); break; case WM_SETFOCUS: if (palette_changed) { HPALETTE new_palette = CreatePalette(pPalette); SelectPalette(hdc[0], new_palette, FALSE); RealizePalette(hdc[0]); SelectPalette(hdc[1], new_palette, FALSE); SelectPalette(hdc[2], new_palette, FALSE); SelectPalette(hdc[3], new_palette, FALSE); DeleteObject(hPalette); hPalette = new_palette; palette_changed = false; } break; case WM_PALETTECHANGED: RealizePalette(hdc[0]); UpdateColors(hdc[0]); palette_changed = true; break; case WM_DESTROY: EndPaint(hWnd, &ps); hdc[0] = 0; DeleteObject(hdc[1]); DeleteObject(hdc[2]); DeleteObject(hdc[3]); if (hPutimageBitmap) { DeleteObject(hPutimageBitmap); hPutimageBitmap = NULL; } for (i = 0; i < MAX_PAGES; i++) { if (hBitmap[i] != NULL) { DeleteObject(hBitmap[i]); hBitmap[i] = 0; } } DeleteObject(hPalette); hPalette = 0; PostQuitMessage(0); break; case WM_SIZE: window_width = LOWORD(lParam); window_height = HIWORD(lParam); break; case WM_TIMER: KillTimer(hWnd, TIMER_ID); timeout_expired = true; break; case WM_CHAR: kbd_queue.put((TCHAR) wParam); break; default: return DefWindowProc(hWnd, messg, wParam, lParam); } return 0; } void closegraph() { if (hWnd != NULL) { DestroyWindow(hWnd); hWnd = NULL; while(handle_input(true)); } } static void detect_mode(int* gd, int* gm) { switch (*gd) { case CGA: window_height = 200; switch (*gm) { case CGAC0: case CGAC1: case CGAC2: case CGAC3: window_width = 320; break; case CGAHI: window_width = 640; break; default: window_width = 320; break; } break; case MCGA: window_height = 200; switch (*gm) { case MCGAC0: case MCGAC1: case MCGAC2: case MCGAC3: window_width = 320; break; case MCGAMED: window_width = 640; break; case MCGAHI: window_width = 640; window_height = 480; break; default: window_width = 320; break; } break; case EGA: window_width = 640; switch (*gm) { case EGALO: window_height = 200; break; case EGAHI: window_height = 350; break; default: window_height = 350; break; } break; case EGA64: window_width = 640; switch (*gm) { case EGA64LO: window_height = 200; break; case EGA64HI: window_height = 350; break; default: window_height = 350; break; } break; case EGAMONO: window_width = 640; window_height = 350; break; case HERCMONO: window_width = 720; window_height = 348; break; case ATT400: window_height = 200; switch (*gm) { case ATT400C0: case ATT400C1: case ATT400C2: case ATT400C3: window_width = 320; break; case ATT400MED: window_width = 640; break; case ATT400HI: window_width = 640; window_height = 400; break; default: window_width = 320; break; } break; default: case DETECT: *gd = VGA; *gm = bgiemu_default_mode; case VGA: window_width = 640; switch (*gm) { case VGALO: window_height = 200; break; case VGAMED: window_height = 350; break; case VGAHI: window_height = 480; break; default: window_height = 480; break; } break; case PC3270: window_width = 720; window_height = 350; break; case IBM8514: switch (*gm) { case IBM8514LO: window_width = 640; window_height = 480; break; case IBM8514HI: window_width = 1024; window_height = 768; break; default: window_width = 1024; window_height = 768; break; } break; } } static void set_defaults() { color = text_color = WHITE; bkcolor = 0; line_settings.thickness = 1; line_settings.linestyle = SOLID_LINE; line_settings.upattern = ~0; fill_settings.pattern = SOLID_FILL; fill_settings.color = WHITE; write_mode = COPY_PUT; text_settings.direction = HORIZ_DIR; text_settings.font = DEFAULT_FONT; text_settings.charsize = 1; text_settings.horiz = LEFT_TEXT; text_settings.vert = TOP_TEXT; text_align_mode = ALIGN_NOT_SET; active_page = visual_page = 0; view_settings.left = 0; view_settings.top = 0; view_settings.right = window_width-1; view_settings.bottom = window_height-1; aspect_ratio_x = aspect_ratio_y = 10000; } void initgraph(int* device, int* mode, char const* /*pathtodriver*/) { int index; static WNDCLASS wcApp; gdi_error_code = grOk; if (wcApp.lpszClassName == NULL) { wcApp.lpszClassName = "BGIlibrary"; wcApp.hInstance = 0; wcApp.lpfnWndProc = WndProc; wcApp.hCursor = LoadCursor(NULL, IDC_ARROW); wcApp.hIcon = 0; wcApp.lpszMenuName = 0; wcApp.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wcApp.style = CS_SAVEBITS; wcApp.cbClsExtra = 0; wcApp.cbWndExtra = 0; if (!RegisterClass(&wcApp)) { gdi_error_code = GetLastError(); return; } pPalette = (NPLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*PALETTE_SIZE); pPalette->palVersion = 0x300; pPalette->palNumEntries = PALETTE_SIZE; memset(pPalette->palPalEntry, 0, sizeof(PALETTEENTRY)*PALETTE_SIZE); for (index = 0; index < BG; index++) { pPalette->palPalEntry[index].peFlags = PC_EXPLICIT; pPalette->palPalEntry[index].peRed = index; pPalette->palPalEntry[PALETTE_SIZE-BG+index].peFlags = PC_EXPLICIT; pPalette->palPalEntry[PALETTE_SIZE-BG+index].peRed = PALETTE_SIZE-BG+index; } hBackgroundBrush = CreateSolidBrush(PALETTEINDEX(BG)); hBrush[EMPTY_FILL] = (HBRUSH)GetStockObject(NULL_BRUSH); hBrush[SOLID_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, SolidBrushBitmap)); hBrush[LINE_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, LineBrushBitmap)); hBrush[LTSLASH_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, LtslashBrushBitmap)); hBrush[SLASH_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, SlashBrushBitmap)); hBrush[BKSLASH_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, BkslashBrushBitmap)); hBrush[LTBKSLASH_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, LtbkslashBrushBitmap)); hBrush[HATCH_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, HatchBrushBitmap)); hBrush[XHATCH_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, XhatchBrushBitmap)); hBrush[INTERLEAVE_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, InterleaveBrushBitmap)); hBrush[WIDE_DOT_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, WidedotBrushBitmap)); hBrush[CLOSE_DOT_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, ClosedotBrushBitmap)); hBrush[USER_FILL] = CreatePatternBrush(CreateBitmap(8, 8, 1, 1, SolidBrushBitmap)); } memcpy(BGIpalette, BGIcolor, sizeof BGIpalette); current_palette.size = MAXCOLORS+1; for (index = 10; index <= MAXCOLORS; index++) { pPalette->palPalEntry[index] = BGIcolor[0]; } for (index = 0; index <= MAXCOLORS; index++) { current_palette.colors[index] = index; pPalette->palPalEntry[index+BG] = BGIcolor[index]; } hPalette = CreatePalette(pPalette); detect_mode(device, mode); set_defaults(); hWnd = CreateWindow("BGIlibrary", "Windows BGI", WS_OVERLAPPEDWINDOW, 0, 0, window_width+BORDER_WIDTH, window_height+BORDER_HEIGHT, (HWND)NULL, (HMENU)NULL, 0, NULL); if (hWnd == NULL) { gdi_error_code = GetLastError(); return; } ShowWindow(hWnd, *mode == VGAMAX ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); UpdateWindow(hWnd); } void graphdefaults() { set_defaults(); for (int i = 0; i <= MAXCOLORS; i++) { current_palette.colors[i] = i; BGIpalette[i] = BGIcolor[i]; } SetPaletteEntries(hPalette, BG, MAXCOLORS+1, BGIpalette); RealizePalette(hdc[0]); SetTextColor(hdc[0], PALETTEINDEX(text_color+BG)); SetTextColor(hdc[1], PALETTEINDEX(text_color+BG)); SetBkColor(hdc[0], PALETTEINDEX(BG)); SetBkColor(hdc[1], PALETTEINDEX(BG)); SelectClipRgn(hdc[0], NULL); SelectClipRgn(hdc[1], NULL); SetViewportOrgEx(hdc[0], 0, 0, NULL); SetViewportOrgEx(hdc[1], 0, 0, NULL); SelectObject(hdc[0], hBrush[fill_settings.pattern]); SelectObject(hdc[1], hBrush[fill_settings.pattern]); moveto(0,0); } void restorecrtmode() {}