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

Revision 13041, 16.1 kB (checked in by robert, 2 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 "Surface.h"
9
10#include <osg/Material>
11#include <osg/CullFace>
12#include <osg/Texture2D>
13#include <osg/TexEnvCombine>
14#include <osg/TexGen>
15#include <osg/BlendFunc>
16#include <osg/Notify>
17
18#include <osgFX/SpecularHighlights>
19
20#include <osgDB/ReadFile>
21
22using namespace lwosg;
23
24namespace
25{
26
27    osg::Texture::WrapMode osg_wrap_mode(Image_map::Wrap_type w)
28    {
29        switch (w) {
30            case Image_map::RESET: return osg::Texture::CLAMP;
31            case Image_map::REPEAT: return osg::Texture::REPEAT;
32            case Image_map::MIRROR: return osg::Texture::MIRROR;
33            case Image_map::EDGE: return osg::Texture::CLAMP_TO_EDGE;
34            default: return osg::Texture::REPEAT;
35        };
36    }
37
38}
39
40Surface::Surface()
41:    base_color_(0.784f, 0.784f, 0.784f),
42    diffuse_(1.0f),
43    luminosity_(0),
44    specularity_(0),
45    reflection_(0),
46    transparency_(0),
47    translucency_(0),
48    glossiness_(0.4f),
49    sidedness_(FRONT_ONLY),
50    max_smoothing_angle_(0)
51{
52}
53
54Surface::Surface(const lwo2::FORM::SURF *surf, const Clip_map &clips)
55:    base_color_(0.784f, 0.784f, 0.784f),
56    diffuse_(1.0f),
57    luminosity_(0),
58    specularity_(0),
59    reflection_(0),
60    transparency_(0),
61    translucency_(0),
62    glossiness_(0.4f),
63    sidedness_(FRONT_ONLY),
64    max_smoothing_angle_(0)
65{
66    compile(surf, clips);
67}
68
69void Surface::compile(const lwo2::FORM::SURF *surf, const Clip_map &clips)
70{
71    // invalidate the stateset so it will be rebuilt
72    stateset_ = 0;
73
74    name_ = surf->name;
75
76    for (iff::Chunk_list::const_iterator j=surf->attributes.begin(); j!=surf->attributes.end(); ++j) {
77
78        const lwo2::FORM::SURF::COLR *colr = dynamic_cast<const lwo2::FORM::SURF::COLR *>(*j);
79        if (colr) base_color_ = osg::Vec3(colr->base_color.red, colr->base_color.green, colr->base_color.blue);
80
81        const lwo2::FORM::SURF::DIFF *diff = dynamic_cast<const lwo2::FORM::SURF::DIFF *>(*j);
82        if (diff) diffuse_ = diff->intensity.fraction;
83
84        const lwo2::FORM::SURF::LUMI *lumi = dynamic_cast<const lwo2::FORM::SURF::LUMI *>(*j);
85        if (lumi) luminosity_ = lumi->intensity.fraction;
86
87        const lwo2::FORM::SURF::SPEC *spec = dynamic_cast<const lwo2::FORM::SURF::SPEC *>(*j);
88        if (spec) specularity_ = spec->intensity.fraction;
89
90        const lwo2::FORM::SURF::REFL *refl = dynamic_cast<const lwo2::FORM::SURF::REFL *>(*j);
91        if (refl) reflection_ = refl->intensity.fraction;
92
93        const lwo2::FORM::SURF::TRAN *tran = dynamic_cast<const lwo2::FORM::SURF::TRAN *>(*j);
94        if (tran) transparency_ = tran->intensity.fraction;
95
96        const lwo2::FORM::SURF::TRNL *trnl = dynamic_cast<const lwo2::FORM::SURF::TRNL *>(*j);
97        if (trnl) translucency_ = trnl->intensity.fraction;
98
99        const lwo2::FORM::SURF::GLOS *glos = dynamic_cast<const lwo2::FORM::SURF::GLOS *>(*j);
100        if (glos) glossiness_ = glos->glossiness.fraction;
101
102        const lwo2::FORM::SURF::SIDE *side = dynamic_cast<const lwo2::FORM::SURF::SIDE *>(*j);
103        if (side) sidedness_ = static_cast<Sidedness>(side->sidedness);
104
105        const lwo2::FORM::SURF::SMAN *sman = dynamic_cast<const lwo2::FORM::SURF::SMAN *>(*j);
106        if (sman) max_smoothing_angle_ = sman->max_smoothing_angle.radians;
107
108        const lwo2::FORM::SURF::VCOL *vcol = dynamic_cast<const lwo2::FORM::SURF::VCOL *>(*j);
109        if (vcol) {
110            color_map_intensity_ = vcol->intensity.fraction;
111            color_map_type_ = std::string(vcol->vmap_type.id, 4);
112            color_map_name_ = vcol->name;
113        }
114
115        const lwo2::FORM::SURF::BLOK *blok = dynamic_cast<const lwo2::FORM::SURF::BLOK *>(*j);
116        if (blok) {
117            Block new_block(blok);
118            if (new_block.get_type() == "IMAP") {
119                Clip_map::const_iterator i = clips.find(new_block.get_image_map().image_map);
120                if (i != clips.end()) {
121                    new_block.get_image_map().clip = &i->second;
122                } else {
123                    OSG_WARN << "Warning: lwosg::Surface: cannot find clip number " << new_block.get_image_map().image_map << std::endl;
124                }
125            }
126            blocks_.insert(Block_map::value_type(new_block.get_ordinal(), new_block));
127        }
128    }
129}
130
131void Surface::generate_stateset(unsigned int max_tex_units, bool force_arb_compression, const osgDB::ReaderWriter::Options* db_options) const
132{
133    if (!stateset_.valid()) {
134
135        stateset_ = new osg::StateSet;
136
137        osg::ref_ptr<osg::Material> material = new osg::Material;
138        material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(base_color_ * diffuse_, 1-transparency_));
139        material->setAmbient(osg::Material::FRONT_AND_BACK, material->getDiffuse(osg::Material::FRONT_AND_BACK));
140        material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(specularity_, specularity_, specularity_, 1));
141        material->setShininess(osg::Material::FRONT_AND_BACK, powf(2, 10 * glossiness_ + 2));
142        material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(base_color_ * luminosity_, 1-transparency_));
143        stateset_->setAttributeAndModes(material.get());
144
145        if (!color_map_name_.empty()) {
146            material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
147        }
148
149        if (transparency_ > 0) {
150            osg::ref_ptr<osg::BlendFunc> bf = new osg::BlendFunc;
151            bf->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
152            stateset_->setAttributeAndModes(bf.get());
153            stateset_->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
154        }
155
156        if (sidedness_ == FRONT_AND_BACK) {
157            stateset_->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
158        } else {
159            osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
160            switch (sidedness_) {
161                case NONE:  cf->setMode(osg::CullFace::FRONT_AND_BACK); break;
162                case FRONT_ONLY: cf->setMode(osg::CullFace::BACK); break;
163                case BACK_ONLY:  cf->setMode(osg::CullFace::FRONT); break;
164                default: ;
165            }
166            stateset_->setAttributeAndModes(cf.get());
167        }
168
169        std::map< std::string, unsigned int > unitmap;
170        unitmap[ "COLR" ] = 0;
171        unitmap[ "TRAN" ] = 1;
172        unsigned int unit = 0;
173        for (Block_map::const_iterator i=blocks_.begin(); i!=blocks_.end(); ++i) {
174
175            const Block &block = i->second;
176            if (!block.enabled()) {
177                continue;
178            }
179
180            if (block.get_type() == "IMAP")
181            {
182                std::string channel = block.get_channel();
183                if ( ( channel == "COLR" ) ||
184                     ( channel == "TRAN" ) )
185                {
186                    unit = unitmap[ channel ];
187                    if (block.get_image_map().clip)
188                    {
189                        std::string image_file = block.get_image_map().clip->get_still_filename();
190                        if (!image_file.empty())
191                        {
192
193                            if (unit >= max_tex_units && max_tex_units > 0)
194                            {
195                                OSG_WARN << "Warning: lwosg::Surface: maximum number of texture units (" << max_tex_units << ") has been reached, skipping incoming blocks" << std::endl;
196                                break;
197                            }
198
199                            osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile(image_file, db_options);
200                            if (!image) break;
201
202                            osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
203                            if (force_arb_compression)
204                                texture->setInternalFormatMode(osg::Texture::USE_ARB_COMPRESSION);
205                            texture->setImage(image.get());
206                            texture->setWrap(osg::Texture::WRAP_S, osg_wrap_mode(block.get_image_map().width_wrap));
207                            texture->setWrap(osg::Texture::WRAP_T, osg_wrap_mode(block.get_image_map().height_wrap));
208                            texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
209                            texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
210                            stateset_->setTextureAttributeAndModes(unit, texture.get());
211
212                            osg::ref_ptr<osg::TexEnvCombine> tec = new osg::TexEnvCombine;
213                            switch (block.get_opacity_type())
214                            {
215                                case Block::NORMAL:
216                                {
217                                    float s = block.get_opacity_amount();
218                                    if (unit == 0)
219                                    {
220                                        tec->setCombine_RGB(osg::TexEnvCombine::MODULATE);
221                                        osg::Vec3 color(diffuse_, diffuse_, diffuse_);
222                                        color = color * s + base_color_ * (1 - s);
223                                        material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(color, 1-transparency_));
224                                        material->setAmbient(osg::Material::FRONT_AND_BACK, material->getDiffuse(osg::Material::FRONT_AND_BACK));
225                                        material->setColorMode(osg::Material::OFF);
226                                    }
227                                    else
228                                    {
229                                        tec->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE);
230                                        tec->setConstantColor(osg::Vec4(s, s, s, s));
231                                    }
232                                }
233                                break;
234
235                                case Block::ADDITIVE:
236                                    tec->setCombine_RGB(osg::TexEnvCombine::ADD);
237                                    break;
238
239                                case Block::SUBTRACTIVE:
240                                    OSG_WARN << "Warning: lwosg::Surface: 'Subtractive' blending mode is not supported, falling back to 'Difference' mode" << std::endl;
241                                case Block::DIFFERENCE:
242                                    tec->setCombine_RGB(osg::TexEnvCombine::SUBTRACT);
243                                    break;
244
245                                case Block::MULTIPLY:
246                                    tec->setCombine_RGB(osg::TexEnvCombine::MODULATE);
247                                    break;
248
249                                case Block::DIVIDE:
250                                    OSG_WARN << "Warning: lwosg::Surface: 'Divide' blending mode is not supported" << std::endl;
251                                    break;
252
253                                case Block::ALPHA:
254                                    OSG_WARN << "Warning: lwosg::Surface: 'Alpha' blending mode is not supported" << std::endl;
255                                    break;
256
257                                case Block::TEXTURE_DISPLACEMENT:
258                                    OSG_WARN << "Warning: lwosg::Surface: 'Texture Displacement' blending mode is not supported" << std::endl;
259                                    break;
260
261                                default:
262                                break;
263                            };
264
265                            stateset_->setTextureAttributeAndModes(unit, tec.get());
266                            ++unit;
267                        }
268                    }
269                }
270                else
271                {
272                    OSG_WARN << "Warning: lwosg::Surface: texture channels of type '" << block.get_channel() << "' are not supported, this block will be ignored" << std::endl;
273                }
274            }
275        }
276    }
277}
278
279osg::Group *Surface::apply(osg::Geometry *geo, const VertexMap_map *texture_maps, const VertexMap_map *rgb_maps, const VertexMap_map *rgba_maps, int max_tex_units, bool use_osgfx, bool force_arb_compression, const VertexMap_binding_map &texmap_bindings, const osgDB::ReaderWriter::Options* db_options) const
280{
281    int num_points = 0;
282
283    if (geo->getVertexArray()) {
284        num_points = static_cast<int>(geo->getVertexArray()->getNumElements());
285    }
286
287    generate_stateset(max_tex_units, force_arb_compression, db_options);
288    geo->setStateSet(stateset_.get());
289
290    int unit = 0;
291    for (Block_map::const_iterator i=blocks_.begin(); i!=blocks_.end(); ++i) {
292        const Block &block = i->second;
293        if (block.get_type() == "IMAP" && block.get_channel() == "COLR" && block.get_image_map().clip) {
294            std::string image_file = block.get_image_map().clip->get_still_filename();
295            if (!image_file.empty()) {
296                if (block.get_image_map().projection == Image_map::UV) {
297                    VertexMap_map::const_iterator i = texture_maps->find(block.get_image_map().uv_map);
298                    if (i != texture_maps->end()) {
299                        geo->setTexCoordArray(unit, i->second->asVec2Array(num_points));
300                    } else {
301                        OSG_WARN << "Warning: lwosg::Surface: surface '" << name_ << "' needs texture map named '" << block.get_image_map().uv_map << "' but I can't find it" << std::endl;
302                    }
303                }
304                ++unit;
305            }
306        }
307    }
308
309    for (VertexMap_binding_map::const_iterator vi=texmap_bindings.begin(); vi!=texmap_bindings.end(); ++vi)
310    {
311        for (VertexMap_map::const_iterator j=texture_maps->begin(); j!=texture_maps->end(); ++j)
312        {
313            if (j->first == vi->first)
314            {
315                if (geo->getTexCoordArray(vi->second) != 0)
316                {
317                    OSG_WARN << "Warning: lwosg::Surface: explicing binding of texture map '" << vi->first << "' to texunit " << vi->second << " will replace existing texture map" << std::endl;
318                }
319                geo->setTexCoordArray(vi->second, j->second->asVec2Array(num_points));
320            }
321            else
322            {
323                OSG_WARN << "Warning: lwosg::Surface: explicit binding of texture map '" << vi->first << "' to texunit " << vi->second << " was requested but there is no such map in this LWO file" << std::endl;
324            }
325        }
326    }
327
328    osg::Vec4 color = osg::Vec4(base_color_, 1-transparency_);
329
330    const VertexMap_map *color_maps = 0;
331
332    if (color_map_type_ == "RGB ") {
333        color_maps = rgb_maps;
334    }
335
336    if (color_map_type_ == "RGBA") {
337        color_maps = rgba_maps;
338    }
339
340    if (color_maps) {
341        VertexMap_map::const_iterator i = color_maps->find(color_map_name_);
342        if (i != color_maps->end() && !i->second->empty()) {
343            geo->setColorArray(i->second->asVec4Array(num_points, color * color_map_intensity_, color * color_map_intensity_));
344            geo->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
345        } else {
346            OSG_WARN << "Warning: lwosg::Surface: surface '" << name_ << "' needs color map named '" << color_map_name_ << "' but I can't find it" << std::endl;
347        }
348    }
349
350    // create osgFX specularity if needed
351    if (use_osgfx && glossiness_ > 0 && specularity_ > 0) {
352        if (unit >= max_tex_units && max_tex_units > 0) {
353            OSG_WARN << "Warning: lwosg::Surface: can't apply osgFX specular lighting: maximum number of texture units (" << max_tex_units << ") has been reached" << std::endl;
354        } else {
355            osg::ref_ptr<osgFX::SpecularHighlights> sh = new osgFX::SpecularHighlights;
356            sh->setTextureUnit(unit);
357            osg::Material *material = dynamic_cast<osg::Material *>(stateset_->getAttribute(osg::StateAttribute::MATERIAL));
358            if (material) {
359                sh->setSpecularColor(material->getSpecular(osg::Material::FRONT_AND_BACK));
360                sh->setSpecularExponent(powf(2, 10 * glossiness_ + 2));
361                material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 0));
362                material->setShininess(osg::Material::FRONT_AND_BACK, 0);
363            }
364            return sh.release();
365        }
366    }
367
368    return 0;
369}
Note: See TracBrowser for help on using the browser.