在Ubuntu Linux操作系统中有不少开源且好用的工具库用于读取图片文件,识别它们的格式,然后以RGB等原生像素格式保存到存储器中。比如libpng就是其中之一。不过我们这里使用更方便、更快捷、更通用的GTK+库中所包含的GDK工具库对指定的图片文件进行读取,然后读取其内部原生像素数据,最后映射到纹理单元上。
我们可以参考这篇文章来下载安装GTK+:Ubuntu下安装GTK+3的方法。
下面我们先建立一个shell文件,命名为build.sh,用它进行构建整个程序。 clang main.c -std=gnu11 -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 -lgdk_pixbuf-2.0 -lglib-2.0 -o glutTexture
如果你的电脑没有安装Clang,也可以使用GCC。如果用GCC进行编译构建的话,只需要将上述的clang改为gcc就可以了。
下面展示main.c源文件: #include <stdio.h> #include <unistd.h> #include <stdbool.h> #include <string.h> #include <GL/freeglut.h> #include <GL/gl.h> #include <gtk/gtk.h> #include <gdk/gdk.h> #include <gdk-pixbuf/gdk-pixbuf.h> #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 sRectTexCoords[] = { // top left 0.0f, 0.0f, // bottom left 0.0f, 1.0f, // top right 1.0f, 0.0f, // bottom right 1.0f, 1.0f }; static void TimerHandler(int value); static GLfloat sDisplacement = -0.5f; static GLfloat sDelta = 0.005f; static int sTimerDuration = 20; //默认以50FPS的帧率进行刷新 static void RenderHandler(void) { glutTimerFunc(sTimerDuration, TimerHandler, 0); sTimerDuration = 20; glClear(GL_COLOR_BUFFER_BIT); // Draw rectangle glVertexPointer(2, GL_FLOAT, 0, sRectVertices); glTexCoordPointer(2, GL_FLOAT, 0, sRectTexCoords); glLoadIdentity(); glTranslatef(sDisplacement, 0.0f, -2.0f); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glFlush(); glutSwapBuffers(); sDisplacement += sDelta; if(sDisplacement >= 0.5f) { sDisplacement = 0.5f; sDelta = -sDelta; sTimerDuration = 1500; } else if(sDisplacement <= -0.5f) { sDisplacement = -0.5f; sDelta = -sDelta; sTimerDuration = 1500; } } static void TimerHandler(int value) { RenderHandler(); } static bool LoadPixelsFromImageToTexture(const char *filePath) { var pixBuf = gdk_pixbuf_new_from_file(filePath, NULL); if(pixBuf == NULL) { puts("The image is not found!"); printf("The file path is: %s\n", filePath); return false; } const var width = gdk_pixbuf_get_width(pixBuf); const var height = gdk_pixbuf_get_height(pixBuf); printf("The image width is: %d, height is: %d\n", width, height); var pixels = gdk_pixbuf_read_pixels(pixBuf); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); g_object_unref(pixBuf); return true; } int main(int argc, char* argv[]) { gtk_init(&argc, &argv); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE); glutInitWindowSize(480, 480); glutInitWindowPosition(200, 100); glutCreateWindow("OpenGL GLUT Demo"); 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); printf("The vendor is: %s\n", vendor); printf("The renderer is: %s\n", renderer); 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); glEnable(GL_TEXTURE_2D); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glActiveTexture(GL_TEXTURE0); GLuint texID; glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); char path[512]; int size = readlink("/proc/self/exe", path, 512); int index = 0; for(int i = size - 1; i >= 0; i--) { const var ch = path[i]; if(ch == '/') { index = i + 1; break; } } bool result = false; do { if(index == 0) break; strcpy(&path[index], "image.png"); result = LoadPixelsFromImageToTexture(path); } while(false); if(!result) { puts("Image data load failed!"); glDeleteTextures(1, &texID); return 0; } glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 3.0f); glMatrixMode(GL_MODELVIEW); glutMainLoop(); glDeleteTextures(1, &texID); }
这里需要注意,在运行上述程序之前先搞一个PNG的图片,把它命名为image.png,然后将它放到build.sh和main.c同一文件目录下。这里对image.png是有要求的,它的宽和高的像素个数必须至少为32的倍数,并且最小值取为64,这是符合作为纹理的最低要求。
相关主题 |