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