00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "daeMaterials.h"
00016 #include "config_daeegg.h"
00017 #include "fcollada_utils.h"
00018
00019 #include "FCDocument/FCDocument.h"
00020 #include "FCDocument/FCDMaterial.h"
00021 #include "FCDocument/FCDEffect.h"
00022 #include "FCDocument/FCDTexture.h"
00023 #include "FCDocument/FCDEffectParameterSampler.h"
00024 #include "FCDocument/FCDImage.h"
00025
00026 #include "filename.h"
00027 #include "string_utils.h"
00028
00029 TypeHandle DaeMaterials::_type_handle;
00030
00031
00032
00033 #define luminance(c) ((c[0] * 0.212671 + c[1] * 0.715160 + c[2] * 0.072169))
00034
00035
00036
00037
00038
00039
00040 DaeMaterials::
00041 DaeMaterials(const FCDGeometryInstance* geometry_instance) {
00042 for (size_t mi = 0; mi < geometry_instance->GetMaterialInstanceCount(); ++mi) {
00043 add_material_instance(geometry_instance->GetMaterialInstance(mi));
00044 }
00045 }
00046
00047
00048
00049
00050
00051
00052
00053 void DaeMaterials::add_material_instance(const FCDMaterialInstance* instance) {
00054 nassertv(instance != NULL);
00055 const string semantic (FROM_FSTRING(instance->GetSemantic()));
00056 if (_materials.count(semantic) > 0) {
00057 daeegg_cat.warning() << "Ignoring duplicate material with semantic " << semantic << endl;
00058 return;
00059 }
00060 _materials[semantic] = new DaeMaterial();
00061
00062
00063 for (size_t vib = 0; vib < instance->GetVertexInputBindingCount(); ++vib) {
00064 const FCDMaterialInstanceBindVertexInput* mivib = instance->GetVertexInputBinding(vib);
00065 assert(mivib != NULL);
00066 PT(DaeVertexInputBinding) bvi = new DaeVertexInputBinding();
00067 bvi->_input_set = mivib->inputSet;
00068 #if FCOLLADA_VERSION >= 0x00030005
00069 bvi->_input_semantic = mivib->GetInputSemantic();
00070 bvi->_semantic = *mivib->semantic;
00071 #else
00072 bvi->_input_semantic = mivib->inputSemantic;
00073 bvi->_semantic = FROM_FSTRING(mivib->semantic);
00074 #endif
00075 _materials[semantic]->_uvsets.push_back(bvi);
00076 }
00077
00078
00079 daeegg_cat.spam() << "Trying to process material with semantic " << semantic << endl;
00080 PT_EggMaterial egg_material = new EggMaterial(semantic);
00081 pvector<PT_EggTexture> egg_textures;
00082 const FCDEffect* effect = instance->GetMaterial()->GetEffect();
00083 if (effect == NULL) {
00084 daeegg_cat.debug() << "Ignoring material (semantic: " << semantic << ") without assigned effect" << endl;
00085 } else {
00086
00087 const FCDEffectStandard* effect_common = (FCDEffectStandard *)effect->FindProfile(FUDaeProfileType::COMMON);
00088 if (effect_common == NULL) {
00089 daeegg_cat.info() << "Ignoring effect referenced by material with semantic " << semantic
00090 << " because it has no common profile" << endl;
00091 } else {
00092 daeegg_cat.spam() << "Processing effect, material semantic is " << semantic << endl;
00093
00094 egg_material->set_amb(TO_COLOR(effect_common->GetAmbientColor()));
00095
00096
00097
00098
00099 egg_material->set_diff(TO_COLOR(effect_common->GetDiffuseColor()));
00100 egg_material->set_emit(TO_COLOR(effect_common->GetEmissionColor()) * effect_common->GetEmissionFactor());
00101 egg_material->set_shininess(effect_common->GetShininess());
00102 egg_material->set_spec(TO_COLOR(effect_common->GetSpecularColor()));
00103
00104 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::DIFFUSE, EggTexture::ET_modulate);
00105 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::BUMP, EggTexture::ET_normal);
00106 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::SPECULAR, EggTexture::ET_modulate_gloss);
00107 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::SPECULAR_LEVEL, EggTexture::ET_gloss);
00108 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::TRANSPARENT, EggTexture::ET_unspecified, EggTexture::F_alpha);
00109 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::EMISSION, EggTexture::ET_add);
00110 #if FCOLLADA_VERSION < 0x00030005
00111 process_texture_bucket(semantic, effect_common, FUDaeTextureChannel::OPACITY, EggTexture::ET_unspecified, EggTexture::F_alpha);
00112 #endif
00113
00114 _materials[semantic]->_blend = convert_blend(effect_common->GetTransparencyMode(),
00115 TO_COLOR(effect_common->GetTranslucencyColor()),
00116 effect_common->GetTranslucencyFactor());
00117 }
00118
00119 process_extra(semantic, effect->GetExtra());
00120 }
00121 daeegg_cat.spam() << "Found " << egg_textures.size() << " textures in material" << endl;
00122 _materials[semantic]->_egg_material = egg_material;
00123 }
00124
00125
00126
00127
00128
00129
00130
00131 void DaeMaterials::
00132 process_texture_bucket(const string semantic, const FCDEffectStandard* effect_common, FUDaeTextureChannel::Channel bucket, EggTexture::EnvType envtype, EggTexture::Format format) {
00133 for (size_t tx = 0; tx < effect_common->GetTextureCount(bucket); ++tx) {
00134 const FCDImage* image = effect_common->GetTexture(bucket, tx)->GetImage();
00135 if (image == NULL) {
00136 daeegg_cat.warning() << "Texture references a nonexisting image!" << endl;
00137 } else {
00138 const FCDEffectParameterSampler* sampler = effect_common->GetTexture(bucket, tx)->GetSampler();
00139
00140
00141 Filename texpath;
00142 if (image->GetDocument()) {
00143 Filename docpath = Filename::from_os_specific(FROM_FSTRING(image->GetDocument()->GetFileUrl()));
00144 docpath.make_canonical();
00145 texpath = Filename::from_os_specific(FROM_FSTRING(image->GetFilename()));
00146 texpath.make_canonical();
00147 texpath.make_relative_to(docpath.get_dirname(), true);
00148 daeegg_cat.debug() << "Found texture with path " << texpath << endl;
00149 } else {
00150
00151 texpath = Filename::from_os_specific(FROM_FSTRING(image->GetFilename()));
00152 }
00153 PT_EggTexture egg_texture = new EggTexture(FROM_FSTRING(image->GetDaeId()), texpath.to_os_generic());
00154
00155 const FCDEffectParameterInt* uvset = effect_common->GetTexture(bucket, tx)->GetSet();
00156 if (uvset != NULL) {
00157 daeegg_cat.debug() << "Texture has uv name '" << FROM_FSTRING(uvset->GetSemantic()) << "'\n";
00158 egg_texture->set_uv_name(FROM_FSTRING(uvset->GetSemantic()));
00159 }
00160
00161 if (sampler != NULL) {
00162 egg_texture->set_texture_type(convert_texture_type(sampler->GetSamplerType()));
00163 egg_texture->set_wrap_u(convert_wrap_mode(sampler->GetWrapS()));
00164 if (sampler->GetSamplerType() != FCDEffectParameterSampler::SAMPLER1D) {
00165 egg_texture->set_wrap_v(convert_wrap_mode(sampler->GetWrapT()));
00166 }
00167 if (sampler->GetSamplerType() == FCDEffectParameterSampler::SAMPLER3D) {
00168 egg_texture->set_wrap_w(convert_wrap_mode(sampler->GetWrapP()));
00169 }
00170 egg_texture->set_minfilter(convert_filter_type(sampler->GetMinFilter()));
00171 egg_texture->set_magfilter(convert_filter_type(sampler->GetMagFilter()));
00172 if (envtype != EggTexture::ET_unspecified) {
00173 egg_texture->set_env_type(envtype);
00174 }
00175 if (format != EggTexture::F_unspecified) {
00176 egg_texture->set_format(format);
00177 }
00178 }
00179 _materials[semantic]->_egg_textures.push_back(egg_texture);
00180 }
00181 }
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191 void DaeMaterials::
00192 process_extra(const string semantic, const FCDExtra* extra) {
00193 if (extra == NULL) return;
00194 const FCDEType* etype = extra->GetDefaultType();
00195 if (etype == NULL) return;
00196 for (size_t et = 0; et < etype->GetTechniqueCount(); ++et) {
00197 const FCDENode* enode = ((const FCDENode*)(etype->GetTechnique(et)))->FindChildNode("double_sided");
00198 if (enode != NULL) {
00199 if (trim(enode->GetContent()) == "1") {
00200 _materials[semantic]->_double_sided = true;
00201 } else if (trim(enode->GetContent()) == "0") {
00202 _materials[semantic]->_double_sided = false;
00203 } else {
00204 daeegg_cat.warning() << "Expected <double_sided> tag to be either 1 or 0, found '" << enode->GetContent() << "' instead" << endl;
00205 }
00206 }
00207 }
00208 }
00209
00210
00211
00212
00213
00214
00215 void DaeMaterials::
00216 apply_to(const string semantic, const PT(EggPrimitive) to) {
00217 if (_materials.count(semantic) > 0) {
00218 to->set_material(_materials[semantic]->_egg_material);
00219 for (pvector<PT_EggTexture>::iterator it = _materials[semantic]->_egg_textures.begin(); it != _materials[semantic]->_egg_textures.end(); ++it) {
00220 daeegg_cat.spam() << "Applying texture " << (*it)->get_name() << " from material with semantic " << semantic << endl;
00221 to->add_texture(*it);
00222 }
00223 to->set_bface_flag(_materials[semantic]->_double_sided);
00224 }
00225 }
00226
00227
00228
00229
00230
00231
00232 void DaeMaterials::
00233 apply_to(const string semantic, const PT(EggGroup) to) {
00234 if (_materials.count(semantic) > 0) {
00235 PT(DaeBlendSettings) blend = _materials[semantic]->_blend;
00236 if (blend && blend->_enabled) {
00237 to->set_blend_mode(EggGroup::BM_add);
00238 to->set_blend_color(blend->_color);
00239 to->set_blend_operand_a(blend->_operand_a);
00240 to->set_blend_operand_b(blend->_operand_b);
00241 }
00242 }
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252 const string DaeMaterials::
00253 get_uvset_name(const string semantic, FUDaeGeometryInput::Semantic input_semantic, int32 input_set) {
00254 if (_materials.count(semantic) > 0) {
00255 if (input_set == -1 && _materials[semantic]->_uvsets.size() == 1) {
00256 return _materials[semantic]->_uvsets[0]->_semantic;
00257 } else {
00258 for (int i = 0; i < _materials[semantic]->_uvsets.size(); ++i) {
00259 if (_materials[semantic]->_uvsets[i]->_input_set == input_set &&
00260 _materials[semantic]->_uvsets[i]->_input_semantic == input_semantic) {
00261 return _materials[semantic]->_uvsets[i]->_semantic;
00262 }
00263 }
00264
00265
00266
00267
00268 for (int i = 0; i < _materials[semantic]->_uvsets.size(); ++i) {
00269 if (_materials[semantic]->_uvsets[i]->_input_set == input_set) {
00270 daeegg_cat.debug() << "Using uv set with non-matching input semantic " << _materials[semantic]->_uvsets[i]->_semantic << "\n";
00271 return _materials[semantic]->_uvsets[i]->_semantic;
00272 }
00273 }
00274 daeegg_cat.debug() << "No uv set binding found for input set " << input_set << "\n";
00275 }
00276 }
00277 return "";
00278 }
00279
00280
00281
00282
00283
00284
00285
00286 EggTexture::TextureType DaeMaterials::
00287 convert_texture_type(const FCDEffectParameterSampler::SamplerType orig_type) {
00288 switch (orig_type) {
00289 case FCDEffectParameterSampler::SAMPLER1D:
00290 return EggTexture::TT_1d_texture;
00291 case FCDEffectParameterSampler::SAMPLER2D:
00292 return EggTexture::TT_2d_texture;
00293 case FCDEffectParameterSampler::SAMPLER3D:
00294 return EggTexture::TT_3d_texture;
00295 case FCDEffectParameterSampler::SAMPLERCUBE:
00296 return EggTexture::TT_cube_map;
00297 default:
00298 daeegg_cat.warning() << "Invalid sampler type found" << endl;
00299 }
00300 return EggTexture::TT_unspecified;
00301 }
00302
00303
00304
00305
00306
00307
00308
00309 EggTexture::WrapMode DaeMaterials::
00310 convert_wrap_mode(const FUDaeTextureWrapMode::WrapMode orig_mode) {
00311 switch (orig_mode) {
00312 case FUDaeTextureWrapMode::NONE:
00313
00314 return EggTexture::WM_unspecified;
00315 case FUDaeTextureWrapMode::WRAP:
00316 return EggTexture::WM_repeat;
00317 case FUDaeTextureWrapMode::MIRROR:
00318 return EggTexture::WM_mirror;
00319 case FUDaeTextureWrapMode::CLAMP:
00320 return EggTexture::WM_clamp;
00321 case FUDaeTextureWrapMode::BORDER:
00322 return EggTexture::WM_border_color;
00323 case FUDaeTextureWrapMode::UNKNOWN:
00324 return EggTexture::WM_unspecified;
00325 default:
00326 daeegg_cat.warning() << "Invalid wrap mode found: " << FUDaeTextureWrapMode::ToString(orig_mode) << endl;
00327 }
00328 return EggTexture::WM_unspecified;
00329 }
00330
00331
00332
00333
00334
00335
00336
00337 EggTexture::FilterType DaeMaterials::
00338 convert_filter_type(const FUDaeTextureFilterFunction::FilterFunction orig_type) {
00339 switch (orig_type) {
00340 case FUDaeTextureFilterFunction::NONE:
00341
00342 return EggTexture::FT_unspecified;
00343 case FUDaeTextureFilterFunction::NEAREST:
00344 return EggTexture::FT_nearest;
00345 case FUDaeTextureFilterFunction::LINEAR:
00346 return EggTexture::FT_linear;
00347 case FUDaeTextureFilterFunction::NEAREST_MIPMAP_NEAREST:
00348 return EggTexture::FT_nearest_mipmap_nearest;
00349 case FUDaeTextureFilterFunction::LINEAR_MIPMAP_NEAREST:
00350 return EggTexture::FT_linear_mipmap_nearest;
00351 case FUDaeTextureFilterFunction::NEAREST_MIPMAP_LINEAR:
00352 return EggTexture::FT_nearest_mipmap_linear;
00353 case FUDaeTextureFilterFunction::LINEAR_MIPMAP_LINEAR:
00354 return EggTexture::FT_linear_mipmap_linear;
00355 case FUDaeTextureFilterFunction::UNKNOWN:
00356 return EggTexture::FT_unspecified;
00357 default:
00358 daeegg_cat.warning() << "Unknown filter type found: " << FUDaeTextureFilterFunction::ToString(orig_type) << endl;
00359 }
00360 return EggTexture::FT_unspecified;
00361 }
00362
00363
00364
00365
00366
00367
00368 PT(DaeMaterials::DaeBlendSettings) DaeMaterials::
00369 convert_blend(FCDEffectStandard::TransparencyMode mode, Colorf transparent, double transparency) {
00370
00371 PT(DaeBlendSettings) blend = new DaeBlendSettings();
00372 blend->_enabled = true;
00373 blend->_color = Colorf::zero();
00374 blend->_operand_a = EggGroup::BO_unspecified;
00375 blend->_operand_b = EggGroup::BO_unspecified;
00376
00377
00378 if (mode == FCDEffectStandard::A_ONE) {
00379 double value = transparent[3] * transparency;
00380 blend->_color = Colorf(value, value, value, value);
00381 } else if (mode == FCDEffectStandard::RGB_ZERO) {
00382 blend->_color = transparent * transparency;
00383 blend->_color[3] = luminance(blend->_color);
00384 } else {
00385 daeegg_cat.error() << "Unknown opaque type found!" << endl;
00386 blend->_enabled = false;
00387 return blend;
00388 }
00389
00390
00391 if (mode == FCDEffectStandard::RGB_ZERO) {
00392 blend->_operand_a = EggGroup::BO_one_minus_constant_color;
00393 blend->_operand_b = EggGroup::BO_constant_color;
00394 } else if (mode == FCDEffectStandard::A_ONE) {
00395 blend->_operand_a = EggGroup::BO_constant_color;
00396 blend->_operand_b = EggGroup::BO_one_minus_constant_color;
00397 } else {
00398 daeegg_cat.error() << "Unknown opaque type found!" << endl;
00399 blend->_enabled = false;
00400 return blend;
00401 }
00402
00403
00404 if (blend->_operand_a == EggGroup::BO_constant_color) {
00405 if ((blend->_color[0] == 0) && (blend->_color[1] == 0) && (blend->_color[2] == 0) && (blend->_color[3] == 0)) {
00406 blend->_operand_a = EggGroup::BO_zero;
00407 }
00408 if ((blend->_color[0] == 1) && (blend->_color[1] == 1) && (blend->_color[2] == 1) && (blend->_color[3] == 1)) {
00409 blend->_operand_a = EggGroup::BO_one;
00410 }
00411 }
00412 if (blend->_operand_b == EggGroup::BO_constant_color) {
00413 if ((blend->_color[0] == 0) && (blend->_color[1] == 0) && (blend->_color[2] == 0) && (blend->_color[3] == 0)) {
00414 blend->_operand_b = EggGroup::BO_zero;
00415 }
00416 if ((blend->_color[0] == 1) && (blend->_color[1] == 1) && (blend->_color[2] == 1) && (blend->_color[3] == 1)) {
00417 blend->_operand_b = EggGroup::BO_one;
00418 }
00419 }
00420 if (blend->_operand_a == EggGroup::BO_one_minus_constant_color) {
00421 if ((blend->_color[0] == 0) && (blend->_color[1] == 0) && (blend->_color[2] == 0) && (blend->_color[3] == 0)) {
00422 blend->_operand_a = EggGroup::BO_one;
00423 }
00424 if ((blend->_color[0] == 1) && (blend->_color[1] == 1) && (blend->_color[2] == 1) && (blend->_color[3] == 1)) {
00425 blend->_operand_a = EggGroup::BO_zero;
00426 }
00427 }
00428 if (blend->_operand_b == EggGroup::BO_one_minus_constant_color) {
00429 if ((blend->_color[0] == 0) && (blend->_color[1] == 0) && (blend->_color[2] == 0) && (blend->_color[3] == 0)) {
00430 blend->_operand_b = EggGroup::BO_one;
00431 }
00432 if ((blend->_color[0] == 1) && (blend->_color[1] == 1) && (blend->_color[2] == 1) && (blend->_color[3] == 1)) {
00433 blend->_operand_b = EggGroup::BO_zero;
00434 }
00435 }
00436
00437
00438 if (blend->_operand_a == EggGroup::BO_one && blend->_operand_b == EggGroup::BO_zero) {
00439 blend->_enabled = false;
00440 }
00441 return blend;
00442 }