/* EXTRAITS DE LA LICENCE
Copyright CEA, contributeurs : Luc BILLARD et Damien
CALISTE, laboratoire L_Sim, (2001-2006)
Adresse mèl :
BILLARD, non joignable par mèl ;
CALISTE, damien P caliste AT cea P fr.
Ce logiciel est un programme informatique servant à visualiser des
structures atomiques dans un rendu pseudo-3D.
Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".
Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
*/
/* LICENCE SUM UP
Copyright CEA, contributors : Luc BILLARD et Damien
CALISTE, laboratoire L_Sim, (2001-2006)
E-mail address:
BILLARD, not reachable any more ;
CALISTE, damien P caliste AT cea P fr.
This software is a computer program whose purpose is to visualize atomic
configurations in 3D.
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms. You can
find a copy of this licence shipped with this software at Documentation/licence.en.txt.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "gtk/gtkwidget.h"
#include <GL/gl.h>
#include "gtk_openGLWidget.h"
#include "OSOpenGL/visu_openGL.h"
#include "visu_tools.h"
/* OS dependent includes */
#if SYSTEM_X11 == 1
#include <GL/glx.h>
#include <gdk/gdkx.h>
#endif
#if SYSTEM_WIN32 == 1
#include <windows.h>
#include <gdk/gdkwin32.h>
#endif
struct OpenGLWidget_struct
{
GtkWidget parent;
gboolean sizeAllocation_has_run;
gboolean dispose_has_run;
/* Redraw method and user data. */
RedrawMethod redraw;
gpointer redrawData;
/* OpenGL part, OS dependent. */
#if SYSTEM_X11 == 1
Display *dpy;
gboolean isContextDirect;
GLXContext context;
#endif
#if SYSTEM_WIN32 == 1
HDC hdc;
gboolean isContextDirect;
HGLRC context;
HWND windowId;
#endif
};
struct OpenGLWidgetClass_struct
{
GtkWidgetClass parent_class;
OpenGLWidget *contextCurrent;
};
/* Local variables. */
static gpointer parent_class;
static OpenGLWidgetClass *myClass = (OpenGLWidgetClass*)0;
/* Local callbacks. */
static gboolean openGLWidgetEvent_expose(GtkWidget *widget, GdkEventExpose *event);
static void openGLWidgetEvent_sizeRequest(GtkWidget *widget, GtkRequisition *requisition);
static void openGLWidgetEvent_sizeAllocate(GtkWidget *widget, GtkAllocation *allocation);
static void openGLWidgetEvent_realise(GtkWidget *widget);
static void openGLWidgetEvent_styleSet(GtkWidget *widget, GtkStyle *previous_style);
/* Initialisation methods. */
static void openGLWidgetInit_class(OpenGLWidgetClass *class);
static void openGLWidgetInit_object(OpenGLWidget *render);
static void openGLWidgetInit_context(OpenGLWidget *render, gboolean contextIsDirect);
/* Freeing methods. */
static void openGLWidgetEvent_dispose(GObject *obj);
static void openGLWidgetEvent_finalize(GObject *obj);
static void openGLWidgetFree_openGL(OpenGLWidget *render);
/* Miscellaneous methods. */
static void openGLWidgetSet_viewport(OpenGLWidget *render, guint width,
guint height, gboolean redraw);
static GdkColormap* openGLWidgetGet_openGLColormap(OpenGLWidget *render);
/* Methods to deals with the handling of the object. */
GType openGLWidgetGet_type(void)
{
static GType openGLWidget_type = 0;
if (!openGLWidget_type)
{
static const GTypeInfo openGLWidget_info =
{
sizeof (OpenGLWidgetClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) openGLWidgetInit_class,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (OpenGLWidget),
0,
(GInstanceInitFunc) openGLWidgetInit_object,
NULL
};
openGLWidget_type = g_type_register_static(GTK_TYPE_WIDGET, "OpenGLWidget",
&openGLWidget_info, 0);
}
return openGLWidget_type;
}
static void openGLWidgetInit_class(OpenGLWidgetClass *class)
{
GtkWidgetClass *widget_class;
GObjectClass *gobject_class;
/* Put a static pointer on the parent class for chaining actions. */
parent_class = g_type_class_peek_parent(class);
/* Dealing with GObject events. */
gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = openGLWidgetEvent_dispose;
gobject_class->finalize = openGLWidgetEvent_finalize;
/* Dealing with widget events. */
widget_class = GTK_WIDGET_CLASS(class);
widget_class->expose_event = openGLWidgetEvent_expose;
widget_class->realize = openGLWidgetEvent_realise;
widget_class->size_request = openGLWidgetEvent_sizeRequest;
widget_class->size_allocate = openGLWidgetEvent_sizeAllocate;
class->contextCurrent = (OpenGLWidget*)0;
myClass = class;
}
static void openGLWidgetInit_object(OpenGLWidget *render)
{
DBG_fprintf(stderr, "Gtk OpenGL (init) : create object %p.\n", (gpointer)render);
render->sizeAllocation_has_run = FALSE;
render->dispose_has_run = FALSE;
render->redraw = (RedrawMethod)0;
render->redrawData = (gpointer)0;
render->isContextDirect = FALSE;
#if SYSTEM_X11 == 1
render->dpy = (Display*)0;
render->context = (GLXContext)0;
#endif
#if SYSTEM_WIN32 == 1
render->hdc = (HDC)0;
render->context = (HGLRC)0;
render->windowId = (HWND)0;
/* Cancel the GTK double buffering since it is taken into
account by OpenGL itself. */
gtk_widget_set_double_buffered(GTK_WIDGET(render), FALSE);
#endif
}
GtkWidget* openGLWidgetNew(gboolean contextIsDirect)
{
OpenGLWidget *render;
render = OPENGL_WIDGET(g_object_new(TYPE_OPENGL_WIDGET, NULL));
render->isContextDirect = contextIsDirect;
return GTK_WIDGET(render);
}
/* Methods to deals with the events. */
static void openGLWidgetEvent_dispose(GObject *obj)
{
DBG_fprintf(stderr, "Gtk OpenGL (events) : dispose event for object %p.\n", (gpointer)obj);
if (OPENGL_WIDGET(obj)->dispose_has_run)
return;
OPENGL_WIDGET(obj)->dispose_has_run = TRUE;
/* Chain up to the parent class */
G_OBJECT_CLASS(parent_class)->dispose(obj);
}
static void openGLWidgetEvent_finalize(GObject *obj)
{
DBG_fprintf(stderr, "Gtk OpenGL (events) : finalize event for object %p.\n", (gpointer)obj);
openGLWidgetFree_openGL(OPENGL_WIDGET(obj));
/* Chain up to the parent class */
G_OBJECT_CLASS(parent_class)->finalize(obj);
}
static gboolean openGLWidgetEvent_expose(GtkWidget *widget, GdkEventExpose *event)
{
OpenGLWidget *render;
DBG_fprintf(stderr, "Gtk OpenGL (events) : expose event for object %p.\n", (gpointer)widget);
render = OPENGL_WIDGET(widget);
if (render->redraw)
openGLWidgetRedraw(render);
else
{
DBG_fprintf(stderr, " | clear window.\n");
gdk_window_clear_area(widget->window, event->area.x, event->area.y,
event->area.width, event->area.height);
}
return FALSE;
}
static void openGLWidgetEvent_sizeRequest(GtkWidget *widget, GtkRequisition *requisition)
{
OpenGLWidget *render;
int width, height;
DBG_fprintf(stderr, "Gtk OpenGL (events) : size request event (%dx%d).\n", requisition->width, requisition->height);
render = OPENGL_WIDGET(widget);
if (render->sizeAllocation_has_run)
{
width = widget->allocation.width;
height = widget->allocation.height;
}
else
{
width = 200;
height = 200;
}
widget->requisition.width = width;
widget->requisition.height = height;
/* Chain up to default that simply reads current requisition */
GTK_WIDGET_CLASS(parent_class)->size_request(widget, requisition);
}
static void openGLWidgetEvent_sizeAllocate(GtkWidget *widget, GtkAllocation *allocation)
{
OpenGLWidget *render;
render = OPENGL_WIDGET(widget);
if ((widget->allocation.width == allocation->width) &&
(widget->allocation.height == allocation->height))
return;
DBG_fprintf(stderr, "Gtk OpenGL (events) : size allocation event (%dx%d).\n", allocation->width, allocation->height);
render->sizeAllocation_has_run = TRUE;
/* Chain up to default that simply reads current requisition */
GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation);
#if SYSTEM_X11 == 1
glXWaitX();
#endif
openGLWidgetSet_viewport(render, widget->allocation.width, widget->allocation.height, TRUE);
}
static void openGLWidgetEvent_realise(GtkWidget *widget)
{
OpenGLWidget *render;
GdkWindowAttr attributes;
gint attributes_mask;
GdkColormap *colormap;
DBG_fprintf(stderr, "Gtk OpenGL (events) : realise event for %p.\n", (gpointer)widget);
render = OPENGL_WIDGET(widget);
colormap = openGLWidgetGet_openGLColormap(render);
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = widget->allocation.x;
attributes.y = widget->allocation.y;
attributes.width = widget->allocation.width;
attributes.height = widget->allocation.height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.visual = gdk_colormap_get_visual(colormap);
attributes.colormap = colormap;
attributes.event_mask = GDK_EXPOSURE_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_SCROLL_MASK |
GDK_KEY_PRESS_MASK |
GDK_POINTER_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK |
GDK_VISIBILITY_NOTIFY_MASK;
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
widget->window = gdk_window_new(gtk_widget_get_parent_window(widget),
&attributes, attributes_mask);
gdk_window_set_user_data(widget->window, render);
widget->style = gtk_style_attach(widget->style, widget->window);
gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
gdk_display_sync(gtk_widget_get_display(widget));
#if SYSTEM_X11 == 1
glXWaitX();
#endif
/* Initialize context for OpenGL, OS dependent. */
openGLWidgetInit_context(render, render->isContextDirect);
openGLWidgetSet_current(render);
}
OpenGLWidget* openGLWidgetClassGet_currentContext()
{
g_return_val_if_fail(myClass, (OpenGLWidget*)0);
return myClass->contextCurrent;
}
static void openGLWidgetSet_viewport(OpenGLWidget *render, guint width,
guint height, gboolean redraw)
{
g_return_if_fail(IS_OPENGL_WIDGET(render));
if (OPENGL_WIDGET_GET_CLASS(render)->contextCurrent != render)
return;
DBG_fprintf(stderr, " | adjusting viewport to %dx%d.\n", width, height);
glViewport(0, 0, width, height);
if (redraw)
{
/* We synchronize the rendering area. */
gdk_display_sync(gtk_widget_get_display(GTK_WIDGET(render)));
/* We clear the back buffer and swap because this buffer has
still the wrong size. */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
openGLWidgetSwap_buffers(render);
}
}
void openGLWidgetSet_redraw(OpenGLWidget *render, RedrawMethod method, gpointer data)
{
g_return_if_fail(IS_OPENGL_WIDGET(render));
DBG_fprintf(stderr, "Gtk OpenGL (action) : set redraw method for OpenGL area %p.\n", (gpointer)render);
render->redraw = method;
render->redrawData = data;
}
void openGLWidgetRedraw(OpenGLWidget *render)
{
g_return_if_fail(IS_OPENGL_WIDGET(render));
if (!render->redraw)
return;
DBG_fprintf(stderr, "Gtk OpenGL (action) : redraw OpenGL area for %p.\n", (gpointer)render);
if (render->redraw)
{
DBG_fprintf(stderr, " | set current.\n");
openGLWidgetSet_current(render);
DBG_fprintf(stderr, " | redraw inside.\n");
render->redraw(GTK_WIDGET(render)->allocation.width,
GTK_WIDGET(render)->allocation.height,
render->redrawData);
DBG_fprintf(stderr, " | swap buffers.\n");
openGLWidgetSwap_buffers(render);
}
}
guchar* openGLWidgetGet_pixmapData(OpenGLWidget *render, int *width,
int *height, gboolean offScreen)
{
GtkWidget *wd;
guchar *image;
DumpImage *dumpData;
g_return_val_if_fail(IS_OPENGL_WIDGET(render), (guchar*)0);
g_return_val_if_fail(OPENGL_WIDGET_GET_CLASS(render)->contextCurrent == render, (guchar*)0);
g_return_val_if_fail(render->redraw, (guchar*)0);
g_return_val_if_fail(width && height, (guchar*)0);
wd = GTK_WIDGET(render);
if (!offScreen)
{
*width = wd->allocation.width;
*height = wd->allocation.height;
return visuOpenGLGet_pixmapData(*width, *height);
}
/* If a method is given, then we draw
in memory to a pixmap. */
*width = (*width > 0)?*width:wd->allocation.width;
*height = (*height > 0)?*height:wd->allocation.height;
/* We create a pixmap context and make this context current. */
OPENGL_WIDGET_GET_CLASS(render)->contextCurrent = (OpenGLWidget*)0;
dumpData = visuOpenGLNew_pixmapContext((guint)*width, (guint)*height);
/* We set the glViewport of this new context. */
glViewport(0, 0, *width, *height);
/* We call the given draw method. */
render->redraw(*width, *height, render->redrawData);
/* We copy the pixmap into generic data. */
image = visuOpenGLGet_pixmapData((guint)*width, (guint)*height);
/* We free the pixmap context. */
visuOpenGLFree_pixmapContext(dumpData);
/* We change back the context to the current rendering area. */
openGLWidgetSet_current(render);
return image;
}
/* OpenGL functions, OS dependent. */
#if SYSTEM_X11 == 1
static void openGLWidgetInit_context(OpenGLWidget *render, gboolean contextIsDirect)
{
gint screenId;
XVisualInfo *vinfo;
GtkWidget *wd;
DBG_fprintf(stderr, "Gtk OpenGL (init) : create an OpenGL context (%d).\n", contextIsDirect);
wd = GTK_WIDGET(render);
if (!render->dpy)
render->dpy = gdk_x11_drawable_get_xdisplay(GDK_DRAWABLE(wd->window));
DBG_fprintf(stderr, " | get the display %p.\n", (gpointer)render->dpy);
/* Check for GLX. */
if (!glXQueryExtension(render->dpy, 0, 0))
g_error("No GLX extension.\nYour X server"
" does not support OpenGL extension. Please contact your"
" system administrator to ask him to add the 'glx'"
" extension to your X server.\n");
/* Get the screen id. */
screenId = gdk_x11_screen_get_screen_number
(gdk_drawable_get_screen(GDK_DRAWABLE(wd->window)));
DBG_fprintf(stderr, " | get a screen number %d.\n", screenId);
/* We don't cancel the double buffering since the backing store
need it. */
/* if (DoesBackingStore(ScreenOfDisplay(render->dpy, screenId)) == NotUseful) */
gtk_widget_set_double_buffered(GTK_WIDGET(render), FALSE);
/* Try to create a visual. */
vinfo = visuOpenGLGet_visualInfo(render->dpy, screenId);
/* Finaly, create the context. */
if (contextIsDirect)
{
render->context = glXCreateContext(render->dpy, vinfo, 0, GL_TRUE);
if (!render->context)
{
g_warning("Can't create a direct rendering context, try an inderect one.\n");
render->context = glXCreateContext(render->dpy, vinfo, 0, GL_FALSE);
render->isContextDirect = FALSE;
}
}
else
render->context = glXCreateContext(render->dpy, vinfo, 0, GL_FALSE);
DBG_fprintf(stderr, " | create the context %p (%d).\n", (gpointer)render->context,
(int)render->isContextDirect);
if (!render->context)
g_error("Cannot create a GLX context.\n");
}
static void openGLWidgetFree_openGL(OpenGLWidget *render)
{
g_return_if_fail(IS_OPENGL_WIDGET(render));
if (render->dpy)
{
DBG_fprintf(stderr, "Free : freeing context.\n");
if (render->context)
glXDestroyContext(render->dpy, render->context);
/* We do NOT close the display since it is shared
by all the application and thus dpy structure
is unique and will be closed by GTK when quiting. */
/* XCloseDisplay(render->dpy); */
}
}
gboolean openGLWidgetSet_current(OpenGLWidget *render)
{
int res;
GtkWidget *wd;
XID windowId;
g_return_val_if_fail(IS_OPENGL_WIDGET(render), FALSE);
if (OPENGL_WIDGET_GET_CLASS(render)->contextCurrent == render)
return TRUE;
DBG_fprintf(stderr, "Gtk OpenGL (debug) : widget visualID %d.\n", (int)gdk_x11_visual_get_xvisual
(gtk_widget_get_visual(GTK_WIDGET(render)))->visualid);
DBG_fprintf(stderr, "Gtk OpenGL (action) : %p is set current.\n", (gpointer)render);
windowId = gdk_x11_drawable_get_xid(GDK_DRAWABLE(GTK_WIDGET(render)->window));
res = glXMakeCurrent(render->dpy, (GLXDrawable)windowId,
render->context);
if (!res)
{
g_warning("Cannot make the openGLWidget object %p current.\n", (gpointer)render);
return FALSE;
}
/* Now that the glx tunnel has been added, we need
to specify again that we want a backing store because until now
the backing store is only for the X window (and thus is black)
but not for the glx screen. */
/* wattrs.backing_store = Always; */
/* XChangeWindowAttributes(render->dpy, windowId, */
/* CWBackingStore, &wattrs); */
OPENGL_WIDGET_GET_CLASS(render)->contextCurrent = render;
wd = GTK_WIDGET(render);
openGLWidgetSet_viewport(render, wd->allocation.width, wd->allocation.height, FALSE);
return TRUE;
}
void openGLWidgetSwap_buffers(OpenGLWidget *render)
{
g_return_if_fail(OPENGL_WIDGET_GET_CLASS(render)->contextCurrent == render);
DBG_fprintf(stderr, "Gtk OpenGL (action) : swap buffers of area %p.\n", (gpointer)render);
glXSwapBuffers(render->dpy, (GLXDrawable)gdk_x11_drawable_get_xid
(GDK_DRAWABLE(GTK_WIDGET(render)->window)));
}
static GdkColormap* openGLWidgetGet_openGLColormap(OpenGLWidget *render)
{
XVisualInfo *vinfo;
Display *dpy;
int screenId;
GdkVisual *visual;
GdkColormap *colormap;
g_return_val_if_fail(IS_OPENGL_WIDGET(render), (GdkColormap*)0);
dpy = gdk_x11_get_default_xdisplay();
screenId = gdk_x11_get_default_screen();
vinfo = visuOpenGLGet_visualInfo(dpy, screenId);
visual = gdkx_visual_get(vinfo->visualid);
colormap = gdk_colormap_new(visual, FALSE);
return colormap;
}
#endif
#if SYSTEM_WIN32 == 1
static void openGLWidgetInit_context(OpenGLWidget *render, gboolean contextIsDirect)
{
GtkWidget *wd;
DBG_fprintf(stderr, "Gtk OpenGL (init) : create an OpenGL context (%d).\n", contextIsDirect);
wd = GTK_WIDGET(render);
render->windowId = (HWND)gdk_win32_drawable_get_handle(GDK_DRAWABLE(wd->window));
render->hdc = GetDC(render->windowId);
DBG_fprintf(stderr, " | get the hdc %d.\n", (int)render->hdc);
/* Choose best matching format*/
visuOpenGLSetup_pixelFormat(render->hdc);
/* Finaly, create the context. */
render->context = wglCreateContext(render->hdc);
}
static void openGLWidgetFree_openGL(OpenGLWidget *render)
{
g_return_if_fail(IS_OPENGL_WIDGET(render));
if (render->context)
wglDeleteContext(render->context);
/* if (render->hdc) */
/* DeleteDC(render->hdc); */
}
gboolean openGLWidgetSet_current(OpenGLWidget *render)
{
int res;
GtkWidget *wd;
g_return_val_if_fail(IS_OPENGL_WIDGET(render), FALSE);
DBG_fprintf(stderr, "Gtk OpenGL (action) : %p is set current.\n", (gpointer)render);
wglMakeCurrent(NULL, NULL);
wglMakeCurrent(render->hdc, render->context);
OPENGL_WIDGET_GET_CLASS(render)->contextCurrent = render;
wd = GTK_WIDGET(render);
openGLWidgetSet_viewport(render, wd->allocation.width, wd->allocation.height, FALSE);
return TRUE;
}
void openGLWidgetSwap_buffers(OpenGLWidget *render)
{
g_return_if_fail(OPENGL_WIDGET_GET_CLASS(render)->contextCurrent == render);
DBG_fprintf(stderr, "Gtk OpenGL (action) : swap buffers of area %p.\n", (gpointer)render);
SwapBuffers(render->hdc);
}
static GdkColormap* openGLWidgetGet_openGLColormap(OpenGLWidget *render)
{
g_return_val_if_fail(IS_OPENGL_WIDGET(render), (GdkColormap*)0);
return gdk_screen_get_system_colormap(gdk_screen_get_default());
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1