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/rect.h"
24 #include "graphics/surface.h"
25 #include "graphics/transparent_surface.h"
26 
27 #include "sludge/allfiles.h"
28 #include "sludge/backdrop.h"
29 #include "sludge/event.h"
30 #include "sludge/fileset.h"
31 #include "sludge/graphics.h"
32 #include "sludge/imgloader.h"
33 #include "sludge/moreio.h"
34 #include "sludge/newfatal.h"
35 #include "sludge/people.h"
36 #include "sludge/sludge.h"
37 #include "sludge/sludger.h"
38 #include "sludge/sprites.h"
39 #include "sludge/zbuffer.h"
40 
41 namespace Sludge {
42 
43 // This function is only used to kill text font
forgetSpriteBank(SpriteBank & forgetme)44 void GraphicsManager::forgetSpriteBank(SpriteBank &forgetme) {
45 	// kill the sprite bank
46 	if (forgetme.myPalette.pal) {
47 		delete[] forgetme.myPalette.pal;
48 		forgetme.myPalette.pal = NULL;
49 		delete[] forgetme.myPalette.r;
50 		forgetme.myPalette.r = NULL;
51 		delete[] forgetme.myPalette.g;
52 		forgetme.myPalette.g = NULL;
53 		delete[] forgetme.myPalette.b;
54 		forgetme.myPalette.b = NULL;
55 	}
56 
57 	if (forgetme.sprites) {
58 		for (int i = 0; i < forgetme.total; ++i) {
59 			forgetme.sprites[i].surface.free();
60 			forgetme.sprites[i].burnSurface.free();
61 		}
62 
63 		delete []forgetme.sprites;
64 		forgetme.sprites = NULL;
65 	}
66 }
67 
reserveSpritePal(SpritePalette & sP,int n)68 bool GraphicsManager::reserveSpritePal(SpritePalette &sP, int n) {
69 	if (sP.pal) {
70 		delete[] sP.pal;
71 		delete[] sP.r;
72 		delete[] sP.g;
73 		delete[] sP.b;
74 	}
75 
76 	sP.pal = new uint16[n];
77 	if (!checkNew(sP.pal))
78 		return false;
79 
80 	sP.r = new byte[n];
81 	if (!checkNew(sP.r))
82 		return false;
83 	sP.g = new byte[n];
84 	if (!checkNew(sP.g))
85 		return false;
86 	sP.b = new byte[n];
87 	if (!checkNew(sP.b))
88 		return false;
89 	sP.total = n;
90 	return (bool)(sP.pal != NULL) && (sP.r != NULL) && (sP.g != NULL) && (sP.b != NULL);
91 }
92 
loadSpriteBank(int fileNum,SpriteBank & loadhere,bool isFont)93 bool GraphicsManager::loadSpriteBank(int fileNum, SpriteBank &loadhere, bool isFont) {
94 
95 	int total, spriteBankVersion = 0, howmany = 0, startIndex = 0;
96 	byte *data;
97 
98 	setResourceForFatal(fileNum);
99 	if (!g_sludge->_resMan->openFileFromNum(fileNum))
100 		return fatal("Can't open sprite bank / font");
101 
102 	loadhere.isFont = isFont;
103 
104 	Common::SeekableReadStream *readStream = g_sludge->_resMan->getData();
105 	total = readStream->readUint16BE();
106 	if (!total) {
107 		spriteBankVersion = readStream->readByte();
108 		if (spriteBankVersion == 1) {
109 			total = 0;
110 		} else {
111 			total = readStream->readUint16BE();
112 		}
113 	}
114 
115 	if (total <= 0)
116 		return fatal("No sprites in bank or invalid sprite bank file");
117 	if (spriteBankVersion > 3)
118 		return fatal("Unsupported sprite bank file format");
119 
120 	loadhere.total = total;
121 	loadhere.sprites = new Sprite[total];
122 	if (!checkNew(loadhere.sprites))
123 		return false;
124 	byte **spriteData = new byte *[total];
125 	if (!checkNew(spriteData))
126 		return false;
127 
128 	// version 1, 2, read how many now
129 	if (spriteBankVersion && spriteBankVersion < 3) {
130 		howmany = readStream->readByte();
131 		startIndex = 1;
132 	}
133 
134 	// version 3, sprite is png
135 	if (spriteBankVersion == 3) {
136 		debugC(2, kSludgeDebugGraphics, "png sprite");
137 		for (int i = 0; i < total; i++) {
138 			loadhere.sprites[i].xhot = readStream->readSint16LE();
139 			loadhere.sprites[i].yhot = readStream->readSint16LE();
140 			if (!ImgLoader::loadPNGImage(readStream, &loadhere.sprites[i].surface, false)) {
141 				return fatal("fail to read png sprite");
142 			}
143 		}
144 		g_sludge->_resMan->finishAccess();
145 		setResourceForFatal(-1);
146 		return true;
147 	}
148 
149 	// version 0, 1, 2
150 	for (int i = 0; i < total; i++) {
151 		uint picwidth, picheight;
152 		// load sprite width, height, relative position
153 		if (spriteBankVersion == 2) {
154 			picwidth = readStream->readUint16BE();
155 			picheight = readStream->readUint16BE();
156 			loadhere.sprites[i].xhot = readStream->readSint16LE();
157 			loadhere.sprites[i].yhot = readStream->readSint16LE();
158 		} else {
159 			picwidth = (byte)readStream->readByte();
160 			picheight = (byte)readStream->readByte();
161 			loadhere.sprites[i].xhot = readStream->readByte();
162 			loadhere.sprites[i].yhot = readStream->readByte();
163 		}
164 
165 		// init data
166 		loadhere.sprites[i].surface.create(picwidth, picheight, *g_sludge->getScreenPixelFormat());
167 		if (isFont) {
168 			loadhere.sprites[i].burnSurface.create(picwidth, picheight, *g_sludge->getScreenPixelFormat());
169 		}
170 		data = (byte *)new byte[picwidth * (picheight + 1)];
171 		if (!checkNew(data))
172 			return false;
173 		memset(data + picwidth * picheight, 0, picwidth);
174 		spriteData[i] = data;
175 
176 		// read color
177 		if (spriteBankVersion == 2) { // RUN LENGTH COMPRESSED DATA
178 			uint size = picwidth * picheight;
179 			uint pip = 0;
180 
181 			while (pip < size) {
182 				byte col = readStream->readByte();
183 				int looper;
184 				if (col > howmany) {
185 					col -= howmany + 1;
186 					looper = readStream->readByte() + 1;
187 				} else
188 					looper = 1;
189 
190 				while (looper--) {
191 					data[pip++] = col;
192 				}
193 			}
194 		} else { // RAW DATA
195 			uint bytes_read = readStream->read(data, picwidth * picheight);
196 			if (bytes_read != picwidth * picheight && readStream->err()) {
197 				warning("Reading error in loadSpriteBank.");
198 			}
199 		}
200 	}
201 
202 	// read howmany for version 0
203 	if (!spriteBankVersion) {
204 		howmany = readStream->readByte();
205 		startIndex = readStream->readByte();
206 	}
207 
208 	// Make palette for version 0, 1, 2
209 	if (!reserveSpritePal(loadhere.myPalette, howmany + startIndex))
210 		return false;
211 	for (int i = 0; i < howmany; i++) {
212 		loadhere.myPalette.r[i + startIndex] = (byte)readStream->readByte();
213 		loadhere.myPalette.g[i + startIndex] = (byte)readStream->readByte();
214 		loadhere.myPalette.b[i + startIndex] = (byte)readStream->readByte();
215 		loadhere.myPalette.pal[i + startIndex] =
216 				(uint16)g_sludge->getOrigPixelFormat()->RGBToColor(
217 						loadhere.myPalette.r[i + startIndex],
218 						loadhere.myPalette.g[i + startIndex],
219 						loadhere.myPalette.b[i + startIndex]);
220 	}
221 	loadhere.myPalette.originalRed = loadhere.myPalette.originalGreen = loadhere.myPalette.originalBlue = 255;
222 
223 	// convert
224 	for (int i = 0; i < total; i++) {
225 		int fromhere = 0;
226 		int transColour = -1;
227 		int size = loadhere.sprites[i].surface.w * loadhere.sprites[i].surface.h;
228 		while (fromhere < size) {
229 			byte s = spriteData[i][fromhere++];
230 			if (s) {
231 				transColour = s;
232 				break;
233 			}
234 		}
235 		fromhere = 0;
236 		for (int y = 0; y < loadhere.sprites[i].surface.h; y++) {
237 			for (int x = 0; x < loadhere.sprites[i].surface.w; x++) {
238 				byte *target = (byte *)loadhere.sprites[i].surface.getBasePtr(x, y);
239 				byte s = spriteData[i][fromhere++];
240 				if (s) {
241 					target[0] = (byte)255;
242 					target[1] = (byte)loadhere.myPalette.b[s];
243 					target[2] = (byte)loadhere.myPalette.g[s];
244 					target[3] = (byte)loadhere.myPalette.r[s];
245 					transColour = s;
246 				} else if (transColour >= 0) {
247 					target[0] = (byte)0;
248 					target[1] = (byte)loadhere.myPalette.b[transColour];
249 					target[2] = (byte)loadhere.myPalette.g[transColour];
250 					target[3] = (byte)loadhere.myPalette.r[transColour];
251 				}
252 				if (isFont) {
253 					target = (byte *)loadhere.sprites[i].burnSurface.getBasePtr(x, y);
254 					if (s)
255 						target[0] = loadhere.myPalette.r[s];
256 					target[1] = (byte)255;
257 					target[2] = (byte)255;
258 					target[3] = (byte)255;
259 				}
260 			}
261 		}
262 		delete[] spriteData[i];
263 	}
264 	delete[] spriteData;
265 	spriteData = NULL;
266 
267 	g_sludge->_resMan->finishAccess();
268 
269 	setResourceForFatal(-1);
270 
271 	return true;
272 }
273 
274 // pasteSpriteToBackDrop uses the colour specified by the setPasteColour (or setPasteColor)
pasteSpriteToBackDrop(int x1,int y1,Sprite & single,const SpritePalette & fontPal)275 void GraphicsManager::pasteSpriteToBackDrop(int x1, int y1, Sprite &single, const SpritePalette &fontPal) {
276 	// kill zBuffer
277 	if (_zBuffer->originalNum >= 0 && _zBuffer->sprites) {
278 		int num = _zBuffer->originalNum;
279 		killZBuffer();
280 		_zBuffer->originalNum = num;
281 	}
282 
283 	//TODO: shader: useLightTexture
284 	x1 -= single.xhot;
285 	y1 -= single.yhot;
286 	Graphics::TransparentSurface tmp(single.surface, false);
287 	tmp.blit(_backdropSurface, x1, y1, Graphics::FLIP_NONE, nullptr,
288 			TS_RGB(fontPal.originalRed, fontPal.originalGreen, fontPal.originalBlue));
289 }
290 
291 // burnSpriteToBackDrop adds text in the colour specified by setBurnColour
292 // using the differing brightness levels of the font to achieve an anti-aliasing effect.
burnSpriteToBackDrop(int x1,int y1,Sprite & single,const SpritePalette & fontPal)293 void GraphicsManager::burnSpriteToBackDrop(int x1, int y1, Sprite &single, const SpritePalette &fontPal) {
294 	// kill zBuffer
295 	if (_zBuffer->originalNum >= 0 && _zBuffer->sprites) {
296 		int num = _zBuffer->originalNum;
297 		killZBuffer();
298 		_zBuffer->originalNum = num;
299 	}
300 
301 	//TODO: shader: useLightTexture
302 	x1 -= single.xhot;
303 	y1 -= single.yhot - 1;
304 	Graphics::TransparentSurface tmp(single.surface, false);
305 	tmp.blit(_backdropSurface, x1, y1, Graphics::FLIP_NONE, nullptr,
306 			TS_RGB(_currentBurnR, _currentBurnG, _currentBurnB));
307 }
308 
fontSprite(bool flip,int x,int y,Sprite & single,const SpritePalette & fontPal)309 void GraphicsManager::fontSprite(bool flip, int x, int y, Sprite &single, const SpritePalette &fontPal) {
310 	float x1 = (float)x - (float)single.xhot / _cameraZoom;
311 	float y1 = (float)y - (float)single.yhot / _cameraZoom;
312 
313 	// Use Transparent surface to scale and blit
314 	Graphics::TransparentSurface tmp(single.surface, false);
315 	tmp.blit(_renderSurface, x1, y1, (flip ? Graphics::FLIP_H : Graphics::FLIP_NONE), 0, TS_RGB(fontPal.originalRed, fontPal.originalGreen, fontPal.originalBlue));
316 
317 	if (single.burnSurface.getPixels() != nullptr) {
318 		Graphics::TransparentSurface tmp2(single.burnSurface, false);
319 		tmp2.blit(_renderSurface, x1, y1, (flip ? Graphics::FLIP_H : Graphics::FLIP_NONE), 0, TS_RGB(fontPal.originalRed, fontPal.originalGreen, fontPal.originalBlue));
320 
321 	}
322 }
323 
fontSprite(int x,int y,Sprite & single,const SpritePalette & fontPal)324 void GraphicsManager::fontSprite(int x, int y, Sprite &single, const SpritePalette &fontPal) {
325 	fontSprite(false, x, y, single, fontPal);
326 }
327 
flipFontSprite(int x,int y,Sprite & single,const SpritePalette & fontPal)328 void GraphicsManager::flipFontSprite(int x, int y, Sprite &single, const SpritePalette &fontPal) {
329 	fontSprite(true, x, y, single, fontPal);
330 }
331 
duplicateSurface(Graphics::Surface * surface)332 Graphics::Surface *GraphicsManager::duplicateSurface(Graphics::Surface *surface) {
333 	Graphics::Surface *res = new Graphics::Surface();
334 	res->copyFrom(*surface);
335 	return res;
336 }
337 
blendColor(Graphics::Surface * blitted,uint32 color,Graphics::TSpriteBlendMode mode)338 void GraphicsManager::blendColor(Graphics::Surface *blitted, uint32 color, Graphics::TSpriteBlendMode mode) {
339 	Graphics::TransparentSurface tmp;
340 	tmp.create(blitted->w, blitted->h, blitted->format);
341 	tmp.fillRect(Common::Rect(0, 0, tmp.w, tmp.h), color);
342 	tmp.blit(*blitted, 0, 0, Graphics::FLIP_NONE, nullptr, TS_ARGB(255, 255, 255, 255), blitted->w, blitted->h, mode);
343 	tmp.free();
344 }
345 
applyLightmapToSprite(Graphics::Surface * & blitted,OnScreenPerson * thisPerson,bool mirror,int x,int y,int x1,int y1,int diffX,int diffY)346 Graphics::Surface *GraphicsManager::applyLightmapToSprite(Graphics::Surface *&blitted, OnScreenPerson *thisPerson, bool mirror, int x, int y, int x1, int y1, int diffX, int diffY) {
347 	Graphics::Surface * toDetele = nullptr;
348 
349 	// if light map is used
350 	bool light = !(thisPerson->extra & EXTRA_NOLITE);
351 
352 	// apply light map and set light map color
353 	byte curLight[3];
354 	if (light && _lightMap.getPixels()) {
355 		if (_lightMapMode == LIGHTMAPMODE_HOTSPOT) {
356 			int lx = x + _cameraX;
357 			int ly = y + _cameraY;
358 			if (lx < 0 || ly < 0 || lx >= (int)_sceneWidth || ly >= (int)_sceneHeight) {
359 				curLight[0] = curLight[1] = curLight[2] = 255;
360 			} else {
361 				byte *target = (byte *)_lightMap.getBasePtr(lx, ly);
362 				curLight[0] = target[3];
363 				curLight[1] = target[2];
364 				curLight[2] = target[1];
365 			}
366 		} else if (_lightMapMode == LIGHTMAPMODE_PIXEL) {
367 			curLight[0] = curLight[1] = curLight[2] = 255;
368 
369 			toDetele = blitted = duplicateSurface(blitted);
370 
371 			// apply light map texture
372 			Graphics::TransparentSurface tmp(_lightMap, false);
373 			Common::Rect rect_none(x1, y1, x1 + diffX, y1 + diffY);
374 			Common::Rect rect_h(_sceneWidth - x1 - diffX, y1, _sceneWidth - x1, y1 + diffY);
375 			tmp.blit(*blitted, 0, 0,
376 					(mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE),
377 					(mirror ? &rect_h : &rect_none),
378 					TS_ARGB(255, 255, 255, 255),
379 					blitted->w, blitted->h, Graphics::BLEND_MULTIPLY);
380 		}
381 	} else {
382 		curLight[0] = curLight[1] = curLight[2] = 255;
383 	}
384 
385 	// calculate light map color
386 	float fr, fg, fb;
387 	fr = fg = fb = 0.0F;
388 	if (thisPerson->colourmix) {
389 		fr = curLight[0]*thisPerson->r * thisPerson->colourmix / 65025 / 255.0F;
390 		fg = curLight[1]*thisPerson->g * thisPerson->colourmix / 65025 / 255.0F;
391 		fb = curLight[2]*thisPerson->b * thisPerson->colourmix / 65025 / 255.0F;
392 	}
393 
394 	uint32 primaryColor = TS_ARGB((uint8)(255 - thisPerson->transparency),
395 			(uint8)(fr + curLight[0] * (255 - thisPerson->colourmix) / 255.f),
396 			(uint8)(fg + curLight[1] * (255 - thisPerson->colourmix) / 255.f),
397 			(uint8)(fb + curLight[2] * (255 - thisPerson->colourmix) / 255.f));
398 
399 	uint32 secondaryColor = TS_ARGB(0, (uint8)(fr * 255), (uint8)(fg * 255), (uint8)(fb * 255));
400 
401 	// apply primary color
402 	if (primaryColor != (uint32)TS_ARGB(255, 255, 255, 255)) {
403 		if (!toDetele) {
404 			toDetele = blitted = duplicateSurface(blitted);
405 			blendColor(blitted, primaryColor, Graphics::BLEND_MULTIPLY);
406 		}
407 	}
408 
409 	// apply secondary light map color
410 	if (secondaryColor != 0x0) {
411 		if (!toDetele) {
412 			toDetele = blitted = duplicateSurface(blitted);
413 		}
414 		blendColor(blitted, secondaryColor, Graphics::BLEND_ADDITIVE);
415 	}
416 	return toDetele;
417 }
418 
scaleSprite(Sprite & single,const SpritePalette & fontPal,OnScreenPerson * thisPerson,bool mirror)419 bool GraphicsManager::scaleSprite(Sprite &single, const SpritePalette &fontPal, OnScreenPerson *thisPerson, bool mirror) {
420 	float x = thisPerson->x;
421 	float y = thisPerson->y;
422 
423 	float scale = thisPerson->scale;
424 	bool useZB = !(thisPerson->extra & EXTRA_NOZB);
425 
426 	if (scale <= 0.05)
427 		return false;
428 
429 	int diffX = (int)(((float)single.surface.w) * scale);
430 	int diffY = (int)(((float)single.surface.h) * scale);
431 
432 	float x1, y1, x2, y2;
433 
434 	if (thisPerson->extra & EXTRA_FIXTOSCREEN) {
435 		x = x / _cameraZoom;
436 		y = y / _cameraZoom;
437 		if (single.xhot < 0)
438 			x1 = x - (int)((mirror ? (float)(single.surface.w - single.xhot) : (float)(single.xhot + 1)) * scale / _cameraZoom);
439 		else
440 			x1 = x - (int)((mirror ? (float)(single.surface.w - (single.xhot + 1)) : (float)single.xhot) * scale / _cameraZoom);
441 		y1 = y - (int)((single.yhot - thisPerson->floaty) * scale / _cameraZoom);
442 		x2 = x1 + (int)(diffX / _cameraZoom);
443 		y2 = y1 + (int)(diffY / _cameraZoom);
444 	} else {
445 		x -= _cameraX;
446 		y -= _cameraY;
447 		if (single.xhot < 0)
448 			x1 = x - (int)((mirror ? (float)(single.surface.w - single.xhot) : (float)(single.xhot + 1)) * scale);
449 		else
450 			x1 = x - (int)((mirror ? (float)(single.surface.w - (single.xhot + 1)) : (float)single.xhot) * scale);
451 		y1 = y - (int)((single.yhot - thisPerson->floaty) * scale);
452 		x2 = x1 + diffX;
453 		y2 = y1 + diffY;
454 	}
455 
456 	Graphics::Surface *blitted = &single.surface;
457 	Graphics::Surface *ptr = applyLightmapToSprite(blitted, thisPerson, mirror, x, y, x1, y1, diffX, diffY);
458 
459 	// Use Transparent surface to scale and blit
460 	if (!_zBuffer->numPanels) {
461 		Graphics::TransparentSurface tmp(*blitted, false);
462 		tmp.blit(_renderSurface, x1, y1, (mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE), nullptr, TS_ARGB(255, 255, 255, 255), diffX, diffY);
463 		if (ptr) {
464 			ptr->free();
465 			delete ptr;
466 			ptr = nullptr;
467 		}
468 	} else {
469 		int d = useZB ? y + _cameraY : (y + _cameraY > _sceneHeight * 0.6 ? _sceneHeight + 1 : 0);
470 		addSpriteDepth(blitted, d, x1, y1, (mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE), diffX, diffY, ptr);
471 	}
472 
473 	// Are we pointing at the sprite?
474 	if (_vm->_evtMan->mouseX() >= x1 && _vm->_evtMan->mouseX() <= x2
475 			&& _vm->_evtMan->mouseY() >= y1 && _vm->_evtMan->mouseY() <= y2) {
476 		if (thisPerson->extra & EXTRA_RECTANGULAR)
477 			return true;
478 
479 		// check if point to non transparent part
480 		int pixelx = (int)(single.surface.w * (_vm->_evtMan->mouseX() - x1) / (x2 - x1));
481 		int pixely = (int)(single.surface.h * (_vm->_evtMan->mouseY() - y1) / (y2 - y1));
482 		uint32 *colorPtr = (uint32 *)single.surface.getBasePtr(pixelx, pixely);
483 
484 		uint8 a, r, g, b;
485 		g_sludge->getScreenPixelFormat()->colorToARGB(*colorPtr, a, r, g, b);
486 		return a != 0;
487 	}
488 	return false;
489 }
490 
resetSpriteLayers(ZBufferData * pz,int x,int y,bool upsidedown)491 void GraphicsManager::resetSpriteLayers(ZBufferData *pz, int x, int y, bool upsidedown) {
492 	if (_spriteLayers->numLayers > 0)
493 		killSpriteLayers();
494 	_spriteLayers->numLayers = pz->numPanels;
495 	debugC(3, kSludgeDebugZBuffer, "%i zBuffer layers", _spriteLayers->numLayers);
496 	for (int i = 0; i < _spriteLayers->numLayers; ++i) {
497 		SpriteDisplay *node = new SpriteDisplay(x, y, (upsidedown ? Graphics::FLIP_V : Graphics::FLIP_NONE), &pz->sprites[i], pz->sprites[i].w, pz->sprites[i].h);
498 		_spriteLayers->layer[i].push_back(node);
499 		debugC(3, kSludgeDebugZBuffer, "Layer %i is of depth %i", i, pz->panel[i]);
500 	}
501 }
502 
addSpriteDepth(Graphics::Surface * ptr,int depth,int x,int y,Graphics::FLIP_FLAGS flip,int width,int height,bool freeAfterUse)503 void GraphicsManager::addSpriteDepth(Graphics::Surface *ptr, int depth, int x, int y, Graphics::FLIP_FLAGS flip, int width, int height, bool freeAfterUse) {
504 	int i;
505 	for (i = 1; i < _zBuffer->numPanels; ++i) {
506 		if (_zBuffer->panel[i] >= depth) {
507 			break;
508 		}
509 	}
510 	--i;
511 	debugC(3, kSludgeDebugZBuffer, "Add sprite of Y-value : %i in layer %i", depth, i);
512 
513 	SpriteDisplay *node = new SpriteDisplay(x, y, flip, ptr, width, height, freeAfterUse);
514 	_spriteLayers->layer[i].push_back(node);
515 }
516 
displaySpriteLayers()517 void GraphicsManager::displaySpriteLayers() {
518 	for (int i = 0; i < _spriteLayers->numLayers; ++i) {
519 		debugC(3, kSludgeDebugGraphics, "Display layer %i with %i sprites", i, _spriteLayers->layer[i].size());
520 		SpriteLayer::iterator it;
521 		for (it = _spriteLayers->layer[i].begin(); it != _spriteLayers->layer[i].end(); ++it) {
522 			Graphics::TransparentSurface tmp(*(*it)->surface, false);
523 			tmp.blit(_renderSurface, (*it)->x, (*it)->y, (*it)->flip, nullptr, TS_ARGB(255, 255, 255, 255), (*it)->width, (*it)->height);
524 		}
525 	}
526 	killSpriteLayers();
527 }
528 
killSpriteLayers()529 void GraphicsManager::killSpriteLayers() {
530 	for (int i = 0; i < _spriteLayers->numLayers; ++i) {
531 		SpriteLayer::iterator it;
532 		for (it = _spriteLayers->layer[i].begin(); it != _spriteLayers->layer[i].end(); ++it) {
533 			if ((*it)->freeAfterUse) {
534 				(*it)->surface->free();
535 				delete (*it)->surface;
536 				(*it)->surface = nullptr;
537 			}
538 			delete (*it);
539 			(*it) = nullptr;
540 		}
541 		_spriteLayers->layer[i].clear();
542 	}
543 	_spriteLayers->numLayers = 0;
544 }
545 
546 // Paste a scaled sprite onto the backdrop
fixScaleSprite(int x,int y,Sprite & single,const SpritePalette & fontPal,OnScreenPerson * thisPerson,int camX,int camY,bool mirror)547 void GraphicsManager::fixScaleSprite(int x, int y, Sprite &single, const SpritePalette &fontPal, OnScreenPerson *thisPerson, int camX, int camY, bool mirror) {
548 
549 	float scale = thisPerson->scale;
550 	bool useZB = !(thisPerson->extra & EXTRA_NOZB);
551 
552 	if (scale <= 0.05)
553 		return;
554 
555 	int diffX = (int)(((float)single.surface.w) * scale);
556 	int diffY = (int)(((float)single.surface.h) * scale);
557 	int x1;
558 	if (single.xhot < 0)
559 		x1 = x - (int)((mirror ? (float)(single.surface.w - single.xhot) : (float)(single.xhot + 1)) * scale);
560 	else
561 		x1 = x - (int)((mirror ? (float)(single.surface.w - (single.xhot + 1)) : (float)single.xhot) * scale);
562 	int y1 = y - (int)((single.yhot - thisPerson->floaty) * scale);
563 
564 	Graphics::Surface *blitted = &single.surface;
565 	Graphics::Surface *ptr = applyLightmapToSprite(blitted, thisPerson, mirror, x, y, x1, y1, diffX, diffY);
566 
567 	// draw backdrop
568 	drawBackDrop();
569 
570 	// draw zBuffer
571 	if (_zBuffer->numPanels) {
572 		drawZBuffer((int)(x1 + camX), (int)(y1 + camY), false);
573 	}
574 
575 	// draw sprite
576 	if (!_zBuffer->numPanels) {
577 		Graphics::TransparentSurface tmp(single.surface, false);
578 		tmp.blit(_renderSurface, x1, y1, (mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE), nullptr, TS_ARGB(255, 255, 255, 255), diffX, diffY);
579 		if (ptr) {
580 			ptr->free();
581 			delete ptr;
582 			ptr = nullptr;
583 		}
584 	} else {
585 		int d = useZB ? y + _cameraY : (y + _cameraY > _sceneHeight * 0.6 ? _sceneHeight + 1 : 0);
586 		addSpriteDepth(&single.surface, d, x1, y1, (mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE), diffX, diffY, ptr);
587 	}
588 
589 	// draw all
590 	displaySpriteLayers();
591 
592 	// copy screen to backdrop
593 	_backdropSurface.copyFrom(_renderSurface);
594 }
595 
596 } // End of namespace Sludge
597