GLuint platformLoadTextureFile(string theFilename, bool generateMipmaps, int *width, int *height) { #ifdef QuickTimeInstalled GLuint textureName; // the "name" by which OpenGL knows the texture unsigned char *pImageBuffer; // the buffer that contains the image data GWorldPtr pGWorld; // a gworld to load the image into int imageDepth; FSSpec fsspecImage; // FSSpec of the image to load #ifdef __APPLE__ CFURLRef imageURL; FSRef imagefsRef; #endif OSStatus err = noErr; // err return value long rowStride; // length, in bytes, of a pixel row in the image GraphicsImportComponent giComp; // component for importing image MatrixRecord matrix; Rect rectImage; // rectangle of source image PixMapHandle hPixMap; // handle to image pix map ImageDescriptionHandle hImageDesc; // handle to image description used to get image depth long imageWidth; long imageHeight; float imageAspect; long textureWidth; long textureHeight; // get the full path to the texture file string fileLocation; fileLocation = pathToResourceDirectory() + theFilename; #ifdef __APPLE__ // create a URL to the file from the C string imageURL = CFURLCreateWithBytes (kCFAllocatorDefault, (UInt8 *)fileLocation.c_str(), fileLocation.length(), kCFStringEncodingASCII, NULL); if (imageURL == NULL) { cout << "error getting URL for image file (image file may not exist): " << theFilename << endl; return 0; } // get a FSRef from the URL if (!CFURLGetFSRef(imageURL, &imagefsRef)) { cout << "error getting FSRef for image file:: " << theFilename << endl; CFRelease(imageURL); return 0; } // get the FSSpec from the FSRef if (FSGetCatalogInfo (&imagefsRef, kFSCatInfoNone, NULL, NULL, &fsspecImage, NULL)) { cout << "error getting FSSpec for image file: " << theFilename << endl; CFRelease(imageURL); return 0; } // release the URL (not needed any more) CFRelease(imageURL); #endif #ifdef _WIN32 // get an FSSpec from the pathname if (NativePathNameToFSSpec ((char *)fileLocation.c_str(), &fsspecImage, kErrorIfFileNotFound)) { cout << "error getting FSSpec for image file: " << fileLocation << endl; return 0; } #endif // save the onscreen graphics port GDHandle origDevice; CGrafPtr origPort; GetGWorld (&origPort, &origDevice); // get an importer for the file err = GetGraphicsImporterForFileWithFlags (&fsspecImage, &giComp, kDontUseValidateToFindGraphicsImporter); if (err != noErr) return 0; // get the image bounds err = GraphicsImportGetNaturalBounds (giComp, &rectImage); if (err != noErr) return 0; // create a handle for the image description and lock it hImageDesc = (ImageDescriptionHandle) NewHandle (sizeof (ImageDescriptionHandle)); HLock ((Handle) hImageDesc); // retrieve the image description err = GraphicsImportGetImageDescription (giComp, &hImageDesc); if (err != noErr) return 0; // find width and height imageWidth = (int) (rectImage.right - rectImage.left); imageHeight = (int) (rectImage.bottom - rectImage.top); // now calculate the aspect ratio (width/height), used to restore image correctly imageAspect = ((float) imageWidth) / ((float) imageHeight); // get the image's pixel depth imageDepth = (**hImageDesc).depth; // find nearest acceptable texture size (width and height) for the image textureWidth = GetTextureDimFromImageDim (imageWidth); textureHeight = GetTextureDimFromImageDim (imageHeight); // pass the optimised (and scaled) size back out to the caller *width = textureWidth; *height = textureHeight; // set texture rectangle for creation of GWorld #ifdef __APPLE__ SetRect (&rectImage, 0, 0, (int) textureWidth, (int) textureHeight); #endif #ifdef _WIN32 MacSetRect (&rectImage, 0, 0, (int) textureWidth, (int) textureHeight); #endif // set stride in bytes width of image * 4 bytes per pixel rowStride = textureWidth * 4; // build new buffer exact size of image (stride * height) pImageBuffer = (unsigned char *) NewPtr (rowStride * textureHeight); // check we got the buffer we wanted if (pImageBuffer == NULL) { // failed - release the component and return an error CloseComponent(giComp); return 0; } // create a new gworld using our unpadded buffer, setting the pixel type correctly for the expected image depth #ifdef __BIG_ENDIAN__ QTNewGWorldFromPtr (&(pGWorld), k32ARGBPixelFormat, &rectImage, NULL, NULL, 0, pImageBuffer, rowStride); #else QTNewGWorldFromPtr (&(pGWorld), k32RGBAPixelFormat, &rectImage, NULL, NULL, 0, pImageBuffer, rowStride); #endif // could we allocate the GWorld? if (pGWorld == NULL) { // failed - release the buffer, component and return an error DisposePtr ((Ptr) pImageBuffer); CloseComponent(giComp); return 0; } // build a transformation matrix to scale the image to the texture size // this also flips the image horizontally, so that texture coordinates map correctly float horizontalScale = (float) textureWidth / (float) imageWidth; float verticalScale = (float) textureHeight / (float) imageHeight; SetIdentityMatrix (&matrix); ScaleMatrix (&matrix, X2Fix(horizontalScale), X2Fix(-verticalScale), 0, 0); TranslateMatrix (&matrix, 0, X2Fix((float)textureHeight)); // set the matrix as the importer matrix err = GraphicsImportSetMatrix(giComp, &matrix); // set the destination of the importer component if (err == noErr) err = GraphicsImportSetGWorld (giComp, pGWorld, NULL); // ensure lossless decompression (if the CODEC supports this) if (err == noErr) err = GraphicsImportSetQuality(giComp, codecLosslessQuality); if (err != noErr) { // failed - release the GWorld, buffer, component and return an error DisposeGWorld (pGWorld); DisposePtr ((Ptr) pImageBuffer); CloseComponent(giComp); return 0; } // get the address of the GWorld's pixmap hPixMap = GetGWorldPixMap (pGWorld); // if everything looks good draw the image to the locked pixmap if ((hPixMap) && (LockPixels (hPixMap))) GraphicsImportDraw (giComp); else { // the pixmap doesn't exist, or we couldn't lock it // release the GWorld, buffer, component and return an error DisposeGWorld (pGWorld); DisposePtr ((Ptr) pImageBuffer); CloseComponent(giComp); return 0; } // for images without an alpha channel, initialise the alpha bytes since QuickTime won't if (imageDepth < 32) { #ifdef __BIG_ENDIAN__ for( unsigned char *p = pImageBuffer; p < pImageBuffer + (rowStride * textureHeight); p+=4) *p = 0xFF; #else for( unsigned char *p = pImageBuffer+3; p < pImageBuffer + (rowStride * textureHeight) +3; p+=4) *p = 0xFF; #endif } // unlock the pixmap UnlockPixels (hPixMap); // dump the component CloseComponent(giComp); // set image width in groups (pixels), accounts for border this ensures proper image alignment row to row glPixelStorei (GL_UNPACK_ROW_LENGTH, textureWidth); // generate a "name" for the texture glGenTextures (1, &textureName); // create the texture in OpenGL glBindTexture(GL_TEXTURE_2D, textureName); // tell OpenGL about the texture and have GLU build mipmaps #ifdef __BIG_ENDIAN__ glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pImageBuffer); #else glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pImageBuffer); #endif if (generateMipmaps) #ifdef __BIG_ENDIAN__ if (gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, textureWidth, textureHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pImageBuffer) != 0) #else if (gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE, pImageBuffer) != 0) #endif // good time to check for errors? openGLCheckError(); // finished with the GWorld but not the image buffer (it's used by OpenGL as the "live" image buffer) DisposeGWorld (pGWorld); // restore the current graphics port we saved earlier SetGWorld(origPort, origDevice); // all done - return the texture name return textureName; #endif // QuickTimeInstalled }
void DisplayJPEGAndDisposeHandle( Handle imageData ) { OSErr err; Rect naturalBounds; MatrixRecord matrix; SInt32 gapH, gapV; Fixed scaleH, scaleV; Rect boundsRect; GraphicsImportComponent grip; Rect windowPortRect; static char gifSentinel[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; static char jpegSentinel[] = {0xFF,0xD9,0xFF,0xD9,0xFF,0xD9,0xFF,0xD9,0xFF,0xD9,0xFF,0xD9,0xFF,0xD9,0xFF,0xD9}; Ptr sentinel; Size sentinelSize; if( !imageData ) { ofLogNotice() << "NO IMAGE DATA" << endl; } else { ofImage image; //ofPixels pixels(); //pixels = imageData; //image.setFromPixels((const unsigned char *)imageData); //string image //image.saveImage(ofToDataPath(ofGetTimestampString()+".jpg", OF_IMAGE_QUALITY_BEST)); ofLogError() << "WE HAVE DATA!" << endl; } return; again: ofLogError() << "Again called"; if( 'G' == **imageData ) { grip = gripG; // for GIF: // FF FF FF FF will ensure that the bit parser aborts, since you can't // have two consecutive all-ones symbols in the LZW codestream -- // you can sometimes have one (say, a 9-bit code), but after consuming // it the code width increases (so we're now using 10-bit codes) // and the all-ones code won't be valid for a while yet. sentinel = gifSentinel; sentinelSize = sizeof(gifSentinel); } else { grip = gripJ; // for JPEG: // FF D9 FF D9 will ensure (a) that the bit-parser aborts, since FF D9 // is an "unstuffed" FF and hence illegal in the entropy-coded datastream, // and (b) be long enough to stop overreads. sentinel = jpegSentinel; sentinelSize = sizeof(jpegSentinel); } //•• add sentinel pattern to the end of the handle. err = PtrAndHand( sentinel, imageData, sentinelSize ); err = GraphicsImportSetDataHandle( grip, imageData ); if( err ) { ofLogNotice() << "GraphicsImportSetDataHandle Error" << endl; goto bail; } err = GraphicsImportGetNaturalBounds( grip, &naturalBounds ); if( err ) { ofLogNotice() << "GraphicsImportGetNaturalBounds Error" << endl; goto bail; } //GetPortBounds( GetWindowPort( window ), &windowPortRect ); gapH = windowPortRect.right - naturalBounds.right; gapV = windowPortRect.bottom - naturalBounds.bottom; if( gapH >= 0 ) { gapH = ((UInt16)Random()) % gapH; scaleH = fixed1; } else { gapH = 0; scaleH = FixDiv( windowPortRect.right, naturalBounds.right ); } if( gapV >= 0 ) { gapV = ((UInt16)Random()) % gapV; scaleV = fixed1; } else { gapV = 0; scaleV = FixDiv( windowPortRect.bottom, naturalBounds.bottom ); } // need to use smaller scale of the two, and then recalc the other gap. if( scaleH > scaleV ) { scaleH = scaleV; gapH = windowPortRect.right - FixMul(scaleH, naturalBounds.right); gapH = ((UInt16)Random()) % gapH; } else if( scaleH < scaleV ) { scaleV = scaleH; gapV = windowPortRect.bottom - FixMul(scaleV, naturalBounds.bottom); gapV = ((UInt16)Random()) % gapV; } SetIdentityMatrix( &matrix ); ScaleMatrix( &matrix, scaleH, scaleV, 0, 0 ); TranslateMatrix( &matrix, gapH<<16, gapV<<16 ); err = GraphicsImportSetMatrix( grip, &matrix ); if( err ) goto bail; err = GraphicsImportDraw( grip ); if( err ) goto bail; err = GraphicsImportGetBoundsRect( grip, &boundsRect ); if( err ) goto bail; InsetRect( &boundsRect, -1, -1 ); //SetPortWindowPort( window ); FrameRect( &boundsRect ); if( scanForAnotherImageMarker(imageData)) { ofLogError() << "again: scanForAnotherImageMarker" << endl; goto again; } bail: DisposeHandle( imageData ); //gDrewJPEG = true; }
GWorldPtr OpenImage (void) { unsigned long rowStride; GraphicsImportComponent giComp; NavReplyRecord replyNav; NavTypeListHandle hTypeList = (NavTypeListHandle) NewHandleClear (sizeof (NavTypeList) + sizeof (OSType) * 13); FSSpec fsspecImage; AEKeyword theKeyword; DescType actualType; Size actualSize; OSStatus err = noErr; Rect rectImage; GDHandle origDevice; CGrafPtr origPort; PixMapHandle hPixMap; ImageDescriptionHandle hImageDesc; MatrixRecord matrix; GWorldPtr pGWorld; unsigned char * pImageBuffer; long imageWidth; long imageHeight; float imageAspect; long imageDepth; long textureWidth; long textureHeight; GetGWorld (&origPort, &origDevice); // save onscreen graphics port HLock ((Handle) hTypeList); (**hTypeList).osTypeCount = 14; (**hTypeList).osType[0] = 'qtif'; (**hTypeList).osType[1] = 'SGI '; (**hTypeList).osType[2] = '8BPS'; (**hTypeList).osType[3] = 'GIF '; (**hTypeList).osType[4] = 'GIFf'; (**hTypeList).osType[5] = 'JPEG'; (**hTypeList).osType[6] = 'JPG '; (**hTypeList).osType[7] = 'PICT'; (**hTypeList).osType[8] = 'PNTG'; (**hTypeList).osType[9] = 'grip'; (**hTypeList).osType[10] = 'BMPp'; (**hTypeList).osType[11] = 'TIFF'; (**hTypeList).osType[12] = 'TEXT'; (**hTypeList).osType[13] = '????'; err = NavChooseFile (NULL, &replyNav, NULL, NULL, NULL, NULL, hTypeList, NULL); if ((err == noErr) && (replyNav.validRecord)) err = AEGetNthPtr (&(replyNav.selection), 1, typeFSS, &theKeyword, &actualType, &fsspecImage, sizeof (fsspecImage), &actualSize); NavDisposeReply (&replyNav); if (err != noErr) return NULL; GetGraphicsImporterForFile (&fsspecImage, &giComp); if (err != noErr) return NULL; // create GWorld err = GraphicsImportGetNaturalBounds (giComp, &rectImage); if (err != noErr) return NULL; hImageDesc = (ImageDescriptionHandle) NewHandle (sizeof (ImageDescriptionHandle)); HLock ((Handle) hImageDesc); err = GraphicsImportGetImageDescription (giComp, &hImageDesc); if (err != noErr) return NULL; imageWidth = rectImage.right - rectImage.left; imageHeight = rectImage.bottom - rectImage.top; imageAspect = ((float) imageWidth) / ((float) imageHeight); imageDepth = (**hImageDesc).depth; // bits if (imageDepth <= 16) imageDepth = 16; else imageDepth = 32; #if 1 textureWidth = imageWidth;//40;//imageWidth;//256; textureHeight = imageHeight;//40 * imageHeight / imageWidth;//imageHeight;//256; #else textureWidth = imageWidth;//256; textureHeight = imageHeight;//256; #endif SetRect (&rectImage, 0, 0, textureWidth, textureHeight); // l, t, r. b reset to texture rectangle rowStride = textureWidth * imageDepth / 8; pImageBuffer = (unsigned char *) NewPtrClear (rowStride * (textureHeight)); if (imageDepth == 32) QTNewGWorldFromPtr (&(pGWorld), k32ARGBPixelFormat, &rectImage, NULL, NULL, 0, pImageBuffer, rowStride); else QTNewGWorldFromPtr (&(pGWorld), k16BE555PixelFormat, &rectImage, NULL, NULL, 0, pImageBuffer, rowStride); if (NULL == pGWorld) return NULL; // decompress to gworld SetIdentityMatrix (&matrix); ScaleMatrix (&matrix, X2Fix ((float) textureWidth / (float) imageWidth), X2Fix ((float) textureHeight / (float) imageHeight), X2Fix (0.0), X2Fix (0.0)); err = GraphicsImportSetMatrix(giComp, &matrix); if (err != noErr) return NULL; err = GraphicsImportSetGWorld (giComp, pGWorld, NULL); if (err != noErr) return NULL; err = GraphicsImportSetQuality(giComp, codecLosslessQuality); if (err != noErr) return NULL; hPixMap = GetGWorldPixMap (pGWorld); if ((hPixMap) && (LockPixels (hPixMap))) // lock offscreen pixel map GraphicsImportDraw (giComp); else return NULL; // modify alpha if ( imageDepth == 32 ) { unsigned long i; unsigned long * pixel = (unsigned long *)GetPixBaseAddr( hPixMap ); for (i = 0; i < textureWidth * textureHeight; i++) { if ((*pixel & 0x00FFFFFF) == 0x00FF00) // mask only color bits and look for green *pixel = 0x00000000;//0x00303040; // replace green with dark gray transparent (to help filtering) else *pixel |= 0xFF000000; // ensure alpha is set for opaque pixels pixel++; } } else { unsigned short i; unsigned short * pixel = (unsigned short *)GetPixBaseAddr( hPixMap ); for (i = 0; i < textureWidth * textureHeight; i++) { if ((*pixel & 0x7FFF) == 0x03E0) // mask only color bits and look for green *pixel = 0x0000;//0x0363; // replace green with dark gray transparent (to help filtering) else *pixel |= 0x8000; // ensure alpha is set for opaque pixels pixel++; } } return pGWorld; }