Merge branch 'lua' into 'master'

More Lua bindings for the camera + some minor improvements

See merge request OpenMW/openmw!1742
pull/3226/head
psi29a 3 years ago
commit 9282f8f091

@ -64,6 +64,7 @@ namespace MWRender
{
class Animation;
class Camera;
class RenderingManager;
}
namespace MWMechanics
@ -664,6 +665,8 @@ namespace MWBase
virtual std::vector<MWWorld::Ptr> getAll(const std::string& id) = 0;
virtual Misc::Rng::Generator& getPrng() = 0;
virtual MWRender::RenderingManager* getRenderingManager() = 0;
};
}

@ -1,6 +1,10 @@
#include "luabindings.hpp"
#include <components/lua/utilpackage.hpp>
#include <components/settings/settings.hpp>
#include "../mwrender/camera.hpp"
#include "../mwrender/renderingmanager.hpp"
namespace MWLua
{
@ -10,6 +14,7 @@ namespace MWLua
sol::table initCameraPackage(const Context& context)
{
MWRender::Camera* camera = MWBase::Environment::get().getWorld()->getCamera();
MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager();
sol::table api(context.mLua->sol(), sol::create);
api["MODE"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with(
@ -77,6 +82,31 @@ namespace MWLua
api["setFocalTransitionSpeed"] = [camera](float v) { camera->setFocalPointTransitionSpeed(v); };
api["instantTransition"] = [camera]() { camera->instantTransition(); };
api["getCollisionType"] = [camera]() { return camera->getCollisionType(); };
api["setCollisionType"] = [camera](int collisionType) { camera->setCollisionType(collisionType); };
api["getBaseFieldOfView"] = []()
{
return osg::DegreesToRadians(std::clamp(Settings::Manager::getFloat("field of view", "Camera"), 1.f, 179.f));
};
api["getFieldOfView"] = [renderingManager]() { return osg::DegreesToRadians(renderingManager->getFieldOfView()); };
api["setFieldOfView"] = [renderingManager](float v) { renderingManager->setFieldOfView(osg::RadiansToDegrees(v)); };
api["getViewTransform"] = [camera]() { return LuaUtil::TransformM{camera->getViewMatrix()}; };
api["viewportToWorldVector"] = [camera, renderingManager](osg::Vec2f pos) -> osg::Vec3f
{
double width = Settings::Manager::getInt("resolution x", "Video");
double height = Settings::Manager::getInt("resolution y", "Video");
double aspect = (height == 0.0) ? 1.0 : width / height;
double fovTan = std::tan(osg::DegreesToRadians(renderingManager->getFieldOfView()) / 2);
osg::Matrixf invertedViewMatrix;
invertedViewMatrix.invert(camera->getViewMatrix());
float x = (pos.x() * 2 - 1) * aspect * fovTan;
float y = (1 - pos.y() * 2) * fovTan;
return invertedViewMatrix.preMult(osg::Vec3f(x, y, -1)) - camera->getPosition();
};
return LuaUtil::makeReadOnly(api);
}

@ -41,7 +41,7 @@ namespace MWLua
{
auto* lua = context.mLua;
sol::table api(lua->sol(), sol::create);
api["API_REVISION"] = 19;
api["API_REVISION"] = 20;
api["quit"] = [lua]()
{
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();

@ -88,7 +88,7 @@ namespace MWLua
[](const LObject& o) { return Inventory<LObject>{o}; },
[](const GObject& o) { return Inventory<GObject>{o}; }
);
actor["equipment"] = [context](const Object& o)
auto getAllEquipment = [context](const Object& o)
{
const MWWorld::Ptr& ptr = o.ptr();
sol::table equipment(context.mLua->sol(), sol::create);
@ -106,6 +106,20 @@ namespace MWLua
}
return equipment;
};
auto getEquipmentFromSlot = [context](const Object& o, int slot) -> sol::object
{
const MWWorld::Ptr& ptr = o.ptr();
sol::table equipment(context.mLua->sol(), sol::create);
if (!ptr.getClass().hasInventoryStore(ptr))
return sol::nil;
MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr);
auto it = store.getSlot(slot);
if (it == store.end())
return sol::nil;
context.mWorldView->getObjectRegistry()->registerPtr(*it);
return o.getObject(context.mLua->sol(), getId(*it));
};
actor["equipment"] = sol::overload(getAllEquipment, getEquipmentFromSlot);
actor["hasEquipped"] = [](const Object& o, const Object& item)
{
const MWWorld::Ptr& ptr = o.ptr();

@ -1556,7 +1556,7 @@ namespace MWMechanics
mov.mRotation[2] = luaControls->mYawChange;
mov.mSpeedFactor = osg::Vec2(luaControls->mMovement, luaControls->mSideMovement).length();
stats.setMovementFlag(MWMechanics::CreatureStats::Flag_Run, luaControls->mRun);
stats.setAttackingOrSpell(luaControls->mUse == 1);
stats.setAttackingOrSpell((luaControls->mUse & 1) == 1);
luaControls->mChanged = false;
}
luaControls->mSideMovement = movement.x();

@ -53,6 +53,7 @@ namespace MWRender
Camera::Camera (osg::Camera* camera)
: mHeightScale(1.f),
mCollisionType(MWPhysics::CollisionType::CollisionType_Default & ~MWPhysics::CollisionType::CollisionType_Actor),
mCamera(camera),
mAnimation(nullptr),
mFirstPersonView(true),
@ -127,6 +128,7 @@ namespace MWRender
pos = calculateFirstPersonPosition(recalculatedTrackedPosition);
}
cam->setViewMatrixAsLookAt(pos, pos + forward, up);
mViewMatrix = cam->getViewMatrix();
}
void Camera::update(float duration, bool paused)
@ -174,7 +176,6 @@ namespace MWRender
constexpr float focalObstacleLimit = 10.f;
const auto* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting();
constexpr int collisionType = (MWPhysics::CollisionType::CollisionType_Default & ~MWPhysics::CollisionType::CollisionType_Actor);
// Adjust focal point to prevent clipping.
osg::Vec3d focalOffset = getFocalPointOffset();
@ -184,7 +185,7 @@ namespace MWRender
float offsetLen = focalOffset.length();
if (offsetLen > 0)
{
MWPhysics::RayCastingResult result = rayCasting->castSphere(focal - focalOffset, focal, focalObstacleLimit, collisionType);
MWPhysics::RayCastingResult result = rayCasting->castSphere(focal - focalOffset, focal, focalObstacleLimit, mCollisionType);
if (result.mHit)
{
double adjustmentCoef = -(result.mHitPos + result.mHitNormal * focalObstacleLimit - focal).length() / offsetLen;
@ -196,7 +197,7 @@ namespace MWRender
mCameraDistance = mPreferredCameraDistance;
osg::Quat orient = osg::Quat(mPitch + mExtraPitch, osg::Vec3d(1,0,0)) * osg::Quat(mYaw + mExtraYaw, osg::Vec3d(0,0,1));
osg::Vec3d offset = orient * osg::Vec3d(0.f, -mCameraDistance, 0.f);
MWPhysics::RayCastingResult result = rayCasting->castSphere(focal, focal + offset, cameraObstacleLimit, collisionType);
MWPhysics::RayCastingResult result = rayCasting->castSphere(focal, focal + offset, cameraObstacleLimit, mCollisionType);
if (result.mHit)
{
mCameraDistance = (result.mHitPos + result.mHitNormal * cameraObstacleLimit - focal).length();
@ -211,7 +212,7 @@ namespace MWRender
if (mMode == newMode)
return;
Mode oldMode = mMode;
if (!force && (newMode == Mode::FirstPerson || oldMode == Mode::FirstPerson) && !mAnimation->upperBodyReady())
if (!force && (newMode == Mode::FirstPerson || oldMode == Mode::FirstPerson) && mAnimation && !mAnimation->upperBodyReady())
{
// Changing the view will stop all playing animations, so if we are playing
// anything important, queue the view change for later

@ -5,6 +5,7 @@
#include <string>
#include <osg/ref_ptr>
#include <osg/Matrix>
#include <osg/Vec3>
#include <osg/Vec3d>
@ -95,11 +96,17 @@ namespace MWRender
void setFirstPersonOffset(const osg::Vec3f& v) { mFirstPersonOffset = v; }
osg::Vec3f getFirstPersonOffset() const { return mFirstPersonOffset; }
int getCollisionType() const { return mCollisionType; }
void setCollisionType(int collisionType) { mCollisionType = collisionType; }
const osg::Matrixf& getViewMatrix() const { return mViewMatrix; }
private:
MWWorld::Ptr mTrackingPtr;
osg::ref_ptr<const osg::Node> mTrackingNode;
osg::Vec3d mTrackedPosition;
float mHeightScale;
int mCollisionType;
osg::ref_ptr<osg::Camera> mCamera;
@ -121,6 +128,7 @@ namespace MWRender
float mExtraPitch = 0, mExtraYaw = 0;
bool mLockPitch = false, mLockYaw = false;
osg::Vec3d mPosition;
osg::Matrixf mViewMatrix;
float mCameraDistance, mPreferredCameraDistance;

@ -817,6 +817,11 @@ namespace MWRender
updateNavMesh();
updateRecastMesh();
if (mUpdateProjectionMatrix)
{
mUpdateProjectionMatrix = false;
updateProjectionMatrix();
}
mCamera->update(dt, paused);
bool isUnderwater = mWater->isUnderwater(mCamera->getPosition());
@ -1161,8 +1166,7 @@ namespace MWRender
// Since our fog is not radial yet, we should take FOV in account, otherwise terrain near viewing distance may disappear.
// Limit FOV here just for sure, otherwise viewing distance can be too high.
fov = std::min(mFieldOfView, 140.f);
float distanceMult = std::cos(osg::DegreesToRadians(fov)/2.f);
float distanceMult = std::cos(osg::DegreesToRadians(std::min(fov, 140.f))/2.f);
mTerrain->setViewDistance(mViewDistance * (distanceMult ? 1.f/distanceMult : 1.f));
}
@ -1300,6 +1304,17 @@ namespace MWRender
}
}
void RenderingManager::setFieldOfView(float val)
{
mFieldOfView = val;
mUpdateProjectionMatrix = true;
}
float RenderingManager::getFieldOfView() const
{
return mFieldOfViewOverridden ? mFieldOfViewOverridden : mFieldOfView;
}
osg::Vec3f RenderingManager::getHalfExtents(const MWWorld::ConstPtr& object) const
{
osg::Vec3f halfExtents(0, 0, 0);

@ -214,6 +214,8 @@ namespace MWRender
/// temporarily override the field of view with given value.
void overrideFieldOfView(float val);
void setFieldOfView(float val);
float getFieldOfView() const;
/// reset a previous overrideFieldOfView() call, i.e. revert to field of view specified in the settings file.
void resetFieldOfView();
@ -301,6 +303,7 @@ namespace MWRender
float mFieldOfViewOverride;
float mFieldOfView;
float mFirstPersonFieldOfView;
bool mUpdateProjectionMatrix = false;
void operator = (const RenderingManager&);
RenderingManager(const RenderingManager&);

@ -743,6 +743,8 @@ namespace MWWorld
std::vector<MWWorld::Ptr> getAll(const std::string& id) override;
Misc::Rng::Generator& getPrng() override;
MWRender::RenderingManager* getRenderingManager() override { return mRendering.get(); }
};
}

