Panda3D

movieTexture.cxx

00001 // Filename: movieTexture.cxx
00002 // Created by: jyelon (01Aug2007)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "pandabase.h"
00016 
00017 #ifdef HAVE_AUDIO
00018 
00019 #include "movieVideo.h"
00020 #include "movieVideoCursor.h"
00021 #include "movieTexture.h"
00022 #include "clockObject.h"
00023 #include "config_gobj.h"
00024 #include "config_grutil.h"
00025 #include "bamCacheRecord.h"
00026 #include "bamReader.h"
00027 #include "bamWriter.h"
00028 #include "math.h"
00029 #include "audioSound.h"
00030 
00031 TypeHandle MovieTexture::_type_handle;
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: MovieTexture::Constructor
00035 //       Access: Published
00036 //  Description: Creates a blank movie texture.  Movies must be 
00037 //               added using do_read_one or do_load_one.
00038 ////////////////////////////////////////////////////////////////////
00039 MovieTexture::
00040 MovieTexture(const string &name) : 
00041   Texture(name)
00042 {
00043 }
00044 
00045 ////////////////////////////////////////////////////////////////////
00046 //     Function: MovieTexture::Constructor
00047 //       Access: Published
00048 //  Description: Creates a texture playing the specified movie.
00049 ////////////////////////////////////////////////////////////////////
00050 MovieTexture::
00051 MovieTexture(MovieVideo *video) : 
00052   Texture(video->get_name())
00053 {
00054   Texture::CDWriter cdata_tex(Texture::_cycler, true);
00055   do_load_one(cdata_tex, video->open(), NULL, 0, LoaderOptions());
00056 }
00057 
00058 ////////////////////////////////////////////////////////////////////
00059 //     Function: MovieTexture::CData::Constructor
00060 //       Access: public
00061 //  Description: xxx
00062 ////////////////////////////////////////////////////////////////////
00063 MovieTexture::CData::
00064 CData() :
00065   _video_width(1),
00066   _video_height(1),
00067   _video_length(1.0),
00068   _clock(0.0),
00069   _playing(false),
00070   _loop_count(1),
00071   _play_rate(1.0),
00072   _has_offset(false)
00073 {
00074 }
00075 
00076 ////////////////////////////////////////////////////////////////////
00077 //     Function: MovieTexture::CData::Copy Constructor
00078 //       Access: public
00079 //  Description: xxx
00080 ////////////////////////////////////////////////////////////////////
00081 MovieTexture::CData::
00082 CData(const CData &copy) :
00083   _pages(copy._pages),
00084   _video_width(copy._video_width),
00085   _video_height(copy._video_height),
00086   _video_length(copy._video_length),
00087   _clock(0.0),
00088   _playing(false),
00089   _loop_count(1),
00090   _play_rate(1.0),
00091   _has_offset(false)
00092 {
00093 }
00094 
00095 ////////////////////////////////////////////////////////////////////
00096 //     Function: MovieTexture::CData::make_copy
00097 //       Access: public
00098 //  Description: xxx
00099 ////////////////////////////////////////////////////////////////////
00100 CycleData *MovieTexture::CData::
00101 make_copy() const {
00102   return new CData(*this);
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: MovieTexture::Copy Constructor
00107 //       Access: Protected
00108 //  Description: Use MovieTexture::make_copy() to make a duplicate copy of
00109 //               an existing MovieTexture.
00110 ////////////////////////////////////////////////////////////////////
00111 MovieTexture::
00112 MovieTexture(const MovieTexture &copy) : 
00113   Texture(copy)
00114 {
00115   nassertv(false);
00116 }
00117 
00118 ////////////////////////////////////////////////////////////////////
00119 //     Function: MovieTexture::Destructor
00120 //       Access: Published, Virtual
00121 //  Description: xxx
00122 ////////////////////////////////////////////////////////////////////
00123 MovieTexture::
00124 ~MovieTexture() {
00125   clear();
00126 }
00127 
00128 ////////////////////////////////////////////////////////////////////
00129 //     Function: MovieTexture::make_texture
00130 //       Access: Public, Static
00131 //  Description: A factory function to make a new MovieTexture, used
00132 //               to pass to the TexturePool.
00133 ////////////////////////////////////////////////////////////////////
00134 PT(Texture) MovieTexture::
00135 make_texture() {
00136   return new MovieTexture("");
00137 }
00138 
00139 ////////////////////////////////////////////////////////////////////
00140 //     Function: MovieTexture::do_recalculate_image_properties
00141 //       Access: Protected
00142 //  Description: Resizes the texture, and adjusts the format,
00143 //               based on the source movies.  The resulting texture
00144 //               will be large enough to hold all the videos.
00145 //
00146 //               Assumes the lock is already held.
00147 ////////////////////////////////////////////////////////////////////
00148 void MovieTexture::
00149 do_recalculate_image_properties(CData *cdata, Texture::CData *cdata_tex, const LoaderOptions &options) {
00150   int x_max = 1;
00151   int y_max = 1;
00152   bool alpha = false;
00153   double len = 0.0;
00154 
00155   for (size_t i = 0; i < cdata->_pages.size(); ++i) {
00156     MovieVideoCursor *t = cdata->_pages[i]._color;
00157     if (t) {
00158       if (t->size_x() > x_max) x_max = t->size_x();
00159       if (t->size_y() > y_max) y_max = t->size_y();
00160       if (t->length() > len) len = t->length();
00161       if (t->get_num_components() == 4) alpha=true;
00162     }
00163     t = cdata->_pages[i]._alpha;
00164     if (t) {
00165       if (t->size_x() > x_max) x_max = t->size_x();
00166       if (t->size_y() > y_max) y_max = t->size_y();
00167       if (t->length() > len) len = t->length();
00168       alpha = true;
00169     }
00170   }
00171 
00172   cdata->_video_width  = x_max;
00173   cdata->_video_height = y_max;
00174   cdata->_video_length = len;
00175 
00176   do_adjust_this_size(cdata_tex, x_max, y_max, get_name(), true);
00177   
00178   do_reconsider_image_properties(cdata_tex, x_max, y_max, alpha?4:3, 
00179                                  T_unsigned_byte, cdata->_pages.size(),
00180                                  options);
00181   cdata_tex->_orig_file_x_size = cdata->_video_width;
00182   cdata_tex->_orig_file_y_size = cdata->_video_height;
00183 
00184   do_set_pad_size(cdata_tex, 
00185                   max(cdata_tex->_x_size - cdata_tex->_orig_file_x_size, 0), 
00186                   max(cdata_tex->_y_size - cdata_tex->_orig_file_y_size, 0),
00187                   0);
00188 }
00189 
00190 ////////////////////////////////////////////////////////////////////
00191 //     Function: MovieTexture::do_adjust_this_size
00192 //       Access: Protected, Virtual
00193 //  Description: Works like adjust_size, but also considers the
00194 //               texture class.  Movie textures, for instance, always
00195 //               pad outwards, never scale down.
00196 ////////////////////////////////////////////////////////////////////
00197 bool MovieTexture::
00198 do_adjust_this_size(const Texture::CData *cdata_tex,
00199                     int &x_size, int &y_size, const string &name,
00200                     bool for_padding) const {
00201   AutoTextureScale ats = do_get_auto_texture_scale(cdata_tex);
00202   if (ats != ATS_none) {
00203     ats = ATS_pad;
00204   }
00205 
00206   return adjust_size(x_size, y_size, name, for_padding, ats);
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: MovieTexture::do_read_one
00211 //       Access: Protected, Virtual
00212 //  Description: Combines a color and alpha video image from the two
00213 //               indicated filenames.  Both must be the same kind of
00214 //               video with similar properties.
00215 ////////////////////////////////////////////////////////////////////
00216 bool MovieTexture::
00217 do_read_one(Texture::CData *cdata_tex,
00218             const Filename &fullpath, const Filename &alpha_fullpath,
00219             int z, int n, int primary_file_num_channels, int alpha_file_channel,
00220             const LoaderOptions &options,
00221             bool header_only, BamCacheRecord *record) {
00222   nassertr(n == 0, false);
00223   if (!do_reconsider_z_size(cdata_tex, z, options)) {
00224     return false;
00225   }
00226   nassertr(z >= 0 && z < cdata_tex->_z_size * cdata_tex->_num_views, false);
00227   
00228   if (record != (BamCacheRecord *)NULL) {
00229     record->add_dependent_file(fullpath);
00230   }
00231 
00232   PT(MovieVideoCursor) color;
00233   PT(MovieVideoCursor) alpha;
00234   
00235   color = MovieVideo::get(fullpath)->open();
00236   if (color == 0) {
00237     return false;
00238   }
00239   if (!alpha_fullpath.empty()) {
00240     alpha = MovieVideo::get(alpha_fullpath)->open();
00241     if (alpha == 0) {
00242       return false;
00243     }
00244   }
00245   
00246   if (z == 0) {
00247     if (!has_name()) {
00248       set_name(fullpath.get_basename_wo_extension());
00249     }
00250     // Don't use has_filename() here, it will cause a deadlock
00251     if (cdata_tex->_filename.empty()) {
00252       cdata_tex->_filename = fullpath;
00253       cdata_tex->_alpha_filename = alpha_fullpath;
00254     }
00255     
00256     cdata_tex->_fullpath = fullpath;
00257     cdata_tex->_alpha_fullpath = alpha_fullpath;
00258   }
00259 
00260   cdata_tex->_primary_file_num_channels = primary_file_num_channels;
00261   cdata_tex->_alpha_file_channel = alpha_file_channel;
00262   
00263   if (!do_load_one(cdata_tex, color, alpha, z, options)) {
00264     return false;
00265   }
00266   
00267   cdata_tex->_loaded_from_image = true;
00268   set_loop(true);
00269   play();
00270   return true;
00271 }
00272 
00273 ////////////////////////////////////////////////////////////////////
00274 //     Function: MovieTexture::do_load_one
00275 //       Access: Protected, Virtual
00276 //  Description: Loads movie objects into the texture.
00277 ////////////////////////////////////////////////////////////////////
00278 bool MovieTexture::
00279 do_load_one(Texture::CData *cdata_tex,
00280             PT(MovieVideoCursor) color, PT(MovieVideoCursor) alpha, int z,
00281             const LoaderOptions &options) {
00282   CDWriter cdata(_cycler);
00283   cdata->_pages.resize(z + 1);
00284   cdata->_pages[z]._color = color;
00285   cdata->_pages[z]._alpha = alpha;
00286   do_recalculate_image_properties(cdata, cdata_tex, options);
00287 
00288   // Make sure the image data is initially black, which is nice for
00289   // padded textures.
00290   PTA_uchar image = make_ram_image();
00291   memset(image.p(), 0, image.size());
00292   
00293   return true;
00294 }
00295 
00296 ////////////////////////////////////////////////////////////////////
00297 //     Function: MovieTexture::do_load_one
00298 //       Access: Protected, Virtual
00299 //  Description: Loading a static image into a MovieTexture is
00300 //               an error.
00301 ////////////////////////////////////////////////////////////////////
00302 bool MovieTexture::
00303 do_load_one(Texture::CData *cdata_tex,
00304             const PNMImage &pnmimage, const string &name, int z, int n,
00305             const LoaderOptions &options) {
00306   grutil_cat.error() << "You cannot load a static image into a MovieTexture\n";
00307   return false;
00308 }
00309 
00310 ////////////////////////////////////////////////////////////////////
00311 //     Function: MovieTexture::do_allocate_pages
00312 //       Access: Protected, Virtual
00313 //  Description: Called internally by do_reconsider_z_size() to
00314 //               allocate new memory in _ram_images[0] for the new
00315 //               number of pages.
00316 //
00317 //               Assumes the lock is already held.
00318 ////////////////////////////////////////////////////////////////////
00319 void MovieTexture::
00320 do_allocate_pages(Texture::CData *cdata_tex) {
00321   // We don't actually do anything here; the allocation is made in
00322   // do_load_one(), above.
00323 }
00324 
00325 ////////////////////////////////////////////////////////////////////
00326 //     Function: MovieTexture::has_cull_callback
00327 //       Access: Public, Virtual
00328 //  Description: Should be overridden by derived classes to return
00329 //               true if cull_callback() has been defined.  Otherwise,
00330 //               returns false to indicate cull_callback() does not
00331 //               need to be called for this node during the cull
00332 //               traversal.
00333 ////////////////////////////////////////////////////////////////////
00334 bool MovieTexture::
00335 has_cull_callback() const {
00336   return true;
00337 }
00338 
00339 ////////////////////////////////////////////////////////////////////
00340 //     Function: MovieTexture::cull_callback
00341 //       Access: Public, Virtual
00342 //  Description: This function will be called during the cull 
00343 //               traversal to update the MovieTexture.  This update
00344 //               consists of fetching the next video frame from the
00345 //               underlying MovieVideo sources.  The MovieVideo
00346 //               object belongs to the cull thread.
00347 ////////////////////////////////////////////////////////////////////
00348 bool MovieTexture::
00349 cull_callback(CullTraverser *, const CullTraverserData &) const {
00350   Texture::CDReader cdata_tex(Texture::_cycler);
00351   CDReader cdata(_cycler);
00352 
00353   if (!cdata->_has_offset) {
00354     // If we don't have a previously-computed timestamp (offset)
00355     // cached, then compute a new one.
00356     double offset;
00357     int true_loop_count = 1;
00358     if (cdata->_synchronize != 0) {
00359       offset = cdata->_synchronize->get_time();
00360     } else {
00361       // Calculate the cursor position modulo the length of the movie.
00362       double now = ClockObject::get_global_clock()->get_frame_time();
00363       offset = cdata->_clock;
00364       if (cdata->_playing) {
00365         offset += now * cdata->_play_rate;
00366       }
00367       true_loop_count = cdata->_loop_count;
00368     }
00369     ((CData *)cdata.p())->_offset = offset;
00370     ((CData *)cdata.p())->_true_loop_count = true_loop_count;
00371     ((CData *)cdata.p())->_has_offset = true;
00372   }
00373 
00374   bool in_sync = do_update_frames(cdata);
00375   if (!in_sync) {
00376     // If it didn't successfully sync, try again--once.  The second
00377     // time it might be able to fill in some more recent frames.
00378     in_sync = do_update_frames(cdata);
00379   }
00380 
00381   if (in_sync) {
00382     // Now go back through and apply all the frames to the texture.
00383     Pages::const_iterator pi;
00384     for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
00385       const VideoPage &page = (*pi);
00386       MovieVideoCursor *color = page._color;
00387       MovieVideoCursor *alpha = page._alpha;
00388       size_t i = pi - cdata->_pages.begin();
00389       
00390       if (color != NULL && alpha != NULL) {
00391         color->apply_to_texture_rgb(page._cbuffer, (MovieTexture*)this, i);
00392         alpha->apply_to_texture_alpha(page._abuffer, (MovieTexture*)this, i, cdata_tex->_alpha_file_channel);
00393         
00394       } else if (color != NULL) {
00395         color->apply_to_texture(page._cbuffer, (MovieTexture*)this, i);
00396       }
00397       
00398       ((VideoPage &)page)._cbuffer.clear();
00399       ((VideoPage &)page)._abuffer.clear();
00400     }
00401 
00402     // Clear the cached offset so we can update the frame next time.
00403     ((CData *)cdata.p())->_has_offset = false;
00404   }
00405     
00406   return true;
00407 }
00408 
00409 ////////////////////////////////////////////////////////////////////
00410 //     Function: MovieTexture::make_copy_impl
00411 //       Access: Protected, Virtual
00412 //  Description: Returns a new copy of the same Texture.  This copy,
00413 //               if applied to geometry, will be copied into texture
00414 //               as a separate texture from the original, so it will
00415 //               be duplicated in texture memory (and may be
00416 //               independently modified if desired).
00417 //               
00418 //               If the Texture is a MovieTexture, the resulting
00419 //               duplicate may be animated independently of the
00420 //               original.
00421 ////////////////////////////////////////////////////////////////////
00422 PT(Texture) MovieTexture::
00423 make_copy_impl() {
00424   Texture::CDReader cdata_tex(Texture::_cycler);
00425   CDReader cdata(_cycler);
00426   PT(MovieTexture) copy = new MovieTexture(get_name());
00427   Texture::CDWriter cdata_copy_tex(copy->Texture::_cycler, true);
00428   CDWriter cdata_copy(copy->_cycler, true);
00429   copy->do_assign(cdata_copy, cdata_copy_tex, this, cdata, cdata_tex);
00430 
00431   return copy.p();
00432 }
00433 
00434 ////////////////////////////////////////////////////////////////////
00435 //     Function: MovieTexture::do_assign
00436 //       Access: Protected
00437 //  Description: Implements make_copy().
00438 ////////////////////////////////////////////////////////////////////
00439 void MovieTexture::
00440 do_assign(CData *cdata, Texture::CData *cdata_tex, const MovieTexture *copy, 
00441           const CData *cdata_copy, const Texture::CData *cdata_copy_tex) {
00442   Texture::do_assign(cdata_tex, copy, cdata_copy_tex);
00443 
00444   pvector<MovieVideoCursor *> color;
00445   pvector<MovieVideoCursor *> alpha;
00446   color.resize(cdata_copy->_pages.size());
00447   alpha.resize(cdata_copy->_pages.size());
00448   for (int i=0; i<(int)(color.size()); i++) {
00449     color[i] = cdata_copy->_pages[i]._color;
00450     alpha[i] = cdata_copy->_pages[i]._alpha;
00451   }
00452   
00453   cdata->_pages.resize(color.size());
00454   for (int i=0; i<(int)(color.size()); i++) {
00455     if (color[i]) {
00456       cdata->_pages[i]._color = color[i]->get_source()->open();
00457     }
00458     if (alpha[i]) {
00459       cdata->_pages[i]._alpha = alpha[i]->get_source()->open();
00460     }
00461   }
00462   do_recalculate_image_properties(cdata, cdata_tex, LoaderOptions());
00463 }
00464 
00465 ////////////////////////////////////////////////////////////////////
00466 //     Function: MovieTexture::reload_ram_image
00467 //       Access: Protected, Virtual
00468 //  Description: A MovieTexture must always keep its ram image, 
00469 //               since there is no way to reload it from the 
00470 //               source MovieVideo.
00471 ////////////////////////////////////////////////////////////////////
00472 void MovieTexture::
00473 do_reload_ram_image(Texture::CData *cdata, bool allow_compression) {
00474   // A MovieTexture should never dump its RAM image.
00475   // Therefore, this is not needed.
00476 }
00477 
00478 ////////////////////////////////////////////////////////////////////
00479 //     Function: MovieTexture::get_keep_ram_image
00480 //       Access: Published, Virtual
00481 //  Description: A MovieTexture must always keep its ram image, 
00482 //               since there is no way to reload it from the 
00483 //               source MovieVideo.
00484 ////////////////////////////////////////////////////////////////////
00485 bool MovieTexture::
00486 get_keep_ram_image() const {
00487   // A MovieTexture should never dump its RAM image.
00488   return true;
00489 }
00490 
00491 ////////////////////////////////////////////////////////////////////
00492 //     Function: MovieTexture::do_has_bam_rawdata
00493 //       Access: Protected, Virtual
00494 //  Description: Returns true if there is a rawdata image that we have
00495 //               available to write to the bam stream.  For a normal
00496 //               Texture, this is the same thing as
00497 //               do_has_ram_image(), but a movie texture might define
00498 //               it differently.
00499 ////////////////////////////////////////////////////////////////////
00500 bool MovieTexture::
00501 do_has_bam_rawdata(const Texture::CData *cdata) const {
00502   return true;
00503 }
00504 
00505 ////////////////////////////////////////////////////////////////////
00506 //     Function: MovieTexture::do_get_bam_rawdata
00507 //       Access: Protected, Virtual
00508 //  Description: If do_has_bam_rawdata() returned false, this attempts
00509 //               to reload the rawdata image if possible.
00510 ////////////////////////////////////////////////////////////////////
00511 void MovieTexture::
00512 do_get_bam_rawdata(Texture::CData *cdata) {
00513 }
00514 
00515 ////////////////////////////////////////////////////////////////////
00516 //     Function: MovieTexture::do_can_reload
00517 //       Access: Protected, Virtual
00518 //  Description: Returns true if we can safely call
00519 //               do_unlock_and_reload_ram_image() in order to make the
00520 //               image available, or false if we shouldn't do this
00521 //               (because we know from a priori knowledge that it
00522 //               wouldn't work anyway).
00523 ////////////////////////////////////////////////////////////////////
00524 bool MovieTexture::
00525 do_can_reload(const Texture::CData *cdata) const {
00526   return false;
00527 }
00528 
00529 ////////////////////////////////////////////////////////////////////
00530 //     Function: MovieTexture::restart
00531 //       Access: Published
00532 //  Description: Start playing the movie from where it was last
00533 //               paused.  Has no effect if the movie is not paused,
00534 //               or if the movie's cursor is already at the end.
00535 ////////////////////////////////////////////////////////////////////
00536 void MovieTexture::
00537 restart() {
00538   CDWriter cdata(_cycler);
00539   if (!cdata->_playing) {
00540     double now = ClockObject::get_global_clock()->get_frame_time();
00541     cdata->_clock = cdata->_clock - (now * cdata->_play_rate);
00542     cdata->_playing = true;
00543   }
00544 }
00545 
00546 ////////////////////////////////////////////////////////////////////
00547 //     Function: MovieTexture::stop
00548 //       Access: Published
00549 //  Description: Stops a currently playing or looping movie right
00550 //               where it is.  The movie's cursor remains frozen at
00551 //               the point where it was stopped.
00552 ////////////////////////////////////////////////////////////////////
00553 void MovieTexture::
00554 stop() {
00555   CDWriter cdata(_cycler);
00556   if (cdata->_playing) {
00557     double now = ClockObject::get_global_clock()->get_frame_time();
00558     cdata->_clock = cdata->_clock + (now * cdata->_play_rate);
00559     cdata->_playing = false;
00560   }
00561 }
00562 
00563 ////////////////////////////////////////////////////////////////////
00564 //     Function: MovieTexture::play
00565 //       Access: Published
00566 //  Description: Plays the movie from the beginning.
00567 ////////////////////////////////////////////////////////////////////
00568 void MovieTexture::
00569 play() {
00570   CDWriter cdata(_cycler);
00571   double now = ClockObject::get_global_clock()->get_frame_time();
00572   cdata->_clock = 0.0 - (now * cdata->_play_rate);
00573   cdata->_playing = true;
00574 }
00575 
00576 ////////////////////////////////////////////////////////////////////
00577 //     Function: MovieTexture::set_time
00578 //       Access: Published
00579 //  Description: Sets the movie's cursor.
00580 ////////////////////////////////////////////////////////////////////
00581 void MovieTexture::
00582 set_time(double t) {
00583   CDWriter cdata(_cycler);
00584   t = min(cdata->_video_length, max(0.0, t));
00585   if (cdata->_playing) {
00586     double now = ClockObject::get_global_clock()->get_frame_time();
00587     cdata->_clock = t - (now * cdata->_play_rate);
00588   } else {
00589     cdata->_clock = t;
00590   }
00591 }
00592 
00593 ////////////////////////////////////////////////////////////////////
00594 //     Function: MovieTexture::get_time
00595 //       Access: Published
00596 //  Description: Returns the current value of the movie's cursor.
00597 //               If the movie's loop count is greater than one, then
00598 //               its length is effectively multiplied for the
00599 //               purposes of this function.  In other words, 
00600 //               the return value will be in the range 0.0 
00601 //               to (length * loopcount).
00602 ////////////////////////////////////////////////////////////////////
00603 double MovieTexture::
00604 get_time() const {
00605   CDReader cdata(_cycler);
00606   double clock = cdata->_clock;
00607   if (cdata->_playing) {
00608     double now = ClockObject::get_global_clock()->get_frame_time();
00609     clock += (now * cdata->_play_rate);
00610   }
00611   return clock;
00612 }
00613 
00614 ////////////////////////////////////////////////////////////////////
00615 //     Function: MovieTexture::set_loop
00616 //       Access: Published
00617 //  Description: If true, sets the movie's loop count to 1 billion.
00618 //               If false, sets the movie's loop count to one.
00619 ////////////////////////////////////////////////////////////////////
00620 void MovieTexture::
00621 set_loop(bool loop) {
00622   set_loop_count(loop ? 0:1);
00623 }
00624 
00625 ////////////////////////////////////////////////////////////////////
00626 //     Function: MovieTexture::get_loop
00627 //       Access: Published
00628 //  Description: Returns true if the movie's loop count is not equal
00629 //               to one.
00630 ////////////////////////////////////////////////////////////////////
00631 bool MovieTexture::
00632 get_loop() const {
00633   CDReader cdata(_cycler);
00634   return (cdata->_loop_count == 0);
00635 }
00636 
00637 ////////////////////////////////////////////////////////////////////
00638 //     Function: MovieTexture::set_loop_count
00639 //       Access: Published
00640 //  Description: Sets the movie's loop count to the desired value.
00641 ////////////////////////////////////////////////////////////////////
00642 void MovieTexture::
00643 set_loop_count(int n) {
00644   CDWriter cdata(_cycler);
00645   cdata->_loop_count = n;
00646 }
00647 
00648 ////////////////////////////////////////////////////////////////////
00649 //     Function: MovieTexture::get_loop_count
00650 //       Access: Published
00651 //  Description: Returns the movie's loop count.
00652 ////////////////////////////////////////////////////////////////////
00653 int MovieTexture::
00654 get_loop_count() const {
00655   CDReader cdata(_cycler);
00656   return cdata->_loop_count;
00657 }
00658 
00659 ////////////////////////////////////////////////////////////////////
00660 //     Function: MovieTexture::set_play_rate
00661 //       Access: Published
00662 //  Description: Sets the movie's play-rate.  This is the speed at
00663 //               which the movie's cursor advances.  The default is
00664 //               to advance 1.0 movie-seconds per real-time second.
00665 ////////////////////////////////////////////////////////////////////
00666 void MovieTexture::
00667 set_play_rate(double rate) {
00668   CDWriter cdata(_cycler);
00669   if (cdata->_playing) {
00670     double now = ClockObject::get_global_clock()->get_frame_time();
00671     cdata->_clock += (now * cdata->_play_rate);
00672     cdata->_play_rate = rate;
00673     cdata->_clock -= (now * cdata->_play_rate);
00674   } else {
00675     cdata->_play_rate = rate;
00676   }    
00677 }
00678 
00679 ////////////////////////////////////////////////////////////////////
00680 //     Function: MovieTexture::get_play_rate
00681 //       Access: Published
00682 //  Description: Gets the movie's play-rate.
00683 ////////////////////////////////////////////////////////////////////
00684 double MovieTexture::
00685 get_play_rate() const {
00686   CDReader cdata(_cycler);
00687   return cdata->_play_rate;
00688 }
00689 
00690 ////////////////////////////////////////////////////////////////////
00691 //     Function: MovieTexture::is_playing
00692 //       Access: Published
00693 //  Description: Returns true if the movie's cursor is advancing.
00694 ////////////////////////////////////////////////////////////////////
00695 bool MovieTexture::
00696 is_playing() const {
00697   CDReader cdata(_cycler);
00698   return cdata->_playing;
00699 }
00700 
00701 ////////////////////////////////////////////////////////////////////
00702 //     Function: MovieTexture::synchronize_to
00703 //       Access: Published
00704 //  Description: Synchronize this texture to a sound.  Typically,
00705 //               you would load the texture and the sound from the
00706 //               same AVI file.
00707 ////////////////////////////////////////////////////////////////////
00708 void MovieTexture::
00709 synchronize_to(AudioSound *s) {
00710   CDWriter cdata(_cycler);
00711   cdata->_synchronize = s;
00712 }
00713 
00714 ////////////////////////////////////////////////////////////////////
00715 //     Function: MovieTexture::unsynchronize
00716 //       Access: Published
00717 //  Description: Stop synchronizing with a sound.
00718 ////////////////////////////////////////////////////////////////////
00719 void MovieTexture::
00720 unsynchronize() {
00721   CDWriter cdata(_cycler);
00722   cdata->_synchronize = 0;
00723 }
00724 
00725 
00726 ////////////////////////////////////////////////////////////////////
00727 //     Function: MovieTexture::do_update_frames
00728 //       Access: Private
00729 //  Description: Called internally to sync all of the frames to the
00730 //               current time.  Returns true if successful, or false
00731 //               of some of the frames are out-of-date with each
00732 //               other.
00733 ////////////////////////////////////////////////////////////////////
00734 bool MovieTexture::
00735 do_update_frames(const CData *cdata) const {
00736   // Throughout this method, we cast the VideoPage to non-const to
00737   // update the _cbuffer or _abuffer member.  We can do this safely
00738   // because this is only a transparent cache value.
00739   nassertr(cdata->_has_offset, false);
00740 
00741   // First, go through and get all of the current frames.
00742   Pages::const_iterator pi;
00743   for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
00744     const VideoPage &page = (*pi);
00745     MovieVideoCursor *color = page._color;
00746     MovieVideoCursor *alpha = page._alpha;
00747 
00748     if (color != NULL && page._cbuffer == NULL) {
00749       if (color->set_time(cdata->_offset, cdata->_true_loop_count)) {
00750         ((VideoPage &)page)._cbuffer = color->fetch_buffer();
00751       }
00752     }
00753     if (alpha != NULL && page._abuffer == NULL) {
00754       if (alpha->set_time(cdata->_offset, cdata->_true_loop_count)) {
00755         ((VideoPage &)page)._abuffer = alpha->fetch_buffer();
00756       }
00757     }
00758   }
00759 
00760   if (!movies_sync_pages) {
00761     // If movies-sync-pages is configured off, we don't care about
00762     // syncing the pages, and we always return true here to render the
00763     // pages we've got.
00764     return true;
00765   }
00766 
00767   // Now make sure all of the frames are in sync with each other.
00768   bool in_sync = true;
00769   bool any_frames = false;
00770   bool any_dropped = false;
00771   PT(MovieVideoCursor::Buffer) newest;
00772   for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
00773     const VideoPage &page = (*pi);
00774     if (page._cbuffer == NULL) {
00775       if (page._color != NULL) {
00776         // This page isn't ready at all.
00777         in_sync = false;
00778       }
00779     } else {
00780       nassertr(page._color != NULL, true);
00781       any_frames = true;
00782       if (newest == NULL) {
00783         newest = page._cbuffer;
00784       } else {
00785         int ref = newest->compare_timestamp(page._cbuffer);
00786         if (ref != 0) {
00787           // This page is ready, but out-of-date.
00788           in_sync = false;
00789           any_dropped = true;
00790           if (ref < 0) {
00791             newest = page._cbuffer;
00792           }
00793         }
00794       }
00795     }
00796     if (page._abuffer == NULL) {
00797       if (page._alpha != NULL) {
00798         in_sync = false;
00799       }
00800     } else {
00801       nassertr(page._alpha != NULL, true);
00802       any_frames = true;
00803       if (newest == NULL) {
00804         newest = page._abuffer;
00805       } else {
00806         int ref = newest->compare_timestamp(page._abuffer);
00807         if (ref != 0) {
00808           in_sync = false;
00809           any_dropped = true;
00810           if (ref < 0) {
00811             newest = page._abuffer;
00812           }
00813         }
00814       }
00815     }
00816   }
00817 
00818   if (!any_frames) {
00819     // If no frames at all are ready yet, just carry on.
00820     return true;
00821   }
00822 
00823   if (!in_sync) {
00824     // If we're not in sync, throw away pages that are older than the
00825     // newest available frame.
00826     if (newest != NULL) {
00827       Pages::const_iterator pi;
00828       for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
00829         const VideoPage &page = (*pi);
00830         if (page._cbuffer != NULL && newest->compare_timestamp(page._cbuffer) > 0) {
00831           ((VideoPage &)page)._cbuffer.clear();
00832           any_dropped = true;
00833         }
00834         if (page._abuffer != NULL && newest->compare_timestamp(page._abuffer) > 0) {
00835           ((VideoPage &)page)._abuffer.clear();
00836           any_dropped = true;
00837         }
00838       }
00839 
00840       if (any_dropped) {
00841         // If we dropped one or more frames for being out-of-sync,
00842         // implying that compare_timestamp() is implemented, then we
00843         // also want to update our internal offset value so that
00844         // future frames will get the same value.
00845         ((CData *)cdata)->_offset = newest->get_timestamp();
00846       }
00847     }
00848   }
00849 
00850   return in_sync;
00851 }
00852 
00853 ////////////////////////////////////////////////////////////////////
00854 //     Function: MovieTexture::register_with_read_factory
00855 //       Access: Public, Static
00856 //  Description: Factory method to generate a Texture object
00857 ////////////////////////////////////////////////////////////////////
00858 void MovieTexture::
00859 register_with_read_factory() {
00860   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00861 }
00862 
00863 ////////////////////////////////////////////////////////////////////
00864 //     Function: MovieTexture::make_from_bam
00865 //       Access: Protected, Static
00866 //  Description: Factory method to generate a MovieTexture object
00867 ////////////////////////////////////////////////////////////////////
00868 TypedWritable *MovieTexture::
00869 make_from_bam(const FactoryParams &params) {
00870   PT(MovieTexture) dummy = new MovieTexture("");
00871   return dummy->make_this_from_bam(params);
00872 }
00873 
00874 ////////////////////////////////////////////////////////////////////
00875 //     Function: MovieTexture::complete_pointers
00876 //       Access: Public, Virtual
00877 //  Description: Receives an array of pointers, one for each time
00878 //               manager->read_pointer() was called in fillin().
00879 //               Returns the number of pointers processed.
00880 ////////////////////////////////////////////////////////////////////
00881 int MovieTexture::
00882 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00883   int pi = Texture::complete_pointers(p_list, manager);
00884 
00885   CDWriter cdata(_cycler);
00886   size_t num_pages = cdata->_pages.size();
00887   for (size_t n = 0; n < num_pages; ++n) {
00888     VideoPage &page = cdata->_pages[n];
00889     page._color = DCAST(MovieVideoCursor, p_list[pi++]);
00890     page._alpha = DCAST(MovieVideoCursor, p_list[pi++]);
00891   }
00892 
00893   return pi;
00894 }
00895 
00896 ////////////////////////////////////////////////////////////////////
00897 //     Function: MovieTexture::do_write_datagram_rawdata
00898 //       Access: Protected, Virtual
00899 //  Description: Writes the rawdata part of the texture to the
00900 //               Datagram.
00901 ////////////////////////////////////////////////////////////////////
00902 void MovieTexture::
00903 do_write_datagram_rawdata(Texture::CData *cdata_tex, BamWriter *manager, Datagram &dg) {
00904   CDReader cdata(_cycler);
00905 
00906   dg.add_uint16(cdata_tex->_z_size);
00907   dg.add_uint16(cdata_tex->_num_views);
00908   nassertv(cdata->_pages.size() == (size_t)(cdata_tex->_z_size * cdata_tex->_num_views));
00909   for (size_t n = 0; n < cdata->_pages.size(); ++n) {
00910     const VideoPage &page = cdata->_pages[n];
00911     manager->write_pointer(dg, page._color);
00912     manager->write_pointer(dg, page._alpha);
00913   }
00914 }
00915 
00916 ////////////////////////////////////////////////////////////////////
00917 //     Function: MovieTexture::do_fillin_rawdata
00918 //       Access: Protected, Virtual
00919 //  Description: Reads in the part of the Texture that was written
00920 //               with do_write_datagram_rawdata().
00921 ////////////////////////////////////////////////////////////////////
00922 void MovieTexture::
00923 do_fillin_rawdata(Texture::CData *cdata_tex, DatagramIterator &scan, BamReader *manager) {
00924   CDWriter cdata(_cycler);
00925 
00926   cdata_tex->_z_size = scan.get_uint16();
00927   cdata_tex->_num_views = 1;
00928   if (manager->get_file_minor_ver() >= 26) {
00929     cdata_tex->_num_views = scan.get_uint16();
00930   }
00931 
00932   size_t num_pages = (size_t)(cdata_tex->_z_size * cdata_tex->_num_views);
00933   cdata->_pages.reserve(num_pages);
00934   for (size_t n = 0; n < num_pages; ++n) {
00935     cdata->_pages.push_back(VideoPage());
00936     manager->read_pointer(scan);  // page._color
00937     manager->read_pointer(scan);  // page._alpha
00938   }
00939 
00940   // We load one or more MovieVideoCursors during the above loop.  We
00941   // need a finalize callback so we can initialize ourselves once
00942   // those cursors have been read completely.
00943   manager->register_finalize(this);
00944 }
00945 
00946 ////////////////////////////////////////////////////////////////////
00947 //     Function: MovieTexture::finalize
00948 //       Access: Public, Virtual
00949 //  Description: Called by the BamReader to perform any final actions
00950 //               needed for setting up the object after all objects
00951 //               have been read and all pointers have been completed.
00952 ////////////////////////////////////////////////////////////////////
00953 void MovieTexture::
00954 finalize(BamReader *manager) {
00955   Texture::CDWriter cdata_tex(Texture::_cycler);
00956   CDWriter cdata(_cycler);
00957 
00958   // Insist that each of our video pages gets finalized before we do.
00959   size_t num_pages = cdata->_pages.size();
00960   for (size_t n = 0; n < num_pages; ++n) {
00961     VideoPage &page = cdata->_pages[n];
00962     manager->finalize_now(page._color);
00963     manager->finalize_now(page._alpha);
00964   }
00965 
00966   do_recalculate_image_properties(cdata, cdata_tex, LoaderOptions());
00967 
00968   set_loaded_from_image();
00969   set_loop(true);
00970   play();
00971 }
00972 
00973 #endif  // HAVE_AUDIO
 All Classes Functions Variables Enumerations