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;
}
Beispiel #3
0
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;
}