Prechádzať zdrojové kódy

finally, pipelined textures

David Rose 14 rokov pred
rodič
commit
9e22c72bf3

+ 0 - 2
panda/src/framework/windowFramework.cxx

@@ -45,8 +45,6 @@
 #include "pgTop.h"
 #include "geomNode.h"
 #include "texture.h"
-#include "videoTexture.h"
-#include "movieTexture.h"
 #include "texturePool.h"
 #include "loaderFileTypeRegistry.h"
 #include "pnmImage.h"

+ 15 - 6
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -3321,9 +3321,7 @@ prepare_texture(Texture *tex, int view) {
     break;
   }
 
-  report_my_gl_errors();
   CLP(TextureContext) *gtc = new CLP(TextureContext)(_prepared_objects, tex, view);
-  report_my_gl_errors();
   GLP(GenTextures)(1, &gtc->_index);
   report_my_gl_errors();
 
@@ -8354,7 +8352,13 @@ apply_texture(TextureContext *tc) {
   if (target == GL_NONE) {
     return false;
   }
-  report_my_gl_errors();
+
+  if (gtc->_target != target) {
+    // The target has changed.  That means we have to re-bind a new
+    // texture object.
+    gtc->reset_data();
+    gtc->_target = target;
+  }
   GLP(BindTexture)(target, gtc->_index);
 
   report_my_gl_errors();
@@ -8543,6 +8547,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
 
   bool success = true;
 
+  GLenum target = get_texture_target(tex->get_texture_type());
   if (tex->get_texture_type() == Texture::TT_cube_map) {
     // A cube map must load six different 2-d images (which are stored
     // as the six pages of the system ram image).
@@ -8550,6 +8555,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
       report_my_gl_errors();
       return false;
     }
+    nassertr(target == GL_TEXTURE_CUBE_MAP, false);
 
     success = success && upload_texture_image
       (gtc, uses_mipmaps, mipmap_bias,
@@ -8589,7 +8595,6 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
 
   } else {
     // Any other kind of texture can be loaded all at once.
-    GLenum target = get_texture_target(tex->get_texture_type());
     success = upload_texture_image
       (gtc, uses_mipmaps, mipmap_bias, target, target,
        internal_format, external_format, component_type,
@@ -9311,10 +9316,14 @@ bool CLP(GraphicsStateGuardian)::
 do_extract_texture_data(CLP(TextureContext) *gtc) {
   report_my_gl_errors();
 
-  Texture *tex = gtc->get_texture();
-  GLenum target = get_texture_target(tex->get_texture_type());
+  GLenum target = gtc->_target;
+  if (target == GL_NONE) {
+    return false;
+  }
   GLP(BindTexture)(target, gtc->_index);
 
+  Texture *tex = gtc->get_texture();
+
   GLint wrap_u, wrap_v, wrap_w;
   GLint minfilter, magfilter;
   GLfloat border_color[4];

+ 1 - 0
panda/src/glstuff/glTextureContext_src.I

@@ -29,4 +29,5 @@ CLP(TextureContext)(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
   _width = 0;
   _height = 0;
   _depth = 0;
+  _target = GL_NONE;
 }

+ 12 - 2
panda/src/glstuff/glTextureContext_src.cxx

@@ -35,7 +35,19 @@ TypeHandle CLP(TextureContext)::_type_handle;
 void CLP(TextureContext)::
 evict_lru() {
   dequeue_lru();
+  reset_data();
+  update_data_size_bytes(0);
+  mark_unloaded();
+}
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLTextureContext::reset_data
+//       Access: Public
+//  Description: Resets the texture object to a new one so a new GL
+//               texture object can be uploaded.
+////////////////////////////////////////////////////////////////////
+void CLP(TextureContext)::
+reset_data() {
   // Free the texture resources.
   GLP(DeleteTextures)(1, &_index);
 
@@ -44,6 +56,4 @@ evict_lru() {
   GLP(GenTextures)(1, &_index);
 
   _already_applied = false;
-  update_data_size_bytes(0);
-  mark_unloaded();
 }

+ 2 - 0
panda/src/glstuff/glTextureContext_src.h

@@ -26,6 +26,7 @@ public:
   ALLOC_DELETED_CHAIN(CLP(TextureContext));
 
   virtual void evict_lru();
+  void reset_data();
 
   // This is the GL "name" of the texture object.
   GLuint _index;
@@ -39,6 +40,7 @@ public:
   GLsizei _width;
   GLsizei _height;
   GLsizei _depth;
+  GLenum _target;
 
 public:
   static TypeHandle get_class_type() {

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 218 - 167
panda/src/gobj/texture.I


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 216 - 285
panda/src/gobj/texture.cxx


+ 249 - 187
panda/src/gobj/texture.h

@@ -32,6 +32,13 @@
 #include "conditionVarFull.h"
 #include "loaderOptions.h"
 #include "string_utils.h"
+#include "cycleData.h"
+#include "cycleDataLockedReader.h"
+#include "cycleDataReader.h"
+#include "cycleDataWriter.h"
+#include "cycleDataStageReader.h"
+#include "cycleDataStageWriter.h"
+#include "pipelineCycler.h"
 
 class PNMImage;
 class TextureContext;
@@ -328,8 +335,8 @@ PUBLISHED:
   CPTA_uchar get_ram_image_as(const string &requested_format);
   INLINE PTA_uchar modify_ram_image();
   INLINE PTA_uchar make_ram_image();
-  void set_ram_image(CPTA_uchar image, CompressionMode compression = CM_off,
-                     size_t page_size = 0);
+  INLINE void set_ram_image(CPTA_uchar image, CompressionMode compression = CM_off,
+                            size_t page_size = 0);
   void set_ram_image_as(CPTA_uchar image, const string &provided_format);
   INLINE void clear_ram_image();
   INLINE void set_keep_ram_image(bool keep_ram_image);
@@ -351,8 +358,8 @@ PUBLISHED:
   INLINE size_t get_expected_ram_mipmap_image_size(int n) const;
   INLINE size_t get_expected_ram_mipmap_view_size(int n) const;
   INLINE size_t get_expected_ram_mipmap_page_size(int n) const;
-  CPTA_uchar get_ram_mipmap_image(int n);
-  void *get_ram_mipmap_pointer(int n);
+  CPTA_uchar get_ram_mipmap_image(int n) const;
+  void *get_ram_mipmap_pointer(int n) const;
   INLINE PTA_uchar modify_ram_mipmap_image(int n);
   INLINE PTA_uchar make_ram_mipmap_image(int n);
   void set_ram_mipmap_pointer(int n, void *image, size_t page_size = 0);
@@ -498,119 +505,133 @@ public:
   static bool adjust_size(int &x_size, int &y_size, const string &name,
                           bool for_padding);
   INLINE bool adjust_this_size(int &x_size, int &y_size, const string &name,
-                               bool for_padding);
+                               bool for_padding) const;
 
 protected:
+  class CData;
+
   virtual void reconsider_dirty();
 
   // All of the functions in this class that begin "do_" are protected
   // methods.  Many of them are implementations of public-facing
   // versions of the same methods.
 
-  // All of these assume the lock is already held; generally, they
-  // also avoid adjusting the _properties_modified and _image_modified
+  // All of these assume the CData lock is already held (and receive a
+  // CData pointer representing that lock); generally, they also avoid
+  // adjusting the _properties_modified and _image_modified
   // semaphores.
-  virtual bool do_adjust_this_size(int &x_size, int &y_size, const string &name, 
-                                   bool for_padding);
+  virtual bool do_adjust_this_size(const CData *cdata, 
+                                   int &x_size, int &y_size, const string &name, 
+                                   bool for_padding) const;
 
-  virtual bool do_read(const Filename &fullpath, const Filename &alpha_fullpath,
+  virtual bool do_read(CData *cdata,
+                       const Filename &fullpath, const Filename &alpha_fullpath,
                        int primary_file_num_channels, int alpha_file_channel,
                        int z, int n, bool read_pages, bool read_mipmaps,
                        const LoaderOptions &options, BamCacheRecord *record);
-  virtual bool do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
+  virtual bool do_read_one(CData *cdata,
+                           const Filename &fullpath, const Filename &alpha_fullpath,
                            int z, int n, int primary_file_num_channels, int alpha_file_channel,
                            const LoaderOptions &options,
                            bool header_only, BamCacheRecord *record);
-  virtual bool do_load_one(const PNMImage &pnmimage, const string &name,
+  virtual bool do_load_one(CData *cdata,
+                           const PNMImage &pnmimage, const string &name,
                            int z, int n, const LoaderOptions &options);
-  bool do_read_txo_file(const Filename &fullpath);
-  bool do_read_txo(istream &in, const string &filename);
-  bool do_read_dds_file(const Filename &fullpath, bool header_only);
-  bool do_read_dds(istream &in, const string &filename, bool header_only);
-
-  bool do_write(const Filename &fullpath, int z, int n, 
-                bool write_pages, bool write_mipmaps) const;
-  bool do_write_one(const Filename &fullpath, int z, int n) const;
-  bool do_store_one(PNMImage &pnmimage, int z, int n) const;
-  bool do_write_txo_file(const Filename &fullpath) const;
-  bool do_write_txo(ostream &out, const string &filename) const;
-
-  virtual void do_unlock_and_reload_ram_image(bool allow_compression);
-  virtual void do_reload_ram_image(bool allow_compression);
-  PTA_uchar do_modify_ram_image();
-  PTA_uchar do_make_ram_image();
-  PTA_uchar do_modify_ram_mipmap_image(int n);
-  PTA_uchar do_make_ram_mipmap_image(int n);
-  void do_set_ram_mipmap_image(int n, CPTA_uchar image, size_t page_size);
-
-  bool consider_auto_process_ram_image(bool generate_mipmaps, 
-                                       bool allow_compression);
-  bool do_compress_ram_image(CompressionMode compression,
+  bool do_read_txo_file(CData *cdata, const Filename &fullpath);
+  bool do_read_txo(CData *cdata, istream &in, const string &filename);
+  bool do_read_dds_file(CData *cdata, const Filename &fullpath, bool header_only);
+  bool do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only);
+
+  bool do_write(CData *cdata, const Filename &fullpath, int z, int n, 
+                bool write_pages, bool write_mipmaps);
+  bool do_write_one(CData *cdata, const Filename &fullpath, int z, int n);
+  bool do_store_one(CData *cdata, PNMImage &pnmimage, int z, int n);
+  bool do_write_txo_file(const CData *cdata, const Filename &fullpath) const;
+  bool do_write_txo(const CData *cdata, ostream &out, const string &filename) const;
+
+  virtual CData *unlocked_ensure_ram_image(bool allow_compression);
+  virtual void do_reload_ram_image(CData *cdata, bool allow_compression);
+
+  PTA_uchar do_modify_ram_image(CData *cdata);
+  PTA_uchar do_make_ram_image(CData *cdata);
+  void do_set_ram_image(CData *cdata, CPTA_uchar image, 
+                        CompressionMode compression = CM_off, size_t page_size = 0);
+  PTA_uchar do_modify_ram_mipmap_image(CData *cdata, int n);
+  PTA_uchar do_make_ram_mipmap_image(CData *cdata, int n);
+  void do_set_ram_mipmap_image(CData *cdata, int n, CPTA_uchar image, size_t page_size);
+
+  bool consider_auto_process_ram_image(bool generate_mipmaps, bool allow_compression);
+  bool do_consider_auto_process_ram_image(CData *cdata, bool generate_mipmaps, 
+                                          bool allow_compression);
+  bool do_compress_ram_image(CData *cdata, CompressionMode compression,
                              QualityLevel quality_level,
                              GraphicsStateGuardianBase *gsg);
-  bool do_uncompress_ram_image();
-  bool do_has_all_ram_mipmap_images() const;
+  bool do_uncompress_ram_image(CData *cdata);
+  bool do_has_all_ram_mipmap_images(const CData *cdata) const;
 
-  bool do_reconsider_z_size(int z, const LoaderOptions &options);
-  virtual void do_allocate_pages();
-  bool do_reconsider_image_properties(int x_size, int y_size, int num_components,
+  bool do_reconsider_z_size(CData *cdata, int z, const LoaderOptions &options);
+  virtual void do_allocate_pages(CData *cdata);
+  bool do_reconsider_image_properties(CData *cdata, 
+                                      int x_size, int y_size, int num_components,
                                       ComponentType component_type, int z,
                                       const LoaderOptions &options);
-  bool do_rescale_texture();
-
-  virtual PT(Texture) do_make_copy() const;
-  void do_assign(const Texture &copy);
-  virtual void do_clear();
-  void do_setup_texture(TextureType texture_type, int x_size, int y_size,
+  bool do_rescale_texture(CData *cdata);
+
+  virtual PT(Texture) make_copy_impl() const;
+  PT(Texture) do_make_copy(const CData *cdata) const;
+  void do_assign(CData *cdata, const Texture *copy, const CData *cdata_copy);
+  virtual void do_clear(CData *cdata);
+  void do_setup_texture(CData *cdata, 
+                        TextureType texture_type, int x_size, int y_size,
                         int z_size, ComponentType component_type,
                         Format format);
-  void do_set_num_views(int num_views);
-  void do_set_format(Format format);
-  void do_set_component_type(ComponentType component_type);
-  void do_set_x_size(int x_size);
-  void do_set_y_size(int y_size);
-  void do_set_z_size(int z_size);
-
-  void do_set_wrap_u(WrapMode wrap);
-  void do_set_wrap_v(WrapMode wrap);
-  void do_set_wrap_w(WrapMode wrap);
-  void do_set_minfilter(FilterType filter);
-  void do_set_magfilter(FilterType filter);
-  void do_set_anisotropic_degree(int anisotropic_degree);
-  void do_set_border_color(const Colorf &color);
-  void do_set_compression(CompressionMode compression);
-  void do_set_quality_level(QualityLevel quality_level);
-
-  bool do_has_compression() const;
-  virtual bool do_has_ram_image() const;
-  virtual bool do_has_uncompressed_ram_image() const;
-  CPTA_uchar do_get_ram_image();
-  CPTA_uchar do_get_uncompressed_ram_image();
-  void do_set_simple_ram_image(CPTA_uchar image, int x_size, int y_size);
-  INLINE size_t do_get_ram_image_size() const;
-  INLINE bool do_has_ram_mipmap_image(int n) const;
-  int do_get_expected_num_mipmap_levels() const;
-  INLINE size_t do_get_expected_ram_image_size() const;
-  INLINE size_t do_get_expected_ram_view_size() const;
-  INLINE size_t do_get_expected_ram_page_size() const;
-  size_t do_get_ram_mipmap_page_size(int n) const;
-  INLINE size_t do_get_expected_ram_mipmap_image_size(int n) const;
-  INLINE size_t do_get_expected_ram_mipmap_view_size(int n) const;
-  INLINE size_t do_get_expected_ram_mipmap_page_size(int n) const;
-  int do_get_expected_mipmap_x_size(int n) const;
-  int do_get_expected_mipmap_y_size(int n) const;
-  int do_get_expected_mipmap_z_size(int n) const;
-  INLINE int do_get_expected_mipmap_num_pages(int n) const;
-  INLINE void do_clear_ram_image();
-  void do_clear_simple_ram_image();
-  void do_clear_ram_mipmap_images();
-  void do_generate_ram_mipmap_images();
-  void do_set_pad_size(int x, int y, int z);
-  virtual bool do_can_reload();
-  bool do_reload();
-
-  virtual bool do_has_bam_rawdata() const;
-  virtual void do_get_bam_rawdata();
+  void do_set_num_views(CData *cdata, int num_views);
+  void do_set_format(CData *cdata, Format format);
+  void do_set_component_type(CData *cdata, ComponentType component_type);
+  void do_set_x_size(CData *cdata, int x_size);
+  void do_set_y_size(CData *cdata, int y_size);
+  void do_set_z_size(CData *cdata, int z_size);
+
+  void do_set_wrap_u(CData *cdata, WrapMode wrap);
+  void do_set_wrap_v(CData *cdata, WrapMode wrap);
+  void do_set_wrap_w(CData *cdata, WrapMode wrap);
+  void do_set_minfilter(CData *cdata, FilterType filter);
+  void do_set_magfilter(CData *cdata, FilterType filter);
+  void do_set_anisotropic_degree(CData *cdata, int anisotropic_degree);
+  void do_set_border_color(CData *cdata, const Colorf &color);
+  void do_set_compression(CData *cdata, CompressionMode compression);
+  void do_set_quality_level(CData *cdata, QualityLevel quality_level);
+
+  bool do_has_compression(const CData *cdata) const;
+  virtual bool do_has_ram_image(const CData *cdata) const;
+  virtual bool do_has_uncompressed_ram_image(const CData *cdata) const;
+  CPTA_uchar do_get_ram_image(CData *cdata);
+  CPTA_uchar do_get_uncompressed_ram_image(CData *cdata);
+  void do_set_simple_ram_image(CData *cdata, CPTA_uchar image, int x_size, int y_size);
+  INLINE size_t do_get_ram_image_size(const CData *cdata) const;
+  INLINE bool do_has_ram_mipmap_image(const CData *cdata, int n) const;
+  int do_get_expected_num_mipmap_levels(const CData *cdata) const;
+  INLINE size_t do_get_expected_ram_image_size(const CData *cdata) const;
+  INLINE size_t do_get_expected_ram_view_size(const CData *cdata) const;
+  INLINE size_t do_get_expected_ram_page_size(const CData *cdata) const;
+  size_t do_get_ram_mipmap_page_size(const CData *cdata, int n) const;
+  INLINE size_t do_get_expected_ram_mipmap_image_size(const CData *cdata, int n) const;
+  INLINE size_t do_get_expected_ram_mipmap_view_size(const CData *cdata, int n) const;
+  INLINE size_t do_get_expected_ram_mipmap_page_size(const CData *cdata, int n) const;
+  int do_get_expected_mipmap_x_size(const CData *cdata, int n) const;
+  int do_get_expected_mipmap_y_size(const CData *cdata, int n) const;
+  int do_get_expected_mipmap_z_size(const CData *cdata, int n) const;
+  INLINE int do_get_expected_mipmap_num_pages(const CData *cdata, int n) const;
+  INLINE void do_clear_ram_image(CData *cdata);
+  void do_clear_simple_ram_image(CData *cdata);
+  void do_clear_ram_mipmap_images(CData *cdata);
+  void do_generate_ram_mipmap_images(CData *cdata);
+  void do_set_pad_size(CData *cdata, int x, int y, int z);
+  virtual bool do_can_reload(const CData *cdata) const;
+  bool do_reload(CData *cdata);
+
+  virtual bool do_has_bam_rawdata(const CData *cdata) const;
+  virtual void do_get_bam_rawdata(CData *cdata);
 
   // This nested class declaration is used below.
   class RamImage {
@@ -633,27 +654,27 @@ private:
                                   int num_components, int component_width,
                                   CPTA_uchar image, size_t page_size, 
                                   int z);
-  static PTA_uchar read_dds_level_rgb8(Texture *tex, const DDSHeader &header, 
+  static PTA_uchar read_dds_level_bgr8(Texture *tex, CData *cdata, const DDSHeader &header, 
                                        int n, istream &in);
-  static PTA_uchar read_dds_level_bgr8(Texture *tex, const DDSHeader &header, 
+  static PTA_uchar read_dds_level_rgb8(Texture *tex, CData *cdata, const DDSHeader &header, 
                                        int n, istream &in);
-  static PTA_uchar read_dds_level_abgr8(Texture *tex, const DDSHeader &header, 
+  static PTA_uchar read_dds_level_abgr8(Texture *tex, CData *cdata, const DDSHeader &header, 
                                         int n, istream &in);
-  static PTA_uchar read_dds_level_rgba8(Texture *tex, const DDSHeader &header, 
+  static PTA_uchar read_dds_level_rgba8(Texture *tex, CData *cdata, const DDSHeader &header, 
                                         int n, istream &in);
-  static PTA_uchar read_dds_level_generic_uncompressed(Texture *tex, 
+  static PTA_uchar read_dds_level_generic_uncompressed(Texture *tex, CData *cdata, 
                                                        const DDSHeader &header, 
                                                        int n, istream &in);
-  static PTA_uchar read_dds_level_luminance_uncompressed(Texture *tex, 
+  static PTA_uchar read_dds_level_luminance_uncompressed(Texture *tex, CData *cdata, 
                                                          const DDSHeader &header, 
                                                          int n, istream &in);
-  static PTA_uchar read_dds_level_dxt1(Texture *tex, 
+  static PTA_uchar read_dds_level_dxt1(Texture *tex, CData *cdata, 
                                        const DDSHeader &header, 
                                        int n, istream &in);
-  static PTA_uchar read_dds_level_dxt23(Texture *tex, 
+  static PTA_uchar read_dds_level_dxt23(Texture *tex, CData *cdata, 
                                         const DDSHeader &header, 
                                         int n, istream &in);
-  static PTA_uchar read_dds_level_dxt45(Texture *tex, 
+  static PTA_uchar read_dds_level_dxt45(Texture *tex, CData *cdata, 
                                         const DDSHeader &header, 
                                         int n, istream &in);
 
@@ -673,11 +694,13 @@ private:
   INLINE static bool is_txo_filename(const Filename &fullpath);
   INLINE static bool is_dds_filename(const Filename &fullpath);
 
-  void filter_2d_mipmap_pages(RamImage &to, const RamImage &from,
-                              int x_size, int y_size);
+  void do_filter_2d_mipmap_pages(const CData *cdata,
+                                 RamImage &to, const RamImage &from,
+                                 int x_size, int y_size) const;
 
-  void filter_3d_mipmap_level(RamImage &to, const RamImage &from,
-                              int x_size, int y_size, int z_size);
+  void do_filter_3d_mipmap_level(const CData *cdata,
+                                 RamImage &to, const RamImage &from,
+                                 int x_size, int y_size, int z_size) const;
 
   typedef void Filter2DComponent(unsigned char *&p, 
                                  const unsigned char *&q,
@@ -704,68 +727,123 @@ private:
                                        size_t pixel_size, size_t row_size,
                                        size_t page_size);
   
-  bool do_squish(CompressionMode compression, int squish_flags);
-  bool do_unsquish(int squish_flags);
+  bool do_squish(CData *cdata, CompressionMode compression, int squish_flags);
+  bool do_unsquish(CData *cdata, int squish_flags);
 
 protected:
-  // Protects all of the members of this class.
+  typedef pvector<RamImage> RamImages;
+
+  // This is the data that must be cycled between pipeline stages.
+  class EXPCL_PANDA_GOBJ CData : public CycleData {
+  public:
+    CData();
+    CData(const CData &copy);
+    ALLOC_DELETED_CHAIN(CData);
+    virtual CycleData *make_copy() const;
+    virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
+    virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
+    virtual void fillin(DatagramIterator &scan, BamReader *manager);
+    virtual TypeHandle get_parent_type() const {
+      return Texture::get_class_type();
+    }
+
+    void do_assign(const CData *copy);
+
+    Filename _filename;
+    Filename _alpha_filename;
+    Filename _fullpath;
+    Filename _alpha_fullpath;
+    
+    // The number of channels of the primary file we use.  1, 2, 3, or 4.
+    int _primary_file_num_channels;
+    
+    // If we have a separate alpha file, this designates which channel
+    // in the alpha file provides the alpha channel.  0 indicates the
+    // combined grayscale value of rgb; otherwise, 1, 2, 3, or 4 are
+    // valid.
+    int _alpha_file_channel;
+    
+    int _x_size;
+    int _y_size;
+    int _z_size;
+    int _num_views;
+    int _num_components;
+    int _component_width;
+    TextureType _texture_type;
+    Format _format;
+    ComponentType _component_type;
+    
+    bool _loaded_from_image;
+    bool _loaded_from_txo;
+    bool _has_read_pages;
+    bool _has_read_mipmaps;
+    int _num_mipmap_levels_read;
+    
+    WrapMode _wrap_u;
+    WrapMode _wrap_v;
+    WrapMode _wrap_w;
+    FilterType _minfilter;
+    FilterType _magfilter;
+    int _anisotropic_degree;
+    bool _keep_ram_image;
+    Colorf _border_color;
+    CompressionMode _compression;
+    bool _render_to_texture;
+    bool _match_framebuffer_format;
+    bool _post_load_store_cache;
+    QualityLevel _quality_level;
+    
+    int _pad_x_size;
+    int _pad_y_size;
+    int _pad_z_size;
+    
+    int _orig_file_x_size;
+    int _orig_file_y_size;
+  
+    CompressionMode _ram_image_compression;
+
+    // There is usually one RamImage for the mipmap level 0 (the base
+    // image).  There may or may not also be additional images for the
+    // additional mipmap levels.
+    RamImages _ram_images;
+
+    // This is the simple image, which may be loaded before the texture
+    // is loaded from disk.  It exists only for 2-d textures.
+    RamImage _simple_ram_image;
+    int _simple_x_size;
+    int _simple_y_size;
+    PN_int32 _simple_image_date_generated;
+  
+    UpdateSeq _properties_modified;
+    UpdateSeq _image_modified;
+    UpdateSeq _simple_image_modified;
+    
+  public:
+    static TypeHandle get_class_type() {
+      return _type_handle;
+    }
+    static void init_type() {
+      register_type(_type_handle, "Geom::CData");
+    }
+    
+  private:
+    static TypeHandle _type_handle;
+  };
+ 
+  PipelineCycler<CData> _cycler;
+  typedef CycleDataLockedReader<CData> CDLockedReader;
+  typedef CycleDataReader<CData> CDReader;
+  typedef CycleDataWriter<CData> CDWriter;
+  typedef CycleDataStageReader<CData> CDStageReader;
+  typedef CycleDataStageWriter<CData> CDStageWriter;
+
+  // Protects the remaining members of this class.
   Mutex _lock;
-  // Used to implement do_unlock_and_reload_ram_image()
+
+  // Used to implement unlocked_reload_ram_image().
   ConditionVarFull _cvar;  // condition: _reloading is true.
   bool _reloading;
-
-  Filename _filename;
-  Filename _alpha_filename;
-  Filename _fullpath;
-  Filename _alpha_fullpath;
-  Filename _texture_pool_key;
-
-  // The number of channels of the primary file we use.  1, 2, 3, or 4.
-  int _primary_file_num_channels;
-
-  // If we have a separate alpha file, this designates which channel
-  // in the alpha file provides the alpha channel.  0 indicates the
-  // combined grayscale value of rgb; otherwise, 1, 2, 3, or 4 are
-  // valid.
-  int _alpha_file_channel;
-
-  int _x_size;
-  int _y_size;
-  int _z_size;
-  int _num_views;
-  int _num_components;
-  int _component_width;
-  TextureType _texture_type;
-  Format _format;
-  ComponentType _component_type;
-
-  bool _loaded_from_image;
-  bool _loaded_from_txo;
-  bool _has_read_pages;
-  bool _has_read_mipmaps;
-  int _num_mipmap_levels_read;
-
-  WrapMode _wrap_u;
-  WrapMode _wrap_v;
-  WrapMode _wrap_w;
-  FilterType _minfilter;
-  FilterType _magfilter;
-  int _anisotropic_degree;
-  bool _keep_ram_image;
-  Colorf _border_color;
-  CompressionMode _compression;
-  bool _render_to_texture;
-  bool _match_framebuffer_format;
-  bool _post_load_store_cache;
-  QualityLevel _quality_level;
-
-  int _pad_x_size;
-  int _pad_y_size;
-  int _pad_z_size;
-
-  int _orig_file_x_size;
-  int _orig_file_y_size;
-  
+    
   // A Texture keeps a list (actually, a map) of all the
   // PreparedGraphicsObjects tables that it has been prepared into.
   // Each PGO conversely keeps a list (a set) of all the Textures that
@@ -782,25 +860,9 @@ protected:
   // lookup of the special maps given the diffuse map and the suffix.
   typedef pmap<CPT(InternalName), PT(Texture)> RelatedTextures;
   RelatedTextures _related_textures;
-  
-  CompressionMode _ram_image_compression;
 
-  // There is usually one RamImage for the mipmap level 0 (the base
-  // image).  There may or may not also be additional images for the
-  // additional mipmap levels.
-  typedef pvector<RamImage> RamImages;
-  RamImages _ram_images;
-
-  // This is the simple image, which may be loaded before the texture
-  // is loaded from disk.  It exists only for 2-d textures.
-  RamImage _simple_ram_image;
-  int _simple_x_size;
-  int _simple_y_size;
-  PN_int32 _simple_image_date_generated;
-  
-  UpdateSeq _properties_modified;
-  UpdateSeq _image_modified;
-  UpdateSeq _simple_image_modified;
+  // The TexturePool finds this useful.
+  Filename _texture_pool_key;
   
 private:
   // The auxiliary data is not recorded to a bam file.
@@ -818,14 +880,14 @@ public:
   virtual void finalize(BamReader *manager);
 
 protected:
-  void do_write_datagram_header(BamWriter *manager, Datagram &me, bool &has_rawdata);
-  virtual void do_write_datagram_body(BamWriter *manager, Datagram &me);
-  virtual void do_write_datagram_rawdata(BamWriter *manager, Datagram &me);
+  void do_write_datagram_header(CData *cdata, BamWriter *manager, Datagram &me, bool &has_rawdata);
+  virtual void do_write_datagram_body(CData *cdata, BamWriter *manager, Datagram &me);
+  virtual void do_write_datagram_rawdata(CData *cdata, BamWriter *manager, Datagram &me);
   static TypedWritable *make_from_bam(const FactoryParams &params);
   virtual TypedWritable *make_this_from_bam(const FactoryParams &params);
-  virtual void do_fillin_body(DatagramIterator &scan, BamReader *manager);
-  virtual void do_fillin_rawdata(DatagramIterator &scan, BamReader *manager);
-  virtual void do_fillin_from(Texture *dummy);
+  virtual void do_fillin_body(CData *cdata, DatagramIterator &scan, BamReader *manager);
+  virtual void do_fillin_rawdata(CData *cdata, DatagramIterator &scan, BamReader *manager);
+  virtual void do_fillin_from(CData *cdata, const Texture *dummy);
 
 public:
   static TypeHandle get_class_type() {

+ 24 - 24
panda/src/gobj/texturePeeker.cxx

@@ -24,8 +24,8 @@
 //               and assumes the texture's lock is already held.
 ////////////////////////////////////////////////////////////////////
 TexturePeeker::
-TexturePeeker(Texture *tex) {
-  if (tex->_texture_type == Texture::TT_cube_map) {
+TexturePeeker(Texture *tex, Texture::CData *cdata) {
+  if (cdata->_texture_type == Texture::TT_cube_map) {
     // Cube map texture.  We'll need to map from (u, v, w) to (u, v)
     // within the appropriate page, where w indicates the page.
 
@@ -36,22 +36,22 @@ TexturePeeker(Texture *tex) {
     // Regular 1-d, 2-d, or 3-d texture.  The coordinates map
     // directly.  Simple ram images are possible if it is a 2-d
     // texture.
-    if (tex->do_has_ram_image() && tex->_ram_image_compression == Texture::CM_off) {
+    if (tex->do_has_ram_image(cdata) && cdata->_ram_image_compression == Texture::CM_off) {
       // Get the regular RAM image if it is available.
-      _image = tex->do_get_ram_image();
-      _x_size = tex->_x_size;
-      _y_size = tex->_y_size;
-      _z_size = tex->_z_size;
-      _component_width = tex->_component_width;
-      _num_components = tex->_num_components;
-      _format = tex->_format;
-      _component_type = tex->_component_type;
-
-    } else if (!tex->_simple_ram_image._image.empty()) {
+      _image = tex->do_get_ram_image(cdata);
+      _x_size = cdata->_x_size;
+      _y_size = cdata->_y_size;
+      _z_size = cdata->_z_size;
+      _component_width = cdata->_component_width;
+      _num_components = cdata->_num_components;
+      _format = cdata->_format;
+      _component_type = cdata->_component_type;
+
+    } else if (!cdata->_simple_ram_image._image.empty()) {
       // Get the simple RAM image if *that* is available.
-      _image = tex->_simple_ram_image._image;
-      _x_size = tex->_simple_x_size;
-      _y_size = tex->_simple_y_size;
+      _image = cdata->_simple_ram_image._image;
+      _x_size = cdata->_simple_x_size;
+      _y_size = cdata->_simple_y_size;
       _z_size = 1;
 
       _component_width = 1;
@@ -61,14 +61,14 @@ TexturePeeker(Texture *tex) {
 
     } else {
       // Failing that, reload and get the uncompressed RAM image.
-      _image = tex->do_get_uncompressed_ram_image();
-      _x_size = tex->_x_size;
-      _y_size = tex->_y_size;
-      _z_size = tex->_z_size;
-      _component_width = tex->_component_width;
-      _num_components = tex->_num_components;
-      _format = tex->_format;
-      _component_type = tex->_component_type;
+      _image = tex->do_get_uncompressed_ram_image(cdata);
+      _x_size = cdata->_x_size;
+      _y_size = cdata->_y_size;
+      _z_size = cdata->_z_size;
+      _component_width = cdata->_component_width;
+      _num_components = cdata->_num_components;
+      _format = cdata->_format;
+      _component_type = cdata->_component_type;
     }
   }
 

+ 1 - 1
panda/src/gobj/texturePeeker.h

@@ -29,7 +29,7 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_GOBJ TexturePeeker : public ReferenceCount {
 private:
-  TexturePeeker(Texture *tex);
+  TexturePeeker(Texture *tex, Texture::CData *cdata);
 
 public:
   INLINE bool is_valid() const;

+ 37 - 20
panda/src/gobj/videoTexture.cxx

@@ -30,7 +30,8 @@ VideoTexture(const string &name) :
   Texture(name) 
 {
   // We don't want to try to compress each frame as it's loaded.
-  _compression = CM_off;
+  Texture::CDWriter cdata(Texture::_cycler, true);
+  cdata->_compression = CM_off;
 
   _video_width = 0;
   _video_height = 0;
@@ -118,11 +119,12 @@ void VideoTexture::
 set_video_size(int video_width, int video_height) {
   _video_width = video_width;
   _video_height = video_height;
-  _orig_file_x_size = video_width;
-  _orig_file_y_size = video_height;
+  set_orig_file_size(video_width, video_height);
 
-  do_set_pad_size(max(_x_size - _video_width, 0), 
-                  max(_y_size - _video_height, 0),
+  Texture::CDWriter cdata(Texture::_cycler, true);
+  do_set_pad_size(cdata,
+                  max(cdata->_x_size - _video_width, 0), 
+                  max(cdata->_y_size - _video_height, 0),
                   0);
 }
 
@@ -134,12 +136,12 @@ set_video_size(int video_width, int video_height) {
 //               texture memory or in the prepared GSG context.
 ////////////////////////////////////////////////////////////////////
 bool VideoTexture::
-do_has_ram_image() const {
+do_has_ram_image(const Texture::CData *cdata) const {
   int this_frame = ClockObject::get_global_clock()->get_frame_count();
   if (this_frame != _last_frame_update) {
     return false;
   }
-  return !_ram_images.empty() && !_ram_images[0]._image.empty();
+  return !cdata->_ram_images.empty() && !cdata->_ram_images[0]._image.empty();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -153,20 +155,34 @@ reconsider_dirty() {
   consider_update();
 }
 
+
 ////////////////////////////////////////////////////////////////////
-//     Function: VideoTexture::do_unlock_and_reload_ram_image
+//     Function: VideoTexture::unlocked_ensure_ram_image
 //       Access: Protected, Virtual
-//  Description: This is similar to do_reload_ram_image(), except that
-//               the lock is released during the actual operation, to
-//               allow normal queries into the Texture object to
-//               continue during what might be a slow operation.
+//  Description: If the texture has a ram image already, this acquires
+//               the CData write lock and returns it.
 //
-//               In the case of a VideoTexture, this is exactly the
-//               same as do_reload_ram_image().
-////////////////////////////////////////////////////////////////////
-void VideoTexture::
-do_unlock_and_reload_ram_image(bool) {
+//               If the texture lacks a ram image, this performs
+//               do_reload_ram_image(), but without holding the lock
+//               on this particular Texture object, to avoid holding
+//               the lock across what might be a slow operation.
+//               Instead, the reload is performed in a copy of the
+//               texture object, and then the lock is acquired and the
+//               data is copied in.
+//
+//               In any case, the return value is a locked CData
+//               object, which must be released with an explicit call
+//               to release_write().  The CData object will have a ram
+//               image unless for some reason do_reload_ram_image()
+//               fails.
+////////////////////////////////////////////////////////////////////
+Texture::CData *VideoTexture::
+unlocked_ensure_ram_image(bool allow_compression) {
   consider_update();
+
+  Thread *current_thread = Thread::get_current_thread();
+  Texture::CData *cdata = Texture::_cycler.write_upstream(false, current_thread);
+  return cdata;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -178,7 +194,7 @@ do_unlock_and_reload_ram_image(bool) {
 //               available, if possible.
 ////////////////////////////////////////////////////////////////////
 void VideoTexture::
-do_reload_ram_image(bool) {
+do_reload_ram_image(Texture::CData *cdata, bool) {
   consider_update();
 }
 
@@ -192,7 +208,7 @@ do_reload_ram_image(bool) {
 //               wouldn't work anyway).
 ////////////////////////////////////////////////////////////////////
 bool VideoTexture::
-do_can_reload() {
+do_can_reload(const Texture::CData *cdata) const {
   return true;
 }
 
@@ -208,7 +224,8 @@ consider_update() {
   if (this_frame != _last_frame_update) {
     int frame = get_frame();
     if (_current_frame != frame) {
-      update_frame(frame);
+      Texture::CDWriter cdata(Texture::_cycler, false);
+      do_update_frame(cdata, frame);
       _current_frame = frame;
     }
     _last_frame_update = this_frame;

+ 5 - 5
panda/src/gobj/videoTexture.h

@@ -46,16 +46,16 @@ public:
 protected:
   void set_video_size(int video_width, int video_height);
 
-  virtual bool do_has_ram_image() const;
+  virtual bool do_has_ram_image(const Texture::CData *cdata) const;
 
   virtual void reconsider_dirty();
-  virtual void do_unlock_and_reload_ram_image(bool allow_compression);
-  virtual void do_reload_ram_image(bool allow_compression);
-  virtual bool do_can_reload();
+  virtual Texture::CData *unlocked_ensure_ram_image(bool allow_compression);
+  virtual void do_reload_ram_image(Texture::CData *cdata, bool allow_compression);
+  virtual bool do_can_reload(const Texture::CData *cdata) const;
 
   virtual void consider_update();
   INLINE void clear_current_frame();
-  virtual void update_frame(int frame)=0;
+  virtual void do_update_frame(Texture::CData *cdata_tex, int frame)=0;
 
 protected:
   int _video_width;

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

@@ -14,7 +14,6 @@
     pipeOcclusionCullTraverser.I pipeOcclusionCullTraverser.h \
     cardMaker.I cardMaker.h \
     config_grutil.h \
-    ffmpegTexture.I ffmpegTexture.h \
     movieTexture.I movieTexture.h \
     fisheyeMaker.I fisheyeMaker.h \
     frameRateMeter.I frameRateMeter.h \
@@ -31,7 +30,6 @@
     
   #define INCLUDED_SOURCES \
     cardMaker.cxx \
-    ffmpegTexture.cxx \
     movieTexture.cxx \
     fisheyeMaker.cxx \
     config_grutil.cxx \
@@ -49,7 +47,6 @@
     
   #define INSTALL_HEADERS \
     cardMaker.I cardMaker.h \
-    ffmpegTexture.I ffmpegTexture.h \
     movieTexture.I movieTexture.h \
     fisheyeMaker.I fisheyeMaker.h \
     frameRateMeter.I frameRateMeter.h \

+ 1 - 14
panda/src/grutil/config_grutil.cxx

@@ -18,7 +18,6 @@
 #include "meshDrawer.h"
 #include "meshDrawer2D.h"
 #include "geoMipTerrain.h"
-#include "ffmpegTexture.h"
 #include "movieTexture.h"
 #include "pandaSystem.h"
 #include "texturePool.h"
@@ -116,23 +115,11 @@ init_libgrutil() {
 #endif  // HAVE_AUDIO
 
 #ifdef HAVE_FFMPEG
-  av_register_all();
   MovieTexture::init_type();
   MovieTexture::register_with_read_factory();
-  FFMpegTexture::init_type();
-  FFMpegTexture::register_with_read_factory();
-
-  ConfigVariableBool use_movietexture
-    ("use-movietexture", true,
-     PRC_DESC("Prefer the newer MovieTexture interface over the older "
-              "FFMpegTexture interface when loading movie textures."));
 
   TexturePool *ts = TexturePool::get_global_ptr();
-  if (use_movietexture) {
-    ts->register_texture_type(MovieTexture::make_texture, "avi mov mpg mpeg mp4 wmv asf flv nut ogm mkv");
-  } else {
-    ts->register_texture_type(FFMpegTexture::make_texture, "avi mov mpg mpeg mp4 wmv asf flv nut ogm mkv");
-  }
+  ts->register_texture_type(MovieTexture::make_texture, "avi mov mpg mpeg mp4 wmv asf flv nut ogm mkv");
 #endif  // HAVE_FFMPEG
 }
 

+ 0 - 77
panda/src/grutil/ffmpegTexture.I

@@ -1,77 +0,0 @@
-// Filename: openCVTexture.I
-// Created by:  zacpavlov (19Aug05)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::is_valid
-//       Access: Public
-//  Description: Returns true if this stream is open and ready, false
-//               otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool FFMpegTexture::VideoStream::
-is_valid() const {
-  return (_format_context != NULL && _codec_context != NULL);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::is_from_file
-//       Access: Public
-//  Description: Returns true if this stream takes its input from a
-//               video file, false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool FFMpegTexture::VideoStream::
-is_from_file() const {
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoPage::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE FFMpegTexture::VideoPage::
-VideoPage() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoPage::Copy Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE FFMpegTexture::VideoPage::
-VideoPage(const FFMpegTexture::VideoPage &copy) :
-  _color(copy._color),
-  _alpha(copy._alpha)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoPage::Destructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE FFMpegTexture::VideoPage::
-~VideoPage() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoPage::Copy Assignment Operator
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE void FFMpegTexture::VideoPage::
-operator = (const FFMpegTexture::VideoPage &copy) {
-  _color = copy._color;
-  _alpha = copy._alpha;
-}

+ 0 - 1106
panda/src/grutil/ffmpegTexture.cxx

@@ -1,1106 +0,0 @@
-// Filename: ffmpegTexture.cxx
-// Created by:  zacpavlov (05May06)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
-
-#include "pandabase.h"
-
-#ifdef HAVE_FFMPEG
-#include "ffmpegTexture.h"
-#include "clockObject.h"
-#include "config_gobj.h"
-#include "config_grutil.h"
-#include "bamCacheRecord.h"
-#include "bamReader.h"
-#include "bamWriter.h"
-
-TypeHandle FFMpegTexture::_type_handle;
-
-#if LIBAVFORMAT_VERSION_MAJOR < 53
-  #define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
-#endif
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::Constructor
-//       Access: Published
-//  Description: 
-////////////////////////////////////////////////////////////////////
-FFMpegTexture::
-FFMpegTexture(const string &name) : 
-  VideoTexture(name) 
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::Copy Constructor
-//       Access: Protected
-//  Description: Use FFmpegTexture::make_copy() to make a duplicate copy of
-//               an existing FFMpegTexture.
-////////////////////////////////////////////////////////////////////
-FFMpegTexture::
-FFMpegTexture(const FFMpegTexture &copy) : 
-  VideoTexture(copy),
-  _pages(copy._pages)
-{
-  nassertv(false);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::Destructor
-//       Access: Published, Virtual
-//  Description: I'm betting that texture takes care of the, so we'll
-//               just do a clear.
-////////////////////////////////////////////////////////////////////
-FFMpegTexture::
-~FFMpegTexture() {
-  clear();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_make_copy
-//       Access: Protected, 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 FFMpegTexture, the resulting
-//               duplicate may be animated independently of the
-//               original.
-////////////////////////////////////////////////////////////////////
-PT(Texture) FFMpegTexture::
-do_make_copy() {
-  PT(FFMpegTexture) tex = new FFMpegTexture(get_name());
-  tex->do_assign(*this);
-
-  return tex.p();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_assign
-//       Access: Protected
-//  Description: Implements make_copy().
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::
-do_assign(const FFMpegTexture &copy) {
-  VideoTexture::do_assign(copy);
-
-  _pages = copy._pages;
-  Pages::iterator pi;
-  for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
-    VideoPage *page = (*pi);
-    (*pi) = new VideoPage(*page);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::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, 3-d
-//               textures, and multiview textures have more.
-////////////////////////////////////////////////////////////////////
-FFMpegTexture::VideoPage &FFMpegTexture::
-modify_page(int z) {
-  nassertr(z < get_num_pages(), *_pages[0]);
-  while (z >= (int)_pages.size()) {
-    _pages.push_back(new VideoPage());
-  }
-  return *_pages[z];
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFmpegTexture::do_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 FFMpegTexture::
-do_reconsider_video_properties(const FFMpegTexture::VideoStream &stream, 
-                               int num_components, int z, 
-                               const LoaderOptions &options) {
-  double frame_rate = 0.0f;
-  int num_frames = 0;
-  if (!stream._codec_context) {
-    // printf("not valid yet\n");
-    return true;
-  }
-  
-  AVStream *vstream = stream._format_context->streams[stream._stream_number];
-  
-  if (stream.is_from_file()) {
-    // frame rate comes from ffmpeg as an avRational. 
-    frame_rate = vstream->r_frame_rate.num/(float)vstream->r_frame_rate.den;
-    
-    // Number of frames is a little questionable if we've got variable 
-    // frame rate. Duration comes in as a generic timestamp, 
-    // and is therefore multiplied by AV_TIME_BASE.
-    num_frames = (int)((stream._format_context->duration*frame_rate)/AV_TIME_BASE);
-    if (grutil_cat.is_debug()) {
-      grutil_cat.debug()
-        << "Loaded " << stream._filename << ", "
-        << num_frames << " frames at " << frame_rate << " fps\n";
-    }
-  }
-  
-  int width = stream._codec_context->width;
-  int height = stream._codec_context->height;
-
-  int x_size = width;
-  int y_size = height;
-
-  do_adjust_this_size(x_size, y_size, get_name(), true);
-
-  if (grutil_cat.is_debug()) {
-    grutil_cat.debug()
-      << "Video stream is " << width << " by " << height 
-      << " pixels; fitting in texture " << x_size << " by "
-      << y_size << " texels.\n";
-  }
-
-  if (!do_reconsider_image_properties(x_size, y_size, num_components,
-                                      T_unsigned_byte, z, options)) {
-    return false;
-  }
-
-  if (_loaded_from_image && 
-      (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: FFMpegTexture::make_texture
-//       Access: Public, Static
-//  Description: A factory function to make a new FFMpegTexture, used
-//               to pass to the TexturePool.
-////////////////////////////////////////////////////////////////////
-PT(Texture) FFMpegTexture::
-make_texture() {
-  return new FFMpegTexture;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::update_frame
-//       Access: Protected, Virtual
-//  Description: Called once per frame, as needed, to load the new
-//               image contents.
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::
-update_frame(int frame) {
-  int max_z = min(get_num_pages(), (int)_pages.size());
-  size_t page_size = do_get_expected_ram_page_size();
-  for (int z = 0; z < max_z; ++z) {
-    VideoPage &page = *(_pages.at(z));
-    if (page._color.is_valid() || page._alpha.is_valid()) {
-      do_modify_ram_image();
-      if (_ram_images[0]._image.size() != do_get_expected_ram_image_size()) {
-        do_make_ram_image();
-      }
-    }
-    if (page._color.is_valid()) {
-      nassertv(_num_components >= 3 && _component_width == 1);
-
-      // A little different from the opencv implementation
-      // The frame is kept on the stream itself. This is partially 
-      // because there is a conversion step that must be done for 
-      // every video (I've gotten very odd results with any video
-      // that I don't convert, even if the IO formats are the same!)  
-      if (page._color.get_frame_data(frame)) {
-        nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
-        unsigned char *dest = _ram_images[0]._image.p() + page_size * z;
-        nassertv(dest + page_size <= _ram_images[0]._image.p() + _ram_images[0]._image.size());
-        int dest_row_width = (_x_size * _num_components * _component_width);
-        
-        // Simplest case, where we deal with an rgb texture
-        if (_num_components == 3) {
-          int source_row_width=3*page._color._codec_context->width;
-          unsigned char * source=(unsigned char *)page._color._frame_out->data[0]
-            +source_row_width*(get_video_height()-1);         
-
-          // row by row copy.        
-          for (int y = 0; y < get_video_height(); ++y) {
-            memcpy(dest, source, source_row_width);
-            dest += dest_row_width;
-            source -= source_row_width;
-          }
-          // Next best option, we're a 4 component alpha video on one stream 
-        } else if (page._color._codec_context->pix_fmt==PIX_FMT_RGB32) {
-          int source_row_width= page._color._codec_context->width * 4;
-          unsigned char * source=(unsigned char *)page._color._frame_out->data[0]
-            +source_row_width*(get_video_height()-1);
-          
-          // row by row copy.        
-          for (int y = 0; y < get_video_height(); ++y) {
-            memcpy(dest,source,source_row_width);
-            dest += dest_row_width;
-            source -= source_row_width;
-          } 
-          // Otherwise, we've got to be tricky
-        } else {
-          int source_row_width= page._color._codec_context->width * 3;
-          unsigned char * source=(unsigned char *)page._color._frame_out->data[0]
-            +source_row_width*(get_video_height()-1);
-          
-          // The harder case--interleave the color in with the alpha,
-          // pixel by pixel.
-          nassertv(_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;
-          }
-        }
-      }
-      ++_image_modified;
-    }
-    
-    if (page._alpha.is_valid()) {
-      nassertv(_num_components == 4 && _component_width == 1);
-  
-      if (page._alpha.get_frame_data(frame)) {
-        nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
-        
-        // Currently, we assume the alpha has been converted to an rgb format
-        // There is no reason it can't be a 256 color grayscale though.
-        unsigned char *dest = _ram_images[0]._image.p() + page_size * z;
-        nassertv(dest + page_size <= _ram_images[0]._image.p() + _ram_images[0]._image.size());
-        int dest_row_width = (_x_size * _num_components * _component_width);
-        
-        int source_row_width= page._alpha._codec_context->width * 3;
-        unsigned char * source=(unsigned char *)page._alpha._frame_out->data[0]
-          +source_row_width*(get_video_height()-1);
-        for (int y = 0; y < get_video_height(); ++y) {
-          int dx = 3;
-          int sx = 0;
-          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;
-        }
-      }
-      ++_image_modified;
-    }
-  }
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_adjust_this_size
-//       Access: Protected, Virtual
-//  Description: Works like adjust_size, but also considers the
-//               texture class.  Movie textures, for instance, always
-//               pad outwards, never scale down.
-////////////////////////////////////////////////////////////////////
-bool FFMpegTexture::
-do_adjust_this_size(int &x_size, int &y_size, const string &name,
-                    bool for_padding) {
-  if (Texture::get_textures_power_2() != ATS_none) {
-    x_size = up_to_power_2(x_size);
-    y_size = up_to_power_2(y_size);
-  }
-
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_read_one
-//       Access: Protected, 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 FFMpegTexture::
-do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
-            int z, int n, int primary_file_num_channels, int alpha_file_channel,
-            const LoaderOptions &options,
-            bool header_only, BamCacheRecord *record) {
-  if (record != (BamCacheRecord *)NULL) {
-    record->add_dependent_file(fullpath);
-  }
-
-  nassertr(n == 0, false);
-  if (!do_reconsider_z_size(z, options)) {
-    return false;
-  }
-  nassertr(z >= 0 && z < _z_size * _num_views, false);
-
-  VideoPage &page = modify_page(z);
-  if (!page._color.read(fullpath)) {
-    grutil_cat.error()
-      << "FFMpeg couldn't read " << fullpath << " as video.\n";
-    return false;
-  }
-
-  if (!alpha_fullpath.empty()) {
-    if (!page._alpha.read(alpha_fullpath)) {
-      grutil_cat.error()
-        << "FFMPEG couldn't read " << alpha_fullpath << " as video.\n";
-      page._color.clear();
-      return false;
-    }
-  }
-
-
-  if (z == 0) {
-    if (!has_name()) {
-      set_name(fullpath.get_basename_wo_extension());
-    }
-    if (!_filename.empty()) {
-      _filename = fullpath;
-      _alpha_filename = alpha_fullpath;
-    }
-
-    _fullpath = fullpath;
-    _alpha_fullpath = alpha_fullpath;
-  }
-  if (page._color._codec_context->pix_fmt==PIX_FMT_RGB32) {
-    // There had better not be an alpha interleave here. 
-    nassertr(alpha_fullpath.empty(), false);
-    
-    _primary_file_num_channels = 4;
-    _alpha_file_channel = 0;
-    if (!do_reconsider_video_properties(page._color, 4, z, options)) {
-      page._color.clear();
-      return false;
-    }
-     
-  } else {
-    _primary_file_num_channels = 3;
-    _alpha_file_channel = alpha_file_channel;
-
-    if (page._alpha.is_valid()) {
-      if (!do_reconsider_video_properties(page._color, 4, z, options)) {
-        page._color.clear();
-        page._alpha.clear();
-        return false;
-      }
-      if (!do_reconsider_video_properties(page._alpha, 4, z, options)) {
-        page._color.clear();
-        page._alpha.clear();
-        return false;
-      }
-    } else {
-      if (!do_reconsider_video_properties(page._color, 3, z, options)) {
-        page._color.clear();
-        page._alpha.clear();
-        return false;
-      }
-    }
-  }
-
-  set_loaded_from_image();
-  clear_current_frame();
-  update_frame(0);
-  return true;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_load_one
-//       Access: Protected, Virtual
-//  Description: Resets the texture (or the particular level of the
-//               texture) to the indicated static image.
-////////////////////////////////////////////////////////////////////
-bool FFMpegTexture::
-do_load_one(const PNMImage &pnmimage, const string &name, int z, int n,
-            const LoaderOptions &options) {
-  if (z <= (int)_pages.size()) {
-    VideoPage &page = modify_page(z);
-    page._color.clear();
-  }
-
-  return Texture::do_load_one(pnmimage, name, z, n, options);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_allocate_pages
-//       Access: Protected, Virtual
-//  Description: Called internally by do_reconsider_z_size() to
-//               allocate new memory in _ram_images[0] for the new
-//               number of pages.
-//
-//               Assumes the lock is already held.
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::
-do_allocate_pages() {
-  // We don't actually do anything here; the allocation is made in
-  // do_load_one(), above.
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_clear
-//       Access: Protected, Virtual
-//  Description: The protected implementation of clear().  Assumes the
-//               lock is already held.
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::
-do_clear() {
-  Texture::do_clear();
-
-  Pages::iterator pi;
-  for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
-    delete (*pi);
-  }
-  _pages.clear();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_has_bam_rawdata
-//       Access: Protected, Virtual
-//  Description: Returns true if there is a rawdata image that we have
-//               available to write to the bam stream.  For a normal
-//               Texture, this is the same thing as
-//               do_has_ram_image(), but a movie texture might define
-//               it differently.
-////////////////////////////////////////////////////////////////////
-bool FFMpegTexture::
-do_has_bam_rawdata() const {
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_get_bam_rawdata
-//       Access: Protected, Virtual
-//  Description: If do_has_bam_rawdata() returned false, this attempts
-//               to reload the rawdata image if possible.
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::
-do_get_bam_rawdata() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_can_reload
-//       Access: Protected, Virtual
-//  Description: Returns true if we can safely call
-//               do_unlock_and_reload_ram_image() in order to make the
-//               image available, or false if we shouldn't do this
-//               (because we know from a priori knowledge that it
-//               wouldn't work anyway).
-////////////////////////////////////////////////////////////////////
-bool FFMpegTexture::
-do_can_reload() {
-  return false;
-}
-
-
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::register_with_read_factory
-//       Access: Public, Static
-//  Description: Factory method to generate a Texture object
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::
-register_with_read_factory() {
-  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::make_from_bam
-//       Access: Protected, Static
-//  Description: Factory method to generate an FFMpegTexture object
-////////////////////////////////////////////////////////////////////
-TypedWritable *FFMpegTexture::
-make_from_bam(const FactoryParams &params) {
-  PT(FFMpegTexture) dummy = new FFMpegTexture;
-  return dummy->make_this_from_bam(params);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_write_datagram_rawdata
-//       Access: Protected, Virtual
-//  Description: Writes the rawdata part of the texture to the
-//               Datagram.
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::
-do_write_datagram_rawdata(BamWriter *manager, Datagram &me) {
-  me.add_uint16(_pages.size());
-  for (size_t n = 0; n < _pages.size(); ++n) {
-    VideoPage &page = (*_pages[n]);
-    page.write_datagram_rawdata(manager, me);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::do_fillin_rawdata
-//       Access: Protected, Virtual
-//  Description: Reads in the part of the Texture that was written
-//               with do_write_datagram_rawdata().
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::
-do_fillin_rawdata(DatagramIterator &scan, BamReader *manager) {
-  int num_pages = scan.get_uint16();
-  _pages.clear();
-  for (int n = 0; n < num_pages; ++n) {
-    _pages.push_back(new VideoPage());
-    VideoPage &page = *(_pages.back());
-    page.fillin_rawdata(scan, manager);
-
-    LoaderOptions options;
-    do_reconsider_video_properties(page._color, _num_components, n, options);
-    if (page._alpha.is_valid()) {
-      do_reconsider_video_properties(page._alpha, _num_components, n, options);
-    }
-  }
-
-  _loaded_from_image = true;
-  ++_image_modified;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-FFMpegTexture::VideoStream::
-VideoStream() :
-  _codec_context(NULL),
-  _format_context(NULL),
-  _frame(NULL),
-  _frame_out(NULL),
-  _next_frame_number(0)
-{
-  // printf("creating video stream\n");
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::Copy Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-FFMpegTexture::VideoStream::
-VideoStream(const FFMpegTexture::VideoStream &copy) :
-  _codec_context(NULL),
-  _format_context(NULL),
-  _frame(NULL),
-  _frame_out(NULL),
-  _next_frame_number(0)
-{
-  // Rather than copying the _capture pointer, we must open a new
-  // stream that references the same file.
-  if (copy.is_valid() && copy.is_from_file()) {
-    if (copy._file_info.is_empty()) {
-      read(copy._filename);
-    } else {
-      read(copy._file_info);
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::Destructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-FFMpegTexture::VideoStream::
-~VideoStream() {
-  clear();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::Copy Assignment Operator
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::VideoStream::
-operator = (const FFMpegTexture::VideoStream &copy) {
-  clear();
-
-  // Rather than copying the _capture pointer, we must open a new
-  // stream that references the same file.
-  if (copy.is_valid() && copy.is_from_file()) {
-    if (copy._file_info.is_empty()) {
-      read(copy._filename);
-    } else {
-      read(copy._file_info);
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::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.
-////////////////////////////////////////////////////////////////////
-bool FFMpegTexture::VideoStream::
-get_frame_data(int frame_number) {
-  nassertr(is_valid(), false);
-  int coming_from = _next_frame_number;
-
-  _next_frame_number = frame_number + 1;
-  AVPacket packet;
-  AVStream *vstream = _format_context->streams[_stream_number];
-  
-  int got_frame;
-                  
-  // Can we get to our target frame just by skipping forward a few
-  // frames?  We arbitrarily draw the line at 50 frames for now.
-  if (frame_number >= coming_from && frame_number - coming_from < 50) { 
-
-    if (frame_number > coming_from) {
-      // Ok, we do have to skip a few frames.
-      _codec_context->skip_frame = AVDISCARD_BIDIR;
-
-      while (frame_number > coming_from) {
-        int err = read_video_frame(&packet);
-        if (err < 0) {
-          return false;
-        }
-#if LIBAVCODEC_VERSION_INT < 3414272
-        avcodec_decode_video(_codec_context, _frame, &got_frame, packet.data, packet.size);
-#else
-        avcodec_decode_video2(_codec_context, _frame, &got_frame, &packet);
-#endif
-        av_free_packet(&packet);
-        ++coming_from;
-      }
-      _codec_context->skip_frame = AVDISCARD_DEFAULT;
-    }
-
-    // Now we're ready to read a frame.
-    int err = read_video_frame(&packet);
-    if (err < 0) {
-      return false;
-    }
-
-  } else {
-    // We have to skip backward, or maybe forward a whole bunch of
-    // frames.  Better off seeking through the stream.
-
-    double time_stamp = ((double)AV_TIME_BASE * frame_number * vstream->r_frame_rate.den) / vstream->r_frame_rate.num;
-    double curr_time_stamp;
-
-    // find point in time
-    av_seek_frame(_format_context, -1, (long long)time_stamp,
-                  AVSEEK_FLAG_BACKWARD);
-    
-    // Okay, now we're at the nearest keyframe behind our timestamp.
-    // Hurry up and move through frames until we find a frame just after it.
-    _codec_context->skip_frame = AVDISCARD_BIDIR;
-    do {
-      int err = read_video_frame(&packet);
-      if (err < 0) {
-        return false;
-      }
-
-      curr_time_stamp = (((double)AV_TIME_BASE * packet.pts) / 
-                         ((double)packet.duration * av_q2d(vstream->r_frame_rate)));
-      if (curr_time_stamp > time_stamp) {
-        break;
-      }
-
-#if LIBAVCODEC_VERSION_INT < 3414272
-      avcodec_decode_video(_codec_context, _frame, &got_frame, packet.data, packet.size);
-#else
-      avcodec_decode_video2(_codec_context, _frame, &got_frame, &packet);
-#endif
-
-      av_free_packet(&packet);
-    } while (true);
-    
-    _codec_context->skip_frame = AVDISCARD_DEFAULT;
-    // Now near frame with Packet ready for decode (and free)
-  }
-  
-  // Now we have a packet from someone. Lets get this in a frame
-  
-  int frame_finished;
-
-  // Is this a packet from the video stream?
-  if (packet.stream_index == _stream_number) {
-    // Decode video frame
-#if LIBAVCODEC_VERSION_INT < 3414272
-    avcodec_decode_video(_codec_context, _frame, &frame_finished, packet.data, packet.size);
-#else
-    avcodec_decode_video2(_codec_context, _frame, &frame_finished, &packet);
-#endif
-
-    // Did we get a video frame?
-    if (frame_finished) {
-      // Convert the image from its native format to RGB
-#ifdef HAVE_SWSCALE
-      // Note from pro-rsoft: ffmpeg removed img_convert and told
-      // everyone to use sws_scale instead - that's why I wrote
-      // this code. I have no idea if it works well or not, but
-      // it seems to compile and run without crashing.
-      PixelFormat dst_format;
-      if (_codec_context->pix_fmt != PIX_FMT_RGB32) {
-        dst_format = PIX_FMT_BGR24;
-      } else {
-        dst_format = PIX_FMT_RGB32;
-      }
-      struct SwsContext *convert_ctx = 
-        sws_getContext(_codec_context->width, _codec_context->height,
-                       _codec_context->pix_fmt, _codec_context->width, _codec_context->height,
-                       dst_format, SWS_FAST_BILINEAR, NULL, NULL, NULL);
-      nassertr(convert_ctx != NULL, false);
-      sws_scale(convert_ctx, _frame->data, _frame->linesize,
-                0, _codec_context->height, _frame_out->data, _frame_out->linesize);
-      sws_freeContext(convert_ctx);
-#else
-      if (_codec_context->pix_fmt != PIX_FMT_RGB32) {
-        img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24, 
-                    (AVPicture *)_frame, _codec_context->pix_fmt, 
-                    _codec_context->width, _codec_context->height);
-
-      } else { // _codec_context->pix_fmt == PIX_FMT_RGB32
-        img_convert((AVPicture *)_frame_out, PIX_FMT_RGB32, 
-                    (AVPicture *)_frame, _codec_context->pix_fmt, 
-                    _codec_context->width, _codec_context->height);
-      }
-#endif
-    }
-  }
-
-  // Free the packet that was allocated by av_read_frame
-  av_free_packet(&packet);
-
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::read
-//       Access: Public
-//  Description: Sets up the stream to read the indicated file from
-//               the VFS.  Returns true on success, false on failure.
-////////////////////////////////////////////////////////////////////
-bool FFMpegTexture::VideoStream::
-read(const Filename &filename) {
-  // Clear out the last stream
-  clear();
-  
-  // Open video file
-  if (!_ffvfile.open_vfs(filename)) {
-    grutil_cat.error()
-      << "couldn't open " << filename << "\n";
-    // Don't call clear(), because nothing happened yet
-    return false;
-  }
-
-  _filename = filename;
-  return continue_read();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::read
-//       Access: Public
-//  Description: Sets up the stream to read the indicated file,
-//               avoiding the VFS.  Returns true on success, false on
-//               failure.
-////////////////////////////////////////////////////////////////////
-bool FFMpegTexture::VideoStream::
-read(const SubfileInfo &info) {
-  // Clear out the last stream
-  clear();
-  
-  // Open video file
-  if (!_ffvfile.open_subfile(info)) {
-    grutil_cat.error()
-      << "couldn't open " << info << "\n";
-    // Don't call clear(), because nothing happened yet
-    return false;
-  }
-
-  _file_info = info;
-  _filename = _file_info.get_filename();
-  return continue_read();
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::clear
-//       Access: Public
-//  Description: Stops the video playback and frees the associated
-//               resources.
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::VideoStream::
-clear() {
-  if (_codec_context) {
-    avcodec_close(_codec_context);
-    _codec_context = NULL;
-  }
-
-  if (_frame) {
-    av_free(_frame);
-    _frame = NULL;
-  }
-  if (_frame_out) {
-    av_free(_frame_out);
-    _frame_out = NULL;
-  }
-
-  // We cannot close the format_context, since we didn't open it--the
-  // FfmpegVirtualFile will do that.
-  _format_context = NULL;
-
-  _next_frame_number = 0;
-  _filename = Filename();
-  _file_info = SubfileInfo();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::write_datagram_rawdata
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::VideoStream::
-write_datagram_rawdata(BamWriter *manager, Datagram &me) {
-  SubfileInfo result;
-  if (!_file_info.is_empty()) {
-    me.add_bool(true);
-    manager->write_file_data(result, _file_info);
-  } else if (!_filename.empty()) {
-    me.add_bool(true);
-    manager->write_file_data(result, _filename);
-  } else {
-    me.add_bool(false);
-  }
-
-  /* Not sure yet if this is a good idea.
-  if (!result.is_empty()) {
-    // If we've just copied the data to a local file, read it from
-    // there in the future.
-    _file_info = result;
-  }
-  */
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::fillin_rawdata
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::VideoStream::
-fillin_rawdata(DatagramIterator &scan, BamReader *manager) {
-  bool got_info = scan.get_bool();
-  if (got_info) {
-    SubfileInfo info;
-    manager->read_file_data(info);
-    read(info);
-  } else {
-    clear();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::continue_read
-//       Access: Private
-//  Description: Once the FfmpegVirtualFile has been opened, continues
-//               to make the appropriate ffmpeg calls to open the
-//               stream.
-////////////////////////////////////////////////////////////////////
-bool FFMpegTexture::VideoStream::
-continue_read() {
-  _format_context = _ffvfile.get_format_context();
-  nassertr(_format_context != NULL, false);
-
-  // Retrieve stream information
-  int result = av_find_stream_info(_format_context);
-  if (result < 0) {
-    grutil_cat.error() << "ffmpeg AVERROR: " << result << endl;
-    clear();
-    return false;
-  }
-  dump_format(_format_context, 0, _filename.c_str(), false);
-  
-  _stream_number = -1;
-  for(size_t i = 0; i < _format_context->nb_streams; i++) {
-    if ((*_format_context->streams[i]->codec).codec_type == AVMEDIA_TYPE_VIDEO) {
-      _stream_number = i;
-      break;
-    }
-  }
-
-  if (_stream_number == -1) {
-    grutil_cat.error()
-      << "ffmpeg: no stream found with codec of type AVMEDIA_TYPE_VIDEO" << endl;
-    clear();
-    return false;
-  }
-  
-  // Get a pointer to the codec context for the video stream
-  AVCodecContext *codec_context = _format_context->streams[_stream_number]->codec;
-  
-  if (grutil_cat.is_debug()) {
-    grutil_cat.debug()
-      << "ffmpeg: codec id is " << codec_context->codec_id << endl;
-  }
-
-  // Find the decoder for the video stream
-  _codec = avcodec_find_decoder(codec_context->codec_id);
-  if (_codec == NULL) {
-    grutil_cat.error() << "ffmpeg: no appropriate decoder found" << endl;
-    clear();
-    return false;
-  }
-
-  if (_codec->capabilities & CODEC_CAP_TRUNCATED) {
-    codec_context->flags |= CODEC_FLAG_TRUNCATED;
-  }
-
-  // Open codec
-  _codec_context = codec_context;
-  result = avcodec_open(_codec_context, _codec);
-  if (result < 0) {
-    grutil_cat.error() << "ffmpeg AVERROR: " << result << endl;
-    _codec_context = NULL;
-    clear();
-    return false;
-  }
-  
-  _frame = avcodec_alloc_frame();
-  
-  if (_codec_context->pix_fmt != PIX_FMT_RGB32) {
-    _frame_out = avcodec_alloc_frame();
-    if (_frame_out == NULL) {
-      grutil_cat.error()
-        << "ffmpeg: unable to allocate AVPFrame (BGR24)" << endl;
-      clear();
-      return false;
-    }
-
-    // Determine required buffer size and allocate buffer
-    _image_size_bytes = avpicture_get_size(PIX_FMT_BGR24, _codec_context->width,
-                                           _codec_context->height);
-            
-    _raw_data = new uint8_t[_image_size_bytes];
-
-    // Assign appropriate parts of buffer to image planes in _frameRGB
-    avpicture_fill((AVPicture *)_frame_out, _raw_data, PIX_FMT_BGR24,
-                   _codec_context->width, _codec_context->height);
-
-  } else {
-    _frame_out = avcodec_alloc_frame();
-    if (_frame_out == NULL) {
-      grutil_cat.error()
-        << "ffmpeg: unable to allocate AVPFrame (RGBA32)" << endl;
-      clear();
-      return false;
-    }
-    
-    // Determine required buffer size and allocate buffer
-    _image_size_bytes = avpicture_get_size(PIX_FMT_RGB32, _codec_context->width,
-                                           _codec_context->height);
-            
-    _raw_data = new uint8_t[_image_size_bytes];
-    // Assign appropriate parts of buffer to image planes in _frameRGB
-    avpicture_fill((AVPicture *)_frame_out, _raw_data, PIX_FMT_RGB32,
-                   _codec_context->width, _codec_context->height);
-  } 
-  // We could put an option here for single channel frames.
-  
-  _next_frame_number = 0;
-
-  return true;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoStream::read_video_frame
-//       Access: Private
-//  Description: Fills packet with the next sequential video frame in
-//               the stream, skipping over all non-video frames.
-//               packet must later be deallocated with
-//               av_free_packet().
-//
-//               Returns nonnegative on success, or negative on error.
-////////////////////////////////////////////////////////////////////
-int FFMpegTexture::VideoStream::
-read_video_frame(AVPacket *packet) {
-  int err = av_read_frame(_format_context, packet);
-  if (grutil_cat.is_spam()) {
-    grutil_cat.spam()
-      << "av_read_frame() = " << err << "\n";
-  }
-  if (err < 0) {
-    return err;
-  }
-
-  while (packet->stream_index != _stream_number) {
-    // It's not a video packet; free it and get another.
-    av_free_packet(packet);
-
-    err = av_read_frame(_format_context, packet);
-    if (grutil_cat.is_spam()) {
-      grutil_cat.spam()
-        << "av_read_frame() = " << err << "\n";
-    }
-    if (err < 0) {
-      if (grutil_cat.is_debug()) {
-        grutil_cat.debug()
-          << "Got error " << err << " reading frame.\n";
-      }
-      return err;
-    }
-  }
-
-  // This is a video packet, return it.
-  return err;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoPage::write_datagram_rawdata
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::VideoPage::
-write_datagram_rawdata(BamWriter *manager, Datagram &me) {
-  _color.write_datagram_rawdata(manager, me);
-  _alpha.write_datagram_rawdata(manager, me);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FFMpegTexture::VideoPage::fillin_rawdata
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void FFMpegTexture::VideoPage::
-fillin_rawdata(DatagramIterator &scan, BamReader *manager) {
-  _color.fillin_rawdata(scan, manager);
-  _alpha.fillin_rawdata(scan, manager);
-}
-
-
-#endif  // HAVE_FFMPEG
-

+ 0 - 165
panda/src/grutil/ffmpegTexture.h

@@ -1,165 +0,0 @@
-// Filename: ffmpegTexture.h
-// Created by:  zacpavlov (19Aug05)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef FFMPEGTEXTURE_H
-#define FFMPEGTEXTURE_H
-
-#include "pandabase.h"
-#ifdef HAVE_FFMPEG
-
-#include "videoTexture.h"
-#include "ffmpegVirtualFile.h"
-
-extern "C" {
-  #include "libavcodec/avcodec.h"
-  #include "libavformat/avformat.h"
-#ifdef HAVE_SWSCALE
-  #include "libswscale/swscale.h"
-#endif
-}
-
-////////////////////////////////////////////////////////////////////
-//       Class : FFMpegTexture
-// Description : 
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_GRUTIL FFMpegTexture : public VideoTexture {
-PUBLISHED:
-  FFMpegTexture(const string &name = string());
-protected:
-  FFMpegTexture(const FFMpegTexture &copy);
-PUBLISHED:
-  virtual ~FFMpegTexture();
-
-public:
-  static PT(Texture) make_texture();
-
-protected:
-  virtual PT(Texture) do_make_copy();
-  void do_assign(const FFMpegTexture &copy);
-
-  virtual void update_frame(int frame);
-  virtual bool do_adjust_this_size(int &x_size, int &y_size, const string &name, 
-                                   bool for_padding);
-  virtual bool do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
-                           int z, int n, int primary_file_num_channels, int alpha_file_channel,
-                           const LoaderOptions &options,
-                           bool header_only, BamCacheRecord *record);
-  virtual bool do_load_one(const PNMImage &pnmimage, const string &name,
-                           int z, int n, const LoaderOptions &options);
-  virtual void do_allocate_pages();
-  virtual void do_clear();
-
-  virtual bool do_has_bam_rawdata() const;
-  virtual void do_get_bam_rawdata();
-  virtual bool do_can_reload();
-
-private:    
-  class VideoPage;
-  class VideoStream;
-
-  VideoPage &modify_page(int z);
-  bool do_reconsider_video_properties(const VideoStream &stream, 
-                                      int num_components, int z, 
-                                      const LoaderOptions &options);
-  void do_update();
-    
-  class VideoStream {
-  public:
-    VideoStream();
-    VideoStream(const VideoStream &copy);
-    ~VideoStream();
-    void operator = (const VideoStream &copy);
-
-    bool read(const Filename &filename);
-    bool read(const SubfileInfo &info);
-    void clear();
-    INLINE bool is_valid() const;
-    INLINE bool is_from_file() const;
-    bool get_frame_data(int frame);
-
-    void write_datagram_rawdata(BamWriter *manager, Datagram &me);
-    void fillin_rawdata(DatagramIterator &scan, BamReader *manager);
-
-  private:
-    bool continue_read();
-    int read_video_frame(AVPacket *packet);
-
-  public:
-    AVCodecContext *_codec_context; 
-    AVFormatContext *_format_context; 
-    FfmpegVirtualFile _ffvfile;
-    
-    int _stream_number;
-    AVFrame *_frame;
-    AVFrame *_frame_out;
-
-    Filename _filename;
-    SubfileInfo _file_info;
-
-    int _next_frame_number;
-    int _image_size_bytes;
-
-  private:
-    unsigned char * _raw_data;
-    AVCodec *_codec;
-  };
-
-  class VideoPage {
-  public:
-    INLINE VideoPage();
-    INLINE VideoPage(const VideoPage &copy);
-    INLINE ~VideoPage();
-    INLINE void operator = (const VideoPage &copy);
-
-    void write_datagram_rawdata(BamWriter *manager, Datagram &me);
-    void fillin_rawdata(DatagramIterator &scan, BamReader *manager);
-
-    VideoStream _color, _alpha;
-  };
-
-  typedef pvector<VideoPage *> Pages;
-  Pages _pages;
-
-public:
-  static void register_with_read_factory();
-
-  static TypedWritable *make_from_bam(const FactoryParams &params);
-  virtual void do_write_datagram_rawdata(BamWriter *manager, Datagram &me);
-  virtual void do_fillin_rawdata(DatagramIterator &scan, BamReader *manager);
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    VideoTexture::init_type();
-    register_type(_type_handle, "FFMpegTexture",
-                  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 "ffmpegTexture.I"
-
-
-
-#endif  // HAVE_OPENCV
-
-#endif

+ 0 - 1
panda/src/grutil/grutil_composite2.cxx

@@ -1,4 +1,3 @@
-#include "ffmpegTexture.cxx"
 #include "movieTexture.cxx"
 #include "nodeVertexTransform.cxx"
 #include "pipeOcclusionCullTraverser.cxx"

+ 0 - 30
panda/src/grutil/movieTexture.I

@@ -52,33 +52,3 @@ get_video_height() const {
   return cdata->_video_height;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: MovieTexture::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 MovieTexture::
-get_tex_scale() const {
-  CDReader cdata(_cycler);
-  if (cdata->_video_width == 0 ||
-      cdata->_video_height == 0 ||
-      _x_size == 0 ||
-      _y_size == 0) {
-    return LVecBase2f(1.0f, 1.0f);
-  }
-  return LVecBase2f((float)cdata->_video_width / _x_size,
-                    (float)cdata->_video_height / _y_size);
-}
-

+ 80 - 78
panda/src/grutil/movieTexture.cxx

@@ -51,7 +51,8 @@ MovieTexture::
 MovieTexture(MovieVideo *video) : 
   Texture(video->get_name())
 {
-  do_load_one(video->open(), NULL, 0, LoaderOptions());
+  Texture::CDWriter cdata_tex(Texture::_cycler, true);
+  do_load_one(cdata_tex, video->open(), NULL, 0, LoaderOptions());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -145,7 +146,7 @@ make_texture() {
 //               Assumes the lock is already held.
 ////////////////////////////////////////////////////////////////////
 void MovieTexture::
-do_recalculate_image_properties(CDWriter &cdata, const LoaderOptions &options) {
+do_recalculate_image_properties(CData *cdata, Texture::CData *cdata_tex, const LoaderOptions &options) {
   int x_max = 1;
   int y_max = 1;
   bool alpha = false;
@@ -172,16 +173,17 @@ do_recalculate_image_properties(CDWriter &cdata, const LoaderOptions &options) {
   cdata->_video_height = y_max;
   cdata->_video_length = len;
 
-  do_adjust_this_size(x_max, y_max, get_name(), true);
+  do_adjust_this_size(cdata_tex, x_max, y_max, get_name(), true);
   
-  do_reconsider_image_properties(x_max, y_max, alpha?4:3, 
+  do_reconsider_image_properties(cdata_tex, x_max, y_max, alpha?4:3, 
                                  T_unsigned_byte, cdata->_pages.size(),
                                  options);
-  _orig_file_x_size = cdata->_video_width;
-  _orig_file_y_size = cdata->_video_height;
+  cdata_tex->_orig_file_x_size = cdata->_video_width;
+  cdata_tex->_orig_file_y_size = cdata->_video_height;
 
-  do_set_pad_size(max(_x_size - _orig_file_x_size, 0), 
-                  max(_y_size - _orig_file_y_size, 0),
+  do_set_pad_size(cdata_tex, 
+                  max(cdata_tex->_x_size - cdata_tex->_orig_file_x_size, 0), 
+                  max(cdata_tex->_y_size - cdata_tex->_orig_file_y_size, 0),
                   0);
 }
 
@@ -193,9 +195,10 @@ do_recalculate_image_properties(CDWriter &cdata, const LoaderOptions &options) {
 //               pad outwards, never scale down.
 ////////////////////////////////////////////////////////////////////
 bool MovieTexture::
-do_adjust_this_size(int &x_size, int &y_size, const string &name,
-                    bool for_padding) {
-  if (_texture_type == TT_cube_map) {
+do_adjust_this_size(const Texture::CData *cdata_tex,
+                    int &x_size, int &y_size, const string &name,
+                    bool for_padding) const {
+  if (cdata_tex->_texture_type == TT_cube_map) {
     // Texture must be square.
     x_size = y_size = max(x_size, y_size);
   }
@@ -216,15 +219,16 @@ do_adjust_this_size(int &x_size, int &y_size, const string &name,
 //               video with similar properties.
 ////////////////////////////////////////////////////////////////////
 bool MovieTexture::
-do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
+do_read_one(Texture::CData *cdata_tex,
+            const Filename &fullpath, const Filename &alpha_fullpath,
             int z, int n, int primary_file_num_channels, int alpha_file_channel,
             const LoaderOptions &options,
             bool header_only, BamCacheRecord *record) {
   nassertr(n == 0, false);
-  if (!do_reconsider_z_size(z, options)) {
+  if (!do_reconsider_z_size(cdata_tex, z, options)) {
     return false;
   }
-  nassertr(z >= 0 && z < _z_size * _num_views, false);
+  nassertr(z >= 0 && z < cdata_tex->_z_size * cdata_tex->_num_views, false);
   
   if (record != (BamCacheRecord *)NULL) {
     record->add_dependent_file(fullpath);
@@ -249,23 +253,23 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
       set_name(fullpath.get_basename_wo_extension());
     }
     // Don't use has_filename() here, it will cause a deadlock
-    if (_filename.empty()) {
-      _filename = fullpath;
-      _alpha_filename = alpha_fullpath;
+    if (cdata_tex->_filename.empty()) {
+      cdata_tex->_filename = fullpath;
+      cdata_tex->_alpha_filename = alpha_fullpath;
     }
     
-    _fullpath = fullpath;
-    _alpha_fullpath = alpha_fullpath;
+    cdata_tex->_fullpath = fullpath;
+    cdata_tex->_alpha_fullpath = alpha_fullpath;
   }
 
-  _primary_file_num_channels = primary_file_num_channels;
-  _alpha_file_channel = alpha_file_channel;
+  cdata_tex->_primary_file_num_channels = primary_file_num_channels;
+  cdata_tex->_alpha_file_channel = alpha_file_channel;
   
-  if (!do_load_one(color, alpha, z, options)) {
+  if (!do_load_one(cdata_tex, color, alpha, z, options)) {
     return false;
   }
   
-  set_loaded_from_image();
+  cdata_tex->_loaded_from_image = true;
   set_loop(true);
   play();
   return true;
@@ -277,15 +281,14 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
 //  Description: Loads movie objects into the texture.
 ////////////////////////////////////////////////////////////////////
 bool MovieTexture::
-do_load_one(PT(MovieVideoCursor) color, PT(MovieVideoCursor) alpha, int z,
+do_load_one(Texture::CData *cdata_tex,
+            PT(MovieVideoCursor) color, PT(MovieVideoCursor) alpha, int z,
             const LoaderOptions &options) {
-  {
-    CDWriter cdata(_cycler);
-    cdata->_pages.resize(z + 1);
-    cdata->_pages[z]._color = color;
-    cdata->_pages[z]._alpha = alpha;
-    do_recalculate_image_properties(cdata, options);
-  }
+  CDWriter cdata(_cycler);
+  cdata->_pages.resize(z + 1);
+  cdata->_pages[z]._color = color;
+  cdata->_pages[z]._alpha = alpha;
+  do_recalculate_image_properties(cdata, cdata_tex, options);
   
   return true;
 }
@@ -297,7 +300,8 @@ do_load_one(PT(MovieVideoCursor) color, PT(MovieVideoCursor) alpha, int z,
 //               an error.
 ////////////////////////////////////////////////////////////////////
 bool MovieTexture::
-do_load_one(const PNMImage &pnmimage, const string &name, int z, int n,
+do_load_one(Texture::CData *cdata_tex,
+            const PNMImage &pnmimage, const string &name, int z, int n,
             const LoaderOptions &options) {
   grutil_cat.error() << "You cannot load a static image into a MovieTexture\n";
   return false;
@@ -313,7 +317,7 @@ do_load_one(const PNMImage &pnmimage, const string &name, int z, int n,
 //               Assumes the lock is already held.
 ////////////////////////////////////////////////////////////////////
 void MovieTexture::
-do_allocate_pages() {
+do_allocate_pages(Texture::CData *cdata_tex) {
   // We don't actually do anything here; the allocation is made in
   // do_load_one(), above.
 }
@@ -343,6 +347,7 @@ has_cull_callback() const {
 ////////////////////////////////////////////////////////////////////
 bool MovieTexture::
 cull_callback(CullTraverser *, const CullTraverserData &) const {
+  Texture::CDReader cdata_tex(Texture::_cycler);
   CDReader cdata(_cycler);
   
   double offset;
@@ -376,7 +381,7 @@ cull_callback(CullTraverser *, const CullTraverserData &) const {
       }
       if ((offset >= alpha->next_start())||
           ((offset < alpha->last_start()) && (alpha->can_seek()))) {
-        alpha->fetch_into_texture_alpha(offset, (MovieTexture*)this, i, _alpha_file_channel);
+        alpha->fetch_into_texture_alpha(offset, (MovieTexture*)this, i, cdata_tex->_alpha_file_channel);
       }
     } else if (color) {
       if ((offset >= color->next_start())||
@@ -389,7 +394,7 @@ cull_callback(CullTraverser *, const CullTraverserData &) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: MovieTexture::do_make_copy
+//     Function: MovieTexture::make_copy_impl
 //       Access: Protected, Virtual
 //  Description: Returns a new copy of the same Texture.  This copy,
 //               if applied to geometry, will be copied into texture
@@ -397,16 +402,20 @@ cull_callback(CullTraverser *, const CullTraverserData &) const {
 //               be duplicated in texture memory (and may be
 //               independently modified if desired).
 //               
-//               If the Texture is an MovieTexture, the resulting
+//               If the Texture is a MovieTexture, the resulting
 //               duplicate may be animated independently of the
 //               original.
 ////////////////////////////////////////////////////////////////////
 PT(Texture) MovieTexture::
-do_make_copy() {
-  PT(MovieTexture) tex = new MovieTexture(get_name());
-  tex->do_assign(*this);
+make_copy_impl() {
+  Texture::CDReader cdata_tex(Texture::_cycler);
+  CDReader cdata(_cycler);
+  PT(MovieTexture) copy = new MovieTexture(get_name());
+  Texture::CDWriter cdata_copy_tex(copy->Texture::_cycler, true);
+  CDWriter cdata_copy(copy->_cycler, true);
+  copy->do_assign(cdata_copy, cdata_copy_tex, this, cdata, cdata_tex);
 
-  return tex.p();
+  return copy.p();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -415,37 +424,29 @@ do_make_copy() {
 //  Description: Implements make_copy().
 ////////////////////////////////////////////////////////////////////
 void MovieTexture::
-do_assign(const MovieTexture &copy) {
-  Texture::do_assign(copy);
+do_assign(CData *cdata, Texture::CData *cdata_tex, const MovieTexture *copy, 
+          const CData *cdata_copy, const Texture::CData *cdata_copy_tex) {
+  Texture::do_assign(cdata_tex, copy, cdata_copy_tex);
 
-  // Since 'make_copy' can be a slow operation, 
-  // I release the read lock before calling make_copy.
-  
   pvector<MovieVideoCursor *> color;
   pvector<MovieVideoCursor *> alpha;
-  {
-    CDReader copy_cdata(copy._cycler);
-    color.resize(copy_cdata->_pages.size());
-    alpha.resize(copy_cdata->_pages.size());
-    for (int i=0; i<(int)(color.size()); i++) {
-      color[i] = copy_cdata->_pages[i]._color;
-      alpha[i] = copy_cdata->_pages[i]._alpha;
-    }
+  color.resize(cdata_copy->_pages.size());
+  alpha.resize(cdata_copy->_pages.size());
+  for (int i=0; i<(int)(color.size()); i++) {
+    color[i] = cdata_copy->_pages[i]._color;
+    alpha[i] = cdata_copy->_pages[i]._alpha;
   }
   
-  {
-    CDWriter cdata(_cycler);
-    cdata->_pages.resize(color.size());
-    for (int i=0; i<(int)(color.size()); i++) {
-      if (color[i]) {
-        cdata->_pages[i]._color = color[i]->get_source()->open();
-      }
-      if (alpha[i]) {
-        cdata->_pages[i]._alpha = alpha[i]->get_source()->open();
-      }
+  cdata->_pages.resize(color.size());
+  for (int i=0; i<(int)(color.size()); i++) {
+    if (color[i]) {
+      cdata->_pages[i]._color = color[i]->get_source()->open();
+    }
+    if (alpha[i]) {
+      cdata->_pages[i]._alpha = alpha[i]->get_source()->open();
     }
-    do_recalculate_image_properties(cdata, LoaderOptions());
   }
+  do_recalculate_image_properties(cdata, cdata_tex, LoaderOptions());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -456,7 +457,7 @@ do_assign(const MovieTexture &copy) {
 //               source MovieVideo.
 ////////////////////////////////////////////////////////////////////
 void MovieTexture::
-do_reload_ram_image() {
+do_reload_ram_image(Texture::CData *cdata, bool allow_compression) {
   // A MovieTexture should never dump its RAM image.
   // Therefore, this is not needed.
 }
@@ -484,7 +485,7 @@ get_keep_ram_image() const {
 //               it differently.
 ////////////////////////////////////////////////////////////////////
 bool MovieTexture::
-do_has_bam_rawdata() const {
+do_has_bam_rawdata(const Texture::CData *cdata) const {
   return true;
 }
 
@@ -495,7 +496,7 @@ do_has_bam_rawdata() const {
 //               to reload the rawdata image if possible.
 ////////////////////////////////////////////////////////////////////
 void MovieTexture::
-do_get_bam_rawdata() {
+do_get_bam_rawdata(Texture::CData *cdata) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -508,7 +509,7 @@ do_get_bam_rawdata() {
 //               wouldn't work anyway).
 ////////////////////////////////////////////////////////////////////
 bool MovieTexture::
-do_can_reload() {
+do_can_reload(const Texture::CData *cdata) const {
   return false;
 }
 
@@ -763,12 +764,12 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
 //               Datagram.
 ////////////////////////////////////////////////////////////////////
 void MovieTexture::
-do_write_datagram_rawdata(BamWriter *manager, Datagram &dg) {
+do_write_datagram_rawdata(Texture::CData *cdata_tex, BamWriter *manager, Datagram &dg) {
   CDReader cdata(_cycler);
 
-  dg.add_uint16(_z_size);
-  dg.add_uint16(_num_views);
-  nassertv(cdata->_pages.size() == (size_t)(_z_size * _num_views));
+  dg.add_uint16(cdata_tex->_z_size);
+  dg.add_uint16(cdata_tex->_num_views);
+  nassertv(cdata->_pages.size() == (size_t)(cdata_tex->_z_size * cdata_tex->_num_views));
   for (size_t n = 0; n < cdata->_pages.size(); ++n) {
     const VideoPage &page = cdata->_pages[n];
     manager->write_pointer(dg, page._color);
@@ -783,16 +784,16 @@ do_write_datagram_rawdata(BamWriter *manager, Datagram &dg) {
 //               with do_write_datagram_rawdata().
 ////////////////////////////////////////////////////////////////////
 void MovieTexture::
-do_fillin_rawdata(DatagramIterator &scan, BamReader *manager) {
+do_fillin_rawdata(Texture::CData *cdata_tex, DatagramIterator &scan, BamReader *manager) {
   CDWriter cdata(_cycler);
 
-  _z_size = scan.get_uint16();
-  _num_views = 1;
+  cdata_tex->_z_size = scan.get_uint16();
+  cdata_tex->_num_views = 1;
   if (manager->get_file_minor_ver() >= 26) {
-    _num_views = scan.get_uint16();
+    cdata_tex->_num_views = scan.get_uint16();
   }
 
-  size_t num_pages = (size_t)(_z_size * _num_views);
+  size_t num_pages = (size_t)(cdata_tex->_z_size * cdata_tex->_num_views);
   cdata->_pages.reserve(num_pages);
   for (size_t n = 0; n < num_pages; ++n) {
     cdata->_pages.push_back(VideoPage());
@@ -815,6 +816,7 @@ do_fillin_rawdata(DatagramIterator &scan, BamReader *manager) {
 ////////////////////////////////////////////////////////////////////
 void MovieTexture::
 finalize(BamReader *manager) {
+  Texture::CDWriter cdata_tex(Texture::_cycler);
   CDWriter cdata(_cycler);
 
   // Insist that each of our video pages gets finalized before we do.
@@ -825,7 +827,7 @@ finalize(BamReader *manager) {
     manager->finalize_now(page._alpha);
   }
 
-  do_recalculate_image_properties(cdata, LoaderOptions());
+  do_recalculate_image_properties(cdata, cdata_tex, LoaderOptions());
 
   set_loaded_from_image();
   set_loop(true);

+ 28 - 21
panda/src/grutil/movieTexture.h

@@ -43,7 +43,6 @@ PUBLISHED:
   INLINE double get_video_length() const;
   INLINE int get_video_width() const;
   INLINE int get_video_height() const;
-  INLINE LVecBase2f get_tex_scale() const;
   
   void   restart();
   void   stop();
@@ -66,27 +65,34 @@ public:
   virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
  
 protected:
-  virtual PT(Texture) do_make_copy();
-  void do_assign(const MovieTexture &copy);
+  class CData;
 
-  virtual void do_reload_ram_image();
+  virtual PT(Texture) make_copy_impl();
+  void do_assign(CData *cdata, Texture::CData *cdata_tex, const MovieTexture *copy, 
+                 const CData *cdata_copy, const Texture::CData *cdata_copy_tex);
+
+  virtual void do_reload_ram_image(Texture::CData *cdata, bool allow_compression);
   virtual bool get_keep_ram_image() const;
-  virtual bool do_has_bam_rawdata() const;
-  virtual void do_get_bam_rawdata();
-  virtual bool do_can_reload();
+  virtual bool do_has_bam_rawdata(const Texture::CData *cdata) const;
+  virtual void do_get_bam_rawdata(Texture::CData *cdata);
+  virtual bool do_can_reload(const Texture::CData *cdata) const;
 
-  virtual bool do_adjust_this_size(int &x_size, int &y_size, const string &name, 
-                                   bool for_padding);
+  virtual bool do_adjust_this_size(const Texture::CData *cdata, 
+                                   int &x_size, int &y_size, const string &name, 
+                                   bool for_padding) const;
 
-  virtual bool do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
+  virtual bool do_read_one(Texture::CData *cdata,
+                           const Filename &fullpath, const Filename &alpha_fullpath,
                            int z, int n, int primary_file_num_channels, int alpha_file_channel,
                            const LoaderOptions &options,
                            bool header_only, BamCacheRecord *record);
-  virtual bool do_load_one(const PNMImage &pnmimage, const string &name,
+  virtual bool do_load_one(Texture::CData *cdata,
+                           const PNMImage &pnmimage, const string &name,
                            int z, int n, const LoaderOptions &options);
-  bool do_load_one(PT(MovieVideoCursor) color, PT(MovieVideoCursor) alpha, 
+  bool do_load_one(Texture::CData *cdata,
+                   PT(MovieVideoCursor) color, PT(MovieVideoCursor) alpha, 
                    int z, const LoaderOptions &options);
-  virtual void do_allocate_pages();
+  virtual void do_allocate_pages(Texture::CData *cdata);
 
   class VideoPage {
   public:
@@ -110,11 +116,11 @@ protected:
     int _video_height;
     double _video_length;
 
-    double         _clock;
-    bool           _playing;
-    int            _loop_count;
-    int            _loops_total;
-    double         _play_rate;
+    double _clock;
+    bool _playing;
+    int _loop_count;
+    int _loops_total;
+    double _play_rate;
     PT(AudioSound) _synchronize;
   };
 
@@ -122,15 +128,16 @@ protected:
   typedef CycleDataReader<CData> CDReader;
   typedef CycleDataWriter<CData> CDWriter;
   
-  void do_recalculate_image_properties(CDWriter &cdata, const LoaderOptions &options);
+  void do_recalculate_image_properties(CData *cdata, Texture::CData *cdata_tex, 
+                                       const LoaderOptions &options);
 
 public:
   static void register_with_read_factory();
 
   static TypedWritable *make_from_bam(const FactoryParams &params);
   virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
-  virtual void do_write_datagram_rawdata(BamWriter *manager, Datagram &dg);
-  virtual void do_fillin_rawdata(DatagramIterator &scan, BamReader *manager);
+  virtual void do_write_datagram_rawdata(Texture::CData *cdata, BamWriter *manager, Datagram &me);
+  virtual void do_fillin_rawdata(Texture::CData *cdata, DatagramIterator &scan, BamReader *manager);
 
   virtual void finalize(BamReader *manager);
 

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

@@ -312,6 +312,10 @@ filter_to_max(int max_texture_stages) const {
 
   // Finally, record this newly-created attrib in the map for next
   // time.
+
+  // TODO: if new_attrib == this, have we just created a circular
+  // reference count?  Whoops!  Fix this!
+
   CPT(TextureAttrib) tex_attrib = (const TextureAttrib *)new_attrib.p();
   ((TextureAttrib *)this)->_filtered[max_texture_stages] = tex_attrib;
   return tex_attrib;

+ 23 - 0
panda/src/pipeline/cycleDataWriter.I

@@ -55,6 +55,29 @@ CycleDataWriter(PipelineCycler<CycleDataType> &cycler, bool force_to_0,
   nassertv(_pointer != (CycleDataType *)NULL);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CycleDataWriter::Constructor (full)
+//       Access: Public
+//  Description: This special constructor "steals" a reference count
+//               from the already-locked cdata object.  It does not
+//               increment the lock count of this object, but will
+//               release it when the destructor is called.
+//
+//               This is designed for special functions that return an
+//               already-locked cdata object and expect the caller to
+//               unlock it.
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE CycleDataWriter<CycleDataType>::
+CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataType *locked_cdata, 
+                Thread *current_thread) :
+  _cycler(&cycler),
+  _current_thread(current_thread)
+{
+  _pointer = locked_cdata;
+  nassertv(_pointer != (CycleDataType *)NULL);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CycleDataWriter::Copy Constructor (full)
 //       Access: Public

+ 3 - 0
panda/src/pipeline/cycleDataWriter.h

@@ -44,6 +44,9 @@ public:
                          Thread *current_thread = Thread::get_current_thread());
   INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, bool force_to_0,
                          Thread *current_thread = Thread::get_current_thread());
+  INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, 
+                         CycleDataType *locked_cdata,
+                         Thread *current_thread = Thread::get_current_thread());
   INLINE CycleDataWriter(const CycleDataWriter<CycleDataType> &copy);
   INLINE void operator = (const CycleDataWriter<CycleDataType> &copy);
 

+ 1 - 1
panda/src/text/dynamicTextPage.cxx

@@ -31,7 +31,7 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
 {
   // Since the texture might change frequently, don't try to compress
   // it by default.
-  _compression = CM_off;
+  set_compression(CM_off);
 
   // It's usually pretty important for text to look its best, and it
   // doesn't usually have a high fill factor.

+ 73 - 62
panda/src/vision/openCVTexture.cxx

@@ -70,15 +70,17 @@ consider_update() {
   if (this_frame != _last_frame_update) {
     int frame = get_frame();
     if (_current_frame != frame) {
-      update_frame(frame);
+      Texture::CDWriter cdata(Texture::_cycler, false);
+      do_update_frame(cdata, frame);
       _current_frame = frame;
     } else {
       // Loop through the pages to see if there's any camera stream to update.
-      int max_z = max(_z_size, (int)_pages.size());
+      Texture::CDWriter cdata(Texture::_cycler, false);
+      int max_z = max(cdata->_z_size, (int)_pages.size());
       for (int z = 0; z < max_z; ++z) {
         VideoPage &page = _pages[z];
         if (!page._color.is_from_file() || !page._alpha.is_from_file()) {
-          update_frame(frame, z);
+          do_update_frame(cdata, frame, z);
         }
       }
     }
@@ -87,7 +89,7 @@ consider_update() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: OpenCVTexture::do_make_copy
+//     Function: OpenCVTexture::make_copy_impl
 //       Access: Protected, Virtual
 //  Description: Returns a new copy of the same Texture.  This copy,
 //               if applied to geometry, will be copied into texture
@@ -100,11 +102,13 @@ consider_update() {
 //               original.
 ////////////////////////////////////////////////////////////////////
 PT(Texture) OpenCVTexture::
-do_make_copy() {
-  PT(OpenCVTexture) tex = new OpenCVTexture(get_name());
-  tex->do_assign(*this);
+make_copy_impl() {
+  Texture::CDReader cdata_tex(Texture::_cycler);
+  PT(OpenCVTexture) copy = new OpenCVTexture(get_name());
+  Texture::CDWriter cdata_copy_tex(copy->Texture::_cycler, true);
+  copy->do_assign(cdata_copy_tex, this, cdata_tex);
 
-  return tex.p();
+  return copy.p();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -113,9 +117,10 @@ do_make_copy() {
 //  Description: Implements make_copy().
 ////////////////////////////////////////////////////////////////////
 void OpenCVTexture::
-do_assign(const OpenCVTexture &copy) {
-  VideoTexture::do_assign(copy);
-  _pages = copy._pages;
+do_assign(Texture::CData *cdata_tex, const OpenCVTexture *copy, 
+          const Texture::CData *cdata_copy_tex) {
+  VideoTexture::do_assign(cdata_tex, copy, cdata_copy_tex);
+  _pages = copy->_pages;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -134,14 +139,15 @@ do_assign(const OpenCVTexture &copy) {
 bool OpenCVTexture::
 from_camera(int camera_index, int z, int alpha_file_channel,
             const LoaderOptions &options) {
-  if (!do_reconsider_z_size(z, options)) {
+  Texture::CDWriter cdata(Texture::_cycler, true);
+  if (!do_reconsider_z_size(cdata, z, options)) {
     return false;
   }
-  nassertr(z >= 0 && z < get_z_size(), false);
+  nassertr(z >= 0 && z < cdata->_z_size, false);
 
-  _alpha_file_channel = alpha_file_channel;
+  cdata->_alpha_file_channel = alpha_file_channel;
 
-  VideoPage &page = modify_page(z);
+  VideoPage &page = do_modify_page(cdata, z);
   if (alpha_file_channel == 0) {
     // A normal RGB texture.
     page._alpha.clear();
@@ -149,7 +155,7 @@ from_camera(int camera_index, int z, int alpha_file_channel,
       return false;
     }
 
-    if (!do_reconsider_video_properties(page._color, 3, z, options)) {
+    if (!do_reconsider_video_properties(cdata, page._color, 3, z, options)) {
       page._color.clear();
       return false;
     }
@@ -160,21 +166,21 @@ from_camera(int camera_index, int z, int alpha_file_channel,
       return false;
     }
 
-    if (!do_reconsider_video_properties(page._alpha, 1, z, options)) {
+    if (!do_reconsider_video_properties(cdata, page._alpha, 1, z, options)) {
       page._alpha.clear();
       return false;
     }
-    do_set_format(F_alpha);
+    do_set_format(cdata, F_alpha);
   }
 
-  set_loaded_from_image();
+  cdata->_loaded_from_image = true;
   clear_current_frame();
-  update_frame(0);
+  do_update_frame(cdata, 0);
   return true;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: OpenCVTexture::modify_page
+//     Function: OpenCVTexture::do_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
@@ -182,8 +188,8 @@ from_camera(int camera_index, int z, int alpha_file_channel,
 //               textures have more.
 ////////////////////////////////////////////////////////////////////
 OpenCVTexture::VideoPage &OpenCVTexture::
-modify_page(int z) {
-  nassertr(z < _z_size, _pages[0]);
+do_modify_page(const Texture::CData *cdata, int z) {
+  nassertr(z < cdata->_z_size, _pages[0]);
   while (z >= (int)_pages.size()) {
     _pages.push_back(VideoPage());
   }
@@ -198,7 +204,8 @@ modify_page(int z) {
 //               is valid, false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool OpenCVTexture::
-do_reconsider_video_properties(const OpenCVTexture::VideoStream &stream, 
+do_reconsider_video_properties(Texture::CData *cdata,
+                               const OpenCVTexture::VideoStream &stream, 
                                int num_components, int z, 
                                const LoaderOptions &options) {
   double frame_rate = 0.0f;
@@ -239,12 +246,12 @@ do_reconsider_video_properties(const OpenCVTexture::VideoStream &stream,
       << y_size << " texels.\n";
   }
 
-  if (!do_reconsider_image_properties(x_size, y_size, num_components,
+  if (!do_reconsider_image_properties(cdata, x_size, y_size, num_components,
                                       T_unsigned_byte, z, options)) {
     return false;
   }
 
-  if (_loaded_from_image && 
+  if (cdata->_loaded_from_image && 
       (get_video_width() != width || get_video_height() != height ||
        get_num_frames() != num_frames || get_frame_rate() != frame_rate)) {
     vision_cat.error()
@@ -276,27 +283,27 @@ make_texture() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: OpenCVTexture::update_frame
+//     Function: OpenCVTexture::do_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());
+do_update_frame(Texture::CData *cdata, int frame) {
+  int max_z = max(cdata->_z_size, (int)_pages.size());
   for (int z = 0; z < max_z; ++z) {
-    update_frame(frame, z);
+    do_update_frame(cdata, frame, z);
   }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: OpenCVTexture::update_frame
+//     Function: OpenCVTexture::do_update_frame
 //       Access: Protected, Virtual
 //  Description: This variant of update_frame updates the
 //               indicated page only.
 ////////////////////////////////////////////////////////////////////
 void OpenCVTexture::
-update_frame(int frame, int z) {
+do_update_frame(Texture::CData *cdata, int frame, int z) {
   if (vision_cat.is_spam()) {
     vision_cat.spam()
       << "Updating OpenCVTexture page " << z << "\n";
@@ -304,11 +311,11 @@ update_frame(int frame, int z) {
 
   VideoPage &page = _pages[z];
   if (page._color.is_valid() || page._alpha.is_valid()) {
-    do_modify_ram_image();
-    ++_image_modified;
+    do_modify_ram_image(cdata);
+    ++(cdata->_image_modified);
   }
-  ssize_t dest_x_pitch = _num_components * _component_width;
-  ssize_t dest_y_pitch = _x_size * dest_x_pitch;
+  ssize_t dest_x_pitch = cdata->_num_components * cdata->_component_width;
+  ssize_t dest_y_pitch = cdata->_x_size * dest_x_pitch;
 
   if (page._color.is_valid()) {
     nassertv(get_num_components() >= 3 && get_component_width() == 1);
@@ -316,10 +323,11 @@ update_frame(int frame, int z) {
     const unsigned char *r, *g, *b;
     ssize_t x_pitch, y_pitch;
     if (page._color.get_frame_data(frame, r, g, b, x_pitch, y_pitch)) {
-      nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
-      unsigned char *dest = _ram_images[0]._image.p() + do_get_expected_ram_page_size() * z;
+      nassertv(get_video_width() <= cdata->_x_size && get_video_height() <= cdata->_y_size);
+      nassertv(!cdata->_ram_images.empty())
+      unsigned char *dest = cdata->_ram_images[0]._image.p() + do_get_expected_ram_page_size(cdata) * z;
 
-      if (_num_components == 3 && x_pitch == 3) {
+      if (cdata->_num_components == 3 && x_pitch == 3) {
         // The easy case--copy the whole thing in, row by row.
         ssize_t copy_bytes = get_video_width() * dest_x_pitch;
         nassertv(copy_bytes <= dest_y_pitch && copy_bytes <= abs(y_pitch));
@@ -359,21 +367,22 @@ update_frame(int frame, int z) {
     ssize_t x_pitch, y_pitch;
     if (page._alpha.get_frame_data(frame, source[0], source[1], source[2],
                                    x_pitch, y_pitch)) {
-      nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
-      unsigned char *dest = _ram_images[0]._image.p() + do_get_expected_ram_page_size() * z;
+      nassertv(get_video_width() <= cdata->_x_size && get_video_height() <= cdata->_y_size);
+      nassertv(!cdata->_ram_images.empty())
+      unsigned char *dest = cdata->_ram_images[0]._image.p() + do_get_expected_ram_page_size(cdata) * z;
 
       // 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.
       const unsigned char *sch = source[0];
-      if (_alpha_file_channel >= 1 && _alpha_file_channel <= 3) {
-        sch = source[_alpha_file_channel - 1];
+      if (cdata->_alpha_file_channel >= 1 && cdata->_alpha_file_channel <= 3) {
+        sch = source[cdata->_alpha_file_channel - 1];
       }
       
       for (int y = 0; y < get_video_height(); ++y) {
         // Start dx at _num_components - 1, which writes to the last
         // channel, i.e. the alpha channel.
-        ssize_t dx = (_num_components - 1) * _component_width; 
+        ssize_t dx = (cdata->_num_components - 1) * cdata->_component_width; 
         ssize_t sx = 0;
         for (int x = 0; x < get_video_width(); ++x) {
           dest[dx] = sch[sx];
@@ -395,7 +404,8 @@ update_frame(int frame, int z) {
 //               video with similar properties.
 ////////////////////////////////////////////////////////////////////
 bool OpenCVTexture::
-do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
+do_read_one(Texture::CData *cdata,
+            const Filename &fullpath, const Filename &alpha_fullpath,
             int z, int n, int primary_file_num_channels, int alpha_file_channel,
             const LoaderOptions &options,
             bool header_only, BamCacheRecord *record) {
@@ -404,9 +414,9 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
   }
 
   nassertr(n == 0, false);
-  nassertr(z >= 0 && z < _z_size, false);
+  nassertr(z >= 0 && z < cdata->_z_size, false);
 
-  VideoPage &page = modify_page(z);
+  VideoPage &page = do_modify_page(cdata, z);
   if (!page._color.read(fullpath)) {
     vision_cat.error()
       << "OpenCV couldn't read " << fullpath << " as video.\n";
@@ -426,36 +436,36 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
       set_name(fullpath.get_basename_wo_extension());
     }
     // Don't use has_filename() here, it will cause a deadlock
-    if (_filename.empty()) {
-      _filename = fullpath;
-      _alpha_filename = alpha_fullpath;
+    if (cdata->_filename.empty()) {
+      cdata->_filename = fullpath;
+      cdata->_alpha_filename = alpha_fullpath;
     }
 
-    _fullpath = fullpath;
-    _alpha_fullpath = alpha_fullpath;
+    cdata->_fullpath = fullpath;
+    cdata->_alpha_fullpath = alpha_fullpath;
   }
 
-  _primary_file_num_channels = 3;
-  _alpha_file_channel = 0;
+  cdata->_primary_file_num_channels = 3;
+  cdata->_alpha_file_channel = 0;
 
   if (alpha_fullpath.empty()) {
     // Only one RGB movie.
-    if (!do_reconsider_video_properties(page._color, 3, z, options)) {
+    if (!do_reconsider_video_properties(cdata, page._color, 3, z, options)) {
       page._color.clear();
       return false;
     }
 
   } else {
     // An RGB movie combined with an alpha movie.
-    _alpha_file_channel = alpha_file_channel;
+    cdata->_alpha_file_channel = alpha_file_channel;
 
-    if (!do_reconsider_video_properties(page._color, 4, z, options)) {
+    if (!do_reconsider_video_properties(cdata, page._color, 4, z, options)) {
       page._color.clear();
       page._alpha.clear();
       return false;
     }
     
-    if (!do_reconsider_video_properties(page._alpha, 4, z, options)) {
+    if (!do_reconsider_video_properties(cdata, page._alpha, 4, z, options)) {
       page._color.clear();
       page._alpha.clear();
       return false;
@@ -464,7 +474,7 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
 
   set_loaded_from_image();
   clear_current_frame();
-  update_frame(0);
+  do_update_frame(cdata, 0);
   return true;
 }
 
@@ -475,15 +485,16 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
 //               texture) to the indicated static image.
 ////////////////////////////////////////////////////////////////////
 bool OpenCVTexture::
-do_load_one(const PNMImage &pnmimage, const string &name,
+do_load_one(Texture::CData *cdata,
+            const PNMImage &pnmimage, const string &name,
             int z, int n, const LoaderOptions &options) {
   if (z <= (int)_pages.size()) {
-    VideoPage &page = modify_page(z);
+    VideoPage &page = do_modify_page(cdata, z);
     page._color.clear();
     page._alpha.clear();
   }
 
-  return Texture::do_load_one(pnmimage, name, z, n, options);
+  return Texture::do_load_one(cdata, pnmimage, name, z, n, options);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 12 - 8
panda/src/vision/openCVTexture.h

@@ -48,25 +48,29 @@ public:
 
 protected:
   virtual void consider_update();
-  virtual PT(Texture) do_make_copy();
-  void do_assign(const OpenCVTexture &copy);
+  virtual PT(Texture) make_copy_impl();
+  void do_assign(Texture::CData *cdata_tex, const OpenCVTexture *copy, 
+                 const Texture::CData *cdata_copy_tex);
 
-  virtual void update_frame(int frame);
-  virtual void update_frame(int frame, int z);
+  virtual void do_update_frame(Texture::CData *cdata_tex, int frame);
+  virtual void do_update_frame(Texture::CData *cdata_tex, int frame, int z);
 
-  virtual bool do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
+  virtual bool do_read_one(Texture::CData *cdata,
+                           const Filename &fullpath, const Filename &alpha_fullpath,
                            int z, int n, int primary_file_num_channels, int alpha_file_channel,
                            const LoaderOptions &options,
                            bool header_only, BamCacheRecord *record);
-  virtual bool do_load_one(const PNMImage &pnmimage, const string &name,
+  virtual bool do_load_one(Texture::CData *cdata,
+                           const PNMImage &pnmimage, const string &name,
                            int z, int n, const LoaderOptions &options);
 
 private:    
   class VideoPage;
   class VideoStream;
 
-  VideoPage &modify_page(int z);
-  bool do_reconsider_video_properties(const VideoStream &stream, 
+  VideoPage &do_modify_page(const Texture::CData *cdata, int z);
+  bool do_reconsider_video_properties(Texture::CData *cdata, 
+                                      const VideoStream &stream, 
                                       int num_components, int z, 
                                       const LoaderOptions &options);
   void do_update();

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov