Hi Robert,

I found letting the image cache enabled in ProxyLoadImageCallback::load() is a 
mistake, since we are INSIDE an image and can't rely on getting a shared 
ref_ptr to a cached ressource (else we would have wrong deallocations or memory 
leaks, depending on the code we write after).
Attached to this mail is my new Callbacks.cpp, with the fix.

Also added to the same file is the ability to handle writing of proxy images in 
the case the format has changed (ex: you load a JPEG and want to write a DDS). 
Here the EmptyImagesWriteFileCallback actually asks for proxy loading, writes 
the image with the appropriate writer, and then deallocates the image. I think 
the deallocation may be an option, but it's not implemented (because I don't 
need it for now ;p ).

Sorry for submitting changes with so little interval, but I think it's 
important (And there is a chance you did not start reviewing, so better sooner 
than later!).

Sukender
PVLE - Lightweight cross-platform game engine - http://pvle.sourceforge.net/

----- "Sukender" <[email protected]> a écrit :

> All done, sir Robert!
> 
> Attached submission contains both previous one (about proxy images),
> and calbacks as we discussed, still after trunk rev. 10898.
> Please note I've split the file copy operation and make it available
> to all (into FileUtils). I guess this will be a "long temporary" code,
> before C++ TR2 comes into most compilers (I've heard TR2's STL will
> include <filesystem>, which is made from boost.filesystem).
> 
> Once again: happy reviewing!
> 
> Sukender
> PVLE - Lightweight cross-platform game engine -
> http://pvle.sourceforge.net/
> 
> ----- "Robert Osfield" <[email protected]> a écrit :
> 
> > Hi Sukender,
> > 
> > On Thu, Dec 17, 2009 at 10:10 AM, Sukender <[email protected]>
> wrote:
> > > The "noTexture" option was something I added recently in 3DS
> > (submitted) and in FBX (not submitted: the last submission does not
> > include it). I guess nobody uses it.
> > 
> > Good, since you wrote it, I do believe you are in a good place to
> > decide that it's past it's sell by date ;-)
> > 
> > > BTW, did you review the submission of the FBX plugin (with write
> > support)?
> > 
> > Not yet.  Been juggling other tasks.
> > 
> > > I'll make another submission soon. It'll roughly contain what
> I've
> > put in the "helper" file. Or do you prefer doing it by yourself?
> > 
> > Could you make another submission in the final form that you feel
> is
> > appropriate to merge.
> > 
> > Cheers,
> > Robert.
> > _______________________________________________
> > osg-submissions mailing list
> > [email protected]
> >
> http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
> 
> _______________________________________________
> osg-submissions mailing list
> [email protected]
> http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * OpenSceneGraph Public License for more details.
*/

#include <osgDB/Callbacks>
#include <osgDB/Registry>

using namespace osgDB;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// FindFileCallback default implementation
//
std::string FindFileCallback::findDataFile(const std::string& filename, const 
Options* options, CaseSensitivity caseSensitivity)
{
    return osgDB::Registry::instance()->findDataFileImplementation(filename, 
options, caseSensitivity);
}

