1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
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 "engines/stark/visual/image.h"
24 
25 #include "graphics/surface.h"
26 #include "image/png.h"
27 
28 #include "engines/stark/formats/xmg.h"
29 #include "engines/stark/gfx/driver.h"
30 #include "engines/stark/gfx/surfacerenderer.h"
31 #include "engines/stark/gfx/texture.h"
32 #include "engines/stark/services/services.h"
33 #include "engines/stark/services/settings.h"
34 
35 namespace Stark {
36 
VisualImageXMG(Gfx::Driver * gfx)37 VisualImageXMG::VisualImageXMG(Gfx::Driver *gfx) :
38 		Visual(TYPE),
39 		_gfx(gfx),
40 		_texture(nullptr),
41 		_surface(nullptr),
42 		_originalWidth(0),
43 		_originalHeight(0) {
44 	_surfaceRenderer = _gfx->createSurfaceRenderer();
45 }
46 
~VisualImageXMG()47 VisualImageXMG::~VisualImageXMG() {
48 	if (_surface) {
49 		_surface->free();
50 	}
51 	delete _surface;
52 	delete _texture;
53 	delete _surfaceRenderer;
54 }
55 
setHotSpot(const Common::Point & hotspot)56 void VisualImageXMG::setHotSpot(const Common::Point &hotspot) {
57 	_hotspot = hotspot;
58 }
59 
load(Common::ReadStream * stream)60 void VisualImageXMG::load(Common::ReadStream *stream) {
61 	assert(!_surface && !_texture);
62 
63 	// Decode the XMG
64 	_surface = Formats::XMGDecoder::decode(stream);
65 	_texture = _gfx->createBitmap(_surface);
66 	_texture->setSamplingFilter(StarkSettings->getImageSamplingFilter());
67 
68 	_originalWidth  = _surface->w;
69 	_originalHeight = _surface->h;
70 }
71 
readOriginalSize(Common::ReadStream * stream)72 void VisualImageXMG::readOriginalSize(Common::ReadStream *stream) {
73 	Formats::XMGDecoder::readSize(stream, _originalWidth, _originalHeight);
74 }
75 
loadPNG(Common::SeekableReadStream * stream)76 bool VisualImageXMG::loadPNG(Common::SeekableReadStream *stream) {
77 	assert(!_surface && !_texture);
78 
79 	// Decode the XMG
80 	Image::PNGDecoder pngDecoder;
81 	if (!pngDecoder.loadStream(*stream)) {
82 		return false;
83 	}
84 
85 	if (pngDecoder.getPalette()) {
86 		warning("Indexed colors PNG images are not supported");
87 		return false;
88 	}
89 
90 	if (StarkSettings->shouldPreMultiplyReplacementPNGs()) {
91 		// We can do alpha pre-multiplication when loading for
92 		// convenience when testing modded graphics.
93 		_surface = multiplyColorWithAlpha(pngDecoder.getSurface());
94 	} else {
95 		_surface = pngDecoder.getSurface()->convertTo(Gfx::Driver::getRGBAPixelFormat());
96 	}
97 
98 	_texture = _gfx->createBitmap(_surface);
99 	_texture->setSamplingFilter(StarkSettings->getImageSamplingFilter());
100 
101 	return true;
102 }
103 
multiplyColorWithAlpha(const Graphics::Surface * source)104 Graphics::Surface *VisualImageXMG::multiplyColorWithAlpha(const Graphics::Surface *source) {
105 	assert(source->format == Gfx::Driver::getRGBAPixelFormat());
106 
107 	Graphics::Surface *dest = new Graphics::Surface();
108 	dest->create(source->w, source->h, Gfx::Driver::getRGBAPixelFormat());
109 
110 	for (int y = 0; y < source->h; y++) {
111 		const uint8 *src = (const uint8 *) source->getBasePtr(0, y);
112 		uint8 *dst = (uint8 *) dest->getBasePtr(0, y);
113 
114 		for (int x = 0; x < source->w; x++) {
115 			uint8 a, r, g, b;
116 			r = *src++;
117 			g = *src++;
118 			b = *src++;
119 			a = *src++;
120 
121 			if (a != 0xFF) {
122 				r = (int) r * a / 255;
123 				g = (int) g * a / 255;
124 				b = (int) b * a / 255;
125 			}
126 
127 			*dst++ = r;
128 			*dst++ = g;
129 			*dst++ = b;
130 			*dst++ = a;
131 		}
132 	}
133 
134 	return dest;
135 }
136 
render(const Common::Point & position,bool useOffset)137 void VisualImageXMG::render(const Common::Point &position, bool useOffset) {
138 	render(position, useOffset, true);
139 }
140 
render(const Common::Point & position,bool useOffset,bool unscaled)141 void VisualImageXMG::render(const Common::Point &position, bool useOffset, bool unscaled) {
142 	Common::Point drawPos = useOffset ? position - _hotspot : position;
143 
144 	if (!unscaled) {
145 		uint width = _gfx->scaleWidthOriginalToCurrent(_originalWidth);
146 		uint height = _gfx->scaleHeightOriginalToCurrent(_originalHeight);
147 		_surfaceRenderer->render(_texture, drawPos, width, height);
148 	} else {
149 		_surfaceRenderer->render(_texture, drawPos, _originalWidth, _originalHeight);
150 	}
151 }
152 
setFadeLevel(float fadeLevel)153 void VisualImageXMG::setFadeLevel(float fadeLevel) {
154 	_surfaceRenderer->setFadeLevel(fadeLevel);
155 }
156 
isPointSolid(const Common::Point & point) const157 bool VisualImageXMG::isPointSolid(const Common::Point &point) const {
158 	assert(_surface);
159 
160 	if (_originalWidth < 32 || _originalHeight < 32) {
161 		return true; // Small images are always solid
162 	}
163 
164 	Common::Point scaledPoint;
165 	scaledPoint.x = point.x * _surface->w / _originalWidth;
166 	scaledPoint.y = point.y * _surface->h / _originalHeight;
167 	scaledPoint.x = CLIP<uint16>(scaledPoint.x, 0, _surface->w);
168 	scaledPoint.y = CLIP<uint16>(scaledPoint.y, 0, _surface->h);
169 
170 	// Maybe implement this method in some other way to avoid having to keep the surface in memory
171 	const byte *ptr = (const byte *) _surface->getBasePtr(scaledPoint.x, scaledPoint.y);
172 	return *(ptr + 3) == 0xFF;
173 }
174 
getWidth() const175 int VisualImageXMG::getWidth() const {
176 	return _originalWidth;
177 }
178 
getHeight() const179 int VisualImageXMG::getHeight() const {
180 	return _originalHeight;
181 }
182 
getSurface() const183 const Graphics::Surface *VisualImageXMG::getSurface() const {
184 	assert(_surface);
185 	return _surface;
186 }
187 
188 } // End of namespace Stark
189