<commit_before>#include <osg/Image>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/GL>

#include <osgDB/Registry>

/****************************************************************************
 *
 * Follows is code written by GWM and translated to fit with the OSG Ethos.
 *
 *
 * Ported into the OSG as a plugin, Geoff Michel October 2001.
 * For patches, bugs and new features
 * please send them direct to the OSG dev team.
 *
 **********************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

enum { ERROR_NO_ERROR =0,ERROR_READING_HEADER,ERROR_READING_PALETTE, ERROR_MEMORY, ERROR_READ_ERROR,
ERROR_NO_FILE,ERROR_READING_COLORS};

static int bmperror = ERROR_NO_ERROR;

// BMP format bits - at start of file is 512 bytes of pure garbage
enum ftype {MB=19778}; // magic number identifies a bmp file; actually chars 'B''M'
// allowed ftypes are 'BM'  for windoze;  OS2 allows:
//'BA' - Bitmap Array
//'CI' - Color Icon
//'CP' - Color Pointer (mouse cursor)
//'IC' - Icon
//'PT' - Pointer (mouse cursor)

enum ncol { BW=1, IA, RGB, RGBA};

struct bmpheader {
    short FileType; //always MB
    unsigned short siz[2]; // a dword for whole file size - make unsigned Feb 2002
    short Reserved1, Reserved2; //reserved for future purposes
    short offset[2]; //offset to image in bytes
};
struct BMPInfo {
    long width;   //width of the image in pixels
    long height;    //   height of the image in pixels
    short planes;       //:word: number of planes (always 1)
    short Colorbits;       //word: number of bits used to describe color in each pixel
    long compression;  //compression used
    long ImageSize;    //image size in bytes
    long XpixPerMeter; //pixels per meter in X
    long YpixPerMeter; //pixels per meter in Y
    long ColorUsed;   //number of colors used
    long Important;   //number of "important" colors
    long os2stuff[6]; // allows os2.1 with 64 bytes to be read.  Dont know what these are yet.
};

int
bmp_error(char *buffer, int bufferlen)
{
    switch (bmperror)
    {
        case ERROR_READING_COLORS:
            strncpy(buffer, "BMP loader: Error reading colours", bufferlen);
            break;
        case ERROR_READING_HEADER:
            strncpy(buffer, "BMP loader: Error reading header", bufferlen);
            break;
        case ERROR_READING_PALETTE:
            strncpy(buffer, "BMP loader: Error reading palette", bufferlen);
            break;
        case ERROR_MEMORY:
            strncpy(buffer, "BMP loader: Out of memory error", bufferlen);
            break;
        case ERROR_READ_ERROR:
            strncpy(buffer, "BMP loader: Read error", bufferlen);
            break;
    }
    return bmperror;
}

/* byte order workarounds *sigh* */
void swapbyte(long *i)
{
    char *vv=(char *)i;
    char tmp=vv[0];
    vv[0]=vv[3];
    vv[3]=tmp;
    tmp=vv[1];
    vv[1]=vv[2];
    vv[2]=tmp;
}
void swapbyte(unsigned long *i)
{
    char *vv=(char *)i;
    char tmp=vv[0];
    vv[0]=vv[3];
    vv[3]=tmp;
    tmp=vv[1];
    vv[1]=vv[2];
    vv[2]=tmp;
}
void swapbyte(float *i)
{
    char *vv=(char *)i;
    char tmp=vv[0];
    vv[0]=vv[3];
    vv[3]=tmp;
    tmp=vv[1];
    vv[1]=vv[2];
    vv[2]=tmp;
}
void swapbyte(unsigned short *i)
{
    char *vv=(char *)i;
    char tmp=vv[0];
    vv[0]=vv[1];
    vv[1]=tmp;
}
void swapbyte(short *i)
{
    char *vv=(char *)i;
    char tmp=vv[0];
    vv[0]=vv[1];
    vv[1]=tmp;
}

unsigned char *
bmp_load(const char *filename,
int *width_ret,
int *height_ret,
int *numComponents_ret)
{ // the main area of changes from the pic format loader.
    // reads filename, and returns the buffer
    // bmp is very very simple format
    // even Master Gates could have invented it.
    // It is extremely expensive on disk space - every RGB pixel uses 3 bytes plus a header!
    // BMP - sponsored by Seagate.
 //   unsigned char palette[256][3];
    unsigned char *buffer=NULL; // returned to sender & as read from the disk

    bmperror = ERROR_NO_FILE;

    FILE *fp = fopen(filename, "rb");
    if (!fp) return NULL;

    int ncolours;
    int ncomp=0;
    bool swap=false; // dont need to swap bytes
     // actual size of the bitmap header; 12=os2; 40 = normal; 64=os2.1

    struct bmpheader hd;
    struct BMPInfo inf;
    bmperror = ERROR_NO_ERROR;
    fread((char *)&hd, sizeof(bmpheader), 1, fp);
    if (hd.FileType != MB) {
        swapbyte(&(hd.FileType));
        swap=true;
        if (hd.FileType != MB) {
            bmperror=ERROR_READING_HEADER;
        }
    }
    if (hd.FileType == MB) {
        long infsize;    //size of BMPinfo in bytes
        unsigned char *cols=NULL; // dynamic colour palette
        unsigned char *imbuff; // returned to sender & as read from the disk
        fread((char *)&infsize, sizeof(long), 1, fp); // insert inside 'the file is bmp' clause
        if (swap) swapbyte(&infsize);
        if ((infsize-sizeof(long))<sizeof(inf)) { // then the next bytes appear to be valid - actually infsize must be 12,40,64
            fread((char *)&inf, infsize-sizeof(long), 1, fp);
            if (swap) { // inverse the field of the header which need swapping
                swapbyte(&hd.siz[0]);
                swapbyte(&hd.siz[1]);
                swapbyte(&inf.Colorbits);
                swapbyte(&inf.width);
                swapbyte(&inf.height);
                swapbyte(&inf.ImageSize);
            }
            if (infsize==12) { // os2, protect us from our friends ? || infsize==64
                int wd = inf.width&0xffff; // shorts replace longs
                int ht = inf.width>>16;
                int npln = inf.height&0xffff; // number of planes
                int cbits = inf.height>>16;
                inf.width=wd;
                inf.height=ht;
                inf.planes=npln;
                inf.Colorbits=cbits;
                inf.ColorUsed=(long)pow(2.0,(double)inf.Colorbits); // infer the colours
            }
            long size = hd.siz[1]*65536+hd.siz[0];
            int ncpal=4; // default number of colours per palette entry
            size -= sizeof(bmpheader)+infsize;
            if (inf.ImageSize<size) inf.ImageSize=size;
            imbuff = (unsigned char *)malloc( inf.ImageSize); // read from disk
            fread((char *)imbuff, sizeof(unsigned char),inf.ImageSize, fp);
            ncolours=inf.Colorbits/8;
            switch (ncolours) {
            case 1:
                ncomp = BW; // actually this is a 256 colour, paletted image
                inf.Colorbits=8; // so this is how many bits there are per index
                inf.ColorUsed=256; // and number of colours used
                cols=imbuff; // colour palette address - uses 4 bytes/colour
                break;
            case 2:
                ncomp = IA;
                break;
            case 3:
                ncomp = RGB;
                break;
            case 4:
                ncomp = RGBA;
                break;
            default:
                cols=imbuff; // colour palette address - uses 4 bytes/colour
                if (infsize==12 || infsize==64) ncpal=3; // OS2 - uses 3 colours per palette entry
                else ncpal=4; // Windoze uses 4!
            }
            if (ncomp>0) buffer = (unsigned char *)malloc( (ncomp==BW?3:ncomp)*inf.width*inf.height*sizeof(unsigned char)); // to be returned
            else buffer = (unsigned char *)malloc( 3*inf.width*inf.height*sizeof(unsigned char)); // default full colour to be returned

            unsigned long off=0;
            unsigned long rowbytes=ncomp*sizeof(unsigned char)*inf.width;
            unsigned long doff=(rowbytes)/4;
            if ((rowbytes%4)) doff++; // round up if needed
            doff*=4; // to find dword alignment
            for(int j=0; j<inf.height; j++) {
                if (ncomp>BW) memcpy(buffer+j*rowbytes, imbuff+off, rowbytes); // pack bytes closely
                else { // find from the palette..
                    unsigned char *imptr=imbuff+inf.ColorUsed*ncpal; // add size of the palette- start of image
                    int npixperbyte=8/inf.Colorbits; // no of pixels per byte
                    for (int ii=0; ii<inf.width/npixperbyte; ii++) {
                        unsigned char mask=0x00; // masked with index to extract colorbits bits
                        unsigned char byte=imptr[(j*inf.width/npixperbyte)+ii];
                        int jj;
                        for (jj=0; jj<inf.Colorbits; jj++) mask |= (0x80>>jj); // fill N High end bits
                        for (jj=0; jj<npixperbyte; jj++) {
                            int colidx=(byte&mask)>>((npixperbyte-1-jj)*inf.Colorbits);
                            buffer[3*(j*inf.width+ii*npixperbyte+jj)+0]=cols[ncpal*colidx+2];
                            buffer[3*(j*inf.width+ii*npixperbyte+jj)+1]=cols[ncpal*colidx+1];
                            buffer[3*(j*inf.width+ii*npixperbyte+jj)+2]=cols[ncpal*colidx];
                            mask>>=inf.Colorbits;
                        }
                    }
                }
                off+=doff;
                if (ncomp>2) { // yes bill, colours are usually BGR aren't they
                    for(int i=0; i<inf.width; i++) {
                        int ijw=i+j*inf.width;
                        unsigned char blu=buffer[3*ijw+0];
                        buffer[3*ijw+0]=buffer[3*ijw+2]; // swap order of colours
                        buffer[3*ijw+2]=blu;
                    }
                }
            }
            delete [] imbuff; // free the on-disk storage
        }

        fclose(fp);

    }
    else // else error in header
    {
        fclose(fp);
        return NULL;
    }
    *width_ret = inf.width;
    *height_ret = inf.height;
    switch (ncomp) {
    case BW:
        *numComponents_ret = 3;
        break;
    case IA:
    case RGB:
    case RGBA:
        *numComponents_ret = ncomp;
        break;
    default:
        *numComponents_ret = 3;
        break;
    }

    return buffer;
}

class ReaderWriterBMP : public osgDB::ReaderWriter
{
    public:
        virtual const char* className() { return "BMP Image Reader"; }
        virtual bool acceptsExtension(const std::string& extension) { return extension=="bmp"; }

        virtual ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options*)
        {

            unsigned char *imageData = NULL;
            int width_ret;
            int height_ret;
            int numComponents_ret;

            imageData = bmp_load(fileName.c_str(),&width_ret,&height_ret,&numComponents_ret);

            if (imageData==NULL) return ReadResult::FILE_NOT_HANDLED;

            int s = width_ret;
            int t = height_ret;
            int r = 1;

            int internalFormat = numComponents_ret;

            unsigned int pixelFormat =
                numComponents_ret == 1 ? GL_LUMINANCE :
            numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
            numComponents_ret == 3 ? GL_RGB :
            numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;

            unsigned int dataType = GL_UNSIGNED_BYTE;

            osg::Image* pOsgImage = new osg::Image;
            pOsgImage->setFileName(fileName.c_str());
            pOsgImage->setImage(s,t,r,
                internalFormat,
                pixelFormat,
                dataType,
                imageData);

            return pOsgImage;

        }
};

// now register with Registry to instantiate the above
// reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterBMP> g_readerWriter_BMP_Proxy;
<commit_msg>Addition of write .bmp to the BMP plugin.<commit_after>#include <osg/Image>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/Image>
#include <osg/GL>

