Ver Fonte

integrate AviTexture better with Panda, rename to OpenCVTexture

David Rose há 20 anos atrás
pai
commit
a7b1f14e80
100 ficheiros alterados com 2577 adições e 1688 exclusões
  1. 1 1
      panda/metalibs/panda/Sources.pp
  2. 0 86
      panda/src/chan/animControl.I
  3. 13 671
      panda/src/chan/animControl.cxx
  4. 9 99
      panda/src/chan/animControl.h
  5. 2 56
      panda/src/chan/animControlCollection.I
  6. 0 6
      panda/src/chan/animControlCollection.h
  7. 0 15
      panda/src/chan/partBundle.cxx
  8. 0 1
      panda/src/chan/partBundle.h
  9. 2 6
      panda/src/char/character.cxx
  10. 1 1
      panda/src/downloader/Sources.pp
  11. 2 2
      panda/src/downloader/bioPtr.cxx
  12. 2 2
      panda/src/downloader/bioPtr.h
  13. 2 2
      panda/src/downloader/bioStream.cxx
  14. 2 2
      panda/src/downloader/bioStream.h
  15. 2 2
      panda/src/downloader/bioStreamBuf.cxx
  16. 2 2
      panda/src/downloader/bioStreamBuf.h
  17. 2 2
      panda/src/downloader/bioStreamPtr.cxx
  18. 2 2
      panda/src/downloader/bioStreamPtr.h
  19. 2 2
      panda/src/downloader/chunkedStream.cxx
  20. 2 2
      panda/src/downloader/chunkedStream.h
  21. 2 2
      panda/src/downloader/chunkedStreamBuf.cxx
  22. 2 2
      panda/src/downloader/chunkedStreamBuf.h
  23. 2 2
      panda/src/downloader/config_downloader.cxx
  24. 2 2
      panda/src/downloader/httpAuthorization.cxx
  25. 2 2
      panda/src/downloader/httpAuthorization.h
  26. 2 2
      panda/src/downloader/httpBasicAuthorization.cxx
  27. 2 2
      panda/src/downloader/httpBasicAuthorization.h
  28. 2 2
      panda/src/downloader/httpChannel.cxx
  29. 2 2
      panda/src/downloader/httpChannel.h
  30. 2 2
      panda/src/downloader/httpClient.cxx
  31. 2 2
      panda/src/downloader/httpClient.h
  32. 2 2
      panda/src/downloader/httpCookie.cxx
  33. 2 2
      panda/src/downloader/httpCookie.h
  34. 2 2
      panda/src/downloader/httpDigestAuthorization.cxx
  35. 2 2
      panda/src/downloader/httpDigestAuthorization.h
  36. 2 2
      panda/src/downloader/httpEnum.cxx
  37. 2 2
      panda/src/downloader/httpEnum.h
  38. 2 2
      panda/src/downloader/identityStream.cxx
  39. 2 2
      panda/src/downloader/identityStream.h
  40. 2 2
      panda/src/downloader/identityStreamBuf.cxx
  41. 2 2
      panda/src/downloader/identityStreamBuf.h
  42. 2 2
      panda/src/downloader/patcher.cxx
  43. 2 2
      panda/src/downloader/patcher.h
  44. 2 2
      panda/src/downloader/socketStream.cxx
  45. 2 2
      panda/src/downloader/socketStream.h
  46. 2 2
      panda/src/downloader/ssl_utils.cxx
  47. 2 2
      panda/src/downloader/ssl_utils.h
  48. 9 9
      panda/src/downloadertools/Sources.pp
  49. 1 1
      panda/src/express/Sources.pp
  50. 2 2
      panda/src/express/encryptStream.cxx
  51. 2 2
      panda/src/express/encryptStream.h
  52. 2 2
      panda/src/express/encryptStreamBuf.cxx
  53. 2 2
      panda/src/express/encryptStreamBuf.h
  54. 2 2
      panda/src/express/hashVal.I
  55. 4 4
      panda/src/express/hashVal.cxx
  56. 2 2
      panda/src/express/hashVal.h
  57. 2 2
      panda/src/express/multifile.I
  58. 6 6
      panda/src/express/multifile.cxx
  59. 2 2
      panda/src/express/password_hash.cxx
  60. 2 2
      panda/src/express/password_hash.h
  61. 2 2
      panda/src/express/patchfile.cxx
  62. 2 2
      panda/src/express/patchfile.h
  63. 3 0
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  64. 6 3
      panda/src/gobj/Sources.pp
  65. 2 8
      panda/src/gobj/config_gobj.cxx
  66. 0 1
      panda/src/gobj/config_gobj.h
  67. 1 0
      panda/src/gobj/gobj_composite2.cxx
  68. 1 1
      panda/src/gobj/shader.cxx
  69. 20 55
      panda/src/gobj/texture.I
  70. 280 89
      panda/src/gobj/texture.cxx
  71. 27 10
      panda/src/gobj/texture.h
  72. 1 0
      panda/src/gobj/textureContext.I
  73. 13 25
      panda/src/gobj/texturePool.I
  74. 78 19
      panda/src/gobj/texturePool.cxx
  75. 12 3
      panda/src/gobj/texturePool.h
  76. 149 0
      panda/src/gobj/videoTexture.I
  77. 152 0
      panda/src/gobj/videoTexture.cxx
  78. 93 0
      panda/src/gobj/videoTexture.h
  79. 4 4
      panda/src/grutil/Sources.pp
  80. 0 134
      panda/src/grutil/aviTexture.I
  81. 0 163
      panda/src/grutil/aviTexture.cxx
  82. 0 94
      panda/src/grutil/aviTexture.h
  83. 11 4
      panda/src/grutil/config_grutil.cxx
  84. 1 1
      panda/src/grutil/grutil_composite1.cxx
  85. 70 0
      panda/src/grutil/openCVTexture.I
  86. 526 0
      panda/src/grutil/openCVTexture.cxx
  87. 125 0
      panda/src/grutil/openCVTexture.h
  88. 22 3
      panda/src/pgraph/cullTraverser.cxx
  89. 32 0
      panda/src/pgraph/renderAttrib.cxx
  90. 5 0
      panda/src/pgraph/renderAttrib.h
  91. 17 0
      panda/src/pgraph/renderState.I
  92. 39 0
      panda/src/pgraph/renderState.cxx
  93. 19 13
      panda/src/pgraph/renderState.h
  94. 48 0
      panda/src/pgraph/textureAttrib.cxx
  95. 3 0
      panda/src/pgraph/textureAttrib.h
  96. 3 0
      panda/src/putil/Sources.pp
  97. 178 0
      panda/src/putil/animInterface.I
  98. 379 0
      panda/src/putil/animInterface.cxx
  99. 111 0
      panda/src/putil/animInterface.h
  100. 2 0
      panda/src/putil/config_util.cxx

+ 1 - 1
panda/metalibs/panda/Sources.pp

@@ -6,7 +6,7 @@
 
 #define DIR_TYPE metalib
 #define BUILDING_DLL BUILDING_PANDA
-#define USE_PACKAGES net cv
+#define USE_PACKAGES net
 
 #define COMPONENT_LIBS \
     recorder pgraph \

+ 0 - 86
panda/src/chan/animControl.I

