Panda3D
movieTexture.cxx
1 // Filename: movieTexture.cxx
2 // Created by: jyelon (01Aug2007)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pandabase.h"
16 
17 #ifdef HAVE_AUDIO
18 
19 #include "movieVideo.h"
20 #include "movieVideoCursor.h"
21 #include "movieTypeRegistry.h"
22 #include "movieTexture.h"
23 #include "clockObject.h"
24 #include "config_gobj.h"
25 #include "config_grutil.h"
26 #include "bamCacheRecord.h"
27 #include "bamReader.h"
28 #include "bamWriter.h"
29 #include "math.h"
30 #include "audioSound.h"
31 
32 TypeHandle MovieTexture::_type_handle;
33 
34 ////////////////////////////////////////////////////////////////////
35 // Function: MovieTexture::Constructor
36 // Access: Published
37 // Description: Creates a blank movie texture. Movies must be
38 // added using do_read_one or do_load_one.
39 ////////////////////////////////////////////////////////////////////
40 MovieTexture::
41 MovieTexture(const string &name) :
42  Texture(name)
43 {
44 }
45 
46 ////////////////////////////////////////////////////////////////////
47 // Function: MovieTexture::Constructor
48 // Access: Published
49 // Description: Creates a texture playing the specified movie.
50 ////////////////////////////////////////////////////////////////////
51 MovieTexture::
52 MovieTexture(MovieVideo *video) :
53  Texture(video->get_name())
54 {
55  Texture::CDWriter cdata_tex(Texture::_cycler, true);
56  do_load_one(cdata_tex, video->open(), NULL, 0, LoaderOptions());
57 }
58 
59 ////////////////////////////////////////////////////////////////////
60 // Function: MovieTexture::CData::Constructor
61 // Access: public
62 // Description: xxx
63 ////////////////////////////////////////////////////////////////////
64 MovieTexture::CData::
65 CData() :
66  _video_width(1),
67  _video_height(1),
68  _video_length(1.0),
69  _clock(0.0),
70  _playing(false),
71  _loop_count(1),
72  _play_rate(1.0),
73  _has_offset(false)
74 {
75 }
76 
77 ////////////////////////////////////////////////////////////////////
78 // Function: MovieTexture::CData::Copy Constructor
79 // Access: public
80 // Description: xxx
81 ////////////////////////////////////////////////////////////////////
82 MovieTexture::CData::
83 CData(const CData &copy) :
84  _pages(copy._pages),
85  _video_width(copy._video_width),
86  _video_height(copy._video_height),
87  _video_length(copy._video_length),
88  _clock(0.0),
89  _playing(false),
90  _loop_count(1),
91  _play_rate(1.0),
92  _has_offset(false)
93 {
94 }
95 
96 ////////////////////////////////////////////////////////////////////
97 // Function: MovieTexture::CData::make_copy
98 // Access: public
99 // Description: xxx
100 ////////////////////////////////////////////////////////////////////
101 CycleData *MovieTexture::CData::
102 make_copy() const {
103  return new CData(*this);
104 }
105 
106 ////////////////////////////////////////////////////////////////////
107 // Function: MovieTexture::Copy Constructor
108 // Access: Protected
109 // Description: Use MovieTexture::make_copy() to make a duplicate copy of
110 // an existing MovieTexture.
111 ////////////////////////////////////////////////////////////////////
112 MovieTexture::
113 MovieTexture(const MovieTexture &copy) :
114  Texture(copy)
115 {
116  nassertv(false);
117 }
118 
119 ////////////////////////////////////////////////////////////////////
120 // Function: MovieTexture::Destructor
121 // Access: Published, Virtual
122 // Description: xxx
123 ////////////////////////////////////////////////////////////////////
124 MovieTexture::
125 ~MovieTexture() {
126  clear();
127 }
128 
129 ////////////////////////////////////////////////////////////////////
130 // Function: MovieTexture::ensure_loader_type
131 // Access: Public, Virtual
132 // Description: May be called prior to calling read_txo() or any
133 // bam-related Texture-creating callback, to ensure that
134 // the proper dynamic libraries for a Texture of the
135 // current class type, and the indicated filename, have
136 // been already loaded.
137 //
138 // This is a low-level function that should not normally
139 // need to be called directly by the user.
140 //
141 // Note that for best results you must first create a
142 // Texture object of the appropriate class type for your
143 // filename, for instance with
144 // TexturePool::make_texture().
145 ////////////////////////////////////////////////////////////////////
146 void MovieTexture::
147 ensure_loader_type(const Filename &filename) {
148  // Creating a MovieVideo of the appropriate type is a slightly hacky
149  // way to ensure the appropriate libraries are loaded. We can let
150  // the MovieVideo we create immediately destruct.
152  PT(MovieVideo) video = reg->make_video(filename);
153 }
154 
155 ////////////////////////////////////////////////////////////////////
156 // Function: MovieTexture::make_texture
157 // Access: Public, Static
158 // Description: A factory function to make a new MovieTexture, used
159 // to pass to the TexturePool.
160 ////////////////////////////////////////////////////////////////////
161 PT(Texture) MovieTexture::
162 make_texture() {
163  return new MovieTexture("");
164 }
165 
166 ////////////////////////////////////////////////////////////////////
167 // Function: MovieTexture::do_recalculate_image_properties
168 // Access: Protected
169 // Description: Resizes the texture, and adjusts the format,
170 // based on the source movies. The resulting texture
171 // will be large enough to hold all the videos.
172 //
173 // Assumes the lock is already held.
174 ////////////////////////////////////////////////////////////////////
175 void MovieTexture::
176 do_recalculate_image_properties(CData *cdata, Texture::CData *cdata_tex, const LoaderOptions &options) {
177  int x_max = 1;
178  int y_max = 1;
179  bool alpha = false;
180  double len = 0.0;
181 
182  for (size_t i = 0; i < cdata->_pages.size(); ++i) {
183  MovieVideoCursor *t = cdata->_pages[i]._color;
184  if (t) {
185  if (t->size_x() > x_max) x_max = t->size_x();
186  if (t->size_y() > y_max) y_max = t->size_y();
187  if (t->length() > len) len = t->length();
188  if (t->get_num_components() == 4) alpha=true;
189  }
190  t = cdata->_pages[i]._alpha;
191  if (t) {
192  if (t->size_x() > x_max) x_max = t->size_x();
193  if (t->size_y() > y_max) y_max = t->size_y();
194  if (t->length() > len) len = t->length();
195  alpha = true;
196  }
197  }
198 
199  cdata->_video_width = x_max;
200  cdata->_video_height = y_max;
201  cdata->_video_length = len;
202 
203  do_adjust_this_size(cdata_tex, x_max, y_max, get_name(), true);
204 
205  do_reconsider_image_properties(cdata_tex, x_max, y_max, alpha?4:3,
206  T_unsigned_byte, cdata->_pages.size(),
207  options);
208  cdata_tex->_orig_file_x_size = cdata->_video_width;
209  cdata_tex->_orig_file_y_size = cdata->_video_height;
210 
211  do_set_pad_size(cdata_tex,
212  max(cdata_tex->_x_size - cdata_tex->_orig_file_x_size, 0),
213  max(cdata_tex->_y_size - cdata_tex->_orig_file_y_size, 0),
214  0);
215 }
216 
217 ////////////////////////////////////////////////////////////////////
218 // Function: MovieTexture::do_adjust_this_size
219 // Access: Protected, Virtual
220 // Description: Works like adjust_size, but also considers the
221 // texture class. Movie textures, for instance, always
222 // pad outwards, never scale down.
223 ////////////////////////////////////////////////////////////////////
224 bool MovieTexture::
225 do_adjust_this_size(const Texture::CData *cdata_tex,
226  int &x_size, int &y_size, const string &name,
227  bool for_padding) const {
228  AutoTextureScale ats = do_get_auto_texture_scale(cdata_tex);
229  if (ats != ATS_none) {
230  ats = ATS_pad;
231  }
232 
233  return adjust_size(x_size, y_size, name, for_padding, ats);
234 }
235 
236 ////////////////////////////////////////////////////////////////////
237 // Function: MovieTexture::do_read_one
238 // Access: Protected, Virtual
239 // Description: Combines a color and alpha video image from the two
240 // indicated filenames. Both must be the same kind of
241 // video with similar properties.
242 ////////////////////////////////////////////////////////////////////
243 bool MovieTexture::
244 do_read_one(Texture::CData *cdata_tex,
245  const Filename &fullpath, const Filename &alpha_fullpath,
246  int z, int n, int primary_file_num_channels, int alpha_file_channel,
247  const LoaderOptions &options,
248  bool header_only, BamCacheRecord *record) {
249  nassertr(n == 0, false);
250  if (!do_reconsider_z_size(cdata_tex, z, options)) {
251  return false;
252  }
253  nassertr(z >= 0 && z < cdata_tex->_z_size * cdata_tex->_num_views, false);
254 
255  if (record != (BamCacheRecord *)NULL) {
256  record->add_dependent_file(fullpath);
257  }
258 
259  PT(MovieVideoCursor) color;
260  PT(MovieVideoCursor) alpha;
261 
262  color = MovieVideo::get(fullpath)->open();
263  if (color == 0) {
264  return false;
265  }
266  if (!alpha_fullpath.empty()) {
267  alpha = MovieVideo::get(alpha_fullpath)->open();
268  if (alpha == 0) {
269  return false;
270  }
271  }
272 
273  if (z == 0) {
274  if (!has_name()) {
275  set_name(fullpath.get_basename_wo_extension());
276  }
277  // Don't use has_filename() here, it will cause a deadlock
278  if (cdata_tex->_filename.empty()) {
279  cdata_tex->_filename = fullpath;
280  cdata_tex->_alpha_filename = alpha_fullpath;
281  }
282 
283  cdata_tex->_fullpath = fullpath;
284  cdata_tex->_alpha_fullpath = alpha_fullpath;
285  }
286 
287  cdata_tex->_primary_file_num_channels = primary_file_num_channels;
288  cdata_tex->_alpha_file_channel = alpha_file_channel;
289 
290  if (!do_load_one(cdata_tex, color, alpha, z, options)) {
291  return false;
292  }
293 
294  cdata_tex->_loaded_from_image = true;
295  set_loop(true);
296  play();
297  return true;
298 }
299 
300 ////////////////////////////////////////////////////////////////////
301 // Function: MovieTexture::do_load_one
302 // Access: Protected, Virtual
303 // Description: Loads movie objects into the texture.
304 ////////////////////////////////////////////////////////////////////
305 bool MovieTexture::
306 do_load_one(Texture::CData *cdata_tex,
307  PT(MovieVideoCursor) color, PT(MovieVideoCursor) alpha, int z,
308  const LoaderOptions &options) {
309  CDWriter cdata(_cycler);
310  cdata->_pages.resize(z + 1);
311  cdata->_pages[z]._color = color;
312  cdata->_pages[z]._alpha = alpha;
313  do_recalculate_image_properties(cdata, cdata_tex, options);
314 
315  // Make sure the image data is initially black, which is nice for
316  // padded textures.
317  PTA_uchar image = make_ram_image();
318  memset(image.p(), 0, image.size());
319 
320  return true;
321 }
322 
323 ////////////////////////////////////////////////////////////////////
324 // Function: MovieTexture::do_load_one
325 // Access: Protected, Virtual
326 // Description: Loading a static image into a MovieTexture is
327 // an error.
328 ////////////////////////////////////////////////////////////////////
329 bool MovieTexture::
330 do_load_one(Texture::CData *cdata_tex,
331  const PNMImage &pnmimage, const string &name, int z, int n,
332  const LoaderOptions &options) {
333  grutil_cat.error() << "You cannot load a static image into a MovieTexture\n";
334  return false;
335 }
336 
337 ////////////////////////////////////////////////////////////////////
338 // Function: MovieTexture::do_allocate_pages
339 // Access: Protected, Virtual
340 // Description: Called internally by do_reconsider_z_size() to
341 // allocate new memory in _ram_images[0] for the new
342 // number of pages.
343 //
344 // Assumes the lock is already held.
345 ////////////////////////////////////////////////////////////////////
346 void MovieTexture::
347 do_allocate_pages(Texture::CData *cdata_tex) {
348  // We don't actually do anything here; the allocation is made in
349  // do_load_one(), above.
350 }
351 
352 ////////////////////////////////////////////////////////////////////
353 // Function: MovieTexture::has_cull_callback
354 // Access: Public, Virtual
355 // Description: Should be overridden by derived classes to return
356 // true if cull_callback() has been defined. Otherwise,
357 // returns false to indicate cull_callback() does not
358 // need to be called for this node during the cull
359 // traversal.
360 ////////////////////////////////////////////////////////////////////
361 bool MovieTexture::
362 has_cull_callback() const {
363  return true;
364 }
365 
366 ////////////////////////////////////////////////////////////////////
367 // Function: MovieTexture::cull_callback
368 // Access: Public, Virtual
369 // Description: This function will be called during the cull
370 // traversal to update the MovieTexture. This update
371 // consists of fetching the next video frame from the
372 // underlying MovieVideo sources. The MovieVideo
373 // object belongs to the cull thread.
374 ////////////////////////////////////////////////////////////////////
375 bool MovieTexture::
376 cull_callback(CullTraverser *, const CullTraverserData &) const {
377  Texture::CDReader cdata_tex(Texture::_cycler);
378  CDReader cdata(_cycler);
379 
380  if (!cdata->_has_offset) {
381  // If we don't have a previously-computed timestamp (offset)
382  // cached, then compute a new one.
383  double offset;
384  int true_loop_count = 1;
385  if (cdata->_synchronize != 0) {
386  offset = cdata->_synchronize->get_time();
387  } else {
388  // Calculate the cursor position modulo the length of the movie.
390  offset = cdata->_clock;
391  if (cdata->_playing) {
392  offset += now * cdata->_play_rate;
393  }
394  true_loop_count = cdata->_loop_count;
395  }
396  ((CData *)cdata.p())->_offset = offset;
397  ((CData *)cdata.p())->_true_loop_count = true_loop_count;
398  ((CData *)cdata.p())->_has_offset = true;
399  }
400 
401  bool in_sync = do_update_frames(cdata);
402  if (!in_sync) {
403  // If it didn't successfully sync, try again--once. The second
404  // time it might be able to fill in some more recent frames.
405  in_sync = do_update_frames(cdata);
406  }
407 
408  if (in_sync) {
409  // Now go back through and apply all the frames to the texture.
410  Pages::const_iterator pi;
411  for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
412  const VideoPage &page = (*pi);
413  MovieVideoCursor *color = page._color;
414  MovieVideoCursor *alpha = page._alpha;
415  size_t i = pi - cdata->_pages.begin();
416 
417  if (color != NULL && alpha != NULL) {
418  color->apply_to_texture_rgb(page._cbuffer, (MovieTexture*)this, i);
419  alpha->apply_to_texture_alpha(page._abuffer, (MovieTexture*)this, i, cdata_tex->_alpha_file_channel);
420 
421  } else if (color != NULL) {
422  color->apply_to_texture(page._cbuffer, (MovieTexture*)this, i);
423  }
424 
425  ((VideoPage &)page)._cbuffer.clear();
426  ((VideoPage &)page)._abuffer.clear();
427  }
428 
429  // Clear the cached offset so we can update the frame next time.
430  ((CData *)cdata.p())->_has_offset = false;
431  }
432 
433  return true;
434 }
435 
436 ////////////////////////////////////////////////////////////////////
437 // Function: MovieTexture::make_copy_impl
438 // Access: Protected, Virtual
439 // Description: Returns a new copy of the same Texture. This copy,
440 // if applied to geometry, will be copied into texture
441 // as a separate texture from the original, so it will
442 // be duplicated in texture memory (and may be
443 // independently modified if desired).
444 //
445 // If the Texture is a MovieTexture, the resulting
446 // duplicate may be animated independently of the
447 // original.
448 ////////////////////////////////////////////////////////////////////
449 PT(Texture) MovieTexture::
450 make_copy_impl() {
451  Texture::CDReader cdata_tex(Texture::_cycler);
452  CDReader cdata(_cycler);
453  PT(MovieTexture) copy = new MovieTexture(get_name());
454  Texture::CDWriter cdata_copy_tex(copy->Texture::_cycler, true);
455  CDWriter cdata_copy(copy->_cycler, true);
456  copy->do_assign(cdata_copy, cdata_copy_tex, this, cdata, cdata_tex);
457 
458  return copy.p();
459 }
460 
461 ////////////////////////////////////////////////////////////////////
462 // Function: MovieTexture::do_assign
463 // Access: Protected
464 // Description: Implements make_copy().
465 ////////////////////////////////////////////////////////////////////
466 void MovieTexture::
467 do_assign(CData *cdata, Texture::CData *cdata_tex, const MovieTexture *copy,
468  const CData *cdata_copy, const Texture::CData *cdata_copy_tex) {
469  Texture::do_assign(cdata_tex, copy, cdata_copy_tex);
470 
473  color.resize(cdata_copy->_pages.size());
474  alpha.resize(cdata_copy->_pages.size());
475  for (int i=0; i<(int)(color.size()); i++) {
476  color[i] = cdata_copy->_pages[i]._color;
477  alpha[i] = cdata_copy->_pages[i]._alpha;
478  }
479 
480  cdata->_pages.resize(color.size());
481  for (int i=0; i<(int)(color.size()); i++) {
482  if (color[i]) {
483  cdata->_pages[i]._color = color[i]->get_source()->open();
484  }
485  if (alpha[i]) {
486  cdata->_pages[i]._alpha = alpha[i]->get_source()->open();
487  }
488  }
489  do_recalculate_image_properties(cdata, cdata_tex, LoaderOptions());
490 }
491 
492 ////////////////////////////////////////////////////////////////////
493 // Function: MovieTexture::reload_ram_image
494 // Access: Protected, Virtual
495 // Description: A MovieTexture must always keep its ram image,
496 // since there is no way to reload it from the
497 // source MovieVideo.
498 ////////////////////////////////////////////////////////////////////
499 void MovieTexture::
500 do_reload_ram_image(Texture::CData *cdata, bool allow_compression) {
501  // A MovieTexture should never dump its RAM image.
502  // Therefore, this is not needed.
503 }
504 
505 ////////////////////////////////////////////////////////////////////
506 // Function: MovieTexture::get_keep_ram_image
507 // Access: Published, Virtual
508 // Description: A MovieTexture must always keep its ram image,
509 // since there is no way to reload it from the
510 // source MovieVideo.
511 ////////////////////////////////////////////////////////////////////
512 bool MovieTexture::
513 get_keep_ram_image() const {
514  // A MovieTexture should never dump its RAM image.
515  return true;
516 }
517 
518 ////////////////////////////////////////////////////////////////////
519 // Function: MovieTexture::do_has_bam_rawdata
520 // Access: Protected, Virtual
521 // Description: Returns true if there is a rawdata image that we have
522 // available to write to the bam stream. For a normal
523 // Texture, this is the same thing as
524 // do_has_ram_image(), but a movie texture might define
525 // it differently.
526 ////////////////////////////////////////////////////////////////////
527 bool MovieTexture::
528 do_has_bam_rawdata(const Texture::CData *cdata) const {
529  return true;
530 }
531 
532 ////////////////////////////////////////////////////////////////////
533 // Function: MovieTexture::do_get_bam_rawdata
534 // Access: Protected, Virtual
535 // Description: If do_has_bam_rawdata() returned false, this attempts
536 // to reload the rawdata image if possible.
537 ////////////////////////////////////////////////////////////////////
538 void MovieTexture::
539 do_get_bam_rawdata(Texture::CData *cdata) {
540 }
541 
542 ////////////////////////////////////////////////////////////////////
543 // Function: MovieTexture::do_can_reload
544 // Access: Protected, Virtual
545 // Description: Returns true if we can safely call
546 // do_unlock_and_reload_ram_image() in order to make the
547 // image available, or false if we shouldn't do this
548 // (because we know from a priori knowledge that it
549 // wouldn't work anyway).
550 ////////////////////////////////////////////////////////////////////
551 bool MovieTexture::
552 do_can_reload(const Texture::CData *cdata) const {
553  return false;
554 }
555 
556 ////////////////////////////////////////////////////////////////////
557 // Function: MovieTexture::restart
558 // Access: Published
559 // Description: Start playing the movie from where it was last
560 // paused. Has no effect if the movie is not paused,
561 // or if the movie's cursor is already at the end.
562 ////////////////////////////////////////////////////////////////////
563 void MovieTexture::
564 restart() {
565  CDWriter cdata(_cycler);
566  if (!cdata->_playing) {
568  cdata->_clock = cdata->_clock - (now * cdata->_play_rate);
569  cdata->_playing = true;
570  }
571 }
572 
573 ////////////////////////////////////////////////////////////////////
574 // Function: MovieTexture::stop
575 // Access: Published
576 // Description: Stops a currently playing or looping movie right
577 // where it is. The movie's cursor remains frozen at
578 // the point where it was stopped.
579 ////////////////////////////////////////////////////////////////////
580 void MovieTexture::
581 stop() {
582  CDWriter cdata(_cycler);
583  if (cdata->_playing) {
585  cdata->_clock = cdata->_clock + (now * cdata->_play_rate);
586  cdata->_playing = false;
587  }
588 }
589 
590 ////////////////////////////////////////////////////////////////////
591 // Function: MovieTexture::play
592 // Access: Published
593 // Description: Plays the movie from the beginning.
594 ////////////////////////////////////////////////////////////////////
595 void MovieTexture::
596 play() {
597  CDWriter cdata(_cycler);
599  cdata->_clock = 0.0 - (now * cdata->_play_rate);
600  cdata->_playing = true;
601 }
602 
603 ////////////////////////////////////////////////////////////////////
604 // Function: MovieTexture::set_time
605 // Access: Published
606 // Description: Sets the movie's cursor.
607 ////////////////////////////////////////////////////////////////////
608 void MovieTexture::
609 set_time(double t) {
610  CDWriter cdata(_cycler);
611  t = min(cdata->_video_length, max(0.0, t));
612  if (cdata->_playing) {
614  cdata->_clock = t - (now * cdata->_play_rate);
615  } else {
616  cdata->_clock = t;
617  }
618 }
619 
620 ////////////////////////////////////////////////////////////////////
621 // Function: MovieTexture::get_time
622 // Access: Published
623 // Description: Returns the current value of the movie's cursor.
624 // If the movie's loop count is greater than one, then
625 // its length is effectively multiplied for the
626 // purposes of this function. In other words,
627 // the return value will be in the range 0.0
628 // to (length * loopcount).
629 ////////////////////////////////////////////////////////////////////
630 double MovieTexture::
631 get_time() const {
632  CDReader cdata(_cycler);
633  double clock = cdata->_clock;
634  if (cdata->_playing) {
636  clock += (now * cdata->_play_rate);
637  }
638  return clock;
639 }
640 
641 ////////////////////////////////////////////////////////////////////
642 // Function: MovieTexture::set_loop
643 // Access: Published
644 // Description: If true, sets the movie's loop count to 1 billion.
645 // If false, sets the movie's loop count to one.
646 ////////////////////////////////////////////////////////////////////
647 void MovieTexture::
648 set_loop(bool loop) {
649  set_loop_count(loop ? 0:1);
650 }
651 
652 ////////////////////////////////////////////////////////////////////
653 // Function: MovieTexture::get_loop
654 // Access: Published
655 // Description: Returns true if the movie's loop count is not equal
656 // to one.
657 ////////////////////////////////////////////////////////////////////
658 bool MovieTexture::
659 get_loop() const {
660  CDReader cdata(_cycler);
661  return (cdata->_loop_count == 0);
662 }
663 
664 ////////////////////////////////////////////////////////////////////
665 // Function: MovieTexture::set_loop_count
666 // Access: Published
667 // Description: Sets the movie's loop count to the desired value.
668 ////////////////////////////////////////////////////////////////////
669 void MovieTexture::
670 set_loop_count(int n) {
671  CDWriter cdata(_cycler);
672  cdata->_loop_count = n;
673 }
674 
675 ////////////////////////////////////////////////////////////////////
676 // Function: MovieTexture::get_loop_count
677 // Access: Published
678 // Description: Returns the movie's loop count.
679 ////////////////////////////////////////////////////////////////////
680 int MovieTexture::
681 get_loop_count() const {
682  CDReader cdata(_cycler);
683  return cdata->_loop_count;
684 }
685 
686 ////////////////////////////////////////////////////////////////////
687 // Function: MovieTexture::set_play_rate
688 // Access: Published
689 // Description: Sets the movie's play-rate. This is the speed at
690 // which the movie's cursor advances. The default is
691 // to advance 1.0 movie-seconds per real-time second.
692 ////////////////////////////////////////////////////////////////////
693 void MovieTexture::
694 set_play_rate(double rate) {
695  CDWriter cdata(_cycler);
696  if (cdata->_playing) {
698  cdata->_clock += (now * cdata->_play_rate);
699  cdata->_play_rate = rate;
700  cdata->_clock -= (now * cdata->_play_rate);
701  } else {
702  cdata->_play_rate = rate;
703  }
704 }
705 
706 ////////////////////////////////////////////////////////////////////
707 // Function: MovieTexture::get_play_rate
708 // Access: Published
709 // Description: Gets the movie's play-rate.
710 ////////////////////////////////////////////////////////////////////
711 double MovieTexture::
712 get_play_rate() const {
713  CDReader cdata(_cycler);
714  return cdata->_play_rate;
715 }
716 
717 ////////////////////////////////////////////////////////////////////
718 // Function: MovieTexture::is_playing
719 // Access: Published
720 // Description: Returns true if the movie's cursor is advancing.
721 ////////////////////////////////////////////////////////////////////
722 bool MovieTexture::
723 is_playing() const {
724  CDReader cdata(_cycler);
725  return cdata->_playing;
726 }
727 
728 ////////////////////////////////////////////////////////////////////
729 // Function: MovieTexture::synchronize_to
730 // Access: Published
731 // Description: Synchronize this texture to a sound. Typically,
732 // you would load the texture and the sound from the
733 // same AVI file.
734 ////////////////////////////////////////////////////////////////////
735 void MovieTexture::
736 synchronize_to(AudioSound *s) {
737  CDWriter cdata(_cycler);
738  cdata->_synchronize = s;
739 }
740 
741 ////////////////////////////////////////////////////////////////////
742 // Function: MovieTexture::unsynchronize
743 // Access: Published
744 // Description: Stop synchronizing with a sound.
745 ////////////////////////////////////////////////////////////////////
746 void MovieTexture::
747 unsynchronize() {
748  CDWriter cdata(_cycler);
749  cdata->_synchronize = 0;
750 }
751 
752 
753 ////////////////////////////////////////////////////////////////////
754 // Function: MovieTexture::do_update_frames
755 // Access: Private
756 // Description: Called internally to sync all of the frames to the
757 // current time. Returns true if successful, or false
758 // of some of the frames are out-of-date with each
759 // other.
760 ////////////////////////////////////////////////////////////////////
761 bool MovieTexture::
762 do_update_frames(const CData *cdata) const {
763  // Throughout this method, we cast the VideoPage to non-const to
764  // update the _cbuffer or _abuffer member. We can do this safely
765  // because this is only a transparent cache value.
766  nassertr(cdata->_has_offset, false);
767 
768  // First, go through and get all of the current frames.
769  Pages::const_iterator pi;
770  for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
771  const VideoPage &page = (*pi);
772  MovieVideoCursor *color = page._color;
773  MovieVideoCursor *alpha = page._alpha;
774 
775  if (color != NULL && page._cbuffer == NULL) {
776  if (color->set_time(cdata->_offset, cdata->_true_loop_count)) {
777  ((VideoPage &)page)._cbuffer = color->fetch_buffer();
778  }
779  }
780  if (alpha != NULL && page._abuffer == NULL) {
781  if (alpha->set_time(cdata->_offset, cdata->_true_loop_count)) {
782  ((VideoPage &)page)._abuffer = alpha->fetch_buffer();
783  }
784  }
785  }
786 
787  if (!movies_sync_pages) {
788  // If movies-sync-pages is configured off, we don't care about
789  // syncing the pages, and we always return true here to render the
790  // pages we've got.
791  return true;
792  }
793 
794  // Now make sure all of the frames are in sync with each other.
795  bool in_sync = true;
796  bool any_frames = false;
797  bool any_dropped = false;
798  PT(MovieVideoCursor::Buffer) newest;
799  for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
800  const VideoPage &page = (*pi);
801  if (page._cbuffer == NULL) {
802  if (page._color != NULL) {
803  // This page isn't ready at all.
804  in_sync = false;
805  }
806  } else {
807  nassertr(page._color != NULL, true);
808  any_frames = true;
809  if (newest == NULL) {
810  newest = page._cbuffer;
811  } else {
812  int ref = newest->compare_timestamp(page._cbuffer);
813  if (ref != 0) {
814  // This page is ready, but out-of-date.
815  in_sync = false;
816  any_dropped = true;
817  if (ref < 0) {
818  newest = page._cbuffer;
819  }
820  }
821  }
822  }
823  if (page._abuffer == NULL) {
824  if (page._alpha != NULL) {
825  in_sync = false;
826  }
827  } else {
828  nassertr(page._alpha != NULL, true);
829  any_frames = true;
830  if (newest == NULL) {
831  newest = page._abuffer;
832  } else {
833  int ref = newest->compare_timestamp(page._abuffer);
834  if (ref != 0) {
835  in_sync = false;
836  any_dropped = true;
837  if (ref < 0) {
838  newest = page._abuffer;
839  }
840  }
841  }
842  }
843  }
844 
845  if (!any_frames) {
846  // If no frames at all are ready yet, just carry on.
847  return true;
848  }
849 
850  if (!in_sync) {
851  // If we're not in sync, throw away pages that are older than the
852  // newest available frame.
853  if (newest != NULL) {
854  Pages::const_iterator pi;
855  for (pi = cdata->_pages.begin(); pi != cdata->_pages.end(); ++pi) {
856  const VideoPage &page = (*pi);
857  if (page._cbuffer != NULL && newest->compare_timestamp(page._cbuffer) > 0) {
858  ((VideoPage &)page)._cbuffer.clear();
859  any_dropped = true;
860  }
861  if (page._abuffer != NULL && newest->compare_timestamp(page._abuffer) > 0) {
862  ((VideoPage &)page)._abuffer.clear();
863  any_dropped = true;
864  }
865  }
866 
867  if (any_dropped) {
868  // If we dropped one or more frames for being out-of-sync,
869  // implying that compare_timestamp() is implemented, then we
870  // also want to update our internal offset value so that
871  // future frames will get the same value.
872  ((CData *)cdata)->_offset = newest->get_timestamp();
873  }
874  }
875  }
876 
877  return in_sync;
878 }
879 
880 ////////////////////////////////////////////////////////////////////
881 // Function: MovieTexture::register_with_read_factory
882 // Access: Public, Static
883 // Description: Factory method to generate a Texture object
884 ////////////////////////////////////////////////////////////////////
885 void MovieTexture::
886 register_with_read_factory() {
887  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
888 }
889 
890 ////////////////////////////////////////////////////////////////////
891 // Function: MovieTexture::make_from_bam
892 // Access: Protected, Static
893 // Description: Factory method to generate a MovieTexture object
894 ////////////////////////////////////////////////////////////////////
895 TypedWritable *MovieTexture::
896 make_from_bam(const FactoryParams &params) {
897  PT(MovieTexture) dummy = new MovieTexture("");
898  return dummy->make_this_from_bam(params);
899 }
900 
901 ////////////////////////////////////////////////////////////////////
902 // Function: MovieTexture::complete_pointers
903 // Access: Public, Virtual
904 // Description: Receives an array of pointers, one for each time
905 // manager->read_pointer() was called in fillin().
906 // Returns the number of pointers processed.
907 ////////////////////////////////////////////////////////////////////
908 int MovieTexture::
909 complete_pointers(TypedWritable **p_list, BamReader *manager) {
910  int pi = Texture::complete_pointers(p_list, manager);
911 
912  CDWriter cdata(_cycler);
913  size_t num_pages = cdata->_pages.size();
914  for (size_t n = 0; n < num_pages; ++n) {
915  VideoPage &page = cdata->_pages[n];
916  page._color = DCAST(MovieVideoCursor, p_list[pi++]);
917  page._alpha = DCAST(MovieVideoCursor, p_list[pi++]);
918  }
919 
920  return pi;
921 }
922 
923 ////////////////////////////////////////////////////////////////////
924 // Function: MovieTexture::do_write_datagram_rawdata
925 // Access: Protected, Virtual
926 // Description: Writes the rawdata part of the texture to the
927 // Datagram.
928 ////////////////////////////////////////////////////////////////////
929 void MovieTexture::
930 do_write_datagram_rawdata(Texture::CData *cdata_tex, BamWriter *manager, Datagram &dg) {
931  CDReader cdata(_cycler);
932 
933  dg.add_uint16(cdata_tex->_z_size);
934  dg.add_uint16(cdata_tex->_num_views);
935  nassertv(cdata->_pages.size() == (size_t)(cdata_tex->_z_size * cdata_tex->_num_views));
936  for (size_t n = 0; n < cdata->_pages.size(); ++n) {
937  const VideoPage &page = cdata->_pages[n];
938  manager->write_pointer(dg, page._color);
939  manager->write_pointer(dg, page._alpha);
940  }
941 }
942 
943 ////////////////////////////////////////////////////////////////////
944 // Function: MovieTexture::do_fillin_rawdata
945 // Access: Protected, Virtual
946 // Description: Reads in the part of the Texture that was written
947 // with do_write_datagram_rawdata().
948 ////////////////////////////////////////////////////////////////////
949 void MovieTexture::
950 do_fillin_rawdata(Texture::CData *cdata_tex, DatagramIterator &scan, BamReader *manager) {
951  CDWriter cdata(_cycler);
952 
953  cdata_tex->_z_size = scan.get_uint16();
954  cdata_tex->_num_views = 1;
955  if (manager->get_file_minor_ver() >= 26) {
956  cdata_tex->_num_views = scan.get_uint16();
957  }
958 
959  size_t num_pages = (size_t)(cdata_tex->_z_size * cdata_tex->_num_views);
960  cdata->_pages.reserve(num_pages);
961  for (size_t n = 0; n < num_pages; ++n) {
962  cdata->_pages.push_back(VideoPage());
963  manager->read_pointer(scan); // page._color
964  manager->read_pointer(scan); // page._alpha
965  }
966 
967  // We load one or more MovieVideoCursors during the above loop. We
968  // need a finalize callback so we can initialize ourselves once
969  // those cursors have been read completely.
970  manager->register_finalize(this);
971 }
972 
973 ////////////////////////////////////////////////////////////////////
974 // Function: MovieTexture::finalize
975 // Access: Public, Virtual
976 // Description: Called by the BamReader to perform any final actions
977 // needed for setting up the object after all objects
978 // have been read and all pointers have been completed.
979 ////////////////////////////////////////////////////////////////////
980 void MovieTexture::
981 finalize(BamReader *manager) {
982  Texture::CDWriter cdata_tex(Texture::_cycler);
983  CDWriter cdata(_cycler);
984 
985  // Insist that each of our video pages gets finalized before we do.
986  size_t num_pages = cdata->_pages.size();
987  for (size_t n = 0; n < num_pages; ++n) {
988  VideoPage &page = cdata->_pages[n];
989  manager->finalize_now(page._color);
990  manager->finalize_now(page._alpha);
991  }
992 
993  do_recalculate_image_properties(cdata, cdata_tex, LoaderOptions());
994 
995  set_loaded_from_image();
996  set_loop(true);
997  play();
998 }
999 
1000 #endif // HAVE_AUDIO
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:271
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition: pnmImage.h:68
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:26
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
This class records the different types of MovieAudio and MovieVideo that are available for loading...
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
double get_frame_time(Thread *current_thread=Thread::get_current_thread()) const
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.I:48
virtual void apply_to_texture_rgb(const Buffer *buffer, Texture *t, int page)
Copies this buffer&#39;s contents into the RGB channels of the supplied texture.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:105
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
virtual bool set_time(double timestamp, int loop_count)
Updates the cursor to the indicated time.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin()...
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
A MovieVideo is actually any source that provides a sequence of video frames.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
virtual void apply_to_texture(const Buffer *buffer, Texture *t, int page)
Stores this buffer&#39;s contents in the indicated texture.
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:886
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:460
void finalize_now(TypedWritable *whom)
Forces the finalization of a particular object.
Definition: bamReader.cxx:986
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:181
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
static MovieTypeRegistry * get_global_ptr()
Returns a pointer to the global MovieTypeRegistry instance.
A MovieVideo is actually any source that provides a sequence of video frames.
Definition: movieVideo.h:42
virtual void apply_to_texture_alpha(const Buffer *buffer, Texture *t, int page, int alpha_src)
Copies this buffer&#39;s contents into the alpha channel of the supplied texture.
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record...
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:279
void read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:658