[osg-users] OpenSceneGraph-3.6 branch made, please test in prep for stable 3.6.0 release

Paul-Tcl3D paul at tcl3d.org
Thu Mar 22 08:37:05 PDT 2018


Here are the results of my build tests of OSG 3.6.0.
Note: These are just build tests. Functional tests to follow.

Build system: Windows 8.1
Compilers   : Visual Studio Express
3rd parties : curl, ffmpeg, freetype, gdal, giflib, jpeg, png, tiff, zlib

         32-bit  64-bit
----------------------
VS2008  Error   N/A
VS2010  Error   N/A
VS2013  OK      OK
VS2015  OK      OK
VS2017  OK      OK

Changes to compile with VS2010:
===============================

osgViewer/GraphicsWindowWin32.cpp Line 87:
------------------------------------------
Change from:
#if(WINVER < 0x0602)
to:
#if(WINVER < 0x0602 || _MSC_VER <= 1600)

Changes to compile with VS2008:
===============================

Change as for VS2010 plus

osgViewer/GraphicsWindowWin32.cpp Line 35:
-----------------------------------------
Change from:
#if(WINVER < 0x0601)
to:
#if(WINVER < 0x0601 || _MSC_VER <= 1500)

osgPlugins/osgjs/WriteVisitor.cpp Line 257:
-------------------------------------------
Change from:
in.read(reinterpret_cast<char*>(rawData.data()),size);
to:
in.read(reinterpret_cast<char*>(&rawData[0]),size);

