OpenRCT2/src/osinterface.c

239 lines
6.0 KiB
C

/*****************************************************************************
* Copyright (c) 2014 Ted John
* 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 <SDL.h>
#include <SDL_syswm.h>
#include "addresses.h"
#include "osinterface.h"
#include "rct2.h"
typedef void(*update_palette_func)(char*, int, int);
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 void *_screenBuffer;
void osinterface_init()
{
osinterface_create_window();
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) {
fprintf(stderr, "Error: SDL_Init\n");
exit(-1);
}
// stuff
{
RCT2_CALLPROC_EBPSAFE(0x0068352C);
RCT2_CALLPROC_EBPSAFE(0x0068371D);
width = RCT2_GLOBAL(0x009AB4C2, sint16);
height = RCT2_GLOBAL(0x009AB4C4, 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);
// Get the HWND context
SDL_GetWindowWMInfo(_window, &wmInfo);
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;
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);
SDL_SetSurfacePalette(_surface, _palette);
if (_screenBuffer != NULL)
free(_screenBuffer);
_screenBuffer = malloc(_surface->pitch * _surface->h);
memset(_screenBuffer, 0, _surface->pitch * _surface->h);
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(0x009ABDE4, sint16) = 64;
RCT2_GLOBAL(0x009ABDE6, sint16) = 8;
RCT2_GLOBAL(0x009ABDE8, sint32) = (width >> 6) + 1;
RCT2_GLOBAL(0x009ABDEC, sint32) = (height >> 3) + 1;
RCT2_CALLPROC_EBPSAFE(0x0066B905); // resize_gui()
RCT2_CALLPROC_EBPSAFE(0x006ED7E5); // 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);
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;
}
SDL_SetPaletteColors(_palette, base, 0, 256);
}
void osinterface_draw()
{
// Lock the surface before setting its pixels
if (SDL_MUSTLOCK(_surface))
if (SDL_LockSurface(_surface) < 0)
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
SDL_BlitSurface(_surface, NULL, SDL_GetWindowSurface(_window), NULL);
SDL_UpdateWindowSurface(_window);
}
void osinterface_process_messages()
{
SDL_Event e;
SDL_PollEvent(&e);
switch (e.type) {
case SDL_QUIT:
rct2_finish();
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;
break;
case SDL_MOUSEWHEEL:
RCT2_GLOBAL(0x009E2D80, int) += 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:
((void(*)(int))0x00406C96)(1);
break;
case SDL_BUTTON_MIDDLE:
break;
case SDL_BUTTON_RIGHT:
__asm push ebp
((void(*)(int))0x00406C96)(2);
__asm pop ebp
break;
}
break;
case SDL_MOUSEBUTTONUP:
*((int*)0x01424318) = e.button.x;
*((int*)0x0142431C) = e.button.y;
switch (e.button.button) {
case SDL_BUTTON_LEFT:
((void(*)(int))0x00406C96)(3);
break;
case SDL_BUTTON_MIDDLE:
break;
case SDL_BUTTON_RIGHT:
((void(*)(int))0x00406C96)(4);
break;
}
break;
default:
break;
}
}
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()
{
osinterface_close_window();
SDL_Quit();
}