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 #pragma once
21 
22 #include <SDL_version.h>
23 #if SDL_MAJOR_VERSION == 2
24 #include <SDL_video.h>
25 #endif
26 #include <cstdint>
27 #include <memory>
28 #include <utility>
29 #include "d_array.h"
30 #include "palette.h"
31 #include "maths.h"
32 #include "u_mem.h"
33 
34 namespace dcx {
35 
36 enum class gr_fade_level : uint8_t;
37 
38 // some defines for transparency and blending
39 constexpr auto TRANSPARENCY_COLOR = color_palette_index{255};            // palette entry of transparency color -- 255 on the PC
40 #define GR_FADE_LEVELS       34u
41 #define GR_FADE_OFF          gr_fade_level::off
42 enum class gr_blend : uint8_t {
43 	normal,		// normal blending
44 	additive_a,	// additive alpha blending
45 	additive_c,	// additive color blending
46 };
47 
48 }
49 
50 #define SWIDTH  (grd_curscreen->get_screen_width())
51 #define SHEIGHT (grd_curscreen->get_screen_height())
52 
53 #if defined(DXX_BUILD_DESCENT_I)
54 namespace dsx {
55 extern uint8_t HiresGFXAvailable;
56 }
57 #define HIRESMODE HiresGFXAvailable		// descent.pig either contains hires or lowres graphics, not both
58 #elif defined(DXX_BUILD_DESCENT_II)
59 #define HIRESMODE (SWIDTH >= 640 && SHEIGHT >= 480 && !GameArg.GfxSkipHiresGFX)
60 #endif
61 #define MAX_BMP_SIZE(width, height) (4 + ((width) + 2) * (height))
62 
63 #define SCRNS_DIR "screenshots/"
64 
65 //these are control characters that have special meaning in the font code
66 
67 #define CC_COLOR        1   //next char is new foreground color
68 #define CC_LSPACING     2   //next char specifies line spacing
69 #define CC_UNDERLINE    3   //next char is underlined
70 
71 //now have string versions of these control characters (can concat inside a string)
72 
73 #define CC_COLOR_S      "\x1"   //next char is new foreground color
74 #define CC_LSPACING_S   "\x2"   //next char specifies line spacing
75 #define CC_UNDERLINE_S  "\x3"   //next char is underlined
76 
77 namespace dcx {
78 
79 enum class bm_mode : uint8_t
80 {
81 	linear,
82 	ilbm,
83 	rgb15 = 3,	//5 bits each r,g,b stored at 16 bits
84 #if DXX_USE_OGL
85 	ogl = 5,
86 #endif /* def OGL */
87 };
88 
89 }
90 
91 #define BM_FLAG_TRANSPARENT         1
92 #define BM_FLAG_SUPER_TRANSPARENT   2
93 #define BM_FLAG_NO_LIGHTING         4
94 #define BM_FLAG_RLE                 8   // A run-length encoded bitmap.
95 #define BM_FLAG_PAGED_OUT           16  // This bitmap's data is paged out.
96 #define BM_FLAG_RLE_BIG             32  // for bitmaps that RLE to > 255 per row (i.e. cockpits)
97 
98 #include "dxxsconf.h"
99 #include "dsx-ns.h"
100 #include <array>
101 
102 namespace dcx {
103 
104 struct grs_bitmap;
105 struct grs_canvas;
106 #define GRS_FONT_SIZE 28    // how much space it takes up on disk
107 struct grs_point;
108 
109 union screen_mode;
110 
111 class grs_screen;
112 
113 struct grs_main_canvas;
114 typedef std::unique_ptr<grs_main_canvas> grs_canvas_ptr;
115 
116 struct grs_subcanvas;
117 typedef std::unique_ptr<grs_subcanvas> grs_subcanvas_ptr;
118 
119 // Free the bitmap and its pixel data
120 class grs_main_bitmap;
121 typedef std::unique_ptr<grs_main_bitmap> grs_bitmap_ptr;
122 
123 struct grs_font;
124 
125 #if SDL_MAJOR_VERSION == 1
126 uint_fast32_t gr_list_modes(std::array<screen_mode, 50> &modes);
127 #elif SDL_MAJOR_VERSION == 2
128 extern SDL_Window *g_pRebirthSDLMainWindow;
129 #endif
130 
131 }
132 
133 #ifdef dsx
134 namespace dsx {
135 int gr_set_mode(screen_mode mode);
136 void gr_set_mode_from_window_size();
137 
138 int gr_init();
139 #if DXX_USE_OGL
140 void gr_set_attributes();
141 #endif
142 void gr_close();
143 }
144 #endif
145 
146 namespace dcx {
147 
148 grs_canvas_ptr gr_create_canvas(uint16_t w, uint16_t h);
149 
150 grs_subcanvas_ptr gr_create_sub_canvas(grs_canvas &canv,uint16_t x,uint16_t y,uint16_t w, uint16_t h);
151 
152 // Initialize the specified canvas. the raw pixel data buffer is passed as
153 // a parameter. no memory allocation is performed.
154 
155 void gr_init_canvas(grs_canvas &canv,unsigned char *pixdata, bm_mode pixtype, uint16_t w, uint16_t h);
156 
157 // Initialize the specified sub canvas. no memory allocation is performed.
158 
159 void gr_init_sub_canvas(grs_subcanvas &n, grs_canvas &src, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
160 
161 // Clear the current canvas to the specified color
162 void gr_clear_canvas(grs_canvas &, color_t color);
163 
164 //=========================================================================
165 // Bitmap functions:
166 
167 // these are the two workhorses, the others just use these
168 void gr_init_bitmap(grs_bitmap &bm, bm_mode mode, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t bytesperline, color_palette_index *data) noexcept;
169 void gr_init_main_bitmap(grs_main_bitmap &bm, bm_mode mode, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t bytesperline, RAIIdmem<uint8_t[]> data);
170 void gr_init_sub_bitmap (grs_bitmap &bm, grs_bitmap &bmParent, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
171 
172 void gr_init_bitmap_alloc(grs_main_bitmap &bm, bm_mode mode, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t bytesperline);
173 void gr_free_bitmap_data(grs_bitmap &bm);
174 
175 // Allocate a bitmap and its pixel data buffer.
176 grs_bitmap_ptr gr_create_bitmap(uint16_t w,uint16_t h);
177 
178 // Free the bitmap, but not the pixel data buffer
179 class grs_subbitmap;
180 typedef std::unique_ptr<grs_subbitmap> grs_subbitmap_ptr;
181 
182 // Creates a bitmap which is part of another bitmap
183 grs_subbitmap_ptr gr_create_sub_bitmap(grs_bitmap &bm, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
184 
185 // Free the bitmap's data
186 
187 #if !DXX_USE_OGL
188 void gr_bm_ubitblt(grs_canvas &dest, unsigned w, unsigned h, int dx, int dy, int sx, int sy, const grs_bitmap &src);
189 void gr_bm_ubitbltm(grs_canvas &dest, unsigned w, unsigned h, unsigned dx, unsigned dy, unsigned sx, unsigned sy, const grs_bitmap &src);
190 #define gr_bm_pixel(C,B,X,Y,C2) gr_bm_pixel(B,X,Y,C2)
191 #define gr_settransblend(A,B,C)	gr_settransblend(A,B)
192 #endif
193 void gr_bm_pixel(grs_canvas &, grs_bitmap &bm, uint_fast32_t x, uint_fast32_t y, uint8_t color);
194 void gr_set_bitmap_data(grs_bitmap &bm, const uint8_t *data);
195 }
196 
197 #ifdef dsx
198 namespace dsx {
199 
200 //=========================================================================
201 // Color functions:
202 
203 // When this function is called, the guns are set to gr_palette, and
204 // the palette stays the same until gr_close is called
205 
206 void gr_use_palette_table(const char * filename);
207 
208 }
209 #endif
210 
211 //=========================================================================
212 // Drawing functions:
213 
214 namespace dcx {
215 
216 // Sets transparency and blending function
217 void gr_settransblend(grs_canvas &, gr_fade_level fade_level, gr_blend blend_func);
218 
219 // Draws a point into the current canvas in the current color and drawmode.
220 void gr_pixel(grs_bitmap &, unsigned x, unsigned y, color_palette_index color);
221 void gr_upixel(grs_bitmap &, unsigned x, unsigned y, color_palette_index color);
222 
223 // Gets a pixel;
224 color_palette_index gr_gpixel(const grs_bitmap &bitmap, unsigned x, unsigned y);
225 color_palette_index gr_ugpixel(const grs_bitmap &bitmap, int x, int y);
226 
227 // Draws a line into the current canvas in the current color and drawmode.
228 void gr_line(grs_canvas &, fix x0,fix y0,fix x1,fix y1, color_palette_index color);
229 void gr_uline(grs_canvas &canvas, fix x0,fix y0,fix x1,fix y1, color_palette_index color);
230 
231 // Draw the bitmap into the current canvas at the specified location.
232 void gr_bitmap(grs_canvas &, unsigned x,unsigned y,grs_bitmap &bm);
233 void gr_ubitmap(grs_canvas &, grs_bitmap &bm);
234 void show_fullscr(grs_canvas &, grs_bitmap &bm);
235 
236 // Find transparent area in bitmap
237 void gr_bitblt_find_transparent_area(const grs_bitmap &bm, unsigned &minx, unsigned &miny, unsigned &maxx, unsigned &maxy);
238 
239 // bitmap function with transparency
240 #if !DXX_USE_OGL
241 void gr_bitmapm(grs_canvas &, unsigned x, unsigned y, const grs_bitmap &bm);
242 void gr_ubitmapm(grs_canvas &, unsigned x, unsigned y, grs_bitmap &bm);
243 #endif
244 
245 // Draw a rectangle into the current canvas.
246 void gr_rect(grs_canvas &, int left,int top,int right,int bot, color_palette_index color);
247 void gr_urect(grs_canvas &, int left,int top,int right,int bot, color_palette_index color);
248 
249 // Draw a filled circle
250 int gr_disk(grs_canvas &, fix x,fix y,fix r, color_palette_index color);
251 
252 // Draw an outline circle
253 int gr_ucircle(grs_canvas &, fix x,fix y,fix r, color_palette_index color);
254 
255 // Draw an unfilled rectangle into the current canvas
256 #if DXX_USE_EDITOR
257 void gr_box(grs_canvas &, uint_fast32_t left,uint_fast32_t top,uint_fast32_t right,uint_fast32_t bot, color_palette_index color);
258 #endif
259 void gr_ubox(grs_canvas &, int left,int top,int right,int bot, color_palette_index color);
260 
261 void gr_scanline(grs_canvas &canvas, int x1, int x2, unsigned y, color_palette_index color);
262 #if !DXX_USE_OGL
263 void gr_uscanline(grs_canvas &canvas, unsigned x1, unsigned x2, unsigned y, color_palette_index color);
264 #endif
265 void gr_close_font(std::unique_ptr<grs_font> font);
266 
267 struct font_delete;
268 typedef std::unique_ptr<grs_font, font_delete> grs_font_ptr;
269 
270 // Reads in a font file... current font set to this one.
271 grs_font_ptr gr_init_font(grs_canvas &canvas, const char * fontfile);
272 
273 }
274 
275 #ifdef dsx
276 namespace dsx {
277 
278 #if defined(DXX_BUILD_DESCENT_I)
279 #define DXX_SDL_WINDOW_CAPTION	"Descent"
280 #define DXX_SDL_WINDOW_ICON_BITMAP	"d1x-rebirth.bmp"
281 #elif defined(DXX_BUILD_DESCENT_II)
282 #define DXX_SDL_WINDOW_CAPTION	"Descent II"
283 #define DXX_SDL_WINDOW_ICON_BITMAP	"d2x-rebirth.bmp"
284 void gr_copy_palette(palette_array_t &gr_palette, const palette_array_t &pal);
285 #endif
286 
287 }
288 #endif
289 
290 // Writes a string using current font. Returns the next column after last char.
291 namespace dcx {
292 
293 //remap (by re-reading) all the color fonts
294 void gr_remap_color_fonts();
295 void gr_set_curfont(grs_canvas &, const grs_font &);
296 void gr_string(grs_canvas &, const grs_font &, int x, int y, const char *s, int w, int h);
297 void gr_string(grs_canvas &, const grs_font &, int x, int y, const char *s);
298 void gr_ustring(grs_canvas &, const grs_font &, int x, int y, const char *s);
299 template <void (&)(grs_canvas &, const grs_font &, int, int, const char *)>
300 void gr_printt(grs_canvas &, const grs_font &, int x, int y, const char *format, ...) __attribute_format_printf(5, 6);
301 #define gr_printfs(...)	gr_printt<gr_string>(__VA_ARGS__)
302 #define gr_printfus(...)	gr_printt<gr_ustring>(__VA_ARGS__)
303 #define gr_printf(A1,A2,A3,A4,F,...)	dxx_call_printf_checked(gr_printfs,gr_string,(A1,A2,A3,A4),(F),##__VA_ARGS__)
304 #define gr_uprintf(A1,A2,A3,A4,F,...)	dxx_call_printf_checked(gr_printfus,gr_ustring,(A1,A2,A3,A4),(F),##__VA_ARGS__)
305 std::pair<const char *, unsigned> gr_get_string_wrap(const grs_font &, const char *s, unsigned limit);
306 unsigned gr_get_string_height(const grs_font &cv_font, unsigned lines);
307 
308 struct gr_string_size
309 {
310 	unsigned long width;
311 	unsigned long height;
312 };
313 gr_string_size gr_get_string_size(const grs_font &, const char *s);
314 gr_string_size gr_get_string_size(const grs_font &, const char *s, unsigned max_chars_per_line);
315 
316 // From scale.c
317 void scale_bitmap(const grs_bitmap &bp, const std::array<grs_point, 3> &vertbuf, int orientation, grs_bitmap &);
318 
319 //===========================================================================
320 // Global variables
321 extern grs_canvas *grd_curcanv;             //active canvas
322 extern std::unique_ptr<grs_screen> grd_curscreen;           //active screen
323 
324 /* Define `DXX_DEBUG_CURRENT_CANVAS_ORIGIN` to a positive integer N to
325  * save __FILE__+__LINE__ of the N most recent callers.  If
326  * `DXX_DEBUG_CURRENT_CANVAS_ORIGIN` is not a positive integer, the
327  * file+line is not passed to the canvas update functions.
328  *
329  * Use this to trace which functions update the global canvas pointer
330  * without requiring a debugger trap on every update.
331  */
332 #ifndef DXX_DEBUG_CURRENT_CANVAS_ORIGIN
333 #define DXX_DEBUG_CURRENT_CANVAS_ORIGIN	0
334 #endif
335 
336 #if DXX_DEBUG_CURRENT_CANVAS_ORIGIN > 0
337 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_DECL_VARS	const char *file = __builtin_FILE(), unsigned line = __builtin_LINE()
338 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_DEFN_VARS	const char *const file, const unsigned line
339 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DECL_VARS	, DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_DECL_VARS
340 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DEFN_VARS	, DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_DEFN_VARS
341 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_PASS_VARS	file, line
342 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_PASS_VARS	, DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_PASS_VARS
343 #else
344 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_DECL_VARS
345 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_DEFN_VARS
346 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DECL_VARS
347 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DEFN_VARS
348 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_PASS_VARS
349 #define DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_PASS_VARS
350 #endif
351 void (gr_set_default_canvas)(DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_DECL_VARS);
352 void (gr_set_current_canvas)(grs_canvas & DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DECL_VARS);
353 void (gr_set_current_canvas)(std::nullptr_t DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DECL_VARS) = delete;
354 void gr_set_current_canvas2(grs_canvas * DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DECL_VARS);
355 
gr_set_current_canvas_inline(grs_canvas * const canv DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DECL_VARS)356 static inline void gr_set_current_canvas_inline(grs_canvas *const canv DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DECL_VARS)
357 {
358 	if (canv)
359 		(gr_set_current_canvas)(*canv DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_PASS_VARS);
360 	else
361 		(gr_set_default_canvas)(DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_N_PASS_VARS);
362 }
363 
364 static inline void (gr_set_current_canvas)(grs_canvas *const canv DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_DECL_VARS)
365 {
366 #ifdef DXX_HAVE_BUILTIN_CONSTANT_P
367 	if (dxx_builtin_constant_p(!canv))
368 		gr_set_current_canvas_inline(canv DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_PASS_VARS);
369 	else
370 #endif
371 		gr_set_current_canvas2(canv DXX_DEBUG_CURRENT_CANVAS_FILE_LINE_COMMA_L_PASS_VARS);
372 }
373 
374 //flags for fonts
375 #define FT_COLOR        1
376 #define FT_PROPORTIONAL 2
377 #define FT_KERNED       4
378 
379 extern palette_array_t gr_palette;
380 using gft_array1 = enumerated_array<std::array<color_t, 256>, GR_FADE_LEVELS, gr_fade_level>;
381 extern gft_array1 gr_fade_table;
382 }
383 
384 extern uint16_t gr_palette_selector;
385 extern uint16_t gr_inverse_table_selector;
386 extern uint16_t gr_fade_table_selector;
387 
388 // Remaps a bitmap into the current palette. If transparent_color is
389 // between 0 and 255 then all occurances of that color are mapped to
390 // whatever color the 2d uses for transparency. This is normally used
391 // right after a call to iff_read_bitmap like this:
392 //		iff_error = iff_read_bitmap(filename,new,bm_mode::linear,newpal);
393 //		if (iff_error != IFF_NO_ERROR) Error("Can't load IFF file <%s>, error=%d",filename,iff_error);
394 //		if (iff_has_transparency)
395 //			gr_remap_bitmap(new, newpal, iff_transparent_color);
396 //		else
397 //			gr_remap_bitmap(new, newpal, -1);
398 
399 // Same as above, but searches using gr_find_closest_color which uses
400 // 18-bit accurracy instead of 15bit when translating colors.
401 namespace dcx {
402 void gr_remap_bitmap_good(grs_bitmap &bmp, palette_array_t &palette, uint_fast32_t transparent_color, uint_fast32_t super_transparent_color);
403 
404 void gr_palette_step_up(int r, int g, int b);
405 
406 #define BM_RGB(r,g,b) ((((r)&31)<<10) | (((g)&31)<<5) | ((b)&31))
407 #define BM_XRGB(r,g,b) gr_find_closest_color((r)*2,(g)*2,(b)*2)
408 
409 // Given: r,g,b, each in range of 0-63, return the color index that
410 // best matches the input.
411 color_palette_index gr_find_closest_color(int r, int g, int b);
412 color_palette_index gr_find_closest_color_15bpp(int rgb);
413 void gr_flip();
414 
415 /*
416  * must return 0 if windowed, 1 if fullscreen
417  */
418 int gr_check_fullscreen();
419 
420 /*
421  * returns state after toggling (ie, same as if you had called
422  * check_fullscreen immediatly after)
423  */
424 void gr_toggle_fullscreen();
425 
426 void ogl_do_palfx();
427 void ogl_init_pixel_buffers(unsigned w, unsigned h);
428 void ogl_close_pixel_buffers();
429 }
430 void ogl_cache_polymodel_textures(unsigned model_num);
431