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 "common/textconsole.h"
24
25 #include "graphics/maccursor.h"
26
27 namespace Graphics {
28
MacCursor()29 MacCursor::MacCursor() {
30 _surface = 0;
31 memset(_palette, 0, 256 * 3);
32
33 _hotspotX = 0;
34 _hotspotY = 0;
35 }
36
~MacCursor()37 MacCursor::~MacCursor() {
38 clear();
39 }
40
clear()41 void MacCursor::clear() {
42 delete[] _surface; _surface = 0;
43 memset(_palette, 0, 256 * 3);
44 }
45
readFromStream(Common::SeekableReadStream & stream,bool forceMonochrome)46 bool MacCursor::readFromStream(Common::SeekableReadStream &stream, bool forceMonochrome) {
47 clear();
48
49 // Older Mac CURS monochrome cursors had a set size
50 // All crsr cursors are larger than this
51 if (stream.size() == 32 * 2 + 4)
52 return readFromCURS(stream);
53
54 return readFromCRSR(stream, forceMonochrome);
55 }
56
readFromCURS(Common::SeekableReadStream & stream)57 bool MacCursor::readFromCURS(Common::SeekableReadStream &stream) {
58 // Grab B/W icon data
59 _surface = new byte[16 * 16];
60 for (int i = 0; i < 32; i++) {
61 byte imageByte = stream.readByte();
62 for (int b = 0; b < 8; b++)
63 _surface[i * 8 + b] = (byte)((imageByte & (0x80 >> b)) > 0 ? 0 : 1);
64 }
65
66 // Apply mask data
67 for (int i = 0; i < 32; i++) {
68 byte imageByte = stream.readByte();
69 for (int b = 0; b < 8; b++)
70 if ((imageByte & (0x80 >> b)) == 0)
71 _surface[i * 8 + b] = 0xff;
72 }
73
74 _hotspotY = stream.readUint16BE();
75 _hotspotX = stream.readUint16BE();
76
77 // Setup a basic palette
78 _palette[1 * 3 + 0] = 0xff;
79 _palette[1 * 3 + 1] = 0xff;
80 _palette[1 * 3 + 2] = 0xff;
81
82 return !stream.eos();
83 }
84
readFromCRSR(Common::SeekableReadStream & stream,bool forceMonochrome)85 bool MacCursor::readFromCRSR(Common::SeekableReadStream &stream, bool forceMonochrome) {
86 stream.readUint16BE(); // type
87 stream.readUint32BE(); // offset to pixel map
88 stream.readUint32BE(); // offset to pixel data
89 stream.readUint32BE(); // expanded cursor data
90 stream.readUint16BE(); // expanded data depth
91 stream.readUint32BE(); // reserved
92
93 // Read the B/W data first
94 if (!readFromCURS(stream))
95 return false;
96
97 // Use b/w cursor on backends which don't support cursor palettes
98 if (forceMonochrome)
99 return true;
100
101 stream.readUint32BE(); // reserved
102 stream.readUint32BE(); // cursorID
103
104 // Color version of cursor
105 stream.readUint32BE(); // baseAddr
106
107 // Keep only lowbyte for now
108 stream.readByte();
109 int iconRowBytes = stream.readByte();
110
111 if (!iconRowBytes)
112 return false;
113
114 int iconBounds[4];
115 iconBounds[0] = stream.readUint16BE();
116 iconBounds[1] = stream.readUint16BE();
117 iconBounds[2] = stream.readUint16BE();
118 iconBounds[3] = stream.readUint16BE();
119
120 stream.readUint16BE(); // pmVersion
121 stream.readUint16BE(); // packType
122 stream.readUint32BE(); // packSize
123
124 stream.readUint32BE(); // hRes
125 stream.readUint32BE(); // vRes
126
127 stream.readUint16BE(); // pixelType
128 stream.readUint16BE(); // pixelSize
129 stream.readUint16BE(); // cmpCount
130 stream.readUint16BE(); // cmpSize
131
132 stream.readUint32BE(); // planeByte
133 stream.readUint32BE(); // pmTable
134 stream.readUint32BE(); // reserved
135
136 // Pixel data for cursor
137 int iconDataSize = iconRowBytes * (iconBounds[3] - iconBounds[1]);
138 byte *iconData = new byte[iconDataSize];
139
140 if (!iconData)
141 error("Cannot allocate Mac color cursor iconData");
142
143 stream.read(iconData, iconDataSize);
144
145 // Color table
146 stream.readUint32BE(); // ctSeed
147 stream.readUint16BE(); // ctFlag
148 uint16 ctSize = stream.readUint16BE() + 1;
149
150 // Read just high byte of 16-bit color
151 for (int c = 0; c < ctSize; c++) {
152 stream.readUint16BE();
153 _palette[c * 3 + 0] = stream.readUint16BE() >> 8;
154 _palette[c * 3 + 1] = stream.readUint16BE() >> 8;
155 _palette[c * 3 + 2] = stream.readUint16BE() >> 8;
156 }
157
158 int pixelsPerByte = (iconBounds[2] - iconBounds[0]) / iconRowBytes;
159 int bpp = 8 / pixelsPerByte;
160
161 // build a mask to make sure the pixels are properly shifted out
162 int bitmask = 0;
163 for (int m = 0; m < bpp; m++) {
164 bitmask <<= 1;
165 bitmask |= 1;
166 }
167
168 // Extract pixels from bytes
169 for (int j = 0; j < iconDataSize; j++) {
170 for (int b = 0; b < pixelsPerByte; b++) {
171 int idx = j * pixelsPerByte + (pixelsPerByte - 1 - b);
172
173 if (_surface[idx] != 0xff) // if mask is not there
174 _surface[idx] = (byte)((iconData[j] >> (b * bpp)) & bitmask);
175 }
176 }
177
178 delete[] iconData;
179 return stream.pos() == stream.size();
180 }
181
182 } // End of namespace Common
183