15 #include "daeMaterials.h" 16 #include "config_daeegg.h" 17 #include "fcollada_utils.h" 19 #include "FCDocument/FCDocument.h" 20 #include "FCDocument/FCDMaterial.h" 21 #include "FCDocument/FCDEffect.h" 22 #include "FCDocument/FCDTexture.h" 23 #include "FCDocument/FCDEffectParameterSampler.h" 24 #include "FCDocument/FCDImage.h" 27 #include "string_utils.h" 33 #define luminance(c) ((c[0] * 0.212671 + c[1] * 0.715160 + c[2] * 0.072169)) 41 DaeMaterials(
const FCDGeometryInstance* geometry_instance) {
42 for (
size_t mi = 0; mi < geometry_instance->GetMaterialInstanceCount(); ++mi) {
54 nassertv(instance != NULL);
55 const string semantic (FROM_FSTRING(instance->GetSemantic()));
56 if (_materials.count(semantic) > 0) {
57 daeegg_cat.warning() <<
"Ignoring duplicate material with semantic " << semantic << endl;
60 _materials[semantic] =
new DaeMaterial();
63 for (
size_t vib = 0; vib < instance->GetVertexInputBindingCount(); ++vib) {
64 const FCDMaterialInstanceBindVertexInput* mivib = instance->GetVertexInputBinding(vib);
65 assert(mivib != NULL);
66 PT(DaeVertexInputBinding) bvi =
new DaeVertexInputBinding();
67 bvi->_input_set = mivib->inputSet;
68 #if FCOLLADA_VERSION >= 0x00030005 69 bvi->_input_semantic = mivib->GetInputSemantic();
70 bvi->_semantic = *mivib->semantic;
72 bvi->_input_semantic = mivib->inputSemantic;
73 bvi->_semantic = FROM_FSTRING(mivib->semantic);
75 _materials[semantic]->_uvsets.push_back(bvi);
79 daeegg_cat.spam() <<
"Trying to process material with semantic " << semantic << endl;
80 PT_EggMaterial egg_material =
new EggMaterial(semantic);
82 const FCDEffect* effect = instance->GetMaterial()->GetEffect();
84 daeegg_cat.debug() <<
"Ignoring material (semantic: " << semantic <<
") without assigned effect" << endl;
87 const FCDEffectStandard* effect_common = (FCDEffectStandard *)effect->FindProfile(FUDaeProfileType::COMMON);
88 if (effect_common == NULL) {
89 daeegg_cat.info() <<
"Ignoring effect referenced by material with semantic " << semantic
90 <<
" because it has no common profile" << endl;
92 daeegg_cat.spam() <<
"Processing effect, material semantic is " << semantic << endl;
94 egg_material->set_amb(TO_COLOR(effect_common->GetAmbientColor()));
99 egg_material->set_diff(TO_COLOR(effect_common->GetDiffuseColor()));
100 egg_material->set_emit(TO_COLOR(effect_common->GetEmissionColor()) * effect_common->GetEmissionFactor());
101 egg_material->set_shininess(effect_common->GetShininess());
102 egg_material->set_spec(TO_COLOR(effect_common->GetSpecularColor()));
104 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::DIFFUSE, EggTexture::ET_modulate);
105 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::BUMP, EggTexture::ET_normal);
106 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::SPECULAR, EggTexture::ET_modulate_gloss);
107 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::SPECULAR_LEVEL, EggTexture::ET_gloss);
108 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::TRANSPARENT, EggTexture::ET_unspecified, EggTexture::F_alpha);
109 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::EMISSION, EggTexture::ET_add);
110 #if FCOLLADA_VERSION < 0x00030005 111 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::OPACITY, EggTexture::ET_unspecified, EggTexture::F_alpha);
114 _materials[semantic]->_blend = convert_blend(effect_common->GetTransparencyMode(),
115 TO_COLOR(effect_common->GetTranslucencyColor()),
116 effect_common->GetTranslucencyFactor());
119 process_extra(semantic, effect->GetExtra());
121 daeegg_cat.spam() <<
"Found " << egg_textures.size() <<
" textures in material" << endl;
122 _materials[semantic]->_egg_material = egg_material;
132 process_texture_bucket(
const string semantic,
const FCDEffectStandard* effect_common, FUDaeTextureChannel::Channel bucket, EggTexture::EnvType envtype, EggTexture::Format format) {
133 for (
size_t tx = 0; tx < effect_common->GetTextureCount(bucket); ++tx) {
134 const FCDImage* image = effect_common->GetTexture(bucket, tx)->GetImage();
136 daeegg_cat.warning() <<
"Texture references a nonexisting image!" << endl;
138 const FCDEffectParameterSampler* sampler = effect_common->GetTexture(bucket, tx)->GetSampler();
142 if (image->GetDocument()) {
148 daeegg_cat.debug() <<
"Found texture with path " << texpath << endl;
155 const FCDEffectParameterInt* uvset = effect_common->GetTexture(bucket, tx)->GetSet();
157 daeegg_cat.debug() <<
"Texture has uv name '" << FROM_FSTRING(uvset->GetSemantic()) <<
"'\n";
158 string uvset_semantic (FROM_FSTRING(uvset->GetSemantic()));
161 for (
size_t i = 0; i < _materials[semantic]->_uvsets.size(); ++i) {
162 if (_materials[semantic]->_uvsets[i]->_semantic == uvset_semantic) {
163 egg_texture->set_uv_name(uvset_semantic);
169 if (sampler != NULL) {
172 if (sampler->GetSamplerType() != FCDEffectParameterSampler::SAMPLER1D) {
175 if (sampler->GetSamplerType() == FCDEffectParameterSampler::SAMPLER3D) {
180 if (envtype != EggTexture::ET_unspecified) {
181 egg_texture->set_env_type(envtype);
183 if (format != EggTexture::F_unspecified) {
184 egg_texture->set_format(format);
187 _materials[semantic]->_egg_textures.push_back(egg_texture);
200 process_extra(
const string semantic,
const FCDExtra* extra) {
201 if (extra == NULL)
return;
202 const FCDEType* etype = extra->GetDefaultType();
203 if (etype == NULL)
return;
204 for (
size_t et = 0; et < etype->GetTechniqueCount(); ++et) {
205 const FCDENode* enode = ((
const FCDENode*)(etype->GetTechnique(et)))->FindChildNode(
"double_sided");
207 string content = trim(enode->GetContent());
208 if (content ==
"1" || content ==
"true") {
209 _materials[semantic]->_double_sided =
true;
210 }
else if (content ==
"0" || content ==
"false") {
211 _materials[semantic]->_double_sided =
false;
213 daeegg_cat.warning() <<
"Expected <double_sided> tag to be either 1 or 0, found '" << content <<
"' instead" << endl;
226 if (_materials.count(semantic) > 0) {
229 daeegg_cat.spam() <<
"Applying texture " << (*it)->get_name() <<
" from material with semantic " << semantic << endl;
243 if (_materials.count(semantic) > 0) {
244 PT(DaeBlendSettings) blend = _materials[semantic]->_blend;
245 if (blend && blend->_enabled) {
246 to->set_blend_mode(EggGroup::BM_add);
247 to->set_blend_color(blend->_color);
248 if (invert_transparency) {
249 to->set_blend_operand_a(blend->_operand_b);
250 to->set_blend_operand_b(blend->_operand_a);
252 to->set_blend_operand_a(blend->_operand_a);
253 to->set_blend_operand_b(blend->_operand_b);
255 }
else if (blend && invert_transparency) {
256 to->set_blend_mode(EggGroup::BM_add);
257 to->set_blend_color(blend->_color);
258 to->set_blend_operand_a(blend->_operand_b);
259 to->set_blend_operand_b(blend->_operand_a);
272 get_uvset_name(
const string semantic, FUDaeGeometryInput::Semantic input_semantic, int32 input_set) {
273 if (_materials.count(semantic) > 0) {
274 if (input_set == -1 && _materials[semantic]->_uvsets.size() == 1) {
275 return _materials[semantic]->_uvsets[0]->_semantic;
277 for (
size_t i = 0; i < _materials[semantic]->_uvsets.size(); ++i) {
278 if (_materials[semantic]->_uvsets[i]->_input_set == input_set &&
279 _materials[semantic]->_uvsets[i]->_input_semantic == input_semantic) {
280 return _materials[semantic]->_uvsets[i]->_semantic;
287 for (
size_t i = 0; i < _materials[semantic]->_uvsets.size(); ++i) {
288 if (_materials[semantic]->_uvsets[i]->_input_set == input_set) {
289 daeegg_cat.debug() <<
"Using uv set with non-matching input semantic " << _materials[semantic]->_uvsets[i]->_semantic <<
"\n";
290 return _materials[semantic]->_uvsets[i]->_semantic;
293 daeegg_cat.debug() <<
"No uv set binding found for input set " << input_set <<
"\n";
308 case FCDEffectParameterSampler::SAMPLER1D:
309 return EggTexture::TT_1d_texture;
310 case FCDEffectParameterSampler::SAMPLER2D:
311 return EggTexture::TT_2d_texture;
312 case FCDEffectParameterSampler::SAMPLER3D:
313 return EggTexture::TT_3d_texture;
314 case FCDEffectParameterSampler::SAMPLERCUBE:
315 return EggTexture::TT_cube_map;
317 daeegg_cat.warning() <<
"Invalid sampler type found" << endl;
319 return EggTexture::TT_unspecified;
331 case FUDaeTextureWrapMode::NONE:
333 return EggTexture::WM_unspecified;
334 case FUDaeTextureWrapMode::WRAP:
335 return EggTexture::WM_repeat;
336 case FUDaeTextureWrapMode::MIRROR:
337 return EggTexture::WM_mirror;
338 case FUDaeTextureWrapMode::CLAMP:
339 return EggTexture::WM_clamp;
340 case FUDaeTextureWrapMode::BORDER:
341 return EggTexture::WM_border_color;
342 case FUDaeTextureWrapMode::UNKNOWN:
343 return EggTexture::WM_unspecified;
345 daeegg_cat.warning() <<
"Invalid wrap mode found: " << FUDaeTextureWrapMode::ToString(orig_mode) << endl;
347 return EggTexture::WM_unspecified;
359 case FUDaeTextureFilterFunction::NONE:
361 return EggTexture::FT_unspecified;
362 case FUDaeTextureFilterFunction::NEAREST:
363 return EggTexture::FT_nearest;
364 case FUDaeTextureFilterFunction::LINEAR:
365 return EggTexture::FT_linear;
366 case FUDaeTextureFilterFunction::NEAREST_MIPMAP_NEAREST:
367 return EggTexture::FT_nearest_mipmap_nearest;
368 case FUDaeTextureFilterFunction::LINEAR_MIPMAP_NEAREST:
369 return EggTexture::FT_linear_mipmap_nearest;
370 case FUDaeTextureFilterFunction::NEAREST_MIPMAP_LINEAR:
371 return EggTexture::FT_nearest_mipmap_linear;
372 case FUDaeTextureFilterFunction::LINEAR_MIPMAP_LINEAR:
373 return EggTexture::FT_linear_mipmap_linear;
374 case FUDaeTextureFilterFunction::UNKNOWN:
375 return EggTexture::FT_unspecified;
377 daeegg_cat.warning() <<
"Unknown filter type found: " << FUDaeTextureFilterFunction::ToString(orig_type) << endl;
379 return EggTexture::FT_unspecified;
387 PT(DaeMaterials::DaeBlendSettings) DaeMaterials::
388 convert_blend(FCDEffectStandard::TransparencyMode mode,
const LColor &transparent,
double transparency) {
390 PT(DaeBlendSettings) blend =
new DaeBlendSettings();
391 blend->_enabled =
true;
393 blend->_operand_a = EggGroup::BO_unspecified;
394 blend->_operand_b = EggGroup::BO_unspecified;
397 if (mode == FCDEffectStandard::A_ONE) {
398 double value = transparent[3] * transparency;
399 blend->_color =
LColor(value, value, value, value);
400 }
else if (mode == FCDEffectStandard::RGB_ZERO) {
401 blend->_color = transparent * transparency;
402 blend->_color[3] = luminance(blend->_color);
404 daeegg_cat.error() <<
"Unknown opaque type found!" << endl;
405 blend->_enabled =
false;
410 if (mode == FCDEffectStandard::RGB_ZERO) {
411 blend->_operand_a = EggGroup::BO_one_minus_constant_color;
412 blend->_operand_b = EggGroup::BO_constant_color;
413 }
else if (mode == FCDEffectStandard::A_ONE) {
414 blend->_operand_a = EggGroup::BO_constant_color;
415 blend->_operand_b = EggGroup::BO_one_minus_constant_color;
417 daeegg_cat.error() <<
"Unknown opaque type found!" << endl;
418 blend->_enabled =
false;
423 if (blend->_operand_a == EggGroup::BO_constant_color) {
425 blend->_operand_a = EggGroup::BO_zero;
426 }
else if (blend->_color ==
LColor(1, 1, 1, 1)) {
427 blend->_operand_a = EggGroup::BO_one;
430 if (blend->_operand_b == EggGroup::BO_constant_color) {
432 blend->_operand_b = EggGroup::BO_zero;
433 }
else if (blend->_color ==
LColor(1, 1, 1, 1)) {
434 blend->_operand_b = EggGroup::BO_one;
437 if (blend->_operand_a == EggGroup::BO_one_minus_constant_color) {
439 blend->_operand_a = EggGroup::BO_one;
440 }
else if (blend->_color ==
LColor(1, 1, 1, 1)) {
441 blend->_operand_a = EggGroup::BO_zero;
444 if (blend->_operand_b == EggGroup::BO_one_minus_constant_color) {
446 blend->_operand_b = EggGroup::BO_one;
447 }
else if (blend->_color ==
LColor(1, 1, 1, 1)) {
448 blend->_operand_b = EggGroup::BO_zero;
453 if (blend->_operand_a == EggGroup::BO_one && blend->_operand_b == EggGroup::BO_zero) {
454 blend->_enabled =
false;
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
string get_dirname() const
Returns the directory part of the filename.
void add_texture(EggTexture *texture)
Applies the indicated texture to the primitive.
Defines a texture map that may be applied to geometry.
static EggTexture::FilterType convert_filter_type(const FUDaeTextureFilterFunction::FilterFunction orig_type)
Converts an FCollada filter function to the EggTexture wrap type equivalent.
void add_material_instance(const FCDMaterialInstance *instance)
Adds a material instance.
bool make_canonical()
Converts this filename to a canonical name by replacing the directory part with the fully-qualified d...
string to_os_generic() const
This is similar to to_os_specific(), but it is designed to generate a filename that can be understood...
void set_bface_flag(bool flag)
Sets the backfacing flag of the polygon.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
The name of a file, such as a texture file or an Egg file.
static EggTexture::WrapMode convert_wrap_mode(const FUDaeTextureWrapMode::WrapMode orig_mode)
Converts an FCollada wrap mode to the EggTexture wrap mode equivalent.
static EggTexture::TextureType convert_texture_type(const FCDEffectParameterSampler::SamplerType orig_type)
Converts an FCollada sampler type to the EggTexture texture type equivalent.
void set_material(EggMaterial *material)
Applies the indicated material to the primitive.
void apply_to_group(const string semantic, const PT(EggGroup) to, bool invert_transparency=false)
Applies the colorblend stuff to the given EggGroup.
bool make_relative_to(Filename directory, bool allow_backups=true)
Adjusts this filename, which must be a fully-specified pathname beginning with a slash, to make it a relative filename, relative to the fully-specified directory indicated (which must also begin with, and may or may not end with, a slash–a terminating slash is ignored).
This is the base class for all three-component vectors and points.
const string get_uvset_name(const string semantic, FUDaeGeometryInput::Semantic input_semantic, int32 input_set)
Returns the semantic of the uvset with the specified input set, or an empty string if the given mater...
TypeHandle is the identifier used to differentiate C++ class types.
void apply_to_primitive(const string semantic, const PT(EggPrimitive) to)
Applies the stuff to the given EggPrimitive.
static const LVecBase4f & zero()
Returns a zero-length vector.
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).