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