// Filename: geomMunger.I
// Created by:  drose (10Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::get_gsg
//       Access: Public
//  Description: Returns a pointer to the GSG that created this
//               munger.
////////////////////////////////////////////////////////////////////
INLINE GraphicsStateGuardianBase *GeomMunger::
get_gsg() const {
  return _gsg;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::is_registered
//       Access: Public
//  Description: Returns true if this munger has been registered,
//               false if it has not.  It may not be used for a Geom
//               until it has been registered, but once registered, it
//               may no longer be modified.
////////////////////////////////////////////////////////////////////
INLINE bool GeomMunger::
is_registered() const {
  return _is_registered;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::register_munger
//       Access: Public, Static
//  Description: Adds the indicated munger to the registry, if there
//               is not an equivalent munger already there; in either
//               case, returns the pointer to the equivalent munger
//               now in the registry.
//
//               This must be called before a munger may be used in a
//               Geom.  After this call, you should discard the
//               original pointer you passed in (which may or may not
//               now be invalid) and let its reference count decrement
//               normally; you should use only the returned value from
//               this point on.
////////////////////////////////////////////////////////////////////
INLINE PT(GeomMunger) GeomMunger::
register_munger(GeomMunger *munger, Thread *current_thread) {
  return get_registry()->register_munger(munger, current_thread);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::unregister_mungers_for_gsg
//       Access: Public, Static
//  Description: Removes all the mungers from the registry that are
//               associated with the indicated GSG.
////////////////////////////////////////////////////////////////////
INLINE void GeomMunger::
unregister_mungers_for_gsg(GraphicsStateGuardianBase *gsg) {
  get_registry()->unregister_mungers_for_gsg(gsg);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::munge_format
//       Access: Public
//  Description: Given a source GeomVertexFormat, converts it if
//               necessary to the appropriate format for rendering.
//
//               If the GeomVertexAnimationSpec so indicates, then the
//               format will be chosen to convert CPU-based animation
//               tables to HW-based animation tables, reserving space
//               for the specified number of transforms per vertex.
////////////////////////////////////////////////////////////////////
INLINE CPT(GeomVertexFormat) GeomMunger::
munge_format(const GeomVertexFormat *format,
             const GeomVertexAnimationSpec &animation) const {
  // We cast away the const pointer, because do_munge_format() needs
  // to update caches and stuff, but we trust it not to change any
  // user-definable parameters.
  return ((GeomMunger *)this)->do_munge_format(format, animation);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::munge_data
//       Access: Public
//  Description: Given a source GeomVertexData, converts it if
//               necessary to the appropriate data for rendering.
////////////////////////////////////////////////////////////////////
INLINE CPT(GeomVertexData) GeomMunger::
munge_data(const GeomVertexData *data) const {
  // We cast away the const pointer, because do_munge_data() needs to
  // update caches and stuff, but we trust it not to change any
  // user-definable parameters.
  return ((GeomMunger *)this)->munge_data_impl(data);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::premunge_format
//       Access: Public
//  Description: This is similar to munge_format(), but it is done at
//               load time, to optimize a model for eventual rendering
//               on a particular GSG.  At this point, we do not
//               necessarily know the final render state that will be
//               applied, so we cannot make any destructive changes to
//               the geom, its data, or its format.
////////////////////////////////////////////////////////////////////
INLINE CPT(GeomVertexFormat) GeomMunger::
premunge_format(const GeomVertexFormat *format) const {
  return ((GeomMunger *)this)->do_premunge_format(format);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::premunge_data
//       Access: Public
//  Description: This is similar to munge_data(), but it is done at
//               load time, to optimize a model for eventual rendering
//               on a particular GSG.  At this point, we do not
//               necessarily know the final render state that will be
//               applied, so we cannot make any destructive changes to
//               the geom, its data, or its format.
////////////////////////////////////////////////////////////////////
INLINE CPT(GeomVertexData) GeomMunger::
premunge_data(const GeomVertexData *data) const {
  return ((GeomMunger *)this)->premunge_data_impl(data);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::premunge_geom
//       Access: Public
//  Description: This is similar to munge_geom(), but it is done at
//               load time, to optimize a model for eventual rendering
//               on a particular GSG.  At this point, we do not
//               necessarily know the final render state that will be
//               applied, so we cannot make any destructive changes to
//               the geom, its data, or its format.
//
//               Unlike munge_geom(), this result is not cached, since
//               the assumption is that this operation is performed at
//               load time once for each model.
////////////////////////////////////////////////////////////////////
INLINE void GeomMunger::
premunge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data) const {
  ((GeomMunger *)this)->premunge_geom_impl(geom, data);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::compare_to
//       Access: Public
//  Description: Provides an arbitrary ordering among all unique
//               GeomMungers, so we can store the essentially
//               different ones in a big set and throw away the rest.
////////////////////////////////////////////////////////////////////
INLINE int GeomMunger::
compare_to(const GeomMunger &other) const {
  // First, we compare the types; if they are of different types then
  // they sort differently.
  TypeHandle type = get_type();
  TypeHandle other_type = other.get_type();
  if (type != other_type) {
    return type.get_index() - other_type.get_index();
  }

  // We only call compare_to_impl() if they have the same type.
  return compare_to_impl(&other);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::geom_compare_to
//       Access: Public
//  Description: Compares two GeomMungers, considering only whether
//               they would produce a different answer to
//               munge_format(), munge_data(), or munge_geom().  (They
//               still might be different in other ways, but if they
//               would produce the same answer, this function consider
//               them to be the same.)
////////////////////////////////////////////////////////////////////
INLINE int GeomMunger::
geom_compare_to(const GeomMunger &other) const {
  // First, we compare the types; if they are of different types then
  // they sort differently.
  TypeHandle type = get_type();
  TypeHandle other_type = other.get_type();
  if (type != other_type) {
    return type.get_index() - other_type.get_index();
  }

  // We only call compare_to_impl() if they have the same type.
  return geom_compare_to_impl(&other);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::unregister_myself
//       Access: Protected
//  Description: Unregisters the GeomMunger, for instance when it is
//               being destructed, or whenever it has become invalid
//               for some reason.  This removes it from the registry
//               so that it will no longer be available to be returned
//               by register_munger().
//
//               It is not an error to call this if the munger has
//               already been unregistered.
////////////////////////////////////////////////////////////////////
INLINE void GeomMunger::
unregister_myself() {
  if (is_registered()) {
    get_registry()->unregister_munger(this);
  }
}

////////////////////////////////////////////////////////////////////
//     Function: GeomMunger::get_registry
//       Access: Private
//  Description: Returns the global registry object.
////////////////////////////////////////////////////////////////////
INLINE GeomMunger::Registry *GeomMunger::
get_registry() {
  if (_registry == (Registry *)NULL) {
    make_registry();
  }
  return _registry;
}
