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