diff --git a/openrct2.vcxproj b/openrct2.vcxproj index ac1e81d854..7b208884da 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -45,6 +45,7 @@ + @@ -337,6 +338,7 @@ + diff --git a/src/drawing/IDrawingEngine.h b/src/drawing/IDrawingEngine.h index 94edfd8346..16da4f4df6 100644 --- a/src/drawing/IDrawingEngine.h +++ b/src/drawing/IDrawingEngine.h @@ -26,7 +26,13 @@ interface IDrawingEngine virtual void Initialise(SDL_Window * window) abstract; virtual void Resize(uint32 width, uint32 height) abstract; + virtual void SetPalette(SDL_Color * colours) abstract; virtual void Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) abstract; virtual void Draw() abstract; }; + +namespace DrawingEngineFactory +{ + IDrawingEngine * CreateSoftware(); +}; diff --git a/src/drawing/NewDrawing.cpp b/src/drawing/NewDrawing.cpp new file mode 100644 index 0000000000..530694a5c0 --- /dev/null +++ b/src/drawing/NewDrawing.cpp @@ -0,0 +1,72 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/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. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "IDrawingEngine.h" + +extern "C" +{ + #include "../platform/platform.h" +} + +static IDrawingEngine * _drawingEngine = nullptr; + +extern "C" +{ + void drawing_engine_init() + { + assert(_drawingEngine == nullptr); + _drawingEngine = DrawingEngineFactory::CreateSoftware(); + _drawingEngine->Initialise(gWindow); + } + + void drawing_engine_resize() + { + if (_drawingEngine == nullptr) + { + drawing_engine_init(); + } + _drawingEngine->Resize(gScreenWidth, gScreenHeight); + } + + void drawing_engine_set_palette(SDL_Color * colours) + { + _drawingEngine->SetPalette(colours); + } + + void drawing_engine_draw() + { + _drawingEngine->Draw(); + } + + void drawing_engine_dispose() + { + delete _drawingEngine; + _drawingEngine = nullptr; + } + + void gfx_set_dirty_blocks(sint16 left, sint16 top, sint16 right, sint16 bottom) + { + if (_drawingEngine != nullptr) + { + _drawingEngine->Invalidate(left, top, right, bottom); + } + } + + void gfx_draw_all_dirty_blocks() + { + + } +} diff --git a/src/drawing/NewDrawing.h b/src/drawing/NewDrawing.h new file mode 100644 index 0000000000..0e7ece76cb --- /dev/null +++ b/src/drawing/NewDrawing.h @@ -0,0 +1,33 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/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. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#ifdef _cplusplus +extern "C" +{ +#endif + +void drawing_engine_init(); +void drawing_engine_resize(); +void drawing_engine_set_palette(SDL_Color * colours); +void drawing_engine_draw(); +void drawing_engine_dispose(); + +#ifdef _cplusplus +} +#endif + diff --git a/src/drawing/drawing.c b/src/drawing/drawing.c index feabfaf4ba..b76f34f28e 100644 --- a/src/drawing/drawing.c +++ b/src/drawing/drawing.c @@ -201,130 +201,6 @@ void gfx_invalidate_screen() gfx_set_dirty_blocks(0, 0, gScreenWidth, gScreenHeight); } -uint8* gfx_get_dirty_blocks() -{ - int size = _screenDirtyBlockColumns * _screenDirtyBlockRows; - if (_screenDirtyBlocksSize != size) { - if (_screenDirtyBlocks) { - _screenDirtyBlocks = realloc(_screenDirtyBlocks, size); - } else { - _screenDirtyBlocks = malloc(size); - } - _screenDirtyBlocksSize = size; - } - return _screenDirtyBlocks; -} - -/** - * - * rct2: 0x006E732D - * left (ax) - * top (bx) - * right (dx) - * bottom (bp) - */ -void gfx_set_dirty_blocks(sint16 left, sint16 top, sint16 right, sint16 bottom) -{ - int x, y; - uint8 *screenDirtyBlocks = gfx_get_dirty_blocks(); - - left = max(left, 0); - top = max(top, 0); - right = min(right, gScreenWidth); - bottom = min(bottom, gScreenHeight); - - if (left >= right) - return; - if (top >= bottom) - return; - - right--; - bottom--; - - left >>= _screenDirtyBlockShiftX; - right >>= _screenDirtyBlockShiftX; - top >>= _screenDirtyBlockShiftY; - bottom >>= _screenDirtyBlockShiftY; - - uint32 dirtyBlockColumns = _screenDirtyBlockColumns; - for (y = top; y <= bottom; y++) { - uint32 yOffset = y * dirtyBlockColumns; - for (x = left; x <= right; x++) { - screenDirtyBlocks[yOffset + x] = 0xFF; - } - } -} - -/** - * - * rct2: 0x006E73BE - */ -void gfx_draw_all_dirty_blocks() -{ - uint32 x, y, xx, yy, columns, rows; - uint32 dirtyBlockColumns = _screenDirtyBlockColumns; - uint32 dirtyBlockRows = _screenDirtyBlockRows; - uint8 *screenDirtyBlocks = gfx_get_dirty_blocks(); - - for (x = 0; x < dirtyBlockColumns; x++) { - for (y = 0; y < dirtyBlockRows; y++) { - uint32 yOffset = y * dirtyBlockColumns; - if (screenDirtyBlocks[yOffset + x] == 0) { - continue; - } - - // Determine columns - for (xx = x; xx < dirtyBlockColumns; xx++) { - if (screenDirtyBlocks[yOffset + xx] == 0) { - break; - } - } - columns = xx - x; - - // Check rows - for (yy = y; yy < dirtyBlockRows; yy++) { - uint32 yyOffset = yy * dirtyBlockColumns; - for (xx = x; xx < x + columns; xx++) { - if (screenDirtyBlocks[yyOffset + xx] == 0) { - goto endRowCheck; - } - } - } - - endRowCheck: - rows = yy - y; - gfx_draw_dirty_blocks(x, y, columns, rows); - } - } -} - -static void gfx_draw_dirty_blocks(int x, int y, int columns, int rows) -{ - uint32 left, top, right, bottom; - uint32 dirtyBlockColumns = _screenDirtyBlockColumns; - uint8 *screenDirtyBlocks = gfx_get_dirty_blocks(); - - // Unset dirty blocks - for (top = y; top < y + (uint32)rows; top++) { - uint32 topOffset = top * dirtyBlockColumns; - for (left = x; left < x + (uint32)columns; left++) { - screenDirtyBlocks[topOffset + left] = 0; - } - } - - // Determine region in pixels - left = max(0, x * _screenDirtyBlockWidth); - top = max(0, y * _screenDirtyBlockHeight); - right = min((uint32)gScreenWidth, left + (columns * _screenDirtyBlockWidth)); - bottom = min((uint32)gScreenHeight, top + (rows * _screenDirtyBlockHeight)); - if (right <= left || bottom <= top) { - return; - } - - // Draw region - gfx_redraw_screen_rect(left, top, right, bottom); -} - /** * * rct2: 0x006E7499 diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h index 0520da78f7..8980ad85e9 100644 --- a/src/drawing/drawing.h +++ b/src/drawing/drawing.h @@ -191,4 +191,6 @@ int scrolling_text_setup(rct_string_id stringId, uint16 scroll, uint16 scrolling void gfx_configure_dirty_grid(); +#include "NewDrawing.h" + #endif diff --git a/src/drawing/engines/SoftwareDrawingEngine.cpp b/src/drawing/engines/SoftwareDrawingEngine.cpp index 2aabf82050..42c1b02dd3 100644 --- a/src/drawing/engines/SoftwareDrawingEngine.cpp +++ b/src/drawing/engines/SoftwareDrawingEngine.cpp @@ -14,13 +14,13 @@ *****************************************************************************/ #pragma endregion -#include "../../config.h" #include "../../core/Math.hpp" #include "../../core/Memory.hpp" #include "../IDrawingEngine.h" extern "C" { + #include "../../config.h" #include "../drawing.h" } @@ -104,6 +104,22 @@ public: ConfigureBits(width, height, _surface->pitch); } + void SetPalette(SDL_Color * palette) override + { + SDL_Surface * windowSurface = SDL_GetWindowSurface(gWindow); + if (windowSurface == nullptr) + { + log_fatal("SDL_GetWindowSurface failed %s", SDL_GetError()); + exit(1); + } + + if (_palette != nullptr && SDL_SetPaletteColors(_palette, gPalette, 0, 256)) + { + log_fatal("SDL_SetPaletteColors failed %s", SDL_GetError()); + exit(1); + } + } + void Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) override { left = Math::Max(left, 0); @@ -341,3 +357,8 @@ private: } } }; + +IDrawingEngine * DrawingEngineFactory::CreateSoftware() +{ + return new SoftwareDrawingEngine(); +} diff --git a/src/platform/shared.c b/src/platform/shared.c index fd68199744..8f710085ab 100644 --- a/src/platform/shared.c +++ b/src/platform/shared.c @@ -60,16 +60,6 @@ bool gHardwareDisplay; bool gSteamOverlayActive = false; -static SDL_Surface *_surface = NULL; -static SDL_Surface *_RGBASurface = NULL; -static SDL_Palette *_palette = NULL; - -static void *_screenBuffer; -static int _screenBufferSize; -static int _screenBufferWidth; -static int _screenBufferHeight; -static int _screenBufferPitch; - static SDL_Cursor* _cursors[CURSOR_COUNT]; static const int _fullscreen_modes[] = { 0, SDL_WINDOW_FULLSCREEN, SDL_WINDOW_FULLSCREEN_DESKTOP }; static unsigned int _lastGestureTimestamp; @@ -82,8 +72,6 @@ static void platform_create_window(); static void platform_load_cursors(); static void platform_unload_cursors(); -static void platform_refresh_screenbuffer(int width, int height, int pitch); - int resolution_sort_func(const void *pa, const void *pb) { const resolution *a = (resolution*)pa; @@ -219,96 +207,8 @@ static void overlay_post_render_check(int width, int height) { void platform_draw() { - int width = gScreenWidth; - int height = gScreenHeight; - if (!gOpenRCT2Headless) { - if (gHardwareDisplay) { - void *pixels; - int pitch; - if (SDL_LockTexture(gBufferTexture, NULL, &pixels, &pitch) == 0) { - uint8 *src = (uint8*)_screenBuffer; - int padding = pitch - (width * 4); - if (pitch == width * 4) { - uint32 *dst = pixels; - for (int i = width * height; i > 0; i--) { *dst++ = *(uint32 *)(&gPaletteHWMapped[*src++]); } - } - else - if (pitch == (width * 2) + padding) { - uint16 *dst = pixels; - for (int y = height; y > 0; y--) { - for (int x = width; x > 0; x--) { - const uint8 lower = *(uint8 *)(&gPaletteHWMapped[*src++]); - const uint8 upper = *(uint8 *)(&gPaletteHWMapped[*src++]); - *dst++ = (lower << 8) | upper; - } - dst = (uint16*)(((uint8 *)dst) + padding); - } - } - else - if (pitch == width + padding) { - uint8 *dst = pixels; - for (int y = height; y > 0; y--) { - for (int x = width; x > 0; x--) { *dst++ = *(uint8 *)(&gPaletteHWMapped[*src++]); } - dst += padding; - } - } - SDL_UnlockTexture(gBufferTexture); - } - - SDL_RenderCopy(gRenderer, gBufferTexture, NULL, NULL); - - if (gSteamOverlayActive && gConfigGeneral.steam_overlay_pause) { - overlay_pre_render_check(width, height); - } - - SDL_RenderPresent(gRenderer); - - if (gSteamOverlayActive && gConfigGeneral.steam_overlay_pause) { - overlay_post_render_check(width, height); - } - } - else { - // Lock the surface before setting its pixels - if (SDL_MUSTLOCK(_surface)) { - if (SDL_LockSurface(_surface) < 0) { - log_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 (gConfigGeneral.window_scale == 1 || gConfigGeneral.window_scale <= 0) - { - if (SDL_BlitSurface(_surface, NULL, SDL_GetWindowSurface(gWindow), NULL)) { - log_fatal("SDL_BlitSurface %s", SDL_GetError()); - exit(1); - } - } else { - // first blit to rgba surface to change the pixel format - if (SDL_BlitSurface(_surface, NULL, _RGBASurface, NULL)) { - log_fatal("SDL_BlitSurface %s", SDL_GetError()); - exit(1); - } - // then scale to window size. Without changing to RGBA first, SDL complains - // about blit configurations being incompatible. - if (SDL_BlitScaled(_RGBASurface, NULL, SDL_GetWindowSurface(gWindow), NULL)) { - log_fatal("SDL_BlitScaled %s", SDL_GetError()); - exit(1); - } - } - if (SDL_UpdateWindowSurface(gWindow)) { - log_fatal("SDL_UpdateWindowSurface %s", SDL_GetError()); - exit(1); - } - } + drawing_engine_draw(); } } @@ -321,7 +221,7 @@ static void platform_resize(int width, int height) gScreenWidth = dst_w; gScreenHeight = dst_h; - platform_refresh_video(); + drawing_engine_resize(); flags = SDL_GetWindowFlags(gWindow); @@ -392,11 +292,9 @@ static uint8 lerp(uint8 a, uint8 b, float t) void platform_update_palette(const uint8* colours, int start_index, int num_colours) { - SDL_Surface *surface; - int i; colours += start_index * 4; - for (i = start_index; i < num_colours + start_index; i++) { + for (int i = start_index; i < num_colours + start_index; i++) { gPalette[i].r = colours[2]; gPalette[i].g = colours[1]; gPalette[i].b = colours[0]; @@ -416,16 +314,7 @@ void platform_update_palette(const uint8* colours, int start_index, int num_colo } if (!gOpenRCT2Headless && !gHardwareDisplay) { - surface = SDL_GetWindowSurface(gWindow); - if (!surface) { - log_fatal("SDL_GetWindowSurface failed %s", SDL_GetError()); - exit(1); - } - - if (_palette != NULL && SDL_SetPaletteColors(_palette, gPalette, 0, 256)) { - log_fatal("SDL_SetPaletteColors failed %s", SDL_GetError()); - exit(1); - } + drawing_engine_set_palette(gPalette); } } @@ -528,15 +417,15 @@ void platform_process_messages() // Apple sends touchscreen events for trackpads, so ignore these events on OS X #ifndef __MACOSX__ case SDL_FINGERMOTION: - RCT2_GLOBAL(0x0142406C, int) = (int)(e.tfinger.x * _screenBufferWidth); - RCT2_GLOBAL(0x01424070, int) = (int)(e.tfinger.y * _screenBufferHeight); + RCT2_GLOBAL(0x0142406C, int) = (int)(e.tfinger.x * gScreenWidth); + RCT2_GLOBAL(0x01424070, int) = (int)(e.tfinger.y * gScreenHeight); - gCursorState.x = (int)(e.tfinger.x * _screenBufferWidth); - gCursorState.y = (int)(e.tfinger.y * _screenBufferHeight); + gCursorState.x = (int)(e.tfinger.x * gScreenWidth); + gCursorState.y = (int)(e.tfinger.y * gScreenHeight); break; case SDL_FINGERDOWN: - RCT2_GLOBAL(0x01424318, int) = (int)(e.tfinger.x * _screenBufferWidth); - RCT2_GLOBAL(0x0142431C, int) = (int)(e.tfinger.y * _screenBufferHeight); + RCT2_GLOBAL(0x01424318, int) = (int)(e.tfinger.x * gScreenWidth); + RCT2_GLOBAL(0x0142431C, int) = (int)(e.tfinger.y * gScreenHeight); gCursorState.touchIsDouble = (!gCursorState.touchIsDouble && e.tfinger.timestamp - gCursorState.touchDownTimestamp < TOUCH_DOUBLE_TIMEOUT); @@ -554,8 +443,8 @@ void platform_process_messages() gCursorState.touchDownTimestamp = e.tfinger.timestamp; break; case SDL_FINGERUP: - RCT2_GLOBAL(0x01424318, int) = (int)(e.tfinger.x * _screenBufferWidth); - RCT2_GLOBAL(0x0142431C, int) = (int)(e.tfinger.y * _screenBufferHeight); + RCT2_GLOBAL(0x01424318, int) = (int)(e.tfinger.x * gScreenWidth); + RCT2_GLOBAL(0x0142431C, int) = (int)(e.tfinger.y * gScreenHeight); if (gCursorState.touchIsDouble) { store_mouse_input(4); @@ -703,14 +592,7 @@ void platform_process_messages() static void platform_close_window() { - if (gWindow != NULL) - SDL_DestroyWindow(gWindow); - if (_surface != NULL) - SDL_FreeSurface(_surface); - if (_palette != NULL) - SDL_FreePalette(_palette); - if (_RGBASurface != NULL) - SDL_FreeSurface(_RGBASurface); + drawing_engine_dispose(); platform_unload_cursors(); } @@ -920,114 +802,6 @@ void platform_refresh_video() log_verbose("HardwareDisplay: %s", gHardwareDisplay ? "true" : "false"); - if (gHardwareDisplay) { - if (gRenderer == NULL) - gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - - if (gRenderer == NULL) { - log_warning("SDL_CreateRenderer failed: %s", SDL_GetError()); - log_warning("Falling back to software rendering..."); - gHardwareDisplay = false; - platform_refresh_video(); // try again without hardware rendering - return; - } - - if (gBufferTexture != NULL) - SDL_DestroyTexture(gBufferTexture); - - if (gBufferTextureFormat != NULL) - SDL_FreeFormat(gBufferTextureFormat); - - SDL_RendererInfo rendererinfo; - SDL_GetRendererInfo(gRenderer, &rendererinfo); - Uint32 pixelformat = SDL_PIXELFORMAT_UNKNOWN; - for(unsigned int i = 0; i < rendererinfo.num_texture_formats; i++){ - Uint32 format = rendererinfo.texture_formats[i]; - if(!SDL_ISPIXELFORMAT_FOURCC(format) && !SDL_ISPIXELFORMAT_INDEXED(format) && (pixelformat == SDL_PIXELFORMAT_UNKNOWN || SDL_BYTESPERPIXEL(format) < SDL_BYTESPERPIXEL(pixelformat))){ - pixelformat = format; - } - } - - gBufferTexture = SDL_CreateTexture(gRenderer, pixelformat, SDL_TEXTUREACCESS_STREAMING, width, height); - Uint32 format; - SDL_QueryTexture(gBufferTexture, &format, 0, 0, 0); - gBufferTextureFormat = SDL_AllocFormat(format); - platform_refresh_screenbuffer(width, height, width); - // Load the current palette into the HWmapped version. - for (int i = 0; i < 256; ++i) { - gPaletteHWMapped[i] = SDL_MapRGB(gBufferTextureFormat, gPalette[i].r, gPalette[i].g, gPalette[i].b); - } - } else { - if (_surface != NULL) - SDL_FreeSurface(_surface); - if (_RGBASurface != NULL) - SDL_FreeSurface(_RGBASurface); - if (_palette != NULL) - SDL_FreePalette(_palette); - - _surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0); - _RGBASurface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0); - SDL_SetSurfaceBlendMode(_RGBASurface, SDL_BLENDMODE_NONE); - _palette = SDL_AllocPalette(256); - - if (!_surface || !_palette || !_RGBASurface) { - log_fatal("%p || %p || %p == NULL %s", _surface, _palette, _RGBASurface, SDL_GetError()); - exit(-1); - } - - if (SDL_SetSurfacePalette(_surface, _palette)) { - log_fatal("SDL_SetSurfacePalette failed %s", SDL_GetError()); - exit(-1); - } - - platform_refresh_screenbuffer(width, height, _surface->pitch); - } -} - -static void platform_refresh_screenbuffer(int width, int height, int pitch) -{ - int newScreenBufferSize = pitch * height; - char *newScreenBuffer = (char*)malloc(newScreenBufferSize); - if (_screenBuffer == NULL) { - memset(newScreenBuffer, 0, newScreenBufferSize); - } else { - if (_screenBufferPitch == pitch) { - memcpy(newScreenBuffer, _screenBuffer, min(_screenBufferSize, newScreenBufferSize)); - } else { - char *src = _screenBuffer; - char *dst = newScreenBuffer; - - int minWidth = min(_screenBufferWidth, width); - int minHeight = min(_screenBufferHeight, height); - for (int y = 0; y < minHeight; y++) { - memcpy(dst, src, minWidth); - if (pitch - minWidth > 0) - memset(dst + minWidth, 0, pitch - minWidth); - - src += _screenBufferPitch; - dst += pitch; - } - } - //if (newScreenBufferSize - _screenBufferSize > 0) - // memset((uint8*)newScreenBuffer + _screenBufferSize, 0, newScreenBufferSize - _screenBufferSize); - free(_screenBuffer); - } - - _screenBuffer = newScreenBuffer; - _screenBufferSize = newScreenBufferSize; - _screenBufferWidth = width; - _screenBufferHeight = height; - _screenBufferPitch = pitch; - - rct_drawpixelinfo *screenDPI = &gScreenDPI; - screenDPI->bits = _screenBuffer; - screenDPI->x = 0; - screenDPI->y = 0; - screenDPI->width = width; - screenDPI->height = height; - screenDPI->pitch = _screenBufferPitch - width; - - gfx_configure_dirty_grid(); } void platform_hide_cursor()