osgPlugins/gles/MostInfluencedGeometryByBone Line 144:
------------------------------------------------------
Change from:
for(BoneSet::iterator bone = bones.begin(); bone != bones.end(); ++bone) {
to:
for(BoneSet::const_iterator bone = bones.begin(); bone != bones.end(); 
++bone) {

osgPlugins/gles/MostInfluencedGeometryByBone Line 156:
------------------------------------------------------
Change from:
for(RigGeometrySet::iterator rigGeometry = rigGeometrySet.begin(); 
rigGeometry != rigGeometrySet.end(); ++rigGeometry, ++index) {
to:
for(RigGeometrySet::const_iterator rigGeometry = rigGeometrySet.begin(); 
rigGeometry != rigGeometrySet.end(); ++rigGeometry, ++index) {

Regards,
Paul

Am 20.03.2018 um 10:58 schrieb Robert Osfield:
> Hi All,
>
> I have create a OpenSceneGraph-3.6 branch from master, this will now
> be the base for an up coming series of release candidates in prep for
> 3.6.0 stable release.
>
> With the creation of the OpenSceneGraph-3.6 branch we are now in a
> feature freeze for the 3.6.0, so further changes will be focused on
> bug and build fixes.  To achieve the best quality of stable release
> we'll need to test out the 3.6 branch and/or the release candidates
> that I tag in the run up to 3.6.0 release.
>
> Before I tagged 3.6.0-rc1 I would appreciate build and runtime testing
> of the 3.6 branch across as many platforms that you have available.
>
> Thanks in advance for you help,
> Robert.
> _______________________________________________
> osg-users mailing list
> osg-users at lists.openscenegraph.org
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
>

-------------- next part --------------
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab
 *
 * This application is open source and may be redistributed and/or modified
 * freely and without restriction, both in commercial and non commercial
 * applications, as long as this copyright notice is maintained.
 *
 * This application 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.
 *
*/

#ifndef MOST_INFLUENCED_GEOMETRY_BY_BONE_H
#define MOST_INFLUENCED_GEOMETRY_BY_BONE_H

#include <algorithm>

#include <osg/NodeVisitor>
#include <osg/Geometry>
#include <osg/Array>

#include <osgAnimation/RigGeometry>
#include <osgAnimation/Bone>

#include "StatLogger"


class InfluenceAttribute;

//{
//    "Bone001": {
//        Geom1: {
//            numVertexInfluenced: (int),
//            gloabalWeight: (float)
//        },
//        Geom2: {
//            numVertexInfluenced: (int),
//            gloabalWeight: (float)
//        },
//        ...
//    },
//    "Bone002": {
//        Geom1: {
//            numVertexInfluenced: (int),
//            gloabalWeight: (float)
//        },
//        Geom4: {
//            numVertexInfluenced: (int),
//            gloabalWeight: (float)
//        },
//        ...
//    },
//    ...
//}
//
//Here we store influences by bone, we will sort it and take the biggest one
typedef std::map< osgAnimation::Bone*, std::map< osgAnimation::RigGeometry*, InfluenceAttribute > > RigGeometryInfluenceByBoneMap;

typedef std::map< osgAnimation::RigGeometry*, InfluenceAttribute > BoneInfluenceMap;
typedef std::pair< osgAnimation::RigGeometry*, InfluenceAttribute > BoneInfluence;
typedef std::vector< BoneInfluence > BoneInfluences;


typedef std::set< osgAnimation::RigGeometry* > RigGeometrySet;
typedef std::set< osgAnimation::Bone* > BoneSet;

//Here we simply collect all bones and all rigGeometries
class CollectBonesAndRigGeometriesVisitor: public osg::NodeVisitor {

public:
    CollectBonesAndRigGeometriesVisitor():
        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
    {}

    void apply(osg::Geometry &geometry) {
        osgAnimation::RigGeometry *rigGeometry = dynamic_cast<osgAnimation::RigGeometry*>(&geometry);
        if(rigGeometry) {
            _rigGeometrySet.insert(rigGeometry);
        }
        traverse(geometry);
    }

    void apply(osg::MatrixTransform &node) {
        osgAnimation::Bone *bone = dynamic_cast<osgAnimation::Bone*>(&node);
        if(bone) {
            _boneSet.insert(bone);
        }

        traverse(node);
    }

    RigGeometrySet& getRigGeometrySet() {
        return _rigGeometrySet;
    }

    BoneSet& getBoneSet() {
        return _boneSet;
    }

protected:
    RigGeometrySet _rigGeometrySet;
    BoneSet _boneSet;
};


//Store and compute influence attributes i.e number of influenced vertex and accumulate weight
class InfluenceAttribute {
public:
    InfluenceAttribute():
        _accumulatedWeight(0),
        _weightCount(0)
    {}

    void addWeight(float weight) {
        _accumulatedWeight += weight;
        _weightCount++;
    }

    unsigned int getNumInfluencedVertex() {
        return _weightCount;
    }

    unsigned int getNumInfluencedVertex() const {
        return _weightCount;
    }

    float getNormalizedWeight() const {
        if(_weightCount == 0) return 0;
        return _accumulatedWeight / _weightCount;
    }

protected:
    float _accumulatedWeight;
    unsigned int _weightCount;
};

typedef std::pair< std::string, osgAnimation::Bone* > StringBonePair;
typedef std::pair< osgAnimation::RigGeometry*, unsigned int > RigGeometryIntPair;

class BoneNameBoneMap : public std::map<std::string, osgAnimation::Bone*> {

public:
    BoneNameBoneMap(const BoneSet& bones) {
        for(BoneSet::const_iterator bone = bones.begin(); bone != bones.end(); ++bone) {
            insert(StringBonePair((*bone)->getName(), *bone));
        }
    }
};


class RigGeometryIndexMap : public std::map<osgAnimation::RigGeometry*, unsigned int> {

public:
    RigGeometryIndexMap(const RigGeometrySet& rigGeometrySet) {
        unsigned int index = 0;
        for(RigGeometrySet::const_iterator rigGeometry = rigGeometrySet.begin(); rigGeometry != rigGeometrySet.end(); ++rigGeometry, ++index) {
            insert(RigGeometryIntPair(*rigGeometry, index));
        }
    }
};


class ComputeMostInfluencedGeometryByBone {

public:
    ComputeMostInfluencedGeometryByBone(RigGeometrySet &rigGeometrySet, BoneSet &boneSet):
        _rigGeometrySet(rigGeometrySet),
        _boneSet(boneSet),
        _logger("ComputeMostInfluencedGeometryByBone::compute(...)")
    {}

    void compute() {
        RigGeometryIndexMap rigGeometryIndexMap(_rigGeometrySet);

        RigGeometryInfluenceByBoneMap ribbm;
        computeInfluences(_boneSet, _rigGeometrySet, ribbm);
        for(RigGeometryInfluenceByBoneMap::iterator boneInfluencePair = ribbm.begin(); boneInfluencePair != ribbm.end(); ++boneInfluencePair) {
            osg::ref_ptr<osgAnimation::Bone> bone = boneInfluencePair->first;
            BoneInfluenceMap boneInfluenceMap = boneInfluencePair->second;
            BoneInfluences influences(boneInfluenceMap.begin(), boneInfluenceMap.end());

            std::sort(influences.begin(), influences.end(), sort_influences());
            bone->setUserValue("rigIndex", rigGeometryIndexMap [ influences.front().first ]);
        }

        RigGeometrySet &rigGeometrySet(_rigGeometrySet);
        for(RigGeometrySet::iterator rigGeometry = rigGeometrySet.begin(); rigGeometry != rigGeometrySet.end(); ++rigGeometry) {
            (*rigGeometry)->setUserValue("rigIndex", rigGeometryIndexMap[ *rigGeometry ]);
        }
    }

protected:
    void computeInfluences(const BoneSet& bones, const RigGeometrySet& rigGeometries, RigGeometryInfluenceByBoneMap& rigGeometryInfluenceByBoneMap) {
        BoneNameBoneMap boneMap(bones);

        for(RigGeometrySet::const_iterator rigGeometry = rigGeometries.begin(); rigGeometry != rigGeometries.end(); ++rigGeometry) {
            osg::ref_ptr<osgAnimation::VertexInfluenceMap> vertexInfluenceMap = (*rigGeometry)->getInfluenceMap();

            for(osgAnimation::VertexInfluenceMap::iterator vertexInfluencePair = vertexInfluenceMap->begin(); vertexInfluencePair != vertexInfluenceMap->end(); ++vertexInfluencePair) {
                BoneNameBoneMap::iterator bone_it = boneMap.find(vertexInfluencePair->first);
                if(bone_it == boneMap.end()) continue;
                osg::ref_ptr<osgAnimation::Bone> bone = bone_it->second;
                const osgAnimation::VertexInfluence& vertexInfluence = (*vertexInfluencePair).second;

                for(osgAnimation::VertexInfluence::const_iterator vertexIndexWeight = vertexInfluence.begin(); vertexIndexWeight != vertexInfluence.end(); ++vertexIndexWeight) {
                    rigGeometryInfluenceByBoneMap[bone.get()][*rigGeometry].addWeight((*vertexIndexWeight).second);
                }
            }
        }
    }

    struct sort_influences {
        //We sort influences by number of influenced vertex first and then by normalized weight (number_of_vertex_influence / accumulated_weight)
        //i.e we choose to keep geometries with many vertex insted of geometries with high normalized weight, it makes more sense for geometry
        //selection via bone influence box @see AABBonBoneVisitor class
        bool operator()(const BoneInfluence &a, const BoneInfluence &b) {
            return (a.second.getNumInfluencedVertex() > b.second.getNumInfluencedVertex()) ||
                   (a.second.getNumInfluencedVertex() == b.second.getNumInfluencedVertex() && \
                        a.second.getNormalizedWeight() > b.second.getNormalizedWeight());
        }
    };

    RigGeometrySet &_rigGeometrySet;
    BoneSet &_boneSet;
    StatLogger _logger;
};


#endif // MOST_INFLUENCED_GEOMETRY_BY_BONE_H
-------------- next part --------------
#include "WriteVisitor"
#include <osgDB/WriteFile>
#include <osgDB/FileUtils>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>
#include <osg/UserDataContainer>
#include <osg/TextureRectangle>
#include <osg/Texture2D>
#include <osg/Texture1D>
#include <osg/Types>
#include <osg/Material>
#include <osg/BlendFunc>

#include <osgText/Text>

#include <osgAnimation/MorphGeometry>

#include "Base64"


osg::Array* getTangentSpaceArray(osg::Geometry& geometry) {
    for(unsigned int i = 0 ; i < geometry.getNumVertexAttribArrays() ; ++ i) {
        osg::Array* attribute = geometry.getVertexAttribArray(i);
        bool isTangentArray = false;
        if(attribute && attribute->getUserValue("tangent", isTangentArray) && isTangentArray) {
            return attribute;
        }
    }
    return 0;
}


osg::Array* getAnimationBonesArray(osgAnimation::RigGeometry& rigGeometry) {
    for(unsigned int i = 0 ; i < rigGeometry.getNumVertexAttribArrays() ; ++ i) {
        osg::Array* attribute = rigGeometry.getVertexAttribArray(i);
        bool isBones = false;
        if(attribute && attribute->getUserValue("bones", isBones) && isBones) {
            return attribute;
        }
    }
    return 0;
}


osg::Array* getAnimationWeightsArray(osgAnimation::RigGeometry& rigGeometry) {
    for(unsigned int i = 0 ; i < rigGeometry.getNumVertexAttribArrays() ; ++ i) {
        osg::Array* attribute = rigGeometry.getVertexAttribArray(i);
        bool isWeights = false;
        if(attribute && attribute->getUserValue("weights", isWeights) && isWeights) {
            return attribute;
        }
    }
    return 0;
}


osg::ref_ptr<JSONObject> buildRigBoneMap(osgAnimation::RigGeometry& rigGeometry) {
    osg::Array* bones = getAnimationBonesArray(rigGeometry);
    osg::ref_ptr<JSONObject> boneMap = new JSONObject;

    unsigned int paletteIndex = 0;
    while(true) {
        std::ostringstream oss;
        oss << "animationBone_" << paletteIndex;
        std::string boneName, palette = oss.str();
        if(!bones->getUserValue(palette, boneName)) {
            break;
        }
        boneMap->getMaps()[boneName] = new JSONValue<int>(paletteIndex);
        ++ paletteIndex;
    }

    return boneMap;
}


void getStringifiedUserValue(osg::Object* o, std::string& name, std::string& value) {
    if(getStringifiedUserValue<std::string>(o, name, value)) return;
    if(getStringifiedUserValue<char>(o, name, value)) return;
    if(getStringifiedUserValue<bool>(o, name, value)) return;
    if(getStringifiedUserValue<short>(o, name, value)) return;
    if(getStringifiedUserValue<unsigned short>(o, name, value)) return;
    if(getStringifiedUserValue<int>(o, name, value)) return;
    if(getStringifiedUserValue<unsigned int>(o, name, value)) return;
    if(getStringifiedUserValue<float>(o, name, value)) return;
    if(getStringifiedUserValue<double>(o, name, value)) return;
}


template<typename T>
bool getStringifiedUserValue(osg::Object* o, std::string& name, std::string& value) {
    osg::TemplateValueObject<T>* vo = dynamic_cast< osg::TemplateValueObject<T>* >(o);
    if (vo) {
        std::ostringstream oss;
        oss << vo->getValue();
        name = vo->getName();
        value = oss.str();
        return true;
    }
    return false;
}


static JSONValue<std::string>* getBlendFuncMode(GLenum mode) {
    switch (mode) {
    case osg::BlendFunc::DST_ALPHA: return new JSONValue<std::string>("DST_ALPHA");
    case osg::BlendFunc::DST_COLOR: return new JSONValue<std::string>("DST_COLOR");
    case osg::BlendFunc::ONE: return new JSONValue<std::string>("ONE");
    case osg::BlendFunc::ONE_MINUS_DST_ALPHA: return new JSONValue<std::string>("ONE_MINUS_DST_ALPHA");
    case osg::BlendFunc::ONE_MINUS_DST_COLOR: return new JSONValue<std::string>("ONE_MINUS_DST_COLOR");
    case osg::BlendFunc::ONE_MINUS_SRC_ALPHA: return new JSONValue<std::string>("ONE_MINUS_SRC_ALPHA");
    case osg::BlendFunc::ONE_MINUS_SRC_COLOR: return new JSONValue<std::string>("ONE_MINUS_SRC_COLOR");
    case osg::BlendFunc::SRC_ALPHA: return new JSONValue<std::string>("SRC_ALPHA");
    case osg::BlendFunc::SRC_ALPHA_SATURATE: return new JSONValue<std::string>("SRC_ALPHA_SATURATE");
    case osg::BlendFunc::SRC_COLOR: return new JSONValue<std::string>("SRC_COLOR");
    case osg::BlendFunc::CONSTANT_COLOR: return new JSONValue<std::string>("CONSTANT_COLOR");
    case osg::BlendFunc::ONE_MINUS_CONSTANT_COLOR: return new JSONValue<std::string>("ONE_MINUS_CONSTANT_COLOR");
    case osg::BlendFunc::CONSTANT_ALPHA: return new JSONValue<std::string>("CONSTANT_ALPHA");
    case osg::BlendFunc::ONE_MINUS_CONSTANT_ALPHA: return new JSONValue<std::string>("ONE_MINUS_CONSTANT_ALPHA");
    case osg::BlendFunc::ZERO: return new JSONValue<std::string>("ZERO");
    default:
        return new JSONValue<std::string>("ONE");
    }
}

static JSONValue<std::string>* getJSONFilterMode(osg::Texture::FilterMode mode)
{
    switch(mode) {
    case GL_LINEAR:
        return new JSONValue<std::string>("LINEAR");
    case GL_LINEAR_MIPMAP_LINEAR:
        return new JSONValue<std::string>("LINEAR_MIPMAP_LINEAR");
    case GL_LINEAR_MIPMAP_NEAREST:
        return new JSONValue<std::string>("LINEAR_MIPMAP_NEAREST");
    case GL_NEAREST:
        return new JSONValue<std::string>("NEAREST");
    case GL_NEAREST_MIPMAP_LINEAR:
        return new JSONValue<std::string>("NEAREST_MIPMAP_LINEAR");
    case GL_NEAREST_MIPMAP_NEAREST:
        return new JSONValue<std::string>("NEAREST_MIPMAP_NEAREST");
    default:
        return 0;
    }
    return 0;
}

static JSONValue<std::string>* getJSONWrapMode(osg::Texture::WrapMode mode)
{
    switch(mode) {
    case GL_CLAMP:
        // clamp does not exist in opengles 2.0
        //return new JSONValue<std::string>("CLAMP");
        return new JSONValue<std::string>("CLAMP_TO_EDGE");
    case GL_CLAMP_TO_EDGE:
        return new JSONValue<std::string>("CLAMP_TO_EDGE");
    case GL_CLAMP_TO_BORDER_ARB:
        return new JSONValue<std::string>("CLAMP_TO_BORDER");
    case GL_REPEAT:
        return new JSONValue<std::string>("REPEAT");
    case GL_MIRRORED_REPEAT_IBM:
        return new JSONValue<std::string>("MIRROR");
    default:
        return 0;
    }
    return 0;
}

static JSONValue<std::string>* getJSONAlignmentType(osgText::Text::AlignmentType type)
{
    switch(type) {
        case osgText::Text::LEFT_TOP:
            return new JSONValue<std::string>("LEFT_TOP");
        case osgText::Text::LEFT_CENTER:
            return new JSONValue<std::string>("LEFT_CENTER");
        case osgText::Text::LEFT_BOTTOM:
            return new JSONValue<std::string>("LEFT_BOTTOM");
        case osgText::Text::CENTER_TOP:
            return new JSONValue<std::string>("CENTER_TOP");
        case osgText::Text::CENTER_CENTER:
            return new JSONValue<std::string>("CENTER_CENTER");
        case osgText::Text::CENTER_BOTTOM:
            return new JSONValue<std::string>("CENTER_BOTTOM");
        case osgText::Text::RIGHT_TOP:
            return new JSONValue<std::string>("RIGHT_TOP");
        case osgText::Text::RIGHT_CENTER:
            return new JSONValue<std::string>("RIGHT_CENTER");
        case osgText::Text::RIGHT_BOTTOM:
            return new JSONValue<std::string>("RIGHT_BOTTOM");
        case osgText::Text::LEFT_BASE_LINE:
            return new JSONValue<std::string>("LEFT_BASE_LINE");
        case osgText::Text::CENTER_BASE_LINE:
            return new JSONValue<std::string>("CENTER_BASE_LINE");
        case osgText::Text::RIGHT_BASE_LINE:
            return new JSONValue<std::string>("RIGHT_BASE_LINE");
        case osgText::Text::LEFT_BOTTOM_BASE_LINE:
            return new JSONValue<std::string>("LEFT_BOTTOM_BASE_LINE");
        case osgText::Text::CENTER_BOTTOM_BASE_LINE:
            return new JSONValue<std::string>("CENTER_BOTTOM_BASE_LINE");
        case osgText::Text::RIGHT_BOTTOM_BASE_LINE:
            return new JSONValue<std::string>("RIGHT_BOTTOM_BASE_LINE");
        default:
            return 0;
    }
    return 0;
}

JSONObject* createImage(osg::Image* image, bool inlineImages, int maxTextureDimension, const std::string &baseName)
{
    if (!image) {
        osg::notify(osg::WARN) << "unknown image from texture2d " << std::endl;
        return new JSONValue<std::string>("/unknown.png");
    } else {
        std::string modelDir = osgDB::getFilePath(baseName);
        if (!image->getFileName().empty() && image->getWriteHint() != osg::Image::STORE_INLINE) {
            if(maxTextureDimension) {
                int new_s = osg::Image::computeNearestPowerOfTwo(image->s());
                int new_t = osg::Image::computeNearestPowerOfTwo(image->t());

                bool notValidPowerOf2 = false;
                if (new_s != image->s() || image->s() > maxTextureDimension) notValidPowerOf2 = true;
                if (new_t != image->t() || image->t() > maxTextureDimension) notValidPowerOf2 = true;

                if (notValidPowerOf2) {
                    image->ensureValidSizeForTexturing(maxTextureDimension);
                    if(osgDB::isAbsolutePath(image->getFileName()))
                        osgDB::writeImageFile(*image, image->getFileName());
                    else
                        osgDB::writeImageFile(*image,
                                              osgDB::concatPaths(modelDir,
                                                                 image->getFileName()));
                }
            }
        } else {
            // no image file so use this inline name image and create a file
            std::stringstream ss;
            if ( !osgDB::getFilePath(baseName).empty())
                ss << osgDB::getFilePath(baseName) << osgDB::getNativePathSeparator();
            ss << (int64_t)image << ".inline_conv_generated.png"; // write the pointer location
            std::string filename = ss.str();
            if (osgDB::writeImageFile(*image, filename)) {
                image->setFileName(filename);
            }
        }

        if (!image->getFileName().empty()) { // means that everything went ok
            if (inlineImages) {

                std::ifstream in(osgDB::findDataFile(image->getFileName()).c_str(), std::ifstream::in | std::ifstream::binary);
                if (in.is_open() && in.good())
                {
                    // read file first to iterate
                    in.seekg(0, std::ifstream::end);
                    const std::ifstream::pos_type size = in.tellg();
                    in.seekg(0, std::ifstream::beg);
                    std::vector<unsigned char> rawData;
                    rawData.resize(size);
                    in.read(reinterpret_cast<char*>(&rawData[0]),size);
                    in.seekg(std::ios_base::beg);

                    std::stringstream out;
                    out << "data:image/" << osgDB::getLowerCaseFileExtension(image->getFileName()) << ";base64,";
                    base64::encode(std::istreambuf_iterator<char>(in),
                                   std::istreambuf_iterator<char>(),
                                   std::ostreambuf_iterator<char>(out), false);

                    return new JSONValue<std::string>(out.str());

                }
            }
            return new JSONValue<std::string>(image->getFileName());
        }
    }
    return 0;
}



JSONObject* WriteVisitor::createJSONOsgSimUserData(osgSim::ShapeAttributeList* osgSimData) {
    JSONObject* jsonUDC = new JSONObject();
    jsonUDC->addUniqueID();

    JSONArray* jsonUDCArray = new JSONArray();
    jsonUDC->getMaps()["Values"] = jsonUDCArray;
    for (unsigned int i = 0; i < osgSimData->size(); i++) {
        const osgSim::ShapeAttribute& attr = (*osgSimData)[i];
        JSONObject* jsonEntry = new JSONObject();
        jsonEntry->getMaps()["Name"] = new JSONValue<std::string>(attr.getName());
        osg::ref_ptr<JSONValue<std::string> > value;
        switch(attr.getType()) {
        case osgSim::ShapeAttribute::INTEGER:
        {
            std::stringstream ss;
            ss << attr.getInt();
            value = new JSONValue<std::string>(ss.str());
        }
        break;
        case osgSim::ShapeAttribute::DOUBLE:
        {
            std::stringstream ss;
            ss << attr.getDouble();
            value = new JSONValue<std::string>(ss.str());
        }
        break;
        case osgSim::ShapeAttribute::STRING:
        {
            std::stringstream ss;
            ss << attr.getString();
            value = new JSONValue<std::string>(ss.str());
        }
        break;
        case osgSim::ShapeAttribute::UNKNOWN:
        default:
            break;
        }
        jsonEntry->getMaps()["Value"] = value;
        jsonUDCArray->getArray().push_back(jsonEntry);
    }
    return jsonUDC;
}


JSONObject* WriteVisitor::createJSONUserDataContainer(osg::UserDataContainer* container) {
    JSONObject* jsonUDC = new JSONObject();
    jsonUDC->addUniqueID();

    if (!container->getName().empty()) {
        jsonUDC->getMaps()["Name"] = new JSONValue<std::string>(container->getName());
    }
    JSONArray* jsonUDCArray = new JSONArray();
    jsonUDC->getMaps()["Values"] = jsonUDCArray;
    for (unsigned int i = 0; i < container->getNumUserObjects(); i++) {
        osg::Object* o = container->getUserObject(i);
        std::string name, value;
        getStringifiedUserValue(o, name, value);
        if(!name.empty() && !value.empty())
        {
            JSONObject* jsonEntry = new JSONObject();
            jsonEntry->getMaps()["Name"] = new JSONValue<std::string>(name);
            jsonEntry->getMaps()["Value"] = new JSONValue<std::string>(value);
            jsonUDCArray->getArray().push_back(jsonEntry);
        }
    }
    return jsonUDC;
}


void WriteVisitor::translateObject(JSONObject* json, osg::Object* osg)
{
    if (!osg->getName().empty()) {
        json->getMaps()["Name"] = new JSONValue<std::string>(osg->getName());
    }

    JSONObject* jsonUDC = 0;

    osgSim::ShapeAttributeList* osgSimData = dynamic_cast<osgSim::ShapeAttributeList* >(osg->getUserData());
    if (osgSimData) {
        jsonUDC = this->getJSON(osgSimData);
        if(!jsonUDC) {
            jsonUDC = createJSONOsgSimUserData(osgSimData);
            this->setJSON(osgSimData, jsonUDC);
        }
    }
    else if (osg::UserDataContainer* container = osg->getUserDataContainer()) {
        jsonUDC = this->getJSON(container);
        if(!jsonUDC) {
            jsonUDC = createJSONUserDataContainer(container);
            this->setJSON(container, jsonUDC);
        }
    }

    if(jsonUDC) {
        json->getMaps()["UserDataContainer"] = jsonUDC;
    }
}




JSONObject* WriteVisitor::createJSONBufferArray(osg::Array* array, osg::Object* parent)
{
    if (_maps.find(array) != _maps.end())
        return _maps[array]->getShadowObject();

    osg::ref_ptr<JSONBufferArray> json = new JSONBufferArray(array);
    _maps[array] = json;
    if(_mergeAllBinaryFiles) {
        setBufferName(json.get(), parent, array);
    }
    return json.get();
}

JSONObject* WriteVisitor::createJSONDrawElementsUInt(osg::DrawElementsUInt* de, osg::Object* parent)
{
    if (_maps.find(de) != _maps.end())
        return _maps[de]->getShadowObject();

    JSONDrawElements<osg::DrawElementsUInt>* json = new JSONDrawElements<osg::DrawElementsUInt>(*de);
    _maps[de] = json;
    if(_mergeAllBinaryFiles) {
        setBufferName(json, parent, de);
    }
    return json;
}

JSONObject* WriteVisitor::createJSONDrawElementsUShort(osg::DrawElementsUShort* de, osg::Object* parent)
{
    if (_maps.find(de) != _maps.end())
        return _maps[de]->getShadowObject();

    JSONDrawElements<osg::DrawElementsUShort>* json = new JSONDrawElements<osg::DrawElementsUShort>(*de);
    _maps[de] = json;
    if(_mergeAllBinaryFiles) {
        setBufferName(json, parent, de);
    }
    return json;
}

JSONObject* WriteVisitor::createJSONDrawElementsUByte(osg::DrawElementsUByte* de, osg::Object* parent)
{
    if (_maps.find(de) != _maps.end())
        return _maps[de]->getShadowObject();

    JSONDrawElements<osg::DrawElementsUByte>* json = new JSONDrawElements<osg::DrawElementsUByte>(*de);
    _maps[de] = json;
    if(_mergeAllBinaryFiles) {
        setBufferName(json, parent, de);
    }
    return json;
}

// use to convert draw array quads to draw elements triangles
JSONObject* WriteVisitor::createJSONDrawElements(osg::DrawArrays* drawArray, osg::Object* parent)
{
    if (_maps.find(drawArray) != _maps.end())
        return _maps[drawArray]->getShadowObject();

    if (drawArray->getMode() != GL_QUADS) {
        osg::notify(osg::WARN) << "" << std::endl;
        return 0;
    }

    osg::ref_ptr<osg::DrawElementsUShort> de = new osg::DrawElementsUShort(GL_TRIANGLES);

    for (int i = 0; i < drawArray->getCount()/4; ++i) {
        int base = drawArray->getFirst() + i*4;
        de->push_back(base + 0);
        de->push_back(base + 1);
        de->push_back(base + 3);

        de->push_back(base + 1);
        de->push_back(base + 2);
        de->push_back(base + 3);
    }
    JSONDrawElements<osg::DrawElementsUShort>* json = new JSONDrawElements<osg::DrawElementsUShort>(*de);
    _maps[drawArray] = json;
    if(_mergeAllBinaryFiles) {
        setBufferName(json, parent, drawArray);
    }
    return json;
}

JSONObject* WriteVisitor::createJSONDrawArray(osg::DrawArrays* da, osg::Object* parent)
{
    if (_maps.find(da) != _maps.end())
        return _maps[da]->getShadowObject();

    osg::ref_ptr<JSONDrawArray> json = new JSONDrawArray(*da);
    _maps[da] = json;
    if(_mergeAllBinaryFiles) {
        setBufferName(json.get(), parent, da);
    }
    return json.get();
}

JSONObject* WriteVisitor::createJSONDrawArrayLengths(osg::DrawArrayLengths* da, osg::Object* parent)
{
    if (_maps.find(da) != _maps.end())
        return _maps[da]->getShadowObject();

    osg::ref_ptr<JSONDrawArrayLengths> json = new JSONDrawArrayLengths(*da);
    _maps[da] = json;
    if(_mergeAllBinaryFiles) {
        setBufferName(json.get(), parent, da);
    }
    return json.get();
}


JSONObject* WriteVisitor::createJSONGeometry(osg::Geometry* geometry, osg::Object* parent)
{
    if(!parent) {
        parent = geometry;
    }

    if (_maps.find(geometry) != _maps.end())
        return _maps[geometry]->getShadowObject();

    osg::ref_ptr<JSONObject> json = new JSONObject;
    json->addUniqueID();
    _maps[geometry] = json;

    if (geometry->getStateSet())
        createJSONStateSet(json.get(), geometry->getStateSet());

    translateObject(json.get(), geometry);

    osg::ref_ptr<JSONObject> attributes = new JSONObject;

    int nbVertexes = 0;

    if (geometry->getVertexArray()) {
        nbVertexes = geometry->getVertexArray()->getNumElements();
        attributes->getMaps()["Vertex"] = createJSONBufferArray(geometry->getVertexArray(), parent);
    }
    if (geometry->getNormalArray()) {
        attributes->getMaps()["Normal"] = createJSONBufferArray(geometry->getNormalArray(), parent);
        int nb = geometry->getNormalArray()->getNumElements();
        if (nbVertexes != nb) {
            osg::notify(osg::FATAL) << "Fatal nb normals " << nb << " != " << nbVertexes << std::endl;
            error();
        }
    }
    if (geometry->getColorArray()) {
        attributes->getMaps()["Color"] = createJSONBufferArray(geometry->getColorArray(), parent);
        int nb = geometry->getColorArray()->getNumElements();
        if (nbVertexes != nb) {
            osg::notify(osg::FATAL) << "Fatal nb colors " << nb << " != " << nbVertexes << std::endl;
            error();
        }
    }

    std::stringstream ss;
    for ( int i = 0; i < 32; i++) {
        ss.str("");
        ss << "TexCoord" << i;
        //osg::notify(osg::NOTICE) << ss.str() << std::endl;
        if (geometry->getTexCoordArray(i)) {
            attributes->getMaps()[ss.str()] = createJSONBufferArray(geometry->getTexCoordArray(i), parent);
            int nb = geometry->getTexCoordArray(i)->getNumElements();
            if (nbVertexes != nb) {
                osg::notify(osg::FATAL) << "Fatal nb tex coord " << i << " " << nb << " != " << nbVertexes << std::endl;
                error();
            }
        }
    }

    osg::Array* tangents = getTangentSpaceArray(*geometry);
    if (tangents) {
        attributes->getMaps()["Tangent"] = createJSONBufferArray(tangents, parent);
        int nb = tangents->getNumElements();
        if (nbVertexes != nb) {
            osg::notify(osg::FATAL) << "Fatal nb tangent " << nb << " != " << nbVertexes << std::endl;
            error();
        }
    }

    json->getMaps()["VertexAttributeList"] = attributes;

    if (!geometry->getPrimitiveSetList().empty()) {
        osg::ref_ptr<JSONArray> primitives = new JSONArray();
        for (unsigned int i = 0; i < geometry->getNumPrimitiveSets(); ++i) {
            osg::ref_ptr<JSONObject> obj = new JSONObject;
            osg::PrimitiveSet* primitive = geometry->getPrimitiveSet(i);
            if(!primitive) continue;

            if (primitive->getType() == osg::PrimitiveSet::DrawArraysPrimitiveType) {
                osg::DrawArrays* da = dynamic_cast<osg::DrawArrays*>((primitive));
                if (da)
                {
                    primitives->getArray().push_back(obj);
                    if (da->getMode() == GL_QUADS) {
                        obj->getMaps()["DrawElementsUShort"] = createJSONDrawElements(da, parent);
                    } else {
                        obj->getMaps()["DrawArrays"] = createJSONDrawArray(da, parent);
                    }
                }
            } else if (primitive->getType() == osg::PrimitiveSet::DrawElementsUIntPrimitiveType) {
                osg::DrawElementsUInt* da = dynamic_cast<osg::DrawElementsUInt*>((primitive));
                if (da)
                {
                    primitives->getArray().push_back(obj);
                    obj->getMaps()["DrawElementsUInt"] = createJSONDrawElementsUInt(da, parent);
                }
            }  else if (primitive->getType() == osg::PrimitiveSet::DrawElementsUShortPrimitiveType) {
                osg::DrawElementsUShort* da = dynamic_cast<osg::DrawElementsUShort*>((primitive));
                if (da)
                {
                    primitives->getArray().push_back(obj);
                    obj->getMaps()["DrawElementsUShort"] = createJSONDrawElementsUShort(da, parent);
                }
            }  else if (primitive->getType() == osg::PrimitiveSet::DrawElementsUBytePrimitiveType) {
                osg::DrawElementsUByte* da = dynamic_cast<osg::DrawElementsUByte*>((primitive));
                if (da)
                {
                    primitives->getArray().push_back(obj);
                    obj->getMaps()["DrawElementsUByte"] = createJSONDrawElementsUByte(da, parent);
                }
            }  else if (primitive->getType() == osg::PrimitiveSet::DrawArrayLengthsPrimitiveType) {
                osg::DrawArrayLengths* dal = dynamic_cast<osg::DrawArrayLengths*>((primitive));
                if (dal)
                {
                    primitives->getArray().push_back(obj);
                    obj->getMaps()["DrawArrayLengths"] = createJSONDrawArrayLengths(dal, parent);
                }
            } else {
                osg::notify(osg::WARN) << "Primitive Type " << geometry->getPrimitiveSetList()[i]->getType() << " not supported, skipping" << std::endl;
            }
        }
        json->getMaps()["PrimitiveSetList"] = primitives;
    }
    if (geometry->getComputeBoundingBoxCallback()) {
           osg::ref_ptr<JSONObject> jsonObj = new JSONObject;
           jsonObj->addUniqueID();
           json->getMaps()["osg.ComputeBoundingBoxCallback"] = jsonObj;
    }
    return json.get();
}

JSONObject* WriteVisitor::createJSONRigGeometry(osgAnimation::RigGeometry* rigGeometry)
{
    //TODO : Convert data to JSONVertexArray "Float32Array"
    osg::ref_ptr<JSONObject> json = new JSONObject;
    json->addUniqueID();
    osg::ref_ptr<JSONObject> sourceGeometry = new JSONObject;

    if(osgAnimation::MorphGeometry *morphGeometry = dynamic_cast<osgAnimation::MorphGeometry*>(rigGeometry->getSourceGeometry())) {
        sourceGeometry->getMaps()["osgAnimation.MorphGeometry"] = createJSONMorphGeometry(morphGeometry, rigGeometry);
    }
    else {
        osg::Geometry *geometry  = dynamic_cast<osg::Geometry*>(rigGeometry->getSourceGeometry());
        if(geometry) {
            sourceGeometry->getMaps()["osg.Geometry"] = createJSONGeometry(geometry, rigGeometry);
        }
    }

    json->getMaps()["SourceGeometry"] = sourceGeometry.get();

    osg::Array* bones = getAnimationBonesArray(*rigGeometry);
    osg::Array* weights = getAnimationWeightsArray(*rigGeometry);
    if (bones && weights) {
        json->getMaps()["BoneMap"] = buildRigBoneMap(*rigGeometry);

        json->getMaps()["VertexAttributeList"] = new JSONObject;
        osg::ref_ptr<JSONObject> attributes = json->getMaps()["VertexAttributeList"];
        int nbVertexes = rigGeometry->getSourceGeometry()->getVertexArray()->getNumElements();

        attributes->getMaps()["Bones"] = createJSONBufferArray(bones, rigGeometry);
        attributes->getMaps()["Weights"] = createJSONBufferArray(weights, rigGeometry);
        int nb = bones->getNumElements();
        if (nbVertexes != nb) {
            osg::notify(osg::FATAL) << "Fatal nb bones " << nb << " != " << nbVertexes << std::endl;
            error();
        }
        nb = weights->getNumElements();
        if (nbVertexes != nb) {
            osg::notify(osg::FATAL) << "Fatal nb weights " << nb << " != " << nbVertexes << std::endl;
            error();
        }
    }

    return json.release();
}

JSONObject* WriteVisitor::createJSONMorphGeometry(osgAnimation::MorphGeometry* morphGeometry, osg::Object* parent)
{
    if(!parent) {
        parent = morphGeometry;
    }

    JSONObject* jsonGeometry = createJSONGeometry(morphGeometry, parent);
    osg::ref_ptr<JSONArray> targetList = new JSONArray;

    osgAnimation::MorphGeometry::MorphTargetList mTargetList = morphGeometry->getMorphTargetList();
    typedef osgAnimation::MorphGeometry::MorphTargetList::iterator TargetIterator;

    for(TargetIterator ti = mTargetList.begin(); ti != mTargetList.end(); ti++) {
        osgAnimation::MorphGeometry::MorphTarget *morphTarget = &(*ti);
        if(osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(morphTarget->getGeometry())) {
            osg::ref_ptr<JSONObject> jsonGeometryObject = new JSONObject;
            geometry->setPrimitiveSetList(osg::Geometry::PrimitiveSetList()); //delete unused drawArray
            jsonGeometryObject->getMaps()["osg.Geometry"] = createJSONGeometry(geometry);
            targetList->asArray()->getArray().push_back(jsonGeometryObject);
        }
    }
    jsonGeometry->getMaps()["MorphTargets"] = targetList;

    return jsonGeometry;
}

JSONObject* WriteVisitor::createJSONBlendFunc(osg::BlendFunc* sa)
{
    if (_maps.find(sa) != _maps.end())
        return _maps[sa]->getShadowObject();

    osg::ref_ptr<JSONObject> json = new JSONObject;
    json->addUniqueID();
    _maps[sa] = json;

    translateObject(json.get(), sa);

    json->getMaps()["SourceRGB"] = getBlendFuncMode(sa->getSource());
    json->getMaps()["DestinationRGB"] = getBlendFuncMode(sa->getDestination());
    json->getMaps()["SourceAlpha"] = getBlendFuncMode(sa->getSourceAlpha());
    json->getMaps()["DestinationAlpha"] = getBlendFuncMode(sa->getDestinationAlpha());
    return json.release();
}

JSONObject* WriteVisitor::createJSONBlendColor(osg::BlendColor* sa)
{
    if (_maps.find(sa) != _maps.end())
        return _maps[sa]->getShadowObject();

    osg::ref_ptr<JSONObject> json = new JSONObject;
    json->addUniqueID();
    _maps[sa] = json;

    translateObject(json.get(), sa);

    json->getMaps()["ConstantColor"] = new JSONVec4Array(sa->getConstantColor());
    return json.release();
}

JSONObject* WriteVisitor::createJSONCullFace(osg::CullFace* sa)
{
    if (_maps.find(sa) != _maps.end())
        return _maps[sa]->getShadowObject();

    osg::ref_ptr<JSONObject> json = new JSONObject;
    json->addUniqueID();
    _maps[sa] = json;

    translateObject(json.get(), sa);

    osg::ref_ptr<JSONValue<std::string> > mode = new JSONValue<std::string>("BACK");
    if (sa->getMode() == osg::CullFace::FRONT) {
        mode = new JSONValue<std::string>("FRONT");
    }
    if (sa->getMode() == osg::CullFace::FRONT_AND_BACK) {
        mode = new JSONValue<std::string>("FRONT_AND_BACK");
    }
    json->getMaps()["Mode"] = mode;
    return json.release();
}



JSONObject* WriteVisitor::createJSONMaterial(osg::Material* material)
{
    if (_maps.find(material) != _maps.end())
        return _maps[material]->getShadowObject();

    osg::ref_ptr<JSONObject> jsonMaterial = new JSONMaterial;
    _maps[material] = jsonMaterial;

    translateObject(jsonMaterial.get(), material);

    jsonMaterial->getMaps()["Ambient"] = new JSONVec4Array(material->getAmbient(osg::Material::FRONT));
    jsonMaterial->getMaps()["Diffuse"] = new JSONVec4Array(material->getDiffuse(osg::Material::FRONT));
    jsonMaterial->getMaps()["Specular"] = new JSONVec4Array(material->getSpecular(osg::Material::FRONT));
    jsonMaterial->getMaps()["Emission"] = new JSONVec4Array(material->getEmission(osg::Material::FRONT));
    jsonMaterial->getMaps()["Shininess"] = new JSONValue<float>(material->getShininess(osg::Material::FRONT));

    return jsonMaterial.release();
}


JSONObject* WriteVisitor::createJSONLight(osg::Light* light)
{
    if (_maps.find(light) != _maps.end())
        return _maps[light]->getShadowObject();

    osg::ref_ptr<JSONObject> jsonLight = new JSONLight;
    _maps[light] = jsonLight;

    translateObject(jsonLight.get(), light);

    jsonLight->getMaps()["LightNum"] = new JSONValue<int>(light->getLightNum());
    jsonLight->getMaps()["Ambient"] = new JSONVec4Array(light->getAmbient());
    jsonLight->getMaps()["Diffuse"] = new JSONVec4Array(light->getDiffuse());
    jsonLight->getMaps()["Specular"] = new JSONVec4Array(light->getSpecular());
    jsonLight->getMaps()["Position"] = new JSONVec4Array(light->getPosition());
    jsonLight->getMaps()["Direction"] = new JSONVec3Array(light->getDirection());

    jsonLight->getMaps()["ConstantAttenuation"] = new JSONValue<float>(light->getConstantAttenuation());
    jsonLight->getMaps()["LinearAttenuation"] = new JSONValue<float>(light->getLinearAttenuation());
    jsonLight->getMaps()["QuadraticAttenuation"] = new JSONValue<float>(light->getQuadraticAttenuation());
    jsonLight->getMaps()["SpotExponent"] = new JSONValue<float>(light->getSpotExponent());
    jsonLight->getMaps()["SpotCutoff"] = new JSONValue<float>(light->getSpotCutoff());
    return jsonLight.release();
}

template <class T>
JSONObject* createImageFromTexture(osg::Texture* texture, JSONObject* jsonTexture, WriteVisitor* writer)
{
    bool inlineImages = writer->getInlineImages();
    int maxTextureDimension = writer->getMaxTextureDimension();
    const std::string baseName = writer->getBaseName();

    T* text = dynamic_cast<T*>( texture);
    if (text) {
        writer->translateObject(jsonTexture,text);
        JSONObject* image = createImage(text->getImage(), inlineImages, maxTextureDimension, baseName);
        if (image)
            jsonTexture->getMaps()["File"] = image;
        return jsonTexture;
    }
    return 0;
}

JSONObject* WriteVisitor::createJSONText(osgText::Text* text)
{
    if (_maps.find(text) != _maps.end())
        return _maps[text]->getShadowObject();

    osg::ref_ptr<JSONObject> jsonText = new JSONObject;
    jsonText->addUniqueID();
    _maps[text] = jsonText;
    jsonText->getMaps()["Text"] = new JSONValue<std::string>( text->getText().createUTF8EncodedString()  );
    jsonText->getMaps()["Position"] = new JSONVec3Array(text->getPosition());
    jsonText->getMaps()["Color"] = new JSONVec4Array(osg::Vec4(text->getColor().x(),text->getColor().y(),text->getColor().z(), text->getColor().w() ));
    jsonText->getMaps()["CharacterSize"] = new JSONValue<float>(text->getCharacterHeight() );
    jsonText->getMaps()["AutoRotateToScreen"] = new JSONValue<int>(text->getAutoRotateToScreen() );
    jsonText->getMaps()["Alignment"] = getJSONAlignmentType(text->getAlignment());

    osg::ref_ptr<JSONValue<std::string> > layout = new JSONValue<std::string>("LEFT_TO_RIGHT");
    if (text->getLayout() == osgText::Text::RIGHT_TO_LEFT) {
        layout = new JSONValue<std::string>("RIGHT_TO_LEFT");
    }
    if (text->getLayout() == osgText::Text::VERTICAL) {
        layout = new JSONValue<std::string>("VERTICAL");
    }
    jsonText->getMaps()["Layout"] = layout;
    return jsonText.release();
}


JSONObject* WriteVisitor::createJSONPagedLOD(osg::PagedLOD *plod)
{
    if (!plod) { return 0; }

    if (_maps.find(plod) != _maps.end()) {
         return _maps[plod]->getShadowObject();
    }

    osg::ref_ptr<JSONObject> jsonPlod = new JSONNode;
    _maps[plod] = jsonPlod;

    // Center Mode
    osg::ref_ptr<JSONValue<std::string> > centerMode = new JSONValue<std::string>("USE_BOUNDING_SPHERE_CENTER");
    if (plod->getCenterMode() == osg::LOD::USER_DEFINED_CENTER) {
        centerMode = new JSONValue<std::string>("USER_DEFINED_CENTER");
    } else if (plod->getCenterMode() == osg::LOD::UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED){
        centerMode = new JSONValue<std::string>("UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED");
    }
    jsonPlod->getMaps()["CenterMode"] = centerMode;
    // User defined center and radius
    jsonPlod->getMaps()["UserCenter"] = new JSONVec4Array(osg::Vec4(plod->getCenter().x(), plod->getCenter().y(),plod->getCenter().z(), plod->getRadius()));


    // Range Mode
    osg::ref_ptr<JSONValue<std::string> > rangeMode = new JSONValue<std::string>("DISTANCE_FROM_EYE_POINT");
    if (plod->getRangeMode() == osg::LOD::PIXEL_SIZE_ON_SCREEN) {
        rangeMode = new JSONValue<std::string>("PIXEL_SIZE_ON_SCREEN");
    }
    jsonPlod->getMaps()["RangeMode"] = rangeMode;
    // Range List
    osg::ref_ptr<JSONObject> rangeObject = new JSONObject;
    for (unsigned int i =0; i< plod->getRangeList().size(); i++)
    {
        std::stringstream ss;
        ss << "Range ";
        ss << i;
        std::string str = ss.str();

        osg::Vec2 range(plod->getRangeList()[i].first, plod->getRangeList()[i].second);

        // Since OSGJS uses pixel area, use square range
        if (plod->getRangeMode() == osg::LOD::PIXEL_SIZE_ON_SCREEN) {
          range.set(pow(range.x(), 2.0f), pow(range.y(), 2.0f));
        }

        rangeObject->getMaps()[str] = new JSONVec2Array(range);
    }
    jsonPlod->getMaps()["RangeList"] = rangeObject;
    // File List

    osg::ref_ptr<JSONObject> fileObject = new JSONObject;
    for (unsigned int i =0; i< plod->getNumFileNames(); i++)
    {
        std::stringstream ss;
        ss << "File ";
        ss << i;
        std::string str = ss.str();
        // We need to convert first from osg format to osgjs format.
        osg::ref_ptr<osg::Node> n = osgDB::readRefNodeFile(plod->getDatabasePath() + plod->getFileName(i)+".gles");
        if (n)
        {
            std::string filename(osgDB::getNameLessExtension(plod->getFileName(i))+".osgjs");

            std::string fullFilePath(osgDB::getFilePath(_baseName) + osgDB::getNativePathSeparator() + filename);
            fileObject->getMaps()[str] =  new JSONValue<std::string>(_baseLodURL + filename);
            osgDB::makeDirectoryForFile(fullFilePath);
            if (_baseLodURL.empty())
                _baseLodURL = osgDB::getFilePath(filename) + osgDB::getNativePathSeparator() ;
            osg::ref_ptr<osgDB::Options> options =  osgDB::Registry::instance()->getOptions()->cloneOptions();
            options->setPluginStringData(std::string("baseLodURL"), _baseLodURL);

            osgDB::writeNodeFile(*n, fullFilePath, options.get());

        }
        else
            fileObject->getMaps()[str] =  new JSONValue<std::string>("");
     }
    jsonPlod->getMaps()["RangeDataList"] = fileObject;

    return jsonPlod.release();
}

JSONObject* WriteVisitor::createJSONTexture(osg::Texture* texture)
{
    if (!texture) {
        return 0;
    }

    if (_maps.find(texture) != _maps.end()) {
        return _maps[texture]->getShadowObject();
    }

    osg::ref_ptr<JSONObject> jsonTexture = new JSONObject;
    jsonTexture->addUniqueID();
    _maps[texture] = jsonTexture;

    jsonTexture->getMaps()["MagFilter"] = getJSONFilterMode(texture->getFilter(osg::Texture::MAG_FILTER));
    jsonTexture->getMaps()["MinFilter"] = getJSONFilterMode(texture->getFilter(osg::Texture::MIN_FILTER));

    jsonTexture->getMaps()["WrapS"] = getJSONWrapMode(texture->getWrap(osg::Texture::WRAP_S));
    jsonTexture->getMaps()["WrapT"] = getJSONWrapMode(texture->getWrap(osg::Texture::WRAP_T));


    {
        JSONObject* obj = createImageFromTexture<osg::Texture1D>(texture, jsonTexture.get(), this);
        if (obj) {
            return obj;
        }
    }

    {
        JSONObject* obj = createImageFromTexture<osg::Texture2D>(texture, jsonTexture.get(), this);
        if (obj) {
            return obj;
        }
    }

    {
        JSONObject* obj = createImageFromTexture<osg::TextureRectangle>(texture, jsonTexture.get(), this);
        if (obj) {
            return obj;
        }
    }

    return 0;
}

JSONObject* WriteVisitor::createJSONStateSet(osg::StateSet* stateset)
{

    if (_maps.find(stateset) != _maps.end()) {
        return _maps[stateset]->getShadowObject();
    }

    osg::ref_ptr<JSONObject> jsonStateSet = new JSONStateSet;
    _maps[stateset] = jsonStateSet;

    translateObject(jsonStateSet.get(), stateset);

    if (stateset->getRenderingHint() == osg::StateSet::TRANSPARENT_BIN) {
        jsonStateSet->getMaps()["RenderingHint"] = new JSONValue<std::string>("TRANSPARENT_BIN");
    }

    bool blendEnabled = false;
    if (stateset->getMode(GL_BLEND) == osg::StateAttribute::ON) {
        blendEnabled = true;
    }

    osg::ref_ptr<JSONArray> textureAttributeList = new JSONArray;
    int lastTextureIndex = -1;
    for (int i = 0; i < 32; ++i) {
        osg::Texture* texture = dynamic_cast<osg::Texture*>(stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE));

        JSONArray* textureUnit = new JSONArray;
        JSONObject* jsonTexture = createJSONTexture(texture);
        textureAttributeList->getArray().push_back(textureUnit);

        if (jsonTexture) {
            JSONObject* textureObject = new JSONObject;
            textureObject->getMaps()["osg.Texture"] = jsonTexture;
            textureUnit->getArray().push_back(textureObject);
            lastTextureIndex = i;
        }
    }
    if (lastTextureIndex > -1) {
        textureAttributeList->getArray().resize(lastTextureIndex+1);
        jsonStateSet->getMaps()["TextureAttributeList"] = textureAttributeList;
    }


    osg::ref_ptr<JSONArray> attributeList = new JSONArray;

    osg::Material* material = dynamic_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
    if (material) {
        JSONObject* obj = new JSONObject;
        obj->getMaps()["osg.Material"] = createJSONMaterial(material);
        attributeList->getArray().push_back(obj);
    }

    osg::BlendFunc* blendFunc = dynamic_cast<osg::BlendFunc*>(stateset->getAttribute(osg::StateAttribute::BLENDFUNC));
    if (blendFunc) {
        JSONObject* obj = new JSONObject;
        obj->getMaps()["osg.BlendFunc"] = createJSONBlendFunc(blendFunc);
        attributeList->getArray().push_back(obj);
    } else if (blendEnabled == true) {
        JSONObject* obj = new JSONObject;
        osg::ref_ptr<osg::BlendFunc> defaultBlend = new osg::BlendFunc();
        obj->getMaps()["osg.BlendFunc"] = createJSONBlendFunc(defaultBlend.get());
        attributeList->getArray().push_back(obj);
    }

    osg::ref_ptr<osg::CullFace> cullFace = dynamic_cast<osg::CullFace*>(stateset->getAttribute(osg::StateAttribute::CULLFACE));
    osg::StateAttribute::GLModeValue cullMode = stateset->getMode(GL_CULL_FACE);
    if (cullFace || cullMode != osg::StateAttribute::INHERIT) {
        JSONObject* obj = new JSONObject;
        JSONObject* cf = 0;
        if (cullMode == osg::StateAttribute::OFF) {
            osg::ref_ptr<osg::CullFace> defaultCull = new osg::CullFace();
            cf = createJSONCullFace(defaultCull.get());
            cf->getMaps()["Mode"] = new JSONValue<std::string>("DISABLE");
            obj->getMaps()["osg.CullFace"] = cf;
            attributeList->getArray().push_back(obj);
        } else {
            if (!cullFace) {
                cullFace = new osg::CullFace();
            }
            cf = createJSONCullFace(cullFace.get());
        }
        obj->getMaps()["osg.CullFace"] = cf;
        attributeList->getArray().push_back(obj);
    }

    osg::BlendColor* blendColor = dynamic_cast<osg::BlendColor*>(stateset->getAttribute(osg::StateAttribute::BLENDCOLOR));
    if (blendColor) {
        JSONObject* obj = new JSONObject;
        obj->getMaps()["osg.BlendColor"] = createJSONBlendColor(blendColor);
        attributeList->getArray().push_back(obj);
    }

    if (!attributeList->getArray().empty()) {
        jsonStateSet->getMaps()["AttributeList"] = attributeList;
    }

    if (jsonStateSet->getMaps().empty())
        return 0;
    return jsonStateSet.release();
}
-------------- next part --------------
/* -*-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.
 *
 * This file is Copyright (C) 2007 - Andre Garneau (andre at pixdev.com) and licensed under OSGPL.
 *
 * Some elements of GraphicsWindowWin32 have used the Producer implementation as a reference.
 * These elements are licensed under OSGPL as above, with Copyright (C) 2001-2004  Don Burns.
 */

#include <osgViewer/api/Win32/GraphicsWindowWin32>
#include <osgViewer/api/Win32/PixelBufferWin32>
#include <osgViewer/View>

#include <osg/GL>
#include <osg/DeleteHandler>
#include <osg/ApplicationUsage>
#include <osg/os_utils>

#include <vector>
#include <map>
#include <sstream>
#include <windowsx.h>

#define MOUSEEVENTF_FROMTOUCH           0xFF515700

// _MSC_VER 1500: VS 2008
#if(WINVER < 0x0601 || _MSC_VER <= 1500)
// Provide Declarations for Multitouch

#define WM_TOUCH                        0x0240

/*
 * Touch Input defines and functions
 */

/*
 * Touch input handle
 */
DECLARE_HANDLE(HTOUCHINPUT);

typedef struct tagTOUCHINPUT {
    LONG x;
    LONG y;
    HANDLE hSource;
    DWORD dwID;
    DWORD dwFlags;
    DWORD dwMask;
    DWORD dwTime;
    ULONG_PTR dwExtraInfo;
    DWORD cxContact;
    DWORD cyContact;
} TOUCHINPUT, *PTOUCHINPUT;
typedef TOUCHINPUT const * PCTOUCHINPUT;


/*
 * Conversion of touch input coordinates to pixels
 */
#define TOUCH_COORD_TO_PIXEL(l)         ((l) / 100)

/*
 * Touch input flag values (TOUCHINPUT.dwFlags)
 */
#define TOUCHEVENTF_MOVE            0x0001
#define TOUCHEVENTF_DOWN            0x0002
#define TOUCHEVENTF_UP              0x0004
#define TOUCHEVENTF_INRANGE         0x0008
#define TOUCHEVENTF_PRIMARY         0x0010
#define TOUCHEVENTF_NOCOALESCE      0x0020
#define TOUCHEVENTF_PEN             0x0040
#define TOUCHEVENTF_PALM            0x0080

#endif


// provide declaration for WM_POINTER* events
// which handle both touch and pen events
// for Windows 8 and above

// _MSC_VER 1600: VS 2010
#if(WINVER < 0x0602 || _MSC_VER <= 1600)

#define WM_POINTERUPDATE                0x0245
#define WM_POINTERDOWN                  0x0246
#define WM_POINTERUP                    0x0247

// PointerInput enumeration
enum tagPOINTER_INPUT_TYPE {
   PT_POINTER = 0x00000001,   // Generic pointer
   PT_TOUCH = 0x00000002,   // Touch
   PT_PEN = 0x00000003,   // Pen
   PT_MOUSE = 0x00000004,   // Mouse
//#if(WINVER >= 0x0603)
   PT_TOUCHPAD = 0x00000005,   // Touchpad
//#endif /* WINVER >= 0x0603 */
};
typedef DWORD POINTER_INPUT_TYPE;


// methods to extract pointer info
#define GET_POINTERID_WPARAM(wParam)                (LOWORD(wParam))
#endif



typedef
BOOL
(WINAPI GetTouchInputInfoFunc)(
    HTOUCHINPUT hTouchInput,               // input event handle; from touch message lParam
    UINT cInputs,                          // number of elements in the array
    PTOUCHINPUT pInputs,  // array of touch inputs
    int cbSize);                           // sizeof(TOUCHINPUT)

typedef
BOOL
(WINAPI CloseTouchInputHandleFunc(
    HTOUCHINPUT hTouchInput));                   // input event handle; from touch message lParam

typedef
BOOL
(WINAPI RegisterTouchWindowFunc(
    HWND hwnd,
    ULONG ulFlags));


// used together with WM_POINTER* events
typedef
BOOL
(WINAPI
GetPointerTypeFunc(
   UINT32 pointerId,
   POINTER_INPUT_TYPE *pointerType));


// Declared static in order to get Header File clean
static RegisterTouchWindowFunc *registerTouchWindowFunc = NULL;
static CloseTouchInputHandleFunc *closeTouchInputHandleFunc = NULL;
static GetTouchInputInfoFunc *getTouchInputInfoFunc = NULL;
static GetPointerTypeFunc *getPointerTypeFunc = NULL;

// DPI Awareness
// #if(WINVER >= 0x0603)

#ifndef DPI_ENUMS_DECLARED

typedef enum PROCESS_DPI_AWARENESS {
	PROCESS_DPI_UNAWARE = 0,
	PROCESS_SYSTEM_DPI_AWARE = 1,
	PROCESS_PER_MONITOR_DPI_AWARE = 2
} PROCESS_DPI_AWARENESS;

#endif // DPI_ENUMS_DECLARED

typedef
BOOL
(WINAPI	SetProcessDpiAwarenessFunc(
	PROCESS_DPI_AWARENESS dpi_awareness));

static SetProcessDpiAwarenessFunc *setProcessDpiAwareness = NULL;
// #endif



using namespace osgViewer;

namespace osgViewer
{

static osg::ApplicationUsageProxy GraphicsWindowWin32_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WIN32_NV_MULTIMON_MULTITHREAD_WORKAROUND on/off","Enable/disable duplicate makeCurrentContext call used as workaround for WinXP/NVidia/MultiView/MulitThread isues (pre 178.13 drivers).");

//
// Defines from the WGL_ARB_pixel_format specification document
// See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
//

#define WGL_NUMBER_PIXEL_FORMATS_ARB            0x2000
#define WGL_DRAW_TO_WINDOW_ARB                  0x2001
#define WGL_DRAW_TO_BITMAP_ARB                  0x2002
#define WGL_ACCELERATION_ARB                    0x2003
#define WGL_NEED_PALETTE_ARB                    0x2004
#define WGL_NEED_SYSTEM_PALETTE_ARB             0x2005
#define WGL_SWAP_LAYER_BUFFERS_ARB              0x2006
#define WGL_SWAP_METHOD_ARB                     0x2007
#define WGL_NUMBER_OVERLAYS_ARB                 0x2008
#define WGL_NUMBER_UNDERLAYS_ARB                0x2009
#define WGL_TRANSPARENT_ARB                     0x200A
#define WGL_TRANSPARENT_RED_VALUE_ARB           0x2037
#define WGL_TRANSPARENT_GREEN_VALUE_ARB         0x2038
#define WGL_TRANSPARENT_BLUE_VALUE_ARB          0x2039
#define WGL_TRANSPARENT_ALPHA_VALUE_ARB         0x203A
#define WGL_TRANSPARENT_INDEX_VALUE_ARB         0x203B
#define WGL_SHARE_DEPTH_ARB                     0x200C
#define WGL_SHARE_STENCIL_ARB                   0x200D
#define WGL_SHARE_ACCUM_ARB                     0x200E
#define WGL_SUPPORT_GDI_ARB                     0x200F
#define WGL_SUPPORT_OPENGL_ARB                  0x2010
#define WGL_DOUBLE_BUFFER_ARB                   0x2011
#define WGL_STEREO_ARB                          0x2012
#define WGL_PIXEL_TYPE_ARB                      0x2013
#define WGL_COLOR_BITS_ARB                      0x2014
#define WGL_RED_BITS_ARB                        0x2015
#define WGL_RED_SHIFT_ARB                       0x2016
#define WGL_GREEN_BITS_ARB                      0x2017
#define WGL_GREEN_SHIFT_ARB                     0x2018
#define WGL_BLUE_BITS_ARB                       0x2019
#define WGL_BLUE_SHIFT_ARB                      0x201A
#define WGL_ALPHA_BITS_ARB                      0x201B
#define WGL_ALPHA_SHIFT_ARB                     0x201C
#define WGL_ACCUM_BITS_ARB                      0x201D
#define WGL_ACCUM_RED_BITS_ARB                  0x201E
#define WGL_ACCUM_GREEN_BITS_ARB                0x201F
#define WGL_ACCUM_BLUE_BITS_ARB                 0x2020
#define WGL_ACCUM_ALPHA_BITS_ARB                0x2021
#define WGL_DEPTH_BITS_ARB                      0x2022
#define WGL_STENCIL_BITS_ARB                    0x2023
#define WGL_AUX_BUFFERS_ARB                     0x2024
#define WGL_NO_ACCELERATION_ARB                 0x2025
#define WGL_GENERIC_ACCELERATION_ARB            0x2026
#define WGL_FULL_ACCELERATION_ARB               0x2027
#define WGL_SWAP_EXCHANGE_ARB                   0x2028
#define WGL_SWAP_COPY_ARB                       0x2029
#define WGL_SWAP_UNDEFINED_ARB                  0x202A
#define WGL_TYPE_RGBA_ARB                       0x202B
#define WGL_TYPE_COLORINDEX_ARB                 0x202C
#define WGL_SAMPLE_BUFFERS_ARB                  0x2041
#define WGL_SAMPLES_ARB                         0x2042

#ifndef WGL_ARB_create_context
#define WGL_CONTEXT_DEBUG_BIT_ARB      0x00000001
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
#define WGL_CONTEXT_MAJOR_VERSION_ARB  0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB  0x2092
#define WGL_CONTEXT_LAYER_PLANE_ARB    0x2093
#define WGL_CONTEXT_FLAGS_ARB          0x2094
#define WGL_CONTEXT_PROFILE_MASK_ARB   0x9126
#define ERROR_INVALID_VERSION_ARB      0x2095
#endif

#ifndef WGL_ARB_create_context
#define WGL_ARB_create_context 1
#ifdef WGL_WGLEXT_PROTOTYPES
extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *);
#endif /* WGL_WGLEXT_PROTOTYPES */
typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);
#endif

//
// Entry points used from the WGL extensions
//
//    BOOL wglChoosePixelFormatARB(HDC hdc,
//                                 const int *piAttribIList,
//                                 const FLOAT *pfAttribFList,
//                                 UINT nMaxFormats,
//                                 int *piFormats,
//                                 UINT *nNumFormats);
//

typedef bool (WINAPI * WGLChoosePixelFormatARB) ( HDC, const int *, const float *, unsigned int, int *, unsigned int * );

//
// Utility class to specify the visual attributes for wglChoosePixelFormatARB() function
//

template <typename T> class WGLAttributes
{
  public:

      WGLAttributes()  {}
      ~WGLAttributes() {}

      void begin()                              { m_parameters.clear(); }
      void set( const T& id, const T& value )   { add(id); add(value); }
      void enable( const T& id )                { add(id); add(true); }
      void disable( const T& id )               { add(id); add(false); }
      void end()                                { add(0); }

      const T* get() const                      { return &m_parameters.front(); }

  protected:

      void add( const T& t )                    { m_parameters.push_back(t); }

      std::vector<T>    m_parameters;        // parameters added

  private:

      // No implementation for these
      WGLAttributes( const WGLAttributes& );
      WGLAttributes& operator=( const WGLAttributes& );
};

typedef WGLAttributes<int>     WGLIntegerAttributes;
typedef WGLAttributes<float> WGLFloatAttributes;

//
// Class responsible for interfacing with the Win32 Window Manager
// The behavior of this class is specific to OSG needs and is not a
// generic Windowing interface.
//
// NOTE: This class is intended to be used by a single-thread.
//         Multi-threading is not enabled for performance reasons.
//         The creation/deletion of graphics windows should be done
//         by a single controller thread. That thread should then
//         call the checkEvents() method of all created windows periodically.
//         This is the case with OSG as a "main" thread does all
//         setup, update & event processing. Rendering is done (optionally) by other threads.
//
// !@todo Have a dedicated thread managed by the Win32WindowingSystem class handle the
//        creation and event message processing for all windows it manages. This
//        is to relieve the "main" thread from having to do this synchronously
//        during frame generation. The "main" thread would only have to process
//          each osgGA-type window event queue.
//

class Win32WindowingSystem : public osg::GraphicsContext::WindowingSystemInterface
{
  public:

    // A class representing an OpenGL rendering context
    class OpenGLContext
    {
      public:

        OpenGLContext()
        : _previousHdc(0),
          _previousHglrc(0),
          _hwnd(0),
          _hdc(0),
          _hglrc(0),
          _restorePreviousOnExit(false)
        {}

        OpenGLContext( HWND hwnd, HDC hdc, HGLRC hglrc )
        : _previousHdc(0),
          _previousHglrc(0),
          _hwnd(hwnd),
          _hdc(hdc),
          _hglrc(hglrc),
          _restorePreviousOnExit(false)
        {}

        ~OpenGLContext();

        void set( HWND hwnd, HDC hdc, HGLRC hglrc )
        {
            _hwnd  = hwnd;
            _hdc   = hdc;
            _hglrc = hglrc;
        }

        HDC deviceContext() { return _hdc; }

        bool makeCurrent( HDC restoreOnHdc, bool restorePreviousOnExit );

      protected:

        //
        // Data members
        //

        HDC   _previousHdc;                // previously HDC to restore rendering context on
        HGLRC _previousHglrc;           // previously current rendering context
        HWND  _hwnd;                    // handle to OpenGL window
        HDC   _hdc;                     // handle to device context
        HGLRC _hglrc;                   // handle to OpenGL rendering context
        bool  _restorePreviousOnExit;   // restore original context on exit

        private:

        // no implementation for these
        OpenGLContext( const OpenGLContext& );
        OpenGLContext& operator=( const OpenGLContext& );
    };

    static std::string osgGraphicsWindowWithCursorClass;    //!< Name of Win32 window class (with cursor) used by OSG graphics window instances
    static std::string osgGraphicsWindowWithoutCursorClass; //!< Name of Win32 window class (without cursor) used by OSG graphics window instances

    Win32WindowingSystem();

    // Access the Win32 windowing system through this singleton class.
    static osg::observer_ptr<Win32WindowingSystem>& getInterface()
    {
        static osg::observer_ptr<Win32WindowingSystem> s_win32Interface;
        return s_win32Interface;
    }

    // Return the number of screens present in the system
    virtual unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si );

    // Return the resolution of specified screen
    // (0,0) is returned if screen is unknown
    virtual void getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution );

    // Return the bits per pixel of specified screen
    // (0) is returned if screen is unknown
    virtual void getScreenColorDepth( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& dmBitsPerPel );

    // Set the resolution for given screen
    virtual bool setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution );

    // Enumerates available resolutions
    virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolution);

    // Return the screen position and width/height.
    // all zeros returned if screen is unknown
    virtual void getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height );

    // Create a graphics context with given traits
    virtual osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits );

    // Register a newly created native window along with its application counterpart
    // This is required to maintain a link between Windows messages and the application window object
    // at event processing time
    virtual void registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window );

    // Unregister a window
    // This is called as part of a window being torn down
    virtual void unregisterWindow( HWND hwnd );

    // Get the application window object associated with a native window
    virtual osgViewer::GraphicsWindowWin32* getGraphicsWindowFor( HWND hwnd );

    // Return a valid sample OpenGL Device Context and current rendering context that can be used with wglXYZ extensions
    virtual bool getSampleOpenGLContext( OpenGLContext& context, HDC windowHDC, int windowOriginX, int windowOriginY );

  protected:

    virtual ~Win32WindowingSystem();

    // Display devices present in the system
    typedef std::vector<DISPLAY_DEVICE> DisplayDevices;

    // Map Win32 window handles to GraphicsWindowWin32 instance
    typedef std::pair< HWND, osgViewer::GraphicsWindowWin32* >  WindowHandleEntry;
    typedef std::map<  HWND, osgViewer::GraphicsWindowWin32* >  WindowHandles;

    // Enumerate all display devices and return in passed container
    void enumerateDisplayDevices( DisplayDevices& displayDevices ) const;

    // Get the screen device current mode information
    bool getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode );

    // Change the screen settings (resolution, refresh rate, etc.)
    bool changeScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode );

    // Register the window classes used by OSG graphics window instances
    void registerWindowClasses();

    // Unregister the window classes used by OSG graphics window instances
    void unregisterWindowClasses();

    // Data members
    WindowHandles       _activeWindows;                //!< handles to active windows
    bool                _windowClassesRegistered;      //!< true after window classes have been registered

 private:

     // No implementation for these
     Win32WindowingSystem( const Win32WindowingSystem& );
     Win32WindowingSystem& operator=( const Win32WindowingSystem& );
};

