<commit_before>#include <osgSim/ShapeAttribute>

#include <iostream>
#include <string>

#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/ParameterOutput>

using namespace osgSim;

bool ShapeAttributeList_readLocalData(osg::Object &obj, osgDB::Input &fr);
bool ShapeAttributeList_writeLocalData(const osg::Object &obj, osgDB::Output &fw);

osgDB::RegisterDotOsgWrapperProxy ShapeAttributeList_Proxy
(
    new ShapeAttributeList,
    "ShapeAttributeList",
    "Object ShapeAttributeList",
    &ShapeAttributeList_readLocalData,
    &ShapeAttributeList_writeLocalData,
    osgDB::DotOsgWrapper::READ_AND_WRITE
);

osgSim::ShapeAttribute::Type ShapeAttributeList_typeStringToEnum(std::string type)
{
    if (type == "STRING") return osgSim::ShapeAttribute::STRING;
    else if (type == "DOUBLE") return osgSim::ShapeAttribute::DOUBLE;
    else if (type == "INTEGER") return osgSim::ShapeAttribute::INTEGER;
    else return osgSim::ShapeAttribute::UNKNOW;
}
void ShapeAttributeList_typeEnumToString(osgSim::ShapeAttribute::Type type, std::string & typeStr)
{
    switch (type)
    {
    case osgSim::ShapeAttribute::STRING:  typeStr = "STRING"; break;
    case osgSim::ShapeAttribute::DOUBLE:  typeStr = "DOUBLE"; break;
    case osgSim::ShapeAttribute::INTEGER: typeStr = "INTEGER"; break;
    default: typeStr = "UNKNOW"; break;
    }
}

bool ShapeAttributeList_readLocalData(osg::Object &obj, osgDB::Input &fr)
{
    bool iteratorAdvanced = false;
    ShapeAttributeList &sal = static_cast<ShapeAttributeList &>(obj);

    int size = 0;

    if (fr[0].matchWord("size") && fr[1].getInt(size))
    {
        sal.reserve(size);
        fr += 2;
        iteratorAdvanced = true;
    }

    if (size)
    {
        std::string name;
        osgSim::ShapeAttribute::Type type;
        for (int i = 0; i < size; ++i)
        {
            if (fr.matchSequence("name %s"))
            {
               name = fr[1].getStr();
               fr += 2;
               iteratorAdvanced = true;
            }
            if (fr[0].matchWord("type"))
            {
               type = ShapeAttributeList_typeStringToEnum(fr[1].getStr());
               fr += 2;
               iteratorAdvanced = true;

                switch (type)
                {
                    case osgSim::ShapeAttribute::STRING:
                    {
                        if (fr.matchSequence("value %s"))
                        {
                           std::string value = fr[1].getStr();
                           fr += 2;
                           iteratorAdvanced = true;
                           sal.push_back(osgSim::ShapeAttribute((const char *) name.c_str(), (char*) value.c_str()));
                        }
                        break;
                    }
                    case osgSim::ShapeAttribute::DOUBLE:
                    {
                        double value;
                        if (fr[0].matchWord("value") && fr[1].getFloat(value))
                        {
                           fr += 2;
                           iteratorAdvanced = true;
                           sal.push_back(osgSim::ShapeAttribute((const char *) name.c_str(), value));
                        }
                        break;
                    }
                    case osgSim::ShapeAttribute::INTEGER:
                    {
                        int value;
                        if (fr[0].matchWord("value") && fr[1].getInt(value))
                        {
                           fr += 2;
                           iteratorAdvanced = true;
                           sal.push_back(osgSim::ShapeAttribute((const char *) name.c_str(), value));
                        }
                        break;
                    }
                    case osgSim::ShapeAttribute::UNKNOW:
                    default:
                    {
                        sal.push_back(osgSim::ShapeAttribute((const char *) name.c_str()));
                        break;
                    }
                }
            }
        }
    }

    return iteratorAdvanced;
}

bool ShapeAttributeList_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
{
    const ShapeAttributeList &sal = static_cast<const ShapeAttributeList &>(obj);

    unsigned int size = sal.size();
    fw.indent()<<"size "<< size << std::endl;

    if (size)
    {
        std::string type;
        ShapeAttributeList::const_iterator it, end = sal.end();
        for (it = sal.begin(); it != end; ++it)
        {
            fw.indent()<<"name \""<< it->getName() << "\"" << std::endl;
            ShapeAttributeList_typeEnumToString(it->getType(), type);
            fw.indent()<<"type "<< type << std::endl;
            switch (it->getType())
            {
            case osgSim::ShapeAttribute::STRING:
            {
                fw.indent()<<"value \""<< it->getString() << "\"" << std::endl;
                break;
            }
            case osgSim::ShapeAttribute::INTEGER:
            {
                fw.indent()<<"value "<< it->getInt() << std::endl;
                break;
            }
            case osgSim::ShapeAttribute::DOUBLE:
            {
                fw.indent()<<"value "<< it->getDouble() << std::endl;
                break;
            }
            case osgSim::ShapeAttribute::UNKNOW:
            default: break;
            }
        }
    }
    return true;
}
<commit_msg>Updated the shapefile attribute IO so that its more streamlined.<commit_after>#include <osgSim/ShapeAttribute>

#include <iostream>
#include <string>

#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/ParameterOutput>

using namespace osgSim;

bool ShapeAttributeList_readLocalData(osg::Object &obj, osgDB::Input &fr);
bool ShapeAttributeList_writeLocalData(const osg::Object &obj, osgDB::Output &fw);

osgDB::RegisterDotOsgWrapperProxy ShapeAttributeList_Proxy
(
    new ShapeAttributeList,
    "ShapeAttributeList",
    "Object ShapeAttributeList",
    &ShapeAttributeList_readLocalData,
    &ShapeAttributeList_writeLocalData,
    osgDB::DotOsgWrapper::READ_AND_WRITE
);

bool ShapeAttributeList_readLocalData(osg::Object &obj, osgDB::Input &fr)
{
    bool iteratorAdvanced = false;
    ShapeAttributeList &sal = static_cast<ShapeAttributeList &>(obj);

    int entry = fr[0].getNoNestedBrackets();

    while (!fr.eof() && fr[0].getNoNestedBrackets()>=entry)
    {
        if (fr.matchSequence("string %s %s"))
        {
            sal.push_back(osgSim::ShapeAttribute(fr[1].getStr(), fr[2].getStr()));
            fr += 3;
            iteratorAdvanced = true;
        }
        else if (fr.matchSequence("double %s %f"))
        {
            double value;
            fr[2].getFloat(value);
            sal.push_back(osgSim::ShapeAttribute(fr[1].getStr(), value));
            fr += 3;
            iteratorAdvanced = true;
        }
        else if (fr.matchSequence("int %s %i"))
        {
            int value;
            fr[2].getInt(value);
            sal.push_back(osgSim::ShapeAttribute(fr[1].getStr(), value));
            fr += 3;
            iteratorAdvanced = true;
        }
        else ++fr;
    }

    return iteratorAdvanced;
}

bool ShapeAttributeList_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
{
    const ShapeAttributeList &sal = static_cast<const ShapeAttributeList &>(obj);

    for (ShapeAttributeList::const_iterator it = sal.begin(); it != sal.end(); ++it)
    {
        switch (it->getType())
        {
            case osgSim::ShapeAttribute::STRING:
            {
                fw.indent()<<"string "<< fw.wrapString(it->getName())<<" "<<fw.wrapString(it->getString()) << std::endl;
                break;
            }
            case osgSim::ShapeAttribute::INTEGER:
            {
                fw.indent()<<"int    "<< fw.wrapString(it->getName())<<" "<<it->getInt() << std::endl;
                break;
            }
            case osgSim::ShapeAttribute::DOUBLE:
            {
                fw.indent()<<"double "<< fw.wrapString(it->getName())<<" "<<it->getDouble() << std::endl;
                break;
            }
            case osgSim::ShapeAttribute::UNKNOW:
                default: break;
        }
    }
    return true;
}
<|endoftext|>


<commit_before>/*
 *  QTImportExport.cpp
 *  cefix
 *
 *  Created by Stephan Huber on 07.02.08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */
#include <map>
#include <sstream>
#include "QTImportExport.h"
#include "QTUtils.h"

#include <osgDB/FileNameUtils>

/** small exception class bundling a error-message */
class QTImportExportException : public std::exception {

    public:
        QTImportExportException(int err, const std::string& msg) : std::exception(), _err(err), _msg(msg) {}

        virtual const char* what() { return _msg.c_str(); }
        int getErrorCode() { return _err; }

        virtual ~QTImportExportException() throw () {}

    private:
        int _err;
        std::string _msg;
};

QuicktimeImportExport::QuicktimeImportExport()
:    _error(0),
    _lastError("")
{
    initQuicktime();
}

// ----------------------------------------------------------------------------------------------------------
// flipImage
// ----------------------------------------------------------------------------------------------------------

void QuicktimeImportExport::flipImage(unsigned char* pixels, int bytesPerPixel, unsigned int width, unsigned height)
{
    // Flip the image
    unsigned imageSize = width * height * bytesPerPixel;
    char *tBuffer = new char [imageSize];
    unsigned int rowBytes = width * bytesPerPixel;
    unsigned int i,j;
    for (i = 0, j = imageSize - rowBytes; i < imageSize; i += rowBytes, j -= rowBytes)
        memcpy( &tBuffer[j], &pixels[i], (size_t)rowBytes );

    memcpy(pixels, tBuffer, (size_t)imageSize);
    delete[] tBuffer;
}

