#include <windows.h>
#include <stddef.h>
#include <stdio.h>
#include <math.h>
#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