fallout2-ce/src/core.cc

1826 lines
42 KiB
C++
Raw Normal View History

2022-05-19 01:51:26 -07:00
#include "core.h"
2022-09-15 02:38:23 -07:00
#include <limits.h>
#include <string.h>
#include <SDL.h>
2022-07-12 02:09:53 -07:00
#include "audio_engine.h"
2022-05-19 01:51:26 -07:00
#include "color.h"
#include "config.h"
2022-05-19 01:51:26 -07:00
#include "dinput.h"
#include "draw.h"
#include "interface.h"
2022-10-03 06:42:34 -07:00
#include "kb.h"
2022-05-19 01:51:26 -07:00
#include "memory.h"
#include "mmx.h"
2022-10-03 02:41:33 -07:00
#include "mouse.h"
2022-05-19 01:51:26 -07:00
#include "text_font.h"
2022-10-02 23:37:05 -07:00
#include "vcr.h"
2022-05-28 11:46:58 -07:00
#include "win32.h"
2022-05-19 01:51:26 -07:00
#include "window_manager.h"
#include "window_manager_private.h"
2022-09-23 05:43:44 -07:00
namespace fallout {
2022-08-16 04:24:57 -07:00
static void idleImpl();
2022-08-16 04:14:53 -07:00
// 0x51E234
IdleFunc* _idle_func = NULL;
2022-05-19 01:51:26 -07:00
2022-08-16 04:14:53 -07:00
// 0x51E238
FocusFunc* _focus_func = NULL;
2022-05-19 01:51:26 -07:00
// 0x51E23C
int gKeyboardKeyRepeatRate = 80;
// 0x51E240
int gKeyboardKeyRepeatDelay = 500;
// NOTE: This value is never set, so it's impossible to understand it's
// meaning.
//
// 0x51E2C4
void (*_update_palette_func)() = NULL;
// 0x51E2C8
bool gMmxEnabled = true;
// 0x51E2CC
bool gMmxProbed = false;
2022-05-23 01:44:49 -07:00
// A map of SDL_SCANCODE_* constants normalized for QWERTY keyboard.
2022-05-19 01:51:26 -07:00
//
// 0x6ABC70
2022-05-23 01:44:49 -07:00
int gNormalizedQwertyKeys[SDL_NUM_SCANCODES];
2022-05-19 01:51:26 -07:00
// Ring buffer of input events.
//
// Looks like this buffer does not support overwriting of values. Once the
// buffer is full it will not overwrite values until they are dequeued.
//
// 0x6ABD70
InputEvent gInputEventQueue[40];
// 0x6ABF50
2022-05-23 01:44:49 -07:00
STRUCT_6ABF50 _GNW95_key_time_stamps[SDL_NUM_SCANCODES];
2022-05-19 01:51:26 -07:00
// 0x6AC750
int _input_mx;
// 0x6AC754
int _input_my;
// 0x6AC75C
bool gPaused;
// 0x6AC760
int gScreenshotKeyCode;
// 0x6AC764
int _using_msec_timer;
// 0x6AC768
int gPauseKeyCode;
// 0x6AC76C
ScreenshotHandler* gScreenshotHandler;
// 0x6AC770
int gInputEventQueueReadIndex;
// 0x6AC774
unsigned char* gScreenshotBuffer;
// 0x6AC778
PauseHandler* gPauseHandler;
// 0x6AC77C
int gInputEventQueueWriteIndex;
// 0x6AC780
bool gRunLoopDisabled;
// 0x6AC784
TickerListNode* gTickerListHead;
// 0x6AC788
unsigned int gTickerLastTimestamp;
// 0x6AC7F0
unsigned short gSixteenBppPalette[256];
// screen rect
Rect _scr_size;
// 0x6ACA00
int gGreenMask;
// 0x6ACA04
int gRedMask;
// 0x6ACA08
int gBlueMask;
// 0x6ACA0C
int gBlueShift;
// 0x6ACA10
int gRedShift;
// 0x6ACA14
int gGreenShift;
// 0x6ACA18
void (*_scr_blit)(unsigned char* src, int src_pitch, int a3, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y) = _GNW95_ShowRect;
// 0x6ACA1C
void (*_zero_mem)() = NULL;
// 0x6ACA20
bool gMmxSupported;
// FIXME: This buffer was supposed to be used as temporary place to store
// current palette while switching video modes (changing resolution). However
// the original game does not have UI to change video mode. Even if it did this
// buffer it too small to hold the entire palette, which require 256 * 3 bytes.
//
// 0x6ACA24
unsigned char gLastVideoModePalette[268];
2022-05-19 04:01:17 -07:00
SDL_Window* gSdlWindow = NULL;
SDL_Surface* gSdlSurface = NULL;
2022-07-12 00:10:23 -07:00
SDL_Renderer* gSdlRenderer = NULL;
SDL_Texture* gSdlTexture = NULL;
SDL_Surface* gSdlTextureSurface = NULL;
2022-05-19 04:01:17 -07:00
2022-05-19 01:51:26 -07:00
// 0x4C8A70
int coreInit(int a1)
{
if (!directInputInit()) {
return -1;
}
if (keyboardInit() == -1) {
return -1;
}
if (mouseInit() == -1) {
return -1;
}
if (_GNW95_input_init() == -1) {
return -1;
}
buildNormalizedQwertyKeys();
_GNW95_clear_time_stamps();
_using_msec_timer = a1;
gInputEventQueueWriteIndex = 0;
gInputEventQueueReadIndex = -1;
_input_mx = -1;
_input_my = -1;
gRunLoopDisabled = 0;
gPaused = false;
gPauseKeyCode = KEY_ALT_P;
gPauseHandler = pauseHandlerDefaultImpl;
gScreenshotHandler = screenshotHandlerDefaultImpl;
gTickerListHead = NULL;
gScreenshotKeyCode = KEY_ALT_C;
2022-08-16 04:24:57 -07:00
// SFALL: Set idle function.
// CE: Prevents frying CPU when window is not focused.
inputSetIdleFunc(idleImpl);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4C8B40
void coreExit()
{
_GNW95_input_init();
mouseFree();
keyboardFree();
directInputFree();
TickerListNode* curr = gTickerListHead;
while (curr != NULL) {
TickerListNode* next = curr->next;
internal_free(curr);
curr = next;
}
}
// 0x4C8B78
int _get_input()
{
int v3;
_GNW95_process_message();
if (!gProgramIsActive) {
_GNW95_lost_focus();
}
_process_bk();
v3 = dequeueInputEvent();
if (v3 == -1 && mouseGetEvent() & 0x33) {
mouseGetPosition(&_input_mx, &_input_my);
return -2;
} else {
return _GNW_check_menu_bars(v3);
}
return -1;
}
// 0x4C8BDC
void _process_bk()
{
int v1;
tickersExecute();
if (vcrUpdate() != 3) {
2022-05-19 01:51:26 -07:00
_mouse_info();
}
v1 = _win_check_all_buttons();
if (v1 != -1) {
enqueueInputEvent(v1);
return;
}
v1 = _kb_getch();
if (v1 != -1) {
enqueueInputEvent(v1);
return;
}
}
// 0x4C8C04
void enqueueInputEvent(int a1)
{
if (a1 == -1) {
return;
}
if (a1 == gPauseKeyCode) {
pauseGame();
return;
}
if (a1 == gScreenshotKeyCode) {
takeScreenshot();
return;
}
if (gInputEventQueueWriteIndex == gInputEventQueueReadIndex) {
return;
}
InputEvent* inputEvent = &(gInputEventQueue[gInputEventQueueWriteIndex]);
inputEvent->logicalKey = a1;
mouseGetPosition(&(inputEvent->mouseX), &(inputEvent->mouseY));
gInputEventQueueWriteIndex++;
if (gInputEventQueueWriteIndex == 40) {
gInputEventQueueWriteIndex = 0;
return;
}
if (gInputEventQueueReadIndex == -1) {
gInputEventQueueReadIndex = 0;
}
}
// 0x4C8C9C
int dequeueInputEvent()
{
if (gInputEventQueueReadIndex == -1) {
return -1;
}
InputEvent* inputEvent = &(gInputEventQueue[gInputEventQueueReadIndex]);
int eventCode = inputEvent->logicalKey;
_input_mx = inputEvent->mouseX;
_input_my = inputEvent->mouseY;
gInputEventQueueReadIndex++;
if (gInputEventQueueReadIndex == 40) {
gInputEventQueueReadIndex = 0;
}
if (gInputEventQueueReadIndex == gInputEventQueueWriteIndex) {
gInputEventQueueReadIndex = -1;
gInputEventQueueWriteIndex = 0;
}
return eventCode;
}
// 0x4C8D04
void inputEventQueueReset()
{
gInputEventQueueReadIndex = -1;
gInputEventQueueWriteIndex = 0;
}
// 0x4C8D1C
void tickersExecute()
{
if (gPaused) {
return;
}
if (gRunLoopDisabled) {
return;
}
2022-05-27 23:32:36 -07:00
gTickerLastTimestamp = SDL_GetTicks();
2022-05-19 01:51:26 -07:00
TickerListNode* curr = gTickerListHead;
TickerListNode** currPtr = &(gTickerListHead);
while (curr != NULL) {
TickerListNode* next = curr->next;
if (curr->flags & 1) {
*currPtr = next;
internal_free(curr);
} else {
curr->proc();
currPtr = &(curr->next);
}
curr = next;
}
}
// 0x4C8D74
void tickersAdd(TickerProc* proc)
{
TickerListNode* curr = gTickerListHead;
while (curr != NULL) {
if (curr->proc == proc) {
if ((curr->flags & 0x01) != 0) {
curr->flags &= ~0x01;
return;
}
}
curr = curr->next;
}
2022-05-21 08:22:03 -07:00
curr = (TickerListNode*)internal_malloc(sizeof(*curr));
2022-05-19 01:51:26 -07:00
curr->flags = 0;
curr->proc = proc;
curr->next = gTickerListHead;
gTickerListHead = curr;
}
// 0x4C8DC4
void tickersRemove(TickerProc* proc)
{
TickerListNode* curr = gTickerListHead;
while (curr != NULL) {
if (curr->proc == proc) {
curr->flags |= 0x01;
return;
}
curr = curr->next;
}
}
// 0x4C8DE4
void tickersEnable()
{
gRunLoopDisabled = false;
}
// 0x4C8DF0
void tickersDisable()
{
gRunLoopDisabled = true;
}
// 0x4C8DFC
void pauseGame()
{
if (!gPaused) {
gPaused = true;
int win = gPauseHandler();
while (_get_input() != KEY_ESCAPE) {
}
gPaused = false;
windowDestroy(win);
}
}
// 0x4C8E38
int pauseHandlerDefaultImpl()
{
int windowWidth = fontGetStringWidth("Paused") + 32;
int windowHeight = 3 * fontGetLineHeight() + 16;
int win = windowCreate((rectGetWidth(&_scr_size) - windowWidth) / 2,
(rectGetHeight(&_scr_size) - windowHeight) / 2,
windowWidth,
windowHeight,
256,
WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
2022-05-19 01:51:26 -07:00
if (win == -1) {
return -1;
}
windowDrawBorder(win);
unsigned char* windowBuffer = windowGetBuffer(win);
fontDrawText(windowBuffer + 8 * windowWidth + 16,
"Paused",
windowWidth,
windowWidth,
_colorTable[31744]);
_win_register_text_button(win,
(windowWidth - fontGetStringWidth("Done") - 16) / 2,
windowHeight - 8 - fontGetLineHeight() - 6,
-1,
-1,
-1,
KEY_ESCAPE,
"Done",
0);
2022-05-19 01:51:26 -07:00
windowRefresh(win);
return win;
}
// 0x4C8F34
void pauseHandlerConfigure(int keyCode, PauseHandler* handler)
{
gPauseKeyCode = keyCode;
if (handler == NULL) {
handler = pauseHandlerDefaultImpl;
}
gPauseHandler = handler;
}
// 0x4C8F4C
void takeScreenshot()
{
int width = _scr_size.right - _scr_size.left + 1;
int height = _scr_size.bottom - _scr_size.top + 1;
2022-05-21 08:22:03 -07:00
gScreenshotBuffer = (unsigned char*)internal_malloc(width * height);
2022-05-19 01:51:26 -07:00
if (gScreenshotBuffer == NULL) {
return;
}
WINDOWDRAWINGPROC v0 = _scr_blit;
_scr_blit = screenshotBlitter;
WINDOWDRAWINGPROC v2 = _mouse_blit;
_mouse_blit = screenshotBlitter;
WindowDrawingProc2* v1 = _mouse_blit_trans;
_mouse_blit_trans = NULL;
windowRefreshAll(&_scr_size);
_mouse_blit_trans = v1;
_mouse_blit = v2;
_scr_blit = v0;
unsigned char* palette = _getSystemPalette();
gScreenshotHandler(width, height, gScreenshotBuffer, palette);
internal_free(gScreenshotBuffer);
}
// 0x4C8FF0
void screenshotBlitter(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int width, int height, int destX, int destY)
{
int destWidth = _scr_size.right - _scr_size.left + 1;
blitBufferToBuffer(src + srcPitch * srcY + srcX, width, height, srcPitch, gScreenshotBuffer + destWidth * destY + destX, destWidth);
}
// 0x4C9048
int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, unsigned char* palette)
{
char fileName[16];
FILE* stream;
int index;
unsigned int intValue;
unsigned short shortValue;
for (index = 0; index < 100000; index++) {
sprintf(fileName, "scr%.5d.bmp", index);
stream = compat_fopen(fileName, "rb");
2022-05-19 01:51:26 -07:00
if (stream == NULL) {
break;
}
fclose(stream);
}
if (index == 100000) {
return -1;
}
stream = compat_fopen(fileName, "wb");
2022-05-19 01:51:26 -07:00
if (stream == NULL) {
return -1;
}
// bfType
shortValue = 0x4D42;
fwrite(&shortValue, sizeof(shortValue), 1, stream);
// bfSize
// 14 - sizeof(BITMAPFILEHEADER)
// 40 - sizeof(BITMAPINFOHEADER)
// 1024 - sizeof(RGBQUAD) * 256
intValue = width * height + 14 + 40 + 1024;
fwrite(&intValue, sizeof(intValue), 1, stream);
// bfReserved1
shortValue = 0;
fwrite(&shortValue, sizeof(shortValue), 1, stream);
// bfReserved2
shortValue = 0;
fwrite(&shortValue, sizeof(shortValue), 1, stream);
// bfOffBits
intValue = 14 + 40 + 1024;
fwrite(&intValue, sizeof(intValue), 1, stream);
// biSize
intValue = 40;
fwrite(&intValue, sizeof(intValue), 1, stream);
// biWidth
intValue = width;
fwrite(&intValue, sizeof(intValue), 1, stream);
// biHeight
intValue = height;
fwrite(&intValue, sizeof(intValue), 1, stream);
// biPlanes
shortValue = 1;
fwrite(&shortValue, sizeof(shortValue), 1, stream);
// biBitCount
shortValue = 8;
fwrite(&shortValue, sizeof(shortValue), 1, stream);
// biCompression
intValue = 0;
fwrite(&intValue, sizeof(intValue), 1, stream);
2022-05-19 01:51:26 -07:00
// biSizeImage
intValue = 0;
fwrite(&intValue, sizeof(intValue), 1, stream);
// biXPelsPerMeter
intValue = 0;
fwrite(&intValue, sizeof(intValue), 1, stream);
// biYPelsPerMeter
intValue = 0;
fwrite(&intValue, sizeof(intValue), 1, stream);
// biClrUsed
intValue = 0;
fwrite(&intValue, sizeof(intValue), 1, stream);
// biClrImportant
intValue = 0;
fwrite(&intValue, sizeof(intValue), 1, stream);
for (int index = 0; index < 256; index++) {
unsigned char rgbReserved = 0;
unsigned char rgbRed = palette[index * 3] << 2;
unsigned char rgbGreen = palette[index * 3 + 1] << 2;
unsigned char rgbBlue = palette[index * 3 + 2] << 2;
fwrite(&rgbBlue, sizeof(rgbBlue), 1, stream);
fwrite(&rgbGreen, sizeof(rgbGreen), 1, stream);
fwrite(&rgbRed, sizeof(rgbRed), 1, stream);
fwrite(&rgbReserved, sizeof(rgbReserved), 1, stream);
}
for (int y = height - 1; y >= 0; y--) {
unsigned char* dataPtr = data + y * width;
fwrite(dataPtr, 1, width, stream);
}
fflush(stream);
fclose(stream);
return 0;
}
// 0x4C9358
void screenshotHandlerConfigure(int keyCode, ScreenshotHandler* handler)
{
gScreenshotKeyCode = keyCode;
if (handler == NULL) {
handler = screenshotHandlerDefaultImpl;
}
gScreenshotHandler = handler;
}
// 0x4C9370
unsigned int _get_time()
{
2022-05-27 23:32:36 -07:00
return SDL_GetTicks();
2022-05-19 01:51:26 -07:00
}
// 0x4C937C
void coreDelayProcessingEvents(unsigned int delay)
{
// NOTE: Uninline.
unsigned int start = _get_time();
unsigned int end = _get_time();
// NOTE: Uninline.
unsigned int diff = getTicksBetween(end, start);
while (diff < delay) {
_process_bk();
end = _get_time();
// NOTE: Uninline.
diff = getTicksBetween(end, start);
}
}
// 0x4C93B8
void coreDelay(unsigned int ms)
{
2022-05-27 23:32:36 -07:00
unsigned int start = SDL_GetTicks();
2022-05-19 01:51:26 -07:00
unsigned int diff;
do {
// NOTE: Uninline
diff = getTicksSince(start);
} while (diff < ms);
}
// 0x4C93E0
unsigned int getTicksSince(unsigned int start)
{
2022-05-27 23:32:36 -07:00
unsigned int end = SDL_GetTicks();
2022-05-19 01:51:26 -07:00
// NOTE: Uninline.
return getTicksBetween(end, start);
}
// 0x4C9400
unsigned int getTicksBetween(unsigned int end, unsigned int start)
{
if (start > end) {
return INT_MAX;
} else {
return end - start;
}
}
// 0x4C9410
unsigned int _get_bk_time()
{
return gTickerLastTimestamp;
}
2022-08-16 04:14:53 -07:00
// NOTE: Unused.
//
// 0x4C9418
void inputSetKeyboardKeyRepeatRate(int value)
{
gKeyboardKeyRepeatRate = value;
}
// NOTE: Unused.
//
// 0x4C9420
int inputGetKeyboardKeyRepeatRate()
{
return gKeyboardKeyRepeatRate;
}
// NOTE: Unused.
//
// 0x4C9428
void inputSetKeyboardKeyRepeatDelay(int value)
{
gKeyboardKeyRepeatDelay = value;
}
// NOTE: Unused.
//
// 0x4C9430
int inputGetKeyboardKeyRepeatDelay()
{
return gKeyboardKeyRepeatDelay;
}
// NOTE: Unused.
//
// 0x4C9438
void inputSetFocusFunc(FocusFunc* func)
{
_focus_func = func;
}
// NOTE: Unused.
//
// 0x4C9440
FocusFunc* inputGetFocusFunc()
{
return _focus_func;
}
// NOTE: Unused.
//
// 0x4C9448
void inputSetIdleFunc(IdleFunc* func)
{
_idle_func = func;
}
// NOTE: Unused.
//
// 0x4C9450
IdleFunc* inputGetIdleFunc()
{
return _idle_func;
}
2022-05-19 01:51:26 -07:00
// 0x4C9490
void buildNormalizedQwertyKeys()
{
2022-05-23 01:44:49 -07:00
int* keys = gNormalizedQwertyKeys;
2022-05-19 01:51:26 -07:00
int k;
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_ESCAPE] = SDL_SCANCODE_ESCAPE;
keys[SDL_SCANCODE_1] = SDL_SCANCODE_1;
keys[SDL_SCANCODE_2] = SDL_SCANCODE_2;
keys[SDL_SCANCODE_3] = SDL_SCANCODE_3;
keys[SDL_SCANCODE_4] = SDL_SCANCODE_4;
keys[SDL_SCANCODE_5] = SDL_SCANCODE_5;
keys[SDL_SCANCODE_6] = SDL_SCANCODE_6;
keys[SDL_SCANCODE_7] = SDL_SCANCODE_7;
keys[SDL_SCANCODE_8] = SDL_SCANCODE_8;
keys[SDL_SCANCODE_9] = SDL_SCANCODE_9;
keys[SDL_SCANCODE_0] = SDL_SCANCODE_0;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 0:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_MINUS;
2022-05-19 01:51:26 -07:00
break;
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_6;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_SLASH;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_MINUS] = k;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_0;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_EQUALS;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_EQUALS] = k;
2022-05-19 01:51:26 -07:00
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_BACKSPACE] = SDL_SCANCODE_BACKSPACE;
keys[SDL_SCANCODE_TAB] = SDL_SCANCODE_TAB;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_A;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_Q;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_Q] = k;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_Z;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_W;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_W] = k;
2022-05-19 01:51:26 -07:00
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_E] = SDL_SCANCODE_E;
keys[SDL_SCANCODE_R] = SDL_SCANCODE_R;
keys[SDL_SCANCODE_T] = SDL_SCANCODE_T;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 0:
case 1:
case 3:
case 4:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_Y;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_Z;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_Y] = k;
2022-05-19 01:51:26 -07:00
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_U] = SDL_SCANCODE_U;
keys[SDL_SCANCODE_I] = SDL_SCANCODE_I;
keys[SDL_SCANCODE_O] = SDL_SCANCODE_O;
keys[SDL_SCANCODE_P] = SDL_SCANCODE_P;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 0:
case 3:
case 4:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_LEFTBRACKET;
2022-05-19 01:51:26 -07:00
break;
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_5;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_8;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_LEFTBRACKET] = k;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 0:
case 3:
case 4:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_RIGHTBRACKET;
2022-05-19 01:51:26 -07:00
break;
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_MINUS;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_9;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_RIGHTBRACKET] = k;
2022-05-19 01:51:26 -07:00
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_RETURN] = SDL_SCANCODE_RETURN;
keys[SDL_SCANCODE_LCTRL] = SDL_SCANCODE_LCTRL;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_Q;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_A;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_A] = k;
2022-05-19 01:51:26 -07:00
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_S] = SDL_SCANCODE_S;
keys[SDL_SCANCODE_D] = SDL_SCANCODE_D;
keys[SDL_SCANCODE_F] = SDL_SCANCODE_F;
keys[SDL_SCANCODE_G] = SDL_SCANCODE_G;
keys[SDL_SCANCODE_H] = SDL_SCANCODE_H;
keys[SDL_SCANCODE_J] = SDL_SCANCODE_J;
keys[SDL_SCANCODE_K] = SDL_SCANCODE_K;
keys[SDL_SCANCODE_L] = SDL_SCANCODE_L;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 0:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_SEMICOLON;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_COMMA;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_SEMICOLON] = k;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 0:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_APOSTROPHE;
2022-05-19 01:51:26 -07:00
break;
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_4;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_MINUS;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_APOSTROPHE] = k;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 0:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_GRAVE;
2022-05-19 01:51:26 -07:00
break;
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_2;
2022-05-19 01:51:26 -07:00
break;
case 3:
case 4:
k = 0;
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_RIGHTBRACKET;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_GRAVE] = k;
2022-05-19 01:51:26 -07:00
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_LSHIFT] = SDL_SCANCODE_LSHIFT;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 0:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_BACKSLASH;
2022-05-19 01:51:26 -07:00
break;
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_8;
2022-05-19 01:51:26 -07:00
break;
case 3:
case 4:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_GRAVE;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_Y;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_BACKSLASH] = k;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 0:
case 3:
case 4:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_Z;
2022-05-19 01:51:26 -07:00
break;
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_W;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_Y;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_Z] = k;
2022-05-19 01:51:26 -07:00
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_X] = SDL_SCANCODE_X;
keys[SDL_SCANCODE_C] = SDL_SCANCODE_C;
keys[SDL_SCANCODE_V] = SDL_SCANCODE_V;
keys[SDL_SCANCODE_B] = SDL_SCANCODE_B;
keys[SDL_SCANCODE_N] = SDL_SCANCODE_N;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_SEMICOLON;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_M;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_M] = k;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_M;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_COMMA;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_COMMA] = k;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_COMMA;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_PERIOD;
2022-05-19 01:51:26 -07:00
break;
}
2022-05-23 01:44:49 -07:00
keys[SDL_SCANCODE_PERIOD] = k;
2022-05-19 01:51:26 -07:00
switch (gKeyboardLayout) {
case 0:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_SLASH;
2022-05-19 01:51:26 -07:00
break;
case 1:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_PERIOD;
2022-05-19 01:51:26 -07:00
break;
default:
2022-05-23 01:44:49 -07:00
k = SDL_SCANCODE_7;
break;
}
keys[SDL_SCANCODE_SLASH] = k;
keys[SDL_SCANCODE_RSHIFT] = SDL_SCANCODE_RSHIFT;
keys[SDL_SCANCODE_KP_MULTIPLY] = SDL_SCANCODE_KP_MULTIPLY;
keys[SDL_SCANCODE_SPACE] = SDL_SCANCODE_SPACE;
keys[SDL_SCANCODE_LALT] = SDL_SCANCODE_LALT;
keys[SDL_SCANCODE_CAPSLOCK] = SDL_SCANCODE_CAPSLOCK;
keys[SDL_SCANCODE_F1] = SDL_SCANCODE_F1;
keys[SDL_SCANCODE_F2] = SDL_SCANCODE_F2;
keys[SDL_SCANCODE_F3] = SDL_SCANCODE_F3;
keys[SDL_SCANCODE_F4] = SDL_SCANCODE_F4;
keys[SDL_SCANCODE_F5] = SDL_SCANCODE_F5;
keys[SDL_SCANCODE_F6] = SDL_SCANCODE_F6;
keys[SDL_SCANCODE_F7] = SDL_SCANCODE_F7;
keys[SDL_SCANCODE_F8] = SDL_SCANCODE_F8;
keys[SDL_SCANCODE_F9] = SDL_SCANCODE_F9;
keys[SDL_SCANCODE_F10] = SDL_SCANCODE_F10;
keys[SDL_SCANCODE_NUMLOCKCLEAR] = SDL_SCANCODE_NUMLOCKCLEAR;
keys[SDL_SCANCODE_SCROLLLOCK] = SDL_SCANCODE_SCROLLLOCK;
keys[SDL_SCANCODE_KP_7] = SDL_SCANCODE_KP_7;
keys[SDL_SCANCODE_KP_9] = SDL_SCANCODE_KP_9;
keys[SDL_SCANCODE_KP_8] = SDL_SCANCODE_KP_8;
keys[SDL_SCANCODE_KP_MINUS] = SDL_SCANCODE_KP_MINUS;
keys[SDL_SCANCODE_KP_4] = SDL_SCANCODE_KP_4;
keys[SDL_SCANCODE_KP_5] = SDL_SCANCODE_KP_5;
keys[SDL_SCANCODE_KP_6] = SDL_SCANCODE_KP_6;
keys[SDL_SCANCODE_KP_PLUS] = SDL_SCANCODE_KP_PLUS;
keys[SDL_SCANCODE_KP_1] = SDL_SCANCODE_KP_1;
keys[SDL_SCANCODE_KP_2] = SDL_SCANCODE_KP_2;
keys[SDL_SCANCODE_KP_3] = SDL_SCANCODE_KP_3;
keys[SDL_SCANCODE_KP_0] = SDL_SCANCODE_KP_0;
keys[SDL_SCANCODE_KP_DECIMAL] = SDL_SCANCODE_KP_DECIMAL;
keys[SDL_SCANCODE_F11] = SDL_SCANCODE_F11;
keys[SDL_SCANCODE_F12] = SDL_SCANCODE_F12;
keys[SDL_SCANCODE_F13] = -1;
keys[SDL_SCANCODE_F14] = -1;
keys[SDL_SCANCODE_F15] = -1;
//keys[DIK_KANA] = -1;
//keys[DIK_CONVERT] = -1;
//keys[DIK_NOCONVERT] = -1;
//keys[DIK_YEN] = -1;
keys[SDL_SCANCODE_KP_EQUALS] = -1;
//keys[DIK_PREVTRACK] = -1;
//keys[DIK_AT] = -1;
//keys[DIK_COLON] = -1;
//keys[DIK_UNDERLINE] = -1;
//keys[DIK_KANJI] = -1;
keys[SDL_SCANCODE_STOP] = -1;
//keys[DIK_AX] = -1;
//keys[DIK_UNLABELED] = -1;
keys[SDL_SCANCODE_KP_ENTER] = SDL_SCANCODE_KP_ENTER;
keys[SDL_SCANCODE_RCTRL] = SDL_SCANCODE_RCTRL;
keys[SDL_SCANCODE_KP_COMMA] = -1;
keys[SDL_SCANCODE_KP_DIVIDE] = SDL_SCANCODE_KP_DIVIDE;
//keys[DIK_SYSRQ] = 84;
keys[SDL_SCANCODE_RALT] = SDL_SCANCODE_RALT;
keys[SDL_SCANCODE_HOME] = SDL_SCANCODE_HOME;
keys[SDL_SCANCODE_UP] = SDL_SCANCODE_UP;
keys[SDL_SCANCODE_PRIOR] = SDL_SCANCODE_PRIOR;
keys[SDL_SCANCODE_LEFT] = SDL_SCANCODE_LEFT;
keys[SDL_SCANCODE_RIGHT] = SDL_SCANCODE_RIGHT;
keys[SDL_SCANCODE_END] = SDL_SCANCODE_END;
keys[SDL_SCANCODE_DOWN] = SDL_SCANCODE_DOWN;
keys[SDL_SCANCODE_PAGEDOWN] = SDL_SCANCODE_PAGEDOWN;
keys[SDL_SCANCODE_INSERT] = SDL_SCANCODE_INSERT;
keys[SDL_SCANCODE_DELETE] = SDL_SCANCODE_DELETE;
keys[SDL_SCANCODE_LGUI] = -1;
keys[SDL_SCANCODE_RGUI] = -1;
keys[SDL_SCANCODE_APPLICATION] = -1;
2022-05-19 01:51:26 -07:00
}
// 0x4C9C20
int _GNW95_input_init()
{
return 0;
}
// 0x4C9CF0
void _GNW95_process_message()
{
2022-05-23 01:44:49 -07:00
// We need to process event loop even if program is not active or keyboard
// is disabled, because if we ignore it, we'll never be able to reactivate
// it again.
KeyboardData keyboardData;
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_MOUSEMOTION:
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
2022-08-07 04:52:44 -07:00
case SDL_MOUSEWHEEL:
handleMouseEvent(&e);
2022-08-07 04:52:44 -07:00
break;
2022-07-29 10:04:37 -07:00
case SDL_FINGERDOWN:
case SDL_FINGERMOTION:
case SDL_FINGERUP:
handleTouchEvent(&e);
2022-07-29 10:04:37 -07:00
break;
2022-05-23 01:44:49 -07:00
case SDL_KEYDOWN:
case SDL_KEYUP:
if (!keyboardIsDisabled()) {
keyboardData.key = e.key.keysym.scancode;
keyboardData.down = (e.key.state & SDL_PRESSED) != 0;
_GNW95_process_key(&keyboardData);
}
break;
case SDL_WINDOWEVENT:
switch (e.window.event) {
case SDL_WINDOWEVENT_EXPOSED:
windowRefreshAll(&_scr_size);
break;
2022-05-23 14:18:41 -07:00
case SDL_WINDOWEVENT_SIZE_CHANGED:
// TODO: Recreate gSdlSurface in case size really changed (i.e.
// not alt-tabbing in fullscreen mode).
break;
2022-05-23 01:44:49 -07:00
case SDL_WINDOWEVENT_FOCUS_GAINED:
gProgramIsActive = true;
windowRefreshAll(&_scr_size);
2022-07-12 02:09:53 -07:00
audioEngineResume();
2022-05-23 01:44:49 -07:00
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
gProgramIsActive = false;
2022-07-12 02:09:53 -07:00
audioEnginePause();
2022-05-23 01:44:49 -07:00
break;
}
break;
case SDL_QUIT:
exit(EXIT_SUCCESS);
break;
2022-05-19 01:51:26 -07:00
}
2022-05-23 01:44:49 -07:00
}
2022-05-19 01:51:26 -07:00
2022-05-23 01:44:49 -07:00
if (gProgramIsActive && !keyboardIsDisabled()) {
2022-05-19 01:51:26 -07:00
// NOTE: Uninline
int tick = _get_time();
2022-05-23 01:44:49 -07:00
for (int key = 0; key < SDL_NUM_SCANCODES; key++) {
2022-05-19 01:51:26 -07:00
STRUCT_6ABF50* ptr = &(_GNW95_key_time_stamps[key]);
if (ptr->tick != -1) {
int elapsedTime = ptr->tick > tick ? INT_MAX : tick - ptr->tick;
int delay = ptr->repeatCount == 0 ? gKeyboardKeyRepeatDelay : gKeyboardKeyRepeatRate;
if (elapsedTime > delay) {
2022-05-23 01:44:49 -07:00
keyboardData.key = key;
keyboardData.down = 1;
_GNW95_process_key(&keyboardData);
2022-05-19 01:51:26 -07:00
ptr->tick = tick;
ptr->repeatCount++;
}
}
}
}
}
// 0x4C9DF0
void _GNW95_clear_time_stamps()
{
2022-05-23 01:44:49 -07:00
for (int index = 0; index < SDL_NUM_SCANCODES; index++) {
2022-05-19 01:51:26 -07:00
_GNW95_key_time_stamps[index].tick = -1;
_GNW95_key_time_stamps[index].repeatCount = 0;
}
}
// 0x4C9E14
void _GNW95_process_key(KeyboardData* data)
{
2022-05-23 01:44:49 -07:00
data->key = gNormalizedQwertyKeys[data->key];
2022-05-19 01:51:26 -07:00
if (gVcrState == VCR_STATE_PLAYING) {
if ((gVcrTerminateFlags & VCR_TERMINATE_ON_KEY_PRESS) != 0) {
gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_TERMINATED;
vcrStop();
2022-05-19 01:51:26 -07:00
}
} else {
2022-05-23 01:44:49 -07:00
STRUCT_6ABF50* ptr = &(_GNW95_key_time_stamps[data->key]);
2022-05-19 01:51:26 -07:00
if (data->down == 1) {
ptr->tick = _get_time();
ptr->repeatCount = 0;
} else {
ptr->tick = -1;
}
2022-05-23 01:44:49 -07:00
_kb_simulate_key(data);
2022-05-19 01:51:26 -07:00
}
}
// 0x4C9EEC
void _GNW95_lost_focus()
{
if (_focus_func != NULL) {
2022-08-16 04:14:53 -07:00
_focus_func(false);
2022-05-19 01:51:26 -07:00
}
while (!gProgramIsActive) {
_GNW95_process_message();
if (_idle_func != NULL) {
_idle_func();
}
}
if (_focus_func != NULL) {
2022-08-16 04:14:53 -07:00
_focus_func(true);
2022-05-19 01:51:26 -07:00
}
}
// 0x4CACD0
void mmxSetEnabled(bool a1)
{
if (!gMmxProbed) {
gMmxSupported = mmxIsSupported();
gMmxProbed = true;
}
if (gMmxSupported) {
gMmxEnabled = a1;
}
}
// 0x4CAD08
int _init_mode_320_200()
{
return _GNW95_init_mode_ex(320, 200, 8);
}
// 0x4CAD40
int _init_mode_320_400()
{
return _GNW95_init_mode_ex(320, 400, 8);
}
// 0x4CAD5C
int _init_mode_640_480_16()
{
return -1;
}
// 0x4CAD64
int _init_mode_640_480()
{
return _init_vesa_mode(640, 480);
}
// 0x4CAD94
int _init_mode_640_400()
{
return _init_vesa_mode(640, 400);
}
// 0x4CADA8
int _init_mode_800_600()
{
return _init_vesa_mode(800, 600);
}
// 0x4CADBC
int _init_mode_1024_768()
{
return _init_vesa_mode(1024, 768);
}
// 0x4CADD0
int _init_mode_1280_1024()
{
return _init_vesa_mode(1280, 1024);
}
// 0x4CADF8
void _get_start_mode_()
{
}
// 0x4CADFC
void _zero_vid_mem()
{
if (_zero_mem) {
_zero_mem();
}
}
// 0x4CAE1C
int _GNW95_init_mode_ex(int width, int height, int bpp)
{
2022-05-19 04:01:17 -07:00
bool fullscreen = true;
Config resolutionConfig;
if (configInit(&resolutionConfig)) {
if (configRead(&resolutionConfig, "f2_res.ini", false)) {
int screenWidth;
if (configGetInt(&resolutionConfig, "MAIN", "SCR_WIDTH", &screenWidth)) {
width = screenWidth;
}
int screenHeight;
if (configGetInt(&resolutionConfig, "MAIN", "SCR_HEIGHT", &screenHeight)) {
height = screenHeight;
}
bool windowed;
if (configGetBool(&resolutionConfig, "MAIN", "WINDOWED", &windowed)) {
fullscreen = !windowed;
}
configGetBool(&resolutionConfig, "IFACE", "IFACE_BAR_MODE", &gInterfaceBarMode);
2022-05-19 04:01:17 -07:00
}
configFree(&resolutionConfig);
}
if (_GNW95_init_window(width, height, fullscreen) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
if (directDrawInit(width, height, bpp) == -1) {
return -1;
}
_scr_size.left = 0;
_scr_size.top = 0;
_scr_size.right = width - 1;
_scr_size.bottom = height - 1;
mmxSetEnabled(true);
if (bpp == 8) {
_mouse_blit_trans = NULL;
_scr_blit = _GNW95_ShowRect;
_zero_mem = _GNW95_zero_vid_mem;
_mouse_blit = _GNW95_ShowRect;
} else {
_zero_mem = NULL;
_mouse_blit = _GNW95_MouseShowRect16;
_mouse_blit_trans = _GNW95_MouseShowTransRect16;
_scr_blit = _GNW95_ShowRect16;
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4CAECC
int _init_vesa_mode(int width, int height)
{
return _GNW95_init_mode_ex(width, height, 8);
}
// 0x4CAEDC
2022-05-19 04:01:17 -07:00
int _GNW95_init_window(int width, int height, bool fullscreen)
2022-05-19 01:51:26 -07:00
{
2022-05-23 01:44:49 -07:00
if (gSdlWindow == NULL) {
2022-07-12 00:10:23 -07:00
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
2022-05-19 04:01:17 -07:00
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
return -1;
}
2022-05-19 01:51:26 -07:00
2022-07-12 00:10:23 -07:00
Uint32 windowFlags = SDL_WINDOW_OPENGL;
if (fullscreen) {
windowFlags |= SDL_WINDOW_FULLSCREEN;
}
gSdlWindow = SDL_CreateWindow(gProgramWindowTitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, windowFlags);
2022-05-19 04:01:17 -07:00
if (gSdlWindow == NULL) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-07-12 00:10:23 -07:00
gSdlRenderer = SDL_CreateRenderer(gSdlWindow, -1, 0);
if (gSdlRenderer == NULL) {
goto err;
}
2022-07-12 00:10:23 -07:00
if (SDL_RenderSetLogicalSize(gSdlRenderer, width, height) != 0) {
goto err;
}
gSdlTexture = SDL_CreateTexture(gSdlRenderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, width, height);
if (gSdlTexture == NULL) {
goto err;
}
Uint32 format;
if (SDL_QueryTexture(gSdlTexture, &format, NULL, NULL, NULL) != 0) {
goto err;
}
gSdlTextureSurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, SDL_BITSPERPIXEL(format), format);
if (gSdlTextureSurface == NULL) {
goto err;
2022-05-19 04:01:17 -07:00
}
2022-05-19 01:51:26 -07:00
}
return 0;
2022-07-12 00:10:23 -07:00
err:
if (gSdlTexture != NULL) {
SDL_DestroyTexture(gSdlTexture);
gSdlTexture = NULL;
}
if (gSdlRenderer != NULL) {
SDL_DestroyRenderer(gSdlRenderer);
gSdlRenderer = NULL;
}
if (gSdlWindow != NULL) {
SDL_DestroyWindow(gSdlWindow);
gSdlWindow = NULL;
}
return -1;
2022-05-19 01:51:26 -07:00
}
// calculate shift for mask
// 0x4CAF50
int getShiftForBitMask(int mask)
{
int shift = 0;
if ((mask & 0xFFFF0000) != 0) {
shift |= 16;
mask &= 0xFFFF0000;
}
if ((mask & 0xFF00FF00) != 0) {
shift |= 8;
mask &= 0xFF00FF00;
}
if ((mask & 0xF0F0F0F0) != 0) {
shift |= 4;
mask &= 0xF0F0F0F0;
}
if ((mask & 0xCCCCCCCC) != 0) {
shift |= 2;
mask &= 0xCCCCCCCC;
}
if ((mask & 0xAAAAAAAA) != 0) {
shift |= 1;
}
return shift;
}
// 0x4CAF9C
int directDrawInit(int width, int height, int bpp)
{
2022-05-19 04:01:17 -07:00
if (gSdlSurface != NULL) {
2022-05-19 01:51:26 -07:00
unsigned char* palette = directDrawGetPalette();
directDrawFree();
if (directDrawInit(width, height, bpp) == -1) {
return -1;
}
directDrawSetPalette(palette);
return 0;
}
2022-05-19 04:01:17 -07:00
gSdlSurface = SDL_CreateRGBSurface(0, width, height, bpp, 0, 0, 0, 0);
2022-05-19 01:51:26 -07:00
if (bpp == 8) {
2022-05-19 04:01:17 -07:00
SDL_Color colors[256];
2022-05-19 01:51:26 -07:00
for (int index = 0; index < 256; index++) {
2022-05-19 04:01:17 -07:00
colors[index].r = index;
colors[index].g = index;
colors[index].b = index;
colors[index].a = 255;
2022-05-19 01:51:26 -07:00
}
2022-05-19 04:01:17 -07:00
SDL_SetPaletteColors(gSdlSurface->format->palette, colors, 0, 256);
2022-05-19 01:51:26 -07:00
} else {
2022-05-24 13:19:36 -07:00
gRedMask = gSdlSurface->format->Rmask;
gGreenMask = gSdlSurface->format->Gmask;
gBlueMask = gSdlSurface->format->Bmask;
2022-05-19 01:51:26 -07:00
2022-05-24 13:19:36 -07:00
gRedShift = gSdlSurface->format->Rshift;
gGreenShift = gSdlSurface->format->Gshift;
gBlueShift = gSdlSurface->format->Bshift;
2022-05-19 01:51:26 -07:00
}
2022-05-24 13:19:36 -07:00
return 0;
2022-05-19 01:51:26 -07:00
}
// 0x4CB1B0
void directDrawFree()
{
2022-05-19 04:01:17 -07:00
if (gSdlSurface != NULL) {
SDL_FreeSurface(gSdlSurface);
gSdlSurface = NULL;
2022-05-19 01:51:26 -07:00
}
}
// 0x4CB310
void directDrawSetPaletteInRange(unsigned char* palette, int start, int count)
{
2022-05-19 04:01:17 -07:00
if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) {
SDL_Color colors[256];
2022-05-19 01:51:26 -07:00
if (count != 0) {
for (int index = 0; index < count; index++) {
2022-05-19 04:01:17 -07:00
colors[index].r = palette[index * 3] << 2;
colors[index].g = palette[index * 3 + 1] << 2;
colors[index].b = palette[index * 3 + 2] << 2;
colors[index].a = 255;
2022-05-19 01:51:26 -07:00
}
}
2022-05-19 04:01:17 -07:00
SDL_SetPaletteColors(gSdlSurface->format->palette, colors, start, count);
2022-07-12 00:10:23 -07:00
SDL_BlitSurface(gSdlSurface, NULL, gSdlTextureSurface, NULL);
SDL_UpdateTexture(gSdlTexture, NULL, gSdlTextureSurface->pixels, gSdlTextureSurface->pitch);
SDL_RenderClear(gSdlRenderer);
SDL_RenderCopy(gSdlRenderer, gSdlTexture, NULL, NULL);
SDL_RenderPresent(gSdlRenderer);
2022-05-19 01:51:26 -07:00
} else {
for (int index = start; index < start + count; index++) {
unsigned short r = palette[0] << 2;
unsigned short g = palette[1] << 2;
unsigned short b = palette[2] << 2;
palette += 3;
r = gRedShift > 0 ? (r << gRedShift) : (r >> -gRedShift);
r &= gRedMask;
g = gGreenShift > 0 ? (g << gGreenShift) : (g >> -gGreenShift);
g &= gGreenMask;
b = gBlueShift > 0 ? (b << gBlueShift) : (b >> -gBlueShift);
b &= gBlueMask;
unsigned short rgb = r | g | b;
gSixteenBppPalette[index] = rgb;
}
windowRefreshAll(&_scr_size);
}
if (_update_palette_func != NULL) {
_update_palette_func();
}
}
// 0x4CB568
void directDrawSetPalette(unsigned char* palette)
{
2022-05-19 04:01:17 -07:00
if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) {
SDL_Color colors[256];
2022-05-19 01:51:26 -07:00
for (int index = 0; index < 256; index++) {
2022-05-19 04:01:17 -07:00
colors[index].r = palette[index * 3] << 2;
colors[index].g = palette[index * 3 + 1] << 2;
colors[index].b = palette[index * 3 + 2] << 2;
colors[index].a = 255;
2022-05-19 01:51:26 -07:00
}
2022-05-19 04:01:17 -07:00
SDL_SetPaletteColors(gSdlSurface->format->palette, colors, 0, 256);
2022-07-12 00:10:23 -07:00
SDL_BlitSurface(gSdlSurface, NULL, gSdlTextureSurface, NULL);
SDL_UpdateTexture(gSdlTexture, NULL, gSdlTextureSurface->pixels, gSdlTextureSurface->pitch);
SDL_RenderClear(gSdlRenderer);
SDL_RenderCopy(gSdlRenderer, gSdlTexture, NULL, NULL);
SDL_RenderPresent(gSdlRenderer);
2022-05-19 01:51:26 -07:00
} else {
for (int index = 0; index < 256; index++) {
unsigned short r = palette[index * 3] << 2;
unsigned short g = palette[index * 3 + 1] << 2;
unsigned short b = palette[index * 3 + 2] << 2;
r = gRedShift > 0 ? (r << gRedShift) : (r >> -gRedShift);
r &= gRedMask;
g = gGreenShift > 0 ? (g << gGreenShift) : (g >> -gGreenShift);
g &= gGreenMask;
b = gBlueShift > 0 ? (b << gBlueShift) : (b >> -gBlueShift);
b &= gBlueMask;
unsigned short rgb = r | g | b;
gSixteenBppPalette[index] = rgb;
}
windowRefreshAll(&_scr_size);
}
if (_update_palette_func != NULL) {
_update_palette_func();
}
}
// 0x4CB68C
unsigned char* directDrawGetPalette()
{
2022-05-19 04:01:17 -07:00
if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) {
SDL_Color* colors = gSdlSurface->format->palette->colors;
2022-05-19 01:51:26 -07:00
for (int index = 0; index < 256; index++) {
2022-05-19 04:01:17 -07:00
SDL_Color* color = &(colors[index]);
gLastVideoModePalette[index * 3] = color->r >> 2;
gLastVideoModePalette[index * 3 + 1] = color->g >> 2;
gLastVideoModePalette[index * 3 + 2] = color->b >> 2;
2022-05-19 01:51:26 -07:00
}
return gLastVideoModePalette;
}
int redShift = gRedShift + 2;
int greenShift = gGreenShift + 2;
int blueShift = gBlueShift + 2;
for (int index = 0; index < 256; index++) {
unsigned short rgb = gSixteenBppPalette[index];
unsigned short r = redShift > 0 ? ((rgb & gRedMask) >> redShift) : ((rgb & gRedMask) << -redShift);
unsigned short g = greenShift > 0 ? ((rgb & gGreenMask) >> greenShift) : ((rgb & gGreenMask) << -greenShift);
unsigned short b = blueShift > 0 ? ((rgb & gBlueMask) >> blueShift) : ((rgb & gBlueMask) << -blueShift);
gLastVideoModePalette[index * 3] = (r >> 2) & 0xFF;
gLastVideoModePalette[index * 3 + 1] = (g >> 2) & 0xFF;
gLastVideoModePalette[index * 3 + 2] = (b >> 2) & 0xFF;
}
return gLastVideoModePalette;
}
// 0x4CB850
void _GNW95_ShowRect(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY)
{
2022-05-19 04:01:17 -07:00
SDL_LockSurface(gSdlSurface);
blitBufferToBuffer(src + srcPitch * srcY + srcX, srcWidth, srcHeight, srcPitch, (unsigned char*)gSdlSurface->pixels + gSdlSurface->pitch * destY + destX, gSdlSurface->pitch);
SDL_UnlockSurface(gSdlSurface);
SDL_Rect srcRect;
srcRect.x = destX;
srcRect.y = destY;
srcRect.w = srcWidth;
srcRect.h = srcHeight;
SDL_Rect destRect;
destRect.x = destX;
destRect.y = destY;
2022-07-12 00:10:23 -07:00
SDL_BlitSurface(gSdlSurface, &srcRect, gSdlTextureSurface, &destRect);
SDL_UpdateTexture(gSdlTexture, NULL, gSdlTextureSurface->pixels, gSdlTextureSurface->pitch);
SDL_RenderClear(gSdlRenderer);
SDL_RenderCopy(gSdlRenderer, gSdlTexture, NULL, NULL);
SDL_RenderPresent(gSdlRenderer);
2022-05-19 01:51:26 -07:00
}
// 0x4CB93C
void _GNW95_MouseShowRect16(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY)
{
if (!gProgramIsActive) {
return;
}
2022-05-24 13:19:36 -07:00
SDL_LockSurface(gSdlSurface);
unsigned char* dest = (unsigned char*)gSdlSurface->pixels + gSdlSurface->pitch * destY + 2 * destX;
2022-05-19 01:51:26 -07:00
src += srcPitch * srcY + srcX;
for (int y = 0; y < srcHeight; y++) {
unsigned short* destPtr = (unsigned short*)dest;
unsigned char* srcPtr = src;
for (int x = 0; x < srcWidth; x++) {
*destPtr = gSixteenBppPalette[*srcPtr];
destPtr++;
srcPtr++;
}
2022-05-24 13:19:36 -07:00
dest += gSdlSurface->pitch;
2022-05-19 01:51:26 -07:00
src += srcPitch;
}
2022-05-24 13:19:36 -07:00
SDL_UnlockSurface(gSdlSurface);
SDL_Rect srcRect;
srcRect.x = destX;
srcRect.y = destY;
srcRect.w = srcWidth;
srcRect.h = srcHeight;
SDL_Rect destRect;
destRect.x = destX;
destRect.y = destY;
2022-07-12 00:10:23 -07:00
SDL_BlitSurface(gSdlSurface, &srcRect, gSdlTextureSurface, &destRect);
SDL_UpdateTexture(gSdlTexture, NULL, gSdlTextureSurface->pixels, gSdlTextureSurface->pitch);
SDL_RenderClear(gSdlRenderer);
SDL_RenderCopy(gSdlRenderer, gSdlTexture, NULL, NULL);
SDL_RenderPresent(gSdlRenderer);
2022-05-19 01:51:26 -07:00
}
// 0x4CBA44
void _GNW95_ShowRect16(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY)
{
_GNW95_MouseShowRect16(src, srcPitch, a3, srcX, srcY, srcWidth, srcHeight, destX, destY);
}
// 0x4CBAB0
void _GNW95_MouseShowTransRect16(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, unsigned char keyColor)
{
if (!gProgramIsActive) {
return;
}
2022-05-24 13:19:36 -07:00
SDL_LockSurface(gSdlSurface);
unsigned char* dest = (unsigned char*)gSdlSurface->pixels + gSdlSurface->pitch * destY + 2 * destX;
2022-05-19 01:51:26 -07:00
src += srcPitch * srcY + srcX;
for (int y = 0; y < srcHeight; y++) {
unsigned short* destPtr = (unsigned short*)dest;
unsigned char* srcPtr = src;
for (int x = 0; x < srcWidth; x++) {
if (*srcPtr != keyColor) {
*destPtr = gSixteenBppPalette[*srcPtr];
}
destPtr++;
srcPtr++;
}
2022-05-24 13:19:36 -07:00
dest += gSdlSurface->pitch;
2022-05-19 01:51:26 -07:00
src += srcPitch;
}
2022-05-24 13:19:36 -07:00
SDL_UnlockSurface(gSdlSurface);
SDL_Rect srcRect;
srcRect.x = destX;
srcRect.y = destY;
srcRect.w = srcWidth;
srcRect.h = srcHeight;
SDL_Rect destRect;
destRect.x = destX;
destRect.y = destY;
2022-07-12 00:10:23 -07:00
SDL_BlitSurface(gSdlSurface, &srcRect, gSdlTextureSurface, &destRect);
SDL_UpdateTexture(gSdlTexture, NULL, gSdlTextureSurface->pixels, gSdlTextureSurface->pitch);
SDL_RenderClear(gSdlRenderer);
SDL_RenderCopy(gSdlRenderer, gSdlTexture, NULL, NULL);
SDL_RenderPresent(gSdlRenderer);
2022-05-19 01:51:26 -07:00
}
// Clears drawing surface.
//
// 0x4CBBC8
void _GNW95_zero_vid_mem()
{
if (!gProgramIsActive) {
return;
}
2022-05-24 13:19:36 -07:00
SDL_LockSurface(gSdlSurface);
2022-05-19 01:51:26 -07:00
2022-05-24 13:19:36 -07:00
unsigned char* surface = (unsigned char*)gSdlSurface->pixels;
2022-07-07 00:52:54 -07:00
for (int y = 0; y < gSdlSurface->h; y++) {
2022-05-24 13:19:36 -07:00
memset(surface, 0, gSdlSurface->w);
surface += gSdlSurface->pitch;
2022-05-19 01:51:26 -07:00
}
2022-05-24 13:19:36 -07:00
SDL_UnlockSurface(gSdlSurface);
2022-05-19 01:51:26 -07:00
2022-07-12 00:10:23 -07:00
SDL_BlitSurface(gSdlSurface, NULL, gSdlTextureSurface, NULL);
SDL_UpdateTexture(gSdlTexture, NULL, gSdlTextureSurface->pixels, gSdlTextureSurface->pitch);
SDL_RenderClear(gSdlRenderer);
SDL_RenderCopy(gSdlRenderer, gSdlTexture, NULL, NULL);
SDL_RenderPresent(gSdlRenderer);
2022-05-19 01:51:26 -07:00
}
2022-05-20 15:50:14 -07:00
int screenGetWidth()
{
// TODO: Make it on par with _xres;
2022-05-20 15:56:07 -07:00
return rectGetWidth(&_scr_size);
2022-05-20 15:50:14 -07:00
}
int screenGetHeight()
{
// TODO: Make it on par with _yres.
2022-05-20 15:56:07 -07:00
return rectGetHeight(&_scr_size);
2022-05-20 15:50:14 -07:00
}
2022-05-20 16:29:59 -07:00
int screenGetVisibleHeight()
{
int windowBottomMargin = 0;
if (!gInterfaceBarMode) {
windowBottomMargin = INTERFACE_BAR_HEIGHT;
}
return screenGetHeight() - windowBottomMargin;
}
2022-08-16 04:24:57 -07:00
static void idleImpl()
{
SDL_Delay(125);
}
2022-09-23 05:43:44 -07:00
} // namespace fallout