2 Copyright (C) 2015 Aaron Suen <warr1024@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "guiscalingfilter.h"
20 #include "imagefilters.h"
22 #include "util/numeric.h"
25 /* Maintain a static cache to store the images that correspond to textures
26 * in a format that's manipulable by code. Some platforms exhibit issues
27 * converting textures back into images repeatedly, and some don't even
30 std::map
<io::path
, video::IImage
*> g_imgCache
;
32 /* Maintain a static cache of all pre-scaled textures. These need to be
33 * cleared as well when the cached images.
35 std::map
<io::path
, video::ITexture
*> g_txrCache
;
37 /* Manually insert an image into the cache, useful to avoid texture-to-image
38 * conversion whenever we can intercept it.
40 void guiScalingCache(io::path key
, video::IVideoDriver
*driver
, video::IImage
*value
)
42 if (!g_settings
->getBool("gui_scaling_filter"))
44 video::IImage
*copied
= driver
->createImage(value
->getColorFormat(),
45 value
->getDimension());
46 value
->copyTo(copied
);
47 g_imgCache
[key
] = copied
;
50 // Manually clear the cache, e.g. when switching to different worlds.
51 void guiScalingCacheClear(video::IVideoDriver
*driver
)
53 for (std::map
<io::path
, video::IImage
*>::iterator it
= g_imgCache
.begin();
54 it
!= g_imgCache
.end(); ++it
) {
55 if (it
->second
!= NULL
)
59 for (std::map
<io::path
, video::ITexture
*>::iterator it
= g_txrCache
.begin();
60 it
!= g_txrCache
.end(); ++it
) {
61 if (it
->second
!= NULL
)
62 driver
->removeTexture(it
->second
);
67 /* Get a cached, high-quality pre-scaled texture for display purposes. If the
68 * texture is not already cached, attempt to create it. Returns a pre-scaled texture,
69 * or the original texture if unable to pre-scale it.
71 video::ITexture
*guiScalingResizeCached(video::IVideoDriver
*driver
,
72 video::ITexture
*src
, const core::rect
<s32
> &srcrect
,
73 const core::rect
<s32
> &destrect
)
77 if (!g_settings
->getBool("gui_scaling_filter"))
80 // Calculate scaled texture name.
82 snprintf(rectstr
, sizeof(rectstr
), "%d:%d:%d:%d:%d:%d",
83 srcrect
.UpperLeftCorner
.X
,
84 srcrect
.UpperLeftCorner
.Y
,
88 destrect
.getHeight());
89 io::path origname
= src
->getName().getPath();
90 io::path scalename
= origname
+ "@guiScalingFilter:" + rectstr
;
92 // Search for existing scaled texture.
93 video::ITexture
*scaled
= g_txrCache
[scalename
];
97 // Try to find the texture converted to an image in the cache.
98 // If the image was not found, try to extract it from the texture.
99 video::IImage
* srcimg
= g_imgCache
[origname
];
100 if (srcimg
== NULL
) {
101 if (!g_settings
->getBool("gui_scaling_filter_txr2img"))
103 srcimg
= driver
->createImageFromData(src
->getColorFormat(),
104 src
->getSize(), src
->lock(), false);
106 g_imgCache
[origname
] = srcimg
;
109 // Create a new destination image and scale the source into it.
110 imageCleanTransparent(srcimg
, 0);
111 video::IImage
*destimg
= driver
->createImage(src
->getColorFormat(),
112 core::dimension2d
<u32
>((u32
)destrect
.getWidth(),
113 (u32
)destrect
.getHeight()));
114 imageScaleNNAA(srcimg
, srcrect
, destimg
);
117 // Android is very picky about textures being powers of 2, so expand
118 // the image dimensions to the next power of 2, if necessary, for
120 video::IImage
*po2img
= driver
->createImage(src
->getColorFormat(),
121 core::dimension2d
<u32
>(npot2((u32
)destrect
.getWidth()),
122 npot2((u32
)destrect
.getHeight())));
123 po2img
->fill(video::SColor(0, 0, 0, 0));
124 destimg
->copyTo(po2img
);
129 // Convert the scaled image back into a texture.
130 scaled
= driver
->addTexture(scalename
, destimg
, NULL
);
132 g_txrCache
[scalename
] = scaled
;
137 /* Convenience wrapper for guiScalingResizeCached that accepts parameters that
138 * are available at GUI imagebutton creation time.
140 video::ITexture
*guiScalingImageButton(video::IVideoDriver
*driver
,
141 video::ITexture
*src
, s32 width
, s32 height
)
145 return guiScalingResizeCached(driver
, src
,
146 core::rect
<s32
>(0, 0, src
->getSize().Width
, src
->getSize().Height
),
147 core::rect
<s32
>(0, 0, width
, height
));
150 /* Replacement for driver->draw2DImage() that uses the high-quality pre-scaled
151 * texture, if configured.
153 void draw2DImageFilterScaled(video::IVideoDriver
*driver
, video::ITexture
*txr
,
154 const core::rect
<s32
> &destrect
, const core::rect
<s32
> &srcrect
,
155 const core::rect
<s32
> *cliprect
, const video::SColor
*const colors
,
158 // Attempt to pre-scale image in software in high quality.
159 video::ITexture
*scaled
= guiScalingResizeCached(driver
, txr
, srcrect
, destrect
);
163 // Correct source rect based on scaled image.
164 const core::rect
<s32
> mysrcrect
= (scaled
!= txr
)
165 ? core::rect
<s32
>(0, 0, destrect
.getWidth(), destrect
.getHeight())
168 driver
->draw2DImage(scaled
, destrect
, mysrcrect
, cliprect
, colors
, usealpha
);