1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-21 00:39:58 +00:00

Merge branch 'master' into 'openmw-confpyupdate'

There were conflicts as I'd based this off the original attempt to ensure the original contributor got credit.

# Conflicts:
#   docs/source/conf.py
This commit is contained in:
AnyOldName3 2023-01-08 21:19:59 +00:00
commit 1e921162ee
109 changed files with 1617 additions and 746 deletions

View File

@ -28,7 +28,9 @@
Bug #7034: Misc items defined in one content file are not treated as keys if another content file uses them as such
Bug #7042: Weapon follow animations that immediately follow the hit animations cause multiple hits
Bug #7044: Changing a class' services does not affect autocalculated NPCs
Bug #7054: Quests aren't sorted by name
Bug #7084: Resurrecting an actor doesn't take into account base record changes
Bug #7088: Deleting last save game of last character doesn't clear character name/details
Feature #6447: Add LOD support to Object Paging
Feature #6933: Support high-resolution cursor textures
Feature #6945: Support S3TC-compressed and BGR/BGRA NiPixelData
@ -37,6 +39,7 @@
Feature #6995: Localize the "show effect duration" option
Feature #7058: Implement TestModels (T3D) console command
Feature #7087: Block resolution change in the Windowed Fullscreen mode
Feature #7130: Ability to set MyGUI logging verbosity
0.48.0
------
@ -217,6 +220,7 @@
Feature #5198: Implement "Magic effect expired" event
Feature #5454: Clear active spells from actor when he disappears from scene
Feature #5489: MCP: Telekinesis fix for activators
Feature #5492: Let rain and snow collide with statics
Feature #5701: Convert osgAnimation::RigGeometry to double-buffered custom version
Feature #5737: OpenMW-CS: Handle instance move from one cell to another
Feature #5928: Allow Glow in the Dahrk to be disabled

View File

@ -8,6 +8,7 @@
#include <components/esm/esmcommon.hpp>
#include <components/esm4/reader.hpp>
#include <components/esm4/readerutils.hpp>
#include <components/esm4/records.hpp>
#include <components/to_utf8/to_utf8.hpp>
@ -69,6 +70,19 @@ namespace EsmTool
template <class T>
constexpr bool hasFormId = HasFormId<T>::value;
template <class T, class = std::void_t<>>
struct HasRefId : std::false_type
{
};
template <class T>
struct HasRefId<T, std::void_t<decltype(T::mId)>> : std::true_type
{
};
template <class T>
constexpr bool hasRefId = HasRefId<T>::value;
template <class T, class = std::void_t<>>
struct HasFlags : std::false_type
{
@ -169,6 +183,8 @@ namespace EsmTool
std::cout << "\n Record: " << ESM::NAME(reader.hdr().record.typeId).toStringView();
if constexpr (hasFormId<T>)
std::cout << "\n FormId: " << value.mFormId;
if constexpr (hasRefId<T>)
std::cout << "\n FormId: " << value.mId;
if constexpr (hasFlags<T>)
std::cout << "\n Record flags: " << recordFlags(value.mFlags);
if constexpr (hasEditorId<T>)
@ -182,60 +198,77 @@ namespace EsmTool
std::cout << '\n';
}
void readRecord(const Params& params, ESM4::Reader& reader)
bool readRecord(const Params& params, ESM4::Reader& reader)
{
switch (static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId))
{
case ESM4::REC_AACT:
break;
case ESM4::REC_ACHR:
return readTypedRecord<ESM4::ActorCharacter>(params, reader);
readTypedRecord<ESM4::ActorCharacter>(params, reader);
return true;
case ESM4::REC_ACRE:
return readTypedRecord<ESM4::ActorCreature>(params, reader);
readTypedRecord<ESM4::ActorCreature>(params, reader);
return true;
case ESM4::REC_ACTI:
return readTypedRecord<ESM4::Activator>(params, reader);
readTypedRecord<ESM4::Activator>(params, reader);
return true;
case ESM4::REC_ADDN:
break;
case ESM4::REC_ALCH:
return readTypedRecord<ESM4::Potion>(params, reader);
readTypedRecord<ESM4::Potion>(params, reader);
return true;
case ESM4::REC_ALOC:
return readTypedRecord<ESM4::MediaLocationController>(params, reader);
readTypedRecord<ESM4::MediaLocationController>(params, reader);
return true;
case ESM4::REC_AMMO:
return readTypedRecord<ESM4::Ammunition>(params, reader);
readTypedRecord<ESM4::Ammunition>(params, reader);
return true;
case ESM4::REC_ANIO:
return readTypedRecord<ESM4::AnimObject>(params, reader);
readTypedRecord<ESM4::AnimObject>(params, reader);
return true;
case ESM4::REC_APPA:
return readTypedRecord<ESM4::Apparatus>(params, reader);
readTypedRecord<ESM4::Apparatus>(params, reader);
return true;
case ESM4::REC_ARMA:
return readTypedRecord<ESM4::ArmorAddon>(params, reader);
readTypedRecord<ESM4::ArmorAddon>(params, reader);
return true;
case ESM4::REC_ARMO:
return readTypedRecord<ESM4::Armor>(params, reader);
readTypedRecord<ESM4::Armor>(params, reader);
return true;
case ESM4::REC_ARTO:
break;
case ESM4::REC_ASPC:
return readTypedRecord<ESM4::AcousticSpace>(params, reader);
readTypedRecord<ESM4::AcousticSpace>(params, reader);
return true;
case ESM4::REC_ASTP:
break;
case ESM4::REC_AVIF:
break;
case ESM4::REC_BOOK:
return readTypedRecord<ESM4::Book>(params, reader);
readTypedRecord<ESM4::Book>(params, reader);
return true;
case ESM4::REC_BPTD:
return readTypedRecord<ESM4::BodyPartData>(params, reader);
readTypedRecord<ESM4::BodyPartData>(params, reader);
return true;
case ESM4::REC_CAMS:
break;
case ESM4::REC_CCRD:
break;
case ESM4::REC_CELL:
return readTypedRecord<ESM4::Cell>(params, reader);
readTypedRecord<ESM4::Cell>(params, reader);
return true;
case ESM4::REC_CLAS:
return readTypedRecord<ESM4::Class>(params, reader);
readTypedRecord<ESM4::Class>(params, reader);
return true;
case ESM4::REC_CLFM:
return readTypedRecord<ESM4::Colour>(params, reader);
readTypedRecord<ESM4::Colour>(params, reader);
return true;
case ESM4::REC_CLMT:
break;
case ESM4::REC_CLOT:
return readTypedRecord<ESM4::Clothing>(params, reader);
readTypedRecord<ESM4::Clothing>(params, reader);
return true;
case ESM4::REC_CMNY:
break;
case ESM4::REC_COBJ:
@ -243,25 +276,30 @@ namespace EsmTool
case ESM4::REC_COLL:
break;
case ESM4::REC_CONT:
return readTypedRecord<ESM4::Container>(params, reader);
readTypedRecord<ESM4::Container>(params, reader);
return true;
case ESM4::REC_CPTH:
break;
case ESM4::REC_CREA:
return readTypedRecord<ESM4::Creature>(params, reader);
readTypedRecord<ESM4::Creature>(params, reader);
return true;
case ESM4::REC_CSTY:
break;
case ESM4::REC_DEBR:
break;
case ESM4::REC_DIAL:
return readTypedRecord<ESM4::Dialogue>(params, reader);
readTypedRecord<ESM4::Dialogue>(params, reader);
return true;
case ESM4::REC_DLBR:
break;
case ESM4::REC_DLVW:
break;
case ESM4::REC_DOBJ:
return readTypedRecord<ESM4::DefaultObj>(params, reader);
readTypedRecord<ESM4::DefaultObj>(params, reader);
return true;
case ESM4::REC_DOOR:
return readTypedRecord<ESM4::Door>(params, reader);
readTypedRecord<ESM4::Door>(params, reader);
return true;
case ESM4::REC_DUAL:
break;
case ESM4::REC_ECZN:
@ -275,81 +313,103 @@ namespace EsmTool
case ESM4::REC_EXPL:
break;
case ESM4::REC_EYES:
return readTypedRecord<ESM4::Eyes>(params, reader);
readTypedRecord<ESM4::Eyes>(params, reader);
return true;
case ESM4::REC_FACT:
break;
case ESM4::REC_FLOR:
return readTypedRecord<ESM4::Flora>(params, reader);
readTypedRecord<ESM4::Flora>(params, reader);
return true;
case ESM4::REC_FLST:
return readTypedRecord<ESM4::FormIdList>(params, reader);
readTypedRecord<ESM4::FormIdList>(params, reader);
return true;
case ESM4::REC_FSTP:
break;
case ESM4::REC_FSTS:
break;
case ESM4::REC_FURN:
return readTypedRecord<ESM4::Furniture>(params, reader);
readTypedRecord<ESM4::Furniture>(params, reader);
return true;
case ESM4::REC_GLOB:
return readTypedRecord<ESM4::GlobalVariable>(params, reader);
readTypedRecord<ESM4::GlobalVariable>(params, reader);
return true;
case ESM4::REC_GMST:
break;
case ESM4::REC_GRAS:
return readTypedRecord<ESM4::Grass>(params, reader);
readTypedRecord<ESM4::Grass>(params, reader);
return true;
case ESM4::REC_GRUP:
break;
case ESM4::REC_HAIR:
return readTypedRecord<ESM4::Hair>(params, reader);
readTypedRecord<ESM4::Hair>(params, reader);
return true;
case ESM4::REC_HAZD:
break;
case ESM4::REC_HDPT:
return readTypedRecord<ESM4::HeadPart>(params, reader);
readTypedRecord<ESM4::HeadPart>(params, reader);
return true;
case ESM4::REC_IDLE:
// FIXME: ESM4::IdleAnimation::load does not work with Oblivion.esm
// return readTypedRecord<ESM4::IdleAnimation>(params, reader);
// readTypedRecord<ESM4::IdleAnimation>(params, reader);
return true;
break;
case ESM4::REC_IDLM:
return readTypedRecord<ESM4::IdleMarker>(params, reader);
readTypedRecord<ESM4::IdleMarker>(params, reader);
return true;
case ESM4::REC_IMAD:
break;
case ESM4::REC_IMGS:
break;
case ESM4::REC_IMOD:
return readTypedRecord<ESM4::ItemMod>(params, reader);
readTypedRecord<ESM4::ItemMod>(params, reader);
return true;
case ESM4::REC_INFO:
return readTypedRecord<ESM4::DialogInfo>(params, reader);
readTypedRecord<ESM4::DialogInfo>(params, reader);
return true;
case ESM4::REC_INGR:
return readTypedRecord<ESM4::Ingredient>(params, reader);
readTypedRecord<ESM4::Ingredient>(params, reader);
return true;
case ESM4::REC_IPCT:
break;
case ESM4::REC_IPDS:
break;
case ESM4::REC_KEYM:
return readTypedRecord<ESM4::Key>(params, reader);
readTypedRecord<ESM4::Key>(params, reader);
return true;
case ESM4::REC_KYWD:
break;
case ESM4::REC_LAND:
return readTypedRecord<ESM4::Land>(params, reader);
readTypedRecord<ESM4::Land>(params, reader);
return true;
case ESM4::REC_LCRT:
break;
case ESM4::REC_LCTN:
break;
case ESM4::REC_LGTM:
return readTypedRecord<ESM4::LightingTemplate>(params, reader);
readTypedRecord<ESM4::LightingTemplate>(params, reader);
return true;
case ESM4::REC_LIGH:
return readTypedRecord<ESM4::Light>(params, reader);
readTypedRecord<ESM4::Light>(params, reader);
return true;
case ESM4::REC_LSCR:
break;
case ESM4::REC_LTEX:
return readTypedRecord<ESM4::LandTexture>(params, reader);
readTypedRecord<ESM4::LandTexture>(params, reader);
return true;
case ESM4::REC_LVLC:
return readTypedRecord<ESM4::LevelledCreature>(params, reader);
readTypedRecord<ESM4::LevelledCreature>(params, reader);
return true;
case ESM4::REC_LVLI:
return readTypedRecord<ESM4::LevelledItem>(params, reader);
readTypedRecord<ESM4::LevelledItem>(params, reader);
return true;
case ESM4::REC_LVLN:
return readTypedRecord<ESM4::LevelledNpc>(params, reader);
readTypedRecord<ESM4::LevelledNpc>(params, reader);
return true;
case ESM4::REC_LVSP:
break;
case ESM4::REC_MATO:
return readTypedRecord<ESM4::Material>(params, reader);
readTypedRecord<ESM4::Material>(params, reader);
return true;
case ESM4::REC_MATT:
break;
case ESM4::REC_MESG:
@ -357,49 +417,66 @@ namespace EsmTool
case ESM4::REC_MGEF:
break;
case ESM4::REC_MISC:
return readTypedRecord<ESM4::MiscItem>(params, reader);
readTypedRecord<ESM4::MiscItem>(params, reader);
return true;
case ESM4::REC_MOVT:
break;
case ESM4::REC_MSET:
return readTypedRecord<ESM4::MediaSet>(params, reader);
readTypedRecord<ESM4::MediaSet>(params, reader);
return true;
case ESM4::REC_MSTT:
return readTypedRecord<ESM4::MovableStatic>(params, reader);
readTypedRecord<ESM4::MovableStatic>(params, reader);
return true;
case ESM4::REC_MUSC:
return readTypedRecord<ESM4::Music>(params, reader);
readTypedRecord<ESM4::Music>(params, reader);
return true;
case ESM4::REC_MUST:
break;
case ESM4::REC_NAVI:
return readTypedRecord<ESM4::Navigation>(params, reader);
readTypedRecord<ESM4::Navigation>(params, reader);
return true;
case ESM4::REC_NAVM:
return readTypedRecord<ESM4::NavMesh>(params, reader);
readTypedRecord<ESM4::NavMesh>(params, reader);
return true;
case ESM4::REC_NOTE:
return readTypedRecord<ESM4::Note>(params, reader);
readTypedRecord<ESM4::Note>(params, reader);
return true;
case ESM4::REC_NPC_:
return readTypedRecord<ESM4::Npc>(params, reader);
readTypedRecord<ESM4::Npc>(params, reader);
return true;
case ESM4::REC_OTFT:
return readTypedRecord<ESM4::Outfit>(params, reader);
readTypedRecord<ESM4::Outfit>(params, reader);
return true;
case ESM4::REC_PACK:
return readTypedRecord<ESM4::AIPackage>(params, reader);
readTypedRecord<ESM4::AIPackage>(params, reader);
return true;
case ESM4::REC_PERK:
break;
case ESM4::REC_PGRD:
return readTypedRecord<ESM4::Pathgrid>(params, reader);
readTypedRecord<ESM4::Pathgrid>(params, reader);
return true;
case ESM4::REC_PGRE:
return readTypedRecord<ESM4::PlacedGrenade>(params, reader);
readTypedRecord<ESM4::PlacedGrenade>(params, reader);
return true;
case ESM4::REC_PHZD:
break;
case ESM4::REC_PROJ:
break;
case ESM4::REC_PWAT:
return readTypedRecord<ESM4::PlaceableWater>(params, reader);
readTypedRecord<ESM4::PlaceableWater>(params, reader);
return true;
case ESM4::REC_QUST:
return readTypedRecord<ESM4::Quest>(params, reader);
readTypedRecord<ESM4::Quest>(params, reader);
return true;
case ESM4::REC_RACE:
return readTypedRecord<ESM4::Race>(params, reader);
readTypedRecord<ESM4::Race>(params, reader);
return true;
case ESM4::REC_REFR:
return readTypedRecord<ESM4::Reference>(params, reader);
readTypedRecord<ESM4::Reference>(params, reader);
return true;
case ESM4::REC_REGN:
return readTypedRecord<ESM4::Region>(params, reader);
readTypedRecord<ESM4::Region>(params, reader);
return true;
case ESM4::REC_RELA:
break;
case ESM4::REC_REVB:
@ -407,23 +484,30 @@ namespace EsmTool
case ESM4::REC_RFCT:
break;
case ESM4::REC_ROAD:
return readTypedRecord<ESM4::Road>(params, reader);
readTypedRecord<ESM4::Road>(params, reader);
return true;
case ESM4::REC_SBSP:
return readTypedRecord<ESM4::SubSpace>(params, reader);
readTypedRecord<ESM4::SubSpace>(params, reader);
return true;
case ESM4::REC_SCEN:
break;
case ESM4::REC_SCOL:
return readTypedRecord<ESM4::StaticCollection>(params, reader);
readTypedRecord<ESM4::StaticCollection>(params, reader);
return true;
case ESM4::REC_SCPT:
return readTypedRecord<ESM4::Script>(params, reader);
readTypedRecord<ESM4::Script>(params, reader);
return true;
case ESM4::REC_SCRL:
return readTypedRecord<ESM4::Scroll>(params, reader);
readTypedRecord<ESM4::Scroll>(params, reader);
return true;
case ESM4::REC_SGST:
return readTypedRecord<ESM4::SigilStone>(params, reader);
readTypedRecord<ESM4::SigilStone>(params, reader);
return true;
case ESM4::REC_SHOU:
break;
case ESM4::REC_SLGM:
return readTypedRecord<ESM4::SoulGem>(params, reader);
readTypedRecord<ESM4::SoulGem>(params, reader);
return true;
case ESM4::REC_SMBN:
break;
case ESM4::REC_SMEN:
@ -433,97 +517,56 @@ namespace EsmTool
case ESM4::REC_SNCT:
break;
case ESM4::REC_SNDR:
return readTypedRecord<ESM4::SoundReference>(params, reader);
readTypedRecord<ESM4::SoundReference>(params, reader);
return true;
case ESM4::REC_SOPM:
break;
case ESM4::REC_SOUN:
return readTypedRecord<ESM4::Sound>(params, reader);
readTypedRecord<ESM4::Sound>(params, reader);
return true;
case ESM4::REC_SPEL:
break;
case ESM4::REC_SPGD:
break;
case ESM4::REC_STAT:
return readTypedRecord<ESM4::Static>(params, reader);
readTypedRecord<ESM4::Static>(params, reader);
return true;
case ESM4::REC_TACT:
return readTypedRecord<ESM4::TalkingActivator>(params, reader);
readTypedRecord<ESM4::TalkingActivator>(params, reader);
return true;
case ESM4::REC_TERM:
return readTypedRecord<ESM4::Terminal>(params, reader);
readTypedRecord<ESM4::Terminal>(params, reader);
return true;
case ESM4::REC_TES4:
return readTypedRecord<ESM4::Header>(params, reader);
readTypedRecord<ESM4::Header>(params, reader);
return true;
case ESM4::REC_TREE:
return readTypedRecord<ESM4::Tree>(params, reader);
readTypedRecord<ESM4::Tree>(params, reader);
return true;
case ESM4::REC_TXST:
return readTypedRecord<ESM4::TextureSet>(params, reader);
readTypedRecord<ESM4::TextureSet>(params, reader);
return true;
case ESM4::REC_VTYP:
break;
case ESM4::REC_WATR:
break;
case ESM4::REC_WEAP:
return readTypedRecord<ESM4::Weapon>(params, reader);
readTypedRecord<ESM4::Weapon>(params, reader);
return true;
case ESM4::REC_WOOP:
break;
case ESM4::REC_WRLD:
return readTypedRecord<ESM4::World>(params, reader);
readTypedRecord<ESM4::World>(params, reader);
return true;
case ESM4::REC_WTHR:
break;
}
if (!params.mQuite)
std::cout << "\n Unsupported record: " << ESM::NAME(reader.hdr().record.typeId).toStringView() << '\n';
reader.skipRecordData();
return false;
}
bool readItem(const Params& params, ESM4::Reader& reader);
bool readGroup(const Params& params, ESM4::Reader& reader)
{
const ESM4::RecordHeader& header = reader.hdr();
if (!params.mQuite)
std::cout << "\nGroup: " << toString(static_cast<ESM4::GroupType>(header.group.type)) << " "
<< ESM::NAME(header.group.typeId).toStringView() << '\n';
switch (static_cast<ESM4::GroupType>(header.group.type))
{
case ESM4::Grp_RecordType:
case ESM4::Grp_InteriorCell:
case ESM4::Grp_InteriorSubCell:
case ESM4::Grp_ExteriorCell:
case ESM4::Grp_ExteriorSubCell:
reader.enterGroup();
return readItem(params, reader);
case ESM4::Grp_WorldChild:
case ESM4::Grp_CellChild:
case ESM4::Grp_TopicChild:
case ESM4::Grp_CellPersistentChild:
case ESM4::Grp_CellTemporaryChild:
case ESM4::Grp_CellVisibleDistChild:
reader.adjustGRUPFormId();
reader.enterGroup();
if (!reader.hasMoreRecs())
return false;
return readItem(params, reader);
}
reader.skipGroup();
return true;
}
bool readItem(const Params& params, ESM4::Reader& reader)
{
if (!reader.getRecordHeader() || !reader.hasMoreRecs())
return false;
const ESM4::RecordHeader& header = reader.hdr();
if (header.record.typeId == ESM4::REC_GRUP)
return readGroup(params, reader);
readRecord(params, reader);
return true;
}
}
int loadTes4(const Arguments& info, std::unique_ptr<std::ifstream>&& stream)
@ -551,12 +594,15 @@ namespace EsmTool
}
}
while (reader.hasMoreRecs())
{
reader.exitGroupCheck();
if (!readItem(params, reader))
break;
}
auto visitorRec = [&params](ESM4::Reader& reader) { return readRecord(params, reader); };
auto visitorGroup = [&params](ESM4::Reader& reader) {
if (params.mQuite)
return;
auto groupType = static_cast<ESM4::GroupType>(reader.hdr().group.type);
std::cout << "\nGroup: " << toString(groupType) << " "
<< ESM::NAME(reader.hdr().group.typeId).toStringView() << '\n';
};
ESM4::ReaderUtils::readAll(reader, visitorRec, visitorGroup);
}
catch (const std::exception& e)
{

View File

@ -126,6 +126,7 @@ bool Launcher::AdvancedPage::loadSettings()
antialiasAlphaTestCheckBox->setCheckState(Qt::Unchecked);
}
loadSettingBool(adjustCoverageForAlphaTestCheckBox, "adjust coverage for alpha test", "Shaders");
loadSettingBool(weatherParticleOcclusionCheckBox, "weather particle occlusion", "Shaders");
loadSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game");
connect(animSourcesCheckBox, &QCheckBox::toggled, this, &AdvancedPage::slotAnimSourcesToggled);
loadSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
@ -285,6 +286,7 @@ void Launcher::AdvancedPage::saveSettings()
saveSettingBool(softParticlesCheckBox, "soft particles", "Shaders");
saveSettingBool(antialiasAlphaTestCheckBox, "antialias alpha test", "Shaders");
saveSettingBool(adjustCoverageForAlphaTestCheckBox, "adjust coverage for alpha test", "Shaders");
saveSettingBool(weatherParticleOcclusionCheckBox, "weather particle occlusion", "Shaders");
saveSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game");
saveSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");

