Panda3D
|
00001 // Filename: recorderController.cxx 00002 // Created by: drose (24Jan04) 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 "recorderController.h" 00016 #include "recorderFrame.h" 00017 #include "bamReader.h" 00018 #include "bamWriter.h" 00019 #include "config_recorder.h" 00020 #include "bam.h" 00021 #include "clockObject.h" 00022 00023 TypeHandle RecorderController::_type_handle; 00024 RecorderController::RecorderFactory *RecorderController::_factory = NULL; 00025 00026 //////////////////////////////////////////////////////////////////// 00027 // Function: RecorderController::Constructor 00028 // Access: Published 00029 // Description: 00030 //////////////////////////////////////////////////////////////////// 00031 RecorderController:: 00032 RecorderController() { 00033 _clock_offset = 0.0; 00034 _frame_offset = 0; 00035 _writer = (BamWriter *)NULL; 00036 _reader = (BamReader *)NULL; 00037 _frame_tie = true; 00038 _user_table = new RecorderTable; 00039 _user_table_modified = false; 00040 _file_table = NULL; 00041 _active_table = NULL; 00042 _eof = false; 00043 } 00044 00045 //////////////////////////////////////////////////////////////////// 00046 // Function: RecorderController::Destructor 00047 // Access: Published 00048 // Description: 00049 //////////////////////////////////////////////////////////////////// 00050 RecorderController:: 00051 ~RecorderController() { 00052 close(); 00053 delete _user_table; 00054 } 00055 00056 //////////////////////////////////////////////////////////////////// 00057 // Function: RecorderController::begin_record 00058 // Access: Published 00059 // Description: Begins recording data to the indicated filename. All 00060 // of the recorders in use should already have been 00061 // added. 00062 //////////////////////////////////////////////////////////////////// 00063 bool RecorderController:: 00064 begin_record(const Filename &filename) { 00065 close(); 00066 _filename = filename; 00067 ClockObject *global_clock = ClockObject::get_global_clock(); 00068 _clock_offset = global_clock->get_frame_time(); 00069 _frame_offset = global_clock->get_frame_count(); 00070 00071 time(&_header._start_time); 00072 00073 if (!_dout.open(_filename)) { 00074 recorder_cat.error() << "Unable to open " << _filename << "\n"; 00075 return false; 00076 } 00077 00078 if (!_dout.write_header(_bam_header)) { 00079 recorder_cat.error() << "Unable to write to " << _filename << "\n"; 00080 return false; 00081 } 00082 00083 _writer = new BamWriter(&_dout); 00084 00085 if (!_writer->init()) { 00086 close(); 00087 return false; 00088 } 00089 00090 // Write out the header information. 00091 _writer->write_object(&_header); 00092 00093 _user_table_modified = true; 00094 00095 // Tell all of our recorders that they're live now. 00096 RecorderTable::Recorders::iterator ri; 00097 for (ri = _user_table->_recorders.begin(); 00098 ri != _user_table->_recorders.end(); 00099 ++ri) { 00100 RecorderBase *recorder = (*ri).second; 00101 recorder->_flags |= RecorderBase::F_recording; 00102 } 00103 00104 recorder_cat.info() 00105 << "Recording session to " << _filename << "\n"; 00106 00107 return true; 00108 } 00109 00110 //////////////////////////////////////////////////////////////////// 00111 // Function: RecorderController::begin_playback 00112 // Access: Published 00113 // Description: Begins playing back data from the indicated filename. 00114 // All of the recorders in use should already have been 00115 // added, although this may define additional recorders 00116 // if they are present in the file (these new recorders 00117 // will not be used). This may also undefine recorders 00118 // that were previously added but are not present in the 00119 // file. 00120 //////////////////////////////////////////////////////////////////// 00121 bool RecorderController:: 00122 begin_playback(const Filename &filename) { 00123 close(); 00124 _filename = filename; 00125 ClockObject *global_clock = ClockObject::get_global_clock(); 00126 _clock_offset = global_clock->get_frame_time(); 00127 _frame_offset = global_clock->get_frame_count(); 00128 00129 if (!_din.open(_filename)) { 00130 recorder_cat.error() << "Unable to open " << _filename << "\n"; 00131 return false; 00132 } 00133 00134 string head; 00135 if (!_din.read_header(head, _bam_header.size()) || head != _bam_header) { 00136 recorder_cat.error() << "Unable to read " << _filename << "\n"; 00137 return false; 00138 } 00139 00140 _reader = new BamReader(&_din); 00141 if (!_reader->init()) { 00142 close(); 00143 return false; 00144 } 00145 00146 _user_table_modified = true; 00147 _active_table = new RecorderTable; 00148 _eof = false; 00149 00150 // Start out by reading the RecorderHeader. 00151 TypedWritable *object = _reader->read_object(); 00152 00153 if (object == (TypedWritable *)NULL || 00154 !object->is_of_type(RecorderHeader::get_class_type())) { 00155 recorder_cat.error() 00156 << _filename << " does not contain a recorded session.\n"; 00157 close(); 00158 return false; 00159 } 00160 00161 if (!_reader->resolve()) { 00162 recorder_cat.warning() 00163 << "Unable to resolve header data.\n"; 00164 } 00165 00166 RecorderHeader *new_header = DCAST(RecorderHeader, object); 00167 _header = (*new_header); 00168 delete new_header; 00169 00170 // Now read the first frame. 00171 _next_frame = read_frame(); 00172 if (_next_frame == (RecorderFrame *)NULL) { 00173 recorder_cat.error() 00174 << _filename << " does not contain any frames.\n"; 00175 close(); 00176 return false; 00177 } 00178 00179 recorder_cat.info() 00180 << "Playing back session from " << _filename << "\n"; 00181 00182 return true; 00183 } 00184 00185 //////////////////////////////////////////////////////////////////// 00186 // Function: RecorderController::close 00187 // Access: Published 00188 // Description: Finishes recording data to the indicated filename. 00189 //////////////////////////////////////////////////////////////////// 00190 void RecorderController:: 00191 close() { 00192 if (_writer != (BamWriter *)NULL) { 00193 delete _writer; 00194 _writer = NULL; 00195 00196 // Tell all of our recorders that they're no longer recording. 00197 RecorderTable::Recorders::iterator ri; 00198 for (ri = _user_table->_recorders.begin(); 00199 ri != _user_table->_recorders.end(); 00200 ++ri) { 00201 RecorderBase *recorder = (*ri).second; 00202 recorder->_flags &= ~RecorderBase::F_recording; 00203 } 00204 } 00205 if (_reader != (BamReader *)NULL) { 00206 delete _reader; 00207 _reader = NULL; 00208 00209 // Tell all of our recorders that they're no longer playing. 00210 RecorderTable::Recorders::iterator ri; 00211 for (ri = _active_table->_recorders.begin(); 00212 ri != _active_table->_recorders.end(); 00213 ++ri) { 00214 RecorderBase *recorder = (*ri).second; 00215 recorder->_flags &= ~RecorderBase::F_playing; 00216 } 00217 } 00218 _dout.close(); 00219 _din.close(); 00220 00221 if (_file_table != (RecorderTable *)NULL) { 00222 delete _file_table; 00223 _file_table = (RecorderTable *)NULL; 00224 } 00225 00226 if (_active_table != (RecorderTable *)NULL) { 00227 delete _active_table; 00228 _active_table = (RecorderTable *)NULL; 00229 } 00230 } 00231 00232 //////////////////////////////////////////////////////////////////// 00233 // Function: RecorderController::record_frame 00234 // Access: Published 00235 // Description: Gets the next frame of data from all of the active 00236 // recorders and adds it to the output file. 00237 //////////////////////////////////////////////////////////////////// 00238 void RecorderController:: 00239 record_frame() { 00240 if (is_recording()) { 00241 ClockObject *global_clock = ClockObject::get_global_clock(); 00242 double now = global_clock->get_frame_time() - _clock_offset; 00243 int frame = global_clock->get_frame_count() - _frame_offset; 00244 00245 RecorderFrame data(now, frame, _user_table_modified, _user_table); 00246 _user_table_modified = false; 00247 00248 _writer->write_object(&data); 00249 } 00250 } 00251 00252 //////////////////////////////////////////////////////////////////// 00253 // Function: RecorderController::play_frame 00254 // Access: Published 00255 // Description: Gets the next frame of data from all of the active 00256 // recorders and adds it to the output file. 00257 //////////////////////////////////////////////////////////////////// 00258 void RecorderController:: 00259 play_frame() { 00260 if (is_playing()) { 00261 if (_eof) { 00262 close(); 00263 return; 00264 } 00265 00266 ClockObject *global_clock = ClockObject::get_global_clock(); 00267 double now = global_clock->get_frame_time() - _clock_offset; 00268 int frame = global_clock->get_frame_count() - _frame_offset; 00269 00270 while (_next_frame != (RecorderFrame *)NULL) { 00271 if (_frame_tie) { 00272 if (frame < _next_frame->_frame) { 00273 // We haven't reached the next frame yet. 00274 return; 00275 } 00276 00277 // Insist that the clock runs at the same rate as it did in 00278 // the previous session. 00279 //global_clock->set_frame_time(_next_frame->_timestamp + _clock_offset); 00280 //global_clock->set_real_time(_next_frame->_timestamp + _clock_offset); 00281 00282 // Hmm, that's crummy. Just keep the clock offset up-to-date. 00283 _clock_offset = global_clock->get_frame_time() - _next_frame->_timestamp; 00284 00285 } else { 00286 if (now < _next_frame->_timestamp) { 00287 // We haven't reached the next frame yet. 00288 return; 00289 } 00290 00291 // Keep our frame_offset up-to-date. 00292 _frame_offset = global_clock->get_frame_count() - _next_frame->_frame; 00293 } 00294 00295 if (_next_frame->_table_changed && _file_table != _next_frame->_table) { 00296 delete _file_table; 00297 _file_table = _next_frame->_table; 00298 } 00299 00300 if (_next_frame->_table_changed || _user_table_modified) { 00301 // We're about to change the active table. Temporarily 00302 // disable the playing flag on the currently-active recorders. 00303 RecorderTable::Recorders::iterator ri; 00304 for (ri = _active_table->_recorders.begin(); 00305 ri != _active_table->_recorders.end(); 00306 ++ri) { 00307 RecorderBase *recorder = (*ri).second; 00308 recorder->_flags &= ~RecorderBase::F_playing; 00309 } 00310 00311 delete _active_table; 00312 _active_table = new RecorderTable(*_file_table); 00313 _active_table->merge_from(*_user_table); 00314 _user_table_modified = false; 00315 00316 // Now reenable the playing flag on the newly-active 00317 // recorders. 00318 for (ri = _active_table->_recorders.begin(); 00319 ri != _active_table->_recorders.end(); 00320 ++ri) { 00321 RecorderBase *recorder = (*ri).second; 00322 recorder->_flags |= RecorderBase::F_playing; 00323 } 00324 } 00325 00326 _next_frame->_table = _active_table; 00327 _next_frame->play_frame(_reader); 00328 00329 delete _next_frame; 00330 _next_frame = read_frame(); 00331 } 00332 00333 if (_reader->is_eof()) { 00334 recorder_cat.info() 00335 << "End of recorded session.\n"; 00336 } else { 00337 recorder_cat.error() 00338 << "Unable to read datagram from recorded session.\n"; 00339 } 00340 _eof = true; 00341 } 00342 } 00343 00344 00345 //////////////////////////////////////////////////////////////////// 00346 // Function: RecorderController::read_frame 00347 // Access: Private 00348 // Description: Loads the next frame data from the playback session 00349 // file. Returns the frame data pointer on success, or 00350 // NULL on failure. 00351 //////////////////////////////////////////////////////////////////// 00352 RecorderFrame *RecorderController:: 00353 read_frame() { 00354 TypedWritable *object = _reader->read_object(); 00355 00356 if (object == (TypedWritable *)NULL || 00357 !object->is_of_type(RecorderFrame::get_class_type())) { 00358 return NULL; 00359 } 00360 00361 if (!_reader->resolve()) { 00362 recorder_cat.warning() 00363 << "Unable to resolve frame data.\n"; 00364 } 00365 00366 return DCAST(RecorderFrame, object); 00367 }