1 /*
2 * ============================================================================
3 * Title: Graphics Interface Routines
4 * Author: J. Zbiciak, J. Tanner
5 * ============================================================================
6 * GFX_INIT -- Initializes a gfx_t object.
7 * GFX_TICK -- Services a gfx_t tick.
8 * GFX_VID_ENABLE -- Alert gfx that video has been enabled or blanked
9 * GFX_SET_BORD -- Set the border / offset parameters for the display
10 * ============================================================================
11 * GFX_T -- Graphics subsystem object.
12 * GFX_PVT_T -- Private internal state to gfx_t structure.
13 * ============================================================================
14 * The graphics subsystem provides an abstraction layer between the
15 * emulator and the graphics library being used. Theoretically, this
16 * should allow easy porting to other graphics libraries.
17 *
18 * TODO:
19 * -- Make use of dirty rectangle updating for speed.
20 * ============================================================================
21 */
22
23 #include "config.h"
24 #include "periph/periph.h"
25 #include "gfx.h"
26 #include "gfx/palette.h"
27 //#include "file/file.h"
28 #include "mvi/mvi.h"
29 #include "avi/avi.h"
30 #include "lzoe/lzoe.h"
31 #include "file/file.h"
32
33 /*
34 * ============================================================================
35 * GFX_PVT_T -- Private internal state to gfx_t structure.
36 * ============================================================================
37 */
38 typedef struct gfx_pvt_t
39 {
40 int vid_enable; /* Video enable flag. */
41 } gfx_pvt_t;
42
43 LOCAL void gfx_dtor(periph_t *const p);
44
45 /* ======================================================================== */
46 /* GFX_CHECK -- Validates gfx parameters */
47 /* ======================================================================== */
gfx_check(int desire_x,int desire_y,int desire_bpp,int prescaler)48 int gfx_check(int desire_x, int desire_y, int desire_bpp, int prescaler)
49 {
50 UNUSED(desire_x);
51 UNUSED(desire_y);
52 UNUSED(desire_bpp);
53 UNUSED(prescaler);
54 return 0;
55 }
56
57 /* ======================================================================== */
58 /* GFX_INIT -- Initializes a gfx_t object. */
59 /* ======================================================================== */
gfx_init(gfx_t * gfx,int desire_x,int desire_y,int desire_bpp,int flags,int verbose,int prescaler,int border_x,int border_y,int pal_mode,struct avi_writer_t * const avi,int audio_rate,const palette_t * const palette)60 int gfx_init(gfx_t *gfx, int desire_x, int desire_y, int desire_bpp,
61 int flags, int verbose, int prescaler,
62 int border_x, int border_y, int pal_mode,
63 struct avi_writer_t *const avi, int audio_rate,
64 const palette_t *const palette)
65 {
66 UNUSED(desire_x);
67 UNUSED(desire_y);
68 UNUSED(desire_bpp);
69 UNUSED(flags);
70 UNUSED(verbose);
71 UNUSED(prescaler);
72 UNUSED(border_x);
73 UNUSED(border_y);
74 UNUSED(pal_mode);
75
76 /* -------------------------------------------------------------------- */
77 /* Sanity checks and cleanups. */
78 /* -------------------------------------------------------------------- */
79 assert(gfx);
80 memset((void*)gfx, 0, sizeof(gfx_t));
81
82 /* -------------------------------------------------------------------- */
83 /* Allocate memory for the gfx_t. */
84 /* -------------------------------------------------------------------- */
85 gfx->vid = CALLOC(uint8_t, 160 * 200);
86 gfx->pvt = CALLOC(gfx_pvt_t, 1);
87
88 if (!gfx->vid || !gfx->pvt)
89 {
90
91 fprintf(stderr, "gfx: Panic: Could not allocate memory.\n");
92
93 goto die;
94 }
95
96 gfx->pvt->vid_enable = 0;
97 gfx->dirty = 3;
98 gfx->b_dirty = 3;
99 gfx->palette = *palette;
100
101 gfx->fps = pal_mode ? 50 : 60;
102 gfx->avi = avi;
103 gfx->audio_rate = audio_rate; // ugh
104
105 gfx->hidden = true;
106
107 /* -------------------------------------------------------------------- */
108 /* Set up the gfx_t's internal structures. */
109 /* -------------------------------------------------------------------- */
110 gfx->periph.read = NULL;
111 gfx->periph.write = NULL;
112 gfx->periph.peek = NULL;
113 gfx->periph.poke = NULL;
114 gfx->periph.tick = NULL;
115 gfx->periph.min_tick = 0;
116 gfx->periph.max_tick = INT_MAX;
117 gfx->periph.addr_base = 0;
118 gfx->periph.addr_mask = 0;
119 gfx->periph.dtor = gfx_dtor;
120
121 #ifdef BENCHMARK_GFX
122 atexit(gfx_dr_hist_dump);
123 #endif
124
125 return 0;
126
127 die:
128 CONDFREE(gfx->pvt);
129 CONDFREE(gfx->vid);
130 return -1;
131 }
132
133 /* ======================================================================== */
134 /* GFX_DTOR -- Tear down the gfx_t */
135 /* ======================================================================== */
gfx_dtor(periph_t * const p)136 LOCAL void gfx_dtor(periph_t *const p)
137 {
138 gfx_t *const gfx = PERIPH_AS(gfx_t, p);
139
140 if (gfx->movie)
141 {
142 if (gfx->movie->f)
143 fclose(gfx->movie->f);
144
145 CONDFREE(gfx->movie);
146 }
147
148 if (avi_is_active(gfx->avi))
149 avi_end_video(gfx->avi);
150
151 CONDFREE(gfx->pvt);
152 CONDFREE(gfx->vid);
153 }
154
155 /* ======================================================================== */
156 /* GFX_TOGGLE_WINDOWED -- Try to toggle windowed vs. full-screen. */
157 /* ======================================================================== */
gfx_toggle_windowed(gfx_t * gfx,int quiet)158 bool gfx_toggle_windowed(gfx_t *gfx, int quiet)
159 {
160 UNUSED(gfx);
161 UNUSED(quiet);
162 return false;
163 }
164
165 /* ======================================================================== */
166 /* GFX_FORCE_WINDOWED -- Force display to be windowed mode; Returns 1 if */
167 /* display was previously full-screen. */
168 /* ======================================================================== */
gfx_force_windowed(gfx_t * gfx,int quiet)169 int gfx_force_windowed(gfx_t *gfx, int quiet)
170 {
171 UNUSED(gfx);
172 UNUSED(quiet);
173 return 0;
174 }
175
176 /* ======================================================================== */
177 /* GFX_SET_TITLE -- Sets the window title */
178 /* ======================================================================== */
gfx_set_title(gfx_t * gfx,const char * title)179 int gfx_set_title(gfx_t *gfx, const char *title)
180 {
181 UNUSED(gfx);
182 UNUSED(title);
183 return 0;
184 }
185
186 /* ======================================================================== */
187 /* GFX_REFRESH -- A whole lotta nuttin. */
188 /* ======================================================================== */
gfx_refresh(gfx_t * const gfx)189 void gfx_refresh(gfx_t *const gfx)
190 {
191 /* -------------------------------------------------------------------- */
192 /* Every ~0.5 second, force a dirty frame, in case there is a static */
193 /* image. On some systems (OS X in my case), the window will not */
194 /* refresh properly unless we send *something* occasionally. */
195 /* */
196 /* Where I saw it: Dragging a window from the Retina display to an */
197 /* external monitor caused the window to go all white. */
198 /* -------------------------------------------------------------------- */
199 if ((gfx->tot_frames++ & 31) == 0)
200 {
201 gfx->dirty |= 3;
202 gfx->b_dirty |= 3;
203 }
204
205 /* -------------------------------------------------------------------- */
206 /* Don't bother if display isn't dirty or if we're iconified. */
207 /* -------------------------------------------------------------------- */
208 if (!gfx->scrshot && (!gfx->dirty || gfx->hidden))
209 {
210 return;
211 }
212
213 /* -------------------------------------------------------------------- */
214 /* DEBUG: Report blocks of dropped frames. */
215 /* -------------------------------------------------------------------- */
216 if (gfx->dropped_frames)
217 {
218 gfx->tot_dropped_frames += gfx->dropped_frames;
219 gfx->dropped_frames = 0;
220 }
221
222 gfx->dirty = 0;
223 gfx->b_dirty = 0;
224 }
225
226 /* ======================================================================== */
227 /* GFX_STIC_TICK -- Called directly from STIC emulation. */
228 /* ======================================================================== */
gfx_stic_tick(gfx_t * const gfx)229 void gfx_stic_tick(gfx_t *const gfx)
230 {
231 gfx->tot_frames++;
232
233 /* -------------------------------------------------------------------- */
234 /* Update a movie if one's active, or user requested toggle in movie */
235 /* state. We do this prior to dropping frames so that movies always */
236 /* have a consistent frame rate. */
237 /* -------------------------------------------------------------------- */
238 if (gfx->scrshot & (GFX_MOVIE | GFX_MVTOG))
239 gfx_movieupd(gfx);
240
241 /* -------------------------------------------------------------------- */
242 /* Update an AVI if one's active, or if user requested a toggle. */
243 /* -------------------------------------------------------------------- */
244 if (gfx->scrshot & (GFX_AVI | GFX_AVTOG))
245 gfx_aviupd(gfx);
246
247 /* -------------------------------------------------------------------- */
248 /* Drop a frame if we need to. */
249 /* -------------------------------------------------------------------- */
250 if (gfx->drop_frame)
251 {
252 gfx->drop_frame--;
253 gfx->tot_frames++;
254 if (gfx->dirty) gfx->dropped_frames++;
255 return;
256 }
257
258 gfx_refresh(gfx);
259
260 /* -------------------------------------------------------------------- */
261 /* If a screen-shot was requested, go write out a GIF file of the */
262 /* screen right now. Screen-shot GIFs are always 320x200. */
263 /* -------------------------------------------------------------------- */
264 if (gfx->scrshot & GFX_SHOT)
265 {
266 gfx_scrshot(gfx);
267 gfx->scrshot &= ~GFX_SHOT;
268 }
269
270 return;
271 }
272
273 /* ======================================================================== */
274 /* GFX_VID_ENABLE -- Alert gfx that video has been enabled or blanked */
275 /* ======================================================================== */
gfx_vid_enable(gfx_t * gfx,int enabled)276 void gfx_vid_enable(gfx_t *gfx, int enabled)
277 {
278 /* -------------------------------------------------------------------- */
279 /* Force 'enabled' to be 0 or 1. */
280 /* -------------------------------------------------------------------- */
281 enabled = enabled == VID_ENABLED;
282
283 /* -------------------------------------------------------------------- */
284 /* If enabled state changed, schedule a palette update. */
285 /* -------------------------------------------------------------------- */
286 if ((gfx->pvt->vid_enable ^ enabled) & 1)
287 {
288 gfx->pvt->vid_enable |= 2;
289 gfx->dirty |= 2;
290 } else
291 {
292 gfx->pvt->vid_enable = enabled;
293 }
294 }
295
296 /* ======================================================================== */
297 /* GFX_SET_BORD -- Set the border color for the display */
298 /* ======================================================================== */
gfx_set_bord(gfx_t * gfx,int b_color)299 void gfx_set_bord
300 (
301 gfx_t *gfx, /* Graphics object. */
302 int b_color
303 )
304 {
305 int dirty = 0;
306
307 /* -------------------------------------------------------------------- */
308 /* Set up the display parameters. */
309 /* -------------------------------------------------------------------- */
310 if (gfx->b_color != b_color) { gfx->b_color = b_color; dirty = 3; }
311
312 if (dirty) { gfx->dirty |= 1; }
313 if (dirty & 2) { gfx->b_dirty |= 2; }
314 }
315
316 /* ======================================================================== */
317 /* This program is free software; you can redistribute it and/or modify */
318 /* it under the terms of the GNU General Public License as published by */
319 /* the Free Software Foundation; either version 2 of the License, or */
320 /* (at your option) any later version. */
321 /* */
322 /* This program is distributed in the hope that it will be useful, */
323 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
324 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
325 /* General Public License for more details. */
326 /* */
327 /* You should have received a copy of the GNU General Public License along */
328 /* with this program; if not, write to the Free Software Foundation, Inc., */
329 /* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
330 /* ======================================================================== */
331 /* Copyright (c) 1998-2020, Joseph Zbiciak. */
332 /* ======================================================================== */
333