ClassiCube/src/Window_MSDOS.c
2024-10-01 21:04:20 +10:00

308 lines
8.7 KiB
C

#include "Core.h"
#if defined CC_BUILD_MSDOS
#include "_WindowBase.h"
#include "String.h"
#include "Funcs.h"
#include "Bitmap.h"
#include "Options.h"
#include "Errors.h"
#include <dpmi.h>
#include <sys/nearptr.h>
#include <pc.h>
#include <bios.h>
#define INT_VGA 0x10
#define VGA_CMD_SETMODE 0x0000
#define VGA_MODE_320x200_8 0x13
#define INT_MOUSE 0x33
#define MOUSE_CMD_RESET 0x0000
#define MOUSE_CMD_SHOW 0x0001
#define MOUSE_CMD_HIDE 0x0002
#define MOUSE_CMD_POLL 0x0003
/*########################################################################################################################*
*------------------------------------------------------Mouse support------------------------------------------------------*
*#########################################################################################################################*/
static cc_bool mouseSupported;
static void Mouse_Init(void) {
__dpmi_regs regs;
regs.x.ax = MOUSE_CMD_RESET;
__dpmi_int(INT_MOUSE, &regs);
if (regs.x.ax == 0) { mouseSupported = false; return; }
mouseSupported = true;
Cursor_DoSetVisible(true);
}
static void Mouse_Poll(void) {
if (!mouseSupported) return;
__dpmi_regs regs;
regs.x.ax = MOUSE_CMD_POLL;
__dpmi_int(INT_MOUSE, &regs);
int b = regs.x.bx;
int x = regs.x.cx;
int y = regs.x.dx;
Input_SetNonRepeatable(CCMOUSE_L, b & 0x01);
Input_SetNonRepeatable(CCMOUSE_R, b & 0x02);
Input_SetNonRepeatable(CCMOUSE_M, b & 0x04);
Pointer_SetPosition(0, x, y);
}
static void Cursor_GetRawPos(int* x, int* y) {
*x = 0;
*y = 0;
if (!mouseSupported) return;
__dpmi_regs regs;
regs.x.ax = MOUSE_CMD_POLL;
__dpmi_int(INT_MOUSE, &regs);
*x = regs.x.cx;
*y = regs.x.dx;
}
void Cursor_SetPosition(int x, int y) {
if (!mouseSupported) return;
}
static void Cursor_DoSetVisible(cc_bool visible) {
if (!mouseSupported) return;
__dpmi_regs regs;
regs.x.ax = visible ? MOUSE_CMD_SHOW : MOUSE_CMD_HIDE;
__dpmi_int(INT_MOUSE, &regs);
}
/*########################################################################################################################*
*----------------------------------------------------Keyboard support-----------------------------------------------------*
*#########################################################################################################################*/
// TODO use proper keyboard interrupts
static float event_time;
static float press_start[256];
// TODO missing numpad codes
static const cc_uint8 key_map[] = {
/* 0x00 */ 0, CCKEY_ESCAPE, '1', '2', '3', '4', '5', '6',
/* 0x08 */ '7', '8', '9', '0', CCKEY_MINUS, CCKEY_EQUALS, CCKEY_BACKSPACE, CCKEY_TAB,
/* 0x10 */ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
/* 0x18 */ 'O', 'P', CCKEY_LBRACKET, CCKEY_RBRACKET, CCKEY_ENTER, 0, 'A', 'S',
/* 0x20 */ 'D', 'F', 'G', 'H', 'J', 'K', 'L', CCKEY_SEMICOLON,
/* 0x28 */ CCKEY_QUOTE, CCKEY_TILDE, 0, CCKEY_BACKSLASH, 'Z', 'X', 'C', 'V',
/* 0x30 */ 'B', 'N', 'M', CCKEY_COMMA, CCKEY_PERIOD, CCKEY_SLASH, 0, 0,
/* 0x38 */ 0, CCKEY_SPACE, 0, CCKEY_F1, CCKEY_F2, CCKEY_F3, CCKEY_F4, CCKEY_F5,
/* 0x40 */ CCKEY_F6, CCKEY_F7, CCKEY_F8, CCKEY_F9, CCKEY_F10, 0, 0, CCKEY_HOME,
/* 0x48 */ CCKEY_UP, CCKEY_PAGEUP, 0, CCKEY_LEFT, 0, CCKEY_RIGHT, 0, CCKEY_END,
/* 0x50 */ CCKEY_DOWN, CCKEY_PAGEDOWN, 0, 0, 0, 0, 0, 0,
/* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x68 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x80 */ 0, 0, 0, 0, 0, CCKEY_F11, CCKEY_F12, 0,
};
static int MapKey(unsigned key) { return key < Array_Elems(key_map) ? key_map[key] : 0; }
static void Keyboard_UpdateState(float delta) {
event_time += delta;
// Auto release keys after a while
for (int i = 0; i < 256; i++)
{
if (press_start[i] && (event_time - press_start[i]) > 1.0f) {
Input_SetReleased(MapKey(i));
press_start[i] = 0.0f;
}
}
}
static void Keyboard_PollInput(void) {
if (_bios_keybrd(_NKEYBRD_READY) == 0) return;
unsigned raw = _bios_keybrd(_NKEYBRD_READ);
// Lower 8 bits contain ascii code
unsigned code = raw & 0xFF;
if (code >= 32 && code < 127) {
Event_RaiseInt(&InputEvents.Press, code);
}
// Higher 8 bits contain raw code
raw = (raw >> 8) & 0xFF;
int key = MapKey(raw);
if (!key) return;
Input_SetPressed(key);
press_start[raw] = event_time;
}
static void Keyboard_UpdateModifiers(void) {
unsigned mods = _bios_keybrd(_KEYBRD_SHIFTSTATUS);
Input_SetNonRepeatable(CCKEY_RSHIFT, mods & 0x02);
Input_SetNonRepeatable(CCKEY_LCTRL, mods & 0x04);
Input_SetNonRepeatable(CCKEY_LALT, mods & 0x08);
Input_SetNonRepeatable(CCKEY_SCROLLLOCK, mods & 0x10);
Input_SetNonRepeatable(CCKEY_NUMLOCK, mods & 0x20);
Input_SetNonRepeatable(CCKEY_CAPSLOCK, mods & 0x40);
Input_SetNonRepeatable(CCKEY_INSERT, mods & 0x80);
}
/*########################################################################################################################*
*--------------------------------------------------Public implementation--------------------------------------------------*
*#########################################################################################################################*/
void Window_PreInit(void) { }
void Window_Init(void) {
DisplayInfo.Width = 320;
DisplayInfo.Height = 200;
DisplayInfo.ScaleX = 0.5f;
DisplayInfo.ScaleY = 0.5f;
// Change VGA mode to 0x13 (320x200x8bpp)
__dpmi_regs regs;
regs.x.ax = VGA_CMD_SETMODE | VGA_MODE_320x200_8;
__dpmi_int(INT_VGA, &regs);
// Change VGA colour palette (NOTE: only lower 6 bits are used)
// Fake a linear RGB palette
outportb(0x3c8, 0);
for (int i = 0; i < 256; i++) {
outportb(0x3c9, ((i >> 0) & 0x03) << 4);
outportb(0x3c9, ((i >> 2) & 0x07) << 3);
outportb(0x3c9, ((i >> 5) & 0x07) << 3);
}
Mouse_Init();
}
void Window_Free(void) { }
static void DoCreateWindow(int width, int height) {
Window_Main.Width = 320;
Window_Main.Height = 200;
Window_Main.Focused = true;
Window_Main.Exists = true;
Window_Main.UIScaleX = DEFAULT_UI_SCALE_X;
Window_Main.UIScaleY = DEFAULT_UI_SCALE_Y;
}
void Window_Create2D(int width, int height) { DoCreateWindow(width, height); }
void Window_Create3D(int width, int height) { DoCreateWindow(width, height); }
void Window_Destroy(void) { }
void Window_SetTitle(const cc_string* title) { }
void Clipboard_GetText(cc_string* value) { }
void Clipboard_SetText(const cc_string* value) { }
int Window_GetWindowState(void) {
return WINDOW_STATE_NORMAL;
}
cc_result Window_EnterFullscreen(void) {
return 0;
}
cc_result Window_ExitFullscreen(void) {
return 0;
}
int Window_IsObscured(void) { return 0; }
void Window_Show(void) { }
void Window_SetSize(int width, int height) { }
void Window_RequestClose(void) {
Event_RaiseVoid(&WindowEvents.Closing);
}
void Window_ProcessEvents(float delta) {
Mouse_Poll();
Keyboard_PollInput();
Keyboard_UpdateModifiers();
Keyboard_UpdateState(delta);
}
void Gamepads_Init(void) {
}
void Gamepads_Process(float delta) { }
static void ShowDialogCore(const char* title, const char* msg) {
Platform_LogConst(title);
Platform_LogConst(msg);
}
cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
return ERR_NOT_SUPPORTED;
}
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
return ERR_NOT_SUPPORTED;
}
void Window_AllocFramebuffer(struct Bitmap* bmp, int width, int height) {
bmp->scan0 = (BitmapCol*)Mem_Alloc(width * height, BITMAPCOLOR_SIZE, "window pixels");
bmp->width = width;
bmp->height = height;
}
void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) {
char *screen;
if (__djgpp_nearptr_enable() == 0) return;
screen = (char*)0xa0000 + __djgpp_conventional_base;
for (int y = r.y; y < r.y + r.height; ++y)
{
BitmapCol* row = Bitmap_GetRow(bmp, y);
for (int x = r.x; x < r.x + r.width; ++x)
{
// TODO optimise
BitmapCol col = row[x];
cc_uint8 R = BitmapCol_R(col);
cc_uint8 G = BitmapCol_G(col);
cc_uint8 B = BitmapCol_B(col);
screen[y*320+x] = (R >> 6) | ((G >> 5) << 2) | ((B >> 5) << 5);
}
}
__djgpp_nearptr_disable();
}
void Window_FreeFramebuffer(struct Bitmap* bmp) {
Mem_Free(bmp->scan0);
}
void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { }
void OnscreenKeyboard_SetText(const cc_string* text) { }
void OnscreenKeyboard_Close(void) { }
void Window_EnableRawMouse(void) {
DefaultEnableRawMouse();
}
void Window_UpdateRawMouse(void) {
DefaultUpdateRawMouse();
}
void Window_DisableRawMouse(void) {
DefaultDisableRawMouse();
}
#endif