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