1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-11-30 06:34:33 +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/debug/debuglog.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/sceneutil/depth.hpp> #include <components/sceneutil/depth.hpp>
#include <components/sceneutil/nodecallback.hpp> #include <components/sceneutil/nodecallback.hpp>
#include <components/sceneutil/workqueue.hpp> #include <components/sceneutil/workqueue.hpp>
#include <components/vfs/pathutil.hpp>
#include <components/esm3/globalmap.hpp> #include <components/esm3/globalmap.hpp>
#include <components/esm3/loadland.hpp> #include <components/esm3/loadland.hpp>
@ -122,7 +127,7 @@ namespace MWRender
{ {
public: public:
CreateMapWorkItem(int width, int height, int minX, int minY, int maxX, int maxY, int cellSize, 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) : mWidth(width)
, mHeight(height) , mHeight(height)
, mMinX(minX) , mMinX(minX)
@ -131,6 +136,7 @@ namespace MWRender
, mMaxY(maxY) , mMaxY(maxY)
, mCellSize(cellSize) , mCellSize(cellSize)
, mLandStore(landStore) , mLandStore(landStore)
, mColorLut(colorLut)
{ {
} }
@ -138,11 +144,9 @@ namespace MWRender
{ {
osg::ref_ptr<osg::Image> image = new osg::Image; osg::ref_ptr<osg::Image> image = new osg::Image;
image->allocateImage(mWidth, mHeight, 1, GL_RGB, GL_UNSIGNED_BYTE); image->allocateImage(mWidth, mHeight, 1, GL_RGB, GL_UNSIGNED_BYTE);
unsigned char* data = image->data();
osg::ref_ptr<osg::Image> alphaImage = new osg::Image; osg::ref_ptr<osg::Image> alphaImage = new osg::Image;
alphaImage->allocateImage(mWidth, mHeight, 1, GL_ALPHA, GL_UNSIGNED_BYTE); alphaImage->allocateImage(mWidth, mHeight, 1, GL_ALPHA, GL_UNSIGNED_BYTE);
unsigned char* alphaData = alphaImage->data();
for (int x = mMinX; x <= mMaxX; ++x) for (int x = mMinX; x <= mMaxX; ++x)
{ {
@ -154,53 +158,26 @@ namespace MWRender
{ {
for (int cellX = 0; cellX < mCellSize; ++cellX) for (int cellX = 0; cellX < mCellSize; ++cellX)
{ {
int vertexX = static_cast<int>(float(cellX) / float(mCellSize) * 9); int vertexX = (cellX * 9) / mCellSize; // 0..8
int vertexY = static_cast<int>(float(cellY) / float(mCellSize) * 9); int vertexY = (cellY * 9) / mCellSize; // 0..8
int texelX = (x - mMinX) * mCellSize + cellX; int texelX = (x - mMinX) * mCellSize + cellX;
int texelY = (y - mMinY) * mCellSize + cellY; 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; // Use getColor to handle all pixel format conversions automatically
if (land && (land->mDataTypes & ESM::Land::DATA_WNAM)) osg::Vec4 color = mColorLut->getColor(lutIndex, 0);
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);
}
data[texelY * mWidth * 3 + texelX * 3] = r; // Use setColor to write to output images
data[texelY * mWidth * 3 + texelX * 3 + 1] = g; image->setColor(color, texelX, texelY);
data[texelY * mWidth * 3 + texelX * 3 + 2] = b;
alphaData[texelY * mWidth + texelX] // Set alpha based on lutIndex threshold
= (y2 < 0) ? static_cast<unsigned char>(0) : static_cast<unsigned char>(255); 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 mMinX, mMinY, mMaxX, mMaxY;
int mCellSize; int mCellSize;
const MWWorld::Store<ESM::Land>& mLandStore; const MWWorld::Store<ESM::Land>& mLandStore;
osg::ref_ptr<osg::Image> mColorLut;
osg::ref_ptr<osg::Texture2D> mBaseTexture; osg::ref_ptr<osg::Texture2D> mBaseTexture;
osg::ref_ptr<osg::Texture2D> mAlphaTexture; osg::ref_ptr<osg::Texture2D> mAlphaTexture;
@ -309,8 +287,20 @@ namespace MWRender
mWidth = cellSize * (mMaxX - mMinX + 1); mWidth = cellSize * (mMaxX - mMinX + 1);
mHeight = cellSize * (mMaxY - mMinY + 1); mHeight = cellSize * (mMaxY - mMinY + 1);
mWorkItem // Load color LUT texture
= new CreateMapWorkItem(mWidth, mHeight, mMinX, mMinY, mMaxX, mMaxY, cellSize, esmStore.get<ESM::Land>()); 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); mWorkQueue->addWorkItem(mWorkItem);
} }

View file

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

Binary file not shown.