Loading
#openttdcoop - Paste
Archives
Trending
Docs
Login
ABAP
ActionScript
ActionScript 3
Ada
AIMMS3
ALGOL 68
Apache configuration
AppleScript
Apt sources
ARM ASSEMBLER
ASM
ASP
asymptote
Autoconf
Autohotkey
AutoIt
AviSynth
awk
BASCOM AVR
Bash
Basic4GL
BibTeX
BlitzBasic
bnf
Boo
Brainfuck
C
C#
C (LoadRunner)
C (Mac)
C (WinAPI)
C++
C++ (Qt)
C++ (WinAPI)
CAD DCL
CAD Lisp
CFDG
ChaiScript
Chapel
CIL
Clojure
CMake
COBOL
CoffeeScript
ColdFusion
CSS
Cuesheet
D
Dart
DCL
DCPU-16 Assembly
DCS
Delphi
Diff
DIV
DOS
dot
E
ECMAScript
Eiffel
eMail (mbox)
EPC
Erlang
Euphoria
EZT
F#
Falcon
FO (abas-ERP)
Formula One
Fortran
FreeBasic
FreeSWITCH
GADV 4CS
GAMBAS
GDB
genero
Genie
glSlang
GML
GNU/Octave
GNU Gettext
GNU make
Gnuplot
Go
Groovy
GwBasic
Haskell
Haxe
HicEst
HQ9+
HTML
HTML5
Icon
INI
Inno
INTERCAL
Io
ISPF Panel
J
Java
Java(TM) 2 Platform Standard Edition 5.0
Javascript
JCL
jQuery
KiXtart
KLone C
KLone C++
LaTeX
LDIF
Liberty BASIC
Lisp
LLVM Intermediate Representation
Locomotive Basic
Logtalk
LOLcode
Lotus Notes @Formulas
LotusScript
LScript
LSL2
Lua
MagikSF
MapBasic
Matlab M
Microchip Assembler
Microsoft Registry
mIRC Scripting
MMIX
Modula-2
Modula-3
MOS 6502 (6510) ACME Cross Assembler format
MOS 6502 (6510) Kick Assembler format
MOS 6502 (6510) TASM/64TASS 1.46 Assembler format
Motorola 68000 - HiSoft Devpac ST 2 Assembler format
Motorola 68000 Assembler
MXML
MySQL
Nagios
NetRexx
newlisp
nginx
Nimrod
NML NewGRF Meta Language
NSIS
Oberon-2
Objeck Programming Language
Objective-C
OCaml
OCaml (brief)
ooRexx
OpenBSD Packet Filter
OpenOffice.org Basic
Oracle 8 SQL
Oracle 11 SQL
Oxygene
OZ
ParaSail
PARI/GP
Pascal
PCRE
per
Perl
Perl 6
PHP
PHP (brief)
PIC16
Pike
Pixel Bender 1.0
PL/I
PL/SQL
PostgreSQL
PostScript
POVRAY
PowerBuilder
PowerShell
ProFTPd configuration
Progress
Prolog
PROPERTIES
ProvideX
Puppet
PureBasic
Python
Python for S60
q/kdb+
QBasic/QuickBASIC
QML
R / S+
Racket
Rails
RBScript
REBOL
rexx
robots.txt
RPM Specification File
Ruby
Rust
SAS
Scala
Scheme
SciLab
SCL
sdlBasic
Smalltalk
Smarty
SPARK
SPARQL
SQL
Squirrel Script
Squirrel Script with OpenTTD AI/GS
StandardML
StoneScript
SystemVerilog
T-SQL
TCL
Tera Term Macro
Text
thinBasic
TypoScript
Unicon (Unified Extended Dialect of Icon)
Uno Idl
Unreal Script
UPC
Urbi
Vala
vb.net
VBScript
Vedit macro language
Verilog
VHDL
Vim Script
Visual Basic
Visual Fox Pro
Visual Prolog
Whitespace
Whois (RPSL format)
Winbatch
X++
XBasic
XML
Xorg configuration
YAML
ZiLOG Z80 Assembler
ZXBasic
diff --git a/src/fence_gui.cpp b/src/fence_gui.cpp index 1e9d178..fbc9718 100644 --- a/src/fence_gui.cpp +++ b/src/fence_gui.cpp @@ -115,7 +115,7 @@ void FenceGui::DrawWidget(WidgetNumber wid_num, const BaseWidget *wid) const lines--; Recolouring recolouring; - _video.BlitImage({rect.x, rect.y - sprite->yoffset}, sprite, recolouring, GS_NORMAL); + _video.BlitImage({rect.x, rect.y - sprite->yoffset}, sprite, recolouring); rect.y += sprite->height; } break; diff --git a/src/freerct.cpp b/src/freerct.cpp index bc093eb..89d57b9 100644 --- a/src/freerct.cpp +++ b/src/freerct.cpp @@ -98,15 +98,9 @@ int freerct_main(int argc, char **argv) /* Load RCD files. */ InitImageStorage(); _rcd_collection.ScanDirectories(); - _sprite_manager.LoadRcdFiles(); InitLanguage(); - if (!_gui_sprites.HasSufficientGraphics()) { - fprintf(stderr, "Insufficient graphics loaded.\n"); - return 1; - } - cfg_file.Load("freerct.cfg"); const char *font_path = cfg_file.GetValue("font", "medium-path"); int font_size = cfg_file.GetNum("font", "medium-size"); @@ -126,6 +120,12 @@ int freerct_main(int argc, char **argv) return 1; } + _sprite_manager.LoadRcdFiles(); + if (!_gui_sprites.HasSufficientGraphics()) { + fprintf(stderr, "Insufficient graphics loaded.\n"); + return 1; + } + InitMouseModes(); StartNewGame(); diff --git a/src/gui_graphics.cpp b/src/gui_graphics.cpp index dfa6910..e974ee2 100644 --- a/src/gui_graphics.cpp +++ b/src/gui_graphics.cpp @@ -55,7 +55,7 @@ void DrawBorderSprites(const BorderSpriteData &bsd, bool pressed, const Rectangl int xleft = pt.x; int ytop = pt.y; if (spr_base[WBS_TOP_LEFT] != nullptr) { - _video.BlitImage(pt, spr_base[WBS_TOP_LEFT], rc, GS_NORMAL); + _video.BlitImage(pt, spr_base[WBS_TOP_LEFT], rc); xleft += spr_base[WBS_TOP_LEFT]->xoffset + spr_base[WBS_TOP_LEFT]->width; ytop += spr_base[WBS_TOP_LEFT]->yoffset + spr_base[WBS_TOP_LEFT]->height; } @@ -63,7 +63,7 @@ void DrawBorderSprites(const BorderSpriteData &bsd, bool pressed, const Rectangl pt.x = rect.base.x + rect.width - 1; int xright = pt.x; if (spr_base[WBS_TOP_RIGHT] != nullptr) { - _video.BlitImage(pt, spr_base[WBS_TOP_RIGHT], rc, GS_NORMAL); + _video.BlitImage(pt, spr_base[WBS_TOP_RIGHT], rc); xright += spr_base[WBS_TOP_RIGHT]->xoffset; } @@ -79,7 +79,7 @@ void DrawBorderSprites(const BorderSpriteData &bsd, bool pressed, const Rectangl pt.y = rect.base.y + rect.height - 1; int ybot = pt.y; if (spr_base[WBS_BOTTOM_LEFT] != nullptr) { - _video.BlitImage(pt, spr_base[WBS_BOTTOM_LEFT], rc, GS_NORMAL); + _video.BlitImage(pt, spr_base[WBS_BOTTOM_LEFT], rc); ybot += spr_base[WBS_BOTTOM_LEFT]->yoffset; } @@ -93,7 +93,7 @@ void DrawBorderSprites(const BorderSpriteData &bsd, bool pressed, const Rectangl pt.x = rect.base.x + rect.width - 1; pt.y = rect.base.y + rect.height - 1; - if (spr_base[WBS_BOTTOM_RIGHT] != nullptr) _video.BlitImage(pt, spr_base[WBS_BOTTOM_RIGHT], rc, GS_NORMAL); + if (spr_base[WBS_BOTTOM_RIGHT] != nullptr) _video.BlitImage(pt, spr_base[WBS_BOTTOM_RIGHT], rc); if (spr_base[WBS_BOTTOM_MIDDLE] != nullptr) _video.BlitHorizontal(xleft, numx, pt.y, spr_base[WBS_BOTTOM_MIDDLE], rc); @@ -117,21 +117,14 @@ void OverlayShaded(const Rectangle32 &rect) r.RestrictTo(0, 0, _video.GetXSize(), _video.GetYSize()); if (r.width == 0 || r.height == 0) return; - /* Set clipped area to the rectangle. */ - ClippedRectangle cr(_video.GetClippedRectangle()); - ClippedRectangle new_cr(cr, r.base.x, r.base.y, r.width, r.height); - _video.SetClippedRectangle(new_cr); - /* Align the disabled sprite so it becomes a continuous pattern. */ - int32 base_x = -(r.base.x % img->width); - int32 base_y = -(r.base.y % img->height); + int32 base_x = r.base.x - (r.base.x % img->width); + int32 base_y = r.base.y - (r.base.y % img->height); uint16 numx = (r.width + img->width - 1) / img->width; uint16 numy = (r.height + img->height - 1) / img->height; static const Recolouring recolour; // Fixed recolouring mapping. _video.BlitImages({base_x, base_y}, img, numx, numy, recolour); - - _video.SetClippedRectangle(cr); // Restore clipped area. } /** @@ -151,10 +144,11 @@ void DrawString(StringID strid, uint8 colour, int x, int y, int width, Alignment DrawText(strid, buffer, lengthof(buffer)); /** \todo Reduce the naiviness of this. */ if (outline) { - _video.BlitText(buffer, MakeRGBA(0, 0, 0, OPAQUE), x + 1, y, width, align); - _video.BlitText(buffer, MakeRGBA(0, 0, 0, OPAQUE), x, y + 1, width, align); - _video.BlitText(buffer, MakeRGBA(0, 0, 0, OPAQUE), x - 1, y, width, align); - _video.BlitText(buffer, MakeRGBA(0, 0, 0, OPAQUE), x, y - 1, width, align); +// _video.BlitText(buffer, MakeRGBA(0, 0, 0, OPAQUE), x + 1, y, width, align); +// _video.BlitText(buffer, MakeRGBA(0, 0, 0, OPAQUE), x, y + 1, width, align); +// _video.BlitText(buffer, MakeRGBA(0, 0, 0, OPAQUE), x - 1, y, width, align); +// _video.BlitText(buffer, MakeRGBA(0, 0, 0, OPAQUE), x, y - 1, width, align); + _video.BlitText(buffer, MakeRGBA(0, 0, 0, OPAQUE), x + 1, y + 1, width, align); } _video.BlitText(buffer, _palette[colour], x, y, width, align); } diff --git a/src/money.h b/src/money.h index cf32ff3..a9d54f5 100644 --- a/src/money.h +++ b/src/money.h @@ -77,7 +77,7 @@ public: */ inline Money& operator+=(const Money& other) { - if ((INT64_MAX - abs(other.m_value)) < abs(this->m_value) && + if ((INT64_MAX - std::abs(other.m_value)) < std::abs(this->m_value) && (this->m_value < 0) == (other.m_value < 0)) { this->m_value = (this->m_value < 0) ? INT64_MIN : INT64_MAX ; } else { @@ -219,7 +219,7 @@ public: */ inline Money& operator*=(const int factor) { - if (factor != 0 && (INT64_MAX / abs(factor)) < abs(this->m_value)) { + if (factor != 0 && (INT64_MAX / std::abs(factor)) < std::abs(this->m_value)) { this->m_value = ((this->m_value < 0) == (factor < 0)) ? INT64_MAX : INT64_MIN; } else { this->m_value *= factor; diff --git a/src/palette.h b/src/palette.h index 42041f4..9c5fd62 100644 --- a/src/palette.h +++ b/src/palette.h @@ -12,6 +12,9 @@ #ifndef PALETTE_H #define PALETTE_H +#include <functional> +#include <map> + class Random; extern const uint32 _palette[256]; ///< The 8bpp FreeRCT palette. @@ -86,6 +89,8 @@ static inline uint32 SetA(uint32 rgba, uint8 opacity) return rgba | opacity; } +#define SPLIT_RGBA(rgba) GetR(rgba), GetG(rgba), GetB(rgba), GetA(rgba) + /** Names of colour ranges. */ enum ColourRange { COL_RANGE_GREY, @@ -129,7 +134,8 @@ enum PaletteColours { /** Shifting of the gradient to make the sprite lighter or darker. */ enum GradientShift { - GS_NIGHT, ///< Shift gradient four steps darker. + GS_START, + GS_NIGHT = GS_START, ///< Shift gradient four steps darker. GS_VERY_DARK, ///< Shift gradient three steps darker. GS_DARK, ///< Shift gradient two steps darker. GS_SLIGHTLY_DARK, ///< Shift gradient one step darker. @@ -143,119 +149,19 @@ enum GradientShift { GS_INVALID = 0xff, ///< Invalid gradient shift. }; -static const int STEP_SIZE = 18; ///< Amount of colour shift for each gradient step. -typedef uint8 (*ShiftFunc)(uint8); ///< Type of the gradient shift function. - -/** - * Gradient shift function for #GS_NIGHT. - * @param col Input colour. - * @return Shifted result colour. - */ -static inline uint8 ShiftGradientNight(uint8 col) -{ - return (col <= 4 * STEP_SIZE) ? 0 : col - 4 * STEP_SIZE; -} - -/** - * Gradient shift function for #GS_VERY_DARK. - * @param col Input colour. - * @return Shifted result colour. - */ -static inline uint8 ShiftGradientVeryDark(uint8 col) -{ - return (col <= 3 * STEP_SIZE) ? 0 : col - 3 * STEP_SIZE; -} - -/** - * Gradient shift function for #GS_DARK - * @param col Input colour. - * @return Shifted result colour. - */ -static inline uint8 ShiftGradientDark(uint8 col) -{ - return (col <= 2 * STEP_SIZE) ? 0 : col - 2 * STEP_SIZE; -} - -/** - * Gradient shift function for #GS_SLIGHTLY_DARK. - * @param col Input colour. - * @return Shifted result colour. - */ -static inline uint8 ShiftGradientSlightlyDark(uint8 col) -{ - return (col <= STEP_SIZE) ? 0 : col - STEP_SIZE; -} - -/** - * Gradient shift function for #GS_NORMAL. - * @param col Input colour. - * @return Shifted result colour. - */ -static inline uint8 ShiftGradientNormal(uint8 col) -{ - return col; -} - -/** - * Gradient shift function for #GS_SLIGHTLY_LIGHT. - * @param col Input colour. - * @return Shifted result colour. - */ -static inline uint8 ShiftGradientSlightlyLight(uint8 col) -{ - return (col >= 255 - STEP_SIZE) ? 255: col + STEP_SIZE; -} - -/** - * Gradient shift function for #GS_LIGHT. - * @param col Input colour. - * @return Shifted result colour. - */ -static inline uint8 ShiftGradientLight(uint8 col) -{ - return (col >= 255 - 2 * STEP_SIZE) ? 255: col + 2 * STEP_SIZE; -} - -/** - * Gradient shift function for #GS_VERY_LIGHT. - * @param col Input colour. - * @return Shifted result colour. - */ -static inline uint8 ShiftGradientVeryLight(uint8 col) -{ - return (col >= 255 - 3 * STEP_SIZE) ? 255: col + 3 * STEP_SIZE; -} - -/** - * Gradient shift function for #GS_DAY. - * @param col Input colour. - * @return Shifted result colour. - */ -static inline uint8 ShiftGradientDay(uint8 col) -{ - return (col >= 255 - 4 * STEP_SIZE) ? 255: col + 4 * STEP_SIZE; -} - -/** - * Select gradient shift function based on the \a shift. - * @param shift Desired amount of gradient shift. - * @return Recolour function implementing the shift. - */ -static inline ShiftFunc GetGradientShiftFunc(GradientShift shift) -{ - switch (shift) { - case GS_NIGHT: return ShiftGradientNight; - case GS_VERY_DARK: return ShiftGradientVeryDark; - case GS_DARK: return ShiftGradientDark; - case GS_SLIGHTLY_DARK: return ShiftGradientSlightlyDark; - case GS_NORMAL: return ShiftGradientNormal; - case GS_SLIGHTLY_LIGHT: return ShiftGradientSlightlyLight; - case GS_LIGHT: return ShiftGradientLight; - case GS_VERY_LIGHT: return ShiftGradientVeryLight; - case GS_DAY: return ShiftGradientDay; - default: NOT_REACHED(); - } -} +static const int STEP_SIZE = 18; + +static const std::map<GradientShift, std::function<uint8(uint8)>> gsmap = { + {GS_NIGHT, [](uint8 col){return (col <= 4 * STEP_SIZE) ? 0: col - 4 * STEP_SIZE;}}, + {GS_VERY_DARK, [](uint8 col){return (col <= 3 * STEP_SIZE) ? 0: col - 3 * STEP_SIZE;}}, + {GS_DARK, [](uint8 col){return (col <= 2 * STEP_SIZE) ? 0: col - 2 * STEP_SIZE;}}, + {GS_SLIGHTLY_DARK, [](uint8 col){return (col <= 1 * STEP_SIZE) ? 0: col - 1 * STEP_SIZE;}}, + {GS_NORMAL, [](uint8 col){return col; }}, + {GS_SLIGHTLY_LIGHT, [](uint8 col){return (col >= 255 - 1 * STEP_SIZE) ? 255: col + 1 * STEP_SIZE;}}, + {GS_LIGHT, [](uint8 col){return (col >= 255 - 2 * STEP_SIZE) ? 255: col + 2 * STEP_SIZE;}}, + {GS_VERY_LIGHT, [](uint8 col){return (col >= 255 - 3 * STEP_SIZE) ? 255: col + 3 * STEP_SIZE;}}, + {GS_DAY, [](uint8 col){return (col >= 255 - 4 * STEP_SIZE) ? 255: col + 4 * STEP_SIZE;}}, +}; /** * Get the index of the base colour of a colour range. diff --git a/src/path_gui.cpp b/src/path_gui.cpp index 4a0e0ef..d5beca9 100644 --- a/src/path_gui.cpp +++ b/src/path_gui.cpp @@ -226,7 +226,7 @@ void PathBuildGui::DrawWidget(WidgetNumber wid_num, const BaseWidget *wid) const int dx = (wid->pos.width - path_type_button_size.width) / 2; int dy = (wid->pos.height - path_type_button_size.height) / 2; Point32 pt(GetWidgetScreenX(wid) + dx - path_type_button_size.base.x, GetWidgetScreenY(wid) + dy - path_type_button_size.base.y); - _video.BlitImage(pt, img, recolour, GS_NORMAL); + _video.BlitImage(pt, img, recolour); } } break; @@ -241,7 +241,7 @@ void PathBuildGui::DrawWidget(WidgetNumber wid_num, const BaseWidget *wid) const int dx = (wid->pos.width - path_type_button_size.width) / 2; int dy = (wid->pos.height - path_type_button_size.height) / 2; Point32 pt(GetWidgetScreenX(wid) + dx - path_type_button_size.base.x, GetWidgetScreenY(wid) + dy - path_type_button_size.base.y); - _video.BlitImage(pt, img, recolour, GS_NORMAL); + _video.BlitImage(pt, img, recolour); } } break; diff --git a/src/ride_gui.cpp b/src/ride_gui.cpp index f72631d..c007c69 100644 --- a/src/ride_gui.cpp +++ b/src/ride_gui.cpp @@ -222,7 +222,7 @@ void RideSelectGui::DrawWidget(WidgetNumber wid_num, const BaseWidget *wid) cons if (ride_type != nullptr && ride_type->kind == RTK_SHOP) { static const Recolouring recolour; // Never modified, display 'original' image in the GUI. Point32 pt(this->GetWidgetScreenX(wid) + wid->pos.width / 2, this->GetWidgetScreenY(wid) + 40); - _video.BlitImage(pt, ride_type->GetView(_shop_placer.orientation), recolour, GS_NORMAL); + _video.BlitImage(pt, ride_type->GetView(_shop_placer.orientation), recolour); } } break; diff --git a/src/sprite_data.cpp b/src/sprite_data.cpp index d221e5c..113e760 100644 --- a/src/sprite_data.cpp +++ b/src/sprite_data.cpp @@ -14,7 +14,9 @@ #include "sprite_data.h" #include "fileio.h" #include "bitmath.h" +#include "video.h" +#include <map> #include <vector> static const int MAX_IMAGE_COUNT = 5000; ///< Maximum number of images that can be loaded (arbitrary number). @@ -25,14 +27,19 @@ ImageData::ImageData() { this->width = 0; this->height = 0; - this->table = nullptr; - this->data = nullptr; + for (int gs = GS_START; gs < GS_COUNT; gs++) { + this->images[static_cast<GradientShift>(gs)] = nullptr; + } } ImageData::~ImageData() { - delete[] this->table; - delete[] this->data; + for (auto &pair : this->images) { + if (pair.second != nullptr) SDL_DestroyTexture(pair.second); + } + + for (auto &mask : this->masks) SDL_DestroyTexture(mask); + SDL_FreeSurface(this->img); } /** @@ -56,38 +63,37 @@ bool ImageData::Load8bpp(RcdFileReader *rcd_file, size_t length) length -= 8; if (length > 100 * 1024) return false; // Another arbitrary limit. - size_t jmp_table = 4 * this->height; - if (length <= jmp_table) return false; // You need at least place for the jump table. - length -= jmp_table; + if (length <= this->height * sizeof(uint32)) return false; // You need at least place for the jump table. + length -= this->height * sizeof(uint32); - this->table = new uint32[jmp_table / 4]; - this->data = new uint8[length]; - if (this->table == nullptr || this->data == nullptr) return false; + uint32 *jmp_table = new uint32[this->height]; + uint8 *data = new uint8[length]; + if (jmp_table == nullptr || data == nullptr) return false; /* Load jump table, adjusting the entries while loading. */ for (uint i = 0; i < this->height; i++) { uint32 dest = rcd_file->GetUInt32(); if (dest == 0) { - this->table[i] = INVALID_JUMP; + jmp_table[i] = INVALID_JUMP; continue; } - dest -= jmp_table; + dest -= this->height * sizeof(uint32); if (dest >= length) return false; - this->table[i] = dest; + jmp_table[i] = dest; } - rcd_file->GetBlob(this->data, length); // Load the image data. + rcd_file->GetBlob(data, length); // Load the image data. /* Verify the image data. */ for (uint i = 0; i < this->height; i++) { - uint32 offset = this->table[i]; + uint32 offset = jmp_table[i]; if (offset == INVALID_JUMP) continue; uint32 xpos = 0; for (;;) { if (offset + 2 >= length) return false; - uint8 rel_pos = this->data[offset]; - uint8 count = this->data[offset + 1]; + uint8 rel_pos = data[offset]; + uint8 count = data[offset + 1]; xpos += (rel_pos & 127) + count; offset += 2 + count; if ((rel_pos & 128) == 0) { @@ -98,14 +104,14 @@ bool ImageData::Load8bpp(RcdFileReader *rcd_file, size_t length) } } } - return true; + return this->Blit8bppSprite(jmp_table, data); } /** * Load a 32bpp image. * @param rcd_file Input stream to read from. * @param length Length of the 32bpp block. - * @return Exeit code, \0 means ok, every other number indicates an error. + * @return Exit code, \0 means ok, every other number indicates an error. */ bool ImageData::Load32bpp(RcdFileReader *rcd_file, size_t length) { @@ -122,14 +128,14 @@ bool ImageData::Load32bpp(RcdFileReader *rcd_file, size_t length) if (length > 100 * 1024) return false; // Another arbitrary limit. /* Allocate and load the image data. */ - this->data = new uint8[length]; - if (this->data == nullptr) return false; - rcd_file->GetBlob(this->data, length); + uint8 *data = new uint8[length]; + if (data == nullptr) return false; + rcd_file->GetBlob(data, length); /* Verify the data. */ - uint8 *abs_end = this->data + length; + uint8 *abs_end = data + length; int line_count = 0; - const uint8 *ptr = this->data; + const uint8 *ptr = data; bool finished = false; while (ptr < abs_end && !finished) { line_count++; @@ -169,92 +175,136 @@ bool ImageData::Load32bpp(RcdFileReader *rcd_file, size_t length) } if (line_count != this->height) return false; if (ptr != abs_end) return false; - return true; + return this->Blit32bppSprite(data); } /** - * Return the pixel-value of the provided position. - * @param xoffset Horizontal offset in the sprite. - * @param yoffset Vertical offset in the sprite. - * @param recolour Recolouring to apply to the retrieved pixel. Use \c nullptr for disabling recolouring. - * @param shift Gradient shift to apply to the retrieved pixel. Use #GS_NORMAL for not shifting the colour. - * @return Pixel value at the given position, or \c 0 if transparent. + * @todo Add other gradientshifts */ -uint32 ImageData::GetPixel(uint16 xoffset, uint16 yoffset, const Recolouring *recolour, GradientShift shift) const +bool ImageData::SetupTextures(const std::vector<uint32> &mem, const std::vector<uint32> &recol) { - if (xoffset >= this->width) return _palette[0]; - if (yoffset >= this->height) return _palette[0]; + this->img = SDL_CreateRGBSurfaceFrom((void *)mem.data(), this->width, this->height, 32, this->width * sizeof(uint32), + 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); + + this->images[GS_NORMAL] = SDL_CreateTextureFromSurface(_video.GetRenderer(), this->img); + SDL_SetTextureBlendMode(this->images[GS_NORMAL], SDL_BLENDMODE_BLEND); +// for (auto &pair : this->images) { +// pair.second = SDL_CreateTextureFromSurface(_video.GetRenderer(), this->img); +// SDL_SetTextureBlendMode(pair.second, SDL_BLENDMODE_BLEND); +// } + + return this->img != nullptr; +} - if (GB(this->flags, IFG_IS_8BPP, 1) != 0) { - /* 8bpp image. */ - uint32 offset = this->table[yoffset]; - if (offset == INVALID_JUMP) return _palette[0]; - - uint16 xpos = 0; - while (xpos <= xoffset) { - uint8 rel_pos = this->data[offset]; - uint8 count = this->data[offset + 1]; - xpos += (rel_pos & 127); - if (xpos > xoffset) return _palette[0]; - if (xoffset - xpos < count) { - uint8 pixel = this->data[offset + 2 + xoffset - xpos]; - if (recolour != nullptr) { - const uint8 *recolour_table = recolour->GetPalette(shift); - pixel = recolour_table[pixel]; +/** + */ +bool ImageData::Blit8bppSprite(const uint32 *jmp_table, const uint8 *data) +{ + if (this->height == 0 || this->width == 0) return false; + std::vector<uint32> mem(this->height * this->width); + std::vector<uint32> recol(this->height * this->width); + + for (int ypos = 0; ypos < this->height; ypos++) { + uint32 offset = jmp_table[ypos]; + if (offset != INVALID_JUMP) { + for (int xpos = 0;;) { + uint8 rel_off = data[offset]; + uint8 count = data[offset + 1]; + const uint8 *pixels = &data[offset + 2]; + offset += 2 + count; + + xpos += rel_off & 0x7F; + for(; count > 0; count--) { + // RECOLOURING + mem.at(ypos * this->width + xpos) = _palette[*pixels]; + pixels++; + xpos++; } - return _palette[pixel]; + if ((rel_off & 0x80) != 0) break; } - xpos += count; - offset += 2 + count; - if ((rel_pos & 128) != 0) break; - } - return _palette[0]; - } else { - /* 32bpp image. */ - const uint8 *ptr = this->data; - while (yoffset > 0) { - uint16 length = ptr[0] | (ptr[1] << 8); - ptr += length; - yoffset--; } - ptr += 2; - while (xoffset > 0) { - uint8 mode = *ptr++; + } + return this->SetupTextures(mem, recol); +} + +/** + */ +bool ImageData::Blit32bppSprite(const uint8 *data) +{ + if (this->height == 0 || this->width == 0) return false; + std::vector<uint32> mem(this->height * this->width); + std::vector<uint32> recol(this->height * this->width); + + const uint8 *src = data + 2; // Skip the length word. + for (int ypos = 0; ypos < this->height; ypos++) { + for (int xpos = 0;;) { + uint8 mode = *src++; if (mode == 0) break; - if ((mode & 0x3F) < xoffset) { - xoffset -= mode & 0x3F; - switch (mode >> 6) { - case 0: ptr += 3 * (mode & 0x3F); break; - case 1: ptr += 1 + 3 * (mode & 0x3F); break; - case 2: ptr++; break; - case 3: ptr += 1 + 1 + (mode & 0x3F); break; - } - } else { - ShiftFunc sf = GetGradientShiftFunc(shift); - switch (mode >> 6) { - case 0: - ptr += 3 * xoffset; - return MakeRGBA(sf(ptr[0]), sf(ptr[1]), sf(ptr[2]), OPAQUE); - case 1: { - uint8 opacity = *ptr; - ptr += 1 + 3 * xoffset; - return MakeRGBA(sf(ptr[0]), sf(ptr[1]), sf(ptr[2]), opacity); + int len = mode & 0x3F; + switch (mode >> 6) { + case 0: // Fully opaque pixels. + for (; len > 0; len--) { + mem.at(ypos * this->width + xpos) = MakeRGBA(src[0], src[1], src[2], OPAQUE); + xpos++; + src += 3; + } + break; + + case 1: { // Partial opaque pixels. + uint8 opacity = *src++; + for (; len > 0; len--) { + mem.at(ypos * this->width + xpos) = MakeRGBA(src[0], src[1], src[2], opacity); + xpos++; + src += 3; } - case 2: - return _palette[0]; // Arbitrary fully transparent. - case 3: { - uint8 opacity = ptr[1]; - if (recolour == nullptr) return MakeRGBA(0, 0, 0, opacity); // Arbitrary colour with the correct opacity. - const uint32 *table = recolour->GetRecolourTable(ptr[0] - 1); - ptr += 2 + xoffset; - uint32 recoloured = table[*ptr]; - return MakeRGBA(sf(GetR(recoloured)), sf(GetG(recoloured)), sf(GetB(recoloured)), opacity); + break; + } + case 2: // Fully transparent pixels. + xpos += len; + break; + + case 3: { // Recoloured pixels. + uint8 layer = *src++; + //const uint32 *table = recolour.GetRecolourTable(layer - 1); + uint8 opacity = *src++; + for (; len > 0; len--) { + *src++;//uint32 recoloured = table[*src++]; + //mem.at(ypos * this->width + xpos) = SetA(recoloured, opacity); + xpos++; } + break; } } } - return _palette[0]; // Arbitrary fully transparent. + src += 2; // Skip the length word. } + + return this->SetupTextures(mem, recol); +} + + +/** + * Return the pixel-value of the provided position. + * @param xoffset Horizontal offset in the sprite. + * @param yoffset Vertical offset in the sprite. + * @param recolour Recolouring to apply to the retrieved pixel. Use \c nullptr for disabling recolouring. + * @param shift Gradient shift to apply to the retrieved pixel. Use #GS_NORMAL for not shifting the colour. + * @return Pixel value at the given position, or \c 0 if transparent. + */ +uint32 ImageData::GetPixel(uint16 xoffset, uint16 yoffset, const Recolouring *recolour) const +{ + if (xoffset >= this->width) return _palette[0]; + if (yoffset >= this->height) return _palette[0]; + + SDL_LockSurface(this->img); + + int pitch = this->img->pitch; + uint32 *pixels = (uint32 *)this->img->pixels; + + uint32 col = pixels[yoffset * pitch + xoffset]; + + SDL_UnlockSurface(this->img); + return col; } /** diff --git a/src/sprite_data.h b/src/sprite_data.h index e1061b1..778f232 100644 --- a/src/sprite_data.h +++ b/src/sprite_data.h @@ -12,6 +12,8 @@ #ifndef SPRITE_DATA_H #define SPRITE_DATA_H +#include <SDL.h> + static const uint32 INVALID_JUMP = UINT32_MAX; ///< Invalid jump destination in image data. class RcdFileReader; @@ -33,7 +35,7 @@ public: bool Load8bpp(RcdFileReader *rcd_file, size_t length); bool Load32bpp(RcdFileReader *rcd_file, size_t length); - uint32 GetPixel(uint16 xoffset, uint16 yoffset, const Recolouring *recolour = nullptr, GradientShift shift = GS_NORMAL) const; + uint32 GetPixel(uint16 xoffset, uint16 yoffset, const Recolouring *recolour = nullptr) const; /** * Is the sprite just a single pixel? @@ -49,8 +51,15 @@ public: uint16 height; ///< Height of the image. int16 xoffset; ///< Horizontal offset of the image. int16 yoffset; ///< Vertical offset of the image. - uint32 *table; ///< The jump table. For missing entries, #INVALID_JUMP is used. - uint8 *data; ///< The image data itself. + + std::map<GradientShift, SDL_Texture *> images; + std::vector<SDL_Texture *> masks; +private: + SDL_Surface *img; // Used to determine an image's opacity + + bool Blit8bppSprite(const uint32 *jmp_table, const uint8 *data); + bool Blit32bppSprite(const uint8 *data); + bool SetupTextures(const std::vector<uint32> &mem, const std::vector<uint32> &recol); }; ImageData *LoadImage(RcdFileReader *rcd_file); diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index dbf13a5..5cd5eaf 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -103,7 +103,7 @@ void TerraformGui::DrawWidget(WidgetNumber wid_num, const BaseWidget *wid) const base.x = this->GetWidgetScreenX(wid) + (wid->pos.width - dot->width) / 2; base.y = this->GetWidgetScreenY(wid) + (wid->pos.height - dot->height) / 2; - _video.BlitImage(base, dot, recolour, GS_NORMAL); + _video.BlitImage(base, dot, recolour); return; } diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 57ba0ae..51f49ae 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -368,14 +368,14 @@ void BottomToolbarWindow::DrawWidget(WidgetNumber wid_num, const BaseWidget *wid Viewport *vp = GetViewport(); int dir = (vp == nullptr) ? 0 : vp->orientation; const ImageData *img = _sprite_manager.GetTableSprite(SPR_GUI_COMPASS_START + dir); - if (img != nullptr) _video.BlitImage({GetWidgetScreenX(wid), GetWidgetScreenY(wid)}, img, recolour, GS_NORMAL); + if (img != nullptr) _video.BlitImage({GetWidgetScreenX(wid), GetWidgetScreenY(wid)}, img, recolour); break; } case BTB_WEATHER: { int spr = SPR_GUI_WEATHER_START + _weather.GetWeatherType(); const ImageData *img = _sprite_manager.GetTableSprite(spr); - if (img != nullptr) _video.BlitImage({GetWidgetScreenX(wid), GetWidgetScreenY(wid)}, img, recolour, GS_NORMAL); + if (img != nullptr) _video.BlitImage({GetWidgetScreenX(wid), GetWidgetScreenY(wid)}, img, recolour); break; } } diff --git a/src/video.cpp b/src/video.cpp index f4fbdb2..7ee8601 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -20,6 +20,8 @@ #include "gamecontrol.h" #include "window.h" #include "viewport.h" +#include "weather.h" + #include <string> VideoSystem _video; ///< Video sub-system. @@ -31,100 +33,6 @@ void QuitProgram() _finish = true; } -/** Default constructor of a clipped rectangle. */ -ClippedRectangle::ClippedRectangle() -{ - this->absx = 0; - this->absy = 0; - this->width = 0; - this->height = 0; - this->address = nullptr; this->pitch = 0; -} - -/** - * Construct a clipped rectangle from coordinates. - * @param x Top-left x position. - * @param y Top-left y position. - * @param w Width. - * @param h Height. - */ -ClippedRectangle::ClippedRectangle(uint16 x, uint16 y, uint16 w, uint16 h) -{ - this->absx = x; - this->absy = y; - this->width = w; - this->height = h; - this->address = nullptr; this->pitch = 0; -} - -/** - * Construct a clipped rectangle inside an existing one. - * @param cr Existing rectangle. - * @param x Top-left x position. - * @param y Top-left y position. - * @param w Width. - * @param h Height. - * @note %Rectangle is clipped to the old one. - */ -ClippedRectangle::ClippedRectangle(const ClippedRectangle &cr, uint16 x, uint16 y, uint16 w, uint16 h) -{ - if (x >= cr.width || y >= cr.height) { - this->absx = 0; - this->absy = 0; - this->width = 0; - this->height = 0; - this->address = nullptr; this->pitch = 0; - return; - } - if (x + w > cr.width) w = cr.width - x; - if (y + h > cr.height) h = cr.height - y; - - this->absx = cr.absx + x; - this->absy = cr.absy + y; - this->width = w; - this->height = h; - this->address = nullptr; this->pitch = 0; -} - -/** - * Copy constructor. - * @param cr Existing clipped rectangle. - */ -ClippedRectangle::ClippedRectangle(const ClippedRectangle &cr) -{ - this->absx = cr.absx; - this->absy = cr.absy; - this->width = cr.width; - this->height = cr.height; - this->address = cr.address; this->pitch = cr.pitch; -} - -/** - * Assignment operator override. - * @param cr Existing clipped rectangle. - * @return The assigned value. - */ -ClippedRectangle &ClippedRectangle::operator=(const ClippedRectangle &cr) -{ - if (this != &cr) { - this->absx = cr.absx; - this->absy = cr.absy; - this->width = cr.width; - this->height = cr.height; - this->address = cr.address; this->pitch = cr.pitch; - } - return *this; -} - -/** Initialize the #address if not done already. */ -void ClippedRectangle::ValidateAddress() -{ - if (this->address == nullptr) { - this->pitch = _video.GetXSize(); - this->address = _video.mem + this->absx + this->absy * this->pitch; - } -} - /** * Default constructor, does nothing, never goes wrong. * Call #Initialize to initialize the system. @@ -165,9 +73,18 @@ std::string VideoSystem::Initialize(const char *font_name, int font_size) return err; } + this->renderer = SDL_CreateRenderer(this->window, -1, 0); + if (this->renderer == nullptr) { + std::string err = "Could not create renderer: "; + err += SDL_GetError(); + SDL_Quit(); + return err; + } + SDL_SetRenderDrawBlendMode(this->renderer, SDL_BLENDMODE_BLEND); + this->GetResolutions(); - this->SetResolution({800, 600}); // Allocates this->mem, return value is ignored. + this->SetResolution({800, 600}); // return value is ignored. /* SDL_CreateRGBSurfaceFrom() pretends to use a void* for the data, * but it's really treated as endian-specific uint32*. @@ -183,12 +100,11 @@ std::string VideoSystem::Initialize(const char *font_name, int font_size) SDL_SetWindowIcon(this->window, icon); SDL_FreeSurface(icon); } else { - printf("Could not set window icon (%s)\n", SDL_GetError()); + fprintf(stderr, "Could not set window icon (%s)\n", SDL_GetError()); } if (TTF_Init() != 0) { SDL_Quit(); - delete[] this->mem; std::string err = "TTF font initialization failed: "; err += TTF_GetError(); return err; @@ -204,7 +120,6 @@ std::string VideoSystem::Initialize(const char *font_name, int font_size) err += TTF_GetError(); TTF_Quit(); SDL_Quit(); - delete[] this->mem; return err; } @@ -230,43 +145,12 @@ bool VideoSystem::SetResolution(const Point32 &res) { if (this->initialized && this->GetXSize() == res.x && this->GetYSize() == res.y) return true; - /* Destroy old window, if it exists. */ - if (this->initialized) { - delete[] mem; - this->mem = nullptr; - SDL_DestroyTexture(this->texture); - this->texture = nullptr; - SDL_DestroyRenderer(this->renderer); - this->renderer = nullptr; - } - this->vid_width = res.x; this->vid_height = res.y; SDL_SetWindowSize(this->window, this->vid_width, this->vid_height); - this->renderer = SDL_CreateRenderer(this->window, -1, 0); - if (this->renderer == nullptr) { - SDL_Quit(); - fprintf(stderr, "Could not create renderer (%s)\n", SDL_GetError()); - return false; - } - - this->texture = SDL_CreateTexture(this->renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, this->vid_width, this->vid_height); - if (this->texture == nullptr) { - SDL_Quit(); - fprintf(stderr, "Could not create texture (%s)\n", SDL_GetError()); - return false; - } - - this->mem = new uint32[this->vid_width * this->vid_height]; - if (this->mem == nullptr) { - SDL_Quit(); - fprintf(stderr, "Failed to obtain window display storage.\n"); - return false; - } - /* Update internal screen size data structures. */ - this->blit_rect = ClippedRectangle(0, 0, this->vid_width, this->vid_height); + this->blit_rect = Rectangle32(0, 0, this->vid_width, this->vid_height); Viewport *vp = GetViewport(); if (vp != nullptr) vp->SetSize(this->vid_width, this->vid_height); _manager.RepositionAllWindows(); @@ -314,18 +198,17 @@ void VideoSystem::MarkDisplayClean() * Set the clipped area. * @param cr New clipped blitting area. */ -void VideoSystem::SetClippedRectangle(const ClippedRectangle &cr) +void VideoSystem::SetClippedRectangle(const Rectangle32 &rect) { - this->blit_rect = cr; + this->blit_rect = rect; } /** * Get the current clipped blitting area. * @return Current clipped area. */ -ClippedRectangle VideoSystem::GetClippedRectangle() +Rectangle32 VideoSystem::GetClippedRectangle() { - this->blit_rect.ValidateAddress(); return this->blit_rect; } @@ -439,6 +322,9 @@ void VideoSystem::MainLoop() if (_finish) break; uint32 now = SDL_GetTicks(); + + printf("%dms\n", now - start); + if (now >= start) { // No wrap around. now -= start; if (now < FRAME_DELAY) SDL_Delay(FRAME_DELAY - now); // Too early, wait until next frame. @@ -458,7 +344,6 @@ void VideoSystem::Shutdown() TTF_CloseFont(this->font); TTF_Quit(); SDL_Quit(); - delete[] this->mem; this->initialized = false; this->dirty = false; } @@ -470,192 +355,13 @@ void VideoSystem::Shutdown() */ void VideoSystem::FinishRepaint() { - SDL_UpdateTexture(this->texture, nullptr, this->mem, this->GetXSize() * sizeof(uint32)); // Upload memory to the GPU. - SDL_RenderClear(this->renderer); - SDL_RenderCopy(this->renderer, this->texture, nullptr, nullptr); SDL_RenderPresent(this->renderer); - MarkDisplayClean(); -} - -/** - * Blit pixels from the \a spr relative to #blit_rect into the area. - * @param img_base Coordinate of the sprite data. - * @param spr The sprite to blit. - * @param recolour Sprite recolouring definition. - * @param shift Gradient shift. - */ -void VideoSystem::BlitImage(const Point32 &img_base, const ImageData *spr, const Recolouring &recolour, GradientShift shift) -{ - this->BlitImage(img_base, spr, recolour, shift); -} - -/** - * Blit a pixel to an area of \a numx times \a numy sprites. - * @param cr Clipped rectangle. - * @param scr_base Base address of the screen array. - * @param xmin Minimal x position. - * @param ymin Minimal y position. - * @param numx Number of horizontal count. - * @param numy Number of vertical count. - * @param width Width of an image. - * @param height Height of an image. - * @param colour Pixel value to blit. - * @note Function does not handle alpha blending of the new pixel with the background. - */ -static void BlitPixel(const ClippedRectangle &cr, uint32 *scr_base, - int32 xmin, int32 ymin, uint16 numx, uint16 numy, uint16 width, uint16 height, uint32 colour) -{ - const int32 xend = xmin + numx * width; - const int32 yend = ymin + numy * height; - while (ymin < yend) { - if (ymin >= cr.height) return; - - if (ymin >= 0) { - uint32 *scr = scr_base; - int32 x = xmin; - while (x < xend) { - if (x >= cr.width) break; - if (x >= 0) *scr = colour; - - x += width; - scr += width; - } - } - ymin += height; - scr_base += height * cr.pitch; - } -} - -/** - * Blit 8bpp images to the screen. - * @param cr Clipped rectangle to draw to. - * @param x_base Base X coordinate of the sprite data. - * @param y_base Base Y coordinate of the sprite data. - * @param spr The sprite to blit. - * @param numx Number of sprites to draw in horizontal direction. - * @param numy Number of sprites to draw in vertical direction. - * @param recoloured Shifted palette to use. - */ -static void Blit8bppImages(const ClippedRectangle &cr, int32 x_base, int32 y_base, const ImageData *spr, uint16 numx, uint16 numy, const uint8 *recoloured) -{ - uint32 *line_base = cr.address + x_base + cr.pitch * y_base; - int32 ypos = y_base; - for (int yoff = 0; yoff < spr->height; yoff++) { - uint32 offset = spr->table[yoff]; - if (offset != INVALID_JUMP) { - int32 xpos = x_base; - uint32 *src_base = line_base; - for (;;) { - uint8 rel_off = spr->data[offset]; - uint8 count = spr->data[offset + 1]; - uint8 *pixels = &spr->data[offset + 2]; - offset += 2 + count; - - xpos += rel_off & 127; - src_base += rel_off & 127; - while (count > 0) { - uint32 colour = _palette[recoloured[*pixels]]; - BlitPixel(cr, src_base, xpos, ypos, numx, numy, spr->width, spr->height, colour); - pixels++; - xpos++; - src_base++; - count--; - } - if ((rel_off & 128) != 0) break; - } - } - line_base += cr.pitch; - ypos++; - } -} - -/** - * Blit 32bpp images to the screen. - * @param cr Clipped rectangle to draw to. - * @param x_base Base X coordinate of the sprite data. - * @param y_base Base Y coordinate of the sprite data. - * @param spr The sprite to blit. - * @param numx Number of sprites to draw in horizontal direction. - * @param numy Number of sprites to draw in vertical direction. - * @param recolour Sprite recolouring definition. - * @param shift Gradient shift. - */ -static void Blit32bppImages(const ClippedRectangle &cr, int32 x_base, int32 y_base, const ImageData *spr, uint16 numx, uint16 numy, const Recolouring &recolour, GradientShift shift) -{ - uint32 *line_base = cr.address + x_base + cr.pitch * y_base; - ShiftFunc sf = GetGradientShiftFunc(shift); - int32 ypos = y_base; - const uint8 *src = spr->data + 2; // Skip the length word. - for (int yoff = 0; yoff < spr->height; yoff++) { - int32 xpos = x_base; - uint32 *src_base = line_base; - for (;;) { - uint8 mode = *src++; - if (mode == 0) break; - switch (mode >> 6) { - case 0: // Fully opaque pixels. - mode &= 0x3F; - for (; mode > 0; mode--) { - uint32 colour = MakeRGBA(sf(src[0]), sf(src[1]), sf(src[2]), OPAQUE); - BlitPixel(cr, src_base, xpos, ypos, numx, numy, spr->width, spr->height, colour); - xpos++; - src_base++; - src += 3; - } - break; - - case 1: { // Partial opaque pixels. - uint8 opacity = *src++; - mode &= 0x3F; - for (; mode > 0; mode--) { - /* Cheat transparency a bit by just recolouring the previously drawn pixel */ - uint32 old_pixel = *src_base; - - uint r = sf(src[0]) * opacity + GetR(old_pixel) * (256 - opacity); - uint g = sf(src[1]) * opacity + GetG(old_pixel) * (256 - opacity); - uint b = sf(src[2]) * opacity + GetB(old_pixel) * (256 - opacity); - - /* Opaque, but colour adjusted depending on the old pixel. */ - uint32 ndest = MakeRGBA(r >> 8, g >> 8, b >> 8, OPAQUE); - BlitPixel(cr, src_base, xpos, ypos, numx, numy, spr->width, spr->height, ndest); - xpos++; - src_base++; - src += 3; - } - break; - } - case 2: // Fully transparent pixels. - xpos += mode & 0x3F; - src_base += mode & 0x3F; - break; + /* Reset the renderer */ + SDL_SetRenderDrawColor(this->renderer, 0, 0, 0, 0); + SDL_RenderClear(this->renderer); - case 3: { // Recoloured pixels. - uint8 layer = *src++; - const uint32 *table = recolour.GetRecolourTable(layer - 1); - uint8 opacity = *src++; - mode &= 0x3F; - for (; mode > 0; mode--) { - uint32 old_pixel = *src_base; - uint32 recoloured = table[*src++]; - - uint r = sf(GetR(recoloured)) * opacity + GetR(old_pixel) * (256 - opacity); - uint g = sf(GetG(recoloured)) * opacity + GetG(old_pixel) * (256 - opacity); - uint b = sf(GetB(recoloured)) * opacity + GetB(old_pixel) * (256 - opacity); - - uint32 colour = MakeRGBA(r >> 8, g >> 8, b >> 8, OPAQUE); - BlitPixel(cr, src_base, xpos, ypos, numx, numy, spr->width, spr->height, colour); - xpos++; - src_base++; - } - break; - } - } - } - line_base += cr.pitch; - ypos++; - src += 2; // Skip the length word. - } + MarkDisplayClean(); } /** @@ -667,31 +373,28 @@ static void Blit32bppImages(const ClippedRectangle &cr, int32 x_base, int32 y_ba * @param recolour Sprite recolouring definition. * @param shift Gradient shift. */ -void VideoSystem::BlitImages(const Point32 &pt, const ImageData *spr, uint16 numx, uint16 numy, const Recolouring &recolour, GradientShift shift) +void VideoSystem::BlitImages(const Point32 &pt, const ImageData *spr, uint16 numx, uint16 numy, const Recolouring &recolour) { - this->blit_rect.ValidateAddress(); - int x_base = pt.x + spr->xoffset; int y_base = pt.y + spr->yoffset; - /* Don't draw wildly outside the screen. */ - while (numx > 0 && x_base + spr->width < 0) { - x_base += spr->width; numx--; - } - while (numx > 0 && x_base + (numx - 1) * spr->width >= this->blit_rect.width) numx--; - if (numx == 0) return; + // Get current gradient shift + GradientShift gs = static_cast<GradientShift>(GS_LIGHT - _weather.GetWeatherType()); - while (numy > 0 && y_base + spr->height < 0) { - y_base += spr->height; numy--; + SDL_Texture *shifted_sprite = spr->images.find(gs)->second; + if (shifted_sprite == nullptr) { + shifted_sprite = spr->images.find(GS_NORMAL)->second; } - while (numy > 0 && y_base + (numy - 1) * spr->height >= this->blit_rect.height) numy--; - if (numy == 0) return; + assert(shifted_sprite != nullptr); - if (GB(spr->flags, IFG_IS_8BPP, 1) != 0) { - Blit8bppImages(this->blit_rect, x_base, y_base, spr, numx, numy, recolour.GetPalette(shift)); - } else { - Blit32bppImages(this->blit_rect, x_base, y_base, spr, numx, numy, recolour, shift); + for (int x = 0; x < numx; x++) { + for (int y = 0; y < numy; y++) { + SDL_Rect sdl_rect = {x_base + x * spr->width, y_base + y * spr->height, spr->width, spr->height}; + SDL_RenderCopy(this->renderer, shifted_sprite, nullptr, &sdl_rect); + // Also draw recolourings + } } + } /** @@ -757,7 +460,7 @@ void VideoSystem::GetNumberRangeSize(int64 smallest, int64 biggest, int *width, */ void VideoSystem::BlitText(const uint8 *text, uint32 colour, int xpos, int ypos, int width, Alignment align) { - SDL_Color col = {0, 0, 0}; // Font colour does not matter as only the bitmap is used. + SDL_Color col = {SPLIT_RGBA(colour)}; SDL_Surface *surf = TTF_RenderUTF8_Solid(this->font, (const char *)text, col); if (surf == nullptr) { fprintf(stderr, "Rendering text failed (%s)\n", TTF_GetError()); @@ -769,7 +472,10 @@ void VideoSystem::BlitText(const uint8 *text, uint32 colour, int xpos, int ypos, return; } + SDL_Texture *tex = SDL_CreateTextureFromSurface(this->renderer, surf); + int real_w = std::min(surf->w, width); + switch (align) { case ALG_LEFT: break; @@ -785,44 +491,10 @@ void VideoSystem::BlitText(const uint8 *text, uint32 colour, int xpos, int ypos, default: NOT_REACHED(); } - this->blit_rect.ValidateAddress(); - - uint8 *src = ((uint8 *)surf->pixels); - uint32 *dest = this->blit_rect.address + xpos + ypos * this->blit_rect.pitch; - int h = surf->h; - if (ypos < 0) { - h += ypos; - src -= ypos * surf->pitch; - dest -= ypos * this->blit_rect.pitch; - ypos = 0; - } - while (h > 0) { - if (ypos >= this->blit_rect.height) break; - uint8 *src2 = src; - uint32 *dest2 = dest; - int w = real_w; - int x = xpos; - if (x < 0) { - w += x; - if (w <= 0) break; - dest2 -= x; - src2 -= x; - x = 0; - } - while (w > 0) { - if (x >= this->blit_rect.width) break; - if (*src2 != 0) *dest2 = colour; - src2++; - dest2++; - x++; - w--; - } - ypos++; - src += surf->pitch; - dest += this->blit_rect.pitch; - h--; - } + SDL_Rect sdl_rect = {xpos, ypos, real_w, surf->h}; + SDL_RenderCopy(this->renderer, tex, nullptr, &sdl_rect); + SDL_DestroyTexture(tex); SDL_FreeSurface(surf); } @@ -834,51 +506,8 @@ void VideoSystem::BlitText(const uint8 *text, uint32 colour, int xpos, int ypos, */ void VideoSystem::DrawLine(const Point16 &start, const Point16 &end, uint32 colour) { - int16 dx, inc_x, dy, inc_y; - if (start.x > end.x) { - dx = start.x - end.x; - inc_x = -1; - } else { - dx = end.x - start.x; - inc_x = 1; - } - if (start.y > end.y) { - dy = start.y - end.y; - inc_y = -1; - } else { - dy = end.y - start.y; - inc_y = 1; - } - - int16 step = std::min(dx, dy); - int16 pos_x = start.x; - int16 pos_y = start.y; - int16 sum_x = 0; - int16 sum_y = 0; - - this->blit_rect.ValidateAddress(); - uint32 *dest = this->blit_rect.address + pos_x + pos_y * this->blit_rect.pitch; - - for (;;) { - /* Blit pixel. */ - if (pos_x >= 0 && pos_x < this->blit_rect.width && pos_y >= 0 && pos_y < this->blit_rect.height) { - *dest = colour; - } - if (pos_x == end.x && pos_y == end.y) break; - - sum_x += step; - sum_y += step; - if (sum_x >= dy) { - pos_x += inc_x; - dest += inc_x; - sum_x -= dy; - } - if (sum_y >= dx) { - pos_y += inc_y; - dest += inc_y * this->blit_rect.pitch; - sum_y -= dx; - } - } + SDL_SetRenderDrawColor(this->renderer, SPLIT_RGBA(colour)); + SDL_RenderDrawLine(this->renderer, start.x, start.y, end.x, end.y); } /** @@ -888,14 +517,9 @@ void VideoSystem::DrawLine(const Point16 &start, const Point16 &end, uint32 colo */ void VideoSystem::DrawRectangle(const Rectangle32 &rect, uint32 colour) { - Point16 top_left (static_cast<int16>(rect.base.x), static_cast<int16>(rect.base.y)); - Point16 top_right (static_cast<int16>(rect.base.x + rect.width - 1), static_cast<int16>(rect.base.y)); - Point16 bottom_left (static_cast<int16>(rect.base.x), static_cast<int16>(rect.base.y + rect.height - 1)); - Point16 bottom_right(static_cast<int16>(rect.base.x + rect.width - 1), static_cast<int16>(rect.base.y + rect.height - 1)); - this->DrawLine(top_left, top_right, colour); - this->DrawLine(top_left, bottom_left, colour); - this->DrawLine(top_right, bottom_right, colour); - this->DrawLine(bottom_left, bottom_right, colour); + SDL_Rect sdl_rect = RectToSDLRect(rect); + SDL_SetRenderDrawColor(this->renderer, SPLIT_RGBA(colour)); + SDL_RenderDrawRect(this->renderer, &sdl_rect); } /** @@ -905,22 +529,7 @@ void VideoSystem::DrawRectangle(const Rectangle32 &rect, uint32 colour) */ void VideoSystem::FillRectangle(const Rectangle32 &rect, uint32 colour) { - ClippedRectangle cr = this->GetClippedRectangle(); - - int x = Clamp((int)rect.base.x, 0, (int)cr.width); - int w = Clamp((int)(rect.base.x + rect.width), 0, (int)cr.width); - int y = Clamp((int)rect.base.y, 0, (int)cr.height); - int h = Clamp((int)(rect.base.y + rect.height), 0, (int)cr.height); - - w -= x; - h -= y; - if (w == 0 || h == 0) return; - - uint32 *pixels_base = cr.address + x + y * cr.pitch; - while (h > 0) { - uint32 *pixels = pixels_base; - for (int i = 0; i < w; i++) *pixels++ = colour; - pixels_base += cr.pitch; - h--; - } + SDL_Rect sdl_rect = RectToSDLRect(rect); + SDL_SetRenderDrawColor(this->renderer, SPLIT_RGBA(colour)); + SDL_RenderFillRect(this->renderer, &sdl_rect); } diff --git a/src/video.h b/src/video.h index 9c9c7ba..d3cfd22 100644 --- a/src/video.h +++ b/src/video.h @@ -22,27 +22,6 @@ void QuitProgram(); class ImageData; -/** Clipped rectangle. */ -class ClippedRectangle { -public: - ClippedRectangle(); - ClippedRectangle(uint16 x, uint16 y, uint16 w, uint16 h); - ClippedRectangle(const ClippedRectangle &cr, uint16 x, uint16 y, uint16 w, uint16 h); - - ClippedRectangle(const ClippedRectangle &cr); - ClippedRectangle &operator=(const ClippedRectangle &cr); - - void ValidateAddress(); - - uint16 absx; ///< Absolute X position in the screen of the top-left. - uint16 absy; ///< Absolute Y position in the screen of the top-left. - uint16 width; ///< Number of columns. - uint16 height; ///< Number of rows. - - uint32 *address; ///< Base address. @note Call #ValidateAddress prior to use. - int32 pitch; ///< Pitch of a row in bytes. @note Call #ValidateAddress prior to use. -}; - /** How to align text during drawing. */ enum Alignment { ALG_LEFT, ///< Align to the left edge. @@ -54,19 +33,26 @@ enum Alignment { * Class representing the video system. */ class VideoSystem { - friend class ClippedRectangle; - public: VideoSystem(); ~VideoSystem(); std::string Initialize(const char *font_name, int font_size); bool SetResolution(const Point32 &res); - void GetResolutions(); void MainLoop(); void Shutdown(); /** + * Should only ever be used externally for creating SDL_Textures + * @return The renderer instance. + */ + inline SDL_Renderer *GetRenderer() + { + assert(this->initialized); + return this->renderer; + } + + /** * Get horizontal size of the screen. * @return Number of pixels of the screen horizontally. */ @@ -98,8 +84,16 @@ public: void MarkDisplayDirty(); void MarkDisplayDirty(const Rectangle32 &rect); - void SetClippedRectangle(const ClippedRectangle &cr); - ClippedRectangle GetClippedRectangle(); + /** + * Blit a single sprite. + * @param img_base Coordinates of the sprite data (relative to window). + * @param spr Sprite to blit. + * @param recolour Sprite recolouring definition. + */ + inline void BlitImage(const Point32 &img_base, const ImageData *spr, const Recolouring &recolour) + { + this->BlitImages(img_base, spr, 1, 1, recolour); + } /** * Blit a row of sprites. @@ -127,8 +121,7 @@ public: this->BlitImages({x, ymin}, spr, 1, numy, recolour); } - void BlitImage(const Point32 &img_base, const ImageData *spr, const Recolouring &recolour, GradientShift shift); - void BlitImages(const Point32 &pt, const ImageData *spr, uint16 numx, uint16 numy, const Recolouring &recolour, GradientShift shift = GS_NORMAL); + void BlitImages(const Point32 &pt, const ImageData *spr, uint16 numx, uint16 numy, const Recolouring &recolour); void FinishRepaint(); @@ -141,6 +134,9 @@ public: return this->font_height; } + void SetClippedRectangle(const Rectangle32 &rect); + Rectangle32 GetClippedRectangle(); + void GetTextSize(const uint8 *text, int *width, int *height); void GetNumberRangeSize(int64 smallest, int64 biggest, int *width, int *height); void BlitText(const uint8 *text, uint32 colour, int xpos, int ypos, int width = 0x7FFF, Alignment align = ALG_LEFT); @@ -162,12 +158,20 @@ private: SDL_Window *window; ///< %Window of the application. SDL_Renderer *renderer; ///< GPU renderer to the application window. SDL_Texture *texture; ///< GPU Texture storage of the application window. - uint32 *mem; ///< Memory used for blitting the application display. - ClippedRectangle blit_rect; ///< %Rectangle to blit in. + Rectangle32 blit_rect; Point16 digit_size; ///< Size of largest digit (initially a zero-size). + void GetResolutions(); bool HandleEvent(); void MarkDisplayClean(); + + template<class PZ, class SZ> + SDL_Rect RectToSDLRect(const Rectangle<PZ, SZ> &rect) + { + SDL_Rect sdl_rect = {static_cast<int>(rect.base.x), static_cast<int>(rect.base.y), + static_cast<int>(rect.width), static_cast<int>(rect.height)}; + return sdl_rect; + } }; extern VideoSystem _video; diff --git a/src/viewport.cpp b/src/viewport.cpp index 418b901..3a919a6 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1404,21 +1404,15 @@ void Viewport::OnDraw() collector.Collect(this->additions_enabled && this->additions_displayed); static const Recolouring recolour; - _video.FillRectangle(this->rect, MakeRGBA(0, 0, 0, OPAQUE)); // Black background. - - ClippedRectangle cr = _video.GetClippedRectangle(); - assert(this->rect.base.x >= 0 && this->rect.base.y >= 0); - ClippedRectangle draw_rect(cr, this->rect.base.x, this->rect.base.y, this->rect.width, this->rect.height); - _video.SetClippedRectangle(draw_rect); - - GradientShift gs = static_cast<GradientShift>(GS_LIGHT - _weather.GetWeatherType()); for (const auto &iter : collector.draw_images) { const DrawData &dd = iter; const Recolouring &rec = (dd.recolour == nullptr) ? recolour : *dd.recolour; - _video.BlitImage(dd.base, dd.sprite, rec, gs); + _video.BlitImage(dd.base, dd.sprite, rec); } - _video.SetClippedRectangle(cr); + //GradientShift gs = static_cast<GradientShift>(GS_LIGHT - _weather.GetWeatherType()); + /// \todo Actually change brightness overlay depending on weather + //_video.FillRectangle(this->rect, MakeRGBA(0, 0, 0, 0)); } /** diff --git a/src/widget.cpp b/src/widget.cpp index 376677e..619ae9f 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -292,7 +292,7 @@ void LeafWidget::Draw(const GuiWindow *w) } else if ((this->flags & LWF_PRESSED) != 0) { spr_num += WCS_EMPTY_PRESSED; } - _video.BlitImage({left, top}, _gui_sprites.radio_button.sprites[spr_num], rc, GS_NORMAL); + _video.BlitImage({left, top}, _gui_sprites.radio_button.sprites[spr_num], rc); return; } @@ -319,7 +319,7 @@ void LeafWidget::Draw(const GuiWindow *w) int yoffset = top + (bottom - 1 - top - _gui_sprites.close_sprite->height) / 2; const ImageData *imgdata = _gui_sprites.close_sprite; - if (imgdata != nullptr) _video.BlitImage({xoffset + 1, yoffset + 1}, imgdata, rc, GS_NORMAL); + if (imgdata != nullptr) _video.BlitImage({xoffset + 1, yoffset + 1}, imgdata, rc); /* Closebox is never shaded. */ } } @@ -500,7 +500,7 @@ void DataWidget::Draw(const GuiWindow *w) int xoffset = left + (right + 1 - left - this->value_width) / 2 - rect.base.x; yoffset -= rect.base.y; const ImageData *imgdata = _sprite_manager.GetTableSprite(this->value); - if (imgdata != nullptr) _video.BlitImage({xoffset + pressed, yoffset + pressed}, imgdata, rc, GS_NORMAL); + if (imgdata != nullptr) _video.BlitImage({xoffset + pressed, yoffset + pressed}, imgdata, rc); break; } @@ -513,7 +513,7 @@ void DataWidget::Draw(const GuiWindow *w) if (imgdata != nullptr) { int triangle_yoff = top + (bottom + 1 - top - imgrect.height) / 2 + pressed; - _video.BlitImage({right - imgrect.width + pressed, triangle_yoff}, imgdata, rc, GS_NORMAL); + _video.BlitImage({right - imgrect.width + pressed, triangle_yoff}, imgdata, rc); } /* Note: Reusing the same string parameters from above */ if (this->value != STR_NULL) DrawString(w->TranslateStringNumber(this->value), TEXT_WHITE, left + pressed, yoffset + pressed, right - left - imgrect.width, align); @@ -589,12 +589,12 @@ void ScrollbarWidget::Draw(const GuiWindow *w) Point32 pos(w->GetWidgetScreenX(this), w->GetWidgetScreenY(this)); /* Draw left/up button. */ - _video.BlitImage(pos, imd[WLS_LEFT_BUTTON], rc, GS_NORMAL); + _video.BlitImage(pos, imd[WLS_LEFT_BUTTON], rc); if (this->wtype == WT_HOR_SCROLLBAR) pos.x += imd[WLS_LEFT_BUTTON]->width; if (this->wtype != WT_HOR_SCROLLBAR) pos.y += imd[WLS_LEFT_BUTTON]->height; /* Draw top/left underground. */ - _video.BlitImage(pos, imd[WLS_LEFT_BED], rc, GS_NORMAL); + _video.BlitImage(pos, imd[WLS_LEFT_BED], rc); if (this->wtype == WT_HOR_SCROLLBAR) pos.x += imd[WLS_LEFT_BED]->width; if (this->wtype != WT_HOR_SCROLLBAR) pos.y += imd[WLS_LEFT_BED]->height; @@ -614,7 +614,7 @@ void ScrollbarWidget::Draw(const GuiWindow *w) } /* Draw bottom/right underground. */ - _video.BlitImage(pos, imd[WLS_RIGHT_BED], rc, GS_NORMAL); + _video.BlitImage(pos, imd[WLS_RIGHT_BED], rc); if (this->wtype == WT_HOR_SCROLLBAR) { pos.x += imd[WLS_RIGHT_BED]->width; } else { @@ -622,7 +622,7 @@ void ScrollbarWidget::Draw(const GuiWindow *w) } /* Draw right/bottom button. */ - _video.BlitImage(pos, imd[WLS_RIGHT_BUTTON], rc, GS_NORMAL); + _video.BlitImage(pos, imd[WLS_RIGHT_BUTTON], rc); int start_edge, slider_length; this->CalculateSliderPosition(&start_edge, &slider_length); @@ -634,7 +634,7 @@ void ScrollbarWidget::Draw(const GuiWindow *w) } /* Draw top/left slider. */ - _video.BlitImage(pos, imd[WLS_LEFT_SLIDER], rc, GS_NORMAL); + _video.BlitImage(pos, imd[WLS_LEFT_SLIDER], rc); if (this->wtype == WT_HOR_SCROLLBAR) { pos.x += imd[WLS_LEFT_SLIDER]->width; } else { @@ -653,7 +653,7 @@ void ScrollbarWidget::Draw(const GuiWindow *w) } /* Draw bottom/right slider. */ - _video.BlitImage(pos, imd[WLS_RIGHT_SLIDER], rc, GS_NORMAL); + _video.BlitImage(pos, imd[WLS_RIGHT_SLIDER], rc); } /** diff --git a/src/window.cpp b/src/window.cpp index 641e9a4..9aa534e 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -989,8 +989,8 @@ void UpdateWindows() /* Until the entire background is covered by the main display, clean the entire display to ensure deleted * windows truly disappear (even if there is no other window behind it). */ - Rectangle32 rect(0, 0, _video.GetXSize(), _video.GetYSize()); - _video.FillRectangle(rect, MakeRGBA(0, 0, 0, OPAQUE)); +// Rectangle32 rect(0, 0, _video.GetXSize(), _video.GetYSize()); +// _video.FillRectangle(rect, MakeRGBA(0, 0, 0, OPAQUE)); Window *w = _manager.bottom; while (w != nullptr) {
Mark as private
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year
forever