#include <osgDB/Registry>

/****************************************************************************
 *
 * Follows is code written by GWM and translated to fit with the OSG Ethos.
 *
 *
 * Ported into the OSG as a plugin, Geoff Michel October 2001.
 * For patches, bugs and new features
 * please send them direct to the OSG dev team.
 *
 **********************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

enum { ERROR_NO_ERROR =0,ERROR_READING_HEADER,ERROR_READING_PALETTE, ERROR_MEMORY, ERROR_READ_ERROR,
ERROR_NO_FILE,ERROR_READING_COLORS};

static int bmperror = ERROR_NO_ERROR;

// BMP format bits - at start of file is 512 bytes of pure garbage
enum ftype {MB=19778}; // magic number identifies a bmp file; actually chars 'B''M'
// allowed ftypes are 'BM'  for windoze;  OS2 allows:
//'BA' - Bitmap Array
//'CI' - Color Icon
//'CP' - Color Pointer (mouse cursor)
//'IC' - Icon
//'PT' - Pointer (mouse cursor)

enum ncol { BW=1, IA, RGB, RGBA};

struct bmpheader {
    short FileType; //always MB
    unsigned short siz[2]; // a dword for whole file size - make unsigned Feb 2002
    short Reserved1, Reserved2; //reserved for future purposes
    unsigned short offset[2]; //offset to image in bytes
};

struct BMPInfo {
    long width;   //width of the image in pixels
    long height;    //   height of the image in pixels
    short planes;       //:word: number of planes (always 1)
    short Colorbits;       //word: number of bits used to describe color in each pixel
    long compression;  //compression used
    long ImageSize;    //image size in bytes
    long XpixPerMeter; //pixels per meter in X
    long YpixPerMeter; //pixels per meter in Y
    long ColorUsed;   //number of colors used
    long Important;   //number of "important" colors
//    unsigned char rgbquad[4];
 //   long os2stuff[6]; // storage for os2.1 with 64 bytes to be read.  Dont know what these are yet.
};

int
bmp_error(char *buffer, int bufferlen)
{
    switch (bmperror)
    {
        case ERROR_READING_COLORS:
            strncpy(buffer, "BMP loader: Error reading colours", bufferlen);
            break;
        case ERROR_READING_HEADER:
            strncpy(buffer, "BMP loader: Error reading header", bufferlen);
            break;
        case ERROR_READING_PALETTE:
            strncpy(buffer, "BMP loader: Error reading palette", bufferlen);
            break;
        case ERROR_MEMORY:
            strncpy(buffer, "BMP loader: Out of memory error", bufferlen);
            break;
        case ERROR_READ_ERROR:
            strncpy(buffer, "BMP loader: Read error", bufferlen);
            break;
    }
    return bmperror;
}

/* byte order workarounds *sigh* */
void swapbyte(long *i)
{
    char *vv=(char *)i;
    char tmp=vv[0];
    vv[0]=vv[3];
    vv[3]=tmp;
    tmp=vv[1];
    vv[1]=vv[2];
    vv[2]=tmp;
}
void swapbyte(unsigned long *i)
{
    char *vv=(char *)i;
    char tmp=vv[0];
    vv[0]=vv[3];
    vv[3]=tmp;
    tmp=vv[1];
    vv[1]=vv[2];
    vv[2]=tmp;
}
void swapbyte(float *i)
{
    char *vv=(char *)i;
    char tmp=vv[0];
    vv[0]=vv[3];
    vv[3]=tmp;
    tmp=vv[1];
    vv[1]=vv[2];
    vv[2]=tmp;
}
void swapbyte(unsigned short *i)
{
    char *vv=(char *)i;
    char tmp=vv[0];
    vv[0]=vv[1];
    vv[1]=tmp;
}
void swapbyte(short *i)
{
    char *vv=(char *)i;
    char tmp=vv[0];
    vv[0]=vv[1];
    vv[1]=tmp;
}

unsigned char *
bmp_load(const char *filename,
int *width_ret,
int *height_ret,
int *numComponents_ret)
{ // the main area of changes from the pic format loader.
    // reads filename, and returns the buffer
    // bmp is very very simple format
    // even Master Gates could have invented it.
    // It is extremely expensive on disk space - every RGB pixel uses 3 bytes plus a header!
    // BMP - sponsored by Seagate.
 //   unsigned char palette[256][3];
    unsigned char *buffer=NULL; // returned to sender & as read from the disk

    bmperror = ERROR_NO_FILE;
    FILE *fp = fopen(filename, "rb");
    if (!fp) return NULL;

    int ncolours;
    int ncomp=0;
    bool swap=false; // dont need to swap bytes
     // actual size of the bitmap header; 12=os2; 40 = normal; 64=os2.1

    struct bmpheader hd;
    struct BMPInfo inf;
    bmperror = ERROR_NO_ERROR;
    fread((char *)&hd, sizeof(bmpheader), 1, fp);
    if (hd.FileType != MB) {
        swapbyte(&(hd.FileType));
        swap=true;
        if (hd.FileType != MB) {
            bmperror=ERROR_READING_HEADER;
        }
    }
    if (hd.FileType == MB) {
        long infsize;    //size of BMPinfo in bytes
        unsigned char *cols=NULL; // dynamic colour palette
        unsigned char *imbuff; // returned to sender & as read from the disk
        fread((char *)&infsize, sizeof(long), 1, fp); // insert inside 'the file is bmp' clause
        if (swap) swapbyte(&infsize);
        unsigned char *hdr=new unsigned char[infsize]; // to hold the new header
        fread((char *)hdr, 1,infsize-sizeof(long), fp);
        unsigned long hsiz=sizeof(inf); // minimum of structure size &
        if(infsize<=hsiz) hsiz=infsize;
        memcpy(&inf,hdr, hsiz/*-sizeof(long)*/); // copy only the bytes I can cope with
        delete [] hdr;
        osg::notify(osg::WARN) << "loading "<<filename <<" "<<swap<<" "<<infsize<< " "<<sizeof(inf) << " "<<sizeof(bmpheader) << std::endl;
        if (swap) { // inverse the field of the header which need swapping
            swapbyte(&hd.siz[0]);
            swapbyte(&hd.siz[1]);
            swapbyte(&inf.Colorbits);
            swapbyte(&inf.width);
            swapbyte(&inf.height);
            swapbyte(&inf.ImageSize);
        }
        if (infsize==12) { // os2, protect us from our friends ? || infsize==64
            int wd = inf.width&0xffff; // shorts replace longs
            int ht = inf.width>>16;
            int npln = inf.height&0xffff; // number of planes
            int cbits = inf.height>>16;
            inf.width=wd;
            inf.height=ht;
            inf.planes=npln;
            inf.Colorbits=cbits;
            inf.ColorUsed=(long)pow(2.0,(double)inf.Colorbits); // infer the colours
        }
        osg::notify(osg::WARN) << "readbmp " <<inf.width<< " "<<inf.height << std::endl;
        long size = hd.siz[1]+hd.siz[0]*65536;
        int ncpal=4; // default number of colours per palette entry
        size -= sizeof(bmpheader)+infsize;
        if (inf.ImageSize<size) inf.ImageSize=size;
        imbuff = (unsigned char *)malloc( inf.ImageSize); // read from disk
        fread((char *)imbuff, sizeof(unsigned char),inf.ImageSize, fp);
        ncolours=inf.Colorbits/8;
        switch (ncolours) {
        case 1:
            ncomp = BW; // actually this is a 256 colour, paletted image
            inf.Colorbits=8; // so this is how many bits there are per index
            inf.ColorUsed=256; // and number of colours used
            cols=imbuff; // colour palette address - uses 4 bytes/colour
            break;
        case 2:
            ncomp = IA;
            break;
        case 3:
            ncomp = RGB;
            break;
        case 4:
            ncomp = RGBA;
            break;
        default:
            cols=imbuff; // colour palette address - uses 4 bytes/colour
            if (infsize==12 || infsize==64) ncpal=3; // OS2 - uses 3 colours per palette entry
            else ncpal=4; // Windoze uses 4!
        }
        if (ncomp>0) buffer = (unsigned char *)malloc( (ncomp==BW?3:ncomp)*inf.width*inf.height*sizeof(unsigned char)); // to be returned
        else buffer = (unsigned char *)malloc( 3*inf.width*inf.height*sizeof(unsigned char)); // default full colour to be returned

        unsigned long off=0;
        unsigned long rowbytes=ncomp*sizeof(unsigned char)*inf.width;
        unsigned long doff=(rowbytes)/4;
        if ((rowbytes%4)) doff++; // round up if needed
        doff*=4; // to find dword alignment
        for(int j=0; j<inf.height; j++) {
            if (ncomp>BW) memcpy(buffer+j*rowbytes, imbuff+off, rowbytes); // pack bytes closely
            else { // find from the palette..
                unsigned char *imptr=imbuff+inf.ColorUsed*ncpal; // add size of the palette- start of image
                int npixperbyte=8/inf.Colorbits; // no of pixels per byte
                for (int ii=0; ii<inf.width/npixperbyte; ii++) {
                    unsigned char mask=0x00; // masked with index to extract colorbits bits
                    unsigned char byte=imptr[(j*inf.width/npixperbyte)+ii];
                    int jj;
                    for (jj=0; jj<inf.Colorbits; jj++) mask |= (0x80>>jj); // fill N High end bits
                    for (jj=0; jj<npixperbyte; jj++) {
                        int colidx=(byte&mask)>>((npixperbyte-1-jj)*inf.Colorbits);
                        buffer[3*(j*inf.width+ii*npixperbyte+jj)+0]=cols[ncpal*colidx+2];
                        buffer[3*(j*inf.width+ii*npixperbyte+jj)+1]=cols[ncpal*colidx+1];
                        buffer[3*(j*inf.width+ii*npixperbyte+jj)+2]=cols[ncpal*colidx];
                        mask>>=inf.Colorbits;
                    }
                }
            }
            off+=doff;
            if (ncomp>2) { // yes bill, colours are usually BGR aren't they
                for(int i=0; i<inf.width; i++) {
                    int ijw=i+j*inf.width;
                    unsigned char blu=buffer[3*ijw+0];
                    buffer[3*ijw+0]=buffer[3*ijw+2]; // swap order of colours
                    buffer[3*ijw+2]=blu;
                }
            }
        }
        delete [] imbuff; // free the on-disk storage

        fclose(fp);

    }
    else // else error in header
    {
        fclose(fp);
        return NULL;
    }
    *width_ret = inf.width;
    *height_ret = inf.height;
    switch (ncomp) {
    case BW:
        *numComponents_ret = 3;
        break;
    case IA:
    case RGB:
    case RGBA:
        *numComponents_ret = ncomp;
        break;
    default:
        *numComponents_ret = 3;
        break;
    }

    return buffer;
}

class ReaderWriterBMP : public osgDB::ReaderWriter
{
    public:
        virtual const char* className() { return "BMP Image Reader"; }
        virtual bool acceptsExtension(const std::string& extension) { return extension=="bmp"; }