std::string FindFileCallback::findLibraryFile(const std::string& filename, 
const Options* options, CaseSensitivity caseSensitivity)
{
    return osgDB::Registry::instance()->findLibraryFileImplementation(filename, 
options, caseSensitivity);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ReadFileCallback default implementation
//
ReaderWriter::ReadResult ReadFileCallback::openArchive(const std::string& 
filename,ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, 
const Options* useObjectCache)
{
    return osgDB::Registry::instance()->openArchiveImplementation(filename, 
status, indexBlockSizeHint, useObjectCache);
}

ReaderWriter::ReadResult ReadFileCallback::readObject(const std::string& 
filename, const Options* options)
{
    return 
osgDB::Registry::instance()->readObjectImplementation(filename,options);
}

ReaderWriter::ReadResult ReadFileCallback::readImage(const std::string& 
filename, const Options* options)
{
    return 
osgDB::Registry::instance()->readImageImplementation(filename,options);
}

ReaderWriter::ReadResult ReadFileCallback::readHeightField(const std::string& 
filename, const Options* options)
{
    return 
osgDB::Registry::instance()->readHeightFieldImplementation(filename,options);
}

ReaderWriter::ReadResult ReadFileCallback::readNode(const std::string& 
filename, const Options* options)
{
    return 
osgDB::Registry::instance()->readNodeImplementation(filename,options);
}

ReaderWriter::ReadResult ReadFileCallback::readShader(const std::string& 
filename, const Options* options)
{
    return 
osgDB::Registry::instance()->readShaderImplementation(filename,options);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// WriteFileCallback default implementation
//
ReaderWriter::WriteResult WriteFileCallback::writeObject(const osg::Object& 
obj, const std::string& fileName,const Options* options)
{
    return 
osgDB::Registry::instance()->writeObjectImplementation(obj,fileName,options);
}

ReaderWriter::WriteResult WriteFileCallback::writeImage(const osg::Image& obj, 
const std::string& fileName,const Options* options)
{
    return 
osgDB::Registry::instance()->writeImageImplementation(obj,fileName,options);
}

ReaderWriter::WriteResult WriteFileCallback::writeHeightField(const 
osg::HeightField& obj, const std::string& fileName,const Options* options)
{
    return 
osgDB::Registry::instance()->writeHeightFieldImplementation(obj,fileName,options);
}

ReaderWriter::WriteResult WriteFileCallback::writeNode(const osg::Node& obj, 
const std::string& fileName,const Options* options)
{
    return 
osgDB::Registry::instance()->writeNodeImplementation(obj,fileName,options);
}

ReaderWriter::WriteResult WriteFileCallback::writeShader(const osg::Shader& 
obj, const std::string& fileName,const Options* options)
{
    return 
osgDB::Registry::instance()->writeShaderImplementation(obj,fileName,options);
}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// NoTextureReadFileCallback, DelayedTextureReadFileCallback
//

ReaderWriter::ReadResult osgDB::NoTextureReadFileCallback::readImage(const 
std::string& filename, const Options* options) {
    osg::ref_ptr<osg::Image> image = new osg::Image;
    image->setFileName(filename);
    return image.get();
}


ReaderWriter::ReadResult osgDB::DelayedTextureReadFileCallback::readImage(const 
std::string& filename, const osgDB::Options* options) {
    osg::ref_ptr<osg::Image> image = new osg::Image;
    image->setFileName(filename);        // Not necessary since 
ProxyLoadImageCallback does it, but it is used as a name when writing image to 
a file.
    image->setProxyLoadCallback(new ProxyLoadImageCallback(filename, options));
    return image.get();
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// EmptyImagesWriteFileCallback
//

#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>

std::string canonicalExtension(const std::string & _ext) {
        std::string ext = osgDB::getLowerCaseFileExtension(_ext);
    if (ext == "tif") return "tiff";
    if (ext == "jpg") return "jpeg";
    if (ext == "jp2" || ext == "jpc" || ext == "jpg2000") return "jpeg2000";
        return ext;
}


osgDB::ReaderWriter::WriteResult EmptyImagesWriteFileCallback::writeImage(const 
osg::Image& obj, const std::string& fileName, const osgDB::Options* options) {
    // Use standard writer for normal images
    if (obj.validNoProxy()) return osgDB::WriteFileCallback::writeImage(obj, 
fileName, options);
    // We have an dummy, proxy or invalid image.

    // Handle the case where format has changed
    const std::string & source = obj.getProxyLoadCallback() && 
!obj.getProxyLoadCallback()->getFileName().empty() ? 
obj.getProxyLoadCallback()->getFileName() : obj.getFileName();
    std::string extSource      = canonicalExtension(source);
    std::string extDestination = canonicalExtension(fileName);
    if (extSource != extDestination) {
        if (!obj.valid()) {
            osg::notify(osg::NOTICE) << 
"EmptyImagesWriteFileCallback::writeImage(): Source filename has different 
extension than destination (" << extSource << "!=" << extDestination << "), but 
source isn't valid for reading." << std::endl;
            return osgDB::ReaderWriter::WriteResult::FILE_SAVED;        // 
Return success since it's not an output error.
        } else {
            if (extDestination.empty()) {
                osg::notify(osg::NOTICE) << 
"EmptyImagesWriteFileCallback::writeImage(): Destination filename has empty 
extension." << std::endl;
                //return 
osgDB::ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE;
                // Still try to do load/write...
            }

                        // Load image
            obj.doProxyLoading();        // Can be called on const objects 
(cache-style mechanism)
            if (!obj.validNoProxy()) {
                osg::notify(osg::NOTICE) << 
"EmptyImagesWriteFileCallback::writeImage(): Source filename has different 
extension than destination (" << extSource << "!=" << extDestination << "), but 
source proxy loading failed." << std::endl;
                return osgDB::ReaderWriter::WriteResult::FILE_SAVED;        // 
Return success since it's not an output error.
            }

                        // Write image file
            ReaderWriter::WriteResult res = 
osgDB::WriteFileCallback::writeImage(obj, fileName, options);

            // Unload image (proxy isn't removed so latter re-loading is still 
possible)
            const_cast<osg::Image &>(obj).setImage(0, 0, 0, 0, 0, 0, NULL, 
osg::Image::NO_DELETE);
            //const_cast<osg::Image &>(obj).setImage(0, 0, 0, 
obj.getInternalTextureFormat(), obj.getPixelFormat(), obj.getDataType(), NULL, 
osg::Image::NO_DELETE, obj.getPacking());
            //const_cast<osg::Image &>(obj).setData(NULL, 
osg::Image::NO_DELETE);

                        return res;
        }
    }

    // Try to copy the original file.
    if (source.empty()) {
        osg::notify(osg::INFO) << "EmptyImagesWriteFileCallback::writeImage(): 
Found empty image without a file name. Can't write anything." << std::endl;
        return osgDB::ReaderWriter::WriteResult::FILE_SAVED;        // Return 
success since it's not an output error.
    }

    osgDB::FileOpResult::Value copyResult = osgDB::copyFile(source, fileName);

    // Succeeded?
    if (copyResult == osgDB::FileOpResult::OK || copyResult == 
osgDB::FileOpResult::SOURCE_EQUALS_DESTINATION) {
        return osgDB::ReaderWriter::WriteResult::FILE_SAVED;
    }

    // Source missing?
    if (copyResult == osgDB::FileOpResult::SOURCE_MISSING) {
        osg::notify(osg::NOTICE) << 
"EmptyImagesWriteFileCallback::writeImage(): Initial image file does not exist: 
" << source << std::endl;
        return osgDB::ReaderWriter::WriteResult::FILE_SAVED;        // Return 
success since it's not an output error.
    }

    // Other error
    return osgDB::ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ProxyLoadImageCallback
//

#include <assert.h>

void ProxyLoadImageCallback::load(osg::Image & image) const {
    // We need to load an image, but without a file callback, hence the 
"osgDB::Registry::instance()->readImageImplementation" instead of 
"osgDB::readImageFile" (Thanks to Robert Osfield)
    osg::ref_ptr<osgDB::Options> localOptions = new osgDB::Options(*options);   
     // Create local options so that we can modify them
        // Remove cache, because we're inside osg::Image, and thus can't rely 
on getting a shared ref_ptr to a cached ressource (else we would have wrong 
deallocations or memory leaks).
        
localOptions->setObjectCacheHint(static_cast<osgDB::Options::CacheHintOptions>( 
localOptions->getObjectCacheHint() & ~osgDB::Options::CACHE_IMAGES ));
    ReaderWriter::ReadResult res = 
osgDB::Registry::instance()->readImageImplementation(filename, localOptions);
    if (!res.success()) return;

    osg::Image * loadedImage = static_cast<osg::Image *>( res.getObject() );
        assert(loadedImage);
    // Ensure there is no proxy on the loaded image, or else this would leads 
to an infinite loop
    loadedImage->setProxyLoadCallback(NULL);
    // Transfer data
    image.setImage(loadedImage->s(), loadedImage->t(), loadedImage->r(),
        loadedImage->getInternalTextureFormat(), loadedImage->getPixelFormat(), 
loadedImage->getDataType(),
        loadedImage->data(), loadedImage->getAllocationMode(), 
loadedImage->getPacking());
    //image.setFileName(filename);              // Must not in order to keep 
re-loading/writing as an identical operation.
    // Avoid the original image to delete image data
    loadedImage->setAllocationMode(osg::Image::NO_DELETE);
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to