Panda3D
|
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 ©) : 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 ©) : 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 ¶ms) { 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