        virtual ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options*)
        {

            unsigned char *imageData = NULL;
            int width_ret;
            int height_ret;
            int numComponents_ret;

            imageData = bmp_load(fileName.c_str(),&width_ret,&height_ret,&numComponents_ret);

            if (imageData==NULL) return ReadResult::FILE_NOT_HANDLED;

            int s = width_ret;
            int t = height_ret;
            int r = 1;

            int internalFormat = numComponents_ret;

            unsigned int pixelFormat =
                numComponents_ret == 1 ? GL_LUMINANCE :
            numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
            numComponents_ret == 3 ? GL_RGB :
            numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;

            unsigned int dataType = GL_UNSIGNED_BYTE;

            osg::Image* pOsgImage = new osg::Image;
            pOsgImage->setFileName(fileName.c_str());
            pOsgImage->setImage(s,t,r,
                internalFormat,
                pixelFormat,
                dataType,
                imageData);

            return pOsgImage;

        }
        virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options* op)
        {
            FILE *fp = fopen(fileName.c_str(), "wb");
            if (!fp) return WriteResult::ERROR_IN_WRITING_FILE;
            // its easier for me to write a binary write using stdio than streams
            struct bmpheader hd;
            unsigned long nx=img.s(),ny=img.t(), ndep=img.r();
            unsigned long size, wordsPerScan;
            long infsize;    //size of BMPinfo in bytes
            wordsPerScan=(nx*3+3)/4; // rounds up to next 32 bit boundary
            size=4*ny*wordsPerScan; // rounded to 4bytes * number of scan lines
            hd.FileType=MB;
            hd.Reserved1=hd.Reserved2=0; // offset to image
            hd.offset[0]=sizeof(long)+sizeof(BMPInfo)+sizeof(hd); // 26; // offset to image
            hd.offset[1]=0; // offset to image
            hd.siz[0]=(size&0xffff0000)>>16; // high word
            hd.siz[1]=(size&0xffff); // low word
            fwrite(&hd, sizeof(hd), 1, fp);
            struct BMPInfo inf;
            osg::notify(osg::WARN) << "sizes "<<size << " "<<sizeof(inf)<< std::endl;
            inf.width=nx;   //width of the image in pixels
            inf.height=ny;    //   height of the image in pixels
            inf.planes=1;       //:word: number of planes (always 1)
            inf.Colorbits=24;       //word: number of bits used to describe color in each pixel
            inf.compression=0;  //compression used windows says 0= no compression
            inf.ImageSize=size;    //nx*ny*3; //image size in bytes
            inf.XpixPerMeter=.001; //pixels per meter in X
            inf.YpixPerMeter=.001; //pixels per meter in Y
            inf.ColorUsed=0;   //number of colors used
            inf.Important=0;   //number of "important" colors
   // inf.os2stuff[6]; // allows os2.1 with 64 bytes to be read.  Dont know what these are yet.
            infsize=sizeof(BMPInfo)+sizeof(long);
            fwrite(&infsize, sizeof(long), 1, fp);
            fwrite(&inf, sizeof(inf), 1, fp); // one dword shorter than the structure defined by MS
              // the infsize value (above) completes the structure.
            osg::notify(osg::WARN) << "save screen "<<fileName <<inf.width<< " "<<inf.height << std::endl;
            osg::notify(osg::WARN) << "sizes "<<size << " "<<infsize <<" "<<sizeof(inf)<< std::endl;
            // now output the bitmap
            // 1) swap Blue with Red - needed for Windoss.
            unsigned char *dta=new unsigned char[size];
            unsigned char tmp;
            memcpy(dta,img.data(),size*sizeof(unsigned char));
            for(int i=0;i<ny;i++) { // per scanline
                int ioff=4*wordsPerScan*i;
                for(int j=0;j<nx;j++) {
                tmp=dta[3*j+ioff]; // swap r with b,  thanks to good ole Bill -
  //"Let's use BGR it's more logical than rgb which everyone else uses."
                dta[3*j+ioff]=dta[3*j+ioff+2];
                dta[3*j+ioff+2]=tmp;
                }
            }
            fwrite(dta, sizeof(unsigned char), size, fp);
            delete [] dta;

            fclose(fp);
            return WriteResult::FILE_SAVED;
        }
};

// now register with Registry to instantiate the above
// reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterBMP> g_readerWriter_BMP_Proxy;
<|endoftext|>


<commit_before>#include <sstream>
#include <memory>
#include <cassert>

#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/Material>
#include <osg/PositionAttitudeTransform>
#include <osg/Texture2D>
#include <osgDB/ConvertUTF>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/ReadFile>
#include <osgDB/Registry>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/Bone>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/Skeleton>
#include <osgAnimation/VertexInfluence>

#if defined(_MSC_VER)
    #pragma warning( disable : 4505 )
#endif
#include <fbxsdk.h>

#include "ReaderWriterFBX.h"
#include "fbxRNode.h"
#include "fbxMaterialToOsgStateSet.h"
#include "WriterNodeVisitor.h"

/// Returns true if the given node is a basic root group with no special information.
/// Used in conjunction with UseFbxRoot option.
/// Identity transforms are considered as basic root nodes.
bool isBasicRootNode(const osg::Node& node)
{
    const osg::Group* osgGroup = node.asGroup();
    if (!osgGroup)
    {
        // Geodes & such are not basic root nodes
        return false;
    }

    // Test if we've got an empty transform (= a group!)
    const osg::Transform* transform = osgGroup->asTransform();
    if (transform)
    {
        if (const osg::MatrixTransform* matrixTransform = transform->asMatrixTransform())
        {
            if (!matrixTransform->getMatrix().isIdentity())
            {
                // Non-identity matrix transform
                return false;
            }
        }
        else if (const osg::PositionAttitudeTransform* pat = transform->asPositionAttitudeTransform())
        {
            if (pat->getPosition() != osg::Vec3d() ||
                pat->getAttitude() != osg::Quat() ||
                pat->getScale() != osg::Vec3d(1.0f, 1.0f, 1.0f) ||
                pat->getPivotPoint() != osg::Vec3d())
            {
                // Non-identity position attribute transform
                return false;
            }
        }
        else
        {
            // Other transform (not identity or not predefined type)
            return false;
        }
    }

    // Test the presence of a non-empty stateset
    if (node.getStateSet())
    {
        osg::ref_ptr<osg::StateSet> emptyStateSet = new osg::StateSet;
        if (node.getStateSet()->compare(*emptyStateSet, true) != 0)
        {
            return false;
        }
    }

    return true;
}

class CleanUpFbx
{
    KFbxSdkManager* m_pSdkManager;
public:
    explicit CleanUpFbx(KFbxSdkManager* pSdkManager) : m_pSdkManager(pSdkManager)
    {}

    ~CleanUpFbx()
    {
        KFbxIOSettings::IOSettingsRef().FreeIOSettings();
        m_pSdkManager->Destroy();
    }
};

void resolveBindMatrices(
    osg::Node& root,
    const BindMatrixMap& boneBindMatrices,
    const std::map<KFbxNode*, osg::Node*>& nodeMap)
{
    std::set<std::string> nodeNames;
    for (std::map<KFbxNode*, osg::Node*>::const_iterator it = nodeMap.begin(); it != nodeMap.end(); ++it)
    {
        nodeNames.insert(it->second->getName());
    }

    for (BindMatrixMap::const_iterator it = boneBindMatrices.begin();
        it != boneBindMatrices.end();)
    {
        KFbxNode* const fbxBone = it->first.first;
        std::map<KFbxNode*, osg::Node*>::const_iterator nodeIt = nodeMap.find(fbxBone);
        if (nodeIt != nodeMap.end())
        {
            const osg::Matrix bindMatrix = it->second;
            osgAnimation::Bone& osgBone = dynamic_cast<osgAnimation::Bone&>(*nodeIt->second);
            osgBone.setInvBindMatrixInSkeletonSpace(bindMatrix);

            ++it;
            for (; it != boneBindMatrices.end() && it->first.first == fbxBone; ++it)
            {
                if (it->second != bindMatrix)
                {
                    std::string name;
                    for (int i = 0;; ++i)
                    {
                        std::stringstream ss;
                        ss << osgBone.getName() << '_' << i;
                        name = ss.str();
                        if (nodeNames.insert(name).second)
                        {
                            break;
                        }
                    }
                    osgAnimation::Bone* newBone = new osgAnimation::Bone(name);
                    newBone->setDefaultUpdateCallback();
                    newBone->setInvBindMatrixInSkeletonSpace(it->second);
                    osgBone.addChild(newBone);

                    osgAnimation::RigGeometry* pRigGeometry = it->first.second;

                    osgAnimation::VertexInfluenceMap* vertexInfluences = pRigGeometry->getInfluenceMap();

                    osgAnimation::VertexInfluenceMap::iterator vimIt = vertexInfluences->find(osgBone.getName());
                    if (vimIt != vertexInfluences->end())
                    {
                        osgAnimation::VertexInfluence vi;
                        vi.swap(vimIt->second);
                        vertexInfluences->erase(vimIt);
                        osgAnimation::VertexInfluence& vi2 = (*vertexInfluences)[name];
                        vi.swap(vi2);
                        vi2.setName(name);
                    }
                    else
                    {
                        assert(0);
                    }
                }
            }
        }
        else
        {
            assert(0);
        }
    }
}