View File

@ -490,13 +490,7 @@ namespace CSMWorld
int Collection<ESXRecordT, IdAccessorT>::searchId(const ESM::RefId& id) const
{
std::map<std::string, int>::const_iterator iter
= mIndex.find(Misc::StringUtils::lowerCase(id.getRefIdString()));
if (iter == mIndex.end())
return -1;
return iter->second;
return searchId(id.getRefIdString());
}
template <typename ESXRecordT, typename IdAccessorT>

View File

@ -1242,10 +1242,10 @@ bool CSMWorld::Data::continueLoading(CSMDoc::Messages& messages)
case ESM::REC_DIAL:
{
ESM::Dialogue record;
const std::string& recordIdString = record.mId.getRefIdString();
bool isDeleted = false;
record.load(*mReader, isDeleted);
const std::string& recordIdString = record.mId.getRefIdString();
if (isDeleted)
{

View File

@ -23,7 +23,7 @@ add_openmw_dir (mwrender
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover
postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass navmeshmode
postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass navmeshmode precipitationocclusion
)
add_openmw_dir (mwinput

View File

@ -127,10 +127,10 @@ namespace MWClass
if (!customData.mSpawn)
return;
MWWorld::LiveCellRef<ESM::CreatureLevList>* ref = ptr.get<ESM::CreatureLevList>();
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
const ESM::RefId& id = MWMechanics::getLevelledItem(ref->mBase, true, prng);
const ESM::RefId& id = MWMechanics::getLevelledItem(
store.get<ESM::CreatureLevList>().find(ptr.getCellRef().getRefId()), true, prng);
if (!id.empty())
{
@ -144,7 +144,6 @@ namespace MWClass
customData.mSpawnActorId = -1;
}
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
MWWorld::ManualRef manualRef(store, id);
manualRef.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition());
manualRef.getPtr().getCellRef().setScale(ptr.getCellRef().getScale());

View File

@ -104,20 +104,20 @@ namespace MWGui
// - Shader editor
MyGUI::TabItem* itemLV = mTabControl->addItem("Log Viewer");
itemLV->setCaptionWithReplacing(" #{DebugMenu:LogViewer} ");
itemLV->setCaptionWithReplacing(" #{OMWEngine:LogViewer} ");
mLogView
= itemLV->createWidgetReal<MyGUI::EditBox>("LogEdit", MyGUI::FloatCoord(0, 0, 1, 1), MyGUI::Align::Stretch);
mLogView->setEditReadOnly(true);
MyGUI::TabItem* itemLuaProfiler = mTabControl->addItem("Lua Profiler");
itemLuaProfiler->setCaptionWithReplacing(" #{DebugMenu:LuaProfiler} ");
itemLuaProfiler->setCaptionWithReplacing(" #{OMWEngine:LuaProfiler} ");
mLuaProfiler = itemLuaProfiler->createWidgetReal<MyGUI::EditBox>(
"LogEdit", MyGUI::FloatCoord(0, 0, 1, 1), MyGUI::Align::Stretch);
mLuaProfiler->setEditReadOnly(true);
#ifndef BT_NO_PROFILE
MyGUI::TabItem* item = mTabControl->addItem("Physics Profiler");
item->setCaptionWithReplacing(" #{DebugMenu:PhysicsProfiler} ");
item->setCaptionWithReplacing(" #{OMWEngine:PhysicsProfiler} ");
mBulletProfilerEdit
= item->createWidgetReal<MyGUI::EditBox>("LogEdit", MyGUI::FloatCoord(0, 0, 1, 1), MyGUI::Align::Stretch);
#else

View File

@ -558,6 +558,7 @@ namespace
mModel->visitQuestNames(!mAllQuests, add);
list->sort();
list->adjustSize();
if (mAllQuests)

View File

@ -329,26 +329,22 @@ namespace MWGui
case fx::Technique::Status::Uncompiled:
{
if (technique->getDynamic())
ss << "#{fontcolourhtml=header}#{PostProcessing:ShaderLocked}: #{fontcolourhtml=normal} "
"#{PostProcessing:ShaderLockedDescription}"
ss << "#{fontcolourhtml=header}#{OMWShaders:ShaderLocked}: #{fontcolourhtml=normal} "
"#{OMWShaders:ShaderLockedDescription}"
<< endl
<< endl;
ss << "#{fontcolourhtml=header}#{PostProcessing:Author}: #{fontcolourhtml=normal} " << author
ss << "#{fontcolourhtml=header}#{OMWShaders:Author}: #{fontcolourhtml=normal} " << author << endl
<< endl
<< "#{fontcolourhtml=header}#{OMWShaders:Version}: #{fontcolourhtml=normal} " << version << endl
<< endl
<< "#{fontcolourhtml=header}#{OMWShaders:Description}: #{fontcolourhtml=normal} " << description
<< endl
<< endl
<< "#{fontcolourhtml=header}#{PostProcessing:Version}: #{fontcolourhtml=normal} " << version
<< endl
<< endl
<< "#{fontcolourhtml=header}#{PostProcessing:Description}: #{fontcolourhtml=normal} " << description
<< endl
<< endl
<< "#{fontcolourhtml=header}#{PostProcessing:InInteriors}: #{fontcolourhtml=normal} "
<< flag_interior
<< "#{fontcolourhtml=header} #{PostProcessing:InExteriors}: #{fontcolourhtml=normal} "
<< flag_exterior
<< "#{fontcolourhtml=header} #{PostProcessing:Underwater}: #{fontcolourhtml=normal} "
<< "#{fontcolourhtml=header}#{OMWShaders:InInteriors}: #{fontcolourhtml=normal} " << flag_interior
<< "#{fontcolourhtml=header} #{OMWShaders:InExteriors}: #{fontcolourhtml=normal} " << flag_exterior
<< "#{fontcolourhtml=header} #{OMWShaders:Underwater}: #{fontcolourhtml=normal} "
<< flag_underwater
<< "#{fontcolourhtml=header} #{PostProcessing:Abovewater}: #{fontcolourhtml=normal} "
<< "#{fontcolourhtml=header} #{OMWShaders:Abovewater}: #{fontcolourhtml=normal} "
<< flag_abovewater;
break;
}
@ -370,7 +366,7 @@ namespace MWGui
{
MyGUI::Button* resetButton
= mConfigArea->createWidget<MyGUI::Button>("MW_Button", { 0, 0, 0, 24 }, MyGUI::Align::Default);
resetButton->setCaptionWithReplacing("#{PostProcessing:ResetShader}");
resetButton->setCaptionWithReplacing("#{OMWShaders:ResetShader}");
resetButton->setTextAlign(MyGUI::Align::Center);
resetButton->eventMouseWheel += MyGUI::newDelegate(this, &PostProcessorHud::notifyMouseWheel);
resetButton->eventMouseButtonClick

View File

@ -111,7 +111,7 @@ namespace MWGui
onCharacterSelected(mCharacterSelection, nextCharacter);
}
else
fillSaveList();
mCharacterSelection->setIndexSelected(MyGUI::ITEM_NONE);
}
}
@ -216,7 +216,7 @@ namespace MWGui
mCharacterSelection->setIndexSelected(selectedIndex);
if (selectedIndex == MyGUI::ITEM_NONE)
mCharacterSelection->setCaptionWithReplacing("#{SavegameMenu:SelectCharacter}");
mCharacterSelection->setCaptionWithReplacing("#{OMWEngine:SelectCharacter}");
fillSaveList();
}
@ -430,7 +430,7 @@ namespace MWGui
if (Settings::Manager::getBool("timeplayed", "Saves"))
{
text << "\n"
<< "#{SavegameMenu:TimePlayed}: " << formatTimeplayed(mCurrentSlot->mProfile.mTimePlayed);
<< "#{OMWEngine:TimePlayed}: " << formatTimeplayed(mCurrentSlot->mProfile.mTimePlayed);
}
mInfoText->setCaptionWithReplacing(text.str());

View File

@ -45,14 +45,14 @@ namespace
std::string textureMipmappingToStr(const std::string& val)
{
if (val == "linear")
return "#{SettingsMenu:TextureFilteringTrilinear}";
return "#{OMWEngine:TextureFilteringTrilinear}";
if (val == "nearest")
return "#{SettingsMenu:TextureFilteringBilinear}";
return "#{OMWEngine:TextureFilteringBilinear}";
if (val == "none")
return "#{SettingsMenu:TextureFilteringDisabled}";
return "#{OMWEngine:TextureFilteringDisabled}";
Log(Debug::Warning) << "Warning: Invalid texture mipmap option: " << val;
return "#{SettingsMenu:TextureFilteringOther}";
return "#{OMWEngine:TextureFilteringOther}";
}
std::string lightingMethodToStr(SceneUtil::LightingMethod method)
@ -61,14 +61,14 @@ namespace
switch (method)
{
case SceneUtil::LightingMethod::FFP:
result = "#{SettingsMenu:LightingMethodLegacy}";
result = "#{OMWEngine:LightingMethodLegacy}";
break;
case SceneUtil::LightingMethod::PerObjectUniform:
result = "#{SettingsMenu:LightingMethodShadersCompatibility}";
result = "#{OMWEngine:LightingMethodShadersCompatibility}";
break;
case SceneUtil::LightingMethod::SingleUBO:
default:
result = "#{SettingsMenu:LightingMethodShaders}";
result = "#{OMWEngine:LightingMethodShaders}";
break;
}
@ -533,7 +533,7 @@ namespace MWGui
_sender->setCaptionWithReplacing(_sender->getItemNameAt(_sender->getIndexSelected()));
MWBase::Environment::get().getWindowManager()->interactiveMessageBox(
"#{SettingsMenu:ChangeRequiresRestart}", { "#{sOK}" }, true);
"#{OMWEngine:ChangeRequiresRestart}", { "#{sOK}" }, true);
Settings::Manager::setString("lighting method", "Shaders", *_sender->getItemDataAt<std::string>(pos));
apply();
@ -547,7 +547,7 @@ namespace MWGui
_sender->setCaptionWithReplacing(_sender->getItemNameAt(_sender->getIndexSelected()));
MWBase::Environment::get().getWindowManager()->interactiveMessageBox(
"#{SettingsMenu:ChangeRequiresRestart}", { "#{sOK}" }, true);
"#{OMWEngine:ChangeRequiresRestart}", { "#{sOK}" }, true);
std::vector<std::string> currentLocales = Settings::Manager::getStringArray("preferred locales", "General");
if (currentLocales.size() <= langPriority)
@ -601,7 +601,7 @@ namespace MWGui
{
std::vector<std::string> buttons = { "#{sYes}", "#{sNo}" };
MWBase::Environment::get().getWindowManager()->interactiveMessageBox(
"#{SettingsMenu:LightingResetToDefaults}", buttons, true);
"#{OMWEngine:LightingResetToDefaults}", buttons, true);
int selectedButton = MWBase::Environment::get().getWindowManager()->readPressedButton();
if (selectedButton == 1 || selectedButton == -1)
return;

View File

