// Copyright Epic Games, Inc. All Rights Reserved. #include "MuR/Model.h" #include "Containers/Array.h" #include "Containers/Map.h" #include "HAL/LowLevelMemTracker.h" #include "HAL/PlatformMath.h" #include "Misc/AssertionMacros.h" #include "MuR/Image.h" #include "MuR/Mesh.h" #include "MuR/ModelPrivate.h" #include "MuR/Operations.h" #include "MuR/ParametersPrivate.h" #include "MuR/Serialisation.h" #include "MuR/SerialisationPrivate.h" #include "MuR/System.h" #include "MuR/Types.h" #include "Templates/Tuple.h" namespace mu { MUTABLE_IMPLEMENT_POD_SERIALISABLE(FRomData); MUTABLE_IMPLEMENT_POD_SERIALISABLE(FImageLODRange); //--------------------------------------------------------------------------------------------- void FProgram::Check() { #ifdef MUTABLE_DEBUG // Insert debug checks here. #endif } //--------------------------------------------------------------------------------------------- void FProgram::LogHistogram() const { #if 0 uint64 countPerType[(int32)OP_TYPE::COUNT]; mutable_memset(countPerType,0,sizeof(countPerType)); for ( const uint32& o: m_opAddress ) { OP_TYPE type = GetOpType(o); countPerType[(int32)type]++; } TArray< TPair > sorted((int32)OP_TYPE::COUNT); for (int32 i=0; i<(int32)OP_TYPE::COUNT; ++i) { sorted[i].second = (OP_TYPE)i; sorted[i].first = countPerType[i]; } std::sort(sorted.begin(),sorted.end(), []( const pair& a, const pair& b ) { return a.first>b.first; }); UE_LOG(LogMutableCore,Log, TEXT("Op histogram (%llu ops):"), m_opAddress.Num()); for(int32 i=0; i<8; ++i) { float p = sorted[i].first/float(m_opAddress.Num())*100.0f; UE_LOG(LogMutableCore,Log, TEXT(" %3.2f%% : %d"), p, (int32)sorted[i].second ); } #endif } //--------------------------------------------------------------------------------------------- void Model::Private::UnloadRoms() { for (int32 RomIndex = 0; RomIndex < m_program.m_roms.Num(); ++RomIndex) { m_program.UnloadRom(RomIndex); } } //--------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------- Model::Model() { m_pD = new Private(); } //--------------------------------------------------------------------------------------------- Model::~Model() { MUTABLE_CPUPROFILER_SCOPE(ModelDestructor); check( m_pD ); delete m_pD; m_pD = 0; } //--------------------------------------------------------------------------------------------- void Model::Serialise( const Model* p, OutputArchive& arch ) { LLM_SCOPE_BYNAME(TEXT("MutableRuntime")); arch << *p->m_pD; } //--------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------- class OutputModelStream : public OutputStream { public: //----------------------------------------------------------------------------------------- // Life cycle //----------------------------------------------------------------------------------------- OutputModelStream(ModelWriter* pStreamer ) : m_pStreamer( pStreamer ) { } //----------------------------------------------------------------------------------------- // InputStream interface //----------------------------------------------------------------------------------------- void Write( const void* pData, uint64 size ) override { m_pStreamer->Write( pData, size ); } private: ModelWriter* m_pStreamer; }; //--------------------------------------------------------------------------------------------- void Model::Serialise( Model* p, ModelWriter& streamer, bool bDropData ) { LLM_SCOPE_BYNAME(TEXT("MutableRuntime")); mu::FProgram& program = p->m_pD->m_program; TArray> InitialImages; TArray> InitialMeshes; if (!bDropData) { InitialImages = program.ConstantImageLODs; InitialMeshes = program.ConstantMeshes; } OutputMemoryStream MemStream(16 * 1024 * 1024); // Save images and unload from memory for (int32 ResourceIndex = 0; ResourceIndex < program.ConstantImageLODs.Num(); ++ResourceIndex) { TPair& ResData = program.ConstantImageLODs[ResourceIndex]; // This shouldn't have been serialised with rom support before. if (ResData.Key < 0) { continue; } int32 RomIndex = ResData.Key; const FRomData& RomData = program.m_roms[RomIndex]; check(RomData.ResourceType == DT_IMAGE); check(RomData.ResourceIndex == ResourceIndex); // Serialize to memory, to find out final size of this rom MemStream.Reset(); OutputArchive MemoryArch(&MemStream); Image::Serialise(ResData.Value.get(), MemoryArch); check(RomData.Size == MemStream.GetBufferSize()); streamer.OpenWriteFile(RomData.Id); streamer.Write(MemStream.GetBuffer(), MemStream.GetBufferSize()); streamer.CloseWriteFile(); // We clear it to avoid including it also with the main model data ResData.Value = nullptr; } // Save meshes and unload from memory for (int32 ResourceIndex = 0; ResourceIndex < program.ConstantMeshes.Num(); ++ResourceIndex) { TPair& ResData = program.ConstantMeshes[ResourceIndex]; // This shouldn't have been serialised with rom support before. if (ResData.Key < 0) { continue; } int32 RomIndex = ResData.Key; const FRomData& RomData = program.m_roms[RomIndex]; check(RomData.ResourceType == DT_MESH); check(RomData.ResourceIndex == ResourceIndex); // Serialize to memory, to find out final size of this rom MemStream.Reset(); OutputArchive MemoryArch(&MemStream); Mesh::Serialise(ResData.Value.get(), MemoryArch); check(RomData.Size == MemStream.GetBufferSize()); streamer.OpenWriteFile(RomData.Id); streamer.Write(MemStream.GetBuffer(), MemStream.GetBufferSize()); streamer.CloseWriteFile(); // We clear it to avoid including it also with the main model data ResData.Value = nullptr; } // Store the main data of the model { streamer.OpenWriteFile(0); OutputModelStream stream(&streamer); OutputArchive arch(&stream); arch << *p->m_pD; streamer.CloseWriteFile(); } // Restore full data if (!bDropData) { program.ConstantImageLODs = InitialImages; program.ConstantMeshes = InitialMeshes; } } //--------------------------------------------------------------------------------------------- bool Model::HasExternalData() const { return m_pD->m_program.m_roms.Num() > 0; } #if WITH_EDITOR //--------------------------------------------------------------------------------------------- bool Model::IsValid() const { return m_pD->m_program.bIsValid; } //--------------------------------------------------------------------------------------------- void Model::Invalidate() { m_pD->m_program.bIsValid = false; } #endif //--------------------------------------------------------------------------------------------- void Model::UnloadExternalData() { LLM_SCOPE_BYNAME(TEXT("MutableRuntime")); for (int32 ResIndex = 0; ResIndex < m_pD->m_program.ConstantImageLODs.Num(); ++ResIndex) { if (m_pD->m_program.ConstantImageLODs[ResIndex].Key >= 0) { m_pD->m_program.ConstantImageLODs[ResIndex].Value = nullptr; } } for (int32 ResIndex = 0; ResIndex < m_pD->m_program.ConstantMeshes.Num(); ++ResIndex) { if (m_pD->m_program.ConstantMeshes[ResIndex].Key >= 0) { m_pD->m_program.ConstantMeshes[ResIndex].Value = nullptr; } } } //--------------------------------------------------------------------------------------------- TSharedPtr Model::StaticUnserialise( InputArchive& arch ) { LLM_SCOPE_BYNAME(TEXT("MutableRuntime")); TSharedPtr pResult = MakeShared(); arch >> *pResult->m_pD; return pResult; } //--------------------------------------------------------------------------------------------- Model::Private* Model::GetPrivate() const { return m_pD; } //--------------------------------------------------------------------------------------------- bool Model::GetBoolDefaultValue(int32 Index) const { check(m_pD->m_program.m_parameters.IsValidIndex(Index)); check(m_pD->m_program.m_parameters[Index].m_type == PARAMETER_TYPE::T_BOOL); // Early out in case of invalid parameters if (!m_pD->m_program.m_parameters.IsValidIndex(Index) || m_pD->m_program.m_parameters[Index].m_type != PARAMETER_TYPE::T_BOOL) { return false; } return m_pD->m_program.m_parameters[Index].m_defaultValue.Get(); } //--------------------------------------------------------------------------------------------- int32 Model::GetIntDefaultValue(int32 Index) const { check(m_pD->m_program.m_parameters.IsValidIndex(Index)); check(m_pD->m_program.m_parameters[Index].m_type == PARAMETER_TYPE::T_INT); // Early out in case of invalid parameters if (!m_pD->m_program.m_parameters.IsValidIndex(Index) || m_pD->m_program.m_parameters[Index].m_type != PARAMETER_TYPE::T_INT) { return 0; } return m_pD->m_program.m_parameters[Index].m_defaultValue.Get(); } //--------------------------------------------------------------------------------------------- float Model::GetFloatDefaultValue(int32 Index) const { check(m_pD->m_program.m_parameters.IsValidIndex(Index)); check(m_pD->m_program.m_parameters[Index].m_type == PARAMETER_TYPE::T_FLOAT); // Early out in case of invalid parameters if (!m_pD->m_program.m_parameters.IsValidIndex(Index) || m_pD->m_program.m_parameters[Index].m_type != PARAMETER_TYPE::T_FLOAT) { return 0.0f; } return m_pD->m_program.m_parameters[Index].m_defaultValue.Get(); } void Model::GetColourDefaultValue(int32 Index, float* R, float* G, float* B, float* A) const { check(m_pD->m_program.m_parameters.IsValidIndex(Index)); check(m_pD->m_program.m_parameters[Index].m_type == PARAMETER_TYPE::T_COLOUR); // Early out in case of invalid parameters if (!m_pD->m_program.m_parameters.IsValidIndex(Index) || m_pD->m_program.m_parameters[Index].m_type != PARAMETER_TYPE::T_COLOUR) { return; } ParamColorType& Color = m_pD->m_program.m_parameters[Index].m_defaultValue.Get(); if (R) { *R = Color[0]; } if (G) { *G = Color[1]; } if (B) { *B = Color[2]; } if (A) { *A = Color[3]; } } FMatrix44f Model::GetMatrixDefaultValue(int32 Index) const { check(m_pD->m_program.m_parameters.IsValidIndex(Index)); check(m_pD->m_program.m_parameters[Index].m_type == PARAMETER_TYPE::T_MATRIX); // Early out in case of invalid parameters if (!m_pD->m_program.m_parameters.IsValidIndex(Index) || m_pD->m_program.m_parameters[Index].m_type != PARAMETER_TYPE::T_MATRIX) { return FMatrix44f::Identity; } return m_pD->m_program.m_parameters[Index].m_defaultValue.Get(); } void Model::GetProjectorDefaultValue(int32 Index, PROJECTOR_TYPE* OutProjectionType, FVector3f* OutPos, FVector3f* OutDir, FVector3f* OutUp, FVector3f* OutScale, float* OutProjectionAngle) const { check(m_pD->m_program.m_parameters.IsValidIndex(Index)); check(m_pD->m_program.m_parameters[Index].m_type == PARAMETER_TYPE::T_PROJECTOR); // Early out in case of invalid parameters if (!m_pD->m_program.m_parameters.IsValidIndex(Index) || m_pD->m_program.m_parameters[Index].m_type != PARAMETER_TYPE::T_PROJECTOR) { return; } const FProjector& Projector = m_pD->m_program.m_parameters[Index].m_defaultValue.Get(); if (OutProjectionType) *OutProjectionType = Projector.type; if (OutPos) *OutPos = Projector.position; if (OutDir) *OutDir = Projector.direction; if (OutUp) *OutUp = Projector.up; if (OutScale) *OutScale = Projector.scale; if (OutProjectionAngle) *OutProjectionAngle = Projector.projectionAngle; } //--------------------------------------------------------------------------------------------- FName Model::GetImageDefaultValue(int32 Index) const { check(m_pD->m_program.m_parameters.IsValidIndex(Index)); check(m_pD->m_program.m_parameters[Index].m_type == PARAMETER_TYPE::T_IMAGE); // Early out in case of invalid parameters if (!m_pD->m_program.m_parameters.IsValidIndex(Index) || m_pD->m_program.m_parameters[Index].m_type != PARAMETER_TYPE::T_IMAGE) { return {}; } return m_pD->m_program.m_parameters[Index].m_defaultValue.Get(); } //--------------------------------------------------------------------------------------------- int32 Model::GetRomCount() const { return m_pD->m_program.m_roms.Num(); } uint32 Model::GetRomId(int32 Index) const { return m_pD->m_program.m_roms[Index].Id; } uint32 Model::GetRomSourceId(int32 Index) const { return m_pD->m_program.m_roms[Index].SourceId; } uint32 Model::GetRomSize(int32 Index) const { return m_pD->m_program.m_roms[Index].Size; } uint16 Model::GetRomType(int32 Index) const { return m_pD->m_program.m_roms[Index].ResourceType; } ERomFlags Model::GetRomFlags(int32 Index) const { return m_pD->m_program.m_roms[Index].Flags; } //--------------------------------------------------------------------------------------------- ParametersPtr Model::NewParameters(TSharedPtr Model, const Parameters* pOld ) { LLM_SCOPE_BYNAME(TEXT("MutableRuntime")); ParametersPtr pRes = new Parameters(); pRes->GetPrivate()->m_pModel = Model; const FProgram& Program = Model->GetPrivate()->m_program; pRes->GetPrivate()->m_values.SetNum(Program.m_parameters.Num()); for ( int32 p=0; p< Program.m_parameters.Num(); ++p ) { pRes->GetPrivate()->m_values[p] = Program.m_parameters[p].m_defaultValue; } // Copy old values if ( pOld ) { for ( int p=0; pGetCount(); ++p ) { int thisP = pRes->GetPrivate()->Find( pOld->GetName(p) ); if ( thisP>=0 ) { if ( pOld->GetType(p)==pRes->GetType(thisP) ) { switch ( pRes->GetType(thisP) ) { case PARAMETER_TYPE::T_BOOL: pRes->SetBoolValue( thisP, pOld->GetBoolValue(p) ); break; case PARAMETER_TYPE::T_INT: pRes->SetIntValue( thisP, pOld->GetIntValue(p) ); break; case PARAMETER_TYPE::T_FLOAT: pRes->SetFloatValue( thisP, pOld->GetFloatValue(p) ); break; case PARAMETER_TYPE::T_COLOUR: { float R, G, B, A; pOld->GetColourValue( p, &R, &G, &B, &A ); pRes->SetColourValue( thisP, R, G, B, A ); break; } case PARAMETER_TYPE::T_PROJECTOR: { // float m[16]; // pOld->GetProjectorValue( p, m ); pRes->GetPrivate()->m_values[thisP].Set(pOld->GetPrivate()->m_values[p].Get()); break; } case PARAMETER_TYPE::T_IMAGE: pRes->SetImageValue( thisP, pOld->GetImageValue(p) ); break; default: check(false); break; } } } } } return pRes; } //--------------------------------------------------------------------------------------------- bool Model::IsParameterMultidimensional(const int32 ParamIndex) const { if (m_pD->m_program.m_parameters.IsValidIndex(ParamIndex)) { return m_pD->m_program.m_parameters[ParamIndex].m_ranges.Num() > 0; } return false; } //--------------------------------------------------------------------------------------------- int Model::GetStateCount() const { return (int)m_pD->m_program.m_states.Num(); } //--------------------------------------------------------------------------------------------- const FString& Model::GetStateName( int32 index ) const { const char* strRes = 0; if ( index>=0 && index<(int)m_pD->m_program.m_states.Num() ) { return m_pD->m_program.m_states[index].Name; } static FString None; return None; } //--------------------------------------------------------------------------------------------- int32 Model::FindState( const FString& Name ) const { int res = -1; for ( int i=0; res<0 && i<(int)m_pD->m_program.m_states.Num(); ++i ) { if ( m_pD->m_program.m_states[i].Name == Name ) { res = i; } } return res; } //--------------------------------------------------------------------------------------------- int Model::GetStateParameterCount( int stateIndex ) const { int res = -1; if ( stateIndex>=0 && stateIndex<(int)m_pD->m_program.m_states.Num() ) { res = (int)m_pD->m_program.m_states[stateIndex].m_runtimeParameters.Num(); } return res; } //--------------------------------------------------------------------------------------------- int Model::GetStateParameterIndex( int stateIndex, int paramIndex ) const { int res = -1; if ( stateIndex>=0 && stateIndex<(int)m_pD->m_program.m_states.Num() ) { const FProgram::FState& state = m_pD->m_program.m_states[stateIndex]; if ( paramIndex>=0 && paramIndex<(int)state.m_runtimeParameters.Num() ) { res = (int)state.m_runtimeParameters[paramIndex]; } } return res; } //--------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------- ModelParametersGenerator::ModelParametersGenerator ( TSharedPtr pModel, System* pSystem ) { LLM_SCOPE_BYNAME(TEXT("MutableRuntime")); m_pD = new Private(); m_pD->m_pModel = pModel; m_pD->m_pSystem = pSystem; size_t paramCount = pModel->GetPrivate()->m_program.m_parameters.Num(); m_pD->m_instanceCount = 1; for (size_t i=0;im_pModel->GetPrivate()->m_program.m_parameters[ i ]; switch ( param.m_type ) { case PARAMETER_TYPE::T_INT: { m_pD->m_instanceCount *= param.m_possibleValues.Num(); break; } case PARAMETER_TYPE::T_BOOL: { m_pD->m_instanceCount *= 2; break; } default: // Parameter not discrete, so ignored for combinations. break; } } } //--------------------------------------------------------------------------------------------- ModelParametersGenerator::~ModelParametersGenerator() { LLM_SCOPE_BYNAME(TEXT("MutableRuntime")); check( m_pD ); delete m_pD; m_pD = 0; } //--------------------------------------------------------------------------------------------- ModelParametersGenerator::Private* ModelParametersGenerator::GetPrivate() const { return m_pD; } //--------------------------------------------------------------------------------------------- int64 ModelParametersGenerator::GetInstanceCount() { return m_pD->m_instanceCount; } //--------------------------------------------------------------------------------------------- Ptr ModelParametersGenerator::GetInstance( int64 index, TFunction RandomGenerator ) { LLM_SCOPE_BYNAME(TEXT("MutableRuntime")); Ptr res = Model::NewParameters(m_pD->m_pModel); const FProgram& Program = m_pD->m_pModel->GetPrivate()->m_program; int paramCount = Program.m_parameters.Num(); int64 currentInstance = index; for (int i=0;i RangeIndex = res->NewRangeIndex(i); switch ( param.m_type ) { case PARAMETER_TYPE::T_INT: { bool bIsRangeSize = Program.m_ranges.ContainsByPredicate([i](const FRangeDesc& r) { return r.m_dimensionParameter == i; }); if (bIsRangeSize) { res->SetIntValue(i, m_pD->DefaultRangeDimension); } else { int numOptions = res->GetIntPossibleValueCount(i); int value = res->GetIntPossibleValue(i, (int)(currentInstance % numOptions)); res->SetIntValue(i, value); currentInstance /= numOptions; } break; } case PARAMETER_TYPE::T_BOOL: { res->SetBoolValue( i, currentInstance%2!=0 ); currentInstance /= 2; break; } case PARAMETER_TYPE::T_FLOAT: { bool bIsRangeSize = Program.m_ranges.ContainsByPredicate([i](const FRangeDesc& r) { return r.m_dimensionParameter == i; }); if (bIsRangeSize) { if (RangeIndex) { for (int32 Dimensions = 0; Dimensions < RangeIndex->GetRangeCount(); ++Dimensions) { for (int32 RangePosition = 0; RangePosition < m_pD->DefaultRangeDimension; ++RangePosition) { RangeIndex->SetPosition(Dimensions, RangePosition); res->SetFloatValue(i, float(m_pD->DefaultRangeDimension), RangeIndex); } } } else { res->SetFloatValue(i, float(m_pD->DefaultRangeDimension)); } } else if (RandomGenerator) { if (RangeIndex) { for (int32 Dimensions = 0; Dimensions < RangeIndex->GetRangeCount(); ++Dimensions) { for (int32 RangePosition = 0; RangePosition < m_pD->DefaultRangeDimension; ++RangePosition) { RangeIndex->SetPosition(Dimensions, RangePosition); res->SetFloatValue(i, RandomGenerator(), RangeIndex); } } } else { res->SetFloatValue(i, RandomGenerator()); } } break; } case PARAMETER_TYPE::T_COLOUR: if (RandomGenerator) { if (RangeIndex) { for (int32 Dimensions = 0; Dimensions < RangeIndex->GetRangeCount(); ++Dimensions) { for (int32 RangePosition = 0; RangePosition < m_pD->DefaultRangeDimension; ++RangePosition) { RangeIndex->SetPosition(Dimensions, RangePosition); res->SetColourValue(i, RandomGenerator(), RandomGenerator(), RandomGenerator(), RandomGenerator(), RangeIndex); } } } else { res->SetColourValue(i, RandomGenerator(), RandomGenerator(), RandomGenerator(), RandomGenerator()); } } break; case PARAMETER_TYPE::T_PROJECTOR: if (RandomGenerator) { // For projectors we just warp the position a little bit just to get something different FVector3f Position, Direction, Up, Scale; float Angle = 1.0f; res->GetProjectorValue(i, nullptr, &Position, &Direction, &Up, &Scale, &Angle); if (RangeIndex) { for (int32 Dimensions = 0; Dimensions < RangeIndex->GetRangeCount(); ++Dimensions) { for (int32 RangePosition = 0; RangePosition < m_pD->DefaultRangeDimension; ++RangePosition) { RangeIndex->SetPosition(Dimensions, RangePosition); Position.X *= 0.9 + RandomGenerator() * 0.2f; Position.Y *= 0.9 + RandomGenerator() * 0.2f; Position.Z *= 0.9 + RandomGenerator() * 0.2f; res->SetProjectorValue(i, Position, Direction, Up, Scale, Angle, RangeIndex); } } } else { Position.X *= 0.9 + RandomGenerator() * 0.2f; Position.Y *= 0.9 + RandomGenerator() * 0.2f; Position.Z *= 0.9 + RandomGenerator() * 0.2f; res->SetProjectorValue(i, Position, Direction, Up, Scale, Angle); } } break; default: break; } } return res; } //--------------------------------------------------------------------------------------------- ParametersPtr ModelParametersGenerator::GetRandomInstance( TFunctionRef randomGenerator) { LLM_SCOPE_BYNAME(TEXT("MutableRuntime")); ParametersPtr res = Model::NewParameters(m_pD->m_pModel); const FProgram& Program = m_pD->m_pModel->GetPrivate()->m_program; int32 ParamCount = Program.m_parameters.Num(); for (int i=0;i RangeIndex = res->NewRangeIndex(i); switch ( param.m_type ) { case PARAMETER_TYPE::T_INT: { bool bIsRangeSize = Program.m_ranges.ContainsByPredicate([i](const FRangeDesc& r) { return r.m_dimensionParameter == i; }); if (bIsRangeSize) { if (RangeIndex) { for (int32 Dimensions = 0; Dimensions < RangeIndex->GetRangeCount(); ++Dimensions) { for (int32 RangePosition = 0; RangePosition < m_pD->DefaultRangeDimension; ++RangePosition) { RangeIndex->SetPosition(Dimensions, RangePosition); res->SetIntValue(i, m_pD->DefaultRangeDimension, RangeIndex); } } } else { res->SetIntValue(i, m_pD->DefaultRangeDimension); } } else { if (RangeIndex) { for (int32 Dimensions = 0; Dimensions < RangeIndex->GetRangeCount(); ++Dimensions) { for (int32 RangePosition = 0; RangePosition < m_pD->DefaultRangeDimension; ++RangePosition) { int numOptions = res->GetIntPossibleValueCount(i); int valueIndex = (int)(FMath::Min(numOptions - 1, int(randomGenerator() * numOptions))); int value = res->GetIntPossibleValue(i, valueIndex); res->SetIntValue(i, value, RangeIndex); } } } else { int numOptions = res->GetIntPossibleValueCount(i); int valueIndex = (int)(FMath::Min(numOptions - 1, int(randomGenerator() * numOptions))); int value = res->GetIntPossibleValue(i, valueIndex); res->SetIntValue(i, value); } } break; } case PARAMETER_TYPE::T_BOOL: { res->SetBoolValue( i, randomGenerator()>0.5f ); break; } case PARAMETER_TYPE::T_FLOAT: { bool bIsRangeSize = Program.m_ranges.ContainsByPredicate([i](const FRangeDesc& r) { return r.m_dimensionParameter == i; }); if (bIsRangeSize) { if (RangeIndex) { for (int32 Dimensions = 0; Dimensions < RangeIndex->GetRangeCount(); ++Dimensions) { for (int32 RangePosition = 0; RangePosition < m_pD->DefaultRangeDimension; ++RangePosition) { res->SetFloatValue(i, float(m_pD->DefaultRangeDimension), RangeIndex); } } } else { res->SetFloatValue(i, float(m_pD->DefaultRangeDimension)); } } else { if (RangeIndex) { for (int32 Dimensions = 0; Dimensions < RangeIndex->GetRangeCount(); ++Dimensions) { for (int32 RangePosition = 0; RangePosition < m_pD->DefaultRangeDimension; ++RangePosition) { res->SetFloatValue(i, randomGenerator(), RangeIndex); } } } else { res->SetFloatValue(i, randomGenerator()); } } break; } case PARAMETER_TYPE::T_COLOUR: if (RangeIndex) { for (int32 Dimensions = 0; Dimensions < RangeIndex->GetRangeCount(); ++Dimensions) { for (int32 RangePosition = 0; RangePosition < m_pD->DefaultRangeDimension; ++RangePosition) { res->SetColourValue(i, randomGenerator(), randomGenerator(), randomGenerator(), randomGenerator(), RangeIndex); } } } else { res->SetColourValue(i, randomGenerator(), randomGenerator(), randomGenerator(), randomGenerator()); } break; case PARAMETER_TYPE::T_PROJECTOR: { // For projectors we just warp the position a little bit just to get something different FVector3f Position, Direction, Up, Scale; float Angle = 1.0f; res->GetProjectorValue(i, nullptr, &Position, &Direction, &Up, &Scale, &Angle); if (RangeIndex) { for (int32 Dimensions = 0; Dimensions < RangeIndex->GetRangeCount(); ++Dimensions) { for (int32 RangePosition = 0; RangePosition < m_pD->DefaultRangeDimension; ++RangePosition) { Position.X *= 0.9 + randomGenerator() * 0.2f; Position.Y *= 0.9 + randomGenerator() * 0.2f; Position.Z *= 0.9 + randomGenerator() * 0.2f; res->SetProjectorValue(i, Position, Direction, Up, Scale, Angle, RangeIndex); } } } else { Position.X *= 0.9 + randomGenerator() * 0.2f; Position.Y *= 0.9 + randomGenerator() * 0.2f; Position.Z *= 0.9 + randomGenerator() * 0.2f; res->SetProjectorValue(i, Position, Direction, Up, Scale, Angle); } break; } default: break; } } return res; } }