PDA

View Full Version : Need a bit of porting help


Lindley
2005.05.02, 04:36 PM
Hi, I'm a long-time Mac user, and I've been a CS student for many years.....but I haven't actually done much programming on Macs before, so I need some help.

The final project for my Computer Graphics class was to write a roller coaster program in OpenGL. I wrote it entirely on school Linux machines, however; I'm now trying to get it to work on my TiBook under 10.3 with as few changes to the actual code as possible.

The project used GLUT, and for textures, it used something called libpicio, which is a simplified interface to libtiff.

Currently, I have managed to get it to run correctly as a command-line X11 app. However, I'd like it convert it into a standalone app with an actual interface, if that's possible without too much work. (The project is over, this port is just for the hell of it.)

What I've done so far is used fink to install libtiff and libglut, and simply compiled using Make. I'd like to figure out how to make it work in Xcode.

First, what type of Xcode project should I use? None of them seems ideally suited to what I want. The roller coaster program is written in C. Would making it a Cocoa application still allow me to use GLUT for windowing, etc, or would I have to change that? For the most part it would probably be an easy change, as long as there's an equivalent to glutSolidTorus.

Second, as of now, I'm getting "_jpeg_std_error" undeclared symbol errors when I run. This didn't happen when compiling with make, so I'm not sure what's going on. Anyone have any ideas?
If not, could you suggest an alternative simple image-reading library? All I really need to do is read in textures in a format acceptable to glTexImage2D.

Thanks in advance!

Malarkey
2005.05.02, 05:08 PM
First, what type of Xcode project should I use? None of them seems ideally suited to what I want. The roller coaster program is written in C. Would making it a Cocoa application still allow me to use GLUT for windowing, etc, or would I have to change that? For the most part it would probably be an easy change, as long as there's an equivalent to glutSolidTorus.


You can use Cocoa to handle all the UI stuff easily. Check out OSC's XCode/GLUT tutorial.

