Panda3D

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 TexCoordd MayaShaderColorDef::
00185 project_uv(const LPoint3d &pos, const LPoint3d &centroid) const {
00186   nassertr(_map_uvs != NULL, TexCoordd::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 _texture_copy, Filename _texture_out_dir, bool trans) {
00270   RGBColorf color_gain;
00271   if (get_vec3f_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   float 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       // create directory, copy texture, modify texture filename
00306       if (_texture_copy) {
00307         if (_texture_out_dir[_texture_out_dir.length()-1] != '/')
00308           _texture_out_dir+="/";
00309         _texture_out_dir.make_dir();
00310         Filename texture_copy_filename=Filename(_texture_out_dir, _texture_filename.get_basename());
00311         if (_texture_filename.copy_to(texture_copy_filename)) {       
00312           _texture_filename=texture_copy_filename;
00313         }
00314         else {
00315           maya_cat.warning()
00316               <<"unable to copy texture files from "<<_texture_filename.get_dirname()
00317               <<" to "<<_texture_out_dir<<"\n"
00318               <<"make sure you have the access right to the assigned directory\n"
00319               <<"the output egg file will adapt to the original texture files' path\n";
00320         }
00321       }
00322     }
00323 
00324     get_vec2f_attribute(color, "coverage", _coverage);
00325     get_vec2f_attribute(color, "translateFrame", _translate_frame);
00326     get_angle_attribute(color, "rotateFrame", _rotate_frame);
00327 
00328     //get_bool_attribute(color, "alphaIsLuminance", _alpha_is_luminance);
00329 
00330     get_bool_attribute(color, "mirror", _mirror);
00331     get_bool_attribute(color, "stagger", _stagger);
00332     get_bool_attribute(color, "wrapU", _wrap_u);
00333     get_bool_attribute(color, "wrapV", _wrap_v);
00334 
00335     get_vec2f_attribute(color, "repeatUV", _repeat_uv);
00336     get_vec2f_attribute(color, "offset", _offset);
00337     get_angle_attribute(color, "rotateUV", _rotate_uv);
00338 
00339     if (!trans) {
00340       if (maya_cat.is_debug()) {
00341         maya_cat.debug() << "pushed a file texture" << endl;
00342       }
00343       shader->_color.push_back(this);
00344     }
00345 
00346   } else if (color.hasFn(MFn::kProjection)) {
00347     if (maya_cat.is_debug()) {
00348       maya_cat.debug() << "reading a projection texture" << endl;
00349     }
00350     // This is a projected texture.  We will have to step one level
00351     // deeper to find the actual texture.
00352     MFnDependencyNode projection_fn(color);
00353     MPlug image_plug = projection_fn.findPlug("image");
00354     if (!image_plug.isNull()) {
00355       MPlugArray image_pa;
00356       image_plug.connectedTo(image_pa, true, false);
00357       
00358       for (size_t i = 0; i < image_pa.length(); i++) {
00359         find_textures_legacy(shader, image_pa[0].node(), _texture_copy, _texture_out_dir);
00360       }
00361     }
00362 
00363     if (!get_mat4d_attribute(color, "placementMatrix", _projection_matrix)) {
00364       _projection_matrix = LMatrix4d::ident_mat();
00365     }
00366 
00367     // The uAngle and vAngle might be used for certain kinds of
00368     // projections.
00369     if (!get_angle_attribute(color, "uAngle", _u_angle)) {
00370       _u_angle = 360.0;
00371     }
00372     if (!get_angle_attribute(color, "vAngle", _v_angle)) {
00373       _v_angle = 180.0;
00374     }
00375 
00376     string type;
00377     if (get_enum_attribute(color, "projType", type)) {
00378       set_projection_type(type);
00379     }
00380 
00381   } else if (color.hasFn(MFn::kLayeredTexture)) {
00382     if (maya_cat.is_debug()) {
00383       maya_cat.debug() << "Found layered texture" << endl;
00384     }
00385 
00386     int blendValue;
00387     MStatus status;
00388     MPlugArray color_pa;
00389     MFnDependencyNode layered_fn(color);
00390     layered_fn.getConnections(color_pa);
00391     MPlug inputsPlug = layered_fn.findPlug("inputs", &status);
00392     MPlug blendModePlug = layered_fn.findPlug("blendMode", &status);
00393 
00394     if (maya_cat.is_debug()) {
00395       maya_cat.debug() << "number of connections: " << color_pa.length() << endl;
00396     }
00397     bool first = true;
00398     BlendType bt = BT_modulate;
00399     for (size_t i=0; i<color_pa.length(); ++i) {
00400       MPlug pl = color_pa[i];
00401       MPlugArray pla;
00402       pl.connectedTo(pla, true, false);
00403 
00404       // First figure out the blend mode intended for this shadercolordef
00405       int li = pl.logicalIndex();
00406       if (li > -1) {
00407         // found a blend mode
00408         if (maya_cat.is_spam()) {
00409           maya_cat.spam() << "*** Start doIt... ***" << endl;
00410           maya_cat.spam() << "inputsPlug Name: " << inputsPlug.name() << endl;
00411         }
00412         status = blendModePlug.selectAncestorLogicalIndex(li,inputsPlug);
00413         blendModePlug.getValue(blendValue);
00414 
00415         if (maya_cat.is_spam()) {
00416           maya_cat.spam() 
00417             << blendModePlug.name() << ": has value " << blendValue << endl;
00418         }
00419 
00420         MFnEnumAttribute blendModeEnum(blendModePlug);
00421         MString blendName = blendModeEnum.fieldName(blendValue, &status);
00422         
00423         switch (blendValue) {
00424         case 1:
00425           bt = BT_decal;
00426           get_bool_attribute(color, "interpolate", _interpolate);
00427           maya_cat.info() << "interpolate: " << _interpolate << endl;
00428           _keep_color = true;
00429           break;
00430         case 6:
00431           bt = BT_modulate;
00432           get_bool_attribute(color, "keepAlpha", _keep_alpha);
00433           maya_cat.info() << "keepAlpha: " << _keep_alpha << endl;
00434           break;
00435         case 4:
00436           bt = BT_add;
00437           break;
00438         }
00439         maya_cat.info() << layered_fn.name() << ": blendMode used " << blendName << endl;
00440         if (maya_cat.is_spam()) {
00441           maya_cat.spam() << "*** END doIt... ***" << endl;
00442         }
00443 
00444         // advance to the next plug, because that is where the shader info are
00445         pl = color_pa[++i];
00446         pl.connectedTo(pla, true, false);
00447       }
00448       for (size_t j=0; j<pla.length(); ++j) {
00449         //maya_cat.debug() << pl.name() << " is(pl) " << pl.node().apiTypeStr() << endl;
00450         //maya_cat.debug() << pla[j].name() << " is(pla) " << pla[j].node().apiTypeStr() << endl;
00451         string pla_name = pla[j].name().asChar();
00452         // sometimes, by default, maya gives a outAlpha on subsequent plugs, ignore that
00453         if (pla_name.find("outAlpha") != string::npos) {
00454           // top texture has an alpha channel, so make sure that this alpha is retained by egg file
00455           if (maya_cat.is_debug()) {
00456             maya_cat.debug() << pl.name().asChar() << ":has alpha channel" << pla_name << endl;
00457           }
00458           _has_alpha_channel = true;
00459           continue;
00460         }
00461         if (!first) {
00462           if (maya_cat.is_debug()) {
00463             maya_cat.debug() << pl.name().asChar() << " next:connectedTo: " << pla_name << endl;
00464           }
00465           MayaShaderColorDef *color_p = new MayaShaderColorDef;
00466           color_p->find_textures_legacy(shader, pla[j].node(), _texture_copy, _texture_out_dir);
00467           color_p->_blend_type = bt;
00468           size_t loc = color_p->_texture_name.find('.',0);
00469           if (loc != string::npos) {
00470             color_p->_texture_name.resize(loc);
00471           }
00472           if (maya_cat.is_debug()) {
00473             maya_cat.debug() << "uv_name : " << color_p->_texture_name << endl;
00474           }
00475         }
00476         else {
00477           if (maya_cat.is_debug()) {
00478             maya_cat.debug() << pl.name().asChar() << " first:connectedTo: " << pla_name << endl;
00479           }
00480           find_textures_legacy(shader, pla[j].node(), _texture_copy, _texture_out_dir);
00481           _texture_name.assign(pla[j].name().asChar());
00482           _blend_type = bt;
00483           size_t loc = _texture_name.find('.',0);
00484           if (loc != string::npos) {
00485             _texture_name.resize(loc);
00486           }
00487           if (maya_cat.is_debug()) {
00488             maya_cat.debug() << "uv_name : " << _texture_name << endl;
00489           }
00490           first = false;
00491         }
00492       }
00493     }
00494   } else {
00495     // This shader wasn't understood.
00496     if (maya_cat.is_debug()) {
00497       maya_cat.info()
00498         << "**Don't know how to interpret color attribute type "
00499         << color.apiTypeStr() << "\n";
00500 
00501     } else {
00502       // If we don't have a heavy verbose count, only report each type
00503       // of unsupported shader once.
00504       static pset<MFn::Type> bad_types;
00505       if (bad_types.insert(color.apiType()).second) {
00506         maya_cat.info()
00507           << "**Don't know how to interpret color attribute type "
00508           << color.apiTypeStr() << "\n";
00509       }
00510     }
00511   }
00512 }
00513 
00514 ////////////////////////////////////////////////////////////////////
00515 //     Function: MayaShaderColorDef::find_textures
00516 //       Access: Private
00517 //  Description: Search to find any file textures that lead into the
00518 //               given input plug.  Any textures found will be added
00519 //               to the provided MayaShaderColorList.
00520 ////////////////////////////////////////////////////////////////////
00521 void MayaShaderColorDef::
00522 find_textures_modern(const string &shadername, MayaShaderColorList &list, MPlug inplug,bool _texture_copy, Filename _texture_out_dir, bool is_alpha) {
00523 
00524   MPlugArray outplugs;
00525   inplug.connectedTo(outplugs, true, false);
00526   if (outplugs.length() == 0) {
00527     return;
00528   }
00529   if (outplugs.length() > 1) {
00530     // Only one output plug should be connected to a given input plug.
00531     maya_cat.warning()
00532       << "Shader " << shadername << " has weird plug connections.\n";
00533     return;
00534   }
00535   MPlug outplug = outplugs[0];
00536   MObject source = outplug.node();
00537   MFnDependencyNode sourceFn(source);
00538   
00539   if (source.hasFn(MFn::kFileTexture)) {
00540 
00541     string filename;
00542     bool hasfn = get_string_attribute(source, "fileTextureName", filename);
00543     if ((!hasfn) || (filename.empty())) {
00544       maya_cat.warning()
00545         << "Shader " << shadername << " references file texture "
00546         << "with no file name, ignoring invalid file texture.\n";
00547       return;
00548     }
00549     Filename fn = filename;
00550     if (fn.is_directory()) {
00551       maya_cat.warning()
00552         << "Shader " << shadername << " references file name "
00553         << filename << " which is a directory, ignoring it.\n";
00554       return;
00555     }
00556     
00557     MayaShaderColorDef *def = new MayaShaderColorDef;
00558     
00559     def->_color_object = new MObject(source);
00560     def->_texture_filename = Filename::from_os_specific(filename);
00561     // create directory, copy texture, modify texture filename
00562     if (_texture_copy) {
00563       if (_texture_out_dir[_texture_out_dir.length()-1] != '/') {
00564         _texture_out_dir+="/";
00565     } 
00566       _texture_out_dir.make_dir();
00567       Filename texture_copy_filename=Filename(_texture_out_dir, def->_texture_filename.get_basename());
00568       if (def->_texture_filename.copy_to(texture_copy_filename)) {       
00569         def->_texture_filename=texture_copy_filename;
00570       }
00571       else {
00572         maya_cat.warning()
00573           <<"unable to copy texture files from "<<def->_texture_filename.get_dirname()
00574           <<" to "<<_texture_out_dir<<"\n"
00575           <<"make sure you have the access right to the assigned directory\n"
00576           <<"the output egg file will adapt to the original texture files' path\n";
00577       }
00578     }
00579     def->_texture_name = sourceFn.name().asChar();
00580 
00581     get_vec2f_attribute(source, "coverage",       def->_coverage);
00582     get_vec2f_attribute(source, "translateFrame", def->_translate_frame);
00583     get_angle_attribute(source, "rotateFrame",    def->_rotate_frame);
00584     
00585     get_bool_attribute(source, "mirror",          def->_mirror);
00586     get_bool_attribute(source, "stagger",         def->_stagger);
00587     get_bool_attribute(source, "wrapU",           def->_wrap_u);
00588     get_bool_attribute(source, "wrapV",           def->_wrap_v);
00589 
00590     get_vec2f_attribute(source, "repeatUV",       def->_repeat_uv);
00591     get_vec2f_attribute(source, "offset",         def->_offset);
00592     get_angle_attribute(source, "rotateUV",       def->_rotate_uv);
00593 
00594     RGBColorf color_gain;
00595     float alpha_gain;
00596     get_vec3f_attribute(source, "colorGain",      color_gain);
00597     get_maya_attribute(source, "alphaGain",       alpha_gain);
00598     def->_color_gain[0] = color_gain[0];
00599     def->_color_gain[1] = color_gain[1];
00600     def->_color_gain[2] = color_gain[2];
00601     def->_color_gain[3] = alpha_gain;
00602 
00603     def->_is_alpha = is_alpha;
00604     
00605     if (maya_cat.is_debug()) {
00606       maya_cat.debug() << "pushed a file texture" << endl;
00607     }
00608     list.push_back(def);
00609 
00610     return;
00611   }
00612 
00613   if (source.hasFn(MFn::kProjection)) {
00614     // This is a projected texture.  We will have to step one level
00615     // deeper to find the actual texture.
00616     size_t before = list.size();
00617     MPlug image_plug = sourceFn.findPlug("image");
00618     if (!image_plug.isNull()) {
00619       MPlugArray image_pa;
00620       image_plug.connectedTo(image_pa, true, false);
00621       
00622       for (size_t i = 0; i < image_pa.length(); i++) {
00623         find_textures_modern(shadername, list, image_pa[0], _texture_copy, _texture_out_dir, is_alpha);
00624       }
00625     }
00626     
00627     // Now apply any inherited attributes to all textures found.
00628     
00629     for (size_t i=before; i<list.size(); i++) {
00630       MayaShaderColorDef *def = list[i];
00631       
00632       if (!get_mat4d_attribute(source, "placementMatrix", def->_projection_matrix)) {
00633         def->_projection_matrix = LMatrix4d::ident_mat();
00634       }
00635 
00636       // The uAngle and vAngle might be used for certain kinds of
00637       // projections.
00638       if (!get_angle_attribute(source, "uAngle", def->_u_angle)) {
00639         def->_u_angle = 360.0;
00640       }
00641       if (!get_angle_attribute(source, "vAngle", def->_v_angle)) {
00642         def->_v_angle = 180.0;
00643       }
00644 
00645       string type;
00646       if (get_enum_attribute(source, "projType", type)) {
00647         def->set_projection_type(type);
00648       }
00649     }
00650     return;
00651   }
00652   
00653   if (source.hasFn(MFn::kLayeredTexture)) {
00654     if (maya_cat.is_debug()) {
00655       maya_cat.debug() << "Found layered texture" << endl;
00656     }
00657 
00658     MPlug inputsPlug = sourceFn.findPlug("inputs");
00659     size_t nlayers = inputsPlug.numElements();
00660     for (size_t layer=0; layer<nlayers; layer++) {
00661       MPlug elt = inputsPlug.elementByPhysicalIndex(layer);
00662       MPlug color;
00663       MPlug blend;
00664       for (size_t j=0; j<elt.numChildren(); j++) {
00665         MPlug child = elt.child(j);
00666         MFnAttribute att(child.attribute());
00667         if (att.name() == "color") color = child;
00668         if (att.name() == "blendMode") blend = child;
00669       }
00670       if (color.isNull() || blend.isNull()) {
00671         maya_cat.warning() << "Invalid layered texture - bad inputs.\n";
00672         return;
00673       }
00674       size_t before = list.size();
00675       find_textures_modern(shadername, list, color, _texture_copy, _texture_out_dir, is_alpha);
00676       int blendValue;
00677       blend.getValue(blendValue);
00678       for (size_t sub=before; sub<list.size(); sub++) {
00679         MayaShaderColorDef *def = list[sub];
00680         switch (blendValue) {
00681         case 1:  def->_blend_type = BT_decal;     break;
00682         case 6:  def->_blend_type = BT_modulate;  break;
00683         case 4:  def->_blend_type = BT_add;       break;
00684         }
00685       }
00686     }
00687     return;
00688   }
00689 
00690   if (source.apiType() == MFn::kReverse) {
00691     MPlug input_plug = sourceFn.findPlug("input");
00692     find_textures_modern(shadername, list, input_plug, _texture_copy, _texture_out_dir, is_alpha);
00693     return;
00694   }
00695   
00696   // This shader wasn't understood.
00697   if (maya_cat.is_debug()) {
00698     maya_cat.info()
00699       << "**Don't know how to interpret color attribute type "
00700       << source.apiTypeStr() << "\n";
00701   } else {
00702     // If we don't have a heavy verbose count, only report each type
00703     // of unsupported shader once.
00704     static pset<MFn::Type> bad_types;
00705     if (bad_types.insert(source.apiType()).second) {
00706       maya_cat.warning()
00707         << "Don't know how to export a shader of type "
00708         << source.apiTypeStr() << " " << sourceFn.type() << "\n";
00709     }
00710   }
00711 }
00712 
00713 ////////////////////////////////////////////////////////////////////
00714 //     Function: MayaShaderColorDef::set_projection_type
00715 //       Access: Private
00716 //  Description: Sets up the shader to apply UV's according to the
00717 //               indicated projection type.
00718 ////////////////////////////////////////////////////////////////////
00719 void MayaShaderColorDef::
00720 set_projection_type(const string &type) {
00721   if (cmp_nocase(type, "planar") == 0) {
00722     _projection_type = PT_planar;
00723     _map_uvs = &MayaShaderColorDef::map_planar;
00724 
00725     // The Planar projection normally projects to a range (-1, 1) in
00726     // both axes.  Scale this into our UV range of (0, 1).
00727     _projection_matrix = _projection_matrix * LMatrix4d(0.5, 0.0, 0.0, 0.0,
00728                                                         0.0, 0.5, 0.0, 0.0,
00729                                                         0.0, 0.0, 1.0, 0.0,
00730                                                         0.5, 0.5, 0.0, 1.0);
00731 
00732   } else if (cmp_nocase(type, "cylindrical") == 0) {
00733     _projection_type = PT_cylindrical;
00734     _map_uvs = &MayaShaderColorDef::map_cylindrical;
00735 
00736     // The cylindrical projection is orthographic in the Y axis; scale
00737     // the range (-1, 1) in this axis into our UV range (0, 1).
00738     _projection_matrix = _projection_matrix * LMatrix4d(1.0, 0.0, 0.0, 0.0,
00739                                                         0.0, 0.5, 0.0, 0.0,
00740                                                         0.0, 0.0, 1.0, 0.0,
00741                                                         0.0, 0.5, 0.0, 1.0);
00742 
00743   } else if (cmp_nocase(type, "spherical") == 0) {
00744     _projection_type = PT_spherical;
00745     _map_uvs = &MayaShaderColorDef::map_spherical;
00746 
00747   } else {
00748     // Other projection types are currently unimplemented by the
00749     // converter.
00750     maya_cat.error()
00751       << "Don't know how to handle type " << type << " projections.\n";
00752     _projection_type = PT_off;
00753     _map_uvs = NULL;
00754   }
00755 }
00756 
00757 ////////////////////////////////////////////////////////////////////
00758 //     Function: MayaShaderColorDef::map_planar
00759 //       Access: Private
00760 //  Description: Computes a UV based on the given point in space,
00761 //               using a planar projection.
00762 ////////////////////////////////////////////////////////////////////
00763 LPoint2d MayaShaderColorDef::
00764 map_planar(const LPoint3d &pos, const LPoint3d &) const {
00765   // A planar projection is about as easy as can be.  We ignore the Z
00766   // axis, and project the point into the XY plane.  Done.
00767   return LPoint2d(pos[0], pos[1]);
00768 }
00769 
00770 ////////////////////////////////////////////////////////////////////
00771 //     Function: MayaShaderColorDef::map_spherical
00772 //       Access: Private
00773 //  Description: Computes a UV based on the given point in space,
00774 //               using a spherical projection.
00775 ////////////////////////////////////////////////////////////////////
00776 LPoint2d MayaShaderColorDef::
00777 map_spherical(const LPoint3d &pos, const LPoint3d &centroid) const {
00778   // To compute the x position on the frame, we only need to consider
00779   // the angle of the vector about the Y axis.  Project the vector
00780   // into the XZ plane to do this.
00781 
00782   LVector2d xz(pos[0], pos[2]);
00783   double xz_length = xz.length();
00784 
00785   if (xz_length < 0.01) {
00786     // If we have a point on or near either pole, we've got problems.
00787     // This point maps to the entire bottom edge of the image, so
00788     // which U value should we choose?  It does make a difference,
00789     // especially if we have a number of polygons around the south
00790     // pole that all share the common vertex.
00791 
00792     // We choose the U value based on the polygon's centroid.
00793     xz.set(centroid[0], centroid[2]);
00794   }
00795 
00796   // Now, if the polygon crosses the seam, we also have problems.
00797   // Make sure that the u value is in the same half of the texture as
00798   // the centroid's u value.
00799   double u = rad_2_deg(atan2(xz[0], xz[1])) / (2.0 * _u_angle);
00800   double c = rad_2_deg(atan2(centroid[0], centroid[2])) / (2.0 * _u_angle);
00801 
00802   if (u - c > 0.5) {
00803     u -= floor(u - c + 0.5);
00804   } else if (u - c < -0.5) {
00805     u += floor(c - u + 0.5);
00806   }
00807 
00808   // Now rotate the vector into the YZ plane, and the V value is based
00809   // on the latitude: the angle about the X axis.
00810   LVector2d yz(pos[1], xz_length);
00811   double v = rad_2_deg(atan2(yz[0], yz[1])) / (2.0 * _v_angle);
00812 
00813   LPoint2d uv(u - 0.5, v - 0.5);
00814 
00815   nassertr(fabs(u - c) <= 0.5, uv);
00816   return uv;
00817 }
00818 
00819 ////////////////////////////////////////////////////////////////////
00820 //     Function: MayaShaderColorDef::map_cylindrical
00821 //       Access: Private
00822 //  Description: Computes a UV based on the given point in space,
00823 //               using a cylindrical projection.
00824 ////////////////////////////////////////////////////////////////////
00825 LPoint2d MayaShaderColorDef::
00826 map_cylindrical(const LPoint3d &pos, const LPoint3d &centroid) const {
00827   // This is almost identical to the spherical projection, except for
00828   // the computation of V.
00829 
00830   LVector2d xz(pos[0], pos[2]);
00831   double xz_length = xz.length();
00832 
00833   if (xz_length < 0.01) {
00834     // A cylindrical mapping has the same singularity problem at the
00835     // pole as a spherical mapping does: points at the pole do not map
00836     // to a single point on the texture.  (It's technically a slightly
00837     // different problem: in a cylindrical mapping, points at the pole
00838     // do not map to any point on the texture, while in a spherical
00839     // mapping, points at the pole map to the top or bottom edge of
00840     // the texture.  But this is a technicality that doesn't really
00841     // apply to us.)  We still solve it the same way: if our point is
00842     // at or near the pole, compute the angle based on the centroid of
00843     // the polygon (which we assume is further from the pole).
00844     xz.set(centroid[0], centroid[2]);
00845   }
00846 
00847   // And cylinders do still have a seam at the back.
00848   double u = rad_2_deg(atan2(xz[0], xz[1])) / _u_angle;
00849   double c = rad_2_deg(atan2(centroid[0], centroid[2])) / _u_angle;
00850 
00851   if (u - c > 0.5) {
00852     u -= floor(u - c + 0.5);
00853   } else if (u - c < -0.5) {
00854     u += floor(c - u + 0.5);
00855   }
00856 
00857   // For a cylindrical mapping, the V value comes directly from Y.
00858   // Easy.
00859   LPoint2d uv(u - 0.5, pos[1]);
00860 
00861   nassertr(fabs(u - c) <= 0.5, uv);
00862   return uv;
00863 }
 All Classes Functions Variables Enumerations