1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 // Conversion routines for planar graphics in Amiga versions
24
25
26 #include "agos/agos.h"
27 #include "agos/intern.h"
28
29 #include "common/endian.h"
30
31 namespace AGOS {
32
33 enum {
34 kMaxColorDepth = 5
35 };
36
uncompressPlane(const byte * plane,byte * outptr,int length)37 static void uncompressPlane(const byte *plane, byte *outptr, int length) {
38 while (length != 0) {
39 int wordlen;
40 signed char x = *plane++;
41 if (x >= 0) {
42 wordlen = MIN<int>(x + 1, length);
43 uint16 w = READ_UINT16(plane); plane += 2;
44 for (int i = 0; i < wordlen; ++i) {
45 WRITE_UINT16(outptr, w); outptr += 2;
46 }
47 } else {
48 wordlen = MIN<int>(-x, length);
49 memcpy(outptr, plane, wordlen * 2);
50 outptr += wordlen * 2;
51 plane += wordlen * 2;
52 }
53 length -= wordlen;
54 }
55 }
56
bitplaneToChunky(uint16 * w,uint8 colorDepth,uint8 * & dst)57 static void bitplaneToChunky(uint16 *w, uint8 colorDepth, uint8 *&dst) {
58 for (int j = 0; j < 8; j++) {
59 byte color1 = 0;
60 byte color2 = 0;
61 for (int p = 0; p < colorDepth; ++p) {
62 if (w[p] & 0x8000) {
63 color1 |= 1 << p;
64 }
65 if (w[p] & 0x4000) {
66 color2 |= 1 << p;
67 }
68 w[p] <<= 2;
69 }
70 if (colorDepth > 4) {
71 *dst++ = color1;
72 *dst++ = color2;
73 } else {
74 *dst++ = (color1 << 4) | color2;
75 }
76 }
77 }
78
bitplaneToChunkyText(uint16 * w,uint8 colorDepth,uint8 * & dst)79 static void bitplaneToChunkyText(uint16 *w, uint8 colorDepth, uint8 *&dst) {
80 for (int j = 0; j < 16; j++) {
81 byte color = 0;
82 for (int p = 0; p < colorDepth; ++p) {
83 if (w[p] & 0x8000) {
84 color |= 1 << p;
85 }
86 w[p] <<= 1;
87 }
88 if (color)
89 color |= 0xC0;
90 *dst++ = color;
91 }
92 }
93
convertCompressedImage(const byte * src,byte * dst,uint8 colorDepth,int height,int width,bool horizontal=true)94 static void convertCompressedImage(const byte *src, byte *dst, uint8 colorDepth, int height, int width, bool horizontal = true) {
95 const byte *plane[kMaxColorDepth];
96 byte *uncptr[kMaxColorDepth];
97 int length, i, j;
98
99 byte *uncbfrout = (byte *)malloc(width * height);
100
101 length = (width + 15) / 16 * height;
102
103 for (i = 0; i < colorDepth; ++i) {
104 plane[i] = src + READ_BE_UINT16(src + i * 4) + READ_BE_UINT16(src + i * 4 + 2);
105 uncptr[i] = (uint8 *)malloc(length * 2);
106 uncompressPlane(plane[i], uncptr[i], length);
107 plane[i] = uncptr[i];
108 }
109
110 byte *uncbfroutptr = uncbfrout;
111 for (i = 0; i < length; ++i) {
112 uint16 w[kMaxColorDepth];
113 for (j = 0; j < colorDepth; ++j) {
114 w[j] = READ_BE_UINT16(plane[j]); plane[j] += 2;
115 }
116 bitplaneToChunky(w, colorDepth, uncbfroutptr);
117 }
118
119 uncbfroutptr = uncbfrout;
120 const int chunkSize = colorDepth > 4 ? 16 : 8;
121 if (horizontal) {
122 for (j = 0; j < height; ++j) {
123 for (i = 0; i < width / 16; ++i) {
124 memcpy(dst + width * chunkSize / 16 * j + chunkSize * i, uncbfroutptr, chunkSize);
125 uncbfroutptr += chunkSize;
126 }
127 }
128 } else {
129 for (i = 0; i < width / 16; ++i) {
130 for (j = 0; j < height; ++j) {
131 memcpy(dst + width * chunkSize / 16 * j + chunkSize * i, uncbfroutptr, chunkSize);
132 uncbfroutptr += chunkSize;
133 }
134 }
135 }
136
137 free(uncbfrout);
138 for (i = 0; i < colorDepth; ++i) {
139 free(uncptr[i]);
140 }
141 }
142
convertImage(VC10_state * state,bool compressed)143 byte *AGOSEngine::convertImage(VC10_state *state, bool compressed) {
144 int length, i, j;
145
146 uint8 colorDepth = 4;
147 if (getGameType() == GType_SIMON1) {
148 if (((_videoLockOut & 0x20) && !state->palette) || ((getFeatures() & GF_32COLOR) &&
149 state->palette != 0xC0)) {
150 colorDepth = 5;
151 }
152 }
153
154 const byte *src = state->srcPtr;
155 int width = state->width * 16;
156 int height = state->height;
157
158 free(_planarBuf);
159 _planarBuf = (byte *)malloc(width * height);
160 byte *dst = _planarBuf;
161
162 if (compressed) {
163 convertCompressedImage(src, dst, colorDepth, height, width, (getGameType() == GType_PN));
164 } else {
165 length = (width + 15) / 16 * height;
166 for (i = 0; i < length; i++) {
167 uint16 w[kMaxColorDepth];
168 if (getGameType() == GType_SIMON1 && colorDepth == 4) {
169 for (j = 0; j < colorDepth; ++j) {
170 w[j] = READ_BE_UINT16(src + j * length * 2);
171 }
172 if (state->palette == 0xC0) {
173 bitplaneToChunkyText(w, colorDepth, dst);
174 } else {
175 bitplaneToChunky(w, colorDepth, dst);
176 }
177 src += 2;
178 } else {
179 for (j = 0; j < colorDepth; ++j) {
180 w[j] = READ_BE_UINT16(src); src += 2;
181 }
182 bitplaneToChunky(w, colorDepth, dst);
183 }
184 }
185 }
186
187 return _planarBuf;
188 }
189
190 } // End of namespace AGOS
191