aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/bomp.cpp
diff options
context:
space:
mode:
authorMax Horn2006-02-11 22:45:04 +0000
committerMax Horn2006-02-11 22:45:04 +0000
commit26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch)
tree26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/scumm/bomp.cpp
parent2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff)
downloadscummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/scumm/bomp.cpp')
-rw-r--r--engines/scumm/bomp.cpp393
1 files changed, 393 insertions, 0 deletions
diff --git a/engines/scumm/bomp.cpp b/engines/scumm/bomp.cpp
new file mode 100644
index 0000000000..f3f78e4731
--- /dev/null
+++ b/engines/scumm/bomp.cpp
@@ -0,0 +1,393 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 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$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "scumm/scumm.h"
+#include "scumm/akos.h"
+#include "scumm/bomp.h"
+#include "scumm/util.h"
+
+
+namespace Scumm {
+
+static int32 setupBompScale(byte *scaling, int32 size, byte scale);
+
+static void bompScaleFuncX(byte *line_buffer, byte *scaling_x_ptr, byte skip, int32 size);
+
+static void bompApplyShadow0(const byte *shadowPalette, const byte *line_buffer, byte *dst, int32 size, byte transparency, byte HE7Check);
+static void bompApplyShadow1(const byte *shadowPalette, const byte *line_buffer, byte *dst, int32 size, byte transparency);
+static void bompApplyShadow3(const byte *shadowPalette, const byte *line_buffer, byte *dst, int32 size, byte transparency);
+static void bompApplyActorPalette(byte *actorPalette, byte *line_buffer, int32 size);
+
+
+
+void decompressBomp(byte *dst, const byte *src, int w, int h) {
+ assert(w > 0);
+ assert(h > 0);
+
+ do {
+ bompDecodeLine(dst, src + 2, w);
+ src += READ_LE_UINT16(src) + 2;
+ dst += w;
+ } while (--h);
+}
+
+void bompDecodeLine(byte *dst, const byte *src, int len) {
+ assert(len > 0);
+
+ int num;
+ byte code, color;
+
+ while (len > 0) {
+ code = *src++;
+ num = (code >> 1) + 1;
+ if (num > len)
+ num = len;
+ len -= num;
+ if (code & 1) {
+ color = *src++;
+ memset(dst, color, num);
+ } else {
+ memcpy(dst, src, num);
+ src += num;
+ }
+ dst += num;
+ }
+}
+
+void bompDecodeLineReverse(byte *dst, const byte *src, int len) {
+ assert(len > 0);
+
+ dst += len;
+
+ int num;
+ byte code, color;
+
+ while (len > 0) {
+ code = *src++;
+ num = (code >> 1) + 1;
+ if (num > len)
+ num = len;
+ len -= num;
+ dst -= num;
+ if (code & 1) {
+ color = *src++;
+ memset(dst, color, num);
+ } else {
+ memcpy(dst, src, num);
+ src += num;
+ }
+ }
+}
+
+void bompApplyMask(byte *line_buffer, byte *mask, byte maskbit, int32 size, byte transparency) {
+ while (1) {
+ do {
+ if (size-- == 0)
+ return;
+ if (*mask & maskbit) {
+ *line_buffer = transparency;
+ }
+ line_buffer++;
+ maskbit >>= 1;
+ } while (maskbit);
+ mask++;
+ maskbit = 128;
+ }
+}
+
+void bompApplyShadow(int shadowMode, const byte *shadowPalette, const byte *line_buffer, byte *dst, int32 size, byte transparency, byte HE7Check) {
+ assert(size > 0);
+ switch (shadowMode) {
+ case 0:
+ bompApplyShadow0(shadowPalette, line_buffer, dst, size, transparency, HE7Check);
+ break;
+ case 1:
+ bompApplyShadow1(shadowPalette, line_buffer, dst, size, transparency);
+ break;
+ case 3:
+ bompApplyShadow3(shadowPalette, line_buffer, dst, size, transparency);
+ break;
+ default:
+ error("Unknown shadow mode %d", shadowMode);
+ }
+}
+void bompApplyShadow0(const byte *shadowPalette, const byte *line_buffer, byte *dst, int32 size, byte transparency, byte HE7Check = false) {
+ while (size-- > 0) {
+ byte tmp = *line_buffer++;
+ if (tmp != transparency) {
+ if (HE7Check)
+ *dst = shadowPalette[tmp];
+ else
+ *dst = tmp;
+ }
+ dst++;
+ }
+}
+
+void bompApplyShadow1(const byte *shadowPalette, const byte *line_buffer, byte *dst, int32 size, byte transparency) {
+ while (size-- > 0) {
+ byte tmp = *line_buffer++;
+ if (tmp != transparency) {
+ if (tmp == 13) {
+ tmp = shadowPalette[*dst];
+ }
+ *dst = tmp;
+ }
+ dst++;
+ }
+}
+
+void bompApplyShadow3(const byte *shadowPalette, const byte *line_buffer, byte *dst, int32 size, byte transparency) {
+ while (size-- > 0) {
+ byte tmp = *line_buffer++;
+ if (tmp != transparency) {
+ if (tmp < 8) {
+ tmp = shadowPalette[*dst + (tmp << 8)];
+ }
+ *dst = tmp;
+ }
+ dst++;
+ }
+}
+
+void bompApplyActorPalette(byte *actorPalette, byte *line_buffer, int32 size) {
+ if (actorPalette != 0) {
+ actorPalette[255] = 255;
+ while (size-- > 0) {
+ *line_buffer = actorPalette[*line_buffer];
+ line_buffer++;
+ }
+ }
+}
+
+void bompScaleFuncX(byte *line_buffer, byte *scaling_x_ptr, byte skip, int32 size) {
+ byte *line_ptr1 = line_buffer;
+ byte *line_ptr2 = line_buffer;
+
+ byte tmp = *scaling_x_ptr++;
+
+ while (size--) {
+ if ((skip & tmp) == 0) {
+ *line_ptr1++ = *line_ptr2;
+ }
+ line_ptr2++;
+ skip >>= 1;
+ if (skip == 0) {
+ skip = 128;
+ tmp = *scaling_x_ptr++;
+ }
+ }
+}
+
+void ScummEngine::drawBomp(const BompDrawData &bd, bool mirror) {
+ const byte *src;
+ byte *dst;
+ byte *mask = 0;
+ Common::Rect clip;
+ byte *scalingYPtr = 0;
+ byte skip_y_bits = 0x80;
+ byte skip_y_new = 0;
+ byte tmp;
+ byte bomp_scaling_x[64];
+ byte bomp_scaling_y[64];
+
+
+ if (bd.x < 0) {
+ clip.left = -bd.x;
+ } else {
+ clip.left = 0;
+ }
+
+ if (bd.y < 0) {
+ clip.top = -bd.y;
+ } else {
+ clip.top = 0;
+ }
+
+ clip.right = bd.srcwidth;
+ if (clip.right > bd.dst.w - bd.x) {
+ clip.right = bd.dst.w - bd.x;
+ }
+
+ clip.bottom = bd.srcheight;
+ if (clip.bottom > bd.dst.h - bd.y) {
+ clip.bottom = bd.dst.h - bd.y;
+ }
+
+ src = bd.dataptr;
+ dst = (byte *)bd.dst.pixels + bd.y * bd.dst.pitch + (bd.x + clip.left);
+
+ const byte maskbit = revBitMask((bd.x + clip.left) & 7);
+
+ // Mask against any additionally imposed mask
+ if (bd.maskPtr) {
+ mask = bd.maskPtr + (bd.y * gdi._numStrips) + ((bd.x + clip.left) / 8);
+ }
+
+ // Setup vertical scaling
+ if (bd.scale_y != 255) {
+ int scaleBottom = setupBompScale(bomp_scaling_y, bd.srcheight, bd.scale_y);
+ scalingYPtr = bomp_scaling_y;
+
+ skip_y_new = *scalingYPtr++;
+ skip_y_bits = 0x80;
+
+ if (clip.bottom > scaleBottom) {
+ clip.bottom = scaleBottom;
+ }
+ }
+
+ // Setup horizontal scaling
+ if (bd.scale_x != 255) {
+ int scaleRight = setupBompScale(bomp_scaling_x, bd.srcwidth, bd.scale_x);
+
+ if (clip.right > scaleRight) {
+ clip.right = scaleRight;
+ }
+ }
+
+ const int width = clip.right - clip.left;
+
+ if (width <= 0)
+ return;
+
+ int pos_y = 0;
+ byte line_buffer[1024];
+
+ byte *line_ptr = line_buffer + clip.left;
+
+ // Loop over all lines
+ while (pos_y < clip.bottom) {
+ // Decode a single (bomp encoded) line, reversed if we are in mirror mode
+ if (mirror)
+ bompDecodeLineReverse(line_buffer, src + 2, bd.srcwidth);
+ else
+ bompDecodeLine(line_buffer, src + 2, bd.srcwidth);
+ src += READ_LE_UINT16(src) + 2;
+
+ // If vertical scaling is enabled, do it
+ if (bd.scale_y != 255) {
+ // A bit set means we should skip this line...
+ tmp = skip_y_new & skip_y_bits;
+
+ // Advance the scale-skip bit mask, if it's 0, get the next scale-skip byte
+ skip_y_bits /= 2;
+ if (skip_y_bits == 0) {
+ skip_y_bits = 0x80;
+ skip_y_new = *scalingYPtr++;
+ }
+
+ // Skip the current line if the above check tells us to
+ if (tmp != 0)
+ continue;
+ }
+
+ // Perform horizontal scaling
+ if (bd.scale_x != 255) {
+ bompScaleFuncX(line_buffer, bomp_scaling_x, 0x80, bd.srcwidth);
+ }
+
+ // The first clip.top lines are to be clipped, i.e. not drawn
+ if (clip.top > 0) {
+ clip.top--;
+ } else {
+ // Replace the parts of the line which are masked with the transparency color
+ if (bd.maskPtr)
+ bompApplyMask(line_ptr, mask, maskbit, width, 255);
+
+ // Apply custom color map, if available
+ if (_bompActorPalettePtr)
+ bompApplyActorPalette(_bompActorPalettePtr, line_ptr, width);
+
+ // Finally, draw the decoded, scaled, masked and recolored line onto
+ // the target surface, using the specified shadow mode
+ bompApplyShadow(bd.shadowMode, _shadowPalette, line_ptr, dst, width, 255);
+ }
+
+ // Advance to the next line
+ pos_y++;
+ mask += gdi._numStrips;
+ dst += bd.dst.pitch;
+ }
+}
+
+static const byte bitCount[] = {
+ 8, 7, 7, 6, 7, 6, 6, 5, 7, 6, 6, 5, 6, 5, 5, 4,
+ 7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3,
+ 7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3,
+ 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2,
+ 7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3,
+ 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2,
+ 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2,
+ 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1,
+ 7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3,
+ 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2,
+ 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2,
+ 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1,
+ 6, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2,
+ 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1,
+ 5, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1,
+ 4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0,
+};
+
+int32 setupBompScale(byte *scaling, int32 size, byte scale) {
+ byte tmp;
+ int32 count;
+ const byte *tmp_ptr;
+ byte *tmp_scaling = scaling;
+ byte a = 0;
+ byte ret_value = 0;
+ const int offsets[8] = { 3, 2, 1, 0, 7, 6, 5, 4 };
+
+ count = (256 - size / 2);
+ assert(0 <= count && count < 768);
+ tmp_ptr = bigCostumeScaleTable + count;
+
+ count = (size + 7) / 8;
+ while (count--) {
+ a = 0;
+ for (int i = 0; i < 8; i++) {
+ tmp = *(tmp_ptr + offsets[i]);
+ a <<= 1;
+ if (scale < tmp) {
+ a |= 1;
+ }
+ }
+ tmp_ptr += 8;
+
+ *tmp_scaling++ = a;
+ }
+ if ((size & 7) != 0) {
+ *(tmp_scaling - 1) |= revBitMask(size & 7);
+ }
+
+ count = (size + 7) / 8;
+ while (count--) {
+ tmp = *scaling++;
+ ret_value += bitCount[tmp];
+ }
+
+ return ret_value;
+}
+
+} // End of namespace Scumm