#31 Add methods for saving and loading weather presets to config file

This commit is contained in:
nsubiron 2017-05-12 18:18:46 +02:00
parent 4d400256d8
commit b546d86e6b
6 changed files with 372 additions and 56 deletions

View File

@ -3,8 +3,54 @@
#include "Carla.h"
#include "DynamicWeather.h"
#include "IniFile.h"
#include "Components/ArrowComponent.h"
static bool GetWeatherIniFileName(FString &FileName)
{
FileName = FPaths::Combine(FPaths::GameConfigDir(), TEXT("CarlaWeather.ini"));
const bool bFileExists = FPaths::FileExists(FileName);
if (!bFileExists) {
UE_LOG(LogCarla, Error, TEXT("\"%s\" no such file"), *FileName);
}
return bFileExists;
}
static bool CheckWeatherValidity(const FWeatherDescription &Weather)
{
if (Weather.Name.IsEmpty()) {
UE_LOG(LogCarla, Error, TEXT("Weather doesn't have a name, please provide one"));
return false;
}
return true;
}
TArray<FWeatherDescription> ADynamicWeather::LoadWeatherDescriptionsFromFile()
{
TArray<FWeatherDescription> Descriptions;
// Try to load config file.
FString FileName;
if (GetWeatherIniFileName(FileName)) {
IniFile ConfigFile(FileName);
// For every section in the config file add a weather description.
for (auto &Item : ConfigFile.GetFConfigFile()) {
Descriptions.AddDefaulted(1u);
Descriptions.Last().ReadFromConfigFile(ConfigFile, Item.Key);
}
}
// If no description was found, append a defaulted one.
if (Descriptions.Num() == 0) {
UE_LOG(LogCarla, Warning, TEXT("No weather description found"));
Descriptions.AddDefaulted(1u);
}
return Descriptions;
}
ADynamicWeather::ADynamicWeather(const FObjectInitializer& ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = false;
@ -42,6 +88,22 @@ void ADynamicWeather::PostEditChangeProperty(FPropertyChangedEvent &Event)
} else {
AdjustSunPositionBasedOnActorRotation();
}
if (bSaveToConfigFile) {
bSaveToConfigFile = false;
if (SaveToConfigFile()) {
UE_LOG(LogCarla, Log, TEXT("Weather \"%s\" saved to config file"), *Weather.Name);
} else {
UE_LOG(LogCarla, Error, TEXT("Error saving weather to config file"));
}
}
if (bLoadFromConfigFile) {
bLoadFromConfigFile = false;
if (LoadFromConfigFile()) {
UE_LOG(LogCarla, Log, TEXT("Weather \"%s\" loaded from config file"), *Weather.Name);
} else {
UE_LOG(LogCarla, Error, TEXT("Error loading weather from config file"));
}
}
}
void ADynamicWeather::EditorApplyRotation(
@ -81,3 +143,35 @@ void ADynamicWeather::AdjustSunPositionBasedOnActorRotation()
Weather.SunPolarAngle = FMath::RadiansToDegrees(SphericalCoords.X);
Weather.SunAzimuthAngle = FMath::RadiansToDegrees(SphericalCoords.Y);
}
#if WITH_EDITOR
bool ADynamicWeather::LoadFromConfigFile()
{
FString FileName;
if (GetWeatherIniFileName(FileName) && CheckWeatherValidity(Weather)) {
IniFile ConfigFile(FileName);
if (!ConfigFile.HasSection(Weather.Name)) {
UE_LOG(LogCarla, Error, TEXT("Weather \"%s\" is not present in config file"), *Weather.Name);
return false;
}
Weather.ReadFromConfigFile(ConfigFile, Weather.Name);
return true;
} else {
return false;
}
}
bool ADynamicWeather::SaveToConfigFile() const
{
FString FileName;
if (GetWeatherIniFileName(FileName) && CheckWeatherValidity(Weather)) {
IniFile ConfigFile(FileName);
Weather.WriteToConfigFile(ConfigFile);
return ConfigFile.Write(FileName);
} else {
return false;
}
}
#endif // WITH_EDITOR

View File

