1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-11-29 16:04:30 +00:00

Merge branch 'fix-8705' into 'master'

Feature #8705: Use texture-based LUT for moddable global map colors

See merge request OpenMW/openmw!4932
This commit is contained in:
Evil Eye 2025-11-23 20:54:11 +00:00
commit f8374f2ff0
3 changed files with 36 additions and 45 deletions

View file

@ -13,10 +13,15 @@
#include <components/debug/debuglog.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/sceneutil/depth.hpp>
#include <components/sceneutil/nodecallback.hpp>
#include <components/sceneutil/workqueue.hpp>
#include <components/vfs/pathutil.hpp>
#include <components/esm3/globalmap.hpp>
#include <components/esm3/loadland.hpp>
@ -122,7 +127,7 @@ namespace MWRender
{
public:
CreateMapWorkItem(int width, int height, int minX, int minY, int maxX, int maxY, int cellSize,
const MWWorld::Store<ESM::Land>& landStore)
const MWWorld::Store<ESM::Land>& landStore, osg::ref_ptr<osg::Image> colorLut)
: mWidth(width)
, mHeight(height)
, mMinX(minX)
@ -131,6 +136,7 @@ namespace MWRender
, mMaxY(maxY)
, mCellSize(cellSize)
, mLandStore(landStore)
, mColorLut(colorLut)
{
}
@ -138,11 +144,9 @@ namespace MWRender
{
osg::ref_ptr<osg::Image> image = new osg::Image;
image->allocateImage(mWidth, mHeight, 1, GL_RGB, GL_UNSIGNED_BYTE);
unsigned char* data = image->data();
osg::ref_ptr<osg::Image> alphaImage = new osg::Image;
alphaImage->allocateImage(mWidth, mHeight, 1, GL_ALPHA, GL_UNSIGNED_BYTE);
unsigned char* alphaData = alphaImage->data();
for (int x = mMinX; x <= mMaxX; ++x)
{
@ -154,53 +158,26 @@ namespace MWRender
{
for (int cellX = 0; cellX < mCellSize; ++cellX)
{
int vertexX = static_cast<int>(float(cellX) / float(mCellSize) * 9);
int vertexY = static_cast<int>(float(cellY) / float(mCellSize) * 9);
int vertexX = (cellX * 9) / mCellSize; // 0..8
int vertexY = (cellY * 9) / mCellSize; // 0..8
int texelX = (x - mMinX) * mCellSize + cellX;
int texelY = (y - mMinY) * mCellSize + cellY;
unsigned char r, g, b;
int lutIndex = 0;
// Converting [-128; 127] WNAM range to [0; 255] index
if (land != nullptr && (land->mDataTypes & ESM::Land::DATA_WNAM))
lutIndex = static_cast<int>(land->mWnam[vertexY * 9 + vertexX]) + 128;
float y2 = 0;
if (land && (land->mDataTypes & ESM::Land::DATA_WNAM))
y2 = land->mWnam[vertexY * 9 + vertexX] / 128.f;
else
y2 = SCHAR_MIN / 128.f;
if (y2 < 0)
{
r = static_cast<unsigned char>(14 * y2 + 38);
g = static_cast<unsigned char>(20 * y2 + 56);
b = static_cast<unsigned char>(18 * y2 + 51);
}
else if (y2 < 0.3f)
{
if (y2 < 0.1f)
y2 *= 8.f;
else
{
y2 -= 0.1f;
y2 += 0.8f;
}
r = static_cast<unsigned char>(66 - 32 * y2);
g = static_cast<unsigned char>(48 - 23 * y2);
b = static_cast<unsigned char>(33 - 16 * y2);
}
else
{
y2 -= 0.3f;
y2 *= 1.428f;
r = static_cast<unsigned char>(34 - 29 * y2);
g = static_cast<unsigned char>(25 - 20 * y2);
b = static_cast<unsigned char>(17 - 12 * y2);
}
// Use getColor to handle all pixel format conversions automatically
osg::Vec4 color = mColorLut->getColor(lutIndex, 0);
data[texelY * mWidth * 3 + texelX * 3] = r;
data[texelY * mWidth * 3 + texelX * 3 + 1] = g;
data[texelY * mWidth * 3 + texelX * 3 + 2] = b;
// Use setColor to write to output images
image->setColor(color, texelX, texelY);
alphaData[texelY * mWidth + texelX]
= (y2 < 0) ? static_cast<unsigned char>(0) : static_cast<unsigned char>(255);
// Set alpha based on lutIndex threshold
osg::Vec4 alpha(0.0f, 0.0f, 0.0f, lutIndex < 128 ? 0.0f : 1.0f);
alphaImage->setColor(alpha, texelX, texelY);
}
}
}
@ -242,6 +219,7 @@ namespace MWRender
int mMinX, mMinY, mMaxX, mMaxY;
int mCellSize;
const MWWorld::Store<ESM::Land>& mLandStore;
osg::ref_ptr<osg::Image> mColorLut;
osg::ref_ptr<osg::Texture2D> mBaseTexture;
osg::ref_ptr<osg::Texture2D> mAlphaTexture;
@ -309,8 +287,20 @@ namespace MWRender
mWidth = cellSize * (mMaxX - mMinX + 1);
mHeight = cellSize * (mMaxY - mMinY + 1);
mWorkItem
= new CreateMapWorkItem(mWidth, mHeight, mMinX, mMinY, mMaxX, mMaxY, cellSize, esmStore.get<ESM::Land>());
// Load color LUT texture
constexpr VFS::Path::NormalizedView colorLutPath("textures/omw_map_color_palette.dds");
auto resourceSystem = MWBase::Environment::get().getResourceSystem();
osg::ref_ptr<osg::Image> colorLut = resourceSystem->getImageManager()->getImage(colorLutPath);
// Validate LUT dimensions
if (!colorLut || colorLut->s() != 256 || colorLut->t() != 1)
{
throw std::runtime_error("Global map color LUT must be 256x1 pixels, got "
+ std::to_string(colorLut ? colorLut->s() : 0) + "x" + std::to_string(colorLut ? colorLut->t() : 0));
}
mWorkItem = new CreateMapWorkItem(
mWidth, mHeight, mMinX, mMinY, mMaxX, mMaxY, cellSize, esmStore.get<ESM::Land>(), colorLut);
mWorkQueue->addWorkItem(mWorkItem);
}

View file

@ -3,6 +3,7 @@ if (NOT DEFINED OPENMW_RESOURCES_ROOT)
endif()
set(BUILTIN_DATA_FILES
textures/omw_map_color_palette.dds
textures/omw_menu_scroll_down.dds
textures/omw_menu_scroll_up.dds
textures/omw_menu_scroll_left.dds

Binary file not shown.