摘要: 最近已经从写技术博客慢慢转移到写技术日记。这里是技术日记的地址:http://joyeecheung.github.io/diary/。 写技术日记的缘由和一些感受 最近已经坚持记了快两个月的技术日记,感觉比技术博客写起来更有意思: 起步 一开始是简单地开了一个 git repo,按照日期存档一堆 阅读全文
posted @ 2015-06-05 23:27 Joyee 阅读(4813) 评论(6) 推荐(3) 编辑

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-toolkitmingw32-basemingw32-gcc-g++msys-base

关于如何在 Windows 下安装 mingw 环境,这里不赘述,可以参考这个链接。安装完之后需要记得将 mingw/binmingw/msys/版本号/bin 加入 PATH 环境变量。设置完环境变量后打开 cmd(如果设置前已经打开了,需要关掉再开或者另开一个cmd),如果运行 make --versiong++ --versionbash --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 下

 

Ubuntu 下

posted @ 2015-03-03 11:11 Joyee 阅读(34916) 评论(1) 推荐(4) 编辑
摘要: 前言这个降噪的模型来自 Christopher M. Bishop 的 Pattern Recognition And Machine Learning (就是神书 PRML……),问题是如何对一个添加了一定椒盐噪声(Salt-and-pepper Noise)(假设噪声比例不超过 10%)的二值图... 阅读全文
posted @ 2015-02-01 00:42 Joyee 阅读(13295) 评论(4) 推荐(2) 编辑
摘要: 这里是用 JavaScript 做的逆转序列(数组/字符串)的递归/尾递归实现。另外还尝鲜用了一下 ES6 的destructuring assignment + spread operator 做了一个更 functional 的版本(只支持数组)。正确性能通过测试(参见 放在我 Github 上... 阅读全文
posted @ 2015-01-11 03:59 Joyee 阅读(2446) 评论(1) 推荐(0) 编辑
摘要: 写在前面这篇没有什么 WebKit 代码的分析,因为……没啥好分析的,在实现里无非就是树的(先序DFS)遍历而已,囧哈哈哈……在WebCore/dom/Node.h , WebCore/dom/ContainerNode.h 和 WebCore/dom/Element.h 以及对应的 .cpp 里看... 阅读全文
posted @ 2014-12-17 08:01 Joyee 阅读(6678) 评论(0) 推荐(1) 编辑
摘要: 使用CSS选择器获取元素 -- querySelector,querySelectorAll(HTML5)标准W3C Selector API Level 1为Document,DocumentFragment和Element追加了querySelector和querySelctorAll,原型为E... 阅读全文
posted @ 2014-11-26 12:35 Joyee 阅读(2065) 评论(0) 推荐(0) 编辑
摘要: 按照类名获取元素 -- getElementsByClassName(HTML5)标准WHATWG 在Document与Element上均有定义,原型 HTMLCollection getElementsByClassName(DOMString classNames),并定义了匹配算法和类名的提取... 阅读全文
posted @ 2014-11-26 12:33 Joyee 阅读(1277) 评论(0) 推荐(0) 编辑
摘要: 按照标签名获取元素 -- getElementsByTagName标准DOM 1在Element和Document两个interface中均有定义,原型NodeList getElementsByTagName(in DOMString tagname),指明按照先序遍历遇到的顺序排列,不会抛出任何... 阅读全文
posted @ 2014-11-22 17:35 Joyee 阅读(3008) 评论(0) 推荐(0) 编辑
摘要: 按照name属性获取多元素 -- getElementsByName标准DOM 1 定义在HTMLDocument Interface 中,原型NodeList getElementsByName(in DOMString elementName),该方法不会抛出任何异常。DOM 2依然定义在HTM... 阅读全文
posted @ 2014-11-22 17:24 Joyee 阅读(2459) 评论(0) 推荐(1) 编辑
摘要: 按照ID获取元素 -- getElementById标准DOM 1,定义在HTMLDocument Interface 中,原型Element getElementById(in DOMString elementId),当不存在拥有对应ID的元素时返回null,该方法不会抛出任何异常。DOM 2,... 阅读全文
posted @ 2014-11-22 17:21 Joyee 阅读(1589) 评论(0) 推荐(0) 编辑
摘要: 涉及获取元素的主要API在获取原生DOM元素的时候,主要涉及这几个DOM API(链接为Living Standard):Node及对应集合NodeListElement(继承Node)及对应集合HTMLCollectionDocument(继承Node)注:计划取代NodeList和HTMLCol... 阅读全文
posted @ 2014-11-01 23:07 Joyee 阅读(1179) 评论(3) 推荐(2) 编辑
点击右上角即可分享
微信分享提示