@ -5,75 +5,68 @@ namespace MWInput
{
enum Actions
{
// please add new actions at the bottom, in order to preserve the channel IDs in the key configuration files
// Action IDs are used in the configuration file input_v3.xml
A_GameMenu,
A_GameMenu = 0,
A_Unused,
A_Screenshot = 2, // Take a screenshot
A_Screenshot, // Take a screenshot
A_Inventory = 3, // Toggle inventory screen
A_Console = 4, // Toggle console screen
A_Inventory, // Toggle inventory screen
A_MoveLeft = 5, // Move player left / right
A_MoveRight = 6,
A_MoveForward = 7, // Forward / Backward
A_MoveBackward = 8,
A_Console, // Toggle console screen
A_Activate = 9,
A_MoveLeft, // Move player left / right
A_MoveRight,
A_MoveForward, // Forward / Backward
A_MoveBackward,
A_Use = 10, // Use weapon, spell, etc.
A_Jump = 11,
A_AutoMove = 12, // Toggle Auto-move forward
A_Rest = 13, // Rest
A_Journal = 14, // Journal
A_Run = 17, // Run when held
A_CycleSpellLeft = 18, // cycling through spells
A_CycleSpellRight = 19,
A_CycleWeaponLeft = 20, // Cycling through weapons
A_CycleWeaponRight = 21,
A_AlwaysRun = 23, // Toggle Walking/Running
A_Sneak = 24,
A_Activate,
A_QuickSave = 25,
A_QuickLoad = 26,
A_QuickMenu = 27,
A_ToggleWeapon = 28,
A_ToggleSpell = 29,
A_Use, // Use weapon, spell, etc.
A_Jump,
A_AutoMove, // Toggle Auto-move forward
A_Rest, // Rest
A_Journal, // Journal
A_Weapon, // Draw/Sheath weapon
A_Spell, // Ready/Unready Casting
A_Run, // Run when held
A_CycleSpellLeft, // cycling through spells
A_CycleSpellRight,
A_CycleWeaponLeft, // Cycling through weapons
A_CycleWeaponRight,
A_ToggleSneak, // Toggles Sneak
A_AlwaysRun, // Toggle Walking/Running
A_Sneak,
A_TogglePOV = 30,
A_QuickSave,
A_QuickLoad,
A_QuickMenu,
A_ToggleWeapon,
A_ToggleSpell,
A_QuickKey1 = 31,
A_QuickKey2 = 32,
A_QuickKey3 = 33,
A_QuickKey4 = 34,
A_QuickKey5 = 35,
A_QuickKey6 = 36,
A_QuickKey7 = 37,
A_QuickKey8 = 38,
A_QuickKey9 = 39,
A_QuickKey10 = 40,
A_TogglePOV,
A_QuickKeysMenu = 41,
A_QuickKey1,
A_QuickKey2,
A_QuickKey3,
A_QuickKey4,
A_QuickKey5,
A_QuickKey6,
A_QuickKey7,
A_QuickKey8,
A_QuickKey9,
A_QuickKey10,
A_ToggleHUD = 42,
A_ToggleDebug = 43,
A_QuickKeysMenu,
A_LookUpDown = 44, // Joystick look
A_LookLeftRight = 45,
A_MoveForwardBackward = 46,
A_MoveLeftRight = 47,
A_ToggleHUD,
A_ZoomIn = 48,
A_ZoomOut = 49,
A_ToggleDebug,
A_LookUpDown, // Joystick look
A_LookLeftRight,
A_MoveForwardBackward,
A_MoveLeftRight,
A_ZoomIn,
A_ZoomOut,
A_TogglePostProcessorHUD,
A_TogglePostProcessorHUD = 50,
A_Last // Marker for the last item
};

View File

@ -441,13 +441,13 @@ namespace MWInput
switch (action)
{
case A_Screenshot:
return "#{SettingsMenu:Screenshot}";
return "#{OMWEngine:Screenshot}";
case A_ZoomIn:
return "#{SettingsMenu:CameraZoomIn}";
return "#{OMWEngine:CameraZoomIn}";
case A_ZoomOut:
return "#{SettingsMenu:CameraZoomOut}";
return "#{OMWEngine:CameraZoomOut}";
case A_ToggleHUD:
return "#{SettingsMenu:ToggleHUD}";
return "#{OMWEngine:ToggleHUD}";
case A_Use:
return "#{sUse}";
case A_Activate:
@ -519,7 +519,7 @@ namespace MWInput
case A_QuickLoad:
return "#{sQuickLoadCmd}";
case A_TogglePostProcessorHUD:
return "#{SettingsMenu:TogglePostProcessorHUD}";
return "#{OMWEngine:TogglePostProcessorHUD}";
default:
return {}; // not configurable
}

View File

@ -45,10 +45,23 @@ namespace MWLua
cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); });
cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); });
cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); });
cellT["hasSky"] = sol::readonly_property([](const CellT& c) {
return c.mStore->getCell()->isExterior() || (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0;
});
cellT["isExterior"] = sol::readonly_property([](const CellT& c) { return c.mStore->isExterior(); });
// deprecated, use cell:hasTag("QuasiExterior") instead
cellT["isQuasiExterior"] = sol::readonly_property(
[](const CellT& c) { return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; });
cellT["hasTag"] = [](const CellT& c, std::string_view tag) -> bool {
if (tag == "NoSleep")
return (c.mStore->getCell()->mData.mFlags & ESM::Cell::NoSleep) != 0;
else if (tag == "QuasiExterior")
return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0;
return false;
};
cellT["isInSameSpace"] = [](const CellT& c, const ObjectT& obj) {
const MWWorld::Ptr& ptr = obj.ptr();
if (!ptr.isInCell())

View File

@ -98,14 +98,11 @@ namespace MWLua
{ "AutoMove", MWInput::A_AutoMove },
{ "Rest", MWInput::A_Rest },
{ "Journal", MWInput::A_Journal },
{ "Weapon", MWInput::A_Weapon },
{ "Spell", MWInput::A_Spell },
{ "Run", MWInput::A_Run },
{ "CycleSpellLeft", MWInput::A_CycleSpellLeft },
{ "CycleSpellRight", MWInput::A_CycleSpellRight },
{ "CycleWeaponLeft", MWInput::A_CycleWeaponLeft },
{ "CycleWeaponRight", MWInput::A_CycleWeaponRight },
{ "ToggleSneak", MWInput::A_ToggleSneak },
{ "AlwaysRun", MWInput::A_AlwaysRun },
{ "Sneak", MWInput::A_Sneak },

View File

@ -401,7 +401,7 @@ namespace MWLua
return localScripts->getActorControls();
}
void LuaManager::addCustomLocalScript(const MWWorld::Ptr& ptr, int scriptId)
void LuaManager::addCustomLocalScript(const MWWorld::Ptr& ptr, int scriptId, std::string_view initData)
{
LocalScripts* localScripts = ptr.getRefData().getLuaScripts();
if (!localScripts)
@ -411,7 +411,7 @@ namespace MWLua
if (ptr.isInCell() && MWBase::Environment::get().getWorldScene()->isCellActive(*ptr.getCell()))
mActiveLocalScripts.insert(localScripts);
}
localScripts->addCustomScript(scriptId);
localScripts->addCustomScript(scriptId, initData);
}
LocalScripts* LuaManager::createLocalScripts(

View File

@ -57,7 +57,7 @@ namespace MWLua
void setupPlayer(const MWWorld::Ptr& ptr) override; // Should be called once after each "clear".
// Used only in Lua bindings
void addCustomLocalScript(const MWWorld::Ptr&, int scriptId);
void addCustomLocalScript(const MWWorld::Ptr&, int scriptId, std::string_view initData);
void addUIMessage(std::string_view message) { mUIMessages.emplace_back(message); }
void addInGameConsoleMessage(const std::string& msg, const Misc::Color& color)
{

View File

@ -200,9 +200,8 @@ namespace MWLua
if constexpr (std::is_same_v<ObjectT, GObject>)
{ // Only for global scripts
objectT["addScript"] = [lua = context.mLua, luaManager = context.mLuaManager](
const GObject& object, std::string_view path) {
const LuaUtil::ScriptsConfiguration& cfg = lua->getConfiguration();
objectT["addScript"] = [context](const GObject& object, std::string_view path, sol::object initData) {
const LuaUtil::ScriptsConfiguration& cfg = context.mLua->getConfiguration();
std::optional<int> scriptId = cfg.findId(path);
if (!scriptId)
throw std::runtime_error("Unknown script: " + std::string(path));
@ -211,7 +210,12 @@ namespace MWLua
"Script without CUSTOM tag can not be added dynamically: " + std::string(path));
if (object.ptr().getType() == ESM::REC_STAT)
throw std::runtime_error("Attaching scripts to Static is not allowed: " + std::string(path));
luaManager->addCustomLocalScript(object.ptr(), *scriptId);
if (initData != sol::nil)
context.mLuaManager->addCustomLocalScript(object.ptr(), *scriptId,
LuaUtil::serialize(initData.as<sol::table>(), context.mSerializer));
else
context.mLuaManager->addCustomLocalScript(
object.ptr(), *scriptId, cfg[*scriptId].mInitializationData);
};
objectT["hasScript"] = [lua = context.mLua](const GObject& object, std::string_view path) {
const LuaUtil::ScriptsConfiguration& cfg = lua->getConfiguration();

View File

@ -400,6 +400,9 @@ namespace MWMechanics
{
if (!mAnimation->isPlaying(mCurrentHit))
{
if (isKnockedOut() && mCurrentHit.empty() && knockout)
return;
mHitState = CharState_None;
mCurrentHit.clear();
stats.setKnockedDown(false);
@ -450,18 +453,6 @@ namespace MWMechanics
mCurrentHit = chooseRandomGroup(hitStateToAnimGroup(CharState_Hit));
}
if (!mAnimation->hasAnimation(mCurrentHit))
{
// The hit animation is missing. Reset the current hit state and immediately cancel all states as if the
// animation were instantaneous.
mHitState = CharState_None;
mCurrentHit.clear();
stats.setKnockedDown(false);
stats.setHitRecovery(false);
resetCurrentIdleState();
return;
}
// Cancel upper body animations
if (isKnockedOut() || isKnockedDown())
{
@ -479,6 +470,12 @@ namespace MWMechanics
}
}
if (!mAnimation->hasAnimation(mCurrentHit))
{
mCurrentHit.clear();
return;
}
mAnimation->play(
mCurrentHit, priority, MWRender::Animation::BlendMask_All, true, 1, startKey, stopKey, 0.0f, ~0ul);
}
@ -755,7 +752,7 @@ namespace MWMechanics
// FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming
// update), the idle animation should be displayed
if (((mUpperBodyState != UpperBodyState::None && mUpperBodyState != UpperBodyState::WeaponEquipped)
|| mMovementState != CharState_None || mHitState != CharState_None)
|| mMovementState != CharState_None || !mCurrentHit.empty())
&& !mPtr.getClass().isBipedal(mPtr))
{
resetCurrentIdleState();

View File

@ -8,6 +8,7 @@
#include <osg/MatrixTransform>
#include <osg/Sequence>
#include <osg/Switch>
#include <osgAnimation/BasicAnimationManager>
#include <osgUtil/IncrementalCompileOperation>
#include <components/esm3/esmreader.hpp>
@ -643,7 +644,9 @@ namespace MWRender
{
if (cnode->getNumChildrenRequiringUpdateTraversal() > 0
|| SceneUtil::hasUserDescription(cnode, Constants::NightDayLabel)
|| SceneUtil::hasUserDescription(cnode, Constants::HerbalismLabel))
|| SceneUtil::hasUserDescription(cnode, Constants::HerbalismLabel)
|| (cnode->getName() == "Collada visual scene group"
&& dynamic_cast<const osgAnimation::BasicAnimationManager*>(cnode->getUpdateCallback())))
continue;
else
refnumSet->mRefnums.push_back(pair.first);

View File

@ -0,0 +1,170 @@
#include "precipitationocclusion.hpp"
#include <osgUtil/CullVisitor>
#include <components/misc/constants.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/depth.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/util.hpp>
#include <components/shader/shadermanager.hpp>
#include "../mwbase/environment.hpp"
#include "vismask.hpp"
namespace
{
class PrecipitationOcclusionUpdater : public SceneUtil::StateSetUpdater
{
public:
PrecipitationOcclusionUpdater(osg::ref_ptr<osg::Texture2D> depthTexture)
: mDepthTexture(depthTexture)
{
}
private:
void setDefaults(osg::StateSet* stateset) override
{
stateset->setTextureAttributeAndModes(3, mDepthTexture);
stateset->addUniform(new osg::Uniform("orthoDepthMap", 3));
stateset->addUniform(new osg::Uniform("depthSpaceMatrix", mDepthSpaceMatrix));
}
void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override
{
osg::Camera* camera = nv->asCullVisitor()->getCurrentCamera();
stateset->getUniform("depthSpaceMatrix")->set(camera->getViewMatrix() * camera->getProjectionMatrix());
}
osg::Matrixf mDepthSpaceMatrix;
osg::ref_ptr<osg::Texture2D> mDepthTexture;
};
class DepthCameraUpdater : public SceneUtil::StateSetUpdater
{
public:
DepthCameraUpdater()
: mDummyTexture(new osg::Texture2D)
{
mDummyTexture->setInternalFormat(GL_RGB);
mDummyTexture->setTextureSize(1, 1);
Shader::ShaderManager& shaderMgr
= MWBase::Environment::get().getResourceSystem()->getSceneManager()->getShaderManager();
osg::ref_ptr<osg::Shader> vertex
= shaderMgr.getShader("precipitationdepth_vertex.glsl", {}, osg::Shader::VERTEX);
osg::ref_ptr<osg::Shader> fragment
= shaderMgr.getShader("precipitationdepth_fragment.glsl", {}, osg::Shader::FRAGMENT);
mProgram = shaderMgr.getProgram(vertex, fragment);
}
private:
void setDefaults(osg::StateSet* stateset) override
{
stateset->addUniform(new osg::Uniform("projectionMatrix", osg::Matrixf()));
stateset->setAttributeAndModes(mProgram, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
stateset->setTextureAttributeAndModes(0, mDummyTexture);
stateset->setRenderBinDetails(
osg::StateSet::OPAQUE_BIN, "RenderBin", osg::StateSet::OVERRIDE_PROTECTED_RENDERBIN_DETAILS);
}
void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override
{
osg::Camera* camera = nv->asCullVisitor()->getCurrentCamera();
stateset->getUniform("projectionMatrix")->set(camera->getProjectionMatrix());
}
osg::Matrixf mProjectionMatrix;
osg::ref_ptr<osg::Texture2D> mDummyTexture;
osg::ref_ptr<osg::Program> mProgram;
};
}
namespace MWRender
{
PrecipitationOccluder::PrecipitationOccluder(
osg::Group* skyNode, osg::Group* sceneNode, osg::Group* rootNode, osg::Camera* camera)
: mSkyNode(skyNode)
, mSceneNode(sceneNode)
, mRootNode(rootNode)
, mSceneCamera(camera)
{
constexpr int rttSize = 256;
mDepthTexture = new osg::Texture2D;
mDepthTexture->setTextureSize(rttSize, rttSize);
mDepthTexture->setSourceFormat(GL_DEPTH_COMPONENT);
mDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24);
mDepthTexture->setSourceType(GL_UNSIGNED_INT);
mDepthTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER);
mDepthTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER);
mDepthTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
mDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
mDepthTexture->setBorderColor(
SceneUtil::AutoDepth::isReversed() ? osg::Vec4(0, 0, 0, 0) : osg::Vec4(1, 1, 1, 1));
mCamera = new osg::Camera;
mCamera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
mCamera->setRenderOrder(osg::Camera::PRE_RENDER);
mCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
mCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT);
mCamera->setNodeMask(Mask_RenderToTexture);
mCamera->setCullMask(Mask_Scene | Mask_Object | Mask_Static);
mCamera->setViewport(0, 0, rttSize, rttSize);
mCamera->attach(osg::Camera::DEPTH_BUFFER, mDepthTexture);
mCamera->addChild(mSceneNode);
SceneUtil::setCameraClearDepth(mCamera);
}
void PrecipitationOccluder::update()
{
const osg::Vec3 pos = mSceneCamera->getInverseViewMatrix().getTrans();
const float zmin = pos.z() - mRange.z() - Constants::CellSizeInUnits;
const float zmax = pos.z() + mRange.z() + Constants::CellSizeInUnits;
const float near = 0;
const float far = zmax - zmin;
const float left = -mRange.x() / 2;
const float right = -left;
const float top = mRange.y() / 2;
const float bottom = -top;
if (SceneUtil::AutoDepth::isReversed())
{
mCamera->setProjectionMatrix(
SceneUtil::getReversedZProjectionMatrixAsOrtho(left, right, bottom, top, near, far));
}
else
{
mCamera->setProjectionMatrix(osg::Matrixf::ortho(left, right, bottom, top, near, far));
}
mCamera->setViewMatrixAsLookAt(
osg::Vec3(pos.x(), pos.y(), zmax), osg::Vec3(pos.x(), pos.y(), zmin), osg::Vec3(0, 1, 0));
}
void PrecipitationOccluder::enable()
{
mSkyNode->setCullCallback(new PrecipitationOcclusionUpdater(mDepthTexture));
mCamera->setCullCallback(new DepthCameraUpdater);
mRootNode->removeChild(mCamera);
mRootNode->addChild(mCamera);
}
void PrecipitationOccluder::disable()
{
mSkyNode->setCullCallback(nullptr);
mCamera->setCullCallback(nullptr);
mRootNode->removeChild(mCamera);
}
void PrecipitationOccluder::updateRange(const osg::Vec3f range)
{
const osg::Vec3f margin = { -50, -50, 0 };
mRange = range - margin;
}
}

View File

@ -0,0 +1,33 @@
#ifndef OPENMW_MWRENDER_PRECIPITATIONOCCLUSION_H
#define OPENMW_MWRENDER_PRECIPITATIONOCCLUSION_H
#include <osg/Camera>
#include <osg/Texture2D>
namespace MWRender
{
class PrecipitationOccluder
{
public:
PrecipitationOccluder(osg::Group* skyNode, osg::Group* sceneNode, osg::Group* rootNode, osg::Camera* camera);
void update();
void enable();
void disable();
void updateRange(const osg::Vec3f range);
private:
osg::Group* mSkyNode;
osg::Group* mSceneNode;
osg::Group* mRootNode;
osg::ref_ptr<osg::Camera> mCamera;
osg::ref_ptr<osg::Camera> mSceneCamera;
osg::ref_ptr<osg::Texture2D> mDepthTexture;
osg::Vec3f mRange;
};
}
#endif

View File

@ -586,8 +586,8 @@ namespace MWRender
mFog = std::make_unique<FogManager>();
mSky = std::make_unique<SkyManager>(sceneRoot, resourceSystem->getSceneManager(), mSkyBlending);
mSky->setCamera(mViewer->getCamera());
mSky = std::make_unique<SkyManager>(
sceneRoot, mRootNode, mViewer->getCamera(), resourceSystem->getSceneManager(), mSkyBlending);
if (mSkyBlending)
{
int skyTextureUnit = mResourceSystem->getSceneManager()->getShaderManager().reserveGlobalTextureUnits(
@ -771,9 +771,11 @@ namespace MWRender
setAmbientColour(ambient);
osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight);
mSunLight->setDiffuse(diffuse);
mSunLight->setSpecular(diffuse);
mSunLight->setPosition(osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f));
setSunColour(diffuse, diffuse, 1.f);
const osg::Vec4f interiorSunPos = osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f);
mPostProcessor->getStateUpdater()->setSunPos(interiorSunPos, false);
mSunLight->setPosition(interiorSunPos);
}
void RenderingManager::setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular, float sunVis)

View File

@ -228,9 +228,10 @@ namespace
namespace MWRender
{
SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager, bool enableSkyRTT)
SkyManager::SkyManager(osg::Group* parentNode, osg::Group* rootNode, osg::Camera* camera,
Resource::SceneManager* sceneManager, bool enableSkyRTT)
: mSceneManager(sceneManager)
, mCamera(nullptr)
, mCamera(camera)
, mAtmosphereNightRoll(0.f)
, mCreated(false)
, mIsStorm(false)
@ -289,6 +290,8 @@ namespace MWRender
mRootNode->setNodeMask(Mask_Sky);
mRootNode->addChild(mEarlyRenderBinRoot);
mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot);
mPrecipitationOccluder = std::make_unique<PrecipitationOccluder>(skyroot, parentNode, rootNode, camera);
}
void SkyManager::create()
@ -382,11 +385,6 @@ namespace MWRender
mCreated = true;
}
void SkyManager::setCamera(osg::Camera* camera)
{
mCamera = camera;
}
void SkyManager::createRain()
{
if (mRainNode)
@ -466,9 +464,11 @@ namespace MWRender
mRainNode->setNodeMask(Mask_WeatherParticles);
mRainParticleSystem->setUserValue("simpleLighting", true);
mRainParticleSystem->setUserValue("particleOcclusion", true);
mSceneManager->recreateShaders(mRainNode);
mRootNode->addChild(mRainNode);
mPrecipitationOccluder->enable();
}
void SkyManager::destroyRain()
@ -482,6 +482,7 @@ namespace MWRender
mCounter = nullptr;
mRainParticleSystem = nullptr;
mRainShooter = nullptr;
mPrecipitationOccluder->disable();
}
SkyManager::~SkyManager()
@ -563,6 +564,7 @@ namespace MWRender
* osg::DegreesToRadians(360.f) / (3600 * 96.f);
if (mAtmosphereNightNode->getNodeMask() != 0)
mAtmosphereNightNode->setAttitude(osg::Quat(mAtmosphereNightRoll, osg::Vec3f(0, 0, 1)));
mPrecipitationOccluder->update();
}
void SkyManager::setEnabled(bool enabled)
@ -606,6 +608,7 @@ namespace MWRender
mPlacer->setZRange(-rainRange.z() / 2, rainRange.z() / 2);
mCounter->setNumberOfParticlesPerSecondToCreate(mRainMaxRaindrops / mRainEntranceSpeed * 20);
mPrecipitationOccluder->updateRange(rainRange);
}
}
@ -671,6 +674,10 @@ namespace MWRender
mRootNode->removeChild(mParticleNode);
mParticleNode = nullptr;
}
if (mRainEffect.empty())
{
mPrecipitationOccluder->disable();
}
}
else
{
@ -693,6 +700,8 @@ namespace MWRender
SceneUtil::FindByClassVisitor findPSVisitor("ParticleSystem");
mParticleEffect->accept(findPSVisitor);
const osg::Vec3 defaultWrapRange = osg::Vec3(1024, 1024, 800);
for (unsigned int i = 0; i < findPSVisitor.mFoundNodes.size(); ++i)
{
osgParticle::ParticleSystem* ps
@ -700,7 +709,7 @@ namespace MWRender
osg::ref_ptr<osgParticle::ModularProgram> program = new osgParticle::ModularProgram;
if (!mIsStorm)
program->addOperator(new WrapAroundOperator(mCamera, osg::Vec3(1024, 1024, 800)));
program->addOperator(new WrapAroundOperator(mCamera, defaultWrapRange));
program->addOperator(new WeatherAlphaOperator(mPrecipitationAlpha, false));
program->setParticleSystem(ps);
mParticleNode->addChild(program);
@ -713,9 +722,16 @@ namespace MWRender
}
ps->setUserValue("simpleLighting", true);
ps->setUserValue("particleOcclusion", true);
}
mSceneManager->recreateShaders(mParticleNode);
if (mCurrentParticleEffect == "meshes\\snow.nif")
{
mPrecipitationOccluder->enable();
mPrecipitationOccluder->updateRange(defaultWrapRange);
}
}
}

