From 39b3ff025165ccb026d6d114057baeb6b95e9807 Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 8 Jun 2017 21:56:39 +0100 Subject: [PATCH 1/6] Create new 8bpp drawing engine in openrct2 --- src/openrct2/drawing/X8DrawingEngine.cpp | 734 +++++++++++++++++++++++ src/openrct2/drawing/X8DrawingEngine.h | 128 ++++ 2 files changed, 862 insertions(+) create mode 100644 src/openrct2/drawing/X8DrawingEngine.cpp create mode 100644 src/openrct2/drawing/X8DrawingEngine.h diff --git a/src/openrct2/drawing/X8DrawingEngine.cpp b/src/openrct2/drawing/X8DrawingEngine.cpp new file mode 100644 index 0000000000..bd38a586ae --- /dev/null +++ b/src/openrct2/drawing/X8DrawingEngine.cpp @@ -0,0 +1,734 @@ +#pragma region Copyright (c) 2014-2017 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 "../config/Config.h" +#include "../Context.h" +#include "../ui/UiContext.h" +#include "../core/Guard.hpp" +#include "../core/Math.hpp" +#include "../core/Memory.hpp" +#include "IDrawingContext.h" +#include "IDrawingEngine.h" +#include "Rain.h" +#include "X8DrawingEngine.h" + +extern "C" +{ + #include "../game.h" + #include "../interface/screenshot.h" + #include "../interface/viewport.h" + #include "../interface/window.h" + #include "../intro.h" + #include "../platform/platform.h" + #include "../rct2.h" + #include "drawing.h" +} + +using namespace OpenRCT2; +using namespace OpenRCT2::Drawing; +using namespace OpenRCT2::Ui; + +X8RainDrawer::X8RainDrawer() +{ + _rainPixels = new RainPixel[_rainPixelsCapacity]; +} + +X8RainDrawer::~X8RainDrawer() +{ + delete [] _rainPixels; +} + +void X8RainDrawer::SetDPI(rct_drawpixelinfo * dpi) +{ + _screenDPI = dpi; +} + +void X8RainDrawer::Draw(sint32 x, sint32 y, sint32 width, sint32 height, sint32 xStart, sint32 yStart) +{ + static const uint8 RainPattern[] = + { + 32, 32, 0, 12, 0, 14, 0, 16, 255, 0, 255, 0, 255, 0, 255, 0, 255, + 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, + 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, + 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 0, 0 + }; + + const uint8 * pattern = RainPattern; + uint8 patternXSpace = *pattern++; + uint8 patternYSpace = *pattern++; + + uint8 patternStartXOffset = xStart % patternXSpace; + uint8 patternStartYOffset = yStart % patternYSpace; + + uint32 pixelOffset = (_screenDPI->pitch + _screenDPI->width) * y + x; + uint8 patternYPos = patternStartYOffset % patternYSpace; + + uint8 * screenBits = _screenDPI->bits; + + //Stores the colours of changed pixels + RainPixel * newPixels = &_rainPixels[_rainPixelsCount]; + for (; height != 0; height--) + { + uint8 patternX = pattern[patternYPos * 2]; + if (patternX != 0xFF) + { + if (_rainPixelsCount < (_rainPixelsCapacity - (uint32)width)) + { + uint32 finalPixelOffset = width + pixelOffset; + + uint32 xPixelOffset = pixelOffset; + xPixelOffset += ((uint8)(patternX - patternStartXOffset)) % patternXSpace; + + uint8 patternPixel = pattern[patternYPos * 2 + 1]; + for (; xPixelOffset < finalPixelOffset; xPixelOffset += patternXSpace) + { + uint8 current_pixel = screenBits[xPixelOffset]; + screenBits[xPixelOffset] = patternPixel; + _rainPixelsCount++; + + // Store colour and position + *newPixels++ = { xPixelOffset, current_pixel }; + } + } + } + + pixelOffset += _screenDPI->pitch + _screenDPI->width; + patternYPos++; + patternYPos %= patternYSpace; + } +} + +void X8RainDrawer::Restore() +{ + if (_rainPixelsCount > 0) + { + uint32 numPixels = (_screenDPI->width + _screenDPI->pitch) * _screenDPI->height; + uint8 * bits = _screenDPI->bits; + for (uint32 i = 0; i < _rainPixelsCount; i++) + { + RainPixel rainPixel = _rainPixels[i]; + if (rainPixel.Position >= numPixels) + { + // Pixel out of bounds, bail + break; + } + + bits[rainPixel.Position] = rainPixel.Colour; + } + _rainPixelsCount = 0; + } +} + +X8DrawingEngine::X8DrawingEngine() +{ + _drawingContext = new X8DrawingContext(this); +} + +X8DrawingEngine::~X8DrawingEngine() +{ + delete _drawingContext; + delete [] _dirtyGrid.Blocks; + delete [] _bits; +} + +void X8DrawingEngine::Initialise(SDL_Window * window) +{ +} + +void X8DrawingEngine::Resize(uint32 width, uint32 height) +{ + uint32 pitch = width; + ConfigureBits(width, height, pitch); +} + +void X8DrawingEngine::SetPalette(const rct_palette_entry * palette) +{ +} + +void X8DrawingEngine::SetUncappedFrameRate(bool uncapped) +{ + // Not applicable for this engine +} + +void X8DrawingEngine::Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) +{ + left = Math::Max(left, 0); + top = Math::Max(top, 0); + right = Math::Min(right, (sint32)_width); + bottom = Math::Min(bottom, (sint32)_height); + + if (left >= right) return; + if (top >= bottom) return; + + right--; + bottom--; + + left >>= _dirtyGrid.BlockShiftX; + right >>= _dirtyGrid.BlockShiftX; + top >>= _dirtyGrid.BlockShiftY; + bottom >>= _dirtyGrid.BlockShiftY; + + uint32 dirtyBlockColumns = _dirtyGrid.BlockColumns; + uint8 * screenDirtyBlocks = _dirtyGrid.Blocks; + for (sint16 y = top; y <= bottom; y++) + { + uint32 yOffset = y * dirtyBlockColumns; + for (sint16 x = left; x <= right; x++) + { + screenDirtyBlocks[yOffset + x] = 0xFF; + } + } +} + +void X8DrawingEngine::Draw() +{ + if (gIntroState != INTRO_STATE_NONE) + { + intro_draw(&_bitsDPI); + } + else + { + _rainDrawer.SetDPI(&_bitsDPI); + _rainDrawer.Restore(); + + ResetWindowVisbilities(); + + // Redraw dirty regions before updating the viewports, otherwise + // when viewports get panned, they copy dirty pixels + DrawAllDirtyBlocks(); + + window_update_all_viewports(); + DrawAllDirtyBlocks(); + window_update_all(); + + gfx_draw_pickedup_peep(&_bitsDPI); + gfx_invalidate_pickedup_peep(); + + DrawRain(&_bitsDPI, &_rainDrawer); + + rct2_draw(&_bitsDPI); + } +} + +void X8DrawingEngine::CopyRect(sint32 x, sint32 y, sint32 width, sint32 height, sint32 dx, sint32 dy) +{ + if (dx == 0 && dy == 0) return; + + // Originally 0x00683359 + // Adjust for move off screen + // NOTE: when zooming, there can be x, y, dx, dy combinations that go off the + // screen; hence the checks. This code should ultimately not be called when + // zooming because this function is specific to updating the screen on move + sint32 lmargin = Math::Min(x - dx, 0); + sint32 rmargin = Math::Min((sint32)_width - (x - dx + width), 0); + sint32 tmargin = Math::Min(y - dy, 0); + sint32 bmargin = Math::Min((sint32)_height - (y - dy + height), 0); + x -= lmargin; + y -= tmargin; + width += lmargin + rmargin; + height += tmargin + bmargin; + + sint32 stride = _bitsDPI.width + _bitsDPI.pitch; + uint8 * to = _bitsDPI.bits + y * stride + x; + uint8 * from = _bitsDPI.bits + (y - dy) * stride + x - dx; + + if (dy > 0) + { + // If positive dy, reverse directions + to += (height - 1) * stride; + from += (height - 1) * stride; + stride = -stride; + } + + // Move bytes + for (sint32 i = 0; i < height; i++) + { + memmove(to, from, width); + to += stride; + from += stride; + } +} + +sint32 X8DrawingEngine::Screenshot() +{ + return screenshot_dump_png(&_bitsDPI); +} + +IDrawingContext * X8DrawingEngine::GetDrawingContext(rct_drawpixelinfo * dpi) +{ + _drawingContext->SetDPI(dpi); + return _drawingContext; +} + +rct_drawpixelinfo * X8DrawingEngine::GetDrawingPixelInfo() +{ + return &_bitsDPI; +} + +DRAWING_ENGINE_FLAGS X8DrawingEngine::GetFlags() +{ + return DEF_DIRTY_OPTIMISATIONS; +} + +void X8DrawingEngine::InvalidateImage(uint32 image) +{ + // Not applicable for this engine +} + +rct_drawpixelinfo * X8DrawingEngine::GetDPI() +{ + return &_bitsDPI; +} + +void X8DrawingEngine::ConfigureBits(uint32 width, uint32 height, uint32 pitch) +{ + size_t newBitsSize = pitch * height; + uint8 * newBits = new uint8[newBitsSize]; + if (_bits == nullptr) + { + Memory::Set(newBits, 0, newBitsSize); + } + else + { + if (_pitch == pitch) + { + Memory::Copy(newBits, _bits, Math::Min(_bitsSize, newBitsSize)); + } + else + { + uint8 * src = _bits; + uint8 * dst = newBits; + + uint32 minWidth = Math::Min(_width, width); + uint32 minHeight = Math::Min(_height, height); + for (uint32 y = 0; y < minHeight; y++) + { + Memory::Copy(dst, src, minWidth); + if (pitch - minWidth > 0) + { + Memory::Set(dst + minWidth, 0, pitch - minWidth); + } + src += _pitch; + dst += pitch; + } + } + delete [] _bits; + } + + _bits = newBits; + _bitsSize = newBitsSize; + _width = width; + _height = height; + _pitch = pitch; + + rct_drawpixelinfo * dpi = &_bitsDPI; + dpi->bits = _bits; + dpi->x = 0; + dpi->y = 0; + dpi->width = width; + dpi->height = height; + dpi->pitch = _pitch - width; + + ConfigureDirtyGrid(); +} + +void X8DrawingEngine::ConfigureDirtyGrid() +{ + _dirtyGrid.BlockShiftX = 7; + _dirtyGrid.BlockShiftY = 6; + _dirtyGrid.BlockWidth = 1 << _dirtyGrid.BlockShiftX; + _dirtyGrid.BlockHeight = 1 << _dirtyGrid.BlockShiftY; + _dirtyGrid.BlockColumns = (_width >> _dirtyGrid.BlockShiftX) + 1; + _dirtyGrid.BlockRows = (_height >> _dirtyGrid.BlockShiftY) + 1; + + delete [] _dirtyGrid.Blocks; + _dirtyGrid.Blocks = new uint8[_dirtyGrid.BlockColumns * _dirtyGrid.BlockRows]; +} + +void X8DrawingEngine::ResetWindowVisbilities() +{ + // reset window visibility status to unknown + for (rct_window *w = g_window_list; w < gWindowNextSlot; w++) + { + w->visibility = VC_UNKNOWN; + if (w->viewport != NULL) w->viewport->visibility = VC_UNKNOWN; + } +} + +void X8DrawingEngine::DrawAllDirtyBlocks() +{ + uint32 dirtyBlockColumns = _dirtyGrid.BlockColumns; + uint32 dirtyBlockRows = _dirtyGrid.BlockRows; + uint8 * dirtyBlocks = _dirtyGrid.Blocks; + + for (uint32 x = 0; x < dirtyBlockColumns; x++) + { + for (uint32 y = 0; y < dirtyBlockRows; y++) + { + uint32 yOffset = y * dirtyBlockColumns; + if (dirtyBlocks[yOffset + x] == 0) + { + continue; + } + + // Determine columns + uint32 xx; + for (xx = x; xx < dirtyBlockColumns; xx++) + { + if (dirtyBlocks[yOffset + xx] == 0) + { + break; + } + } + uint32 columns = xx - x; + + // Check rows + uint32 yy; + for (yy = y; yy < dirtyBlockRows; yy++) + { + uint32 yyOffset = yy * dirtyBlockColumns; + for (xx = x; xx < x + columns; xx++) + { + if (dirtyBlocks[yyOffset + xx] == 0) + { + goto endRowCheck; + } + } + } + + endRowCheck: + uint32 rows = yy - y; + DrawDirtyBlocks(x, y, columns, rows); + } + } +} + +void X8DrawingEngine::DrawDirtyBlocks(uint32 x, uint32 y, uint32 columns, uint32 rows) +{ + uint32 dirtyBlockColumns = _dirtyGrid.BlockColumns; + uint8 * screenDirtyBlocks = _dirtyGrid.Blocks; + + // Unset dirty blocks + for (uint32 top = y; top < y + (uint32)rows; top++) + { + uint32 topOffset = top * dirtyBlockColumns; + for (uint32 left = x; left < x + (uint32)columns; left++) + { + screenDirtyBlocks[topOffset + left] = 0; + } + } + + // Determine region in pixels + uint32 left = Math::Max(0, x * _dirtyGrid.BlockWidth); + uint32 top = Math::Max(0, y * _dirtyGrid.BlockHeight); + uint32 right = Math::Min(_width, left + (columns * _dirtyGrid.BlockWidth)); + uint32 bottom = Math::Min(_height, top + (rows * _dirtyGrid.BlockHeight)); + if (right <= left || bottom <= top) + { + return; + } + + // Draw region + window_draw_all(&_bitsDPI, left, top, right, bottom); +} + +X8DrawingContext::X8DrawingContext(X8DrawingEngine * engine) +{ + _engine = engine; +} + +X8DrawingContext::~X8DrawingContext() +{ + +} + +IDrawingEngine * X8DrawingContext::GetEngine() +{ + return _engine; +} + +void X8DrawingContext::Clear(uint8 paletteIndex) +{ + rct_drawpixelinfo * dpi = _dpi; + + sint32 w = dpi->width >> dpi->zoom_level; + sint32 h = dpi->height >> dpi->zoom_level; + uint8 * ptr = dpi->bits; + + for (sint32 y = 0; y < h; y++) + { + Memory::Set(ptr, paletteIndex, w); + ptr += w + dpi->pitch; + } +} + +/** rct2: 0x0097FF04 */ +static const uint16 Pattern[] = { + 0b0111111110000000, + 0b0011111111000000, + 0b0001111111100000, + 0b0000111111110000, + 0b0000011111111000, + 0b0000001111111100, + 0b0000000111111110, + 0b0000000011111111, + 0b1000000001111111, + 0b1100000000111111, + 0b1110000000011111, + 0b1111000000001111, + 0b1111100000000111, + 0b1111110000000011, + 0b1111111000000001, + 0b1111111100000000, +}; + +/** rct2: 0x0097FF14 */ +static const uint16 PatternInverse[] = { + 0b1000000001111111, + 0b1100000000111111, + 0b1110000000011111, + 0b1111000000001111, + 0b1111100000000111, + 0b1111110000000011, + 0b1111111000000001, + 0b1111111100000000, + 0b0111111110000000, + 0b0011111111000000, + 0b0001111111100000, + 0b0000111111110000, + 0b0000011111111000, + 0b0000001111111100, + 0b0000000111111110, + 0b0000000011111111 +}; + +/** rct2: 0x0097FEFC */ +static const uint16 * Patterns[] = { + Pattern, + PatternInverse +}; + +void X8DrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint32 right, sint32 bottom) +{ + rct_drawpixelinfo * dpi = _dpi; + + if (left > right) return; + if (top > bottom) return; + if (dpi->x > right) return; + if (left >= dpi->x + dpi->width) return; + if (bottom < dpi->y) return; + if (top >= dpi->y + dpi->height) return; + + uint16 crossPattern = 0; + + sint32 startX = left - dpi->x; + if (startX < 0) + { + crossPattern ^= startX; + startX = 0; + } + + sint32 endX = right - dpi->x + 1; + if (endX > dpi->width) + { + endX = dpi->width; + } + + sint32 startY = top - dpi->y; + if (startY < 0) + { + crossPattern ^= startY; + startY = 0; + } + + sint32 endY = bottom - dpi->y + 1; + if (endY > dpi->height) + { + endY = dpi->height; + } + + sint32 width = endX - startX; + sint32 height = endY - startY; + + if (colour & 0x1000000) + { + // Cross hatching + uint8 * dst = (startY * (dpi->width + dpi->pitch)) + startX + dpi->bits; + for (sint32 i = 0; i < height; i++) + { + uint8 * nextdst = dst + dpi->width + dpi->pitch; + uint32 p = ror32(crossPattern, 1); + p = (p & 0xFFFF0000) | width; + + // Fill every other pixel with the colour + for (; (p & 0xFFFF) != 0; p--) + { + p = p ^ 0x80000000; + if (p & 0x80000000) + { + *dst = colour & 0xFF; + } + dst++; + } + crossPattern ^= 1; + dst = nextdst; + } + } + else if (colour & 0x2000000) + { + assert(false); + } + else if (colour & 0x4000000) + { + uint8 * dst = startY * (dpi->width + dpi->pitch) + startX + dpi->bits; + + // The pattern loops every 15 lines this is which + // part the pattern is on. + sint32 patternY = (startY + dpi->y) % 16; + + // The pattern loops every 15 pixels this is which + // part the pattern is on. + sint32 startPatternX = (startX + dpi->x) % 16; + sint32 patternX = startPatternX; + + const uint16 * patternsrc = Patterns[colour >> 28]; // or possibly uint8)[esi*4] ? + + for (sint32 numLines = height; numLines > 0; numLines--) + { + uint8 * nextdst = dst + dpi->width + dpi->pitch; + uint16 pattern = patternsrc[patternY]; + + for (sint32 numPixels = width; numPixels > 0; numPixels--) + { + if (pattern & (1 << patternX)) + { + *dst = colour & 0xFF; + } + patternX = (patternX + 1) % 16; + dst++; + } + patternX = startPatternX; + patternY = (patternY + 1) % 16; + dst = nextdst; + } + } + else + { + uint8 * dst = startY * (dpi->width + dpi->pitch) + startX + dpi->bits; + for (sint32 i = 0; i < height; i++) + { + Memory::Set(dst, colour & 0xFF, width); + dst += dpi->width + dpi->pitch; + } + } +} + +void X8DrawingContext::FilterRect(FILTER_PALETTE_ID palette, sint32 left, sint32 top, sint32 right, sint32 bottom) +{ + rct_drawpixelinfo * dpi = _dpi; + + if (left > right) return; + if (top > bottom) return; + if (dpi->x > right) return; + if (left >= dpi->x + dpi->width) return; + if (bottom < dpi->y) return; + if (top >= dpi->y + dpi->height) return; + + sint32 startX = left - dpi->x; + if (startX < 0) + { + startX = 0; + } + + sint32 endX = right - dpi->x + 1; + if (endX > dpi->width) + { + endX = dpi->width; + } + + sint32 startY = top - dpi->y; + if (startY < 0) + { + startY = 0; + } + + sint32 endY = bottom - dpi->y + 1; + if (endY > dpi->height) + { + endY = dpi->height; + } + + sint32 width = endX - startX; + sint32 height = endY - startY; + + + //0x2000000 + // 00678B7E 00678C83 + // Location in screen buffer? + uint8 * dst = dpi->bits + (uint32)((startY >> (dpi->zoom_level)) * ((dpi->width >> dpi->zoom_level) + dpi->pitch) + (startX >> dpi->zoom_level)); + + // Find colour in colour table? + uint16 g1Index = palette_to_g1_offset[palette]; + rct_g1_element * g1Element = &g1Elements[g1Index]; + uint8 * g1Bits = g1Element->offset; + + // Fill the rectangle with the colours from the colour table + for (sint32 i = 0; i < height >> dpi->zoom_level; i++) + { + uint8 * nextdst = dst + (dpi->width >> dpi->zoom_level) + dpi->pitch; + for (sint32 j = 0; j < (width >> dpi->zoom_level); j++) + { + *dst = g1Bits[*dst]; + dst++; + } + dst = nextdst; + } +} + +void X8DrawingContext::DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 x2, sint32 y2) +{ + gfx_draw_line_software(_dpi, x1, y1, x2, y2, colour); +} + +void X8DrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 tertiaryColour) +{ + gfx_draw_sprite_software(_dpi, image, x, y, tertiaryColour); +} + +void X8DrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskImage, uint32 colourImage) +{ + gfx_draw_sprite_raw_masked_software(_dpi, x, y, maskImage, colourImage); +} + +void X8DrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) +{ + uint8 palette[256]; + memset(palette, colour, 256); + palette[0] = 0; + + image &= 0x7FFFF; + gfx_draw_sprite_palette_set_software(_dpi, image | 0x20000000, x, y, palette, nullptr); +} + +void X8DrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette) +{ + gfx_draw_sprite_palette_set_software(_dpi, image, x, y, palette, nullptr); +} + +void X8DrawingContext::SetDPI(rct_drawpixelinfo * dpi) +{ + _dpi = dpi; +} diff --git a/src/openrct2/drawing/X8DrawingEngine.h b/src/openrct2/drawing/X8DrawingEngine.h new file mode 100644 index 0000000000..dbca408c73 --- /dev/null +++ b/src/openrct2/drawing/X8DrawingEngine.h @@ -0,0 +1,128 @@ +#pragma region Copyright (c) 2014-2017 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 + +#include "../common.h" +#include "IDrawingContext.h" +#include "IDrawingEngine.h" + +namespace OpenRCT2 { namespace Drawing +{ + class X8DrawingContext; + + struct DirtyGrid + { + uint32 BlockShiftX; + uint32 BlockShiftY; + uint32 BlockWidth; + uint32 BlockHeight; + uint32 BlockColumns; + uint32 BlockRows; + uint8 * Blocks; + }; + + class X8RainDrawer final : public IRainDrawer + { + private: + struct RainPixel + { + uint32 Position; + uint8 Colour; + }; + + static constexpr uint32 MaxRainPixels = 0xFFFE; + + size_t _rainPixelsCapacity = MaxRainPixels; + uint32 _rainPixelsCount = 0; + RainPixel * _rainPixels = nullptr; + rct_drawpixelinfo * _screenDPI = nullptr; + + public: + X8RainDrawer(); + ~X8RainDrawer(); + void SetDPI(rct_drawpixelinfo * dpi); + void Draw(sint32 x, sint32 y, sint32 width, sint32 height, sint32 xStart, sint32 yStart) override; + void Restore(); + }; + + class X8DrawingEngine final : public IDrawingEngine + { + private: + uint32 _width = 0; + uint32 _height = 0; + uint32 _pitch = 0; + size_t _bitsSize = 0; + uint8 * _bits = nullptr; + + DirtyGrid _dirtyGrid = { 0 }; + + rct_drawpixelinfo _bitsDPI = { 0 }; + + X8RainDrawer _rainDrawer; + X8DrawingContext * _drawingContext; + + public: + explicit X8DrawingEngine(); + ~X8DrawingEngine() override; + + void Initialise(SDL_Window * window) override; + void Resize(uint32 width, uint32 height) override; + void SetPalette(const rct_palette_entry * palette) override; + void SetUncappedFrameRate(bool uncapped) override; + void Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) override; + void Draw() override; + void CopyRect(sint32 x, sint32 y, sint32 width, sint32 height, sint32 dx, sint32 dy) override; + sint32 Screenshot() override; + IDrawingContext * GetDrawingContext(rct_drawpixelinfo * dpi) override; + rct_drawpixelinfo * GetDrawingPixelInfo() override; + DRAWING_ENGINE_FLAGS GetFlags() override; + void InvalidateImage(uint32 image) override; + + rct_drawpixelinfo * GetDPI(); + + private: + void ConfigureBits(uint32 width, uint32 height, uint32 pitch); + void ConfigureDirtyGrid(); + static void ResetWindowVisbilities(); + void DrawAllDirtyBlocks(); + void DrawDirtyBlocks(uint32 x, uint32 y, uint32 columns, uint32 rows); + }; + + class X8DrawingContext final : public IDrawingContext + { + private: + X8DrawingEngine * _engine = nullptr; + rct_drawpixelinfo * _dpi = nullptr; + + public: + explicit X8DrawingContext(X8DrawingEngine * engine); + ~X8DrawingContext() override; + + IDrawingEngine * GetEngine() override; + + void Clear(uint8 paletteIndex) override; + void FillRect(uint32 colour, sint32 x, sint32 y, sint32 w, sint32 h) override; + void FilterRect(FILTER_PALETTE_ID palette, sint32 left, sint32 top, sint32 right, sint32 bottom) override; + void DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 x2, sint32 y2) override; + void DrawSprite(uint32 image, sint32 x, sint32 y, uint32 tertiaryColour) override; + void DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskImage, uint32 colourImage) override; + void DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) override; + void DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette) override; + + void SetDPI(rct_drawpixelinfo * dpi); + }; +} } From df16e6a4f751767f01fd910dd9141f260eed9998 Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 8 Jun 2017 22:14:19 +0100 Subject: [PATCH 2/6] Inherit X8 engine from software engine --- .../drawing/engines/SoftwareDrawingEngine.cpp | 755 +----------------- src/openrct2/drawing/X8DrawingEngine.cpp | 19 + src/openrct2/drawing/X8DrawingEngine.h | 12 +- 3 files changed, 31 insertions(+), 755 deletions(-) diff --git a/src/openrct2-ui/drawing/engines/SoftwareDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/SoftwareDrawingEngine.cpp index 5e8eff2d15..e5781e5350 100644 --- a/src/openrct2-ui/drawing/engines/SoftwareDrawingEngine.cpp +++ b/src/openrct2-ui/drawing/engines/SoftwareDrawingEngine.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "DrawingEngines.h" extern "C" @@ -43,153 +44,7 @@ using namespace OpenRCT2; using namespace OpenRCT2::Drawing; using namespace OpenRCT2::Ui; -class SoftwareDrawingEngine; - -struct DirtyGrid -{ - uint32 BlockShiftX; - uint32 BlockShiftY; - uint32 BlockWidth; - uint32 BlockHeight; - uint32 BlockColumns; - uint32 BlockRows; - uint8 * Blocks; -}; - -class RainDrawer final : public IRainDrawer -{ -private: - struct RainPixel - { - uint32 Position; - uint8 Colour; - }; - - static constexpr uint32 MaxRainPixels = 0xFFFE; - - size_t _rainPixelsCapacity = MaxRainPixels; - uint32 _rainPixelsCount = 0; - RainPixel * _rainPixels = nullptr; - rct_drawpixelinfo * _screenDPI = nullptr; - -public: - RainDrawer() - { - _rainPixels = new RainPixel[_rainPixelsCapacity]; - } - - ~RainDrawer() - { - delete [] _rainPixels; - } - - void SetDPI(rct_drawpixelinfo * dpi) - { - _screenDPI = dpi; - } - - void Draw(sint32 x, sint32 y, sint32 width, sint32 height, sint32 xStart, sint32 yStart) override - { - static const uint8 RainPattern[] = - { - 32, 32, 0, 12, 0, 14, 0, 16, 255, 0, 255, 0, 255, 0, 255, 0, 255, - 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, - 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, - 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 0, 0 - }; - - const uint8 * pattern = RainPattern; - uint8 patternXSpace = *pattern++; - uint8 patternYSpace = *pattern++; - - uint8 patternStartXOffset = xStart % patternXSpace; - uint8 patternStartYOffset = yStart % patternYSpace; - - uint32 pixelOffset = (_screenDPI->pitch + _screenDPI->width) * y + x; - uint8 patternYPos = patternStartYOffset % patternYSpace; - - uint8 * screenBits = _screenDPI->bits; - - //Stores the colours of changed pixels - RainPixel * newPixels = &_rainPixels[_rainPixelsCount]; - for (; height != 0; height--) - { - uint8 patternX = pattern[patternYPos * 2]; - if (patternX != 0xFF) - { - if (_rainPixelsCount < (_rainPixelsCapacity - (uint32)width)) - { - uint32 finalPixelOffset = width + pixelOffset; - - uint32 xPixelOffset = pixelOffset; - xPixelOffset += ((uint8)(patternX - patternStartXOffset)) % patternXSpace; - - uint8 patternPixel = pattern[patternYPos * 2 + 1]; - for (; xPixelOffset < finalPixelOffset; xPixelOffset += patternXSpace) - { - uint8 current_pixel = screenBits[xPixelOffset]; - screenBits[xPixelOffset] = patternPixel; - _rainPixelsCount++; - - // Store colour and position - *newPixels++ = { xPixelOffset, current_pixel }; - } - } - } - - pixelOffset += _screenDPI->pitch + _screenDPI->width; - patternYPos++; - patternYPos %= patternYSpace; - } - } - - void Restore() - { - if (_rainPixelsCount > 0) - { - uint32 numPixels = (_screenDPI->width + _screenDPI->pitch) * _screenDPI->height; - uint8 * bits = _screenDPI->bits; - for (uint32 i = 0; i < _rainPixelsCount; i++) - { - RainPixel rainPixel = _rainPixels[i]; - if (rainPixel.Position >= numPixels) - { - // Pixel out of bounds, bail - break; - } - - bits[rainPixel.Position] = rainPixel.Colour; - } - _rainPixelsCount = 0; - } - } -}; - -class SoftwareDrawingContext final : public IDrawingContext -{ -private: - SoftwareDrawingEngine * _engine = nullptr; - rct_drawpixelinfo * _dpi = nullptr; - -public: - explicit SoftwareDrawingContext(SoftwareDrawingEngine * engine); - ~SoftwareDrawingContext() override; - - IDrawingEngine * GetEngine() override; - - void Clear(uint8 paletteIndex) override; - void FillRect(uint32 colour, sint32 x, sint32 y, sint32 w, sint32 h) override; - void FilterRect(FILTER_PALETTE_ID palette, sint32 left, sint32 top, sint32 right, sint32 bottom) override; - void DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 x2, sint32 y2) override; - void DrawSprite(uint32 image, sint32 x, sint32 y, uint32 tertiaryColour) override; - void DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskImage, uint32 colourImage) override; - void DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) override; - void DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette) override; - - void SetDPI(rct_drawpixelinfo * dpi); -}; - -class SoftwareDrawingEngine final : public IDrawingEngine +class SoftwareDrawingEngine final : public X8DrawingEngine { private: IUiContext * const _uiContext; @@ -207,7 +62,6 @@ private: uint32 _paletteHWMapped[256] = { 0 }; #ifdef __ENABLE_LIGHTFX__ uint32 _lightPaletteHWMapped[256] = { 0 }; - bool _lastLightFXenabled = false; #endif // Steam overlay checking @@ -216,36 +70,16 @@ private: bool _overlayActive = false; bool _pausedBeforeOverlay = false; - uint32 _width = 0; - uint32 _height = 0; - uint32 _pitch = 0; - size_t _bitsSize = 0; - uint8 * _bits = nullptr; - - DirtyGrid _dirtyGrid = { 0 }; - - rct_drawpixelinfo _bitsDPI = { 0 }; - - RainDrawer _rainDrawer; - SoftwareDrawingContext * _drawingContext; - public: explicit SoftwareDrawingEngine(IUiContext * uiContext, bool hardwareDisplay) : _uiContext(uiContext), _hardwareDisplay(hardwareDisplay) { UNUSED(_uiContext); // Will be used in due course to retrieve window information - _drawingContext = new SoftwareDrawingContext(this); -#ifdef __ENABLE_LIGHTFX__ - _lastLightFXenabled = (gConfigGeneral.enable_light_fx != 0); -#endif } ~SoftwareDrawingEngine() override { - delete _drawingContext; - delete [] _dirtyGrid.Blocks; - delete [] _bits; SDL_FreeSurface(_surface); SDL_FreeSurface(_RGBASurface); SDL_FreePalette(_palette); @@ -361,74 +195,9 @@ public: } } - void SetUncappedFrameRate(bool uncapped) override - { - // Not applicable for this engine - } - - void Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) override - { - left = Math::Max(left, 0); - top = Math::Max(top, 0); - right = Math::Min(right, (sint32)_width); - bottom = Math::Min(bottom, (sint32)_height); - - if (left >= right) return; - if (top >= bottom) return; - - right--; - bottom--; - - left >>= _dirtyGrid.BlockShiftX; - right >>= _dirtyGrid.BlockShiftX; - top >>= _dirtyGrid.BlockShiftY; - bottom >>= _dirtyGrid.BlockShiftY; - - uint32 dirtyBlockColumns = _dirtyGrid.BlockColumns; - uint8 * screenDirtyBlocks = _dirtyGrid.Blocks; - for (sint16 y = top; y <= bottom; y++) - { - uint32 yOffset = y * dirtyBlockColumns; - for (sint16 x = left; x <= right; x++) - { - screenDirtyBlocks[yOffset + x] = 0xFF; - } - } - } - void Draw() override { - if (gIntroState != INTRO_STATE_NONE) { - intro_draw(&_bitsDPI); - } else { -#ifdef __ENABLE_LIGHTFX__ - // HACK we need to re-configure the bits if light fx has been enabled / disabled - if (_lastLightFXenabled != (gConfigGeneral.enable_light_fx != 0)) { - Resize(_width, _height); - } -#endif - - _rainDrawer.SetDPI(&_bitsDPI); - _rainDrawer.Restore(); - - ResetWindowVisbilities(); - - // Redraw dirty regions before updating the viewports, otherwise - // when viewports get panned, they copy dirty pixels - DrawAllDirtyBlocks(); - - window_update_all_viewports(); - DrawAllDirtyBlocks(); - window_update_all(); - - gfx_draw_pickedup_peep(&_bitsDPI); - gfx_invalidate_pickedup_peep(); - - DrawRain(&_bitsDPI, &_rainDrawer); - - rct2_draw(&_bitsDPI); - } - + X8DrawingEngine::Draw(); if (_sdlRenderer != nullptr) { DisplayViaTexture(); @@ -439,237 +208,7 @@ public: } } - void CopyRect(sint32 x, sint32 y, sint32 width, sint32 height, sint32 dx, sint32 dy) override - { - if (dx == 0 && dy == 0) return; - - // Originally 0x00683359 - // Adjust for move off screen - // NOTE: when zooming, there can be x, y, dx, dy combinations that go off the - // screen; hence the checks. This code should ultimately not be called when - // zooming because this function is specific to updating the screen on move - sint32 lmargin = Math::Min(x - dx, 0); - sint32 rmargin = Math::Min((sint32)_width - (x - dx + width), 0); - sint32 tmargin = Math::Min(y - dy, 0); - sint32 bmargin = Math::Min((sint32)_height - (y - dy + height), 0); - x -= lmargin; - y -= tmargin; - width += lmargin + rmargin; - height += tmargin + bmargin; - - sint32 stride = _bitsDPI.width + _bitsDPI.pitch; - uint8 * to = _bitsDPI.bits + y * stride + x; - uint8 * from = _bitsDPI.bits + (y - dy) * stride + x - dx; - - if (dy > 0) - { - // If positive dy, reverse directions - to += (height - 1) * stride; - from += (height - 1) * stride; - stride = -stride; - } - - // Move bytes - for (sint32 i = 0; i < height; i++) - { - memmove(to, from, width); - to += stride; - from += stride; - } - } - - sint32 Screenshot() override - { - return screenshot_dump_png(&_bitsDPI); - } - - IDrawingContext * GetDrawingContext(rct_drawpixelinfo * dpi) override - { - _drawingContext->SetDPI(dpi); - return _drawingContext; - } - - rct_drawpixelinfo * GetDrawingPixelInfo() override - { - return &_bitsDPI; - } - - DRAWING_ENGINE_FLAGS GetFlags() override - { - return DEF_DIRTY_OPTIMISATIONS; - } - - void InvalidateImage(uint32 image) override - { - // Not applicable for this engine - } - - rct_drawpixelinfo * GetDPI() - { - return &_bitsDPI; - } - private: - - void ConfigureBits(uint32 width, uint32 height, uint32 pitch) - { - size_t newBitsSize = pitch * height; - uint8 * newBits = new uint8[newBitsSize]; - if (_bits == nullptr) - { - Memory::Set(newBits, 0, newBitsSize); - } - else - { - if (_pitch == pitch) - { - Memory::Copy(newBits, _bits, Math::Min(_bitsSize, newBitsSize)); - } - else - { - uint8 * src = _bits; - uint8 * dst = newBits; - - uint32 minWidth = Math::Min(_width, width); - uint32 minHeight = Math::Min(_height, height); - for (uint32 y = 0; y < minHeight; y++) - { - Memory::Copy(dst, src, minWidth); - if (pitch - minWidth > 0) - { - Memory::Set(dst + minWidth, 0, pitch - minWidth); - } - src += _pitch; - dst += pitch; - } - } - delete [] _bits; - } - - _bits = newBits; - _bitsSize = newBitsSize; - _width = width; - _height = height; - _pitch = pitch; - - rct_drawpixelinfo * dpi = &_bitsDPI; - dpi->bits = _bits; - dpi->x = 0; - dpi->y = 0; - dpi->width = width; - dpi->height = height; - dpi->pitch = _pitch - width; - - ConfigureDirtyGrid(); - -#ifdef __ENABLE_LIGHTFX__ - if (gConfigGeneral.enable_light_fx) - { - lightfx_update_buffers(dpi); - } -#endif - } - - void ConfigureDirtyGrid() - { - _dirtyGrid.BlockShiftX = 7; - _dirtyGrid.BlockShiftY = 6; - _dirtyGrid.BlockWidth = 1 << _dirtyGrid.BlockShiftX; - _dirtyGrid.BlockHeight = 1 << _dirtyGrid.BlockShiftY; - _dirtyGrid.BlockColumns = (_width >> _dirtyGrid.BlockShiftX) + 1; - _dirtyGrid.BlockRows = (_height >> _dirtyGrid.BlockShiftY) + 1; - - delete [] _dirtyGrid.Blocks; - _dirtyGrid.Blocks = new uint8[_dirtyGrid.BlockColumns * _dirtyGrid.BlockRows]; - } - - static void ResetWindowVisbilities() - { - // reset window visibility status to unknown - for (rct_window *w = g_window_list; w < gWindowNextSlot; w++) - { - w->visibility = VC_UNKNOWN; - if (w->viewport != NULL) w->viewport->visibility = VC_UNKNOWN; - } - } - - void DrawAllDirtyBlocks() - { - uint32 dirtyBlockColumns = _dirtyGrid.BlockColumns; - uint32 dirtyBlockRows = _dirtyGrid.BlockRows; - uint8 * dirtyBlocks = _dirtyGrid.Blocks; - - for (uint32 x = 0; x < dirtyBlockColumns; x++) - { - for (uint32 y = 0; y < dirtyBlockRows; y++) - { - uint32 yOffset = y * dirtyBlockColumns; - if (dirtyBlocks[yOffset + x] == 0) - { - continue; - } - - // Determine columns - uint32 xx; - for (xx = x; xx < dirtyBlockColumns; xx++) - { - if (dirtyBlocks[yOffset + xx] == 0) - { - break; - } - } - uint32 columns = xx - x; - - // Check rows - uint32 yy; - for (yy = y; yy < dirtyBlockRows; yy++) - { - uint32 yyOffset = yy * dirtyBlockColumns; - for (xx = x; xx < x + columns; xx++) - { - if (dirtyBlocks[yyOffset + xx] == 0) - { - goto endRowCheck; - } - } - } - - endRowCheck: - uint32 rows = yy - y; - DrawDirtyBlocks(x, y, columns, rows); - } - } - } - - void DrawDirtyBlocks(uint32 x, uint32 y, uint32 columns, uint32 rows) - { - uint32 dirtyBlockColumns = _dirtyGrid.BlockColumns; - uint8 * screenDirtyBlocks = _dirtyGrid.Blocks; - - // Unset dirty blocks - for (uint32 top = y; top < y + (uint32)rows; top++) - { - uint32 topOffset = top * dirtyBlockColumns; - for (uint32 left = x; left < x + (uint32)columns; left++) - { - screenDirtyBlocks[topOffset + left] = 0; - } - } - - // Determine region in pixels - uint32 left = Math::Max(0, x * _dirtyGrid.BlockWidth); - uint32 top = Math::Max(0, y * _dirtyGrid.BlockHeight); - uint32 right = Math::Min(_width, left + (columns * _dirtyGrid.BlockWidth)); - uint32 bottom = Math::Min(_height, top + (rows * _dirtyGrid.BlockHeight)); - if (right <= left || bottom <= top) - { - return; - } - - // Draw region - window_draw_all(&_bitsDPI, left, top, right, bottom); - } - void Display() { // Lock the surface before setting its pixels @@ -849,291 +388,3 @@ IDrawingEngine * OpenRCT2::Ui::CreateHardwareDisplayDrawingEngine(IUiContext * u { return new SoftwareDrawingEngine(uiContext, true); } - -SoftwareDrawingContext::SoftwareDrawingContext(SoftwareDrawingEngine * engine) -{ - _engine = engine; -} - -SoftwareDrawingContext::~SoftwareDrawingContext() -{ - -} - -IDrawingEngine * SoftwareDrawingContext::GetEngine() -{ - return _engine; -} - -void SoftwareDrawingContext::Clear(uint8 paletteIndex) -{ - rct_drawpixelinfo * dpi = _dpi; - - sint32 w = dpi->width >> dpi->zoom_level; - sint32 h = dpi->height >> dpi->zoom_level; - uint8 * ptr = dpi->bits; - - for (sint32 y = 0; y < h; y++) - { - Memory::Set(ptr, paletteIndex, w); - ptr += w + dpi->pitch; - } -} - -/** rct2: 0x0097FF04 */ -static const uint16 Pattern[] = { - 0b0111111110000000, - 0b0011111111000000, - 0b0001111111100000, - 0b0000111111110000, - 0b0000011111111000, - 0b0000001111111100, - 0b0000000111111110, - 0b0000000011111111, - 0b1000000001111111, - 0b1100000000111111, - 0b1110000000011111, - 0b1111000000001111, - 0b1111100000000111, - 0b1111110000000011, - 0b1111111000000001, - 0b1111111100000000, -}; - -/** rct2: 0x0097FF14 */ -static const uint16 PatternInverse[] = { - 0b1000000001111111, - 0b1100000000111111, - 0b1110000000011111, - 0b1111000000001111, - 0b1111100000000111, - 0b1111110000000011, - 0b1111111000000001, - 0b1111111100000000, - 0b0111111110000000, - 0b0011111111000000, - 0b0001111111100000, - 0b0000111111110000, - 0b0000011111111000, - 0b0000001111111100, - 0b0000000111111110, - 0b0000000011111111 -}; - -/** rct2: 0x0097FEFC */ -static const uint16 * Patterns[] = { - Pattern, - PatternInverse -}; - -void SoftwareDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint32 right, sint32 bottom) -{ - rct_drawpixelinfo * dpi = _dpi; - - if (left > right) return; - if (top > bottom) return; - if (dpi->x > right) return; - if (left >= dpi->x + dpi->width) return; - if (bottom < dpi->y) return; - if (top >= dpi->y + dpi->height) return; - - uint16 crossPattern = 0; - - sint32 startX = left - dpi->x; - if (startX < 0) - { - crossPattern ^= startX; - startX = 0; - } - - sint32 endX = right - dpi->x + 1; - if (endX > dpi->width) - { - endX = dpi->width; - } - - sint32 startY = top - dpi->y; - if (startY < 0) - { - crossPattern ^= startY; - startY = 0; - } - - sint32 endY = bottom - dpi->y + 1; - if (endY > dpi->height) - { - endY = dpi->height; - } - - sint32 width = endX - startX; - sint32 height = endY - startY; - - if (colour & 0x1000000) - { - // Cross hatching - uint8 * dst = (startY * (dpi->width + dpi->pitch)) + startX + dpi->bits; - for (sint32 i = 0; i < height; i++) - { - uint8 * nextdst = dst + dpi->width + dpi->pitch; - uint32 p = ror32(crossPattern, 1); - p = (p & 0xFFFF0000) | width; - - // Fill every other pixel with the colour - for (; (p & 0xFFFF) != 0; p--) - { - p = p ^ 0x80000000; - if (p & 0x80000000) - { - *dst = colour & 0xFF; - } - dst++; - } - crossPattern ^= 1; - dst = nextdst; - } - } - else if (colour & 0x2000000) - { - assert(false); - } - else if (colour & 0x4000000) - { - uint8 * dst = startY * (dpi->width + dpi->pitch) + startX + dpi->bits; - - // The pattern loops every 15 lines this is which - // part the pattern is on. - sint32 patternY = (startY + dpi->y) % 16; - - // The pattern loops every 15 pixels this is which - // part the pattern is on. - sint32 startPatternX = (startX + dpi->x) % 16; - sint32 patternX = startPatternX; - - const uint16 * patternsrc = Patterns[colour >> 28]; // or possibly uint8)[esi*4] ? - - for (sint32 numLines = height; numLines > 0; numLines--) - { - uint8 * nextdst = dst + dpi->width + dpi->pitch; - uint16 pattern = patternsrc[patternY]; - - for (sint32 numPixels = width; numPixels > 0; numPixels--) - { - if (pattern & (1 << patternX)) - { - *dst = colour & 0xFF; - } - patternX = (patternX + 1) % 16; - dst++; - } - patternX = startPatternX; - patternY = (patternY + 1) % 16; - dst = nextdst; - } - } - else - { - uint8 * dst = startY * (dpi->width + dpi->pitch) + startX + dpi->bits; - for (sint32 i = 0; i < height; i++) - { - Memory::Set(dst, colour & 0xFF, width); - dst += dpi->width + dpi->pitch; - } - } -} - -void SoftwareDrawingContext::FilterRect(FILTER_PALETTE_ID palette, sint32 left, sint32 top, sint32 right, sint32 bottom) -{ - rct_drawpixelinfo * dpi = _dpi; - - if (left > right) return; - if (top > bottom) return; - if (dpi->x > right) return; - if (left >= dpi->x + dpi->width) return; - if (bottom < dpi->y) return; - if (top >= dpi->y + dpi->height) return; - - sint32 startX = left - dpi->x; - if (startX < 0) - { - startX = 0; - } - - sint32 endX = right - dpi->x + 1; - if (endX > dpi->width) - { - endX = dpi->width; - } - - sint32 startY = top - dpi->y; - if (startY < 0) - { - startY = 0; - } - - sint32 endY = bottom - dpi->y + 1; - if (endY > dpi->height) - { - endY = dpi->height; - } - - sint32 width = endX - startX; - sint32 height = endY - startY; - - - //0x2000000 - // 00678B7E 00678C83 - // Location in screen buffer? - uint8 * dst = dpi->bits + (uint32)((startY >> (dpi->zoom_level)) * ((dpi->width >> dpi->zoom_level) + dpi->pitch) + (startX >> dpi->zoom_level)); - - // Find colour in colour table? - uint16 g1Index = palette_to_g1_offset[palette]; - rct_g1_element * g1Element = &g1Elements[g1Index]; - uint8 * g1Bits = g1Element->offset; - - // Fill the rectangle with the colours from the colour table - for (sint32 i = 0; i < height >> dpi->zoom_level; i++) - { - uint8 * nextdst = dst + (dpi->width >> dpi->zoom_level) + dpi->pitch; - for (sint32 j = 0; j < (width >> dpi->zoom_level); j++) - { - *dst = g1Bits[*dst]; - dst++; - } - dst = nextdst; - } -} - -void SoftwareDrawingContext::DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 x2, sint32 y2) -{ - gfx_draw_line_software(_dpi, x1, y1, x2, y2, colour); -} - -void SoftwareDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 tertiaryColour) -{ - gfx_draw_sprite_software(_dpi, image, x, y, tertiaryColour); -} - -void SoftwareDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskImage, uint32 colourImage) -{ - gfx_draw_sprite_raw_masked_software(_dpi, x, y, maskImage, colourImage); -} - -void SoftwareDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) -{ - uint8 palette[256]; - memset(palette, colour, 256); - palette[0] = 0; - - image &= 0x7FFFF; - gfx_draw_sprite_palette_set_software(_dpi, image | 0x20000000, x, y, palette, nullptr); -} - -void SoftwareDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette) -{ - gfx_draw_sprite_palette_set_software(_dpi, image, x, y, palette, nullptr); -} - -void SoftwareDrawingContext::SetDPI(rct_drawpixelinfo * dpi) -{ - _dpi = dpi; -} diff --git a/src/openrct2/drawing/X8DrawingEngine.cpp b/src/openrct2/drawing/X8DrawingEngine.cpp index bd38a586ae..dce5fb3b35 100644 --- a/src/openrct2/drawing/X8DrawingEngine.cpp +++ b/src/openrct2/drawing/X8DrawingEngine.cpp @@ -35,6 +35,7 @@ extern "C" #include "../platform/platform.h" #include "../rct2.h" #include "drawing.h" + #include "lightfx.h" } using namespace OpenRCT2; @@ -135,6 +136,9 @@ void X8RainDrawer::Restore() X8DrawingEngine::X8DrawingEngine() { _drawingContext = new X8DrawingContext(this); +#ifdef __ENABLE_LIGHTFX__ + _lastLightFXenabled = (gConfigGeneral.enable_light_fx != 0); +#endif } X8DrawingEngine::~X8DrawingEngine() @@ -201,6 +205,14 @@ void X8DrawingEngine::Draw() } else { +#ifdef __ENABLE_LIGHTFX__ + // HACK we need to re-configure the bits if light fx has been enabled / disabled + if (_lastLightFXenabled != (gConfigGeneral.enable_light_fx != 0)) + { + Resize(_width, _height); + } +#endif + _rainDrawer.SetDPI(&_bitsDPI); _rainDrawer.Restore(); @@ -343,6 +355,13 @@ void X8DrawingEngine::ConfigureBits(uint32 width, uint32 height, uint32 pitch) dpi->pitch = _pitch - width; ConfigureDirtyGrid(); + +#ifdef __ENABLE_LIGHTFX__ + if (gConfigGeneral.enable_light_fx) + { + lightfx_update_buffers(dpi); + } +#endif } void X8DrawingEngine::ConfigureDirtyGrid() diff --git a/src/openrct2/drawing/X8DrawingEngine.h b/src/openrct2/drawing/X8DrawingEngine.h index dbca408c73..791945114a 100644 --- a/src/openrct2/drawing/X8DrawingEngine.h +++ b/src/openrct2/drawing/X8DrawingEngine.h @@ -59,9 +59,9 @@ namespace OpenRCT2 { namespace Drawing void Restore(); }; - class X8DrawingEngine final : public IDrawingEngine + class X8DrawingEngine : public IDrawingEngine { - private: + protected: uint32 _width = 0; uint32 _height = 0; uint32 _pitch = 0; @@ -72,6 +72,10 @@ namespace OpenRCT2 { namespace Drawing rct_drawpixelinfo _bitsDPI = { 0 }; +#ifdef __ENABLE_LIGHTFX__ + bool _lastLightFXenabled = false; +#endif + X8RainDrawer _rainDrawer; X8DrawingContext * _drawingContext; @@ -94,8 +98,10 @@ namespace OpenRCT2 { namespace Drawing rct_drawpixelinfo * GetDPI(); - private: + protected: void ConfigureBits(uint32 width, uint32 height, uint32 pitch); + + private: void ConfigureDirtyGrid(); static void ResetWindowVisbilities(); void DrawAllDirtyBlocks(); From 0ad2c075e51fb706d6e20a707ad8ae959483048e Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 8 Jun 2017 22:42:22 +0100 Subject: [PATCH 3/6] Separate hardware display drawing engine from software --- .../engines/HardwareDisplayDrawingEngine.cpp | 249 +++++++++++++++ .../drawing/engines/SoftwareDrawingEngine.cpp | 288 +++--------------- src/openrct2-ui/libopenrct2ui.vcxproj | 1 + 3 files changed, 286 insertions(+), 252 deletions(-) create mode 100644 src/openrct2-ui/drawing/engines/HardwareDisplayDrawingEngine.cpp diff --git a/src/openrct2-ui/drawing/engines/HardwareDisplayDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/HardwareDisplayDrawingEngine.cpp new file mode 100644 index 0000000000..08d89060ee --- /dev/null +++ b/src/openrct2-ui/drawing/engines/HardwareDisplayDrawingEngine.cpp @@ -0,0 +1,249 @@ +#pragma region Copyright (c) 2014-2017 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 +#include +#include +#include +#include +#include +#include "DrawingEngines.h" + +extern "C" +{ + #include + #include +} + +using namespace OpenRCT2; +using namespace OpenRCT2::Drawing; +using namespace OpenRCT2::Ui; + +class HardwareDisplayDrawingEngine final : public X8DrawingEngine +{ +private: + IUiContext * const _uiContext; + SDL_Window * _window = nullptr; + SDL_Renderer * _sdlRenderer = nullptr; + SDL_Texture * _screenTexture = nullptr; + SDL_PixelFormat * _screenTextureFormat = nullptr; + uint32 _paletteHWMapped[256] = { 0 }; +#ifdef __ENABLE_LIGHTFX__ + uint32 _lightPaletteHWMapped[256] = { 0 }; +#endif + + // Steam overlay checking + uint32 _pixelBeforeOverlay = 0; + uint32 _pixelAfterOverlay = 0; + bool _overlayActive = false; + bool _pausedBeforeOverlay = false; + +public: + explicit HardwareDisplayDrawingEngine(IUiContext * uiContext) + : _uiContext(uiContext) + { + UNUSED(_uiContext); // Will be used in due course to retrieve window information + } + + ~HardwareDisplayDrawingEngine() override + { + SDL_DestroyTexture(_screenTexture); + SDL_FreeFormat(_screenTextureFormat); + SDL_DestroyRenderer(_sdlRenderer); + } + + void Initialise(SDL_Window * window) override + { + _window = window; + _sdlRenderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + } + + void Resize(uint32 width, uint32 height) override + { + SDL_DestroyTexture(_screenTexture); + SDL_FreeFormat(_screenTextureFormat); + + SDL_RendererInfo rendererInfo; + SDL_GetRendererInfo(_sdlRenderer, &rendererInfo); + uint32 pixelFormat = SDL_PIXELFORMAT_UNKNOWN; + for (uint32 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; + } + } + + _screenTexture = SDL_CreateTexture(_sdlRenderer, pixelFormat, SDL_TEXTUREACCESS_STREAMING, width, height); + + uint32 format; + SDL_QueryTexture(_screenTexture, &format, 0, 0, 0); + _screenTextureFormat = SDL_AllocFormat(format); + + ConfigureBits(width, height, width); + } + + void SetPalette(const rct_palette_entry * palette) override + { + if (_screenTextureFormat != nullptr) + { + for (sint32 i = 0; i < 256; i++) + { + _paletteHWMapped[i] = SDL_MapRGB(_screenTextureFormat, palette[i].red, palette[i].green, palette[i].blue); + } + +#ifdef __ENABLE_LIGHTFX__ + if (gConfigGeneral.enable_light_fx) + { + const SDL_Color * lightPalette = lightfx_get_palette(); + for (sint32 i = 0; i < 256; i++) + { + _lightPaletteHWMapped[i] = SDL_MapRGBA(_screenTextureFormat, lightPalette[i].r, lightPalette[i].g, lightPalette[i].b, lightPalette[i].a); + } + } +#endif + } + } + + void Draw() override + { + X8DrawingEngine::Draw(); + Display(); + } + +private: + void Display() + { +#ifdef __ENABLE_LIGHTFX__ + if (gConfigGeneral.enable_light_fx) + { + lightfx_render_to_texture(_screenTexture, _bits, _width, _height, _paletteHWMapped, _lightPaletteHWMapped); + } + else +#endif + { + CopyBitsToTexture(_screenTexture, _bits, (sint32)_width, (sint32)_height, _paletteHWMapped); + } + SDL_RenderCopy(_sdlRenderer, _screenTexture, nullptr, nullptr); + + bool isSteamOverlayActive = GetContext()->GetUiContext()->IsSteamOverlayActive(); + if (isSteamOverlayActive && gConfigGeneral.steam_overlay_pause) + { + OverlayPreRenderCheck(); + } + + SDL_RenderPresent(_sdlRenderer); + + if (isSteamOverlayActive && gConfigGeneral.steam_overlay_pause) + { + OverlayPostRenderCheck(); + } + } + + void CopyBitsToTexture(SDL_Texture * texture, uint8 * src, sint32 width, sint32 height, uint32 * palette) + { + void * pixels; + sint32 pitch; + if (SDL_LockTexture(texture, nullptr, &pixels, &pitch) == 0) + { + sint32 padding = pitch - (width * 4); + if (pitch == width * 4) + { + uint32 * dst = (uint32 *)pixels; + for (sint32 i = width * height; i > 0; i--) + { + *dst++ = palette[*src++]; + } + } + else + { + if (pitch == (width * 2) + padding) + { + uint16 * dst = (uint16 *)pixels; + for (sint32 y = height; y > 0; y--) + { + for (sint32 x = width; x > 0; x--) + { + const uint8 lower = *(uint8 *)(&palette[*src++]); + const uint8 upper = *(uint8 *)(&palette[*src++]); + *dst++ = (lower << 8) | upper; + } + dst = (uint16*)(((uint8 *)dst) + padding); + } + } + else if (pitch == width + padding) + { + uint8 * dst = (uint8 *)pixels; + for (sint32 y = height; y > 0; y--) + { + for (sint32 x = width; x > 0; x--) + { + *dst++ = *(uint8 *)(&palette[*src++]); + } + dst += padding; + } + } + } + SDL_UnlockTexture(texture); + } + } + + void ReadCentrePixel(uint32 * pixel) + { + SDL_Rect centrePixelRegion = { (sint32)(_width / 2), (sint32)(_height / 2), 1, 1 }; + SDL_RenderReadPixels(_sdlRenderer, ¢rePixelRegion, SDL_PIXELFORMAT_RGBA8888, pixel, sizeof(uint32)); + } + + // Should be called before SDL_RenderPresent to capture frame buffer before Steam overlay is drawn. + void OverlayPreRenderCheck() + { + ReadCentrePixel(&_pixelBeforeOverlay); + } + + // Should be called after SDL_RenderPresent, when Steam overlay has had the chance to be drawn. + void OverlayPostRenderCheck() + { + ReadCentrePixel(&_pixelAfterOverlay); + + // Detect an active Steam overlay by checking if the center pixel is changed by the gray fade. + // Will not be triggered by applications rendering to corners, like FRAPS, MSI Afterburner and Friends popups. + bool newOverlayActive = _pixelBeforeOverlay != _pixelAfterOverlay; + + // Toggle game pause state consistently with base pause state + if (!_overlayActive && newOverlayActive) + { + _pausedBeforeOverlay = gGamePaused & GAME_PAUSED_NORMAL; + if (!_pausedBeforeOverlay) + { + pause_toggle(); + } + } + else if (_overlayActive && !newOverlayActive && !_pausedBeforeOverlay) + { + pause_toggle(); + } + + _overlayActive = newOverlayActive; + } +}; + +IDrawingEngine * OpenRCT2::Ui::CreateHardwareDisplayDrawingEngine(IUiContext * uiContext) +{ + return new HardwareDisplayDrawingEngine(uiContext); +} diff --git a/src/openrct2-ui/drawing/engines/SoftwareDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/SoftwareDrawingEngine.cpp index e5781e5350..f55bd0212d 100644 --- a/src/openrct2-ui/drawing/engines/SoftwareDrawingEngine.cpp +++ b/src/openrct2-ui/drawing/engines/SoftwareDrawingEngine.cpp @@ -14,30 +14,19 @@ *****************************************************************************/ #pragma endregion +#include +#include #include -#include -#include #include -#include #include -#include #include -#include #include +#include #include "DrawingEngines.h" extern "C" { - #include #include - #include - #include - #include - #include - #include - #include - #include - #include } using namespace OpenRCT2; @@ -48,32 +37,14 @@ class SoftwareDrawingEngine final : public X8DrawingEngine { private: IUiContext * const _uiContext; - bool const _hardwareDisplay; - - SDL_Window * _window = nullptr; - SDL_Surface * _surface = nullptr; - SDL_Surface * _RGBASurface = nullptr; - SDL_Palette * _palette = nullptr; - - // For hardware display only - SDL_Renderer * _sdlRenderer = nullptr; - SDL_Texture * _screenTexture = nullptr; - SDL_PixelFormat * _screenTextureFormat = nullptr; - uint32 _paletteHWMapped[256] = { 0 }; -#ifdef __ENABLE_LIGHTFX__ - uint32 _lightPaletteHWMapped[256] = { 0 }; -#endif - - // Steam overlay checking - uint32 _pixelBeforeOverlay = 0; - uint32 _pixelAfterOverlay = 0; - bool _overlayActive = false; - bool _pausedBeforeOverlay = false; + SDL_Window * _window = nullptr; + SDL_Surface * _surface = nullptr; + SDL_Surface * _RGBASurface = nullptr; + SDL_Palette * _palette = nullptr; public: - explicit SoftwareDrawingEngine(IUiContext * uiContext, bool hardwareDisplay) - : _uiContext(uiContext), - _hardwareDisplay(hardwareDisplay) + explicit SoftwareDrawingEngine(IUiContext * uiContext) + : _uiContext(uiContext) { UNUSED(_uiContext); // Will be used in due course to retrieve window information } @@ -83,19 +54,11 @@ public: SDL_FreeSurface(_surface); SDL_FreeSurface(_RGBASurface); SDL_FreePalette(_palette); - SDL_DestroyTexture(_screenTexture); - SDL_FreeFormat(_screenTextureFormat); - SDL_DestroyRenderer(_sdlRenderer); } void Initialise(SDL_Window * window) override { _window = window; - if (_hardwareDisplay) - { - // Try to create the accelerated renderer. - _sdlRenderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - } } void Resize(uint32 width, uint32 height) override @@ -103,109 +66,49 @@ public: SDL_FreeSurface(_surface); SDL_FreeSurface(_RGBASurface); SDL_FreePalette(_palette); - SDL_DestroyTexture(_screenTexture); - SDL_FreeFormat(_screenTextureFormat); - if (_sdlRenderer != nullptr) + _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 == nullptr || + _palette == nullptr || + _RGBASurface == nullptr) { - SDL_RendererInfo rendererInfo; - SDL_GetRendererInfo(_sdlRenderer, &rendererInfo); - uint32 pixelFormat = SDL_PIXELFORMAT_UNKNOWN; - for (uint32 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; - } - } - - _screenTexture = SDL_CreateTexture(_sdlRenderer, pixelFormat, SDL_TEXTUREACCESS_STREAMING, width, height); - - uint32 format; - SDL_QueryTexture(_screenTexture, &format, 0, 0, 0); - _screenTextureFormat = SDL_AllocFormat(format); - - ConfigureBits(width, height, width); + log_fatal("%p || %p || %p == NULL %s", _surface, _palette, _RGBASurface, SDL_GetError()); + exit(-1); } - else + + if (SDL_SetSurfacePalette(_surface, _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 == nullptr || - _palette == nullptr || - _RGBASurface == nullptr) - { - 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); - } - - ConfigureBits(width, height, _surface->pitch); + log_fatal("SDL_SetSurfacePalette failed %s", SDL_GetError()); + exit(-1); } + + ConfigureBits(width, height, _surface->pitch); } void SetPalette(const rct_palette_entry * palette) override { - if (_sdlRenderer != nullptr) + SDL_Surface * windowSurface = SDL_GetWindowSurface(_window); + if (windowSurface != nullptr && _palette != nullptr) { - if (_screenTextureFormat != nullptr) - { - for (sint32 i = 0; i < 256; i++) - { - _paletteHWMapped[i] = SDL_MapRGB(_screenTextureFormat, palette[i].red, palette[i].green, palette[i].blue); - } - -#ifdef __ENABLE_LIGHTFX__ - if (gConfigGeneral.enable_light_fx) - { - const SDL_Color * lightPalette = lightfx_get_palette(); - for (sint32 i = 0; i < 256; i++) - { - _lightPaletteHWMapped[i] = SDL_MapRGBA(_screenTextureFormat, lightPalette[i].r, lightPalette[i].g, lightPalette[i].b, lightPalette[i].a); - } - } -#endif - } - } - else - { - SDL_Surface * windowSurface = SDL_GetWindowSurface(_window); - if (windowSurface != nullptr && _palette != nullptr) - { - SDL_Colour colours[256]; - for (sint32 i = 0; i < 256; i++) { - colours[i].r = palette[i].red; - colours[i].g = palette[i].green; - colours[i].b = palette[i].blue; - colours[i].a = palette[i].alpha; - } - SDL_SetPaletteColors(_palette, colours, 0, 256); + SDL_Colour colours[256]; + for (sint32 i = 0; i < 256; i++) { + colours[i].r = palette[i].red; + colours[i].g = palette[i].green; + colours[i].b = palette[i].blue; + colours[i].a = palette[i].alpha; } + SDL_SetPaletteColors(_palette, colours, 0, 256); } } void Draw() override { X8DrawingEngine::Draw(); - if (_sdlRenderer != nullptr) - { - DisplayViaTexture(); - } - else - { - Display(); - } + Display(); } private: @@ -263,128 +166,9 @@ private: exit(1); } } - - void DisplayViaTexture() - { -#ifdef __ENABLE_LIGHTFX__ - if (gConfigGeneral.enable_light_fx) - { - lightfx_render_to_texture(_screenTexture, _bits, _width, _height, _paletteHWMapped, _lightPaletteHWMapped); - } - else -#endif - { - CopyBitsToTexture(_screenTexture, _bits, (sint32)_width, (sint32)_height, _paletteHWMapped); - } - SDL_RenderCopy(_sdlRenderer, _screenTexture, nullptr, nullptr); - - bool isSteamOverlayActive = GetContext()->GetUiContext()->IsSteamOverlayActive(); - if (isSteamOverlayActive && gConfigGeneral.steam_overlay_pause) - { - OverlayPreRenderCheck(); - } - - SDL_RenderPresent(_sdlRenderer); - - if (isSteamOverlayActive && gConfigGeneral.steam_overlay_pause) - { - OverlayPostRenderCheck(); - } - } - - void CopyBitsToTexture(SDL_Texture * texture, uint8 * src, sint32 width, sint32 height, uint32 * palette) - { - void * pixels; - sint32 pitch; - if (SDL_LockTexture(texture, nullptr, &pixels, &pitch) == 0) - { - sint32 padding = pitch - (width * 4); - if (pitch == width * 4) - { - uint32 * dst = (uint32 *)pixels; - for (sint32 i = width * height; i > 0; i--) - { - *dst++ = palette[*src++]; - } - } - else - { - if (pitch == (width * 2) + padding) - { - uint16 * dst = (uint16 *)pixels; - for (sint32 y = height; y > 0; y--) - { - for (sint32 x = width; x > 0; x--) - { - const uint8 lower = *(uint8 *)(&palette[*src++]); - const uint8 upper = *(uint8 *)(&palette[*src++]); - *dst++ = (lower << 8) | upper; - } - dst = (uint16*)(((uint8 *)dst) + padding); - } - } - else if (pitch == width + padding) - { - uint8 * dst = (uint8 *)pixels; - for (sint32 y = height; y > 0; y--) - { - for (sint32 x = width; x > 0; x--) - { - *dst++ = *(uint8 *)(&palette[*src++]); - } - dst += padding; - } - } - } - SDL_UnlockTexture(texture); - } - } - - void ReadCentrePixel(uint32 * pixel) - { - SDL_Rect centrePixelRegion = { (sint32)(_width / 2), (sint32)(_height / 2), 1, 1 }; - SDL_RenderReadPixels(_sdlRenderer, ¢rePixelRegion, SDL_PIXELFORMAT_RGBA8888, pixel, sizeof(uint32)); - } - - // Should be called before SDL_RenderPresent to capture frame buffer before Steam overlay is drawn. - void OverlayPreRenderCheck() - { - ReadCentrePixel(&_pixelBeforeOverlay); - } - - // Should be called after SDL_RenderPresent, when Steam overlay has had the chance to be drawn. - void OverlayPostRenderCheck() - { - ReadCentrePixel(&_pixelAfterOverlay); - - // Detect an active Steam overlay by checking if the center pixel is changed by the gray fade. - // Will not be triggered by applications rendering to corners, like FRAPS, MSI Afterburner and Friends popups. - bool newOverlayActive = _pixelBeforeOverlay != _pixelAfterOverlay; - - // Toggle game pause state consistently with base pause state - if (!_overlayActive && newOverlayActive) - { - _pausedBeforeOverlay = gGamePaused & GAME_PAUSED_NORMAL; - if (!_pausedBeforeOverlay) - { - pause_toggle(); - } - } - else if (_overlayActive && !newOverlayActive && !_pausedBeforeOverlay) - { - pause_toggle(); - } - - _overlayActive = newOverlayActive; - } }; IDrawingEngine * OpenRCT2::Ui::CreateSoftwareDrawingEngine(IUiContext * uiContext) { - return new SoftwareDrawingEngine(uiContext, false); -} - -IDrawingEngine * OpenRCT2::Ui::CreateHardwareDisplayDrawingEngine(IUiContext * uiContext) -{ - return new SoftwareDrawingEngine(uiContext, true); + return new SoftwareDrawingEngine(uiContext); } diff --git a/src/openrct2-ui/libopenrct2ui.vcxproj b/src/openrct2-ui/libopenrct2ui.vcxproj index 9bd0b6ad68..8f22ec0203 100644 --- a/src/openrct2-ui/libopenrct2ui.vcxproj +++ b/src/openrct2-ui/libopenrct2ui.vcxproj @@ -29,6 +29,7 @@ + From 97d68957f07e8246f680e089d6c6c9555d34085d Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 8 Jun 2017 23:02:39 +0100 Subject: [PATCH 4/6] Fix segfault in screenshot command --- .../engines/opengl/OpenGLDrawingEngine.cpp | 3 +- src/openrct2/Imaging.h | 10 ++++- src/openrct2/cmdline/ScreenshotCommands.cpp | 6 +-- src/openrct2/drawing/NewDrawing.cpp | 2 +- src/openrct2/drawing/X8DrawingEngine.cpp | 2 +- src/openrct2/game.c | 2 +- .../{screenshot.c => Screenshot.cpp} | 42 ++++++++++++------- .../interface/{screenshot.h => Screenshot.h} | 32 +++++++------- src/openrct2/interface/keyboard_shortcut.c | 2 +- src/openrct2/title/TitleScreen.cpp | 2 +- src/openrct2/ui/DummyUiContext.cpp | 8 +++- src/openrct2/windows/top_toolbar.c | 2 +- 12 files changed, 69 insertions(+), 44 deletions(-) rename src/openrct2/interface/{screenshot.c => Screenshot.cpp} (95%) rename src/openrct2/interface/{screenshot.h => Screenshot.h} (64%) diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 5f80b7fd2f..3ec17a8420 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -28,12 +28,11 @@ #include #include #include -#include +#include #include extern "C" { - #include #include #include #include diff --git a/src/openrct2/Imaging.h b/src/openrct2/Imaging.h index 268c6a71fe..efd3cebc4a 100644 --- a/src/openrct2/Imaging.h +++ b/src/openrct2/Imaging.h @@ -17,7 +17,15 @@ #pragma once #include "common.h" -#include "drawing/drawing.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + #include "drawing/drawing.h" +#ifdef __cplusplus +} +#endif #ifdef __cplusplus diff --git a/src/openrct2/cmdline/ScreenshotCommands.cpp b/src/openrct2/cmdline/ScreenshotCommands.cpp index ab02eca0f9..97b7e0bfa4 100644 --- a/src/openrct2/cmdline/ScreenshotCommands.cpp +++ b/src/openrct2/cmdline/ScreenshotCommands.cpp @@ -14,11 +14,7 @@ *****************************************************************************/ #pragma endregion -extern "C" -{ - #include "../interface/screenshot.h" -} - +#include "../interface/Screenshot.h" #include "CommandLine.hpp" static exitcode_t HandleScreenshot(CommandLineArgEnumerator *argEnumerator); diff --git a/src/openrct2/drawing/NewDrawing.cpp b/src/openrct2/drawing/NewDrawing.cpp index 14feacd67c..4727df0a50 100644 --- a/src/openrct2/drawing/NewDrawing.cpp +++ b/src/openrct2/drawing/NewDrawing.cpp @@ -19,6 +19,7 @@ #include "../ui/UiContext.h" #include "../core/Exception.hpp" #include "../core/Registration.hpp" +#include "../interface/Screenshot.h" #include "IDrawingContext.h" #include "IDrawingEngine.h" #include "NewDrawing.h" @@ -27,7 +28,6 @@ extern "C" { #include "../config/Config.h" #include "../drawing/drawing.h" - #include "../interface/screenshot.h" #include "../localisation/string_ids.h" #include "../platform/platform.h" #include "../rct2.h" diff --git a/src/openrct2/drawing/X8DrawingEngine.cpp b/src/openrct2/drawing/X8DrawingEngine.cpp index dce5fb3b35..fb539a8ab4 100644 --- a/src/openrct2/drawing/X8DrawingEngine.cpp +++ b/src/openrct2/drawing/X8DrawingEngine.cpp @@ -20,6 +20,7 @@ #include "../core/Guard.hpp" #include "../core/Math.hpp" #include "../core/Memory.hpp" +#include "../interface/Screenshot.h" #include "IDrawingContext.h" #include "IDrawingEngine.h" #include "Rain.h" @@ -28,7 +29,6 @@ extern "C" { #include "../game.h" - #include "../interface/screenshot.h" #include "../interface/viewport.h" #include "../interface/window.h" #include "../intro.h" diff --git a/src/openrct2/game.c b/src/openrct2/game.c index 1b954e7f7a..a93d00ad50 100644 --- a/src/openrct2/game.c +++ b/src/openrct2/game.c @@ -21,7 +21,7 @@ #include "editor.h" #include "game.h" #include "input.h" -#include "interface/screenshot.h" +#include "interface/Screenshot.h" #include "interface/viewport.h" #include "interface/widget.h" #include "interface/window.h" diff --git a/src/openrct2/interface/screenshot.c b/src/openrct2/interface/Screenshot.cpp similarity index 95% rename from src/openrct2/interface/screenshot.c rename to src/openrct2/interface/Screenshot.cpp index 0b5bd9a500..a6db3913b5 100644 --- a/src/openrct2/interface/screenshot.c +++ b/src/openrct2/interface/Screenshot.cpp @@ -17,19 +17,27 @@ #include "../audio/audio.h" #include "../config/Config.h" #include "../Context.h" -#include "../drawing/drawing.h" -#include "../game.h" #include "../Imaging.h" -#include "../intro.h" -#include "../localisation/localisation.h" #include "../OpenRCT2.h" -#include "../platform/platform.h" -#include "../rct2.h" -#include "../util/util.h" -#include "../windows/error.h" -#include "screenshot.h" -#include "viewport.h" +#include "Screenshot.h" +extern "C" +{ + #include "../drawing/drawing.h" + #include "../game.h" + #include "../intro.h" + #include "../localisation/localisation.h" + #include "../platform/platform.h" + #include "../rct2.h" + #include "../util/util.h" + #include "../windows/error.h" + #include "viewport.h" +} + +using namespace OpenRCT2; + +extern "C" +{ uint8 gScreenshotCountdown = 0; /** @@ -211,7 +219,7 @@ void screenshot_giant() dpi.height = resolutionHeight; dpi.pitch = 0; dpi.zoom_level = 0; - dpi.bits = malloc(dpi.width * dpi.height); + dpi.bits = (uint8 *)malloc(dpi.width * dpi.height); viewport_render(&dpi, &viewport, 0, 0, viewport.width, viewport.height); @@ -283,7 +291,9 @@ sint32 cmdline_for_screenshot(const char **argv, sint32 argc) } gOpenRCT2Headless = true; - // if (openrct2_initialise()) { + auto context = CreateContext(); + if (context->Initialise()) + { drawing_engine_init(); rct2_open_file(inputPath); @@ -357,7 +367,7 @@ sint32 cmdline_for_screenshot(const char **argv, sint32 argc) dpi.height = resolutionHeight; dpi.pitch = 0; dpi.zoom_level = 0; - dpi.bits = malloc(dpi.width * dpi.height); + dpi.bits = (uint8 *)malloc(dpi.width * dpi.height); viewport_render(&dpi, &viewport, 0, 0, viewport.width, viewport.height); @@ -368,7 +378,9 @@ sint32 cmdline_for_screenshot(const char **argv, sint32 argc) free(dpi.bits); drawing_engine_dispose(); - // } - // openrct2_dispose(); + } + delete context; return 1; } + +} diff --git a/src/openrct2/interface/screenshot.h b/src/openrct2/interface/Screenshot.h similarity index 64% rename from src/openrct2/interface/screenshot.h rename to src/openrct2/interface/Screenshot.h index 2c99809e87..a4c9b8dcb6 100644 --- a/src/openrct2/interface/screenshot.h +++ b/src/openrct2/interface/Screenshot.h @@ -14,19 +14,23 @@ *****************************************************************************/ #pragma endregion -#ifndef _SCREENSHOT_H_ -#define _SCREENSHOT_H_ - -#include "../drawing/drawing.h" - -extern uint8 gScreenshotCountdown; - -void screenshot_check(); -sint32 screenshot_dump(); -sint32 screenshot_dump_png(rct_drawpixelinfo *dpi); -sint32 screenshot_dump_png_32bpp(sint32 width, sint32 height, const void *pixels); - -void screenshot_giant(); -sint32 cmdline_for_screenshot(const char **argv, sint32 argc); +#pragma once +#ifdef __cplusplus +extern "C" +{ +#endif + #include "../drawing/drawing.h" + + extern uint8 gScreenshotCountdown; + + void screenshot_check(); + sint32 screenshot_dump(); + sint32 screenshot_dump_png(rct_drawpixelinfo *dpi); + sint32 screenshot_dump_png_32bpp(sint32 width, sint32 height, const void *pixels); + + void screenshot_giant(); + sint32 cmdline_for_screenshot(const char **argv, sint32 argc); +#ifdef __cplusplus +} #endif diff --git a/src/openrct2/interface/keyboard_shortcut.c b/src/openrct2/interface/keyboard_shortcut.c index d2137c17c1..486bc5d3f0 100644 --- a/src/openrct2/interface/keyboard_shortcut.c +++ b/src/openrct2/interface/keyboard_shortcut.c @@ -20,7 +20,7 @@ #include "../game.h" #include "../input.h" #include "../interface/chat.h" -#include "../interface/screenshot.h" +#include "../interface/Screenshot.h" #include "../localisation/localisation.h" #include "../network/network.h" #include "../platform/platform.h" diff --git a/src/openrct2/title/TitleScreen.cpp b/src/openrct2/title/TitleScreen.cpp index cfa6cc65bb..9db015fe33 100644 --- a/src/openrct2/title/TitleScreen.cpp +++ b/src/openrct2/title/TitleScreen.cpp @@ -16,6 +16,7 @@ #include "../core/Console.hpp" #include "../Context.h" +#include "../interface/Screenshot.h" #include "../network/network.h" #include "../OpenRCT2.h" #include "../scenario/ScenarioRepository.h" @@ -31,7 +32,6 @@ extern "C" #include "../drawing/drawing.h" #include "../game.h" #include "../input.h" - #include "../interface/screenshot.h" #include "../interface/viewport.h" #include "../interface/window.h" #include "../localisation/localisation.h" diff --git a/src/openrct2/ui/DummyUiContext.cpp b/src/openrct2/ui/DummyUiContext.cpp index bc4346e015..52b893198a 100644 --- a/src/openrct2/ui/DummyUiContext.cpp +++ b/src/openrct2/ui/DummyUiContext.cpp @@ -14,8 +14,11 @@ *****************************************************************************/ #pragma endregion +#include "../drawing/X8DrawingEngine.h" #include "UiContext.h" +using namespace OpenRCT2::Drawing; + namespace OpenRCT2 { namespace Ui { /** @@ -53,7 +56,10 @@ namespace OpenRCT2 { namespace Ui virtual void SetKeysPressed(uint32 keysym, uint8 scancode) override { } // Drawing - virtual Drawing::IDrawingEngine * CreateDrawingEngine(Drawing::DRAWING_ENGINE_TYPE type) override { return nullptr; } + virtual Drawing::IDrawingEngine * CreateDrawingEngine(Drawing::DRAWING_ENGINE_TYPE type) override + { + return new X8DrawingEngine(); + } // Text input virtual bool IsTextInputActive() override { return false; } diff --git a/src/openrct2/windows/top_toolbar.c b/src/openrct2/windows/top_toolbar.c index 53b16550ef..c58eda009a 100644 --- a/src/openrct2/windows/top_toolbar.c +++ b/src/openrct2/windows/top_toolbar.c @@ -22,7 +22,7 @@ #include "../game.h" #include "../input.h" #include "../interface/console.h" -#include "../interface/screenshot.h" +#include "../interface/Screenshot.h" #include "../interface/viewport.h" #include "../interface/widget.h" #include "../interface/window.h" From a5e4a0965f9cb9f7bc8fd323282a16d3bbc7b286 Mon Sep 17 00:00:00 2001 From: Ted John Date: Fri, 9 Jun 2017 21:02:24 +0100 Subject: [PATCH 5/6] Ignore final warnings for X8DrawingEngine --- openrct2.common.props | 3 ++- src/openrct2/drawing/X8DrawingEngine.cpp | 5 +++++ src/openrct2/drawing/X8DrawingEngine.h | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/openrct2.common.props b/openrct2.common.props index f66464cbb9..fae5b0cf83 100644 --- a/openrct2.common.props +++ b/openrct2.common.props @@ -28,8 +28,9 @@ - 4091;4100;4132;4200;4201;4204;4206;4221;4244;4245;%(DisableSpecificWarnings) + 4068;4091;4100;4132;4200;4201;4204;4206;4221;4244;4245;%(DisableSpecificWarnings)