added OpenGL support to Gtk realization of highgui

This commit is contained in:
Vladislav Vinogradov 2011-11-28 08:23:26 +00:00
parent fb2fad52a2
commit 2a4fb155e1
6 changed files with 1027 additions and 466 deletions

View File

@ -507,6 +507,17 @@ if(UNIX)
if(WITH_GTK)
CHECK_MODULE(gtk+-2.0 HAVE_GTK)
CHECK_MODULE(gthread-2.0 HAVE_GTHREAD)
if(WITH_OPENGL)
CHECK_MODULE(gtkglext-1.0 HAVE_GTKGLEXT)
if(HAVE_GTKGLEXT)
find_package(OpenGL QUIET)
if(OPENGL_FOUND)
set(HAVE_OPENGL 1)
set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${OPENGL_LIBRARIES})
include_directories(${OPENGL_INCLUDE_DIR})
endif()
endif()
endif()
else()
set(HAVE_GTK FALSE)
set(HAVE_GTHREAD FALSE)
@ -1726,6 +1737,7 @@ else()
else()
status(" GTK+ 2.x:" HAVE_GTK THEN YES ELSE NO)
status(" GThread :" HAVE_GTHREAD THEN YES ELSE NO)
status(" GtkGlExt:" HAVE_GTKGLEXT THEN YES ELSE NO)
endif()
endif()
endif()

View File

@ -186,8 +186,13 @@ double cvGetModeWindow_GTK(const char* name);
double cvGetModeWindow_CARBON(const char* name);
double cvGetPropWindowAutoSize_W32(const char* name);
double cvGetPropWindowAutoSize_GTK(const char* name);
double cvGetRatioWindow_W32(const char* name);
double cvGetRatioWindow_GTK(const char* name);
double cvGetOpenGlProp_W32(const char* name);
double cvGetOpenGlProp_GTK(const char* name);
//for QT
#if defined (HAVE_QT)

View File

@ -109,6 +109,8 @@ CV_IMPL double cvGetWindowProperty(const char* name, int prop_id)
return cvGetPropWindow_QT(name);
#elif defined WIN32 || defined _WIN32
return cvGetPropWindowAutoSize_W32(name);
#elif defined (HAVE_GTK)
return cvGetPropWindowAutoSize_GTK(name);
#else
return -1;
#endif
@ -120,6 +122,8 @@ CV_IMPL double cvGetWindowProperty(const char* name, int prop_id)
return cvGetRatioWindow_QT(name);
#elif defined WIN32 || defined _WIN32
return cvGetRatioWindow_W32(name);
#elif defined (HAVE_GTK)
return cvGetRatioWindow_GTK(name);
#else
return -1;
#endif
@ -130,6 +134,8 @@ CV_IMPL double cvGetWindowProperty(const char* name, int prop_id)
#if defined (HAVE_QT)
#elif defined WIN32 || defined _WIN32
return cvGetOpenGlProp_W32(name);
#elif defined (HAVE_GTK)
return cvGetOpenGlProp_GTK(name);
#else
return -1;
#endif

View File

