mirror of https://github.com/OpenRCT2/OpenRCT2.git
446 lines
12 KiB
C
446 lines
12 KiB
C
/*****************************************************************************
|
|
* Copyright (c) 2014 Ted John, Alexander Overvoorde
|
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
|
*
|
|
* This file is part of OpenRCT2.
|
|
*
|
|
* OpenRCT2 is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <shlobj.h>
|
|
#include <tchar.h>
|
|
#include <windows.h>
|
|
#include <SDL.h>
|
|
#include <SDL_syswm.h>
|
|
|
|
#include "addresses.h"
|
|
#include "gfx.h"
|
|
#include "osinterface.h"
|
|
#include "rct2.h"
|
|
|
|
typedef void(*update_palette_func)(char*, int, int);
|
|
|
|
openrct2_cursor gCursorState;
|
|
const unsigned char *gKeysState;
|
|
unsigned char *gKeysPressed;
|
|
unsigned int gLastKeyPressed;
|
|
|
|
static void osinterface_create_window();
|
|
static void osinterface_close_window();
|
|
static void osinterface_resize(int width, int height);
|
|
static void osinterface_update_palette(char* colours, int start_index, int num_colours);
|
|
|
|
static SDL_Window *_window;
|
|
static SDL_Surface *_surface;
|
|
static SDL_Palette *_palette;
|
|
|
|
static int _screenBufferSize;
|
|
static void *_screenBuffer;
|
|
|
|
void osinterface_init()
|
|
{
|
|
osinterface_create_window();
|
|
|
|
gKeysPressed = malloc(sizeof(unsigned char) * 256);
|
|
memset(gKeysPressed, 0, sizeof(unsigned char) * 256);
|
|
|
|
// RCT2_CALLPROC(0x00404584); // dinput_init()
|
|
}
|
|
|
|
static void osinterface_create_window()
|
|
{
|
|
SDL_SysWMinfo wmInfo;
|
|
HWND hWnd;
|
|
int width, height;
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
|
RCT2_ERROR("SDL_Init %s", SDL_GetError());
|
|
exit(-1);
|
|
}
|
|
|
|
// stuff
|
|
{
|
|
RCT2_CALLPROC_EBPSAFE(0x0068352C);
|
|
RCT2_CALLPROC_EBPSAFE(0x0068371D);
|
|
|
|
width = RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_RESOLUTION_WIDTH, sint16);
|
|
height = RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_RESOLUTION_HEIGHT, sint16);
|
|
|
|
width = 640;
|
|
height = 480;
|
|
}
|
|
|
|
RCT2_GLOBAL(0x009E2D8C, sint32) = 0;
|
|
|
|
|
|
_window = SDL_CreateWindow("OpenRCT2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_RESIZABLE);
|
|
if (!_window) {
|
|
RCT2_ERROR("SDL_CreateWindow failed %s", SDL_GetError());
|
|
exit(-1);
|
|
}
|
|
|
|
// Get the HWND context
|
|
if (SDL_GetWindowWMInfo(_window, &wmInfo) != SDL_TRUE) {
|
|
RCT2_ERROR("SDL_GetWindowWMInfo failed %s", SDL_GetError());
|
|
exit(-1);
|
|
}
|
|
hWnd = wmInfo.info.win.window;
|
|
RCT2_GLOBAL(0x009E2D70, HWND) = hWnd;
|
|
|
|
// Set the update palette function pointer
|
|
RCT2_GLOBAL(0x009E2BE4, update_palette_func) = osinterface_update_palette;
|
|
|
|
// Initialise the surface, palette and draw buffer
|
|
osinterface_resize(width, height);
|
|
}
|
|
|
|
static void osinterface_resize(int width, int height)
|
|
{
|
|
rct_drawpixelinfo *screenDPI;
|
|
int newScreenBufferSize;
|
|
void *newScreenBuffer;
|
|
|
|
if (_surface != NULL)
|
|
SDL_FreeSurface(_surface);
|
|
if (_palette != NULL)
|
|
SDL_FreePalette(_palette);
|
|
|
|
_surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0);
|
|
_palette = SDL_AllocPalette(256);
|
|
|
|
if (!_surface || !_palette) {
|
|
RCT2_ERROR("%p || %p == NULL %s", _surface, _palette, SDL_GetError());
|
|
exit(-1);
|
|
}
|
|
|
|
if (SDL_SetSurfacePalette(_surface, _palette)) {
|
|
RCT2_ERROR("SDL_SetSurfacePalette failed %s", SDL_GetError());
|
|
exit(-1);
|
|
}
|
|
|
|
newScreenBufferSize = _surface->pitch * _surface->h;
|
|
newScreenBuffer = malloc(newScreenBufferSize);
|
|
if (_screenBuffer == NULL) {
|
|
memset(newScreenBuffer, 0, newScreenBufferSize);
|
|
} else {
|
|
memcpy(newScreenBuffer, _screenBuffer, min(_screenBufferSize, newScreenBufferSize));
|
|
if (newScreenBufferSize - _screenBufferSize > 0)
|
|
memset((uint8*)newScreenBuffer + _screenBufferSize, 0, newScreenBufferSize - _screenBufferSize);
|
|
free(_screenBuffer);
|
|
}
|
|
|
|
_screenBuffer = newScreenBuffer;
|
|
_screenBufferSize = newScreenBufferSize;
|
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) = width;
|
|
RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) = height;
|
|
|
|
screenDPI = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo);
|
|
screenDPI->bits = _screenBuffer;
|
|
screenDPI->x = 0;
|
|
screenDPI->y = 0;
|
|
screenDPI->width = width;
|
|
screenDPI->height = height;
|
|
screenDPI->pitch = _surface->pitch - _surface->w;
|
|
|
|
RCT2_GLOBAL(0x009ABDF0, uint8) = 6;
|
|
RCT2_GLOBAL(0x009ABDF1, uint8) = 3;
|
|
RCT2_GLOBAL(0x009ABDF2, uint8) = 1;
|
|
RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, sint16) = 64;
|
|
RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, sint16) = 8;
|
|
RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) = (width >> 6) + 1;
|
|
RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, sint32) = (height >> 3) + 1;
|
|
|
|
RCT2_CALLPROC_EBPSAFE(0x0066B905); // resize_gui()
|
|
gfx_invalidate_screen();
|
|
}
|
|
|
|
static void osinterface_update_palette(char* colours, int start_index, int num_colours)
|
|
{
|
|
SDL_Color base[256];
|
|
SDL_Surface *surface;
|
|
int i;
|
|
|
|
surface = SDL_GetWindowSurface(_window);
|
|
if (!surface) {
|
|
RCT2_ERROR("SDL_GetWindowSurface failed %s", SDL_GetError());
|
|
exit(1);
|
|
}
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
base[i].r = colours[2];
|
|
base[i].g = colours[1];
|
|
base[i].b = colours[0];
|
|
base[i].a = 0;
|
|
colours += 4;
|
|
}
|
|
|
|
if (SDL_SetPaletteColors(_palette, base, 0, 256)) {
|
|
RCT2_ERROR("SDL_SetPaletteColors failed %s", SDL_GetError());
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void osinterface_draw()
|
|
{
|
|
// Lock the surface before setting its pixels
|
|
if (SDL_MUSTLOCK(_surface))
|
|
if (SDL_LockSurface(_surface) < 0) {
|
|
RCT2_ERROR("locking failed %s", SDL_GetError());
|
|
return;
|
|
}
|
|
|
|
// Copy pixels from the virtual screen buffer to the surface
|
|
memcpy(_surface->pixels, _screenBuffer, _surface->pitch * _surface->h);
|
|
|
|
// Unlock the surface
|
|
if (SDL_MUSTLOCK(_surface))
|
|
SDL_UnlockSurface(_surface);
|
|
|
|
// Copy the surface to the window
|
|
if (SDL_BlitSurface(_surface, NULL, SDL_GetWindowSurface(_window), NULL)) {
|
|
RCT2_ERROR("SDL_BlitSurface %s", SDL_GetError());
|
|
exit(1);
|
|
}
|
|
if (SDL_UpdateWindowSurface(_window)) {
|
|
RCT2_ERROR("SDL_UpdateWindowSurface %s", SDL_GetError());
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void osinterface_process_messages()
|
|
{
|
|
SDL_Event e;
|
|
|
|
gLastKeyPressed = 0;
|
|
// gCursorState.wheel = 0;
|
|
gCursorState.left &= ~CURSOR_CHANGED;
|
|
gCursorState.middle &= ~CURSOR_CHANGED;
|
|
gCursorState.right &= ~CURSOR_CHANGED;
|
|
gCursorState.old = 0;
|
|
|
|
while (SDL_PollEvent(&e)) {
|
|
switch (e.type) {
|
|
case SDL_QUIT:
|
|
// rct2_finish();
|
|
rct2_quit();
|
|
break;
|
|
case SDL_WINDOWEVENT:
|
|
if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
|
|
osinterface_resize(e.window.data1, e.window.data2);
|
|
break;
|
|
case SDL_MOUSEMOTION:
|
|
RCT2_GLOBAL(0x0142406C, int) = e.motion.x;
|
|
RCT2_GLOBAL(0x01424070, int) = e.motion.y;
|
|
|
|
gCursorState.x = e.motion.x;
|
|
gCursorState.y = e.motion.y;
|
|
break;
|
|
case SDL_MOUSEWHEEL:
|
|
gCursorState.wheel += e.wheel.y * 128;
|
|
break;
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
RCT2_GLOBAL(0x01424318, int) = e.button.x;
|
|
RCT2_GLOBAL(0x0142431C, int) = e.button.y;
|
|
switch (e.button.button) {
|
|
case SDL_BUTTON_LEFT:
|
|
RCT2_CALLPROC_1(0x00406C96, int, 1);
|
|
gCursorState.left = CURSOR_PRESSED;
|
|
gCursorState.old = 1;
|
|
break;
|
|
case SDL_BUTTON_MIDDLE:
|
|
gCursorState.middle = CURSOR_PRESSED;
|
|
break;
|
|
case SDL_BUTTON_RIGHT:
|
|
RCT2_CALLPROC_1(0x00406C96, int, 3);
|
|
gCursorState.right = CURSOR_PRESSED;
|
|
gCursorState.old = 2;
|
|
break;
|
|
}
|
|
break;
|
|
case SDL_MOUSEBUTTONUP:
|
|
RCT2_GLOBAL(0x01424318, int) = e.button.x;
|
|
RCT2_GLOBAL(0x0142431C, int) = e.button.y;
|
|
switch (e.button.button) {
|
|
case SDL_BUTTON_LEFT:
|
|
RCT2_CALLPROC_1(0x00406C96, int, 2);
|
|
gCursorState.left = CURSOR_RELEASED;
|
|
gCursorState.old = 3;
|
|
break;
|
|
case SDL_BUTTON_MIDDLE:
|
|
gCursorState.middle = CURSOR_RELEASED;
|
|
break;
|
|
case SDL_BUTTON_RIGHT:
|
|
RCT2_CALLPROC_1(0x00406C96, int, 4);
|
|
gCursorState.right = CURSOR_RELEASED;
|
|
gCursorState.old = 4;
|
|
break;
|
|
}
|
|
break;
|
|
case SDL_KEYDOWN:
|
|
gLastKeyPressed = e.key.keysym.sym;
|
|
gKeysPressed[e.key.keysym.scancode] = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
gCursorState.any = gCursorState.left | gCursorState.middle | gCursorState.right;
|
|
|
|
// Updates the state of the keys
|
|
int numKeys = 256;
|
|
gKeysState = SDL_GetKeyboardState(&numKeys);
|
|
}
|
|
|
|
static void osinterface_close_window()
|
|
{
|
|
if (_window != NULL)
|
|
SDL_DestroyWindow(_window);
|
|
if (_surface != NULL)
|
|
SDL_FreeSurface(_surface);
|
|
if (_palette != NULL)
|
|
SDL_FreePalette(_palette);
|
|
}
|
|
|
|
void osinterface_free()
|
|
{
|
|
free(gKeysPressed);
|
|
|
|
osinterface_close_window();
|
|
SDL_Quit();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* rct2: 0x004080EA
|
|
*/
|
|
int osinterface_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName)
|
|
{
|
|
char initialDirectory[MAX_PATH], *dotAddress, *slashAddress;
|
|
OPENFILENAME openFileName;
|
|
BOOL result;
|
|
int tmp;
|
|
|
|
// Get directory path from given filename
|
|
strcpy(initialDirectory, filename);
|
|
dotAddress = strrchr(filename, '.');
|
|
if (dotAddress != NULL) {
|
|
slashAddress = strrchr(filename, '\\');
|
|
if (slashAddress < dotAddress)
|
|
*(slashAddress + 1) = 0;
|
|
}
|
|
|
|
// Clear filename
|
|
*filename = 0;
|
|
|
|
// Set open file name options
|
|
memset(&openFileName, 0, sizeof(OPENFILENAME));
|
|
openFileName.lStructSize = sizeof(OPENFILENAME);
|
|
openFileName.hwndOwner = RCT2_GLOBAL(0x009E2D70, HWND);
|
|
openFileName.lpstrFile = filename;
|
|
openFileName.nMaxFile = MAX_PATH;
|
|
openFileName.lpstrInitialDir = initialDirectory;
|
|
openFileName.lpstrTitle = title;
|
|
|
|
// Copy filter name
|
|
strcpy((char*)0x01423800, filterName);
|
|
|
|
// Copy filter pattern
|
|
strcpy((char*)0x01423800 + strlen(filterName) + 1, filterPattern);
|
|
*((char*)(0x01423800 + strlen(filterName) + 1 + strlen(filterPattern) + 1)) = 0;
|
|
openFileName.lpstrFilter = (char*)0x01423800;
|
|
|
|
//
|
|
tmp = RCT2_GLOBAL(0x009E2C74, uint32);
|
|
if (RCT2_GLOBAL(0x009E2BB8, uint32) == 2 && RCT2_GLOBAL(0x009E1AF8, uint32) == 1)
|
|
RCT2_GLOBAL(0x009E2C74, uint32) = 1;
|
|
|
|
// Open dialog
|
|
if (type == 0) {
|
|
openFileName.Flags = OFN_EXPLORER | OFN_CREATEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
|
|
result = GetSaveFileName(&openFileName);
|
|
} else if (type == 1) {
|
|
openFileName.Flags = OFN_EXPLORER | OFN_NONETWORKBUTTON | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
|
|
result = GetOpenFileName(&openFileName);
|
|
}
|
|
|
|
//
|
|
RCT2_GLOBAL(0x009E2C74, uint32) = tmp;
|
|
|
|
return result;
|
|
}
|
|
|
|
void osinterface_show_messagebox(char* message){
|
|
MessageBox(NULL, message, "OpenRCT2", MB_OK);
|
|
}
|
|
|
|
char* osinterface_open_directory_browser(char *title) {
|
|
BROWSEINFO bi;
|
|
char pszBuffer[MAX_PATH];
|
|
LPITEMIDLIST pidl;
|
|
LPMALLOC lpMalloc;
|
|
|
|
// Initialize COM
|
|
if (CoInitializeEx(0, COINIT_APARTMENTTHREADED) != S_OK) {
|
|
MessageBox(NULL, _T("Error opening browse window"), _T("ERROR"), MB_OK);
|
|
CoUninitialize();
|
|
return 0;
|
|
}
|
|
|
|
// Get a pointer to the shell memory allocator
|
|
if (SHGetMalloc(&lpMalloc) != S_OK) {
|
|
MessageBox(NULL, _T("Error opening browse window"), _T("ERROR"), MB_OK);
|
|
CoUninitialize();
|
|
return 0;
|
|
}
|
|
|
|
bi.hwndOwner = NULL;
|
|
bi.pidlRoot = NULL;
|
|
bi.pszDisplayName = pszBuffer;
|
|
bi.lpszTitle = _T(title);
|
|
bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
|
|
bi.lpfn = NULL;
|
|
bi.lParam = 0;
|
|
|
|
char *outPath = "C:\\";
|
|
|
|
if (pidl = SHBrowseForFolder(&bi)) {
|
|
// Copy the path directory to the buffer
|
|
if (SHGetPathFromIDList(pidl, pszBuffer)) {
|
|
// Store pszBuffer (and the path) in the outPath
|
|
outPath = (char*) malloc(strlen(pszBuffer)+1);
|
|
strcpy(outPath, pszBuffer);
|
|
}
|
|
}
|
|
CoUninitialize();
|
|
return outPath;
|
|
}
|
|
|
|
char* osinterface_get_orct2_homefolder()
|
|
{
|
|
char path[260]="";
|
|
|
|
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, path))) { // find home folder
|
|
strcat(path, "\\OpenRCT2");
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
char osinterface_get_path_separator()
|
|
{
|
|
return '\\';
|
|
} |