477 lines
8.9 KiB
C++
477 lines
8.9 KiB
C++
/*****************************************************************
|
|
* INCLUDE DIRECTIVES *
|
|
*****************************************************************/
|
|
#include<string.h>
|
|
#include<conio.h>
|
|
#include<stdlib.h>
|
|
#include<stdio.h>
|
|
#include<fstream.h>
|
|
|
|
/*****************************************************************
|
|
* 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<cSizeY; yy++)
|
|
for (int xx=0; xx<cSizeX; xx++)
|
|
{
|
|
file>>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;
|
|
}
|