///////////////////////////////////////////////////////////////////////////////
//  Check if window dimensions have changed w.r.t stored values
//////////////////////////////////////////////////////////////////////////////
static bool areWindowDimensionsChanged(HWND hwnd, int screenOriginX, int screenOriginY, int& windowX, int& windowY, int& windowWidth, int& windowHeight)
{
    POINT origin;
    origin.x = 0;
    origin.y = 0;

    ::ClientToScreen(hwnd, &origin);

    int new_windowX = origin.x - screenOriginX;
    int new_windowY = origin.y - screenOriginY;

    RECT clientRect;
    ::GetClientRect(hwnd, &clientRect);

    int new_windowWidth = (clientRect.right == 0) ? 1 : clientRect.right;
    int new_windowHeight = (clientRect.bottom == 0) ? 1 : clientRect.bottom;

    if ((new_windowX != windowX) || (new_windowY != windowY) || (new_windowWidth != windowWidth) || (new_windowHeight != windowHeight))
    {
        windowX = new_windowX;
        windowY = new_windowY;
        windowWidth = new_windowWidth;
        windowHeight = new_windowHeight;

        return true;
    }
    else
    {
        return false;
    }
}

///////////////////////////////////////////////////////////////////////////////
//                             Error reporting
//////////////////////////////////////////////////////////////////////////////

