1 /* Copyright 2006 Guillaume Duhamel
2 Copyright 2006 Fabien Coulon
3
4 This file is part of Yabause.
5
6 Yabause is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 Yabause is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Yabause; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "gtkglwidget.h"
22 #ifdef HAVE_LIBGTKGLEXT
23 #include <gtk/gtkgl.h>
24 #endif
25 #include "../vidsoft.h"
26 #include "../peripheral.h"
27
28 #define X_NOSCALE 160
29 #define Y_NOSCALE 120
30
31 static void yui_gl_class_init (YuiGlClass * klass);
32 static void yui_gl_init (YuiGl * yfe);
33 static gboolean yui_gl_resize (GtkWidget *w,GdkEventConfigure *event, gpointer data);
34
yui_gl_draw(YuiGl * glxarea)35 void yui_gl_draw(YuiGl * glxarea) {
36 #ifdef HAVE_LIBGTKGLEXT
37 GdkGLContext *glcontext = gtk_widget_get_gl_context (GTK_WIDGET(glxarea));
38 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (GTK_WIDGET(glxarea));
39
40 if (!gdk_gl_drawable_make_current (gldrawable, glcontext)) {
41 g_print("Cannot set gl drawable current\n");
42 return;
43 }
44
45 gdk_gl_drawable_swap_buffers(gldrawable);
46 #else
47 int buf_width, buf_height;
48 GdkPixbuf * pixbuf, * scaledpixbuf;
49
50 VIDCore->GetGlSize( &buf_width, &buf_height );
51 glxarea->pixels_width = GTK_WIDGET(glxarea)->allocation.width;
52 glxarea->pixels_height = GTK_WIDGET(glxarea)->allocation.height;
53 glxarea->pixels_rowstride = glxarea->pixels_width * 4;
54 glxarea->pixels_rowstride += (glxarea->pixels_rowstride % 4)? (4 - (glxarea->pixels_rowstride % 4)): 0;
55
56 if (dispbuffer == NULL) return;
57
58 pixbuf = gdk_pixbuf_new_from_data((const guchar *) dispbuffer, GDK_COLORSPACE_RGB, TRUE, 8,
59 buf_width, buf_height, buf_width*4, NULL, NULL);
60
61 if (( glxarea->pixels_width < buf_width + X_NOSCALE )&&( glxarea->pixels_height < buf_height + Y_NOSCALE )) {
62
63 gdk_draw_pixbuf(GTK_WIDGET(glxarea)->window, NULL, pixbuf, 0, 0,
64 (glxarea->pixels_width-buf_width)/2, (glxarea->pixels_height-buf_height)/2,
65 buf_width, buf_height, GDK_RGB_DITHER_NONE, 0, 0);
66 } else {
67
68 scaledpixbuf = gdk_pixbuf_scale_simple(pixbuf,
69 glxarea->pixels_width, glxarea->pixels_height, GDK_INTERP_NEAREST );
70 gdk_draw_pixbuf(GTK_WIDGET(glxarea)->window, NULL,
71 scaledpixbuf, 0, 0, 0, 0, glxarea->pixels_width, glxarea->pixels_height,
72 GDK_RGB_DITHER_NONE, 0, 0);
73 g_object_unref(scaledpixbuf);
74 }
75 g_object_unref(pixbuf);
76 #endif
77 glxarea->is_init = 1;
78 }
79
yui_gl_draw_pause(YuiGl * glxarea)80 void yui_gl_draw_pause(YuiGl * glxarea) {
81 #ifdef HAVE_LIBGTKGLEXT
82 if (glxarea->pixels) {
83 /* The "correct" raster position would be (0, height) but it's not a
84 * valid position, so I have to use this hack... found here:
85 * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/ */
86 glRasterPos2i(0, 0);
87 glBitmap(0, 0, 0, 0, 0, - glxarea->pixels_height, NULL);
88 glPixelZoom(1, 1);
89 glDrawPixels(glxarea->pixels_width, glxarea->pixels_height, GL_RGB, GL_UNSIGNED_BYTE, glxarea->pixels);
90 yui_gl_draw(glxarea);
91 } else {
92 gdk_draw_rectangle(GTK_WIDGET(glxarea)->window, GTK_WIDGET(glxarea)->style->bg_gc[GTK_WIDGET_STATE (glxarea)],
93 TRUE, 0, 0, GTK_WIDGET(glxarea)->allocation.width, GTK_WIDGET(glxarea)->allocation.height);
94 }
95 #else
96 if (dispbuffer)
97 yui_gl_draw(glxarea);
98 #endif
99 }
100
yui_gl_resize(GtkWidget * w,GdkEventConfigure * event,gpointer data)101 static gboolean yui_gl_resize(GtkWidget *w,GdkEventConfigure *event, gpointer data) {
102 #ifdef HAVE_LIBGTKGLEXT
103 GdkGLContext *glcontext = gtk_widget_get_gl_context (w);
104 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (w);
105
106 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
107 return FALSE;
108
109 glViewport(0, 0, event->width, event->height);
110 if ( YUI_GL(w)->is_init ) VIDCore->Resize(event->width, event->height, FALSE );
111 #endif
112 return FALSE;
113 }
114
115 int beforehiding = 0;
116
gonna_hide(gpointer data)117 static gboolean gonna_hide(gpointer data) {
118 beforehiding--;
119
120 if (beforehiding == 0) {
121 static char source_data[] = { 0 };
122 static char mask_data[] = { 0 };
123
124 GdkCursor *cursor;
125 GdkPixmap *source, *mask;
126 GdkColor fg = { 0, 65535, 65535, 65535 };
127 GdkColor bg = { 0, 0, 0, 0 };
128
129 source = gdk_bitmap_create_from_data(NULL, source_data, 1, 1);
130 mask = gdk_bitmap_create_from_data(NULL, mask_data, 1, 1);
131 cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 1, 1);
132 gdk_pixmap_unref(source);
133 gdk_pixmap_unref(mask);
134
135 gdk_window_set_cursor(GTK_WIDGET(data)->window, cursor);
136
137 return FALSE;
138 } else {
139 return TRUE;
140 }
141 }
142
143 extern void * padbits;
144 extern GKeyFile * keyfile;
145 int oldx = 0;
146 int oldy = 0;
147
yui_gl_hide_cursor(GtkWidget * widget,GdkEventMotion * event,gpointer user_data)148 static gboolean yui_gl_hide_cursor(GtkWidget * widget, GdkEventMotion * event, gpointer user_data) {
149 if (PerGetId(padbits) == PERMOUSE) {
150 int x = event->x;
151 int y = event->y;
152 double speed = g_key_file_get_double(keyfile, "General", "MouseSpeed", NULL);
153
154 PerMouseMove(padbits, speed * (x - oldx), -speed * (y - oldy));
155 oldx = x;
156 oldy = y;
157 }
158
159 if (beforehiding == 0) {
160 gdk_window_set_cursor(widget->window, NULL);
161 g_timeout_add(1000, gonna_hide, widget);
162 }
163
164 beforehiding = 2;
165
166 return FALSE;
167 }
168
yui_gl_button_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)169 static gboolean yui_gl_button_press(GtkWidget * widget, GdkEventButton * event, gpointer user_data) {
170 if (PerGetId(padbits) == PERMOUSE) {
171 switch(event->button) {
172 case 1:
173 PerMouseLeftPressed(padbits);
174 break;
175 case 2:
176 PerMouseMiddlePressed(padbits);
177 break;
178 case 3:
179 PerMouseRightPressed(padbits);
180 break;
181 }
182 }
183 return FALSE;
184 }
185
yui_gl_button_release(GtkWidget * widget,GdkEventButton * event,gpointer user_data)186 static gboolean yui_gl_button_release(GtkWidget * widget, GdkEventButton * event, gpointer user_data) {
187 if (PerGetId(padbits) == PERMOUSE) {
188 switch(event->button) {
189 case 1:
190 PerMouseLeftReleased(padbits);
191 break;
192 case 2:
193 PerMouseMiddleReleased(padbits);
194 break;
195 case 3:
196 PerMouseRightReleased(padbits);
197 break;
198 }
199 }
200 return FALSE;
201 }
202
yui_gl_new(void)203 GtkWidget * yui_gl_new(void) {
204 GtkWidget * drawingArea;
205 #ifdef HAVE_LIBGTKGLEXT
206 int attribs[] = {
207 GDK_GL_RGBA,
208 GDK_GL_RED_SIZE, 1,
209 GDK_GL_GREEN_SIZE, 1,
210 GDK_GL_BLUE_SIZE, 1,
211
212 GDK_GL_DOUBLEBUFFER,
213
214 GDK_GL_DEPTH_SIZE ,1,
215 GDK_GL_STENCIL_SIZE ,8,
216 GDK_GL_ATTRIB_LIST_NONE
217 };
218 #endif
219
220 drawingArea = GTK_WIDGET(g_object_new(yui_gl_get_type(), NULL));
221 YUI_GL(drawingArea)->is_init = 0;
222
223 #ifdef HAVE_LIBGTKGLEXT
224 gtk_widget_set_gl_capability(drawingArea, gdk_gl_config_new(attribs), NULL, TRUE, GDK_GL_RGBA_TYPE);
225 #endif
226
227 g_signal_connect (GTK_OBJECT(drawingArea),"configure_event", GTK_SIGNAL_FUNC(yui_gl_resize),0);
228
229 gtk_widget_set_events(drawingArea, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
230
231 g_signal_connect(GTK_OBJECT(drawingArea), "motion-notify-event", GTK_SIGNAL_FUNC(yui_gl_hide_cursor),0);
232 g_signal_connect(GTK_OBJECT(drawingArea), "button-press-event", GTK_SIGNAL_FUNC(yui_gl_button_press),0);
233 g_signal_connect(GTK_OBJECT(drawingArea), "button-release-event", GTK_SIGNAL_FUNC(yui_gl_button_release),0);
234
235 return drawingArea;
236 }
237
yui_gl_dump_screen(YuiGl * glxarea)238 void yui_gl_dump_screen(YuiGl * glxarea) {
239 #ifdef HAVE_LIBGTKGLEXT
240 int size;
241
242 glxarea->pixels_width = GTK_WIDGET(glxarea)->allocation.width;
243 glxarea->pixels_height = GTK_WIDGET(glxarea)->allocation.height;
244 glxarea->pixels_rowstride = glxarea->pixels_width * 3;
245 glxarea->pixels_rowstride += (glxarea->pixels_rowstride % 4)? (4 - (glxarea->pixels_rowstride % 4)): 0;
246
247 size = glxarea->pixels_rowstride * glxarea->pixels_height;
248
249 if (glxarea->pixels) free(glxarea->pixels);
250 glxarea->pixels = malloc(sizeof(GLubyte) * size);
251 if (glxarea->pixels == NULL) return;
252
253 glReadPixels(0, 0, glxarea->pixels_width, glxarea->pixels_height, GL_RGB, GL_UNSIGNED_BYTE, glxarea->pixels);
254 #else
255 int buf_width, buf_height;
256 int i, j;
257 int size;
258 int cur = 0;
259 u8 * pixels;
260 u8 * buffer;
261
262 VIDCore->GetGlSize( &buf_width, &buf_height );
263 size = buf_width * buf_height * 3;
264
265 glxarea->pixels_width = buf_width;
266 glxarea->pixels_height = buf_height;
267 glxarea->pixels_rowstride = glxarea->pixels_width * 3;
268 glxarea->pixels_rowstride += (glxarea->pixels_rowstride % 4)? (4 - (glxarea->pixels_rowstride % 4)): 0;
269
270 if (! glxarea->pixels) glxarea->pixels = malloc(sizeof(u8) * size);
271
272 pixels = (u8 *)glxarea->pixels;
273 pixels += size - (buf_width * 3);
274 buffer = (u8 *)dispbuffer;
275
276 for(i = 0;i < buf_height;i++) {
277 for(j = 0;j < buf_width;j++) {
278 *pixels++ = buffer[cur];
279 *pixels++ = buffer[cur + 1];
280 *pixels++ = buffer[cur + 2];
281 cur += 4;
282 }
283 pixels -= buf_width * 6;
284 }
285 #endif
286 }
287
yui_gl_get_type(void)288 GType yui_gl_get_type (void) {
289 static GType yfe_type = 0;
290
291 if (!yfe_type)
292 {
293 static const GTypeInfo yfe_info =
294 {
295 sizeof (YuiGlClass),
296 NULL, /* base_init */
297 NULL, /* base_finalize */
298 (GClassInitFunc) yui_gl_class_init,
299 NULL, /* class_finalize */
300 NULL, /* class_data */
301 sizeof (YuiGl),
302 0,
303 (GInstanceInitFunc) yui_gl_init,
304 NULL,
305 };
306
307 yfe_type = g_type_register_static(GTK_TYPE_DRAWING_AREA, "YuiGl", &yfe_info, 0);
308 }
309
310 return yfe_type;
311 }
312
yui_gl_class_init(UNUSED YuiGlClass * klass)313 static void yui_gl_class_init (UNUSED YuiGlClass * klass) {
314 }
315
yui_gl_init(YuiGl * y)316 static void yui_gl_init (YuiGl * y) {
317 y->pixels = NULL;
318 }
319