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