// ----------------------------------------------------------------------------------------------------------
// prepareBufferForOSG
// ----------------------------------------------------------------------------------------------------------

unsigned char* QuicktimeImportExport::pepareBufferForOSG(unsigned char * buffer, int bytesPerPixel, unsigned int width, unsigned int height)
{
    unsigned char *pixels = new unsigned char [height * width * 4];
    unsigned char *dstp = pixels;
    unsigned char *srcp = buffer;
    unsigned int i, j;

    int roffset, goffset, boffset, aoffset;
    aoffset = -1;
    int sourceStep;

    switch (bytesPerPixel) {
        case 1:
            sourceStep = 1;
            roffset = goffset = boffset = 0;
            break;
        case 3:
            sourceStep = 3;
            roffset = 0;
            goffset = 1;
            boffset = 2;
            break;
        case 4:
            sourceStep = 4;
            aoffset = 1;
            roffset = 2;
            goffset = 3;
            boffset = 0;
            break;

    }

    for (i = 0; i < height; ++i )
    {
        for (j = 0; j < width; ++j )
        {
            dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
            dstp[1] = srcp[roffset];
            dstp[2] = srcp[goffset];
            dstp[3] = srcp[boffset];
            srcp+=sourceStep;
            dstp+=4;

        }
    }

    flipImage(pixels, bytesPerPixel, width, height);
    return pixels;

}

// ----------------------------------------------------------------------------------------------------------
// prepareBufferForQuicktime
// ----------------------------------------------------------------------------------------------------------

unsigned char* QuicktimeImportExport::prepareBufferForQuicktime(unsigned char* buffer, GLenum pixelFormat, int bytesPerPixel, unsigned int width, unsigned int height)
{
    unsigned char *pixels = new unsigned char [height * width * 4];
    unsigned char *dstp = pixels;
    unsigned char *srcp = buffer;
    unsigned int i, j;

    int roffset, goffset, boffset, aoffset;
    aoffset = -1;
    int sourceStep;

    switch (bytesPerPixel) {
        case 1:
            sourceStep = 1;
            roffset = goffset = boffset = 0;
            break;
        case 3:
            sourceStep = 3;
            roffset = 0;
            goffset = 1;
            boffset = 2;
            break;
        case 4:
            sourceStep = 4;
            switch (pixelFormat) {
                case GL_RGBA:
                    aoffset = 3;
                    roffset = 0;
                    goffset = 1;
                    boffset = 2;
                    break;

                case GL_BGRA_EXT:
                    aoffset = 0;
                    roffset = 1;
                    goffset = 2;
                    boffset = 3;
                    break;
            }
    }

    for (i = 0; i < height; ++i )
    {
        for (j = 0; j < width; ++j )
        {
            dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
            dstp[1] = srcp[roffset];
            dstp[2] = srcp[goffset];
            dstp[3] = srcp[boffset];
            srcp+=sourceStep;
            dstp+=4;

        }
    }

    flipImage(pixels, 4, width, height);

    return pixels;

}

// ----------------------------------------------------------------------------------------------------------
// readFromStream
// ----------------------------------------------------------------------------------------------------------

osg::Image* QuicktimeImportExport::readFromStream(std::istream & inStream, const std::string& fileTypeHint, long sizeHint)
{
    char* content = NULL;
    long length = 0;
     if (sizeHint != 0)
    {
        length = sizeHint;
        content = new char[length];
        inStream.read (content,length);
    }
    else
    {
        int readBytes(0), newBytes(0);

        char buffer[10240];

        while (!inStream.eof()) {
            inStream.read(buffer, 10240);
            newBytes = inStream.gcount();
            if (newBytes > 0) {
                char* newcontent = new char[readBytes + newBytes];

                if (readBytes > 0)
                    memcpy(newcontent, content, readBytes);

                memcpy(&newcontent[readBytes], &buffer, newBytes);
                readBytes += newBytes;
                if (content) delete[] content;
                content = newcontent;
            }
        }
        length = readBytes;
    }

    osg::Image* img = doImport(reinterpret_cast<unsigned char*>(content), length, fileTypeHint);

    if (content) delete[] content;
    return img;
 }

Handle getPtrDataRef(unsigned char *data, unsigned int size, const std::string &filename)
{
     // Load Data Reference
     Handle dataRef;
     Handle fileNameHandle;
     PointerDataRefRecord ptrDataRefRec;
     ComponentInstance dataRefHandler;
     unsigned char pstr[255];

     ptrDataRefRec.data = data;
     ptrDataRefRec.dataLength = size;

     /*err = */PtrToHand(&ptrDataRefRec, &dataRef, sizeof(PointerDataRefRecord));

     // Open a Data Handler for the Data Reference
     /*err = */OpenADataHandler(dataRef, PointerDataHandlerSubType, NULL,
         (OSType)0, NULL, kDataHCanRead, &dataRefHandler);

     // Convert From CString in filename to a PascalString in pstr
     if (filename.length() > 255) {
         CopyCStringToPascal(filename.c_str(), pstr);
         //hmm...not good, pascal string limit is 255!
         //do some error handling maybe?!
     }

    // Add filename extension
     /*err = */PtrToHand(pstr, &fileNameHandle, filename.length() + 1);
     /*err = */DataHSetDataRefExtension(dataRefHandler, fileNameHandle,
         kDataRefExtensionFileName);
     DisposeHandle(fileNameHandle);

     // Release old handler which does not have the extensions
     DisposeHandle(dataRef);

     // Grab the SAFE_NEW version of the data ref from the data handler
     /*err = */ DataHGetDataRef(dataRefHandler, &dataRef);

     CloseComponent(dataRefHandler);

     return dataRef;
}

