mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-19 19:11:32 +00:00
Merge branch 'master' of gitlab.com:openmw/openmw into lua_record_services
This commit is contained in:
commit
f287b2f436
59 changed files with 1835 additions and 932 deletions
|
@ -70,6 +70,7 @@
|
||||||
Bug #7472: Crash when enchanting last projectiles
|
Bug #7472: Crash when enchanting last projectiles
|
||||||
Bug #7505: Distant terrain does not support sample size greater than cell size
|
Bug #7505: Distant terrain does not support sample size greater than cell size
|
||||||
Bug #7553: Faction reaction loading is incorrect
|
Bug #7553: Faction reaction loading is incorrect
|
||||||
|
Bug #7557: Terrain::ChunkManager::createChunk is called twice for the same position, lod on initial loading
|
||||||
Feature #3537: Shader-based water ripples
|
Feature #3537: Shader-based water ripples
|
||||||
Feature #5492: Let rain and snow collide with statics
|
Feature #5492: Let rain and snow collide with statics
|
||||||
Feature #6149: Dehardcode Lua API_REVISION
|
Feature #6149: Dehardcode Lua API_REVISION
|
||||||
|
@ -77,6 +78,7 @@
|
||||||
Feature #6491: Add support for Qt6
|
Feature #6491: Add support for Qt6
|
||||||
Feature #6556: Lua API for sounds
|
Feature #6556: Lua API for sounds
|
||||||
Feature #6726: Lua API for creating new objects
|
Feature #6726: Lua API for creating new objects
|
||||||
|
Feature #6864: Lua file access API
|
||||||
Feature #6922: Improve launcher appearance
|
Feature #6922: Improve launcher appearance
|
||||||
Feature #6933: Support high-resolution cursor textures
|
Feature #6933: Support high-resolution cursor textures
|
||||||
Feature #6945: Support S3TC-compressed and BGR/BGRA NiPixelData
|
Feature #6945: Support S3TC-compressed and BGR/BGRA NiPixelData
|
||||||
|
|
|
@ -71,7 +71,7 @@ message(STATUS "Configuring OpenMW...")
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 49)
|
set(OPENMW_VERSION_MINOR 49)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
set(OPENMW_LUA_API_REVISION 45)
|
set(OPENMW_LUA_API_REVISION 46)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
set(OPENMW_VERSION_TAGHASH "")
|
set(OPENMW_VERSION_TAGHASH "")
|
||||||
|
|
|
@ -61,7 +61,7 @@ add_openmw_dir (mwscript
|
||||||
add_openmw_dir (mwlua
|
add_openmw_dir (mwlua
|
||||||
luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant
|
luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant
|
||||||
context globalscripts localscripts playerscripts luabindings objectbindings cellbindings mwscriptbindings
|
context globalscripts localscripts playerscripts luabindings objectbindings cellbindings mwscriptbindings
|
||||||
camerabindings uibindings soundbindings inputbindings nearbybindings postprocessingbindings stats debugbindings
|
camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings postprocessingbindings stats debugbindings
|
||||||
types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair types/armor types/light types/static types/clothing types/levelledlist types/terminal
|
types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair types/armor types/light types/static types/clothing types/levelledlist types/terminal
|
||||||
worker magicbindings
|
worker magicbindings
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <MyGUI_TextIterator.h>
|
#include <MyGUI_TextIterator.h>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <components/misc/constants.hpp>
|
#include <components/misc/constants.hpp>
|
||||||
|
@ -93,8 +94,10 @@ namespace
|
||||||
int level = creatureStats.getLevel();
|
int level = creatureStats.getLevel();
|
||||||
for (const ESM::Attribute& attribute : attributes)
|
for (const ESM::Attribute& attribute : attributes)
|
||||||
{
|
{
|
||||||
const ESM::Race::MaleFemale& value
|
auto index = ESM::Attribute::refIdToIndex(attribute.mId);
|
||||||
= race->mData.mAttributeValues[static_cast<size_t>(ESM::Attribute::refIdToIndex(attribute.mId))];
|
assert(index >= 0);
|
||||||
|
|
||||||
|
const ESM::Race::MaleFemale& value = race->mData.mAttributeValues[static_cast<size_t>(index)];
|
||||||
creatureStats.setAttribute(attribute.mId, male ? value.mMale : value.mFemale);
|
creatureStats.setAttribute(attribute.mId, male ? value.mMale : value.mFemale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "soundbindings.hpp"
|
#include "soundbindings.hpp"
|
||||||
#include "types/types.hpp"
|
#include "types/types.hpp"
|
||||||
#include "uibindings.hpp"
|
#include "uibindings.hpp"
|
||||||
|
#include "vfsbindings.hpp"
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
|
@ -347,6 +348,7 @@ namespace MWLua
|
||||||
{ "openmw.core", initCorePackage(context) },
|
{ "openmw.core", initCorePackage(context) },
|
||||||
{ "openmw.types", initTypesPackage(context) },
|
{ "openmw.types", initTypesPackage(context) },
|
||||||
{ "openmw.util", LuaUtil::initUtilPackage(lua) },
|
{ "openmw.util", LuaUtil::initUtilPackage(lua) },
|
||||||
|
{ "openmw.vfs", initVFSPackage(context) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
346
apps/openmw/mwlua/vfsbindings.cpp
Normal file
346
apps/openmw/mwlua/vfsbindings.cpp
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
#include "vfsbindings.hpp"
|
||||||
|
|
||||||
|
#include <components/files/istreamptr.hpp>
|
||||||
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
#include <components/settings/values.hpp>
|
||||||
|
#include <components/vfs/manager.hpp>
|
||||||
|
#include <components/vfs/pathutil.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
|
#include "context.hpp"
|
||||||
|
#include "luamanagerimp.hpp"
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Too many arguments may cause stack corruption and crash.
|
||||||
|
constexpr std::size_t sMaximumReadArguments = 20;
|
||||||
|
|
||||||
|
// Print a message if we read a large chunk of file to string.
|
||||||
|
constexpr std::size_t sFileSizeWarningThreshold = 1024 * 1024;
|
||||||
|
|
||||||
|
struct FileHandle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileHandle(Files::IStreamPtr stream, std::string_view fileName)
|
||||||
|
{
|
||||||
|
mFilePtr = std::move(stream);
|
||||||
|
mFileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Files::IStreamPtr mFilePtr;
|
||||||
|
std::string mFileName;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ios_base::seekdir getSeekDir(FileHandle& self, std::string_view whence)
|
||||||
|
{
|
||||||
|
if (whence == "cur")
|
||||||
|
return std::ios_base::cur;
|
||||||
|
if (whence == "set")
|
||||||
|
return std::ios_base::beg;
|
||||||
|
if (whence == "end")
|
||||||
|
return std::ios_base::end;
|
||||||
|
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Error when handling '" + self.mFileName + "': invalid seek direction: '" + std::string(whence) + "'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getBytesLeftInStream(Files::IStreamPtr& file)
|
||||||
|
{
|
||||||
|
auto oldPos = file->tellg();
|
||||||
|
file->seekg(0, std::ios_base::end);
|
||||||
|
auto newPos = file->tellg();
|
||||||
|
file->seekg(oldPos, std::ios_base::beg);
|
||||||
|
|
||||||
|
return newPos - oldPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printLargeDataMessage(FileHandle& file, size_t size)
|
||||||
|
{
|
||||||
|
if (!file.mFilePtr || !Settings::lua().mLuaDebug || size < sFileSizeWarningThreshold)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Log(Debug::Verbose) << "Read a large data chunk (" << size << " bytes) from '" << file.mFileName << "'.";
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::object readFile(LuaUtil::LuaState* lua, FileHandle& file)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
if (file.mFilePtr && file.mFilePtr->peek() != EOF)
|
||||||
|
os << file.mFilePtr->rdbuf();
|
||||||
|
|
||||||
|
auto result = os.str();
|
||||||
|
printLargeDataMessage(file, result.size());
|
||||||
|
return sol::make_object<std::string>(lua->sol(), std::move(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::object readLineFromFile(LuaUtil::LuaState* lua, FileHandle& file)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
if (file.mFilePtr && std::getline(*file.mFilePtr, result))
|
||||||
|
{
|
||||||
|
printLargeDataMessage(file, result.size());
|
||||||
|
return sol::make_object<std::string>(lua->sol(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sol::nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::object readNumberFromFile(LuaUtil::LuaState* lua, Files::IStreamPtr& file)
|
||||||
|
{
|
||||||
|
double number = 0;
|
||||||
|
if (file && *file >> number)
|
||||||
|
return sol::make_object<double>(lua->sol(), number);
|
||||||
|
|
||||||
|
return sol::nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::object readCharactersFromFile(LuaUtil::LuaState* lua, FileHandle& file, size_t count)
|
||||||
|
{
|
||||||
|
if (count <= 0 && file.mFilePtr->peek() != EOF)
|
||||||
|
return sol::make_object<std::string>(lua->sol(), std::string());
|
||||||
|
|
||||||
|
auto bytesLeft = getBytesLeftInStream(file.mFilePtr);
|
||||||
|
if (bytesLeft <= 0)
|
||||||
|
return sol::nil;
|
||||||
|
|
||||||
|
if (count > bytesLeft)
|
||||||
|
count = bytesLeft;
|
||||||
|
|
||||||
|
std::string result(count, '\0');
|
||||||
|
if (file.mFilePtr->read(&result[0], count))
|
||||||
|
{
|
||||||
|
printLargeDataMessage(file, result.size());
|
||||||
|
return sol::make_object<std::string>(lua->sol(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sol::nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void validateFile(const FileHandle& self)
|
||||||
|
{
|
||||||
|
if (self.mFilePtr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
throw std::runtime_error("Error when handling '" + self.mFileName + "': attempt to use a closed file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::variadic_results seek(
|
||||||
|
LuaUtil::LuaState* lua, FileHandle& self, std::ios_base::seekdir dir, std::streamoff off)
|
||||||
|
{
|
||||||
|
sol::variadic_results values;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
self.mFilePtr->seekg(off, dir);
|
||||||
|
if (self.mFilePtr->fail() || self.mFilePtr->bad())
|
||||||
|
{
|
||||||
|
auto msg = "Failed to seek in file '" + self.mFileName + "'";
|
||||||
|
values.push_back(sol::nil);
|
||||||
|
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
values.push_back(sol::make_object<std::streampos>(lua->sol(), self.mFilePtr->tellg()));
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
auto msg = "Failed to seek in file '" + self.mFileName + "': " + std::string(e.what());
|
||||||
|
values.push_back(sol::nil);
|
||||||
|
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::table initVFSPackage(const Context& context)
|
||||||
|
{
|
||||||
|
sol::table api(context.mLua->sol(), sol::create);
|
||||||
|
|
||||||
|
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||||
|
|
||||||
|
sol::usertype<FileHandle> handle = context.mLua->sol().new_usertype<FileHandle>("FileHandle");
|
||||||
|
handle["fileName"] = sol::readonly_property([](const FileHandle& self) { return self.mFileName; });
|
||||||
|
handle[sol::meta_function::to_string] = [](const FileHandle& self) {
|
||||||
|
return "FileHandle{'" + self.mFileName + "'" + (!self.mFilePtr ? ", closed" : "") + "}";
|
||||||
|
};
|
||||||
|
handle["seek"] = sol::overload(
|
||||||
|
[lua = context.mLua](FileHandle& self, std::string_view whence, sol::optional<long> offset) {
|
||||||
|
validateFile(self);
|
||||||
|
|
||||||
|
auto off = static_cast<std::streamoff>(offset.value_or(0));
|
||||||
|
auto dir = getSeekDir(self, whence);
|
||||||
|
|
||||||
|
return seek(lua, self, dir, off);
|
||||||
|
},
|
||||||
|
[lua = context.mLua](FileHandle& self, sol::optional<long> offset) {
|
||||||
|
validateFile(self);
|
||||||
|
|
||||||
|
auto off = static_cast<std::streamoff>(offset.value_or(0));
|
||||||
|
|
||||||
|
return seek(lua, self, std::ios_base::cur, off);
|
||||||
|
});
|
||||||
|
handle["lines"] = [lua = context.mLua](FileHandle& self) {
|
||||||
|
return sol::as_function([&lua, &self]() mutable {
|
||||||
|
validateFile(self);
|
||||||
|
return readLineFromFile(lua, self);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
api["lines"] = [lua = context.mLua, vfs](std::string_view fileName) {
|
||||||
|
auto normalizedName = VFS::Path::normalizeFilename(fileName);
|
||||||
|
return sol::as_function(
|
||||||
|
[lua, file = FileHandle(vfs->getNormalized(normalizedName), normalizedName)]() mutable {
|
||||||
|
validateFile(file);
|
||||||
|
auto result = readLineFromFile(lua, file);
|
||||||
|
if (result == sol::nil)
|
||||||
|
file.mFilePtr.reset();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handle["close"] = [lua = context.mLua](FileHandle& self) {
|
||||||
|
sol::variadic_results values;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
self.mFilePtr.reset();
|
||||||
|
if (self.mFilePtr)
|
||||||
|
{
|
||||||
|
auto msg = "Can not close file '" + self.mFileName + "': file handle is still opened.";
|
||||||
|
values.push_back(sol::nil);
|
||||||
|
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
values.push_back(sol::make_object<bool>(lua->sol(), true));
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
auto msg = "Can not close file '" + self.mFileName + "': " + std::string(e.what());
|
||||||
|
values.push_back(sol::nil);
|
||||||
|
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
|
||||||
|
handle["read"] = [lua = context.mLua](FileHandle& self, const sol::variadic_args args) {
|
||||||
|
validateFile(self);
|
||||||
|
|
||||||
|
if (args.size() > sMaximumReadArguments)
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Error when handling '" + self.mFileName + "': too many arguments for 'read'.");
|
||||||
|
|
||||||
|
sol::variadic_results values;
|
||||||
|
// If there are no arguments, read a string
|
||||||
|
if (args.size() == 0)
|
||||||
|
{
|
||||||
|
values.push_back(readLineFromFile(lua, self));
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = true;
|
||||||
|
size_t i = 0;
|
||||||
|
for (i = 0; i < args.size() && success; i++)
|
||||||
|
{
|
||||||
|
if (args[i].is<std::string_view>())
|
||||||
|
{
|
||||||
|
auto format = args[i].as<std::string_view>();
|
||||||
|
|
||||||
|
if (format == "*a" || format == "*all")
|
||||||
|
{
|
||||||
|
values.push_back(readFile(lua, self));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == "*n" || format == "*number")
|
||||||
|
{
|
||||||
|
auto result = readNumberFromFile(lua, self.mFilePtr);
|
||||||
|
values.push_back(result);
|
||||||
|
if (result == sol::nil)
|
||||||
|
success = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == "*l" || format == "*line")
|
||||||
|
{
|
||||||
|
auto result = readLineFromFile(lua, self);
|
||||||
|
values.push_back(result);
|
||||||
|
if (result == sol::nil)
|
||||||
|
success = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Error when handling '" + self.mFileName + "': bad argument #"
|
||||||
|
+ std::to_string(i + 1) + " to 'read' (invalid format)");
|
||||||
|
}
|
||||||
|
else if (args[i].is<int>())
|
||||||
|
{
|
||||||
|
int number = args[i].as<int>();
|
||||||
|
auto result = readCharactersFromFile(lua, self, number);
|
||||||
|
values.push_back(result);
|
||||||
|
if (result == sol::nil)
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should return nil if we just reached the end of stream
|
||||||
|
if (!success && self.mFilePtr->eof())
|
||||||
|
return values;
|
||||||
|
|
||||||
|
if (!success && (self.mFilePtr->fail() || self.mFilePtr->bad()))
|
||||||
|
{
|
||||||
|
auto msg = "Error when handling '" + self.mFileName + "': can not read data for argument #"
|
||||||
|
+ std::to_string(i);
|
||||||
|
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
|
||||||
|
api["open"] = [lua = context.mLua, vfs](std::string_view fileName) {
|
||||||
|
sol::variadic_results values;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto normalizedName = VFS::Path::normalizeFilename(fileName);
|
||||||
|
auto handle = FileHandle(vfs->getNormalized(normalizedName), normalizedName);
|
||||||
|
values.push_back(sol::make_object<FileHandle>(lua->sol(), std::move(handle)));
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
auto msg = "Can not open file: " + std::string(e.what());
|
||||||
|
values.push_back(sol::nil);
|
||||||
|
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
|
||||||
|
api["type"] = sol::overload(
|
||||||
|
[](const FileHandle& handle) -> std::string {
|
||||||
|
if (handle.mFilePtr)
|
||||||
|
return "file";
|
||||||
|
|
||||||
|
return "closed file";
|
||||||
|
},
|
||||||
|
[](const sol::object&) -> sol::object { return sol::nil; });
|
||||||
|
|
||||||
|
api["fileExists"] = [vfs](std::string_view fileName) -> bool { return vfs->exists(fileName); };
|
||||||
|
api["pathsWithPrefix"] = [vfs](std::string_view prefix) {
|
||||||
|
auto iterator = vfs->getRecursiveDirectoryIterator(prefix);
|
||||||
|
return sol::as_function([iterator, current = iterator.begin()]() mutable -> sol::optional<std::string> {
|
||||||
|
if (current != iterator.end())
|
||||||
|
{
|
||||||
|
const std::string& result = *current;
|
||||||
|
++current;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sol::nullopt;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return LuaUtil::makeReadOnly(api);
|
||||||
|
}
|
||||||
|
}
|
13
apps/openmw/mwlua/vfsbindings.hpp
Normal file
13
apps/openmw/mwlua/vfsbindings.hpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef MWLUA_VFSBINDINGS_H
|
||||||
|
#define MWLUA_VFSBINDINGS_H
|
||||||
|
|
||||||
|
#include <sol/forward.hpp>
|
||||||
|
|
||||||
|
#include "context.hpp"
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
sol::table initVFSPackage(const Context&);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MWLUA_VFSBINDINGS_H
|
|
@ -48,9 +48,9 @@ namespace MWMechanics
|
||||||
std::string EffectKey::toString() const
|
std::string EffectKey::toString() const
|
||||||
{
|
{
|
||||||
const auto& store = MWBase::Environment::get().getESMStore();
|
const auto& store = MWBase::Environment::get().getESMStore();
|
||||||
const ESM::MagicEffect* magicEffect = store->get<ESM::MagicEffect>().search(mId);
|
const ESM::MagicEffect* magicEffect = store->get<ESM::MagicEffect>().find(mId);
|
||||||
return getMagicEffectString(
|
return getMagicEffectString(
|
||||||
*magicEffect, store->get<ESM::Attribute>().search(mArg), store->get<ESM::Skill>().search(mArg));
|
*magicEffect, store->get<ESM::Attribute>().find(mArg), store->get<ESM::Skill>().find(mArg));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const EffectKey& left, const EffectKey& right)
|
bool operator<(const EffectKey& left, const EffectKey& right)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "mechanicsmanagerimp.hpp"
|
#include "mechanicsmanagerimp.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include <osg/Stats>
|
#include <osg/Stats>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
@ -150,9 +152,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
for (const ESM::Attribute& attribute : esmStore.get<ESM::Attribute>())
|
for (const ESM::Attribute& attribute : esmStore.get<ESM::Attribute>())
|
||||||
{
|
{
|
||||||
const ESM::Race::MaleFemale& value
|
auto index = ESM::Attribute::refIdToIndex(attribute.mId);
|
||||||
= race->mData.mAttributeValues[static_cast<size_t>(ESM::Attribute::refIdToIndex(attribute.mId))];
|
assert(index >= 0);
|
||||||
|
|
||||||
|
const ESM::Race::MaleFemale& value = race->mData.mAttributeValues[static_cast<size_t>(index)];
|
||||||
creatureStats.setAttribute(attribute.mId, male ? value.mMale : value.mFemale);
|
creatureStats.setAttribute(attribute.mId, male ? value.mMale : value.mFemale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -488,7 +488,12 @@ void MWMechanics::NpcStats::writeState(ESM::NpcStats& state) const
|
||||||
|
|
||||||
state.mSkillIncrease.fill(0);
|
state.mSkillIncrease.fill(0);
|
||||||
for (const auto& [key, value] : mSkillIncreases)
|
for (const auto& [key, value] : mSkillIncreases)
|
||||||
state.mSkillIncrease[static_cast<size_t>(ESM::Attribute::refIdToIndex(key))] = value;
|
{
|
||||||
|
// TODO extend format
|
||||||
|
auto index = ESM::Attribute::refIdToIndex(key);
|
||||||
|
assert(index >= 0);
|
||||||
|
state.mSkillIncrease[static_cast<size_t>(index)] = value;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < state.mSpecIncreases.size(); ++i)
|
for (size_t i = 0; i < state.mSpecIncreases.size(); ++i)
|
||||||
state.mSpecIncreases[i] = mSpecIncreases[i];
|
state.mSpecIncreases[i] = mSpecIncreases[i];
|
||||||
|
|
|
@ -556,7 +556,7 @@ namespace MWWorld
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CellStore::CellStore(MWWorld::Cell cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers)
|
CellStore::CellStore(MWWorld::Cell&& cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers)
|
||||||
: mStore(esmStore)
|
: mStore(esmStore)
|
||||||
, mReaders(readers)
|
, mReaders(readers)
|
||||||
, mCellVariant(std::move(cell))
|
, mCellVariant(std::move(cell))
|
||||||
|
|
|
@ -140,7 +140,7 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param readerList The readers to use for loading of the cell on-demand.
|
/// @param readerList The readers to use for loading of the cell on-demand.
|
||||||
CellStore(MWWorld::Cell cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers);
|
CellStore(MWWorld::Cell&& cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers);
|
||||||
|
|
||||||
CellStore(const CellStore&) = delete;
|
CellStore(const CellStore&) = delete;
|
||||||
|
|
||||||
|
|
|
@ -159,9 +159,16 @@ MWWorld::ContainerStore::ContainerStore()
|
||||||
|
|
||||||
MWWorld::ContainerStore::~ContainerStore()
|
MWWorld::ContainerStore::~ContainerStore()
|
||||||
{
|
{
|
||||||
MWWorld::WorldModel* worldModel = MWBase::Environment::get().getWorldModel();
|
try
|
||||||
for (MWWorld::ContainerStoreIterator iter(begin()); iter != end(); ++iter)
|
{
|
||||||
worldModel->deregisterPtr(*iter);
|
MWWorld::WorldModel* worldModel = MWBase::Environment::get().getWorldModel();
|
||||||
|
for (MWWorld::ContainerStoreIterator iter(begin()); iter != end(); ++iter)
|
||||||
|
worldModel->deregisterPtr(*iter);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Failed to deregister container store: " << e.what();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::ConstContainerStoreIterator MWWorld::ContainerStore::cbegin(int mask) const
|
MWWorld::ConstContainerStoreIterator MWWorld::ContainerStore::cbegin(int mask) const
|
||||||
|
|
|
@ -834,9 +834,6 @@ namespace MWWorld
|
||||||
mPreloader = std::make_unique<CellPreloader>(rendering.getResourceSystem(), physics->getShapeManager(),
|
mPreloader = std::make_unique<CellPreloader>(rendering.getResourceSystem(), physics->getShapeManager(),
|
||||||
rendering.getTerrain(), rendering.getLandManager());
|
rendering.getTerrain(), rendering.getLandManager());
|
||||||
mPreloader->setWorkQueue(mRendering.getWorkQueue());
|
mPreloader->setWorkQueue(mRendering.getWorkQueue());
|
||||||
|
|
||||||
rendering.getResourceSystem()->setExpiryDelay(Settings::cells().mCacheExpiryDelay);
|
|
||||||
|
|
||||||
mPreloader->setExpiryDelay(Settings::cells().mPreloadCellExpiryDelay);
|
mPreloader->setExpiryDelay(Settings::cells().mPreloadCellExpiryDelay);
|
||||||
mPreloader->setMinCacheSize(Settings::cells().mPreloadCellCacheMin);
|
mPreloader->setMinCacheSize(Settings::cells().mPreloadCellCacheMin);
|
||||||
mPreloader->setMaxCacheSize(Settings::cells().mPreloadCellCacheMax);
|
mPreloader->setMaxCacheSize(Settings::cells().mPreloadCellCacheMax);
|
||||||
|
|
|
@ -1017,11 +1017,12 @@ namespace MWWorld
|
||||||
void Store<ESM::GameSetting>::setUp()
|
void Store<ESM::GameSetting>::setUp()
|
||||||
{
|
{
|
||||||
auto addSetting = [&](const std::string& key, ESM::Variant value) {
|
auto addSetting = [&](const std::string& key, ESM::Variant value) {
|
||||||
|
auto id = ESM::RefId::stringRefId(key);
|
||||||
ESM::GameSetting setting;
|
ESM::GameSetting setting;
|
||||||
setting.blank();
|
setting.blank();
|
||||||
setting.mId = ESM::RefId::stringRefId(key);
|
setting.mId = id;
|
||||||
setting.mValue = std::move(value);
|
setting.mValue = std::move(value);
|
||||||
auto [iter, inserted] = mStatic.insert_or_assign(setting.mId, std::move(setting));
|
auto [iter, inserted] = mStatic.insert_or_assign(id, std::move(setting));
|
||||||
if (inserted)
|
if (inserted)
|
||||||
mShared.push_back(&iter->second);
|
mShared.push_back(&iter->second);
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Nif::Testing
|
||||||
|
|
||||||
inline void init(Extra& value)
|
inline void init(Extra& value)
|
||||||
{
|
{
|
||||||
value.next = ExtraPtr(nullptr);
|
value.mNext = ExtraPtr(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void init(Named& value)
|
inline void init(Named& value)
|
||||||
|
|
|
@ -996,7 +996,7 @@ namespace
|
||||||
TEST_F(TestBulletNifLoader,
|
TEST_F(TestBulletNifLoader,
|
||||||
for_tri_shape_child_node_with_extra_data_string_equal_ncc_should_return_shape_with_cameraonly_collision)
|
for_tri_shape_child_node_with_extra_data_string_equal_ncc_should_return_shape_with_cameraonly_collision)
|
||||||
{
|
{
|
||||||
mNiStringExtraData.string = "NCC__";
|
mNiStringExtraData.mData = "NCC__";
|
||||||
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
|
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
|
||||||
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
||||||
mNiTriShape.parents.push_back(&mNiNode);
|
mNiTriShape.parents.push_back(&mNiNode);
|
||||||
|
@ -1024,8 +1024,8 @@ namespace
|
||||||
TEST_F(TestBulletNifLoader,
|
TEST_F(TestBulletNifLoader,
|
||||||
for_tri_shape_child_node_with_not_first_extra_data_string_equal_ncc_should_return_shape_with_cameraonly_collision)
|
for_tri_shape_child_node_with_not_first_extra_data_string_equal_ncc_should_return_shape_with_cameraonly_collision)
|
||||||
{
|
{
|
||||||
mNiStringExtraData.next = Nif::ExtraPtr(&mNiStringExtraData2);
|
mNiStringExtraData.mNext = Nif::ExtraPtr(&mNiStringExtraData2);
|
||||||
mNiStringExtraData2.string = "NCC__";
|
mNiStringExtraData2.mData = "NCC__";
|
||||||
mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
|
mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
|
||||||
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
||||||
mNiTriShape.parents.push_back(&mNiNode);
|
mNiTriShape.parents.push_back(&mNiNode);
|
||||||
|
@ -1052,7 +1052,7 @@ namespace
|
||||||
TEST_F(TestBulletNifLoader,
|
TEST_F(TestBulletNifLoader,
|
||||||
for_tri_shape_child_node_with_extra_data_string_starting_with_nc_should_return_shape_with_nocollision)
|
for_tri_shape_child_node_with_extra_data_string_starting_with_nc_should_return_shape_with_nocollision)
|
||||||
{
|
{
|
||||||
mNiStringExtraData.string = "NC___";
|
mNiStringExtraData.mData = "NC___";
|
||||||
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
|
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
|
||||||
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
||||||
mNiTriShape.parents.push_back(&mNiNode);
|
mNiTriShape.parents.push_back(&mNiNode);
|
||||||
|
@ -1079,8 +1079,8 @@ namespace
|
||||||
TEST_F(TestBulletNifLoader,
|
TEST_F(TestBulletNifLoader,
|
||||||
for_tri_shape_child_node_with_not_first_extra_data_string_starting_with_nc_should_return_shape_with_nocollision)
|
for_tri_shape_child_node_with_not_first_extra_data_string_starting_with_nc_should_return_shape_with_nocollision)
|
||||||
{
|
{
|
||||||
mNiStringExtraData.next = Nif::ExtraPtr(&mNiStringExtraData2);
|
mNiStringExtraData.mNext = Nif::ExtraPtr(&mNiStringExtraData2);
|
||||||
mNiStringExtraData2.string = "NC___";
|
mNiStringExtraData2.mData = "NC___";
|
||||||
mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
|
mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
|
||||||
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
||||||
mNiTriShape.parents.push_back(&mNiNode);
|
mNiTriShape.parents.push_back(&mNiNode);
|
||||||
|
@ -1141,7 +1141,7 @@ namespace
|
||||||
TEST_F(TestBulletNifLoader,
|
TEST_F(TestBulletNifLoader,
|
||||||
for_tri_shape_child_node_with_extra_data_string_mrk_should_return_shape_with_null_collision_shape)
|
for_tri_shape_child_node_with_extra_data_string_mrk_should_return_shape_with_null_collision_shape)
|
||||||
{
|
{
|
||||||
mNiStringExtraData.string = "MRK";
|
mNiStringExtraData.mData = "MRK";
|
||||||
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
|
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
|
||||||
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
||||||
mNiTriShape.parents.push_back(&mNiNode);
|
mNiTriShape.parents.push_back(&mNiNode);
|
||||||
|
@ -1160,7 +1160,7 @@ namespace
|
||||||
|
|
||||||
TEST_F(TestBulletNifLoader, bsx_editor_marker_flag_disables_collision_for_markers)
|
TEST_F(TestBulletNifLoader, bsx_editor_marker_flag_disables_collision_for_markers)
|
||||||
{
|
{
|
||||||
mNiIntegerExtraData.data = 32; // BSX flag "editor marker"
|
mNiIntegerExtraData.mData = 32; // BSX flag "editor marker"
|
||||||
mNiIntegerExtraData.recType = Nif::RC_BSXFlags;
|
mNiIntegerExtraData.recType = Nif::RC_BSXFlags;
|
||||||
mNiTriShape.extralist.push_back(Nif::ExtraPtr(&mNiIntegerExtraData));
|
mNiTriShape.extralist.push_back(Nif::ExtraPtr(&mNiIntegerExtraData));
|
||||||
mNiTriShape.parents.push_back(&mNiNode);
|
mNiTriShape.parents.push_back(&mNiNode);
|
||||||
|
@ -1181,7 +1181,7 @@ namespace
|
||||||
TEST_F(TestBulletNifLoader,
|
TEST_F(TestBulletNifLoader,
|
||||||
for_tri_shape_child_node_with_extra_data_string_mrk_and_other_collision_node_should_return_shape_with_triangle_mesh_shape_with_all_meshes)
|
for_tri_shape_child_node_with_extra_data_string_mrk_and_other_collision_node_should_return_shape_with_triangle_mesh_shape_with_all_meshes)
|
||||||
{
|
{
|
||||||
mNiStringExtraData.string = "MRK";
|
mNiStringExtraData.mData = "MRK";
|
||||||
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
|
mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
|
||||||
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
||||||
mNiTriShape.parents.push_back(&mNiNode2);
|
mNiTriShape.parents.push_back(&mNiNode2);
|
||||||
|
|
|
@ -42,7 +42,7 @@ list (APPEND COMPONENT_FILES "${OpenMW_BINARY_DIR}/${VERSION_CPP_FILE}")
|
||||||
# source files
|
# source files
|
||||||
|
|
||||||
add_component_dir (lua
|
add_component_dir (lua
|
||||||
luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage
|
luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage utf8
|
||||||
shapes/box
|
shapes/box
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ add_component_dir (sceneutil
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (nif
|
add_component_dir (nif
|
||||||
controlled effect niftypes record controller extra node record_ptr data niffile property nifkey base nifstream physics
|
base controller data effect extra niffile nifkey nifstream niftypes node particle physics property record record_ptr texture
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (nifosg
|
add_component_dir (nifosg
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
#include "scriptscontainer.hpp"
|
#include "scriptscontainer.hpp"
|
||||||
|
#include "utf8.hpp"
|
||||||
|
|
||||||
namespace LuaUtil
|
namespace LuaUtil
|
||||||
{
|
{
|
||||||
|
@ -51,7 +52,7 @@ namespace LuaUtil
|
||||||
|
|
||||||
static const std::string safeFunctions[] = { "assert", "error", "ipairs", "next", "pairs", "pcall", "select",
|
static const std::string safeFunctions[] = { "assert", "error", "ipairs", "next", "pairs", "pcall", "select",
|
||||||
"tonumber", "tostring", "type", "unpack", "xpcall", "rawequal", "rawget", "rawset", "setmetatable" };
|
"tonumber", "tostring", "type", "unpack", "xpcall", "rawequal", "rawget", "rawset", "setmetatable" };
|
||||||
static const std::string safePackages[] = { "coroutine", "math", "string", "table" };
|
static const std::string safePackages[] = { "coroutine", "math", "string", "table", "utf8" };
|
||||||
|
|
||||||
static constexpr int64_t countHookStep = 1000;
|
static constexpr int64_t countHookStep = 1000;
|
||||||
|
|
||||||
|
@ -181,6 +182,8 @@ namespace LuaUtil
|
||||||
mSol["math"]["randomseed"](static_cast<unsigned>(std::time(nullptr)));
|
mSol["math"]["randomseed"](static_cast<unsigned>(std::time(nullptr)));
|
||||||
mSol["math"]["randomseed"] = [] {};
|
mSol["math"]["randomseed"] = [] {};
|
||||||
|
|
||||||
|
mSol["utf8"] = LuaUtf8::initUtf8Package(mSol);
|
||||||
|
|
||||||
mSol["writeToLog"] = [](std::string_view s) { Log(Debug::Level::Info) << s; };
|
mSol["writeToLog"] = [](std::string_view s) { Log(Debug::Level::Info) << s; };
|
||||||
|
|
||||||
mSol["setEnvironment"]
|
mSol["setEnvironment"]
|
||||||
|
|
233
components/lua/utf8.cpp
Normal file
233
components/lua/utf8.cpp
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
#include <codecvt>
|
||||||
|
#include <components/misc/strings/format.hpp>
|
||||||
|
|
||||||
|
#include "utf8.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr std::string_view UTF8PATT = "[%z\x01-\x7F\xC2-\xF4][\x80-\xBF]*"; // %z is deprecated in Lua5.2
|
||||||
|
constexpr uint32_t MAXUTF = 0x7FFFFFFFu;
|
||||||
|
// constexpr uint32_t MAXUNICODE = 0x10FFFFu;
|
||||||
|
|
||||||
|
inline bool isNilOrNone(const sol::stack_proxy arg)
|
||||||
|
{
|
||||||
|
return (arg.get_type() == sol::type::lua_nil || arg.get_type() == sol::type::none);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double getInteger(const sol::stack_proxy arg, const size_t n, std::string_view name)
|
||||||
|
{
|
||||||
|
double integer;
|
||||||
|
if (!arg.is<double>())
|
||||||
|
throw std::runtime_error(Misc::StringUtils::format("bad argument #%i to '%s' (number expected, got %s)", n,
|
||||||
|
name, sol::type_name(arg.lua_state(), arg.get_type())));
|
||||||
|
|
||||||
|
if (std::modf(arg, &integer) != 0)
|
||||||
|
throw std::runtime_error(
|
||||||
|
Misc::StringUtils::format("bad argument #{} to '{}' (number has no integer representation)", n, name));
|
||||||
|
|
||||||
|
return integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the input 'pos' is negative, it is treated as counting from the end of the string,
|
||||||
|
// where -1 represents the last character position, -2 represents the second-to-last position,
|
||||||
|
// and so on. If 'pos' is non-negative, it is used as-is.
|
||||||
|
inline void relativePosition(int64_t& pos, const size_t len)
|
||||||
|
{
|
||||||
|
if (pos < 0)
|
||||||
|
pos = std::max<int64_t>(0, pos + len + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns: first - character pos in bytes, second - character codepoint
|
||||||
|
std::pair<int64_t, int64_t> decodeNextUTF8Character(std::string_view s, std::vector<int64_t>& pos_byte)
|
||||||
|
{
|
||||||
|
const int64_t pos = pos_byte.back() - 1;
|
||||||
|
const unsigned char ch = static_cast<unsigned char>(s[pos]);
|
||||||
|
int64_t codepoint = -1;
|
||||||
|
size_t byteSize = 0;
|
||||||
|
|
||||||
|
if ((ch & 0b10000000) == 0)
|
||||||
|
{
|
||||||
|
codepoint = ch;
|
||||||
|
byteSize = 1;
|
||||||
|
}
|
||||||
|
else if ((ch & 0b11100000) == 0b11000000)
|
||||||
|
{
|
||||||
|
codepoint = ch & 0b00011111;
|
||||||
|
byteSize = 2;
|
||||||
|
}
|
||||||
|
else if ((ch & 0b11110000) == 0b11100000)
|
||||||
|
{
|
||||||
|
codepoint = ch & 0b00001111;
|
||||||
|
byteSize = 3;
|
||||||
|
}
|
||||||
|
else if ((ch & 0b11111000) == 0b11110000)
|
||||||
|
{
|
||||||
|
codepoint = ch & 0b00000111;
|
||||||
|
byteSize = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct codepoint for non-ascii
|
||||||
|
for (size_t i = 1; i < byteSize; ++i)
|
||||||
|
{
|
||||||
|
// if not a continuation byte
|
||||||
|
if ((pos + i) >= s.size() || (static_cast<unsigned char>(s[pos + i]) & 0b11000000) != 0b10000000)
|
||||||
|
{
|
||||||
|
return std::make_pair(0, -1);
|
||||||
|
}
|
||||||
|
codepoint = (codepoint << 6) | (static_cast<unsigned char>(s[pos + i]) & 0b00111111);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<size_t, int64_t> res = std::make_pair(pos_byte.back(), codepoint);
|
||||||
|
|
||||||
|
pos_byte.push_back(pos_byte.back() + byteSize); /* the next character (if exists) starts at this byte */
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace LuaUtf8
|
||||||
|
{
|
||||||
|
sol::table initUtf8Package(sol::state_view& lua)
|
||||||
|
{
|
||||||
|
sol::table utf8(lua, sol::create);
|
||||||
|
|
||||||
|
utf8["charpattern"] = UTF8PATT;
|
||||||
|
|
||||||
|
utf8["char"] = [](const sol::variadic_args args) -> std::string {
|
||||||
|
std::string result{};
|
||||||
|
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
||||||
|
for (size_t i = 0; i < args.size(); ++i)
|
||||||
|
{
|
||||||
|
int64_t codepoint = getInteger(args[i], (i + 1), "char");
|
||||||
|
if (codepoint < 0 || codepoint > MAXUTF)
|
||||||
|
throw std::runtime_error(
|
||||||
|
Misc::StringUtils::format("bad argument #{} to 'char' (value out of range)", (i + 1)));
|
||||||
|
|
||||||
|
result += converter.to_bytes(codepoint);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
utf8["codes"] = [](std::string_view s) {
|
||||||
|
std::vector<int64_t> pos_byte{ 1 };
|
||||||
|
return sol::as_function([s, pos_byte]() mutable -> sol::optional<std::pair<int64_t, int64_t>> {
|
||||||
|
if (pos_byte.back() <= static_cast<int64_t>(s.size()))
|
||||||
|
{
|
||||||
|
const auto pair = decodeNextUTF8Character(s, pos_byte);
|
||||||
|
if (pair.second == -1)
|
||||||
|
throw std::runtime_error("Invalid UTF-8 code at position " + std::to_string(pos_byte.size()));
|
||||||
|
|
||||||
|
return pair;
|
||||||
|
}
|
||||||
|
return sol::nullopt;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
utf8["len"] = [](std::string_view s,
|
||||||
|
const sol::variadic_args args) -> std::variant<size_t, std::pair<sol::object, int64_t>> {
|
||||||
|
const size_t len = s.size();
|
||||||
|
int64_t iv = isNilOrNone(args[0]) ? 1 : getInteger(args[0], 2, "len");
|
||||||
|
int64_t fv = isNilOrNone(args[1]) ? -1 : getInteger(args[1], 3, "len");
|
||||||
|
|
||||||
|
relativePosition(iv, len);
|
||||||
|
relativePosition(fv, len);
|
||||||
|
|
||||||
|
if (iv <= 0)
|
||||||
|
throw std::runtime_error("bad argument #2 to 'len' (initial position out of bounds)");
|
||||||
|
if (fv > static_cast<int64_t>(len))
|
||||||
|
throw std::runtime_error("bad argument #3 to 'len' (final position out of bounds)");
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return len;
|
||||||
|
|
||||||
|
std::vector<int64_t> pos_byte = { iv };
|
||||||
|
|
||||||
|
while (pos_byte.back() <= fv)
|
||||||
|
{
|
||||||
|
if (decodeNextUTF8Character(s, pos_byte).second == -1)
|
||||||
|
return std::pair(sol::lua_nil, pos_byte.back());
|
||||||
|
}
|
||||||
|
return pos_byte.size() - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
utf8["codepoint"]
|
||||||
|
= [](std::string_view s, const sol::variadic_args args) -> sol::as_returns_t<std::vector<int64_t>> {
|
||||||
|
size_t len = s.size();
|
||||||
|
int64_t iv = isNilOrNone(args[0]) ? 1 : getInteger(args[0], 2, "codepoint");
|
||||||
|
int64_t fv = isNilOrNone(args[1]) ? iv : getInteger(args[1], 3, "codepoint");
|
||||||
|
|
||||||
|
relativePosition(iv, len);
|
||||||
|
relativePosition(fv, len);
|
||||||
|
|
||||||
|
if (iv <= 0)
|
||||||
|
throw std::runtime_error("bad argument #2 to 'codepoint' (initial position out of bounds)");
|
||||||
|
if (fv > static_cast<int64_t>(len))
|
||||||
|
throw std::runtime_error("bad argument #3 to 'codepoint' (final position out of bounds)");
|
||||||
|
|
||||||
|
if (iv > fv)
|
||||||
|
return sol::as_returns(std::vector<int64_t>{}); /* empty interval; return nothing */
|
||||||
|
|
||||||
|
std::vector<int64_t> pos_byte = { iv };
|
||||||
|
std::vector<int64_t> codepoints;
|
||||||
|
|
||||||
|
while (pos_byte.back() <= fv)
|
||||||
|
{
|
||||||
|
codepoints.push_back(decodeNextUTF8Character(s, pos_byte).second);
|
||||||
|
if (codepoints.back() == -1)
|
||||||
|
throw std::runtime_error("Invalid UTF-8 code at position " + std::to_string(pos_byte.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sol::as_returns(std::move(codepoints));
|
||||||
|
};
|
||||||
|
|
||||||
|
utf8["offset"]
|
||||||
|
= [](std::string_view s, const int64_t n, const sol::variadic_args args) -> sol::optional<int64_t> {
|
||||||
|
size_t len = s.size();
|
||||||
|
int64_t iv;
|
||||||
|
|
||||||
|
if (isNilOrNone(args[0]))
|
||||||
|
{
|
||||||
|
if (n >= 0)
|
||||||
|
iv = 1;
|
||||||
|
else
|
||||||
|
iv = s.size() + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
iv = getInteger(args[0], 3, "offset");
|
||||||
|
|
||||||
|
std::vector<int64_t> pos_byte = { 1 };
|
||||||
|
|
||||||
|
relativePosition(iv, len);
|
||||||
|
|
||||||
|
if (iv > static_cast<int64_t>(len) + 1)
|
||||||
|
throw std::runtime_error("bad argument #3 to 'offset' (position out of bounds)");
|
||||||
|
|
||||||
|
while (pos_byte.back() <= static_cast<int64_t>(len))
|
||||||
|
decodeNextUTF8Character(s, pos_byte);
|
||||||
|
|
||||||
|
for (auto it = pos_byte.begin(); it != pos_byte.end(); ++it)
|
||||||
|
{
|
||||||
|
if (*it == iv)
|
||||||
|
{
|
||||||
|
if (n <= 0 && it + n >= pos_byte.begin())
|
||||||
|
return *(it + n);
|
||||||
|
if (n > 0 && it + n - 1 < pos_byte.end())
|
||||||
|
return *(it + n - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (*it > iv) /* a continuation byte */
|
||||||
|
{
|
||||||
|
if (n == 0)
|
||||||
|
return *(it - 1); /* special case */
|
||||||
|
else
|
||||||
|
throw std::runtime_error("initial position is a continuation byte");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sol::nullopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
return utf8;
|
||||||
|
}
|
||||||
|
}
|
11
components/lua/utf8.hpp
Normal file
11
components/lua/utf8.hpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef COMPONENTS_LUA_UTF8_H
|
||||||
|
#define COMPONENTS_LUA_UTF8_H
|
||||||
|
|
||||||
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
|
namespace LuaUtf8
|
||||||
|
{
|
||||||
|
sol::table initUtf8Package(sol::state_view&);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -5,11 +5,11 @@ namespace Nif
|
||||||
void Extra::read(NIFStream* nif)
|
void Extra::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0))
|
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0))
|
||||||
name = nif->getString();
|
nif->read(mName);
|
||||||
else if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0))
|
else if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0))
|
||||||
{
|
{
|
||||||
next.read(nif);
|
mNext.read(nif);
|
||||||
recordSize = nif->getUInt();
|
nif->read(mRecordSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,12 @@ namespace Nif
|
||||||
// An extra data record. All the extra data connected to an object form a linked list.
|
// An extra data record. All the extra data connected to an object form a linked list.
|
||||||
struct Extra : public Record
|
struct Extra : public Record
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string mName;
|
||||||
ExtraPtr next; // Next extra data record in the list
|
ExtraPtr mNext; // Next extra data record in the list
|
||||||
unsigned int recordSize{ 0u };
|
uint32_t mRecordSize{ 0u };
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
void post(Reader& nif) override { next.post(nif); }
|
void post(Reader& nif) override { mNext.post(nif); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Controller : public Record
|
struct Controller : public Record
|
||||||
|
|
|
@ -1,140 +0,0 @@
|
||||||
#include "controlled.hpp"
|
|
||||||
|
|
||||||
#include "data.hpp"
|
|
||||||
|
|
||||||
namespace Nif
|
|
||||||
{
|
|
||||||
|
|
||||||
void NiSourceTexture::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
Named::read(nif);
|
|
||||||
|
|
||||||
external = nif->getChar() != 0;
|
|
||||||
bool internal = false;
|
|
||||||
if (external)
|
|
||||||
filename = nif->getString();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (nif->getVersion() <= NIFStream::generateVersion(10, 0, 1, 3))
|
|
||||||
internal = nif->getChar();
|
|
||||||
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
|
|
||||||
filename = nif->getString(); // Original file path of the internal texture
|
|
||||||
}
|
|
||||||
if (nif->getVersion() <= NIFStream::generateVersion(10, 0, 1, 3))
|
|
||||||
{
|
|
||||||
if (!external && internal)
|
|
||||||
data.read(nif);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
data.read(nif);
|
|
||||||
}
|
|
||||||
|
|
||||||
pixel = nif->getUInt();
|
|
||||||
mipmap = nif->getUInt();
|
|
||||||
alpha = nif->getUInt();
|
|
||||||
|
|
||||||
// Renderer hints, typically of no use for us
|
|
||||||
/* bool mIsStatic = */ nif->getChar();
|
|
||||||
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 103))
|
|
||||||
/* bool mDirectRendering = */ nif->getBoolean();
|
|
||||||
if (nif->getVersion() >= NIFStream::generateVersion(20, 2, 0, 4))
|
|
||||||
/* bool mPersistRenderData = */ nif->getBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiSourceTexture::post(Reader& nif)
|
|
||||||
{
|
|
||||||
Named::post(nif);
|
|
||||||
data.post(nif);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BSShaderTextureSet::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
nif->getSizedStrings(textures, nif->getUInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiParticleModifier::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
next.read(nif);
|
|
||||||
controller.read(nif);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiParticleModifier::post(Reader& nif)
|
|
||||||
{
|
|
||||||
next.post(nif);
|
|
||||||
controller.post(nif);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiParticleGrowFade::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
NiParticleModifier::read(nif);
|
|
||||||
growTime = nif->getFloat();
|
|
||||||
fadeTime = nif->getFloat();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiParticleColorModifier::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
NiParticleModifier::read(nif);
|
|
||||||
data.read(nif);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiParticleColorModifier::post(Reader& nif)
|
|
||||||
{
|
|
||||||
NiParticleModifier::post(nif);
|
|
||||||
data.post(nif);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiGravity::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
NiParticleModifier::read(nif);
|
|
||||||
|
|
||||||
mDecay = nif->getFloat();
|
|
||||||
mForce = nif->getFloat();
|
|
||||||
mType = nif->getUInt();
|
|
||||||
mPosition = nif->getVector3();
|
|
||||||
mDirection = nif->getVector3();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiParticleCollider::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
NiParticleModifier::read(nif);
|
|
||||||
|
|
||||||
mBounceFactor = nif->getFloat();
|
|
||||||
if (nif->getVersion() >= NIFStream::generateVersion(4, 2, 0, 2))
|
|
||||||
{
|
|
||||||
// Unused in NifSkope. Need to figure out what these do.
|
|
||||||
/*bool mSpawnOnCollision = */ nif->getBoolean();
|
|
||||||
/*bool mDieOnCollision = */ nif->getBoolean();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiPlanarCollider::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
NiParticleCollider::read(nif);
|
|
||||||
|
|
||||||
mExtents = nif->getVector2();
|
|
||||||
mPosition = nif->getVector3();
|
|
||||||
mXVector = nif->getVector3();
|
|
||||||
mYVector = nif->getVector3();
|
|
||||||
mPlaneNormal = nif->getVector3();
|
|
||||||
mPlaneDistance = nif->getFloat();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiParticleRotation::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
NiParticleModifier::read(nif);
|
|
||||||
|
|
||||||
/* bool mRandomInitialAxis = */ nif->getChar();
|
|
||||||
/* osg::Vec3f mInitialAxis = */ nif->getVector3();
|
|
||||||
/* float mRotationSpeed = */ nif->getFloat();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiSphericalCollider::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
NiParticleCollider::read(nif);
|
|
||||||
|
|
||||||
mRadius = nif->getFloat();
|
|
||||||
mCenter = nif->getVector3();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,157 +0,0 @@
|
||||||
/*
|
|
||||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
||||||
Copyright (C) 2008-2010 Nicolay Korslund
|
|
||||||
Email: < korslund@gmail.com >
|
|
||||||
WWW: https://openmw.org/
|
|
||||||
|
|
||||||
This file (controlled.h) is part of the OpenMW package.
|
|
||||||
|
|
||||||
OpenMW is distributed as free software: you can redistribute it
|
|
||||||
and/or modify it under the terms of the GNU General Public License
|
|
||||||
version 3, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
version 3 along with this program. If not, see
|
|
||||||
https://www.gnu.org/licenses/ .
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OPENMW_COMPONENTS_NIF_CONTROLLED_HPP
|
|
||||||
#define OPENMW_COMPONENTS_NIF_CONTROLLED_HPP
|
|
||||||
|
|
||||||
#include "base.hpp"
|
|
||||||
|
|
||||||
namespace Nif
|
|
||||||
{
|
|
||||||
|
|
||||||
struct NiSourceTexture : public Named
|
|
||||||
{
|
|
||||||
// Is this an external (references a separate texture file) or
|
|
||||||
// internal (data is inside the nif itself) texture?
|
|
||||||
bool external;
|
|
||||||
|
|
||||||
std::string filename; // In case of external textures
|
|
||||||
NiPixelDataPtr data; // In case of internal textures
|
|
||||||
|
|
||||||
/* Pixel layout
|
|
||||||
0 - Palettised
|
|
||||||
1 - High color 16
|
|
||||||
2 - True color 32
|
|
||||||
3 - Compressed
|
|
||||||
4 - Bumpmap
|
|
||||||
5 - Default */
|
|
||||||
unsigned int pixel;
|
|
||||||
|
|
||||||
/* Mipmap format
|
|
||||||
0 - no
|
|
||||||
1 - yes
|
|
||||||
2 - default */
|
|
||||||
unsigned int mipmap;
|
|
||||||
|
|
||||||
/* Alpha
|
|
||||||
0 - none
|
|
||||||
1 - binary
|
|
||||||
2 - smooth
|
|
||||||
3 - default (use material alpha, or multiply material with texture if present)
|
|
||||||
*/
|
|
||||||
unsigned int alpha;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
void post(Reader& nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BSShaderTextureSet : public Record
|
|
||||||
{
|
|
||||||
enum TextureType
|
|
||||||
{
|
|
||||||
TextureType_Base = 0,
|
|
||||||
TextureType_Normal = 1,
|
|
||||||
TextureType_Glow = 2,
|
|
||||||
TextureType_Parallax = 3,
|
|
||||||
TextureType_Env = 4,
|
|
||||||
TextureType_EnvMask = 5,
|
|
||||||
TextureType_Subsurface = 6,
|
|
||||||
TextureType_BackLighting = 7
|
|
||||||
};
|
|
||||||
std::vector<std::string> textures;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiParticleModifier : public Record
|
|
||||||
{
|
|
||||||
NiParticleModifierPtr next;
|
|
||||||
ControllerPtr controller;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
void post(Reader& nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiParticleGrowFade : public NiParticleModifier
|
|
||||||
{
|
|
||||||
float growTime;
|
|
||||||
float fadeTime;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiParticleColorModifier : public NiParticleModifier
|
|
||||||
{
|
|
||||||
NiColorDataPtr data;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
void post(Reader& nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiGravity : public NiParticleModifier
|
|
||||||
{
|
|
||||||
float mForce;
|
|
||||||
/* 0 - Wind (fixed direction)
|
|
||||||
* 1 - Point (fixed origin)
|
|
||||||
*/
|
|
||||||
int mType;
|
|
||||||
float mDecay;
|
|
||||||
osg::Vec3f mPosition;
|
|
||||||
osg::Vec3f mDirection;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiParticleCollider : public NiParticleModifier
|
|
||||||
{
|
|
||||||
float mBounceFactor;
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// NiPinaColada
|
|
||||||
struct NiPlanarCollider : public NiParticleCollider
|
|
||||||
{
|
|
||||||
osg::Vec2f mExtents;
|
|
||||||
osg::Vec3f mPosition;
|
|
||||||
osg::Vec3f mXVector, mYVector;
|
|
||||||
osg::Vec3f mPlaneNormal;
|
|
||||||
float mPlaneDistance;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiSphericalCollider : public NiParticleCollider
|
|
||||||
{
|
|
||||||
float mRadius;
|
|
||||||
osg::Vec3f mCenter;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiParticleRotation : public NiParticleModifier
|
|
||||||
{
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // Namespace
|
|
||||||
#endif
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include "controller.hpp"
|
#include "controller.hpp"
|
||||||
|
|
||||||
#include "controlled.hpp"
|
|
||||||
#include "data.hpp"
|
#include "data.hpp"
|
||||||
#include "node.hpp"
|
#include "node.hpp"
|
||||||
#include "recordptr.hpp"
|
#include "particle.hpp"
|
||||||
|
#include "texture.hpp"
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "effect.hpp"
|
#include "effect.hpp"
|
||||||
|
|
||||||
#include "controlled.hpp"
|
|
||||||
#include "node.hpp"
|
#include "node.hpp"
|
||||||
|
#include "texture.hpp"
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
@ -9,55 +9,61 @@ namespace Nif
|
||||||
void NiDynamicEffect::read(NIFStream* nif)
|
void NiDynamicEffect::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
Node::read(nif);
|
Node::read(nif);
|
||||||
if (nif->getVersion() >= nif->generateVersion(10, 1, 0, 106)
|
|
||||||
&& nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO4)
|
if (nif->getVersion() > NIFFile::VER_MW && nif->getVersion() < nif->generateVersion(10, 1, 0, 0))
|
||||||
nif->getBoolean(); // Switch state
|
return;
|
||||||
if (nif->getVersion() <= NIFFile::VER_MW
|
|
||||||
|| (nif->getVersion() >= nif->generateVersion(10, 1, 0, 0)
|
if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_FO4)
|
||||||
&& nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO4))
|
return;
|
||||||
{
|
|
||||||
size_t numAffectedNodes = nif->get<uint32_t>();
|
if (nif->getVersion() >= nif->generateVersion(10, 1, 0, 106))
|
||||||
nif->skip(numAffectedNodes * 4);
|
nif->read(mSwitchState);
|
||||||
}
|
size_t numAffectedNodes = nif->get<uint32_t>();
|
||||||
|
nif->skip(numAffectedNodes * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiLight::read(NIFStream* nif)
|
void NiLight::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
NiDynamicEffect::read(nif);
|
NiDynamicEffect::read(nif);
|
||||||
|
|
||||||
dimmer = nif->getFloat();
|
mDimmer = nif->getFloat();
|
||||||
ambient = nif->getVector3();
|
mAmbient = nif->getVector3();
|
||||||
diffuse = nif->getVector3();
|
mDiffuse = nif->getVector3();
|
||||||
specular = nif->getVector3();
|
mSpecular = nif->getVector3();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiPointLight::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
NiLight::read(nif);
|
||||||
|
|
||||||
|
mConstantAttenuation = nif->getFloat();
|
||||||
|
mLinearAttenuation = nif->getFloat();
|
||||||
|
mQuadraticAttenuation = nif->getFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiSpotLight::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
NiPointLight::read(nif);
|
||||||
|
|
||||||
|
mCutoff = nif->getFloat();
|
||||||
|
mExponent = nif->getFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiTextureEffect::read(NIFStream* nif)
|
void NiTextureEffect::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
NiDynamicEffect::read(nif);
|
NiDynamicEffect::read(nif);
|
||||||
|
|
||||||
// Model Projection Matrix
|
nif->read(mProjectionRotation);
|
||||||
nif->skip(3 * 3 * sizeof(float));
|
nif->read(mProjectionPosition);
|
||||||
|
nif->read(mFilterMode);
|
||||||
// Model Projection Transform
|
|
||||||
nif->skip(3 * sizeof(float));
|
|
||||||
|
|
||||||
// Texture Filtering
|
|
||||||
nif->skip(4);
|
|
||||||
|
|
||||||
// Max anisotropy samples
|
|
||||||
if (nif->getVersion() >= NIFStream::generateVersion(20, 5, 0, 4))
|
if (nif->getVersion() >= NIFStream::generateVersion(20, 5, 0, 4))
|
||||||
nif->skip(2);
|
nif->read(mMaxAnisotropy);
|
||||||
|
nif->read(mClampMode);
|
||||||
clamp = nif->getUInt();
|
mTextureType = static_cast<TextureType>(nif->get<uint32_t>());
|
||||||
|
mCoordGenType = static_cast<CoordGenType>(nif->get<uint32_t>());
|
||||||
textureType = (TextureType)nif->getUInt();
|
mTexture.read(nif);
|
||||||
|
nif->read(mEnableClipPlane);
|
||||||
coordGenType = (CoordGenType)nif->getUInt();
|
mClipPlane = osg::Plane(nif->get<osg::Vec4f>());
|
||||||
|
|
||||||
texture.read(nif);
|
|
||||||
|
|
||||||
nif->skip(1); // Use clipping plane
|
|
||||||
nif->skip(16); // Clipping plane dimensions vector
|
|
||||||
if (nif->getVersion() <= NIFStream::generateVersion(10, 2, 0, 0))
|
if (nif->getVersion() <= NIFStream::generateVersion(10, 2, 0, 0))
|
||||||
nif->skip(4); // PS2-specific shorts
|
nif->skip(4); // PS2-specific shorts
|
||||||
if (nif->getVersion() <= NIFStream::generateVersion(4, 1, 0, 12))
|
if (nif->getVersion() <= NIFStream::generateVersion(4, 1, 0, 12))
|
||||||
|
@ -67,24 +73,8 @@ namespace Nif
|
||||||
void NiTextureEffect::post(Reader& nif)
|
void NiTextureEffect::post(Reader& nif)
|
||||||
{
|
{
|
||||||
NiDynamicEffect::post(nif);
|
NiDynamicEffect::post(nif);
|
||||||
texture.post(nif);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiPointLight::read(NIFStream* nif)
|
mTexture.post(nif);
|
||||||
{
|
|
||||||
NiLight::read(nif);
|
|
||||||
|
|
||||||
constantAttenuation = nif->getFloat();
|
|
||||||
linearAttenuation = nif->getFloat();
|
|
||||||
quadraticAttenuation = nif->getFloat();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiSpotLight::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
NiPointLight::read(nif);
|
|
||||||
|
|
||||||
cutoff = nif->getFloat();
|
|
||||||
exponent = nif->getFloat();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,67 +29,75 @@
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Abstract
|
||||||
struct NiDynamicEffect : public Node
|
struct NiDynamicEffect : public Node
|
||||||
{
|
{
|
||||||
|
bool mSwitchState{ true };
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used as base for NiAmbientLight, NiDirectionalLight, NiPointLight and NiSpotLight.
|
// Abstract light source
|
||||||
struct NiLight : NiDynamicEffect
|
struct NiLight : NiDynamicEffect
|
||||||
{
|
{
|
||||||
float dimmer;
|
float mDimmer;
|
||||||
osg::Vec3f ambient;
|
osg::Vec3f mAmbient;
|
||||||
osg::Vec3f diffuse;
|
osg::Vec3f mDiffuse;
|
||||||
osg::Vec3f specular;
|
osg::Vec3f mSpecular;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NiPointLight : public NiLight
|
struct NiPointLight : public NiLight
|
||||||
{
|
{
|
||||||
float constantAttenuation;
|
float mConstantAttenuation;
|
||||||
float linearAttenuation;
|
float mLinearAttenuation;
|
||||||
float quadraticAttenuation;
|
float mQuadraticAttenuation;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NiSpotLight : public NiPointLight
|
struct NiSpotLight : public NiPointLight
|
||||||
{
|
{
|
||||||
float cutoff;
|
float mCutoff;
|
||||||
float exponent;
|
float mExponent;
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NiTextureEffect : NiDynamicEffect
|
struct NiTextureEffect : NiDynamicEffect
|
||||||
{
|
{
|
||||||
NiSourceTexturePtr texture;
|
enum class TextureType : uint32_t
|
||||||
unsigned int clamp;
|
|
||||||
|
|
||||||
enum TextureType
|
|
||||||
{
|
{
|
||||||
Projected_Light = 0,
|
ProjectedLight = 0,
|
||||||
Projected_Shadow = 1,
|
ProjectedShadow = 1,
|
||||||
Environment_Map = 2,
|
EnvironmentMap = 2,
|
||||||
Fog_Map = 3
|
FogMap = 3,
|
||||||
};
|
};
|
||||||
TextureType textureType;
|
|
||||||
|
|
||||||
enum CoordGenType
|
enum class CoordGenType : uint32_t
|
||||||
{
|
{
|
||||||
World_Parallel = 0,
|
WorldParallel = 0,
|
||||||
World_Perspective,
|
WorldPerspective = 1,
|
||||||
Sphere_Map,
|
SphereMap = 2,
|
||||||
Specular_Cube_Map,
|
SpecularCubeMap = 3,
|
||||||
Diffuse_Cube_Map
|
DiffuseCubeMap = 4,
|
||||||
};
|
};
|
||||||
CoordGenType coordGenType;
|
|
||||||
|
Matrix3 mProjectionRotation;
|
||||||
|
osg::Vec3f mProjectionPosition;
|
||||||
|
uint32_t mFilterMode;
|
||||||
|
NiSourceTexturePtr mTexture;
|
||||||
|
uint16_t mMaxAnisotropy{ 0 };
|
||||||
|
uint32_t mClampMode;
|
||||||
|
TextureType mTextureType;
|
||||||
|
CoordGenType mCoordGenType;
|
||||||
|
uint8_t mEnableClipPlane;
|
||||||
|
osg::Plane mClipPlane;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
void post(Reader& nif) override;
|
void post(Reader& nif) override;
|
||||||
|
|
||||||
bool wrapT() const { return clamp & 1; }
|
bool wrapT() const { return mClampMode & 1; }
|
||||||
bool wrapS() const { return (clamp >> 1) & 1; }
|
bool wrapS() const { return mClampMode & 2; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Namespace
|
} // Namespace
|
||||||
|
|
|
@ -6,25 +6,21 @@ namespace Nif
|
||||||
void NiExtraData::read(NIFStream* nif)
|
void NiExtraData::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
Extra::read(nif);
|
Extra::read(nif);
|
||||||
nif->readVector(data, recordSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiStringExtraData::read(NIFStream* nif)
|
nif->readVector(mData, mRecordSize);
|
||||||
{
|
|
||||||
Extra::read(nif);
|
|
||||||
string = nif->getString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiTextKeyExtraData::read(NIFStream* nif)
|
void NiTextKeyExtraData::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
Extra::read(nif);
|
Extra::read(nif);
|
||||||
|
|
||||||
int keynum = nif->getInt();
|
uint32_t numKeys;
|
||||||
list.resize(keynum);
|
nif->read(numKeys);
|
||||||
for (int i = 0; i < keynum; i++)
|
mList.resize(numKeys);
|
||||||
|
for (TextKey& key : mList)
|
||||||
{
|
{
|
||||||
list[i].time = nif->getFloat();
|
nif->read(key.mTime);
|
||||||
list[i].text = nif->getString();
|
nif->read(key.mText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,81 +28,39 @@ namespace Nif
|
||||||
{
|
{
|
||||||
Extra::read(nif);
|
Extra::read(nif);
|
||||||
|
|
||||||
nif->skip(nif->getUShort() * sizeof(float)); // vertex weights I guess
|
nif->skip(nif->get<uint16_t>() * sizeof(float)); // vertex weights I guess
|
||||||
}
|
|
||||||
|
|
||||||
void NiIntegerExtraData::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
Extra::read(nif);
|
|
||||||
|
|
||||||
data = nif->getUInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiIntegersExtraData::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
Extra::read(nif);
|
|
||||||
|
|
||||||
nif->readVector(data, nif->getUInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiBinaryExtraData::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
Extra::read(nif);
|
|
||||||
nif->readVector(data, nif->getUInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiBooleanExtraData::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
Extra::read(nif);
|
|
||||||
data = nif->getBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiVectorExtraData::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
Extra::read(nif);
|
|
||||||
data = nif->getVector4();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiFloatExtraData::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
Extra::read(nif);
|
|
||||||
|
|
||||||
data = nif->getFloat();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NiFloatsExtraData::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
Extra::read(nif);
|
|
||||||
nif->readVector(data, nif->getUInt());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSBound::read(NIFStream* nif)
|
void BSBound::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
Extra::read(nif);
|
Extra::read(nif);
|
||||||
center = nif->getVector3();
|
|
||||||
halfExtents = nif->getVector3();
|
nif->read(mCenter);
|
||||||
|
nif->read(mExtents);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSFurnitureMarker::LegacyFurniturePosition::read(NIFStream* nif)
|
void BSFurnitureMarker::LegacyFurniturePosition::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mOffset = nif->getVector3();
|
nif->read(mOffset);
|
||||||
mOrientation = nif->getUShort();
|
nif->read(mOrientation);
|
||||||
mPositionRef = nif->getChar();
|
nif->read(mPositionRef);
|
||||||
nif->skip(1); // Position ref 2
|
nif->skip(1); // Position ref 2
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSFurnitureMarker::FurniturePosition::read(NIFStream* nif)
|
void BSFurnitureMarker::FurniturePosition::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mOffset = nif->getVector3();
|
nif->read(mOffset);
|
||||||
mHeading = nif->getFloat();
|
nif->read(mHeading);
|
||||||
mType = nif->getUShort();
|
nif->read(mType);
|
||||||
mEntryPoint = nif->getUShort();
|
nif->read(mEntryPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSFurnitureMarker::read(NIFStream* nif)
|
void BSFurnitureMarker::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
Extra::read(nif);
|
Extra::read(nif);
|
||||||
unsigned int num = nif->getUInt();
|
|
||||||
|
uint32_t num;
|
||||||
|
nif->read(num);
|
||||||
if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3)
|
if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3)
|
||||||
{
|
{
|
||||||
mLegacyMarkers.resize(num);
|
mLegacyMarkers.resize(num);
|
||||||
|
@ -124,19 +78,20 @@ namespace Nif
|
||||||
void BSInvMarker::read(NIFStream* nif)
|
void BSInvMarker::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
Extra::read(nif);
|
Extra::read(nif);
|
||||||
float rotX = nif->getUShort() / 1000.0;
|
|
||||||
float rotY = nif->getUShort() / 1000.0;
|
|
||||||
float rotZ = nif->getUShort() / 1000.0;
|
|
||||||
mScale = nif->getFloat();
|
|
||||||
|
|
||||||
|
float rotX = nif->get<uint16_t>() / 1000.f;
|
||||||
|
float rotY = nif->get<uint16_t>() / 1000.f;
|
||||||
|
float rotZ = nif->get<uint16_t>() / 1000.f;
|
||||||
mRotation = osg::Quat(rotX, osg::X_AXIS, rotY, osg::Y_AXIS, rotZ, osg::Z_AXIS);
|
mRotation = osg::Quat(rotX, osg::X_AXIS, rotY, osg::Y_AXIS, rotZ, osg::Z_AXIS);
|
||||||
|
nif->read(mScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSBehaviorGraphExtraData::read(NIFStream* nif)
|
void BSBehaviorGraphExtraData::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
Extra::read(nif);
|
Extra::read(nif);
|
||||||
mFile = nif->getString();
|
|
||||||
mControlsBaseSkeleton = nif->getBoolean();
|
nif->read(mFile);
|
||||||
|
nif->read(mControlsBaseSkeleton);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,3 @@
|
||||||
/*
|
|
||||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
||||||
Copyright (C) 2008-2010 Nicolay Korslund
|
|
||||||
Email: < korslund@gmail.com >
|
|
||||||
WWW: https://openmw.org/
|
|
||||||
|
|
||||||
This file (extra.h) is part of the OpenMW package.
|
|
||||||
|
|
||||||
OpenMW is distributed as free software: you can redistribute it
|
|
||||||
and/or modify it under the terms of the GNU General Public License
|
|
||||||
version 3, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
version 3 along with this program. If not, see
|
|
||||||
https://www.gnu.org/licenses/ .
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OPENMW_COMPONENTS_NIF_EXTRA_HPP
|
#ifndef OPENMW_COMPONENTS_NIF_EXTRA_HPP
|
||||||
#define OPENMW_COMPONENTS_NIF_EXTRA_HPP
|
#define OPENMW_COMPONENTS_NIF_EXTRA_HPP
|
||||||
|
|
||||||
|
@ -29,9 +6,46 @@
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct TypedExtra : public Extra
|
||||||
|
{
|
||||||
|
T mData;
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override
|
||||||
|
{
|
||||||
|
Extra::read(nif);
|
||||||
|
|
||||||
|
nif->read(mData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct TypedVectorExtra : public Extra
|
||||||
|
{
|
||||||
|
std::vector<T> mData;
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override
|
||||||
|
{
|
||||||
|
Extra::read(nif);
|
||||||
|
|
||||||
|
nif->readVector(mData, nif->get<uint32_t>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using NiBooleanExtraData = TypedExtra<bool>;
|
||||||
|
using NiFloatExtraData = TypedExtra<float>;
|
||||||
|
using NiIntegerExtraData = TypedExtra<uint32_t>;
|
||||||
|
using NiStringExtraData = TypedExtra<std::string>;
|
||||||
|
using NiVectorExtraData = TypedExtra<osg::Vec4f>;
|
||||||
|
|
||||||
|
using NiBinaryExtraData = TypedVectorExtra<uint8_t>;
|
||||||
|
using NiFloatsExtraData = TypedVectorExtra<float>;
|
||||||
|
using NiIntegersExtraData = TypedVectorExtra<uint32_t>;
|
||||||
|
|
||||||
|
// Distinct from NiBinaryExtraData, uses mRecordSize as its size
|
||||||
struct NiExtraData : public Extra
|
struct NiExtraData : public Extra
|
||||||
{
|
{
|
||||||
std::vector<char> data;
|
std::vector<uint8_t> mData;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
@ -45,78 +59,17 @@ namespace Nif
|
||||||
{
|
{
|
||||||
struct TextKey
|
struct TextKey
|
||||||
{
|
{
|
||||||
float time;
|
float mTime;
|
||||||
std::string text;
|
std::string mText;
|
||||||
};
|
};
|
||||||
std::vector<TextKey> list;
|
std::vector<TextKey> mList;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiStringExtraData : public Extra
|
|
||||||
{
|
|
||||||
/* Known meanings:
|
|
||||||
"MRK" - marker, only visible in the editor, not rendered in-game
|
|
||||||
"NCC" - no collision except with the camera
|
|
||||||
Anything else starting with "NC" - no collision
|
|
||||||
*/
|
|
||||||
std::string string;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiIntegerExtraData : public Extra
|
|
||||||
{
|
|
||||||
unsigned int data;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiIntegersExtraData : public Extra
|
|
||||||
{
|
|
||||||
std::vector<unsigned int> data;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiBinaryExtraData : public Extra
|
|
||||||
{
|
|
||||||
std::vector<char> data;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiBooleanExtraData : public Extra
|
|
||||||
{
|
|
||||||
bool data;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiVectorExtraData : public Extra
|
|
||||||
{
|
|
||||||
osg::Vec4f data;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiFloatExtraData : public Extra
|
|
||||||
{
|
|
||||||
float data;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NiFloatsExtraData : public Extra
|
|
||||||
{
|
|
||||||
std::vector<float> data;
|
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BSBound : public Extra
|
struct BSBound : public Extra
|
||||||
{
|
{
|
||||||
osg::Vec3f center, halfExtents;
|
osg::Vec3f mCenter, mExtents;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
@ -149,7 +102,7 @@ namespace Nif
|
||||||
struct BSInvMarker : public Extra
|
struct BSInvMarker : public Extra
|
||||||
{
|
{
|
||||||
osg::Quat mRotation;
|
osg::Quat mRotation;
|
||||||
float mScale = 1.0f;
|
float mScale;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
@ -162,5 +115,5 @@ namespace Nif
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Namespace
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,15 +10,16 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "controlled.hpp"
|
|
||||||
#include "controller.hpp"
|
#include "controller.hpp"
|
||||||
#include "data.hpp"
|
#include "data.hpp"
|
||||||
#include "effect.hpp"
|
#include "effect.hpp"
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
#include "extra.hpp"
|
#include "extra.hpp"
|
||||||
#include "node.hpp"
|
#include "node.hpp"
|
||||||
|
#include "particle.hpp"
|
||||||
#include "physics.hpp"
|
#include "physics.hpp"
|
||||||
#include "property.hpp"
|
#include "property.hpp"
|
||||||
|
#include "texture.hpp"
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
|
95
components/nif/particle.cpp
Normal file
95
components/nif/particle.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#include "particle.hpp"
|
||||||
|
|
||||||
|
#include "data.hpp"
|
||||||
|
|
||||||
|
namespace Nif
|
||||||
|
{
|
||||||
|
|
||||||
|
void NiParticleModifier::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
mNext.read(nif);
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13))
|
||||||
|
mController.read(nif);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiParticleModifier::post(Reader& nif)
|
||||||
|
{
|
||||||
|
mNext.post(nif);
|
||||||
|
mController.post(nif);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiParticleGrowFade::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
NiParticleModifier::read(nif);
|
||||||
|
nif->read(mGrowTime);
|
||||||
|
nif->read(mFadeTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiParticleColorModifier::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
NiParticleModifier::read(nif);
|
||||||
|
|
||||||
|
mData.read(nif);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiParticleColorModifier::post(Reader& nif)
|
||||||
|
{
|
||||||
|
NiParticleModifier::post(nif);
|
||||||
|
|
||||||
|
mData.post(nif);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiGravity::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
NiParticleModifier::read(nif);
|
||||||
|
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13))
|
||||||
|
nif->read(mDecay);
|
||||||
|
nif->read(mForce);
|
||||||
|
mType = static_cast<ForceType>(nif->get<uint32_t>());
|
||||||
|
nif->read(mPosition);
|
||||||
|
nif->read(mDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiParticleCollider::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
NiParticleModifier::read(nif);
|
||||||
|
|
||||||
|
nif->read(mBounceFactor);
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(4, 2, 0, 2))
|
||||||
|
{
|
||||||
|
nif->read(mSpawnOnCollision);
|
||||||
|
nif->read(mDieOnCollision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiPlanarCollider::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
NiParticleCollider::read(nif);
|
||||||
|
|
||||||
|
nif->read(mExtents);
|
||||||
|
nif->read(mPosition);
|
||||||
|
nif->read(mXVector);
|
||||||
|
nif->read(mYVector);
|
||||||
|
nif->read(mPlaneNormal);
|
||||||
|
nif->read(mPlaneDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiSphericalCollider::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
NiParticleCollider::read(nif);
|
||||||
|
|
||||||
|
nif->read(mRadius);
|
||||||
|
nif->read(mCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiParticleRotation::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
NiParticleModifier::read(nif);
|
||||||
|
|
||||||
|
nif->read(mRandomInitialAxis);
|
||||||
|
nif->read(mInitialAxis);
|
||||||
|
nif->read(mRotationSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
90
components/nif/particle.hpp
Normal file
90
components/nif/particle.hpp
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_NIF_PARTICLE_HPP
|
||||||
|
#define OPENMW_COMPONENTS_NIF_PARTICLE_HPP
|
||||||
|
|
||||||
|
#include "base.hpp"
|
||||||
|
|
||||||
|
namespace Nif
|
||||||
|
{
|
||||||
|
|
||||||
|
struct NiParticleModifier : public Record
|
||||||
|
{
|
||||||
|
NiParticleModifierPtr mNext;
|
||||||
|
ControllerPtr mController;
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override;
|
||||||
|
void post(Reader& nif) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiParticleGrowFade : public NiParticleModifier
|
||||||
|
{
|
||||||
|
float mGrowTime;
|
||||||
|
float mFadeTime;
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiParticleColorModifier : public NiParticleModifier
|
||||||
|
{
|
||||||
|
NiColorDataPtr mData;
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override;
|
||||||
|
void post(Reader& nif) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiGravity : public NiParticleModifier
|
||||||
|
{
|
||||||
|
enum class ForceType : uint32_t
|
||||||
|
{
|
||||||
|
Wind = 0, // Fixed direction
|
||||||
|
Point = 1, // Fixed origin
|
||||||
|
};
|
||||||
|
|
||||||
|
float mDecay{ 0.f };
|
||||||
|
float mForce;
|
||||||
|
ForceType mType;
|
||||||
|
osg::Vec3f mPosition;
|
||||||
|
osg::Vec3f mDirection;
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiParticleCollider : public NiParticleModifier
|
||||||
|
{
|
||||||
|
float mBounceFactor;
|
||||||
|
bool mSpawnOnCollision{ false };
|
||||||
|
bool mDieOnCollision{ false };
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NiPinaColada
|
||||||
|
struct NiPlanarCollider : public NiParticleCollider
|
||||||
|
{
|
||||||
|
osg::Vec2f mExtents;
|
||||||
|
osg::Vec3f mPosition;
|
||||||
|
osg::Vec3f mXVector, mYVector;
|
||||||
|
osg::Vec3f mPlaneNormal;
|
||||||
|
float mPlaneDistance;
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiSphericalCollider : public NiParticleCollider
|
||||||
|
{
|
||||||
|
float mRadius;
|
||||||
|
osg::Vec3f mCenter;
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiParticleRotation : public NiParticleModifier
|
||||||
|
{
|
||||||
|
uint8_t mRandomInitialAxis;
|
||||||
|
osg::Vec3f mInitialAxis;
|
||||||
|
float mRotationSpeed;
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -12,15 +12,15 @@ namespace Nif
|
||||||
|
|
||||||
void bhkWorldObjCInfoProperty::read(NIFStream* nif)
|
void bhkWorldObjCInfoProperty::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mData = nif->getUInt();
|
nif->read(mData);
|
||||||
mSize = nif->getUInt();
|
nif->read(mSize);
|
||||||
mCapacityAndFlags = nif->getUInt();
|
nif->read(mCapacityAndFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkWorldObjectCInfo::read(NIFStream* nif)
|
void bhkWorldObjectCInfo::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
nif->skip(4); // Unused
|
nif->skip(4); // Unused
|
||||||
mPhaseType = static_cast<BroadPhaseType>(nif->getChar());
|
mPhaseType = static_cast<BroadPhaseType>(nif->get<uint8_t>());
|
||||||
nif->skip(3); // Unused
|
nif->skip(3); // Unused
|
||||||
mProperty.read(nif);
|
mProperty.read(nif);
|
||||||
}
|
}
|
||||||
|
@ -29,47 +29,47 @@ namespace Nif
|
||||||
{
|
{
|
||||||
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD)
|
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD)
|
||||||
nif->skip(4); // Unknown
|
nif->skip(4); // Unknown
|
||||||
mMaterial = nif->getUInt();
|
nif->read(mMaterial);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HavokFilter::read(NIFStream* nif)
|
void HavokFilter::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mLayer = nif->getChar();
|
nif->read(mLayer);
|
||||||
mFlags = nif->getChar();
|
nif->read(mFlags);
|
||||||
mGroup = nif->getUShort();
|
nif->read(mGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hkSubPartData::read(NIFStream* nif)
|
void hkSubPartData::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mHavokFilter.read(nif);
|
mHavokFilter.read(nif);
|
||||||
mNumVertices = nif->getUInt();
|
nif->read(mNumVertices);
|
||||||
mHavokMaterial.read(nif);
|
mHavokMaterial.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hkpMoppCode::read(NIFStream* nif)
|
|
||||||
{
|
|
||||||
unsigned int size = nif->getUInt();
|
|
||||||
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
|
|
||||||
mOffset = nif->getVector4();
|
|
||||||
if (nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3)
|
|
||||||
nif->getChar(); // MOPP data build type
|
|
||||||
nif->readVector(mData, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bhkEntityCInfo::read(NIFStream* nif)
|
void bhkEntityCInfo::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mResponseType = static_cast<hkResponseType>(nif->getChar());
|
mResponseType = static_cast<hkResponseType>(nif->get<uint8_t>());
|
||||||
nif->skip(1); // Unused
|
nif->skip(1); // Unused
|
||||||
mProcessContactDelay = nif->getUShort();
|
nif->read(mProcessContactDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hkpMoppCode::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
uint32_t dataSize;
|
||||||
|
nif->read(dataSize);
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
|
||||||
|
nif->read(mOffset);
|
||||||
|
if (nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3)
|
||||||
|
nif->read(mBuildType);
|
||||||
|
nif->readVector(mData, dataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriangleData::read(NIFStream* nif)
|
void TriangleData::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 3; i++)
|
nif->readArray(mTriangle);
|
||||||
mTriangle[i] = nif->getUShort();
|
nif->read(mWeldingInfo);
|
||||||
mWeldingInfo = nif->getUShort();
|
|
||||||
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB)
|
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB)
|
||||||
mNormal = nif->getVector3();
|
nif->read(mNormal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkMeshMaterial::read(NIFStream* nif)
|
void bhkMeshMaterial::read(NIFStream* nif)
|
||||||
|
@ -80,28 +80,27 @@ namespace Nif
|
||||||
|
|
||||||
void bhkQsTransform::read(NIFStream* nif)
|
void bhkQsTransform::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mTranslation = nif->getVector4();
|
nif->read(mTranslation);
|
||||||
mRotation = nif->getQuaternion();
|
nif->read(mRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkCMSBigTri::read(NIFStream* nif)
|
void bhkCMSBigTri::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 3; i++)
|
nif->readArray(mTriangle);
|
||||||
mTriangle[i] = nif->getUShort();
|
nif->read(mMaterial);
|
||||||
mMaterial = nif->getUInt();
|
nif->read(mWeldingInfo);
|
||||||
mWeldingInfo = nif->getUShort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkCMSChunk::read(NIFStream* nif)
|
void bhkCMSChunk::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mTranslation = nif->getVector4();
|
nif->read(mTranslation);
|
||||||
mMaterialIndex = nif->getUInt();
|
nif->read(mMaterialIndex);
|
||||||
mReference = nif->getUShort();
|
nif->read(mReference);
|
||||||
mTransformIndex = nif->getUShort();
|
nif->read(mTransformIndex);
|
||||||
nif->readVector(mVertices, nif->getUInt());
|
nif->readVector(mVertices, nif->get<uint32_t>());
|
||||||
nif->readVector(mIndices, nif->getUInt());
|
nif->readVector(mIndices, nif->get<uint32_t>());
|
||||||
nif->readVector(mStrips, nif->getUInt());
|
nif->readVector(mStrips, nif->get<uint32_t>());
|
||||||
nif->readVector(mWeldingInfos, nif->getUInt());
|
nif->readVector(mWeldingInfos, nif->get<uint32_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkRigidBodyCInfo::read(NIFStream* nif)
|
void bhkRigidBodyCInfo::read(NIFStream* nif)
|
||||||
|
@ -115,64 +114,67 @@ namespace Nif
|
||||||
{
|
{
|
||||||
if (nif->getBethVersion() >= 83)
|
if (nif->getBethVersion() >= 83)
|
||||||
nif->skip(4); // Unused
|
nif->skip(4); // Unused
|
||||||
mResponseType = static_cast<hkResponseType>(nif->getChar());
|
mResponseType = static_cast<hkResponseType>(nif->get<uint8_t>());
|
||||||
nif->skip(1); // Unused
|
nif->skip(1); // Unused
|
||||||
mProcessContactDelay = nif->getUShort();
|
nif->read(mProcessContactDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nif->getBethVersion() < 83)
|
if (nif->getBethVersion() < 83)
|
||||||
nif->skip(4); // Unused
|
nif->skip(4); // Unused
|
||||||
mTranslation = nif->getVector4();
|
nif->read(mTranslation);
|
||||||
mRotation = nif->getQuaternion();
|
nif->read(mRotation);
|
||||||
mLinearVelocity = nif->getVector4();
|
nif->read(mLinearVelocity);
|
||||||
mAngularVelocity = nif->getVector4();
|
nif->read(mAngularVelocity);
|
||||||
|
// A bit hacky, but this is the only instance where a 3x3 matrix has padding.
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
for (int j = 0; j < 4; j++)
|
{
|
||||||
mInertiaTensor[i][j] = nif->getFloat();
|
nif->read(mInertiaTensor.mValues[i], 3);
|
||||||
mCenter = nif->getVector4();
|
nif->skip(4); // Padding
|
||||||
mMass = nif->getFloat();
|
}
|
||||||
mLinearDamping = nif->getFloat();
|
nif->read(mCenter);
|
||||||
mAngularDamping = nif->getFloat();
|
nif->read(mMass);
|
||||||
|
nif->read(mLinearDamping);
|
||||||
|
nif->read(mAngularDamping);
|
||||||
if (nif->getBethVersion() >= 83)
|
if (nif->getBethVersion() >= 83)
|
||||||
{
|
{
|
||||||
if (nif->getBethVersion() != NIFFile::BethVersion::BETHVER_FO4)
|
if (nif->getBethVersion() != NIFFile::BethVersion::BETHVER_FO4)
|
||||||
mTimeFactor = nif->getFloat();
|
nif->read(mTimeFactor);
|
||||||
mGravityFactor = nif->getFloat();
|
nif->read(mGravityFactor);
|
||||||
}
|
}
|
||||||
mFriction = nif->getFloat();
|
nif->read(mFriction);
|
||||||
if (nif->getBethVersion() >= 83)
|
if (nif->getBethVersion() >= 83)
|
||||||
mRollingFrictionMult = nif->getFloat();
|
nif->read(mRollingFrictionMult);
|
||||||
mRestitution = nif->getFloat();
|
nif->read(mRestitution);
|
||||||
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
|
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
|
||||||
{
|
{
|
||||||
mMaxLinearVelocity = nif->getFloat();
|
nif->read(mMaxLinearVelocity);
|
||||||
mMaxAngularVelocity = nif->getFloat();
|
nif->read(mMaxAngularVelocity);
|
||||||
if (nif->getBethVersion() != NIFFile::BethVersion::BETHVER_FO4)
|
if (nif->getBethVersion() != NIFFile::BethVersion::BETHVER_FO4)
|
||||||
mPenetrationDepth = nif->getFloat();
|
nif->read(mPenetrationDepth);
|
||||||
}
|
}
|
||||||
mMotionType = static_cast<hkMotionType>(nif->getChar());
|
mMotionType = static_cast<hkMotionType>(nif->get<uint8_t>());
|
||||||
if (nif->getBethVersion() < 83)
|
if (nif->getBethVersion() < 83)
|
||||||
mDeactivatorType = static_cast<hkDeactivatorType>(nif->getChar());
|
mDeactivatorType = static_cast<hkDeactivatorType>(nif->get<uint8_t>());
|
||||||
else
|
else
|
||||||
mEnableDeactivation = nif->getBoolean();
|
nif->read(mEnableDeactivation);
|
||||||
mSolverDeactivation = static_cast<hkSolverDeactivation>(nif->getChar());
|
mSolverDeactivation = static_cast<hkSolverDeactivation>(nif->get<uint8_t>());
|
||||||
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_FO4)
|
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_FO4)
|
||||||
{
|
{
|
||||||
nif->skip(1);
|
nif->skip(1);
|
||||||
mPenetrationDepth = nif->getFloat();
|
nif->read(mPenetrationDepth);
|
||||||
mTimeFactor = nif->getFloat();
|
nif->read(mTimeFactor);
|
||||||
nif->skip(4);
|
nif->skip(4);
|
||||||
mResponseType = static_cast<hkResponseType>(nif->getChar());
|
mResponseType = static_cast<hkResponseType>(nif->get<uint8_t>());
|
||||||
nif->skip(1); // Unused
|
nif->skip(1); // Unused
|
||||||
mProcessContactDelay = nif->getUShort();
|
nif->read(mProcessContactDelay);
|
||||||
}
|
}
|
||||||
mQualityType = static_cast<hkQualityType>(nif->getChar());
|
mQualityType = static_cast<hkQualityType>(nif->get<uint8_t>());
|
||||||
if (nif->getBethVersion() >= 83)
|
if (nif->getBethVersion() >= 83)
|
||||||
{
|
{
|
||||||
mAutoRemoveLevel = nif->getChar();
|
nif->read(mAutoRemoveLevel);
|
||||||
mResponseModifierFlags = nif->getChar();
|
nif->read(mResponseModifierFlags);
|
||||||
mNumContactPointShapeKeys = nif->getChar();
|
nif->read(mNumContactPointShapeKeys);
|
||||||
mForceCollidedOntoPPU = nif->getBoolean();
|
nif->read(mForceCollidedOntoPPU);
|
||||||
}
|
}
|
||||||
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_FO4)
|
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_FO4)
|
||||||
nif->skip(3); // Unused
|
nif->skip(3); // Unused
|
||||||
|
@ -182,7 +184,7 @@ namespace Nif
|
||||||
|
|
||||||
void bhkConstraintCInfo::read(NIFStream* nif)
|
void bhkConstraintCInfo::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
nif->get<unsigned int>(); // Number of entities, unused
|
nif->get<uint32_t>(); // Number of entities, unused
|
||||||
mEntityA.read(nif);
|
mEntityA.read(nif);
|
||||||
mEntityB.read(nif);
|
mEntityB.read(nif);
|
||||||
|
|
||||||
|
@ -203,7 +205,7 @@ namespace Nif
|
||||||
nif->read(mDamping);
|
nif->read(mDamping);
|
||||||
nif->read(mProportionalRecoveryVelocity);
|
nif->read(mProportionalRecoveryVelocity);
|
||||||
nif->read(mConstantRecoveryVelocity);
|
nif->read(mConstantRecoveryVelocity);
|
||||||
mEnabled = nif->getBoolean();
|
nif->read(mEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkVelocityConstraintMotor::read(NIFStream* nif)
|
void bhkVelocityConstraintMotor::read(NIFStream* nif)
|
||||||
|
@ -212,8 +214,8 @@ namespace Nif
|
||||||
nif->read(mMaxForce);
|
nif->read(mMaxForce);
|
||||||
nif->read(mTau);
|
nif->read(mTau);
|
||||||
nif->read(mTargetVelocity);
|
nif->read(mTargetVelocity);
|
||||||
mUseVelocityTarget = nif->getBoolean();
|
nif->read(mUseVelocityTarget);
|
||||||
mEnabled = nif->getBoolean();
|
nif->read(mEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkSpringDamperConstraintMotor::read(NIFStream* nif)
|
void bhkSpringDamperConstraintMotor::read(NIFStream* nif)
|
||||||
|
@ -222,7 +224,7 @@ namespace Nif
|
||||||
nif->read(mMaxForce);
|
nif->read(mMaxForce);
|
||||||
nif->read(mSpringConstant);
|
nif->read(mSpringConstant);
|
||||||
nif->read(mSpringDamping);
|
nif->read(mSpringDamping);
|
||||||
mEnabled = nif->getBoolean();
|
nif->read(mEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkConstraintMotorCInfo::read(NIFStream* nif)
|
void bhkConstraintMotorCInfo::read(NIFStream* nif)
|
||||||
|
@ -335,7 +337,8 @@ namespace Nif
|
||||||
void bhkCollisionObject::read(NIFStream* nif)
|
void bhkCollisionObject::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
NiCollisionObject::read(nif);
|
NiCollisionObject::read(nif);
|
||||||
mFlags = nif->getUShort();
|
|
||||||
|
nif->read(mFlags);
|
||||||
mBody.read(nif);
|
mBody.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,6 +359,7 @@ namespace Nif
|
||||||
void bhkEntity::read(NIFStream* nif)
|
void bhkEntity::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkWorldObject::read(nif);
|
bhkWorldObject::read(nif);
|
||||||
|
|
||||||
mInfo.read(nif);
|
mInfo.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,21 +376,26 @@ namespace Nif
|
||||||
void bhkMoppBvTreeShape::read(NIFStream* nif)
|
void bhkMoppBvTreeShape::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkBvTreeShape::read(nif);
|
bhkBvTreeShape::read(nif);
|
||||||
|
|
||||||
nif->skip(12); // Unused
|
nif->skip(12); // Unused
|
||||||
mScale = nif->getFloat();
|
nif->read(mScale);
|
||||||
mMopp.read(nif);
|
mMopp.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkNiTriStripsShape::read(NIFStream* nif)
|
void bhkNiTriStripsShape::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mHavokMaterial.read(nif);
|
mHavokMaterial.read(nif);
|
||||||
mRadius = nif->getFloat();
|
nif->read(mRadius);
|
||||||
nif->skip(20); // Unused
|
nif->skip(20); // Unused
|
||||||
mGrowBy = nif->getUInt();
|
nif->read(mGrowBy);
|
||||||
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
|
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
|
||||||
mScale = nif->getVector4();
|
nif->read(mScale);
|
||||||
readRecordList(nif, mData);
|
readRecordList(nif, mData);
|
||||||
nif->readVector(mFilters, nif->getUInt());
|
uint32_t numFilters;
|
||||||
|
nif->read(numFilters);
|
||||||
|
mHavokFilters.resize(numFilters);
|
||||||
|
for (HavokFilter& filter : mHavokFilters)
|
||||||
|
filter.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkNiTriStripsShape::post(Reader& nif)
|
void bhkNiTriStripsShape::post(Reader& nif)
|
||||||
|
@ -398,15 +407,17 @@ namespace Nif
|
||||||
{
|
{
|
||||||
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB)
|
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB)
|
||||||
{
|
{
|
||||||
mSubshapes.resize(nif->getUShort());
|
uint16_t numSubshapes;
|
||||||
|
nif->read(numSubshapes);
|
||||||
|
mSubshapes.resize(numSubshapes);
|
||||||
for (hkSubPartData& subshape : mSubshapes)
|
for (hkSubPartData& subshape : mSubshapes)
|
||||||
subshape.read(nif);
|
subshape.read(nif);
|
||||||
}
|
}
|
||||||
mUserData = nif->getUInt();
|
nif->read(mUserData);
|
||||||
nif->skip(4); // Unused
|
nif->skip(4); // Unused
|
||||||
mRadius = nif->getFloat();
|
nif->read(mRadius);
|
||||||
nif->skip(4); // Unused
|
nif->skip(4); // Unused
|
||||||
mScale = nif->getVector4();
|
nif->read(mScale);
|
||||||
nif->skip(20); // Duplicates of the two previous fields
|
nif->skip(20); // Duplicates of the two previous fields
|
||||||
mData.read(nif);
|
mData.read(nif);
|
||||||
}
|
}
|
||||||
|
@ -418,22 +429,26 @@ namespace Nif
|
||||||
|
|
||||||
void hkPackedNiTriStripsData::read(NIFStream* nif)
|
void hkPackedNiTriStripsData::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
unsigned int numTriangles = nif->getUInt();
|
uint32_t numTriangles;
|
||||||
|
nif->read(numTriangles);
|
||||||
mTriangles.resize(numTriangles);
|
mTriangles.resize(numTriangles);
|
||||||
for (unsigned int i = 0; i < numTriangles; i++)
|
for (uint32_t i = 0; i < numTriangles; i++)
|
||||||
mTriangles[i].read(nif);
|
mTriangles[i].read(nif);
|
||||||
|
|
||||||
unsigned int numVertices = nif->getUInt();
|
uint32_t numVertices;
|
||||||
|
nif->read(numVertices);
|
||||||
bool compressed = false;
|
bool compressed = false;
|
||||||
if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS)
|
if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS)
|
||||||
compressed = nif->getBoolean();
|
nif->read(compressed);
|
||||||
if (!compressed)
|
if (!compressed)
|
||||||
nif->readVector(mVertices, numVertices);
|
nif->readVector(mVertices, numVertices);
|
||||||
else
|
else
|
||||||
nif->skip(6 * numVertices); // Half-precision vectors are not currently supported
|
nif->skip(6 * numVertices); // Half-precision vectors are not currently supported
|
||||||
if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS)
|
if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS)
|
||||||
{
|
{
|
||||||
mSubshapes.resize(nif->getUShort());
|
uint16_t numSubshapes;
|
||||||
|
nif->read(numSubshapes);
|
||||||
|
mSubshapes.resize(numSubshapes);
|
||||||
for (hkSubPartData& subshape : mSubshapes)
|
for (hkSubPartData& subshape : mSubshapes)
|
||||||
subshape.read(nif);
|
subshape.read(nif);
|
||||||
}
|
}
|
||||||
|
@ -447,23 +462,25 @@ namespace Nif
|
||||||
void bhkConvexShape::read(NIFStream* nif)
|
void bhkConvexShape::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkSphereRepShape::read(nif);
|
bhkSphereRepShape::read(nif);
|
||||||
mRadius = nif->getFloat();
|
|
||||||
|
nif->read(mRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkConvexVerticesShape::read(NIFStream* nif)
|
void bhkConvexVerticesShape::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkConvexShape::read(nif);
|
bhkConvexShape::read(nif);
|
||||||
|
|
||||||
mVerticesProperty.read(nif);
|
mVerticesProperty.read(nif);
|
||||||
mNormalsProperty.read(nif);
|
mNormalsProperty.read(nif);
|
||||||
nif->readVector(mVertices, nif->getUInt());
|
nif->readVector(mVertices, nif->get<uint32_t>());
|
||||||
nif->readVector(mNormals, nif->getUInt());
|
nif->readVector(mNormals, nif->get<uint32_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkConvexTransformShape::read(NIFStream* nif)
|
void bhkConvexTransformShape::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mShape.read(nif);
|
mShape.read(nif);
|
||||||
mHavokMaterial.read(nif);
|
mHavokMaterial.read(nif);
|
||||||
mRadius = nif->getFloat();
|
nif->read(mRadius);
|
||||||
nif->skip(8); // Unused
|
nif->skip(8); // Unused
|
||||||
std::array<float, 16> mat;
|
std::array<float, 16> mat;
|
||||||
nif->readArray(mat);
|
nif->readArray(mat);
|
||||||
|
@ -478,19 +495,21 @@ namespace Nif
|
||||||
void bhkBoxShape::read(NIFStream* nif)
|
void bhkBoxShape::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkConvexShape::read(nif);
|
bhkConvexShape::read(nif);
|
||||||
|
|
||||||
nif->skip(8); // Unused
|
nif->skip(8); // Unused
|
||||||
mExtents = nif->getVector3();
|
nif->read(mExtents);
|
||||||
nif->skip(4); // Unused
|
nif->skip(4); // Unused
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkCapsuleShape::read(NIFStream* nif)
|
void bhkCapsuleShape::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkConvexShape::read(nif);
|
bhkConvexShape::read(nif);
|
||||||
|
|
||||||
nif->skip(8); // Unused
|
nif->skip(8); // Unused
|
||||||
mPoint1 = nif->getVector3();
|
nif->read(mPoint1);
|
||||||
mRadius1 = nif->getFloat();
|
nif->read(mRadius1);
|
||||||
mPoint2 = nif->getVector3();
|
nif->read(mPoint2);
|
||||||
mRadius2 = nif->getFloat();
|
nif->read(mRadius2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkListShape::read(NIFStream* nif)
|
void bhkListShape::read(NIFStream* nif)
|
||||||
|
@ -499,7 +518,8 @@ namespace Nif
|
||||||
mHavokMaterial.read(nif);
|
mHavokMaterial.read(nif);
|
||||||
mChildShapeProperty.read(nif);
|
mChildShapeProperty.read(nif);
|
||||||
mChildFilterProperty.read(nif);
|
mChildFilterProperty.read(nif);
|
||||||
unsigned int numFilters = nif->getUInt();
|
uint32_t numFilters;
|
||||||
|
nif->read(numFilters);
|
||||||
mHavokFilters.resize(numFilters);
|
mHavokFilters.resize(numFilters);
|
||||||
for (HavokFilter& filter : mHavokFilters)
|
for (HavokFilter& filter : mHavokFilters)
|
||||||
filter.read(nif);
|
filter.read(nif);
|
||||||
|
@ -508,12 +528,12 @@ namespace Nif
|
||||||
void bhkCompressedMeshShape::read(NIFStream* nif)
|
void bhkCompressedMeshShape::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mTarget.read(nif);
|
mTarget.read(nif);
|
||||||
mUserData = nif->getUInt();
|
nif->read(mUserData);
|
||||||
mRadius = nif->getFloat();
|
nif->read(mRadius);
|
||||||
nif->getFloat(); // Unknown
|
nif->skip(4); // Unknown
|
||||||
mScale = nif->getVector4();
|
nif->read(mScale);
|
||||||
nif->getFloat(); // Radius
|
nif->skip(4); // Radius
|
||||||
nif->getVector4(); // Scale
|
nif->skip(16); // Scale
|
||||||
mData.read(nif);
|
mData.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,60 +545,66 @@ namespace Nif
|
||||||
|
|
||||||
void bhkCompressedMeshShapeData::read(NIFStream* nif)
|
void bhkCompressedMeshShapeData::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
mBitsPerIndex = nif->getUInt();
|
nif->read(mBitsPerIndex);
|
||||||
mBitsPerWIndex = nif->getUInt();
|
nif->read(mBitsPerWIndex);
|
||||||
mMaskWIndex = nif->getUInt();
|
nif->read(mMaskWIndex);
|
||||||
mMaskIndex = nif->getUInt();
|
nif->read(mMaskIndex);
|
||||||
mError = nif->getFloat();
|
nif->read(mError);
|
||||||
mAabbMin = nif->getVector4();
|
nif->read(mAabbMin);
|
||||||
mAabbMax = nif->getVector4();
|
nif->read(mAabbMax);
|
||||||
mWeldingType = nif->getChar();
|
nif->read(mWeldingType);
|
||||||
mMaterialType = nif->getChar();
|
nif->read(mMaterialType);
|
||||||
nif->skip(nif->getUInt() * 4); // Unused
|
nif->skip(nif->get<uint32_t>() * 4); // Unused
|
||||||
nif->skip(nif->getUInt() * 4); // Unused
|
nif->skip(nif->get<uint32_t>() * 4); // Unused
|
||||||
nif->skip(nif->getUInt() * 4); // Unused
|
nif->skip(nif->get<uint32_t>() * 4); // Unused
|
||||||
|
|
||||||
size_t numMaterials = nif->getUInt();
|
uint32_t numMaterials;
|
||||||
|
nif->read(numMaterials);
|
||||||
mMaterials.resize(numMaterials);
|
mMaterials.resize(numMaterials);
|
||||||
for (bhkMeshMaterial& material : mMaterials)
|
for (bhkMeshMaterial& material : mMaterials)
|
||||||
material.read(nif);
|
material.read(nif);
|
||||||
|
|
||||||
nif->getUInt(); // Unused
|
nif->skip(4); // Unused
|
||||||
size_t numTransforms = nif->getUInt();
|
|
||||||
|
|
||||||
|
uint32_t numTransforms;
|
||||||
|
nif->read(numTransforms);
|
||||||
mChunkTransforms.resize(numTransforms);
|
mChunkTransforms.resize(numTransforms);
|
||||||
for (bhkQsTransform& transform : mChunkTransforms)
|
for (bhkQsTransform& transform : mChunkTransforms)
|
||||||
transform.read(nif);
|
transform.read(nif);
|
||||||
|
|
||||||
nif->readVector(mBigVerts, nif->getUInt());
|
nif->readVector(mBigVerts, nif->get<uint32_t>());
|
||||||
|
|
||||||
size_t numBigTriangles = nif->getUInt();
|
uint32_t numBigTriangles;
|
||||||
|
nif->read(numBigTriangles);
|
||||||
mBigTris.resize(numBigTriangles);
|
mBigTris.resize(numBigTriangles);
|
||||||
for (bhkCMSBigTri& tri : mBigTris)
|
for (bhkCMSBigTri& tri : mBigTris)
|
||||||
tri.read(nif);
|
tri.read(nif);
|
||||||
|
|
||||||
size_t numChunks = nif->getUInt();
|
uint32_t numChunks;
|
||||||
|
nif->read(numChunks);
|
||||||
mChunks.resize(numChunks);
|
mChunks.resize(numChunks);
|
||||||
for (bhkCMSChunk& chunk : mChunks)
|
for (bhkCMSChunk& chunk : mChunks)
|
||||||
chunk.read(nif);
|
chunk.read(nif);
|
||||||
|
|
||||||
nif->getUInt(); // Unused
|
nif->skip(4); // Unused
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkRigidBody::read(NIFStream* nif)
|
void bhkRigidBody::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkEntity::read(nif);
|
bhkEntity::read(nif);
|
||||||
|
|
||||||
mInfo.read(nif);
|
mInfo.read(nif);
|
||||||
readRecordList(nif, mConstraints);
|
readRecordList(nif, mConstraints);
|
||||||
if (nif->getBethVersion() < 76)
|
if (nif->getBethVersion() < 76)
|
||||||
mBodyFlags = nif->getUInt();
|
nif->read(mBodyFlags);
|
||||||
else
|
else
|
||||||
mBodyFlags = nif->getUShort();
|
mBodyFlags = nif->get<uint16_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkSimpleShapePhantom::read(NIFStream* nif)
|
void bhkSimpleShapePhantom::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkWorldObject::read(nif);
|
bhkWorldObject::read(nif);
|
||||||
|
|
||||||
nif->skip(8); // Unused
|
nif->skip(8); // Unused
|
||||||
std::array<float, 16> mat;
|
std::array<float, 16> mat;
|
||||||
nif->readArray(mat);
|
nif->readArray(mat);
|
||||||
|
@ -598,18 +624,21 @@ namespace Nif
|
||||||
void bhkRagdollConstraint::read(NIFStream* nif)
|
void bhkRagdollConstraint::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkConstraint::read(nif);
|
bhkConstraint::read(nif);
|
||||||
|
|
||||||
mConstraint.read(nif);
|
mConstraint.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkHingeConstraint::read(NIFStream* nif)
|
void bhkHingeConstraint::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkConstraint::read(nif);
|
bhkConstraint::read(nif);
|
||||||
|
|
||||||
mConstraint.read(nif);
|
mConstraint.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bhkLimitedHingeConstraint::read(NIFStream* nif)
|
void bhkLimitedHingeConstraint::read(NIFStream* nif)
|
||||||
{
|
{
|
||||||
bhkConstraint::read(nif);
|
bhkConstraint::read(nif);
|
||||||
|
|
||||||
mConstraint.read(nif);
|
mConstraint.read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef OPENMW_COMPONENTS_NIF_PHYSICS_HPP
|
#ifndef OPENMW_COMPONENTS_NIF_PHYSICS_HPP
|
||||||
#define OPENMW_COMPONENTS_NIF_PHYSICS_HPP
|
#define OPENMW_COMPONENTS_NIF_PHYSICS_HPP
|
||||||
|
|
||||||
|
#include "niftypes.hpp"
|
||||||
#include "record.hpp"
|
#include "record.hpp"
|
||||||
#include "recordptr.hpp"
|
#include "recordptr.hpp"
|
||||||
|
|
||||||
|
@ -23,9 +24,10 @@ namespace Nif
|
||||||
|
|
||||||
struct bhkWorldObjCInfoProperty
|
struct bhkWorldObjCInfoProperty
|
||||||
{
|
{
|
||||||
unsigned int mData;
|
uint32_t mData;
|
||||||
unsigned int mSize;
|
uint32_t mSize;
|
||||||
unsigned int mCapacityAndFlags;
|
uint32_t mCapacityAndFlags;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,28 +43,32 @@ namespace Nif
|
||||||
{
|
{
|
||||||
BroadPhaseType mPhaseType;
|
BroadPhaseType mPhaseType;
|
||||||
bhkWorldObjCInfoProperty mProperty;
|
bhkWorldObjCInfoProperty mProperty;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HavokMaterial
|
struct HavokMaterial
|
||||||
{
|
{
|
||||||
unsigned int mMaterial;
|
uint32_t mMaterial;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HavokFilter
|
struct HavokFilter
|
||||||
{
|
{
|
||||||
unsigned char mLayer;
|
uint8_t mLayer;
|
||||||
unsigned char mFlags;
|
uint8_t mFlags;
|
||||||
unsigned short mGroup;
|
uint16_t mGroup;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hkSubPartData
|
struct hkSubPartData
|
||||||
{
|
{
|
||||||
HavokMaterial mHavokMaterial;
|
HavokMaterial mHavokMaterial;
|
||||||
unsigned int mNumVertices;
|
uint32_t mNumVertices;
|
||||||
HavokFilter mHavokFilter;
|
HavokFilter mHavokFilter;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,22 +83,26 @@ namespace Nif
|
||||||
struct bhkEntityCInfo
|
struct bhkEntityCInfo
|
||||||
{
|
{
|
||||||
hkResponseType mResponseType;
|
hkResponseType mResponseType;
|
||||||
unsigned short mProcessContactDelay;
|
uint16_t mProcessContactDelay;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hkpMoppCode
|
struct hkpMoppCode
|
||||||
{
|
{
|
||||||
osg::Vec4f mOffset;
|
osg::Vec4f mOffset;
|
||||||
std::vector<char> mData;
|
uint8_t mBuildType;
|
||||||
|
std::vector<uint8_t> mData;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TriangleData
|
struct TriangleData
|
||||||
{
|
{
|
||||||
unsigned short mTriangle[3];
|
std::array<uint16_t, 3> mTriangle;
|
||||||
unsigned short mWeldingInfo;
|
uint16_t mWeldingInfo;
|
||||||
osg::Vec3f mNormal;
|
osg::Vec3f mNormal;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,6 +110,7 @@ namespace Nif
|
||||||
{
|
{
|
||||||
HavokMaterial mHavokMaterial;
|
HavokMaterial mHavokMaterial;
|
||||||
HavokFilter mHavokFilter;
|
HavokFilter mHavokFilter;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,27 +118,30 @@ namespace Nif
|
||||||
{
|
{
|
||||||
osg::Vec4f mTranslation;
|
osg::Vec4f mTranslation;
|
||||||
osg::Quat mRotation;
|
osg::Quat mRotation;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bhkCMSBigTri
|
struct bhkCMSBigTri
|
||||||
{
|
{
|
||||||
unsigned short mTriangle[3];
|
std::array<uint16_t, 3> mTriangle;
|
||||||
unsigned int mMaterial;
|
uint32_t mMaterial;
|
||||||
unsigned short mWeldingInfo;
|
uint16_t mWeldingInfo;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bhkCMSChunk
|
struct bhkCMSChunk
|
||||||
{
|
{
|
||||||
osg::Vec4f mTranslation;
|
osg::Vec4f mTranslation;
|
||||||
unsigned int mMaterialIndex;
|
uint32_t mMaterialIndex;
|
||||||
unsigned short mReference;
|
uint16_t mReference;
|
||||||
unsigned short mTransformIndex;
|
uint16_t mTransformIndex;
|
||||||
std::vector<unsigned short> mVertices;
|
std::vector<uint16_t> mVertices;
|
||||||
std::vector<unsigned short> mIndices;
|
std::vector<uint16_t> mIndices;
|
||||||
std::vector<unsigned short> mStrips;
|
std::vector<uint16_t> mStrips;
|
||||||
std::vector<unsigned short> mWeldingInfos;
|
std::vector<uint16_t> mWeldingInfos;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -180,12 +194,12 @@ namespace Nif
|
||||||
{
|
{
|
||||||
HavokFilter mHavokFilter;
|
HavokFilter mHavokFilter;
|
||||||
hkResponseType mResponseType;
|
hkResponseType mResponseType;
|
||||||
unsigned short mProcessContactDelay;
|
uint16_t mProcessContactDelay;
|
||||||
osg::Vec4f mTranslation;
|
osg::Vec4f mTranslation;
|
||||||
osg::Quat mRotation;
|
osg::Quat mRotation;
|
||||||
osg::Vec4f mLinearVelocity;
|
osg::Vec4f mLinearVelocity;
|
||||||
osg::Vec4f mAngularVelocity;
|
osg::Vec4f mAngularVelocity;
|
||||||
float mInertiaTensor[3][4];
|
Matrix3 mInertiaTensor;
|
||||||
osg::Vec4f mCenter;
|
osg::Vec4f mCenter;
|
||||||
float mMass;
|
float mMass;
|
||||||
float mLinearDamping;
|
float mLinearDamping;
|
||||||
|
@ -203,10 +217,11 @@ namespace Nif
|
||||||
bool mEnableDeactivation{ true };
|
bool mEnableDeactivation{ true };
|
||||||
hkSolverDeactivation mSolverDeactivation;
|
hkSolverDeactivation mSolverDeactivation;
|
||||||
hkQualityType mQualityType;
|
hkQualityType mQualityType;
|
||||||
unsigned char mAutoRemoveLevel;
|
uint8_t mAutoRemoveLevel;
|
||||||
unsigned char mResponseModifierFlags;
|
uint8_t mResponseModifierFlags;
|
||||||
unsigned char mNumContactPointShapeKeys;
|
uint8_t mNumContactPointShapeKeys;
|
||||||
bool mForceCollidedOntoPPU;
|
bool mForceCollidedOntoPPU;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -222,6 +237,7 @@ namespace Nif
|
||||||
bhkEntityPtr mEntityA;
|
bhkEntityPtr mEntityA;
|
||||||
bhkEntityPtr mEntityB;
|
bhkEntityPtr mEntityB;
|
||||||
ConstraintPriority mPriority;
|
ConstraintPriority mPriority;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
void post(Reader& nif);
|
void post(Reader& nif);
|
||||||
};
|
};
|
||||||
|
@ -242,6 +258,7 @@ namespace Nif
|
||||||
float mProportionalRecoveryVelocity;
|
float mProportionalRecoveryVelocity;
|
||||||
float mConstantRecoveryVelocity;
|
float mConstantRecoveryVelocity;
|
||||||
bool mEnabled;
|
bool mEnabled;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -252,6 +269,7 @@ namespace Nif
|
||||||
float mTargetVelocity;
|
float mTargetVelocity;
|
||||||
bool mUseVelocityTarget;
|
bool mUseVelocityTarget;
|
||||||
bool mEnabled;
|
bool mEnabled;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -261,6 +279,7 @@ namespace Nif
|
||||||
float mSpringConstant;
|
float mSpringConstant;
|
||||||
float mSpringDamping;
|
float mSpringDamping;
|
||||||
bool mEnabled;
|
bool mEnabled;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -270,6 +289,7 @@ namespace Nif
|
||||||
bhkPositionConstraintMotor mPositionMotor;
|
bhkPositionConstraintMotor mPositionMotor;
|
||||||
bhkVelocityConstraintMotor mVelocityMotor;
|
bhkVelocityConstraintMotor mVelocityMotor;
|
||||||
bhkSpringDamperConstraintMotor mSpringDamperMotor;
|
bhkSpringDamperConstraintMotor mSpringDamperMotor;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -289,6 +309,7 @@ namespace Nif
|
||||||
float mTwistMinAngle, mTwistMaxAngle;
|
float mTwistMinAngle, mTwistMaxAngle;
|
||||||
float mMaxFriction;
|
float mMaxFriction;
|
||||||
bhkConstraintMotorCInfo mMotor;
|
bhkConstraintMotorCInfo mMotor;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -301,8 +322,10 @@ namespace Nif
|
||||||
osg::Vec4f mPerpAxis1;
|
osg::Vec4f mPerpAxis1;
|
||||||
osg::Vec4f mPerpAxis2;
|
osg::Vec4f mPerpAxis2;
|
||||||
};
|
};
|
||||||
|
|
||||||
HingeData mDataA;
|
HingeData mDataA;
|
||||||
HingeData mDataB;
|
HingeData mDataB;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -315,11 +338,13 @@ namespace Nif
|
||||||
osg::Vec4f mPerpAxis1;
|
osg::Vec4f mPerpAxis1;
|
||||||
osg::Vec4f mPerpAxis2;
|
osg::Vec4f mPerpAxis2;
|
||||||
};
|
};
|
||||||
|
|
||||||
HingeData mDataA;
|
HingeData mDataA;
|
||||||
HingeData mDataB;
|
HingeData mDataB;
|
||||||
float mMinAngle, mMaxAngle;
|
float mMinAngle, mMaxAngle;
|
||||||
float mMaxFriction;
|
float mMaxFriction;
|
||||||
bhkConstraintMotorCInfo mMotor;
|
bhkConstraintMotorCInfo mMotor;
|
||||||
|
|
||||||
void read(NIFStream* nif);
|
void read(NIFStream* nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -358,7 +383,7 @@ namespace Nif
|
||||||
// Bethesda Havok-specific collision object
|
// Bethesda Havok-specific collision object
|
||||||
struct bhkCollisionObject : public NiCollisionObject
|
struct bhkCollisionObject : public NiCollisionObject
|
||||||
{
|
{
|
||||||
unsigned short mFlags;
|
uint16_t mFlags;
|
||||||
bhkWorldObjectPtr mBody;
|
bhkWorldObjectPtr mBody;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
|
@ -375,6 +400,7 @@ namespace Nif
|
||||||
bhkShapePtr mShape;
|
bhkShapePtr mShape;
|
||||||
HavokFilter mHavokFilter;
|
HavokFilter mHavokFilter;
|
||||||
bhkWorldObjectCInfo mWorldObjectInfo;
|
bhkWorldObjectCInfo mWorldObjectInfo;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
void post(Reader& nif) override;
|
void post(Reader& nif) override;
|
||||||
};
|
};
|
||||||
|
@ -383,6 +409,7 @@ namespace Nif
|
||||||
struct bhkEntity : public bhkWorldObject
|
struct bhkEntity : public bhkWorldObject
|
||||||
{
|
{
|
||||||
bhkEntityCInfo mInfo;
|
bhkEntityCInfo mInfo;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -391,6 +418,7 @@ namespace Nif
|
||||||
struct bhkBvTreeShape : public bhkShape
|
struct bhkBvTreeShape : public bhkShape
|
||||||
{
|
{
|
||||||
bhkShapePtr mShape;
|
bhkShapePtr mShape;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
void post(Reader& nif) override;
|
void post(Reader& nif) override;
|
||||||
};
|
};
|
||||||
|
@ -400,6 +428,7 @@ namespace Nif
|
||||||
{
|
{
|
||||||
float mScale;
|
float mScale;
|
||||||
hkpMoppCode mMopp;
|
hkpMoppCode mMopp;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -408,10 +437,11 @@ namespace Nif
|
||||||
{
|
{
|
||||||
HavokMaterial mHavokMaterial;
|
HavokMaterial mHavokMaterial;
|
||||||
float mRadius;
|
float mRadius;
|
||||||
unsigned int mGrowBy;
|
uint32_t mGrowBy;
|
||||||
osg::Vec4f mScale{ 1.f, 1.f, 1.f, 0.f };
|
osg::Vec4f mScale{ 1.f, 1.f, 1.f, 0.f };
|
||||||
NiTriStripsDataList mData;
|
NiTriStripsDataList mData;
|
||||||
std::vector<unsigned int> mFilters;
|
std::vector<HavokFilter> mHavokFilters;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
void post(Reader& nif) override;
|
void post(Reader& nif) override;
|
||||||
};
|
};
|
||||||
|
@ -420,7 +450,7 @@ namespace Nif
|
||||||
struct bhkPackedNiTriStripsShape : public bhkShapeCollection
|
struct bhkPackedNiTriStripsShape : public bhkShapeCollection
|
||||||
{
|
{
|
||||||
std::vector<hkSubPartData> mSubshapes;
|
std::vector<hkSubPartData> mSubshapes;
|
||||||
unsigned int mUserData;
|
uint32_t mUserData;
|
||||||
float mRadius;
|
float mRadius;
|
||||||
osg::Vec4f mScale;
|
osg::Vec4f mScale;
|
||||||
hkPackedNiTriStripsDataPtr mData;
|
hkPackedNiTriStripsDataPtr mData;
|
||||||
|
@ -435,6 +465,7 @@ namespace Nif
|
||||||
std::vector<TriangleData> mTriangles;
|
std::vector<TriangleData> mTriangles;
|
||||||
std::vector<osg::Vec3f> mVertices;
|
std::vector<osg::Vec3f> mVertices;
|
||||||
std::vector<hkSubPartData> mSubshapes;
|
std::vector<hkSubPartData> mSubshapes;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -442,6 +473,7 @@ namespace Nif
|
||||||
struct bhkSphereRepShape : public bhkShape
|
struct bhkSphereRepShape : public bhkShape
|
||||||
{
|
{
|
||||||
HavokMaterial mHavokMaterial;
|
HavokMaterial mHavokMaterial;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -449,6 +481,7 @@ namespace Nif
|
||||||
struct bhkConvexShape : public bhkSphereRepShape
|
struct bhkConvexShape : public bhkSphereRepShape
|
||||||
{
|
{
|
||||||
float mRadius;
|
float mRadius;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -459,6 +492,7 @@ namespace Nif
|
||||||
bhkWorldObjCInfoProperty mNormalsProperty;
|
bhkWorldObjCInfoProperty mNormalsProperty;
|
||||||
std::vector<osg::Vec4f> mVertices;
|
std::vector<osg::Vec4f> mVertices;
|
||||||
std::vector<osg::Vec4f> mNormals;
|
std::vector<osg::Vec4f> mNormals;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -468,6 +502,7 @@ namespace Nif
|
||||||
HavokMaterial mHavokMaterial;
|
HavokMaterial mHavokMaterial;
|
||||||
float mRadius;
|
float mRadius;
|
||||||
osg::Matrixf mTransform;
|
osg::Matrixf mTransform;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
void post(Reader& nif) override;
|
void post(Reader& nif) override;
|
||||||
};
|
};
|
||||||
|
@ -476,6 +511,7 @@ namespace Nif
|
||||||
struct bhkBoxShape : public bhkConvexShape
|
struct bhkBoxShape : public bhkConvexShape
|
||||||
{
|
{
|
||||||
osg::Vec3f mExtents;
|
osg::Vec3f mExtents;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -499,28 +535,30 @@ namespace Nif
|
||||||
bhkWorldObjCInfoProperty mChildShapeProperty;
|
bhkWorldObjCInfoProperty mChildShapeProperty;
|
||||||
bhkWorldObjCInfoProperty mChildFilterProperty;
|
bhkWorldObjCInfoProperty mChildFilterProperty;
|
||||||
std::vector<HavokFilter> mHavokFilters;
|
std::vector<HavokFilter> mHavokFilters;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bhkCompressedMeshShape : public bhkShape
|
struct bhkCompressedMeshShape : public bhkShape
|
||||||
{
|
{
|
||||||
NodePtr mTarget;
|
NodePtr mTarget;
|
||||||
unsigned int mUserData;
|
uint32_t mUserData;
|
||||||
float mRadius;
|
float mRadius;
|
||||||
osg::Vec4f mScale;
|
osg::Vec4f mScale;
|
||||||
bhkCompressedMeshShapeDataPtr mData;
|
bhkCompressedMeshShapeDataPtr mData;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
void post(Reader& nif) override;
|
void post(Reader& nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bhkCompressedMeshShapeData : public bhkRefObject
|
struct bhkCompressedMeshShapeData : public bhkRefObject
|
||||||
{
|
{
|
||||||
unsigned int mBitsPerIndex, mBitsPerWIndex;
|
uint32_t mBitsPerIndex, mBitsPerWIndex;
|
||||||
unsigned int mMaskWIndex, mMaskIndex;
|
uint32_t mMaskWIndex, mMaskIndex;
|
||||||
float mError;
|
float mError;
|
||||||
osg::Vec4f mAabbMin, mAabbMax;
|
osg::Vec4f mAabbMin, mAabbMax;
|
||||||
char mWeldingType;
|
uint8_t mWeldingType;
|
||||||
char mMaterialType;
|
uint8_t mMaterialType;
|
||||||
std::vector<bhkMeshMaterial> mMaterials;
|
std::vector<bhkMeshMaterial> mMaterials;
|
||||||
std::vector<bhkQsTransform> mChunkTransforms;
|
std::vector<bhkQsTransform> mChunkTransforms;
|
||||||
std::vector<osg::Vec4f> mBigVerts;
|
std::vector<osg::Vec4f> mBigVerts;
|
||||||
|
@ -534,7 +572,7 @@ namespace Nif
|
||||||
{
|
{
|
||||||
bhkRigidBodyCInfo mInfo;
|
bhkRigidBodyCInfo mInfo;
|
||||||
bhkSerializableList mConstraints;
|
bhkSerializableList mConstraints;
|
||||||
unsigned int mBodyFlags;
|
uint32_t mBodyFlags;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
@ -542,6 +580,7 @@ namespace Nif
|
||||||
struct bhkSimpleShapePhantom : public bhkWorldObject
|
struct bhkSimpleShapePhantom : public bhkWorldObject
|
||||||
{
|
{
|
||||||
osg::Matrixf mTransform;
|
osg::Matrixf mTransform;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -549,6 +588,7 @@ namespace Nif
|
||||||
struct bhkConstraint : public bhkSerializable
|
struct bhkConstraint : public bhkSerializable
|
||||||
{
|
{
|
||||||
bhkConstraintCInfo mInfo;
|
bhkConstraintCInfo mInfo;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
void post(Reader& nif) override;
|
void post(Reader& nif) override;
|
||||||
};
|
};
|
||||||
|
@ -556,18 +596,21 @@ namespace Nif
|
||||||
struct bhkRagdollConstraint : public bhkConstraint
|
struct bhkRagdollConstraint : public bhkConstraint
|
||||||
{
|
{
|
||||||
bhkRagdollConstraintCInfo mConstraint;
|
bhkRagdollConstraintCInfo mConstraint;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bhkHingeConstraint : public bhkConstraint
|
struct bhkHingeConstraint : public bhkConstraint
|
||||||
{
|
{
|
||||||
bhkHingeConstraintCInfo mConstraint;
|
bhkHingeConstraintCInfo mConstraint;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bhkLimitedHingeConstraint : public bhkConstraint
|
struct bhkLimitedHingeConstraint : public bhkConstraint
|
||||||
{
|
{
|
||||||
bhkLimitedHingeConstraintCInfo mConstraint;
|
bhkLimitedHingeConstraintCInfo mConstraint;
|
||||||
|
|
||||||
void read(NIFStream* nif) override;
|
void read(NIFStream* nif) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "property.hpp"
|
#include "property.hpp"
|
||||||
|
|
||||||
#include "controlled.hpp"
|
|
||||||
#include "data.hpp"
|
#include "data.hpp"
|
||||||
|
#include "texture.hpp"
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
|
47
components/nif/texture.cpp
Normal file
47
components/nif/texture.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include "texture.hpp"
|
||||||
|
|
||||||
|
#include "data.hpp"
|
||||||
|
|
||||||
|
namespace Nif
|
||||||
|
{
|
||||||
|
|
||||||
|
void NiSourceTexture::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
NiTexture::read(nif);
|
||||||
|
|
||||||
|
nif->read(mExternal);
|
||||||
|
if (mExternal || nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
|
||||||
|
nif->read(mFile);
|
||||||
|
|
||||||
|
bool hasData = nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 4);
|
||||||
|
if (!hasData && !mExternal)
|
||||||
|
nif->read(hasData);
|
||||||
|
|
||||||
|
if (hasData)
|
||||||
|
mData.read(nif);
|
||||||
|
|
||||||
|
mPrefs.mPixelLayout = static_cast<PixelLayout>(nif->get<uint32_t>());
|
||||||
|
mPrefs.mUseMipMaps = static_cast<MipMapFormat>(nif->get<uint32_t>());
|
||||||
|
mPrefs.mAlphaFormat = static_cast<AlphaFormat>(nif->get<uint32_t>());
|
||||||
|
|
||||||
|
nif->read(mIsStatic);
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 103))
|
||||||
|
{
|
||||||
|
nif->read(mDirectRendering);
|
||||||
|
if (nif->getVersion() >= NIFStream::generateVersion(20, 2, 0, 4))
|
||||||
|
nif->read(mPersistRenderData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NiSourceTexture::post(Reader& nif)
|
||||||
|
{
|
||||||
|
NiTexture::post(nif);
|
||||||
|
mData.post(nif);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSShaderTextureSet::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
nif->getSizedStrings(mTextures, nif->get<uint32_t>());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
81
components/nif/texture.hpp
Normal file
81
components/nif/texture.hpp
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_NIF_TEXTURE_HPP
|
||||||
|
#define OPENMW_COMPONENTS_NIF_TEXTURE_HPP
|
||||||
|
|
||||||
|
#include "base.hpp"
|
||||||
|
|
||||||
|
namespace Nif
|
||||||
|
{
|
||||||
|
|
||||||
|
struct NiTexture : public Named
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiSourceTexture : public NiTexture
|
||||||
|
{
|
||||||
|
enum class PixelLayout : uint32_t
|
||||||
|
{
|
||||||
|
Palette = 0,
|
||||||
|
HighColor = 1,
|
||||||
|
TrueColor = 2,
|
||||||
|
Compressed = 3,
|
||||||
|
BumpMap = 4,
|
||||||
|
Default = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MipMapFormat : uint32_t
|
||||||
|
{
|
||||||
|
No = 0,
|
||||||
|
Yes = 1,
|
||||||
|
Default = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AlphaFormat : uint32_t
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Binary = 1,
|
||||||
|
Smooth = 2,
|
||||||
|
Default = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FormatPrefs
|
||||||
|
{
|
||||||
|
PixelLayout mPixelLayout;
|
||||||
|
MipMapFormat mUseMipMaps;
|
||||||
|
AlphaFormat mAlphaFormat;
|
||||||
|
};
|
||||||
|
|
||||||
|
char mExternal; // References external file
|
||||||
|
|
||||||
|
std::string mFile;
|
||||||
|
NiPixelDataPtr mData;
|
||||||
|
|
||||||
|
FormatPrefs mPrefs;
|
||||||
|
|
||||||
|
char mIsStatic{ 1 };
|
||||||
|
bool mDirectRendering{ true };
|
||||||
|
bool mPersistRenderData{ false };
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override;
|
||||||
|
void post(Reader& nif) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BSShaderTextureSet : public Record
|
||||||
|
{
|
||||||
|
enum class TextureType : uint32_t
|
||||||
|
{
|
||||||
|
Base = 0,
|
||||||
|
Normal = 1,
|
||||||
|
Glow = 2,
|
||||||
|
Parallax = 3,
|
||||||
|
Environment = 4,
|
||||||
|
EnvironmentMask = 5,
|
||||||
|
Subsurface = 6,
|
||||||
|
BackLighting = 7,
|
||||||
|
};
|
||||||
|
std::vector<std::string> mTextures;
|
||||||
|
|
||||||
|
void read(NIFStream* nif) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -305,7 +305,7 @@ namespace NifBullet
|
||||||
|
|
||||||
// Check for extra data
|
// Check for extra data
|
||||||
std::vector<Nif::ExtraPtr> extraCollection;
|
std::vector<Nif::ExtraPtr> extraCollection;
|
||||||
for (Nif::ExtraPtr e = node.extra; !e.empty(); e = e->next)
|
for (Nif::ExtraPtr e = node.extra; !e.empty(); e = e->mNext)
|
||||||
extraCollection.emplace_back(e);
|
extraCollection.emplace_back(e);
|
||||||
for (const auto& extraNode : node.extralist)
|
for (const auto& extraNode : node.extralist)
|
||||||
if (!extraNode.empty())
|
if (!extraNode.empty())
|
||||||
|
@ -316,29 +316,30 @@ namespace NifBullet
|
||||||
{
|
{
|
||||||
// String markers may contain important information
|
// String markers may contain important information
|
||||||
// affecting the entire subtree of this node
|
// affecting the entire subtree of this node
|
||||||
Nif::NiStringExtraData* sd = (Nif::NiStringExtraData*)e.getPtr();
|
auto sd = static_cast<const Nif::NiStringExtraData*>(e.getPtr());
|
||||||
|
|
||||||
if (Misc::StringUtils::ciStartsWith(sd->string, "NC"))
|
if (Misc::StringUtils::ciStartsWith(sd->mData, "NC"))
|
||||||
{
|
{
|
||||||
// NCC flag in vanilla is partly case sensitive: prefix NC is case insensitive but second C needs be
|
// NCC flag in vanilla is partly case sensitive: prefix NC is case insensitive but second C needs be
|
||||||
// uppercase
|
// uppercase
|
||||||
if (sd->string.length() > 2 && sd->string[2] == 'C')
|
if (sd->mData.length() > 2 && sd->mData[2] == 'C')
|
||||||
// Collide only with camera.
|
// Collide only with camera.
|
||||||
visualCollisionType = Resource::VisualCollisionType::Camera;
|
visualCollisionType = Resource::VisualCollisionType::Camera;
|
||||||
else
|
else
|
||||||
// No collision.
|
// No collision.
|
||||||
visualCollisionType = Resource::VisualCollisionType::Default;
|
visualCollisionType = Resource::VisualCollisionType::Default;
|
||||||
}
|
}
|
||||||
else if (sd->string == "MRK" && args.mAutogenerated)
|
// Don't autogenerate collision if MRK is set.
|
||||||
|
// FIXME: verify if this covers the entire subtree
|
||||||
|
else if (sd->mData == "MRK" && args.mAutogenerated)
|
||||||
{
|
{
|
||||||
// Marker can still have collision if the model explicitely specifies it via a RootCollisionNode.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (e->recType == Nif::RC_BSXFlags)
|
else if (e->recType == Nif::RC_BSXFlags)
|
||||||
{
|
{
|
||||||
auto bsxFlags = static_cast<const Nif::NiIntegerExtraData*>(e.getPtr());
|
auto bsxFlags = static_cast<const Nif::NiIntegerExtraData*>(e.getPtr());
|
||||||
if (bsxFlags->data & 32) // Editor marker flag
|
if (bsxFlags->mData & 32) // Editor marker flag
|
||||||
args.mHasMarkers = true;
|
args.mHasMarkers = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,13 +42,14 @@
|
||||||
#include <osg/TexEnvCombine>
|
#include <osg/TexEnvCombine>
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
|
|
||||||
#include <components/nif/controlled.hpp>
|
|
||||||
#include <components/nif/effect.hpp>
|
#include <components/nif/effect.hpp>
|
||||||
#include <components/nif/exception.hpp>
|
#include <components/nif/exception.hpp>
|
||||||
#include <components/nif/extra.hpp>
|
#include <components/nif/extra.hpp>
|
||||||
#include <components/nif/niffile.hpp>
|
#include <components/nif/niffile.hpp>
|
||||||
#include <components/nif/node.hpp>
|
#include <components/nif/node.hpp>
|
||||||
|
#include <components/nif/particle.hpp>
|
||||||
#include <components/nif/property.hpp>
|
#include <components/nif/property.hpp>
|
||||||
|
#include <components/nif/texture.hpp>
|
||||||
#include <components/sceneutil/depth.hpp>
|
#include <components/sceneutil/depth.hpp>
|
||||||
#include <components/sceneutil/morphgeometry.hpp>
|
#include <components/sceneutil/morphgeometry.hpp>
|
||||||
#include <components/sceneutil/riggeometry.hpp>
|
#include <components/sceneutil/riggeometry.hpp>
|
||||||
|
@ -174,16 +175,16 @@ namespace
|
||||||
|
|
||||||
void extractTextKeys(const Nif::NiTextKeyExtraData* tk, SceneUtil::TextKeyMap& textkeys)
|
void extractTextKeys(const Nif::NiTextKeyExtraData* tk, SceneUtil::TextKeyMap& textkeys)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < tk->list.size(); i++)
|
for (const Nif::NiTextKeyExtraData::TextKey& key : tk->mList)
|
||||||
{
|
{
|
||||||
std::vector<std::string> results;
|
std::vector<std::string> results;
|
||||||
Misc::StringUtils::split(tk->list[i].text, results, "\r\n");
|
Misc::StringUtils::split(key.mText, results, "\r\n");
|
||||||
for (std::string& result : results)
|
for (std::string& result : results)
|
||||||
{
|
{
|
||||||
Misc::StringUtils::trim(result);
|
Misc::StringUtils::trim(result);
|
||||||
Misc::StringUtils::lowerCaseInPlace(result);
|
Misc::StringUtils::lowerCaseInPlace(result);
|
||||||
if (!result.empty())
|
if (!result.empty())
|
||||||
textkeys.emplace(tk->list[i].time, std::move(result));
|
textkeys.emplace(key.mTime, std::move(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,9 +286,9 @@ namespace NifOsg
|
||||||
|
|
||||||
extractTextKeys(static_cast<const Nif::NiTextKeyExtraData*>(extra.getPtr()), target.mTextKeys);
|
extractTextKeys(static_cast<const Nif::NiTextKeyExtraData*>(extra.getPtr()), target.mTextKeys);
|
||||||
|
|
||||||
extra = extra->next;
|
extra = extra->mNext;
|
||||||
Nif::ControllerPtr ctrl = seq->controller;
|
Nif::ControllerPtr ctrl = seq->controller;
|
||||||
for (; !extra.empty() && !ctrl.empty(); (extra = extra->next), (ctrl = ctrl->next))
|
for (; !extra.empty() && !ctrl.empty(); (extra = extra->mNext), (ctrl = ctrl->next))
|
||||||
{
|
{
|
||||||
if (extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController)
|
if (extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController)
|
||||||
{
|
{
|
||||||
|
@ -315,8 +316,8 @@ namespace NifOsg
|
||||||
osg::ref_ptr<SceneUtil::KeyframeController> callback = new NifOsg::KeyframeController(key);
|
osg::ref_ptr<SceneUtil::KeyframeController> callback = new NifOsg::KeyframeController(key);
|
||||||
setupController(key, callback, /*animflags*/ 0);
|
setupController(key, callback, /*animflags*/ 0);
|
||||||
|
|
||||||
if (!target.mKeyframeControllers.emplace(strdata->string, callback).second)
|
if (!target.mKeyframeControllers.emplace(strdata->mData, callback).second)
|
||||||
Log(Debug::Verbose) << "Controller " << strdata->string << " present more than once in "
|
Log(Debug::Verbose) << "Controller " << strdata->mData << " present more than once in "
|
||||||
<< nif.getFilename() << ", ignoring later version";
|
<< nif.getFilename() << ", ignoring later version";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,15 +510,15 @@ namespace NifOsg
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
osg::ref_ptr<osg::Image> image;
|
osg::ref_ptr<osg::Image> image;
|
||||||
if (!st->external && !st->data.empty())
|
if (st->mExternal)
|
||||||
{
|
{
|
||||||
image = handleInternalTexture(st->data.getPtr());
|
std::string filename = Misc::ResourceHelpers::correctTexturePath(st->mFile, imageManager->getVFS());
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, imageManager->getVFS());
|
|
||||||
image = imageManager->getImage(filename);
|
image = imageManager->getImage(filename);
|
||||||
}
|
}
|
||||||
|
else if (!st->mData.empty())
|
||||||
|
{
|
||||||
|
image = handleInternalTexture(st->mData.getPtr());
|
||||||
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,38 +537,41 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
|
|
||||||
const Nif::NiTextureEffect* textureEffect = static_cast<const Nif::NiTextureEffect*>(nifNode);
|
const Nif::NiTextureEffect* textureEffect = static_cast<const Nif::NiTextureEffect*>(nifNode);
|
||||||
if (textureEffect->textureType != Nif::NiTextureEffect::Environment_Map)
|
if (!textureEffect->mSwitchState)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (textureEffect->mTextureType != Nif::NiTextureEffect::TextureType::EnvironmentMap)
|
||||||
{
|
{
|
||||||
Log(Debug::Info) << "Unhandled NiTextureEffect type " << textureEffect->textureType << " in "
|
Log(Debug::Info) << "Unhandled NiTextureEffect type "
|
||||||
<< mFilename;
|
<< static_cast<uint32_t>(textureEffect->mTextureType) << " in " << mFilename;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textureEffect->texture.empty())
|
if (textureEffect->mTexture.empty())
|
||||||
{
|
{
|
||||||
Log(Debug::Info) << "NiTextureEffect missing source texture in " << mFilename;
|
Log(Debug::Info) << "NiTextureEffect missing source texture in " << mFilename;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::TexGen> texGen(new osg::TexGen);
|
osg::ref_ptr<osg::TexGen> texGen(new osg::TexGen);
|
||||||
switch (textureEffect->coordGenType)
|
switch (textureEffect->mCoordGenType)
|
||||||
{
|
{
|
||||||
case Nif::NiTextureEffect::World_Parallel:
|
case Nif::NiTextureEffect::CoordGenType::WorldParallel:
|
||||||
texGen->setMode(osg::TexGen::OBJECT_LINEAR);
|
texGen->setMode(osg::TexGen::OBJECT_LINEAR);
|
||||||
break;
|
break;
|
||||||
case Nif::NiTextureEffect::World_Perspective:
|
case Nif::NiTextureEffect::CoordGenType::WorldPerspective:
|
||||||
texGen->setMode(osg::TexGen::EYE_LINEAR);
|
texGen->setMode(osg::TexGen::EYE_LINEAR);
|
||||||
break;
|
break;
|
||||||
case Nif::NiTextureEffect::Sphere_Map:
|
case Nif::NiTextureEffect::CoordGenType::SphereMap:
|
||||||
texGen->setMode(osg::TexGen::SPHERE_MAP);
|
texGen->setMode(osg::TexGen::SPHERE_MAP);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Log(Debug::Info) << "Unhandled NiTextureEffect coordGenType " << textureEffect->coordGenType
|
Log(Debug::Info) << "Unhandled NiTextureEffect CoordGenType "
|
||||||
<< " in " << mFilename;
|
<< static_cast<uint32_t>(textureEffect->mCoordGenType) << " in " << mFilename;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Image> image(handleSourceTexture(textureEffect->texture.getPtr(), imageManager));
|
osg::ref_ptr<osg::Image> image(handleSourceTexture(textureEffect->mTexture.getPtr(), imageManager));
|
||||||
osg::ref_ptr<osg::Texture2D> texture2d(new osg::Texture2D(image));
|
osg::ref_ptr<osg::Texture2D> texture2d(new osg::Texture2D(image));
|
||||||
if (image)
|
if (image)
|
||||||
texture2d->setTextureSize(image->s(), image->t());
|
texture2d->setTextureSize(image->s(), image->t());
|
||||||
|
@ -644,7 +648,7 @@ namespace NifOsg
|
||||||
|
|
||||||
std::vector<Nif::ExtraPtr> extraCollection;
|
std::vector<Nif::ExtraPtr> extraCollection;
|
||||||
|
|
||||||
for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->next)
|
for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->mNext)
|
||||||
extraCollection.emplace_back(e);
|
extraCollection.emplace_back(e);
|
||||||
|
|
||||||
for (const auto& extraNode : nifNode->extralist)
|
for (const auto& extraNode : nifNode->extralist)
|
||||||
|
@ -666,25 +670,25 @@ namespace NifOsg
|
||||||
|
|
||||||
// String markers may contain important information
|
// String markers may contain important information
|
||||||
// affecting the entire subtree of this obj
|
// affecting the entire subtree of this obj
|
||||||
if (sd->string == "MRK" && !Loader::getShowMarkers())
|
if (sd->mData == "MRK" && !Loader::getShowMarkers())
|
||||||
{
|
{
|
||||||
// Marker objects. These meshes are only visible in the editor.
|
// Marker objects. These meshes are only visible in the editor.
|
||||||
args.mHasMarkers = true;
|
args.mHasMarkers = true;
|
||||||
}
|
}
|
||||||
else if (sd->string == "BONE")
|
else if (sd->mData == "BONE")
|
||||||
{
|
{
|
||||||
node->getOrCreateUserDataContainer()->addDescription("CustomBone");
|
node->getOrCreateUserDataContainer()->addDescription("CustomBone");
|
||||||
}
|
}
|
||||||
else if (sd->string.rfind(extraDataIdentifer, 0) == 0)
|
else if (sd->mData.rfind(extraDataIdentifer, 0) == 0)
|
||||||
{
|
{
|
||||||
node->setUserValue(
|
node->setUserValue(
|
||||||
Misc::OsgUserValues::sExtraData, sd->string.substr(extraDataIdentifer.length()));
|
Misc::OsgUserValues::sExtraData, sd->mData.substr(extraDataIdentifer.length()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (e->recType == Nif::RC_BSXFlags)
|
else if (e->recType == Nif::RC_BSXFlags)
|
||||||
{
|
{
|
||||||
auto bsxFlags = static_cast<const Nif::NiIntegerExtraData*>(e.getPtr());
|
auto bsxFlags = static_cast<const Nif::NiIntegerExtraData*>(e.getPtr());
|
||||||
if (bsxFlags->data & 32) // Editor marker flag
|
if (bsxFlags->mData & 32) // Editor marker flag
|
||||||
args.mHasMarkers = true;
|
args.mHasMarkers = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -895,7 +899,7 @@ namespace NifOsg
|
||||||
if (!key->mInterpolator.empty() && key->mInterpolator->recType != Nif::RC_NiTransformInterpolator)
|
if (!key->mInterpolator.empty() && key->mInterpolator->recType != Nif::RC_NiTransformInterpolator)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Unsupported interpolator type for NiKeyframeController " << key->recIndex
|
Log(Debug::Error) << "Unsupported interpolator type for NiKeyframeController " << key->recIndex
|
||||||
<< " in " << mFilename;
|
<< " in " << mFilename << ": " << key->mInterpolator->recName;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
osg::ref_ptr<KeyframeController> callback = new KeyframeController(key);
|
osg::ref_ptr<KeyframeController> callback = new KeyframeController(key);
|
||||||
|
@ -922,7 +926,7 @@ namespace NifOsg
|
||||||
&& visctrl->mInterpolator->recType != Nif::RC_NiBoolInterpolator)
|
&& visctrl->mInterpolator->recType != Nif::RC_NiBoolInterpolator)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Unsupported interpolator type for NiVisController " << visctrl->recIndex
|
Log(Debug::Error) << "Unsupported interpolator type for NiVisController " << visctrl->recIndex
|
||||||
<< " in " << mFilename;
|
<< " in " << mFilename << ": " << visctrl->mInterpolator->recName;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
osg::ref_ptr<VisController> callback(new VisController(visctrl, Loader::getHiddenNodeMask()));
|
osg::ref_ptr<VisController> callback(new VisController(visctrl, Loader::getHiddenNodeMask()));
|
||||||
|
@ -938,7 +942,7 @@ namespace NifOsg
|
||||||
&& rollctrl->mInterpolator->recType != Nif::RC_NiFloatInterpolator)
|
&& rollctrl->mInterpolator->recType != Nif::RC_NiFloatInterpolator)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Unsupported interpolator type for NiRollController " << rollctrl->recIndex
|
Log(Debug::Error) << "Unsupported interpolator type for NiRollController " << rollctrl->recIndex
|
||||||
<< " in " << mFilename;
|
<< " in " << mFilename << ": " << rollctrl->mInterpolator->recName;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
osg::ref_ptr<RollController> callback = new RollController(rollctrl);
|
osg::ref_ptr<RollController> callback = new RollController(rollctrl);
|
||||||
|
@ -973,8 +977,9 @@ namespace NifOsg
|
||||||
if (!alphactrl->mInterpolator.empty()
|
if (!alphactrl->mInterpolator.empty()
|
||||||
&& alphactrl->mInterpolator->recType != Nif::RC_NiFloatInterpolator)
|
&& alphactrl->mInterpolator->recType != Nif::RC_NiFloatInterpolator)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Unsupported interpolator type for NiAlphaController "
|
Log(Debug::Error)
|
||||||
<< alphactrl->recIndex << " in " << mFilename;
|
<< "Unsupported interpolator type for NiAlphaController " << alphactrl->recIndex << " in "
|
||||||
|
<< mFilename << ": " << alphactrl->mInterpolator->recName;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
osg::ref_ptr<AlphaController> osgctrl = new AlphaController(alphactrl, baseMaterial);
|
osg::ref_ptr<AlphaController> osgctrl = new AlphaController(alphactrl, baseMaterial);
|
||||||
|
@ -994,8 +999,9 @@ namespace NifOsg
|
||||||
if (!matctrl->mInterpolator.empty()
|
if (!matctrl->mInterpolator.empty()
|
||||||
&& matctrl->mInterpolator->recType != Nif::RC_NiPoint3Interpolator)
|
&& matctrl->mInterpolator->recType != Nif::RC_NiPoint3Interpolator)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Unsupported interpolator type for NiMaterialColorController "
|
Log(Debug::Error)
|
||||||
<< matctrl->recIndex << " in " << mFilename;
|
<< "Unsupported interpolator type for NiMaterialColorController " << matctrl->recIndex
|
||||||
|
<< " in " << mFilename << ": " << matctrl->mInterpolator->recName;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
osg::ref_ptr<MaterialColorController> osgctrl = new MaterialColorController(matctrl, baseMaterial);
|
osg::ref_ptr<MaterialColorController> osgctrl = new MaterialColorController(matctrl, baseMaterial);
|
||||||
|
@ -1021,7 +1027,7 @@ namespace NifOsg
|
||||||
&& flipctrl->mInterpolator->recType != Nif::RC_NiFloatInterpolator)
|
&& flipctrl->mInterpolator->recType != Nif::RC_NiFloatInterpolator)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Unsupported interpolator type for NiFlipController " << flipctrl->recIndex
|
Log(Debug::Error) << "Unsupported interpolator type for NiFlipController " << flipctrl->recIndex
|
||||||
<< " in " << mFilename;
|
<< " in " << mFilename << ": " << flipctrl->mInterpolator->recName;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::vector<osg::ref_ptr<osg::Texture2D>> textures;
|
std::vector<osg::ref_ptr<osg::Texture2D>> textures;
|
||||||
|
@ -1067,12 +1073,12 @@ namespace NifOsg
|
||||||
attachTo->addChild(program);
|
attachTo->addChild(program);
|
||||||
program->setParticleSystem(partsys);
|
program->setParticleSystem(partsys);
|
||||||
program->setReferenceFrame(rf);
|
program->setReferenceFrame(rf);
|
||||||
for (; !affectors.empty(); affectors = affectors->next)
|
for (; !affectors.empty(); affectors = affectors->mNext)
|
||||||
{
|
{
|
||||||
if (affectors->recType == Nif::RC_NiParticleGrowFade)
|
if (affectors->recType == Nif::RC_NiParticleGrowFade)
|
||||||
{
|
{
|
||||||
const Nif::NiParticleGrowFade* gf = static_cast<const Nif::NiParticleGrowFade*>(affectors.getPtr());
|
const Nif::NiParticleGrowFade* gf = static_cast<const Nif::NiParticleGrowFade*>(affectors.getPtr());
|
||||||
program->addOperator(new GrowFadeAffector(gf->growTime, gf->fadeTime));
|
program->addOperator(new GrowFadeAffector(gf->mGrowTime, gf->mFadeTime));
|
||||||
}
|
}
|
||||||
else if (affectors->recType == Nif::RC_NiGravity)
|
else if (affectors->recType == Nif::RC_NiGravity)
|
||||||
{
|
{
|
||||||
|
@ -1083,9 +1089,9 @@ namespace NifOsg
|
||||||
{
|
{
|
||||||
const Nif::NiParticleColorModifier* cl
|
const Nif::NiParticleColorModifier* cl
|
||||||
= static_cast<const Nif::NiParticleColorModifier*>(affectors.getPtr());
|
= static_cast<const Nif::NiParticleColorModifier*>(affectors.getPtr());
|
||||||
if (cl->data.empty())
|
if (cl->mData.empty())
|
||||||
continue;
|
continue;
|
||||||
const Nif::NiColorData* clrdata = cl->data.getPtr();
|
const Nif::NiColorData* clrdata = cl->mData.getPtr();
|
||||||
program->addOperator(new ParticleColorAffector(clrdata));
|
program->addOperator(new ParticleColorAffector(clrdata));
|
||||||
}
|
}
|
||||||
else if (affectors->recType == Nif::RC_NiParticleRotation)
|
else if (affectors->recType == Nif::RC_NiParticleRotation)
|
||||||
|
@ -1095,7 +1101,7 @@ namespace NifOsg
|
||||||
else
|
else
|
||||||
Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename;
|
Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename;
|
||||||
}
|
}
|
||||||
for (; !colliders.empty(); colliders = colliders->next)
|
for (; !colliders.empty(); colliders = colliders->mNext)
|
||||||
{
|
{
|
||||||
if (colliders->recType == Nif::RC_NiPlanarCollider)
|
if (colliders->recType == Nif::RC_NiPlanarCollider)
|
||||||
{
|
{
|
||||||
|
@ -2008,15 +2014,15 @@ namespace NifOsg
|
||||||
|
|
||||||
const unsigned int uvSet = 0;
|
const unsigned int uvSet = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < textureSet->textures.size(); ++i)
|
for (size_t i = 0; i < textureSet->mTextures.size(); ++i)
|
||||||
{
|
{
|
||||||
if (textureSet->textures[i].empty())
|
if (textureSet->mTextures[i].empty())
|
||||||
continue;
|
continue;
|
||||||
switch (i)
|
switch (static_cast<Nif::BSShaderTextureSet::TextureType>(i))
|
||||||
{
|
{
|
||||||
case Nif::BSShaderTextureSet::TextureType_Base:
|
case Nif::BSShaderTextureSet::TextureType::Base:
|
||||||
case Nif::BSShaderTextureSet::TextureType_Normal:
|
case Nif::BSShaderTextureSet::TextureType::Normal:
|
||||||
case Nif::BSShaderTextureSet::TextureType_Glow:
|
case Nif::BSShaderTextureSet::TextureType::Glow:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
@ -2026,7 +2032,7 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string filename
|
std::string filename
|
||||||
= Misc::ResourceHelpers::correctTexturePath(textureSet->textures[i], imageManager->getVFS());
|
= Misc::ResourceHelpers::correctTexturePath(textureSet->mTextures[i], imageManager->getVFS());
|
||||||
osg::ref_ptr<osg::Image> image = imageManager->getImage(filename);
|
osg::ref_ptr<osg::Image> image = imageManager->getImage(filename);
|
||||||
osg::ref_ptr<osg::Texture2D> texture2d = new osg::Texture2D(image);
|
osg::ref_ptr<osg::Texture2D> texture2d = new osg::Texture2D(image);
|
||||||
if (image)
|
if (image)
|
||||||
|
@ -2035,17 +2041,19 @@ namespace NifOsg
|
||||||
unsigned int texUnit = boundTextures.size();
|
unsigned int texUnit = boundTextures.size();
|
||||||
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
||||||
// BSShaderTextureSet presence means there's no need for FFP support for the affected node
|
// BSShaderTextureSet presence means there's no need for FFP support for the affected node
|
||||||
switch (i)
|
switch (static_cast<Nif::BSShaderTextureSet::TextureType>(i))
|
||||||
{
|
{
|
||||||
case Nif::BSShaderTextureSet::TextureType_Base:
|
case Nif::BSShaderTextureSet::TextureType::Base:
|
||||||
texture2d->setName("diffuseMap");
|
texture2d->setName("diffuseMap");
|
||||||
break;
|
break;
|
||||||
case Nif::BSShaderTextureSet::TextureType_Normal:
|
case Nif::BSShaderTextureSet::TextureType::Normal:
|
||||||
texture2d->setName("normalMap");
|
texture2d->setName("normalMap");
|
||||||
break;
|
break;
|
||||||
case Nif::BSShaderTextureSet::TextureType_Glow:
|
case Nif::BSShaderTextureSet::TextureType::Glow:
|
||||||
texture2d->setName("emissiveMap");
|
texture2d->setName("emissiveMap");
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
boundTextures.emplace_back(uvSet);
|
boundTextures.emplace_back(uvSet);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
#include <components/nif/controlled.hpp>
|
|
||||||
#include <components/nif/data.hpp>
|
#include <components/nif/data.hpp>
|
||||||
#include <components/sceneutil/morphgeometry.hpp>
|
#include <components/sceneutil/morphgeometry.hpp>
|
||||||
#include <components/sceneutil/riggeometry.hpp>
|
#include <components/sceneutil/riggeometry.hpp>
|
||||||
|
@ -281,20 +280,13 @@ namespace NifOsg
|
||||||
|
|
||||||
GravityAffector::GravityAffector(const Nif::NiGravity* gravity)
|
GravityAffector::GravityAffector(const Nif::NiGravity* gravity)
|
||||||
: mForce(gravity->mForce)
|
: mForce(gravity->mForce)
|
||||||
, mType(static_cast<ForceType>(gravity->mType))
|
, mType(gravity->mType)
|
||||||
, mPosition(gravity->mPosition)
|
, mPosition(gravity->mPosition)
|
||||||
, mDirection(gravity->mDirection)
|
, mDirection(gravity->mDirection)
|
||||||
, mDecay(gravity->mDecay)
|
, mDecay(gravity->mDecay)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GravityAffector::GravityAffector()
|
|
||||||
: mForce(0)
|
|
||||||
, mType(Type_Wind)
|
|
||||||
, mDecay(0.f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
GravityAffector::GravityAffector(const GravityAffector& copy, const osg::CopyOp& copyop)
|
GravityAffector::GravityAffector(const GravityAffector& copy, const osg::CopyOp& copyop)
|
||||||
: osgParticle::Operator(copy, copyop)
|
: osgParticle::Operator(copy, copyop)
|
||||||
{
|
{
|
||||||
|
@ -311,8 +303,8 @@ namespace NifOsg
|
||||||
{
|
{
|
||||||
bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF);
|
bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF);
|
||||||
|
|
||||||
if (mType == Type_Point
|
// We don't need the position for Wind gravity, except if decay is being applied
|
||||||
|| mDecay != 0.f) // we don't need the position for Wind gravity, except if decay is being applied
|
if (mType == Nif::NiGravity::ForceType::Point || mDecay != 0.f)
|
||||||
mCachedWorldPosition = absolute ? program->transformLocalToWorld(mPosition) : mPosition;
|
mCachedWorldPosition = absolute ? program->transformLocalToWorld(mPosition) : mPosition;
|
||||||
|
|
||||||
mCachedWorldDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection;
|
mCachedWorldDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection;
|
||||||
|
@ -324,7 +316,7 @@ namespace NifOsg
|
||||||
const float magic = 1.6f;
|
const float magic = 1.6f;
|
||||||
switch (mType)
|
switch (mType)
|
||||||
{
|
{
|
||||||
case Type_Wind:
|
case Nif::NiGravity::ForceType::Wind:
|
||||||
{
|
{
|
||||||
float decayFactor = 1.f;
|
float decayFactor = 1.f;
|
||||||
if (mDecay != 0.f)
|
if (mDecay != 0.f)
|
||||||
|
@ -338,7 +330,7 @@ namespace NifOsg
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type_Point:
|
case Nif::NiGravity::ForceType::Point:
|
||||||
{
|
{
|
||||||
osg::Vec3f diff = mCachedWorldPosition - particle->getPosition();
|
osg::Vec3f diff = mCachedWorldPosition - particle->getPosition();
|
||||||
|
|
||||||
|
|
|
@ -10,15 +10,14 @@
|
||||||
#include <osgParticle/Placer>
|
#include <osgParticle/Placer>
|
||||||
#include <osgParticle/Shooter>
|
#include <osgParticle/Shooter>
|
||||||
|
|
||||||
|
#include <components/nif/particle.hpp> // NiGravity::ForceType
|
||||||
|
|
||||||
#include <components/sceneutil/nodecallback.hpp>
|
#include <components/sceneutil/nodecallback.hpp>
|
||||||
|
|
||||||
#include "controller.hpp" // ValueInterpolator
|
#include "controller.hpp" // ValueInterpolator
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
struct NiGravity;
|
|
||||||
struct NiPlanarCollider;
|
|
||||||
struct NiSphericalCollider;
|
|
||||||
struct NiColorData;
|
struct NiColorData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +179,7 @@ namespace NifOsg
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GravityAffector(const Nif::NiGravity* gravity);
|
GravityAffector(const Nif::NiGravity* gravity);
|
||||||
GravityAffector();
|
GravityAffector() = default;
|
||||||
GravityAffector(const GravityAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
GravityAffector(const GravityAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
||||||
|
|
||||||
GravityAffector& operator=(const GravityAffector&) = delete;
|
GravityAffector& operator=(const GravityAffector&) = delete;
|
||||||
|
@ -191,16 +190,11 @@ namespace NifOsg
|
||||||
void beginOperate(osgParticle::Program*) override;
|
void beginOperate(osgParticle::Program*) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float mForce;
|
float mForce{ 0.f };
|
||||||
enum ForceType
|
Nif::NiGravity::ForceType mType{ Nif::NiGravity::ForceType::Wind };
|
||||||
{
|
|
||||||
Type_Wind,
|
|
||||||
Type_Point
|
|
||||||
};
|
|
||||||
ForceType mType;
|
|
||||||
osg::Vec3f mPosition;
|
osg::Vec3f mPosition;
|
||||||
osg::Vec3f mDirection;
|
osg::Vec3f mDirection;
|
||||||
float mDecay;
|
float mDecay{ 0.f };
|
||||||
osg::Vec3f mCachedWorldPosition;
|
osg::Vec3f mCachedWorldPosition;
|
||||||
osg::Vec3f mCachedWorldDirection;
|
osg::Vec3f mCachedWorldDirection;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,7 +32,9 @@ namespace Resource
|
||||||
};
|
};
|
||||||
|
|
||||||
NifFileManager::NifFileManager(const VFS::Manager* vfs)
|
NifFileManager::NifFileManager(const VFS::Manager* vfs)
|
||||||
: ResourceManager(vfs)
|
// NIF files aren't needed any more once the converted objects are cached in SceneManager / BulletShapeManager,
|
||||||
|
// so no point in using an expiry delay.
|
||||||
|
: ResourceManager(vfs, 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,9 +62,9 @@ namespace Resource
|
||||||
{
|
{
|
||||||
// If ref count is greater than 1, the object has an external reference.
|
// If ref count is greater than 1, the object has an external reference.
|
||||||
// If the timestamp is yet to be initialized, it needs to be updated too.
|
// If the timestamp is yet to be initialized, it needs to be updated too.
|
||||||
if ((itr->second.first != nullptr && itr->second.first->referenceCount() > 1)
|
if ((itr->second.mValue != nullptr && itr->second.mValue->referenceCount() > 1)
|
||||||
|| itr->second.second == 0.0)
|
|| itr->second.mLastUsage == 0.0)
|
||||||
itr->second.second = referenceTime;
|
itr->second.mLastUsage = referenceTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,10 +81,10 @@ namespace Resource
|
||||||
typename ObjectCacheMap::iterator oitr = _objectCache.begin();
|
typename ObjectCacheMap::iterator oitr = _objectCache.begin();
|
||||||
while (oitr != _objectCache.end())
|
while (oitr != _objectCache.end())
|
||||||
{
|
{
|
||||||
if (oitr->second.second <= expiryTime)
|
if (oitr->second.mLastUsage <= expiryTime)
|
||||||
{
|
{
|
||||||
if (oitr->second.first != nullptr)
|
if (oitr->second.mValue != nullptr)
|
||||||
objectsToRemove.push_back(oitr->second.first);
|
objectsToRemove.push_back(std::move(oitr->second.mValue));
|
||||||
_objectCache.erase(oitr++);
|
_objectCache.erase(oitr++);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -106,7 +106,7 @@ namespace Resource
|
||||||
void addEntryToObjectCache(const KeyType& key, osg::Object* object, double timestamp = 0.0)
|
void addEntryToObjectCache(const KeyType& key, osg::Object* object, double timestamp = 0.0)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
_objectCache[key] = ObjectTimeStampPair(object, timestamp);
|
_objectCache[key] = Item{ object, timestamp };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Remove Object from cache.*/
|
/** Remove Object from cache.*/
|
||||||
|
@ -124,7 +124,7 @@ namespace Resource
|
||||||
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
typename ObjectCacheMap::iterator itr = _objectCache.find(key);
|
typename ObjectCacheMap::iterator itr = _objectCache.find(key);
|
||||||
if (itr != _objectCache.end())
|
if (itr != _objectCache.end())
|
||||||
return itr->second.first;
|
return itr->second.mValue;
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ namespace Resource
|
||||||
const auto it = _objectCache.find(key);
|
const auto it = _objectCache.find(key);
|
||||||
if (it == _objectCache.end())
|
if (it == _objectCache.end())
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return it->second.first;
|
return it->second.mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if an object is in the cache, and if it is, update its usage time stamp. */
|
/** Check if an object is in the cache, and if it is, update its usage time stamp. */
|
||||||
|
@ -145,7 +145,7 @@ namespace Resource
|
||||||
typename ObjectCacheMap::iterator itr = _objectCache.find(key);
|
typename ObjectCacheMap::iterator itr = _objectCache.find(key);
|
||||||
if (itr != _objectCache.end())
|
if (itr != _objectCache.end())
|
||||||
{
|
{
|
||||||
itr->second.second = timeStamp;
|
itr->second.mLastUsage = timeStamp;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -158,7 +158,7 @@ namespace Resource
|
||||||
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
for (typename ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr)
|
for (typename ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr)
|
||||||
{
|
{
|
||||||
osg::Object* object = itr->second.first.get();
|
osg::Object* object = itr->second.mValue.get();
|
||||||
object->releaseGLObjects(state);
|
object->releaseGLObjects(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,8 +169,7 @@ namespace Resource
|
||||||
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
for (typename ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr)
|
for (typename ObjectCacheMap::iterator itr = _objectCache.begin(); itr != _objectCache.end(); ++itr)
|
||||||
{
|
{
|
||||||
osg::Object* object = itr->second.first.get();
|
if (osg::Object* object = itr->second.mValue.get())
|
||||||
if (object)
|
|
||||||
{
|
{
|
||||||
osg::Node* node = dynamic_cast<osg::Node*>(object);
|
osg::Node* node = dynamic_cast<osg::Node*>(object);
|
||||||
if (node)
|
if (node)
|
||||||
|
@ -185,7 +184,7 @@ namespace Resource
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
for (typename ObjectCacheMap::iterator it = _objectCache.begin(); it != _objectCache.end(); ++it)
|
for (typename ObjectCacheMap::iterator it = _objectCache.begin(); it != _objectCache.end(); ++it)
|
||||||
f(it->first, it->second.first.get());
|
f(it->first, it->second.mValue.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the number of objects in the cache. */
|
/** Get the number of objects in the cache. */
|
||||||
|
@ -195,11 +194,26 @@ namespace Resource
|
||||||
return _objectCache.size();
|
return _objectCache.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
std::optional<std::pair<KeyType, osg::ref_ptr<osg::Object>>> lowerBound(K&& key)
|
||||||
|
{
|
||||||
|
const std::lock_guard<std::mutex> lock(_objectCacheMutex);
|
||||||
|
const auto it = _objectCache.lower_bound(std::forward<K>(key));
|
||||||
|
if (it == _objectCache.end())
|
||||||
|
return std::nullopt;
|
||||||
|
return std::pair(it->first, it->second.mValue);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
struct Item
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Object> mValue;
|
||||||
|
double mLastUsage;
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~GenericObjectCache() {}
|
virtual ~GenericObjectCache() {}
|
||||||
|
|
||||||
typedef std::pair<osg::ref_ptr<osg::Object>, double> ObjectTimeStampPair;
|
using ObjectCacheMap = std::map<KeyType, Item, std::less<>>;
|
||||||
typedef std::map<KeyType, ObjectTimeStampPair> ObjectCacheMap;
|
|
||||||
|
|
||||||
ObjectCacheMap _objectCache;
|
ObjectCacheMap _objectCache;
|
||||||
mutable std::mutex _objectCacheMutex;
|
mutable std::mutex _objectCacheMutex;
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
|
||||||
|
#include <components/settings/values.hpp>
|
||||||
|
|
||||||
#include "objectcache.hpp"
|
#include "objectcache.hpp"
|
||||||
|
|
||||||
namespace VFS
|
namespace VFS
|
||||||
|
@ -23,11 +25,11 @@ namespace Resource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~BaseResourceManager() = default;
|
virtual ~BaseResourceManager() = default;
|
||||||
virtual void updateCache(double referenceTime) {}
|
virtual void updateCache(double referenceTime) = 0;
|
||||||
virtual void clearCache() {}
|
virtual void clearCache() = 0;
|
||||||
virtual void setExpiryDelay(double expiryDelay) {}
|
virtual void setExpiryDelay(double expiryDelay) = 0;
|
||||||
virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const {}
|
virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const = 0;
|
||||||
virtual void releaseGLObjects(osg::State* state) {}
|
virtual void releaseGLObjects(osg::State* state) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Base class for managers that require a virtual file system and object cache.
|
/// @brief Base class for managers that require a virtual file system and object cache.
|
||||||
|
@ -39,10 +41,11 @@ namespace Resource
|
||||||
public:
|
public:
|
||||||
typedef GenericObjectCache<KeyType> CacheType;
|
typedef GenericObjectCache<KeyType> CacheType;
|
||||||
|
|
||||||
GenericResourceManager(const VFS::Manager* vfs)
|
explicit GenericResourceManager(
|
||||||
|
const VFS::Manager* vfs, double expiryDelay = Settings::cells().mCacheExpiryDelay)
|
||||||
: mVFS(vfs)
|
: mVFS(vfs)
|
||||||
, mCache(new CacheType)
|
, mCache(new CacheType)
|
||||||
, mExpiryDelay(0.0)
|
, mExpiryDelay(expiryDelay)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +62,7 @@ namespace Resource
|
||||||
void clearCache() override { mCache->clear(); }
|
void clearCache() override { mCache->clear(); }
|
||||||
|
|
||||||
/// How long to keep objects in cache after no longer being referenced.
|
/// How long to keep objects in cache after no longer being referenced.
|
||||||
void setExpiryDelay(double expiryDelay) override { mExpiryDelay = expiryDelay; }
|
void setExpiryDelay(double expiryDelay) final { mExpiryDelay = expiryDelay; }
|
||||||
double getExpiryDelay() const { return mExpiryDelay; }
|
double getExpiryDelay() const { return mExpiryDelay; }
|
||||||
|
|
||||||
const VFS::Manager* getVFS() const { return mVFS; }
|
const VFS::Manager* getVFS() const { return mVFS; }
|
||||||
|
@ -77,10 +80,15 @@ namespace Resource
|
||||||
class ResourceManager : public GenericResourceManager<std::string>
|
class ResourceManager : public GenericResourceManager<std::string>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ResourceManager(const VFS::Manager* vfs)
|
explicit ResourceManager(const VFS::Manager* vfs)
|
||||||
: GenericResourceManager<std::string>(vfs)
|
: GenericResourceManager<std::string>(vfs)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit ResourceManager(const VFS::Manager* vfs, double expiryDelay)
|
||||||
|
: GenericResourceManager<std::string>(vfs, expiryDelay)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace Terrain
|
||||||
|
|
||||||
ChunkManager::ChunkManager(Storage* storage, Resource::SceneManager* sceneMgr, TextureManager* textureManager,
|
ChunkManager::ChunkManager(Storage* storage, Resource::SceneManager* sceneMgr, TextureManager* textureManager,
|
||||||
CompositeMapRenderer* renderer, ESM::RefId worldspace)
|
CompositeMapRenderer* renderer, ESM::RefId worldspace)
|
||||||
: GenericResourceManager<ChunkId>(nullptr)
|
: GenericResourceManager<ChunkKey>(nullptr)
|
||||||
, QuadTreeWorld::ChunkManager(worldspace)
|
, QuadTreeWorld::ChunkManager(worldspace)
|
||||||
, mStorage(storage)
|
, mStorage(storage)
|
||||||
, mSceneManager(sceneMgr)
|
, mSceneManager(sceneMgr)
|
||||||
|
@ -39,38 +39,26 @@ namespace Terrain
|
||||||
mMultiPassRoot->setAttributeAndModes(material, osg::StateAttribute::ON);
|
mMultiPassRoot->setAttributeAndModes(material, osg::StateAttribute::ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FindChunkTemplate
|
|
||||||
{
|
|
||||||
void operator()(ChunkId id, osg::Object* obj)
|
|
||||||
{
|
|
||||||
if (std::get<0>(id) == std::get<0>(mId) && std::get<1>(id) == std::get<1>(mId))
|
|
||||||
mFoundTemplate = obj;
|
|
||||||
}
|
|
||||||
ChunkId mId;
|
|
||||||
osg::ref_ptr<osg::Object> mFoundTemplate;
|
|
||||||
};
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> ChunkManager::getChunk(float size, const osg::Vec2f& center, unsigned char lod,
|
osg::ref_ptr<osg::Node> ChunkManager::getChunk(float size, const osg::Vec2f& center, unsigned char lod,
|
||||||
unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile)
|
unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile)
|
||||||
{
|
{
|
||||||
// Override lod with the vertexLodMod adjusted value.
|
// Override lod with the vertexLodMod adjusted value.
|
||||||
// TODO: maybe we can refactor this code by moving all vertexLodMod code into this class.
|
// TODO: maybe we can refactor this code by moving all vertexLodMod code into this class.
|
||||||
lod = static_cast<unsigned char>(lodFlags >> (4 * 4));
|
lod = static_cast<unsigned char>(lodFlags >> (4 * 4));
|
||||||
ChunkId id = std::make_tuple(center, lod, lodFlags);
|
|
||||||
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(id);
|
const ChunkKey key{ .mCenter = center, .mLod = lod, .mLodFlags = lodFlags };
|
||||||
if (obj)
|
if (osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(key))
|
||||||
return static_cast<osg::Node*>(obj.get());
|
return static_cast<osg::Node*>(obj.get());
|
||||||
else
|
|
||||||
{
|
const TerrainDrawable* templateGeometry = nullptr;
|
||||||
FindChunkTemplate find;
|
const TemplateKey templateKey{ .mCenter = center, .mLod = lod };
|
||||||
find.mId = id;
|
const auto pair = mCache->lowerBound(templateKey);
|
||||||
mCache->call(find);
|
if (pair.has_value() && templateKey == TemplateKey{ .mCenter = pair->first.mCenter, .mLod = pair->first.mLod })
|
||||||
TerrainDrawable* templateGeometry
|
templateGeometry = static_cast<const TerrainDrawable*>(pair->second.get());
|
||||||
= find.mFoundTemplate ? static_cast<TerrainDrawable*>(find.mFoundTemplate.get()) : nullptr;
|
|
||||||
osg::ref_ptr<osg::Node> node = createChunk(size, center, lod, lodFlags, compile, templateGeometry);
|
osg::ref_ptr<osg::Node> node = createChunk(size, center, lod, lodFlags, compile, templateGeometry);
|
||||||
mCache->addEntryToObjectCache(id, node.get());
|
mCache->addEntryToObjectCache(key, node.get());
|
||||||
return node;
|
return node;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkManager::reportStats(unsigned int frameNumber, osg::Stats* stats) const
|
void ChunkManager::reportStats(unsigned int frameNumber, osg::Stats* stats) const
|
||||||
|
@ -80,14 +68,14 @@ namespace Terrain
|
||||||
|
|
||||||
void ChunkManager::clearCache()
|
void ChunkManager::clearCache()
|
||||||
{
|
{
|
||||||
GenericResourceManager<ChunkId>::clearCache();
|
GenericResourceManager<ChunkKey>::clearCache();
|
||||||
|
|
||||||
mBufferCache.clearCache();
|
mBufferCache.clearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkManager::releaseGLObjects(osg::State* state)
|
void ChunkManager::releaseGLObjects(osg::State* state)
|
||||||
{
|
{
|
||||||
GenericResourceManager<ChunkId>::releaseGLObjects(state);
|
GenericResourceManager<ChunkKey>::releaseGLObjects(state);
|
||||||
mBufferCache.releaseGLObjects(state);
|
mBufferCache.releaseGLObjects(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +190,7 @@ namespace Terrain
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Vec2f& chunkCenter, unsigned char lod,
|
osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Vec2f& chunkCenter, unsigned char lod,
|
||||||
unsigned int lodFlags, bool compile, TerrainDrawable* templateGeometry)
|
unsigned int lodFlags, bool compile, const TerrainDrawable* templateGeometry)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<TerrainDrawable> geometry(new TerrainDrawable);
|
osg::ref_ptr<TerrainDrawable> geometry(new TerrainDrawable);
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,51 @@ namespace Terrain
|
||||||
class CompositeMap;
|
class CompositeMap;
|
||||||
class TerrainDrawable;
|
class TerrainDrawable;
|
||||||
|
|
||||||
typedef std::tuple<osg::Vec2f, unsigned char, unsigned int> ChunkId; // Center, Lod, Lod Flags
|
struct TemplateKey
|
||||||
|
{
|
||||||
|
osg::Vec2f mCenter;
|
||||||
|
unsigned char mLod;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline auto tie(const TemplateKey& v)
|
||||||
|
{
|
||||||
|
return std::tie(v.mCenter, v.mLod);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator<(const TemplateKey& l, const TemplateKey& r)
|
||||||
|
{
|
||||||
|
return tie(l) < tie(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const TemplateKey& l, const TemplateKey& r)
|
||||||
|
{
|
||||||
|
return tie(l) == tie(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ChunkKey
|
||||||
|
{
|
||||||
|
osg::Vec2f mCenter;
|
||||||
|
unsigned char mLod;
|
||||||
|
unsigned mLodFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline auto tie(const ChunkKey& v)
|
||||||
|
{
|
||||||
|
return std::tie(v.mCenter, v.mLod, v.mLodFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator<(const ChunkKey& l, const ChunkKey& r)
|
||||||
|
{
|
||||||
|
return tie(l) < tie(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator<(const ChunkKey& l, const TemplateKey& r)
|
||||||
|
{
|
||||||
|
return TemplateKey{ .mCenter = l.mCenter, .mLod = l.mLod } < r;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Handles loading and caching of terrain chunks
|
/// @brief Handles loading and caching of terrain chunks
|
||||||
class ChunkManager : public Resource::GenericResourceManager<ChunkId>, public QuadTreeWorld::ChunkManager
|
class ChunkManager : public Resource::GenericResourceManager<ChunkKey>, public QuadTreeWorld::ChunkManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ChunkManager(Storage* storage, Resource::SceneManager* sceneMgr, TextureManager* textureManager,
|
ChunkManager(Storage* storage, Resource::SceneManager* sceneMgr, TextureManager* textureManager,
|
||||||
|
@ -55,7 +96,7 @@ namespace Terrain
|
||||||
|
|
||||||
private:
|
private:
|
||||||
osg::ref_ptr<osg::Node> createChunk(float size, const osg::Vec2f& center, unsigned char lod,
|
osg::ref_ptr<osg::Node> createChunk(float size, const osg::Vec2f& center, unsigned char lod,
|
||||||
unsigned int lodFlags, bool compile, TerrainDrawable* templateGeometry);
|
unsigned int lodFlags, bool compile, const TerrainDrawable* templateGeometry);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> createCompositeMapRTT();
|
osg::ref_ptr<osg::Texture2D> createCompositeMapRTT();
|
||||||
|
|
||||||
|
|
|
@ -544,37 +544,16 @@ namespace Terrain
|
||||||
vd->setViewPoint(viewPoint);
|
vd->setViewPoint(viewPoint);
|
||||||
vd->setActiveGrid(grid);
|
vd->setActiveGrid(grid);
|
||||||
|
|
||||||
for (unsigned int pass = 0; pass < 3; ++pass)
|
DefaultLodCallback lodCallback(mLodFactor, mMinSize, mViewDistance, grid, cellWorldSize);
|
||||||
|
mRootNode->traverseNodes(vd, viewPoint, &lodCallback);
|
||||||
|
|
||||||
|
reporter.addTotal(vd->getNumEntries());
|
||||||
|
|
||||||
|
for (unsigned int i = 0, n = vd->getNumEntries(); i < n && !abort; ++i)
|
||||||
{
|
{
|
||||||
unsigned int startEntry = vd->getNumEntries();
|
ViewDataEntry& entry = vd->getEntry(i);
|
||||||
|
loadRenderingNode(entry, vd, cellWorldSize, grid, true);
|
||||||
float distanceModifier = 0.f;
|
reporter.addProgress(1);
|
||||||
if (pass == 1)
|
|
||||||
distanceModifier = 1024;
|
|
||||||
else if (pass == 2)
|
|
||||||
distanceModifier = -1024;
|
|
||||||
DefaultLodCallback lodCallback(mLodFactor, mMinSize, mViewDistance, grid, cellWorldSize, distanceModifier);
|
|
||||||
mRootNode->traverseNodes(vd, viewPoint, &lodCallback);
|
|
||||||
|
|
||||||
if (pass == 0)
|
|
||||||
{
|
|
||||||
std::size_t progressTotal = 0;
|
|
||||||
for (unsigned int i = 0, n = vd->getNumEntries(); i < n; ++i)
|
|
||||||
progressTotal += vd->getEntry(i).mNode->getSize();
|
|
||||||
|
|
||||||
reporter.addTotal(progressTotal);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = startEntry; i < vd->getNumEntries() && !abort; ++i)
|
|
||||||
{
|
|
||||||
ViewDataEntry& entry = vd->getEntry(i);
|
|
||||||
|
|
||||||
loadRenderingNode(entry, vd, cellWorldSize, grid, true);
|
|
||||||
if (pass == 0)
|
|
||||||
reporter.addProgress(entry.mNode->getSize());
|
|
||||||
vd->removeNodeFromIndex(entry.mNode);
|
|
||||||
entry.mNode = nullptr; // Clear node lest we break the neighbours search for the next pass
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace Terrain
|
||||||
const osg::BoundingBox& getWaterBoundingBox() const { return mWaterBoundingBox; }
|
const osg::BoundingBox& getWaterBoundingBox() const { return mWaterBoundingBox; }
|
||||||
|
|
||||||
void setCompositeMap(CompositeMap* map) { mCompositeMap = map; }
|
void setCompositeMap(CompositeMap* map) { mCompositeMap = map; }
|
||||||
CompositeMap* getCompositeMap() { return mCompositeMap; }
|
CompositeMap* getCompositeMap() const { return mCompositeMap; }
|
||||||
void setCompositeMapRenderer(CompositeMapRenderer* renderer) { mCompositeMapRenderer = renderer; }
|
void setCompositeMapRenderer(CompositeMapRenderer* renderer) { mCompositeMapRenderer = renderer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -17,6 +17,7 @@ Lua API reference
|
||||||
openmw_core
|
openmw_core
|
||||||
openmw_types
|
openmw_types
|
||||||
openmw_async
|
openmw_async
|
||||||
|
openmw_vfs
|
||||||
openmw_world
|
openmw_world
|
||||||
openmw_self
|
openmw_self
|
||||||
openmw_nearby
|
openmw_nearby
|
||||||
|
|
7
docs/source/reference/lua-scripting/openmw_vfs.rst
Normal file
7
docs/source/reference/lua-scripting/openmw_vfs.rst
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Package openmw.vfs
|
||||||
|
==================
|
||||||
|
|
||||||
|
.. include:: version.rst
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: generated_html/openmw_vfs.html
|
|
@ -6,7 +6,7 @@ Overview of Lua scripting
|
||||||
Language and sandboxing
|
Language and sandboxing
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
OpenMW supports scripts written in Lua 5.1 with some extensions (see below) from Lua 5.2.
|
OpenMW supports scripts written in Lua 5.1 with some extensions (see below) from Lua 5.2 and Lua 5.3.
|
||||||
There are no plans to switch to any newer version of the language, because newer versions are not supported by LuaJIT.
|
There are no plans to switch to any newer version of the language, because newer versions are not supported by LuaJIT.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -40,6 +40,10 @@ Supported Lua 5.2 features:
|
||||||
- ``__pairs`` and ``__ipairs`` metamethods;
|
- ``__pairs`` and ``__ipairs`` metamethods;
|
||||||
- Function ``table.unpack`` (alias to Lua 5.1 ``unpack``).
|
- Function ``table.unpack`` (alias to Lua 5.1 ``unpack``).
|
||||||
|
|
||||||
|
Supported Lua 5.3 features:
|
||||||
|
|
||||||
|
- All functions in the `UTF-8 Library <https://www.lua.org/manual/5.3/manual.html#6.5>`__
|
||||||
|
|
||||||
Loading libraries with ``require('library_name')`` is allowed, but limited. It works this way:
|
Loading libraries with ``require('library_name')`` is allowed, but limited. It works this way:
|
||||||
|
|
||||||
1. If `library_name` is one of the standard libraries, then return the library.
|
1. If `library_name` is one of the standard libraries, then return the library.
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw.async <Package openmw.async>` | everywhere | | Timers and callbacks. |
|
|:ref:`openmw.async <Package openmw.async>` | everywhere | | Timers and callbacks. |
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.vfs <Package openmw.vfs>` | everywhere | | Read-only access to data directories via VFS. |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw.world <Package openmw.world>` | by global scripts | | Read-write access to the game world. |
|
|:ref:`openmw.world <Package openmw.world>` | by global scripts | | Read-write access to the game world. |
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw.self <Package openmw.self>` | by local scripts | | Full access to the object the script is attached to. |
|
|:ref:`openmw.self <Package openmw.self>` | by local scripts | | Full access to the object the script is attached to. |
|
||||||
|
|
|
@ -22,6 +22,7 @@ local env = {
|
||||||
storage = require('openmw.storage'),
|
storage = require('openmw.storage'),
|
||||||
core = require('openmw.core'),
|
core = require('openmw.core'),
|
||||||
types = require('openmw.types'),
|
types = require('openmw.types'),
|
||||||
|
vfs = require('openmw.vfs'),
|
||||||
async = require('openmw.async'),
|
async = require('openmw.async'),
|
||||||
world = require('openmw.world'),
|
world = require('openmw.world'),
|
||||||
aux_util = require('openmw_aux.util'),
|
aux_util = require('openmw_aux.util'),
|
||||||
|
|
|
@ -24,6 +24,7 @@ local env = {
|
||||||
storage = require('openmw.storage'),
|
storage = require('openmw.storage'),
|
||||||
core = require('openmw.core'),
|
core = require('openmw.core'),
|
||||||
types = require('openmw.types'),
|
types = require('openmw.types'),
|
||||||
|
vfs = require('openmw.vfs'),
|
||||||
async = require('openmw.async'),
|
async = require('openmw.async'),
|
||||||
nearby = require('openmw.nearby'),
|
nearby = require('openmw.nearby'),
|
||||||
self = require('openmw.self'),
|
self = require('openmw.self'),
|
||||||
|
|
|
@ -71,6 +71,8 @@ local env = {
|
||||||
storage = require('openmw.storage'),
|
storage = require('openmw.storage'),
|
||||||
core = require('openmw.core'),
|
core = require('openmw.core'),
|
||||||
types = require('openmw.types'),
|
types = require('openmw.types'),
|
||||||
|
vfs = require('openmw.vfs'),
|
||||||
|
ambient = require('openmw.ambient'),
|
||||||
async = require('openmw.async'),
|
async = require('openmw.async'),
|
||||||
nearby = require('openmw.nearby'),
|
nearby = require('openmw.nearby'),
|
||||||
self = require('openmw.self'),
|
self = require('openmw.self'),
|
||||||
|
|
|
@ -12,14 +12,15 @@ set(LUA_API_FILES
|
||||||
openmw/ambient.lua
|
openmw/ambient.lua
|
||||||
openmw/async.lua
|
openmw/async.lua
|
||||||
openmw/core.lua
|
openmw/core.lua
|
||||||
|
openmw/debug.lua
|
||||||
openmw/nearby.lua
|
openmw/nearby.lua
|
||||||
|
openmw/postprocessing.lua
|
||||||
openmw/self.lua
|
openmw/self.lua
|
||||||
|
openmw/types.lua
|
||||||
openmw/ui.lua
|
openmw/ui.lua
|
||||||
openmw/util.lua
|
openmw/util.lua
|
||||||
|
openmw/vfs.lua
|
||||||
openmw/world.lua
|
openmw/world.lua
|
||||||
openmw/types.lua
|
|
||||||
openmw/postprocessing.lua
|
|
||||||
openmw/debug.lua
|
|
||||||
)
|
)
|
||||||
|
|
||||||
foreach (f ${LUA_API_FILES})
|
foreach (f ${LUA_API_FILES})
|
||||||
|
|
159
files/lua_api/openmw/vfs.lua
Normal file
159
files/lua_api/openmw/vfs.lua
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
---
|
||||||
|
-- `openmw.vfs` provides read-only access to data directories via VFS.
|
||||||
|
-- Interface is very similar to "io" library.
|
||||||
|
-- @module vfs
|
||||||
|
-- @usage local vfs = require('openmw.vfs')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @type FileHandle
|
||||||
|
-- @field #string fileName VFS path to related file
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Close a file handle
|
||||||
|
-- @function [parent=#FileHandle] close
|
||||||
|
-- @param self
|
||||||
|
-- @return #boolean true if a call succeeds without errors.
|
||||||
|
-- @return #nil, #string nil plus the error message in case of any error.
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Get an iterator function to fetch the next line from given file.
|
||||||
|
-- Throws an exception if file is closed.
|
||||||
|
--
|
||||||
|
-- Hint: since garbage collection works once per frame,
|
||||||
|
-- you will get the whole file in RAM if you read it in one frame.
|
||||||
|
-- So if you need to read a really large file, it is better to split reading
|
||||||
|
-- between different frames (e.g. by keeping a current position in file
|
||||||
|
-- and using a "seek" to read from saved position).
|
||||||
|
-- @function [parent=#FileHandle] lines
|
||||||
|
-- @param self
|
||||||
|
-- @return #function Iterator function to get next line
|
||||||
|
-- @usage f = vfs.open("Test\\test.txt");
|
||||||
|
-- for line in f:lines() do
|
||||||
|
-- print(line);
|
||||||
|
-- end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Set new position in file.
|
||||||
|
-- Throws an exception if file is closed or seek base is incorrect.
|
||||||
|
-- @function [parent=#FileHandle] seek
|
||||||
|
-- @param self
|
||||||
|
-- @param #string whence Seek base (optional, "cur" by default). Can be:
|
||||||
|
--
|
||||||
|
-- * "set" - seek from beginning of file;
|
||||||
|
-- * "cur" - seek from current position;
|
||||||
|
-- * "end" - seek from end of file (offset needs to be <= 0);
|
||||||
|
-- @param #number offset Offset from given base (optional, 0 by default)
|
||||||
|
-- @return #number new position in file if a call succeeds without errors.
|
||||||
|
-- @return #nil, #string nil plus the error message in case of any error.
|
||||||
|
-- @usage -- set pointer to beginning of file
|
||||||
|
-- f = vfs.open("Test\\test.txt");
|
||||||
|
-- f:seek("set");
|
||||||
|
-- @usage -- print current position in file
|
||||||
|
-- f = vfs.open("Test\\test.txt");
|
||||||
|
-- print(f:seek());
|
||||||
|
-- @usage -- print file size
|
||||||
|
-- f = vfs.open("Test\\test.txt");
|
||||||
|
-- print(f:seek("end"));
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Read data from file to strings.
|
||||||
|
-- Throws an exception if file is closed, if there is too many arguments or if an invalid format encountered.
|
||||||
|
--
|
||||||
|
-- Hint: since garbage collection works once per frame,
|
||||||
|
-- you will get the whole file in RAM if you read it in one frame.
|
||||||
|
-- So if you need to read a really large file, it is better to split reading
|
||||||
|
-- between different frames (e.g. by keeping a current position in file
|
||||||
|
-- and using a "seek" to read from saved position).
|
||||||
|
-- @function [parent=#FileHandle] read
|
||||||
|
-- @param self
|
||||||
|
-- @param ... Read formats (up to 20 arguments, default value is one "*l"). Can be:
|
||||||
|
--
|
||||||
|
-- * "\*a" (or "*all") - reads the whole file, starting at the current position as #string. On end of file, it returns the empty string.
|
||||||
|
-- * "\*l" (or "*line") - reads the next line (skipping the end of line), returning nil on end of file (nil and error message if error occured);
|
||||||
|
-- * "\*n" (or "*number") - read a floating point value as #number (nil and error message if error occured);
|
||||||
|
-- * number - reads a #string with up to this number of characters, returning nil on end of file (nil and error message if error occured). If number is 0 and end of file is not reached, it reads nothing and returns an empty string;
|
||||||
|
-- @return #string One #string for every format if a call succeeds without errors. One #string for every successfully handled format, nil for first failed format.
|
||||||
|
-- @usage -- read three numbers from file
|
||||||
|
-- f = vfs.open("Test\\test.txt");
|
||||||
|
-- local n1, n2, n3 = f:read("*number", "*number", "*number");
|
||||||
|
-- @usage -- read 10 bytes from file
|
||||||
|
-- f = vfs.open("Test\\test.txt");
|
||||||
|
-- local n4 = f:read(10);
|
||||||
|
-- @usage -- read until end of file
|
||||||
|
-- f = vfs.open("Test\\test.txt");
|
||||||
|
-- local n5 = f:read("*all");
|
||||||
|
-- @usage -- read a line from file
|
||||||
|
-- f = vfs.open("Test\\test.txt");
|
||||||
|
-- local n6 = f:read();
|
||||||
|
-- @usage -- try to read three numbers from file with "1" content
|
||||||
|
-- f = vfs.open("one.txt");
|
||||||
|
-- print(f:read("*number", "*number", "*number"));
|
||||||
|
-- -- prints(1, nil)
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Check if file exists in VFS
|
||||||
|
-- @function [parent=#vfs] fileExists
|
||||||
|
-- @param #string fileName Path to file in VFS
|
||||||
|
-- @return #boolean (true - exists, false - does not exist)
|
||||||
|
-- @usage local exists = vfs.fileExists("Test\\test.txt");
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Open a file
|
||||||
|
-- @function [parent=#vfs] open
|
||||||
|
-- @param #string fileName Path to file in VFS
|
||||||
|
-- @return #FileHandle Opened file handle if a call succeeds without errors.
|
||||||
|
-- @return #nil, #string nil plus the error message in case of any error.
|
||||||
|
-- @usage f, msg = vfs.open("Test\\test.txt");
|
||||||
|
-- -- print file name or error message
|
||||||
|
-- if (f == nil)
|
||||||
|
-- print(msg);
|
||||||
|
-- else
|
||||||
|
-- print(f.fileName);
|
||||||
|
-- end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Get an iterator function to fetch the next line from file with given path.
|
||||||
|
-- Throws an exception if file is closed or file with given path does not exist.
|
||||||
|
-- Closes file automatically when it fails to read any more bytes.
|
||||||
|
--
|
||||||
|
-- Hint: since garbage collection works once per frame,
|
||||||
|
-- you will get the whole file in RAM if you read it in one frame.
|
||||||
|
-- So if you need to read a really large file, it is better to split reading
|
||||||
|
-- between different frames (e.g. by keeping a current position in file
|
||||||
|
-- and using a "seek" to read from saved position).
|
||||||
|
-- @function [parent=#vfs] lines
|
||||||
|
-- @param #string fileName Path to file in VFS
|
||||||
|
-- @return #function Iterator function to get next line
|
||||||
|
-- @usage for line in vfs.lines("Test\\test.txt") do
|
||||||
|
-- print(line);
|
||||||
|
-- end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Get iterator function to fetch file names with given path prefix from VFS
|
||||||
|
-- @function [parent=#vfs] pathsWithPrefix
|
||||||
|
-- @param #string path Path prefix
|
||||||
|
-- @return #function Function to get next file name
|
||||||
|
-- @usage -- get all files with given prefix from VFS index
|
||||||
|
-- for fileName in vfs.pathsWithPrefix("Music\\Explore") do
|
||||||
|
-- print(fileName);
|
||||||
|
-- end
|
||||||
|
-- @usage -- get some first files
|
||||||
|
-- local getNextFile = vfs.pathsWithPrefix("Music\\Explore");
|
||||||
|
-- local firstFile = getNextFile();
|
||||||
|
-- local secondFile = getNextFile();
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Detect a file handle type
|
||||||
|
-- @function [parent=#vfs] type
|
||||||
|
-- @param #any handle Object to check
|
||||||
|
-- @return #string File handle type. Can be:
|
||||||
|
--
|
||||||
|
-- * "file" - an argument is a valid opened @{openmw.vfs#FileHandle};
|
||||||
|
-- * "closed file" - an argument is a valid closed @{openmw.vfs#FileHandle};
|
||||||
|
-- * nil - an argument is not a @{openmw.vfs#FileHandle};
|
||||||
|
-- @usage f = vfs.open("Test\\test.txt");
|
||||||
|
-- print(vfs.type(f));
|
||||||
|
|
||||||
|
return nil
|
77
files/lua_api/utf8.doclua
Normal file
77
files/lua_api/utf8.doclua
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- UTF-8 Support.
|
||||||
|
-- This library provides basic support for UTF-8 encoding.
|
||||||
|
-- It provides all its functions inside the table utf8.
|
||||||
|
-- This library does not provide any support for Unicode other than the handling of the encoding.
|
||||||
|
-- Any operation that needs the meaning of a character, such as character classification, is outside its scope.
|
||||||
|
--
|
||||||
|
-- Unless stated otherwise, all functions that expect a byte position as a parameter assume that
|
||||||
|
-- the given position is either the start of a byte sequence or one plus the length of the subject string.
|
||||||
|
-- As in the string library, negative indices count from the end of the string.
|
||||||
|
-- @module utf8
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Receives zero or more integers, converts each one to its
|
||||||
|
-- corresponding UTF-8 byte sequence, and returns a string with the concatenation
|
||||||
|
-- of all these sequences.
|
||||||
|
-- @function [parent=#utf8] char
|
||||||
|
-- @param ... zero or more integers.
|
||||||
|
-- @return #string
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- The pattern which matches exactly one UTF-8 byte sequence, assuming that
|
||||||
|
-- the subject is a valid UTF-8 string.
|
||||||
|
-- @function [parent=#utf8] charpattern
|
||||||
|
-- @return #string
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Returns values so that the construction
|
||||||
|
--
|
||||||
|
-- for p, c in utf8.codes(s) do body end
|
||||||
|
--
|
||||||
|
-- will iterate over all characters in string s, with p being the position (in bytes)
|
||||||
|
-- and c the code point of each character.
|
||||||
|
-- It raises an error if it meets any invalid byte sequence.
|
||||||
|
-- @function [parent=#utf8] codes
|
||||||
|
-- @param #string s string to handle.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Returns the codepoints (as integers) from all characters in s that start
|
||||||
|
-- between byte position i and j (both included). The default for i is 1 and for j is i.
|
||||||
|
-- It raises an error if it meets any invalid byte sequence.
|
||||||
|
-- @function [parent=#utf8] codepoint
|
||||||
|
-- @param #string s string to handle
|
||||||
|
-- @param #number i the initial position (default value is 1)
|
||||||
|
-- @param #number j the final position (default value is i)
|
||||||
|
-- @return #number the codepoints of each character in s
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Returns the number of UTF-8 characters in string s that start
|
||||||
|
-- between positions i and j (both inclusive).
|
||||||
|
-- The default for i is 1 and for j is -1.
|
||||||
|
-- If it finds any invalid byte sequence,
|
||||||
|
-- returns a false value plus the position of the first invalid byte.
|
||||||
|
-- @function [parent=#utf8] len
|
||||||
|
-- @param #string s string to handle
|
||||||
|
-- @param #number i the initial position (default value is 1)
|
||||||
|
-- @param #number j the final position (default value is -1)
|
||||||
|
-- @return #number the number of utf8 characters in s
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Returns the position (in bytes) where the encoding of the n-th character of s
|
||||||
|
-- (counting from position i) starts. A negative n gets characters before position i.
|
||||||
|
-- The default for i is 1 when n is non-negative and #s + 1 otherwise,
|
||||||
|
-- so that utf8.offset(s, -n) gets the offset of the n-th character from the end of the string.
|
||||||
|
-- If the specified character is neither in the subject nor right after its end, the function returns nil.
|
||||||
|
--
|
||||||
|
-- As a special case, when n is 0 the function returns the
|
||||||
|
-- start of the encoding of the character that contains the i-th byte of s.
|
||||||
|
--
|
||||||
|
-- This function assumes that s is a valid UTF-8 string.
|
||||||
|
-- @function [parent=#utf8] offset
|
||||||
|
-- @param #string s string to handle
|
||||||
|
-- @param #number n the n-th character
|
||||||
|
-- @param #number i the initial position (default value is 1 if n is is non-negative and #s + 1 otherwise)
|
||||||
|
-- @return #number
|
||||||
|
|
||||||
|
return nil
|
Loading…
Reference in a new issue