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