1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-12-12 17:13:07 +00:00
This commit is contained in:
Andrew Lanzone 2025-06-20 23:39:03 -07:00
commit 9380233ab7
14 changed files with 68 additions and 38 deletions

View file

@ -11,8 +11,7 @@ brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd
command -v ccache >/dev/null 2>&1 || brew install ccache
command -v cmake >/dev/null 2>&1 || brew install cmake
command -v qmake >/dev/null 2>&1 || brew install qt@5
export PATH="/opt/homebrew/opt/qt@5/bin:$PATH"
command -v qmake >/dev/null 2>&1 || brew install qt@6
# Install deps
brew install openal-soft icu4c yaml-cpp sqlite

View file

@ -9,7 +9,7 @@ cd build
DEPENDENCIES_ROOT="/tmp/openmw-deps"
QT_PATH=$(brew --prefix qt@5)
QT_PATH=$(brew --prefix qt@6)
ICU_PATH=$(brew --prefix icu4c)
OPENAL_PATH=$(brew --prefix openal-soft)
CCACHE_EXECUTABLE=$(brew --prefix ccache)/bin/ccache

View file

@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 49)
set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_LUA_API_REVISION 75)
set(OPENMW_LUA_API_REVISION 76)
set(OPENMW_POSTPROCESSING_API_REVISION 2)
set(OPENMW_VERSION_COMMITHASH "")

View file