@ -51,7 +51,7 @@ namespace LuaUtil
LuaState::LuaState(const VFS::Manager* vfs, const ScriptsConfiguration* conf) : mConf(conf), mVFS(vfs)
{
mLua.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::math,
mLua.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::math, sol::lib::bit32,
sol::lib::string, sol::lib::table, sol::lib::os, sol::lib::debug);
mLua["math"]["randomseed"](static_cast<unsigned>(std::time(nullptr)));

@ -216,6 +216,37 @@ namespace LuaUtil
util["normalizeAngle"] = &Misc::normalizeAngle;
util["makeReadOnly"] = &makeReadOnly;
if (lua["bit32"] != sol::nil)
{
sol::table bit = lua["bit32"];
util["bitOr"] = bit["bor"];
util["bitAnd"] = bit["band"];
util["bitXor"] = bit["bxor"];
util["bitNot"] = bit["bnot"];
}
else
{
util["bitOr"] = [](unsigned a, sol::variadic_args va)
{
for (auto v : va)
a |= v.as<unsigned>();
return a;
};
util["bitAnd"] = [](unsigned a, sol::variadic_args va)
{
for (auto v : va)
a &= v.as<unsigned>();
return a;
};
util["bitXor"] = [](unsigned a, sol::variadic_args va)
{
for (auto v : va)
a ^= v.as<unsigned>();
return a;
};
util["bitNot"] = [](unsigned a) { return ~a; };
}
return util;
}

