From ad6a1665ccfdbd5dbd74a524db0932030a8b9e68 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 16 Jan 2002 10:41:55 +0000 Subject: [PATCH] Added quicktime plugin (for Mac's only), submitted by Phil Atkin. --- src/osgPlugins/quicktime/Makedepend | 0 src/osgPlugins/quicktime/Makefile | 27 ++ src/osgPlugins/quicktime/QTtexture.c | 385 ++++++++++++++++++++ src/osgPlugins/quicktime/ReaderWriterQT.cpp | 173 +++++++++ 4 files changed, 585 insertions(+) create mode 100644 src/osgPlugins/quicktime/Makedepend create mode 100644 src/osgPlugins/quicktime/Makefile create mode 100644 src/osgPlugins/quicktime/QTtexture.c create mode 100644 src/osgPlugins/quicktime/ReaderWriterQT.cpp diff --git a/src/osgPlugins/quicktime/Makedepend b/src/osgPlugins/quicktime/Makedepend new file mode 100644 index 000000000..e69de29bb diff --git a/src/osgPlugins/quicktime/Makefile b/src/osgPlugins/quicktime/Makefile new file mode 100644 index 000000000..6e200fc9b --- /dev/null +++ b/src/osgPlugins/quicktime/Makefile @@ -0,0 +1,27 @@ +#!smake +include ../../../Make/makedefs + +C++FILES = \ + ReaderWriterQT.cpp\ + +CFILES = \ + QTtexture.c\ + +TARGET_BASENAME = osgdb_qt + +TARGET_LIB_FILES = lib$(TARGET_BASENAME).$(DL_EXT) + +LOADABLE = $(OSGHOME)/lib/osgPlugins/$(TARGET_BASENAME).$(DL_EXT) +LIB= + +TARGET_LOADER_FILES = osgPlugins/$(TARGET_BASENAME).$(DL_EXT) + +LIBS = $(GL_LIBS) -losg -losgDB +MACOSXLIBS = -framework QuickTime -L../../../lib -losg -losgUtil -losgDB -ldl -lm -lstdc++ + + +C++FLAGS += -I. -I$(OSGHOME)/include +LDFLAGS += -L$(OSGHOME)/lib + +include $(OSGHOME)/Make/makerules + diff --git a/src/osgPlugins/quicktime/QTtexture.c b/src/osgPlugins/quicktime/QTtexture.c new file mode 100644 index 000000000..82b874787 --- /dev/null +++ b/src/osgPlugins/quicktime/QTtexture.c @@ -0,0 +1,385 @@ +/* + * QTtexture.c + * Cocoa rostrumMIP + + * + * Created by philatki on Thu Nov 29 2001. + * Copyright (c) 2001 __MyCompanyName__. All rights reserved. + * + */ + +/* +PORTIONS OF THIS CODE ARE COPYRIGHT APPLE COMPUTER - + + Copyright: Copyright © 2001 Apple Computer, Inc., All Rights Reserved + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include + +#include // for image loading and decompression +#include // for file type support + +#include // for OpenGL API +#include // for OpenGL API +#include // for OpenGL extension support + +// ================================== + +enum // how to scale image to power of two on read if scaling +{ + kNone = 1, + kNearest, // find nearest power of 2 + kNearestLess, // nearest power of 2 which is less than or equal image dimension + KNearestGreater, // nearest power of 2 which is greater than or equal image dimension + k32, // use this size specifically + k64, + k128, + k256, + k512, + k1024, + k2048, + k4096, + k8192 +}; + +// Default values for images loading +short gTextureScale = k1024; // for non-tiled images the type of texture scaling to do +short gMaxTextureSize = 4096; // maximum texture size to use for application +Boolean gfTileTextures = true; // are multiple tiled textures used to display image? +Boolean gfOverlapTextures = true; // do tiled textures overlapped to create correct filtering between tiles? (only applies if using tiled textures) +Boolean gfClientTextures = false; // 10.1+ only: texture from client memory +Boolean gfAGPTextures = false; // 10.1+ only: texture from AGP memory without loading to GPU can be set after inmage loaded +Boolean gfNPOTTextures = false; // 10.1+ only: use Non-Power Of Two (NPOT) textures + +// --------------------------------- + +static long GetScaledTextureDimFromImageDim (long imageDimension, short scaling); +static unsigned char * LoadBufferFromImageFile (FSSpec fsspecImage, short imageScale, + long * pOrigImageWidth, long * pOrigImageHeight, long *pOrigDepth, + long * pBufferWidth, long * pBufferHeight, long * pBufferDepth); + +// --------------------------------- + +// based on scaling determine the texture dimension which fits the image dimension passe in +// kNone: no scaling just use image dimension (will not guarentee support power for 2 textures) +// kNearest: find nearest power of 2 texture +// kNearestLess: find nearest power of 2 texture which is less than image dimension +// kNearestGreater: find nearest power of 2 texture which is greater than image dimension +// k32 - k1024: use this specific texture size + +static long GetScaledTextureDimFromImageDim (long imageDimension, short scaling) +{ + switch (scaling) + { + case kNone: // no scaling + return imageDimension; + break; + case kNearest: // scale to nearest power of two + { + // find power of 2 greater + long i = 0, texDim = 1, imageTemp = imageDimension; + while (imageTemp >>= 1) // while the dimension still has bits of data shift right (losing a bit at a time) + i++; // count shifts (i.e., powers of two) + texDim = texDim << i; // shift our one bit representation left the like amount (i.e., 2 ^ i) + if (texDim >= gMaxTextureSize) // if we are too big or at max size + return gMaxTextureSize; // then must use max texture size + // are we closer to greater pow 2 or closer to higher pow 2? + // compare to the power of two that is double of initial guess + else if (((texDim << 1) - imageDimension) < (imageDimension - texDim)) + return (texDim << 1); // if it is closer away then return double guess + else + return texDim; // otherwise orginal guess is closer so return this + } + break; + case kNearestLess: + { + // find power of 2 lower + long i = 0, texDim = 1; + while (imageDimension >>= 1) // while the dimension still has bits of data shift right (losing a bit at a time) + i++; // count shifts (i.e., powers of two) + texDim = texDim << i; // shift our one bit representation left the like amount (i.e., 2 ^ i) + return texDim; // returns the maxium power of two that is less than or equal the texture dimension + } + break; + case KNearestGreater: + { + // find power of 2 greater + long i = 0, texDim = 1; + while (imageDimension >>= 1) // while the dimension still has bits of data shift right (losing a bit at a time) + i++; // count shifts (i.e., powers of two) + texDim = texDim << (i + 1); // shift our one bit representation left the like amount (i.e., 2 ^ (i + 1)) + return texDim; // returns the minimum power of two that is greater than or equal the texture dimension + } + break; + case k32: // return hard values for texture dimension + return 32; + break; + case k64: + return 64; + break; + case k128: + return 128; + break; + case k256: + return 256; + break; + case k512: + return 512; + break; + case k1024: + return 1024; + break; + case k2048: + return 2048; + break; + case k4096: + return 8192; + break; + case k8192: + return 8192; + break; + } + return 0; +} + +static char errMess[256]; + +char *QTfailureMessage(void) { return errMess; } + +static unsigned char * LoadBufferFromImageFile ( FSSpec fsspecImage, + short imageScale, + long *pOrigImageWidth, long *pOrigImageHeight, long *pOrigImageDepth, + long *pBufferWidth, long *pBufferHeight, long *pBufferDepth) +{ + unsigned char * pImageBuffer = NULL; + int scalefac, xoffs, yoffs; + GWorldPtr pGWorld = NULL; + OSType pixelFormat; + long rowStride; // length, in bytes, of a pixel row in the image + GraphicsImportComponent giComp; // componenet for importing image + Rect rectImage; // rectangle of source image + ImageDescriptionHandle hImageDesc; // handle to image description used to get image depth + MatrixRecord matrix; + GDHandle origDevice; // save field for current graphics device + CGrafPtr origPort; // save field for current graphics port + OSStatus err = noErr; // err return value + + // zero output params + *pOrigImageWidth = 0; + *pOrigImageHeight = 0; + *pOrigImageDepth = 0; + *pBufferWidth = 0; + *pBufferHeight = 0; + *pBufferDepth = 0; + + // get imorter for the image tyoe in file + GetGraphicsImporterForFile (&fsspecImage, &giComp); + if (err != noErr) { // if we have an error + sprintf ( errMess, "couldnt find importer\n"); + return NULL; // go away + } + + // Create GWorld + err = GraphicsImportGetNaturalBounds (giComp, &rectImage); // get the image bounds + if (err != noErr) { + sprintf ( errMess, "failed to GraphicsImportGetNaturalBounds"); + + return NULL; // go away if error + } + // create a handle for the image description + hImageDesc = (ImageDescriptionHandle) NewHandle (sizeof (ImageDescriptionHandle)); + HLock ((Handle) hImageDesc); // lock said handle + err = GraphicsImportGetImageDescription (giComp, &hImageDesc); // retrieve the image description + if (err != noErr) { + sprintf ( errMess, "failed to GraphicsImportGetImageDescription"); + + return NULL; // go away if error + } + *pOrigImageWidth = (long) (rectImage.right - rectImage.left); // find width from right side - left side bounds + *pOrigImageHeight = (long) (rectImage.bottom - rectImage.top); // same for height + + // we will use a 24-bit rgb texture or a 32-bit rgba + if ((**hImageDesc).depth == 32) *pOrigImageDepth=4; + else *pOrigImageDepth=3; + + *pBufferDepth = 32; // we will use a 32 bbit texture (this includes 24 bit images) + pixelFormat = k32ARGBPixelFormat; + + // note - we want texels to stay square, so + if ((*pOrigImageWidth) > (*pOrigImageHeight)) { + *pBufferWidth = GetScaledTextureDimFromImageDim ( *pOrigImageWidth, imageScale ) ; + *pBufferHeight=*pBufferWidth; + scalefac = X2Fix ((float) (*pBufferWidth) / (float) *pOrigImageWidth); + } + else { + *pBufferHeight = GetScaledTextureDimFromImageDim (*pOrigImageHeight, imageScale ); + *pBufferWidth = *pBufferHeight; + scalefac = X2Fix ((float) (*pBufferHeight) / (float) *pOrigImageHeight); + } + SetRect (&rectImage, 0, 0, (short) *pBufferWidth, (short) *pBufferHeight); // l, t, r. b set image rectangle for creation of GWorld + rowStride = *pBufferWidth * *pBufferDepth >> 3; // set stride in bytes width of image * pixel depth in bytes + pImageBuffer = (unsigned char *) NewPtrClear (rowStride * *pBufferHeight); // build new buffer exact size of image (stride * height) + if (NULL == pImageBuffer) + { + sprintf ( errMess, "failed to allocate image buffer"); + CloseComponent(giComp); // dump component + return NULL; // if we failed to allocate buffer + } + // create a new gworld using our unpadded buffer, ensure we set the pixel type correctly for the expected image bpp + QTNewGWorldFromPtr (&pGWorld, pixelFormat, &rectImage, NULL, NULL, 0, pImageBuffer, rowStride); + if (NULL == pGWorld) + { + sprintf ( errMess, "failed to create GWorld"); + DisposePtr ((Ptr) pImageBuffer); // dump image buffer + pImageBuffer = NULL; + CloseComponent(giComp); + return NULL; // if we failed to create gworld + } + + GetGWorld (&origPort, &origDevice); // save onscreen graphics port + // decompress (draw) to gworld and thus fill buffer + SetIdentityMatrix (&matrix); // set transform matrix to identity (basically pass thorugh) + + + TranslateMatrix ( &matrix, -X2Fix(0.5f * *pOrigImageWidth), -X2Fix(0.5f * *pOrigImageHeight)); + ScaleMatrix (&matrix, X2Fix(1.0), X2Fix(-1.0), X2Fix (0.0), X2Fix (0.0)); + TranslateMatrix ( &matrix, X2Fix(0.5f * *pOrigImageWidth), X2Fix(0.5f * *pOrigImageHeight)); + + err = GraphicsImportSetMatrix(giComp, &matrix); // set our matrix as the importer matrix + if (err == noErr) + err = GraphicsImportSetGWorld (giComp, pGWorld, NULL); // set the destination of the importer component + if (err == noErr) + err = GraphicsImportSetQuality (giComp, codecLosslessQuality); // we want lossless decompression + if ((err == noErr) && GetGWorldPixMap (pGWorld) && LockPixels (GetGWorldPixMap (pGWorld))) + GraphicsImportDraw (giComp); // if everything looks good draw image to locked pixmap + else + { + sprintf ( errMess, "failed to Set Matrix or GWorld or Quality or GetPixMap"); + + DisposeGWorld (pGWorld); // dump gworld + pGWorld = NULL; + DisposePtr ((Ptr) pImageBuffer); // dump image buffer + pImageBuffer = NULL; + CloseComponent(giComp); // dump component + return NULL; + } + + UnlockPixels (GetGWorldPixMap (pGWorld)); // unlock pixels + CloseComponent(giComp); // dump component + SetGWorld(origPort, origDevice); // set current graphics port to offscreen + // done with gworld and image since they are loaded to a texture + // DisposeGWorld (pGWorld); // do not need gworld + // pGWorld = NULL; + + return pImageBuffer; +} + +// takes a Darwin path name and returns the FSSpec associated with it +// ths is pretty horrible. sorry. +FSSpec *darwinPathToFSSpec ( char *fname ) +{ + char cfname[256], + cvolname[256], + pvolname[256]; + int i; + SInt16 vrefNum; + SInt32 dirID; + OSErr err; + FSSpec *fs=(FSSpec *) malloc(sizeof(FSSpec)); + char *qtvolname; + + qtvolname=getenv("OSG_QTIMPORT_VOLNAME"); + + if (qtvolname) + strcpy ( cvolname, qtvolname ); + else { + err=HGetVol ( pvolname, &vrefNum, &dirID ); + + if (err==noErr) { + int l=0xff & pvolname[0]; + memcpy ( cvolname, pvolname+1, l ); + cvolname[l]=0x0; + } + else { + sprintf ( errMess, "failed to determine root drive name" ); + free(fs); + return NULL; + } + } + + sprintf ( cfname, " %s%s", cvolname, fname ); + + for (i=0; i +#include +#include + +#include "osg/GL" + +#include "osgDB/FileNameUtils" +#include "osgDB/Registry" + +#include +#include +#include + +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif + +extern "C" unsigned char* +LoadBufferFromDarwinPath ( const char *fname, long *origWidth, long *origHeight, long *origDepth, + long *buffWidth, long *buffHeight, long *buffDepth); + +extern "C" char * +QTfailureMessage(void); + +using namespace osg; + +class ReaderWriterQT : public osgDB::ReaderWriter +{ + public: + virtual const char* className() { return "Default Quicktime Image Reader/Writer"; } + + virtual bool acceptsExtension(const std::string& extension) + { + // this should be the only image importer required on the Mac + // dont know what else it supports, but these will do + return osgDB::equalCaseInsensitive(extension,"rgb") || + osgDB::equalCaseInsensitive(extension,"rgba") || + osgDB::equalCaseInsensitive(extension,"jpg") || + osgDB::equalCaseInsensitive(extension,"jpeg") || + osgDB::equalCaseInsensitive(extension,"tiff") || + osgDB::equalCaseInsensitive(extension,"pict") || + osgDB::equalCaseInsensitive(extension,"gif") || + osgDB::equalCaseInsensitive(extension,"tga"); + } + + virtual ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options*) + { + std::string ext = osgDB::getFileExtension(fileName); + if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; + + long origWidth, origHeight,buffWidth,buffHeight,buffDepth,origDepth; + + // NOTE - implememntation means that this will always return 32 bits, so it is hard to work out if + // an image was monochrome. So it will waste texture memory unless it gets a monochrome hint. + + unsigned char *pixels = LoadBufferFromDarwinPath ( fileName.c_str(), &origWidth,&origHeight,&origDepth, + &buffWidth,&buffHeight, + &buffDepth); + + // IMPORTANT - + // origDepth in BYTES, buffDepth in BITS + + if (pixels == 0) { + cerr << "LoadBufferFromDarwinPath failed " << fileName.c_str() << QTfailureMessage() << endl; + return 0; + } + + unsigned int pixelFormat; + + switch(origDepth) { + case 1 : + pixelFormat = GL_RGB; + break; + case 2 : + pixelFormat = GL_LUMINANCE_ALPHA; + break; + case 3 : + pixelFormat = GL_RGB; + break; + case 4 : + pixelFormat = GL_RGBA; + break; + default : + cerr << "Unknown file type in " << fileName.c_str() << " with " << origDepth << endl; + pixelFormat = (GLenum)-1; + return 0; + break; + } + + { + unsigned char *srcp=pixels, *dstp=pixels; + + int i, j; + + // swizzle entire image in-place + for (i=0; isetFileName(fileName.c_str()); + image->setImage(buffWidth,buffHeight,1, + buffDepth >> 3, + pixelFormat, + GL_UNSIGNED_BYTE, + pixels ); + + notify(INFO) << "image read ok "< g_readerWriter_QT_Proxy;