1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3 * Copyright (C) 2011-2017 - Daniel De Matteis
4 * Copyright (C) 2016-2019 - Brad Parker
5 *
6 * RetroArch is free software: you can redistribute it and/or modify it under the terms
7 * of the GNU General Public License as published by the Free Software Found-
8 * ation, either version 3 of the License, or (at your option) any later version.
9 *
10 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with RetroArch.
15 * If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <caca.h>
19
20 #include <retro_miscellaneous.h>
21
22 #ifdef HAVE_MENU
23 #include "../../menu/menu_driver.h"
24 #endif
25
26 #include "../common/caca_common.h"
27
28 #include "../font_driver.h"
29
30 #include "../../driver.h"
31 #include "../../verbosity.h"
32
33 static void caca_gfx_free(void *data);
34
caca_gfx_create(caca_t * caca)35 static void caca_gfx_create(caca_t *caca)
36 {
37 caca->display = caca_create_display(NULL);
38 caca->cv = caca_get_canvas(caca->display);
39
40 if (!caca->video_width || !caca->video_height)
41 {
42 caca->video_width = caca_get_canvas_width(caca->cv);
43 caca->video_height = caca_get_canvas_height(caca->cv);
44 }
45
46 if (caca->rgb32)
47 caca->dither = caca_create_dither(32, caca->video_width,
48 caca->video_height, caca->video_pitch,
49 0x00ff0000, 0xff00, 0xff, 0x0);
50 else
51 caca->dither = caca_create_dither(16, caca->video_width,
52 caca->video_height, caca->video_pitch,
53 0xf800, 0x7e0, 0x1f, 0x0);
54
55 video_driver_set_size(caca->video_width, caca->video_height);
56 }
57
caca_gfx_init(const video_info_t * video,input_driver_t ** input,void ** input_data)58 static void *caca_gfx_init(const video_info_t *video,
59 input_driver_t **input, void **input_data)
60 {
61 caca_t *caca = (caca_t*)calloc(1, sizeof(*caca));
62
63 if (!caca)
64 return NULL;
65
66 *input = NULL;
67 *input_data = NULL;
68
69 caca->video_width = video->width;
70 caca->video_height = video->height;
71 caca->rgb32 = video->rgb32;
72
73 if (video->rgb32)
74 caca->video_pitch = video->width * 4;
75 else
76 caca->video_pitch = video->width * 2;
77
78 caca_gfx_create(caca);
79
80 if (!caca->cv || !caca->dither || !caca->display)
81 {
82 /* TODO: handle errors */
83 }
84
85 if (video->font_enable)
86 font_driver_init_osd(caca, video,
87 false, video->is_threaded,
88 FONT_DRIVER_RENDER_CACA);
89
90 return caca;
91 }
92
caca_gfx_frame(void * data,const void * frame,unsigned frame_width,unsigned frame_height,uint64_t frame_count,unsigned pitch,const char * msg,video_frame_info_t * video_info)93 static bool caca_gfx_frame(void *data, const void *frame,
94 unsigned frame_width, unsigned frame_height, uint64_t frame_count,
95 unsigned pitch, const char *msg, video_frame_info_t *video_info)
96 {
97 size_t len = 0;
98 void *buffer = NULL;
99 const void *frame_to_copy = frame;
100 unsigned width = 0;
101 unsigned height = 0;
102 bool draw = true;
103 caca_t *caca = (caca_t*)data;
104 #ifdef HAVE_MENU
105 bool menu_is_alive = video_info->menu_is_alive;
106 #endif
107
108 if (!frame || !frame_width || !frame_height)
109 return true;
110
111 if ( caca->video_width != frame_width ||
112 caca->video_height != frame_height ||
113 caca->video_pitch != pitch)
114 {
115 if (frame_width > 4 && frame_height > 4)
116 {
117 caca->video_width = frame_width;
118 caca->video_height = frame_height;
119 caca->video_pitch = pitch;
120 caca_gfx_free(caca);
121 caca_gfx_create(caca);
122 }
123 }
124
125 if (!caca->cv)
126 return true;
127
128 #ifdef HAVE_MENU
129 if (caca->menu_frame && menu_is_alive)
130 frame_to_copy = caca->menu_frame;
131 #endif
132
133 width = caca_get_canvas_width(caca->cv);
134 height = caca_get_canvas_height(caca->cv);
135
136 if ( frame_to_copy == frame &&
137 frame_width == 4 &&
138 frame_height == 4 &&
139 (frame_width < width && frame_height < height))
140 draw = false;
141
142 #ifdef HAVE_MENU
143 if (menu_is_alive)
144 draw = false;
145 #endif
146
147 caca_clear_canvas(caca->cv);
148
149 #ifdef HAVE_MENU
150 menu_driver_frame(menu_is_alive, video_info);
151 #endif
152
153 if (msg)
154 font_driver_render_msg(data, msg, NULL, NULL);
155
156 if (draw)
157 {
158 caca_dither_bitmap(caca->cv, 0, 0,
159 width,
160 height,
161 caca->dither, frame_to_copy);
162
163 buffer = caca_export_canvas_to_memory(caca->cv, "caca", &len);
164
165 if (buffer)
166 {
167 if (len)
168 caca_refresh_display(caca->display);
169
170 free(buffer);
171 }
172 }
173
174 return true;
175 }
176
caca_gfx_alive(void * data)177 static bool caca_gfx_alive(void *data)
178 {
179 caca_t *caca = (caca_t*)data;
180 video_driver_set_size(caca->video_width, caca->video_height);
181 return true;
182 }
183
caca_gfx_set_nonblock_state(void * data,bool a,bool b,unsigned c)184 static void caca_gfx_set_nonblock_state(void *data, bool a,
185 bool b, unsigned c) { }
caca_gfx_focus(void * data)186 static bool caca_gfx_focus(void *data) { return true; }
caca_gfx_suppress_screensaver(void * data,bool enable)187 static bool caca_gfx_suppress_screensaver(void *data, bool enable) { return false; }
caca_gfx_has_windowed(void * data)188 static bool caca_gfx_has_windowed(void *data) { return true; }
189
caca_gfx_free(void * data)190 static void caca_gfx_free(void *data)
191 {
192 caca_t *caca = (caca_t*)data;
193
194 if (caca->display)
195 caca_free_display(caca->display);
196 caca->display = NULL;
197
198 if (caca->dither)
199 caca_free_dither(caca->dither);
200 caca->dither = NULL;
201
202 if (caca->menu_frame)
203 free(caca->menu_frame);
204 caca->menu_frame = NULL;
205 }
206
caca_gfx_set_shader(void * data,enum rarch_shader_type type,const char * path)207 static bool caca_gfx_set_shader(void *data,
208 enum rarch_shader_type type, const char *path)
209 {
210 (void)data;
211 (void)type;
212 (void)path;
213
214 return false;
215 }
216
caca_gfx_set_rotation(void * data,unsigned rotation)217 static void caca_gfx_set_rotation(void *data,
218 unsigned rotation)
219 {
220 (void)data;
221 (void)rotation;
222 }
223
caca_set_texture_frame(void * data,const void * frame,bool rgb32,unsigned width,unsigned height,float alpha)224 static void caca_set_texture_frame(void *data,
225 const void *frame, bool rgb32, unsigned width, unsigned height,
226 float alpha)
227 {
228 caca_t *caca = (caca_t*)data;
229 unsigned pitch = width * 2;
230
231 if (rgb32)
232 pitch = width * 4;
233
234 if (caca->menu_frame)
235 free(caca->menu_frame);
236 caca->menu_frame = NULL;
237
238 if ( !caca->menu_frame ||
239 caca->menu_width != width ||
240 caca->menu_height != height ||
241 caca->menu_pitch != pitch)
242 {
243 if (pitch && height)
244 caca->menu_frame = (unsigned char*)malloc(pitch * height);
245 }
246
247 if (caca->menu_frame && frame && pitch && height)
248 memcpy(caca->menu_frame, frame, pitch * height);
249 }
250
251 static const video_poke_interface_t caca_poke_interface = {
252 NULL, /* get_flags */
253 NULL,
254 NULL,
255 NULL,
256 NULL,
257 NULL,
258 NULL,
259 NULL,
260 NULL,
261 NULL,
262 NULL,
263 NULL,
264 NULL,
265 caca_set_texture_frame,
266 NULL,
267 font_driver_render_msg,
268 NULL, /* show_mouse */
269 NULL, /* grab_mouse_toggle */
270 NULL, /* get_current_shader */
271 NULL, /* get_current_software_framebuffer */
272 NULL, /* get_hw_render_interface */
273 };
274
caca_gfx_get_poke_interface(void * data,const video_poke_interface_t ** iface)275 static void caca_gfx_get_poke_interface(void *data,
276 const video_poke_interface_t **iface)
277 {
278 (void)data;
279 *iface = &caca_poke_interface;
280 }
281
caca_gfx_set_viewport(void * data,unsigned viewport_width,unsigned viewport_height,bool force_full,bool allow_rotate)282 static void caca_gfx_set_viewport(void *data, unsigned viewport_width,
283 unsigned viewport_height, bool force_full, bool allow_rotate)
284 {
285 }
286
287 video_driver_t video_caca = {
288 caca_gfx_init,
289 caca_gfx_frame,
290 caca_gfx_set_nonblock_state,
291 caca_gfx_alive,
292 caca_gfx_focus,
293 caca_gfx_suppress_screensaver,
294 caca_gfx_has_windowed,
295 caca_gfx_set_shader,
296 caca_gfx_free,
297 "caca",
298 caca_gfx_set_viewport,
299 caca_gfx_set_rotation,
300 NULL, /* viewport_info */
301 NULL, /* read_viewport */
302 NULL, /* read_frame_raw */
303
304 #ifdef HAVE_OVERLAY
305 NULL, /* overlay_interface */
306 #endif
307 #ifdef HAVE_VIDEO_LAYOUT
308 NULL,
309 #endif
310 caca_gfx_get_poke_interface,
311 NULL /* wrap_type_to_enum */
312 };
313