前一段边看OpenGL边练手,很早就在Mac下调通了(估计Linux也能跑吧),但Mac版发上来也没啥意义,于是今天移植到Windows下,姑且一发,有兴趣的同志试看看吧,自认为操作还是很友好的,鼠标左键拧它,右键控制视角,中键让它随机自拧。
这里下载。
前一段边看OpenGL边练手,很早就在Mac下调通了(估计Linux也能跑吧),但Mac版发上来也没啥意义,于是今天移植到Windows下,姑且一发,有兴趣的同志试看看吧,自认为操作还是很友好的,鼠标左键拧它,右键控制视角,中键让它随机自拧。
这里下载。
换到Glut上面,原先找到的cocoa那层都得重新写过。考虑到将来的移植问题,读取BMP的部分也就没用glaux(这玩意儿只有windows下能用……)和mac的库,自己弄了个读bmp的函数。写好之后测了半天,图片明明读进来了就是不显示纹理。折腾了一个下午,最后发现是个莫名其妙的问题导致bmp的头部读取不正常。
typedef struct tagBITMAPFILEHEADER
{
short int bfType; //specifies the file type
int bfSize; //specifies the size in bytes of the bitmap file
short int bfReserved1; //reserved; must be 0
short int bfReserved2; //reserved; must be 0
int bfOffBits; //species the offset in bytes from the bitmapfileheader to the bitmap bits
}BITMAPFILEHEADER;
很清楚的结构,short int长度2,int长度4,想当然的sizeof(BITMAPFILEHEADER)=14,试了一下,居然是16……搜了搜,发现这涉及结构体成员的对齐方式,把这段定义放进#pragma pack(1)和#pargma pack()之间即可。
原因是#pragma pack(n)指定了成员的对齐方式。对齐的时候,假设某个成员长度len,则取x=min(len, n),这个成员的起始地址就是x的整数倍。
据说intel和m$的面试题也考到这点,当然更深入。http://www.sf.org.cn/Article/base/200509/260.html
做了几件事:
1. 贴图上去,生成texture。
2. 可以用键盘控制转动速度和视角远近。
3. 可以选择贴图的插值方式(Nearest, Linear & MipMapped)。在拉近视角的那一段演示了三者的区别,可能要用高清模式才能看清。后二者在这里没区别,因为箱子是很标准的256^3,第一个则可以看出来颗粒。
4. 灯光。设置了两个光源,一个是ambient的白光,亮度50%,另一个是diffuse的白光,亮度100%,位置固定。结果居然是看到箱子在两面显得暗,转到另外两面就变亮了。现在还不知道坐标是怎么设置的,也许是因为这里相对于空间转动的是视角而不是箱子吧。
update about 4:
检查了一个晚上,发现原来是在绘制立方体的时候没有用glNormal指定每个面的法向量,导致了光线诡异的变化。修改之后就正常了,下面这段视频是在修改后的基础上加入blending,实现透明效果。
昨天夜里到今天夜里,解决了两个主要问题:如何读取BMP文件来构建CGImage对象,以及如何把24-bit的BMP做成纹理放到OpenGL里。
第一个问题就贴一段代码好了。
CFBundleRef bundle = CFBundleGetMainBundle();
CFURLRef url = CFBundleCopyResourceURL(bundle, CFSTR(“filename”), CFSTR(“bmp”), NULL);
//然后调用LoadImage(CFURLRef url),就可以得到一个CGImageRef了。
CGImageRef LoadImage(CFURLRef url)
{
if (!url)
return NULL;
CGImageSourceRef isr = CGImageSourceCreateWithURL (url, NULL);
CGImageRef ir = CGImageSourceCreateImageAtIndex (isr, 0, NULL);
return ir;
}
整个过程相当郁闷,折腾了半天url总是NULL,后来才找到这个比较通用的流程。如果在windows下应该只需要读进来一个File扔给auxDIBImageLoad()就可以了,无奈在Mac下最好的替代也许就是这个CGImage,只好硬着头皮上。
第二个问题就更是体现出CGImage的怪异。
事情是这样的。glTexImage2D需要的纹理数据存放在一个空间(就叫myData)里面。已经读入的要作为纹理的图片构成的CGImage对象由ir这个指针指向。于是,必须用CGBitmapContextCreate(…)来把CGImage的数据提取出来放到myData里。而这个函数只支持有限的几种图片模式(具体可见http://developer.apple.com/qa/qa2001/qa1037.html),也就是说OS/2下面24-bit的RGB三通道的BMP是不能直接用的。然后,我就迷糊了:我读入这个图片之后,在CGImage对象里面被存成什么样了呢?如果直接读取它的BitmapInfo传进去,报错说不支持这种模式。于是就得从支持的模式里面挑一中来强制转换。最后我才算明白,恶心之处就在于CGImage把RGB的存放方式改了,而且加上了Alpha通道,放在一个32-bit的结构里,但你用CGImageGetBitmapInfo()读取出来的只是转换之前的信息。经过半天摸石头过河的实验之后才搞清楚,RGB的24-bit被变成了顺序为RGBA的32-bit。所以应该用kCGImageAlphaPremultipliedLast或者kCGImageAlphaNoneSkipLast把Alpha扔掉才行。
并且,在glTexImage2D函数里面,internalformat要用GL_RGB,format要用GL_RGBA,才能把纹理正确渲染出来。因为前者是指定纹理的储存和绘制方式,后者是指定myData里的数据是以什么格式储存的。
最后,我用Photoshop做了个RGBA的32-bit BMP放进去,BitmapInfo参数用实际读取的结果做参数居然还是报告不支持该模式,nnd,也不应该是Big-endian和Little-endian的问题啊……再说了。
有关Framework。
今天遇到一个问题。某个例程里面用了#include
Mac下面的Framework都是用bundle的形式提供的,一个bundle里面可以共存多种版本,保证了对旧版本程序的支持。为了为特定的应用环境提供必需的编程接口,Apple在标准的Framework之外还提供了Umbrella Framework。照我的理解,UF顾名思义应该是期望用伞架的结构,讲分散在各个Standard Framework里的subframework虚拟的链接起来,形成针对某种特定应用的新的framework。与Standard Framework不同,UF并不把它的subframeworks里的头文件都包括进来,而仅仅包含那个framework的master header file,也就是与framework同名的那个。因此,在调用UF的时候,只需要include这个头文件即可。这样也带来一个好处,就是如果Apple对某个framework里的东西进行了修改,开发者并不需要对他们的代码做改动,因为那个master header file总是不会改变的。
好了,废话这么多,最终结论就是,只需要#include
今天开始配OpenGL的编译环境。
目前,根据我的理解,OpenGL并没有提供统一的SDK,所以有GLUT, freeglut之类的东西并存,安装之后,它们就能提供OpenGL编译所需要的一系列接口。
首先试了Mac OS X。其实没多想就放弃了。这姑娘长得那么漂亮,就没个编程的氛围……
然后就开Parallels拿Ubuntu 8.04出来。很轻松的apt-get install一下,就装上了libglut和freeglut等4个包。网上抄了一段测试代码,写好makefile,编译,通过,跳出来一个渲染后的窗口。但是console里很显眼的报错:freeglut: unable to create direct context rendering for window ‘xx’。google了一下,问题在于显卡的硬件加速没有发挥作用。从跳出来的窗口上也可以感觉到确实有些不顺畅。于是,找了nvidia的驱动来装。估量着Pro的显卡还是比较新的,8600M GT,所以装了nvidia-glx-new(-dev)。而且这个new的东西也确实是为8.04的新内核而生的。
但是,装完之后又出现新问题,连运行都不能了。编译、链接通过,运行直接报错:freeglut: OpenGL GLX extension not supported by display ‘:0.0’。再google,说是freeglut,libglut的库和nvidia驱动自带的库不能共存。!×·&……#¥×(!……#
之后看到有一篇文章,面对这种情况时,某人用mesa编译了库来用软件加速,直接无视nvidia的东西。于是照猫画虎,我也弄了mesa来编译。不见起色……怀疑是nvidia还在的缘故,于是又删了驱动,重装freeglut & libglut,重启,又弄出来新的问题,找不到-lGL。手动跑了一次ldconfig,还是死样。又把驱动装回来,编译过了,运行又是unable to create……回到原点。这时候真是严重的心烦意乱,懒得再折腾LIBRARY_PATH啥的了,估计是用虚拟机跑的时候显卡驱动比较土吧。
最后收拾收拾,还是回到Mac下了。正好翻到NeHe的OpenGL教程,里面居然有专门针对OS X的说明!OS X里也有自带OpenGL Framework。nnd。。。正好之前也装了Xcode,就下了一段sample code来。结果……一下通过……运行顺利……出现了一个可爱的红色三角形……
叹,虽然是绕了个大圈,花了大半天时间,最后的结果还是成功的,不仅可以动手写东西了,而且能舒服的呆在Mac下享受漂亮的界面而不必忍受Parallels上面奇怪的Linux(btw, Parallels跑Linux居然不能与OS X之间copy/paste,官方的解释也是无能为力。这叫人怎么用……)。
发泄完毕。