osg::Image* QuicktimeImportExport::doImport(unsigned char* data, unsigned int sizeData, const std::string& fileTypeHint)
{
    GWorldPtr gworld = 0;
    OSType pixelFormat;
    int rowStride;
    GraphicsImportComponent gicomp = 0;
    Rect rectImage;
    GDHandle origDevice = 0;
    CGrafPtr origPort = 0;
    ImageDescriptionHandle desc = 0;
    int depth = 32;
    unsigned int xsize, ysize;
    unsigned char* imageData;

    // Data Handle for file data ( & load data from file )
    Handle dataRef = getPtrDataRef(data, sizeData, fileTypeHint);

    try {
        OSErr err = noErr;

        // GraphicsImporter - Get Importer for our filetype
        GetGraphicsImporterForDataRef(dataRef, 'ptr ', &gicomp);

        // GWorld - Get Texture Info
        err = GraphicsImportGetNaturalBounds(gicomp, &rectImage);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportGetNaturalBounds failed");

        }
        xsize = (unsigned int)(rectImage.right - rectImage.left);
        ysize = (unsigned int)(rectImage.bottom - rectImage.top);

        // ImageDescription - Get Image Description
        err = GraphicsImportGetImageDescription(gicomp, &desc);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportGetImageDescription failed");
        }

        // ImageDescription - Get Bit Depth
        HLock(reinterpret_cast<char **>(desc));

        // GWorld - Pixel Format stuff
        pixelFormat = k32ARGBPixelFormat; // Make sure its forced...NOTE: i'm pretty sure this cannot be RGBA!

        // GWorld - Row stride
        rowStride = xsize * 4; // (width * depth_bpp / 8)

        // GWorld - Allocate output buffer
        imageData = new unsigned char[rowStride * ysize];

        // GWorld - Actually Create IT!
        QTNewGWorldFromPtr(&gworld, pixelFormat, &rectImage, 0, 0, 0, imageData, rowStride);
        if (!gworld) {
            throw QTImportExportException(-1, "QTNewGWorldFromPtr failed");
        }

        // Save old Graphics Device and Graphics Port to reset to later
        GetGWorld (&origPort, &origDevice);

        // GraphicsImporter - Set Destination GWorld (our buffer)
        err = GraphicsImportSetGWorld(gicomp, gworld, 0);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportSetGWorld failed");
        }

        // GraphicsImporter - Set Quality Level
        err = GraphicsImportSetQuality(gicomp, codecLosslessQuality);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportSetQuality failed");
        }

        // Lock pixels so that we can draw to our memory texture
        if (!GetGWorldPixMap(gworld) || !LockPixels(GetGWorldPixMap(gworld))) {
            throw QTImportExportException(0, "GetGWorldPixMap failed");
        }

        //*** Draw GWorld into our Memory Texture!
        GraphicsImportDraw(gicomp);

        // Clean up
        UnlockPixels(GetGWorldPixMap(gworld));
        SetGWorld(origPort, origDevice); // set graphics port to offscreen (we don't need it now)
        DisposeGWorld(gworld);
        CloseComponent(gicomp);
        DisposeHandle(reinterpret_cast<char **>(desc));
        DisposeHandle(dataRef);
    }
    catch (QTImportExportException e)
    {
        setError(e.what());

        if (gworld) {
            UnlockPixels(GetGWorldPixMap(gworld));
            SetGWorld(origPort, origDevice); // set graphics port to offscreen (we don't need it now)
            DisposeGWorld(gworld);
        }
        if (gicomp)
            CloseComponent(gicomp);
        if (desc)
            DisposeHandle(reinterpret_cast<char **>(desc));

        if (imageData)
            delete[] imageData;
        if (dataRef)
            DisposeHandle(dataRef);

        return NULL;
    }

    unsigned int glpixelFormat;

    switch(depth >> 3) {
        case 3 :
            glpixelFormat = GL_RGB;
            break;
        case 4 :
            glpixelFormat = GL_RGBA;
            break;
        default :
            delete imageData;
            setError("unknown pixelformat");
            return NULL;
            break;
    }

    unsigned char* swizzled = pepareBufferForOSG(imageData, depth >> 3, xsize, ysize);

    delete[] imageData;

    osg::Image* image = new osg::Image();
    image->setFileName(fileTypeHint.c_str());
    image->setImage(xsize,ysize,1,
        depth >> 3,
        glpixelFormat,
        GL_UNSIGNED_BYTE,
        swizzled,
        osg::Image::USE_NEW_DELETE );

    return image;
}

 void QuicktimeImportExport::writeToStream(std::ostream& outStream, osg::Image* image, const std::string& fileTypeHint)
 {

    std::string ext = osgDB::getFileExtension(fileTypeHint);
    //Build map  of extension <-> osFileTypes
    static std::map<std::string, OSType> extmap;
    if (extmap.size() == 0) {
        extmap["jpg"]  = kQTFileTypeJPEG;
        extmap["jpeg"] = kQTFileTypeJPEG;
        extmap["bmp"]  = kQTFileTypeBMP;
        extmap["tif"]  = kQTFileTypeTIFF;
        extmap["tiff"] = kQTFileTypeTIFF;
        extmap["png"]  = kQTFileTypePNG;
        extmap["gif"]  = kQTFileTypeGIF;
        extmap["psd"]  = kQTFileTypePhotoShop;
        extmap["sgi"]  = kQTFileTypeSGIImage;
        extmap["rgb"]  = kQTFileTypeSGIImage;
        extmap["rgba"] = kQTFileTypeSGIImage;
    }

    std::map<std::string, OSType>::iterator cur = extmap.find(ext);

    // can not handle this type of file, perhaps a movie?
    if (cur == extmap.end())
        return;

    unsigned int numBytes = image->computeNumComponents(image->getPixelFormat());
    unsigned char* pixels = prepareBufferForQuicktime(
        image->data(),
        image->getPixelFormat(),
        numBytes,
        image->s(),
        image->t()
    );

    OSType desiredType = cur->second;
    GraphicsExportComponent geComp = NULL;
    GWorldPtr gw = 0;
    Handle dataHandle;
    dataHandle = NewHandle(0);

    try {
        OSErr err = OpenADefaultComponent(GraphicsExporterComponentType, desiredType, &geComp);
        Rect bounds = {0,0, image->t(), image->s()};

        err = QTNewGWorldFromPtr(&gw, k32ARGBPixelFormat, &bounds, 0,0,0, pixels, image->s()*4);
        if (err != noErr) {
            throw QTImportExportException(err,  "could not create gworld for type " + ext);
        }

        err = GraphicsExportSetInputGWorld(geComp, gw);
        if (err != noErr) {
            throw QTImportExportException(err, "could not set input gworld for type " + ext);
        }

        err = GraphicsExportSetOutputHandle( geComp, dataHandle);
        if (err != noErr) {
            throw QTImportExportException(err, "could not set output file for type " + ext);
        }

        // Set the compression quality (needed for JPEG, not necessarily for other formats)
        if (desiredType == kQTFileTypeJPEG) {
            err = GraphicsExportSetCompressionQuality(geComp, codecLosslessQuality);
            if (err != noErr) {
                throw QTImportExportException(err, "could not set compression for type " + ext);
            }
        }

        if(4 == numBytes)
        {
            err = GraphicsExportSetDepth( geComp, k32ARGBPixelFormat );    // depth
        }
        // else k24RGBPixelFormat???

        // do the export
        err = GraphicsExportDoExport(geComp, NULL);
        if (err != noErr) {
            throw QTImportExportException(err, "could not do the export for type " + ext);
        }

        if (geComp != NULL)
            CloseComponent(geComp);

        if (gw) DisposeGWorld (gw);
        if (pixels) free(pixels);

        outStream.write(*dataHandle, GetHandleSize(dataHandle));
        DisposeHandle(dataHandle);
    }

    catch (QTImportExportException e)
    {
        setError(e.what());

        if (geComp != NULL) CloseComponent(geComp);
        if (gw != NULL) DisposeGWorld (gw);
        if (pixels) free(pixels);

        DisposeHandle(dataHandle);

    }

}

<commit_msg>From Ulrich Hertlien, "attached is a patch to src/osgPlugins/quicktime/QTImportExport.cpp that fixes loading images using the quicktime loader.  Also fixes some minor bugs like uninitialized variables and incorrect deletes.<commit_after>/*
 *  QTImportExport.cpp
 *  cefix
 *
 *  Created by Stephan Huber on 07.02.08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */
#include <map>
#include <sstream>
#include "QTImportExport.h"
#include "QTUtils.h"

#include <osgDB/FileNameUtils>

/** small exception class bundling a error-message */
class QTImportExportException : public std::exception {

    public:
        QTImportExportException(int err, const std::string& msg) : std::exception(), _err(err), _msg(msg) {}

        virtual const char* what() { return _msg.c_str(); }
        int getErrorCode() { return _err; }

        virtual ~QTImportExportException() throw () {}

    private:
        int _err;
        std::string _msg;
};

QuicktimeImportExport::QuicktimeImportExport()
:    _error(0),
    _lastError("")
{
    initQuicktime();
}

// ----------------------------------------------------------------------------------------------------------
// flipImage
// ----------------------------------------------------------------------------------------------------------

void QuicktimeImportExport::flipImage(unsigned char* pixels, int bytesPerPixel, unsigned int width, unsigned height)
{
    // Flip the image
    unsigned imageSize = width * height * bytesPerPixel;
    char *tBuffer = new char [imageSize];
    unsigned int rowBytes = width * bytesPerPixel;
    unsigned int i,j;
    for (i = 0, j = imageSize - rowBytes; i < imageSize; i += rowBytes, j -= rowBytes)
        memcpy( &tBuffer[j], &pixels[i], (size_t)rowBytes );

    memcpy(pixels, tBuffer, (size_t)imageSize);
    delete[] tBuffer;
}

// ----------------------------------------------------------------------------------------------------------
// prepareBufferForOSG
// ----------------------------------------------------------------------------------------------------------

unsigned char* QuicktimeImportExport::pepareBufferForOSG(unsigned char * buffer, int bytesPerPixel, unsigned int width, unsigned int height)
{
    unsigned char *pixels = new unsigned char [height * width * 4];
    unsigned char *dstp = pixels;
    unsigned char *srcp = buffer;
    unsigned int i, j;

    int roffset, goffset, boffset, aoffset;
    aoffset = -1;
    int sourceStep;

    switch (bytesPerPixel) {
        case 1:
            sourceStep = 1;
            roffset = goffset = boffset = 0;
            break;
        case 3:
            sourceStep = 3;
            roffset = 0;
            goffset = 1;
            boffset = 2;
            break;
        case 4:
            sourceStep = 4;
            aoffset = 1;
            roffset = 2;
            goffset = 3;
            boffset = 0;
            break;

    }

    for (i = 0; i < height; ++i )
    {
        for (j = 0; j < width; ++j )
        {
            dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
            dstp[1] = srcp[roffset];
            dstp[2] = srcp[goffset];
            dstp[3] = srcp[boffset];
            srcp+=sourceStep;
            dstp+=4;

        }
    }

    flipImage(pixels, bytesPerPixel, width, height);
    return pixels;

}

// ----------------------------------------------------------------------------------------------------------
// prepareBufferForQuicktime
// ----------------------------------------------------------------------------------------------------------

unsigned char* QuicktimeImportExport::prepareBufferForQuicktime(unsigned char* buffer, GLenum pixelFormat, int bytesPerPixel, unsigned int width, unsigned int height)
{
    unsigned char *pixels = new unsigned char [height * width * 4];
    unsigned char *dstp = pixels;
    unsigned char *srcp = buffer;
    unsigned int i, j;

    int roffset, goffset, boffset, aoffset;
    aoffset = -1;
    int sourceStep;

    switch (bytesPerPixel) {
        case 1:
            sourceStep = 1;
            roffset = goffset = boffset = 0;
            break;
        case 3:
            sourceStep = 3;
            roffset = 0;
            goffset = 1;
            boffset = 2;
            break;
        case 4:
            sourceStep = 4;
            switch (pixelFormat) {
                case GL_RGBA:
                    aoffset = 3;
                    roffset = 0;
                    goffset = 1;
                    boffset = 2;
                    break;

                case GL_BGRA_EXT:
                    aoffset = 0;
                    roffset = 1;
                    goffset = 2;
                    boffset = 3;
                    break;
            }
    }

    for (i = 0; i < height; ++i )
    {
        for (j = 0; j < width; ++j )
        {
            dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
            dstp[1] = srcp[roffset];
            dstp[2] = srcp[goffset];
            dstp[3] = srcp[boffset];
            srcp+=sourceStep;
            dstp+=4;

        }
    }

    flipImage(pixels, 4, width, height);

    return pixels;

}

// ----------------------------------------------------------------------------------------------------------
// readFromStream
// ----------------------------------------------------------------------------------------------------------

osg::Image* QuicktimeImportExport::readFromStream(std::istream & inStream, const std::string& fileTypeHint, long sizeHint)
{
    char* content = NULL;
    long length = 0;
     if (sizeHint != 0)
    {
        length = sizeHint;
        content = new char[length];
        inStream.read (content,length);
    }
    else
    {
        int readBytes(0), newBytes(0);

        char buffer[10240];

        while (!inStream.eof()) {
            inStream.read(buffer, 10240);
            newBytes = inStream.gcount();
            if (newBytes > 0) {
                char* newcontent = new char[readBytes + newBytes];

                if (readBytes > 0)
                    memcpy(newcontent, content, readBytes);

                memcpy(&newcontent[readBytes], &buffer, newBytes);
                readBytes += newBytes;
                if (content) delete[] content;
                content = newcontent;
            }
        }
        length = readBytes;
    }

    osg::Image* img = doImport(reinterpret_cast<unsigned char*>(content), length, fileTypeHint);

    if (content) delete[] content;
    return img;
 }

