Load colorization data for vulkan

This commit is contained in:
Benau 2022-09-05 13:39:02 +08:00
parent 5252c78a05
commit 647988ad30
4 changed files with 149 additions and 36 deletions

View File

@ -1345,6 +1345,25 @@ void B3DMeshLoader::loadTextures(SB3dMaterial& material, scene::IMeshBuffer* mb)
else
full_path = fs->getFileBasename(B3dTexture->TextureName);
#ifndef SERVER_ONLY
std::function<void(irr::video::IImage*)> image_mani;
if (!CVS->isGLSL())
{
Material* m = material_manager->getMaterial(B3dTexture->TextureName.c_str(),
/*is_full_path*/false,
/*make_permanent*/false,
/*complain_if_not_found*/true,
/*strip_path*/true, /*install*/true,
/*create_if_not_found*/false);
if (m)
{
image_mani = m->getMaskImageMani();
if (image_mani)
STKTexManager::getInstance()->getTexture(full_path.c_str(), image_mani);
}
}
#endif
#ifndef SERVER_ONLY
bool convert_spm = CVS->isGLSL() || GE::getVKDriver() != NULL;
if (convert_spm)

View File

@ -47,6 +47,7 @@
#ifndef SERVER_ONLY
#include <ge_spm_buffer.hpp>
#include <ge_texture.hpp>
#endif
using namespace irr::video;
@ -958,3 +959,121 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m
#endif
} // setMaterialProperties
//-----------------------------------------------------------------------------
std::function<void(irr::video::IImage*)> Material::getMaskImageMani() const
{
#ifndef SERVER_ONLY
std::function<void(irr::video::IImage*)> image_mani;
core::dimension2du max_size = irr_driver->getVideoDriver()
->getDriverAttributes().getAttributeAsDimension2d("MAX_TEXTURE_SIZE");
// Material using alpha channel will be colorized as a whole
if (irr_driver->getVideoDriver()->getDriverType() == EDT_VULKAN &&
!useAlphaChannel() && (!m_colorization_mask.empty() ||
m_colorization_factor > 0.0f || m_colorizable))
{
std::string colorization_mask;
if (!m_colorization_mask.empty())
{
colorization_mask = StringUtils::getPath(m_sampler_path[0]) + "/" +
m_colorization_mask;
}
float colorization_factor = m_colorization_factor;
image_mani = [colorization_mask, colorization_factor, max_size]
(video::IImage* img)->void
{
video::IImage* mask = NULL;
core::dimension2du img_size = img->getDimension();
const unsigned total_size = img_size.Width * img_size.Height;
std::vector<uint8_t> empty_mask;
uint8_t* mask_data = NULL;
if (!colorization_mask.empty())
{
mask = GE::getResizedImage(colorization_mask, max_size);
if (!mask)
{
Log::warn("Material",
"Applying colorization mask failed for '%s'!",
colorization_mask.c_str());
return;
}
core::dimension2du mask_size = mask->getDimension();
if (mask->getColorFormat() != video::ECF_A8R8G8B8 ||
img_size != mask_size)
{
video::IImage* new_mask = irr_driver
->getVideoDriver()->createImage(video::ECF_A8R8G8B8,
img_size);
if (img_size != mask_size)
{
mask->copyToScaling(new_mask);
}
else
{
mask->copyTo(new_mask);
}
mask->drop();
mask = new_mask;
}
mask_data = (uint8_t*)mask->lock();
}
else
{
empty_mask.resize(total_size * 4, 0);
mask_data = empty_mask.data();
}
uint8_t colorization_factor_encoded = uint8_t
(irr::core::clamp(
int(colorization_factor * 0.4f * 255.0f), 0, 255));
for (unsigned int i = 0; i < total_size; i++)
{
if (!colorization_mask.empty() && mask_data[i * 4 + 3] > 127)
continue;
mask_data[i * 4 + 3] = colorization_factor_encoded;
}
uint8_t* img_data = (uint8_t*)img->lock();
for (unsigned int i = 0; i < total_size; i++)
img_data[i * 4 + 3] = mask_data[i * 4 + 3];
if (mask)
mask->drop();
};
return image_mani;
}
std::string mask_full_path;
if (!m_mask.empty())
{
mask_full_path = StringUtils::getPath(m_sampler_path[0]) + "/" +
m_mask;
}
if (!mask_full_path.empty())
{
image_mani = [mask_full_path, max_size](video::IImage* img)->void
{
video::IImage* converted_mask =
GE::getResizedImage(mask_full_path, max_size);
if (converted_mask == NULL)
{
Log::warn("Material", "Applying alpha mask failed for '%s'!",
mask_full_path.c_str());
return;
}
const core::dimension2du& dim = img->getDimension();
for (unsigned int x = 0; x < dim.Width; x++)
{
for (unsigned int y = 0; y < dim.Height; y++)
{
video::SColor col = img->getPixel(x, y);
video::SColor alpha = converted_mask->getPixel(x, y);
col.setAlpha(alpha.getRed());
img->setPixel(x, y, col, false);
} // for y
} // for x
converted_mask->drop();
};
return image_mani;
}
#endif
return nullptr;
} // getMaskImageMani

