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 "graphics/cursorman.h"
24 
25 #include "common/system.h"
26 #include "common/stack.h"
27 
28 namespace Common {
29 DECLARE_SINGLETON(Graphics::CursorManager);
30 }
31 
32 namespace Graphics {
33 
~CursorManager()34 CursorManager::~CursorManager() {
35 	for (Common::Stack<Cursor *>::size_type i = 0; i < _cursorStack.size(); ++i)
36 		delete _cursorStack[i];
37 	_cursorStack.clear();
38 	for (Common::Stack<Palette *>::size_type i = 0; i < _cursorPaletteStack.size(); ++i)
39 		delete _cursorPaletteStack[i];
40 	_cursorPaletteStack.clear();
41 }
42 
isVisible()43 bool CursorManager::isVisible() {
44 	if (_cursorStack.empty())
45 		return false;
46 	return _cursorStack.top()->_visible;
47 }
48 
showMouse(bool visible)49 bool CursorManager::showMouse(bool visible) {
50 	if (_cursorStack.empty())
51 		return false;
52 	if (_locked) {
53 		return false;
54 	}
55 
56 	_cursorStack.top()->_visible = visible;
57 
58 	// Should work, even if there's just a dummy cursor on the stack.
59 	return g_system->showMouse(visible);
60 }
61 
pushCursor(const void * buf,uint w,uint h,int hotspotX,int hotspotY,uint32 keycolor,bool dontScale,const Graphics::PixelFormat * format)62 void CursorManager::pushCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
63 	Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
64 
65 	cur->_visible = isVisible();
66 	_cursorStack.push(cur);
67 
68 	g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
69 }
70 
popCursor()71 void CursorManager::popCursor() {
72 	if (_cursorStack.empty())
73 		return;
74 
75 	Cursor *cur = _cursorStack.pop();
76 	delete cur;
77 
78 	if (!_cursorStack.empty()) {
79 		cur = _cursorStack.top();
80 		g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_dontScale, &cur->_format);
81 	} else {
82 		g_system->setMouseCursor(nullptr, 0, 0, 0, 0, 0);
83 	}
84 
85 	g_system->showMouse(isVisible());
86 }
87 
88 
popAllCursors()89 void CursorManager::popAllCursors() {
90 	while (!_cursorStack.empty()) {
91 		Cursor *cur = _cursorStack.pop();
92 		delete cur;
93 	}
94 
95 	if (g_system->hasFeature(OSystem::kFeatureCursorPalette)) {
96 		while (!_cursorPaletteStack.empty()) {
97 			Palette *pal = _cursorPaletteStack.pop();
98 			delete pal;
99 		}
100 	}
101 
102 	g_system->setMouseCursor(nullptr, 0, 0, 0, 0, 0);
103 	g_system->showMouse(isVisible());
104 }
105 
replaceCursor(const void * buf,uint w,uint h,int hotspotX,int hotspotY,uint32 keycolor,bool dontScale,const Graphics::PixelFormat * format)106 void CursorManager::replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
107 
108 	if (_cursorStack.empty()) {
109 		pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
110 		return;
111 	}
112 
113 	Cursor *cur = _cursorStack.top();
114 
115 #ifdef USE_RGB_COLOR
116 	uint size;
117 	if (!format)
118 		size = w * h;
119 	else
120 		size = w * h * format->bytesPerPixel;
121 #else
122 	uint size = w * h;
123 #endif
124 
125 	if (cur->_size < size) {
126 		delete[] cur->_data;
127 		cur->_data = new byte[size];
128 		cur->_size = size;
129 	}
130 
131 	if (buf && cur->_data)
132 		memcpy(cur->_data, buf, size);
133 
134 	cur->_width = w;
135 	cur->_height = h;
136 	cur->_hotspotX = hotspotX;
137 	cur->_hotspotY = hotspotY;
138 	cur->_keycolor = keycolor;
139 	cur->_dontScale = dontScale;
140 #ifdef USE_RGB_COLOR
141 	if (format)
142 		cur->_format = *format;
143 	else
144 		cur->_format = Graphics::PixelFormat::createFormatCLUT8();
145 #endif
146 
147 	g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
148 }
149 
replaceCursor(const Graphics::Cursor * cursor)150 void CursorManager::replaceCursor(const Graphics::Cursor *cursor) {
151 	replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(),
152 	              cursor->getHotspotY(), cursor->getKeyColor());
153 
154 	if (cursor->getPalette())
155 		replaceCursorPalette(cursor->getPalette(), cursor->getPaletteStartIndex(), cursor->getPaletteCount());
156 }
157 
supportsCursorPalettes()158 bool CursorManager::supportsCursorPalettes() {
159 	return g_system->hasFeature(OSystem::kFeatureCursorPalette);
160 }
161 
disableCursorPalette(bool disable)162 void CursorManager::disableCursorPalette(bool disable) {
163 	if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
164 		return;
165 
166 	if (_cursorPaletteStack.empty())
167 		return;
168 
169 	Palette *pal = _cursorPaletteStack.top();
170 	pal->_disabled = disable;
171 
172 	g_system->setFeatureState(OSystem::kFeatureCursorPalette, !disable);
173 }
174 
pushCursorPalette(const byte * colors,uint start,uint num)175 void CursorManager::pushCursorPalette(const byte *colors, uint start, uint num) {
176 	if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
177 		return;
178 
179 	Palette *pal = new Palette(colors, start, num);
180 	_cursorPaletteStack.push(pal);
181 
182 	if (num)
183 		g_system->setCursorPalette(colors, start, num);
184 	else
185 		g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
186 }
187 
popCursorPalette()188 void CursorManager::popCursorPalette() {
189 	if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
190 		return;
191 
192 	if (_cursorPaletteStack.empty())
193 		return;
194 
195 	Palette *pal = _cursorPaletteStack.pop();
196 	delete pal;
197 
198 	if (_cursorPaletteStack.empty()) {
199 		g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
200 		return;
201 	}
202 
203 	pal = _cursorPaletteStack.top();
204 
205 	if (pal->_num && !pal->_disabled)
206 		g_system->setCursorPalette(pal->_data, pal->_start, pal->_num);
207 	else
208 		g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
209 }
210 
replaceCursorPalette(const byte * colors,uint start,uint num)211 void CursorManager::replaceCursorPalette(const byte *colors, uint start, uint num) {
212 	if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
213 		return;
214 
215 	if (_cursorPaletteStack.empty()) {
216 		pushCursorPalette(colors, start, num);
217 		return;
218 	}
219 
220 	Palette *pal = _cursorPaletteStack.top();
221 	uint size = 3 * num;
222 
223 	if (pal->_size < size) {
224 		// Could not re-use the old buffer. Create a new one.
225 		delete[] pal->_data;
226 		pal->_data = new byte[size];
227 		pal->_size = size;
228 	}
229 
230 	pal->_start = start;
231 	pal->_num = num;
232 
233 	if (num) {
234 		memcpy(pal->_data, colors, size);
235 		g_system->setCursorPalette(pal->_data, pal->_start, pal->_num);
236 	} else {
237 		g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
238 	}
239 }
240 
lock(bool locked)241 void CursorManager::lock(bool locked) {
242 	_locked = locked;
243 }
244 
Cursor(const void * data,uint w,uint h,int hotspotX,int hotspotY,uint32 keycolor,bool dontScale,const Graphics::PixelFormat * format)245 CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
246 #ifdef USE_RGB_COLOR
247 	if (!format)
248 		_format = Graphics::PixelFormat::createFormatCLUT8();
249 	 else
250 		_format = *format;
251 	_size = w * h * _format.bytesPerPixel;
252 	_keycolor = keycolor & ((1 << (_format.bytesPerPixel << 3)) - 1);
253 #else
254 	_format = Graphics::PixelFormat::createFormatCLUT8();
255 	_size = w * h;
256 	_keycolor = keycolor & 0xFF;
257 #endif
258 	_data = new byte[_size];
259 	if (data && _data)
260 		memcpy(_data, data, _size);
261 	_width = w;
262 	_height = h;
263 	_hotspotX = hotspotX;
264 	_hotspotY = hotspotY;
265 	_dontScale = dontScale;
266 	_visible = false;
267 }
268 
~Cursor()269 CursorManager::Cursor::~Cursor() {
270 	delete[] _data;
271 }
272 
Palette(const byte * colors,uint start,uint num)273 CursorManager::Palette::Palette(const byte *colors, uint start, uint num) {
274 	_start = start;
275 	_num = num;
276 	_size = 3 * num;
277 
278 	if (num) {
279 		_data = new byte[_size];
280 		memcpy(_data, colors, _size);
281 	} else {
282 		_data = NULL;
283 	}
284 
285 	_disabled = false;
286 }
287 
~Palette()288 CursorManager::Palette::~Palette() {
289 	delete[] _data;
290 }
291 
292 } // End of namespace Graphics
293