static void reportError( const std::string& msg )
{
    OSG_WARN << "Error: " << msg.c_str() << std::endl;
}

static void reportError( const std::string& msg, unsigned int errorCode )
{
    //
    // Some APIs are documented as returning the error in ::GetLastError but apparently do not
    // Skip "Reason" field if the errorCode is still success
    //

    if (errorCode==0)
    {
        reportError(msg);
        return;
    }

    OSG_WARN << "Windows Error #"   << errorCode << ": " << msg.c_str();

    LPVOID lpMsgBuf;

    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                      NULL,
                      errorCode,
                      0, // Default language
                      (LPTSTR) &lpMsgBuf,
                      0,
                      NULL)!=0)
    {
        OSG_WARN << ". Reason: " << LPTSTR(lpMsgBuf) << std::endl;
        ::LocalFree(lpMsgBuf);
    }
    else
    {
        OSG_WARN << std::endl;
    }
}

static void reportErrorForScreen( const std::string& msg, const osg::GraphicsContext::ScreenIdentifier& si, unsigned int errorCode )
{
    std::ostringstream str;

    str << "[Screen #" << si.screenNum << "] " << msg;
    reportError(str.str(), errorCode);
}

//////////////////////////////////////////////////////////////////////////////
//                       Keyboard key mapping for Win32
//////////////////////////////////////////////////////////////////////////////

class Win32KeyboardMap
{
    public:

