Categories
OpenGL

OpenGL notes(2)

昨天夜里到今天夜里,解决了两个主要问题:如何读取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的问题啊……再说了。

Categories
OpenGL

OpenGL notes(1)

有关Framework。

今天遇到一个问题。某个例程里面用了#include 调用了Mac OS X自带的OpenGL库,编译正常。在尝试用贴图渲染3D物体时,NeHe教程里用了AUX_RGBImageRec来储存读入的图片,而这个类型是包含在glaux库里的,这个库又是windows only的。Apple给的官方说明给了一些选项来完成mac中的相同任务,一是用Cocoa的NSView类,二是用Quartz的image source,三是直接从解压的文件里读入Raw数据。当然,我选了第二个。系统的ApplicationServices/CoreGraphics.framework/CGImage.h里面定义了Quartz的图像数据类型CGImageRef,所以,我得把这个头文件include进去。可是导入了ApplicationServices Framework到工程里,在头文件里用#include 却总是报错,no such file or directory。而在工程浏览器里CGImage.h明明在ApplicationServices下面……后来翻Xcode的文档才发现,涉及深层次的问题。

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 就可以。