#0 

20-01-2015 21:10:10

Magun
SleekThink Producer
Lieu: Punakha
Date d'inscription: 18-11-2007
Messages: 903
Corrections: 2
Site web

C'est un loader d'image BLP (utiliser par warcraft 3, warcraft 3 frozen trone, et wow, correspondant au revision 0, 1, 2)
ce loader implementes toutes les features du format, mais seulement le premier niveaux de mipmap est charger à cause de l'architecture d'irrlicht
de tout façon le mipmap peut-être régénéré quand l'image est transformaer en texture avec une feature du driver d'irrlicht

pour la compilation, je sugère d'ajouter le dossier jpeglib du dossier des sources d'irrlicht pour que les informations coincide avec le header

Code c++ :

#ifndef __C_BLP_IMAGE_LOADER_H_INCLUDED__
#define __C_BLP_IMAGE_LOADER_H_INCLUDED__

/**
* Copyright (C) <2014>
* Ovan/Magun contact on irrlicht-fr.org or ovan@sleek-think.ovh
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
*    claim that you wrote the original software. If you use this software
*    in a product, an acknowledgment in the product documentation would be
*    appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/


#include "IrrCompileConfig.h"
#define _IRR_COMPILE_WITH_BLP_LOADER_

// force plugin compilation
// guard efined if loader included to the engine
#ifdef _IRR_COMPILE_WITH_BLP_LOADER_

#include <IImageLoader.h>

namespace irr
{
    namespace video
    {
        struct sharedheader;
        class IVideoDriver;
        class CImageLoaderBLP : public IImageLoader
        {
            protected:
                enum Compression : int
                {
                    JPG = 0,
                    BLP = 1,
                    RAW = 2,
                    DXT = 3
                };
            public:
                CImageLoaderBLP(IVideoDriver*);
                virtual ~CImageLoaderBLP();

                virtual bool isALoadableFileExtension(const io::path& filename) const;
                virtual bool isALoadableFileFormat(io::IReadFile* file) const;
                virtual IImage* loadImage(io::IReadFile* file) const;
            protected:
                IImage* decompressBLP(const sharedheader&, char *, size_t) const;
                IImage* decompressDXT(const sharedheader&, char *, size_t) const;
                IImage* decompressRaw(const sharedheader&, char *, size_t) const;
                IImage* decompressJpg(const sharedheader&, char *, size_t) const;
            private:
                IVideoDriver *driver;
        };

        IImageLoader* createImageLoaderBLP();
    }
}

#endif
#endif


Code c++ :

#include "CImageLoaderBLP.h"

#ifdef _IRR_COMPILE_WITH_BLP_LOADER_

#include <IVideoDriver.h>
#include <IReadFile.h>
#include <IImage.h>
#include <irrString.h>
#include <iostream>
#include "jpeglib.h"

namespace irr
{
    namespace video
    {
        struct sharedheader
        {
            u32 compression;
            u32 flags;
            u32 width;
            u32 height;
            u32 alpha_depth;
            u32 mipmap_offsets[16];
            u32 mipmap_lengths[16];
            u32 palette[265];
        };

        struct blpheader
        {
            u32 compression;
            u32 flags;
            u32 width;
            u32 height;
            u32 alpha_depth;
            u32 pictureSubType;
            u32 mipmap_offsets[16];
            u32 mipmap_lengths[16];
        };

        struct blp2header
        {
            u32   type;               // 0 = JPG, 1 = BLP / DXTC / Uncompressed
            u8    compression;        // 1 = BLP, 2 = DXTC, 3 = Uncompressed
            u8    alpha_depth;        // 0, 1, 4, or 8
            u8    alpha_type;         // 0, 1, 7, or 8
            u8    has_mips;           // 0 = no mips, 1 = has mips
            u32   width;              // Image width in pixels, usually a power of 2
            u32   height;             // Image height in pixels, usually a power of 2
            u32   mipmap_offsets[16]; // The file offsets of each mipmap, 0 for unused
            u32   mipmap_lengths[16]; // The length of each mipmap data block
        };

        CImageLoaderBLP::CImageLoaderBLP(irr::video::IVideoDriver *d) : driver(d)
        {
            #ifdef _DEBUG
            setDebugName("CImageLoaderBLP");
            #endif
        }

        //! destructor
        CImageLoaderBLP::~CImageLoaderBLP()
        {
        }

        bool CImageLoaderBLP::isALoadableFileExtension(const io::path& filename) const
        {
            return core::hasFileExtension(filename, "blp");
        }

        bool CImageLoaderBLP::isALoadableFileFormat(io::IReadFile* file) const
        {
            if(!file)
                return false;

            char buf[4];
            file->read(buf, 4);

            return buf[0] == 'B' && buf[1] == 'L' && buf[2] == 'P' &&
                   (buf[3] == '2' || buf[3] == '1' || buf[3] == '0');
        }

        IImage* CImageLoaderBLP::loadImage(io::IReadFile* file) const
        {
            if(!file)
                return 0;

            char blpid[4];
            file->read(blpid, 4);

            if(blpid[0] != 'B' || blpid[1] != 'L' || blpid[2] != 'P' ||
               !(blpid[3] == '2' || blpid[3] == '1' || blpid[3] == '0'))
               return 0;

            sharedheader shd;

            if(blpid[3] < '2')
            {
                std::cout << "war3 revision" << std::endl;

                blpheader header;
                file->read(&header, sizeof(blpheader));

                shd.compression = header.compression;
                shd.flags = header.flags;
                shd.width = header.width;
                shd.height = header.height;
                shd.alpha_depth = header.alpha_depth;

                for(int i = 0; i<16; ++i)
                {
                    shd.mipmap_offsets[i] = header.mipmap_offsets[i];
                    shd.mipmap_lengths[i] = header.mipmap_lengths[i];
                }
            }
            else
            {
                std::cout << "wow revision" << std::endl;

                blp2header header;
                file->read(&header, sizeof(blp2header));

                shd.flags = header.alpha_type;
                shd.width = header.width;
                shd.height = header.height;
                shd.alpha_depth = header.alpha_depth;

                for(int i = 0; i<16; ++i)
                {
                    shd.mipmap_offsets[i] = header.mipmap_offsets[i];
                    shd.mipmap_lengths[i] = header.mipmap_lengths[i];
                }

                if(header.type == 0)
                    shd.compression = JPG;
                else
                {
                    switch(header.compression)
                    {
                        case 1:  shd.compression = BLP; break;
                        case 2:  shd.compression = DXT; break;
                        default: shd.compression = RAW; break;
                    }
                    shd.flags = header.alpha_depth;
                }
            }

            std::cout << "compression: " << std::to_string(shd.compression) << std::endl;
            // only the first mipmap is loader, other can be generated by the engine

            switch(shd.compression)
            {
                case JPG:
                {
                    u32 jpegHeaderSize = 0;
                    file->read(&jpegHeaderSize, 4);
                    char *data = new char[shd.mipmap_lengths[0] + jpegHeaderSize];
                    file->read(data, jpegHeaderSize);
                    file->seek(shd.mipmap_offsets[0]);
                    file->read(data+jpegHeaderSize, shd.mipmap_lengths[0]);
                    return decompressJpg(shd, data, shd.mipmap_lengths[0] + jpegHeaderSize);
                }
                break;
                case BLP:
                {
                    file->read(shd.palette, 256*sizeof(u32));
                    for(int i = 0; i<256; ++i)
                    {
                        // from rgba
                        SColor c = shd.palette[i];
                        shd.palette[i] = SColor(
                            255-c.getRed(),
                            c.getGreen(),
                            c.getBlue(),
                            c.getAlpha()
                        ).color;
                    }
                    file->seek(shd.mipmap_offsets[0]);
                    char *data = new char[shd.mipmap_lengths[0]];
                    file->read(data, shd.mipmap_lengths[0]);
                    return decompressBLP(shd, data, shd.mipmap_lengths[0]);
                }
                break;
                case DXT:
                {
                    file->seek(shd.mipmap_offsets[0]);
                    char *data = new char[shd.mipmap_lengths[0]];
                    file->read(data, shd.mipmap_lengths[0]);
                    return decompressDXT(shd, data, shd.mipmap_lengths[0]);
                }
                break;
                default:
                {
                    file->seek(shd.mipmap_offsets[0]);
                    char *data = new char[shd.mipmap_lengths[0]];
                    file->read(data, shd.mipmap_lengths[0]);
                    return decompressRaw(shd, data, shd.mipmap_lengths[0]);
                }
                break;
            }

            return 0;
        }

        IImage* CImageLoaderBLP::decompressBLP(const sharedheader &header, char *data, size_t size) const
        {
            IImage *tmp = driver->createImage(
                ECF_A8R8G8B8,
                core::dimension2du(header.width, header.height)
            );

            for(int height = 0; height < header.height; ++height)
            {
                for(int width = 0; width < header.width; ++width)
                {
                    unsigned char index = (unsigned char)data[width + header.width*height];
                    tmp->setPixel(width, height, SColor(header.palette[index]));
                }
            }

            if(header.alpha_depth == 3 || header.alpha_depth == 4)
            {
                char *alpha = data + header.width*header.height;
                for(int height = 0; height < header.height; ++height)
                {
                    for(int width = 0; width < header.width; ++width)
                    {
                        SColor c(tmp->getPixel(width, height));
                        c.setAlpha(alpha[width + header.width*height]);
                        tmp->setPixel(width, height, c);
                    }
                }
            }

            delete [] data;
            return tmp;
        }
        IImage* CImageLoaderBLP::decompressDXT(const sharedheader &header, char *data, size_t size) const
        {
            ECOLOR_FORMAT dxt;

            // untested section (no file found)
            // the doc tell that the header.palette is used to compute DXTC
            // but I suppose that irrlicht DXTC does not require it

            if(header.flags == 0)
                dxt = ECF_DXT1;
            if(header.flags == 1)
                dxt = ECF_DXT3;
            if(header.flags == 7)
                dxt = ECF_DXT5;

            return driver->createImageFromData(
                dxt,
                core::dimension2du(header.width, header.height),
                data, true, true
            );
        }
        IImage* CImageLoaderBLP::decompressRaw(const sharedheader &header, char *data, size_t size) const
        {
            ECOLOR_FORMAT dxt;

            if(header.alpha_depth == 0)
                 dxt = ECF_R8G8B8;
            else dxt = ECF_A8R8G8B8;

            // untested section (no file found)

            IImage *tmp = driver->createImageFromData(
                ECF_A8R8G8B8,
                core::dimension2du(header.width, header.height),
                data, true, true
            );

            return tmp;
        }
        IImage* CImageLoaderBLP::decompressJpg(const sharedheader &header, char *buffer, size_t size) const
        {
            struct jpeg_error_mgr jerr;
            struct jpeg_decompress_struct cinfo;
            cinfo.err = jpeg_std_error(&jerr);
            jpeg_create_decompress(&cinfo);

            jpeg_mem_src(&cinfo, (unsigned char*)buffer, size);

            if(jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK ||
              !jpeg_start_decompress(&cinfo))
            {
                jpeg_finish_decompress(&cinfo);
                jpeg_destroy_decompress(&cinfo);
                return 0;
            }

            IImage *tmp = driver->createImage(
                ECF_A8R8G8B8,
                core::dimension2du(cinfo.image_width, cinfo.image_height)
            );

            const JDIMENSION requiredScanlines = cinfo.output_height;
            const JDIMENSION scanlineSize = cinfo.output_width * cinfo.output_components;

            JSAMPARRAY scanlines = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, scanlineSize, requiredScanlines);

            while(cinfo.output_scanline < cinfo.output_height)
            {
                const JDIMENSION currentScanline = cinfo.output_scanline;
                const JDIMENSION dimension = jpeg_read_scanlines(&cinfo, scanlines, requiredScanlines);

                for(int height = 0; height < dimension; ++height)
                {
                    int width = 0;
                    for(int component = 0; component < scanlineSize; component += cinfo.output_components)
                    {
                        u32 argb = ((u32)scanlines[height][component]) |
                                   ((u32)scanlines[height][component + 1] << 8) |
                                   ((u32)scanlines[height][component + 2] << 16);

                        if(cinfo.output_components == 4)
                            argb |= ((u32)(scanlines[height][component + 3]) << 24);

                        tmp->setPixel(width, height + currentScanline, argb);
                        ++width;
                    }
                }
            }

            jpeg_finish_decompress(&cinfo);
            jpeg_destroy_decompress(&cinfo);
            return tmp;
        }
    }
}

#endif


utilisation

Code c++ :

driver->addExternalImageLoader(new irr::video::CImageLoaderBLP(driver));
driver->getTexture("CImageLoaderBLP");


fait attention pour les formats Raw et DXTC, il ne sont pas tester (faute de n'avoir pue trouver des fichier de test)

voud pouvez trouver des ressources sur  http://www.hiveworkshop.com/forums/icons.php & http://www.hiveworkshop.com/forums/skins.php

post forum-off:
http://irrlicht.sourceforge.net/forum/v … mp;t=50551

Hors ligne


Options Liens officiels Caractéristiques Statistiques Communauté
Corrections
irrlicht
irrklang
irredit
irrxml
xhtml 1.0
css 2.1
Propulsé par FluxBB
Traduit par FluxBB.fr
Analysé par
876 membres
1424 sujets
11110 messages
Dernier membre inscrit: uriel988
5 invités en ligne
Aucun membre connecté
RSS Feed