View File

@ -8,6 +8,7 @@
#include <osg/Vec4f>
#include <osg/ref_ptr>
#include "precipitationocclusion.hpp"
#include "skyutil.hpp"
namespace osg
@ -43,7 +44,8 @@ namespace MWRender
class SkyManager
{
public:
SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager, bool enableSkyRTT);
SkyManager(osg::Group* parentNode, osg::Group* rootNode, osg::Camera* camera,
Resource::SceneManager* sceneManager, bool enableSkyRTT);
~SkyManager();
void update(float duration);
@ -98,8 +100,6 @@ namespace MWRender
void listAssetsToPreload(std::vector<std::string>& models, std::vector<std::string>& textures);
void setCamera(osg::Camera* camera);
float getBaseWindSpeed() const;
void setSunglare(bool enabled);
@ -151,6 +151,8 @@ namespace MWRender
osg::ref_ptr<RainCounter> mCounter;
osg::ref_ptr<RainShooter> mRainShooter;
std::unique_ptr<PrecipitationOccluder> mPrecipitationOccluder;
bool mCreated;
bool mIsStorm;

View File

@ -1,9 +1,14 @@
#include "esmloader.hpp"
#include "esmstore.hpp"
#include <fstream>
#include <components/esm/format.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/readerscache.hpp>
#include <components/esm4/reader.hpp>
#include <components/files/conversion.hpp>
#include <components/files/openfile.hpp>
namespace MWWorld
{
@ -21,28 +26,47 @@ namespace MWWorld
void EsmLoader::load(const std::filesystem::path& filepath, int& index, Loading::Listener* listener)
{
const ESM::ReadersCache::BusyItem reader = mReaders.get(static_cast<std::size_t>(index));
reader->setEncoder(mEncoder);
reader->setIndex(index);
reader->open(filepath);
reader->resolveParentFileIndices(mReaders);
auto stream = Files::openBinaryInputFileStream(filepath);
const ESM::Format format = ESM::readFormat(*stream);
stream->seekg(0);
assert(reader->getGameFiles().size() == reader->getParentFileIndices().size());
for (std::size_t i = 0, n = reader->getParentFileIndices().size(); i < n; ++i)
if (i == static_cast<std::size_t>(reader->getIndex()))
throw std::runtime_error("File " + Files::pathToUnicodeString(reader->getName()) + " asks for parent file "
switch (format)
{
case ESM::Format::Tes3:
{
const ESM::ReadersCache::BusyItem reader = mReaders.get(static_cast<std::size_t>(index));
reader->setEncoder(mEncoder);
reader->setIndex(index);
reader->open(filepath);
reader->resolveParentFileIndices(mReaders);
assert(reader->getGameFiles().size() == reader->getParentFileIndices().size());
for (std::size_t i = 0, n = reader->getParentFileIndices().size(); i < n; ++i)
if (i == static_cast<std::size_t>(reader->getIndex()))
throw std::runtime_error("File " + Files::pathToUnicodeString(reader->getName()) + " asks for parent file "
+ reader->getGameFiles()[i].name
+ ", but it is not available or has been loaded in the wrong order. "
"Please run the launcher to fix this issue.");
mESMVersions[index] = reader->getVer();
mStore.load(*reader, listener, mDialogue);
mESMVersions[index] = reader->getVer();
mStore.load(*reader, listener, mDialogue);
if (!mMasterFileFormat.has_value()
&& (Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".esm")
|| Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".omwgame")))
mMasterFileFormat = reader->getFormat();
if (!mMasterFileFormat.has_value()
&& (Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".esm")
|| Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".omwgame")))
mMasterFileFormat = reader->getFormat();
break;
}
case ESM::Format::Tes4:
{
ESM4::Reader readerESM4(std::move(stream), filepath);
auto statelessEncoder = mEncoder->getStatelessEncoder();
readerESM4.setEncoder(&statelessEncoder);
mStore.loadESM4(readerESM4);
break;
}
}
}
} /* namespace MWWorld */

View File

@ -14,6 +14,11 @@
#include <components/misc/algorithm.hpp>
#include <components/esm4/common.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadstat.hpp>
#include <components/esm4/reader.hpp>
#include <components/esm4/readerutils.hpp>
#include <components/esmloader/load.hpp>
#include "../mwmechanics/spelllist.hpp"
@ -180,6 +185,35 @@ namespace MWWorld
}
}
}
template <typename T>
static bool typedReadRecordESM4(ESM4::Reader& reader, Store<T>& store)
{
auto recordType = static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId);
ESM::RecNameInts esm4RecName = static_cast<ESM::RecNameInts>(ESM::esm4Recname(recordType));
if constexpr (std::is_convertible_v<Store<T>*, DynamicStore*> && HasRecordId<T>::value)
{
if constexpr (ESM::isESM4Rec(T::sRecordId))
{
if (T::sRecordId == esm4RecName)
{
reader.getRecordData();
T value;
value.load(reader);
store.insertStatic(value);
return true;
}
}
}
return false;
}
static bool readRecord(ESM4::Reader& reader, ESMStore& store)
{
return std::apply([&reader](auto&... x) { return (ESMStoreImp::typedReadRecordESM4(reader, x) || ...); },
store.mStoreImp->mStores);
}
};
int ESMStore::find(const ESM::RefId& id) const
@ -338,6 +372,12 @@ namespace MWWorld
}
}
void ESMStore::loadESM4(ESM4::Reader& reader)
{
auto visitorRec = [this](ESM4::Reader& reader) { return ESMStoreImp::readRecord(reader, *this); };
ESM4::ReaderUtils::readAll(reader, visitorRec, [](ESM4::Reader&) {});
}
void ESMStore::setIdType(const ESM::RefId& id, ESM::RecNameInts type)
{
mStoreImp->mIds[id] = type;

View File

@ -24,6 +24,14 @@ namespace MWMechanics
class SpellList;
}
namespace ESM4
{
class Reader;
struct Static;
struct Cell;
struct Reference;
}
namespace ESM
{
class ReadersCache;
@ -78,7 +86,7 @@ namespace MWWorld
class ESMStore
{
friend struct ESMStoreImp; // This allows StoreImp to extend esmstore without beeing included everywhere
public:
using StoreTuple = std::tuple<Store<ESM::Activator>, Store<ESM::Potion>, Store<ESM::Apparatus>,
Store<ESM::Armor>, Store<ESM::BodyPart>, Store<ESM::Book>, Store<ESM::BirthSign>, Store<ESM::Class>,
Store<ESM::Clothing>, Store<ESM::Container>, Store<ESM::Creature>, Store<ESM::Dialogue>, Store<ESM::Door>,
@ -95,8 +103,11 @@ namespace MWWorld
Store<ESM::MagicEffect>, Store<ESM::Skill>,
// Special entry which is hardcoded and not loaded from an ESM
Store<ESM::Attribute>>;
Store<ESM::Attribute>,
Store<ESM4::Static>, Store<ESM4::Cell>, Store<ESM4::Reference>>;
private:
template <typename T>
static constexpr std::size_t getTypeIndex()
{
@ -162,6 +173,7 @@ namespace MWWorld
void validateDynamic();
void load(ESM::ESMReader& esm, Loading::Listener* listener, ESM::Dialogue*& dialogue);
void loadESM4(ESM4::Reader& esm);
template <class T>
const Store<T>& get() const
@ -252,6 +264,16 @@ namespace MWWorld
template <>
const ESM::NPC* ESMStore::insert<ESM::NPC>(const ESM::NPC& npc);
template <class T, class = std::void_t<>>
struct HasRecordId : std::false_type
{
};
template <class T>
struct HasRecordId<T, std::void_t<decltype(T::sRecordId)>> : std::true_type
{
};
}
#endif

View File

@ -1,18 +1,19 @@
#include "store.hpp"
#include <components/debug/debuglog.hpp>
#include <components/esm/records.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/misc/rng.hpp>
#include <iterator>
#include <sstream>
#include <stdexcept>
#include <components/debug/debuglog.hpp>
#include <components/esm/records.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadstat.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/misc/rng.hpp>
namespace
{
// TODO: Switch to C++23 to get a working version of std::unordered_map::erase
@ -161,7 +162,15 @@ namespace MWWorld
if (ptr == nullptr)
{
std::stringstream msg;
msg << T::getRecordType() << " '" << id << "' not found";
if constexpr (!ESM::isESM4Rec(T::sRecordId))
{
msg << T::getRecordType();
}
else
{
msg << "ESM::REC_" << getRecNameString(T::sRecordId).toStringView();
}
msg << " '" << id << "' not found";
throw std::runtime_error(msg.str());
}
return ptr;
@ -171,8 +180,10 @@ namespace MWWorld
{
T record;
bool isDeleted = false;
record.load(esm, isDeleted);
if constexpr (!ESM::isESM4Rec(T::sRecordId))
{
record.load(esm, isDeleted);
}
std::pair<typename Static::iterator, bool> inserted = mStatic.insert_or_assign(record.mId, record);
if (inserted.second)
@ -292,9 +303,12 @@ namespace MWWorld
{
for (typename Dynamic::const_iterator iter(mDynamic.begin()); iter != mDynamic.end(); ++iter)
{
writer.startRecord(T::sRecordId);
iter->second.save(writer);
writer.endRecord(T::sRecordId);
if constexpr (!ESM::isESM4Rec(T::sRecordId))
{
writer.startRecord(T::sRecordId);
iter->second.save(writer);
writer.endRecord(T::sRecordId);
}
}
}
template <typename T>
@ -302,8 +316,10 @@ namespace MWWorld
{
T record;
bool isDeleted = false;
record.load(reader, isDeleted);
if constexpr (!ESM::isESM4Rec(T::sRecordId))
{
record.load(reader, isDeleted);
}
insert(record, overrideOnly);
return RecordId(record.mId, isDeleted);
@ -1152,6 +1168,20 @@ namespace MWWorld
return mKeywordSearch;
}
ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName)
{
ESM::FixedString<6> name;
name.assign("");
ESM::NAME fourCCName(recName & ~ESM::sEsm4RecnameFlag);
for (int i = 0; i < 4; i++)
name.mData[i] = fourCCName.mData[i];
if (ESM::isESM4Rec(recName))
{
name.mData[4] = '4';
}
return name;
}
}
template class MWWorld::TypedDynamicStore<ESM::Activator>;
@ -1196,3 +1226,7 @@ template class MWWorld::TypedDynamicStore<ESM::Spell>;
template class MWWorld::TypedDynamicStore<ESM::StartScript>;
template class MWWorld::TypedDynamicStore<ESM::Static>;
template class MWWorld::TypedDynamicStore<ESM::Weapon>;
template class MWWorld::TypedDynamicStore<ESM4::Static>;
template class MWWorld::TypedDynamicStore<ESM4::Reference>;
template class MWWorld::TypedDynamicStore<ESM4::Cell>;

View File

@ -517,6 +517,8 @@ namespace MWWorld
const MWDialogue::KeywordSearch<std::string, int>& getDialogIdKeywordSearch() const;
};
ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName);
} // end namespace
#endif

View File