@ -15,6 +15,9 @@ class CARLA_API ADynamicWeather : public AActor
public:
/// If none is found return the default one.
static TArray<FWeatherDescription> LoadWeatherDescriptionsFromFile();
ADynamicWeather(const FObjectInitializer& ObjectInitializer);
virtual void OnConstruction(const FTransform &Transform) override;
@ -50,11 +53,27 @@ private:
void AdjustSunPositionBasedOnActorRotation();
#if WITH_EDITOR
bool LoadFromConfigFile();
bool SaveToConfigFile() const;
#endif // WITH_EDITOR
#if WITH_EDITORONLY_DATA
UPROPERTY()
UArrowComponent* ArrowComponent;
UArrowComponent *ArrowComponent;
#endif // WITH_EDITORONLY_DATA
UPROPERTY(Category = "Weather", EditAnywhere)
#if WITH_EDITOR
UPROPERTY(Category = "Weather Description", EditAnywhere)
bool bLoadFromConfigFile = false;
UPROPERTY(Category = "Weather Description", EditAnywhere)
bool bSaveToConfigFile = false;
#endif // WITH_EDITOR
UPROPERTY(Category = "Weather Description", EditAnywhere)
FWeatherDescription Weather;
};

View File

@ -4,66 +4,25 @@
#include "CarlaSettings.h"
#include "CommandLine.h"
#include "ConfigCacheIni.h"
#include <limits>
#include "IniFile.h"
// INI file sections.
#define S_CARLA_SERVER TEXT("CARLA/Server")
#define S_CARLA_SCENECAPTURE TEXT("CARLA/SceneCapture")
template <typename TARGET, typename SOURCE>
static void SafeCastTo(SOURCE source, TARGET &target)
{
if ((source >= std::numeric_limits<TARGET>::lowest()) &&
(source <= std::numeric_limits<TARGET>::max())) {
target = static_cast<TARGET>(source);
} else {
UE_LOG(LogCarla, Error, TEXT("CarlaSettings: Type cast failed"));
}
}
// =============================================================================
// -- INIFile ------------------------------------------------------------------
// -- MyIniFile ----------------------------------------------------------------
// =============================================================================
class INIFile {
class MyIniFile : public IniFile {
public:
explicit INIFile(const FString &FileName)
{
ConfigFile.Read(FileName);
}
void GetBool(const TCHAR* Section, const TCHAR* Key, bool &Target) const
{
bool Value;
if (ConfigFile.GetBool(Section, Key, Value)) {
Target = Value;
}
}
template <typename T>
void GetInt(const TCHAR* Section, const TCHAR* Key, T &Target) const
{
int64 Value;
if (ConfigFile.GetInt64(Section, Key, Value)) {
SafeCastTo<T>(Value, Target);
}
}
void GetString(const TCHAR* Section, const TCHAR* Key, FString &Target) const
{
FString Value;
if (ConfigFile.GetString(Section, Key, Value)) {
Target = Value;
}
}
explicit MyIniFile(const FString &FileName) : IniFile(FileName) {}
void GetPostProcessEffect(const TCHAR* Section, const TCHAR* Key, EPostProcessEffect &Target) const
{
FString ValueString;
if (ConfigFile.GetString(Section, Key, ValueString)) {
if (GetFConfigFile().GetString(Section, Key, ValueString)) {
if (ValueString == "None") {
Target = EPostProcessEffect::None;
} else if (ValueString == "SceneFinal") {
@ -78,18 +37,14 @@ public:
}
}
}
private:
FConfigFile ConfigFile;
};
// =============================================================================
// -- Other static methods -----------------------------------------------------
// -- Static methods -----------------------------------------------------------
// =============================================================================
static void GetCameraDescription(
const INIFile &ConfigFile,
const MyIniFile &ConfigFile,
const TCHAR* Section,
FCameraDescription &Camera)
{
@ -120,7 +75,7 @@ static bool RequestedSemanticSegmentation(const FCameraDescription &Camera)
static void LoadSettingsFromFile(const FString &FileName, UCarlaSettings &Settings)
{
UE_LOG(LogCarla, Log, TEXT("Loading settings from \"%s\""), *FileName);
INIFile ConfigFile(FileName);
MyIniFile ConfigFile(FileName);
// CarlaServer.
ConfigFile.GetBool(S_CARLA_SERVER, TEXT("UseNetworking"), Settings.bUseNetworking);
ConfigFile.GetInt(S_CARLA_SERVER, TEXT("WorldPort"), Settings.WorldPort);

154
Source/Carla/IniFile.h Normal file
View File

@ -0,0 +1,154 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#pragma once
#include "ConfigCacheIni.h"
#include <limits>
/// Wrapper around Unreal's INI file. In get functions, @a Target value is only
/// set if it was present in the INI file, otherwise it keeps its value.
class CARLA_API IniFile : private NonCopyable
{
private:
template <typename TARGET, typename SOURCE>
static void SafeCastTo(SOURCE source, TARGET &target)
{
if ((source >= std::numeric_limits<TARGET>::lowest()) &&
(source <= std::numeric_limits<TARGET>::max())) {
target = static_cast<TARGET>(source);
} else {
UE_LOG(LogCarla, Error, TEXT("IniFile: Type cast failed"));
}
}
public:
// ===========================================================================
/// @name Constructor
// ===========================================================================
/// @{
explicit IniFile(const FString &FileName)
{
ConfigFile.Read(FileName);
}
/// @}
// ===========================================================================
/// @name Other functions
// ===========================================================================
/// @{
void AddSectionIfMissing(const FString &Section)
{
ConfigFile.FindOrAddSection(Section);
}
bool HasSection(const FString &Section) const
{
return (ConfigFile.Num() > 0) && (ConfigFile.Find(Section) != nullptr);
}
/// Write contents to disk.
bool Write(const FString &Filename)
{
return ConfigFile.Write(Filename);
}
/// Retrieve Unreal's FConfigFile.
const FConfigFile &GetFConfigFile() const
{
return ConfigFile;
}
/// @}
// ===========================================================================
/// @name Get functions
// ===========================================================================
/// @{
template <typename T>
void GetInt(const TCHAR* Section, const TCHAR* Key, T &Target) const
{
int64 Value;
if (ConfigFile.GetInt64(Section, Key, Value)) {
SafeCastTo<T>(Value, Target);
}
}
void GetString(const TCHAR* Section, const TCHAR* Key, FString &Target) const
{
FString Value;
if (ConfigFile.GetString(Section, Key, Value)) {
Target = Value;
}
}
void GetBool(const TCHAR* Section, const TCHAR* Key, bool &Target) const
{
bool Value;
if (ConfigFile.GetBool(Section, Key, Value)) {
Target = Value;
}
}
void GetFloat(const TCHAR* Section, const TCHAR* Key, float &Target) const
{
FString Value;
if (ConfigFile.GetString(Section, Key, Value)) {
Target = FCString::Atof(*Value);
}
}
void GetLinearColor(const TCHAR* Section, const TCHAR* Key, FLinearColor &Target) const
{
FString Value;
if (ConfigFile.GetString(Section, Key, Value)) {
Target.InitFromString(Value);
}
}
/// @}
// ===========================================================================
/// @name Set functions
// ===========================================================================
/// @{
void SetInt(const TCHAR* Section, const TCHAR* Key, const int64 Value)
{
ConfigFile.SetInt64(Section, Key, Value);
}
void SetString(const TCHAR* Section, const TCHAR* Key, const TCHAR* Value)
{
ConfigFile.SetString(Section, Key, Value);
}
void SetString(const TCHAR* Section, const TCHAR* Key, const FString &Value)
{
SetString(Section, Key, *Value);
}
void SetBool(const TCHAR* Section, const TCHAR* Key, const bool Value)
{
SetString(Section, Key, Value ? TEXT("True") : TEXT("False"));
}
void SetFloat(const TCHAR* Section, const TCHAR* Key, const float Value)
{
SetString(Section, Key, FText::AsNumber(Value).ToString());
}
void SetLinearColor(const TCHAR* Section, const TCHAR* Key, const FLinearColor &Value)
{
SetString(Section, Key, Value.ToString());
}
/// @}
private:
FConfigFile ConfigFile;
};

View File

@ -0,0 +1,88 @@
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
#include "Carla.h"
#include "WeatherDescription.h"
#include "IniFile.h"
static FString PrecipitationTypeToString(EPrecipitationType PrecipitationType)
{
const UEnum* ptr = FindObject<UEnum>(ANY_PACKAGE, TEXT("EPrecipitationType"), true);
if(!ptr)
return FString("Rain");
return ptr->GetEnumName(static_cast<int32>(PrecipitationType));
}
static void LoadPrecipitationType(
const IniFile &ConfigFile,
const TCHAR* Section,
const TCHAR* Key,
EPrecipitationType &Target)
{
FString ValueString;
if (ConfigFile.GetFConfigFile().GetString(Section, Key, ValueString)) {
if (ValueString == "Rain") {
Target = EPrecipitationType::Rain;
} else {
UE_LOG(LogCarla, Error, TEXT("Invalid precipitation type \"%s\" in INI file"), *ValueString);
Target = EPrecipitationType::Rain;
}
}
}
void FWeatherDescription::ReadFromConfigFile(const IniFile &ConfigFile, const FString &Section)
{
Name = Section;
#define CARLA_LOAD_FROM_INI(Type, Key) ConfigFile.Get ## Type(*Section, TEXT(#Key), Key);
// Sun.
CARLA_LOAD_FROM_INI(Float, SunPolarAngle)
CARLA_LOAD_FROM_INI(Float, SunAzimuthAngle)
CARLA_LOAD_FROM_INI(Float, SunBrightness)
CARLA_LOAD_FROM_INI(Float, SunDirectionalLightIntensity)
CARLA_LOAD_FROM_INI(LinearColor, SunDirectionalLightColor)
CARLA_LOAD_FROM_INI(Float, SunIndirectLightIntensity)
// Sky.
CARLA_LOAD_FROM_INI(Float, CloudOpacity)
CARLA_LOAD_FROM_INI(Float, HorizontFalloff)
CARLA_LOAD_FROM_INI(LinearColor, ZenithColor)
CARLA_LOAD_FROM_INI(LinearColor, HorizonColor)
CARLA_LOAD_FROM_INI(LinearColor, CloudColor)
CARLA_LOAD_FROM_INI(LinearColor, OverallSkyColor)
CARLA_LOAD_FROM_INI(Float, SkyLightIntensity)
CARLA_LOAD_FROM_INI(LinearColor, SkyLightColor)
// Precipitation.
CARLA_LOAD_FROM_INI(Bool, bPrecipitation)
LoadPrecipitationType(ConfigFile, *Section, TEXT("PrecipitationType"), PrecipitationType);
CARLA_LOAD_FROM_INI(Float, PrecipitationAmount)
CARLA_LOAD_FROM_INI(Float, PrecipitationAccumulation)
#undef CARLA_LOAD_FROM_INI
}
void FWeatherDescription::WriteToConfigFile(IniFile &ConfigFile) const
{
const FString &Section = Name;
ConfigFile.AddSectionIfMissing(Section);
#define CARLA_WRITE_TO_INI(Type, Key) ConfigFile.Set ## Type(*Section, TEXT(#Key), Key);
// Sun.
CARLA_WRITE_TO_INI(Float, SunPolarAngle)
CARLA_WRITE_TO_INI(Float, SunAzimuthAngle)
CARLA_WRITE_TO_INI(Float, SunBrightness)
CARLA_WRITE_TO_INI(Float, SunDirectionalLightIntensity)
CARLA_WRITE_TO_INI(LinearColor, SunDirectionalLightColor)
CARLA_WRITE_TO_INI(Float, SunIndirectLightIntensity)
// Sky.
CARLA_WRITE_TO_INI(Float, CloudOpacity)
CARLA_WRITE_TO_INI(Float, HorizontFalloff)
CARLA_WRITE_TO_INI(LinearColor, ZenithColor)
CARLA_WRITE_TO_INI(LinearColor, HorizonColor)
CARLA_WRITE_TO_INI(LinearColor, CloudColor)
CARLA_WRITE_TO_INI(LinearColor, OverallSkyColor)
CARLA_WRITE_TO_INI(Float, SkyLightIntensity)
CARLA_WRITE_TO_INI(LinearColor, SkyLightColor)
// Precipitation.
CARLA_WRITE_TO_INI(Bool, bPrecipitation)
ConfigFile.SetString(*Section, TEXT("PrecipitationType"), PrecipitationTypeToString(PrecipitationType));
CARLA_WRITE_TO_INI(Float, PrecipitationAmount)
CARLA_WRITE_TO_INI(Float, PrecipitationAccumulation)
#undef CARLA_WRITE_TO_INI
}

View File

@ -4,10 +4,12 @@
#include "WeatherDescription.generated.h"
class IniFile;
UENUM(BlueprintType)
enum class EPrecipitationType : uint8
{
Rain UMETA(DisplayName = "Rain"),
Rain UMETA(DisplayName = "Rain")
};
USTRUCT(BlueprintType)
@ -15,6 +17,10 @@ struct FWeatherDescription
{
GENERATED_USTRUCT_BODY()
void ReadFromConfigFile(const IniFile &ConfigFile, const FString &Section);
void WriteToConfigFile(IniFile &ConfigFile) const;
// ===========================================================================
/// @name Weather
// ===========================================================================