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 #include "Drawing.h"
11 
12 #include "../Context.h"
13 #include "../OpenRCT2.h"
14 #include "../common.h"
15 #include "../core/Guard.hpp"
16 #include "../object/Object.h"
17 #include "../platform/platform.h"
18 #include "../sprites.h"
19 #include "../util/Util.h"
20 #include "../world/Location.hpp"
21 #include "../world/Water.h"
22 
23 #include <cstring>
24 
GetDefault()25 const PaletteMap& PaletteMap::GetDefault()
26 {
27     static bool initialised = false;
28     static uint8_t data[256];
29     static PaletteMap defaultMap(data);
30     if (!initialised)
31     {
32         for (size_t i = 0; i < sizeof(data); i++)
33         {
34             data[i] = static_cast<uint8_t>(i);
35         }
36     }
37     return defaultMap;
38 }
39 
operator [](size_t index)40 uint8_t& PaletteMap::operator[](size_t index)
41 {
42     assert(index < _dataLength);
43 
44     // Provide safety in release builds
45     if (index >= _dataLength)
46     {
47         static uint8_t dummy;
48         return dummy;
49     }
50 
51     return _data[index];
52 }
53 
operator [](size_t index) const54 uint8_t PaletteMap::operator[](size_t index) const
55 {
56     assert(index < _dataLength);
57 
58     // Provide safety in release builds
59     if (index >= _dataLength)
60     {
61         return 0;
62     }
63 
64     return _data[index];
65 }
66 
Blend(uint8_t src,uint8_t dst) const67 uint8_t PaletteMap::Blend(uint8_t src, uint8_t dst) const
68 {
69     // src = 0 would be transparent so there is no blend palette for that, hence (src - 1)
70     assert(src != 0 && (src - 1) < _numMaps);
71     assert(dst < _mapLength);
72     auto idx = ((src - 1) * 256) + dst;
73     return (*this)[idx];
74 }
75 
Copy(size_t dstIndex,const PaletteMap & src,size_t srcIndex,size_t length)76 void PaletteMap::Copy(size_t dstIndex, const PaletteMap& src, size_t srcIndex, size_t length)
77 {
78     auto maxLength = std::min(_mapLength - srcIndex, _mapLength - dstIndex);
79     assert(length <= maxLength);
80     auto copyLength = std::min(length, maxLength);
81     std::memcpy(&_data[dstIndex], &src._data[srcIndex], copyLength);
82 }
83 
84 uint8_t gGamePalette[256 * 4];
85 uint32_t gPaletteEffectFrame;
86 
87 uint32_t gPickupPeepImage;
88 int32_t gPickupPeepX;
89 int32_t gPickupPeepY;
90 
91 /**
92  * 12 elements from 0xF3 are the peep top colour, 12 elements from 0xCA are peep trouser colour
93  *
94  * rct2: 0x0009ABE0C
95  */
96 // clang-format off
97 thread_local uint8_t gPeepPalette[256] = {
98     0x00, 0xF3, 0xF4, 0xF5, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
99     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
100     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
101     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
102     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
103     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
104     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
105     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
106     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
107     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
108     0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
109     0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
110     0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
111     0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
112     0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
113     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
114 };
115 
116 /** rct2: 0x009ABF0C */
117 thread_local uint8_t gOtherPalette[256] = {
118     0x00, 0xF3, 0xF4, 0xF5, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
119     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
120     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
121     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
122     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
123     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
124     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
125     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
126     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
127     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
128     0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
129     0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
130     0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
131     0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
132     0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
133     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
134 };
135 
136 // Originally 0x9ABE04
137 uint8_t text_palette[0x8] = {
138     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 };
140 
141 enum
142 {
143     SPR_PALETTE_3100 = 3100,
144     SPR_PALETTE_3101 = 3101,
145     SPR_PALETTE_3102 = 3102,
146     SPR_PALETTE_3103 = 3103,
147     SPR_PALETTE_3104 = 3104,
148     SPR_PALETTE_3105 = 3105,
149     SPR_PALETTE_3106 = 3106,
150     SPR_PALETTE_3107 = 3107,
151     SPR_PALETTE_3108 = 3108,
152     SPR_PALETTE_3109 = 3109,
153     SPR_PALETTE_3110 = 3110,
154 
155     SPR_PALETTE_BLACK = 4915,
156     SPR_PALETTE_GREY = 4916,
157     SPR_PALETTE_WHITE = 4917,
158     SPR_PALETTE_DARK_PURPLE = 4918,
159     SPR_PALETTE_LIGHT_PURPLE = 4919,
160     SPR_PALETTE_BRIGHT_PURPLE = 4920,
161     SPR_PALETTE_DARK_BLUE = 4921,
162     SPR_PALETTE_LIGHT_BLUE = 4922,
163     SPR_PALETTE_ICY_BLUE = 4923,
164     SPR_PALETTE_TEAL = 4924,
165     SPR_PALETTE_AQUAMARINE = 4925,
166     SPR_PALETTE_SATURATED_GREEN = 4926,
167     SPR_PALETTE_DARK_GREEN = 4927,
168     SPR_PALETTE_MOSS_GREEN = 4928,
169     SPR_PALETTE_BRIGHT_GREEN = 4929,
170     SPR_PALETTE_OLIVE_GREEN = 4930,
171     SPR_PALETTE_DARK_OLIVE_GREEN = 4931,
172     SPR_PALETTE_BRIGHT_YELLOW = 4932,
173     SPR_PALETTE_YELLOW = 4933,
174     SPR_PALETTE_DARK_YELLOW = 4934,
175     SPR_PALETTE_LIGHT_ORANGE = 4935,
176     SPR_PALETTE_DARK_ORANGE = 4936,
177     SPR_PALETTE_LIGHT_BROWN = 4937,
178     SPR_PALETTE_SATURATED_BROWN = 4938,
179     SPR_PALETTE_DARK_BROWN = 4939,
180     SPR_PALETTE_SALMON_PINK = 4940,
181     SPR_PALETTE_BORDEAUX_RED = 4941,
182     SPR_PALETTE_SATURATED_RED = 4942,
183     SPR_PALETTE_BRIGHT_RED = 4943,
184     SPR_PALETTE_DARK_PINK = 4944,
185     SPR_PALETTE_BRIGHT_PINK = 4945,
186     SPR_PALETTE_LIGHT_PINK = 4946,
187     SPR_PALETTE_WATER = 4947,
188     SPR_PALETTE_4948 = 4948,
189     SPR_PALETTE_4949 = 4949,
190     SPR_PALETTE_4950 = 4950,
191     SPR_PALETTE_DARKEN_3 = 4951,
192     SPR_PALETTE_4952 = 4952,
193     SPR_PALETTE_DARKEN_1 = 4953,
194     SPR_PALETTE_DARKEN_2 = 4954,
195     SPR_PALETTE_4955 = 4955,
196     SPR_PALETTE_TRANSLUCENT_GREY = 4956,
197     SPR_PALETTE_TRANSLUCENT_GREY_HIGHLIGHT = 4957,
198     SPR_PALETTE_TRANSLUCENT_GREY_SHADOW = 4958,
199     SPR_PALETTE_TRANSLUCENT_LIGHT_BLUE = 4959,
200     SPR_PALETTE_TRANSLUCENT_LIGHT_BLUE_HIGHLIGHT = 4960,
201     SPR_PALETTE_TRANSLUCENT_LIGHT_BLUE_SHADOW = 4961,
202     SPR_PALETTE_TRANSLUCENT_BORDEAUX_RED = 4962,
203     SPR_PALETTE_TRANSLUCENT_BORDEAUX_RED_HIGHLIGHT = 4963,
204     SPR_PALETTE_TRANSLUCENT_BORDEAUX_RED_SHADOW = 4964,
205     SPR_PALETTE_TRANSLUCENT_DARK_GREEN = 4965,
206     SPR_PALETTE_TRANSLUCENT_DARK_GREEN_HIGHLIGHT = 4966,
207     SPR_PALETTE_TRANSLUCENT_DARK_GREEN_SHADOW = 4967,
208     SPR_PALETTE_TRANSLUCENT_LIGHT_PURPLE = 4968,
209     SPR_PALETTE_TRANSLUCENT_LIGHT_PURPLE_HIGHLIGHT = 4969,
210     SPR_PALETTE_TRANSLUCENT_LIGHT_PURPLE_SHADOW = 4970,
211     SPR_PALETTE_TRANSLUCENT_DARK_OLIVE_GREEN = 4971,
212     SPR_PALETTE_TRANSLUCENT_DARK_OLIVE_GREEN_HIGHLIGHT = 4972,
213     SPR_PALETTE_TRANSLUCENT_DARK_OLIVE_GREEN_SHADOW = 4973,
214     SPR_PALETTE_TRANSLUCENT_LIGHT_BROWN = 4974,
215     SPR_PALETTE_TRANSLUCENT_LIGHT_BROWN_HIGHLIGHT = 4975,
216     SPR_PALETTE_TRANSLUCENT_LIGHT_BROWN_SHADOW = 4976,
217     SPR_PALETTE_TRANSLUCENT_YELLOW = 4977,
218     SPR_PALETTE_TRANSLUCENT_YELLOW_HIGHLIGHT = 4978,
219     SPR_PALETTE_TRANSLUCENT_YELLOW_SHADOW = 4979,
220     SPR_PALETTE_TRANSLUCENT_MOSS_GREEN = 4980,
221     SPR_PALETTE_TRANSLUCENT_MOSS_GREEN_HIGHLIGHT = 4981,
222     SPR_PALETTE_TRANSLUCENT_MOSS_GREEN_SHADOW = 4982,
223     SPR_PALETTE_TRANSLUCENT_OLIVE_GREEN = 4983,
224     SPR_PALETTE_TRANSLUCENT_OLIVE_GREEN_HIGHLIGHT = 4984,
225     SPR_PALETTE_TRANSLUCENT_OLIVE_GREEN_SHADOW = 4985,
226     SPR_PALETTE_TRANSLUCENT_BRIGHT_GREEN = 4986,
227     SPR_PALETTE_TRANSLUCENT_BRIGHT_GREEN_HIGHLIGHT = 4987,
228     SPR_PALETTE_TRANSLUCENT_BRIGHT_GREEN_SHADOW = 4988,
229     SPR_PALETTE_TRANSLUCENT_SALMON_PINK = 4989,
230     SPR_PALETTE_TRANSLUCENT_SALMON_PINK_HIGHLIGHT = 4990,
231     SPR_PALETTE_TRANSLUCENT_SALMON_PINK_SHADOW = 4991,
232     SPR_PALETTE_TRANSLUCENT_BRIGHT_PURPLE = 4992,
233     SPR_PALETTE_TRANSLUCENT_BRIGHT_PURPLE_HIGHLIGHT = 4993,
234     SPR_PALETTE_TRANSLUCENT_BRIGHT_PURPLE_SHADOW = 4994,
235     SPR_PALETTE_TRANSLUCENT_BRIGHT_RED = 4995,
236     SPR_PALETTE_TRANSLUCENT_BRIGHT_RED_HIGHLIGHT = 4996,
237     SPR_PALETTE_TRANSLUCENT_BRIGHT_RED_SHADOW = 4997,
238     SPR_PALETTE_TRANSLUCENT_LIGHT_ORANGE = 4998,
239     SPR_PALETTE_TRANSLUCENT_LIGHT_ORANGE_HIGHLIGHT = 4999,
240     SPR_PALETTE_TRANSLUCENT_LIGHT_ORANGE_SHADOW = 5000,
241     SPR_PALETTE_TRANSLUCENT_TEAL = 5001,
242     SPR_PALETTE_TRANSLUCENT_TEAL_HIGHLIGHT = 5002,
243     SPR_PALETTE_TRANSLUCENT_TEAL_SHADOW = 5003,
244     SPR_PALETTE_TRANSLUCENT_BRIGHT_PINK = 5004,
245     SPR_PALETTE_TRANSLUCENT_BRIGHT_PINK_HIGHLIGHT = 5005,
246     SPR_PALETTE_TRANSLUCENT_BRIGHT_PINK_SHADOW = 5006,
247     SPR_PALETTE_TRANSLUCENT_DARK_BROWN = 5007,
248     SPR_PALETTE_TRANSLUCENT_DARK_BROWN_HIGHLIGHT = 5008,
249     SPR_PALETTE_TRANSLUCENT_DARK_BROWN_SHADOW = 5009,
250     SPR_PALETTE_TRANSLUCENT_LIGHT_PINK = 5010,
251     SPR_PALETTE_TRANSLUCENT_LIGHT_PINK_HIGHLIGHT = 5011,
252     SPR_PALETTE_TRANSLUCENT_LIGHT_PINK_SHADOW = 5012,
253     SPR_PALETTE_TRANSLUCENT_WHITE = 5013,
254     SPR_PALETTE_TRANSLUCENT_WHITE_HIGHLIGHT = 5014,
255     SPR_PALETTE_TRANSLUCENT_WHITE_SHADOW = 5015,
256     SPR_PALETTE_GLASS_BLACK = 5016,
257     SPR_PALETTE_GLASS_GREY = 5017,
258     SPR_PALETTE_GLASS_WHITE = 5018,
259     SPR_PALETTE_GLASS_DARK_PURPLE = 5019,
260     SPR_PALETTE_GLASS_LIGHT_PURPLE = 5020,
261     SPR_PALETTE_GLASS_BRIGHT_PURPLE = 5021,
262     SPR_PALETTE_GLASS_DARK_BLUE = 5022,
263     SPR_PALETTE_GLASS_LIGHT_BLUE = 5023,
264     SPR_PALETTE_GLASS_ICY_BLUE = 5024,
265     SPR_PALETTE_GLASS_TEAL = 5025,
266     SPR_PALETTE_GLASS_AQUAMARINE = 5026,
267     SPR_PALETTE_GLASS_SATURATED_GREEN = 5027,
268     SPR_PALETTE_GLASS_DARK_GREEN = 5028,
269     SPR_PALETTE_GLASS_MOSS_GREEN = 5029,
270     SPR_PALETTE_GLASS_BRIGHT_GREEN = 5030,
271     SPR_PALETTE_GLASS_OLIVE_GREEN = 5031,
272     SPR_PALETTE_GLASS_DARK_OLIVE_GREEN = 5032,
273     SPR_PALETTE_GLASS_BRIGHT_YELLOW = 5033,
274     SPR_PALETTE_GLASS_YELLOW = 5034,
275     SPR_PALETTE_GLASS_DARK_YELLOW = 5035,
276     SPR_PALETTE_GLASS_LIGHT_ORANGE = 5036,
277     SPR_PALETTE_GLASS_DARK_ORANGE = 5037,
278     SPR_PALETTE_GLASS_LIGHT_BROWN = 5038,
279     SPR_PALETTE_GLASS_SATURATED_BROWN = 5039,
280     SPR_PALETTE_GLASS_DARK_BROWN = 5040,
281     SPR_PALETTE_GLASS_SALMON_PINK = 5041,
282     SPR_PALETTE_GLASS_BORDEAUX_RED = 5042,
283     SPR_PALETTE_GLASS_SATURATED_RED = 5043,
284     SPR_PALETTE_GLASS_BRIGHT_RED = 5044,
285     SPR_PALETTE_GLASS_DARK_PINK = 5045,
286     SPR_PALETTE_GLASS_BRIGHT_PINK = 5046,
287     SPR_PALETTE_GLASS_LIGHT_PINK = 5047,
288 };
289 
290 const FilterPaletteID GlassPaletteIds[COLOUR_COUNT] = {
291     FilterPaletteID::PaletteGlassBlack,
292     FilterPaletteID::PaletteGlassGrey,
293     FilterPaletteID::PaletteGlassWhite,
294     FilterPaletteID::PaletteGlassDarkPurple,
295     FilterPaletteID::PaletteGlassLightPurple,
296     FilterPaletteID::PaletteGlassBrightPurple,
297     FilterPaletteID::PaletteGlassDarkBlue,
298     FilterPaletteID::PaletteGlassLightBlue,
299     FilterPaletteID::PaletteGlassIcyBlue,
300     FilterPaletteID::PaletteGlassTeal,
301     FilterPaletteID::PaletteGlassAquamarine,
302     FilterPaletteID::PaletteGlassSaturatedGreen,
303     FilterPaletteID::PaletteGlassDarkGreen,
304     FilterPaletteID::PaletteGlassMossGreen,
305     FilterPaletteID::PaletteGlassBrightGreen,
306     FilterPaletteID::PaletteGlassOliveGreen,
307     FilterPaletteID::PaletteGlassDarkOliveGreen,
308     FilterPaletteID::PaletteGlassBrightYellow,
309     FilterPaletteID::PaletteGlassYellow,
310     FilterPaletteID::PaletteGlassDarkYellow,
311     FilterPaletteID::PaletteGlassLightOrange,
312     FilterPaletteID::PaletteGlassDarkOrange,
313     FilterPaletteID::PaletteGlassLightBrown,
314     FilterPaletteID::PaletteGlassSaturatedBrown,
315     FilterPaletteID::PaletteGlassDarkBrown,
316     FilterPaletteID::PaletteGlassSalmonPink,
317     FilterPaletteID::PaletteGlassBordeauxRed,
318     FilterPaletteID::PaletteGlassSaturatedRed,
319     FilterPaletteID::PaletteGlassBrightRed,
320     FilterPaletteID::PaletteGlassDarkPink,
321     FilterPaletteID::PaletteGlassBrightPink,
322     FilterPaletteID::PaletteGlassLightPink,
323 };
324 
325 // Previously 0x97FCBC use it to get the correct palette from g1_elements
326 static const uint16_t palette_to_g1_offset[PALETTE_TO_G1_OFFSET_COUNT] = {
327     SPR_PALETTE_BLACK,
328     SPR_PALETTE_GREY,
329     SPR_PALETTE_WHITE,
330     SPR_PALETTE_DARK_PURPLE,
331     SPR_PALETTE_LIGHT_PURPLE,
332     SPR_PALETTE_BRIGHT_PURPLE,
333     SPR_PALETTE_DARK_BLUE,
334     SPR_PALETTE_LIGHT_BLUE,
335     SPR_PALETTE_ICY_BLUE,
336     SPR_PALETTE_TEAL,
337     SPR_PALETTE_AQUAMARINE,
338     SPR_PALETTE_SATURATED_GREEN,
339     SPR_PALETTE_DARK_GREEN,
340     SPR_PALETTE_MOSS_GREEN,
341     SPR_PALETTE_BRIGHT_GREEN,
342     SPR_PALETTE_OLIVE_GREEN,
343     SPR_PALETTE_DARK_OLIVE_GREEN,
344     SPR_PALETTE_BRIGHT_YELLOW,
345     SPR_PALETTE_YELLOW,
346     SPR_PALETTE_DARK_YELLOW,
347     SPR_PALETTE_LIGHT_ORANGE,
348     SPR_PALETTE_DARK_ORANGE,
349     SPR_PALETTE_LIGHT_BROWN,
350     SPR_PALETTE_SATURATED_BROWN,
351     SPR_PALETTE_DARK_BROWN,
352     SPR_PALETTE_SALMON_PINK,
353     SPR_PALETTE_BORDEAUX_RED,
354     SPR_PALETTE_SATURATED_RED,
355     SPR_PALETTE_BRIGHT_RED,
356     SPR_PALETTE_DARK_PINK,
357     SPR_PALETTE_BRIGHT_PINK,
358     SPR_PALETTE_LIGHT_PINK,
359 
360 
361     SPR_PALETTE_WATER,      // PaletteWater (water)
362     SPR_PALETTE_3100,
363     SPR_PALETTE_3101,       // Palette34
364     SPR_PALETTE_3102,
365     SPR_PALETTE_3103,
366     SPR_PALETTE_3104,
367     SPR_PALETTE_3106,
368     SPR_PALETTE_3107,
369     SPR_PALETTE_3108,       // 40
370     SPR_PALETTE_3109,
371     SPR_PALETTE_3110,
372     SPR_PALETTE_3105,
373     SPR_PALETTE_4948,
374     SPR_PALETTE_4949,       // Palette45
375     SPR_PALETTE_4950,
376     SPR_PALETTE_DARKEN_3,   // PaletteDarken3
377     SPR_PALETTE_4952,       // Decreases contrast
378     SPR_PALETTE_DARKEN_1,   // PaletteDarken1
379     SPR_PALETTE_DARKEN_2,   // PaletteDarken2 (construction marker)
380     SPR_PALETTE_4955,       // Palette51
381 
382     SPR_PALETTE_TRANSLUCENT_GREY,
383     SPR_PALETTE_TRANSLUCENT_GREY_HIGHLIGHT,
384     SPR_PALETTE_TRANSLUCENT_GREY_SHADOW,
385     SPR_PALETTE_TRANSLUCENT_LIGHT_BLUE,
386     SPR_PALETTE_TRANSLUCENT_LIGHT_BLUE_HIGHLIGHT,
387     SPR_PALETTE_TRANSLUCENT_LIGHT_BLUE_SHADOW,
388     SPR_PALETTE_TRANSLUCENT_BORDEAUX_RED,
389     SPR_PALETTE_TRANSLUCENT_BORDEAUX_RED_HIGHLIGHT,
390     SPR_PALETTE_TRANSLUCENT_BORDEAUX_RED_SHADOW,
391     SPR_PALETTE_TRANSLUCENT_DARK_GREEN,
392     SPR_PALETTE_TRANSLUCENT_DARK_GREEN_HIGHLIGHT,
393     SPR_PALETTE_TRANSLUCENT_DARK_GREEN_SHADOW,
394     SPR_PALETTE_TRANSLUCENT_LIGHT_PURPLE,
395     SPR_PALETTE_TRANSLUCENT_LIGHT_PURPLE_HIGHLIGHT,
396     SPR_PALETTE_TRANSLUCENT_LIGHT_PURPLE_SHADOW,
397     SPR_PALETTE_TRANSLUCENT_DARK_OLIVE_GREEN,
398     SPR_PALETTE_TRANSLUCENT_DARK_OLIVE_GREEN_HIGHLIGHT,
399     SPR_PALETTE_TRANSLUCENT_DARK_OLIVE_GREEN_SHADOW,
400     SPR_PALETTE_TRANSLUCENT_LIGHT_BROWN,
401     SPR_PALETTE_TRANSLUCENT_LIGHT_BROWN_HIGHLIGHT,
402     SPR_PALETTE_TRANSLUCENT_LIGHT_BROWN_SHADOW,
403     SPR_PALETTE_TRANSLUCENT_YELLOW,
404     SPR_PALETTE_TRANSLUCENT_YELLOW_HIGHLIGHT,
405     SPR_PALETTE_TRANSLUCENT_YELLOW_SHADOW,
406     SPR_PALETTE_TRANSLUCENT_MOSS_GREEN,
407     SPR_PALETTE_TRANSLUCENT_MOSS_GREEN_HIGHLIGHT,
408     SPR_PALETTE_TRANSLUCENT_MOSS_GREEN_SHADOW,
409     SPR_PALETTE_TRANSLUCENT_OLIVE_GREEN,
410     SPR_PALETTE_TRANSLUCENT_OLIVE_GREEN_HIGHLIGHT,
411     SPR_PALETTE_TRANSLUCENT_OLIVE_GREEN_SHADOW,
412     SPR_PALETTE_TRANSLUCENT_BRIGHT_GREEN,
413     SPR_PALETTE_TRANSLUCENT_BRIGHT_GREEN_HIGHLIGHT,
414     SPR_PALETTE_TRANSLUCENT_BRIGHT_GREEN_SHADOW,
415     SPR_PALETTE_TRANSLUCENT_SALMON_PINK,
416     SPR_PALETTE_TRANSLUCENT_SALMON_PINK_HIGHLIGHT,
417     SPR_PALETTE_TRANSLUCENT_SALMON_PINK_SHADOW,
418     SPR_PALETTE_TRANSLUCENT_BRIGHT_PURPLE,
419     SPR_PALETTE_TRANSLUCENT_BRIGHT_PURPLE_HIGHLIGHT,
420     SPR_PALETTE_TRANSLUCENT_BRIGHT_PURPLE_SHADOW,
421     SPR_PALETTE_TRANSLUCENT_BRIGHT_RED,
422     SPR_PALETTE_TRANSLUCENT_BRIGHT_RED_HIGHLIGHT,
423     SPR_PALETTE_TRANSLUCENT_BRIGHT_RED_SHADOW,
424     SPR_PALETTE_TRANSLUCENT_LIGHT_ORANGE,
425     SPR_PALETTE_TRANSLUCENT_LIGHT_ORANGE_HIGHLIGHT,
426     SPR_PALETTE_TRANSLUCENT_LIGHT_ORANGE_SHADOW,
427     SPR_PALETTE_TRANSLUCENT_TEAL,
428     SPR_PALETTE_TRANSLUCENT_TEAL_HIGHLIGHT,
429     SPR_PALETTE_TRANSLUCENT_TEAL_SHADOW,
430     SPR_PALETTE_TRANSLUCENT_BRIGHT_PINK,
431     SPR_PALETTE_TRANSLUCENT_BRIGHT_PINK_HIGHLIGHT,
432     SPR_PALETTE_TRANSLUCENT_BRIGHT_PINK_SHADOW,
433     SPR_PALETTE_TRANSLUCENT_DARK_BROWN,
434     SPR_PALETTE_TRANSLUCENT_DARK_BROWN_HIGHLIGHT,
435     SPR_PALETTE_TRANSLUCENT_DARK_BROWN_SHADOW,
436     SPR_PALETTE_TRANSLUCENT_LIGHT_PINK,
437     SPR_PALETTE_TRANSLUCENT_LIGHT_PINK_HIGHLIGHT,
438     SPR_PALETTE_TRANSLUCENT_LIGHT_PINK_SHADOW,
439     SPR_PALETTE_TRANSLUCENT_WHITE,
440     SPR_PALETTE_TRANSLUCENT_WHITE_HIGHLIGHT,
441     SPR_PALETTE_TRANSLUCENT_WHITE_SHADOW,
442 
443     SPR_PALETTE_GLASS_BLACK,
444     SPR_PALETTE_GLASS_GREY,
445     SPR_PALETTE_GLASS_WHITE,
446     SPR_PALETTE_GLASS_DARK_PURPLE,
447     SPR_PALETTE_GLASS_LIGHT_PURPLE,
448     SPR_PALETTE_GLASS_BRIGHT_PURPLE,
449     SPR_PALETTE_GLASS_DARK_BLUE,
450     SPR_PALETTE_GLASS_LIGHT_BLUE,
451     SPR_PALETTE_GLASS_ICY_BLUE,
452     SPR_PALETTE_GLASS_TEAL,
453     SPR_PALETTE_GLASS_AQUAMARINE,
454     SPR_PALETTE_GLASS_SATURATED_GREEN,
455     SPR_PALETTE_GLASS_DARK_GREEN,
456     SPR_PALETTE_GLASS_MOSS_GREEN,
457     SPR_PALETTE_GLASS_BRIGHT_GREEN,
458     SPR_PALETTE_GLASS_OLIVE_GREEN,
459     SPR_PALETTE_GLASS_DARK_OLIVE_GREEN,
460     SPR_PALETTE_GLASS_BRIGHT_YELLOW,
461     SPR_PALETTE_GLASS_YELLOW,
462     SPR_PALETTE_GLASS_DARK_YELLOW,
463     SPR_PALETTE_GLASS_LIGHT_ORANGE,
464     SPR_PALETTE_GLASS_DARK_ORANGE,
465     SPR_PALETTE_GLASS_LIGHT_BROWN,
466     SPR_PALETTE_GLASS_SATURATED_BROWN,
467     SPR_PALETTE_GLASS_DARK_BROWN,
468     SPR_PALETTE_GLASS_SALMON_PINK,
469     SPR_PALETTE_GLASS_BORDEAUX_RED,
470     SPR_PALETTE_GLASS_SATURATED_RED,
471     SPR_PALETTE_GLASS_BRIGHT_RED,
472     SPR_PALETTE_GLASS_DARK_PINK,
473     SPR_PALETTE_GLASS_BRIGHT_PINK,
474     SPR_PALETTE_GLASS_LIGHT_PINK,
475 };
476 
477 #define WINDOW_PALETTE_GREY                 {FilterPaletteID::PaletteTranslucentGrey,                  FilterPaletteID::PaletteTranslucentGreyHighlight,             FilterPaletteID::PaletteTranslucentGreyShadow}
478 #define WINDOW_PALETTE_LIGHT_PURPLE         {FilterPaletteID::PaletteTranslucentLightPurple,          FilterPaletteID::PaletteTranslucentLightPurpleHighlight,     FilterPaletteID::PaletteTranslucentLightPurpleShadow}
479 #define WINDOW_PALETTE_LIGHT_BLUE           {FilterPaletteID::PaletteTranslucentLightBlue,            FilterPaletteID::PaletteTranslucentLightBlueHighlight,       FilterPaletteID::PaletteTranslucentLightBlueShadow}
480 #define WINDOW_PALETTE_TEAL                 {FilterPaletteID::PaletteTranslucentTeal,                  FilterPaletteID::PaletteTranslucentTealHighlight,             FilterPaletteID::PaletteTranslucentTealShadow}
481 #define WINDOW_PALETTE_BRIGHT_GREEN         {FilterPaletteID::PaletteTranslucentBrightGreen,          FilterPaletteID::PaletteTranslucentBrightGreenHighlight,     FilterPaletteID::PaletteTranslucentBrightGreenShadow}
482 #define WINDOW_PALETTE_YELLOW               {FilterPaletteID::PaletteTranslucentYellow,                FilterPaletteID::PaletteTranslucentYellowHighlight,           FilterPaletteID::PaletteTranslucentYellowShadow}
483 #define WINDOW_PALETTE_LIGHT_ORANGE         {FilterPaletteID::PaletteTranslucentLightOrange,          FilterPaletteID::PaletteTranslucentLightOrangeHighlight,     FilterPaletteID::PaletteTranslucentLightOrangeShadow}
484 #define WINDOW_PALETTE_LIGHT_BROWN          {FilterPaletteID::PaletteTranslucentLightBrown,           FilterPaletteID::PaletteTranslucentLightBrownHighlight,      FilterPaletteID::PaletteTranslucentLightBrownShadow}
485 #define WINDOW_PALETTE_BRIGHT_RED           {FilterPaletteID::PaletteTranslucentBrightRed,            FilterPaletteID::PaletteTranslucentBrightRedHighlight,       FilterPaletteID::PaletteTranslucentBrightRedShadow}
486 #define WINDOW_PALETTE_BRIGHT_PINK          {FilterPaletteID::PaletteTranslucentBrightPink,           FilterPaletteID::PaletteTranslucentBrightPinkHighlight,      FilterPaletteID::PaletteTranslucentBrightPinkShadow}
487 
488 const translucent_window_palette TranslucentWindowPalettes[COLOUR_COUNT] = {
489     WINDOW_PALETTE_GREY,                    // COLOUR_BLACK
490     WINDOW_PALETTE_GREY,                    // COLOUR_GREY
491     {FilterPaletteID::PaletteTranslucentWhite,             FilterPaletteID::PaletteTranslucentWhiteHighlight,            FilterPaletteID::PaletteTranslucentWhiteShadow},
492     WINDOW_PALETTE_LIGHT_PURPLE,            // COLOUR_DARK_PURPLE
493     WINDOW_PALETTE_LIGHT_PURPLE,            // COLOUR_LIGHT_PURPLE
494     {FilterPaletteID::PaletteTranslucentBrightPurple,     FilterPaletteID::PaletteTranslucentBrightPurpleHighlight,    FilterPaletteID::PaletteTranslucentBrightPurpleShadow},
495     WINDOW_PALETTE_LIGHT_BLUE,              // COLOUR_DARK_BLUE
496     WINDOW_PALETTE_LIGHT_BLUE,              // COLOUR_LIGHT_BLUE
497     WINDOW_PALETTE_LIGHT_BLUE,              // COLOUR_ICY_BLUE
498     WINDOW_PALETTE_TEAL,                    // COLOUR_TEAL
499     WINDOW_PALETTE_TEAL,                    // COLOUR_AQUAMARINE
500     WINDOW_PALETTE_BRIGHT_GREEN,            // COLOUR_SATURATED_GREEN
501     {FilterPaletteID::PaletteTranslucentDarkGreen,        FilterPaletteID::PaletteTranslucentDarkGreenHighlight,       FilterPaletteID::PaletteTranslucentDarkGreenShadow},
502     {FilterPaletteID::PaletteTranslucentMossGreen,        FilterPaletteID::PaletteTranslucentMossGreenHighlight,       FilterPaletteID::PaletteTranslucentMossGreenShadow},
503     WINDOW_PALETTE_BRIGHT_GREEN,            // COLOUR_BRIGHT_GREEN
504     {FilterPaletteID::PaletteTranslucentOliveGreen,       FilterPaletteID::PaletteTranslucentOliveGreenHighlight,      FilterPaletteID::PaletteTranslucentOliveGreenShadow},
505     {FilterPaletteID::PaletteTranslucentDarkOliveGreen,  FilterPaletteID::PaletteTranslucentDarkOliveGreenHighlight, FilterPaletteID::PaletteTranslucentDarkOliveGreenShadow},
506     WINDOW_PALETTE_YELLOW,                  // COLOUR_BRIGHT_YELLOW
507     WINDOW_PALETTE_YELLOW,                  // COLOUR_YELLOW
508     WINDOW_PALETTE_YELLOW,                  // COLOUR_DARK_YELLOW
509     WINDOW_PALETTE_LIGHT_ORANGE,            // COLOUR_LIGHT_ORANGE
510     WINDOW_PALETTE_LIGHT_ORANGE,            // COLOUR_DARK_ORANGE
511     WINDOW_PALETTE_LIGHT_BROWN,             // COLOUR_LIGHT_BROWN
512     WINDOW_PALETTE_LIGHT_BROWN,             // COLOUR_SATURATED_BROWN
513     {FilterPaletteID::PaletteTranslucentDarkBrown,        FilterPaletteID::PaletteTranslucentDarkBrownHighlight,       FilterPaletteID::PaletteTranslucentDarkBrownShadow},
514     {FilterPaletteID::PaletteTranslucentSalmonPink,       FilterPaletteID::PaletteTranslucentSalmonPinkHighlight,      FilterPaletteID::PaletteTranslucentSalmonPinkShadow},
515     {FilterPaletteID::PaletteTranslucentBordeauxRed,      FilterPaletteID::PaletteTranslucentBordeauxRedHighlight,     FilterPaletteID::PaletteTranslucentBordeauxRedShadow},
516     WINDOW_PALETTE_BRIGHT_RED,              // COLOUR_SATURATED_RED
517     WINDOW_PALETTE_BRIGHT_RED,              // COLOUR_BRIGHT_RED
518     WINDOW_PALETTE_BRIGHT_PINK,             // COLOUR_DARK_PINK
519     WINDOW_PALETTE_BRIGHT_PINK,             // COLOUR_BRIGHT_PINK
520     {FilterPaletteID::PaletteTranslucentLightPink,        FilterPaletteID::PaletteTranslucentLightPinkHighlight,       FilterPaletteID::PaletteTranslucentLightPinkShadow},
521 };
522 // clang-format on
523 
GetCatalogue() const524 ImageCatalogue ImageId::GetCatalogue() const
525 {
526     auto index = GetIndex();
527     if (index == SPR_TEMP)
528     {
529         return ImageCatalogue::TEMPORARY;
530     }
531     if (index < SPR_RCTC_G1_END)
532     {
533         return ImageCatalogue::G1;
534     }
535     if (index < SPR_G2_END)
536     {
537         return ImageCatalogue::G2;
538     }
539     if (index < SPR_CSG_END)
540     {
541         return ImageCatalogue::CSG;
542     }
543     if (index < SPR_IMAGE_LIST_END)
544     {
545         return ImageCatalogue::OBJECT;
546     }
547     return ImageCatalogue::UNKNOWN;
548 }
549 
550 void (*mask_fn)(
551     int32_t width, int32_t height, const uint8_t* RESTRICT maskSrc, const uint8_t* RESTRICT colourSrc, uint8_t* RESTRICT dst,
552     int32_t maskWrap, int32_t colourWrap, int32_t dstWrap)
553     = nullptr;
554 
mask_init()555 void mask_init()
556 {
557     if (avx2_available())
558     {
559         log_verbose("registering AVX2 mask function");
560         mask_fn = mask_avx2;
561     }
562     else if (sse41_available())
563     {
564         log_verbose("registering SSE4.1 mask function");
565         mask_fn = mask_sse4_1;
566     }
567     else
568     {
569         log_verbose("registering scalar mask function");
570         mask_fn = mask_scalar;
571     }
572 }
573 
gfx_filter_pixel(rct_drawpixelinfo * dpi,const ScreenCoordsXY & coords,FilterPaletteID palette)574 void gfx_filter_pixel(rct_drawpixelinfo* dpi, const ScreenCoordsXY& coords, FilterPaletteID palette)
575 {
576     gfx_filter_rect(dpi, { coords, coords }, palette);
577 }
578 
579 /**
580  *
581  *  rct2: 0x00683854
582  * a1 (ebx)
583  * product (cl)
584  */
gfx_transpose_palette(int32_t pal,uint8_t product)585 void gfx_transpose_palette(int32_t pal, uint8_t product)
586 {
587     const rct_g1_element* g1 = gfx_get_g1_element(pal);
588     if (g1 != nullptr)
589     {
590         int32_t width = g1->width;
591         int32_t x = g1->x_offset;
592         uint8_t* dest_pointer = &gGamePalette[x * 4];
593         uint8_t* source_pointer = g1->offset;
594 
595         for (; width > 0; width--)
596         {
597             dest_pointer[0] = (source_pointer[0] * product) >> 8;
598             dest_pointer[1] = (source_pointer[1] * product) >> 8;
599             dest_pointer[2] = (source_pointer[2] * product) >> 8;
600             source_pointer += 3;
601             dest_pointer += 4;
602         }
603         platform_update_palette(gGamePalette, 10, 236);
604     }
605 }
606 
607 /**
608  *
609  *  rct2: 0x006837E3
610  */
load_palette()611 void load_palette()
612 {
613     if (gOpenRCT2NoGraphics)
614     {
615         return;
616     }
617 
618     auto water_type = static_cast<rct_water_type*>(object_entry_get_chunk(ObjectType::Water, 0));
619 
620     uint32_t palette = 0x5FC;
621 
622     if (water_type != nullptr)
623     {
624         openrct2_assert(water_type->image_id != 0xFFFFFFFF, "Failed to load water palette");
625         palette = water_type->image_id;
626     }
627 
628     const rct_g1_element* g1 = gfx_get_g1_element(palette);
629     if (g1 != nullptr)
630     {
631         int32_t width = g1->width;
632         int32_t x = g1->x_offset;
633         uint8_t* src = g1->offset;
634         uint8_t* dst = &gGamePalette[x * 4];
635         for (; width > 0; width--)
636         {
637             dst[0] = src[0];
638             dst[1] = src[1];
639             dst[2] = src[2];
640             src += 3;
641             dst += 4;
642         }
643     }
644     platform_update_palette(gGamePalette, 10, 236);
645     gfx_invalidate_screen();
646 }
647 
648 /**
649  *
650  *  rct2: 0x006ED7E5
651  */
gfx_invalidate_screen()652 void gfx_invalidate_screen()
653 {
654     gfx_set_dirty_blocks({ { 0, 0 }, { context_get_width(), context_get_height() } });
655 }
656 
657 /*
658  *
659  * rct2: 0x006EE53B
660  * left (ax)
661  * width (bx)
662  * top (cx)
663  * height (dx)
664  * drawpixelinfo (edi)
665  */
clip_drawpixelinfo(rct_drawpixelinfo * dst,rct_drawpixelinfo * src,const ScreenCoordsXY & coords,int32_t width,int32_t height)666 bool clip_drawpixelinfo(
667     rct_drawpixelinfo* dst, rct_drawpixelinfo* src, const ScreenCoordsXY& coords, int32_t width, int32_t height)
668 {
669     int32_t right = coords.x + width;
670     int32_t bottom = coords.y + height;
671 
672     *dst = *src;
673     dst->zoom_level = 0;
674 
675     if (coords.x > dst->x)
676     {
677         uint16_t clippedFromLeft = coords.x - dst->x;
678         dst->width -= clippedFromLeft;
679         dst->x = coords.x;
680         dst->pitch += clippedFromLeft;
681         dst->bits += clippedFromLeft;
682     }
683 
684     int32_t stickOutWidth = dst->x + dst->width - right;
685     if (stickOutWidth > 0)
686     {
687         dst->width -= stickOutWidth;
688         dst->pitch += stickOutWidth;
689     }
690 
691     if (coords.y > dst->y)
692     {
693         uint16_t clippedFromTop = coords.y - dst->y;
694         dst->height -= clippedFromTop;
695         dst->y = coords.y;
696         uint32_t bitsPlus = (dst->pitch + dst->width) * clippedFromTop;
697         dst->bits += bitsPlus;
698     }
699 
700     int32_t bp = dst->y + dst->height - bottom;
701     if (bp > 0)
702     {
703         dst->height -= bp;
704     }
705 
706     if (dst->width > 0 && dst->height > 0)
707     {
708         dst->x -= coords.x;
709         dst->y -= coords.y;
710         return true;
711     }
712 
713     return false;
714 }
715 
gfx_invalidate_pickedup_peep()716 void gfx_invalidate_pickedup_peep()
717 {
718     uint32_t sprite = gPickupPeepImage;
719     if (sprite != UINT32_MAX)
720     {
721         const rct_g1_element* g1 = gfx_get_g1_element(sprite & 0x7FFFF);
722         if (g1 != nullptr)
723         {
724             int32_t left = gPickupPeepX + g1->x_offset;
725             int32_t top = gPickupPeepY + g1->y_offset;
726             int32_t right = left + g1->width;
727             int32_t bottom = top + g1->height;
728             gfx_set_dirty_blocks({ { left, top }, { right, bottom } });
729         }
730     }
731 }
732 
gfx_draw_pickedup_peep(rct_drawpixelinfo * dpi)733 void gfx_draw_pickedup_peep(rct_drawpixelinfo* dpi)
734 {
735     if (gPickupPeepImage != UINT32_MAX)
736     {
737         gfx_draw_sprite(dpi, gPickupPeepImage, { gPickupPeepX, gPickupPeepY }, 0);
738     }
739 }
740 
GetPaletteG1Index(colour_t paletteId)741 std::optional<uint32_t> GetPaletteG1Index(colour_t paletteId)
742 {
743     if (paletteId < std::size(palette_to_g1_offset))
744     {
745         return palette_to_g1_offset[paletteId];
746     }
747     return std::nullopt;
748 }
749 
GetPaletteMapForColour(colour_t paletteId)750 std::optional<PaletteMap> GetPaletteMapForColour(colour_t paletteId)
751 {
752     auto g1Index = GetPaletteG1Index(paletteId);
753     if (g1Index.has_value())
754     {
755         auto g1 = gfx_get_g1_element(g1Index.value());
756         if (g1 != nullptr)
757         {
758             return PaletteMap(g1->offset, g1->height, g1->width);
759         }
760     }
761     return std::nullopt;
762 }
763 
GetBytesPerRow() const764 size_t rct_drawpixelinfo::GetBytesPerRow() const
765 {
766     return static_cast<size_t>(width) + pitch;
767 }
768 
GetBitsOffset(const ScreenCoordsXY & pos) const769 uint8_t* rct_drawpixelinfo::GetBitsOffset(const ScreenCoordsXY& pos) const
770 {
771     return bits + pos.x + (pos.y * GetBytesPerRow());
772 }
773 
Crop(const ScreenCoordsXY & pos,const ScreenSize & size) const774 rct_drawpixelinfo rct_drawpixelinfo::Crop(const ScreenCoordsXY& pos, const ScreenSize& size) const
775 {
776     rct_drawpixelinfo result = *this;
777     result.bits = GetBitsOffset(pos);
778     result.x = static_cast<int16_t>(pos.x);
779     result.y = static_cast<int16_t>(pos.y);
780     result.width = static_cast<int16_t>(size.width);
781     result.height = static_cast<int16_t>(size.height);
782     result.pitch = static_cast<int16_t>(width + pitch - size.width);
783     return result;
784 }
785