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