1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include "common/endian.h"
27 #include "common/system.h"
29 #include "graphics/dither.h"
30 #include "graphics/video/coktelvideo/coktelvideo.h"
31 #include "graphics/video/coktelvideo/indeo3.h"
43 uint32
Imd::getFeatures() const {
47 uint16
Imd::getFlags() const {
51 int16
Imd::getX() const {
55 int16
Imd::getY() const {
59 int16
Imd::getWidth() const {
63 int16
Imd::getHeight() const {
67 uint16
Imd::getFramesCount() const {
71 uint16
Imd::getCurrentFrame() const {
75 int16
Imd::getFrameRate() const {
79 return 1000 / (_soundSliceLength
>> 16);
82 uint32
Imd::getSyncLag() const {
86 const byte
*Imd::getPalette() const {
90 bool Imd::getFrameCoords(int16 frame
,
91 int16
&x
, int16
&y
, int16
&width
, int16
&height
) {
96 bool Imd::hasExtraData(const char *fileName
) const {
100 Common::MemoryReadStream
*Imd::getExtraData(const char *fileName
) {
104 bool Imd::loadCoordinates() {
105 // Standard coordinates
107 _stdX
= _stream
->readUint16LE();
109 warning("IMD: More than one standard coordinate quad found (%d)", _stdX
);
113 _stdX
= _stream
->readSint16LE();
114 _stdY
= _stream
->readSint16LE();
115 _stdWidth
= _stream
->readSint16LE();
116 _stdHeight
= _stream
->readSint16LE();
117 _features
|= kFeaturesStdCoords
;
126 bool Imd::loadFrameTableOffsets(uint32
&framesPosPos
, uint32
&framesCoordsPos
) {
132 framesPosPos
= _stream
->readUint32LE();
133 if (framesPosPos
!= 0) {
134 _framesPos
= new uint32
[_framesCount
];
136 _features
|= kFeaturesFramesPos
;
141 if (_features
& kFeaturesFrameCoords
)
142 framesCoordsPos
= _stream
->readUint32LE();
147 bool Imd::assessVideoProperties() {
148 // Sizes of the frame data and extra video buffer
149 if (_features
& kFeaturesDataSize
) {
150 _frameDataSize
= _stream
->readUint16LE();
151 if (_frameDataSize
== 0) {
152 _frameDataSize
= _stream
->readUint32LE();
153 _vidBufferSize
= _stream
->readUint32LE();
155 _vidBufferSize
= _stream
->readUint16LE();
157 _frameDataSize
= _width
* _height
+ 500;
158 if (!(_flags
& 0x100) || (_flags
& 0x1000))
159 _vidBufferSize
= _frameDataSize
;
162 // Allocating working memory
163 _frameData
= new byte
[_frameDataSize
+ 500];
165 memset(_frameData
, 0, _frameDataSize
+ 500);
166 _vidBuffer
= new byte
[_vidBufferSize
+ 500];
168 memset(_vidBuffer
, 0, _vidBufferSize
+ 500);
173 bool Imd::assessAudioProperties() {
174 if (_features
& kFeaturesSound
) {
175 _soundFreq
= _stream
->readSint16LE();
176 _soundSliceSize
= _stream
->readSint16LE();
177 _soundSlicesCount
= _stream
->readSint16LE();
180 _soundFreq
= -_soundFreq
;
182 if (_soundSlicesCount
< 0)
183 _soundSlicesCount
= -_soundSlicesCount
- 1;
185 if (_soundSlicesCount
> 40) {
186 warning("Imd::load(): More than 40 sound slices found (%d)", _soundSlicesCount
);
190 _soundSliceLength
= (uint32
) (((double) (1000 << 16)) /
191 ((double) _soundFreq
/ (double) _soundSliceSize
));
192 _frameLength
= _soundSliceLength
>> 16;
197 _audioStream
= Audio::makeAppendableAudioStream(_soundFreq
, 0);
199 _frameLength
= 1000 / _frameRate
;
204 bool Imd::loadFrameTables(uint32 framesPosPos
, uint32 framesCoordsPos
) {
207 _stream
->seek(framesPosPos
, SEEK_SET
);
208 for (int i
= 0; i
< _framesCount
; i
++)
209 _framesPos
[i
] = _stream
->readUint32LE();
213 if (_features
& kFeaturesFrameCoords
) {
214 _stream
->seek(framesCoordsPos
, SEEK_SET
);
215 _frameCoords
= new Coord
[_framesCount
];
216 assert(_frameCoords
);
217 for (int i
= 0; i
< _framesCount
; i
++) {
218 _frameCoords
[i
].left
= _stream
->readSint16LE();
219 _frameCoords
[i
].top
= _stream
->readSint16LE();
220 _frameCoords
[i
].right
= _stream
->readSint16LE();
221 _frameCoords
[i
].bottom
= _stream
->readSint16LE();
228 bool Imd::load(Common::SeekableReadStream
&stream
) {
235 handle
= _stream
->readUint16LE();
236 _version
= _stream
->readByte();
239 if ((handle
!= 0) || (_version
< 2)) {
240 warning("Imd::load(): Version incorrect (%d,%X)", handle
, _version
);
246 _features
= _stream
->readByte();
247 _framesCount
= _stream
->readUint16LE();
248 _x
= _stream
->readSint16LE();
249 _y
= _stream
->readSint16LE();
250 _width
= _stream
->readSint16LE();
251 _height
= _stream
->readSint16LE();
252 _flags
= _stream
->readUint16LE();
253 _firstFramePos
= _stream
->readUint16LE();
255 // IMDs always have video
256 _features
|= kFeaturesVideo
;
257 // IMDs always have palettes
258 _features
|= kFeaturesPalette
;
261 _stream
->read((byte
*) _palette
, 768);
263 if (!loadCoordinates()) {
268 uint32 framesPosPos
, frameCoordsPos
;
269 if (!loadFrameTableOffsets(framesPosPos
, frameCoordsPos
)) {
274 if (!assessAudioProperties()) {
279 if (!assessVideoProperties()) {
284 if (!loadFrameTables(framesPosPos
, frameCoordsPos
)) {
289 // Seek to the first frame
290 _stream
->seek(_firstFramePos
, SEEK_SET
);
299 void Imd::setFrameRate(int16 frameRate
) {
303 _frameRate
= frameRate
;
304 _frameLength
= 1000 / _frameRate
;
307 void Imd::setXY(int16 x
, int16 y
) {
308 // Adjusting the standard coordinates
311 _stdX
= _stdX
- _x
+ x
;
313 _stdY
= _stdY
- _y
+ y
;
316 // Going through the coordinate table as well
318 for (int i
= 0; i
< _framesCount
; i
++) {
319 if (_frameCoords
[i
].left
!= -1) {
321 _frameCoords
[i
].left
= _frameCoords
[i
].left
- _x
+ x
;
322 _frameCoords
[i
].right
= _frameCoords
[i
].right
- _x
+ x
;
325 _frameCoords
[i
].top
= _frameCoords
[i
].top
- _y
+ y
;
326 _frameCoords
[i
].bottom
= _frameCoords
[i
].bottom
- _y
+ y
;
338 void Imd::setVideoMemory(byte
*vidMem
, uint16 width
, uint16 height
) {
341 _hasOwnVidMem
= false;
343 _vidMemWidth
= width
;
344 _vidMemHeight
= height
;
347 void Imd::setVideoMemory() {
350 if ((_width
> 0) && (_height
> 0)) {
352 _hasOwnVidMem
= true;
353 _vidMem
= new byte
[_width
* _height
];
354 _vidMemWidth
= _width
;
355 _vidMemHeight
= _height
;
357 memset(_vidMem
, 0, _width
* _height
);
361 void Imd::setDoubleMode(bool doubleMode
) {
364 void Imd::enableSound(Audio::Mixer
&mixer
) {
365 // Only possible on the first frame
370 _soundEnabled
= true;
373 void Imd::disableSound() {
376 if (_soundStage
== 2) {
377 _audioStream
->finish();
378 _mixer
->stopHandle(_audioHandle
);
385 _soundEnabled
= false;
389 bool Imd::isSoundPlaying() const {
390 if (_audioStream
&& _mixer
->isSoundHandleActive(_audioHandle
))
396 void Imd::seekFrame(int32 frame
, int16 whence
, bool restart
) {
401 // Find the frame to which to seek
402 if (whence
== SEEK_CUR
)
404 else if (whence
== SEEK_END
)
405 frame
= _framesCount
- frame
- 1;
406 else if (whence
!= SEEK_SET
)
409 if ((frame
< 0) || (frame
>= _framesCount
) || (frame
== _curFrame
))
413 // Try every possible way to find a file offset to that frame
416 framePos
= _firstFramePos
;
417 } else if (frame
== 1) {
418 framePos
= _firstFramePos
;
419 _stream
->seek(framePos
, SEEK_SET
);
420 framePos
+= _stream
->readUint16LE() + 4;
421 } else if (_framesPos
) {
422 framePos
= _framesPos
[frame
];
423 } else if (restart
&& (_soundStage
== 0)) {
424 for (int i
= ((frame
> _curFrame
) ? _curFrame
: 0); i
<= frame
; i
++)
428 error("Imd::seekFrame(): Frame %d is not directly accessible", frame
);
431 _stream
->seek(framePos
);
435 CoktelVideo::State
Imd::nextFrame() {
436 return processFrame(_curFrame
);
439 void Imd::waitEndFrame() {
440 if (_soundEnabled
&& _hasSound
) {;
441 if (_soundStage
!= 2)
444 if (_skipFrames
== 0) {
445 int32 waitTime
= (int16
) (((_curFrame
* _soundSliceLength
) -
446 (_mixer
->getSoundElapsedTime(_audioHandle
) << 16)) >> 16);
449 _skipFrames
= -waitTime
/ (_soundSliceLength
>> 16);
450 warning("Video A/V sync broken, skipping %d frame(s)", _skipFrames
+ 1);
451 } else if (waitTime
> 0)
452 g_system
->delayMillis(waitTime
);
457 g_system
->delayMillis(_frameLength
);
460 void Imd::copyCurrentFrame(byte
*dest
,
461 uint16 left
, uint16 top
, uint16 width
, uint16 height
,
462 uint16 x
, uint16 y
, uint16 pitch
, int16 transp
) {
467 if (((left
+ width
) > _width
) || ((top
+ height
) > _height
))
471 byte
*vidMem
= _vidMem
+ _width
* top
;
475 if ((x
> 0) || (left
> 0) || (pitch
!= _width
) || (width
!= _width
)) {
477 for (int i
= 0; i
< height
; i
++) {
479 byte
*s
= vidMem
+ left
;
487 // Dimensions fit, copy everything at once
488 memcpy(dest
, vidMem
, width
* height
);
493 for (int i
= 0; i
< height
; i
++) {
495 byte
*s
= vidMem
+ left
;
497 for (int j
= 0; j
< width
; j
++) {
511 void Imd::deleteVidMem(bool del
) {
517 _hasOwnVidMem
= false;
523 void Imd::clear(bool del
) {
526 delete[] _frameCoords
;
539 _x
= _y
= _width
= _height
= 0;
540 _stdX
= _stdY
= _stdWidth
= _stdHeight
= 0;
542 _framesCount
= _curFrame
= 0;
548 _frameDataSize
= _vidBufferSize
= 0;
549 _frameData
= _vidBuffer
= 0;
552 memset(_palette
, 0, 768);
557 _soundEnabled
= false;
564 _soundSlicesCount
= 0;
565 _soundSliceLength
= 0;
573 void Imd::nextSoundSlice(bool hasNextCmd
) {
574 if (hasNextCmd
|| !_soundEnabled
) {
575 _stream
->seek(_soundSliceSize
, SEEK_CUR
);
579 byte
*soundBuf
= new byte
[_soundSliceSize
];
581 _stream
->read(soundBuf
, _soundSliceSize
);
582 unsignedToSigned(soundBuf
, _soundSliceSize
);
584 _audioStream
->queueBuffer(soundBuf
, _soundSliceSize
);
587 bool Imd::initialSoundSlice(bool hasNextCmd
) {
588 int dataLength
= _soundSliceSize
* _soundSlicesCount
;
590 if (hasNextCmd
|| !_soundEnabled
) {
591 _stream
->seek(dataLength
, SEEK_CUR
);
595 byte
*soundBuf
= new byte
[dataLength
];
597 _stream
->read(soundBuf
, dataLength
);
598 unsignedToSigned(soundBuf
, dataLength
);
600 _audioStream
->queueBuffer(soundBuf
, dataLength
);
602 return _soundStage
== 1;
605 void Imd::emptySoundSlice(bool hasNextCmd
) {
606 if (hasNextCmd
|| !_soundEnabled
)
609 byte
*soundBuf
= new byte
[_soundSliceSize
];
611 memset(soundBuf
, 0, _soundSliceSize
);
613 _audioStream
->queueBuffer(soundBuf
, _soundSliceSize
);
616 void Imd::videoData(uint32 size
, State
&state
) {
617 _stream
->read(_frameData
, size
);
618 _frameDataLen
= size
;
620 if (_vidMemWidth
<= state
.right
) {
622 state
.right
-= state
.left
;
624 if (_vidMemWidth
<= state
.right
)
625 state
.right
= _vidMemWidth
- 1;
626 if (_vidMemHeight
<= state
.bottom
) {
628 state
.bottom
-= state
.top
;
630 if (_vidMemHeight
<= state
.bottom
)
631 state
.bottom
= _vidMemHeight
-1;
633 state
.flags
|= renderFrame(state
.left
, state
.top
, state
.right
, state
.bottom
);
634 state
.flags
|= _frameData
[0];
637 void Imd::calcFrameCoords(uint16 frame
, State
&state
) {
641 state
.right
= _stdWidth
+ state
.left
- 1;
642 state
.bottom
= _stdHeight
+ state
.top
- 1;
643 state
.flags
|= kStateStdCoords
;
646 (_frameCoords
[frame
].left
!= -1)) {
647 state
.left
= _frameCoords
[frame
].left
;
648 state
.top
= _frameCoords
[frame
].top
;
649 state
.right
= _frameCoords
[frame
].right
;
650 state
.bottom
= _frameCoords
[frame
].bottom
;
651 state
.flags
|= kStateFrameCoords
;
655 CoktelVideo::State
Imd::processFrame(uint16 frame
) {
658 bool hasNextCmd
= false;
659 bool startSound
= false;
661 if (!_stream
|| (frame
>= _framesCount
)) {
662 state
.flags
= kStateBreak
;
666 if (frame
!= _curFrame
) {
667 state
.flags
|= kStateSeeked
;
676 state
.right
= _width
+ state
.left
- 1;
677 state
.bottom
= _height
+ state
.top
- 1;
681 calcFrameCoords(frame
, state
);
683 cmd
= _stream
->readUint16LE();
685 if ((cmd
& kCommandBreakMask
) == kCommandBreak
) {
688 if (cmd
== kCommandBreak
) {
689 _stream
->seek(2, SEEK_CUR
);
690 cmd
= _stream
->readUint16LE();
694 if (cmd
== kCommandBreakSkip0
) {
695 state
.flags
= kStateBreak
;
697 } else if (cmd
== kCommandBreakSkip16
) {
698 cmd
= _stream
->readUint16LE();
699 _stream
->seek(cmd
, SEEK_CUR
);
700 state
.flags
= kStateBreak
;
702 } else if (cmd
== kCommandBreakSkip32
) {
703 cmd
= _stream
->readUint32LE();
704 _stream
->seek(cmd
, SEEK_CUR
);
705 state
.flags
= kStateBreak
;
711 if (_soundStage
!= 0) {
712 if (cmd
== kCommandNextSound
) {
714 nextSoundSlice(hasNextCmd
);
715 cmd
= _stream
->readUint16LE();
717 } else if (cmd
== kCommandStartSound
) {
719 startSound
= initialSoundSlice(hasNextCmd
);
720 cmd
= _stream
->readUint16LE();
723 emptySoundSlice(hasNextCmd
);
727 if (cmd
== kCommandPalette
) {
728 _stream
->seek(2, SEEK_CUR
);
729 state
.flags
|= kStatePalette
;
731 _stream
->read(_palette
, 768);
732 cmd
= _stream
->readUint16LE();
737 if (cmd
== kCommandJump
) {
740 frame
= _stream
->readSint16LE();
743 _stream
->seek(_framesPos
[frame
], SEEK_SET
);
746 state
.flags
|= kStateJump
;
749 } else if (cmd
== kCommandVideoData
) {
750 uint32 size
= _stream
->readUint32LE() + 2;
752 videoData(size
, state
);
756 } else if (cmd
!= 0) {
757 uint32 size
= cmd
+ 2;
759 videoData(size
, state
);
762 state
.flags
|= kStateNoVideoData
;
764 } while (hasNextCmd
);
766 if (startSound
&& _soundEnabled
) {
767 _mixer
->playInputStream(Audio::Mixer::kSFXSoundType
, &_audioHandle
, _audioStream
);
773 if ((_curFrame
== _framesCount
) && (_soundStage
== 2)) {
774 _audioStream
->finish();
775 _mixer
->stopHandle(_audioHandle
);
780 _lastFrameTime
= g_system
->getMillis();
784 // A whole, completely filled block
785 void Imd::renderBlockWhole(byte
*dest
, const byte
*src
, int16 width
, int16 height
,
786 int16 destWidth
, int16 destHeight
) {
788 int16 w
= MIN(width
, destWidth
);
789 int16 h
= MIN(height
, destHeight
);
791 for (int i
= 0; i
< h
; i
++) {
792 memcpy(dest
, src
, w
);
799 // A quarter-wide whole, completely filled block
800 void Imd::renderBlockWhole4X(byte
*dest
, const byte
*src
, int16 width
, int16 height
,
801 int16 destWidth
, int16 destHeight
) {
803 for (int i
= 0; i
< height
; i
++) {
804 byte
*destBak
= dest
;
806 for (int j
= 0; j
< width
; j
+= 4, dest
+= 4, src
++)
807 memset(dest
, *src
, 4);
809 dest
= destBak
+ destWidth
;
813 // A half-high whole, completely filled block
814 void Imd::renderBlockWhole2Y(byte
*dest
, const byte
*src
, int16 width
, int16 height
,
815 int16 destWidth
, int16 destHeight
) {
818 memcpy(dest
, src
, width
);
819 memcpy(dest
+ destWidth
, src
, width
);
822 dest
+= 2 * destWidth
;
827 memcpy(dest
, src
, width
);
831 void Imd::renderBlockSparse(byte
*dest
, const byte
*src
, int16 width
, int16 height
,
832 int16 destWidth
, int16 destHeight
) {
834 for (int i
= 0; i
< height
; i
++) {
835 byte
*destBak
= dest
;
836 uint16 pixWritten
= 0;
838 while (pixWritten
< width
) {
839 uint16 pixCount
= *src
++;
841 if (pixCount
& 0x80) { // Data
842 pixCount
= MIN((pixCount
& 0x7F) + 1, width
- pixWritten
);
843 memcpy(dest
, src
, pixCount
);
845 pixWritten
+= pixCount
;
849 pixWritten
+= pixCount
+ 1;
850 dest
+= pixCount
+ 1;
855 dest
= destBak
+ destWidth
;
859 // A half-high sparse block
860 void Imd::renderBlockSparse2Y(byte
*dest
, const byte
*src
, int16 width
, int16 height
,
861 int16 destWidth
, int16 destHeight
) {
863 for (int i
= 0; i
< height
; i
+= 2) {
864 byte
*destBak
= dest
;
865 uint16 pixWritten
= 0;
867 while (pixWritten
< width
) {
868 uint16 pixCount
= *src
++;
870 if (pixCount
& 0x80) { // Data
871 pixCount
= MIN((pixCount
& 0x7F) + 1, width
- pixWritten
);
872 memcpy(dest
, src
, pixCount
);
873 memcpy(dest
+ destWidth
, src
, pixCount
);
875 pixWritten
+= pixCount
;
879 pixWritten
+= pixCount
+ 1;
880 dest
+= pixCount
+ 1;
885 dest
= destBak
+ destWidth
;
889 uint32
Imd::renderFrame(int16 left
, int16 top
, int16 right
, int16 bottom
) {
890 if (!_frameData
|| !_vidMem
|| (_width
<= 0) || (_height
<= 0))
895 int16 width
= right
- left
+ 1;
896 int16 height
= bottom
- top
+ 1;
897 int16 sW
= _vidMemWidth
;
898 int16 sH
= _vidMemHeight
;
900 byte
*dataPtr
= _frameData
;
901 byte
*imdVidMem
= _vidMem
+ sW
* top
+ left
;
904 uint8 type
= *dataPtr
++;
906 if (type
& 0x10) { // Palette data
908 int index
= *dataPtr
++;
909 // 16 entries with each 3 bytes (RGB)
910 memcpy(_palette
+ index
* 3, dataPtr
, MIN((255 - index
) * 3, 48));
912 retVal
= kStatePalette
;
920 // Frame data is compressed
924 if ((type
== 2) && (width
== sW
)) {
925 // Directly uncompress onto the video surface
926 deLZ77(imdVidMem
, dataPtr
);
929 deLZ77(srcPtr
, dataPtr
);
932 // Evaluate the block type
934 renderBlockSparse (imdVidMem
, srcPtr
, width
, height
, sW
, sH
);
935 else if (type
== 0x02)
936 renderBlockWhole (imdVidMem
, srcPtr
, width
, height
, sW
, sH
);
937 else if (type
== 0x42)
938 renderBlockWhole4X (imdVidMem
, srcPtr
, width
, height
, sW
, sH
);
939 else if ((type
& 0x0F) == 0x02)
940 renderBlockWhole2Y (imdVidMem
, srcPtr
, width
, height
, sW
, sH
);
942 renderBlockSparse2Y(imdVidMem
, srcPtr
, width
, height
, sW
, sH
);
947 void Imd::deLZ77(byte
*dest
, byte
*src
) {
959 frameLength
= READ_LE_UINT32(src
);
962 if ((READ_LE_UINT16(src
) == 0x1234) && (READ_LE_UINT16(src
+ 2) == 0x5678)) {
965 mode
= 1; // 123Ch (cmp al, 12h)
968 mode
= 0; // 275h (jnz +2)
971 memset(buf
, 32, bufPos1
);
975 while (frameLength
> 0) {
977 if (chunkCount
== 0) {
982 if (chunkBitField
% 2) {
986 bufPos1
= (bufPos1
+ 1) % 4096;
992 tmp
= READ_LE_UINT16(src
);
994 chunkLength
= ((tmp
& 0xF00) >> 8) + 3;
996 if ((mode
&& ((chunkLength
& 0xFF) == 0x12)) ||
997 (!mode
&& (chunkLength
== 0)))
998 chunkLength
= *src
++ + 0x12;
1000 bufPos2
= (tmp
& 0xFF) + ((tmp
>> 4) & 0x0F00);
1001 if (((tmp
+ chunkLength
) >= 4096) ||
1002 ((chunkLength
+ bufPos1
) >= 4096)) {
1004 for (i
= 0; i
< chunkLength
; i
++, dest
++) {
1005 *dest
= buf
[bufPos2
];
1006 buf
[bufPos1
] = buf
[bufPos2
];
1007 bufPos1
= (bufPos1
+ 1) % 4096;
1008 bufPos2
= (bufPos2
+ 1) % 4096;
1011 } else if (((tmp
+ chunkLength
) < bufPos1
) ||
1012 ((chunkLength
+ bufPos1
) < bufPos2
)) {
1014 memcpy(dest
, buf
+ bufPos2
, chunkLength
);
1015 memmove(buf
+ bufPos1
, buf
+ bufPos2
, chunkLength
);
1017 dest
+= chunkLength
;
1018 bufPos1
+= chunkLength
;
1019 bufPos2
+= chunkLength
;
1023 for (i
= 0; i
< chunkLength
; i
++, dest
++, bufPos1
++, bufPos2
++) {
1024 *dest
= buf
[bufPos2
];
1025 buf
[bufPos1
] = buf
[bufPos2
];
1029 frameLength
-= chunkLength
;
1034 inline void Imd::unsignedToSigned(byte
*buffer
, int length
) {
1035 while (length
-- > 0) *buffer
++ ^= 0x80;
1039 Vmd::ExtraData::ExtraData() {
1040 memset(name
, 0, 16);
1049 type
= kPartTypeSeparator
;
1062 Vmd::Frame::Frame() {
1067 Vmd::Frame::~Frame() {
1072 const uint16
Vmd::_tableDPCM
[128] = {
1073 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080,
1074 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120,
1075 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0,
1076 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230,
1077 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280,
1078 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0,
1079 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320,
1080 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370,
1081 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0,
1082 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480,
1083 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700,
1084 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00,
1085 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
1088 const int32
Vmd::_tableADPCM
[] = {
1089 7, 8, 9, 10, 11, 12, 13, 14,
1090 16, 17, 19, 21, 23, 25, 28, 31,
1091 34, 37, 41, 45, 50, 55, 60, 66,
1092 73, 80, 88, 97, 107, 118, 130, 143,
1093 157, 173, 190, 209, 230, 253, 279, 307,
1094 337, 371, 408, 449, 494, 544, 598, 658,
1095 724, 796, 876, 963, 1060, 1166, 1282, 1411,
1096 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
1097 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
1098 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
1099 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
1103 const int32
Vmd::_tableADPCMStep
[] = {
1104 -1, -1, -1, -1, 2, 4, 6, 8,
1105 -1, -1, -1, -1, 2, 4, 6, 8
1108 Vmd::Vmd(Graphics::PaletteLUT
*palLUT
) : _palLUT(palLUT
) {
1116 bool Vmd::assessVideoProperties() {
1117 if (_bytesPerPixel
> 1)
1118 _features
|= kFeaturesFullColor
;
1120 _features
|= kFeaturesPalette
;
1122 if ((_version
& 2) && !(_version
& 8)) {
1123 _externalCodec
= true;
1124 _frameDataSize
= _vidBufferSize
= 0;
1126 _externalCodec
= false;
1128 if (_externalCodec
) {
1129 if (_videoCodec
== MKID_BE('iv32')) {
1130 _features
&= ~kFeaturesPalette
;
1131 _features
|= kFeaturesFullColor
;
1132 _codecIndeo3
= new Indeo3(_width
, _height
, _palLUT
);
1134 char *fourcc
= (char *) &_videoCodec
;
1136 warning("Vmd::assessVideoProperties(): Unknow video codec FourCC \'%c%c%c%c\'",
1137 fourcc
[3], fourcc
[2], fourcc
[1], fourcc
[0]);
1147 else if (_bytesPerPixel
== 1)
1149 else if ((_bytesPerPixel
== 2) || (_bytesPerPixel
== 3)) {
1150 int n
= (_flags
& 0x80) ? 2 : 3;
1154 if (_bytesPerPixel
== 2) {
1157 } else if (_bytesPerPixel
== 3) {
1165 _scaleExternalX
= 1;
1166 if (!_externalCodec
&& !(_flags
& 0x1000))
1167 _scaleExternalX
= _bytesPerPixel
;
1170 if ((_frameDataSize
== 0) || (_frameDataSize
> 1048576))
1171 _frameDataSize
= _width
* _height
+ 1000;
1172 if ((_vidBufferSize
== 0) || (_vidBufferSize
> 1048576))
1173 _vidBufferSize
= _frameDataSize
;
1175 _frameData
= new byte
[_frameDataSize
];
1177 memset(_frameData
, 0, _frameDataSize
);
1179 _vidBuffer
= new byte
[_vidBufferSize
];
1181 memset(_vidBuffer
, 0, _vidBufferSize
);
1183 if (_blitMode
> 0) {
1184 _vidMemBuffer
= new byte
[_bytesPerPixel
* (_width
* _height
+ 1000)];
1185 memset(_vidMemBuffer
, 0, _bytesPerPixel
* (_width
* _height
+ 1000));
1189 if (_externalCodec
&& _codecIndeo3
)
1190 _features
|= kFeaturesSupportsDouble
;
1195 bool Vmd::assessAudioProperties() {
1196 bool supportedFormat
= true;
1198 _features
|= kFeaturesSound
;
1200 _soundStereo
= (_soundFlags
& 0x8000) ? 1 : ((_soundFlags
& 0x200) ? 2 : 0);
1202 if (_soundSliceSize
< 0) {
1203 _soundBytesPerSample
= 2;
1204 _soundSliceSize
= -_soundSliceSize
;
1206 if (_soundFlags
& 0x10) {
1207 _audioFormat
= kAudioFormat16bitADPCM
;
1208 _soundHeaderSize
= 3;
1209 _soundDataSize
= _soundSliceSize
>> 1;
1211 if (_soundStereo
> 0)
1212 supportedFormat
= false;
1215 _audioFormat
= kAudioFormat16bitDPCM
;
1216 _soundHeaderSize
= 1;
1217 _soundDataSize
= _soundSliceSize
;
1219 if (_soundStereo
== 1) {
1220 supportedFormat
= false;
1221 } else if (_soundStereo
== 2) {
1222 _soundDataSize
= 2 * _soundDataSize
+ 2;
1223 _soundHeaderSize
= 4;
1228 _soundBytesPerSample
= 1;
1229 _audioFormat
= kAudioFormat8bitDirect
;
1230 _soundHeaderSize
= 0;
1231 _soundDataSize
= _soundSliceSize
;
1233 if (_soundStereo
> 0)
1234 supportedFormat
= false;
1237 if (!supportedFormat
) {
1238 warning("Vmd::assessAudioProperties(): Unsupported audio format: %d bits, encoding %d, stereo %d",
1239 _soundBytesPerSample
* 8, _audioFormat
, _soundStereo
);
1243 _soundSliceLength
= (uint32
) (((double) (1000 << 16)) /
1244 ((double) _soundFreq
/ (double) _soundSliceSize
));
1245 _frameLength
= _soundSliceLength
>> 16;
1251 flags
|= (_soundBytesPerSample
== 2) ? Audio::Mixer::FLAG_16BITS
: 0;
1252 flags
|= (_soundStereo
> 0) ? Audio::Mixer::FLAG_STEREO
: 0;
1254 _audioStream
= Audio::makeAppendableAudioStream(_soundFreq
, flags
);
1259 void Vmd::readFrameTable(int &numExtraData
) {
1262 _stream
->seek(_frameInfoOffset
);
1263 _frames
= new Frame
[_framesCount
];
1264 for (uint16 i
= 0; i
< _framesCount
; i
++) {
1265 _frames
[i
].parts
= new Part
[_partsPerFrame
];
1266 _stream
->skip(2); // Unknown
1267 _frames
[i
].offset
= _stream
->readUint32LE();
1270 for (uint16 i
= 0; i
< _framesCount
; i
++) {
1271 bool separator
= false;
1273 for (uint16 j
= 0; j
< _partsPerFrame
; j
++) {
1275 _frames
[i
].parts
[j
].type
= (PartType
) _stream
->readByte();
1276 _frames
[i
].parts
[j
].field_1
= _stream
->readByte();
1277 _frames
[i
].parts
[j
].size
= _stream
->readUint32LE();
1279 if (_frames
[i
].parts
[j
].type
== kPartTypeAudio
) {
1281 _frames
[i
].parts
[j
].flags
= _stream
->readByte();
1282 _stream
->skip(9); // Unknown
1284 } else if (_frames
[i
].parts
[j
].type
== kPartTypeVideo
) {
1286 _frames
[i
].parts
[j
].left
= _stream
->readUint16LE();
1287 _frames
[i
].parts
[j
].top
= _stream
->readUint16LE();
1288 _frames
[i
].parts
[j
].right
= _stream
->readUint16LE();
1289 _frames
[i
].parts
[j
].bottom
= _stream
->readUint16LE();
1290 _frames
[i
].parts
[j
].field_E
= _stream
->readByte();
1291 _frames
[i
].parts
[j
].flags
= _stream
->readByte();
1293 } else if (_frames
[i
].parts
[j
].type
== kPartTypeSpeech
) {
1294 _frames
[i
].parts
[j
].id
= _stream
->readUint16LE();
1295 // Speech text file name
1297 } else if (_frames
[i
].parts
[j
].type
== kPartTypeExtraData
) {
1301 } else if (_frames
[i
].parts
[j
].type
== kPartTypeSeparator
) {
1313 void Vmd::readExtraData() {
1314 uint32 ssize
= _stream
->size();
1315 for (uint16 i
= 0; i
< _framesCount
; i
++) {
1316 _stream
->seek(_frames
[i
].offset
);
1318 for (uint16 j
= 0; j
< _partsPerFrame
; j
++) {
1319 if (_frames
[i
].parts
[j
].type
== kPartTypeSeparator
)
1322 if (_frames
[i
].parts
[j
].type
== kPartTypeExtraData
) {
1325 data
.offset
= _stream
->pos() + 20;
1326 data
.size
= _frames
[i
].parts
[j
].size
;
1327 data
.realSize
= _stream
->readUint32LE();
1329 _stream
->read(data
.name
, 16);
1330 data
.name
[15] = '\0';
1332 _stream
->skip(_frames
[i
].parts
[j
].size
- 20);
1334 if ((((uint32
) data
.realSize
) >= ssize
) || (data
.name
[0] == 0))
1337 _extraData
.push_back(data
);
1340 _stream
->skip(_frames
[i
].parts
[j
].size
);
1345 bool Vmd::load(Common::SeekableReadStream
&stream
) {
1350 uint16 headerLength
;
1353 headerLength
= _stream
->readUint16LE();
1354 handle
= _stream
->readUint16LE();
1355 _version
= _stream
->readUint16LE();
1360 if (headerLength
== 50) {
1361 // Newer version, used in Addy 5 upwards
1362 warning("Vmd::load(): TODO: Addy 5 videos");
1363 readPalette
= false;
1364 } else if (headerLength
== 814) {
1368 warning("Vmd::load(): Version incorrect (%d, %d, %d)", headerLength
, handle
, _version
);
1373 _framesCount
= _stream
->readUint16LE();
1375 _x
= _stream
->readSint16LE();
1376 _y
= _stream
->readSint16LE();
1377 _width
= _stream
->readSint16LE();
1378 _height
= _stream
->readSint16LE();
1380 if ((_width
!= 0) && (_height
!= 0)) {
1383 _features
|= kFeaturesVideo
;
1390 _bytesPerPixel
= handle
+ 1;
1392 if (_bytesPerPixel
> 3) {
1393 warning("Vmd::load(): Requested %d bytes per pixel (%d, %d, %d)", _bytesPerPixel
, headerLength
, handle
, _version
);
1398 _flags
= _stream
->readUint16LE();
1400 _partsPerFrame
= _stream
->readUint16LE();
1401 _firstFramePos
= _stream
->readUint32LE();
1403 _videoCodec
= _stream
->readUint32BE();
1406 _stream
->read((byte
*) _palette
, 768);
1408 _frameDataSize
= _stream
->readUint32LE();
1409 _vidBufferSize
= _stream
->readUint32LE();
1411 _doubleMode
= false;
1414 if (!assessVideoProperties()) {
1420 _soundFreq
= _stream
->readSint16LE();
1421 _soundSliceSize
= _stream
->readSint16LE();
1422 _soundSlicesCount
= _stream
->readSint16LE();
1423 _soundFlags
= _stream
->readUint16LE();
1425 _hasSound
= (_soundFreq
!= 0);
1428 if (!assessAudioProperties()) {
1433 _frameLength
= 1000 / _frameRate
;
1435 _frameInfoOffset
= _stream
->readUint32LE();
1438 readFrameTable(numExtraData
);
1440 _stream
->seek(_firstFramePos
);
1442 if (numExtraData
== 0)
1445 _extraData
.reserve(numExtraData
);
1448 _stream
->seek(_firstFramePos
);
1452 void Vmd::unload() {
1456 int16
Vmd::getWidth() const {
1457 return preScaleX(_width
);
1460 void Vmd::setXY(int16 x
, int16 y
) {
1462 x
*= _scaleExternalX
;
1464 for (int i
= 0; i
< _framesCount
; i
++) {
1465 for (int j
= 0; j
< _partsPerFrame
; j
++) {
1467 if (_frames
[i
].parts
[j
].type
== kPartTypeVideo
) {
1469 _frames
[i
].parts
[j
].left
= _frames
[i
].parts
[j
].left
- _x
+ x
;
1470 _frames
[i
].parts
[j
].right
= _frames
[i
].parts
[j
].right
- _x
+ x
;
1473 _frames
[i
].parts
[j
].top
= _frames
[i
].parts
[j
].top
- _y
+ y
;
1474 _frames
[i
].parts
[j
].bottom
= _frames
[i
].parts
[j
].bottom
- _y
+ y
;
1487 void Vmd::setDoubleMode(bool doubleMode
) {
1488 if (_doubleMode
== doubleMode
)
1492 delete[] _vidBuffer
;
1495 _vidBufferSize
*= 4;
1497 _vidBufferSize
/= 4;
1499 _vidBuffer
= new byte
[_vidBufferSize
];
1501 memset(_vidBuffer
, 0, _vidBufferSize
);
1506 delete _codecIndeo3
;
1508 _codecIndeo3
= new Indeo3(_width
* (doubleMode
? 2 : 1),
1509 _height
* (doubleMode
? 2 : 1), _palLUT
);
1512 _doubleMode
= doubleMode
;
1515 void Vmd::seekFrame(int32 frame
, int16 whence
, bool restart
) {
1520 // Find the frame to which to seek
1521 if (whence
== SEEK_CUR
)
1523 else if (whence
== SEEK_END
)
1524 frame
= _framesCount
- frame
- 1;
1525 else if (whence
!= SEEK_SET
)
1528 if ((frame
< 0) || (frame
>= _framesCount
))
1533 if (_hasSound
&& (frame
== 0) && (_soundStage
== 0) && !_audioStream
) {
1535 _audioStream
= Audio::makeAppendableAudioStream(_soundFreq
,
1536 (_soundBytesPerSample
== 2) ? Audio::Mixer::FLAG_16BITS
: 0);
1540 _stream
->seek(_frames
[frame
].offset
);
1544 CoktelVideo::State
Vmd::nextFrame() {
1547 state
= processFrame(_curFrame
);
1552 void Vmd::clear(bool del
) {
1556 delete _codecIndeo3
;
1558 delete[] _vidMemBuffer
;
1571 _soundBytesPerSample
= 1;
1573 _soundHeaderSize
= 0;
1575 _audioFormat
= kAudioFormat8bitDirect
;
1577 _externalCodec
= false;
1578 _doubleMode
= false;
1583 _scaleExternalX
= 1;
1587 CoktelVideo::State
Vmd::processFrame(uint16 frame
) {
1589 bool startSound
= false;
1593 state
.flags
|= kStateNoVideoData
;
1594 state
.left
= 0x7FFF;
1602 for (uint16 i
= 0; (i
< _partsPerFrame
) && (frame
< _framesCount
); i
++) {
1603 uint32 pos
= _stream
->pos();
1605 Part
&part
= _frames
[frame
].parts
[i
];
1607 if (part
.type
== kPartTypeAudio
) {
1608 // Next sound slice data
1609 if (part
.flags
== 1) {
1611 if (_soundEnabled
) {
1612 filledSoundSlice(part
.size
);
1614 if (_soundStage
== 1)
1618 _stream
->skip(part
.size
);
1620 // Initial sound data (all slices)
1621 } else if (part
.flags
== 2) {
1623 if (_soundEnabled
) {
1624 uint32 mask
= _stream
->readUint32LE();
1625 filledSoundSlices(part
.size
- 4, mask
);
1627 if (_soundStage
== 1)
1631 _stream
->skip(part
.size
);
1633 // Empty sound slice
1634 } else if (part
.flags
== 3) {
1636 if (_soundEnabled
) {
1637 emptySoundSlice(_soundDataSize
* _soundBytesPerSample
);
1639 if (_soundStage
== 1)
1643 _stream
->skip(part
.size
);
1644 } else if (part
.flags
== 4) {
1645 warning("Vmd::processFrame(): TODO: Addy 5 sound type 4 (%d)", part
.size
);
1647 _stream
->skip(part
.size
);
1649 warning("Vmd::processFrame(): Unknown sound type %d", part
.flags
);
1650 _stream
->skip(part
.size
);
1653 _stream
->seek(pos
+ part
.size
);
1655 } else if ((part
.type
== kPartTypeVideo
) && !_hasVideo
) {
1656 warning("Vmd::processFrame(): Header claims there's no video, but video found (%d)", part
.size
);
1657 _stream
->skip(part
.size
);
1658 } else if ((part
.type
== kPartTypeVideo
) && _hasVideo
) {
1659 state
.flags
&= ~kStateNoVideoData
;
1661 uint32 size
= part
.size
;
1664 if (part
.flags
& 2) {
1665 uint8 index
= _stream
->readByte();
1666 uint8 count
= _stream
->readByte();
1668 _stream
->read(_palette
+ index
* 3, (count
+ 1) * 3);
1669 _stream
->skip((255 - count
) * 3);
1671 state
.flags
|= kStatePalette
;
1676 _stream
->read(_frameData
, size
);
1677 _frameDataLen
= size
;
1679 int16 l
= part
.left
, t
= part
.top
, r
= part
.right
, b
= part
.bottom
;
1680 if (renderFrame(l
, t
, r
, b
)) {
1681 if (!_externalCodec
) {
1685 // Rendering succeeded, merging areas
1686 state
.left
= MIN(state
.left
, l
);
1687 state
.top
= MIN(state
.top
, t
);
1688 state
.right
= MAX(state
.right
, r
);
1689 state
.bottom
= MAX(state
.bottom
, b
);
1692 } else if (part
.type
== kPartTypeSeparator
) {
1693 } else if (part
.type
== kPartTypeExtraData
) {
1694 _stream
->skip(part
.size
);
1695 } else if (part
.type
== kPartType4
) {
1697 _stream
->skip(part
.size
);
1698 } else if (part
.type
== kPartTypeSpeech
) {
1699 state
.flags
|= kStateSpeech
;
1700 state
.speechId
= part
.id
;
1701 // Always triggers when speech starts
1702 _stream
->skip(part
.size
);
1704 warning("Vmd::processFrame(): Unknown frame part type %d, size %d (%d of %d)", part
.type
, part
.size
, i
+ 1, _partsPerFrame
);
1708 if (startSound
&& _soundEnabled
) {
1709 _mixer
->playInputStream(Audio::Mixer::kSFXSoundType
, &_audioHandle
, _audioStream
);
1714 if ((_curFrame
== (_framesCount
- 1)) && (_soundStage
== 2)) {
1715 _audioStream
->finish();
1716 _mixer
->stopHandle(_audioHandle
);
1721 // If these are still 0x7FFF, no video data has been processed
1722 if ((state
.left
== 0x7FFF) || (state
.top
== 0x7FFF))
1723 state
.left
= state
.top
= state
.right
= state
.bottom
= 0;
1725 _lastFrameTime
= g_system
->getMillis();
1729 void Vmd::deRLE(byte
*&destPtr
, const byte
*&srcPtr
, int16 len
) {
1733 *destPtr
++ = *srcPtr
++;
1738 uint8 tmp
= *srcPtr
++;
1739 if (tmp
& 0x80) { // Verbatim copy
1742 memcpy(destPtr
, srcPtr
, tmp
* 2);
1745 } else { // 2 bytes tmp times
1746 for (int i
= 0; i
< tmp
; i
++) {
1747 *destPtr
++ = srcPtr
[0];
1748 *destPtr
++ = srcPtr
[1];
1756 // A run-length-encoded sparse block
1757 void Vmd::renderBlockRLE(byte
*dest
, const byte
*src
, int16 width
, int16 height
,
1758 int16 destWidth
, int16 destHeight
) {
1760 for (int i
= 0; i
< height
; i
++) {
1761 byte
*destBak
= dest
;
1762 uint16 pixWritten
= 0;
1764 while (pixWritten
< width
) {
1765 uint16 pixCount
= *src
++;
1767 if (pixCount
& 0x80) {
1768 pixCount
= (pixCount
& 0x7F) + 1;
1770 if (*src
!= 0xFF) { // Normal copy
1771 memcpy(dest
, src
, pixCount
);
1775 deRLE(dest
, src
, pixCount
);
1777 pixWritten
+= pixCount
;
1779 dest
+= pixCount
+ 1;
1780 pixWritten
+= pixCount
+ 1;
1785 dest
= destBak
+ destWidth
;
1790 uint32
Vmd::renderFrame(int16
&left
, int16
&top
, int16
&right
, int16
&bottom
) {
1791 if (!_frameData
|| !_vidMem
|| (_width
<= 0) || (_height
<= 0))
1794 int16 width
= right
- left
+ 1;
1795 int16 height
= bottom
- top
+ 1;
1796 int16 sW
= _vidMemWidth
;
1797 int16 sH
= _vidMemHeight
;
1798 uint32 dataLen
= _frameDataLen
;
1800 byte
*dataPtr
= _frameData
;
1801 byte
*imdVidMem
= _vidMem
+ sW
* top
+ left
;
1804 if ((left
< 0) || (top
< 0) || (right
< 0) || (bottom
< 0))
1806 if ((width
<= 0) || (height
<= 0))
1810 byte
*dest
= imdVidMem
;
1812 if (Indeo3::isIndeo3(dataPtr
, dataLen
)) {
1816 if (!_codecIndeo3
->decompressFrame(dataPtr
, dataLen
, _vidBuffer
,
1817 width
* (_doubleMode
? 2 : 1), height
* (_doubleMode
? 2 : 1)))
1821 srcPtr
= _vidBuffer
;
1822 width
= _width
* (_doubleMode
? 2 : 1);
1823 height
= _height
* (_doubleMode
? 2 : 1);
1824 right
= left
+ width
- 1;
1825 bottom
= top
+ height
- 1;
1829 if (_externalCodec
) {
1830 warning("Unknown external codec");
1837 if (_blitMode
> 0) {
1838 dest
= _vidMemBuffer
+ postScaleX(_width
) * (top
- _y
) + postScaleX((left
- _x
));
1839 imdVidMem
= _vidMem
+ _vidMemWidth
* top
+ preScaleX(left
);
1840 sW
= postScaleX(_width
);
1845 // Frame data is compressed
1847 srcPtr
= _vidBuffer
;
1849 if ((type
== 2) && (postScaleX(width
) == sW
)) {
1850 // Directly uncompress onto the video surface
1851 deLZ77(dest
, dataPtr
);
1852 blit(imdVidMem
, dest
, width
, height
);
1855 deLZ77(srcPtr
, dataPtr
);
1860 width
= postScaleX(width
);
1862 // Evaluate the block type
1864 renderBlockSparse (dest
, srcPtr
, width
, height
, sW
, sH
);
1865 else if (type
== 0x02)
1866 renderBlockWhole (dest
, srcPtr
, width
, height
, sW
, sH
);
1867 else if (type
== 0x03)
1868 renderBlockRLE (dest
, srcPtr
, width
, height
, sW
, sH
);
1869 else if (type
== 0x42)
1870 renderBlockWhole4X (dest
, srcPtr
, width
, height
, sW
, sH
);
1871 else if ((type
& 0x0F) == 0x02)
1872 renderBlockWhole2Y (dest
, srcPtr
, width
, height
, sW
, sH
);
1874 renderBlockSparse2Y(dest
, srcPtr
, width
, height
, sW
, sH
);
1877 dest
= _vidMemBuffer
+ postScaleX(_width
) * (top
- _y
) + postScaleX(left
- _x
);
1878 blit(imdVidMem
, dest
, width
, height
);
1883 inline int32
Vmd::preScaleX(int32 x
) const {
1884 return x
/ _preScaleX
;
1887 inline int32
Vmd::postScaleX(int32 x
) const {
1888 return x
* _postScaleX
;
1891 void Vmd::blit(byte
*dest
, byte
*src
, int16 width
, int16 height
) {
1896 blit16(dest
, src
, preScaleX(_width
), preScaleX(width
), height
);
1897 else if (_blitMode
== 2)
1898 blit24(dest
, src
, preScaleX(_width
), preScaleX(width
), height
);
1901 void Vmd::blit16(byte
*dest
, byte
*src
, int16 srcPitch
, int16 width
, int16 height
) {
1904 Graphics::SierraLight
*dither
=
1905 new Graphics::SierraLight(width
, _palLUT
);
1907 for (int i
= 0; i
< height
; i
++) {
1911 for (int j
= 0; j
< width
; j
++, s
+= 2) {
1912 uint16 data
= READ_LE_UINT16(s
);
1913 byte r
= ((data
& 0x7C00) >> 10);
1914 byte g
= ((data
& 0x03E0) >> 5);
1915 byte b
= ((data
& 0x001F) >> 0);
1918 Graphics::PaletteLUT::RGB2YUV(r
<< 3, g
<< 3, b
<< 3, dY
, dU
, dV
);
1920 byte p
= dither
->dither(dY
, dU
, dV
, j
);
1922 if ((dY
== 0) || ((r
== 0) && (g
== 0) && (b
== 0)))
1929 dest
+= _vidMemWidth
;
1930 src
+= 2 * srcPitch
;
1936 void Vmd::blit24(byte
*dest
, byte
*src
, int16 srcPitch
, int16 width
, int16 height
) {
1939 Graphics::SierraLight
*dither
=
1940 new Graphics::SierraLight(width
, _palLUT
);
1942 for (int i
= 0; i
< height
; i
++) {
1946 for (int j
= 0; j
< width
; j
++, s
+= 3) {
1952 Graphics::PaletteLUT::RGB2YUV(r
, g
, b
, dY
, dU
, dV
);
1954 byte p
= dither
->dither(dY
, dU
, dV
, j
);
1956 if ((dY
== 0) || ((r
== 0) && (g
== 0) && (b
== 0)))
1963 dest
+= _vidMemWidth
;
1964 src
+= 3 * srcPitch
;
1970 byte
*Vmd::deDPCM(const byte
*data
, uint32
&size
, int32 init
[2]) {
1971 if (!data
|| (size
== 0))
1974 int channels
= (_soundStereo
> 0) ? 2 : 1;
1976 uint32 inSize
= size
;
1977 uint32 outSize
= size
+ channels
;
1979 int16
*out
= new int16
[outSize
];
1980 byte
*sound
= (byte
*) out
;
1984 for (int i
= 0; i
< channels
; i
++) {
1985 *out
++ = TO_BE_16(init
[channel
]);
1987 channel
= (channel
+ 1) % channels
;
1990 while (inSize
-- > 0) {
1992 init
[channel
] -= _tableDPCM
[*data
++ & 0x7F];
1994 init
[channel
] += _tableDPCM
[*data
++];
1996 init
[channel
] = CLIP
<int32
>(init
[channel
], -32768, 32767);
1997 *out
++ = TO_BE_16(init
[channel
]);
1999 channel
= (channel
+ 1) % channels
;
2006 // Yet another IMA ADPCM variant
2007 byte
*Vmd::deADPCM(const byte
*data
, uint32
&size
, int32 init
, int32 index
) {
2008 if (!data
|| (size
== 0))
2011 uint32 outSize
= size
* 2;
2013 int16
*out
= new int16
[outSize
];
2014 byte
*sound
= (byte
*) out
;
2016 index
= CLIP
<int32
>(index
, 0, 88);
2018 int32 predictor
= _tableADPCM
[index
];
2020 uint32 dataByte
= 0;
2021 bool newByte
= true;
2024 while (size
-- > 0) {
2029 code
= (dataByte
>> 4) & 0xF;
2031 code
= dataByte
& 0xF;
2035 index
+= _tableADPCMStep
[code
];
2036 index
= CLIP
<int32
>(index
, 0, 88);
2038 int32 value
= predictor
/ 8;
2043 value
+= predictor
/ 2;
2045 value
+= predictor
/ 4;
2052 init
= CLIP
<int32
>(init
, -32768, 32767);
2054 predictor
= _tableADPCM
[index
];
2056 *out
++ = TO_BE_16(init
);
2063 byte
*Vmd::soundEmpty(uint32
&size
) {
2067 byte
*soundBuf
= new byte
[size
];
2068 memset(soundBuf
, 0, size
);
2073 byte
*Vmd::sound8bitDirect(uint32
&size
) {
2074 if (!_audioStream
) {
2075 _stream
->skip(size
);
2079 byte
*soundBuf
= new byte
[size
];
2080 _stream
->read(soundBuf
, size
);
2081 unsignedToSigned(soundBuf
, size
);
2086 byte
*Vmd::sound16bitDPCM(uint32
&size
) {
2087 if (!_audioStream
) {
2088 _stream
->skip(size
);
2094 init
[0] = _stream
->readSint16LE();
2097 if (_soundStereo
> 0) {
2098 init
[1] = _stream
->readSint16LE();
2102 byte
*data
= new byte
[size
];
2105 if (_stream
->read(data
, size
) == size
)
2106 sound
= deDPCM(data
, size
, init
);
2113 byte
*Vmd::sound16bitADPCM(uint32
&size
) {
2114 if (!_audioStream
) {
2115 _stream
->skip(size
);
2119 int32 init
= _stream
->readSint16LE();
2122 int32 index
= _stream
->readByte();
2125 byte
*data
= new byte
[size
];
2128 if (_stream
->read(data
, size
) == size
)
2129 sound
= deADPCM(data
, size
, init
, index
);
2136 void Vmd::emptySoundSlice(uint32 size
) {
2137 byte
*sound
= soundEmpty(size
);
2140 _audioStream
->queueBuffer(sound
, size
);
2143 void Vmd::filledSoundSlice(uint32 size
) {
2145 if (_audioFormat
== kAudioFormat8bitDirect
)
2146 sound
= sound8bitDirect(size
);
2147 else if (_audioFormat
== kAudioFormat16bitDPCM
)
2148 sound
= sound16bitDPCM(size
);
2149 else if (_audioFormat
== kAudioFormat16bitADPCM
)
2150 sound
= sound16bitADPCM(size
);
2153 _audioStream
->queueBuffer(sound
, size
);
2156 uint8
Vmd::evaluateMask(uint32 mask
, bool *fillInfo
, uint8
&max
) {
2157 max
= MIN
<int>(_soundSlicesCount
- 1, 31);
2160 for (int i
= 0; i
< max
; i
++) {
2166 *fillInfo
++ = false;
2174 void Vmd::filledSoundSlices(uint32 size
, uint32 mask
) {
2178 uint8 n
= evaluateMask(mask
, fillInfo
, max
);
2182 extraSize
= size
- n
* _soundDataSize
;
2184 if (_soundSlicesCount
> 32)
2185 extraSize
-= (_soundSlicesCount
- 32) * _soundDataSize
;
2190 for (uint8 i
= 0; i
< max
; i
++)
2192 filledSoundSlice(_soundDataSize
+ extraSize
);
2194 emptySoundSlice(_soundDataSize
* _soundBytesPerSample
);
2196 if (_soundSlicesCount
> 32)
2197 filledSoundSlice((_soundSlicesCount
- 32) * _soundDataSize
+ _soundHeaderSize
);
2200 bool Vmd::getPartCoords(int16 frame
, PartType type
,
2201 int16
&x
, int16
&y
, int16
&width
, int16
&height
) {
2203 if (frame
>= _framesCount
)
2206 Frame
&f
= _frames
[frame
];
2208 // Look for a part matching the requested type, stopping at a separator
2210 for (int i
= 0; i
< _partsPerFrame
; i
++) {
2211 Part
&p
= f
.parts
[i
];
2213 if ((p
.type
== kPartTypeSeparator
) || (p
.type
== type
)) {
2224 width
= part
->right
- part
->left
+ 1;
2225 height
= part
->bottom
- part
->top
+ 1;
2230 bool Vmd::getFrameCoords(int16 frame
,
2231 int16
&x
, int16
&y
, int16
&width
, int16
&height
) {
2233 return getPartCoords(frame
, kPartTypeVideo
, x
, y
, width
, height
);
2236 bool Vmd::hasExtraData(const char *fileName
) const {
2237 for (uint i
= 0; i
< _extraData
.size(); i
++)
2238 if (!scumm_stricmp(_extraData
[i
].name
, fileName
))
2244 Common::MemoryReadStream
*Vmd::getExtraData(const char *fileName
) {
2247 for (i
= 0; i
< _extraData
.size(); i
++)
2248 if (!scumm_stricmp(_extraData
[i
].name
, fileName
))
2251 if (i
>= _extraData
.size())
2254 if ((_extraData
[i
].size
- 20) != _extraData
[i
].realSize
) {
2255 warning("Vmd::getExtraData(): Sizes for \"%s\" differ! (%d, %d)",
2256 fileName
, (_extraData
[i
].size
- 20), _extraData
[i
].realSize
);
2260 if (!_stream
->seek(_extraData
[i
].offset
)) {
2261 warning("Vmd::getExtraData(): Can't seek to offset %d to (file \"%s\")",
2262 _extraData
[i
].offset
, fileName
);
2266 byte
*data
= (byte
*) malloc(_extraData
[i
].realSize
);
2267 if (_stream
->read(data
, _extraData
[i
].realSize
) != _extraData
[i
].realSize
) {
2269 warning("Vmd::getExtraData(): Couldn't read %d bytes (file \"%s\")",
2270 _extraData
[i
].realSize
, fileName
);
2273 Common::MemoryReadStream
*stream
=
2274 new Common::MemoryReadStream(data
, _extraData
[i
].realSize
, true);
2279 } // End of namespace Graphics