Handle getPtrDataRef(unsigned char *data, unsigned int size, const std::string &filename)
{
     // Load Data Reference
     Handle dataRef;
     Handle fileNameHandle;
     PointerDataRefRecord ptrDataRefRec;
     ComponentInstance dataRefHandler;
     unsigned char pstr[255];

     ptrDataRefRec.data = data;
     ptrDataRefRec.dataLength = size;

     /*err = */PtrToHand(&ptrDataRefRec, &dataRef, sizeof(PointerDataRefRecord));

     // Open a Data Handler for the Data Reference
     /*err = */OpenADataHandler(dataRef, PointerDataHandlerSubType, NULL,
         (OSType)0, NULL, kDataHCanRead, &dataRefHandler);

     // Convert From CString in filename to a PascalString in pstr
     if (filename.length() > 255) {
         //hmm...not good, pascal string limit is 255!
         //do some error handling maybe?!
         throw QTImportExportException(0, "filename length limit exceeded");
     }
     CopyCStringToPascal(filename.c_str(), pstr);

    // Add filename extension
     /*err = */PtrToHand(pstr, &fileNameHandle, filename.length() + 1);
     /*err = */DataHSetDataRefExtension(dataRefHandler, fileNameHandle,
         kDataRefExtensionFileName);
     DisposeHandle(fileNameHandle);

     // Release old handler which does not have the extensions
     DisposeHandle(dataRef);

     // Grab the SAFE_NEW version of the data ref from the data handler
     /*err = */ DataHGetDataRef(dataRefHandler, &dataRef);

     CloseComponent(dataRefHandler);

     return dataRef;
}

osg::Image* QuicktimeImportExport::doImport(unsigned char* data, unsigned int sizeData, const std::string& fileTypeHint)
{
    GWorldPtr gworld = 0;
    OSType pixelFormat;
    int rowStride;
    GraphicsImportComponent gicomp = 0;
    Rect rectImage;
    GDHandle origDevice = 0;
    CGrafPtr origPort = 0;
    ImageDescriptionHandle desc = 0;
    int depth = 32;
    unsigned int xsize, ysize;
    unsigned char* imageData = 0;

    // Data Handle for file data ( & load data from file )
    Handle dataRef = getPtrDataRef(data, sizeData, fileTypeHint);

    try {
        OSErr err = noErr;

        // GraphicsImporter - Get Importer for our filetype
        GetGraphicsImporterForDataRef(dataRef, 'ptr ', &gicomp);

        // GWorld - Get Texture Info
        err = GraphicsImportGetNaturalBounds(gicomp, &rectImage);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportGetNaturalBounds failed");

        }
        xsize = (unsigned int)(rectImage.right - rectImage.left);
        ysize = (unsigned int)(rectImage.bottom - rectImage.top);

        // ImageDescription - Get Image Description
        err = GraphicsImportGetImageDescription(gicomp, &desc);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportGetImageDescription failed");
        }

        // ImageDescription - Get Bit Depth
        HLock(reinterpret_cast<char **>(desc));

        // GWorld - Pixel Format stuff
        pixelFormat = k32ARGBPixelFormat; // Make sure its forced...NOTE: i'm pretty sure this cannot be RGBA!

        // GWorld - Row stride
        rowStride = xsize * 4; // (width * depth_bpp / 8)

        // GWorld - Allocate output buffer
        imageData = new unsigned char[rowStride * ysize];

        // GWorld - Actually Create IT!
        QTNewGWorldFromPtr(&gworld, pixelFormat, &rectImage, 0, 0, 0, imageData, rowStride);
        if (!gworld) {
            throw QTImportExportException(-1, "QTNewGWorldFromPtr failed");
        }

        // Save old Graphics Device and Graphics Port to reset to later
        GetGWorld (&origPort, &origDevice);

        // GraphicsImporter - Set Destination GWorld (our buffer)
        err = GraphicsImportSetGWorld(gicomp, gworld, 0);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportSetGWorld failed");
        }

        // GraphicsImporter - Set Quality Level
        err = GraphicsImportSetQuality(gicomp, codecLosslessQuality);
        if (err != noErr) {
            throw QTImportExportException(err, "GraphicsImportSetQuality failed");
        }

        // Lock pixels so that we can draw to our memory texture
        if (!GetGWorldPixMap(gworld) || !LockPixels(GetGWorldPixMap(gworld))) {
            throw QTImportExportException(0, "GetGWorldPixMap failed");
        }

        //*** Draw GWorld into our Memory Texture!
        GraphicsImportDraw(gicomp);

        // Clean up
        UnlockPixels(GetGWorldPixMap(gworld));
        SetGWorld(origPort, origDevice); // set graphics port to offscreen (we don't need it now)
        DisposeGWorld(gworld);
        CloseComponent(gicomp);
        DisposeHandle(reinterpret_cast<char **>(desc));
        DisposeHandle(dataRef);
    }
    catch (QTImportExportException& e)
    {
        setError(e.what());

        if (gworld) {
            UnlockPixels(GetGWorldPixMap(gworld));
            SetGWorld(origPort, origDevice); // set graphics port to offscreen (we don't need it now)
            DisposeGWorld(gworld);
        }
        if (gicomp)
            CloseComponent(gicomp);
        if (desc)
            DisposeHandle(reinterpret_cast<char **>(desc));

        if (imageData)
            delete[] imageData;
        if (dataRef)
            DisposeHandle(dataRef);

        return NULL;
    }

    unsigned int bytesPerPixel = depth / 8;
    unsigned int glpixelFormat;
    switch(bytesPerPixel) {
        case 3 :
            glpixelFormat = GL_RGB;
            break;
        case 4 :
            glpixelFormat = GL_RGBA;
            break;
        default :
            delete[] imageData;
            setError("unknown pixelformat");
            return NULL;
            break;
    }

    unsigned char* swizzled = pepareBufferForOSG(imageData, bytesPerPixel, xsize, ysize);

    delete[] imageData;

    osg::Image* image = new osg::Image();
    image->setFileName(fileTypeHint.c_str());
    image->setImage(xsize,ysize,1,
        bytesPerPixel,
        glpixelFormat,
        GL_UNSIGNED_BYTE,
        swizzled,
        osg::Image::USE_NEW_DELETE );

    return image;
}

 void QuicktimeImportExport::writeToStream(std::ostream& outStream, osg::Image* image, const std::string& fileTypeHint)
 {

    std::string ext = osgDB::getFileExtension(fileTypeHint);
    //Build map  of extension <-> osFileTypes
    static std::map<std::string, OSType> extmap;
    if (extmap.size() == 0) {
        extmap["jpg"]  = kQTFileTypeJPEG;
        extmap["jpeg"] = kQTFileTypeJPEG;
        extmap["bmp"]  = kQTFileTypeBMP;
        extmap["tif"]  = kQTFileTypeTIFF;
        extmap["tiff"] = kQTFileTypeTIFF;
        extmap["png"]  = kQTFileTypePNG;
        extmap["gif"]  = kQTFileTypeGIF;
        extmap["psd"]  = kQTFileTypePhotoShop;
        extmap["sgi"]  = kQTFileTypeSGIImage;
        extmap["rgb"]  = kQTFileTypeSGIImage;
        extmap["rgba"] = kQTFileTypeSGIImage;
    }

    std::map<std::string, OSType>::iterator cur = extmap.find(ext);

    // can not handle this type of file, perhaps a movie?
    if (cur == extmap.end())
        return;

    unsigned int numBytes = image->computeNumComponents(image->getPixelFormat());
    unsigned char* pixels = prepareBufferForQuicktime(
        image->data(),
        image->getPixelFormat(),
        numBytes,
        image->s(),
        image->t()
    );

    OSType desiredType = cur->second;
    GraphicsExportComponent geComp = NULL;
    GWorldPtr gw = 0;
    Handle dataHandle;
    dataHandle = NewHandle(0);

    try {
        OSErr err = OpenADefaultComponent(GraphicsExporterComponentType, desiredType, &geComp);
        Rect bounds = {0,0, image->t(), image->s()};

        err = QTNewGWorldFromPtr(&gw, k32ARGBPixelFormat, &bounds, 0,0,0, pixels, image->s()*4);
        if (err != noErr) {
            throw QTImportExportException(err,  "could not create gworld for type " + ext);
        }

        err = GraphicsExportSetInputGWorld(geComp, gw);
        if (err != noErr) {
            throw QTImportExportException(err, "could not set input gworld for type " + ext);
        }

        err = GraphicsExportSetOutputHandle( geComp, dataHandle);
        if (err != noErr) {
            throw QTImportExportException(err, "could not set output file for type " + ext);
        }

        // Set the compression quality (needed for JPEG, not necessarily for other formats)
        if (desiredType == kQTFileTypeJPEG) {
            err = GraphicsExportSetCompressionQuality(geComp, codecLosslessQuality);
            if (err != noErr) {
                throw QTImportExportException(err, "could not set compression for type " + ext);
            }
        }

        if(4 == numBytes)
        {
            err = GraphicsExportSetDepth( geComp, k32ARGBPixelFormat );    // depth
        }
        // else k24RGBPixelFormat???

        // do the export
        err = GraphicsExportDoExport(geComp, NULL);
        if (err != noErr) {
            throw QTImportExportException(err, "could not do the export for type " + ext);
        }

        if (geComp != NULL)
            CloseComponent(geComp);

        if (gw) DisposeGWorld (gw);
        if (pixels) free(pixels);

        outStream.write(*dataHandle, GetHandleSize(dataHandle));
        DisposeHandle(dataHandle);
    }

    catch (QTImportExportException& e)
    {
        setError(e.what());

        if (geComp != NULL) CloseComponent(geComp);
        if (gw != NULL) DisposeGWorld (gw);
        if (pixels) free(pixels);

        DisposeHandle(dataHandle);

    }

}

