Ubuntu下GTK与GLUT的共同使用

今天不知神马原因,一下子突发奇想,试想了一下GTK与GLUT是否可以相互协作,经过初步测试,这还算是可行的。在以下demo中,我们可以点击由GTK创建的按钮然后弹出用GLUT创建的窗口。由于GTK与GLUT是两个完全独立的库,两者均含有各自的消息循环(也就是通常所说的runloop),因此当我们点击按钮弹出GLUT窗口的时候,其实相应的都是GLUT的消息循环,GTK此时处于冻结状态。只有当我们将GLUT窗口关闭之后,GTK窗口才会被再次激活,侦听消息。

跟以往一样,这里先给出本次demo所需的shell文件内容,便于编译构建。

clang main.c -std=gnu11 -fblocks -lBlocksRuntime -lglut -lGL -I/usr/include/glib-2.0/ -I/usr/include/atk-1.0/ -I/usr/include/gdk-pixbuf-2.0/ -I/usr/include/cairo/ -I/usr/include/pango-1.0/ -I/usr/lib/x86_64-linux-gnu/glib-2.0/include/ -I/usr/include/gtk-3.0/ -L/usr/lib/x86_64-linux-gnu/ -lgtk-3 -lgobject-2.0 -lpangocairo-1.0 -lgio-2.0 -latk-1.0 -lgdk-3 -lglib-2.0    -o gtk-glut

同样,如果各位使用的是GCC编译器,那么将上述的clang变为gcc,同时删除-fblocks -lBlocksRuntime这两个命令行选项。
下面则是C源代码。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#ifndef var
#define var     __auto_type
#endif


static const GLfloat sRectVertices[] = {
    // top left
    -0.4f, 0.4f,

    // bottom left
    -0.4f, -0.4f,

    // top right
    0.4f, 0.4f,

    // bottom right
    0.4f, -0.4f
};

static const GLfloat sTriangleVertices[] = {
    // top center
    0.0f, 0.4f,

    // bottom left
    -0.4f, -0.4f,

    // bottom right
    0.4f, -0.4f
};

static const GLfloat sColors[] = {
    // red
    1.0f, 0.0f, 0.0f, 1.0f,

    // green
    0.0f, 1.0f, 0.0f, 1.0f,

    // blue
    0.0f, 0.0f, 1.0f, 1.0f,

    // white
    1.0f, 1.0f, 1.0f, 1.0f
};

static int sRotAngle = 0;

static void TimerHandler(int value);

static void RenderHandler(void)
{
    // 以50FPS的帧率进行刷新
    glutTimerFunc(20, TimerHandler, 0);

    glClear(GL_COLOR_BUFFER_BIT);

    // Draw rectangle
    glVertexPointer(2, GL_FLOAT, 0, sRectVertices);
    glColorPointer(4, GL_FLOAT, 0, sColors);

    glLoadIdentity();
    glTranslatef(-0.5f, 0.0f, -2.0f);
    glRotatef(sRotAngle, 0.0f, 0.0f, 1.0f);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    // Draw triangle
    glVertexPointer(2, GL_FLOAT, 0, sTriangleVertices);
    glColorPointer(4, GL_FLOAT, 0, sColors);

    glLoadIdentity();
    glTranslatef(0.5f, 0.0f, -2.1f);
    glRotatef(-sRotAngle, 0.0f, 0.0f, 1.0f);

    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    glFlush();

    glutSwapBuffers();

    if(++sRotAngle == 360)
        sRotAngle = 0;
}

static void TimerHandler(int value)
{
    RenderHandler();
}

static int sGLUTWindow;
static int sStoredArgC;
static char **sStoredArgv;

static void GLUTWindowCloseHandler(void)
{
    glutDestroyWindow(sGLUTWindow);
    glutLeaveMainLoop();
}

static void ShowOpenGLWindow(GtkWidget *widget, gpointer window) 
{
    if(window != NULL)
        g_printf("Button clicked\n");

    // 每次打开GLUT窗口前必须先调用一次glutInit函数
    glutInit(&sStoredArgC, sStoredArgv);
    // 当用户点击GLUT窗口时,应用不直接退出
    glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
    glutCloseFunc(GLUTWindowCloseHandler);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE);
    glutInitWindowSize(480, 480);
    glutInitWindowPosition(200, 100);
    sGLUTWindow = glutCreateWindow("OpenGL GLUT Window");

    glutSetOption(GLUT_MULTISAMPLE, 4);
    glutDisplayFunc(RenderHandler);

    var vendor = (const char*)glGetString(GL_VENDOR);
    var renderer = (const char*)glGetString(GL_RENDERER);
    var version = (const char*)glGetString(GL_VERSION);
    g_printf("The vendor is: %s\n", vendor);
    g_printf("The renderer is: %s\n", renderer);
    g_printf("The GL version is: %s\n", version);

    glViewport(0, 0, 480, 480);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glShadeModel(GL_SMOOTH);
    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);

    glEnable(GL_CULL_FACE);
    glEnable(GL_MULTISAMPLE_ARB);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 3.0f);

    glMatrixMode(GL_MODELVIEW);

    glutMainLoop();

    g_printf("GLUT runloop has quit!\n");
}

int main(int argc, char *argv[])
{
    // 保存argc与argv        
    sStoredArgC = argc;
    sStoredArgv = argv;

    gtk_init(&argc, &argv);

    var window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "GTK-GLUT");
    gtk_window_set_default_size(GTK_WINDOW(window), 480, 320);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_container_set_border_width(GTK_CONTAINER(window), 15);

    var button = gtk_button_new_with_label("Show GLUT");
    gtk_widget_set_halign(button, GTK_ALIGN_START);
    gtk_widget_set_valign(button, GTK_ALIGN_START);
    gtk_widget_set_tooltip_text(button, "This is a button widget");
    g_signal_connect(button, "clicked", G_CALLBACK(ShowOpenGLWindow), window); 
    gtk_container_add(GTK_CONTAINER(window), button);

    gtk_widget_show_all(window);
 
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    static_assert(sizeof(int) == 4, "Not compatible architecture!");

    puts("Will enter GTK runloop...");

    gtk_main();

    puts("Program terminated!");
}

我们编译构建完此程序之后,直接在命令行输入gtk-glut这个app即可运行。我们每次点击按钮均能弹出GLUT窗口,点击关闭GLUT窗口可再次对GTK窗口中的按钮进行点击。

你可能感兴趣的:(Ubuntu下GTK与GLUT的共同使用)