@ -2,142 +2,187 @@
#include "components/esm/esmcommon.hpp"
#include <gtest/gtest.h>
TEST(EsmFixedString, operator__eq_ne)
namespace
{
TEST(EsmFixedString, operator__eq_ne)
{
SCOPED_TRACE("asdc == asdc");
constexpr ESM::NAME name("asdc");
char s[4] = { 'a', 's', 'd', 'c' };
std::string ss(s, 4);
{
SCOPED_TRACE("asdc == asdc");
constexpr ESM::NAME name("asdc");
char s[4] = { 'a', 's', 'd', 'c' };
std::string ss(s, 4);
EXPECT_TRUE(name == s);
EXPECT_TRUE(name == ss.c_str());
EXPECT_TRUE(name == ss);
EXPECT_TRUE(name == s);
EXPECT_TRUE(name == ss.c_str());
EXPECT_TRUE(name == ss);
}
{
SCOPED_TRACE("asdc == asdcx");
constexpr ESM::NAME name("asdc");
char s[5] = { 'a', 's', 'd', 'c', 'x' };
std::string ss(s, 5);
EXPECT_TRUE(name != s);
EXPECT_TRUE(name != ss.c_str());
EXPECT_TRUE(name != ss);
}
{
SCOPED_TRACE("asdc == asdc[NULL]");
const ESM::NAME name("asdc");
char s[5] = { 'a', 's', 'd', 'c', '\0' };
std::string ss(s, 5);
EXPECT_TRUE(name == s);
EXPECT_TRUE(name == ss.c_str());
EXPECT_TRUE(name == ss);
}
}
{
SCOPED_TRACE("asdc == asdcx");
constexpr ESM::NAME name("asdc");
char s[5] = { 'a', 's', 'd', 'c', 'x' };
std::string ss(s, 5);
EXPECT_TRUE(name != s);
EXPECT_TRUE(name != ss.c_str());
EXPECT_TRUE(name != ss);
TEST(EsmFixedString, operator__eq_ne_const)
{
{
SCOPED_TRACE("asdc == asdc (const)");
constexpr ESM::NAME name("asdc");
const char s[4] = { 'a', 's', 'd', 'c' };
std::string ss(s, 4);
EXPECT_TRUE(name == s);
EXPECT_TRUE(name == ss.c_str());
EXPECT_TRUE(name == ss);
}
{
SCOPED_TRACE("asdc == asdcx (const)");
constexpr ESM::NAME name("asdc");
const char s[5] = { 'a', 's', 'd', 'c', 'x' };
std::string ss(s, 5);
EXPECT_TRUE(name != s);
EXPECT_TRUE(name != ss.c_str());
EXPECT_TRUE(name != ss);
}
{
SCOPED_TRACE("asdc == asdc[NULL] (const)");
constexpr ESM::NAME name("asdc");
const char s[5] = { 'a', 's', 'd', 'c', '\0' };
std::string ss(s, 5);
EXPECT_TRUE(name == s);
EXPECT_TRUE(name == ss.c_str());
EXPECT_TRUE(name == ss);
}
}
{
SCOPED_TRACE("asdc == asdc[NULL]");
const ESM::NAME name("asdc");
char s[5] = { 'a', 's', 'd', 'c', '\0' };
std::string ss(s, 5);
EXPECT_TRUE(name == s);
EXPECT_TRUE(name == ss.c_str());
EXPECT_TRUE(name == ss);
TEST(EsmFixedString, empty_strings)
{
{
SCOPED_TRACE("4 bytes");
ESM::NAME empty = ESM::NAME();
EXPECT_TRUE(empty == "");
EXPECT_TRUE(empty == static_cast<uint32_t>(0));
EXPECT_TRUE(empty != "some string");
EXPECT_TRUE(empty != static_cast<uint32_t>(42));
}
{
SCOPED_TRACE("32 bytes");
ESM::NAME32 empty = ESM::NAME32();
EXPECT_TRUE(empty == "");
EXPECT_TRUE(empty != "some string");
}
}
TEST(EsmFixedString, assign_should_zero_untouched_bytes_for_4)
{
ESM::NAME value;
value = static_cast<uint32_t>(0xFFFFFFFFu);
value.assign(std::string(1, 'a'));
EXPECT_EQ(value, static_cast<uint32_t>('a')) << value.toInt();
}
TEST(EsmFixedString, assign_should_only_truncate_for_4)
{
ESM::NAME value;
value.assign(std::string(5, 'a'));
EXPECT_EQ(value, std::string(4, 'a'));
}
TEST(EsmFixedString, assign_should_truncate_and_set_last_element_to_zero)
{
ESM::FixedString<17> value;
value.assign(std::string(20, 'a'));
EXPECT_EQ(value, std::string(16, 'a'));
}
TEST(EsmFixedString, assign_should_truncate_and_set_last_element_to_zero_for_32)
{
ESM::NAME32 value;
value.assign(std::string(33, 'a'));
EXPECT_EQ(value, std::string(31, 'a'));
}
TEST(EsmFixedString, assign_should_truncate_and_set_last_element_to_zero_for_64)
{
ESM::NAME64 value;
value.assign(std::string(65, 'a'));
EXPECT_EQ(value, std::string(63, 'a'));
}
TEST(EsmFixedString, assignment_operator_is_supported_for_uint32)
{
ESM::NAME value;
value = static_cast<uint32_t>(0xFEDCBA98u);
EXPECT_EQ(value, static_cast<uint32_t>(0xFEDCBA98u)) << value.toInt();
}
TEST(EsmFixedString, construction_from_uint32_is_supported)
{
constexpr ESM::NAME value(0xFEDCBA98u);
EXPECT_EQ(value, static_cast<std::uint32_t>(0xFEDCBA98u)) << value.toInt();
}
TEST(EsmFixedString, construction_from_RecNameInts_is_supported)
{
constexpr ESM::NAME value(ESM::RecNameInts::REC_ACTI);
EXPECT_EQ(value, static_cast<std::uint32_t>(ESM::RecNameInts::REC_ACTI)) << value.toInt();
}
TEST(EsmFixedString, equality_operator_for_not_convertible_to_uint32_with_string_literal)
{
const ESM::FixedString<5> value("abcd");
EXPECT_EQ(value, "abcd");
}
TEST(EsmFixedString, equality_operator_for_not_convertible_to_uint32_with_fixed_size_char_array)
{
const ESM::FixedString<5> value("abcd");
const char other[5] = { 'a', 'b', 'c', 'd', '\0' };
EXPECT_EQ(value, other);
}
TEST(EsmFixedString, equality_operator_for_not_convertible_to_uint32_with_const_char_pointer)
{
const ESM::FixedString<5> value("abcd");
const char other[5] = { 'a', 'b', 'c', 'd', '\0' };
EXPECT_EQ(value, static_cast<const char*>(other));
}
TEST(EsmFixedString, equality_operator_for_not_convertible_to_uint32_with_string)
{
const ESM::FixedString<5> value("abcd");
EXPECT_EQ(value, std::string("abcd"));
}
TEST(EsmFixedString, equality_operator_for_not_convertible_to_uint32_with_string_view)
{
const ESM::FixedString<5> value("abcd");
const std::string other("abcd");
EXPECT_EQ(value, std::string_view(other));
}
TEST(EsmFixedString, equality_operator_should_not_get_out_of_bounds)
{
ESM::FixedString<5> value;
const char other[5] = { 'a', 'b', 'c', 'd', 'e' };
std::memcpy(value.mData, other, sizeof(other));
EXPECT_EQ(value, static_cast<const char*>(other));
}
}
TEST(EsmFixedString, operator__eq_ne_const)
{
{
SCOPED_TRACE("asdc == asdc (const)");
constexpr ESM::NAME name("asdc");
const char s[4] = { 'a', 's', 'd', 'c' };
std::string ss(s, 4);
EXPECT_TRUE(name == s);
EXPECT_TRUE(name == ss.c_str());
EXPECT_TRUE(name == ss);
}
{
SCOPED_TRACE("asdc == asdcx (const)");
constexpr ESM::NAME name("asdc");
const char s[5] = { 'a', 's', 'd', 'c', 'x' };
std::string ss(s, 5);
EXPECT_TRUE(name != s);
EXPECT_TRUE(name != ss.c_str());
EXPECT_TRUE(name != ss);
}
{
SCOPED_TRACE("asdc == asdc[NULL] (const)");
constexpr ESM::NAME name("asdc");
const char s[5] = { 'a', 's', 'd', 'c', '\0' };
std::string ss(s, 5);
EXPECT_TRUE(name == s);
EXPECT_TRUE(name == ss.c_str());
EXPECT_TRUE(name == ss);
}
}
TEST(EsmFixedString, empty_strings)
{
{
SCOPED_TRACE("4 bytes");
ESM::NAME empty = ESM::NAME();
EXPECT_TRUE(empty == "");
EXPECT_TRUE(empty == static_cast<uint32_t>(0));
EXPECT_TRUE(empty != "some string");
EXPECT_TRUE(empty != static_cast<uint32_t>(42));
}
{
SCOPED_TRACE("32 bytes");
ESM::NAME32 empty = ESM::NAME32();
EXPECT_TRUE(empty == "");
EXPECT_TRUE(empty != "some string");
}
}
TEST(EsmFixedString, assign_should_zero_untouched_bytes_for_4)
{
ESM::NAME value;
value = static_cast<uint32_t>(0xFFFFFFFFu);
value.assign(std::string(1, 'a'));
EXPECT_EQ(value, static_cast<uint32_t>('a')) << value.toInt();
}
TEST(EsmFixedString, assign_should_only_truncate_for_4)
{
ESM::NAME value;
value.assign(std::string(5, 'a'));
EXPECT_EQ(value, std::string(4, 'a'));
}
TEST(EsmFixedString, assign_should_truncate_and_set_last_element_to_zero)
{
ESM::FixedString<17> value;
value.assign(std::string(20, 'a'));
EXPECT_EQ(value, std::string(16, 'a'));
}
TEST(EsmFixedString, assign_should_truncate_and_set_last_element_to_zero_for_32)
{
ESM::NAME32 value;
value.assign(std::string(33, 'a'));
EXPECT_EQ(value, std::string(31, 'a'));
}
TEST(EsmFixedString, assign_should_truncate_and_set_last_element_to_zero_for_64)
{
ESM::NAME64 value;
value.assign(std::string(65, 'a'));
EXPECT_EQ(value, std::string(63, 'a'));
}
TEST(EsmFixedString, assignment_operator_is_supported_for_uint32)
{
ESM::NAME value;
value = static_cast<uint32_t>(0xFEDCBA98u);
EXPECT_EQ(value, static_cast<uint32_t>(0xFEDCBA98u)) << value.toInt();
}
TEST(EsmFixedString, construction_from_uint32_is_supported)
{
constexpr ESM::NAME value(0xFEDCBA98u);
EXPECT_EQ(value, static_cast<std::uint32_t>(0xFEDCBA98u)) << value.toInt();
}
TEST(EsmFixedString, construction_from_RecNameInts_is_supported)
{
constexpr ESM::NAME value(ESM::RecNameInts::REC_ACTI);
EXPECT_EQ(value, static_cast<std::uint32_t>(ESM::RecNameInts::REC_ACTI)) << value.toInt();
}

View File

@ -8,6 +8,12 @@
#include <components/esm/records.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/esm4/common.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadstat.hpp>
#include <components/esm4/reader.hpp>
#include <components/esm4/readerutils.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/files/conversion.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
@ -289,6 +295,41 @@ TEST_F(StoreTest, delete_test)
ASSERT_TRUE(mEsmStore.get<RecordType>().getSize() == 1);
}
template <typename T>
static unsigned int hasSameRecordId(const MWWorld::Store<T>& store, ESM::RecNameInts RecName)
{
if constexpr (MWWorld::HasRecordId<T>::value)
{
return T::sRecordId == RecName ? 1 : 0;
}
else
{
return 0;
}
}
template <typename T>
static void testRecNameIntCount(const MWWorld::Store<T>& store, const MWWorld::ESMStore::StoreTuple& stores)
{
if constexpr (MWWorld::HasRecordId<T>::value)
{
const unsigned int recordIdCount
= std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores);
ASSERT_EQ(recordIdCount, static_cast<unsigned int>(1))
<< "The same RecNameInt is used twice ESM::REC_" << MWWorld::getRecNameString(T::sRecordId).toStringView();
}
}
static void testAllRecNameIntUnique(const MWWorld::ESMStore::StoreTuple& stores)
{
std::apply([&stores](auto&&... x) { (testRecNameIntCount(x, stores), ...); }, stores);
}
TEST_F(StoreTest, eachRecordTypeShouldHaveUniqueRecordId)
{
testAllRecNameIntUnique(MWWorld::ESMStore::StoreTuple());
}
/// Tests overwriting of records.
TEST_F(StoreTest, overwrite_test)
{

View File

@ -193,6 +193,7 @@ add_component_dir (esm4
reader
reference
script
readerutils
)
add_component_dir (misc

View File

@ -276,7 +276,7 @@ namespace DetourNavigator
const Loading::ScopedLoad load(listener);
if (listener != nullptr)
{
listener->setLabel("#{Navigation:BuildingNavigationMesh}");
listener->setLabel("#{OMWEngine:BuildingNavigationMesh}");
listener->setProgressRange(maxProgress);
}
while (!mDone.wait_for(lock, std::chrono::milliseconds(20), isDone))

View File

@ -333,6 +333,11 @@ namespace ESM
REC_MSET4 = esm4Recname(ESM4::REC_MSET) // Media Set
};
constexpr bool isESM4Rec(RecNameInts RecName)
{
return RecName & sEsm4RecnameFlag;
}
/// Common subrecords
enum SubRecNameInts
{

View File

@ -121,23 +121,23 @@ namespace ESM
}
};
template <std::size_t capacity, class T, typename = std::enable_if_t<std::is_same_v<T, char>>>
inline bool operator==(const FixedString<capacity>& lhs, const T* const& rhs) noexcept
template <std::size_t capacity>
inline bool operator==(const FixedString<capacity>& lhs, std::string_view rhs) noexcept
{
for (std::size_t i = 0; i < capacity; ++i)
for (std::size_t i = 0, n = std::min(rhs.size(), capacity); i < n; ++i)
{
if (lhs.mData[i] != rhs[i])
return false;
if (lhs.mData[i] == '\0')
return true;
}
return rhs[capacity] == '\0';
return rhs.size() <= capacity || rhs[capacity] == '\0';
}
template <std::size_t capacity>
inline bool operator==(const FixedString<capacity>& lhs, const std::string& rhs) noexcept
template <std::size_t capacity, class T, typename = std::enable_if_t<std::is_same_v<T, char>>>
inline bool operator==(const FixedString<capacity>& lhs, const T* const& rhs) noexcept
{
return lhs == rhs.c_str();
return lhs == std::string_view(rhs, capacity);
}
template <std::size_t capacity, std::size_t rhsSize>
@ -156,6 +156,12 @@ namespace ESM
return lhs.toInt() == rhs.toInt();
}
template <class T, typename = std::enable_if_t<std::is_same_v<T, char>>>
inline bool operator==(const FixedString<4>& lhs, const T* const& rhs) noexcept
{
return lhs == std::string_view(rhs, 5);
}
template <std::size_t capacity, class Rhs>
inline bool operator!=(const FixedString<capacity>& lhs, const Rhs& rhs) noexcept
{

View File

@ -29,6 +29,11 @@ namespace ESM
return newRefId;
}
RefId RefId::formIdRefId(const ESM4::FormId id)
{
return ESM::RefId::stringRefId(ESM4::formIdToString(id));
}
bool RefId::operator==(std::string_view rhs) const
{
return Misc::StringUtils::ciEqual(mId, rhs);

View File

@ -6,6 +6,8 @@
#include <string>
#include <string_view>
#include <components/esm4/formid.hpp>
namespace ESM
{
// RefId is used to represent an Id that identifies an ESM record. These Ids can then be used in
@ -27,6 +29,7 @@ namespace ESM
// RefIds that are as string in the code. For serialization, and display. Using explicit conversions make it
// very clear where in the code we need to convert from string to RefId and Vice versa.
static RefId stringRefId(std::string_view id);
static RefId formIdRefId(const ESM4::FormId id);
const std::string& getRefIdString() const { return mId; }
private:

View File

@ -32,12 +32,13 @@
#include <cassert>
#include <cfloat> // FLT_MAX for gcc
#include <iostream> // FIXME: debug only
#include <stdexcept>
#include <iostream> // FIXME: debug only
#include "reader.hpp"
//#include "writer.hpp"
// #include "writer.hpp"
#include <components/esm/refid.hpp>
// TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent)
//
@ -48,8 +49,9 @@
// longer/shorter/same as loading the subrecords.
void ESM4::Cell::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
auto formId = reader.hdr().record.id;
reader.adjustFormId(formId);
mId = ESM::RefId::formIdRefId(formId);
mFlags = reader.hdr().record.flags;
mParent = reader.currWorld();
@ -71,7 +73,7 @@ void ESM4::Cell::load(ESM4::Reader& reader)
// WARN: we need to call setCurrCell (and maybe setCurrCellGrid?) again before loading
// cell child groups if we are loading them after restoring the context
// (may be easier to update the context before saving?)
reader.setCurrCell(mFormId); // save for LAND (and other children) to access later
reader.setCurrCell(formId); // save for LAND (and other children) to access later
std::uint32_t esmVer = reader.esmVersion();
bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134;

View File

@ -34,6 +34,9 @@
#include "formid.hpp"
#include "lighting.hpp"
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
namespace ESM4
{
class Reader;
@ -61,7 +64,7 @@ namespace ESM4
{
FormId mParent; // world formId (for grouping cells), from the loading sequence
FormId mFormId; // from the header
ESM::RefId mId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
@ -95,6 +98,8 @@ namespace ESM4
// void save(ESM4::Writer& writer) const;
void blank();
static constexpr ESM::RecNameInts sRecordId = ESM::REC_CELL4;
};
}

View File

@ -30,14 +30,15 @@
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
// #include "writer.hpp"
void ESM4::Reference::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
auto formId = reader.hdr().record.id;
reader.adjustFormId(formId);
mId = ESM::RefId::formIdRefId(formId);
mFlags = reader.hdr().record.flags;
mParent = reader.currCell(); // NOTE: only for persistent refs?
mParent = ESM::RefId::formIdRefId(reader.currCell()); // NOTE: only for persistent refs?
// TODO: Let the engine apply this? Saved games?
// mInitiallyDisabled = ((mFlags & ESM4::Rec_Disabled) != 0) ? true : false;
@ -60,7 +61,9 @@ void ESM4::Reference::load(ESM4::Reader& reader)
break;
case ESM4::SUB_NAME:
{
reader.getFormId(mBaseObj);
FormId BaseId;
reader.getFormId(BaseId);
mBaseObj = ESM::RefId::formIdRefId(BaseId);
#if 0
if (mFlags & ESM4::Rec_Disabled)
std::cout << "REFR disable at start " << formIdToString(mFormId) <<

View File

@ -31,6 +31,9 @@
#include "reference.hpp" // FormId, Placement, EnableParent
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
namespace ESM4
{
class Reader;
@ -71,15 +74,15 @@ namespace ESM4
struct Reference
{
FormId mParent; // cell FormId (currently persistent refs only), from the loading sequence
// NOTE: for exterior cells it will be the dummy cell FormId
ESM::RefId mParent; // cell FormId (currently persistent refs only), from the loading sequence
// NOTE: for exterior cells it will be the dummy cell FormId
FormId mFormId; // from the header
ESM::RefId mId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
std::string mFullName;
FormId mBaseObj;
ESM::RefId mBaseObj;
Placement mPlacement;
float mScale = 1.0f;
@ -110,6 +113,8 @@ namespace ESM4
// void save(ESM4::Writer& writer) const;
void blank();
static constexpr ESM::RecNameInts sRecordId = ESM::REC_REFR4;
};
}

View File

@ -30,12 +30,13 @@
#include <stdexcept>
#include "reader.hpp"
//#include "writer.hpp"
// #include "writer.hpp"
void ESM4::Static::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
FormId formId = reader.hdr().record.id;
reader.adjustFormId(formId);
mId = ESM::RefId::formIdRefId(formId);
mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader())

View File

@ -33,6 +33,9 @@
#include "formid.hpp"
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
namespace ESM4
{
class Reader;
@ -40,7 +43,7 @@ namespace ESM4
struct Static
{
FormId mFormId; // from the header
ESM::RefId mId; // from the header
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
std::string mEditorId;
@ -53,6 +56,8 @@ namespace ESM4
// void save(ESM4::Writer& writer) const;
// void blank();
static constexpr ESM::RecNameInts sRecordId = ESM::REC_STAT4;
};
}

View File

@ -0,0 +1,84 @@
#ifndef OPENMW_COMPONENTS_ESM4_READERUTILS
#define OPENMW_COMPONENTS_ESM4_READERUTILS
#include <components/esm4/reader.hpp>
namespace ESM4
{
struct ReaderUtils
{
/* RecordInvocable must be an invocable, takes an ESM4::Reader& as input, and outputs a boolean that indicates
if the record was read or ignored. Will be invoked for every record
GroupInvocable's invocable must take a ESM4::Reader& as input, doesn't need to output anything. Will be invoked
for every group*/
template <typename RecordInvocable, typename GroupInvocable>
static void readAll(ESM4::Reader& reader, RecordInvocable&& recordInvocable, GroupInvocable&& groupInvocable)
{
while (reader.hasMoreRecs())
{
reader.exitGroupCheck();
if (!readItem(reader, recordInvocable, groupInvocable))
break;
}
}
template <typename RecordInvocable>
static void readRecord(ESM4::Reader& reader, RecordInvocable&& recordInvocable)
{
if (!recordInvocable(reader))
reader.skipRecordData();
}
template <typename RecordInvocable, typename GroupInvocable>
static bool readGroup(ESM4::Reader& reader, RecordInvocable&& recordInvocable, GroupInvocable&& groupInvocable)
{
const ESM4::RecordHeader& header = reader.hdr();
groupInvocable(reader);
switch (static_cast<ESM4::GroupType>(header.group.type))
{
case ESM4::Grp_RecordType:
case ESM4::Grp_InteriorCell:
case ESM4::Grp_InteriorSubCell:
case ESM4::Grp_ExteriorCell:
case ESM4::Grp_ExteriorSubCell:
reader.enterGroup();
return readItem(reader, recordInvocable, groupInvocable);
case ESM4::Grp_WorldChild:
case ESM4::Grp_CellChild:
case ESM4::Grp_TopicChild:
case ESM4::Grp_CellPersistentChild:
case ESM4::Grp_CellTemporaryChild:
case ESM4::Grp_CellVisibleDistChild:
reader.adjustGRUPFormId();
reader.enterGroup();
if (!reader.hasMoreRecs())
return false;
return readItem(reader, recordInvocable, groupInvocable);
}
reader.skipGroup();
return true;
}
template <typename RecordInvocable, typename GroupInvocable>
static bool readItem(ESM4::Reader& reader, RecordInvocable&& recordInvocable, GroupInvocable&& groupInvocable)
{
if (!reader.getRecordHeader() || !reader.hasMoreRecs())
return false;
const ESM4::RecordHeader& header = reader.hdr();
if (header.record.typeId == ESM4::REC_GRUP)
return readGroup(reader, recordInvocable, groupInvocable);
readRecord(reader, recordInvocable);
return true;
}
};
}
#endif // !OPENMW_COMPONENTS_ESM4_READERUTILS

View File

@ -35,14 +35,13 @@ namespace LuaUtil
mAPI.emplace(std::move(packageName), makeReadOnly(std::move(package)));
}
bool ScriptsContainer::addCustomScript(int scriptId)
bool ScriptsContainer::addCustomScript(int scriptId, std::string_view initData)
{
const ScriptsConfiguration& conf = mLua.getConfiguration();
assert(conf.isCustomScript(scriptId));
assert(mLua.getConfiguration().isCustomScript(scriptId));
std::optional<sol::function> onInit, onLoad;
bool ok = addScript(scriptId, onInit, onLoad);
if (ok && onInit)
callOnInit(scriptId, *onInit, conf[scriptId].mInitializationData);
callOnInit(scriptId, *onInit, initData);
return ok;
}

View File

@ -91,7 +91,7 @@ namespace LuaUtil
// new script, adds it to the container, and calls onInit for this script. Returns `true` if the script was
// successfully added. The script should have CUSTOM flag. If the flag is not set, or file not found, or has
// syntax errors, returns false. If such script already exists in the container, then also returns false.
bool addCustomScript(int scriptId);
bool addCustomScript(int scriptId, std::string_view initData = "");
bool hasScript(int scriptId) const { return mScripts.count(scriptId) != 0; }
void removeScript(int scriptId);

View File

@ -37,4 +37,17 @@ namespace osgMyGUI
<< separator << _line << std::endl;
}
}
MyGUI::LogLevel LogFacility::getCurrentLogLevel() const
{
switch (Debug::CurrentDebugLevel)
{
case Debug::Error:
return MyGUI::LogLevel::Error;
case Debug::Warning:
return MyGUI::LogLevel::Warning;
default:
return MyGUI::LogLevel::Info;
}
}
}

View File

@ -47,12 +47,14 @@ namespace osgMyGUI
MyGUI::LevelLogFilter mFilter;
MyGUI::LogSource mSource;
MyGUI::LogLevel getCurrentLogLevel() const;
public:
LogFacility(const std::filesystem::path& output, bool console)
: mFile(output)
{
mConsole.setEnabled(console);
mFilter.setLoggingLevel(MyGUI::LogLevel::Info);
mFilter.setLoggingLevel(getCurrentLogLevel());
mSource.addLogListener(&mFile);
mSource.addLogListener(&mConsole);

View File

@ -636,6 +636,9 @@ namespace Resource
backToOriginTrans->addChild(newRiggeometryHolder);
group->addChild(backToOriginTrans);
node->getOrCreateUserDataContainer()->addUserObject(
new TemplateRef(newRiggeometryHolder->getGeometry(0)));
}
}
}