<|endoftext|>


<commit_before>#include <osg/Program>
#include <osgDB/ObjectWrapper>
#include <osgDB/InputStream>
#include <osgDB/OutputStream>

#define PROGRAM_LIST_FUNC( PROP, TYPE, DATA ) \
    static bool check##PROP(const osg::Program& attr) \
    { return attr.get##TYPE().size()>0; } \
    static bool read##PROP(osgDB::InputStream& is, osg::Program& attr) { \
        unsigned int size = is.readSize(); is >> is.BEGIN_BRACKET; \
        for ( unsigned int i=0; i<size; ++i ) { \
            std::string key; unsigned int value; \
            is >> key >> value; attr.add##DATA(key, value); \
        } \
        is >> is.END_BRACKET; \
        return true; \
    } \
    static bool write##PROP( osgDB::OutputStream& os, const osg::Program& attr ) \
    { \
        const osg::Program::TYPE& plist = attr.get##TYPE(); \
        os.writeSize(plist.size()); os << os.BEGIN_BRACKET << std::endl; \
        for ( osg::Program::TYPE::const_iterator itr=plist.begin(); \
              itr!=plist.end(); ++itr ) { \
            os << itr->first << itr->second << std::endl; \
        } \
        os << os.END_BRACKET << std::endl; \
        return true; \
    }

PROGRAM_LIST_FUNC( AttribBinding, AttribBindingList, BindAttribLocation )
PROGRAM_LIST_FUNC( FragDataBinding, FragDataBindingList, BindFragDataLocation )

#define PROGRAM_PARAMETER_FUNC( PROP, NAME ) \
    static bool check##PROP(const osg::Program& attr) \
    { return true; } \
    static bool read##PROP(osgDB::InputStream& is, osg::Program& attr) { \
        int value; is >> is.PROPERTY(#NAME) >> value; \
        attr.setParameter(NAME, value); \
        return true; \
    } \
    static bool write##PROP(osgDB::OutputStream& os, const osg::Program& attr) { \
        os << os.PROPERTY(#NAME) << (int)attr.getParameter(NAME) << std::endl; \
        return true; \
    }

PROGRAM_PARAMETER_FUNC( GeometryVerticesOut, GL_GEOMETRY_VERTICES_OUT_EXT )
PROGRAM_PARAMETER_FUNC( GeometryInputType, GL_GEOMETRY_INPUT_TYPE_EXT )
PROGRAM_PARAMETER_FUNC( GeometryOutputType, GL_GEOMETRY_OUTPUT_TYPE_EXT )

// _shaderList
static bool checkShaders( const osg::Program& attr )
{
    return attr.getNumShaders()>0;
}

static bool readShaders( osgDB::InputStream& is, osg::Program& attr )
{
    unsigned int size = is.readSize(); is >> is.BEGIN_BRACKET;
    for ( unsigned int i=0; i<size; ++i )
    {
        osg::ref_ptr<osg::Shader> shader = is.readObjectOfType<osg::Shader>();
        if ( shader ) attr.addShader( shader );
    }
    is >> is.END_BRACKET;
    return true;
}

static bool writeShaders( osgDB::OutputStream& os, const osg::Program& attr )
{
    unsigned int size = attr.getNumShaders();
    os.writeSize(size); os << os.BEGIN_BRACKET << std::endl;
    for ( unsigned int i=0; i<size; ++i )
    {
        os << attr.getShader(i);
    }
    os << os.END_BRACKET << std::endl;
    return true;
}
// feedBackVaryings
static bool checkFeedBackVaryingsName( const osg::Program& attr )
{
	return true;
}
static bool readFeedBackVaryingsName( osgDB::InputStream& is, osg::Program& attr )
{
	unsigned int size = is.readSize(); is >> is.BEGIN_BRACKET;
	for ( unsigned int i=0; i<size; ++i )
	{
		std::string str;
		is>> str;
		attr.addTransformFeedBackVarying(str);
	}
	is >> is.END_BRACKET;
	return true;
}
static bool writeFeedBackVaryingsName( osgDB::OutputStream& os, const osg::Program& attr )
{
	unsigned int size = attr.getNumTransformFeedBackVaryings();
	os.writeSize(size); os << os.BEGIN_BRACKET << std::endl;
	for ( unsigned int i=0; i<size; ++i )
	{
		os << attr.getTransformFeedBackVarying(i)<< std::endl;
	}
	os << os.END_BRACKET << std::endl;
	return true;
}
// feedBack mode
static bool checkFeedBackMode( const osg::Program& attr )
{
	return true;
}
static bool readFeedBackMode( osgDB::InputStream& is, osg::Program& attr )
{
	unsigned int size ;
	is>>size;
	attr.setTransformFeedBackMode(size);
	return true;
}
static bool writeFeedBackMode( osgDB::OutputStream& os, const osg::Program& attr )
{
	os << attr.getTransformFeedBackMode()<< std::endl;
	return true;
}
// _numGroupsX/Y/Z
static bool checkComputeGroups( const osg::Program& attr )
{
    GLint numX = 0, numY = 0, numZ = 0;
    attr.getComputeGroups( numX, numY, numZ );
    return numX>0 && numY>0 && numZ>0;
}

static bool readComputeGroups( osgDB::InputStream& is, osg::Program& attr )
{
    GLint numX = 0, numY = 0, numZ = 0;
    is >> numX >> numY >> numZ;
    attr.setComputeGroups( numX, numY, numZ );
    return true;
}

static bool writeComputeGroups( osgDB::OutputStream& os, const osg::Program& attr )
{
    GLint numX = 0, numY = 0, numZ = 0;
    attr.getComputeGroups( numX, numY, numZ );
    os << numX << numY << numZ << std::endl;
    return true;
}

REGISTER_OBJECT_WRAPPER( Program,
                         new osg::Program,
                         osg::Program,
                         "osg::Object osg::StateAttribute osg::Program" )
{
    ADD_USER_SERIALIZER( AttribBinding );  // _attribBindingList
    ADD_USER_SERIALIZER( FragDataBinding );  // _fragDataBindingList
    ADD_USER_SERIALIZER( Shaders );  // _shaderList
    ADD_USER_SERIALIZER( GeometryVerticesOut );  // _geometryVerticesOut
    ADD_USER_SERIALIZER( GeometryInputType );  // _geometryInputType
    ADD_USER_SERIALIZER( GeometryOutputType );  // _geometryOutputType

    {
        UPDATE_TO_VERSION_SCOPED( 95 )
        ADD_USER_SERIALIZER( ComputeGroups );  // _numGroupsX/Y/Z
    }

    {
        UPDATE_TO_VERSION_SCOPED( 116 )
        ADD_USER_SERIALIZER( FeedBackVaryingsName );
        ADD_USER_SERIALIZER( FeedBackMode );
    }
}
<commit_msg>add osg::Program::BindUniformBlock serialization<commit_after>#include <osg/Program>
#include <osgDB/ObjectWrapper>
#include <osgDB/InputStream>
#include <osgDB/OutputStream>

#define PROGRAM_LIST_FUNC( PROP, TYPE, DATA ) \
    static bool check##PROP(const osg::Program& attr) \
    { return attr.get##TYPE().size()>0; } \
    static bool read##PROP(osgDB::InputStream& is, osg::Program& attr) { \
        unsigned int size = is.readSize(); is >> is.BEGIN_BRACKET; \
        for ( unsigned int i=0; i<size; ++i ) { \
            std::string key; unsigned int value; \
            is >> key >> value; attr.add##DATA(key, value); \
        } \
        is >> is.END_BRACKET; \
        return true; \
    } \
    static bool write##PROP( osgDB::OutputStream& os, const osg::Program& attr ) \
    { \
        const osg::Program::TYPE& plist = attr.get##TYPE(); \
        os.writeSize(plist.size()); os << os.BEGIN_BRACKET << std::endl; \
        for ( osg::Program::TYPE::const_iterator itr=plist.begin(); \
              itr!=plist.end(); ++itr ) { \
            os << itr->first << itr->second << std::endl; \
        } \
        os << os.END_BRACKET << std::endl; \
        return true; \
    }

PROGRAM_LIST_FUNC( AttribBinding, AttribBindingList, BindAttribLocation )
PROGRAM_LIST_FUNC( FragDataBinding, FragDataBindingList, BindFragDataLocation )

#define PROGRAM_PARAMETER_FUNC( PROP, NAME ) \
    static bool check##PROP(const osg::Program& attr) \
    { return true; } \
    static bool read##PROP(osgDB::InputStream& is, osg::Program& attr) { \
        int value; is >> is.PROPERTY(#NAME) >> value; \
        attr.setParameter(NAME, value); \
        return true; \
    } \
    static bool write##PROP(osgDB::OutputStream& os, const osg::Program& attr) { \
        os << os.PROPERTY(#NAME) << (int)attr.getParameter(NAME) << std::endl; \
        return true; \
    }