igame3d
2005.05.02, 05:15 PM
you'll find that Tutorial
Here (http://onesadcookie.is-a-geek.net/cgi-bin/blosxom.cgi)

Lindley
2005.05.02, 05:46 PM
That tutorial cleared the GLUT issues right up, but I'm still getting errors from the image-reading routines. Any suggestions on that?

Malarkey
2005.05.02, 06:03 PM
you'll find that Tutorial
Here (http://onesadcookie.is-a-geek.net/cgi-bin/blosxom.cgi)

Doh! And you know, I had that URL in my copy/paste buffer too... Anyway, I can't help out with the jpeg thing since I usually use libpng and glpng (http://www.wyatt100.freeserve.co.uk/download.htm) to do my stuff. Maybe you're not linking in the jpeg libraries correctly.

Puzzler183
2005.05.02, 06:22 PM
That tutorial cleared the GLUT issues right up, but I'm still getting errors from the image-reading routines. Any suggestions on that?

I suspect you have endianness problems. Do 24 bit images look like red and blue are switched? If so, you have endianness problems. 32 bit images will also look odd if you have endianness issues.

Lindley
2005.05.02, 07:17 PM
It could very well be an endian problem, but that's not all of it. I can't load images into memory at all.

I also have a small library someone wrote which is designed to read bmp images, but that hasn't worked either.....that may be an endianness issue, since it seems to be reading the image dimensions incorrectly right off the bat.

Lindley
2005.05.02, 11:34 PM
All right, let me state exactly what I'm looking for right now:

-A known-to-work method of reading images (any format) into memory in such a way that they're immediately passable to glTexImg2D.

I really don't care what format my textures are in, I just want a way to read them. Apple's help files don't seem terribly useful in this regard.

Regarding libpng and glpng above----anything special to using those, or is it straightforward?

DoG
2005.05.03, 07:37 AM
All right, let me state exactly what I'm looking for right now:

-A known-to-work method of reading images (any format) into memory in such a way that they're immediately passable to glTexImg2D.

I really don't care what format my textures are in, I just want a way to read them. Apple's help files don't seem terribly useful in this regard.

Regarding libpng and glpng above----anything special to using those, or is it straightforward?
The obvious way to read images on the Mac would be by using QuickTime. OSC's fabulous QT tutorial should show you all you need to know.

Lindley
2005.05.03, 09:59 AM
Do'h! Hadn't considered that.

...But, off hand, I can't find this QT tutorial of which you speak at the link above. Some sample code which may be helpful, but no tutorial.

sealfin
2005.05.03, 02:17 PM
I believe this is the tutorial of which DoG speaks: here (http://onesadcookie.is-a-geek.net/svn/repos/QTValuePak/).

Lindley
2005.05.03, 04:43 PM
All right. I can use that....but it looks needlessly complicated.

Surely someone has written a wrapper class such that I can just do something akin to
pic = jpeg_read(filename); ?

Anyway, before I go changing all my code around to work through Quicktime, here's a different question:

The makefile which I currently have *will* compile correctly (for X11). I get linker errors when compiling in XCode. Clearly, something is different.

XCode claims that it uses gcc to compile....is there a way for me to see exactly what is being passed to gcc, so I can figure out what it's not sending?

phydeaux
2005.05.03, 05:02 PM
http://openil.sourceforge.net/
This is the cross-platform lib I always use for image loading. It's about this easy:


ilInit( );

ILuint imgId;
ilGenImages( 1, &imgId );

ilBindImage( imgId );

ilLoadL( IL_TYPE_UNKNOWN, ( ILvoid * ) resource->getBuffer( ), resource->getSize( ) );

ilConvertImage( IL_BGRA, IL_UNSIGNED_BYTE );

int width = ilGetInteger( IL_IMAGE_WIDTH );
int height = ilGetInteger( IL_IMAGE_HEIGHT );


unsigned int* buffer = (unsigned int *) ilGetData( );


Then you can use buffer as an argument to BGRA data (you could use RGBA if you want that too, or whatever.)

Lindley
2005.05.03, 05:21 PM
Looks great in theory, but Stuffit Expander is getting write permissions errors trying to deal with the .tar....

Malarkey
2005.05.03, 05:25 PM
XCode claims that it uses gcc to compile....is there a way for me to see exactly what is being passed to gcc, so I can figure out what it's not sending?

Build menu -> Detailed Build Results. The panel that contains all the raw compiler output is in a window pane that is completely closed so you'll have to drag it open (look for the two vertical dots in the middle of the window). If you want to adjust the compile options/flags/what have you, do a Get Info on the project file itself.

Puzzler183
2005.05.03, 06:45 PM
I should point out that SDL image works great, and fits with the rest of the SDL framework (which makes porting applications ridiculously easy).

Duane
2005.05.03, 07:09 PM
I should point out that SDL image works great, and fits with the rest of the SDL framework (which makes porting applications ridiculously easy).
I'm with him...
couldn't you simply export all the textures to other formats, then load them through your own code, or libjpg/libpng?

Lindley
2005.05.03, 08:59 PM
I'll try SDL. I've looked into just about everything else, and each one is either too complicated for my needs (libgd doesn't even give an image reading example, just writing!) or won't work for some other reason.

My current problem: fopen is failing for no good reason, when it worked just before that on another file. Apparently fopen can handle text files, but not jpegs......

This is vaguely ridiculous. It should not be so difficult to figure out how to load image files.

Puzzler183
2005.05.03, 09:04 PM
Uh, for fopen, are you doing: FILE *myFile = fopen("file", "rb"); and not just "r"? Binary reading is important if you plan to use binary files. See http://www.cplusplus.com/ref/cstdio/fopen.html for details.

Anyhow, SDL is really easy and you can use it for windowing, input and maybe sound (although the SDL_mixer extension or FMOD are both nicer). Then you get the SDL_image extension which reads images really easily..

Lindley
2005.05.03, 09:20 PM
Not quite. The actual failure is in jpeg_read (in jpeg.c):

if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
return 0;
}

This works perfectly when I compile it for X11 using my Makefile. This fails when I compile it for Cocoa using Xcode. Frustrating as hell.

Lindley
2005.05.03, 09:46 PM
Now I'm getting a linker warning claiming the directory containing the project does not exist!

I'm starting to suspect Xcode is not entirely bug-free....

Lindley
2005.05.03, 11:15 PM
You know what? Screw it. Thanks to everyone who tried to help. The program works under X11, and that's going to have to be good enough, I guess. It's just not worth the hassel of figuring out what's going wrong.

OneSadCookie
2005.05.03, 11:32 PM
Remember, you have no guarantees what your current working directory is when your application is run. You should always make sure to set it to a known place before using relative paths to load files.

Lindley
2005.05.04, 12:34 AM
Remember, you have no guarantees what your current working directory is when your application is run. You should always make sure to set it to a known place before using relative paths to load files.

Normally I'd agree, but there are other files in the same directory which are being loaded correctly. Only the texture files are failing.

EDIT: I think I solved it. I moved the readTextures() call before any of the glut function calls. For some strange reason, that seems to have worked.

I'm not complaining, though.....

OneSadCookie
2005.05.04, 12:41 AM
glut changes the working directory to the Resources folder within your application's bundle for you. This is normally a good thing :)

I think you'll find that if moving the readTextures() before your glut call worked, that your app won't work if double-clicked in the finder.

And of course, be careful not to make any OpenGL calls before glutCreateWindow, or you'll crash.

Lindley
2005.05.04, 01:18 AM
So, should I just use absolute paths, or somehow put the textures inside the .app, or what? How do I make the app work as a standalone?

FCCovett
2005.05.04, 01:18 AM
With C and Carbon:


void LoadGLTextureFrom_PNG_CGImageURL( CFURLRef currURL_ref, TextureImageRef texImage_ref )
{
//----------------------------------------------------------------------
// Variables:

CGDataProviderRef dataProvider_ref;
CGImageRef image_ref;

//----------------------------------------------------------------------
// Create a CFDataProviderRef and a CGImageRef to hold the PNG image data:

dataProvider_ref = CGDataProviderCreateWithURL( currURL_ref );
image_ref = CGImageCreateWithPNGDataProvider( dataProvider_ref, NULL, FALSE, kCGRenderingIntentDefault );

//----------------------------------------------------------------------
// Load the texture from the CGImage:

LoadGLTextureFromCGImage( image_ref, texImage_ref );

//----------------------------------------------------------------------
// Release the CGDataProvider and the CGImageRef:

CGDataProviderRelease( dataProvider_ref );
dataProvider_ref = NULL;

CFRelease( image_ref );
image_ref = NULL;
}



void LoadGLTextureFromCGImage( CGImageRef image_ref, TextureImageRef texImage_ref )
{
//----------------------------------------------------------------------
// Get image data for OpenGL texture (images should be at least 16 X 16 pxl, up to 256 X 256 pxl for best results):

CGContextRef context_ref = NULL;
CGColorSpaceRef colorspace_ref;
CGImageAlphaInfo alpha_info;

CGSize image_size;
size_t image_depth;
size_t buffer_rowbytes;
int bitmap_byteCount;
GLubyte *data_buffer;

//----------------------------------------------------------------------
// Get original image's size and bit depth:

image_size = CGSizeMake( CGImageGetWidth( image_ref ), CGImageGetHeight( image_ref ) );
image_depth = CGImageGetBitsPerPixel( image_ref );

//----------------------------------------------------------------------
// Determine the size of the CGContext bitmap buffer (RGBA_32):

//buffer_rowbytes = CGImageGetBytesPerRow( image_ref );
//printf( "1) %s : W = %.2f, H = %.2f, R = %d \n", texImage_ref->name, image_size.width, image_size.height, (int) buffer_rowbytes );

buffer_rowbytes = (size_t) ( ( ( image_size.width * 32 ) + 7 ) / 8 ); // Do not use CGImageGetBytesPerRow( image_ref ); // (((width)*(bits per component)*(number of components per pixel))+7)/8;
bitmap_byteCount = buffer_rowbytes * image_size.height;

//printf( "2) %s : W = %.2f, H = %.2f, R = %d \n\n", texImage_ref->name, image_size.width, image_size.height, (int) buffer_rowbytes );

//----------------------------------------------------------------------
// Allocate memory block for bitmap buffer:

data_buffer = (GLubyte *) calloc( bitmap_byteCount, sizeof( GLubyte ) );

if ( data_buffer == NULL )
{
FatalAlert( "Error on LoadGLTextureFromCGImage(): Not enough memory to allocate for data_buffer.\n", -1 );
}
else
{
//----------------------------------------------------------------------
// Create bitmap graphics colorspace (Monitor == RGB):

colorspace_ref = CGColorSpaceCreateDeviceRGB();

if ( !colorspace_ref )
{
FatalAlert( "Error on LoadGLTextureFromCGImage(): Could not create CGColorSpace.\n", -1 );
}

//----------------------------------------------------------------------
// Specify the context's alpha info (RGBA_32 or RGBX_32):

alpha_info = ( image_depth > 24 ) ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast; //kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast;

//----------------------------------------------------------------------
// Create bitmap graphics context:

context_ref = CGBitmapContextCreate( data_buffer, (size_t) image_size.width, (size_t) image_size.height, ( 8 ), buffer_rowbytes, colorspace_ref, alpha_info );

if ( context_ref )
{
CGContextSetFillColorSpace( context_ref, colorspace_ref );
CGContextSetStrokeColorSpace( context_ref, colorspace_ref );
CGContextTranslateCTM( context_ref, 0.0, image_size.height );
CGContextScaleCTM( context_ref, 1.0, -1.0);
}
else
{
FatalAlert( "Error on LoadGLTextureFromCGImage(): Could not create CGContext.\n", -1 );
}

//CGContextSetRenderingIntent( context_ref, kCGRenderingIntentPerceptual ); crashes on Panther.

CGColorSpaceRelease( colorspace_ref );
colorspace_ref = NULL;

//----------------------------------------------------------------------
// Draw the image into the bitmap graphics context:

CGRect picRect;

picRect = CGRectMake( 0.0f, 0.0f, image_size.width, image_size.height );

CGContextClearRect( context_ref, picRect );
//CGContextSetRGBFillColor( context_ref, 0.0f, 0.0f, 0.0f, 0.0f );
//CGContextFillRect( context_ref, picRect );

CGContextDrawImage( context_ref, picRect, image_ref );

//----------------------------------------------------------------------
// Create OpenGL texture from the bitmap data:

texImage_ref->bpp = (GLuint) 32; // image_depth;
texImage_ref->width = (GLuint) image_size.width;
texImage_ref->height = (GLuint) image_size.height;

//printf( "Texture: %s, bpp: %d, width: %d, height: %d\n", texImage_ref->name, (int) image_depth, (int) image_size.width, (int) image_size.height );

//----------------------------------------------------------------------
// Generate OpenGL texture (it returns texID):

CreateGLTexture( texImage_ref, data_buffer );

//----------------------------------------------------------------------
// Release data_buffer, context_ref:

CGContextRelease( context_ref );
context_ref = NULL;

free( data_buffer );
data_buffer = NULL;
}
}

wadesworld
2005.05.04, 01:41 AM
No offense, but the problem here is not bugs in XCode.

The problem is you don't understand enough about what you're doing. fopen() does not start randomly failing for no reason.

So, should I just use absolute paths, or somehow put the textures inside the .app, or what? How do I make the app work as a standalone?

You should read and understand the bundle functions (NSBundle for Cocoa or CFBundle for Carbon) and use those to find the location of your main bundle. From there, you can find the Resources folder in your bundle or anything else.

Malarkey
2005.05.04, 01:58 AM
So, should I just use absolute paths, or somehow put the textures inside the .app, or what? How do I make the app work as a standalone?

I think (someone correct me on this) that if you add your textures to the project and group them in a folder called "Resources", XCode will copy them into the .app (which is really a directory) it creates for you. Then you can get the main bundle and from that, get the path to your resources directory.

Lindley
2005.05.04, 02:29 AM
No offense, but the problem here is not bugs in XCode.

The problem is you don't understand enough about what you're doing. fopen() does not start randomly failing for no reason.


I know, but it certainly seemed that way for a while. How was I know that that Apple's version of GLUT did something different than libglut (the version I had been working with before)? It's supposed to be seamlessly cross-platform.

As I said at the start, long-time programmer, long time Mac user, but almost never both at the same time. Most of the actual programming I've done has been on other systems.

Besides which, this past semester was the first time I've taken a Computer Graphics course. Before now I haven't had to worry about reading in images. And the course provided a simple-to-use interface for reading based only on filename, so I just assumed (stupidly, I suppose) that there was no more to it than that.


You should read and understand the bundle functions (NSBundle for Cocoa or CFBundle for Carbon) and use those to find the location of your main bundle. From there, you can find the Resources folder in your bundle or anything else.

I'll look into it. I haven't done much with that sort of stuff so far.

Does this apply to all files read in by the program?

FCCovett
2005.05.04, 09:24 PM
You can read files with fopen, but it's convenient to convert file paths to CFURLRefs and use those instead. Also, you can open the application's bundle and get the CFURLs to all .jpg files stored on a certain folder, for example.


void LoadMainBundleResources()
{
//----------------------------------------------------------------------
// Get the main bundle for the app:

//CFBundleRef gMainBundle_ref;

gMainBundle_ref = CFBundleGetMainBundle();

//----------------------------------------------------------------------
// Look for the bundle’s version number:

UInt32 bundleVersion;

bundleVersion = CFBundleGetVersionNumber( gMainBundle_ref );

//----------------------------------------------------------------------
// Check the bundle version for compatibility with our app:

if ( bundleVersion < kMyBundleVersion1 )
{
FatalAlert( "Error on LoadMainBundleResources(): CFBundleGetVersionNumber() bundle version too old", -1 );
}

//----------------------------------------------------------------------

RetrieveMainBundleInfo();
}

//----------------------------------------------------------------------

void RetrieveMainBundleInfo()
{
//----------------------------------------------------------------------
// Retrieving info from the bundle (get an instance of the info.plist):
// Use CFBundleCopyInfoDictionaryInDirectory() if you don't want to open the bundle:

CFDictionaryRef bundleInfo_CFDictionaryRef;

bundleInfo_CFDictionaryRef = CFBundleGetInfoDictionary( gMainBundle_ref );

//----------------------------------------------------------------------
// If we succeeded, look for our property:

if ( bundleInfo_CFDictionaryRef != NULL )
{
CFStringRef applicationID_CFStringRef;

applicationID_CFStringRef = CFDictionaryGetValue( bundleInfo_CFDictionaryRef, CFSTR( "CFBundleIdentifier" ) );

// CFRelease( bundleInfo_CFDictionaryRef ); if you release this from memory before you open windows and stuff, the app will crash then.
// Only release CF Objects that you own, i.e. you've created with a function that has Create or Copy in its name.

CFShow( applicationID_CFStringRef ); // Debug tool;
}
}

//----------------------------------------------------------------------

void ReleaseMainBundleResources()
{
//----------------------------------------------------------------------
// Always remember to release any CF Objects created/copied or returned as a value by a function:

CFRelease( gMainBundle_ref );
gMainBundle_ref = NULL;
}




void LoadOneGLTextureFromBundle( CFBundleRef bundle_ref, CFStringRef fileName, CFStringRef fileExtension, CFStringRef subDirName, TextureImageRef texture_ref )
{
//----------------------------------------------------------------------
// Variables:

Boolean didLoad;
CFURLRef url_ref;

//----------------------------------------------------------------------
// Get the URL for that file:

url_ref = CFBundleCopyResourceURL( bundle_ref, fileName, fileExtension, subDirName );

//theURLs[0] = CFBundleCopyResourceURLsOfType( bundle_ref, CFSTR( "jpg" ), subDirName );

//----------------------------------------------------------------------

if ( url_ref == NULL )
{
FatalAlert( "Error on LoadOneGLTextureFromBundle(): CFBundleCopyResourceURL() file doesn't exist.", -1 );
}

//----------------------------------------------------------------------
// Display the file path for the current URL (debug):

didLoad = CFURLGetFileSystemRepresentation( url_ref, TRUE, texture_ref->filePath, 256 );

if ( didLoad )
{
//printf( "\nTexture file path: %s \n", (char *) texture_ref->filePath );
}

//----------------------------------------------------------------------
// Set texture's name:

ConvertCFStringtoCString( fileName, texture_ref->name, 256 );

//----------------------------------------------------------------------
// Create a texture from the URL:

if ( kCFNotFound != ( CFStringFind( fileExtension, CFSTR( "jpg" ), kCFCompareCaseInsensitive ) ).location )
{
LoadGLTextureFrom_JPG_CGImageURL( url_ref, texture_ref );
}
else if ( kCFNotFound != ( CFStringFind( fileExtension, CFSTR( "png" ), kCFCompareCaseInsensitive ) ).location )
{
LoadGLTextureFrom_PNG_CGImageURL( url_ref, texture_ref );
}
else if ( kCFNotFound != ( CFStringFind( fileExtension, CFSTR( "tga" ), kCFCompareCaseInsensitive ) ).location )
{
LoadGLTextureFrom_TGA_CFDataURL( url_ref, texture_ref );
}

//----------------------------------------------------------------------
// Release the URL:

CFRelease( url_ref );
url_ref = NULL;
}