[svn] / trunk / src / examples / eqPly / plyFileIO.cpp Repository:
ViewVC logotype

View of /trunk/src/examples/eqPly/plyFileIO.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1008 - (download) (as text) (annotate)
Wed Apr 11 08:23:04 2007 UTC (3 months ago) by eile
File size: 15326 byte(s)
Minor code cleanups
[ ] May break build
[ ] Breaks existing applications
[ ] Bugfix
[ ] New Feature
[x] Cleanup
[ ] Optimization
[ ] Documentation
/* Copyright (c) 2006-2007, Stefan Eilemann <[email protected]> 
   All rights reserved.
   Adapted code for Equalizer usage.
   Win32 porting.
 */
/******************************************************************************
 *                                                                            *
 * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.            *
 *                                                                            *
 * The recipient ("Recipient") of this software, including as modified        *
 * ("Software") may reproduce, redistribute, use, and derive works from the   *
 * Software without restriction, subject to the following conditions:         *
 *                                                                            *
 * - Redistribution of the Software in any form must reproduce this entire    *
 *   notice, including as modified in accordance with these provisions        *
 *   ("Notice");                                                              *
 * - Any Recipient who modifies and subsequently redistributes the Software   *
 *   shall add information to this Notice to sufficiently identify the        *
 *   Recipient's modifications;                                               *
 * - Recipient may not use the name(s) of any previous Recipient to endorse   *
 *   or promote any products derived from the Software without prior express  *
 *   written permission from such previous Recipient.                         *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS," WITHOUT ANY EXPRESS OR IMPLIED WARRANTY  *
 * OR CONDITION, INCLUDING WITHOUT LIMITATION ANY WARRANTIES OR CONDITIONS OF *
 * MERCHANTABILITY, SECURITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR  *
 * PURPOSE, AND NONINFRINGEMENT.  PATENT LICENSES, IF ANY, PROVIDED HEREIN   *
 * DO NOT APPLY TO COMBINATIONS OF THIS PROGRAM WITH OTHER SOFTWARE, OR ANY   *
 * OTHER PRODUCT WHATSOEVER.  IN NO EVENT WILL THE ORIGINATOR OR SUBSEQUENT   *
 * RECIPIENT OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  *
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ARISING IN RELATION TO THE    *
 * SOFTWARE, ITS USE, OR THESE PROVISIONS, HOWEVER CAUSED AND ON ANY THEORY   *
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR NEGLIGENCE OR      *
 * OTHER TORT, EVEN IF PRE-ADVISED OF THE PROSPECT OF SUCH DAMAGES.           *
 *                                                                            *
 * This Software was developed at private expense; if acquired under an       *
 * agreement with the USA government or any contractor thereto, it is         *
 * acquired as "commercial computer software" subject to the provisions of    *
 * this license agreement, as specified in (a) 48 CFR 12.212 of the FAR; or,  *
 * if acquired for Department of Defense units, (b) 48 CFR 227-7202 of the    *
 * DoD FAR Supplement; or sections succeeding thereto.                        *
 *                                                                            *
 *                                                                            *
 * Originator:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,               *
 * Mountain View, CA  94043.  http://www.sgi.com                              *
 *                                                                            *
 ******************************************************************************/
#include "plyFileIO.h"
#include "plyModel.h"
#include "colorVertex.h"
#include "normalFace.h"
#include <eq/eq.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef WIN32
#  include <malloc.h>
#  define EQ_WIN32_ERROR getErrorString( GetLastError( )) << \
    "(" << GetLastError() << ")"