PROGRAM_PARAMETER_FUNC( GeometryVerticesOut, GL_GEOMETRY_VERTICES_OUT_EXT )
PROGRAM_PARAMETER_FUNC( GeometryInputType, GL_GEOMETRY_INPUT_TYPE_EXT )
PROGRAM_PARAMETER_FUNC( GeometryOutputType, GL_GEOMETRY_OUTPUT_TYPE_EXT )

// _shaderList
static bool checkShaders( const osg::Program& attr )
{
    return attr.getNumShaders()>0;
}

static bool readShaders( osgDB::InputStream& is, osg::Program& attr )
{
    unsigned int size = is.readSize(); is >> is.BEGIN_BRACKET;
    for ( unsigned int i=0; i<size; ++i )
    {
        osg::ref_ptr<osg::Shader> shader = is.readObjectOfType<osg::Shader>();
        if ( shader ) attr.addShader( shader );
    }
    is >> is.END_BRACKET;
    return true;
}

static bool writeShaders( osgDB::OutputStream& os, const osg::Program& attr )
{
    unsigned int size = attr.getNumShaders();
    os.writeSize(size); os << os.BEGIN_BRACKET << std::endl;
    for ( unsigned int i=0; i<size; ++i )
    {
        os << attr.getShader(i);
    }
    os << os.END_BRACKET << std::endl;
    return true;
}
// feedBackVaryings
static bool checkFeedBackVaryingsName( const osg::Program& attr )
{
	return true;
}
static bool readFeedBackVaryingsName( osgDB::InputStream& is, osg::Program& attr )
{
	unsigned int size = is.readSize(); is >> is.BEGIN_BRACKET;
	for ( unsigned int i=0; i<size; ++i )
	{
		std::string str;
		is>> str;
		attr.addTransformFeedBackVarying(str);
	}
	is >> is.END_BRACKET;
	return true;
}
static bool writeFeedBackVaryingsName( osgDB::OutputStream& os, const osg::Program& attr )
{
	unsigned int size = attr.getNumTransformFeedBackVaryings();
	os.writeSize(size); os << os.BEGIN_BRACKET << std::endl;
	for ( unsigned int i=0; i<size; ++i )
	{
		os << attr.getTransformFeedBackVarying(i)<< std::endl;
	}
	os << os.END_BRACKET << std::endl;
	return true;
}
// feedBack mode
static bool checkFeedBackMode( const osg::Program& attr )
{
	return true;
}
static bool readFeedBackMode( osgDB::InputStream& is, osg::Program& attr )
{
	unsigned int size ;
	is>>size;
	attr.setTransformFeedBackMode(size);
	return true;
}
static bool writeFeedBackMode( osgDB::OutputStream& os, const osg::Program& attr )
{
	os << attr.getTransformFeedBackMode()<< std::endl;
	return true;
}
// _numGroupsX/Y/Z
static bool checkComputeGroups( const osg::Program& attr )
{
    GLint numX = 0, numY = 0, numZ = 0;
    attr.getComputeGroups( numX, numY, numZ );
    return numX>0 && numY>0 && numZ>0;
}

static bool readComputeGroups( osgDB::InputStream& is, osg::Program& attr )
{
    GLint numX = 0, numY = 0, numZ = 0;
    is >> numX >> numY >> numZ;
    attr.setComputeGroups( numX, numY, numZ );
    return true;
}

static bool writeComputeGroups( osgDB::OutputStream& os, const osg::Program& attr )
{
    GLint numX = 0, numY = 0, numZ = 0;
    attr.getComputeGroups( numX, numY, numZ );
    os << numX << numY << numZ << std::endl;
    return true;
}

static bool checkBindUniformBlock( const osg::Program& node )
{
    return true;
}

static bool readBindUniformBlock( osgDB::InputStream& is, osg::Program& p )
{
    unsigned int  size = 0; is >> size >> is.BEGIN_BRACKET;
    std::string name; unsigned int index;
    for ( unsigned int i=0; i<size; ++i )
    {
        is >>name;        is >>index;
        p.addBindUniformBlock(name, index);
    }
    is >> is.END_BRACKET;
    return true;
}

static bool writeBindUniformBlock( osgDB::OutputStream& os, const osg::Program& p )
{
    unsigned int size = p.getUniformBlockBindingList().size();
    os << size << os.BEGIN_BRACKET << std::endl;
    for(osg::Program::UniformBlockBindingList::const_iterator bbit = p.getUniformBlockBindingList().begin();
        bbit != p.getUniformBlockBindingList().end(); ++bbit)
    {
        os << bbit->first;
        os << bbit->second;
    }
    os << os.END_BRACKET << std::endl;
    return true;
}

REGISTER_OBJECT_WRAPPER( Program,
                         new osg::Program,
                         osg::Program,
                         "osg::Object osg::StateAttribute osg::Program" )
{
    ADD_USER_SERIALIZER( AttribBinding );  // _attribBindingList
    ADD_USER_SERIALIZER( FragDataBinding );  // _fragDataBindingList
    ADD_USER_SERIALIZER( Shaders );  // _shaderList
    ADD_USER_SERIALIZER( GeometryVerticesOut );  // _geometryVerticesOut
    ADD_USER_SERIALIZER( GeometryInputType );  // _geometryInputType
    ADD_USER_SERIALIZER( GeometryOutputType );  // _geometryOutputType

    {
        UPDATE_TO_VERSION_SCOPED( 95 )
        ADD_USER_SERIALIZER( ComputeGroups );  // _numGroupsX/Y/Z
    }

    {
        UPDATE_TO_VERSION_SCOPED( 116 )
        ADD_USER_SERIALIZER( FeedBackVaryingsName );
        ADD_USER_SERIALIZER( FeedBackMode );
    }
    {
        UPDATE_TO_VERSION_SCOPED( 150 )
        ADD_USER_SERIALIZER( BindUniformBlock );
    }
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cppqtstyleindenter.h"

#include "cppcodeformatter.h"
#include "cpptoolssettings.h"
#include "cppcodestylepreferences.h"

#include <QChar>
#include <QTextDocument>
#include <QTextBlock>
#include <QTextCursor>

using namespace CppTools;

CppQtStyleIndenter::CppQtStyleIndenter()
    : m_cppCodeStylePreferences(0)
{
    // Just for safety. setCodeStylePreferences should be called when the editor the
    // indenter belongs to gets initialized.
    m_cppCodeStylePreferences = CppToolsSettings::instance()->cppCodeStyle();
}

CppQtStyleIndenter::~CppQtStyleIndenter()
{}

bool CppQtStyleIndenter::isElectricCharacter(const QChar &ch) const
{
    switch (ch.toLatin1()) {
    case '{':
    case '}':
    case ':':
    case '#':
    case '<':
    case '>':
        return true;
    }
    return false;
}

static bool isElectricInLine(const QChar ch, const QString &text)
{
    switch (ch.toLatin1()) {
    case ':':
        // switch cases and access declarations should be reindented
        if (text.contains(QLatin1String("case"))
                || text.contains(QLatin1String("default"))
                || text.contains(QLatin1String("public"))
                || text.contains(QLatin1String("private"))
                || text.contains(QLatin1String("protected"))
                || text.contains(QLatin1String("signals"))
                || text.contains(QLatin1String("Q_SIGNALS"))) {
            return true;
        }

        // fall-through
        // lines that start with : might have a constructor initializer list
    case '<':
    case '>': {
        // Electrical if at line beginning (after space indentation)
        const QString trimmedtext = text.trimmed();
        return !trimmedtext.isEmpty() && trimmedtext.at(0) == ch;
    }
    }

    return true;
}

void CppQtStyleIndenter::indentBlock(QTextDocument *doc,
                                     const QTextBlock &block,
                                     const QChar &typedChar,
                                     const TextEditor::TabSettings &tabSettings)
{
    Q_UNUSED(doc)

    CppTools::QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());

    codeFormatter.updateStateUntil(block);
    int indent;
    int padding;
    codeFormatter.indentFor(block, &indent, &padding);

    if (isElectricCharacter(typedChar)) {
        // : should not be electric for labels
        if (!isElectricInLine(typedChar, block.text()))
            return;

        // only reindent the current line when typing electric characters if the
        // indent is the same it would be if the line were empty
        int newlineIndent;
        int newlinePadding;
        codeFormatter.indentForNewLineAfter(block.previous(), &newlineIndent, &newlinePadding);
        if (tabSettings.indentationColumn(block.text()) != newlineIndent + newlinePadding)
            return;
    }

    tabSettings.indentLine(block, indent + padding, padding);
}

void CppQtStyleIndenter::indent(QTextDocument *doc,
                                const QTextCursor &cursor,
                                const QChar &typedChar,
                                const TextEditor::TabSettings &tabSettings)
{
    if (cursor.hasSelection()) {
        QTextBlock block = doc->findBlock(cursor.selectionStart());
        const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();

        CppTools::QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());
        codeFormatter.updateStateUntil(block);

        QTextCursor tc = cursor;
        tc.beginEditBlock();
        do {
            int indent;
            int padding;
            codeFormatter.indentFor(block, &indent, &padding);
            tabSettings.indentLine(block, indent + padding, padding);
            codeFormatter.updateLineStateChange(block);
            block = block.next();
        } while (block.isValid() && block != end);
        tc.endEditBlock();
    } else {
        indentBlock(doc, cursor.block(), typedChar, tabSettings);
    }
}

void CppQtStyleIndenter::setCodeStylePreferences(TextEditor::ICodeStylePreferences *preferences)
{
    CppTools::CppCodeStylePreferences *cppCodeStylePreferences
            = qobject_cast<CppTools::CppCodeStylePreferences *>(preferences);
    if (cppCodeStylePreferences)
        m_cppCodeStylePreferences = cppCodeStylePreferences;
}

