2012-09-12 22:54:32 +00:00
# include "characterpreview.hpp"
2018-04-23 18:17:25 +00:00
# include <cmath>
2015-06-14 21:13:26 +00:00
2017-03-14 04:02:31 +00:00
# include <osg/Material>
2016-02-16 21:32:59 +00:00
# include <osg/Fog>
2017-02-21 17:29:18 +00:00
# include <osg/BlendFunc>
2021-01-20 01:17:16 +00:00
# include <osg/TexEnvCombine>
2015-05-20 00:18:20 +00:00
# include <osg/Texture2D>
# include <osg/Camera>
# include <osg/PositionAttitudeTransform>
# include <osg/LightModel>
2016-08-16 20:47:45 +00:00
# include <osg/LightSource>
2021-03-11 01:01:55 +00:00
# include <osg/ValueObject>
2015-05-20 01:35:52 +00:00
# include <osgUtil/IntersectionVisitor>
# include <osgUtil/LineSegmentIntersector>
2012-09-14 12:34:18 +00:00
2018-08-14 19:05:43 +00:00
# include <components/debug/debuglog.hpp>
2018-04-22 19:31:56 +00:00
# include <components/fallback/fallback.hpp>
2021-01-20 23:37:19 +00:00
# include <components/resource/scenemanager.hpp>
# include <components/resource/resourcesystem.hpp>
2015-05-20 00:18:20 +00:00
# include <components/sceneutil/lightmanager.hpp>
2017-11-08 13:38:30 +00:00
# include <components/sceneutil/shadow.hpp>
2020-12-28 22:39:09 +00:00
# include <components/settings/settings.hpp>
2012-09-12 22:54:32 +00:00
2012-09-14 22:57:29 +00:00
# include "../mwbase/world.hpp"
2013-01-06 05:12:08 +00:00
# include "../mwworld/class.hpp"
2013-04-29 19:08:43 +00:00
# include "../mwworld/inventorystore.hpp"
2012-09-14 22:57:29 +00:00
2015-08-21 09:12:39 +00:00
# include "../mwmechanics/actorutil.hpp"
2018-12-26 09:45:28 +00:00
# include "../mwmechanics/weapontype.hpp"
2015-08-21 09:12:39 +00:00
2012-09-13 17:03:31 +00:00
# include "npcanimation.hpp"
2020-04-20 16:47:14 +00:00
# include "vismask.hpp"
2012-09-12 22:54:32 +00:00
namespace MWRender
{
2015-05-20 00:18:20 +00:00
class DrawOnceCallback : public osg : : NodeCallback
{
public :
DrawOnceCallback ( )
: mRendered ( false )
2015-11-30 04:39:51 +00:00
, mLastRenderedFrame ( 0 )
2015-05-20 00:18:20 +00:00
{
}
2020-10-16 18:18:54 +00:00
void operator ( ) ( osg : : Node * node , osg : : NodeVisitor * nv ) override
2015-05-20 00:18:20 +00:00
{
if ( ! mRendered )
{
mRendered = true ;
2015-11-30 04:39:51 +00:00
mLastRenderedFrame = nv - > getTraversalNumber ( ) ;
2017-02-21 17:25:25 +00:00
osg : : ref_ptr < osg : : FrameStamp > previousFramestamp = const_cast < osg : : FrameStamp * > ( nv - > getFrameStamp ( ) ) ;
osg : : FrameStamp * fs = new osg : : FrameStamp ( * previousFramestamp ) ;
fs - > setSimulationTime ( 0.0 ) ;
nv - > setFrameStamp ( fs ) ;
2015-11-30 04:39:51 +00:00
traverse ( node , nv ) ;
2017-02-21 17:25:25 +00:00
nv - > setFrameStamp ( previousFramestamp ) ;
2015-05-20 00:18:20 +00:00
}
else
{
2020-04-20 16:47:14 +00:00
node - > setNodeMask ( 0 ) ;
2015-05-20 00:18:20 +00:00
}
}
void redrawNextFrame ( )
{
mRendered = false ;
}
2015-11-30 04:39:51 +00:00
unsigned int getLastRenderedFrame ( ) const
{
return mLastRenderedFrame ;
}
2015-05-20 00:18:20 +00:00
private :
bool mRendered ;
2015-11-30 04:39:51 +00:00
unsigned int mLastRenderedFrame ;
2015-05-20 00:18:20 +00:00
} ;
2017-02-21 17:29:18 +00:00
2021-03-10 22:07:14 +00:00
// Set up alpha blending mode to avoid issues caused by transparent objects writing onto the alpha value of the FBO
// This makes the RTT have premultiplied alpha, though, so the source blend factor must be GL_ONE when it's applied
2017-02-21 17:29:18 +00:00
class SetUpBlendVisitor : public osg : : NodeVisitor
{
public :
2021-01-20 01:17:16 +00:00
SetUpBlendVisitor ( ) : osg : : NodeVisitor ( TRAVERSE_ALL_CHILDREN ) , mNoAlphaUniform ( new osg : : Uniform ( " noAlpha " , false ) )
2017-02-21 17:29:18 +00:00
{
}
2020-10-16 18:18:54 +00:00
void apply ( osg : : Node & node ) override
2017-02-21 17:29:18 +00:00
{
2021-03-10 22:07:14 +00:00
if ( osg : : ref_ptr < osg : : StateSet > stateset = node . getStateSet ( ) )
2017-02-21 17:29:18 +00:00
{
2021-03-10 22:07:14 +00:00
osg : : ref_ptr < osg : : StateSet > newStateSet ;
2017-02-21 17:29:18 +00:00
if ( stateset - > getAttribute ( osg : : StateAttribute : : BLENDFUNC ) | | stateset - > getBinNumber ( ) = = osg : : StateSet : : TRANSPARENT_BIN )
{
osg : : BlendFunc * blendFunc = static_cast < osg : : BlendFunc * > ( stateset - > getAttribute ( osg : : StateAttribute : : BLENDFUNC ) ) ;
2021-03-10 22:07:14 +00:00
if ( blendFunc )
{
newStateSet = new osg : : StateSet ( * stateset , osg : : CopyOp : : SHALLOW_COPY ) ;
node . setStateSet ( newStateSet ) ;
osg : : ref_ptr < osg : : BlendFunc > newBlendFunc = new osg : : BlendFunc ( * blendFunc ) ;
newStateSet - > setAttribute ( newBlendFunc , osg : : StateAttribute : : ON ) ;
// I *think* (based on some by-hand maths) that the RGB and dest alpha factors are unchanged, and only dest determines source alpha factor
// This has the benefit of being idempotent if we assume nothing used glBlendFuncSeparate before we touched it
if ( blendFunc - > getDestination ( ) = = osg : : BlendFunc : : ONE_MINUS_SRC_ALPHA )
newBlendFunc - > setSourceAlpha ( osg : : BlendFunc : : ONE ) ;
else if ( blendFunc - > getDestination ( ) = = osg : : BlendFunc : : ONE )
newBlendFunc - > setSourceAlpha ( osg : : BlendFunc : : ZERO ) ;
// Other setups barely exist in the wild and aren't worth supporting as they're not equippable gear
else
Log ( Debug : : Info ) < < " Unable to adjust blend mode for character preview. Source factor 0x " < < std : : hex < < blendFunc - > getSource ( ) < < " , destination factor 0x " < < blendFunc - > getDestination ( ) < < std : : dec ;
}
2017-02-21 17:29:18 +00:00
}
2021-01-20 01:17:16 +00:00
if ( stateset - > getMode ( GL_BLEND ) & osg : : StateAttribute : : ON )
{
2021-03-10 22:07:14 +00:00
if ( ! newStateSet )
{
newStateSet = new osg : : StateSet ( * stateset , osg : : CopyOp : : SHALLOW_COPY ) ;
node . setStateSet ( newStateSet ) ;
}
2021-01-20 01:17:16 +00:00
// Disable noBlendAlphaEnv
2021-03-10 22:07:14 +00:00
newStateSet - > setTextureMode ( 7 , GL_TEXTURE_2D , osg : : StateAttribute : : OFF ) ;
newStateSet - > addUniform ( mNoAlphaUniform ) ;
2021-01-20 01:17:16 +00:00
}
2017-02-21 17:29:18 +00:00
}
traverse ( node ) ;
}
2021-01-20 01:17:16 +00:00
private :
osg : : ref_ptr < osg : : Uniform > mNoAlphaUniform ;
2017-02-21 17:29:18 +00:00
} ;
2016-08-16 20:47:45 +00:00
CharacterPreview : : CharacterPreview ( osg : : Group * parent , Resource : : ResourceSystem * resourceSystem ,
2017-04-20 11:36:14 +00:00
const MWWorld : : Ptr & character , int sizeX , int sizeY , const osg : : Vec3f & position , const osg : : Vec3f & lookAt )
2016-08-16 20:47:45 +00:00
: mParent ( parent )
2015-05-20 00:18:20 +00:00
, mResourceSystem ( resourceSystem )
2012-09-14 22:57:29 +00:00
, mPosition ( position )
, mLookAt ( lookAt )
, mCharacter ( character )
2017-04-28 15:30:26 +00:00
, mAnimation ( nullptr )
2013-04-19 12:41:26 +00:00
, mSizeX ( sizeX )
, mSizeY ( sizeY )
2012-09-14 22:57:29 +00:00
{
2015-05-20 00:18:20 +00:00
mTexture = new osg : : Texture2D ;
mTexture - > setTextureSize ( sizeX , sizeY ) ;
mTexture - > setInternalFormat ( GL_RGBA ) ;
mTexture - > setFilter ( osg : : Texture : : MIN_FILTER , osg : : Texture : : LINEAR ) ;
mTexture - > setFilter ( osg : : Texture : : MAG_FILTER , osg : : Texture : : LINEAR ) ;
2021-03-10 22:07:14 +00:00
mTexture - > setUserValue ( " premultiplied alpha " , true ) ;
2015-05-20 00:18:20 +00:00
mCamera = new osg : : Camera ;
// hints that the camera is not relative to the master camera
mCamera - > setReferenceFrame ( osg : : Camera : : ABSOLUTE_RF ) ;
mCamera - > setRenderTargetImplementation ( osg : : Camera : : FRAME_BUFFER_OBJECT , osg : : Camera : : PIXEL_BUFFER_RTT ) ;
mCamera - > setClearColor ( osg : : Vec4 ( 0.f , 0.f , 0.f , 0.f ) ) ;
mCamera - > setClearMask ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
const float fovYDegrees = 12.3f ;
mCamera - > setProjectionMatrixAsPerspective ( fovYDegrees , sizeX / static_cast < float > ( sizeY ) , 0.1f , 10000.f ) ; // zNear and zFar are autocomputed
mCamera - > setViewport ( 0 , 0 , sizeX , sizeY ) ;
mCamera - > setRenderOrder ( osg : : Camera : : PRE_RENDER ) ;
2020-12-28 22:39:09 +00:00
mCamera - > attach ( osg : : Camera : : COLOR_BUFFER , mTexture , 0 , 0 , false , Settings : : Manager : : getInt ( " antialiasing " , " Video " ) ) ;
2017-02-02 20:46:25 +00:00
mCamera - > setName ( " CharacterPreview " ) ;
2017-07-21 22:34:36 +00:00
mCamera - > setComputeNearFarMode ( osg : : Camera : : COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES ) ;
2020-04-20 16:47:14 +00:00
mCamera - > setCullMask ( ~ ( Mask_UpdateVisitor ) ) ;
2015-05-20 00:18:20 +00:00
2020-04-20 16:47:14 +00:00
mCamera - > setNodeMask ( Mask_RenderToTexture ) ;
2015-05-26 14:40:44 +00:00
2021-03-15 04:42:34 +00:00
bool ffp = mResourceSystem - > getSceneManager ( ) - > getLightingMethod ( ) = = SceneUtil : : LightingMethod : : FFP ;
osg : : ref_ptr < SceneUtil : : LightManager > lightManager = new SceneUtil : : LightManager ( ffp ) ;
2015-05-20 00:18:20 +00:00
lightManager - > setStartLight ( 1 ) ;
2016-02-17 00:56:47 +00:00
osg : : ref_ptr < osg : : StateSet > stateset = lightManager - > getOrCreateStateSet ( ) ;
2015-05-20 00:18:20 +00:00
stateset - > setMode ( GL_LIGHTING , osg : : StateAttribute : : ON ) ;
stateset - > setMode ( GL_NORMALIZE , osg : : StateAttribute : : ON ) ;
stateset - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : ON ) ;
2017-03-14 04:02:31 +00:00
osg : : ref_ptr < osg : : Material > defaultMat ( new osg : : Material ) ;
defaultMat - > setColorMode ( osg : : Material : : OFF ) ;
defaultMat - > setAmbient ( osg : : Material : : FRONT_AND_BACK , osg : : Vec4f ( 1 , 1 , 1 , 1 ) ) ;
defaultMat - > setDiffuse ( osg : : Material : : FRONT_AND_BACK , osg : : Vec4f ( 1 , 1 , 1 , 1 ) ) ;
defaultMat - > setSpecular ( osg : : Material : : FRONT_AND_BACK , osg : : Vec4f ( 0.f , 0.f , 0.f , 0.f ) ) ;
stateset - > setAttribute ( defaultMat ) ;
2018-02-26 14:29:31 +00:00
SceneUtil : : ShadowManager : : disableShadowsForStateSet ( stateset ) ;
2017-11-08 13:38:30 +00:00
2016-02-16 21:32:59 +00:00
// assign large value to effectively turn off fog
// shaders don't respect glDisable(GL_FOG)
osg : : ref_ptr < osg : : Fog > fog ( new osg : : Fog ) ;
fog - > setStart ( 10000000 ) ;
fog - > setEnd ( 10000000 ) ;
stateset - > setAttributeAndModes ( fog , osg : : StateAttribute : : OFF | osg : : StateAttribute : : OVERRIDE ) ;
2015-05-20 00:18:20 +00:00
2021-01-20 01:17:16 +00:00
// Opaque stuff must have 1 as its fragment alpha as the FBO is translucent, so having blending off isn't enough
osg : : ref_ptr < osg : : TexEnvCombine > noBlendAlphaEnv = new osg : : TexEnvCombine ( ) ;
noBlendAlphaEnv - > setCombine_Alpha ( osg : : TexEnvCombine : : REPLACE ) ;
noBlendAlphaEnv - > setSource0_Alpha ( osg : : TexEnvCombine : : CONSTANT ) ;
noBlendAlphaEnv - > setConstantColor ( osg : : Vec4 ( 0.0 , 0.0 , 0.0 , 1.0 ) ) ;
noBlendAlphaEnv - > setCombine_RGB ( osg : : TexEnvCombine : : REPLACE ) ;
noBlendAlphaEnv - > setSource0_RGB ( osg : : TexEnvCombine : : PREVIOUS ) ;
osg : : ref_ptr < osg : : Texture2D > dummyTexture = new osg : : Texture2D ( ) ;
2021-02-23 23:24:40 +00:00
dummyTexture - > setInternalFormat ( GL_DEPTH_COMPONENT ) ;
2021-01-20 01:17:16 +00:00
dummyTexture - > setTextureSize ( 1 , 1 ) ;
2021-02-03 18:45:22 +00:00
// This might clash with a shadow map, so make sure it doesn't cast shadows
dummyTexture - > setShadowComparison ( true ) ;
dummyTexture - > setShadowCompareFunc ( osg : : Texture : : ShadowCompareFunc : : ALWAYS ) ;
2021-01-20 01:17:16 +00:00
stateset - > setTextureAttributeAndModes ( 7 , dummyTexture , osg : : StateAttribute : : ON ) ;
stateset - > setTextureAttribute ( 7 , noBlendAlphaEnv , osg : : StateAttribute : : ON ) ;
stateset - > addUniform ( new osg : : Uniform ( " noAlpha " , true ) ) ;
2015-05-20 00:18:20 +00:00
osg : : ref_ptr < osg : : LightModel > lightmodel = new osg : : LightModel ;
2018-04-25 12:31:49 +00:00
lightmodel - > setAmbientIntensity ( osg : : Vec4 ( 0.0 , 0.0 , 0.0 , 1.0 ) ) ;
2015-05-20 00:18:20 +00:00
stateset - > setAttributeAndModes ( lightmodel , osg : : StateAttribute : : ON ) ;
osg : : ref_ptr < osg : : Light > light = new osg : : Light ;
2019-01-22 06:08:48 +00:00
float diffuseR = Fallback : : Map : : getFloat ( " Inventory_DirectionalDiffuseR " ) ;
float diffuseG = Fallback : : Map : : getFloat ( " Inventory_DirectionalDiffuseG " ) ;
float diffuseB = Fallback : : Map : : getFloat ( " Inventory_DirectionalDiffuseB " ) ;
float ambientR = Fallback : : Map : : getFloat ( " Inventory_DirectionalAmbientR " ) ;
float ambientG = Fallback : : Map : : getFloat ( " Inventory_DirectionalAmbientG " ) ;
float ambientB = Fallback : : Map : : getFloat ( " Inventory_DirectionalAmbientB " ) ;
float azimuth = osg : : DegreesToRadians ( Fallback : : Map : : getFloat ( " Inventory_DirectionalRotationX " ) ) ;
float altitude = osg : : DegreesToRadians ( Fallback : : Map : : getFloat ( " Inventory_DirectionalRotationY " ) ) ;
float positionX = - std : : cos ( azimuth ) * std : : sin ( altitude ) ;
2018-04-23 18:17:25 +00:00
float positionY = std : : sin ( azimuth ) * std : : sin ( altitude ) ;
float positionZ = std : : cos ( altitude ) ;
light - > setPosition ( osg : : Vec4 ( positionX , positionY , positionZ , 0.0 ) ) ;
2018-04-22 19:31:56 +00:00
light - > setDiffuse ( osg : : Vec4 ( diffuseR , diffuseG , diffuseB , 1 ) ) ;
2021-04-16 18:55:40 +00:00
osg : : Vec4 ambientRGBA = osg : : Vec4 ( ambientR , ambientG , ambientB , 1 ) ;
if ( mResourceSystem - > getSceneManager ( ) - > getForceShaders ( ) )
{
// When using shaders, we now skip the ambient sun calculation as this is the only place it's used.
// Using the scene ambient will give identical results.
lightmodel - > setAmbientIntensity ( ambientRGBA ) ;
light - > setAmbient ( osg : : Vec4 ( 0 , 0 , 0 , 1 ) ) ;
}
else
light - > setAmbient ( ambientRGBA ) ;
2015-05-20 00:18:20 +00:00
light - > setSpecular ( osg : : Vec4 ( 0 , 0 , 0 , 0 ) ) ;
light - > setLightNum ( 0 ) ;
light - > setConstantAttenuation ( 1.f ) ;
light - > setLinearAttenuation ( 0.f ) ;
light - > setQuadraticAttenuation ( 0.f ) ;
2021-02-21 18:38:15 +00:00
lightManager - > setSunlight ( light ) ;
2015-05-20 00:18:20 +00:00
osg : : ref_ptr < osg : : LightSource > lightSource = new osg : : LightSource ;
lightSource - > setLight ( light ) ;
lightSource - > setStateSetModes ( * stateset , osg : : StateAttribute : : ON ) ;
lightManager - > addChild ( lightSource ) ;
mCamera - > addChild ( lightManager ) ;
mNode = new osg : : PositionAttitudeTransform ;
lightManager - > addChild ( mNode ) ;
mDrawOnceCallback = new DrawOnceCallback ;
mCamera - > addUpdateCallback ( mDrawOnceCallback ) ;
2016-08-16 20:47:45 +00:00
mParent - > addChild ( mCamera ) ;
2015-05-20 00:18:20 +00:00
2017-04-28 15:30:26 +00:00
mCharacter . mCell = nullptr ;
2012-09-14 22:57:29 +00:00
}
2015-05-20 00:18:20 +00:00
CharacterPreview : : ~ CharacterPreview ( )
2012-09-12 22:54:32 +00:00
{
2016-08-15 16:11:36 +00:00
mCamera - > removeChildren ( 0 , mCamera - > getNumChildren ( ) ) ;
2016-08-16 20:47:45 +00:00
mParent - > removeChild ( mCamera ) ;
2012-09-14 22:57:29 +00:00
}
2015-05-20 00:18:20 +00:00
int CharacterPreview : : getTextureWidth ( ) const
2014-08-08 13:44:22 +00:00
{
2015-05-20 00:18:20 +00:00
return mSizeX ;
2014-08-08 13:44:22 +00:00
}
2015-05-20 00:18:20 +00:00
int CharacterPreview : : getTextureHeight ( ) const
2012-09-14 22:57:29 +00:00
{
2015-05-20 00:18:20 +00:00
return mSizeY ;
}
2012-09-14 22:57:29 +00:00
2017-02-21 17:29:18 +00:00
void CharacterPreview : : setBlendMode ( )
{
2021-01-20 23:37:19 +00:00
mResourceSystem - > getSceneManager ( ) - > recreateShaders ( mNode , " objects " , true ) ;
2017-02-21 17:29:18 +00:00
SetUpBlendVisitor visitor ;
mNode - > accept ( visitor ) ;
}
2015-05-20 00:18:20 +00:00
void CharacterPreview : : onSetup ( )
{
2017-02-21 17:29:18 +00:00
setBlendMode ( ) ;
2012-09-14 22:57:29 +00:00
}
2015-05-20 00:18:20 +00:00
osg : : ref_ptr < osg : : Texture2D > CharacterPreview : : getTexture ( )
2012-09-14 22:57:29 +00:00
{
2015-05-20 00:18:20 +00:00
return mTexture ;
2012-09-12 22:54:32 +00:00
}
2012-11-10 07:41:12 +00:00
void CharacterPreview : : rebuild ( )
{
2018-10-09 06:21:12 +00:00
mAnimation = nullptr ;
2013-03-15 15:44:35 +00:00
2017-02-22 14:22:40 +00:00
mAnimation = new NpcAnimation ( mCharacter , mNode , mResourceSystem , true ,
( renderHeadOnly ( ) ? NpcAnimation : : VM_HeadOnly : NpcAnimation : : VM_Normal ) ) ;
2012-11-10 07:41:12 +00:00
onSetup ( ) ;
2014-08-04 14:32:53 +00:00
2015-05-20 00:18:20 +00:00
redraw ( ) ;
2014-08-04 14:32:53 +00:00
}
2015-05-20 00:18:20 +00:00
void CharacterPreview : : redraw ( )
2014-08-04 14:32:53 +00:00
{
2020-04-20 16:47:14 +00:00
mCamera - > setNodeMask ( Mask_RenderToTexture ) ;
2015-05-20 00:18:20 +00:00
mDrawOnceCallback - > redrawNextFrame ( ) ;
2014-08-04 14:32:53 +00:00
}
2012-09-13 17:03:31 +00:00
// --------------------------------------------------------------------------------------------------
2017-04-20 11:36:14 +00:00
InventoryPreview : : InventoryPreview ( osg : : Group * parent , Resource : : ResourceSystem * resourceSystem , const MWWorld : : Ptr & character )
2016-08-16 20:47:45 +00:00
: CharacterPreview ( parent , resourceSystem , character , 512 , 1024 , osg : : Vec3f ( 0 , 700 , 71 ) , osg : : Vec3f ( 0 , 0 , 71 ) )
2012-09-13 17:03:31 +00:00
{
2012-09-14 12:34:18 +00:00
}
2012-09-13 17:03:31 +00:00
2015-05-20 00:18:20 +00:00
void InventoryPreview : : setViewport ( int sizeX , int sizeY )
2012-09-14 12:34:18 +00:00
{
2015-05-20 00:18:20 +00:00
sizeX = std : : max ( sizeX , 0 ) ;
sizeY = std : : max ( sizeY , 0 ) ;
2014-08-04 14:32:53 +00:00
2017-07-19 15:43:15 +00:00
// NB Camera::setViewport has threading issues
osg : : ref_ptr < osg : : StateSet > stateset = new osg : : StateSet ;
2017-07-21 22:06:43 +00:00
mViewport = new osg : : Viewport ( 0 , mSizeY - sizeY , std : : min ( mSizeX , sizeX ) , std : : min ( mSizeY , sizeY ) ) ;
stateset - > setAttributeAndModes ( mViewport ) ;
2017-07-19 15:43:15 +00:00
mCamera - > setStateSet ( stateset ) ;
2014-08-12 14:36:13 +00:00
2015-05-20 00:18:20 +00:00
redraw ( ) ;
2014-08-12 14:36:13 +00:00
}
void InventoryPreview : : update ( )
{
2015-11-10 23:50:57 +00:00
if ( ! mAnimation . get ( ) )
2014-12-02 23:02:14 +00:00
return ;
2015-05-20 00:18:20 +00:00
mAnimation - > showWeapons ( true ) ;
2014-01-04 19:43:57 +00:00
mAnimation - > updateParts ( ) ;
2013-11-20 23:27:22 +00:00
2014-01-19 10:42:58 +00:00
MWWorld : : InventoryStore & inv = mCharacter . getClass ( ) . getInventoryStore ( mCharacter ) ;
2013-04-29 19:08:43 +00:00
MWWorld : : ContainerStoreIterator iter = inv . getSlot ( MWWorld : : InventoryStore : : Slot_CarriedRight ) ;
2018-12-26 09:45:28 +00:00
std : : string groupname = " inventoryhandtohand " ;
2014-12-12 15:49:22 +00:00
bool showCarriedLeft = true ;
2018-12-26 09:45:28 +00:00
if ( iter ! = inv . end ( ) )
2013-04-29 19:08:43 +00:00
{
2018-12-26 09:45:28 +00:00
groupname = " inventoryweapononehand " ;
if ( iter - > getTypeName ( ) = = typeid ( ESM : : Weapon ) . name ( ) )
2013-04-29 19:08:43 +00:00
{
MWWorld : : LiveCellRef < ESM : : Weapon > * ref = iter - > get < ESM : : Weapon > ( ) ;
int type = ref - > mBase - > mData . mType ;
2018-12-26 09:45:28 +00:00
const ESM : : WeaponType * weaponInfo = MWMechanics : : getWeaponType ( type ) ;
showCarriedLeft = ! ( weaponInfo - > mFlags & ESM : : WeaponType : : TwoHanded ) ;
std : : string inventoryGroup = weaponInfo - > mLongGroup ;
inventoryGroup = " inventory " + inventoryGroup ;
// We still should use one-handed animation as fallback
if ( mAnimation - > hasAnimation ( inventoryGroup ) )
groupname = inventoryGroup ;
2019-08-09 08:58:20 +00:00
else
{
static const std : : string oneHandFallback = " inventory " + MWMechanics : : getWeaponType ( ESM : : Weapon : : LongBladeOneHand ) - > mLongGroup ;
static const std : : string twoHandFallback = " inventory " + MWMechanics : : getWeaponType ( ESM : : Weapon : : LongBladeTwoHand ) - > mLongGroup ;
// For real two-handed melee weapons use 2h swords animations as fallback, otherwise use the 1h ones
if ( weaponInfo - > mFlags & ESM : : WeaponType : : TwoHanded & & weaponInfo - > mWeaponClass = = ESM : : WeaponType : : Melee )
groupname = twoHandFallback ;
else
groupname = oneHandFallback ;
}
2014-12-12 15:49:22 +00:00
}
2013-04-29 19:08:43 +00:00
}
2014-12-12 15:49:22 +00:00
mAnimation - > showCarriedLeft ( showCarriedLeft ) ;
2014-01-04 19:43:57 +00:00
mCurrentAnimGroup = groupname ;
2015-07-09 16:47:11 +00:00
mAnimation - > play ( mCurrentAnimGroup , 1 , Animation : : BlendMask_All , false , 1.0f , " start " , " stop " , 0.0f , 0 ) ;
2013-04-29 19:08:43 +00:00
2017-02-28 14:31:51 +00:00
MWWorld : : ConstContainerStoreIterator torch = inv . getSlot ( MWWorld : : InventoryStore : : Slot_CarriedLeft ) ;
2014-12-28 13:09:27 +00:00
if ( torch ! = inv . end ( ) & & torch - > getTypeName ( ) = = typeid ( ESM : : Light ) . name ( ) & & showCarriedLeft )
2013-05-17 13:21:59 +00:00
{
if ( ! mAnimation - > getInfo ( " torch " ) )
2015-07-09 16:47:11 +00:00
mAnimation - > play ( " torch " , 2 , Animation : : BlendMask_LeftArm , false ,
2014-12-21 14:29:20 +00:00
1.0f , " start " , " stop " , 0.0f , ~ 0ul , true ) ;
2013-05-17 13:21:59 +00:00
}
else if ( mAnimation - > getInfo ( " torch " ) )
mAnimation - > disable ( " torch " ) ;
2013-02-22 19:16:00 +00:00
mAnimation - > runAnimation ( 0.0f ) ;
2012-09-13 17:03:31 +00:00
2017-02-21 17:29:18 +00:00
setBlendMode ( ) ;
2015-05-20 00:18:20 +00:00
redraw ( ) ;
2012-09-13 17:03:31 +00:00
}
2015-05-20 00:18:20 +00:00
int InventoryPreview : : getSlotSelected ( int posX , int posY )
2014-08-04 14:32:53 +00:00
{
2017-07-21 22:06:43 +00:00
if ( ! mViewport )
return - 1 ;
float projX = ( posX / mViewport - > width ( ) ) * 2 - 1.f ;
float projY = ( posY / mViewport - > height ( ) ) * 2 - 1.f ;
2015-11-30 16:19:27 +00:00
// With Intersector::WINDOW, the intersection ratios are slightly inaccurate. Seems to be a
// precision issue - compiling with OSG_USE_FLOAT_MATRIX=0, Intersector::WINDOW works ok.
// Using Intersector::PROJECTION results in better precision because the start/end points and the model matrices
// don't go through as many transformations.
2015-11-30 16:04:45 +00:00
osg : : ref_ptr < osgUtil : : LineSegmentIntersector > intersector ( new osgUtil : : LineSegmentIntersector ( osgUtil : : Intersector : : PROJECTION , projX , projY ) ) ;
2015-11-30 04:39:51 +00:00
intersector - > setIntersectionLimit ( osgUtil : : LineSegmentIntersector : : LIMIT_NEAREST ) ;
2015-05-20 01:35:52 +00:00
osgUtil : : IntersectionVisitor visitor ( intersector ) ;
2015-11-30 04:39:51 +00:00
visitor . setTraversalMode ( osg : : NodeVisitor : : TRAVERSE_ACTIVE_CHILDREN ) ;
// Set the traversal number from the last draw, so that the frame switch used for RigGeometry double buffering works correctly
visitor . setTraversalNumber ( mDrawOnceCallback - > getLastRenderedFrame ( ) ) ;
2015-05-20 01:35:52 +00:00
osg : : Node : : NodeMask nodeMask = mCamera - > getNodeMask ( ) ;
2021-04-20 06:42:06 +00:00
mCamera - > setNodeMask ( ~ 0u ) ;
2015-05-20 01:35:52 +00:00
mCamera - > accept ( visitor ) ;
mCamera - > setNodeMask ( nodeMask ) ;
if ( intersector - > containsIntersections ( ) )
{
osgUtil : : LineSegmentIntersector : : Intersection intersection = intersector - > getFirstIntersection ( ) ;
return mAnimation - > getSlot ( intersection . nodePath ) ;
}
return - 1 ;
2014-08-04 14:32:53 +00:00
}
2015-05-20 00:18:20 +00:00
void InventoryPreview : : updatePtr ( const MWWorld : : Ptr & ptr )
2012-09-13 17:03:31 +00:00
{
2018-10-09 06:21:12 +00:00
mCharacter = MWWorld : : Ptr ( ptr . getBase ( ) , nullptr ) ;
2012-09-13 17:03:31 +00:00
}
2015-05-20 00:18:20 +00:00
void InventoryPreview : : onSetup ( )
2012-09-14 12:34:18 +00:00
{
2017-02-21 17:29:18 +00:00
CharacterPreview : : onSetup ( ) ;
2015-05-20 00:18:20 +00:00
osg : : Vec3f scale ( 1.f , 1.f , 1.f ) ;
2015-11-01 20:45:58 +00:00
mCharacter . getClass ( ) . adjustScale ( mCharacter , scale , true ) ;
2012-10-01 16:04:21 +00:00
2015-05-20 00:18:20 +00:00
mNode - > setScale ( scale ) ;
2013-04-29 19:08:43 +00:00
2015-05-20 00:18:20 +00:00
mCamera - > setViewMatrixAsLookAt ( mPosition * scale . z ( ) , mLookAt * scale . z ( ) , osg : : Vec3f ( 0 , 0 , 1 ) ) ;
2012-09-14 12:34:18 +00:00
}
2012-09-13 17:03:31 +00:00
// --------------------------------------------------------------------------------------------------
2016-08-16 20:47:45 +00:00
RaceSelectionPreview : : RaceSelectionPreview ( osg : : Group * parent , Resource : : ResourceSystem * resourceSystem )
: CharacterPreview ( parent , resourceSystem , MWMechanics : : getPlayer ( ) ,
2015-05-20 00:18:20 +00:00
512 , 512 , osg : : Vec3f ( 0 , 125 , 8 ) , osg : : Vec3f ( 0 , 0 , 8 ) )
2014-09-26 15:12:48 +00:00
, mBase ( * mCharacter . get < ESM : : NPC > ( ) - > mBase )
2012-11-10 07:41:12 +00:00
, mRef ( & mBase )
2015-05-20 00:18:20 +00:00
, mPitchRadians ( osg : : DegreesToRadians ( 6.f ) )
2012-09-13 17:03:31 +00:00
{
2018-10-09 06:21:12 +00:00
mCharacter = MWWorld : : Ptr ( & mRef , nullptr ) ;
2012-09-13 17:03:31 +00:00
}
2015-05-20 00:18:20 +00:00
RaceSelectionPreview : : ~ RaceSelectionPreview ( )
2012-09-13 17:03:31 +00:00
{
2013-07-06 15:02:40 +00:00
}
2013-03-06 17:03:47 +00:00
2015-05-20 00:18:20 +00:00
void RaceSelectionPreview : : setAngle ( float angleRadians )
2013-07-06 15:02:40 +00:00
{
2015-05-20 00:18:20 +00:00
mNode - > setAttitude ( osg : : Quat ( mPitchRadians , osg : : Vec3 ( 1 , 0 , 0 ) )
* osg : : Quat ( angleRadians , osg : : Vec3 ( 0 , 0 , 1 ) ) ) ;
redraw ( ) ;
2012-09-12 22:54:32 +00:00
}
2012-11-10 07:41:12 +00:00
void RaceSelectionPreview : : setPrototype ( const ESM : : NPC & proto )
{
mBase = proto ;
mBase . mId = " player " ;
rebuild ( ) ;
}
2013-02-26 00:40:08 +00:00
2015-05-20 00:18:20 +00:00
class UpdateCameraCallback : public osg : : NodeCallback
2013-02-26 00:40:08 +00:00
{
2015-05-20 00:18:20 +00:00
public :
UpdateCameraCallback ( osg : : ref_ptr < const osg : : Node > nodeToFollow , const osg : : Vec3 & posOffset , const osg : : Vec3 & lookAtOffset )
: mNodeToFollow ( nodeToFollow )
, mPosOffset ( posOffset )
, mLookAtOffset ( lookAtOffset )
{
}
2013-03-06 17:03:47 +00:00
2020-10-16 18:18:54 +00:00
void operator ( ) ( osg : : Node * node , osg : : NodeVisitor * nv ) override
2015-05-20 00:18:20 +00:00
{
osg : : Camera * cam = static_cast < osg : : Camera * > ( node ) ;
2013-03-06 17:03:47 +00:00
2015-05-20 00:18:20 +00:00
// Update keyframe controllers in the scene graph first...
traverse ( node , nv ) ;
// Now update camera utilizing the updated head position
2016-02-22 17:58:19 +00:00
osg : : NodePathList nodepaths = mNodeToFollow - > getParentalNodePaths ( ) ;
2016-02-22 18:06:12 +00:00
if ( nodepaths . empty ( ) )
2015-05-20 00:18:20 +00:00
return ;
2016-02-22 17:58:19 +00:00
osg : : Matrix worldMat = osg : : computeLocalToWorld ( nodepaths [ 0 ] ) ;
2015-05-20 00:18:20 +00:00
osg : : Vec3 headOffset = worldMat . getTrans ( ) ;
cam - > setViewMatrixAsLookAt ( headOffset + mPosOffset , headOffset + mLookAtOffset , osg : : Vec3 ( 0 , 0 , 1 ) ) ;
}
private :
osg : : ref_ptr < const osg : : Node > mNodeToFollow ;
osg : : Vec3 mPosOffset ;
osg : : Vec3 mLookAtOffset ;
} ;
void RaceSelectionPreview : : onSetup ( )
2013-03-06 17:03:47 +00:00
{
2017-02-21 17:29:18 +00:00
CharacterPreview : : onSetup ( ) ;
2015-07-09 16:47:11 +00:00
mAnimation - > play ( " idle " , 1 , Animation : : BlendMask_All , false , 1.0f , " start " , " stop " , 0.0f , 0 ) ;
2015-05-20 00:18:20 +00:00
mAnimation - > runAnimation ( 0.f ) ;
2013-03-06 17:03:47 +00:00
2015-05-20 00:18:20 +00:00
// attach camera to follow the head node
if ( mUpdateCameraCallback )
mCamera - > removeUpdateCallback ( mUpdateCameraCallback ) ;
const osg : : Node * head = mAnimation - > getNode ( " Bip01 Head " ) ;
2015-05-29 23:41:38 +00:00
if ( head )
{
mUpdateCameraCallback = new UpdateCameraCallback ( head , mPosition , mLookAt ) ;
mCamera - > addUpdateCallback ( mUpdateCameraCallback ) ;
}
else
2018-08-14 19:05:43 +00:00
Log ( Debug : : Error ) < < " Error: Bip01 Head node not found " ;
2013-02-26 00:40:08 +00:00
}
2015-05-20 00:18:20 +00:00
2012-09-12 22:54:32 +00:00
}