1 /*
2 * Portions of this file are copyright Rebirth contributors and licensed as
3 * described in COPYING.txt.
4 * Portions of this file are copyright Parallax Software and licensed
5 * according to the Parallax license below.
6 * See COPYING.txt for license details.
7
8 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
9 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
10 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
11 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
12 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
13 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
14 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
15 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
16 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
17 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
18 */
19
20 /*
21 *
22 * Definitions for graphics lib.
23 *
24 */
25
26 #pragma once
27
28 #include <cassert>
29 #include "fwd-gr.h"
30 #include "pstypes.h"
31 #include "maths.h"
32 #include "palette.h"
33 #include "dxxsconf.h"
34 #include "dsx-ns.h"
35 #include "pack.h"
36 #include <array>
37
38 namespace dcx {
39
40 enum class gr_fade_level : uint8_t
41 {
42 off = GR_FADE_LEVELS // yes, max means OFF - don't screw that up
43 };
44
45 struct grs_point
46 {
47 fix x,y;
48 };
49
50 struct grs_bitmap : prohibit_void_ptr<grs_bitmap>
51 {
52 uint16_t bm_x,bm_y; // Offset from parent's origin
53 uint16_t bm_w,bm_h; // width,height
54 private:
55 bm_mode bm_type;
56 uint8_t bm_flags;
57 public:
get_typegrs_bitmap58 bm_mode get_type() const
59 {
60 return bm_type;
61 }
set_typegrs_bitmap62 void set_type(bm_mode t)
63 {
64 bm_type = t;
65 }
get_flagsgrs_bitmap66 uint8_t get_flags() const
67 {
68 return bm_flags;
69 }
get_flag_maskgrs_bitmap70 uint8_t get_flag_mask(const uint8_t mask) const
71 {
72 return get_flags() & mask;
73 }
set_flagsgrs_bitmap74 void set_flags(const uint8_t f)
75 {
76 bm_flags = f;
77 }
clear_flagsgrs_bitmap78 void clear_flags()
79 {
80 set_flags(0);
81 }
set_flag_maskgrs_bitmap82 void set_flag_mask(const bool set, const uint8_t mask)
83 {
84 const auto f = get_flags();
85 set_flags(set ? f | mask : f & ~mask);
86 }
add_flagsgrs_bitmap87 void add_flags(const uint8_t f)
88 {
89 bm_flags |= f;
90 }
91 // bit 1 on means it has supertransparency
92 // bit 2 on means it doesn't get passed through lighting.
93 short bm_rowsize; // unsigned char offset to next row
94 std::array<fix, 3> avg_color_rgb; // same as above but real rgb value to be used to textured objects that should emit light
95 union {
96 const color_palette_index *bm_data; // ptr to pixel data...
97 // Linear = *parent+(rowsize*y+x)
98 // ModeX = *parent+(rowsize*y+x/4)
99 // SVGA = *parent+(rowsize*y+x)
100 color_palette_index *bm_mdata;
101 };
get_bitmap_datagrs_bitmap102 const color_palette_index *get_bitmap_data() const { return bm_data; }
get_bitmap_datagrs_bitmap103 color_palette_index *get_bitmap_data() { return bm_mdata; }
104 struct grs_bitmap *bm_parent;
105 #if DXX_USE_OGL
106 struct ogl_texture *gltexture;
107 #else
108 uint8_t avg_color; // Average color of all pixels in texture map.
109 #endif /* def OGL */
110 };
111
112 // Free the bitmap and its pixel data
113 class grs_main_bitmap : public grs_bitmap
114 {
115 public:
116 grs_main_bitmap();
117 grs_main_bitmap(const grs_main_bitmap &) = delete;
118 grs_main_bitmap &operator=(const grs_main_bitmap &) = delete;
grs_main_bitmap(grs_main_bitmap && r)119 grs_main_bitmap(grs_main_bitmap &&r) :
120 grs_bitmap(std::move(static_cast<grs_bitmap &>(r)))
121 {
122 r.bm_data = nullptr;
123 #if DXX_USE_OGL
124 r.gltexture = nullptr;
125 #endif
126 }
127 grs_main_bitmap &operator=(grs_main_bitmap &&r)
128 {
129 if (this == &r)
130 return *this;
131 reset();
132 grs_bitmap::operator=(std::move(static_cast<grs_bitmap &>(r)));
133 r.bm_data = nullptr;
134 #if DXX_USE_OGL
135 r.gltexture = nullptr;
136 #endif
137 return *this;
138 }
~grs_main_bitmap()139 ~grs_main_bitmap()
140 {
141 reset();
142 }
reset()143 void reset()
144 {
145 gr_free_bitmap_data(*this);
146 }
147 };
148
149 struct grs_canvas : prohibit_void_ptr<grs_canvas>
150 {
151 grs_canvas(const grs_canvas &) = delete;
152 grs_canvas &operator=(const grs_canvas &) = delete;
153 grs_canvas(grs_canvas &&) = default;
154 grs_canvas &operator=(grs_canvas &&) = default;
~grs_canvasgrs_canvas155 ~grs_canvas()
156 {
157 /* `grd_curcanv` points to the currently active canvas. If it
158 * points to `this` when the destructor runs, then any further
159 * attempts to use the referenced canvas will access an
160 * out-of-scope variable, leading to undefined behavior. Assert
161 * that `grd_curcanv` does not point to the expiring variable so
162 * that potential misuses are detected before they manifest as
163 * undefined behavior.
164 *
165 * If you get an assertion failure here, enable
166 * `DXX_DEBUG_CURRENT_CANVAS_ORIGIN` to trace where the canvas
167 * was most recently set.
168 *
169 * Eventually, `grd_curcanv` will be removed and this test will
170 * become obsolete.
171 */
172 assert(this != grd_curcanv);
173 /* If the canvas is reset before next use, then no crash.
174 * If the canvas is not reset, then crash instead of accessing
175 * freed memory.
176 */
177 if (grd_curcanv == this)
178 grd_curcanv = nullptr;
179 }
180 grs_bitmap cv_bitmap; // the bitmap for this canvas
181 const grs_font * cv_font; // the currently selected font
182 color_palette_index cv_font_fg_color; // current font foreground color (255==Invisible)
183 color_palette_index cv_font_bg_color; // current font background color (255==Invisible)
184 gr_fade_level cv_fade_level; // transparency level
185 protected:
186 grs_canvas() = default;
187 };
188
189 //=========================================================================
190 // System functions:
191 // setup and set mode. this creates a grs_screen structure and sets
192 // grd_curscreen to point to it. grs_curcanv points to this screen's
193 // canvas. Saves the current VGA state and screen mode.
194
195 union screen_mode
196 {
197 private:
198 uint32_t wh;
199 public:
200 struct {
201 uint16_t width, height;
202 };
203 bool operator==(const screen_mode &rhs) const
204 {
205 return wh == rhs.wh;
206 }
207 bool operator!=(const screen_mode &rhs) const
208 {
209 return !(*this == rhs);
210 }
211 screen_mode() = default;
screen_mode(uint16_t && w,uint16_t && h)212 constexpr screen_mode(uint16_t &&w, uint16_t &&h) :
213 width(w), height(h)
214 {
215 }
216 };
217
SM_W(const screen_mode & s)218 static inline uint16_t SM_W(const screen_mode &s)
219 {
220 return s.width;
221 }
222
SM_H(const screen_mode & s)223 static inline uint16_t SM_H(const screen_mode &s)
224 {
225 return s.height;
226 }
227
228 // Makes a new canvas. allocates memory for the canvas and its bitmap,
229 // including the raw pixel buffer.
230
231 struct grs_main_canvas : grs_canvas, prohibit_void_ptr<grs_main_canvas>
232 {
233 using prohibit_void_ptr<grs_main_canvas>::operator &;
234 grs_main_canvas &operator=(grs_main_canvas &) = delete;
235 grs_main_canvas &operator=(grs_main_canvas &&) = default;
236 ~grs_main_canvas();
237 };
238
239 class grs_screen : prohibit_void_ptr<grs_screen>
240 { // This is a video screen
241 screen_mode sc_mode;
242 public:
243 grs_screen &operator=(grs_screen &) = delete;
244 grs_screen &operator=(grs_screen &&) = default;
245 grs_main_canvas sc_canvas; // Represents the entire screen
246 fix sc_aspect; //aspect ratio (w/h) for this screen
get_screen_width()247 uint16_t get_screen_width() const
248 {
249 return SM_W(sc_mode);
250 }
get_screen_height()251 uint16_t get_screen_height() const
252 {
253 return SM_H(sc_mode);
254 }
get_screen_mode()255 screen_mode get_screen_mode() const
256 {
257 return sc_mode;
258 }
set_screen_width_height(uint16_t w,uint16_t h)259 void set_screen_width_height(uint16_t w, uint16_t h)
260 {
261 sc_mode.width = w;
262 sc_mode.height = h;
263 }
264 };
265
266 //=========================================================================
267 // Canvas functions:
268
269 // Creates a canvas that is part of another canvas. this can be used to make
270 // a window on the screen. the canvas structure is malloc'd; the address of
271 // the raw pixel data is inherited from the parent canvas.
272
273 struct grs_subcanvas : grs_canvas, prohibit_void_ptr<grs_subcanvas>
274 {
275 using prohibit_void_ptr<grs_subcanvas>::operator &;
276 };
277
278 // Free the bitmap, but not the pixel data buffer
279 class grs_subbitmap : public grs_bitmap
280 {
281 };
282
283 //font structure
284 struct grs_font : public prohibit_void_ptr<grs_font>
285 {
286 uint16_t ft_w; // Width in pixels
287 uint16_t ft_h; // Height in pixels
288 int16_t ft_flags; // Proportional?
289 int16_t ft_baseline; //
290 uint8_t ft_minchar; // First char defined by this font
291 uint8_t ft_maxchar; // Last char defined by this font
292 std::array<char, 13> ft_filename;
293 const uint8_t *ft_data = nullptr; // Ptr to raw data.
294 const uint8_t *const *ft_chars = nullptr; // Ptrs to data for each char (required for prop font)
295 const int16_t *ft_widths = nullptr; // Array of widths (required for prop font)
296 const uint8_t *ft_kerndata = nullptr; // Array of kerning triplet data
297 std::unique_ptr<uint8_t[]> ft_allocdata;
298 #if DXX_USE_OGL
299 // These fields do not participate in disk i/o!
300 std::unique_ptr<grs_bitmap[]> ft_bitmaps;
301 grs_main_bitmap ft_parent_bitmap;
302 #endif /* def OGL */
303 };
304
305 }
306
gr_set_bitmap_flags(grs_bitmap & bm,uint8_t flags)307 static inline void gr_set_bitmap_flags(grs_bitmap &bm, uint8_t flags)
308 {
309 bm.set_flags(flags);
310 }
311
gr_set_transparent(grs_bitmap & bm,bool bTransparent)312 static inline void gr_set_transparent(grs_bitmap &bm, bool bTransparent)
313 {
314 bm.set_flag_mask(bTransparent, BM_FLAG_TRANSPARENT);
315 }
316
317 namespace dcx {
318
gr_set_font_fg_color(grs_canvas & canvas,int fg_color)319 static inline void gr_set_font_fg_color(grs_canvas &canvas, int fg_color)
320 {
321 canvas.cv_font_fg_color = fg_color;
322 }
323
gr_set_font_fg_color(grs_canvas & canvas,color_palette_index fg_color)324 static inline void gr_set_font_fg_color(grs_canvas &canvas, color_palette_index fg_color)
325 {
326 canvas.cv_font_fg_color = static_cast<int>(fg_color);
327 }
328
gr_set_font_bg_color(grs_canvas & canvas,int bg_color)329 static inline void gr_set_font_bg_color(grs_canvas &canvas, int bg_color)
330 {
331 canvas.cv_font_bg_color = bg_color;
332 }
333
gr_set_font_bg_color(grs_canvas & canvas,color_palette_index bg_color)334 static inline void gr_set_font_bg_color(grs_canvas &canvas, color_palette_index bg_color)
335 {
336 canvas.cv_font_bg_color = static_cast<int>(bg_color);
337 }
338
339 #define gr_set_fontcolor(C,F,B) \
340 ( DXX_BEGIN_COMPOUND_STATEMENT { \
341 auto &gr_set_fontcolor = C; \
342 gr_set_font_fg_color(gr_set_fontcolor, F); \
343 gr_set_font_bg_color(gr_set_fontcolor, B); \
344 } DXX_END_COMPOUND_STATEMENT )
345
346 struct font_delete
347 {
operatorfont_delete348 void operator()(grs_font *p) const
349 {
350 gr_close_font(std::unique_ptr<grs_font>(p));
351 }
352 };
353 }
354
355 static inline void (gr_set_current_canvas)(grs_canvas_ptr &canv DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DECL_VARS)
356 {
357 (gr_set_current_canvas)(canv.get() DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_PASS_VARS);
358 }
359
360 static inline void (gr_set_current_canvas)(grs_subcanvas_ptr &canv DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DECL_VARS)
361 {
362 (gr_set_current_canvas)(canv.get() DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_PASS_VARS);
363 }
364