root/OpenSceneGraph/trunk/src/osgPlugins/lwo/old_Lwo2.cpp @ 13041

Revision 13041, 20.5 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Lightwave Object version 2 loader for Open Scene Graph
3 * Version 2 introduced in Lightwave v6.0
4 *
5 * Copyright (C) 2002 Pavel Moloshtan <pasha@moloshtan.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
20 *
21 * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for
22 * real-time rendering of large 3D photo-realistic models.
23 * The OSG homepage is http://www.openscenegraph.org/
24 */
25
26#include <osg/Notify>
27#include <osg/Geode>
28#include <osg/Group>
29#include <osg/Texture2D>
30#include <osg/Material>
31#include <osg/CullFace>
32#include <osg/BlendFunc>
33#include <osg/io_utils>
34
35#include <osgDB/Registry>
36#include <osgDB/ReadFile>
37
38#include <iostream>
39#include <fstream>
40#include <string.h>
41
42#include "old_Lwo2.h"
43#include "old_Lwo2Layer.h"
44#include "lwo2read.h"
45
46Lwo2::Lwo2():
47  _current_layer(0),
48  _successfully_read(false)
49{
50}
51
52Lwo2::~Lwo2()
53{
54  // delete all layers
55  for (IteratorLayers itr = _layers.begin(); itr != _layers.end(); itr++)
56    {
57      delete (*itr).second;
58    }
59
60  // delete all surfaces
61  for (IteratorSurfaces itr_surf = _surfaces.begin(); itr_surf != _surfaces.end(); itr_surf++)
62    {
63      delete (*itr_surf).second;
64    }
65}
66
67bool
68Lwo2::ReadFile( const string& filename )
69{
70    OSG_INFO  << "Opening file: " << filename << std::endl;
71
72    _fin.open(filename.c_str(), ios::in | ios::binary );
73    if (!_fin.is_open())
74    {
75        OSG_INFO << "Can't open file '" << filename << "'" << std::endl;
76        return false;
77    }
78
79    // checking EA-IFF85 format
80    // http://www.lightwave3d.com/developer/75lwsdk/docs/filefmts/eaiff85.html
81    if (_read_uint() != tag_FORM)
82    {
83        OSG_INFO << "File '" << filename << "' is not IFF format file." << std::endl;
84        _fin.close();
85        return false;
86    }
87    else
88    {
89        OSG_INFO << "Detected EA-IFF85 format" << std::endl;
90    }
91
92    unsigned int form_size = _read_uint();
93    OSG_INFO << "Form size: " << form_size << std::endl;
94
95    // checking LWO2 format
96    // http://www.lightwave3d.com/developer/75lwsdk/docs/filefmts/lwo2.html
97    if (_read_uint() != tag_LWO2)
98    {
99        unsigned long make_id(const char*);
100        OSG_INFO << "File '" << filename << "' is not LWO2 format file." << std::endl;
101        _fin.close();
102        return false;
103    }
104    else
105    {
106        OSG_INFO << "Detected LWO2 format" << std::endl;
107    }
108
109    unsigned long read_bytes = 4;
110    unsigned long current_tag_name;
111    unsigned long current_tag_size;
112
113    // main loop for reading tags
114    while (read_bytes < form_size && !_fin.eof())
115    {
116        current_tag_name = _read_uint();
117        current_tag_size = _read_uint();
118        read_bytes += 8 + current_tag_size + current_tag_size % 2;
119
120        _print_tag(current_tag_name, current_tag_size);
121
122        if (current_tag_name == tag_TAGS)
123        {
124            _read_tag_strings(current_tag_size);
125        }
126        else if (current_tag_name == tag_LAYR)
127        {
128            _read_layer(current_tag_size);
129        }
130        else if (current_tag_name == tag_PNTS)
131        {
132            _read_points(current_tag_size);
133        }
134        else if (current_tag_name == tag_VMAP)
135        {
136            _read_vertex_mapping(current_tag_size);
137        }
138        else if (current_tag_name == tag_VMAD)
139        {
140            _read_polygons_mapping(current_tag_size);
141        }
142        else if (current_tag_name == tag_POLS)
143        {
144            _read_polygons(current_tag_size);
145        }
146        else if (current_tag_name == tag_PTAG)
147        {
148            _read_polygon_tag_mapping(current_tag_size);
149        }
150        else if (current_tag_name == tag_CLIP)
151        {
152            _read_image_definition(current_tag_size);
153        }
154        else if (current_tag_name == tag_SURF)
155        {
156            _read_surface(current_tag_size);
157        }
158        else
159        {
160            _fin.seekg(current_tag_size + current_tag_size % 2, ios::cur);
161        }
162    }
163
164    _fin.close();
165
166    return _successfully_read = true;
167}
168
169unsigned char
170Lwo2::_read_char()
171{
172  char c = 0;
173  if (_fin.is_open())
174    {
175      _fin.read(&c, 1);
176    }
177  return static_cast<unsigned char>(c);
178}
179
180unsigned int
181Lwo2::_read_uint()
182{
183  return
184    (_read_char() << 24) |
185    (_read_char() << 16) |
186    (_read_char() <<  8) |
187    _read_char();
188}
189
190unsigned short
191Lwo2::_read_short()
192{
193  return
194    (_read_char() <<  8) |
195    _read_char();
196}
197
198float
199Lwo2::_read_float()
200{
201  return lwo2::changeType4<float, unsigned int>(_read_uint());
202}
203
204// read null terminated string
205
206string&
207Lwo2::_read_string(string& str)
208{
209  char c;
210  do {
211    c = _read_char();
212    str += c;
213  } while (c != 0);
214
215  // if length of string (including \0) is odd skip another byte
216  if (str.length() % 2) {
217    _read_char();
218  }
219
220  return str;
221}
222
223// print 4-char tag to debug out
224
225void
226Lwo2::_print_tag(unsigned int tag, unsigned int size) {
227  OSG_DEBUG << "Found tag "
228                     << char(tag >> 24)
229                     << char(tag >> 16)
230                     << char(tag >>  8)
231                     << char(tag)
232                     << " size " << size << " bytes"
233                     << std::endl;
234}
235
236// print 4-char type
237void
238Lwo2::_print_type(unsigned int type) {
239  OSG_DEBUG << "  type   \t"
240                     << char(type >> 24)
241                     << char(type >> 16)
242                     << char(type >>  8)
243                     << char(type)
244                     << std::endl;
245}
246
247// read TAGS info
248
249void
250Lwo2::_read_tag_strings(unsigned long size)
251{
252    while (size > 0)
253    {
254        string name;
255        _read_string(name);
256        size -= name.length() + name.length() % 2;
257        _tags.push_back(name);
258
259        OSG_DEBUG << "  name   \t'" << name.c_str() << "'" << std::endl;
260    }
261}
262
263// read LAYR info
264
265void Lwo2::_read_layer(unsigned long size)
266{
267    unsigned short number = _read_short();
268    size -= 2;
269
270    Lwo2Layer* layer = new Lwo2Layer();
271    _layers[number] = layer;
272    _current_layer = layer;
273    layer->_number = number;
274
275    layer->_flags = _read_short();
276    size -= 2;
277
278    float x = _read_float();
279    float y = _read_float();
280    float z = _read_float();
281    layer->_pivot.set(x, y, z);
282    size -= 4 * 3;
283
284    _read_string(layer->_name);
285    size -= layer->_name.length() + layer->_name.length() % 2;
286
287    if (size > 2)
288    {
289        layer->_parent = _read_short();
290        size -= 2;
291    }
292
293    _fin.seekg(size + size % 2, ios::cur);
294}
295
296// read PNTS info
297
298void Lwo2::_read_points(unsigned long size)
299{
300    int count = size / 12;
301    OSG_DEBUG << "  count \t" << count << std::endl;
302
303    while (count--)
304    {
305        PointData point;
306
307        float x = _read_float();
308        float y = _read_float();
309        float z = _read_float();
310        point.coord = Vec3(x, y, z);
311        _current_layer->_points.push_back(point);
312    }
313}
314
315// read VMAP info
316
317void Lwo2::_read_vertex_mapping(unsigned long size)
318{
319    unsigned int type = _read_uint();
320    size -= 4;
321
322    _print_type(type);
323
324    short dimension = _read_short();
325    size -= 2;
326
327    OSG_DEBUG << "  dimension \t" << dimension << std::endl;
328
329    string name;
330    _read_string(name);
331    size -= name.length() + name.length() % 2;
332    OSG_DEBUG << "  name   \t'" << name.c_str() << "'" << std::endl;
333
334    if (type == tag_TXUV && dimension == 2)
335    {
336        int count = size / 10;
337        unsigned short n;
338        float u;
339        float v;
340        while (count--)
341        {
342            n = _read_short();
343            u = _read_float();
344            v = _read_float();
345
346            // point coords must be read previously
347            if (n < _current_layer->_points.size())
348            {
349                _current_layer->_points[n].texcoord = Vec2(u, v);
350            }
351        }
352    }
353    else
354    {
355
356        // not recognized yet
357        OSG_DEBUG << "  skipping..." << std::endl;
358        _fin.seekg(size + size % 2, ios::cur);
359    }
360}
361
362// read POLS info
363
364void
365Lwo2::_read_polygons(unsigned long size)
366{
367    unsigned int type = _read_uint();
368    size -= 4;
369
370    _print_type(type);
371
372    if (type == tag_FACE)
373    {
374        unsigned short vertex_count;
375
376        while (size > 0)
377        {
378            PointData point;
379            vertex_count = _read_short() & 0x03FF;
380            size -= 2;
381
382            PointsList points_list;
383
384            while (vertex_count--)
385            {
386                unsigned short point_index = _read_short();
387
388                point = _current_layer->_points[point_index];
389                point.point_index = point_index;
390
391                points_list.push_back(point);
392                size -= 2;
393            }
394
395            _current_layer->_polygons.push_back(points_list);
396        }
397    }
398    else
399    {
400
401        // not recognized yet
402        OSG_DEBUG << "  skipping..." << std::endl;
403        _fin.seekg(size + size % 2, ios::cur);
404    }
405}
406
407// read PTAG info
408
409void Lwo2::_read_polygon_tag_mapping(unsigned long size)
410{
411    unsigned int type = _read_uint();
412    size -= 4;
413
414    _print_type(type);
415
416    if (type == tag_SURF)
417    {
418        int count = size / 4;
419        _current_layer->_polygons_tag.resize(count);
420
421        short polygon_index;
422        short tag_index;
423
424        while (count--)
425        {
426            polygon_index = _read_short();
427            tag_index = _read_short();
428            _current_layer->_polygons_tag[polygon_index] = tag_index;
429        }
430    }
431    else
432    {
433
434        // not recognized yet
435        OSG_DEBUG << "  skipping..." << std::endl;
436        _fin.seekg(size + size % 2, ios::cur);
437    }
438}
439
440// read VMAD info
441
442void Lwo2::_read_polygons_mapping(unsigned long size)
443{
444    unsigned int type = _read_uint();
445    size -= 4;
446
447    _print_type(type);
448
449    short dimension = _read_short();
450    size -= 2;
451
452    OSG_DEBUG << "  dimension \t" << dimension << std::endl;
453
454    string name;
455    _read_string(name);
456    size -= name.length() + name.length() % 2;
457    OSG_DEBUG << "  name   \t'" << name.c_str() << "'" << std::endl;
458
459    if (type == tag_TXUV && dimension == 2)
460    {
461        OSG_DEBUG << "  polygons mappings:" << endl;
462        OSG_DEBUG << "\tpoint\tpolygon\ttexcoord" <<  endl;
463        OSG_DEBUG << "\t=====\t=======\t========" <<  endl;
464
465        int count = size / 12;
466
467        short point_index;
468        short polygon_index;
469        float u;
470        float v;
471        while (count--)
472        {
473            point_index = _read_short();
474            polygon_index = _read_short();
475            u = _read_float();
476            v = _read_float();
477
478            OSG_DEBUG << "    \t" << point_index << "\t" << polygon_index << "\t" << Vec2(u, v) << endl;
479
480            // apply texture coordinates
481            PointsList& points_list = _current_layer->_polygons[polygon_index];
482            for (unsigned int i = 0; i < points_list.size(); i++)
483            {
484                if (points_list[i].point_index == point_index)
485                {
486                    points_list[i].texcoord = Vec2(u, v);
487                }
488            }
489        }
490    }
491    else
492    {
493
494        // not recognized yet
495        OSG_DEBUG << "  skipping..." << std::endl;
496        _fin.seekg(size + size % 2, ios::cur);
497    }
498
499}
500
501// read CLIP info
502
503void
504Lwo2::_read_image_definition(unsigned long size)
505{
506    unsigned int index = _read_uint();
507    size -= 4;
508    OSG_DEBUG << "  index  \t" << index << std::endl;
509
510    unsigned int type;
511    while (size > 0)
512    {
513        type = _read_uint();
514        size -= 4;
515
516        _print_type(type);
517
518        // size of name
519        // not included in specification ??
520        _read_short();
521        size -= 2;
522
523        string name;
524        _read_string(name);
525        size -= name.length() + name.length() % 2;
526
527        if (index + 1 > _images.size())
528        {
529          _images.resize(index + 1);
530        }
531
532        _images[index] = name.c_str();
533
534        OSG_DEBUG << "  name   \t'" << name.c_str() << "'" << std::endl;
535    }
536}
537
538// read SURF info
539
540void Lwo2::_read_surface(unsigned long size)
541{
542    Lwo2Surface* surface = new Lwo2Surface();
543    surface->image_index = -1;
544    surface->state_set = NULL;
545
546    _read_string(surface->name);
547    size -= surface->name.length() + surface->name.length() % 2;
548    OSG_DEBUG << "  name   \t'" << surface->name.c_str() << "'" << std::endl;
549
550    string source;
551    _read_string(source);
552    size -= source.length() + source.length() % 2;
553    OSG_DEBUG << "  source   \t'" << source.c_str() << "'" << std::endl;
554
555    unsigned long current_tag_name;
556    unsigned short current_tag_size;
557
558    while (size > 0 && !_fin.eof())
559    {
560        current_tag_name = _read_uint();
561        size -= 4;
562        current_tag_size = _read_short();
563        size -= 2;
564
565        _print_tag(current_tag_name, current_tag_size);
566
567        if (current_tag_name == tag_BLOK)
568        {
569
570            // BLOK
571            int blok_size = current_tag_size;
572            size -= blok_size;
573            while (blok_size > 0)
574            {
575                current_tag_name = _read_uint();
576                blok_size -= 4;
577                current_tag_size = _read_short();
578                blok_size -= 2;
579                OSG_DEBUG << "  ";
580                _print_tag(current_tag_name, current_tag_size);
581
582                if (current_tag_name == tag_IMAG)
583                {
584                    surface->image_index = _read_short();
585                    OSG_DEBUG << "    image index\t" << surface->image_index << std::endl;
586                    blok_size -= 2;
587                }
588                else if (current_tag_name == tag_IMAP)
589                {
590
591                    // IMAP
592                    int imap_size = current_tag_size;
593                    blok_size -= imap_size;
594
595                    string ordinal;
596                    _read_string(ordinal);
597                    imap_size -= ordinal.length() + ordinal.length() % 2;
598                    OSG_DEBUG << "    ordinal   \t'" << ordinal.c_str() << "'" << std::endl;
599
600                    while(imap_size > 0)
601                    {
602                        current_tag_name = _read_uint();
603                        imap_size -= 4;
604                        current_tag_size = _read_short();
605                        imap_size -= 2;
606                        OSG_DEBUG << "    ";
607                        _print_tag(current_tag_name, current_tag_size);
608
609                        _fin.seekg(current_tag_size + current_tag_size % 2, ios::cur);
610                        imap_size -= current_tag_size + current_tag_size % 2;
611                    }
612                }
613                else
614                {
615                    _fin.seekg(current_tag_size + current_tag_size % 2, ios::cur);
616                    blok_size -= current_tag_size + current_tag_size % 2;
617                }
618            }
619        }
620        else if (current_tag_name == tag_COLR)
621        {
622            float r = _read_float();
623            float g = _read_float();
624            float b = _read_float();
625            surface->color.set(r,g,b);
626            OSG_DEBUG << "  color   \t" << surface->color << std::endl;
627            current_tag_size -= 12;
628            size -= 12;
629
630            // skip ununderstooded envelope
631            _fin.seekg(current_tag_size + current_tag_size % 2, ios::cur);
632            size -= current_tag_size + current_tag_size % 2;
633        }
634        else
635        {
636          _fin.seekg(current_tag_size + current_tag_size % 2, ios::cur);
637          size -= current_tag_size + current_tag_size % 2;
638        }
639    }
640
641    _surfaces[surface->name] = surface;
642}
643
644// Generation OSG Geode object from parsed LWO2 file
645
646bool
647Lwo2::GenerateGroup( Group& group )
648{
649  if (!_successfully_read) return false;
650
651  // generate StateSets for each surface
652  _generate_statesets_from_surfaces();
653
654  // create geometry from all layers
655  for (IteratorLayers itr = _layers.begin(); itr != _layers.end(); itr++)
656    {
657      osg::Geode* geode = new osg::Geode();
658
659      OSG_DEBUG << "Generate geode for layer " << (*itr).first << std::endl;
660      DrawableToTagMapping tag_mapping;
661      (*itr).second->GenerateGeode(*geode, _tags.size(), tag_mapping);
662
663      // assign StateSet for each PTAG group
664      for (unsigned int i = 0; i < geode->getNumDrawables(); i++)
665        {
666          OSG_DEBUG << "  Assigning surface " << _tags[tag_mapping[i]] << " to drawable " << i << std::endl;
667          geode->getDrawable(i)->setStateSet(_surfaces[_tags[tag_mapping[i]]]->state_set);
668
669          // copy material color to color array of geometry
670          // because when lighting off color not applyed
671          Geometry* geometry = geode->getDrawable(i)->asGeometry();
672          if (geometry)
673            {
674              Material* material = dynamic_cast<Material*>(_surfaces[_tags[tag_mapping[i]]]->state_set->getAttribute(StateAttribute::MATERIAL));
675              if (material) {
676                Vec4Array* colors = new Vec4Array();
677                colors->push_back(material->getDiffuse(Material::FRONT_AND_BACK));
678                geometry->setColorBinding(Geometry::BIND_OVERALL);
679                geometry->setColorArray(colors);
680              }
681            }
682        }
683
684      group.addChild(geode);
685    }
686
687  return true;
688}
689
690// generate StateSets for each surface
691void
692Lwo2::_generate_statesets_from_surfaces()
693{
694    ref_ptr<BlendFunc> blending = new BlendFunc();
695    blending->setFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
696    ref_ptr<CullFace> culling = new CullFace();
697    culling->setMode(CullFace::BACK);
698
699    for (IteratorSurfaces itr_surf = _surfaces.begin(); itr_surf != _surfaces.end(); itr_surf++)
700    {
701        Lwo2Surface* surface = (*itr_surf).second;
702        StateSet* state_set = new osg::StateSet;
703        bool use_blending = false;
704
705        OSG_DEBUG << "\tcreating surface " << (*itr_surf).first << std::endl;
706
707        // check if exist texture image for this surface
708        if (surface->image_index >= 0)
709        {
710            osg::ref_ptr<Image> image = osgDB::readRefImageFile(_images[surface->image_index]);
711            OSG_DEBUG << "\tloaded image '" << _images[surface->image_index] << "'" << std::endl;
712            OSG_DEBUG << "\tresult - " << image << std::endl;
713            if (image.valid())
714            {
715                // create texture
716                Texture2D* texture = new osg::Texture2D;
717                texture->setImage(image.get());
718                state_set->setTextureAttributeAndModes(0, texture, StateAttribute::ON);
719
720                // setup texture wrapping
721                texture->setWrap(Texture::WRAP_S, Texture::REPEAT);
722                texture->setWrap(Texture::WRAP_T, Texture::REPEAT);
723
724                // detect blending
725                if (image->getPixelSizeInBits() == 32)
726                {
727                    for (int i = 0; i < image->s(); i++)
728                    {
729                        for (int j = 0; j < image->t(); j++)
730                        {
731                            unsigned char* data = image->data(i, j);
732                            data++; // skip r
733                            data++; // skip g
734                            data++; // skip b
735
736                            // check alpha
737                            if (*data < 255)
738                            {
739                                use_blending = true;
740                                break;
741                            }
742                        }
743                        if (use_blending) break;
744                    }
745                }
746            }
747        }
748
749        // set color
750        Material* material = new Material();
751        material->setDiffuse(Material::FRONT_AND_BACK, Vec4(surface->color, 1.0f));
752        state_set->setAttribute(material);
753
754        state_set->setMode(GL_NORMALIZE, StateAttribute::ON);
755
756        if (use_blending)
757        {
758            // setup blending
759            state_set->setAttribute(blending.get());
760            state_set->setMode(GL_BLEND, StateAttribute::ON);
761
762            // setup depth sorting
763            state_set->setRenderingHint(StateSet::TRANSPARENT_BIN);
764        }
765        else
766        {
767            // setup culling
768            state_set->setAttribute(culling.get());
769            state_set->setMode(GL_CULL_FACE, StateAttribute::ON);
770        }
771
772        surface->state_set = state_set;
773    }
774}
775
776// makes 4-byte integer tag from four chars
777// used in IFF standard
778
779unsigned long make_id(const char* tag)
780{
781    unsigned long result = 0;
782    for (unsigned int i = 0; i < strlen(tag) && i < 4; i++)
783    {
784        result <<= 8;
785        result += int(tag[i]);
786    }
787    return result;
788}
Note: See TracBrowser for help on using the browser.