void CppQtStyleIndenter::invalidateCache(QTextDocument *doc)
{
    CppTools::QtStyleCodeFormatter formatter;
    formatter.invalidateCache(doc);
}

CppCodeStyleSettings CppQtStyleIndenter::codeStyleSettings() const
{
    if (m_cppCodeStylePreferences)
        return m_cppCodeStylePreferences->currentCodeStyleSettings();
    return CppCodeStyleSettings();
}
<commit_msg>CppTools: Optimize test for electric char in context<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cppqtstyleindenter.h"

#include "cppcodeformatter.h"
#include "cpptoolssettings.h"
#include "cppcodestylepreferences.h"

#include <QChar>
#include <QTextDocument>
#include <QTextBlock>
#include <QTextCursor>

using namespace CppTools;

CppQtStyleIndenter::CppQtStyleIndenter()
    : m_cppCodeStylePreferences(0)
{
    // Just for safety. setCodeStylePreferences should be called when the editor the
    // indenter belongs to gets initialized.
    m_cppCodeStylePreferences = CppToolsSettings::instance()->cppCodeStyle();
}

CppQtStyleIndenter::~CppQtStyleIndenter()
{}

bool CppQtStyleIndenter::isElectricCharacter(const QChar &ch) const
{
    switch (ch.toLatin1()) {
    case '{':
    case '}':
    case ':':
    case '#':
    case '<':
    case '>':
        return true;
    }
    return false;
}

static bool isElectricInLine(const QChar ch, const QString &text)
{
    switch (ch.toLatin1()) {
    case ':':
        // switch cases and access declarations should be reindented
        if (text.contains(QLatin1String("case"))
                || text.contains(QLatin1String("default"))
                || text.contains(QLatin1String("public"))
                || text.contains(QLatin1String("private"))
                || text.contains(QLatin1String("protected"))
                || text.contains(QLatin1String("signals"))
                || text.contains(QLatin1String("Q_SIGNALS"))) {
            return true;
        }

        // fall-through
        // lines that start with : might have a constructor initializer list
    case '<':
    case '>': {
        // Electric if at line beginning (after space indentation)
        for (int i = 0, len = text.count(); i < len; ++i) {
            if (!text.at(i).isSpace())
                return text.at(i) == ch;
        }
        return false;
    }
    }

    return true;
}

void CppQtStyleIndenter::indentBlock(QTextDocument *doc,
                                     const QTextBlock &block,
                                     const QChar &typedChar,
                                     const TextEditor::TabSettings &tabSettings)
{
    Q_UNUSED(doc)

    CppTools::QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());

    codeFormatter.updateStateUntil(block);
    int indent;
    int padding;
    codeFormatter.indentFor(block, &indent, &padding);

    if (isElectricCharacter(typedChar)) {
        // : should not be electric for labels
        if (!isElectricInLine(typedChar, block.text()))
            return;

        // only reindent the current line when typing electric characters if the
        // indent is the same it would be if the line were empty
        int newlineIndent;
        int newlinePadding;
        codeFormatter.indentForNewLineAfter(block.previous(), &newlineIndent, &newlinePadding);
        if (tabSettings.indentationColumn(block.text()) != newlineIndent + newlinePadding)
            return;
    }

    tabSettings.indentLine(block, indent + padding, padding);
}

void CppQtStyleIndenter::indent(QTextDocument *doc,
                                const QTextCursor &cursor,
                                const QChar &typedChar,
                                const TextEditor::TabSettings &tabSettings)
{
    if (cursor.hasSelection()) {
        QTextBlock block = doc->findBlock(cursor.selectionStart());
        const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();

        CppTools::QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());
        codeFormatter.updateStateUntil(block);

        QTextCursor tc = cursor;
        tc.beginEditBlock();
        do {
            int indent;
            int padding;
            codeFormatter.indentFor(block, &indent, &padding);
            tabSettings.indentLine(block, indent + padding, padding);
            codeFormatter.updateLineStateChange(block);
            block = block.next();
        } while (block.isValid() && block != end);
        tc.endEditBlock();
    } else {
        indentBlock(doc, cursor.block(), typedChar, tabSettings);
    }
}

void CppQtStyleIndenter::setCodeStylePreferences(TextEditor::ICodeStylePreferences *preferences)
{
    CppTools::CppCodeStylePreferences *cppCodeStylePreferences
            = qobject_cast<CppTools::CppCodeStylePreferences *>(preferences);
    if (cppCodeStylePreferences)
        m_cppCodeStylePreferences = cppCodeStylePreferences;
}

void CppQtStyleIndenter::invalidateCache(QTextDocument *doc)
{
    CppTools::QtStyleCodeFormatter formatter;
    formatter.invalidateCache(doc);
}

