Example #1
0
bool
AtlasBuilder::build(const ResourceLibrary* inputLib,
                    const std::string&     newAtlasURI,
                    Atlas&                 out          ) const
{
    if ( !inputLib )
        return false;

    // prepare an atlaser:
    TextureAtlasBuilderEx tab;

    // maximum size of the texture (x,y)
    tab.setMaximumAtlasSize( (int)_width, (int)_height );

    // texels between atlased images
    tab.setMargin( 1 );

    // clone the Resource library so we can re-write the URIs and add 
    // texture matrix information.
    out._lib = new ResourceLibrary( inputLib->getConfig() );
    out._lib->initialize( _options );
    out._lib->uri().unset();

    // store a mapping from atlasbuilder source to skin.
    typedef std::map<TextureAtlasBuilderEx::SourceEx*, SkinResource*> SourceSkinMap;
    SourceSkinMap sourceSkins;

    // fetch all the skins from the catalog:
    SkinResourceVector skins;
    out._lib->getSkins( skins );
    for(SkinResourceVector::iterator i = skins.begin(); i != skins.end(); ++i)
    {
        SkinResource* skin = i->get();
        osg::Image* image = skin->createImage( _options );
        if ( image )
        {
            // ensure we're not trying to atlas an atlas.
            if ( image->r() > 1 )
            {
                OE_WARN << LC <<
                    "Found an image with more than one layer. You cannot create an "
                    "altas from another atlas. Stopping." << std::endl;
                return false;
            }

            tab.addSource( image );

            // re-write the URI to point at our new atlas:
            skin->imageURI() = newAtlasURI;

            // save the associate so we can come back later:
            sourceSkins[tab.getSourceList().back().get()] = skin;

            OE_INFO << LC << "Added skin: \"" << skin->name() << "\"" << std::endl;
        }
        else
        {
            OE_WARN << LC << "Failed to load image from catalog: \""
                << skin->name() << "\" ... skipped" << std::endl;
        }
    }

    unsigned numSources = tab.getNumSources();
    OE_INFO << LC << "Added " << numSources << " images ... building atlas ..." << std::endl;

    // build the atlas images.
    tab.buildAtlas();

    const TextureAtlasBuilderEx::AtlasListEx& atlasList = tab.getAtlasList();

    // create the target multi-layer image.
    out._image = new osg::Image();
    out._image->allocateImage(
        _width,
        _height,
        atlasList.size(),
        GL_RGBA,
        GL_UNSIGNED_BYTE);

    // initialize to all zeros
    memset(out._image->data(), 0, out._image->getTotalSizeInBytesIncludingMipmaps());

    // combine each of the atlas images into the corresponding "r" slot of the composed image:
    for(int r=0; r<(int)atlasList.size(); ++r)
    {
        // copy the atlas image into the image array:
        osg::Image* atlasImage = atlasList[r]->_image.get();

        ImageUtils::PixelReader read (atlasImage);
        ImageUtils::PixelWriter write(out._image.get());

        for(int s=0; s<atlasImage->s(); ++s)
            for(int t=0; t<atlasImage->t(); ++t)
                write(read(s, t, 0), s, t, r);

        // for each source in this atlas layer, apply its texture matrix info
        // to the new catalog.
        for(int k=0; k<atlasList[r]->_sourceList.size(); ++k)
        {
            TextureAtlasBuilderEx::SourceEx* source = atlasList[r]->_sourceList[k].get();
            SourceSkinMap::iterator n = sourceSkins.find(source);
            if ( n != sourceSkins.end() )
            {                
                SkinResource* skin = n->second;
                skin->imageLayer()  = r;
                skin->imageBiasS()  = (float)source->_x/(float)atlasImage->s(); //(float)trans.x();
                skin->imageBiasT()  = (float)source->_y/(float)atlasImage->t(); //(float)trans.y();
                skin->imageScaleS() = (float)source->_image->s()/(float)atlasImage->s();
                skin->imageScaleT() = (float)source->_image->t()/(float)atlasImage->t();
            }
        }
    }

    return true;
}