        Win32KeyboardMap()
        {
            _keymap[VK_ESCAPE       ] = osgGA::GUIEventAdapter::KEY_Escape;
            _keymap[VK_F1           ] = osgGA::GUIEventAdapter::KEY_F1;
            _keymap[VK_F2           ] = osgGA::GUIEventAdapter::KEY_F2;
            _keymap[VK_F3           ] = osgGA::GUIEventAdapter::KEY_F3;
            _keymap[VK_F4           ] = osgGA::GUIEventAdapter::KEY_F4;
            _keymap[VK_F5           ] = osgGA::GUIEventAdapter::KEY_F5;
            _keymap[VK_F6           ] = osgGA::GUIEventAdapter::KEY_F6;
            _keymap[VK_F7           ] = osgGA::GUIEventAdapter::KEY_F7;
            _keymap[VK_F8           ] = osgGA::GUIEventAdapter::KEY_F8;
            _keymap[VK_F9           ] = osgGA::GUIEventAdapter::KEY_F9;
            _keymap[VK_F10          ] = osgGA::GUIEventAdapter::KEY_F10;
            _keymap[VK_F11          ] = osgGA::GUIEventAdapter::KEY_F11;
            _keymap[VK_F12          ] = osgGA::GUIEventAdapter::KEY_F12;
            _keymap[0xc0            ] = osgGA::GUIEventAdapter::KEY_Backquote;
            _keymap['0'             ] = osgGA::GUIEventAdapter::KEY_0;
            _keymap['1'             ] = osgGA::GUIEventAdapter::KEY_1;
            _keymap['2'             ] = osgGA::GUIEventAdapter::KEY_2;
            _keymap['3'             ] = osgGA::GUIEventAdapter::KEY_3;
            _keymap['4'             ] = osgGA::GUIEventAdapter::KEY_4;
            _keymap['5'             ] = osgGA::GUIEventAdapter::KEY_5;
            _keymap['6'             ] = osgGA::GUIEventAdapter::KEY_6;
            _keymap['7'             ] = osgGA::GUIEventAdapter::KEY_7;
            _keymap['8'             ] = osgGA::GUIEventAdapter::KEY_8;
            _keymap['9'             ] = osgGA::GUIEventAdapter::KEY_9;
            _keymap[0xbd            ] = osgGA::GUIEventAdapter::KEY_Minus;
            _keymap[0xbb            ] = osgGA::GUIEventAdapter::KEY_Equals;
            _keymap[VK_BACK         ] = osgGA::GUIEventAdapter::KEY_BackSpace;
            _keymap[VK_TAB          ] = osgGA::GUIEventAdapter::KEY_Tab;
            _keymap['A'             ] = osgGA::GUIEventAdapter::KEY_A;
            _keymap['B'             ] = osgGA::GUIEventAdapter::KEY_B;
            _keymap['C'             ] = osgGA::GUIEventAdapter::KEY_C;
            _keymap['D'             ] = osgGA::GUIEventAdapter::KEY_D;
            _keymap['E'             ] = osgGA::GUIEventAdapter::KEY_E;
            _keymap['F'             ] = osgGA::GUIEventAdapter::KEY_F;
            _keymap['G'             ] = osgGA::GUIEventAdapter::KEY_G;
            _keymap['H'             ] = osgGA::GUIEventAdapter::KEY_H;
            _keymap['I'             ] = osgGA::GUIEventAdapter::KEY_I;
            _keymap['J'             ] = osgGA::GUIEventAdapter::KEY_J;
            _keymap['K'             ] = osgGA::GUIEventAdapter::KEY_K;
            _keymap['L'             ] = osgGA::GUIEventAdapter::KEY_L;
            _keymap['M'             ] = osgGA::GUIEventAdapter::KEY_M;
            _keymap['N'             ] = osgGA::GUIEventAdapter::KEY_N;
            _keymap['O'             ] = osgGA::GUIEventAdapter::KEY_O;
            _keymap['P'             ] = osgGA::GUIEventAdapter::KEY_P;
            _keymap['Q'             ] = osgGA::GUIEventAdapter::KEY_Q;
            _keymap['R'             ] = osgGA::GUIEventAdapter::KEY_R;
            _keymap['S'             ] = osgGA::GUIEventAdapter::KEY_S;
            _keymap['T'             ] = osgGA::GUIEventAdapter::KEY_T;
            _keymap['U'             ] = osgGA::GUIEventAdapter::KEY_U;
            _keymap['V'             ] = osgGA::GUIEventAdapter::KEY_V;
            _keymap['W'             ] = osgGA::GUIEventAdapter::KEY_W;
            _keymap['X'             ] = osgGA::GUIEventAdapter::KEY_X;
            _keymap['Y'             ] = osgGA::GUIEventAdapter::KEY_Y;
            _keymap['Z'             ] = osgGA::GUIEventAdapter::KEY_Z;
            _keymap[0xdb            ] = osgGA::GUIEventAdapter::KEY_Leftbracket;
            _keymap[0xdd            ] = osgGA::GUIEventAdapter::KEY_Rightbracket;
            _keymap[0xdc            ] = osgGA::GUIEventAdapter::KEY_Backslash;
            _keymap[VK_CAPITAL      ] = osgGA::GUIEventAdapter::KEY_Caps_Lock;
            _keymap[0xba            ] = osgGA::GUIEventAdapter::KEY_Semicolon;
            _keymap[0xde            ] = osgGA::GUIEventAdapter::KEY_Quote;
            _keymap[VK_RETURN       ] = osgGA::GUIEventAdapter::KEY_Return;
            _keymap[VK_LSHIFT       ] = osgGA::GUIEventAdapter::KEY_Shift_L;
            _keymap[0xbc            ] = osgGA::GUIEventAdapter::KEY_Comma;
            _keymap[0xbe            ] = osgGA::GUIEventAdapter::KEY_Period;
            _keymap[0xbf            ] = osgGA::GUIEventAdapter::KEY_Slash;
            _keymap[VK_RSHIFT       ] = osgGA::GUIEventAdapter::KEY_Shift_R;
            _keymap[VK_LCONTROL     ] = osgGA::GUIEventAdapter::KEY_Control_L;
            _keymap[VK_LWIN         ] = osgGA::GUIEventAdapter::KEY_Super_L;
            _keymap[VK_SPACE        ] = osgGA::GUIEventAdapter::KEY_Space;
            _keymap[VK_LMENU        ] = osgGA::GUIEventAdapter::KEY_Alt_L;
            _keymap[VK_RMENU        ] = osgGA::GUIEventAdapter::KEY_Alt_R;
            _keymap[VK_RWIN         ] = osgGA::GUIEventAdapter::KEY_Super_R;
            _keymap[VK_APPS         ] = osgGA::GUIEventAdapter::KEY_Menu;
            _keymap[VK_RCONTROL     ] = osgGA::GUIEventAdapter::KEY_Control_R;
            _keymap[VK_SNAPSHOT     ] = osgGA::GUIEventAdapter::KEY_Print;
            _keymap[VK_SCROLL       ] = osgGA::GUIEventAdapter::KEY_Scroll_Lock;
            _keymap[VK_PAUSE        ] = osgGA::GUIEventAdapter::KEY_Pause;
            _keymap[VK_HOME         ] = osgGA::GUIEventAdapter::KEY_Home;
            _keymap[VK_PRIOR        ] = osgGA::GUIEventAdapter::KEY_Page_Up;
            _keymap[VK_END          ] = osgGA::GUIEventAdapter::KEY_End;
            _keymap[VK_NEXT         ] = osgGA::GUIEventAdapter::KEY_Page_Down;
            _keymap[VK_DELETE       ] = osgGA::GUIEventAdapter::KEY_Delete;
            _keymap[VK_INSERT       ] = osgGA::GUIEventAdapter::KEY_Insert;
            _keymap[VK_LEFT         ] = osgGA::GUIEventAdapter::KEY_Left;
            _keymap[VK_UP           ] = osgGA::GUIEventAdapter::KEY_Up;
            _keymap[VK_RIGHT        ] = osgGA::GUIEventAdapter::KEY_Right;
            _keymap[VK_DOWN         ] = osgGA::GUIEventAdapter::KEY_Down;
            _keymap[VK_NUMLOCK      ] = osgGA::GUIEventAdapter::KEY_Num_Lock;
            _keymap[VK_DIVIDE       ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
            _keymap[VK_MULTIPLY     ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
            _keymap[VK_SUBTRACT     ] = osgGA::GUIEventAdapter::KEY_KP_Subtract;
            _keymap[VK_ADD          ] = osgGA::GUIEventAdapter::KEY_KP_Add;
            _keymap[VK_NUMPAD7      ] = osgGA::GUIEventAdapter::KEY_KP_Home;
            _keymap[VK_NUMPAD8      ] = osgGA::GUIEventAdapter::KEY_KP_Up;
            _keymap[VK_NUMPAD9      ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
            _keymap[VK_NUMPAD4      ] = osgGA::GUIEventAdapter::KEY_KP_Left;
            _keymap[VK_NUMPAD5      ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
            _keymap[VK_NUMPAD6      ] = osgGA::GUIEventAdapter::KEY_KP_Right;
            _keymap[VK_NUMPAD1      ] = osgGA::GUIEventAdapter::KEY_KP_End;
            _keymap[VK_NUMPAD2      ] = osgGA::GUIEventAdapter::KEY_KP_Down;
            _keymap[VK_NUMPAD3      ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
            _keymap[VK_NUMPAD0      ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
            _keymap[VK_DECIMAL      ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
            _keymap[VK_CLEAR        ] = osgGA::GUIEventAdapter::KEY_Clear;
        }

        ~Win32KeyboardMap() {}

        int remapKey(int key)
        {
            KeyMap::const_iterator map = _keymap.find(key);
            return map==_keymap.end() ? key : map->second;
        }

    protected:

        typedef std::map<int, int> KeyMap;
        KeyMap _keymap;
};

static Win32KeyboardMap s_win32KeyboardMap;
static int remapWin32Key(int key)
{
    return s_win32KeyboardMap.remapKey(key);
}

//////////////////////////////////////////////////////////////////////////////
//         Window procedure for all GraphicsWindowWin32 instances
//           Dispatches the call to the actual instance
//////////////////////////////////////////////////////////////////////////////

static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    osgViewer::GraphicsWindowWin32* window = Win32WindowingSystem::getInterface()->getGraphicsWindowFor(hwnd);
    return window ? window->handleNativeWindowingEvent(hwnd, uMsg, wParam, lParam) :
                    ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}

//////////////////////////////////////////////////////////////////////////////
//              Win32WindowingSystem::OpenGLContext implementation
//////////////////////////////////////////////////////////////////////////////

Win32WindowingSystem::OpenGLContext::~OpenGLContext()
{
    if (_restorePreviousOnExit && _previousHglrc!=_hglrc && !::wglMakeCurrent(_previousHdc, _previousHglrc))
    {
        reportError("Win32WindowingSystem::OpenGLContext() - Unable to restore current OpenGL rendering context", ::GetLastError());
    }

    _previousHdc   = 0;
    _previousHglrc = 0;

    if (_hglrc)
    {
        ::wglMakeCurrent(_hdc, NULL);
        ::wglDeleteContext(_hglrc);
        _hglrc = 0;
    }

    if (_hdc)
    {
        ::ReleaseDC(_hwnd, _hdc);
        _hdc = 0;
    }

    if (_hwnd)
    {
        ::DestroyWindow(_hwnd);
        _hwnd = 0;
    }
}

bool Win32WindowingSystem::OpenGLContext::makeCurrent( HDC restoreOnHdc, bool restorePreviousOnExit )
{
    if (_hdc==0 || _hglrc==0) return false;

    _previousHglrc = restorePreviousOnExit ? ::wglGetCurrentContext() : 0;
    _previousHdc   = restoreOnHdc;

    if (_hglrc==_previousHglrc) return true;

    if (!::wglMakeCurrent(_hdc, _hglrc))
    {
        reportError("Win32WindowingSystem::OpenGLContext() - Unable to set current OpenGL rendering context", ::GetLastError());
        return false;
    }

    _restorePreviousOnExit = restorePreviousOnExit;

    return true;
}

//////////////////////////////////////////////////////////////////////////////
//              Win32WindowingSystem implementation
//////////////////////////////////////////////////////////////////////////////

std::string Win32WindowingSystem::osgGraphicsWindowWithCursorClass;
std::string Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass;

Win32WindowingSystem::Win32WindowingSystem()
: _windowClassesRegistered(false)
{
    getInterface() = this;

    // Detect presence of runtime support for multitouch
    HMODULE hModule = LoadLibrary("user32");
    if (hModule)
    {
        registerTouchWindowFunc = (RegisterTouchWindowFunc *) GetProcAddress( hModule, "RegisterTouchWindow");
        closeTouchInputHandleFunc = (CloseTouchInputHandleFunc *) GetProcAddress( hModule, "CloseTouchInputHandle");
        getTouchInputInfoFunc = (GetTouchInputInfoFunc *)  GetProcAddress( hModule, "GetTouchInputInfo");

       // check if Win8 and later API is available
       getPointerTypeFunc = (GetPointerTypeFunc*)GetProcAddress(hModule, "GetPointerType");

        if (!(registerTouchWindowFunc && closeTouchInputHandleFunc && getTouchInputInfoFunc))
        {
            registerTouchWindowFunc = NULL;
            closeTouchInputHandleFunc = NULL;
            getTouchInputInfoFunc = NULL;
            FreeLibrary( hModule);
        }
    }


// #if(WINVER >= 0x0603)
	// For Windows 8.1 and higher
	//
	// Per monitor DPI aware.This app checks for the DPI when it is created and adjusts the scale factor
	// whenever the DPI changes.These applications are not automatically scaled by the system.
	HMODULE hModuleShore = LoadLibrary("Shcore");
	if (hModuleShore) {
		setProcessDpiAwareness = (SetProcessDpiAwarenessFunc *) GetProcAddress(hModuleShore, "SetProcessDpiAwareness");
		if (setProcessDpiAwareness) {
			(*setProcessDpiAwareness)(PROCESS_DPI_AWARENESS::PROCESS_PER_MONITOR_DPI_AWARE);
		}
	}
// #endif
}

Win32WindowingSystem::~Win32WindowingSystem()
{
    if (osg::Referenced::getDeleteHandler())
    {
        osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
        osg::Referenced::getDeleteHandler()->flushAll();
    }

    unregisterWindowClasses();
}

void Win32WindowingSystem::enumerateDisplayDevices( DisplayDevices& displayDevices ) const
{
    for (unsigned int deviceNum=0;; ++deviceNum)
    {
        DISPLAY_DEVICE displayDevice;
        displayDevice.cb = sizeof(displayDevice);

        if (!::EnumDisplayDevices(NULL, deviceNum, &displayDevice, 0)) break;

        // Do not track devices used for remote access (Terminal Services pseudo-displays, etc.)
        if (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) continue;

        // Only return display devices that are attached to the desktop
        if (!(displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) continue;

        displayDevices.push_back(displayDevice);
    }
}

void Win32WindowingSystem::registerWindowClasses()
{
    if (_windowClassesRegistered) return;

    //
    // Register the window classes used by OSG GraphicsWindowWin32 instances
    //

    std::ostringstream str;
    str << "OSG Graphics Window for Win32 [" << ::GetCurrentProcessId() << "]";

    osgGraphicsWindowWithCursorClass    = str.str() + "{ with cursor }";
    osgGraphicsWindowWithoutCursorClass = str.str() + "{ without cursor }";

    WNDCLASSEX wc;

    HINSTANCE hinst = ::GetModuleHandle(NULL);

    //
    // First class: class for OSG Graphics Window with a cursor enabled
    //

    wc.cbSize        = sizeof(wc);
    wc.style         = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc   = WindowProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hinst;
    wc.hIcon         = ::LoadIcon(hinst, "OSG_ICON");
    wc.hCursor       = ::LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName  = 0;
    wc.lpszClassName = osgGraphicsWindowWithCursorClass.c_str();
    wc.hIconSm       = NULL;

    if (::RegisterClassEx(&wc)==0)
    {
        unsigned int lastError = ::GetLastError();
        if (lastError!=ERROR_CLASS_ALREADY_EXISTS)
        {
            reportError("Win32WindowingSystem::registerWindowClasses() - Unable to register first window class", lastError);
            return;
        }
    }

    //
    // Second class: class for OSG Graphics Window without a cursor
    //

    wc.hCursor       = NULL;
    wc.lpszClassName = osgGraphicsWindowWithoutCursorClass.c_str();

    if (::RegisterClassEx(&wc)==0)
    {
        unsigned int lastError = ::GetLastError();
        if (lastError!=ERROR_CLASS_ALREADY_EXISTS)
        {
            reportError("Win32WindowingSystem::registerWindowClasses() - Unable to register second window class", lastError);
            return;
        }
    }

    _windowClassesRegistered = true;
}

void Win32WindowingSystem::unregisterWindowClasses()
{
    if (_windowClassesRegistered)
    {
        ::UnregisterClass(osgGraphicsWindowWithCursorClass.c_str(),    ::GetModuleHandle(NULL));
        ::UnregisterClass(osgGraphicsWindowWithoutCursorClass.c_str(), ::GetModuleHandle(NULL));
        _windowClassesRegistered = false;
    }
}

bool Win32WindowingSystem::getSampleOpenGLContext( OpenGLContext& context, HDC windowHDC, int windowOriginX, int windowOriginY )
{
    context.set(0, 0, 0);

    registerWindowClasses();

    HWND hwnd = ::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
                                 osgGraphicsWindowWithoutCursorClass.c_str(),
                                 NULL,
                                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
                                 windowOriginX,
                                 windowOriginY,
                                 1,
                                 1,
                                 NULL,
                                 NULL,
                                 ::GetModuleHandle(NULL),
                                 NULL);
    if (hwnd==0)
    {
        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create window", ::GetLastError());
        return false;
    }

    //
    // Set the pixel format of the window
    //

    PIXELFORMATDESCRIPTOR pixelFormat =
    {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,
        PFD_TYPE_RGBA,
        24,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        24,
        0,
        0,
        PFD_MAIN_PLANE,
        0,
        0, 0, 0
    };

    HDC hdc = ::GetDC(hwnd);
    if (hdc==0)
    {
        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to get window device context", ::GetLastError());
        ::DestroyWindow(hwnd);
        return false;
    }

    int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat);
    if (pixelFormatIndex==0)
    {
        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to choose pixel format", ::GetLastError());
        ::ReleaseDC(hwnd, hdc);
        ::DestroyWindow(hwnd);
        return false;
    }

    if (!::SetPixelFormat(hdc, pixelFormatIndex, &pixelFormat))
    {
        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to set pixel format", ::GetLastError());
        ::ReleaseDC(hwnd, hdc);
        ::DestroyWindow(hwnd);
        return false;
    }

    HGLRC hglrc = ::wglCreateContext(hdc);
    if (hglrc==0)
    {
        reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create an OpenGL rendering context", ::GetLastError());
        ::ReleaseDC(hwnd, hdc);
        ::DestroyWindow(hwnd);
        return false;
    }

    context.set(hwnd, hdc, hglrc);

    if (!context.makeCurrent(windowHDC, true)) return false;

    return true;
}

unsigned int Win32WindowingSystem::getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si )
{
    return si.displayNum==0 ? ::GetSystemMetrics(SM_CMONITORS) : 0;
}

bool Win32WindowingSystem::getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode )
{
    if (si.displayNum>0)
    {
        OSG_WARN << "Win32WindowingSystem::getScreenInformation() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl;
        return false;
    }

    DisplayDevices displayDevices;
    enumerateDisplayDevices(displayDevices);

    if (si.screenNum>=static_cast<int>(displayDevices.size()))
    {
        OSG_WARN << "Win32WindowingSystem::getScreenInformation() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl;
        return false;
    }

    displayDevice = displayDevices[si.screenNum];

    deviceMode.dmSize        = sizeof(deviceMode);
    deviceMode.dmDriverExtra = 0;

    if (!::EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &deviceMode))
    {
        std::ostringstream str;
        str << "Win32WindowingSystem::getScreenInformation() - Unable to query information for screen number " << si.screenNum;
        reportError(str.str(), ::GetLastError());
        return false;
    }

    return true;
}

void Win32WindowingSystem::getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution )
{
    DISPLAY_DEVICE displayDevice;
    DEVMODE        deviceMode;

    if (!getScreenInformation(si, displayDevice, deviceMode))
        deviceMode.dmFields = 0;        // Set the fields to 0 so that it says 'nothing'.

    // Get resolution
    if ((deviceMode.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != 0) {
        resolution.width  = deviceMode.dmPelsWidth;
        resolution.height = deviceMode.dmPelsHeight;
    } else {
        resolution.width  = 0;
        resolution.height = 0;
    }

    // Get refersh rate
    if ((deviceMode.dmFields & DM_DISPLAYFREQUENCY) != 0) {
        resolution.refreshRate = deviceMode.dmDisplayFrequency;
        if (resolution.refreshRate == 0 || resolution.refreshRate == 1) {
            // Windows specific: 0 and 1 represent the hhardware's default refresh rate.
            // If someone knows how to get this refresh rate (in Hz)...
            OSG_NOTICE << "Win32WindowingSystem::getScreenSettings() is not fully implemented (cannot retrieve the hardware's default refresh rate)."<<std::endl;
            resolution.refreshRate = 0;
        }
    } else
        resolution.refreshRate = 0;

    // Get bits per pixel for color buffer
    if ((deviceMode.dmFields & DM_BITSPERPEL) != 0)
        resolution.colorDepth = deviceMode.dmBitsPerPel;
    else
        resolution.colorDepth = 0;
}

void Win32WindowingSystem::getScreenColorDepth( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& dmBitsPerPel )
{
    DISPLAY_DEVICE displayDevice;
    DEVMODE        deviceMode;

    if (getScreenInformation(si, displayDevice, deviceMode))
    {
        dmBitsPerPel = deviceMode.dmBitsPerPel;
    }
    else
    {
        dmBitsPerPel  = 0;
    }
}

bool Win32WindowingSystem::changeScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode )
{
    //
    // Start by testing if the change would be successful (without applying it)
    //

    unsigned int result = ::ChangeDisplaySettingsEx(displayDevice.DeviceName, &deviceMode, NULL, CDS_TEST, NULL);
    if (result==DISP_CHANGE_SUCCESSFUL)
    {
        result = ::ChangeDisplaySettingsEx(displayDevice.DeviceName, &deviceMode, NULL, 0, NULL);
        if (result==DISP_CHANGE_SUCCESSFUL) return true;
    }

    std::string msg = "Win32WindowingSystem::changeScreenSettings() - Unable to change the screen settings.";

    switch( result )
    {
        case DISP_CHANGE_BADMODE     : msg += " The specified graphics mode is not supported."; break;
        case DISP_CHANGE_FAILED      : msg += " The display driver failed the specified graphics mode."; break;
        case DISP_CHANGE_RESTART     : msg += " The computer must be restarted for the graphics mode to work."; break;
        default : break;
    }

    reportErrorForScreen(msg, si, result);
    return false;
}

bool Win32WindowingSystem::setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution )
{
    DISPLAY_DEVICE displayDevice;
    DEVMODE        deviceMode;

    if (!getScreenInformation(si, displayDevice, deviceMode)) return false;

    deviceMode.dmFields = 0;
    // Set resolution
    if (resolution.width>0 && resolution.height>0) {
        deviceMode.dmFields    |= DM_PELSWIDTH | DM_PELSHEIGHT;
        deviceMode.dmPelsWidth  = static_cast<DWORD>(resolution.width);
        deviceMode.dmPelsHeight = static_cast<DWORD>(resolution.height);
    }
    // Set refersh rate
    if (resolution.refreshRate>0) {
        deviceMode.dmFields           |= DM_DISPLAYFREQUENCY;
        deviceMode.dmDisplayFrequency  = static_cast<DWORD>(resolution.refreshRate);
    }
    // Set bits per pixel for color buffer
    if (resolution.colorDepth>0) {
        deviceMode.dmFields     |= DM_BITSPERPEL;
        deviceMode.dmBitsPerPel  = static_cast<DWORD>(resolution.colorDepth);
    }

    return changeScreenSettings(si, displayDevice, deviceMode);
}

