📄 winbgi.cpp
字号:
//
// winbgi.cpp -- One of the files required to run BGI graphics programs
//
// You don't need to edit this file, or print it out.
#include "graphics.h"
//namespace bgi {
#include <windows.h>
#include <stddef.h>
#include <stdio.h>
#include <math.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 64
#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;
//Mouse info (Added 1-Oct-2000, Matthew Weathers)
static bool bMouseUp = false;
static bool bMouseDown = false;
static int iCurrentMouseX = 0;
static int iCurrentMouseY = 0;
static int iClickedMouseX = 0;
static int iClickedMouseY = 0;
static int iWhichMouseButton = LEFT_BUTTON;
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[64];
};
static BGIbitmapinfo bminfo = {
{sizeof(BITMAPINFOHEADER), 0, 0, 1, 4, BI_RGB}
};
//static int* image_bits; //Bill 2006
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[64] = {
{ 0, 0, 0, FLAGS }, // 0
{ 0, 0, 255, FLAGS }, // 1
{ 0, 255, 0, FLAGS }, // 2
{ 0, 255, 255, FLAGS }, // 3
{ 255, 0, 0, FLAGS }, // 4
{ 255, 0, 255, FLAGS }, // 5
{ 165, 42, 42, FLAGS }, // 6
{ 211, 211, 211, FLAGS }, // 7
{ 47, 79, 79, FLAGS }, // 8
{ 173, 216, 230, FLAGS }, // 9
{ 32, 178, 170, FLAGS }, // 10
{ 224, 255, 255, FLAGS }, // 11
{ 240, 128, 128, FLAGS }, // 12
{ 219, 112, 147, FLAGS }, // 13
{ 255, 255, 0, FLAGS }, // 14
{ 255, 255, 255, FLAGS }, // 15
{ 0xF0, 0xF8, 0xFF, FLAGS }, // 16
{ 0xFA, 0xEB, 0xD7, FLAGS }, // 17
{ 0x22, 0x85, 0xFF, FLAGS }, // 18
{ 0x7F, 0xFF, 0xD4, FLAGS }, // 19
{ 0xF0, 0xFF, 0xFF, FLAGS }, // 20
{ 0xF5, 0xF5, 0xDC, FLAGS }, // 21
{ 0xFF, 0xE4, 0xC4, FLAGS }, // 22
{ 0xFF, 0x7B, 0xCD, FLAGS }, // 23
{ 0x00, 0x00, 0xFF, FLAGS }, // 24
{ 0x8A, 0x2B, 0xE2, FLAGS }, // 25
{ 0xA5, 0x2A, 0x2A, FLAGS }, // 26
{ 0xDE, 0xB8, 0x87, FLAGS }, // 27
{ 0x5F, 0x9E, 0xA0, FLAGS }, // 28
{ 0x7F, 0xFF, 0x00, FLAGS }, // 29
{ 0xD2, 0x50, 0x1E, FLAGS }, // 30
{ 0xFF, 0x7F, 0x50, FLAGS }, // 31
{ 0x64, 0x95, 0xED, FLAGS }, // 32
{ 0xFF, 0xF8, 0xDC, FLAGS }, // 33
{ 0xDC, 0x14, 0x3C, FLAGS }, // 34
{ 0x68, 0xCF, 0xDF, FLAGS }, // 35
{ 0x00, 0x00, 0x8B, FLAGS }, // 36
{ 0x00, 0x8B, 0x8B, FLAGS }, // 37
{ 0xB8, 0x86, 0x0B, FLAGS }, // 38
{ 0xA9, 0xA9, 0xA9, FLAGS }, // 39
{ 0x00, 0x64, 0x00, FLAGS }, // 40
{ 0xBD, 0xB7, 0x6B, FLAGS }, // 41
{ 0x8B, 0x00, 0x8B, FLAGS }, // 42
{ 0x55, 0x6B, 0x2F, FLAGS }, // 43
{ 0xFF, 0x8C, 0x00, FLAGS }, // 44
{ 0xB9, 0x82, 0xFC, FLAGS }, // 45
{ 0x8B, 0x00, 0x00, FLAGS }, // 46
{ 0xE9, 0x96, 0x7A, FLAGS }, // 47
{ 0x8F, 0xBC, 0x8F, FLAGS }, // 48
{ 0x48, 0x3D, 0x8B, FLAGS }, // 49
{ 0x2F, 0x4F, 0x4F, FLAGS }, // 50
{ 0x00, 0xCE, 0xD1, FLAGS }, // 51
{ 0x94, 0x00, 0xD3, FLAGS }, // 52
{ 0xFF, 0x14, 0x93, FLAGS }, // 53
{ 0x00, 0xBF, 0xFF, FLAGS }, // 54
{ 0x69, 0x69, 0x69, FLAGS }, // 55
{ 0x1E, 0x90, 0xFF, FLAGS }, // 56
{ 0xB2, 0x22, 0x22, FLAGS }, // 57
{ 0xFF, 0xFA, 0xF0, FLAGS }, // 58
{ 0x22, 0x8B, 0x22, FLAGS }, // 59
{ 0xFF, 0x00, 0xFF, FLAGS }, // 60
{ 0xDC, 0xDC, 0xDC, FLAGS }, // 61
{ 0xF8, 0xF8, 0xBF, FLAGS }, // 62
{ 0xFF, 0xD7, 0x00, FLAGS }, // 63
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -