// Filename: shaderAttrib.cxx
// Created by:  sshodhan (10Jul04)
// Updated by:  fperazzi, PandaSE (06Apr10) (added more overloads
//   for set_shader_input)
// Updated by: weifengh, PandaSE(15Apr10) (added overload for
//   set_shader_auto)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "pandabase.h"
#include "shaderAttrib.h"
#include "graphicsStateGuardianBase.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "datagram.h"
#include "datagramIterator.h"

TypeHandle ShaderAttrib::_type_handle;
int ShaderAttrib::_attrib_slot;

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::make_off
//       Access: Published, Static
//  Description: Constructs a new ShaderAttrib object that disables
//               the use of shaders (it does not clear out all shader
//               data, however.)
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
make_off() {
  static CPT(RenderAttrib) _off_attrib;
  if (_off_attrib == 0) {
    ShaderAttrib *attrib = new ShaderAttrib;
    attrib->_has_shader = true;
    _off_attrib = return_new(attrib);
  }
  return _off_attrib;
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::make
//       Access: Published, Static
//  Description: Constructs a new ShaderAttrib object with nothing
//               set.
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
make() {
  static CPT(RenderAttrib) _null_attrib;
  if (_null_attrib == 0) {
    ShaderAttrib *attrib = new ShaderAttrib;
    _null_attrib = return_new(attrib);
  }
  return _null_attrib;
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::make_default
//       Access: Published, Static
//  Description: Returns a RenderAttrib that corresponds to whatever
//               the standard default properties for render attributes
//               of this type ought to be.
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
make_default() {
  return return_new(new ShaderAttrib);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
set_shader(const Shader *s, int priority) const {
  ShaderAttrib *result = new ShaderAttrib(*this);
  result->_shader = s;
  result->_shader_priority = priority;
  result->_auto_shader = false;
  result->_has_shader = true;
  return return_new(result);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_off
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
set_shader_off(int priority) const {
  ShaderAttrib *result = new ShaderAttrib(*this);
  result->_shader = NULL;
  result->_shader_priority = priority;
  result->_auto_shader = false;
  result->_auto_normal_on = false;
  result->_auto_glow_on = false;
  result->_auto_gloss_on = false;
  result->_auto_ramp_on = false;
  result->_auto_shadow_on = false;

  result->_has_shader = true;
  return return_new(result);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_auto
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
set_shader_auto(int priority) const {
  ShaderAttrib *result = new ShaderAttrib(*this);
  result->_shader = NULL;
  result->_shader_priority = priority;
  result->_auto_shader = true;
  result->_has_shader = true;
  result->_auto_normal_on = true;
  result->_auto_glow_on = true;
  result->_auto_gloss_on = true;
  result->_auto_ramp_on = true;
  result->_auto_shadow_on = true;
  return return_new(result);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_auto
//       Access: Published
//  Description: Set auto shader with bitmask to customize use,
//  e.g., to keep normal, glow, etc., on or off
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
set_shader_auto(BitMask32 shader_switch, int priority) const {
  
  ShaderAttrib *result = new ShaderAttrib(*this);
  result->_shader = NULL;
  result->_shader_priority = priority;
  result->_auto_shader = true;
  result->_has_shader = true;
  result->_auto_normal_on = shader_switch.get_bit(Shader::bit_AutoShaderNormal);
  result->_auto_glow_on = shader_switch.get_bit(Shader::bit_AutoShaderGlow);
  result->_auto_gloss_on = shader_switch.get_bit(Shader::bit_AutoShaderGloss);
  result->_auto_ramp_on = shader_switch.get_bit(Shader::bit_AutoShaderRamp);
  result->_auto_shadow_on = shader_switch.get_bit(Shader::bit_AutoShaderShadow);

  return return_new(result);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::clear_shader
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
clear_shader() const {
  ShaderAttrib *result = new ShaderAttrib(*this);
  result->_shader = NULL;
  result->_shader_priority = 0;
  result->_auto_shader = false;
  result->_has_shader = false;
  result->_auto_normal_on = false;
  result->_auto_glow_on = false;
  result->_auto_gloss_on = false;
  result->_auto_ramp_on = false;
  result->_auto_shadow_on = false;
  return return_new(result);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_flag
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
set_flag(int flag, bool value) const {
  ShaderAttrib *result = new ShaderAttrib(*this);
  int bit = 1<<flag;
  if (value) {
    result->_flags |= bit;
  } else {
    result->_flags &= ~bit;
  }
  result->_has_flags |= bit;
  return return_new(result);
}
  
////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::clear_flag
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
clear_flag(int flag) const {
  ShaderAttrib *result = new ShaderAttrib(*this);
  int bit = 1<<flag;
  result->_flags &= ~bit;
  result->_has_flags &= ~bit;
  return return_new(result);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
set_shader_input(const ShaderInput *input) const {
  ShaderAttrib *result = new ShaderAttrib(*this);
  Inputs::iterator i = result->_inputs.find(input->get_name());
  if (i == result->_inputs.end()) {
    result->_inputs.insert(Inputs::value_type(input->get_name(),input));
  } else {
    i->second = input;
  }
  return return_new(result);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const PTA_float &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const PTA_double &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const PTA_LVecBase4 &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const PTA_LVecBase3 &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}


////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const PTA_LVecBase2 &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const LVecBase4 &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const LVecBase3 &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const LVecBase2 &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const PTA_LMatrix4 &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const PTA_LMatrix3 &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const LMatrix4 &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib:: 
set_shader_input(const InternalName *id, const LMatrix3 &v, int priority) const {
  return set_shader_input(new ShaderInput(id,v,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
set_shader_input(const InternalName *id, Texture *tex, int priority) const {
  return set_shader_input(new ShaderInput(id,tex,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
set_shader_input(const InternalName *id, const NodePath &np, int priority) const {
  return set_shader_input(new ShaderInput(id,np,priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
set_shader_input(const InternalName *id, double n1, double n2, double n3, double n4, int priority) const {
  return set_shader_input(new ShaderInput(id, LVecBase4(n1,n2,n3,n4), priority));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::set_instance_count
//       Access: Published
//  Description: Sets the geometry instance count. Do not confuse
//               this with instanceTo, which is used for animation
//               instancing, and has nothing to do with this.
//               A value of 0 means not to use instancing at all.
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
set_instance_count(int instance_count) const {
  ShaderAttrib *result = new ShaderAttrib(*this);
  result->_instance_count = instance_count;
  return return_new(result);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::clear_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
clear_shader_input(const InternalName *id) const {
  ShaderAttrib *result = new ShaderAttrib(*this);
  result->_inputs.erase(id);
  return return_new(result);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::clear_shader_input
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
clear_shader_input(const string &id) const {
  return clear_shader_input(InternalName::make(id));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::clear_all_shader_inputs
//       Access: Published
//  Description: Clears all the shader inputs on the attrib.
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
clear_all_shader_inputs() const {
  ShaderAttrib *result = new ShaderAttrib(*this);
  result->_inputs.clear();
  return return_new(result);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::get_shader_input
//       Access: Published
//  Description: Returns the ShaderInput of the given name.  If
//               no such name is found, this function does not return
//               NULL --- it returns the "blank" ShaderInput.
////////////////////////////////////////////////////////////////////
const ShaderInput *ShaderAttrib::
get_shader_input(const InternalName *id) const {
  Inputs::const_iterator i = _inputs.find(id);
  if (i == _inputs.end()) {
    return ShaderInput::get_blank();
  } else {
    return (*i).second;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::get_shader_input
//       Access: Published
//  Description: Returns the ShaderInput of the given name.  If
//               no such name is found, this function does not return
//               NULL --- it returns the "blank" ShaderInput.
////////////////////////////////////////////////////////////////////
const ShaderInput *ShaderAttrib::
get_shader_input(const string &id) const {
  return get_shader_input(InternalName::make(id));
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::get_shader_input_nodepath
//       Access: Published
//  Description: Returns the ShaderInput as a nodepath.  Assertion 
//               fails if there is none, or if it is not a nodepath.
////////////////////////////////////////////////////////////////////
const NodePath &ShaderAttrib::
get_shader_input_nodepath(const InternalName *id) const {
  static NodePath resfail;
  Inputs::const_iterator i = _inputs.find(id);
  if (i == _inputs.end()) {
    ostringstream strm;
    strm << "Shader input " << id->get_name() << " is not present.\n";
    nassert_raise(strm.str());
    return resfail;
  } else {
    const ShaderInput *p = (*i).second;
    if (p->get_value_type() != ShaderInput::M_nodepath) {
      ostringstream strm;
      strm << "Shader input " << id->get_name() << " is not a nodepath.\n";
      nassert_raise(strm.str());
      return resfail;
    }
    return p->get_nodepath();
  }

  // Satisfy compiler.
  return resfail;
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::get_shader_input_vector
//       Access: Published
//  Description: Returns the ShaderInput as a vector.  Assertion 
//               fails if there is none, or if it is not a vector.
////////////////////////////////////////////////////////////////////
const LVecBase4 &ShaderAttrib::
get_shader_input_vector(InternalName *id) const {
  static LVecBase4 resfail(0,0,0,0);
  Inputs::const_iterator i = _inputs.find(id);
  if (i == _inputs.end()) {
    ostringstream strm;
    strm << "Shader input " << id->get_name() << " is not present.\n";
    nassert_raise(strm.str());
    return resfail;
  } else {
    const ShaderInput *p = (*i).second;
    if (p->get_value_type() != ShaderInput::M_numeric) {
      ostringstream strm;
      strm << "Shader input " << id->get_name() << " is not a vector.\n";
      nassert_raise(strm.str());
      return resfail;
    }
    return p->get_vector();
  }
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::get_shader_input_ptr
//       Access: Published
//  Description: Returns the ShaderInput as a ShaderPtrData struct. 
//               Assertion fails if there is none. or if it is not 
//               a PTA(double/float)
////////////////////////////////////////////////////////////////////
const Shader::ShaderPtrData *ShaderAttrib:: 
get_shader_input_ptr(const InternalName *id) const {
  Inputs::const_iterator i = _inputs.find(id);
  if (i == _inputs.end()) {
    ostringstream strm;
    strm << "Shader input " << id->get_name() << " is not present.\n";
    nassert_raise(strm.str());
    return NULL;
  } else {
    const ShaderInput *p = (*i).second;
    if (p->get_value_type() != ShaderInput::M_numeric) {
      ostringstream strm;
      strm << "Shader input " << id->get_name() << " is not a PTA(float/double) type.\n";
      nassert_raise(strm.str());
      return NULL;
    }
    return &(p->get_ptr());
  }
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::get_shader_input_texture
//       Access: Published
//  Description: Returns the ShaderInput as a texture.  Assertion 
//               fails if there is none, or if it is not a texture.
////////////////////////////////////////////////////////////////////
Texture *ShaderAttrib::
get_shader_input_texture(const InternalName *id) const {
  Inputs::const_iterator i = _inputs.find(id);
  if (i == _inputs.end()) {
    ostringstream strm;
    strm << "Shader input " << id->get_name() << " is not present.\n";
    nassert_raise(strm.str());
    return NULL;
  } else {
    const ShaderInput *p = (*i).second;
    if (p->get_value_type() != ShaderInput::M_texture) {
      ostringstream strm;
      strm <<  "Shader input " << id->get_name() << " is not a texture.\n";
      nassert_raise(strm.str());
      return NULL;
    }
    return p->get_texture();
  }
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::get_shader
//       Access: Published
//  Description: Returns the shader object associated with the node.
//               If get_override returns true, but get_shader 
//               returns NULL, that means that this attribute should
//               disable the shader.
////////////////////////////////////////////////////////////////////
const Shader *ShaderAttrib::
get_shader() const {
  return _shader;
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::compare_to_impl
//       Access: Protected, Virtual
//  Description: Intended to be overridden by derived ShaderAttrib
//               types to return a unique number indicating whether
//               this ShaderAttrib is equivalent to the other one.
//
//               This should return 0 if the two ShaderAttrib objects
//               are equivalent, a number less than zero if this one
//               should be sorted before the other one, and a number
//               greater than zero otherwise.
//
//               This will only be called with two ShaderAttrib
//               objects whose get_type() functions return the same.
////////////////////////////////////////////////////////////////////
int ShaderAttrib::
compare_to_impl(const RenderAttrib *other) const {
  const ShaderAttrib *that;
  DCAST_INTO_R(that, other, 0);
  
  if (this->_shader != that->_shader) {
    return (this->_shader < that->_shader) ? -1 : 1;
  }
  if (this->_shader_priority != that->_shader_priority) {
    return (this->_shader_priority < that->_shader_priority) ? -1 : 1;
  }
  if (this->_auto_shader != that->_auto_shader) {
    return (this->_auto_shader < that->_auto_shader) ? -1 : 1;
  }
  if (this->_has_shader != that->_has_shader) {
    return (this->_has_shader < that->_has_shader) ? -1 : 1;
  }
  if (this->_flags != that->_flags) {
    return (this->_flags < that->_flags) ? -1 : 1;
  }
  if (this->_has_flags != that->_has_flags) {
    return (this->_has_flags < that->_has_flags) ? -1 : 1;
  }
  if (this->_instance_count != that->_instance_count) {
    return (this->_instance_count < that->_instance_count) ? -1 : 1;
  }
  if (this->_auto_normal_on != that->_auto_normal_on) {
    return (this->_auto_normal_on < that->_auto_normal_on) ? -1 : 1;
  }
  if (this->_auto_glow_on != that->_auto_glow_on) {
    return (this->_auto_glow_on < that->_auto_glow_on) ? -1 : 1;
  }
  if (this->_auto_gloss_on != that->_auto_gloss_on) {
    return (this->_auto_gloss_on < that->_auto_gloss_on) ? -1 : 1;
  }
  if (this->_auto_ramp_on != that->_auto_ramp_on) {
    return (this->_auto_ramp_on < that->_auto_ramp_on) ? -1 : 1;
  }
  if (this->_auto_shadow_on != that->_auto_shadow_on) {
    return (this->_auto_shadow_on < that->_auto_shadow_on) ? -1 : 1;
  }

  Inputs::const_iterator i1 = this->_inputs.begin();
  Inputs::const_iterator i2 = that->_inputs.begin();
  while ((i1 != this->_inputs.end()) && (i2 != that->_inputs.end())) {
    if (i1->second != i2->second) {
      return (i1->second < i2->second) ? -1 : 1;
    }
    ++i1;
    ++i2;
  }
  if (i1 != this->_inputs.end()) {
    return 1;
  }
  if (i2 != that->_inputs.end()) {
    return -1;
  }
  
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::get_hash_impl
//       Access: Protected, Virtual
//  Description: Intended to be overridden by derived RenderAttrib
//               types to return a unique hash for these particular
//               properties.  RenderAttribs that compare the same with
//               compare_to_impl(), above, should return the same
//               hash; RenderAttribs that compare differently should
//               return a different hash.
////////////////////////////////////////////////////////////////////
size_t ShaderAttrib::
get_hash_impl() const {
  size_t hash = 0;
  hash = pointer_hash::add_hash(hash, _shader);
  hash = int_hash::add_hash(hash, _shader_priority);
  hash = int_hash::add_hash(hash, (int)_auto_shader);
  hash = int_hash::add_hash(hash, (int)_has_shader);
  hash = int_hash::add_hash(hash, _flags);
  hash = int_hash::add_hash(hash, _has_flags);
  hash = int_hash::add_hash(hash, _instance_count);
  hash = int_hash::add_hash(hash, (int)_auto_normal_on);
  hash = int_hash::add_hash(hash, (int)_auto_glow_on);
  hash = int_hash::add_hash(hash, (int)_auto_gloss_on);
  hash = int_hash::add_hash(hash, (int)_auto_shadow_on);

  Inputs::const_iterator ii;
  for (ii = _inputs.begin(); ii != _inputs.end(); ++ii) {
    hash = pointer_hash::add_hash(hash, (*ii).first);
    hash = pointer_hash::add_hash(hash, (*ii).second);
  }

  return hash;
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::compose_impl
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
compose_impl(const RenderAttrib *other) const {
  ShaderAttrib *attr = new ShaderAttrib(*this);
  const ShaderAttrib *over;
  DCAST_INTO_R(over, other, 0);
  // Update the shader portion.
  if (over->_has_shader) {
    if ((attr->_has_shader == false) ||
        (over->_shader_priority >= attr->_shader_priority)) {
      attr->_shader = over->_shader;
      attr->_shader_priority = over->_shader_priority;
      attr->_auto_shader = over->_auto_shader;
      attr->_has_shader = over->_has_shader;
      attr->_auto_normal_on = over->_auto_normal_on;
      attr->_auto_glow_on = over->_auto_glow_on;
      attr->_auto_gloss_on = over->_auto_gloss_on;
      attr->_auto_ramp_on = over->_auto_ramp_on;
      attr->_auto_shadow_on = over->_auto_shadow_on;
    }
  }
  // Update the shader-data portion.
  Inputs::const_iterator iover;
  for (iover=over->_inputs.begin(); iover!=over->_inputs.end(); ++iover) {
    const InternalName *id = (*iover).first;
    const ShaderInput *dover = (*iover).second;
    Inputs::iterator iattr = attr->_inputs.find(id);
    if (iattr == attr->_inputs.end()) {
      attr->_inputs.insert(Inputs::value_type(id,dover));
    } else {
      const ShaderInput *dattr = (*iattr).second;
      if (dattr->get_priority() <= dover->get_priority()) {
        iattr->second = iover->second;
      }
    }
  }
  // Just copy the instance count.
  attr->_instance_count = over->_instance_count;
  // Update the flags.
  attr->_flags &= ~(over->_has_flags);
  attr->_flags |= over->_flags;
  attr->_has_flags |= (over->_has_flags);
  return return_new(attr);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::get_auto_shader_attrib_impl
//       Access: Protected, Virtual
//  Description: 
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ShaderAttrib::
get_auto_shader_attrib_impl(const RenderState *state) const {
  // For a ShaderAttrib, we only need to preserve the auto-shader
  // flags.  Custom shaders, and custom shader inputs, aren't relevant
  // to the shader generator.
  ShaderAttrib *attrib = new ShaderAttrib;
  attrib->_auto_shader = _auto_shader;
  attrib->_has_shader = _has_shader;
  attrib->_auto_normal_on = _auto_normal_on;
  attrib->_auto_glow_on = _auto_glow_on;
  attrib->_auto_gloss_on = _auto_gloss_on;
  attrib->_auto_ramp_on = _auto_ramp_on;
  attrib->_auto_shadow_on = _auto_shadow_on;
  return return_new(attrib);
}

////////////////////////////////////////////////////////////////////
//     Function: ShaderAttrib::register_with_read_factory
//       Access: Public, Static
//  Description: Factory method to generate a Shader object
////////////////////////////////////////////////////////////////////
void ShaderAttrib::
register_with_read_factory() {
  // IMPLEMENT ME
}

