Hi Robert,

I ran into some issues with the directX loader plugin, here's some minor tweaks 
that helped.

Changes described apply to files in the 2.8.0 release.
path - OpenSceneGraph-2.8.0/src/osgPlugins/x
 
I made a few minor changes to ReaderWriterDirectX.cpp and directx.cpp 
(attached):

In directx.cpp: 
 
Changed a call from "parseFrame" to "parseSection".  The call to the parseFrame 
function was breaking the recursive brace-tracking mechanism in parseSection, 
so it was kicking out of nested braces too early.

In ReaderWriterDirectX.cpp:

Changed behaviour of convertFromDX from "return null if no texture coords" to 
"don't copy texture coords if no texture coords".

I still am unable to load about half of Microsoft's .x files from the DirectX 
SDK, but some do load.  The ones that don't are either binary or they use some 
non-simple geometry descriptions.

Tested on Windows XP/VS8.

Thanks,
Aric



      
// -*-c++-*-

/*
 * $Id: directx.cpp 9124 2008-11-07 15:08:08Z robert $
 *
 * Loader for DirectX .x files.
 * Copyright (c)2002-2006 Ulrich Hertlein <[email protected]>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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 GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#if defined(_MSC_VER) && (_MSC_VER <= 1200)
#pragma warning (disable : 4786)
#endif

#include "directx.h"

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

#include <math.h>

#include <osg/Notify>
#include <osgDB/fstream>

using namespace DX;
using namespace std;


/**********************************************************************
 *
 * DirectX object.
 *
 **********************************************************************/

Object::Object()
{
}

void Object::clear()
{
    for (unsigned int i = 0; i < _meshes.size(); ++i) {
        _meshes[i]->clear();
    }
    _meshes.clear();
}

bool Object::load(const char* filename)
{
    if (!filename)
        return false;

    osgDB::ifstream fin(filename);
    if (fin.bad()) {
        osg::notify(osg::WARN) << "Object::load: Unable to open: " << filename 
<< endl;
        return false;
    }

    parseSection(fin);
    fin.close();

    return true;
}

bool Object::generateNormals(float creaseAngle)
{
    bool result = true;
    for (unsigned int i = 0; i < _meshes.size(); ++i) {
        result &= _meshes[i]->generateNormals(creaseAngle);
    }

    return result;
}

Material * Object::findMaterial(const std::string & name)
{
    std::vector<Material>::iterator itr;
    for (itr = _globalMaterials.begin(); itr != _globalMaterials.end(); ++itr) {
        //cerr << "search=" << name << " have=" << (*itr).name << endl;
        if ((*itr).name == name) {
            return &*itr;
        }
    }

    return 0;
}


/**********************************************************************
 *
 * Private
 *
 **********************************************************************/

// Parse section
void Object::parseSection(ifstream& fin)
{
    char buf[256];
    vector<string> token;

    while (fin.getline(buf, sizeof(buf))) {

        if (strrchr(buf, '}') != 0) {
            //cerr << "!!! End section\n";
            break;
        }
        else if (strrchr(buf, '{') != 0) {
            // Tokenize
            token.clear();
            tokenize(buf, token);
            if (token.size() == 0)
                continue;

            if (token[0] == "Mesh") {
                // create new mesh
                //cerr << "!!! Begin Mesh" << endl;
                Mesh * mesh = new Mesh(this);
                _meshes.push_back(mesh);
                mesh->parseMesh(fin);
                                osg::notify(osg::INFO) << "Mesh " << 
(token.size()>1?token[1]:"") << endl;
            }
            else if (token[0] == "Material") {
                //
                // dgm - In later versions of directx files, materials
                // can be declared at the top of the file (e.g. globally).
                // Keep this list of global materials in "_globalMaterials"
                //
                Material mm;
                if (token.size() > 1 && token[1] != "") {
                    mm.name = token[1];
                }
                parseMaterial(fin, mm);
                _globalMaterials.push_back(mm);
                                osg::notify(osg::INFO) << "Material " << 
(token.size()>1?token[1]:"") << endl;
            }
            else if (token[0] == "Frame") {
                                //parseFrame(fin);
                                parseSection(fin);
            }
            else {
                //cerr << "!!! Begin section " << token[0] << endl;
                parseSection(fin);
            }
        }
    }
}

// Parse frame
void Object::parseFrame(ifstream& /*fin*/)
{
}
// -*-c++-*-

/*
 * $Id: ReaderWriterDirectX.cpp 9527 2009-01-21 18:23:55Z robert $
 *
 * DirectX file converter for OpenSceneGraph.
 * Copyright (c)2002 Ulrich Hertlein <[email protected]>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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 GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "directx.h"

#include <osg/TexEnv>
#include <osg/CullFace>

#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/Image>
#include <osg/Texture2D>

#include <osg/Notify>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>

#include <map>
#include <iostream>


/**
 * OpenSceneGraph plugin wrapper/converter.
 */
class ReaderWriterDirectX : public osgDB::ReaderWriter
{
public:
    ReaderWriterDirectX()
    {
        supportsExtension("x","DirectX scene format");
        supportsOption("flipTexture", "flip texture upside-down");
    }

    virtual const char* className() const {
        return "DirectX Reader";
    }

    virtual ReadResult readNode(const std::string& fileName, const 
osgDB::ReaderWriter::Options* options) const;

private:
    osg::Group * convertFromDX(DX::Object & obj, bool flipTexture, float 
creaseAngle,
            const osgDB::ReaderWriter::Options * options) const;

    osg::Geode * convertFromDX(DX::Mesh & mesh, bool flipTexture, float 
creaseAngle,
            const osgDB::ReaderWriter::Options * options) const;
};

// Register with Registry to instantiate the above reader/writer.
REGISTER_OSGPLUGIN(x, ReaderWriterDirectX)


// Read node
osgDB::ReaderWriter::ReadResult ReaderWriterDirectX::readNode(const 
std::string& file, const osgDB::ReaderWriter::Options* options) const
{
    std::string ext = osgDB::getLowerCaseFileExtension(file);
    if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

    std::string fileName = osgDB::findDataFile( file, options );
    if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

    osg::notify(osg::INFO) << "ReaderWriterDirectX::readNode(" << 
fileName.c_str() << ")\n";

    // Load DirectX mesh
    DX::Object obj;
    if (obj.load(fileName.c_str()) == false) {
        return ReadResult::ERROR_IN_READING_FILE;
    }

    // code for setting up the database path so that internally referenced file 
are searched for on relative paths. 
    osg::ref_ptr<Options> local_opt = options ? 
static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
    local_opt->setDatabasePath(osgDB::getFilePath(fileName));

    // Options?
    bool flipTexture = true;
    float creaseAngle = 80.0f;
    if (options) {
        const std::string option = options->getOptionString();
        if (option.find("flipTexture") != std::string::npos) {
            flipTexture = false;
        }
        if (option.find("creaseAngle") != std::string::npos) {
            // TODO
        }
    }

    // Convert to osg::Group
    osg::Group* group = convertFromDX(obj, flipTexture, creaseAngle, 
local_opt.get());
    if (!group) {
        return ReadResult::ERROR_IN_READING_FILE;
    }

    return group;
}

// Convert DirectX object
osg::Group * ReaderWriterDirectX::convertFromDX(DX::Object & obj,
                                                bool flipTexture, float 
creaseAngle,
                                                const 
osgDB::ReaderWriter::Options * options) const
{
    osg::ref_ptr<osg::Group> group = new osg::Group;

    for (unsigned int i = 0; i < obj.getNumMeshes(); ++i) {
        //std::cerr << "converting mesh " << i << std::endl;
        DX::Mesh & mesh = *obj.getMesh(i);
        osg::Geode * geode = convertFromDX(mesh, flipTexture, creaseAngle, 
options);
        if (!geode) {
            return 0;
        }
        group->addChild(geode);
    }

    return group.release();
}