@ -49,6 +49,12 @@
#include "gdk/gdkkeysyms.h"
#include <stdio.h>
#ifdef HAVE_OPENGL
#include <gtk/gtkgl.h>
#include <GL/gl.h>
#include <GL/glu.h>
#endif
/*#if _MSC_VER >= 1200
#pragma warning( disable: 4505 )
#pragma comment(lib,"gtk-win32-2.0.lib")
@ -302,45 +308,6 @@ cvImageWidget_size_allocate (GtkWidget *widget,
}
}
static gboolean
cvImageWidget_expose( GtkWidget *widget,
GdkEventExpose *event )
{
CvImageWidget *image_widget;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
if (event->count > 0)
return FALSE;
image_widget = CV_IMAGE_WIDGET (widget);
gdk_window_clear_area (widget->window,
0, 0,
widget->allocation.width,
widget->allocation.height);
if( image_widget->scaled_image ){
// center image in available region
int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
x0, y0, MIN(image_widget->scaled_image->cols, widget->allocation.width),
MIN(image_widget->scaled_image->rows, widget->allocation.height),
GDK_RGB_DITHER_MAX, image_widget->scaled_image->data.ptr, image_widget->scaled_image->step );
}
else if( image_widget->original_image ){
gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
0, 0,
MIN(image_widget->original_image->cols, widget->allocation.width),
MIN(image_widget->original_image->rows, widget->allocation.height),
GDK_RGB_DITHER_MAX, image_widget->original_image->data.ptr, image_widget->original_image->step );
}
return TRUE;
}
static void
cvImageWidget_destroy (GtkObject *object)
{
@ -371,7 +338,6 @@ static void cvImageWidget_class_init (CvImageWidgetClass * klass)
object_class->destroy = cvImageWidget_destroy;
widget_class->realize = cvImageWidget_realize;
widget_class->expose_event = cvImageWidget_expose;
widget_class->size_request = cvImageWidget_size_request;
widget_class->size_allocate = cvImageWidget_size_allocate;
widget_class->button_press_event = NULL;
@ -456,6 +422,16 @@ typedef struct CvWindow
CvTrackbar* first;
}
toolbar;
#ifdef HAVE_OPENGL
bool useGl;
CvOpenGLCallback glDrawCallback;
void* glDrawData;
CvOpenGlCleanCallback glCleanCallback;
void* glCleanData;
#endif
}
CvWindow;
@ -488,6 +464,11 @@ CV_IMPL int cvInitSystem( int argc, char** argv )
hg_windows = 0;
gtk_init( &argc, &argv );
#ifdef HAVE_OPENGL
gtk_gl_init(&argc, &argv);
#endif
wasInitialized = 1;
}
@ -637,6 +618,393 @@ void cvSetModeWindow_GTK( const char* name, double prop_value)//Yannick Verdie
__END__;
}
double cvGetPropWindowAutoSize_GTK(const char* name)
{
double result = -1;
CV_FUNCNAME( "cvGetPropWindowAutoSize_GTK" );
__BEGIN__;
CvWindow* window;
if (!name)
CV_ERROR( CV_StsNullPtr, "NULL name string" );
window = icvFindWindowByName( name );
if (!window)
EXIT; // keep silence here
result = window->flags & CV_WINDOW_AUTOSIZE;
__END__;
return result;
}
double cvGetRatioWindow_GTK(const char* name)
{
double result = -1;
CV_FUNCNAME( "cvGetRatioWindow_GTK" );
__BEGIN__;
CvWindow* window;
if (!name)
CV_ERROR( CV_StsNullPtr, "NULL name string" );
window = icvFindWindowByName( name );
if (!window)
EXIT; // keep silence here
result = static_cast<double>(window->widget->allocation.width) / window->widget->allocation.height;
__END__;
return result;
}
double cvGetOpenGlProp_GTK(const char* name)
{
double result = -1;
#ifdef HAVE_OPENGL
CV_FUNCNAME( "cvGetOpenGlProp_GTK" );
__BEGIN__;
CvWindow* window;
if (!name)
CV_ERROR( CV_StsNullPtr, "NULL name string" );
window = icvFindWindowByName( name );
if (!window)
EXIT; // keep silence here
result = window->useGl;
__END__;
#endif
return result;
}
// OpenGL support
#ifdef HAVE_OPENGL
namespace
{
class GlFuncTab_GTK : public cv::gpu::GlFuncTab
{
public:
PFNGLGENBUFFERSPROC glGenBuffersExt;
PFNGLDELETEBUFFERSPROC glDeleteBuffersExt;
PFNGLBUFFERDATAPROC glBufferDataExt;
PFNGLBUFFERSUBDATAPROC glBufferSubDataExt;
PFNGLBINDBUFFERPROC glBindBufferExt;
PFNGLMAPBUFFERPROC glMapBufferExt;
PFNGLUNMAPBUFFERPROC glUnmapBufferExt;
bool initialized;
GlFuncTab_GTK()
{
glGenBuffersExt = 0;
glDeleteBuffersExt = 0;
glBufferDataExt = 0;
glBufferSubDataExt = 0;
glBindBufferExt = 0;
glMapBufferExt = 0;
glUnmapBufferExt = 0;
initialized = false;
}
void genBuffers(int n, unsigned int* buffers) const
{
CV_FUNCNAME( "genBuffers" );
__BEGIN__;
if (!glGenBuffersExt)
CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
glGenBuffersExt(n, buffers);
CV_CheckGlError();
__END__;
}
void deleteBuffers(int n, const unsigned int* buffers) const
{
CV_FUNCNAME( "deleteBuffers" );
__BEGIN__;
if (!glDeleteBuffersExt)
CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
glDeleteBuffersExt(n, buffers);
CV_CheckGlError();
__END__;
}
void bufferData(unsigned int target, ptrdiff_t size, const void* data, unsigned int usage) const
{
CV_FUNCNAME( "bufferData" );
__BEGIN__;
if (!glBufferDataExt)
CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
glBufferDataExt(target, size, data, usage);
CV_CheckGlError();
__END__;
}
void bufferSubData(unsigned int target, ptrdiff_t offset, ptrdiff_t size, const void* data) const
{
CV_FUNCNAME( "bufferSubData" );
__BEGIN__;
if (!glBufferSubDataExt)
CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
glBufferSubDataExt(target, offset, size, data);
CV_CheckGlError();
__END__;
}
void bindBuffer(unsigned int target, unsigned int buffer) const
{
CV_FUNCNAME( "bindBuffer" );
__BEGIN__;
if (!glBindBufferExt)
CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
glBindBufferExt(target, buffer);
CV_CheckGlError();
__END__;
}
void* mapBuffer(unsigned int target, unsigned int access) const
{
CV_FUNCNAME( "mapBuffer" );
void* res = 0;
__BEGIN__;
if (!glMapBufferExt)
CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
res = glMapBufferExt(target, access);
CV_CheckGlError();
__END__;
return res;
}
void unmapBuffer(unsigned int target) const
{
CV_FUNCNAME( "unmapBuffer" );
__BEGIN__;
if (!glUnmapBufferExt)
CV_ERROR(CV_OpenGlApiCallError, "Current OpenGL implementation doesn't support required extension");
glUnmapBufferExt(target);
CV_CheckGlError();
__END__;
}
bool isGlContextInitialized() const
{
return initialized;
}
};
void initGl()
{
static GlFuncTab_GTK glFuncTab;
static bool first = true;
if (first)
{
// Load extensions
GdkGLProc func;
func = gdk_gl_get_proc_address("glGenBuffers");
glFuncTab.glGenBuffersExt = (PFNGLGENBUFFERSPROC)func;
func = gdk_gl_get_proc_address("glDeleteBuffers");
glFuncTab.glDeleteBuffersExt = (PFNGLDELETEBUFFERSPROC)func;
func = gdk_gl_get_proc_address("glBufferData");
glFuncTab.glBufferDataExt = (PFNGLBUFFERDATAPROC)func;
func = gdk_gl_get_proc_address("glBufferSubData");
glFuncTab.glBufferSubDataExt = (PFNGLBUFFERSUBDATAPROC)func;
func = gdk_gl_get_proc_address("glBindBuffer");
glFuncTab.glBindBufferExt = (PFNGLBINDBUFFERPROC)func;
func = gdk_gl_get_proc_address("glMapBuffer");
glFuncTab.glMapBufferExt = (PFNGLMAPBUFFERPROC)func;
func = gdk_gl_get_proc_address("glUnmapBuffer");
glFuncTab.glUnmapBufferExt = (PFNGLUNMAPBUFFERPROC)func;
glFuncTab.initialized = true;
cv::gpu::setGlFuncTab(&glFuncTab);
first = false;
}
}
void createGlContext(CvWindow* window)
{
GdkGLConfig* glconfig;
CV_FUNCNAME( "createGlContext" );
__BEGIN__;
window->useGl = false;
// Try double-buffered visual
glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE));
if (!glconfig)
CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
// Set OpenGL-capability to the widget
if (!gtk_widget_set_gl_capability(window->widget, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE))
CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
initGl();
window->useGl = true;
__END__;
}
void releaseGlContext(CvWindow* window)
{
CV_FUNCNAME( "releaseGlContext" );
__BEGIN__;
window->useGl = false;
__END__;
}
void drawGl(CvWindow* window)
{
CV_FUNCNAME( "drawGl" );
__BEGIN__;
GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget);
GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget);
if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
glViewport(0, 0, window->widget->allocation.width, window->widget->allocation.height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (window->glDrawCallback)
window->glDrawCallback(window->glDrawData);
CV_CheckGlError();
if (gdk_gl_drawable_is_double_buffered (gldrawable))
gdk_gl_drawable_swap_buffers(gldrawable);
else
glFlush();
gdk_gl_drawable_gl_end(gldrawable);
__END__;
}
}
#endif // HAVE_OPENGL
static gboolean cvImageWidget_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data)
{
#ifdef HAVE_OPENGL
CvWindow* window = (CvWindow*)data;
if (window->useGl)
{
drawGl(window);
return TRUE;
}
#endif
CvImageWidget *image_widget;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (CV_IS_IMAGE_WIDGET (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
if (event->count > 0)
return FALSE;
image_widget = CV_IMAGE_WIDGET (widget);
gdk_window_clear_area (widget->window,
0, 0,
widget->allocation.width,
widget->allocation.height);
if( image_widget->scaled_image ){
// center image in available region
int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2;
int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2;
gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
x0, y0, MIN(image_widget->scaled_image->cols, widget->allocation.width),
MIN(image_widget->scaled_image->rows, widget->allocation.height),
GDK_RGB_DITHER_MAX, image_widget->scaled_image->data.ptr, image_widget->scaled_image->step );
}
else if( image_widget->original_image ){
gdk_draw_rgb_image( widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
0, 0,
MIN(image_widget->original_image->cols, widget->allocation.width),
MIN(image_widget->original_image->rows, widget->allocation.height),
GDK_RGB_DITHER_MAX, image_widget->original_image->data.ptr, image_widget->original_image->step );
}
return TRUE;
}
CV_IMPL int cvNamedWindow( const char* name, int flags )
{
int result = 0;
@ -683,6 +1051,15 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
gtk_widget_show( window->widget );
gtk_container_add( GTK_CONTAINER(window->frame), window->paned );
gtk_widget_show( window->paned );
#ifndef HAVE_OPENGL
if (flags & CV_WINDOW_OPENGL)
CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
#else
if (flags & CV_WINDOW_OPENGL)
createGlContext(window);
#endif
//
// configure event handlers
// TODO -- move this to CvImageWidget ?
@ -696,9 +1073,10 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
GTK_SIGNAL_FUNC(icvOnMouse), window );
gtk_signal_connect( GTK_OBJECT(window->frame), "delete-event",
GTK_SIGNAL_FUNC(icvOnClose), window );
gtk_signal_connect( GTK_OBJECT(window->widget), "expose-event",
GTK_SIGNAL_FUNC(cvImageWidget_expose), window );
gtk_widget_add_events (window->widget, GDK_EXPOSURE_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK) ;
gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK) ;
gtk_widget_show( window->frame );
gtk_window_set_title( GTK_WINDOW(window->frame), name );
@ -721,6 +1099,11 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
CV_UNLOCK_MUTEX();
#ifdef HAVE_OPENGL
if (window->useGl)
cvSetOpenGlContext(name);
#endif
result = 1;
__END__;
@ -728,10 +1111,144 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
}
#ifdef HAVE_OPENGL
CV_IMPL void cvSetOpenGlContext(const char* name)
{
CvWindow* window;
GdkGLContext* glcontext;
GdkGLDrawable* gldrawable;
CV_FUNCNAME( "cvSetOpenGlContext" );
__BEGIN__;
if(!name)
CV_ERROR( CV_StsNullPtr, "NULL name string" );
window = icvFindWindowByName( name );
if (!window)
CV_ERROR( CV_StsNullPtr, "NULL window" );
if (!window->useGl)
CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
glcontext = gtk_widget_get_gl_context(window->widget);
gldrawable = gtk_widget_get_gl_drawable(window->widget);
if (!gdk_gl_drawable_make_current(gldrawable, glcontext))
CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
__END__;
}
CV_IMPL void cvUpdateWindow(const char* name)
{
CV_FUNCNAME( "cvUpdateWindow" );
__BEGIN__;
CvWindow* window;
if (!name)
CV_ERROR( CV_StsNullPtr, "NULL name string" );
window = icvFindWindowByName( name );
if (!window)
EXIT;
// window does not refresh without this
gtk_widget_queue_draw( GTK_WIDGET(window->widget) );
__END__;
}
CV_IMPL void cvCreateOpenGLCallback(const char* name, CvOpenGLCallback callback, void* userdata, double, double, double)
{
CvWindow* window;
CV_FUNCNAME( "cvCreateOpenGLCallback" );
__BEGIN__;
if(!name)
CV_ERROR( CV_StsNullPtr, "NULL name string" );
window = icvFindWindowByName( name );
if( !window )
EXIT;
if (!window->useGl)
CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
window->glDrawCallback = callback;
window->glDrawData = userdata;
__END__;
}
void icvSetOpenGlCleanCallback(const char* name, CvOpenGlCleanCallback callback, void* userdata)
{
CvWindow* window;
GdkGLContext* glcontext;
GdkGLDrawable* gldrawable;
CV_FUNCNAME( "icvSetOpenGlCleanCallback" );
__BEGIN__;
if (!name)
CV_ERROR(CV_StsNullPtr, "NULL name string");
window = icvFindWindowByName(name);
if (!window)
EXIT;
if (!window->useGl)
CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
glcontext = gtk_widget_get_gl_context(window->widget);
gldrawable = gtk_widget_get_gl_drawable(window->widget);
gdk_gl_drawable_make_current(gldrawable, glcontext);
if (window->glCleanCallback)
window->glCleanCallback(window->glCleanData);
window->glCleanCallback = callback;
window->glCleanData = userdata;
__END__;
}
#endif // HAVE_OPENGL
static void icvDeleteWindow( CvWindow* window )
{
CvTrackbar* trackbar;
#ifdef HAVE_OPENGL
if (window->useGl)
{
GdkGLContext* glcontext = gtk_widget_get_gl_context(window->widget);
GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(window->widget);
gdk_gl_drawable_make_current(gldrawable, glcontext);
if (window->glCleanCallback)
{
window->glCleanCallback(window->glCleanData);
window->glCleanCallback = 0;
window->glCleanData = 0;
}
releaseGlContext(window);
}
#endif
if( window->prev )
window->prev->next = window->next;
else
@ -835,7 +1352,20 @@ cvShowImage( const char* name, const CvArr* arr )
cvNamedWindow(name, 1);
window = icvFindWindowByName(name);
}
if( window && arr ){
if( window && arr )
{
#ifdef HAVE_OPENGL
if (window->useGl)
{
CvMat stub;
CvMat* mat = cvGetMat(arr, &stub);
cv::Mat im(mat);
cv::imshow(name, im);
return;
}
#endif
CvImageWidget * image_widget = CV_IMAGE_WIDGET( window->widget );
cvImageWidgetSetImage( image_widget, arr );
}
@ -862,8 +1392,8 @@ CV_IMPL void cvResizeWindow(const char* name, int width, int height )
EXIT;
image_widget = CV_IMAGE_WIDGET( window->widget );
if(image_widget->flags & CV_WINDOW_AUTOSIZE)
EXIT;
//if(image_widget->flags & CV_WINDOW_AUTOSIZE)
//EXIT;
CV_LOCK_MUTEX();
@ -1240,7 +1770,7 @@ static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_da
if( window->signature != CV_WINDOW_MAGIC_VAL ||
window->widget != widget || !window->widget ||
!window->on_mouse || !image_widget->original_image)
!window->on_mouse /*|| !image_widget->original_image*/)
return FALSE;
if( event->type == GDK_MOTION_NOTIFY )
@ -1299,8 +1829,8 @@ static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_da
pt = cvPointFrom32f( pt32f );
}
if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) &&
(unsigned)pt.y < (unsigned)(image_widget->original_image->height) )
// if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) &&
// (unsigned)pt.y < (unsigned)(image_widget->original_image->height) )
{
int flags = (state & GDK_SHIFT_MASK ? CV_EVENT_FLAG_SHIFTKEY : 0) |
(state & GDK_CONTROL_MASK ? CV_EVENT_FLAG_CTRLKEY : 0) |

View File

@ -214,6 +214,8 @@ int main(int argc, const char* argv[])
while (true)
{
int key = waitKey(1);
if (key >= 0)
key = key & 0xff;
if (key == 27)
break;
@ -221,7 +223,13 @@ int main(int argc, const char* argv[])
double aspect = getWindowProperty("OpenGL Sample", WND_PROP_ASPECT_RATIO);
const double posStep = 0.1;
#ifdef _WIN32
const double mouseStep = 0.001;
#else
const double mouseStep = 0.000001;
#endif
const int mouseClamp = 300;
camera.setPerspectiveProjection(30.0 + fov / 100.0 * 40.0, aspect, 0.1, 1000.0);