void Win32WindowingSystem::enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettingsList & resolutionList) {
    resolutionList.clear();

    if (si.displayNum>0)
    {
        OSG_WARN << "Win32WindowingSystem::enumerateScreenSettings() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl;
        return;
    }

    DisplayDevices displayDevices;
    enumerateDisplayDevices(displayDevices);

    if (si.screenNum>=static_cast<int>(displayDevices.size()))
    {
        OSG_WARN << "Win32WindowingSystem::enumerateScreenSettings() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl;
        return;
    }

    DISPLAY_DEVICE displayDevice = displayDevices[si.screenNum];

    // Do the enumeration
    DEVMODE deviceMode;
    static const unsigned int MAX_RESOLUTIONS = 4046;        // Upper limit to avoid infinite (= very long) loop.
    for (unsigned int i=0; i<MAX_RESOLUTIONS; ++i)
    {
        if (!::EnumDisplaySettings(displayDevice.DeviceName, i, &deviceMode))
            break;
        deviceMode.dmSize        = sizeof(deviceMode);
        deviceMode.dmDriverExtra = 0;
        resolutionList.push_back(osg::GraphicsContext::ScreenSettings(deviceMode.dmPelsWidth, deviceMode.dmPelsHeight, deviceMode.dmDisplayFrequency, deviceMode.dmBitsPerPel));
    }
}

void Win32WindowingSystem::getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height )
{
    DISPLAY_DEVICE displayDevice;
    DEVMODE        deviceMode;

    if (getScreenInformation(si, displayDevice, deviceMode))
    {
        originX = deviceMode.dmPosition.x;
        originY = deviceMode.dmPosition.y;
        width   = deviceMode.dmPelsWidth;
        height  = deviceMode.dmPelsHeight;
    }
    else
    {
        originX = 0;
        originY = 0;
        width   = 0;
        height  = 0;
    }
}

osg::GraphicsContext* Win32WindowingSystem::createGraphicsContext( osg::GraphicsContext::Traits* traits )
{
    if (traits->pbuffer)
    {
        osg::ref_ptr<osgViewer::PixelBufferWin32> pbuffer = new PixelBufferWin32(traits);
        if (pbuffer->valid()) return pbuffer.release();
        else return 0;
    }
    else
    {
        registerWindowClasses();

        osg::ref_ptr<osgViewer::GraphicsWindowWin32> window = new GraphicsWindowWin32(traits);
        if (window->valid()) return window.release();
        else return 0;
    }
}

void Win32WindowingSystem::registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window )
{
    if (hwnd) _activeWindows.insert(WindowHandleEntry(hwnd, window));
}

//
// Unregister a window
// This is called as part of a window being torn down
//

void Win32WindowingSystem::unregisterWindow( HWND hwnd )
{
    if (hwnd) _activeWindows.erase(hwnd);
}

//
// Get the application window object associated with a native window
//

osgViewer::GraphicsWindowWin32* Win32WindowingSystem::getGraphicsWindowFor( HWND hwnd )
{
    WindowHandles::const_iterator entry = _activeWindows.find(hwnd);
    return entry==_activeWindows.end() ? 0 : entry->second;
}

//////////////////////////////////////////////////////////////////////////////
//                    GraphicsWindowWin32 implementation
//////////////////////////////////////////////////////////////////////////////

GraphicsWindowWin32::GraphicsWindowWin32( osg::GraphicsContext::Traits* traits )
: _currentCursor(0),
  _windowProcedure(0),
  _timeOfLastCheckEvents(-1.0),
  _screenOriginX(0),
  _screenOriginY(0),
  _screenWidth(0),
  _screenHeight(0),
  _windowOriginXToRealize(0),
  _windowOriginYToRealize(0),
  _windowWidthToRealize(0),
  _windowHeightToRealize(0),
  _initialized(false),
  _valid(false),
  _realized(false),
  _ownsWindow(true),
  _closeWindow(false),
  _destroyWindow(false),
  _destroying(false),
  _mouseCursor(InheritCursor),
  _appMouseCursor(LeftArrowCursor),
  _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues( false )
{
    _traits = traits;
    if (_traits->useCursor) setCursor(LeftArrowCursor);
    else setCursor(NoCursor);

    init();

    if (valid())
    {
        setState( new osg::State );
        getState()->setGraphicsContext(this);

        if (_traits.valid() && _traits->sharedContext.valid())
        {
            getState()->setContextID( _traits->sharedContext->getState()->getContextID() );
            incrementContextIDUsageCount( getState()->getContextID() );
        }
        else
        {
            getState()->setContextID( osg::GraphicsContext::createNewContextID() );
        }
    }
}

GraphicsWindowWin32::~GraphicsWindowWin32()
{
    close();
    destroyWindow();
}

void GraphicsWindowWin32::init()
{
    if (_initialized) return;

    // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get());

    WindowData *windowData = _traits.valid() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
    HWND windowHandle = windowData ? windowData->_hwnd : 0;

    _ownsWindow    = windowHandle==0;
    _closeWindow   = false;
    _destroyWindow = false;
    _destroying    = false;

    _initialized = _ownsWindow ? createWindow() : setWindow(windowHandle);
    _valid       = _initialized;

    int windowX = 0, windowY = 0, windowWidth = 0, windowHeight = 0;
    if (_traits.valid())
    {
        windowX = _traits->x;
        windowY = _traits->y;
        windowWidth = _traits->width;
        windowHeight = _traits->height;
    }

    if (areWindowDimensionsChanged(_hwnd, _screenOriginX, _screenOriginY, windowX, windowY, windowWidth, windowHeight))
    {
        resized(windowX, windowY, windowWidth, windowHeight);
    }

    // make sure the event queue has the correct window rectangle size and input range
    getEventQueue()->syncWindowRectangleWithGraphicsContext();

    // 2008/10/03
    // Few days ago NVidia released WHQL certified drivers ver 178.13.
    // These drivers (as well as former beta ver 177.92) were free from the bug described below.
    // So it looks like its high time to make the workaround inactive by default.
    // If you happen to still use earlier drivers and have problems consider changing to new ones or
    // activate OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND macro def through CMake advanced vars.
#ifdef OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND

    // 2008/05/12
    // Workaround for Bugs in NVidia drivers for windows XP / multithreaded / dualview / multicore CPU
    // affects GeForce 6x00, 7x00, 8x00 boards (others were not tested) driver versions 174.xx - 175.xx
    // pre 174.xx had other issues so reverting is not an option (statitistics, fbo)
    // drivers release 175.16 is the latest currently available
    //
    // When using OpenGL in threaded app ( main thread sets up context / renderer thread draws using it )
    // first wglMakeCurrent seems to not work right and screw OpenGL context driver data:
    // 1: successive drawing shows a number of artifacts in TriangleStrips and TriangleFans
    // 2: weird behaviour of FramBufferObjects (glGenFramebuffer generates already generated ids ...)
    // Looks like repeating wglMakeCurrent call fixes all these issues
    // wglMakeCurrent call can impact performance so I try to minimize number of
    // wglMakeCurrent calls by checking current HDC and GL context
    // and repeat wglMakeCurrent only when they change for current thread

    _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues = true;
#endif

    std::string str;
    if (osg::getEnvVar("OSG_WIN32_NV_MULTIMON_MULTITHREAD_WORKAROUND", str))
    {
        _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues = (str=="on") || (str=="ON") || (str=="On");
    }
}

bool GraphicsWindowWin32::createWindow()
{
    unsigned int extendedStyle;
    unsigned int windowStyle;

    if (!determineWindowPositionAndStyle(_traits->screenNum,
                                         _traits->x,
                                         _traits->y,
                                         _traits->width,
                                         _traits->height,
                                         _traits->windowDecoration,
                                         _windowOriginXToRealize,
                                         _windowOriginYToRealize,
                                         _windowWidthToRealize,
                                         _windowHeightToRealize,
                                         windowStyle,
                                         extendedStyle))
    {
        reportError("GraphicsWindowWin32::createWindow() - Unable to determine the window position and style");
        return false;
    }

    _hwnd = ::CreateWindowEx(extendedStyle,
                             _traits->useCursor ? Win32WindowingSystem::osgGraphicsWindowWithCursorClass.c_str() :
                                                  Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass.c_str(),
                             _traits->windowName.c_str(),
                             windowStyle,
                             _windowOriginXToRealize,
                             _windowOriginYToRealize,
                             _windowWidthToRealize,
                             _windowHeightToRealize,
                             NULL,
                             NULL,
                             ::GetModuleHandle(NULL),
                             NULL);
    if (_hwnd==0)
    {
        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create window", _traits->screenNum, ::GetLastError());
        return false;
    }

    _hdc = ::GetDC(_hwnd);
    if (_hdc==0)
    {
        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError());
        destroyWindow();
        _hwnd = 0;
        return false;
    }

    //
    // Set the pixel format according to traits specified
    //

    if (!setPixelFormat())
    {
        ::ReleaseDC(_hwnd, _hdc);
        _hdc  = 0;
        destroyWindow();
        return false;
    }

    //
    // Create the OpenGL rendering context associated with this window
    //

    _hglrc = createContextImplementation();
    if (_hglrc==0)
    {
        reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError());
        ::ReleaseDC(_hwnd, _hdc);
        _hdc  = 0;
        destroyWindow();
        return false;
    }

    Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);

    if (registerTouchWindowFunc)
        (*registerTouchWindowFunc)( _hwnd, 0);
    return true;
}

bool GraphicsWindowWin32::setWindow( HWND handle )
{
    if (_initialized)
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Window already created; it cannot be changed", _traits->screenNum, ::GetLastError());
        return false;
    }

    if (handle==0)
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Invalid window handle passed", _traits->screenNum, ::GetLastError());
        return false;
    }

    _hwnd = handle;
    if (_hwnd==0)
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to retrieve native window handle", _traits->screenNum, ::GetLastError());
        return false;
    }

    _hdc = ::GetDC(_hwnd);
    if (_hdc==0)
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError());
        _hwnd = 0;
        return false;
    }

    //
    // Check if we must set the pixel format of the inherited window
    //

    if (!setPixelFormat())
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to set the inherited window pixel format", _traits->screenNum, ::GetLastError());
        ::ReleaseDC(_hwnd, _hdc);
        _hdc  = 0;
        _hwnd = 0;
        return false;
    }

    _hglrc = createContextImplementation();
    if (_hglrc==0)
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError());
        ::ReleaseDC(_hwnd, _hdc);
        _hdc  = 0;
        _hwnd = 0;
        return false;
    }

    WindowData *windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;

    if (!windowData || windowData->_installEventHandler)
    {
        if (!registerWindowProcedure())
        {
            ::wglDeleteContext(_hglrc);
            _hglrc = 0;
            ::ReleaseDC(_hwnd, _hdc);
            _hdc  = 0;
            _hwnd = 0;
            return false;
        }
    }

    Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);

    _initialized = true;
    _valid       = true;

    return true;
}

void GraphicsWindowWin32::destroyWindow( bool deleteNativeWindow )
{
    if (_destroying) return;
    _destroying = true;

    if (_graphicsThread && _graphicsThread->isRunning())
    {
        // find all the viewers that might own use this graphics context
        osg::GraphicsContext::Cameras cameras = getCameras();
        for(osg::GraphicsContext::Cameras::iterator it=cameras.begin(); it!=cameras.end(); ++it)
        {
            osgViewer::View* view = dynamic_cast<osgViewer::View*>((*it)->getView());
            osgViewer::ViewerBase* viewerBase = view ? view->getViewerBase() : 0;
            if (viewerBase && viewerBase->areThreadsRunning())
            {
                viewerBase->stopThreading();
            }
        }
    }

    if (_hdc)
    {
        releaseContext();

        if (_hglrc)
        {
            ::wglDeleteContext(_hglrc);
            _hglrc = 0;
        }

        ::ReleaseDC(_hwnd, _hdc);
        _hdc = 0;
    }

    (void)unregisterWindowProcedure();

    if (_hwnd)
    {
        Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd);
        if (_ownsWindow && deleteNativeWindow) ::DestroyWindow(_hwnd);
        _hwnd = 0;
    }

    _initialized = false;
    _realized    = false;
    _valid       = false;
    _destroying  = false;
}

void GraphicsWindowWin32::registerWindow()
{
  Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
}

void GraphicsWindowWin32::unregisterWindow()
{
  Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd);
}

bool GraphicsWindowWin32::registerWindowProcedure()
{
    ::SetLastError(0);
    _windowProcedure = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(WindowProc));
    unsigned int error = ::GetLastError();

    if (_windowProcedure==0 && error)
    {
        reportErrorForScreen("GraphicsWindowWin32::registerWindowProcedure() - Unable to register window procedure", _traits->screenNum, error);
        return false;
    }

    return true;
}

bool GraphicsWindowWin32::unregisterWindowProcedure()
{
    if (_windowProcedure==0 || _hwnd==0) return true;

    ::SetLastError(0);
    WNDPROC wndProc = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(_windowProcedure));
    unsigned int error = ::GetLastError();

    if (wndProc==0 && error)
    {
        reportErrorForScreen("GraphicsWindowWin32::unregisterWindowProcedure() - Unable to unregister window procedure", _traits->screenNum, error);
        return false;
    }

    _windowProcedure = 0;

    return true;
}

bool GraphicsWindowWin32::determineWindowPositionAndStyle( unsigned int  screenNum,
                                                           int           clientAreaX,
                                                           int           clientAreaY,
                                                           unsigned int  clientAreaWidth,
                                                           unsigned int  clientAreaHeight,
                                                           bool          decorated,
                                                           int&          x,
                                                           int&          y,
                                                           unsigned int& w,
                                                           unsigned int& h,
                                                           unsigned int& style,
                                                           unsigned int& extendedStyle )
{
    if (_traits==0) return false;

    //
    // Query the screen position and size
    //

    osg::GraphicsContext::ScreenIdentifier screenId(screenNum);
    osg::ref_ptr<Win32WindowingSystem> windowManager = Win32WindowingSystem::getInterface();

    windowManager->getScreenPosition(screenId, _screenOriginX, _screenOriginY, _screenWidth, _screenHeight);
    if (_screenWidth==0 || _screenHeight==0) return false;

    x = clientAreaX + _screenOriginX;
    y = clientAreaY + _screenOriginY;
    w = clientAreaWidth;
    h = clientAreaHeight;

    style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

    extendedStyle = 0;

    if (decorated)
    {
        style |= WS_CAPTION     |
                 WS_SYSMENU     |
                 WS_MINIMIZEBOX |
                 WS_MAXIMIZEBOX;

        if (_traits->supportsResize) style |= WS_SIZEBOX;

        extendedStyle = WS_EX_APPWINDOW           |
                        WS_EX_OVERLAPPEDWINDOW |
                        WS_EX_ACCEPTFILES      |
                        WS_EX_LTRREADING;

        RECT corners;

        corners.left   = x;
        corners.top    = y;
        corners.right  = x + w - 1;
        corners.bottom = y + h - 1;

        //
        // Determine the location of the window corners in order to have
        // a client area of the requested size
        //

        if (!::AdjustWindowRectEx(&corners, style, FALSE, extendedStyle))
        {
            reportErrorForScreen("GraphicsWindowWin32::determineWindowPositionAndStyle() - Unable to adjust window rectangle", _traits->screenNum, ::GetLastError());
            return false;
        }

        x = corners.left;
        y = corners.top;
        w = corners.right  - corners.left + 1;
        h = corners.bottom - corners.top  + 1;
    }

    return true;
}

static void PreparePixelFormatSpecifications( const osg::GraphicsContext::Traits& traits,
                                              WGLIntegerAttributes&               attributes,
                                              bool                                allowSwapExchangeARB )
{
    attributes.begin();

    attributes.enable(WGL_DRAW_TO_WINDOW_ARB);
    attributes.enable(WGL_SUPPORT_OPENGL_ARB);

    attributes.set(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
    attributes.set(WGL_PIXEL_TYPE_ARB,   WGL_TYPE_RGBA_ARB);

    attributes.set(WGL_COLOR_BITS_ARB,   traits.red + traits.green + traits.blue);
    attributes.set(WGL_RED_BITS_ARB,     traits.red);
    attributes.set(WGL_GREEN_BITS_ARB,   traits.green);
    attributes.set(WGL_BLUE_BITS_ARB,    traits.blue);
    attributes.set(WGL_DEPTH_BITS_ARB,   traits.depth);

    if (traits.doubleBuffer)
    {
        attributes.enable(WGL_DOUBLE_BUFFER_ARB);

        switch ( traits.swapMethod )
        {
            case osg::DisplaySettings::SWAP_COPY:
                attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_COPY_ARB);
                break;
            case osg::DisplaySettings::SWAP_EXCHANGE:
                attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
                break;
            case osg::DisplaySettings::SWAP_UNDEFINED:
                attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_UNDEFINED_ARB);
                break;
            case osg::DisplaySettings::SWAP_DEFAULT:
                // Wojtek Lewandowski 2010-09-28:
                // Keep backward compatibility if no method is selected via traits
                // and let wglSwapExchangeARB flag select swap method.
                // However, I would rather remove this flag because its
                // now redundant to Traits::swapMethod and it looks like
                // WGL_SWAP_EXCHANGE_ARB is the GL default when no WGL_SWAP attrib is given.
                // To be precise: At least on Windows 7 and Nvidia it seems to be a default.
                if ( allowSwapExchangeARB )
                    attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
                break;
        }
    }

    if (traits.alpha)         attributes.set(WGL_ALPHA_BITS_ARB,     traits.alpha);
    if (traits.stencil)       attributes.set(WGL_STENCIL_BITS_ARB,   traits.stencil);
    if (traits.sampleBuffers) attributes.set(WGL_SAMPLE_BUFFERS_ARB, traits.sampleBuffers);
    if (traits.samples)       attributes.set(WGL_SAMPLES_ARB,        traits.samples);

    if (traits.quadBufferStereo) attributes.enable(WGL_STEREO_ARB);

    attributes.end();
}

static int ChooseMatchingPixelFormat( HDC hdc, int screenNum, const WGLIntegerAttributes& formatSpecifications ,osg::GraphicsContext::Traits* _traits)
{
    //
    // Access the entry point for the wglChoosePixelFormatARB function
    //

    WGLChoosePixelFormatARB wglChoosePixelFormatARB = (WGLChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB");
    if (wglChoosePixelFormatARB==0)
    {
        // = openGLContext.getTraits()
        reportErrorForScreen("ChooseMatchingPixelFormat() - wglChoosePixelFormatARB extension not found, trying GDI", screenNum, ::GetLastError());
        PIXELFORMATDESCRIPTOR pixelFormat = {
            sizeof(PIXELFORMATDESCRIPTOR),  //  size of this pfd
            1,                     // version number
            PFD_DRAW_TO_WINDOW |   // support window
            PFD_SUPPORT_OPENGL |   // support OpenGL
            DWORD(_traits->doubleBuffer ? PFD_DOUBLEBUFFER : 0) |      // double buffered ?
            DWORD(_traits->swapMethod ==  osg::DisplaySettings::SWAP_COPY ? PFD_SWAP_COPY : 0) |
            DWORD(_traits->swapMethod ==  osg::DisplaySettings::SWAP_EXCHANGE ? PFD_SWAP_EXCHANGE : 0),
            PFD_TYPE_RGBA,         // RGBA type
            BYTE(_traits->red + _traits->green + _traits->blue),                      // color depth
            BYTE(_traits->red), 0, BYTE(_traits->green), 0, BYTE(_traits->blue), 0,   // shift bits ignored
            BYTE(_traits->alpha),  // alpha buffer ?
            0,                     // shift bit ignored
            0,                     // no accumulation buffer
            0, 0, 0, 0,            // accum bits ignored
            BYTE(_traits->depth),      // 32 or 16 bit z-buffer ?
            BYTE(_traits->stencil),    // stencil buffer ?
            0,                     // no auxiliary buffer
            PFD_MAIN_PLANE,  // main layer
            0,                     // reserved
            0, 0, 0                // layer masks ignored
        };
        int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat);
        if (pixelFormatIndex == 0)
        {
            reportErrorForScreen("ChooseMatchingPixelFormat() - GDI ChoosePixelFormat Failed.", screenNum, ::GetLastError());
            return -1;
        }

        ::DescribePixelFormat(hdc, pixelFormatIndex ,sizeof(PIXELFORMATDESCRIPTOR),&pixelFormat);
        if (((pixelFormat.dwFlags & PFD_GENERIC_FORMAT) != 0)  && ((pixelFormat.dwFlags & PFD_GENERIC_ACCELERATED) == 0))
        {
            OSG_WARN << "Rendering in software: pixelFormatIndex " << pixelFormatIndex << std::endl;
        }
        return pixelFormatIndex;
    }

    int pixelFormatIndex = 0;
    unsigned int numMatchingPixelFormats = 0;

    if (!wglChoosePixelFormatARB(hdc,
                                 formatSpecifications.get(),
                                 NULL,
                                 1,
                                 &pixelFormatIndex,
                                 &numMatchingPixelFormats))
    {
        reportErrorForScreen("ChooseMatchingPixelFormat() - Unable to choose the requested pixel format", screenNum, ::GetLastError());
        return -1;
    }

    return numMatchingPixelFormats==0 ? -1 : pixelFormatIndex;
}

bool GraphicsWindowWin32::setPixelFormat()
{
    Win32WindowingSystem::OpenGLContext openGLContext;
    if (!Win32WindowingSystem::getInterface()->getSampleOpenGLContext(openGLContext, _hdc, _screenOriginX, _screenOriginY)) return false;

    //
    // Build the specifications of the requested pixel format
    //

    WGLIntegerAttributes formatSpecs;
    ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);

    //
    // Choose the closest matching pixel format from the specified traits
    //

    int pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());

    if (pixelFormatIndex<0)
    {
            unsigned int bpp;
            Win32WindowingSystem::getInterface()->getScreenColorDepth(*_traits.get(), bpp);
            if (bpp < 32) {
                OSG_INFO    << "GraphicsWindowWin32::setPixelFormat() - Display setting is not 32 bit colors, "
                                        << bpp
                                        << " bits per pixel on screen #"
                                        << _traits->screenNum
                                        << std::endl;

                _traits->red = bpp / 4; //integer divide, determine minimum number of bits we will accept
                _traits->green = bpp / 4;
                _traits->blue = bpp / 4;
                ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);// try again with WGL_SWAP_METHOD_ARB
                pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
            }
    }
    if (pixelFormatIndex<0)
    {
        ::PreparePixelFormatSpecifications(*_traits, formatSpecs, false);
        pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
        if (pixelFormatIndex<0)
        {
            reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - No matching pixel format found based on traits specified", _traits->screenNum, 0);
            return false;
        }

        OSG_INFO << "GraphicsWindowWin32::setPixelFormat() - Found a matching pixel format but without the WGL_SWAP_METHOD_ARB specification for screen #"
                               << _traits->screenNum
                               << std::endl;
    }

    //
    // Set the pixel format found
    //

    PIXELFORMATDESCRIPTOR pfd;
    ::memset(&pfd, 0, sizeof(pfd));
    pfd.nSize    = sizeof(PIXELFORMATDESCRIPTOR);
    pfd.nVersion = 1;

    if (!::SetPixelFormat(_hdc, pixelFormatIndex, &pfd))
    {
        reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - Unable to set pixel format", _traits->screenNum, ::GetLastError());
        return false;
    }

    return true;
}

HGLRC GraphicsWindowWin32::createContextImplementation()
{
    HGLRC context( NULL );

    if( OSG_GL3_FEATURES )
    {
        OSG_NOTIFY( osg::INFO ) << "GL3: Attempting to create OpenGL3 context." << std::endl;
        OSG_NOTIFY( osg::INFO ) << "GL3: version: " << _traits->glContextVersion << std::endl;
        OSG_NOTIFY( osg::INFO ) << "GL3: context flags: " << _traits->glContextFlags << std::endl;
        OSG_NOTIFY( osg::INFO ) << "GL3: profile: " << _traits->glContextProfileMask << std::endl;

        Win32WindowingSystem::OpenGLContext openGLContext;
        if( !Win32WindowingSystem::getInterface()->getSampleOpenGLContext( openGLContext, _hdc, _screenOriginX, _screenOriginY ) )
        {
            reportErrorForScreen( "GL3: Can't create sample context.",
                _traits->screenNum, ::GetLastError() );
        }
        else
        {
            PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB =
                ( PFNWGLCREATECONTEXTATTRIBSARBPROC ) wglGetProcAddress( "wglCreateContextAttribsARB" );
            if( wglCreateContextAttribsARB==0 )
            {
                reportErrorForScreen( "GL3: wglCreateContextAttribsARB not available.",
                    _traits->screenNum, ::GetLastError() );
            }
            else
            {
                unsigned int idx( 0 );
                int attribs[ 16 ];

                unsigned int major = 1, minor = 0;
                if( !_traits->getContextVersion(major, minor) || major<3 )
                {
                    OSG_NOTIFY( osg::WARN ) << "GL3: Non-GL3 version number: " << _traits->glContextVersion << std::endl;
                }

                attribs[ idx++ ] = WGL_CONTEXT_MAJOR_VERSION_ARB;
                attribs[ idx++ ] = major;
                attribs[ idx++ ] = WGL_CONTEXT_MINOR_VERSION_ARB;
                attribs[ idx++ ] = minor;
                if( _traits->glContextFlags != 0 )
                {
                    attribs[ idx++ ] = WGL_CONTEXT_FLAGS_ARB;
                    attribs[ idx++ ] = _traits->glContextFlags;
                }
                if( _traits->glContextProfileMask != 0 )
                {
                    attribs[ idx++ ] = WGL_CONTEXT_PROFILE_MASK_ARB;
                    attribs[ idx++ ] = _traits->glContextProfileMask;
                }
                attribs[ idx++ ] = 0;

                context = wglCreateContextAttribsARB( _hdc, 0, attribs );
                if( context == NULL )
                {
                    reportErrorForScreen( "GL3: wglCreateContextAttribsARB returned NULL.",
                        _traits->screenNum, ::GetLastError() );
                }
                else
                {
                    OSG_NOTIFY( osg::INFO ) << "GL3: context created successfully." << std::endl;
                }
            }
        }
    }

    // TBD insert GL ES 2 suppurt, if required for Win32.

    // If platform context creation fails for any reason,
    // we'll create a standard context. This means you could
    // build OSG for GL3, have the context creation fail
    // (because you have the wrong driver), and end up with
    // a GL3 context. Something else will likely fail down
    // the line, as the GL3-built OSG will assume GL3 features
    // are present.
    //
    // This is also the typical path for GL 1/2 context creation.
    if( context == NULL )
        context = ::wglCreateContext(_hdc);

    return( context );
}

bool GraphicsWindowWin32::setWindowDecorationImplementation( bool decorated )
{
    unsigned int windowStyle;
    unsigned int extendedStyle;

    //
    // Determine position and size of window with/without decorations to retain the size specified in traits
    //

    int x, y;
    unsigned int w, h;

    if (!determineWindowPositionAndStyle(_traits->screenNum,
                                 _traits->x,
                     _traits->y,
                     _traits->width,
                     _traits->height,
                     decorated,
                     x,
                     y,
                     w,
                     h,
                     windowStyle,
                     extendedStyle))
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to determine the window position and style", _traits->screenNum, 0);
        return false;
    }

    //
    // Change the window style
    //

    ::SetLastError(0);
    unsigned int result = ::SetWindowLong(_hwnd, GWL_STYLE, windowStyle);
    unsigned int error  = ::GetLastError();
    if (result==0 && error)
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window style", _traits->screenNum, error);
        return false;
    }

    //
    // Change the window extended style
    //

    ::SetLastError(0);
    result = ::SetWindowLong(_hwnd, GWL_EXSTYLE, extendedStyle);
    error  = ::GetLastError();
    if (result==0 && error)
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window extented style", _traits->screenNum, error);
        return false;
    }

    //
    // Change the window position and size and realize the style changes
    //

    if (!::SetWindowPos(_hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_SHOWWINDOW))
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set new window position and size", _traits->screenNum, ::GetLastError());
        return false;
    }

    //
    // Force a repaint of the desktop
    //

    ::InvalidateRect(NULL, NULL, TRUE);

    return true;
}

bool GraphicsWindowWin32::realizeImplementation()
{
    if (_realized) return true;

    if (!_initialized)
    {
        init();
        if (!_initialized) return false;
    }

    if (_traits.valid() && (_traits->sharedContext.valid() || _traits->vsync || _traits->swapGroupEnabled))
    {
        // make context current so we can test capabilities and set up context sharing
        struct RestoreContext
        {
            RestoreContext()
            {
                _hdc = wglGetCurrentDC();
                _hglrc = wglGetCurrentContext();
            }
            ~RestoreContext()
            {
                wglMakeCurrent(_hdc,_hglrc);
            }
        protected:
            HDC      _hdc;
            HGLRC    _hglrc;
        } restoreContext;

        _realized = true;
        bool result = makeCurrent();
        _realized = false;

        if (!result)
        {
            return false;
        }

        // set up sharing of contexts if required
        GraphicsHandleWin32* graphicsHandleWin32 = dynamic_cast<GraphicsHandleWin32*>(_traits->sharedContext.get());
        if (graphicsHandleWin32)
        {
            if (!wglShareLists(graphicsHandleWin32->getWGLContext(), getWGLContext()))
            {
                reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to share OpenGL context", _traits->screenNum, ::GetLastError());
                return false;
            }
        }

        // if vysnc should be on then enable it.
        if (_traits->vsync)
        {
            setSyncToVBlank(_traits->vsync);
        }

        // If the swap group is active then enable it.
        if (_traits->swapGroupEnabled)
        {
            setSwapGroup(_traits->swapGroupEnabled, _traits->swapGroup, _traits->swapBarrier);
        }
    }

    if (_ownsWindow)
    {
        //
        // Bring the window on top of other ones (including the taskbar if it covers it completely)
        //
        // NOTE: To cover the taskbar with a window that does not completely cover it, the HWND_TOPMOST
        // Z-order must be used in the code below instead of HWND_TOP.
        // @todo: This should be controlled through a flag in the traits (topMostWindow)
        //

        if (!::SetWindowPos(_hwnd,
                            HWND_TOP,
                            _windowOriginXToRealize,
                            _windowOriginYToRealize,
                            _windowWidthToRealize,
                            _windowHeightToRealize,
                            SWP_SHOWWINDOW))
        {
            reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to show window", _traits->screenNum, ::GetLastError());
            return false;
        }

        if (!::UpdateWindow(_hwnd))
        {
            reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to update window", _traits->screenNum, ::GetLastError());
            return false;
        }
    }

    _realized = true;

    // make sure the event queue has the correct window rectangle size and input range
    getEventQueue()->syncWindowRectangleWithGraphicsContext();

    return true;
}

bool GraphicsWindowWin32::makeCurrentImplementation()
{
    if (!_realized)
    {
        reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Window not realized; cannot do makeCurrent.", _traits->screenNum, 0);
        return false;
    }

    if( _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues )
    {
        if( ::wglGetCurrentDC() != _hdc ||
            ::wglGetCurrentContext() != _hglrc )
        {
            if (!::wglMakeCurrent(_hdc, _hglrc))
            {
                reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError());
                return false;
            }
        }
    }

    if (!::wglMakeCurrent(_hdc, _hglrc))
    {
        reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError());
        return false;
    }

    return true;
}

bool GraphicsWindowWin32::releaseContextImplementation()
{
    if (!::wglMakeCurrent(_hdc, NULL))
    {
        reportErrorForScreen("GraphicsWindowWin32::releaseContextImplementation() - Unable to release current OpenGL rendering context", _traits->screenNum, ::GetLastError());
        return false;
    }

    return true;
}

void GraphicsWindowWin32::closeImplementation()
{
    destroyWindow();

    _initialized = false;
    _valid       = false;
    _realized    = false;
}

void GraphicsWindowWin32::swapBuffersImplementation()
{
    if (!_realized) return;
    if (!::SwapBuffers(_hdc) && ::GetLastError() != 0)
    {
        reportErrorForScreen("GraphicsWindowWin32::swapBuffersImplementation() - Unable to swap display buffers", _traits->screenNum, ::GetLastError());
    }
}

bool GraphicsWindowWin32::checkEvents()
{
    if (!_realized) return false;

    MSG msg;
    while (::PeekMessage(&msg, _hwnd, 0, 0, PM_REMOVE))
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }

    if (_closeWindow)
    {
        _closeWindow = false;
        close();
    }

    if (_destroyWindow)
    {
        _destroyWindow = false;
        destroyWindow(false);
    }

    return !(getEventQueue()->empty());
}

void GraphicsWindowWin32::grabFocus()
{
    if (!::SetForegroundWindow(_hwnd))
    {
        OSG_WARN << "Warning: GraphicsWindowWin32::grabFocus() - Failed grabbing the focus" << std::endl;
    }
}

void GraphicsWindowWin32::grabFocusIfPointerInWindow()
{
    POINT mousePos;
    if (!::GetCursorPos(&mousePos))
    {
        reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get cursor position", _traits->screenNum, ::GetLastError());
        return;
    }

    RECT windowRect;
    if (!::GetWindowRect(_hwnd, &windowRect))
    {
        reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get window position", _traits->screenNum, ::GetLastError());
        return;
    }

    if (mousePos.x>=windowRect.left && mousePos.x<=windowRect.right &&
        mousePos.y>=windowRect.top  && mousePos.y<=windowRect.bottom)
    {
        grabFocus();
    }
}

void GraphicsWindowWin32::requestWarpPointer( float x, float y )
{
    if (!_realized)
    {
        OSG_INFO<<"GraphicsWindowWin32::requestWarpPointer() - Window not realized; cannot warp pointer, screenNum="<< _traits->screenNum<<std::endl;
        return;
    }

#if 0
    RECT windowRect;
    if (!::GetWindowRect(_hwnd, &windowRect))
    {
        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to get window rectangle", _traits->screenNum, ::GetLastError());
        return;
    }

    if (!::SetCursorPos(windowRect.left + x, windowRect.top + y))
    {
        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError());
        return;
    }
#else
    // MIKEC: NEW CODE
    POINT pt;
    pt.x = (LONG)x;
    pt.y = (LONG)y;

    // convert point in client area coordinates to screen coordinates
    if (!::ClientToScreen(_hwnd, &pt))
    {
        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to convert cursor position to screen coordinates", _traits->screenNum, ::GetLastError());
    }
    if (!::SetCursorPos(pt.x, pt.y))
    {
        reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError());
        return;
    }
#endif

    getEventQueue()->mouseWarped(x,y);
}

bool GraphicsWindowWin32::setWindowRectangleImplementation(int x, int y, int width, int height)
{
    unsigned int windowStyle;
    unsigned int extendedStyle;

    //
    // Determine position and size of window with/without decorations to retain the size specified in traits
    //

    int wx, wy;
    unsigned int ww, wh;

    if (!determineWindowPositionAndStyle(_traits->screenNum,
                                         x,
                                         y,
                                         width,
                                         height,
                                         _traits->windowDecoration,
                                         wx,
                                         wy,
                                         ww,
                                         wh,
                                         windowStyle,
                                         extendedStyle))
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindowRectangleImplementation() - Unable to determine the window position and style", _traits->screenNum, 0);
        return false;
    }

    if (!::SetWindowPos(_hwnd, HWND_TOP, wx, wy, ww, wh, SWP_SHOWWINDOW | SWP_FRAMECHANGED))
    {
        reportErrorForScreen("GraphicsWindowWin32::setWindowRectangleImplementation() - Unable to set new window position and size", _traits->screenNum, ::GetLastError());
        return false;
    }
    return true;
}

void GraphicsWindowWin32::setWindowName( const std::string & name )
{
    _traits->windowName = name;
    SetWindowText(_hwnd, name.c_str());
}

void GraphicsWindowWin32::useCursor( bool cursorOn )
{
    if (_traits.valid())
        _traits->useCursor = cursorOn;

    // note, we are using setCursorImpl to set the cursor, so we can use
    // _appMouseCursor to cache the current mouse-cursor
    setCursorImpl(cursorOn ? _appMouseCursor : NoCursor);
}

void GraphicsWindowWin32::setCursor( MouseCursor mouseCursor )
{
    _appMouseCursor = mouseCursor;
    setCursorImpl(mouseCursor);
}

void GraphicsWindowWin32::setCursorImpl( MouseCursor mouseCursor )
{
    if (_mouseCursor != mouseCursor)
    {
        _mouseCursor = mouseCursor;
        HCURSOR newCursor = getOrCreateCursor( mouseCursor);
        if (newCursor == _currentCursor) return;

        _currentCursor = newCursor;
        _traits->useCursor = (_currentCursor != NULL) && (_mouseCursor != NoCursor);

        PostMessage(_hwnd, WM_SETCURSOR, 0, 0);
    }
}

HCURSOR GraphicsWindowWin32::getOrCreateCursor(MouseCursor mouseCursor)
{
    std::map<MouseCursor,HCURSOR>::iterator i = _mouseCursorMap.find(mouseCursor);
    if (i != _mouseCursorMap.end()) return i->second;

    switch (mouseCursor) {
    case NoCursor:
        _mouseCursorMap[mouseCursor] = NULL;
    break;
    case RightArrowCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW);
        break;
    case LeftArrowCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW);
        break;
    case InfoCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL);
        break;
    case DestroyCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO );
        break;
    case HelpCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HELP );
        break;
    case CycleCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO );
        break;
    case SprayCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL );
        break;
    case WaitCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_WAIT);
        break;
    case TextCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_IBEAM );
        break;
    case CrosshairCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_CROSS );
        break;
    case UpDownCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENS );
        break;
    case LeftRightCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE );
        break;
    case TopSideCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW );
        break;
    case BottomSideCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW );
        break;
    case LeftSideCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE);
        break;
    case RightSideCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE );
        break;
    case TopLeftCorner:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE );
        break;
    case TopRightCorner:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW );
        break;
    case BottomRightCorner:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE );
        break;
    case BottomLeftCorner:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW );
        break;
    case HandCursor:
        _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HAND );
        break;
    default:
        break;
    }

    return _mouseCursorMap[mouseCursor];
}

void GraphicsWindowWin32::setSwapGroup(bool on, GLuint group, GLuint barrier)
{
    if (_traits.valid())
    {
        _traits->swapGroupEnabled = on;
        _traits->swapGroup        = group;
        _traits->swapBarrier      = barrier;
    }

    typedef BOOL (GL_APIENTRY *PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group);
    PFNWGLJOINSWAPGROUPNVPROC wglJoinSwapGroupNV = (PFNWGLJOINSWAPGROUPNVPROC)wglGetProcAddress( "wglJoinSwapGroupNV" );

    typedef BOOL (GL_APIENTRY *PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier);
    PFNWGLBINDSWAPBARRIERNVPROC wglBindSwapBarrierNV = (PFNWGLBINDSWAPBARRIERNVPROC)wglGetProcAddress( "wglBindSwapBarrierNV" );

    if ((!wglJoinSwapGroupNV) || (!wglBindSwapBarrierNV))
    {
        OSG_INFO << "GraphicsWindowWin32::wglJoinSwapGroupNV(bool, GLuint, GLuint) not supported" << std::endl;
        return;
    }

    int swapGroup = (on ? group : 0);
    BOOL resultJoin = wglJoinSwapGroupNV(_hdc, swapGroup);
    OSG_INFO << "GraphicsWindowWin32::wglJoinSwapGroupNV (" << swapGroup << ") returned " << resultJoin << std::endl;

    int swapBarrier = (on ? barrier : 0);
    BOOL resultBind = wglBindSwapBarrierNV(swapGroup, swapBarrier);
    OSG_INFO << "GraphicsWindowWin32::wglBindSwapBarrierNV (" << swapGroup << ", " << swapBarrier << ") returned " << resultBind << std::endl;
}

