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

Revision 13041, 21.8 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 Loader for OSG
3
4  Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
5  OpenSceneGraph is (C) 2004 Robert Osfield
6********************************************************/
7
8#include "Object.h"
9
10#include <osg/Notify>
11
12#include <vector>
13#include <string>
14#include <sstream>
15
16using namespace lwosg;
17
18namespace
19{
20
21    bool triangle_is_clockwise(const osg::Vec3Array *points, int a, int b, int c)
22    {
23        const osg::Vec3 &A = (*points)[a];
24        const osg::Vec3 &B = (*points)[b];
25        const osg::Vec3 &C = (*points)[c];
26        float area2 = 0;
27        area2 += A.x() * B.y() - B.x() * A.y();
28        area2 += B.x() * C.y() - C.x() * B.y();
29        area2 += C.x() * A.y() - A.x() * C.y();
30        return area2 < 0;
31    }
32
33    float cylindrical_angle(float x, float y)
34    {
35        float r = sqrtf(x*x+y*y);
36        if (r == 0) return 0;
37        x /= r;
38        float a;
39        if (x < 0 && y >= 0) a = osg::PI_2 - acosf(-x);
40        else if (x < 0 && y < 0) a = acosf(-x) + osg::PI_2;
41        else if (x >= 0 && y >= 0) a = acosf(x) + 3 * osg::PI_2;
42        else if (x >= 0 && y < 0) a = 3 * osg::PI_2 - acosf(x);
43                else a = 0.0f;
44        return a/osg::PI/2;
45    }
46
47}
48
49Object::Object()
50:    csf_(new LwoCoordFixer)
51{
52}
53
54Object::Object(const iff::Chunk_list &data)
55:    csf_(new LwoCoordFixer)
56{
57    build(data);
58}
59
60void Object::build(const iff::Chunk_list &data)
61{
62    clips_.clear();
63    surfaces_.clear();
64    layers_.clear();
65    comment_ = "";
66    description_ = "";
67
68    OSG_INFO << "INFO: lwosg::Object: scanning clips\n";
69    scan_clips(data);
70    OSG_INFO << "INFO: lwosg::Object: scanning surfaces\n";
71    scan_surfaces(data);
72    OSG_INFO << "INFO: lwosg::Object: parsing LWO2 chunks and building object\n";
73    parse(data);
74    OSG_INFO << "INFO: lwosg::Object: generating normals\n";
75    generate_normals();
76    OSG_INFO << "INFO: lwosg::Object: generating automatic texture maps\n";
77    generate_auto_texture_maps();
78}
79
80void Object::scan_clips(const iff::Chunk_list &data)
81{
82    for (iff::Chunk_list::const_iterator i=data.begin(); i!=data.end(); ++i) {
83        const lwo2::FORM::CLIP *clip = dynamic_cast<const lwo2::FORM::CLIP *>(*i);
84        if (clip) {
85            clips_[clip->index] = Clip(clip);
86        }
87    }
88}
89
90void Object::scan_surfaces(const iff::Chunk_list &data)
91{
92    for (iff::Chunk_list::const_iterator i=data.begin(); i!=data.end(); ++i) {
93        const lwo2::FORM::SURF *surf = dynamic_cast<const lwo2::FORM::SURF *>(*i);
94        if (surf) {
95            surfaces_[surf->name] = Surface(surf, clips_);
96        }
97    }
98}
99
100void Object::parse(const iff::Chunk_list &data)
101{
102    typedef std::vector<std::string> String_list;
103    String_list tag_strings;
104
105    Layer current_layer;
106
107    for (iff::Chunk_list::const_iterator i=data.begin(); i!=data.end(); ++i) {
108
109        const lwo2::FORM::LAYR *layr = dynamic_cast<const lwo2::FORM::LAYR *>(*i);
110        if (layr) {
111            if (!current_layer.units().empty() || current_layer.get_layer_chunk()) {
112                layers_[current_layer.number()] = current_layer;
113            }
114            current_layer.set_layer_chunk(layr);
115            current_layer.units().clear();
116        }
117
118        const lwo2::FORM::PNTS *pnts = dynamic_cast<const lwo2::FORM::PNTS *>(*i);
119        if (pnts) {
120            Unit new_unit;
121            for (lwo2::FORM::PNTS::Point_list::const_iterator i=pnts->point_location.begin(); i!=pnts->point_location.end(); ++i) {
122                new_unit.points()->push_back(csf_->fix_point(osg::Vec3(i->X, i->Y, i->Z) /*+ current_layer.pivot()*/));
123            }
124            new_unit.shares().assign(new_unit.points()->size(), Unit::Index_list());
125            current_layer.units().push_back(new_unit);
126        }
127
128        const lwo2::FORM::VMAP *vmap = dynamic_cast<const lwo2::FORM::VMAP *>(*i);
129        if (vmap && !current_layer.units().empty()) {
130            std::string type(vmap->type.id, 4);
131            if (type == "WGHT") {
132                if (vmap->dimension != 1) {
133                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
134                    continue;
135                }
136                VertexMap *new_map = current_layer.units().back().weight_maps()->getOrCreate(vmap->name);
137                for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
138                    (*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), 0, 0, 0);
139                }
140            }
141            if (type == "MNVW") {
142                if (vmap->dimension != 1) {
143                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
144                    continue;
145                }
146                VertexMap *new_map = current_layer.units().back().subpatch_weight_maps()->getOrCreate(vmap->name);
147                for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
148                    (*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), 0, 0, 0);
149                }
150            }
151            if (type == "TXUV") {
152                if (vmap->dimension != 2) {
153                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
154                    continue;
155                }
156                VertexMap *new_map = current_layer.units().back().texture_maps()->getOrCreate(vmap->name);
157                for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
158                    (*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), 0, 0);
159                }
160            }
161            if (type == "RGB ") {
162                if (vmap->dimension != 3) {
163                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
164                    continue;
165                }
166                VertexMap *new_map = current_layer.units().back().rgb_maps()->getOrCreate(vmap->name);
167                for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
168                    (*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), i->value.at(2), 1);
169                }
170            }
171            if (type == "RGBA") {
172                if (vmap->dimension != 4) {
173                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
174                    continue;
175                }
176                VertexMap *new_map = current_layer.units().back().rgba_maps()->getOrCreate(vmap->name);
177                for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
178                    (*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), i->value.at(2), i->value.at(3));
179                }
180            }
181            if (type == "MORF") {
182                if (vmap->dimension != 3) {
183                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
184                    continue;
185                }
186                VertexMap *new_map = current_layer.units().back().displacement_maps()->getOrCreate(vmap->name);
187                for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
188                    (*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), i->value.at(2), 0);
189                }
190            }
191            if (type == "SPOT") {
192                if (vmap->dimension != 3) {
193                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
194                    continue;
195                }
196                VertexMap *new_map = current_layer.units().back().spot_maps()->getOrCreate(vmap->name);
197                for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
198                    (*new_map)[i->vert.index] = osg::Vec4(csf_->fix_point(osg::Vec3(i->value.at(0), i->value.at(1), i->value.at(2))), 0);
199                }
200            }
201        }
202
203        const lwo2::FORM::POLS *pols = dynamic_cast<const lwo2::FORM::POLS *>(*i);
204        if (pols && !current_layer.units().empty()) {
205            std::string type(pols->type.id, 4);
206            if (type != "FACE") {
207                OSG_INFO << "INFO: Lwo2Object: polygon list of type " << type << " not supported, rendering may be inaccurate" << std::endl;
208            }
209            for (lwo2::FORM::POLS::Polygon_list::const_iterator i=pols->polygons.begin(); i!=pols->polygons.end(); ++i) {
210                Polygon polygon;
211                bool must_invert_winding = csf_->invert_winding();
212
213                // FIX FOR A LIGHTWAVE BUG? MAYBE IT IS A FEATURE, I DON'T KNOW...
214                // if the first vertex is at a concave corner, we must invert the winding of the polygon
215                // beacuse it appears as flipped in Lighwave. Also, we tell the polygon to invert its normal.
216                // (not implemented yet)
217                /*if (i->vert.size() >= 4) {
218                    if (must_invert_winding == triangle_is_clockwise(current_layer.units().back().points(), i->vert.front().index, i->vert.back().index, i->vert[1].index)) {
219                        must_invert_winding = !must_invert_winding;
220                        polygon.set_invert_normal(true);
221                    }
222                }*/
223
224                if (must_invert_winding) {
225                    for (unsigned j=0; j<i->numvert; ++j) {
226                        int index = i->vert.at((i->numvert-j)%i->numvert).index;
227                        polygon.indices().push_back(index);
228                        current_layer.units().back().shares().at(index).push_back(current_layer.units().back().polygons().size());
229                    }
230                } else {
231                    for (unsigned j=0; j<i->numvert; ++j) {
232                        int index = i->vert.at(j).index;
233                        polygon.indices().push_back(index);
234                        current_layer.units().back().shares().at(index).push_back(current_layer.units().back().polygons().size());
235                    }
236                }
237                current_layer.units().back().polygons().push_back(polygon);
238            }
239        }
240
241        const lwo2::FORM::TAGS *tags = dynamic_cast<const lwo2::FORM::TAGS *>(*i);
242        if (tags) {
243            tag_strings = tags->tag_string;
244        }
245
246        const lwo2::FORM::PTAG *ptag = dynamic_cast<const lwo2::FORM::PTAG *>(*i);
247        if (ptag && !current_layer.units().empty()) {
248            std::string type(ptag->type.id, 4);
249            if (type == "SURF") {
250                for (lwo2::FORM::PTAG::Mapping_list::const_iterator i=ptag->mapping.begin(); i!=ptag->mapping.end(); ++i) {
251                    current_layer.units().back().polygons().at(i->poly.index).set_surface(&surfaces_[tag_strings.at(i->tag)]);
252                }
253            }
254            if (type == "PART") {
255                for (lwo2::FORM::PTAG::Mapping_list::const_iterator i=ptag->mapping.begin(); i!=ptag->mapping.end(); ++i) {
256                    current_layer.units().back().polygons().at(i->poly.index).set_part_name(tag_strings.at(i->tag));
257                }
258            }
259            if (type == "SMGP") {
260                for (lwo2::FORM::PTAG::Mapping_list::const_iterator i=ptag->mapping.begin(); i!=ptag->mapping.end(); ++i) {
261                    current_layer.units().back().polygons().at(i->poly.index).set_smoothing_group(tag_strings.at(i->tag));
262                }
263            }
264        }
265
266        const lwo2::FORM::VMAD *vmad = dynamic_cast<const lwo2::FORM::VMAD *>(*i);
267        if (vmad && !current_layer.units().empty()) {
268            std::string type(vmad->type.id, 4);
269            if (type == "WGHT") {
270                if (vmad->dimension != 1) {
271                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " discontinuous vertex map dimension: " << vmad->dimension << std::endl;
272                    continue;
273                }
274                for (lwo2::FORM::VMAD::Mapping_list::const_iterator i=vmad->mapping.begin(); i!=vmad->mapping.end(); ++i) {
275                    VertexMap *this_map = current_layer.units().back().polygons().at(i->poly.index).weight_maps()->getOrCreate(vmad->name);
276                    (*this_map)[i->vert.index] = osg::Vec4(i->value.at(0), 0, 0, 0);
277                }
278            }
279            if (type == "TXUV") {
280                if (vmad->dimension != 2) {
281                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " discontinuous vertex map dimension: " << vmad->dimension << std::endl;
282                    continue;
283                }
284                for (lwo2::FORM::VMAD::Mapping_list::const_iterator i=vmad->mapping.begin(); i!=vmad->mapping.end(); ++i) {
285                    VertexMap *this_map = current_layer.units().back().polygons().at(i->poly.index).texture_maps()->getOrCreate(vmad->name);
286                    (*this_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), 0, 0);
287                }
288            }
289            if (type == "RGB ") {
290                if (vmad->dimension != 3) {
291                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " discontinuous vertex map dimension: " << vmad->dimension << std::endl;
292                    continue;
293                }
294                for (lwo2::FORM::VMAD::Mapping_list::const_iterator i=vmad->mapping.begin(); i!=vmad->mapping.end(); ++i) {
295                    VertexMap *this_map = current_layer.units().back().polygons().at(i->poly.index).rgb_maps()->getOrCreate(vmad->name);
296                    (*this_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), i->value.at(2), 1);
297                }
298            }
299            if (type == "RGBA") {
300                if (vmad->dimension != 4) {
301                    OSG_WARN << "Warning: Lwo2Object: invalid " << type << " discontinuous vertex map dimension: " << vmad->dimension << std::endl;
302                    continue;
303                }
304                for (lwo2::FORM::VMAD::Mapping_list::const_iterator i=vmad->mapping.begin(); i!=vmad->mapping.end(); ++i) {
305                    VertexMap *this_map = current_layer.units().back().polygons().at(i->poly.index).rgba_maps()->getOrCreate(vmad->name);
306                    (*this_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), i->value.at(2), i->value.at(3));
307                }
308            }
309        }
310
311        const lwo2::FORM::DESC *desc = dynamic_cast<const lwo2::FORM::DESC *>(*i);
312        if (desc) {
313            description_ = desc->description_line;
314        }
315
316        const lwo2::FORM::TEXT *text = dynamic_cast<const lwo2::FORM::TEXT *>(*i);
317        if (text) {
318            comment_ = text->comment;
319        }
320
321    }
322
323    if (!current_layer.units().empty() || current_layer.get_layer_chunk()) {
324        layers_[current_layer.number()] = current_layer;
325    }
326}
327
328void Object::generate_normals()
329{
330    for (Layer_map::iterator i=layers_.begin(); i!=layers_.end(); ++i) {
331        for (Layer::Unit_list::iterator j=i->second.units().begin(); j!=i->second.units().end(); ++j) {
332            j->generate_normals();
333        }
334    }
335}
336
337void Object::generate_auto_texture_maps()
338{
339    for (Surface_map::iterator i=surfaces_.begin(); i!=surfaces_.end(); ++i) {
340        for (Surface::Block_map::iterator j=i->second.blocks().begin(); j!=i->second.blocks().end(); ++j) {
341            Block &block = j->second;
342            if (block.get_type() == "IMAP") {
343                if (block.get_image_map().projection == Image_map::UV) continue;
344
345                Image_map::Axis_type axis = block.get_image_map().axis;
346
347                std::ostringstream oss;
348                oss << "Auto_map_" << &block;
349                std::string map_name = oss.str();
350
351                OSG_DEBUG << "DEBUG INFO: lwosg::Object: creating automatic texture map '" << map_name << "'\n";
352
353                for (Layer_map::iterator k=layers_.begin(); k!=layers_.end(); ++k) {
354                    for (Layer::Unit_list::iterator h=k->second.units().begin(); h!=k->second.units().end(); ++h) {
355
356                        osg::ref_ptr<VertexMap> new_map = new VertexMap;
357                        (*h->texture_maps())[map_name] = new_map.get();
358
359                        if (block.get_image_map().projection == Image_map::FRONT_PROJECTION) {
360                            OSG_WARN << "Warning: lwosg::Object: front projection is not supported" << std::endl;
361                        }
362
363                        if (block.get_image_map().projection == Image_map::CUBIC) {
364
365                            for (Unit::Polygon_list::iterator p=h->polygons().begin(); p!=h->polygons().end(); ++p) {
366
367                                Polygon &poly = *p;
368                                osg::ref_ptr<VertexMap> local_uv_map = poly.texture_maps()->getOrCreate(map_name);
369
370                                osg::Vec3 N = csf_->fix_vector(poly.face_normal(h->points()));
371
372                                Image_map::Axis_type axis = Image_map::X;
373                                if (N.y() > N.x() && N.y() > N.z()) axis = Image_map::Y;
374                                if (-N.y() > N.x() && -N.y() > N.z()) axis = Image_map::Y;
375                                if (N.z() > N.x() && N.z() > N.y()) axis = Image_map::Z;
376                                if (-N.z() > N.x() && -N.z() > N.y()) axis = Image_map::Z;
377
378                                for (Polygon::Index_list::iterator i=poly.indices().begin(); i!=poly.indices().end(); ++i) {
379
380                                    // fetch vertex
381                                    osg::Vec3 P = csf_->fix_point((*h->points())[*i]);
382
383                                    // setup scale/translation/rotation
384                                    P = block.setup_texture_point(P);
385
386                                    osg::Vec2 uv;
387                                    switch (axis) {
388                                        case Image_map::X: uv.set(P.z(), P.y()); break;
389                                        case Image_map::Y: uv.set(P.x(), P.z()); break;
390                                        case Image_map::Z: uv.set(P.x(), P.y()); break;
391                                        default: ;
392                                    }
393                                    uv += osg::Vec2(0.5f, 0.5f);
394
395                                    osg::Vec4 map_value(uv.x(), uv.y(), 0, 0);
396
397                                    if ((new_map->find(*i) != new_map->end()) && (map_value != (*new_map.get())[*i])) {
398                                        (*local_uv_map.get())[*i] = map_value;
399                                    } else {
400                                        (*new_map.get())[*i] = map_value;
401                                    }
402                                }
403                            }
404                        } else {
405
406                            for (unsigned p=0; p<h->points()->size(); ++p) {
407
408                                // fetch vertex
409                                osg::Vec3 P = csf_->fix_point((*h->points())[p]);
410
411                                // setup scale/translation/rotation
412                                P = block.setup_texture_point(P);
413
414                                osg::Vec2 uv;
415
416                                if (block.get_image_map().projection == Image_map::PLANAR) {
417                                    switch (axis) {
418                                        case Image_map::X: uv.set(P.z(), P.y()); break;
419                                        case Image_map::Y: uv.set(P.x(), P.z()); break;
420                                        case Image_map::Z: uv.set(P.x(), P.y()); break;
421                                        default: ;
422                                    }
423                                    uv += osg::Vec2(0.5f, 0.5f);
424                                }
425
426                                if (block.get_image_map().projection == Image_map::CYLINDRICAL) {
427                                    switch (axis) {
428                                        case Image_map::X: uv.set(cylindrical_angle(-P.z(), -P.y()), P.x()); break;
429                                        case Image_map::Y: uv.set(cylindrical_angle(P.x(), P.z()), P.y()); break;
430                                        case Image_map::Z: uv.set(cylindrical_angle(P.x(), -P.y()), P.z()); break;
431                                        default: ;
432                                    }
433                                    uv.x() *= block.get_image_map().wrap_amount_w;
434                                    uv += osg::Vec2(0, 0.5f);
435                                }
436
437                                if (block.get_image_map().projection == Image_map::SPHERICAL) {
438                                    float r = P.length();
439                                    if (r != 0) {
440                                        switch (axis) {
441                                            case Image_map::X: uv.set(cylindrical_angle(-P.z(), -P.y()), (asinf(P.x()/r) + osg::PI_2) / osg::PI); break;
442                                            case Image_map::Y: uv.set(cylindrical_angle(P.x(), P.z()), (asinf(P.y()/r) + osg::PI_2) / osg::PI); break;
443                                            case Image_map::Z: uv.set(cylindrical_angle(P.x(), -P.y()), (asinf(P.z()/r) + osg::PI_2) / osg::PI); break;
444                                            default: ;
445                                        }
446                                    }
447                                    uv.x() *= block.get_image_map().wrap_amount_w;
448                                    uv.y() *= block.get_image_map().wrap_amount_h;
449                                }
450
451                                (*new_map.get())[p] = osg::Vec4(uv.x(), uv.y(), 0, 0);
452                            }
453                        }
454                    }
455                }
456
457                block.get_image_map().uv_map = map_name;
458                block.get_image_map().projection = Image_map::UV;
459            }
460        }
461    }
462}
Note: See TracBrowser for help on using the browser.