mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-14 01:19:59 +00:00
Merge branch 'landscape-data-bindings' into 'master'
Landscape height and texture bindings for Lua (Revised) See merge request OpenMW/openmw!4500
This commit is contained in:
commit
30baadbfb3
@ -1,3 +1,8 @@
|
||||
0.50.0
|
||||
------
|
||||
|
||||
Feature #8112: Expose landscape record data to Lua
|
||||
|
||||
0.49.0
|
||||
------
|
||||
|
||||
|
@ -62,7 +62,7 @@ add_openmw_dir (mwlua
|
||||
luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant
|
||||
context menuscripts globalscripts localscripts playerscripts luabindings objectbindings cellbindings
|
||||
mwscriptbindings camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings dialoguebindings
|
||||
postprocessingbindings stats recordstore debugbindings corebindings worldbindings worker magicbindings factionbindings
|
||||
postprocessingbindings stats recordstore debugbindings corebindings worldbindings worker landbindings magicbindings factionbindings
|
||||
classbindings itemdata inputprocessor animationbindings birthsignbindings racebindings markupbindings
|
||||
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
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "dialoguebindings.hpp"
|
||||
#include "factionbindings.hpp"
|
||||
#include "landbindings.hpp"
|
||||
#include "luaevents.hpp"
|
||||
#include "magicbindings.hpp"
|
||||
#include "soundbindings.hpp"
|
||||
@ -97,6 +98,8 @@ namespace MWLua
|
||||
api["stats"]
|
||||
= context.cachePackage("openmw_core_stats", [context]() { return initCoreStatsBindings(context); });
|
||||
|
||||
api["land"] = context.cachePackage("openmw_core_land", [context]() { return initCoreLandBindings(context); });
|
||||
|
||||
api["factions"]
|
||||
= context.cachePackage("openmw_core_factions", [context]() { return initCoreFactionBindings(context); });
|
||||
api["dialogue"]
|
||||
|
121
apps/openmw/mwlua/landbindings.cpp
Normal file
121
apps/openmw/mwlua/landbindings.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include "landbindings.hpp"
|
||||
|
||||
#include <apps/openmw/mwlua/object.hpp>
|
||||
#include <apps/openmw/mwworld/cellstore.hpp>
|
||||
#include <apps/openmw/mwworld/worldmodel.hpp>
|
||||
|
||||
#include <components/esm/util.hpp>
|
||||
#include <components/esmterrain/storage.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
// Takes in a corrected world pos to match the visuals.
|
||||
ESMTerrain::UniqueTextureId getTextureAt(const std::span<const std::uint16_t> landData, const int plugin,
|
||||
const osg::Vec3f& correctedWorldPos, const float cellSize)
|
||||
{
|
||||
int cellX = static_cast<int>(std::floor(correctedWorldPos.x() / cellSize));
|
||||
int cellY = static_cast<int>(std::floor(correctedWorldPos.y() / cellSize));
|
||||
|
||||
// Normalized position in the cell
|
||||
float nX = (correctedWorldPos.x() - (cellX * cellSize)) / cellSize;
|
||||
float nY = (correctedWorldPos.y() - (cellY * cellSize)) / cellSize;
|
||||
|
||||
int startX = static_cast<int>(nX * ESM::Land::LAND_TEXTURE_SIZE);
|
||||
int startY = static_cast<int>(nY * ESM::Land::LAND_TEXTURE_SIZE);
|
||||
|
||||
assert(startX < ESM::Land::LAND_TEXTURE_SIZE);
|
||||
assert(startY < ESM::Land::LAND_TEXTURE_SIZE);
|
||||
|
||||
const std::uint16_t tex = landData[startY * ESM::Land::LAND_TEXTURE_SIZE + startX];
|
||||
if (tex == 0)
|
||||
return { 0, 0 }; // vtex 0 is always the base texture, regardless of plugin
|
||||
|
||||
return { tex, plugin };
|
||||
}
|
||||
|
||||
const ESM::RefId worldspaceAt(sol::object cellOrName)
|
||||
{
|
||||
const MWWorld::Cell* cell = nullptr;
|
||||
if (cellOrName.is<MWLua::GCell>())
|
||||
cell = cellOrName.as<MWLua::GCell>().mStore->getCell();
|
||||
else if (cellOrName.is<MWLua::LCell>())
|
||||
cell = cellOrName.as<MWLua::LCell>().mStore->getCell();
|
||||
else if (cellOrName.is<std::string_view>() && !cellOrName.as<std::string_view>().empty())
|
||||
cell = MWBase::Environment::get().getWorldModel()->getCell(cellOrName.as<std::string_view>()).getCell();
|
||||
if (cell == nullptr)
|
||||
throw std::runtime_error("Invalid cell");
|
||||
else if (!cell->isExterior())
|
||||
throw std::runtime_error("Cell cannot be interior");
|
||||
|
||||
return cell->getWorldSpace();
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
sol::table initCoreLandBindings(const Context& context)
|
||||
{
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table landApi(lua, sol::create);
|
||||
|
||||
landApi["getHeightAt"] = [](const osg::Vec3f& pos, sol::object cellOrName) {
|
||||
ESM::RefId worldspace = worldspaceAt(cellOrName);
|
||||
return MWBase::Environment::get().getWorld()->getTerrainHeightAt(pos, worldspace);
|
||||
};
|
||||
|
||||
landApi["getTextureAt"] = [lua = lua](const osg::Vec3f& pos, sol::object cellOrName) {
|
||||
sol::variadic_results values;
|
||||
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
||||
const MWWorld::Store<ESM::Land>& landStore = store.get<ESM::Land>();
|
||||
ESM::RefId worldspace = worldspaceAt(cellOrName);
|
||||
|
||||
if (worldspace != ESM::Cell::sDefaultWorldspaceId)
|
||||
return values;
|
||||
|
||||
const float cellSize = ESM::getCellSize(worldspace);
|
||||
const float offset = (cellSize / ESM::LandRecordData::sLandTextureSize) * 0.25;
|
||||
const osg::Vec3f correctedPos = pos + osg::Vec3f{ -offset, +offset, 0.0f };
|
||||
|
||||
const ESM::Land* land = nullptr;
|
||||
const ESM::Land::LandData* landData = nullptr;
|
||||
|
||||
int cellX = static_cast<int>(std::floor(correctedPos.x() / cellSize));
|
||||
int cellY = static_cast<int>(std::floor(correctedPos.y() / cellSize));
|
||||
|
||||
land = landStore.search(cellX, cellY);
|
||||
|
||||
if (land != nullptr)
|
||||
landData = land->getLandData(ESM::Land::DATA_VTEX);
|
||||
|
||||
// If we fail to preload land data, return, we need to be able to get *any* land to know how to correct
|
||||
// the position used to sample terrain
|
||||
if (landData == nullptr)
|
||||
return values;
|
||||
|
||||
const ESMTerrain::UniqueTextureId textureId
|
||||
= getTextureAt(landData->mTextures, land->getPlugin(), correctedPos, cellSize);
|
||||
|
||||
// Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId
|
||||
if (textureId.first != 0)
|
||||
{
|
||||
const MWWorld::Store<ESM::LandTexture>& textureStore = store.get<ESM::LandTexture>();
|
||||
const std::string* textureString = textureStore.search(textureId.first - 1, textureId.second);
|
||||
if (!textureString)
|
||||
return values;
|
||||
|
||||
values.push_back(sol::make_object<std::string>(lua, *textureString));
|
||||
const std::vector<std::string>& contentList = MWBase::Environment::get().getWorld()->getContentFiles();
|
||||
if (textureId.second >= 0 && static_cast<size_t>(textureId.second) < contentList.size())
|
||||
values.push_back(sol::make_object<std::string>(lua, contentList[textureId.second]));
|
||||
}
|
||||
|
||||
return values;
|
||||
};
|
||||
|
||||
return LuaUtil::makeReadOnly(landApi);
|
||||
}
|
||||
}
|
11
apps/openmw/mwlua/landbindings.hpp
Normal file
11
apps/openmw/mwlua/landbindings.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef MWLUA_LANDBINDINGS_H
|
||||
#define MWLUA_LANDBINDINGS_H
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
sol::table initCoreLandBindings(const Context& context);
|
||||
}
|
||||
|
||||
#endif // MWLUA_LANDBINDINGS_H
|
@ -450,6 +450,25 @@
|
||||
-- @usage for _, item in ipairs(inventory:findAll('common_shirt_01')) do ... end
|
||||
|
||||
|
||||
--- @{#Land}: Functions for interacting with land data
|
||||
-- @field [parent=#core] #Land land
|
||||
|
||||
---
|
||||
-- Get the terrain height at a given location.
|
||||
-- @function [parent=#Land] getHeightAt
|
||||
-- @param openmw.util#Vector3 position
|
||||
-- @param #any cellOrName (optional) cell or cell name in their exterior world space to query
|
||||
-- @return #number
|
||||
|
||||
---
|
||||
-- Get the terrain texture at a given location.
|
||||
-- @function [parent=#Land] getTextureAt
|
||||
-- @param openmw.util#Vector3 position
|
||||
-- @param #any cellOrName cell or cell name in their exterior world space to query
|
||||
-- @return #nil, #string Texture path or nil if one isn't defined
|
||||
-- @return #nil, #string Plugin name or nil if failed to retrieve the texture
|
||||
|
||||
|
||||
--- @{#Magic}: spells and spell effects
|
||||
-- @field [parent=#core] #Magic magic
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user