View File

@ -284,6 +284,13 @@ public:
m_shader_name == "displace";
}
// ------------------------------------------------------------------------
bool useAlphaChannel () const
{
return isTransparent() || m_shader_name == "alphatest" ||
m_shader_name == "unlit" || m_shader_name == "grass";
}
// ------------------------------------------------------------------------
/** Returns the fraction of maximum speed on this material. */
float getMaxSpeedFraction() const { return m_max_speed_fraction; }
@ -382,6 +389,8 @@ public:
return empty;
return m_container_id;
}
// ------------------------------------------------------------------------
std::function<void(irr::video::IImage*)> getMaskImageMani() const;
};

View File

@ -40,7 +40,6 @@ const uint8_t VERSION_NOW = 1;
#include <ge_main.hpp>
#include <ge_spm_buffer.hpp>
#include <ge_spm.hpp>
#include <ge_texture.hpp>
#endif
// ----------------------------------------------------------------------------
@ -170,47 +169,14 @@ scene::IAnimatedMesh* SPMeshLoader::createMesh(io::IReadFile* f)
}
std::function<void(irr::video::IImage*)> image_mani;
#ifndef SERVER_ONLY
std::string mask_full_path;
Material* m = material_manager->getMaterial(tex_name_1,
/*is_full_path*/false,
/*make_permanent*/false,
/*complain_if_not_found*/true,
/*strip_path*/true, /*install*/true,
/*create_if_not_found*/false);
if (m && !m->getAlphaMask().empty())
{
mask_full_path =
StringUtils::getPath(m->getSamplerPath(0)) +
"/" + m->getAlphaMask();
}
if (!mask_full_path.empty())
{
core::dimension2du max_size = irr_driver->getVideoDriver()
->getDriverAttributes().getAttributeAsDimension2d("MAX_TEXTURE_SIZE");
image_mani = [mask_full_path, max_size](video::IImage* img)->void
{
video::IImage* converted_mask =
GE::getResizedImage(mask_full_path, max_size);
if (converted_mask == NULL)
{
Log::warn("SPMeshLoader", "Applying mask failed for '%s'!",
mask_full_path.c_str());
return;
}
const core::dimension2du& dim = img->getDimension();
for (unsigned int x = 0; x < dim.Width; x++)
{
for (unsigned int y = 0; y < dim.Height; y++)
{
video::SColor col = img->getPixel(x, y);
video::SColor alpha = converted_mask->getPixel(x, y);
col.setAlpha(alpha.getRed());
img->setPixel(x, y, col, false);
} // for y
} // for x
converted_mask->drop();
};
}
if (m)
image_mani = m->getMaskImageMani();
#endif
video::ITexture* tex = STKTexManager::getInstance()
->getTexture(tex_name_1, image_mani);