// Convert DirectX mesh to osg::Geode
osg::Geode* ReaderWriterDirectX::convertFromDX(DX::Mesh & mesh,
                                               bool flipTexture, float 
creaseAngle,
                                               const 
osgDB::ReaderWriter::Options * options) const
{
        const DX::MeshMaterialList* meshMaterial = mesh.getMeshMaterialList();
    if (!meshMaterial)
        return NULL;

        const DX::MeshNormals* meshNormals = mesh.getMeshNormals();
    if (!meshNormals) {
        mesh.generateNormals(creaseAngle);
        meshNormals = mesh.getMeshNormals();
    }
    //std::cerr << "normals=" << meshNormals << std::endl;
    if (!meshNormals)
        return NULL;

    const DX::MeshTextureCoords* meshTexCoords = mesh.getMeshTextureCoords();
    //std::cerr << "texcoord=" << meshTexCoords << std::endl;

    /*
     * - MeshMaterialList contains a list of Material and a per-face
     *   information with Material is to be applied to which face.
     * - Mesh contains a list of Vertices and a per-face information
     *   which vertices (three or four) belong to this face.
     * - MeshNormals contains a list of Normals and a per-face information
     *   which normal is used by which vertex.
     * - MeshTextureCoords contains a list of per-vertex texture coordinates.
     *
     * - Uses left-hand CS with Y-up, Z-into
     *   obj_x -> osg_x
     *   obj_y -> osg_z
     *   obj_z -> osg_y
     *
     * - Polys are CW oriented
     */
    std::vector<osg::Geometry*> geomList;

    // Texture-for-Image map
    std::map<std::string, osg::Texture2D*> texForImage;
    
    unsigned int i;
    for (i = 0; i < meshMaterial->material.size(); i++) {

        //std::cerr << "material " << i << std::endl;

        const DX::Material& mtl = meshMaterial->material[i];
        osg::StateSet* state = new osg::StateSet;

        // Material
        osg::Material* material = new osg::Material;
        state->setAttributeAndModes(material);

        float alpha = mtl.faceColor.alpha;
        osg::Vec4 ambient(mtl.faceColor.red,
                          mtl.faceColor.green,
                          mtl.faceColor.blue,
                          alpha);
        material->setAmbient(osg::Material::FRONT, ambient);
        material->setDiffuse(osg::Material::FRONT, ambient);

        material->setShininess(osg::Material::FRONT, mtl.power);

        osg::Vec4 specular(mtl.specularColor.red,
                           mtl.specularColor.green,
                           mtl.specularColor.blue, alpha);
        material->setSpecular(osg::Material::FRONT, specular);

        osg::Vec4 emissive(mtl.emissiveColor.red,
                           mtl.emissiveColor.green,
                           mtl.emissiveColor.blue, alpha);
        material->setEmission(osg::Material::FRONT, emissive);

        // Transparency? Set render hint & blending
        if (alpha < 1.0f) {
            state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
            state->setMode(GL_BLEND, osg::StateAttribute::ON);
        }
        else
            state->setMode(GL_BLEND, osg::StateAttribute::OFF);

        unsigned int textureCount = mtl.texture.size();
        for (unsigned int j = 0; j < textureCount; j++) {

            //std::cerr << "texture " << j << std::endl;

            // Share image/texture pairs
            osg::Texture2D* texture = texForImage[mtl.texture[j]];
            if (!texture) {
                osg::ref_ptr<osg::Image> image = 
osgDB::readRefImageFile(mtl.texture[j],options);
                if (!image)
                    continue;

                // Texture
                texture = new osg::Texture2D;
                texForImage[mtl.texture[j]] = texture;

                texture->setImage(image.get());
                texture->setWrap(osg::Texture2D::WRAP_S, 
osg::Texture2D::REPEAT);
                texture->setWrap(osg::Texture2D::WRAP_T, 
osg::Texture2D::REPEAT);
            }
            state->setTextureAttributeAndModes(j, texture);
        }

        // Geometry
        osg::Geometry* geom = new osg::Geometry;
        geomList.push_back(geom);

        geom->setStateSet(state);

        // Arrays to hold vertices, normals, and texcoords.
        geom->setVertexArray(new osg::Vec3Array);
        geom->setNormalArray(new osg::Vec3Array);
        geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
        if (textureCount) {
            // All texture units share the same array
            osg::Vec2Array* texCoords = new osg::Vec2Array;
            for (unsigned int j = 0; j < textureCount; j++)
                geom->setTexCoordArray(j, texCoords);
        }

        geom->addPrimitiveSet(new 
osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON));
    }

    const std::vector<DX::MeshFace> & faces = mesh.getFaces();
    if (faces.size() != meshMaterial->faceIndices.size())
    {
        osg::notify(osg::FATAL)<<"Error: internal error in DirectX .x 
loader,"<<std::endl;
        osg::notify(osg::FATAL)<<"       mesh->faces.size() == 
meshMaterial->faceIndices.size()"<<std::endl;
        return NULL;
    }

    // Add faces to Geometry
    for (i = 0; i < meshMaterial->faceIndices.size(); i++) {

        // Geometry for Material
        unsigned int mi = meshMaterial->faceIndices[i];
        osg::Geometry* geom = geomList[mi];

        // #pts of this face
        unsigned int np = faces[i].size();
        ((osg::DrawArrayLengths*) geom->getPrimitiveSet(0))->push_back(np);

        if (np != meshNormals->faceNormals[i].size())
        {
            osg::notify(osg::WARN)<<"DirectX loader: Error, error in normal 
list."<<std::endl;
        }

        osg::Vec3Array* vertexArray = (osg::Vec3Array*) geom->getVertexArray();
        osg::Vec3Array* normalArray = (osg::Vec3Array*) geom->getNormalArray();
                osg::Vec2Array* texCoordArray=NULL; // only make them if the 
original has them
                if(meshTexCoords) texCoordArray = (osg::Vec2Array*) 
geom->getTexCoordArray(0);

        // Add vertices, normals, texcoords
        for (unsigned int j = 0; j < np; j++) {

            // Convert CW to CCW order
            unsigned int jj = (j > 0 ? np - j : j);

            // Vertices
            unsigned int vi = faces[i][jj];
            if (vertexArray) {
                // Transform Xleft/Yup/Zinto to Xleft/Yinto/Zup
                const DX::Vector & v = mesh.getVertices()[vi];
                vertexArray->push_back(osg::Vec3(v.x,v.z,v.y));
            }

            // Normals
            unsigned int ni = meshNormals->faceNormals[i][jj];
            if (normalArray) {
                // Transform Xleft/Yup/Zinto to Xleft/Yinto/Zup
                const DX::Vector& n = meshNormals->normals[ni];
                normalArray->push_back(osg::Vec3(n.x,n.z,n.y));
            }

            // TexCoords
            if (texCoordArray) {
                const DX::Coords2d& tc = (*meshTexCoords)[vi];
                osg::Vec2 uv;
                if (flipTexture)
                    uv.set(tc.u, 1.0f - tc.v); // Image is upside down
                else
                    uv.set(tc.u, tc.v);
                texCoordArray->push_back(uv);
            }
        }
    }

    // Add non-empty nodes to Geode
    osg::Geode* geode = new osg::Geode;
    for (i = 0; i < geomList.size(); i++) {
        osg::Geometry* geom = geomList[i];
        if (((osg::Vec3Array*) geom->getVertexArray())->size())
            geode->addDrawable(geom);
    }

    // Back-face culling
    osg::StateSet* state = new osg::StateSet;
    geode->setStateSet(state);

    osg::CullFace* cullFace = new osg::CullFace;
    cullFace->setMode(osg::CullFace::BACK);
    state->setAttributeAndModes(cullFace);

    return geode;
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to