luxos/VIDEO.CPP
2021-09-14 18:46:50 +03:00

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;
}