Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

player.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2002 Xavier Trochu
00003 
00004 This software is provided 'as-is', without any express or implied warranty. In no event
00005 will the authors be held liable for any damages arising from the use of this software.
00006 
00007 Permission is granted to anyone to use this software for any purpose, including commercial
00008 applications, and to alter it and redistribute it freely, subject to the following
00009 restrictions:
00010 
00011 1. The origin of this software must not be misrepresented; you must not claim that you
00012    wrote the original software. If you use this software in a product, an acknowledgment
00013    in the product documentation would be appreciated but is not required.
00014 
00015 2. Altered source versions must be plainly marked as such, and must not be misrepresented 
00016    as being the original software.
00017 
00018 3. This notice may not be removed or altered from any source distribution.
00019 */
00020 #include <sstream>
00021 #include <fstream>
00022 #include <stdexcept>
00023 
00024 #include "player.h"
00025 
00026 #include "renderer.h"
00027 #include "channel.h"
00028 #include "chunck_type.h"
00029 #include "rect.h"
00030 #include "blitter.h"
00031 #include "endian.h"
00032 
00033 #ifdef DEBUG
00034 #include <iomanip>
00035 #include <iostream>
00036 #endif
00037 
00038 const int WAIT = 100;
00039 
00040 using namespace std;
00041 
00049 class string_resource {
00050 private:
00051     map<int, string> _strings;  
00052 public:
00060     bool init(char * buffer, int length) throw(exception) {
00061         string str(buffer, length);
00062         string::size_type i = str.find('#');
00063         while(i != string::npos) {
00064             string::size_type j = str.find('\n', i) + 1;
00065             assert(j != string::npos);
00066             string::size_type m = j - 2;
00067             while((str[m] == '\r') || (str[m] == '\n') || (str[m] == ' ') || (str[m] == '\t')) m--;
00068             //~ cout << static_cast<int>(str[m]) << " == " << str[m] << endl;
00069             string::size_type k = str.rfind(' ', m);
00070             string::size_type l = str.rfind('\t', m);
00071             if(l != string::npos && k < l) k = l;
00072             assert(k != string::npos); 
00073             m++; k++;
00074             //~ cout << "k == " << k << ", m == " << m << ", str == " << string(str, k, m-k) << endl;
00075             istringstream iss(string(str, k, m-k));
00076             int id;
00077             iss >> id;
00078             k = str.find('\n', j) - 1;
00079             if(str[j] == '/') j += 2;
00080             string value = string(str, j, k-j);
00081 #ifdef DEBUG
00082             cout << "Inserting " << id << " == \"" << value << "\"" << endl;
00083 #endif              
00084             _strings.insert(make_pair(id, value));
00085             i = str.find('#', k);
00086         }
00087         return true;
00088     }
00095     const string & get(int id) const throw(exception) {
00096         map<int, string>::const_iterator i = _strings.find(id);
00097         if(i == _strings.end()) 
00098             throw(runtime_error("invalid string id"));
00099         return i->second;
00100     }
00101 };
00102 
00103 void player::show(const std::string & p) {
00104     if(p == "subtitles")
00105         _subtitles = true;
00106     else if(p == "bgmusic")
00107         _bgmusic = true;
00108     else if(p == "voices")
00109         _voices = true;
00110     else {
00111         istringstream iss(p);
00112         int id = -1;
00113         iss >> id;
00114         if(id < 0 || id > 36) throw runtime_error("invalid parameter to show");
00115         _skips.insert(make_pair(id, true));
00116     }
00117 }
00118 
00119 void player::hide(const std::string & p) {
00120     if(p == "subtitles")
00121         _subtitles = false;
00122     else if(p == "bgmusic")
00123         _bgmusic = false;
00124     else if(p == "voices")
00125         _voices = false;
00126     else {
00127         istringstream iss(p);
00128         int id = -1;
00129         iss >> id;
00130         if(id < 0 || id > 36) throw runtime_error("invalid parameter to show");
00131         _skips.insert(make_pair(id, false));
00132     }
00133 }
00134 
00135 
00136 player::player(renderer * renderer, bool wait, bool sound) throw() : 
00137                             _version(-1), 
00138                             _secondary_version(0),
00139                             _sound_frequency(0),
00140                             _nbframes(0), 
00141                             _renderer(renderer), 
00142                             _strings(0),
00143                             _frame_size(-1, -1), 
00144                             _frame(0),
00145                             _output_sound(sound),
00146                             _wait(wait),
00147                             _already_init(false),
00148                             _codec37_called(false),
00149                             _skipnext(false),
00150                             _subtitles(true),
00151                             _bgmusic(true),
00152                             _voices(true)
00153 {
00154     _fr[0] = _fr[1] = _fr[2] = _fr[3] = 0;
00155     assert(_renderer != 0);
00156 }
00157 
00158 player::~player() throw() { 
00159     clean(); 
00160 }
00161 
00162 void player::update_palette(void) { 
00163     _renderer->set_palette(_pal); 
00164 }
00165 
00166 void player::clean() throw() {
00167     if(_strings) delete _strings;
00168     if(_fr[0]) delete _fr[0];
00169     if(_fr[1]) delete _fr[1];
00170     if(_fr[2]) delete _fr[2];
00171     if(_fr[3]) delete _fr[3];
00172 }
00173 
00174 void player::checkBlock(const chunck & b, chunck::type type_expected, unsigned int min_size) {
00175 #ifdef DEBUG
00176     //~ cout << "checkBlock(" << chunck::chunck_string(b.get_type()) << ", " << b.get_size() << ")" << endl;
00177 #endif      
00178     if(type_expected != b.get_type()) {
00179         ostringstream oss;
00180         oss << "chunck type is different from expected : " << b.get_type() << " != " << type_expected;
00181         throw runtime_error(oss.str());
00182     }
00183     if(min_size > b.get_size()) {
00184         ostringstream oss;
00185         oss << "chunck size is inferior than minimum required size : " << b.get_size() << " < " << min_size;
00186         throw runtime_error(oss.str());
00187     }
00188 }
00189 
00190 void player::handleSoundBuffer(int track_id, int index, int max_frames, int flags, int vol, int bal, chunck & b, int size) throw(exception) {
00191     if(!_voices && (flags & 128) == 128) return;
00192     if(!_bgmusic && (flags & 64) == 64) return;
00193     channel * c = _mixer.find_channel(track_id);
00194     if(c == 0) {
00195         c = new saud_channel(track_id,  _mixer.get_frequency());
00196         _mixer.add_channel(track_id, c);
00197     }
00198     if(index == 0)
00199         c->set_parameters(max_frames, flags, vol, bal);
00200     else
00201         c->check_parameters(index, max_frames, flags, vol, bal);
00202     c->append_data(b, size);
00203 }
00204 
00205 void player::handleSoundFrame(chunck & b) throw(exception) { 
00206 #ifdef DEBUG
00207     cout << "handleSoundFrame()" << endl; 
00208 #endif
00209     checkBlock(b, TYPE_PSAD);
00210     if(!_output_sound) return;
00211     int track_id = b.get_word();
00212     int index = b.get_word();
00213     int max_frames = b.get_word();
00214     int flags = b.get_word();
00215     int vol = b.get_byte();
00216     int bal = b.get_char();
00217 #ifdef DEBUG
00218     //~ cout << "track_id == " << track_id << ", index == " << index << ", max_frames == " << max_frames << ", " << flags << ", " << vol << ", " << bal << endl;
00219     if(index == 0) { // What is thig flag about ??
00220         cout << "track_id == " << track_id << ", max_frames == " << max_frames << ", " << flags << ", " << vol << ", " << bal << endl;
00221     }
00222 #endif
00223     int size = b.get_size() - 10;
00224     handleSoundBuffer(track_id, index, max_frames, flags, vol, bal, b, size);
00225 }
00226 
00227 void player::handleSkip(chunck & b) throw(exception) { 
00228     checkBlock(b, TYPE_SKIP, 4);
00229     int code = b.get_dword();
00230 #ifdef DEBUG
00231     cout << "handleSkip(" << code << ")" << endl;
00232 #endif
00233     map<int, bool>::iterator i = _skips.find(code);
00234     if(i != _skips.end())
00235         _skipnext = i->second;
00236     else
00237         _skipnext =true;
00238 }
00239 
00240 void player::handleStore(chunck & b) throw(exception) { 
00241 #ifdef DEBUG
00242     cerr << "handleStore()" << endl; 
00243     //~ int i = 0;
00244     //~ while(!b.eof()) {
00245         //~ int code = b.get_byte();
00246         //~ cout << "STOR DATA " << i << " == " << code << endl;
00247         //~ i++;
00248     //~ }
00249 #endif
00250     checkBlock(b, TYPE_STOR, 4);
00251     
00252 }
00253 
00254 void player::handleFetch(chunck & b) throw(exception) { 
00255 #ifdef DEBUG
00256     cerr << "handleFetch()" << endl; 
00257     //~ int i = 0;
00258     //~ while(!b.eof()) {
00259         //~ int code = b.get_byte();
00260         //~ cout << "FTCH DATA " << i << " == " << code << endl;
00261         //~ i++;
00262     //~ }
00263 #endif
00264     checkBlock(b, TYPE_FTCH, 6); 
00265 }
00266 
00267 void player::handleImuseBuffer(int track_id, int index, int nbframes, int size, int unk1, int unk2, chunck & b, int bsize) throw(exception) { 
00268     channel * c = _mixer.find_channel(track_id);
00269     if(c == 0) {
00270         c = new imuse_channel(track_id, _mixer.get_frequency());
00271         _mixer.add_channel(track_id, c);
00272     }
00273     if(index == 0)
00274         c->set_parameters(nbframes, size, unk1, unk2);
00275     else
00276         c->check_parameters(index, nbframes, size, unk1, unk2);
00277     c->append_data(b, bsize);
00278 }
00279 
00280 void player::handleImuseAction8(chunck & b, int flags, int unknown, int track_id) throw(exception) {
00281     assert(flags == 46 && unknown == 0);
00282     int unknown2 = b.get_word();
00283     track_id |= unknown2 << 16;
00284     int index = b.get_word();
00285     int nbframes = b.get_word();
00286     int size = b.get_dword();
00287 #ifdef DEBUG
00288     cout << "handleImuseAction8() : " << unknown2 << ", " << index << "/" << nbframes << " == " << size << endl; 
00289 #endif
00290     int bsize = b.get_size() - 18;
00291     handleImuseBuffer(track_id, index, nbframes, size, unknown, unknown2, b, bsize);
00292 }
00293 
00294 void player::handleImuseAction(chunck & b) throw(exception) { 
00295     checkBlock(b, TYPE_IACT, 8);
00296     if(!_output_sound) return;
00297     int code = b.get_word();
00298     int flags = b.get_word();
00299     int unknown = b.get_short();
00300     int track_id = b.get_word();
00301 #ifdef DEBUG
00302     cout << "handleImuseAction(" << code << "," << flags << "," << unknown << "," << track_id << ")" << endl;
00303 #endif
00304     switch(code) {
00305         case 8:
00306             handleImuseAction8(b, flags, unknown, track_id);
00307             break;
00308 #ifdef DEBUG
00309         default:
00310             //~ cerr << "unknown IACT code : " << code << ", IACT size == " << b.get_size() << endl;
00311             //~ cout << "unknown IACT code : " << code << ", IACT size == " << b.get_size() << endl;
00312             {
00313                 cerr  << setw(5) << track_id << " " << code << " " << setw(8) << flags << " " << setw(4) << unknown << " : ";
00314                 int i = 1;
00315                 while(!b.eof()) {
00316                     int value = b.get_byte();
00317                     cerr << setw(3) << value << " ";
00318                     if(i++ == 80) { i = 0; cerr << endl; }
00319                 }
00320                 if(i) cerr << endl;
00321             }
00322 #endif
00323     }
00324 }
00325 
00326 //~ #include <iostream>
00327 
00328 void player::handleTextResource(chunck & b) throw(exception) { 
00329 #ifdef DEBUG
00330     cout << "handleTextResource()" << endl; 
00331 #endif
00332     checkBlock(b, TYPE_TRES, 18); 
00333     assert(_strings);
00334     int pos_x = b.get_short();
00335     int pos_y = b.get_short();
00336     int flags = b.get_short();
00337     int left = b.get_short();
00338     int top = b.get_short();
00339     int width = b.get_short();
00340     int height = b.get_short();
00341     int unk2 = b.get_word();
00342     int string_id = b.get_word();
00343     string str = _strings->get(string_id);
00344 #ifdef DEBUG
00345     //~ cerr << "TRES : " << _subtitles << ", " <<  flags << ", " << left << ", " << top << ", " << width << ", " << height << ", " << unk2 << " : " << str << endl;
00346 #else
00347     height = height;
00348     unk2 = unk2;
00349 #endif
00350     if((!_subtitles) && ((flags & 8) == 8)) return;
00351     font_renderer * fr = _fr[0];
00352     int color = 15;
00353     while(str[0] == '^') {
00354         switch(str[1]) {
00355         case 'f':
00356             {
00357                 istringstream iss(string(str, 2, 2));
00358                 int id = 0;
00359                 iss >> id;
00360                 str = string(str, 4); 
00361                 fr = _fr[id]; 
00362             } break;
00363         case 'c':
00364             {
00365                 istringstream iss(string(str, 2, 3));
00366                 iss >> color;
00367                 str = string(str, 5); 
00368             } break;
00369         default:
00370             throw runtime_error("invalid escape code in text string");
00371         }
00372     }
00373     fr->set_color(color);
00374     // if subtitles disabled and bit 3 is set, then do not draw
00375     if(!_cur_buffer) { _cur_buffer = _renderer->lock_frame(_frame); }
00376     if(flags == 0 || flags == 4)
00377         fr->draw_string_absolute(str, _cur_buffer, _frame_size, pos_x, pos_y);
00378     else 
00379         fr->draw_string_centered(str, _cur_buffer, _frame_size, max(pos_y, top), left, width, pos_x);
00380 }
00381 
00382 void player::readPalette(palette & out, chunck & in) throw(exception) {
00383     unsigned char buffer[768];
00384     in.read(buffer, 768);
00385     out = palette(buffer);
00386 }
00387 
00388 void player::handleDeltaPalette(chunck & b) throw(exception) { 
00389 #ifdef DEBUG_DELTA_PALETTE
00390     cout << "handleDeltaPalette()" << endl; 
00391 #endif
00392     checkBlock(b, TYPE_XPAL);
00393     if(b.get_size() == 768*3+4) {
00394         int unk1, num;
00395         unk1 = b.get_word();
00396         num = b.get_word();
00397         for(int i = 0; i < 768; i++)
00398         {
00399             _delta_pal[i] = b.get_word();
00400         }
00401         readPalette(_pal, b);
00402         update_palette();
00403 #ifdef DEBUG_DELTA_PALETTE
00404         cout << "DELTA PALETTE : unk1 == " << unk1 << ", num == " << num << endl;
00405         for(int i = 0; i < 256; i++)
00406         {
00407             cout << "deltapal[" << i << "] == " << _delta_pal[3*i] << ", " << _delta_pal[3*i+1] << ", " << _delta_pal[3*i+2] << endl;
00408         }
00409         cout << "palette == " << _pal << endl;
00410 #endif
00411     } else if(b.get_size() == 6) {
00412         int unk1, num, unk2;
00413         unk1 = b.get_word();
00414         num = b.get_word();
00415         unk2 = b.get_word();
00416 #ifdef DEBUG_DELTA_PALETTE
00417         cout << "DELTA PALETTE : unk1 == " << unk1 << ", num == " << num << ", unk2 == " << unk2 << endl;
00418 #endif
00419         for(int i = 0; i < 256; i++)
00420         {
00421             _pal[i].delta(_delta_pal+3*i);
00422         }
00423         update_palette();
00424     } else {
00425         throw runtime_error("wrong size for DeltaPalette");
00426     }
00427 }
00428 
00429 void player::handleNewPalette(chunck & b) throw(exception) { 
00430 #ifdef DEBUG
00431     cout << "handleNewPalette()" << endl; 
00432 #endif
00433     checkBlock(b, TYPE_NPAL, 768);
00434     readPalette(_pal, b);
00435     update_palette();
00436 }
00437 
00438 void player::decodeCodec(chunck & b, const rect & r, decoder & codec) throw(exception) {
00439     assert(_cur_buffer);
00440     try {
00441         blitter blit(_cur_buffer, _frame_size, r);
00442         codec.decode(blit, b);
00443     } catch(const exception & e) {
00444 #ifdef DEBUG
00445         cerr << "Exception occured during decodeCodec : " << e.what() << endl;
00446 #endif
00447     }
00448 }
00449 
00450 void player::init_size(const rect & r, bool always, bool transparent) throw(exception)
00451 {
00452     if(_codec37_called) _already_init = true;
00453         
00454     if(!_already_init || _frame_size.get_x() < r.right() || _frame_size.get_y() < r.bottom() || always) {
00455         if(_cur_buffer) { _renderer->unlock_frame(); _cur_buffer = 0; }
00456         _frame_size = r.bottomright();
00457         _renderer->init_frame(_frame_size);
00458     }
00459     if(_cur_buffer) { _renderer->unlock_frame(); _cur_buffer = 0; }
00460     _cur_buffer = _renderer->lock_frame(_frame);
00461     if(!_already_init && transparent) {
00462 #ifdef DEBUG
00463         cout << "clearing buffer" << endl;
00464 #endif  
00465         memset(_cur_buffer, 0, _frame_size.get_x()*_frame_size.get_y());
00466     }
00467     _codec1.init_size(_frame_size, r);
00468     _codec37.init_size(_frame_size, r);
00469     _codec44.init_size(_frame_size, r);
00470     _already_init = true;
00471 }
00472 
00473 void player::handleFrameObject(chunck & b) throw(exception) { 
00474 #ifdef DEBUG
00475     cout << "handleFrameObject()" << endl; 
00476 #endif
00477     checkBlock(b, TYPE_FOBJ, 14);
00478     if(_skipnext) {
00479         _skipnext = false;
00480         return;
00481     }
00482     int codec = b.get_word();
00483     unsigned short left = b.get_word();
00484     unsigned short top = b.get_word();
00485     unsigned short width = b.get_word();
00486     unsigned short height = b.get_word();
00487     rect r(left, top, left+width, top+height);
00488     unsigned short data[2];
00489     data[1] = b.get_word();
00490     data[0] = b.get_word();
00491 #ifdef DEBUG
00492     cout << "Frame pos : " << left << ", " << top << endl;
00493     cout << "Frame size : " << width << "x" << height << endl;
00494     cout << "Codec : " << codec << endl;
00495     for(int i = 0; i < 2; i++)
00496         if(data[i] != 0) {
00497             cout << "FRAMEOBJECT:data[" << i << "] == " << data[i] << endl;
00498             cerr << "FRAMEOBJECT:data[" << i << "] == " << data[i] << endl;
00499         }
00500 #endif
00501     switch (codec) {
00502     case 3:
00503     case 1:
00504         init_size(r, false, true);
00505         decodeCodec(b, r, _codec1);
00506         break;
00507     case 37:
00508         assert(left == 0 && top == 0);
00509         init_size(r, true, false);
00510         decodeCodec(b, r, _codec37);
00511         _codec37_called = true;
00512         break;
00513     case 21:
00514     case 44:
00515         init_size(r, true, true);
00516         decodeCodec(b, r, _codec44);
00517         break;
00518     default:
00519         ostringstream oss;
00520         oss << "Invalid codec for frame object : " << static_cast<int>(codec);
00521         throw runtime_error(oss.str());
00522     }
00523     //~ _renderer->save_current();
00524 }
00525 
00526 
00527 void player::handleFrame(chunck & b) throw(exception) {
00528 #ifdef DEBUG
00529     cout << "handleFrame(" << _frame << ")" << endl; 
00530 #endif
00531     checkBlock(b, TYPE_FRME);
00532     _already_init = false;
00533     _skipnext = false;
00534     
00535     while(!b.eof()) {
00536         chunck * sub = b.sub_block();
00537         if(sub->get_size() & 1) b.seek(1);
00538         switch(sub->get_type()) {
00539             case TYPE_NPAL:
00540                 handleNewPalette(*sub);
00541                 break;
00542             case TYPE_FOBJ:
00543                 handleFrameObject(*sub);
00544                 break;
00545             case TYPE_PSAD:
00546                 handleSoundFrame(*sub);
00547                 break;
00548             case TYPE_TRES:
00549                 handleTextResource(*sub);
00550                 break;
00551             case TYPE_XPAL:
00552                 handleDeltaPalette(*sub);
00553                 break;
00554             case TYPE_IACT:
00555                 handleImuseAction(*sub);
00556                 break;
00557             case TYPE_STOR:
00558                 handleStore(*sub);
00559                 break;
00560             case TYPE_FTCH:
00561                 handleFetch(*sub);
00562                 break;
00563             case TYPE_SKIP:
00564                 handleSkip(*sub);
00565                 break;
00566             default:
00567                 ostringstream oss;
00568                 oss << "Unknown frame subchunck found : " << chunck::chunck_string(sub->get_type()) << ", " << sub->get_size();
00569                 throw runtime_error(oss.str());
00570         }
00571         delete sub;
00572     }
00573     if(_cur_buffer) { _renderer->unlock_frame(); _cur_buffer = 0; }
00574     if(_output_sound) _mixer.handle_frame();
00575 #ifdef DEBUG
00576     //~ cout << "Frame() terminated" << endl; 
00577     cout << "=========================================================" << endl; 
00578 #endif
00579     _renderer->flip_frame();
00580     if(_wait) _renderer->wait(WAIT);
00581     _frame++;
00582 }
00583 
00584 void player::handleAnimHeader(chunck & b) throw(exception) {
00585 #ifdef DEBUG
00586     cout << "handleAnimHeader()" << endl; 
00587 #endif
00588     checkBlock(b, TYPE_AHDR, 774); 
00589     _version = b.get_word();
00590     _nbframes = b.get_word();
00591     int unknown = b.get_word();
00592 #ifdef DEBUG
00593     cout << "HEADER : version == " << _version << ", nbframes == " << _nbframes << ", unknown == " << unknown << endl;
00594 #else
00595     unknown = unknown;
00596 #endif
00597     _renderer->start_decode(_fname, _version, _nbframes);
00598     readPalette(_pal, b);
00599     update_palette();
00600     if(_version == 1) {
00601         _sound_frequency = 22050;
00602     }
00603     if(_version == 2) {
00604         _secondary_version = b.get_dword();
00605         int unknown2 = b.get_dword();
00606         _sound_frequency = b.get_dword();
00607 #ifdef DEBUG
00608         cout << "HEADER : secondary version == " << _secondary_version << ", unknown2 == " << unknown2 << ", sound frequency == " << _sound_frequency << endl;
00609         int i = 0, c;
00610         while(!b.eof()) {
00611             c = b.get_byte();
00612             //~ cout << "HEADER : remaining bytes : " << i << " == " << c << endl;
00613             if(c) cerr << "HEADER : remaining bytes : " << i << " == " << c << endl;
00614             i++;
00615         }
00616 #else
00617         unknown2 = unknown2;
00618 #endif
00619         if(_secondary_version != 10 && _secondary_version != 0 && _secondary_version != 12 && _secondary_version != 15 && _secondary_version != 14)
00620             throw runtime_error("Wrong secondary version number for SMUSH animation");
00621         if(_sound_frequency != 0 && _sound_frequency != 11025 && _sound_frequency != 22050)
00622             throw runtime_error("Wrong _sound_frequency number for SMUSH animation");
00623     }else if(_version > 2) {
00624         throw runtime_error("Wrong primary version number for SMUSH animation");
00625     }
00626     if(_output_sound && _sound_frequency) {
00627         if(_sound_frequency != 22050) _sound_frequency = 22050;
00628         sound_renderer * sr = _renderer->get_sound_renderer();
00629         if(sr) {
00630             _mixer.init(sr, _sound_frequency, 1000 / WAIT);
00631         } else {
00632             _output_sound = false;
00633         }
00634     }
00635 }
00636 
00637 string_resource * get_strings(const string & file, bool is_encoded) {
00638     ifstream is;
00639     is.exceptions(ifstream::badbit);
00640     is.open (file.c_str(), ios::binary);
00641     if(is.fail()) return 0;
00642     is.seekg (0, ios::end);
00643     ifstream::pos_type length = is.tellg();
00644     is.seekg (0, ios::beg);
00645     char * filebuffer = new char [length];
00646     assert(filebuffer);
00647     is.read (filebuffer,length);
00648     is.close();
00649     if(is_encoded) {
00650         chunck::type type = from_big_endian(*reinterpret_cast<unsigned int *>(filebuffer));
00651         if(type != TYPE_ETRS) throw runtime_error("invalid type for file"); // mem leak !!!
00652         char * old = filebuffer;
00653         filebuffer = new char[static_cast<int>(length) - 8];
00654         for(int i = 8; i < length; i++)
00655             filebuffer[i-8] = old[i] ^ 0xCC;
00656         delete []old;
00657         length -= 8;
00658     }
00659     string_resource * sr = new string_resource;
00660     assert(sr);
00661     try {
00662         sr->init(filebuffer, length);
00663     } catch(exception & e) {
00664         delete sr;
00665         sr = 0;
00666     }
00667     delete []filebuffer;
00668     return sr;
00669 }
00670 
00671 bool player::read_string(const string & file) throw(exception) {
00672 #ifdef DEBUG
00673     cout << "player::read_string(" << file << ")" << endl;
00674 #endif
00675     string::size_type i = file.rfind('.');
00676     if(i == string::npos) throw(runtime_error("invalid filename"));
00677     string fname = string(file, 0, i) + ".TRS";
00678     if((_strings = get_strings(fname, false)) != 0)
00679         return true;
00680     i = file.rfind('\\');
00681     if(i == string::npos) i = file.rfind('/');
00682     if(i == string::npos) throw(runtime_error("invalid filename"));
00683     fname = string(file, 0, i+1) + "MINEROAD.TRS";
00684     if((_strings = get_strings(fname, false)) != 0)
00685         return true;
00686     fname = string(file, 0, i+1) + "DIGTXT.TRS";
00687     if((_strings = get_strings(fname, true)) != 0)
00688         return false;
00689     return true;
00690 }
00691 
00692 namespace {
00693     font_renderer * load_font(const string & file, bool original = false) {
00694 #ifdef DEBUG
00695         cout << "loading font from \"" << file << "\"" << endl;
00696 #endif
00697         font_renderer * fr = new font_renderer(original);
00698         player p(fr, false, false);
00699         p.play(file.c_str());
00700         return fr;
00701     }
00702 }
00703 
00704 bool player::play(const string & file) throw(exception) {
00705     string::size_type i = file.rfind('\\');
00706     if(i == string::npos)
00707     {
00708         i = file.rfind('/');
00709     } else {
00710         string::size_type j = file.rfind('/', i);
00711         if(j != string::npos)
00712             i = j;
00713     }
00714     string directory;
00715     if(i != string::npos) {
00716         directory = string(file, 0, i);
00717         _fname = string(file, i+1);
00718     } else {
00719         directory = "";
00720         _fname = string(file);
00721     }
00722     clean();
00723     
00724     bool is_fullthrottle = true;
00725     try {
00726         is_fullthrottle = read_string(file);
00727     } catch(exception & e) {
00728 #ifdef DEBUG
00729         cerr << "read_string() returned an exception : " << e.what();
00730 #endif
00731     }
00732     if(_strings) {
00733         if(is_fullthrottle) {
00734             if(directory == "") {
00735                 directory == "../DATA/";
00736             } else {
00737                 string::size_type i = directory.rfind('\\');
00738                 if(i == string::npos) i = directory.rfind('/');
00739                 if(i == string::npos) {
00740                     directory = "DATA/";
00741                 } else {
00742                     directory = string(directory, 0, i) + "/DATA/";
00743                 }
00744             }
00745             _fr[0] = load_font(directory + "SCUMMFNT.NUT", true);
00746             _fr[2] = load_font(directory + "TITLFNT.NUT", true);
00747         } else {
00748             for(int i = 0; i < 4; i++) {
00749                 ostringstream oss;
00750                 oss << directory << "/FONT" << i << ".NUT";
00751                 _fr[i] = load_font(oss.str());
00752             }
00753         }
00754     }
00755     
00756     file_chunck base = file_chunck(file);
00757     
00758     checkBlock(base, TYPE_ANIM); 
00759     
00760     while(!base.eof()) {
00761         chunck * sub = base.sub_block();
00762         switch(sub->get_type()) {
00763             case TYPE_AHDR:
00764                 handleAnimHeader(*sub);
00765                 break;
00766             case TYPE_FRME:
00767                 handleFrame(*sub);
00768                 break;
00769             default:
00770                 ostringstream oss;
00771                 oss << "Unknown chunck found : " << sub->get_type() << ", " << sub->get_size();
00772                 throw runtime_error(oss.str());
00773         }
00774         delete sub;
00775     }
00776     if(_output_sound) {
00777         _mixer.stop();
00778     }
00779     return true;
00780 }

Generated on Fri Aug 9 22:54:29 2002 for san_player by doxygen1.2.16