1 /*****************************************************************************
2  * Copyright (c) 2014-2020 OpenRCT2 developers
3  *
4  * For a complete list of all authors, please refer to contributors.md
5  * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6  *
7  * OpenRCT2 is licensed under the GNU General Public License version 3.
8  *****************************************************************************/
9 
10 #pragma once
11 
12 #include "../common.h"
13 #include "../interface/Colour.h"
14 #include "../interface/ZoomLevel.h"
15 #include "../world/Location.hpp"
16 #include "Font.h"
17 #include "Text.h"
18 
19 #include <memory>
20 #include <optional>
21 #include <vector>
22 
23 struct ScreenCoordsXY;
24 struct ScreenLine;
25 struct ScreenRect;
26 namespace OpenRCT2
27 {
28     struct IPlatformEnvironment;
29 }
30 
31 namespace OpenRCT2::Drawing
32 {
33     struct IDrawingEngine;
34 }
35 
36 struct PaletteBGRA
37 {
38     uint8_t Blue{};
39     uint8_t Green{};
40     uint8_t Red{};
41     uint8_t Alpha{};
42 };
43 
44 constexpr const auto PALETTE_SIZE = 256;
45 
46 struct GamePalette
47 {
48     PaletteBGRA Colour[PALETTE_SIZE]{};
49 
50     PaletteBGRA& operator[](uint16_t idx)
51     {
52         assert(idx < PALETTE_SIZE);
53         if (idx >= PALETTE_SIZE)
54         {
55             static PaletteBGRA dummy;
56             return dummy;
57         }
58 
59         return Colour[idx];
60     }
61 
62     const PaletteBGRA operator[](uint16_t idx) const
63     {
64         assert(idx < PALETTE_SIZE);
65         if (idx >= PALETTE_SIZE)
66             return {};
67 
68         return Colour[idx];
69     }
70 
71     explicit operator uint8_t*()
72     {
73         return reinterpret_cast<uint8_t*>(Colour);
74     }
75 };
76 
77 struct rct_g1_element
78 {
79     uint8_t* offset;       // 0x00
80     int16_t width;         // 0x04
81     int16_t height;        // 0x06
82     int16_t x_offset;      // 0x08
83     int16_t y_offset;      // 0x0A
84     uint16_t flags;        // 0x0C
85     int32_t zoomed_offset; // 0x0E
86 };
87 
88 #pragma pack(push, 1)
89 struct rct_g1_header
90 {
91     uint32_t num_entries;
92     uint32_t total_size;
93 };
94 assert_struct_size(rct_g1_header, 8);
95 #pragma pack(pop)
96 
97 struct rct_gx
98 {
99     rct_g1_header header;
100     std::vector<rct_g1_element> elements;
101     std::unique_ptr<uint8_t[]> data;
102 };
103 
104 struct rct_drawpixelinfo
105 {
106     uint8_t* bits{};
107     int32_t x{};
108     int32_t y{};
109     int32_t width{};
110     int32_t height{};
111     int32_t pitch{}; // note: this is actually (pitch - width)
112     ZoomLevel zoom_level{};
113 
114     /**
115      * As x and y are based on 1:1 units, zooming in will cause a reduction in precision when mapping zoomed-in
116      * pixels to 1:1 pixels. When x, y are not a multiple of the zoom level, the remainder will be non-zero.
117      * The drawing of sprites will need to be offset by this amount.
118      */
119     uint8_t remX{};
120     uint8_t remY{};
121 
122     // Last position of drawn text.
123     ScreenCoordsXY lastStringPos{};
124 
125     OpenRCT2::Drawing::IDrawingEngine* DrawingEngine{};
126 
127     size_t GetBytesPerRow() const;
128     uint8_t* GetBitsOffset(const ScreenCoordsXY& pos) const;
129     rct_drawpixelinfo Crop(const ScreenCoordsXY& pos, const ScreenSize& size) const;
130 };
131 
132 struct rct_g1_element_32bit
133 {
134     uint32_t offset;        // 0x00 note: uint32_t always!
135     int16_t width;          // 0x04
136     int16_t height;         // 0x06
137     int16_t x_offset;       // 0x08
138     int16_t y_offset;       // 0x0A
139     uint16_t flags;         // 0x0C
140     uint16_t zoomed_offset; // 0x0E
141 };
142 assert_struct_size(rct_g1_element_32bit, 0x10);
143 
144 enum
145 {
146     G1_FLAG_BMP = (1 << 0), // Image data is encoded as raw pixels (no transparency)
147     G1_FLAG_1 = (1 << 1),
148     G1_FLAG_RLE_COMPRESSION = (1 << 2), // Image data is encoded using RCT2's form of run length encoding
149     G1_FLAG_PALETTE = (1 << 3),         // Image data is a sequence of palette entries R8G8B8
150     G1_FLAG_HAS_ZOOM_SPRITE = (1 << 4), // Use a different sprite for higher zoom levels
151     G1_FLAG_NO_ZOOM_DRAW = (1 << 5),    // Does not get drawn at higher zoom levels (only zoom 0)
152 };
153 
154 enum : uint32_t
155 {
156     IMAGE_TYPE_DEFAULT = 0,
157     IMAGE_TYPE_REMAP = (1 << 29),
158     IMAGE_TYPE_TRANSPARENT = (1 << 30),
159     IMAGE_TYPE_REMAP_2_PLUS = (1u << 31)
160     // REMAP_2_PLUS + REMAP = REMAP 2
161     // REMAP_2_PLUS = REMAP 3
162 };
163 
164 using DrawBlendOp = uint8_t;
165 
166 constexpr DrawBlendOp BLEND_NONE = 0;
167 
168 /**
169  * Only supported by BITMAP. RLE images always encode transparency via the encoding.
170  * Pixel value of 0 represents transparent.
171  */
172 constexpr DrawBlendOp BLEND_TRANSPARENT = 1 << 0;
173 
174 /**
175  * Whether to use the pixel value from the source image.
176  * This is usually only unset for glass images where there the src is only a transparency mask.
177  */
178 constexpr DrawBlendOp BLEND_SRC = 1 << 1;
179 
180 /**
181  * Whether to use the pixel value of the destination image for blending.
182  * This is used for any image that filters the target image, e.g. glass or water.
183  */
184 constexpr DrawBlendOp BLEND_DST = 2 << 2;
185 
186 enum
187 {
188     INSET_RECT_FLAG_FILL_GREY = (1 << 2),         // 0x04
189     INSET_RECT_FLAG_BORDER_NONE = (1 << 3),       // 0x08
190     INSET_RECT_FLAG_FILL_NONE = (1 << 4),         // 0x10
191     INSET_RECT_FLAG_BORDER_INSET = (1 << 5),      // 0x20
192     INSET_RECT_FLAG_FILL_DONT_LIGHTEN = (1 << 6), // 0x40
193     INSET_RECT_FLAG_FILL_MID_LIGHT = (1 << 7),    // 0x80
194 };
195 
196 enum class FilterPaletteID : int32_t
197 {
198     PaletteNull = 0,
199 
200     PaletteWater = 32,
201 
202     Palette34 = 34,
203 
204     Palette45 = 45, // Decolourise + lighten
205     Palette46 = 46,
206 
207     PaletteDarken3 = 47,
208 
209     PaletteDarken1 = 49,
210     PaletteDarken2 = 50,
211     Palette51 = 51, // Decolourise + darken
212     PaletteTranslucentGrey = 52,
213     PaletteTranslucentGreyHighlight = 53,
214     PaletteTranslucentGreyShadow = 54,
215     PaletteTranslucentLightBlue = 55,
216     PaletteTranslucentLightBlueHighlight = 56,
217     PaletteTranslucentLightBlueShadow = 57,
218     PaletteTranslucentBordeauxRed = 58,
219     PaletteTranslucentBordeauxRedHighlight = 59,
220     PaletteTranslucentBordeauxRedShadow = 60,
221     PaletteTranslucentDarkGreen = 61,
222     PaletteTranslucentDarkGreenHighlight = 62,
223     PaletteTranslucentDarkGreenShadow = 63,
224     PaletteTranslucentLightPurple = 64,
225     PaletteTranslucentLightPurpleHighlight = 65,
226     PaletteTranslucentLightPurpleShadow = 66,
227     PaletteTranslucentDarkOliveGreen = 67,
228     PaletteTranslucentDarkOliveGreenHighlight = 68,
229     PaletteTranslucentDarkOliveGreenShadow = 69,
230     PaletteTranslucentLightBrown = 70,
231     PaletteTranslucentLightBrownHighlight = 71,
232     PaletteTranslucentLightBrownShadow = 72,
233     PaletteTranslucentYellow = 73,
234     PaletteTranslucentYellowHighlight = 74,
235     PaletteTranslucentYellowShadow = 75,
236     PaletteTranslucentMossGreen = 76,
237     PaletteTranslucentMossGreenHighlight = 77,
238     PaletteTranslucentMossGreenShadow = 78,
239     PaletteTranslucentOliveGreen = 79,
240     PaletteTranslucentOliveGreenHighlight = 80,
241     PaletteTranslucentOliveGreenShadow = 81,
242     PaletteTranslucentBrightGreen = 82,
243     PaletteTranslucentBrightGreenHighlight = 83,
244     PaletteTranslucentBrightGreenShadow = 84,
245     PaletteTranslucentSalmonPink = 85,
246     PaletteTranslucentSalmonPinkHighlight = 86,
247     PaletteTranslucentSalmonPinkShadow = 87,
248     PaletteTranslucentBrightPurple = 88,
249     PaletteTranslucentBrightPurpleHighlight = 89,
250     PaletteTranslucentBrightPurpleShadow = 90,
251     PaletteTranslucentBrightRed = 91,
252     PaletteTranslucentBrightRedHighlight = 92,
253     PaletteTranslucentBrightRedShadow = 93,
254     PaletteTranslucentLightOrange = 94,
255     PaletteTranslucentLightOrangeHighlight = 95,
256     PaletteTranslucentLightOrangeShadow = 96,
257     PaletteTranslucentTeal = 97,
258     PaletteTranslucentTealHighlight = 98,
259     PaletteTranslucentTealShadow = 99,
260     PaletteTranslucentBrightPink = 100,
261     PaletteTranslucentBrightPinkHighlight = 101,
262     PaletteTranslucentBrightPinkShadow = 102,
263     PaletteTranslucentDarkBrown = 103,
264     PaletteTranslucentDarkBrownHighlight = 104,
265     PaletteTranslucentDarkBrownShadow = 105,
266     PaletteTranslucentLightPink = 106,
267     PaletteTranslucentLightPinkHighlight = 107,
268     PaletteTranslucentLightPinkShadow = 108,
269     PaletteTranslucentWhite = 109,
270     PaletteTranslucentWhiteHighlight = 110,
271     PaletteTranslucentWhiteShadow = 111,
272     PaletteGlass = 112,
273     PaletteGlassBlack = PaletteGlass + COLOUR_BLACK,
274     PaletteGlassGrey = PaletteGlass + COLOUR_GREY,
275     PaletteGlassWhite = PaletteGlass + COLOUR_WHITE,
276     PaletteGlassDarkPurple = PaletteGlass + COLOUR_DARK_PURPLE,
277     PaletteGlassLightPurple = PaletteGlass + COLOUR_LIGHT_PURPLE,
278     PaletteGlassBrightPurple = PaletteGlass + COLOUR_BRIGHT_PURPLE,
279     PaletteGlassDarkBlue = PaletteGlass + COLOUR_DARK_BLUE,
280     PaletteGlassLightBlue = PaletteGlass + COLOUR_LIGHT_BLUE,
281     PaletteGlassIcyBlue = PaletteGlass + COLOUR_ICY_BLUE,
282     PaletteGlassTeal = PaletteGlass + COLOUR_TEAL,
283     PaletteGlassAquamarine = PaletteGlass + COLOUR_AQUAMARINE,
284     PaletteGlassSaturatedGreen = PaletteGlass + COLOUR_SATURATED_GREEN,
285     PaletteGlassDarkGreen = PaletteGlass + COLOUR_DARK_GREEN,
286     PaletteGlassMossGreen = PaletteGlass + COLOUR_MOSS_GREEN,
287     PaletteGlassBrightGreen = PaletteGlass + COLOUR_BRIGHT_GREEN,
288     PaletteGlassOliveGreen = PaletteGlass + COLOUR_OLIVE_GREEN,
289     PaletteGlassDarkOliveGreen = PaletteGlass + COLOUR_DARK_OLIVE_GREEN,
290     PaletteGlassBrightYellow = PaletteGlass + COLOUR_BRIGHT_YELLOW,
291     PaletteGlassYellow = PaletteGlass + COLOUR_YELLOW,
292     PaletteGlassDarkYellow = PaletteGlass + COLOUR_DARK_YELLOW,
293     PaletteGlassLightOrange = PaletteGlass + COLOUR_LIGHT_ORANGE,
294     PaletteGlassDarkOrange = PaletteGlass + COLOUR_DARK_ORANGE,
295     PaletteGlassLightBrown = PaletteGlass + COLOUR_LIGHT_BROWN,
296     PaletteGlassSaturatedBrown = PaletteGlass + COLOUR_SATURATED_BROWN,
297     PaletteGlassDarkBrown = PaletteGlass + COLOUR_DARK_BROWN,
298     PaletteGlassSalmonPink = PaletteGlass + COLOUR_SALMON_PINK,
299     PaletteGlassBordeauxRed = PaletteGlass + COLOUR_BORDEAUX_RED,
300     PaletteGlassSaturatedRed = PaletteGlass + COLOUR_SATURATED_RED,
301     PaletteGlassBrightRed = PaletteGlass + COLOUR_BRIGHT_RED,
302     PaletteGlassDarkPink = PaletteGlass + COLOUR_DARK_PINK,
303     PaletteGlassBrightPink = PaletteGlass + COLOUR_BRIGHT_PINK,
304     PaletteGlassLightPink = PaletteGlass + COLOUR_LIGHT_PINK,
305 };
306 
307 struct translucent_window_palette
308 {
309     FilterPaletteID base;
310     FilterPaletteID highlight;
311     FilterPaletteID shadow;
312 };
313 
314 struct rct_size16
315 {
316     int16_t width;
317     int16_t height;
318 };
319 
320 enum class ImageCatalogue
321 {
322     UNKNOWN,
323     G1,
324     G2,
325     CSG,
326     OBJECT,
327     TEMPORARY,
328 };
329 
330 /**
331  * Represents a specific image from a catalogue such as G1, G2, CSG etc. with remap
332  * colours and flags.
333  *
334  * This is currently all stored as a single 32-bit integer, but will allow easy
335  * extension to 64-bits or higher so that more images can be used.
336  */
337 struct ImageId
338 {
339 private:
340     // clang-format off
341     static constexpr uint32_t MASK_INDEX       = 0b00000000000001111111111111111111;
342     static constexpr uint32_t MASK_REMAP       = 0b00000111111110000000000000000000;
343     static constexpr uint32_t MASK_PRIMARY     = 0b00000000111110000000000000000000;
344     static constexpr uint32_t MASK_SECONDARY   = 0b00011111000000000000000000000000;
345     static constexpr uint32_t FLAG_PRIMARY     = 0b00100000000000000000000000000000;
346     static constexpr uint32_t FLAG_BLEND       = 0b01000000000000000000000000000000;
347     static constexpr uint32_t FLAG_SECONDARY   = 0b10000000000000000000000000000000;
348     static constexpr uint32_t SHIFT_REMAP      = 19;
349     static constexpr uint32_t SHIFT_PRIMARY    = 19;
350     static constexpr uint32_t SHIFT_SECONDARY  = 24;
351     static constexpr uint32_t INDEX_UNDEFINED  = 0b00000000000001111111111111111111;
352     static constexpr uint32_t VALUE_UNDEFINED  = INDEX_UNDEFINED;
353     // clang-format on
354 
355     uint32_t _value = VALUE_UNDEFINED;
356     uint8_t _tertiary = 0;
357 
358 public:
FromUInt32ImageId359     static ImageId FromUInt32(uint32_t value)
360     {
361         ImageId result;
362         result._value = value;
363         return result;
364     }
365 
FromUInt32ImageId366     static ImageId FromUInt32(uint32_t value, uint32_t tertiary)
367     {
368         ImageId result;
369         result._value = value;
370         result._tertiary = tertiary & 0xFF;
371         return result;
372     }
373 
374     ImageId() = default;
375 
ImageIdImageId376     explicit constexpr ImageId(uint32_t index)
377         : _value(index & MASK_INDEX)
378     {
379     }
380 
ImageIdImageId381     constexpr ImageId(uint32_t index, uint8_t primaryColourOrPalette)
382         : ImageId(ImageId(index).WithPrimary(primaryColourOrPalette))
383     {
384     }
385 
ImageIdImageId386     constexpr ImageId(uint32_t index, colour_t primaryColour, colour_t secondaryColour)
387         : ImageId(ImageId(index).WithPrimary(primaryColour).WithSecondary(secondaryColour))
388     {
389     }
390 
ImageIdImageId391     constexpr ImageId(uint32_t index, colour_t primaryColour, colour_t secondaryColour, colour_t tertiaryColour)
392         : ImageId(ImageId(index).WithPrimary(primaryColour).WithSecondary(secondaryColour).WithTertiary(tertiaryColour))
393     {
394     }
395 
ToUInt32ImageId396     uint32_t ToUInt32() const
397     {
398         return _value;
399     }
400 
HasValueImageId401     bool HasValue() const
402     {
403         return GetIndex() != INDEX_UNDEFINED;
404     }
405 
HasPrimaryImageId406     bool HasPrimary() const
407     {
408         return (_value & FLAG_PRIMARY) || (_value & FLAG_SECONDARY);
409     }
410 
HasSecondaryImageId411     bool HasSecondary() const
412     {
413         return _value & FLAG_SECONDARY;
414     }
415 
HasTertiaryImageId416     bool HasTertiary() const
417     {
418         return !(_value & FLAG_PRIMARY) && (_value & FLAG_SECONDARY);
419     }
420 
IsRemapImageId421     bool IsRemap() const
422     {
423         return (_value & FLAG_PRIMARY) && !(_value & FLAG_SECONDARY);
424     }
425 
IsBlendedImageId426     bool IsBlended() const
427     {
428         return _value & FLAG_BLEND;
429     }
430 
GetIndexImageId431     uint32_t GetIndex() const
432     {
433         return _value & MASK_INDEX;
434     }
435 
GetRemapImageId436     uint8_t GetRemap() const
437     {
438         return (_value & MASK_REMAP) >> SHIFT_REMAP;
439     }
440 
GetPrimaryImageId441     colour_t GetPrimary() const
442     {
443         return (_value & MASK_PRIMARY) >> SHIFT_PRIMARY;
444     }
445 
GetSecondaryImageId446     colour_t GetSecondary() const
447     {
448         return (_value & MASK_SECONDARY) >> SHIFT_SECONDARY;
449     }
450 
GetTertiaryImageId451     colour_t GetTertiary() const
452     {
453         return _tertiary;
454     }
455 
456     ImageCatalogue GetCatalogue() const;
457 
WithIndexImageId458     constexpr ImageId WithIndex(uint32_t index)
459     {
460         ImageId result = *this;
461         result._value = (_value & ~MASK_INDEX) | (index & MASK_INDEX);
462         return result;
463     }
464 
WithRemapImageId465     constexpr ImageId WithRemap(uint8_t paletteId)
466     {
467         ImageId result = *this;
468         result._value = (_value & ~MASK_REMAP) | ((paletteId << SHIFT_REMAP) & MASK_REMAP) | FLAG_PRIMARY;
469         return result;
470     }
471 
WithPrimaryImageId472     constexpr ImageId WithPrimary(colour_t colour)
473     {
474         ImageId result = *this;
475         result._value = (_value & ~MASK_PRIMARY) | ((colour << SHIFT_PRIMARY) & MASK_PRIMARY) | FLAG_PRIMARY;
476         return result;
477     }
478 
WithSecondaryImageId479     constexpr ImageId WithSecondary(colour_t colour)
480     {
481         ImageId result = *this;
482         result._value = (_value & ~MASK_SECONDARY) | ((colour << SHIFT_SECONDARY) & MASK_SECONDARY) | FLAG_SECONDARY;
483         return result;
484     }
485 
WithTertiaryImageId486     constexpr ImageId WithTertiary(colour_t tertiary)
487     {
488         ImageId result = *this;
489         result._value &= ~FLAG_PRIMARY;
490         if (!(_value & FLAG_SECONDARY))
491         {
492             // Tertiary implies primary and secondary, so if colour was remap (8-bit primary) then
493             // we need to zero the secondary colour.
494             result._value &= ~MASK_SECONDARY;
495             result._value |= FLAG_SECONDARY;
496         }
497         result._tertiary = tertiary;
498         return result;
499     }
500 };
501 
502 /**
503  * Represents an 8-bit indexed map that maps from one palette index to another.
504  */
505 struct PaletteMap
506 {
507 private:
508     uint8_t* _data{};
509     uint32_t _dataLength{};
510 #pragma clang diagnostic push
511 #pragma clang diagnostic ignored "-Wunused-private-field"
512     uint16_t _numMaps;
513 #pragma clang diagnostic pop
514     uint16_t _mapLength;
515 
516 public:
517     static const PaletteMap& GetDefault();
518 
519     PaletteMap() = default;
520 
PaletteMapPaletteMap521     PaletteMap(uint8_t* data, uint16_t numMaps, uint16_t mapLength)
522         : _data(data)
523         , _dataLength(numMaps * mapLength)
524         , _numMaps(numMaps)
525         , _mapLength(mapLength)
526     {
527     }
528 
529     template<std::size_t TSize>
PaletteMapPaletteMap530     PaletteMap(uint8_t (&map)[TSize])
531         : _data(map)
532         , _dataLength(static_cast<uint32_t>(std::size(map)))
533         , _numMaps(1)
534         , _mapLength(static_cast<uint16_t>(std::size(map)))
535     {
536     }
537 
538     uint8_t& operator[](size_t index);
539     uint8_t operator[](size_t index) const;
540     uint8_t Blend(uint8_t src, uint8_t dst) const;
541     void Copy(size_t dstIndex, const PaletteMap& src, size_t srcIndex, size_t length);
542 };
543 
544 struct DrawSpriteArgs
545 {
546     ImageId Image;
547     const PaletteMap& PalMap;
548     const rct_g1_element& SourceImage;
549     int32_t SrcX;
550     int32_t SrcY;
551     int32_t Width;
552     int32_t Height;
553     uint8_t* DestinationBits;
554 
DrawSpriteArgsDrawSpriteArgs555     DrawSpriteArgs(
556         ImageId image, const PaletteMap& palMap, const rct_g1_element& sourceImage, int32_t srcX, int32_t srcY, int32_t width,
557         int32_t height, uint8_t* destinationBits)
558         : Image(image)
559         , PalMap(palMap)
560         , SourceImage(sourceImage)
561         , SrcX(srcX)
562         , SrcY(srcY)
563         , Width(width)
564         , Height(height)
565         , DestinationBits(destinationBits)
566     {
567     }
568 };
569 
BlitPixel(const uint8_t * src,uint8_t * dst,const PaletteMap & paletteMap)570 template<DrawBlendOp TBlendOp> bool FASTCALL BlitPixel(const uint8_t* src, uint8_t* dst, const PaletteMap& paletteMap)
571 {
572     if constexpr (TBlendOp & BLEND_TRANSPARENT)
573     {
574         // Ignore transparent pixels
575         if (*src == 0)
576         {
577             return false;
578         }
579     }
580 
581     if constexpr (((TBlendOp & BLEND_SRC) != 0) && ((TBlendOp & BLEND_DST) != 0))
582     {
583         auto pixel = paletteMap.Blend(*src, *dst);
584         if constexpr (TBlendOp & BLEND_TRANSPARENT)
585         {
586             if (pixel == 0)
587             {
588                 return false;
589             }
590         }
591         *dst = pixel;
592         return true;
593     }
594     else if constexpr ((TBlendOp & BLEND_SRC) != 0)
595     {
596         auto pixel = paletteMap[*src];
597         if constexpr (TBlendOp & BLEND_TRANSPARENT)
598         {
599             if (pixel == 0)
600             {
601                 return false;
602             }
603         }
604         *dst = pixel;
605         return true;
606     }
607     else if constexpr ((TBlendOp & BLEND_DST) != 0)
608     {
609         auto pixel = paletteMap[*dst];
610         if constexpr (TBlendOp & BLEND_TRANSPARENT)
611         {
612             if (pixel == 0)
613             {
614                 return false;
615             }
616         }
617         *dst = pixel;
618         return true;
619     }
620     else
621     {
622         *dst = *src;
623         return true;
624     }
625 }
626 
627 template<DrawBlendOp TBlendOp>
BlitPixels(const uint8_t * src,uint8_t * dst,const PaletteMap & paletteMap,uint8_t zoom,size_t dstPitch)628 void FASTCALL BlitPixels(const uint8_t* src, uint8_t* dst, const PaletteMap& paletteMap, uint8_t zoom, size_t dstPitch)
629 {
630     auto yDstSkip = dstPitch - zoom;
631     for (uint8_t yy = 0; yy < zoom; yy++)
632     {
633         for (uint8_t xx = 0; xx < zoom; xx++)
634         {
635             BlitPixel<TBlendOp>(src, dst, paletteMap);
636             dst++;
637         }
638         dst += yDstSkip;
639     }
640 }
641 
642 #define SPRITE_ID_PALETTE_COLOUR_1(colourId) (IMAGE_TYPE_REMAP | ((colourId) << 19))
643 #define SPRITE_ID_PALETTE_COLOUR_2(primaryId, secondaryId)                                                                     \
644     (IMAGE_TYPE_REMAP_2_PLUS | IMAGE_TYPE_REMAP | (((primaryId) << 19) | ((secondaryId) << 24)))
645 #define SPRITE_ID_PALETTE_COLOUR_3(primaryId, secondaryId)                                                                     \
646     (IMAGE_TYPE_REMAP_2_PLUS | (((primaryId) << 19) | ((secondaryId) << 24)))
647 
648 #define PALETTE_TO_G1_OFFSET_COUNT 144
649 
650 #define INSET_RECT_F_30 (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_NONE)
651 #define INSET_RECT_F_60 (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_DONT_LIGHTEN)
652 #define INSET_RECT_F_E0 (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_DONT_LIGHTEN | INSET_RECT_FLAG_FILL_MID_LIGHT)
653 
654 #define MAX_SCROLLING_TEXT_MODES 38
655 
656 extern GamePalette gPalette;
657 extern uint8_t gGamePalette[256 * 4];
658 extern uint32_t gPaletteEffectFrame;
659 extern const FilterPaletteID GlassPaletteIds[COLOUR_COUNT];
660 extern thread_local uint8_t gPeepPalette[256];
661 extern thread_local uint8_t gOtherPalette[256];
662 extern uint8_t text_palette[];
663 extern const translucent_window_palette TranslucentWindowPalettes[COLOUR_COUNT];
664 
665 extern uint32_t gPickupPeepImage;
666 extern int32_t gPickupPeepX;
667 extern int32_t gPickupPeepY;
668 
669 extern bool gTinyFontAntiAliased;
670 
671 bool clip_drawpixelinfo(
672     rct_drawpixelinfo* dst, rct_drawpixelinfo* src, const ScreenCoordsXY& coords, int32_t width, int32_t height);
673 void gfx_set_dirty_blocks(const ScreenRect& rect);
674 void gfx_invalidate_screen();
675 
676 // palette
677 void gfx_transpose_palette(int32_t pal, uint8_t product);
678 void load_palette();
679 
680 // other
681 void gfx_clear(rct_drawpixelinfo* dpi, uint8_t paletteIndex);
682 void gfx_filter_pixel(rct_drawpixelinfo* dpi, const ScreenCoordsXY& coords, FilterPaletteID palette);
683 void gfx_invalidate_pickedup_peep();
684 void gfx_draw_pickedup_peep(rct_drawpixelinfo* dpi);
685 
686 // line
687 void gfx_draw_line(rct_drawpixelinfo* dpi, const ScreenLine& line, int32_t colour);
688 void gfx_draw_line_software(rct_drawpixelinfo* dpi, const ScreenLine& line, int32_t colour);
689 void gfx_draw_dashed_line(
690     rct_drawpixelinfo* dpi, const ScreenLine& screenLine, const int32_t dashedLineSegmentLength, const int32_t color);
691 
692 // rect
693 void gfx_fill_rect(rct_drawpixelinfo* dpi, const ScreenRect& rect, int32_t colour);
694 void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, const ScreenRect& rect, int32_t colour, uint8_t flags);
695 void gfx_filter_rect(rct_drawpixelinfo* dpi, const ScreenRect& rect, FilterPaletteID palette);
696 
697 // sprite
698 bool gfx_load_g1(const OpenRCT2::IPlatformEnvironment& env);
699 bool gfx_load_g2();
700 bool gfx_load_csg();
701 void gfx_unload_g1();
702 void gfx_unload_g2();
703 void gfx_unload_csg();
704 const rct_g1_element* gfx_get_g1_element(ImageId imageId);
705 const rct_g1_element* gfx_get_g1_element(int32_t image_id);
706 void gfx_set_g1_element(int32_t imageId, const rct_g1_element* g1);
707 bool is_csg_loaded();
708 uint32_t gfx_object_allocate_images(const rct_g1_element* images, uint32_t count);
709 void gfx_object_free_images(uint32_t baseImageId, uint32_t count);
710 void gfx_object_check_all_images_freed();
711 size_t ImageListGetUsedCount();
712 size_t ImageListGetMaximum();
713 void FASTCALL gfx_sprite_to_buffer(rct_drawpixelinfo& dpi, const DrawSpriteArgs& args);
714 void FASTCALL gfx_bmp_sprite_to_buffer(rct_drawpixelinfo& dpi, const DrawSpriteArgs& args);
715 void FASTCALL gfx_rle_sprite_to_buffer(rct_drawpixelinfo& dpi, const DrawSpriteArgs& args);
716 void FASTCALL gfx_draw_sprite(rct_drawpixelinfo* dpi, ImageId image_id, const ScreenCoordsXY& coords);
717 void FASTCALL gfx_draw_sprite(rct_drawpixelinfo* dpi, int32_t image_id, const ScreenCoordsXY& coords, uint32_t tertiary_colour);
718 void FASTCALL
719     gfx_draw_glyph(rct_drawpixelinfo* dpi, int32_t image_id, const ScreenCoordsXY& coords, const PaletteMap& paletteMap);
720 void FASTCALL
721     gfx_draw_sprite_raw_masked(rct_drawpixelinfo* dpi, const ScreenCoordsXY& coords, int32_t maskImage, int32_t colourImage);
722 void FASTCALL gfx_draw_sprite_solid(rct_drawpixelinfo* dpi, int32_t image, const ScreenCoordsXY& coords, uint8_t colour);
723 
724 void FASTCALL gfx_draw_sprite_software(rct_drawpixelinfo* dpi, ImageId imageId, const ScreenCoordsXY& spriteCoords);
725 void FASTCALL gfx_draw_sprite_palette_set_software(
726     rct_drawpixelinfo* dpi, ImageId imageId, const ScreenCoordsXY& coords, const PaletteMap& paletteMap);
727 void FASTCALL gfx_draw_sprite_raw_masked_software(
728     rct_drawpixelinfo* dpi, const ScreenCoordsXY& scrCoords, int32_t maskImage, int32_t colourImage);
729 
730 // string
731 void gfx_draw_string(rct_drawpixelinfo* dpi, const ScreenCoordsXY& coords, const_utf8string buffer, TextPaint textPaint = {});
732 void gfx_draw_string_no_formatting(
733     rct_drawpixelinfo* dpi, const ScreenCoordsXY& coords, const_utf8string buffer, TextPaint textPaint);
734 
735 void gfx_draw_string_left_centred(
736     rct_drawpixelinfo* dpi, rct_string_id format, void* args, colour_t colour, const ScreenCoordsXY& coords);
737 void draw_string_centred_raw(
738     rct_drawpixelinfo* dpi, const ScreenCoordsXY& coords, int32_t numLines, char* text, FontSpriteBase fontSpriteBase);
739 void DrawNewsTicker(
740     rct_drawpixelinfo* dpi, const ScreenCoordsXY& coords, int32_t width, colour_t colour, rct_string_id format, void* args,
741     int32_t ticks);
742 void gfx_draw_string_with_y_offsets(
743     rct_drawpixelinfo* dpi, const utf8* text, int32_t colour, const ScreenCoordsXY& coords, const int8_t* yOffsets,
744     bool forceSpriteFont, FontSpriteBase fontSpriteBase);
745 
746 int32_t gfx_wrap_string(char* buffer, int32_t width, FontSpriteBase fontSpriteBase, int32_t* num_lines);
747 int32_t gfx_get_string_width(std::string_view text, FontSpriteBase fontSpriteBase);
748 int32_t gfx_get_string_width_new_lined(std::string_view text, FontSpriteBase fontSpriteBase);
749 int32_t gfx_get_string_width_no_formatting(std::string_view text, FontSpriteBase fontSpriteBase);
750 int32_t string_get_height_raw(std::string_view text, FontSpriteBase fontBase);
751 int32_t gfx_clip_string(char* buffer, int32_t width, FontSpriteBase fontSpriteBase);
752 void shorten_path(utf8* buffer, size_t bufferSize, const utf8* path, int32_t availableWidth, FontSpriteBase fontSpriteBase);
753 void ttf_draw_string(
754     rct_drawpixelinfo* dpi, const_utf8string text, int32_t colour, const ScreenCoordsXY& coords, bool noFormatting,
755     FontSpriteBase fontSpriteBase);
756 
757 // scrolling text
758 void scrolling_text_initialise_bitmaps();
759 void scrolling_text_invalidate();
760 
761 class Formatter;
762 
763 int32_t scrolling_text_setup(
764     struct paint_session* session, rct_string_id stringId, Formatter& ft, uint16_t scroll, uint16_t scrollingMode,
765     colour_t colour);
766 
767 rct_size16 FASTCALL gfx_get_sprite_size(uint32_t image_id);
768 size_t g1_calculate_data_size(const rct_g1_element* g1);
769 
770 void mask_scalar(
771     int32_t width, int32_t height, const uint8_t* RESTRICT maskSrc, const uint8_t* RESTRICT colourSrc, uint8_t* RESTRICT dst,
772     int32_t maskWrap, int32_t colourWrap, int32_t dstWrap);
773 void mask_sse4_1(
774     int32_t width, int32_t height, const uint8_t* RESTRICT maskSrc, const uint8_t* RESTRICT colourSrc, uint8_t* RESTRICT dst,
775     int32_t maskWrap, int32_t colourWrap, int32_t dstWrap);
776 void mask_avx2(
777     int32_t width, int32_t height, const uint8_t* RESTRICT maskSrc, const uint8_t* RESTRICT colourSrc, uint8_t* RESTRICT dst,
778     int32_t maskWrap, int32_t colourWrap, int32_t dstWrap);
779 void mask_init();
780 
781 extern void (*mask_fn)(
782     int32_t width, int32_t height, const uint8_t* RESTRICT maskSrc, const uint8_t* RESTRICT colourSrc, uint8_t* RESTRICT dst,
783     int32_t maskWrap, int32_t colourWrap, int32_t dstWrap);
784 
785 std::optional<uint32_t> GetPaletteG1Index(colour_t paletteId);
786 std::optional<PaletteMap> GetPaletteMapForColour(colour_t paletteId);
787 
788 #include "NewDrawing.h"
789