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