Hi Robert,

This fixes a small problem in .osg files, where inline shaders would have an extra newline per line:

          Shader {
            type VERTEX
            code {
              "#version 120
"
              "#extension GL_EXT_geometry_shader4 : enable
"
              "uniform mat4 osg_ViewMatrixInverse;
"
              "
"

...

This is because the shader is being written directly from the string (_shaderSource) to the .osg file, and that string contains newlines.

osgDB::Output::wrapString() is called from src/osgWrappers/deprecated-dotosg/osg/Shader.cpp : Shader_writeLocalData(). I made the change to osgDB::Output::wrapString() because I think in no case would we want to keep those newlines when writing a wrapped string, because the wrapping itself adds a newline after each closing quote of each line anyways. So the same shader above now looks like:

          Shader {
            type VERTEX
            code {
              "#version 120"
              "#extension GL_EXT_geometry_shader4 : enable"
              "uniform mat4 osg_ViewMatrixInverse;"
              ""

...

I also made the corresponding change for the new .osgt plugin. AsciiOutputIterator::writeWrappedString() is called from src/osgWrappers/serializers/osg/Shader.cpp : writeShaderSource(). Again the change will take effect for any wrapped string. I have tested this and it fixes it too.

The reading already adds a newline to each line of code read from the .osg/.osgt file, so the shader code we read will be what we want. The only thing that didn't work on reading was that empty lines were discarded in the old deprecated .osg plugin. The change to src/osgWrappers/deprecated-dotosg/osg/Shader.cpp fixes that.

So Output.cpp goes in src/osgDB, AsciiStreamOperator.h goes in src/osgPlugins/osg, and Shader.cpp goes in src/osgWrappers/deprecated-dotosg/osg/

By the way, is there a way of commenting out lines in the old or new .osg/.osgt formats?

Thanks, and sorry for being verbose.

J-S

--
______________________________________________________
Jean-Sebastien Guay    jean-sebastien.g...@cm-labs.com
                               http://www.cm-labs.com/
                        http://whitestar02.webhop.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/Output>
#include <osgDB/Registry>
#include <osgDB/FileNameUtils>

#include <osg/Notify>

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

using namespace std;
using namespace osgDB;

static osg::ApplicationUsageProxy 
Output_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WRITE_OUT_DEFAULT_VALUES",
 "ON | OFF");

Output::Output()
{
    init();
}

Output::Output(const char* name) : osgDB::ofstream(name)
{
    init();
    _filename = name;
}

Output::~Output()
{
}


void Output::init()
{
    _indent = 0;
    _indentStep = 2;
    _numIndicesPerLine = 10;
    _pathNameHint = AS_IS;
    
    _outputTextureFiles = false;
    _textureFileNameNumber = 0;

    _outputShaderFiles = false;
    _shaderFileNameNumber = 0;
    
    _writeOutDefaultValues = false;

    const char* env = getenv("OSG_WRITE_OUT_DEFAULT_VALUES");
    if (env)
    {
        _writeOutDefaultValues = strcmp(env,"ON")==0;
    }
}

void Output::setOptions(const Options* options)
{
    _options = options;
}

void Output::open(const char *name)
{
    init();
    osgDB::ofstream::open(name);
    _filename = name;
}

// Comment out to avoid compile errors under new compilers, the int mode
// is now a replaced by a class to wrap the mode.  
// This method is not used right now to hopefully nobody will miss it... 
// Jan 2002.
// void Output::open(const char *name,int mode)
// {
//     init();
//     ofstream::open(name,mode);
//     _filename = name;
// }

Output& Output::indent()
{
    for(int i=0;i<_indent;++i) *this<<' ';
    return *this;
}



void Output::moveIn()
{
    _indent += _indentStep;
}


void Output::moveOut()
{
    _indent -= _indentStep;
    if (_indent<0) _indent=0;
}

std::string Output::wrapString(const char* str)
{
    if (!str) return std::string("\"\"");
    return wrapString(std::string(str));
}

std::string Output::wrapString(const std::string& str)
{
    std::string newstring;
    newstring += '"';
    for(unsigned int i=0;i<str.size();++i)
    {
        if (str[i]=='\\')
        {
            newstring += '\\';
            newstring += '\\';
        }
        else if (str[i]=='"')
        {
            newstring += '\\';
            newstring += '"';
        }
        else if (str[i] == '\r')
            continue;
        else if (str[i] == '\n')
            continue;
        else newstring += (str[i]);
    }
    newstring += '"';
    return newstring;
}

bool Output::writeObject(const osg::Object& obj)
{
    return 
Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->writeObject(obj,*this);
}


void Output::writeBeginObject(const std::string& name)
{
    indent() << name << " {" << std::endl;
}

void Output::writeEndObject()
{
    indent() << "}" << std::endl;
}

void Output::writeUseID(const std::string& id)
{
    indent() << "Use " << id << std::endl;
}

void Output::writeUniqueID(const std::string& id)
{
    indent() << "UniqueID " << id << std::endl;
}

bool Output::getUniqueIDForObject(const osg::Object* obj,std::string& uniqueID)
{
    UniqueIDToLabelMapping::iterator fitr = _objectToUniqueIDMap.find(obj);
    if (fitr != _objectToUniqueIDMap.end())
    {
        uniqueID = (*fitr).second;
        return true;
    }
    else return false;
}


bool Output::createUniqueIDForObject(const osg::Object* obj,std::string& 
uniqueID)
{
    char str[256];
    sprintf(str,"%s_%i",obj->className(),(unsigned 
int)_objectToUniqueIDMap.size());
    uniqueID = str;
    return true;
}


bool Output::registerUniqueIDForObject(const osg::Object* obj,std::string& 
uniqueID)
{
    _objectToUniqueIDMap[obj] = uniqueID;
    return true;
}

std::string Output::getFileNameForOutput(const std::string& filename) const
{
    switch(_pathNameHint)
    {
    case(FULL_PATH):
        {
            // need to think about how best to implement this first...
            osg::notify(osg::WARN)<<"Warning: Output::getFileNameForOutput() 
does not support FULL_PATH yet."<< std::endl;        
            return filename;
        }
    case(RELATIVE_PATH):
        {
            // need to think about how best to implement this as well...
            osg::notify(osg::WARN)<<"Warning: Output::getFileNameForOutput() 
does not support RELATIVE_PATH yet."<< std::endl;        
            return filename;
        }
    case(FILENAME_ONLY):
        // this one is straight forward.
        return getSimpleFileName(filename);
    case(AS_IS):
    default:
        // and this one is even more trivial.
        return filename;
    }
}

std::string Output::getTextureFileNameForOutput()
{
    std::string fileName = osgDB::getNameLessExtension(_filename);
    if (_textureFileNameNumber>0)
    {
        std::ostringstream o;
        o << '_' << _textureFileNameNumber;
        fileName += o.str();
    }
    
    fileName += ".dds";
    ++_textureFileNameNumber;
    
    return fileName;
}

std::string Output::getShaderFileNameForOutput()
{
    std::string fileName = osgDB::getNameLessExtension(_filename);
    if (_shaderFileNameNumber>0)
    {
        std::ostringstream o;
        o << '_' << _shaderFileNameNumber;
        fileName += o.str();
    }
    
    fileName += ".glsl";
    ++_shaderFileNameNumber;
    
    return fileName;
}

void Output::setExternalFileWritten(const std::string& filename, bool 
hasBeenWritten)
{
    _externalFileWritten[filename] = hasBeenWritten;
}

bool Output::getExternalFileWritten(const std::string& filename) const
{
    ExternalFileWrittenMap::const_iterator itr = 
_externalFileWritten.find(filename);
    if (itr != _externalFileWritten.end()) return itr->second;
    return false;
}
#ifndef OSGDB_ASCIISTREAMOPERATOR
#define OSGDB_ASCIISTREAMOPERATOR

#include <osgDB/StreamOperator>

class AsciiOutputIterator : public osgDB::OutputIterator
{
public:
    AsciiOutputIterator( std::ostream* ostream )
    : _readyForEndBracket(false), _indent(0) { _out = ostream; }
    
    virtual ~AsciiOutputIterator() {}
    
    virtual bool isBinary() const { return false; }
    
    virtual void writeBool( bool b )
    {
        if ( b ) *_out << "TRUE ";
        else *_out << "FALSE ";
    }
    
    virtual void writeChar( char c )
    { *_out << (short)c << ' '; }
    
    virtual void writeUChar( unsigned char c )
    { *_out << (unsigned short)c << ' '; }
    
    virtual void writeShort( short s )
    { *_out << s << ' '; }
    
    virtual void writeUShort( unsigned short s )
    { *_out << s << ' '; }
    
    virtual void writeInt( int i )
    { *_out << i << ' '; }
    
    virtual void writeUInt( unsigned int i )
    { *_out << i << ' '; }
    
    virtual void writeLong( long l )
    { *_out << l << ' '; }
    
    virtual void writeULong( unsigned long l )
    { *_out << l << ' '; }
    
    virtual void writeFloat( float f )
    { *_out << f << ' '; }
    
    virtual void writeDouble( double d )
    { *_out << d << ' '; }
    
    virtual void writeString( const std::string& s )
    { *_out << s << ' '; }
    
    virtual void writeStream( std::ostream& (*fn)(std::ostream&) )
    {
        *_out << fn;
        if ( fn==static_cast<std::ostream& (*)(std::ostream&)>(std::endl) )
        {
            _readyForEndBracket = true;
            for (int i=0; i<_indent; ++i)
                *_out << ' ';
        }
    }
    
    virtual void writeBase( std::ios_base& (*fn)(std::ios_base&) )
    {
        *_out << fn;
    }
    
    virtual void writeGLenum( const osgDB::ObjectGLenum& value )
    {
        GLenum e = value.get(); 
        const std::string& enumString = 
osgDB::Registry::instance()->getObjectWrapperManager()->getString("GL", e);
        *_out << enumString << ' ';
    }
    
    virtual void writeProperty( const osgDB::ObjectProperty& prop )
    {
        std::string enumString = prop._name;
        if ( prop._mapProperty )
        {
            enumString = 
osgDB::Registry::instance()->getObjectWrapperManager()->getString(prop._name, 
prop._value);
        }
        *_out << enumString << ' ';
    }
    
    virtual void writeMark( const osgDB::ObjectMark& mark )
    {
        int delta = mark._indentDelta;
        if ( delta<0 && _readyForEndBracket )
        {
            if ( _indent<-delta ) delta = -_indent;
            _readyForEndBracket = false;
            _out->seekp( delta, std::ios::cur );
        }
        _indent += delta;
        *_out << mark._name << ' ';
    }
    
    virtual void writeCharArray( const char* s, unsigned int size ) {}
    
    virtual void writeWrappedString( const std::string& str )
    {
        std::string wrappedStr;
        unsigned int size = str.size();
        for ( unsigned int i=0; i<size; ++i )
        {
            char ch = str[i];
            if ( ch=='\"' ) wrappedStr += '\\';
            else if ( ch=='\\' ) wrappedStr += '\\';
            else if ( ch=='\r' ) continue;
            else if ( ch=='\n' ) continue;
            wrappedStr += ch;
        }
        
        wrappedStr.insert( 0, 1, '\"' );
        wrappedStr += '\"';
        writeString( wrappedStr );
    }
    
protected:
    bool _readyForEndBracket;
    int _indent;
};

class AsciiInputIterator : public osgDB::InputIterator
{
public:
    AsciiInputIterator( std::istream* istream ) { _in = istream; }
    virtual ~AsciiInputIterator() {}
    
    virtual bool isBinary() const { return false; }
    
    virtual void readBool( bool& b )
    {
        std::string boolString;
        *_in >> boolString;
        if ( boolString=="TRUE" ) b = true;
        else b = false;
    }
    
    virtual void readChar( char& c )
    {
        short s = 0;
        *_in >> s;
        c = (char)s;
    }
    
    virtual void readSChar( signed char& c )
    {
        short s = 0;
        *_in >> s;
        c = (signed char)s;
    }
    
    virtual void readUChar( unsigned char& c )
    {
        short s = 0;
        *_in >> s;
        c = (unsigned char)s;
    }
    
    virtual void readShort( short& s )
    { *_in >> s; }
    
    virtual void readUShort( unsigned short& s )
    { *_in >> s; }
    
    virtual void readInt( int& i )
    { *_in >> i; }
    
    virtual void readUInt( unsigned int& i )
    { *_in >> i; }
    
    virtual void readLong( long& l )
    { *_in >> l; }
    
    virtual void readULong( unsigned long& l )
    { *_in >> l; }
    
    virtual void readFloat( float& f )
    { *_in >> f; }
    
    virtual void readDouble( double& d )
    { *_in >> d; }
    
    virtual void readString( std::string& s )
    { *_in >> s; }
    
    virtual void readStream( std::istream& (*fn)(std::istream&) )
    { *_in >> fn; }
    
    virtual void readBase( std::ios_base& (*fn)(std::ios_base&) )
    { *_in >> fn; }
    
    virtual void readGLenum( osgDB::ObjectGLenum& value )
    {
        GLenum e = 0;
        std::string enumString;
        *_in >> enumString;
        e = 
osgDB::Registry::instance()->getObjectWrapperManager()->getValue("GL", 
enumString);
        value.set( e );
    }
    
    virtual void readProperty( osgDB::ObjectProperty& prop )
    {
        int value = 0;
        std::string enumString;
        *_in >> enumString;
        if ( prop._mapProperty )
        {
            value = 
osgDB::Registry::instance()->getObjectWrapperManager()->getValue(prop._name, 
enumString);
        }
        else
        {
            if ( prop._name!=enumString )
            {
                OSG_NOTIFY(osg::WARN) << "AsciiInputIterator::readProperty(): 
Unmatched property "
                                       << enumString << ", expecting " << 
prop._name << std::endl;
            }
            prop._name = enumString;
        }
        prop.set( value );
    }
    
    virtual void readMark( osgDB::ObjectMark& mark )
    {
        std::string markString;
        *_in >> markString;
    }
    
    virtual void readCharArray( char* s, unsigned int size ) {}
    
    virtual void readWrappedString( std::string& str )
    {
        readString( str );
        if ( str[0]=='\"' )
        {
            if ( str.size()==1 || (*str.rbegin())!='\"' )
            {
                char ch;
                do
                {
                    _in->get( ch ); checkStream();
                    if ( ch=='\\' )
                    {
                        _in->get( ch ); checkStream();
                        if ( ch=='\"' )
                        {
                            str += ch; ch = 0;
                        }
                        else if ( ch=='\\' )
                        {
                            str += ch;
                        }
                        else
                        {
                            str += '\\'; str += ch;
                        }
                    }
                    else
                        str += ch;
                } while ( ch!='\"' );
            }
            str = str.substr(1, str.size()-2);
        }
    }
    
    virtual bool matchString( const std::string& str )
    {
        std::string s; readString(s);
        if ( s==str ) return true;
        else _in->seekg( -(int)(s.length()), std::ios::cur );
        return false;
    }
    
    virtual void advanceToCurrentEndBracket()
    {
        std::string passString;
        unsigned int blocks = 0;
        while ( !_in->eof() )
        {
            passString.clear();
            readString( passString );
            
            if ( passString=="}" )
            {
                if ( blocks<=0 ) return;
                else blocks--;
            }
            else if ( passString=="{" )
                blocks++;
        }
    }
};

#endif
#include "osg/Shader"
#include "osg/Notify"

#include <iostream>
#include <sstream>

#include "osgDB/Registry"
#include "osgDB/Input"
#include "osgDB/Output"
#include "osgDB/FileUtils"
#include "osgDB/WriteFile"

using namespace osg;
using namespace osgDB;
using namespace std;

// forward declare functions to use later.
bool Shader_readLocalData(Object& obj, Input& fr);
bool Shader_writeLocalData(const Object& obj, Output& fw);

// register the read and write functions with the osgDB::Registry.
REGISTER_DOTOSGWRAPPER(Shader)
(
    new osg::Shader,
    "Shader",
    "Object Shader",
    &Shader_readLocalData,
    &Shader_writeLocalData
);


bool Shader_readLocalData(Object& obj, Input& fr)
{
    bool iteratorAdvanced = false;

    Shader& shader = static_cast<Shader&>(obj);

    if (fr.matchSequence("type %w"))
    {
        shader.setType( Shader::getTypeId(fr[1].getStr()) );
        fr+=2;
        iteratorAdvanced = true;
    }
    
    if (fr.matchSequence("file %w") || fr.matchSequence("file %s") )
    {
        std::string fileName = osgDB::findDataFile(fr[1].getStr());
        if (!fileName.empty())
        {
            shader.loadShaderSourceFromFile( fileName.c_str() );
        }
        else
        {
            osg::notify(osg::NOTICE)<<"Warning: could not find shader file 
\""<<fr[1].getStr()<<"\""<<std::endl;
        }
        
        fr += 2;
        iteratorAdvanced = true;
    }

    if (fr.matchSequence("code {"))
    {
        std::string code;
        fr += 2;
        iteratorAdvanced = true;
        int entry = fr[0].getNoNestedBrackets();
        while (!fr.eof() && fr[0].getNoNestedBrackets() >= entry)
        {
            if (fr[0].getStr()) code.append(std::string(fr[0].getStr()));
            code += '\n' ;
            ++fr;
        }
        shader.setShaderSource(code.c_str());
    }

    return iteratorAdvanced;
}


bool Shader_writeLocalData(const Object& obj,Output& fw)
{
    const Shader& shader = static_cast<const Shader&>(obj);

    fw.indent() << "type " << shader.getTypename() << std::endl;

    // 
osg::notify(osg::NOTICE)<<"fw.getOutputShaderFiles()="<<fw.getOutputShaderFiles()<<std::endl;

    // check whenever output to shader files is requested
    if (fw.getOutputShaderFiles())
    {
        std::string fileName = shader.getFileName();

        if (fileName.empty())
        {
            fileName = fw.getShaderFileNameForOutput();
        }
        
        osgDB::writeShaderFile(shader, fileName);

        if (!fileName.empty())
        {    
            fw.indent() << "file 
"<<fw.wrapString(fw.getFileNameForOutput(fileName))<< std::endl;
        }

    }
    else // no need to write shaders to external files, hence embed it 
    {
        
        // split source text into individual lines
        std::vector<std::string> lines;
        std::istringstream iss(shader.getShaderSource());
        std::string line;
        while (std::getline(iss, line)) {
            lines.push_back(line);
        }

        fw.indent() << "code {\n";
        fw.moveIn();
    
        std::vector<std::string>::const_iterator j;
        for (j=lines.begin(); j!=lines.end(); ++j) {
            fw.indent() << fw.wrapString(*j) << "\n";
        }
    
        fw.moveOut();
        fw.indent() << "}\n";
    }

    return true;
}
_______________________________________________
osg-users mailing list
osg-users@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to