Thursday, March 27, 2008

Crossing Every T, Dotting Every I.

I've had a bug in some GL code for about an hour, and I've been beating my head against the wall trying to figure out what I'd done wrong.  glGetUniformLocation was returning crazy values, and glUniform1f was generating an invaild operation.  The problem? glUniform1f where I had intended glUniform1i. A simple typo, but somehow it also screwed up the values coming back from glGetUniformLocation, which is where I noticed it.

On that note, remember that glUniform* act on the currently bound program, so make sure there is one before you call it.

Sunday, March 23, 2008

NSArray indexOfObjectIdentialTo:

NSArray's indexOfObjectIdenticalTo: does not behave as documented, and the the sample code given by Apple demonstrating it does not do what it says it does. For a more complete description see my two posts at:
http://www.idevapps.com/forum/showthread.php?t=6463

Tuesday, March 18, 2008

Another Demo Finished

Up to fixing up the user controls, I've finished my reflection/refraction demo. I've used hdr textures, but I haven't tone mapped them, so they're a bit bright. I'm going to do that in a future demo. At some point I'm going to turn these into a set of tutorials, but I might wait until OpenGL 3.0 finally arrives.

ImageIO OpenGL and Radiance .hdr Files

I promised to post my ImageIO code once I had things working, and now that it's working, I'm going to do just that. I just worked through the last bug I had in my texturing code. 

If you're using ImageIO to read Radiance .hdr files, and you're getting garbage, check the type parameter you're passing to glTexImage2D. The Apple documentation concerning ImageIO and OpenGL uses the format GL_UNSIGNED_INT_8_8_8_8_REV. While .hdr files are floating point, its the REV you should take note of.  The byte ordering of each R, G, B component is individually reversed between what ImageIO provides and OpenGL expects. Simply call glPixelStorei(GL_UNPACK_SWAP_BYTES,1) and things should look a bit more normal.

I hope this saves someone else a few minutes. 





Boolean osx_CGImageSupportsFileFormat(std::string format) {
CFArrayRef imageFormats = CGImageSourceCopyTypeIdentifiers();
CFStringRef targetImageFormat = CFStringCreateWithCString( kCFAllocatorDefault, format.c_str(), kCFStringEncodingUTF8 );
CFRange imageFormatsRange = CFRangeMake( 0, CFArrayGetCount( imageFormats ) );
Boolean didContainFormat = CFArrayContainsValue(imageFormats, CFRangeMake(0, CFArrayGetCount(imageFormats)), targetImageFormat);
CFRelease(targetImageFormat);
CFRelease(imageFormats);
return didContainFormat;
}

CGImageRef osx_CGImageCreateFromFile(std::string filename) {
CGImageRef image = 0;
CFStringRef fileString = 0;
CFURLRef fileURL = 0;
CGImageSourceRef imageSource = 0;
CFDictionaryRef imageSourceOptions = 0;
CFStringRef imageSourceKeys[] = { kCGImageSourceShouldAllowFloat, kCGImageSourceShouldCache };
CFBooleanRef imageSourceValues[] = { kCFBooleanTrue, kCFBooleanTrue };

try {
fileString = CFStringCreateWithCString( kCFAllocatorDefault, filename.c_str(), kCFStringEncodingUTF8 );
if (fileString == 0) throw std::runtime_error("CFStringCreateWithCString");

fileURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, fileString, kCFURLPOSIXPathStyle, 0);
if (fileURL == 0) throw std::runtime_error("CFURLCreateWithFileSystemPath");

imageSource = CGImageSourceCreateWithURL(fileURL, 0);
if (imageSource == 0) throw std::runtime_error("CGImageSourceCreateWithURL");

imageSourceOptions = CFDictionaryCreate( kCFAllocatorDefault, (const void**)&imageSourceKeys, (const void**)&imageSourceValues, 1, 0, 0 );
if (imageSourceOptions == 0) throw std::runtime_error("CFDictionaryCreate");

image = CGImageSourceCreateImageAtIndex(imageSource, 0, imageSourceOptions);
if (image == 0) throw std::runtime_error("CGImageSourceCreateImageAtIndex");
}
catch(std::runtime_error &problem) {
std::cerr << problem.what() << std::endl;
}

CFRelease(imageSourceOptions);
CFRelease(imageSource);
CFRelease(fileURL);
CFRelease(fileString);

return image;
}

