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 "NewDrawing.h"
11 
12 #include "../Context.h"
13 #include "../config/Config.h"
14 #include "../drawing/Drawing.h"
15 #include "../interface/Screenshot.h"
16 #include "../localisation/StringIds.h"
17 #include "../paint/Painter.h"
18 #include "../platform/Platform2.h"
19 #include "../ui/UiContext.h"
20 #include "../world/Location.hpp"
21 #include "IDrawingContext.h"
22 #include "IDrawingEngine.h"
23 
24 #include <cmath>
25 
26 using namespace OpenRCT2;
27 using namespace OpenRCT2::Drawing;
28 using namespace OpenRCT2::Paint;
29 using namespace OpenRCT2::Ui;
30 
31 rct_string_id DrawingEngineStringIds[] = {
32     STR_DRAWING_ENGINE_SOFTWARE,
33     STR_DRAWING_ENGINE_SOFTWARE_WITH_HARDWARE_DISPLAY,
34     STR_DRAWING_ENGINE_OPENGL,
35 };
36 
drawing_engine_get_type()37 DrawingEngine drawing_engine_get_type()
38 {
39     auto context = GetContext();
40     return context->GetDrawingEngineType();
41 }
42 
GetDrawingEngine()43 static IDrawingEngine* GetDrawingEngine()
44 {
45     IDrawingEngine* result = nullptr;
46     auto context = GetContext();
47     if (context != nullptr)
48     {
49         result = context->GetDrawingEngine();
50     }
51     return result;
52 }
53 
drawing_engine_requires_new_window(DrawingEngine srcEngine,DrawingEngine dstEngine)54 bool drawing_engine_requires_new_window(DrawingEngine srcEngine, DrawingEngine dstEngine)
55 {
56     bool openGL = srcEngine == DrawingEngine::OpenGL || dstEngine == DrawingEngine::OpenGL;
57     return Platform::RequireNewWindow(openGL);
58 }
59 
drawing_engine_init()60 void drawing_engine_init()
61 {
62     auto context = GetContext();
63     if (context != nullptr)
64     {
65         context->InitialiseDrawingEngine();
66     }
67 }
68 
drawing_engine_resize()69 void drawing_engine_resize()
70 {
71     auto context = GetContext();
72     if (context != nullptr)
73     {
74         auto drawingEngine = context->GetDrawingEngine();
75         if (drawingEngine != nullptr)
76         {
77             auto uiContext = context->GetUiContext();
78             drawingEngine->Resize(uiContext->GetWidth(), uiContext->GetHeight());
79         }
80     }
81 }
82 
drawing_engine_set_palette(const GamePalette & colours)83 void drawing_engine_set_palette(const GamePalette& colours)
84 {
85     auto context = GetContext();
86     if (context != nullptr)
87     {
88         auto drawingEngine = context->GetDrawingEngine();
89         if (drawingEngine != nullptr)
90         {
91             drawingEngine->SetPalette(colours);
92         }
93     }
94 }
95 
drawing_engine_copy_rect(int32_t x,int32_t y,int32_t width,int32_t height,int32_t dx,int32_t dy)96 void drawing_engine_copy_rect(int32_t x, int32_t y, int32_t width, int32_t height, int32_t dx, int32_t dy)
97 {
98     auto context = GetContext();
99     if (context != nullptr)
100     {
101         auto drawingEngine = context->GetDrawingEngine();
102         if (drawingEngine != nullptr)
103         {
104             drawingEngine->CopyRect(x, y, width, height, dx, dy);
105         }
106     }
107 }
108 
drawing_engine_dispose()109 void drawing_engine_dispose()
110 {
111     auto context = GetContext();
112     if (context != nullptr)
113     {
114         context->DisposeDrawingEngine();
115     }
116 }
117 
drawing_engine_get_dpi()118 rct_drawpixelinfo* drawing_engine_get_dpi()
119 {
120     auto context = GetContext();
121     auto drawingEngine = context->GetDrawingEngine();
122     return drawingEngine->GetDrawingPixelInfo();
123 }
124 
drawing_engine_has_dirty_optimisations()125 bool drawing_engine_has_dirty_optimisations()
126 {
127     bool result = false;
128     auto drawingEngine = GetDrawingEngine();
129     if (drawingEngine != nullptr)
130     {
131         result = (drawingEngine->GetFlags() & DEF_DIRTY_OPTIMISATIONS);
132     }
133     return result;
134 }
135 
drawing_engine_invalidate_image(uint32_t image)136 void drawing_engine_invalidate_image(uint32_t image)
137 {
138     auto drawingEngine = GetDrawingEngine();
139     if (drawingEngine != nullptr)
140     {
141         drawingEngine->InvalidateImage(image);
142     }
143 }
144 
drawing_engine_set_vsync(bool vsync)145 void drawing_engine_set_vsync(bool vsync)
146 {
147     auto drawingEngine = GetDrawingEngine();
148     if (drawingEngine != nullptr)
149     {
150         drawingEngine->SetVSync(vsync);
151     }
152 }
153 
gfx_set_dirty_blocks(const ScreenRect & rect)154 void gfx_set_dirty_blocks(const ScreenRect& rect)
155 {
156     auto drawingEngine = GetDrawingEngine();
157     if (drawingEngine != nullptr)
158     {
159         drawingEngine->Invalidate(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
160     }
161 }
162 
gfx_clear(rct_drawpixelinfo * dpi,uint8_t paletteIndex)163 void gfx_clear(rct_drawpixelinfo* dpi, uint8_t paletteIndex)
164 {
165     auto drawingEngine = dpi->DrawingEngine;
166     if (drawingEngine != nullptr)
167     {
168         IDrawingContext* dc = drawingEngine->GetDrawingContext();
169         dc->Clear(dpi, paletteIndex);
170     }
171 }
172 
gfx_fill_rect(rct_drawpixelinfo * dpi,const ScreenRect & rect,int32_t colour)173 void gfx_fill_rect(rct_drawpixelinfo* dpi, const ScreenRect& rect, int32_t colour)
174 {
175     auto drawingEngine = dpi->DrawingEngine;
176     if (drawingEngine != nullptr)
177     {
178         IDrawingContext* dc = drawingEngine->GetDrawingContext();
179         dc->FillRect(dpi, colour, rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
180     }
181 }
182 
gfx_filter_rect(rct_drawpixelinfo * dpi,const ScreenRect & rect,FilterPaletteID palette)183 void gfx_filter_rect(rct_drawpixelinfo* dpi, const ScreenRect& rect, FilterPaletteID palette)
184 {
185     auto drawingEngine = dpi->DrawingEngine;
186     if (drawingEngine != nullptr)
187     {
188         IDrawingContext* dc = drawingEngine->GetDrawingContext();
189         dc->FilterRect(dpi, palette, rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
190     }
191 }
192 
gfx_draw_line(rct_drawpixelinfo * dpi,const ScreenLine & line,int32_t colour)193 void gfx_draw_line(rct_drawpixelinfo* dpi, const ScreenLine& line, int32_t colour)
194 {
195     auto drawingEngine = dpi->DrawingEngine;
196     if (drawingEngine != nullptr)
197     {
198         IDrawingContext* dc = drawingEngine->GetDrawingContext();
199         dc->DrawLine(dpi, colour, line);
200     }
201 }
202 
gfx_draw_dashed_line(rct_drawpixelinfo * dpi,const ScreenLine & screenLine,const int32_t dashedLineSegmentLength,const int32_t color)203 void gfx_draw_dashed_line(
204     rct_drawpixelinfo* dpi, const ScreenLine& screenLine, const int32_t dashedLineSegmentLength, const int32_t color)
205 {
206     assert(dashedLineSegmentLength > 0);
207 
208     const auto drawingEngine = dpi->DrawingEngine;
209     if (drawingEngine != nullptr)
210     {
211         constexpr int32_t precisionFactor = 1000;
212 
213         const int32_t dashedLineLength = std::hypot(
214             screenLine.GetX2() - screenLine.GetX1(), screenLine.GetY2() - screenLine.GetY1());
215         const int32_t lineSegmentCount = dashedLineLength / dashedLineSegmentLength / 2;
216         if (lineSegmentCount == 0)
217         {
218             return;
219         }
220 
221         const int32_t lineXDist = std::abs(screenLine.GetX2() - screenLine.GetX1());
222         const int32_t lineYDist = std::abs(screenLine.GetY2() - screenLine.GetY1());
223         const int32_t dxPrecise = precisionFactor * lineXDist / lineSegmentCount / 2;
224         const int32_t dyPrecise = precisionFactor * lineYDist / lineSegmentCount / 2;
225         IDrawingContext* dc = drawingEngine->GetDrawingContext();
226 
227         for (int32_t i = 0, x, y; i < lineSegmentCount; ++i)
228         {
229             x = screenLine.GetX1() + dxPrecise * i * 2 / precisionFactor;
230             y = screenLine.GetY1() + dyPrecise * i * 2 / precisionFactor;
231             dc->DrawLine(dpi, color, { { x, y }, { x + dxPrecise / precisionFactor, y + dyPrecise / precisionFactor } });
232         }
233     }
234 }
235 
gfx_draw_sprite(rct_drawpixelinfo * dpi,ImageId image_id,const ScreenCoordsXY & coords)236 void FASTCALL gfx_draw_sprite(rct_drawpixelinfo* dpi, ImageId image_id, const ScreenCoordsXY& coords)
237 {
238     gfx_draw_sprite(dpi, image_id.ToUInt32(), coords, image_id.GetTertiary());
239 }
240 
gfx_draw_sprite(rct_drawpixelinfo * dpi,int32_t image,const ScreenCoordsXY & coords,uint32_t tertiary_colour)241 void FASTCALL gfx_draw_sprite(rct_drawpixelinfo* dpi, int32_t image, const ScreenCoordsXY& coords, uint32_t tertiary_colour)
242 {
243     auto drawingEngine = dpi->DrawingEngine;
244     if (drawingEngine != nullptr)
245     {
246         IDrawingContext* dc = drawingEngine->GetDrawingContext();
247         dc->DrawSprite(dpi, image, coords.x, coords.y, tertiary_colour);
248     }
249 }
250 
gfx_draw_glyph(rct_drawpixelinfo * dpi,int32_t image,const ScreenCoordsXY & coords,const PaletteMap & paletteMap)251 void FASTCALL gfx_draw_glyph(rct_drawpixelinfo* dpi, int32_t image, const ScreenCoordsXY& coords, const PaletteMap& paletteMap)
252 {
253     auto drawingEngine = dpi->DrawingEngine;
254     if (drawingEngine != nullptr)
255     {
256         IDrawingContext* dc = drawingEngine->GetDrawingContext();
257         dc->DrawGlyph(dpi, image, coords.x, coords.y, paletteMap);
258     }
259 }
260 
261 void FASTCALL
gfx_draw_sprite_raw_masked(rct_drawpixelinfo * dpi,const ScreenCoordsXY & coords,int32_t maskImage,int32_t colourImage)262     gfx_draw_sprite_raw_masked(rct_drawpixelinfo* dpi, const ScreenCoordsXY& coords, int32_t maskImage, int32_t colourImage)
263 {
264     auto drawingEngine = dpi->DrawingEngine;
265     if (drawingEngine != nullptr)
266     {
267         IDrawingContext* dc = drawingEngine->GetDrawingContext();
268         dc->DrawSpriteRawMasked(dpi, coords.x, coords.y, maskImage, colourImage);
269     }
270 }
271 
gfx_draw_sprite_solid(rct_drawpixelinfo * dpi,int32_t image,const ScreenCoordsXY & coords,uint8_t colour)272 void FASTCALL gfx_draw_sprite_solid(rct_drawpixelinfo* dpi, int32_t image, const ScreenCoordsXY& coords, uint8_t colour)
273 {
274     auto drawingEngine = dpi->DrawingEngine;
275     if (drawingEngine != nullptr)
276     {
277         IDrawingContext* dc = drawingEngine->GetDrawingContext();
278         dc->DrawSpriteSolid(dpi, image, coords.x, coords.y, colour);
279     }
280 }
281 
screenshot_dump()282 std::string screenshot_dump()
283 {
284     auto drawingEngine = GetDrawingEngine();
285     if (drawingEngine != nullptr)
286     {
287         return drawingEngine->Screenshot();
288     }
289     return "";
290 }
291