osgDB::ReaderWriter::ReadResult
ReaderWriterFBX::readNode(const std::string& filenameInit,
                          const Options* options) const
{
    try
    {
        std::string ext(osgDB::getLowerCaseFileExtension(filenameInit));
        if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

        std::string filename(osgDB::findDataFile(filenameInit, options));
        if (filename.empty()) return ReadResult::FILE_NOT_FOUND;

        KFbxSdkManager* pSdkManager = KFbxSdkManager::Create();

        if (!pSdkManager)
        {
            return ReadResult::ERROR_IN_READING_FILE;
        }

        CleanUpFbx cleanUpFbx(pSdkManager);

        KFbxScene* pScene = KFbxScene::Create(pSdkManager, "");

        // The FBX SDK interprets the filename as UTF-8
#ifdef OSG_USE_UTF8_FILENAME
        const std::string& utf8filename(filename);
#else
        std::string utf8filename(osgDB::convertStringFromCurrentCodePageToUTF8(filename));
#endif

        int fileFormat;
        if (!pSdkManager->GetIOPluginRegistry()->DetectFileFormat(utf8filename.c_str(), fileFormat))
        {
            return ReadResult::FILE_NOT_HANDLED;
        }
        KFbxImporter* lImporter = KFbxImporter::Create(pSdkManager, "");

        if (!lImporter->Initialize(utf8filename.c_str(), fileFormat))
        {
            return std::string(lImporter->GetLastErrorString());
        }

        if (!lImporter->IsFBX())
        {
            return ReadResult::ERROR_IN_READING_FILE;
        }

        for (int i = 0; i < lImporter->GetTakeCount(); i++)
        {
            KFbxTakeInfo* lTakeInfo = lImporter->GetTakeInfo(i);

            lTakeInfo->mSelect = true;
        }

        if (!lImporter->Import(pScene))
        {
            return std::string(lImporter->GetLastErrorString());
        }

        //KFbxAxisSystem::OpenGL.ConvertScene(pScene);        // Doesn't work as expected. Still need to transform vertices.

        if (KFbxNode* pNode = pScene->GetRootNode())
        {
            pScene->SetCurrentTake(pScene->GetCurrentTakeName());

            bool useFbxRoot = false;
            if (options)
            {
                std::istringstream iss(options->getOptionString());
                std::string opt;
                while (iss >> opt)
                {
                    if (opt == "UseFbxRoot")
                    {
                        useFbxRoot = true;
                    }
                }
            }

            osg::ref_ptr<osgAnimation::AnimationManagerBase> pAnimationManager;
            bool bIsBone = false;
            int nLightCount = 0;
            osg::ref_ptr<Options> localOptions = NULL;
            if (options)
                localOptions = options->cloneOptions();
            else
                localOptions = new osgDB::Options();
            localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_IMAGES);

            std::string filePath = osgDB::getFilePath(filename);
            FbxMaterialToOsgStateSet fbxMaterialToOsgStateSet(filePath, localOptions.get());

            std::map<KFbxNode*, osg::Node*> nodeMap;
            BindMatrixMap boneBindMatrices;
            std::map<KFbxNode*, osgAnimation::Skeleton*> skeletonMap;
            ReadResult res = readFbxNode(*pSdkManager, pNode, pAnimationManager,
                bIsBone, nLightCount, fbxMaterialToOsgStateSet, nodeMap,
                boneBindMatrices, skeletonMap, localOptions.get());

            if (res.success())
            {
                fbxMaterialToOsgStateSet.checkInvertTransparency();

                resolveBindMatrices(*res.getNode(), boneBindMatrices, nodeMap);

                osg::Node* osgNode = res.getNode();
                osgNode->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL,osg::StateAttribute::ON);
                osgNode->getOrCreateStateSet()->setMode(GL_NORMALIZE,osg::StateAttribute::ON);

                if (pAnimationManager.valid())
                {
                    if (osgNode->getUpdateCallback())
                    {
                        osg::Group* osgGroup = new osg::Group;
                        osgGroup->addChild(osgNode);
                        osgNode = osgGroup;
                    }

                    //because the animations may be altered after registering
                    pAnimationManager->buildTargetReference();
                    osgNode->setUpdateCallback(pAnimationManager.get());
                }

                KFbxAxisSystem fbxAxis = pScene->GetGlobalSettings().GetAxisSystem();

                if (fbxAxis != KFbxAxisSystem::OpenGL)
                {
                    int upSign;
                    KFbxAxisSystem::eUpVector eUp = fbxAxis.GetUpVector(upSign);
                    bool bLeftHanded = fbxAxis.GetCoorSystem() == KFbxAxisSystem::LeftHanded;
                    float fSign = upSign < 0 ? -1.0f : 1.0f;
                    float zScale = bLeftHanded ? -1.0f : 1.0f;

                    osg::Matrix mat;
                    switch (eUp)
                    {
                    case KFbxAxisSystem::XAxis:
                        mat.set(0,fSign,0,0,-fSign,0,0,0,0,0,zScale,0,0,0,0,1);
                        break;
                    case KFbxAxisSystem::YAxis:
                        mat.set(1,0,0,0,0,fSign,0,0,0,0,fSign*zScale,0,0,0,0,1);
                        break;
                    case KFbxAxisSystem::ZAxis:
                        mat.set(1,0,0,0,0,0,-fSign*zScale,0,0,fSign,0,0,0,0,0,1);
                        break;
                    }

                    osg::Transform* pTransformTemp = osgNode->asTransform();
                    osg::MatrixTransform* pMatrixTransform = pTransformTemp ?
                        pTransformTemp->asMatrixTransform() : NULL;
                    if (pMatrixTransform)
                    {
                        pMatrixTransform->setMatrix(pMatrixTransform->getMatrix() * mat);
                    }
                    else
                    {
                        pMatrixTransform = new osg::MatrixTransform(mat);
                        if (useFbxRoot && isBasicRootNode(*osgNode))
                        {
                            // If root node is a simple group, put all FBX elements under the OSG root
                            osg::Group* osgGroup = osgNode->asGroup();
                            for(unsigned int i = 0; i < osgGroup->getNumChildren(); ++i)
                            {
                                pMatrixTransform->addChild(osgGroup->getChild(i));
                            }
                            pMatrixTransform->setName(osgGroup->getName());
                        }
                        else
                        {
                            pMatrixTransform->addChild(osgNode);
                        }
                    }
                    osgNode = pMatrixTransform;
                }

                osgNode->setName(filenameInit);
                return osgNode;
            }
        }
    }
    catch (...)
    {
        osg::notify(osg::WARN) << "Exception thrown while importing \"" << filenameInit << '\"' << std::endl;
    }

    return ReadResult::ERROR_IN_READING_FILE;
}

osgDB::ReaderWriter::WriteResult ReaderWriterFBX::writeNode(
    const osg::Node& node,
    const std::string& filename,
    const Options* options) const
{
    try
    {
        std::string ext = osgDB::getLowerCaseFileExtension(filename);
        if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;

        osg::ref_ptr<Options> localOptions = options ?
            static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
        localOptions->getDatabasePathList().push_front(osgDB::getFilePath(filename));

        KFbxSdkManager* pSdkManager = KFbxSdkManager::Create();

        if (!pSdkManager)
        {
            return WriteResult::ERROR_IN_WRITING_FILE;
        }

        CleanUpFbx cleanUpFbx(pSdkManager);

        bool useFbxRoot = false;
        if (options)
        {
            std::istringstream iss(options->getOptionString());
            std::string opt;
            while (iss >> opt)
            {
                if (opt == "Embedded")
                {
                    IOSREF.SetBoolProp(EXP_FBX_EMBEDDED, true);
                    if (KFbxIOSettings::IOSettingsRef().IsIOSettingsAllocated())
                        KFbxIOSettings::IOSettingsRef().AllocateIOSettings(*pSdkManager);
                }
                else if (opt == "UseFbxRoot")
                {
                    useFbxRoot = true;
                }
            }
        }

        KFbxScene* pScene = KFbxScene::Create(pSdkManager, "");
        WriterNodeVisitor writerNodeVisitor(pScene, pSdkManager, filename,
            options, osgDB::getFilePath(node.getName().empty() ? filename : node.getName()));
        if (useFbxRoot && isBasicRootNode(node))
        {
            // If root node is a simple group, put all elements under the FBX root
            const osg::Group * osgGroup = node.asGroup();
            for(unsigned int child=0; child<osgGroup->getNumChildren(); ++child) {
                const_cast<osg::Node *>(osgGroup->getChild(child))->accept(writerNodeVisitor);
            }
        }
        else {
            // Normal scene
            const_cast<osg::Node&>(node).accept(writerNodeVisitor);
        }

        KFbxExporter* lExporter = KFbxExporter::Create(pSdkManager, "");
        pScene->GetGlobalSettings().SetAxisSystem(KFbxAxisSystem::eOpenGL);

        // Ensure the directory exists or else the FBX SDK will fail
        if (!osgDB::makeDirectoryForFile(filename)) {
            osg::notify(osg::NOTICE) << "Can't create directory for file '" << filename << "'. FBX SDK may fail creating the file." << std::endl;
        }

        // The FBX SDK interprets the filename as UTF-8
#ifdef OSG_USE_UTF8_FILENAME
        const std::string& utf8filename(filename);
#else
        std::string utf8filename(osgDB::convertStringFromCurrentCodePageToUTF8(filename));
#endif

        if (!lExporter->Initialize(utf8filename.c_str()))
        {
            return std::string(lExporter->GetLastErrorString());
        }
        if (!lExporter->Export(pScene))
        {
            return std::string(lExporter->GetLastErrorString());
        }

        return WriteResult::FILE_SAVED;
    }
    catch (const std::string& s)
    {
        return s;
    }
    catch (const char* s)
    {
        return std::string(s);
    }
    catch (...)
    {
    }

    return WriteResult::ERROR_IN_WRITING_FILE;
}

///////////////////////////////////////////////////////////////////////////
// Add ourself to the Registry to instantiate the reader/writer.

REGISTER_OSGPLUGIN(fbx, ReaderWriterFBX)
<commit_msg>Fixed an infinite loop when loading a malformed file.<commit_after>#include <sstream>
#include <memory>

#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/Material>
#include <osg/PositionAttitudeTransform>
#include <osg/Texture2D>
#include <osgDB/ConvertUTF>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/ReadFile>
#include <osgDB/Registry>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/Bone>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/Skeleton>
#include <osgAnimation/VertexInfluence>

#if defined(_MSC_VER)
    #pragma warning( disable : 4505 )
#endif
#include <fbxsdk.h>

#include "ReaderWriterFBX.h"
#include "fbxRNode.h"
#include "fbxMaterialToOsgStateSet.h"
#include "WriterNodeVisitor.h"

/// Returns true if the given node is a basic root group with no special information.
/// Used in conjunction with UseFbxRoot option.
/// Identity transforms are considered as basic root nodes.
bool isBasicRootNode(const osg::Node& node)
{
    const osg::Group* osgGroup = node.asGroup();
    if (!osgGroup)
    {
        // Geodes & such are not basic root nodes
        return false;
    }

    // Test if we've got an empty transform (= a group!)
    const osg::Transform* transform = osgGroup->asTransform();
    if (transform)
    {
        if (const osg::MatrixTransform* matrixTransform = transform->asMatrixTransform())
        {
            if (!matrixTransform->getMatrix().isIdentity())
            {
                // Non-identity matrix transform
                return false;
            }
        }
        else if (const osg::PositionAttitudeTransform* pat = transform->asPositionAttitudeTransform())
        {
            if (pat->getPosition() != osg::Vec3d() ||
                pat->getAttitude() != osg::Quat() ||
                pat->getScale() != osg::Vec3d(1.0f, 1.0f, 1.0f) ||
                pat->getPivotPoint() != osg::Vec3d())
            {
                // Non-identity position attribute transform
                return false;
            }
        }
        else
        {
            // Other transform (not identity or not predefined type)
            return false;
        }
    }

    // Test the presence of a non-empty stateset
    if (node.getStateSet())
    {
        osg::ref_ptr<osg::StateSet> emptyStateSet = new osg::StateSet;
        if (node.getStateSet()->compare(*emptyStateSet, true) != 0)
        {
            return false;
        }
    }

    return true;
}

class CleanUpFbx
{
    KFbxSdkManager* m_pSdkManager;
public:
    explicit CleanUpFbx(KFbxSdkManager* pSdkManager) : m_pSdkManager(pSdkManager)
    {}

    ~CleanUpFbx()
    {
        KFbxIOSettings::IOSettingsRef().FreeIOSettings();
        m_pSdkManager->Destroy();
    }
};

void resolveBindMatrices(
    osg::Node& root,
    const BindMatrixMap& boneBindMatrices,
    const std::map<KFbxNode*, osg::Node*>& nodeMap)
{
    std::set<std::string> nodeNames;
    for (std::map<KFbxNode*, osg::Node*>::const_iterator it = nodeMap.begin(); it != nodeMap.end(); ++it)
    {
        nodeNames.insert(it->second->getName());
    }

    for (BindMatrixMap::const_iterator it = boneBindMatrices.begin();
        it != boneBindMatrices.end();)
    {
        KFbxNode* const fbxBone = it->first.first;
        std::map<KFbxNode*, osg::Node*>::const_iterator nodeIt = nodeMap.find(fbxBone);
        if (nodeIt != nodeMap.end())
        {
            const osg::Matrix bindMatrix = it->second;
            osgAnimation::Bone& osgBone = dynamic_cast<osgAnimation::Bone&>(*nodeIt->second);
            osgBone.setInvBindMatrixInSkeletonSpace(bindMatrix);

            ++it;
            for (; it != boneBindMatrices.end() && it->first.first == fbxBone; ++it)
            {
                if (it->second != bindMatrix)
                {
                    std::string name;
                    for (int i = 0;; ++i)
                    {
                        std::stringstream ss;
                        ss << osgBone.getName() << '_' << i;
                        name = ss.str();
                        if (nodeNames.insert(name).second)
                        {
                            break;
                        }
                    }
                    osgAnimation::Bone* newBone = new osgAnimation::Bone(name);
                    newBone->setDefaultUpdateCallback();
                    newBone->setInvBindMatrixInSkeletonSpace(it->second);
                    osgBone.addChild(newBone);

                    osgAnimation::RigGeometry* pRigGeometry = it->first.second;

                    osgAnimation::VertexInfluenceMap* vertexInfluences = pRigGeometry->getInfluenceMap();

                    osgAnimation::VertexInfluenceMap::iterator vimIt = vertexInfluences->find(osgBone.getName());
                    if (vimIt != vertexInfluences->end())
                    {
                        osgAnimation::VertexInfluence vi;
                        vi.swap(vimIt->second);
                        vertexInfluences->erase(vimIt);
                        osgAnimation::VertexInfluence& vi2 = (*vertexInfluences)[name];
                        vi.swap(vi2);
                        vi2.setName(name);
                    }
                    else
                    {
                        osg::notify(osg::WARN) << "No vertex influences found for \"" << osgBone.getName() << "\"" << std::endl;
                    }
                }
            }
        }
        else
        {
            osg::notify(osg::WARN) << "No bone found for \"" << fbxBone->GetName() << "\"" << std::endl;
            ++it;
        }
    }
}