#else
#  include <alloca.h>
#  include <sys/mman.h>
#endif
using namespace std;
using namespace eqBase;
//---------------------------------------------------------------------------
// read
//---------------------------------------------------------------------------
PlyModel< NormalFace<ColorVertex> > *PlyFileIO::read( const char *filename )
{
    const size_t len     = strlen(filename);
    char        *binName = (char *)alloca( (unsigned int)len+6 );
    if( sizeof( void* ) == 8 )
        sprintf( binName, "%s.b64", filename );
    else
        sprintf( binName, "%s.b32", filename );
#if 1
    PlyModel< NormalFace<ColorVertex> > *model = readBin( binName );
#else
    PlyModel< NormalFace<ColorVertex> > *model = 0;
#endif
    if( !model )
    {
        model = readPly( filename );
        if( !model )
            return 0;
        writeBin( model, binName );
    }
    return model;
}
//---------------------------------------------------------------------------
// readPly
//---------------------------------------------------------------------------
PlyModel< NormalFace<ColorVertex> > *PlyFileIO::readPly( const char *filename )
{
    NormalFace<ColorVertex>  *faces    = 0;
    size_t                    nFaces;
    if( !readPlyFile( filename, &faces, &nFaces ))
        return 0;
    PlyModel< NormalFace<ColorVertex> > *model = 
        new PlyModel< NormalFace<ColorVertex> >;
    size_t threshold = MAX( nFaces/1000, 16384 );
    model->setFaces( nFaces, faces, threshold );
    model->normalize();
    free( faces );    
    return model;
}
bool PlyFileIO::readPlyFile( const char *filename,
    NormalFace<ColorVertex> **faces, size_t *nFaces )
{
    int       nElems;
    char    **elemNames;
    int       fileType;
    float     version;
    PlyFile *file = ply_open_for_reading( (char *)filename, &nElems, 
        &elemNames, &fileType, &version );
    if( !file )
        return false;
    ColorVertex *vertices  = 0;
    int          nVertices = 0;
    EQINFO << filename << ": " << nElems << " elements, file version " 
           << version << endl;
    for( int i=0; i<nElems; i++ )
    {
        int nElems, nProps;
        PlyProperty **props = 
            ply_get_element_description( file, elemNames[i], &nElems, &nProps );
        EQINFO << "Element " << i << ": name " << elemNames[i] << ", " 
               << nProps << " properties" << endl;
        // vertices
        if( strcmp( elemNames[i], "vertex" ) == 0 )
        {
            bool color = false;
            // look for color in model
            for( int j=0; j<nProps; j++ )
                if( strcmp( props[j]->name, "red" )==0 )
                    color = true;
            vertices = (ColorVertex *)malloc( nElems * sizeof( ColorVertex ));
            readVertices( file, nElems, color, vertices );
            nVertices = nElems;
        }
        // faces
        else if( strcmp( elemNames[i], "face" ) == 0 )
        {
            assert( vertices );
            *faces = (NormalFace<ColorVertex> *)
                malloc( nElems * sizeof( NormalFace<ColorVertex> ));
            readFaces( file, vertices, nVertices, *faces, nElems );
            *nFaces = nElems;
            free( vertices );
            nVertices = 0;
            ply_close( file );
            return true;
        }
    }
    ply_close( file );
    return false;
}
//---------------------------------------------------------------------------
// readVertices
//---------------------------------------------------------------------------
void PlyFileIO::readVertices( PlyFile *file, int num, bool color, 
    ColorVertex *vertices )
{
    // setup read
    int nVProps = 3;
    // C++ does not allow offsetof on non-POD types. Work around this using
    // pointer voodoo knowing that our non-POD ColorVertex is 'well-behaved'
    ColorVertex dummy;
    const int xOffset = ((char*)&dummy.pos[0] - (char*)&dummy );
    const int yOffset = ((char*)&dummy.pos[1] - (char*)&dummy );
    const int zOffset = ((char*)&dummy.pos[2] - (char*)&dummy );
    PlyProperty vProps[6] =
        { 
            { "x", PLY_FLOAT, PLY_FLOAT, xOffset, 0, 0, 0, 0 },
            { "y", PLY_FLOAT, PLY_FLOAT, yOffset, 0, 0, 0, 0 },
            { "z", PLY_FLOAT, PLY_FLOAT, zOffset, 0, 0, 0, 0 }
        };
    char colors[3][6] = { "red", "green", "blue" };
    if( color )
    {
        for( int i=3; i<6; i++ )
        {
            vProps[i].name = colors[i-3];
            vProps[i].external_type = PLY_UCHAR;   
            vProps[i].internal_type = PLY_FLOAT;   
            vProps[i].is_list = 0;         
        }
        // non-POD offsets: see comment above
        const int rOffset = ((char*)&dummy.color[0] - (char*)&dummy );
        const int gOffset = ((char*)&dummy.color[1] - (char*)&dummy );
        const int bOffset = ((char*)&dummy.color[2] - (char*)&dummy );
        vProps[3].offset = rOffset;
        vProps[4].offset = gOffset;
        vProps[5].offset = bOffset;        
        nVProps = 6;
    }
    else
        nVProps = 3;
    EQINFO << disableHeader << "Reading " << num << " vertices";
    ply_get_element_setup( file, "vertex", nVProps, vProps );
    // read vertices
    for( int i=0; i<num; i++ )
    {
        if( i%10000 == 0 )
            EQINFO << "." << forceFlush;
        ply_get_element( file, &vertices[i] );
        if( color )
        {
            vertices[i].color[0] /= 256.;
            vertices[i].color[1] /= 256.;
            vertices[i].color[2] /= 256.;
        }
        else
        {
            vertices[i].color[0] = 1.;
            vertices[i].color[1] = 1.;
            vertices[i].color[2] = 1.;
        }
    }
    EQINFO << enableHeader << endl;
}
//---------------------------------------------------------------------------
// readFaces
//---------------------------------------------------------------------------
void PlyFileIO::readFaces( PlyFile *file, 
                           ColorVertex *vertices, const int nVertices, 
                           NormalFace<ColorVertex> *faces, const int nFaces )
{
    // setup read
    int nFProps = 1;
    struct IndexFace {
        int  nVertices;
        int* vertices;
    } face;
    PlyProperty fProps[] = {{
        "vertex_indices", PLY_INT, PLY_INT, offsetof( IndexFace, vertices ),
        1, PLY_INT, PLY_INT, offsetof( IndexFace, nVertices ) }};
    EQINFO << "Reading " << nFaces << " faces" << disableHeader;
    ply_get_element_setup( file, "face", nFProps, fProps );
    // read faces
    unsigned wrongNormals = 0;
    for( int i=0; i<nFaces; i++ )
    {
        if( i%10000 == 0 )
            EQINFO << "." << forceFlush;
        // read face
        ply_get_element( file, &face );
        assert( face.nVertices == 3 );
        // dereference face indices
        for( int j=0; j<3; j++ )
        {
            EQASSERT( face.vertices[j] < nVertices );
            EQASSERT( face.vertices[j] >= 0 );
            faces[i].vertices[j] = vertices[face.vertices[j]]; 
        }
        // calculate normal
        if( !calculateNormal( faces[i] ))
            ++wrongNormals;
    }
#ifndef NDEBUG
    EQINFO << endl << enableHeader;
    if( wrongNormals )
        EQWARN << "No normal for " << wrongNormals << " faces ("
               << (float)wrongNormals/(float)nFaces*100. << "%)" << endl;
#endif            
}
//---------------------------------------------------------------------------
// calculateNormal
//---------------------------------------------------------------------------
bool PlyFileIO::calculateNormal( NormalFace<ColorVertex> &face )
{
    double ax = 1000.*face.vertices[0].pos[0] - 1000.*face.vertices[1].pos[0];
    double ay = 1000.*face.vertices[0].pos[1] - 1000.*face.vertices[1].pos[1];
    double az = 1000.*face.vertices[0].pos[2] - 1000.*face.vertices[1].pos[2];
    double bx = 1000.*face.vertices[0].pos[0] - 1000.*face.vertices[2].pos[0];
    double by = 1000.*face.vertices[0].pos[1] - 1000.*face.vertices[2].pos[1];
    double bz = 1000.*face.vertices[0].pos[2] - 1000.*face.vertices[2].pos[2];
    face.normal[0] = static_cast<float>( ay*bz - az*by );
    face.normal[1] = static_cast<float>( az*bx - ax*bz );
    face.normal[2] = static_cast<float>( ax*by - ay*bx );
    const float n = sqrtf( face.normal[0] * face.normal[0] + 
                           face.normal[1] * face.normal[1] + 
                           face.normal[2] * face.normal[2] );
    if( n==0.0f )
    {
        face.normal[0] = 0.0f;
        face.normal[1] = 0.0f;
        face.normal[2] = 1.0f;
        return false;
    }
    const float nInv = 1.0f / n;
    face.normal[0] *= nInv;
    face.normal[1] *= nInv;
    face.normal[2] *= nInv;
    return true;
}
//---------------------------------------------------------------------------
// readBin
//---------------------------------------------------------------------------
PlyModel< NormalFace<ColorVertex> > *PlyFileIO::readBin( const char *filename )
{
#ifdef WIN32
    EQINFO << "Trying " << filename << endl;
    HANDLE file = CreateFile( filename, GENERIC_READ, FILE_SHARE_READ, 0,
                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
    if( file == INVALID_HANDLE_VALUE )
    {
        EQINFO << "Open of " << filename << " failed: " << EQ_WIN32_ERROR 
               << endl;
        return 0;
    }
    HANDLE map = CreateFileMapping( file, 0, PAGE_READONLY, 0, 0, filename );
    CloseHandle( file );
    if( !map )
    {
        EQINFO << "Mapping of " << filename << " failed: " << EQ_WIN32_ERROR
               << endl;
        return 0;
    }
    /* get a view of the mapping */
    char* addr = static_cast<char*>( MapViewOfFile( map, FILE_MAP_READ, 0, 0, 
                                                    0 ));
    if( !addr )
    {
        EQINFO << "Mapping to memory of " << filename << " failed: " 
               << EQ_WIN32_ERROR << endl;
        CloseHandle( map );
        return 0;
    }
#else
    int fd = open( filename, O_RDONLY );
    if( fd < 0 ) 
        return 0;
    struct stat status;
    fstat( fd, &status );
    char *addr = static_cast<char *>( mmap( 0, (size_t) status.st_size, 
                                            PROT_READ, MAP_SHARED, fd, 0 ));
    if( addr == MAP_FAILED )
    {
        EQERROR << "mmap failed: " << strerror( errno ) << endl;
        return 0;
    }
#endif
    PlyModel< NormalFace<ColorVertex> > *model = 
        new PlyModel< NormalFace<ColorVertex> >;
    if( !model->fromMemory( addr ) )
    {
        EQWARN << filename << " invalid" << endl;
        delete model;
        model = 0;
    }
#ifdef WIN32
    UnmapViewOfFile( addr );
    CloseHandle( map );
#else
    munmap( addr, (size_t) status.st_size );
    close( fd );
#endif
    return model;
}
//---------------------------------------------------------------------------
// writeBin
//---------------------------------------------------------------------------
void PlyFileIO::writeBin( PlyModel< NormalFace<ColorVertex> > *model, 
    const char *filename )
{
    EQINFO << "Writing " << filename << endl;
    ofstream fout( filename, ios::out | ios::binary );
    if( !fout )
    {
        EQWARN << "Can't open " << filename << " for writing" << endl;
        return;
    }
    model->toStream( fout );
    fout.close();
}

Back to Equalizer website
ViewVC Help
Powered by ViewVC 1.0.3