aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'graphics')
-rw-r--r--graphics/VectorRendererSpec.cpp30
-rw-r--r--graphics/module.mk6
-rw-r--r--graphics/scaler.cpp52
-rw-r--r--graphics/scaler.h3
-rwxr-xr-xgraphics/scaler/Normal2xARM.s171
-rw-r--r--graphics/scaler/scale2x.cpp38
-rw-r--r--graphics/scaler/scale2x.h10
-rwxr-xr-xgraphics/scaler/scale2xARM.s182
-rw-r--r--graphics/scaler/scalebit.cpp12
-rw-r--r--graphics/sjis.cpp112
-rw-r--r--graphics/sjis.h79
-rw-r--r--graphics/video/coktelvideo/coktelvideo.cpp1652
-rw-r--r--graphics/video/coktelvideo/coktelvideo.h256
-rw-r--r--graphics/video/smk_decoder.cpp6
-rw-r--r--graphics/video/smk_decoder.h4
15 files changed, 1865 insertions, 748 deletions
diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp
index b68f4822d8..a575ee8b94 100644
--- a/graphics/VectorRendererSpec.cpp
+++ b/graphics/VectorRendererSpec.cpp
@@ -366,22 +366,24 @@ applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle) {
uint8 r, g, b;
uint lum;
- const uint32 shiftMask = (uint32)~(
- (1 << _format.rShift) | (1 << _format.gShift) | (1 << _format.bShift) | (_format.aLoss == 8 ? 0 : (1 << _format.aShift))) >> 1;
+ // Mask to clear the last bit of every color component and all unused bits
+ const uint32 colorMask = ~((1 << _format.rShift) | (1 << _format.gShift) | (1 << _format.bShift) // R/G/B components
+ | (_format.aLoss == 8 ? 0 : (1 << _format.aShift)) // Alpha component
+ | ~(_alphaMask | _redMask | _greenMask | _blueMask)); // All unused bits
if (shadingStyle == GUI::ThemeEngine::kShadingDim) {
int n = (pixels + 7) >> 3;
switch (pixels % 8) {
case 0: do {
- *ptr = (*ptr >> 1) & shiftMask; ++ptr;
- case 7: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
- case 6: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
- case 5: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
- case 4: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
- case 3: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
- case 2: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
- case 1: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
+ *ptr = (*ptr & colorMask) >> 1; ++ptr;
+ case 7: *ptr = (*ptr & colorMask) >> 1; ++ptr;
+ case 6: *ptr = (*ptr & colorMask) >> 1; ++ptr;
+ case 5: *ptr = (*ptr & colorMask) >> 1; ++ptr;
+ case 4: *ptr = (*ptr & colorMask) >> 1; ++ptr;
+ case 3: *ptr = (*ptr & colorMask) >> 1; ++ptr;
+ case 2: *ptr = (*ptr & colorMask) >> 1; ++ptr;
+ case 1: *ptr = (*ptr & colorMask) >> 1; ++ptr;
} while (--n > 0);
}
@@ -421,10 +423,10 @@ calcGradient(uint32 pos, uint32 max) {
PixelType output = 0;
pos = (MIN(pos * Base::_gradientFactor, max) << 12) / max;
- output |= ((_gradientStart&_redMask) + ((Base::_gradientBytes[0] * pos) >> 12)) & _redMask;
- output |= ((_gradientStart&_greenMask) + ((Base::_gradientBytes[1] * pos) >> 12)) & _greenMask;
- output |= ((_gradientStart&_blueMask) + ((Base::_gradientBytes[2] * pos) >> 12)) & _blueMask;
- output |= ~(_redMask | _greenMask | _blueMask);
+ output |= ((_gradientStart & _redMask) + ((Base::_gradientBytes[0] * pos) >> 12)) & _redMask;
+ output |= ((_gradientStart & _greenMask) + ((Base::_gradientBytes[1] * pos) >> 12)) & _greenMask;
+ output |= ((_gradientStart & _blueMask) + ((Base::_gradientBytes[2] * pos) >> 12)) & _blueMask;
+ output |= _alphaMask;
return output;
}
diff --git a/graphics/module.mk b/graphics/module.mk
index 2387bb708c..ed14051243 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -37,6 +37,12 @@ MODULE_OBJS += \
scaler/scale3x.o \
scaler/scalebit.o
+ifdef USE_ARM_SCALER_ASM
+MODULE_OBJS += \
+ scaler/scale2xARM.o \
+ scaler/Normal2xARM.o
+endif
+
ifndef DISABLE_HQ_SCALERS
MODULE_OBJS += \
scaler/hq2x.o \
diff --git a/graphics/scaler.cpp b/graphics/scaler.cpp
index 082258bfc0..8c677cc083 100644
--- a/graphics/scaler.cpp
+++ b/graphics/scaler.cpp
@@ -186,6 +186,57 @@ void Normal1x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPit
}
#ifndef DISABLE_SCALERS
+#ifdef USE_ARM_SCALER_ASM
+extern "C" void Normal2xAspectMask(const uint8 *srcPtr,
+ uint32 srcPitch,
+ uint8 *dstPtr,
+ uint32 dstPitch,
+ int width,
+ int height,
+ uint32 mask);
+
+void Normal2xAspect(const uint8 *srcPtr,
+ uint32 srcPitch,
+ uint8 *dstPtr,
+ uint32 dstPitch,
+ int width,
+ int height) {
+ if (gBitFormat == 565) {
+ Normal2xAspectMask(srcPtr,
+ srcPitch,
+ dstPtr,
+ dstPitch,
+ width,
+ height,
+ 0x07e0F81F);
+ } else {
+ Normal2xAspectMask(srcPtr,
+ srcPitch,
+ dstPtr,
+ dstPitch,
+ width,
+ height,
+ 0x03e07C1F);
+ }
+}
+
+extern "C" void Normal2xARM(const uint8 *srcPtr,
+ uint32 srcPitch,
+ uint8 *dstPtr,
+ uint32 dstPitch,
+ int width,
+ int height);
+
+void Normal2x(const uint8 *srcPtr,
+ uint32 srcPitch,
+ uint8 *dstPtr,
+ uint32 dstPitch,
+ int width,
+ int height) {
+ Normal2xARM(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
+}
+
+#else
/**
* Trivial nearest-neighbour 2x scaler.
*/
@@ -209,6 +260,7 @@ void Normal2x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPit
dstPtr += dstPitch << 1;
}
}
+#endif
/**
* Trivial nearest-neighbour 3x scaler.
diff --git a/graphics/scaler.h b/graphics/scaler.h
index 4cea9ee2fb..bdae161bd1 100644
--- a/graphics/scaler.h
+++ b/graphics/scaler.h
@@ -45,6 +45,9 @@ DECLARE_SCALER(AdvMame2x);
DECLARE_SCALER(AdvMame3x);
DECLARE_SCALER(Normal1x);
DECLARE_SCALER(Normal2x);
+#ifdef USE_ARM_SCALER_ASM
+DECLARE_SCALER(Normal2xAspect);
+#endif
DECLARE_SCALER(Normal3x);
DECLARE_SCALER(Normal1o5x);
DECLARE_SCALER(TV2x);
diff --git a/graphics/scaler/Normal2xARM.s b/graphics/scaler/Normal2xARM.s
new file mode 100755
index 0000000000..5de50d9c17
--- /dev/null
+++ b/graphics/scaler/Normal2xARM.s
@@ -0,0 +1,171 @@
+@ ScummVM Scumm Interpreter
+@ Copyright (C) 2009 The ScummVM project
+@
+@ This program is free software@ you can redistribute it and/or
+@ modify it under the terms of the GNU General Public License
+@ as published by the Free Software Foundation@ either version 2
+@ of the License, or (at your option) any later version.
+@
+@ This program is distributed in the hope that it will be useful,
+@ but WITHOUT ANY WARRANTY@ without even the implied warranty of
+@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+@ GNU General Public License for more details.
+@
+@ You should have received a copy of the GNU General Public License
+@ along with this program@ if not, write to the Free Software
+@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+@
+@ $URL$
+@ $Id$
+@
+@ @author Robin Watts (robin@wss.co.uk)
+
+ .text
+
+ .global Normal2xARM
+ .global Normal2xAspectMask
+
+
+ @ Assumes dst is aligned (so did the C)
+ @ Assumes 16bit (so did the C)
+Normal2xARM:
+ @ r0 = src
+ @ r1 = srcPitch
+ @ r2 = dst
+ @ r3 = dstPitch
+ @ r4 = w
+ @ r5 = h
+ STMFD r13!,{r4-r11,r14}
+ LDR r4, [r13,#4*9] @ r4 = w
+ LDR r5, [r13,#4*10] @ r5 = h
+ ADD r12,r2, r3
+ SUB r1, r1, r4, LSL #1
+ SUB r6, r3, r4, LSL #2
+ ADD r3, r3, r6
+yloop:
+ SUBS r14,r4, #4
+ BLT thin
+xloop:
+ LDRH r6, [r0], #2
+ LDRH r7, [r0], #2
+ LDRH r8, [r0], #2
+ LDRH r9, [r0], #2
+ ORR r6, r6, r6, LSL #16
+ ORR r7, r7, r7, LSL #16
+ ORR r8, r8, r8, LSL #16
+ ORR r9, r9, r9, LSL #16
+ STMIA r2!, {r6-r9}
+ STMIA r12!,{r6-r9}
+ SUBS r14,r14,#4
+ BGE xloop
+ ADDS r14,r14,#4
+ BNE thin
+ ADD r0, r0, r1
+ ADD r2, r2, r3
+ ADD r12,r12,r3
+ SUBS r5, r5, #1
+ BGT yloop
+
+ LDMFD r13!,{r4-r11,PC}
+thin:
+ LDRH r6, [r0], #2
+ ORR r6, r6, r6, LSL #16
+ STR r6, [r2], #4
+ STR r6, [r12],#4
+ SUBS r14,r14,#1
+ BGT thin
+ ADD r0, r0, r1
+ ADD r2, r2, r3
+ ADD r12,r12,r3
+ SUBS r5, r5, #1
+ BGT yloop
+
+ LDMFD r13!,{r4-r11,PC}
+
+
+ @ Horrid filter calculations
+ @ AAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCDDDDDDDDDDDDEEEEEEEEEEEE
+ @ <-+-><-+-><-+-><-+-><-+-><-+-><-+-><-+-><-+-><-+-><-+-><-+->
+ @ Ideal: A,A,(A*2+B*3)/5,B,(B*4+C)/5,C,C,(C+D*4)/5,D,(D*3+E*2)/5,E,E
+ @ Actual: A,A,(A*3+B*5)/8,B,(B*7+C)/8,C,C,(C+D*7)/8,D,(D*5+E*3)/8,E,E
+
+ @ Assumes dst is aligned (so did the C)
+ @ Assumes 16bit (so did the C)
+Normal2xAspectMask:
+ @ r0 = src
+ @ r1 = srcPitch
+ @ r2 = dst
+ @ r3 = dstPitch
+ @ r4 = w
+ @ r5 = h
+ @ r12= mask
+ STMFD r13!,{r4-r11,r14}
+ LDR r4, [r13,#4*9] @ r4 = w
+ LDR r5, [r13,#4*10] @ r5 = h
+ LDR r12,[r13,#4*11] @ r12= mask
+ MOV r11,#2
+ SUB r11,r11,r1, LSL #2 @ r11= 2-srcPitch*4
+ MOV r14,#4
+ SUB r14,r14,r3, LSL #3
+ SUB r14,r14,r3, LSL #1
+ SUB r14,r14,r3 @ r14 = 4-dstPitch*11
+yloop_aspect:
+xloop_aspect:
+ LDRH r6, [r0], r1 @ r6 = A
+ LDRH r7, [r0], r1 @ r7 = B
+ LDRH r8, [r0], r1 @ r8 = C
+ LDRH r9, [r0], r1 @ r9 = D
+ LDRH r10,[r0], r11 @ r10= E
+ ORR r6, r6, r6, LSL #16 @ r6 = output 0, 1
+ ORR r7, r7, r7, LSL #16 @ r7 = output 3
+ ORR r8, r8, r8, LSL #16 @ r8 = output 5,6
+ ORR r9, r9, r9, LSL #16 @ r9 = output 8
+ ORR r10,r10,r10,LSL #16 @ r10= output 10, 11
+ STR r6, [r2], r3 @ output 0 (A)
+ STR r6, [r2], r3 @ output 1 (A)
+ AND r6, r6, r12 @ r6 = A split
+ ADD r6, r6, r6, LSL #1 @ r6 = A*3
+ STR r7, [r2, r3] @ output 3 (B)
+ AND r7, r7, r12 @ r7 = B split
+ ADD r6, r6, r7 @ r6 = A*3 + B
+ ADD r6, r6, r7, LSL #2 @ r6 = A*3 + B*5
+ AND r6, r12,r6, LSR #3 @ r6 = (A*3 + B*5)>>3
+ ORR r6, r6, r6, ROR #16 @ r6 = output 2
+ STR r6, [r2], r3, LSL #1 @ output 2 (A*3+B*5)>>3
+ RSB r7, r7, r7, LSL #3 @ r7 = B*7
+ AND r6, r8, r12 @ r6 = C split
+ ADD r7, r7, r6 @ r7 = B*7+C
+ AND r7, r12,r7, LSR #3 @ r7 = (B*7 + C)>>3
+ ORR r7, r7, r7, ROR #16 @ r7 = output 4
+ STR r7, [r2], r3 @ output 4 (B*7+C)>>3
+ STR r8, [r2], r3 @ output 5 (C)
+ STR r8, [r2], r3 @ output 6 (C)
+ STR r9, [r2, r3] @ output 8 (D)
+ AND r9, r9, r12 @ r9 = D split
+ RSB r7, r9, r9, LSL #3 @ r7 = D*7
+ ADD r6, r6, r7 @ r6 = C+D*7
+ AND r6, r12,r6, LSR #3 @ r6 = (C + D*7)>>3
+ ORR r6, r6, r6, ROR #16 @ r6 = output 7
+ STR r6, [r2], r3, LSL #1 @ output 7 (C+D*7)>>3
+ ADD r9, r9, r9, LSL #2 @ r9 = D*5
+ AND r6, r10,r12 @ r6 = E split
+ ADD r9, r9, r6 @ r9 = D*5+E
+ ADD r9, r9, r6, LSL #1 @ r9 = D*5+E*3
+ AND r9, r12,r9, LSR #3 @ r9 = (D*5 + E*3)>>3
+ ORR r9, r9, r9, ROR #16 @ r9 = output 9
+ STR r9, [r2], r3 @ output 9 (D*5+E*3)>>3
+ STR r10,[r2], r3 @ output 10 (E)
+ STR r10,[r2], r14 @ output 11 (E)
+ SUBS r4, r4, #1
+ BGT xloop_aspect
+ LDR r4, [r13,#4*9] @ r4 = w
+ ADD r0, r0, r1, LSL #2
+ ADD r0, r0, r1
+ SUB r0, r0, r4, LSL #1
+ ADD r2, r2, r3, LSL #3
+ ADD r2, r2, r3, LSL #2
+ SUB r2, r2, r4, LSL #2
+ SUBS r5, r5, #5
+ BGT yloop_aspect
+
+ LDMFD r13!,{r4-r11,PC}
diff --git a/graphics/scaler/scale2x.cpp b/graphics/scaler/scale2x.cpp
index 226d379c91..877bbb9509 100644
--- a/graphics/scaler/scale2x.cpp
+++ b/graphics/scaler/scale2x.cpp
@@ -158,7 +158,7 @@ void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_ui
/***************************************************************************/
/* Scale2x MMX implementation */
-#if defined(__GNUC__) && defined(__i386__)
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
/*
* Apply the Scale2x effect at a single row.
@@ -205,7 +205,7 @@ static inline void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8*
__asm__ __volatile__(
/* central runs */
- "shrl $3, %4\n"
+ "shr $3, %4\n"
"jz 1f\n"
"0:\n"
@@ -261,12 +261,12 @@ static inline void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8*
"movq %%mm3, 8(%3)\n"
/* next */
- "addl $8, %0\n"
- "addl $8, %1\n"
- "addl $8, %2\n"
- "addl $16, %3\n"
+ "add $8, %0\n"
+ "add $8, %1\n"
+ "add $8, %2\n"
+ "add $16, %3\n"
- "decl %4\n"
+ "dec %4\n"
"jnz 0b\n"
"1:\n"
@@ -283,7 +283,7 @@ static inline void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint
__asm__ __volatile__(
/* central runs */
- "shrl $2, %4\n"
+ "shr $2, %4\n"
"jz 1f\n"
"0:\n"
@@ -339,12 +339,12 @@ static inline void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint
"movq %%mm3, 8(%3)\n"
/* next */
- "addl $8, %0\n"
- "addl $8, %1\n"
- "addl $8, %2\n"
- "addl $16, %3\n"
+ "add $8, %0\n"
+ "add $8, %1\n"
+ "add $8, %2\n"
+ "add $16, %3\n"
- "decl %4\n"
+ "dec %4\n"
"jnz 0b\n"
"1:\n"
@@ -361,7 +361,7 @@ static inline void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint
__asm__ __volatile__(
/* central runs */
- "shrl $1, %4\n"
+ "shr $1, %4\n"
"jz 1f\n"
"0:\n"
@@ -417,12 +417,12 @@ static inline void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint
"movq %%mm3, 8(%3)\n"
/* next */
- "addl $8, %0\n"
- "addl $8, %1\n"
- "addl $8, %2\n"
- "addl $16, %3\n"
+ "add $8, %0\n"
+ "add $8, %1\n"
+ "add $8, %2\n"
+ "add $16, %3\n"
- "decl %4\n"
+ "dec %4\n"
"jnz 0b\n"
"1:\n"
diff --git a/graphics/scaler/scale2x.h b/graphics/scaler/scale2x.h
index 2101790905..cefa14f22a 100644
--- a/graphics/scaler/scale2x.h
+++ b/graphics/scaler/scale2x.h
@@ -33,7 +33,7 @@ void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8
void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
-#if defined(__GNUC__) && defined(__i386__)
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
@@ -52,5 +52,13 @@ static inline void scale2x_mmx_emms(void)
#endif
+#if defined(USE_ARM_SCALER_ASM)
+
+extern "C" void scale2x_8_arm(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
+extern "C" void scale2x_16_arm(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
+extern "C" void scale2x_32_arm(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
+
+#endif
+
#endif
diff --git a/graphics/scaler/scale2xARM.s b/graphics/scaler/scale2xARM.s
new file mode 100755
index 0000000000..3ca237e02d
--- /dev/null
+++ b/graphics/scaler/scale2xARM.s
@@ -0,0 +1,182 @@
+@ ScummVM Scumm Interpreter
+@ Copyright (C) 2009 The ScummVM project
+@
+@ This program is free software@ you can redistribute it and/or
+@ modify it under the terms of the GNU General Public License
+@ as published by the Free Software Foundation@ either version 2
+@ of the License, or (at your option) any later version.
+@
+@ This program is distributed in the hope that it will be useful,
+@ but WITHOUT ANY WARRANTY@ without even the implied warranty of
+@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+@ GNU General Public License for more details.
+@
+@ You should have received a copy of the GNU General Public License
+@ along with this program@ if not, write to the Free Software
+@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+@
+@ $URL$
+@ $Id$
+@
+@ @author Robin Watts (robin@wss.co.uk)
+
+ .text
+
+ .global scale2x_8_arm
+ .global scale2x_16_arm
+ .global scale2x_32_arm
+
+ @ r0 = dst0
+ @ r1 = dst1
+ @ r2 = src
+ @ r3 = src_prev
+ @ r4 = src_next
+ @ r5 = len
+
+
+ @ We hold: r10 B
+ @ r8 r14 r7 D E F
+ @ r12 H
+scale2x_8_arm:
+ STMFD r13!,{r4-r5,r7-r8,r10-r11,r14}
+ LDR r4, [r13,#4*7]
+ LDR r5, [r13,#4*8]
+
+ LDRB r14,[r2], #1
+ CMP r3, #0 @ Set NE
+ @ Stall on Xscale
+ MOV r8, r14
+ B loop8
+same8:
+ STRB r14,[r0], #1
+ STRB r14,[r0], #1
+ STRB r14,[r1], #1
+ STRB r14,[r1], #1
+ SUBS r5, r5, #1
+ MOV r8, r14
+ MOV r14,r7
+ BLT end8
+loop8:
+ LDRNEB r7, [r3], #1 @ As long as we aren't on the last pixel
+ LDRB r10,[r2], #1
+ LDRB r12,[r4], #1
+ @ Stall on Xscale
+ CMP r7, r8
+ CMPNE r10,r12
+ BEQ same8
+ CMP r8, r10
+ STREQB r8, [r0], #1
+ STRNEB r14,[r0], #1
+ CMP r10,r7
+ STREQB r7, [r0], #1
+ STRNEB r14,[r0], #1
+ CMP r8, r12
+ STREQB r8, [r1], #1
+ STRNEB r14,[r1], #1
+ CMP r12,r7
+ STREQB r7, [r1], #1
+ STRNEB r14,[r1], #1
+
+ SUBS r5, r5, #1
+ MOV r8, r14
+ MOV r14,r7
+ BGE loop8
+end8:
+
+ LDMFD r13!,{r4-r5,r7-r8,r10-r11,PC}
+
+scale2x_16_arm:
+ STMFD r13!,{r4-r5,r7-r8,r10-r11,r14}
+ LDR r4, [r13,#4*7]
+ LDR r5, [r13,#4*8]
+
+ LDRH r14,[r3], #2
+ CMP r3, #0 @ Set NE
+ @ Stall on Xscale
+ MOV r8, r14
+ B loop16
+same16:
+ STRH r14,[r0], #2
+ STRH r14,[r0], #2
+ STRH r14,[r1], #2
+ STRH r14,[r1], #2
+ SUBS r5, r5, #1
+ MOV r8, r14
+ MOV r14,r7
+ BLT end16
+loop16:
+ LDRNEH r7, [r3], #2 @ As long as we aren't on the last pixel
+ LDRH r10,[r2], #2
+ LDRH r12,[r4], #2
+ @ Stall on Xscale
+ CMP r7, r8
+ CMPNE r10,r12
+ BEQ same16
+ CMP r8, r10
+ STREQH r8, [r0], #2
+ STRNEH r14,[r0], #2
+ CMP r10,r7
+ STREQH r7, [r0], #2
+ STRNEH r14,[r0], #2
+ CMP r8, r12
+ STREQH r8, [r1], #2
+ STRNEH r14,[r1], #2
+ CMP r12,r7
+ STREQH r7, [r1], #2
+ STRNEH r14,[r1], #2
+
+ SUBS r5, r5, #1
+ MOV r8, r14
+ MOV r14,r7
+ BGE loop16
+end16:
+
+ LDMFD r13!,{r4-r5,r7-r8,r10-r11,PC}
+
+scale2x_32_arm:
+ STMFD r13!,{r4-r5,r7-r8,r10-r11,r14}
+ LDR r4, [r13,#4*7]
+ LDR r5, [r13,#4*8]
+
+ LDR r14,[r3], #4
+ CMP r3, #0 @ Set NE
+ @ Stall on Xscale
+ MOV r8, r14
+ B loop32
+same32:
+ STR r14,[r0], #4
+ STR r14,[r0], #4
+ STR r14,[r1], #4
+ STR r14,[r1], #4
+ SUBS r5, r5, #1
+ MOV r8, r14
+ MOV r14,r7
+ BLT end32
+loop32:
+ LDRNE r7, [r3], #4 @ As long as we aren't on the last pixel
+ LDR r10,[r2], #4
+ LDR r12,[r4], #4
+ @ Stall on Xscale
+ CMP r7, r8
+ CMPNE r10,r12
+ BEQ same32
+ CMP r8, r10
+ STREQ r8, [r0], #4
+ STRNE r14,[r0], #4
+ CMP r10,r7
+ STREQ r7, [r0], #4
+ STRNE r14,[r0], #4
+ CMP r8, r12
+ STREQ r8, [r1], #4
+ STRNE r14,[r1], #4
+ CMP r12,r7
+ STREQ r7, [r1], #4
+ STRNE r14,[r1], #4
+
+ SUBS r5, r5, #1
+ MOV r8, r14
+ MOV r14,r7
+ BGE loop32
+end32:
+
+ LDMFD r13!,{r4-r5,r7-r8,r10-r11,PC}
diff --git a/graphics/scaler/scalebit.cpp b/graphics/scaler/scalebit.cpp
index a6fd8df58f..6a3b47b0f5 100644
--- a/graphics/scaler/scalebit.cpp
+++ b/graphics/scaler/scalebit.cpp
@@ -55,10 +55,14 @@
static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
{
switch (pixel) {
-#if defined(__GNUC__) && defined(__i386__)
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
case 1 : scale2x_8_mmx(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
case 2 : scale2x_16_mmx(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
case 4 : scale2x_32_mmx(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
+#elif defined(USE_ARM_SCALER_ASM)
+ case 1 : scale2x_8_arm(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
+ case 2 : scale2x_16_arm(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
+ case 4 : scale2x_32_arm(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
#else
case 1 : scale2x_8_def(DST(8,0), DST(8,1), SRC(8,0), SRC(8,1), SRC(8,2), pixel_per_row); break;
case 2 : scale2x_16_def(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
@@ -125,7 +129,7 @@ static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, un
--count;
}
-#if defined(__GNUC__) && defined(__i386__)
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
scale2x_mmx_emms();
#endif
}
@@ -225,7 +229,7 @@ static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsi
--count;
}
-#if defined(__GNUC__) && defined(__i386__)
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
scale2x_mmx_emms();
#endif
}
@@ -303,7 +307,7 @@ int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned
break;
}
-#if defined(__GNUC__) && defined(__i386__)
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
switch (scale) {
case 2 :
case 4 :
diff --git a/graphics/sjis.cpp b/graphics/sjis.cpp
index 5392a1c9a4..405d8622c2 100644
--- a/graphics/sjis.cpp
+++ b/graphics/sjis.cpp
@@ -27,17 +27,33 @@
#ifdef GRAPHICS_SJIS_H
#include "common/debug.h"
+#include "common/archive.h"
+#include "common/endian.h"
namespace Graphics {
-bool FontTowns::loadFromStream(Common::ReadStream &stream) {
- for (uint i = 0; i < (kFontRomSize / 2); ++i)
- _fontData[i] = stream.readUint16BE();
- return !stream.err();
+FontSJIS *FontSJIS::createFont(const Common::Platform platform) {
+ FontSJIS *ret = 0;
+
+ // Try the font ROM of the specified platform
+ if (platform == Common::kPlatformFMTowns) {
+ ret = new FontTowns();
+ if (ret && ret->loadData())
+ return ret;
+ delete ret;
+ }
+
+ // Try ScummVM's font.
+ ret = new FontSjisSVM();
+ if (ret && ret->loadData())
+ return ret;
+ delete ret;
+
+ return 0;
}
template<typename Color>
-void FontTowns::drawCharInternOutline(const uint16 *glyph, uint8 *dst, int pitch, Color c1, Color c2) const {
+void FontSJIS16x16::drawCharInternOutline(const uint16 *glyph, uint8 *dst, int pitch, Color c1, Color c2) const {
uint32 outlineGlyph[18];
memset(outlineGlyph, 0, sizeof(outlineGlyph));
@@ -72,7 +88,7 @@ void FontTowns::drawCharInternOutline(const uint16 *glyph, uint8 *dst, int pitch
}
template<typename Color>
-void FontTowns::drawCharIntern(const uint16 *glyph, uint8 *dst, int pitch, Color c1) const {
+void FontSJIS16x16::drawCharIntern(const uint16 *glyph, uint8 *dst, int pitch, Color c1) const {
for (int y = 0; y < 16; ++y) {
Color *lineBuf = (Color *)dst;
uint16 line = *glyph++;
@@ -88,8 +104,12 @@ void FontTowns::drawCharIntern(const uint16 *glyph, uint8 *dst, int pitch, Color
}
}
-void FontTowns::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2) const {
- const uint16 *glyphSource = _fontData + sjisToChunk(ch & 0xFF, ch >> 8) * 16;
+void FontSJIS16x16::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2) const {
+ const uint16 *glyphSource = getCharData(ch);
+ if (!glyphSource) {
+ warning("FontSJIS16x16::drawChar: Font does not offer data for %02X %02X", ch & 0xFF, ch >> 8);
+ return;
+ }
if (bpp == 1) {
if (!_outlineEnabled)
@@ -106,7 +126,25 @@ void FontTowns::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, ui
}
}
-uint FontTowns::sjisToChunk(uint8 f, uint8 s) {
+// FM-TOWNS ROM font
+
+bool FontTowns::loadData() {
+ Common::SeekableReadStream *data = SearchMan.createReadStreamForMember("FMT_FNT.ROM");
+ if (!data)
+ return false;
+
+ for (uint i = 0; i < (kFontRomSize / 2); ++i)
+ _fontData[i] = data->readUint16BE();
+
+ bool retValue = !data->err();
+ delete data;
+ return retValue;
+}
+
+const uint16 *FontTowns::getCharData(uint16 ch) const {
+ uint8 f = ch & 0xFF;
+ uint8 s = ch >> 8;
+
// copied from scumm\charset.cpp
enum {
KANA = 0,
@@ -188,7 +226,61 @@ uint FontTowns::sjisToChunk(uint8 f, uint8 s) {
}
debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr);
- return ((chunk_f + chunk) * 32 + (s - base)) + cr;
+ return _fontData + (((chunk_f + chunk) * 32 + (s - base)) + cr) * 16;
+}
+
+// ScummVM SJIS font
+
+bool FontSjisSVM::loadData() {
+ Common::SeekableReadStream *data = SearchMan.createReadStreamForMember("SJIS.FNT");
+ if (!data)
+ return false;
+
+ uint32 magic1 = data->readUint32BE();
+ uint32 magic2 = data->readUint32BE();
+
+ if (magic1 != MKID_BE('SCVM') || magic2 != MKID_BE('SJIS')) {
+ delete data;
+ return false;
+ }
+
+ uint32 version = data->readUint32BE();
+ if (version != 1) {
+ delete data;
+ return false;
+ }
+ uint numChars = data->readUint16BE();
+
+ _fontData = new uint16[numChars * 16];
+ assert(_fontData);
+
+ for (uint i = 0; i < numChars * 16; ++i)
+ _fontData[i] = data->readUint16BE();
+
+ bool retValue = !data->err();
+ delete data;
+ return retValue;
+}
+
+const uint16 *FontSjisSVM::getCharData(uint16 c) const {
+ const uint8 fB = c & 0xFF;
+ const uint8 sB = c >> 8;
+
+ // We only allow 2 byte SJIS characters.
+ if (fB <= 0x80 || fB >= 0xF0 || (fB >= 0xA0 && fB <= 0xDF) || sB == 0x7F)
+ return 0;
+
+ int base = fB;
+ base -= 0x81;
+ if (base >= 0x5F)
+ base -= 0x40;
+
+ int index = sB;
+ index -= 0x40;
+ if (index >= 0x3F)
+ --index;
+
+ return _fontData + (base * 0xBC + index) * 16;
}
} // end of namespace Graphics
diff --git a/graphics/sjis.h b/graphics/sjis.h
index f7321742af..b5d997a19a 100644
--- a/graphics/sjis.h
+++ b/graphics/sjis.h
@@ -35,6 +35,7 @@
#include "common/scummsys.h"
#include "common/stream.h"
+#include "common/util.h"
#include "graphics/surface.h"
@@ -50,6 +51,24 @@ public:
virtual ~FontSJIS() {}
/**
+ * Creates the first SJIS font, which ROM/font file is present.
+ * It will also call loadData, so the user can just start
+ * using the font.
+ *
+ * It'll prefer the platform specific ROM file, when platform
+ * is set to a value, which's font ROM is supported.
+ * So far that is only kPlatformFMTowns.
+ *
+ * The last file tried is ScummVM's SJIS.FNT file.
+ */
+ static FontSJIS *createFont(const Common::Platform platform = Common::kPlatformUnknown);
+
+ /**
+ * Load the font data.
+ */
+ virtual bool loadData() = 0;
+
+ /**
* Enable outline drawing.
*
* After changing outline state, getFontHeight and getFontWidth might return
@@ -69,6 +88,10 @@ public:
/**
* Draws a SJIS encoded character on the given surface.
+ *
+ * TODO: Currently there is no assurance, that this method will only draw within
+ * the surface boundaries. Thus the caller has to assure the glyph will fit at
+ * the specified position.
*/
void drawChar(Graphics::Surface &dst, uint16 ch, int x, int y, uint32 c1, uint32 c2) const {
drawChar(dst.getBasePtr(x, y), ch, c1, c2, dst.pitch, dst.bytesPerPixel);
@@ -78,7 +101,7 @@ public:
* Draws a SJIS char on the given raw buffer.
*
* @param dst pointer to the destination
- * @param ch character to draw
+ * @param ch character to draw (in little endian)
* @param pitch pitch of the destination buffer (size in *bytes*)
* @param bpp bytes per pixel of the destination buffer
* @param c1 forground color
@@ -88,18 +111,11 @@ public:
};
/**
- * FM-TOWNS ROM based SJIS compatible font.
- *
- * This is used in KYRA and SCI.
+ * A base class to render 16x16 monochrome SJIS fonts.
*/
-class FontTowns : public FontSJIS {
+class FontSJIS16x16 : public FontSJIS {
public:
- FontTowns() : _outlineEnabled(false) {}
-
- /**
- * Loads the ROM data from the given read stream.
- */
- bool loadFromStream(Common::ReadStream &stream);
+ FontSJIS16x16() : _outlineEnabled(false) {}
void enableOutline(bool enable) { _outlineEnabled = enable; }
@@ -115,14 +131,51 @@ private:
template<typename Color>
void drawCharIntern(const uint16 *glyph, uint8 *dst, int pitch, Color c1) const;
+ bool _outlineEnabled;
+protected:
+
+ virtual const uint16 *getCharData(uint16 c) const = 0;
+};
+
+/**
+ * FM-TOWNS ROM based SJIS compatible font.
+ *
+ * This is used in KYRA and SCI.
+ */
+class FontTowns : public FontSJIS16x16 {
+public:
+ /**
+ * Loads the ROM data from "FMT_FNT.ROM".
+ */
+ bool loadData();
+
+private:
enum {
kFontRomSize = 262144
};
- bool _outlineEnabled;
uint16 _fontData[kFontRomSize / 2];
- static uint sjisToChunk(uint8 low, uint8 high);
+ const uint16 *getCharData(uint16 c) const;
+};
+
+/**
+ * Our custom SJIS FNT.
+ */
+class FontSjisSVM : public FontSJIS16x16 {
+public:
+ FontSjisSVM() : _fontData(0) {}
+ ~FontSjisSVM() { delete[] _fontData; }
+
+ /**
+ * Load the font data from "SJIS.FNT".
+ */
+ bool loadData();
+
+private:
+ uint16 *_fontData;
+
+ const uint16 *getCharData(uint16 c) const;
};
// TODO: Consider adding support for PC98 ROM
diff --git a/graphics/video/coktelvideo/coktelvideo.cpp b/graphics/video/coktelvideo/coktelvideo.cpp
index c88c5beee2..063ad190e6 100644
--- a/graphics/video/coktelvideo/coktelvideo.cpp
+++ b/graphics/video/coktelvideo/coktelvideo.cpp
@@ -41,52 +41,79 @@ Imd::~Imd() {
clear();
}
-bool Imd::load(Common::SeekableReadStream &stream) {
- unload();
+uint32 Imd::getFeatures() const {
+ return _features;
+}
- _stream = &stream;
+uint16 Imd::getFlags() const {
+ return _flags;
+}
- // Version
- uint16 handle = _stream->readUint16LE();
- _version = _stream->readByte();
+int16 Imd::getX() const {
+ return _x;
+}
- // Version checking
- if ((handle != 0) || (_version < 2)) {
- warning("IMD Version incorrect (%d,%X)", handle, _version);
- unload();
- return false;
- }
+int16 Imd::getY() const {
+ return _y;
+}
- // Rest header
- _features = _stream->readByte();
- _framesCount = _stream->readUint16LE();
- _x = _stream->readSint16LE();
- _y = _stream->readSint16LE();
- _width = _stream->readSint16LE();
- _height = _stream->readSint16LE();
- _flags = _stream->readUint16LE();
- _firstFramePos = _stream->readUint16LE();
+int16 Imd::getWidth() const {
+ return _width;
+}
- // IMDs always have video
- _features |= kFeaturesVideo;
- // IMDs always have palettes
- _features |= kFeaturesPalette;
+int16 Imd::getHeight() const {
+ return _height;
+}
- // Palette
- _stream->read((byte *) _palette, 768);
+uint16 Imd::getFramesCount() const {
+ return _framesCount;
+}
+
+uint16 Imd::getCurrentFrame() const {
+ return _curFrame;
+}
+
+int16 Imd::getFrameRate() const {
+ if (!_hasSound)
+ return _frameRate;
+ return 1000 / (_soundSliceLength >> 16);
+}
+
+uint32 Imd::getSyncLag() const {
+ return _skipFrames;
+}
+
+const byte *Imd::getPalette() const {
+ return _palette;
+}
+
+bool Imd::getFrameCoords(int16 frame,
+ int16 &x, int16 &y, int16 &width, int16 &height) {
+
+ return false;
+}
+
+bool Imd::hasExtraData(const char *fileName) const {
+ return false;
+}
+
+Common::MemoryReadStream *Imd::getExtraData(const char *fileName) {
+ return 0;
+}
+
+bool Imd::loadCoordinates() {
// Standard coordinates
if (_version >= 3) {
_stdX = _stream->readUint16LE();
if (_stdX > 1) {
warning("IMD: More than one standard coordinate quad found (%d)", _stdX);
- unload();
return false;
}
if (_stdX != 0) {
- _stdX = _stream->readSint16LE();
- _stdY = _stream->readSint16LE();
- _stdWidth = _stream->readSint16LE();
+ _stdX = _stream->readSint16LE();
+ _stdY = _stream->readSint16LE();
+ _stdWidth = _stream->readSint16LE();
_stdHeight = _stream->readSint16LE();
_features |= kFeaturesStdCoords;
} else
@@ -94,8 +121,14 @@ bool Imd::load(Common::SeekableReadStream &stream) {
} else
_stdX = -1;
- // Offset to frame positions table
- uint32 framesPosPos = 0;
+ return true;
+}
+
+bool Imd::loadFrameTableOffsets(uint32 &framesPosPos, uint32 &framesCoordsPos) {
+ framesPosPos = 0;
+ framesCoordsPos = 0;
+
+ // Frame positions
if (_version >= 4) {
framesPosPos = _stream->readUint32LE();
if (framesPosPos != 0) {
@@ -105,15 +138,43 @@ bool Imd::load(Common::SeekableReadStream &stream) {
}
}
- // Offset to frame coordinates
- uint32 framesCoordsPos = 0;
+ // Frame coordinates
if (_features & kFeaturesFrameCoords)
framesCoordsPos = _stream->readUint32LE();
- // Sound
+ return true;
+}
+
+bool Imd::assessVideoProperties() {
+ // Sizes of the frame data and extra video buffer
+ if (_features & kFeaturesDataSize) {
+ _frameDataSize = _stream->readUint16LE();
+ if (_frameDataSize == 0) {
+ _frameDataSize = _stream->readUint32LE();
+ _vidBufferSize = _stream->readUint32LE();
+ } else
+ _vidBufferSize = _stream->readUint16LE();
+ } else {
+ _frameDataSize = _width * _height + 500;
+ if (!(_flags & 0x100) || (_flags & 0x1000))
+ _vidBufferSize = _frameDataSize;
+ }
+
+ // Allocating working memory
+ _frameData = new byte[_frameDataSize + 500];
+ assert(_frameData);
+ memset(_frameData, 0, _frameDataSize + 500);
+ _vidBuffer = new byte[_vidBufferSize + 500];
+ assert(_vidBuffer);
+ memset(_vidBuffer, 0, _vidBufferSize + 500);
+
+ return true;
+}
+
+bool Imd::assessAudioProperties() {
if (_features & kFeaturesSound) {
- _soundFreq = _stream->readSint16LE();
- _soundSliceSize = _stream->readSint16LE();
+ _soundFreq = _stream->readSint16LE();
+ _soundSliceSize = _stream->readSint16LE();
_soundSlicesCount = _stream->readSint16LE();
if (_soundFreq < 0)
@@ -123,8 +184,7 @@ bool Imd::load(Common::SeekableReadStream &stream) {
_soundSlicesCount = -_soundSlicesCount - 1;
if (_soundSlicesCount > 40) {
- warning("IMD: More than 40 sound slices found (%d)", _soundSlicesCount);
- unload();
+ warning("Imd::load(): More than 40 sound slices found (%d)", _soundSlicesCount);
return false;
}
@@ -133,57 +193,103 @@ bool Imd::load(Common::SeekableReadStream &stream) {
_frameLength = _soundSliceLength >> 16;
_soundStage = 1;
- _hasSound = true;
+ _hasSound = true;
_audioStream = Audio::makeAppendableAudioStream(_soundFreq, 0);
} else
_frameLength = 1000 / _frameRate;
- // Sizes of the frame data and extra video buffer
- if (_features & kFeaturesDataSize) {
- _frameDataSize = _stream->readUint16LE();
- if (_frameDataSize == 0) {
- _frameDataSize = _stream->readUint32LE();
- _vidBufferSize = _stream->readUint32LE();
- } else
- _vidBufferSize = _stream->readUint16LE();
- } else {
- _frameDataSize = _width * _height + 500;
- if (!(_flags & 0x100) || (_flags & 0x1000))
- _vidBufferSize = _frameDataSize;
- }
+ return true;
+}
- // Frame positions table
+bool Imd::loadFrameTables(uint32 framesPosPos, uint32 framesCoordsPos) {
+ // Positions table
if (_framesPos) {
_stream->seek(framesPosPos, SEEK_SET);
for (int i = 0; i < _framesCount; i++)
_framesPos[i] = _stream->readUint32LE();
}
- // Frame coordinates table
+ // Coordinates table
if (_features & kFeaturesFrameCoords) {
_stream->seek(framesCoordsPos, SEEK_SET);
_frameCoords = new Coord[_framesCount];
assert(_frameCoords);
for (int i = 0; i < _framesCount; i++) {
- _frameCoords[i].left = _stream->readSint16LE();
- _frameCoords[i].top = _stream->readSint16LE();
- _frameCoords[i].right = _stream->readSint16LE();
+ _frameCoords[i].left = _stream->readSint16LE();
+ _frameCoords[i].top = _stream->readSint16LE();
+ _frameCoords[i].right = _stream->readSint16LE();
_frameCoords[i].bottom = _stream->readSint16LE();
}
}
+ return true;
+}
+
+bool Imd::load(Common::SeekableReadStream &stream) {
+ unload();
+
+ _stream = &stream;
+
+ uint16 handle;
+
+ handle = _stream->readUint16LE();
+ _version = _stream->readByte();
+
+ // Version checking
+ if ((handle != 0) || (_version < 2)) {
+ warning("Imd::load(): Version incorrect (%d,%X)", handle, _version);
+ unload();
+ return false;
+ }
+
+ // Rest header
+ _features = _stream->readByte();
+ _framesCount = _stream->readUint16LE();
+ _x = _stream->readSint16LE();
+ _y = _stream->readSint16LE();
+ _width = _stream->readSint16LE();
+ _height = _stream->readSint16LE();
+ _flags = _stream->readUint16LE();
+ _firstFramePos = _stream->readUint16LE();
+
+ // IMDs always have video
+ _features |= kFeaturesVideo;
+ // IMDs always have palettes
+ _features |= kFeaturesPalette;
+
+ // Palette
+ _stream->read((byte *) _palette, 768);
+
+ if (!loadCoordinates()) {
+ unload();
+ return false;
+ }
+
+ uint32 framesPosPos, frameCoordsPos;
+ if (!loadFrameTableOffsets(framesPosPos, frameCoordsPos)) {
+ unload();
+ return false;
+ }
+
+ if (!assessAudioProperties()) {
+ unload();
+ return false;
+ }
+
+ if (!assessVideoProperties()) {
+ unload();
+ return false;
+ }
+
+ if (!loadFrameTables(framesPosPos, frameCoordsPos)) {
+ unload();
+ return false;
+ }
+
// Seek to the first frame
_stream->seek(_firstFramePos, SEEK_SET);
- // Allocating working memory
- _frameData = new byte[_frameDataSize + 500];
- assert(_frameData);
- memset(_frameData, 0, _frameDataSize + 500);
- _vidBuffer = new byte[_vidBufferSize + 500];
- assert(_vidBuffer);
- memset(_vidBuffer, 0, _vidBufferSize + 500);
-
return true;
}
@@ -195,7 +301,7 @@ void Imd::setFrameRate(int16 frameRate) {
if (frameRate == 0)
frameRate = 1;
- _frameRate = frameRate;
+ _frameRate = frameRate;
_frameLength = 1000 / _frameRate;
}
@@ -213,11 +319,11 @@ void Imd::setXY(int16 x, int16 y) {
for (int i = 0; i < _framesCount; i++) {
if (_frameCoords[i].left != -1) {
if (x >= 0) {
- _frameCoords[i].left = _frameCoords[i].left - _x + x;
+ _frameCoords[i].left = _frameCoords[i].left - _x + x;
_frameCoords[i].right = _frameCoords[i].right - _x + x;
}
if (y >= 0) {
- _frameCoords[i].top = _frameCoords[i].top - _y + y;
+ _frameCoords[i].top = _frameCoords[i].top - _y + y;
_frameCoords[i].bottom = _frameCoords[i].bottom - _y + y;
}
}
@@ -234,8 +340,8 @@ void Imd::setVideoMemory(byte *vidMem, uint16 width, uint16 height) {
deleteVidMem();
_hasOwnVidMem = false;
- _vidMem = vidMem;
- _vidMemWidth = width;
+ _vidMem = vidMem;
+ _vidMemWidth = width;
_vidMemHeight = height;
}
@@ -245,12 +351,17 @@ void Imd::setVideoMemory() {
if ((_width > 0) && (_height > 0)) {
setXY(0, 0);
_hasOwnVidMem = true;
- _vidMem = new byte[_width * _height];
- _vidMemWidth = _width;
+ _vidMem = new byte[_width * _height];
+ _vidMemWidth = _width;
_vidMemHeight = _height;
+
+ memset(_vidMem, 0, _width * _height);
}
}
+void Imd::setDoubleMode(bool doubleMode) {
+}
+
void Imd::enableSound(Audio::Mixer &mixer) {
// Only possible on the first frame
if (_curFrame > 0)
@@ -270,7 +381,7 @@ void Imd::disableSound() {
delete _audioStream;
_audioStream = 0;
- _soundStage = 0;
+ _soundStage = 0;
}
_soundEnabled = false;
_mixer = 0;
@@ -313,8 +424,9 @@ void Imd::seekFrame(int32 frame, int16 whence, bool restart) {
} else if (restart && (_soundStage == 0)) {
for (int i = ((frame > _curFrame) ? _curFrame : 0); i <= frame; i++)
processFrame(i);
+ return;
} else
- error("Frame %d is not directly accessible", frame);
+ error("Imd::seekFrame(): Frame %d is not directly accessible", frame);
// Seek
_stream->seek(framePos);
@@ -326,7 +438,7 @@ CoktelVideo::State Imd::nextFrame() {
}
void Imd::waitEndFrame() {
- if (_soundEnabled && _hasSound) {
+ if (_soundEnabled && _hasSound) {;
if (_soundStage != 2)
return;
@@ -404,8 +516,9 @@ void Imd::deleteVidMem(bool del) {
}
_hasOwnVidMem = false;
- _vidMem = 0;
- _vidMemWidth = _vidMemHeight = 0;
+ _vidMem = 0;
+ _vidMemWidth = 0;
+ _vidMemHeight = 0;
}
void Imd::clear(bool del) {
@@ -420,42 +533,126 @@ void Imd::clear(bool del) {
_stream = 0;
- _version = 0;
+ _version = 0;
_features = 0;
- _flags = 0;
- _x = _y = _width = _height = 0;
+ _flags = 0;
+
+ _x = _y = _width = _height = 0;
_stdX = _stdY = _stdWidth = _stdHeight = 0;
+
_framesCount = _curFrame = 0;
- _framesPos = 0;
+
+ _framesPos = 0;
_firstFramePos = 0;
- _frameCoords = 0;
+ _frameCoords = 0;
_frameDataSize = _vidBufferSize = 0;
- _frameData = _vidBuffer = 0;
- _frameDataLen = 0;
+ _frameData = _vidBuffer = 0;
+ _frameDataLen = 0;
memset(_palette, 0, 768);
deleteVidMem(del);
- _hasSound = false;
+ _hasSound = false;
_soundEnabled = false;
- _soundStage = 0;
- _skipFrames = 0;
+ _soundStage = 0;
+ _skipFrames = 0;
- _soundFlags = 0;
- _soundFreq = 0;
- _soundSliceSize = 0;
+ _soundFlags = 0;
+ _soundFreq = 0;
+ _soundSliceSize = 0;
_soundSlicesCount = 0;
_soundSliceLength = 0;
+ _audioStream = 0;
- _audioStream = 0;
-
- _frameRate = 12;
- _frameLength = 0;
+ _frameRate = 12;
+ _frameLength = 0;
_lastFrameTime = 0;
}
+void Imd::nextSoundSlice(bool hasNextCmd) {
+ if (hasNextCmd || !_soundEnabled) {
+ _stream->seek(_soundSliceSize, SEEK_CUR);
+ return;
+ }
+
+ byte *soundBuf = new byte[_soundSliceSize];
+
+ _stream->read(soundBuf, _soundSliceSize);
+ unsignedToSigned(soundBuf, _soundSliceSize);
+
+ _audioStream->queueBuffer(soundBuf, _soundSliceSize);
+}
+
+bool Imd::initialSoundSlice(bool hasNextCmd) {
+ int dataLength = _soundSliceSize * _soundSlicesCount;
+
+ if (hasNextCmd || !_soundEnabled) {
+ _stream->seek(dataLength, SEEK_CUR);
+ return false;
+ }
+
+ byte *soundBuf = new byte[dataLength];
+
+ _stream->read(soundBuf, dataLength);
+ unsignedToSigned(soundBuf, dataLength);
+
+ _audioStream->queueBuffer(soundBuf, dataLength);
+
+ return _soundStage == 1;
+}
+
+void Imd::emptySoundSlice(bool hasNextCmd) {
+ if (hasNextCmd || !_soundEnabled)
+ return;
+
+ byte *soundBuf = new byte[_soundSliceSize];
+
+ memset(soundBuf, 0, _soundSliceSize);
+
+ _audioStream->queueBuffer(soundBuf, _soundSliceSize);
+}
+
+void Imd::videoData(uint32 size, State &state) {
+ _stream->read(_frameData, size);
+ _frameDataLen = size;
+
+ if (_vidMemWidth <= state.right) {
+ state.left = 0;
+ state.right -= state.left;
+ }
+ if (_vidMemWidth <= state.right)
+ state.right = _vidMemWidth - 1;
+ if (_vidMemHeight <= state.bottom) {
+ state.top = 0;
+ state.bottom -= state.top;
+ }
+ if (_vidMemHeight <= state.bottom)
+ state.bottom = _vidMemHeight -1;
+
+ state.flags |= renderFrame(state.left, state.top, state.right, state.bottom);
+ state.flags |= _frameData[0];
+}
+
+void Imd::calcFrameCoords(uint16 frame, State &state) {
+ if (_stdX != -1) {
+ state.left = _stdX;
+ state.top = _stdY;
+ state.right = _stdWidth + state.left - 1;
+ state.bottom = _stdHeight + state.top - 1;
+ state.flags |= kStateStdCoords;
+ }
+ if (_frameCoords &&
+ (_frameCoords[frame].left != -1)) {
+ state.left = _frameCoords[frame].left;
+ state.top = _frameCoords[frame].top;
+ state.right = _frameCoords[frame].right;
+ state.bottom = _frameCoords[frame].bottom;
+ state.flags |= kStateFrameCoords;
+ }
+}
+
CoktelVideo::State Imd::processFrame(uint16 frame) {
State state;
uint32 cmd = 0;
@@ -475,47 +672,35 @@ CoktelVideo::State Imd::processFrame(uint16 frame) {
if (!_vidMem)
setVideoMemory();
- state.left = _x;
- state.top = _y;
- state.right = _width + state.left - 1;
- state.bottom = _height + state.top - 1;
+ state.left = _x;
+ state.top = _y;
+ state.right = _width + state.left - 1;
+ state.bottom = _height + state.top - 1;
do {
- if (frame != 0) {
- if (_stdX != -1) {
- state.left = _stdX;
- state.top = _stdY;
- state.right = _stdWidth + state.left - 1;
- state.bottom = _stdHeight + state.top - 1;
- state.flags |= kStateStdCoords;
- }
- if (_frameCoords &&
- (_frameCoords[frame].left != -1)) {
- state.left = _frameCoords[frame].left;
- state.top = _frameCoords[frame].top;
- state.right = _frameCoords[frame].right;
- state.bottom = _frameCoords[frame].bottom;
- state.flags |= kStateFrameCoords;
- }
- }
+ if (frame != 0)
+ calcFrameCoords(frame, state);
cmd = _stream->readUint16LE();
- if ((cmd & 0xFFF8) == 0xFFF0) {
- if (cmd == 0xFFF0) {
+ if ((cmd & kCommandBreakMask) == kCommandBreak) {
+ // Flow control
+
+ if (cmd == kCommandBreak) {
_stream->seek(2, SEEK_CUR);
cmd = _stream->readUint16LE();
}
- if (cmd == 0xFFF1) {
+ // Break
+ if (cmd == kCommandBreakSkip0) {
state.flags = kStateBreak;
continue;
- } else if (cmd == 0xFFF2) { // Skip (16 bit)
+ } else if (cmd == kCommandBreakSkip16) {
cmd = _stream->readUint16LE();
_stream->seek(cmd, SEEK_CUR);
state.flags = kStateBreak;
continue;
- } else if (cmd == 0xFFF3) { // Skip (32 bit)
+ } else if (cmd == kCommandBreakSkip32) {
cmd = _stream->readUint32LE();
_stream->seek(cmd, SEEK_CUR);
state.flags = kStateBreak;
@@ -523,57 +708,24 @@ CoktelVideo::State Imd::processFrame(uint16 frame) {
}
}
+ // Audio
if (_soundStage != 0) {
- byte *soundBuf;
-
- // Next sound slice data
- if (cmd == 0xFF00) {
-
- if (!hasNextCmd && _soundEnabled) {
- soundBuf = new byte[_soundSliceSize];
- assert(soundBuf);
-
- _stream->read(soundBuf, _soundSliceSize);
- unsignedToSigned(soundBuf, _soundSliceSize);
- _audioStream->queueBuffer(soundBuf, _soundSliceSize);
- } else
- _stream->seek(_soundSliceSize, SEEK_CUR);
+ if (cmd == kCommandNextSound) {
+ nextSoundSlice(hasNextCmd);
cmd = _stream->readUint16LE();
- // Initial sound data (all slices)
- } else if (cmd == 0xFF01) {
- int dataLength = _soundSliceSize * _soundSlicesCount;
-
- if (!hasNextCmd && _soundEnabled) {
- soundBuf = new byte[dataLength];
- assert(soundBuf);
-
- _stream->read(soundBuf, dataLength);
- unsignedToSigned(soundBuf, dataLength);
-
- if (_soundStage == 1)
- startSound = true;
-
- _audioStream->queueBuffer(soundBuf, dataLength);
- } else
- _stream->seek(dataLength, SEEK_CUR);
+ } else if (cmd == kCommandStartSound) {
+ startSound = initialSoundSlice(hasNextCmd);
cmd = _stream->readUint16LE();
- // Empty sound slice
- } else if (!hasNextCmd && (_soundEnabled)) {
- soundBuf = new byte[_soundSliceSize];
- assert(soundBuf);
-
- memset(soundBuf, 0, _soundSliceSize);
-
- _audioStream->queueBuffer(soundBuf, _soundSliceSize);
- }
+ } else
+ emptySoundSlice(hasNextCmd);
}
// Set palette
- if (cmd == 0xFFF4) {
+ if (cmd == kCommandPalette) {
_stream->seek(2, SEEK_CUR);
state.flags |= kStatePalette;
@@ -583,8 +735,8 @@ CoktelVideo::State Imd::processFrame(uint16 frame) {
hasNextCmd = false;
- // Jump to frame
- if (cmd == 0xFFFD) {
+ if (cmd == kCommandJump) {
+ // Jump to frame
frame = _stream->readSint16LE();
if (_framesPos) {
@@ -595,37 +747,17 @@ CoktelVideo::State Imd::processFrame(uint16 frame) {
state.flags |= kStateJump;
}
- } else if (cmd == 0xFFFC) {
+ } else if (cmd == kCommandVideoData) {
+ uint32 size = _stream->readUint32LE() + 2;
- state.flags |= 1;
- cmd = _stream->readUint32LE();
- _stream->read(_frameData, cmd + 2);
- _frameDataLen = cmd + 2;
+ videoData(size, state);
- if (_vidMemWidth <= state.right) {
- state.left = 0;
- state.right -= state.left;
- }
- if (_vidMemWidth <= state.right)
- state.right = _vidMemWidth - 1;
- if (_vidMemHeight <= state.bottom) {
- state.top = 0;
- state.bottom -= state.top;
- }
- if (_vidMemHeight <= state.bottom)
- state.bottom = _vidMemHeight -1;
-
- state.flags |= renderFrame(state.left, state.top, state.right, state.bottom);
- state.flags |= _frameData[0];
+ state.flags |= 1;
- // Frame video data
} else if (cmd != 0) {
+ uint32 size = cmd + 2;
- _stream->read(_frameData, cmd + 2);
- _frameDataLen = cmd + 2;
-
- state.flags |= renderFrame(state.left, state.top, state.right, state.bottom);
- state.flags |= _frameData[0];
+ videoData(size, state);
} else
state.flags |= kStateNoVideoData;
@@ -643,24 +775,133 @@ CoktelVideo::State Imd::processFrame(uint16 frame) {
_audioStream->finish();
_mixer->stopHandle(_audioHandle);
_audioStream = 0;
- _soundStage = 0;
+ _soundStage = 0;
}
_lastFrameTime = g_system->getMillis();
return state;
}
+// A whole, completely filled block
+void Imd::renderBlockWhole(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight) {
+
+ int16 w = MIN(width, destWidth);
+ int16 h = MIN(height, destHeight);
+
+ for (int i = 0; i < h; i++) {
+ memcpy(dest, src, w);
+
+ src += width;
+ dest += destWidth;
+ }
+}
+
+// A quarter-wide whole, completely filled block
+void Imd::renderBlockWhole4X(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight) {
+
+ for (int i = 0; i < height; i++) {
+ byte *destBak = dest;
+
+ for (int j = 0; j < width; j += 4, dest += 4, src++)
+ memset(dest, *src, 4);
+
+ dest = destBak + destWidth;
+ }
+}
+
+// A half-high whole, completely filled block
+void Imd::renderBlockWhole2Y(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight) {
+
+ while (height > 1) {
+ memcpy(dest , src, width);
+ memcpy(dest + destWidth, src, width);
+
+ height -= 2;
+ dest += 2 * destWidth;
+ src += width;
+ }
+
+ if (height == 1)
+ memcpy(dest, src, width);
+}
+
+// A sparse block
+void Imd::renderBlockSparse(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight) {
+
+ for (int i = 0; i < height; i++) {
+ byte *destBak = dest;
+ uint16 pixWritten = 0;
+
+ while (pixWritten < width) {
+ uint16 pixCount = *src++;
+
+ if (pixCount & 0x80) { // Data
+ pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten);
+ memcpy(dest, src, pixCount);
+
+ pixWritten += pixCount;
+ dest += pixCount;
+ src += pixCount;
+ } else { // "Hole"
+ pixWritten += pixCount + 1;
+ dest += pixCount + 1;
+ }
+
+ }
+
+ dest = destBak + destWidth;
+ }
+}
+
+// A half-high sparse block
+void Imd::renderBlockSparse2Y(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight) {
+
+ for (int i = 0; i < height; i += 2) {
+ byte *destBak = dest;
+ uint16 pixWritten = 0;
+
+ while (pixWritten < width) {
+ uint16 pixCount = *src++;
+
+ if (pixCount & 0x80) { // Data
+ pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten);
+ memcpy(dest , src, pixCount);
+ memcpy(dest + destWidth, src, pixCount);
+
+ pixWritten += pixCount;
+ dest += pixCount;
+ src += pixCount;
+ } else { // "Hole"
+ pixWritten += pixCount + 1;
+ dest += pixCount + 1;
+ }
+
+ }
+
+ dest = destBak + destWidth;
+ }
+}
+
uint32 Imd::renderFrame(int16 left, int16 top, int16 right, int16 bottom) {
if (!_frameData || !_vidMem || (_width <= 0) || (_height <= 0))
return 0;
uint32 retVal = 0;
- int16 width = right - left + 1;
- int16 height = bottom - top + 1;
- int16 sW = _vidMemWidth;
- byte *dataPtr = _frameData;
+
+ int16 width = right - left + 1;
+ int16 height = bottom - top + 1;
+ int16 sW = _vidMemWidth;
+ int16 sH = _vidMemHeight;
+
+ byte *dataPtr = _frameData;
byte *imdVidMem = _vidMem + sW * top + left;
byte *srcPtr;
+
uint8 type = *dataPtr++;
if (type & 0x10) { // Palette data
@@ -676,88 +917,30 @@ uint32 Imd::renderFrame(int16 left, int16 top, int16 right, int16 bottom) {
srcPtr = dataPtr;
- if (type & 0x80) { // Frame data is compressed
+ if (type & 0x80) {
+ // Frame data is compressed
+
srcPtr = _vidBuffer;
type &= 0x7F;
if ((type == 2) && (width == sW)) {
+ // Directly uncompress onto the video surface
deLZ77(imdVidMem, dataPtr);
return retVal;
} else
deLZ77(srcPtr, dataPtr);
}
- uint16 pixCount, pixWritten;
- byte *imdVidMemBak;
-
- if (type == 2) { // Whole block
- for (int i = 0; i < height; i++) {
- memcpy(imdVidMem, srcPtr, width);
- srcPtr += width;
- imdVidMem += sW;
- }
- } else if (type == 1) { // Sparse block
- imdVidMemBak = imdVidMem;
- for (int i = 0; i < height; i++) {
- pixWritten = 0;
- while (pixWritten < width) {
- pixCount = *srcPtr++;
- if (pixCount & 0x80) { // Data
- pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten);
- memcpy(imdVidMem, srcPtr, pixCount);
-
- pixWritten += pixCount;
- imdVidMem += pixCount;
- srcPtr += pixCount;
- } else { // "Hole"
- pixCount = (pixCount + 1) % 256;
- pixWritten += pixCount;
- imdVidMem += pixCount;
- }
- }
- imdVidMemBak += sW;
- imdVidMem = imdVidMemBak;
- }
- } else if (type == 0x42) { // Whole quarter-wide block
- for (int i = 0; i < height; i++) {
- imdVidMemBak = imdVidMem;
-
- for (int j = 0; j < width; j += 4, imdVidMem += 4, srcPtr++)
- memset(imdVidMem, *srcPtr, 4);
-
- imdVidMemBak += sW;
- imdVidMem = imdVidMemBak;
- }
- } else if ((type & 0xF) == 2) { // Whole half-high block
- for (; height > 1; height -= 2, imdVidMem += sW + sW, srcPtr += width) {
- memcpy(imdVidMem, srcPtr, width);
- memcpy(imdVidMem + sW, srcPtr, width);
- }
- if (height == -1)
- memcpy(imdVidMem, srcPtr, width);
- } else { // Sparse half-high block
- imdVidMemBak = imdVidMem;
- for (int i = 0; i < height; i += 2) {
- pixWritten = 0;
- while (pixWritten < width) {
- pixCount = *srcPtr++;
- if (pixCount & 0x80) { // Data
- pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten);
- memcpy(imdVidMem, srcPtr, pixCount);
- memcpy(imdVidMem + sW, srcPtr, pixCount);
-
- pixWritten += pixCount;
- imdVidMem += pixCount;
- srcPtr += pixCount;
- } else { // "Hole"
- pixCount = (pixCount + 1) % 256;
- pixWritten += pixCount;
- imdVidMem += pixCount;
- }
- }
- imdVidMemBak += sW + sW;
- imdVidMem = imdVidMemBak;
- }
- }
+ // Evaluate the block type
+ if (type == 0x01)
+ renderBlockSparse (imdVidMem, srcPtr, width, height, sW, sH);
+ else if (type == 0x02)
+ renderBlockWhole (imdVidMem, srcPtr, width, height, sW, sH);
+ else if (type == 0x42)
+ renderBlockWhole4X (imdVidMem, srcPtr, width, height, sW, sH);
+ else if ((type & 0x0F) == 0x02)
+ renderBlockWhole2Y (imdVidMem, srcPtr, width, height, sW, sH);
+ else
+ renderBlockSparse2Y(imdVidMem, srcPtr, width, height, sW, sH);
return retVal;
}
@@ -849,7 +1032,45 @@ void Imd::deLZ77(byte *dest, byte *src) {
}
}
-const uint16 Vmd::_tableADPCM[128] = {
+inline void Imd::unsignedToSigned(byte *buffer, int length) {
+ while (length-- > 0) *buffer++ ^= 0x80;
+}
+
+
+Vmd::ExtraData::ExtraData() {
+ memset(name, 0, 16);
+
+ offset = 0;
+ size = 0;
+ realSize = 0;
+}
+
+
+Vmd::Part::Part() {
+ type = kPartTypeSeparator;
+ field_1 = 0;
+ field_E = 0;
+ size = 0;
+ left = 0;
+ top = 0;
+ right = 0;
+ bottom = 0;
+ id = 0;
+ flags = 0;
+}
+
+
+Vmd::Frame::Frame() {
+ parts = 0;
+ offset = 0;
+}
+
+Vmd::Frame::~Frame() {
+ delete[] parts;
+}
+
+
+const uint16 Vmd::_tableDPCM[128] = {
0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080,
0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120,
0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0,
@@ -865,6 +1086,26 @@ const uint16 Vmd::_tableADPCM[128] = {
0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
};
+const int32 Vmd::_tableADPCM[] = {
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 16, 17, 19, 21, 23, 25, 28, 31,
+ 34, 37, 41, 45, 50, 55, 60, 66,
+ 73, 80, 88, 97, 107, 118, 130, 143,
+ 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658,
+ 724, 796, 876, 963, 1060, 1166, 1282, 1411,
+ 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
+ 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
+ 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
+ 32767, 0
+};
+
+const int32 Vmd::_tableADPCMStep[] = {
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+};
+
Vmd::Vmd(Graphics::PaletteLUT *palLUT) : _palLUT(palLUT) {
clear(false);
}
@@ -873,84 +1114,11 @@ Vmd::~Vmd() {
clear();
}
-bool Vmd::load(Common::SeekableReadStream &stream) {
- unload();
-
- _stream = &stream;
-
- uint16 headerLength = _stream->readUint16LE();
- uint16 handle = _stream->readUint16LE();
- _version = _stream->readUint16LE();
-
- if (!(_version & 2))
- _features |= kFeaturesPalette;
- else
- _features |= kFeaturesFullColor;
-
- // 0x4 (4)
-
- // Version checking
- if (headerLength != 814) {
- warning("VMD Version incorrect (%d, %d, %d)", headerLength, handle, _version);
- unload();
- return false;
- }
-
- _framesCount = _stream->readUint16LE();
-
- // 0x6 (6)
-
- _x = _stream->readSint16LE();
- _y = _stream->readSint16LE();
- _width = _stream->readSint16LE();
- _height = _stream->readSint16LE();
-
- // 0xE (14)
-
- if ((_width != 0) && (_height != 0)) {
- _hasVideo = true;
- _features |= kFeaturesVideo;
- if (_features & kFeaturesFullColor)
- _codecIndeo3 = new Indeo3(_width, _height, _palLUT);
- } else
- _hasVideo = false;
-
- if (_width > 320) {
- if (!(_version & 4)) {
- _version |= 4;
- handle = 0;
- }
- }
-
- if (handle > 2) {
- warning("VMD Version incorrect (%d, %d, %d)", headerLength, handle, _version);
- unload();
- return false;
- }
-
- _bytesPerPixel = handle + 1;
-
- if (_bytesPerPixel > 1) {
+bool Vmd::assessVideoProperties() {
+ if (_bytesPerPixel > 1)
_features |= kFeaturesFullColor;
- _features &= ~kFeaturesPalette;
- }
-
- _flags = _stream->readUint16LE();
-
- _partsPerFrame = _stream->readUint16LE();
- _firstFramePos = _stream->readUint32LE();
- _stream->skip(4); // Unknown
-
- // 0x1A (26)
-
- _stream->read((byte *) _palette, 768);
-
- // 0x31A (794)
-
- _frameDataSize = _stream->readUint32LE();
- _vidBufferSize = _stream->readUint32LE();
-
- _doubleMode = false;
+ else
+ _features |= kFeaturesPalette;
if ((_version & 2) && !(_version & 8)) {
_externalCodec = true;
@@ -958,7 +1126,21 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
} else
_externalCodec = false;
- _preScaleX = 1;
+ if (_externalCodec) {
+ if (_videoCodec == MKID_BE('iv32')) {
+ _features &= ~kFeaturesPalette;
+ _features |= kFeaturesFullColor;
+ _codecIndeo3 = new Indeo3(_width, _height, _palLUT);
+ } else {
+ char *fourcc = (char *) &_videoCodec;
+
+ warning("Vmd::assessVideoProperties(): Unknow video codec FourCC \'%c%c%c%c\'",
+ fourcc[3], fourcc[2], fourcc[1], fourcc[0]);
+ return false;
+ }
+ }
+
+ _preScaleX = 1;
_postScaleX = 1;
if (_externalCodec)
@@ -971,10 +1153,10 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
_blitMode = n - 1;
if (_bytesPerPixel == 2) {
- _preScaleX = n;
+ _preScaleX = n;
_postScaleX = 1;
} else if (_bytesPerPixel == 3) {
- _preScaleX = 1;
+ _preScaleX = 1;
_postScaleX = n;
}
@@ -985,8 +1167,6 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
if (!_externalCodec && !(_flags & 0x1000))
_scaleExternalX = _bytesPerPixel;
- // 0x322 (802)
-
if (_hasVideo) {
if ((_frameDataSize == 0) || (_frameDataSize > 1048576))
_frameDataSize = _width * _height + 1000;
@@ -1010,42 +1190,75 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
if (_externalCodec && _codecIndeo3)
_features |= kFeaturesSupportsDouble;
- _soundFreq = _stream->readSint16LE();
- _soundSliceSize = _stream->readSint16LE();
- _soundSlicesCount = _stream->readSint16LE();
- _soundFlags = _stream->readUint16LE();
- _hasSound = (_soundFreq != 0);
+ return true;
+}
- // 0x32A (810)
+bool Vmd::assessAudioProperties() {
+ bool supportedFormat = true;
- if (_hasSound) {
- _features |= kFeaturesSound;
+ _features |= kFeaturesSound;
- _soundStereo = (_soundFlags & 0x8000) ? 1 : ((_soundFlags & 0x200) ? 2 : 0);
- if (_soundStereo > 0) {
- warning("TODO: VMD stereo");
- unload();
- return false;
- }
+ _soundStereo = (_soundFlags & 0x8000) ? 1 : ((_soundFlags & 0x200) ? 2 : 0);
+
+ if (_soundSliceSize < 0) {
+ _soundBytesPerSample = 2;
+ _soundSliceSize = -_soundSliceSize;
+
+ if (_soundFlags & 0x10) {
+ _audioFormat = kAudioFormat16bitADPCM;
+ _soundHeaderSize = 3;
+ _soundDataSize = _soundSliceSize >> 1;
+
+ if (_soundStereo > 0)
+ supportedFormat = false;
+
+ } else {
+ _audioFormat = kAudioFormat16bitDPCM;
+ _soundHeaderSize = 1;
+ _soundDataSize = _soundSliceSize;
+
+ if (_soundStereo == 1) {
+ supportedFormat = false;
+ } else if (_soundStereo == 2) {
+ _soundDataSize = 2 * _soundDataSize + 2;
+ _soundHeaderSize = 4;
+ }
- if (_soundSliceSize < 0) {
- _soundBytesPerSample = 2;
- _soundSliceSize = -_soundSliceSize;
}
+ } else {
+ _soundBytesPerSample = 1;
+ _audioFormat = kAudioFormat8bitDirect;
+ _soundHeaderSize = 0;
+ _soundDataSize = _soundSliceSize;
- _soundSliceLength = (uint32) (((double) (1000 << 16)) /
- ((double) _soundFreq / (double) _soundSliceSize));
- _frameLength = _soundSliceLength >> 16;
+ if (_soundStereo > 0)
+ supportedFormat = false;
+ }
- _soundStage = 1;
- _audioStream = Audio::makeAppendableAudioStream(_soundFreq,
- (_soundBytesPerSample == 2) ? Audio::Mixer::FLAG_16BITS : 0);
- } else
- _frameLength = 1000 / _frameRate;
+ if (!supportedFormat) {
+ warning("Vmd::assessAudioProperties(): Unsupported audio format: %d bits, encoding %d, stereo %d",
+ _soundBytesPerSample * 8, _audioFormat, _soundStereo);
+ return false;
+ }
- _frameInfoOffset = _stream->readUint32LE();
+ _soundSliceLength = (uint32) (((double) (1000 << 16)) /
+ ((double) _soundFreq / (double) _soundSliceSize));
+ _frameLength = _soundSliceLength >> 16;
+
+ _soundStage = 1;
+
+ uint32 flags = 0;
+
+ flags |= (_soundBytesPerSample == 2) ? Audio::Mixer::FLAG_16BITS : 0;
+ flags |= (_soundStereo > 0) ? Audio::Mixer::FLAG_STEREO : 0;
+
+ _audioStream = Audio::makeAppendableAudioStream(_soundFreq, flags);
- int numExtraData = 0;
+ return true;
+}
+
+void Vmd::readFrameTable(int &numExtraData) {
+ numExtraData = 0;
_stream->seek(_frameInfoOffset);
_frames = new Frame[_framesCount];
@@ -1054,14 +1267,15 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
_stream->skip(2); // Unknown
_frames[i].offset = _stream->readUint32LE();
}
+
for (uint16 i = 0; i < _framesCount; i++) {
bool separator = false;
for (uint16 j = 0; j < _partsPerFrame; j++) {
- _frames[i].parts[j].type = (PartType) _stream->readByte();
+ _frames[i].parts[j].type = (PartType) _stream->readByte();
_frames[i].parts[j].field_1 = _stream->readByte();
- _frames[i].parts[j].size = _stream->readUint32LE();
+ _frames[i].parts[j].size = _stream->readUint32LE();
if (_frames[i].parts[j].type == kPartTypeAudio) {
@@ -1070,13 +1284,17 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
} else if (_frames[i].parts[j].type == kPartTypeVideo) {
- _frames[i].parts[j].left = _stream->readUint16LE();
- _frames[i].parts[j].top = _stream->readUint16LE();
- _frames[i].parts[j].right = _stream->readUint16LE();
- _frames[i].parts[j].bottom = _stream->readUint16LE();
+ _frames[i].parts[j].left = _stream->readUint16LE();
+ _frames[i].parts[j].top = _stream->readUint16LE();
+ _frames[i].parts[j].right = _stream->readUint16LE();
+ _frames[i].parts[j].bottom = _stream->readUint16LE();
_frames[i].parts[j].field_E = _stream->readByte();
- _frames[i].parts[j].flags = _stream->readByte();
+ _frames[i].parts[j].flags = _stream->readByte();
+ } else if (_frames[i].parts[j].type == kPartTypeSpeech) {
+ _frames[i].parts[j].id = _stream->readUint16LE();
+ // Speech text file name
+ _stream->skip(8);
} else if (_frames[i].parts[j].type == kPartTypeExtraData) {
if (!separator)
numExtraData++;
@@ -1091,16 +1309,9 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
}
}
+}
- _stream->seek(_firstFramePos);
-
- if (numExtraData == 0)
- return true;
-
- _extraData.reserve(numExtraData);
-
- numExtraData = 0;
-
+void Vmd::readExtraData() {
uint32 ssize = _stream->size();
for (uint16 i = 0; i < _framesCount; i++) {
_stream->seek(_frames[i].offset);
@@ -1112,9 +1323,10 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
if (_frames[i].parts[j].type == kPartTypeExtraData) {
ExtraData data;
- data.offset = _stream->pos() + 20;
- data.size = _frames[i].parts[j].size;
+ data.offset = _stream->pos() + 20;
+ data.size = _frames[i].parts[j].size;
data.realSize = _stream->readUint32LE();
+
_stream->read(data.name, 16);
data.name[15] = '\0';
@@ -1129,6 +1341,110 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
_stream->skip(_frames[i].parts[j].size);
}
}
+}
+
+bool Vmd::load(Common::SeekableReadStream &stream) {
+ unload();
+
+ _stream = &stream;
+
+ uint16 headerLength;
+ uint16 handle;
+
+ headerLength = _stream->readUint16LE();
+ handle = _stream->readUint16LE();
+ _version = _stream->readUint16LE();
+
+ bool readPalette;
+
+ // Version checking
+ if (headerLength == 50) {
+ // Newer version, used in Addy 5 upwards
+ warning("Vmd::load(): TODO: Addy 5 videos");
+ readPalette = false;
+ } else if (headerLength == 814) {
+ // Old version
+ readPalette = true;
+ } else {
+ warning("Vmd::load(): Version incorrect (%d, %d, %d)", headerLength, handle, _version);
+ unload();
+ return false;
+ }
+
+ _framesCount = _stream->readUint16LE();
+
+ _x = _stream->readSint16LE();
+ _y = _stream->readSint16LE();
+ _width = _stream->readSint16LE();
+ _height = _stream->readSint16LE();
+
+ if ((_width != 0) && (_height != 0)) {
+
+ _hasVideo = true;
+ _features |= kFeaturesVideo;
+
+ } else
+ _hasVideo = false;
+
+ _bytesPerPixel = 1;
+ if (_version & 4)
+ _bytesPerPixel = handle + 1;
+
+ if (_bytesPerPixel > 3) {
+ warning("Vmd::load(): Requested %d bytes per pixel (%d, %d, %d)", _bytesPerPixel, headerLength, handle, _version);
+ unload();
+ return false;
+ }
+
+ _flags = _stream->readUint16LE();
+
+ _partsPerFrame = _stream->readUint16LE();
+ _firstFramePos = _stream->readUint32LE();
+
+ _videoCodec = _stream->readUint32BE();
+
+ if (readPalette)
+ _stream->read((byte *) _palette, 768);
+
+ _frameDataSize = _stream->readUint32LE();
+ _vidBufferSize = _stream->readUint32LE();
+
+ _doubleMode = false;
+
+ if (_hasVideo) {
+ if (!assessVideoProperties()) {
+ unload();
+ return false;
+ }
+ }
+
+ _soundFreq = _stream->readSint16LE();
+ _soundSliceSize = _stream->readSint16LE();
+ _soundSlicesCount = _stream->readSint16LE();
+ _soundFlags = _stream->readUint16LE();
+
+ _hasSound = (_soundFreq != 0);
+
+ if (_hasSound) {
+ if (!assessAudioProperties()) {
+ unload();
+ return false;
+ }
+ } else
+ _frameLength = 1000 / _frameRate;
+
+ _frameInfoOffset = _stream->readUint32LE();
+
+ int numExtraData;
+ readFrameTable(numExtraData);
+
+ _stream->seek(_firstFramePos);
+
+ if (numExtraData == 0)
+ return true;
+
+ _extraData.reserve(numExtraData);
+ readExtraData();
_stream->seek(_firstFramePos);
return true;
@@ -1151,11 +1467,11 @@ void Vmd::setXY(int16 x, int16 y) {
if (_frames[i].parts[j].type == kPartTypeVideo) {
if (x >= 0) {
- _frames[i].parts[j].left = _frames[i].parts[j].left - _x + x;
+ _frames[i].parts[j].left = _frames[i].parts[j].left - _x + x;
_frames[i].parts[j].right = _frames[i].parts[j].right - _x + x;
}
if (y >= 0) {
- _frames[i].parts[j].top = _frames[i].parts[j].top - _y + y;
+ _frames[i].parts[j].top = _frames[i].parts[j].top - _y + y;
_frames[i].parts[j].bottom = _frames[i].parts[j].bottom - _y + y;
}
}
@@ -1243,7 +1559,8 @@ void Vmd::clear(bool del) {
delete[] _vidMemBuffer;
}
- _hasVideo = true;
+ _hasVideo = true;
+ _videoCodec = 0;
_codecIndeo3 = 0;
@@ -1253,16 +1570,19 @@ void Vmd::clear(bool del) {
_extraData.clear();
_soundBytesPerSample = 1;
- _soundStereo = 0;
-
- _externalCodec = false;
- _doubleMode = false;
- _blitMode = 0;
- _bytesPerPixel = 1;
- _preScaleX = 1;
- _postScaleX = 1;
+ _soundStereo = 0;
+ _soundHeaderSize = 0;
+ _soundDataSize = 0;
+ _audioFormat = kAudioFormat8bitDirect;
+
+ _externalCodec = false;
+ _doubleMode = false;
+ _blitMode = 0;
+ _bytesPerPixel = 1;
+ _preScaleX = 1;
+ _postScaleX = 1;
_scaleExternalX = 1;
- _vidMemBuffer = 0;
+ _vidMemBuffer = 0;
}
CoktelVideo::State Vmd::processFrame(uint16 frame) {
@@ -1272,15 +1592,17 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) {
seekFrame(frame);
state.flags |= kStateNoVideoData;
- state.left = 0x7FFF;
- state.top = 0x7FFF;
- state.right = 0;
+ state.left = 0x7FFF;
+ state.top = 0x7FFF;
+ state.right = 0;
state.bottom = 0;
if (!_vidMem)
setVideoMemory();
for (uint16 i = 0; (i < _partsPerFrame) && (frame < _framesCount); i++) {
+ uint32 pos = _stream->pos();
+
Part &part = _frames[frame].parts[i];
if (part.type == kPartTypeAudio) {
@@ -1313,20 +1635,27 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) {
} else if (part.flags == 3) {
if (_soundEnabled) {
- emptySoundSlice(_soundSliceSize * _soundBytesPerSample);
+ emptySoundSlice(_soundDataSize * _soundBytesPerSample);
if (_soundStage == 1)
startSound = true;
}
_stream->skip(part.size);
+ } else if (part.flags == 4) {
+ warning("Vmd::processFrame(): TODO: Addy 5 sound type 4 (%d)", part.size);
+ disableSound();
+ _stream->skip(part.size);
} else {
- warning("Unknown sound part type %d", part.flags);
+ warning("Vmd::processFrame(): Unknown sound type %d", part.flags);
_stream->skip(part.size);
}
+ _stream->seek(pos + part.size);
+
} else if ((part.type == kPartTypeVideo) && !_hasVideo) {
- warning("Header claims there's no video, but video frame part found");
+ warning("Vmd::processFrame(): Header claims there's no video, but video found (%d)", part.size);
+ _stream->skip(part.size);
} else if ((part.type == kPartTypeVideo) && _hasVideo) {
state.flags &= ~kStateNoVideoData;
@@ -1361,12 +1690,19 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) {
state.bottom = MAX(state.bottom, b);
}
- } else if (part.type == 4) {
+ } else if (part.type == kPartTypeSeparator) {
+ } else if (part.type == kPartTypeExtraData) {
+ _stream->skip(part.size);
+ } else if (part.type == kPartType4) {
// Unknown
_stream->skip(part.size);
+ } else if (part.type == kPartTypeSpeech) {
+ state.flags |= kStateSpeech;
+ state.speechId = part.id;
+ // Always triggers when speech starts
+ _stream->skip(part.size);
} else {
- // Unknow type
-// warning("Unknown frame part type %d, size %d (%d of %d)", part.type, part.size, i + 1, _partsPerFrame);
+ warning("Vmd::processFrame(): Unknown frame part type %d, size %d (%d of %d)", part.type, part.size, i + 1, _partsPerFrame);
}
}
@@ -1380,7 +1716,7 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) {
_audioStream->finish();
_mixer->stopHandle(_audioHandle);
_audioStream = 0;
- _soundStage = 0;
+ _soundStage = 0;
}
// If these are still 0x7FFF, no video data has been processed
@@ -1391,7 +1727,7 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) {
return state;
}
-void Vmd::deRLE(byte *&srcPtr, byte *&destPtr, int16 len) {
+void Vmd::deRLE(byte *&destPtr, const byte *&srcPtr, int16 len) {
srcPtr++;
if (len & 1)
@@ -1418,23 +1754,60 @@ void Vmd::deRLE(byte *&srcPtr, byte *&destPtr, int16 len) {
}
}
+// A run-length-encoded sparse block
+void Vmd::renderBlockRLE(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight) {
+
+ for (int i = 0; i < height; i++) {
+ byte *destBak = dest;
+ uint16 pixWritten = 0;
+
+ while (pixWritten < width) {
+ uint16 pixCount = *src++;
+
+ if (pixCount & 0x80) {
+ pixCount = (pixCount & 0x7F) + 1;
+
+ if (*src != 0xFF) { // Normal copy
+ memcpy(dest, src, pixCount);
+ dest += pixCount;
+ src += pixCount;
+ } else
+ deRLE(dest, src, pixCount);
+
+ pixWritten += pixCount;
+ } else { // "Hole"
+ dest += pixCount + 1;
+ pixWritten += pixCount + 1;
+ }
+
+ }
+
+ dest = destBak + destWidth;
+ }
+
+}
+
uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) {
if (!_frameData || !_vidMem || (_width <= 0) || (_height <= 0))
return 0;
- int16 width = right - left + 1;
- int16 height = bottom - top + 1;
- int16 sW = _vidMemWidth;
- int16 sH = _vidMemHeight;
+ int16 width = right - left + 1;
+ int16 height = bottom - top + 1;
+ int16 sW = _vidMemWidth;
+ int16 sH = _vidMemHeight;
uint32 dataLen = _frameDataLen;
- byte *dataPtr = _frameData;
+
+ byte *dataPtr = _frameData;
byte *imdVidMem = _vidMem + sW * top + left;
byte *srcPtr;
- uint8 type;
- if ((width < 0) || (height < 0))
+ if ((left < 0) || (top < 0) || (right < 0) || (bottom < 0))
+ return 1;
+ if ((width <= 0) || (height <= 0))
return 1;
+ uint8 type;
byte *dest = imdVidMem;
if (Indeo3::isIndeo3(dataPtr, dataLen)) {
@@ -1445,12 +1818,12 @@ uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) {
width * (_doubleMode ? 2 : 1), height * (_doubleMode ? 2 : 1)))
return 0;
- type = 2;
+ type = 2;
srcPtr = _vidBuffer;
- width = _width * (_doubleMode ? 2 : 1);
+ width = _width * (_doubleMode ? 2 : 1);
height = _height * (_doubleMode ? 2 : 1);
- right = left + width - 1;
- bottom = top + height - 1;
+ right = left + width - 1;
+ bottom = top + height - 1;
} else {
@@ -1459,8 +1832,8 @@ uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) {
return 0;
}
- type = *dataPtr++;
- srcPtr = dataPtr;
+ type = *dataPtr++;
+ srcPtr = dataPtr;
if (_blitMode > 0) {
dest = _vidMemBuffer + postScaleX(_width) * (top - _y) + postScaleX((left - _x));
@@ -1469,10 +1842,13 @@ uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) {
sH = _height;
}
- if (type & 0x80) { // Frame data is compressed
+ if (type & 0x80) {
+ // Frame data is compressed
+
srcPtr = _vidBuffer;
type &= 0x7F;
if ((type == 2) && (postScaleX(width) == sW)) {
+ // Directly uncompress onto the video surface
deLZ77(dest, dataPtr);
blit(imdVidMem, dest, width, height);
return 1;
@@ -1482,109 +1858,22 @@ uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) {
}
- uint16 pixCount, pixWritten;
- byte *destBak;
-
- if (type == 1) { // Sparse block
- destBak = dest;
- for (int i = 0; i < height; i++) {
- pixWritten = 0;
- while (pixWritten < postScaleX(width)) {
- pixCount = *srcPtr++;
- if (pixCount & 0x80) { // Data
- pixCount = MIN<int>((pixCount & 0x7F) + 1, postScaleX(width) - pixWritten);
- memcpy(dest, srcPtr, pixCount);
-
- pixWritten += pixCount;
- dest += pixCount;
- srcPtr += pixCount;
- } else { // "Hole"
- pixCount = (pixCount + 1) % 256;
- pixWritten += pixCount;
- dest += pixCount;
- }
- }
- destBak += sW;
- dest = destBak;
- }
- } else if (type == 2) { // Whole block
- int16 w = MIN<int32>(postScaleX(width), sW);
- int16 h = MIN(height, sH);
-
- for (int i = 0; i < h; i++) {
- memcpy(dest, srcPtr, w);
- srcPtr += postScaleX(width);
- dest += sW;
- }
-
- } else if (type == 3) { // RLE block
- for (int i = 0; i < height; i++) {
- destBak = dest;
-
- pixWritten = 0;
- while (pixWritten < width) {
- pixCount = *srcPtr++;
- if (pixCount & 0x80) {
- pixCount = (pixCount & 0x7F) + 1;
-
- if (*srcPtr != 0xFF) { // Normal copy
- memcpy(dest, srcPtr, pixCount);
- dest += pixCount;
- srcPtr += pixCount;
- } else
- deRLE(srcPtr, dest, pixCount);
-
- pixWritten += pixCount;
- } else { // "Hole"
- dest += pixCount + 1;
- pixWritten += pixCount + 1;
- }
-
- }
- destBak += sW;
- dest = destBak;
- }
- } else if (type == 0x42) { // Whole quarter-wide block
- for (int i = 0; i < height; i++) {
- destBak = dest;
+ width = postScaleX(width);
+
+ // Evaluate the block type
+ if (type == 0x01)
+ renderBlockSparse (dest, srcPtr, width, height, sW, sH);
+ else if (type == 0x02)
+ renderBlockWhole (dest, srcPtr, width, height, sW, sH);
+ else if (type == 0x03)
+ renderBlockRLE (dest, srcPtr, width, height, sW, sH);
+ else if (type == 0x42)
+ renderBlockWhole4X (dest, srcPtr, width, height, sW, sH);
+ else if ((type & 0x0F) == 0x02)
+ renderBlockWhole2Y (dest, srcPtr, width, height, sW, sH);
+ else
+ renderBlockSparse2Y(dest, srcPtr, width, height, sW, sH);
- for (int j = 0; j < width; j += 4, dest += 4, srcPtr++)
- memset(dest, *srcPtr, 4);
-
- destBak += sW;
- dest = destBak;
- }
- } else if ((type & 0xF) == 2) { // Whole half-high block
- for (; height > 1; height -= 2, dest += sW + sW, srcPtr += width) {
- memcpy(dest, srcPtr, width);
- memcpy(dest + sW, srcPtr, width);
- }
- if (height == -1)
- memcpy(dest, srcPtr, width);
- } else { // Sparse half-high block
- destBak = dest;
- for (int i = 0; i < height; i += 2) {
- pixWritten = 0;
- while (pixWritten < width) {
- pixCount = *srcPtr++;
- if (pixCount & 0x80) { // Data
- pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten);
- memcpy(dest, srcPtr, pixCount);
- memcpy(dest + sW, srcPtr, pixCount);
-
- pixWritten += pixCount;
- dest += pixCount;
- srcPtr += pixCount;
- } else { // "Hole"
- pixCount = (pixCount + 1) % 256;
- pixWritten += pixCount;
- dest += pixCount;
- }
- }
- destBak += sW + sW;
- dest = destBak;
- }
- }
dest = _vidMemBuffer + postScaleX(_width) * (top - _y) + postScaleX(left - _x);
blit(imdVidMem, dest, width, height);
@@ -1673,129 +1962,278 @@ void Vmd::blit24(byte *dest, byte *src, int16 srcPitch, int16 width, int16 heigh
dither->nextLine();
dest += _vidMemWidth;
- src += 3 * srcPitch;
+ src += 3 * srcPitch;
}
delete dither;
}
-void Vmd::emptySoundSlice(uint32 size) {
- if (!_audioStream)
- return;
+byte *Vmd::deDPCM(const byte *data, uint32 &size, int32 init[2]) {
+ if (!data || (size == 0))
+ return 0;
- byte *soundBuf = new byte[size];
- assert(soundBuf);
+ int channels = (_soundStereo > 0) ? 2 : 1;
- memset(soundBuf, 0, size);
+ uint32 inSize = size;
+ uint32 outSize = size + channels;
+
+ int16 *out = new int16[outSize];
+ byte *sound = (byte *) out;
+
+ int channel = 0;
+
+ for (int i = 0; i < channels; i++) {
+ *out++ = TO_BE_16(init[channel]);
- _audioStream->queueBuffer(soundBuf, size);
+ channel = (channel + 1) % channels;
+ }
+
+ while (inSize-- > 0) {
+ if (*data & 0x80)
+ init[channel] -= _tableDPCM[*data++ & 0x7F];
+ else
+ init[channel] += _tableDPCM[*data++];
+
+ init[channel] = CLIP<int32>(init[channel], -32768, 32767);
+ *out++ = TO_BE_16(init[channel]);
+
+ channel = (channel + 1) % channels;
+ }
+
+ size = outSize * 2;
+ return sound;
}
-void Vmd::soundSlice8bit(uint32 size) {
+// Yet another IMA ADPCM variant
+byte *Vmd::deADPCM(const byte *data, uint32 &size, int32 init, int32 index) {
+ if (!data || (size == 0))
+ return 0;
+
+ uint32 outSize = size * 2;
+
+ int16 *out = new int16[outSize];
+ byte *sound = (byte *) out;
+
+ index = CLIP<int32>(index, 0, 88);
+
+ int32 predictor = _tableADPCM[index];
+
+ uint32 dataByte = 0;
+ bool newByte = true;
+
+ size *= 2;
+ while (size -- > 0) {
+ byte code = 0;
+
+ if (newByte) {
+ dataByte = *data++;
+ code = (dataByte >> 4) & 0xF;
+ } else
+ code = dataByte & 0xF;
+
+ newByte = !newByte;
+
+ index += _tableADPCMStep[code];
+ index = CLIP<int32>(index, 0, 88);
+
+ int32 value = predictor / 8;
+
+ if (code & 4)
+ value += predictor;
+ if (code & 2)
+ value += predictor / 2;
+ if (code & 1)
+ value += predictor / 4;
+
+ if (code & 8)
+ init -= value;
+ else
+ init += value;
+
+ init = CLIP<int32>(init, -32768, 32767);
+
+ predictor = _tableADPCM[index];
+
+ *out++ = TO_BE_16(init);
+ }
+
+ size = outSize * 2;
+ return sound;
+}
+
+byte *Vmd::soundEmpty(uint32 &size) {
if (!_audioStream)
- return;
+ return 0;
byte *soundBuf = new byte[size];
- assert(soundBuf);
+ memset(soundBuf, 0, size);
+
+ return soundBuf;
+}
+byte *Vmd::sound8bitDirect(uint32 &size) {
+ if (!_audioStream) {
+ _stream->skip(size);
+ return 0;
+ }
+
+ byte *soundBuf = new byte[size];
_stream->read(soundBuf, size);
unsignedToSigned(soundBuf, size);
- _audioStream->queueBuffer(soundBuf, size);
+ return soundBuf;
}
-void Vmd::soundSlice16bit(uint32 size, int16 &init) {
- if (!_audioStream)
- return;
+byte *Vmd::sound16bitDPCM(uint32 &size) {
+ if (!_audioStream) {
+ _stream->skip(size);
+ return 0;
+ }
- byte *dataBuf = new byte[size];
- byte *soundBuf = new byte[size * 2];
+ int32 init[2];
- _stream->read(dataBuf, size);
- deADPCM(soundBuf, dataBuf, init, size);
- _audioStream->queueBuffer(soundBuf, size * 2);
+ init[0] = _stream->readSint16LE();
+ size -= 2;
+
+ if (_soundStereo > 0) {
+ init[1] = _stream->readSint16LE();
+ size -= 2;
+ }
- delete[] dataBuf;
+ byte *data = new byte[size];
+ byte *sound = 0;
+
+ if (_stream->read(data, size) == size)
+ sound = deDPCM(data, size, init);
+
+ delete[] data;
+
+ return sound;
}
-void Vmd::filledSoundSlice(uint32 size) {
- if (_soundBytesPerSample == 1) {
- soundSlice8bit(size);
- } else if (_soundBytesPerSample == 2) {
- int16 init = _stream->readSint16LE();
- soundSlice16bit(size - 2, init);
+byte *Vmd::sound16bitADPCM(uint32 &size) {
+ if (!_audioStream) {
+ _stream->skip(size);
+ return 0;
}
+
+ int32 init = _stream->readSint16LE();
+ size -= 2;
+
+ int32 index = _stream->readByte();
+ size--;
+
+ byte *data = new byte[size];
+ byte *sound = 0;
+
+ if (_stream->read(data, size) == size)
+ sound = deADPCM(data, size, init, index);
+
+ delete[] data;
+
+ return sound;
}
-void Vmd::filledSoundSlices(uint32 size, uint32 mask) {
- int n = MIN<int>(_soundSlicesCount - 1, 31);
- for (int i = 0; i < n; i++) {
+void Vmd::emptySoundSlice(uint32 size) {
+ byte *sound = soundEmpty(size);
- if (mask & 1)
- emptySoundSlice(_soundSliceSize * _soundBytesPerSample);
- else
- filledSoundSlice(_soundSliceSize + 1);
+ if (sound)
+ _audioStream->queueBuffer(sound, size);
+}
+
+void Vmd::filledSoundSlice(uint32 size) {
+ byte *sound = 0;
+ if (_audioFormat == kAudioFormat8bitDirect)
+ sound = sound8bitDirect(size);
+ else if (_audioFormat == kAudioFormat16bitDPCM)
+ sound = sound16bitDPCM(size);
+ else if (_audioFormat == kAudioFormat16bitADPCM)
+ sound = sound16bitADPCM(size);
+
+ if (sound)
+ _audioStream->queueBuffer(sound, size);
+}
+
+uint8 Vmd::evaluateMask(uint32 mask, bool *fillInfo, uint8 &max) {
+ max = MIN<int>(_soundSlicesCount - 1, 31);
+
+ uint8 n = 0;
+ for (int i = 0; i < max; i++) {
+
+ if (!(mask & 1)) {
+ n++;
+ *fillInfo++ = true;
+ } else
+ *fillInfo++ = false;
mask >>= 1;
}
- if (_soundSlicesCount > 32)
- filledSoundSlice((_soundSlicesCount - 32) * _soundSliceSize);
+
+ return n;
}
-void Vmd::deADPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n) {
- int16 *out = (int16 *) soundBuf;
+void Vmd::filledSoundSlices(uint32 size, uint32 mask) {
+ bool fillInfo[32];
+
+ uint8 max;
+ uint8 n = evaluateMask(mask, fillInfo, max);
+
+ int32 extraSize;
+
+ extraSize = size - n * _soundDataSize;
+
+ if (_soundSlicesCount > 32)
+ extraSize -= (_soundSlicesCount - 32) * _soundDataSize;
+
+ if (n > 0)
+ extraSize /= n;
- int32 s = init;
- for (uint32 i = 0; i < n; i++) {
- if (dataBuf[i] & 0x80)
- s -= _tableADPCM[dataBuf[i] & 0x7F];
+ for (uint8 i = 0; i < max; i++)
+ if (fillInfo[i])
+ filledSoundSlice(_soundDataSize + extraSize);
else
- s += _tableADPCM[dataBuf[i]];
+ emptySoundSlice(_soundDataSize * _soundBytesPerSample);
- s = CLIP<int32>(s, -32768, 32767);
- *out++ = TO_BE_16(s);
- }
+ if (_soundSlicesCount > 32)
+ filledSoundSlice((_soundSlicesCount - 32) * _soundDataSize + _soundHeaderSize);
}
-bool Vmd::getAnchor(int16 frame, uint16 partType,
+bool Vmd::getPartCoords(int16 frame, PartType type,
int16 &x, int16 &y, int16 &width, int16 &height) {
- uint32 pos = _stream->pos();
+ if (frame >= _framesCount)
+ return false;
- _stream->seek(_frameInfoOffset);
- // Offsets to frames
- _stream->skip(_framesCount * 6);
- // Jump to the specified frame
- _stream->skip(_partsPerFrame * frame * 16);
+ Frame &f = _frames[frame];
- // Find the anchor part
- uint16 i;
- for (i = 0; i < _partsPerFrame; i++) {
- byte type = _stream->readByte();
+ // Look for a part matching the requested type, stopping at a separator
+ Part *part = 0;
+ for (int i = 0; i < _partsPerFrame; i++) {
+ Part &p = f.parts[i];
- if ((type == kPartTypeSeparator) || (type == partType))
+ if ((p.type == kPartTypeSeparator) || (p.type == type)) {
+ part = &p;
break;
-
- _stream->skip(15);
+ }
}
- if (i == _partsPerFrame) {
- // No anchor
-
- _stream->seek(pos);
+ if (!part)
return false;
- }
- _stream->skip(5);
- x = _stream->readSint16LE();
- y = _stream->readSint16LE();
- width = _stream->readSint16LE() - x + 1;
- height = _stream->readSint16LE() - y + 1;
+ x = part->left;
+ y = part->top;
+ width = part->right - part->left + 1;
+ height = part->bottom - part->top + 1;
- _stream->seek(pos);
return true;
}
+bool Vmd::getFrameCoords(int16 frame,
+ int16 &x, int16 &y, int16 &width, int16 &height) {
+
+ return getPartCoords(frame, kPartTypeVideo, x, y, width, height);
+}
+
bool Vmd::hasExtraData(const char *fileName) const {
for (uint i = 0; i < _extraData.size(); i++)
if (!scumm_stricmp(_extraData[i].name, fileName))
diff --git a/graphics/video/coktelvideo/coktelvideo.h b/graphics/video/coktelvideo/coktelvideo.h
index 58b56e18ec..db80b4c43d 100644
--- a/graphics/video/coktelvideo/coktelvideo.h
+++ b/graphics/video/coktelvideo/coktelvideo.h
@@ -76,7 +76,9 @@ public:
/** Had to explicitely seek to the frame. */
kStateSeeked = 0x2000,
/** Reached a break-point. */
- kStateBreak = 0x8000
+ kStateBreak = 0x8000,
+ /** Frame marks the beginning of speech. */
+ kStateSpeech = 0x4000000
};
struct State {
@@ -90,8 +92,10 @@ public:
int16 bottom;
/** Set accordingly to what was done. */
uint32 flags;
+ /** The id of the spoken words. */
+ uint16 speechId;
- State() : left(0), top(0), right(0), bottom(0), flags(0) { }
+ State() : left(0), top(0), right(0), bottom(0), flags(0), speechId(0) { }
};
virtual ~CoktelVideo() { }
@@ -123,8 +127,8 @@ public:
/** Returns the current frame's palette. */
virtual const byte *getPalette() const = 0;
- /** Reads the video's anchor pointer */
- virtual bool getAnchor(int16 frame, uint16 partType,
+ /** Returns the frame's coordinates */
+ virtual bool getFrameCoords(int16 frame,
int16 &x, int16 &y, int16 &width, int16 &height) = 0;
/** Returns whether that extra data file exists */
@@ -171,9 +175,6 @@ public:
/** Wait for the frame to end. */
virtual void waitEndFrame() = 0;
- /** Notifies the video that it was paused for duration ms. */
- virtual void notifyPaused(uint32 duration) = 0;
-
/** Copy the current frame.
*
* @param dest The memory to which to copy the current frame.
@@ -198,29 +199,26 @@ public:
Imd();
~Imd();
- uint32 getFeatures() const { return _features; }
- uint16 getFlags() const { return _flags; }
- int16 getX() const { return _x; }
- int16 getY() const { return _y; }
- int16 getWidth() const { return _width; }
- int16 getHeight() const { return _height; }
- uint16 getFramesCount() const { return _framesCount; }
- uint16 getCurrentFrame() const { return _curFrame; }
- int16 getFrameRate() const {
- if (_hasSound)
- return 1000 / (_soundSliceLength >> 16);
- return _frameRate;
- }
- uint32 getSyncLag() const { return _skipFrames; }
- const byte *getPalette() const { return _palette; }
-
- bool getAnchor(int16 frame, uint16 partType,
- int16 &x, int16 &y, int16 &width, int16 &height) { return false; }
-
- bool hasExtraData(const char *fileName) const { return false; }
- Common::MemoryReadStream *getExtraData(const char *fileName) { return 0; }
-
- void notifyPaused(uint32 duration) { }
+ uint32 getFeatures() const;
+ uint16 getFlags() const;
+
+ int16 getX() const;
+ int16 getY() const;
+ int16 getWidth() const;
+ int16 getHeight() const;
+
+ uint16 getFramesCount() const;
+ uint16 getCurrentFrame() const;
+ int16 getFrameRate() const;
+ uint32 getSyncLag() const;
+
+ const byte *getPalette() const;
+
+ bool getFrameCoords(int16 frame,
+ int16 &x, int16 &y, int16 &width, int16 &height);
+
+ bool hasExtraData(const char *fileName) const;
+ Common::MemoryReadStream *getExtraData(const char *fileName);
void setFrameRate(int16 frameRate);
@@ -231,7 +229,7 @@ public:
void setVideoMemory(byte *vidMem, uint16 width, uint16 height);
void setVideoMemory();
- void setDoubleMode(bool doubleMode) { }
+ void setDoubleMode(bool doubleMode);
void enableSound(Audio::Mixer &mixer);
void disableSound();
@@ -248,6 +246,22 @@ public:
uint16 x, uint16 y, uint16 pitch, int16 transp = -1);
protected:
+ enum Command {
+ kCommandNextSound = 0xFF00,
+ kCommandStartSound = 0xFF01,
+
+ kCommandBreak = 0xFFF0,
+ kCommandBreakSkip0 = 0xFFF1,
+ kCommandBreakSkip16 = 0xFFF2,
+ kCommandBreakSkip32 = 0xFFF3,
+ kCommandBreakMask = 0xFFF8,
+
+ kCommandPalette = 0xFFF4,
+ kCommandVideoData = 0xFFFC,
+
+ kCommandJump = 0xFFFD
+ };
+
struct Coord {
int16 left;
int16 top;
@@ -256,56 +270,104 @@ protected:
} PACKED_STRUCT;
Common::SeekableReadStream *_stream;
+
+ // Properties
uint16 _version;
uint32 _features;
uint16 _flags;
- int16 _x, _y, _width, _height;
- int16 _stdX, _stdY, _stdWidth, _stdHeight;
- uint16 _framesCount, _curFrame;
+
+ // Current coordinates
+ int16 _x;
+ int16 _y;
+ int16 _width;
+ int16 _height;
+
+ // Standard coordinates gives by the header
+ int16 _stdX;
+ int16 _stdY;
+ int16 _stdWidth;
+ int16 _stdHeight;
+
+ uint16 _framesCount;
+ uint16 _curFrame;
+
uint32 *_framesPos;
- uint32 _firstFramePos;
+ uint32 _firstFramePos;
Coord *_frameCoords;
- uint32 _frameDataSize, _vidBufferSize;
- byte *_frameData, *_vidBuffer;
+ // Buffer for raw frame data
+ byte *_frameData;
+ uint32 _frameDataSize;
uint32 _frameDataLen;
- byte _palette[768];
+ // Buffer for uncompressed raw frame data
+ byte *_vidBuffer;
+ uint32 _vidBufferSize;
- bool _hasOwnVidMem;
- byte *_vidMem;
- uint16 _vidMemWidth, _vidMemHeight;
+ byte _palette[768];
- bool _hasSound;
- bool _soundEnabled;
- uint8 _soundStage; // (0: no sound, 1: loaded, 2: playing)
- uint32 _skipFrames;
+ // Video memory
+ bool _hasOwnVidMem;
+ byte *_vidMem;
+ uint16 _vidMemWidth;
+ uint16 _vidMemHeight;
+ // Sound properties
uint16 _soundFlags;
- int16 _soundFreq;
- int16 _soundSliceSize;
- int16 _soundSlicesCount;
+ int16 _soundFreq;
+ int16 _soundSliceSize;
+ int16 _soundSlicesCount;
uint32 _soundSliceLength;
+ // Current sound state
+ bool _hasSound;
+ bool _soundEnabled;
+ uint8 _soundStage; // (0: no sound, 1: loaded, 2: playing)
+ uint32 _skipFrames;
+
Audio::AppendableAudioStream *_audioStream;
Audio::SoundHandle _audioHandle;
- int16 _frameRate;
+ // Current video state
+ int16 _frameRate;
uint32 _frameLength;
uint32 _lastFrameTime;
Audio::Mixer *_mixer;
- void unsignedToSigned(byte *buffer, int length) {
- while (length-- > 0) *buffer++ ^= 0x80;
- }
+ void unsignedToSigned(byte *buffer, int length);
void deleteVidMem(bool del = true);
void clear(bool del = true);
+ bool loadCoordinates();
+ bool loadFrameTableOffsets(uint32 &framesPosPos, uint32 &framesCoordsPos);
+ bool assessVideoProperties();
+ bool assessAudioProperties();
+ bool loadFrameTables(uint32 framesPosPos, uint32 framesCoordsPos);
+
State processFrame(uint16 frame);
uint32 renderFrame(int16 left, int16 top, int16 right, int16 bottom);
void deLZ77(byte *dest, byte *src);
+
+ void renderBlockWhole (byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight);
+ void renderBlockWhole4X (byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight);
+ void renderBlockWhole2Y (byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight);
+ void renderBlockSparse (byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight);
+ void renderBlockSparse2Y(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight);
+
+ void calcFrameCoords(uint16 frame, State &state);
+
+ void nextSoundSlice(bool hasNextCmd);
+ bool initialSoundSlice(bool hasNextCmd);
+ void emptySoundSlice(bool hasNextCmd);
+
+ void videoData(uint32 size, State &state);
};
class Vmd : public Imd {
@@ -313,7 +375,7 @@ public:
Vmd(Graphics::PaletteLUT *palLUT = 0);
~Vmd();
- bool getAnchor(int16 frame, uint16 partType,
+ bool getFrameCoords(int16 frame,
int16 &x, int16 &y, int16 &width, int16 &height);
bool hasExtraData(const char *fileName) const;
@@ -335,38 +397,58 @@ public:
protected:
enum PartType {
kPartTypeSeparator = 0,
- kPartTypeAudio = 1,
- kPartTypeVideo = 2,
- kPartTypeExtraData = 3
+ kPartTypeAudio = 1,
+ kPartTypeVideo = 2,
+ kPartTypeExtraData = 3,
+ kPartType4 = 4,
+ kPartTypeSpeech = 5
};
+
+ enum AudioFormat {
+ kAudioFormat8bitDirect = 0,
+ kAudioFormat16bitDPCM = 1,
+ kAudioFormat16bitADPCM = 2
+ };
+
struct ExtraData {
- char name[16];
+ char name[16];
uint32 offset;
uint32 size;
uint32 realSize;
+
+ ExtraData();
} PACKED_STRUCT;
+
struct Part {
PartType type;
- byte field_1;
- byte field_E;
- uint32 size;
- int16 left;
- int16 top;
- int16 right;
- int16 bottom;
- byte flags;
+ byte field_1;
+ byte field_E;
+ uint32 size;
+ int16 left;
+ int16 top;
+ int16 right;
+ int16 bottom;
+ uint16 id;
+ byte flags;
+
+ Part();
} PACKED_STRUCT;
+
struct Frame {
uint32 offset;
- Part *parts;
+ Part *parts;
- Frame() : parts(0) { }
- ~Frame() { delete[] parts; }
+ Frame();
+ ~Frame();
} PACKED_STRUCT;
- static const uint16 _tableADPCM[128];
+ // Tables for the audio decompressors
+ static const uint16 _tableDPCM[128];
+ static const int32 _tableADPCM[];
+ static const int32 _tableADPCMStep[];
- bool _hasVideo;
+ bool _hasVideo;
+ uint32 _videoCodec;
uint32 _frameInfoOffset;
uint16 _partsPerFrame;
@@ -374,9 +456,14 @@ protected:
Common::Array<ExtraData> _extraData;
- byte _soundBytesPerSample;
- byte _soundStereo; // (0: mono, 1: old-style stereo, 2: new-style stereo)
+ // Sound properties
+ byte _soundBytesPerSample;
+ byte _soundStereo; // (0: mono, 1: old-style stereo, 2: new-style stereo)
+ uint32 _soundHeaderSize;
+ uint32 _soundDataSize;
+ AudioFormat _audioFormat;
+ // Video properties
bool _externalCodec;
byte _blitMode;
byte _bytesPerPixel;
@@ -392,10 +479,21 @@ protected:
void clear(bool del = true);
+ bool getPartCoords(int16 frame, PartType type,
+ int16 &x, int16 &y, int16 &width, int16 &height);
+
+ bool assessVideoProperties();
+ bool assessAudioProperties();
+ void readFrameTable(int &numExtraData);
+ void readExtraData();
+
State processFrame(uint16 frame);
uint32 renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom);
- void deRLE(byte *&srcPtr, byte *&destPtr, int16 len);
+ void renderBlockRLE(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destWidth, int16 destHeight);
+
+ void deRLE(byte *&destPtr, const byte *&srcPtr, int16 len);
inline int32 preScaleX(int32 x) const;
inline int32 postScaleX(int32 x) const;
@@ -404,12 +502,18 @@ protected:
void blit16(byte *dest, byte *src, int16 srcPitch, int16 width, int16 height);
void blit24(byte *dest, byte *src, int16 srcPitch, int16 width, int16 height);
+ byte *deDPCM(const byte *data, uint32 &size, int32 init[2]);
+ byte *deADPCM(const byte *data, uint32 &size, int32 init, int32 v28);
+
+ byte *soundEmpty(uint32 &size);
+ byte *sound8bitDirect(uint32 &size);
+ byte *sound16bitDPCM(uint32 &size);
+ byte *sound16bitADPCM(uint32 &size);
+
+ uint8 evaluateMask(uint32 mask, bool *fillInfo, uint8 &max);
void emptySoundSlice(uint32 size);
- void soundSlice8bit(uint32 size);
- void soundSlice16bit(uint32 size, int16 &init);
void filledSoundSlice(uint32 size);
void filledSoundSlices(uint32 size, uint32 mask);
- void deADPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n);
};
} // End of namespace Graphics
diff --git a/graphics/video/smk_decoder.cpp b/graphics/video/smk_decoder.cpp
index 9db8f0c730..8952f553b7 100644
--- a/graphics/video/smk_decoder.cpp
+++ b/graphics/video/smk_decoder.cpp
@@ -348,8 +348,8 @@ uint32 BigHuffmanTree::getCode(BitStream &bs) {
return v;
}
-SmackerDecoder::SmackerDecoder(Audio::Mixer *mixer)
- : _audioStarted(false), _audioStream(0), _mixer(mixer) {
+SmackerDecoder::SmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType)
+ : _audioStarted(false), _audioStream(0), _mixer(mixer), _soundType(soundType) {
}
SmackerDecoder::~SmackerDecoder() {
@@ -583,7 +583,7 @@ bool SmackerDecoder::decodeNextFrame() {
}
if (!_audioStarted) {
- _mixer->playInputStream(Audio::Mixer::kPlainSoundType, &_audioHandle, _audioStream, -1, 255);
+ _mixer->playInputStream(_soundType, &_audioHandle, _audioStream, -1, 255);
_audioStarted = true;
}
} else {
diff --git a/graphics/video/smk_decoder.h b/graphics/video/smk_decoder.h
index e70d0e6454..e28d85119d 100644
--- a/graphics/video/smk_decoder.h
+++ b/graphics/video/smk_decoder.h
@@ -55,7 +55,8 @@ class BigHuffmanTree;
*/
class SmackerDecoder : public VideoDecoder {
public:
- SmackerDecoder(Audio::Mixer *mixer);
+ SmackerDecoder(Audio::Mixer *mixer,
+ Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType);
virtual ~SmackerDecoder();
int getHeight();
@@ -113,6 +114,7 @@ private:
// The RGB palette
byte *_palette;
+ Audio::Mixer::SoundType _soundType;
Audio::Mixer *_mixer;
bool _audioStarted;
Audio::AppendableAudioStream *_audioStream;