Panda3D
 All Classes Functions Variables Enumerations
mayaShaderColorDef.cxx
00001 // Filename: mayaShaderColorDef.cxx
00002 // Created by:  drose (12Apr03)
00003 // Modified 19Mar10 by ETC PandaSE team (see
00004 //   header comment for mayaToEgg.cxx for details)
00005 //
00006 ////////////////////////////////////////////////////////////////////
00007 //
00008 // PANDA 3D SOFTWARE
00009 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00010 //
00011 // All use of this software is subject to the terms of the revised BSD
00012 // license.  You should have received a copy of this license along
00013 // with this source code in a file named "LICENSE."
00014 //
00015 ////////////////////////////////////////////////////////////////////
00016 
00017 #include "mayaShaderColorDef.h"
00018 #include "mayaShader.h"
00019 #include "maya_funcs.h"
00020 #include "config_maya.h"
00021 #include "string_utils.h"
00022 #include "pset.h"
00023 
00024 #include "pre_maya_include.h"
00025 #include <maya/MFnDependencyNode.h>
00026 #include <maya/MPlug.h>
00027 #include <maya/MPlugArray.h>
00028 #include <maya/MObject.h>
00029 #include <maya/MStatus.h>
00030 #include <maya/MFnEnumAttribute.h>
00031 #include "post_maya_include.h"
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: MayaShaderColorDef::Constructor
00035 //       Access: Public
00036 //  Description: 
00037 ////////////////////////////////////////////////////////////////////
00038 MayaShaderColorDef::
00039 MayaShaderColorDef() {
00040 
00041   _blend_type = BT_unspecified;
00042 
00043   _projection_type = PT_off;
00044   _projection_matrix = LMatrix4d::ident_mat();
00045   _u_angle = 0.0;
00046   _v_angle = 0.0;
00047     
00048   _texture_filename = "";
00049   _texture_name = "";
00050   _color_gain.set(1.0f, 1.0f, 1.0f, 1.0f);
00051   
00052   _coverage.set(1.0, 1.0);
00053   _translate_frame.set(0.0, 0.0);
00054   _rotate_frame = 0.0;
00055 
00056   _mirror = false;
00057   _stagger = false;
00058   _wrap_u = true;
00059   _wrap_v = true;
00060 
00061   _repeat_uv.set(1.0, 1.0);
00062   _offset.set(0.0, 0.0);
00063   _rotate_uv = 0.0;
00064 
00065   _is_alpha = false;
00066 
00067   _opposite = 0;
00068 
00069   _color_object = (MObject *)NULL;
00070 
00071   _has_texture = false;
00072   _has_flat_color = false;
00073   _flat_color.set(0.0, 0.0, 0.0, 0.0);
00074   _has_alpha_channel = false;
00075   _keep_color = false; // classic mode overwrites color: new mode retains color with a 3rd layer
00076   _keep_alpha = false;
00077   _interpolate = false;
00078   _uvset_name = "map1";
00079 
00080   _map_uvs = NULL;
00081 }
00082 
00083 ////////////////////////////////////////////////////////////////////
00084 //     Function: MayaShaderColorDef::Constructor
00085 //       Access: Public
00086 //  Description: 
00087 ////////////////////////////////////////////////////////////////////
00088 MayaShaderColorDef::
00089 MayaShaderColorDef(MayaShaderColorDef &copy) {
00090   _has_texture = copy._has_texture;
00091   _texture_filename = copy._texture_filename;
00092   _texture_name = copy._texture_name;
00093   _uvset_name = copy._uvset_name;
00094   _color_gain = copy._color_gain;
00095 
00096   _has_flat_color = copy._has_flat_color;
00097   _flat_color = copy._flat_color;
00098 
00099   _projection_type = copy._projection_type;
00100   _projection_matrix = copy._projection_matrix;
00101   _u_angle = copy._u_angle;
00102   _v_angle = copy._v_angle;
00103 
00104   _coverage = copy._coverage;
00105   _translate_frame = copy._translate_frame;
00106   _rotate_frame = copy._rotate_frame;
00107 
00108   _mirror = copy._mirror;
00109   _stagger = copy._stagger;
00110   _wrap_u = copy._wrap_u;
00111   _wrap_v = copy._wrap_v;
00112 
00113   _blend_type = copy._blend_type;
00114   _has_alpha_channel = copy._has_alpha_channel;
00115   _keep_color = copy._keep_color;
00116   _keep_alpha = copy._keep_alpha;
00117   _interpolate = copy._interpolate;
00118 
00119   _repeat_uv = copy._repeat_uv;
00120   _offset = copy._offset;
00121   _rotate_uv = copy._rotate_uv;
00122 
00123   _is_alpha = copy._is_alpha;
00124   
00125   _map_uvs = copy._map_uvs;
00126   _color_object = copy._color_object;
00127   
00128   _opposite = 0;
00129 }
00130 
00131 ////////////////////////////////////////////////////////////////////
00132 //     Function: MayaShaderColorDef::Destructor
00133 //       Access: Public
00134 //  Description: 
00135 ////////////////////////////////////////////////////////////////////
00136 MayaShaderColorDef::
00137 ~MayaShaderColorDef() {
00138   if (_color_object != (MObject *)NULL) {
00139     delete _color_object;
00140   }
00141 }
00142 
00143 ////////////////////////////////////////////////////////////////////
00144 //     Function: MayaShaderColorDef::compute_texture_matrix
00145 //       Access: Public
00146 //  Description: Returns a texture matrix corresponding to the texture
00147 //               transforms indicated by the shader.
00148 ////////////////////////////////////////////////////////////////////
00149 LMatrix3d MayaShaderColorDef::
00150 compute_texture_matrix() const {
00151   LVector2d scale(_repeat_uv[0] / _coverage[0],
00152                   _repeat_uv[1] / _coverage[1]);
00153   LVector2d trans(_offset[0] - _translate_frame[0] / _coverage[0],
00154                   _offset[1] - _translate_frame[1] / _coverage[1]);
00155 
00156   return
00157     (LMatrix3d::translate_mat(LVector2d(-0.5, -0.5)) *
00158      LMatrix3d::rotate_mat(_rotate_frame) *
00159      LMatrix3d::translate_mat(LVector2d(0.5, 0.5))) *
00160     LMatrix3d::scale_mat(scale) *
00161     LMatrix3d::translate_mat(trans);
00162 }
00163 
00164 ////////////////////////////////////////////////////////////////////
00165 //     Function: MayaShaderColorDef::has_projection
00166 //       Access: Public
00167 //  Description: Returns true if the shader has a projection in effect.
00168 ////////////////////////////////////////////////////////////////////
00169 bool MayaShaderColorDef::
00170 has_projection() const {
00171   return (_projection_type != PT_off);
00172 }
00173 
00174 ////////////////////////////////////////////////////////////////////
00175 //     Function: MayaShaderColorDef::project_uv
00176 //       Access: Public
00177 //  Description: If the shader has a projection (has_projection()
00178 //               returns true), this computes the appropriate UV
00179 //               corresponding to the indicated 3-d point.  Seams that
00180 //               might be introduced on polygons that cross quadrants
00181 //               are closed up by ensuring the point is in the same
00182 //               quadrant as the indicated reference point.
00183 ////////////////////////////////////////////////////////////////////
00184 LTexCoordd MayaShaderColorDef::
00185 project_uv(const LPoint3d &pos, const LPoint3d &centroid) const {
00186   nassertr(_map_uvs != NULL, LTexCoordd::zero());
00187   return (this->*_map_uvs)(pos * _projection_matrix, centroid * _projection_matrix);
00188 }
00189 
00190 ////////////////////////////////////////////////////////////////////
00191 //     Function: MayaShaderColorDef::write
00192 //       Access: Public
00193 //  Description: 
00194 ////////////////////////////////////////////////////////////////////
00195 void MayaShaderColorDef::
00196 write(ostream &out) const {
00197   if (_has_texture) {
00198     out << "    texture filename is " << _texture_filename << "\n"
00199         << "    texture name is " << _texture_name << "\n"
00200         << "    uv_set name is " << _uvset_name << "\n"
00201         << "    coverage is " << _coverage << "\n"
00202         << "    translate_frame is " << _translate_frame << "\n"
00203         << "    rotate_frame is " << _rotate_frame << "\n"
00204         << "    mirror is " << _mirror << "\n"
00205         << "    stagger is " << _stagger << "\n"
00206         << "    wrap_u is " << _wrap_u << "\n"
00207         << "    wrap_v is " << _wrap_v << "\n"
00208         << "    repeat_uv is " << _repeat_uv << "\n"
00209         << "    offset is " << _offset << "\n"
00210         << "    rotate_uv is " << _rotate_uv << "\n"
00211         << "    color_gain is " << _color_gain << "\n";
00212 
00213   } else if (_has_flat_color) {
00214     out << "    flat color is " << _flat_color << "\n";
00215   }
00216 }
00217 
00218 ////////////////////////////////////////////////////////////////////
00219 //     Function: MayaShaderColorDef::reset_maya_texture
00220 //       Access: Public
00221 //  Description: Changes the texture filename stored in the Maya file
00222 //               for this particular shader.
00223 ////////////////////////////////////////////////////////////////////
00224 bool MayaShaderColorDef::
00225 reset_maya_texture(const Filename &texture) {
00226   if (_color_object != (MObject *)NULL) {
00227     _has_texture = set_string_attribute(*_color_object, "fileTextureName", 
00228                                         texture.to_os_generic());
00229     _texture_filename = texture;
00230 
00231     if (!_has_texture) {
00232       maya_cat.error()
00233         << "Unable to reset texture filename.\n";
00234     }
00235 
00236     return _has_texture;
00237   }
00238 
00239   maya_cat.error()
00240     << "Attempt to reset texture on Maya object that has no color set.\n";
00241   return false;
00242 }
00243 
00244 
00245 ////////////////////////////////////////////////////////////////////
00246 //     Function: MayaShaderColorDef::get_panda_uvset_name
00247 //       Access: Private
00248 //  Description: Maya's default uvset name is "map1".  Panda's default
00249 //               uvset name is "default".  Otherwise, leaves uvset
00250 //               name untranslated.
00251 ////////////////////////////////////////////////////////////////////
00252 string MayaShaderColorDef::
00253 get_panda_uvset_name() {
00254   if (_uvset_name == "map1") {
00255     return "default";
00256   }
00257   return _uvset_name;
00258 }
00259 
00260 ////////////////////////////////////////////////////////////////////
00261 //     Function: MayaShaderColorDef::find_textures_legacy
00262 //       Access: Private
00263 //  Description: This is part of the deprecated codepath.
00264 //               Determines the surface color specified by the shader.
00265 //               This includes texturing and other advanced shader
00266 //               properties.
00267 ////////////////////////////////////////////////////////////////////
00268 void MayaShaderColorDef::
00269 find_textures_legacy(MayaShader *shader, MObject color, bool trans) {
00270   LRGBColor color_gain;
00271   if (get_vec3_attribute(color, "colorGain", color_gain)) {
00272     color_gain[0] = color_gain[0] > 1.0 ? 1.0 : color_gain[0];
00273     color_gain[0] = color_gain[0] < 0.0 ? 0.0 : color_gain[0];
00274     _color_gain[0] *= color_gain[0];
00275     color_gain[1] = color_gain[1] > 1.0 ? 1.0 : color_gain[1];
00276     color_gain[1] = color_gain[1] < 0.0 ? 0.0 : color_gain[1];
00277     _color_gain[1] *= color_gain[1];
00278     color_gain[2] = color_gain[2] > 1.0 ? 1.0 : color_gain[2];
00279     color_gain[2] = color_gain[2] < 0.0 ? 0.0 : color_gain[2];
00280     _color_gain[2] *= color_gain[2];
00281   }
00282   PN_stdfloat alpha_gain;
00283   if (get_maya_attribute(color, "alphaGain", alpha_gain)) {
00284     alpha_gain = alpha_gain > 1.0 ? 1.0 : alpha_gain;
00285     alpha_gain = alpha_gain < 0.0 ? 0.0 : alpha_gain;
00286     _color_gain[3] *= alpha_gain;
00287   }
00288   if (color.hasFn(MFn::kFileTexture)) {
00289     MFnDependencyNode dfn(color);
00290     _color_object = new MObject(color);
00291     _texture_name = dfn.name().asChar();
00292     string filename;
00293     _has_texture = get_string_attribute(color, "fileTextureName", filename);
00294     _has_texture = _has_texture && !filename.empty();
00295     if (_has_texture) {
00296       _texture_filename = Filename::from_os_specific(filename);
00297       if (_texture_filename.is_directory()) {
00298         maya_cat.warning()
00299           << "Shader " << shader->get_name()
00300           << " references texture filename " << filename
00301           << " which is a directory; clearing.\n";
00302         _has_texture = false;
00303         set_string_attribute(color, "fileTextureName", "");
00304       }
00305     }
00306 
00307     get_vec2_attribute(color, "coverage", _coverage);
00308     get_vec2_attribute(color, "translateFrame", _translate_frame);
00309     get_angle_attribute(color, "rotateFrame", _rotate_frame);
00310 
00311     //get_bool_attribute(color, "alphaIsLuminance", _alpha_is_luminance);
00312 
00313     get_bool_attribute(color, "mirror", _mirror);
00314     get_bool_attribute(color, "stagger", _stagger);
00315     get_bool_attribute(color, "wrapU", _wrap_u);
00316     get_bool_attribute(color, "wrapV", _wrap_v);
00317 
00318     get_vec2_attribute(color, "repeatUV", _repeat_uv);
00319     get_vec2_attribute(color, "offset", _offset);
00320     get_angle_attribute(color, "rotateUV", _rotate_uv);
00321 
00322     if (!trans) {
00323       if (maya_cat.is_debug()) {
00324         maya_cat.debug() << "pushed a file texture" << endl;
00325       }
00326       shader->_color.push_back(this);
00327     }
00328 
00329   } else if (color.hasFn(MFn::kProjection)) {
00330     if (maya_cat.is_debug()) {
00331       maya_cat.debug() << "reading a projection texture" << endl;
00332     }
00333     // This is a projected texture.  We will have to step one level
00334     // deeper to find the actual texture.
00335     MFnDependencyNode projection_fn(color);
00336     MPlug image_plug = projection_fn.findPlug("image");
00337     if (!image_plug.isNull()) {
00338       MPlugArray image_pa;
00339       image_plug.connectedTo(image_pa, true, false);
00340       
00341       for (size_t i = 0; i < image_pa.length(); i++) {
00342         find_textures_legacy(shader, image_pa[0].node());
00343       }
00344     }
00345 
00346     if (!get_mat4d_attribute(color, "placementMatrix", _projection_matrix)) {
00347       _projection_matrix = LMatrix4d::ident_mat();
00348     }
00349 
00350     // The uAngle and vAngle might be used for certain kinds of
00351     // projections.
00352     if (!get_angle_attribute(color, "uAngle", _u_angle)) {
00353       _u_angle = 360.0;
00354     }
00355     if (!get_angle_attribute(color, "vAngle", _v_angle)) {
00356       _v_angle = 180.0;
00357     }
00358 
00359     string type;
00360     if (get_enum_attribute(color, "projType", type)) {
00361       set_projection_type(type);
00362     }
00363 
00364   } else if (color.hasFn(MFn::kLayeredTexture)) {
00365     if (maya_cat.is_debug()) {
00366       maya_cat.debug() << "Found layered texture" << endl;
00367     }
00368 
00369     int blendValue;
00370     MStatus status;
00371     MPlugArray color_pa;
00372     MFnDependencyNode layered_fn(color);
00373     layered_fn.getConnections(color_pa);
00374     MPlug inputsPlug = layered_fn.findPlug("inputs", &status);
00375     MPlug blendModePlug = layered_fn.findPlug("blendMode", &status);
00376 
00377     if (maya_cat.is_debug()) {
00378       maya_cat.debug() << "number of connections: " << color_pa.length() << endl;
00379     }
00380     bool first = true;
00381     BlendType bt = BT_modulate;
00382     for (size_t i=0; i<color_pa.length(); ++i) {
00383       MPlug pl = color_pa[i];
00384       MPlugArray pla;
00385       pl.connectedTo(pla, true, false);
00386 
00387       // First figure out the blend mode intended for this shadercolordef
00388       int li = pl.logicalIndex();
00389       if (li > -1) {
00390         // found a blend mode
00391         if (maya_cat.is_spam()) {
00392           maya_cat.spam() << "*** Start doIt... ***" << endl;
00393           maya_cat.spam() << "inputsPlug Name: " << inputsPlug.name() << endl;
00394         }
00395         status = blendModePlug.selectAncestorLogicalIndex(li,inputsPlug);
00396         blendModePlug.getValue(blendValue);
00397 
00398         if (maya_cat.is_spam()) {
00399           maya_cat.spam() 
00400             << blendModePlug.name() << ": has value " << blendValue << endl;
00401         }
00402 
00403         MFnEnumAttribute blendModeEnum(blendModePlug);
00404         MString blendName = blendModeEnum.fieldName(blendValue, &status);
00405         
00406         switch (blendValue) {
00407         case 1:
00408           bt = BT_decal;
00409           get_bool_attribute(color, "interpolate", _interpolate);
00410           maya_cat.info() << "interpolate: " << _interpolate << endl;
00411           _keep_color = true;
00412           break;
00413         case 6:
00414           bt = BT_modulate;
00415           get_bool_attribute(color, "keepAlpha", _keep_alpha);
00416           maya_cat.info() << "keepAlpha: " << _keep_alpha << endl;
00417           break;
00418         case 4:
00419           bt = BT_add;
00420           break;
00421         }
00422         maya_cat.info() << layered_fn.name() << ": blendMode used " << blendName << endl;
00423         if (maya_cat.is_spam()) {
00424           maya_cat.spam() << "*** END doIt... ***" << endl;
00425         }
00426 
00427         // advance to the next plug, because that is where the shader info are
00428         pl = color_pa[++i];
00429         pl.connectedTo(pla, true, false);
00430       }
00431       for (size_t j=0; j<pla.length(); ++j) {
00432         //maya_cat.debug() << pl.name() << " is(pl) " << pl.node().apiTypeStr() << endl;
00433         //maya_cat.debug() << pla[j].name() << " is(pla) " << pla[j].node().apiTypeStr() << endl;
00434         string pla_name = pla[j].name().asChar();
00435         // sometimes, by default, maya gives a outAlpha on subsequent plugs, ignore that
00436         if (pla_name.find("outAlpha") != string::npos) {
00437           // top texture has an alpha channel, so make sure that this alpha is retained by egg file
00438           if (maya_cat.is_debug()) {
00439             maya_cat.debug() << pl.name().asChar() << ":has alpha channel" << pla_name << endl;
00440           }
00441           _has_alpha_channel = true;
00442           continue;
00443         }
00444         if (!first) {
00445           if (maya_cat.is_debug()) {
00446             maya_cat.debug() << pl.name().asChar() << " next:connectedTo: " << pla_name << endl;
00447           }
00448           MayaShaderColorDef *color_p = new MayaShaderColorDef;
00449           color_p->find_textures_legacy(shader, pla[j].node());
00450           color_p->_blend_type = bt;
00451           size_t loc = color_p->_texture_name.find('.',0);
00452           if (loc != string::npos) {
00453             color_p->_texture_name.resize(loc);
00454           }
00455           if (maya_cat.is_debug()) {
00456             maya_cat.debug() << "uv_name : " << color_p->_texture_name << endl;
00457           }
00458         }
00459         else {
00460           if (maya_cat.is_debug()) {
00461             maya_cat.debug() << pl.name().asChar() << " first:connectedTo: " << pla_name << endl;
00462           }
00463           find_textures_legacy(shader, pla[j].node());
00464           _texture_name.assign(pla[j].name().asChar());
00465           _blend_type = bt;
00466           size_t loc = _texture_name.find('.',0);
00467           if (loc != string::npos) {
00468             _texture_name.resize(loc);
00469           }
00470           if (maya_cat.is_debug()) {
00471             maya_cat.debug() << "uv_name : " << _texture_name << endl;
00472           }
00473           first = false;
00474         }
00475       }
00476     }
00477   } else {
00478     // This shader wasn't understood.
00479     if (maya_cat.is_debug()) {
00480       maya_cat.info()
00481         << "**Don't know how to interpret color attribute type "
00482         << color.apiTypeStr() << "\n";
00483 
00484     } else {
00485       // If we don't have a heavy verbose count, only report each type
00486       // of unsupported shader once.
00487       static pset<MFn::Type> bad_types;
00488       if (bad_types.insert(color.apiType()).second) {
00489         maya_cat.info()
00490           << "**Don't know how to interpret color attribute type "
00491           << color.apiTypeStr() << "\n";
00492       }
00493     }
00494   }
00495 }
00496 
00497 ////////////////////////////////////////////////////////////////////
00498 //     Function: MayaShaderColorDef::find_textures
00499 //       Access: Private
00500 //  Description: Search to find any file textures that lead into the
00501 //               given input plug.  Any textures found will be added
00502 //               to the provided MayaShaderColorList.
00503 ////////////////////////////////////////////////////////////////////
00504 void MayaShaderColorDef::
00505 find_textures_modern(const string &shadername, MayaShaderColorList &list, MPlug inplug, bool is_alpha) {
00506 
00507   MPlugArray outplugs;
00508   inplug.connectedTo(outplugs, true, false);
00509   if (outplugs.length() == 0) {
00510     return;
00511   }
00512   if (outplugs.length() > 1) {
00513     // Only one output plug should be connected to a given input plug.
00514     maya_cat.warning()
00515       << "Shader " << shadername << " has weird plug connections.\n";
00516     return;
00517   }
00518   MPlug outplug = outplugs[0];
00519   MObject source = outplug.node();
00520   MFnDependencyNode sourceFn(source);
00521   
00522   if (source.hasFn(MFn::kFileTexture)) {
00523 
00524     string filename;
00525     bool hasfn = get_string_attribute(source, "fileTextureName", filename);
00526     if ((!hasfn) || (filename.empty())) {
00527       maya_cat.warning()
00528         << "Shader " << shadername << " references file texture "
00529         << "with no file name, ignoring invalid file texture.\n";
00530       return;
00531     }
00532     Filename fn = filename;
00533     if (fn.is_directory()) {
00534       maya_cat.warning()
00535         << "Shader " << shadername << " references file name "
00536         << filename << " which is a directory, ignoring it.\n";
00537       return;
00538     }
00539     
00540     MayaShaderColorDef *def = new MayaShaderColorDef;
00541     
00542     def->_color_object = new MObject(source);
00543     def->_texture_filename = Filename::from_os_specific(filename);
00544     def->_texture_name = sourceFn.name().asChar();
00545 
00546     get_vec2_attribute(source, "coverage",       def->_coverage);
00547     get_vec2_attribute(source, "translateFrame", def->_translate_frame);
00548     get_angle_attribute(source, "rotateFrame",    def->_rotate_frame);
00549     
00550     get_bool_attribute(source, "mirror",          def->_mirror);
00551     get_bool_attribute(source, "stagger",         def->_stagger);
00552     get_bool_attribute(source, "wrapU",           def->_wrap_u);
00553     get_bool_attribute(source, "wrapV",           def->_wrap_v);
00554 
00555     get_vec2_attribute(source, "repeatUV",       def->_repeat_uv);
00556     get_vec2_attribute(source, "offset",         def->_offset);
00557     get_angle_attribute(source, "rotateUV",       def->_rotate_uv);
00558 
00559     LRGBColor color_gain;
00560     PN_stdfloat alpha_gain;
00561     get_vec3_attribute(source, "colorGain",      color_gain);
00562     get_maya_attribute(source, "alphaGain",       alpha_gain);
00563     def->_color_gain[0] = color_gain[0];
00564     def->_color_gain[1] = color_gain[1];
00565     def->_color_gain[2] = color_gain[2];
00566     def->_color_gain[3] = alpha_gain;
00567 
00568     def->_is_alpha = is_alpha;
00569     
00570     if (maya_cat.is_debug()) {
00571       maya_cat.debug() << "pushed a file texture" << endl;
00572     }
00573     list.push_back(def);
00574 
00575     return;
00576   }
00577 
00578   if (source.hasFn(MFn::kProjection)) {
00579     // This is a projected texture.  We will have to step one level
00580     // deeper to find the actual texture.
00581     size_t before = list.size();
00582     MPlug image_plug = sourceFn.findPlug("image");
00583     if (!image_plug.isNull()) {
00584       MPlugArray image_pa;
00585       image_plug.connectedTo(image_pa, true, false);
00586       
00587       for (size_t i = 0; i < image_pa.length(); i++) {
00588         find_textures_modern(shadername, list, image_pa[0], is_alpha);
00589       }
00590     }
00591     
00592     // Now apply any inherited attributes to all textures found.
00593     
00594     for (size_t i=before; i<list.size(); i++) {
00595       MayaShaderColorDef *def = list[i];
00596       
00597       if (!get_mat4d_attribute(source, "placementMatrix", def->_projection_matrix)) {
00598         def->_projection_matrix = LMatrix4d::ident_mat();
00599       }
00600 
00601       // The uAngle and vAngle might be used for certain kinds of
00602       // projections.
00603       if (!get_angle_attribute(source, "uAngle", def->_u_angle)) {
00604         def->_u_angle = 360.0;
00605       }
00606       if (!get_angle_attribute(source, "vAngle", def->_v_angle)) {
00607         def->_v_angle = 180.0;
00608       }
00609 
00610       string type;
00611       if (get_enum_attribute(source, "projType", type)) {
00612         def->set_projection_type(type);
00613       }
00614     }
00615     return;
00616   }
00617   
00618   if (source.hasFn(MFn::kLayeredTexture)) {
00619     if (maya_cat.is_debug()) {
00620       maya_cat.debug() << "Found layered texture" << endl;
00621     }
00622 
00623     MPlug inputsPlug = sourceFn.findPlug("inputs");
00624     size_t nlayers = inputsPlug.numElements();
00625     for (size_t layer=0; layer<nlayers; layer++) {
00626       MPlug elt = inputsPlug.elementByPhysicalIndex(layer);
00627       MPlug color;
00628       MPlug blend;
00629       for (size_t j=0; j<elt.numChildren(); j++) {
00630         MPlug child = elt.child(j);
00631         MFnAttribute att(child.attribute());
00632         if (att.name() == "color") color = child;
00633         if (att.name() == "blendMode") blend = child;
00634       }
00635       if (color.isNull() || blend.isNull()) {
00636         maya_cat.warning() << "Invalid layered texture - bad inputs.\n";
00637         return;
00638       }
00639       size_t before = list.size();
00640       find_textures_modern(shadername, list, color, is_alpha);
00641       int blendValue;
00642       blend.getValue(blendValue);
00643       for (size_t sub=before; sub<list.size(); sub++) {
00644         MayaShaderColorDef *def = list[sub];
00645         switch (blendValue) {
00646         case 1:  def->_blend_type = BT_decal;     break;
00647         case 6:  def->_blend_type = BT_modulate;  break;
00648         case 4:  def->_blend_type = BT_add;       break;
00649         }
00650       }
00651     }
00652     return;
00653   }
00654 
00655   if (source.apiType() == MFn::kReverse) {
00656     MPlug input_plug = sourceFn.findPlug("input");
00657     find_textures_modern(shadername, list, input_plug, is_alpha);
00658     return;
00659   }
00660   
00661   // This shader wasn't understood.
00662   if (maya_cat.is_debug()) {
00663     maya_cat.info()
00664       << "**Don't know how to interpret color attribute type "
00665       << source.apiTypeStr() << "\n";
00666   } else {
00667     // If we don't have a heavy verbose count, only report each type
00668     // of unsupported shader once.
00669     static pset<MFn::Type> bad_types;
00670     if (bad_types.insert(source.apiType()).second) {
00671       maya_cat.warning()
00672         << "Don't know how to export a shader of type "
00673         << source.apiTypeStr() << " " << sourceFn.type() << "\n";
00674     }
00675   }
00676 }
00677 
00678 ////////////////////////////////////////////////////////////////////
00679 //     Function: MayaShaderColorDef::set_projection_type
00680 //       Access: Private
00681 //  Description: Sets up the shader to apply UV's according to the
00682 //               indicated projection type.
00683 ////////////////////////////////////////////////////////////////////
00684 void MayaShaderColorDef::
00685 set_projection_type(const string &type) {
00686   if (cmp_nocase(type, "planar") == 0) {
00687     _projection_type = PT_planar;
00688     _map_uvs = &MayaShaderColorDef::map_planar;
00689 
00690     // The Planar projection normally projects to a range (-1, 1) in
00691     // both axes.  Scale this into our UV range of (0, 1).
00692     _projection_matrix = _projection_matrix * LMatrix4d(0.5, 0.0, 0.0, 0.0,
00693                                                         0.0, 0.5, 0.0, 0.0,
00694                                                         0.0, 0.0, 1.0, 0.0,
00695                                                         0.5, 0.5, 0.0, 1.0);
00696 
00697   } else if (cmp_nocase(type, "cylindrical") == 0) {
00698     _projection_type = PT_cylindrical;
00699     _map_uvs = &MayaShaderColorDef::map_cylindrical;
00700 
00701     // The cylindrical projection is orthographic in the Y axis; scale
00702     // the range (-1, 1) in this axis into our UV range (0, 1).
00703     _projection_matrix = _projection_matrix * LMatrix4d(1.0, 0.0, 0.0, 0.0,
00704                                                         0.0, 0.5, 0.0, 0.0,
00705                                                         0.0, 0.0, 1.0, 0.0,
00706                                                         0.0, 0.5, 0.0, 1.0);
00707 
00708   } else if (cmp_nocase(type, "spherical") == 0) {
00709     _projection_type = PT_spherical;
00710     _map_uvs = &MayaShaderColorDef::map_spherical;
00711 
00712   } else {
00713     // Other projection types are currently unimplemented by the
00714     // converter.
00715     maya_cat.error()
00716       << "Don't know how to handle type " << type << " projections.\n";
00717     _projection_type = PT_off;
00718     _map_uvs = NULL;
00719   }
00720 }
00721 
00722 ////////////////////////////////////////////////////////////////////
00723 //     Function: MayaShaderColorDef::map_planar
00724 //       Access: Private
00725 //  Description: Computes a UV based on the given point in space,
00726 //               using a planar projection.
00727 ////////////////////////////////////////////////////////////////////
00728 LPoint2d MayaShaderColorDef::
00729 map_planar(const LPoint3d &pos, const LPoint3d &) const {
00730   // A planar projection is about as easy as can be.  We ignore the Z
00731   // axis, and project the point into the XY plane.  Done.
00732   return LPoint2d(pos[0], pos[1]);
00733 }
00734 
00735 ////////////////////////////////////////////////////////////////////
00736 //     Function: MayaShaderColorDef::map_spherical
00737 //       Access: Private
00738 //  Description: Computes a UV based on the given point in space,
00739 //               using a spherical projection.
00740 ////////////////////////////////////////////////////////////////////
00741 LPoint2d MayaShaderColorDef::
00742 map_spherical(const LPoint3d &pos, const LPoint3d &centroid) const {
00743   // To compute the x position on the frame, we only need to consider
00744   // the angle of the vector about the Y axis.  Project the vector
00745   // into the XZ plane to do this.
00746 
00747   LVector2d xz(pos[0], pos[2]);
00748   double xz_length = xz.length();
00749 
00750   if (xz_length < 0.01) {
00751     // If we have a point on or near either pole, we've got problems.
00752     // This point maps to the entire bottom edge of the image, so
00753     // which U value should we choose?  It does make a difference,
00754     // especially if we have a number of polygons around the south
00755     // pole that all share the common vertex.
00756 
00757     // We choose the U value based on the polygon's centroid.
00758     xz.set(centroid[0], centroid[2]);
00759   }
00760 
00761   // Now, if the polygon crosses the seam, we also have problems.
00762   // Make sure that the u value is in the same half of the texture as
00763   // the centroid's u value.
00764   double u = rad_2_deg(atan2(xz[0], xz[1])) / (2.0 * _u_angle);
00765   double c = rad_2_deg(atan2(centroid[0], centroid[2])) / (2.0 * _u_angle);
00766 
00767   if (u - c > 0.5) {
00768     u -= floor(u - c + 0.5);
00769   } else if (u - c < -0.5) {
00770     u += floor(c - u + 0.5);
00771   }
00772 
00773   // Now rotate the vector into the YZ plane, and the V value is based
00774   // on the latitude: the angle about the X axis.
00775   LVector2d yz(pos[1], xz_length);
00776   double v = rad_2_deg(atan2(yz[0], yz[1])) / (2.0 * _v_angle);
00777 
00778   LPoint2d uv(u - 0.5, v - 0.5);
00779 
00780   nassertr(fabs(u - c) <= 0.5, uv);
00781   return uv;
00782 }
00783 
00784 ////////////////////////////////////////////////////////////////////
00785 //     Function: MayaShaderColorDef::map_cylindrical
00786 //       Access: Private
00787 //  Description: Computes a UV based on the given point in space,
00788 //               using a cylindrical projection.
00789 ////////////////////////////////////////////////////////////////////
00790 LPoint2d MayaShaderColorDef::
00791 map_cylindrical(const LPoint3d &pos, const LPoint3d &centroid) const {
00792   // This is almost identical to the spherical projection, except for
00793   // the computation of V.
00794 
00795   LVector2d xz(pos[0], pos[2]);
00796   double xz_length = xz.length();
00797 
00798   if (xz_length < 0.01) {
00799     // A cylindrical mapping has the same singularity problem at the
00800     // pole as a spherical mapping does: points at the pole do not map
00801     // to a single point on the texture.  (It's technically a slightly
00802     // different problem: in a cylindrical mapping, points at the pole
00803     // do not map to any point on the texture, while in a spherical
00804     // mapping, points at the pole map to the top or bottom edge of
00805     // the texture.  But this is a technicality that doesn't really
00806     // apply to us.)  We still solve it the same way: if our point is
00807     // at or near the pole, compute the angle based on the centroid of
00808     // the polygon (which we assume is further from the pole).
00809     xz.set(centroid[0], centroid[2]);
00810   }
00811 
00812   // And cylinders do still have a seam at the back.
00813   double u = rad_2_deg(atan2(xz[0], xz[1])) / _u_angle;
00814   double c = rad_2_deg(atan2(centroid[0], centroid[2])) / _u_angle;
00815 
00816   if (u - c > 0.5) {
00817     u -= floor(u - c + 0.5);
00818   } else if (u - c < -0.5) {
00819     u += floor(c - u + 0.5);
00820   }
00821 
00822   // For a cylindrical mapping, the V value comes directly from Y.
00823   // Easy.
00824   LPoint2d uv(u - 0.5, pos[1]);
00825 
00826   nassertr(fabs(u - c) <= 0.5, uv);
00827   return uv;
00828 }
 All Classes Functions Variables Enumerations