void GraphicsWindowWin32::setSyncToVBlank( bool on )
{
    if (_traits.valid())
    {
        _traits->vsync = on;
    }

//#if 0
    // we ought to properly check if the extension is listed as supported rather than just
    // if the function pointer resolves through wglGetProcAddress, but in practice everything
    // supports this extension
    typedef BOOL (GL_APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int );
    PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0;

    wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
    if( wglSwapIntervalEXT )
    {
        int swapInterval = (on ? 1 : 0);
        wglSwapIntervalEXT(swapInterval);
        OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank " << (on ? "on" : "off") << std::endl;
    }
    else
    {
        OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not supported" << std::endl;
    }
//#else
//    OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not yet implemented."<< std::endl;
//#endif
}

void GraphicsWindowWin32::adaptKey( WPARAM wParam, LPARAM lParam, int& keySymbol, unsigned int& modifierMask, int& unmodifiedKeySymbol)
{
    modifierMask = 0;

    bool rightSide = (lParam & 0x01000000)!=0;
    int virtualKey = ::MapVirtualKeyEx((lParam>>16) & 0xff, 3, ::GetKeyboardLayout(0));

    BYTE keyState[256];

    if (virtualKey==0 || !::GetKeyboardState(keyState))
    {
        keySymbol = 0;
        return;
    }

    switch (virtualKey)
    {
        //////////////////
        case VK_LSHIFT   :
        //////////////////

        modifierMask |= osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT;
            break;

        //////////////////
        case VK_RSHIFT   :
        //////////////////

        modifierMask |= osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT;
            break;

        //////////////////
        case VK_CONTROL  :
        case VK_LCONTROL :
        //////////////////

            virtualKey    = rightSide ? VK_RCONTROL : VK_LCONTROL;
            modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL : osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL;
            break;

        //////////////////
        case VK_MENU     :
        case VK_LMENU    :
        //////////////////

            virtualKey    = rightSide ? VK_RMENU : VK_LMENU;
            modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT : osgGA::GUIEventAdapter::MODKEY_LEFT_ALT;
            break;

        //////////////////
        default          :
        //////////////////

            virtualKey = wParam;
            break;
    }

    if (keyState[VK_CAPITAL] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
    if (keyState[VK_NUMLOCK] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK;

    keySymbol = remapWin32Key(virtualKey);

    if (keySymbol==osgGA::GUIEventAdapter::KEY_Return && rightSide)
    {
        keySymbol = osgGA::GUIEventAdapter::KEY_KP_Enter;
    }

    unmodifiedKeySymbol = keySymbol;

    if ((keySymbol & 0xff00)==0)
    {
        char asciiKey[2];
        int numChars = ::ToAscii(wParam, (lParam>>16)&0xff, keyState, reinterpret_cast<WORD*>(asciiKey), 0);
        if (numChars>0) keySymbol = asciiKey[0];
    }
}

void GraphicsWindowWin32::transformMouseXY( float& x, float& y )
{
    if (getEventQueue()->getUseFixedMouseInputRange())
    {
        osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();

        x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
        y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
    }
}

LRESULT GraphicsWindowWin32::handleNativeWindowingEvent( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    //!@todo adapt windows event time to osgGA event queue time for better resolution
    double eventTime  = getEventQueue()->getTime();
    _timeOfLastCheckEvents = eventTime;

    if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH)
    {
        switch(uMsg)
        {
            /////////////////
            case WM_SYSCOMMAND:
            /////////////////
            {
                UINT cmd = LOWORD(wParam);
                if (cmd == SC_CLOSE)
                    getEventQueue()->closeWindow(eventTime);
                break;
            }
            /////////////////
            case WM_NCLBUTTONUP:
            /////////////////
            {
                UINT cmd = LOWORD(wParam);
                if (cmd == HTCLOSE)
                    getEventQueue()->closeWindow(eventTime);
                break;
            }
            default: break;
        }
        return TRUE;
    }

    switch(uMsg)
    {
        // Wojtek Lewandowski 2010-09-28:
        // All web docs on Windows Aero and OpenGL compatibiltiy
        // suggest WM_ERASEBKGND should be handled with non NULL value return.
        // This sugesstion may be irrelevant for our window class
        // as default brush pattern is not set so erase flag is forwarded to WM_PAINT
        // and gets ignored when WM_PAINT is handled.
        // But it will certainly be safer and not make things worse
        // if we handle this message to be sure everything is done as suggested.
        case WM_ERASEBKGND :
            return TRUE;
            break;

        /////////////////
        case WM_PAINT   :
        /////////////////

            if (_ownsWindow)
            {
                PAINTSTRUCT paint;
                ::BeginPaint(hwnd, &paint);
                ::EndPaint(hwnd, &paint);
                requestRedraw();
            }
            break;

        ///////////////////
        case WM_MOUSEMOVE :
        ///////////////////

            {
                float mx = GET_X_LPARAM(lParam);
                float my = GET_Y_LPARAM(lParam);
                transformMouseXY(mx, my);
                getEventQueue()->mouseMotion(mx, my, eventTime);
            }
            break;

        /////////////////////
        case WM_LBUTTONDOWN :
        case WM_MBUTTONDOWN :
        case WM_RBUTTONDOWN :
        /////////////////////

            {
                ::SetCapture(hwnd);

                int button;

                if (uMsg==WM_LBUTTONDOWN)      button = 1;
                else if (uMsg==WM_MBUTTONDOWN) button = 2;
                else button = 3;

                _capturedMouseButtons.insert(button);

                float mx = GET_X_LPARAM(lParam);
                float my = GET_Y_LPARAM(lParam);
                transformMouseXY(mx, my);
                getEventQueue()->mouseButtonPress(mx, my, button, eventTime);
            }
            break;

        /////////////////////
        case WM_LBUTTONUP   :
        case WM_MBUTTONUP   :
        case WM_RBUTTONUP   :
        /////////////////////

            {
                int button;

                if (uMsg==WM_LBUTTONUP)      button = 1;
                else if (uMsg==WM_MBUTTONUP) button = 2;
                else button = 3;

                _capturedMouseButtons.erase(button);

                if(_capturedMouseButtons.empty())
                  ::ReleaseCapture();

                float mx = GET_X_LPARAM(lParam);
                float my = GET_Y_LPARAM(lParam);
                transformMouseXY(mx, my);
                getEventQueue()->mouseButtonRelease(mx, my, button, eventTime);
            }
            break;

        ///////////////////////
        case WM_LBUTTONDBLCLK :
        case WM_MBUTTONDBLCLK :
        case WM_RBUTTONDBLCLK :
        ///////////////////////

            {
                ::SetCapture(hwnd);

                int button;

                if (uMsg==WM_LBUTTONDBLCLK)            button = 1;
                else if (uMsg==WM_MBUTTONDBLCLK)    button = 2;
                else button = 3;

                _capturedMouseButtons.insert(button);

                float mx = GET_X_LPARAM(lParam);
                float my = GET_Y_LPARAM(lParam);
                transformMouseXY(mx, my);
                getEventQueue()->mouseDoubleButtonPress(mx, my, button, eventTime);
            }
            break;

        ////////////////////
        case WM_MOUSEWHEEL :
        ////////////////////

            getEventQueue()->mouseScroll(GET_WHEEL_DELTA_WPARAM(wParam)<0 ? osgGA::GUIEventAdapter::SCROLL_DOWN :
                                                                            osgGA::GUIEventAdapter::SCROLL_UP,
                                         eventTime);
            break;

        /////////////////
        case WM_MOVE    :
        case WM_SIZE    :
        /////////////////

            {
                int windowX=_traits->x, windowY=_traits->y, windowWidth=_traits->width, windowHeight=_traits->height;
                if (areWindowDimensionsChanged(hwnd, _screenOriginX, _screenOriginY, windowX, windowY, windowWidth, windowHeight))
                {
                    resized(windowX, windowY, windowWidth, windowHeight);
                    getEventQueue()->windowResize(windowX, windowY, windowWidth, windowHeight, eventTime);

                    // request redraw if window size was changed
                    if (windowWidth!=_traits->width || windowHeight!=_traits->height)
                        requestRedraw();
                }
            }
            break;

        ////////////////////
        case WM_KEYDOWN    :
        case WM_SYSKEYDOWN :
        ////////////////////

            {
                int keySymbol = 0;
                int unmodifiedKeySymbol = 0;
                unsigned int modifierMask = 0;
                adaptKey(wParam, lParam, keySymbol, modifierMask, unmodifiedKeySymbol);
                _keyMap[std::make_pair(keySymbol,unmodifiedKeySymbol)] = true;
                //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
                getEventQueue()->keyPress(keySymbol, eventTime, unmodifiedKeySymbol);
            }
            break;

        //////////////////
        case WM_KEYUP    :
        case WM_SYSKEYUP :
        //////////////////

            {
                int keySymbol = 0;
                int unmodifiedKeySymbol = 0;
                unsigned int modifierMask = 0;
                adaptKey(wParam, lParam, keySymbol, modifierMask, unmodifiedKeySymbol);
                _keyMap[std::make_pair(keySymbol, unmodifiedKeySymbol)] = false;
                //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
                getEventQueue()->keyRelease(keySymbol, eventTime, unmodifiedKeySymbol);
            }
            break;

        ///////////////////
        case WM_SETCURSOR :
        ///////////////////
            //The cursor is only modified in response to the WM_SETCURSOR message if the mouse cursor isn't set to
            //InheritCursor.  InheritCursor lets the user manage the cursor externally.
            if (_mouseCursor != InheritCursor)
            {
                if (_traits->useCursor)
                    ::SetCursor( _currentCursor);
                else
                    ::SetCursor(NULL);
                return TRUE;
            }
            break;

        ///////////////////
        case WM_SETFOCUS :
        ///////////////////
            // Check keys and send a message if the key is pressed when the
            // focus comes back to the window.
            // I don't really like this hard-coded loop, but the key codes
            // (VK_* constants) seem to go from 0x08 to 0xFE so it should be
            // ok. See winuser.h for the key codes.
            for (unsigned int i = 0x08; i < 0xFF; i++)
            {
                // Wojciech Lewandowski: 2011/09/12
                // Skip CONTROL | MENU | SHIFT tests because we are polling exact left or right keys
                // above return press for both right and left so we may end up with incosistent
                // modifier mask if we report left control & right control while only right was pressed
                LONG rightSideCode = 0;
                switch( i )
                {
                    case VK_CONTROL:
                    case VK_SHIFT:
                    case VK_MENU:
                        continue;

                    case VK_RCONTROL:
                    case VK_RSHIFT:
                    case VK_RMENU:
                        rightSideCode = 0x01000000;
                }
                if ((::GetAsyncKeyState(i) & 0x8000) != 0)
                {
                    // Compute lParam because subsequent adaptKey will rely on correct lParam
                    UINT scanCode = ::MapVirtualKeyEx( i, 0, ::GetKeyboardLayout(0));
                    // Set Extended Key bit + Scan Code + 30 bit to indicate key was set before sending message
                    // See Windows SDK help on WM_KEYDOWN for explanation
                    LONG lParamKey = rightSideCode | ( ( scanCode & 0xFF ) << 16 ) | (1 << 30);
                    ::SendMessage(hwnd, WM_KEYDOWN, i, lParamKey);
                }
            }
            break;

        ///////////////////
        case WM_KILLFOCUS :
        ///////////////////

            // Release all keys that were pressed when the window lost focus.
            for (std::map<std::pair<int, int>, bool>::iterator key = _keyMap.begin();
                 key != _keyMap.end(); ++key)
            {
                if (key->second)
                {
                    getEventQueue()->keyRelease(key->first.first, key->first.second);
                    key->second = false;
                }
            }

            _capturedMouseButtons.clear();

            break;

        ///////////////////
        case WM_NCHITTEST :
        ///////////////////
            {
                LONG_PTR result = _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) :
                                                        ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam);

                switch(result)
                {
                case HTLEFT:
                case HTRIGHT:
                    setCursorImpl(LeftRightCursor);
                    break;
                case HTTOP:
                case HTBOTTOM:
                    setCursorImpl(UpDownCursor);
                    break;
                case HTTOPLEFT:
                    setCursorImpl(TopLeftCorner);
                    break;
                case HTTOPRIGHT:
                    setCursorImpl(TopRightCorner);
                    break;
                case HTBOTTOMLEFT:
                    setCursorImpl(BottomLeftCorner);
                    break;
                case HTBOTTOMRIGHT:
                case HTGROWBOX:
                    setCursorImpl(BottomRightCorner);
                    break;
                case HTSYSMENU:
                case HTCAPTION:
                case HTMAXBUTTON:
                case HTMINBUTTON:
                case HTCLOSE:
                case HTHELP:
                   setCursorImpl(LeftArrowCursor);
                   break;

                default:
                    if (_traits->useCursor && _appMouseCursor != InheritCursor)
                        setCursorImpl(_appMouseCursor);
                    break;
                }
                return result;
            }
            break;

        /////////////////
        case WM_CLOSE   :
        /////////////////

            getEventQueue()->closeWindow(eventTime);
            break;

        /////////////////
        case WM_DESTROY :
        /////////////////

            _destroyWindow = true;
            if (_ownsWindow)
            {
                ::PostQuitMessage(0);
            }
            break;

        //////////////
        case WM_QUIT :
        //////////////

            _closeWindow = true;
            return wParam;

        //////////////
        case WM_TOUCH:
        /////////////
            {
                unsigned int numInputs = (unsigned int) wParam;
                TOUCHINPUT* ti = new TOUCHINPUT[numInputs];
                POINT pt;
                osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL);
                if(getTouchInputInfoFunc && (*getTouchInputInfoFunc)((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT)))
                {
                    // For each contact, dispatch the message to the appropriate message handler.
                    for(unsigned int i=0; i< numInputs; ++i)
                    {
                        pt.x =TOUCH_COORD_TO_PIXEL(ti[i].x);
                        pt.y =TOUCH_COORD_TO_PIXEL(ti[i].y);
                        ScreenToClient(getHWND(), &pt);
                        if(ti[i].dwFlags & TOUCHEVENTF_DOWN)
                        {
                            if (!osg_event) {
                                osg_event = getEventQueue()->touchBegan( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_BEGAN, pt.x, pt.y);
                            } else {
                                osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_BEGAN, pt.x, pt.y);
                            }
                        }
                        else if(ti[i].dwFlags & TOUCHEVENTF_UP)
                        {
                            // No double tap detection with RAW TOUCH Events, sorry.
                            if (!osg_event) {
                                osg_event = getEventQueue()->touchEnded( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_ENDED, pt.x, pt.y, 1);
                            } else {
                                osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_ENDED, pt.x, pt.y);
                            }
                        }
                        else if(ti[i].dwFlags & TOUCHEVENTF_MOVE)
                        {
                            if (!osg_event) {
                                osg_event = getEventQueue()->touchMoved(  ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_MOVED, pt.x, pt.y);
                            } else {
                                osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_MOVED, pt.x, pt.y);
                            }
                        }
                    }
                }
                if (closeTouchInputHandleFunc)
                    (*closeTouchInputHandleFunc)((HTOUCHINPUT)lParam);
                delete [] ti;
            }
            break;


            /************************************************************************/
            /*              TOUCH inputs for Win8 and later                         */
            /************************************************************************/
            // Note by Riccardo Corsi, 2017-03-16
            // Currently only handle the PEN input which is not handled nicely by the
            // WM_TOUCH framework.
            // At the moment the PEN is mapped to the mouse, emulating LEFT button click.
            // WM_POINTER* messages could entirely replace the WM_TOUCH framework,
            // at the moment if the input doesn't come from a PEN, than the DefWindowProc()
            // default implementation is invoked, which will generate the WM_TOUCH messages.


            /////
            case WM_POINTERDOWN:
            /////
            {
                UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
                POINTER_INPUT_TYPE pointerType = PT_POINTER;

                // check pointer type
                if (getPointerTypeFunc)
                {
                    (getPointerTypeFunc)(pointerId, &pointerType);
                    // handle PEN only
                    if (pointerType == PT_PEN)
                    {
                        POINT pt;
                        pt.x = GET_X_LPARAM(lParam);
                        pt.y = GET_Y_LPARAM(lParam);
                        ScreenToClient(hwnd, &pt);

                        getEventQueue()->mouseButtonPress(pt.x, pt.y, osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON);
                    }
                    // call default implementation to fallback on WM_TOUCH
                    else
                    {
                        if (_ownsWindow)
                        return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
                    }
                }
            }

            break;

            /////
            case WM_POINTERUPDATE:
            /////
            {
                UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
                POINTER_INPUT_TYPE pointerType = PT_POINTER;

                // check pointer type
                if (getPointerTypeFunc)
                {
                    (getPointerTypeFunc)(pointerId, &pointerType);
                    // handle PEN only
                    if (pointerType == PT_PEN)
                    {
                        POINT pt;
                        pt.x = GET_X_LPARAM(lParam);
                        pt.y = GET_Y_LPARAM(lParam);
                        ScreenToClient(hwnd, &pt);

                        getEventQueue()->mouseMotion(pt.x, pt.y);
                    }
                    // call default implementation to fallback on WM_TOUCH
                    else
                    {
                        if (_ownsWindow)
                        return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
                    }
                }
            }

            break;


            /////
            case WM_POINTERUP:
            /////
            {
                UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
                POINTER_INPUT_TYPE pointerType = PT_POINTER;

                // check pointer type
                if (getPointerTypeFunc)
                {
                    (getPointerTypeFunc)(pointerId, &pointerType);
                    // handle PEN only
                    if (pointerType == PT_PEN)
                    {
                        POINT pt;
                        pt.x = GET_X_LPARAM(lParam);
                        pt.y = GET_Y_LPARAM(lParam);
                        ScreenToClient(hwnd, &pt);

                        getEventQueue()->mouseButtonRelease(pt.x, pt.y, osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON);
                    }
                    // call default implementation to fallback on WM_TOUCH
                    else
                    {
                        if (_ownsWindow)
                        return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
                    }
                }
            }

            break;


        /////////////////
        default         :
        /////////////////

            if (_ownsWindow) return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
            break;
    }

    if (_ownsWindow) return 0;

    return _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) :
                                 ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam);
}


//////////////////////////////////////////////////////////////////////////////
//  Class responsible for registering the Win32 Windowing System interface
//////////////////////////////////////////////////////////////////////////////
#if 0
struct RegisterWindowingSystemInterfaceProxy
{
    RegisterWindowingSystemInterfaceProxy()
    {
        osg::GraphicsContext::setWindowingSystemInterface(Win32WindowingSystem::getInterface());
    }

    ~RegisterWindowingSystemInterfaceProxy()
    {
        if (osg::Referenced::getDeleteHandler())
        {
            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
            osg::Referenced::getDeleteHandler()->flushAll();
        }

        osg::GraphicsContext::setWindowingSystemInterface(0);
    }
};

static RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
#endif

} // namespace OsgViewer

#if 1
REGISTER_WINDOWINGSYSTEMINTERFACE(Win32, Win32WindowingSystem)
#else
// declare C entry point for static compilation.
extern "C" void OSGVIEWER_EXPORT graphicswindow_Win32(void)
{
    osg::GraphicsContext::setWindowingSystemInterface(osgViewer::Win32WindowingSystem::getInterface());
}
#endif

void GraphicsWindowWin32::raiseWindow()
{

    SetWindowPos(_hwnd, HWND_TOPMOST, _traits->x, _traits->y, _traits->width, _traits->height, SWP_NOMOVE|SWP_NOSIZE);
    SetWindowPos(_hwnd, HWND_NOTOPMOST, _traits->x, _traits->y, _traits->width, _traits->height, SWP_NOMOVE|SWP_NOSIZE);

}



More information about the osg-users mailing list