@ -2,29 +2,22 @@ if (NOT DEFINED OPENMW_RESOURCES_ROOT)
return()
endif()
# Copy resource files into the build directory
set(SDIR ${CMAKE_CURRENT_SOURCE_DIR})
set(DDIRRELATIVE resources/vfs)
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_RESOURCES_ROOT} ${DDIRRELATIVE} "builtin.omwscripts")
set(LUA_BUILTIN_FILES
builtin.omwscripts
set(LUA_AUX_FILES
openmw_aux/util.lua
openmw_aux/time.lua
openmw_aux/calendar.lua
)
set(DDIRRELATIVE resources/vfs/openmw_aux)
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_RESOURCES_ROOT} ${DDIRRELATIVE} "${LUA_AUX_FILES}")
set(LUA_SCRIPTS_FILES
scripts/omw/ai.lua
scripts/omw/camera.lua
scripts/omw/head_bobbing.lua
scripts/omw/third_person.lua
i18n/Calendar/en.lua
)
set(DDIRRELATIVE resources/vfs/scripts/omw)
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_RESOURCES_ROOT} ${DDIRRELATIVE} "${LUA_SCRIPTS_FILES}")
foreach (f ${LUA_BUILTIN_FILES})
copy_resource_file("${CMAKE_CURRENT_SOURCE_DIR}/${f}" "${OPENMW_RESOURCES_ROOT}" "resources/vfs/${f}")
endforeach (f)
set(DDIRRELATIVE resources/vfs/i18n/Calendar)
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_RESOURCES_ROOT} ${DDIRRELATIVE} "i18n/Calendar/en.lua")

