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