#include "camerabindings.hpp" #include #include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwrender/camera.hpp" #include "../mwrender/renderingmanager.hpp" namespace MWLua { using CameraMode = MWRender::Camera::Mode; sol::table initCameraPackage(sol::state_view& lua) { MWRender::Camera* camera = MWBase::Environment::get().getWorld()->getCamera(); MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager(); sol::table api(lua, sol::create); api["MODE"] = LuaUtil::makeStrictReadOnly( lua.create_table_with("Static", CameraMode::Static, "FirstPerson", CameraMode::FirstPerson, "ThirdPerson", CameraMode::ThirdPerson, "Vanity", CameraMode::Vanity, "Preview", CameraMode::Preview)); api["getMode"] = [camera]() -> int { return static_cast(camera->getMode()); }; api["getQueuedMode"] = [camera]() -> sol::optional { std::optional mode = camera->getQueuedMode(); if (mode) return static_cast(*mode); else return sol::nullopt; }; api["setMode"] = [camera](int mode, sol::optional force) { camera->setMode(static_cast(mode), force ? *force : false); }; api["allowCharacterDeferredRotation"] = [camera](bool v) { camera->allowCharacterDeferredRotation(v); }; api["showCrosshair"] = [camera](bool v) { camera->showCrosshair(v); }; api["getTrackedPosition"] = [camera]() -> osg::Vec3f { return camera->getTrackedPosition(); }; api["getPosition"] = [camera]() -> osg::Vec3f { return camera->getPosition(); }; // All angles are negated in order to make camera rotation consistent with objects rotation. // TODO: Fix the inconsistency of rotation direction in camera.cpp. api["getPitch"] = [camera]() { return -camera->getPitch(); }; api["getYaw"] = [camera]() { return -camera->getYaw(); }; api["getRoll"] = [camera]() { return -camera->getRoll(); }; api["setStaticPosition"] = [camera](const osg::Vec3f& pos) { camera->setStaticPosition(pos); }; api["setPitch"] = [camera](float v) { camera->setPitch(-v, true); if (camera->getMode() == CameraMode::ThirdPerson) camera->calculateDeferredRotation(); }; api["setYaw"] = [camera](float v) { camera->setYaw(-v, true); if (camera->getMode() == CameraMode::ThirdPerson) camera->calculateDeferredRotation(); }; api["setRoll"] = [camera](float v) { camera->setRoll(-v); }; api["setExtraPitch"] = [camera](float v) { camera->setExtraPitch(-v); }; api["setExtraYaw"] = [camera](float v) { camera->setExtraYaw(-v); }; api["setExtraRoll"] = [camera](float v) { camera->setExtraRoll(-v); }; api["getExtraPitch"] = [camera]() { return -camera->getExtraPitch(); }; api["getExtraYaw"] = [camera]() { return -camera->getExtraYaw(); }; api["getExtraRoll"] = [camera]() { return -camera->getExtraRoll(); }; api["getThirdPersonDistance"] = [camera]() { return camera->getCameraDistance(); }; api["setPreferredThirdPersonDistance"] = [camera](float v) { camera->setPreferredCameraDistance(v); }; api["getFirstPersonOffset"] = [camera]() { return camera->getFirstPersonOffset(); }; api["setFirstPersonOffset"] = [camera](const osg::Vec3f& v) { camera->setFirstPersonOffset(v); }; api["getFocalPreferredOffset"] = [camera]() -> osg::Vec2f { return camera->getFocalPointTargetOffset(); }; api["setFocalPreferredOffset"] = [camera](const osg::Vec2f& v) { camera->setFocalPointTargetOffset(v); }; api["getFocalTransitionSpeed"] = [camera]() { return camera->getFocalPointTransitionSpeed(); }; 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(Settings::camera().mFieldOfView); }; api["getFieldOfView"] = [renderingManager]() { return osg::DegreesToRadians(renderingManager->getFieldOfView()); }; api["setFieldOfView"] = [renderingManager](float v) { renderingManager->setFieldOfView(osg::RadiansToDegrees(v)); }; api["getBaseViewDistance"] = [] { return Settings::camera().mViewingDistance.get(); }; api["getViewDistance"] = [renderingManager]() { return renderingManager->getViewDistance(); }; api["setViewDistance"] = [renderingManager](float d) { renderingManager->setViewDistance(d, true); }; api["getViewTransform"] = [camera]() { return LuaUtil::TransformM{ camera->getViewMatrix() }; }; api["viewportToWorldVector"] = [camera, renderingManager](osg::Vec2f pos) -> osg::Vec3f { const double width = Settings::video().mResolutionX; const double height = Settings::video().mResolutionY; 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(); }; api["worldToViewportVector"] = [camera](osg::Vec3f pos) { const double width = Settings::video().mResolutionX; const double height = Settings::video().mResolutionY; osg::Matrix windowMatrix = osg::Matrix::translate(1.0, 1.0, 1.0) * osg::Matrix::scale(0.5 * width, 0.5 * height, 0.5); osg::Vec3f vpCoords = pos * (camera->getViewMatrix() * camera->getProjectionMatrix() * windowMatrix); // Move 0,0 to top left to match viewportToWorldVector vpCoords.y() = height - vpCoords.y(); // Set the z component to be distance from camera, in world space units vpCoords.z() = (pos - camera->getPosition()).length(); return vpCoords; }; return LuaUtil::makeReadOnly(api); } }