@ -4,6 +4,7 @@ local input = require('openmw.input')
local settings = require('openmw.settings')
local util = require('openmw.util')
local self = require('openmw.self')
local nearby = require('openmw.nearby')
local Actor = require('openmw.types').Actor
@ -23,6 +24,8 @@ local noHeadBobbing = 0
local noZoom = 0
local function init()
camera.setCollisionType(util.bitAnd(nearby.COLLISION_TYPE.Default, util.bitNot(nearby.COLLISION_TYPE.Actor)))
camera.setFieldOfView(camera.getBaseFieldOfView())
camera.allowCharacterDeferredRotation(settings._getBoolFromSettingsCfg('Camera', 'deferred preview rotation'))
if camera.getMode() == MODE.FirstPerson then
primaryMode = MODE.FirstPerson

@ -78,6 +78,8 @@ local function updateState()
state = STATE.Swimming
elseif oldState == STATE.Combat or oldState == STATE.Swimming then
state = defaultShoulder
elseif not state then
state = defaultShoulder
end
if autoSwitchShoulder and (mode == MODE.ThirdPerson or state ~= oldState or noThirdPersonLastFrame)
and (state == STATE.LeftShoulder or state == STATE.RightShoulder) then

@ -166,6 +166,36 @@
-- Make instant the current transition of camera focal point and the current deferred rotation (see `allowCharacterDeferredRotation`).
-- @function [parent=#camera] instantTransition
--- Get current camera collision type (see @{openmw.nearby#COLLISION_TYPE}).
-- @function [parent=#camera] getCollisionType
-- @return #number
--- Set camera collision type (see @{openmw.nearby#COLLISION_TYPE}).
-- @function [parent=#camera] setCollisionType
-- @param #number collisionType
--- Return base field of view vertical angle in radians
-- @function [parent=#camera] getBaseFieldOfView
-- @return #number
--- Return current field of view vertical angle in radians
-- @function [parent=#camera] getFieldOfView
-- @return #number
--- Set field of view
-- @function [parent=#camera] setFieldOfView
-- @param #number fov Field of view vertical angle in radians
--- Get world to local transform for the camera.
-- @function [parent=#camera] getViewTransform
-- @return openmw.util#Transform
--- Get vector from the camera to the world for the given point in viewport.
-- (0, 0) is the top left corner of the screen.
-- @function [parent=#camera] viewportToWorldVector
-- @param openmw.util#Vector2 normalizedScreenPos
-- @return openmw.util#Vector3
return nil

@ -108,12 +108,14 @@
---
-- Get equipment.
-- Returns a table `slot` -> @{openmw.core#GameObject} of currently equipped items.
-- Has two overloads:
-- 1) With single argument: returns a table `slot` -> @{openmw.core#GameObject} of currently equipped items.
-- See @{#EQUIPMENT_SLOT}. Returns empty table if the actor doesn't have
-- equipment slots.
-- equipment slots.
-- 2) With two arguments: returns an item equipped to the given slot.
-- @function [parent=#Actor] equipment
-- @param openmw.core#GameObject actor
-- @return #map<#number,openmw.core#GameObject>
-- @param #number slot (optional argument)
---
-- Set equipment.

@ -25,6 +25,33 @@
-- @param #table table Any table.
-- @return #table The same table wrapped with read only userdata.
---
-- Bitwise And (supports any number of arguments).
-- @function [parent=#util] bitAnd
-- @param #number A First argument (integer).
-- @param #number B Second argument (integer).
-- @return #number Bitwise And of A and B.
---
-- Bitwise Or (supports any number of arguments).
-- @function [parent=#util] bitOr
-- @param #number A First argument (integer).
-- @param #number B Second argument (integer).
-- @return #number Bitwise Or of A and B.
---
-- Bitwise Xor (supports any number of arguments).
-- @function [parent=#util] bitXor
-- @param #number A First argument (integer).
-- @param #number B Second argument (integer).
-- @return #number Bitwise Xor of A and B.
---
-- Bitwise inversion.
-- @function [parent=#util] bitNot
-- @param #number A Argument (integer).
-- @return #number Bitwise Not of A.
---
-- Immutable 2D vector

Loading…
Cancel
Save