2011-09-07 23:06:51 +02:00
|
|
|
//
|
|
|
|
// OpenGL window
|
|
|
|
//
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <gdk/gdkx.h>
|
|
|
|
#include "opengl.h"
|
|
|
|
#include "glwindow.h"
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GtkWidget *widget;
|
|
|
|
Display* xdisplay;
|
|
|
|
GLXContext context;
|
|
|
|
} GLWindowPrivate;
|
|
|
|
|
|
|
|
// =============================================================================
|
|
|
|
// static functions
|
|
|
|
|
|
|
|
static gint realize_event (GtkWidget *widget, gpointer data)
|
|
|
|
{
|
|
|
|
GLWindow *wnd = (GLWindow*)data;
|
|
|
|
|
|
|
|
wnd->OnInitialUpdate ();
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer data)
|
|
|
|
{
|
|
|
|
GLWindow *wnd = (GLWindow*)data;
|
|
|
|
|
|
|
|
if (event->count > 0)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
wnd->OnDraw ();
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer data)
|
|
|
|
{
|
|
|
|
GLWindow *wnd = (GLWindow*)data;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
x = (int)event->x;
|
|
|
|
y = widget->allocation.height - (int)event->y - 1;
|
|
|
|
|
|
|
|
if (event->type == GDK_BUTTON_PRESS)
|
|
|
|
{
|
|
|
|
if (event->button == 1)
|
|
|
|
wnd->OnLeftButtonDown (x, y, (event->state & GDK_CONTROL_MASK) != 0,
|
|
|
|
(event->state & GDK_SHIFT_MASK) != 0);
|
|
|
|
else if (event->button == 3)
|
|
|
|
wnd->OnRightButtonDown (x, y, (event->state & GDK_CONTROL_MASK) != 0,
|
|
|
|
(event->state & GDK_SHIFT_MASK) != 0);
|
|
|
|
}
|
|
|
|
else if (event->type == GDK_2BUTTON_PRESS)
|
|
|
|
{
|
|
|
|
wnd->OnLeftButtonDoubleClick (x, y, (event->state & GDK_CONTROL_MASK) != 0,
|
|
|
|
(event->state & GDK_SHIFT_MASK) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_window_set_focus (GTK_WINDOW (gtk_widget_get_toplevel (widget)), widget);
|
|
|
|
gdk_pointer_grab (widget->window, FALSE, (GdkEventMask)(GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|
|
|
|
|
GDK_POINTER_MOTION_MASK|GDK_POINTER_MOTION_HINT_MASK),
|
|
|
|
NULL, NULL, GDK_CURRENT_TIME);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer data)
|
|
|
|
{
|
|
|
|
GLWindow *wnd = (GLWindow*)data;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
x = (int)event->x;
|
|
|
|
y = widget->allocation.height - (int)event->y - 1;
|
|
|
|
|
|
|
|
gdk_pointer_ungrab (GDK_CURRENT_TIME);
|
|
|
|
|
|
|
|
if (event->button == 1)
|
|
|
|
wnd->OnLeftButtonUp (x, y, (event->state & GDK_CONTROL_MASK) != 0,
|
|
|
|
(event->state & GDK_SHIFT_MASK) != 0);
|
|
|
|
else if (event->button == 3)
|
|
|
|
wnd->OnRightButtonUp (x, y, (event->state & GDK_CONTROL_MASK) != 0,
|
|
|
|
(event->state & GDK_SHIFT_MASK) != 0);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint pointer_motion_event (GtkWidget *widget, GdkEventMotion *event, gpointer data)
|
|
|
|
{
|
|
|
|
GLWindow *wnd = (GLWindow*)data;
|
|
|
|
GdkModifierType state;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
if (event->is_hint)
|
|
|
|
{
|
|
|
|
gdk_window_get_pointer (event->window, &x, &y, &state);
|
|
|
|
state = (GdkModifierType)0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x = (int)event->x;
|
|
|
|
y = (int)event->y;
|
|
|
|
state = (GdkModifierType)event->state;
|
|
|
|
}
|
|
|
|
|
|
|
|
y = widget->allocation.height - y - 1;
|
|
|
|
|
|
|
|
wnd->OnMouseMove (x, y, (event->state & GDK_CONTROL_MASK) != 0, (event->state & GDK_SHIFT_MASK) != 0);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint size_allocate_event (GtkWidget *widget, GtkAllocation *allocation, gpointer data)
|
|
|
|
{
|
|
|
|
GLWindow *wnd = (GLWindow*)data;
|
|
|
|
|
|
|
|
wnd->OnSize (allocation->width, allocation->height);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
static void destroy_event (GtkWidget *widget, gpointer data)
|
|
|
|
{
|
|
|
|
GLWindow *wnd = (GLWindow*)data;
|
|
|
|
|
|
|
|
wnd->DestroyContext ();
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
// =============================================================================
|
|
|
|
// GLWindow class
|
|
|
|
|
|
|
|
GLWindow::GLWindow (GLWindow *share)
|
|
|
|
{
|
|
|
|
m_pShare = share;
|
|
|
|
m_pData = g_malloc (sizeof (GLWindowPrivate));
|
|
|
|
}
|
|
|
|
|
|
|
|
GLWindow::~GLWindow ()
|
|
|
|
{
|
|
|
|
DestroyContext ();
|
|
|
|
g_free (m_pData);
|
|
|
|
}
|
|
|
|
|
2012-02-02 02:04:24 +01:00
|
|
|
bool GLWindow::CreateFromWindow (void *data)
|
2011-09-07 23:06:51 +02:00
|
|
|
{
|
|
|
|
int attrlist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16, 0 };
|
|
|
|
GLWindowPrivate *prv = (GLWindowPrivate*)m_pData;
|
|
|
|
Display *dpy = GDK_DISPLAY();
|
|
|
|
GdkVisual *visual;
|
|
|
|
XVisualInfo *vi;
|
|
|
|
|
|
|
|
// choose visual
|
|
|
|
visual = gdk_visual_get_system ();
|
|
|
|
if (visual->depth < 16)
|
|
|
|
printf ("OpenGL fatal error: LeoCAD needs a display with at least 16 bit colors.\n");
|
|
|
|
|
|
|
|
if (dpy == NULL)
|
|
|
|
{
|
|
|
|
printf ("OpenGL fatal error: Cannot get display.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
prv->xdisplay = dpy;
|
|
|
|
|
|
|
|
vi = pfnglXChooseVisual (dpy, DefaultScreen (dpy), attrlist);
|
|
|
|
if (vi == NULL)
|
|
|
|
{
|
|
|
|
printf ("OpenGL fatal error: glXChooseVisual failed.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
visual = gdkx_visual_get (vi->visualid);
|
|
|
|
if (visual == NULL)
|
|
|
|
{
|
|
|
|
printf ("OpenGL fatal error: Cannot get visual.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_widget_push_colormap (gdk_colormap_new (visual, TRUE));
|
|
|
|
gtk_widget_push_visual (visual);
|
|
|
|
|
|
|
|
prv->widget = gtk_drawing_area_new ();
|
|
|
|
gtk_widget_set_double_buffered(GTK_WIDGET(prv->widget), FALSE);
|
|
|
|
|
|
|
|
if (m_pShare == NULL)
|
|
|
|
prv->context = pfnglXCreateContext (dpy, vi, NULL, True);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GLWindowPrivate *share = (GLWindowPrivate*)m_pShare->m_pData;
|
|
|
|
|
|
|
|
prv->context = pfnglXCreateContext (dpy, vi, share->context, True);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_widget_pop_visual ();
|
|
|
|
gtk_widget_pop_colormap ();
|
|
|
|
|
|
|
|
XFree (vi);
|
|
|
|
|
|
|
|
GTK_WIDGET_SET_FLAGS (prv->widget, GTK_CAN_FOCUS);
|
|
|
|
|
|
|
|
gtk_widget_set_events (GTK_WIDGET (prv->widget), GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
|
|
|
|
GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
|
|
|
|
|
|
|
|
// Connect signal handlers
|
|
|
|
gtk_signal_connect (GTK_OBJECT (prv->widget), "expose_event",
|
|
|
|
GTK_SIGNAL_FUNC (expose_event), this);
|
|
|
|
// gtk_signal_connect (GTK_OBJECT (prv->widget), "destroy",
|
|
|
|
// GTK_SIGNAL_FUNC (destroy_event), this);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (prv->widget), "size_allocate",
|
|
|
|
GTK_SIGNAL_FUNC (size_allocate_event), this);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (prv->widget), "motion_notify_event",
|
|
|
|
GTK_SIGNAL_FUNC (pointer_motion_event), this);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (prv->widget), "button_press_event",
|
|
|
|
GTK_SIGNAL_FUNC (button_press_event), this);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (prv->widget), "button_release_event",
|
|
|
|
GTK_SIGNAL_FUNC (button_release_event), this);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (prv->widget), "realize",
|
|
|
|
GTK_SIGNAL_FUNC (realize_event), this);
|
|
|
|
|
|
|
|
*((GtkWidget**)data) = prv->widget;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLWindow::DestroyContext ()
|
|
|
|
{
|
|
|
|
GLWindowPrivate *prv = (GLWindowPrivate*)m_pData;
|
|
|
|
|
|
|
|
if (prv->context == pfnglXGetCurrentContext ())
|
|
|
|
pfnglXMakeCurrent (prv->xdisplay, None, NULL);
|
|
|
|
|
|
|
|
if (prv->context)
|
|
|
|
pfnglXDestroyContext (prv->xdisplay, prv->context);
|
|
|
|
|
|
|
|
prv->context = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLWindow::OnInitialUpdate ()
|
|
|
|
{
|
|
|
|
MakeCurrent ();
|
|
|
|
GL_InitializeExtensions ();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GLWindow::MakeCurrent ()
|
|
|
|
{
|
|
|
|
GLWindowPrivate *prv = (GLWindowPrivate*)m_pData;
|
|
|
|
gboolean ret = false;
|
|
|
|
|
|
|
|
if (prv->context)
|
|
|
|
ret = pfnglXMakeCurrent (prv->xdisplay, GDK_WINDOW_XWINDOW (prv->widget->window), prv->context);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLWindow::SwapBuffers ()
|
|
|
|
{
|
|
|
|
GLWindowPrivate *prv = (GLWindowPrivate*)m_pData;
|
|
|
|
|
|
|
|
if (prv->context)
|
|
|
|
pfnglXSwapBuffers (GDK_WINDOW_XDISPLAY (prv->widget->window), GDK_WINDOW_XWINDOW (prv->widget->window));
|
|
|
|
}
|
|
|
|
|
2012-02-02 02:04:24 +01:00
|
|
|
void GLWindow::Redraw (bool ForceRedraw)
|
2011-09-07 23:06:51 +02:00
|
|
|
{
|
|
|
|
GLWindowPrivate *prv = (GLWindowPrivate*)m_pData;
|
|
|
|
|
|
|
|
gtk_widget_draw (prv->widget, (GdkRectangle*)NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLWindow::CaptureMouse()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLWindow::ReleaseMouse()
|
|
|
|
{
|
|
|
|
}
|