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

Last change on this file since 287 was 287, checked in by epyon, 11 years ago
  • mesh_data_pack's in every format
  • md5_mesh_data removed, uses standard mesh_data
  • BONE_ARRAY in NMD is now a simple set of animation nodes
  • bone and animation node concepts merged
  • several minor changes
File size: 8.5 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"
[138]8#include "nv/io/std_stream.hh"
[136]9#include <sstream>
10
11using namespace nv;
12
[238]13struct obj_vertex_vt
14{
15        vec3 position;
16        vec2 texcoord;
17
[240]18        obj_vertex_vt( vec3 a_position, vec2 a_texcoord, vec3 )
[238]19                : position( a_position ), texcoord( a_texcoord ) {}
20};
21
22struct obj_vertex_vtn
23{
24        vec3 position;
25        vec2 texcoord;
26        vec3 normal;
27
28        obj_vertex_vtn( vec3 a_position, vec2 a_texcoord, vec3 a_normal )
29                : position( a_position ), texcoord( a_texcoord ), normal( a_normal ) {}
30};
31
32
33struct obj_vertex_vtnt
34{
35        vec3 position;
36        vec2 texcoord;
37        vec3 normal;
38        vec4 tangent;
39
40        obj_vertex_vtnt( vec3 a_position, vec2 a_texcoord, vec3 a_normal )
41                : position( a_position ), texcoord( a_texcoord ), normal( a_normal ) {}
42};
43
[136]44struct obj_reader
45{
46        std::vector< vec3 > v;
47        std::vector< vec3 > n;
48        std::vector< vec2 > t;
49
50        std::string line;
51        std::string cmd;
[287]52        std::string name;
53        std::string next_name;
[136]54
55        std::size_t size;
[240]56        bool        eof;
[136]57
58        obj_reader();
59        bool read_stream( std::istream& stream );
[238]60        virtual size_t add_face( uint32* vi, uint32* ti, uint32* ni, size_t count ) = 0;
[239]61        virtual size_t raw_size() const = 0;
[240]62        virtual void reset() = 0;
[239]63        virtual const uint8* raw_pointer() const = 0;
[238]64        virtual void calculate_tangents() {}
[136]65
66        virtual ~obj_reader(){}
67};
68
69obj_reader::obj_reader()
70{
71        // push in dummy 0-index objects for faster indexing
72        v.push_back( vec3() );
73        n.push_back( vec3() );
74        t.push_back( vec2() );
75        size = 0;
[240]76        eof = false;
[136]77}
78
79bool obj_reader::read_stream( std::istream& stream )
80{
[287]81        name = next_name;
[240]82        bool added_faces = false;
[136]83        f32 x, y, z;
[240]84        if ( eof ) return false;
[136]85
86        while ( std::getline( stream, line ) )
87        {
88                if ( line.length() < 3 || line[0] == '#' )
89                {
90                        continue;
91                }
92
93                std::istringstream ss(line);
94                ss >> cmd;
95
96                if ( cmd == "v" )
97                {
98                        ss >> x >> y >> z;
99                        v.push_back( vec3( x, y, z ) );
100                        continue;
101                }
102
103                if ( cmd == "vn" )
104                {
105                        ss >> x >> y >> z;
106                        n.push_back( vec3( x, y, z ) );
107                        continue;
108                }
109
110                if ( cmd == "vt" )
111                {
112                        ss >> x >> y;
113                        t.push_back( vec2( x, 1.0f - y ) );
114                        continue;
115                }
116
117                if ( cmd == "f" )
118                {
[240]119                        added_faces = true;
[136]120                        ss >> cmd;
121
122                        uint32 vis[8];
123                        uint32 tis[8];
124                        uint32 nis[8];
125                        bool   normals = false;
126                        uint32 count = 0;
127
128                        while ( !ss.fail() )
129                        {
130                                char ch;
131
132                                std::istringstream ss2( cmd );
133                                ss2 >> vis[count] >> ch;
134                                ss2 >> tis[count] >> ch;
135                                if ( ch == '/')
136                                {
137                                        normals = true;
138                                        ss2 >> nis[count];
139                                }
140
141                                ss >> cmd;
142                                count++;
143                        }
144
145                        size += add_face( vis, tis, normals ? nis : nullptr, count );
146                        continue;
147                }
148
[240]149                if ( cmd == "g" )
[136]150                {
[287]151                        ss >> next_name;
152                        if (added_faces)
153                                return true;
154                        name = next_name;
[136]155                        continue;
156                }
157
[240]158                if ( cmd == "s" )
159                {
160                        continue;
161                }
162
[136]163                // unknown command
164        }
165
[240]166        eof = true;
[136]167        return true;
168}
169
[240]170template < typename VTX >
171struct mesh_data_reader : public obj_reader
[238]172{
[240]173        mesh_data_reader( bool normals ) : m_normals( normals ) {}
174        virtual std::size_t add_face( uint32* vi, uint32* ti, uint32* ni, size_t count )
[238]175        {
176                if ( count < 3 ) return 0; // TODO : report error?
[240]177
[238]178                // TODO : support if normals not present;
[240]179                vec3 nullvec;
[238]180                std::size_t result = 0;
181                // Simple triangulation - obj's shouldn't have more than quads anyway
[240]182
183                if ( m_normals )
[238]184                {
[240]185                        for ( size_t i = 2; i < count; ++i )
186                        {
187                                result++;
188                                m_data.emplace_back( v[ vi[ 0 ]   ], t[ ti[ 0   ] ], n[ ni[ 0   ] ] );
189                                m_data.emplace_back( v[ vi[ i-1 ] ], t[ ti[ i-1 ] ], n[ ni[ i-1 ] ] );
190                                m_data.emplace_back( v[ vi[ i ]   ], t[ ti[ i   ] ], n[ ni[ i   ] ] );
191                        }
[238]192                }
[240]193                else
194                {
195                        for ( size_t i = 2; i < count; ++i )
196                        {
197                                result++;
198                                m_data.emplace_back( v[ vi[ 0 ]   ], t[ ti[ 0   ] ], nullvec );
199                                m_data.emplace_back( v[ vi[ i-1 ] ], t[ ti[ i-1 ] ], nullvec );
200                                m_data.emplace_back( v[ vi[ i ]   ], t[ ti[ i   ] ], nullvec );
201                        }
202                }
[238]203                return result;
204        }
[240]205        bool m_normals;
206        std::vector< VTX > m_data;
207        virtual void reset() { m_data.clear(); }
208        virtual size_t raw_size() const { return m_data.size() * sizeof( VTX ); }
[239]209        virtual const uint8* raw_pointer() const { return (const uint8*)m_data.data(); }
[238]210};
211
[240]212
213struct mesh_data_reader_vt : public mesh_data_reader< obj_vertex_vt >
[238]214{
[240]215        mesh_data_reader_vt() : mesh_data_reader( false ) {}
[238]216};
217
[240]218struct mesh_data_reader_vtn : public mesh_data_reader< obj_vertex_vtn >
[238]219{
[240]220        mesh_data_reader_vtn() : mesh_data_reader( true ) {}
221};
[238]222
[240]223struct mesh_data_reader_vtnt : public mesh_data_reader< obj_vertex_vtnt >
224{
225        mesh_data_reader_vtnt() : mesh_data_reader( true ) {}
226
[238]227        // based on http://www.terathon.com/code/tangent.html
228        void calculate_tangents()
229        {
230                //              const std::vector< vec3 >& vp = m_mesh->get_positions();
231                //              const std::vector< vec2 >& vt = m_mesh->get_texcoords();
232                //              const std::vector< vec3 >& vn = m_mesh->get_normals();
233                //              std::vector< vec3 >& tg = m_mesh->get_tangents();
234
235                size_t count  = m_data.size();
236                size_t tcount = count / 3;
237
238                std::vector< vec3 > tan1( count );
239                std::vector< vec3 > tan2( count );
240
241                for (size_t a = 0; a < tcount; ++a )
242                {
243                        size_t i1 = a * 3;
244                        size_t i2 = a * 3 + 1;
245                        size_t i3 = a * 3 + 2;
246                        obj_vertex_vtnt& vtx1 = m_data[ i1 ];
247                        obj_vertex_vtnt& vtx2 = m_data[ i2 ];
248                        obj_vertex_vtnt& vtx3 = m_data[ i3 ];
249
250                        // TODO: simplify
251                        vec3 xyz1 = vtx2.position - vtx1.position;
252                        vec3 xyz2 = vtx3.position - vtx1.position;
253                        //vec2 st1  = w2 - w1;
254                        //vec2 st2  = w3 - w1;
255
256                        float s1 = vtx2.texcoord.x - vtx1.texcoord.x;
257                        float t1 = vtx2.texcoord.y - vtx1.texcoord.y;
258                        float s2 = vtx3.texcoord.x - vtx1.texcoord.x;
259                        float t2 = vtx3.texcoord.y - vtx1.texcoord.y;
260
261                        float stst = s1 * t2 - s2 * t1;
262                        float r = 0.0f;
263                        if (stst > 0.0f || stst < 0.0f) r = 1.0f / stst;
264
265                        vec3 sdir = ( t2 * xyz1 - t1 * xyz2 ) * r;
266                        vec3 tdir = ( s1 * xyz2 - s2 * xyz1 ) * r;
267
268                        // the += below obviously doesn't make sense in this case, but I'll
269                        // leave it here for when I move to indices
270                        tan1[i1] += sdir;
271                        tan1[i2] += sdir;
272                        tan1[i3] += sdir;
273
274                        // tan2 not needed anymore??
275                        tan2[i1] += tdir;
276                        tan2[i2] += tdir;
277                        tan2[i3] += tdir;
278                }
279
280                for (std::size_t a = 0; a < count; ++a )
281                {
282                        const vec3& n = m_data[a].normal;
283                        const vec3& t = tan1[a];
284                        if ( ! (t.x == 0.0f && t.y == 0.0f && t.z == 0.0f) )
285                        {
286                                m_data[a].tangent    = vec4( glm::normalize(t - n * glm::dot( n, t )), 0.0f );
287                                m_data[a].tangent[3] = (glm::dot(glm::cross(n, t), tan2[a]) < 0.0f) ? -1.0f : 1.0f;
288                        }
289                }
290
291        }
292
293
294};
295
[239]296nv::obj_loader::obj_loader( bool normals /*= true*/, bool tangents /*= false */ )
[240]297        : m_normals( normals ), m_tangents( tangents )
[238]298{
299        if ( normals )
300        {
301                if ( tangents )
302                        m_descriptor.initialize<obj_vertex_vtnt>();
303                else
304                        m_descriptor.initialize<obj_vertex_vtn>();
305        }
306        else
307                m_descriptor.initialize<obj_vertex_vt>();
308}
309
[239]310bool nv::obj_loader::load( stream& source )
[238]311{
312        obj_reader* reader = nullptr;
313        if ( m_normals )
314        {
315                if ( m_tangents )
316                        reader = new mesh_data_reader_vtnt();
317                else
318                        reader = new mesh_data_reader_vtn();
319        }
320        else
321                reader = new mesh_data_reader_vt();
322        std_stream sstream( &source );
323
[240]324        while ( reader->read_stream( sstream ) )
[238]325        {
[240]326                if ( m_tangents )
327                {
328                        reader->calculate_tangents();
329                }
[238]330       
[240]331                mesh_raw_channel* channel = new mesh_raw_channel();
332                nv::uint8* data = nullptr;
[238]333
[240]334                if ( reader->raw_size() > 0 )
335                {
336                        data = new uint8[ reader->raw_size() ];
337                        std::copy_n( reader->raw_pointer(), reader->raw_size(), data );
338                }
339                channel->data  = data;
340                channel->desc  = m_descriptor;
341                channel->count = reader->size * 3;
[239]342
[287]343                mesh_data* mesh = new mesh_data(reader->name);
[240]344                mesh->add_channel( channel );
345                m_meshes.push_back( mesh );
346
347                reader->reset();
[238]348        }
349        delete reader;
350        return true;
351
352}
353
[240]354mesh_data* nv::obj_loader::release_mesh_data( size_t index )
[238]355{
[240]356        mesh_data* result = m_meshes[ index ];
357        m_meshes[ index ] = nullptr;
[238]358        return result;
359}
360
[239]361nv::obj_loader::~obj_loader()
[238]362{
[240]363        for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
[238]364}
[287]365
366mesh_data_pack* nv::obj_loader::release_mesh_data_pack()
367{
368        uint32 size = m_meshes.size();
369        mesh_data* meshes = new mesh_data[ size ];
370        for ( uint32 i = 0; i < size; ++i )
371        {
372                m_meshes[i]->move_to( meshes[i] );
373                delete m_meshes[i];
374        }
375        m_meshes.clear();
376        return new mesh_data_pack( size, meshes );
377}
Note: See TracBrowser for help on using the repository browser.