source: trunk/src/formats/obj_loader.cc

Last change on this file was 534, checked in by epyon, 8 years ago

CONTINUED:

  • getting rid of size_t
  • datatypes now restricted to uint32 size
  • 64-bit compatibility
  • copyright updates where modified
File size: 8.5 KB
RevLine 
[534]1// Copyright (C) 2012-2017 ChaosForge Ltd
[136]2// http://chaosforge.org/
3//
[395]4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
[136]6
7#include "nv/formats/obj_loader.hh"
[416]8#include "nv/interface/data_channel_access.hh"
9
[442]10#include <cstdio>
[136]11
12using namespace nv;
13
[238]14struct obj_vertex_vt
15{
16        vec3 position;
17        vec2 texcoord;
18
[240]19        obj_vertex_vt( vec3 a_position, vec2 a_texcoord, vec3 )
[238]20                : position( a_position ), texcoord( a_texcoord ) {}
21};
22
23struct obj_vertex_vtn
24{
25        vec3 position;
26        vec2 texcoord;
27        vec3 normal;
28
29        obj_vertex_vtn( vec3 a_position, vec2 a_texcoord, vec3 a_normal )
30                : position( a_position ), texcoord( a_texcoord ), normal( a_normal ) {}
31};
32
33
34struct obj_vertex_vtnt
35{
36        vec3 position;
37        vec2 texcoord;
38        vec3 normal;
39        vec4 tangent;
40
41        obj_vertex_vtnt( vec3 a_position, vec2 a_texcoord, vec3 a_normal )
42                : position( a_position ), texcoord( a_texcoord ), normal( a_normal ) {}
43};
44
[136]45struct obj_reader
46{
[383]47        vector< vec3 > v;
48        vector< vec3 > n;
49        vector< vec2 > t;
[136]50
[442]51        string32 name;
52        string32 next_name;
[136]53
[534]54        uint32 size;
[374]55        bool   eof;
[136]56
57        obj_reader();
[442]58        bool read_stream( stream& str );
[534]59        virtual uint32 add_face( uint32* vi, uint32* ti, uint32* ni, uint32 count ) = 0;
60        virtual uint32 raw_size() const = 0;
[240]61        virtual void reset() = 0;
[239]62        virtual const uint8* raw_pointer() const = 0;
[238]63        virtual void calculate_tangents() {}
[136]64
65        virtual ~obj_reader(){}
66};
67
68obj_reader::obj_reader()
69{
70        // push in dummy 0-index objects for faster indexing
71        v.push_back( vec3() );
72        n.push_back( vec3() );
73        t.push_back( vec2() );
74        size = 0;
[240]75        eof = false;
[136]76}
77
[442]78bool obj_reader::read_stream( stream& str )
[136]79{
[442]80        name.assign( next_name );
[240]81        bool added_faces = false;
[136]82        f32 x, y, z;
[240]83        if ( eof ) return false;
[442]84        char buffer[256];
85        while ( str.gets( buffer, 256 ) )
86        {
87                string_view cline( static_cast<const char*>( buffer ) );
88                cline = nv::trimmed( cline );
[136]89
[442]90                if ( cline.length() < 3 || cline[0] == '#' )
[136]91                {
92                        continue;
93                }
94
[442]95                if ( cline.starts_with( "vn " ) )
[136]96                {
[442]97                        sscanf( cline.data(), "vn %f %f %f", &x, &y, &z );
98                        n.push_back( vec3( x, y, z ) );
[136]99                        continue;
100                }
101
[442]102                if ( cline.starts_with( "vt " ) )
[136]103                {
[442]104                        sscanf( cline.data(), "vt %f %f", &x, &y );
105                        t.push_back( vec2( x, 1.0f - y ) );
[136]106                        continue;
107                }
108
[442]109                if ( cline.starts_with( "v " ) )
[136]110                {
[442]111                        sscanf( cline.data(), "v %f %f %f", &x, &y, &z );
112                        v.push_back( vec3( x, y, z ) );
[136]113                        continue;
114                }
115
[442]116                if ( cline.starts_with( "f " ) )
[136]117                {
[240]118                        added_faces = true;
[136]119
120                        uint32 vis[8];
121                        uint32 tis[8];
122                        uint32 nis[8];
123                        bool   normals = false;
124                        uint32 count = 0;
125
[442]126                        string_view scan( cline );
127                        scan.remove_prefix( 2 );
[534]128                        uint32 pos = 0;
[442]129                        while ( pos != string_view::npos )
[136]130                        {
[442]131                                scan.remove_prefix( pos );
132                                scan = nv::trimmed( scan );
133                                if ( sscanf( scan.data(), "%u/%u/%u", &vis[count], &tis[count], &nis[count] ) == 3 )
[136]134                                {
135                                        normals = true;
136                                }
[442]137                                else if ( !normals && sscanf( scan.data(), "%u/%u", &vis[count], &tis[count] ) == 2 )
138                                {
[136]139
[442]140                                }
141                                else
142                                {
143                                        break;
144                                }
[136]145                                count++;
[442]146                                pos = scan.find_first_of( "\t " );
[136]147                        }
148
149                        size += add_face( vis, tis, normals ? nis : nullptr, count );
150                        continue;
151                }
152
[442]153                if ( cline.starts_with( "g " ) )
[136]154                {
[442]155                        next_name.assign( nv::trimmed( cline.without_prefix( 2 ) ) );
[287]156                        if (added_faces)
157                                return true;
[442]158                        name.assign( next_name );
[136]159                        continue;
160                }
161
[442]162                if ( cline.starts_with( "s " ) )
[240]163                {
164                        continue;
165                }
166
[136]167                // unknown command
168        }
169
[240]170        eof = true;
[136]171        return true;
172}
173
[240]174template < typename VTX >
175struct mesh_data_reader : public obj_reader
[238]176{
[240]177        mesh_data_reader( bool normals ) : m_normals( normals ) {}
[534]178        virtual uint32 add_face( uint32* vi, uint32* ti, uint32* ni, uint32 count )
[238]179        {
180                if ( count < 3 ) return 0; // TODO : report error?
[240]181
[238]182                // TODO : support if normals not present;
[240]183                vec3 nullvec;
[534]184                uint32 result = 0;
[238]185                // Simple triangulation - obj's shouldn't have more than quads anyway
[240]186
187                if ( m_normals )
[238]188                {
[534]189                        for ( uint32 i = 2; i < count; ++i )
[240]190                        {
191                                result++;
192                                m_data.emplace_back( v[ vi[ 0 ]   ], t[ ti[ 0   ] ], n[ ni[ 0   ] ] );
193                                m_data.emplace_back( v[ vi[ i-1 ] ], t[ ti[ i-1 ] ], n[ ni[ i-1 ] ] );
194                                m_data.emplace_back( v[ vi[ i ]   ], t[ ti[ i   ] ], n[ ni[ i   ] ] );
195                        }
[238]196                }
[240]197                else
198                {
[534]199                        for ( uint32 i = 2; i < count; ++i )
[240]200                        {
201                                result++;
202                                m_data.emplace_back( v[ vi[ 0 ]   ], t[ ti[ 0   ] ], nullvec );
203                                m_data.emplace_back( v[ vi[ i-1 ] ], t[ ti[ i-1 ] ], nullvec );
204                                m_data.emplace_back( v[ vi[ i ]   ], t[ ti[ i   ] ], nullvec );
205                        }
206                }
[238]207                return result;
208        }
[240]209        bool m_normals;
[383]210        vector< VTX > m_data;
[240]211        virtual void reset() { m_data.clear(); }
[534]212        virtual uint32 raw_size() const { return m_data.size() * sizeof( VTX ); }
[406]213        virtual const uint8* raw_pointer() const { return reinterpret_cast< const uint8* >( m_data.data() ); }
[238]214};
215
[240]216
217struct mesh_data_reader_vt : public mesh_data_reader< obj_vertex_vt >
[238]218{
[240]219        mesh_data_reader_vt() : mesh_data_reader( false ) {}
[238]220};
221
[240]222struct mesh_data_reader_vtn : public mesh_data_reader< obj_vertex_vtn >
[238]223{
[240]224        mesh_data_reader_vtn() : mesh_data_reader( true ) {}
225};
[238]226
[240]227struct mesh_data_reader_vtnt : public mesh_data_reader< obj_vertex_vtnt >
228{
229        mesh_data_reader_vtnt() : mesh_data_reader( true ) {}
230
[238]231        // based on http://www.terathon.com/code/tangent.html
232        void calculate_tangents()
233        {
[534]234                uint32 count = m_data.size();
235                uint32 tcount = count / 3;
[238]236
[383]237                vector< vec3 > tan1( count );
238                vector< vec3 > tan2( count );
[238]239
[534]240                for ( uint32 a = 0; a < tcount; ++a )
[238]241                {
[534]242                        uint32 i1 = a * 3;
243                        uint32 i2 = a * 3 + 1;
244                        uint32 i3 = a * 3 + 2;
[238]245                        obj_vertex_vtnt& vtx1 = m_data[ i1 ];
246                        obj_vertex_vtnt& vtx2 = m_data[ i2 ];
247                        obj_vertex_vtnt& vtx3 = m_data[ i3 ];
248
249                        // TODO: simplify
250                        vec3 xyz1 = vtx2.position - vtx1.position;
251                        vec3 xyz2 = vtx3.position - vtx1.position;
252                        //vec2 st1  = w2 - w1;
253                        //vec2 st2  = w3 - w1;
254
255                        float s1 = vtx2.texcoord.x - vtx1.texcoord.x;
256                        float t1 = vtx2.texcoord.y - vtx1.texcoord.y;
257                        float s2 = vtx3.texcoord.x - vtx1.texcoord.x;
258                        float t2 = vtx3.texcoord.y - vtx1.texcoord.y;
259
260                        float stst = s1 * t2 - s2 * t1;
261                        float r = 0.0f;
262                        if (stst > 0.0f || stst < 0.0f) r = 1.0f / stst;
263
264                        vec3 sdir = ( t2 * xyz1 - t1 * xyz2 ) * r;
265                        vec3 tdir = ( s1 * xyz2 - s2 * xyz1 ) * r;
266
267                        // the += below obviously doesn't make sense in this case, but I'll
268                        // leave it here for when I move to indices
269                        tan1[i1] += sdir;
270                        tan1[i2] += sdir;
271                        tan1[i3] += sdir;
272
273                        // tan2 not needed anymore??
274                        tan2[i1] += tdir;
275                        tan2[i2] += tdir;
276                        tan2[i3] += tdir;
277                }
278
[534]279                for ( uint32 a = 0; a < count; ++a )
[238]280                {
[382]281                        const vec3& nv = m_data[a].normal;
282                        const vec3& tv = tan1[a];
283                        if ( ! (tv.x == 0.0f && tv.y == 0.0f && tv.z == 0.0f) )
[238]284                        {
[454]285                                m_data[a].tangent    = vec4( math::normalize(tv - nv * math::dot( nv, tv )), 0.0f );
286                                m_data[a].tangent[3] = ( math::dot( math::cross(nv, tv), tan2[a]) < 0.0f) ? -1.0f : 1.0f;
[238]287                        }
288                }
289
290        }
291
292
293};
294
[425]295nv::obj_loader::obj_loader( string_table* strings, bool normals /*= true*/, bool tangents /*= false */ )
296        : mesh_loader( strings ), m_normals( normals ), m_tangents( tangents )
[238]297{
298        if ( normals )
299        {
300                if ( tangents )
301                        m_descriptor.initialize<obj_vertex_vtnt>();
302                else
303                        m_descriptor.initialize<obj_vertex_vtn>();
304        }
305        else
306                m_descriptor.initialize<obj_vertex_vt>();
307}
308
[239]309bool nv::obj_loader::load( stream& source )
[238]310{
311        obj_reader* reader = nullptr;
312        if ( m_normals )
313        {
314                if ( m_tangents )
315                        reader = new mesh_data_reader_vtnt();
316                else
317                        reader = new mesh_data_reader_vtn();
318        }
319        else
320                reader = new mesh_data_reader_vt();
[442]321        while ( reader->read_stream( source ) )
[238]322        {
[240]323                if ( m_tangents )
324                {
325                        reader->calculate_tangents();
326                }
[238]327       
[424]328                data_channel_set* result = data_channel_set_creator::create_set( 1 );
[417]329
[482]330                uint8* rdata = data_channel_set_creator(result).add_channel( m_descriptor, reader->size * 3 ).raw_data();
331
[412]332                if ( reader->raw_size() > 0 )
[240]333                {
[417]334                        raw_copy_n( reader->raw_pointer(), reader->raw_size(), rdata );
[240]335                }
[482]336                data_node_info info;
337                info.name = make_name( reader->name );
338                info.parent_id = -1;
339                m_infos.push_back( info );
[417]340                m_meshes.push_back( result );
[240]341
342                reader->reset();
[238]343        }
344        delete reader;
345        return true;
346
347}
348
[534]349data_channel_set* nv::obj_loader::release_mesh_data( uint32 index, data_node_info& info )
[238]350{
[416]351        data_channel_set* result = m_meshes[ index ];
[482]352        info = m_infos[index];
[240]353        m_meshes[ index ] = nullptr;
[238]354        return result;
355}
356
[239]357nv::obj_loader::~obj_loader()
[238]358{
[240]359        for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
[238]360}
[287]361
Note: See TracBrowser for help on using the repository browser.