2022-09-26 15:12:13 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
2022-10-01 02:04:57 -04:00
# include "MuR/CodeRunner.h"
2022-09-26 15:12:13 -04:00
2024-10-01 19:09:05 -04:00
# include "OpMeshTransformWithMesh.h"
2023-08-21 05:50:06 -04:00
# include "GenericPlatform/GenericPlatformMath.h"
2022-10-02 10:56:02 -04:00
# include "HAL/UnrealMemory.h"
# include "Logging/LogCategory.h"
# include "Logging/LogMacros.h"
# include "Math/IntPoint.h"
# include "Math/UnrealMathSSE.h"
# include "Math/UnrealMathUtility.h"
# include "Math/Vector2D.h"
# include "Misc/AssertionMacros.h"
2022-10-01 02:04:57 -04:00
# include "MuR/ImagePrivate.h"
2022-10-02 10:56:02 -04:00
# include "MuR/Instance.h"
# include "MuR/InstancePrivate.h"
# include "MuR/Mesh.h"
# include "MuR/MeshBufferSet.h"
# include "MuR/Model.h"
# include "MuR/ModelPrivate.h"
# include "MuR/MutableMath.h"
# include "MuR/MutableString.h"
# include "MuR/MutableTrace.h"
2022-10-01 02:04:57 -04:00
# include "MuR/OpImageApplyComposite.h"
2022-10-02 10:56:02 -04:00
# include "MuR/OpImageBinarise.h"
# include "MuR/OpImageBlend.h"
# include "MuR/OpImageColourMap.h"
# include "MuR/OpImageDisplace.h"
# include "MuR/OpImageGradient.h"
# include "MuR/OpImageInterpolate.h"
# include "MuR/OpImageInvert.h"
# include "MuR/OpImageLuminance.h"
# include "MuR/OpImageNormalCombine.h"
# include "MuR/OpImageProject.h"
# include "MuR/OpImageRasterMesh.h"
# include "MuR/OpImageSaturate.h"
2022-10-01 02:04:57 -04:00
# include "MuR/OpImageTransform.h"
# include "MuR/OpLayoutPack.h"
# include "MuR/OpLayoutRemoveBlocks.h"
2022-10-02 10:56:02 -04:00
# include "MuR/OpMeshApplyLayout.h"
# include "MuR/OpMeshApplyPose.h"
# include "MuR/OpMeshBind.h"
# include "MuR/OpMeshClipDeform.h"
# include "MuR/OpMeshClipMorphPlane.h"
# include "MuR/OpMeshClipWithMesh.h"
# include "MuR/OpMeshDifference.h"
# include "MuR/OpMeshExtractLayoutBlock.h"
# include "MuR/OpMeshFormat.h"
# include "MuR/OpMeshGeometryOperation.h"
# include "MuR/OpMeshMerge.h"
# include "MuR/OpMeshMorph.h"
2023-06-15 06:49:52 -04:00
# include "MuR/OpMeshRemove.h"
2022-10-02 10:56:02 -04:00
# include "MuR/OpMeshReshape.h"
# include "MuR/OpMeshTransform.h"
2023-01-04 15:46:42 -05:00
# include "MuR/OpMeshOptimizeSkinning.h"
2022-10-02 10:56:02 -04:00
# include "MuR/Operations.h"
# include "MuR/Parameters.h"
# include "MuR/ParametersPrivate.h"
# include "MuR/PhysicsBody.h"
# include "MuR/Platform.h"
# include "MuR/Skeleton.h"
# include "MuR/SystemPrivate.h"
# include "Templates/Tuple.h"
# include "Trace/Detail/Channel.h"
2022-09-26 15:12:13 -04:00
2023-04-28 15:56:53 -04:00
namespace
{
2023-05-03 12:48:24 -04:00
int32 ForcedProjectionMode = - 1 ;
static FAutoConsoleVariableRef CVarForceProjectionSamplingMode (
TEXT ( " mutable.ForceProjectionMode " ) ,
ForcedProjectionMode ,
TEXT ( " force mutable to use an specific projection mode, 0 = Point + None, 1 = Bilinear + TotalAreaHeuristic, -1 uses the values provided by the projector. " ) ,
ECVF_Default ) ;
float GlobalProjectionLodBias = 0.0f ;
static FAutoConsoleVariableRef CVarGlobalProjectionLodBias (
TEXT ( " mutable.GlobalProjectionLodBias " ) ,
GlobalProjectionLodBias ,
2023-08-21 05:50:06 -04:00
TEXT ( " Lod bias applied to the lod resulting form the best mip computation for ImageProject operations, only used if a min filter method different than None is used. " ) ,
2023-05-03 12:48:24 -04:00
ECVF_Default ) ;
2023-05-12 05:07:47 -04:00
bool bUseProjectionVectorImpl = true ;
2023-05-09 06:27:09 -04:00
static FAutoConsoleVariableRef CVarUseProjectionVectorImpl (
TEXT ( " mutable.UseProjectionVectorImpl " ) ,
bUseProjectionVectorImpl ,
TEXT ( " If set to true, enables the vectorized implementation of the projection pixel processing. " ) ,
ECVF_Default ) ;
2023-08-21 05:50:06 -04:00
float GlobalImageTransformLodBias = 0.0f ;
static FAutoConsoleVariableRef CVarGlobalImageTransformLodBias (
TEXT ( " mutable.GlobalImageTransformLodBias " ) ,
GlobalImageTransformLodBias ,
TEXT ( " Lod bias applied to the lod resulting form the best mip computation for ImageTransform operations " ) ,
ECVF_Default ) ;
bool bUseImageTransformVectorImpl = true ;
static FAutoConsoleVariableRef CVarUseImageTransformVectorImpl (
TEXT ( " mutable.UseImageTransformVectorImpl " ) ,
bUseImageTransformVectorImpl ,
TEXT ( " If set to true, enables the vectorized implementation of the image transform pixel processing. " ) ,
ECVF_Default ) ;
2023-04-28 15:56:53 -04:00
}
2022-09-26 15:12:13 -04:00
namespace mu
{
2024-03-13 07:52:36 -04:00
TSharedRef < CodeRunner > CodeRunner : : Create (
const Ptr < const Settings > & InSettings ,
class System : : Private * InSystem ,
EExecutionStrategy InExecutionStrategy ,
const TSharedPtr < const Model > & InModel ,
const Parameters * InParams ,
OP : : ADDRESS At ,
uint32 InLODMask , uint8 ExecutionOptions , int32 InImageLOD , FScheduledOp : : EType Type )
{
return MakeShared < CodeRunner > ( FPrivateToken { } ,
InSettings , InSystem , InExecutionStrategy , InModel , InParams , At , InLODMask , ExecutionOptions , InImageLOD , Type ) ;
}
CodeRunner : : CodeRunner ( FPrivateToken PrivateToken ,
const Ptr < const Settings > & InSettings ,
2023-03-08 04:37:54 -05:00
class System : : Private * InSystem ,
EExecutionStrategy InExecutionStrategy ,
const TSharedPtr < const Model > & InModel ,
const Parameters * InParams ,
2024-08-13 10:23:49 -04:00
OP : : ADDRESS at ,
uint32 InLodMask , uint8 executionOptions , int32 InImageLOD , FScheduledOp : : EType Type )
2023-03-08 04:37:54 -05:00
: m_pSettings ( InSettings )
2024-03-13 07:52:36 -04:00
, RunnerCompletionEvent ( TEXT ( " CodeRunnerCompletioneEventInit " ) )
2023-03-08 04:37:54 -05:00
, ExecutionStrategy ( InExecutionStrategy )
, m_pSystem ( InSystem )
, m_pModel ( InModel )
, m_pParams ( InParams )
, m_lodMask ( InLodMask )
2022-09-26 15:12:13 -04:00
{
2024-08-13 10:23:49 -04:00
const FProgram & program = m_pModel - > GetPrivate ( ) - > m_program ;
ScheduledStagePerOp . resize ( program . m_opAddress . Num ( ) ) ;
2022-09-26 15:12:13 -04:00
// We will read this in the end, so make sure we keep it.
2024-08-13 10:23:49 -04:00
if ( Type = = FScheduledOp : : EType : : Full )
2023-03-14 07:59:00 -04:00
{
2024-08-13 10:23:49 -04:00
GetMemory ( ) . IncreaseHitCount ( FCacheAddress ( at , 0 , executionOptions ) ) ;
2023-03-14 07:59:00 -04:00
}
2024-03-13 07:52:36 -04:00
// Start with a completed Event. This is checked at StartRun() to make sure StartRun is not called while there is
// a Run in progress.
RunnerCompletionEvent . Trigger ( ) ;
2022-09-26 15:12:13 -04:00
2023-01-27 14:54:49 -05:00
ImageLOD = InImageLOD ;
2024-03-13 07:52:36 -04:00
2022-09-26 15:12:13 -04:00
// Push the root operation
2024-08-13 10:23:49 -04:00
FScheduledOp rootOp ;
rootOp . At = at ;
rootOp . ExecutionOptions = executionOptions ;
rootOp . Type = Type ;
AddOp ( rootOp ) ;
2022-09-26 15:12:13 -04:00
}
//---------------------------------------------------------------------------------------------
FProgramCache & CodeRunner : : GetMemory ( )
{
2023-05-24 02:50:03 -04:00
return * m_pSystem - > WorkingMemoryManager . CurrentInstanceCache ;
2022-09-26 15:12:13 -04:00
}
2024-05-14 07:28:21 -04:00
TTuple < UE : : Tasks : : FTask , TFunction < void ( ) > > CodeRunner : : LoadExternalImageAsync ( FExternalResourceId Id , uint8 MipmapsToSkip , TFunction < void ( Ptr < Image > ) > & ResultCallback )
2022-09-26 15:12:13 -04:00
{
2023-01-13 10:48:15 -05:00
MUTABLE_CPUPROFILER_SCOPE ( LoadExternalImageAsync ) ;
2022-09-26 15:12:13 -04:00
check ( m_pSystem ) ;
2024-05-14 07:28:21 -04:00
if ( m_pSystem - > ExternalResourceProvider )
2022-09-26 15:12:13 -04:00
{
2024-05-14 07:28:21 -04:00
if ( Id . ReferenceResourceId < 0 )
2023-10-05 04:46:46 -04:00
{
// It's a parameter image
2024-05-14 07:28:21 -04:00
return m_pSystem - > ExternalResourceProvider - > GetImageAsync ( Id . ParameterId , MipmapsToSkip , ResultCallback ) ;
2023-10-05 04:46:46 -04:00
}
else
{
// It's an image reference
2024-05-14 07:28:21 -04:00
return m_pSystem - > ExternalResourceProvider - > GetReferencedImageAsync ( m_pModel . Get ( ) , Id . ReferenceResourceId , MipmapsToSkip , ResultCallback ) ;
}
}
else
{
// Not found and there is no generator!
check ( false ) ;
}
return MakeTuple ( UE : : Tasks : : MakeCompletedTask < void > ( ) , [ ] ( ) - > void { } ) ;
}
TTuple < UE : : Tasks : : FTask , TFunction < void ( ) > > CodeRunner : : LoadExternalMeshAsync ( FExternalResourceId Id , TFunction < void ( Ptr < Mesh > ) > & ResultCallback )
{
MUTABLE_CPUPROFILER_SCOPE ( LoadExternalImageAsync ) ;
check ( m_pSystem ) ;
if ( m_pSystem - > ExternalResourceProvider )
{
if ( Id . ReferenceResourceId < 0 )
{
// It's a parameter mesh
return m_pSystem - > ExternalResourceProvider - > GetMeshAsync ( Id . ParameterId , ResultCallback ) ;
}
else
{
// It's a mesh reference
return m_pSystem - > ExternalResourceProvider - > GetReferencedMeshAsync ( m_pModel . Get ( ) , Id . ReferenceResourceId , ResultCallback ) ;
2023-10-05 04:46:46 -04:00
}
2022-09-26 15:12:13 -04:00
}
else
{
// Not found and there is no generator!
2023-01-03 10:26:42 -05:00
check ( false ) ;
2022-09-26 15:12:13 -04:00
}
2024-03-01 05:39:11 -05:00
return MakeTuple ( UE : : Tasks : : MakeCompletedTask < void > ( ) , [ ] ( ) - > void { } ) ;
2022-09-26 15:12:13 -04:00
}
2023-01-13 10:48:15 -05:00
//---------------------------------------------------------------------------------------------
2023-07-31 03:24:06 -04:00
FImageDesc CodeRunner : : GetExternalImageDesc ( FName Id , uint8 MipmapsToSkip )
2023-01-13 10:48:15 -05:00
{
MUTABLE_CPUPROFILER_SCOPE ( GetExternalImageDesc ) ;
2022-09-26 15:12:13 -04:00
2023-01-13 10:48:15 -05:00
check ( m_pSystem ) ;
2024-05-14 07:28:21 -04:00
if ( m_pSystem - > ExternalResourceProvider )
2023-01-13 10:48:15 -05:00
{
2024-05-14 07:28:21 -04:00
return m_pSystem - > ExternalResourceProvider - > GetImageDesc ( Id , MipmapsToSkip ) ;
2023-01-13 10:48:15 -05:00
}
else
{
// Not found and there is no generator!
check ( false ) ;
}
return FImageDesc ( ) ;
}
2022-09-26 15:12:13 -04:00
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_Conditional ( const FScheduledOp & item , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Conditional ) ;
2022-09-26 15:12:13 -04:00
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
OP : : ConditionalArgs args = Program . GetOpArgs < OP : : ConditionalArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
// Conditionals have the following execution stages:
// 0: we need to run the condition
// 1: we need to run the branch
// 2: we need to fetch the result and store it in this op
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . condition , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case 1 :
{
// Get the condition result
// If there is no expression, we'll assume true.
bool value = true ;
2023-05-24 02:50:03 -04:00
value = LoadBool ( FCacheAddress ( args . condition , item . ExecutionIndex , item . ExecutionOptions ) ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS resultAt = value ? args . yes : args . no ;
// Schedule the end of this instruction if necessary
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 2 , ( uint32 ) value ) ,
FScheduledOp ( resultAt , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case 2 :
{
2022-11-23 03:17:56 -05:00
OP : : ADDRESS resultAt = item . CustomState ? args . yes : args . no ;
2022-09-26 15:12:13 -04:00
// Store the final result
2022-11-23 03:17:56 -05:00
FCacheAddress cat ( item ) ;
FCacheAddress rat ( resultAt , item ) ;
2022-09-26 15:12:13 -04:00
switch ( GetOpDataType ( type ) )
{
2023-05-24 02:50:03 -04:00
case DT_BOOL : StoreBool ( cat , LoadBool ( rat ) ) ; break ;
case DT_INT : StoreInt ( cat , LoadInt ( rat ) ) ; break ;
case DT_SCALAR : StoreScalar ( cat , LoadScalar ( rat ) ) ; break ;
case DT_STRING : StoreString ( cat , LoadString ( rat ) ) ; break ;
case DT_COLOUR : StoreColor ( cat , LoadColor ( rat ) ) ; break ;
case DT_PROJECTOR : StoreProjector ( cat , LoadProjector ( rat ) ) ; break ;
case DT_MESH : StoreMesh ( cat , LoadMesh ( rat ) ) ; break ;
case DT_IMAGE : StoreImage ( cat , LoadImage ( rat ) ) ; break ;
case DT_LAYOUT : StoreLayout ( cat , LoadLayout ( rat ) ) ; break ;
case DT_INSTANCE : StoreInstance ( cat , LoadInstance ( rat ) ) ; break ;
2023-08-03 12:40:31 -04:00
case DT_EXTENSION_DATA : StoreExtensionData ( cat , LoadExtensionData ( rat ) ) ; break ;
2022-09-26 15:12:13 -04:00
default :
// Not implemented
check ( false ) ;
}
break ;
}
default :
check ( false ) ;
}
}
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_Switch ( const FScheduledOp & item , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
2022-09-26 15:12:13 -04:00
2023-12-19 05:19:14 -05:00
OP_TYPE type = Program . GetOpType ( item . At ) ;
const uint8 * data = Program . GetOpArgsPointer ( item . At ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS VarAddress ;
FMemory : : Memcpy ( & VarAddress , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
OP : : ADDRESS DefAddress ;
FMemory : : Memcpy ( & DefAddress , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
2022-10-06 20:10:22 -04:00
uint32 CaseCount ;
FMemory : : Memcpy ( & CaseCount , data , sizeof ( uint32 ) ) ;
data + = sizeof ( uint32 ) ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
if ( VarAddress )
{
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( VarAddress , item ) ) ;
2022-09-26 15:12:13 -04:00
}
else
{
switch ( GetOpDataType ( type ) )
{
2023-05-24 02:50:03 -04:00
case DT_BOOL : StoreBool ( item , false ) ; break ;
case DT_INT : StoreInt ( item , 0 ) ; break ;
case DT_SCALAR : StoreScalar ( item , 0.0f ) ; break ;
case DT_STRING : StoreString ( item , nullptr ) ; break ;
case DT_COLOUR : StoreColor ( item , FVector4f ( ) ) ; break ;
2023-06-06 02:00:32 -04:00
case DT_PROJECTOR : StoreProjector ( item , FProjector ( ) ) ; break ;
2023-05-24 02:50:03 -04:00
case DT_MESH : StoreMesh ( item , nullptr ) ; break ;
case DT_IMAGE : StoreImage ( item , nullptr ) ; break ;
case DT_LAYOUT : StoreLayout ( item , nullptr ) ; break ;
case DT_INSTANCE : StoreInstance ( item , nullptr ) ; break ;
2023-08-03 12:40:31 -04:00
case DT_EXTENSION_DATA : StoreExtensionData ( item , new ExtensionData ) ; break ;
2022-09-26 15:12:13 -04:00
default :
// Not implemented
check ( false ) ;
}
}
break ;
}
case 1 :
{
// Get the variable result
2023-05-24 02:50:03 -04:00
int var = LoadInt ( FCacheAddress ( VarAddress , item ) ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS valueAt = DefAddress ;
2022-10-06 20:10:22 -04:00
for ( uint32 C = 0 ; C < CaseCount ; + + C )
2022-09-26 15:12:13 -04:00
{
2022-10-06 20:10:22 -04:00
int32 Condition ;
FMemory : : Memcpy ( & Condition , data , sizeof ( int32 ) ) ;
data + = sizeof ( int32 ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS At ;
FMemory : : Memcpy ( & At , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
if ( At & & var = = ( int ) Condition )
{
valueAt = At ;
break ;
}
}
// Schedule the end of this instruction if necessary
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 2 , valueAt ) ,
FScheduledOp ( valueAt , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case 2 :
{
2022-11-23 03:17:56 -05:00
OP : : ADDRESS resultAt = OP : : ADDRESS ( item . CustomState ) ;
2022-09-26 15:12:13 -04:00
// Store the final result
2022-11-23 03:17:56 -05:00
FCacheAddress cat ( item ) ;
FCacheAddress rat ( resultAt , item ) ;
2022-09-26 15:12:13 -04:00
switch ( GetOpDataType ( type ) )
{
2023-05-24 02:50:03 -04:00
case DT_BOOL : StoreBool ( cat , LoadBool ( rat ) ) ; break ;
case DT_INT : StoreInt ( cat , LoadInt ( rat ) ) ; break ;
case DT_SCALAR : StoreScalar ( cat , LoadScalar ( rat ) ) ; break ;
case DT_STRING : StoreString ( cat , LoadString ( rat ) ) ; break ;
case DT_COLOUR : StoreColor ( cat , LoadColor ( rat ) ) ; break ;
case DT_PROJECTOR : StoreProjector ( cat , LoadProjector ( rat ) ) ; break ;
2023-06-15 04:45:22 -04:00
case DT_MESH : StoreMesh ( cat , LoadMesh ( rat ) ) ; break ;
2023-05-24 02:50:03 -04:00
case DT_IMAGE : StoreImage ( cat , LoadImage ( rat ) ) ; break ;
case DT_LAYOUT : StoreLayout ( cat , LoadLayout ( rat ) ) ; break ;
case DT_INSTANCE : StoreInstance ( cat , LoadInstance ( rat ) ) ; break ;
2023-08-03 12:40:31 -04:00
case DT_EXTENSION_DATA : StoreExtensionData ( cat , LoadExtensionData ( rat ) ) ; break ;
2022-09-26 15:12:13 -04:00
default :
// Not implemented
check ( false ) ;
}
break ;
}
default :
check ( false ) ;
}
}
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_Instance ( const FScheduledOp & item , const Model * pModel , uint32 lodMask )
2022-09-26 15:12:13 -04:00
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Instance ) ;
2022-09-26 15:12:13 -04:00
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : IN_ADDVECTOR :
{
2023-12-19 05:19:14 -05:00
OP : : InstanceAddArgs args = Program . GetOpArgs < OP : : InstanceAddArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . instance , item ) ,
FScheduledOp ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
InstancePtrConst pBase = LoadInstance ( FCacheAddress ( args . instance , item ) ) ;
2022-09-26 15:12:13 -04:00
InstancePtr pResult ;
if ( ! pBase )
{
pResult = new Instance ( ) ;
}
else
{
2023-05-24 02:50:03 -04:00
pResult = mu : : CloneOrTakeOver < Instance > ( pBase . get ( ) ) ;
2022-09-26 15:12:13 -04:00
}
if ( args . value )
{
2023-05-24 02:50:03 -04:00
FVector4f value = LoadColor ( FCacheAddress ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS nameAd = args . name ;
2023-12-19 05:19:14 -05:00
check ( nameAd < ( uint32 ) Program . m_constantStrings . Num ( ) ) ;
const FString & Name = Program . m_constantStrings [ nameAd ] ;
2022-09-26 15:12:13 -04:00
2023-09-26 04:43:37 -04:00
pResult - > GetPrivate ( ) - > AddVector ( 0 , 0 , 0 , value , FName ( Name ) ) ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
StoreInstance ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IN_ADDSCALAR :
{
2023-12-19 05:19:14 -05:00
OP : : InstanceAddArgs args = Program . GetOpArgs < OP : : InstanceAddArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . instance , item ) ,
FScheduledOp ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
InstancePtrConst pBase = LoadInstance ( FCacheAddress ( args . instance , item ) ) ;
2022-09-26 15:12:13 -04:00
InstancePtr pResult ;
if ( ! pBase )
{
pResult = new Instance ( ) ;
}
else
{
2023-05-24 02:50:03 -04:00
pResult = mu : : CloneOrTakeOver < Instance > ( pBase . get ( ) ) ;
2022-09-26 15:12:13 -04:00
}
if ( args . value )
{
2023-05-24 02:50:03 -04:00
float value = LoadScalar ( FCacheAddress ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS nameAd = args . name ;
2023-12-19 05:19:14 -05:00
check ( nameAd < ( uint32 ) Program . m_constantStrings . Num ( ) ) ;
const FString & Name = Program . m_constantStrings [ nameAd ] ;
2022-09-26 15:12:13 -04:00
2023-09-26 04:43:37 -04:00
pResult - > GetPrivate ( ) - > AddScalar ( 0 , 0 , 0 , value , FName ( Name ) ) ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
StoreInstance ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IN_ADDSTRING :
{
2023-12-19 05:19:14 -05:00
OP : : InstanceAddArgs args = Program . GetOpArgs < OP : : InstanceAddArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . instance , item ) ,
FScheduledOp ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
InstancePtrConst pBase =
2023-05-24 02:50:03 -04:00
LoadInstance ( FCacheAddress ( args . instance , item ) ) ;
2022-09-26 15:12:13 -04:00
InstancePtr pResult ;
if ( ! pBase )
{
pResult = new Instance ( ) ;
}
else
{
2023-05-24 02:50:03 -04:00
pResult = mu : : CloneOrTakeOver < Instance > ( pBase . get ( ) ) ;
2022-11-23 03:17:56 -05:00
}
2022-09-26 15:12:13 -04:00
if ( args . value )
{
2024-06-10 04:10:54 -04:00
Ptr < const String > value = LoadString ( FCacheAddress ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS nameAd = args . name ;
2023-12-19 05:19:14 -05:00
check ( nameAd < ( uint32 ) Program . m_constantStrings . Num ( ) ) ;
const FString & Name = Program . m_constantStrings [ nameAd ] ;
2022-09-26 15:12:13 -04:00
2023-09-26 04:43:37 -04:00
pResult - > GetPrivate ( ) - > AddString ( 0 , 0 , 0 , value - > GetValue ( ) , FName ( Name ) ) ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
StoreInstance ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IN_ADDCOMPONENT :
{
2023-12-19 05:19:14 -05:00
OP : : InstanceAddArgs args = Program . GetOpArgs < OP : : InstanceAddArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . instance , item ) ,
FScheduledOp ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2024-06-10 04:10:54 -04:00
Ptr < const Instance > pBase = LoadInstance ( FCacheAddress ( args . instance , item ) ) ;
Ptr < Instance > pResult ;
2022-09-26 15:12:13 -04:00
if ( ! pBase )
{
pResult = new Instance ( ) ;
}
else
{
2023-05-24 02:50:03 -04:00
pResult = mu : : CloneOrTakeOver < Instance > ( pBase . get ( ) ) ;
2022-11-23 03:17:56 -05:00
}
2022-09-26 15:12:13 -04:00
if ( args . value )
{
2024-06-10 04:10:54 -04:00
Ptr < const Instance > pComp = LoadInstance ( FCacheAddress ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-06-10 04:10:54 -04:00
int32 NewComponentIndex = pResult - > GetPrivate ( ) - > AddComponent ( ) ;
2022-09-26 15:12:13 -04:00
2024-06-10 04:10:54 -04:00
if ( ! pComp - > GetPrivate ( ) - > Components . IsEmpty ( ) )
2022-09-26 15:12:13 -04:00
{
2024-06-10 04:10:54 -04:00
pResult - > GetPrivate ( ) - > Components [ NewComponentIndex ] = pComp - > GetPrivate ( ) - > Components [ 0 ] ;
2022-09-26 15:12:13 -04:00
2024-06-10 04:10:54 -04:00
// Id
pResult - > GetPrivate ( ) - > Components [ NewComponentIndex ] . Id = args . id ;
2022-09-26 15:12:13 -04:00
}
}
2023-05-24 02:50:03 -04:00
StoreInstance ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IN_ADDSURFACE :
{
2023-12-19 05:19:14 -05:00
OP : : InstanceAddArgs args = Program . GetOpArgs < OP : : InstanceAddArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . instance , item ) ,
FScheduledOp ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2024-06-10 04:10:54 -04:00
Ptr < const Instance > pBase = LoadInstance ( FCacheAddress ( args . instance , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-06-10 04:10:54 -04:00
Ptr < Instance > pResult ;
2022-11-23 03:17:56 -05:00
if ( pBase )
{
2023-05-24 02:50:03 -04:00
pResult = mu : : CloneOrTakeOver < Instance > ( pBase . get ( ) ) ;
2022-11-23 03:17:56 -05:00
}
else
{
pResult = new Instance ( ) ;
}
2022-09-26 15:12:13 -04:00
// Empty surfaces are ok, they still need to be created, because they may contain
// additional information like internal or external IDs
//if ( args.value )
{
2024-06-10 04:10:54 -04:00
Ptr < const Instance > pSurf = LoadInstance ( FCacheAddress ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
int sindex = pResult - > GetPrivate ( ) - > AddSurface ( 0 , 0 ) ;
// Surface data
if ( pSurf
& &
2024-06-10 04:10:54 -04:00
pSurf - > GetPrivate ( ) - > Components . Num ( )
2022-09-26 15:12:13 -04:00
& &
2024-06-10 04:10:54 -04:00
pSurf - > GetPrivate ( ) - > Components [ 0 ] . LODs . Num ( )
2022-09-26 15:12:13 -04:00
& &
2024-06-10 04:10:54 -04:00
pSurf - > GetPrivate ( ) - > Components [ 0 ] . LODs [ 0 ] . Surfaces . Num ( ) )
2022-09-26 15:12:13 -04:00
{
2024-06-10 04:10:54 -04:00
pResult - > GetPrivate ( ) - > Components [ 0 ] . LODs [ 0 ] . Surfaces [ sindex ] =
pSurf - > GetPrivate ( ) - > Components [ 0 ] . LODs [ 0 ] . Surfaces [ 0 ] ;
2022-09-26 15:12:13 -04:00
}
// Name
OP : : ADDRESS nameAd = args . name ;
2023-12-19 05:19:14 -05:00
check ( nameAd < ( uint32 ) Program . m_constantStrings . Num ( ) ) ;
const FString & Name = Program . m_constantStrings [ nameAd ] ;
2023-09-26 04:43:37 -04:00
pResult - > GetPrivate ( ) - > SetSurfaceName ( 0 , 0 , sindex , FName ( Name ) ) ;
2022-09-26 15:12:13 -04:00
// IDs
2024-06-10 04:10:54 -04:00
pResult - > GetPrivate ( ) - > Components [ 0 ] . LODs [ 0 ] . Surfaces [ sindex ] . InternalId = args . id ;
pResult - > GetPrivate ( ) - > Components [ 0 ] . LODs [ 0 ] . Surfaces [ sindex ] . ExternalId = args . ExternalId ;
pResult - > GetPrivate ( ) - > Components [ 0 ] . LODs [ 0 ] . Surfaces [ sindex ] . SharedId = args . SharedSurfaceId ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
StoreInstance ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IN_ADDLOD :
{
2024-08-19 09:27:54 -04:00
const uint8 * Data = Program . GetOpArgsPointer ( item . At ) ;
uint8 LODCount ;
FMemory : : Memcpy ( & LODCount , Data , sizeof ( uint8 ) ) ;
Data + = sizeof ( uint8 ) ;
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
2022-11-23 03:17:56 -05:00
TArray < FScheduledOp > deps ;
2024-08-19 09:27:54 -04:00
for ( uint8 LODIndex = 0 ; LODIndex < LODCount ; + + LODIndex )
2022-11-23 03:17:56 -05:00
{
2024-08-19 09:27:54 -04:00
OP : : ADDRESS LODAddress ;
FMemory : : Memcpy ( & LODAddress , Data , sizeof ( OP : : ADDRESS ) ) ;
Data + = sizeof ( OP : : ADDRESS ) ;
2022-09-26 15:12:13 -04:00
2024-08-19 09:27:54 -04:00
if ( LODAddress )
{
bool bSelectedLod = ( ( 1 < < LODIndex ) & lodMask ) ! = 0 ;
if ( bSelectedLod )
2022-11-23 03:17:56 -05:00
{
2024-08-19 09:27:54 -04:00
deps . Emplace ( LODAddress , item ) ;
2022-09-26 15:12:13 -04:00
}
}
2022-11-23 03:17:56 -05:00
}
2022-09-26 15:12:13 -04:00
2024-08-19 09:27:54 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , deps ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case 1 :
{
// Assemble result
2024-06-10 04:10:54 -04:00
Ptr < Instance > pResult = new Instance ( ) ;
int32 ComponentIndex = pResult - > GetPrivate ( ) - > AddComponent ( ) ;
2022-09-26 15:12:13 -04:00
2024-08-19 09:27:54 -04:00
for ( uint8 LODIndex = 0 ; LODIndex < LODCount ; + + LODIndex )
2022-09-26 15:12:13 -04:00
{
2024-08-19 09:27:54 -04:00
OP : : ADDRESS LODAddress ;
FMemory : : Memcpy ( & LODAddress , Data , sizeof ( OP : : ADDRESS ) ) ;
Data + = sizeof ( OP : : ADDRESS ) ;
if ( LODAddress )
{
bool bIsSelectedLod = ( ( 1 < < LODIndex ) & lodMask ) ! = 0 ;
2022-09-26 15:12:13 -04:00
2024-06-10 04:10:54 -04:00
// Add an empty LOD even if not selected.
2024-08-19 09:27:54 -04:00
int32 InstanceLODIndex = pResult - > GetPrivate ( ) - > AddLOD ( ComponentIndex ) ;
2024-06-10 04:10:54 -04:00
if ( bIsSelectedLod )
2022-09-26 15:12:13 -04:00
{
2024-08-19 09:27:54 -04:00
Ptr < const Instance > pLOD = LoadInstance ( FCacheAddress ( LODAddress , item ) ) ;
2022-09-26 15:12:13 -04:00
// In a degenerated case, the returned pLOD may not have an LOD inside
2024-06-10 04:10:54 -04:00
if ( ! pLOD - > GetPrivate ( ) - > Components . IsEmpty ( )
& &
! pLOD - > GetPrivate ( ) - > Components [ 0 ] . LODs . IsEmpty ( ) )
{
2024-08-19 09:27:54 -04:00
pResult - > GetPrivate ( ) - > Components [ ComponentIndex ] . LODs [ InstanceLODIndex ] = pLOD - > GetPrivate ( ) - > Components [ 0 ] . LODs [ 0 ] ;
2024-06-10 04:10:54 -04:00
}
}
2022-09-26 15:12:13 -04:00
}
}
2023-05-24 02:50:03 -04:00
StoreInstance ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2023-04-05 11:20:44 -04:00
case OP_TYPE : : IN_ADDEXTENSIONDATA :
{
2023-12-19 05:19:14 -05:00
OP : : InstanceAddExtensionDataArgs Args = Program . GetOpArgs < OP : : InstanceAddExtensionDataArgs > ( item . At ) ;
2023-04-05 11:20:44 -04:00
switch ( item . Stage )
{
case 0 :
{
// Must pass in an Instance op and ExtensionData op
check ( Args . Instance ) ;
check ( Args . ExtensionData ) ;
TArray < FScheduledOp > Dependencies ;
Dependencies . Emplace ( Args . Instance , item ) ;
Dependencies . Emplace ( Args . ExtensionData , item ) ;
AddOp ( FScheduledOp ( item . At , item , 1 ) , Dependencies ) ;
break ;
}
case 1 :
{
// Assemble result
2023-05-24 02:50:03 -04:00
InstancePtrConst InstanceOpResult = LoadInstance ( FCacheAddress ( Args . Instance , item ) ) ;
2023-04-05 11:20:44 -04:00
2023-05-24 02:50:03 -04:00
InstancePtr Result = mu : : CloneOrTakeOver < Instance > ( InstanceOpResult . get ( ) ) ;
2023-04-05 11:20:44 -04:00
2023-05-24 02:50:03 -04:00
if ( ExtensionDataPtrConst ExtensionData = LoadExtensionData ( FCacheAddress ( Args . ExtensionData , item ) ) )
2023-04-05 11:20:44 -04:00
{
const OP : : ADDRESS NameAddress = Args . ExtensionDataName ;
2023-12-19 05:19:14 -05:00
check ( NameAddress < ( uint32 ) Program . m_constantStrings . Num ( ) ) ;
const FString & NameString = Program . m_constantStrings [ NameAddress ] ;
2023-04-05 11:20:44 -04:00
2023-09-26 04:43:37 -04:00
Result - > GetPrivate ( ) - > AddExtensionData ( ExtensionData , FName ( NameString ) ) ;
2023-04-05 11:20:44 -04:00
}
2023-05-24 02:50:03 -04:00
StoreInstance ( item , Result ) ;
2023-04-05 11:20:44 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
default :
check ( false ) ;
}
}
//---------------------------------------------------------------------------------------------
2023-08-03 03:37:44 -04:00
void CodeRunner : : RunCode_InstanceAddResource ( const FScheduledOp & item , const TSharedPtr < const Model > & InModel , const Parameters * InParams )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_InstanceAddResource ) ;
2023-07-31 03:24:06 -04:00
if ( ! InModel | | ! m_pSystem )
2023-06-26 02:16:47 -04:00
{
return ;
}
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : IN_ADDMESH :
{
2023-12-19 05:19:14 -05:00
OP : : InstanceAddArgs args = Program . GetOpArgs < OP : : InstanceAddArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2024-06-10 04:10:54 -04:00
// We don't build the resources when building instance: just store ids for them.
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . instance , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
InstancePtrConst pBase = LoadInstance ( FCacheAddress ( args . instance , item ) ) ;
2022-09-26 15:12:13 -04:00
InstancePtr pResult ;
if ( ! pBase )
{
pResult = new Instance ( ) ;
}
else
{
2023-05-24 02:50:03 -04:00
pResult = mu : : CloneOrTakeOver < Instance > ( pBase . get ( ) ) ;
2022-11-23 03:17:56 -05:00
}
2022-09-26 15:12:13 -04:00
if ( args . value )
{
2023-07-31 03:24:06 -04:00
FResourceID MeshId = m_pSystem - > WorkingMemoryManager . GetResourceKey ( InModel , InParams , args . relevantParametersListIndex , args . value ) ;
OP : : ADDRESS NameAd = args . name ;
2023-12-19 05:19:14 -05:00
check ( NameAd < ( uint32 ) Program . m_constantStrings . Num ( ) ) ;
const FString & Name = Program . m_constantStrings [ NameAd ] ;
2024-06-10 04:10:54 -04:00
pResult - > GetPrivate ( ) - > SetMesh ( 0 , 0 , MeshId , FName ( Name ) ) ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
StoreInstance ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IN_ADDIMAGE :
{
2023-12-19 05:19:14 -05:00
OP : : InstanceAddArgs args = Program . GetOpArgs < OP : : InstanceAddArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
// We don't build the resources when building instance: just store ids for them.
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . instance , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
InstancePtrConst pBase = LoadInstance ( FCacheAddress ( args . instance , item ) ) ;
2022-09-26 15:12:13 -04:00
InstancePtr pResult ;
if ( ! pBase )
{
pResult = new Instance ( ) ;
}
else
{
2023-05-24 02:50:03 -04:00
pResult = mu : : CloneOrTakeOver < Instance > ( pBase . get ( ) ) ;
2022-11-23 03:17:56 -05:00
}
2022-09-26 15:12:13 -04:00
if ( args . value )
{
2023-07-31 03:24:06 -04:00
FResourceID ImageId = m_pSystem - > WorkingMemoryManager . GetResourceKey ( InModel , InParams , args . relevantParametersListIndex , args . value ) ;
OP : : ADDRESS NameAd = args . name ;
2023-12-19 05:19:14 -05:00
check ( NameAd < ( uint32 ) Program . m_constantStrings . Num ( ) ) ;
const FString & Name = Program . m_constantStrings [ NameAd ] ;
2023-09-26 04:43:37 -04:00
pResult - > GetPrivate ( ) - > AddImage ( 0 , 0 , 0 , ImageId , FName ( Name ) ) ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
StoreInstance ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
default :
check ( false ) ;
}
}
2024-08-13 10:23:49 -04:00
//---------------------------------------------------------------------------------------------
bool CodeRunner : : RunCode_ConstantResource ( const FScheduledOp & item , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Constant ) ;
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
2024-08-13 10:23:49 -04:00
OP_TYPE type = Program . GetOpType ( item . At ) ;
switch ( type )
2022-09-26 15:12:13 -04:00
{
case OP_TYPE : : ME_CONSTANT :
{
2024-08-13 10:23:49 -04:00
OP : : MeshConstantArgs args = Program . GetOpArgs < OP : : MeshConstantArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
OP : : ADDRESS cat = args . value ;
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
// Assume the ROM has been loaded previously
check ( Program . ConstantMeshes [ cat ] . Value )
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
Ptr < const Mesh > SourceConst ;
Program . GetConstant ( cat , SourceConst ) ;
2023-06-15 04:45:22 -04:00
2024-08-13 10:23:49 -04:00
check ( SourceConst ) ;
Ptr < Mesh > Source = CreateMesh ( SourceConst - > GetDataSize ( ) ) ;
Source - > CopyFrom ( * SourceConst ) ;
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
// Set the separate skeleton if necessary
if ( args . skeleton > = 0 )
{
check ( Program . m_constantSkeletons . Num ( ) > size_t ( args . skeleton ) ) ;
Ptr < const Skeleton > pSkeleton = Program . m_constantSkeletons [ args . skeleton ] ;
Source - > SetSkeleton ( pSkeleton ) ;
}
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
if ( args . physicsBody > = 0 )
2024-08-13 05:15:15 -04:00
{
2024-08-13 10:23:49 -04:00
check ( Program . m_constantPhysicsBodies . Num ( ) > size_t ( args . physicsBody ) ) ;
Ptr < const PhysicsBody > pPhysicsBody = Program . m_constantPhysicsBodies [ args . physicsBody ] ;
Source - > SetPhysicsBody ( pPhysicsBody ) ;
2024-08-13 05:15:15 -04:00
}
2024-08-13 10:23:49 -04:00
StoreMesh ( item , Source ) ;
2022-11-23 03:17:56 -05:00
//UE_LOG(LogMutableCore, Log, TEXT("Set mesh constant %d."), item.At);
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : IM_CONSTANT :
{
2024-08-13 10:23:49 -04:00
OP : : ResourceConstantArgs args = Program . GetOpArgs < OP : : ResourceConstantArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
OP : : ADDRESS cat = args . value ;
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
int32 MipsToSkip = item . ExecutionOptions ;
2023-05-24 02:50:03 -04:00
Ptr < const Image > Source ;
2023-12-19 05:19:14 -05:00
Program . GetConstant ( cat , Source , MipsToSkip , [ this ] ( int32 x , int32 y , int32 m , EImageFormat f , EInitializationType i )
2023-06-23 02:01:13 -04:00
{
return CreateImage ( x , y , m , f , i ) ;
} ) ;
2022-09-26 15:12:13 -04:00
// Assume the ROM has been loaded previously in a task generated at IssueOp
2024-06-14 04:01:28 -04:00
if ( ! Source )
{
return false ;
}
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
StoreImage ( item , Source ) ;
2022-11-23 03:17:56 -05:00
//UE_LOG(LogMutableCore, Log, TEXT("Set image constant %d."), item.At);
2022-09-26 15:12:13 -04:00
break ;
}
2023-04-05 11:20:44 -04:00
case OP_TYPE : : ED_CONSTANT :
{
2024-08-13 10:23:49 -04:00
OP : : ResourceConstantArgs Args = Program . GetOpArgs < OP : : ResourceConstantArgs > ( item . At ) ;
2023-04-05 11:20:44 -04:00
// Assume the ROM has been loaded previously
ExtensionDataPtrConst SourceConst ;
Program . GetExtensionDataConstant ( Args . value , SourceConst ) ;
check ( SourceConst ) ;
2024-08-13 10:23:49 -04:00
StoreExtensionData ( item , SourceConst ) ;
2023-04-05 11:20:44 -04:00
break ;
}
2022-09-26 15:12:13 -04:00
default :
2024-08-13 10:23:49 -04:00
if ( type ! = OP_TYPE : : NONE )
2022-09-26 15:12:13 -04:00
{
// Operation not implemented
check ( false ) ;
}
break ;
}
2024-06-14 04:01:28 -04:00
// Success
return true ;
2022-09-26 15:12:13 -04:00
}
//---------------------------------------------------------------------------------------------
2023-05-03 12:48:24 -04:00
void CodeRunner : : RunCode_Mesh ( const FScheduledOp & item , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Mesh ) ;
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2023-06-15 04:45:22 -04:00
2022-09-26 15:12:13 -04:00
switch ( type )
{
2024-05-14 07:28:21 -04:00
case OP_TYPE : : ME_REFERENCE :
{
OP : : ResourceReferenceArgs Args = Program . GetOpArgs < OP : : ResourceReferenceArgs > ( item . At ) ;
switch ( item . Stage )
{
case 0 :
{
Ptr < Mesh > Result ;
if ( Args . ForceLoad )
{
// This should never be reached because it should have been caught as a Task in IssueOp
check ( false ) ;
}
else
{
Result = Mesh : : CreateAsReference ( Args . ID , false ) ;
}
StoreMesh ( item , Result ) ;
break ;
}
default :
check ( false ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case OP_TYPE : : ME_APPLYLAYOUT :
{
2023-12-19 05:19:14 -05:00
OP : : MeshApplyLayoutArgs args = Program . GetOpArgs < OP : : MeshApplyLayoutArgs > ( item . At ) ;
2023-06-15 04:45:22 -04:00
switch ( item . Stage )
{
case 0 :
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . mesh , item ) ,
2024-08-13 10:23:49 -04:00
FScheduledOp ( args . layout , item ) ) ;
2023-06-15 04:45:22 -04:00
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_APPLYLAYOUT )
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > pBase = LoadMesh ( FCacheAddress ( args . mesh , item ) ) ;
2022-09-26 15:12:13 -04:00
if ( pBase )
{
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CloneOrTakeOver ( pBase ) ;
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
Ptr < const Layout > pLayout = LoadLayout ( FCacheAddress ( args . layout , item ) ) ;
2022-09-26 15:12:13 -04:00
int texCoordsSet = args . channel ;
2023-06-15 04:45:22 -04:00
MeshApplyLayout ( Result . get ( ) , pLayout . get ( ) , texCoordsSet ) ;
StoreMesh ( item , Result ) ;
}
else
{
StoreMesh ( item , nullptr ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_DIFFERENCE :
{
2023-12-19 05:19:14 -05:00
const uint8 * data = Program . GetOpArgsPointer ( item . At ) ;
2022-10-19 15:14:57 -04:00
OP : : ADDRESS BaseAt = 0 ;
2023-06-15 04:45:22 -04:00
FMemory : : Memcpy ( & BaseAt , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
2022-10-19 15:14:57 -04:00
OP : : ADDRESS TargetAt = 0 ;
2023-06-15 04:45:22 -04:00
FMemory : : Memcpy ( & TargetAt , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
2022-10-19 15:14:57 -04:00
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
if ( BaseAt & & TargetAt )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( BaseAt , item ) ,
FScheduledOp ( TargetAt , item ) ) ;
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_DIFFERENCE )
2023-05-24 02:50:03 -04:00
Ptr < const Mesh > pBase = LoadMesh ( FCacheAddress ( BaseAt , item ) ) ;
Ptr < const Mesh > pTarget = LoadMesh ( FCacheAddress ( TargetAt , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-04-03 05:35:18 -04:00
TArray < EMeshBufferSemantic , TInlineAllocator < 8 > > Semantics ;
2022-10-19 15:14:57 -04:00
TArray < int32 , TInlineAllocator < 8 > > SemanticIndices ;
2022-09-26 15:12:13 -04:00
2022-10-19 15:14:57 -04:00
uint8 bIgnoreTextureCoords = 0 ;
2023-06-15 04:45:22 -04:00
FMemory : : Memcpy ( & bIgnoreTextureCoords , data , sizeof ( uint8 ) ) ;
data + = sizeof ( uint8 ) ;
2022-10-19 15:14:57 -04:00
uint8 NumChannels = 0 ;
2023-06-15 04:45:22 -04:00
FMemory : : Memcpy ( & NumChannels , data , sizeof ( uint8 ) ) ;
data + = sizeof ( uint8 ) ;
2022-10-19 15:14:57 -04:00
2023-06-15 04:45:22 -04:00
for ( uint8 i = 0 ; i < NumChannels ; + + i )
2022-09-26 15:12:13 -04:00
{
2022-10-19 15:14:57 -04:00
uint8 Semantic = 0 ;
2023-06-15 04:45:22 -04:00
FMemory : : Memcpy ( & Semantic , data , sizeof ( uint8 ) ) ;
data + = sizeof ( uint8 ) ;
2022-10-19 15:14:57 -04:00
uint8 SemanticIndex = 0 ;
2023-06-15 04:45:22 -04:00
FMemory : : Memcpy ( & SemanticIndex , data , sizeof ( uint8 ) ) ;
data + = sizeof ( uint8 ) ;
2022-10-19 15:14:57 -04:00
2024-04-03 05:35:18 -04:00
Semantics . Add ( EMeshBufferSemantic ( Semantic ) ) ;
2022-10-19 15:14:57 -04:00
SemanticIndices . Add ( SemanticIndex ) ;
2022-09-26 15:12:13 -04:00
}
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( ) ;
bool bOutSuccess = false ;
MeshDifference ( Result . get ( ) , pBase . get ( ) , pTarget . get ( ) ,
NumChannels , Semantics . GetData ( ) , SemanticIndices . GetData ( ) ,
bIgnoreTextureCoords ! = 0 , bOutSuccess ) ;
Release ( pBase ) ;
Release ( pTarget ) ;
StoreMesh ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2023-06-08 05:48:32 -04:00
case OP_TYPE : : ME_MORPH :
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
const uint8 * Data = Program . GetOpArgsPointer ( item . At ) ;
2022-10-21 22:27:28 -04:00
OP : : ADDRESS FactorAt = 0 ;
2024-07-26 04:34:11 -04:00
FMemory : : Memcpy ( & FactorAt , Data , sizeof ( OP : : ADDRESS ) ) ;
Data + = sizeof ( OP : : ADDRESS ) ;
2022-10-21 22:27:28 -04:00
OP : : ADDRESS BaseAt = 0 ;
2024-07-26 04:34:11 -04:00
FMemory : : Memcpy ( & BaseAt , Data , sizeof ( OP : : ADDRESS ) ) ;
Data + = sizeof ( OP : : ADDRESS ) ;
2022-10-21 22:27:28 -04:00
2023-06-08 05:48:32 -04:00
OP : : ADDRESS TargetAt = 0 ;
2024-07-26 04:34:11 -04:00
FMemory : : Memcpy ( & TargetAt , Data , sizeof ( OP : : ADDRESS ) ) ;
Data + = sizeof ( OP : : ADDRESS ) ;
2022-10-21 22:27:28 -04:00
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-10-21 22:27:28 -04:00
if ( BaseAt )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( FactorAt , item ) ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2023-06-15 04:45:22 -04:00
StoreMesh ( item , nullptr ) ;
2022-09-26 15:12:13 -04:00
}
break ;
case 1 :
{
2023-06-08 05:48:32 -04:00
MUTABLE_CPUPROFILER_SCOPE ( ME_MORPH_1 )
2023-01-25 04:08:49 -05:00
2023-06-15 04:45:22 -04:00
float Factor = LoadScalar ( FCacheAddress ( FactorAt , item ) ) ;
2022-09-26 15:12:13 -04:00
// Factor goes from -1 to 1 across all targets. [0 - 1] represents positive morphs, while [-1, 0) represent negative morphs.
2023-06-08 05:48:32 -04:00
Factor = FMath : : Clamp ( Factor , - 1.0f , 1.0f ) ; // Is the factor not in range [-1, 1], it will index a non existing morph.
2022-09-26 15:12:13 -04:00
2023-06-08 05:48:32 -04:00
FScheduledOpData HeapData ;
HeapData . Interpolate . Bifactor = Factor ;
2024-07-26 04:34:11 -04:00
uint32 DataAddress = uint32 ( m_heapData . Add ( HeapData ) ) ;
2022-09-26 15:12:13 -04:00
2023-06-08 05:48:32 -04:00
// No morph
2023-06-15 04:45:22 -04:00
if ( FMath : : IsNearlyZero ( Factor ) )
2023-06-08 05:48:32 -04:00
{
2024-07-26 04:34:11 -04:00
AddOp ( FScheduledOp ( item . At , item , 2 , DataAddress ) ,
2023-06-15 04:45:22 -04:00
FScheduledOp ( BaseAt , item ) ) ;
2023-06-08 05:48:32 -04:00
}
// The Morph, partial or full
else
2022-09-26 15:12:13 -04:00
{
2023-06-08 05:48:32 -04:00
// We will need the base again
2024-07-26 04:34:11 -04:00
AddOp ( FScheduledOp ( item . At , item , 2 , DataAddress ) ,
2023-06-15 04:45:22 -04:00
FScheduledOp ( BaseAt , item ) ,
FScheduledOp ( TargetAt , item ) ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
case 2 :
{
2023-06-08 05:48:32 -04:00
MUTABLE_CPUPROFILER_SCOPE ( ME_MORPH_2 )
2023-01-25 04:08:49 -05:00
2024-07-26 04:34:11 -04:00
Ptr < const Mesh > BaseMesh = LoadMesh ( FCacheAddress ( BaseAt , item ) ) ;
2022-09-26 15:12:13 -04:00
// Factor from 0 to 1 between the two targets
2024-07-26 04:34:11 -04:00
const FScheduledOpData & HeapData = m_heapData [ item . CustomState ] ;
2023-06-08 05:48:32 -04:00
float Factor = HeapData . Interpolate . Bifactor ;
2022-09-26 15:12:13 -04:00
2024-07-26 04:34:11 -04:00
if ( BaseMesh )
2022-09-26 15:12:13 -04:00
{
2023-06-08 05:48:32 -04:00
// No morph
2023-06-15 04:45:22 -04:00
if ( FMath : : IsNearlyZero ( Factor ) )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
StoreMesh ( item , BaseMesh ) ;
2022-09-26 15:12:13 -04:00
}
2023-06-08 05:48:32 -04:00
// The Morph, partial or full
else
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
Ptr < const Mesh > MorphMesh = LoadMesh ( FCacheAddress ( TargetAt , item ) ) ;
2023-06-15 04:45:22 -04:00
2024-07-26 04:34:11 -04:00
if ( MorphMesh )
2023-06-15 04:45:22 -04:00
{
2024-07-26 04:34:11 -04:00
Ptr < Mesh > Result = CloneOrTakeOver ( BaseMesh ) ;
MeshMorph ( Result . get ( ) , MorphMesh . get ( ) , Factor ) ;
2023-06-15 04:45:22 -04:00
2024-07-26 04:34:11 -04:00
Release ( MorphMesh ) ;
StoreMesh ( item , Result ) ;
2023-06-15 04:45:22 -04:00
}
else
{
2024-07-26 04:34:11 -04:00
StoreMesh ( item , BaseMesh ) ;
2023-06-15 04:45:22 -04:00
}
2022-09-26 15:12:13 -04:00
}
}
2023-06-15 04:45:22 -04:00
else
{
StoreMesh ( item , nullptr ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_MERGE :
{
2023-12-19 05:19:14 -05:00
OP : : MeshMergeArgs args = Program . GetOpArgs < OP : : MeshMergeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . base , item ) ,
FScheduledOp ( args . added , item ) ) ;
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-05-03 12:48:24 -04:00
MUTABLE_CPUPROFILER_SCOPE ( ME_MERGE_1 )
2023-01-25 04:08:49 -05:00
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > pA = LoadMesh ( FCacheAddress ( args . base , item ) ) ;
Ptr < const Mesh > pB = LoadMesh ( FCacheAddress ( args . added , item ) ) ;
2022-09-26 15:12:13 -04:00
if ( pA & & pB & & pA - > GetVertexCount ( ) & & pB - > GetVertexCount ( ) )
{
2024-05-14 07:28:21 -04:00
check ( ! pA - > IsReference ( ) & & ! pB - > IsReference ( ) ) ;
2023-06-15 04:45:22 -04:00
FMeshMergeScratchMeshes Scratch ;
Scratch . FirstReformat = CreateMesh ( ) ;
Scratch . SecondReformat = CreateMesh ( ) ;
Ptr < Mesh > Result = CreateMesh ( pA - > GetDataSize ( ) + pB - > GetDataSize ( ) ) ;
MeshMerge ( Result . get ( ) , pA . get ( ) , pB . get ( ) , ! args . newSurfaceID , Scratch ) ;
Release ( Scratch . FirstReformat ) ;
Release ( Scratch . SecondReformat ) ;
2022-09-26 15:12:13 -04:00
2023-05-10 07:27:16 -04:00
if ( args . newSurfaceID )
2022-09-26 15:12:13 -04:00
{
2023-05-10 07:27:16 -04:00
check ( pB - > GetSurfaceCount ( ) = = 1 ) ;
2024-04-29 03:42:15 -04:00
Result - > Surfaces . Last ( ) . Id = args . newSurfaceID ;
2022-09-26 15:12:13 -04:00
}
2023-06-15 04:45:22 -04:00
Release ( pA ) ;
Release ( pB ) ;
StoreMesh ( item , Result ) ;
2022-09-26 15:12:13 -04:00
}
2024-05-14 07:28:21 -04:00
else if ( pA & & ( pA - > GetVertexCount ( ) | | pA - > IsReference ( ) ) )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Release ( pB ) ;
StoreMesh ( item , pA ) ;
2022-09-26 15:12:13 -04:00
}
2024-05-14 07:28:21 -04:00
else if ( pB & & ( pB - > GetVertexCount ( ) | | pB - > IsReference ( ) ) )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CloneOrTakeOver ( pB ) ;
2024-05-14 07:28:21 -04:00
check ( Result - > IsReference ( ) | | ( Result - > GetSurfaceCount ( ) = = 1 ) ) ;
2023-06-15 04:45:22 -04:00
if ( Result - > GetSurfaceCount ( ) > 0 & & args . newSurfaceID )
2022-09-26 15:12:13 -04:00
{
2024-04-29 03:42:15 -04:00
Result - > Surfaces . Last ( ) . Id = args . newSurfaceID ;
2022-09-26 15:12:13 -04:00
}
2023-06-15 04:45:22 -04:00
Release ( pA ) ;
StoreMesh ( item , Result ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2023-06-26 06:39:22 -04:00
Release ( pA ) ;
Release ( pB ) ;
2023-06-15 04:45:22 -04:00
StoreMesh ( item , CreateMesh ( ) ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_INTERPOLATE :
{
2024-07-26 04:34:11 -04:00
OP : : MeshInterpolateArgs Args = Program . GetOpArgs < OP : : MeshInterpolateArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
2024-07-26 04:34:11 -04:00
if ( Args . base )
2023-06-15 04:45:22 -04:00
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
2024-07-26 04:34:11 -04:00
FScheduledOp ( Args . base , item ) ,
FScheduledOp ( Args . factor , item ) ) ;
2023-06-15 04:45:22 -04:00
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_INTERPOLATE_1 )
2024-07-26 04:34:11 -04:00
int32 Count = 1 ;
for ( int32 TargetIndex = 0 ; TargetIndex < MUTABLE_OP_MAX_INTERPOLATE_COUNT - 1 & & Args . targets [ TargetIndex ] ; + + TargetIndex )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
+ + Count ;
2022-09-26 15:12:13 -04:00
}
// Factor from 0 to 1 across all targets
2024-07-26 04:34:11 -04:00
float Factor = LoadScalar ( FCacheAddress ( Args . factor , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-07-26 04:34:11 -04:00
float Delta = 1.0f / ( Count - 1 ) ;
int32 Min = FMath : : FloorToInt ( Factor / Delta ) ;
int32 Max = FMath : : CeilToInt ( Factor / Delta ) ;
2022-09-26 15:12:13 -04:00
// Factor from 0 to 1 between the two targets
2024-07-26 04:34:11 -04:00
float Bifactor = Factor / Delta - Min ;
2022-09-26 15:12:13 -04:00
2024-07-26 04:34:11 -04:00
FScheduledOpData Data ;
Data . Interpolate . Bifactor = Bifactor ;
Data . Interpolate . Min = FMath : : Clamp ( Min , 0 , Count - 1 ) ;
Data . Interpolate . Max = FMath : : Clamp ( Max , 0 , Count - 1 ) ;
uint32 DataAddress = uint32 ( m_heapData . Num ( ) ) ;
2022-09-26 15:12:13 -04:00
// Just the first of the targets
2024-07-26 04:34:11 -04:00
if ( Bifactor < UE_SMALL_NUMBER )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
if ( Min = = 0 )
2022-09-26 15:12:13 -04:00
{
// Just the base
2024-07-26 04:34:11 -04:00
Ptr < const Mesh > BaseMesh = LoadMesh ( FCacheAddress ( Args . base , item ) ) ;
StoreMesh ( item , BaseMesh ) ;
2023-06-15 04:45:22 -04:00
}
2022-09-26 15:12:13 -04:00
else
{
// Base with one full morph
2024-07-26 04:34:11 -04:00
m_heapData . Add ( Data ) ;
AddOp ( FScheduledOp ( item . At , item , 2 , DataAddress ) ,
FScheduledOp ( Args . base , item ) ,
FScheduledOp ( Args . targets [ Min - 1 ] , item ) ) ;
2023-06-15 04:45:22 -04:00
}
}
2022-09-26 15:12:13 -04:00
// Just the second of the targets
2024-07-26 04:34:11 -04:00
else if ( Bifactor > 1.0f - UE_SMALL_NUMBER )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
m_heapData . Add ( Data ) ;
AddOp ( FScheduledOp ( item . At , item , 2 , DataAddress ) ,
FScheduledOp ( Args . base , item ) ,
FScheduledOp ( Args . targets [ Max - 1 ] , item ) ) ;
2023-06-15 04:45:22 -04:00
}
2022-09-26 15:12:13 -04:00
// Mix the first target on the base
2024-07-26 04:34:11 -04:00
else if ( Min = = 0 )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
m_heapData . Add ( Data ) ;
AddOp ( FScheduledOp ( item . At , item , 2 , DataAddress ) ,
FScheduledOp ( Args . base , item ) ,
FScheduledOp ( Args . targets [ 0 ] , item ) ) ;
2023-06-15 04:45:22 -04:00
}
2022-09-26 15:12:13 -04:00
// Mix two targets on the base
else
{
2024-07-26 04:34:11 -04:00
m_heapData . Add ( Data ) ;
AddOp ( FScheduledOp ( item . At , item , 2 , DataAddress ) ,
FScheduledOp ( Args . base , item ) ,
FScheduledOp ( Args . targets [ Min - 1 ] , item ) ,
FScheduledOp ( Args . targets [ Max - 1 ] , item ) ) ;
2023-06-15 04:45:22 -04:00
}
2022-09-26 15:12:13 -04:00
break ;
}
case 2 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_INTERPOLATE_2 )
2024-07-26 04:34:11 -04:00
int32 Count = 1 ;
for ( int32 TargetIndex = 0 ; TargetIndex < MUTABLE_OP_MAX_INTERPOLATE_COUNT - 1 & & Args . targets [ TargetIndex ] ; + + TargetIndex )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
+ + Count ;
2022-09-26 15:12:13 -04:00
}
2024-07-26 04:34:11 -04:00
const FScheduledOpData & Data = m_heapData [ ( size_t ) item . CustomState ] ;
2022-09-26 15:12:13 -04:00
// Factor from 0 to 1 between the two targets
2024-07-26 04:34:11 -04:00
float Bifactor = Data . Interpolate . Bifactor ;
int32 Min = Data . Interpolate . Min ;
int32 Max = Data . Interpolate . Max ;
2022-09-26 15:12:13 -04:00
2024-07-26 04:34:11 -04:00
Ptr < const Mesh > BaseMesh = LoadMesh ( FCacheAddress ( Args . base , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-07-26 04:34:11 -04:00
if ( BaseMesh )
2022-09-26 15:12:13 -04:00
{
// Just the first of the targets
2024-07-26 04:34:11 -04:00
if ( Bifactor < UE_SMALL_NUMBER )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
if ( Min = = 0 )
2022-09-26 15:12:13 -04:00
{
// Just the base. It should have been dealt with in the previous stage.
2023-06-15 04:45:22 -04:00
check ( false ) ;
2022-09-26 15:12:13 -04:00
}
else
{
// Base with one full morph
2024-07-26 04:34:11 -04:00
Ptr < const Mesh > MorphMesh = LoadMesh ( FCacheAddress ( Args . targets [ Min - 1 ] , item ) ) ;
2023-06-15 04:45:22 -04:00
2024-07-26 04:34:11 -04:00
if ( MorphMesh )
2023-06-15 04:45:22 -04:00
{
2024-07-26 04:34:11 -04:00
Ptr < Mesh > Result = CloneOrTakeOver ( BaseMesh ) ;
MeshMorph ( Result . get ( ) , MorphMesh . get ( ) ) ;
StoreMesh ( item , Result ) ;
2023-06-15 04:45:22 -04:00
}
else
{
2024-07-26 04:34:11 -04:00
StoreMesh ( item , BaseMesh ) ;
2023-06-15 04:45:22 -04:00
}
2024-07-26 04:34:11 -04:00
Release ( MorphMesh ) ;
2022-09-26 15:12:13 -04:00
}
}
// Just the second of the targets
2024-07-26 04:34:11 -04:00
else if ( Bifactor > 1.0f - UE_SMALL_NUMBER )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
check ( Max > 0 ) ;
Ptr < const Mesh > MorphMesh = LoadMesh ( FCacheAddress ( Args . targets [ Max - 1 ] , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-07-26 04:34:11 -04:00
if ( MorphMesh )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
Ptr < Mesh > Result = CloneOrTakeOver ( BaseMesh ) ;
2023-06-15 04:45:22 -04:00
2024-07-26 04:34:11 -04:00
MeshMorph ( Result . get ( ) , MorphMesh . get ( ) ) ;
2023-06-15 04:45:22 -04:00
2024-07-26 04:34:11 -04:00
StoreMesh ( item , Result ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2024-07-26 04:34:11 -04:00
StoreMesh ( item , BaseMesh ) ;
2022-09-26 15:12:13 -04:00
}
2024-07-26 04:34:11 -04:00
Release ( MorphMesh ) ;
2022-09-26 15:12:13 -04:00
}
// Mix the first target on the base
2024-07-26 04:34:11 -04:00
else if ( Min = = 0 )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
Ptr < const Mesh > MorphMesh = LoadMesh ( FCacheAddress ( Args . targets [ 0 ] , item ) ) ;
if ( MorphMesh )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
Ptr < Mesh > Result = CloneOrTakeOver ( BaseMesh ) ;
2023-06-15 04:45:22 -04:00
2024-07-26 04:34:11 -04:00
MeshMorph ( Result . get ( ) , MorphMesh . get ( ) , Bifactor ) ;
2023-06-15 04:45:22 -04:00
2024-07-26 04:34:11 -04:00
StoreMesh ( item , Result ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2024-07-26 04:34:11 -04:00
StoreMesh ( item , BaseMesh ) ;
2022-09-26 15:12:13 -04:00
}
2024-07-26 04:34:11 -04:00
Release ( MorphMesh ) ;
2022-09-26 15:12:13 -04:00
}
// Mix two targets on the base
else
{
2024-07-26 04:34:11 -04:00
Ptr < const Mesh > MinMesh = LoadMesh ( FCacheAddress ( Args . targets [ Min - 1 ] , item ) ) ;
Ptr < const Mesh > MaxMesh = LoadMesh ( FCacheAddress ( Args . targets [ Max - 1 ] , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-07-26 04:34:11 -04:00
if ( MinMesh & & MaxMesh )
2022-09-26 15:12:13 -04:00
{
2024-07-26 04:34:11 -04:00
Ptr < Mesh > Result = CloneOrTakeOver ( BaseMesh ) ;
2023-06-15 04:45:22 -04:00
2024-07-26 04:34:11 -04:00
MeshMorph2 ( Result . get ( ) , MinMesh . get ( ) , MaxMesh . get ( ) , Bifactor ) ;
2023-06-15 04:45:22 -04:00
2024-07-26 04:34:11 -04:00
StoreMesh ( item , Result ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2024-07-26 04:34:11 -04:00
StoreMesh ( item , BaseMesh ) ;
2022-09-26 15:12:13 -04:00
}
2024-07-26 04:34:11 -04:00
Release ( MinMesh ) ;
Release ( MaxMesh ) ;
2022-09-26 15:12:13 -04:00
}
}
2023-06-15 04:45:22 -04:00
else
{
2024-07-26 04:34:11 -04:00
StoreMesh ( item , BaseMesh ) ;
2023-06-15 04:45:22 -04:00
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_MASKCLIPMESH :
{
2023-12-19 05:19:14 -05:00
OP : : MeshMaskClipMeshArgs args = Program . GetOpArgs < OP : : MeshMaskClipMeshArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . source , item ) ,
FScheduledOp ( args . clip , item ) ) ;
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_MASKCLIPMESH_1 )
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( args . source , item ) ) ;
Ptr < const Mesh > pClip = LoadMesh ( FCacheAddress ( args . clip , item ) ) ;
2022-09-26 15:12:13 -04:00
// Only if both are valid.
2023-05-24 02:50:03 -04:00
if ( Source . get ( ) & & pClip . get ( ) )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( ) ;
bool bOutSuccess = false ;
MeshMaskClipMesh ( Result . get ( ) , Source . get ( ) , pClip . get ( ) , bOutSuccess ) ;
Release ( Source ) ;
Release ( pClip ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , nullptr ) ;
}
else
{
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
2023-06-15 04:45:22 -04:00
else
{
Release ( Source ) ;
Release ( pClip ) ;
StoreMesh ( item , nullptr ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2023-10-24 06:20:03 -04:00
case OP_TYPE : : ME_MASKCLIPUVMASK :
{
2023-12-19 05:19:14 -05:00
OP : : MeshMaskClipUVMaskArgs args = Program . GetOpArgs < OP : : MeshMaskClipUVMaskArgs > ( item . At ) ;
2023-10-24 06:20:03 -04:00
switch ( item . Stage )
{
case 0 :
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . Source , item ) ,
[mutable] Convert the following nodes to modifiers: EditMaterial, ExtendMaterial, RemoveMesh, RemoveMeshBlocks, MorphMaterial.
- Rename some existing modifier nodes to actually be prefixed "Modifier" instead of "Mesh".
- Added additional entry points for modifiers during code generation. Now there are 4: right after generating a mesh constant, right after all mesh operations have been generated, right after a texture block has been generated and right after a texture has been generated.
- Fix bug with mesh clip with UV mask when layout blocks were used.
- For legacy data conversion autogenerated tags are created and assigned to the material nodes and the new modifier nodes.
- MorphMaterial code generation has been redesigned passing all morphs to the MutableTools layer.
#jira UE-221279
#jira UE-221278
#rnx
[REVIEW] [at]genis.sole, [at]gerard.martin, [at]pere.rifa
#rb genis.sole, gerard.martin, pere.rifa
[CL 35952198 by jordi rovira in ue5-main branch]
2024-09-02 04:15:31 -04:00
FScheduledOp ( args . UVSource , item ) ,
FScheduledOp ( args . MaskImage , item ) ,
FScheduledOp ( args . MaskLayout , item ) ) ;
2023-10-24 06:20:03 -04:00
break ;
}
case 1 :
{
[mutable] Convert the following nodes to modifiers: EditMaterial, ExtendMaterial, RemoveMesh, RemoveMeshBlocks, MorphMaterial.
- Rename some existing modifier nodes to actually be prefixed "Modifier" instead of "Mesh".
- Added additional entry points for modifiers during code generation. Now there are 4: right after generating a mesh constant, right after all mesh operations have been generated, right after a texture block has been generated and right after a texture has been generated.
- Fix bug with mesh clip with UV mask when layout blocks were used.
- For legacy data conversion autogenerated tags are created and assigned to the material nodes and the new modifier nodes.
- MorphMaterial code generation has been redesigned passing all morphs to the MutableTools layer.
#jira UE-221279
#jira UE-221278
#rnx
[REVIEW] [at]genis.sole, [at]gerard.martin, [at]pere.rifa
#rb genis.sole, gerard.martin, pere.rifa
[CL 35952198 by jordi rovira in ue5-main branch]
2024-09-02 04:15:31 -04:00
MUTABLE_CPUPROFILER_SCOPE ( ME_MASKCLIPUVMASK_1 ) ;
2023-10-24 06:20:03 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( args . Source , item ) ) ;
[mutable] Convert the following nodes to modifiers: EditMaterial, ExtendMaterial, RemoveMesh, RemoveMeshBlocks, MorphMaterial.
- Rename some existing modifier nodes to actually be prefixed "Modifier" instead of "Mesh".
- Added additional entry points for modifiers during code generation. Now there are 4: right after generating a mesh constant, right after all mesh operations have been generated, right after a texture block has been generated and right after a texture has been generated.
- Fix bug with mesh clip with UV mask when layout blocks were used.
- For legacy data conversion autogenerated tags are created and assigned to the material nodes and the new modifier nodes.
- MorphMaterial code generation has been redesigned passing all morphs to the MutableTools layer.
#jira UE-221279
#jira UE-221278
#rnx
[REVIEW] [at]genis.sole, [at]gerard.martin, [at]pere.rifa
#rb genis.sole, gerard.martin, pere.rifa
[CL 35952198 by jordi rovira in ue5-main branch]
2024-09-02 04:15:31 -04:00
Ptr < const Mesh > UVSource = LoadMesh ( FCacheAddress ( args . UVSource , item ) ) ;
Ptr < const Image > MaskImage = LoadImage ( FCacheAddress ( args . MaskImage , item ) ) ;
Ptr < const Layout > MaskLayout = LoadLayout ( FCacheAddress ( args . MaskLayout , item ) ) ;
2023-10-24 06:20:03 -04:00
// Only if both are valid.
[mutable] Convert the following nodes to modifiers: EditMaterial, ExtendMaterial, RemoveMesh, RemoveMeshBlocks, MorphMaterial.
- Rename some existing modifier nodes to actually be prefixed "Modifier" instead of "Mesh".
- Added additional entry points for modifiers during code generation. Now there are 4: right after generating a mesh constant, right after all mesh operations have been generated, right after a texture block has been generated and right after a texture has been generated.
- Fix bug with mesh clip with UV mask when layout blocks were used.
- For legacy data conversion autogenerated tags are created and assigned to the material nodes and the new modifier nodes.
- MorphMaterial code generation has been redesigned passing all morphs to the MutableTools layer.
#jira UE-221279
#jira UE-221278
#rnx
[REVIEW] [at]genis.sole, [at]gerard.martin, [at]pere.rifa
#rb genis.sole, gerard.martin, pere.rifa
[CL 35952198 by jordi rovira in ue5-main branch]
2024-09-02 04:15:31 -04:00
if ( Source . get ( ) & & MaskImage . get ( ) )
2023-10-24 06:20:03 -04:00
{
Ptr < Mesh > Result = CreateMesh ( ) ;
bool bOutSuccess = false ;
[mutable] Convert the following nodes to modifiers: EditMaterial, ExtendMaterial, RemoveMesh, RemoveMeshBlocks, MorphMaterial.
- Rename some existing modifier nodes to actually be prefixed "Modifier" instead of "Mesh".
- Added additional entry points for modifiers during code generation. Now there are 4: right after generating a mesh constant, right after all mesh operations have been generated, right after a texture block has been generated and right after a texture has been generated.
- Fix bug with mesh clip with UV mask when layout blocks were used.
- For legacy data conversion autogenerated tags are created and assigned to the material nodes and the new modifier nodes.
- MorphMaterial code generation has been redesigned passing all morphs to the MutableTools layer.
#jira UE-221279
#jira UE-221278
#rnx
[REVIEW] [at]genis.sole, [at]gerard.martin, [at]pere.rifa
#rb genis.sole, gerard.martin, pere.rifa
[CL 35952198 by jordi rovira in ue5-main branch]
2024-09-02 04:15:31 -04:00
MakeMeshMaskFromUVMask ( Result . get ( ) , Source . get ( ) , UVSource . get ( ) , MaskImage . get ( ) , args . LayoutIndex , bOutSuccess ) ;
2023-10-24 06:20:03 -04:00
Release ( Source ) ;
[mutable] Convert the following nodes to modifiers: EditMaterial, ExtendMaterial, RemoveMesh, RemoveMeshBlocks, MorphMaterial.
- Rename some existing modifier nodes to actually be prefixed "Modifier" instead of "Mesh".
- Added additional entry points for modifiers during code generation. Now there are 4: right after generating a mesh constant, right after all mesh operations have been generated, right after a texture block has been generated and right after a texture has been generated.
- Fix bug with mesh clip with UV mask when layout blocks were used.
- For legacy data conversion autogenerated tags are created and assigned to the material nodes and the new modifier nodes.
- MorphMaterial code generation has been redesigned passing all morphs to the MutableTools layer.
#jira UE-221279
#jira UE-221278
#rnx
[REVIEW] [at]genis.sole, [at]gerard.martin, [at]pere.rifa
#rb genis.sole, gerard.martin, pere.rifa
[CL 35952198 by jordi rovira in ue5-main branch]
2024-09-02 04:15:31 -04:00
Release ( UVSource ) ;
Release ( MaskImage ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , nullptr ) ;
}
else
{
StoreMesh ( item , Result ) ;
}
}
else if ( Source . get ( ) & & MaskLayout . get ( ) )
{
Ptr < Mesh > Result = CreateMesh ( ) ;
bool bOutSuccess = false ;
MakeMeshMaskFromLayout ( Result . get ( ) , Source . get ( ) , UVSource . get ( ) , MaskLayout . get ( ) , args . LayoutIndex , bOutSuccess ) ;
Release ( Source ) ;
Release ( UVSource ) ;
Release ( MaskImage ) ;
2023-10-24 06:20:03 -04:00
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , nullptr ) ;
}
else
{
StoreMesh ( item , Result ) ;
}
}
else
{
Release ( Source ) ;
[mutable] Convert the following nodes to modifiers: EditMaterial, ExtendMaterial, RemoveMesh, RemoveMeshBlocks, MorphMaterial.
- Rename some existing modifier nodes to actually be prefixed "Modifier" instead of "Mesh".
- Added additional entry points for modifiers during code generation. Now there are 4: right after generating a mesh constant, right after all mesh operations have been generated, right after a texture block has been generated and right after a texture has been generated.
- Fix bug with mesh clip with UV mask when layout blocks were used.
- For legacy data conversion autogenerated tags are created and assigned to the material nodes and the new modifier nodes.
- MorphMaterial code generation has been redesigned passing all morphs to the MutableTools layer.
#jira UE-221279
#jira UE-221278
#rnx
[REVIEW] [at]genis.sole, [at]gerard.martin, [at]pere.rifa
#rb genis.sole, gerard.martin, pere.rifa
[CL 35952198 by jordi rovira in ue5-main branch]
2024-09-02 04:15:31 -04:00
Release ( UVSource ) ;
Release ( MaskImage ) ;
2023-10-24 06:20:03 -04:00
StoreMesh ( item , nullptr ) ;
}
break ;
}
default :
check ( false ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case OP_TYPE : : ME_MASKDIFF :
{
2023-12-19 05:19:14 -05:00
OP : : MeshMaskDiffArgs args = Program . GetOpArgs < OP : : MeshMaskDiffArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . source , item ) ,
FScheduledOp ( args . fragment , item ) ) ;
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_MASKDIFF_1 )
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( args . source , item ) ) ;
Ptr < const Mesh > pClip = LoadMesh ( FCacheAddress ( args . fragment , item ) ) ;
2022-09-26 15:12:13 -04:00
// Only if both are valid.
2023-05-24 02:50:03 -04:00
if ( Source . get ( ) & & pClip . get ( ) )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( ) ;
bool bOutSuccess = false ;
MeshMaskDiff ( Result . get ( ) , Source . get ( ) , pClip . get ( ) , bOutSuccess ) ;
Release ( Source ) ;
Release ( pClip ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , nullptr ) ;
}
else
{
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
2023-06-15 04:45:22 -04:00
else
{
Release ( Source ) ;
Release ( pClip ) ;
StoreMesh ( item , nullptr ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_FORMAT :
{
2023-12-19 05:19:14 -05:00
OP : : MeshFormatArgs args = Program . GetOpArgs < OP : : MeshFormatArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
if ( args . source & & args . format )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . source , item ) ,
FScheduledOp ( args . format , item ) ) ;
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_FORMAT_1 )
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( args . source , item ) ) ;
2024-04-03 05:35:18 -04:00
Ptr < const Mesh > Format = LoadMesh ( FCacheAddress ( args . format , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-05-14 07:28:21 -04:00
if ( Source & & Source - > IsReference ( ) )
{
Release ( Format ) ;
StoreMesh ( item , Source ) ;
}
else if ( Source )
2023-06-15 04:45:22 -04:00
{
2024-04-03 05:35:18 -04:00
uint8 Flags = args . Flags ;
if ( ! Format & & ! ( Flags & OP : : MeshFormatArgs : : ResetBufferIndices ) )
2023-06-15 04:45:22 -04:00
{
StoreMesh ( item , Source ) ;
}
2024-04-03 05:35:18 -04:00
else if ( ! Format )
2023-06-15 04:45:22 -04:00
{
Ptr < Mesh > Result = CloneOrTakeOver ( Source ) ;
2022-09-26 15:12:13 -04:00
2024-04-03 05:35:18 -04:00
if ( Flags & OP : : MeshFormatArgs : : ResetBufferIndices )
2023-06-15 04:45:22 -04:00
{
Result - > ResetBufferIndices ( ) ;
}
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
StoreMesh ( item , Result ) ;
}
else
{
Ptr < Mesh > Result = CreateMesh ( ) ;
bool bOutSuccess = false ;
2024-04-03 05:35:18 -04:00
MeshFormat ( Result . get ( ) , Source . get ( ) , Format . get ( ) ,
2023-06-15 04:45:22 -04:00
true ,
2024-04-03 05:35:18 -04:00
( Flags & OP : : MeshFormatArgs : : Vertex ) ! = 0 ,
( Flags & OP : : MeshFormatArgs : : Index ) ! = 0 ,
( Flags & OP : : MeshFormatArgs : : IgnoreMissing ) ! = 0 ,
2023-06-15 04:45:22 -04:00
bOutSuccess ) ;
check ( bOutSuccess ) ;
2024-04-03 05:35:18 -04:00
if ( Flags & OP : : MeshFormatArgs : : ResetBufferIndices )
2023-06-15 04:45:22 -04:00
{
Result - > ResetBufferIndices ( ) ;
}
2024-04-03 05:35:18 -04:00
if ( Flags & OP : : MeshFormatArgs : : OptimizeBuffers )
{
MUTABLE_CPUPROFILER_SCOPE ( MeshOptimizeBuffers )
MeshOptimizeBuffers ( Result . get ( ) ) ;
}
2023-06-15 04:45:22 -04:00
Release ( Source ) ;
2024-04-03 05:35:18 -04:00
Release ( Format ) ;
2023-06-15 04:45:22 -04:00
StoreMesh ( item , Result ) ;
}
}
else
{
2024-04-03 05:35:18 -04:00
Release ( Format ) ;
2023-06-15 04:45:22 -04:00
StoreMesh ( item , nullptr ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_EXTRACTLAYOUTBLOCK :
{
2023-12-19 05:19:14 -05:00
const uint8 * data = Program . GetOpArgsPointer ( item . At ) ;
2022-09-26 15:12:13 -04:00
2023-01-11 14:28:53 -05:00
OP : : ADDRESS source ;
FMemory : : Memcpy ( & source , data , sizeof ( OP : : ADDRESS ) ) ;
2022-09-26 15:12:13 -04:00
data + = sizeof ( OP : : ADDRESS ) ;
2022-10-06 20:10:22 -04:00
uint16 layout ;
2023-01-11 14:28:53 -05:00
FMemory : : Memcpy ( & layout , data , sizeof ( uint16 ) ) ;
2022-10-06 20:10:22 -04:00
data + = sizeof ( uint16 ) ;
2022-09-26 15:12:13 -04:00
2022-10-06 20:10:22 -04:00
uint16 blockCount ;
2023-01-11 14:28:53 -05:00
FMemory : : Memcpy ( & blockCount , data , sizeof ( uint16 ) ) ;
2022-10-06 20:10:22 -04:00
data + = sizeof ( uint16 ) ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
if ( source )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( source , item ) ) ;
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_EXTRACTLAYOUTBLOCK_1 )
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( source , item ) ) ;
2024-08-05 03:50:33 -04:00
// Access with memcpy necessary for unaligned memory access issues.
2024-05-13 03:20:24 -04:00
uint64 blocks [ 512 ] ;
check ( blockCount < 512 ) ;
FMemory : : Memcpy ( blocks , data , sizeof ( uint64 ) * FMath : : Min ( 512 , int32 ( blockCount ) ) ) ;
2022-09-26 15:12:13 -04:00
2023-06-09 03:22:13 -04:00
if ( Source )
{
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( ) ;
bool bOutSuccess ;
2024-08-05 03:50:33 -04:00
if ( blockCount > 0 )
{
MeshExtractLayoutBlock ( Result . get ( ) , Source . get ( ) , layout , blockCount , blocks , bOutSuccess ) ;
}
else
{
MeshExtractLayoutBlock ( Result . get ( ) , Source . get ( ) , layout , bOutSuccess ) ;
}
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , Source ) ;
}
else
{
Release ( Source ) ;
StoreMesh ( item , Result ) ;
}
}
else
{
StoreMesh ( item , nullptr ) ;
2023-06-09 03:22:13 -04:00
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_TRANSFORM :
{
2023-12-19 05:19:14 -05:00
OP : : MeshTransformArgs args = Program . GetOpArgs < OP : : MeshTransformArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
if ( args . source )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . source , item ) ) ;
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_TRANSFORM_1 )
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-03-18 04:26:21 -04:00
const FMatrix44f & mat = Program . m_constantMatrices [ args . matrix ] ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( Source ? Source - > GetDataSize ( ) : 0 ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
bool bOutSuccess = false ;
2024-03-18 04:26:21 -04:00
MeshTransform ( Result . get ( ) , Source . get ( ) , mat , bOutSuccess ) ;
2023-06-15 04:45:22 -04:00
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , Source ) ;
}
else
{
Release ( Source ) ;
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_CLIPMORPHPLANE :
{
2023-12-19 05:19:14 -05:00
OP : : MeshClipMorphPlaneArgs args = Program . GetOpArgs < OP : : MeshClipMorphPlaneArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
if ( args . source )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
2024-08-13 10:23:49 -04:00
FScheduledOp ( args . source , item ) ) ;
2023-06-15 04:45:22 -04:00
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_CLIPMORPHPLANE_1 )
2024-08-13 10:23:49 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
check ( args . morphShape < ( uint32 ) pModel - > GetPrivate ( ) - > m_program . m_constantShapes . Num ( ) ) ;
2022-09-26 15:12:13 -04:00
// Should be an ellipse
2023-12-19 05:19:14 -05:00
const FShape & morphShape = Program . m_constantShapes [ args . morphShape ] ;
2022-09-26 15:12:13 -04:00
2024-03-18 04:26:21 -04:00
const FVector3f & origin = morphShape . position ;
const FVector3f & normal = morphShape . up ;
2022-09-26 15:12:13 -04:00
2024-09-16 03:38:54 -04:00
bool bRemoveFaceIfAllVerticesCulled = args . FaceCullStrategy = = EFaceCullStrategy : : AllVerticesCulled ;
if ( args . VertexSelectionType = = EClipVertexSelectionType : : Shape )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
check ( args . vertexSelectionShapeOrBone < ( uint32 ) pModel - > GetPrivate ( ) - > m_program . m_constantShapes . Num ( ) ) ;
2022-09-26 15:12:13 -04:00
// Should be None or an axis aligned box
2023-12-19 05:19:14 -05:00
const FShape & selectionShape = Program . m_constantShapes [ args . vertexSelectionShapeOrBone ] ;
2023-06-15 04:45:22 -04:00
2023-06-15 11:38:34 -04:00
Ptr < Mesh > Result = CreateMesh ( Source ? Source - > GetDataSize ( ) : 0 ) ;
2023-06-15 04:45:22 -04:00
bool bOutSuccess = false ;
2024-09-16 03:38:54 -04:00
MeshClipMorphPlane ( Result . get ( ) , Source . get ( ) , origin , normal , args . dist , args . factor , morphShape . size [ 0 ] , morphShape . size [ 1 ] , morphShape . size [ 2 ] , selectionShape , bRemoveFaceIfAllVerticesCulled , bOutSuccess , nullptr , - 1 ) ;
2023-06-15 04:45:22 -04:00
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , Source ) ;
}
else
{
Release ( Source ) ;
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
2024-09-16 03:38:54 -04:00
else if ( args . VertexSelectionType = = EClipVertexSelectionType : : BoneHierarchy )
2023-06-15 04:45:22 -04:00
{
FShape selectionShape ;
selectionShape . type = ( uint8 ) FShape : : Type : : None ;
Ptr < Mesh > Result = CreateMesh ( Source - > GetDataSize ( ) ) ;
2024-04-10 06:42:45 -04:00
check ( args . vertexSelectionShapeOrBone < = MAX_uint32 ) ;
const FBoneName Bone ( args . vertexSelectionShapeOrBone ) ;
2023-06-15 04:45:22 -04:00
bool bOutSuccess = false ;
2024-09-16 03:38:54 -04:00
MeshClipMorphPlane ( Result . get ( ) , Source . get ( ) , origin , normal , args . dist , args . factor , morphShape . size [ 0 ] , morphShape . size [ 1 ] , morphShape . size [ 2 ] , selectionShape , bRemoveFaceIfAllVerticesCulled , bOutSuccess , & Bone , args . maxBoneRadius ) ;
2023-06-15 04:45:22 -04:00
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , Source ) ;
}
else
{
Release ( Source ) ;
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
else
{
// No vertex selection
2022-10-26 13:00:52 -04:00
FShape selectionShape ;
selectionShape . type = ( uint8 ) FShape : : Type : : None ;
2023-06-15 04:45:22 -04:00
2023-06-15 11:38:34 -04:00
Ptr < Mesh > Result = CreateMesh ( Source ? Source - > GetDataSize ( ) : 0 ) ;
2023-06-15 04:45:22 -04:00
bool bOutSuccess = false ;
2024-09-16 03:38:54 -04:00
MeshClipMorphPlane ( Result . get ( ) , Source . get ( ) , origin , normal , args . dist , args . factor , morphShape . size [ 0 ] , morphShape . size [ 1 ] , morphShape . size [ 2 ] , selectionShape , bRemoveFaceIfAllVerticesCulled , bOutSuccess , nullptr , - 1.0f ) ;
2023-06-15 04:45:22 -04:00
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , Source ) ;
}
else
{
Release ( Source ) ;
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_CLIPWITHMESH :
{
2023-12-19 05:19:14 -05:00
OP : : MeshClipWithMeshArgs args = Program . GetOpArgs < OP : : MeshClipWithMeshArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
if ( args . source )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . source , item ) ,
FScheduledOp ( args . clipMesh , item ) ) ;
}
else
{
StoreMesh ( item , nullptr ) ;
}
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_CLIPWITHMESH_1 )
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( args . source , item ) ) ;
Ptr < const Mesh > pClip = LoadMesh ( FCacheAddress ( args . clipMesh , item ) ) ;
2022-09-26 15:12:13 -04:00
// Only if both are valid.
2023-05-24 02:50:03 -04:00
if ( Source & & pClip )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( Source - > GetDataSize ( ) ) ;
bool bOutSuccess = false ;
MeshClipWithMesh ( Result . get ( ) , Source . get ( ) , pClip . get ( ) , bOutSuccess ) ;
Release ( pClip ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , Source ) ;
}
else
{
Release ( Source ) ;
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
2023-06-15 04:45:22 -04:00
else
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Release ( pClip ) ;
StoreMesh ( item , Source ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_CLIPDEFORM :
{
2023-12-19 05:19:14 -05:00
OP : : MeshClipDeformArgs args = Program . GetOpArgs < OP : : MeshClipDeformArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
2022-09-26 15:12:13 -04:00
if ( args . mesh )
{
2023-06-15 04:45:22 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . mesh , item ) ,
FScheduledOp ( args . clipShape , item ) ) ;
}
else
{
2023-05-24 02:50:03 -04:00
StoreMesh ( item , nullptr ) ;
2022-09-26 15:12:13 -04:00
}
break ;
2023-06-15 04:45:22 -04:00
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_CLIPDEFORM_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Mesh > BaseMesh = LoadMesh ( FCacheAddress ( args . mesh , item ) ) ;
Ptr < const Mesh > ClipShape = LoadMesh ( FCacheAddress ( args . clipShape , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
if ( BaseMesh & & ClipShape )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( BaseMesh - > GetDataSize ( ) ) ;
2024-09-16 03:38:54 -04:00
bool bRemoveIfAllVerticesCulled = args . FaceCullStrategy = = EFaceCullStrategy : : AllVerticesCulled ;
2023-06-15 04:45:22 -04:00
bool bOutSuccess = false ;
2024-09-16 03:38:54 -04:00
MeshClipDeform ( Result . get ( ) , BaseMesh . get ( ) , ClipShape . get ( ) , args . clipWeightThreshold , bRemoveIfAllVerticesCulled , bOutSuccess ) ;
2023-06-15 04:45:22 -04:00
Release ( ClipShape ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , BaseMesh ) ;
}
else
{
Release ( BaseMesh ) ;
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
2023-06-15 04:45:22 -04:00
else
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Release ( ClipShape ) ;
StoreMesh ( item , BaseMesh ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_APPLYPOSE :
{
2023-12-19 05:19:14 -05:00
OP : : MeshApplyPoseArgs args = Program . GetOpArgs < OP : : MeshApplyPoseArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
if ( args . base )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . base , item ) ,
2024-08-13 10:23:49 -04:00
FScheduledOp ( args . pose , item ) ) ;
2023-06-15 04:45:22 -04:00
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_APPLYPOSE_1 )
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > pBase = LoadMesh ( FCacheAddress ( args . base , item ) ) ;
2024-08-13 10:23:49 -04:00
Ptr < const Mesh > pPose = LoadMesh ( FCacheAddress ( args . pose , item ) ) ;
2022-09-26 15:12:13 -04:00
// Only if both are valid.
if ( pBase & & pPose )
{
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( pBase - > GetSkeleton ( ) ? pBase - > GetDataSize ( ) : 0 ) ;
bool bOutSuccess = false ;
MeshApplyPose ( Result . get ( ) , pBase . get ( ) , pPose . get ( ) , bOutSuccess ) ;
Release ( pPose ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , pBase ) ;
}
else
{
Release ( pBase ) ;
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
2023-06-15 04:45:22 -04:00
else
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Release ( pPose ) ;
StoreMesh ( item , pBase ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_GEOMETRYOPERATION :
{
2023-12-19 05:19:14 -05:00
OP : : MeshGeometryOperationArgs args = Program . GetOpArgs < OP : : MeshGeometryOperationArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
2022-09-26 15:12:13 -04:00
if ( args . meshA )
{
2023-06-15 04:45:22 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . meshA , item ) ,
FScheduledOp ( args . meshB , item ) ,
2024-08-13 10:23:49 -04:00
FScheduledOp ( args . scalarA , item ) ,
FScheduledOp ( args . scalarB , item ) ) ;
2023-06-15 04:45:22 -04:00
}
else
{
2023-05-24 02:50:03 -04:00
StoreMesh ( item , nullptr ) ;
2022-09-26 15:12:13 -04:00
}
break ;
2023-06-15 04:45:22 -04:00
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_GEOMETRYOPERATION_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Mesh > MeshA = LoadMesh ( FCacheAddress ( args . meshA , item ) ) ;
Ptr < const Mesh > MeshB = LoadMesh ( FCacheAddress ( args . meshB , item ) ) ;
2024-08-13 10:23:49 -04:00
float ScalarA = LoadScalar ( FCacheAddress ( args . scalarA , item ) ) ;
float ScalarB = LoadScalar ( FCacheAddress ( args . scalarB , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 11:38:34 -04:00
Ptr < Mesh > Result = CreateMesh ( MeshA ? MeshA - > GetDataSize ( ) : 0 ) ;
2023-06-15 04:45:22 -04:00
bool bOutSuccess = false ;
MeshGeometryOperation ( Result . get ( ) , MeshA . get ( ) , MeshB . get ( ) , ScalarA , ScalarB , bOutSuccess ) ;
Release ( MeshA ) ;
Release ( MeshB ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , nullptr ) ;
}
else
{
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_BINDSHAPE :
{
2023-12-19 05:19:14 -05:00
OP : : MeshBindShapeArgs Args = Program . GetOpArgs < OP : : MeshBindShapeArgs > ( item . At ) ;
const uint8 * Data = Program . GetOpArgsPointer ( item . At ) ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
2023-03-29 05:23:08 -04:00
if ( Args . mesh )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
2023-06-15 04:45:22 -04:00
FScheduledOp ( Args . mesh , item ) ,
FScheduledOp ( Args . shape , item ) ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2023-05-24 02:50:03 -04:00
StoreMesh ( item , nullptr ) ;
2022-09-26 15:12:13 -04:00
}
break ;
2023-06-15 04:45:22 -04:00
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_BINDSHAPE_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Mesh > BaseMesh = LoadMesh ( FCacheAddress ( Args . mesh , item ) ) ;
Ptr < const Mesh > Shape = LoadMesh ( FCacheAddress ( Args . shape , item ) ) ;
2023-01-25 04:08:49 -05:00
2023-03-29 05:23:08 -04:00
EShapeBindingMethod BindingMethod = static_cast < EShapeBindingMethod > ( Args . bindingMethod ) ;
2022-09-26 15:12:13 -04:00
if ( BindingMethod = = EShapeBindingMethod : : ReshapeClosestProject )
{
// Bones are stored after the args
2023-03-29 05:23:08 -04:00
Data + = sizeof ( Args ) ;
2022-09-26 15:12:13 -04:00
// Rebuilding array of bone names ----
int32 NumBones ;
2023-03-29 05:23:08 -04:00
FMemory : : Memcpy ( & NumBones , Data , sizeof ( int32 ) ) ;
Data + = sizeof ( int32 ) ;
2022-09-26 15:12:13 -04:00
2024-04-10 06:42:45 -04:00
TArray < FBoneName > BonesToDeform ;
2023-06-28 07:02:00 -04:00
BonesToDeform . SetNumUninitialized ( NumBones ) ;
2024-04-10 06:42:45 -04:00
FMemory : : Memcpy ( BonesToDeform . GetData ( ) , Data , NumBones * sizeof ( FBoneName ) ) ;
Data + = NumBones * sizeof ( FBoneName ) ;
2022-09-26 15:12:13 -04:00
int32 NumPhysicsBodies ;
2023-03-29 05:23:08 -04:00
FMemory : : Memcpy ( & NumPhysicsBodies , Data , sizeof ( int32 ) ) ;
Data + = sizeof ( int32 ) ;
2022-09-26 15:12:13 -04:00
2024-04-10 06:42:45 -04:00
TArray < FBoneName > PhysicsToDeform ;
2023-06-28 07:02:00 -04:00
PhysicsToDeform . SetNumUninitialized ( NumPhysicsBodies ) ;
2024-04-10 06:42:45 -04:00
FMemory : : Memcpy ( PhysicsToDeform . GetData ( ) , Data , NumPhysicsBodies * sizeof ( FBoneName ) ) ;
Data + = NumPhysicsBodies * sizeof ( FBoneName ) ;
2022-09-26 15:12:13 -04:00
2023-03-29 05:23:08 -04:00
const EMeshBindShapeFlags BindFlags = static_cast < EMeshBindShapeFlags > ( Args . flags ) ;
2023-08-02 05:11:59 -04:00
FMeshBindColorChannelUsages ColorChannelUsages ;
FMemory : : Memcpy ( & ColorChannelUsages , & Args . ColorUsage , sizeof ( ColorChannelUsages ) ) ;
static_assert ( sizeof ( ColorChannelUsages ) = = sizeof ( Args . ColorUsage ) ) ;
2023-06-15 04:45:22 -04:00
Ptr < Mesh > BindMeshResult = CreateMesh ( ) ;
bool bOutSuccess = false ;
2023-08-02 05:11:59 -04:00
MeshBindShapeReshape ( BindMeshResult . get ( ) , BaseMesh . get ( ) , Shape . get ( ) , BonesToDeform , PhysicsToDeform , BindFlags , ColorChannelUsages , bOutSuccess ) ;
2023-06-15 04:45:22 -04:00
Release ( Shape ) ;
// not success indicates nothing has bond so the base mesh can be reused.
if ( ! bOutSuccess )
2023-03-29 05:23:08 -04:00
{
2023-06-15 04:45:22 -04:00
Release ( BindMeshResult ) ;
StoreMesh ( item , BaseMesh ) ;
2023-03-29 05:23:08 -04:00
}
else
{
2023-06-15 04:45:22 -04:00
if ( ! EnumHasAnyFlags ( BindFlags , EMeshBindShapeFlags : : ReshapeVertices ) )
{
Ptr < Mesh > BindMeshNoVertsResult = CloneOrTakeOver ( BaseMesh ) ;
2023-09-18 04:39:21 -04:00
BindMeshNoVertsResult - > AdditionalBuffers = MoveTemp ( BindMeshResult - > AdditionalBuffers ) ;
2023-06-15 04:45:22 -04:00
Release ( BaseMesh ) ;
Release ( BindMeshResult ) ;
StoreMesh ( item , BindMeshNoVertsResult ) ;
}
else
{
Release ( BaseMesh ) ;
StoreMesh ( item , BindMeshResult ) ;
}
}
2022-09-26 15:12:13 -04:00
}
else
{
2023-06-15 11:38:34 -04:00
Ptr < Mesh > Result = CreateMesh ( BaseMesh ? BaseMesh - > GetDataSize ( ) : 0 ) ;
2023-06-15 04:45:22 -04:00
bool bOutSuccess = false ;
MeshBindShapeClipDeform ( Result . get ( ) , BaseMesh . get ( ) , Shape . get ( ) , BindingMethod , bOutSuccess ) ;
Release ( Shape ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , BaseMesh ) ;
}
else
{
Release ( BaseMesh ) ;
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_APPLYSHAPE :
{
2023-12-19 05:19:14 -05:00
OP : : MeshApplyShapeArgs args = Program . GetOpArgs < OP : : MeshApplyShapeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
2022-09-26 15:12:13 -04:00
if ( args . mesh )
{
2023-06-15 04:45:22 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . mesh , item ) ,
FScheduledOp ( args . shape , item ) ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2023-05-24 02:50:03 -04:00
StoreMesh ( item , nullptr ) ;
2022-09-26 15:12:13 -04:00
}
break ;
2023-06-15 04:45:22 -04:00
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_APPLYSHAPE_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Mesh > BaseMesh = LoadMesh ( FCacheAddress ( args . mesh , item ) ) ;
Ptr < const Mesh > Shape = LoadMesh ( FCacheAddress ( args . shape , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-03-29 05:23:08 -04:00
const EMeshBindShapeFlags ReshapeFlags = static_cast < EMeshBindShapeFlags > ( args . flags ) ;
const bool bReshapeVertices = EnumHasAnyFlags ( ReshapeFlags , EMeshBindShapeFlags : : ReshapeVertices ) ;
2023-06-15 11:38:34 -04:00
Ptr < Mesh > ReshapedMeshResult = CreateMesh ( BaseMesh ? BaseMesh - > GetDataSize ( ) : 0 ) ;
2023-03-29 05:23:08 -04:00
2023-06-15 04:45:22 -04:00
bool bOutSuccess = false ;
MeshApplyShape ( ReshapedMeshResult . get ( ) , BaseMesh . get ( ) , Shape . get ( ) , ReshapeFlags , bOutSuccess ) ;
Release ( Shape ) ;
if ( ! bOutSuccess )
{
Release ( ReshapedMeshResult ) ;
StoreMesh ( item , BaseMesh ) ;
2023-03-29 05:23:08 -04:00
}
else
{
2023-06-15 04:45:22 -04:00
if ( ! bReshapeVertices )
{
// Clone without Skeleton, Physics or Poses
EMeshCopyFlags CopyFlags = ~ (
EMeshCopyFlags : : WithSkeleton |
EMeshCopyFlags : : WithPhysicsBody |
EMeshCopyFlags : : WithAdditionalPhysics |
EMeshCopyFlags : : WithPoses ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
Ptr < Mesh > NoVerticesReshpedMesh = CloneOrTakeOver ( BaseMesh ) ;
NoVerticesReshpedMesh - > SetSkeleton ( ReshapedMeshResult - > GetSkeleton ( ) . get ( ) ) ;
NoVerticesReshpedMesh - > SetPhysicsBody ( ReshapedMeshResult - > GetPhysicsBody ( ) . get ( ) ) ;
NoVerticesReshpedMesh - > AdditionalPhysicsBodies = ReshapedMeshResult - > AdditionalPhysicsBodies ;
NoVerticesReshpedMesh - > BonePoses = ReshapedMeshResult - > BonePoses ;
Release ( BaseMesh ) ;
Release ( ReshapedMeshResult ) ;
StoreMesh ( item , NoVerticesReshpedMesh ) ;
}
else
{
Release ( BaseMesh ) ;
StoreMesh ( item , ReshapedMeshResult ) ;
}
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_MORPHRESHAPE :
{
2023-12-19 05:19:14 -05:00
OP : : MeshMorphReshapeArgs Args = Program . GetOpArgs < OP : : MeshMorphReshapeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
if ( Args . Morph )
{
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
2023-06-15 04:45:22 -04:00
FScheduledOp ( Args . Morph , item ) ,
FScheduledOp ( Args . Reshape , item ) ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2023-05-24 02:50:03 -04:00
StoreMesh ( item , nullptr ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_MORPHRESHAPE_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Mesh > MorphedMesh = LoadMesh ( FCacheAddress ( Args . Morph , item ) ) ;
Ptr < const Mesh > ReshapeMesh = LoadMesh ( FCacheAddress ( Args . Reshape , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 11:38:34 -04:00
if ( ReshapeMesh & & MorphedMesh )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
// Copy without Skeleton, Physics or Poses
EMeshCopyFlags CopyFlags = ~ (
EMeshCopyFlags : : WithSkeleton |
EMeshCopyFlags : : WithPhysicsBody |
EMeshCopyFlags : : WithPoses ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( MorphedMesh - > GetDataSize ( ) ) ;
Result - > CopyFrom ( * MorphedMesh , CopyFlags ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
Result - > SetSkeleton ( ReshapeMesh - > GetSkeleton ( ) . get ( ) ) ;
Result - > SetPhysicsBody ( ReshapeMesh - > GetPhysicsBody ( ) . get ( ) ) ;
Result - > BonePoses = ReshapeMesh - > BonePoses ;
Release ( MorphedMesh ) ;
Release ( ReshapeMesh ) ;
StoreMesh ( item , Result ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2023-06-15 04:45:22 -04:00
StoreMesh ( item , MorphedMesh ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_SETSKELETON :
{
2023-12-19 05:19:14 -05:00
OP : : MeshSetSkeletonArgs args = Program . GetOpArgs < OP : : MeshSetSkeletonArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
if ( args . source )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . source , item ) ,
2024-08-13 10:23:49 -04:00
FScheduledOp ( args . skeleton , item ) ) ;
2023-06-15 04:45:22 -04:00
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_SETSKELETON_1 )
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( args . source , item ) ) ;
2024-08-13 10:23:49 -04:00
Ptr < const Mesh > pSkeleton = LoadMesh ( FCacheAddress ( args . skeleton , item ) ) ;
2022-09-26 15:12:13 -04:00
// Only if both are valid.
2023-05-24 02:50:03 -04:00
if ( Source & & pSkeleton )
2022-09-26 15:12:13 -04:00
{
2024-08-13 10:23:49 -04:00
if ( Source - > GetSkeleton ( )
& &
Source - > GetSkeleton ( ) - > GetBoneCount ( ) > 0 )
2022-09-26 15:12:13 -04:00
{
// For some reason we already have bone data, so we can't just overwrite it
// or the skinning may break. This may happen because of a problem in the
// optimiser that needs investigation.
// \TODO Be defensive, for now.
2023-06-15 04:45:22 -04:00
UE_LOG ( LogMutableCore , Warning , TEXT ( " Performing a MeshRemapSkeleton, instead of MeshSetSkeletonData because source mesh already has some skeleton. " ) ) ;
Ptr < Mesh > Result = CreateMesh ( Source - > GetDataSize ( ) ) ;
bool bOutSuccess = false ;
MeshRemapSkeleton ( Result . get ( ) , Source . get ( ) , pSkeleton - > GetSkeleton ( ) . get ( ) , bOutSuccess ) ;
Release ( pSkeleton ) ;
if ( ! bOutSuccess )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Release ( Result ) ;
StoreMesh ( item , Source ) ;
2022-09-26 15:12:13 -04:00
}
2023-06-15 04:45:22 -04:00
else
{
//Result->GetPrivate()->CheckIntegrity();
Release ( Source ) ;
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
else
{
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CloneOrTakeOver ( Source ) ;
Result - > SetSkeleton ( pSkeleton - > GetSkeleton ( ) . get ( ) ) ;
//Result->GetPrivate()->CheckIntegrity();
Release ( pSkeleton ) ;
StoreMesh ( item , Result ) ;
2022-09-26 15:12:13 -04:00
}
}
2023-06-15 04:45:22 -04:00
else
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Release ( pSkeleton ) ;
StoreMesh ( item , Source ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : ME_REMOVEMASK :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_REMOVEMASK )
2022-09-26 15:12:13 -04:00
// Decode op
// TODO: Partial decode for each stage
2023-12-19 05:19:14 -05:00
const uint8 * data = Program . GetOpArgsPointer ( item . At ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS source ;
2023-06-15 04:45:22 -04:00
FMemory : : Memcpy ( & source , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
2022-09-26 15:12:13 -04:00
2024-09-16 03:38:54 -04:00
EFaceCullStrategy FaceCullStrategy ;
FMemory : : Memcpy ( & FaceCullStrategy , data , sizeof ( EFaceCullStrategy ) ) ;
data + = sizeof ( EFaceCullStrategy ) ;
2022-11-23 03:17:56 -05:00
TArray < FScheduledOp > conditions ;
2022-10-11 05:14:05 -04:00
TArray < OP : : ADDRESS > masks ;
2022-09-26 15:12:13 -04:00
2022-10-06 20:10:22 -04:00
uint16 removes ;
2023-06-15 04:45:22 -04:00
FMemory : : Memcpy ( & removes , data , sizeof ( uint16 ) ) ;
data + = sizeof ( uint16 ) ;
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
for ( uint16 r = 0 ; r < removes ; + + r )
2022-09-26 15:12:13 -04:00
{
OP : : ADDRESS condition ;
2023-06-15 04:45:22 -04:00
FMemory : : Memcpy ( & condition , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
2024-08-13 10:23:49 -04:00
conditions . Emplace ( condition , item ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS mask ;
2023-06-15 04:45:22 -04:00
FMemory : : Memcpy ( & mask , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
masks . Add ( mask ) ;
2022-09-26 15:12:13 -04:00
}
// Schedule next stages
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
if ( source )
{
// Request the conditions
AddOp ( FScheduledOp ( item . At , item , 1 ) , conditions ) ;
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_REMOVEMASK_1 )
2022-09-26 15:12:13 -04:00
// Request the source and the necessary masks
// \todo: store condition values in heap?
2022-11-23 03:17:56 -05:00
TArray < FScheduledOp > deps ;
2022-10-11 05:14:05 -04:00
deps . Emplace ( source , item ) ;
2024-08-13 10:23:49 -04:00
for ( size_t r = 0 ; source & & r < conditions . Num ( ) ; + + r )
2022-09-26 15:12:13 -04:00
{
// If there is no expression, we'll assume true.
bool value = true ;
2022-11-23 03:17:56 -05:00
if ( conditions [ r ] . At )
2022-09-26 15:12:13 -04:00
{
2024-08-13 10:23:49 -04:00
value = LoadBool ( FCacheAddress ( conditions [ r ] . At , item ) ) ;
2022-09-26 15:12:13 -04:00
}
if ( value )
{
2023-06-15 04:45:22 -04:00
deps . Emplace ( masks [ r ] , item ) ;
2022-09-26 15:12:13 -04:00
}
}
if ( source )
{
2023-06-15 04:45:22 -04:00
AddOp ( FScheduledOp ( item . At , item , 2 ) , deps ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
case 2 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_REMOVEMASK_2 )
2022-09-26 15:12:13 -04:00
// \todo: single remove operation with all masks?
2023-06-15 04:45:22 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( source , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
if ( Source )
{
Ptr < Mesh > Result = CreateMesh ( Source - > GetDataSize ( ) ) ;
Result - > CopyFrom ( * Source ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
Release ( Source ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
for ( int32 r = 0 ; r < conditions . Num ( ) ; + + r )
{
// If there is no expression, we'll assume true.
bool value = true ;
if ( conditions [ r ] . At )
{
2024-08-13 10:23:49 -04:00
value = LoadBool ( FCacheAddress ( conditions [ r ] . At , item ) ) ;
2023-06-15 04:45:22 -04:00
}
if ( value )
{
Ptr < const Mesh > Mask = LoadMesh ( FCacheAddress ( masks [ r ] , item ) ) ;
if ( Mask )
{
//MeshRemoveMask will make a copy of Result, try to make room for it.
Ptr < Mesh > IterResult = CreateMesh ( Result - > GetDataSize ( ) ) ;
bool bOutSuccess = false ;
2024-09-16 03:38:54 -04:00
bool bRemoveIfAllVerticesCulled = FaceCullStrategy = = EFaceCullStrategy : : AllVerticesCulled ;
MeshRemoveMask ( IterResult . get ( ) , Result . get ( ) , Mask . get ( ) , bRemoveIfAllVerticesCulled , bOutSuccess ) ;
2023-06-15 04:45:22 -04:00
Release ( Mask ) ;
if ( ! bOutSuccess )
{
Release ( IterResult ) ;
}
else
{
Swap ( Result , IterResult ) ;
Release ( IterResult ) ;
}
}
}
}
StoreMesh ( item , Result ) ;
}
else
{
StoreMesh ( item , nullptr ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2023-12-01 04:46:27 -05:00
case OP_TYPE : : ME_ADDTAGS :
{
MUTABLE_CPUPROFILER_SCOPE ( ME_ADDTAGS )
// Decode op
// TODO: Partial decode for each stage
2023-12-19 05:19:14 -05:00
const uint8 * Data = Program . GetOpArgsPointer ( item . At ) ;
2023-12-01 04:46:27 -05:00
OP : : ADDRESS Source ;
FMemory : : Memcpy ( & Source , Data , sizeof ( OP : : ADDRESS ) ) ;
Data + = sizeof ( OP : : ADDRESS ) ;
// Schedule next stages
switch ( item . Stage )
{
case 0 :
{
if ( Source )
{
// Request the source
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( Source , item ) ) ;
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
case 1 :
{
MUTABLE_CPUPROFILER_SCOPE ( ME_ADDTAGS_2 )
Ptr < const Mesh > SourceMesh = LoadMesh ( FCacheAddress ( Source , item ) ) ;
2024-08-13 10:23:49 -04:00
if ( ! SourceMesh )
2023-12-01 04:46:27 -05:00
{
2024-08-13 10:23:49 -04:00
StoreMesh ( item , nullptr ) ;
2023-12-01 04:46:27 -05:00
}
else
{
Ptr < Mesh > Result = CloneOrTakeOver ( SourceMesh ) ;
2024-08-13 10:23:49 -04:00
// Decode the tags
uint16 TagCount ;
2023-12-01 04:46:27 -05:00
FMemory : : Memcpy ( & TagCount , Data , sizeof ( uint16 ) ) ;
Data + = sizeof ( uint16 ) ;
2024-04-29 03:42:15 -04:00
int32 FirstMeshTagIndex = Result - > Tags . Num ( ) ;
Result - > Tags . SetNum ( FirstMeshTagIndex + TagCount ) ;
2023-12-01 04:46:27 -05:00
for ( uint16 TagIndex = 0 ; TagIndex < TagCount ; + + TagIndex )
{
OP : : ADDRESS TagConstant ;
FMemory : : Memcpy ( & TagConstant , Data , sizeof ( OP : : ADDRESS ) ) ;
Data + = sizeof ( OP : : ADDRESS ) ;
check ( TagConstant < ( uint32 ) pModel - > GetPrivate ( ) - > m_program . m_constantStrings . Num ( ) ) ;
2023-12-19 05:19:14 -05:00
const FString & Name = Program . m_constantStrings [ TagConstant ] ;
2024-04-29 03:42:15 -04:00
Result - > Tags [ FirstMeshTagIndex + TagIndex ] = Name ;
2023-12-01 04:46:27 -05:00
}
2024-08-13 10:23:49 -04:00
2023-12-01 04:46:27 -05:00
StoreMesh ( item , Result ) ;
}
break ;
}
default :
check ( false ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case OP_TYPE : : ME_PROJECT :
{
2023-12-19 05:19:14 -05:00
OP : : MeshProjectArgs args = Program . GetOpArgs < OP : : MeshProjectArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-06-15 04:45:22 -04:00
{
if ( args . mesh )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . mesh , item ) ,
2024-08-13 10:23:49 -04:00
FScheduledOp ( args . projector , item ) ) ;
2023-06-15 04:45:22 -04:00
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_PROJECT_1 )
2024-08-13 10:23:49 -04:00
Ptr < const Mesh > pMesh = LoadMesh ( FCacheAddress ( args . mesh , item ) ) ;
const FProjector Projector = LoadProjector ( FCacheAddress ( args . projector , item ) ) ;
2022-09-26 15:12:13 -04:00
// Only if both are valid.
2023-06-15 04:45:22 -04:00
if ( pMesh & & pMesh - > GetVertexBuffers ( ) . GetBufferCount ( ) > 0 )
2022-09-26 15:12:13 -04:00
{
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( ) ;
bool bOutSuccess = false ;
MeshProject ( Result . get ( ) , pMesh . get ( ) , Projector , bOutSuccess ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , pMesh ) ;
}
else
{
// Result->GetPrivate()->CheckIntegrity();
Release ( pMesh ) ;
StoreMesh ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
}
2023-06-15 04:45:22 -04:00
else
{
Release ( pMesh ) ;
StoreMesh ( item , nullptr ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2023-01-04 15:46:42 -05:00
case OP_TYPE : : ME_OPTIMIZESKINNING :
{
2023-12-19 05:19:14 -05:00
OP : : MeshOptimizeSkinningArgs args = Program . GetOpArgs < OP : : MeshOptimizeSkinningArgs > ( item . At ) ;
2023-01-04 15:46:42 -05:00
switch ( item . Stage )
{
case 0 :
2023-06-15 04:45:22 -04:00
{
2023-01-04 15:46:42 -05:00
if ( args . source )
{
2023-01-11 14:28:53 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2023-01-04 15:46:42 -05:00
}
else
{
2023-05-24 02:50:03 -04:00
StoreMesh ( item , nullptr ) ;
2023-01-04 15:46:42 -05:00
}
break ;
2023-06-15 04:45:22 -04:00
}
2023-01-04 15:46:42 -05:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( ME_OPTIMIZESKINNING_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Mesh > Source = LoadMesh ( FCacheAddress ( args . source , item ) ) ;
2023-01-04 15:46:42 -05:00
2024-05-14 07:28:21 -04:00
if ( Source & & Source - > IsReference ( ) )
{
StoreMesh ( item , Source ) ;
}
2023-06-15 04:45:22 -04:00
Ptr < Mesh > Result = CreateMesh ( ) ;
bool bOutSuccess = false ;
MeshOptimizeSkinning ( Result . get ( ) , Source . get ( ) , bOutSuccess ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , Source ) ;
}
else
{
Release ( Source ) ;
StoreMesh ( item , Result ) ;
}
2023-01-04 15:46:42 -05:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2024-10-01 19:09:05 -04:00
case OP_TYPE : : ME_TRANSFORMWITHMESH :
{
OP : : MeshTransformWithinMeshArgs args = Program . GetOpArgs < OP : : MeshTransformWithinMeshArgs > ( item . At ) ;
switch ( item . Stage )
{
case 0 :
{
if ( args . sourceMesh )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . sourceMesh , item ) ,
FScheduledOp ( args . boundingMesh , item ) ,
FScheduledOp ( args . matrix , item ) ) ;
}
else
{
StoreMesh ( item , nullptr ) ;
}
break ;
}
case 1 :
{
MUTABLE_CPUPROFILER_SCOPE ( ME_TRANSFORMWITHMESH_1 )
Ptr < const Mesh > SourceMesh = LoadMesh ( FCacheAddress ( args . sourceMesh , item ) ) ;
Ptr < const Mesh > BoundingMesh = LoadMesh ( FCacheAddress ( args . boundingMesh , item ) ) ;
const FMatrix44f & Transform = LoadMatrix ( FCacheAddress ( args . matrix , item ) ) ;
if ( SourceMesh )
{
Ptr < Mesh > Result = CreateMesh ( SourceMesh - > GetDataSize ( ) ) ;
bool bOutSuccess = false ;
MeshTransformWithMesh ( Result . get ( ) , SourceMesh . get ( ) , BoundingMesh . get ( ) , Transform , bOutSuccess ) ;
Release ( BoundingMesh ) ;
if ( ! bOutSuccess )
{
Release ( Result ) ;
StoreMesh ( item , SourceMesh ) ;
}
else
{
Release ( SourceMesh ) ;
StoreMesh ( item , Result ) ;
}
}
else
{
Release ( BoundingMesh ) ;
StoreMesh ( item , SourceMesh ) ;
}
break ;
}
default :
check ( false ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
default :
2024-08-13 10:23:49 -04:00
if ( type ! = OP_TYPE : : NONE )
2022-09-26 15:12:13 -04:00
{
// Operation not implemented
2024-08-13 10:23:49 -04:00
check ( false ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
}
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_Image ( const FScheduledOp & item , const Parameters * pParams , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Image ) ;
2023-06-23 02:01:13 -04:00
FImageOperator ImOp = MakeImageOperator ( this ) ;
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : IM_LAYERCOLOUR :
{
2023-12-19 05:19:14 -05:00
OP : : ImageLayerColourArgs args = Program . GetOpArgs < OP : : ImageLayerColourArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . base , item ) ,
FScheduledOp : : FromOpAndOptions ( args . colour , item , 0 ) ,
FScheduledOp ( args . mask , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
break ;
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_LAYER :
{
2023-12-19 05:19:14 -05:00
OP : : ImageLayerArgs args = Program . GetOpArgs < OP : : ImageLayerArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
2023-03-08 04:37:54 -05:00
if ( ExecutionStrategy = = EExecutionStrategy : : MinimizeMemory )
{
switch ( item . Stage )
{
case 0 :
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . base , item ) ) ;
break ;
2023-02-09 16:18:52 -05:00
2023-03-08 04:37:54 -05:00
case 1 :
// Request the rest of the data.
AddOp ( FScheduledOp ( item . At , item , 2 ) ,
FScheduledOp ( args . blended , item ) ,
FScheduledOp ( args . mask , item ) ) ;
break ;
case 2 :
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
break ;
default :
check ( false ) ;
}
}
else
{
switch ( item . Stage )
{
case 0 :
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . base , item ) ,
FScheduledOp ( args . blended , item ) ,
FScheduledOp ( args . mask , item ) ) ;
break ;
case 1 :
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
break ;
default :
check ( false ) ;
}
}
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : IM_MULTILAYER :
{
2023-12-19 05:19:14 -05:00
OP : : ImageMultiLayerArgs args = Program . GetOpArgs < OP : : ImageMultiLayerArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . rangeSize , item ) ,
FScheduledOp ( args . base , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_MULTILAYER_1 )
2022-09-26 15:12:13 -04:00
// We now know the number of iterations
2022-11-21 09:44:42 -05:00
int32 Iterations = 0 ;
2022-09-26 15:12:13 -04:00
if ( args . rangeSize )
{
2022-11-23 03:17:56 -05:00
FCacheAddress RangeAddress ( args . rangeSize , item ) ;
2022-09-26 15:12:13 -04:00
// We support both integers and scalars here, which is not common.
// \todo: review if this is necessary or we can enforce it at compile time.
2022-11-21 09:44:42 -05:00
DATATYPE RangeSizeType = GetOpDataType ( pModel - > GetPrivate ( ) - > m_program . GetOpType ( args . rangeSize ) ) ;
if ( RangeSizeType = = DT_INT )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
Iterations = LoadInt ( RangeAddress ) ;
2022-09-26 15:12:13 -04:00
}
2022-11-21 09:44:42 -05:00
else if ( RangeSizeType = = DT_SCALAR )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
Iterations = int32 ( LoadScalar ( RangeAddress ) ) ;
2022-09-26 15:12:13 -04:00
}
}
2023-05-24 02:50:03 -04:00
Ptr < const Image > Base = LoadImage ( FCacheAddress ( args . base , item ) ) ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
if ( Iterations < = 0 )
{
// There are no layers: return the base
2023-05-24 02:50:03 -04:00
StoreImage ( item , Base ) ;
2022-11-23 03:17:56 -05:00
}
else
{
// Store the base
2023-05-24 02:50:03 -04:00
Ptr < Image > New = CloneOrTakeOver ( Base ) ;
EImageFormat InitialBaseFormat = New - > GetFormat ( ) ;
2022-09-26 15:12:13 -04:00
2023-02-08 08:22:43 -05:00
// Reset relevancy map.
New - > m_flags & = ~ Image : : EImageFlags : : IF_HAS_RELEVANCY_MAP ;
2022-11-23 03:17:56 -05:00
// This shouldn't happen in optimised models, but it could happen in editors, etc.
// \todo: raise a performance warning?
2023-05-24 02:50:03 -04:00
EImageFormat BaseFormat = GetUncompressedFormat ( New - > GetFormat ( ) ) ;
if ( New - > GetFormat ( ) ! = BaseFormat )
2022-11-23 03:17:56 -05:00
{
2023-05-24 02:50:03 -04:00
Ptr < Image > Formatted = CreateImage ( New - > GetSizeX ( ) , New - > GetSizeY ( ) , New - > GetLODCount ( ) , BaseFormat , EInitializationType : : NotInitialized ) ;
bool bSuccess = false ;
2023-06-23 02:01:13 -04:00
ImOp . ImagePixelFormat ( bSuccess , m_pSettings - > ImageCompressionQuality , Formatted . get ( ) , New . get ( ) ) ;
2023-05-24 02:50:03 -04:00
check ( bSuccess ) ; // Decompression cannot fail
Release ( New ) ;
New = Formatted ;
2022-11-23 03:17:56 -05:00
}
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
FScheduledOpData Data ;
Data . Resource = New ;
Data . MultiLayer . Iterations = Iterations ;
2023-05-24 02:50:03 -04:00
Data . MultiLayer . OriginalBaseFormat = InitialBaseFormat ;
2022-11-23 03:17:56 -05:00
Data . MultiLayer . bBlendOnlyOneMip = false ;
int32 DataPos = m_heapData . Add ( Data ) ;
// Request the first layer
int32 CurrentIteration = 0 ;
FScheduledOp ItemCopy = item ;
2023-05-24 02:50:03 -04:00
ExecutionIndex Index = GetMemory ( ) . GetRangeIndex ( item . ExecutionIndex ) ;
2022-11-23 03:17:56 -05:00
Index . SetFromModelRangeIndex ( args . rangeId , CurrentIteration ) ;
2023-05-24 02:50:03 -04:00
ItemCopy . ExecutionIndex = GetMemory ( ) . GetRangeIndexIndex ( Index ) ;
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 2 , DataPos ) , FScheduledOp ( args . base , item ) , FScheduledOp ( args . blended , ItemCopy ) , FScheduledOp ( args . mask , ItemCopy ) ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
2022-11-23 03:17:56 -05:00
default :
2022-09-26 15:12:13 -04:00
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_MULTILAYER_default )
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
FScheduledOpData & Data = m_heapData [ item . CustomState ] ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
int32 Iterations = Data . MultiLayer . Iterations ;
int32 CurrentIteration = item . Stage - 2 ;
check ( CurrentIteration > = 0 & & CurrentIteration < 120 ) ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT ( * FString : : Printf ( TEXT ( " Layer %d of %d " ) , CurrentIteration , Iterations ) ) ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
// Process the current layer
2022-10-31 07:17:29 -04:00
2022-11-23 03:17:56 -05:00
Ptr < Image > Base = static_cast < Image * > ( Data . Resource . get ( ) ) ;
FScheduledOp itemCopy = item ;
2023-05-24 02:50:03 -04:00
ExecutionIndex index = GetMemory ( ) . GetRangeIndex ( item . ExecutionIndex ) ;
2022-11-02 12:53:04 -04:00
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
index . SetFromModelRangeIndex ( args . rangeId , CurrentIteration ) ;
2023-05-24 02:50:03 -04:00
itemCopy . ExecutionIndex = GetMemory ( ) . GetRangeIndexIndex ( index ) ;
2022-11-23 03:17:56 -05:00
itemCopy . CustomState = 0 ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Ptr < const Image > Blended = LoadImage ( FCacheAddress ( args . blended , itemCopy ) ) ;
2022-09-26 15:12:13 -04:00
// This shouldn't happen in optimised models, but it could happen in editors, etc.
// \todo: raise a performance warning?
2023-05-24 02:50:03 -04:00
if ( Blended & & Blended - > GetFormat ( ) ! = Base - > GetFormat ( ) )
2022-09-26 15:12:13 -04:00
{
2022-11-02 12:53:04 -04:00
MUTABLE_CPUPROFILER_SCOPE ( ImageResize_BlendedReformat ) ;
2023-05-24 02:50:03 -04:00
Ptr < Image > Formatted = CreateImage ( Blended - > GetSizeX ( ) , Blended - > GetSizeY ( ) , Blended - > GetLODCount ( ) , Base - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
bool bSuccess = false ;
2023-06-23 02:01:13 -04:00
ImOp . ImagePixelFormat ( bSuccess , m_pSettings - > ImageCompressionQuality , Formatted . get ( ) , Blended . get ( ) ) ;
2023-05-24 02:50:03 -04:00
check ( bSuccess ) ;
Release ( Blended ) ;
Blended = Formatted ;
2022-09-26 15:12:13 -04:00
}
// TODO: This shouldn't happen, but be defensive.
2022-11-23 03:17:56 -05:00
FImageSize ResultSize = Base - > GetSize ( ) ;
2023-05-24 02:50:03 -04:00
if ( Blended & & Blended - > GetSize ( ) ! = ResultSize )
2022-09-26 15:12:13 -04:00
{
2022-11-02 12:53:04 -04:00
MUTABLE_CPUPROFILER_SCOPE ( ImageResize_BlendedFixForMultilayer ) ;
2023-05-24 02:50:03 -04:00
Ptr < Image > Resized = CreateImage ( ResultSize [ 0 ] , ResultSize [ 1 ] , Blended - > GetLODCount ( ) , Blended - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
2023-06-23 02:01:13 -04:00
ImOp . ImageResizeLinear ( Resized . get ( ) , 0 , Blended . get ( ) ) ;
2023-05-24 02:50:03 -04:00
Release ( Blended ) ;
Blended = Resized ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
if ( Blended - > GetLODCount ( ) < Base - > GetLODCount ( ) )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
Data . MultiLayer . bBlendOnlyOneMip = true ;
2022-09-26 15:12:13 -04:00
}
2022-11-21 09:44:42 -05:00
bool bApplyColorBlendToAlpha = false ;
bool bDone = false ;
2022-11-23 03:17:56 -05:00
// This becomes true if we need to update the mips of the resulting image
// This could happen in the base image has mips, but one of the blended one doesn't.
bool bBlendOnlyOneMip = Data . MultiLayer . bBlendOnlyOneMip ;
2023-01-27 14:09:59 -05:00
bool bUseBlendSourceFromBlendAlpha = false ; // (Args.flags& OP::ImageLayerArgs::F_BLENDED_RGB_FROM_ALPHA) != 0;
2022-11-23 03:17:56 -05:00
2022-11-21 09:44:42 -05:00
if ( ! args . mask & & args . bUseMaskFromBlended
& &
args . blendType = = uint8 ( EBlendType : : BT_BLEND )
& &
args . blendTypeAlpha = = uint8 ( EBlendType : : BT_LIGHTEN ) )
{
// This is a frequent critical-path case because of multilayer projectors.
bDone = true ;
2023-01-26 05:27:42 -05:00
constexpr bool bUseVectorImpl = false ;
if constexpr ( bUseVectorImpl )
{
2023-05-24 02:50:03 -04:00
BufferLayerCompositeVector < VectorBlendChannelMasked , VectorLightenChannel , false > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , args . BlendAlphaSourceChannel ) ;
2023-01-26 05:27:42 -05:00
}
else
{
2023-05-24 02:50:03 -04:00
BufferLayerComposite < BlendChannelMasked , LightenChannel , false > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , args . BlendAlphaSourceChannel ) ;
2023-01-26 05:27:42 -05:00
}
2022-11-21 09:44:42 -05:00
}
if ( ! bDone & & args . mask )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
Ptr < const Image > Mask = LoadImage ( FCacheAddress ( args . mask , itemCopy ) ) ;
2022-09-26 15:12:13 -04:00
// TODO: This shouldn't happen, but be defensive.
2023-05-24 02:50:03 -04:00
if ( Mask & & Mask - > GetSize ( ) ! = ResultSize )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( ImageResize_MaskFixForMultilayer ) ;
2023-05-24 02:50:03 -04:00
Ptr < Image > Resized = CreateImage ( ResultSize [ 0 ] , ResultSize [ 1 ] , Mask - > GetLODCount ( ) , Mask - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
2023-06-23 02:01:13 -04:00
ImOp . ImageResizeLinear ( Resized . get ( ) , 0 , Mask . get ( ) ) ;
2023-05-24 02:50:03 -04:00
Release ( Mask ) ;
Mask = Resized ;
2022-09-26 15:12:13 -04:00
}
2023-01-27 14:09:59 -05:00
// Not implemented yet
check ( ! bUseBlendSourceFromBlendAlpha ) ;
2022-09-26 15:12:13 -04:00
switch ( EBlendType ( args . blendType ) )
{
2022-11-23 03:17:56 -05:00
case EBlendType : : BT_NORMAL_COMBINE : check ( false ) ; break ;
2024-03-12 07:17:49 -04:00
case EBlendType : : BT_SOFTLIGHT : BufferLayer < SoftLightChannelMasked , SoftLightChannel , false > ( Base . get ( ) , Base . get ( ) , Mask . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_HARDLIGHT : BufferLayer < HardLightChannelMasked , HardLightChannel , false > ( Base . get ( ) , Base . get ( ) , Mask . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_BURN : BufferLayer < BurnChannelMasked , BurnChannel , false > ( Base . get ( ) , Base . get ( ) , Mask . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_DODGE : BufferLayer < DodgeChannelMasked , DodgeChannel , false > ( Base . get ( ) , Base . get ( ) , Mask . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_SCREEN : BufferLayer < ScreenChannelMasked , ScreenChannel , false > ( Base . get ( ) , Base . get ( ) , Mask . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_OVERLAY : BufferLayer < OverlayChannelMasked , OverlayChannel , false > ( Base . get ( ) , Base . get ( ) , Mask . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_LIGHTEN : BufferLayer < LightenChannelMasked , LightenChannel , false > ( Base . get ( ) , Base . get ( ) , Mask . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_MULTIPLY : BufferLayer < MultiplyChannelMasked , MultiplyChannel , false > ( Base . get ( ) , Base . get ( ) , Mask . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_BLEND : BufferLayer < BlendChannelMasked , BlendChannel , false > ( Base . get ( ) , Base . get ( ) , Mask . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
2023-05-24 02:50:03 -04:00
Release ( Mask ) ;
2022-09-26 15:12:13 -04:00
}
2022-11-21 09:44:42 -05:00
else if ( ! bDone & & args . bUseMaskFromBlended )
{
2023-01-27 14:09:59 -05:00
// Not implemented yet
check ( ! bUseBlendSourceFromBlendAlpha ) ;
2022-11-21 09:44:42 -05:00
switch ( EBlendType ( args . blendType ) )
{
2022-11-23 03:17:56 -05:00
case EBlendType : : BT_NORMAL_COMBINE : check ( false ) ; break ;
2024-03-12 07:17:49 -04:00
case EBlendType : : BT_SOFTLIGHT : BufferLayerEmbeddedMask < SoftLightChannelMasked , SoftLightChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_HARDLIGHT : BufferLayerEmbeddedMask < HardLightChannelMasked , HardLightChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_BURN : BufferLayerEmbeddedMask < BurnChannelMasked , BurnChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_DODGE : BufferLayerEmbeddedMask < DodgeChannelMasked , DodgeChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_SCREEN : BufferLayerEmbeddedMask < ScreenChannelMasked , ScreenChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_OVERLAY : BufferLayerEmbeddedMask < OverlayChannelMasked , OverlayChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_LIGHTEN : BufferLayerEmbeddedMask < LightenChannelMasked , LightenChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_MULTIPLY : BufferLayerEmbeddedMask < MultiplyChannelMasked , MultiplyChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
case EBlendType : : BT_BLEND : BufferLayerEmbeddedMask < BlendChannelMasked , BlendChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip ) ; break ;
2022-11-21 09:44:42 -05:00
default : check ( false ) ;
}
}
else if ( ! bDone )
2022-09-26 15:12:13 -04:00
{
switch ( EBlendType ( args . blendType ) )
{
2022-11-23 03:17:56 -05:00
case EBlendType : : BT_NORMAL_COMBINE : check ( false ) ; break ;
2023-05-24 02:50:03 -04:00
case EBlendType : : BT_SOFTLIGHT : BufferLayer < SoftLightChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip , bUseBlendSourceFromBlendAlpha ) ; break ;
case EBlendType : : BT_HARDLIGHT : BufferLayer < HardLightChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip , bUseBlendSourceFromBlendAlpha ) ; break ;
case EBlendType : : BT_BURN : BufferLayer < BurnChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip , bUseBlendSourceFromBlendAlpha ) ; break ;
case EBlendType : : BT_DODGE : BufferLayer < DodgeChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip , bUseBlendSourceFromBlendAlpha ) ; break ;
case EBlendType : : BT_SCREEN : BufferLayer < ScreenChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip , bUseBlendSourceFromBlendAlpha ) ; break ;
case EBlendType : : BT_OVERLAY : BufferLayer < OverlayChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip , bUseBlendSourceFromBlendAlpha ) ; break ;
case EBlendType : : BT_LIGHTEN : BufferLayer < LightenChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip , bUseBlendSourceFromBlendAlpha ) ; break ;
case EBlendType : : BT_MULTIPLY : BufferLayer < MultiplyChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip , bUseBlendSourceFromBlendAlpha ) ; break ;
case EBlendType : : BT_BLEND : BufferLayer < BlendChannel , false > ( Base . get ( ) , Base . get ( ) , Blended . get ( ) , bApplyColorBlendToAlpha , bBlendOnlyOneMip , bUseBlendSourceFromBlendAlpha ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
}
2022-11-21 09:44:42 -05:00
// Apply the separate blend operation for alpha
if ( ! bDone & & ! bApplyColorBlendToAlpha & & args . blendTypeAlpha ! = uint8 ( EBlendType : : BT_NONE ) )
{
// Separate alpha operation ignores the mask.
switch ( EBlendType ( args . blendTypeAlpha ) )
{
2023-05-24 02:50:03 -04:00
case EBlendType : : BT_SOFTLIGHT : BufferLayerInPlace < SoftLightChannel , false , 1 > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , 3 , args . BlendAlphaSourceChannel ) ; break ;
case EBlendType : : BT_HARDLIGHT : BufferLayerInPlace < HardLightChannel , false , 1 > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , 3 , args . BlendAlphaSourceChannel ) ; break ;
case EBlendType : : BT_BURN : BufferLayerInPlace < BurnChannel , false , 1 > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , 3 , args . BlendAlphaSourceChannel ) ; break ;
case EBlendType : : BT_DODGE : BufferLayerInPlace < DodgeChannel , false , 1 > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , 3 , args . BlendAlphaSourceChannel ) ; break ;
case EBlendType : : BT_SCREEN : BufferLayerInPlace < ScreenChannel , false , 1 > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , 3 , args . BlendAlphaSourceChannel ) ; break ;
case EBlendType : : BT_OVERLAY : BufferLayerInPlace < OverlayChannel , false , 1 > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , 3 , args . BlendAlphaSourceChannel ) ; break ;
case EBlendType : : BT_LIGHTEN : BufferLayerInPlace < LightenChannel , false , 1 > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , 3 , args . BlendAlphaSourceChannel ) ; break ;
case EBlendType : : BT_MULTIPLY : BufferLayerInPlace < MultiplyChannel , false , 1 > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , 3 , args . BlendAlphaSourceChannel ) ; break ;
case EBlendType : : BT_BLEND : BufferLayerInPlace < BlendChannel , false , 1 > ( Base . get ( ) , Blended . get ( ) , bBlendOnlyOneMip , 3 , args . BlendAlphaSourceChannel ) ; break ;
2022-11-21 09:44:42 -05:00
default : check ( false ) ;
}
}
2023-05-24 02:50:03 -04:00
Release ( Blended ) ;
2022-09-26 15:12:13 -04:00
}
2022-11-23 03:17:56 -05:00
// Are we done?
if ( CurrentIteration + 1 = = Iterations )
2022-11-02 12:53:04 -04:00
{
2022-11-23 03:17:56 -05:00
if ( Data . MultiLayer . bBlendOnlyOneMip )
{
MUTABLE_CPUPROFILER_SCOPE ( ImageLayer_MipFix ) ;
FMipmapGenerationSettings DummyMipSettings { } ;
2023-05-24 02:50:03 -04:00
ImageMipmapInPlace ( m_pSettings - > ImageCompressionQuality , Base . get ( ) , DummyMipSettings ) ;
2022-11-23 03:17:56 -05:00
}
// TODO: Reconvert to OriginalBaseFormat if necessary?
Data . Resource = nullptr ;
2023-05-24 02:50:03 -04:00
StoreImage ( item , Base ) ;
2022-11-23 03:17:56 -05:00
break ;
}
else
{
// Request a new layer
+ + CurrentIteration ;
FScheduledOp ItemCopy = item ;
2023-05-24 02:50:03 -04:00
ExecutionIndex Index = GetMemory ( ) . GetRangeIndex ( item . ExecutionIndex ) ;
2022-11-23 03:17:56 -05:00
Index . SetFromModelRangeIndex ( args . rangeId , CurrentIteration ) ;
2023-05-24 02:50:03 -04:00
ItemCopy . ExecutionIndex = GetMemory ( ) . GetRangeIndexIndex ( Index ) ;
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 2 + CurrentIteration , item . CustomState ) , FScheduledOp ( args . blended , ItemCopy ) , FScheduledOp ( args . mask , ItemCopy ) ) ;
2022-11-02 12:53:04 -04:00
}
2022-09-26 15:12:13 -04:00
break ;
}
2022-11-23 03:17:56 -05:00
} // switch stage
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : IM_NORMALCOMPOSITE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageNormalCompositeArgs args = Program . GetOpArgs < OP : : ImageNormalCompositeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
if ( args . base & & args . normal )
{
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . base , item ) ,
FScheduledOp ( args . normal , item ) ) ;
2023-12-19 05:19:14 -05:00
}
2023-05-24 02:50:03 -04:00
else
{
StoreImage ( item , nullptr ) ;
2022-09-26 15:12:13 -04:00
}
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_NORMALCOMPOSITE_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Image > Base = LoadImage ( FCacheAddress ( args . base , item ) ) ;
Ptr < const Image > Normal = LoadImage ( FCacheAddress ( args . normal , item ) ) ;
2022-09-26 15:12:13 -04:00
if ( Normal - > GetLODCount ( ) < Base - > GetLODCount ( ) )
{
MUTABLE_CPUPROFILER_SCOPE ( ImageNormalComposite_EmergencyFix ) ;
2024-03-12 07:17:49 -04:00
int32 StartLevel = Normal - > GetLODCount ( ) - 1 ;
int32 LevelCount = Base - > GetLODCount ( ) ;
Ptr < Image > NormalFix = CloneOrTakeOver ( Normal ) ;
2022-09-26 15:12:13 -04:00
2024-03-12 07:17:49 -04:00
FMipmapGenerationSettings MipSettings { } ;
ImOp . ImageMipmap ( m_pSettings - > ImageCompressionQuality , NormalFix . get ( ) , NormalFix . get ( ) , StartLevel , LevelCount , MipSettings ) ;
2023-05-24 02:50:03 -04:00
2024-03-12 07:17:49 -04:00
Normal = NormalFix ;
2022-09-26 15:12:13 -04:00
}
2024-03-12 07:17:49 -04:00
Ptr < Image > Result = CreateImage ( Base - > GetSizeX ( ) , Base - > GetSizeY ( ) , Base - > GetLODCount ( ) , Base - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
2023-05-24 02:50:03 -04:00
ImageNormalComposite ( Result . get ( ) , Base . get ( ) , Normal . get ( ) , args . mode , args . power ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Release ( Base ) ;
Release ( Normal ) ;
StoreImage ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_PIXELFORMAT :
{
2023-12-19 05:19:14 -05:00
OP : : ImagePixelFormatArgs args = Program . GetOpArgs < OP : : ImagePixelFormatArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_MIPMAP :
{
2023-12-19 05:19:14 -05:00
OP : : ImageMipmapArgs args = Program . GetOpArgs < OP : : ImageMipmapArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-24 10:06:46 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
break ;
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_RESIZE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageResizeArgs args = Program . GetOpArgs < OP : : ImageResizeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-01-25 04:08:49 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-26 05:27:42 -05:00
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
2022-09-26 15:12:13 -04:00
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_RESIZELIKE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageResizeLikeArgs args = Program . GetOpArgs < OP : : ImageResizeLikeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2024-03-12 07:17:49 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . source , item ) ,
FScheduledOp ( args . sizeSource , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_RESIZELIKE_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Image > Base = LoadImage ( FCacheAddress ( args . source , item ) ) ;
Ptr < const Image > SizeBase = LoadImage ( FCacheAddress ( args . sizeSource , item ) ) ;
FImageSize DestSize = SizeBase - > GetSize ( ) ;
Release ( SizeBase ) ;
2022-09-26 15:12:13 -04:00
2024-03-12 07:17:49 -04:00
if ( Base - > GetSize ( ) ! = DestSize )
2022-09-26 15:12:13 -04:00
{
2023-07-31 13:21:43 -04:00
int32 BaseLODCount = Base - > GetLODCount ( ) ;
Ptr < Image > Result = CreateImage ( DestSize [ 0 ] , DestSize [ 1 ] , BaseLODCount , Base - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
2024-03-12 07:17:49 -04:00
ImOp . ImageResizeLinear ( Result . get ( ) , m_pSettings - > ImageCompressionQuality , Base . get ( ) ) ;
2023-05-24 02:50:03 -04:00
Release ( Base ) ;
2022-09-26 15:12:13 -04:00
// If the source image had mips, generate them as well for the resized image.
// This shouldn't happen often since "ResizeLike" should be usually optimised out
// during model compilation. The mipmap generation below is not very precise with
// the number of mips that are needed and will probably generate too many
2024-03-12 07:17:49 -04:00
bool bSourceHasMips = BaseLODCount > 1 ;
if ( bSourceHasMips )
2022-09-26 15:12:13 -04:00
{
2024-03-12 07:17:49 -04:00
int32 LevelCount = Image : : GetMipmapCount ( Result - > GetSizeX ( ) , Result - > GetSizeY ( ) ) ;
Result - > DataStorage . SetNumLODs ( LevelCount ) ;
2022-09-26 15:12:13 -04:00
2024-03-12 07:17:49 -04:00
FMipmapGenerationSettings MipSettings { } ;
ImOp . ImageMipmap ( m_pSettings - > ImageCompressionQuality , Result . get ( ) , Result . get ( ) , 0 , LevelCount , MipSettings ) ;
2023-05-24 02:50:03 -04:00
}
StoreImage ( item , Result ) ;
}
2022-09-26 15:12:13 -04:00
else
{
2023-05-24 02:50:03 -04:00
StoreImage ( item , Base ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_RESIZEREL :
{
2023-12-19 05:19:14 -05:00
OP : : ImageResizeRelArgs args = Program . GetOpArgs < OP : : ImageResizeRelArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-26 05:27:42 -05:00
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
2022-09-26 15:12:13 -04:00
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_BLANKLAYOUT :
{
2024-03-12 07:17:49 -04:00
OP : : ImageBlankLayoutArgs Args = Program . GetOpArgs < OP : : ImageBlankLayoutArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2024-03-12 07:17:49 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp : : FromOpAndOptions ( Args . layout , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_BLANKLAYOUT_1 )
2024-03-12 07:17:49 -04:00
Ptr < const Layout > pLayout = LoadLayout ( FScheduledOp : : FromOpAndOptions ( Args . layout , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
FIntPoint SizeInBlocks = pLayout - > GetGridSize ( ) ;
2024-03-12 07:17:49 -04:00
FIntPoint BlockSizeInPixels ( Args . blockSize [ 0 ] , Args . blockSize [ 1 ] ) ;
2022-09-26 15:12:13 -04:00
// Image size if we don't skip any mipmap
FIntPoint FullImageSizeInPixels = SizeInBlocks * BlockSizeInPixels ;
int32 FullImageMipCount = Image : : GetMipmapCount ( FullImageSizeInPixels . X , FullImageSizeInPixels . Y ) ;
FIntPoint ImageSizeInPixels = FullImageSizeInPixels ;
2022-11-23 03:17:56 -05:00
int32 MipsToSkip = item . ExecutionOptions ;
2022-09-26 15:12:13 -04:00
MipsToSkip = FMath : : Min ( MipsToSkip , FullImageMipCount ) ;
if ( MipsToSkip > 0 )
{
//FIntPoint ReducedBlockSizeInPixels;
// This method tries to reduce only the block size, but it fails if the image is still too big
// If we want to generate only a subset of mipmaps, reduce the layout block size accordingly.
//ReducedBlockSizeInPixels.X = BlockSizeInPixels.X >> MipsToSkip;
//ReducedBlockSizeInPixels.Y = BlockSizeInPixels.Y >> MipsToSkip;
//const FImageFormatData& FormatData = GetImageFormatData((EImageFormat)args.format);
2023-06-23 02:01:13 -04:00
//int MinBlockSize = FMath::Max(FormatData.PixelsPerBlockX, FormatData.PixelsPerBlockY);
//ReducedBlockSizeInPixels.X = FMath::Max<int32>(ReducedBlockSizeInPixels.X, FormatData.PixelsPerBlockX);
//ReducedBlockSizeInPixels.Y = FMath::Max<int32>(ReducedBlockSizeInPixels.Y, FormatData.PixelsPerBlockY);
2022-09-26 15:12:13 -04:00
//FIntPoint ReducedImageSizeInPixels = SizeInBlocks * ReducedBlockSizeInPixels;
// This method simply reduces the size and assumes all the other operations will handle degeenrate cases.
ImageSizeInPixels = FullImageSizeInPixels / ( 1 < < MipsToSkip ) ;
//if (ReducedImageSizeInPixels!= ImageSizeInPixels)
//{
// check(false);
//}
}
2024-03-12 07:17:49 -04:00
int32 MipsToGenerate = 1 ;
if ( Args . generateMipmaps )
2022-09-26 15:12:13 -04:00
{
2024-03-12 07:17:49 -04:00
if ( Args . mipmapCount = = 0 )
2022-09-26 15:12:13 -04:00
{
MipsToGenerate = Image : : GetMipmapCount ( ImageSizeInPixels . X , ImageSizeInPixels . Y ) ;
}
else
{
2024-03-12 07:17:49 -04:00
MipsToGenerate = FMath : : Max ( Args . mipmapCount - MipsToSkip , 1 ) ;
2022-09-26 15:12:13 -04:00
}
}
2023-06-23 02:01:13 -04:00
// It needs to be initialized in case it has gaps.
2024-03-12 07:17:49 -04:00
Ptr < Image > New = CreateImage ( ImageSizeInPixels . X , ImageSizeInPixels . Y , MipsToGenerate , EImageFormat ( Args . format ) , EInitializationType : : Black ) ;
StoreImage ( item , New ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_COMPOSE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageComposeArgs Args = Program . GetOpArgs < OP : : ImageComposeArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
2023-10-09 04:49:01 -04:00
if ( ExecutionStrategy = = EExecutionStrategy : : MinimizeMemory )
{
switch ( item . Stage )
{
case 0 :
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp : : FromOpAndOptions ( Args . layout , item , 0 ) ) ;
break ;
case 1 :
{
Ptr < const Layout > ComposeLayout =
LoadLayout ( FCacheAddress ( Args . layout , FScheduledOp : : FromOpAndOptions ( Args . layout , item , 0 ) ) ) ;
2022-09-26 15:12:13 -04:00
2023-10-09 04:49:01 -04:00
FScheduledOpData Data ;
Data . Resource = const_cast < Layout * > ( ComposeLayout . get ( ) ) ;
int32 DataPos = m_heapData . Add ( Data ) ;
2022-09-26 15:12:13 -04:00
2024-05-13 03:20:24 -04:00
int32 RelBlockIndex = ComposeLayout - > FindBlock ( Args . BlockId ) ;
2022-09-26 15:12:13 -04:00
2023-10-09 04:49:01 -04:00
if ( RelBlockIndex > = 0 )
{
AddOp ( FScheduledOp ( item . At , item , 2 , DataPos ) , FScheduledOp ( Args . base , item ) ) ;
}
else
{
// Jump directly to stage 3, no need to load mask or blockImage.
AddOp ( FScheduledOp ( item . At , item , 3 , DataPos ) , FScheduledOp ( Args . base , item ) ) ;
}
2022-09-26 15:12:13 -04:00
2023-10-09 04:49:01 -04:00
break ;
}
case 2 :
{
AddOp ( FScheduledOp ( item . At , item , 3 , item . CustomState ) ,
FScheduledOp ( Args . blockImage , item ) ,
FScheduledOp ( Args . mask , item ) ) ;
break ;
}
case 3 :
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
break ;
default :
check ( false ) ;
}
}
else
{
switch ( item . Stage )
{
case 0 :
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp : : FromOpAndOptions ( Args . layout , item , 0 ) ) ;
break ;
case 1 :
{
Ptr < const Layout > ComposeLayout =
LoadLayout ( FCacheAddress ( Args . layout , FScheduledOp : : FromOpAndOptions ( Args . layout , item , 0 ) ) ) ;
FScheduledOpData Data ;
Data . Resource = const_cast < Layout * > ( ComposeLayout . get ( ) ) ;
int32 DataPos = m_heapData . Add ( Data ) ;
2024-05-13 03:20:24 -04:00
int32 RelBlockIndex = ComposeLayout - > FindBlock ( Args . BlockId ) ;
2023-10-09 04:49:01 -04:00
if ( RelBlockIndex > = 0 )
{
AddOp ( FScheduledOp ( item . At , item , 2 , DataPos ) ,
FScheduledOp ( Args . base , item ) ,
FScheduledOp ( Args . blockImage , item ) ,
FScheduledOp ( Args . mask , item ) ) ;
}
else
{
AddOp ( FScheduledOp ( item . At , item , 2 , DataPos ) , FScheduledOp ( Args . base , item ) ) ;
}
break ;
}
case 2 :
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
break ;
default :
check ( false ) ;
}
}
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : IM_INTERPOLATE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageInterpolateArgs args = Program . GetOpArgs < OP : : ImageInterpolateArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . factor , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_INTERPOLATE_1 )
2022-09-26 15:12:13 -04:00
// Targets must be consecutive
int count = 0 ;
for ( int i = 0
; i < MUTABLE_OP_MAX_INTERPOLATE_COUNT & & args . targets [ i ]
; + + i )
{
count + + ;
}
2023-05-24 02:50:03 -04:00
float factor = LoadScalar ( FCacheAddress ( args . factor , item ) ) ;
2022-09-26 15:12:13 -04:00
float delta = 1.0f / ( count - 1 ) ;
int min = ( int ) floorf ( factor / delta ) ;
int max = ( int ) ceilf ( factor / delta ) ;
float bifactor = factor / delta - min ;
2022-11-21 09:44:42 -05:00
FScheduledOpData data ;
2022-11-23 03:17:56 -05:00
data . Interpolate . Bifactor = bifactor ;
data . Interpolate . Min = FMath : : Clamp ( min , 0 , count - 1 ) ;
data . Interpolate . Max = FMath : : Clamp ( max , 0 , count - 1 ) ;
2022-09-26 15:12:13 -04:00
uint32 dataPos = uint32 ( m_heapData . Add ( data ) ) ;
2022-10-21 22:27:28 -04:00
if ( bifactor < UE_SMALL_NUMBER )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 2 , dataPos ) ,
FScheduledOp ( args . targets [ min ] , item ) ) ;
}
2022-10-21 22:27:28 -04:00
else if ( bifactor > 1.0f - UE_SMALL_NUMBER )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 2 , dataPos ) ,
FScheduledOp ( args . targets [ max ] , item ) ) ;
}
else
{
AddOp ( FScheduledOp ( item . At , item , 2 , dataPos ) ,
FScheduledOp ( args . targets [ min ] , item ) ,
FScheduledOp ( args . targets [ max ] , item ) ) ;
}
2022-09-26 15:12:13 -04:00
break ;
}
case 2 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_INTERPOLATE_2 )
2022-09-26 15:12:13 -04:00
// Targets must be consecutive
int count = 0 ;
for ( int i = 0
; i < MUTABLE_OP_MAX_INTERPOLATE_COUNT & & args . targets [ i ]
; + + i )
{
count + + ;
}
// Factor from 0 to 1 between the two targets
2024-03-12 07:17:49 -04:00
const FScheduledOpData & Data = m_heapData [ ( size_t ) item . CustomState ] ;
float Bifactor = Data . Interpolate . Bifactor ;
int32 Min = Data . Interpolate . Min ;
int32 Max = Data . Interpolate . Max ;
2022-09-26 15:12:13 -04:00
2024-03-12 07:17:49 -04:00
if ( Bifactor < UE_SMALL_NUMBER )
2022-09-26 15:12:13 -04:00
{
2024-03-12 07:17:49 -04:00
Ptr < const Image > Source = LoadImage ( FCacheAddress ( args . targets [ Min ] , item ) ) ;
2023-05-24 02:50:03 -04:00
StoreImage ( item , Source ) ;
}
2024-03-12 07:17:49 -04:00
else if ( Bifactor > 1.0f - UE_SMALL_NUMBER )
2022-09-26 15:12:13 -04:00
{
2024-03-12 07:17:49 -04:00
Ptr < const Image > Source = LoadImage ( FCacheAddress ( args . targets [ Max ] , item ) ) ;
2023-05-24 02:50:03 -04:00
StoreImage ( item , Source ) ;
}
2022-09-26 15:12:13 -04:00
else
{
2024-03-12 07:17:49 -04:00
Ptr < const Image > pMin = LoadImage ( FCacheAddress ( args . targets [ Min ] , item ) ) ;
Ptr < const Image > pMax = LoadImage ( FCacheAddress ( args . targets [ Max ] , item ) ) ;
2022-09-26 15:12:13 -04:00
if ( pMin & & pMax )
2023-12-19 05:19:14 -05:00
{
2023-06-20 04:26:21 -04:00
Ptr < Image > pNew = CloneOrTakeOver ( pMin ) ;
2022-09-26 15:12:13 -04:00
// Be defensive: ensure image sizes match.
2023-06-20 04:26:21 -04:00
if ( pNew - > GetSize ( ) ! = pMax - > GetSize ( ) )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( ImageResize_ForInterpolate ) ;
2023-06-20 04:26:21 -04:00
Ptr < Image > Resized = CreateImage ( pNew - > GetSizeX ( ) , pNew - > GetSizeY ( ) , pMax - > GetLODCount ( ) , pMax - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
2023-06-23 02:01:13 -04:00
ImOp . ImageResizeLinear ( Resized . get ( ) , 0 , pMax . get ( ) ) ;
2023-05-24 02:50:03 -04:00
Release ( pMax ) ;
pMax = Resized ;
2022-09-26 15:12:13 -04:00
}
2023-11-29 07:21:09 -05:00
// Be defensive: ensure format matches.
if ( pNew - > GetFormat ( ) ! = pMax - > GetFormat ( ) )
{
MUTABLE_CPUPROFILER_SCOPE ( Format_ForInterpolate ) ;
Ptr < Image > Formatted = CreateImage ( pMax - > GetSizeX ( ) , pMax - > GetSizeY ( ) , pMax - > GetLODCount ( ) , pNew - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
bool bSuccess = false ;
ImOp . ImagePixelFormat ( bSuccess , m_pSettings - > ImageCompressionQuality , Formatted . get ( ) , pMax . get ( ) ) ;
check ( bSuccess ) ;
Release ( pMax ) ;
pMax = Formatted ;
}
2023-12-19 05:19:14 -05:00
int32 LevelCount = FMath : : Max ( pNew - > GetLODCount ( ) , pMax - > GetLODCount ( ) ) ;
2023-06-20 04:26:21 -04:00
if ( pNew - > GetLODCount ( ) ! = LevelCount )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( Mipmap_ForInterpolate ) ;
2024-03-12 07:17:49 -04:00
int32 StartLevel = pNew - > GetLODCount ( ) - 1 ;
// pNew is local owned, no need to CloneOrTakeOver.
pNew - > DataStorage . SetNumLODs ( LevelCount ) ;
2022-09-26 15:12:13 -04:00
2024-03-12 07:17:49 -04:00
FMipmapGenerationSettings Settings { } ;
ImOp . ImageMipmap ( m_pSettings - > ImageCompressionQuality , pNew . get ( ) , pNew . get ( ) , StartLevel , LevelCount , Settings ) ;
2022-09-26 15:12:13 -04:00
2022-12-09 03:57:57 -05:00
}
if ( pMax - > GetLODCount ( ) ! = LevelCount )
{
MUTABLE_CPUPROFILER_SCOPE ( Mipmap_ForInterpolate ) ;
2024-03-12 07:17:49 -04:00
int32 StartLevel = pMax - > GetLODCount ( ) - 1 ;
2022-12-09 03:57:57 -05:00
2024-03-12 07:17:49 -04:00
Ptr < Image > MaxFix = CloneOrTakeOver ( pMax ) ;
MaxFix - > DataStorage . SetNumLODs ( LevelCount ) ;
FMipmapGenerationSettings Settings { } ;
ImOp . ImageMipmap ( m_pSettings - > ImageCompressionQuality , MaxFix . get ( ) , MaxFix . get ( ) , StartLevel , LevelCount , Settings ) ;
2022-12-09 03:57:57 -05:00
2024-03-12 07:17:49 -04:00
pMax = MaxFix ;
2022-09-26 15:12:13 -04:00
}
2024-03-12 07:17:49 -04:00
ImageInterpolate ( pNew . get ( ) , pMax . get ( ) , Bifactor ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Release ( pMax ) ;
StoreImage ( item , pNew ) ;
}
2022-09-26 15:12:13 -04:00
else if ( pMin )
{
2023-05-24 02:50:03 -04:00
StoreImage ( item , pMin ) ;
}
2022-09-26 15:12:13 -04:00
else if ( pMax )
{
2023-05-24 02:50:03 -04:00
StoreImage ( item , pMax ) ;
}
}
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_SATURATE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageSaturateArgs args = Program . GetOpArgs < OP : : ImageSaturateArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . base , item ) ,
FScheduledOp : : FromOpAndOptions ( args . factor , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-26 05:27:42 -05:00
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
2022-09-26 15:12:13 -04:00
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_LUMINANCE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageLuminanceArgs args = Program . GetOpArgs < OP : : ImageLuminanceArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . base , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_LUMINANCE_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Image > Base = LoadImage ( FCacheAddress ( args . base , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Ptr < Image > Result = CreateImage ( Base - > GetSizeX ( ) , Base - > GetSizeY ( ) , Base - > GetLODCount ( ) , EImageFormat : : IF_L_UBYTE , EInitializationType : : NotInitialized ) ;
ImageLuminance ( Result . get ( ) , Base . get ( ) ) ;
Release ( Base ) ;
StoreImage ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_SWIZZLE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageSwizzleArgs args = Program . GetOpArgs < OP : : ImageSwizzleArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . sources [ 0 ] , item ) ,
FScheduledOp ( args . sources [ 1 ] , item ) ,
FScheduledOp ( args . sources [ 2 ] , item ) ,
FScheduledOp ( args . sources [ 3 ] , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
break ;
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_COLOURMAP :
{
2023-12-19 05:19:14 -05:00
OP : : ImageColourMapArgs args = Program . GetOpArgs < OP : : ImageColourMapArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . base , item ) ,
FScheduledOp ( args . mask , item ) ,
FScheduledOp ( args . map , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_COLOURMAP_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Image > Source = LoadImage ( FCacheAddress ( args . base , item ) ) ;
Ptr < const Image > Mask = LoadImage ( FCacheAddress ( args . mask , item ) ) ;
Ptr < const Image > Map = LoadImage ( FCacheAddress ( args . map , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
bool bOnlyOneMip = ( Mask - > GetLODCount ( ) < Source - > GetLODCount ( ) ) ;
2023-02-01 11:13:36 -05:00
2022-09-26 15:12:13 -04:00
// Be defensive: ensure image sizes match.
2023-05-24 02:50:03 -04:00
if ( Mask - > GetSize ( ) ! = Source - > GetSize ( ) )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( ImageResize_ForColourmap ) ;
2023-05-24 02:50:03 -04:00
Ptr < Image > Resized = CreateImage ( Source - > GetSizeX ( ) , Source - > GetSizeY ( ) , 1 , Mask - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
2023-06-23 02:01:13 -04:00
ImOp . ImageResizeLinear ( Resized . get ( ) , 0 , Mask . get ( ) ) ;
2023-05-24 02:50:03 -04:00
Release ( Mask ) ;
Mask = Resized ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
Ptr < Image > Result = CreateImage ( Source - > GetSizeX ( ) , Source - > GetSizeY ( ) , Source - > GetLODCount ( ) , Source - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
ImageColourMap ( Result . get ( ) , Source . get ( ) , Mask . get ( ) , Map . get ( ) , bOnlyOneMip ) ;
2023-02-01 11:13:36 -05:00
if ( bOnlyOneMip )
{
MUTABLE_CPUPROFILER_SCOPE ( ImageColourMap_MipFix ) ;
FMipmapGenerationSettings DummyMipSettings { } ;
2023-05-24 02:50:03 -04:00
ImageMipmapInPlace ( m_pSettings - > ImageCompressionQuality , Result . get ( ) , DummyMipSettings ) ;
2023-02-01 11:13:36 -05:00
}
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Release ( Source ) ;
Release ( Mask ) ;
Release ( Map ) ;
StoreImage ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_GRADIENT :
{
2023-12-19 05:19:14 -05:00
OP : : ImageGradientArgs args = Program . GetOpArgs < OP : : ImageGradientArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp : : FromOpAndOptions ( args . colour0 , item , 0 ) ,
FScheduledOp : : FromOpAndOptions ( args . colour1 , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_GRADIENT_1 )
2023-05-24 02:50:03 -04:00
FVector4f colour0 = LoadColor ( FScheduledOp : : FromOpAndOptions ( args . colour0 , item , 0 ) ) ;
FVector4f colour1 = LoadColor ( FScheduledOp : : FromOpAndOptions ( args . colour1 , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
2023-06-23 02:01:13 -04:00
ImagePtr pResult = CreateImage ( args . size [ 0 ] , args . size [ 1 ] , 1 , EImageFormat : : IF_RGB_UBYTE , EInitializationType : : NotInitialized ) ;
2023-05-24 02:50:03 -04:00
ImageGradient ( pResult . get ( ) , colour0 , colour1 ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
StoreImage ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_BINARISE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageBinariseArgs args = Program . GetOpArgs < OP : : ImageBinariseArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . base , item ) ,
FScheduledOp : : FromOpAndOptions ( args . threshold , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_BINARISE_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Image > pA = LoadImage ( FCacheAddress ( args . base , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
float c = LoadScalar ( FScheduledOp : : FromOpAndOptions ( args . threshold , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
2023-06-23 02:01:13 -04:00
Ptr < Image > Result = CreateImage ( pA - > GetSizeX ( ) , pA - > GetSizeY ( ) , pA - > GetLODCount ( ) , EImageFormat : : IF_L_UBYTE , EInitializationType : : NotInitialized ) ;
2023-05-24 02:50:03 -04:00
ImageBinarise ( Result . get ( ) , pA . get ( ) , c ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Release ( pA ) ;
StoreImage ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_INVERT :
{
2023-12-19 05:19:14 -05:00
OP : : ImageInvertArgs args = Program . GetOpArgs < OP : : ImageInvertArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-26 05:27:42 -05:00
// This has been moved to a task. It should have been intercepted in IssueOp.
check ( false ) ;
2022-09-26 15:12:13 -04:00
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_PLAINCOLOUR :
{
2023-12-19 05:19:14 -05:00
OP : : ImagePlainColourArgs args = Program . GetOpArgs < OP : : ImagePlainColourArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp : : FromOpAndOptions ( args . colour , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_PLAINCOLOUR_1 )
2023-05-24 02:50:03 -04:00
FVector4f c = LoadColor ( FScheduledOp : : FromOpAndOptions ( args . colour , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
uint16 SizeX = args . size [ 0 ] ;
uint16 SizeY = args . size [ 1 ] ;
2023-03-17 09:40:20 -04:00
int32 LODs = args . LODs ;
// This means all the mip chain
if ( LODs = = 0 )
{
LODs = FMath : : CeilLogTwo ( FMath : : Max ( SizeX , SizeY ) ) ;
}
2022-11-23 03:17:56 -05:00
for ( int l = 0 ; l < item . ExecutionOptions ; + + l )
2022-09-26 15:12:13 -04:00
{
SizeX = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( SizeX , uint16 ( 2 ) ) ) ;
SizeY = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( SizeY , uint16 ( 2 ) ) ) ;
2023-03-17 09:40:20 -04:00
- - LODs ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
ImagePtr pA = CreateImage ( SizeX , SizeY , FMath : : Max ( LODs , 1 ) , EImageFormat ( args . format ) , EInitializationType : : NotInitialized ) ;
2022-09-26 15:12:13 -04:00
2023-06-23 02:01:13 -04:00
ImOp . FillColor ( pA . get ( ) , c ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
StoreImage ( item , pA ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2023-04-28 15:57:31 -04:00
case OP_TYPE : : IM_REFERENCE :
{
2023-12-19 05:19:14 -05:00
OP : : ResourceReferenceArgs Args = Program . GetOpArgs < OP : : ResourceReferenceArgs > ( item . At ) ;
2023-04-28 15:57:31 -04:00
switch ( item . Stage )
{
case 0 :
{
2023-10-05 04:46:46 -04:00
Ptr < Image > Result ;
if ( Args . ForceLoad )
{
// This should never be reached because it should have been caught as a Task in IssueOp
check ( false ) ;
}
else
{
Result = Image : : CreateAsReference ( Args . ID , Args . ImageDesc , false ) ;
}
2023-05-24 02:50:03 -04:00
StoreImage ( item , Result ) ;
2023-04-28 15:57:31 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
case OP_TYPE : : IM_CROP :
{
2023-12-19 05:19:14 -05:00
OP : : ImageCropArgs args = Program . GetOpArgs < OP : : ImageCropArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_CROP_1 )
2023-05-24 02:50:03 -04:00
Ptr < const Image > pA = LoadImage ( FCacheAddress ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-07-28 04:00:17 -04:00
box < UE : : Math : : TIntVector2 < int32 > > rect ;
2022-09-26 15:12:13 -04:00
rect . min [ 0 ] = args . minX ;
rect . min [ 1 ] = args . minY ;
rect . size [ 0 ] = args . sizeX ;
rect . size [ 1 ] = args . sizeY ;
// Apply ther mipmap reduction to the crop rectangle.
2022-11-23 03:17:56 -05:00
int32 MipsToSkip = item . ExecutionOptions ;
2022-09-26 15:12:13 -04:00
while ( MipsToSkip > 0 & & rect . size [ 0 ] > 0 & & rect . size [ 1 ] > 0 )
{
2023-09-14 12:02:21 -04:00
rect . min [ 0 ] / = 2 ;
rect . min [ 1 ] / = 2 ;
rect . size [ 0 ] / = 2 ;
rect . size [ 1 ] / = 2 ;
2022-09-26 15:12:13 -04:00
MipsToSkip - - ;
}
ImagePtr pResult ;
if ( ! rect . IsEmpty ( ) )
{
2023-06-23 02:01:13 -04:00
pResult = CreateImage ( rect . size [ 0 ] , rect . size [ 1 ] , 1 , pA - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
ImOp . ImageCrop ( pResult . get ( ) , m_pSettings - > ImageCompressionQuality , pA . get ( ) , rect ) ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
Release ( pA ) ;
StoreImage ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_PATCH :
{
2023-03-17 09:40:20 -04:00
// TODO: This is optimized for memory-usage but base and patch could be requested at the same time
2023-12-19 05:19:14 -05:00
OP : : ImagePatchArgs args = Program . GetOpArgs < OP : : ImagePatchArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2023-03-17 09:40:20 -04:00
case 0 :
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ;
break ;
2022-09-26 15:12:13 -04:00
2023-03-17 09:40:20 -04:00
case 1 :
AddOp ( FScheduledOp ( item . At , item , 2 ) , FScheduledOp ( args . patch , item ) ) ;
break ;
case 2 :
2022-09-26 15:12:13 -04:00
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_PATCH_1 )
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Ptr < const Image > pA = LoadImage ( FCacheAddress ( args . base , item ) ) ;
Ptr < const Image > pB = LoadImage ( FCacheAddress ( args . patch , item ) ) ;
2022-09-26 15:12:13 -04:00
2022-11-11 14:56:03 -05:00
// Failsafe
if ( ! pA | | ! pB )
{
2023-05-24 02:50:03 -04:00
Release ( pB ) ;
StoreImage ( item , pA ) ;
2022-11-11 14:56:03 -05:00
break ;
}
2023-03-17 09:40:20 -04:00
// Apply the mipmap reduction to the crop rectangle.
2022-11-23 03:17:56 -05:00
int32 MipsToSkip = item . ExecutionOptions ;
2024-08-13 03:25:12 -04:00
box < FIntVector2 > rect ;
2023-03-17 09:40:20 -04:00
rect . min [ 0 ] = args . minX / ( 1 < < MipsToSkip ) ;
rect . min [ 1 ] = args . minY / ( 1 < < MipsToSkip ) ;
rect . size [ 0 ] = pB - > GetSizeX ( ) ;
rect . size [ 1 ] = pB - > GetSizeY ( ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
ImagePtr pResult = CloneOrTakeOver ( pA ) ;
2022-09-26 15:12:13 -04:00
bool bApplyPatch = ! rect . IsEmpty ( ) ;
if ( bApplyPatch )
{
// Change the block image format if it doesn't match the composed image
// This is usually enforced at object compilation time.
if ( pResult - > GetFormat ( ) ! = pB - > GetFormat ( ) )
{
2023-06-23 02:01:13 -04:00
MUTABLE_CPUPROFILER_SCOPE ( ImagPatchReformat ) ;
2022-09-26 15:12:13 -04:00
EImageFormat format = GetMostGenericFormat ( pResult - > GetFormat ( ) , pB - > GetFormat ( ) ) ;
const FImageFormatData & finfo = GetImageFormatData ( format ) ;
2023-06-23 02:01:13 -04:00
if ( finfo . PixelsPerBlockX = = 0 )
2022-09-26 15:12:13 -04:00
{
format = GetUncompressedFormat ( format ) ;
}
if ( pResult - > GetFormat ( ) ! = format )
{
2023-05-24 02:50:03 -04:00
Ptr < Image > Formatted = CreateImage ( pResult - > GetSizeX ( ) , pResult - > GetSizeY ( ) , pResult - > GetLODCount ( ) , format , EInitializationType : : NotInitialized ) ;
bool bSuccess = false ;
2023-06-23 02:01:13 -04:00
ImOp . ImagePixelFormat ( bSuccess , m_pSettings - > ImageCompressionQuality , Formatted . get ( ) , pResult . get ( ) ) ;
2023-05-24 02:50:03 -04:00
check ( bSuccess ) ;
Release ( pResult ) ;
pResult = Formatted ;
2022-09-26 15:12:13 -04:00
}
if ( pB - > GetFormat ( ) ! = format )
{
2023-05-24 02:50:03 -04:00
Ptr < Image > Formatted = CreateImage ( pB - > GetSizeX ( ) , pB - > GetSizeY ( ) , pB - > GetLODCount ( ) , format , EInitializationType : : NotInitialized ) ;
bool bSuccess = false ;
2023-06-23 02:01:13 -04:00
ImOp . ImagePixelFormat ( bSuccess , m_pSettings - > ImageCompressionQuality , Formatted . get ( ) , pB . get ( ) ) ;
2023-05-24 02:50:03 -04:00
check ( bSuccess ) ;
Release ( pB ) ;
2024-02-15 12:08:31 -05:00
pB = Formatted ;
2022-09-26 15:12:13 -04:00
}
}
// Don't patch if below the image compression block size.
const FImageFormatData & finfo = GetImageFormatData ( pResult - > GetFormat ( ) ) ;
bApplyPatch =
2023-06-23 02:01:13 -04:00
( rect . min [ 0 ] % finfo . PixelsPerBlockX = = 0 ) & &
( rect . min [ 1 ] % finfo . PixelsPerBlockY = = 0 ) & &
( rect . size [ 0 ] % finfo . PixelsPerBlockX = = 0 ) & &
( rect . size [ 1 ] % finfo . PixelsPerBlockY = = 0 ) & &
2022-09-26 15:12:13 -04:00
( rect . min [ 0 ] + rect . size [ 0 ] ) < = pResult - > GetSizeX ( ) & &
( rect . min [ 1 ] + rect . size [ 1 ] ) < = pResult - > GetSizeY ( )
;
}
if ( bApplyPatch )
{
2023-06-23 02:01:13 -04:00
ImOp . ImageCompose ( pResult . get ( ) , pB . get ( ) , rect ) ;
2022-09-26 15:12:13 -04:00
pResult - > m_flags = 0 ;
}
else
{
// This happens very often when skipping mips, and floods the log.
//UE_LOG( LogMutableCore, Verbose, TEXT("Skipped patch operation for image not fitting the block compression size. Small image? Patch rect is (%d, %d), (%d, %d), base is (%d, %d)"),
// rect.min[0], rect.min[1], rect.size[0], rect.size[1], pResult->GetSizeX(), pResult->GetSizeY());
}
2023-05-24 02:50:03 -04:00
Release ( pB ) ;
StoreImage ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_RASTERMESH :
{
2023-12-19 05:19:14 -05:00
OP : : ImageRasterMeshArgs args = Program . GetOpArgs < OP : : ImageRasterMeshArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-03-01 10:04:25 -05:00
if ( args . image )
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
2024-08-13 10:23:49 -04:00
FScheduledOp : : FromOpAndOptions ( args . mesh , item , 0 ) ,
2023-03-01 10:04:25 -05:00
FScheduledOp : : FromOpAndOptions ( args . projector , item , 0 ) ) ;
}
else
{
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
2024-08-13 10:23:49 -04:00
FScheduledOp : : FromOpAndOptions ( args . mesh , item , 0 ) ) ;
2023-03-01 10:04:25 -05:00
}
2022-09-26 15:12:13 -04:00
break ;
2023-03-17 09:40:20 -04:00
2023-03-01 10:04:25 -05:00
case 1 :
{
2023-03-09 09:42:19 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_RASTERMESH_1 )
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
Ptr < const Mesh > pMesh = LoadMesh ( FScheduledOp : : FromOpAndOptions ( args . mesh , item , 0 ) ) ;
2023-03-17 09:40:20 -04:00
2023-03-09 09:42:19 -05:00
// If no image, we are generating a flat mesh UV raster. This is the final stage in this case.
2023-03-01 10:04:25 -05:00
if ( ! args . image )
{
uint16 SizeX = args . sizeX ;
uint16 SizeY = args . sizeY ;
2023-03-17 09:40:20 -04:00
UE : : Math : : TIntVector2 < uint16 > CropMin ( args . CropMinX , args . CropMinY ) ;
UE : : Math : : TIntVector2 < uint16 > UncroppedSize ( args . UncroppedSizeX , args . UncroppedSizeY ) ;
2023-03-01 10:04:25 -05:00
// Drop mips while possible
int32 MipsToDrop = item . ExecutionOptions ;
2023-03-17 09:40:20 -04:00
bool bUseCrop = UncroppedSize [ 0 ] > 0 ;
2023-03-01 10:04:25 -05:00
while ( MipsToDrop & & ! ( SizeX % 2 ) & & ! ( SizeY % 2 ) )
{
2023-03-17 09:40:20 -04:00
SizeX = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( SizeX , uint16 ( 2 ) ) ) ;
SizeY = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( SizeY , uint16 ( 2 ) ) ) ;
if ( bUseCrop )
{
CropMin [ 0 ] = FMath : : DivideAndRoundUp ( CropMin [ 0 ] , uint16 ( 2 ) ) ;
CropMin [ 1 ] = FMath : : DivideAndRoundUp ( CropMin [ 1 ] , uint16 ( 2 ) ) ;
UncroppedSize [ 0 ] = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( UncroppedSize [ 0 ] , uint16 ( 2 ) ) ) ;
UncroppedSize [ 1 ] = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( UncroppedSize [ 1 ] , uint16 ( 2 ) ) ) ;
}
2023-03-01 10:04:25 -05:00
- - MipsToDrop ;
}
// Flat mesh UV raster
2023-06-23 02:01:13 -04:00
Ptr < Image > ResultImage = CreateImage ( SizeX , SizeY , 1 , EImageFormat : : IF_L_UBYTE , EInitializationType : : Black ) ;
2023-03-09 09:42:19 -05:00
if ( pMesh )
{
2024-05-13 03:20:24 -04:00
ImageRasterMesh ( pMesh . get ( ) , ResultImage . get ( ) , args . LayoutIndex , args . BlockId , CropMin , UncroppedSize ) ;
2023-06-15 04:45:22 -04:00
Release ( pMesh ) ;
2023-03-09 09:42:19 -05:00
}
2023-03-01 10:04:25 -05:00
// Stop execution.
2023-05-24 02:50:03 -04:00
StoreImage ( item , ResultImage ) ;
2023-03-01 10:04:25 -05:00
break ;
}
const int32 MipsToSkip = item . ExecutionOptions ;
int32 ProjectionMip = MipsToSkip ;
2023-04-28 15:56:53 -04:00
FScheduledOpData Data ;
Data . RasterMesh . Mip = ProjectionMip ;
Data . RasterMesh . MipValue = static_cast < float > ( ProjectionMip ) ;
2023-06-06 02:00:32 -04:00
FProjector Projector = LoadProjector ( FScheduledOp : : FromOpAndOptions ( args . projector , item , 0 ) ) ;
EMinFilterMethod MinFilterMethod = Invoke ( [ & ] ( ) - > EMinFilterMethod
2023-03-01 10:04:25 -05:00
{
2023-06-06 02:00:32 -04:00
if ( ForcedProjectionMode = = 0 )
2023-05-03 12:48:24 -04:00
{
2023-06-06 02:00:32 -04:00
return EMinFilterMethod : : None ;
}
else if ( ForcedProjectionMode = = 1 )
2023-03-01 10:04:25 -05:00
{
2023-06-06 02:00:32 -04:00
return EMinFilterMethod : : TotalAreaHeuristic ;
}
2023-03-09 09:42:19 -05:00
2023-06-06 02:00:32 -04:00
return static_cast < EMinFilterMethod > ( args . MinFilterMethod ) ;
} ) ;
2023-04-28 15:56:53 -04:00
2023-06-06 02:00:32 -04:00
if ( MinFilterMethod = = EMinFilterMethod : : TotalAreaHeuristic )
{
FVector2f TargetImageSizeF = FVector2f (
FMath : : Max ( args . sizeX > > MipsToSkip , 1 ) ,
FMath : : Max ( args . sizeY > > MipsToSkip , 1 ) ) ;
FVector2f SourceImageSizeF = FVector2f ( args . SourceSizeX , args . SourceSizeY ) ;
if ( pMesh )
{
const float ComputedMip = ComputeProjectedFootprintBestMip ( pMesh . get ( ) , Projector , TargetImageSizeF , SourceImageSizeF ) ;
Data . RasterMesh . MipValue = FMath : : Max ( 0.0f , ComputedMip + GlobalProjectionLodBias ) ;
Data . RasterMesh . Mip = static_cast < uint8 > ( FMath : : FloorToInt32 ( Data . RasterMesh . MipValue ) ) ;
2023-03-01 10:04:25 -05:00
}
}
2023-06-15 04:45:22 -04:00
const int32 DataHeapAddress = m_heapData . Add ( Data ) ;
2023-03-01 10:04:25 -05:00
2023-06-15 04:45:22 -04:00
// pMesh is need again in the next stage, store it in the heap.
m_heapData [ DataHeapAddress ] . Resource = const_cast < Mesh * > ( pMesh . get ( ) ) ;
2023-04-28 15:56:53 -04:00
AddOp ( FScheduledOp ( item . At , item , 2 , DataHeapAddress ) ,
2023-03-01 10:04:25 -05:00
FScheduledOp : : FromOpAndOptions ( args . projector , item , 0 ) ,
2023-04-28 15:56:53 -04:00
FScheduledOp : : FromOpAndOptions ( args . image , item , Data . RasterMesh . Mip ) ,
2023-03-01 10:04:25 -05:00
FScheduledOp ( args . mask , item ) ,
FScheduledOp : : FromOpAndOptions ( args . angleFadeProperties , item , 0 ) ) ;
break ;
}
2023-03-17 09:40:20 -04:00
2023-03-01 10:04:25 -05:00
case 2 :
{
MUTABLE_CPUPROFILER_SCOPE ( IM_RASTERMESH_2 )
if ( ! args . image )
{
// This case is treated at the previous stage.
check ( false ) ;
2023-05-24 02:50:03 -04:00
StoreImage ( item , nullptr ) ;
2023-03-01 10:04:25 -05:00
break ;
}
2023-06-15 04:45:22 -04:00
FScheduledOpData & Data = m_heapData [ item . CustomState ] ;
// Unsafe downcast, should be fine as it is known to be a Mesh.
Ptr < const Mesh > pMesh = static_cast < Mesh * > ( Data . Resource . get ( ) ) ;
Data . Resource = nullptr ;
2022-09-26 15:12:13 -04:00
2023-03-17 09:40:20 -04:00
if ( ! pMesh )
{
check ( false ) ;
2023-05-24 02:50:03 -04:00
StoreImage ( item , nullptr ) ;
2023-03-17 09:40:20 -04:00
break ;
}
2022-09-26 15:12:13 -04:00
uint16 SizeX = args . sizeX ;
uint16 SizeY = args . sizeY ;
2023-03-17 09:40:20 -04:00
UE : : Math : : TIntVector2 < uint16 > CropMin ( args . CropMinX , args . CropMinY ) ;
UE : : Math : : TIntVector2 < uint16 > UncroppedSize ( args . UncroppedSizeX , args . UncroppedSizeY ) ;
2022-09-26 15:12:13 -04:00
// Drop mips while possible
2022-11-23 03:17:56 -05:00
int32 MipsToDrop = item . ExecutionOptions ;
2023-03-17 09:40:20 -04:00
bool bUseCrop = UncroppedSize [ 0 ] > 0 ;
2022-09-26 15:12:13 -04:00
while ( MipsToDrop & & ! ( SizeX % 2 ) & & ! ( SizeY % 2 ) )
{
SizeX = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( SizeX , uint16 ( 2 ) ) ) ;
SizeY = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( SizeY , uint16 ( 2 ) ) ) ;
2023-03-17 09:40:20 -04:00
if ( bUseCrop )
{
CropMin [ 0 ] = FMath : : DivideAndRoundUp ( CropMin [ 0 ] , uint16 ( 2 ) ) ;
CropMin [ 1 ] = FMath : : DivideAndRoundUp ( CropMin [ 1 ] , uint16 ( 2 ) ) ;
UncroppedSize [ 0 ] = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( UncroppedSize [ 0 ] , uint16 ( 2 ) ) ) ;
UncroppedSize [ 1 ] = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( UncroppedSize [ 1 ] , uint16 ( 2 ) ) ) ;
}
2022-09-26 15:12:13 -04:00
- - MipsToDrop ;
}
2023-03-01 10:04:25 -05:00
// Raster with projection
2023-05-24 02:50:03 -04:00
Ptr < const Image > Source = LoadImage ( FCacheAddress ( args . image , item . ExecutionIndex , Data . RasterMesh . Mip ) ) ;
2023-03-01 10:04:25 -05:00
2023-05-24 02:50:03 -04:00
Ptr < const Image > Mask = nullptr ;
2023-03-01 10:04:25 -05:00
if ( args . mask )
{
2023-05-24 02:50:03 -04:00
Mask = LoadImage ( FCacheAddress ( args . mask , item ) ) ;
2023-03-01 10:04:25 -05:00
// TODO: This shouldn't happen, but be defensive.
FImageSize ResultSize ( SizeX , SizeY ) ;
2023-05-24 02:50:03 -04:00
if ( Mask & & Mask - > GetSize ( ) ! = ResultSize )
2023-03-01 10:04:25 -05:00
{
MUTABLE_CPUPROFILER_SCOPE ( ImageResize_MaskFixForProjection ) ;
2023-05-24 02:50:03 -04:00
Ptr < Image > Resized = CreateImage ( SizeX , SizeY , Mask - > GetLODCount ( ) , Mask - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
2023-06-23 02:01:13 -04:00
ImOp . ImageResizeLinear ( Resized . get ( ) , 0 , Mask . get ( ) ) ;
2023-05-24 02:50:03 -04:00
Release ( Mask ) ;
Mask = Resized ;
2023-03-01 10:04:25 -05:00
}
}
float fadeStart = 180.0f ;
float fadeEnd = 180.0f ;
if ( args . angleFadeProperties )
{
2023-05-24 02:50:03 -04:00
FVector4f fadeProperties = LoadColor ( FScheduledOp : : FromOpAndOptions ( args . angleFadeProperties , item , 0 ) ) ;
2023-03-01 10:04:25 -05:00
fadeStart = fadeProperties [ 0 ] ;
fadeEnd = fadeProperties [ 1 ] ;
}
const float FadeStartRad = FMath : : DegreesToRadians ( fadeStart ) ;
const float FadeEndRad = FMath : : DegreesToRadians ( fadeEnd ) ;
2023-05-24 02:50:03 -04:00
EImageFormat Format = Source ? GetUncompressedFormat ( Source - > GetFormat ( ) ) : EImageFormat : : IF_L_UBYTE ;
2023-03-01 10:04:25 -05:00
2023-05-24 02:50:03 -04:00
if ( Source & & Source - > GetFormat ( ) ! = Format )
2023-03-01 10:04:25 -05:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_RasterMesh_ReformatSource ) ;
2023-05-24 02:50:03 -04:00
Ptr < Image > Formatted = CreateImage ( Source - > GetSizeX ( ) , Source - > GetSizeY ( ) , Source - > GetLODCount ( ) , Format , EInitializationType : : NotInitialized ) ;
bool bSuccess = false ;
2023-06-23 02:01:13 -04:00
ImOp . ImagePixelFormat ( bSuccess , m_pSettings - > ImageCompressionQuality , Formatted . get ( ) , Source . get ( ) ) ;
2023-05-24 02:50:03 -04:00
check ( bSuccess ) ;
Release ( Source ) ;
Source = Formatted ;
2023-03-01 10:04:25 -05:00
}
2024-10-01 20:09:26 -04:00
EMinFilterMethod MinFilterMethod = Invoke ( [ & ] ( ) - > EMinFilterMethod
{
if ( ForcedProjectionMode = = 0 )
{
return EMinFilterMethod : : None ;
}
else if ( ForcedProjectionMode = = 1 )
{
return EMinFilterMethod : : TotalAreaHeuristic ;
}
return static_cast < EMinFilterMethod > ( args . MinFilterMethod ) ;
} ) ;
if ( MinFilterMethod = = EMinFilterMethod : : TotalAreaHeuristic )
{
const uint16 Mip = Data . RasterMesh . Mip ;
const FImageSize ExpectedSourceSize = FImageSize (
FMath : : Max < uint16 > ( args . SourceSizeX > > Mip , 1 ) ,
FMath : : Max < uint16 > ( args . SourceSizeY > > Mip , 1 ) ) ;
if ( Source - > GetSize ( ) ! = ExpectedSourceSize )
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_ImageRasterMesh_SizeFixup ) ;
Ptr < Image > Resized = CreateImage ( ExpectedSourceSize . X , ExpectedSourceSize . Y , 1 , Format , EInitializationType : : NotInitialized ) ;
ImOp . ImageResizeLinear ( Resized . get ( ) , m_pSettings - > ImageCompressionQuality , Source . get ( ) ) ;
Release ( Source ) ;
Source = Resized ;
}
}
2023-03-01 10:04:25 -05:00
// Allocate memory for the temporary buffers
2023-09-18 05:57:38 -04:00
FScratchImageProject Scratch ;
Scratch . Vertices . SetNum ( pMesh - > GetVertexCount ( ) ) ;
Scratch . CulledVertex . SetNum ( pMesh - > GetVertexCount ( ) ) ;
2023-03-01 10:04:25 -05:00
2023-05-03 12:48:24 -04:00
ESamplingMethod SamplingMethod = Invoke ( [ & ] ( ) - > ESamplingMethod
{
2023-05-12 05:07:47 -04:00
if ( ForcedProjectionMode = = 0 )
2023-05-03 12:48:24 -04:00
{
return ESamplingMethod : : Point ;
}
else if ( ForcedProjectionMode = = 1 )
{
return ESamplingMethod : : BiLinear ;
}
return static_cast < ESamplingMethod > ( args . SamplingMethod ) ;
} ) ;
2023-04-28 15:56:53 -04:00
if ( SamplingMethod = = ESamplingMethod : : BiLinear )
{
2023-05-24 02:50:03 -04:00
if ( Source - > GetLODCount ( ) < 2 & & Source - > GetSizeX ( ) > 1 & & Source - > GetSizeY ( ) > 1 )
2023-04-28 15:56:53 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_RasterMesh_BilinearMipGen ) ;
2024-03-12 07:17:49 -04:00
Ptr < Image > OwnedSource = CloneOrTakeOver ( Source ) ;
2023-04-28 15:56:53 -04:00
2024-03-12 07:17:49 -04:00
OwnedSource - > DataStorage . SetNumLODs ( 2 ) ;
ImageMipmapInPlace ( 0 , OwnedSource . get ( ) , FMipmapGenerationSettings { } ) ;
2023-04-28 15:56:53 -04:00
2024-03-12 07:17:49 -04:00
Source = OwnedSource ;
2023-04-28 15:56:53 -04:00
}
}
2023-03-01 10:04:25 -05:00
2023-05-03 12:48:24 -04:00
// Allocate new image after bilinear mip generation to reduce operation memory peak.
2023-06-23 02:01:13 -04:00
Ptr < Image > New = CreateImage ( SizeX , SizeY , 1 , Format , EInitializationType : : Black ) ;
2023-05-03 12:48:24 -04:00
2023-05-24 02:50:03 -04:00
if ( args . projector & & Source & & Source - > GetSizeX ( ) > 0 & & Source - > GetSizeY ( ) > 0 )
2023-03-01 10:04:25 -05:00
{
2023-06-06 02:00:32 -04:00
FProjector Projector = LoadProjector ( FScheduledOp : : FromOpAndOptions ( args . projector , item , 0 ) ) ;
switch ( Projector . type )
2023-03-01 10:04:25 -05:00
{
2023-06-06 02:00:32 -04:00
case PROJECTOR_TYPE : : PLANAR :
2023-06-23 02:01:13 -04:00
ImageRasterProjectedPlanar ( pMesh . get ( ) , New . get ( ) ,
2023-06-06 02:00:32 -04:00
Source . get ( ) , Mask . get ( ) ,
args . bIsRGBFadingEnabled , args . bIsAlphaFadingEnabled ,
SamplingMethod ,
FadeStartRad , FadeEndRad , FMath : : Frac ( Data . RasterMesh . MipValue ) ,
2024-05-13 03:20:24 -04:00
args . LayoutIndex , args . BlockId ,
2023-06-06 02:00:32 -04:00
CropMin , UncroppedSize ,
2023-09-18 05:57:38 -04:00
& Scratch , bUseProjectionVectorImpl ) ;
2023-06-06 02:00:32 -04:00
break ;
2023-03-01 10:04:25 -05:00
2023-06-06 02:00:32 -04:00
case PROJECTOR_TYPE : : WRAPPING :
2023-06-23 02:01:13 -04:00
ImageRasterProjectedWrapping ( pMesh . get ( ) , New . get ( ) ,
2023-06-06 02:00:32 -04:00
Source . get ( ) , Mask . get ( ) ,
args . bIsRGBFadingEnabled , args . bIsAlphaFadingEnabled ,
SamplingMethod ,
FadeStartRad , FadeEndRad , FMath : : Frac ( Data . RasterMesh . MipValue ) ,
2024-05-13 03:20:24 -04:00
args . LayoutIndex , args . BlockId ,
2023-06-06 02:00:32 -04:00
CropMin , UncroppedSize ,
2023-09-18 05:57:38 -04:00
& Scratch , bUseProjectionVectorImpl ) ;
2023-06-06 02:00:32 -04:00
break ;
2023-03-01 10:04:25 -05:00
2023-06-06 02:00:32 -04:00
case PROJECTOR_TYPE : : CYLINDRICAL :
2023-06-23 02:01:13 -04:00
ImageRasterProjectedCylindrical ( pMesh . get ( ) , New . get ( ) ,
2023-06-06 02:00:32 -04:00
Source . get ( ) , Mask . get ( ) ,
args . bIsRGBFadingEnabled , args . bIsAlphaFadingEnabled ,
2023-09-18 05:57:38 -04:00
SamplingMethod ,
FadeStartRad , FadeEndRad , FMath : : Frac ( Data . RasterMesh . MipValue ) ,
2023-08-03 03:37:44 -04:00
args . LayoutIndex ,
2023-06-06 02:00:32 -04:00
Projector . projectionAngle ,
CropMin , UncroppedSize ,
2023-09-18 05:57:38 -04:00
& Scratch , bUseProjectionVectorImpl ) ;
2023-06-06 02:00:32 -04:00
break ;
2023-03-01 10:04:25 -05:00
2023-06-06 02:00:32 -04:00
default :
check ( false ) ;
break ;
2023-03-01 10:04:25 -05:00
}
}
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
Release ( pMesh ) ;
2023-05-24 02:50:03 -04:00
Release ( Source ) ;
Release ( Mask ) ;
2023-06-23 02:01:13 -04:00
StoreImage ( item , New ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_MAKEGROWMAP :
{
2023-12-19 05:19:14 -05:00
OP : : ImageMakeGrowMapArgs args = Program . GetOpArgs < OP : : ImageMakeGrowMapArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . mask , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_MAKEGROWMAP_1 )
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Ptr < const Image > Mask = LoadImage ( FCacheAddress ( args . mask , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-06-23 02:01:13 -04:00
Ptr < Image > Result = CreateImage ( Mask - > GetSizeX ( ) , Mask - > GetSizeY ( ) , Mask - > GetLODCount ( ) , EImageFormat : : IF_L_UBYTE , EInitializationType : : NotInitialized ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
ImageMakeGrowMap ( Result . get ( ) , Mask . get ( ) , args . border ) ;
Result - > m_flags | = Image : : IF_CANNOT_BE_SCALED ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Release ( Mask ) ;
StoreImage ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_DISPLACE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageDisplaceArgs args = Program . GetOpArgs < OP : : ImageDisplaceArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . source , item ) ,
FScheduledOp ( args . displacementMap , item ) ) ;
break ;
2022-09-26 15:12:13 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_DISPLACE_1 )
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Ptr < const Image > Source = LoadImage ( FCacheAddress ( args . source , item ) ) ;
Ptr < const Image > pMap = LoadImage ( FCacheAddress ( args . displacementMap , item ) ) ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
if ( ! Source )
2023-04-04 08:43:43 -04:00
{
2023-05-24 02:50:03 -04:00
Release ( pMap ) ;
StoreImage ( item , nullptr ) ;
2023-04-04 08:43:43 -04:00
break ;
}
2022-09-26 15:12:13 -04:00
// TODO: This shouldn't happen: displacement maps cannot be scaled because their information
// is resolution sensitive (pixel offsets). If the size doesn't match, scale the source, apply
// displacement and then unscale it.
2023-05-24 02:50:03 -04:00
FImageSize OriginalSourceScale = Source - > GetSize ( ) ;
2023-03-08 04:37:54 -05:00
if ( OriginalSourceScale [ 0 ] > 0 & & OriginalSourceScale [ 1 ] > 0 & & OriginalSourceScale ! = pMap - > GetSize ( ) )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( ImageResize_EmergencyHackForDisplacementStep1 ) ;
2023-05-24 02:50:03 -04:00
Ptr < Image > Resized = CreateImage ( pMap - > GetSizeX ( ) , pMap - > GetSizeY ( ) , Source - > GetLODCount ( ) , Source - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
2023-06-23 02:01:13 -04:00
ImOp . ImageResizeLinear ( Resized . get ( ) , 0 , Source . get ( ) ) ;
2023-05-24 02:50:03 -04:00
Release ( Source ) ;
Source = Resized ;
2022-09-26 15:12:13 -04:00
}
2022-11-02 12:53:04 -04:00
// This works based on the assumption that displacement maps never read from a position they actually write to.
// Since they are used for UV border expansion, this should always be the case.
2023-05-24 02:50:03 -04:00
Ptr < Image > Result = CloneOrTakeOver ( Source ) ;
2022-09-26 15:12:13 -04:00
2023-03-08 04:37:54 -05:00
if ( OriginalSourceScale [ 0 ] > 0 & & OriginalSourceScale [ 1 ] > 0 )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
ImageDisplace ( Result . get ( ) , Result . get ( ) , pMap . get ( ) ) ;
2022-12-05 05:01:41 -05:00
2023-05-24 02:50:03 -04:00
if ( OriginalSourceScale ! = Result - > GetSize ( ) )
2022-12-05 05:01:41 -05:00
{
MUTABLE_CPUPROFILER_SCOPE ( ImageResize_EmergencyHackForDisplacementStep2 ) ;
2023-05-24 02:50:03 -04:00
Ptr < Image > Resized = CreateImage ( OriginalSourceScale [ 0 ] , OriginalSourceScale [ 1 ] , Result - > GetLODCount ( ) , Result - > GetFormat ( ) , EInitializationType : : NotInitialized ) ;
2023-06-23 02:01:13 -04:00
ImOp . ImageResizeLinear ( Resized . get ( ) , 0 , Result . get ( ) ) ;
2023-05-24 02:50:03 -04:00
Release ( Result ) ;
Result = Resized ;
2022-12-05 05:01:41 -05:00
}
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
Release ( pMap ) ;
StoreImage ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_TRANSFORM :
{
2023-12-19 05:19:14 -05:00
const OP : : ImageTransformArgs Args = Program . GetOpArgs < OP : : ImageTransformArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
2023-08-21 05:50:06 -04:00
const TArray < FScheduledOp , TFixedAllocator < 2 > > Deps =
{
2023-08-23 05:27:20 -04:00
FScheduledOp ( Args . ScaleX , item ) ,
FScheduledOp ( Args . ScaleY , item ) ,
2023-08-21 05:50:06 -04:00
} ;
2022-09-26 15:12:13 -04:00
2023-06-22 06:08:36 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , Deps ) ;
2022-09-26 15:12:13 -04:00
break ;
}
2023-08-21 05:50:06 -04:00
case 1 :
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( IM_TRANSFORM_1 )
2022-09-26 15:12:13 -04:00
2023-09-04 05:31:06 -04:00
FVector2f Scale = FVector2f (
2023-08-23 05:27:20 -04:00
Args . ScaleX ? LoadScalar ( FCacheAddress ( Args . ScaleX , item ) ) : 1.0f ,
Args . ScaleY ? LoadScalar ( FCacheAddress ( Args . ScaleY , item ) ) : 1.0f ) ;
2023-08-21 05:50:06 -04:00
using FUint16Vector2 = UE : : Math : : TIntVector2 < uint16 > ;
const FUint16Vector2 DestSizeI = Invoke ( [ & ] ( )
{
int32 MipsToDrop = item . ExecutionOptions ;
FUint16Vector2 Size = FUint16Vector2 (
Args . SizeX > 0 ? Args . SizeX : Args . SourceSizeX ,
Args . SizeY > 0 ? Args . SizeY : Args . SourceSizeY ) ;
while ( MipsToDrop & & ! ( Size . X % 2 ) & & ! ( Size . Y % 2 ) )
{
Size . X = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( Size . X , uint16 ( 2 ) ) ) ;
Size . Y = FMath : : Max ( uint16 ( 1 ) , FMath : : DivideAndRoundUp ( Size . Y , uint16 ( 2 ) ) ) ;
- - MipsToDrop ;
}
2023-09-04 05:31:06 -04:00
return FUint16Vector2 ( FMath : : Max ( Size . X , uint16 ( 1 ) ) , FMath : : Max ( Size . Y , uint16 ( 1 ) ) ) ;
2023-08-21 05:50:06 -04:00
} ) ;
2023-09-04 05:31:06 -04:00
const FVector2f DestSize = FVector2f ( DestSizeI . X , DestSizeI . Y ) ;
const FVector2f SourceSize = FVector2f ( FMath : : Max ( Args . SourceSizeX , uint16 ( 1 ) ) , FMath : : Max ( Args . SourceSizeY , uint16 ( 1 ) ) ) ;
FVector2f AspectCorrectionScale = FVector2f ( 1.0f , 1.0f ) ;
2023-08-23 05:27:20 -04:00
if ( Args . bKeepAspectRatio )
{
2023-09-04 05:31:06 -04:00
const float DestAspectOverSrcAspect = ( DestSize . X * SourceSize . Y ) / ( DestSize . Y * SourceSize . X ) ;
2023-08-21 05:50:06 -04:00
2023-09-04 05:31:06 -04:00
AspectCorrectionScale = DestAspectOverSrcAspect > 1.0f
? FVector2f ( 1.0f / DestAspectOverSrcAspect , 1.0f )
: FVector2f ( 1.0f , DestAspectOverSrcAspect ) ;
2023-08-23 05:27:20 -04:00
}
2023-08-21 05:50:06 -04:00
2023-08-23 05:27:20 -04:00
const FTransform2f Transform = FTransform2f ( FVector2f ( - 0.5f ) )
. Concatenate ( FTransform2f ( FScale2f ( Scale ) ) )
2023-09-04 05:31:06 -04:00
. Concatenate ( FTransform2f ( FScale2f ( AspectCorrectionScale ) ) )
2023-08-23 05:27:20 -04:00
. Concatenate ( FTransform2f ( FVector2f ( 0.5f ) ) ) ;
2023-08-21 05:50:06 -04:00
FBox2f NormalizedCropRect ( ForceInit ) ;
NormalizedCropRect + = Transform . TransformPoint ( FVector2f ( 0.0f , 0.0f ) ) ;
NormalizedCropRect + = Transform . TransformPoint ( FVector2f ( 1.0f , 0.0f ) ) ;
NormalizedCropRect + = Transform . TransformPoint ( FVector2f ( 0.0f , 1.0f ) ) ;
NormalizedCropRect + = Transform . TransformPoint ( FVector2f ( 1.0f , 1.0f ) ) ;
const FVector2f ScaledSourceSize = NormalizedCropRect . GetSize ( ) * DestSize ;
const float BestMip =
FMath : : Log2 ( FMath : : Max ( 1.0f , FMath : : Square ( SourceSize . GetMin ( ) ) ) ) * 0.5f -
FMath : : Log2 ( FMath : : Max ( 1.0f , FMath : : Square ( ScaledSourceSize . GetMin ( ) ) ) ) * 0.5f ;
FScheduledOpData HeapData ;
HeapData . ImageTransform . SizeX = DestSizeI . X ;
HeapData . ImageTransform . SizeY = DestSizeI . Y ;
2023-09-04 05:31:06 -04:00
FPlatformMath : : StoreHalf ( & HeapData . ImageTransform . ScaleXEncodedHalf , Scale . X ) ;
FPlatformMath : : StoreHalf ( & HeapData . ImageTransform . ScaleYEncodedHalf , Scale . Y ) ;
2023-08-21 05:50:06 -04:00
HeapData . ImageTransform . MipValue = BestMip + GlobalImageTransformLodBias ;
const int32 HeapDataAddress = m_heapData . Add ( HeapData ) ;
const uint8 Mip = static_cast < uint8 > ( FMath : : Max ( 0 , FMath : : FloorToInt ( HeapData . ImageTransform . MipValue ) ) ) ;
const TArray < FScheduledOp , TFixedAllocator < 4 > > Deps =
{
2023-08-23 05:27:20 -04:00
FScheduledOp : : FromOpAndOptions ( Args . Base , item , Mip ) ,
FScheduledOp ( Args . OffsetX , item ) ,
FScheduledOp ( Args . OffsetY , item ) ,
FScheduledOp ( Args . Rotation , item )
2023-08-21 05:50:06 -04:00
} ;
AddOp ( FScheduledOp ( item . At , item , 2 , HeapDataAddress ) , Deps ) ;
break ;
}
case 2 :
{
MUTABLE_CPUPROFILER_SCOPE ( IM_TRANSFORM_2 ) ;
const FScheduledOpData HeapData = m_heapData [ item . CustomState ] ;
const uint8 Mip = static_cast < uint8 > ( FMath : : Max ( 0 , FMath : : FloorToInt ( HeapData . ImageTransform . MipValue ) ) ) ;
2023-08-23 05:27:20 -04:00
Ptr < const Image > Source = LoadImage ( FCacheAddress ( Args . Base , item . ExecutionIndex , Mip ) ) ;
2023-08-21 05:50:06 -04:00
const FVector2f Offset = FVector2f (
2023-08-23 05:27:20 -04:00
Args . OffsetX ? LoadScalar ( FCacheAddress ( Args . OffsetX , item ) ) : 0.0f ,
Args . OffsetY ? LoadScalar ( FCacheAddress ( Args . OffsetY , item ) ) : 0.0f ) ;
2023-08-21 05:50:06 -04:00
2023-09-04 05:31:06 -04:00
FVector2f Scale = FVector2f (
2023-08-21 05:50:06 -04:00
FPlatformMath : : LoadHalf ( & HeapData . ImageTransform . ScaleXEncodedHalf ) ,
FPlatformMath : : LoadHalf ( & HeapData . ImageTransform . ScaleYEncodedHalf ) ) ;
2022-09-26 15:12:13 -04:00
2023-09-04 05:31:06 -04:00
FVector2f AspectCorrectionScale = FVector2f ( 1.0f , 1.0f ) ;
if ( Args . bKeepAspectRatio )
{
const FVector2f DestSize = FVector2f ( HeapData . ImageTransform . SizeX , HeapData . ImageTransform . SizeY ) ;
const FVector2f SourceSize = FVector2f ( FMath : : Max ( Args . SourceSizeX , uint16 ( 1 ) ) , FMath : : Max ( Args . SourceSizeY , uint16 ( 1 ) ) ) ;
const float DestAspectOverSrcAspect = ( DestSize . X * SourceSize . Y ) / ( DestSize . Y * SourceSize . X ) ;
AspectCorrectionScale = DestAspectOverSrcAspect > 1.0f
? FVector2f ( 1.0f / DestAspectOverSrcAspect , 1.0f )
: FVector2f ( 1.0f , DestAspectOverSrcAspect ) ;
}
// Map Range [0..1] to a full rotation
const float RotationRad = LoadScalar ( FCacheAddress ( Args . Rotation , item ) ) * UE_TWO_PI ;
2022-09-26 15:12:13 -04:00
2023-08-21 05:50:06 -04:00
EImageFormat SourceFormat = Source - > GetFormat ( ) ;
EImageFormat Format = GetUncompressedFormat ( SourceFormat ) ;
2022-09-26 15:12:13 -04:00
2023-08-21 05:50:06 -04:00
if ( Format ! = SourceFormat )
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_ImageTransform_FormatFixup ) ;
Ptr < Image > Formatted = CreateImage ( Source - > GetSizeX ( ) , Source - > GetSizeY ( ) , Source - > GetLODCount ( ) , Format , EInitializationType : : NotInitialized ) ;
bool bSuccess = false ;
ImOp . ImagePixelFormat ( bSuccess , m_pSettings - > ImageCompressionQuality , Formatted . get ( ) , Source . get ( ) ) ;
check ( bSuccess ) ;
2023-05-24 02:50:03 -04:00
2023-08-21 05:50:06 -04:00
Release ( Source ) ;
Source = Formatted ;
}
2024-10-01 20:09:26 -04:00
const FImageSize ExpectedSourceSize = FImageSize (
FMath : : Max < uint16 > ( Args . SourceSizeX > > ( uint16 ) Mip , 1 ) ,
FMath : : Max < uint16 > ( Args . SourceSizeY > > ( uint16 ) Mip , 1 ) ) ;
if ( Source - > GetSize ( ) ! = ExpectedSourceSize )
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_ImageTransform_SizeFixup ) ;
Ptr < Image > Resized = CreateImage ( ExpectedSourceSize . X , ExpectedSourceSize . Y , 1 , Format , EInitializationType : : NotInitialized ) ;
ImOp . ImageResizeLinear ( Resized . get ( ) , m_pSettings - > ImageCompressionQuality , Source . get ( ) ) ;
Release ( Source ) ;
Source = Resized ;
}
2023-08-21 05:50:06 -04:00
if ( Source - > GetLODCount ( ) < 2 & & Source - > GetSizeX ( ) > 1 & & Source - > GetSizeY ( ) > 1 )
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_ImageTransform_BilinearMipGen ) ;
2024-03-12 07:17:49 -04:00
Ptr < Image > OwnedSource = CloneOrTakeOver ( Source ) ;
OwnedSource - > DataStorage . SetNumLODs ( 2 ) ;
2023-08-21 05:50:06 -04:00
2024-03-12 07:17:49 -04:00
ImageMipmapInPlace ( 0 , OwnedSource . get ( ) , FMipmapGenerationSettings { } ) ;
2023-08-21 05:50:06 -04:00
2024-03-12 07:17:49 -04:00
Source = OwnedSource ;
2023-08-21 05:50:06 -04:00
}
2023-09-04 05:31:06 -04:00
Scale . X = FMath : : IsNearlyZero ( Scale . X , UE_KINDA_SMALL_NUMBER ) ? UE_KINDA_SMALL_NUMBER : Scale . X ;
Scale . Y = FMath : : IsNearlyZero ( Scale . Y , UE_KINDA_SMALL_NUMBER ) ? UE_KINDA_SMALL_NUMBER : Scale . Y ;
AspectCorrectionScale . X = FMath : : IsNearlyZero ( AspectCorrectionScale . X , UE_KINDA_SMALL_NUMBER )
? UE_KINDA_SMALL_NUMBER
: AspectCorrectionScale . X ;
AspectCorrectionScale . Y = FMath : : IsNearlyZero ( AspectCorrectionScale . Y , UE_KINDA_SMALL_NUMBER )
? UE_KINDA_SMALL_NUMBER
: AspectCorrectionScale . Y ;
const FTransform2f Transform = FTransform2f ( FVector2f ( - 0.5f ) )
. Concatenate ( FTransform2f ( FScale2f ( Scale ) ) )
. Concatenate ( FTransform2f ( FQuat2f ( RotationRad ) ) )
. Concatenate ( FTransform2f ( FScale2f ( AspectCorrectionScale ) ) )
. Concatenate ( FTransform2f ( Offset + FVector2f ( 0.5f ) ) ) ;
2023-08-21 05:50:06 -04:00
const EAddressMode AddressMode = static_cast < EAddressMode > ( Args . AddressMode ) ;
2023-09-04 05:31:06 -04:00
const EInitializationType InitType = AddressMode = = EAddressMode : : ClampToBlack
? EInitializationType : : Black
: EInitializationType : : NotInitialized ;
2023-08-21 05:50:06 -04:00
Ptr < Image > Result = CreateImage (
2023-09-04 05:31:06 -04:00
HeapData . ImageTransform . SizeX , HeapData . ImageTransform . SizeY , 1 , Format , InitType ) ;
2023-08-21 05:50:06 -04:00
const float MipFactor = FMath : : Frac ( FMath : : Max ( 0.0f , HeapData . ImageTransform . MipValue ) ) ;
2023-09-04 05:31:06 -04:00
ImageTransform ( Result . get ( ) , Source . get ( ) , Transform , MipFactor , AddressMode , bUseImageTransformVectorImpl ) ;
2023-08-21 05:50:06 -04:00
Release ( Source ) ;
2023-06-22 06:08:36 -04:00
StoreImage ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
default :
if ( type ! = OP_TYPE : : NONE )
{
// Operation not implemented
check ( false ) ;
}
break ;
}
2024-03-13 07:52:36 -04:00
}
2023-09-18 05:57:38 -04:00
//---------------------------------------------------------------------------------------------
2022-11-23 03:17:56 -05:00
Ptr < RangeIndex > CodeRunner : : BuildCurrentOpRangeIndex ( const FScheduledOp & item , const Parameters * pParams , const Model * pModel , int32 parameterIndex )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
if ( ! item . ExecutionIndex )
2022-09-26 15:12:13 -04:00
{
return nullptr ;
}
// \todo: optimise to avoid allocating the index here, we could access internal
// data directly.
Ptr < RangeIndex > index = pParams - > NewRangeIndex ( parameterIndex ) ;
if ( ! index )
{
return nullptr ;
}
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
const FParameterDesc & paramDesc = Program . m_parameters [ parameterIndex ] ;
2022-09-26 15:12:13 -04:00
for ( size_t rangeIndexInParam = 0 ;
2022-10-11 05:14:05 -04:00
rangeIndexInParam < paramDesc . m_ranges . Num ( ) ;
2022-09-26 15:12:13 -04:00
+ + rangeIndexInParam )
{
2023-01-11 14:28:53 -05:00
uint32 rangeIndexInModel = paramDesc . m_ranges [ rangeIndexInParam ] ;
2023-05-24 02:50:03 -04:00
const ExecutionIndex & currentIndex = GetMemory ( ) . GetRangeIndex ( item . ExecutionIndex ) ;
2022-09-26 15:12:13 -04:00
int position = currentIndex . GetFromModelRangeIndex ( rangeIndexInModel ) ;
index - > GetPrivate ( ) - > m_values [ rangeIndexInParam ] = position ;
}
return index ;
}
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_Bool ( const FScheduledOp & item , const Parameters * pParams , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
2023-01-25 04:08:49 -05:00
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Bool ) ;
2022-09-26 15:12:13 -04:00
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : BO_CONSTANT :
{
2023-12-19 05:19:14 -05:00
OP : : BoolConstantArgs args = Program . GetOpArgs < OP : : BoolConstantArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
bool result = args . value ;
2023-05-24 02:50:03 -04:00
StoreBool ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : BO_PARAMETER :
{
2023-12-19 05:19:14 -05:00
OP : : ParameterArgs args = Program . GetOpArgs < OP : : ParameterArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
bool result = false ;
Ptr < RangeIndex > index = BuildCurrentOpRangeIndex ( item , pParams , pModel , args . variable ) ;
result = pParams - > GetBoolValue ( args . variable , index ) ;
2023-05-24 02:50:03 -04:00
StoreBool ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : BO_LESS :
{
2023-12-19 05:19:14 -05:00
OP : : BoolLessArgs args = Program . GetOpArgs < OP : : BoolLessArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2023-05-24 02:50:03 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . a , item ) ,
FScheduledOp ( args . b , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
float a = LoadScalar ( FCacheAddress ( args . a , item ) ) ;
float b = LoadScalar ( FCacheAddress ( args . b , item ) ) ;
2022-09-26 15:12:13 -04:00
bool result = a < b ;
2023-05-24 02:50:03 -04:00
StoreBool ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : BO_AND :
{
2023-12-19 05:19:14 -05:00
OP : : BoolBinaryArgs args = Program . GetOpArgs < OP : : BoolBinaryArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
// Try to avoid the op entirely if we have some children cached
bool skip = false ;
2022-11-23 03:17:56 -05:00
if ( args . a & & GetMemory ( ) . IsValid ( FCacheAddress ( args . a , item ) ) )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
bool a = LoadBool ( FCacheAddress ( args . a , item ) ) ;
2022-09-26 15:12:13 -04:00
if ( ! a )
{
2023-05-24 02:50:03 -04:00
StoreBool ( item , false ) ;
2022-09-26 15:12:13 -04:00
skip = true ;
}
}
2022-11-23 03:17:56 -05:00
if ( ! skip & & args . b & & GetMemory ( ) . IsValid ( FCacheAddress ( args . b , item ) ) )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
bool b = LoadBool ( FCacheAddress ( args . b , item ) ) ;
2022-09-26 15:12:13 -04:00
if ( ! b )
{
2023-05-24 02:50:03 -04:00
StoreBool ( item , false ) ;
2022-09-26 15:12:13 -04:00
skip = true ;
}
}
if ( ! skip )
{
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . a , item ) ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
case 1 :
{
2023-05-24 02:50:03 -04:00
bool a = args . a ? LoadBool ( FCacheAddress ( args . a , item ) ) : true ;
2022-09-26 15:12:13 -04:00
if ( ! a )
{
2023-05-24 02:50:03 -04:00
StoreBool ( item , false ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 2 ) ,
FScheduledOp ( args . b , item ) ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
case 2 :
{
// We arrived here because a is true
2023-05-24 02:50:03 -04:00
bool b = args . b ? LoadBool ( FCacheAddress ( args . b , item ) ) : true ;
StoreBool ( item , b ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : BO_OR :
{
2023-12-19 05:19:14 -05:00
OP : : BoolBinaryArgs args = Program . GetOpArgs < OP : : BoolBinaryArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
// Try to avoid the op entirely if we have some children cached
bool skip = false ;
2022-11-23 03:17:56 -05:00
if ( args . a & & GetMemory ( ) . IsValid ( FCacheAddress ( args . a , item ) ) )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
bool a = LoadBool ( FCacheAddress ( args . a , item ) ) ;
2022-09-26 15:12:13 -04:00
if ( a )
{
2023-05-24 02:50:03 -04:00
StoreBool ( item , true ) ;
2022-09-26 15:12:13 -04:00
skip = true ;
}
}
2022-11-23 03:17:56 -05:00
if ( ! skip & & args . b & & GetMemory ( ) . IsValid ( FCacheAddress ( args . b , item ) ) )
2022-09-26 15:12:13 -04:00
{
2023-05-24 02:50:03 -04:00
bool b = LoadBool ( FCacheAddress ( args . b , item ) ) ;
2022-09-26 15:12:13 -04:00
if ( b )
{
2023-05-24 02:50:03 -04:00
StoreBool ( item , true ) ;
2022-09-26 15:12:13 -04:00
skip = true ;
}
}
if ( ! skip )
{
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . a , item ) ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
case 1 :
{
2023-05-24 02:50:03 -04:00
bool a = args . a ? LoadBool ( FCacheAddress ( args . a , item ) ) : false ;
2022-09-26 15:12:13 -04:00
if ( a )
{
2023-05-24 02:50:03 -04:00
StoreBool ( item , true ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 2 ) ,
FScheduledOp ( args . b , item ) ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
case 2 :
{
// We arrived here because a is false
2023-05-24 02:50:03 -04:00
bool b = args . b ? LoadBool ( FCacheAddress ( args . b , item ) ) : false ;
StoreBool ( item , b ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : BO_NOT :
{
2023-12-19 05:19:14 -05:00
OP : : BoolNotArgs args = Program . GetOpArgs < OP : : BoolNotArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
bool result = ! LoadBool ( FCacheAddress ( args . source , item ) ) ;
StoreBool ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : BO_EQUAL_INT_CONST :
{
2023-12-19 05:19:14 -05:00
OP : : BoolEqualScalarConstArgs args = Program . GetOpArgs < OP : : BoolEqualScalarConstArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
int a = LoadInt ( FCacheAddress ( args . value , item ) ) ;
2022-09-26 15:12:13 -04:00
bool result = a = = args . constant ;
2023-05-24 02:50:03 -04:00
StoreBool ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
default :
check ( false ) ;
break ;
}
}
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_Int ( const FScheduledOp & item , const Parameters * pParams , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Int ) ;
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : NU_CONSTANT :
{
2023-12-19 05:19:14 -05:00
OP : : IntConstantArgs args = Program . GetOpArgs < OP : : IntConstantArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
int result = args . value ;
2023-05-24 02:50:03 -04:00
StoreInt ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : NU_PARAMETER :
{
2023-12-19 05:19:14 -05:00
OP : : ParameterArgs args = Program . GetOpArgs < OP : : ParameterArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
Ptr < RangeIndex > index = BuildCurrentOpRangeIndex ( item , pParams , pModel , args . variable ) ;
int result = pParams - > GetIntValue ( args . variable , index ) ;
// Check that the value is actually valid. Otherwise set the default.
if ( pParams - > GetIntPossibleValueCount ( args . variable ) )
{
bool valid = false ;
for ( int i = 0 ;
( ! valid ) & & i < pParams - > GetIntPossibleValueCount ( args . variable ) ;
+ + i )
{
if ( result = = pParams - > GetIntPossibleValue ( args . variable , i ) )
{
valid = true ;
}
}
if ( ! valid )
{
result = pParams - > GetIntPossibleValue ( args . variable , 0 ) ;
}
}
2023-05-24 02:50:03 -04:00
StoreInt ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
break ;
}
}
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_Scalar ( const FScheduledOp & item , const Parameters * pParams , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Scalar ) ;
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : SC_CONSTANT :
{
2023-12-19 05:19:14 -05:00
OP : : ScalarConstantArgs args = Program . GetOpArgs < OP : : ScalarConstantArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
float result = args . value ;
2023-05-24 02:50:03 -04:00
StoreScalar ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : SC_PARAMETER :
{
2023-12-19 05:19:14 -05:00
OP : : ParameterArgs args = Program . GetOpArgs < OP : : ParameterArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
Ptr < RangeIndex > index = BuildCurrentOpRangeIndex ( item , pParams , pModel , args . variable ) ;
float result = pParams - > GetFloatValue ( args . variable , index ) ;
2023-05-24 02:50:03 -04:00
StoreScalar ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : SC_CURVE :
{
2023-12-19 05:19:14 -05:00
OP : : ScalarCurveArgs args = Program . GetOpArgs < OP : : ScalarCurveArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2024-06-03 08:55:45 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . time , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
float time = LoadScalar ( FCacheAddress ( args . time , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-06-03 08:55:45 -04:00
const FRichCurve & Curve = Program . ConstantCurves [ args . curve ] ;
float Result = Curve . Eval ( time ) ;
2022-09-26 15:12:13 -04:00
2024-06-03 08:55:45 -04:00
StoreScalar ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : SC_MULTIPLYADD :
// \TODO
check ( false ) ;
break ;
case OP_TYPE : : SC_ARITHMETIC :
{
2023-12-19 05:19:14 -05:00
OP : : ArithmeticArgs args = Program . GetOpArgs < OP : : ArithmeticArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . a , item ) ,
FScheduledOp ( args . b , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
float a = LoadScalar ( FCacheAddress ( args . a , item ) ) ;
float b = LoadScalar ( FCacheAddress ( args . b , item ) ) ;
2022-09-26 15:12:13 -04:00
float result = 1.0f ;
switch ( args . operation )
{
case OP : : ArithmeticArgs : : ADD :
result = a + b ;
break ;
case OP : : ArithmeticArgs : : MULTIPLY :
result = a * b ;
break ;
case OP : : ArithmeticArgs : : SUBTRACT :
result = a - b ;
break ;
case OP : : ArithmeticArgs : : DIVIDE :
result = a / b ;
break ;
default :
checkf ( false , TEXT ( " Arithmetic operation not implemented. " ) ) ;
break ;
}
2023-05-24 02:50:03 -04:00
StoreScalar ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
default :
check ( false ) ;
break ;
}
}
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_String ( const FScheduledOp & item , const Parameters * pParams , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_String ) ;
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : ST_CONSTANT :
{
2023-12-19 05:19:14 -05:00
OP : : ResourceConstantArgs args = Program . GetOpArgs < OP : : ResourceConstantArgs > ( item . At ) ;
2022-10-11 05:14:05 -04:00
check ( args . value < ( uint32 ) pModel - > GetPrivate ( ) - > m_program . m_constantStrings . Num ( ) ) ;
2022-09-26 15:12:13 -04:00
2023-12-19 05:19:14 -05:00
const FString & result = Program . m_constantStrings [ args . value ] ;
2023-09-26 04:43:37 -04:00
StoreString ( item , new String ( result ) ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : ST_PARAMETER :
{
2023-12-19 05:19:14 -05:00
OP : : ParameterArgs args = Program . GetOpArgs < OP : : ParameterArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
Ptr < RangeIndex > index = BuildCurrentOpRangeIndex ( item , pParams , pModel , args . variable ) ;
2023-09-26 04:43:37 -04:00
FString result ;
pParams - > GetStringValue ( args . variable , result , index ) ;
StoreString ( item , new String ( result ) ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
break ;
}
}
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_Colour ( const FScheduledOp & item , const Parameters * pParams , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Colour ) ;
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
2022-09-26 15:12:13 -04:00
2023-12-19 05:19:14 -05:00
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : CO_CONSTANT :
{
2023-12-19 05:19:14 -05:00
OP : : ColourConstantArgs args = Program . GetOpArgs < OP : : ColourConstantArgs > ( item . At ) ;
2022-10-26 19:35:32 -04:00
FVector4f result ;
2022-09-26 15:12:13 -04:00
result [ 0 ] = args . value [ 0 ] ;
result [ 1 ] = args . value [ 1 ] ;
result [ 2 ] = args . value [ 2 ] ;
result [ 3 ] = args . value [ 3 ] ;
2023-05-24 02:50:03 -04:00
StoreColor ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : CO_PARAMETER :
{
2023-12-19 05:19:14 -05:00
OP : : ParameterArgs args = Program . GetOpArgs < OP : : ParameterArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
Ptr < RangeIndex > index = BuildCurrentOpRangeIndex ( item , pParams , pModel , args . variable ) ;
2024-01-25 05:42:38 -05:00
float R = 0.f ;
float G = 0.f ;
float B = 0.f ;
float A = 0.f ;
pParams - > GetColourValue ( args . variable , & R , & G , & B , & A , index ) ;
StoreColor ( item , FVector4f ( R , G , B , A ) ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : CO_SAMPLEIMAGE :
{
2023-12-19 05:19:14 -05:00
OP : : ColourSampleImageArgs args = Program . GetOpArgs < OP : : ColourSampleImageArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . x , item ) ,
FScheduledOp ( args . y , item ) ,
2022-09-26 15:12:13 -04:00
// Don't skip mips for the texture to sample
2022-11-23 03:17:56 -05:00
FScheduledOp : : FromOpAndOptions ( args . image , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
float x = args . x ? LoadScalar ( FCacheAddress ( args . x , item ) ) : 0.5f ;
float y = args . y ? LoadScalar ( FCacheAddress ( args . y , item ) ) : 0.5f ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
Ptr < const Image > pImage = LoadImage ( FScheduledOp : : FromOpAndOptions ( args . image , item , 0 ) ) ;
2022-09-26 15:12:13 -04:00
2022-10-26 19:35:32 -04:00
FVector4f result ;
2022-09-26 15:12:13 -04:00
if ( pImage )
{
if ( args . filter )
{
// TODO
2022-10-26 19:35:32 -04:00
result = pImage - > Sample ( FVector2f ( x , y ) ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2022-10-26 19:35:32 -04:00
result = pImage - > Sample ( FVector2f ( x , y ) ) ;
2022-09-26 15:12:13 -04:00
}
}
else
{
2022-10-26 19:35:32 -04:00
result = FVector4f ( ) ;
2022-09-26 15:12:13 -04:00
}
2023-05-24 02:50:03 -04:00
Release ( pImage ) ;
StoreColor ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : CO_SWIZZLE :
{
2023-12-19 05:19:14 -05:00
OP : : ColourSwizzleArgs args = Program . GetOpArgs < OP : : ColourSwizzleArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . sources [ 0 ] , item ) ,
FScheduledOp ( args . sources [ 1 ] , item ) ,
FScheduledOp ( args . sources [ 2 ] , item ) ,
FScheduledOp ( args . sources [ 3 ] , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2022-10-26 19:35:32 -04:00
FVector4f result ;
2022-09-26 15:12:13 -04:00
for ( int t = 0 ; t < MUTABLE_OP_MAX_SWIZZLE_CHANNELS ; + + t )
{
if ( args . sources [ t ] )
{
2023-05-24 02:50:03 -04:00
FVector4f p = LoadColor ( FCacheAddress ( args . sources [ t ] , item ) ) ;
2022-09-26 15:12:13 -04:00
result [ t ] = p [ args . sourceChannels [ t ] ] ;
}
}
2023-05-24 02:50:03 -04:00
StoreColor ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : CO_FROMSCALARS :
{
2023-12-19 05:19:14 -05:00
OP : : ColourFromScalarsArgs args = Program . GetOpArgs < OP : : ColourFromScalarsArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
2023-08-02 02:33:32 -04:00
FScheduledOp ( args . v [ 0 ] , item ) ,
FScheduledOp ( args . v [ 1 ] , item ) ,
FScheduledOp ( args . v [ 2 ] , item ) ,
FScheduledOp ( args . v [ 3 ] , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-08-28 10:07:58 -04:00
FVector4f Result = FVector4f ( 0 , 0 , 0 , 1 ) ;
2022-09-26 15:12:13 -04:00
2023-08-02 02:33:32 -04:00
for ( int32 t = 0 ; t < MUTABLE_OP_MAX_SWIZZLE_CHANNELS ; + + t )
{
if ( args . v [ t ] )
{
Result [ t ] = LoadScalar ( FCacheAddress ( args . v [ t ] , item ) ) ;
}
}
2022-09-26 15:12:13 -04:00
2023-08-02 02:33:32 -04:00
StoreColor ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : CO_ARITHMETIC :
{
2023-12-19 05:19:14 -05:00
OP : : ArithmeticArgs args = Program . GetOpArgs < OP : : ArithmeticArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . a , item ) ,
FScheduledOp ( args . b , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-12-19 05:19:14 -05:00
OP_TYPE otype = Program . GetOpType ( args . a ) ;
2022-09-26 15:12:13 -04:00
DATATYPE dtype = GetOpDataType ( otype ) ;
check ( dtype = = DT_COLOUR ) ;
2023-12-19 05:19:14 -05:00
otype = Program . GetOpType ( args . b ) ;
2022-09-26 15:12:13 -04:00
dtype = GetOpDataType ( otype ) ;
check ( dtype = = DT_COLOUR ) ;
2023-05-24 02:50:03 -04:00
FVector4f a = args . a ? LoadColor ( FCacheAddress ( args . a , item ) )
2022-10-26 19:35:32 -04:00
: FVector4f ( 0 , 0 , 0 , 0 ) ;
2023-05-24 02:50:03 -04:00
FVector4f b = args . b ? LoadColor ( FCacheAddress ( args . b , item ) )
2022-10-26 19:35:32 -04:00
: FVector4f ( 0 , 0 , 0 , 0 ) ;
2022-09-26 15:12:13 -04:00
2022-10-26 19:35:32 -04:00
FVector4f result = FVector4f ( 0 , 0 , 0 , 0 ) ;
2022-09-26 15:12:13 -04:00
switch ( args . operation )
{
case OP : : ArithmeticArgs : : ADD :
result = a + b ;
break ;
case OP : : ArithmeticArgs : : MULTIPLY :
result = a * b ;
break ;
case OP : : ArithmeticArgs : : SUBTRACT :
result = a - b ;
break ;
case OP : : ArithmeticArgs : : DIVIDE :
result = a / b ;
break ;
default :
checkf ( false , TEXT ( " Arithmetic operation not implemented. " ) ) ;
break ;
}
2023-05-24 02:50:03 -04:00
StoreColor ( item , result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
default :
check ( false ) ;
break ;
}
}
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_Projector ( const FScheduledOp & item , const Parameters * pParams , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Projector ) ;
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : PR_CONSTANT :
{
2023-12-19 05:19:14 -05:00
OP : : ResourceConstantArgs args = Program . GetOpArgs < OP : : ResourceConstantArgs > ( item . At ) ;
FProjector Result = Program . m_constantProjectors [ args . value ] ;
2023-06-06 02:00:32 -04:00
StoreProjector ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : PR_PARAMETER :
{
2023-12-19 05:19:14 -05:00
OP : : ParameterArgs args = Program . GetOpArgs < OP : : ParameterArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
Ptr < RangeIndex > index = BuildCurrentOpRangeIndex ( item , pParams , pModel , args . variable ) ;
2023-06-06 02:00:32 -04:00
FProjector Result = pParams - > GetPrivate ( ) - > GetProjectorValue ( args . variable , index ) ;
2022-09-26 15:12:13 -04:00
// The type cannot be changed, take it from the default value
2023-12-19 05:19:14 -05:00
const FProjector & def = Program . m_parameters [ args . variable ] . m_defaultValue . Get < ParamProjectorType > ( ) ;
2023-06-06 02:00:32 -04:00
Result . type = def . type ;
2022-09-26 15:12:13 -04:00
2023-06-06 02:00:32 -04:00
StoreProjector ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
break ;
}
}
2024-10-01 19:09:05 -04:00
//---------------------------------------------------------------------------------------------
void CodeRunner : : RunCode_Matrix ( const FScheduledOp & item , const Parameters * pParams , const Model * pModel )
{
MUTABLE_CPUPROFILER_SCOPE ( RunCode_Transform ) ;
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
switch ( type )
{
case OP_TYPE : : MA_CONSTANT :
{
OP : : MatrixConstantArgs args = Program . GetOpArgs < OP : : MatrixConstantArgs > ( item . At ) ;
StoreMatrix ( item , Program . m_constantMatrices [ args . value ] ) ;
break ;
}
case OP_TYPE : : MA_PARAMETER :
{
OP : : ParameterArgs args = Program . GetOpArgs < OP : : ParameterArgs > ( item . At ) ;
Ptr < RangeIndex > index = BuildCurrentOpRangeIndex ( item , pParams , pModel , args . variable ) ;
FMatrix44f Value ;
pParams - > GetMatrixValue ( args . variable , Value , index ) ;
StoreMatrix ( item , Value ) ;
break ;
}
}
}
2022-09-26 15:12:13 -04:00
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCode_Layout ( const FScheduledOp & item , const Model * pModel )
2022-09-26 15:12:13 -04:00
{
//MUTABLE_CPUPROFILER_SCOPE(RunCode_Layout);
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : LA_CONSTANT :
{
2023-12-19 05:19:14 -05:00
OP : : ResourceConstantArgs args = Program . GetOpArgs < OP : : ResourceConstantArgs > ( item . At ) ;
2024-08-13 10:23:49 -04:00
check ( args . value < ( uint32 ) pModel - > GetPrivate ( ) - > m_program . m_constantLayouts . Num ( ) ) ;
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
Ptr < const Layout > pResult = Program . m_constantLayouts
[ args . value ] ;
StoreLayout ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : LA_MERGE :
{
2023-12-19 05:19:14 -05:00
OP : : LayoutMergeArgs args = Program . GetOpArgs < OP : : LayoutMergeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . Base , item ) ,
FScheduledOp ( args . Added , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
Ptr < const Layout > pA = LoadLayout ( FCacheAddress ( args . Base , item ) ) ;
Ptr < const Layout > pB = LoadLayout ( FCacheAddress ( args . Added , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-07-17 04:18:05 -04:00
Ptr < const Layout > pResult ;
2022-09-26 15:12:13 -04:00
if ( pA & & pB )
{
pResult = LayoutMerge ( pA . get ( ) , pB . get ( ) ) ;
}
else if ( pA )
{
pResult = pA - > Clone ( ) ;
}
else if ( pB )
{
pResult = pB - > Clone ( ) ;
}
2023-05-24 02:50:03 -04:00
StoreLayout ( item , pResult ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : LA_PACK :
{
2023-12-19 05:19:14 -05:00
OP : : LayoutPackArgs args = Program . GetOpArgs < OP : : LayoutPackArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . Source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
Ptr < const Layout > Source = LoadLayout ( FCacheAddress ( args . Source , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-07-17 04:18:05 -04:00
Ptr < Layout > Result ;
2022-09-26 15:12:13 -04:00
2023-05-24 02:50:03 -04:00
if ( Source )
2022-09-26 15:12:13 -04:00
{
2024-07-17 04:18:05 -04:00
Result = Source - > Clone ( ) ;
2022-09-26 15:12:13 -04:00
2024-07-17 04:18:05 -04:00
LayoutPack3 ( Result . get ( ) , Source . get ( ) ) ;
2022-09-26 15:12:13 -04:00
}
2024-07-17 04:18:05 -04:00
StoreLayout ( item , Result ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2022-11-08 12:29:21 -05:00
case OP_TYPE : : LA_FROMMESH :
{
2023-12-19 05:19:14 -05:00
OP : : LayoutFromMeshArgs args = Program . GetOpArgs < OP : : LayoutFromMeshArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-11-08 12:29:21 -05:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
2024-08-13 10:23:49 -04:00
FScheduledOp ( args . Mesh , item ) ) ;
2022-11-08 12:29:21 -05:00
break ;
2022-09-26 15:12:13 -04:00
2022-11-08 12:29:21 -05:00
case 1 :
{
2024-08-13 10:23:49 -04:00
Ptr < const Mesh > Mesh = LoadMesh ( FCacheAddress ( args . Mesh , item ) ) ;
2022-11-14 10:46:41 -05:00
Ptr < const Layout > Result = LayoutFromMesh_RemoveBlocks ( Mesh . get ( ) , args . LayoutIndex ) ;
2022-09-26 15:12:13 -04:00
2023-06-15 04:45:22 -04:00
Release ( Mesh ) ;
2023-05-24 02:50:03 -04:00
StoreLayout ( item , Result ) ;
2022-11-08 12:29:21 -05:00
break ;
}
2022-09-26 15:12:13 -04:00
2022-11-08 12:29:21 -05:00
default :
check ( false ) ;
}
2022-09-26 15:12:13 -04:00
2022-11-08 12:29:21 -05:00
break ;
}
case OP_TYPE : : LA_REMOVEBLOCKS :
{
2023-12-19 05:19:14 -05:00
OP : : LayoutRemoveBlocksArgs args = Program . GetOpArgs < OP : : LayoutRemoveBlocksArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-11-08 12:29:21 -05:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) ,
FScheduledOp ( args . Source , item ) ,
FScheduledOp ( args . ReferenceLayout , item ) ) ;
2022-11-08 12:29:21 -05:00
break ;
case 1 :
{
2023-05-24 02:50:03 -04:00
Ptr < const Layout > Source = LoadLayout ( FCacheAddress ( args . Source , item ) ) ;
Ptr < const Layout > ReferenceLayout = LoadLayout ( FCacheAddress ( args . ReferenceLayout , item ) ) ;
2022-11-08 12:29:21 -05:00
Ptr < const Layout > pResult ;
if ( Source & & ReferenceLayout )
{
pResult = LayoutRemoveBlocks ( Source . get ( ) , ReferenceLayout . get ( ) ) ;
}
else if ( Source )
{
pResult = Source ;
}
2023-05-24 02:50:03 -04:00
StoreLayout ( item , pResult ) ;
2022-11-08 12:29:21 -05:00
break ;
}
default :
check ( false ) ;
}
break ;
}
2022-09-26 15:12:13 -04:00
default :
// Operation not implemented
check ( false ) ;
break ;
}
}
//---------------------------------------------------------------------------------------------
2023-08-03 03:37:44 -04:00
void CodeRunner : : RunCode ( const FScheduledOp & item , const Parameters * pParams , const TSharedPtr < const Model > & InModel , uint32 lodMask )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
//UE_LOG( LogMutableCore, Log, TEXT("Running :%5d , %d "), item.At, item.Stage );
check ( item . Type = = FScheduledOp : : EType : : Full ) ;
2022-09-26 15:12:13 -04:00
2023-08-03 03:37:44 -04:00
const Model * pModel = InModel . Get ( ) ;
2023-12-19 05:19:14 -05:00
const FProgram & Program = pModel - > GetPrivate ( ) - > m_program ;
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-11-23 03:17:56 -05:00
//UE_LOG(LogMutableCore, Log, TEXT("Running :%5d , %d, of type %d "), item.At, item.Stage, type);
2023-03-09 09:42:19 -05:00
2023-05-24 02:50:03 -04:00
// Very spammy, for debugging purposes.
//if (m_pSystem)
//{
// m_pSystem->WorkingMemoryManager.LogWorkingMemory( this );
//}
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : NONE :
break ;
case OP_TYPE : : NU_CONDITIONAL :
case OP_TYPE : : SC_CONDITIONAL :
case OP_TYPE : : CO_CONDITIONAL :
case OP_TYPE : : IM_CONDITIONAL :
case OP_TYPE : : ME_CONDITIONAL :
case OP_TYPE : : LA_CONDITIONAL :
case OP_TYPE : : IN_CONDITIONAL :
2023-08-03 12:40:31 -04:00
case OP_TYPE : : ED_CONDITIONAL :
2022-09-26 15:12:13 -04:00
RunCode_Conditional ( item , pModel ) ;
break ;
case OP_TYPE : : ME_CONSTANT :
2023-04-05 11:20:44 -04:00
case OP_TYPE : : IM_CONSTANT :
case OP_TYPE : : ED_CONSTANT :
2022-09-26 15:12:13 -04:00
RunCode_ConstantResource ( item , pModel ) ;
break ;
case OP_TYPE : : NU_SWITCH :
case OP_TYPE : : SC_SWITCH :
case OP_TYPE : : CO_SWITCH :
case OP_TYPE : : IM_SWITCH :
case OP_TYPE : : ME_SWITCH :
case OP_TYPE : : LA_SWITCH :
case OP_TYPE : : IN_SWITCH :
2023-08-03 12:40:31 -04:00
case OP_TYPE : : ED_SWITCH :
2022-09-26 15:12:13 -04:00
RunCode_Switch ( item , pModel ) ;
break ;
case OP_TYPE : : IN_ADDMESH :
case OP_TYPE : : IN_ADDIMAGE :
2023-08-03 03:37:44 -04:00
RunCode_InstanceAddResource ( item , InModel , pParams ) ;
2022-09-26 15:12:13 -04:00
break ;
default :
{
DATATYPE DataType = GetOpDataType ( type ) ;
switch ( DataType )
{
case DT_INSTANCE :
RunCode_Instance ( item , pModel , lodMask ) ;
break ;
case DT_MESH :
RunCode_Mesh ( item , pModel ) ;
break ;
case DT_IMAGE :
RunCode_Image ( item , pParams , pModel ) ;
break ;
case DT_LAYOUT :
RunCode_Layout ( item , pModel ) ;
break ;
case DT_BOOL :
RunCode_Bool ( item , pParams , pModel ) ;
break ;
case DT_SCALAR :
RunCode_Scalar ( item , pParams , pModel ) ;
break ;
case DT_STRING :
RunCode_String ( item , pParams , pModel ) ;
break ;
case DT_INT :
RunCode_Int ( item , pParams , pModel ) ;
break ;
case DT_PROJECTOR :
RunCode_Projector ( item , pParams , pModel ) ;
break ;
case DT_COLOUR :
RunCode_Colour ( item , pParams , pModel ) ;
break ;
2024-10-01 19:09:05 -04:00
case DT_MATRIX :
RunCode_Matrix ( item , pParams , pModel ) ;
break ;
2022-09-26 15:12:13 -04:00
default :
check ( false ) ;
break ;
}
break ;
}
}
}
2024-08-13 10:23:49 -04:00
//---------------------------------------------------------------------------------------------
2023-02-14 12:12:46 -05:00
void CodeRunner : : RunCodeImageDesc ( const FScheduledOp & item , const Parameters * pParams , const Model * pModel , uint32 lodMask )
2022-09-26 15:12:13 -04:00
{
MUTABLE_CPUPROFILER_SCOPE ( RunCodeImageDesc ) ;
2022-11-23 03:17:56 -05:00
check ( item . Type = = FScheduledOp : : EType : : ImageDesc ) ;
2022-09-26 15:12:13 -04:00
// Ensure there is room for the result in the heap.
2022-11-23 03:17:56 -05:00
if ( item . CustomState > = uint32 ( m_heapData . Num ( ) ) )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
m_heapImageDesc . SetNum ( item . CustomState + 1 ) ;
2022-09-26 15:12:13 -04:00
}
2023-12-19 05:19:14 -05:00
const FProgram & Program = m_pModel - > GetPrivate ( ) - > m_program ;
2022-09-26 15:12:13 -04:00
2023-12-19 05:19:14 -05:00
OP_TYPE type = Program . GetOpType ( item . At ) ;
2022-09-26 15:12:13 -04:00
switch ( type )
{
case OP_TYPE : : IM_CONSTANT :
{
2022-11-23 03:17:56 -05:00
check ( item . Stage = = 0 ) ;
2023-12-19 05:19:14 -05:00
OP : : ResourceConstantArgs args = Program . GetOpArgs < OP : : ResourceConstantArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
int32 ImageIndex = args . value ;
2023-04-28 15:57:31 -04:00
FImageDesc & Result = m_heapImageDesc [ item . CustomState ] ;
2024-06-13 04:48:11 -04:00
Result . m_format = Program . ConstantImages [ ImageIndex ] . ImageFormat ;
Result . m_size [ 0 ] = Program . ConstantImages [ ImageIndex ] . ImageSizeX ;
Result . m_size [ 1 ] = Program . ConstantImages [ ImageIndex ] . ImageSizeY ;
Result . m_lods = Program . ConstantImages [ ImageIndex ] . LODCount ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : IM_PARAMETER :
{
2022-11-23 03:17:56 -05:00
check ( item . Stage = = 0 ) ;
2023-12-19 05:19:14 -05:00
OP : : ParameterArgs args = Program . GetOpArgs < OP : : ParameterArgs > ( item . At ) ;
2023-07-31 03:24:06 -04:00
FName Id = pParams - > GetImageValue ( args . variable ) ;
2023-01-03 10:26:42 -05:00
uint8 MipsToSkip = item . ExecutionOptions ;
2023-07-31 03:24:06 -04:00
m_heapImageDesc [ item . CustomState ] = GetExternalImageDesc ( Id , MipsToSkip ) ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
2023-04-28 15:57:31 -04:00
case OP_TYPE : : IM_REFERENCE :
{
check ( item . Stage = = 0 ) ;
2023-12-19 05:19:14 -05:00
OP : : ResourceReferenceArgs Args = Program . GetOpArgs < OP : : ResourceReferenceArgs > ( item . At ) ;
2023-04-28 15:57:31 -04:00
FImageDesc & Result = m_heapImageDesc [ item . CustomState ] ;
2023-10-05 04:46:46 -04:00
Result = Args . ImageDesc ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2023-04-28 15:57:31 -04:00
break ;
}
2022-09-26 15:12:13 -04:00
case OP_TYPE : : IM_CONDITIONAL :
{
2023-12-19 05:19:14 -05:00
OP : : ConditionalArgs args = Program . GetOpArgs < OP : : ConditionalArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
// We need to run the full condition result
2022-11-23 03:17:56 -05:00
FScheduledOp FullConditionOp ( args . condition , item ) ;
FullConditionOp . Type = FScheduledOp : : EType : : Full ;
AddOp ( FScheduledOp ( item . At , item , 1 ) , FullConditionOp ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case 1 :
{
2024-08-13 10:23:49 -04:00
bool value = LoadBool ( FCacheAddress ( args . condition , item . ExecutionIndex , item . ExecutionOptions ) ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS resultAt = value ? args . yes : args . no ;
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 2 ) , FScheduledOp ( resultAt , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
}
2023-05-24 02:50:03 -04:00
case 2 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_SWITCH :
{
2024-08-13 10:23:49 -04:00
const uint8 * data = Program . GetOpArgsPointer ( item . At ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS VarAddress ;
2024-08-13 10:23:49 -04:00
FMemory : : Memcpy ( & VarAddress , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS DefAddress ;
2024-08-13 10:23:49 -04:00
FMemory : : Memcpy ( & DefAddress , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
2022-09-26 15:12:13 -04:00
2022-10-06 20:10:22 -04:00
uint32 CaseCount ;
2024-08-13 10:23:49 -04:00
FMemory : : Memcpy ( & CaseCount , data , sizeof ( uint32 ) ) ;
data + = sizeof ( uint32 ) ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
if ( VarAddress )
{
// We need to run the full condition result
2022-11-23 03:17:56 -05:00
FScheduledOp FullVariableOp ( VarAddress , item ) ;
FullVariableOp . Type = FScheduledOp : : EType : : Full ;
AddOp ( FScheduledOp ( item . At , item , 1 ) , FullVariableOp ) ;
2022-09-26 15:12:13 -04:00
}
else
{
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
case 1 :
{
// Get the variable result
2024-08-13 10:23:49 -04:00
int var = LoadInt ( FCacheAddress ( VarAddress , item ) ) ;
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
OP : : ADDRESS valueAt = DefAddress ;
2022-10-06 20:10:22 -04:00
for ( uint32 C = 0 ; C < CaseCount ; + + C )
2022-09-26 15:12:13 -04:00
{
2022-10-06 20:10:22 -04:00
int32 Condition ;
2024-08-13 10:23:49 -04:00
FMemory : : Memcpy ( & Condition , data , sizeof ( int32 ) ) ;
data + = sizeof ( int32 ) ;
2022-09-26 15:12:13 -04:00
OP : : ADDRESS At ;
2024-08-13 10:23:49 -04:00
FMemory : : Memcpy ( & At , data , sizeof ( OP : : ADDRESS ) ) ;
data + = sizeof ( OP : : ADDRESS ) ;
2022-09-26 15:12:13 -04:00
2024-08-13 10:23:49 -04:00
if ( At & & var = = ( int ) Condition )
2022-09-26 15:12:13 -04:00
{
2024-08-13 10:23:49 -04:00
valueAt = At ;
2022-09-26 15:12:13 -04:00
break ;
}
}
2024-08-13 10:23:49 -04:00
AddOp ( FScheduledOp ( item . At , item , 2 , valueAt ) ,
FScheduledOp ( valueAt , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
}
2023-05-24 02:50:03 -04:00
case 2 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ; break ;
}
break ;
}
case OP_TYPE : : IM_LAYERCOLOUR :
{
2023-12-19 05:19:14 -05:00
OP : : ImageLayerColourArgs args = Program . GetOpArgs < OP : : ImageLayerColourArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_LAYER :
{
2023-12-19 05:19:14 -05:00
OP : : ImageLayerArgs args = Program . GetOpArgs < OP : : ImageLayerArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_MULTILAYER :
{
2023-12-19 05:19:14 -05:00
OP : : ImageMultiLayerArgs args = Program . GetOpArgs < OP : : ImageMultiLayerArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_NORMALCOMPOSITE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageNormalCompositeArgs args = Program . GetOpArgs < OP : : ImageNormalCompositeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_PIXELFORMAT :
{
2023-12-19 05:19:14 -05:00
OP : : ImagePixelFormatArgs args = Program . GetOpArgs < OP : : ImagePixelFormatArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
// Update directly in the heap
2022-11-23 03:17:56 -05:00
EImageFormat OldFormat = m_heapImageDesc [ item . CustomState ] . m_format ;
2022-09-26 15:12:13 -04:00
EImageFormat NewFormat = args . format ;
if ( args . formatIfAlpha ! = EImageFormat : : IF_NONE
& &
2023-06-23 02:01:13 -04:00
GetImageFormatData ( OldFormat ) . Channels > 3 )
2022-09-26 15:12:13 -04:00
{
NewFormat = args . formatIfAlpha ;
}
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] . m_format = NewFormat ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_MIPMAP :
{
2023-12-19 05:19:14 -05:00
OP : : ImageMipmapArgs args = Program . GetOpArgs < OP : : ImageMipmapArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
// Somewhat synched with Full op execution code.
2022-11-23 03:17:56 -05:00
FImageDesc BaseDesc = m_heapImageDesc [ item . CustomState ] ;
2024-03-12 07:17:49 -04:00
int32 LevelCount = args . levels ;
int32 MaxLevelCount = Image : : GetMipmapCount ( BaseDesc . m_size [ 0 ] , BaseDesc . m_size [ 1 ] ) ;
if ( LevelCount = = 0 )
2022-09-26 15:12:13 -04:00
{
2024-03-12 07:17:49 -04:00
LevelCount = MaxLevelCount ;
2022-09-26 15:12:13 -04:00
}
2024-03-12 07:17:49 -04:00
else if ( LevelCount > MaxLevelCount )
2022-09-26 15:12:13 -04:00
{
// If code generation is smart enough, this should never happen.
// \todo But apparently it does, sometimes.
2024-03-12 07:17:49 -04:00
LevelCount = MaxLevelCount ;
2022-09-26 15:12:13 -04:00
}
// At least keep the levels we already have.
2024-03-12 07:17:49 -04:00
int32 StartLevel = BaseDesc . m_lods ;
LevelCount = FMath : : Max ( StartLevel , LevelCount ) ;
2022-09-26 15:12:13 -04:00
// Update result.
2024-03-12 07:17:49 -04:00
m_heapImageDesc [ item . CustomState ] . m_lods = LevelCount ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_RESIZE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageResizeArgs args = Program . GetOpArgs < OP : : ImageResizeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] . m_size [ 0 ] = args . size [ 0 ] ;
m_heapImageDesc [ item . CustomState ] . m_size [ 1 ] = args . size [ 1 ] ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_RESIZELIKE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageResizeLikeArgs args = Program . GetOpArgs < OP : : ImageResizeLikeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
2022-11-23 03:17:56 -05:00
int32 ResultAndBaseDesc = item . CustomState ;
2022-09-26 15:12:13 -04:00
int32 SourceDescAddress = m_heapImageDesc . Add ( { } ) ;
2022-11-23 03:17:56 -05:00
FScheduledOpData Data ;
Data . ResizeLike . ResultDescAt = ResultAndBaseDesc ;
Data . ResizeLike . SourceDescAt = SourceDescAddress ;
int32 SecondStageData = m_heapData . Add ( Data ) ;
AddOp ( FScheduledOp ( item . At , item , 1 , SecondStageData ) ,
FScheduledOp ( args . source , item , 0 , ResultAndBaseDesc ) ,
FScheduledOp ( args . sizeSource , item , 0 , SourceDescAddress ) ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case 1 :
{
2022-11-23 03:17:56 -05:00
const FScheduledOpData & SecondStageData = m_heapData [ item . CustomState ] ;
FImageDesc & ResultAndBaseDesc = m_heapImageDesc [ SecondStageData . ResizeLike . ResultDescAt ] ;
const FImageDesc & SourceDesc = m_heapImageDesc [ SecondStageData . ResizeLike . SourceDescAt ] ;
2022-09-26 15:12:13 -04:00
ResultAndBaseDesc . m_size = SourceDesc . m_size ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_RESIZEREL :
{
2023-12-19 05:19:14 -05:00
OP : : ImageResizeRelArgs args = Program . GetOpArgs < OP : : ImageResizeRelArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
{
2022-11-23 03:17:56 -05:00
FImageDesc & ResultAndBaseDesc = m_heapImageDesc [ item . CustomState ] ;
2022-09-26 15:12:13 -04:00
FImageSize destSize (
2022-10-06 20:10:22 -04:00
uint16 ( ResultAndBaseDesc . m_size [ 0 ] * args . factor [ 0 ] + 0.5f ) ,
uint16 ( ResultAndBaseDesc . m_size [ 1 ] * args . factor [ 1 ] + 0.5f ) ) ;
2022-09-26 15:12:13 -04:00
ResultAndBaseDesc . m_size = destSize ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_BLANKLAYOUT :
{
2023-12-19 05:19:14 -05:00
OP : : ImageBlankLayoutArgs args = Program . GetOpArgs < OP : : ImageBlankLayoutArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
// We need to run the full layout
2022-11-23 03:17:56 -05:00
FScheduledOp FullLayoutOp ( args . layout , item ) ;
FullLayoutOp . Type = FScheduledOp : : EType : : Full ;
AddOp ( FScheduledOp ( item . At , item , 1 ) , FullLayoutOp ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case 1 :
{
2024-08-13 10:23:49 -04:00
Ptr < const Layout > pLayout = LoadLayout ( FCacheAddress ( args . layout , item ) ) ;
2022-09-26 15:12:13 -04:00
FIntPoint SizeInBlocks = pLayout - > GetGridSize ( ) ;
FIntPoint BlockSizeInPixels ( args . blockSize [ 0 ] , args . blockSize [ 1 ] ) ;
FIntPoint ImageSizeInPixels = SizeInBlocks * BlockSizeInPixels ;
2022-11-23 03:17:56 -05:00
FImageDesc & ResultAndBaseDesc = m_heapImageDesc [ item . CustomState ] ;
2022-10-06 20:10:22 -04:00
FImageSize destSize ( uint16 ( ImageSizeInPixels . X ) , uint16 ( ImageSizeInPixels . Y ) ) ;
2022-09-26 15:12:13 -04:00
ResultAndBaseDesc . m_size = destSize ;
2023-02-02 02:41:54 -05:00
ResultAndBaseDesc . m_format = args . format ;
2022-09-26 15:12:13 -04:00
if ( args . generateMipmaps )
{
if ( args . mipmapCount = = 0 )
{
ResultAndBaseDesc . m_lods = Image : : GetMipmapCount ( ImageSizeInPixels . X , ImageSizeInPixels . Y ) ;
}
else
{
ResultAndBaseDesc . m_lods = args . mipmapCount ;
}
}
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_COMPOSE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageComposeArgs args = Program . GetOpArgs < OP : : ImageComposeArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_INTERPOLATE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageInterpolateArgs args = Program . GetOpArgs < OP : : ImageInterpolateArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . targets [ 0 ] , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_SATURATE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageSaturateArgs args = Program . GetOpArgs < OP : : ImageSaturateArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_LUMINANCE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageLuminanceArgs args = Program . GetOpArgs < OP : : ImageLuminanceArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] . m_format = EImageFormat : : IF_L_UBYTE ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_SWIZZLE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageSwizzleArgs args = Program . GetOpArgs < OP : : ImageSwizzleArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . sources [ 0 ] , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] . m_format = args . format ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_COLOURMAP :
{
2023-12-19 05:19:14 -05:00
OP : : ImageColourMapArgs args = Program . GetOpArgs < OP : : ImageColourMapArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_GRADIENT :
{
2023-12-19 05:19:14 -05:00
OP : : ImageGradientArgs args = Program . GetOpArgs < OP : : ImageGradientArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] . m_size [ 0 ] = args . size [ 0 ] ;
m_heapImageDesc [ item . CustomState ] . m_size [ 1 ] = args . size [ 1 ] ;
m_heapImageDesc [ item . CustomState ] . m_lods = 1 ;
m_heapImageDesc [ item . CustomState ] . m_format = EImageFormat : : IF_RGB_UBYTE ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : IM_BINARISE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageBinariseArgs args = Program . GetOpArgs < OP : : ImageBinariseArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] . m_format = EImageFormat : : IF_L_UBYTE ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_INVERT :
{
2023-12-19 05:19:14 -05:00
OP : : ImageInvertArgs args = Program . GetOpArgs < OP : : ImageInvertArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_PLAINCOLOUR :
{
2023-12-19 05:19:14 -05:00
OP : : ImagePlainColourArgs args = Program . GetOpArgs < OP : : ImagePlainColourArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] . m_size [ 0 ] = args . size [ 0 ] ;
m_heapImageDesc [ item . CustomState ] . m_size [ 1 ] = args . size [ 1 ] ;
2023-03-17 09:40:20 -04:00
m_heapImageDesc [ item . CustomState ] . m_lods = args . LODs ;
2023-02-02 02:41:54 -05:00
m_heapImageDesc [ item . CustomState ] . m_format = args . format ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : IM_CROP :
{
2023-12-19 05:19:14 -05:00
OP : : ImageCropArgs args = Program . GetOpArgs < OP : : ImageCropArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] . m_size [ 0 ] = args . sizeX ;
m_heapImageDesc [ item . CustomState ] . m_size [ 1 ] = args . sizeY ;
m_heapImageDesc [ item . CustomState ] . m_lods = 1 ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_PATCH :
{
2023-12-19 05:19:14 -05:00
OP : : ImagePatchArgs args = Program . GetOpArgs < OP : : ImagePatchArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . base , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_RASTERMESH :
{
2023-12-19 05:19:14 -05:00
OP : : ImageRasterMeshArgs args = Program . GetOpArgs < OP : : ImageRasterMeshArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] . m_size [ 0 ] = args . sizeX ;
m_heapImageDesc [ item . CustomState ] . m_size [ 1 ] = args . sizeY ;
m_heapImageDesc [ item . CustomState ] . m_lods = 1 ;
m_heapImageDesc [ item . CustomState ] . m_format = EImageFormat : : IF_L_UBYTE ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case OP_TYPE : : IM_MAKEGROWMAP :
{
2023-12-19 05:19:14 -05:00
OP : : ImageMakeGrowMapArgs args = Program . GetOpArgs < OP : : ImageMakeGrowMapArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
2022-11-23 03:17:56 -05:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . mask , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
case 1 :
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] . m_format = EImageFormat : : IF_L_UBYTE ;
m_heapImageDesc [ item . CustomState ] . m_lods = 1 ;
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
default :
check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_DISPLACE :
{
2023-12-19 05:19:14 -05:00
OP : : ImageDisplaceArgs args = Program . GetOpArgs < OP : : ImageDisplaceArgs > ( item . At ) ;
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
2022-11-23 03:17:56 -05:00
case 0 : AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( args . source , item ) ) ; break ;
2023-05-24 02:50:03 -04:00
case 1 : StoreValidDesc ( item ) ; break ;
2022-09-26 15:12:13 -04:00
default : check ( false ) ;
}
break ;
}
case OP_TYPE : : IM_TRANSFORM :
{
2023-12-19 05:19:14 -05:00
OP : : ImageTransformArgs Args = Program . GetOpArgs < OP : : ImageTransformArgs > ( item . At ) ;
2022-09-26 15:12:13 -04:00
2022-11-23 03:17:56 -05:00
switch ( item . Stage )
2022-09-26 15:12:13 -04:00
{
case 0 :
{
2023-08-23 05:27:20 -04:00
AddOp ( FScheduledOp ( item . At , item , 1 ) , FScheduledOp ( Args . Base , item ) ) ;
2022-09-26 15:12:13 -04:00
break ;
}
case 1 :
{
2023-08-23 05:27:20 -04:00
m_heapImageDesc [ item . CustomState ] . m_lods = 1 ;
m_heapImageDesc [ item . CustomState ] . m_format = GetUncompressedFormat ( m_heapImageDesc [ item . CustomState ] . m_format ) ;
if ( ! ( Args . SizeX = = 0 & & Args . SizeY = = 0 ) )
{
m_heapImageDesc [ item . CustomState ] . m_size [ 0 ] = Args . SizeX ;
m_heapImageDesc [ item . CustomState ] . m_size [ 1 ] = Args . SizeY ;
}
2023-05-24 02:50:03 -04:00
StoreValidDesc ( item ) ;
2022-09-26 15:12:13 -04:00
break ;
}
default :
check ( false ) ;
}
break ;
}
default :
if ( type ! = OP_TYPE : : NONE )
{
// Operation not implemented
check ( false ) ;
2022-11-23 03:17:56 -05:00
m_heapImageDesc [ item . CustomState ] = FImageDesc ( ) ;
2022-09-26 15:12:13 -04:00
}
break ;
}
}
}