GLUT/freeglut 是什么? OpenGL 和它們有什么關系?
OpenGL只是一個標准,它的實現一般自帶在操作系統里,只要確保顯卡驅動足夠新就可以使用。如果需要在程序里直接使用OpenGL,會有很多非常惡心的預備工作要做,而且可能還要專門為平台的差異寫一些代碼。要跳過這些工作,可以用一個utility庫,直接使用它提供的函數,就不用操心那些細節了。這樣的庫新一點的有GLEW,因為開源所以安裝相對方便(大不了丟進去一起編譯),但各種教程和書里常見的是閉源的GLUT。由於GLUT的作者已經很久沒更新過了(最后更新於2000年!= =),所以其他人另外做了一個接口兼容GLUT的freeglut,開源而且一直在維護中。
這篇文章介紹了怎樣在 Linux(Ubuntu)和 Windows 下安裝 GLUT/freeglut,以及如何編寫能夠跨平台編譯的 Makefile 和代碼。在 Windows 下可以安裝 GLUT 或者 freeglut 其中的一個,不過建議安裝后者。在 Ubuntu 下安裝 freeglut即可。
Linux 下安裝
Linux 下一般使用開源的 freeglut,安裝相對於 windows 比較方便,比如 Ubuntu 下安裝只要一行命令:
$ sudo apt-get install build-essential freeglut3 freeglut3-dev binutils-gold
Windows 下安裝
在 Windows 下如果不使用 Visual Studio 系的環境,可以用 *nix 的命令行工具在 Windows 下的移植版,通常使用的是 mingw 系列套裝。
建議直接使用 mingw 的包管理器下載安裝需要的包,如果要像這篇文章一樣能夠用 g++ 和 Make 編譯,最好安裝 g++(gcc)、GNU Make 和 *nix 常用命令行工具的移植版,也就是在 mingw 的包管理器里選擇安裝 mingw-developer-toolkit
、mingw32-base
、mingw32-gcc-g++
和 msys-base
。
關於如何在 Windows 下安裝 mingw 環境,這里不贅述,可以參考這個鏈接。安裝完之后需要記得將 mingw/bin
和 mingw/msys/版本號/bin
加入 PATH
環境變量。設置完環境變量后打開 cmd(如果設置前已經打開了,需要關掉再開或者另開一個cmd),如果運行 make --version
,g++ --version
和 bash --version
可以看到相關的版本信息,就說明安裝成功了,比如:
C:\Users\Administrator> make --version GNU Make 3.81 Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. C:\Users\Administrator> g++ --version g++ (GCC) 4.8.1 Copyright (C) 2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. C:\Users\Administrator>bash --version GNU bash, version 3.1.23(1)-release (i686-pc-msys) Copyright (C) 2005 Free Software Foundation, Inc.
1. 下載 GLUT/freeglut
如果安裝 GLUT,地址在:https://user.xmission.com/~nate/glut.html,下載 glut-3.7.6-bin.zip(已經十幾年沒更新過了所以就是這個版本了2333)
freeglut 在地址:http://www.transmissionzero.co.uk/software/freeglut-devel/ ,點擊 Download freeglut 2.8.1-1 for MinGW
2. 放置頭文件和庫文件(GLUT)
解壓下載到的zip,里面就是相關的頭文件和庫文件了。
對於 GLUT 而言,因為glut.dll 是32位的,所以在64位系統下放在C:\Windows\SysWOW64,32位系統下放在C:\Windows\System32。另外無論系統直接放在C:\Windows也可以。glut.h 放到mingw/include/GL,glut32.lib 放到mingw/lib。
比如一個64位系統的mingw安裝在D:/mingw,GLUT 放完之后大概是這樣:
C:\Windows\SysWOW64 └─ glut.dll D:\mingw ├─ include │ └─ GL │ └─ glut.h └─ lib └─ glut32.lib
2. 放置頭文件和庫文件(freeglut)
放置如下,因為mingw如果不用64位的port(mingw-w64)的話只有32位,所以這里使用32位的文件。
C:\Windows\SysWOW64 └─ freeglut.dll (32位的mingw就用bin目錄下那個,不是bin/x64那個) D:\mingw ├─ include │ └─ GL │ ├─ freeglut.h │ ├─ freeglut_ext.h │ ├─ freeglut_std.h │ └─ glut.h (注意這個和老版的glut.h不同) └─ lib ├─ libfreeglut.a (這兩個同樣用lib目錄下的兩個) └─ libfreeglut_static.a
一般操作系統會自帶 glu32.dll, mingw 在安裝的時候就會帶上一些頭文件在 include/GL,lib 里也有opengl和glu的庫文件,看到不需要奇怪。
如果熟悉自己的工具,更喜歡自己編譯連接時指定庫文件和頭文件位置,這一步可以跳過,放在自己覺得合適的地方,只要在工程/Makefile聲明路徑即可。
配置編譯/鏈接參數
GLUT
- 編譯參數需要加上加
-DGLUT_DISABLE_ATEXIT_HACK
(也可以在代碼里#define GLUT_DISABLE_ATEXIT_HACK
) - 鏈接參數加上
-lopengl32 -lglu32 -lglut32
freeglut (Windows)
- 不需要特別的編譯參數
- 鏈接參數為
-lfreeglut -lopengl32 -Wl,--subsystem,windows。
freeglut (Linux)
- 不需要特別的編譯參數
- 鏈接參數為
-lGL -lglut。
mingw 本身就是 32 位,所以不需要特別設置。如果是用的 mingw-w64,還需要在參數里加上 -m32
代碼里使用頭文件
在 windows 下使用 GLUT 的函數前需要引用以下兩個頭文件
#include <windows.h>
#include <GL/glut.h>
順序不能反。一般教程或者樣例代碼里如果不是針對win32平台不會有#include <windows.h>
,很多東西的定義就找不到了,所以跑之前要檢查。如果要自動檢測操作系統的話進行條件編譯的話,就是這樣
#if defined(_WIN32) || defined(WIN32) #include <windows.h> #endif
例子
Makefile
如果用的是使用 mingw 的 IDE,只要記得在里面配置步驟 3 的參數即可(一般在project或者build之類的選項里)。
GLUT 使用的 Makefile
LDFLAGS=-lopengl32 -lglu32 -lglut32 CFLAGS=-g -DDEBUG -DGLUT_DISABLE_ATEXIT_HACK all: g++ main.cpp -c -o main.o $(CFLAGS) g++ main.o $(LDFLAGS) -o main.exe clean: rm main.o main.exe
freeglut 使用的 Makefile
LDFLAGS=-lfreeglut -lopengl32 -Wl,--subsystem,windows CFLAGS=-g -DDEBUG all: g++ main.cpp -c -o main.o $(CFLAGS) g++ main.o $(LDFLAGS) -o main.exe clean: rm main.o main.exe
使用freeglut,跨平台支持的 Makefile
ifeq ($(OS),Windows_NT) LDFLAGS=-lfreeglut -lopengl32 -Wl,--subsystem,windows EXECUTABLE=main.exe else LDFLAGS=-lGL -lglut EXECUTABLE=main endif CFLAGS=-g -DDEBUG all: g++ main.cpp -c -o main.o $(CFLAGS) g++ main.o $(LDFLAGS) -o $(EXECUTABLE) clean: rm main.o $(EXECUTABLE)
程序main.cpp
,來自OpenGL Code Samples,注意windows下要添加 windows.h:
#include <stdio.h> #include <stdlib.h> #include <string.h>
#if defined(_WIN32) || defined(WIN32)
#include <windows.h>
#endif
#include <GL/glut.h> GLenum doubleBuffer; GLint thing1, thing2; static void Init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glClearAccum(0.0, 0.0, 0.0, 0.0); thing1 = glGenLists(1); glNewList(thing1, GL_COMPILE); glColor3f(1.0, 0.0, 0.0); glRectf(-1.0, -1.0, 1.0, 0.0); glEndList(); thing2 = glGenLists(1); glNewList(thing2, GL_COMPILE); glColor3f(0.0, 1.0, 0.0); glRectf(0.0, -1.0, 1.0, 1.0); glEndList(); } static void Reshape(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } static void Key(unsigned char key, int x, int y) { switch (key) { case '1': glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glutPostRedisplay(); break; case '2': glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glutPostRedisplay(); break; case 27: exit(0); } } static void Draw(void) { glPushMatrix(); glScalef(0.8, 0.8, 1.0); glClear(GL_COLOR_BUFFER_BIT); glCallList(thing1); glAccum(GL_LOAD, 0.5); glClear(GL_COLOR_BUFFER_BIT); glCallList(thing2); glAccum(GL_ACCUM, 0.5); glAccum(GL_RETURN, 1.0); glPopMatrix(); if (doubleBuffer) { glutSwapBuffers(); } else { glFlush(); } } static void Args(int argc, char **argv) { GLint i; doubleBuffer = GL_FALSE; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-sb") == 0) { doubleBuffer = GL_FALSE; } else if (strcmp(argv[i], "-db") == 0) { doubleBuffer = GL_TRUE; } } } int main(int argc, char **argv) { GLenum type; glutInit(&argc, argv); Args(argc, argv); type = GLUT_RGB | GLUT_ACCUM; type |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE; glutInitDisplayMode(type); glutInitWindowSize(300, 300); glutCreateWindow("Accum Test"); Init(); glutReshapeFunc(Reshape); glutKeyboardFunc(Key); glutDisplayFunc(Draw); glutMainLoop(); }
運行結果
Windows 下