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