source: trunk/src/formats/obj_loader.cc @ 136

Last change on this file since 136 was 136, checked in by epyon, 12 years ago
  • mesh_loader - mesh loading interface (crappy, will need to change)
  • formats - submodule for mesh/image formats
  • obj_loader - naive implementation of Wavefront OBJ format
File size: 4.0 KB
RevLine 
[136]1// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
2// http://chaosforge.org/
3//
4// This file is part of NV Libraries.
5// For conditions of distribution and use, see copyright notice in nv.hh
6
7#include "nv/formats/obj_loader.hh"
8#include <sstream>
9
10using namespace nv;
11
12struct obj_reader
13{
14        std::vector< vec3 > v;
15        std::vector< vec3 > n;
16        std::vector< vec2 > t;
17
18        std::string line;
19        std::string cmd;
20
21        std::size_t size;
22
23        obj_reader();
24        bool read_stream( std::istream& stream );
25
26        virtual std::size_t add_face( uint32* vi, uint32* ti, uint32* ni, size_t count ) = 0;
27        virtual ~obj_reader(){}
28};
29
30obj_reader::obj_reader()
31{
32        // push in dummy 0-index objects for faster indexing
33        v.push_back( vec3() );
34        n.push_back( vec3() );
35        t.push_back( vec2() );
36        size = 0;
37}
38
39bool obj_reader::read_stream( std::istream& stream )
40{
41        f32 x, y, z;
42
43        while ( std::getline( stream, line ) )
44        {
45                if ( line.length() < 3 || line[0] == '#' )
46                {
47                        continue;
48                }
49
50                std::istringstream ss(line);
51                ss >> cmd;
52
53                if ( cmd == "v" )
54                {
55                        ss >> x >> y >> z;
56                        v.push_back( vec3( x, y, z ) );
57                        continue;
58                }
59
60                if ( cmd == "vn" )
61                {
62                        ss >> x >> y >> z;
63                        n.push_back( vec3( x, y, z ) );
64                        continue;
65                }
66
67                if ( cmd == "vt" )
68                {
69                        ss >> x >> y;
70                        t.push_back( vec2( x, 1.0f - y ) );
71                        continue;
72                }
73
74                if ( cmd == "f" )
75                {
76                        ss >> cmd;
77
78                        uint32 vis[8];
79                        uint32 tis[8];
80                        uint32 nis[8];
81                        bool   normals = false;
82                        uint32 count = 0;
83
84                        while ( !ss.fail() )
85                        {
86                                char ch;
87
88                                std::istringstream ss2( cmd );
89                                ss2 >> vis[count] >> ch;
90                                ss2 >> tis[count] >> ch;
91                                if ( ch == '/')
92                                {
93                                        normals = true;
94                                        ss2 >> nis[count];
95                                }
96
97                                ss >> cmd;
98                                count++;
99                        }
100
101                        size += add_face( vis, tis, normals ? nis : nullptr, count );
102                        continue;
103                }
104
105                if ( cmd == "g" || cmd == "s" )
106                {
107                        // ignored
108                        continue;
109                }
110
111                // unknown command
112        }
113
114        return true;
115}
116
117
118struct mesh_obj_reader : public obj_reader
119{
120        mesh_obj_reader( mesh* m ) : m_mesh( m ), m_position( nullptr ), m_normal( nullptr ), m_tex_coord( nullptr ) {}
121        virtual std::size_t add_face( uint32* v, uint32* t, uint32* n, size_t count );
122
123        vertex_attribute< vec3 >* m_position;
124        vertex_attribute< vec3 >* m_normal;
125        vertex_attribute< vec2 >* m_tex_coord;
126        mesh* m_mesh;
127};
128
129std::size_t mesh_obj_reader::add_face( uint32* vi, uint32* ti, uint32* ni, size_t count )
130{
131        if ( count < 3 )
132        {
133                // TODO : report error?
134                return 0;
135        }
136
137        if ( m_position == nullptr )
138        {
139                m_position  = m_mesh->add_attribute< vec3 >( "position" );
140        }
141        if ( m_tex_coord == nullptr )
142        {
143                m_tex_coord = m_mesh->add_attribute< vec2 >( "texcoord" );
144        }
145        if ( m_normal == nullptr && ni != nullptr )
146        {
147                m_normal = m_mesh->add_attribute< vec3 >( "normal" );
148        }
149
150        // TODO : support if normals not present;
151
152        std::vector< vec3 >& vp = m_position->get();
153        std::vector< vec2 >& vt = m_tex_coord->get();
154        std::vector< vec3 >& vn = m_normal->get();
155
156        std::size_t result = 0;
157
158        // Simple triangulation - obj's shouldn't have more than quads anyway
159        for ( size_t i = 2; i < count; ++i )
160        {
161                result++;
162                vp.push_back( v[ vi[ 0 ] ] );   vt.push_back( t[ ti[ 0 ] ] );   vn.push_back( n[ ni[ 0 ] ] );
163                vp.push_back( v[ vi[ i-1 ] ] ); vt.push_back( t[ ti[ i-1 ] ] ); vn.push_back( n[ ni[ i-1 ] ] );
164                vp.push_back( v[ vi[ i ] ] );   vt.push_back( t[ ti[ i ] ] );   vn.push_back( n[ ni[ i ] ] );
165        }
166
167        return result;
168}
169
170nv::obj_loader::obj_loader()
171        : m_mesh( nullptr )
172{
173
174}
175
176nv::obj_loader::~obj_loader()
177{
178        delete m_mesh;
179}
180
181bool nv::obj_loader::load( stream& source )
182{
183        if ( m_mesh != nullptr )
184        {
185                delete m_mesh;
186        }
187        m_mesh = new mesh();
188        mesh_obj_reader reader( m_mesh );
189        size_t size = source.size();
190        char* data  = new char[ size ];
191        source.read( data, 1, size );
192        std::string cache( data, size );
193        std::istringstream sstream( cache );
194        reader.read_stream( sstream );
195        m_size = reader.size;
196        return true;
197}
Note: See TracBrowser for help on using the repository browser.