@ -5,6 +5,7 @@
#include <components/esm3/loadligh.hpp>
#include <components/lua/luastate.hpp>
#include <components/lua/util.hpp>
#include <components/misc/color.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp>
@ -62,7 +63,13 @@ namespace
if (rec["radius"] != sol::nil)
light.mData.mRadius = rec["radius"];
if (rec["color"] != sol::nil)
light.mData.mColor = rec["color"];
{
sol::object color = rec["color"];
if (color.is<Misc::Color>())
light.mData.mColor = color.as<Misc::Color>().toRGBA();
else
light.mData.mColor = color.as<uint32_t>();
}
setRecordFlag(rec, "isCarriable", ESM::Light::Carry, light);
setRecordFlag(rec, "isDynamic", ESM::Light::Dynamic, light);
setRecordFlag(rec, "isFire", ESM::Light::Fire, light);
@ -104,7 +111,8 @@ namespace MWLua
record["value"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mValue; });
record["duration"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mTime; });
record["radius"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mRadius; });
record["color"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mColor; });
record["color"] = sol::readonly_property(
[](const ESM::Light& rec) -> Misc::Color { return Misc::Color::fromRGB(rec.mData.mColor); });
record["isCarriable"] = sol::readonly_property(
[](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::Carry; });
record["isDynamic"] = sol::readonly_property(

View file

@ -129,7 +129,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex& index
{
if (depFile->isGameFile() && file->gameFiles().contains(depFile->fileName(), Qt::CaseInsensitive))
{
if (!depFile->builtIn() && !depFile->fromAnotherConfigFile() && !mCheckedFiles.contains(depFile))
if (!isChecked(depFile))
break;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
@ -215,8 +215,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int
if (file == mGameFile)
return QVariant();
return (file->builtIn() || file->fromAnotherConfigFile() || mCheckedFiles.contains(file)) ? Qt::Checked
: Qt::Unchecked;
return isChecked(file) ? Qt::Checked : Qt::Unchecked;
}
case Qt::UserRole:
@ -230,7 +229,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int
}
case Qt::UserRole + 1:
return mCheckedFiles.contains(file);
return isChecked(file);
}
return QVariant();
}
@ -264,9 +263,9 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const
{
int checkValue = value.toInt();
if (checkValue == Qt::Checked)
return mCheckedFiles.contains(file) || setCheckState(file, true);
return isChecked(file) || setCheckState(file, true);
if (checkValue == Qt::Unchecked)
return !mCheckedFiles.contains(file) || setCheckState(file, false);
return !isChecked(file) || setCheckState(file, false);
}
}
@ -606,6 +605,14 @@ void ContentSelectorModel::ContentModel::sortFiles()
emit layoutChanged();
}
bool ContentSelectorModel::ContentModel::isChecked(const EsmFile* file) const
{
if (file == nullptr)
return false;
return file->builtIn() || file->fromAnotherConfigFile() || mCheckedFiles.contains(file);
}
bool ContentSelectorModel::ContentModel::isEnabled(const QModelIndex& index) const
{
return (flags(index) & Qt::ItemIsEnabled);
@ -691,7 +698,7 @@ QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::
}
else
{
if (!mCheckedFiles.contains(dependentFile))
if (!isChecked(dependentFile))
{
errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName));
}
@ -706,7 +713,7 @@ QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::
{
// Warn the user if Bloodmoon is loaded before Tribunal (Tribunal is not a hard dependency)
const EsmFile* tribunalFile = item("Tribunal.esm");
if (tribunalFile != nullptr && mCheckedFiles.contains(tribunalFile) && row < indexFromItem(tribunalFile).row())
if (isChecked(tribunalFile) && row < indexFromItem(tribunalFile).row())
errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, "Tribunal.esm"));
}
@ -770,8 +777,9 @@ bool ContentSelectorModel::ContentModel::setCheckState(const EsmFile* file, bool
for (const QString& upstreamName : file->gameFiles())
{
const EsmFile* upstreamFile = item(upstreamName);
if (upstreamFile == nullptr || !mCheckedFiles.insert(upstreamFile).second)
if (upstreamFile == nullptr || isChecked(upstreamFile))
continue;
mCheckedFiles.insert(upstreamFile);
QModelIndex upstreamIndex = indexFromItem(upstreamFile);
emit dataChanged(upstreamIndex, upstreamIndex);
}

View file

@ -58,6 +58,7 @@ namespace ContentSelectorModel
QStringList gameFiles() const;
void setCurrentGameFile(const EsmFile* file);
bool isChecked(const EsmFile* file) const;
bool isEnabled(const QModelIndex& index) const;
bool setCheckState(const EsmFile* file, bool isChecked);
bool isNew(const QString& filepath) const;

View file

@ -157,7 +157,7 @@ void ContentSelectorView::ContentSelector::setGameFile(const QString& filename)
index = ui->gameFileView->findText(file->fileName());
// verify that the current index is also checked in the model
if (!mContentModel->setCheckState(file, true))
if (!mContentModel->isChecked(file) && !mContentModel->setCheckState(file, true))
{
// throw error in case file not found?
return;

View file

@ -237,6 +237,7 @@ namespace LuaUtil
colorType["asRgba"] = [](const Misc::Color& c) { return Vec4(c.r(), c.g(), c.b(), c.a()); };
colorType["asRgb"] = [](const Misc::Color& c) { return Vec3(c.r(), c.g(), c.b()); };
colorType["asHex"] = [](const Misc::Color& c) { return c.toHex(); };
colorType[sol::meta_function::equal_to] = [](const Misc::Color& a, const Misc::Color& b) { return a == b; };
sol::table color(lua, sol::create);
color["rgba"] = [](float r, float g, float b, float a) { return Misc::Color(r, g, b, a); };

View file

@ -6,13 +6,12 @@
#include <sstream>
#include <system_error>
#include <components/sceneutil/util.hpp>
namespace Misc
{
Color::Color(float r, float g, float b, float a)
: mR(std::clamp(r, 0.f, 1.f))
, mG(std::clamp(g, 0.f, 1.f))
, mB(std::clamp(b, 0.f, 1.f))
, mA(std::clamp(a, 0.f, 1.f))
: mValue(std::clamp(r, 0.f, 1.f), std::clamp(g, 0.f, 1.f), std::clamp(b, 0.f, 1.f), std::clamp(a, 0.f, 1.f))
{
}
@ -27,26 +26,31 @@ namespace Misc
{
if (hex.size() != 6)
throw std::logic_error(std::string("Invalid hex color: ") += hex);
std::array<float, 3> rgb;
for (size_t i = 0; i < rgb.size(); i++)
Color col;
col.mValue.a() = 1;
for (size_t i = 0; i < 3; i++)
{
auto sub = hex.substr(i * 2, 2);
int v = 0;
auto [_, ec] = std::from_chars(sub.data(), sub.data() + sub.size(), v, 16);
if (ec != std::errc())
throw std::logic_error(std::string("Invalid hex color: ") += hex);
rgb[i] = v / 255.0f;
col.mValue[i] = v / 255.0f;
}
return Color(rgb[0], rgb[1], rgb[2], 1);
return col;
}
Color Color::fromRGB(unsigned int value)
{
return Color(SceneUtil::colourFromRGB(value));
}
std::string Color::toHex() const
{
std::string result(6, '0');
std::array<float, 3> rgb = { mR, mG, mB };
for (size_t i = 0; i < rgb.size(); i++)
for (size_t i = 0; i < 3; i++)
{
int b = static_cast<int>(rgb[i] * 255.0f);
int b = static_cast<int>(mValue[i] * 255.0f);
char* start = result.data() + i * 2;
if (b < 16)
start++;
@ -59,6 +63,6 @@ namespace Misc
bool operator==(const Color& l, const Color& r)
{
return l.mR == r.mR && l.mG == r.mG && l.mB == r.mB && l.mA == r.mA;
return l.mValue == r.mValue;
}
}

View file

@ -3,31 +3,38 @@
#include <string>
#include <osg/Vec4>
namespace Misc
{
class Color
{
explicit Color(osg::Vec4&& value)
: mValue(value)
{
}
public:
Color() = default;
Color(float r, float g, float b, float a);
float r() const { return mR; }
float g() const { return mG; }
float b() const { return mB; }
float a() const { return mA; }
float r() const { return mValue.r(); }
float g() const { return mValue.g(); }
float b() const { return mValue.b(); }
float a() const { return mValue.a(); }
std::string toString() const;
static Color fromHex(std::string_view hex);
static Color fromRGB(unsigned int value);
std::string toHex() const;
unsigned int toRGBA() const { return mValue.asRGBA(); }
friend bool operator==(const Color& l, const Color& r);
private:
float mR;
float mG;
float mB;
float mA;
osg::Vec4 mValue;
};
}

View file

@ -1673,7 +1673,7 @@
-- @field #number value
-- @field #number duration
-- @field #number radius
-- @field #number color
-- @field openmw.util#Color color
-- @field #boolean isCarriable True if the light can be carried by actors and appears up in their inventory.
-- @field #boolean isDynamic If true, the light will apply to actors and other moving objects
-- @field #boolean isFire True if the light acts like a fire.

View file

@ -8,3 +8,4 @@ TryExec=openmw-cs
Exec=openmw-cs
Icon=openmw-cs
Categories=Game;RolePlaying;
StartupWMClass=openmw-cs

View file

@ -8,3 +8,4 @@ TryExec=openmw-launcher
Exec=openmw-launcher
Icon=openmw
Categories=Game;RolePlaying;
StartupWMClass=openmw-launcher

View file

@ -157,7 +157,7 @@ testing.registerGlobalTest('record creation', function()
value = 10,
duration = 12,
radius = 30,
color = 5,
color = util.color.hex('123456'),
name = "TestLight",
model = "meshes/marker_door.dae"
}