/***************************************************************** * INCLUDE DIRECTIVES * *****************************************************************/ #include #include #include #include #include /***************************************************************** * UNIVERSAL DATA TYPES, CONSTANTS * *****************************************************************/ typedef unsigned char byte; typedef struct { int X, Y; } Point; #define DEBUG 1 #define LOG(x) printf(x); /***************************************************************** * VIDEO DRIVER * *****************************************************************/ // Used variables byte far* VGAMem = (byte far *)0xA0000000L; byte* Buffer; // Used by cursor. Need to be initialized here int SaveX, SaveY; // Change video mode routine void VideoMode(byte mode) { asm { mov ah, 0 mov al, mode int 0x10 } } // Initialize graphic mode 0x13, use duble buffering if possible void InitGraph() { Buffer = (byte*)malloc(320 * 200); if (Buffer) memset(Buffer, 0, 320*200); #if DEBUG == 1 if (!Buffer) LOG("Error: Not enough memory. Double buffering disabled."); #endif VideoMode(0x13); SaveX = SaveY = 400; } // Go back to normal text mode 0x03 void ExitGraph() { free(Buffer); VideoMode(0x03); } // Put a pixel in specified position. Does not put it on the screen if double buffering. void PutPixel(int x, int y, int c) { if (y >= 200 || x >= 320) return; if (Buffer) Buffer[y*320 + x] = c; else VGAMem[y*320 + x] = c; } // Get a pixel from screen/double buffer byte GetPixel(int x, int y) { return (Buffer) ? Buffer[320*y + x] : VGAMem[320*y+x]; } // Put double buffer on the screen. Should be called after e.g. displaying something new. void Update() { if (Buffer) memcpy(VGAMem, Buffer, 320*200); } /***************************************************************** * MOUSE DRIVER * *****************************************************************/ // Defines cursor size and array #define cX 7 #define cY 7 byte Cursor[cY][cX] = { {1, 0, 0, 1, 1, 1, 1}, {1, 0, 0, 1, 0, 0, 0}, {1, 0, 0, 1, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1}, {0, 0, 0, 1, 0, 0, 1}, {0, 0, 0, 1, 0, 0, 1}, {1, 1, 1, 1, 0, 0, 1}}; // Save what is under the cursor byte Save[cY][cX]; void SaveUnder(int x, int y) { for (int i = 0; i < cX; i++) for (int j = 0; j < cY; j++) Save[i][j] = GetPixel(i+x, j+y); SaveX = x; SaveY = y; } // Restore what was under the cursor void RestoreUnder () { for (int i = 0; i < cX; i++) for (int j = 0; j < cY; j++) PutPixel(i+SaveX, j+SaveY, Save[j][i]); } // Display the cursor void PutCursor(int x, int y, byte c) { // restore old RestoreUnder(); SaveUnder(x, y); for (int i = 0; i < cX; i++) for (int j = 0; j < cY; j++) { Save[j][i] = GetPixel(i+x, j+y); if (Cursor[j][i] == 1) PutPixel(i+x, j+y, Cursor[j][i] * c); if (Cursor[j][i] == 2) PutPixel(i+x, j+y, 256-(Cursor[j][i] * c)); } } // Check if mouse cursor is in specified area unsigned char MouseIsInArea (int MouseX, int MouseY, int left, int top, int right, int bottom) { if (MouseX >= left && MouseX <= right && MouseY >= top && MouseY <= bottom) return 1; return 0; } // Bit masks for mouse buttons const byte MouseLeftB = 1, MouseRightB = 2, MouseMiddleB = 4; // Initialize mouse driver int MouseInit(int *NumberOfButtons) { int r; int tmp; asm { mov ax, 0 int 0x33 mov tmp, ax mov r, bx } *NumberOfButtons = tmp; return r; } // Get the status of the mouse (buttons, etc) byte MouseGetStatus() { byte re; asm { mov ax, 3 int 0x33 mov re, bl } return re; } // Get movement void MouseGetDirection (int *x, int *y) { int tx, ty; asm { mov ax, 0x0B int 0x33 mov tx, cx mov ty, dx } *x = tx; *y = ty; } /***************************************************************** * FONT MANAGER * *****************************************************************/ class Font { char Path[256]; ifstream file; public: byte Error; Font(char* c); Font(); ~Font() { file.close(); } Point PutChar(int x, int y, char c); void PutString(int x, int y, char* str); void OpenNew(char* c); }; Font::Font(char* c) { int len = strlen(c); for (int i = 0; i < len && i<256; i++) Path[i] = c[i]; file.open(c); if (!file) Error = 1; else Error = 0; } Font::Font() { Path[0] = 0; } void Font::OpenNew(char* c) { int len = strlen(c); for (int i = 0; i < len && i<256; i++) Path[i] = c[i]; file.open(c); if (!file) Error = 1; else Error = 0; } Point Font::PutChar(int x, int y, char c) { Point ret; int cSizeX, cSizeY; if (Error) return ret; int tmp = 0; file.seekg(0, ios::beg); for (int i = 0; i < c; i++) { file>>cSizeX>>cSizeY; for (int j = 0; j < cSizeX * cSizeY; j++) file>>tmp; } file>>cSizeX>>cSizeY; for (int yy=0; yy>tmp; if (tmp) PutPixel(xx+x, yy+y, c); } ret.X = cSizeX; ret.Y = cSizeY; return ret; } void Font::PutString(int x, int y, char* str) { if (Error) return; Point temp; int sum = 0; // Use a default kerning value of 1 pixels. int len = strlen(str); for (int i=0; i < len; i++) { temp = PutChar(x+sum, y, str[i]); sum += temp.X+1; } } /***************************************************************** * WINDOW MANAGER * *****************************************************************/ class Window { byte Visible; char Title[256]; Font Fnt; public: Point Pos, Size; Window(char* s); Window(); Window(Point pos, Point siz, char* s); void Show(); void Hide(); void DrawPixel(int x, int y, int c) { if (x < this->Size.X && y < this->Size.Y) PutPixel (x+this->Pos.X, y+this->Pos.Y, c); } void Update(); void MouseAction(int X, int Y, byte Buttons) { if (Buttons & MouseLeftB) DrawPixel(5,5, 150); else DrawPixel(5, 5, 0); } }; Window::Window(char* s) { memcpy(Title, s, 256); Visible = 0; Size.X = 0; Size.Y = 0; Pos.X = 0; Pos.Y = 0; Fnt.OpenNew("font.txt"); } Window::Window() { Visible = 0; Size.X = 0; Size.Y = 0; Pos.X = 0; Pos.Y = 0; Title[0] = 0; Fnt.OpenNew("font.txt"); } Window::Window(Point pos, Point siz, char* s) { Visible = 0; Size = siz; Pos = pos; memcpy(Title, s, 256); } void Window::Show() { Visible = 1; for (int i = Pos.X; i < Size.X + Pos.X; i++) { for (int j = Pos.Y+10; j < Size.Y + Pos.Y; j++) PutPixel(i, j, 7); for (j = Pos.Y; j < Pos.Y+10; j++) PutPixel(i, j, 12); } Fnt.PutString(Pos.X+3, Pos.Y+2, Title); } void Window::Hide() { Visible = 0; for (int i = Pos.X; i < Size.X + Pos.X; i++) for (int j = Pos.Y; j < Size.Y + Pos.Y; j++) PutPixel(i, j, 0); } /***************************************************************** * MAIN FUNCTION * *****************************************************************/ int main() { int a; InitGraph(); MouseInit(&a); Window alpha("AaBbCcXyZhSgGZz@,HEL"); alpha.Pos.X = 320/2; alpha.Pos.Y = 200/2; alpha.Size.X = 140; alpha.Size.Y = 80; int MouseX = 320/2, MouseY = 200/2; int dx, dy, oldX, oldY; int Col = 15; for (;;) { if (oldX != MouseX || oldY != MouseY) { memset (Buffer, 0, 320*200); alpha.Show(); PutCursor(MouseX, MouseY, Col); Update(); } oldX = MouseX; oldY = MouseY; MouseGetDirection(&dx, &dy); MouseX+=dx; MouseY+=dy; if (MouseX > 320) MouseX = 320; if (MouseY > 200) MouseY = 200; if (MouseX < 0) MouseX = 0; if (MouseY < 0) MouseY = 0; int ok=0; if (MouseGetStatus() & MouseLeftB) { alpha.MouseAction(MouseX, MouseY, MouseGetStatus()); // Check if bottom right corner => ok=2 if (MouseIsInArea (oldX, oldY, alpha.Pos.X+alpha.Size.X-5, alpha.Pos.Y + alpha.Size.Y-5, alpha.Pos.X+alpha.Size.X, alpha.Pos.Y + alpha.Size.Y)) ok = 2; else if (MouseIsInArea (oldX, oldY, alpha.Pos.X, alpha.Pos.Y, alpha.Pos.X+alpha.Size.X, alpha.Pos.Y + alpha.Size.Y)) ok = 1; if (ok==1) { alpha.Pos.X += dx; alpha.Pos.Y += dy; if (alpha.Pos.X < 0) alpha.Pos.X = 0; if (alpha.Pos.Y < 0) alpha.Pos.Y = 0; if (alpha.Pos.X > 320 - alpha.Size.X) alpha.Pos.X = 320-alpha.Size.X; if (alpha.Pos.Y > 200 - alpha.Size.Y) alpha.Pos.Y = 200-alpha.Size.Y; } else if (ok==2) { alpha.Size.X += dx; alpha.Size.Y += dy; if (alpha.Size.X > 300) alpha.Size.X = 300; if (alpha.Size.X < 40) alpha.Size.X = 40; if (alpha.Size.Y > 150) alpha.Size.Y = 150; if (alpha.Size.Y < 30) alpha.Size.Y = 30; } } if (!(MouseGetStatus() & MouseLeftB)) ok=0; if(kbhit()) break; } ExitGraph(); return 0; }