1 /*
2  * Copyright 2006 Sony Computer Entertainment Inc.
3  *
4  * Licensed under the SCEA Shared Source License, Version 1.0 (the "License"); you may not use this
5  * file except in compliance with the License. You may obtain a copy of the License at:
6  * http://research.scea.com/scea_shared_source_license.html
7  *
8  * Unless required by applicable law or agreed to in writing, software distributed under the License
9  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
10  * implied. See the License for the specific language governing permissions and limitations under the
11  * License.
12  */
13 
14 #include "daeReader.h"
15 #include "ReaderWriterDAE.h"
16 
17 #include <dae.h>
18 #include <dae/daeSIDResolver.h>
19 #include <dae/domAny.h>
20 #include <dom/domCOLLADA.h>
21 #include <dom/domProfile_COMMON.h>
22 #include <dom/domConstants.h>
23 
24 #include <osg/BlendColor>
25 #include <osg/BlendFunc>
26 #include <osg/Texture2D>
27 #include <osg/TexEnv>
28 #include <osg/LightModel>
29 #include <osgDB/Registry>
30 #include <osgDB/ReadFile>
31 
32 #include <sstream>
33 
34 using namespace osgDAE;
35 
36 #ifdef COLLADA_DOM_2_4_OR_LATER
37 #include <dom/domAny.h>
38 using namespace ColladaDOM141;
39 #endif
40 
41 template <typename T>
getTransparencyCounts(daeDatabase * database,int & transparentCount,int & opaqueCount) const42 void daeReader::getTransparencyCounts(daeDatabase* database, int& transparentCount, int& opaqueCount) const
43 {
44     std::vector<T*> constantVec;
45     database->typeLookup(constantVec);
46 
47     for (size_t i = 0; i < constantVec.size(); ++i)
48     {
49         if (const domCommon_transparent_type* pTransparent = constantVec[i]->getTransparent())
50         {
51             domFx_opaque_enum opaque = pTransparent->getOpaque();
52             if (opaque == FX_OPAQUE_ENUM_RGB_ZERO)
53             {
54                 ++opaqueCount;
55                 continue;
56             }
57         }
58 
59         if (const domCommon_float_or_param_type* pTransparency = constantVec[i]->getTransparency())
60         {
61             float transparency;
62 
63             domFloat transparencyParam = 1.0;
64             if (pTransparency->getFloat())
65             {
66                 transparency = pTransparency->getFloat()->getValue();
67             }
68             else if (pTransparency->getParam() &&
69                 GetFloatParam(pTransparency->getParam()->getRef(), transparencyParam))
70             {
71                 transparency = transparencyParam;
72             }
73             else
74             {
75                 continue;
76             }
77 
78             if (transparency < 0.01f)
79             {
80                 ++transparentCount;
81             }
82             else if (transparency > 0.99f)
83             {
84                 ++opaqueCount;
85             }
86         }
87 
88     }
89 
90 }
91 
findInvertTransparency(daeDatabase * database) const92 bool daeReader::findInvertTransparency(daeDatabase* database) const
93 {
94     int transparentCount = 0, opaqueCount = 0;
95     getTransparencyCounts<domProfile_COMMON::domTechnique::domConstant>(database, transparentCount, opaqueCount);
96     getTransparencyCounts<domProfile_COMMON::domTechnique::domLambert>(database, transparentCount, opaqueCount);
97     getTransparencyCounts<domProfile_COMMON::domTechnique::domPhong>(database, transparentCount, opaqueCount);
98     getTransparencyCounts<domProfile_COMMON::domTechnique::domBlinn>(database, transparentCount, opaqueCount);
99 
100     return transparentCount > opaqueCount;
101 }
102 
103 // <bind_material>
104 // elements:
105 // 0..*    <param>
106 //        name
107 //        sid
108 //        semantic
109 //        type
110 // 1    <technique_common>
111 //        0..*    <instance_material>
112 //                symbol
113 //                target
114 //                sid
115 //                name
116 // 0..*    <technique>
117 //        profile
118 // 0..* <extra>
119 //        id
120 //        name
121 //        type
processBindMaterial(domBind_material * bm,domGeometry * geom,osg::Geode * geode,osg::Geode * cachedGeode)122 void daeReader::processBindMaterial( domBind_material *bm, domGeometry *geom, osg::Geode *geode, osg::Geode *cachedGeode )
123 {
124     if (bm->getTechnique_common() == NULL )
125     {
126         OSG_WARN << "No COMMON technique for bind_material" << std::endl;
127         return;
128     }
129 
130     for (size_t i =0; i < geode->getNumDrawables(); i++)
131     {
132         osg::Drawable* drawable = geode->getDrawable(i);
133         std::string materialName = drawable->getName();
134         osg::Geometry *cachedGeometry = dynamic_cast<osg::Geometry*>(cachedGeode->getDrawable(i)->asGeometry());
135 
136         domInstance_material_Array &ima = bm->getTechnique_common()->getInstance_material_array();
137         std::string symbol;
138         bool found = false;
139         for ( size_t j = 0; j < ima.getCount(); j++)
140         {
141             symbol = ima[j]->getSymbol();
142             if (symbol.compare(materialName) == 0)
143             {
144                 found = true;
145                 domMaterial *mat = daeSafeCast< domMaterial >(getElementFromURI( ima[j]->getTarget()));
146                 if (mat)
147                 {
148                     // Check material cache if this material already exists
149                     osg::StateSet* ss;
150                     domMaterialStateSetMap::iterator iter = _materialMap.find( mat );
151                     if (iter != _materialMap.end() )
152                     {
153                         // Reuse material
154                         ss = iter->second.get();
155                     }
156                     else
157                     {
158                         // Create new material
159                         ss = new osg::StateSet;
160                         processMaterial(ss, mat);
161                         _materialMap.insert(std::make_pair(mat, ss));
162                     }
163                     drawable->setStateSet(ss);
164                     // Need to process bind_vertex_inputs here
165                     // 1. Clear the texcoord arrays and associated texcoord vertex indices
166                     // from the current (cloned) drawable.
167                     osg::Geometry *clonedGeometry = drawable->asGeometry();
168                     if (NULL == clonedGeometry)
169                     {
170                         OSG_WARN << "Failed to convert drawable to geometry object" << std::endl;
171                         break;
172                     }
173                     clonedGeometry->getTexCoordArrayList().clear();
174 
175                     // 2. For each possible texture unit find the correct texcoord array and
176                     // indices from the cached drawable and place in the cloned drawable
177                     // in the correct texture unit slot
178                     unsigned int textureUnit(0);
179                     if (copyTextureCoordinateSet(ss, cachedGeometry, clonedGeometry, ima[j], AMBIENT_OCCLUSION_UNIT, textureUnit)) ++textureUnit;
180                     if (copyTextureCoordinateSet(ss, cachedGeometry, clonedGeometry, ima[j], MAIN_TEXTURE_UNIT     , textureUnit)) ++textureUnit;
181                     if (copyTextureCoordinateSet(ss, cachedGeometry, clonedGeometry, ima[j], TRANSPARENCY_MAP_UNIT , textureUnit)) ++textureUnit;
182                 }
183                 else
184                 {
185                     OSG_WARN << "Failed to locate <material> with id " << ima[i]->getTarget().getURI() << std::endl;
186                 }
187 
188                 break;
189             }
190         }
191         if (!found)
192         {
193             OSG_WARN << "Failed to locate <instance_material> with symbol " << materialName << std::endl;
194         }
195     }
196 }
197 
198 // <material>
199 // attributes:
200 // 0..1    id
201 // 0..1    name
202 // elements:
203 // 0..1 <asset>
204 // 1    <instance_effect>
205 // 0..* <extra>
processMaterial(osg::StateSet * ss,domMaterial * mat)206 void    daeReader::processMaterial(osg::StateSet *ss, domMaterial *mat )
207 {
208     if (!mat)
209     {
210         return;
211     }
212     if (mat->getName()) {
213         ss->setName(mat->getName());
214     }
215     _currentInstance_effect = mat->getInstance_effect();
216     if (!_currentInstance_effect)
217     {
218         return;
219     }
220     domEffect *effect = daeSafeCast< domEffect >( getElementFromURI( _currentInstance_effect->getUrl() ) );
221     if (effect)
222     {
223         processEffect(ss, effect);
224 
225         //TODO: process all of the setParams that could happen here in the material. ESP. the textures
226     }
227     else
228     {
229         OSG_WARN << "Failed to locate effect " << mat->getInstance_effect()->getUrl().getURI() << std::endl;
230     }
231 }
232 
233 // <effect>
234 // attributes:
235 // 1    id
236 // 0..1    name
237 // elements:
238 // 0..1 <asset>
239 // 0..* <annotate>
240 // 0..* <image>
241 // 0..* <newparam>
242 // 1..*    <fx_profile_abstract>
243 // 0..* <extra>
processEffect(osg::StateSet * ss,domEffect * effect)244 void daeReader::processEffect(osg::StateSet *ss, domEffect *effect )
245 {
246     bool hasCOMMON = false;
247 
248     for ( size_t i = 0; i < effect->getFx_profile_abstract_array().getCount(); i++ )
249     {
250         domProfile_COMMON *pc = daeSafeCast< domProfile_COMMON >( effect->getFx_profile_abstract_array()[i] );
251         if (pc != NULL )
252         {
253             if (hasCOMMON )
254             {
255                 OSG_WARN << "Effect already has a profile_COMMON. Skipping this one" << std::endl;
256                 continue;
257             }
258             _currentEffect = effect;
259             processProfileCOMMON(ss, pc);
260             hasCOMMON = true;
261             continue;
262         }
263 
264         OSG_WARN << "unsupported effect profile " << effect->getFx_profile_abstract_array()[i]->getTypeName() << std::endl;
265     }
266 }
267 
268 // <profile_COMMON>
269 // elements:
270 // 0..* <image>, <newparam>
271 // 1    <technique>
272 //        attributes:
273 //        elements:
274 //        0..1    <asset>
275 //        0..*    <image>, <newparam>
276 //        1        <constant>, <lambert>, <phong>, <blinn>
277 //        0..*    <extra>
278 // 0..* <extra>
processProfileCOMMON(osg::StateSet * ss,domProfile_COMMON * pc)279 void daeReader::processProfileCOMMON(osg::StateSet *ss, domProfile_COMMON *pc )
280 {
281     domProfile_COMMON::domTechnique *teq = pc->getTechnique();
282 
283     domProfile_COMMON::domTechnique::domConstant *c = teq ? teq->getConstant() : NULL;
284     domProfile_COMMON::domTechnique::domLambert *l = teq ? teq->getLambert() : NULL;
285     domProfile_COMMON::domTechnique::domPhong *p = teq ? teq->getPhong() : NULL;
286     domProfile_COMMON::domTechnique::domBlinn *b = teq ? teq->getBlinn() : NULL;
287 
288     ss->setMode( GL_CULL_FACE, osg::StateAttribute::ON ); // Cull Back faces
289 
290     // See if there are any extra's that are supported by OpenSceneGraph
291     const domExtra_Array& ExtraArray = pc->getExtra_array();
292     size_t NumberOfExtras = ExtraArray.getCount();
293     size_t CurrentExtra;
294     for (CurrentExtra = 0; CurrentExtra < NumberOfExtras; CurrentExtra++)
295     {
296         const domTechnique_Array& TechniqueArray = ExtraArray[CurrentExtra]->getTechnique_array();
297         size_t NumberOfTechniques = TechniqueArray.getCount();
298         size_t CurrentTechnique;
299         for (CurrentTechnique = 0; CurrentTechnique < NumberOfTechniques; CurrentTechnique++)
300         {
301             //  <technique profile="GOOGLEEARTH">
302             //      <double_sided>0</double_sided>
303             //  </technique>
304             const domTechniqueRef& TechniqueRef = TechniqueArray[CurrentTechnique];
305             if (TechniqueRef->getProfile() && strcmp(TechniqueRef->getProfile(), "GOOGLEEARTH") == 0)
306             {
307                 const daeElementRefArray& ElementArray = TechniqueRef->getContents();
308                 size_t NumberOfElements = ElementArray.getCount();
309                 size_t CurrentElement;
310                 for (CurrentElement = 0; CurrentElement < NumberOfElements; CurrentElement++)
311                 {
312                     domAny* pAny = (domAny*)ElementArray[CurrentElement].cast();
313                     if (strcmp(pAny->getElementName(), "double_sided") == 0)
314                     {
315                         daeString Value = pAny->getValue();
316                         if (Value && strcmp(Value, "1") == 0)
317                             ss->setMode( GL_CULL_FACE, osg::StateAttribute::OFF );
318                     }
319                 }
320             }
321         }
322     }
323 
324     osg::ref_ptr< osg::Material > mat = new osg::Material();
325     // <blinn>
326     // elements:
327     // 0..1 <emission>
328     // 0..1 <ambient>
329     // 0..1 <diffuse>
330     // 0..1 <specular>
331     // 0..1 <shininess>
332     // 0..1 <reflective>
333     // 0..1 <reflectivity>
334     // 0..1 <transparent>
335     // 0..1 <transparency>
336     // 0..1 <index_of_refraction>
337     if (b != NULL )
338     {
339         osg::Texture2D *EmissionStateAttribute = NULL;
340         osg::Texture2D *AmbientStateAttribute = NULL;
341         osg::Texture2D *DiffuseStateAttribute = NULL;
342         processColorOrTextureType(ss, b->getEmission(), osg::Material::EMISSION, mat.get(), NULL, &EmissionStateAttribute );
343         if (NULL != EmissionStateAttribute)
344             OSG_WARN << "Currently no support for <texture> in Emission channel " << std::endl;
345 
346         processColorOrTextureType(ss, b->getAmbient(), osg::Material::AMBIENT, mat.get(), NULL,  &AmbientStateAttribute );
347 
348         processColorOrTextureType(ss, b->getDiffuse(), osg::Material::DIFFUSE, mat.get(), NULL, &DiffuseStateAttribute );
349         if (DiffuseStateAttribute != NULL )
350         {
351             if (AmbientStateAttribute != NULL )
352             {
353                 // Set the ambient and diffuse colour white so that the incoming fragment colour ends up as a
354                 // lit white colour. I modulate both textures onto this to approximate the lighting equation.
355                 // Using a zero diffuse and then an ADD of the diffuse texture seems overlit to me.
356                 mat->setAmbient( osg::Material::FRONT_AND_BACK, osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
357                 mat->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
358                 // Use the ambient texture map as an occlusion map.
359                 unsigned int textureUnit( _pluginOptions.usePredefinedTextureUnits ? AMBIENT_OCCLUSION_UNIT : 0);
360                 ss->setTextureMode( textureUnit, GL_TEXTURE_2D, GL_TRUE );
361                 ss->setTextureAttribute( textureUnit, new osg::TexEnv(osg::TexEnv::MODULATE) );
362                 ss->setTextureAttribute( textureUnit, AmbientStateAttribute );
363                 // Modulate in the diffuse texture
364                 textureUnit = _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 1;
365                 ss->setTextureMode( textureUnit, GL_TEXTURE_2D, GL_TRUE );
366                 ss->setTextureAttribute( textureUnit, new osg::TexEnv(osg::TexEnv::MODULATE) );
367                 ss->setTextureAttribute( textureUnit, DiffuseStateAttribute );
368             }
369             else
370             {
371                 // Set the diffuse colour white so that the incoming fragment colour ends up as the global diffuse lighting colour
372                 // plus any constant ambient contribution after the lighting calculation. This means that I am modulating the the
373                 // ambient with the texture as well but I cannot see a way of avoiding that.
374                 mat->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
375                 unsigned int textureUnit( _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 0);
376                 ss->setTextureMode( textureUnit, GL_TEXTURE_2D, GL_TRUE );
377                 ss->setTextureAttribute( textureUnit, new osg::TexEnv(osg::TexEnv::MODULATE) );
378                 ss->setTextureAttribute( textureUnit, DiffuseStateAttribute );
379             }
380         }
381         else
382         {
383             if (NULL != AmbientStateAttribute  )
384                 OSG_WARN << "Ambient occlusion map only supported when diffuse texture also specified" << std::endl;
385         }
386 
387         if (processColorOrTextureType(ss, b->getSpecular(), osg::Material::SPECULAR, mat.get(), b->getShininess() ) && (NULL != DiffuseStateAttribute) )
388         {
389             // Diffuse texture will defeat specular highlighting
390             // So postpone specular - Not sure if I should do this here
391             // because it will override any global light model states
392             osg::LightModel* lightmodel = new osg::LightModel;
393             lightmodel->setColorControl(osg::LightModel::SEPARATE_SPECULAR_COLOR);
394             ss->setAttributeAndModes(lightmodel, osg::StateAttribute::ON);
395         }
396 
397         processTransparencySettings(b->getTransparent(), b->getTransparency(), ss, mat.get(), _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 0 );
398     }
399     // <phong>
400     // elements:
401     // 0..1 <emission>
402     // 0..1 <ambient>
403     // 0..1 <diffuse>
404     // 0..1 <specular>
405     // 0..1 <shininess>
406     // 0..1 <reflective>
407     // 0..1 <reflectivity>
408     // 0..1 <transparent>
409     // 0..1 <transparency>
410     // 0..1 <index_of_refraction>
411     else if (p != NULL )
412     {
413         osg::Texture2D *EmissionStateAttribute = NULL;
414         osg::Texture2D *AmbientStateAttribute = NULL;
415         osg::Texture2D *DiffuseStateAttribute = NULL;
416         processColorOrTextureType(ss, p->getEmission(), osg::Material::EMISSION, mat.get(), NULL, &EmissionStateAttribute );
417         if (NULL != EmissionStateAttribute)
418             OSG_WARN << "Currently no support for <texture> in Emission channel " << std::endl;
419 
420         processColorOrTextureType(ss, p->getAmbient(), osg::Material::AMBIENT, mat.get(), NULL,  &AmbientStateAttribute );
421 
422         processColorOrTextureType(ss, p->getDiffuse(), osg::Material::DIFFUSE, mat.get(), NULL, &DiffuseStateAttribute );
423         if (DiffuseStateAttribute != NULL )
424         {
425             if (AmbientStateAttribute != NULL )
426             {
427                 // Set the ambient and diffuse colour white so that the incoming fragment colour ends up as a
428                 // lit white colour. I modulate both textures onto this to approximate the lighting equation.
429                 // Using a zero diffuse and then an ADD of the diffuse texture seems overlit to me.
430                 mat->setAmbient( osg::Material::FRONT_AND_BACK, osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
431                 mat->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
432                 // Use the ambient texture map as an occlusion map.
433                 unsigned int textureUnit( _pluginOptions.usePredefinedTextureUnits ? AMBIENT_OCCLUSION_UNIT : 0);
434                 ss->setTextureMode( textureUnit, GL_TEXTURE_2D, GL_TRUE );
435                 ss->setTextureAttribute( textureUnit, new osg::TexEnv(osg::TexEnv::MODULATE) );
436                 ss->setTextureAttribute( textureUnit, AmbientStateAttribute );
437                 // Modulate in the diffuse texture
438                 textureUnit = _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 1;
439                 ss->setTextureMode( textureUnit, GL_TEXTURE_2D, GL_TRUE );
440                 ss->setTextureAttribute( textureUnit, new osg::TexEnv(osg::TexEnv::MODULATE) );
441                 ss->setTextureAttribute( textureUnit, DiffuseStateAttribute );
442             }
443             else
444             {
445                 // Set the diffuse colour white so that the incoming fragment colour ends up as the global diffuse lighting colour
446                 // plus any constant ambient contribution after the lighting calculation. This means that I am modulating the the
447                 // ambient with the texture as well but I cannot see a way of avoiding that.
448                 mat->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
449                 unsigned int textureUnit( _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 0);
450                 ss->setTextureMode( textureUnit, GL_TEXTURE_2D, GL_TRUE );
451                 ss->setTextureAttribute( textureUnit, new osg::TexEnv(osg::TexEnv::MODULATE) );
452                 ss->setTextureAttribute( textureUnit, DiffuseStateAttribute );
453             }
454         }
455         else
456         {
457             if (NULL != AmbientStateAttribute  )
458                 OSG_WARN << "Ambient occlusion map only supported when diffuse texture also specified" << std::endl;
459         }
460 
461         if (processColorOrTextureType(ss, p->getSpecular(), osg::Material::SPECULAR, mat.get(), p->getShininess() ) && (NULL != DiffuseStateAttribute) )
462         {
463             // Diffuse texture will defeat specular highlighting
464             // So postpone specular - Not sure if I should do this here
465             // because it will override any global light model states
466             osg::LightModel* lightmodel = new osg::LightModel;
467             lightmodel->setColorControl(osg::LightModel::SEPARATE_SPECULAR_COLOR);
468             ss->setAttributeAndModes(lightmodel, osg::StateAttribute::ON);
469         }
470 
471         processTransparencySettings(p->getTransparent(), p->getTransparency(), ss, mat.get(), _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 0 );
472     }
473     // <lambert>
474     // elements:
475     // 0..1 <emission>
476     // 0..1 <ambient>
477     // 0..1 <diffuse>
478     // 0..1 <reflective>
479     // 0..1 <reflectivity>
480     // 0..1 <transparent>
481     // 0..1 <transparency>
482     // 0..1 <index_of_refraction>
483     else if (l != NULL )
484     {
485         osg::Texture2D *EmissionStateAttribute = NULL;
486         osg::Texture2D *AmbientStateAttribute = NULL;
487         osg::Texture2D *DiffuseStateAttribute = NULL;
488         processColorOrTextureType(ss, l->getEmission(), osg::Material::EMISSION, mat.get(), NULL, &EmissionStateAttribute );
489         if (NULL != EmissionStateAttribute)
490             OSG_WARN << "Currently no support for <texture> in Emission channel " << std::endl;
491 
492         processColorOrTextureType(ss, l->getAmbient(), osg::Material::AMBIENT, mat.get(), NULL,  &AmbientStateAttribute);
493 
494         processColorOrTextureType(ss, l->getDiffuse(), osg::Material::DIFFUSE, mat.get(), NULL, &DiffuseStateAttribute );
495         if (DiffuseStateAttribute != NULL )
496         {
497             if (AmbientStateAttribute != NULL )
498             {
499                 // Set the ambient and diffuse colour white so that the incoming fragment colour ends up as a
500                 // lit white colour. I modulate both textures onto this to approximate the lighting equation.
501                 // Using a zero diffuse and then an ADD of the diffuse texture seems overlit to me.
502                 mat->setAmbient( osg::Material::FRONT_AND_BACK, osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
503                 mat->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
504                 // Use the ambient texture map as an occlusion map.
505                 unsigned int textureUnit( _pluginOptions.usePredefinedTextureUnits ? AMBIENT_OCCLUSION_UNIT : 0);
506                 ss->setTextureMode( textureUnit, GL_TEXTURE_2D, GL_TRUE );
507                 ss->setTextureAttribute( textureUnit, new osg::TexEnv(osg::TexEnv::MODULATE) );
508                 ss->setTextureAttribute( textureUnit, AmbientStateAttribute );
509                 // Modulate in the diffuse texture
510                 textureUnit = _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 1;
511                 ss->setTextureMode( textureUnit, GL_TEXTURE_2D, GL_TRUE );
512                 ss->setTextureAttribute( textureUnit, new osg::TexEnv(osg::TexEnv::MODULATE) );
513                 ss->setTextureAttribute( textureUnit, DiffuseStateAttribute );
514             }
515             else
516             {
517                 // Set the diffuse colour white so that the incoming fragment colour ends up as the global diffuse lighting colour
518                 // plus any constant ambient contribution after the lighting calculation. This means that I am modulating the the
519                 // ambient with the texture as well but I cannot see a way of avoiding that.
520                 mat->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
521                 unsigned int textureUnit( _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 0);
522                 ss->setTextureMode( textureUnit, GL_TEXTURE_2D, GL_TRUE );
523                 ss->setTextureAttribute( textureUnit, new osg::TexEnv(osg::TexEnv::MODULATE) );
524                 ss->setTextureAttribute( textureUnit, DiffuseStateAttribute );
525             }
526         }
527         else
528         {
529             if (NULL != AmbientStateAttribute  )
530                 OSG_WARN << "Ambient occlusion map only supported when diffuse texture also specified" << std::endl;
531         }
532 
533         processTransparencySettings(l->getTransparent(), l->getTransparency(), ss, mat.get(), _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 0 );
534     }
535     // <constant>
536     // elements:
537     // 0..1 <emission>
538     // 0..1 <reflective>
539     // 0..1 <reflectivity>
540     // 0..1 <transparent>
541     // 0..1 <transparency>
542     // 0..1 <index_of_refraction>
543     else if (c != NULL )
544     {
545         osg::Texture2D *sa = NULL;
546         processColorOrTextureType(ss, c->getEmission(), osg::Material::EMISSION, mat.get(), NULL, &sa );
547         if (sa != NULL )
548         {
549             unsigned int textureUnit( _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 0);
550             ss->setTextureMode( textureUnit, GL_TEXTURE_2D, GL_TRUE );
551             ss->setTextureAttribute( textureUnit, new osg::TexEnv(osg::TexEnv::REPLACE) );
552             ss->setTextureAttribute( textureUnit, sa );
553         }
554 
555         // Use the emission colour as the main colour in transparency calculations
556         mat->setDiffuse(osg::Material::FRONT_AND_BACK, mat->getEmission(osg::Material::FRONT_AND_BACK));
557 
558         processTransparencySettings(c->getTransparent(), c->getTransparency(), ss, mat.get(), _pluginOptions.usePredefinedTextureUnits ? MAIN_TEXTURE_UNIT : 0 );
559 
560         // Kill the lighting
561         mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0, 0.0, 0.0, 1.0));
562         mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0, 0.0, 0.0, 1.0));
563     }
564     ss->setAttribute( mat.get() );
565 }
566 
567 // colorOrTexture
568 // 1  of
569 //         <color>
570 //        <param>
571 //        attributes:
572 //        1        ref
573 //        <texture>
574 //        attributes:
575 //        1        texture
576 //        1        texcoord
577 //        0..*    extra
processColorOrTextureType(const osg::StateSet * ss,domCommon_color_or_texture_type * cot,osg::Material::ColorMode channel,osg::Material * mat,domCommon_float_or_param_type * fop,osg::Texture2D ** sa,bool blinn)578 bool daeReader::processColorOrTextureType(const osg::StateSet* ss,
579                                           domCommon_color_or_texture_type *cot,
580                                           osg::Material::ColorMode channel,
581                                           osg::Material *mat,
582                                           domCommon_float_or_param_type *fop,
583                                           osg::Texture2D **sa,
584                                           bool blinn)
585 {
586     if (cot == NULL )
587     {
588         return false;
589     }
590     bool retVal = false;
591 
592     //osg::StateAttribute *sa = NULL;
593     //TODO: Make all channels process <param ref=""> type of value
594     if (channel == osg::Material::EMISSION )
595     {
596         if (cot->getColor() != NULL )
597         {
598             domFloat4 &f4 = cot->getColor()->getValue();
599             mat->setEmission( osg::Material::FRONT_AND_BACK, osg::Vec4( f4[0], f4[1], f4[2], (f4.getCount()==4)? f4[3] : 1.0 ) );
600             retVal = true;
601         }
602         else if (cot->getParam() != NULL)
603         {
604             domFloat4 f4;
605             if (GetFloat4Param(cot->getParam()->getRef(), f4))
606             {
607                 mat->setEmission( osg::Material::FRONT_AND_BACK, osg::Vec4( f4[0], f4[1], f4[2], f4[3] ) );
608                 retVal = true;
609             }
610         }
611         else if (cot->getTexture() != NULL)
612         {
613             if (sa != NULL)
614             {
615                 *sa = processTexture( cot->getTexture(), ss, MAIN_TEXTURE_UNIT);
616                 retVal = true;
617             }
618             else
619                 OSG_WARN << "Currently no support for <texture> in Emission channel " << std::endl;
620         }
621         else
622         {
623             OSG_WARN << "Missing <color>, <param> or <texture> in Emission channel " << std::endl;
624         }
625     }
626     else if (channel == osg::Material::AMBIENT )
627     {
628         if (cot->getColor() != NULL )
629         {
630             domFloat4 &f4 = cot->getColor()->getValue();
631             mat->setAmbient( osg::Material::FRONT_AND_BACK, osg::Vec4( f4[0], f4[1], f4[2], (f4.getCount()==4)? f4[3] : 1.0 ) );
632             retVal = true;
633         }
634         else if (cot->getParam() != NULL)
635         {
636             domFloat4 f4;
637             if (cot->getParam()->getRef() != 0 && GetFloat4Param(cot->getParam()->getRef(), f4))
638             {
639                 mat->setAmbient( osg::Material::FRONT_AND_BACK, osg::Vec4( f4[0], f4[1], f4[2], f4[3] ) );
640                 retVal = true;
641             }
642         }
643         else if (cot->getTexture() != NULL)
644         {
645             if (sa != NULL)
646                 *sa = processTexture( cot->getTexture(), ss, AMBIENT_OCCLUSION_UNIT);
647             else
648             {
649                 OSG_WARN << "Currently no support for <texture> in Ambient channel " << std::endl;
650                 mat->setAmbient( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.2f, 0.2f, 0.2f, 1.0f ) );
651             }
652             retVal = true;
653        }
654         else
655         {
656             OSG_WARN << "Missing <color>, <param> or <texture> in Ambient channel " << std::endl;
657         }
658     }
659     else if (channel == osg::Material::DIFFUSE )
660     {
661         if (cot->getColor() != NULL)
662         {
663             domFloat4 &f4 = cot->getColor()->getValue();
664             mat->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4( f4[0], f4[1], f4[2], (f4.getCount()==4)? f4[3] : 1.0 ) );
665             retVal = true;
666         }
667         else if (cot->getTexture() != NULL)
668         {
669             if (sa != NULL)
670                 *sa = processTexture( cot->getTexture(), ss, MAIN_TEXTURE_UNIT);
671             else
672             {
673                 OSG_WARN << "Currently no support for <texture> in Diffuse channel " << std::endl;
674                 mat->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.8f, 0.8f, 0.8f, 1.0f ) );
675             }
676             domExtra *extra = cot->getTexture()->getExtra();
677             if (extra != NULL && extra->getType() != NULL && strcmp( extra->getType(), "color" ) == 0 )
678             {
679                 //the extra data for osg. Diffuse color can happen with a texture.
680                 for ( unsigned int i = 0; i < extra->getTechnique_array().getCount(); i++ )
681                 {
682                     domTechnique *teq = extra->getTechnique_array()[i];
683                     if (strcmp( teq->getProfile(), "SCEI" ) == 0 )
684                     {
685                         osg::Vec4 col;
686                         domAny *dcol = (domAny*)(daeElement*)teq->getContents()[0];
687                         std::istringstream diffuse_colour((const char *)dcol->getValue());
688                         diffuse_colour >> col.r() >> col.g() >> col.b() >> col.a();
689                         mat->setDiffuse( osg::Material::FRONT_AND_BACK, col );
690                         break;
691                     }
692                 }
693             }
694             retVal = true;
695         }
696         else if (cot->getParam() != NULL)
697         {
698             domFloat4 f4;
699             if (GetFloat4Param(cot->getParam()->getRef(), f4))
700             {
701                 mat->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4( f4[0], f4[1], f4[2], f4[3] ) );
702                 retVal = true;
703             }
704         }
705         else
706         {
707             OSG_WARN << "Missing <color>, <param> or <texture> in Diffuse channel " << std::endl;
708         }
709     }
710     else if (channel == osg::Material::SPECULAR )
711     {
712         if (cot->getColor() != NULL )
713         {
714             domFloat4 &f4 = cot->getColor()->getValue();
715             mat->setSpecular( osg::Material::FRONT_AND_BACK, osg::Vec4( f4[0], f4[1], f4[2], (f4.getCount()==4)? f4[3] : 1.0 ) );
716             retVal = true;
717         }
718         else if (cot->getParam() != NULL)
719         {
720             domFloat4 f4;
721             if (GetFloat4Param(cot->getParam()->getRef(), f4))
722             {
723                 mat->setSpecular( osg::Material::FRONT_AND_BACK, osg::Vec4( f4[0], f4[1], f4[2], f4[3] ) );
724                 retVal = true;
725             }
726         }
727         else if (cot->getTexture() != NULL)
728         {
729             OSG_WARN << "Currently no support for <texture> in Specular channel " << std::endl;
730         }
731         else
732         {
733             OSG_WARN << "Missing <color>, <param> or <texture> in Specular channel " << std::endl;
734         }
735 
736         if (fop != NULL && fop->getFloat() != NULL )
737         {
738             float shininess = fop->getFloat()->getValue();
739             if (blinn)
740             {
741                 // If the blinn mode is in the range [0,1] rescale it to [0,128]
742                 if (shininess < 1)
743                     shininess *= 128.0f;
744             }
745             mat->setShininess( osg::Material::FRONT_AND_BACK, shininess );
746         }
747     }
748 
749     return retVal;
750 }
751 
GetFloat4Param(xsNCName Reference,domFloat4 & f4) const752 bool daeReader::GetFloat4Param(xsNCName Reference, domFloat4 &f4) const
753 {
754     std::string MyReference = Reference;
755 
756     MyReference.insert(0, "./");
757     daeSIDResolver Resolver(_currentEffect, MyReference.c_str());
758     daeElement *el = Resolver.getElement();
759     if (NULL == el)
760             return false;
761 
762     if (NULL != _currentInstance_effect)
763     {
764         // look here first for setparams
765         // I am sure there must be a better way of doing this
766         // Maybe the Collada DAE guys can give us a parameter management mechanism !
767         const domInstance_effect::domSetparam_Array& SetParamArray = _currentInstance_effect->getSetparam_array();
768         size_t NumberOfSetParams = SetParamArray.getCount();
769         for (size_t i = 0; i < NumberOfSetParams; i++)
770         {
771             // Just do a simple comaprison of the ref strings for the time being
772             if (0 == strcmp(SetParamArray[i]->getRef(), Reference))
773             {
774                 if (NULL != SetParamArray[i]->getFx_basic_type_common() && (NULL != SetParamArray[i]->getFx_basic_type_common()->getFloat4()))
775                 {
776                     f4 = SetParamArray[i]->getFx_basic_type_common()->getFloat4()->getValue();
777                     return true;
778                 }
779             }
780         }
781     }
782 
783     domCommon_newparam_type *cnp = daeSafeCast< domCommon_newparam_type >( el );
784     domFx_newparam_common *npc = daeSafeCast< domFx_newparam_common >( el );
785     if ((cnp != NULL) && (NULL != cnp->getFloat4()))
786     {
787         f4 = cnp->getFloat4()->getValue();
788         return true;
789     }
790     else if ((npc != NULL) && (NULL != npc->getFx_basic_type_common()) && (NULL != npc->getFx_basic_type_common()->getFloat4()))
791     {
792         f4 = npc->getFx_basic_type_common()->getFloat4()->getValue();
793         return true;
794     }
795     else
796         return false;
797 }
798 
GetFloatParam(xsNCName Reference,domFloat & f) const799 bool daeReader::GetFloatParam(xsNCName Reference, domFloat &f) const
800 {
801     std::string MyReference = Reference;
802 
803     MyReference.insert(0, "./");
804     daeSIDResolver Resolver(_currentEffect, MyReference.c_str());
805     daeElement *el = Resolver.getElement();
806     if (NULL == el)
807         return false;
808 
809     if (NULL != _currentInstance_effect)
810     {
811         // look here first for setparams
812         // I am sure there must be a better way of doing this
813         // Maybe the Collada DAE guys can give us a parameter management mechanism !
814         const domInstance_effect::domSetparam_Array& SetParamArray = _currentInstance_effect->getSetparam_array();
815         size_t NumberOfSetParams = SetParamArray.getCount();
816         for (size_t i = 0; i < NumberOfSetParams; i++)
817         {
818             // Just do a simple comaprison of the ref strings for the time being
819             if (0 == strcmp(SetParamArray[i]->getRef(), Reference))
820             {
821                 if (NULL != SetParamArray[i]->getFx_basic_type_common() && (NULL != SetParamArray[i]->getFx_basic_type_common()->getFloat()))
822                 {
823                     f = SetParamArray[i]->getFx_basic_type_common()->getFloat()->getValue();
824                     return true;
825                 }
826             }
827         }
828     }
829 
830     domCommon_newparam_type *cnp = daeSafeCast< domCommon_newparam_type >( el );
831     domFx_newparam_common *npc = daeSafeCast< domFx_newparam_common >( el );
832     if ((cnp != NULL) && (NULL != cnp->getFloat()))
833     {
834         f = cnp->getFloat()->getValue();
835         return true;
836     }
837     else if ((npc != NULL) && (NULL != npc->getFx_basic_type_common()) && (NULL != npc->getFx_basic_type_common()->getFloat()))
838     {
839         f = npc->getFx_basic_type_common()->getFloat()->getValue();
840         return true;
841     }
842     else
843         return false;
844 }
845 
getWrapMode(domFx_sampler_wrap_common domWrap)846 osg::Texture::WrapMode getWrapMode(domFx_sampler_wrap_common domWrap)
847 {
848     switch (domWrap)
849     {
850     case FX_SAMPLER_WRAP_COMMON_WRAP:
851         return osg::Texture::REPEAT;
852     case FX_SAMPLER_WRAP_COMMON_MIRROR:
853         return osg::Texture::MIRROR;
854     case FX_SAMPLER_WRAP_COMMON_CLAMP:
855         return osg::Texture::CLAMP_TO_EDGE;
856     case FX_SAMPLER_WRAP_COMMON_NONE:
857     case FX_SAMPLER_WRAP_COMMON_BORDER:
858         return osg::Texture::CLAMP_TO_BORDER;
859     default:
860         OSG_WARN << "Unrecognised domFx_sampler_wrap_common." << std::endl;
861     }
862     return osg::Texture::CLAMP;
863 }
864 
getFilterMode(domFx_sampler_filter_common domFilter,bool allowMipMap)865 osg::Texture::FilterMode getFilterMode(domFx_sampler_filter_common domFilter, bool allowMipMap)
866 {
867     switch (domFilter)
868     {
869     case FX_SAMPLER_FILTER_COMMON_NONE:
870     case FX_SAMPLER_FILTER_COMMON_NEAREST:
871         return osg::Texture::NEAREST;
872     case FX_SAMPLER_FILTER_COMMON_LINEAR:
873         return osg::Texture::LINEAR;
874     case FX_SAMPLER_FILTER_COMMON_NEAREST_MIPMAP_NEAREST:
875         return allowMipMap ? osg::Texture::NEAREST_MIPMAP_NEAREST : osg::Texture::NEAREST;
876     case FX_SAMPLER_FILTER_COMMON_LINEAR_MIPMAP_NEAREST:
877         return allowMipMap ? osg::Texture::LINEAR_MIPMAP_NEAREST : osg::Texture::LINEAR;
878     case FX_SAMPLER_FILTER_COMMON_NEAREST_MIPMAP_LINEAR:
879         return allowMipMap ? osg::Texture::NEAREST_MIPMAP_LINEAR : osg::Texture::NEAREST;
880     case FX_SAMPLER_FILTER_COMMON_LINEAR_MIPMAP_LINEAR:
881         return allowMipMap ? osg::Texture::LINEAR_MIPMAP_LINEAR : osg::Texture::LINEAR;
882     default:
883         OSG_WARN << "Unrecognised domFx_sampler_filter_common." << std::endl;
884     }
885     return osg::Texture::LINEAR;
886 }
887 
processImagePath(const domImage * pDomImage) const888 std::string daeReader::processImagePath(const domImage* pDomImage) const
889 {
890     if (pDomImage == NULL)
891     {
892         OSG_WARN << "Could not locate image for texture" << std::endl;
893         return std::string();
894     }
895 
896     //Got a sampler and a surface and an imaged. Time to create the texture stuff for osg
897     if (pDomImage->getInit_from())
898     {
899         pDomImage->getInit_from()->getValue().validate();
900         if (strcmp(pDomImage->getInit_from()->getValue().getProtocol(), "file") == 0)
901         {
902             std::string path = pDomImage->getInit_from()->getValue().pathDir() +
903                 pDomImage->getInit_from()->getValue().pathFile();
904             path = ReaderWriterDAE::ConvertColladaCompatibleURIToFilePath(path);
905             if (path.empty())
906             {
907                 OSG_WARN << "Unable to get path from URI." << std::endl;
908                 return std::string();
909             }
910 #ifdef WIN32
911             // If the path has a drive specifier or a UNC name then strip the leading /
912             if (path.size() > 2 && (path[2] == ':' || (path[1] == '/' && path[2] == '/')))
913                 return path.substr(1, std::string::npos);
914 #endif
915             return path;
916         }
917         else
918         {
919             OSG_WARN << "Only images with a \"file\" scheme URI are supported in this version." << std::endl;
920         }
921     }
922     else
923     {
924         OSG_WARN << "Embedded image data is not supported in this version." << std::endl;
925     }
926     return std::string();
927 }
928 
luminance(const osg::Vec4 & color)929 float luminance(const osg::Vec4& color)
930 {
931     return
932         color.r() * 0.212671f +
933         color.g() * 0.715160f +
934         color.b() * 0.072169f;
935 }
936 
processImageTransparency(const osg::Image * srcImg,domFx_opaque_enum opaque,float transparency) const937 osg::Image* daeReader::processImageTransparency(const osg::Image* srcImg, domFx_opaque_enum opaque, float transparency) const
938 {
939     int s = srcImg->s();
940     int t = srcImg->t();
941     unsigned char* pixels = new unsigned char [s * t];
942 
943     if (opaque == FX_OPAQUE_ENUM_RGB_ZERO)
944     {
945         for (int i = 0; i < t; ++i)
946         {
947             for (int j = 0; j < s; ++j)
948             {
949                 osg::Vec4 color(srcImg->getColor(j, i));
950 
951                 pixels[i * s + j] = static_cast<unsigned char>(
952                     (1.0f - luminance(color) * transparency) * 255.0f);
953             }
954         }
955     }
956     else
957     {
958         bool texHasAlpha = false;
959         switch (srcImg->getPixelFormat())
960         {
961         case GL_ALPHA:
962         case GL_LUMINANCE_ALPHA:
963         case GL_RGBA:
964         case GL_BGRA:
965             texHasAlpha = true;
966         }
967 
968         if (texHasAlpha)
969         {
970             for (int i = 0; i < t; ++i)
971             {
972                 for (int j = 0; j < s; ++j)
973                 {
974                     osg::Vec4 color(srcImg->getColor(j, i));
975 
976                     pixels[i * s + j] = static_cast<unsigned char>(
977                         color.a() * transparency * 255.0f);
978                 }
979             }
980         }
981         else
982         {
983             for (int i = 0; i < t; ++i)
984             {
985                 for (int j = 0; j < s; ++j)
986                 {
987                     osg::Vec4 color(srcImg->getColor(j, i));
988 
989                     pixels[i * s + j] = static_cast<unsigned char>(
990                         luminance(color) * transparency * 255.0f);
991                 }
992             }
993         }
994     }
995 
996     osg::Image* transparentImage = new osg::Image;
997     transparentImage->setWriteHint(osg::Image::STORE_INLINE);
998     transparentImage->setImage(s, t, 1, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, pixels, osg::Image::USE_NEW_DELETE);
999 
1000     return transparentImage;
1001 }
1002 
processTexture(domCommon_color_or_texture_type_complexType::domTexture * tex,const osg::StateSet * ss,TextureUnitUsage tuu,domFx_opaque_enum opaque,float transparency)1003 osg::Texture2D* daeReader::processTexture(
1004     domCommon_color_or_texture_type_complexType::domTexture *tex,
1005     const osg::StateSet* ss, TextureUnitUsage tuu,
1006     domFx_opaque_enum opaque, float transparency)
1007 {
1008     TextureParameters parameters;
1009     parameters.transparent = tuu == TRANSPARENCY_MAP_UNIT;
1010     parameters.opaque = opaque;
1011     parameters.transparency = transparency;
1012 
1013     //find the newparam for the sampler based on the texture attribute
1014     domFx_sampler2D_common *sampler = NULL;
1015     domFx_surface_common *surface = NULL;
1016     domImage *dImg = NULL;
1017 
1018     if(tex->getTexture() == NULL)
1019     {
1020         return NULL;
1021     }
1022 
1023     std::string target = std::string("./") + std::string(tex->getTexture());
1024     OSG_INFO<<"processTexture("<<target<<")"<<std::endl;
1025 
1026     daeSIDResolver res1( _currentEffect, target.c_str() );
1027     daeElement *el = res1.getElement();
1028 
1029     if (el == NULL )
1030     {
1031         OSG_WARN << "Could not locate newparam for texture sampler2D \"" << tex->getTexture() <<
1032             "\". Checking if data does incorrect linking straight to the image" << std::endl;
1033         _dae->getDatabase()->getElement( (daeElement**)&dImg, 0, tex->getTexture(), "image" );
1034         if (dImg != NULL )
1035         {
1036             OSG_WARN << "Direct image link found. Data is incorrect but will continue to load texture" << std::endl;
1037         }
1038     }
1039     else
1040     {
1041         domCommon_newparam_type *cnp = daeSafeCast< domCommon_newparam_type >( el );
1042         domFx_newparam_common *npc = daeSafeCast< domFx_newparam_common >( el );
1043 
1044         if (cnp != NULL )
1045         {
1046             sampler = cnp->getSampler2D();
1047         }
1048         else if (npc != NULL )
1049         {
1050             sampler = npc->getFx_basic_type_common()->getSampler2D();
1051         }
1052 
1053         if (sampler == NULL )
1054         {
1055             OSG_WARN << "Wrong newparam type. Expected sampler2D" << std::endl;
1056             return NULL;
1057         }
1058 
1059         if (sampler->getSource() == NULL || sampler->getSource()->getValue() == NULL)
1060         {
1061             OSG_WARN << "Could not locate source for sampler2D" << std::endl;
1062             return NULL;
1063         }
1064 
1065         //find the newparam for the surface based on the sampler2D->source value
1066         target = std::string("./") + std::string( sampler->getSource()->getValue() );
1067         daeSIDResolver res2( _currentEffect, target.c_str() );
1068         el = res2.getElement();
1069         if (el == NULL )
1070         {
1071             OSG_WARN << "Could not locate newparam for source " << sampler->getSource()->getValue() << std::endl;
1072             return NULL;
1073         }
1074         cnp = daeSafeCast< domCommon_newparam_type >( el );
1075         npc = daeSafeCast< domFx_newparam_common >( el );
1076 
1077         if (cnp != NULL )
1078         {
1079             surface = cnp->getSurface();
1080         }
1081         else if (npc != NULL )
1082         {
1083             surface = npc->getFx_basic_type_common()->getSurface();
1084         }
1085 
1086         if (surface == NULL )
1087         {
1088             OSG_WARN << "Wrong newparam type. Expected surface" << std::endl;
1089             return NULL;
1090         }
1091 
1092         //look for the domImage based on the surface initialization stuff
1093         daeIDRef &ref = surface->getFx_surface_init_common()->getInit_from_array()[0]->getValue();
1094         dImg = daeSafeCast< domImage >( getElementFromIDRef( ref ) );
1095     }
1096 
1097     parameters.filename = processImagePath(dImg);
1098     if (parameters.filename.empty())
1099     {
1100         return NULL;
1101     }
1102 
1103     //set texture parameters
1104     if (sampler)
1105     {
1106         if (sampler->getWrap_s())
1107         {
1108             parameters.wrap_s = getWrapMode(sampler->getWrap_s()->getValue());
1109         }
1110         if (sampler->getWrap_t())
1111         {
1112             parameters.wrap_t = getWrapMode(sampler->getWrap_s()->getValue());
1113         }
1114 
1115         if (sampler->getMinfilter() && sampler->getMinfilter()->getValue() != FX_SAMPLER_FILTER_COMMON_NONE)
1116         {
1117             parameters.filter_min = getFilterMode(sampler->getMinfilter()->getValue(), true);
1118         }
1119         if (sampler->getMagfilter() && sampler->getMagfilter()->getValue() != FX_SAMPLER_FILTER_COMMON_NONE)
1120         {
1121             parameters.filter_mag = getFilterMode(sampler->getMagfilter()->getValue(), false);
1122         }
1123 
1124         if (sampler->getBorder_color() != NULL )
1125         {
1126             const domFloat4& col = sampler->getBorder_color()->getValue();
1127             parameters.border.set(col[0], col[1], col[2], col[3]);
1128         }
1129     }
1130 
1131     osg::Texture2D* t2D = NULL;
1132     TextureParametersMap::const_iterator mapIt = _textureParamMap.find(parameters);
1133     if (mapIt != _textureParamMap.end())
1134     {
1135         t2D = mapIt->second.get();
1136     }
1137     else
1138     {
1139         osg::ref_ptr<osg::Image> img = osgDB::readRefImageFile(parameters.filename, _pluginOptions.options.get());
1140 
1141         if (!img.valid())
1142         {
1143             _textureParamMap[parameters] = NULL;
1144             return NULL;
1145         }
1146 
1147         OSG_INFO<<"  processTexture(..) - readImage("<<parameters.filename<<")"<<std::endl;
1148 
1149         if (tuu == TRANSPARENCY_MAP_UNIT)
1150         {
1151             img = processImageTransparency(img.get(), opaque, transparency);
1152         }
1153 
1154         t2D = new osg::Texture2D(img.get());
1155 
1156         t2D->setWrap( osg::Texture::WRAP_S, parameters.wrap_s);
1157         t2D->setWrap( osg::Texture::WRAP_T, parameters.wrap_t);
1158         t2D->setFilter( osg::Texture::MIN_FILTER, parameters.filter_min);
1159         t2D->setFilter( osg::Texture::MAG_FILTER, parameters.filter_mag);
1160         t2D->setBorderColor(parameters.border);
1161 
1162         _textureParamMap[parameters] = t2D;
1163     }
1164 
1165     if(tex->getTexcoord() != NULL)
1166     {
1167         _texCoordSetMap[TextureToCoordSetMap::key_type(ss, tuu)] = tex->getTexcoord();
1168     }
1169 
1170     return t2D;
1171 }
1172 
1173 
1174 /*
1175 Collada 1.4.1 Specification (2nd Edition) Patch Release Notes: Revision C Release notes
1176 
1177 In <blinn>, <constant>, <lambert>, and <phong>, the child element <transparent> now has an
1178 optional opaque attribute whose valid values are:
1179  A_ONE (the default): Takes the transparency information from the colors alpha channel, where the value 1.0 is opaque.
1180  RGB_ZERO: Takes the transparency information from the colors red, green, and blue channels, where the value 0.0 is opaque,
1181  with each channel modulated independently.
1182 
1183  In the Specification, this is described in the FX Reference chapter in the
1184 common_color_or_texture_type entry, along with a description of how transparency works in the
1185 Getting Started with COLLADA FX chapter in the Determining Transparency section.
1186 
1187 
1188 Collada Digital Asset Schema Release 1.5.0 Release Notes
1189 
1190 The <transparent> elements opaque attribute now allows, in addition to A_ONE and RGB_ZERO, the following values:
1191  A_ZERO: Takes the transparency information from the colors alpha channel, where the value 0.0 is opaque.
1192  RGB_ONE: Takes the transparency information from the colors red, green, and blue channels, where the value 1.0
1193  is opaque, with each channel modulated independently.
1194 
1195 When we update to a version of the dom using that schema we will need to modify the code below
1196 */
1197 
processTransparencySettings(domCommon_transparent_type * ctt,domCommon_float_or_param_type * pTransparency,osg::StateSet * ss,osg::Material * material,unsigned int diffuseTextureUnit)1198 void daeReader::processTransparencySettings( domCommon_transparent_type *ctt,
1199                                             domCommon_float_or_param_type *pTransparency,
1200                                             osg::StateSet *ss,
1201                                             osg::Material *material,
1202                                             unsigned int diffuseTextureUnit  )
1203 {
1204     if (ss == NULL)
1205         return;
1206 
1207     if (NULL == ctt && NULL == pTransparency)
1208         return;
1209 
1210     float transparency = 1.0f;
1211     if (pTransparency)
1212     {
1213         if (pTransparency->getFloat())
1214         {
1215             transparency = pTransparency->getFloat()->getValue();
1216         }
1217         else if (pTransparency->getParam())
1218         {
1219             domFloat transparencyParam;
1220             if (GetFloatParam(pTransparency->getParam()->getRef(), transparencyParam))
1221             {
1222                 transparency = transparencyParam;
1223             }
1224         }
1225 
1226         if (_invertTransparency)
1227         {
1228             transparency = 1.0f - transparency;
1229         }
1230     }
1231 
1232     osg::Texture2D* pTransparentTexture = NULL;
1233     osg::Vec4 transparentColor(transparency, transparency, transparency, transparency);
1234 
1235     // Fix up defaults according to "Determining Transparency" chapter of 1.4.1 spec
1236     domFx_opaque_enum opaque = FX_OPAQUE_ENUM_A_ONE;
1237     if (ctt)
1238     {
1239         opaque = ctt->getOpaque();
1240         if (ctt->getColor())
1241         {
1242             const domFx_color_common& domColorValue = ctt->getColor()->getValue();
1243             transparentColor.set(
1244                 domColorValue.get(0),
1245                 domColorValue.get(1),
1246                 domColorValue.get(2),
1247                 domColorValue.get(3));
1248 
1249             if (opaque == FX_OPAQUE_ENUM_RGB_ZERO)
1250             {
1251                 transparentColor.set(
1252                     1.0f - transparentColor.r() * transparency,
1253                     1.0f - transparentColor.g() * transparency,
1254                     1.0f - transparentColor.b() * transparency,
1255                     1.0f - luminance(transparentColor) * transparency);
1256             }
1257             else
1258             {
1259                 float a = transparentColor.a() * transparency;
1260                 transparentColor.set(a, a, a, a);
1261             }
1262         }
1263         else if (ctt->getTexture())
1264         {
1265             pTransparentTexture = processTexture(ctt->getTexture(), ss, TRANSPARENCY_MAP_UNIT, opaque, transparency);
1266         }
1267     }
1268 
1269     if (pTransparentTexture)
1270     {
1271         ss->setTextureAttributeAndModes(TRANSPARENCY_MAP_UNIT, pTransparentTexture);
1272         ss->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
1273     }
1274     else
1275     {
1276         bool strictTransparency = _pluginOptions.strictTransparency;
1277         if (!strictTransparency)
1278         {
1279             const osg::Texture* pMainTexture = dynamic_cast<osg::Texture*>(
1280                 ss->getTextureAttribute(diffuseTextureUnit, osg::StateAttribute::TEXTURE));
1281             bool haveTranslucentTexture = pMainTexture &&
1282                 pMainTexture->getImage(0) && pMainTexture->getImage(0)->isImageTranslucent();
1283             strictTransparency = !haveTranslucentTexture;
1284         }
1285 
1286         if (strictTransparency)
1287         {
1288             if (transparentColor == osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f))
1289             {
1290                 return;
1291             }
1292 
1293             ss->setAttributeAndModes(new osg::BlendColor(transparentColor));
1294             ss->setAttributeAndModes(new osg::BlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR));
1295         }
1296         else
1297         {
1298             ss->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
1299         }
1300     }
1301 
1302     ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1303 }
1304 
copyTextureCoordinateSet(const osg::StateSet * ss,const osg::Geometry * cachedGeometry,osg::Geometry * clonedGeometry,const domInstance_material * im,TextureUnitUsage tuu,unsigned int textureUnit)1305 bool daeReader::copyTextureCoordinateSet(const osg::StateSet* ss, const osg::Geometry* cachedGeometry, osg::Geometry* clonedGeometry, const domInstance_material* im, TextureUnitUsage tuu, unsigned int textureUnit)
1306 {
1307     unsigned int localTextureUnit( _pluginOptions.usePredefinedTextureUnits ? tuu : textureUnit);
1308     if (!ss->getTextureAttribute(localTextureUnit, osg::StateAttribute::TEXTURE))
1309         return false;
1310 
1311     const std::string& texCoordSetName = _texCoordSetMap
1312         [TextureToCoordSetMap::key_type(ss, tuu)];
1313     if (texCoordSetName.empty()) return false;
1314 
1315     const domInstance_material::domBind_vertex_input_Array &bvia = im->getBind_vertex_input_array();
1316     size_t k;
1317     for (k = 0; k < bvia.getCount(); k++)
1318     {
1319         if (!strcmp(bvia[k]->getSemantic(), texCoordSetName.c_str()) && !strcmp(bvia[k]->getInput_semantic(), COMMON_PROFILE_INPUT_TEXCOORD))
1320         {
1321             unsigned int set = bvia[k]->getInput_set();
1322             if (set < cachedGeometry->getNumTexCoordArrays())
1323             {
1324                 clonedGeometry->setTexCoordArray(localTextureUnit, const_cast<osg::Array*>(cachedGeometry->getTexCoordArray(set)));
1325             }
1326             else
1327             {
1328                 OSG_WARN << "Texture coordinate set " << set << " not found." << std::endl;
1329             }
1330             break;
1331         }
1332     }
1333     if (k == bvia.getCount())
1334     {
1335         OSG_WARN << "Failed to find matching <bind_vertex_input> for " << texCoordSetName << std::endl;
1336 
1337         //bind_vertex_input failed, we try bind
1338         const domInstance_material::domBind_Array &ba = im->getBind_array();
1339         for (k = 0; k < ba.getCount(); k++)
1340         {
1341             if (!strcmp(ba[k]->getSemantic(), texCoordSetName.c_str()) )
1342             {
1343                 IdToCoordIndexMap::const_iterator it = _texCoordIdMap.find(ba[k]->getTarget());
1344                 if (it!=_texCoordIdMap.end()&& (cachedGeometry->getNumTexCoordArrays()>it->second))
1345                 {
1346                   clonedGeometry->setTexCoordArray(localTextureUnit, const_cast<osg::Array*>(cachedGeometry->getTexCoordArray(it->second)));
1347                 }
1348                 else
1349                 {
1350                     OSG_WARN << "Texture coordinate set " << ba[k]->getTarget() << " not found." << std::endl;
1351                 }
1352                 break;
1353             }
1354         }
1355         if (k == ba.getCount())
1356         {
1357             if (cachedGeometry->getNumTexCoordArrays())
1358             {
1359                 clonedGeometry->setTexCoordArray(localTextureUnit, const_cast<osg::Array*>(cachedGeometry->getTexCoordArray(0)));
1360             }
1361         }
1362     }
1363     return true;
1364 }
1365