1 #include <gtk/gtk.h>
2 #include <gdk/gdk.h>
3 #include <cairo.h>
4 #include "gtk_display.h"
5 #include "gtk_display_driver_gtk.h"
6 
7 
S9xGTKDisplayDriver(Snes9xWindow * window,Snes9xConfig * config)8 S9xGTKDisplayDriver::S9xGTKDisplayDriver (Snes9xWindow *window,
9                                           Snes9xConfig *config)
10 {
11     this->window = window;
12     this->config = config;
13     this->drawing_area = GTK_WIDGET (window->drawing_area);
14     this->pixbuf = NULL;
15 
16     return;
17 }
18 
19 void
update(int width,int height)20 S9xGTKDisplayDriver::update (int width, int height)
21 {
22     int           x, y, w, h;
23     int           c_width, c_height, final_pitch;
24     uint8         *final_buffer;
25     GtkAllocation allocation;
26 
27     gtk_widget_get_allocation (drawing_area, &allocation);
28     c_width = allocation.width;
29     c_height = allocation.height;
30 
31     if (width <= 0)
32         return;
33 
34     if (config->scale_method > 0)
35     {
36         uint8 *src_buffer = (uint8 *) padded_buffer[0];
37         uint8 *dst_buffer = (uint8 *) padded_buffer[1];
38         int   src_pitch = image_width * image_bpp;
39         int   dst_pitch = scaled_max_width * image_bpp;
40 
41         S9xFilter (src_buffer,
42                    src_pitch,
43                    dst_buffer,
44                    dst_pitch,
45                    width,
46                    height);
47 
48         final_buffer = (uint8 *) padded_buffer[1];
49         final_pitch = dst_pitch;
50     }
51     else
52     {
53         final_buffer = (uint8 *) padded_buffer[0];
54         final_pitch = image_width * image_bpp;
55     }
56 
57     x = width; y = height; w = c_width; h = c_height;
58     S9xApplyAspect (x, y, w, h);
59 
60     output (final_buffer, final_pitch, x, y, width, height, w, h);
61 
62     return;
63 }
64 
65 void
output(void * src,int src_pitch,int x,int y,int width,int height,int dst_width,int dst_height)66 S9xGTKDisplayDriver::output (void *src,
67                              int  src_pitch,
68                              int  x,
69                              int  y,
70                              int  width,
71                              int  height,
72                              int  dst_width,
73                              int  dst_height)
74 {
75     if (width != gdk_buffer_width || height != gdk_buffer_height)
76     {
77         gdk_buffer_width = width;
78         gdk_buffer_height = height;
79 
80         g_object_unref (pixbuf);
81 
82         padded_buffer[2] = realloc (padded_buffer[2],
83                                     gdk_buffer_width * gdk_buffer_height * 3);
84         pixbuf = gdk_pixbuf_new_from_data ((guchar *) padded_buffer[2],
85                                            GDK_COLORSPACE_RGB,
86                                            FALSE,
87                                            8,
88                                            gdk_buffer_width,
89                                            gdk_buffer_height,
90                                            gdk_buffer_width * 3,
91                                            NULL,
92                                            NULL);
93     }
94 
95     if (last_known_width != dst_width || last_known_height != dst_height)
96     {
97         clear ();
98 
99         last_known_width = dst_width;
100         last_known_height = dst_height;
101     }
102 
103     S9xConvert (src,
104                 padded_buffer[2],
105                 src_pitch,
106                 gdk_buffer_width * 3,
107                 width,
108                 height,
109                 24);
110 
111     cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (drawing_area));
112 
113     gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
114 
115     if (width != dst_width || height != dst_height)
116     {
117         cairo_matrix_t matrix;
118         cairo_pattern_t *pattern = cairo_get_source (cr);;
119 
120         cairo_matrix_init_identity (&matrix);
121         cairo_matrix_scale (&matrix,
122                             (double) width / (double) dst_width,
123                             (double) height / (double) dst_height);
124         cairo_matrix_translate (&matrix, -x, -y);
125         cairo_pattern_set_matrix (pattern, &matrix);
126         cairo_pattern_set_filter (pattern,
127                                   config->bilinear_filter
128                                        ? CAIRO_FILTER_BILINEAR
129                                        : CAIRO_FILTER_NEAREST);
130     }
131 
132     cairo_rectangle (cr, x, y, dst_width, dst_height);
133     cairo_fill (cr);
134 
135     cairo_destroy (cr);
136 
137     window->set_mouseable_area (x, y, width, height);
138 
139     return;
140 }
141 
142 int
init(void)143 S9xGTKDisplayDriver::init (void)
144 {
145     int padding;
146     GtkAllocation allocation;
147 
148     buffer[0] = malloc (image_padded_size);
149     buffer[1] = malloc (scaled_padded_size);
150 
151     padding = (image_padded_size - image_size) / 2;
152     padded_buffer[0] = (void *) (((uint8 *) buffer[0]) + padding);
153 
154     padding = (scaled_padded_size - scaled_size) / 2;
155     padded_buffer[1] = (void *) (((uint8 *) buffer[1]) + padding);
156 
157     gtk_widget_get_allocation (drawing_area, &allocation);
158     gdk_buffer_width = allocation.width;
159     gdk_buffer_height = allocation.height;
160 
161     padded_buffer[2] = malloc (gdk_buffer_width * gdk_buffer_height * 3);
162     pixbuf = gdk_pixbuf_new_from_data ((guchar *) padded_buffer[2],
163                                        GDK_COLORSPACE_RGB,
164                                        FALSE,
165                                        8,
166                                        gdk_buffer_width,
167                                        gdk_buffer_height,
168                                        gdk_buffer_width * 3,
169                                        NULL,
170                                        NULL);
171 
172     S9xSetEndianess (ENDIAN_MSB);
173 
174     memset (buffer[0], 0, image_padded_size);
175     memset (buffer[1], 0, scaled_padded_size);
176 
177     GFX.Screen = (uint16 *) padded_buffer[0];
178     GFX.Pitch = image_width * image_bpp;
179 
180     return 0;
181 }
182 
183 void
deinit(void)184 S9xGTKDisplayDriver::deinit (void)
185 {
186     padded_buffer[0] = NULL;
187     padded_buffer[1] = NULL;
188 
189     free (buffer[0]);
190     free (buffer[1]);
191 
192     g_object_unref (pixbuf);
193     free (padded_buffer[2]);
194 
195     return;
196 }
197 
198 void
clear(void)199 S9xGTKDisplayDriver::clear (void)
200 {
201     int  x, y, w, h;
202     int  width, height;
203     GtkAllocation allocation;
204 
205     gtk_widget_get_allocation (drawing_area, &allocation);
206     width = allocation.width;
207     height = allocation.height;
208 
209     cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (drawing_area));
210 
211     cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
212 
213     if (window->last_width <= 0 || window->last_height <= 0)
214     {
215         cairo_paint (cr);
216         cairo_destroy (cr);
217 
218         return;
219     }
220 
221     x = window->last_width;
222     y = window->last_height;
223     get_filter_scale (x, y);
224     w = width;
225     h = height;
226     S9xApplyAspect (x, y, w, h);
227 
228     if (x > 0)
229     {
230         cairo_rectangle (cr, 0, y, x, h);
231     }
232     if (x + w < width)
233     {
234         cairo_rectangle (cr, x + w, y, width - (x + w), h);
235     }
236     if (y > 0)
237     {
238         cairo_rectangle (cr, 0, 0, width, y);
239     }
240     if (y + h < height)
241     {
242         cairo_rectangle (cr, 0, y + h, width, height - (y + h));
243     }
244 
245     cairo_fill (cr);
246     cairo_destroy (cr);
247 
248     return;
249 }
250 
251 void
refresh(int width,int height)252 S9xGTKDisplayDriver::refresh (int width, int height)
253 {
254     if (!config->rom_loaded)
255         return;
256 
257     clear ();
258 
259     return;
260 }
261 
262 uint16 *
get_next_buffer(void)263 S9xGTKDisplayDriver::get_next_buffer (void)
264 {
265     return (uint16 *) padded_buffer[0];
266 }
267 
268 uint16 *
get_current_buffer(void)269 S9xGTKDisplayDriver::get_current_buffer (void)
270 {
271     return (uint16 *) padded_buffer[0];
272 }
273 
274 void
push_buffer(uint16 * src)275 S9xGTKDisplayDriver::push_buffer (uint16 *src)
276 {
277     memmove (GFX.Screen, src, image_size);
278     update (window->last_width, window->last_height);
279 
280     return;
281 }
282 
283 void
clear_buffers(void)284 S9xGTKDisplayDriver::clear_buffers (void)
285 {
286     memset (buffer[0], 0, image_padded_size);
287     memset (buffer[1], 0, scaled_padded_size);
288 
289     return;
290 }
291 
292 void
reconfigure(int width,int height)293 S9xGTKDisplayDriver::reconfigure (int width, int height)
294 {
295     return;
296 }
297