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