// Filename: graphicsStateGuardian.I
// Created by:  drose (24Sep99)
//
////////////////////////////////////////////////////////////////////
//
// 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 <notify.h>

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::StateInfo::Constructor
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
INLINE GraphicsStateGuardian::StateInfo::
StateInfo(TypeHandle type) :
  _type(type)
{
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::StateInfo::Constructor
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
INLINE GraphicsStateGuardian::StateInfo::
StateInfo(const NodeTransitions::value_type &value) :
  _type(value.first), _trans(value.second)
{
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::StateInfo::Constructor
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
INLINE GraphicsStateGuardian::StateInfo::
StateInfo(const NodeTransitionCache::value_type &value) :
  _type(value.first), _trans(value.second)
{
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::StateInfo::Ordering operator
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
INLINE bool GraphicsStateGuardian::StateInfo::
operator < (const StateInfo &other) const {
  return _type < other._type;
}


////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::set_render_traverser
//       Access: Published
//  Description: Sets the traverser that will be used to render the
//               scene graph.  If this is unset, nothing will be
//               rendered.
////////////////////////////////////////////////////////////////////
INLINE void GraphicsStateGuardian::
set_render_traverser(RenderTraverser *rt) {
  _render_traverser = rt;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::get_render_traverser
//       Access: Published
//  Description: Returns the traverser that will be used to render the
//               scene graph.
////////////////////////////////////////////////////////////////////
INLINE RenderTraverser *GraphicsStateGuardian::
get_render_traverser() const {
  return _render_traverser;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::is_closed
//       Access: Public
//  Description: Returns true if the window associated with this GSG
//               has been closed, and hence the resources associated
//               with this GSG have been freed.
////////////////////////////////////////////////////////////////////
INLINE bool GraphicsStateGuardian::
is_closed() const {
  return (_win == (GraphicsWindow *)NULL);
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::set_state
//       Access: Public
//  Description: Applies the transitions indicated in the state set to
//               the current state, and issues the changes to the
//               graphics hardware.
//
//               The state is taken to be a complete description of
//               what the graphics state should be; any transitions
//               not mentioned in new_state are implicitly reset to
//               their initial values.
////////////////////////////////////////////////////////////////////
INLINE void GraphicsStateGuardian::
set_state(const AllTransitionsWrapper &new_state) {
  set_state(new_state.get_transitions());
}

/*
////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::get_state
//       Access: Public
//  Description: Returns the current state of the GSG.  This state may
//               be saved and used to restore the GSG to its current
//               state later.
////////////////////////////////////////////////////////////////////
INLINE const NodeTransitionCache *GraphicsStateGuardian::
get_state() const {
  return _state;
}
*/

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::get_current_projection_node
//       Access: Public
//  Description: Returns the node currently being used as the
//               projection node (i.e. the camera) for this scene, as
//               set by the last call to render_subgraph().
////////////////////////////////////////////////////////////////////
INLINE ProjectionNode *GraphicsStateGuardian::
get_current_projection_node(void) const {
  return _current_projection_node;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::get_current_root_node
//       Access: Public
//  Description: Returns the root node of the entire scene graph (not
//               the current subgraph) currently being rendered, as
//               set by the last call to render_scene().
////////////////////////////////////////////////////////////////////
INLINE const Node *GraphicsStateGuardian::
get_current_root_node(void) const {
  return _current_root_node;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::get_current_display_region
//       Access: Public
//  Description: Returns the current display region being rendered to,
//               as set by the last call to push_display_region() (or
//               restored by pop_display_region()).  This display
//               region will be made active (if it is not already) by
//               a call to prepare_display_region().
////////////////////////////////////////////////////////////////////
INLINE const DisplayRegion *GraphicsStateGuardian::
get_current_display_region(void) const {
  return _current_display_region;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::push_display_region
//       Access: Public
//  Description: Saves the current display region information and sets
//               up a new display region for rendering.  The return
//               value from this function must eventually be passed to
//               a matching pop_display_region() call.
//
//               The new display region will not actually be made
//               active for rendering until the next call to
//               prepare_display_region().  This is a state-changing
//               optimization.
////////////////////////////////////////////////////////////////////
INLINE DisplayRegionStack GraphicsStateGuardian::
push_display_region(const DisplayRegion *dr) {
  DisplayRegionStack old;
  old._display_region = _current_display_region;
  old._stack_level = _display_region_stack_level;
  _display_region_stack_level++;
  _current_display_region = dr;
  return old;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::pop_display_region
//       Access: Public
//  Description: Restores the display region previously in effect,
//               before the matching call to push_display_region().
//
//               The newly-restored display region will not actually
//               be made active for rendering until the next call to
//               prepare_display_region().  This is a state-changing
//               optimization.
////////////////////////////////////////////////////////////////////
INLINE void GraphicsStateGuardian::
pop_display_region(DisplayRegionStack &node) {
  nassertv(_display_region_stack_level > 0);
  _display_region_stack_level--;
  nassertv(node._stack_level == _display_region_stack_level);
  _current_display_region = node._display_region;
  node._stack_level = -1;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::push_frame_buffer
//       Access: Public
//  Description: Saves the contents of the frame buffer (within the
//               indicated display region only) so that rendering may
//               be performed (for instance, to render a partial in a
//               multipass algorithm) and the frame buffer later
//               restored via a matching call to pop_frame_buffer().
////////////////////////////////////////////////////////////////////
INLINE FrameBufferStack GraphicsStateGuardian::
push_frame_buffer(const RenderBuffer &buffer,
                  const DisplayRegion *dr) {
  FrameBufferStack old;
  old._frame_buffer = save_frame_buffer(buffer, dr);
  old._stack_level = _frame_buffer_stack_level;
  _frame_buffer_stack_level++;
  return old;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::pop_frame_buffer
//       Access: Public
//  Description: Restores the contents of the frame buffer as saved by
//               a previous call to push_frame_buffer().
////////////////////////////////////////////////////////////////////
INLINE void GraphicsStateGuardian::
pop_frame_buffer(FrameBufferStack &node) {
  nassertv(_frame_buffer_stack_level > 0);
  _frame_buffer_stack_level--;
  nassertv(node._stack_level == _frame_buffer_stack_level);
  restore_frame_buffer(node._frame_buffer);
  node._stack_level = -1;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::set_coordinate_system
//       Access: Public
//  Description: Changes the coordinate system in effect on this
//               particular gsg.  Normally, this will be the default
//               coordinate system, but it might be set differently at
//               runtime.
////////////////////////////////////////////////////////////////////
INLINE void GraphicsStateGuardian::
set_coordinate_system(CoordinateSystem cs) {
  _coordinate_system = cs;
}

////////////////////////////////////////////////////////////////////
//     Function: GraphicsStateGuardian::get_coordinate_system
//       Access: Public
//  Description: Returns the coordinate system in effect on this
//               particular gsg.  Normally, this will be the default
//               coordinate system, but it might be set differently at
//               runtime.
////////////////////////////////////////////////////////////////////
INLINE CoordinateSystem GraphicsStateGuardian::
get_coordinate_system() const {
  return _coordinate_system;
}

////////////////////////////////////////////////////////////////////
//     Function: get_attribute_into
//  Description: This external template function is handy for
//               extracting a transition of a particular type from the
//               gsg's state.  It works like get_transition_into().
////////////////////////////////////////////////////////////////////
template<class Transition>
INLINE bool
get_attribute_into(Transition *&ptr, const GraphicsStateGuardian *gsg) {
  NodeTransition *nt = gsg->get_attribute(Transition::get_class_type());
  if (nt == (NodeTransition *)NULL) {
    ptr = (Transition *)NULL;
    return false;
  }
  DCAST_INTO_R(ptr, nt, false);
  return true;
}
