diff --git a/pandatool/src/maya/Sources.pp b/pandatool/src/maya/Sources.pp index 1c8c45a67f..663a1f7eaa 100644 --- a/pandatool/src/maya/Sources.pp +++ b/pandatool/src/maya/Sources.pp @@ -14,6 +14,7 @@ config_maya.cxx config_maya.h \ mayaApi.cxx mayaApi.h \ mayaShader.cxx mayaShader.h \ + mayaShaderColorDef.cxx mayaShaderColorDef.h \ mayaShaders.cxx mayaShaders.h \ maya_funcs.I maya_funcs.cxx maya_funcs.h \ post_maya_include.h pre_maya_include.h diff --git a/pandatool/src/maya/mayaShader.cxx b/pandatool/src/maya/mayaShader.cxx index 765b61327d..ed74b66f9f 100644 --- a/pandatool/src/maya/mayaShader.cxx +++ b/pandatool/src/maya/mayaShader.cxx @@ -20,6 +20,7 @@ #include "maya_funcs.h" #include "config_maya.h" #include "string_utils.h" +#include "pnmImageHeader.h" // for lumin_red, etc. #include "pset.h" #include "pre_maya_include.h" @@ -40,35 +41,13 @@ //////////////////////////////////////////////////////////////////// MayaShader:: MayaShader(MObject engine) { - _has_color = false; - _transparency = 0.0; - - _has_texture = false; - _projection_type = PT_off; - _map_uvs = NULL; - - _coverage.set(1.0, 1.0); - _translate_frame.set(0.0, 0.0); - _rotate_frame = 0.0; - - _mirror = false; - _stagger = false; - _wrap_u = true; - _wrap_v = true; - - _repeat_uv.set(1.0, 1.0); - _offset.set(0.0, 0.0); - _rotate_uv = 0.0; - - _color_object = (MObject *)NULL; - MFnDependencyNode engine_fn(engine); - _name = engine_fn.name().asChar(); + set_name(engine_fn.name().asChar()); if (maya_cat.is_debug()) { maya_cat.debug() - << "Reading shading engine " << _name << "\n"; + << "Reading shading engine " << get_name() << "\n"; } bool found_shader = false; @@ -91,56 +70,6 @@ MayaShader(MObject engine) { //////////////////////////////////////////////////////////////////// MayaShader:: ~MayaShader() { - if (_color_object != (MObject *)NULL) { - delete _color_object; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: MayaShader::compute_texture_matrix -// Access: Public -// Description: Returns a texture matrix corresponding to the texture -// transforms indicated by the shader. -//////////////////////////////////////////////////////////////////// -LMatrix3d MayaShader:: -compute_texture_matrix() const { - LVector2d scale(_repeat_uv[0] / _coverage[0], - _repeat_uv[1] / _coverage[1]); - LVector2d trans(_offset[0] - _translate_frame[0] / _coverage[0], - _offset[1] - _translate_frame[1] / _coverage[1]); - - return - (LMatrix3d::translate_mat(LVector2d(-0.5, -0.5)) * - LMatrix3d::rotate_mat(_rotate_frame) * - LMatrix3d::translate_mat(LVector2d(0.5, 0.5))) * - LMatrix3d::scale_mat(scale) * - LMatrix3d::translate_mat(trans); -} - -//////////////////////////////////////////////////////////////////// -// Function: MayaShader::has_projection -// Access: Public -// Description: Returns true if the shader has a projection in effect. -//////////////////////////////////////////////////////////////////// -bool MayaShader:: -has_projection() const { - return (_projection_type != PT_off); -} - -//////////////////////////////////////////////////////////////////// -// Function: MayaShader::project_uv -// Access: Public -// Description: If the shader has a projection (has_projection() -// returns true), this computes the appropriate UV -// corresponding to the indicated 3-d point. Seams that -// might be introduced on polygons that cross quadrants -// are closed up by ensuring the point is in the same -// quadrant as the indicated reference point. -//////////////////////////////////////////////////////////////////// -TexCoordd MayaShader:: -project_uv(const LPoint3d &pos, const LPoint3d ¢roid) const { - nassertr(_map_uvs != NULL, TexCoordd::zero()); - return (this->*_map_uvs)(pos * _projection_matrix, centroid * _projection_matrix); } //////////////////////////////////////////////////////////////////// @@ -150,49 +79,58 @@ project_uv(const LPoint3d &pos, const LPoint3d ¢roid) const { //////////////////////////////////////////////////////////////////// void MayaShader:: output(ostream &out) const { - out << "Shader " << _name << ":\n"; - if (_has_texture) { - out << " texture is " << _texture << "\n" - << " coverage is " << _coverage << "\n" - << " translate_frame is " << _translate_frame << "\n" - << " rotate_frame is " << _rotate_frame << "\n" - << " mirror is " << _mirror << "\n" - << " stagger is " << _stagger << "\n" - << " wrap_u is " << _wrap_u << "\n" - << " wrap_v is " << _wrap_v << "\n" - << " repeat_uv is " << _repeat_uv << "\n" - << " offset is " << _offset << "\n" - << " rotate_uv is " << _rotate_uv << "\n"; - - } else if (_has_color) { - out << " color is " << _color << "\n"; - } + out << "Shader " << get_name(); } //////////////////////////////////////////////////////////////////// -// Function: MayaShader::reset_maya_texture +// Function: MayaShader::write // Access: Public -// Description: Changes the texture filename stored in the Maya file -// for this particular shader. +// Description: //////////////////////////////////////////////////////////////////// -bool MayaShader:: -reset_maya_texture(const Filename &texture) { - if (_color_object != (MObject *)NULL) { - _has_texture = set_string_attribute(*_color_object, "fileTextureName", - texture); - _texture = texture; +void MayaShader:: +write(ostream &out) const { + out << "Shader " << get_name() << "\n" + << " color:\n"; + _color.write(out); + out << " transparency:\n"; + _transparency.write(out); +} - if (!_has_texture) { - maya_cat.error() - << "Unable to reset texture filename.\n"; - } +//////////////////////////////////////////////////////////////////// +// Function: MayaShader::get_rgba +// Access: Public +// Description: Returns the overall color of the shader as a +// single-precision rgba value, where the alpha +// component represents transparency according to the +// Panda convention. If no overall color is specified +// (_has_flat_color is not true), this returns white. +// +// Normally, Maya makes texture color override the flat +// color, so if a texture is also applied (_has_texture +// is true), this value is not used by Maya. +//////////////////////////////////////////////////////////////////// +Colorf MayaShader:: +get_rgba() const { + Colorf rgba(1.0f, 1.0f, 1.0f, 1.0f); - return _has_texture; + if (_color._has_flat_color) { + rgba[0] = (float)_color._flat_color[0]; + rgba[1] = (float)_color._flat_color[1]; + rgba[2] = (float)_color._flat_color[2]; } - maya_cat.error() - << "Attempt to reset texture on Maya object that has no color set.\n"; - return false; + if (_transparency._has_flat_color) { + // Maya supports colored transparency, but we only support + // grayscale transparency. Use the pnmimage constants to + // convert color to grayscale. + double trans = + _transparency._flat_color[0] * lumin_red + + _transparency._flat_color[1] * lumin_grn + + _transparency._flat_color[2] * lumin_blu; + rgba[3] = 1.0f - (float)trans; + } + + return rgba; } //////////////////////////////////////////////////////////////////// @@ -216,25 +154,34 @@ read_surface_shader(MObject shader) { // shader says for color. MPlug color_plug = shader_fn.findPlug("color"); + if (color_plug.isNull()) { + // Or maybe a connection to outColor. Not sure how this differs + // from just color, but empirically it seems that either might be + // used. + color_plug = shader_fn.findPlug("outColor"); + } + if (!color_plug.isNull()) { MPlugArray color_pa; color_plug.connectedTo(color_pa, true, false); for (size_t i = 0; i < color_pa.length(); i++) { - read_surface_color(color_pa[0].node()); + _color.read_surface_color(color_pa[0].node()); } } - // Or maybe a connection to outColor. Not sure how this differs - // from just color, but empirically it seems that either might be - // used. - MPlug out_color_plug = shader_fn.findPlug("outColor"); - if (!out_color_plug.isNull()) { - MPlugArray color_pa; - out_color_plug.connectedTo(color_pa, true, false); + // Transparency is stored separately. + MPlug trans_plug = shader_fn.findPlug("transparency"); + if (trans_plug.isNull()) { + trans_plug = shader_fn.findPlug("outTransparency"); + } + + if (!trans_plug.isNull()) { + MPlugArray trans_pa; + trans_plug.connectedTo(trans_pa, true, false); - for (size_t i = 0; i < color_pa.length(); i++) { - read_surface_color(color_pa[0].node()); + for (size_t i = 0; i < trans_pa.length(); i++) { + _transparency.read_surface_color(trans_pa[0].node()); } } @@ -244,12 +191,22 @@ read_surface_shader(MObject shader) { MFnLambertShader lambert_fn(shader); MColor color = lambert_fn.color(&status); if (status) { - _color.set(color.r, color.g, color.b, color.a); - _has_color = true; + // Warning! The alpha component of color doesn't mean + // transparency in Maya. + _color._has_flat_color = true; + _color._flat_color.set(color.r, color.g, color.b, color.a); + _transparency._flat_color.set(0.0, 0.0, 0.0, 0.0); + + // Get the transparency separately. + color = lambert_fn.transparency(&status); + if (status) { + _transparency._has_flat_color = true; + _transparency._flat_color.set(color.r, color.g, color.b, color.a); + } } } - if (!_has_color && !_has_texture) { + if (!_color._has_flat_color && !_color._has_texture) { if (maya_cat.is_spam()) { maya_cat.spam() << " Color definition not found.\n"; @@ -257,237 +214,3 @@ read_surface_shader(MObject shader) { } return true; } - -//////////////////////////////////////////////////////////////////// -// Function: MayaShader::read_surface_color -// Access: Private -// Description: Determines the surface color specified by the shader. -// This includes texturing and other advanced shader -// properties. -//////////////////////////////////////////////////////////////////// -void MayaShader:: -read_surface_color(MObject color) { - if (color.hasFn(MFn::kFileTexture)) { - _color_object = new MObject(color); - string filename; - _has_texture = get_string_attribute(color, "fileTextureName", filename); - if (_has_texture) { - _texture = Filename::from_os_specific(filename); - } - - get_vec2f_attribute(color, "coverage", _coverage); - get_vec2f_attribute(color, "translateFrame", _translate_frame); - get_angle_attribute(color, "rotateFrame", _rotate_frame); - - get_bool_attribute(color, "mirror", _mirror); - get_bool_attribute(color, "stagger", _stagger); - get_bool_attribute(color, "wrapU", _wrap_u); - get_bool_attribute(color, "wrapV", _wrap_v); - - get_vec2f_attribute(color, "repeatUV", _repeat_uv); - get_vec2f_attribute(color, "offset", _offset); - get_angle_attribute(color, "rotateUV", _rotate_uv); - - } else if (color.hasFn(MFn::kProjection)) { - // This is a projected texture. We will have to step one level - // deeper to find the actual texture. - MFnDependencyNode projection_fn(color); - MPlug image_plug = projection_fn.findPlug("image"); - if (!image_plug.isNull()) { - MPlugArray image_pa; - image_plug.connectedTo(image_pa, true, false); - - for (size_t i = 0; i < image_pa.length(); i++) { - read_surface_color(image_pa[0].node()); - } - } - - if (!get_mat4d_attribute(color, "placementMatrix", _projection_matrix)) { - _projection_matrix = LMatrix4d::ident_mat(); - } - - // The uAngle and vAngle might be used for certain kinds of - // projections. - if (!get_angle_attribute(color, "uAngle", _u_angle)) { - _u_angle = 360.0; - } - if (!get_angle_attribute(color, "vAngle", _v_angle)) { - _v_angle = 180.0; - } - - string type; - if (get_enum_attribute(color, "projType", type)) { - set_projection_type(type); - } - - } else { - // This shader wasn't understood. - if (maya_cat.is_debug()) { - maya_cat.info() - << "**Don't know how to interpret color attribute type " - << color.apiTypeStr() << "\n"; - - } else { - // If we don't have a heavy verbose count, only report each type - // of unsupportted shader once. - static pset bad_types; - if (bad_types.insert(color.apiType()).second) { - maya_cat.info() - << "**Don't know how to interpret color attribute type " - << color.apiTypeStr() << "\n"; - } - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: MayaShader::set_projection_type -// Access: Private -// Description: Sets up the shader to apply UV's according to the -// indicated projection type. -//////////////////////////////////////////////////////////////////// -void MayaShader:: -set_projection_type(const string &type) { - if (cmp_nocase(type, "planar") == 0) { - _projection_type = PT_planar; - _map_uvs = &MayaShader::map_planar; - - // The Planar projection normally projects to a range (-1, 1) in - // both axes. Scale this into our UV range of (0, 1). - _projection_matrix = _projection_matrix * LMatrix4d(0.5, 0.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.5, 0.5, 0.0, 1.0); - - } else if (cmp_nocase(type, "cylindrical") == 0) { - _projection_type = PT_cylindrical; - _map_uvs = &MayaShader::map_cylindrical; - - // The cylindrical projection is orthographic in the Y axis; scale - // the range (-1, 1) in this axis into our UV range (0, 1). - _projection_matrix = _projection_matrix * LMatrix4d(1.0, 0.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.5, 0.0, 1.0); - - } else if (cmp_nocase(type, "spherical") == 0) { - _projection_type = PT_spherical; - _map_uvs = &MayaShader::map_spherical; - - } else { - // Other projection types are currently unimplemented by the - // converter. - maya_cat.error() - << "Don't know how to handle type " << type << " projections.\n"; - _projection_type = PT_off; - _map_uvs = NULL; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: MayaShader::map_planar -// Access: Private -// Description: Computes a UV based on the given point in space, -// using a planar projection. -//////////////////////////////////////////////////////////////////// -LPoint2d MayaShader:: -map_planar(const LPoint3d &pos, const LPoint3d &) const { - // A planar projection is about as easy as can be. We ignore the Z - // axis, and project the point into the XY plane. Done. - return LPoint2d(pos[0], pos[1]); -} - -//////////////////////////////////////////////////////////////////// -// Function: MayaShader::map_spherical -// Access: Private -// Description: Computes a UV based on the given point in space, -// using a spherical projection. -//////////////////////////////////////////////////////////////////// -LPoint2d MayaShader:: -map_spherical(const LPoint3d &pos, const LPoint3d ¢roid) const { - // To compute the x position on the frame, we only need to consider - // the angle of the vector about the Y axis. Project the vector - // into the XZ plane to do this. - - LVector2d xz(pos[0], pos[2]); - double xz_length = xz.length(); - - if (xz_length < 0.01) { - // If we have a point on or near either pole, we've got problems. - // This point maps to the entire bottom edge of the image, so - // which U value should we choose? It does make a difference, - // especially if we have a number of polygons around the south - // pole that all share the common vertex. - - // We choose the U value based on the polygon's centroid. - xz.set(centroid[0], centroid[2]); - } - - // Now, if the polygon crosses the seam, we also have problems. - // Make sure that the u value is in the same half of the texture as - // the centroid's u value. - double u = rad_2_deg(atan2(xz[0], xz[1])) / (2.0 * _u_angle); - double c = rad_2_deg(atan2(centroid[0], centroid[2])) / (2.0 * _u_angle); - - if (u - c > 0.5) { - u -= floor(u - c + 0.5); - } else if (u - c < -0.5) { - u += floor(c - u + 0.5); - } - - // Now rotate the vector into the YZ plane, and the V value is based - // on the latitude: the angle about the X axis. - LVector2d yz(pos[1], xz_length); - double v = rad_2_deg(atan2(yz[0], yz[1])) / (2.0 * _v_angle); - - LPoint2d uv(u - 0.5, v - 0.5); - - nassertr(fabs(u - c) <= 0.5, uv); - return uv; -} - -//////////////////////////////////////////////////////////////////// -// Function: MayaShader::map_cylindrical -// Access: Private -// Description: Computes a UV based on the given point in space, -// using a cylindrical projection. -//////////////////////////////////////////////////////////////////// -LPoint2d MayaShader:: -map_cylindrical(const LPoint3d &pos, const LPoint3d ¢roid) const { - // This is almost identical to the spherical projection, except for - // the computation of V. - - LVector2d xz(pos[0], pos[2]); - double xz_length = xz.length(); - - if (xz_length < 0.01) { - // A cylindrical mapping has the same singularity problem at the - // pole as a spherical mapping does: points at the pole do not map - // to a single point on the texture. (It's technically a slightly - // different problem: in a cylindrical mapping, points at the pole - // do not map to any point on the texture, while in a spherical - // mapping, points at the pole map to the top or bottom edge of - // the texture. But this is a technicality that doesn't really - // apply to us.) We still solve it the same way: if our point is - // at or near the pole, compute the angle based on the centroid of - // the polygon (which we assume is further from the pole). - xz.set(centroid[0], centroid[2]); - } - - // And cylinders do still have a seam at the back. - double u = rad_2_deg(atan2(xz[0], xz[1])) / _u_angle; - double c = rad_2_deg(atan2(centroid[0], centroid[2])) / _u_angle; - - if (u - c > 0.5) { - u -= floor(u - c + 0.5); - } else if (u - c < -0.5) { - u += floor(c - u + 0.5); - } - - // For a cylindrical mapping, the V value comes directly from Y. - // Easy. - LPoint2d uv(u - 0.5, pos[1]); - - nassertr(fabs(u - c) <= 0.5, uv); - return uv; -} diff --git a/pandatool/src/maya/mayaShader.h b/pandatool/src/maya/mayaShader.h index 2a226b3d70..11fe356eae 100644 --- a/pandatool/src/maya/mayaShader.h +++ b/pandatool/src/maya/mayaShader.h @@ -20,9 +20,11 @@ #define MAYASHADER_H #include "pandatoolbase.h" +#include "mayaShaderColorDef.h" #include "luse.h" #include "lmatrix.h" +#include "namable.h" class MObject; @@ -34,69 +36,21 @@ class MObject; // that we don't care about or don't know enough to // extract. //////////////////////////////////////////////////////////////////// -class MayaShader { +class MayaShader : public Namable { public: MayaShader(MObject engine); ~MayaShader(); - LMatrix3d compute_texture_matrix() const; - bool has_projection() const; - TexCoordd project_uv(const LPoint3d &pos, const LPoint3d &ref_point) const; - void output(ostream &out) const; - bool reset_maya_texture(const Filename &texture); + void write(ostream &out) const; - string _name; + Colorf get_rgba() const; - bool _has_color; - Colord _color; - double _transparency; - - bool _has_texture; - Filename _texture; - - enum ProjectionType { - PT_off, - PT_planar, - PT_spherical, - PT_cylindrical, - PT_ball, - PT_cubic, - PT_triplanar, - PT_concentric, - PT_perspective, - }; - ProjectionType _projection_type; - LMatrix4d _projection_matrix; - double _u_angle; - double _v_angle; - - LVector2f _coverage; - LVector2f _translate_frame; - double _rotate_frame; - - bool _mirror; - bool _stagger; - bool _wrap_u; - bool _wrap_v; - - LVector2f _repeat_uv; - LVector2f _offset; - double _rotate_uv; + MayaShaderColorDef _color; + MayaShaderColorDef _transparency; private: - MObject *_color_object; - bool read_surface_shader(MObject shader); - void read_surface_color(MObject color); - void set_projection_type(const string &type); - - LPoint2d map_planar(const LPoint3d &pos, const LPoint3d ¢roid) const; - LPoint2d map_spherical(const LPoint3d &pos, const LPoint3d ¢roid) const; - LPoint2d map_cylindrical(const LPoint3d &pos, const LPoint3d ¢roid) const; - - // Define a pointer to one of the above member functions. - LPoint2d (MayaShader::*_map_uvs)(const LPoint3d &pos, const LPoint3d ¢roid) const; }; INLINE ostream &operator << (ostream &out, const MayaShader &shader) { diff --git a/pandatool/src/maya/mayaShaderColorDef.cxx b/pandatool/src/maya/mayaShaderColorDef.cxx new file mode 100644 index 0000000000..ed83a98617 --- /dev/null +++ b/pandatool/src/maya/mayaShaderColorDef.cxx @@ -0,0 +1,405 @@ +// Filename: mayaShaderColorDef.cxx +// Created by: drose (12Apr03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "mayaShaderColorDef.h" +#include "maya_funcs.h" +#include "config_maya.h" +#include "string_utils.h" +#include "pset.h" + +#include "pre_maya_include.h" +#include +#include +#include +#include +#include +#include "post_maya_include.h" + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +MayaShaderColorDef:: +MayaShaderColorDef() { + _has_flat_color = false; + _flat_color.set(0.0, 0.0, 0.0, 0.0); + + _has_texture = false; + _projection_type = PT_off; + _map_uvs = NULL; + + _coverage.set(1.0, 1.0); + _translate_frame.set(0.0, 0.0); + _rotate_frame = 0.0; + + _mirror = false; + _stagger = false; + _wrap_u = true; + _wrap_v = true; + + _repeat_uv.set(1.0, 1.0); + _offset.set(0.0, 0.0); + _rotate_uv = 0.0; + + _color_object = (MObject *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +MayaShaderColorDef:: +~MayaShaderColorDef() { + if (_color_object != (MObject *)NULL) { + delete _color_object; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::compute_texture_matrix +// Access: Public +// Description: Returns a texture matrix corresponding to the texture +// transforms indicated by the shader. +//////////////////////////////////////////////////////////////////// +LMatrix3d MayaShaderColorDef:: +compute_texture_matrix() const { + LVector2d scale(_repeat_uv[0] / _coverage[0], + _repeat_uv[1] / _coverage[1]); + LVector2d trans(_offset[0] - _translate_frame[0] / _coverage[0], + _offset[1] - _translate_frame[1] / _coverage[1]); + + return + (LMatrix3d::translate_mat(LVector2d(-0.5, -0.5)) * + LMatrix3d::rotate_mat(_rotate_frame) * + LMatrix3d::translate_mat(LVector2d(0.5, 0.5))) * + LMatrix3d::scale_mat(scale) * + LMatrix3d::translate_mat(trans); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::has_projection +// Access: Public +// Description: Returns true if the shader has a projection in effect. +//////////////////////////////////////////////////////////////////// +bool MayaShaderColorDef:: +has_projection() const { + return (_projection_type != PT_off); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::project_uv +// Access: Public +// Description: If the shader has a projection (has_projection() +// returns true), this computes the appropriate UV +// corresponding to the indicated 3-d point. Seams that +// might be introduced on polygons that cross quadrants +// are closed up by ensuring the point is in the same +// quadrant as the indicated reference point. +//////////////////////////////////////////////////////////////////// +TexCoordd MayaShaderColorDef:: +project_uv(const LPoint3d &pos, const LPoint3d ¢roid) const { + nassertr(_map_uvs != NULL, TexCoordd::zero()); + return (this->*_map_uvs)(pos * _projection_matrix, centroid * _projection_matrix); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::write +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void MayaShaderColorDef:: +write(ostream &out) const { + if (_has_texture) { + out << " texture is " << _texture << "\n" + << " coverage is " << _coverage << "\n" + << " translate_frame is " << _translate_frame << "\n" + << " rotate_frame is " << _rotate_frame << "\n" + << " mirror is " << _mirror << "\n" + << " stagger is " << _stagger << "\n" + << " wrap_u is " << _wrap_u << "\n" + << " wrap_v is " << _wrap_v << "\n" + << " repeat_uv is " << _repeat_uv << "\n" + << " offset is " << _offset << "\n" + << " rotate_uv is " << _rotate_uv << "\n"; + + } else if (_has_flat_color) { + out << " flat color is " << _flat_color << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::reset_maya_texture +// Access: Public +// Description: Changes the texture filename stored in the Maya file +// for this particular shader. +//////////////////////////////////////////////////////////////////// +bool MayaShaderColorDef:: +reset_maya_texture(const Filename &texture) { + if (_color_object != (MObject *)NULL) { + _has_texture = set_string_attribute(*_color_object, "fileTextureName", + texture); + _texture = texture; + + if (!_has_texture) { + maya_cat.error() + << "Unable to reset texture filename.\n"; + } + + return _has_texture; + } + + maya_cat.error() + << "Attempt to reset texture on Maya object that has no color set.\n"; + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::read_surface_color +// Access: Private +// Description: Determines the surface color specified by the shader. +// This includes texturing and other advanced shader +// properties. +//////////////////////////////////////////////////////////////////// +void MayaShaderColorDef:: +read_surface_color(MObject color) { + if (color.hasFn(MFn::kFileTexture)) { + _color_object = new MObject(color); + string filename; + _has_texture = get_string_attribute(color, "fileTextureName", filename); + if (_has_texture) { + _texture = Filename::from_os_specific(filename); + } + + get_vec2f_attribute(color, "coverage", _coverage); + get_vec2f_attribute(color, "translateFrame", _translate_frame); + get_angle_attribute(color, "rotateFrame", _rotate_frame); + + get_bool_attribute(color, "mirror", _mirror); + get_bool_attribute(color, "stagger", _stagger); + get_bool_attribute(color, "wrapU", _wrap_u); + get_bool_attribute(color, "wrapV", _wrap_v); + + get_vec2f_attribute(color, "repeatUV", _repeat_uv); + get_vec2f_attribute(color, "offset", _offset); + get_angle_attribute(color, "rotateUV", _rotate_uv); + + } else if (color.hasFn(MFn::kProjection)) { + // This is a projected texture. We will have to step one level + // deeper to find the actual texture. + MFnDependencyNode projection_fn(color); + MPlug image_plug = projection_fn.findPlug("image"); + if (!image_plug.isNull()) { + MPlugArray image_pa; + image_plug.connectedTo(image_pa, true, false); + + for (size_t i = 0; i < image_pa.length(); i++) { + read_surface_color(image_pa[0].node()); + } + } + + if (!get_mat4d_attribute(color, "placementMatrix", _projection_matrix)) { + _projection_matrix = LMatrix4d::ident_mat(); + } + + // The uAngle and vAngle might be used for certain kinds of + // projections. + if (!get_angle_attribute(color, "uAngle", _u_angle)) { + _u_angle = 360.0; + } + if (!get_angle_attribute(color, "vAngle", _v_angle)) { + _v_angle = 180.0; + } + + string type; + if (get_enum_attribute(color, "projType", type)) { + set_projection_type(type); + } + + } else { + // This shader wasn't understood. + if (maya_cat.is_debug()) { + maya_cat.info() + << "**Don't know how to interpret color attribute type " + << color.apiTypeStr() << "\n"; + + } else { + // If we don't have a heavy verbose count, only report each type + // of unsupported shader once. + static pset bad_types; + if (bad_types.insert(color.apiType()).second) { + maya_cat.info() + << "**Don't know how to interpret color attribute type " + << color.apiTypeStr() << "\n"; + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::set_projection_type +// Access: Private +// Description: Sets up the shader to apply UV's according to the +// indicated projection type. +//////////////////////////////////////////////////////////////////// +void MayaShaderColorDef:: +set_projection_type(const string &type) { + if (cmp_nocase(type, "planar") == 0) { + _projection_type = PT_planar; + _map_uvs = &MayaShaderColorDef::map_planar; + + // The Planar projection normally projects to a range (-1, 1) in + // both axes. Scale this into our UV range of (0, 1). + _projection_matrix = _projection_matrix * LMatrix4d(0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.5, 0.5, 0.0, 1.0); + + } else if (cmp_nocase(type, "cylindrical") == 0) { + _projection_type = PT_cylindrical; + _map_uvs = &MayaShaderColorDef::map_cylindrical; + + // The cylindrical projection is orthographic in the Y axis; scale + // the range (-1, 1) in this axis into our UV range (0, 1). + _projection_matrix = _projection_matrix * LMatrix4d(1.0, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.5, 0.0, 1.0); + + } else if (cmp_nocase(type, "spherical") == 0) { + _projection_type = PT_spherical; + _map_uvs = &MayaShaderColorDef::map_spherical; + + } else { + // Other projection types are currently unimplemented by the + // converter. + maya_cat.error() + << "Don't know how to handle type " << type << " projections.\n"; + _projection_type = PT_off; + _map_uvs = NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::map_planar +// Access: Private +// Description: Computes a UV based on the given point in space, +// using a planar projection. +//////////////////////////////////////////////////////////////////// +LPoint2d MayaShaderColorDef:: +map_planar(const LPoint3d &pos, const LPoint3d &) const { + // A planar projection is about as easy as can be. We ignore the Z + // axis, and project the point into the XY plane. Done. + return LPoint2d(pos[0], pos[1]); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::map_spherical +// Access: Private +// Description: Computes a UV based on the given point in space, +// using a spherical projection. +//////////////////////////////////////////////////////////////////// +LPoint2d MayaShaderColorDef:: +map_spherical(const LPoint3d &pos, const LPoint3d ¢roid) const { + // To compute the x position on the frame, we only need to consider + // the angle of the vector about the Y axis. Project the vector + // into the XZ plane to do this. + + LVector2d xz(pos[0], pos[2]); + double xz_length = xz.length(); + + if (xz_length < 0.01) { + // If we have a point on or near either pole, we've got problems. + // This point maps to the entire bottom edge of the image, so + // which U value should we choose? It does make a difference, + // especially if we have a number of polygons around the south + // pole that all share the common vertex. + + // We choose the U value based on the polygon's centroid. + xz.set(centroid[0], centroid[2]); + } + + // Now, if the polygon crosses the seam, we also have problems. + // Make sure that the u value is in the same half of the texture as + // the centroid's u value. + double u = rad_2_deg(atan2(xz[0], xz[1])) / (2.0 * _u_angle); + double c = rad_2_deg(atan2(centroid[0], centroid[2])) / (2.0 * _u_angle); + + if (u - c > 0.5) { + u -= floor(u - c + 0.5); + } else if (u - c < -0.5) { + u += floor(c - u + 0.5); + } + + // Now rotate the vector into the YZ plane, and the V value is based + // on the latitude: the angle about the X axis. + LVector2d yz(pos[1], xz_length); + double v = rad_2_deg(atan2(yz[0], yz[1])) / (2.0 * _v_angle); + + LPoint2d uv(u - 0.5, v - 0.5); + + nassertr(fabs(u - c) <= 0.5, uv); + return uv; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShaderColorDef::map_cylindrical +// Access: Private +// Description: Computes a UV based on the given point in space, +// using a cylindrical projection. +//////////////////////////////////////////////////////////////////// +LPoint2d MayaShaderColorDef:: +map_cylindrical(const LPoint3d &pos, const LPoint3d ¢roid) const { + // This is almost identical to the spherical projection, except for + // the computation of V. + + LVector2d xz(pos[0], pos[2]); + double xz_length = xz.length(); + + if (xz_length < 0.01) { + // A cylindrical mapping has the same singularity problem at the + // pole as a spherical mapping does: points at the pole do not map + // to a single point on the texture. (It's technically a slightly + // different problem: in a cylindrical mapping, points at the pole + // do not map to any point on the texture, while in a spherical + // mapping, points at the pole map to the top or bottom edge of + // the texture. But this is a technicality that doesn't really + // apply to us.) We still solve it the same way: if our point is + // at or near the pole, compute the angle based on the centroid of + // the polygon (which we assume is further from the pole). + xz.set(centroid[0], centroid[2]); + } + + // And cylinders do still have a seam at the back. + double u = rad_2_deg(atan2(xz[0], xz[1])) / _u_angle; + double c = rad_2_deg(atan2(centroid[0], centroid[2])) / _u_angle; + + if (u - c > 0.5) { + u -= floor(u - c + 0.5); + } else if (u - c < -0.5) { + u += floor(c - u + 0.5); + } + + // For a cylindrical mapping, the V value comes directly from Y. + // Easy. + LPoint2d uv(u - 0.5, pos[1]); + + nassertr(fabs(u - c) <= 0.5, uv); + return uv; +} diff --git a/pandatool/src/maya/mayaShaderColorDef.h b/pandatool/src/maya/mayaShaderColorDef.h new file mode 100755 index 0000000000..d5502e29e2 --- /dev/null +++ b/pandatool/src/maya/mayaShaderColorDef.h @@ -0,0 +1,100 @@ +// Filename: mayaShaderColorDef.h +// Created by: drose (12Apr03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef MAYASHADERCOLORDEF_H +#define MAYASHADERCOLORDEF_H + +#include "pandatoolbase.h" + +#include "luse.h" +#include "lmatrix.h" + +class MObject; + +//////////////////////////////////////////////////////////////////// +// Class : MayaShaderColorDef +// Description : This defines the various attributes that Maya may +// associate with the "color" channel for a particular +// shader (as well as on the "transparency" channel). +//////////////////////////////////////////////////////////////////// +class MayaShaderColorDef { +public: + MayaShaderColorDef(); + ~MayaShaderColorDef(); + + LMatrix3d compute_texture_matrix() const; + bool has_projection() const; + TexCoordd project_uv(const LPoint3d &pos, const LPoint3d &ref_point) const; + bool reset_maya_texture(const Filename &texture); + + void write(ostream &out) const; + + enum ProjectionType { + PT_off, + PT_planar, + PT_spherical, + PT_cylindrical, + PT_ball, + PT_cubic, + PT_triplanar, + PT_concentric, + PT_perspective, + }; + + bool _has_texture; + Filename _texture; + + bool _has_flat_color; + Colord _flat_color; + + ProjectionType _projection_type; + LMatrix4d _projection_matrix; + double _u_angle; + double _v_angle; + + LVector2f _coverage; + LVector2f _translate_frame; + double _rotate_frame; + + bool _mirror; + bool _stagger; + bool _wrap_u; + bool _wrap_v; + + LVector2f _repeat_uv; + LVector2f _offset; + double _rotate_uv; + +private: + void read_surface_color(MObject color); + void set_projection_type(const string &type); + + LPoint2d map_planar(const LPoint3d &pos, const LPoint3d ¢roid) const; + LPoint2d map_spherical(const LPoint3d &pos, const LPoint3d ¢roid) const; + LPoint2d map_cylindrical(const LPoint3d &pos, const LPoint3d ¢roid) const; + + // Define a pointer to one of the above member functions. + LPoint2d (MayaShaderColorDef::*_map_uvs)(const LPoint3d &pos, const LPoint3d ¢roid) const; + + MObject *_color_object; + + friend class MayaShader; +}; + +#endif + diff --git a/pandatool/src/mayaegg/mayaToEggConverter.cxx b/pandatool/src/mayaegg/mayaToEggConverter.cxx index 7c92af462d..da9149fa7b 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.cxx +++ b/pandatool/src/mayaegg/mayaToEggConverter.cxx @@ -1388,11 +1388,13 @@ make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, shader = default_shader; } + const MayaShaderColorDef &color_def = shader->_color; + // Since a texture completely replaces a polygon or vertex color, // we need to know up front whether we have a texture. bool has_texture = false; if (shader != (MayaShader *)NULL) { - has_texture = shader->_has_texture; + has_texture = color_def._has_texture; } // Get the vertices for the polygon. @@ -1400,7 +1402,7 @@ make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, long i; LPoint3d centroid(0.0, 0.0, 0.0); - if (shader != (MayaShader *)NULL && shader->has_projection()) { + if (shader != (MayaShader *)NULL && color_def.has_projection()) { // If the shader has a projection, we may need to compute the // polygon's centroid to avoid seams at the edges. for (i = 0; i < num_verts; i++) { @@ -1430,10 +1432,10 @@ make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, vert.set_normal(n3d); } - if (shader != (MayaShader *)NULL && shader->has_projection()) { + if (shader != (MayaShader *)NULL && color_def.has_projection()) { // If the shader has a projection, use it instead of the // polygon's built-in UV's. - vert.set_uv(shader->project_uv(p3d, centroid)); + vert.set_uv(color_def.project_uv(p3d, centroid)); } else if (pi.hasUVs()) { // Get the UV's from the polygon. @@ -1778,7 +1780,7 @@ get_egg_table(const MDagPath &dag_path, EggGroupNode *egg_root) { //////////////////////////////////////////////////////////////////// // Function: MayaShader::set_shader_attributes -// Access: Public +// Access: Private // Description: Applies the known shader attributes to the indicated // egg primitive. //////////////////////////////////////////////////////////////////// @@ -1786,40 +1788,162 @@ void MayaToEggConverter:: set_shader_attributes(EggPrimitive &primitive, const MayaShader &shader) { // In Maya, a polygon is either textured or colored. The texture, // if present, replaces the color. + const MayaShaderColorDef &color_def = shader._color; + const MayaShaderColorDef &trans_def = shader._transparency; + if (color_def._has_texture || trans_def._has_texture) { + EggTexture tex(shader.get_name(), ""); - if (shader._has_texture) { - Filename filename = Filename::from_os_specific(shader._texture); - Filename fullpath = - _path_replace->match_path(filename, get_texture_path()); - EggTexture tex(shader._name, _path_replace->store_path(fullpath)); - tex.set_fullpath(fullpath); + if (color_def._has_texture) { + // If we have a texture on color, apply it as the filename. + Filename filename = Filename::from_os_specific(color_def._texture); + Filename fullpath = + _path_replace->match_path(filename, get_texture_path()); + tex.set_filename(_path_replace->store_path(fullpath)); + tex.set_fullpath(fullpath); + apply_texture_properties(tex, color_def); - tex.set_wrap_u(shader._wrap_u ? EggTexture::WM_repeat : EggTexture::WM_clamp); - tex.set_wrap_v(shader._wrap_v ? EggTexture::WM_repeat : EggTexture::WM_clamp); - - // Let's mipmap all textures by default. - tex.set_minfilter(EggTexture::FT_linear_mipmap_linear); - tex.set_magfilter(EggTexture::FT_linear); + // If we also have a texture on transparency, apply it as the + // alpha filename. + if (trans_def._has_texture) { + if (color_def._wrap_u != trans_def._wrap_u || + color_def._wrap_u != trans_def._wrap_u) { + mayaegg_cat.warning() + << "Shader " << shader.get_name() + << " has contradictory wrap modes on color and texture.\n"; + } + + filename = Filename::from_os_specific(trans_def._texture); + fullpath = _path_replace->match_path(filename, get_texture_path()); + tex.set_alpha_filename(_path_replace->store_path(fullpath)); + tex.set_alpha_fullpath(fullpath); + tex.set_format(EggTexture::F_rgba); - LMatrix3d mat = shader.compute_texture_matrix(); - if (!mat.almost_equal(LMatrix3d::ident_mat())) { - tex.set_transform(mat); + if (!compare_texture_properties(tex, trans_def)) { + // Only report each broken shader once. + static pset bad_shaders; + if (bad_shaders.insert(shader.get_name()).second) { + mayaegg_cat.error() + << "Color and transparency texture properties differ on shader " + << shader.get_name() << "\n"; + } + } + + } else { + // Otherwise, we don't have any transparency, so tell the egg + // format to ignore any alpha channel that might be on the + // color texture. + tex.set_format(EggTexture::F_rgb); + } + + } else { // trans_def._has_texture + // We have a texture on transparency only. Apply it as the + // primary filename, and set the format accordingly. + Filename filename = Filename::from_os_specific(trans_def._texture); + Filename fullpath = + _path_replace->match_path(filename, get_texture_path()); + tex.set_filename(_path_replace->store_path(fullpath)); + tex.set_fullpath(fullpath); + tex.set_format(EggTexture::F_alpha); + apply_texture_properties(tex, trans_def); } - + EggTexture *new_tex = _textures.create_unique_texture(tex, ~EggTexture::E_tref_name); - + primitive.set_texture(new_tex); - } else if (shader._has_color) { - primitive.set_color(Colorf(shader._color[0], shader._color[1], - shader._color[2], 1.0f)); + } + + // Also apply an overall color to the primitive. + Colorf rgba = shader.get_rgba(); + + // This is a placeholder for a parameter on the shader or group that + // we have yet to define. + static const bool modulate = false; + + if (!modulate) { + // If modulate is not specified, the existence of a texture on + // either color channel completely replaces the flat color. + if (color_def._has_texture) { + rgba[0] = 1.0f; + rgba[1] = 1.0f; + rgba[2] = 1.0f; + } + if (trans_def._has_texture) { + rgba[3] = 1.0f; + } + } + + primitive.set_color(rgba); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShader::apply_texture_properties +// Access: Private +// Description: Applies all the appropriate texture properties to the +// EggTexture object, including wrap modes and texture +// matrix. +//////////////////////////////////////////////////////////////////// +void MayaToEggConverter:: +apply_texture_properties(EggTexture &tex, const MayaShaderColorDef &color_def) { + // Let's mipmap all textures by default. + tex.set_minfilter(EggTexture::FT_linear_mipmap_linear); + tex.set_magfilter(EggTexture::FT_linear); + + EggTexture::WrapMode wrap_u = color_def._wrap_u ? EggTexture::WM_repeat : EggTexture::WM_clamp; + EggTexture::WrapMode wrap_v = color_def._wrap_v ? EggTexture::WM_repeat : EggTexture::WM_clamp; + + tex.set_wrap_u(wrap_u); + tex.set_wrap_v(wrap_v); + + LMatrix3d mat = color_def.compute_texture_matrix(); + if (!mat.almost_equal(LMatrix3d::ident_mat())) { + tex.set_transform(mat); } } +//////////////////////////////////////////////////////////////////// +// Function: MayaShader::compare_texture_properties +// Access: Private +// Description: Compares the texture properties already on the +// texture (presumably set by a previous call to +// apply_texture_properties()) and returns false if they +// differ from that specified by the indicated color_def +// object, or true if they match. +//////////////////////////////////////////////////////////////////// +bool MayaToEggConverter:: +compare_texture_properties(EggTexture &tex, + const MayaShaderColorDef &color_def) { + bool okflag = true; + + EggTexture::WrapMode wrap_u = color_def._wrap_u ? EggTexture::WM_repeat : EggTexture::WM_clamp; + EggTexture::WrapMode wrap_v = color_def._wrap_v ? EggTexture::WM_repeat : EggTexture::WM_clamp; + + if (wrap_u != tex.determine_wrap_u()) { + // Choose the more general of the two. + if (wrap_u == EggTexture::WM_repeat) { + tex.set_wrap_u(wrap_u); + } + okflag = false; + } + if (wrap_v != tex.determine_wrap_v()) { + if (wrap_v == EggTexture::WM_repeat) { + tex.set_wrap_v(wrap_v); + } + okflag = false; + } + + LMatrix3d mat = color_def.compute_texture_matrix(); + if (!mat.almost_equal(tex.get_transform())) { + okflag = false; + } + + return okflag; +} + //////////////////////////////////////////////////////////////////// // Function: MayaShader::reparent_decals -// Access: Public +// Access: Private // Description: Recursively walks the egg hierarchy, reparenting // "decal" type nodes below their corresponding // "decalbase" type nodes, and setting the flags. @@ -1876,13 +2000,10 @@ reparent_decals(EggGroupNode *egg_parent) { // All the decal children get moved to be a child of decal base. // This usually will not affect the vertex positions, but it // could if the decal base has a transform and the decal child - // is an instance node. So don't do that. Also, we assume it's - // undesired to have a transform on a decal, so we flatten those - // out here--there's no real requirement to do this, however. + // is an instance node. So don't do that. pvector::iterator di; for (di = decal_children.begin(); di != decal_children.end(); ++di) { EggGroup *child_group = (*di); - child_group->flatten_transforms(); decal_base->add_child(child_group); } diff --git a/pandatool/src/mayaegg/mayaToEggConverter.h b/pandatool/src/mayaegg/mayaToEggConverter.h index 365b0095c8..d2735fe77d 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.h +++ b/pandatool/src/mayaegg/mayaToEggConverter.h @@ -39,6 +39,7 @@ class EggVertexPool; class EggNurbsCurve; class EggPrimitive; class EggXfmSAnim; +class MayaShaderColorDef; class MDagPath; class MFnNurbsSurface; @@ -119,6 +120,10 @@ private: JointAnim *get_egg_table(const string &name, EggGroupNode *egg_root); void set_shader_attributes(EggPrimitive &primitive, const MayaShader &shader); + void apply_texture_properties(EggTexture &tex, + const MayaShaderColorDef &color_def); + bool compare_texture_properties(EggTexture &tex, + const MayaShaderColorDef &color_def); bool reparent_decals(EggGroupNode *egg_parent); diff --git a/pandatool/src/mayaprogs/mayaCopy.cxx b/pandatool/src/mayaprogs/mayaCopy.cxx index acfd9926ed..4fdcf75269 100644 --- a/pandatool/src/mayaprogs/mayaCopy.cxx +++ b/pandatool/src/mayaprogs/mayaCopy.cxx @@ -167,32 +167,11 @@ copy_maya_file(const Filename &source, const Filename &dest, int num_shaders = _shaders.get_num_shaders(); for (int i = 0; i < num_shaders; i++) { MayaShader *shader = _shaders.get_shader(i); - if (shader->_has_texture) { - Filename texture_filename = - _path_replace->convert_path(shader->_texture); - if (!texture_filename.exists()) { - nout << "*** Warning: texture " << texture_filename - << " does not exist.\n"; - } else if (!texture_filename.is_regular_file()) { - nout << "*** Warning: texture " << texture_filename - << " is not a regular file.\n"; - } else { - ExtraData ed; - ed._type = FT_texture; - - CVSSourceDirectory *texture_dir = - import(texture_filename, &ed, _map_dir); - if (texture_dir == (CVSSourceDirectory *)NULL) { - return false; - } - - // Update the texture reference to point to the new texture - // filename, relative to the flt file. Not sure how to do - // this right now. - Filename new_filename = dir->get_rel_to(texture_dir) + "/" + - texture_filename.get_basename(); - shader->reset_maya_texture(new_filename); - } + if (!extract_texture(shader->_color, dir)) { + return false; + } + if (!extract_texture(shader->_transparency, dir)) { + return false; } } @@ -236,6 +215,46 @@ copy_maya_file(const Filename &source, const Filename &dest, return true; } +//////////////////////////////////////////////////////////////////// +// Function: MayaCopy::extract_texture +// Access: Private +// Description: Gets the texture out of the indicated color channel +// and copies it in, updating the channel with the new +// texture filename. Returns true on success, false on +// failure. +//////////////////////////////////////////////////////////////////// +bool MayaCopy:: +extract_texture(MayaShaderColorDef &color_def, CVSSourceDirectory *dir) { + if (color_def._has_texture) { + Filename texture_filename = + _path_replace->convert_path(color_def._texture); + if (!texture_filename.exists()) { + nout << "*** Warning: texture " << texture_filename + << " does not exist.\n"; + } else if (!texture_filename.is_regular_file()) { + nout << "*** Warning: texture " << texture_filename + << " is not a regular file.\n"; + } else { + ExtraData ed; + ed._type = FT_texture; + + CVSSourceDirectory *texture_dir = + import(texture_filename, &ed, _map_dir); + if (texture_dir == (CVSSourceDirectory *)NULL) { + return false; + } + + // Update the texture reference to point to the new texture + // filename, relative to the maya file. + Filename new_filename = dir->get_rel_to(texture_dir) + "/" + + texture_filename.get_basename(); + color_def.reset_maya_texture(new_filename); + } + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: MayaCopy::copy_texture // Access: Private diff --git a/pandatool/src/mayaprogs/mayaCopy.h b/pandatool/src/mayaprogs/mayaCopy.h index f4de9d6b78..47759a4b23 100644 --- a/pandatool/src/mayaprogs/mayaCopy.h +++ b/pandatool/src/mayaprogs/mayaCopy.h @@ -29,6 +29,7 @@ #include "pset.h" class MayaShader; +class MayaShaderColorDef; class MDagPath; //////////////////////////////////////////////////////////////////// @@ -63,6 +64,7 @@ private: bool copy_maya_file(const Filename &source, const Filename &dest, CVSSourceDirectory *dir); + bool extract_texture(MayaShaderColorDef &color_def, CVSSourceDirectory *dir); bool copy_texture(const Filename &source, const Filename &dest, CVSSourceDirectory *dir);