CppCodeStyleSettings CppQtStyleIndenter::codeStyleSettings() const
{
    if (m_cppCodeStylePreferences)
        return m_cppCodeStylePreferences->currentCodeStyleSettings();
    return CppCodeStyleSettings();
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** Copyright (C) 2015 Denis Mingulov.
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "imageviewerfile.h"
#include "imageviewer.h"
#include "imageviewerconstants.h"

#include <coreplugin/editormanager/documentmodel.h>
#include <utils/fileutils.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>

#include <QFileInfo>
#include <QGraphicsPixmapItem>
#ifndef QT_NO_SVG
#include <QGraphicsSvgItem>
#endif
#include <QImageReader>
#include <QMovie>
#include <QPainter>
#include <QPixmap>

namespace ImageViewer {
namespace Internal {

class MovieItem : public QObject, public QGraphicsPixmapItem
{
public:
    MovieItem(QMovie *movie)
        : m_movie(movie)
    {
        setPixmap(m_movie->currentPixmap());
        connect(m_movie, &QMovie::updated, this, [this](const QRectF &rect) {
            update(rect);
        });
    }

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
    {
        const bool smoothTransform = painter->worldTransform().m11() < 1;
        painter->setRenderHint(QPainter::SmoothPixmapTransform, smoothTransform);
        painter->drawPixmap(offset(), m_movie->currentPixmap());
    }

private:
    QMovie *m_movie;
};

ImageViewerFile::ImageViewerFile()
{
    setId(Constants::IMAGEVIEWER_ID);
    connect(this, &ImageViewerFile::mimeTypeChanged, this, &ImageViewerFile::changed);
}

ImageViewerFile::~ImageViewerFile()
{
    cleanUp();
}

Core::IDocument::OpenResult ImageViewerFile::open(QString *errorString, const QString &fileName,
                                                  const QString &realFileName)
{
    QTC_CHECK(fileName == realFileName); // does not support auto save
    OpenResult success = openImpl(errorString, fileName);
    emit openFinished(success == OpenResult::Success);
    return success;
}

Core::IDocument::OpenResult ImageViewerFile::openImpl(QString *errorString, const QString &fileName)
{
    cleanUp();
    m_type = TypeInvalid;

    if (!QFileInfo(fileName).isReadable())
        return OpenResult::ReadError;

    QByteArray format = QImageReader::imageFormat(fileName);
    // if it is impossible to recognize a file format - file will not be open correctly
    if (format.isEmpty()) {
        if (errorString)
            *errorString = tr("Image format not supported.");
        return OpenResult::CannotHandle;
    }

#ifndef QT_NO_SVG
    if (format.startsWith("svg")) {
        m_type = TypeSvg;
        m_tempSvgItem = new QGraphicsSvgItem(fileName);
        QRectF bound = m_tempSvgItem->boundingRect();
        if (bound.width() == 0 && bound.height() == 0) {
            if (errorString)
                *errorString = tr("Failed to read SVG image.");
            return OpenResult::CannotHandle;
        }
        emit imageSizeChanged(QSize());
    } else
#endif
    if (QMovie::supportedFormats().contains(format)) {
        m_type = TypeMovie;
        m_movie = new QMovie(fileName, QByteArray(), this);
        m_movie->setCacheMode(QMovie::CacheAll);
        connect(m_movie, &QMovie::finished, m_movie, &QMovie::start);
        connect(m_movie, &QMovie::resized, this, &ImageViewerFile::imageSizeChanged);
        m_movie->start();
        m_isPaused = false; // force update
        setPaused(true);
    } else {
        m_type = TypePixmap;
        m_pixmap = new QPixmap(fileName);
        if (m_pixmap->isNull()) {
            if (errorString)
                *errorString = tr("Failed to read image.");
            delete m_pixmap;
            return OpenResult::CannotHandle;
        }
        emit imageSizeChanged(m_pixmap->size());
    }

    setFilePath(Utils::FileName::fromString(fileName));
    Utils::MimeDatabase mdb;
    setMimeType(mdb.mimeTypeForFile(fileName).name());
    return OpenResult::Success;
}

Core::IDocument::ReloadBehavior ImageViewerFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
{
    if (type == TypeRemoved || type == TypePermissions)
        return BehaviorSilent;
    if (type == TypeContents && state == TriggerInternal && !isModified())
        return BehaviorSilent;
    return BehaviorAsk;
}

bool ImageViewerFile::reload(QString *errorString,
                             Core::IDocument::ReloadFlag flag,
                             Core::IDocument::ChangeType type)
{
    if (flag == FlagIgnore)
        return true;
    if (type == TypePermissions) {
        emit changed();
        return true;
    }
    emit aboutToReload();
    bool success = (openImpl(errorString, filePath().toString()) == OpenResult::Success);
    emit reloadFinished(success);
    return success;
}

bool ImageViewerFile::isPaused() const
{
    return m_isPaused;
}

void ImageViewerFile::setPaused(bool paused)
{
    if (!m_movie || m_isPaused == paused)
        return;
    m_isPaused = paused;
    m_movie->setPaused(paused);
    emit isPausedChanged(m_isPaused);
}

QGraphicsItem *ImageViewerFile::createGraphicsItem() const
{
    QGraphicsItem *val = 0;
    switch (m_type) {
    case TypeInvalid:
        break;
    case TypeSvg:
#ifndef QT_NO_SVG
        if (m_tempSvgItem) {
            val = m_tempSvgItem;
            m_tempSvgItem = 0;
        } else {
            val = new QGraphicsSvgItem(filePath().toString());
        }
#endif
        break;
    case TypeMovie:
        val = new MovieItem(m_movie);
        break;
    case TypePixmap: {
        auto pixmapItem = new QGraphicsPixmapItem(*m_pixmap);
        pixmapItem->setTransformationMode(Qt::SmoothTransformation);
        val = pixmapItem;
        break;
    }
    default:
        break;
    }
    return val;
}

ImageViewerFile::ImageType ImageViewerFile::type() const
{
    return m_type;
}

void ImageViewerFile::updateVisibility()
{
    if (!m_movie || m_isPaused)
        return;
    bool visible = false;
    foreach (Core::IEditor *editor, Core::DocumentModel::editorsForDocument(this)) {
        if (editor->widget()->isVisible()) {
            visible = true;
            break;
        }
    }
    m_movie->setPaused(!visible);
}

void ImageViewerFile::cleanUp()
{
    delete m_pixmap;
    delete m_movie;
#ifndef QT_NO_SVG
    delete m_tempSvgItem;
#endif
}

bool ImageViewerFile::save(QString *errorString, const QString &fileName, bool autoSave)
{
    Q_UNUSED(errorString)
    Q_UNUSED(fileName);
    Q_UNUSED(autoSave)
    return false;
}

bool ImageViewerFile::setContents(const QByteArray &contents)
{
    Q_UNUSED(contents);
    return false;
}

QString ImageViewerFile::defaultPath() const
{
    return QString();
}

QString ImageViewerFile::suggestedFileName() const
{
    return QString();
}

bool ImageViewerFile::isModified() const
{
    return false;
}

bool ImageViewerFile::isSaveAsAllowed() const
{
    return false;
}

} // namespace Internal
} // namespace ImageViewer
<commit_msg>ImageViewer: fix crash<commit_after>/**************************************************************************
**
** Copyright (C) 2015 Denis Mingulov.
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "imageviewerfile.h"
#include "imageviewer.h"
#include "imageviewerconstants.h"

#include <coreplugin/editormanager/documentmodel.h>
#include <utils/fileutils.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>

#include <QFileInfo>
#include <QGraphicsPixmapItem>
#ifndef QT_NO_SVG
#include <QGraphicsSvgItem>
#endif
#include <QImageReader>
#include <QMovie>
#include <QPainter>
#include <QPixmap>

namespace ImageViewer {
namespace Internal {

class MovieItem : public QObject, public QGraphicsPixmapItem
{
public:
    MovieItem(QMovie *movie)
        : m_movie(movie)
    {
        setPixmap(m_movie->currentPixmap());
        connect(m_movie, &QMovie::updated, this, [this](const QRectF &rect) {
            update(rect);
        });
    }

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
    {
        const bool smoothTransform = painter->worldTransform().m11() < 1;
        painter->setRenderHint(QPainter::SmoothPixmapTransform, smoothTransform);
        painter->drawPixmap(offset(), m_movie->currentPixmap());
    }

private:
    QMovie *m_movie;
};

ImageViewerFile::ImageViewerFile()
{
    setId(Constants::IMAGEVIEWER_ID);
    connect(this, &ImageViewerFile::mimeTypeChanged, this, &ImageViewerFile::changed);
}

ImageViewerFile::~ImageViewerFile()
{
    cleanUp();
}

Core::IDocument::OpenResult ImageViewerFile::open(QString *errorString, const QString &fileName,
                                                  const QString &realFileName)
{
    QTC_CHECK(fileName == realFileName); // does not support auto save
    OpenResult success = openImpl(errorString, fileName);
    emit openFinished(success == OpenResult::Success);
    return success;
}

Core::IDocument::OpenResult ImageViewerFile::openImpl(QString *errorString, const QString &fileName)
{
    cleanUp();

    if (!QFileInfo(fileName).isReadable())
        return OpenResult::ReadError;

    QByteArray format = QImageReader::imageFormat(fileName);
    // if it is impossible to recognize a file format - file will not be open correctly
    if (format.isEmpty()) {
        if (errorString)
            *errorString = tr("Image format not supported.");
        return OpenResult::CannotHandle;
    }

#ifndef QT_NO_SVG
    if (format.startsWith("svg")) {
        m_tempSvgItem = new QGraphicsSvgItem(fileName);
        QRectF bound = m_tempSvgItem->boundingRect();
        if (bound.width() == 0 && bound.height() == 0) {
            delete m_tempSvgItem;
            m_tempSvgItem = 0;
            if (errorString)
                *errorString = tr("Failed to read SVG image.");
            return OpenResult::CannotHandle;
        }
        m_type = TypeSvg;
        emit imageSizeChanged(QSize());
    } else
#endif
    if (QMovie::supportedFormats().contains(format)) {
        m_type = TypeMovie;
        m_movie = new QMovie(fileName, QByteArray(), this);
        m_movie->setCacheMode(QMovie::CacheAll);
        connect(m_movie, &QMovie::finished, m_movie, &QMovie::start);
        connect(m_movie, &QMovie::resized, this, &ImageViewerFile::imageSizeChanged);
        m_movie->start();
        m_isPaused = false; // force update
        setPaused(true);
    } else {
        m_pixmap = new QPixmap(fileName);
        if (m_pixmap->isNull()) {
            if (errorString)
                *errorString = tr("Failed to read image.");
            delete m_pixmap;
            m_pixmap = 0;
            return OpenResult::CannotHandle;
        }
        m_type = TypePixmap;
        emit imageSizeChanged(m_pixmap->size());
    }

    setFilePath(Utils::FileName::fromString(fileName));
    Utils::MimeDatabase mdb;
    setMimeType(mdb.mimeTypeForFile(fileName).name());
    return OpenResult::Success;
}

Core::IDocument::ReloadBehavior ImageViewerFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
{
    if (type == TypeRemoved || type == TypePermissions)
        return BehaviorSilent;
    if (type == TypeContents && state == TriggerInternal && !isModified())
        return BehaviorSilent;
    return BehaviorAsk;
}

bool ImageViewerFile::reload(QString *errorString,
                             Core::IDocument::ReloadFlag flag,
                             Core::IDocument::ChangeType type)
{
    if (flag == FlagIgnore)
        return true;
    if (type == TypePermissions) {
        emit changed();
        return true;
    }
    emit aboutToReload();
    bool success = (openImpl(errorString, filePath().toString()) == OpenResult::Success);
    emit reloadFinished(success);
    return success;
}

bool ImageViewerFile::isPaused() const
{
    return m_isPaused;
}

void ImageViewerFile::setPaused(bool paused)
{
    if (!m_movie || m_isPaused == paused)
        return;
    m_isPaused = paused;
    m_movie->setPaused(paused);
    emit isPausedChanged(m_isPaused);
}

QGraphicsItem *ImageViewerFile::createGraphicsItem() const
{
    QGraphicsItem *val = 0;
    switch (m_type) {
    case TypeInvalid:
        break;
    case TypeSvg:
#ifndef QT_NO_SVG
        if (m_tempSvgItem) {
            val = m_tempSvgItem;
            m_tempSvgItem = 0;
        } else {
            val = new QGraphicsSvgItem(filePath().toString());
        }
#endif
        break;
    case TypeMovie:
        val = new MovieItem(m_movie);
        break;
    case TypePixmap: {
        auto pixmapItem = new QGraphicsPixmapItem(*m_pixmap);
        pixmapItem->setTransformationMode(Qt::SmoothTransformation);
        val = pixmapItem;
        break;
    }
    default:
        break;
    }
    return val;
}

ImageViewerFile::ImageType ImageViewerFile::type() const
{
    return m_type;
}

void ImageViewerFile::updateVisibility()
{
    if (!m_movie || m_isPaused)
        return;
    bool visible = false;
    foreach (Core::IEditor *editor, Core::DocumentModel::editorsForDocument(this)) {
        if (editor->widget()->isVisible()) {
            visible = true;
            break;
        }
    }
    m_movie->setPaused(!visible);
}

void ImageViewerFile::cleanUp()
{
    delete m_pixmap;
    m_pixmap = 0;
    delete m_movie;
    m_movie = 0;
#ifndef QT_NO_SVG
    delete m_tempSvgItem;
    m_tempSvgItem = 0;
#endif
    m_type = TypeInvalid;
}

bool ImageViewerFile::save(QString *errorString, const QString &fileName, bool autoSave)
{
    Q_UNUSED(errorString)
    Q_UNUSED(fileName);
    Q_UNUSED(autoSave)
    return false;
}

bool ImageViewerFile::setContents(const QByteArray &contents)
{
    Q_UNUSED(contents);
    return false;
}

QString ImageViewerFile::defaultPath() const
{
    return QString();
}

QString ImageViewerFile::suggestedFileName() const
{
    return QString();
}

bool ImageViewerFile::isModified() const
{
    return false;
}

bool ImageViewerFile::isSaveAsAllowed() const
{
    return false;
}

} // namespace Internal
} // namespace ImageViewer
<|endoftext|>