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