osgDB::ReaderWriter::ReadResult
ReaderWriterFBX::readNode(const std::string& filenameInit,
                          const Options* options) const
{
    try
    {
        std::string ext(osgDB::getLowerCaseFileExtension(filenameInit));
        if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

        std::string filename(osgDB::findDataFile(filenameInit, options));
        if (filename.empty()) return ReadResult::FILE_NOT_FOUND;

        KFbxSdkManager* pSdkManager = KFbxSdkManager::Create();

        if (!pSdkManager)
        {
            return ReadResult::ERROR_IN_READING_FILE;
        }

        CleanUpFbx cleanUpFbx(pSdkManager);

        KFbxScene* pScene = KFbxScene::Create(pSdkManager, "");

        // The FBX SDK interprets the filename as UTF-8
#ifdef OSG_USE_UTF8_FILENAME
        const std::string& utf8filename(filename);
#else
        std::string utf8filename(osgDB::convertStringFromCurrentCodePageToUTF8(filename));
#endif

        int fileFormat;
        if (!pSdkManager->GetIOPluginRegistry()->DetectFileFormat(utf8filename.c_str(), fileFormat))
        {
            return ReadResult::FILE_NOT_HANDLED;
        }
        KFbxImporter* lImporter = KFbxImporter::Create(pSdkManager, "");

        if (!lImporter->Initialize(utf8filename.c_str(), fileFormat))
        {
            return std::string(lImporter->GetLastErrorString());
        }

        if (!lImporter->IsFBX())
        {
            return ReadResult::ERROR_IN_READING_FILE;
        }

        for (int i = 0; i < lImporter->GetTakeCount(); i++)
        {
            KFbxTakeInfo* lTakeInfo = lImporter->GetTakeInfo(i);

            lTakeInfo->mSelect = true;
        }

        if (!lImporter->Import(pScene))
        {
            return std::string(lImporter->GetLastErrorString());
        }

        //KFbxAxisSystem::OpenGL.ConvertScene(pScene);        // Doesn't work as expected. Still need to transform vertices.

        if (KFbxNode* pNode = pScene->GetRootNode())
        {
            pScene->SetCurrentTake(pScene->GetCurrentTakeName());

            bool useFbxRoot = false;
            if (options)
            {
                std::istringstream iss(options->getOptionString());
                std::string opt;
                while (iss >> opt)
                {
                    if (opt == "UseFbxRoot")
                    {
                        useFbxRoot = true;
                    }
                }
            }

            osg::ref_ptr<osgAnimation::AnimationManagerBase> pAnimationManager;
            bool bIsBone = false;
            int nLightCount = 0;
            osg::ref_ptr<Options> localOptions = NULL;
            if (options)
                localOptions = options->cloneOptions();
            else
                localOptions = new osgDB::Options();
            localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_IMAGES);

            std::string filePath = osgDB::getFilePath(filename);
            FbxMaterialToOsgStateSet fbxMaterialToOsgStateSet(filePath, localOptions.get());

            std::map<KFbxNode*, osg::Node*> nodeMap;
            BindMatrixMap boneBindMatrices;
            std::map<KFbxNode*, osgAnimation::Skeleton*> skeletonMap;
            ReadResult res = readFbxNode(*pSdkManager, pNode, pAnimationManager,
                bIsBone, nLightCount, fbxMaterialToOsgStateSet, nodeMap,
                boneBindMatrices, skeletonMap, localOptions.get());

            if (res.success())
            {
                fbxMaterialToOsgStateSet.checkInvertTransparency();

                resolveBindMatrices(*res.getNode(), boneBindMatrices, nodeMap);

                osg::Node* osgNode = res.getNode();
                osgNode->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL,osg::StateAttribute::ON);
                osgNode->getOrCreateStateSet()->setMode(GL_NORMALIZE,osg::StateAttribute::ON);

                if (pAnimationManager.valid())
                {
                    if (osgNode->getUpdateCallback())
                    {
                        osg::Group* osgGroup = new osg::Group;
                        osgGroup->addChild(osgNode);
                        osgNode = osgGroup;
                    }

                    //because the animations may be altered after registering
                    pAnimationManager->buildTargetReference();
                    osgNode->setUpdateCallback(pAnimationManager.get());
                }

                KFbxAxisSystem fbxAxis = pScene->GetGlobalSettings().GetAxisSystem();

                if (fbxAxis != KFbxAxisSystem::OpenGL)
                {
                    int upSign;
                    KFbxAxisSystem::eUpVector eUp = fbxAxis.GetUpVector(upSign);
                    bool bLeftHanded = fbxAxis.GetCoorSystem() == KFbxAxisSystem::LeftHanded;
                    float fSign = upSign < 0 ? -1.0f : 1.0f;
                    float zScale = bLeftHanded ? -1.0f : 1.0f;

                    osg::Matrix mat;
                    switch (eUp)
                    {
                    case KFbxAxisSystem::XAxis:
                        mat.set(0,fSign,0,0,-fSign,0,0,0,0,0,zScale,0,0,0,0,1);
                        break;
                    case KFbxAxisSystem::YAxis:
                        mat.set(1,0,0,0,0,fSign,0,0,0,0,fSign*zScale,0,0,0,0,1);
                        break;
                    case KFbxAxisSystem::ZAxis:
                        mat.set(1,0,0,0,0,0,-fSign*zScale,0,0,fSign,0,0,0,0,0,1);
                        break;
                    }

                    osg::Transform* pTransformTemp = osgNode->asTransform();
                    osg::MatrixTransform* pMatrixTransform = pTransformTemp ?
                        pTransformTemp->asMatrixTransform() : NULL;
                    if (pMatrixTransform)
                    {
                        pMatrixTransform->setMatrix(pMatrixTransform->getMatrix() * mat);
                    }
                    else
                    {
                        pMatrixTransform = new osg::MatrixTransform(mat);
                        if (useFbxRoot && isBasicRootNode(*osgNode))
                        {
                            // If root node is a simple group, put all FBX elements under the OSG root
                            osg::Group* osgGroup = osgNode->asGroup();
                            for(unsigned int i = 0; i < osgGroup->getNumChildren(); ++i)
                            {
                                pMatrixTransform->addChild(osgGroup->getChild(i));
                            }
                            pMatrixTransform->setName(osgGroup->getName());
                        }
                        else
                        {
                            pMatrixTransform->addChild(osgNode);
                        }
                    }
                    osgNode = pMatrixTransform;
                }

                osgNode->setName(filenameInit);
                return osgNode;
            }
        }
    }
    catch (...)
    {
        osg::notify(osg::WARN) << "Exception thrown while importing \"" << filenameInit << '\"' << std::endl;
    }

    return ReadResult::ERROR_IN_READING_FILE;
}

osgDB::ReaderWriter::WriteResult ReaderWriterFBX::writeNode(
    const osg::Node& node,
    const std::string& filename,
    const Options* options) const
{
    try
    {
        std::string ext = osgDB::getLowerCaseFileExtension(filename);
        if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;

        osg::ref_ptr<Options> localOptions = options ?
            static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
        localOptions->getDatabasePathList().push_front(osgDB::getFilePath(filename));

        KFbxSdkManager* pSdkManager = KFbxSdkManager::Create();

        if (!pSdkManager)
        {
            return WriteResult::ERROR_IN_WRITING_FILE;
        }

        CleanUpFbx cleanUpFbx(pSdkManager);

        bool useFbxRoot = false;
        if (options)
        {
            std::istringstream iss(options->getOptionString());
            std::string opt;
            while (iss >> opt)
            {
                if (opt == "Embedded")
                {
                    IOSREF.SetBoolProp(EXP_FBX_EMBEDDED, true);
                    if (KFbxIOSettings::IOSettingsRef().IsIOSettingsAllocated())
                        KFbxIOSettings::IOSettingsRef().AllocateIOSettings(*pSdkManager);
                }
                else if (opt == "UseFbxRoot")
                {
                    useFbxRoot = true;
                }
            }
        }

        KFbxScene* pScene = KFbxScene::Create(pSdkManager, "");
        WriterNodeVisitor writerNodeVisitor(pScene, pSdkManager, filename,
            options, osgDB::getFilePath(node.getName().empty() ? filename : node.getName()));
        if (useFbxRoot && isBasicRootNode(node))
        {
            // If root node is a simple group, put all elements under the FBX root
            const osg::Group * osgGroup = node.asGroup();
            for(unsigned int child=0; child<osgGroup->getNumChildren(); ++child) {
                const_cast<osg::Node *>(osgGroup->getChild(child))->accept(writerNodeVisitor);
            }
        }
        else {
            // Normal scene
            const_cast<osg::Node&>(node).accept(writerNodeVisitor);
        }

        KFbxExporter* lExporter = KFbxExporter::Create(pSdkManager, "");
        pScene->GetGlobalSettings().SetAxisSystem(KFbxAxisSystem::eOpenGL);

        // Ensure the directory exists or else the FBX SDK will fail
        if (!osgDB::makeDirectoryForFile(filename)) {
            osg::notify(osg::NOTICE) << "Can't create directory for file '" << filename << "'. FBX SDK may fail creating the file." << std::endl;
        }

        // The FBX SDK interprets the filename as UTF-8
#ifdef OSG_USE_UTF8_FILENAME
        const std::string& utf8filename(filename);
#else
        std::string utf8filename(osgDB::convertStringFromCurrentCodePageToUTF8(filename));
#endif

        if (!lExporter->Initialize(utf8filename.c_str()))
        {
            return std::string(lExporter->GetLastErrorString());
        }
        if (!lExporter->Export(pScene))
        {
            return std::string(lExporter->GetLastErrorString());
        }

        return WriteResult::FILE_SAVED;
    }
    catch (const std::string& s)
    {
        return s;
    }
    catch (const char* s)
    {
        return std::string(s);
    }
    catch (...)
    {
    }

    return WriteResult::ERROR_IN_WRITING_FILE;
}

///////////////////////////////////////////////////////////////////////////
// Add ourself to the Registry to instantiate the reader/writer.

REGISTER_OSGPLUGIN(fbx, ReaderWriterFBX)
<|endoftext|>


<commit_before>#include "UEPyFARFilter.h"

#if WITH_EDITOR

static PyObject *py_ue_farfilter_append(ue_PyFARFilter *self, PyObject * args)
{
	PyObject *pyfilter = nullptr;
	py_ue_sync_farfilter((PyObject *)self);
	if (!PyArg_ParseTuple(args, "|O:append", &pyfilter))
		return NULL;
	ue_PyFARFilter *filter = py_ue_is_farfilter(pyfilter);
	self->filter.Append(filter->filter);
	Py_RETURN_NONE;
}

static PyObject *py_ue_farfilter_clear(ue_PyFARFilter *self)
{
	py_ue_clear_farfilter(self);
	self->filter.Clear();
	Py_RETURN_NONE;
}

