Panda3D
daeMaterials.cxx
1 // Filename: daeMaterials.cxx
2 // Created by: pro-rsoft (03Oct08)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "daeMaterials.h"
16 #include "config_daeegg.h"
17 #include "fcollada_utils.h"
18 
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"
25 
26 #include "filename.h"
27 #include "string_utils.h"
28 
29 TypeHandle DaeMaterials::_type_handle;
30 
31 // luminance function, based on the ISO/CIE color standards
32 // see ITU-R Recommendation BT.709-4
33 #define luminance(c) ((c[0] * 0.212671 + c[1] * 0.715160 + c[2] * 0.072169))
34 
35 ////////////////////////////////////////////////////////////////////
36 // Function: DaeMaterials::Constructor
37 // Access: Public
38 // Description:
39 ////////////////////////////////////////////////////////////////////
40 DaeMaterials::
41 DaeMaterials(const FCDGeometryInstance* geometry_instance) {
42  for (size_t mi = 0; mi < geometry_instance->GetMaterialInstanceCount(); ++mi) {
43  add_material_instance(geometry_instance->GetMaterialInstance(mi));
44  }
45 }
46 
47 ////////////////////////////////////////////////////////////////////
48 // Function: DaeMaterials::add_material_instance
49 // Access: Public
50 // Description: Adds a material instance. Normally automatically
51 // done by constructor.
52 ////////////////////////////////////////////////////////////////////
53 void DaeMaterials::add_material_instance(const FCDMaterialInstance* instance) {
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;
58  return;
59  }
60  _materials[semantic] = new DaeMaterial();
61 
62  // Load in the uvsets
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;
71 #else
72  bvi->_input_semantic = mivib->inputSemantic;
73  bvi->_semantic = FROM_FSTRING(mivib->semantic);
74 #endif
75  _materials[semantic]->_uvsets.push_back(bvi);
76  }
77 
78  // Handle the material stuff
79  daeegg_cat.spam() << "Trying to process material with semantic " << semantic << endl;
80  PT_EggMaterial egg_material = new EggMaterial(semantic);
81  pvector<PT_EggTexture> egg_textures;
82  const FCDEffect* effect = instance->GetMaterial()->GetEffect();
83  if (effect == NULL) {
84  daeegg_cat.debug() << "Ignoring material (semantic: " << semantic << ") without assigned effect" << endl;
85  } else {
86  // Grab the common profile effect
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;
91  } else {
92  daeegg_cat.spam() << "Processing effect, material semantic is " << semantic << endl;
93  // Set the material parameters
94  egg_material->set_amb(TO_COLOR(effect_common->GetAmbientColor()));
95  ////We already process transparency using blend modes
96  //LVecBase4 diffuse = TO_COLOR(effect_common->GetDiffuseColor());
97  //diffuse.set_w(diffuse.get_w() * (1.0f - effect_common->GetOpacity()));
98  //egg_material->set_diff(diffuse);
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()));
103  // Now try to load in the textures
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);
112 #endif
113  // Now, calculate the color blend stuff.
114  _materials[semantic]->_blend = convert_blend(effect_common->GetTransparencyMode(),
115  TO_COLOR(effect_common->GetTranslucencyColor()),
116  effect_common->GetTranslucencyFactor());
117  }
118  // Find an <extra> tag to support some extra stuff from extensions
119  process_extra(semantic, effect->GetExtra());
120  }
121  daeegg_cat.spam() << "Found " << egg_textures.size() << " textures in material" << endl;
122  _materials[semantic]->_egg_material = egg_material;
123 }
124 
125 ////////////////////////////////////////////////////////////////////
126 // Function: DaeMaterials::process_texture_bucket
127 // Access: Private
128 // Description: Processes the given texture bucket and gives
129 // the textures in it the given envtype and format.
130 ////////////////////////////////////////////////////////////////////
131 void DaeMaterials::
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();
135  if (image == NULL) {
136  daeegg_cat.warning() << "Texture references a nonexisting image!" << endl;
137  } else {
138  const FCDEffectParameterSampler* sampler = effect_common->GetTexture(bucket, tx)->GetSampler();
139  // FCollada only supplies absolute paths. We need to grab the document
140  // location ourselves and make the image path absolute.
141  Filename texpath;
142  if (image->GetDocument()) {
143  Filename docpath = Filename::from_os_specific(FROM_FSTRING(image->GetDocument()->GetFileUrl()));
144  docpath.make_canonical();
145  texpath = Filename::from_os_specific(FROM_FSTRING(image->GetFilename()));
146  texpath.make_canonical();
147  texpath.make_relative_to(docpath.get_dirname(), true);
148  daeegg_cat.debug() << "Found texture with path " << texpath << endl;
149  } else {
150  // Never mind.
151  texpath = Filename::from_os_specific(FROM_FSTRING(image->GetFilename()));
152  }
153  PT_EggTexture egg_texture = new EggTexture(FROM_FSTRING(image->GetDaeId()), texpath.to_os_generic());
154  // Find a set of UV coordinates
155  const FCDEffectParameterInt* uvset = effect_common->GetTexture(bucket, tx)->GetSet();
156  if (uvset != NULL) {
157  daeegg_cat.debug() << "Texture has uv name '" << FROM_FSTRING(uvset->GetSemantic()) << "'\n";
158  string uvset_semantic (FROM_FSTRING(uvset->GetSemantic()));
159 
160  // Only set the UV name if this UV set actually exists.
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);
164  break;
165  }
166  }
167  }
168  // Apply sampler stuff
169  if (sampler != NULL) {
170  egg_texture->set_texture_type(convert_texture_type(sampler->GetSamplerType()));
171  egg_texture->set_wrap_u(convert_wrap_mode(sampler->GetWrapS()));
172  if (sampler->GetSamplerType() != FCDEffectParameterSampler::SAMPLER1D) {
173  egg_texture->set_wrap_v(convert_wrap_mode(sampler->GetWrapT()));
174  }
175  if (sampler->GetSamplerType() == FCDEffectParameterSampler::SAMPLER3D) {
176  egg_texture->set_wrap_w(convert_wrap_mode(sampler->GetWrapP()));
177  }
178  egg_texture->set_minfilter(convert_filter_type(sampler->GetMinFilter()));
179  egg_texture->set_magfilter(convert_filter_type(sampler->GetMagFilter()));
180  if (envtype != EggTexture::ET_unspecified) {
181  egg_texture->set_env_type(envtype);
182  }
183  if (format != EggTexture::F_unspecified) {
184  egg_texture->set_format(format);
185  }
186  }
187  _materials[semantic]->_egg_textures.push_back(egg_texture);
188  }
189  }
190 }
191 
192 ////////////////////////////////////////////////////////////////////
193 // Function: DaeMaterials::process_extra
194 // Access: Private
195 // Description: Processes the extra data in the given <extra> tag.
196 // If the given element is NULL, it just silently
197 // returns.
198 ////////////////////////////////////////////////////////////////////
199 void DaeMaterials::
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");
206  if (enode != NULL) {
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;
212  } else {
213  daeegg_cat.warning() << "Expected <double_sided> tag to be either 1 or 0, found '" << content << "' instead" << endl;
214  }
215  }
216  }
217 }
218 
219 ////////////////////////////////////////////////////////////////////
220 // Function: DaeMaterials::apply_to
221 // Access: Public
222 // Description: Applies the stuff to the given EggPrimitive.
223 ////////////////////////////////////////////////////////////////////
224 void DaeMaterials::
225 apply_to_primitive(const string semantic, const PT(EggPrimitive) to) {
226  if (_materials.count(semantic) > 0) {
227  to->set_material(_materials[semantic]->_egg_material);
228  for (pvector<PT_EggTexture>::iterator it = _materials[semantic]->_egg_textures.begin(); it != _materials[semantic]->_egg_textures.end(); ++it) {
229  daeegg_cat.spam() << "Applying texture " << (*it)->get_name() << " from material with semantic " << semantic << endl;
230  to->add_texture(*it);
231  }
232  to->set_bface_flag(_materials[semantic]->_double_sided);
233  }
234 }
235 
236 ////////////////////////////////////////////////////////////////////
237 // Function: DaeMaterials::apply_to
238 // Access: Public
239 // Description: Applies the colorblend stuff to the given EggGroup.
240 ////////////////////////////////////////////////////////////////////
241 void DaeMaterials::
242 apply_to_group(const string semantic, const PT(EggGroup) to, bool invert_transparency) {
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);
251  } else {
252  to->set_blend_operand_a(blend->_operand_a);
253  to->set_blend_operand_b(blend->_operand_b);
254  }
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);
260  }
261  }
262 }
263 
264 ////////////////////////////////////////////////////////////////////
265 // Function: DaeMaterials::get_uvset_name
266 // Access: Public
267 // Description: Returns the semantic of the uvset with the
268 // specified input set, or an empty string if the
269 // given material has no input set.
270 ////////////////////////////////////////////////////////////////////
271 const string DaeMaterials::
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;
276  } else {
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;
281  }
282  }
283  // If we can't find it, let's look again, but don't care for the
284  // input_semantic this time. The reason for this is that some tools
285  // export textangents and texbinormals bound to a uvset with input
286  // semantic TEXCOORD.
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;
291  }
292  }
293  daeegg_cat.debug() << "No uv set binding found for input set " << input_set << "\n";
294  }
295  }
296  return "";
297 }
298 
299 ////////////////////////////////////////////////////////////////////
300 // Function: DaeMaterials::convert_texture_type
301 // Access: Public, Static
302 // Description: Converts an FCollada sampler type to the EggTexture
303 // texture type equivalent.
304 ////////////////////////////////////////////////////////////////////
305 EggTexture::TextureType DaeMaterials::
306 convert_texture_type(const FCDEffectParameterSampler::SamplerType orig_type) {
307  switch (orig_type) {
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;
316  default:
317  daeegg_cat.warning() << "Invalid sampler type found" << endl;
318  }
319  return EggTexture::TT_unspecified;
320 }
321 
322 ////////////////////////////////////////////////////////////////////
323 // Function: DaeMaterials::convert_wrap_mode
324 // Access: Public, Static
325 // Description: Converts an FCollada wrap mode to the
326 // EggTexture wrap mode equivalent.
327 ////////////////////////////////////////////////////////////////////
328 EggTexture::WrapMode DaeMaterials::
329 convert_wrap_mode(const FUDaeTextureWrapMode::WrapMode orig_mode) {
330  switch (orig_mode) {
331  case FUDaeTextureWrapMode::NONE:
332  //FIXME: this shouldnt be unspecified
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;
344  default:
345  daeegg_cat.warning() << "Invalid wrap mode found: " << FUDaeTextureWrapMode::ToString(orig_mode) << endl;
346  }
347  return EggTexture::WM_unspecified;
348 }
349 
350 ////////////////////////////////////////////////////////////////////
351 // Function: DaeMaterials::convert_filter_type
352 // Access: Public, Static
353 // Description: Converts an FCollada filter function to the
354 // EggTexture wrap type equivalent.
355 ////////////////////////////////////////////////////////////////////
356 EggTexture::FilterType DaeMaterials::
357 convert_filter_type(const FUDaeTextureFilterFunction::FilterFunction orig_type) {
358  switch (orig_type) {
359  case FUDaeTextureFilterFunction::NONE:
360  //FIXME: this shouldnt be unspecified
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;
376  default:
377  daeegg_cat.warning() << "Unknown filter type found: " << FUDaeTextureFilterFunction::ToString(orig_type) << endl;
378  }
379  return EggTexture::FT_unspecified;
380 }
381 
382 ////////////////////////////////////////////////////////////////////
383 // Function: DaeMaterials::convert_blend
384 // Access: Private, Static
385 // Description: Converts collada blend attribs to Panda's equivalents.
386 ////////////////////////////////////////////////////////////////////
387 PT(DaeMaterials::DaeBlendSettings) DaeMaterials::
388 convert_blend(FCDEffectStandard::TransparencyMode mode, const LColor &transparent, double transparency) {
389  // Create the DaeBlendSettings and fill it with some defaults.
390  PT(DaeBlendSettings) blend = new DaeBlendSettings();
391  blend->_enabled = true;
392  blend->_color = LColor::zero();
393  blend->_operand_a = EggGroup::BO_unspecified;
394  blend->_operand_b = EggGroup::BO_unspecified;
395 
396  // First fill in the color value.
397  if (mode == FCDEffectStandard::A_ONE) {// || mode == FCDEffectStandard::A_ZERO) {
398  double value = transparent[3] * transparency;
399  blend->_color = LColor(value, value, value, value);
400  } else if (mode == FCDEffectStandard::RGB_ZERO) {//|| mode == FCDEffectStandard::RGB_ONE) {
401  blend->_color = transparent * transparency;
402  blend->_color[3] = luminance(blend->_color);
403  } else {
404  daeegg_cat.error() << "Unknown opaque type found!" << endl;
405  blend->_enabled = false;
406  return blend;
407  }
408 
409  // Now figure out the operands.
410  if (mode == FCDEffectStandard::RGB_ZERO) {// || mode == FCDEffectStandard::A_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) {// || mode == FCDEffectStandard::RGB_ONE) {
414  blend->_operand_a = EggGroup::BO_constant_color;
415  blend->_operand_b = EggGroup::BO_one_minus_constant_color;
416  } else {
417  daeegg_cat.error() << "Unknown opaque type found!" << endl;
418  blend->_enabled = false;
419  return blend;
420  }
421 
422  // See if we can optimize out the color.
423  if (blend->_operand_a == EggGroup::BO_constant_color) {
424  if (blend->_color == LColor::zero()) {
425  blend->_operand_a = EggGroup::BO_zero;
426  } else if (blend->_color == LColor(1, 1, 1, 1)) {
427  blend->_operand_a = EggGroup::BO_one;
428  }
429  }
430  if (blend->_operand_b == EggGroup::BO_constant_color) {
431  if (blend->_color == LColor::zero()) {
432  blend->_operand_b = EggGroup::BO_zero;
433  } else if (blend->_color == LColor(1, 1, 1, 1)) {
434  blend->_operand_b = EggGroup::BO_one;
435  }
436  }
437  if (blend->_operand_a == EggGroup::BO_one_minus_constant_color) {
438  if (blend->_color == LColor::zero()) {
439  blend->_operand_a = EggGroup::BO_one;
440  } else if (blend->_color == LColor(1, 1, 1, 1)) {
441  blend->_operand_a = EggGroup::BO_zero;
442  }
443  }
444  if (blend->_operand_b == EggGroup::BO_one_minus_constant_color) {
445  if (blend->_color == LColor::zero()) {
446  blend->_operand_b = EggGroup::BO_one;
447  } else if (blend->_color == LColor(1, 1, 1, 1)) {
448  blend->_operand_b = EggGroup::BO_zero;
449  }
450  }
451 
452  // See if we can entirely disable the blend.
453  if (blend->_operand_a == EggGroup::BO_one && blend->_operand_b == EggGroup::BO_zero) {
454  blend->_enabled = false;
455  }
456  return blend;
457 }
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
Definition: eggPrimitive.h:51
string get_dirname() const
Returns the directory part of the filename.
Definition: filename.I:424
void add_texture(EggTexture *texture)
Applies the indicated texture to the primitive.
Definition: eggPrimitive.I:197
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:33
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...
Definition: filename.cxx:1072
string to_os_generic() const
This is similar to to_os_specific(), but it is designed to generate a filename that can be understood...
Definition: filename.cxx:1261
void set_bface_flag(bool flag)
Sets the backfacing flag of the polygon.
Definition: eggPrimitive.I:289
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:36
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
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.
Definition: eggPrimitive.I:241
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).
Definition: filename.cxx:1766
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
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.
Definition: typeHandle.h:85
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.
Definition: lvecBase4.h:493
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).
Definition: filename.cxx:332