summaryrefslogtreecommitdiff
path: root/src/skel
diff options
context:
space:
mode:
authorclaude-bot <[email protected]>2026-07-13 12:27:07 +0000
committerclaude-bot <[email protected]>2026-07-13 12:27:07 +0000
commit9f61c9e6ac6b1ac5692cf6352d2ebbd47a31a686 (patch)
treea84756b82513739a2672db3a1f0ec579db6d18ff /src/skel
downloadre3-miami.tar.gz
re3-miami.zip
Import Cai1Hsu/re3 @ miami (reVC / GTA:VC decompilation)HEADmiami
Snapshot import (no upstream history) into git.ancap.in.ua/claude, per @lzcnt. Source: https://github.com/Cai1Hsu/re3 branch miami.
Diffstat (limited to 'src/skel')
-rw-r--r--src/skel/crossplatform.cpp272
-rw-r--r--src/skel/crossplatform.h159
-rw-r--r--src/skel/events.cpp829
-rw-r--r--src/skel/events.h7
-rw-r--r--src/skel/glfw/glfw.cpp2528
-rw-r--r--src/skel/platform.h61
-rw-r--r--src/skel/skeleton.cpp428
-rw-r--r--src/skel/skeleton.h290
-rw-r--r--src/skel/win/gtavc.icobin0 -> 81817 bytes
-rw-r--r--src/skel/win/resource.h21
-rw-r--r--src/skel/win/win.cpp3460
-rw-r--r--src/skel/win/win.h91
-rw-r--r--src/skel/win/win.rc47
13 files changed, 8193 insertions, 0 deletions
diff --git a/src/skel/crossplatform.cpp b/src/skel/crossplatform.cpp
new file mode 100644
index 0000000..68df670
--- /dev/null
+++ b/src/skel/crossplatform.cpp
@@ -0,0 +1,272 @@
+#include "common.h"
+#include "crossplatform.h"
+
+// Codes compatible with Windows and Linux
+#ifndef _WIN32
+
+// For internal use
+// wMilliseconds is not needed
+void tmToSystemTime(const tm *tm, SYSTEMTIME *out) {
+ out->wYear = tm->tm_year + 1900;
+ out->wMonth = tm->tm_mon + 1;
+ out->wDayOfWeek = tm->tm_wday;
+ out->wDay = tm->tm_mday;
+ out->wHour = tm->tm_hour;
+ out->wMinute = tm->tm_min;
+ out->wSecond = tm->tm_sec;
+}
+
+void GetLocalTime_CP(SYSTEMTIME *out) {
+ time_t timestamp = time(nil);
+ tm *localTm = localtime(&timestamp);
+ tmToSystemTime(localTm, out);
+}
+#endif
+
+// Compatible with Linux/POSIX and MinGW on Windows
+#ifndef _WIN32
+HANDLE FindFirstFile(const char* pathname, WIN32_FIND_DATA* firstfile) {
+ char pathCopy[MAX_PATH];
+ strcpy(pathCopy, pathname);
+
+ char *folder = strtok(pathCopy, "*");
+ char *extension = strtok(NULL, "*");
+
+ // because I remember like strtok might not return NULL for last delimiter
+ if (extension && extension - folder == strlen(pathname))
+ extension = nil;
+
+ // Case-sensitivity and backslashes...
+ // Will be freed at the bottom
+ char *realFolder = casepath(folder);
+ if (realFolder) {
+ folder = realFolder;
+ }
+
+ strncpy(firstfile->folder, folder, sizeof(firstfile->folder));
+
+ if (extension)
+ strncpy(firstfile->extension, extension, sizeof(firstfile->extension));
+ else
+ firstfile->extension[0] = '\0';
+
+ if (realFolder)
+ free(realFolder);
+
+ HANDLE d;
+ if ((d = (HANDLE)opendir(firstfile->folder)) == NULL || !FindNextFile(d, firstfile))
+ return NULL;
+
+ return d;
+}
+
+bool FindNextFile(HANDLE d, WIN32_FIND_DATA* finddata) {
+ dirent *file;
+ static struct stat fileStats;
+ static char path[PATH_MAX], relativepath[NAME_MAX + sizeof(finddata->folder) + 1];
+ int extensionLen = strlen(finddata->extension);
+ while ((file = readdir((DIR*)d)) != NULL) {
+
+ // We only want "DT_REG"ular Files, but reportedly some FS and OSes gives DT_UNKNOWN as type.
+ if ((file->d_type == DT_UNKNOWN || file->d_type == DT_REG || file->d_type == DT_LNK) &&
+ (extensionLen == 0 || strncasecmp(&file->d_name[strlen(file->d_name) - extensionLen], finddata->extension, extensionLen) == 0)) {
+
+ sprintf(relativepath, "%s/%s", finddata->folder, file->d_name);
+ realpath(relativepath, path);
+ stat(path, &fileStats);
+ strncpy(finddata->cFileName, file->d_name, sizeof(finddata->cFileName));
+ finddata->ftLastWriteTime = fileStats.st_mtime;
+ return true;
+ }
+ }
+ return false;
+}
+
+void GetDateFormat(int unused1, int unused2, SYSTEMTIME* in, int unused3, char* out, int size) {
+ tm linuxTime;
+ linuxTime.tm_year = in->wYear - 1900;
+ linuxTime.tm_mon = in->wMonth - 1;
+ linuxTime.tm_wday = in->wDayOfWeek;
+ linuxTime.tm_mday = in->wDay;
+ linuxTime.tm_hour = in->wHour;
+ linuxTime.tm_min = in->wMinute;
+ linuxTime.tm_sec = in->wSecond;
+ strftime(out, size, nl_langinfo(D_FMT), &linuxTime);
+}
+
+void FileTimeToSystemTime(time_t* writeTime, SYSTEMTIME* out) {
+ tm *ptm = gmtime(writeTime);
+ tmToSystemTime(ptm, out);
+}
+#endif
+
+// Because wchar length differs between platforms.
+wchar*
+AllocUnicode(const char* src)
+{
+ wchar *dst = (wchar*)malloc(strlen(src)*2 + 2);
+ wchar *i = dst;
+ while((*i++ = (unsigned char)*src++) != '\0');
+ return dst;
+}
+
+// Funcs/features from Windows that we need on other platforms
+#ifndef _WIN32
+char *strupr(char *s) {
+ char* tmp = s;
+
+ for (;*tmp;++tmp) {
+ *tmp = toupper((unsigned char) *tmp);
+ }
+
+ return s;
+}
+char *strlwr(char *s) {
+ char* tmp = s;
+
+ for (;*tmp;++tmp) {
+ *tmp = tolower((unsigned char) *tmp);
+ }
+
+ return s;
+}
+
+char *trim(char *s) {
+ char *ptr;
+ if (!s)
+ return NULL; // handle NULL string
+ if (!*s)
+ return s; // handle empty string
+ for (ptr = s + strlen(s) - 1; (ptr >= s) && isspace(*ptr); --ptr);
+ ptr[1] = '\0';
+ return s;
+}
+
+FILE* _fcaseopen(char const* filename, char const* mode)
+{
+ FILE* result;
+ char* real = casepath(filename);
+ if (!real)
+ result = fopen(filename, mode);
+ else {
+ result = fopen(real, mode);
+ free(real);
+ }
+ return result;
+}
+
+// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
+// Returned string should freed manually (if exists)
+char* casepath(char const* path, bool checkPathFirst)
+{
+ if (checkPathFirst && access(path, F_OK) != -1) {
+ // File path is correct
+ return nil;
+ }
+
+ size_t l = strlen(path);
+ char* p = (char*)alloca(l + 1);
+ char* out = (char*)malloc(l + 3); // for extra ./
+ strcpy(p, path);
+
+ // my addon: linux doesn't handle filenames with spaces at the end nicely
+ p = trim(p);
+
+ size_t rl = 0;
+
+ DIR* d;
+ if (p[0] == '/' || p[0] == '\\')
+ {
+ d = opendir("/");
+ }
+ else
+ {
+ d = opendir(".");
+ out[0] = '.';
+ out[1] = 0;
+ rl = 1;
+ }
+
+ bool cantProceed = false; // just convert slashes in what's left in string, don't correct case of letters(because we can't)
+ bool mayBeTrailingSlash = false;
+ char* c;
+ while (c = strsep(&p, "/\\"))
+ {
+ // May be trailing slash(allow), slash at the start(avoid), or multiple slashes(avoid)
+ if (*c == '\0')
+ {
+ mayBeTrailingSlash = true;
+ continue;
+ } else {
+ mayBeTrailingSlash = false;
+ }
+
+ out[rl] = '/';
+ rl += 1;
+ out[rl] = 0;
+
+ if (cantProceed)
+ {
+ strcpy(out + rl, c);
+ rl += strlen(c);
+ continue;
+ }
+
+ struct dirent* e;
+ while (e = readdir(d))
+ {
+ if (strcasecmp(c, e->d_name) == 0)
+ {
+ strcpy(out + rl, e->d_name);
+ int reportedLen = (int)strlen(e->d_name);
+ rl += reportedLen;
+ assert(reportedLen == strlen(c) && "casepath: This is not good at all");
+
+ closedir(d);
+ d = opendir(out);
+
+ // Either it wasn't a folder, or permission error, I/O error etc.
+ if (!d) {
+ cantProceed = true;
+ }
+
+ break;
+ }
+ }
+
+ if (!e)
+ {
+ printf("casepath couldn't find dir/file \"%s\", full path was %s\n", c, path);
+ // No match, add original name and continue converting further slashes.
+ strcpy(out + rl, c);
+ rl += strlen(c);
+ cantProceed = true;
+ }
+ }
+
+ if (d) closedir(d);
+ if (mayBeTrailingSlash) {
+ out[rl] = '/'; rl += 1;
+ out[rl] = '\0';
+ }
+
+ if (rl > l + 2) {
+ printf("\n\ncasepath: Corrected path length is longer then original+2:\n\tOriginal: %s (%zu chars)\n\tCorrected: %s (%zu chars)\n\n", path, l, out, rl);
+ }
+ return out;
+}
+#endif
+
+#if !defined(_MSC_VER) && !defined(__CWCC__)
+char *strdate(char *buf) {
+ time_t timestamp;
+ time(&timestamp);
+ tm *localTm = localtime(&timestamp);
+ strftime(buf, 10, "%m/%d/%y", localTm);
+ return buf;
+}
+
+char *_strdate(char *buf) {
+ return strdate(buf);
+}
+#endif
diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h
new file mode 100644
index 0000000..9b43bca
--- /dev/null
+++ b/src/skel/crossplatform.h
@@ -0,0 +1,159 @@
+#include <time.h>
+
+// This is the common include for platform/renderer specific skeletons(glfw.cpp, win.cpp etc.) and using cross platform things (like Windows directories wrapper, platform specific global arrays etc.)
+// Functions that's different on glfw and win but have same signature, should be located on platform.h.
+
+enum eWinVersion
+{
+ OS_WIN95 = 0,
+ OS_WIN98,
+ OS_WINNT,
+ OS_WIN2000,
+ OS_WINXP,
+};
+
+#if !defined(_MSC_VER) && !defined(__CWCC__)
+char *_strdate(char *buf);
+#endif
+
+#ifdef _WIN32
+
+// As long as WITHWINDOWS isn't defined / <Windows.h> isn't included, we only need type definitions so let's include <IntSafe.h>.
+// NOTE: It's perfectly fine to include <Windows.h> here, but it can increase build size and time in *some* conditions, and maybe substantially in future if we'll use crossplatform.h more.
+#ifndef _INC_WINDOWS
+ #ifndef __MWERKS__
+ #include <IntSafe.h>
+ #else
+ #include <Windows.h>
+ #endif
+#endif
+#if defined RW_D3D9 || defined RWLIBS
+#include "win.h"
+#endif
+extern DWORD _dwOperatingSystemVersion;
+#define fcaseopen fopen
+#else
+char *strupr(char *str);
+char *strlwr(char *str);
+
+enum {
+ LANG_OTHER,
+ LANG_GERMAN,
+ LANG_FRENCH,
+ LANG_ENGLISH,
+ LANG_ITALIAN,
+ LANG_SPANISH,
+};
+
+enum {
+ SUBLANG_OTHER,
+ SUBLANG_ENGLISH_AUS
+};
+
+extern long _dwOperatingSystemVersion;
+char *casepath(char const *path, bool checkPathFirst = true);
+FILE *_fcaseopen(char const *filename, char const *mode);
+#define fcaseopen _fcaseopen
+#endif
+
+#ifdef RW_GL3
+typedef struct
+{
+ GLFWwindow* window;
+ RwBool fullScreen;
+ RwV2d lastMousePos;
+ double mouseWheel; // glfw doesn't cache it
+ bool cursorIsInWindow;
+ RwInt8 joy1id;
+ RwInt8 joy2id;
+}
+psGlobalType;
+
+#define PSGLOBAL(var) (((psGlobalType *)(RsGlobal.ps))->var)
+
+void CapturePad(RwInt32 padID);
+void joysChangeCB(int jid, int event);
+#endif
+
+#ifdef DETECT_JOYSTICK_MENU
+extern char gSelectedJoystickName[128];
+#endif
+
+enum eGameState
+{
+ GS_START_UP = 0,
+ GS_INIT_LOGO_MPEG,
+ GS_LOGO_MPEG,
+ GS_INIT_INTRO_MPEG,
+ GS_INTRO_MPEG,
+ GS_INIT_ONCE,
+ GS_INIT_FRONTEND,
+ GS_FRONTEND,
+ GS_INIT_PLAYING_GAME,
+ GS_PLAYING_GAME,
+};
+extern RwUInt32 gGameState;
+
+RwBool IsForegroundApp();
+
+#ifndef MAX_PATH
+ #if !defined _WIN32 || defined __MINGW32__
+ #define MAX_PATH PATH_MAX
+ #else
+ #define MAX_PATH 260
+ #endif
+#endif
+
+// Codes compatible with Windows and Linux
+#ifndef _WIN32
+#define DeleteFile unlink
+
+// Needed for save games
+struct SYSTEMTIME {
+ RwUInt16 wYear;
+ RwUInt16 wMonth;
+ RwUInt16 wDayOfWeek;
+ RwUInt16 wDay;
+ RwUInt16 wHour;
+ RwUInt16 wMinute;
+ RwUInt16 wSecond;
+ RwUInt16 wMilliseconds;
+};
+
+void GetLocalTime_CP(SYSTEMTIME* out);
+#define GetLocalTime GetLocalTime_CP
+#define OutputDebugString(s) re3_debug("[DBG-2]: %s\n",s)
+#endif
+
+// Compatible with Linux/POSIX and MinGW on Windows
+#ifndef _WIN32
+#include <iostream>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <langinfo.h>
+#include <unistd.h>
+
+typedef void* HANDLE;
+#define INVALID_HANDLE_VALUE NULL
+#define FindClose(h) \
+ do { \
+ if (h != nil) \
+ closedir((DIR*)h); \
+ } while(0)
+
+#define LOCALE_USER_DEFAULT 0
+#define DATE_SHORTDATE 0
+
+struct WIN32_FIND_DATA {
+ char extension[32]; // for searching
+ char folder[32]; // for searching
+ char cFileName[256]; // because tSkinInfo has it 256
+ time_t ftLastWriteTime;
+};
+
+HANDLE FindFirstFile(const char*, WIN32_FIND_DATA*);
+bool FindNextFile(HANDLE, WIN32_FIND_DATA*);
+void FileTimeToSystemTime(time_t*, SYSTEMTIME*);
+void GetDateFormat(int, int, SYSTEMTIME*, int, char*, int);
+#endif
diff --git a/src/skel/events.cpp b/src/skel/events.cpp
new file mode 100644
index 0000000..3e1e95b
--- /dev/null
+++ b/src/skel/events.cpp
@@ -0,0 +1,829 @@
+#include "common.h"
+#include "Pad.h"
+#include "ControllerConfig.h"
+#include "Frontend.h"
+#include "Camera.h"
+
+#include "rwcore.h"
+#include "skeleton.h"
+#include "events.h"
+
+
+/*
+ *****************************************************************************
+ */
+static RsEventStatus
+HandleKeyDown(RsKeyStatus *keyStatus)
+{
+ CPad *pad0 = CPad::GetPad(0);
+ CPad *pad1 = CPad::GetPad(1);
+
+ RwInt32 c = keyStatus->keyCharCode;
+
+ if ( c != rsNULL )
+ {
+ switch (c)
+ {
+ case rsESC:
+ {
+ CPad::TempKeyState.ESC = 255;
+ break;
+ }
+
+ case rsINS:
+ {
+ CPad::TempKeyState.INS = 255;
+ break;
+ }
+
+ case rsDEL:
+ {
+ CPad::TempKeyState.DEL = 255;
+ break;
+ }
+
+ case rsHOME:
+ {
+ CPad::TempKeyState.HOME = 255;
+ break;
+ }
+
+ case rsEND:
+ {
+ CPad::TempKeyState.END = 255;
+ break;
+ }
+
+ case rsPGUP:
+ {
+ CPad::TempKeyState.PGUP = 255;
+ break;
+ }
+
+ case rsPGDN:
+ {
+ CPad::TempKeyState.PGDN = 255;
+ break;
+ }
+
+ case rsUP:
+ {
+ CPad::TempKeyState.UP = 255;
+ break;
+ }
+
+ case rsDOWN:
+ {
+ CPad::TempKeyState.DOWN = 255;
+ break;
+ }
+
+ case rsLEFT:
+ {
+ CPad::TempKeyState.LEFT = 255;
+ break;
+ }
+
+ case rsRIGHT:
+ {
+ CPad::TempKeyState.RIGHT = 255;
+ break;
+ }
+
+ case rsNUMLOCK:
+ {
+ CPad::TempKeyState.NUMLOCK = 255;
+ break;
+ }
+
+ case rsPADDEL:
+ {
+ CPad::TempKeyState.DECIMAL = 255;
+ break;
+ }
+
+ case rsPADEND:
+ {
+ CPad::TempKeyState.NUM1 = 255;
+ break;
+ }
+
+ case rsPADDOWN:
+ {
+ CPad::TempKeyState.NUM2 = 255;
+ break;
+ }
+
+ case rsPADPGDN:
+ {
+ CPad::TempKeyState.NUM3 = 255;
+ break;
+ }
+
+ case rsPADLEFT:
+ {
+ CPad::TempKeyState.NUM4 = 255;
+ break;
+ }
+
+ case rsPAD5:
+ {
+ CPad::TempKeyState.NUM5 = 255;
+ break;
+ }
+
+ case rsPADRIGHT:
+ {
+ CPad::TempKeyState.NUM6 = 255;
+ break;
+ }
+
+ case rsPADHOME:
+ {
+ CPad::TempKeyState.NUM7 = 255;
+ break;
+ }
+
+ case rsPADUP:
+ {
+ CPad::TempKeyState.NUM8 = 255;
+ break;
+ }
+
+ case rsPADPGUP:
+ {
+ CPad::TempKeyState.NUM9 = 255;
+ break;
+ }
+
+ case rsPADINS:
+ {
+ CPad::TempKeyState.NUM0 = 255;
+ break;
+ }
+
+ case rsDIVIDE:
+ {
+ CPad::TempKeyState.DIV = 255;
+ break;
+ }
+
+ case rsTIMES:
+ {
+ CPad::TempKeyState.MUL = 255;
+ break;
+ }
+
+ case rsMINUS:
+ {
+ CPad::TempKeyState.SUB = 255;
+ break;
+ }
+
+ case rsPADENTER:
+ {
+ CPad::TempKeyState.ENTER = 255;
+ break;
+ }
+
+ case rsPLUS:
+ {
+ CPad::TempKeyState.ADD = 255;
+ break;
+ }
+
+ case rsENTER:
+ {
+ CPad::TempKeyState.EXTENTER = 255;
+ break;
+ }
+
+ case rsSCROLL:
+ {
+ CPad::TempKeyState.SCROLLLOCK = 255;
+ break;
+ }
+
+ case rsPAUSE:
+ {
+ CPad::TempKeyState.PAUSE = 255;
+ break;
+ }
+
+ case rsBACKSP:
+ {
+ CPad::TempKeyState.BACKSP = 255;
+ break;
+ }
+
+ case rsTAB:
+ {
+ CPad::TempKeyState.TAB = 255;
+ break;
+ }
+
+ case rsCAPSLK:
+ {
+ CPad::TempKeyState.CAPSLOCK = 255;
+ break;
+ }
+
+ case rsLSHIFT:
+ {
+ CPad::TempKeyState.LSHIFT = 255;
+ break;
+ }
+
+ case rsSHIFT:
+ {
+ CPad::TempKeyState.SHIFT = 255;
+ break;
+ }
+
+ case rsRSHIFT:
+ {
+ CPad::TempKeyState.RSHIFT = 255;
+ break;
+ }
+
+ case rsLCTRL:
+ {
+ CPad::TempKeyState.LCTRL = 255;
+ break;
+ }
+
+ case rsRCTRL:
+ {
+ CPad::TempKeyState.RCTRL = 255;
+ break;
+ }
+
+ case rsLALT:
+ {
+ CPad::TempKeyState.LALT = 255;
+ break;
+ }
+
+ case rsRALT:
+ {
+ CPad::TempKeyState.RALT = 255;
+ break;
+ }
+
+
+ case rsLWIN:
+ {
+ CPad::TempKeyState.LWIN = 255;
+ break;
+ }
+
+ case rsRWIN:
+ {
+ CPad::TempKeyState.RWIN = 255;
+ break;
+ }
+
+ case rsAPPS:
+ {
+ CPad::TempKeyState.APPS = 255;
+ break;
+ }
+
+ case rsF1:
+ case rsF2:
+ case rsF3:
+ case rsF4:
+ case rsF5:
+ case rsF6:
+ case rsF7:
+ case rsF8:
+ case rsF9:
+ case rsF10:
+ case rsF11:
+ case rsF12:
+ {
+ CPad::TempKeyState.F[c - rsF1] = 255;
+ break;
+ }
+
+ default:
+ {
+ if ( c < 255 )
+ {
+ CPad::TempKeyState.VK_KEYS[c] = 255;
+ pad0->AddToPCCheatString(c);
+ }
+ break;
+ }
+ }
+
+ if ( CPad::m_bMapPadOneToPadTwo )
+ {
+ if ( c == 'D' ) pad1->PCTempKeyState.LeftStickX = 128;
+ if ( c == 'A' ) pad1->PCTempKeyState.LeftStickX = -128;
+ if ( c == 'W' ) pad1->PCTempKeyState.LeftStickY = 128;
+ if ( c == 'S' ) pad1->PCTempKeyState.LeftStickY = -128;
+ if ( c == 'J' ) pad1->PCTempKeyState.RightStickX = 128;
+ if ( c == 'G' ) pad1->PCTempKeyState.RightStickX = -128;
+ if ( c == 'Y' ) pad1->PCTempKeyState.RightStickY = 128;
+ if ( c == 'H' ) pad1->PCTempKeyState.RightStickY = -128;
+ if ( c == 'Z' ) pad1->PCTempKeyState.LeftShoulder1 = 255;
+ if ( c == 'X' ) pad1->PCTempKeyState.LeftShoulder2 = 255;
+ if ( c == 'C' ) pad1->PCTempKeyState.RightShoulder1 = 255;
+ if ( c == 'V' ) pad1->PCTempKeyState.RightShoulder2 = 255;
+ if ( c == 'O' ) pad1->PCTempKeyState.DPadUp = 255;
+ if ( c == 'L' ) pad1->PCTempKeyState.DPadDown = 255;
+ if ( c == 'K' ) pad1->PCTempKeyState.DPadLeft = 255;
+ if ( c == ';' ) pad1->PCTempKeyState.DPadRight = 255;
+ if ( c == 'B' ) pad1->PCTempKeyState.Start = 255;
+ if ( c == 'N' ) pad1->PCTempKeyState.Select = 255;
+ if ( c == 'M' ) pad1->PCTempKeyState.Square = 255;
+ if ( c == ',' ) pad1->PCTempKeyState.Triangle = 255;
+ if ( c == '.' ) pad1->PCTempKeyState.Cross = 255;
+ if ( c == '/' ) pad1->PCTempKeyState.Circle = 255;
+ if ( c == rsRSHIFT ) pad1->PCTempKeyState.LeftShock = 255;
+ if ( c == rsRCTRL ) pad1->PCTempKeyState.RightShock = 255;
+ }
+ }
+
+ return rsEVENTPROCESSED;
+}
+
+
+static RsEventStatus
+HandleKeyUp(RsKeyStatus *keyStatus)
+{
+ CPad *pad0 = CPad::GetPad(0);
+ CPad *pad1 = CPad::GetPad(1);
+
+ RwInt32 c = keyStatus->keyCharCode;
+
+ if ( c != rsNULL )
+ {
+ switch (c)
+ {
+ case rsESC:
+ {
+ CPad::TempKeyState.ESC = 0;
+ break;
+ }
+
+ case rsINS:
+ {
+ CPad::TempKeyState.INS = 0;
+ break;
+ }
+
+ case rsDEL:
+ {
+ CPad::TempKeyState.DEL = 0;
+ break;
+ }
+
+ case rsHOME:
+ {
+ CPad::TempKeyState.HOME = 0;
+ break;
+ }
+
+ case rsEND:
+ {
+ CPad::TempKeyState.END = 0;
+ break;
+ }
+
+ case rsPGUP:
+ {
+ CPad::TempKeyState.PGUP = 0;
+ break;
+ }
+
+ case rsPGDN:
+ {
+ CPad::TempKeyState.PGDN = 0;
+ break;
+ }
+
+ case rsUP:
+ {
+ CPad::TempKeyState.UP = 0;
+ break;
+ }
+
+ case rsDOWN:
+ {
+ CPad::TempKeyState.DOWN = 0;
+ break;
+ }
+
+ case rsLEFT:
+ {
+ CPad::TempKeyState.LEFT = 0;
+ break;
+ }
+
+ case rsRIGHT:
+ {
+ CPad::TempKeyState.RIGHT = 0;
+ break;
+ }
+
+ case rsNUMLOCK:
+ {
+ CPad::TempKeyState.NUMLOCK = 0;
+ break;
+ }
+
+ case rsPADDEL:
+ {
+ CPad::TempKeyState.DECIMAL = 0;
+ break;
+ }
+
+ case rsPADEND:
+ {
+ CPad::TempKeyState.NUM1 = 0;
+ break;
+ }
+
+ case rsPADDOWN:
+ {
+ CPad::TempKeyState.NUM2 = 0;
+ break;
+ }
+
+ case rsPADPGDN:
+ {
+ CPad::TempKeyState.NUM3 = 0;
+ break;
+ }
+
+ case rsPADLEFT:
+ {
+ CPad::TempKeyState.NUM4 = 0;
+ break;
+ }
+
+ case rsPAD5:
+ {
+ CPad::TempKeyState.NUM5 = 0;
+ break;
+ }
+
+ case rsPADRIGHT:
+ {
+ CPad::TempKeyState.NUM6 = 0;
+ break;
+ }
+
+ case rsPADHOME:
+ {
+ CPad::TempKeyState.NUM7 = 0;
+ break;
+ }
+
+ case rsPADUP:
+ {
+ CPad::TempKeyState.NUM8 = 0;
+ break;
+ }
+
+ case rsPADPGUP:
+ {
+ CPad::TempKeyState.NUM9 = 0;
+ break;
+ }
+
+ case rsPADINS:
+ {
+ CPad::TempKeyState.NUM0 = 0;
+ break;
+ }
+
+ case rsDIVIDE:
+ {
+ CPad::TempKeyState.DIV = 0;
+ break;
+ }
+
+ case rsTIMES:
+ {
+ CPad::TempKeyState.MUL = 0;
+ break;
+ }
+
+ case rsMINUS:
+ {
+ CPad::TempKeyState.SUB = 0;
+ break;
+ }
+
+ case rsPADENTER:
+ {
+ CPad::TempKeyState.ENTER = 0;
+ break;
+ }
+
+ case rsPLUS:
+ {
+ CPad::TempKeyState.ADD = 0;
+ break;
+ }
+
+ case rsENTER:
+ {
+ CPad::TempKeyState.EXTENTER = 0;
+ break;
+ }
+
+ case rsSCROLL:
+ {
+ CPad::TempKeyState.SCROLLLOCK = 0;
+ break;
+ }
+
+ case rsPAUSE:
+ {
+ CPad::TempKeyState.PAUSE = 0;
+ break;
+ }
+
+ case rsBACKSP:
+ {
+ CPad::TempKeyState.BACKSP = 0;
+ break;
+ }
+
+ case rsTAB:
+ {
+ CPad::TempKeyState.TAB = 0;
+ break;
+ }
+
+ case rsCAPSLK:
+ {
+ CPad::TempKeyState.CAPSLOCK = 0;
+ break;
+ }
+
+ case rsLSHIFT:
+ {
+ CPad::TempKeyState.LSHIFT = 0;
+ break;
+ }
+
+ case rsSHIFT:
+ {
+ CPad::TempKeyState.SHIFT = 0;
+ break;
+ }
+
+ case rsRSHIFT:
+ {
+ CPad::TempKeyState.RSHIFT = 0;
+ break;
+ }
+
+ case rsLCTRL:
+ {
+ CPad::TempKeyState.LCTRL = 0;
+ break;
+ }
+
+ case rsRCTRL:
+ {
+ CPad::TempKeyState.RCTRL = 0;
+ break;
+ }
+
+ case rsLALT:
+ {
+ CPad::TempKeyState.LALT = 0;
+ break;
+ }
+
+ case rsRALT:
+ {
+ CPad::TempKeyState.RALT = 0;
+ break;
+ }
+
+
+ case rsLWIN:
+ {
+ CPad::TempKeyState.LWIN = 0;
+ break;
+ }
+
+ case rsRWIN:
+ {
+ CPad::TempKeyState.RWIN = 0;
+ break;
+ }
+
+ case rsAPPS:
+ {
+ CPad::TempKeyState.APPS = 0;
+ break;
+ }
+
+ case rsF1:
+ case rsF2:
+ case rsF3:
+ case rsF4:
+ case rsF5:
+ case rsF6:
+ case rsF7:
+ case rsF8:
+ case rsF9:
+ case rsF10:
+ case rsF11:
+ case rsF12:
+ {
+ CPad::TempKeyState.F[c - rsF1] = 0;
+ break;
+ }
+
+ default:
+ {
+ if ( c < 255 )
+ {
+ CPad::TempKeyState.VK_KEYS[c] = 0;
+ }
+ break;
+ }
+ }
+
+ if ( CPad::m_bMapPadOneToPadTwo )
+ {
+ if ( c == 'D' ) pad1->PCTempKeyState.LeftStickX = 0;
+ if ( c == 'A' ) pad1->PCTempKeyState.LeftStickX = 0;
+ if ( c == 'W' ) pad1->PCTempKeyState.LeftStickY = 0;
+ if ( c == 'S' ) pad1->PCTempKeyState.LeftStickY = 0;
+ if ( c == 'J' ) pad1->PCTempKeyState.RightStickX = 0;
+ if ( c == 'G' ) pad1->PCTempKeyState.RightStickX = 0;
+ if ( c == 'Y' ) pad1->PCTempKeyState.RightStickY = 0;
+ if ( c == 'H' ) pad1->PCTempKeyState.RightStickY = 0;
+ if ( c == 'Z' ) pad1->PCTempKeyState.LeftShoulder1 = 0;
+ if ( c == 'X' ) pad1->PCTempKeyState.LeftShoulder2 = 0;
+ if ( c == 'C' ) pad1->PCTempKeyState.RightShoulder1 = 0;
+ if ( c == 'V' ) pad1->PCTempKeyState.RightShoulder2 = 0;
+ if ( c == 'O' ) pad1->PCTempKeyState.DPadUp = 0;
+ if ( c == 'L' ) pad1->PCTempKeyState.DPadDown = 0;
+ if ( c == 'K' ) pad1->PCTempKeyState.DPadLeft = 0;
+ if ( c == ';' ) pad1->PCTempKeyState.DPadRight = 0;
+ if ( c == 'B' ) pad1->PCTempKeyState.Start = 0;
+ if ( c == 'N' ) pad1->PCTempKeyState.Select = 0;
+ if ( c == 'M' ) pad1->PCTempKeyState.Square = 0;
+ if ( c == ',' ) pad1->PCTempKeyState.Triangle = 0;
+ if ( c == '.' ) pad1->PCTempKeyState.Cross = 0;
+ if ( c == '/' ) pad1->PCTempKeyState.Circle = 0;
+ if ( c == rsRSHIFT ) pad1->PCTempKeyState.LeftShock = 0;
+ if ( c == rsRCTRL ) pad1->PCTempKeyState.RightShock = 0;
+ }
+ }
+
+ return rsEVENTPROCESSED;
+}
+
+
+/*
+ *****************************************************************************
+ */
+static RsEventStatus
+KeyboardHandler(RsEvent event, void *param)
+{
+ /*
+ * ...then the application events, if necessary...
+ */
+ switch( event )
+ {
+ case rsKEYDOWN:
+ {
+ return HandleKeyDown((RsKeyStatus *)param);
+ }
+
+ case rsKEYUP:
+ {
+ return HandleKeyUp((RsKeyStatus *)param);
+ }
+
+ default:
+ {
+ return rsEVENTNOTPROCESSED;
+ }
+ }
+}
+
+/*
+ *****************************************************************************
+ */
+static RsEventStatus
+HandlePadButtonDown(RsPadButtonStatus *padButtonStatus)
+{
+ bool bPadTwo = false;
+ int32 padNumber = padButtonStatus->padID;
+
+ CPad *pad = CPad::GetPad(padNumber);
+
+ if ( CPad::m_bMapPadOneToPadTwo )
+ padNumber = 1;
+
+ if ( padNumber == 1 )
+ bPadTwo = true;
+
+ ControlsManager.UpdateJoyButtonState(padNumber);
+
+ for ( int32 i = 0; i < _TODOCONST(16); i++ )
+ {
+ RsPadButtons btn = rsPADNULL;
+ if ( ControlsManager.m_aButtonStates[i] == TRUE )
+ btn = (RsPadButtons)(i + 1);
+
+ if ( FrontEndMenuManager.m_bMenuActive || bPadTwo )
+ ControlsManager.UpdateJoyInConfigMenus_ButtonDown(btn, padNumber);
+ else
+ ControlsManager.AffectControllerStateOn_ButtonDown(btn, JOYSTICK);
+ }
+
+ return rsEVENTPROCESSED;
+}
+
+
+/*
+ *****************************************************************************
+ */
+static RsEventStatus
+HandlePadButtonUp(RsPadButtonStatus *padButtonStatus)
+{
+ bool bPadTwo = false;
+ int32 padNumber = padButtonStatus->padID;
+
+ CPad *pad = CPad::GetPad(padNumber);
+
+ if ( CPad::m_bMapPadOneToPadTwo )
+ padNumber = 1;
+
+ if ( padNumber == 1 )
+ bPadTwo = true;
+
+ bool bCam = false;
+ int16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
+ if ( mode == CCam::MODE_FLYBY || mode == CCam::MODE_FIXED )
+ bCam = true;
+
+ ControlsManager.UpdateJoyButtonState(padNumber);
+
+ for ( int32 i = 1; i < _TODOCONST(16); i++ )
+ {
+ RsPadButtons btn = rsPADNULL;
+ if ( ControlsManager.m_aButtonStates[i] == FALSE )
+ btn = (RsPadButtons)(i + 1); // bug ?, cycle begins from 1(not zero), 1+1==2==rsPADBUTTON2, so we skip rsPADBUTTON1, right ?
+
+ if ( FrontEndMenuManager.m_bMenuActive || bPadTwo || bCam )
+ ControlsManager.UpdateJoyInConfigMenus_ButtonUp(btn, padNumber);
+ else
+ ControlsManager.AffectControllerStateOn_ButtonUp(btn, JOYSTICK);
+ }
+
+ return rsEVENTPROCESSED;
+}
+
+/*
+ *****************************************************************************
+ */
+static RsEventStatus
+PadHandler(RsEvent event, void *param)
+{
+ switch( event )
+ {
+ case rsPADBUTTONDOWN:
+ {
+ return HandlePadButtonDown((RsPadButtonStatus *)param);
+ }
+
+ case rsPADBUTTONUP:
+ {
+ return HandlePadButtonUp((RsPadButtonStatus *)param);
+ }
+
+ default:
+ {
+ return rsEVENTNOTPROCESSED;
+ }
+ }
+}
+
+
+/*
+ *****************************************************************************
+ */
+RwBool
+AttachInputDevices(void)
+{
+ RsInputDeviceAttach(rsKEYBOARD, KeyboardHandler);
+
+ RsInputDeviceAttach(rsPAD, PadHandler);
+
+ return TRUE;
+}
diff --git a/src/skel/events.h b/src/skel/events.h
new file mode 100644
index 0000000..ef812eb
--- /dev/null
+++ b/src/skel/events.h
@@ -0,0 +1,7 @@
+#ifndef EVENTS_H
+#define EVENTS_H
+
+#include <rwcore.h>
+#include "skeleton.h"
+
+#endif /* EVENTS_H */
diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp
new file mode 100644
index 0000000..f5195b8
--- /dev/null
+++ b/src/skel/glfw/glfw.cpp
@@ -0,0 +1,2528 @@
+#if defined RW_GL3 && !defined LIBRW_SDL2
+
+#ifdef _WIN32
+#include <shlobj.h>
+#include <basetsd.h>
+#include <mmsystem.h>
+#include <regstr.h>
+#include <shellapi.h>
+#include <windowsx.h>
+
+DWORD _dwOperatingSystemVersion;
+#include "resource.h"
+#else
+long _dwOperatingSystemVersion;
+#ifndef __APPLE__
+#include <sys/sysinfo.h>
+#else
+#include <mach/mach_host.h>
+#include <sys/sysctl.h>
+#endif
+#include <errno.h>
+#include <locale.h>
+#include <signal.h>
+#include <stddef.h>
+#endif
+
+#include "common.h"
+#if (defined(_MSC_VER))
+#include <tchar.h>
+#endif /* (defined(_MSC_VER)) */
+#include <stdio.h>
+#include "rwcore.h"
+#include "skeleton.h"
+#include "platform.h"
+#include "crossplatform.h"
+
+#include "main.h"
+#include "FileMgr.h"
+#include "Text.h"
+#include "Pad.h"
+#include "Timer.h"
+#include "DMAudio.h"
+#include "ControllerConfig.h"
+#include "Frontend.h"
+#include "Game.h"
+#include "PCSave.h"
+#include "MemoryCard.h"
+#include "Sprite2d.h"
+#include "AnimViewer.h"
+#include "Font.h"
+#include "MemoryMgr.h"
+
+// We found out that GLFW's keyboard input handling is still pretty delayed/not stable, so now we fetch input from X11 directly on Linux.
+#if !defined _WIN32 && !defined __APPLE__ && !defined __SWITCH__ // && !defined WAYLAND
+#define GET_KEYBOARD_INPUT_FROM_X11
+#endif
+
+#ifdef GET_KEYBOARD_INPUT_FROM_X11
+#include <X11/Xlib.h>
+#include <X11/XKBlib.h>
+#define GLFW_EXPOSE_NATIVE_X11
+#include <GLFW/glfw3native.h>
+#endif
+
+#ifdef _WIN32
+#define GLFW_EXPOSE_NATIVE_WIN32
+#include <GLFW/glfw3native.h>
+#endif
+
+#define MAX_SUBSYSTEMS (16)
+
+rw::EngineOpenParams openParams;
+
+static RwBool ForegroundApp = TRUE;
+static RwBool WindowIconified = FALSE;
+static RwBool WindowFocused = TRUE;
+
+static RwBool RwInitialised = FALSE;
+
+static RwSubSystemInfo GsubSysInfo[MAX_SUBSYSTEMS];
+static RwInt32 GnumSubSystems = 0;
+static RwInt32 GcurSel = 0, GcurSelVM = 0;
+
+static RwBool useDefault;
+
+// What is that for anyway?
+#ifndef IMPROVED_VIDEOMODE
+static RwBool defaultFullscreenRes = TRUE;
+#else
+static RwBool defaultFullscreenRes = FALSE;
+static RwInt32 bestWndMode = -1;
+#endif
+
+static psGlobalType PsGlobal;
+
+
+#define PSGLOBAL(var) (((psGlobalType *)(RsGlobal.ps))->var)
+
+size_t _dwMemAvailPhys;
+RwUInt32 gGameState;
+
+#ifdef DETECT_JOYSTICK_MENU
+char gSelectedJoystickName[128] = "";
+#endif
+
+/*
+ *****************************************************************************
+ */
+void _psCreateFolder(const char *path)
+{
+#ifdef _WIN32
+ HANDLE hfle = CreateFile(path, GENERIC_READ,
+ FILE_SHARE_READ,
+ nil,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
+ nil);
+
+ if ( hfle == INVALID_HANDLE_VALUE )
+ CreateDirectory(path, nil);
+ else
+ CloseHandle(hfle);
+#else
+ struct stat info;
+ char fullpath[PATH_MAX];
+ realpath(path, fullpath);
+
+ if (lstat(fullpath, &info) != 0) {
+ if (errno == ENOENT || (errno != EACCES && !S_ISDIR(info.st_mode))) {
+ mkdir(fullpath, 0755);
+ }
+ }
+#endif
+}
+
+/*
+ *****************************************************************************
+ */
+const char *_psGetUserFilesFolder()
+{
+#if defined USE_MY_DOCUMENTS && defined _WIN32
+ HKEY hKey = NULL;
+
+ static CHAR szUserFiles[256];
+
+ if ( RegOpenKeyEx(HKEY_CURRENT_USER,
+ REGSTR_PATH_SPECIAL_FOLDERS,
+ REG_OPTION_RESERVED,
+ KEY_READ,
+ &hKey) == ERROR_SUCCESS )
+ {
+ DWORD KeyType;
+ DWORD KeycbData = sizeof(szUserFiles);
+ if ( RegQueryValueEx(hKey,
+ "Personal",
+ NULL,
+ &KeyType,
+ (LPBYTE)szUserFiles,
+ &KeycbData) == ERROR_SUCCESS )
+ {
+ RegCloseKey(hKey);
+ strcat(szUserFiles, "\\GTA Vice City User Files");
+ _psCreateFolder(szUserFiles);
+ return szUserFiles;
+ }
+
+ RegCloseKey(hKey);
+ }
+
+ strcpy(szUserFiles, "data");
+ return szUserFiles;
+#else
+ static char szUserFiles[256];
+ strcpy(szUserFiles, "userfiles");
+ _psCreateFolder(szUserFiles);
+ return szUserFiles;
+#endif
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+psCameraBeginUpdate(RwCamera *camera)
+{
+ if ( !RwCameraBeginUpdate(Scene.camera) )
+ {
+ ForegroundApp = FALSE;
+ RsEventHandler(rsACTIVATE, (void *)FALSE);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ *****************************************************************************
+ */
+void
+psCameraShowRaster(RwCamera *camera)
+{
+#ifdef LEGACY_MENU_OPTIONS
+ if (FrontEndMenuManager.m_PrefsVsync || FrontEndMenuManager.m_bMenuActive)
+#else
+ if (FrontEndMenuManager.m_PrefsFrameLimiter || FrontEndMenuManager.m_bMenuActive)
+#endif
+ RwCameraShowRaster(camera, PSGLOBAL(window), rwRASTERFLIPWAITVSYNC);
+ else
+ RwCameraShowRaster(camera, PSGLOBAL(window), rwRASTERFLIPDONTWAIT);
+
+ return;
+}
+
+/*
+ *****************************************************************************
+ */
+RwImage *
+psGrabScreen(RwCamera *pCamera)
+{
+#ifndef LIBRW
+ RwRaster *pRaster = RwCameraGetRaster(pCamera);
+ if (RwImage *pImage = RwImageCreate(pRaster->width, pRaster->height, 32)) {
+ RwImageAllocatePixels(pImage);
+ RwImageSetFromRaster(pImage, pRaster);
+ return pImage;
+ }
+#else
+ rw::Image *image = RwCameraGetRaster(pCamera)->toImage();
+ image->removeMask();
+ if(image)
+ return image;
+#endif
+ return nil;
+}
+
+/*
+ *****************************************************************************
+ */
+#ifdef _WIN32
+#pragma comment( lib, "Winmm.lib" ) // Needed for time
+RwUInt32
+psTimer(void)
+{
+ RwUInt32 time;
+
+ TIMECAPS TimeCaps;
+
+ timeGetDevCaps(&TimeCaps, sizeof(TIMECAPS));
+
+ timeBeginPeriod(TimeCaps.wPeriodMin);
+
+ time = (RwUInt32) timeGetTime();
+
+ timeEndPeriod(TimeCaps.wPeriodMin);
+
+ return time;
+}
+#else
+double
+psTimer(void)
+{
+ struct timespec start;
+#if defined(CLOCK_MONOTONIC_RAW)
+ clock_gettime(CLOCK_MONOTONIC_RAW, &start);
+#elif defined(CLOCK_MONOTONIC_FAST)
+ clock_gettime(CLOCK_MONOTONIC_FAST, &start);
+#else
+ clock_gettime(CLOCK_MONOTONIC, &start);
+#endif
+ return start.tv_sec * 1000.0 + start.tv_nsec/1000000.0;
+}
+#endif
+
+
+/*
+ *****************************************************************************
+ */
+void
+psMouseSetPos(RwV2d *pos)
+{
+ glfwSetCursorPos(PSGLOBAL(window), pos->x, pos->y);
+
+ PSGLOBAL(lastMousePos.x) = (RwInt32)pos->x;
+
+ PSGLOBAL(lastMousePos.y) = (RwInt32)pos->y;
+
+ return;
+}
+
+/*
+ *****************************************************************************
+ */
+RwMemoryFunctions*
+psGetMemoryFunctions(void)
+{
+#ifdef USE_CUSTOM_ALLOCATOR
+ return &memFuncs;
+#else
+ return nil;
+#endif
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+psInstallFileSystem(void)
+{
+ return (TRUE);
+}
+
+
+/*
+ *****************************************************************************
+ */
+RwBool
+psNativeTextureSupport(void)
+{
+ return true;
+}
+
+/*
+ *****************************************************************************
+ */
+#ifdef UNDER_CE
+#define CMDSTR LPWSTR
+#else
+#define CMDSTR LPSTR
+#endif
+
+/*
+ *****************************************************************************
+ */
+RwBool
+psInitialize(void)
+{
+ PsGlobal.lastMousePos.x = PsGlobal.lastMousePos.y = 0.0f;
+
+ RsGlobal.ps = &PsGlobal;
+
+ PsGlobal.fullScreen = FALSE;
+ PsGlobal.cursorIsInWindow = FALSE;
+ WindowFocused = TRUE;
+ WindowIconified = FALSE;
+
+ PsGlobal.joy1id = -1;
+ PsGlobal.joy2id = -1;
+
+ CFileMgr::Initialise();
+
+#ifdef PS2_MENU
+ CPad::Initialise();
+ CPad::GetPad(0)->Mode = 0;
+
+ CGame::frenchGame = false;
+ CGame::germanGame = false;
+ CGame::nastyGame = true;
+ CMenuManager::m_PrefsAllowNastyGame = true;
+
+#ifndef _WIN32
+ // Mandatory for Linux(Unix? Posix?) to set lang. to environment lang.
+ setlocale(LC_ALL, "");
+
+ char *systemLang, *keyboardLang;
+
+ systemLang = setlocale (LC_ALL, NULL);
+ keyboardLang = setlocale (LC_CTYPE, NULL);
+
+ short lang;
+ lang = !strncmp(systemLang, "fr_",3) ? LANG_FRENCH :
+ !strncmp(systemLang, "de_",3) ? LANG_GERMAN :
+ !strncmp(systemLang, "en_",3) ? LANG_ENGLISH :
+ !strncmp(systemLang, "it_",3) ? LANG_ITALIAN :
+ !strncmp(systemLang, "es_",3) ? LANG_SPANISH :
+ LANG_OTHER;
+#else
+ WORD lang = PRIMARYLANGID(GetSystemDefaultLCID());
+#endif
+
+ if ( lang == LANG_ITALIAN )
+ CMenuManager::m_PrefsLanguage = CMenuManager::LANGUAGE_ITALIAN;
+ else if ( lang == LANG_SPANISH )
+ CMenuManager::m_PrefsLanguage = CMenuManager::LANGUAGE_SPANISH;
+ else if ( lang == LANG_GERMAN )
+ {
+ CGame::germanGame = true;
+ CGame::nastyGame = false;
+ CMenuManager::m_PrefsAllowNastyGame = false;
+ CMenuManager::m_PrefsLanguage = CMenuManager::LANGUAGE_GERMAN;
+ }
+ else if ( lang == LANG_FRENCH )
+ {
+ CGame::frenchGame = true;
+ CGame::nastyGame = false;
+ CMenuManager::m_PrefsAllowNastyGame = false;
+ CMenuManager::m_PrefsLanguage = CMenuManager::LANGUAGE_FRENCH;
+ }
+ else
+ CMenuManager::m_PrefsLanguage = CMenuManager::LANGUAGE_AMERICAN;
+
+ FrontEndMenuManager.InitialiseMenuContentsAfterLoadingGame();
+
+ TheMemoryCard.Init();
+#else
+ C_PcSave::SetSaveDirectory(_psGetUserFilesFolder());
+
+ InitialiseLanguage();
+
+#endif
+
+ gGameState = GS_START_UP;
+ TRACE("gGameState = GS_START_UP");
+#ifdef _WIN32
+ OSVERSIONINFO verInfo;
+ verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+ GetVersionEx(&verInfo);
+
+ _dwOperatingSystemVersion = OS_WIN95;
+
+ if ( verInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+ {
+ if ( verInfo.dwMajorVersion == 4 )
+ {
+ debug("Operating System is WinNT\n");
+ _dwOperatingSystemVersion = OS_WINNT;
+ }
+ else if ( verInfo.dwMajorVersion == 5 )
+ {
+ debug("Operating System is Win2000\n");
+ _dwOperatingSystemVersion = OS_WIN2000;
+ }
+ else if ( verInfo.dwMajorVersion > 5 )
+ {
+ debug("Operating System is WinXP or greater\n");
+ _dwOperatingSystemVersion = OS_WINXP;
+ }
+ }
+ else if ( verInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
+ {
+ if ( verInfo.dwMajorVersion > 4 || verInfo.dwMajorVersion == 4 && verInfo.dwMinorVersion != 0 )
+ {
+ debug("Operating System is Win98\n");
+ _dwOperatingSystemVersion = OS_WIN98;
+ }
+ else
+ {
+ debug("Operating System is Win95\n");
+ _dwOperatingSystemVersion = OS_WIN95;
+ }
+ }
+#else
+ _dwOperatingSystemVersion = OS_WINXP; // To fool other classes
+#endif
+
+
+#ifndef PS2_MENU
+ FrontEndMenuManager.LoadSettings();
+#endif
+
+
+#ifdef _WIN32
+ MEMORYSTATUS memstats;
+ GlobalMemoryStatus(&memstats);
+
+ _dwMemAvailPhys = memstats.dwAvailPhys;
+
+ debug("Physical memory size %u\n", memstats.dwTotalPhys);
+ debug("Available physical memory %u\n", memstats.dwAvailPhys);
+#elif defined (__APPLE__)
+ uint64_t size = 0;
+ uint64_t page_size = 0;
+ size_t uint64_len = sizeof(uint64_t);
+ size_t ull_len = sizeof(unsigned long long);
+ sysctl((int[]){CTL_HW, HW_PAGESIZE}, 2, &page_size, &ull_len, NULL, 0);
+ sysctl((int[]){CTL_HW, HW_MEMSIZE}, 2, &size, &uint64_len, NULL, 0);
+ vm_statistics_data_t vm_stat;
+ mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+ host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stat, &count);
+ _dwMemAvailPhys = (uint64_t)(vm_stat.free_count * page_size);
+ debug("Physical memory size %llu\n", _dwMemAvailPhys);
+ debug("Available physical memory %llu\n", size);
+#else
+#ifndef __APPLE__
+ struct sysinfo systemInfo;
+ sysinfo(&systemInfo);
+ _dwMemAvailPhys = systemInfo.freeram;
+ debug("Physical memory size %u\n", systemInfo.totalram);
+ debug("Available physical memory %u\n", systemInfo.freeram);
+#else
+ uint64_t size = 0;
+ uint64_t page_size = 0;
+ size_t uint64_len = sizeof(uint64_t);
+ size_t ull_len = sizeof(unsigned long long);
+ sysctl((int[]){CTL_HW, HW_PAGESIZE}, 2, &page_size, &ull_len, NULL, 0);
+ sysctl((int[]){CTL_HW, HW_MEMSIZE}, 2, &size, &uint64_len, NULL, 0);
+ vm_statistics_data_t vm_stat;
+ mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+ host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stat, &count);
+ _dwMemAvailPhys = (uint64_t)(vm_stat.free_count * page_size);
+ debug("Physical memory size %llu\n", _dwMemAvailPhys);
+ debug("Available physical memory %llu\n", size);
+#endif
+ _dwOperatingSystemVersion = OS_WINXP; // To fool other classes
+#endif
+
+ TheText.Unload();
+
+ return TRUE;
+}
+
+
+/*
+ *****************************************************************************
+ */
+void
+psTerminate(void)
+{
+ return;
+}
+
+/*
+ *****************************************************************************
+ */
+static RwChar **_VMList;
+
+RwInt32 _psGetNumVideModes()
+{
+ return RwEngineGetNumVideoModes();
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool _psFreeVideoModeList()
+{
+ RwInt32 numModes;
+ RwInt32 i;
+
+ numModes = _psGetNumVideModes();
+
+ if ( _VMList == nil )
+ return TRUE;
+
+ for ( i = 0; i < numModes; i++ )
+ {
+ RwFree(_VMList[i]);
+ }
+
+ RwFree(_VMList);
+
+ _VMList = nil;
+
+ return TRUE;
+}
+
+/*
+ *****************************************************************************
+ */
+RwChar **_psGetVideoModeList()
+{
+ RwInt32 numModes;
+ RwInt32 i;
+
+ if ( _VMList != nil )
+ {
+ return _VMList;
+ }
+
+ numModes = RwEngineGetNumVideoModes();
+
+ _VMList = (RwChar **)RwCalloc(numModes, sizeof(RwChar*));
+
+ for ( i = 0; i < numModes; i++ )
+ {
+ RwVideoMode vm;
+
+ RwEngineGetVideoModeInfo(&vm, i);
+
+ if ( vm.flags & rwVIDEOMODEEXCLUSIVE )
+ {
+ _VMList[i] = (RwChar*)RwCalloc(100, sizeof(RwChar));
+ rwsprintf(_VMList[i],"%d X %d X %d", vm.width, vm.height, vm.depth);
+ }
+ else
+ _VMList[i] = nil;
+ }
+
+ return _VMList;
+}
+
+/*
+ *****************************************************************************
+ */
+void _psSelectScreenVM(RwInt32 videoMode)
+{
+ RwTexDictionarySetCurrent( nil );
+
+ FrontEndMenuManager.UnloadTextures();
+
+ if (!_psSetVideoMode(RwEngineGetCurrentSubSystem(), videoMode))
+ {
+ RsGlobal.quit = TRUE;
+
+ printf("ERROR: Failed to select new screen resolution\n");
+ }
+ else
+ FrontEndMenuManager.LoadAllTextures();
+}
+
+/*
+ *****************************************************************************
+ */
+
+RwBool IsForegroundApp()
+{
+ return !!ForegroundApp;
+}
+/*
+UINT GetBestRefreshRate(UINT width, UINT height, UINT depth)
+{
+ LPDIRECT3D8 d3d = Direct3DCreate8(D3D_SDK_VERSION);
+
+ ASSERT(d3d != nil);
+
+ UINT refreshRate = INT_MAX;
+ D3DFORMAT format;
+
+ if ( depth == 32 )
+ format = D3DFMT_X8R8G8B8;
+ else if ( depth == 24 )
+ format = D3DFMT_R8G8B8;
+ else
+ format = D3DFMT_R5G6B5;
+
+ UINT modeCount = d3d->GetAdapterModeCount(GcurSel);
+
+ for ( UINT i = 0; i < modeCount; i++ )
+ {
+ D3DDISPLAYMODE mode;
+
+ d3d->EnumAdapterModes(GcurSel, i, &mode);
+
+ if ( mode.Width == width && mode.Height == height && mode.Format == format )
+ {
+ if ( mode.RefreshRate == 0 )
+ return 0;
+
+ if ( mode.RefreshRate < refreshRate && mode.RefreshRate >= 60 )
+ refreshRate = mode.RefreshRate;
+ }
+ }
+
+#ifdef FIX_BUGS
+ d3d->Release();
+#endif
+
+ if ( refreshRate == -1 )
+ return -1;
+
+ return refreshRate;
+}
+*/
+/*
+ *****************************************************************************
+ */
+RwBool
+psSelectDevice()
+{
+ RwVideoMode vm;
+ RwInt32 subSysNum;
+ RwInt32 AutoRenderer = 0;
+
+
+ RwBool modeFound = FALSE;
+
+ if ( !useDefault )
+ {
+ GnumSubSystems = RwEngineGetNumSubSystems();
+ if ( !GnumSubSystems )
+ {
+ return FALSE;
+ }
+
+ /* Just to be sure ... */
+ GnumSubSystems = (GnumSubSystems > MAX_SUBSYSTEMS) ? MAX_SUBSYSTEMS : GnumSubSystems;
+
+ /* Get the names of all the sub systems */
+ for (subSysNum = 0; subSysNum < GnumSubSystems; subSysNum++)
+ {
+ RwEngineGetSubSystemInfo(&GsubSysInfo[subSysNum], subSysNum);
+ }
+
+ /* Get the default selection */
+ GcurSel = RwEngineGetCurrentSubSystem();
+#ifdef IMPROVED_VIDEOMODE
+ if(FrontEndMenuManager.m_nPrefsSubsystem < GnumSubSystems)
+ GcurSel = FrontEndMenuManager.m_nPrefsSubsystem;
+#endif
+ }
+
+ /* Set the driver to use the correct sub system */
+ if (!RwEngineSetSubSystem(GcurSel))
+ {
+ return FALSE;
+ }
+
+#ifdef IMPROVED_VIDEOMODE
+ FrontEndMenuManager.m_nPrefsSubsystem = GcurSel;
+#endif
+
+#ifndef IMPROVED_VIDEOMODE
+ if ( !useDefault )
+ {
+ if ( _psGetVideoModeList()[FrontEndMenuManager.m_nDisplayVideoMode] && FrontEndMenuManager.m_nDisplayVideoMode )
+ {
+ FrontEndMenuManager.m_nPrefsVideoMode = FrontEndMenuManager.m_nDisplayVideoMode;
+ GcurSelVM = FrontEndMenuManager.m_nDisplayVideoMode;
+ }
+ else
+ {
+#ifdef DEFAULT_NATIVE_RESOLUTION
+ // get the native video mode
+ HDC hDevice = GetDC(NULL);
+ int w = GetDeviceCaps(hDevice, HORZRES);
+ int h = GetDeviceCaps(hDevice, VERTRES);
+ int d = GetDeviceCaps(hDevice, BITSPIXEL);
+#else
+ const int w = 640;
+ const int h = 480;
+ const int d = 16;
+#endif
+ while ( !modeFound && GcurSelVM < RwEngineGetNumVideoModes() )
+ {
+ RwEngineGetVideoModeInfo(&vm, GcurSelVM);
+ if ( defaultFullscreenRes && vm.width != w
+ || vm.height != h
+ || vm.depth != d
+ || !(vm.flags & rwVIDEOMODEEXCLUSIVE) )
+ ++GcurSelVM;
+ else
+ modeFound = TRUE;
+ }
+
+ if ( !modeFound )
+ {
+#ifdef DEFAULT_NATIVE_RESOLUTION
+ GcurSelVM = 1;
+#else
+ printf("WARNING: Cannot find 640x480 video mode, selecting device cancelled\n");
+ return FALSE;
+#endif
+ }
+ }
+ }
+#else
+ if ( !useDefault )
+ {
+ if(FrontEndMenuManager.m_nPrefsWidth == 0 ||
+ FrontEndMenuManager.m_nPrefsHeight == 0 ||
+ FrontEndMenuManager.m_nPrefsDepth == 0){
+ // Defaults if nothing specified
+ const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
+ FrontEndMenuManager.m_nPrefsWidth = mode->width;
+ FrontEndMenuManager.m_nPrefsHeight = mode->height;
+ FrontEndMenuManager.m_nPrefsDepth = 32;
+ FrontEndMenuManager.m_nPrefsWindowed = 0;
+ }
+
+ // Find the videomode that best fits what we got from the settings file
+ RwInt32 bestFsMode = -1;
+ RwInt32 bestWidth = -1;
+ RwInt32 bestHeight = -1;
+ RwInt32 bestDepth = -1;
+ for(GcurSelVM = 0; GcurSelVM < RwEngineGetNumVideoModes(); GcurSelVM++){
+ RwEngineGetVideoModeInfo(&vm, GcurSelVM);
+
+ if (!(vm.flags & rwVIDEOMODEEXCLUSIVE)){
+ bestWndMode = GcurSelVM;
+ } else {
+ // try the largest one that isn't larger than what we wanted
+ if(vm.width >= bestWidth && vm.width <= FrontEndMenuManager.m_nPrefsWidth &&
+ vm.height >= bestHeight && vm.height <= FrontEndMenuManager.m_nPrefsHeight &&
+ vm.depth >= bestDepth && vm.depth <= FrontEndMenuManager.m_nPrefsDepth){
+ bestWidth = vm.width;
+ bestHeight = vm.height;
+ bestDepth = vm.depth;
+ bestFsMode = GcurSelVM;
+ }
+ }
+ }
+
+ if(bestFsMode < 0){
+ printf("WARNING: Cannot find desired video mode, selecting device cancelled\n");
+ return FALSE;
+ }
+ GcurSelVM = bestFsMode;
+
+ FrontEndMenuManager.m_nDisplayVideoMode = GcurSelVM;
+ FrontEndMenuManager.m_nPrefsVideoMode = FrontEndMenuManager.m_nDisplayVideoMode;
+
+ FrontEndMenuManager.m_nSelectedScreenMode = FrontEndMenuManager.m_nPrefsWindowed;
+ }
+#endif
+
+ RwEngineGetVideoModeInfo(&vm, GcurSelVM);
+
+#ifdef IMPROVED_VIDEOMODE
+ if (FrontEndMenuManager.m_nPrefsWindowed)
+ GcurSelVM = bestWndMode;
+
+ // Now GcurSelVM is 0 but vm has sizes(and fullscreen flag) of the video mode we want, that's why we changed the rwVIDEOMODEEXCLUSIVE conditions below
+ FrontEndMenuManager.m_nPrefsWidth = vm.width;
+ FrontEndMenuManager.m_nPrefsHeight = vm.height;
+ FrontEndMenuManager.m_nPrefsDepth = vm.depth;
+#endif
+
+#ifndef PS2_MENU
+ FrontEndMenuManager.m_nCurrOption = 0;
+#endif
+
+ /* Set up the video mode and set the apps window
+ * dimensions to match */
+ if (!RwEngineSetVideoMode(GcurSelVM))
+ {
+ return FALSE;
+ }
+ /*
+ TODO
+ if (vm.flags & rwVIDEOMODEEXCLUSIVE)
+ {
+ debug("%dx%dx%d", vm.width, vm.height, vm.depth);
+
+ UINT refresh = GetBestRefreshRate(vm.width, vm.height, vm.depth);
+
+ if ( refresh != (UINT)-1 )
+ {
+ debug("refresh %d", refresh);
+ RwD3D8EngineSetRefreshRate((RwUInt32)refresh);
+ }
+ }
+ */
+#ifndef IMPROVED_VIDEOMODE
+ if (vm.flags & rwVIDEOMODEEXCLUSIVE)
+ {
+ RsGlobal.maximumWidth = vm.width;
+ RsGlobal.maximumHeight = vm.height;
+ RsGlobal.width = vm.width;
+ RsGlobal.height = vm.height;
+
+ PSGLOBAL(fullScreen) = TRUE;
+ }
+#else
+ RsGlobal.maximumWidth = FrontEndMenuManager.m_nPrefsWidth;
+ RsGlobal.maximumHeight = FrontEndMenuManager.m_nPrefsHeight;
+ RsGlobal.width = FrontEndMenuManager.m_nPrefsWidth;
+ RsGlobal.height = FrontEndMenuManager.m_nPrefsHeight;
+
+ PSGLOBAL(fullScreen) = !FrontEndMenuManager.m_nPrefsWindowed;
+#endif
+
+#ifdef MULTISAMPLING
+ RwD3D8EngineSetMultiSamplingLevels(1 << FrontEndMenuManager.m_nPrefsMSAALevel);
+#endif
+ return TRUE;
+}
+
+#ifndef GET_KEYBOARD_INPUT_FROM_X11
+void keypressCB(GLFWwindow* window, int key, int scancode, int action, int mods);
+#endif
+void resizeCB(GLFWwindow* window, int width, int height);
+void scrollCB(GLFWwindow* window, double xoffset, double yoffset);
+void cursorCB(GLFWwindow* window, double xpos, double ypos);
+void cursorEnterCB(GLFWwindow* window, int entered);
+void windowFocusCB(GLFWwindow* window, int focused);
+void windowIconifyCB(GLFWwindow* window, int iconified);
+void joysChangeCB(int jid, int event);
+
+bool IsThisJoystickBlacklisted(int i)
+{
+#ifndef DETECT_JOYSTICK_MENU
+ return false;
+#else
+ if (glfwJoystickIsGamepad(i))
+ return false;
+
+ const char* joyname = glfwGetJoystickName(i);
+
+ if (gSelectedJoystickName[0] != '\0' &&
+ strncmp(joyname, gSelectedJoystickName, strlen(gSelectedJoystickName)) == 0)
+ return false;
+
+ return true;
+#endif
+}
+
+void _InputInitialiseJoys()
+{
+ PSGLOBAL(joy1id) = -1;
+ PSGLOBAL(joy2id) = -1;
+
+ // Load our gamepad mappings.
+#define SDL_GAMEPAD_DB_PATH "gamecontrollerdb.txt"
+ FILE *f = fopen(SDL_GAMEPAD_DB_PATH, "rb");
+ if (f) {
+ fseek(f, 0, SEEK_END);
+ size_t fsize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ char *db = (char*)malloc(fsize + 1);
+ if (fread(db, 1, fsize, f) == fsize) {
+ db[fsize] = '\0';
+
+ if (glfwUpdateGamepadMappings(db) == GLFW_FALSE)
+ Error("glfwUpdateGamepadMappings didn't succeed, check " SDL_GAMEPAD_DB_PATH ".\n");
+ } else
+ Error("fread on " SDL_GAMEPAD_DB_PATH " wasn't successful.\n");
+
+ free(db);
+ fclose(f);
+ } else
+ printf("You don't seem to have copied " SDL_GAMEPAD_DB_PATH " file from re3/gamefiles to GTA3 directory. Some gamepads may not be recognized.\n");
+
+#undef SDL_GAMEPAD_DB_PATH
+
+ // But always overwrite it with the one in SDL_GAMECONTROLLERCONFIG.
+ char const* EnvControlConfig = getenv("SDL_GAMECONTROLLERCONFIG");
+ if (EnvControlConfig != nil) {
+ glfwUpdateGamepadMappings(EnvControlConfig);
+ }
+
+ for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) {
+ if (glfwJoystickPresent(i) && !IsThisJoystickBlacklisted(i)) {
+ if (PSGLOBAL(joy1id) == -1)
+ PSGLOBAL(joy1id) = i;
+ else if (PSGLOBAL(joy2id) == -1)
+ PSGLOBAL(joy2id) = i;
+ else
+ break;
+ }
+ }
+
+ if (PSGLOBAL(joy1id) != -1) {
+ int count;
+ glfwGetJoystickButtons(PSGLOBAL(joy1id), &count);
+#ifdef DETECT_JOYSTICK_MENU
+ strcpy(gSelectedJoystickName, glfwGetJoystickName(PSGLOBAL(joy1id)));
+#endif
+ ControlsManager.InitDefaultControlConfigJoyPad(count);
+ }
+}
+
+int lastCursorMode = GLFW_CURSOR_HIDDEN;
+long _InputInitialiseMouse(bool exclusive)
+{
+ // Disabled = keep cursor centered and hide
+ lastCursorMode = exclusive ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_HIDDEN;
+ glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, lastCursorMode);
+ return 0;
+}
+
+void _InputShutdownMouse()
+{
+ // Not needed
+}
+
+// Not "needs exclusive" on GLFW, but more like "needs to change mode"
+bool _InputMouseNeedsExclusive()
+{
+ // That was the cause of infamous mouse bug on Win.
+
+ RwVideoMode vm;
+ RwEngineGetVideoModeInfo(&vm, GcurSelVM);
+
+ // If windowed, free the cursor on menu(where this func. is called and DISABLED-HIDDEN transition is done accordingly)
+ // If it's fullscreen, be sure that it didn't stuck on HIDDEN.
+ return !(vm.flags & rwVIDEOMODEEXCLUSIVE) || lastCursorMode == GLFW_CURSOR_HIDDEN;
+}
+
+void psPostRWinit(void)
+{
+ RwVideoMode vm;
+ RwEngineGetVideoModeInfo(&vm, GcurSelVM);
+
+#ifndef GET_KEYBOARD_INPUT_FROM_X11
+ glfwSetKeyCallback(PSGLOBAL(window), keypressCB);
+#endif
+ glfwSetFramebufferSizeCallback(PSGLOBAL(window), resizeCB);
+ glfwSetScrollCallback(PSGLOBAL(window), scrollCB);
+ glfwSetCursorPosCallback(PSGLOBAL(window), cursorCB);
+ glfwSetCursorEnterCallback(PSGLOBAL(window), cursorEnterCB);
+ glfwSetWindowIconifyCallback(PSGLOBAL(window), windowIconifyCB);
+ glfwSetWindowFocusCallback(PSGLOBAL(window), windowFocusCB);
+ glfwSetJoystickCallback(joysChangeCB);
+
+ _InputInitialiseJoys();
+ _InputInitialiseMouse(false);
+
+ if(!(vm.flags & rwVIDEOMODEEXCLUSIVE))
+ glfwSetWindowSize(PSGLOBAL(window), RsGlobal.maximumWidth, RsGlobal.maximumHeight);
+
+ // Make sure all keys are released
+ CPad::GetPad(0)->Clear(true);
+ CPad::GetPad(1)->Clear(true);
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool _psSetVideoMode(RwInt32 subSystem, RwInt32 videoMode)
+{
+ RwInitialised = FALSE;
+
+ RsEventHandler(rsRWTERMINATE, nil);
+
+ GcurSel = subSystem;
+ GcurSelVM = videoMode;
+
+ useDefault = TRUE;
+
+ if ( RsEventHandler(rsRWINITIALIZE, &openParams) == rsEVENTERROR )
+ return FALSE;
+
+ RwInitialised = TRUE;
+ useDefault = FALSE;
+
+ RwRect r;
+
+ r.x = 0;
+ r.y = 0;
+ r.w = RsGlobal.maximumWidth;
+ r.h = RsGlobal.maximumHeight;
+
+ RsEventHandler(rsCAMERASIZE, &r);
+
+ psPostRWinit();
+
+ return TRUE;
+}
+
+
+/*
+ *****************************************************************************
+ */
+static RwChar **
+CommandLineToArgv(RwChar *cmdLine, RwInt32 *argCount)
+{
+ RwInt32 numArgs = 0;
+ RwBool inArg, inString;
+ RwInt32 i, len;
+ RwChar *res, *str, **aptr;
+
+ len = strlen(cmdLine);
+
+ /*
+ * Count the number of arguments...
+ */
+ inString = FALSE;
+ inArg = FALSE;
+
+ for(i=0; i<=len; i++)
+ {
+ if( cmdLine[i] == '"' )
+ {
+ inString = !inString;
+ }
+
+ if( (cmdLine[i] <= ' ' && !inString) || i == len )
+ {
+ if( inArg )
+ {
+ inArg = FALSE;
+
+ numArgs++;
+ }
+ }
+ else if( !inArg )
+ {
+ inArg = TRUE;
+ }
+ }
+
+ /*
+ * Allocate memory for result...
+ */
+ res = (RwChar *)malloc(sizeof(RwChar *) * numArgs + len + 1);
+ str = res + sizeof(RwChar *) * numArgs;
+ aptr = (RwChar **)res;
+
+ strcpy(str, cmdLine);
+
+ /*
+ * Walk through cmdLine again this time setting pointer to each arg...
+ */
+ inArg = FALSE;
+ inString = FALSE;
+
+ for(i=0; i<=len; i++)
+ {
+ if( cmdLine[i] == '"' )
+ {
+ inString = !inString;
+ }
+
+ if( (cmdLine[i] <= ' ' && !inString) || i == len )
+ {
+ if( inArg )
+ {
+ if( str[i-1] == '"' )
+ {
+ str[i-1] = '\0';
+ }
+ else
+ {
+ str[i] = '\0';
+ }
+
+ inArg = FALSE;
+ }
+ }
+ else if( !inArg && cmdLine[i] != '"' )
+ {
+ inArg = TRUE;
+
+ *aptr++ = &str[i];
+ }
+ }
+
+ *argCount = numArgs;
+
+ return (RwChar **)res;
+}
+
+/*
+ *****************************************************************************
+ */
+void InitialiseLanguage()
+{
+#ifndef _WIN32
+ // Mandatory for Linux(Unix? Posix?) to set lang. to environment lang.
+ setlocale(LC_ALL, "");
+
+ char *systemLang, *keyboardLang;
+
+ systemLang = setlocale (LC_ALL, NULL);
+ keyboardLang = setlocale (LC_CTYPE, NULL);
+
+ short primUserLCID, primSystemLCID;
+ primUserLCID = primSystemLCID = !strncmp(systemLang, "fr_",3) ? LANG_FRENCH :
+ !strncmp(systemLang, "de_",3) ? LANG_GERMAN :
+ !strncmp(systemLang, "en_",3) ? LANG_ENGLISH :
+ !strncmp(systemLang, "it_",3) ? LANG_ITALIAN :
+ !strncmp(systemLang, "es_",3) ? LANG_SPANISH :
+ LANG_OTHER;
+
+ short primLayout = !strncmp(keyboardLang, "fr_",3) ? LANG_FRENCH : (!strncmp(keyboardLang, "de_",3) ? LANG_GERMAN : LANG_ENGLISH);
+
+ short subUserLCID, subSystemLCID;
+ subUserLCID = subSystemLCID = !strncmp(systemLang, "en_AU",5) ? SUBLANG_ENGLISH_AUS : SUBLANG_OTHER;
+ short subLayout = !strncmp(keyboardLang, "en_AU",5) ? SUBLANG_ENGLISH_AUS : SUBLANG_OTHER;
+
+#else
+ WORD primUserLCID = PRIMARYLANGID(GetSystemDefaultLCID());
+ WORD primSystemLCID = PRIMARYLANGID(GetUserDefaultLCID());
+ WORD primLayout = PRIMARYLANGID((DWORD)GetKeyboardLayout(0));
+
+ WORD subUserLCID = SUBLANGID(GetSystemDefaultLCID());
+ WORD subSystemLCID = SUBLANGID(GetUserDefaultLCID());
+ WORD subLayout = SUBLANGID((DWORD)GetKeyboardLayout(0));
+#endif
+ if ( primUserLCID == LANG_GERMAN
+ || primSystemLCID == LANG_GERMAN
+ || primLayout == LANG_GERMAN )
+ {
+ CGame::nastyGame = false;
+ FrontEndMenuManager.m_PrefsAllowNastyGame = false;
+ CGame::germanGame = true;
+ }
+
+ if ( primUserLCID == LANG_FRENCH
+ || primSystemLCID == LANG_FRENCH
+ || primLayout == LANG_FRENCH )
+ {
+ CGame::nastyGame = false;
+ FrontEndMenuManager.m_PrefsAllowNastyGame = false;
+ CGame::frenchGame = true;
+ }
+
+ if ( subUserLCID == SUBLANG_ENGLISH_AUS
+ || subSystemLCID == SUBLANG_ENGLISH_AUS
+ || subLayout == SUBLANG_ENGLISH_AUS )
+ CGame::noProstitutes = true;
+
+#ifdef NASTY_GAME
+ CGame::nastyGame = true;
+ FrontEndMenuManager.m_PrefsAllowNastyGame = true;
+ CGame::noProstitutes = false;
+#endif
+
+ int32 lang;
+
+ switch ( primSystemLCID )
+ {
+ case LANG_GERMAN:
+ {
+ lang = LANG_GERMAN;
+ break;
+ }
+ case LANG_FRENCH:
+ {
+ lang = LANG_FRENCH;
+ break;
+ }
+ case LANG_SPANISH:
+ {
+ lang = LANG_SPANISH;
+ break;
+ }
+ case LANG_ITALIAN:
+ {
+ lang = LANG_ITALIAN;
+ break;
+ }
+ default:
+ {
+ lang = ( subSystemLCID == SUBLANG_ENGLISH_AUS ) ? -99 : LANG_ENGLISH;
+ break;
+ }
+ }
+
+ FrontEndMenuManager.OS_Language = primUserLCID;
+
+ switch ( lang )
+ {
+ case LANG_GERMAN:
+ {
+ FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_GERMAN;
+ break;
+ }
+ case LANG_SPANISH:
+ {
+ FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_SPANISH;
+ break;
+ }
+ case LANG_FRENCH:
+ {
+ FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_FRENCH;
+ break;
+ }
+ case LANG_ITALIAN:
+ {
+ FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_ITALIAN;
+ break;
+ }
+ default:
+ {
+ FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_AMERICAN;
+ break;
+ }
+ }
+
+#ifndef _WIN32
+ // TODO this is needed for strcasecmp to work correctly across all languages, but can these cause other problems??
+ setlocale(LC_CTYPE, "C");
+ setlocale(LC_COLLATE, "C");
+ setlocale(LC_NUMERIC, "C");
+#endif
+
+ TheText.Unload();
+ TheText.Load();
+}
+
+/*
+ *****************************************************************************
+ */
+
+void HandleExit()
+{
+#ifdef _WIN32
+ MSG message;
+ while ( PeekMessage(&message, nil, 0U, 0U, PM_REMOVE|PM_NOYIELD) )
+ {
+ if( message.message == WM_QUIT )
+ {
+ RsGlobal.quit = TRUE;
+ }
+ else
+ {
+ TranslateMessage(&message);
+ DispatchMessage(&message);
+ }
+ }
+#else
+ // We now handle terminate message always, why handle on some cases?
+ return;
+#endif
+}
+
+#ifndef _WIN32
+void terminateHandler(int sig, siginfo_t *info, void *ucontext) {
+ RsGlobal.quit = TRUE;
+}
+
+#ifdef FLUSHABLE_STREAMING
+void dummyHandler(int sig){
+ // Don't kill the app pls
+}
+#endif
+#endif
+
+void resizeCB(GLFWwindow* window, int width, int height) {
+ /*
+ * Handle event to ensure window contents are displayed during re-size
+ * as this can be disabled by the user, then if there is not enough
+ * memory things don't work.
+ */
+ /* redraw window */
+
+ if (RwInitialised && gGameState == GS_PLAYING_GAME)
+ {
+ RsEventHandler(rsIDLE, (void *)TRUE);
+ }
+
+ if (RwInitialised && height > 0 && width > 0) {
+ RwRect r;
+
+ // TODO fix artifacts of resizing with mouse
+ RsGlobal.maximumHeight = height;
+ RsGlobal.maximumWidth = width;
+
+ r.x = 0;
+ r.y = 0;
+ r.w = width;
+ r.h = height;
+
+ RsEventHandler(rsCAMERASIZE, &r);
+ }
+// glfwSetWindowPos(window, 0, 0);
+}
+
+void scrollCB(GLFWwindow* window, double xoffset, double yoffset) {
+ PSGLOBAL(mouseWheel) = yoffset;
+}
+
+bool lshiftStatus = false;
+bool rshiftStatus = false;
+
+#ifndef GET_KEYBOARD_INPUT_FROM_X11
+int keymap[GLFW_KEY_LAST + 1];
+
+static void
+initkeymap(void)
+{
+ int i;
+ for (i = 0; i < GLFW_KEY_LAST + 1; i++)
+ keymap[i] = rsNULL;
+
+ keymap[GLFW_KEY_SPACE] = ' ';
+ keymap[GLFW_KEY_APOSTROPHE] = '\'';
+ keymap[GLFW_KEY_COMMA] = ',';
+ keymap[GLFW_KEY_MINUS] = '-';
+ keymap[GLFW_KEY_PERIOD] = '.';
+ keymap[GLFW_KEY_SLASH] = '/';
+ keymap[GLFW_KEY_0] = '0';
+ keymap[GLFW_KEY_1] = '1';
+ keymap[GLFW_KEY_2] = '2';
+ keymap[GLFW_KEY_3] = '3';
+ keymap[GLFW_KEY_4] = '4';
+ keymap[GLFW_KEY_5] = '5';
+ keymap[GLFW_KEY_6] = '6';
+ keymap[GLFW_KEY_7] = '7';
+ keymap[GLFW_KEY_8] = '8';
+ keymap[GLFW_KEY_9] = '9';
+ keymap[GLFW_KEY_SEMICOLON] = ';';
+ keymap[GLFW_KEY_EQUAL] = '=';
+ keymap[GLFW_KEY_A] = 'A';
+ keymap[GLFW_KEY_B] = 'B';
+ keymap[GLFW_KEY_C] = 'C';
+ keymap[GLFW_KEY_D] = 'D';
+ keymap[GLFW_KEY_E] = 'E';
+ keymap[GLFW_KEY_F] = 'F';
+ keymap[GLFW_KEY_G] = 'G';
+ keymap[GLFW_KEY_H] = 'H';
+ keymap[GLFW_KEY_I] = 'I';
+ keymap[GLFW_KEY_J] = 'J';
+ keymap[GLFW_KEY_K] = 'K';
+ keymap[GLFW_KEY_L] = 'L';
+ keymap[GLFW_KEY_M] = 'M';
+ keymap[GLFW_KEY_N] = 'N';
+ keymap[GLFW_KEY_O] = 'O';
+ keymap[GLFW_KEY_P] = 'P';
+ keymap[GLFW_KEY_Q] = 'Q';
+ keymap[GLFW_KEY_R] = 'R';
+ keymap[GLFW_KEY_S] = 'S';
+ keymap[GLFW_KEY_T] = 'T';
+ keymap[GLFW_KEY_U] = 'U';
+ keymap[GLFW_KEY_V] = 'V';
+ keymap[GLFW_KEY_W] = 'W';
+ keymap[GLFW_KEY_X] = 'X';
+ keymap[GLFW_KEY_Y] = 'Y';
+ keymap[GLFW_KEY_Z] = 'Z';
+ keymap[GLFW_KEY_LEFT_BRACKET] = '[';
+ keymap[GLFW_KEY_BACKSLASH] = '\\';
+ keymap[GLFW_KEY_RIGHT_BRACKET] = ']';
+ keymap[GLFW_KEY_GRAVE_ACCENT] = '`';
+ keymap[GLFW_KEY_ESCAPE] = rsESC;
+ keymap[GLFW_KEY_ENTER] = rsENTER;
+ keymap[GLFW_KEY_TAB] = rsTAB;
+ keymap[GLFW_KEY_BACKSPACE] = rsBACKSP;
+ keymap[GLFW_KEY_INSERT] = rsINS;
+ keymap[GLFW_KEY_DELETE] = rsDEL;
+ keymap[GLFW_KEY_RIGHT] = rsRIGHT;
+ keymap[GLFW_KEY_LEFT] = rsLEFT;
+ keymap[GLFW_KEY_DOWN] = rsDOWN;
+ keymap[GLFW_KEY_UP] = rsUP;
+ keymap[GLFW_KEY_PAGE_UP] = rsPGUP;
+ keymap[GLFW_KEY_PAGE_DOWN] = rsPGDN;
+ keymap[GLFW_KEY_HOME] = rsHOME;
+ keymap[GLFW_KEY_END] = rsEND;
+ keymap[GLFW_KEY_CAPS_LOCK] = rsCAPSLK;
+ keymap[GLFW_KEY_SCROLL_LOCK] = rsSCROLL;
+ keymap[GLFW_KEY_NUM_LOCK] = rsNUMLOCK;
+ keymap[GLFW_KEY_PRINT_SCREEN] = rsNULL;
+ keymap[GLFW_KEY_PAUSE] = rsPAUSE;
+
+ keymap[GLFW_KEY_F1] = rsF1;
+ keymap[GLFW_KEY_F2] = rsF2;
+ keymap[GLFW_KEY_F3] = rsF3;
+ keymap[GLFW_KEY_F4] = rsF4;
+ keymap[GLFW_KEY_F5] = rsF5;
+ keymap[GLFW_KEY_F6] = rsF6;
+ keymap[GLFW_KEY_F7] = rsF7;
+ keymap[GLFW_KEY_F8] = rsF8;
+ keymap[GLFW_KEY_F9] = rsF9;
+ keymap[GLFW_KEY_F10] = rsF10;
+ keymap[GLFW_KEY_F11] = rsF11;
+ keymap[GLFW_KEY_F12] = rsF12;
+ keymap[GLFW_KEY_F13] = rsNULL;
+ keymap[GLFW_KEY_F14] = rsNULL;
+ keymap[GLFW_KEY_F15] = rsNULL;
+ keymap[GLFW_KEY_F16] = rsNULL;
+ keymap[GLFW_KEY_F17] = rsNULL;
+ keymap[GLFW_KEY_F18] = rsNULL;
+ keymap[GLFW_KEY_F19] = rsNULL;
+ keymap[GLFW_KEY_F20] = rsNULL;
+ keymap[GLFW_KEY_F21] = rsNULL;
+ keymap[GLFW_KEY_F22] = rsNULL;
+ keymap[GLFW_KEY_F23] = rsNULL;
+ keymap[GLFW_KEY_F24] = rsNULL;
+ keymap[GLFW_KEY_F25] = rsNULL;
+ keymap[GLFW_KEY_KP_0] = rsPADINS;
+ keymap[GLFW_KEY_KP_1] = rsPADEND;
+ keymap[GLFW_KEY_KP_2] = rsPADDOWN;
+ keymap[GLFW_KEY_KP_3] = rsPADPGDN;
+ keymap[GLFW_KEY_KP_4] = rsPADLEFT;
+ keymap[GLFW_KEY_KP_5] = rsPAD5;
+ keymap[GLFW_KEY_KP_6] = rsPADRIGHT;
+ keymap[GLFW_KEY_KP_7] = rsPADHOME;
+ keymap[GLFW_KEY_KP_8] = rsPADUP;
+ keymap[GLFW_KEY_KP_9] = rsPADPGUP;
+ keymap[GLFW_KEY_KP_DECIMAL] = rsPADDEL;
+ keymap[GLFW_KEY_KP_DIVIDE] = rsDIVIDE;
+ keymap[GLFW_KEY_KP_MULTIPLY] = rsTIMES;
+ keymap[GLFW_KEY_KP_SUBTRACT] = rsMINUS;
+ keymap[GLFW_KEY_KP_ADD] = rsPLUS;
+ keymap[GLFW_KEY_KP_ENTER] = rsPADENTER;
+ keymap[GLFW_KEY_KP_EQUAL] = rsNULL;
+ keymap[GLFW_KEY_LEFT_SHIFT] = rsLSHIFT;
+ keymap[GLFW_KEY_LEFT_CONTROL] = rsLCTRL;
+ keymap[GLFW_KEY_LEFT_ALT] = rsLALT;
+ keymap[GLFW_KEY_LEFT_SUPER] = rsLWIN;
+ keymap[GLFW_KEY_RIGHT_SHIFT] = rsRSHIFT;
+ keymap[GLFW_KEY_RIGHT_CONTROL] = rsRCTRL;
+ keymap[GLFW_KEY_RIGHT_ALT] = rsRALT;
+ keymap[GLFW_KEY_RIGHT_SUPER] = rsRWIN;
+ keymap[GLFW_KEY_MENU] = rsNULL;
+}
+
+void
+keypressCB(GLFWwindow* window, int key, int scancode, int action, int mods)
+{
+ if (key >= 0 && key <= GLFW_KEY_LAST && action != GLFW_REPEAT) {
+ RsKeyCodes ks = (RsKeyCodes)keymap[key];
+
+ if (key == GLFW_KEY_LEFT_SHIFT)
+ lshiftStatus = action != GLFW_RELEASE;
+
+ if (key == GLFW_KEY_RIGHT_SHIFT)
+ rshiftStatus = action != GLFW_RELEASE;
+
+ if (action == GLFW_RELEASE) RsKeyboardEventHandler(rsKEYUP, &ks);
+ else if (action == GLFW_PRESS) RsKeyboardEventHandler(rsKEYDOWN, &ks);
+ }
+}
+
+#else
+
+uint32 keymap[512]; // 256 ascii + 256 KeySyms between 0xff00 - 0xffff
+bool keyStates[512];
+uint32 keyCodeToKeymapIndex[256]; // cache for physical keys
+
+#define KEY_MAP_OFFSET (0xff00 - 256)
+static void
+initkeymap(void)
+{
+ Display *display = glfwGetX11Display();
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(keymap); i++)
+ keymap[i] = rsNULL;
+
+ // You can add new ASCII mappings to here freely (but beware that if right hand side of assignment isn't supported on CFont, it'll be blank/won't work on binding screen)
+ // Right hand side of assigments should always be uppercase counterpart of character
+ keymap[XK_space] = ' ';
+ keymap[XK_apostrophe] = '\'';
+ keymap[XK_ampersand] = '&';
+ keymap[XK_percent] = '%';
+ keymap[XK_dollar] = '$';
+ keymap[XK_comma] = ',';
+ keymap[XK_minus] = '-';
+ keymap[XK_period] = '.';
+ keymap[XK_slash] = '/';
+ keymap[XK_question] = '?';
+ keymap[XK_exclam] = '!';
+ keymap[XK_quotedbl] = '"';
+ keymap[XK_colon] = ':';
+ keymap[XK_semicolon] = ';';
+ keymap[XK_equal] = '=';
+ keymap[XK_bracketleft] = '[';
+ keymap[XK_backslash] = '\\';
+ keymap[XK_bracketright] = ']';
+ keymap[XK_grave] = '`';
+ keymap[XK_0] = '0';
+ keymap[XK_1] = '1';
+ keymap[XK_2] = '2';
+ keymap[XK_3] = '3';
+ keymap[XK_4] = '4';
+ keymap[XK_5] = '5';
+ keymap[XK_6] = '6';
+ keymap[XK_7] = '7';
+ keymap[XK_8] = '8';
+ keymap[XK_9] = '9';
+ keymap[XK_a] = 'A';
+ keymap[XK_b] = 'B';
+ keymap[XK_c] = 'C';
+ keymap[XK_d] = 'D';
+ keymap[XK_e] = 'E';
+ keymap[XK_f] = 'F';
+ keymap[XK_g] = 'G';
+ keymap[XK_h] = 'H';
+ keymap[XK_i] = 'I';
+ keymap[XK_I] = 'I'; // Turkish I problem
+ keymap[XK_j] = 'J';
+ keymap[XK_k] = 'K';
+ keymap[XK_l] = 'L';
+ keymap[XK_m] = 'M';
+ keymap[XK_n] = 'N';
+ keymap[XK_o] = 'O';
+ keymap[XK_p] = 'P';
+ keymap[XK_q] = 'Q';
+ keymap[XK_r] = 'R';
+ keymap[XK_s] = 'S';
+ keymap[XK_t] = 'T';
+ keymap[XK_u] = 'U';
+ keymap[XK_v] = 'V';
+ keymap[XK_w] = 'W';
+ keymap[XK_x] = 'X';
+ keymap[XK_y] = 'Y';
+ keymap[XK_z] = 'Z';
+
+ // Some of regional but ASCII characters that GTA supports
+ keymap[XK_agrave] = 0x00c0;
+ keymap[XK_aacute] = 0x00c1;
+ keymap[XK_acircumflex] = 0x00c2;
+ keymap[XK_adiaeresis] = 0x00c4;
+
+ keymap[XK_ae] = 0x00c6;
+
+ keymap[XK_egrave] = 0x00c8;
+ keymap[XK_eacute] = 0x00c9;
+ keymap[XK_ecircumflex] = 0x00ca;
+ keymap[XK_ediaeresis] = 0x00cb;
+
+ keymap[XK_igrave] = 0x00cc;
+ keymap[XK_iacute] = 0x00cd;
+ keymap[XK_icircumflex] = 0x00ce;
+ keymap[XK_idiaeresis] = 0x00cf;
+
+ keymap[XK_ccedilla] = 0x00c7;
+ keymap[XK_odiaeresis] = 0x00d6;
+ keymap[XK_udiaeresis] = 0x00dc;
+
+ // These are 0xff00 - 0xffff range of KeySym's, and subtracting KEY_MAP_OFFSET is needed
+ keymap[XK_Escape - KEY_MAP_OFFSET] = rsESC;
+ keymap[XK_Return - KEY_MAP_OFFSET] = rsENTER;
+ keymap[XK_Tab - KEY_MAP_OFFSET] = rsTAB;
+ keymap[XK_BackSpace - KEY_MAP_OFFSET] = rsBACKSP;
+ keymap[XK_Insert - KEY_MAP_OFFSET] = rsINS;
+ keymap[XK_Delete - KEY_MAP_OFFSET] = rsDEL;
+ keymap[XK_Right - KEY_MAP_OFFSET] = rsRIGHT;
+ keymap[XK_Left - KEY_MAP_OFFSET] = rsLEFT;
+ keymap[XK_Down - KEY_MAP_OFFSET] = rsDOWN;
+ keymap[XK_Up - KEY_MAP_OFFSET] = rsUP;
+ keymap[XK_Page_Up - KEY_MAP_OFFSET] = rsPGUP;
+ keymap[XK_Page_Down - KEY_MAP_OFFSET] = rsPGDN;
+ keymap[XK_Home - KEY_MAP_OFFSET] = rsHOME;
+ keymap[XK_End - KEY_MAP_OFFSET] = rsEND;
+ keymap[XK_Caps_Lock - KEY_MAP_OFFSET] = rsCAPSLK;
+ keymap[XK_Scroll_Lock - KEY_MAP_OFFSET] = rsSCROLL;
+ keymap[XK_Num_Lock - KEY_MAP_OFFSET] = rsNUMLOCK;
+ keymap[XK_Pause - KEY_MAP_OFFSET] = rsPAUSE;
+
+ keymap[XK_F1 - KEY_MAP_OFFSET] = rsF1;
+ keymap[XK_F2 - KEY_MAP_OFFSET] = rsF2;
+ keymap[XK_F3 - KEY_MAP_OFFSET] = rsF3;
+ keymap[XK_F4 - KEY_MAP_OFFSET] = rsF4;
+ keymap[XK_F5 - KEY_MAP_OFFSET] = rsF5;
+ keymap[XK_F6 - KEY_MAP_OFFSET] = rsF6;
+ keymap[XK_F7 - KEY_MAP_OFFSET] = rsF7;
+ keymap[XK_F8 - KEY_MAP_OFFSET] = rsF8;
+ keymap[XK_F9 - KEY_MAP_OFFSET] = rsF9;
+ keymap[XK_F10 - KEY_MAP_OFFSET] = rsF10;
+ keymap[XK_F11 - KEY_MAP_OFFSET] = rsF11;
+ keymap[XK_F12 - KEY_MAP_OFFSET] = rsF12;
+ keymap[XK_F13 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F14 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F15 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F16 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F17 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F18 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F19 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F20 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F21 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F22 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F23 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F24 - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_F25 - KEY_MAP_OFFSET] = rsNULL;
+
+ keymap[XK_KP_0 - KEY_MAP_OFFSET] = rsPADINS;
+ keymap[XK_KP_1 - KEY_MAP_OFFSET] = rsPADEND;
+ keymap[XK_KP_2 - KEY_MAP_OFFSET] = rsPADDOWN;
+ keymap[XK_KP_3 - KEY_MAP_OFFSET] = rsPADPGDN;
+ keymap[XK_KP_4 - KEY_MAP_OFFSET] = rsPADLEFT;
+ keymap[XK_KP_5 - KEY_MAP_OFFSET] = rsPAD5;
+ keymap[XK_KP_6 - KEY_MAP_OFFSET] = rsPADRIGHT;
+ keymap[XK_KP_7 - KEY_MAP_OFFSET] = rsPADHOME;
+ keymap[XK_KP_8 - KEY_MAP_OFFSET] = rsPADUP;
+ keymap[XK_KP_9 - KEY_MAP_OFFSET] = rsPADPGUP;
+ keymap[XK_KP_Insert - KEY_MAP_OFFSET] = rsPADINS;
+ keymap[XK_KP_End - KEY_MAP_OFFSET] = rsPADEND;
+ keymap[XK_KP_Down - KEY_MAP_OFFSET] = rsPADDOWN;
+ keymap[XK_KP_Page_Down - KEY_MAP_OFFSET] = rsPADPGDN;
+ keymap[XK_KP_Left - KEY_MAP_OFFSET] = rsPADLEFT;
+ keymap[XK_KP_Begin - KEY_MAP_OFFSET] = rsPAD5;
+ keymap[XK_KP_Right - KEY_MAP_OFFSET] = rsPADRIGHT;
+ keymap[XK_KP_Home - KEY_MAP_OFFSET] = rsPADHOME;
+ keymap[XK_KP_Up - KEY_MAP_OFFSET] = rsPADUP;
+ keymap[XK_KP_Page_Up - KEY_MAP_OFFSET] = rsPADPGUP;
+
+ keymap[XK_KP_Decimal - KEY_MAP_OFFSET] = rsPADDEL;
+ keymap[XK_KP_Divide - KEY_MAP_OFFSET] = rsDIVIDE;
+ keymap[XK_KP_Multiply - KEY_MAP_OFFSET] = rsTIMES;
+ keymap[XK_KP_Subtract - KEY_MAP_OFFSET] = rsMINUS;
+ keymap[XK_KP_Add - KEY_MAP_OFFSET] = rsPLUS;
+ keymap[XK_KP_Enter - KEY_MAP_OFFSET] = rsPADENTER;
+ keymap[XK_KP_Equal - KEY_MAP_OFFSET] = rsNULL;
+ keymap[XK_Shift_L - KEY_MAP_OFFSET] = rsLSHIFT;
+ keymap[XK_Control_L - KEY_MAP_OFFSET] = rsLCTRL;
+ keymap[XK_Alt_L - KEY_MAP_OFFSET] = rsLALT;
+ keymap[XK_Super_L - KEY_MAP_OFFSET] = rsLWIN;
+ keymap[XK_Shift_R - KEY_MAP_OFFSET] = rsRSHIFT;
+ keymap[XK_Control_R - KEY_MAP_OFFSET] = rsRCTRL;
+ keymap[XK_Alt_R - KEY_MAP_OFFSET] = rsRALT;
+ keymap[XK_Super_R - KEY_MAP_OFFSET] = rsRWIN;
+ keymap[XK_Menu - KEY_MAP_OFFSET] = rsNULL;
+
+ // Cache the key codes' key symbol equivelants, otherwise we will have to do it on each frame
+ // KeyCode is always in [0,255], and represents a physical key
+
+ int min_keycode, max_keycode, keysyms_per_keycode;
+ KeySym *keymap, *origkeymap;
+
+ char *keyboardLang = setlocale (LC_CTYPE, NULL);
+ setlocale(LC_CTYPE, "");
+
+ XDisplayKeycodes(display, &min_keycode, &max_keycode);
+ origkeymap = XGetKeyboardMapping(display, min_keycode, (max_keycode - min_keycode + 1), &keysyms_per_keycode);
+ keymap = origkeymap;
+ for (int i = min_keycode; i <= max_keycode; i++) {
+ int j, lastKeysym;
+
+ lastKeysym = keysyms_per_keycode - 1;
+ while ((lastKeysym >= 0) && (keymap[lastKeysym] == NoSymbol))
+ lastKeysym--;
+
+ for (j = 0; j <= lastKeysym; j++) {
+ KeySym ks = keymap[j];
+
+ if (ks == NoSymbol)
+ continue;
+
+ if (ks < 256) {
+ keyCodeToKeymapIndex[i] = ks;
+ break;
+ } else if (ks >= 0xff00 && ks < 0xffff) {
+ keyCodeToKeymapIndex[i] = ks - KEY_MAP_OFFSET;
+ break;
+ }
+ }
+ keymap += keysyms_per_keycode;
+ }
+ XFree(origkeymap);
+
+ setlocale(LC_CTYPE, keyboardLang);
+}
+#undef KEY_MAP_OFFSET
+
+void checkKeyPresses()
+{
+ Display *display = glfwGetX11Display();
+ char keys[32];
+ XQueryKeymap(display, keys);
+ for (int i = 0; i < sizeof(keys); i++) {
+ for (int j = 0; j < 8; j++) {
+ KeyCode keycode = 8 * i + j;
+ uint32 keymapIndex = keyCodeToKeymapIndex[keycode];
+ if (keymapIndex != 0) {
+ int rsCode = keymap[keymapIndex];
+ if (rsCode == rsNULL)
+ continue;
+
+ bool pressed = WindowFocused && !!(keys[i] & (1 << j));
+
+ // idk why R* does that
+ if (rsCode == rsLSHIFT)
+ lshiftStatus = pressed;
+ else if (rsCode == rsRSHIFT)
+ rshiftStatus = pressed;
+
+ if (keyStates[keymapIndex] != pressed) {
+ if (pressed) {
+ RsKeyboardEventHandler(rsKEYDOWN, &rsCode);
+ } else {
+ RsKeyboardEventHandler(rsKEYUP, &rsCode);
+ }
+ }
+
+ keyStates[keymapIndex] = pressed;
+ }
+ }
+ }
+
+}
+#endif
+
+// R* calls that in ControllerConfig, idk why
+void
+_InputTranslateShiftKeyUpDown(RsKeyCodes *rs) {
+ RsKeyboardEventHandler(lshiftStatus ? rsKEYDOWN : rsKEYUP, &(*rs = rsLSHIFT));
+ RsKeyboardEventHandler(rshiftStatus ? rsKEYDOWN : rsKEYUP, &(*rs = rsRSHIFT));
+}
+
+// TODO this only works in frontend(and luckily only frontend use this). Fun fact: if I get pos manually in game, glfw reports that it's > 32000
+void
+cursorCB(GLFWwindow* window, double xpos, double ypos) {
+ if (!FrontEndMenuManager.m_bMenuActive)
+ return;
+
+ int winw, winh;
+ glfwGetWindowSize(PSGLOBAL(window), &winw, &winh);
+ FrontEndMenuManager.m_nMouseTempPosX = xpos * (RsGlobal.maximumWidth / winw);
+ FrontEndMenuManager.m_nMouseTempPosY = ypos * (RsGlobal.maximumHeight / winh);
+}
+
+void
+cursorEnterCB(GLFWwindow* window, int entered) {
+ PSGLOBAL(cursorIsInWindow) = !!entered;
+}
+
+void
+windowFocusCB(GLFWwindow* window, int focused) {
+ WindowFocused = !!focused;
+}
+
+void
+windowIconifyCB(GLFWwindow* window, int iconified) {
+ WindowIconified = !!iconified;
+}
+
+/*
+ *****************************************************************************
+ */
+#ifdef _WIN32
+int PASCAL
+WinMain(HINSTANCE instance,
+ HINSTANCE prevInstance __RWUNUSED__,
+ CMDSTR cmdLine,
+ int cmdShow)
+{
+
+ RwInt32 argc;
+ RwChar** argv;
+ SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, SPIF_SENDCHANGE);
+
+#ifndef MASTER
+ if (strstr(cmdLine, "-console"))
+ {
+ AllocConsole();
+ freopen("CONIN$", "r", stdin);
+ freopen("CONOUT$", "w", stdout);
+ freopen("CONOUT$", "w", stderr);
+ }
+#endif
+
+#else
+int
+main(int argc, char *argv[])
+{
+#endif
+ RwV2d pos;
+ RwInt32 i;
+
+#ifdef USE_CUSTOM_ALLOCATOR
+ InitMemoryMgr();
+#endif
+
+#ifndef _WIN32
+ struct sigaction act;
+ act.sa_sigaction = terminateHandler;
+ act.sa_flags = SA_SIGINFO;
+ sigaction(SIGTERM, &act, NULL);
+#ifdef FLUSHABLE_STREAMING
+ struct sigaction sa;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = dummyHandler;
+ sa.sa_flags = 0;
+ sigaction(SIGUSR1, &sa, NULL);
+#endif
+#endif
+
+ /*
+ * Initialize the platform independent data.
+ * This will in turn initialize the platform specific data...
+ */
+ if( RsEventHandler(rsINITIALIZE, nil) == rsEVENTERROR )
+ {
+ return FALSE;
+ }
+
+#ifdef _WIN32
+ /*
+ * Get proper command line params, cmdLine passed to us does not
+ * work properly under all circumstances...
+ */
+ cmdLine = GetCommandLine();
+
+ /*
+ * Parse command line into standard (argv, argc) parameters...
+ */
+ argv = CommandLineToArgv(cmdLine, &argc);
+
+
+ /*
+ * Parse command line parameters (except program name) one at
+ * a time BEFORE RenderWare initialization...
+ */
+#endif
+ for(i=1; i<argc; i++)
+ {
+ RsEventHandler(rsPREINITCOMMANDLINE, argv[i]);
+ }
+
+ /*
+ * Parameters to be used in RwEngineOpen / rsRWINITIALISE event
+ */
+
+ openParams.width = RsGlobal.maximumWidth;
+ openParams.height = RsGlobal.maximumHeight;
+ openParams.windowtitle = RsGlobal.appName;
+ openParams.window = &PSGLOBAL(window);
+
+ ControlsManager.MakeControllerActionsBlank();
+ ControlsManager.InitDefaultControlConfiguration();
+
+ /*
+ * Initialize the 3D (RenderWare) components of the app...
+ */
+ if( rsEVENTERROR == RsEventHandler(rsRWINITIALIZE, &openParams) )
+ {
+ RsEventHandler(rsTERMINATE, nil);
+
+ return 0;
+ }
+
+#ifdef _WIN32
+ HWND wnd = glfwGetWin32Window(PSGLOBAL(window));
+
+ HICON icon = LoadIcon(instance, MAKEINTRESOURCE(IDI_MAIN_ICON));
+
+ SendMessage(wnd, WM_SETICON, ICON_BIG, (LPARAM)icon);
+ SendMessage(wnd, WM_SETICON, ICON_SMALL, (LPARAM)icon);
+#endif
+
+ psPostRWinit();
+
+ ControlsManager.InitDefaultControlConfigMouse(MousePointerStateHelper.GetMouseSetUp());
+
+// glfwSetWindowPos(PSGLOBAL(window), 0, 0);
+
+ /*
+ * Parse command line parameters (except program name) one at
+ * a time AFTER RenderWare initialization...
+ */
+ for(i=1; i<argc; i++)
+ {
+ RsEventHandler(rsCOMMANDLINE, argv[i]);
+ }
+
+ /*
+ * Force a camera resize event...
+ */
+ {
+ RwRect r;
+
+ r.x = 0;
+ r.y = 0;
+ r.w = RsGlobal.maximumWidth;
+ r.h = RsGlobal.maximumHeight;
+
+ RsEventHandler(rsCAMERASIZE, &r);
+ }
+#ifdef _WIN32
+ SystemParametersInfo(SPI_SETPOWEROFFACTIVE, FALSE, nil, SPIF_SENDCHANGE);
+ SystemParametersInfo(SPI_SETLOWPOWERACTIVE, FALSE, nil, SPIF_SENDCHANGE);
+
+
+ STICKYKEYS SavedStickyKeys;
+ SavedStickyKeys.cbSize = sizeof(STICKYKEYS);
+
+ SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &SavedStickyKeys, SPIF_SENDCHANGE);
+
+ STICKYKEYS NewStickyKeys;
+ NewStickyKeys.cbSize = sizeof(STICKYKEYS);
+ NewStickyKeys.dwFlags = SKF_TWOKEYSOFF;
+
+ SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &NewStickyKeys, SPIF_SENDCHANGE);
+#endif
+
+ {
+ CFileMgr::SetDirMyDocuments();
+
+#ifdef LOAD_INI_SETTINGS
+ // At this point InitDefaultControlConfigJoyPad must have set all bindings to default and ms_padButtonsInited to number of detected buttons.
+ // We will load stored bindings below, but let's cache ms_padButtonsInited before LoadINIControllerSettings and LoadSettings clears it,
+ // so we can add new joy bindings **on top of** stored bindings.
+ int connectedPadButtons = ControlsManager.ms_padButtonsInited;
+#endif
+
+ int32 gta3set = CFileMgr::OpenFile("gta_vc.set", "r");
+
+ if ( gta3set )
+ {
+ ControlsManager.LoadSettings(gta3set);
+ CFileMgr::CloseFile(gta3set);
+ }
+
+ CFileMgr::SetDir("");
+
+#ifdef LOAD_INI_SETTINGS
+ LoadINIControllerSettings();
+ if (connectedPadButtons != 0) {
+ ControlsManager.InitDefaultControlConfigJoyPad(connectedPadButtons);
+ SaveINIControllerSettings();
+ }
+#endif
+ }
+
+#ifdef _WIN32
+ SetErrorMode(SEM_FAILCRITICALERRORS);
+#endif
+
+#ifdef PS2_MENU
+ int32 r = TheMemoryCard.CheckCardStateAtGameStartUp(CARD_ONE);
+ if ( r == CMemoryCard::ERR_DIRNOENTRY || r == CMemoryCard::ERR_NOFORMAT
+ && r != CMemoryCard::ERR_OPENNOENTRY && r != CMemoryCard::ERR_NONE )
+ {
+ LoadingScreen(nil, nil, "loadsc0");
+
+ TheText.Unload();
+ TheText.Load();
+
+ CFont::Initialise();
+
+ FrontEndMenuManager.DrawMemoryCardStartUpMenus();
+ }
+#endif
+
+ initkeymap();
+
+ while ( TRUE )
+ {
+ RwInitialised = TRUE;
+
+ /*
+ * Set the initial mouse position...
+ */
+ pos.x = RsGlobal.maximumWidth * 0.5f;
+ pos.y = RsGlobal.maximumHeight * 0.5f;
+
+ RsMouseSetPos(&pos);
+
+ /*
+ * Enter the message processing loop...
+ */
+
+#ifndef MASTER
+ if (gbModelViewer) {
+ // This is TheModelViewer in LCS
+ LoadingScreen("Loading the ModelViewer", NULL, GetRandomSplashScreen());
+ CAnimViewer::Initialise();
+ CTimer::Update();
+#ifndef PS2_MENU
+ FrontEndMenuManager.m_bGameNotLoaded = false;
+#endif
+ }
+#endif
+
+#ifdef PS2_MENU
+ if (TheMemoryCard.m_bWantToLoad)
+ LoadSplash(GetLevelSplashScreen(CGame::currLevel));
+
+ TheMemoryCard.m_bWantToLoad = false;
+
+ CTimer::Update();
+
+ while( !RsGlobal.quit && !(FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad) && !glfwWindowShouldClose(PSGLOBAL(window)) )
+#else
+ while( !RsGlobal.quit && !FrontEndMenuManager.m_bWantToRestart && !glfwWindowShouldClose(PSGLOBAL(window)))
+#endif
+ {
+ glfwPollEvents();
+#ifdef GET_KEYBOARD_INPUT_FROM_X11
+ checkKeyPresses();
+#endif
+#ifndef MASTER
+ if (gbModelViewer) {
+ // This is TheModelViewerCore in LCS
+ TheModelViewer();
+ } else
+#endif
+ if ( ForegroundApp )
+ {
+ switch ( gGameState )
+ {
+ case GS_START_UP:
+ {
+#ifdef NO_MOVIES
+ gGameState = GS_INIT_ONCE;
+#else
+ gGameState = GS_INIT_LOGO_MPEG;
+#endif
+ TRACE("gGameState = GS_INIT_ONCE");
+ break;
+ }
+
+ case GS_INIT_LOGO_MPEG:
+ {
+ //if (!startupDeactivate)
+ // PlayMovieInWindow(cmdShow, "movies\\Logo.mpg");
+ gGameState = GS_LOGO_MPEG;
+ TRACE("gGameState = GS_LOGO_MPEG;");
+ break;
+ }
+
+ case GS_LOGO_MPEG:
+ {
+// CPad::UpdatePads();
+
+// if (startupDeactivate || ControlsManager.GetJoyButtonJustDown() != 0)
+ ++gGameState;
+// else if (CPad::GetPad(0)->GetLeftMouseJustDown())
+// ++gGameState;
+// else if (CPad::GetPad(0)->GetEnterJustDown())
+// ++gGameState;
+// else if (CPad::GetPad(0)->GetCharJustDown(' '))
+// ++gGameState;
+// else if (CPad::GetPad(0)->GetAltJustDown())
+// ++gGameState;
+// else if (CPad::GetPad(0)->GetTabJustDown())
+// ++gGameState;
+
+ break;
+ }
+
+ case GS_INIT_INTRO_MPEG:
+ {
+//#ifndef NO_MOVIES
+// CloseClip();
+// CoUninitialize();
+//#endif
+//
+// if (CMenuManager::OS_Language == LANG_FRENCH || CMenuManager::OS_Language == LANG_GERMAN)
+// PlayMovieInWindow(cmdShow, "movies\\GTAtitlesGER.mpg");
+// else
+// PlayMovieInWindow(cmdShow, "movies\\GTAtitles.mpg");
+
+ gGameState = GS_INTRO_MPEG;
+ TRACE("gGameState = GS_INTRO_MPEG;");
+ break;
+ }
+
+ case GS_INTRO_MPEG:
+ {
+// CPad::UpdatePads();
+//
+// if (startupDeactivate || ControlsManager.GetJoyButtonJustDown() != 0)
+ ++gGameState;
+// else if (CPad::GetPad(0)->GetLeftMouseJustDown())
+// ++gGameState;
+// else if (CPad::GetPad(0)->GetEnterJustDown())
+// ++gGameState;
+// else if (CPad::GetPad(0)->GetCharJustDown(' '))
+// ++gGameState;
+// else if (CPad::GetPad(0)->GetAltJustDown())
+// ++gGameState;
+// else if (CPad::GetPad(0)->GetTabJustDown())
+// ++gGameState;
+
+ break;
+ }
+
+ case GS_INIT_ONCE:
+ {
+ //CoUninitialize();
+
+#ifdef PS2_MENU
+ extern char version_name[64];
+ if ( CGame::frenchGame || CGame::germanGame )
+ LoadingScreen(NULL, version_name, "loadsc24");
+ else
+ LoadingScreen(NULL, version_name, "loadsc0");
+
+ printf("Into TheGame!!!\n");
+#else
+ LoadingScreen(nil, nil, "loadsc0");
+ // LoadingScreen(nil, nil, "loadsc0"); // duplicate
+#endif
+ if ( !CGame::InitialiseOnceAfterRW() )
+ RsGlobal.quit = TRUE;
+
+#ifdef PS2_MENU
+ gGameState = GS_INIT_PLAYING_GAME;
+#else
+ gGameState = GS_INIT_FRONTEND;
+ TRACE("gGameState = GS_INIT_FRONTEND;");
+#endif
+ break;
+ }
+#ifndef PS2_MENU
+ case GS_INIT_FRONTEND:
+ {
+ LoadingScreen(nil, nil, "loadsc0");
+ // LoadingScreen(nil, nil, "loadsc0"); // duplicate
+
+ FrontEndMenuManager.m_bGameNotLoaded = true;
+
+ FrontEndMenuManager.m_bStartUpFrontEndRequested = true;
+
+ if ( defaultFullscreenRes )
+ {
+ defaultFullscreenRes = FALSE;
+ FrontEndMenuManager.m_nPrefsVideoMode = GcurSelVM;
+ FrontEndMenuManager.m_nDisplayVideoMode = GcurSelVM;
+ }
+
+ gGameState = GS_FRONTEND;
+ TRACE("gGameState = GS_FRONTEND;");
+ break;
+ }
+
+ case GS_FRONTEND:
+ {
+ if(!WindowIconified)
+ RsEventHandler(rsFRONTENDIDLE, nil);
+
+#ifdef PS2_MENU
+ if ( !FrontEndMenuManager.m_bMenuActive || TheMemoryCard.m_bWantToLoad )
+#else
+ if ( !FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bWantToLoad )
+#endif
+ {
+ gGameState = GS_INIT_PLAYING_GAME;
+ TRACE("gGameState = GS_INIT_PLAYING_GAME;");
+ }
+
+#ifdef PS2_MENU
+ if (TheMemoryCard.m_bWantToLoad )
+#else
+ if ( FrontEndMenuManager.m_bWantToLoad )
+#endif
+ {
+ InitialiseGame();
+ FrontEndMenuManager.m_bGameNotLoaded = false;
+ gGameState = GS_PLAYING_GAME;
+ TRACE("gGameState = GS_PLAYING_GAME;");
+ }
+ break;
+ }
+#endif
+
+ case GS_INIT_PLAYING_GAME:
+ {
+#ifdef PS2_MENU
+ CGame::Initialise("DATA\\GTA3.DAT");
+
+ //LoadingScreen("Starting Game", NULL, GetRandomSplashScreen());
+
+ if ( TheMemoryCard.CheckCardInserted(CARD_ONE) == CMemoryCard::NO_ERR_SUCCESS
+ && TheMemoryCard.ChangeDirectory(CARD_ONE, TheMemoryCard.Cards[CARD_ONE].dir)
+ && TheMemoryCard.FindMostRecentFileName(CARD_ONE, TheMemoryCard.MostRecentFile) == true
+ && TheMemoryCard.CheckDataNotCorrupt(TheMemoryCard.MostRecentFile))
+ {
+ strcpy(TheMemoryCard.LoadFileName, TheMemoryCard.MostRecentFile);
+ TheMemoryCard.b_FoundRecentSavedGameWantToLoad = true;
+
+ if (CMenuManager::m_PrefsLanguage != TheMemoryCard.GetLanguageToLoad())
+ {
+ CMenuManager::m_PrefsLanguage = TheMemoryCard.GetLanguageToLoad();
+ TheText.Unload();
+ TheText.Load();
+ }
+
+ CGame::currLevel = (eLevelName)TheMemoryCard.GetLevelToLoad();
+ }
+#else
+ InitialiseGame();
+
+ FrontEndMenuManager.m_bGameNotLoaded = false;
+#endif
+ gGameState = GS_PLAYING_GAME;
+ TRACE("gGameState = GS_PLAYING_GAME;");
+ break;
+ }
+
+ case GS_PLAYING_GAME:
+ {
+ float ms = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
+ if ( RwInitialised )
+ {
+ if (!FrontEndMenuManager.m_PrefsFrameLimiter || (1000.0f / (float)RsGlobal.maxFPS) < ms)
+ RsEventHandler(rsIDLE, (void *)TRUE);
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ if ( RwCameraBeginUpdate(Scene.camera) )
+ {
+ RwCameraEndUpdate(Scene.camera);
+ ForegroundApp = TRUE;
+ RsEventHandler(rsACTIVATE, (void *)TRUE);
+ }
+
+ }
+ }
+
+
+ /*
+ * About to shut down - block resize events again...
+ */
+ RwInitialised = FALSE;
+
+ FrontEndMenuManager.UnloadTextures();
+#ifdef PS2_MENU
+ if ( !(FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad))
+ break;
+#else
+ if ( !FrontEndMenuManager.m_bWantToRestart )
+ break;
+#endif
+
+ CPad::ResetCheats();
+ CPad::StopPadsShaking();
+
+ DMAudio.ChangeMusicMode(MUSICMODE_DISABLE);
+
+#ifdef PS2_MENU
+ CGame::ShutDownForRestart();
+#endif
+
+ CTimer::Stop();
+
+#ifdef PS2_MENU
+ if (FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad)
+ {
+ if (TheMemoryCard.b_FoundRecentSavedGameWantToLoad)
+ {
+ FrontEndMenuManager.m_bWantToRestart = true;
+ TheMemoryCard.m_bWantToLoad = true;
+ }
+
+ CGame::InitialiseWhenRestarting();
+ DMAudio.ChangeMusicMode(MUSICMODE_GAME);
+ FrontEndMenuManager.m_bWantToRestart = false;
+
+ continue;
+ }
+
+ CGame::ShutDown();
+ CTimer::Stop();
+
+ break;
+#else
+ if ( FrontEndMenuManager.m_bWantToLoad )
+ {
+ CGame::ShutDownForRestart();
+ CGame::InitialiseWhenRestarting();
+ DMAudio.ChangeMusicMode(MUSICMODE_GAME);
+ LoadSplash(GetLevelSplashScreen(CGame::currLevel));
+ FrontEndMenuManager.m_bWantToLoad = false;
+ }
+ else
+ {
+#ifndef MASTER
+ if ( gbModelViewer )
+ CAnimViewer::Shutdown();
+ else
+#endif
+ if ( gGameState == GS_PLAYING_GAME )
+ CGame::ShutDown();
+
+ CTimer::Stop();
+
+ if ( FrontEndMenuManager.m_bFirstTime == true )
+ {
+ gGameState = GS_INIT_FRONTEND;
+ TRACE("gGameState = GS_INIT_FRONTEND;");
+ }
+ else
+ {
+ gGameState = GS_INIT_PLAYING_GAME;
+ TRACE("gGameState = GS_INIT_PLAYING_GAME;");
+ }
+ }
+
+ FrontEndMenuManager.m_bFirstTime = false;
+ FrontEndMenuManager.m_bWantToRestart = false;
+#endif
+ }
+
+#ifndef MASTER
+ if ( gbModelViewer )
+ CAnimViewer::Shutdown();
+ else
+#endif
+ if ( gGameState == GS_PLAYING_GAME )
+ CGame::ShutDown();
+
+ DMAudio.Terminate();
+
+ _psFreeVideoModeList();
+
+
+ /*
+ * Tidy up the 3D (RenderWare) components of the application...
+ */
+ RsEventHandler(rsRWTERMINATE, nil);
+
+ /*
+ * Free the platform dependent data...
+ */
+ RsEventHandler(rsTERMINATE, nil);
+
+#ifdef _WIN32
+ /*
+ * Free the argv strings...
+ */
+ free(argv);
+
+ SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &SavedStickyKeys, SPIF_SENDCHANGE);
+ SystemParametersInfo(SPI_SETPOWEROFFACTIVE, TRUE, nil, SPIF_SENDCHANGE);
+ SystemParametersInfo(SPI_SETLOWPOWERACTIVE, TRUE, nil, SPIF_SENDCHANGE);
+ SetErrorMode(0);
+#endif
+
+ return 0;
+}
+
+/*
+ *****************************************************************************
+ */
+
+RwV2d leftStickPos;
+RwV2d rightStickPos;
+
+void CapturePad(RwInt32 padID)
+{
+ int8 glfwPad = -1;
+
+ if( padID == 0 )
+ glfwPad = PSGLOBAL(joy1id);
+ else if( padID == 1)
+ glfwPad = PSGLOBAL(joy2id);
+ else
+ assert("invalid padID");
+
+ if ( glfwPad == -1 )
+ return;
+
+ int numButtons, numAxes;
+ const uint8 *buttons = glfwGetJoystickButtons(glfwPad, &numButtons);
+ const float *axes = glfwGetJoystickAxes(glfwPad, &numAxes);
+ GLFWgamepadstate gamepadState;
+
+ if (ControlsManager.m_bFirstCapture == false) {
+ memcpy(&ControlsManager.m_OldState, &ControlsManager.m_NewState, sizeof(ControlsManager.m_NewState));
+ } else {
+ // In case connected gamepad doesn't have L-R trigger axes.
+ ControlsManager.m_NewState.mappedButtons[15] = ControlsManager.m_NewState.mappedButtons[16] = 0;
+ }
+
+ ControlsManager.m_NewState.buttons = (uint8*)buttons;
+ ControlsManager.m_NewState.numButtons = numButtons;
+ ControlsManager.m_NewState.id = glfwPad;
+ ControlsManager.m_NewState.isGamepad = glfwGetGamepadState(glfwPad, &gamepadState);
+ if (ControlsManager.m_NewState.isGamepad) {
+ memcpy(&ControlsManager.m_NewState.mappedButtons, gamepadState.buttons, sizeof(gamepadState.buttons));
+ float lt = gamepadState.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER], rt = gamepadState.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER];
+
+ // glfw returns 0.0 for non-existent axises(which is bullocks) so we treat it as deadzone, and keep value of previous frame.
+ // otherwise if this axis is present, -1 = released, 1 = pressed
+ if (lt != 0.0f)
+ ControlsManager.m_NewState.mappedButtons[15] = lt > -0.8f;
+
+ if (rt != 0.0f)
+ ControlsManager.m_NewState.mappedButtons[16] = rt > -0.8f;
+ }
+ // TODO? L2-R2 axes(not buttons-that's fine) on joysticks that don't have SDL gamepad mapping AREN'T handled, and I think it's impossible to do without mapping.
+
+ if (ControlsManager.m_bFirstCapture == true) {
+ memcpy(&ControlsManager.m_OldState, &ControlsManager.m_NewState, sizeof(ControlsManager.m_NewState));
+
+ ControlsManager.m_bFirstCapture = false;
+ }
+
+ RsPadButtonStatus bs;
+ bs.padID = padID;
+
+ RsPadEventHandler(rsPADBUTTONUP, (void *)&bs);
+
+ // Gamepad axes are guaranteed to return 0.0f if that particular gamepad doesn't have that axis.
+ // And that's really good for sticks, because gamepads return 0.0 for them when sticks are in released state.
+ if ( glfwPad != -1 ) {
+ leftStickPos.x = ControlsManager.m_NewState.isGamepad ? gamepadState.axes[GLFW_GAMEPAD_AXIS_LEFT_X] : numAxes >= 1 ? axes[0] : 0.0f;
+ leftStickPos.y = ControlsManager.m_NewState.isGamepad ? gamepadState.axes[GLFW_GAMEPAD_AXIS_LEFT_Y] : numAxes >= 2 ? axes[1] : 0.0f;
+
+ rightStickPos.x = ControlsManager.m_NewState.isGamepad ? gamepadState.axes[GLFW_GAMEPAD_AXIS_RIGHT_X] : numAxes >= 3 ? axes[2] : 0.0f;
+ rightStickPos.y = ControlsManager.m_NewState.isGamepad ? gamepadState.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y] : numAxes >= 4 ? axes[3] : 0.0f;
+ }
+
+ {
+ if (CPad::m_bMapPadOneToPadTwo)
+ bs.padID = 1;
+
+ RsPadEventHandler(rsPADBUTTONUP, (void *)&bs);
+ RsPadEventHandler(rsPADBUTTONDOWN, (void *)&bs);
+ }
+
+ {
+ if (CPad::m_bMapPadOneToPadTwo)
+ bs.padID = 1;
+
+ CPad *pad = CPad::GetPad(bs.padID);
+
+ if ( Abs(leftStickPos.x) > 0.3f )
+ pad->PCTempJoyState.LeftStickX = (int32)(leftStickPos.x * 128.0f);
+
+ if ( Abs(leftStickPos.y) > 0.3f )
+ pad->PCTempJoyState.LeftStickY = (int32)(leftStickPos.y * 128.0f);
+
+ if ( Abs(rightStickPos.x) > 0.3f )
+ pad->PCTempJoyState.RightStickX = (int32)(rightStickPos.x * 128.0f);
+
+ if ( Abs(rightStickPos.y) > 0.3f )
+ pad->PCTempJoyState.RightStickY = (int32)(rightStickPos.y * 128.0f);
+ }
+
+ return;
+}
+
+void joysChangeCB(int jid, int event)
+{
+ if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid)) {
+ if (PSGLOBAL(joy1id) == -1) {
+ PSGLOBAL(joy1id) = jid;
+#ifdef DETECT_JOYSTICK_MENU
+ strcpy(gSelectedJoystickName, glfwGetJoystickName(jid));
+#endif
+ // This is behind LOAD_INI_SETTINGS, because otherwise the Init call below will destroy/overwrite your bindings.
+#ifdef LOAD_INI_SETTINGS
+ int count;
+ glfwGetJoystickButtons(PSGLOBAL(joy1id), &count);
+ ControlsManager.InitDefaultControlConfigJoyPad(count);
+#endif
+ } else if (PSGLOBAL(joy2id) == -1)
+ PSGLOBAL(joy2id) = jid;
+
+ } else if (event == GLFW_DISCONNECTED) {
+ if (PSGLOBAL(joy1id) == jid) {
+ PSGLOBAL(joy1id) = -1;
+ } else if (PSGLOBAL(joy2id) == jid)
+ PSGLOBAL(joy2id) = -1;
+ }
+}
+
+#if (defined(_MSC_VER))
+int strcasecmp(const char* str1, const char* str2)
+{
+ return _strcmpi(str1, str2);
+}
+int strncasecmp(const char *str1, const char *str2, size_t len)
+{
+ return _strnicmp(str1, str2, len);
+}
+#endif
+#endif
diff --git a/src/skel/platform.h b/src/skel/platform.h
new file mode 100644
index 0000000..0475d20
--- /dev/null
+++ b/src/skel/platform.h
@@ -0,0 +1,61 @@
+#ifndef PLATFORM_H
+#define PLATFORM_H
+
+// Functions that's different on glfw/win etc. but have same signature (but if a function only used in win.cpp you can keep in win.h)
+
+#include "rwcore.h"
+#include "skeleton.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#ifdef _WIN32
+extern RwUInt32 psTimer(void);
+#else
+extern double psTimer(void);
+#endif
+
+extern RwBool psInitialize(void);
+extern void psTerminate(void);
+
+extern void psCameraShowRaster(RwCamera *camera);
+extern RwBool psCameraBeginUpdate(RwCamera *camera);
+extern RwImage *psGrabScreen(RwCamera *camera);
+
+extern void psMouseSetPos(RwV2d *pos);
+
+extern RwBool psSelectDevice();
+
+extern RwMemoryFunctions *psGetMemoryFunctions(void);
+
+/* install the platform specific file system */
+extern RwBool psInstallFileSystem(void);
+
+
+/* Handle native texture support */
+extern RwBool psNativeTextureSupport(void);
+
+extern void _InputTranslateShiftKeyUpDown(RsKeyCodes* rs);
+extern long _InputInitialiseMouse(bool exclusive); // returns HRESULT on Windows actually
+extern void _InputShutdownMouse();
+extern bool _InputMouseNeedsExclusive();
+extern void _InputInitialiseJoys();
+
+extern void HandleExit();
+
+extern void _psSelectScreenVM(RwInt32 videoMode);
+
+extern void InitialiseLanguage();
+
+extern RwBool _psSetVideoMode(RwInt32 subSystem, RwInt32 videoMode);
+
+extern RwChar** _psGetVideoModeList();
+
+extern RwInt32 _psGetNumVideModes();
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PLATFORM_H */
diff --git a/src/skel/skeleton.cpp b/src/skel/skeleton.cpp
new file mode 100644
index 0000000..2bb2346
--- /dev/null
+++ b/src/skel/skeleton.cpp
@@ -0,0 +1,428 @@
+#include "common.h"
+
+
+#include <stdio.h>
+#include <math.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "rwcore.h"
+
+#include "skeleton.h"
+#include "platform.h"
+#include "main.h"
+#include "MemoryHeap.h"
+
+static RwBool DefaultVideoMode = TRUE;
+
+RsGlobalType RsGlobal;
+
+#ifdef _WIN32
+RwUInt32
+#else
+double
+#endif
+RsTimer(void)
+{
+ return psTimer();
+}
+
+
+/*
+ *****************************************************************************
+ */
+void
+RsCameraShowRaster(RwCamera * camera)
+{
+ psCameraShowRaster(camera);
+
+ return;
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+RsCameraBeginUpdate(RwCamera * camera)
+{
+ return psCameraBeginUpdate(camera);
+}
+
+/*
+ *****************************************************************************
+ */
+RwImage*
+RsGrabScreen(RwCamera *camera)
+{
+ return psGrabScreen(camera);
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+RsRegisterImageLoader(void)
+{
+ return TRUE;
+}
+
+/*
+ *****************************************************************************
+ */
+static RwBool
+RsSetDebug(void)
+{
+ return TRUE;
+}
+
+/*
+ *****************************************************************************
+ */
+void
+RsMouseSetPos(RwV2d * pos)
+{
+ psMouseSetPos(pos);
+
+ return;
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+RsSelectDevice(void)
+{
+ return psSelectDevice();
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+RsInputDeviceAttach(RsInputDeviceType inputDevice,
+ RsInputEventHandler inputEventHandler)
+{
+ switch (inputDevice)
+ {
+ case rsKEYBOARD:
+ {
+ RsGlobal.keyboard.inputEventHandler = inputEventHandler;
+ RsGlobal.keyboard.used = TRUE;
+ break;
+ }
+ case rsMOUSE:
+ {
+ RsGlobal.mouse.inputEventHandler = inputEventHandler;
+ RsGlobal.mouse.used = TRUE;
+ break;
+ }
+ case rsPAD:
+ {
+ RsGlobal.pad.inputEventHandler = inputEventHandler;
+ RsGlobal.pad.used = TRUE;
+ break;
+ }
+ default:
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *****************************************************************************
+ */
+static RwBool
+rsCommandLine(RwChar *arg)
+{
+ RsEventHandler(rsFILELOAD, arg);
+
+ return TRUE;
+}
+
+
+/*
+ *****************************************************************************
+ */
+static RwBool
+rsPreInitCommandLine(RwChar *arg)
+{
+ if( !strcmp(arg, RWSTRING("-vms")) )
+ {
+ DefaultVideoMode = FALSE;
+
+ return TRUE;
+ }
+#ifndef MASTER
+ if (!strcmp(arg, RWSTRING("-animviewer")))
+ {
+ gbModelViewer = TRUE;
+
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+/*
+ *****************************************************************************
+ */
+RsEventStatus
+RsKeyboardEventHandler(RsEvent event, void *param)
+{
+ if (RsGlobal.keyboard.used)
+ {
+ return RsGlobal.keyboard.inputEventHandler(event, param);
+ }
+
+ return rsEVENTNOTPROCESSED;
+}
+
+/*
+ *****************************************************************************
+ */
+RsEventStatus
+RsPadEventHandler(RsEvent event, void *param)
+{
+ if (RsGlobal.pad.used)
+ {
+ return RsGlobal.pad.inputEventHandler(event, param);
+ }
+
+ return rsEVENTNOTPROCESSED;
+}
+
+/*
+ *****************************************************************************
+ */
+RsEventStatus
+RsEventHandler(RsEvent event, void *param)
+{
+ RsEventStatus result;
+ RsEventStatus es;
+
+ /*
+ * Give the application an opportunity to override any events...
+ */
+ es = AppEventHandler(event, param);
+
+ /*
+ * We never allow the app to replace the quit behaviour,
+ * only to intercept...
+ */
+ if (event == rsQUITAPP)
+ {
+ /*
+ * Set the flag which causes the event loop to exit...
+ */
+ RsGlobal.quit = TRUE;
+ }
+
+ if (es == rsEVENTNOTPROCESSED)
+ {
+ switch (event)
+ {
+ case rsSELECTDEVICE:
+ result =
+ (RsSelectDevice()? rsEVENTPROCESSED : rsEVENTERROR);
+ break;
+
+ case rsCOMMANDLINE:
+ result = (rsCommandLine((RwChar *) param) ?
+ rsEVENTPROCESSED : rsEVENTERROR);
+ break;
+ case rsPREINITCOMMANDLINE:
+ result = (rsPreInitCommandLine((RwChar *) param) ?
+ rsEVENTPROCESSED : rsEVENTERROR);
+ break;
+ case rsINITDEBUG:
+ result =
+ (RsSetDebug()? rsEVENTPROCESSED : rsEVENTERROR);
+ break;
+
+ case rsREGISTERIMAGELOADER:
+ result = (RsRegisterImageLoader()?
+ rsEVENTPROCESSED : rsEVENTERROR);
+ break;
+
+ case rsRWTERMINATE:
+ RsRwTerminate();
+ result = (rsEVENTPROCESSED);
+ break;
+
+ case rsRWINITIALIZE:
+ result = (RsRwInitialize(param) ?
+ rsEVENTPROCESSED : rsEVENTERROR);
+ break;
+
+ case rsTERMINATE:
+ RsTerminate();
+ result = (rsEVENTPROCESSED);
+ break;
+
+ case rsINITIALIZE:
+ result =
+ (RsInitialize()? rsEVENTPROCESSED : rsEVENTERROR);
+ break;
+
+ default:
+ result = (es);
+ break;
+
+ }
+ }
+ else
+ {
+ result = (es);
+ }
+
+ return result;
+}
+
+/*
+ *****************************************************************************
+ */
+void
+RsRwTerminate(void)
+{
+ /* Close RenderWare */
+
+ RwEngineStop();
+ RwEngineClose();
+ RwEngineTerm();
+
+ return;
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+RsRwInitialize(void *displayID)
+{
+ RwEngineOpenParams openParams;
+
+ /*
+ * Start RenderWare...
+ */
+
+ if (!RwEngineInit(psGetMemoryFunctions(), 0, rsRESOURCESDEFAULTARENASIZE))
+ {
+ return (FALSE);
+ }
+
+ /*
+ * Install any platform specific file systems...
+ */
+ psInstallFileSystem();
+
+ /*
+ * Initialize debug message handling...
+ */
+ RsEventHandler(rsINITDEBUG, nil);
+
+ /*
+ * Attach all plugins...
+ */
+ if (RsEventHandler(rsPLUGINATTACH, nil) == rsEVENTERROR)
+ {
+ return (FALSE);
+ }
+
+ /*
+ * Attach input devices...
+ */
+ if (RsEventHandler(rsINPUTDEVICEATTACH, nil) == rsEVENTERROR)
+ {
+ return (FALSE);
+ }
+
+ openParams.displayID = displayID;
+
+ if (!RwEngineOpen(&openParams))
+ {
+ RwEngineTerm();
+ return (FALSE);
+ }
+
+ if (RsEventHandler(rsSELECTDEVICE, displayID) == rsEVENTERROR)
+ {
+ RwEngineClose();
+ RwEngineTerm();
+ return (FALSE);
+ }
+
+ if (!RwEngineStart())
+ {
+ RwEngineClose();
+ RwEngineTerm();
+ return (FALSE);
+ }
+
+ /*
+ * Register loaders for an image with a particular file extension...
+ */
+ RsEventHandler(rsREGISTERIMAGELOADER, nil);
+
+ psNativeTextureSupport();
+
+ RwTextureSetAutoMipmapping(TRUE);
+ RwTextureSetMipmapping(FALSE);
+
+ return TRUE;
+}
+
+/*
+ *****************************************************************************
+ */
+void
+RsTerminate(void)
+{
+ psTerminate();
+
+ return;
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+RsInitialize(void)
+{
+ /*
+ * Initialize Platform independent data...
+ */
+ RwBool result;
+
+ RsGlobal.appName = RWSTRING("GTA: Vice City");
+ RsGlobal.maximumWidth = DEFAULT_SCREEN_WIDTH;
+ RsGlobal.maximumHeight = DEFAULT_SCREEN_HEIGHT;
+ RsGlobal.width = DEFAULT_SCREEN_WIDTH;
+ RsGlobal.height = DEFAULT_SCREEN_HEIGHT;
+
+ RsGlobal.maxFPS = 30;
+
+ RsGlobal.quit = FALSE;
+
+ /* setup the keyboard */
+ RsGlobal.keyboard.inputDeviceType = rsKEYBOARD;
+ RsGlobal.keyboard.inputEventHandler = nil;
+ RsGlobal.keyboard.used = FALSE;
+
+ /* setup the mouse */
+ RsGlobal.mouse.inputDeviceType = rsMOUSE;
+ RsGlobal.mouse.inputEventHandler = nil;
+ RsGlobal.mouse.used = FALSE;
+
+ /* setup the pad */
+ RsGlobal.pad.inputDeviceType = rsPAD;
+ RsGlobal.pad.inputEventHandler = nil;
+ RsGlobal.pad.used = FALSE;
+
+ result = psInitialize();
+
+ return result;
+}
diff --git a/src/skel/skeleton.h b/src/skel/skeleton.h
new file mode 100644
index 0000000..380b6c0
--- /dev/null
+++ b/src/skel/skeleton.h
@@ -0,0 +1,290 @@
+#ifndef SKELETON_H
+#define SKELETON_H
+
+#include "rwcore.h"
+
+/* Default arena size depending on platform. */
+#define rsRESOURCESDEFAULTARENASIZE (1 << 20)
+
+#if (!defined(RsSprintf))
+#define RsSprintf rwsprintf
+#endif /* (!defined(RsSprintf)) */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#if (!defined(RSASSERT))
+#define RSASSERT(_condition) /* No-op */
+#endif /* (!defined(RSASSERT)) */
+
+#define RSASSERTISTYPE(_f, _t) \
+ RSASSERT( (!(_f)) || ((((const RwObject *)(_f))->type)==(_t)) )
+
+enum RsInputDeviceType
+{
+ rsKEYBOARD,
+ rsMOUSE,
+ rsPAD
+};
+typedef enum RsInputDeviceType RsInputDeviceType;
+
+enum RsEventStatus
+{
+ rsEVENTERROR,
+ rsEVENTPROCESSED,
+ rsEVENTNOTPROCESSED
+};
+typedef enum RsEventStatus RsEventStatus;
+
+enum RsEvent
+{
+ rsCAMERASIZE,
+ rsCOMMANDLINE,
+ rsFILELOAD,
+ rsINITDEBUG,
+ rsINPUTDEVICEATTACH,
+ rsLEFTBUTTONDOWN,
+ rsLEFTBUTTONUP,
+ rsMOUSEMOVE,
+ rsMOUSEWHEELMOVE,
+ rsPLUGINATTACH,
+ rsREGISTERIMAGELOADER,
+ rsRIGHTBUTTONDOWN,
+ rsRIGHTBUTTONUP,
+ _rs_13,
+ _rs_14,
+ _rs_15,
+ _rs_16,
+ _rs_17,
+ _rs_18,
+ _rs_19,
+ _rs_20,
+ rsRWINITIALIZE,
+ rsRWTERMINATE,
+ rsSELECTDEVICE,
+ rsINITIALIZE,
+ rsTERMINATE,
+ rsIDLE,
+ rsFRONTENDIDLE,
+ rsKEYDOWN,
+ rsKEYUP,
+ rsQUITAPP,
+ rsPADBUTTONDOWN,
+ rsPADBUTTONUP,
+ rsPADANALOGUELEFT,
+ rsPADANALOGUELEFTRESET,
+ rsPADANALOGUERIGHT,
+ rsPADANALOGUERIGHTRESET,
+ rsPREINITCOMMANDLINE,
+ rsACTIVATE,
+};
+
+typedef enum RsEvent RsEvent;
+
+typedef RsEventStatus (*RsInputEventHandler)(RsEvent event, void *param);
+
+typedef struct RsInputDevice RsInputDevice;
+struct RsInputDevice
+{
+ RsInputDeviceType inputDeviceType;
+ RwBool used;
+ RsInputEventHandler inputEventHandler;
+};
+
+typedef struct RsGlobalType RsGlobalType;
+struct RsGlobalType
+{
+ const RwChar *appName;
+ RwInt32 width;
+ RwInt32 height;
+ RwInt32 maximumWidth;
+ RwInt32 maximumHeight;
+ RwInt32 maxFPS;
+ RwBool quit;
+
+ void *ps; /* platform specific data */
+
+ RsInputDevice keyboard;
+ RsInputDevice mouse;
+ RsInputDevice pad;
+};
+
+enum RsKeyCodes
+{
+ rsESC = 1000,
+
+ rsF1 = 1001,
+ rsF2 = 1002,
+ rsF3 = 1003,
+ rsF4 = 1004,
+ rsF5 = 1005,
+ rsF6 = 1006,
+ rsF7 = 1007,
+ rsF8 = 1008,
+ rsF9 = 1009,
+ rsF10 = 1010,
+ rsF11 = 1011,
+ rsF12 = 1012,
+
+ rsINS = 1013,
+ rsDEL = 1014,
+ rsHOME = 1015,
+ rsEND = 1016,
+ rsPGUP = 1017,
+ rsPGDN = 1018,
+
+ rsUP = 1019,
+ rsDOWN = 1020,
+ rsLEFT = 1021,
+ rsRIGHT = 1022,
+
+ rsDIVIDE = 1023,
+ rsTIMES = 1024,
+ rsPLUS = 1025,
+ rsMINUS = 1026,
+ rsPADDEL = 1027,
+ rsPADEND = 1028,
+ rsPADDOWN = 1029,
+ rsPADPGDN = 1030,
+ rsPADLEFT = 1031,
+ rsPAD5 = 1032,
+ rsNUMLOCK = 1033,
+ rsPADRIGHT = 1034,
+ rsPADHOME = 1035,
+ rsPADUP = 1036,
+ rsPADPGUP = 1037,
+ rsPADINS = 1038,
+ rsPADENTER = 1039,
+
+ rsSCROLL = 1040,
+ rsPAUSE = 1041,
+
+ rsBACKSP = 1042,
+ rsTAB = 1043,
+ rsCAPSLK = 1044,
+ rsENTER = 1045,
+ rsLSHIFT = 1046,
+ rsRSHIFT = 1047,
+ rsSHIFT = 1048,
+ rsLCTRL = 1049,
+ rsRCTRL = 1050,
+ rsLALT = 1051,
+ rsRALT = 1052,
+ rsLWIN = 1053,
+ rsRWIN = 1054,
+ rsAPPS = 1055,
+
+ rsNULL = 1056,
+
+ rsMOUSELEFTBUTTON = 1,
+ rsMOUSMIDDLEBUTTON = 2,
+ rsMOUSERIGHTBUTTON = 3,
+ rsMOUSEWHEELUPBUTTON = 4,
+ rsMOUSEWHEELDOWNBUTTON = 5,
+ rsMOUSEX1BUTTON = 6,
+ rsMOUSEX2BUTTON = 7,
+};
+typedef enum RsKeyCodes RsKeyCodes;
+
+typedef struct RsKeyStatus RsKeyStatus;
+struct RsKeyStatus
+{
+ RwInt32 keyCharCode;
+};
+
+typedef struct RsPadButtonStatus RsPadButtonStatus;
+struct RsPadButtonStatus
+{
+ RwInt32 padID;
+};
+
+enum RsPadButtons
+{
+ rsPADNULL = 0,
+
+ rsPADBUTTON1 = 1,
+ rsPADBUTTON2 = 2,
+ rsPADBUTTON3 = 3,
+ rsPADBUTTON4 = 4,
+
+ rsPADBUTTON5 = 5,
+ rsPADBUTTON6 = 6,
+ rsPADBUTTON7 = 7,
+ rsPADBUTTON8 = 8,
+
+ rsPADSELECT = 9,
+
+ rsPADBUTTONA1 = 10,
+ rsPADBUTTONA2 = 11,
+
+ rsPADSTART = 12,
+
+ rsPADDPADUP = 13,
+ rsPADDPADRIGHT = 14,
+ rsPADDPADDOWN = 15,
+ rsPADDPADLEFT = 16,
+};
+typedef enum RsPadButtons RsPadButtons;
+
+
+extern RsGlobalType RsGlobal;
+
+extern RsEventStatus AppEventHandler(RsEvent event, void *param);
+extern RwBool AttachInputDevices(void);
+
+extern RsEventStatus RsEventHandler(RsEvent event, void *param);
+extern RsEventStatus RsKeyboardEventHandler(RsEvent event, void *param);
+extern RsEventStatus RsPadEventHandler(RsEvent event, void *param);
+
+extern RwBool
+RsInitialize(void);
+
+extern RwBool
+RsRegisterImageLoader(void);
+
+extern RwBool
+RsRwInitialize(void *param);
+
+extern RwBool
+RsSelectDevice(void);
+
+extern RwBool
+RsInputDeviceAttach(RsInputDeviceType inputDevice,
+ RsInputEventHandler inputEventHandler);
+
+#ifdef _WIN32
+extern RwUInt32
+#else
+extern double
+#endif
+RsTimer(void);
+
+extern void
+RsCameraShowRaster(RwCamera *camera);
+
+extern RwBool
+RsCameraBeginUpdate(RwCamera *camera);
+
+//TODO
+//extern void
+//RsMouseSetVisibility(RwBool visible);
+
+extern RwImage*
+RsGrabScreen(RwCamera *camera);
+
+extern void
+RsMouseSetPos(RwV2d *pos);
+
+extern void
+RsRwTerminate(void);
+
+extern void
+RsTerminate(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SKELETON_H */
diff --git a/src/skel/win/gtavc.ico b/src/skel/win/gtavc.ico
new file mode 100644
index 0000000..7bfcc5a
--- /dev/null
+++ b/src/skel/win/gtavc.ico
Binary files differ
diff --git a/src/skel/win/resource.h b/src/skel/win/resource.h
new file mode 100644
index 0000000..93f1421
--- /dev/null
+++ b/src/skel/win/resource.h
@@ -0,0 +1,21 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by dungeon.rc
+//
+#define IDD_DIALOG1 104
+#define IDC_DEVICESEL 1000
+#define IDC_VIDMODE 1001
+#define IDEXIT 1002
+#define IDC_SELECTDEVICE 1005
+
+#define IDI_MAIN_ICON 100
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 104
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp
new file mode 100644
index 0000000..21bd0eb
--- /dev/null
+++ b/src/skel/win/win.cpp
@@ -0,0 +1,3460 @@
+#if defined RW_D3D9 || defined RWLIBS || defined __MWERKS__
+
+#define _WIN32_WINDOWS 0x0500
+#define WINVER 0x0500
+
+#include <winerror.h>
+#include <windows.h>
+#include <mmsystem.h>
+#include <shellapi.h>
+
+#include <windowsx.h>
+#include <basetsd.h>
+
+#include <regstr.h>
+#include <shlobj.h>
+
+#include <dbt.h>
+
+#pragma warning( push )
+#pragma warning( disable : 4005)
+
+#ifdef __MWERKS__
+#define MAPVK_VK_TO_CHAR (2) // this is missing from codewarrior win32 headers - but it gets used ... how?
+#endif
+
+#include <ddraw.h>
+#include <DShow.h>
+#pragma warning( pop )
+
+#define WM_GRAPHNOTIFY WM_USER+13
+
+#ifndef USE_D3D9
+#pragma comment( lib, "d3d8.lib" )
+#endif
+#pragma comment( lib, "ddraw.lib" )
+#pragma comment( lib, "Winmm.lib" )
+#pragma comment( lib, "dxguid.lib" )
+#pragma comment( lib, "strmiids.lib" )
+#pragma comment( lib, "dinput8.lib" )
+
+#define WITHD3D
+#define WITHDINPUT
+#include "common.h"
+#if (defined(_MSC_VER))
+#include <tchar.h>
+#endif /* (defined(_MSC_VER)) */
+#include <stdio.h>
+#include "rwcore.h"
+#include "resource.h"
+#include "skeleton.h"
+#include "platform.h"
+#include "crossplatform.h"
+
+#define MAX_SUBSYSTEMS (16)
+
+static RwBool ForegroundApp = TRUE;
+
+static RwBool RwInitialised = FALSE;
+
+static RwSubSystemInfo GsubSysInfo[MAX_SUBSYSTEMS];
+static RwInt32 GnumSubSystems = 0;
+static RwInt32 GcurSel = 0, GcurSelVM = 0;
+
+static RwBool startupDeactivate;
+
+static RwBool useDefault;
+
+/* Class name for the MS Window's window class. */
+
+static const RwChar *AppClassName = RWSTRING("Grand theft auto 3");
+
+static psGlobalType PsGlobal;
+
+
+#define PSGLOBAL(var) (((psGlobalType *)(RsGlobal.ps))->var)
+
+#undef MAKEPOINTS
+#define MAKEPOINTS(l) (*((POINTS /*FAR*/ *)&(l)))
+
+#define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
+#define JIF(x) if (FAILED(hr=(x))) \
+ {debug(TEXT("FAILED(hr=0x%x) in ") TEXT(#x) TEXT("\n"), hr); return;}
+
+#include "main.h"
+#include "FileMgr.h"
+#include "Text.h"
+#include "Pad.h"
+#include "Timer.h"
+#include "DMAudio.h"
+#include "ControllerConfig.h"
+#include "Frontend.h"
+#include "Game.h"
+#include "PCSave.h"
+#include "AnimViewer.h"
+#include "MemoryMgr.h"
+
+#ifdef PS2_MENU
+#include "MemoryCard.h"
+#include "Font.h"
+#endif
+
+VALIDATE_SIZE(psGlobalType, 0x28);
+
+// DirectShow interfaces
+IGraphBuilder *pGB = nil;
+IMediaControl *pMC = nil;
+IMediaEventEx *pME = nil;
+IVideoWindow *pVW = nil;
+IMediaSeeking *pMS = nil;
+
+DWORD dwDXVersion;
+SIZE_T _dwMemTotalPhys;
+size_t _dwMemAvailPhys;
+SIZE_T _dwMemTotalVirtual;
+SIZE_T _dwMemAvailVirtual;
+DWORD _dwMemTotalVideo;
+DWORD _dwMemAvailVideo;
+DWORD _dwOperatingSystemVersion;
+
+RwUInt32 gGameState;
+CJoySticks AllValidWinJoys;
+
+#ifdef DETECT_JOYSTICK_MENU
+char gSelectedJoystickName[128] = "";
+#endif
+
+// What is that for anyway?
+#ifndef IMPROVED_VIDEOMODE
+static RwBool defaultFullscreenRes = TRUE;
+#else
+static RwBool defaultFullscreenRes = FALSE;
+static RwInt32 bestWndMode = -1;
+#endif
+
+CJoySticks::CJoySticks()
+{
+ for (int i = 0; i < MAX_JOYSTICKS; i++)
+ {
+ ClearJoyInfo(i);
+ }
+}
+
+void CJoySticks::ClearJoyInfo(int joyID)
+{
+ m_aJoys[joyID].m_State = JOYPAD_UNUSED;
+ m_aJoys[joyID].m_bInitialised = false;
+ m_aJoys[joyID].m_bHasAxisZ = false;
+ m_aJoys[joyID].m_bHasAxisR = false;
+}
+
+
+
+/*
+ *****************************************************************************
+ */
+void _psCreateFolder(LPCSTR path)
+{
+ HANDLE hfle = CreateFile(path, GENERIC_READ,
+ FILE_SHARE_READ,
+ nil,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
+ nil);
+
+ if ( hfle == INVALID_HANDLE_VALUE )
+ CreateDirectory(path, nil);
+ else
+ CloseHandle(hfle);
+}
+
+/*
+ *****************************************************************************
+ */
+const char *_psGetUserFilesFolder()
+{
+#ifdef USE_MY_DOCUMENTS
+ HKEY hKey = NULL;
+
+ static CHAR szUserFiles[256];
+
+ if ( RegOpenKeyEx(HKEY_CURRENT_USER,
+ REGSTR_PATH_SPECIAL_FOLDERS,
+ REG_OPTION_RESERVED,
+ KEY_READ,
+ &hKey) == ERROR_SUCCESS )
+ {
+ DWORD KeyType;
+ DWORD KeycbData = sizeof(szUserFiles);
+ if ( RegQueryValueEx(hKey,
+ "Personal",
+ NULL,
+ &KeyType,
+ (LPBYTE)szUserFiles,
+ &KeycbData) == ERROR_SUCCESS )
+ {
+ RegCloseKey(hKey);
+ strcat(szUserFiles, "\\GTA Vice City User Files");
+ _psCreateFolder(szUserFiles);
+ return szUserFiles;
+ }
+
+ RegCloseKey(hKey);
+ }
+
+ strcpy(szUserFiles, "data");
+ return szUserFiles;
+#else
+ static CHAR szUserFiles[256];
+ strcpy(szUserFiles, "userfiles");
+ _psCreateFolder(szUserFiles);
+ return szUserFiles;
+#endif
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+psCameraBeginUpdate(RwCamera *camera)
+{
+ if ( !RwCameraBeginUpdate(Scene.camera) )
+ {
+ ForegroundApp = FALSE;
+ RsEventHandler(rsACTIVATE, (void *)FALSE);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ *****************************************************************************
+ */
+void
+psCameraShowRaster(RwCamera *camera)
+{
+#ifdef LEGACY_MENU_OPTIONS
+ if (FrontEndMenuManager.m_PrefsVsync || FrontEndMenuManager.m_bMenuActive)
+#else
+ if (FrontEndMenuManager.m_PrefsFrameLimiter || FrontEndMenuManager.m_bMenuActive)
+#endif
+ RwCameraShowRaster(camera, PSGLOBAL(window), rwRASTERFLIPWAITVSYNC);
+ else
+ RwCameraShowRaster(camera, PSGLOBAL(window), rwRASTERFLIPDONTWAIT);
+
+ return;
+}
+
+
+/*
+ *****************************************************************************
+ */
+RwImage *
+psGrabScreen(RwCamera *pCamera)
+{
+#ifndef LIBRW
+ RwRaster *pRaster = RwCameraGetRaster(pCamera);
+ if (RwImage *pImage = RwImageCreate(pRaster->width, pRaster->height, 32)) {
+ RwImageAllocatePixels(pImage);
+ RwImageSetFromRaster(pImage, pRaster);
+ return pImage;
+ }
+#else
+ rw::Image *image = RwCameraGetRaster(pCamera)->toImage();
+ image->removeMask();
+ if(image)
+ return image;
+#endif
+ return nil;
+}
+
+/*
+ *****************************************************************************
+ */
+RwUInt32
+psTimer(void)
+{
+ RwUInt32 time;
+
+ TIMECAPS TimeCaps;
+
+ timeGetDevCaps(&TimeCaps, sizeof(TIMECAPS));
+
+ timeBeginPeriod(TimeCaps.wPeriodMin);
+
+ time = (RwUInt32) timeGetTime();
+
+ timeEndPeriod(TimeCaps.wPeriodMin);
+
+ return time;
+}
+
+/*
+ *****************************************************************************
+ */
+void
+psMouseSetPos(RwV2d *pos)
+{
+ POINT point;
+
+ point.x = (RwInt32) pos->x;
+ point.y = (RwInt32) pos->y;
+
+ ClientToScreen(PSGLOBAL(window), &point);
+
+ SetCursorPos(point.x, point.y);
+
+ PSGLOBAL(lastMousePos.x) = (RwInt32)pos->x;
+
+ PSGLOBAL(lastMousePos.y) = (RwInt32)pos->y;
+
+ return;
+}
+
+/*
+ *****************************************************************************
+ */
+RwMemoryFunctions*
+psGetMemoryFunctions(void)
+{
+#ifdef USE_CUSTOM_ALLOCATOR
+ return &memFuncs;
+#else
+ return nil;
+#endif
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+psInstallFileSystem(void)
+{
+ return (TRUE);
+}
+
+
+/*
+ *****************************************************************************
+ */
+RwBool
+psNativeTextureSupport(void)
+{
+ return RwD3D8DeviceSupportsDXTTexture();
+}
+
+/*
+ *****************************************************************************
+ */
+static HWND
+InitInstance(HANDLE instance)
+{
+ /*
+ * Perform any necessary initialization for this instance of the
+ * application.
+ *
+ * Create the MS Window's window instance for this application. The
+ * initial window size is given by the defined camera size. The window
+ * is not given a title as we set it during Init3D() with information
+ * about the version of RenderWare being used.
+ */
+
+ RECT rect;
+
+ rect.left = rect.top = 0;
+ rect.right = RsGlobal.maximumWidth;
+ rect.bottom = RsGlobal.maximumHeight;
+
+ AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
+
+ return CreateWindow(AppClassName, RsGlobal.appName,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ rect.right - rect.left, rect.bottom - rect.top,
+ (HWND)nil, (HMENU)nil, (HINSTANCE)instance, nil);
+}
+
+void _GetVideoMemInfo(LPDWORD total, LPDWORD avaible)
+{
+ HRESULT hr;
+ LPDIRECTDRAW7 pDD7;
+
+ hr = DirectDrawCreateEx(nil, (VOID**)&pDD7, IID_IDirectDraw7, nil);
+
+ if ( FAILED(hr) )
+ return;
+
+ DDSCAPS2 caps;
+
+ ZeroMemory(&caps, sizeof(DDSCAPS2));
+ caps.dwCaps = DDSCAPS_VIDEOMEMORY;
+
+ pDD7->GetAvailableVidMem(&caps, total, avaible);
+
+ pDD7->Release();
+}
+
+/*
+ *****************************************************************************
+ */
+typedef HRESULT(WINAPI * DIRECTDRAWCREATEEX)( GUID*, VOID**, REFIID, IUnknown* );
+
+
+//-----------------------------------------------------------------------------
+// Name: GetDXVersion()
+// Desc: This function returns the DirectX version number as follows:
+// 0x0000 = No DirectX installed
+// 0x0700 = At least DirectX 7 installed.
+// 0x0800 = At least DirectX 8 installed.
+//
+// Please note that this code is intended as a general guideline. Your
+// app will probably be able to simply query for functionality (via
+// QueryInterface) for one or two components.
+//
+// Please also note:
+// "if( dwDXVersion != 0x500 ) return FALSE;" is VERY BAD.
+// "if( dwDXVersion < 0x500 ) return FALSE;" is MUCH BETTER.
+// to ensure your app will run on future releases of DirectX.
+//-----------------------------------------------------------------------------
+DWORD GetDXVersion()
+{
+ DIRECTDRAWCREATEEX DirectDrawCreateEx = NULL;
+ HINSTANCE hDDrawDLL = nil;
+ HINSTANCE hD3D8DLL = nil;
+ HINSTANCE hDPNHPASTDLL = NULL;
+ DWORD dwDXVersion = 0;
+ //HRESULT hr;
+
+ // First see if DDRAW.DLL even exists.
+ hDDrawDLL = LoadLibrary( "DDRAW.DLL" );
+ if( hDDrawDLL == nil )
+ {
+ dwDXVersion = 0;
+ OutputDebugString( "Couldn't LoadLibrary DDraw\r\n" );
+ return dwDXVersion;
+ }
+
+
+ //-------------------------------------------------------------------------
+ // DirectX 7.0 Checks
+ //-------------------------------------------------------------------------
+
+ // Check for DirectX 7 by creating a DDraw7 object
+ LPDIRECTDRAW7 pDD7;
+ DirectDrawCreateEx = (DIRECTDRAWCREATEEX)GetProcAddress( hDDrawDLL,
+ "DirectDrawCreateEx" );
+ if( nil == DirectDrawCreateEx )
+ {
+ FreeLibrary( hDDrawDLL );
+ OutputDebugString( "Couldn't GetProcAddress DirectDrawCreateEx\r\n" );
+ return dwDXVersion;
+ }
+
+ if( FAILED( DirectDrawCreateEx( nil, (VOID**)&pDD7, IID_IDirectDraw7,
+ nil ) ) )
+ {
+ FreeLibrary( hDDrawDLL );
+ OutputDebugString( "Couldn't DirectDrawCreateEx\r\n" );
+ return dwDXVersion;
+ }
+
+ // DDraw7 was created successfully. We must be at least DX7.0
+ dwDXVersion = 0x700;
+ pDD7->Release();
+
+#ifdef USE_D3D9
+ HINSTANCE hD3D9DLL = LoadLibrary("D3D9.DLL");
+ if (hD3D9DLL != nil) {
+ FreeLibrary(hDDrawDLL);
+ FreeLibrary(hD3D9DLL);
+
+ dwDXVersion = 0x900;
+ return dwDXVersion;
+ }
+#endif
+
+ //-------------------------------------------------------------------------
+ // DirectX 8.0 Checks
+ //-------------------------------------------------------------------------
+
+ // Simply see if D3D8.dll exists.
+ hD3D8DLL = LoadLibrary( "D3D8.DLL" );
+ if( hD3D8DLL == nil )
+ {
+ FreeLibrary( hDDrawDLL );
+ OutputDebugString( "Couldn't LoadLibrary D3D8.DLL\r\n" );
+ return dwDXVersion;
+ }
+
+ // D3D8.dll exists. We must be at least DX8.0
+ dwDXVersion = 0x800;
+
+
+ //-------------------------------------------------------------------------
+ // DirectX 8.1 Checks
+ //-------------------------------------------------------------------------
+
+ // Simply see if dpnhpast.dll exists.
+ hDPNHPASTDLL = LoadLibrary( "dpnhpast.dll" );
+ if( hDPNHPASTDLL == nil )
+ {
+ FreeLibrary( hDPNHPASTDLL );
+ OutputDebugString( "Couldn't LoadLibrary dpnhpast.dll\r\n" );
+ return dwDXVersion;
+ }
+
+ // dpnhpast.dll exists. We must be at least DX8.1
+ dwDXVersion = 0x801;
+
+
+ //-------------------------------------------------------------------------
+ // End of checking for versions of DirectX
+ //-------------------------------------------------------------------------
+
+ // Close open libraries and return
+ FreeLibrary( hDDrawDLL );
+ FreeLibrary( hD3D8DLL );
+
+ return dwDXVersion;
+}
+
+/*
+ *****************************************************************************
+ */
+#ifndef _WIN64
+static char cpuvendor[16] = "UnknownVendr";
+__declspec(naked) const char * _psGetCpuVendr()
+{
+ __asm
+ {
+ push ebx
+ xor eax, eax
+ cpuid
+ mov dword ptr [cpuvendor+0], ebx
+ mov dword ptr [cpuvendor+4], edx
+ mov dword ptr [cpuvendor+8], ecx
+ mov eax, offset cpuvendor
+ pop ebx
+ retn
+ }
+}
+
+/*
+ *****************************************************************************
+ */
+__declspec(naked) RwUInt32 _psGetCpuFeatures()
+{
+ __asm
+ {
+ mov eax, 1
+ cpuid
+ mov eax, edx
+ retn
+ }
+}
+
+/*
+ *****************************************************************************
+ */
+__declspec(naked) RwUInt32 _psGetCpuFeaturesEx()
+{
+ __asm
+ {
+ mov eax, 80000000h
+ cpuid
+
+ cmp eax, 80000000h
+ jbe short _NOEX
+
+ mov eax, 80000001h
+ cpuid
+
+ mov eax, edx
+ jmp short _RETEX
+
+_NOEX:
+ xor eax, eax
+ mov eax, eax
+
+_RETEX:
+ retn
+ }
+}
+
+#ifdef __MWERKS__
+#pragma dont_inline on
+#endif
+void _psPrintCpuInfo()
+{
+ RwUInt32 features = _psGetCpuFeatures();
+ RwUInt32 FeaturesEx = _psGetCpuFeaturesEx();
+
+ debug("Running on a %s", _psGetCpuVendr());
+
+ if ( features & 0x800000 )
+ debug("with MMX");
+ if ( features & 0x2000000 )
+ debug("with SSE");
+ if ( FeaturesEx & 0x80000000 )
+ debug("with 3DNow");
+}
+#ifdef __MWERKS__
+#pragma dont_inline off
+#endif
+#endif
+
+/*
+ *****************************************************************************
+ */
+#ifdef UNDER_CE
+#define CMDSTR LPWSTR
+#else
+#define CMDSTR LPSTR
+#endif
+
+/*
+ *****************************************************************************
+ */
+RwBool
+psInitialize(void)
+{
+ PsGlobal.lastMousePos.x = PsGlobal.lastMousePos.y = 0.0f;
+
+ RsGlobal.ps = &PsGlobal;
+
+ PsGlobal.fullScreen = FALSE;
+
+ PsGlobal.dinterface = nil;
+ PsGlobal.mouse = nil;
+ PsGlobal.joy1 = nil;
+ PsGlobal.joy2 = nil;
+
+ CFileMgr::Initialise();
+
+#ifdef PS2_MENU
+ CPad::Initialise();
+ CPad::GetPad(0)->Mode = 0;
+
+ CGame::frenchGame = false;
+ CGame::germanGame = false;
+ CGame::nastyGame = true;
+ CMenuManager::m_PrefsAllowNastyGame = true;
+
+ WORD lang = PRIMARYLANGID(GetSystemDefaultLCID());
+ if ( lang == LANG_ITALIAN )
+ CMenuManager::m_PrefsLanguage = CMenuManager::LANGUAGE_ITALIAN;
+ else if ( lang == LANG_SPANISH )
+ CMenuManager::m_PrefsLanguage = CMenuManager::LANGUAGE_SPANISH;
+ else if ( lang == LANG_GERMAN )
+ {
+ CGame::germanGame = true;
+ CGame::nastyGame = false;
+ CMenuManager::m_PrefsAllowNastyGame = false;
+ CMenuManager::m_PrefsLanguage = CMenuManager::LANGUAGE_GERMAN;
+ }
+ else if ( lang == LANG_FRENCH )
+ {
+ CGame::frenchGame = true;
+ CGame::nastyGame = false;
+ CMenuManager::m_PrefsAllowNastyGame = false;
+ CMenuManager::m_PrefsLanguage = CMenuManager::LANGUAGE_FRENCH;
+ }
+ else
+ CMenuManager::m_PrefsLanguage = CMenuManager::LANGUAGE_AMERICAN;
+
+ FrontEndMenuManager.InitialiseMenuContentsAfterLoadingGame();
+
+ TheMemoryCard.Init();
+#else
+ C_PcSave::SetSaveDirectory(_psGetUserFilesFolder());
+
+ InitialiseLanguage();
+#endif
+
+ gGameState = GS_START_UP;
+ TRACE("gGameState = GS_START_UP");
+#ifndef _WIN64
+ _psPrintCpuInfo();
+#endif
+ OSVERSIONINFO verInfo;
+ verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+ GetVersionEx(&verInfo);
+
+ _dwOperatingSystemVersion = OS_WIN95;
+
+ if ( verInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+ {
+ if ( verInfo.dwMajorVersion == 4 )
+ {
+ debug("Operating System is WinNT\n");
+ _dwOperatingSystemVersion = OS_WINNT;
+ }
+ else if ( verInfo.dwMajorVersion == 5 )
+ {
+ debug("Operating System is Win2000\n");
+ _dwOperatingSystemVersion = OS_WIN2000;
+ }
+ else if ( verInfo.dwMajorVersion > 5 )
+ {
+ debug("Operating System is WinXP or greater\n");
+ _dwOperatingSystemVersion = OS_WINXP;
+ }
+ }
+ else if ( verInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
+ {
+ if ( verInfo.dwMajorVersion > 4 || verInfo.dwMajorVersion == 4 && verInfo.dwMinorVersion != 0 )
+ {
+ debug("Operating System is Win98\n");
+ _dwOperatingSystemVersion = OS_WIN98;
+ }
+ else
+ {
+ debug("Operating System is Win95\n");
+ _dwOperatingSystemVersion = OS_WIN95;
+ }
+ }
+
+#ifndef PS2_MENU
+ FrontEndMenuManager.LoadSettings();
+#endif
+
+ dwDXVersion = GetDXVersion();
+ debug("DirectX version 0x%x\n", dwDXVersion);
+
+ if ( _dwOperatingSystemVersion == OS_WIN95 )
+ {
+ MessageBoxW(nil,
+ (LPCWSTR)TheText.Get("WIN_95"), // Grand Theft Auto III cannot run on Windows 95
+ (LPCWSTR)TheText.Get("WIN_TTL"), // Grand Theft Auto III
+ MB_OK);
+
+ return FALSE;
+ }
+
+ if ( dwDXVersion < 0x801 )
+ {
+ MessageBoxW(nil,
+ (LPCWSTR)TheText.Get("WIN_DX"), // Grand Theft Auto III requires at least DirectX version 8.1
+ (LPCWSTR)TheText.Get("WIN_TTL"), // Grand Theft Auto III
+ MB_OK);
+
+ return FALSE;
+ }
+
+ MEMORYSTATUS memstats;
+ GlobalMemoryStatus(&memstats);
+
+ _dwMemTotalPhys = memstats.dwTotalPhys;
+ _dwMemAvailPhys = memstats.dwAvailPhys;
+ _dwMemTotalVirtual = memstats.dwTotalVirtual;
+ _dwMemAvailVirtual = memstats.dwAvailVirtual;
+
+ _GetVideoMemInfo(&_dwMemTotalVideo, &_dwMemAvailVideo);
+#ifdef FIX_BUGS
+ debug("Physical memory size %lu\n", _dwMemTotalPhys);
+ debug("Available physical memory %lu\n", _dwMemAvailPhys);
+ debug("Video memory size %lu\n", _dwMemTotalVideo);
+ debug("Available video memory %lu\n", _dwMemAvailVideo);
+#else
+ debug("Physical memory size %d\n", _dwMemTotalPhys);
+ debug("Available physical memory %d\n", _dwMemAvailPhys);
+ debug("Video memory size %d\n", _dwMemTotalVideo);
+ debug("Available video memory %d\n", _dwMemAvailVideo);
+#endif
+
+ if ( _dwMemAvailVideo < (12 * 1024 * 1024) /*12 MB*/ )
+ {
+ MessageBoxW(nil,
+ (LPCWSTR)TheText.Get("WIN_VDM"), // Grand Theft Auto III requires at least 12MB of available video memory
+ (LPCWSTR)TheText.Get("WIN_TTL"), // Grand Theft Auto III
+ MB_OK);
+
+ return FALSE;
+ }
+
+ TheText.Unload();
+
+ return TRUE;
+}
+
+
+/*
+ *****************************************************************************
+ */
+void
+psTerminate(void)
+{
+ return;
+}
+
+/*
+ *****************************************************************************
+ */
+static RwChar **_VMList;
+
+RwInt32 _psGetNumVideModes()
+{
+ return RwEngineGetNumVideoModes();
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool _psFreeVideoModeList()
+{
+ RwInt32 numModes;
+ RwInt32 i;
+
+ numModes = _psGetNumVideModes();
+
+ if ( _VMList == nil )
+ return TRUE;
+
+ for ( i = 0; i < numModes; i++ )
+ {
+ RwFree(_VMList[i]);
+ }
+
+ RwFree(_VMList);
+
+ _VMList = nil;
+
+ return TRUE;
+}
+
+/*
+ *****************************************************************************
+ */
+RwChar **_psGetVideoModeList()
+{
+ RwInt32 numModes;
+ RwInt32 i;
+
+ if ( _VMList != nil )
+ {
+ return _VMList;
+ }
+
+ numModes = RwEngineGetNumVideoModes();
+
+ _VMList = (RwChar **)RwCalloc(numModes, sizeof(RwChar*));
+
+ for ( i = 0; i < numModes; i++ )
+ {
+ RwVideoMode vm;
+
+ RwEngineGetVideoModeInfo(&vm, i);
+
+ if ( vm.flags & rwVIDEOMODEEXCLUSIVE )
+ {
+ if ( vm.width >= 640
+ && vm.height >= 480
+ && (vm.width == 640
+ && vm.height == 480)
+ || !(vm.flags & rwVIDEOMODEEXCLUSIVE)
+ || (_dwMemTotalVideo - vm.depth * vm.height * vm.width / 8) > (12 * 1024 * 1024)/*12 MB*/ )
+ {
+ _VMList[i] = (RwChar*)RwCalloc(100, sizeof(RwChar));
+ rwsprintf(_VMList[i],"%lu X %lu X %lu", vm.width, vm.height, vm.depth);
+ }
+ else
+ _VMList[i] = nil;
+ }
+ else
+ _VMList[i] = nil;
+ }
+
+ return _VMList;
+}
+
+/*
+ *****************************************************************************
+ */
+void _psSelectScreenVM(RwInt32 videoMode)
+{
+ RwTexDictionarySetCurrent( nil );
+
+ FrontEndMenuManager.UnloadTextures();
+
+ if ( !_psSetVideoMode(RwEngineGetCurrentSubSystem(), videoMode) )
+ {
+ RsGlobal.quit = TRUE;
+
+ ShowWindow(PSGLOBAL(window), SW_HIDE);
+
+ MessageBoxW(nil,
+ (LPCWSTR)TheText.Get("WIN_RSZ"), // Failed to select new screen resolution
+ (LPCWSTR)TheText.Get("WIN_TTL"), // Grand Theft Auto III
+ MB_OK);
+ }
+ else
+ FrontEndMenuManager.LoadAllTextures();
+}
+
+/*
+ *****************************************************************************
+ */
+void WaitForState(FILTER_STATE State)
+{
+ HRESULT hr;
+
+ ASSERT(pMC != nil);
+
+ // Make sure we have switched to the required state
+ LONG lfs;
+ do
+ {
+ hr = pMC->GetState(10, &lfs);
+ } while (State != lfs);
+}
+
+/*
+ *****************************************************************************
+ */
+void HandleGraphEvent(void)
+{
+ LONG evCode, evParam1, evParam2;
+ HRESULT hr=S_OK;
+
+ ASSERT(pME != nil);
+
+ // Process all queued events
+ while (SUCCEEDED(pME->GetEvent(&evCode, (LONG_PTR *)&evParam1,
+ (LONG_PTR *)&evParam2, 0)))
+ {
+ // Free memory associated with callback, since we're not using it
+ hr = pME->FreeEventParams(evCode, evParam1, evParam2);
+
+ // If this is the end of the clip, reset to beginning
+ if (EC_COMPLETE == evCode)
+ {
+ switch (gGameState)
+ {
+ case GS_LOGO_MPEG:
+ {
+ gGameState = GS_INIT_INTRO_MPEG;
+ TRACE("gGameState = GS_INIT_INTRO_MPEG");
+ break;
+ }
+ case GS_INTRO_MPEG:
+ {
+ gGameState = GS_INIT_ONCE;
+ TRACE("gGameState = GS_INIT_ONCE");
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ pME->SetNotifyWindow((OAHWND)NULL, 0, 0);
+ }
+ }
+}
+
+/*
+ *****************************************************************************
+ */
+LRESULT CALLBACK
+MainWndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ POINTS points;
+ static BOOL noMemory = FALSE;
+
+
+ switch( message )
+ {
+ case WM_SETCURSOR:
+ {
+ ShowCursor(FALSE);
+
+ SetCursor(nil);
+
+ break; // is this correct ?
+ }
+
+ case WM_SIZE:
+ {
+ RwRect r;
+
+ r.x = 0;
+ r.y = 0;
+ r.w = LOWORD(lParam);
+ r.h = HIWORD(lParam);
+
+ if (RwInitialised && r.h > 0 && r.w > 0)
+ {
+ RsEventHandler(rsCAMERASIZE, &r);
+
+ if (r.w != LOWORD(lParam) && r.h != HIWORD(lParam))
+ {
+ WINDOWPLACEMENT wp;
+
+ /* failed to create window of required size */
+ noMemory = TRUE;
+
+ /* stop re-sizing */
+ ReleaseCapture();
+
+ /* handle maximised window */
+ GetWindowPlacement(window, &wp);
+ if (wp.showCmd == SW_SHOWMAXIMIZED)
+ {
+ SendMessage(window, WM_WINDOWPOSCHANGED, 0, 0);
+ }
+ }
+ else
+ {
+ noMemory = FALSE;
+ }
+
+ }
+
+ return 0L;
+ }
+
+ case WM_SIZING:
+ {
+ /*
+ * Handle event to ensure window contents are displayed during re-size
+ * as this can be disabled by the user, then if there is not enough
+ * memory things don't work.
+ */
+ RECT *newPos = (LPRECT) lParam;
+ RECT rect;
+
+ /* redraw window */
+
+ if (RwInitialised && gGameState == GS_PLAYING_GAME)
+ {
+ RsEventHandler(rsIDLE, (void *)TRUE);
+ }
+
+ /* Manually resize window */
+ rect.left = rect.top = 0;
+ rect.bottom = newPos->bottom - newPos->top;
+ rect.right = newPos->right - newPos->left;
+
+ SetWindowPos(window, HWND_TOP, rect.left, rect.top,
+ (rect.right - rect.left),
+ (rect.bottom - rect.top), SWP_NOMOVE);
+
+ return 0L;
+ }
+
+ case WM_LBUTTONDOWN:
+ {
+ SetCapture(window);
+
+ return 0L;
+ }
+
+ case WM_RBUTTONDOWN:
+ {
+ SetCapture(window);
+
+ return 0L;
+ }
+
+ case WM_MBUTTONDOWN:
+ {
+ SetCapture(window);
+
+ return 0L;
+ }
+
+ case WM_MOUSEWHEEL:
+ {
+ return 0L;
+ }
+
+ case WM_MOUSEMOVE:
+ {
+ points = MAKEPOINTS(lParam);
+
+ FrontEndMenuManager.m_nMouseTempPosX = points.x;
+ FrontEndMenuManager.m_nMouseTempPosY = points.y;
+
+ return 0L;
+ }
+
+ case WM_LBUTTONUP:
+ {
+ ReleaseCapture();
+
+ return 0L;
+ }
+
+ case WM_RBUTTONUP:
+ {
+ ReleaseCapture();
+
+ return 0L;
+ }
+
+ case WM_MBUTTONUP:
+ {
+ ReleaseCapture();
+
+ return 0L;
+ }
+
+ case WM_KEYDOWN:
+ {
+ RsKeyCodes ks;
+
+ if ( _InputTranslateKey(&ks, lParam, wParam) )
+ RsKeyboardEventHandler(rsKEYDOWN, &ks);
+
+ if ( wParam == VK_SHIFT )
+ _InputTranslateShiftKeyUpDown(&ks);
+#ifdef FIX_BUGS
+ break;
+#else
+ return 0L;
+#endif
+ }
+
+ case WM_KEYUP:
+ {
+ RsKeyCodes ks;
+
+ if ( _InputTranslateKey(&ks, lParam, wParam) )
+ RsKeyboardEventHandler(rsKEYUP, &ks);
+
+ if ( wParam == VK_SHIFT )
+ _InputTranslateShiftKeyUpDown(&ks);
+
+#ifdef FIX_BUGS
+ break;
+#else
+ return 0L;
+#endif
+ }
+
+ case WM_SYSKEYDOWN:
+ {
+ RsKeyCodes ks;
+
+ if ( _InputTranslateKey(&ks, lParam, wParam) )
+ RsKeyboardEventHandler(rsKEYDOWN, &ks);
+
+ if ( wParam == VK_SHIFT )
+ _InputTranslateShiftKeyUpDown(&ks);
+
+#ifdef FIX_BUGS
+ break;
+#else
+ return 0L;
+#endif
+ }
+
+ case WM_SYSKEYUP:
+ {
+ RsKeyCodes ks;
+
+ if ( _InputTranslateKey(&ks, lParam, wParam) )
+ RsKeyboardEventHandler(rsKEYUP, &ks);
+
+ if ( wParam == VK_SHIFT )
+ _InputTranslateShiftKeyUpDown(&ks);
+
+#ifdef FIX_BUGS
+ break;
+#else
+ return 0L;
+#endif
+ }
+
+ case WM_ACTIVATEAPP:
+ {
+ switch ( gGameState )
+ {
+ case GS_LOGO_MPEG:
+ case GS_INTRO_MPEG:
+ {
+ ASSERT(pMC != nil);
+
+ LONG state;
+ pMC->GetState(10, &state);
+
+ if ( !(BOOL)wParam ) // losing activation
+ {
+ if ( state == State_Running && pMC != nil )
+ {
+ HRESULT hr = pMC->Pause();
+
+ if (hr == S_FALSE)
+ OutputDebugString("Failed to pause the MPEG");
+ else
+ WaitForState(State_Paused);
+ }
+ }
+ else
+ {
+ CenterVideo();
+
+ if ( state != State_Running && pMC != nil )
+ {
+ HRESULT hr = pMC->Run();
+
+ if ( hr == S_FALSE )
+ OutputDebugString("Failed to run the MPEG");
+ else
+ {
+ WaitForState(State_Running);
+ SetFocus(PSGLOBAL(window));
+ }
+ }
+ }
+
+ break;
+ }
+
+ case GS_START_UP:
+ {
+ if ( !(BOOL)wParam && PSGLOBAL(fullScreen) ) // losing activation
+ startupDeactivate = TRUE;
+
+ break;
+ }
+ }
+
+ CPad::GetPad(0)->Clear(false);
+ CPad::GetPad(1)->Clear(false);
+
+ return 0L;
+ }
+
+ case WM_TIMER:
+ {
+ return 0L;
+ }
+
+ case WM_GRAPHNOTIFY:
+ {
+ if (gGameState == GS_INTRO_MPEG || gGameState == GS_LOGO_MPEG)
+ HandleGraphEvent();
+
+ break;
+ }
+
+ case WM_CLOSE:
+ case WM_DESTROY:
+ {
+ /*
+ * Quit message handling.
+ */
+ ClipCursor(nil);
+
+ _InputShutdown();
+
+ PostQuitMessage(0);
+
+ return 0L;
+ }
+
+ case WM_DEVICECHANGE:
+ {
+ if( wParam == DBT_DEVICEREMOVECOMPLETE )
+ {
+ PDEV_BROADCAST_HDR pDev = (PDEV_BROADCAST_HDR)lParam;
+
+ if (pDev->dbch_devicetype != DBT_DEVTYP_VOLUME)
+ break;
+
+ if ( DMAudio.IsAudioInitialised() )
+ {
+ PDEV_BROADCAST_VOLUME pVol = (PDEV_BROADCAST_VOLUME)pDev;
+ if ( pVol->dbcv_flags & DBTF_MEDIA )
+ {
+ char c = DMAudio.GetCDAudioDriveLetter();
+
+ if ( c >= 'A' && pVol->dbcv_unitmask & (1 << (c - 'A')) )
+ {
+ OutputDebugString("About to check CD drive...");
+
+ while ( true )
+ {
+ FrontEndMenuManager.WaitForUserCD();
+
+ if ( !FrontEndMenuManager.m_bQuitGameNoCD )
+ {
+ if ( DMAudio.CheckForAnAudioFileOnCD() )
+ {
+ OutputDebugString("GTA3 Audio CD has been inserted");
+ break;
+ }
+ }
+ else
+ {
+ OutputDebugString("Exiting game as Audio CD was not inserted");
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ break;
+ }
+
+#ifdef FIX_BUGS // game turns on menu when focus is re-gained rather than lost
+ case WM_KILLFOCUS:
+#else
+ case WM_SETFOCUS:
+#endif
+ {
+ CGame::InitAfterFocusLoss();
+ break;
+ }
+
+ }
+
+ /*
+ * Let Windows handle all other messages.
+ */
+ return DefWindowProc(window, message, wParam, lParam);
+}
+
+/*
+ *****************************************************************************
+ */
+static BOOL
+InitApplication(HANDLE instance)
+{
+ /*
+ * Perform any necessary MS Windows application initialization. Basically,
+ * this means registering the window class for this application.
+ */
+
+ WNDCLASS windowClass;
+
+ windowClass.style = CS_BYTEALIGNWINDOW;
+ windowClass.lpfnWndProc = (WNDPROC)MainWndProc;
+ windowClass.cbClsExtra = 0;
+ windowClass.cbWndExtra = 0;
+ windowClass.hInstance = (HINSTANCE)instance;
+ windowClass.hIcon = LoadIcon((HINSTANCE)instance, (LPCSTR)IDI_MAIN_ICON);
+ windowClass.hCursor = LoadCursor(nil, IDC_ARROW);
+ windowClass.hbrBackground = nil;
+ windowClass.lpszMenuName = NULL;
+ windowClass.lpszClassName = AppClassName;
+
+ return RegisterClass(&windowClass);
+}
+
+
+/*
+ *****************************************************************************
+ */
+
+RwBool IsForegroundApp()
+{
+ return !!ForegroundApp;
+}
+
+UINT GetBestRefreshRate(UINT width, UINT height, UINT depth)
+{
+#ifdef USE_D3D9
+ LPDIRECT3D9 d3d = Direct3DCreate9(D3D_SDK_VERSION);
+#else
+ LPDIRECT3D8 d3d = Direct3DCreate8(D3D_SDK_VERSION);
+#endif
+ ASSERT(d3d != nil);
+
+ UINT refreshRate = INT_MAX;
+ D3DFORMAT format;
+
+ if ( depth == 32 )
+ format = D3DFMT_X8R8G8B8;
+ else if ( depth == 24 )
+ format = D3DFMT_R8G8B8;
+ else
+ format = D3DFMT_R5G6B5;
+
+#ifdef USE_D3D9
+ UINT modeCount = d3d->GetAdapterModeCount(GcurSel, format);
+#else
+ UINT modeCount = d3d->GetAdapterModeCount(GcurSel);
+#endif
+
+ for ( UINT i = 0; i < modeCount; i++ )
+ {
+ D3DDISPLAYMODE mode;
+
+#ifdef USE_D3D9
+ d3d->EnumAdapterModes(GcurSel, format, i, &mode);
+#else
+ d3d->EnumAdapterModes(GcurSel, i, &mode);
+#endif
+ if ( mode.Width == width && mode.Height == height && mode.Format == format )
+ {
+ if ( mode.RefreshRate == 0 ) {
+ d3d->Release();
+ return 0;
+ }
+
+ if ( mode.RefreshRate < refreshRate && mode.RefreshRate >= 60 )
+ refreshRate = mode.RefreshRate;
+ }
+ }
+
+ d3d->Release();
+
+ if ( refreshRate == -1 )
+ return -1;
+
+ return refreshRate;
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool
+psSelectDevice()
+{
+ RwVideoMode vm;
+ RwInt32 subSysNum;
+ RwInt32 AutoRenderer = 0;
+
+
+ RwBool modeFound = FALSE;
+
+ if ( !useDefault )
+ {
+ GnumSubSystems = RwEngineGetNumSubSystems();
+ if ( !GnumSubSystems )
+ {
+ return FALSE;
+ }
+
+ /* Just to be sure ... */
+ GnumSubSystems = (GnumSubSystems > MAX_SUBSYSTEMS) ? MAX_SUBSYSTEMS : GnumSubSystems;
+
+ /* Get the names of all the sub systems */
+ for (subSysNum = 0; subSysNum < GnumSubSystems; subSysNum++)
+ {
+ RwEngineGetSubSystemInfo(&GsubSysInfo[subSysNum], subSysNum);
+ }
+
+ /* Get the default selection */
+ GcurSel = RwEngineGetCurrentSubSystem();
+#ifdef IMPROVED_VIDEOMODE
+ if(FrontEndMenuManager.m_nPrefsSubsystem < GnumSubSystems)
+ GcurSel = FrontEndMenuManager.m_nPrefsSubsystem;
+#endif
+ }
+
+ /* Set the driver to use the correct sub system */
+ if (!RwEngineSetSubSystem(GcurSel))
+ {
+ return FALSE;
+ }
+
+#ifdef IMPROVED_VIDEOMODE
+ FrontEndMenuManager.m_nPrefsSubsystem = GcurSel;
+#endif
+
+#ifndef IMPROVED_VIDEOMODE
+ if ( !useDefault )
+ {
+ if ( _psGetVideoModeList()[FrontEndMenuManager.m_nDisplayVideoMode] && FrontEndMenuManager.m_nDisplayVideoMode )
+ {
+ FrontEndMenuManager.m_nPrefsVideoMode = FrontEndMenuManager.m_nDisplayVideoMode;
+ GcurSelVM = FrontEndMenuManager.m_nDisplayVideoMode;
+ }
+ else
+ {
+#ifdef DEFAULT_NATIVE_RESOLUTION
+ // get the native video mode
+ HDC hDevice = GetDC(NULL);
+ int w = GetDeviceCaps(hDevice, HORZRES);
+ int h = GetDeviceCaps(hDevice, VERTRES);
+ int d = GetDeviceCaps(hDevice, BITSPIXEL);
+#else
+ const int w = 640;
+ const int h = 480;
+ const int d = 16;
+#endif
+ while ( !modeFound && GcurSelVM < RwEngineGetNumVideoModes() )
+ {
+ RwEngineGetVideoModeInfo(&vm, GcurSelVM);
+ if ( defaultFullscreenRes && vm.width != w
+ || vm.height != h
+ || vm.depth != d
+ || !(vm.flags & rwVIDEOMODEEXCLUSIVE) )
+ ++GcurSelVM;
+ else
+ modeFound = TRUE;
+ }
+
+ if ( !modeFound )
+ {
+#ifdef DEFAULT_NATIVE_RESOLUTION
+ GcurSelVM = 1;
+#else
+ MessageBox(nil, "Cannot find 640x480 video mode", "GTA3", MB_OK);
+ return FALSE;
+#endif
+ }
+ }
+ }
+#else
+ if ( !useDefault )
+ {
+ if(FrontEndMenuManager.m_nPrefsWidth == 0 ||
+ FrontEndMenuManager.m_nPrefsHeight == 0 ||
+ FrontEndMenuManager.m_nPrefsDepth == 0){
+ // Defaults if nothing specified
+ FrontEndMenuManager.m_nPrefsWidth = GetSystemMetrics(SM_CXSCREEN);
+ FrontEndMenuManager.m_nPrefsHeight = GetSystemMetrics(SM_CYSCREEN);
+ FrontEndMenuManager.m_nPrefsDepth = 32;
+ FrontEndMenuManager.m_nPrefsWindowed = 0;
+ }
+
+ // Find the videomode that best fits what we got from the settings file
+ RwInt32 bestFsMode = -1;
+ RwInt32 bestWidth = -1;
+ RwInt32 bestHeight = -1;
+ RwInt32 bestDepth = -1;
+ for (GcurSelVM = 0; GcurSelVM < RwEngineGetNumVideoModes(); GcurSelVM++) {
+ RwEngineGetVideoModeInfo(&vm, GcurSelVM);
+
+ if (!(vm.flags & rwVIDEOMODEEXCLUSIVE)) {
+ bestWndMode = GcurSelVM;
+ } else {
+ // try the largest one that isn't larger than what we wanted
+ if (vm.width >= bestWidth && vm.width <= FrontEndMenuManager.m_nPrefsWidth &&
+ vm.height >= bestHeight && vm.height <= FrontEndMenuManager.m_nPrefsHeight &&
+ vm.depth >= bestDepth && vm.depth <= FrontEndMenuManager.m_nPrefsDepth){
+ bestWidth = vm.width;
+ bestHeight = vm.height;
+ bestDepth = vm.depth;
+ bestFsMode = GcurSelVM;
+ }
+ }
+ }
+
+ if(bestFsMode < 0){
+ MessageBox(nil, "Cannot find desired video mode", "GTA3", MB_OK);
+ return FALSE;
+ }
+ GcurSelVM = bestFsMode;
+
+ FrontEndMenuManager.m_nDisplayVideoMode = GcurSelVM;
+ FrontEndMenuManager.m_nPrefsVideoMode = FrontEndMenuManager.m_nDisplayVideoMode;
+
+ FrontEndMenuManager.m_nSelectedScreenMode = FrontEndMenuManager.m_nPrefsWindowed;
+ }
+#endif
+
+ RwEngineGetVideoModeInfo(&vm, GcurSelVM);
+
+#ifdef IMPROVED_VIDEOMODE
+ if (FrontEndMenuManager.m_nPrefsWindowed)
+ GcurSelVM = bestWndMode;
+
+ // Now GcurSelVM is 0 but vm has sizes(and fullscreen flag) of the video mode we want, that's why we changed the rwVIDEOMODEEXCLUSIVE conditions below
+ FrontEndMenuManager.m_nPrefsWidth = vm.width;
+ FrontEndMenuManager.m_nPrefsHeight = vm.height;
+ FrontEndMenuManager.m_nPrefsDepth = vm.depth;
+#endif
+
+#ifndef PS2_MENU
+ FrontEndMenuManager.m_nCurrOption = 0;
+#endif
+
+ /* Set up the video mode and set the apps window
+ * dimensions to match */
+ if (!RwEngineSetVideoMode(GcurSelVM))
+ {
+ return FALSE;
+ }
+
+#ifdef IMPROVED_VIDEOMODE
+ if (!FrontEndMenuManager.m_nPrefsWindowed)
+#else
+ if (vm.flags & rwVIDEOMODEEXCLUSIVE)
+#endif
+ {
+ debug("%dx%dx%d", vm.width, vm.height, vm.depth);
+
+ UINT refresh = GetBestRefreshRate(vm.width, vm.height, vm.depth);
+
+ if ( refresh != (UINT)-1 )
+ {
+ debug("refresh %d", refresh);
+ RwD3D8EngineSetRefreshRate((RwUInt32)refresh);
+ }
+ }
+
+#ifdef IMPROVED_VIDEOMODE
+ if (!FrontEndMenuManager.m_nPrefsWindowed)
+#else
+ if (vm.flags & rwVIDEOMODEEXCLUSIVE)
+#endif
+ {
+ RsGlobal.maximumWidth = vm.width;
+ RsGlobal.maximumHeight = vm.height;
+ RsGlobal.width = vm.width;
+ RsGlobal.height = vm.height;
+
+ PSGLOBAL(fullScreen) = TRUE;
+
+#ifdef IMPROVED_VIDEOMODE
+ SetWindowLong(PSGLOBAL(window), GWL_STYLE, WS_POPUP);
+ SetWindowPos(PSGLOBAL(window), nil, 0, 0, 0, 0,
+ SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|
+ SWP_FRAMECHANGED);
+ }else{
+ RECT rect;
+ rect.left = rect.top = 0;
+ rect.right = FrontEndMenuManager.m_nPrefsWidth;
+ rect.bottom = FrontEndMenuManager.m_nPrefsHeight;
+ AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
+
+ // center it
+ int spaceX = GetSystemMetrics(SM_CXSCREEN) - (rect.right-rect.left);
+ int spaceY = GetSystemMetrics(SM_CYSCREEN) - (rect.bottom-rect.top);
+
+ SetWindowLong(PSGLOBAL(window), GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW);
+ SetWindowPos(PSGLOBAL(window), HWND_NOTOPMOST, spaceX/2, spaceY/2,
+ (rect.right - rect.left),
+ (rect.bottom - rect.top), 0);
+
+ // Have to get actual size because the window perhaps didn't fit
+ GetClientRect(PSGLOBAL(window), &rect);
+ RsGlobal.maximumWidth = rect.right;
+ RsGlobal.maximumHeight = rect.bottom;
+ RsGlobal.width = rect.right;
+ RsGlobal.height = rect.bottom;
+
+ PSGLOBAL(fullScreen) = FALSE;
+#endif
+ }
+#ifdef MULTISAMPLING
+ RwD3D8EngineSetMultiSamplingLevels(1 << FrontEndMenuManager.m_nPrefsMSAALevel);
+#endif
+ return TRUE;
+}
+
+/*
+ *****************************************************************************
+ */
+RwBool _psSetVideoMode(RwInt32 subSystem, RwInt32 videoMode)
+{
+ RwInitialised = FALSE;
+
+ RsEventHandler(rsRWTERMINATE, nil);
+
+ GcurSel = subSystem;
+ GcurSelVM = videoMode;
+
+ useDefault = TRUE;
+
+ if ( RsEventHandler(rsRWINITIALIZE, PSGLOBAL(window)) == rsEVENTERROR )
+ return FALSE;
+
+ RwInitialised = TRUE;
+ useDefault = FALSE;
+
+ RwRect r;
+
+ r.x = 0;
+ r.y = 0;
+ r.w = RsGlobal.maximumWidth;
+ r.h = RsGlobal.maximumHeight;
+
+ RsEventHandler(rsCAMERASIZE, &r);
+
+ return TRUE;
+}
+
+/*
+ *****************************************************************************
+ */
+static RwChar **
+CommandLineToArgv(RwChar *cmdLine, RwInt32 *argCount)
+{
+ RwInt32 numArgs = 0;
+ RwBool inArg, inString;
+ RwInt32 i, len;
+ RwChar *res, *str, **aptr;
+
+ len = (int)strlen(cmdLine);
+
+ /*
+ * Count the number of arguments...
+ */
+ inString = FALSE;
+ inArg = FALSE;
+
+ for(i=0; i<=len; i++)
+ {
+ if( cmdLine[i] == '"' )
+ {
+ inString = !inString;
+ }
+
+ if( (cmdLine[i] <= ' ' && !inString) || i == len )
+ {
+ if( inArg )
+ {
+ inArg = FALSE;
+
+ numArgs++;
+ }
+ }
+ else if( !inArg )
+ {
+ inArg = TRUE;
+ }
+ }
+
+ /*
+ * Allocate memory for result...
+ */
+ res = (RwChar *)malloc(sizeof(RwChar *) * numArgs + len + 1);
+ str = res + sizeof(RwChar *) * numArgs;
+ aptr = (RwChar **)res;
+
+ strcpy(str, cmdLine);
+
+ /*
+ * Walk through cmdLine again this time setting pointer to each arg...
+ */
+ inArg = FALSE;
+ inString = FALSE;
+
+ for(i=0; i<=len; i++)
+ {
+ if( cmdLine[i] == '"' )
+ {
+ inString = !inString;
+ }
+
+ if( (cmdLine[i] <= ' ' && !inString) || i == len )
+ {
+ if( inArg )
+ {
+ if( str[i-1] == '"' )
+ {
+ str[i-1] = '\0';
+ }
+ else
+ {
+ str[i] = '\0';
+ }
+
+ inArg = FALSE;
+ }
+ }
+ else if( !inArg && cmdLine[i] != '"' )
+ {
+ inArg = TRUE;
+
+ *aptr++ = &str[i];
+ }
+ }
+
+ *argCount = numArgs;
+
+ return (RwChar **)res;
+}
+
+/*
+ *****************************************************************************
+ */
+void InitialiseLanguage()
+{
+ WORD primUserLCID = PRIMARYLANGID(GetSystemDefaultLCID());
+ WORD primSystemLCID = PRIMARYLANGID(GetUserDefaultLCID());
+ WORD primLayout = PRIMARYLANGID((DWORD_PTR)GetKeyboardLayout(0));
+
+ WORD subUserLCID = SUBLANGID(GetSystemDefaultLCID());
+ WORD subSystemLCID = SUBLANGID(GetUserDefaultLCID());
+ WORD subLayout = SUBLANGID((DWORD_PTR)GetKeyboardLayout(0));
+
+ if ( primUserLCID == LANG_GERMAN
+ || primSystemLCID == LANG_GERMAN
+ || primLayout == LANG_GERMAN )
+ {
+ CGame::nastyGame = false;
+ FrontEndMenuManager.m_PrefsAllowNastyGame = false;
+ CGame::germanGame = true;
+ }
+
+ if ( primUserLCID == LANG_FRENCH
+ || primSystemLCID == LANG_FRENCH
+ || primLayout == LANG_FRENCH )
+ {
+ CGame::nastyGame = false;
+ FrontEndMenuManager.m_PrefsAllowNastyGame = false;
+ CGame::frenchGame = true;
+ }
+
+ if ( subUserLCID == SUBLANG_ENGLISH_AUS
+ || subSystemLCID == SUBLANG_ENGLISH_AUS
+ || subLayout == SUBLANG_ENGLISH_AUS )
+ CGame::noProstitutes = true;
+
+#ifdef NASTY_GAME
+ CGame::nastyGame = true;
+ FrontEndMenuManager.m_PrefsAllowNastyGame = true;
+ CGame::noProstitutes = false;
+#endif
+
+ int32 lang;
+
+ switch ( primSystemLCID )
+ {
+ case LANG_GERMAN:
+ {
+ lang = LANG_GERMAN;
+ break;
+ }
+ case LANG_FRENCH:
+ {
+ lang = LANG_FRENCH;
+ break;
+ }
+ case LANG_SPANISH:
+ {
+ lang = LANG_SPANISH;
+ break;
+ }
+ case LANG_ITALIAN:
+ {
+ lang = LANG_ITALIAN;
+ break;
+ }
+ default:
+ {
+ lang = ( subSystemLCID == SUBLANG_ENGLISH_AUS ) ? -99 : LANG_ENGLISH;
+ break;
+ }
+ }
+
+ FrontEndMenuManager.OS_Language = primUserLCID;
+
+ switch ( lang )
+ {
+ case LANG_GERMAN:
+ {
+ FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_GERMAN;
+ break;
+ }
+ case LANG_SPANISH:
+ {
+ FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_SPANISH;
+ break;
+ }
+ case LANG_FRENCH:
+ {
+ FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_FRENCH;
+ break;
+ }
+ case LANG_ITALIAN:
+ {
+ FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_ITALIAN;
+ break;
+ }
+ default:
+ {
+ FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_AMERICAN;
+ break;
+ }
+ }
+
+ TheText.Unload();
+ TheText.Load();
+}
+
+/*
+ *****************************************************************************
+ */
+void CenterVideo(void)
+{
+ HRESULT hr = S_OK;
+ RECT rect;
+
+ ASSERT(pVW != nil);
+
+ GetClientRect(PSGLOBAL(window), &rect);
+
+ JIF(pVW->SetWindowPosition(rect.left, rect.top, rect.right, rect.bottom));
+
+ JIF(pVW->put_MessageDrain((OAHWND) PSGLOBAL(window)));
+
+ SetFocus(PSGLOBAL(window));
+}
+
+/*
+ *****************************************************************************
+ */
+void PlayMovieInWindow(int cmdShow, const char* szFile)
+{
+ WCHAR wFileName[256];
+ HRESULT hr;
+
+ // Clear open dialog remnants before calling RenderFile()
+ UpdateWindow(PSGLOBAL(window));
+
+ // Convert filename to wide character string
+ MultiByteToWideChar(CP_ACP, 0, szFile, -1, wFileName, sizeof(wFileName) - 1);
+
+ // Initialize COM
+#ifdef FIX_BUGS // will also return S_FALSE if it has already been inited in the same thread
+ CoInitialize(nil);
+#else
+ JIF(CoInitialize(nil));
+#endif
+
+ // Get the interface for DirectShow's GraphBuilder
+ JIF(CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC,
+ IID_IGraphBuilder, (void **)&pGB));
+
+ if(SUCCEEDED(hr))
+ {
+ // Have the graph builder construct its the appropriate graph automatically
+ JIF(pGB->RenderFile(&wFileName[0], nil));
+
+ // QueryInterface for DirectShow interfaces
+ JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC));
+ JIF(pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME));
+ JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS));
+
+ // Query for video interfaces, which may not be relevant for audio files
+ JIF(pGB->QueryInterface(IID_IVideoWindow, (void **)&pVW));
+
+ JIF(pVW->put_Owner((OAHWND) PSGLOBAL(window)));
+ JIF(pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN));
+
+ // Have the graph signal event via window callbacks for performance
+ JIF(pME->SetNotifyWindow((OAHWND)PSGLOBAL(window), WM_GRAPHNOTIFY, 0));
+
+ CenterVideo();
+
+ // Run the graph to play the media file
+ JIF(pMC->Run());
+
+ SetFocus(PSGLOBAL(window));
+ }
+
+ ASSERT(pGB != nil);
+ ASSERT(pVW != nil);
+ ASSERT(pME != nil);
+ ASSERT(pMC != nil);
+
+ if(FAILED(hr))
+ CloseClip();
+}
+
+/*
+ *****************************************************************************
+ */
+void CloseInterfaces(void)
+{
+ // Release and zero DirectShow interfaces
+ SAFE_RELEASE(pME);
+ SAFE_RELEASE(pMS);
+ SAFE_RELEASE(pMC);
+ SAFE_RELEASE(pVW);
+ SAFE_RELEASE(pGB);
+}
+
+/*
+ *****************************************************************************
+ */
+void CloseClip(void)
+{
+ HRESULT hr;
+
+ // Stop playback
+ if(pMC)
+ hr = pMC->Stop();
+
+ // Free DirectShow interfaces
+ CloseInterfaces();
+}
+
+/*
+ *****************************************************************************
+ */
+void HandleExit()
+{
+ MSG message;
+ while ( PeekMessage(&message, nil, 0U, 0U, PM_REMOVE|PM_NOYIELD) )
+ {
+ if( message.message == WM_QUIT )
+ {
+ RsGlobal.quit = TRUE;
+ }
+ else
+ {
+ TranslateMessage(&message);
+ DispatchMessage(&message);
+ }
+ }
+}
+
+/*
+ *****************************************************************************
+ */
+int PASCAL
+WinMain(HINSTANCE instance,
+ HINSTANCE prevInstance __RWUNUSED__,
+ CMDSTR cmdLine,
+ int cmdShow)
+{
+ MSG message;
+ RwV2d pos;
+ RwInt32 argc, i;
+ RwChar **argv;
+ SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, SPIF_SENDCHANGE);
+
+#ifndef MASTER
+ if (strstr(cmdLine, "-console"))
+ {
+ AllocConsole();
+ freopen("CONIN$", "r", stdin);
+ freopen("CONOUT$", "w", stdout);
+ freopen("CONOUT$", "w", stderr);
+ }
+#endif
+
+#ifdef USE_CUSTOM_ALLOCATOR
+ InitMemoryMgr();
+#endif
+
+ /*
+ * Initialize the platform independent data.
+ * This will in turn initialize the platform specific data...
+ */
+ if( RsEventHandler(rsINITIALIZE, nil) == rsEVENTERROR )
+ {
+ return FALSE;
+ }
+
+ /*
+ * Register the window class...
+ */
+ if( !InitApplication(instance) )
+ {
+ return FALSE;
+ }
+
+ /*
+ * Get proper command line params, cmdLine passed to us does not
+ * work properly under all circumstances...
+ */
+ cmdLine = GetCommandLine();
+
+ /*
+ * Parse command line into standard (argv, argc) parameters...
+ */
+ argv = CommandLineToArgv(cmdLine, &argc);
+
+
+ /*
+ * Parse command line parameters (except program name) one at
+ * a time BEFORE RenderWare initialization...
+ */
+ for(i=1; i<argc; i++)
+ {
+ RsEventHandler(rsPREINITCOMMANDLINE, argv[i]);
+ }
+
+ /*
+ * Create the window...
+ */
+ PSGLOBAL(window) = InitInstance(instance);
+ if( PSGLOBAL(window) == nil )
+ {
+ return FALSE;
+ }
+
+ PSGLOBAL(instance) = instance;
+
+ ControlsManager.MakeControllerActionsBlank();
+ ControlsManager.InitDefaultControlConfiguration();
+
+ if ( _InputInitialise() == S_OK )
+ {
+ _InputInitialiseMouse(false);
+ _InputInitialiseJoys();
+ }
+
+ ControlsManager.InitDefaultControlConfigMouse(MousePointerStateHelper.GetMouseSetUp());
+
+#ifndef IMPROVED_VIDEOMODE
+ SetWindowLong(PSGLOBAL(window), GWL_STYLE, WS_POPUP);
+ SetWindowPos(PSGLOBAL(window), nil, 0, 0, 0, 0,
+ SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|
+ SWP_FRAMECHANGED);
+#endif
+
+ /*
+ * Initialize the 3D (RenderWare) components of the app...
+ */
+ if( rsEVENTERROR == RsEventHandler(rsRWINITIALIZE, PSGLOBAL(window)) )
+ {
+ DestroyWindow(PSGLOBAL(window));
+
+ RsEventHandler(rsTERMINATE, nil);
+
+ return FALSE;
+ }
+
+ /*
+ * Parse command line parameters (except program name) one at
+ * a time AFTER RenderWare initialization...
+ */
+ for(i=1; i<argc; i++)
+ {
+ RsEventHandler(rsCOMMANDLINE, argv[i]);
+ }
+
+ /*
+ * Force a camera resize event...
+ */
+ {
+ RwRect r;
+
+ r.x = 0;
+ r.y = 0;
+ r.w = RsGlobal.maximumWidth;
+ r.h = RsGlobal.maximumHeight;
+
+ RsEventHandler(rsCAMERASIZE, &r);
+ }
+
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, nil, SPIF_SENDCHANGE);
+ SystemParametersInfo(SPI_SETPOWEROFFACTIVE, FALSE, nil, SPIF_SENDCHANGE);
+ SystemParametersInfo(SPI_SETLOWPOWERACTIVE, FALSE, nil, SPIF_SENDCHANGE);
+
+
+ STICKYKEYS SavedStickyKeys;
+ SavedStickyKeys.cbSize = sizeof(STICKYKEYS);
+
+ SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &SavedStickyKeys, SPIF_SENDCHANGE);
+
+ STICKYKEYS NewStickyKeys;
+ NewStickyKeys.cbSize = sizeof(STICKYKEYS);
+ NewStickyKeys.dwFlags = SKF_TWOKEYSOFF;
+
+ SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &NewStickyKeys, SPIF_SENDCHANGE);
+
+
+ /*
+ * Show the window, and refresh it...
+ */
+ ShowWindow(PSGLOBAL(window), cmdShow);
+ UpdateWindow(PSGLOBAL(window));
+
+ {
+ CFileMgr::SetDirMyDocuments();
+
+#ifdef LOAD_INI_SETTINGS
+ // At this point InitDefaultControlConfigJoyPad must have set all bindings to default and ms_padButtonsInited to number of detected buttons.
+ // We will load stored bindings below, but let's cache ms_padButtonsInited before LoadINIControllerSettings and LoadSettings clears it,
+ // so we can add new joy bindings **on top of** stored bindings.
+ int connectedPadButtons = ControlsManager.ms_padButtonsInited;
+#endif
+
+ int32 gta3set = CFileMgr::OpenFile("gta_vc.set", "r");
+
+ if ( gta3set )
+ {
+ ControlsManager.LoadSettings(gta3set);
+ CFileMgr::CloseFile(gta3set);
+ }
+
+ CFileMgr::SetDir("");
+
+#ifdef LOAD_INI_SETTINGS
+ LoadINIControllerSettings();
+ if (connectedPadButtons != 0) {
+ ControlsManager.InitDefaultControlConfigJoyPad(connectedPadButtons);
+ SaveINIControllerSettings();
+ }
+#endif
+ }
+
+ SetErrorMode(SEM_FAILCRITICALERRORS);
+
+
+#ifdef PS2_MENU
+ int32 r = TheMemoryCard.CheckCardStateAtGameStartUp(CARD_ONE);
+ if ( r == CMemoryCard::ERR_DIRNOENTRY || r == CMemoryCard::ERR_NOFORMAT
+ && r != CMemoryCard::ERR_OPENNOENTRY && r != CMemoryCard::ERR_NONE )
+ {
+ LoadingScreen(nil, nil, "loadsc0");
+
+ TheText.Unload();
+ TheText.Load();
+
+ CFont::Initialise();
+
+ FrontEndMenuManager.DrawMemoryCardStartUpMenus();
+ }
+#endif
+
+#ifndef MASTER
+ if (gbModelViewer) {
+ // This is TheModelViewer in LCS
+ LoadingScreen("Loading the ModelViewer", NULL, GetRandomSplashScreen());
+ CAnimViewer::Initialise();
+ CTimer::Update();
+#ifndef PS2_MENU
+ FrontEndMenuManager.m_bGameNotLoaded = false;
+#endif
+ }
+#endif
+
+ while ( TRUE )
+ {
+ RwInitialised = TRUE;
+
+ /*
+ * Set the initial mouse position...
+ */
+ pos.x = RsGlobal.maximumWidth * 0.5f;
+ pos.y = RsGlobal.maximumHeight * 0.5f;
+
+ RsMouseSetPos(&pos);
+
+ WINDOWPLACEMENT wp;
+ wp.length = sizeof(WINDOWPLACEMENT);
+
+ /*
+ * Enter the message processing loop...
+ */
+#ifdef PS2_MENU
+ if (TheMemoryCard.m_bWantToLoad)
+ LoadSplash(GetLevelSplashScreen(CGame::currLevel));
+
+ TheMemoryCard.m_bWantToLoad = false;
+
+ CTimer::Update();
+
+ while( !RsGlobal.quit && !(FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad) )
+#else
+ while( !RsGlobal.quit && !FrontEndMenuManager.m_bWantToRestart )
+#endif
+ {
+ if( PeekMessage(&message, nil, 0U, 0U, PM_REMOVE|PM_NOYIELD) )
+ {
+ if( message.message == WM_QUIT )
+ {
+ break;
+ }
+ else
+ {
+ TranslateMessage(&message);
+ DispatchMessage(&message);
+ }
+ }
+#ifndef MASTER
+ else if (gbModelViewer) {
+ // This is TheModelViewerCore in LCS
+ TheModelViewer();
+ }
+#endif
+ else if( ForegroundApp )
+ {
+ switch ( gGameState )
+ {
+ case GS_START_UP:
+ {
+#ifdef NO_MOVIES
+ gGameState = gbNoMovies ? GS_INIT_ONCE : GS_INIT_LOGO_MPEG;
+#else
+ gGameState = GS_INIT_LOGO_MPEG;
+#endif
+ TRACE("gGameState = GS_INIT_LOGO_MPEG");
+ break;
+ }
+
+ case GS_INIT_LOGO_MPEG:
+ {
+ if ( !startupDeactivate )
+ PlayMovieInWindow(cmdShow, "movies\\Logo.mpg");
+ gGameState = GS_LOGO_MPEG;
+ TRACE("gGameState = GS_LOGO_MPEG;");
+ break;
+ }
+
+ case GS_LOGO_MPEG:
+ {
+ CPad::UpdatePads();
+
+ if ( startupDeactivate || ControlsManager.GetJoyButtonJustDown() != 0 )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->NewState.CheckForInput() )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->GetLeftMouseJustDown() )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->GetEnterJustDown() )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->GetCharJustDown(' ') )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->GetAltJustDown() )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->GetTabJustDown() )
+ ++gGameState;
+
+ break;
+ }
+
+ case GS_INIT_INTRO_MPEG:
+ {
+#ifdef NO_MOVIES
+ if (!gbNoMovies)
+#endif
+ CloseClip();
+#ifndef FIX_BUGS
+ CoUninitialize();
+#endif
+
+ if ( FrontEndMenuManager.OS_Language == LANG_FRENCH || FrontEndMenuManager.OS_Language == LANG_GERMAN )
+ PlayMovieInWindow(cmdShow, "movies\\GTAtitlesGER.mpg");
+ else
+ PlayMovieInWindow(cmdShow, "movies\\GTAtitles.mpg");
+
+ gGameState = GS_INTRO_MPEG;
+ TRACE("gGameState = GS_INTRO_MPEG;");
+ break;
+ }
+
+ case GS_INTRO_MPEG:
+ {
+ CPad::UpdatePads();
+
+ if ( startupDeactivate || ControlsManager.GetJoyButtonJustDown() != 0 )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->NewState.CheckForInput() )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->GetLeftMouseJustDown() )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->GetEnterJustDown() )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->GetCharJustDown(' ') )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->GetAltJustDown() )
+ ++gGameState;
+ else if ( CPad::GetPad(0)->GetTabJustDown() )
+ ++gGameState;
+
+ break;
+ }
+
+ case GS_INIT_ONCE:
+ {
+#ifdef NO_MOVIES
+ if (!gbNoMovies)
+#endif
+ CloseClip();
+#ifndef FIX_BUGS
+ CoUninitialize();
+#endif
+
+#ifdef FIX_BUGS
+ // draw one frame because otherwise we'll end up looking at black screen for a while if vsync is on
+ RsCameraShowRaster(Scene.camera);
+#endif
+
+#ifdef PS2_MENU
+ extern char version_name[64];
+ if ( CGame::frenchGame || CGame::germanGame )
+ LoadingScreen(NULL, version_name, "loadsc24");
+ else
+ LoadingScreen(NULL, version_name, "loadsc0");
+
+ printf("Into TheGame!!!\n");
+#else
+ LoadingScreen(nil, nil, "loadsc0");
+ // LoadingScreen(nil, nil, "loadsc0"); // duplicate
+#endif
+ if ( !CGame::InitialiseOnceAfterRW() )
+ RsGlobal.quit = TRUE;
+
+#ifdef PS2_MENU
+ gGameState = GS_INIT_PLAYING_GAME;
+#else
+ gGameState = GS_INIT_FRONTEND;
+ TRACE("gGameState = GS_INIT_FRONTEND;");
+#endif
+ break;
+ }
+
+#ifndef PS2_MENU
+ case GS_INIT_FRONTEND:
+ {
+ LoadingScreen(nil, nil, "loadsc0");
+ // LoadingScreen(nil, nil, "loadsc0"); // duplicate
+
+ FrontEndMenuManager.m_bGameNotLoaded = true;
+
+ FrontEndMenuManager.m_bStartUpFrontEndRequested = true;
+
+ if ( defaultFullscreenRes )
+ {
+ defaultFullscreenRes = FALSE;
+ FrontEndMenuManager.m_nPrefsVideoMode = GcurSelVM;
+ FrontEndMenuManager.m_nDisplayVideoMode = GcurSelVM;
+ }
+
+ gGameState = GS_FRONTEND;
+ TRACE("gGameState = GS_FRONTEND;");
+ break;
+ }
+
+ case GS_FRONTEND:
+ {
+ GetWindowPlacement(PSGLOBAL(window), &wp);
+
+ if (wp.showCmd != SW_SHOWMINIMIZED)
+ RsEventHandler(rsFRONTENDIDLE, nil);
+
+#ifdef PS2_MENU
+ if ( !FrontEndMenuManager.m_bMenuActive || TheMemoryCard.m_bWantToLoad )
+#else
+ if ( !FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bWantToLoad )
+#endif
+ {
+ gGameState = GS_INIT_PLAYING_GAME;
+ TRACE("gGameState = GS_INIT_PLAYING_GAME;");
+ }
+
+#ifdef PS2_MENU
+ if (TheMemoryCard.m_bWantToLoad )
+#else
+ if ( FrontEndMenuManager.m_bWantToLoad )
+#endif
+ {
+ InitialiseGame();
+ FrontEndMenuManager.m_bGameNotLoaded = false;
+ gGameState = GS_PLAYING_GAME;
+ TRACE("gGameState = GS_PLAYING_GAME;");
+ }
+ break;
+ }
+#endif
+
+ case GS_INIT_PLAYING_GAME:
+ {
+#ifdef PS2_MENU
+ CGame::Initialise("DATA\\GTA3.DAT");
+
+ //LoadingScreen("Starting Game", NULL, GetRandomSplashScreen());
+
+ if ( TheMemoryCard.CheckCardInserted(CARD_ONE) == CMemoryCard::NO_ERR_SUCCESS
+ && TheMemoryCard.ChangeDirectory(CARD_ONE, TheMemoryCard.Cards[CARD_ONE].dir)
+ && TheMemoryCard.FindMostRecentFileName(CARD_ONE, TheMemoryCard.MostRecentFile) == true
+ && TheMemoryCard.CheckDataNotCorrupt(TheMemoryCard.MostRecentFile))
+ {
+ strcpy(TheMemoryCard.LoadFileName, TheMemoryCard.MostRecentFile);
+ TheMemoryCard.b_FoundRecentSavedGameWantToLoad = true;
+
+ if (CMenuManager::m_PrefsLanguage != TheMemoryCard.GetLanguageToLoad())
+ {
+ CMenuManager::m_PrefsLanguage = TheMemoryCard.GetLanguageToLoad();
+ TheText.Unload();
+ TheText.Load();
+ }
+
+ CGame::currLevel = (eLevelName)TheMemoryCard.GetLevelToLoad();
+ }
+#else
+ InitialiseGame();
+
+ FrontEndMenuManager.m_bGameNotLoaded = false;
+#endif
+ gGameState = GS_PLAYING_GAME;
+ TRACE("gGameState = GS_PLAYING_GAME;");
+ break;
+ }
+
+ case GS_PLAYING_GAME:
+ {
+ float ms = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
+ if ( RwInitialised )
+ {
+ if (!FrontEndMenuManager.m_PrefsFrameLimiter || (1000.0f / (float)RsGlobal.maxFPS) < ms)
+ RsEventHandler(rsIDLE, (void *)TRUE);
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ if ( RwCameraBeginUpdate(Scene.camera) )
+ {
+ RwCameraEndUpdate(Scene.camera);
+ ForegroundApp = TRUE;
+ RsEventHandler(rsACTIVATE, (void *)TRUE);
+ }
+
+ WaitMessage();
+ }
+ }
+
+
+ /*
+ * About to shut down - block resize events again...
+ */
+ RwInitialised = FALSE;
+
+ FrontEndMenuManager.UnloadTextures();
+#ifdef PS2_MENU
+ if ( !(FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad))
+ break;
+#else
+ if ( !FrontEndMenuManager.m_bWantToRestart )
+ break;
+#endif
+
+ CPad::ResetCheats();
+ CPad::StopPadsShaking();
+
+ DMAudio.ChangeMusicMode(MUSICMODE_DISABLE);
+
+#ifdef PS2_MENU
+ CGame::ShutDownForRestart();
+#endif
+ CTimer::Stop();
+
+#ifdef PS2_MENU
+ if (FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad)
+ {
+ if (TheMemoryCard.b_FoundRecentSavedGameWantToLoad)
+ {
+ FrontEndMenuManager.m_bWantToRestart = true;
+ TheMemoryCard.m_bWantToLoad = true;
+ }
+
+ CGame::InitialiseWhenRestarting();
+ DMAudio.ChangeMusicMode(MUSICMODE_GAME);
+ FrontEndMenuManager.m_bWantToRestart = false;
+
+ continue;
+ }
+
+ CGame::ShutDown();
+ CTimer::Stop();
+
+ break;
+#else
+ if ( FrontEndMenuManager.m_bWantToLoad )
+ {
+ CGame::ShutDownForRestart();
+ CGame::InitialiseWhenRestarting();
+ DMAudio.ChangeMusicMode(MUSICMODE_GAME);
+ LoadSplash(GetLevelSplashScreen(CGame::currLevel));
+ FrontEndMenuManager.m_bWantToLoad = false;
+ }
+ else
+ {
+#ifndef MASTER
+ if ( gbModelViewer )
+ CAnimViewer::Shutdown();
+ else
+#endif
+ if ( gGameState == GS_PLAYING_GAME )
+ CGame::ShutDown();
+
+ CTimer::Stop();
+
+ if ( FrontEndMenuManager.m_bFirstTime == true )
+ {
+ gGameState = GS_INIT_FRONTEND;
+ TRACE("gGameState = GS_INIT_FRONTEND;");
+ }
+ else
+ {
+ gGameState = GS_INIT_PLAYING_GAME;
+ TRACE("gGameState = GS_INIT_PLAYING_GAME;");
+ }
+ }
+
+ FrontEndMenuManager.m_bFirstTime = false;
+ FrontEndMenuManager.m_bWantToRestart = false;
+#endif
+ }
+
+
+#ifndef MASTER
+ if ( gbModelViewer )
+ CAnimViewer::Shutdown();
+ else
+#endif
+ if ( gGameState == GS_PLAYING_GAME )
+ CGame::ShutDown();
+
+ DMAudio.Terminate();
+
+ _psFreeVideoModeList();
+
+
+ /*
+ * Tidy up the 3D (RenderWare) components of the application...
+ */
+ RsEventHandler(rsRWTERMINATE, nil);
+
+ /*
+ * Kill the window...
+ */
+ DestroyWindow(PSGLOBAL(window));
+
+ /*
+ * Free the platform dependent data...
+ */
+ RsEventHandler(rsTERMINATE, nil);
+
+ /*
+ * Free the argv strings...
+ */
+ free(argv);
+
+ ShowCursor(TRUE);
+
+ SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &SavedStickyKeys, SPIF_SENDCHANGE);
+ SystemParametersInfo(SPI_SETPOWEROFFACTIVE, TRUE, nil, SPIF_SENDCHANGE);
+ SystemParametersInfo(SPI_SETLOWPOWERACTIVE, TRUE, nil, SPIF_SENDCHANGE);
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE, nil, SPIF_SENDCHANGE);
+
+ SetErrorMode(0);
+
+ return message.wParam;
+}
+
+/*
+ *****************************************************************************
+ */
+
+#define DEVICE_AXIS_MIN -2000
+#define DEVICE_AXIS_MAX 2000
+
+
+HRESULT _InputInitialise()
+{
+ HRESULT hr;
+
+ // Create a DInput object
+ if( FAILED( hr = DirectInput8Create( GetModuleHandle(nil), DIRECTINPUT_VERSION,
+ IID_IDirectInput8, (VOID**)&PSGLOBAL(dinterface), nil ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+HRESULT _InputInitialiseMouse(bool exclusive)
+{
+ HRESULT hr;
+
+ // Obtain an interface to the system mouse device.
+ if( FAILED( hr = PSGLOBAL(dinterface)->CreateDevice( GUID_SysMouse, &PSGLOBAL(mouse), nil ) ) )
+ return hr;
+
+ // Set the data format to "mouse format" - a predefined data format
+ //
+ // A data format specifies which controls on a device we
+ // are interested in, and how they should be reported.
+ //
+ // This tells DirectInput that we will be passing a
+ // DIMOUSESTATE2 structure to IDirectInputDevice::GetDeviceState.
+ if( FAILED( hr = PSGLOBAL(mouse)->SetDataFormat( &c_dfDIMouse2 ) ) )
+ return hr;
+
+ if( FAILED( hr = PSGLOBAL(mouse)->SetCooperativeLevel( PSGLOBAL(window), (exclusive ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE) | DISCL_FOREGROUND ) ) )
+ return hr;
+
+ // Acquire the newly created device
+ PSGLOBAL(mouse)->Acquire();
+
+ return S_OK;
+}
+
+RwV2d leftStickPos;
+RwV2d rightStickPos;
+
+HRESULT CapturePad(RwInt32 padID)
+{
+ HRESULT hr;
+ DIJOYSTATE2 js;
+ LPDIRECTINPUTDEVICE8 *pPad = nil;
+
+ if( padID == 0 )
+ pPad = &PSGLOBAL(joy1);
+ else if( padID == 1)
+ pPad = &PSGLOBAL(joy2);
+ else
+ assert("invalid padID");
+
+ if ( nil == (*pPad) )
+ return S_OK;
+
+ // Poll the device to read the current state
+ hr = (*pPad)->Poll();
+
+ if( FAILED(hr) )
+ {
+ // DInput is telling us that the input stream has been
+ // interrupted. We aren't tracking any state between polls, so
+ // we don't have any special reset that needs to be done. We
+ // just re-acquire and try again.
+ hr = (*pPad)->Acquire();
+ while( hr == DIERR_INPUTLOST )
+ hr = (*pPad)->Acquire();
+
+ // hr may be DIERR_OTHERAPPHASPRIO or other errors. This
+ // may occur when the app is minimized or in the process of
+ // switching, so just try again later
+
+ if( FAILED(hr) )
+ return hr;
+
+ hr = (*pPad)->Poll();
+ if( FAILED(hr) )
+ return hr;
+ }
+
+ // Get the input's device state
+ if( FAILED( hr = (*pPad)->GetDeviceState( sizeof(DIJOYSTATE2), &js ) ) )
+ return hr; // The device should have been acquired during the Poll()
+
+ if ( ControlsManager.m_bFirstCapture == true )
+ {
+ memcpy(&ControlsManager.m_OldState, &js, sizeof(DIJOYSTATE2));
+ memcpy(&ControlsManager.m_NewState, &js, sizeof(DIJOYSTATE2));
+
+ ControlsManager.m_bFirstCapture = false;
+ }
+ else
+ {
+ memcpy(&ControlsManager.m_OldState, &ControlsManager.m_NewState, sizeof(DIJOYSTATE2));
+ memcpy(&ControlsManager.m_NewState, &js, sizeof(DIJOYSTATE2));
+ }
+
+ RsPadButtonStatus bs;
+ bs.padID = padID;
+
+ RsPadEventHandler(rsPADBUTTONUP, (void *)&bs);
+
+ bool deviceAvailable = (*pPad) != nil;
+
+ if ( deviceAvailable )
+ {
+ leftStickPos.x = (float)js.lX / (float)((DEVICE_AXIS_MAX - DEVICE_AXIS_MIN) / 2);
+ leftStickPos.y = (float)js.lY / (float)((DEVICE_AXIS_MAX - DEVICE_AXIS_MIN) / 2);
+
+ if (LOWORD(js.rgdwPOV[0]) != 0xFFFF)
+ {
+ float angle = DEGTORAD((float)js.rgdwPOV[0] / 100.0f);
+
+ leftStickPos.x = Sin(angle);
+ leftStickPos.y = -Cos(angle);
+ }
+
+ if ( AllValidWinJoys.m_aJoys[bs.padID].m_bHasAxisR && AllValidWinJoys.m_aJoys[bs.padID].m_bHasAxisZ )
+ {
+ rightStickPos.x = (float)js.lZ / (float)((DEVICE_AXIS_MAX - DEVICE_AXIS_MIN) / 2);
+ rightStickPos.y = (float)js.lRz / (float)((DEVICE_AXIS_MAX - DEVICE_AXIS_MIN) / 2);
+ }
+ }
+
+ {
+ if (CPad::m_bMapPadOneToPadTwo)
+ bs.padID = 1;
+
+ RsPadEventHandler(rsPADBUTTONUP, (void *)&bs);
+ RsPadEventHandler(rsPADBUTTONDOWN, (void *)&bs);
+ }
+
+ {
+ if (CPad::m_bMapPadOneToPadTwo)
+ bs.padID = 1;
+
+ CPad *pad = CPad::GetPad(bs.padID);
+
+ if ( Abs(leftStickPos.x) > 0.3f )
+ pad->PCTempJoyState.LeftStickX = (int32)(leftStickPos.x * 128.0f);
+
+ if ( Abs(leftStickPos.y) > 0.3f )
+ pad->PCTempJoyState.LeftStickY = (int32)(leftStickPos.y * 128.0f);
+
+ if ( Abs(rightStickPos.x) > 0.3f )
+ pad->PCTempJoyState.RightStickX = (int32)(rightStickPos.x * 128.0f);
+
+ if ( Abs(rightStickPos.y) > 0.3f )
+ pad->PCTempJoyState.RightStickY = (int32)(rightStickPos.y * 128.0f);
+ }
+
+ return S_OK;
+}
+
+void _InputInitialiseJoys()
+{
+ DIPROPDWORD prop;
+ DIDEVCAPS devCaps;
+
+ for ( int32 i = 0; i < _TODOCONST(2); i++ )
+ AllValidWinJoys.ClearJoyInfo(i);
+
+ _InputAddJoys();
+
+ if ( PSGLOBAL(joy1) != nil )
+ {
+ devCaps.dwSize = sizeof(DIDEVCAPS);
+ PSGLOBAL(joy1)->GetCapabilities(&devCaps);
+
+ prop.diph.dwSize = sizeof(DIPROPDWORD);
+ prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+ prop.diph.dwObj = 0;
+ prop.diph.dwHow = 0;
+
+ PSGLOBAL(joy1)->GetProperty(DIPROP_VIDPID, (LPDIPROPHEADER)&prop);
+ AllValidWinJoys.m_aJoys[0].m_nVendorID = LOWORD(prop.dwData);
+ AllValidWinJoys.m_aJoys[0].m_nProductID = HIWORD(prop.dwData);
+ AllValidWinJoys.m_aJoys[0].m_bInitialised = true;
+
+ ControlsManager.InitDefaultControlConfigJoyPad(devCaps.dwButtons);
+ }
+
+ if ( PSGLOBAL(joy2) != nil )
+ {
+ PSGLOBAL(joy2)->GetProperty(DIPROP_VIDPID, (LPDIPROPHEADER)&prop);
+ AllValidWinJoys.m_aJoys[1].m_nVendorID = LOWORD(prop.dwData);
+ AllValidWinJoys.m_aJoys[1].m_nProductID = HIWORD(prop.dwData);
+ AllValidWinJoys.m_aJoys[1].m_bInitialised = true;
+ }
+}
+
+void _InputAddJoyStick(LPDIRECTINPUTDEVICE8 lpDevice, INT num)
+{
+ DIDEVICEOBJECTINSTANCE objInst;
+
+ objInst.dwSize = sizeof( DIDEVICEOBJECTINSTANCE );
+
+ DIPROPRANGE range;
+ range.diph.dwSize = sizeof(DIPROPRANGE);
+ range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+ range.lMin = DEVICE_AXIS_MIN;
+ range.lMax = DEVICE_AXIS_MAX;
+ range.diph.dwHow = DIPH_BYOFFSET;
+
+ // get the info about the object from the device
+
+ range.diph.dwObj = DIJOFS_X;
+ if ( lpDevice != nil )
+ {
+ if ( SUCCEEDED( lpDevice->GetObjectInfo( &objInst, DIJOFS_X, DIPH_BYOFFSET ) ) )
+ {
+ if( FAILED( lpDevice->SetProperty( DIPROP_RANGE, (LPCDIPROPHEADER)&range ) ) )
+ return;
+ else
+ ;
+ }
+ }
+
+ range.diph.dwObj = DIJOFS_Y;
+ if ( lpDevice != nil )
+ {
+ if ( SUCCEEDED( lpDevice->GetObjectInfo( &objInst, DIJOFS_Y, DIPH_BYOFFSET ) ) )
+ {
+ if( FAILED( lpDevice->SetProperty( DIPROP_RANGE, (LPCDIPROPHEADER)&range ) ) )
+ return;
+ else
+ ;
+ }
+ }
+
+ range.diph.dwObj = DIJOFS_Z;
+ if ( lpDevice != nil )
+ {
+ if ( SUCCEEDED( lpDevice->GetObjectInfo( &objInst, DIJOFS_Z, DIPH_BYOFFSET ) ) )
+ {
+ if( FAILED( lpDevice->SetProperty( DIPROP_RANGE, (LPCDIPROPHEADER)&range ) ) )
+ return;
+ else
+ AllValidWinJoys.m_aJoys[num].m_bHasAxisZ = true; // z rightStickPos.x
+ }
+ }
+
+ range.diph.dwObj = DIJOFS_RZ;
+ if ( lpDevice != nil )
+ {
+ if ( SUCCEEDED( lpDevice->GetObjectInfo( &objInst, DIJOFS_RZ, DIPH_BYOFFSET ) ) )
+ {
+ if( FAILED( lpDevice->SetProperty( DIPROP_RANGE, (LPCDIPROPHEADER)&range ) ) )
+ return;
+ else
+ AllValidWinJoys.m_aJoys[num].m_bHasAxisR = true; // r rightStickPos.y
+ }
+ }
+}
+
+HRESULT _InputAddJoys()
+{
+ HRESULT hr;
+
+ hr = PSGLOBAL(dinterface)->EnumDevices(DI8DEVCLASS_GAMECTRL, _InputEnumDevicesCallback, nil, DIEDFL_ATTACHEDONLY );
+
+ if( FAILED(hr) )
+ return hr;
+
+ if ( PSGLOBAL(joy1) == nil )
+ return S_FALSE;
+
+ _InputAddJoyStick(PSGLOBAL(joy1), 0);
+
+ if ( PSGLOBAL(joy2) == nil )
+ return S_OK; // we have one device already so return OK and ignore second
+
+ _InputAddJoyStick(PSGLOBAL(joy2), 1);
+
+ return S_OK;
+}
+
+HRESULT _InputGetMouseState(DIMOUSESTATE2 *state)
+{
+ HRESULT hr;
+
+ if ( PSGLOBAL(mouse) == nil )
+ return S_FALSE;
+
+ // Get the input's device state, and put the state in dims
+ ZeroMemory( state, sizeof(DIMOUSESTATE2) );
+
+ hr = PSGLOBAL(mouse)->GetDeviceState( sizeof(DIMOUSESTATE2), state );
+
+ if( FAILED(hr) )
+ {
+ // DirectInput may be telling us that the input stream has been
+ // interrupted. We aren't tracking any state between polls, so
+ // we don't have any special reset that needs to be done.
+ // We just re-acquire and try again.
+
+ // If input is lost then acquire and keep trying
+ hr = PSGLOBAL(mouse)->Acquire();
+ while( hr == DIERR_INPUTLOST )
+ hr = PSGLOBAL(mouse)->Acquire();
+
+ ZeroMemory( state, sizeof(DIMOUSESTATE2) );
+ hr = PSGLOBAL(mouse)->GetDeviceState( sizeof(DIMOUSESTATE2), state );
+
+ return hr;
+ }
+
+ return S_OK;
+}
+
+void _InputShutdown()
+{
+ SAFE_RELEASE(PSGLOBAL(dinterface));
+}
+
+void _InputShutdownMouse()
+{
+ if (PSGLOBAL(mouse) == nil)
+ return;
+
+ PSGLOBAL(mouse)->Unacquire();
+ SAFE_RELEASE(PSGLOBAL(mouse));
+}
+
+bool _InputMouseNeedsExclusive(void)
+{
+ // FIX: I don't know why R* needed that, but it causes infamous mouse bug on modern systems.
+ // Probably DirectInput bug, since Acquire() and GetDeviceState() reports everything A-OK.
+#ifdef FIX_BUGS
+ return false;
+#endif
+ RwVideoMode vm;
+ RwEngineGetVideoModeInfo(&vm, GcurSelVM);
+
+ return vm.flags & rwVIDEOMODEEXCLUSIVE;
+}
+
+BOOL CALLBACK _InputEnumDevicesCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext )
+{
+ HRESULT hr;
+
+ static INT Count = 0;
+
+ LPDIRECTINPUTDEVICE8 *pJoystick = nil;
+
+ if ( Count == 0 )
+ pJoystick = &PSGLOBAL(joy1);
+ else if ( Count == 1 )
+ pJoystick = &PSGLOBAL(joy2);
+ else
+ assert("too many pads");
+
+ // Obtain an interface to the enumerated joystick.
+ hr = PSGLOBAL(dinterface)->CreateDevice( pdidInstance->guidInstance, pJoystick, nil );
+
+ // If it failed, then we can't use this joystick. (Maybe the user unplugged
+ // it while we were in the middle of enumerating it.)
+ if( hr != S_OK )
+ return DIENUM_CONTINUE;
+
+ hr = (*pJoystick)->SetDataFormat( &c_dfDIJoystick2 );
+ if( hr != S_OK )
+ {
+ (*pJoystick)->Release();
+ return DIENUM_CONTINUE;
+ }
+
+ ++Count;
+
+ hr = (*pJoystick)->SetCooperativeLevel( PSGLOBAL(window), DISCL_NONEXCLUSIVE|DISCL_FOREGROUND );
+ if( hr != S_OK )
+ {
+ (*pJoystick)->Release();
+#ifdef FIX_BUGS
+ // BUG: enum will be called with Count == 2, which will write to a null pointer
+ // So decrement count again since we're not using this pad
+ --Count;
+#endif
+ return DIENUM_CONTINUE;
+ }
+
+ // Stop enumeration. Note: we're just taking the first two joysticks we get. You
+ // could store all the enumerated joysticks and let the user pick.
+ if ( Count == 2 )
+ return DIENUM_STOP;
+
+ return DIENUM_CONTINUE;
+}
+
+BOOL _InputTranslateKey(RsKeyCodes *rs, UINT flag, UINT key)
+{
+ *rs = rsNULL;
+
+ switch ( key )
+ {
+ case VK_SHIFT:
+ {
+ if ( _dwOperatingSystemVersion == OS_WIN98 )
+ *rs = rsSHIFT;
+ break;
+ }
+
+ case VK_RETURN:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsPADENTER;
+ else
+ *rs = rsENTER;
+ break;
+ }
+
+ case VK_CONTROL:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsRCTRL;
+ else
+ *rs = rsLCTRL;
+ break;
+ }
+
+ case VK_MENU:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsRALT;
+ else
+ *rs = rsLALT;
+ break;
+ }
+
+ case VK_APPS:
+ {
+ *rs = rsAPPS;
+ break;
+ }
+
+ case VK_PAUSE:
+ {
+ *rs = rsPAUSE;
+ break;
+ }
+
+ case VK_CAPITAL:
+ {
+ *rs = rsCAPSLK;
+ break;
+ }
+
+ case VK_ESCAPE:
+ {
+ *rs = rsESC;
+ break;
+ }
+
+ case VK_PRIOR:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsPGUP;
+ else
+ *rs = rsPADPGUP;
+ break;
+ }
+
+ case VK_NEXT:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsPGDN;
+ else
+ *rs = rsPADPGDN;
+ break;
+ }
+
+ case VK_END:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsEND;
+ else
+ *rs = rsPADEND;
+ break;
+ }
+
+ case VK_HOME:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsHOME;
+ else
+ *rs = rsPADHOME;
+ break;
+ }
+
+ case VK_LEFT:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsLEFT;
+ else
+ *rs = rsPADLEFT;
+ break;
+ }
+
+ case VK_UP:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsUP;
+ else
+ *rs = rsPADUP;
+ break;
+ }
+
+ case VK_RIGHT:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsRIGHT;
+ else
+ *rs = rsPADRIGHT;
+ break;
+ }
+
+ case VK_DOWN:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsDOWN;
+ else
+ *rs = rsPADDOWN;
+ break;
+ }
+
+ case VK_INSERT:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsINS;
+ else
+ *rs = rsPADINS;
+ break;
+ }
+
+ case VK_DELETE:
+ {
+ if ( _InputIsExtended(flag) )
+ *rs = rsDEL;
+ else
+ *rs = rsPADDEL;
+ break;
+ }
+
+ case VK_LWIN:
+ {
+ *rs = rsLWIN;
+ break;
+ }
+
+ case VK_RWIN:
+ {
+ *rs = rsRWIN;
+ break;
+ }
+
+ case VK_NUMPAD0:
+ {
+ *rs = rsPADINS;
+ break;
+ }
+
+ case VK_NUMPAD1:
+ {
+ *rs = rsPADEND;
+ break;
+ }
+
+ case VK_NUMPAD2:
+ {
+ *rs = rsPADDOWN;
+ break;
+ }
+
+ case VK_NUMPAD3:
+ {
+ *rs = rsPADPGDN;
+ break;
+ }
+
+ case VK_NUMPAD4:
+ {
+ *rs = rsPADLEFT;
+ break;
+ }
+
+ case VK_NUMPAD5:
+ {
+ *rs = rsPAD5;
+ break;
+ }
+
+ case VK_NUMPAD6:
+ {
+ *rs = rsPADRIGHT;
+ break;
+ }
+
+ case VK_NUMPAD7:
+ {
+ *rs = rsPADHOME;
+ break;
+ }
+
+ case VK_NUMPAD8:
+ {
+ *rs = rsPADUP;
+ break;
+ }
+
+ case VK_NUMPAD9:
+ {
+ *rs = rsPADPGUP;
+ break;
+ }
+
+ case VK_MULTIPLY:
+ {
+ *rs = rsTIMES;
+ break;
+ }
+
+ case VK_DIVIDE:
+ {
+ *rs = rsDIVIDE;
+ break;
+ }
+
+ case VK_ADD:
+ {
+ *rs = rsPLUS;
+ break;
+ }
+
+ case VK_SUBTRACT:
+ {
+ *rs = rsMINUS;
+ break;
+ }
+
+ case VK_DECIMAL:
+ {
+ *rs = rsPADDEL;
+ break;
+ }
+
+ case VK_F1:
+ {
+ *rs = rsF1;
+ break;
+ }
+
+ case VK_F2:
+ {
+ *rs = rsF2;
+ break;
+ }
+
+ case VK_F3:
+ {
+ *rs = rsF3;
+ break;
+ }
+
+ case VK_F4:
+ {
+ *rs = rsF4;
+ break;
+ }
+
+ case VK_F5:
+ {
+ *rs = rsF5;
+ break;
+ }
+
+ case VK_F6:
+ {
+ *rs = rsF6;
+ break;
+ }
+
+ case VK_F7:
+ {
+ *rs = rsF7;
+ break;
+ }
+
+ case VK_F8:
+ {
+ *rs = rsF8;
+ break;
+ }
+
+ case VK_F9:
+ {
+ *rs = rsF9;
+ break;
+ }
+
+ case VK_F10:
+ {
+ *rs = rsF10;
+ break;
+ }
+
+ case VK_F11:
+ {
+ *rs = rsF11;
+ break;
+ }
+
+ case VK_F12:
+ {
+ *rs = rsF12;
+ break;
+ }
+
+ case VK_NUMLOCK:
+ {
+ *rs = rsNUMLOCK;
+ break;
+ }
+
+ case VK_SCROLL:
+ {
+ *rs = rsSCROLL;
+ break;
+ }
+
+ case VK_BACK:
+ {
+ *rs = rsBACKSP;
+ break;
+ }
+
+ case VK_TAB:
+ {
+ *rs = rsTAB;
+ break;
+ }
+
+ default:
+ {
+ UINT vkey = MapVirtualKey(key, MAPVK_VK_TO_CHAR) & 0xFFFF;
+ if ( vkey < 255 )
+ *rs = (RsKeyCodes)vkey;
+ break;
+ }
+ }
+
+ return *rs != rsNULL;
+}
+
+void _InputTranslateShiftKeyUpDown(RsKeyCodes *rs)
+{
+ if ( _dwOperatingSystemVersion != OS_WIN98 )
+ {
+ if ( _InputTranslateShiftKey(rs, VK_LSHIFT, TRUE) )
+ RsKeyboardEventHandler(rsKEYDOWN, rs);
+ if ( _InputTranslateShiftKey(rs, VK_RSHIFT, TRUE) )
+ RsKeyboardEventHandler(rsKEYDOWN, rs);
+ if ( _InputTranslateShiftKey(rs, VK_LSHIFT, FALSE) )
+ RsKeyboardEventHandler(rsKEYUP, rs);
+ if ( _InputTranslateShiftKey(rs, VK_RSHIFT, FALSE) )
+ RsKeyboardEventHandler(rsKEYUP, rs);
+ }
+}
+
+BOOL _InputTranslateShiftKey(RsKeyCodes *rs, UINT key, BOOLEAN bDown)
+{
+ *rs = rsNULL;
+ switch ( key )
+ {
+ case VK_LSHIFT:
+ {
+ if ( bDown == (GetKeyState(VK_LSHIFT) & 0x8000) >> 15 )
+ *rs = rsLSHIFT;
+ break;
+ }
+
+ case VK_RSHIFT:
+ {
+ if ( bDown == (GetKeyState(VK_RSHIFT) & 0x8000) >> 15 )
+ *rs = rsRSHIFT;
+ break;
+ }
+
+ default:
+ {
+ return *rs != rsNULL;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL _InputIsExtended(INT flag)
+{
+ return (flag & 0x1000000) != 0;
+}
+
+#if (defined(_MSC_VER))
+int strcasecmp(const char *str1, const char *str2)
+{
+ return _strcmpi(str1, str2);
+}
+int strncasecmp(const char *str1, const char *str2, size_t len)
+{
+ return _strnicmp(str1, str2, len);
+}
+#endif
+#endif
diff --git a/src/skel/win/win.h b/src/skel/win/win.h
new file mode 100644
index 0000000..be84089
--- /dev/null
+++ b/src/skel/win/win.h
@@ -0,0 +1,91 @@
+
+// DON'T include directly. crossplatform.h includes this if you're using D3D9 backend(win.cpp).
+
+#if (!defined(_PLATFORM_WIN_H))
+#define _PLATFORM_WIN_H
+
+#if (!defined(RSREGSETBREAKALLOC))
+#define RSREGSETBREAKALLOC(_name) /* No op */
+#endif /* (!defined(RSREGSETBREAKALLOC)) */
+
+#ifdef __DINPUT_INCLUDED__
+/* platform specfic global data */
+typedef struct
+{
+ HWND window;
+ HINSTANCE instance;
+ RwBool fullScreen;
+ RwV2d lastMousePos;
+
+ DWORD field_14;
+
+ LPDIRECTINPUT8 dinterface;
+ LPDIRECTINPUTDEVICE8 mouse;
+ LPDIRECTINPUTDEVICE8 joy1;
+ LPDIRECTINPUTDEVICE8 joy2;
+}
+psGlobalType;
+
+#define PSGLOBAL(var) (((psGlobalType *)(RsGlobal.ps))->var)
+
+enum eJoypads
+{
+ JOYSTICK1 = 0,
+ JOYSTICK2,
+ MAX_JOYSTICKS
+};
+
+enum eJoypadState
+{
+ JOYPAD_UNUSED,
+ JOYPAD_ATTACHED,
+};
+
+struct tJoy
+{
+ eJoypadState m_State;
+ bool m_bInitialised;
+ bool m_bHasAxisZ;
+ bool m_bHasAxisR;
+ int m_nVendorID;
+ int m_nProductID;
+};
+
+class CJoySticks
+{
+public:
+ tJoy m_aJoys[MAX_JOYSTICKS];
+
+ CJoySticks();
+ void ClearJoyInfo(int joyID);
+};
+
+extern CJoySticks AllValidWinJoys;
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#ifdef __DINPUT_INCLUDED__
+HRESULT _InputInitialise();
+HRESULT CapturePad(RwInt32 padID);
+void _InputAddJoyStick(LPDIRECTINPUTDEVICE8 lpDevice, INT num);
+HRESULT _InputAddJoys();
+HRESULT _InputGetMouseState(DIMOUSESTATE2 *state);
+void _InputShutdown();
+BOOL CALLBACK _InputEnumDevicesCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext );
+BOOL _InputTranslateKey(RsKeyCodes *rs, UINT flag, UINT key);
+BOOL _InputTranslateShiftKey(RsKeyCodes *rs, UINT key, BOOLEAN bDown);
+BOOL _InputIsExtended(INT flag);
+#endif
+
+void CenterVideo(void);
+void CloseClip(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* (!defined(_PLATFORM_WIN_H)) */
diff --git a/src/skel/win/win.rc b/src/skel/win/win.rc
new file mode 100644
index 0000000..9b5aa30
--- /dev/null
+++ b/src/skel/win/win.rc
@@ -0,0 +1,47 @@
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+//#if !defined(__GNU_C__)
+//#include "afxres.h"
+//#else
+#include "winresrc.h"
+//#endif /* !defined(__GNU_C__) */
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 186, 90
+STYLE DS_MODALFRAME | DS_CENTER | DS_CENTERMOUSE | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Device Selection"
+FONT 8, "MS Sans Serif"
+BEGIN
+ COMBOBOX IDC_DEVICESEL,7,25,172,33,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ COMBOBOX IDC_VIDMODE,7,46,172,74,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ DEFPUSHBUTTON "EXIT",IDEXIT,103,69,52,14
+ DEFPUSHBUTTON "OK",IDOK,28,69,50,14
+ LTEXT "Please select the Device To Use:",IDC_SELECTDEVICE,7,7,
+ 137,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN_ICON ICON DISCARDABLE "gtavc.ico"
+
+///////////////////////////////////////////////////////////////////////////// \ No newline at end of file