天天看點

在Windows/Ubuntu下安裝OpenGL環境(GLUT/freeglut)與跨平台編譯(mingw/g++)

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 下

在Windows/Ubuntu下安裝OpenGL環境(GLUT/freeglut)與跨平台編譯(mingw/g++)

Ubuntu 下

在Windows/Ubuntu下安裝OpenGL環境(GLUT/freeglut)與跨平台編譯(mingw/g++)

繼續閱讀