View File

@ -25,6 +25,7 @@
#include <components/sceneutil/morphgeometry.hpp>
#include <components/sceneutil/riggeometry.hpp>
#include <components/sceneutil/riggeometryosgaextension.hpp>
#include <components/settings/settings.hpp>
#include <components/stereo/stereomanager.hpp>
#include <components/vfs/manager.hpp>
@ -675,6 +676,11 @@ namespace Shader
if (simpleLighting || dynamic_cast<osgParticle::ParticleSystem*>(&node))
defineMap["forcePPL"] = "0";
bool particleOcclusion = false;
node.getUserValue("particleOcclusion", particleOcclusion);
defineMap["particleOcclusion"]
= particleOcclusion && Settings::Manager::getBool("weather particle occlusion", "Shaders") ? "1" : "0";
if (reqs.mAlphaBlend && mSupportsNormalsRT)
{
if (reqs.mSoftParticles)

View File

@ -68,6 +68,8 @@ namespace ToUTF8
/// ASCII-only string. Otherwise returns a view to the input.
std::string_view getLegacyEnc(std::string_view input);
StatelessUtf8Encoder getStatelessEncoder() const { return mImpl; }
private:
std::string mBuffer;
StatelessUtf8Encoder mImpl;

View File

@ -4,6 +4,8 @@
#include <MyGUI_Gui.h>
#include <MyGUI_ImageBox.h>
#include <components/misc/strings/algorithm.hpp>
namespace Gui
{
@ -124,6 +126,12 @@ namespace Gui
return mItems[at];
}
void MWList::sort()
{
// A special case for separators is not needed for now
std::sort(mItems.begin(), mItems.end(), Misc::StringUtils::ciLess);
}
void MWList::removeItem(const std::string& name)
{
assert(std::find(mItems.begin(), mItems.end(), name) != mItems.end());

View File

@ -35,6 +35,7 @@ namespace Gui
*/
void adjustSize();
void sort();
void addItem(std::string_view name);
void addSeparator(); ///< add a seperator between the current and the next item.
void removeItem(const std::string& name);

View File

@ -49,8 +49,8 @@ pip3 install -r docs/requirements.txt
sudo apt install luarocks
git clone https://gitlab.com/ptmikheev/openmw-luadocumentor.git
cd openmw-luadocumentor/luarocks
luarocks --local pack openmwluadocumentor-0.1.1-1.rockspec
luarocks --local install openmwluadocumentor-0.1.1-1.src.rock
luarocks --local pack openmwluadocumentor-0.2.0-1.rockspec
luarocks --local install openmwluadocumentor-0.2.0-1.src.rock
```
**Windows**
@ -61,8 +61,8 @@ luarocks --local install openmwluadocumentor-0.1.1-1.src.rock
- `cd openmw-luadocumentor/luarocks`
- open "Developer Command Prompt for VS <2017/2019>" in this directory and run:
```bash
luarocks --local pack openmwluadocumentor-0.1.1-1.rockspec
luarocks --local install openmwluadocumentor-0.1.1-1.src.rock
luarocks --local pack openmwluadocumentor-0.2.0-1.rockspec
luarocks --local install openmwluadocumentor-0.2.0-1.src.rock
```
### Generating HTML

View File

@ -59,7 +59,8 @@ Sources can be found in ``resources/vfs/openmw_aux``. In theory mods can overrid
.. include:: tables/aux_packages.rst
**Interfaces of built-in scripts**
Interfaces of built-in scripts
------------------------------
.. list-table::
:widths: 20 20 60

View File

@ -85,7 +85,7 @@ Let's write a simple example of a `Player script`:
.. code-block:: Lua
-- Save to my_lua_mod/example/player.lua
-- Save to my_lua_mod/scripts/example/player.lua
local ui = require('openmw.ui')
@ -107,7 +107,7 @@ The options are:
1. Create text file "my_lua_mod.omwscripts" with the following line:
::
PLAYER: example/player.lua
PLAYER: scripts/example/player.lua
2. (not implemented yet) Add the script in OpenMW CS on "Lua scripts" view and save as "my_lua_mod.omwaddon".
@ -122,6 +122,19 @@ Enable it in ``openmw.cfg`` the same way as any other mod:
Now every time the player presses "X" on a keyboard, a message is shown.
Lua scripts naming policy
=========================
Technically scripts can be placed anywhere in the virtual file system, but we recommend to follow the naming policy and choose one of:
- ``scripts/<ModName>/<ScriptName>.lua``: general case.
- ``scripts/<AuthorName>/<ModName>/<ScriptName>.lua``: if "ModName" is short and can potentially collide with other mods.
- ``scripts/<ModName>.lua``: if it is a simple mod that consists from a single script, the script can placed to ``scripts/`` without subdirs.
``scripts/omw/`` is reserved for built-in scripts, don't use it in mods. Overriding built-in scripts is not recommended, prefer to adjust their behaviour via :ref:`Interfaces of built-in scripts` instead.
See also naming policy of :ref:`Localisation Files`.
Format of ``.omwscripts``
=========================
@ -129,20 +142,20 @@ Format of ``.omwscripts``
# Lines starting with '#' are comments
GLOBAL: my_mod/some_global_script.lua
GLOBAL: scripts/my_mod/some_global_script.lua
# Script that will be automatically attached to the player
PLAYER: my_mod/player.lua
PLAYER: scripts/my_mod/player.lua
# Local script that will be automatically attached to every NPC and every creature in the game
NPC, CREATURE: my_mod/some_other_script.lua
NPC, CREATURE: scripts/my_mod/some_other_script.lua
# Local script that can be attached to any object by a global script
CUSTOM: my_mod/something.lua
CUSTOM: scripts/my_mod/something.lua
# Local script that will be automatically attached to any Container AND can be
# attached to any other object by a global script.
CONTAINER, CUSTOM: my_mod/container.lua
CONTAINER, CUSTOM: scripts/my_mod/container.lua
Each script is described by one line:
``<flags>: <path to .lua file in virtual file system>``.

View File

@ -31,11 +31,26 @@ E.g. if you include ``en_US.yaml`` and ``en_GB.yaml`` localisation files, you sh
Note that because of the fallbacks only messages which differ between variants need to be included in the country-specific localisation files.
Localisation Files
--------------------------
------------------
Localisation files (containing the message names and translations) should be stored in the
VFS as files of the form ``l10n/<ContextName>/<Locale>.yaml``.
**Naming policy**
"ContextName" should be in line with :ref:`Lua scripts naming policy`:
- L10n files for ``scripts/<ModName>/<ScriptName>.lua`` should be placed to ``l10n/<ModName>/<Locale>.yaml``.
- L10n files for ``scripts/<AuthorName>/<ModName>/<ScriptName>.lua`` should be placed to ``l10n/<AuthorName><ModName>/<Locale>.yaml``.
In most cases one mod should have only one l10n context. Don't create a new context for each single message. Really big mods with hundreds and thousands of messages can have several l10n contexts. In this case all context names should start with the name of the mod. I.e. ``<ContextName> = <ModName><Subcontext>`` (or ``<AuthorName><ModName><Subcontext>``).
L10n contexts with prefix "OMW" are reserved for the OpenMW itself (in particular for built-in scripts ``scripts/omw/``) and shouldn't be used in mods.
Built-in l10n contexts "Interface" and "Calendar" don't have the "OMW" prefix because these messages are more generic and can be reused in mods.
**Format**
Messages contents have the form of ICU MessageFormat strings.
See `the Formatting Messages chapter of the ICU Guide <https://unicode-org.github.io/icu/userguide/format_parse/messages/>`_
for a guide to MessageFormat, and see

View File

@ -287,3 +287,18 @@ the look of some particle systems.
Note that the rendering will act as if you have 'force shaders' option enabled.
This means that shaders will be used to render all objects and the terrain.
weather particle occlusion
--------------------------
:Type: boolean
:Range: True/False
:Default: False
Enables particle occlusion for rain and snow particle effects.
When enabled, rain and snow will not clip through ceilings and overhangs.
Currently this relies on an additional render pass, which may lead to a performance hit.
.. warning::
This is an experimental feature that may cause visual oddities, especially when using default rain settings.
It is recommended to at least double the rain diameter through `openmw.cfg`.`

View File

@ -20,53 +20,43 @@ set(BUILTIN_DATA_FILES
fonts/MysticCards.omwfont
fonts/MysticCardsFontLicense.txt
l10n/BuiltInShaders/de.yaml
l10n/BuiltInShaders/en.yaml
l10n/BuiltInShaders/ru.yaml
l10n/BuiltInShaders/sv.yaml
l10n/BuiltInShaders/fr.yaml
# Month names and date formatting
l10n/Calendar/de.yaml
l10n/Calendar/en.yaml
l10n/Calendar/ru.yaml
l10n/Calendar/sv.yaml
l10n/Calendar/fr.yaml
l10n/DebugMenu/de.yaml
l10n/DebugMenu/en.yaml
l10n/DebugMenu/ru.yaml
l10n/DebugMenu/sv.yaml
l10n/DebugMenu/fr.yaml
# Generic UI messages that can be reused by mods
l10n/Interface/de.yaml
l10n/Interface/en.yaml
l10n/Interface/ru.yaml
l10n/Interface/sv.yaml
l10n/Interface/fr.yaml
l10n/Navigation/de.yaml
l10n/Navigation/en.yaml
l10n/Navigation/ru.yaml
l10n/Navigation/sv.yaml
l10n/Navigation/fr.yaml
# L10n for scripts/omw
l10n/OMWCamera/de.yaml
l10n/OMWCamera/en.yaml
l10n/OMWCamera/ru.yaml
l10n/OMWCamera/sv.yaml
l10n/OMWCamera/fr.yaml
l10n/OMWControls/en.yaml
l10n/OMWControls/ru.yaml
l10n/OMWControls/sv.yaml
l10n/PostProcessing/de.yaml
l10n/PostProcessing/en.yaml
l10n/PostProcessing/ru.yaml
l10n/PostProcessing/sv.yaml
l10n/PostProcessing/fr.yaml
l10n/SavegameMenu/de.yaml
l10n/SavegameMenu/en.yaml
l10n/SavegameMenu/ru.yaml
l10n/SavegameMenu/sv.yaml
l10n/SavegameMenu/fr.yaml
l10n/SettingsMenu/de.yaml
l10n/SettingsMenu/en.yaml
l10n/SettingsMenu/ru.yaml
l10n/SettingsMenu/sv.yaml
l10n/SettingsMenu/fr.yaml
# L10n for OpenMW menus and non-game-specific messages
l10n/OMWEngine/de.yaml
l10n/OMWEngine/en.yaml
l10n/OMWEngine/ru.yaml
l10n/OMWEngine/sv.yaml
l10n/OMWEngine/fr.yaml
# L10n for post-processing HUD and built-in shaders
l10n/OMWShaders/de.yaml
l10n/OMWShaders/en.yaml
l10n/OMWShaders/ru.yaml
l10n/OMWShaders/sv.yaml
l10n/OMWShaders/fr.yaml
openmw_aux/util.lua
openmw_aux/time.lua

View File

@ -1,7 +0,0 @@
DisplayDepthName: "Visualisiert den Tiefenpuffer."
DisplayDepthFactorDescription: "Bestimmt die Korrelation zwischen dem Pixeltiefenwert und seiner Ausgabefarbe. Hohe Werte führen zu einem helleren Bild."
DisplayDepthFactorName: "Farbfaktor"
ContrastLevelDescription: "Kontraststufe"
ContrastLevelName: "Kontrast"
GammaLevelDescription: "Gamma-Level"
GammaLevelName: "Gamma"

View File

@ -1,4 +0,0 @@
DebugWindow: "Debug"
LogViewer: "Protokollansicht"
LuaProfiler: "Lua-Profiler"
PhysicsProfiler: "Physik-Profiler"

View File

@ -1,4 +0,0 @@
DebugWindow: "Debug"
LogViewer: "Log Viewer"
LuaProfiler: "Lua Profiler"
PhysicsProfiler: "Physics Profiler"

View File

@ -1,3 +0,0 @@
DebugWindow: "Fenêtre de débogage"
LogViewer: "Journal"
PhysicsProfiler: "Profileur des performances de la physique"

View File

@ -1,4 +0,0 @@
DebugWindow: "Меню отладки"
LogViewer: "Журнал логов"
LuaProfiler: "Профилировщик Луа"
PhysicsProfiler: "Профилировщик физики"

View File

@ -1,3 +0,0 @@
DebugWindow: "Felsökning"
LogViewer: "Loggvisare"
PhysicsProfiler: "Fysikprofilerare"

View File

@ -1 +0,0 @@
BuildingNavigationMesh: "Baue Navigationsgitter"

View File

@ -1 +0,0 @@
BuildingNavigationMesh: "Building navigation mesh"

View File

@ -1 +0,0 @@
BuildingNavigationMesh: "Construction du mesh de navigation"

View File

@ -1 +0,0 @@
BuildingNavigationMesh: "Построение навигационной сетки"

View File

@ -1 +0,0 @@
BuildingNavigationMesh: "Bygger navigeringsmesh"

View File

@ -0,0 +1,16 @@
ControlsPage: "Управление OpenMW"
ControlsPageDescription: "Дополнительные настройки, связанные с управлением игроком"
MovementSettings: "Движение"
alwaysRun: "Постоянный бег"
alwaysRunDescription: |
Когда эта настройка включена, по умолчанию персонаж бегает, в противном случае по умолчанию он ходит.
Клавиша бега (по умолчанию Shift) инвертирует режим временно, а клавиша постоянного бега (Caps Lock) переключает эту настройку.
toggleSneak: "Переключение движения крадучись"
toggleSneakDescription: |
Эта настройка меняет поведение клавиши движения крадучись (по умолчанию Ctrl):
чтобы красться, её достаточно нажать единожды для переключения положения, а не зажимать.
Игрокам, которые много времени крадутся, может быть проще управлять персонажем, когда опция включена.

View File

@ -1,3 +1,24 @@
# Debug window
DebugWindow: "Debug"
LogViewer: "Protokollansicht"
LuaProfiler: "Lua-Profiler"
PhysicsProfiler: "Physik-Profiler"
# Messages
BuildingNavigationMesh: "Baue Navigationsgitter"
# Save game menu
SelectCharacter: "Charakterauswahl..."
TimePlayed: "Spielzeit"
# Settings menu
ActorsProcessingRange: "Akteur-Verarbeitungsreichweite"
Anisotropy: "Anisotropie"
CameraSensitivity: "Kameraempfindlichkeit"

View File

@ -1,3 +1,24 @@
# Debug window
DebugWindow: "Debug"
LogViewer: "Log Viewer"
LuaProfiler: "Lua Profiler"
PhysicsProfiler: "Physics Profiler"
# Messages
BuildingNavigationMesh: "Building navigation mesh"
# Save game menu
SelectCharacter: "Select Character..."
TimePlayed: "Time played"
# Settings menu
ActorsProcessingRange: "Actors Processing Range"
Anisotropy: "Anisotropy"
CameraSensitivity: "Camera Sensitivity"
@ -62,6 +83,6 @@ WaterShaderTextureQuality: "Texture quality"
WindowBorder: "Window Border"
WindowMode: "Window Mode"
WindowModeFullscreen: "Fullscreen"
WindowModeHint: "Hint: the Windowed Fullscreen mode\nalways uses a native screen resolution."
WindowModeHint: "Hint: Windowed Fullscreen mode\nalways uses the native display resolution."
WindowModeWindowed: "Windowed"
WindowModeWindowedFullscreen: "Windowed Fullscreen"

View File

@ -1,3 +1,23 @@
# Debug window
DebugWindow: "Fenêtre de débogage"
LogViewer: "Journal"
PhysicsProfiler: "Profileur des performances de la physique"
# Messages
BuildingNavigationMesh: "Construction du mesh de navigation"
# Save game menu
SelectCharacter: "Sélection du personnage..."
TimePlayed: "Temps de jeu"
# Settings menu
ActorsProcessingRange: "Distance de traitement pour les personnages"
Anisotropy: "Anisotropie"
CameraSensitivity: "Sensibilité de la caméra"

View File

@ -1,3 +1,24 @@
# Debug window
DebugWindow: "Меню отладки"
LogViewer: "Журнал логов"
LuaProfiler: "Профилировщик Луа"
PhysicsProfiler: "Профилировщик физики"
# Messages
BuildingNavigationMesh: "Построение навигационной сетки"
# Save game menu
SelectCharacter: "Выберите персонажа..."
TimePlayed: "Время в игре"
# Settings menu
ActorsProcessingRange: "Дальность обработки персонажей"
Anisotropy: "Анизотропная фильтрация"
CameraSensitivity: "Чувствительность камеры"

View File

@ -1,3 +1,23 @@
# Debug window
DebugWindow: "Felsökning"
LogViewer: "Loggvisare"
PhysicsProfiler: "Fysikprofilerare"
# Messages
BuildingNavigationMesh: "Bygger navigeringsmesh"
# Save game menu
SelectCharacter: "Välj spelfigur..."
TimePlayed: "Speltid"
# Settings menu
ActorsProcessingRange: "Processavstånd för figurer"
Anisotropy: "Anisotropi"
CameraSensitivity: "Kamerakänslighet"

View File

@ -1,3 +1,5 @@
# Post-processing HUD
Abovewater: "Überwasser"
ActiveShaders: "Aktive Shader"
Author: "Autor"
@ -19,3 +21,14 @@ ShaderLockedDescription: "Kann nicht umgeschaltet oder verschoben werden, gesteu
ShaderResetUniform: "r"
Underwater: "Unterwasser"
Version: "Version"
# Built-in post-processing shaders
DisplayDepthName: "Visualisiert den Tiefenpuffer."
DisplayDepthFactorDescription: "Bestimmt die Korrelation zwischen dem Pixeltiefenwert und seiner Ausgabefarbe. Hohe Werte führen zu einem helleren Bild."
DisplayDepthFactorName: "Farbfaktor"
ContrastLevelDescription: "Kontraststufe"
ContrastLevelName: "Kontrast"
GammaLevelDescription: "Gamma-Level"
GammaLevelName: "Gamma"

View File

@ -1,3 +1,30 @@
# Post-processing HUD
Abovewater: "Abovewater"
ActiveShaders: "Active Shaders"
Author: "Author"
Description: "Description"
InactiveShaders: "Inactive Shaders"
InExteriors: "Exteriors"
InInteriors: "Interiors"
KeyboardControls: |
Keyboard controls:
Shift+Right-Arrow > Activate shader
Shift+Left-Arrow > Deactive shader
Shift+Up-Arrow > Move shader up
Shift+Down-Arrow > Move shader down
PostProcessHUD: "Postprocess HUD"
ResetShader: "Reset shader to default state"
ShaderLocked: "Locked"
ShaderLockedDescription: "Cannot be toggled or moved, controlled by external Lua script"
ShaderResetUniform: "r"
Underwater: "Underwater"
Version: "Version"
# Built-in post-processing shaders
AdjustmentsDescription: "Colour adjustments."
BloomDescription: "Bloom shader performing its calculations in (approximately) linear light."
DebugDescription: "Debug shader."

View File

@ -1,3 +1,30 @@
# Post-processing HUD
Abovewater: "Hors de l'eau"
ActiveShaders: "Shaders actifs"
Author: "Auteur(e)"
Description: "Description"
InactiveShaders: "Shaders inactifs"
InExteriors: "À l'extérieur"
InInteriors: "En intérieur"
KeyboardControls: |
Raccourcis clavier:
Majuscule+Flèche droite > Active le shader
Majuscule+Flèche gauche > Désactive le shader
Majuscule+Flèche haut > Monte le shader dans la liste
Majuscule+Flèche bas > Descend le shader dans la liste
MainPassDescription: "Transmet les données de la scène aux shaders de post-traitement. Ne peut être déplacé ou supprimé."
PostProcessHUD: "HUD de post-traitement"
ResetShader: "Restaure le shader dans sa configuration par défaut"
ShaderLocked: "Verrouillé"
ShaderResetUniform: "r"
Underwater: "Sous l'eau"
Version: "Version"
# Built-in post-processing shaders
AdjustmentsDescription: "Ajustements de l'image (couleurs, luminosité, contrastes...)."
BloomDescription: "Flou lumineux, calculé (approximativement) de façon linéaire suivant l'intensité de la lumière."
DebugDescription: "Shader de débogage."

View File

@ -1,3 +1,30 @@
# Post-processing HUD
Abovewater: "Над водой"
ActiveShaders: "Включенные шейдеры"
Author: "Автор"
Description: "Описание"
InactiveShaders: "Выключенные шейдеры"
InExteriors: "Вне помещений"
InInteriors: "В помещениях"
KeyboardControls: |
Управление с помощью клавиатуры:
Shift+Right-Arrow > Включить шейдер
Shift+Left-Arrow > Выключить шейдер
Shift+Up-Arrow > Передвинуть шейдер выше
Shift+Down-Arrow > Передвинуть шейдер ниже
PostProcessHUD: "Настройки постобработки"
ResetShader: "Обнулить настройки этого шейдера"
ShaderLocked: "Заблокирован"
ShaderLockedDescription: "Не может быть выключен или передвинут, управляется внешним Lua-скриптом"
ShaderResetUniform: "x"
Underwater: "Под водой"
Version: "Версия"
# Built-in post-processing shaders
AdjustmentsDescription: "Коррекция цвета."
DebugDescription: "Отладочный шейдер."
DebugHeaderDepth: "Буфер глубины"

View File

@ -1,3 +1,30 @@
# Post-processing HUD
Abovewater: "Ovan vatten"
ActiveShaders: "Aktiva shaders"
Author: "Skapare" # Author = Författare, but författare sounds very book-author-ish. Skapare, meaning "creator", sounds better in Swedish in this case. Ok?
Description: "Beskrivning"
ActiveShaders: "Inaktiva shaders"
InExteriors: "Exteriörer"
InInteriors: "Interiörer"
KeyboardControls: |
Tangentbordskontroller:
Shift+Högerpil > Aktivera shader
Shift+Vänsterpil > Avaktivera shader
Shift+Pil upp > Flytta shader upp
Shift+Pil ner > Flytta shader ner
PostProcessHUD: "Postprocess HUD"
ResetShader: "Återställ shader to ursprungligt läge"
ShaderLocked: "Låst"
ShaderLockedDescription: "Kan ej aktiveras/inaktiveras eller flyttas. Kontrolleras av externt Lua-skript"
ShaderResetUniform: "r"
Underwater: "Under vatten"
Version: "Version"
# Built-in post-processing shaders
AdjustmentsDescription: "Färgjusteringar."
BloomDescription: "Bloomshader som utför sina beräkningar i (ungefärligt) linjärt ljus."
DebugDescription: "Felsökningsshader."
@ -10,7 +37,7 @@ DisplayNormalsName: "Visualisera normalvektorer" # på engelska står det "pass
ContrastLevelDescription: "Kontrastnivå"
ContrastLevelName: "Kontrast"
GammaLevelDescription: "Gammanivå"
# GammaLevelName: "Gamma" samma som engelska
GammaLevelName: "Gamma" # samma som engelska
StrengthLevelName: "Styrka"
StrengthLevelDescription: "Effektens styrka."
RadiusLevelName: "Radie"

View File

@ -1,21 +0,0 @@
Abovewater: "Abovewater"
ActiveShaders: "Active Shaders"
Author: "Author"
Description: "Description"
InactiveShaders: "Inactive Shaders"
InExteriors: "Exteriors"
InInteriors: "Interiors"
KeyboardControls: |
Keyboard controls:
Shift+Right-Arrow > Activate shader
Shift+Left-Arrow > Deactive shader
Shift+Up-Arrow > Move shader up
Shift+Down-Arrow > Move shader down
PostProcessHUD: "Postprocess HUD"
ResetShader: "Reset shader to default state"
ShaderLocked: "Locked"
ShaderLockedDescription: "Cannot be toggled or moved, controlled by external Lua script"
ShaderResetUniform: "r"
Underwater: "Underwater"
Version: "Version"

View File

@ -1,21 +0,0 @@
Abovewater: "Hors de l'eau"
ActiveShaders: "Shaders actifs"
Author: "Auteur(e)"
Description: "Description"
InactiveShaders: "Shaders inactifs"
InExteriors: "À l'extérieur"
InInteriors: "En intérieur"
KeyboardControls: |
Raccourcis clavier:
Majuscule+Flèche droite > Active le shader
Majuscule+Flèche gauche > Désactive le shader
Majuscule+Flèche haut > Monte le shader dans la liste
Majuscule+Flèche bas > Descend le shader dans la liste
MainPassDescription: "Transmet les données de la scène aux shaders de post-traitement. Ne peut être déplacé ou supprimé."
PostProcessHUD: "HUD de post-traitement"
ResetShader: "Restaure le shader dans sa configuration par défaut"
ShaderLocked: "Verrouillé"
ShaderResetUniform: "r"
Underwater: "Sous l'eau"
Version: "Version"

View File

@ -1,21 +0,0 @@
Abovewater: "Над водой"
ActiveShaders: "Включенные шейдеры"
Author: "Автор"
Description: "Описание"
InactiveShaders: "Выключенные шейдеры"
InExteriors: "Вне помещений"
InInteriors: "В помещениях"
KeyboardControls: |
Управление с помощью клавиатуры:
Shift+Right-Arrow > Включить шейдер
Shift+Left-Arrow > Выключить шейдер
Shift+Up-Arrow > Передвинуть шейдер выше
Shift+Down-Arrow > Передвинуть шейдер ниже
PostProcessHUD: "Настройки постобработки"
ResetShader: "Обнулить настройки этого шейдера"
ShaderLocked: "Заблокирован"
ShaderLockedDescription: "Не может быть выключен или передвинут, управляется внешним Lua-скриптом"
ShaderResetUniform: "x"
Underwater: "Под водой"
Version: "Версия"

View File

@ -1,22 +0,0 @@
Abovewater: "Ovan vatten"
ActiveShaders: "Aktiva shaders"
Author: "Skapare" # Author = Författare, but författare sounds very book-author-ish. Skapare, meaning "creator", sounds better in Swedish in this case. Ok?
Description: "Beskrivning"
ActiveShaders: "Inaktiva shaders"
InExteriors: "Exteriörer"
InInteriors: "Interiörer"
KeyboardControls: |
Tangentbordskontroller:
Shift+Högerpil > Aktivera shader
Shift+Vänsterpil > Avaktivera shader
Shift+Pil upp > Flytta shader upp
Shift+Pil ner > Flytta shader ner
PostProcessHUD: "Postprocess HUD"
ResetShader: "Återställ shader to ursprungligt läge"
ShaderLocked: "Låst"
ShaderLockedDescription: "Kan ej aktiveras/inaktiveras eller flyttas. Kontrolleras av externt Lua-skript"
ShaderResetUniform: "r"
Underwater: "Under vatten"
Version: "Version"

View File

@ -1,2 +0,0 @@
SelectCharacter: "Charakterauswahl..."
TimePlayed: "Spielzeit"

View File

@ -1,2 +0,0 @@
SelectCharacter: "Select Character..."
TimePlayed: "Time played"

View File

@ -1,2 +0,0 @@
SelectCharacter: "Sélection du personnage..."
TimePlayed: "Temps de jeu"

View File

@ -1,2 +0,0 @@
SelectCharacter: "Выберите персонажа..."
TimePlayed: "Время в игре"

View File

@ -1,2 +0,0 @@
SelectCharacter: "Välj spelfigur..."
TimePlayed: "Speltid"

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Window" position="0 0 400 400" layer="Debug" name="_Main" align="Stretch">
<Property key="Caption" value="#{DebugMenu:DebugWindow}"/>
<Property key="Caption" value="#{OMWEngine:DebugWindow}"/>
<Property key="Visible" value="false"/>
<Widget type="Widget" skin="DialogBG" position_real="0 0 1 1" name="Background" align="Stretch">

View File

@ -2,7 +2,7 @@
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Window" position="0 0 500 500" layer="Debug" name="_Main" align="Stretch">
<Property key="Visible" value="false"/>
<Property key="Caption" value="#{PostProcessing:PostProcessHUD}"/>
<Property key="Caption" value="#{OMWShaders:PostProcessHUD}"/>
<Property key="MinSize" value="600 600"/>
<Widget type="TabControl" skin="TabControl_NoBorder" position="8 8 468 450" align="Stretch" name="TabControl">
@ -12,7 +12,7 @@
<Property key="Caption" value="[?]"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="TextToolTip"/>
<UserString key="Caption_Text" value="#{PostProcessing:KeyboardControls}"/>
<UserString key="Caption_Text" value="#{OMWShaders:KeyboardControls}"/>
<Property key="Depth" value="-10"/>
</Widget>
@ -34,7 +34,7 @@
<Widget type="VBox" position_real="0 0 1 1" align="Stretch">
<Widget type="AutoSizedTextBox" skin="NormalText" position="0 0 50 50" align="Top Right">
<Property key="Caption" value="#{PostProcessing:InactiveShaders}"/>
<Property key="Caption" value="#{OMWShaders:InactiveShaders}"/>
</Widget>
<Widget type="EditBox" skin="MW_TextBoxEditWithBorder" position="0 0 0 28" name="Filter">
@ -80,7 +80,7 @@
<Widget type="VBox" position_real="0 0 1 1" align="Stretch">
<Widget type="AutoSizedTextBox" skin="NormalText" position="0 0 50 50" align="Top Right">
<Property key="Caption" value="#{PostProcessing:ActiveShaders}"/>
<Property key="Caption" value="#{OMWShaders:ActiveShaders}"/>
</Widget>
<Widget type="ListWrapper" skin="MW_List" name="ActiveList">

View File

@ -59,7 +59,7 @@
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 22 22" name="Reset">
<UserString key="HStretch" value="false"/>
<UserString key="VStretch" value="false"/>
<Property key="Caption" value="#{PostProcessing:ShaderResetUniform}"/>
<Property key="Caption" value="#{OMWShaders:ShaderResetUniform}"/>
</Widget>
<Widget type="Widget" skin="BlackBG" position="0 0 225 22" name="Client">
<UserString key="HStretch" value="false"/>

View File

@ -6,7 +6,7 @@
<Property key="Spacing" value="8"/>
<Widget type="ComboBox" skin="MW_ComboBox" position="0 0 0 24" name="SelectCharacter">
<Property key="Caption" value="#{SavegameMenu:SelectCharacter}"/>
<Property key="Caption" value="#{OMWEngine:SelectCharacter}"/>
<UserString key="HStretch" value="true"/>
</Widget>

View File

@ -75,7 +75,7 @@
</Widget>
<Widget type="Widget" position="4 184 400 54" align="Left Top HStretch">
<Widget type="TextBox" skin="NormalText" position="0 0 400 16" align="Left Top" name="ActorProcessingText">
<Property key="Caption" value="#{SettingsMenu:ActorsProcessingRange}"/>
<Property key="Caption" value="#{OMWEngine:ActorsProcessingRange}"/>
</Widget>
<Widget type="ScrollBar" skin="MW_HScroll" position="0 20 352 14" align="Left Top HStretch">
<Property key="Range" value="3584"/>
@ -87,7 +87,7 @@
<UserString key="SettingMin" value="3584"/>
<UserString key="SettingMax" value="7168"/>
<UserString key="SettingLabelWidget" value="ActorProcessingText"/>
<UserString key="SettingLabelCaption" value="#{SettingsMenu:ActorsProcessingRange} (%s)"/>
<UserString key="SettingLabelCaption" value="#{OMWEngine:ActorsProcessingRange} (%s)"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="0 38 352 16" align="Left Top">
<Property key="Caption" value="#{sLow}"/>
@ -204,10 +204,10 @@
<Property key="Padding" value="0"/>
<Property key="Spacing" value="4"/>
<Widget type="AutoSizedButton" skin="MW_Button" name="KeyboardButton">
<Property key="Caption" value="#{SettingsMenu:MouseAndKeyboard}"/>
<Property key="Caption" value="#{OMWEngine:MouseAndKeyboard}"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" name="ControllerButton">
<Property key="Caption" value="#{SettingsMenu:Controller}"/>
<Property key="Caption" value="#{OMWEngine:Controller}"/>
</Widget>
</Widget>
@ -226,7 +226,7 @@
<UserString key="SettingType" value="CheckButton"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText">
<Property key="Caption" value="#{SettingsMenu:InvertXAxis} "/>
<Property key="Caption" value="#{OMWEngine:InvertXAxis} "/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button">
<UserString key="SettingCategory" value="Input"/>
@ -238,7 +238,7 @@
</Widget>
</Widget>
<Widget type="TextBox" skin="NormalText" position="4 258 352 18" align="Left Bottom">
<Property key="Caption" value="#{SettingsMenu:CameraSensitivity}"/>
<Property key="Caption" value="#{OMWEngine:CameraSensitivity}"/>
</Widget>
<Widget type="ScrollBar" skin="MW_HScroll" position="4 282 352 18" align="HStretch Bottom">
<Property key="Range" value="10000"/>
@ -277,13 +277,13 @@
<Property key="Caption" value=" #{sVideo} "/>
<Widget type="ListBox" skin="MW_List" position="0 4 185 225" align="Left Top" name="ResolutionList"/>
<Widget type="TextBox" skin="NormalText" position="197 4 185 18" align="Left Top">
<Property key="Caption" value="#{SettingsMenu:WindowMode}"/>
<Property key="Caption" value="#{OMWEngine:WindowMode}"/>
</Widget>
<Widget type="HBox" position="197 28 400 24">
<Widget type="ComboBox" skin="MW_ComboBox" position="0 0 200 24" align="Left Top" name="WindowModeList">
<Property key="AddItem" value="#{SettingsMenu:WindowModeFullscreen}"/>
<Property key="AddItem" value="#{SettingsMenu:WindowModeWindowedFullscreen}"/>
<Property key="AddItem" value="#{SettingsMenu:WindowModeWindowed}"/>
<Property key="AddItem" value="#{OMWEngine:WindowModeFullscreen}"/>
<Property key="AddItem" value="#{OMWEngine:WindowModeWindowedFullscreen}"/>
<Property key="AddItem" value="#{OMWEngine:WindowModeWindowed}"/>
</Widget>
</Widget>
<Widget type="HBox" position="197 58 400 28">
@ -293,7 +293,7 @@
<UserString key="SettingType" value="CheckButton"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" position="28 4 48 16" align="Left Top">
<Property key="Caption" value="#{SettingsMenu:VSync}"/>
<Property key="Caption" value="#{OMWEngine:VSync}"/>
</Widget>
</Widget>
<Widget type="HBox" position="197 88 300 28">
@ -303,7 +303,7 @@
<UserString key="SettingType" value="CheckButton"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" position="28 4 48 16" align="Left Top">
<Property key="Caption" value="#{SettingsMenu:WindowBorder}"/>
<Property key="Caption" value="#{OMWEngine:WindowBorder}"/>
</Widget>
</Widget>
<Widget type="HBox" position="197 118 300 28">
@ -313,15 +313,15 @@
<UserString key="SettingType" value="CheckButton"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" position="28 4 48 16" align="Left Top">
<Property key="Caption" value="#{SettingsMenu:PostProcessing}"/>
<Property key="Caption" value="#{OMWEngine:PostProcessing}"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="TextToolTip"/>
<UserString key="Caption_Text" value="#{SettingsMenu:PostProcessingTooltip}"/>
<UserString key="Caption_Text" value="#{OMWEngine:PostProcessingTooltip}"/>
</Widget>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" position="197 154 300 32" align="Left Top">
<Property key="Caption" value="#{SettingsMenu:FrameRateHint}"/>
<Property key="Caption" value="#{OMWEngine:FrameRateHint}"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" position="197 196 300 32" align="Left Top" name="WindowModeHint">
<Property key="Caption" value="#{SettingsMenu:WindowModeHint}"/>
@ -339,7 +339,7 @@
<UserString key="SettingMin" value="30"/>
<UserString key="SettingMax" value="110"/>
<UserString key="SettingLabelWidget" value="FovText"/>
<UserString key="SettingLabelCaption" value="#{SettingsMenu:FieldOfView} (%s)"/>
<UserString key="SettingLabelCaption" value="#{OMWEngine:FieldOfView} (%s)"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="0 286 352 18" align="Left Top">
<Property key="Caption" value="#{sLow}"/>
@ -375,17 +375,17 @@
<Property key="Caption" value=" #{sDetail_Level} "/>
<Widget type="AutoSizedTextBox" skin="NormalText" align="Left Top">
<Property key="Caption" value="#{SettingsMenu:TextureFiltering}"/>
<Property key="Caption" value="#{OMWEngine:TextureFiltering}"/>
<UserString key="VStretch" value="false"/>
<UserString key="HStretch" value="false"/>
</Widget>
<Widget type="ComboBox" align="Left Top" skin="MW_ComboBox" position="0 28 200 24" name="TextureFilteringButton">
<Property key="AddItem" value="#{SettingsMenu:TextureFilteringBilinear}"/>
<Property key="AddItem" value="#{SettingsMenu:TextureFilteringTrilinear}"/>
<Property key="AddItem" value="#{OMWEngine:TextureFilteringBilinear}"/>
<Property key="AddItem" value="#{OMWEngine:TextureFilteringTrilinear}"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="NormalText" position="0 58 200 18" name="AnisotropyLabel">
<Property key="Caption" value="#{SettingsMenu:Anisotropy}"/>
<Property key="Caption" value="#{OMWEngine:Anisotropy}"/>
</Widget>
<Widget type="ScrollBar" skin="MW_HScroll" position="0 80 352 18" align="HStretch Top">
<Property key="Range" value="17"/>
@ -394,7 +394,7 @@
<UserString key="SettingCategory" value="General"/>
<UserString key="SettingName" value="anisotropy"/>
<UserString key="SettingLabelWidget" value="AnisotropyLabel"/>
<UserString key="SettingLabelCaption" value="#{SettingsMenu:Anisotropy} (%s)"/>
<UserString key="SettingLabelCaption" value="#{OMWEngine:Anisotropy} (%s)"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="NormalText" position="0 104 0 18" align="Left Top" name="RenderDistanceLabel">
@ -435,7 +435,7 @@
</Widget>
<Widget type="TabItem">
<Property key="Caption" value=" #{SettingsMenu:Water} "/>
<Property key="Caption" value=" #{OMWEngine:Water} "/>
<Widget type="VBox" position_real="0 0 1 1" align="Stretch">
@ -449,7 +449,7 @@
<UserString key="SettingType" value="CheckButton"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText">
<Property key="Caption" value="#{SettingsMenu:WaterShader}"/>
<Property key="Caption" value="#{OMWEngine:WaterShader}"/>
</Widget>
</Widget>
@ -463,14 +463,14 @@
<UserString key="SettingType" value="CheckButton"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText">
<Property key="Caption" value="#{SettingsMenu:Refraction}"/>
<Property key="Caption" value="#{OMWEngine:Refraction}"/>
</Widget>
</Widget>
<Widget type="Widget" position="0 0 0 18" align="Top Left HStretch">
<UserString key="HStretch" value="true"/>
<Widget type="AutoSizedTextBox" skin="NormalText">
<Property key="Caption" value="#{SettingsMenu:WaterShaderTextureQuality}"/>
<Property key="Caption" value="#{OMWEngine:WaterShaderTextureQuality}"/>
</Widget>
<Widget type="Spacer" />
</Widget>
@ -489,7 +489,7 @@
<Widget type="Widget" position="0 0 0 18" align="Top Left HStretch">
<UserString key="HStretch" value="true"/>
<Widget type="AutoSizedTextBox" skin="NormalText">
<Property key="Caption" value="#{SettingsMenu:ReflectionShaderDetail}"/>
<Property key="Caption" value="#{OMWEngine:ReflectionShaderDetail}"/>
</Widget>
<Widget type="Spacer" />
</Widget>
@ -498,12 +498,12 @@
<UserString key="VStretch" value="false"/>
<Widget type="ComboBox" skin="MW_ComboBox" position="0 0 200 24" align="Left Top" name="WaterReflectionDetail">
<Property key="AddItem" value="#{SettingsMenu:ReflectionShaderDetailSky}"/>
<Property key="AddItem" value="#{SettingsMenu:ReflectionShaderDetailTerrain}"/>
<Property key="AddItem" value="#{SettingsMenu:ReflectionShaderDetailWorld}"/>
<Property key="AddItem" value="#{SettingsMenu:ReflectionShaderDetailObjects}"/>
<Property key="AddItem" value="#{SettingsMenu:ReflectionShaderDetailActors}"/>
<Property key="AddItem" value="#{SettingsMenu:ReflectionShaderDetailGroundcover}"/>
<Property key="AddItem" value="#{OMWEngine:ReflectionShaderDetailSky}"/>
<Property key="AddItem" value="#{OMWEngine:ReflectionShaderDetailTerrain}"/>
<Property key="AddItem" value="#{OMWEngine:ReflectionShaderDetailWorld}"/>
<Property key="AddItem" value="#{OMWEngine:ReflectionShaderDetailObjects}"/>
<Property key="AddItem" value="#{OMWEngine:ReflectionShaderDetailActors}"/>
<Property key="AddItem" value="#{OMWEngine:ReflectionShaderDetailGroundcover}"/>
</Widget>
<Widget type="Spacer" />
</Widget>
@ -511,7 +511,7 @@
<Widget type="Widget" position="0 0 0 18" align="Top Left HStretch">
<UserString key="HStretch" value="true"/>
<Widget type="AutoSizedTextBox" skin="NormalText">
<Property key="Caption" value="#{SettingsMenu:RainRippleDetail}"/>
<Property key="Caption" value="#{OMWEngine:RainRippleDetail}"/>
</Widget>
<Widget type="Spacer" />
</Widget>
@ -521,9 +521,9 @@
<UserString key="VStretch" value="false"/>
<Widget type="ComboBox" skin="MW_ComboBox" position="0 0 200 24" align="Left Top" name="WaterRainRippleDetail">
<Property key="AddItem" value="#{SettingsMenu:RainRippleDetailSimple}"/>
<Property key="AddItem" value="#{SettingsMenu:RainRippleDetailSparse}"/>
<Property key="AddItem" value="#{SettingsMenu:RainRippleDetailDense}"/>
<Property key="AddItem" value="#{OMWEngine:RainRippleDetailSimple}"/>
<Property key="AddItem" value="#{OMWEngine:RainRippleDetailSparse}"/>
<Property key="AddItem" value="#{OMWEngine:RainRippleDetailDense}"/>
</Widget>
<Widget type="Spacer" />
</Widget>
@ -532,10 +532,10 @@
</Widget>
<Widget type="TabItem">
<Property key="Caption" value=" #{SettingsMenu:Lights} "/>
<Property key="Caption" value=" #{OMWEngine:Lights} "/>
<!-- Lighting Method -->
<Widget type="TextBox" skin="NormalText" position="0 4 250 18" align="Left Top">
<Property key="Caption" value="#{SettingsMenu:LightingMethod}"/>
<Property key="Caption" value="#{OMWEngine:LightingMethod}"/>
</Widget>
<Widget type="ComboBox" skin="MW_ComboBox" position="0 28 250 24" align="Left Top" name="LightingMethodButton">
<Property key="AddItem" value="legacy"/>
@ -546,7 +546,7 @@
<Widget type="TextBox" skin="NormalText" position="258 4 350 18" align="Left Top" name="MaxLightsText">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="TextToolTip"/>
<UserString key="Caption_Text" value="#{SettingsMenu:MaxLightsTooltip}"/>
<UserString key="Caption_Text" value="#{OMWEngine:MaxLightsTooltip}"/>
</Widget>
<Widget type="ScrollBar" position="0 0 0 0">
<UserString key="SettingType" value="Slider"/>
@ -554,7 +554,7 @@
<UserString key="SettingName" value="max lights"/>
<UserString key="SettingValueType" value="Integer"/>
<UserString key="SettingLabelWidget" value="MaxLightsText"/>
<UserString key="SettingLabelCaption" value="#{SettingsMenu:MaxLights} (%s)"/>
<UserString key="SettingLabelCaption" value="#{OMWEngine:MaxLights} (%s)"/>
</Widget>
<Widget type="ComboBox" skin="MW_ComboBox" position="258 28 250 24" align="Left Top" name="MaxLights">
<Property key="AddItem" value="8"/>
@ -567,7 +567,7 @@
<Widget type="TextBox" skin="NormalText" position="0 78 500 18" align="Left Top" name="MaxLightDistanceText">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="TextToolTip"/>
<UserString key="Caption_Text" value="#{SettingsMenu:LightsMaximumDistanceTooltip}"/>
<UserString key="Caption_Text" value="#{OMWEngine:LightsMaximumDistanceTooltip}"/>
</Widget>
<Widget type="ScrollBar" skin="MW_HScroll" position="0 104 352 18" align="HStretch Top">
<Property key="Range" value="8192"/>
@ -579,13 +579,13 @@
<UserString key="SettingName" value="maximum light distance"/>
<UserString key="SettingValueType" value="Integer"/>
<UserString key="SettingLabelWidget" value="MaxLightDistanceText"/>
<UserString key="SettingLabelCaption" value="#{SettingsMenu:LightsMaximumDistance} (%s)"/>
<UserString key="SettingLabelCaption" value="#{OMWEngine:LightsMaximumDistance} (%s)"/>
</Widget>
<!-- Light Fade Multiplier -->
<Widget type="TextBox" skin="NormalText" position="0 128 500 18" align="Left Top" name="LightFadeMultiplierText">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="TextToolTip"/>
<UserString key="Caption_Text" value="#{SettingsMenu:LightsFadeStartMultiplierTooltip}"/>
<UserString key="Caption_Text" value="#{OMWEngine:LightsFadeStartMultiplierTooltip}"/>
</Widget>
<Widget type="ScrollBar" skin="MW_HScroll" position="0 152 352 18" align="HStretch Top">
<Property key="Range" value="10000"/>
@ -597,13 +597,13 @@
<UserString key="SettingMin" value="0.0"/>
<UserString key="SettingMax" value="1.0"/>
<UserString key="SettingLabelWidget" value="LightFadeMultiplierText"/>
<UserString key="SettingLabelCaption" value="#{SettingsMenu:LightsFadeStartMultiplier} (%s)"/>
<UserString key="SettingLabelCaption" value="#{OMWEngine:LightsFadeStartMultiplier} (%s)"/>
</Widget>
<!-- Bounding Sphere Multiplier -->
<Widget type="TextBox" skin="NormalText" position="0 176 500 18" align="Left Top" name="BoundingSphereMultText">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="TextToolTip"/>
<UserString key="Caption_Text" value="#{SettingsMenu:LightsBoundingSphereMultiplierTooltip}"/>
<UserString key="Caption_Text" value="#{OMWEngine:LightsBoundingSphereMultiplierTooltip}"/>
</Widget>
<Widget type="ScrollBar" skin="MW_HScroll" position="0 200 352 18" align="HStretch Top">
<Property key="Range" value="500000"/>
@ -615,13 +615,13 @@
<UserString key="SettingName" value="light bounds multiplier"/>
<UserString key="SettingValueType" value="Float"/>
<UserString key="SettingLabelWidget" value="BoundingSphereMultText"/>
<UserString key="SettingLabelCaption" value="#{SettingsMenu:LightsBoundingSphereMultiplier} (%s)"/>
<UserString key="SettingLabelCaption" value="#{OMWEngine:LightsBoundingSphereMultiplier} (%s)"/>
</Widget>
<!-- Minimum Ambient Brightness -->
<Widget type="TextBox" skin="NormalText" position="0 224 500 18" align="Left Top" name="MinimumBrightnessText">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="TextToolTip"/>
<UserString key="Caption_Text" value="#{SettingsMenu:LightsMinimumInteriorBrightnessTooltip}"/>
<UserString key="Caption_Text" value="#{OMWEngine:LightsMinimumInteriorBrightnessTooltip}"/>
</Widget>
<Widget type="ScrollBar" skin="MW_HScroll" position="0 248 352 18" align="HStretch Top">
<Property key="Range" value="10000"/>
@ -631,7 +631,7 @@
<UserString key="SettingName" value="minimum interior brightness"/>
<UserString key="SettingValueType" value="Float"/>
<UserString key="SettingLabelWidget" value="MinimumBrightnessText"/>
<UserString key="SettingLabelCaption" value="#{SettingsMenu:LightsMinimumInteriorBrightness} (%s)"/>
<UserString key="SettingLabelCaption" value="#{OMWEngine:LightsMinimumInteriorBrightness} (%s)"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="0 290 0 0" align="Top Left" name="LightsResetButton">
<Property key="Caption" value="#{sControlsMenu1}"/>
@ -640,10 +640,10 @@
</Widget>
</Widget>
<Widget type="TabItem">
<Property key="Caption" value=" #{SettingsMenu:Scripts} "/>
<Property key="Caption" value=" #{OMWEngine:Scripts} "/>
<Widget name="ScriptDisabled" type="EditBox" skin="SandText" position_real="0 0 1 1" align="HStretch Top">
<Property key="Caption" value="#{SettingsMenu:ScriptsDisabled}"/>
<Property key="Caption" value="#{OMWEngine:ScriptsDisabled}"/>
<Property key="TextAlign" value="Center"/>
<Property key="MultiLine" value="true"/>
<Property key="WordWrap" value="true"/>
@ -681,24 +681,24 @@
</Widget>
<Widget type="TabItem">
<Property key="Caption" value=" #{SettingsMenu:Language} "/>
<Property key="Caption" value=" #{OMWEngine:Language} "/>
<Widget type="AutoSizedTextBox" skin="SandText" position="4 4 300 32" align="Left Top">
<Property key="Caption" value="#{SettingsMenu:LanguageNote}"/>
<Property key="Caption" value="#{OMWEngine:LanguageNote}"/>
</Widget>
<!-- Primary Language -->
<Widget type="TextBox" skin="NormalText" position="4 28 250 18" align="Left Top">
<Property key="Caption" value="#{SettingsMenu:PrimaryLanguage}"/>
<Property key="Caption" value="#{OMWEngine:PrimaryLanguage}"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="TextToolTip"/>
<UserString key="Caption_Text" value="#{SettingsMenu:PrimaryLanguageTooltip}"/>
<UserString key="Caption_Text" value="#{OMWEngine:PrimaryLanguageTooltip}"/>
</Widget>
<Widget type="ComboBox" skin="MW_ComboBox" position="4 52 250 24" align="Left Top" name="PrimaryLanguage" />
<!-- Secondary Language -->
<Widget type="TextBox" skin="NormalText" position="262 28 250 18" align="Left Top">
<Property key="Caption" value="#{SettingsMenu:SecondaryLanguage}"/>
<Property key="Caption" value="#{OMWEngine:SecondaryLanguage}"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="TextToolTip"/>
<UserString key="Caption_Text" value="#{SettingsMenu:SecondaryLanguageTooltip}"/>
<UserString key="Caption_Text" value="#{OMWEngine:SecondaryLanguageTooltip}"/>
</Widget>
<Widget type="ComboBox" skin="MW_ComboBox" position="262 52 250 24" align="Left Top" name="SecondaryLanguage" />
</Widget>

View File

@ -3,8 +3,8 @@ uniform_float uGamma {
step = 0.01;
min = 0.0;
max = 5.0;
display_name = "#{BuiltInShaders:GammaLevelName}";
description = "#{BuiltInShaders:GammaLevelDescription}";
display_name = "#{OMWShaders:GammaLevelName}";
description = "#{OMWShaders:GammaLevelDescription}";
}
uniform_float uContrast {
@ -12,8 +12,8 @@ uniform_float uContrast {
step = 0.01;
min = 0.0;
max = 5.0;
display_name = "#{BuiltInShaders:ContrastLevelName}";
description = "#{BuiltInShaders:ContrastLevelDescription}";
display_name = "#{OMWShaders:ContrastLevelName}";
description = "#{OMWShaders:ContrastLevelDescription}";
}
fragment main {
@ -31,7 +31,7 @@ fragment main {
}
technique {
description = "#{BuiltInShaders:AdjustmentsDescription}";
description = "#{OMWShaders:AdjustmentsDescription}";
version = "1.0";
author = "OpenMW";
passes = main;

View File

@ -3,48 +3,48 @@ uniform_float uGamma {
min = 0.1;
max = 4.0;
step = 0.01;
display_name = "#{BuiltInShaders:GammaLevelName}";
description = "#{BuiltInShaders:GammaLevelDescription}";
display_name = "#{OMWShaders:GammaLevelName}";
description = "#{OMWShaders:GammaLevelDescription}";
}
uniform_float uThreshold {
default = 0.35;
min = 0.0;
max = 1.0;
step = 0.01;
display_name = "#{BuiltInShaders:BloomThresholdLevelName}";
description = "#{BuiltInShaders:BloomThresholdLevelDescription}";
display_name = "#{OMWShaders:BloomThresholdLevelName}";
description = "#{OMWShaders:BloomThresholdLevelDescription}";
}
uniform_float uClamp {
default = 1.0;
min = 0.0;
max = 1.0;
step = 0.01;
display_name = "#{BuiltInShaders:BloomClampLevelName}";
description = "#{BuiltInShaders:BloomClampLevelDescription}";
display_name = "#{OMWShaders:BloomClampLevelName}";
description = "#{OMWShaders:BloomClampLevelDescription}";
}
uniform_float uSkyFactor {
default = 0.5;
min = 0.0;
max = 2.0;
step = 0.01;
display_name = "#{BuiltInShaders:SkyFactorLevelName}";
description = "#{BuiltInShaders:SkyFactorLevelDescription}";
display_name = "#{OMWShaders:SkyFactorLevelName}";
description = "#{OMWShaders:SkyFactorLevelDescription}";
}
uniform_float uRadius {
default = 0.5;
min = 0.0;
max = 1.0;
step = 0.01;
display_name = "#{BuiltInShaders:RadiusLevelName}";
description = "#{BuiltInShaders:RadiusLevelDescription}";
display_name = "#{OMWShaders:RadiusLevelName}";
description = "#{OMWShaders:RadiusLevelDescription}";
}
uniform_float uStrength {
default = 0.25;
min = 0.0;
max = 1.0;
step = 0.01;
display_name = "#{BuiltInShaders:StrengthLevelName}";
description = "#{BuiltInShaders:StrengthLevelDescription}";
display_name = "#{OMWShaders:StrengthLevelName}";
description = "#{OMWShaders:StrengthLevelDescription}";
}
shared {
@ -215,7 +215,7 @@ fragment final(rt1=RT_Vertical) {
technique {
passes = nomipmap, horizontal, vertical, final;
description = "#{BuiltInShaders:BloomDescription}";
description = "#{OMWShaders:BloomDescription}";
author = "OpenMW";
version = "1.0";
}

View File

@ -1,7 +1,7 @@
uniform_bool uDisplayDepth {
header = "#{BuiltInShaders:DebugHeaderDepth}";
header = "#{OMWShaders:DebugHeaderDepth}";
default = true;
display_name = "#{BuiltInShaders:DisplayDepthName}";
display_name = "#{OMWShaders:DisplayDepthName}";
}
uniform_float uDepthFactor {
@ -9,14 +9,14 @@ uniform_float uDepthFactor {
min = 0.01;
max = 20.0;
default = 1.0;
display_name = "#{BuiltInShaders:DisplayDepthFactorName}";
description = "#{BuiltInShaders:DisplayDepthFactorDescription}";
display_name = "#{OMWShaders:DisplayDepthFactorName}";
description = "#{OMWShaders:DisplayDepthFactorDescription}";
}
uniform_bool uDisplayNormals {
header = "#{BuiltInShaders:DebugHeaderNormals}";
header = "#{OMWShaders:DebugHeaderNormals}";
default = true;
display_name = "#{BuiltInShaders:DisplayNormalsName}";
display_name = "#{OMWShaders:DisplayNormalsName}";
}
fragment main {
@ -38,7 +38,7 @@ fragment main {
technique {
passes = main;
description = "#{BuiltInShaders:DebugDescription}";
description = "#{OMWShaders:DebugDescription}";
author = "OpenMW";
version = "1.0";
pass_normals = true;

Some files were not shown because too many files have changed in this diff Show More