1 /*
2  * File:        mat_preview.c
3  *
4  * Description:	displays a preview of the material attributes passed to it
5  *
6  * This source code is part of kludge3d, and is released under the
7  * GNU General Public License.
8  *
9  *
10  */
11 
12 /* Note: this file is based on:
13  * simple.c, written by Naofumi Yasufuku	<naofumi@users.sourceforge.net>
14  * ...which is one of the example programs packaged with gtkglext.
15  * I grabbed the checkered-background interleaved array (backer_square) from
16  * me3d's gtk_gl_tex_preview.
17  *
18  * This widget is intended as a simple replacement for me3d's
19  * gtk_gl_tex_preview.  The ultimate goal is to make it easier to port me3d's
20  * mat_edit to kludge3d.
21  *
22  * Note: Unlike me3d's gtk_gl_tex_preview, this widget is for output only.
23  * You can not *retrieve* the material attributes from the widget; you can
24  * only *set* the attributes.
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include <gtk/gtk.h>
32 #include <gtk/gtkgl.h>
33 #ifdef G_OS_WIN32
34 #define WIN32_LEAN_AND_MEAN 1
35 #include <windows.h>
36 #endif
37 #include <GL/gl.h>
38 #include <GL/glu.h>
39 
40 #include "mat_preview.h"
41 #include "material.h"
42 
43 #ifdef MEMWATCH
44 #include "memwatch.h"
45 #endif
46 
47 
48 #define MAT_PREVIEW_SPHERE_DISPLIST 1
49 #define MAT_PREVIEW_DRAW_CHECKERED_BACKGROUND 1
50 
51 
52 static GLfloat backer_square[] = {
53   0.50, 0.50, 0.50, 1.0,  0.0, 0.0, -1.0,  -100.0,  100.0, 0.0,
54   0.50, 0.50, 0.50, 1.0,  0.0, 0.0, -1.0,  -100.0,    0.0, 0.0,
55   0.50, 0.50, 0.50, 1.0,  0.0, 0.0, -1.0,     0.0,    0.0, 0.0,
56   0.50, 0.50, 0.50, 1.0,  0.0, 0.0, -1.0,     0.0,  100.0, 0.0,
57   0.75, 0.75, 0.75, 1.0,  0.0, 0.0, -1.0,     0.0,  100.0, 0.0,
58   0.75, 0.75, 0.75, 1.0,  0.0, 0.0, -1.0,     0.0,    0.0, 0.0,
59   0.75, 0.75, 0.75, 1.0,  0.0, 0.0, -1.0,   100.0,    0.0, 0.0,
60   0.75, 0.75, 0.75, 1.0,  0.0, 0.0, -1.0,   100.0,  100.0, 0.0,
61   0.75, 0.75, 0.75, 1.0,  0.0, 0.0, -1.0,  -100.0,    0.0, 0.0,
62   0.75, 0.75, 0.75, 1.0,  0.0, 0.0, -1.0,  -100.0, -100.0, 0.0,
63   0.75, 0.75, 0.75, 1.0,  0.0, 0.0, -1.0,     0.0, -100.0, 0.0,
64   0.75, 0.75, 0.75, 1.0,  0.0, 0.0, -1.0,     0.0,    0.0, 0.0,
65   0.50, 0.50, 0.50, 1.0,  0.0, 0.0, -1.0,     0.0,    0.0, 0.0,
66   0.50, 0.50, 0.50, 1.0,  0.0, 0.0, -1.0,     0.0, -100.0, 0.0,
67   0.50, 0.50, 0.50, 1.0,  0.0, 0.0, -1.0,   100.0, -100.0, 0.0,
68   0.50, 0.50, 0.50, 1.0,  0.0, 0.0, -1.0,   100.0,    0.0, 0.0,
69 };		/* C4F_N3F_V3F with CCW polygons */
70 
71 
72 
73 gboolean matpreview_free_attr(
74 	GtkWidget *widget, gpointer data );
75 
76 
77 static void
matpreview_realize(GtkWidget * widget,gpointer data)78 matpreview_realize( GtkWidget *widget, gpointer data )
79 {
80 	GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
81 	GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
82 
83 	GLUquadricObj *qobj;
84 	static GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};
85 	static GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0};
86 	GLfloat aspect = 1.0;
87 	int width, height;
88 
89 	/*** OpenGL BEGIN ***/
90 	if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
91 		return;
92 
93 	width = widget->allocation.width;
94 	height = widget->allocation.height;
95 
96 	qobj = gluNewQuadric ();
97 	gluQuadricDrawStyle (qobj, GLU_FILL);
98 	glNewList (MAT_PREVIEW_SPHERE_DISPLIST, GL_COMPILE);
99 	gluSphere (qobj, 1.0, 20, 20);
100 	glEndList ();
101 
102 	glLightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse);
103 	glLightfv (GL_LIGHT0, GL_POSITION, light_position);
104 	glEnable (GL_LIGHTING);
105 	glEnable (GL_LIGHT0);
106 
107 	glEnable (GL_DEPTH_TEST);
108 
109 	glClearColor (0.50, 0.50, 0.50, 1.0);
110 	glClearDepth (1.0);
111 
112 	glViewport (0, 0, width, height);
113 	aspect = (GLfloat)width / (GLfloat)height;
114 
115 	glMatrixMode (GL_PROJECTION);
116 	glLoadIdentity ();
117 	gluPerspective (40.0, (GLdouble)aspect, 1.0, 10.0);
118 
119 	glMatrixMode (GL_MODELVIEW);
120 	glLoadIdentity ();
121 	gluLookAt( 0.0, 0.0, 3.0,
122 				0.0, 0.0, 0.0,
123 				0.0, 1.0, 0.0 );
124 	glTranslatef (0.0, 0.0, -2.0);
125 
126 	gdk_gl_drawable_gl_end (gldrawable);
127 	/*** OpenGL END ***/
128 }
129 
130 static gboolean
matpreview_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer data)131 matpreview_configure_event(
132 	GtkWidget *widget, GdkEventConfigure *event, gpointer data )
133 {
134 	GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
135 	GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
136 
137 	/*** OpenGL BEGIN ***/
138 	if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
139 		return FALSE;
140 
141 	glViewport (0, 0,
142 		widget->allocation.width, widget->allocation.height);
143 
144 	gdk_gl_drawable_gl_end (gldrawable);
145 	/*** OpenGL END ***/
146 
147 	return TRUE;
148 }
149 
150 static gboolean
matpreview_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer data)151 matpreview_expose_event(
152 	GtkWidget *widget, GdkEventExpose *event, gpointer data )
153 {
154 	GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
155 	GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
156 	Material *mp_attr;
157 
158 	/*** OpenGL BEGIN ***/
159 	if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
160 		return FALSE;
161 
162 #if MAT_PREVIEW_DRAW_CHECKERED_BACKGROUND
163 	glClear (GL_DEPTH_BUFFER_BIT);
164 	glDisable(GL_LIGHTING);
165 	glInterleavedArrays(GL_C4F_N3F_V3F, 0, backer_square);
166 	glDrawArrays(GL_QUADS, 0, 16);
167 	glEnable(GL_LIGHTING);
168 #else
169 	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
170 #endif
171 
172 	mp_attr = (Material *)
173 		g_object_get_data( G_OBJECT( widget ), "user-data" );
174 
175     glMaterialfv(GL_FRONT, GL_AMBIENT, mp_attr->ambient);
176     glMaterialfv(GL_FRONT, GL_DIFFUSE, mp_attr->diffuse);
177     glMaterialfv(GL_FRONT, GL_SPECULAR, mp_attr->specular);
178     glMaterialfv(GL_FRONT, GL_EMISSION, mp_attr->emission);
179     glMaterialf(GL_FRONT, GL_SHININESS, mp_attr->shininess);
180 
181 	glCallList ( MAT_PREVIEW_SPHERE_DISPLIST );
182 
183 	if (gdk_gl_drawable_is_double_buffered (gldrawable))
184 		gdk_gl_drawable_swap_buffers (gldrawable);
185 	else
186 		glFlush ();
187 
188 	gdk_gl_drawable_gl_end (gldrawable);
189 	/*** OpenGL END ***/
190 
191 	return TRUE;
192 }
193 
194 
mat_preview_new(void)195 GtkWidget *mat_preview_new( void )
196 {
197 	GdkGLConfig *glconfig;
198 	GtkWidget *drawing_area;
199 	Material *mp_attr;
200 
201 	/*
202 	 * Configure OpenGL-capable visual.
203 	 */
204 
205 	/* Try double-buffered visual */
206 	glconfig = gdk_gl_config_new_by_mode (
207 		GDK_GL_MODE_RGB		|
208 		GDK_GL_MODE_DEPTH	|
209 		GDK_GL_MODE_DOUBLE);
210 
211 	if (glconfig == NULL) {
212 		fprintf( stderr, "*** Cannot find the double-buffered visual.\n");
213 		fprintf( stderr, "*** Trying single-buffered visual.\n");
214 
215 		/* Try single-buffered visual */
216 		glconfig = gdk_gl_config_new_by_mode (
217 			GDK_GL_MODE_RGB	 |
218 			GDK_GL_MODE_DEPTH );
219 		if (glconfig == NULL) {
220 			fprintf( stderr, "*** No appropriate OpenGL-capable visual found.\n" );
221 			return NULL;
222 		}
223 	}
224 
225 	/*
226 	 * Drawing area for drawing OpenGL scene.
227 	 */
228 
229 	drawing_area = gtk_drawing_area_new ();
230 	gtk_widget_set_size_request (drawing_area, 200, 200);
231 
232 	/* Set OpenGL-capability to the widget. */
233 	gtk_widget_set_gl_capability (drawing_area,
234 		glconfig,
235 		NULL,
236 		TRUE,
237 		GDK_GL_RGBA_TYPE);
238 
239 	mp_attr = material_new();
240 
241 	g_object_set_data( G_OBJECT( drawing_area ), "user-data", mp_attr );
242 	g_signal_connect (G_OBJECT (drawing_area), "destroy",
243 				G_CALLBACK (matpreview_free_attr), mp_attr );
244 
245 	g_signal_connect_after (G_OBJECT (drawing_area), "realize",
246 				G_CALLBACK (matpreview_realize), NULL);
247 	g_signal_connect (G_OBJECT (drawing_area), "configure_event",
248 				G_CALLBACK (matpreview_configure_event), NULL);
249 	g_signal_connect (G_OBJECT (drawing_area), "expose_event",
250 				G_CALLBACK (matpreview_expose_event), NULL);
251 
252 	gtk_widget_show (drawing_area);
253 
254 	return drawing_area;
255 }
256 
257 
mat_preview_set_all(GtkWidget * widget,Material * material)258 void mat_preview_set_all( GtkWidget *widget, Material *material ) {
259 	Material *mp_attr;
260 
261 	mp_attr = (Material *)
262 		g_object_get_data( G_OBJECT( widget ), "user-data" );
263 	if( mp_attr == NULL )
264 		return;
265 
266 	material_copy( mp_attr, material );
267 
268 	gtk_widget_queue_draw( widget );
269 }
270 
271 
mat_preview_set_ambient(GtkWidget * widget,float * ambient)272 void mat_preview_set_ambient( GtkWidget *widget, float *ambient ) {
273 	Material *mp_attr;
274 
275 	mp_attr = (Material *)
276 		g_object_get_data( G_OBJECT( widget ), "user-data" );
277 	if( mp_attr == NULL )
278 		return;
279 
280 	mp_attr->ambient[0] = ambient[0];
281 	mp_attr->ambient[1] = ambient[1];
282 	mp_attr->ambient[2] = ambient[2];
283 	mp_attr->ambient[3] = ambient[3];
284 
285 	gtk_widget_queue_draw( widget );
286 }
287 
288 
mat_preview_set_diffuse(GtkWidget * widget,float * diffuse)289 void mat_preview_set_diffuse( GtkWidget *widget, float *diffuse ) {
290 	Material *mp_attr;
291 
292 	mp_attr = (Material *)
293 		g_object_get_data( G_OBJECT( widget ), "user-data" );
294 	if( mp_attr == NULL )
295 		return;
296 
297 	mp_attr->diffuse[0] = diffuse[0];
298 	mp_attr->diffuse[1] = diffuse[1];
299 	mp_attr->diffuse[2] = diffuse[2];
300 	mp_attr->diffuse[3] = diffuse[3];
301 
302 	gtk_widget_queue_draw( widget );
303 }
304 
305 
mat_preview_set_specular(GtkWidget * widget,float * specular)306 void mat_preview_set_specular( GtkWidget *widget, float *specular ) {
307 	Material *mp_attr;
308 
309 	mp_attr = (Material *)
310 		g_object_get_data( G_OBJECT( widget ), "user-data" );
311 	if( mp_attr == NULL )
312 		return;
313 
314 	mp_attr->specular[0] = specular[0];
315 	mp_attr->specular[1] = specular[1];
316 	mp_attr->specular[2] = specular[2];
317 	mp_attr->specular[3] = specular[3];
318 
319 	gtk_widget_queue_draw( widget );
320 }
321 
322 
mat_preview_set_emission(GtkWidget * widget,float * emission)323 void mat_preview_set_emission( GtkWidget *widget, float *emission ) {
324 	Material *mp_attr;
325 
326 	mp_attr = (Material *)
327 		g_object_get_data( G_OBJECT( widget ), "user-data" );
328 	if( mp_attr == NULL )
329 		return;
330 
331 	mp_attr->emission[0] = emission[0];
332 	mp_attr->emission[1] = emission[1];
333 	mp_attr->emission[2] = emission[2];
334 	mp_attr->emission[3] = emission[3];
335 
336 	gtk_widget_queue_draw( widget );
337 }
338 
339 
mat_preview_set_shininess(GtkWidget * widget,float shininess)340 void mat_preview_set_shininess( GtkWidget *widget, float shininess ) {
341 	Material *mp_attr;
342 
343 	mp_attr = (Material *)
344 		g_object_get_data( G_OBJECT( widget ), "user-data" );
345 	if( mp_attr == NULL )
346 		return;
347 
348 	mp_attr->shininess = shininess;
349 
350 	gtk_widget_queue_draw( widget );
351 }
352 
353 
matpreview_free_attr(GtkWidget * widget,gpointer data)354 gboolean matpreview_free_attr(
355 	GtkWidget *widget, gpointer data )
356 {
357 	free( data );
358 	return FALSE;
359 }
360 
361 
362 /**************************************************************************
363 
364 DEAD CODE
365 
366 ***************************************************************************/
367 
368 #if 0
369 
370 static void
371 print_gl_config_attrib (GdkGLConfig *glconfig,
372 		const gchar *attrib_str,
373 		int					attrib,
374 		gboolean		 is_boolean)
375 {
376 	int value;
377 
378 	g_print ("%s = ", attrib_str);
379 	if (gdk_gl_config_get_attrib (glconfig, attrib, &value))
380 		{
381 			if (is_boolean)
382 				g_print ("%s\n", value == TRUE ? "TRUE" : "FALSE");
383 			else
384 				g_print ("%d\n", value);
385 		}
386 	else
387 		g_print ("*** Cannot get %s attribute value\n", attrib_str);
388 }
389 
390 static void
391 examine_gl_config_attrib (GdkGLConfig *glconfig)
392 {
393 	g_print ("\nOpenGL visual configurations :\n\n");
394 
395 	g_print ("gdk_gl_config_is_rgba (glconfig) = %s\n",
396 					 gdk_gl_config_is_rgba (glconfig) ? "TRUE" : "FALSE");
397 	g_print ("gdk_gl_config_is_double_buffered (glconfig) = %s\n",
398 					 gdk_gl_config_is_double_buffered (glconfig) ? "TRUE" : "FALSE");
399 	g_print ("gdk_gl_config_is_stereo (glconfig) = %s\n",
400 					 gdk_gl_config_is_stereo (glconfig) ? "TRUE" : "FALSE");
401 	g_print ("gdk_gl_config_has_alpha (glconfig) = %s\n",
402 					 gdk_gl_config_has_alpha (glconfig) ? "TRUE" : "FALSE");
403 	g_print ("gdk_gl_config_has_depth_buffer (glconfig) = %s\n",
404 					 gdk_gl_config_has_depth_buffer (glconfig) ? "TRUE" : "FALSE");
405 	g_print ("gdk_gl_config_has_stencil_buffer (glconfig) = %s\n",
406 					 gdk_gl_config_has_stencil_buffer (glconfig) ? "TRUE" : "FALSE");
407 	g_print ("gdk_gl_config_has_accum_buffer (glconfig) = %s\n",
408 					 gdk_gl_config_has_accum_buffer (glconfig) ? "TRUE" : "FALSE");
409 
410 	g_print ("\n");
411 
412 	print_gl_config_attrib (glconfig, "GDK_GL_USE_GL",					 GDK_GL_USE_GL,					 TRUE);
413 	print_gl_config_attrib (glconfig, "GDK_GL_BUFFER_SIZE",			GDK_GL_BUFFER_SIZE,			FALSE);
414 	print_gl_config_attrib (glconfig, "GDK_GL_LEVEL",						GDK_GL_LEVEL,						FALSE);
415 	print_gl_config_attrib (glconfig, "GDK_GL_RGBA",						 GDK_GL_RGBA,						 TRUE);
416 	print_gl_config_attrib (glconfig, "GDK_GL_DOUBLEBUFFER",		 GDK_GL_DOUBLEBUFFER,		 TRUE);
417 	print_gl_config_attrib (glconfig, "GDK_GL_STEREO",					 GDK_GL_STEREO,					 TRUE);
418 	print_gl_config_attrib (glconfig, "GDK_GL_AUX_BUFFERS",			GDK_GL_AUX_BUFFERS,			FALSE);
419 	print_gl_config_attrib (glconfig, "GDK_GL_RED_SIZE",				 GDK_GL_RED_SIZE,				 FALSE);
420 	print_gl_config_attrib (glconfig, "GDK_GL_GREEN_SIZE",			 GDK_GL_GREEN_SIZE,			 FALSE);
421 	print_gl_config_attrib (glconfig, "GDK_GL_BLUE_SIZE",				GDK_GL_BLUE_SIZE,				FALSE);
422 	print_gl_config_attrib (glconfig, "GDK_GL_ALPHA_SIZE",			 GDK_GL_ALPHA_SIZE,			 FALSE);
423 	print_gl_config_attrib (glconfig, "GDK_GL_DEPTH_SIZE",			 GDK_GL_DEPTH_SIZE,			 FALSE);
424 	print_gl_config_attrib (glconfig, "GDK_GL_STENCIL_SIZE",		 GDK_GL_STENCIL_SIZE,		 FALSE);
425 	print_gl_config_attrib (glconfig, "GDK_GL_ACCUM_RED_SIZE",	 GDK_GL_ACCUM_RED_SIZE,	 FALSE);
426 	print_gl_config_attrib (glconfig, "GDK_GL_ACCUM_GREEN_SIZE", GDK_GL_ACCUM_GREEN_SIZE, FALSE);
427 	print_gl_config_attrib (glconfig, "GDK_GL_ACCUM_BLUE_SIZE",	GDK_GL_ACCUM_BLUE_SIZE,	FALSE);
428 	print_gl_config_attrib (glconfig, "GDK_GL_ACCUM_ALPHA_SIZE", GDK_GL_ACCUM_ALPHA_SIZE, FALSE);
429 
430 	g_print ("\n");
431 }
432 
433 
434 #endif
435 
436 
437 
438 
439 
440 
441