|
|
|
@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
|
|
|
|
|
|
#include "tile.h"
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <ICameraSceneNode.h>
|
|
|
|
|
#include "util/string.h"
|
|
|
|
|
#include "util/container.h"
|
|
|
|
@ -362,12 +363,6 @@ public:
|
|
|
|
|
// Shall be called from the main thread.
|
|
|
|
|
void rebuildImagesAndTextures();
|
|
|
|
|
|
|
|
|
|
// Render a mesh to a texture.
|
|
|
|
|
// Returns NULL if render-to-texture failed.
|
|
|
|
|
// Shall be called from the main thread.
|
|
|
|
|
video::ITexture* generateTextureFromMesh(
|
|
|
|
|
const TextureFromMeshParams ¶ms);
|
|
|
|
|
|
|
|
|
|
video::ITexture* getNormalTexture(const std::string &name);
|
|
|
|
|
video::SColor getTextureAverageColor(const std::string &name);
|
|
|
|
|
video::ITexture *getShaderFlagsTexture(bool normamap_present);
|
|
|
|
@ -775,205 +770,121 @@ void TextureSource::rebuildImagesAndTextures()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
video::ITexture* TextureSource::generateTextureFromMesh(
|
|
|
|
|
const TextureFromMeshParams ¶ms)
|
|
|
|
|
inline static void applyShadeFactor(video::SColor &color, u32 factor)
|
|
|
|
|
{
|
|
|
|
|
u32 f = core::clamp<u32>(factor, 0, 256);
|
|
|
|
|
color.setRed(color.getRed() * f / 256);
|
|
|
|
|
color.setGreen(color.getGreen() * f / 256);
|
|
|
|
|
color.setBlue(color.getBlue() * f / 256);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static video::IImage *createInventoryCubeImage(
|
|
|
|
|
video::IImage *top, video::IImage *left, video::IImage *right)
|
|
|
|
|
{
|
|
|
|
|
core::dimension2du size_top = top->getDimension();
|
|
|
|
|
core::dimension2du size_left = left->getDimension();
|
|
|
|
|
core::dimension2du size_right = right->getDimension();
|
|
|
|
|
|
|
|
|
|
u32 size = npot2(std::max({
|
|
|
|
|
size_top.Width, size_top.Height,
|
|
|
|
|
size_left.Width, size_left.Height,
|
|
|
|
|
size_right.Width, size_right.Height,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// It must be divisible by 4, to let everything work correctly.
|
|
|
|
|
// But it is a power of 2, so being at least 4 is the same.
|
|
|
|
|
// And the resulting texture should't be too large as well.
|
|
|
|
|
size = core::clamp<u32>(size, 4, 64);
|
|
|
|
|
|
|
|
|
|
// With such parameters, the cube fits exactly, touching each image line
|
|
|
|
|
// from `0` to `cube_size - 1`. (Note that division is exact here).
|
|
|
|
|
u32 cube_size = 9 * size;
|
|
|
|
|
u32 offset = size / 2;
|
|
|
|
|
|
|
|
|
|
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
|
|
|
|
sanity_check(driver);
|
|
|
|
|
|
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
|
const GLubyte* renderstr = glGetString(GL_RENDERER);
|
|
|
|
|
std::string renderer((char*) renderstr);
|
|
|
|
|
|
|
|
|
|
// use no render to texture hack
|
|
|
|
|
if (
|
|
|
|
|
(renderer.find("Adreno") != std::string::npos) ||
|
|
|
|
|
(renderer.find("Mali") != std::string::npos) ||
|
|
|
|
|
(renderer.find("Immersion") != std::string::npos) ||
|
|
|
|
|
(renderer.find("Tegra") != std::string::npos) ||
|
|
|
|
|
g_settings->getBool("inventory_image_hack")
|
|
|
|
|
) {
|
|
|
|
|
// Get a scene manager
|
|
|
|
|
scene::ISceneManager *smgr_main = RenderingEngine::get_raw_device()->getSceneManager();
|
|
|
|
|
sanity_check(smgr_main);
|
|
|
|
|
scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
|
|
|
|
|
sanity_check(smgr);
|
|
|
|
|
|
|
|
|
|
const float scaling = 0.2;
|
|
|
|
|
|
|
|
|
|
scene::IMeshSceneNode* meshnode =
|
|
|
|
|
smgr->addMeshSceneNode(params.mesh, NULL,
|
|
|
|
|
-1, v3f(0,0,0), v3f(0,0,0),
|
|
|
|
|
v3f(1.0 * scaling,1.0 * scaling,1.0 * scaling), true);
|
|
|
|
|
meshnode->setMaterialFlag(video::EMF_LIGHTING, true);
|
|
|
|
|
meshnode->setMaterialFlag(video::EMF_ANTI_ALIASING, true);
|
|
|
|
|
meshnode->setMaterialFlag(video::EMF_TRILINEAR_FILTER, m_setting_trilinear_filter);
|
|
|
|
|
meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, m_setting_bilinear_filter);
|
|
|
|
|
meshnode->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, m_setting_anisotropic_filter);
|
|
|
|
|
|
|
|
|
|
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
|
|
|
|
|
params.camera_position, params.camera_lookat);
|
|
|
|
|
// second parameter of setProjectionMatrix (isOrthogonal) is ignored
|
|
|
|
|
camera->setProjectionMatrix(params.camera_projection_matrix, false);
|
|
|
|
|
|
|
|
|
|
smgr->setAmbientLight(params.ambient_light);
|
|
|
|
|
smgr->addLightSceneNode(0,
|
|
|
|
|
params.light_position,
|
|
|
|
|
params.light_color,
|
|
|
|
|
params.light_radius*scaling);
|
|
|
|
|
|
|
|
|
|
core::dimension2d<u32> screen = driver->getScreenSize();
|
|
|
|
|
|
|
|
|
|
// Render scene
|
|
|
|
|
driver->beginScene(true, true, video::SColor(0,0,0,0));
|
|
|
|
|
driver->clearZBuffer();
|
|
|
|
|
smgr->drawAll();
|
|
|
|
|
|
|
|
|
|
core::dimension2d<u32> partsize(screen.Width * scaling,screen.Height * scaling);
|
|
|
|
|
|
|
|
|
|
irr::video::IImage* rawImage =
|
|
|
|
|
driver->createImage(irr::video::ECF_A8R8G8B8, partsize);
|
|
|
|
|
|
|
|
|
|
u8* pixels = static_cast<u8*>(rawImage->lock());
|
|
|
|
|
if (!pixels)
|
|
|
|
|
{
|
|
|
|
|
rawImage->drop();
|
|
|
|
|
return NULL;
|
|
|
|
|
auto lock_image = [size, driver] (video::IImage *&image) -> const u32 * {
|
|
|
|
|
image->grab();
|
|
|
|
|
core::dimension2du dim = image->getDimension();
|
|
|
|
|
video::ECOLOR_FORMAT format = image->getColorFormat();
|
|
|
|
|
if (dim.Width != size || dim.Height != size || format != video::ECF_A8R8G8B8) {
|
|
|
|
|
video::IImage *scaled = driver->createImage(video::ECF_A8R8G8B8, {size, size});
|
|
|
|
|
image->copyToScaling(scaled);
|
|
|
|
|
image->drop();
|
|
|
|
|
image = scaled;
|
|
|
|
|
}
|
|
|
|
|
sanity_check(image->getPitch() == 4 * size);
|
|
|
|
|
return reinterpret_cast<u32 *>(image->lock());
|
|
|
|
|
};
|
|
|
|
|
auto free_image = [] (video::IImage *image) -> void {
|
|
|
|
|
image->unlock();
|
|
|
|
|
image->drop();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
core::rect<s32> source(
|
|
|
|
|
screen.Width /2 - (screen.Width * (scaling / 2)),
|
|
|
|
|
screen.Height/2 - (screen.Height * (scaling / 2)),
|
|
|
|
|
screen.Width /2 + (screen.Width * (scaling / 2)),
|
|
|
|
|
screen.Height/2 + (screen.Height * (scaling / 2))
|
|
|
|
|
);
|
|
|
|
|
video::IImage *result = driver->createImage(video::ECF_A8R8G8B8, {cube_size, cube_size});
|
|
|
|
|
sanity_check(result->getPitch() == 4 * cube_size);
|
|
|
|
|
result->fill(video::SColor(0x00000000u));
|
|
|
|
|
u32 *target = reinterpret_cast<u32 *>(result->lock());
|
|
|
|
|
|
|
|
|
|
glReadPixels(source.UpperLeftCorner.X, source.UpperLeftCorner.Y,
|
|
|
|
|
partsize.Width, partsize.Height, GL_RGBA,
|
|
|
|
|
GL_UNSIGNED_BYTE, pixels);
|
|
|
|
|
|
|
|
|
|
driver->endScene();
|
|
|
|
|
|
|
|
|
|
// Drop scene manager
|
|
|
|
|
smgr->drop();
|
|
|
|
|
|
|
|
|
|
unsigned int pixelcount = partsize.Width*partsize.Height;
|
|
|
|
|
|
|
|
|
|
u8* runptr = pixels;
|
|
|
|
|
for (unsigned int i=0; i < pixelcount; i++) {
|
|
|
|
|
|
|
|
|
|
u8 B = *runptr;
|
|
|
|
|
u8 G = *(runptr+1);
|
|
|
|
|
u8 R = *(runptr+2);
|
|
|
|
|
u8 A = *(runptr+3);
|
|
|
|
|
|
|
|
|
|
//BGRA -> RGBA
|
|
|
|
|
*runptr = R;
|
|
|
|
|
runptr ++;
|
|
|
|
|
*runptr = G;
|
|
|
|
|
runptr ++;
|
|
|
|
|
*runptr = B;
|
|
|
|
|
runptr ++;
|
|
|
|
|
*runptr = A;
|
|
|
|
|
runptr ++;
|
|
|
|
|
// Draws single cube face
|
|
|
|
|
// `shade_factor` is face brightness, in range [0.0, 1.0]
|
|
|
|
|
// (xu, xv, x1; yu, yv, y1) form coordinate transformation matrix
|
|
|
|
|
// `offsets` list pixels to be drawn for single source pixel
|
|
|
|
|
auto draw_image = [=] (video::IImage *image, float shade_factor,
|
|
|
|
|
s16 xu, s16 xv, s16 x1,
|
|
|
|
|
s16 yu, s16 yv, s16 y1,
|
|
|
|
|
std::initializer_list<v2s16> offsets) -> void {
|
|
|
|
|
u32 brightness = core::clamp<u32>(256 * shade_factor, 0, 256);
|
|
|
|
|
const u32 *source = lock_image(image);
|
|
|
|
|
for (u16 v = 0; v < size; v++) {
|
|
|
|
|
for (u16 u = 0; u < size; u++) {
|
|
|
|
|
video::SColor pixel(*source);
|
|
|
|
|
applyShadeFactor(pixel, brightness);
|
|
|
|
|
s16 x = xu * u + xv * v + x1;
|
|
|
|
|
s16 y = yu * u + yv * v + y1;
|
|
|
|
|
for (const auto &off : offsets)
|
|
|
|
|
target[(y + off.Y) * cube_size + (x + off.X) + offset] = pixel.color;
|
|
|
|
|
source++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free_image(image);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
video::IImage* inventory_image =
|
|
|
|
|
driver->createImage(irr::video::ECF_A8R8G8B8, params.dim);
|
|
|
|
|
draw_image(top, 1.000000f,
|
|
|
|
|
4, -4, 4 * (size - 1),
|
|
|
|
|
2, 2, 0,
|
|
|
|
|
{
|
|
|
|
|
{2, 0}, {3, 0}, {4, 0}, {5, 0},
|
|
|
|
|
{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1},
|
|
|
|
|
{2, 2}, {3, 2}, {4, 2}, {5, 2},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
rawImage->copyToScaling(inventory_image);
|
|
|
|
|
rawImage->drop();
|
|
|
|
|
draw_image(left, 0.836660f,
|
|
|
|
|
4, 0, 0,
|
|
|
|
|
2, 5, 2 * size,
|
|
|
|
|
{
|
|
|
|
|
{0, 0}, {1, 0},
|
|
|
|
|
{0, 1}, {1, 1}, {2, 1}, {3, 1},
|
|
|
|
|
{0, 2}, {1, 2}, {2, 2}, {3, 2},
|
|
|
|
|
{0, 3}, {1, 3}, {2, 3}, {3, 3},
|
|
|
|
|
{0, 4}, {1, 4}, {2, 4}, {3, 4},
|
|
|
|
|
{2, 5}, {3, 5},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
guiScalingCache(io::path(params.rtt_texture_name.c_str()), driver, inventory_image);
|
|
|
|
|
draw_image(right, 0.670820f,
|
|
|
|
|
4, 0, 4 * size,
|
|
|
|
|
-2, 5, 4 * size - 2,
|
|
|
|
|
{
|
|
|
|
|
{2, 0}, {3, 0},
|
|
|
|
|
{0, 1}, {1, 1}, {2, 1}, {3, 1},
|
|
|
|
|
{0, 2}, {1, 2}, {2, 2}, {3, 2},
|
|
|
|
|
{0, 3}, {1, 3}, {2, 3}, {3, 3},
|
|
|
|
|
{0, 4}, {1, 4}, {2, 4}, {3, 4},
|
|
|
|
|
{0, 5}, {1, 5},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
video::ITexture *rtt = driver->addTexture(params.rtt_texture_name.c_str(), inventory_image);
|
|
|
|
|
inventory_image->drop();
|
|
|
|
|
|
|
|
|
|
if (rtt == NULL) {
|
|
|
|
|
errorstream << "TextureSource::generateTextureFromMesh(): failed to recreate texture from image: " << params.rtt_texture_name << std::endl;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
driver->makeColorKeyTexture(rtt, v2s32(0,0));
|
|
|
|
|
|
|
|
|
|
if (params.delete_texture_on_shutdown)
|
|
|
|
|
m_texture_trash.push_back(rtt);
|
|
|
|
|
|
|
|
|
|
return rtt;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (!driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) {
|
|
|
|
|
static bool warned = false;
|
|
|
|
|
if (!warned)
|
|
|
|
|
{
|
|
|
|
|
errorstream<<"TextureSource::generateTextureFromMesh(): "
|
|
|
|
|
<<"EVDF_RENDER_TO_TARGET not supported."<<std::endl;
|
|
|
|
|
warned = true;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create render target texture
|
|
|
|
|
video::ITexture *rtt = driver->addRenderTargetTexture(
|
|
|
|
|
params.dim, params.rtt_texture_name.c_str(),
|
|
|
|
|
video::ECF_A8R8G8B8);
|
|
|
|
|
if (rtt == NULL)
|
|
|
|
|
{
|
|
|
|
|
errorstream<<"TextureSource::generateTextureFromMesh(): "
|
|
|
|
|
<<"addRenderTargetTexture returned NULL."<<std::endl;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set render target
|
|
|
|
|
if (!driver->setRenderTarget(rtt, false, true, video::SColor(0,0,0,0))) {
|
|
|
|
|
driver->removeTexture(rtt);
|
|
|
|
|
errorstream<<"TextureSource::generateTextureFromMesh(): "
|
|
|
|
|
<<"failed to set render target"<<std::endl;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get a scene manager
|
|
|
|
|
scene::ISceneManager *smgr_main = RenderingEngine::get_scene_manager();
|
|
|
|
|
assert(smgr_main);
|
|
|
|
|
scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
|
|
|
|
|
assert(smgr);
|
|
|
|
|
|
|
|
|
|
scene::IMeshSceneNode* meshnode =
|
|
|
|
|
smgr->addMeshSceneNode(params.mesh, NULL,
|
|
|
|
|
-1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true);
|
|
|
|
|
meshnode->setMaterialFlag(video::EMF_LIGHTING, true);
|
|
|
|
|
meshnode->setMaterialFlag(video::EMF_ANTI_ALIASING, true);
|
|
|
|
|
meshnode->setMaterialFlag(video::EMF_TRILINEAR_FILTER, m_setting_trilinear_filter);
|
|
|
|
|
meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, m_setting_bilinear_filter);
|
|
|
|
|
meshnode->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, m_setting_anisotropic_filter);
|
|
|
|
|
|
|
|
|
|
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
|
|
|
|
|
params.camera_position, params.camera_lookat);
|
|
|
|
|
// second parameter of setProjectionMatrix (isOrthogonal) is ignored
|
|
|
|
|
camera->setProjectionMatrix(params.camera_projection_matrix, false);
|
|
|
|
|
|
|
|
|
|
smgr->setAmbientLight(params.ambient_light);
|
|
|
|
|
smgr->addLightSceneNode(0,
|
|
|
|
|
params.light_position,
|
|
|
|
|
params.light_color,
|
|
|
|
|
params.light_radius);
|
|
|
|
|
|
|
|
|
|
// Render scene
|
|
|
|
|
driver->beginScene(true, true, video::SColor(0,0,0,0));
|
|
|
|
|
smgr->drawAll();
|
|
|
|
|
driver->endScene();
|
|
|
|
|
|
|
|
|
|
// Drop scene manager
|
|
|
|
|
smgr->drop();
|
|
|
|
|
|
|
|
|
|
// Unset render target
|
|
|
|
|
driver->setRenderTarget(0, false, true, video::SColor(0,0,0,0));
|
|
|
|
|
|
|
|
|
|
if (params.delete_texture_on_shutdown)
|
|
|
|
|
m_texture_trash.push_back(rtt);
|
|
|
|
|
|
|
|
|
|
return rtt;
|
|
|
|
|
result->unlock();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
video::IImage* TextureSource::generateImage(const std::string &name)
|
|
|
|
@ -1516,89 +1427,14 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
|
assert(img_top->getDimension().Height == npot2(img_top->getDimension().Height));
|
|
|
|
|
assert(img_top->getDimension().Width == npot2(img_top->getDimension().Width));
|
|
|
|
|
baseimg = createInventoryCubeImage(img_top, img_left, img_right);
|
|
|
|
|
|
|
|
|
|
assert(img_left->getDimension().Height == npot2(img_left->getDimension().Height));
|
|
|
|
|
assert(img_left->getDimension().Width == npot2(img_left->getDimension().Width));
|
|
|
|
|
|
|
|
|
|
assert(img_right->getDimension().Height == npot2(img_right->getDimension().Height));
|
|
|
|
|
assert(img_right->getDimension().Width == npot2(img_right->getDimension().Width));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Create textures from images
|
|
|
|
|
video::ITexture *texture_top = driver->addTexture(
|
|
|
|
|
(imagename_top + "__temp__").c_str(), img_top);
|
|
|
|
|
video::ITexture *texture_left = driver->addTexture(
|
|
|
|
|
(imagename_left + "__temp__").c_str(), img_left);
|
|
|
|
|
video::ITexture *texture_right = driver->addTexture(
|
|
|
|
|
(imagename_right + "__temp__").c_str(), img_right);
|
|
|
|
|
FATAL_ERROR_IF(!(texture_top && texture_left && texture_right), "");
|
|
|
|
|
|
|
|
|
|
// Drop images
|
|
|
|
|
// Face images are not needed anymore
|
|
|
|
|
img_top->drop();
|
|
|
|
|
img_left->drop();
|
|
|
|
|
img_right->drop();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Draw a cube mesh into a render target texture
|
|
|
|
|
*/
|
|
|
|
|
scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1));
|
|
|
|
|
setMeshColor(cube, video::SColor(255, 255, 255, 255));
|
|
|
|
|
cube->getMeshBuffer(0)->getMaterial().setTexture(0, texture_top);
|
|
|
|
|
cube->getMeshBuffer(1)->getMaterial().setTexture(0, texture_top);
|
|
|
|
|
cube->getMeshBuffer(2)->getMaterial().setTexture(0, texture_right);
|
|
|
|
|
cube->getMeshBuffer(3)->getMaterial().setTexture(0, texture_right);
|
|
|
|
|
cube->getMeshBuffer(4)->getMaterial().setTexture(0, texture_left);
|
|
|
|
|
cube->getMeshBuffer(5)->getMaterial().setTexture(0, texture_left);
|
|
|
|
|
|
|
|
|
|
TextureFromMeshParams params;
|
|
|
|
|
params.mesh = cube;
|
|
|
|
|
params.dim.set(64, 64);
|
|
|
|
|
params.rtt_texture_name = part_of_name + "_RTT";
|
|
|
|
|
// We will delete the rtt texture ourselves
|
|
|
|
|
params.delete_texture_on_shutdown = false;
|
|
|
|
|
params.camera_position.set(0, 1.0, -1.5);
|
|
|
|
|
params.camera_position.rotateXZBy(45);
|
|
|
|
|
params.camera_lookat.set(0, 0, 0);
|
|
|
|
|
// Set orthogonal projection
|
|
|
|
|
params.camera_projection_matrix.buildProjectionMatrixOrthoLH(
|
|
|
|
|
1.65, 1.65, 0, 100);
|
|
|
|
|
|
|
|
|
|
params.ambient_light.set(1.0, 0.2, 0.2, 0.2);
|
|
|
|
|
params.light_position.set(10, 100, -50);
|
|
|
|
|
params.light_color.set(1.0, 0.5, 0.5, 0.5);
|
|
|
|
|
params.light_radius = 1000;
|
|
|
|
|
|
|
|
|
|
video::ITexture *rtt = generateTextureFromMesh(params);
|
|
|
|
|
|
|
|
|
|
// Drop mesh
|
|
|
|
|
cube->drop();
|
|
|
|
|
|
|
|
|
|
// Free textures
|
|
|
|
|
driver->removeTexture(texture_top);
|
|
|
|
|
driver->removeTexture(texture_left);
|
|
|
|
|
driver->removeTexture(texture_right);
|
|
|
|
|
|
|
|
|
|
if (rtt == NULL) {
|
|
|
|
|
baseimg = generateImage(imagename_top);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create image of render target
|
|
|
|
|
video::IImage *image = driver->createImage(rtt, v2s32(0, 0), params.dim);
|
|
|
|
|
FATAL_ERROR_IF(!image, "Could not create image of render target");
|
|
|
|
|
|
|
|
|
|
// Cleanup texture
|
|
|
|
|
driver->removeTexture(rtt);
|
|
|
|
|
|
|
|
|
|
baseimg = driver->createImage(video::ECF_A8R8G8B8, params.dim);
|
|
|
|
|
|
|
|
|
|
if (image) {
|
|
|
|
|
image->copyTo(baseimg);
|
|
|
|
|
image->drop();
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
[lowpart:percent:filename
|
|
|
|
|