diff options
| author | James Brown | 2004-01-17 14:20:32 +0000 | 
|---|---|---|
| committer | James Brown | 2004-01-17 14:20:32 +0000 | 
| commit | 04f2bc0276aa10f083ed1fca64b2da705311ae67 (patch) | |
| tree | 93f1afd0dd73eee871f906ad1492feec65afaeff | |
| parent | ccd5f0842fbc540dda21dbefd6dab34da804107b (diff) | |
| download | scummvm-rg350-04f2bc0276aa10f083ed1fca64b2da705311ae67.tar.gz scummvm-rg350-04f2bc0276aa10f083ed1fca64b2da705311ae67.tar.bz2 scummvm-rg350-04f2bc0276aa10f083ed1fca64b2da705311ae67.zip | |
Update BS2 cutscene player with changes from roever: overlay support (default, 8bit backends should define BACKEND_8BIT for fast colour remapping) and sound syncronisation.
svn-id: r12456
| -rw-r--r-- | sound/audiostream.h | 13 | ||||
| -rw-r--r-- | sound/vorbis.cpp | 7 | ||||
| -rw-r--r-- | sword2/driver/animation.cpp | 168 | ||||
| -rw-r--r-- | sword2/driver/animation.h | 46 | ||||
| -rw-r--r-- | sword2/driver/d_draw.h | 5 | ||||
| -rw-r--r-- | sword2/driver/render.cpp | 3 | 
6 files changed, 201 insertions, 41 deletions
| diff --git a/sound/audiostream.h b/sound/audiostream.h index 97822c0c26..0dde9a61b5 100644 --- a/sound/audiostream.h +++ b/sound/audiostream.h @@ -74,6 +74,19 @@ public:  	/** Sample rate of the stream. */  	virtual int getRate() const = 0; + +	/** +	 * This function returns the number of samples that were delivered to +	 * the mixer which is a rough estimate of how moch time of the stream +	 * has been played. +	 * The exact value is not available as it needs information from the +	 * audio device on how many samples have been already played +	 * As our buffer is relatively short the estimate is exact enough +	 * The return -1 is kind of a hack as this function is only required +	 * for the video audio sync in the bs2 cutscenes I am to lazy to +	 * implement it for all subclasses +	 */ +	virtual int getSamplesPlayed() const { return -1; }  };  class AppendableAudioStream : public AudioStream { diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp index 9a4904e5ad..99600f8747 100644 --- a/sound/vorbis.cpp +++ b/sound/vorbis.cpp @@ -172,6 +172,7 @@ class VorbisInputStream : public AudioStream {  	int16 _buffer[4096];  	const int16 *_bufferEnd;  	const int16 *_pos; +	int _played;  	void refill();  	inline bool eosIntern() const; @@ -184,6 +185,8 @@ public:  	bool isStereo() const		{ return _numChannels >= 2; }  	int getRate() const			{ return ov_info(_ov_file, -1)->rate; } +	int getSamplesPlayed() const { return _played / _numChannels; } +  }; @@ -193,7 +196,7 @@ public:  VorbisInputStream::VorbisInputStream(OggVorbis_File *file, int duration)  -	: _ov_file(file), _bufferEnd(_buffer + ARRAYSIZE(_buffer)) { +	: _ov_file(file), _bufferEnd(_buffer + ARRAYSIZE(_buffer)), _played(0) {  	// Check the header, determine if this is a stereo stream  	_numChannels = ov_info(_ov_file, -1)->channels; @@ -215,6 +218,7 @@ inline int16 VorbisInputStream::read() {  	if (_pos >= _bufferEnd) {  		refill();  	} +	_played++;  	return sample;  } @@ -234,6 +238,7 @@ int VorbisInputStream::readBuffer(int16 *buffer, const int numSamples) {  			refill();  		}  	} +	_played += samples;  	return samples;  } diff --git a/sword2/driver/animation.cpp b/sword2/driver/animation.cpp index 4c621692ba..5d37f3fdbf 100644 --- a/sword2/driver/animation.cpp +++ b/sword2/driver/animation.cpp @@ -27,6 +27,8 @@  #include "common/file.h" +#include "sound/vorbis.h" +  namespace Sword2 {  AnimationState::AnimationState(Sword2Engine *vm) @@ -39,7 +41,11 @@ AnimationState::~AnimationState() {  	if (decoder)  		mpeg2_close(decoder);  	delete mpgfile; -	delete sndfile; +        delete sndfile; +#ifndef BACKEND_8BIT +        _vm->_system->hide_overlay(); +        delete overlay; +#endif  #endif  } @@ -47,15 +53,19 @@ bool AnimationState::init(const char *name) {  #ifdef USE_MPEG2  	char basename[512], tempFile[512]; -  	int i, p;  	decoder = NULL;  	mpgfile = NULL;  	sndfile = NULL; +        bgSoundStream = NULL;  	strcpy(basename, name);  	basename[strlen(basename) - 4] = 0;	// FIXME: hack to remove extension +#ifdef BACKEND_8BIT + +        int i, p; +  	// Load lookup palettes  	// TODO: Binary format so we can use File class  	sprintf(tempFile, "%s/%s.pal", _vm->getGameDataPath(), basename); @@ -71,10 +81,10 @@ bool AnimationState::init(const char *name) {  		if (fscanf(f, "%i %i", &palettes[p].end, &palettes[p].cnt) != 2)  			break;  		for (i = 0; i < palettes[p].cnt; i++) { -  			int r, g, b; -  			fscanf(f, "%i", &r); -  			fscanf(f, "%i", &g); -  			fscanf(f, "%i", &b); +			int r, g, b; +			fscanf(f, "%i", &r); +			fscanf(f, "%i", &g); +			fscanf(f, "%i", &b);  			palettes[p].pal[4 * i] = r;  			palettes[p].pal[4 * i + 1] = g;  			palettes[p].pal[4 * i + 2] = b; @@ -98,6 +108,12 @@ bool AnimationState::init(const char *name) {  	cr = 0;  	buildLookup(palnum, 256);  	lut2 = lookup[1]; +	lutcalcnum = (BITDEPTH + palettes[palnum].end + 2) / (palettes[palnum].end + 2); +#else +	buildLookup2(); +	overlay = (NewGuiColor*)calloc(640 * 400, sizeof(NewGuiColor)); +	_vm->_system->show_overlay(); +#endif  	// Open MPEG2 stream  	mpgfile = new File(); @@ -117,9 +133,6 @@ bool AnimationState::init(const char *name) {  	info = mpeg2_info(decoder);  	framenum = 0; -	// Load in palette data -	lutcalcnum = (BITDEPTH + palettes[palnum].end + 2) / (palettes[palnum].end + 2); -  	/* Play audio - TODO: Sync with video?*/  #ifdef USE_VORBIS @@ -128,8 +141,11 @@ bool AnimationState::init(const char *name) {  	// there?  	sndfile = new File;  	sprintf(tempFile, "%s.ogg", basename); -	if (sndfile->open(tempFile)) -		_vm->_mixer->playVorbis(&bgSound, sndfile, 100000000);	// FIXME: this size value is bogus +	if (sndfile->open(tempFile)) { +		bgSoundStream = makeVorbisStream(sndfile, sndfile->size()); +		_vm->_mixer->playInputStream(&bgSound, bgSoundStream, false, 255, 0, -1); +	} +  #endif  	return true; @@ -138,6 +154,8 @@ bool AnimationState::init(const char *name) {  #endif  } + +#ifdef BACKEND_8BIT  /**   * Build 'Best-Match' RGB lookup table   */ @@ -188,7 +206,7 @@ void AnimationState::buildLookup(int p, int lines) {  	}  } -void AnimationState::checkPaletteSwitch() { +bool AnimationState::checkPaletteSwitch() {  	// if we have reached the last image with this palette, switch to new one  	if (framenum == palettes[palnum].end) {  		unsigned char *l = lut2; @@ -197,9 +215,78 @@ void AnimationState::checkPaletteSwitch() {  		lutcalcnum = (BITDEPTH + palettes[palnum].end - (framenum + 1) + 2) / (palettes[palnum].end - (framenum + 1) + 2);  		lut2 = lut;  		lut = l; +		return true; +	} + +	return false; +} + + +#else + +bool AnimationState::lookupInit = false; +NewGuiColor AnimationState::lookup2[BITDEPTH * BITDEPTH * 256]; + +void AnimationState::buildLookup2() { + +	if (lookupInit) return; +	lookupInit = true; + +	int y, cb, cr; +	int r, g, b; +	int pos = 0; + +	for (cr = 0; cr < BITDEPTH; cr++) { +		for (cb = 0; cb < BITDEPTH; cb++) { +			for (y = 0; y < 256; y++) { +				r = ((y-16) * 256 + (int) (256 * 1.596) * ((cr << SHIFT) - 128)) / 256; +				g = ((y-16) * 256 - (int) (0.813 * 256) * ((cr << SHIFT) - 128) - (int) (0.391 * 256) * ((cb << SHIFT) - 128)) / 256; +				b = ((y-16) * 256 + (int) (2.018 * 256) * ((cb << SHIFT) - 128)) / 256; + +				if (r < 0) r = 0; +				if (r > 255) r = 255; +				if (g < 0) g = 0; +				if (g > 255) g = 255; +				if (b < 0) b = 0; +				if (b > 255) b = 255; + +				lookup2[pos++] = _vm->_system->RGBToColor(r, g, b); +			} +		}  	}  } + +void AnimationState::plotYUV(NewGuiColor *lut, int width, int height, byte *const *dat) { + +	NewGuiColor *ptr = overlay + (400-height)/2 * 640 + (640-width)/2; + +	int x, y; + +	int ypos = 0; +	int cpos = 0; +	int linepos = 0; + +	for (y = 0; y < height; y += 2) { +		for (x = 0; x < width; x += 2) { +			int i = ((((dat[2][cpos] + ROUNDADD) >> SHIFT) * BITDEPTH) + ((dat[1][cpos] + ROUNDADD)>>SHIFT)) * 256; +			cpos++; + +			ptr[linepos               ] = lut[i + dat[0][        ypos  ]]; +			ptr[RENDERWIDE + linepos++] = lut[i + dat[0][width + ypos++]]; +			ptr[linepos               ] = lut[i + dat[0][        ypos  ]]; +			ptr[RENDERWIDE + linepos++] = lut[i + dat[0][width + ypos++]]; + +                } +		linepos += (2 * 640 - width); +		ypos += width; +	} + +	_vm->_system->copy_rect_overlay(overlay, 640, 0, 40, 640, 400); +} + +#endif +  bool AnimationState::decodeFrame() {  #ifdef USE_MPEG2  	mpeg2_state_t state; @@ -219,12 +306,47 @@ bool AnimationState::decodeFrame() {  		case STATE_SLICE:  		case STATE_END:  			if (info->display_fbuf) { -				checkPaletteSwitch(); -				_vm->_graphics->plotYUV(lut, sequence_i->width, sequence_i->height, info->display_fbuf->buf); -				framenum++; +				/* simple audio video sync code: +				 * we calculate the actual frame by taking the delivered audio samples +				 * we add 2 frames as the number of samples delivered is higher than the +				 * number actually played due to buffering +				 * +				 * we then try to stay inside +- 1 frame of this calculated frame number by +				 * dropping frames if we run behind and delaying if we are too fast +				 */ + +#ifdef BACKEND_8BIT +				if (checkPaletteSwitch() || +                                    (bgSoundStream->getSamplesPlayed()*12/bgSoundStream->getRate()) < (framenum+3)){ +					_vm->_graphics->plotYUV(lut, sequence_i->width, sequence_i->height, info->display_fbuf->buf); + +					while ((bgSoundStream->getSamplesPlayed()*12/bgSoundStream->getRate()) < framenum+1); +						_vm->_system->delay_msecs(10); + +					_vm->_graphics->setNeedFullRedraw(); + +				} else +					printf("dropped frame %i\n", framenum); +  				buildLookup(palnum + 1, lutcalcnum); + +#else + +				if ((bgSoundStream->getSamplesPlayed()*12/bgSoundStream->getRate()) < (framenum+3)){ +					plotYUV(lookup2, sequence_i->width, sequence_i->height, info->display_fbuf->buf); + +					while ((bgSoundStream->getSamplesPlayed()*12/bgSoundStream->getRate()) < framenum+1); +						_vm->_system->delay_msecs(10); + +				} else +					printf("dropped frame %i\n", framenum); + +#endif + +				framenum++;  				return true; -			} + +                        }  			break;  		default: @@ -264,7 +386,7 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu  	int frameCounter = 0, textCounter = 0;  	PlayingSoundHandle handle;  	bool skipCutscene = false, textVisible = false; -	uint32 flags = SoundMixer::FLAG_16BITS, ticks = _vm->_system->get_msecs() + 83; +	uint32 flags = SoundMixer::FLAG_16BITS;  	uint8 oldPal[1024];  	memcpy(oldPal, _vm->_graphics->_palCopy, 1024); @@ -285,7 +407,6 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu  #endif  	while (anim->decodeFrame()) { -		_vm->_graphics->setNeedFullRedraw();  		if (text && text[textCounter]) {                        			if (frameCounter == text[textCounter]->startFrame) { @@ -307,7 +428,11 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu  		frameCounter++; +#ifdef BACKEND_8BIT  		_vm->_graphics->updateDisplay(true); +#else +		_vm->_graphics->updateDisplay(false); +#endif  		KeyboardEvent ke; @@ -317,13 +442,6 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu  			break;  		} -		// Simulate ~12 frames per second. I don't know what -		// frame rate the original movies had, or even if it -		// was constant, but this seems to work reasonably. - -		_vm->sleepUntil(ticks); -		ticks += 82; -  	}  	// Wait for the voice to stop playing. This is to make sure diff --git a/sword2/driver/animation.h b/sword2/driver/animation.h index 9016ce89a5..cc2b896f11 100644 --- a/sword2/driver/animation.h +++ b/sword2/driver/animation.h @@ -52,9 +52,14 @@ typedef sequence_t mpeg2_sequence_t;  namespace Sword2 { -#define SQR(x) ((x) * (x)) +#ifdef BACKEND_8BIT +#define SQR(x) ((x) * (x))  #define SHIFT 3 +#else +#define SHIFT 1 +#endif +  #define BITDEPTH (1 << (8 - SHIFT))  #define ROUNDADD (1 << (SHIFT - 1)) @@ -64,14 +69,6 @@ class AnimationState {  private:  	Sword2Engine *_vm; -	int palnum; -	int maxPalnum; - -	byte lookup[2][BITDEPTH * BITDEPTH * BITDEPTH]; -	byte *lut; -	byte *lut2; -	int lutcalcnum; -  	int framenum;  #ifdef USE_MPEG2 @@ -82,6 +79,20 @@ private:  	File *mpgfile;  	File *sndfile; +	byte buffer[BUFFER_SIZE]; + +	PlayingSoundHandle bgSound; +	AudioStream *bgSoundStream; + +#ifdef BACKEND_8BIT +	int palnum; +	int maxPalnum; + +	byte lookup[2][BITDEPTH * BITDEPTH * BITDEPTH]; +	byte *lut; +	byte *lut2; +	int lutcalcnum; +  	int curpal;  	int cr;  	int pos; @@ -91,12 +102,15 @@ private:  		int end;  		byte pal[4 * 256];  	} palettes[50]; +#else +        static NewGuiColor lookup2[BITDEPTH * BITDEPTH * 256]; +        NewGuiColor * overlay; +        static bool lookupInit; -	byte buffer[BUFFER_SIZE]; - -	PlayingSoundHandle bgSound; +#endif  public: +  	AnimationState(Sword2Engine *vm);  	~AnimationState(); @@ -104,8 +118,14 @@ public:  	bool decodeFrame();  private: + +#ifdef BACKEND_8BIT  	void buildLookup(int p, int lines); -	void checkPaletteSwitch(); +	bool checkPaletteSwitch(); +#else +	void buildLookup2(void); +	void plotYUV(NewGuiColor *lut, int width, int height, byte *const *dat); +#endif  };  class MoviePlayer { diff --git a/sword2/driver/d_draw.h b/sword2/driver/d_draw.h index a442f2d220..c40bc0e0af 100644 --- a/sword2/driver/d_draw.h +++ b/sword2/driver/d_draw.h @@ -225,7 +225,10 @@ public:  	void plotPoint(uint16 x, uint16 y, uint8 colour);  	void drawLine(int16 x1, int16 y1, int16 x2, int16 y2, uint8 colour); -	void plotYUV(byte *lut, int width, int height, uint8 *const *buf); +#ifdef BACKEND_8BIT +	void plotYUV(byte *lut, int width, int height, byte *const *dat); +#endif +  	int32 createSurface(SpriteInfo *s, uint8 **surface);  	void drawSurface(SpriteInfo *s, uint8 *surface, Common::Rect *clipRect = NULL); diff --git a/sword2/driver/render.cpp b/sword2/driver/render.cpp index fed1e0ed28..4674aa80fd 100644 --- a/sword2/driver/render.cpp +++ b/sword2/driver/render.cpp @@ -828,7 +828,7 @@ void Graphics::closeBackgroundLayer(void) {  	_layer = 0;  } - +#ifdef BACKEND_8BIT  void Graphics::plotYUV(byte *lut, int width, int height, byte *const *dat) {  	byte *buf = _buffer + (40 + (400 - height) / 2) * RENDERWIDE + (640 - width) / 2; @@ -852,6 +852,7 @@ void Graphics::plotYUV(byte *lut, int width, int height, byte *const *dat) {  		ypos += width;  	}  } +#endif  } // End of namespace Sword2 | 