@@ -16,92 +16,6 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include <math.h>
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::set_play_rate
-//       Access: Published
-//  Description: Sets the speed of the animation, relative to its
-//               "normal" speed.  Setting this number to 2.0 plays it
-//               twice as fast, 0.5 half as fast.  -1.0 plays it
-//               backwards, and 0.0 stops it.  The change is actually
-//               retroactive to the last frame.
-//
-//               If you are going to change the play_rate from a
-//               positive number to a negative number, or vice-versa,
-//               you should do this before starting the animation.
-//               The various flavors of play() and loop() do slightly
-//               different behavior based on whether play_rate is
-//               positive or negative.
-////////////////////////////////////////////////////////////////////
-INLINE void AnimControl::
-set_play_rate(double play_rate) {
-  _play_rate = play_rate;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::get_play_rate
-//       Access: Published
-//  Description: Returns the current speed of the animation.  See
-//               set_play_rate().
-////////////////////////////////////////////////////////////////////
-INLINE double AnimControl::
-get_play_rate() const {
-  return _play_rate;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::get_frame_rate
-//       Access: Published
-//  Description: Returns the actual frame rate of the animation, based
-//               on the play_rate (see set_play_rate()) and the
-//               animation's base frame rate (see
-//               AnimBundle::get_base_frame_rate()).  This is in
-//               frames per second.
-////////////////////////////////////////////////////////////////////
-INLINE double AnimControl::
-get_frame_rate() const {
-  return get_play_rate() * get_anim()->get_base_frame_rate();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::get_frame
-//       Access: Published
-//  Description: Returns the current frame number of the animation.
-////////////////////////////////////////////////////////////////////
-INLINE int AnimControl::
-get_frame() const {
-  // We have to use floor() here instead of simply casting the number
-  // to an integer, becase the frame number might have become
-  // negative.
-  return (int)cfloor(_frame + 0.0001);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::get_num_frames
-//       Access: Published
-//  Description: Returns the number of frames of animation.  This is
-//               actually just extracted directly from the AnimBundle;
-//               the function is duplicated here for convenience.  The
-//               frame number will never be outside the range 0 <=
-//               frame < get_num_frames().
-////////////////////////////////////////////////////////////////////
-INLINE int AnimControl::
-get_num_frames() const {
-  return get_anim()->get_num_frames();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::is_playing
-//       Access: Published
-//  Description: Returns true if the AnimControl is currently playing,
-//               false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool AnimControl::
-is_playing() const {
-  return _playing;
-}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimControl::get_anim

+ 13 - 671
panda/src/chan/animControl.cxx

@@ -16,16 +16,11 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
 #include "animControl.h"
 #include "animChannelBase.h"
 #include "partBundle.h"
 #include "config_chan.h"
 
-#include "event.h"
-#include "throw_event.h"
-
-
 TypeHandle AnimControl::_type_handle;
 
 ////////////////////////////////////////////////////////////////////
@@ -42,18 +37,15 @@ AnimControl(PartBundle *part, AnimBundle *anim, int channel_index) {
   _part = part;
   _anim = anim;
   _channel_index = channel_index;
-
-  _play_rate = 1.0f;
-  _frame = 0.0f;
-  _as_of_time = 0.0f;
-  _playing = false;
+  set_frame_rate(_anim->get_base_frame_rate());
+  set_num_frames(_anim->get_num_frames());
 
   _marked_frame = -1;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimControl::Destructor
-//       Access: Published
+//       Access: Published, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
 AnimControl::
@@ -61,296 +53,6 @@ AnimControl::
   get_part()->set_control_effect(this, 0.0f);
 }
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::play
-//       Access: Published
-//  Description: Runs the entire animation from beginning to end and
-//               stops, throwing the stop event (if it is non-NULL).
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-play(const CPT_Event &stop_event) {
-  nassertv(get_num_frames() > 0);
-
-  if (get_play_rate() < 0.0f) {
-    play(get_num_frames()-1, 0, stop_event);
-  } else {
-    play(0, get_num_frames()-1, stop_event);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::play
-//       Access: Published
-//  Description: Runs the animation from the frame "from" to and
-//               including the frame "to", at which point the
-//               animation is stopped and the indicated stop event is
-//               thrown (if it is non-NULL).  If the to frame is less
-//               than the from frame (unless play_rate is negative),
-//               the animation will wrap around the end and begins
-//               again at the beginning before the animation stops.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-play(int from, int to, const CPT_Event &stop_event) {
-  nassertv(get_num_frames() > 0);
-
-  nassertv(from >= 0 && from < get_num_frames());
-  nassertv(to >= 0 && to < get_num_frames());
-  _as_of_time = ClockObject::get_global_clock()->get_frame_time();
-  _playing = true;
-
-  _actions = _user_actions;
-  if (stop_event != (Event*)0L) {
-    insert_event_action(_actions, to, stop_event);
-  }
-  insert_stop_action(_actions, to);
-
-  get_part()->control_activated(this);
-  set_frame(from);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::loop
-//       Access: Published
-//  Description: Starts the entire animation looping.  If restart is
-//               true, the animation is restarted from the beginning;
-//               otherwise, it continues from the current frame.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-loop(bool restart) {
-  nassertv(get_num_frames() > 0);
-
-  _as_of_time = ClockObject::get_global_clock()->get_frame_time();
-  _playing = true;
-
-  _actions = _user_actions;
-  get_part()->control_activated(this);
-
-  if (restart) {
-    if (get_play_rate() < 0.0f) {
-      set_frame(get_num_frames() - 1);
-    } else {
-      set_frame(0);
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::loop
-//       Access: Published
-//  Description: Loops the animation from the frame "from" to and
-//               including the frame "to", indefinitely.  If restart
-//               is true, the animation is restarted from the
-//               beginning; otherwise, it continues from the current
-//               frame.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-loop(bool restart, int from, int to) {
-  nassertv(get_num_frames() > 0);
-
-  nassertv(from >= 0 && from < get_num_frames());
-  nassertv(to >= 0 && to < get_num_frames());
-  _as_of_time = ClockObject::get_global_clock()->get_frame_time();
-  _playing = true;
-
-  _actions = _user_actions;
-
-  if (get_play_rate() < 0.0f) {
-    // If we're playing backward, we need to set up the loop a little
-    // differently.
-
-    if ((to == 0 && from == get_num_frames()-1) ||
-        (to == from-1)) {
-
-      // In this case, the user has specified to loop over the whole
-      // range of animation.  We don't need a special jump action to
-      // handle this.
-
-    } else {
-      // Otherwise, set up a jump action to effect the loop.  This isn't
-      // completely accurate, since it will always jump exactly to the
-      // first frame of the loop, no matter how many frames past the end
-      // we'd gotten to, but it should be reasonably close, especially
-      // if the number of frames in the loop is large enough and/or the
-      // frame rate is high enough.
-      insert_jump_action(_actions, (to-1+get_num_frames())%get_num_frames(),
-                         from);
-    }
-  } else {
-
-    if ((from == 0 && to == get_num_frames()-1) ||
-        (from == to-1)) {
-
-      // In this case, the user has specified to loop over the whole
-      // range of animation.  We don't need a special jump action to
-      // handle this.
-
-    } else {
-      // Otherwise, set up a jump action to effect the loop.  This isn't
-      // completely accurate, since it will always jump exactly to the
-      // first frame of the loop, no matter how many frames past the end
-      // we'd gotten to, but it should be reasonably close, especially
-      // if the number of frames in the loop is large enough and/or the
-      // frame rate is high enough.
-      insert_jump_action(_actions, (to+1)%get_num_frames(), from);
-    }
-  }
-
-  get_part()->control_activated(this);
-  if (restart) {
-    set_frame(from);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::pingpong
-//       Access: Published
-//  Description: Loops the animation from the frame "from" to and
-//               including the frame "to", and then back in the
-//               opposite direction, indefinitely.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-pingpong(bool restart, int from, int to) {
-  if (from == to) {
-    pose(from);
-    return;
-  }
-
-  nassertv(get_num_frames() > 0);
-
-  nassertv(from >= 0 && from < get_num_frames());
-  nassertv(to >= 0 && to < get_num_frames());
-  _as_of_time = ClockObject::get_global_clock()->get_frame_time();
-  _playing = true;
-
-  _actions = _user_actions;
-
-  insert_forward_action(_actions, from);
-  insert_backward_action(_actions, to);
-
-  get_part()->control_activated(this);
-  if (restart) {
-    set_frame(from);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::stop
-//       Access: Published
-//  Description: Stops a currently playing or looping animation right
-//               where it is.  The animation remains posed at the
-//               current frame, and no event is thrown.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-stop() {
-  _playing = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::pose
-//       Access: Published
-//  Description: Sets the animation to the indicated frame and holds
-//               it there.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-pose(int frame) {
-  int num_frames = get_num_frames();
-  nassertv(num_frames > 0);
-
-  // Modulo the number of frames.
-  frame = (int)(frame - cfloor(frame / num_frames) * num_frames);
-  nassertv(frame >= 0 && frame < num_frames);
-  _as_of_time = ClockObject::get_global_clock()->get_frame_time();
-  _playing = false;
-
-  _actions = _user_actions;
-
-  get_part()->control_activated(this);
-  set_frame(frame);
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::add_event
-//       Access: Published
-//  Description: Adds the indicated event to the list of events that
-//               will be called whenever the animation reaches the
-//               indicated frame number.  Once added, the event will
-//               persist until it is removed via remove_event() or
-//               remove_all_events().
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-add_event(int frame, const CPT_Event &event) {
-  insert_event_action(_user_actions, frame, event);
-  if (_playing) {
-    insert_event_action(_actions, frame, event);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::remove_event
-//       Access: Published
-//  Description: Removes all events found that match the indicated
-//               event name, and returns the number of events
-//               removed.
-////////////////////////////////////////////////////////////////////
-int AnimControl::
-remove_event(const string &event_name) {
-  Actions new_actions;
-
-  int removed = 0;
-
-  Actions::const_iterator ai;
-  for (ai = _user_actions.begin(); ai != _user_actions.end(); ++ai) {
-    const Action &action = (*ai).second;
-    if (action._type == AT_event &&
-        action._event->get_name() == event_name) {
-      // Remove this event by not copying it to new_actions.
-      removed++;
-    } else {
-      // Preserve this event.
-      new_actions.insert(*ai);
-    }
-  }
-
-  if (removed != 0) {
-    _user_actions.swap(new_actions);
-
-    if (_playing) {
-      new_actions.clear();
-      int p_removed = 0;
-      for (ai = _actions.begin(); ai != _actions.end(); ++ai) {
-        const Action &action = (*ai).second;
-        if (action._type == AT_event &&
-            action._event->get_name() == event_name) {
-          // Remove this event by not copying it to new_actions.
-          p_removed++;
-        } else {
-          // Preserve this event.
-          new_actions.insert(*ai);
-        }
-      }
-      nassertr(p_removed == removed, removed);
-      _actions.swap(new_actions);
-    }
-  }
-
-  return removed;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::remove_all_events
-//       Access: Published
-//  Description: Removes all user-defined event messages.  However, if
-//               called while an animation is running, this will not
-//               take effect until the animation is stopped and
-//               restarted.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-remove_all_events() {
-  _user_actions.clear();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimControl::get_part
 //       Access: Published
@@ -370,77 +72,11 @@ get_part() const {
 void AnimControl::
 output(ostream &out) const {
   out << "AnimControl(" << get_part()->get_name()
-      << ", " << get_anim()->get_name() << ")";
+      << ", " << get_anim()->get_name() << ": ";
+  AnimInterface::output(out);
+  out << ")";
 }
 
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::advance_time
-//       Access: Public
-//  Description: Tells the AnimControl what time it is.  This
-//               recomputes the frame number according to the amount
-//               of time elapsed since last time.  Until this function
-//               is called, the frame number will not increment.  The
-//               time passed to this function must be nondecreasing;
-//               it is an error to call it with a value less than a
-//               previously-passed value.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-advance_time(double time) {
-  double elapsed_time = time - _as_of_time;
-  double elapsed_frames = elapsed_time * get_frame_rate();
-  _as_of_time = time;
-
-  if (_playing && elapsed_frames != 0.0f) {
-    int orig_frame = get_frame();
-
-    _frame += elapsed_frames;
-    double num_frames = (double)get_num_frames();
-
-    int new_frame = get_frame();
-
-    // Now call all the actions.
-    if (elapsed_frames < 0.0f) {
-      // If we're playing the animation backward, we have to check the
-      // actions in reverse order.
-
-      if (new_frame >= 0) {
-        do_actions_backward(orig_frame-1, new_frame);
-      } else {
-        if (do_actions_backward(orig_frame-1, 0)) {
-          // floor() is correct here, instead of simply an integer
-          // cast, because we are using floating-point arithmetic
-          // anyway (no need to convert to integer format and back
-          // again), and because we need correct behavior when the
-          // frame number is negative.
-          _frame = _frame - cfloor(_frame / num_frames) * num_frames;
-          new_frame = get_frame();
-          do_actions_backward(get_num_frames(), new_frame);
-        }
-      }
-    } else {
-      // Normally, we'll be playing the animation forward.
-
-      if (new_frame < get_num_frames()) {
-        do_actions_forward(orig_frame+1, new_frame);
-      } else {
-        if (do_actions_forward(orig_frame+1, get_num_frames()-1)) {
-          // floor() is correct here, instead of simply an integer
-          // cast, because we are using floating-point arithmetic
-          // anyway (no need to convert to integer format and back
-          // again), and because we need correct behavior when the
-          // frame number is negative.
-          _frame = _frame - cfloor(_frame / num_frames) * num_frames;
-          new_frame = get_frame();
-          do_actions_forward(0, new_frame);
-        }
-      }
-    }
-  }
-}
-
-
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimControl::channel_has_changed
 //       Access: Public
@@ -457,7 +93,6 @@ channel_has_changed(AnimChannelBase *channel) const {
   return channel->has_changed(_marked_frame, this_frame);
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimControl::mark_channels
 //       Access: Public
@@ -469,307 +104,14 @@ mark_channels() {
   _marked_frame = get_frame();
 }
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::insert_event_action
-//       Access: Private, Static
-//  Description: Inserts an "event" action at the indicated frame
-//               number.  The event will be thrown as the animation
-//               reaches the indicated frame number.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-insert_event_action(Actions &actions, int frame, const CPT_Event &event) {
-  Action new_action;
-  new_action._type = AT_event;
-  new_action._event = event;
-  actions.insert(pair<int, Action>(frame, new_action));
-}
-
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::insert_stop_action
-//       Access: Private, Static
-//  Description: Inserts a "stop" action at the indicated frame
-//               number.  The animation will stop as soon as it
-//               reaches the indicated frame number, traveling from
-//               either direction.
+//     Function: AnimControl::animation_activated
+//       Access: Protected, Virtual
+//  Description: This is provided as a callback method for when the
+//               user calls one of the play/loop/pose type methods to
+//               start the animation playing.
 ////////////////////////////////////////////////////////////////////
 void AnimControl::
-insert_stop_action(Actions &actions, int frame) {
-  Action new_action;
-  new_action._type = AT_stop;
-  actions.insert(pair<int, Action>(frame, new_action));
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::insert_jump_action
-//       Access: Private, Static
-//  Description: Inserts a "jump" action at the indicated frame
-//               number.  When the animation reaches the indicated
-//               frame number, it will jump to the indicated jump_to
-//               frame.  It will not seem to spend any time at the
-//               reached frame number.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-insert_jump_action(Actions &actions, int frame, int jump_to) {
-  Action new_action;
-  new_action._type = AT_jump;
-  new_action._jump_to = jump_to;
-  actions.insert(pair<int, Action>(frame, new_action));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::insert_forward_action
-//       Access: Private, Static
-//  Description: Inserts a "forward" action at the indicated frame
-//               number.  When the animation hits this action while
-//               playing in a backward direction, it will stop and
-//               play in a forward direction instead.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-insert_forward_action(Actions &actions, int frame) {
-  Action new_action;
-  new_action._type = AT_forward;
-  actions.insert(pair<int, Action>(frame, new_action));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::insert_backward_action
-//       Access: Private, Static
-//  Description: Inserts a "backward" action at the indicated frame
-//               number.  When the animation hits this action while
-//               playing in a forward direction, it will stop and
-//               play in a backward direction instead.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-insert_backward_action(Actions &actions, int frame) {
-  Action new_action;
-  new_action._type = AT_backward;
-  actions.insert(pair<int, Action>(frame, new_action));
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::set_frame
-//       Access: Private
-//  Description: Sets the current frame number to the indicated frame,
-//               and performs any actions on that frame.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-set_frame(double frame) {
-  _frame = frame;
-  int iframe = get_frame();
-  do_actions_forward(iframe, iframe);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::do_actions_forward
-//       Access: Private
-//  Description: Calls each of the actions, in turn, on the timeline
-//               between the indicated "from" frame and the indicated
-//               "to" frame, inclusive.  If any of the actions
-//               specifies to stop the animation, the animation is
-//               stopped, the current frame number is set to the point
-//               of stopping, no further actions are called, and false
-//               is returned.  Otherwise, true is returned.
-////////////////////////////////////////////////////////////////////
-bool AnimControl::
-do_actions_forward(int from, int to) {
-  if (to >= from) {
-    Actions::const_iterator lower = _actions.lower_bound(from);
-    Actions::const_iterator upper = _actions.lower_bound(to+1);
-
-    int sequence_frame = -1;
-    const Action *sequence_action;
-
-    Actions::const_iterator ai;
-    for (ai = lower; ai != upper; ++ai) {
-      int frame = (*ai).first;
-      const Action &action = (*ai).second;
-
-      if (sequence_frame != -1 && frame > sequence_frame) {
-        // We encountered an action that resequenced our frame numbers.
-        // Now that we've finished evaluating all the other actions that
-        // occurred in the same frame, evaluate this one action and
-        // exit.
-        do_sequence_action(sequence_frame, *sequence_action);
-        return false;
-      }
-
-      do_action(frame, action, sequence_frame, sequence_action);
-    }
-
-    if (sequence_frame != -1) {
-      do_sequence_action(sequence_frame, *sequence_action);
-      return false;
-    }
-  }
-
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::do_actions_backward
-//       Access: Private
-//  Description: Calls each of the actions, in turn, on the timeline
-//               between the indicated "from" frame and the indicated
-//               "to" frame, in reverse order.  If any of the actions
-//               specifies to stop the animation, the animation is
-//               stopped, the current frame number is set to the point
-//               of stopping, no further actions are called, and false
-//               is returned.  Otherwise, true is returned.
-////////////////////////////////////////////////////////////////////
-bool AnimControl::
-do_actions_backward(int from, int to) {
-  if (from >= to) {
-#if defined(WIN32_VC) && !defined(NO_PCH)
-    typedef Actions::const_reverse_iterator Action_reverse_iterator;
-#else
-    typedef reverse_iterator<Actions::const_iterator> Action_reverse_iterator;
-#endif
-    Action_reverse_iterator lower(_actions.upper_bound(from));
-    Action_reverse_iterator upper(_actions.upper_bound(to-1));
-
-    int sequence_frame = -1;
-    const Action *sequence_action;
-
-    Action_reverse_iterator ai;
-    for (ai = lower; ai != upper; ++ai) {
-      int frame = (*ai).first;
-      const Action &action = (*ai).second;
-
-      if (sequence_frame != -1 && frame < sequence_frame) {
-        // We encountered an action that resequenced our frame numbers.
-        // Now that we've finished evaluating all the other actions that
-        // occurred in the same frame, evaluate this one action and
-        // exit.
-        do_sequence_action(sequence_frame, *sequence_action);
-        return false;
-      }
-
-      do_action(frame, action, sequence_frame, sequence_action);
-    }
-
-    if (sequence_frame != -1) {
-      do_sequence_action(sequence_frame, *sequence_action);
-      return false;
-    }
-  }
-
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::do_action
-//       Access: Private
-//  Description: Performs a single action.  If the action involves
-//               some resequencing behavior--stopping, or jumping
-//               around to a new frame or something--does nothing
-//               immediately, but instead sets sequence_frame and
-//               sequence_action to the current frame number and
-//               action, so they may be executed later (after all the
-//               other actions this frame have been executed).
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-do_action(int frame, const Action &action,
-          int &sequence_frame, const Action *&sequence_action) {
-  switch (action._type) {
-  case AT_stop:
-  case AT_jump:
-    sequence_frame = frame;
-    sequence_action = &action;
-    break;
-
-  case AT_forward:
-    // We only see "forward" actions if we're currently playing
-    // backwards.
-    if (_play_rate < 0.0f) {
-      sequence_frame = frame;
-      sequence_action = &action;
-    }
-    break;
-
-  case AT_backward:
-    // We only see "backward" actions if we're currently playing
-    // forwards.
-    if (_play_rate > 0.0f) {
-      sequence_frame = frame;
-      sequence_action = &action;
-    }
-    break;
-
-  case AT_event:
-    throw_event(action._event);
-    break;
-
-  default:
-    chan_cat.error() << "Invalid action!\n";
-    abort();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::do_sequence_action
-//       Access: Private
-//  Description: Performs an action that was saved from do_action(),
-//               above.  This action presumably does some mucking
-//               around with the frame number or something, so we
-//               needed to do all the other actions associated with
-//               that frame first.
-////////////////////////////////////////////////////////////////////
-void AnimControl::
-do_sequence_action(int frame, const Action &action) {
-  switch (action._type) {
-  case AT_stop:
-    stop();
-    break;
-
-  case AT_jump:
-    set_frame(action._jump_to);
-    break;
-
-  case AT_forward:
-  case AT_backward:
-    _play_rate = -_play_rate;
-    set_frame(frame);
-    break;
-
-  case AT_event:
-  default:
-    chan_cat.error() << "Invalid sequence action!\n";
-    abort();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControl::Action::output
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void AnimControl::Action::
-output(ostream &out) const {
-  switch (_type) {
-  case AT_event:
-    out << "event " << *_event;
-    break;
-
-  case AT_stop:
-    out << "stop";
-    break;
-
-  case AT_jump:
-    out << "jump to " << _jump_to;
-    break;
-
-  case AT_forward:
-    out << "forward";
-    break;
-
-  case AT_backward:
-    out << "backward";
-    break;
-
-  default:
-    out << "**error**";
-  }
+animation_activated() {
+  get_part()->control_activated(this);
 }

+ 9 - 99
panda/src/chan/animControl.h

@@ -21,17 +21,11 @@
 
 #include "pandabase.h"
 
+#include "animInterface.h"
 #include "animBundle.h"
 #include "partGroup.h"
 
-#include "clockObject.h"
-#include "typedef.h"
 #include "referenceCount.h"
-#include "event.h"
-#include "pt_Event.h"
-#include "cmath.h"
-#include <string>
-#include "pmap.h"
 
 class PartBundle;
 class AnimChannelBase;
@@ -44,93 +38,31 @@ class AnimChannelBase;
 //               animation: whether started, stopped, or looping, and
 //               the current frame number and play rate.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA AnimControl : public ReferenceCount {
+class EXPCL_PANDA AnimControl : public ReferenceCount, public AnimInterface {
 public:
   AnimControl(PartBundle *part, AnimBundle *anim, int channel_index);
 
 PUBLISHED:
-  ~AnimControl();
-  void play(const CPT_Event &stop_event = NULL);
-  void play(int from, int to, const CPT_Event &stop_event = NULL);
-  void loop(bool restart);
-  void loop(bool restart, int from, int to);
-  void pingpong(bool restart, int from, int to);
-  void stop();
-  void pose(int frame);
-
-  void add_event(int frame, const CPT_Event &event);
-  int remove_event(const string &event_name);
-  void remove_all_events();
-
-  INLINE void set_play_rate(double play_rate);
-  INLINE double get_play_rate() const;
-  INLINE double get_frame_rate() const;
-
-  INLINE int get_frame() const;
-  INLINE int get_num_frames() const;
-
-  INLINE bool is_playing() const;
+  virtual ~AnimControl();
 
   PartBundle *get_part() const;
   INLINE AnimBundle *get_anim() const;
   INLINE int get_channel_index() const;
 
-  void output(ostream &out) const;
+  virtual void output(ostream &out) const;
 
 public:
   // The following functions aren't really part of the public
   // interface; they're just public so we don't have to declare a
   // bunch of friends.
 
-  void advance_time(double time);
-
   bool channel_has_changed(AnimChannelBase *channel) const;
   void mark_channels();
 
-private:
-
-  enum ActionType {
-    AT_event,
-    AT_stop,
-    AT_jump,
-    AT_forward,
-    AT_backward,
-  };
-
-#ifdef WIN32_VC
-public:
-#endif
-
-  class EXPCL_PANDA Action {
-  public:
-    ActionType _type;
-    CPT_Event _event;
-    int _jump_to;
-
-    void output(ostream &out) const;
-  };
+protected:
+  virtual void animation_activated();
 
 private:
-  typedef pmultimap<int, Action> Actions;
-
-  static void insert_event_action(Actions &actions, int frame, const CPT_Event &event);
-  static void insert_stop_action(Actions &actions, int frame);
-  static void insert_jump_action(Actions &actions, int frame, int jump_to);
-  static void insert_forward_action(Actions &actions, int frame);
-  static void insert_backward_action(Actions &actions, int frame);
-
-  void set_frame(double frame);
-
-  bool do_actions_forward(int from, int to);
-  bool do_actions_backward(int from, int to);
-
-  void do_action(int frame, const Action &action,
-                 int &sequence_frame, const Action *&sequence_action);
-  void do_sequence_action(int frame, const Action &action);
-
-  Actions _actions;
-  Actions _user_actions;
-
   // This is a PT(PartGroup) instead of a PT(PartBundle), just because
   // we can't include partBundle.h for circular reasons.  But it
   // actually keeps a pointer to a PartBundle.
@@ -138,17 +70,6 @@ private:
   PT(AnimBundle) _anim;
   int _channel_index;
 
-  double _play_rate;
-
-  // We keep a floating-point frame number.  This increments fluidly,
-  // and records honest "between-frame" increments.  However, whenever
-  // we report the current frame number, we just report the integer
-  // portion.
-  double _frame;
-  double _as_of_time;
-
-  bool _playing;
-
   // This is the frame number as of the last call to mark_channels().
   int _marked_frame;
 
@@ -158,27 +79,16 @@ public:
   }
   static void init_type() {
     ReferenceCount::init_type();
+    AnimInterface::init_type();
     register_type(_type_handle, "AnimControl",
-                  ReferenceCount::get_class_type());
+                  ReferenceCount::get_class_type(),
+                  AnimInterface::get_class_type());
   }
 
 private:
   static TypeHandle _type_handle;
-
-friend inline ostream &operator << (ostream &, const AnimControl::Action &);
-friend class AnimControl::Action;
 };
 
-inline ostream &operator << (ostream &out, const AnimControl &ac) {
-  ac.output(out);
-  return out;
-}
-
-inline ostream &operator << (ostream &out, const AnimControl::Action &action) {
-  action.output(out);
-  return out;
-}
-
 #include "animControl.I"
 
 #endif

+ 2 - 56
panda/src/chan/animControlCollection.I

@@ -17,60 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControlCollection::set_stop_event
-//       Access: Public
-//  Description: Sets the event that will be thrown when the next
-//               animation that is played eventually comes to a stop.
-//               Setting this does not affect any stop event that is
-//               pending from a previously-started animation.
-////////////////////////////////////////////////////////////////////
-INLINE void AnimControlCollection::
-set_stop_event(const CPT_Event &stop_event) {
-  _stop_event = stop_event;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControlCollection::clear_stop_event
-//       Access: Public
-//  Description: Indicates that the next-started animation will not
-//               throw a stop event when it comes to a stop.  This
-//               does not affect any already-started animations.
-////////////////////////////////////////////////////////////////////
-INLINE void AnimControlCollection::
-clear_stop_event() {
-  _stop_event = (const Event *)NULL;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControlCollection::has_stop_event
-//       Access: Public
-//  Description: Returns true if a stop event has been established via
-//               set_stop_event().  If true, this means that
-//               animations that are to be started in the future will
-//               throw this event when they stop.  However, it does
-//               not necessarily mean that the currently-playing
-//               animation will throw this event.
-////////////////////////////////////////////////////////////////////
-INLINE bool AnimControlCollection::
-has_stop_event() const {
-  return (_stop_event != (const Event *)NULL);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimControlCollection::get_stop_event
-//       Access: Public
-//  Description: Returns the event that has been established via
-//               set_stop_event().  This is the event that will be
-//               thrown by animations that are started in the future
-//               when they stop.  However, this may or may not be
-//               associated with any currently-playing animations.
-////////////////////////////////////////////////////////////////////
-INLINE CPT_Event AnimControlCollection::
-get_stop_event() const {
-  return _stop_event;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimControlCollection::play
 //       Access: Public
@@ -83,7 +29,7 @@ play(const string &anim_name) {
     return false;
   }
   _last_started_control = control;
-  control->play(_stop_event);
+  control->play();
   return true;
 }
 
@@ -99,7 +45,7 @@ play(const string &anim_name, int from, int to) {
     return false;
   }
   _last_started_control = control;
-  control->play(from, to, _stop_event);
+  control->play(from, to);
   return true;
 }
 

+ 0 - 6
panda/src/chan/animControlCollection.h

@@ -52,11 +52,6 @@ PUBLISHED:
   string get_anim_name(int n) const;
   void clear_anims();
 
-  INLINE void set_stop_event(const CPT_Event &stop_event);
-  INLINE void clear_stop_event();
-  INLINE bool has_stop_event() const;
-  INLINE CPT_Event get_stop_event() const;
-
   // The following functions are convenience functions that vector
   // directly into the AnimControl's functionality by anim name.
 
@@ -100,7 +95,6 @@ private:
   typedef pmap<string, size_t> ControlsByName;
   ControlsByName _controls_by_name;
 
-  CPT_Event _stop_event;
   AnimControl *_last_started_control;
 };
 

+ 0 - 15
panda/src/chan/partBundle.cxx

@@ -326,21 +326,6 @@ bind_anim(AnimBundle *anim, const string &name,
   return true;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::advance_time
-//       Access: Public
-//  Description: Calls advance_time() on all AnimControls currently
-//               in effect.
-////////////////////////////////////////////////////////////////////
-void PartBundle::
-advance_time(double time) {
-  ChannelBlend::const_iterator cbi;
-  for (cbi = _blend.begin(); cbi != _blend.end(); ++cbi) {
-    AnimControl *control = (*cbi).first;
-    control->advance_time(time);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: PartBundle::update
 //       Access: Public

+ 0 - 1
panda/src/chan/partBundle.h

@@ -123,7 +123,6 @@ public:
   // interface; they're just public so we don't have to declare a
   // bunch of friends.
 
-  void advance_time(double time);
   bool update();
   bool force_update();
   virtual void control_activated(AnimControl *control);

+ 2 - 6
panda/src/char/character.cxx

@@ -160,10 +160,8 @@ cull_callback(CullTraverser *, CullTraverserData &) {
 
   PStatTimer timer(_joints_pcollector);
 
-  double now = ClockObject::get_global_clock()->get_frame_time();
-  get_bundle()->advance_time(now);
-
   if (char_cat.is_spam()) {
+    double now = ClockObject::get_global_clock()->get_frame_time();
     char_cat.spam() << "Animating " << *this << " at time " << now << "\n";
   }
 
@@ -183,10 +181,8 @@ cull_callback(CullTraverser *, CullTraverserData &) {
 ////////////////////////////////////////////////////////////////////
 void Character::
 update_to_now() {
-  double now = ClockObject::get_global_clock()->get_frame_time();
-  get_bundle()->advance_time(now);
-
   if (char_cat.is_spam()) {
+    double now = ClockObject::get_global_clock()->get_frame_time();
     char_cat.spam() << "Animating " << *this << " at time " << now << "\n";
   }
 

+ 1 - 1
panda/src/downloader/Sources.pp

@@ -1,7 +1,7 @@
 #define LOCAL_LIBS express pandabase
 #define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
                    dtoolutil:c dtoolbase:c dtool:m
-#define USE_PACKAGES zlib net ssl
+#define USE_PACKAGES zlib net openssl
 
 #begin lib_target
   #define TARGET downloader

+ 2 - 2
panda/src/downloader/bioPtr.cxx

@@ -19,7 +19,7 @@
 #include "bioPtr.h"
 #include "urlSpec.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BioPtr::Constructor
@@ -55,4 +55,4 @@ BioPtr::
   }
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/bioPtr.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 #define OPENSSL_NO_KRB5
 
 #include "referenceCount.h"
@@ -63,7 +63,7 @@ private:
 
 #include "bioPtr.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 
 #endif

+ 2 - 2
panda/src/downloader/bioStream.cxx

@@ -19,7 +19,7 @@
 #include "bioStream.h"
 
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 ////////////////////////////////////////////////////////////////////
 //     Function: IBioStream::is_closed
@@ -104,4 +104,4 @@ close() {
   _buf.close();
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/bioStream.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "socketStream.h"
 #include "bioStreamBuf.h"
@@ -94,7 +94,7 @@ private:
 
 #include "bioStream.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 
 #endif

+ 2 - 2
panda/src/downloader/bioStreamBuf.cxx

@@ -21,7 +21,7 @@
 #include "ssl_utils.h"
 #include <errno.h>
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #ifndef HAVE_STREAMSIZE
 // Some compilers (notably SGI) don't define this for us
@@ -275,4 +275,4 @@ write_chars(const char *start, size_t length) {
   return length;
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/bioStreamBuf.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 #define OPENSSL_NO_KRB5
 
 #include "bioPtr.h"
@@ -58,6 +58,6 @@ private:
   friend class BioStream;
 };
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif

+ 2 - 2
panda/src/downloader/bioStreamPtr.cxx

@@ -18,7 +18,7 @@
 
 #include "bioStreamPtr.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BioStreamPtr::Destructor
@@ -33,4 +33,4 @@ BioStreamPtr::
   }
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/bioStreamPtr.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 #define OPENSSL_NO_KRB5
 
 #include "bioStream.h"
@@ -52,7 +52,7 @@ private:
 
 #include "bioStreamPtr.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 
 #endif

+ 2 - 2
panda/src/downloader/chunkedStream.cxx

@@ -19,7 +19,7 @@
 #include "chunkedStream.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 ////////////////////////////////////////////////////////////////////
 //     Function: IChunkedStream::is_closed
@@ -48,4 +48,4 @@ close() {
   _buf.close_read();
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/chunkedStream.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "socketStream.h"
 #include "chunkedStreamBuf.h"
@@ -55,7 +55,7 @@ private:
 
 #include "chunkedStream.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif
 

+ 2 - 2
panda/src/downloader/chunkedStreamBuf.cxx

@@ -21,7 +21,7 @@
 #include <ctype.h>
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #ifndef HAVE_STREAMSIZE
 // Some compilers (notably SGI) don't define this for us
@@ -249,4 +249,4 @@ http_getline(string &str) {
   return false;
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/chunkedStreamBuf.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "httpChannel.h"
 #include "bioStreamPtr.h"
@@ -60,6 +60,6 @@ private:
   friend class IChunkedStream;
 };
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif

+ 2 - 2
panda/src/downloader/config_downloader.cxx

@@ -167,7 +167,7 @@ init_libdownloader() {
   }
   initialized = true;
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
   HTTPChannel::init_type();
 
   // We need to define this here, rather than above, to guarantee that
@@ -194,5 +194,5 @@ init_libdownloader() {
 
   PandaSystem *ps = PandaSystem::get_global_ptr();
   ps->add_system("OpenSSL");
-#endif
+#endif  // HAVE_OPENSSL
 }

+ 2 - 2
panda/src/downloader/httpAuthorization.cxx

@@ -20,7 +20,7 @@
 #include "httpChannel.h"
 #include "urlSpec.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 static const char base64_table[64] = {
   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
@@ -346,4 +346,4 @@ scan_quoted_or_unquoted_string(string &result, const string &source,
   return start;
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/httpAuthorization.h

@@ -25,7 +25,7 @@
 // actually use any OpenSSL code, because it is a support module for
 // HTTPChannel, which *does* use OpenSSL code.
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "referenceCount.h"
 #include "httpEnum.h"
@@ -81,7 +81,7 @@ protected:
 
 #include "httpAuthorization.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif
 

+ 2 - 2
panda/src/downloader/httpBasicAuthorization.cxx

@@ -18,7 +18,7 @@
 
 #include "httpBasicAuthorization.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 const string HTTPBasicAuthorization::_mechanism = "basic";
 
@@ -68,4 +68,4 @@ generate(HTTPEnum::Method, const string &,
   return "Basic " + base64_encode(username);
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/httpBasicAuthorization.h

@@ -25,7 +25,7 @@
 // actually use any OpenSSL code, because it is a support module for
 // HTTPChannel, which *does* use OpenSSL code.
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "httpAuthorization.h"
 
@@ -53,7 +53,7 @@ private:
 
 #include "httpBasicAuthorization.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif
 

+ 2 - 2
panda/src/downloader/httpChannel.cxx

@@ -27,7 +27,7 @@
 #include "clockObject.h"
 #include "ramfile.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 #include <openssl/x509.h>
 
 #ifdef WIN32_VC
@@ -3498,4 +3498,4 @@ operator << (ostream &out, HTTPChannel::State state) {
 #endif  // NDEBUG
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/httpChannel.h

@@ -26,7 +26,7 @@
 // the OpenSSL library to portably handle all of the socket
 // communications.
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 #define OPENSSL_NO_KRB5
 
 #include "httpClient.h"
@@ -429,7 +429,7 @@ ostream &operator << (ostream &out, HTTPChannel::State state);
 
 #include "httpChannel.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif
 

+ 2 - 2
panda/src/downloader/httpClient.cxx

@@ -28,7 +28,7 @@
 #include "httpDigestAuthorization.h"
 #include "globPattern.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include <openssl/rand.h>
 #include <openssl/err.h>
@@ -1629,4 +1629,4 @@ ssl_msg_callback(int write_p, int version, int content_type,
 }
 #endif  // defined(SSL_097) && !defined(NDEBUG)
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/httpClient.h

@@ -26,7 +26,7 @@
 // the OpenSSL library to portably handle all of the socket
 // communications.
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 #define OPENSSL_NO_KRB5
 
 #include "urlSpec.h"
@@ -207,7 +207,7 @@ private:
 
 #include "httpClient.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif
   

+ 2 - 2
panda/src/downloader/httpCookie.cxx

@@ -18,7 +18,7 @@
 
 #include "httpCookie.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "ctype.h"
 #include "httpChannel.h"
@@ -218,4 +218,4 @@ parse_cookie_param(const string &param, bool first_param) {
   return true;
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/httpCookie.h

@@ -26,7 +26,7 @@
 // the OpenSSL library to portably handle all of the socket
 // communications.
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "httpDate.h"
 #include "urlSpec.h"
@@ -88,6 +88,6 @@ INLINE ostream &operator << (ostream &out, const HTTPCookie &cookie);
 
 #include "httpCookie.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif

+ 2 - 2
panda/src/downloader/httpDigestAuthorization.cxx

@@ -18,7 +18,7 @@
 
 #include "httpDigestAuthorization.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include <openssl/ssl.h>
 #include <openssl/md5.h>
@@ -371,4 +371,4 @@ operator << (ostream &out, HTTPDigestAuthorization::Qop qop) {
   return out;
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/httpDigestAuthorization.h

@@ -25,7 +25,7 @@
 // actually use any OpenSSL code, because it is a support module for
 // HTTPChannel, which *does* use OpenSSL code.
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "httpAuthorization.h"
 
@@ -96,7 +96,7 @@ ostream &operator << (ostream &out, HTTPDigestAuthorization::Qop qop);
 
 #include "httpDigestAuthorization.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif
 

+ 2 - 2
panda/src/downloader/httpEnum.cxx

@@ -18,7 +18,7 @@
 
 #include "httpEnum.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 ////////////////////////////////////////////////////////////////////
 //     Function: HTTPEnum::Method::output operator
@@ -63,4 +63,4 @@ operator << (ostream &out, HTTPEnum::Method method) {
   return out;
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/httpEnum.h

@@ -26,7 +26,7 @@
 // the OpenSSL library to portably handle all of the socket
 // communications.
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 ////////////////////////////////////////////////////////////////////
 //       Class : HTTPEnum
@@ -57,7 +57,7 @@ PUBLISHED:
 
 ostream &operator << (ostream &out, HTTPEnum::Method method);
 
-#endif // HAVE_SSL
+#endif // HAVE_OPENSSL
 
 #endif
 

+ 2 - 2
panda/src/downloader/identityStream.cxx

@@ -19,7 +19,7 @@
 #include "identityStream.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 ////////////////////////////////////////////////////////////////////
 //     Function: IIdentityStream::is_closed
@@ -49,4 +49,4 @@ close() {
   _buf.close_read();
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/identityStream.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "socketStream.h"
 #include "identityStreamBuf.h"
@@ -62,7 +62,7 @@ private:
 
 #include "identityStream.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif
 

+ 2 - 2
panda/src/downloader/identityStreamBuf.cxx

@@ -19,7 +19,7 @@
 #include "identityStreamBuf.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #ifndef HAVE_STREAMSIZE
 // Some compilers (notably SGI) don't define this for us
@@ -180,4 +180,4 @@ read_chars(char *start, size_t length) {
   return read_count;
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/identityStreamBuf.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "httpChannel.h"
 #include "bioStreamPtr.h"
@@ -58,6 +58,6 @@ private:
   friend class IIdentityStream;
 };
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif

+ 2 - 2
panda/src/downloader/patcher.cxx

@@ -18,7 +18,7 @@
 
 #include "pandabase.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "config_downloader.h"
 #include "patcher.h"
@@ -89,4 +89,4 @@ run() {
   return _patchfile->run();
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/patcher.h

@@ -21,7 +21,7 @@
 
 #include "pandabase.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "filename.h"
 #include "buffer.h"
@@ -50,6 +50,6 @@ private:
 
 #include "patcher.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif

+ 2 - 2
panda/src/downloader/socketStream.cxx

@@ -20,7 +20,7 @@
 #include "datagram.h"
 #include "datagramIterator.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 ////////////////////////////////////////////////////////////////////
 //     Function: SSReader::Destructor
@@ -209,4 +209,4 @@ send_datagram(const Datagram &dg) {
   return !is_closed();
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/socketStream.h

@@ -29,7 +29,7 @@
 // available, since the only current use for it is to implement
 // OpenSSL-defined constructs (like ISocketStream).
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 ////////////////////////////////////////////////////////////////////
 //       Class : SSReader
@@ -168,7 +168,7 @@ PUBLISHED:
 
 #include "socketStream.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 
 #endif

+ 2 - 2
panda/src/downloader/ssl_utils.cxx

@@ -19,7 +19,7 @@
 #include "ssl_utils.h"
 #include "config_downloader.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #ifdef REPORT_OPENSSL_ERRORS
 #include <openssl/err.h>
@@ -53,4 +53,4 @@ void notify_ssl_errors() {
 #endif  //  REPORT_OPENSSL_ERRORS
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/downloader/ssl_utils.h

@@ -22,14 +22,14 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 #define OPENSSL_NO_KRB5
 
 #include <openssl/ssl.h>
 
 EXPCL_PANDAEXPRESS void notify_ssl_errors();
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif
 

+ 9 - 9
panda/src/downloadertools/Sources.pp

@@ -4,7 +4,7 @@
 
 #begin bin_target
   #define TARGET apply_patch
-  #define BUILD_TARGET $[HAVE_SSL]
+  #define BUILD_TARGET $[HAVE_OPENSSL]
 
   #define SOURCES \
     apply_patch.cxx
@@ -15,7 +15,7 @@
 
 #begin bin_target
   #define TARGET build_patch
-  #define BUILD_TARGET $[HAVE_SSL]
+  #define BUILD_TARGET $[HAVE_OPENSSL]
 
   #define SOURCES \
     build_patch.cxx
@@ -24,7 +24,7 @@
 
 #begin bin_target
   #define TARGET show_ddb
-  #define BUILD_TARGET $[HAVE_SSL]
+  #define BUILD_TARGET $[HAVE_OPENSSL]
 
   #define SOURCES \
     show_ddb.cxx
@@ -53,8 +53,8 @@
 
 #begin bin_target
   #define TARGET check_md5
-  #define BUILD_TARGET $[HAVE_SSL]
-  #define USE_PACKAGES $[USE_PACKAGES] ssl
+  #define BUILD_TARGET $[HAVE_OPENSSL]
+  #define USE_PACKAGES $[USE_PACKAGES] openssl
 
   #define SOURCES \
     check_md5.cxx
@@ -91,8 +91,8 @@
 
 #begin bin_target
   #define TARGET pencrypt
-  #define BUILD_TARGET $[HAVE_SSL]
-  #define USE_PACKAGES $[USE_PACKAGES] ssl
+  #define BUILD_TARGET $[HAVE_OPENSSL]
+  #define USE_PACKAGES $[USE_PACKAGES] openssl
 
   #define SOURCES \
     pencrypt.cxx
@@ -101,8 +101,8 @@
 
 #begin bin_target
   #define TARGET pdecrypt
-  #define BUILD_TARGET $[HAVE_SSL]
-  #define USE_PACKAGES $[USE_PACKAGES] ssl
+  #define BUILD_TARGET $[HAVE_OPENSSL]
+  #define USE_PACKAGES $[USE_PACKAGES] openssl
 
   #define SOURCES \
     pdecrypt.cxx

+ 1 - 1
panda/src/express/Sources.pp

@@ -4,7 +4,7 @@
 
 #begin lib_target
   #define TARGET express
-  #define USE_PACKAGES nspr net zlib ssl
+  #define USE_PACKAGES nspr net zlib openssl
   
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
 

+ 2 - 2
panda/src/express/encryptStream.cxx

@@ -18,7 +18,7 @@
 
 #include "encryptStream.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 ////////////////////////////////////////////////////////////////////
 //     Function: encrypt_string
 //       Access: Published
@@ -66,4 +66,4 @@ decrypt_string(const string &source, const string &password) {
   return output.str();
 }
 
-#endif // HAVE_SSL
+#endif // HAVE_OPENSSL

+ 2 - 2
panda/src/express/encryptStream.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "encryptStreamBuf.h"
 
@@ -92,7 +92,7 @@ END_PUBLISH
 
 #include "encryptStream.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 
 #endif

+ 2 - 2
panda/src/express/encryptStreamBuf.cxx

@@ -21,7 +21,7 @@
 #include "streamReader.h"
 #include "streamWriter.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include <openssl/rand.h>
 
@@ -477,4 +477,4 @@ write_chars(const char *start, size_t length) {
   }
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL

+ 2 - 2
panda/src/express/encryptStreamBuf.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 // This module is not compiled if OpenSSL is not available.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include <openssl/evp.h>
 
@@ -84,6 +84,6 @@ private:
 
 #include "encryptStreamBuf.I"
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 #endif

+ 2 - 2
panda/src/express/hashVal.I

@@ -202,7 +202,7 @@ read_stream(StreamReader &source) {
   _hv[3] = source.get_uint32();
 }
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 ////////////////////////////////////////////////////////////////////
 //     Function: HashVal::hash_ramfile
 //       Access: Published
@@ -228,7 +228,7 @@ INLINE void HashVal::
 hash_string(const string &data) {
   return hash_buffer(data.data(), data.length());
 }
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 ////////////////////////////////////////////////////////////////////
 //     Function: HashVal::tohex

+ 4 - 4
panda/src/express/hashVal.cxx

@@ -21,9 +21,9 @@
 
 #include <ctype.h>
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 #include <openssl/md5.h>
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 
 ////////////////////////////////////////////////////////////////////
@@ -164,7 +164,7 @@ set_from_hex(const string &text) {
   return !strm.fail();
 }
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 ////////////////////////////////////////////////////////////////////
 //     Function: HashVal::hash_file
 //       Access: Published
@@ -234,7 +234,7 @@ hash_buffer(const char *buffer, int length) {
   _hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]);
 }
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/express/hashVal.h

@@ -66,12 +66,12 @@ PUBLISHED:
   INLINE void write_stream(StreamWriter &destination) const;
   INLINE void read_stream(StreamReader &source);
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
   bool hash_file(const Filename &filename);
   INLINE void hash_ramfile(const Ramfile &ramfile);
   INLINE void hash_string(const string &data);
   void hash_buffer(const char *buffer, int length);
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
 private:
   static void encode_hex(PN_uint32 val, char *buffer);

+ 2 - 2
panda/src/express/multifile.I

@@ -92,13 +92,13 @@ get_scale_factor() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void Multifile::
 set_encryption_flag(bool flag) {
-#ifndef HAVE_SSL
+#ifndef HAVE_OPENSSL
   if (flag) {
     express_cat.warning()
       << "OpenSSL not compiled in; cannot generated encrypted multifiles.\n";
     flag = false;
   }
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
   _encryption_flag = flag;
 }
 

+ 6 - 6
panda/src/express/multifile.cxx

@@ -846,12 +846,12 @@ open_read_subfile(int index) {
                    subfile->_data_start + (streampos)subfile->_data_length); 
   
   if ((subfile->_flags & SF_encrypted) != 0) {
-#ifndef HAVE_SSL
+#ifndef HAVE_OPENSSL
     express_cat.error()
       << "OpenSSL not compiled in; cannot read encrypted multifiles.\n";
     delete stream;
     return NULL;
-#else  // HAVE_SSL
+#else  // HAVE_OPENSSL
     // The subfile is encrypted.  So actually, return an
     // IDecryptStream that wraps around the ISubStream.
     IDecryptStream *wrapper = 
@@ -869,7 +869,7 @@ open_read_subfile(int index) {
       delete stream;
       return NULL;
     }
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
   }
 
   if ((subfile->_flags & SF_compressed) != 0) {
@@ -1182,11 +1182,11 @@ add_new_subfile(Subfile *subfile, int compression_level) {
 #endif  // HAVE_ZLIB
   }
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
   if (_encryption_flag) {
     subfile->_flags |= SF_encrypted;
   }
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 
   if (_next_index != (streampos)0) {
     // If we're adding a Subfile to an already-existing Multifile, we
@@ -1566,7 +1566,7 @@ write_data(ostream &write, istream *read, streampos fpos,
     ostream *putter = &write;
     bool delete_putter = false;
 
-#ifndef HAVE_SSL
+#ifndef HAVE_OPENSSL
     // Without OpenSSL, we can't support encryption.  The flag had
     // better not be set.
     nassertr((_flags & SF_encrypted) == 0, fpos);

+ 2 - 2
panda/src/express/password_hash.cxx

@@ -20,7 +20,7 @@
 
 // The functions defined within this file rely on algorithms defined
 // within OpenSSL.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include <openssl/evp.h>
 
@@ -75,5 +75,5 @@ password_hash(const string &password, const string &salt,
 
 
 
-#endif  // HAVE_SSL
+#endif  // HAVE_OPENSSL
 

+ 2 - 2
panda/src/express/password_hash.h

@@ -23,7 +23,7 @@
 
 // The functions defined within this file rely on algorithms defined
 // within OpenSSL.
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 BEGIN_PUBLISH
 
@@ -32,6 +32,6 @@ string password_hash(const string &password, const string &salt,
 
 END_PUBLISH
 
-#endif // HAVE_SSL
+#endif // HAVE_OPENSSL
 
 #endif

+ 2 - 2
panda/src/express/patchfile.cxx

@@ -18,7 +18,7 @@
 
 #include "pandabase.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "config_express.h"
 #include "error_utils.h"
@@ -981,4 +981,4 @@ build(Filename file_orig, Filename file_new, Filename patch_name) {
   return true;
 }
 
-#endif // HAVE_SSL
+#endif // HAVE_OPENSSL

+ 2 - 2
panda/src/express/patchfile.h

@@ -20,7 +20,7 @@
 
 #include "pandabase.h"
 
-#ifdef HAVE_SSL
+#ifdef HAVE_OPENSSL
 
 #include "typedef.h"
 #include "notify.h"
@@ -136,6 +136,6 @@ protected:
 
 #include "patchfile.I"
 
-#endif // HAVE_SSL
+#endif // HAVE_OPENSSL
 
 #endif

+ 3 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -5700,6 +5700,9 @@ upload_texture_image(CLP(TextureContext) *gtc,
   } else {
     // We can reload the image over the previous image, possibly
     // saving on texture memory fragmentation.
+#ifdef DO_PSTATS
+    _data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type));
+#endif
     switch (target) {
     case GL_TEXTURE_1D:
       GLP(TexSubImage1D)(target, 0, 0, width, 

+ 6 - 3
panda/src/gobj/Sources.pp

@@ -57,7 +57,8 @@
     userVertexTransform.I userVertexTransform.h \
     vertexBufferContext.I vertexBufferContext.h \
     vertexSlider.I vertexSlider.h \
-    vertexTransform.I vertexTransform.h
+    vertexTransform.I vertexTransform.h \
+    videoTexture.I videoTexture.h
     
   #define INCLUDED_SOURCES \
     boundedObject.cxx \
@@ -104,7 +105,8 @@
     userVertexTransform.cxx \
     vertexBufferContext.cxx \
     vertexSlider.cxx \
-    vertexTransform.cxx
+    vertexTransform.cxx \
+    videoTexture.cxx
 
   #define INSTALL_HEADERS \
     boundedObject.I boundedObject.h \
@@ -156,7 +158,8 @@
     userVertexTransform.I userVertexTransform.h \
     vertexBufferContext.I vertexBufferContext.h \
     vertexSlider.I vertexSlider.h \
-    vertexTransform.I vertexTransform.h
+    vertexTransform.I vertexTransform.h \
+    videoTexture.I videoTexture.h
 
 
   #define IGATESCAN all

+ 2 - 8
panda/src/gobj/config_gobj.cxx

@@ -50,6 +50,7 @@
 #include "userVertexTransform.h"
 #include "vertexTransform.h"
 #include "vertexSlider.h"
+#include "videoTexture.h"
 #include "geomContext.h"
 #include "vertexBufferContext.h"
 #include "indexBufferContext.h"
@@ -187,14 +188,6 @@ ConfigVariableEnum<AutoTextureScale> textures_square
           "a square aspect ratio when they are loaded from disk.  Set this "
           "to 'none', 'down', or 'up'.  See textures-power-2."));
 
-ConfigVariableString fake_texture_image
-("fake-texture-image", "",
- PRC_DESC("Set this to enable a speedy-load mode in which you don't care "
-          "what the world looks like, you just want it to load in minimal "
-          "time.  This causes all texture loads via the TexturePool to use "
-          "the same texture file, which will presumably only be loaded "
-          "once."));
-
 ConfigVariableInt geom_cache_size
 ("geom-cache-size", 5000,
  PRC_DESC("Specifies the maximum number of entries in the cache "
@@ -264,6 +257,7 @@ ConfigureFn(config_gobj) {
   UserVertexTransform::init_type();
   VertexTransform::init_type();
   VertexSlider::init_type();
+  VideoTexture::init_type();
   InternalName::init_type();
 
   //Registration of writeable object's creation

+ 0 - 1
panda/src/gobj/config_gobj.h

@@ -61,7 +61,6 @@ extern EXPCL_PANDA ConfigVariableBool connect_triangle_strips;
 extern EXPCL_PANDA ConfigVariableEnum<BamTextureMode> bam_texture_mode;
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_power_2;
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_square;
-extern EXPCL_PANDA ConfigVariableString fake_texture_image;
 
 extern EXPCL_PANDA ConfigVariableInt geom_cache_size;
 extern EXPCL_PANDA ConfigVariableInt geom_cache_min_frames;

+ 1 - 0
panda/src/gobj/gobj_composite2.cxx

@@ -26,3 +26,4 @@
 #include "vertexBufferContext.cxx"
 #include "vertexSlider.cxx"
 #include "vertexTransform.cxx"
+#include "videoTexture.cxx"

+ 1 - 1
panda/src/gobj/shader.cxx

@@ -91,7 +91,7 @@ parse_upto(string &result, string pattern, bool include) {
   GlobPattern endpat(pattern);
   int start = _parse;
   int last = _parse;
-  while (_parse < _text.size()) {
+  while (_parse < (int)_text.size()) {
     string t;
     parse_line(t, true, true);
     if (endpat.matches(t)) break;

+ 20 - 55
panda/src/gobj/texture.I

@@ -411,36 +411,18 @@ uses_mipmaps() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: Texture::has_ram_image
+//     Function: Texture::might_have_ram_image
 //       Access: Published
-//  Description: Returns true if the Texture has its image contents
-//               available in main RAM, false if it exists only in
-//               texture memory or in the prepared GSG context.
-//
-//               Note that this has nothing to do with whether
-//               get_ram_image() will fail or not.  Even if
-//               has_ram_image() returns false, get_ram_image() may
-//               still return a valid RAM image, because
-//               get_ram_image() will automatically load the texture
-//               from disk if necessary.  The only thing
-//               has_ram_image() tells you is whether the texture is
-//               available right now without hitting the disk first.
-//
-//               Note also that if an application uses only one GSG,
-//               it may appear that has_ram_image() returns true if
-//               the texture has not yet been loaded by the GSG, but
-//               this correlation is not true in general and should
-//               not be depended on.  Specifically, if an application
-//               ever uses multiple GSG's in its lifetime (for
-//               instance, by opening more than one window, or by
-//               closing its window and opening another one later),
-//               then has_ram_image() may well return false on
-//               textures that have never been loaded on the current
-//               GSG.
+//  Description: Returns true if the texture's image contents are
+//               currently available in main RAM, or there is reason
+//               to believe it can be loaded on demand.  That is, this
+//               function returns a "best guess" as to whether
+//               get_ram_image() will succeed without actually calling
+//               it first.
 ////////////////////////////////////////////////////////////////////
 INLINE bool Texture::
-has_ram_image() const {
-  return !_image.empty();
+might_have_ram_image() const {
+  return (has_ram_image() || has_filename());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -479,21 +461,6 @@ get_expected_ram_page_size() const {
   return (size_t)(_x_size * _y_size * _num_components * _component_width);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: Texture::might_have_ram_image
-//       Access: Published
-//  Description: Returns true if the texture's image contents are
-//               currently available in main RAM, or there is reason
-//               to believe it can be loaded on demand.  That is, this
-//               function returns a "best guess" as to whether
-//               get_ram_image() will succeed without actually calling
-//               it first.
-////////////////////////////////////////////////////////////////////
-INLINE bool Texture::
-might_have_ram_image() const {
-  return (has_ram_image() || has_filename());
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::set_keep_ram_image
 //       Access: Published
@@ -514,19 +481,6 @@ set_keep_ram_image(bool keep_ram_image) {
   _keep_ram_image = keep_ram_image;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: Texture::get_keep_ram_image
-//       Access: Published
-//  Description: Returns the flag that indicates whether this Texture
-//               is eligible to have its main RAM copy of the texture
-//               memory dumped when the texture is prepared for
-//               rendering.  See set_keep_ram_image().
-////////////////////////////////////////////////////////////////////
-INLINE bool Texture::
-get_keep_ram_image() const {
-  return _keep_ram_image;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::set_filename
 //       Access: Published
@@ -700,6 +654,17 @@ set_loaded_from_disk() {
   _loaded_from_disk = true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_loaded_from_disk
+//       Access: Published
+//  Description: Returns the flag that indicates the texture has been
+//               loaded from a disk file.  See set_loaded_from_disk().
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+get_loaded_from_disk() const {
+  return _loaded_from_disk;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::get_match_framebuffer_format
 //       Access: Public

+ 280 - 89
panda/src/gobj/texture.cxx

@@ -71,6 +71,44 @@ Texture(const string &name) :
   _loaded_from_disk = false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::Copy Constructor
+//       Access: Protected
+//  Description: Use Texture::make_copy() to make a duplicate copy of
+//               an existing Texture.
+////////////////////////////////////////////////////////////////////
+Texture::
+Texture(const Texture &copy) :
+  Namable(copy),
+  _filename(copy._filename),
+  _alpha_filename(copy._alpha_filename),
+  _fullpath(copy._fullpath),
+  _alpha_fullpath(copy._alpha_fullpath),
+  _primary_file_num_channels(copy._primary_file_num_channels),
+  _alpha_file_channel(copy._alpha_file_channel),
+  _x_size(copy._x_size),
+  _y_size(copy._y_size),
+  _z_size(copy._z_size),
+  _num_components(copy._num_components),
+  _component_width(copy._component_width),
+  _texture_type(copy._texture_type),
+  _format(copy._format),
+  _component_type(copy._component_type),
+  _loaded_from_disk(copy._loaded_from_disk),
+  _wrap_u(copy._wrap_u),
+  _wrap_v(copy._wrap_v),
+  _wrap_w(copy._wrap_w),
+  _minfilter(copy._minfilter),
+  _magfilter(copy._magfilter),
+  _anisotropic_degree(copy._anisotropic_degree),
+  _keep_ram_image(copy._keep_ram_image),
+  _border_color(copy._border_color),
+  _match_framebuffer_format(copy._match_framebuffer_format),
+  _all_dirty_flags(0),
+  _image(copy._image)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::Destructor
 //       Access: Published, Virtual
@@ -81,6 +119,24 @@ Texture::
   release_all();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::make_copy
+//       Access: Published, Virtual
+//  Description: Returns a new copy of the same Texture.  This copy,
+//               if applied to geometry, will be copied into texture
+//               as a separate texture from the original, so it will
+//               be duplicated in texture memory (and may be
+//               independently modified if desired).
+//               
+//               If the Texture is an AviTexture, the resulting
+//               duplicate may be animated independently of the
+//               original.
+////////////////////////////////////////////////////////////////////
+PT(Texture) Texture::
+make_copy() {
+  return new Texture(*this);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::setup_texture
 //       Access: Published
@@ -221,7 +277,7 @@ generate_normalization_cube_map(int size) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::read
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Reads the texture from the indicated filename.  If
 //               num_channels is not 0, it specifies the number of
 //               components to downgrade the image to if it is greater
@@ -262,7 +318,7 @@ read(const Filename &fullpath, int z, int primary_file_num_channels) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::read
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Combine a 3-component image with a grayscale image
 //               to get a 4-component image
 //
@@ -477,7 +533,7 @@ write_pages(const HashFilename &fullpath_template) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::load
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Fills the texture system RAM data from the
 //               already-read PNMImage.
 //
@@ -496,85 +552,21 @@ write_pages(const HashFilename &fullpath_template) {
 ////////////////////////////////////////////////////////////////////
 bool Texture::
 load(const PNMImage &pnmimage, int z) {
-  if (z >= _z_size) {
-    // If we're loading a page past _z_size, treat it as an implicit
-    // request to enlarge _z_size.  However, this is only legal if
-    // this is, in fact, a 3-d texture (cube maps always have z_size
-    // 6, and other types have z_size 1).
-    nassertr(_texture_type == Texture::TT_3d_texture, false);
-
-    _z_size = z + 1;
-    // Increase the size of the data buffer to make room for the new
-    // texture level.
-    size_t new_size = get_expected_ram_image_size();
-    if (!_image.is_null() && new_size > _image.size()) {
-      _image.insert(_image.end(), new_size - _image.size(), 0);
-      nassertr(_image.size() == new_size, false);
-    }
+  if (!reconsider_z_size(z)) {
+    return false;
   }
-
   nassertr(z >= 0 && z < _z_size, false);
 
-  int num_components = pnmimage.get_num_channels();
   ComponentType component_type = T_unsigned_byte;
-
   xelval maxval = pnmimage.get_maxval();
   if (maxval > 255) {
     component_type = T_unsigned_short;
   }
 
-  if (!_loaded_from_disk || num_components != _num_components) {
-    // Come up with a default format based on the number of channels.
-    // But only do this the first time the file is loaded, or if the
-    // number of channels in the image changes on subsequent loads.
-
-    switch (pnmimage.get_color_type()) {
-    case PNMImage::CT_grayscale:
-      _format = F_luminance;
-      break;
-      
-    case PNMImage::CT_two_channel:
-      _format = F_luminance_alpha;
-      break;
-      
-    case PNMImage::CT_color:
-      _format = F_rgb;
-      break;
-      
-    case PNMImage::CT_four_channel:
-      _format = F_rgba;
-      break;
-      
-    default:
-      // Eh?
-      nassertr(false, false);
-      _format = F_rgb;
-    }
-  }
-
-  if (!_loaded_from_disk) {
-#ifndef NDEBUG
-    if (_texture_type == TT_1d_texture) {
-      nassertr(pnmimage.get_y_size() == 1, false);
-    } else if (_texture_type == TT_cube_map) {
-      nassertr(pnmimage.get_x_size() == pnmimage.get_y_size(), false);
-    }
-#endif
-    _x_size = pnmimage.get_x_size();
-    _y_size = pnmimage.get_y_size();
-    _num_components = num_components;
-    set_component_type(component_type);
-
-  } else {
-    if (_x_size != pnmimage.get_x_size() ||
-        _y_size != pnmimage.get_y_size() ||
-        _num_components != num_components ||
-        _component_type != component_type) {
-      gobj_cat.error()
-        << "Texture properties have changed for texture " << get_name()
-        << " level " << z << ".\n";
-      return false;
-    }
+  if (!reconsider_image_properties(pnmimage.get_x_size(), pnmimage.get_y_size(),
+				   pnmimage.get_num_channels(), component_type,
+				   z)) {
+    return false;
   }
 
   _loaded_from_disk = true;
@@ -856,6 +848,39 @@ set_border_color(const Colorf &color) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::has_ram_image
+//       Access: Published, Virtual
+//  Description: Returns true if the Texture has its image contents
+//               available in main RAM, false if it exists only in
+//               texture memory or in the prepared GSG context.
+//
+//               Note that this has nothing to do with whether
+//               get_ram_image() will fail or not.  Even if
+//               has_ram_image() returns false, get_ram_image() may
+//               still return a valid RAM image, because
+//               get_ram_image() will automatically load the texture
+//               from disk if necessary.  The only thing
+//               has_ram_image() tells you is whether the texture is
+//               available right now without hitting the disk first.
+//
+//               Note also that if an application uses only one GSG,
+//               it may appear that has_ram_image() returns true if
+//               the texture has not yet been loaded by the GSG, but
+//               this correlation is not true in general and should
+//               not be depended on.  Specifically, if an application
+//               ever uses multiple GSG's in its lifetime (for
+//               instance, by opening more than one window, or by
+//               closing its window and opening another one later),
+//               then has_ram_image() may well return false on
+//               textures that have never been loaded on the current
+//               GSG.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+has_ram_image() const {
+  return !_image.empty();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::get_ram_image
 //       Access: Published
@@ -886,19 +911,8 @@ set_border_color(const Colorf &color) {
 ////////////////////////////////////////////////////////////////////
 CPTA_uchar Texture::
 get_ram_image() {
-  if (_loaded_from_disk && !has_ram_image() && has_filename() &&
-      (_texture_type == TT_1d_texture || _texture_type == TT_2d_texture)) {
-    // Now we have to reload the texture image.
-    gobj_cat.info()
-      << "Reloading texture " << get_name() << "\n";
-
-    make_ram_image();
-    if (has_alpha_fullpath()) {
-      read(get_fullpath(), get_alpha_fullpath(),
-           0, _primary_file_num_channels, _alpha_file_channel);
-    } else {
-      read(get_fullpath(), 0, _primary_file_num_channels);
-    }
+  if (_loaded_from_disk && !has_ram_image() && has_filename()) {
+    reload_ram_image();
   }
 
   return _image;
@@ -914,7 +928,7 @@ get_ram_image() {
 ////////////////////////////////////////////////////////////////////
 PTA_uchar Texture::
 modify_ram_image() {
-  if (!has_ram_image()) {
+  if (_image.empty()) {
     make_ram_image();
   }
 
@@ -968,6 +982,19 @@ clear_ram_image() {
   _image.clear();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_keep_ram_image
+//       Access: Published, Virtual
+//  Description: Returns the flag that indicates whether this Texture
+//               is eligible to have its main RAM copy of the texture
+//               memory dumped when the texture is prepared for
+//               rendering.  See set_keep_ram_image().
+////////////////////////////////////////////////////////////////////
+bool Texture::
+get_keep_ram_image() const {
+  return _keep_ram_image;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::prepare
 //       Access: Published
@@ -1218,6 +1245,38 @@ mark_dirty(int flags_to_set) {
   _all_dirty_flags |= flags_to_set;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::has_cull_callback
+//       Access: Public, Virtual
+//  Description: Should be overridden by derived classes to return
+//               true if cull_callback() has been defined.  Otherwise,
+//               returns false to indicate cull_callback() does not
+//               need to be called for this node during the cull
+//               traversal.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+has_cull_callback() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::cull_callback
+//       Access: Public, Virtual
+//  Description: If has_cull_callback() returns true, this function
+//               will be called during the cull traversal to perform
+//               any additional operations that should be performed at
+//               cull time.
+//
+//               This is called each time the Texture is discovered
+//               applied to a Geom in the traversal.  It should return
+//               true if the Geom is visible, false if it should be
+//               omitted.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+cull_callback(CullTraverser *, const CullTraverserData &) const {
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::string_wrap_mode
 //       Access: Public
@@ -1271,6 +1330,41 @@ string_filter_type(const string &string) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::reconsider_dirty
+//       Access: Protected, Virtual
+//  Description: Called by TextureContext to give the Texture a chance
+//               to mark itself dirty before rendering, if necessary.
+////////////////////////////////////////////////////////////////////
+void Texture::
+reconsider_dirty() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::reload_ram_image
+//       Access: Protected, Virtual
+//  Description: Called when the Texture image is required but the ram
+//               image is not available, this will reload it from disk
+//               or otherwise do whatever is required to make it
+//               available, if possible.
+////////////////////////////////////////////////////////////////////
+void Texture::
+reload_ram_image() {
+  if (_texture_type == TT_1d_texture || _texture_type == TT_2d_texture) {
+    gobj_cat.info()
+      << "Reloading texture " << get_name() << "\n";
+    
+    make_ram_image();
+    if (has_alpha_fullpath()) {
+      read(get_fullpath(), get_alpha_fullpath(),
+           0, _primary_file_num_channels, _alpha_file_channel);
+    } else {
+      read(get_fullpath(), 0, _primary_file_num_channels);
+    }
+  }
+}
+
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::up_to_power_2
 //       Access: Protected, Static
@@ -1301,6 +1395,102 @@ down_to_power_2(int value) {
   return x;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::reconsider_z_size
+//       Access: Protected
+//  Description: Considers whether the z_size should automatically be
+//               adjusted when the user loads a new page.  Returns
+//               true if the z size is valid, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+reconsider_z_size(int z) {
+  if (z >= _z_size) {
+    // If we're loading a page past _z_size, treat it as an implicit
+    // request to enlarge _z_size.  However, this is only legal if
+    // this is, in fact, a 3-d texture (cube maps always have z_size
+    // 6, and other types have z_size 1).
+    nassertr(_texture_type == Texture::TT_3d_texture, false);
+
+    _z_size = z + 1;
+    // Increase the size of the data buffer to make room for the new
+    // texture level.
+    size_t new_size = get_expected_ram_image_size();
+    if (!_image.is_null() && new_size > _image.size()) {
+      _image.insert(_image.end(), new_size - _image.size(), 0);
+      nassertr(_image.size() == new_size, false);
+    }
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::reconsider_image_properties
+//       Access: Protected
+//  Description: Resets the internal Texture properties when a new
+//               image file is loaded.  Returns true if the new image
+//               is valid, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool Texture::
+reconsider_image_properties(int x_size, int y_size, int num_components,
+			    Texture::ComponentType component_type, int z) {
+  if (!_loaded_from_disk || num_components != _num_components) {
+    // Come up with a default format based on the number of channels.
+    // But only do this the first time the file is loaded, or if the
+    // number of channels in the image changes on subsequent loads.
+
+    switch (num_components) {
+    case 1:
+      _format = F_luminance;
+      break;
+      
+    case 2:
+      _format = F_luminance_alpha;
+      break;
+      
+    case 3:
+      _format = F_rgb;
+      break;
+      
+    case 4:
+      _format = F_rgba;
+      break;
+      
+    default:
+      // Eh?
+      nassertr(false, false);
+      _format = F_rgb;
+    }
+  }
+
+  if (!_loaded_from_disk) {
+#ifndef NDEBUG
+    if (_texture_type == TT_1d_texture) {
+      nassertr(y_size == 1, false);
+    } else if (_texture_type == TT_cube_map) {
+      nassertr(x_size == y_size, false);
+    }
+#endif
+    _x_size = x_size;
+    _y_size = y_size;
+    _num_components = num_components;
+    set_component_type(component_type);
+
+  } else {
+    if (_x_size != x_size ||
+        _y_size != y_size ||
+        _num_components != num_components ||
+        _component_type != component_type) {
+      gobj_cat.error()
+        << "Texture properties have changed for texture " << get_name()
+        << " level " << z << ".\n";
+      return false;
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::clear_prepared
 //       Access: Private
@@ -1323,6 +1513,7 @@ clear_prepared(PreparedGraphicsObjects *prepared_objects) {
   }
 }
 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::consider_rescale
 //       Access: Private
@@ -1444,7 +1635,7 @@ make_Texture(const FactoryParams &params) {
   if (has_rawdata) {
     // If the raw image data is included, then just create a Texture
     // and don't load from the file.
-    me = new Texture;
+    me = new Texture("");
 
   } else {
     if (filename.empty()) {
@@ -1473,7 +1664,7 @@ make_Texture(const FactoryParams &params) {
     // Oops, we couldn't load the texture; we'll just return NULL.
     // But we do need a dummy texture to read in and ignore all of the
     // attributes.
-    PT(Texture) dummy = new Texture;
+    PT(Texture) dummy = new Texture("");
     dummy->fillin(scan, manager, has_rawdata);
 
   } else {

+ 27 - 10
panda/src/gobj/texture.h

@@ -32,6 +32,8 @@ class TextureContext;
 class FactoryParams;
 class PreparedGraphicsObjects;
 class HashFilename;
+class CullTraverser;
+class CullTraverserData;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : Texture
@@ -133,8 +135,13 @@ PUBLISHED:
 
 PUBLISHED:
   Texture(const string &name = string());
+protected:
+  Texture(const Texture &copy);
+PUBLISHED:
   virtual ~Texture();
 
+  virtual PT(Texture) make_copy();
+
   void setup_texture(TextureType texture_type,
                      int x_size, int y_size, int z_size,
                      ComponentType component_type, Format format);
@@ -154,17 +161,17 @@ PUBLISHED:
 
   void generate_normalization_cube_map(int size);
 
-  bool read(const Filename &fullpath, int z = 0,
-            int primary_file_num_channels = 0);
-  bool read(const Filename &fullpath, const Filename &alpha_fullpath, 
-            int z = 0,
-            int primary_file_num_channels = 0, int alpha_file_channel = 0);
+  virtual bool read(const Filename &fullpath, int z = 0,
+		    int primary_file_num_channels = 0);
+  virtual bool read(const Filename &fullpath, const Filename &alpha_fullpath, 
+		    int z = 0,
+		    int primary_file_num_channels = 0, int alpha_file_channel = 0);
   bool write(const Filename &fullpath, int z = 0) const;
 
   bool read_pages(const HashFilename &fullpath_template, int z_size = 0);
   bool write_pages(const HashFilename &fullpath_template);
 
-  bool load(const PNMImage &pnmimage, int z = 0);
+  virtual bool load(const PNMImage &pnmimage, int z = 0);
   bool store(PNMImage &pnmimage, int z = 0) const;
 
   INLINE bool has_filename() const;
@@ -203,7 +210,7 @@ PUBLISHED:
   INLINE Colorf get_border_color() const;
   INLINE bool uses_mipmaps() const;
 
-  INLINE bool has_ram_image() const;
+  virtual bool has_ram_image() const;
   INLINE bool might_have_ram_image() const;
   INLINE size_t get_ram_image_size() const;
   INLINE size_t get_expected_ram_image_size() const;
@@ -214,7 +221,7 @@ PUBLISHED:
   void set_ram_image(PTA_uchar image);
   void clear_ram_image();
   INLINE void set_keep_ram_image(bool keep_ram_image);
-  INLINE bool get_keep_ram_image() const;
+  virtual bool get_keep_ram_image() const;
 
   void prepare(PreparedGraphicsObjects *prepared_objects);
   bool release(PreparedGraphicsObjects *prepared_objects);
@@ -240,6 +247,7 @@ PUBLISHED:
   void set_format(Format format);
   void set_component_type(ComponentType component_type);
   INLINE void set_loaded_from_disk();
+  INLINE bool get_loaded_from_disk() const;
 
 public:
   INLINE bool get_match_framebuffer_format() const;
@@ -263,16 +271,25 @@ public:
 
   void mark_dirty(int flags_to_set);
 
+  virtual bool has_cull_callback() const;
+  virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
+
   static WrapMode string_wrap_mode(const string &string);
   static FilterType string_filter_type(const string &string);
 
 protected:
+  virtual void reconsider_dirty();
+  virtual void reload_ram_image();
+
   static int up_to_power_2(int value);
   static int down_to_power_2(int value);
+  bool reconsider_z_size(int z);
+  bool reconsider_image_properties(int x_size, int y_size, int num_components,
+				   ComponentType component_type, int z);
 
 private:
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
-  
+
   void consider_rescale(PNMImage &pnmimage);
   void consider_downgrade(PNMImage &pnmimage, int num_channels);
 
@@ -283,7 +300,7 @@ private:
   INLINE double get_unsigned_byte(int &index) const;
   INLINE double get_unsigned_short(int &index) const;
 
-private:
+protected:
   Filename _filename;
   Filename _alpha_filename;
   Filename _fullpath;

+ 1 - 0
panda/src/gobj/textureContext.I

@@ -86,6 +86,7 @@ clear_dirty_flags(int flags_to_clear) {
 ////////////////////////////////////////////////////////////////////
 INLINE int TextureContext::
 get_dirty_flags() const {
+  _texture->reconsider_dirty();
   return _dirty_flags;
 }
 

+ 13 - 25
panda/src/gobj/texturePool.I

@@ -25,7 +25,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE bool TexturePool::
 has_texture(const string &filename) {
-  return get_ptr()->ns_has_texture(filename);
+  return get_global_ptr()->ns_has_texture(filename);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -54,7 +54,7 @@ verify_texture(const string &filename) {
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 load_texture(const string &filename, int primary_file_num_channels) {
-  return get_ptr()->ns_load_texture(filename, primary_file_num_channels);
+  return get_global_ptr()->ns_load_texture(filename, primary_file_num_channels);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -69,7 +69,7 @@ load_texture(const string &filename, int primary_file_num_channels) {
 INLINE Texture *TexturePool::
 load_texture(const string &filename, const string &alpha_filename,
              int primary_file_num_channels, int alpha_file_channel) {
-  return get_ptr()->ns_load_texture(filename, alpha_filename, 
+  return get_global_ptr()->ns_load_texture(filename, alpha_filename, 
                                     primary_file_num_channels,
                                     alpha_file_channel);
 }
@@ -85,7 +85,7 @@ load_texture(const string &filename, const string &alpha_filename,
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 load_3d_texture(const string &filename_template) {
-  return get_ptr()->ns_load_3d_texture(filename_template);
+  return get_global_ptr()->ns_load_3d_texture(filename_template);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -99,7 +99,7 @@ load_3d_texture(const string &filename_template) {
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 load_cube_map(const string &filename_template) {
-  return get_ptr()->ns_load_cube_map(filename_template);
+  return get_global_ptr()->ns_load_cube_map(filename_template);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -115,7 +115,7 @@ load_cube_map(const string &filename_template) {
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 get_normalization_cube_map(int size) {
-  return get_ptr()->ns_get_normalization_cube_map(size);
+  return get_global_ptr()->ns_get_normalization_cube_map(size);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -129,7 +129,7 @@ get_normalization_cube_map(int size) {
 ////////////////////////////////////////////////////////////////////
 INLINE void TexturePool::
 add_texture(Texture *texture) {
-  get_ptr()->ns_add_texture(texture);
+  get_global_ptr()->ns_add_texture(texture);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -147,7 +147,7 @@ add_texture(Texture *texture) {
 ////////////////////////////////////////////////////////////////////
 INLINE void TexturePool::
 release_texture(Texture *texture) {
-  get_ptr()->ns_release_texture(texture);
+  get_global_ptr()->ns_release_texture(texture);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -158,7 +158,7 @@ release_texture(Texture *texture) {
 ////////////////////////////////////////////////////////////////////
 INLINE void TexturePool::
 release_all_textures() {
-  get_ptr()->ns_release_all_textures();
+  get_global_ptr()->ns_release_all_textures();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -171,7 +171,7 @@ release_all_textures() {
 ////////////////////////////////////////////////////////////////////
 INLINE int TexturePool::
 garbage_collect() {
-  return get_ptr()->ns_garbage_collect();
+  return get_global_ptr()->ns_garbage_collect();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -182,7 +182,7 @@ garbage_collect() {
 ////////////////////////////////////////////////////////////////////
 INLINE void TexturePool::
 list_contents(ostream &out) {
-  get_ptr()->ns_list_contents(out);
+  get_global_ptr()->ns_list_contents(out);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -193,7 +193,7 @@ list_contents(ostream &out) {
 ////////////////////////////////////////////////////////////////////
 INLINE void TexturePool::
 set_fake_texture_image(const string &filename) {
-  get_ptr()->_fake_texture_image = filename;
+  get_global_ptr()->_fake_texture_image = filename;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -226,17 +226,5 @@ has_fake_texture_image() {
 ////////////////////////////////////////////////////////////////////
 INLINE const string &TexturePool::
 get_fake_texture_image() {
-  return get_ptr()->_fake_texture_image;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexturePool::Constructor
-//       Access: Private
-//  Description: The constructor is not intended to be called
-//               directly; there's only supposed to be one TexturePool
-//               in the universe and it constructs itself.
-////////////////////////////////////////////////////////////////////
-INLINE TexturePool::
-TexturePool() {
-  _fake_texture_image = fake_texture_image;
+  return get_global_ptr()->_fake_texture_image;
 }

+ 78 - 19
panda/src/gobj/texturePool.cxx

@@ -20,6 +20,7 @@
 #include "config_gobj.h"
 #include "config_util.h"
 #include "config_express.h"
+#include "string_utils.h"
 #include "virtualFileSystem.h"
 
 
@@ -35,7 +36,79 @@ TexturePool *TexturePool::_global_ptr = (TexturePool *)NULL;
 ////////////////////////////////////////////////////////////////////
 void TexturePool::
 write(ostream &out) {
-  get_ptr()->ns_list_contents(out);
+  get_global_ptr()->ns_list_contents(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::register_texture_type
+//       Access: Public
+//  Description: Records a factory function that makes a Texture
+//               object of the appropriate type for one or more
+//               particular filename extensions.  The string
+//               extensions may be a string that contains
+//               space-separated list of extensions, case-insensitive.
+////////////////////////////////////////////////////////////////////
+void TexturePool::
+register_texture_type(MakeTextureFunc *func, const string &extensions) {
+  vector_string words;
+  extract_words(downcase(extensions), words);
+
+  vector_string::const_iterator wi;
+  for (wi = words.begin(); wi != words.end(); ++wi) {
+    _type_registry[*wi] = func;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::make_texture
+//       Access: Public
+//  Description: Creates a new Texture object of the appropriate type
+//               for the indicated filename extension, according to
+//               the types that have been registered via
+//               register_texture_type().
+////////////////////////////////////////////////////////////////////
+PT(Texture) TexturePool::
+make_texture(const string &extension) {
+  string c = downcase(extension);
+  TypeRegistry::const_iterator ti;
+  ti = _type_registry.find(extension);
+  if (ti != _type_registry.end()) {
+    return (*ti).second();
+  }
+  return new Texture;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::get_global_ptr
+//       Access: Public, Static
+//  Description: Initializes and/or returns the global pointer to the
+//               one TexturePool object in the system.
+////////////////////////////////////////////////////////////////////
+TexturePool *TexturePool::
+get_global_ptr() {
+  if (_global_ptr == (TexturePool *)NULL) {
+    _global_ptr = new TexturePool;
+  }
+  return _global_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TexturePool::Constructor
+//       Access: Private
+//  Description: The constructor is not intended to be called
+//               directly; there's only supposed to be one TexturePool
+//               in the universe and it constructs itself.
+////////////////////////////////////////////////////////////////////
+TexturePool::
+TexturePool() {
+  ConfigVariableString fake_texture_image
+    ("fake-texture-image", "",
+     PRC_DESC("Set this to enable a speedy-load mode in which you don't care "
+	      "what the world looks like, you just want it to load in minimal "
+	      "time.  This causes all texture loads via the TexturePool to use "
+	      "the same texture file, which will presumably only be loaded "
+	      "once."));
+  _fake_texture_image = fake_texture_image;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -91,7 +164,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels) {
 
   gobj_cat.info()
     << "Loading texture " << filename << "\n";
-  PT(Texture) tex = new Texture;
+  PT(Texture) tex = make_texture(filename.get_extension());
   if (!tex->read(filename, 0, primary_file_num_channels)) {
     // This texture was not found or could not be read.
     report_texture_unreadable(filename);
@@ -139,7 +212,7 @@ ns_load_texture(const Filename &orig_filename,
   gobj_cat.info()
     << "Loading texture " << filename << " and alpha component "
     << alpha_filename << endl;
-  PT(Texture) tex = new Texture;
+  PT(Texture) tex = make_texture(filename.get_extension());
   if (!tex->read(filename, alpha_filename, 0, primary_file_num_channels,
                  alpha_file_channel)) {
     // This texture was not found or could not be read.
@@ -186,7 +259,7 @@ ns_load_3d_texture(const HashFilename &filename_template) {
 
   gobj_cat.info()
     << "Loading 3-d texture " << hash_filename << "\n";
-  PT(Texture) tex = new Texture;
+  PT(Texture) tex = make_texture(hash_filename.get_extension());
   tex->setup_3d_texture();
   if (!tex->read_pages(hash_filename)) {
     // This texture was not found or could not be read.
@@ -231,7 +304,7 @@ ns_load_cube_map(const HashFilename &filename_template) {
 
   gobj_cat.info()
     << "Loading cube map texture " << hash_filename << "\n";
-  PT(Texture) tex = new Texture;
+  PT(Texture) tex = make_texture(hash_filename.get_extension());
   tex->setup_cube_map();
   if (!tex->read_pages(hash_filename)) {
     // This texture was not found or could not be read.
@@ -392,17 +465,3 @@ report_texture_unreadable(const Filename &filename) const {
       << "Texture \"" << filename << "\" exists but cannot be read.\n";
   }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexturePool::get_ptr
-//       Access: Private, Static
-//  Description: Initializes and/or returns the global pointer to the
-//               one TexturePool object in the system.
-////////////////////////////////////////////////////////////////////
-TexturePool *TexturePool::
-get_ptr() {
-  if (_global_ptr == (TexturePool *)NULL) {
-    _global_ptr = new TexturePool;
-  }
-  return _global_ptr;
-}

+ 12 - 3
panda/src/gobj/texturePool.h

@@ -68,8 +68,16 @@ PUBLISHED:
   
   static void write(ostream &out);
 
+public:
+  typedef PT(Texture) MakeTextureFunc();
+  void register_texture_type(MakeTextureFunc *func, const string &extensions);
+
+  PT(Texture) make_texture(const string &extension);
+
+  static TexturePool *get_global_ptr();
+
 private:
-  INLINE TexturePool();
+  TexturePool();
 
   bool ns_has_texture(const Filename &orig_filename);
   Texture *ns_load_texture(const Filename &orig_filename, int primary_file_num_channels);
@@ -89,14 +97,15 @@ private:
 
   void report_texture_unreadable(const Filename &filename) const;
 
-  static TexturePool *get_ptr();
-
   static TexturePool *_global_ptr;
   typedef phash_map<string,  PT(Texture), string_hash> Textures;
   Textures _textures;
   string _fake_texture_image;
 
   PT(Texture) _normalization_cube_map;
+
+  typedef pmap<string, MakeTextureFunc *> TypeRegistry;
+  TypeRegistry _type_registry;
 };
 
 #include "texturePool.I"

+ 149 - 0
panda/src/gobj/videoTexture.I

@@ -0,0 +1,149 @@
+// Filename: videoTexture.I
+// Created by:  drose (21Sep05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::set_power_2
+//       Access: Published
+//  Description: Sets the flag that indicates whether a newly-loaded
+//               VideoTexture will be constrained to dimensions that are
+//               a power of 2 or not.  If true, then a newly-loaded
+//               video stream will be set within the smallest power of
+//               2 texture that will fit it; if false, a newly-loaded
+//               video stream will be set within a texture that
+//               exactly fits it, even if that means creating a
+//               texture whose dimensions are not a power of 2.
+//
+//               This must be set before the first call to read().
+//               The default value is false if the Config.prc variable
+//               textures-power-2 is "none", true otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE void VideoTexture::
+set_power_2(bool power_2) {
+  _power_2 = power_2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::get_power_2
+//       Access: Published
+//  Description: Returns the flag that indicates whether a
+//               newly-loaded VideoTexture will be constrained to
+//               dimensions that are a power of 2 or not.  See
+//               set_power_2().
+////////////////////////////////////////////////////////////////////
+INLINE bool VideoTexture::
+get_power_2() const {
+  return _power_2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::get_video_width
+//       Access: Published
+//  Description: Returns the width in texels of the source video
+//               stream.  This is not necessarily the width of the
+//               actual texture, since the texture may have been
+//               expanded to raise it to a power of 2.
+////////////////////////////////////////////////////////////////////
+INLINE int VideoTexture::
+get_video_width() const {
+  return _video_width;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::get_video_height
+//       Access: Published
+//  Description: Returns the height in texels of the source video
+//               stream.  This is not necessarily the height of the
+//               actual texture, since the texture may have been
+//               expanded to raise it to a power of 2.
+////////////////////////////////////////////////////////////////////
+INLINE int VideoTexture::
+get_video_height() const {
+  return _video_height;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::get_tex_scale
+//       Access: Published
+//  Description: Returns a scale pair that is suitable for applying to
+//               geometry via NodePath::set_tex_scale(), which will
+//               convert texture coordinates on the geometry from the
+//               range 0..1 into the appropriate range to render the
+//               video part of the texture.
+//
+//               This is necessary in the event the video source is
+//               not a power of two and set_power_2() is true.  In
+//               this case, the video image will be mapped to the
+//               lower-left corner of the texture, and the rest of the
+//               texture space will be unused; so we will need to
+//               remap any texture coordinates to fill the space
+//               correctly.
+////////////////////////////////////////////////////////////////////
+INLINE LVecBase2f VideoTexture::
+get_tex_scale() const {
+  if (_video_width == 0 || _video_height == 0 ||
+      _x_size == 0 || _y_size == 0) {
+    LVecBase2f(1.0f, 1.0f);
+  }
+  return LVecBase2f((float)_video_width / _x_size,
+		    (float)_video_height / _y_size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::set_video_size
+//       Access: Protected
+//  Description: Should be called by a derived class to set the size
+//               of the video when it is loaded.
+////////////////////////////////////////////////////////////////////
+INLINE void VideoTexture::
+set_video_size(int video_width, int video_height) {
+  _video_width = video_width;
+  _video_height = video_height;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::consider_update
+//       Access: Protected
+//  Description: Calls update_frame() if the current frame has
+//               changed.
+////////////////////////////////////////////////////////////////////
+INLINE void VideoTexture::
+consider_update() {
+  int this_frame = ClockObject::get_global_clock()->get_frame_count();
+  if (this_frame != _last_frame_update) {
+    int frame = get_frame();
+    if (_current_frame != frame) {
+      update_frame(frame);
+      _current_frame = frame;
+    }
+    _last_frame_update = this_frame;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::clear_current_frame
+//       Access: Protected
+//  Description: Resets the record of the current frame so that it
+//               will be forced to reload the next time it is
+//               requested.
+////////////////////////////////////////////////////////////////////
+INLINE void VideoTexture::
+clear_current_frame() {
+  _last_frame_update = 0;
+  _current_frame = -1;
+}

+ 152 - 0
panda/src/gobj/videoTexture.cxx

@@ -0,0 +1,152 @@
+// Filename: videoTexture.cxx
+// Created by:  drose (21Sep05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandabase.h"
+
+#include "videoTexture.h"
+#include "clockObject.h"
+#include "config_gobj.h"
+
+TypeHandle VideoTexture::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::Constructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+VideoTexture::
+VideoTexture(const string &name) : 
+  Texture(name) 
+{
+  _power_2 = (textures_power_2 != ATS_none);
+  _video_width = 0;
+  _video_height = 0;
+
+  _last_frame_update = 0;
+  _current_frame = -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::Copy Constructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+VideoTexture::
+VideoTexture(const VideoTexture &copy) : 
+  Texture(copy),
+  AnimInterface(copy),
+  _power_2(copy._power_2),
+  _video_width(copy._video_width),
+  _video_height(copy._video_height),
+  _last_frame_update(copy._last_frame_update),
+  _current_frame(copy._current_frame)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::has_ram_image
+//       Access: Published, Virtual
+//  Description: Returns true if the Texture has its image contents
+//               available in main RAM, false if it exists only in
+//               texture memory or in the prepared GSG context.
+////////////////////////////////////////////////////////////////////
+bool VideoTexture::
+has_ram_image() const {
+  int this_frame = ClockObject::get_global_clock()->get_frame_count();
+  if (this_frame != _last_frame_update) {
+    return false;
+  }
+  return !_image.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::get_keep_ram_image
+//       Access: Published, Virtual
+//  Description: Returns the flag that indicates whether this Texture
+//               is eligible to have its main RAM copy of the texture
+//               memory dumped when the texture is prepared for
+//               rendering.  See set_keep_ram_image().
+////////////////////////////////////////////////////////////////////
+bool VideoTexture::
+get_keep_ram_image() const {
+  // An VideoTexture should never dump its RAM image.
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::has_cull_callback
+//       Access: Public, Virtual
+//  Description: Should be overridden by derived classes to return
+//               true if cull_callback() has been defined.  Otherwise,
+//               returns false to indicate cull_callback() does not
+//               need to be called for this node during the cull
+//               traversal.
+////////////////////////////////////////////////////////////////////
+bool VideoTexture::
+has_cull_callback() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::cull_callback
+//       Access: Public, Virtual
+//  Description: If has_cull_callback() returns true, this function
+//               will be called during the cull traversal to perform
+//               any additional operations that should be performed at
+//               cull time.
+//
+//               This is called each time the Texture is discovered
+//               applied to a Geom in the traversal.  It should return
+//               true if the Geom is visible, false if it should be
+//               omitted.
+////////////////////////////////////////////////////////////////////
+bool VideoTexture::
+cull_callback(CullTraverser *, const CullTraverserData &) const {
+  // Strictly speaking, the cull_callback() method isn't necessary for
+  // VideoTexture, since the get_ram_image() function is already
+  // overloaded to update itself if necessary.  However, we define it
+  // anyway, to move the update calculation into the cull traversal
+  // rather than the draw traversal.
+  ((VideoTexture *)this)->reconsider_dirty();
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::reconsider_dirty
+//       Access: Protected, Virtual
+//  Description: Called by TextureContext to give the Texture a chance
+//               to mark itself dirty before rendering, if necessary.
+////////////////////////////////////////////////////////////////////
+void VideoTexture::
+reconsider_dirty() {
+  consider_update();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VideoTexture::reload_ram_image
+//       Access: Protected, Virtual
+//  Description: Called when the Texture image is required but the ram
+//               image is not available, this will reload it from disk
+//               or otherwise do whatever is required to make it
+//               available, if possible.
+////////////////////////////////////////////////////////////////////
+void VideoTexture::
+reload_ram_image() {
+  consider_update();
+}
+

+ 93 - 0
panda/src/gobj/videoTexture.h

@@ -0,0 +1,93 @@
+// Filename: videoTexture.h
+// Created by:  drose (21Sep05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef VIDEOTEXTURE_H
+#define VIDEOTEXTURE_H
+
+#include "pandabase.h"
+#include "texture.h"
+#include "animInterface.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : VideoTexture
+// Description : The base class for a family of animated Textures that
+//               take their input from a video source, such as a movie
+//               file.  These Textures may be stopped, started,
+//               etc. using the AnimInterface controls, similar to an
+//               animated character.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA VideoTexture : public Texture, public AnimInterface {
+protected:
+  VideoTexture(const string &name);
+  VideoTexture(const VideoTexture &copy);
+
+PUBLISHED:
+  INLINE void set_power_2(bool power_2);
+  INLINE bool get_power_2() const;
+
+  virtual bool has_ram_image() const;
+  virtual bool get_keep_ram_image() const;
+
+  INLINE int get_video_width() const;
+  INLINE int get_video_height() const;
+  INLINE LVecBase2f get_tex_scale() const;
+
+public:
+  virtual bool has_cull_callback() const;
+  virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
+
+protected:
+  INLINE void set_video_size(int video_width, int video_height);
+
+  virtual void reconsider_dirty();
+  virtual void reload_ram_image();
+
+  INLINE void consider_update();
+  INLINE void clear_current_frame();
+  virtual void update_frame(int frame)=0;
+
+private:
+  bool _power_2;
+  int _video_width;
+  int _video_height;
+  int _last_frame_update;
+  int _current_frame;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    Texture::init_type();
+    AnimInterface::init_type();
+    register_type(_type_handle, "VideoTexture",
+                  Texture::get_class_type(),
+		  AnimInterface::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "videoTexture.I"
+
+#endif

+ 4 - 4
panda/src/grutil/Sources.pp

@@ -1,7 +1,7 @@
 #define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
                    dtoolutil:c dtoolbase:c dtool:m
 
-#define USE_PACKAGES cv
+#define USE_PACKAGES opencv
 
 #begin lib_target
   #define TARGET grutil
@@ -16,13 +16,13 @@
     frameRateMeter.I frameRateMeter.h \
     lineSegs.I lineSegs.h \
     multitexReducer.I multitexReducer.h multitexReducer.cxx \
-    aviTexture.h aviTexture.I 
+    openCVTexture.h openCVTexture.I 
     
   #define INCLUDED_SOURCES \
     cardMaker.cxx \
     config_grutil.cxx \
     frameRateMeter.cxx \
-    aviTexture.cxx \    	 
+    openCVTexture.cxx \    	 
     lineSegs.cxx 
     
 
@@ -31,7 +31,7 @@
     frameRateMeter.I frameRateMeter.h \
     lineSegs.I lineSegs.h \
     multitexReducer.I multitexReducer.h \
-    aviTexture.I aviTexture.h
+    openCVTexture.I openCVTexture.h
 
   #define IGATESCAN all
 

+ 0 - 134
panda/src/grutil/aviTexture.I

@@ -1,134 +0,0 @@
-// Filename: aviTexture.I
-// Created by:  zacpavlov (19Aug05)
-//
-////////////////////////////////////////////////////////////////////
-//
-// 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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::obtain_ram
-//       Access: Private
-//  Description: Grabs a fresh ram buffer to mess with
-//
-////////////////////////////////////////////////////////////////////
-INLINE bool AviTexture::
-obtain_ram() {
-  _buf = modify_ram_image();
-
-  if (_buf) {
-    return true;
-  }
-  return false;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::get_time
-//       Access: Published
-//  Description: returns the ratio between 0 and 1 that the movie is
-//               positioned at. Disabled for camera input
-//
-////////////////////////////////////////////////////////////////////
-INLINE float AviTexture::
-get_time() {
-  if (!_isCamera) {
-    return _time;
-  }
-  return 0.0f;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::set_time
-//       Access: Published
-//  Description: sets the time on the opencv video reader. Disabled 
-//               for camera input
-//
-////////////////////////////////////////////////////////////////////
-INLINE void AviTexture::
-set_time(float t) {
-  if (_isCamera) {
-    return;
-  }
-  if (t >= 0 && t <= 1) { 
-    _time=t;
-  } 
-  if (_capture) {
-    cvSetCaptureProperty(_capture,CV_CAP_PROP_POS_AVI_RATIO,t);
-    _current_frame = cvGetCaptureProperty(_capture,CV_CAP_PROP_POS_FRAMES);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::set_fps
-//       Access: Published
-//  Description: sets the fps for the movie, and affects frame receives
-//               from camera. Note, since frame update is controlled
-//               by python, this item is sort of arbitrary
-////////////////////////////////////////////////////////////////////
-INLINE void AviTexture::
-set_fps(float fps) {
-  if (fps >= 0) {
-    _fps = fps;
-  } else {
-    return;
-  }
-  if (_isCamera && _capture) {
-    cvSetCaptureProperty(_capture,CV_CAP_PROP_FPS,int(fps));
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::get_fps
-//       Access: Published
-//  Description: returns the fps as recieved from movie
-////////////////////////////////////////////////////////////////////
-INLINE float AviTexture::
-get_fps() {
-  return _fps;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::get_total_frames
-//       Access: Published
-//  Description: returns the total amount of frames
-////////////////////////////////////////////////////////////////////
-INLINE int AviTexture::
-get_total_frames() {
-  return _total_frames;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::get_current_frame
-//       Access: Published
-//  Description: returns current frame (base 0)
-////////////////////////////////////////////////////////////////////
-INLINE int AviTexture::
-get_current_frame() {
-  return _current_frame;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::set_current_frame
-//       Access: Published
-//  Description: sets the current frame (base 0)
-////////////////////////////////////////////////////////////////////
-INLINE void AviTexture::
-set_current_frame(int frame) {
-  if (frame>=0 && frame<_total_frames) {
-    _current_frame = frame;
-    cvSetCaptureProperty(_capture,CV_CAP_PROP_POS_FRAMES,_current_frame);
-    _time = cvGetCaptureProperty(_capture,CV_CAP_PROP_POS_AVI_RATIO);
-  }
-}

+ 0 - 163
panda/src/grutil/aviTexture.cxx

@@ -1,163 +0,0 @@
-// Filename: aviTexture.cxx
-// Created by:  zacpavlov (19Aug05)
-//
-////////////////////////////////////////////////////////////////////
-//
-// 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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "pandabase.h"
-
-#ifdef HAVE_CV
-#include "aviTexture.h"
-
-TypeHandle AviTexture::_type_handle;
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::Constructor
-//       Access: Published
-//  Description: Sets up the texture to read frames from a camera
-////////////////////////////////////////////////////////////////////
-AviTexture::
-AviTexture() {
-  _isCamera = true;
-  _capture = cvCaptureFromCAM(0);
-  _buf = NULL;
-  _magicNum = 0;
-  _time = 0.0f;
-  _fps = 30.0f;
-  _total_frames = 0;
-  _current_frame = 0;
-  
-  if (_capture) {
-    cvSetCaptureProperty(_capture, CV_CAP_PROP_FPS,_fps);
-    _width = cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_WIDTH);
-    _height = cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_HEIGHT);
-
-    if (_width < _height) {
-      gen_tex(_width);
-    } else {
-      gen_tex(_height);
-    }
-  }             
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::Constructor
-//       Access: Published
-//  Description: Defines the texture as a movie texture. 
-//               TODO: Make this search the panda paths
-////////////////////////////////////////////////////////////////////
-AviTexture::
-AviTexture(const string &filename) {
-  _isCamera = false;
-  _capture = cvCaptureFromFile(filename.c_str());
-  _buf = NULL;
-  _magicNum = 0; 
-  _time = 0.0f;
-  _fps = 30.0f;
-  _total_frames = 0;
-  _current_frame = 0;   
-
-  if (_capture) {
-    _fps = cvGetCaptureProperty(_capture, CV_CAP_PROP_FPS);
-    _total_frames = cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_COUNT);
-    _width = cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_WIDTH);
-    _height = cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_HEIGHT);
-
-    if (_width < _height) {
-      gen_tex(_width);
-    } else {
-      gen_tex(_height);
-    }
-  }             
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::Destructor
-//       Access: Published
-//  Description: Destructor. Release the camera or video stream
-////////////////////////////////////////////////////////////////////
-AviTexture::
-~AviTexture() {
-  cvReleaseCapture(&_capture);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::gen_tex
-//       Access: Published
-//  Description: Tries to find the largest texture that will fit
-//               inside the video stream. TODO: allow for fit around
-////////////////////////////////////////////////////////////////////
-void AviTexture::
-gen_tex(int magicNum) {
-  int size = down_to_power_2(magicNum);
-
-  setup_2d_texture(size, size, Texture::T_unsigned_byte, Texture::F_rgb8);
-  _magicNum = size;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AviTexture::update
-//       Access: Published
-//  Description: Grabs the next frame off the camera or avi file
-//               Returns false if the capture fails or reached EOF 
-////////////////////////////////////////////////////////////////////
-bool AviTexture::
-update() {
-  int begx, endx, begy, endy;
-  IplImage *frame = 0;
-  int xs, ys;
-
-  if (_capture) {
-    if (_time == 1.0f) {
-      return false;
-    }
-    frame = cvQueryFrame( _capture );
-
-    if (frame) {
-      _time = cvGetCaptureProperty(_capture, CV_CAP_PROP_POS_AVI_RATIO);
-      _current_frame = cvGetCaptureProperty(_capture, CV_CAP_PROP_POS_FRAMES);
-      if (!obtain_ram()) {
-	return false;
-      }
-      begx = (_width - _magicNum) / 2.0;
-      endx = _width - begx;
-      begy = (_height - _magicNum) / 2.0;
-      endy = _height - begy;
-      
-      if (_buf) {
-	xs = get_x_size();
-	ys = get_y_size();
-	
-	if (get_num_components() != 3) {
-	  return false;
-        }
-	
-	for (int i = begy; i < endy; ++i) {
-	  memcpy(_buf + ((i - begy) * xs * 3),
-                 frame->imageData + i * _width * 3 + begx * 3,
-                 xs * 3);
-        }
-	
-	return true;
-      }
-    }
-  }
-
-  return false;
-}
-
-#endif  // HAVE_CV
-

+ 0 - 94
panda/src/grutil/aviTexture.h

@@ -1,94 +0,0 @@
-// Filename: aviTexture.h
-// Created by:  zacpavlov (19Aug05)
-//
-////////////////////////////////////////////////////////////////////
-//
-// 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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef AVITEXTURE_H
-#define AVITEXTURE_H
-
-#include "pandabase.h"
-#ifdef HAVE_CV
-
-#include "texture.h"
-#include <cxcore.h>
-#include <cv.h>
-#include <highgui.h>
-
-////////////////////////////////////////////////////////////////////
-//       Class : AviTexture
-// Description : A specialization on Texture that takes its input
-//               using the CV library, to produce an animated texture,
-//               with its source taken from an .avi file or from a
-//               camera input.
-//
-//               Presently, it is necessary for the application to
-//               call update() periodically to advance to the next
-//               frame.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA AviTexture : public Texture {
-PUBLISHED:
-  AviTexture();
-  AviTexture(const string &filename);
-  ~AviTexture();
-
-  INLINE void set_time(float t);
-  INLINE float get_time();
-  INLINE float get_fps();
-  INLINE void set_fps(float fps);
-  INLINE int get_total_frames();
-  INLINE int get_current_frame();
-  INLINE void set_current_frame(int frame);
-  bool update();
-
-private:    
-  void gen_tex(int magicNum);
-  INLINE bool obtain_ram();
-
-  int _magicNum;
-  PTA_uchar _buf;
-  CvCapture * _capture;
-  float _time;
-  bool _isCamera;
-  float _fps;
-  int _total_frames;
-  int _current_frame;
-  int _width;
-  int _height;
-  
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    Texture::init_type();
-    register_type(_type_handle, "AviTexture",
-                  Texture::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-
-  static TypeHandle _type_handle;
-};
-
-#include "aviTexture.I"
-
-#endif  // HAVE_CV
-
-#endif

+ 11 - 4
panda/src/grutil/config_grutil.cxx

@@ -18,7 +18,9 @@
 
 #include "config_grutil.h"
 #include "frameRateMeter.h"
-#include "aviTexture.h"
+#include "openCVTexture.h"
+#include "pandaSystem.h"
+#include "texturePool.h"
 
 #include "dconfig.h"
 
@@ -63,8 +65,13 @@ init_libgrutil() {
 
   FrameRateMeter::init_type();
 
-#ifdef HAVE_CV
-  AviTexture::init_type();
-#endif // HAVE_CV
+#ifdef HAVE_OPENCV
+  OpenCVTexture::init_type();
+
+  PandaSystem *ps = PandaSystem::get_global_ptr();
+  ps->add_system("OpenCV");
+  TexturePool *ts = TexturePool::get_global_ptr();
+  ts->register_texture_type(OpenCVTexture::make_texture, "avi");
+#endif // HAVE_OPENCV
 }
 

+ 1 - 1
panda/src/grutil/grutil_composite1.cxx

@@ -2,5 +2,5 @@
 #include "config_grutil.cxx"
 #include "lineSegs.cxx"
 #include "frameRateMeter.cxx"
-#include "aviTexture.cxx"
+#include "openCVTexture.cxx"
 

+ 70 - 0
panda/src/grutil/openCVTexture.I

@@ -0,0 +1,70 @@
+// Filename: openCVTexture.I
+// Created by:  zacpavlov (19Aug05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoStream::is_valid
+//       Access: Public
+//  Description: Returns true if this stream is open and ready, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool OpenCVTexture::VideoStream::
+is_valid() const {
+  return (_capture != NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoStream::is_from_file
+//       Access: Public
+//  Description: Returns true if this stream takes its input from a
+//               video file, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool OpenCVTexture::VideoStream::
+is_from_file() const {
+  return !_filename.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoPage::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE OpenCVTexture::VideoPage::
+VideoPage() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoPage::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE OpenCVTexture::VideoPage::
+VideoPage(const OpenCVTexture::VideoPage &copy) :
+  _color(copy._color),
+  _alpha(copy._alpha)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoPage::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE OpenCVTexture::VideoPage::
+~VideoPage() {
+}

+ 526 - 0
panda/src/grutil/openCVTexture.cxx

@@ -0,0 +1,526 @@
+// Filename: openCVTexture.cxx
+// Created by:  zacpavlov (19Aug05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandabase.h"
+
+#ifdef HAVE_OPENCV
+#include "openCVTexture.h"
+#include "clockObject.h"
+#include "config_gobj.h"
+#include "config_grutil.h"
+
+TypeHandle OpenCVTexture::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::Constructor
+//       Access: Published
+//  Description: Sets up the texture to read frames from a camera
+////////////////////////////////////////////////////////////////////
+OpenCVTexture::
+OpenCVTexture(const string &name) : 
+  VideoTexture(name) 
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::Copy Constructor
+//       Access: Protected
+//  Description: Use OpenCVTexture::make_copy() to make a duplicate copy of
+//               an existing OpenCVTexture.
+////////////////////////////////////////////////////////////////////
+OpenCVTexture::
+OpenCVTexture(const OpenCVTexture &copy) : 
+  VideoTexture(copy),
+  _pages(copy._pages)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+OpenCVTexture::
+~OpenCVTexture() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::make_copy
+//       Access: Published, Virtual
+//  Description: Returns a new copy of the same Texture.  This copy,
+//               if applied to geometry, will be copied into texture
+//               as a separate texture from the original, so it will
+//               be duplicated in texture memory (and may be
+//               independently modified if desired).
+//               
+//               If the Texture is an OpenCVTexture, the resulting
+//               duplicate may be animated independently of the
+//               original.
+////////////////////////////////////////////////////////////////////
+PT(Texture) OpenCVTexture::
+make_copy() {
+  return new OpenCVTexture(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::from_camera
+//       Access: Published, Virtual
+//  Description: Sets up the OpenCVTexture (or the indicated page, if z
+//               is specified) to accept its input from the camera
+//               with the given index number, or the default camera if
+//               the index number is -1 or unspecified.
+////////////////////////////////////////////////////////////////////
+bool OpenCVTexture::
+from_camera(int camera_index, int z) {
+  if (!reconsider_z_size(z)) {
+    return false;
+  }
+  nassertr(z >= 0 && z < get_z_size(), false);
+
+  VideoPage &page = modify_page(z);
+  page._alpha.clear();
+  if (!page._color.from_camera(camera_index)) {
+    return false;
+  }
+
+  int width = cvGetCaptureProperty(page._color._capture, CV_CAP_PROP_FRAME_WIDTH);
+  int height = cvGetCaptureProperty(page._color._capture, CV_CAP_PROP_FRAME_HEIGHT);
+
+  if (!reconsider_video_properties(page._color, 3, z)) {
+    page._color.clear();
+    return false;
+  }
+
+  set_loaded_from_disk();
+  clear_current_frame();
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::read
+//       Access: Published, Virtual
+//  Description: Takes the video image from the indicated filename.
+//               If the filename is not a video file, attempts to read
+//               it as a still image instead.
+////////////////////////////////////////////////////////////////////
+bool OpenCVTexture::
+read(const Filename &fullpath, int z, int) {
+  if (!reconsider_z_size(z)) {
+    return false;
+  }
+  nassertr(z >= 0 && z < get_z_size(), false);
+
+  VideoPage &page = modify_page(z);
+  page._alpha.clear();
+  if (!page._color.read(fullpath)) {
+    grutil_cat.error()
+      << "OpenCV couldn't read " << fullpath << " as video.\n";
+    return false;
+  }
+
+  if (!has_name()) {
+    set_name(fullpath.get_basename_wo_extension());
+  }
+  if (!has_filename()) {
+    set_filename(fullpath);
+    clear_alpha_filename();
+  }
+
+  set_fullpath(fullpath);
+  clear_alpha_fullpath();
+
+  _primary_file_num_channels = 3;
+  _alpha_file_channel = 0;
+
+  if (!reconsider_video_properties(page._color, 3, z)) {
+    page._color.clear();
+    return false;
+  }
+
+  set_loaded_from_disk();
+  clear_current_frame();
+  
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::read
+//       Access: Published, Virtual
+//  Description: Combines a color and alpha video image from the two
+//               indicated filenames.  Both must be the same kind of
+//               video with similar properties.
+////////////////////////////////////////////////////////////////////
+bool OpenCVTexture::
+read(const Filename &fullpath, const Filename &alpha_fullpath,
+     int z, int, int alpha_file_channel) {
+  if (!reconsider_z_size(z)) {
+    return false;
+  }
+  nassertr(z >= 0 && z < get_z_size(), false);
+
+  VideoPage &page = modify_page(z);
+  if (!page._color.read(fullpath)) {
+    grutil_cat.error()
+      << "OpenCV couldn't read " << fullpath << " as video.\n";
+    return false;
+  }
+  if (!page._alpha.read(alpha_fullpath)) {
+    grutil_cat.error()
+      << "OpenCV couldn't read " << alpha_fullpath << " as video.\n";
+    page._color.clear();
+    return false;
+  }
+
+  if (!has_name()) {
+    set_name(fullpath.get_basename_wo_extension());
+  }
+  if (!has_filename()) {
+    set_filename(fullpath);
+    set_alpha_filename(alpha_fullpath);
+  }
+
+  set_fullpath(fullpath);
+  set_alpha_fullpath(alpha_fullpath);
+
+  _primary_file_num_channels = 3;
+  _alpha_file_channel = alpha_file_channel;
+
+  if (!reconsider_video_properties(page._color, 4, z)) {
+    page._color.clear();
+    page._alpha.clear();
+    return false;
+  }
+
+  if (!reconsider_video_properties(page._alpha, 4, z)) {
+    page._color.clear();
+    page._alpha.clear();
+    return false;
+  }
+
+  set_loaded_from_disk();
+  clear_current_frame();
+  
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::load
+//       Access: Published, Virtual
+//  Description: Resets the texture (or the particular level of the
+//               texture) to the indicated static image.
+////////////////////////////////////////////////////////////////////
+bool OpenCVTexture::
+load(const PNMImage &pnmimage, int z) {
+  if (z <= (int)_pages.size()) {
+    VideoPage &page = modify_page(z);
+    page._color.clear();
+    page._alpha.clear();
+  }
+
+  return Texture::load(pnmimage, z);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::modify_page
+//       Access: Private
+//  Description: Returns a reference to the zth VideoPage (level) of
+//               the texture.  In the case of a 2-d texture, there is
+//               only one page, level 0; but cube maps and 3-d
+//               textures have more.
+////////////////////////////////////////////////////////////////////
+OpenCVTexture::VideoPage &OpenCVTexture::
+modify_page(int z) {
+  nassertr(z < _z_size, _pages[0]);
+  while (z >= (int)_pages.size()) {
+    _pages.push_back(VideoPage());
+  }
+  return _pages[z];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::reconsider_video_properties
+//       Access: Private
+//  Description: Resets the internal Texture properties when a new
+//               video file is loaded.  Returns true if the new image
+//               is valid, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool OpenCVTexture::
+reconsider_video_properties(const OpenCVTexture::VideoStream &stream, 
+			    int num_components, int z) {
+  double frame_rate = 0.0f;
+  int num_frames = 0;
+
+  if (stream.is_from_file()) {
+    frame_rate = cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FPS);
+    num_frames = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_COUNT);
+  }
+  int width = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_WIDTH);
+  int height = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_HEIGHT);
+
+  int x_size = width;
+  int y_size = height;
+
+  if (get_power_2()) {
+    x_size = up_to_power_2(width);
+    y_size = up_to_power_2(height);
+  }
+
+  if (!reconsider_image_properties(x_size, y_size, num_components,
+				   T_unsigned_byte, z)) {
+    return false;
+  }
+
+  if (_loaded_from_disk && 
+      (get_video_width() != width || get_video_height() != height ||
+       get_num_frames() != num_frames || get_frame_rate() != frame_rate)) {
+    grutil_cat.error()
+      << "Video properties have changed for texture " << get_name()
+      << " level " << z << ".\n";
+    return false;
+  }
+
+  set_frame_rate(frame_rate);
+  set_num_frames(num_frames);
+  set_video_size(width, height);
+
+  // By default, the newly-loaded video stream will immediately start
+  // looping.
+  loop(true);
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::make_texture
+//       Access: Public, Static
+//  Description: A factory function to make a new OpenCVTexture, used
+//               to pass to the TexturePool.
+////////////////////////////////////////////////////////////////////
+PT(Texture) OpenCVTexture::
+make_texture() {
+  return new OpenCVTexture;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::update_frame
+//       Access: Protected, Virtual
+//  Description: Called once per frame, as needed, to load the new
+//               image contents.
+////////////////////////////////////////////////////////////////////
+void OpenCVTexture::
+update_frame(int frame) {
+  int max_z = max(_z_size, (int)_pages.size());
+  for (int z = 0; z < max_z; ++z) {
+    VideoPage &page = _pages[z];
+    if (page._color.is_valid() || page._alpha.is_valid()) {
+      modify_ram_image();
+    }
+    if (page._color.is_valid()) {
+      nassertv(get_num_components() >= 3 && get_component_width() == 1);
+	
+      const unsigned char *source = page._color.get_frame_data(frame);
+      if (source != NULL) {
+	nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
+	unsigned char *dest = _image.p() + get_expected_ram_page_size() * z;
+	  
+	int dest_row_width = (_x_size * _num_components * _component_width);
+	int source_row_width = get_video_width() * 3;
+	  
+	if (get_num_components() == 3) {
+	  // The easy case--copy the whole thing in, row by row.
+	  for (int y = 0; y < get_video_height(); ++y) {
+	    memcpy(dest, source, source_row_width);
+	    dest += dest_row_width;
+	    source += source_row_width;
+	  }
+	    
+	} else {
+	  // The harder case--interleave the color in with the alpha,
+	  // pixel by pixel.
+	  nassertv(get_num_components() == 4);
+	  for (int y = 0; y < get_video_height(); ++y) {
+	    int dx = 0;
+	    int sx = 0;
+	    for (int x = 0; x < get_video_width(); ++x) {
+	      dest[dx] = source[sx];
+	      dest[dx + 1] = source[sx + 1];
+	      dest[dx + 2] = source[sx + 2];
+	      dx += 4;
+	      sx += 3;
+	    }
+	    dest += dest_row_width;
+	    source += source_row_width;
+	  }
+	}
+      }
+    }
+    if (page._alpha.is_valid()) {
+      nassertv(get_num_components() == 4 && get_component_width() == 1);
+	
+      const unsigned char *source = page._alpha.get_frame_data(frame);
+      if (source != NULL) {
+	nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
+	unsigned char *dest = _image.p() + get_expected_ram_page_size() * z;
+	  
+	int dest_row_width = (_x_size * _num_components * _component_width);
+	int source_row_width = get_video_width() * 3;
+	  
+	// Interleave the alpha in with the color, pixel by pixel.
+	// Even though the alpha will probably be a grayscale video,
+	// the OpenCV library presents it as RGB.
+	for (int y = 0; y < get_video_height(); ++y) {
+	  int dx = 3;
+	  int sx = _alpha_file_channel;
+	  for (int x = 0; x < get_video_width(); ++x) {
+	    dest[dx] = source[sx];
+	    dx += 4;
+	    sx += 3;
+	  }
+	  dest += dest_row_width;
+	  source += source_row_width;
+	}
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoStream::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+OpenCVTexture::VideoStream::
+VideoStream() :
+  _capture(NULL),
+  _camera_index(-1),
+  _next_frame(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoStream::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+OpenCVTexture::VideoStream::
+VideoStream(const OpenCVTexture::VideoStream &copy) :
+  _capture(NULL),
+  _camera_index(-1)
+{
+  // Rather than copying the _capture pointer, we must open a new
+  // stream that references the same file.
+  if (copy.is_valid()) {
+    if (copy.is_from_file()) {
+      read(copy._filename);
+    } else {
+      from_camera(copy._camera_index);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoStream::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+OpenCVTexture::VideoStream::
+~VideoStream() {
+  clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoStream::get_frame_data
+//       Access: Public
+//  Description: Returns the pointer to the beginning of the
+//               decompressed buffer for the indicated frame number.
+//               It is most efficient to call this in increasing order
+//               of frame number.
+////////////////////////////////////////////////////////////////////
+const unsigned char *OpenCVTexture::VideoStream::
+get_frame_data(int frame) {
+  nassertr(is_valid(), NULL);
+
+  if (is_from_file() && _next_frame != frame) {
+    cvSetCaptureProperty(_capture, CV_CAP_PROP_POS_FRAMES, frame);
+  }
+
+  _next_frame = frame + 1;
+  IplImage *image = cvQueryFrame(_capture);
+  if (image == NULL) {
+    return NULL;
+  }
+  return (const unsigned char *)image->imageData;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoStream::read
+//       Access: Public
+//  Description: Sets up the stream to read the indicated file.
+//               Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool OpenCVTexture::VideoStream::
+read(const Filename &filename) {
+  clear();
+
+  string os_specific = filename.to_os_specific();
+  _capture = cvCaptureFromFile(os_specific.c_str());
+  if (_capture == NULL) {
+    return false;
+  }
+  _filename = filename;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoStream::from_camera
+//       Access: Public
+//  Description: Sets up the stream to display the indicated camera.
+//               Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool OpenCVTexture::VideoStream::
+from_camera(int camera_index) {
+  clear();
+
+  _capture = cvCaptureFromCAM(camera_index);
+  if (_capture == NULL) {
+    return false;
+  }
+  _camera_index = camera_index;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::VideoStream::clear
+//       Access: Public
+//  Description: Stops the video playback and frees the associated
+//               resources.
+////////////////////////////////////////////////////////////////////
+void OpenCVTexture::VideoStream::
+clear() {
+  if (_capture != NULL) {
+    cvReleaseCapture(&_capture);
+    _capture = NULL;
+  }
+  _filename = Filename();
+  _camera_index = -1;
+  _next_frame = 0;
+}
+
+#endif  // HAVE_OPENCV
+

+ 125 - 0
panda/src/grutil/openCVTexture.h

@@ -0,0 +1,125 @@
+// Filename: openCVTexture.h
+// Created by:  zacpavlov (19Aug05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef OPENCVTEXTURE_H
+#define OPENCVTEXTURE_H
+
+#include "pandabase.h"
+#ifdef HAVE_OPENCV
+
+#include "videoTexture.h"
+
+#include <cxcore.h>
+#include <cv.h>
+#include <highgui.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : OpenCVTexture
+// Description : A specialization on VideoTexture that takes its input
+//               using the CV library, to produce an animated texture,
+//               with its source taken from an .avi file or from a
+//               camera input.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA OpenCVTexture : public VideoTexture {
+PUBLISHED:
+  OpenCVTexture(const string &name = string());
+protected:
+  OpenCVTexture(const OpenCVTexture &copy);
+PUBLISHED:
+  virtual ~OpenCVTexture();
+
+  virtual PT(Texture) make_copy();
+
+  bool from_camera(int camera_index = -1, int z = 0);
+
+  virtual bool read(const Filename &fullpath, int z = 0,
+		    int primary_file_num_channels = 0);
+  virtual bool read(const Filename &fullpath, const Filename &alpha_fullpath, 
+		    int z = 0,
+		    int primary_file_num_channels = 0, int alpha_file_channel = 0);
+  virtual bool load(const PNMImage &pnmimage, int z = 0);
+
+public:
+  static PT(Texture) make_texture();
+
+protected:
+  virtual void update_frame(int frame);
+
+private:    
+  class VideoPage;
+  class VideoStream;
+
+  VideoPage &modify_page(int z);
+  bool reconsider_video_properties(const VideoStream &stream, 
+				   int num_components, int z);
+  void do_update();
+
+  class VideoStream {
+  public:
+    VideoStream();
+    VideoStream(const VideoStream &copy);
+    ~VideoStream();
+
+    bool read(const Filename &filename);
+    bool from_camera(int camera_index);
+    void clear();
+    INLINE bool is_valid() const;
+    INLINE bool is_from_file() const;
+    const unsigned char *get_frame_data(int frame);
+
+    CvCapture *_capture;
+    Filename _filename;
+    int _camera_index;
+    int _next_frame;
+  };
+
+  class VideoPage {
+  public:
+    INLINE VideoPage();
+    INLINE VideoPage(const VideoPage &copy);
+    INLINE ~VideoPage();
+
+    VideoStream _color, _alpha;
+  };
+
+  typedef pvector<VideoPage> Pages;
+  Pages _pages;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    VideoTexture::init_type();
+    register_type(_type_handle, "OpenCVTexture",
+                  VideoTexture::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "openCVTexture.I"
+
+#endif  // HAVE_OPENCV
+
+#endif

+ 22 - 3
panda/src/pgraph/cullTraverser.cxx

@@ -214,7 +214,12 @@ traverse_below(CullTraverserData &data) {
       _geoms_pcollector.add_level(num_geoms);
       for (int i = 0; i < num_geoms; i++) {
         CullableObject *object = new CullableObject(data, geom_node, i);
-        _cull_handler->record_object(object, this);
+	if (object->_state->has_cull_callback() &&
+	    !object->_state->cull_callback(this, data)) {
+	  delete object;
+	} else {
+	  _cull_handler->record_object(object, this);
+	}
       }
     }
 
@@ -533,7 +538,14 @@ start_decal(const CullTraverserData &data) {
   int num_geoms = geom_node->get_num_geoms();
   _geoms_pcollector.add_level(num_geoms);
   for (int i = num_geoms - 1; i >= 0; i--) {
-    object = new CullableObject(data, geom_node, i, object);
+    CullableObject *next_object = 
+      new CullableObject(data, geom_node, i, object);
+    if (next_object->_state->has_cull_callback() &&
+	!next_object->_state->cull_callback(this, data)) {
+      delete next_object;
+    } else {
+      object = next_object;
+    }
   }
 
   if (object != separator) {
@@ -591,7 +603,14 @@ r_get_decals(CullTraverserData &data, CullableObject *decals) {
       int num_geoms = geom_node->get_num_geoms();
       _geoms_pcollector.add_level(num_geoms);
       for (int i = num_geoms - 1; i >= 0; i--) {
-        decals = new CullableObject(data, geom_node, i, decals);
+	CullableObject *next_decals = 
+	  new CullableObject(data, geom_node, i, decals);
+	if (next_decals->_state->has_cull_callback() &&
+	    !next_decals->_state->cull_callback(this, data)) {
+	  delete next_decals;
+	} else {
+	  decals = next_decals;
+	}
       }
     }
   }

+ 32 - 0
panda/src/pgraph/renderAttrib.cxx

@@ -125,6 +125,38 @@ lower_attrib_can_override() const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::has_cull_callback
+//       Access: Public, Virtual
+//  Description: Should be overridden by derived classes to return
+//               true if cull_callback() has been defined.  Otherwise,
+//               returns false to indicate cull_callback() does not
+//               need to be called for this node during the cull
+//               traversal.
+////////////////////////////////////////////////////////////////////
+bool RenderAttrib::
+has_cull_callback() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::cull_callback
+//       Access: Public, Virtual
+//  Description: If has_cull_callback() returns true, this function
+//               will be called during the cull traversal to perform
+//               any additional operations that should be performed at
+//               cull time.
+//
+//               This is called each time the RenderAttrib is
+//               discovered applied to a Geom in the traversal.  It
+//               should return true if the Geom is visible, false if
+//               it should be omitted.
+////////////////////////////////////////////////////////////////////
+bool RenderAttrib::
+cull_callback(CullTraverser *, const CullTraverserData &) const {
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttrib::output
 //       Access: Published, Virtual

+ 5 - 0
panda/src/pgraph/renderAttrib.h

@@ -27,6 +27,8 @@
 
 class AttribSlots;
 class GraphicsStateGuardianBase;
+class CullTraverser;
+class CullTraverserData;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : RenderAttrib
@@ -73,6 +75,9 @@ public:
   INLINE bool always_reissue() const;
   virtual void store_into_slot(AttribSlots *slots) const=0;
 
+  virtual bool has_cull_callback() const;
+  virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
+
 PUBLISHED:
   INLINE int compare_to(const RenderAttrib &other) const;
   virtual void output(ostream &out) const;

+ 17 - 0
panda/src/pgraph/renderState.I

@@ -61,6 +61,23 @@ get_override(int n) const {
   return _attributes[n]._override;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::has_cull_callback
+//       Access: Published
+//  Description: Returns true if any of the RenderAttribs in this
+//               state request a cull_callback(), false if none of
+//               them do.
+////////////////////////////////////////////////////////////////////
+INLINE bool RenderState::
+has_cull_callback() const {
+  if ((_flags & F_checked_cull_callback) == 0) {
+    // We pretend this function is const, even though it transparently
+    // modifies the internal shader cache.
+    ((RenderState *)this)->determine_cull_callback();
+  }
+  return (_flags & F_has_cull_callback) != 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::cache_ref
 //       Access: Published

+ 39 - 0
panda/src/pgraph/renderState.cxx

@@ -136,6 +136,26 @@ operator < (const RenderState &other) const {
                                  CompareTo<Attribute>());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::cull_callback
+//       Access: Published
+//  Description: Calls cull_callback() on each attrib.  If any attrib
+//               returns false, interrupts the list and returns false
+//               immediately; otherwise, completes the list and
+//               returns true.
+////////////////////////////////////////////////////////////////////
+bool RenderState::
+cull_callback(CullTraverser *trav, const CullTraverserData &data) const {
+  Attributes::const_iterator ai;
+  for (ai = _attributes.begin(); ai != _attributes.end(); ++ai) {
+    const Attribute &attrib = *ai;
+    if (!attrib._attrib->cull_callback(trav, data)) {
+      return false;
+    }
+  }
+
+  return true;
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::find_attrib
@@ -1570,6 +1590,25 @@ determine_shader() {
   _flags |= F_checked_shader;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::determine_cull_callback
+//       Access: Private
+//  Description: This is the private implementation of has_cull_callback().
+////////////////////////////////////////////////////////////////////
+void RenderState::
+determine_cull_callback() {
+  Attributes::const_iterator ai;
+  for (ai = _attributes.begin(); ai != _attributes.end(); ++ai) {
+    const Attribute &attrib = *ai;
+    if (attrib._attrib->has_cull_callback()) {
+      _flags |= F_has_cull_callback;
+      break;
+    }
+  }
+
+  _flags |= F_checked_cull_callback;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::update_pstats
 //       Access: Private

+ 19 - 13
panda/src/pgraph/renderState.h

@@ -75,6 +75,9 @@ PUBLISHED:
   INLINE const RenderAttrib *get_attrib(int n) const;
   INLINE int get_override(int n) const;
 
+  INLINE bool has_cull_callback() const;
+  bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
+
   int find_attrib(TypeHandle type) const;
 
   static CPT(RenderState) make_empty();
@@ -181,6 +184,7 @@ private:
   void determine_render_mode();
   void determine_clip_plane();
   void determine_shader();
+  void determine_cull_callback();
 
   INLINE void set_destructing();
   INLINE bool is_destructing() const;
@@ -282,19 +286,21 @@ private:
   const ShaderAttrib *_shader;
   
   enum Flags {
-    F_checked_bin_index    = 0x0001,
-    F_checked_fog          = 0x0002,
-    F_checked_bin          = 0x0004,
-    F_checked_transparency = 0x0008,
-    F_checked_color        = 0x0010,
-    F_checked_color_scale  = 0x0020,
-    F_checked_texture      = 0x0040,
-    F_checked_tex_gen      = 0x0080,
-    F_checked_tex_matrix   = 0x0100,
-    F_checked_render_mode  = 0x0200,
-    F_checked_clip_plane   = 0x0400,
-    F_checked_shader       = 0x0800,
-    F_is_destructing       = 0x8000,
+    F_checked_bin_index     = 0x0001,
+    F_checked_fog           = 0x0002,
+    F_checked_bin           = 0x0004,
+    F_checked_transparency  = 0x0008,
+    F_checked_color         = 0x0010,
+    F_checked_color_scale   = 0x0020,
+    F_checked_texture       = 0x0040,
+    F_checked_tex_gen       = 0x0080,
+    F_checked_tex_matrix    = 0x0100,
+    F_checked_render_mode   = 0x0200,
+    F_checked_clip_plane    = 0x0400,
+    F_checked_shader        = 0x0800,
+    F_checked_cull_callback = 0x1000,
+    F_has_cull_callback     = 0x2000,
+    F_is_destructing        = 0x8000,
   };
   unsigned short _flags;
 

+ 48 - 0
panda/src/pgraph/textureAttrib.cxx

@@ -390,6 +390,54 @@ output(ostream &out) const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::has_cull_callback
+//       Access: Public, Virtual
+//  Description: Should be overridden by derived classes to return
+//               true if cull_callback() has been defined.  Otherwise,
+//               returns false to indicate cull_callback() does not
+//               need to be called for this node during the cull
+//               traversal.
+////////////////////////////////////////////////////////////////////
+bool TextureAttrib::
+has_cull_callback() const {
+  OnTextures::const_iterator nti;
+  for (nti = _on_textures.begin(); nti != _on_textures.end(); ++nti) {
+    Texture *texture = (*nti).second;
+    if (texture->has_cull_callback()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::cull_callback
+//       Access: Public, Virtual
+//  Description: If has_cull_callback() returns true, this function
+//               will be called during the cull traversal to perform
+//               any additional operations that should be performed at
+//               cull time.
+//
+//               This is called each time the RenderAttrib is
+//               discovered applied to a Geom in the traversal.  It
+//               should return true if the Geom is visible, false if
+//               it should be omitted.
+////////////////////////////////////////////////////////////////////
+bool TextureAttrib::
+cull_callback(CullTraverser *trav, const CullTraverserData &data) const {
+  OnTextures::const_iterator nti;
+  for (nti = _on_textures.begin(); nti != _on_textures.end(); ++nti) {
+    Texture *texture = (*nti).second;
+    if (!texture->cull_callback(trav, data)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureAttrib::compare_to_impl
 //       Access: Protected, Virtual

+ 3 - 0
panda/src/pgraph/textureAttrib.h

@@ -84,6 +84,9 @@ public:
   virtual void output(ostream &out) const;
   virtual void store_into_slot(AttribSlots *slots) const;
 
+  virtual bool has_cull_callback() const;
+  virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
+
 protected:
   virtual int compare_to_impl(const RenderAttrib *other) const;
   virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const;

+ 3 - 0
panda/src/putil/Sources.pp

@@ -8,6 +8,7 @@
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx   
   
   #define SOURCES \
+    animInterface.h animInterface.I \
     bam.h bamEndian.h \
     bamReader.I bamReader.N bamReader.h bamReaderParam.I \
     bamReaderParam.h bamWriter.I bamWriter.h bitMask.I \
@@ -60,6 +61,7 @@
     writableParam.I writableParam.h 
     
  #define INCLUDED_SOURCES \
+    animInterface.cxx \
     bamEndian.cxx \
     bamReader.cxx bamReaderParam.cxx bamWriter.cxx bitMask.cxx \
     buttonHandle.cxx buttonRegistry.cxx \
@@ -96,6 +98,7 @@
     writableConfigurable.cxx writableParam.cxx 
 
   #define INSTALL_HEADERS \
+    animInterface.h animInterface.I \
     bam.h bamEndian.h \
     bamReader.I bamReader.h bamReaderParam.I bamReaderParam.h \
     bamWriter.I bamWriter.h bitMask.I bitMask.h \

+ 178 - 0
panda/src/putil/animInterface.I

@@ -0,0 +1,178 @@
+// Filename: animInterface.I
+// Created by:  drose (20Sep05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::play
+//       Access: Published
+//  Description: Runs the entire animation from beginning to end and
+//               stops.
+////////////////////////////////////////////////////////////////////
+INLINE void AnimInterface::
+play() {
+  play(0, get_num_frames() - 1);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::loop
+//       Access: Published
+//  Description: Starts the entire animation looping.  If restart is
+//               true, the animation is restarted from the beginning;
+//               otherwise, it continues from the current frame.
+////////////////////////////////////////////////////////////////////
+INLINE void AnimInterface::
+loop(bool restart) {
+  loop(restart, 0, get_num_frames() - 1);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::pingpong
+//       Access: Published
+//  Description: Starts the entire animation bouncing back and forth
+//               between its first frame and last frame.  If restart
+//               is true, the animation is restarted from the
+//               beginning; otherwise, it continues from the current
+//               frame.
+////////////////////////////////////////////////////////////////////
+INLINE void AnimInterface::
+pingpong(bool restart) {
+  pingpong(restart, 0, get_num_frames() - 1);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::stop
+//       Access: Published
+//  Description: Stops a currently playing or looping animation right
+//               where it is.  The animation remains posed at the
+//               current frame.
+////////////////////////////////////////////////////////////////////
+INLINE void AnimInterface::
+stop() {
+  pose(get_frame());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::set_play_rate
+//       Access: Published
+//  Description: Changes the rate at which the animation plays.  1.0
+//               is the normal speed, 2.0 is twice normal speed, and
+//               0.5 is half normal speed.  0.0 is legal to pause the
+//               animation, and a negative value will play the
+//               animation backwards.
+////////////////////////////////////////////////////////////////////
+INLINE void AnimInterface::
+set_play_rate(double play_rate) {
+  internal_set_rate(_frame_rate, play_rate);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::get_play_rate
+//       Access: Published
+//  Description: Returns the rate at which the animation plays.  See
+//               set_play_rate().
+////////////////////////////////////////////////////////////////////
+INLINE double AnimInterface::
+get_play_rate() const {
+  return _play_rate;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::get_frame_rate
+//       Access: Published
+//  Description: Returns the native frame rate of the animation.  This
+//               is the number of frames per second that will elapse
+//               when the play_rate is set to 1.0.  It is a fixed
+//               property of the animation and may not be adjusted by
+//               the user.
+////////////////////////////////////////////////////////////////////
+INLINE double AnimInterface::
+get_frame_rate() const {
+  return _frame_rate;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::get_num_frames
+//       Access: Published
+//  Description: Returns the number of frames in the animation.  This
+//               is a fixed property of the animation and may not be
+//               adjusted by the user.
+////////////////////////////////////////////////////////////////////
+INLINE int AnimInterface::
+get_num_frames() const {
+  return _num_frames;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::get_frame
+//       Access: Published
+//  Description: Returns the current integer frame number.
+//               This number will be in the range 0 <= f <
+//               get_num_frames().
+////////////////////////////////////////////////////////////////////
+INLINE int AnimInterface::
+get_frame() const {
+  return cmod(get_full_frame(), get_num_frames());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::get_frac
+//       Access: Published
+//  Description: Returns the fractional part of the current frame.
+//               Normally, this is in the range 0.0 <= f < 1.0, but in
+//               the one special case of an animation playing to its
+//               end frame and stopping, it might exactly equal 1.0.
+//
+//               It will always be true that get_full_frame() +
+//               get_frac() == get_full_fframe().
+////////////////////////////////////////////////////////////////////
+INLINE double AnimInterface::
+get_frac() const {
+  return get_full_fframe() - (double)get_full_frame();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::set_frame_rate
+//       Access: Protected
+//  Description: Should be called by a derived class to specify the
+//               native frame rate of the animation.  It is legal to
+//               call this after the animation has already started.
+////////////////////////////////////////////////////////////////////
+INLINE void AnimInterface::
+set_frame_rate(double frame_rate) {
+  internal_set_rate(frame_rate, _play_rate);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::set_num_frames
+//       Access: Protected
+//  Description: Should be called by a derived class to specify the
+//               number of frames of the animation.  It is legal to
+//               call this after the animation has already started,
+//               but doing so may suddenly change the apparent current
+//               frame number.
+////////////////////////////////////////////////////////////////////
+INLINE void AnimInterface::
+set_num_frames(int num_frames) {
+  _num_frames = num_frames;
+}
+
+INLINE ostream &
+operator << (ostream &out, const AnimInterface &ai) {
+  ai.output(out);
+  return out;
+}

+ 379 - 0
panda/src/putil/animInterface.cxx

@@ -0,0 +1,379 @@
+// Filename: animInterface.cxx
+// Created by:  drose (20Sep05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "animInterface.h"
+#include "clockObject.h"
+
+TypeHandle AnimInterface::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+AnimInterface::
+AnimInterface() :
+  _frame_rate(0.0),
+  _num_frames(0),
+  _play_mode(PM_pose),
+  _start_time(0.0),
+  _start_frame(0.0),
+  _play_frames(0.0),
+  _from_frame(0),
+  _to_frame(0),
+  _play_rate(1.0),
+  _effective_frame_rate(0.0),
+  _paused(true),
+  _paused_f(0.0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::Copy Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+AnimInterface::
+AnimInterface(const AnimInterface &copy) :
+  _frame_rate(copy._frame_rate),
+  _num_frames(copy._num_frames),
+  _play_mode(copy._play_mode),
+  _start_time(copy._start_time),
+  _start_frame(copy._start_frame),
+  _play_frames(copy._play_frames),
+  _from_frame(copy._from_frame),
+  _to_frame(copy._to_frame),
+  _play_rate(copy._play_rate),
+  _effective_frame_rate(copy._effective_frame_rate),
+  _paused(copy._paused),
+  _paused_f(copy._paused_f)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::Destructor
+//       Access: Published, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+AnimInterface::
+~AnimInterface() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::play
+//       Access: Published
+//  Description: Runs the animation from the frame "from" to and
+//               including the frame "to", at which point the
+//               animation is stopped.  Both "from" and "to" frame
+//               numbers may be outside the range (0,
+//               get_num_frames()) and the animation will follow the
+//               range correctly, reporting numbers modulo
+//               get_num_frames().  For instance, play(0,
+//               get_num_frames() * 2) will play the animation twice
+//               and then stop.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+play(double from, double to) {
+  if (from >= to) {
+    pose(from);
+    return;
+  }
+
+  _play_mode = PM_play;
+  _start_time = ClockObject::get_global_clock()->get_frame_time();
+  _start_frame = from;
+  _play_frames = to - from + 1.0;
+  _from_frame = (int)floor(from);
+  _to_frame = (int)floor(to);
+  _paused_f = 0.0;
+
+  if (_effective_frame_rate < 0.0) {
+    // If we'll be playing backward, start at the end.
+    _start_time -= _play_frames / _effective_frame_rate;
+  }
+
+  animation_activated();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::loop
+//       Access: Published
+//  Description: Loops the animation from the frame "from" to and
+//               including the frame "to", indefinitely.  If restart
+//               is true, the animation is restarted from the
+//               beginning; otherwise, it continues from the current
+//               frame.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+loop(bool restart, double from, double to) {
+  if (from >= to) {
+    pose(from);
+    return;
+  }
+
+  double fframe = get_full_fframe();
+
+  _play_mode = PM_loop;
+  _start_time = ClockObject::get_global_clock()->get_frame_time();
+  _start_frame = from;
+  _play_frames = to - from + 1.0;
+  _from_frame = (int)floor(from);
+  _to_frame = (int)floor(to);
+  _paused_f = 0.0;
+
+  if (!restart) {
+    if (_paused) {
+      _paused_f = fframe - _start_frame;
+    } else {
+      _start_time -= fframe / _effective_frame_rate;
+    }
+  }
+
+  animation_activated();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::pingpong
+//       Access: Published
+//  Description: Loops the animation from the frame "from" to and
+//               including the frame "to", and then back in the
+//               opposite direction, indefinitely.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+pingpong(bool restart, double from, double to) {
+  if (from >= to) {
+    pose(from);
+    return;
+  }
+
+  double fframe = get_full_fframe();
+
+  _play_mode = PM_pingpong;
+  _start_time = ClockObject::get_global_clock()->get_frame_time();
+  _start_frame = from;
+  _play_frames = to - from + 1.0;
+  _from_frame = (int)floor(from);
+  _to_frame = (int)floor(to);
+  _paused_f = 0.0;
+
+  if (!restart) {
+    if (_paused) {
+      _paused_f = fframe - _start_frame;
+    } else {
+      _start_time -= fframe / _effective_frame_rate;
+    }
+  }
+
+  animation_activated();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::pose
+//       Access: Published
+//  Description: Sets the animation to the indicated frame and holds
+//               it there.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+pose(int frame) {
+  _play_mode = PM_pose;
+  _start_time = ClockObject::get_global_clock()->get_frame_time();
+  _start_frame = (double)frame;
+  _play_frames = 0.0;
+  _from_frame = frame;
+  _to_frame = frame;
+  _paused_f = 0.0;
+
+  animation_activated();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::get_full_frame
+//       Access: Published
+//  Description: Returns the current integer frame number.
+//
+//               Unlike the value returned by get_frame(), this frame
+//               number may extend beyond the range of
+//               get_num_frames() if the frame range passed to play(),
+//               loop(), etc. did.
+//
+//               Unlike the value returned by get_full_fframe(), this
+//               return value will never exceed the value passed to
+//               to_frame in the play() method.
+////////////////////////////////////////////////////////////////////
+int AnimInterface::
+get_full_frame() const {
+  int frame = (int)floor(get_full_fframe());
+  if (_play_mode == PM_play) {
+    // In play mode, we never let the return value exceed
+    // (_from_frame, _to_frame).
+    frame = min(max(frame, _from_frame), _to_frame);
+  }
+  return frame;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::get_full_fframe
+//       Access: Published
+//  Description: Returns the current floating-point frame number.
+//
+//               Unlike the value returned by get_frame(), this frame
+//               number may extend beyond the range of
+//               get_num_frames() if the frame range passed to play(),
+//               loop(), etc. did.
+//
+//               Unlike the value returned by get_full_frame(), this
+//               return value may equal (to_frame + 1.0), when the
+//               animation has played to its natural end.  However, in
+//               this case the return value of get_full_frame() will
+//               be to_frame, not (to_frame + 1).
+////////////////////////////////////////////////////////////////////
+double AnimInterface::
+get_full_fframe() const {
+  switch (_play_mode) {
+  case PM_pose:
+    return _start_frame;
+
+  case PM_play:
+    return min(max(get_f(), 0.0), _play_frames) + _start_frame;
+
+  case PM_loop:
+    return cmod(get_f(), _play_frames) + _start_frame;
+
+  case PM_pingpong:
+    {
+      double f = cmod(get_f(), _play_frames * 2.0);
+      if (f > _play_frames) {
+	return (_play_frames * 2.0 - f) + _start_frame;
+      } else {
+	return f + _start_frame;
+      }
+    }
+  }
+
+  return _start_frame;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::is_playing
+//       Access: Published
+//  Description: Returns true if the animation is currently playing,
+//               false if it is stopped (e.g. because stop() or pose()
+//               was called, or because it reached the end of the
+//               animation after play() was called).
+////////////////////////////////////////////////////////////////////
+bool AnimInterface::
+is_playing() const {
+  switch (_play_mode) {
+  case PM_pose:
+    return false;
+
+  case PM_play:
+    return get_f() < _play_frames;
+
+  case PM_loop:
+  case PM_pingpong:
+    return true;
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::output
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+output(ostream &out) const {
+  switch (_play_mode) {
+  case PM_pose:
+    out << "pose, frame " << get_frame();
+    return;
+
+  case PM_play:
+    out << "play, frame " << get_frame();
+    return;
+
+  case PM_loop:
+    out << "loop, frame " << get_frame();
+    return;
+
+  case PM_pingpong:
+    out << "pingpong, frame " << get_frame();
+    return;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::animation_activated
+//       Access: Protected, Virtual
+//  Description: This is provided as a callback method for when the
+//               user calls one of the play/loop/pose type methods to
+//               start the animation playing.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+animation_activated() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::get_f
+//       Access: Private
+//  Description: Returns the current floating-point frame number,
+//               elapsed since _start_frame.
+////////////////////////////////////////////////////////////////////
+double AnimInterface::
+get_f() const {
+  if (_paused) {
+    return _paused_f;
+
+  } else {
+    double now = ClockObject::get_global_clock()->get_frame_time();
+    double elapsed = now - _start_time;
+    return (elapsed * _effective_frame_rate);
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::internal_set_rate
+//       Access: Private
+//  Description: Called internally to adjust either or both of the
+//               frame_rate or play_rate without changing the current
+//               frame number if the animation is already playing.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+internal_set_rate(double frame_rate, double play_rate) {
+  double f = get_f();
+  
+  _frame_rate = frame_rate;
+  _play_rate = play_rate;
+  _effective_frame_rate = frame_rate * play_rate;
+
+  if (_effective_frame_rate == 0.0) {
+    _paused_f = f;
+    _paused = true;
+
+  } else {
+    // Compute a new _start_time that will keep f the same value with
+    // the new play_rate.
+    double new_elapsed = f / _effective_frame_rate;
+    double now = ClockObject::get_global_clock()->get_frame_time();
+    _start_time = now - new_elapsed;
+    _paused = false;
+  }
+}

+ 111 - 0
panda/src/putil/animInterface.h

@@ -0,0 +1,111 @@
+// Filename: animInterface.h
+// Created by:  drose (20Sep05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef ANIMINTERFACE_H
+#define ANIMINTERFACE_H
+
+#include "pandabase.h"
+#include "typeHandle.h"
+#include "register_type.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : AnimInterface
+// Description : This is the fundamental interface for things that
+//               have a play/loop/stop type interface for frame-based
+//               animation, such as animated characters.  This is the
+//               base class for AnimControl and other, similar
+//               classes.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA AnimInterface {
+protected:
+  AnimInterface();
+  AnimInterface(const AnimInterface &copy);
+
+PUBLISHED:
+  virtual ~AnimInterface();
+  INLINE void play();
+  void play(double from, double to);
+  INLINE void loop(bool restart);
+  void loop(bool restart, double from, double to);
+  INLINE void pingpong(bool restart);
+  void pingpong(bool restart, double from, double to);
+  INLINE void stop();
+  void pose(int frame);
+
+  INLINE void set_play_rate(double play_rate);
+  INLINE double get_play_rate() const;
+  INLINE double get_frame_rate() const;
+  INLINE int get_num_frames() const;
+
+  INLINE int get_frame() const;
+  INLINE double get_frac() const;
+  int get_full_frame() const;
+  double get_full_fframe() const;
+  bool is_playing() const;
+
+  virtual void output(ostream &out) const;
+
+protected:
+  INLINE void set_frame_rate(double frame_rate);
+  INLINE void set_num_frames(int num_frames);
+  virtual void animation_activated();
+
+private:
+  double get_f() const;
+  void internal_set_rate(double frame_rate, double play_rate);
+
+private:
+  enum PlayMode {
+    PM_pose,
+    PM_play,
+    PM_loop,
+    PM_pingpong,
+  };
+
+  double _frame_rate;
+  int _num_frames;
+
+  PlayMode _play_mode;
+  double _start_time;
+  double _start_frame;
+  double _play_frames;
+  int _from_frame;
+  int _to_frame;
+
+  double _play_rate;
+  double _effective_frame_rate;
+  bool _paused;
+  double _paused_f;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    register_type(_type_handle, "AnimInterface");
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+INLINE ostream &operator << (ostream &out, const AnimInterface &ai);
+
+#include "animInterface.I"
+
+#endif

+ 2 - 0
panda/src/putil/config_util.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "config_util.h"
+#include "animInterface.h"
 #include "bamReaderParam.h"
 #include "cachedTypedWritableReferenceCount.h"
 #include "clockObject.h"
@@ -67,6 +68,7 @@ ConfigVariableSearchPath sound_path
  PRC_DESC("The directories to search for sound and music files to be loaded."));
 
 ConfigureFn(config_util) {
+  AnimInterface::init_type();
   BamReaderParam::init_type();
   CachedTypedWritableReferenceCount::init_type();
   Configurable::init_type();

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff