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 #include "image/cel_3do.h"
24
25 #include "common/file.h"
26 #include "common/stream.h"
27 #include "common/substream.h"
28 #include "common/textconsole.h"
29 #include "graphics/pixelformat.h"
30 #include "graphics/surface.h"
31 #include "image/bmp.h"
32
33 namespace Image {
34
35 enum CCBFlags {
36 kCCBPacked = 1 << 9,
37 kCCBNoPre0 = 1 << 22
38 };
39
Cel3DODecoder()40 Cel3DODecoder::Cel3DODecoder() {
41 _surface = 0;
42 _palette = 0;
43 _paletteColorCount = 0;
44 }
45
~Cel3DODecoder()46 Cel3DODecoder::~Cel3DODecoder() {
47 destroy();
48 }
49
destroy()50 void Cel3DODecoder::destroy() {
51 _surface = 0;
52
53 delete[] _palette;
54 _palette = 0;
55
56 _paletteColorCount = 0;
57 }
58
loadStream(Common::SeekableReadStream & stream)59 bool Cel3DODecoder::loadStream(Common::SeekableReadStream &stream) {
60 destroy();
61
62 // This is not a full implementaion of CEL support,
63 // just what is currently needed for following games:
64 // * Plumbers don't wear ties
65 // TODO: support paletted
66
67 if (stream.readUint32BE() != MKTAG('C', 'C', 'B', ' '))
68 return false;
69
70 if (stream.readUint32BE() != 0x50) // block size
71 return false;
72
73 if (stream.readUint32BE() != 0) // CCB version
74 return false;
75
76 uint32 flags = stream.readUint32BE();
77
78 stream.skip(0x30);
79 uint32 pre0 = stream.readUint32BE();
80 /* pre1 = */ stream.readUint32BE();
81 uint32 width = stream.readUint32BE();
82 uint32 height = stream.readUint32BE();
83
84 while (!stream.eos()) {
85 if (stream.readUint32BE() == MKTAG('P', 'D', 'A', 'T'))
86 break;
87 stream.skip(stream.readUint32BE() - 8);
88 }
89
90 if (stream.eos())
91 return false;
92
93 if (width == 0 || height == 0)
94 return false;
95
96 /* pdat_size = */ stream.readUint32BE();
97
98 Graphics::PixelFormat format(2, 5, 5, 5, 1, 10, 5, 0, 15);
99 Graphics::Surface *surface = new Graphics::Surface();
100 surface->create(width, height, format);
101
102 uint16 *dst = (uint16 *)surface->getBasePtr(0, 0);
103
104 if(!(flags & kCCBNoPre0)) {
105 pre0 = stream.readUint32BE();
106 if(!(flags & kCCBPacked)) {
107 /* pre1 = */ stream.readUint32BE();
108 }
109 }
110
111 // Only RGB555 is supported
112 if ((pre0 & 0x17) != 0x16)
113 return false;
114
115 if(!(flags & kCCBPacked)) {
116 // RAW
117 // TODO: this can be optimized, especially on BE systems, but do we care?
118 for (uint xy = 0; xy < width * height; xy++)
119 *dst++ = stream.readUint16BE();
120 } else {
121 // RLE
122 for (uint y = 0; y < height; y++) {
123 int linecomprem = (stream.readUint16BE() + 2) * 4 - 2;
124 int linerem = width;
125 bool stopLine = false;
126 while (linerem > 0 && linecomprem > 0 && !stopLine) {
127 byte lead = stream.readByte();
128 linecomprem--;
129 switch (lead >> 6) {
130 case 0: // end of the line
131 stopLine = true;
132 break;
133 case 1: // copy
134 for (uint i = 0; i <= (lead & 0x3f) && linerem > 0 && linecomprem > 0;
135 i++, linerem--, linecomprem -= 2)
136 *dst++ = stream.readUint16BE();
137 break;
138 case 2: // black
139 for (uint i = 0; i <= (lead & 0x3f) && linerem > 0; i++, linerem--)
140 *dst++ = 0;
141 break;
142 case 3: { // RLE multiply
143 uint16 rleval = stream.readUint16BE();
144 linecomprem -= 2;
145 for (uint i = 0; i <= (lead & 0x3f) && linerem > 0; i++, linerem--)
146 *dst++ = rleval;
147 break;
148 }
149 }
150 }
151 if (linecomprem > 0)
152 stream.skip(linecomprem);
153 if (linerem > 0) {
154 memset(dst, 0, 2 * linerem);
155 dst += linerem;
156 }
157 }
158 }
159
160 _surface = surface;
161
162 return true;
163 }
164
165 } // End of namespace Image
166