// Filename: geomVertexColumn.I
// Created by:  drose (06Mar05)
//
////////////////////////////////////////////////////////////////////
//
// 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: GeomVertexColumn::Default Constructor
//       Access: Private
//  Description: Creates an invalid column.  Used on when constructing
//               from a bam file.
////////////////////////////////////////////////////////////////////
INLINE GeomVertexColumn::
GeomVertexColumn() :
  _packer(NULL)
{
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Constructor
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
INLINE GeomVertexColumn::
GeomVertexColumn(InternalName *name, int num_components,
                 NumericType numeric_type, Contents contents,
                 int start) :
  _name(name),
  _num_components(num_components),
  _numeric_type(numeric_type),
  _contents(contents),
  _start(start),
  _packer(NULL)
{
  setup();
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Copy Constructor
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
INLINE GeomVertexColumn::
GeomVertexColumn(const GeomVertexColumn &copy) :
  _name(copy._name),
  _num_components(copy._num_components),
  _numeric_type(copy._numeric_type),
  _contents(copy._contents),
  _start(copy._start),
  _packer(NULL)
{
  setup();
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Destructor
//       Access: Published
//  Description: 
////////////////////////////////////////////////////////////////////
INLINE GeomVertexColumn::
~GeomVertexColumn() {
  delete _packer;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::get_name
//       Access: Published
//  Description: Returns the name of this particular data field,
//               e.g. "vertex" or "normal".  The name may be a
//               user-defined string, or it may be one of the standard
//               system-defined field types.  Only the system-defined
//               field types are used for the actual rendering.
////////////////////////////////////////////////////////////////////
INLINE InternalName *GeomVertexColumn::
get_name() const {
  return _name;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::get_num_components
//       Access: Published
//  Description: Returns the number of components of the column:
//               the number of instances of the NumericType in each
//               element.  This is usually, but not always, the same
//               thing as get_num_values().
////////////////////////////////////////////////////////////////////
INLINE int GeomVertexColumn::
get_num_components() const {
  return _num_components;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::get_num_values
//       Access: Published
//  Description: Returns the number of numeric values of the column:
//               the number of distinct numeric values that go into
//               each element.  This is usually, but not always, the
//               same thing as get_num_components(); the difference is
//               in the case of a composite numeric type like
//               NT_packed_dcba, which has four numeric values per
//               component.
////////////////////////////////////////////////////////////////////
INLINE int GeomVertexColumn::
get_num_values() const {
  return _num_values;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::get_numeric_type
//       Access: Published
//  Description: Returns the token representing the numeric type of
//               the data storage.
////////////////////////////////////////////////////////////////////
INLINE GeomVertexColumn::NumericType GeomVertexColumn::
get_numeric_type() const {
  return _numeric_type;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::get_contents
//       Access: Published
//  Description: Returns the token representing the semantic meaning of
//               the stored value.
////////////////////////////////////////////////////////////////////
INLINE GeomVertexColumn::Contents GeomVertexColumn::
get_contents() const {
  return _contents;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::get_start
//       Access: Published
//  Description: Returns the byte within the array record at which
//               this column starts.  This can be set to non-zero
//               to implement interleaved arrays.
////////////////////////////////////////////////////////////////////
INLINE int GeomVertexColumn::
get_start() const {
  return _start;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::get_component_bytes
//       Access: Published
//  Description: Returns the number of bytes used by each component
//               (that is, by one element of the numeric type).
////////////////////////////////////////////////////////////////////
INLINE int GeomVertexColumn::
get_component_bytes() const {
  return _component_bytes;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::get_total_bytes
//       Access: Published
//  Description: Returns the number of bytes used by each element of
//               the column: component_bytes * num_components.
////////////////////////////////////////////////////////////////////
INLINE int GeomVertexColumn::
get_total_bytes() const {
  return _total_bytes;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::has_homogeneous_coord
//       Access: Published
//  Description: Returns true if this Contents type is one that
//               includes a homogeneous coordinate in the fourth
//               component, or false otherwise.  If this is true,
//               correct operation on the vertex data may require
//               scaling by the homogeneous coordinate from time to
//               time (but in general this is handled automatically if
//               you use the 3-component or smaller forms of
//               get_data() and set_data()).
////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexColumn::
has_homogeneous_coord() const {
  switch (_contents) {
  case C_point:
  case C_texcoord:
    return true;

  default:
    return false;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::overlaps_with
//       Access: Published
//  Description: Returns true if this column overlaps with any of
//               the bytes in the indicated range, false if it does
//               not.
////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexColumn::
overlaps_with(int start_byte, int num_bytes) const {
  return (_start < start_byte + num_bytes &&
          _start + _total_bytes > start_byte);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::is_bytewise_equivalent
//       Access: Published
//  Description: Returns true if the data store of this column is
//               exactly the same as that of the other, irrespective
//               of name or start position within the record.
////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexColumn::
is_bytewise_equivalent(const GeomVertexColumn &other) const {
  // Not sure if the contents are relevant, but let's say that they
  // are.
  return (_num_components == other._num_components &&
          _numeric_type == other._numeric_type &&
          _contents == other._contents);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::is_packed_argb
//       Access: Public
//  Description: Returns true if this column is the standard
//               DirectX representation of 4-component color: C_color,
//               in NT_packed_dabc, with 1 component (4 values).
////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexColumn::
is_packed_argb() const {
  return (_num_components == 1 &&
          _numeric_type == NT_packed_dabc &&
          _contents == C_color);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::is_uint8_rgba
//       Access: Public
//  Description: Returns true if this column is the standard
//               OpenGL representation of 4-component color: C_color,
//               in NT_uint8, with 4 components.
////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexColumn::
is_uint8_rgba() const {
  return (_num_components == 4 &&
          _numeric_type == NT_uint8 &&
          _contents == C_color);
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::compare_to
//       Access: Public
//  Description: This is used to unquify columns, and hence
//               formats, for the GeomVertexFormat registry.
////////////////////////////////////////////////////////////////////
INLINE int GeomVertexColumn::
compare_to(const GeomVertexColumn &other) const {
  if (_name != other._name) {
    return _name < other._name ? -1 : 1;
  }
  if (_num_components != other._num_components) {
    return _num_components - other._num_components;
  }
  if (_numeric_type != other._numeric_type) {
    return (int)_numeric_type - (int)other._numeric_type;
  }
  if (_contents != other._contents) {
    return (int)_contents - (int)other._contents;
  }
  if (_start != other._start) {
    return _start - other._start;
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::operator ==
//       Access: Public
//  Description: Returns true if the two columns are exactly
//               equivalent, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexColumn::
operator == (const GeomVertexColumn &other) const {
  return compare_to(other) == 0;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::operator !=
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexColumn::
operator != (const GeomVertexColumn &other) const {
  return compare_to(other) != 0;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::operator <
//       Access: Public
//  Description: This is used to put columns in order within a
//               particular GeomVertexArrayFormat.  Note that it is
//               *not* in the same space as operator == and operator
//               !=.
////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexColumn::
operator < (const GeomVertexColumn &other) const {
  if (_start != other._start) { 
    return _start < other._start;
  }
  if (_total_bytes < other._total_bytes) {
    return _total_bytes < other._total_bytes;
  }
  return 0;
}

INLINE ostream &
operator << (ostream &out, const GeomVertexColumn &obj) {
  obj.output(out);
  return out;
}

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Packer::maybe_scale_color
//       Access: Public
//  Description: Converts an integer (typically a uint8) value to a
//               floating-point value.  If the contents value
//               indicates this is a color value, scales it into the
//               range 0..1 per convention; otherwise leaves it alone.
////////////////////////////////////////////////////////////////////
INLINE float GeomVertexColumn::Packer::
maybe_scale_color(unsigned int value) {
  if (_column->get_contents() == C_color) {
    return (float)value / 255.0f;
  } else {
    return (float)value;
  }
}
    
////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Packer::maybe_scale_color
//       Access: Public
//  Description: Converts a pair of integers into the _v2 member.  See
//               one-parameter maybe_scale_color() for more info.
////////////////////////////////////////////////////////////////////
INLINE void GeomVertexColumn::Packer::
maybe_scale_color(unsigned int a, unsigned int b) {
  if (_column->get_contents() == C_color) {
    _v2.set((float)a / 255.0f,
            (float)b / 255.0f);
  } else {    
    _v2.set((float)a, (float)b);
  }
}
    
////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Packer::maybe_scale_color
//       Access: Public
//  Description: Converts a pair of integers into the _v3 member.  See
//               one-parameter maybe_scale_color() for more info.
////////////////////////////////////////////////////////////////////
INLINE void GeomVertexColumn::Packer::
maybe_scale_color(unsigned int a, unsigned int b, unsigned int c) {
  if (_column->get_contents() == C_color) {
    _v3.set((float)a / 255.0f,
            (float)b / 255.0f,
            (float)c / 255.0f);
  } else {    
    _v3.set((float)a, (float)b, (float)c);
  }
}
    
////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Packer::maybe_scale_color
//       Access: Public
//  Description: Converts a pair of integers into the _v4 member.  See
//               one-parameter maybe_scale_color() for more info.
////////////////////////////////////////////////////////////////////
INLINE void GeomVertexColumn::Packer::
maybe_scale_color(unsigned int a, unsigned int b, unsigned int c,
                  unsigned int d) {
  if (_column->get_contents() == C_color) {
    _v4.set((float)a / 255.0f,
            (float)b / 255.0f,
            (float)c / 255.0f,
            (float)d / 255.0f);
  } else {
    _v4.set((float)a, (float)b, (float)c, (float)d);
  }
}
    

////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Packer::maybe_unscale_color
//       Access: Public
//  Description: Converts a floating-point value to a uint8 value.  If
//               the contents value indicates this is a color value,
//               scales it into the range 0..255 per convention;
//               otherwise leaves it alone.
////////////////////////////////////////////////////////////////////
INLINE unsigned int GeomVertexColumn::Packer::
maybe_unscale_color(float data) {
  if (_column->get_contents() == C_color) {
    return (unsigned int)(data * 255.0f);
  } else {
    return (unsigned int)data;
  }
}
    
////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Packer::maybe_unscale_color
//       Access: Public
//  Description: Converts an LVecBase2f into a pair of uint8
//               values.  See one-parameter maybe_unscale_color() for
//               more info.
////////////////////////////////////////////////////////////////////
INLINE void GeomVertexColumn::Packer::
maybe_unscale_color(const LVecBase2f &data) {
  if (_column->get_contents() == C_color) {
    _a = (unsigned int)(data[0] * 255.0f);
    _b = (unsigned int)(data[1] * 255.0f);
  } else {
    _a = (unsigned int)data[0];
    _b = (unsigned int)data[1];
  }
}
    
////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Packer::maybe_unscale_color
//       Access: Public
//  Description: Converts an LVecBase3f into a pair of uint8
//               values.  See one-parameter maybe_unscale_color() for
//               more info.
////////////////////////////////////////////////////////////////////
INLINE void GeomVertexColumn::Packer::
maybe_unscale_color(const LVecBase3f &data) {
  if (_column->get_contents() == C_color) {
    _a = (unsigned int)(data[0] * 255.0f);
    _b = (unsigned int)(data[1] * 255.0f);
    _c = (unsigned int)(data[2] * 255.0f);
  } else {
    _a = (unsigned int)data[0];
    _b = (unsigned int)data[1];
    _c = (unsigned int)data[2];
  }
}
    
////////////////////////////////////////////////////////////////////
//     Function: GeomVertexColumn::Packer::maybe_unscale_color
//       Access: Public
//  Description: Converts an LVecBase4f into a pair of uint8
//               values.  See one-parameter maybe_unscale_color() for
//               more info.
////////////////////////////////////////////////////////////////////
INLINE void GeomVertexColumn::Packer::
maybe_unscale_color(const LVecBase4f &data) {
  if (_column->get_contents() == C_color) {
    _a = (unsigned int)(data[0] * 255.0f);
    _b = (unsigned int)(data[1] * 255.0f);
    _c = (unsigned int)(data[2] * 255.0f);
    _d = (unsigned int)(data[3] * 255.0f);
  } else {
    _a = (unsigned int)data[0];
    _b = (unsigned int)data[1];
    _c = (unsigned int)data[2];
    _d = (unsigned int)data[3];
  }
}
