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