static PyObject *py_ue_farfilter_is_empty(ue_PyFARFilter *self, PyObject * args)
{
	py_ue_sync_farfilter((PyObject *)self);
	if (self->filter.IsEmpty())
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

static PyMethodDef ue_PyFARFilter_methods[] = {
	{ "append", (PyCFunction)py_ue_farfilter_append, METH_VARARGS, "" },
	{ "clear", (PyCFunction)py_ue_farfilter_clear, METH_VARARGS, "" },
	{ "is_empty", (PyCFunction)py_ue_farfilter_is_empty, METH_VARARGS, "" },
	{ NULL }  /* Sentinel */
};

static PyObject *py_ue_farfilter_get_include_only_on_disk_assets(ue_PyFARFilter *self, void *closure)
{
	if (self->filter.bIncludeOnlyOnDiskAssets)
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

static int py_ue_farfilter_set_include_only_on_disk_assets(ue_PyFARFilter *self, PyObject *value, void *closure)
{
	if (value && PyBool_Check(value))
	{
		if (PyObject_IsTrue(value))
			self->filter.bIncludeOnlyOnDiskAssets = true;
		else
			self->filter.bIncludeOnlyOnDiskAssets = false;
		return 0;
	}
	PyErr_SetString(PyExc_TypeError, "value is not a bool");
	return -1;
}

static PyObject *py_ue_farfilter_get_recursive_classes(ue_PyFARFilter *self, void *closure)
{
	if (self->filter.bRecursiveClasses)
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

static int py_ue_farfilter_set_recursive_classes(ue_PyFARFilter *self, PyObject *value, void *closure)
{
	if (value && PyBool_Check(value))
	{
		if (PyObject_IsTrue(value))
			self->filter.bRecursiveClasses = true;
		else
			self->filter.bRecursiveClasses = false;
		return 0;
	}
	PyErr_SetString(PyExc_TypeError, "value is not a bool");
	return -1;
}

static PyObject *py_ue_farfilter_get_recursive_paths(ue_PyFARFilter *self, void *closure)
{
	if (self->filter.bRecursivePaths)
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

static int py_ue_farfilter_set_recursive_paths(ue_PyFARFilter *self, PyObject *value, void *closure)
{
	if (value && PyBool_Check(value))
	{
		if (PyObject_IsTrue(value))
			self->filter.bRecursivePaths = true;
		else
			self->filter.bRecursivePaths = false;
		return 0;
	}
	PyErr_SetString(PyExc_TypeError, "value is not a bool");
	return -1;
}

static PyGetSetDef ue_PyFARFilter_getseters[] = {
	{ (char *)"include_only_on_disk_assets", (getter)py_ue_farfilter_get_include_only_on_disk_assets,
									 (setter)py_ue_farfilter_set_include_only_on_disk_assets, (char *)"", NULL },
	{ (char *)"recursive_classes", (getter)py_ue_farfilter_get_recursive_classes,
						   (setter)py_ue_farfilter_set_recursive_classes, (char *)"", NULL },
	{ (char *)"recursive_paths", (getter)py_ue_farfilter_get_recursive_paths,
						 (setter)py_ue_farfilter_set_recursive_paths, (char *)"", NULL },
	{ NULL }  /* Sentinel */
};

static PyMemberDef ue_PyFARFilter_members[] = {
	{ (char *)"class_names", T_OBJECT_EX, offsetof(ue_PyFARFilter, class_names), 0, (char *)"class_names" },
	{ (char *)"object_paths", T_OBJECT_EX, offsetof(ue_PyFARFilter, object_paths), 0, (char *)"object_paths" },
	{ (char *)"package_names", T_OBJECT_EX, offsetof(ue_PyFARFilter, package_names), 0, (char *)"package_names" },
	{ (char *)"package_paths", T_OBJECT_EX, offsetof(ue_PyFARFilter, package_paths), 0, (char *)"package_paths" },
	{ (char *)"recursive_classes_exclusion_set", T_OBJECT_EX, offsetof(ue_PyFARFilter, recursive_classes_exclusion_set), 0, (char *)"recursive_classes_exclusion_set" },
	{ (char *)"tags_and_values", T_OBJECT_EX, offsetof(ue_PyFARFilter, tags_and_values), 0, (char *)"tags_and_values" },
	{ NULL }  /* Sentinel */
};

static int ue_py_farfilter_init(ue_PyFARFilter *self, PyObject *args, PyObject *kwargs)
{
	return 0;
}

static void ue_py_farfilter_dealloc(ue_PyFARFilter *self)
{
	Py_XDECREF(self->class_names);
	Py_XDECREF(self->object_paths);
	Py_XDECREF(self->package_names);
	Py_XDECREF(self->package_paths);
	Py_XDECREF(self->recursive_classes_exclusion_set);
	Py_XDECREF(self->tags_and_values);

#if PY_MAJOR_VERSION < 3
	self->ob_type->tp_free((PyObject*)self);
#else
	Py_TYPE(self)->tp_free((PyObject*)self);
#endif
}

static PyObject * ue_py_farfilter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
	ue_PyFARFilter *self;

	self = (ue_PyFARFilter *)type->tp_alloc(type, 0);
	if (self != NULL)
	{
		self->class_names = PyList_New(0);
		if (self->class_names == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}

		self->object_paths = PyList_New(0);
		if (self->object_paths == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}

		self->package_names = PyList_New(0);
		if (self->package_names == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}

		self->package_paths = PyList_New(0);
		if (self->package_paths == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}

		self->recursive_classes_exclusion_set = PySet_New(0);
		if (self->recursive_classes_exclusion_set == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}

		PyObject *collections = PyImport_ImportModule("collections");
		PyObject *collections_module_dict = PyModule_GetDict(collections);
		PyObject *defaultdict_cls = PyDict_GetItemString(collections_module_dict, "defaultdict");

		PyObject *main_module = PyImport_ImportModule("__main__");
		PyObject *main_dict = PyModule_GetDict(main_module);
		PyObject *builtins_module = PyDict_GetItemString(main_dict, "__builtins__");
		PyObject *builtins_dict = PyModule_GetDict(builtins_module);
		PyObject *set_cls = PyDict_GetItemString(builtins_dict, "set");

		PyObject *py_args = PyTuple_New(1);
		PyTuple_SetItem(py_args, 0, set_cls);
		PyObject *default_dict = PyObject_CallObject(defaultdict_cls, py_args);
		Py_XDECREF(py_args);

		self->tags_and_values = default_dict;
		if (self->tags_and_values == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}
	}

	return (PyObject *)self;
}

static PyTypeObject ue_PyFARFilterType = {
	PyVarObject_HEAD_INIT(NULL, 0)
	"unreal_engine.FARFilter", /* tp_name */
	sizeof(ue_PyFARFilter),    /* tp_basicsize */
	0,                         /* tp_itemsize */
	(destructor)ue_py_farfilter_dealloc,   /* tp_dealloc */
	0,                         /* tp_print */
	0,                         /* tp_getattr */
	0,                         /* tp_setattr */
	0,                         /* tp_reserved */
	0,                         /* tp_repr */
	0,                         /* tp_as_number */
	0,                         /* tp_as_sequence */
	0,                         /* tp_as_mapping */
	0,                         /* tp_hash  */
	0,                         /* tp_call */
	0,                         /* tp_str */
	0,                         /* tp_getattro */
	0,                         /* tp_setattro */
	0,                         /* tp_as_buffer */
	Py_TPFLAGS_DEFAULT,        /* tp_flags */
	"Unreal Engine FARFilter", /* tp_doc */
	0,                         /* tp_traverse */
	0,                         /* tp_clear */
	0,                         /* tp_richcompare */
	0,                         /* tp_weaklistoffset */
	0,                         /* tp_iter */
	0,                         /* tp_iternext */
	ue_PyFARFilter_methods,    /* tp_methods */
	ue_PyFARFilter_members,    /* tp_members */
	ue_PyFARFilter_getseters,   /* tp_getset */
};

void ue_python_init_farfilter(PyObject *ue_module)
{
	ue_PyFARFilterType.tp_new = ue_py_farfilter_new;
	ue_PyFARFilterType.tp_init = (initproc)ue_py_farfilter_init;
	if (PyType_Ready(&ue_PyFARFilterType) < 0)
		return;

	Py_INCREF(&ue_PyFARFilterType);
	PyModule_AddObject(ue_module, "FARFilter", (PyObject *)&ue_PyFARFilterType);
}

void py_ue_clear_seq(PyObject *pyseq)
{
	if (PyList_Check(pyseq))
	{
		Py_ssize_t pysize = PyObject_Length(pyseq);
		PyObject *pyitem;
		for (int i = 0; i < (int)pysize; i++)
		{
			pyitem = PyList_GetItem(pyseq, i);
			PyObject_DelItem(pyseq, pyitem);
		}
	}
	else if (PySet_Check(pyseq))
	{
		PySet_Clear(pyseq);
	}
	else if (PyDict_Check(pyseq))
	{
		PyObject *pykeys = PyDict_Keys(pyseq);
		Py_ssize_t pysize = PyObject_Length(pykeys);
		PyObject *pykey;
		for (int i = 0; i < (int)pysize; i++)
		{
			pykey = PyList_GetItem(pykeys, i);
			PyObject_DelItem(pyseq, pykey);
		}
	}
}

void py_ue_clear_farfilter(ue_PyFARFilter *pyfilter)
{
	py_ue_clear_seq(pyfilter->class_names);
	py_ue_clear_seq(pyfilter->object_paths);
	py_ue_clear_seq(pyfilter->package_names);
	py_ue_clear_seq(pyfilter->package_paths);
	py_ue_clear_seq(pyfilter->recursive_classes_exclusion_set);
	py_ue_clear_seq(pyfilter->tags_and_values);
}

void ue_sync_farfilter_name_array(PyObject *pylist, TArray<FName> &uelist)
{
	Py_ssize_t pylist_len = PyList_Size(pylist);
	uelist.Reset(pylist_len);
	for (int i = 0; i < (int)pylist_len; i++)
	{
		PyObject *py_item = PyList_GetItem(pylist, i);
		uelist.Add(FName(UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(py_item))));
	}
}

void py_ue_sync_farfilter(PyObject *pyobj)
{
	ue_PyFARFilter *pyfilter = py_ue_is_farfilter(pyobj);
	ue_sync_farfilter_name_array(pyfilter->class_names, pyfilter->filter.ClassNames);
	ue_sync_farfilter_name_array(pyfilter->object_paths, pyfilter->filter.ObjectPaths);
	ue_sync_farfilter_name_array(pyfilter->package_names, pyfilter->filter.PackageNames);
	ue_sync_farfilter_name_array(pyfilter->package_paths, pyfilter->filter.PackagePaths);

	PyObject *pyset = pyfilter->recursive_classes_exclusion_set;
	Py_ssize_t pyset_len = PySet_Size(pyset);
	PyObject *py_item;
	pyfilter->filter.RecursiveClassesExclusionSet.Reset();
	for (int i = 0; i < (int)pyset_len; i++)
	{
		py_item = PyList_GetItem(pyset, i);
		pyfilter->filter.RecursiveClassesExclusionSet.Add(FName(UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(py_item))));
	}

	PyObject *pykey, *pyvalue;
	Py_ssize_t pypos;
	FName ukey;
	pyfilter->filter.TagsAndValues.Reset();
	while (PyDict_Next(pyfilter->tags_and_values, &pypos, &pykey, &pyvalue))
	{
		ukey = UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(pykey));
		pyset_len = PySet_Size(pyvalue);
		for (int i = 0; i < (int)pyset_len; i++)
		{
			py_item = PyList_GetItem(pyset, i);
#if ENGINE_MINOR_VERSION < 20
			pyfilter->filter.TagsAndValues.AddUnique(ukey, UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(py_item)));
#else
			pyfilter->filter.TagsAndValues.AddUnique(ukey, FString(UTF8_TO_TCHAR(PyUnicode_AsUTF8(py_item))));
#endif
		}
	}
}

PyObject *py_ue_new_farfilter(FARFilter filter)
{
	ue_PyFARFilter *ret = (ue_PyFARFilter *)PyObject_CallObject((PyObject *)&ue_PyFARFilterType, NULL);
	ret->filter = filter;
	return (PyObject *)ret;
}

ue_PyFARFilter *py_ue_is_farfilter(PyObject *obj)
{
	if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyFARFilterType))
		return nullptr;
	return (ue_PyFARFilter *)obj;
}

#endif
<commit_msg>fixed python2.7 build<commit_after>#include "UEPyFARFilter.h"

#if WITH_EDITOR

static PyObject *py_ue_farfilter_append(ue_PyFARFilter *self, PyObject * args)
{
	PyObject *pyfilter = nullptr;
	py_ue_sync_farfilter((PyObject *)self);
	if (!PyArg_ParseTuple(args, "|O:append", &pyfilter))
		return NULL;
	ue_PyFARFilter *filter = py_ue_is_farfilter(pyfilter);
	self->filter.Append(filter->filter);
	Py_RETURN_NONE;
}

static PyObject *py_ue_farfilter_clear(ue_PyFARFilter *self)
{
	py_ue_clear_farfilter(self);
	self->filter.Clear();
	Py_RETURN_NONE;
}

static PyObject *py_ue_farfilter_is_empty(ue_PyFARFilter *self, PyObject * args)
{
	py_ue_sync_farfilter((PyObject *)self);
	if (self->filter.IsEmpty())
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

static PyMethodDef ue_PyFARFilter_methods[] = {
	{ "append", (PyCFunction)py_ue_farfilter_append, METH_VARARGS, "" },
	{ "clear", (PyCFunction)py_ue_farfilter_clear, METH_VARARGS, "" },
	{ "is_empty", (PyCFunction)py_ue_farfilter_is_empty, METH_VARARGS, "" },
	{ NULL }  /* Sentinel */
};

static PyObject *py_ue_farfilter_get_include_only_on_disk_assets(ue_PyFARFilter *self, void *closure)
{
	if (self->filter.bIncludeOnlyOnDiskAssets)
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

static int py_ue_farfilter_set_include_only_on_disk_assets(ue_PyFARFilter *self, PyObject *value, void *closure)
{
	if (value && PyBool_Check(value))
	{
		if (PyObject_IsTrue(value))
			self->filter.bIncludeOnlyOnDiskAssets = true;
		else
			self->filter.bIncludeOnlyOnDiskAssets = false;
		return 0;
	}
	PyErr_SetString(PyExc_TypeError, "value is not a bool");
	return -1;
}

static PyObject *py_ue_farfilter_get_recursive_classes(ue_PyFARFilter *self, void *closure)
{
	if (self->filter.bRecursiveClasses)
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

static int py_ue_farfilter_set_recursive_classes(ue_PyFARFilter *self, PyObject *value, void *closure)
{
	if (value && PyBool_Check(value))
	{
		if (PyObject_IsTrue(value))
			self->filter.bRecursiveClasses = true;
		else
			self->filter.bRecursiveClasses = false;
		return 0;
	}
	PyErr_SetString(PyExc_TypeError, "value is not a bool");
	return -1;
}

static PyObject *py_ue_farfilter_get_recursive_paths(ue_PyFARFilter *self, void *closure)
{
	if (self->filter.bRecursivePaths)
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

static int py_ue_farfilter_set_recursive_paths(ue_PyFARFilter *self, PyObject *value, void *closure)
{
	if (value && PyBool_Check(value))
	{
		if (PyObject_IsTrue(value))
			self->filter.bRecursivePaths = true;
		else
			self->filter.bRecursivePaths = false;
		return 0;
	}
	PyErr_SetString(PyExc_TypeError, "value is not a bool");
	return -1;
}

static PyGetSetDef ue_PyFARFilter_getseters[] = {
	{ (char *)"include_only_on_disk_assets", (getter)py_ue_farfilter_get_include_only_on_disk_assets,
									 (setter)py_ue_farfilter_set_include_only_on_disk_assets, (char *)"", NULL },
	{ (char *)"recursive_classes", (getter)py_ue_farfilter_get_recursive_classes,
						   (setter)py_ue_farfilter_set_recursive_classes, (char *)"", NULL },
	{ (char *)"recursive_paths", (getter)py_ue_farfilter_get_recursive_paths,
						 (setter)py_ue_farfilter_set_recursive_paths, (char *)"", NULL },
	{ NULL }  /* Sentinel */
};

static PyMemberDef ue_PyFARFilter_members[] = {
	{ (char *)"class_names", T_OBJECT_EX, offsetof(ue_PyFARFilter, class_names), 0, (char *)"class_names" },
	{ (char *)"object_paths", T_OBJECT_EX, offsetof(ue_PyFARFilter, object_paths), 0, (char *)"object_paths" },
	{ (char *)"package_names", T_OBJECT_EX, offsetof(ue_PyFARFilter, package_names), 0, (char *)"package_names" },
	{ (char *)"package_paths", T_OBJECT_EX, offsetof(ue_PyFARFilter, package_paths), 0, (char *)"package_paths" },
	{ (char *)"recursive_classes_exclusion_set", T_OBJECT_EX, offsetof(ue_PyFARFilter, recursive_classes_exclusion_set), 0, (char *)"recursive_classes_exclusion_set" },
	{ (char *)"tags_and_values", T_OBJECT_EX, offsetof(ue_PyFARFilter, tags_and_values), 0, (char *)"tags_and_values" },
	{ NULL }  /* Sentinel */
};

static int ue_py_farfilter_init(ue_PyFARFilter *self, PyObject *args, PyObject *kwargs)
{
	return 0;
}

static void ue_py_farfilter_dealloc(ue_PyFARFilter *self)
{
	Py_XDECREF(self->class_names);
	Py_XDECREF(self->object_paths);
	Py_XDECREF(self->package_names);
	Py_XDECREF(self->package_paths);
	Py_XDECREF(self->recursive_classes_exclusion_set);
	Py_XDECREF(self->tags_and_values);

#if PY_MAJOR_VERSION < 3
	self->ob_type->tp_free((PyObject*)self);
#else
	Py_TYPE(self)->tp_free((PyObject*)self);
#endif
}

static PyObject * ue_py_farfilter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
	ue_PyFARFilter *self;

	self = (ue_PyFARFilter *)type->tp_alloc(type, 0);
	if (self != NULL)
	{
		self->class_names = PyList_New(0);
		if (self->class_names == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}

		self->object_paths = PyList_New(0);
		if (self->object_paths == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}

		self->package_names = PyList_New(0);
		if (self->package_names == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}

		self->package_paths = PyList_New(0);
		if (self->package_paths == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}

		self->recursive_classes_exclusion_set = PySet_New(0);
		if (self->recursive_classes_exclusion_set == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}

		PyObject *collections = PyImport_ImportModule("collections");
		PyObject *collections_module_dict = PyModule_GetDict(collections);
		PyObject *defaultdict_cls = PyDict_GetItemString(collections_module_dict, "defaultdict");

		PyObject *main_module = PyImport_ImportModule("__main__");
		PyObject *main_dict = PyModule_GetDict(main_module);
		PyObject *builtins_module = PyDict_GetItemString(main_dict, "__builtins__");
		PyObject *builtins_dict = PyModule_GetDict(builtins_module);
		PyObject *set_cls = PyDict_GetItemString(builtins_dict, "set");

		PyObject *py_args = PyTuple_New(1);
		PyTuple_SetItem(py_args, 0, set_cls);
		PyObject *default_dict = PyObject_CallObject(defaultdict_cls, py_args);
		Py_XDECREF(py_args);

		self->tags_and_values = default_dict;
		if (self->tags_and_values == NULL)
		{
			Py_DECREF(self);
			return NULL;
		}
	}

	return (PyObject *)self;
}

static PyTypeObject ue_PyFARFilterType = {
	PyVarObject_HEAD_INIT(NULL, 0)
	"unreal_engine.FARFilter", /* tp_name */
	sizeof(ue_PyFARFilter),    /* tp_basicsize */
	0,                         /* tp_itemsize */
	(destructor)ue_py_farfilter_dealloc,   /* tp_dealloc */
	0,                         /* tp_print */
	0,                         /* tp_getattr */
	0,                         /* tp_setattr */
	0,                         /* tp_reserved */
	0,                         /* tp_repr */
	0,                         /* tp_as_number */
	0,                         /* tp_as_sequence */
	0,                         /* tp_as_mapping */
	0,                         /* tp_hash  */
	0,                         /* tp_call */
	0,                         /* tp_str */
	0,                         /* tp_getattro */
	0,                         /* tp_setattro */
	0,                         /* tp_as_buffer */
	Py_TPFLAGS_DEFAULT,        /* tp_flags */
	"Unreal Engine FARFilter", /* tp_doc */
	0,                         /* tp_traverse */
	0,                         /* tp_clear */
	0,                         /* tp_richcompare */
	0,                         /* tp_weaklistoffset */
	0,                         /* tp_iter */
	0,                         /* tp_iternext */
	ue_PyFARFilter_methods,    /* tp_methods */
	ue_PyFARFilter_members,    /* tp_members */
	ue_PyFARFilter_getseters,   /* tp_getset */
};

void ue_python_init_farfilter(PyObject *ue_module)
{
	ue_PyFARFilterType.tp_new = ue_py_farfilter_new;
	ue_PyFARFilterType.tp_init = (initproc)ue_py_farfilter_init;
	if (PyType_Ready(&ue_PyFARFilterType) < 0)
		return;

	Py_INCREF(&ue_PyFARFilterType);
	PyModule_AddObject(ue_module, "FARFilter", (PyObject *)&ue_PyFARFilterType);
}

void py_ue_clear_seq(PyObject *pyseq)
{
	if (PyList_Check(pyseq))
	{
		Py_ssize_t pysize = PyObject_Length(pyseq);
		PyObject *pyitem;
		for (int i = 0; i < (int)pysize; i++)
		{
			pyitem = PyList_GetItem(pyseq, i);
			PyObject_DelItem(pyseq, pyitem);
		}
	}
	else if (PySet_Check(pyseq))
	{
		PySet_Clear(pyseq);
	}
	else if (PyDict_Check(pyseq))
	{
		PyObject *pykeys = PyDict_Keys(pyseq);
		Py_ssize_t pysize = PyObject_Length(pykeys);
		PyObject *pykey;
		for (int i = 0; i < (int)pysize; i++)
		{
			pykey = PyList_GetItem(pykeys, i);
			PyObject_DelItem(pyseq, pykey);
		}
	}
}

void py_ue_clear_farfilter(ue_PyFARFilter *pyfilter)
{
	py_ue_clear_seq(pyfilter->class_names);
	py_ue_clear_seq(pyfilter->object_paths);
	py_ue_clear_seq(pyfilter->package_names);
	py_ue_clear_seq(pyfilter->package_paths);
	py_ue_clear_seq(pyfilter->recursive_classes_exclusion_set);
	py_ue_clear_seq(pyfilter->tags_and_values);
}

void ue_sync_farfilter_name_array(PyObject *pylist, TArray<FName> &uelist)
{
	Py_ssize_t pylist_len = PyList_Size(pylist);
	uelist.Reset(pylist_len);
	for (int i = 0; i < (int)pylist_len; i++)
	{
		PyObject *py_item = PyList_GetItem(pylist, i);
		uelist.Add(FName(UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(py_item))));
	}
}

void py_ue_sync_farfilter(PyObject *pyobj)
{
	ue_PyFARFilter *pyfilter = py_ue_is_farfilter(pyobj);
	ue_sync_farfilter_name_array(pyfilter->class_names, pyfilter->filter.ClassNames);
	ue_sync_farfilter_name_array(pyfilter->object_paths, pyfilter->filter.ObjectPaths);
	ue_sync_farfilter_name_array(pyfilter->package_names, pyfilter->filter.PackageNames);
	ue_sync_farfilter_name_array(pyfilter->package_paths, pyfilter->filter.PackagePaths);

	PyObject *pyset = pyfilter->recursive_classes_exclusion_set;
	Py_ssize_t pyset_len = PySet_Size(pyset);
	PyObject *py_item;
	pyfilter->filter.RecursiveClassesExclusionSet.Reset();
	for (int i = 0; i < (int)pyset_len; i++)
	{
		py_item = PyList_GetItem(pyset, i);
		pyfilter->filter.RecursiveClassesExclusionSet.Add(FName(UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(py_item))));
	}

	PyObject *pykey, *pyvalue;
	Py_ssize_t pypos;
	FName ukey;
	pyfilter->filter.TagsAndValues.Reset();
	while (PyDict_Next(pyfilter->tags_and_values, &pypos, &pykey, &pyvalue))
	{
		ukey = UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(pykey));
		pyset_len = PySet_Size(pyvalue);
		for (int i = 0; i < (int)pyset_len; i++)
		{
			py_item = PyList_GetItem(pyset, i);
#if ENGINE_MINOR_VERSION < 20
			pyfilter->filter.TagsAndValues.AddUnique(ukey, UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(py_item)));
#else
			pyfilter->filter.TagsAndValues.AddUnique(ukey, FString(UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(py_item))));
#endif
		}
	}
}

PyObject *py_ue_new_farfilter(FARFilter filter)
{
	ue_PyFARFilter *ret = (ue_PyFARFilter *)PyObject_CallObject((PyObject *)&ue_PyFARFilterType, NULL);
	ret->filter = filter;
	return (PyObject *)ret;
}

ue_PyFARFilter *py_ue_is_farfilter(PyObject *obj)
{
	if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyFARFilterType))
		return nullptr;
	return (ue_PyFARFilter *)obj;
}

#endif
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "otbGenericRSResampleImageFilter.h"
#include "otbVectorImage.h"
#include "itkVector.h"
#include "otbImage.h"

#include "otbImageFileReader.h"
#include "otbStreamingImageFileWriter.h"

#include <ogr_spatialref.h>

int otbGenericRSResampleImageFilter(int argc, char* argv[])
{
  const char * infname = argv[1];
  const char * outfname = argv[4];
  unsigned int isize    = atoi(argv[2]);
  double iGridSpacing    = atof(argv[3]);

  // Images definition
  const unsigned int Dimension = 2;
  typedef double                                      PixelType;
  typedef otb::VectorImage<PixelType, Dimension>      ImageType;
  typedef ImageType::SizeType                         SizeType;

  typedef itk::Vector<PixelType, 2>                   DeformationValueType;
  typedef otb::Image<DeformationValueType, Dimension> DeformationFieldType;

  typedef otb::GenericRSResampleImageFilter<ImageType, ImageType, DeformationFieldType> ImageResamplerType;
  typedef ImageResamplerType::OriginType               OriginType;
  typedef ImageResamplerType::SpacingType              SpacingType;
  typedef otb::ImageFileReader<ImageType>             ReaderType;

  // SmartPointer instanciation
  ReaderType::Pointer         reader    = ReaderType::New();
  ImageResamplerType::Pointer resampler = ImageResamplerType::New();

  // Read the input image
  reader->SetFileName(infname);
  reader->UpdateOutputInformation();

  // Fill the output size with the user selection
  SizeType      size;
  size.Fill(isize);

  // Set the origin & the spacing of the output
  OriginType  origin;
  origin[0] = 367340;
  origin[1] = 4.83467e+06;

  SpacingType  spacing;
  spacing[0] = 0.6;
  spacing[1] = -0.6;

  // Build the ouput projection ref : UTM ref
  OGRSpatialReference    oSRS;
  oSRS.SetProjCS("UTM");
  oSRS.SetUTM(31, true);
  char * utmRef = NULL;
  oSRS.exportToWkt(&utmRef);

  // Deformation Field spacing
  SpacingType  gridSpacing;
  gridSpacing[0] = iGridSpacing;
  gridSpacing[1] = -iGridSpacing;

  // Set the Resampler Parameters
  resampler->SetInput(reader->GetOutput());
  resampler->SetDeformationFieldSpacing(gridSpacing);
  resampler->SetOutputOrigin(origin);
  resampler->SetOutputSize(size);
  resampler->SetOutputSpacing(spacing);
  resampler->SetOutputProjectionRef(utmRef);

  // Write the resampled image
  typedef otb::StreamingImageFileWriter<ImageType>    WriterType;
  WriterType::Pointer writer= WriterType::New();
  writer->SetTilingStreamDivisions(4);
  writer->WriteGeomFileOn();
  writer->SetFileName(outfname);
  writer->SetInput(resampler->GetOutput());
  writer->Update();

  return 0;
}
<commit_msg>STYLE<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "otbGenericRSResampleImageFilter.h"
#include "otbVectorImage.h"
#include "itkVector.h"
#include "otbImage.h"

#include "otbImageFileReader.h"
#include "otbStreamingImageFileWriter.h"

#include <ogr_spatialref.h>

int otbGenericRSResampleImageFilter(int argc, char* argv[])
{
  const char * infname = argv[1];
  const char * outfname = argv[4];
  unsigned int isize    = atoi(argv[2]);
  double iGridSpacing    = atof(argv[3]);

  // Images definition
  const unsigned int Dimension = 2;
  typedef double                                      PixelType;
  typedef otb::VectorImage<PixelType, Dimension>      ImageType;
  typedef ImageType::SizeType                         SizeType;

  typedef itk::Vector<PixelType, 2>                   DeformationValueType;
  typedef otb::Image<DeformationValueType, Dimension> DeformationFieldType;

  typedef otb::GenericRSResampleImageFilter<ImageType, ImageType, DeformationFieldType> ImageResamplerType;
  typedef ImageResamplerType::OriginType               OriginType;
  typedef ImageResamplerType::SpacingType              SpacingType;
  typedef otb::ImageFileReader<ImageType>              ReaderType;

  // SmartPointer instanciation
  ReaderType::Pointer         reader    = ReaderType::New();
  ImageResamplerType::Pointer resampler = ImageResamplerType::New();

  // Read the input image
  reader->SetFileName(infname);
  reader->UpdateOutputInformation();

  // Fill the output size with the user selection
  SizeType      size;
  size.Fill(isize);

  // Set the origin & the spacing of the output
  OriginType  origin;
  origin[0] = 367340;
  origin[1] = 4.83467e+06;

  SpacingType  spacing;
  spacing[0] = 0.6;
  spacing[1] = -0.6;

  // Build the ouput projection ref : UTM ref
  OGRSpatialReference    oSRS;
  oSRS.SetProjCS("UTM");
  oSRS.SetUTM(31, true);
  char * utmRef = NULL;
  oSRS.exportToWkt(&utmRef);

  // Deformation Field spacing
  SpacingType  gridSpacing;
  gridSpacing[0] = iGridSpacing;
  gridSpacing[1] = -iGridSpacing;

  // Set the Resampler Parameters
  resampler->SetInput(reader->GetOutput());
  resampler->SetDeformationFieldSpacing(gridSpacing);
  resampler->SetOutputOrigin(origin);
  resampler->SetOutputSize(size);
  resampler->SetOutputSpacing(spacing);
  resampler->SetOutputProjectionRef(utmRef);

  // Write the resampled image
  typedef otb::StreamingImageFileWriter<ImageType>    WriterType;
  WriterType::Pointer writer= WriterType::New();
  writer->SetTilingStreamDivisions(4);
  writer->WriteGeomFileOn();
  writer->SetFileName(outfname);
  writer->SetInput(resampler->GetOutput());
  writer->Update();

  return 0;
}
<|endoftext|>


<commit_before>#include <kprint>
#include <info>
#include <service>
#include <smp>
#include <boot/multiboot.h>

extern  void default_stdout_handlers();
extern  void __platform_init();

extern "C" {
  void __init_serial1();
  void __init_sanity_checks();
  void kernel_sanity_checks();
  uintptr_t _multiboot_free_begin(uintptr_t boot_addr);
  uintptr_t _move_symbols(uintptr_t loc);
  void _init_bss();
  void _init_heap(uintptr_t);
  void _init_c_runtime();
  void _init_syscalls();
  void __libc_init_array();
  uintptr_t _end;

  void kernel_start(uintptr_t magic, uintptr_t addr){

    // Initialize serial port 1
    __init_serial1();

    // generate checksums of read-only areas etc.
    __init_sanity_checks();

    // Determine where free memory starts
    uintptr_t free_mem_begin = reinterpret_cast<uintptr_t>(&_end);

    if (magic == MULTIBOOT_BOOTLOADER_MAGIC) {
      free_mem_begin = _multiboot_free_begin(addr);
    }

    // Preserve symbols from the ELF binary
    free_mem_begin += _move_symbols(free_mem_begin);

    // Initialize zero-initialized vars
    _init_bss();

    // Initialize heap
    _init_heap(free_mem_begin);

    //Initialize stack-unwinder, call global constructors etc.
    _init_c_runtime();

    // Initialize system calls
    _init_syscalls();

    //Initialize stdout handlers
    default_stdout_handlers();

    // Call global ctors
    __libc_init_array();

    __platform_init();

    // Start the service
    Service::start();

    // verify certain read-only sections in memory
    kernel_sanity_checks();

    __arch_poweroff();

  }
}
<commit_msg>kernel_start: add license text<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2017 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <kprint>
#include <info>
#include <service>
#include <smp>
#include <boot/multiboot.h>

extern  void default_stdout_handlers();
extern  void __platform_init();

extern "C" {
  void __init_serial1();
  void __init_sanity_checks();
  void kernel_sanity_checks();
  uintptr_t _multiboot_free_begin(uintptr_t boot_addr);
  uintptr_t _move_symbols(uintptr_t loc);
  void _init_bss();
  void _init_heap(uintptr_t);
  void _init_c_runtime();
  void _init_syscalls();
  void __libc_init_array();
  uintptr_t _end;

  void kernel_start(uintptr_t magic, uintptr_t addr)
  {

    // Initialize serial port 1
    __init_serial1();

    // generate checksums of read-only areas etc.
    __init_sanity_checks();

    // Determine where free memory starts
    uintptr_t free_mem_begin = reinterpret_cast<uintptr_t>(&_end);

    if (magic == MULTIBOOT_BOOTLOADER_MAGIC) {
      free_mem_begin = _multiboot_free_begin(addr);
    }

    // Preserve symbols from the ELF binary
    free_mem_begin += _move_symbols(free_mem_begin);

    // Initialize zero-initialized vars
    _init_bss();

    // Initialize heap
    _init_heap(free_mem_begin);

    //Initialize stack-unwinder, call global constructors etc.
    _init_c_runtime();

    // Initialize system calls
    _init_syscalls();

    //Initialize stdout handlers
    default_stdout_handlers();

    // Call global ctors
    __libc_init_array();

    __platform_init();

    // Start the service
    Service::start();

    // verify certain read-only sections in memory
    kernel_sanity_checks();

    __arch_poweroff();

  }
}
<|endoftext|>