void osx_CGImageCrossCubeToImageCube(CGImageRef source, ImageCube &imageCube) {
size_t x = CGImageGetWidth(source) / 3;
size_t y = CGImageGetHeight(source) / 4;

assert( x == y ); // Images should be square. Could scale to ensure this instead of aborting.

CGRect imageBounds[6] = {0};

imageBounds[0] = CGRectMake(2*x, y, x, y); // +x 1
imageBounds[1] = CGRectMake(0, y, x, y); // -x 0
imageBounds[2] = CGRectMake(x, 2*y, x, y); // -y 2
imageBounds[3] = CGRectMake(x, 0, x, y); // +y 3
imageBounds[4] = CGRectMake(x, y, x, y); // -z 4
imageBounds[5] = CGRectMake(x, 3*y, x, y); // +z 5

imageCube.size = x;
imageCube.bitsPerComponent = CGImageGetBitsPerComponent(source);
imageCube.numComponents = 4;

const size_t bytesPerRow = imageCube.size * imageCube.numComponents * imageCube.bitsPerComponent / 8;

CGImageRef partitions[6] = {0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

for (int i = 0; i < 6; ++i) {
imageCube.image[i].resize( imageCube.size * bytesPerRow );
partitions[i] = CGImageCreateWithImageInRect(source, imageBounds[i]);
CGContextRef imageContext = CGBitmapContextCreate( &imageCube.image[i][0],
imageCube.size, imageCube.size,
imageCube.bitsPerComponent,
bytesPerRow,
colorSpace,
kCGImageAlphaNoneSkipLast | kCGBitmapFloatComponents );

CGContextSaveGState(imageContext);

// Up Down and Backwards are flipped in the cube cross format
if ( i == 2 || i == 3 || i == 5 ) {
CGContextTranslateCTM(imageContext, imageCube.size, imageCube.size);
CGContextScaleCTM(imageContext, -1.0f, -1.0f);
}

CGContextDrawImage(imageContext, CGRectMake(0, 0, imageCube.size, imageCube.size), partitions[i]);
CGContextRestoreGState(imageContext);
CGContextRelease(imageContext);
CGImageRelease(partitions[i]);
}

CGColorSpaceRelease(colorSpace);
}

Apple and OpenGL 3.0

OS X has never had good OpenGL drivers, by which I mean few bugs, and wide support of current standards. Things have improved over time, but there are clearly still problems.

OpenGL 3.0 promises to clean up and slim down the specification, making it clearer and easier to develop and maintain a standards compliant implementation. I'm holding out hope that the change will help Apple out and the quality of their GL drivers will improve.

Speaking of OpenGL 3.0, I'm hoping that GLSL is being moved out of core, and/or that it's being replaced with something better, namely Cg; I'm tired of dealing with vendor-dependent GLSL bugs.

Cube Mapping

The GLSL mat3 constructor that is supposed to take a mat4 and slice out the upper 3x3 doesn't work on my MacBook Pro. Apparently I'm not the only one. http://emergencyexit.untergrund.net/2007/12/glsl/

As described in the above url, you can use the following instead:

mat3(matrix[0].xyz, matrix[1].xyz, matrix[2].xyz)

Sunday, March 16, 2008

CGImage Problems

I'm trying to use ImageIO to load Radiance HDR files, then draw the contents to a user-backed floating point context, but things are crashing. Once I figure out what's wrong, I'll post code.

Andrew.

Tuesday, March 11, 2008

OpenGL Demos

I've written an implementation of Preetham's "A Practical Analytic Model for Daylight", an ambient occlusion demo, a vertex buffer object demo, and a GLSL per-pixel lighting demo, I'll post them soon. Tomorrow I'm going to start on a reflection/refraction demo. I'll likely follow them up with a set of tutorials explaining them in some detail; I'd like to start doing more tutorials.

Saturday, March 8, 2008

New Macbook Pro

I'd had enough of OpenGL driver problems on my old mac, so today I went out and picked up a new one. I grabbed a new 2.5Ghz, which has an 8600GM 512M card, which should outpace my G4 17" by quite a bit. I'm eager to start using the new gesture controls in my programs.

Thursday, March 6, 2008

gl_NormalMatrix

I've run into a few driver problems under OS X

For comparison, here are my system specs:
Mac OS X Version 10.5.2
Processor: 1.5 GHz PowerPC G4
Memory 512 MB DDR SDRAM

gl_NormalMatrix is computed incorrectly on my mac.
The problem, and a temporary solution are listed below.
frag_Normal = gl_NormalMatrix * gl_Normal

frag_Normal = (gl_ModelViewMatrix * vec4(gl_Normal, 0.0)).xyz


Framebuffer objects must be powers of two.

More to come.

Wednesday, March 5, 2008

Revisiting Shadow Mapping

I'm revisiting my shadow mapping code, and I've hit a problem. A picture will do a better job of describing it than I can in words: