HAxis sos
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FMODAmbientSoundActorFactory.generated.h"
|
||||
|
||||
/** FMOD Ambient Sound Actor Factory.
|
||||
*/
|
||||
UCLASS(MinimalAPI, config=Editor, collapsecategories, hidecategories=Object)
|
||||
class UFMODAmbientSoundActorFactory : public UActorFactory
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
// Begin UActorFactory Interface
|
||||
virtual void PostSpawnActor( UObject* Asset, AActor* NewActor ) override;
|
||||
virtual void PostCreateBlueprint( UObject* Asset, AActor* CDO ) override;
|
||||
virtual bool CanCreateActorFrom( const FAssetData& AssetData, FText& OutErrorMsg ) override;
|
||||
virtual UObject* GetAssetFromActorInstance(AActor* ActorInstance) override;
|
||||
// End UActorFactory Interface
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
namespace UnrealBuildTool.Rules
|
||||
{
|
||||
public class FMODStudioEditor : ModuleRules
|
||||
{
|
||||
public FMODStudioEditor(TargetInfo Target)
|
||||
{
|
||||
bFasterWithoutUnity = true;
|
||||
|
||||
PublicIncludePaths.AddRange(
|
||||
new string[] {
|
||||
}
|
||||
);
|
||||
|
||||
PrivateIncludePaths.AddRange(
|
||||
new string[] {
|
||||
"FMODStudioEditor/Private",
|
||||
"FMODStudio/Private",
|
||||
}
|
||||
);
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"FMODStudio"
|
||||
}
|
||||
);
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"UnrealEd",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
"InputCore",
|
||||
"Settings",
|
||||
"EditorStyle",
|
||||
"LevelEditor",
|
||||
"AssetTools",
|
||||
"AssetRegistry",
|
||||
"PropertyEditor",
|
||||
"WorkspaceMenuStructure",
|
||||
"Sockets"
|
||||
}
|
||||
);
|
||||
|
||||
DynamicallyLoadedModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#include "FMODStudioEditorPrivatePCH.h"
|
||||
#include "AssetTypeActions_Base.h"
|
||||
#include "AssetTypeActions_FMODEvent.h"
|
||||
#include "FMODEventEditor.h"
|
||||
#include "FMODEvent.h"
|
||||
#include "FMODUtils.h"
|
||||
#include "FMODStudioModule.h"
|
||||
#include "FMODStudioEditorModule.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "AssetTypeActions"
|
||||
|
||||
FAssetTypeActions_FMODEvent::FAssetTypeActions_FMODEvent()
|
||||
: CurrentPreviewEventInstance(nullptr)
|
||||
{
|
||||
BeginPIEDelegateHandle = FEditorDelegates::BeginPIE.AddRaw(this, &FAssetTypeActions_FMODEvent::HandleBeginPIE);
|
||||
IFMODStudioModule::Get().BanksReloadedEvent().AddRaw(this, &FAssetTypeActions_FMODEvent::HandleBanksReloaded);
|
||||
}
|
||||
|
||||
FAssetTypeActions_FMODEvent::~FAssetTypeActions_FMODEvent()
|
||||
{
|
||||
FEditorDelegates::BeginPIE.Remove(BeginPIEDelegateHandle);
|
||||
IFMODStudioModule::Get().BanksReloadedEvent().RemoveAll(this);
|
||||
IFMODStudioModule::Get().StopAuditioningInstance();
|
||||
}
|
||||
|
||||
UClass* FAssetTypeActions_FMODEvent::GetSupportedClass() const
|
||||
{
|
||||
return UFMODEvent::StaticClass();
|
||||
}
|
||||
|
||||
void FAssetTypeActions_FMODEvent::GetActions(const TArray<UObject*>& InObjects, FMenuBuilder& MenuBuilder)
|
||||
{
|
||||
auto Events = GetTypedWeakObjectPtrs<UFMODEvent>(InObjects);
|
||||
|
||||
|
||||
MenuBuilder.AddMenuEntry(
|
||||
LOCTEXT("FMODEvent_Play", "Play"),
|
||||
LOCTEXT("FMODEvent_PlayTooltip", "Plays the selected FMOD event."),
|
||||
FSlateIcon(FEditorStyle::GetStyleSetName(), "MediaAsset.AssetActions.Play"),
|
||||
FUIAction(
|
||||
FExecuteAction::CreateSP(this, &FAssetTypeActions_FMODEvent::ExecutePlay, Events),
|
||||
FCanExecuteAction::CreateSP(this, &FAssetTypeActions_FMODEvent::CanExecutePlayCommand, Events)
|
||||
)
|
||||
);
|
||||
|
||||
MenuBuilder.AddMenuEntry(
|
||||
LOCTEXT("FMODEvent_Stop", "Stop"),
|
||||
LOCTEXT("FMODEvent_StopTooltip", "Stops the currently playing FMOD event."),
|
||||
FSlateIcon(FEditorStyle::GetStyleSetName(), "MediaAsset.AssetActions.Stop"),
|
||||
FUIAction(
|
||||
FExecuteAction::CreateSP(this, &FAssetTypeActions_FMODEvent::ExecuteStop, Events),
|
||||
FCanExecuteAction()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void FAssetTypeActions_FMODEvent::OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<IToolkitHost> EditWithinLevelEditor)
|
||||
{
|
||||
EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone;
|
||||
|
||||
for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt)
|
||||
{
|
||||
auto Event = Cast<UFMODEvent>(*ObjIt);
|
||||
if (Event != nullptr)
|
||||
{
|
||||
TSharedRef<FFMODEventEditor> NewFMODEventEditor(new FFMODEventEditor());
|
||||
NewFMODEventEditor->InitFMODEventEditor(Mode, EditWithinLevelEditor, Event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FAssetTypeActions_FMODEvent::CanExecutePlayCommand(TArray<TWeakObjectPtr<UFMODEvent>> Objects) const
|
||||
{
|
||||
return Objects.Num() == 1;
|
||||
}
|
||||
|
||||
void FAssetTypeActions_FMODEvent::AssetsActivated(const TArray<UObject*>& InObjects, EAssetTypeActivationMethod::Type ActivationType)
|
||||
{
|
||||
if (ActivationType == EAssetTypeActivationMethod::Previewed)
|
||||
{
|
||||
for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt)
|
||||
{
|
||||
UFMODEvent* Event = Cast<UFMODEvent>(*ObjIt);
|
||||
if (Event != nullptr)
|
||||
{
|
||||
// Only play the first valid event
|
||||
PlayEvent(Event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FAssetTypeActions_Base::AssetsActivated(InObjects, ActivationType);
|
||||
}
|
||||
}
|
||||
|
||||
void FAssetTypeActions_FMODEvent::ExecuteEdit(TArray<TWeakObjectPtr<UFMODEvent>> Objects)
|
||||
{
|
||||
for (auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt)
|
||||
{
|
||||
auto Object = (*ObjIt).Get();
|
||||
if (Object != nullptr)
|
||||
{
|
||||
FAssetEditorManager::Get().OpenEditorForAsset(Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FAssetTypeActions_FMODEvent::ExecutePlay(TArray<TWeakObjectPtr<UFMODEvent>> Objects)
|
||||
{
|
||||
for (auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt)
|
||||
{
|
||||
UFMODEvent* Event = (*ObjIt).Get();
|
||||
if (Event != nullptr)
|
||||
{
|
||||
// Only play the first valid event
|
||||
PlayEvent(Event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FAssetTypeActions_FMODEvent::ExecuteStop(TArray<TWeakObjectPtr<UFMODEvent>> Objects)
|
||||
{
|
||||
IFMODStudioModule::Get().StopAuditioningInstance();
|
||||
}
|
||||
|
||||
void FAssetTypeActions_FMODEvent::PlayEvent(UFMODEvent* Event)
|
||||
{
|
||||
CurrentPreviewEventInstance = IFMODStudioModule::Get().CreateAuditioningInstance(Event);
|
||||
if (CurrentPreviewEventInstance != nullptr)
|
||||
{
|
||||
CurrentPreviewEventInstance->start();
|
||||
}
|
||||
}
|
||||
|
||||
void FAssetTypeActions_FMODEvent::HandleBeginPIE(bool bSimulating)
|
||||
{
|
||||
// Studio module will handle its own auditioning, just clear the handle
|
||||
CurrentPreviewEventInstance = nullptr;
|
||||
}
|
||||
|
||||
void FAssetTypeActions_FMODEvent::HandleBanksReloaded()
|
||||
{
|
||||
// Studio module will handle its own auditioning, just clear the handle
|
||||
CurrentPreviewEventInstance = nullptr;
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AssetTypeActions_Base.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
namespace Studio
|
||||
{
|
||||
class EventInstance;
|
||||
}
|
||||
}
|
||||
|
||||
class UFMODEvent;
|
||||
|
||||
class FAssetTypeActions_FMODEvent : public FAssetTypeActions_Base
|
||||
{
|
||||
public:
|
||||
FAssetTypeActions_FMODEvent();
|
||||
~FAssetTypeActions_FMODEvent();
|
||||
|
||||
// IAssetTypeActions Implementation
|
||||
virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_FMODEvent", "FMOD Event"); }
|
||||
virtual FColor GetTypeColor() const override { return FColor(0, 175, 255); }
|
||||
virtual UClass* GetSupportedClass() const override;
|
||||
virtual bool HasActions(const TArray<UObject*>& InObjects) const override { return true; }
|
||||
virtual void GetActions(const TArray<UObject*>& InObjects, FMenuBuilder& MenuBuilder) override;
|
||||
virtual void AssetsActivated(const TArray<UObject*>& InObjects, EAssetTypeActivationMethod::Type ActivationType) override;
|
||||
virtual void OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<class IToolkitHost> EditWithinLevelEditor = TSharedPtr<IToolkitHost>()) override;
|
||||
virtual bool CanFilter() override { return false; }
|
||||
virtual uint32 GetCategories() override { return EAssetTypeCategories::Sounds; }
|
||||
|
||||
private:
|
||||
/** Returns true if only one event is selected to play */
|
||||
bool CanExecutePlayCommand(TArray<TWeakObjectPtr<UFMODEvent>> Objects) const;
|
||||
|
||||
/** Handler for when Edit is selected */
|
||||
void ExecuteEdit(TArray<TWeakObjectPtr<UFMODEvent>> Objects);
|
||||
|
||||
/** Handler for when Play is selected */
|
||||
void ExecutePlay(TArray<TWeakObjectPtr<UFMODEvent>> Objects);
|
||||
|
||||
/** Handler for when Stop is selected */
|
||||
void ExecuteStop(TArray<TWeakObjectPtr<UFMODEvent>> Objects);
|
||||
|
||||
/** Plays the event */
|
||||
void PlayEvent(UFMODEvent* Event);
|
||||
|
||||
void HandleBeginPIE(bool bSimulating);
|
||||
void HandleBanksReloaded();
|
||||
|
||||
FMOD::Studio::EventInstance* CurrentPreviewEventInstance;
|
||||
FDelegateHandle BeginPIEDelegateHandle;
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#include "FMODStudioEditorPrivatePCH.h"
|
||||
#include "AssetData.h"
|
||||
#include "FMODAmbientSoundActorFactory.h"
|
||||
#include "FMODAmbientSound.h"
|
||||
#include "FMODEvent.h"
|
||||
|
||||
UFMODAmbientSoundActorFactory::UFMODAmbientSoundActorFactory(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
DisplayName = NSLOCTEXT("FMOD", "FMODAmbientSoundDisplayName", "FMOD Ambient Sound");
|
||||
NewActorClass = AFMODAmbientSound::StaticClass();
|
||||
}
|
||||
|
||||
bool UFMODAmbientSoundActorFactory::CanCreateActorFrom( const FAssetData& AssetData, FText& OutErrorMsg )
|
||||
{
|
||||
//We allow creating AAmbientSounds without an existing sound asset
|
||||
if ( UActorFactory::CanCreateActorFrom( AssetData, OutErrorMsg ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( AssetData.IsValid() && !AssetData.GetClass()->IsChildOf( UFMODEvent::StaticClass() ) )
|
||||
{
|
||||
OutErrorMsg = NSLOCTEXT("FMOD", "CanCreateActorFrom_NoFMODEventAsset", "A valid FMOD Event asset must be specified.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UFMODAmbientSoundActorFactory::PostSpawnActor( UObject* Asset, AActor* NewActor)
|
||||
{
|
||||
UFMODEvent* Event = Cast<UFMODEvent>( Asset );
|
||||
|
||||
if ( Event != NULL )
|
||||
{
|
||||
AFMODAmbientSound* NewSound = CastChecked<AFMODAmbientSound>( NewActor );
|
||||
FActorLabelUtilities::SetActorLabelUnique(NewSound, Event->GetName());
|
||||
NewSound->AudioComponent->Event = Event;
|
||||
}
|
||||
}
|
||||
|
||||
UObject* UFMODAmbientSoundActorFactory::GetAssetFromActorInstance(AActor* Instance)
|
||||
{
|
||||
check(Instance->IsA(NewActorClass));
|
||||
AFMODAmbientSound* SoundActor = CastChecked<AFMODAmbientSound>(Instance);
|
||||
|
||||
check(SoundActor->AudioComponent);
|
||||
return SoundActor->AudioComponent->Event.Get();
|
||||
}
|
||||
|
||||
void UFMODAmbientSoundActorFactory::PostCreateBlueprint( UObject* Asset, AActor* CDO )
|
||||
{
|
||||
if (Asset != NULL && CDO != NULL)
|
||||
{
|
||||
UFMODEvent* Event = Cast<UFMODEvent>(Asset);
|
||||
|
||||
if (Event != NULL)
|
||||
{
|
||||
AFMODAmbientSound* NewSound = CastChecked<AFMODAmbientSound>(CDO);
|
||||
NewSound->AudioComponent->Event = Event;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#include "FMODStudioEditorPrivatePCH.h"
|
||||
#include "FMODAmbientSoundDetails.h"
|
||||
#include "Toolkits/AssetEditorManager.h"
|
||||
#include "FMODAmbientSound.h"
|
||||
#include "FMODStudioModule.h"
|
||||
#include "FMODEvent.h"
|
||||
#include "fmod_studio.hpp"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FMODStudio"
|
||||
|
||||
TSharedRef<IDetailCustomization> FFMODAmbientSoundDetails::MakeInstance()
|
||||
{
|
||||
return MakeShareable( new FFMODAmbientSoundDetails );
|
||||
}
|
||||
|
||||
void FFMODAmbientSoundDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
|
||||
{
|
||||
const TArray< TWeakObjectPtr<UObject> >& SelectedObjects = DetailBuilder.GetDetailsView().GetSelectedObjects();
|
||||
|
||||
for( int32 ObjectIndex = 0; !AmbientSound.IsValid() && ObjectIndex < SelectedObjects.Num(); ++ObjectIndex )
|
||||
{
|
||||
const TWeakObjectPtr<UObject>& CurrentObject = SelectedObjects[ObjectIndex];
|
||||
if ( CurrentObject.IsValid() )
|
||||
{
|
||||
AmbientSound = Cast<AFMODAmbientSound>(CurrentObject.Get());
|
||||
}
|
||||
}
|
||||
|
||||
DetailBuilder.EditCategory(TEXT("Sound"))
|
||||
.AddCustomRow(FText::GetEmpty())
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
+ SVerticalBox::Slot()
|
||||
.Padding( 0, 2.0f, 0, 0 )
|
||||
.FillHeight(1.0f)
|
||||
.VAlign( VAlign_Center )
|
||||
[
|
||||
SNew(SHorizontalBox)
|
||||
+SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.Padding( 2.0f, 0.0f )
|
||||
.VAlign(VAlign_Center)
|
||||
.HAlign(HAlign_Left)
|
||||
[
|
||||
SNew(SButton)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked( this, &FFMODAmbientSoundDetails::OnEditSoundClicked )
|
||||
.Text( LOCTEXT("EditAsset", "Edit") )
|
||||
.ToolTipText( LOCTEXT("EditAssetToolTip", "Edit this sound cue") )
|
||||
]
|
||||
+SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.Padding( 2.0f, 0.0f )
|
||||
.VAlign(VAlign_Center)
|
||||
.HAlign(HAlign_Left)
|
||||
[
|
||||
SNew(SButton)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked( this, &FFMODAmbientSoundDetails::OnPlaySoundClicked )
|
||||
.Text( LOCTEXT("PlaySoundCue", "Play") )
|
||||
]
|
||||
+SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.Padding( 2.0f, 0.0f )
|
||||
.VAlign(VAlign_Center)
|
||||
.HAlign(HAlign_Left)
|
||||
[
|
||||
SNew(SButton)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked( this, &FFMODAmbientSoundDetails::OnStopSoundClicked )
|
||||
.Text( LOCTEXT("StopSoundCue", "Stop") )
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
FReply FFMODAmbientSoundDetails::OnEditSoundClicked()
|
||||
{
|
||||
if( AmbientSound.IsValid() )
|
||||
{
|
||||
UFMODEvent* Event = AmbientSound.Get()->AudioComponent->Event.Get();
|
||||
if (Event)
|
||||
{
|
||||
FAssetEditorManager::Get().OpenEditorForAsset(Event);
|
||||
}
|
||||
}
|
||||
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
FReply FFMODAmbientSoundDetails::OnPlaySoundClicked()
|
||||
{
|
||||
if( AmbientSound.IsValid() )
|
||||
{
|
||||
UFMODEvent* Event = AmbientSound.Get()->AudioComponent->Event.Get();
|
||||
if (Event)
|
||||
{
|
||||
FMOD::Studio::EventInstance* Instance = IFMODStudioModule::Get().CreateAuditioningInstance(Event);
|
||||
if (Instance)
|
||||
{
|
||||
Instance->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
FReply FFMODAmbientSoundDetails::OnStopSoundClicked()
|
||||
{
|
||||
IFMODStudioModule::Get().StopAuditioningInstance();
|
||||
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PropertyEditing.h"
|
||||
#include "PropertyCustomizationHelpers.h"
|
||||
|
||||
class FFMODAmbientSoundDetails : public IDetailCustomization
|
||||
{
|
||||
public:
|
||||
/** Makes a new instance of this detail layout class for a specific detail view requesting it */
|
||||
static TSharedRef<IDetailCustomization> MakeInstance();
|
||||
|
||||
private:
|
||||
/** IDetailCustomization interface */
|
||||
virtual void CustomizeDetails( IDetailLayoutBuilder& DetailBuilder ) override;
|
||||
|
||||
FReply OnEditSoundClicked();
|
||||
FReply OnPlaySoundClicked();
|
||||
FReply OnStopSoundClicked();
|
||||
|
||||
TWeakObjectPtr<class AFMODAmbientSound> AmbientSound;
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ComponentAssetBroker.h"
|
||||
#include "FMODEvent.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// FFMODAssetBroker
|
||||
|
||||
class FFMODAssetBroker : public IComponentAssetBroker
|
||||
{
|
||||
public:
|
||||
UClass* GetSupportedAssetClass() override
|
||||
{
|
||||
return UFMODEvent::StaticClass();
|
||||
}
|
||||
|
||||
virtual bool AssignAssetToComponent(UActorComponent* InComponent, UObject* InAsset) override
|
||||
{
|
||||
if (UFMODAudioComponent* AudioComp = Cast<UFMODAudioComponent>(InComponent))
|
||||
{
|
||||
UFMODEvent* Event = Cast<UFMODEvent>(InAsset);
|
||||
|
||||
if ((Event != NULL) || (InAsset == NULL))
|
||||
{
|
||||
AudioComp->Event = Event;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual UObject* GetAssetFromComponent(UActorComponent* InComponent) override
|
||||
{
|
||||
if (UFMODAudioComponent* AudioComp = Cast<UFMODAudioComponent>(InComponent))
|
||||
{
|
||||
return AudioComp->Event.Get();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#include "FMODStudioEditorPrivatePCH.h"
|
||||
#include "FMODAudioComponentVisualizer.h"
|
||||
#include "FMODAudioComponent.h"
|
||||
#include "FMODUtils.h"
|
||||
#include "FMODEvent.h"
|
||||
#include "fmod_studio.hpp"
|
||||
|
||||
void FFMODAudioComponentVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI)
|
||||
{
|
||||
if (View->Family->EngineShowFlags.AudioRadius)
|
||||
{
|
||||
const UFMODAudioComponent* AudioComp = Cast<const UFMODAudioComponent>(Component);
|
||||
if (AudioComp != nullptr && AudioComp->Event.IsValid())
|
||||
{
|
||||
FMOD::Studio::EventDescription* EventDesc = IFMODStudioModule::Get().GetEventDescription(AudioComp->Event.Get(), EFMODSystemContext::Auditioning);
|
||||
if (EventDesc != nullptr)
|
||||
{
|
||||
bool bIs3D = false;
|
||||
EventDesc->is3D(&bIs3D);
|
||||
if (bIs3D)
|
||||
{
|
||||
const FColor AudioOuterRadiusColor(255, 153, 0);
|
||||
const FColor AudioInnerRadiusColor(216, 130, 0);
|
||||
|
||||
const FTransform& Transform = AudioComp->ComponentToWorld;
|
||||
|
||||
float MinDistance = 0.0f;
|
||||
float MaxDistance = 0.0f;
|
||||
EventDesc->getMinimumDistance(&MinDistance);
|
||||
EventDesc->getMaximumDistance(&MaxDistance);
|
||||
MinDistance = FMODUtils::DistanceToUEScale(MinDistance);
|
||||
MaxDistance = FMODUtils::DistanceToUEScale(MaxDistance);
|
||||
|
||||
DrawWireSphereAutoSides(PDI, Transform.GetTranslation(), AudioOuterRadiusColor, MinDistance, SDPG_World);
|
||||
if (MaxDistance != MinDistance)
|
||||
{
|
||||
DrawWireSphereAutoSides(PDI, Transform.GetTranslation(), AudioInnerRadiusColor, MaxDistance, SDPG_World);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ComponentVisualizer.h"
|
||||
|
||||
class FFMODAudioComponentVisualizer : public FComponentVisualizer
|
||||
{
|
||||
public:
|
||||
// Begin FComponentVisualizer interface
|
||||
virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI) override;
|
||||
// End FComponentVisualizer interface
|
||||
};
|
||||
@@ -0,0 +1,187 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#include "FMODStudioEditorPrivatePCH.h"
|
||||
#include "FMODEventEditor.h"
|
||||
#include "FMODEvent.h"
|
||||
#include "FMODStudioModule.h"
|
||||
#include "FMODUtils.h"
|
||||
#include "SFMODEventEditorPanel.h"
|
||||
#include "SDockTab.h"
|
||||
//#include "WorkspaceMenuStructureModule.h"
|
||||
#include "fmod_studio.hpp"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FMODEventEditor"
|
||||
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogFMODEventEditor, Log, All);
|
||||
|
||||
const FName FFMODEventEditor::EventEditorTabId(TEXT("FFMODEventEditor_EventView"));
|
||||
const FName FFMODEventEditor::FMODEventEditorAppIdentifier(TEXT("FMODEventEditorApp"));
|
||||
|
||||
void FFMODEventEditor::RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager)
|
||||
{
|
||||
WorkspaceMenuCategory = TabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_FMODEventEditor", "FMOD Event Editor"));
|
||||
auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef();
|
||||
|
||||
FAssetEditorToolkit::RegisterTabSpawners(TabManager);
|
||||
|
||||
TabManager->RegisterTabSpawner(
|
||||
EventEditorTabId,
|
||||
FOnSpawnTab::CreateSP(this, &FFMODEventEditor::SpawnTab_EventEditor))
|
||||
.SetDisplayName(LOCTEXT("EventTab", "FMOD Event"))
|
||||
.SetGroup(WorkspaceMenuCategoryRef);
|
||||
}
|
||||
|
||||
void FFMODEventEditor::UnregisterTabSpawners(const TSharedRef<class FTabManager>& TabManager)
|
||||
{
|
||||
FAssetEditorToolkit::UnregisterTabSpawners(TabManager);
|
||||
|
||||
TabManager->UnregisterTabSpawner(EventEditorTabId);
|
||||
}
|
||||
|
||||
FFMODEventEditor::FFMODEventEditor()
|
||||
: CurrentPreviewEventInstance(nullptr)
|
||||
{
|
||||
IFMODStudioModule::Get().BanksReloadedEvent().AddRaw(this, &FFMODEventEditor::HandleBanksReloaded);
|
||||
BeginPIEDelegateHandle = FEditorDelegates::BeginPIE.AddRaw(this, &FFMODEventEditor::HandleBeginPIE);
|
||||
}
|
||||
|
||||
FFMODEventEditor::~FFMODEventEditor()
|
||||
{
|
||||
IFMODStudioModule::Get().BanksReloadedEvent().RemoveAll(this);
|
||||
FEditorDelegates::BeginPIE.Remove(BeginPIEDelegateHandle);
|
||||
|
||||
CurrentPreviewEventInstance = nullptr;
|
||||
}
|
||||
|
||||
UFMODEvent* FFMODEventEditor::GetEditedEvent() const
|
||||
{
|
||||
return EditedEvent;
|
||||
}
|
||||
|
||||
FMOD::Studio::EventDescription* FFMODEventEditor::GetEventDescription() const
|
||||
{
|
||||
return IFMODStudioModule::Get().GetEventDescription(EditedEvent, EFMODSystemContext::Auditioning);
|
||||
}
|
||||
|
||||
void FFMODEventEditor::PlayEvent()
|
||||
{
|
||||
CurrentPreviewEventInstance = IFMODStudioModule::Get().CreateAuditioningInstance(EditedEvent);
|
||||
if (CurrentPreviewEventInstance != nullptr)
|
||||
{
|
||||
for (int32 ParamIdx = 0; ParamIdx < ParameterValues.Num(); ParamIdx++)
|
||||
{
|
||||
CurrentPreviewEventInstance->setParameterValueByIndex(ParamIdx, ParameterValues[ParamIdx]);
|
||||
}
|
||||
|
||||
CurrentPreviewEventInstance->start();
|
||||
}
|
||||
}
|
||||
|
||||
void FFMODEventEditor::PauseEvent()
|
||||
{
|
||||
if (CurrentPreviewEventInstance != nullptr)
|
||||
{
|
||||
bool bIsPaused = false;
|
||||
CurrentPreviewEventInstance->getPaused(&bIsPaused);
|
||||
CurrentPreviewEventInstance->setPaused(!bIsPaused);
|
||||
}
|
||||
}
|
||||
|
||||
void FFMODEventEditor::StopEvent()
|
||||
{
|
||||
IFMODStudioModule::Get().StopAuditioningInstance();
|
||||
}
|
||||
|
||||
void FFMODEventEditor::SetParameterValue(int32 ParameterIdx, float Value)
|
||||
{
|
||||
ParameterValues[ParameterIdx] = Value;
|
||||
|
||||
if (CurrentPreviewEventInstance != nullptr)
|
||||
{
|
||||
CurrentPreviewEventInstance->setParameterValueByIndex(ParameterIdx, Value);
|
||||
}
|
||||
}
|
||||
|
||||
TArray<float>& FFMODEventEditor::GetParameterValues()
|
||||
{
|
||||
return ParameterValues;
|
||||
}
|
||||
|
||||
void FFMODEventEditor::InitFMODEventEditor(const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UFMODEvent* Event)
|
||||
{
|
||||
EditedEvent = Event;
|
||||
|
||||
TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout("Standalone_FMODEventEditor_Layout")
|
||||
->AddArea
|
||||
(
|
||||
FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical)
|
||||
->Split
|
||||
(
|
||||
FTabManager::NewStack()
|
||||
->AddTab(EventEditorTabId, ETabState::OpenedTab)->SetHideTabWell(true)
|
||||
)
|
||||
);
|
||||
|
||||
const bool bCreateDefaultStandaloneMenu = true;
|
||||
const bool bCreateDefaultToolbar = false;
|
||||
FAssetEditorToolkit::InitAssetEditor(Mode, InitToolkitHost, FFMODEventEditor::FMODEventEditorAppIdentifier, StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, Event);
|
||||
}
|
||||
|
||||
FName FFMODEventEditor::GetToolkitFName() const
|
||||
{
|
||||
return FName("FMODEventEditor");
|
||||
}
|
||||
|
||||
FText FFMODEventEditor::GetBaseToolkitName() const
|
||||
{
|
||||
return LOCTEXT("ToolkitName", "FMOD Event Editor");
|
||||
}
|
||||
|
||||
FString FFMODEventEditor::GetWorldCentricTabPrefix() const
|
||||
{
|
||||
return LOCTEXT("WorldCentricTabPrefix", "FMOD Event ").ToString();
|
||||
}
|
||||
|
||||
FLinearColor FFMODEventEditor::GetWorldCentricTabColorScale() const
|
||||
{
|
||||
return FLinearColor(0.0f, 0.0f, 0.5f, 0.5f);
|
||||
}
|
||||
|
||||
void FFMODEventEditor::CreateInternalWidgets()
|
||||
{
|
||||
FMODEventEditorPanel = SNew(SFMODEventEditorPanel)
|
||||
.FMODEventEditor(SharedThis(this));
|
||||
}
|
||||
|
||||
TSharedRef<SDockTab> FFMODEventEditor::SpawnTab_EventEditor(const FSpawnTabArgs& Args)
|
||||
{
|
||||
check(Args.GetTabId().TabType == EventEditorTabId);
|
||||
|
||||
CreateInternalWidgets();
|
||||
|
||||
return SAssignNew(OwnerTab, SDockTab)
|
||||
.Label(LOCTEXT("EventEditorTitle", "FMOD Event"))
|
||||
.TabColorScale(GetTabColorScale())
|
||||
[
|
||||
FMODEventEditorPanel.ToSharedRef()
|
||||
];
|
||||
}
|
||||
|
||||
void FFMODEventEditor::HandleBanksReloaded()
|
||||
{
|
||||
CurrentPreviewEventInstance = nullptr;
|
||||
|
||||
CreateInternalWidgets();
|
||||
|
||||
if (OwnerTab.IsValid())
|
||||
{
|
||||
OwnerTab->SetContent(FMODEventEditorPanel.ToSharedRef());
|
||||
}
|
||||
}
|
||||
|
||||
void FFMODEventEditor::HandleBeginPIE(bool bSimulating)
|
||||
{
|
||||
CurrentPreviewEventInstance = nullptr;
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Toolkits/AssetEditorToolkit.h"
|
||||
#include "fmod_studio_common.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
namespace Studio
|
||||
{
|
||||
class EventDescription;
|
||||
class EventInstance;
|
||||
}
|
||||
}
|
||||
|
||||
class FFMODEventEditor : public FAssetEditorToolkit
|
||||
{
|
||||
public:
|
||||
virtual void RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override;
|
||||
virtual void UnregisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override;
|
||||
|
||||
/**
|
||||
* Edits the specified event
|
||||
*
|
||||
* @param Mode Asset editing mode for this editor (standalone or world-centric)
|
||||
* @param InitToolkitHost When Mode is WorldCentric, this is the level editor instance to spawn this editor within
|
||||
* @param Event The event to edit
|
||||
*/
|
||||
void InitFMODEventEditor(const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, class UFMODEvent* Event);
|
||||
|
||||
/** Constructor */
|
||||
FFMODEventEditor();
|
||||
|
||||
/** Destructor */
|
||||
virtual ~FFMODEventEditor();
|
||||
|
||||
UFMODEvent* GetEditedEvent() const;
|
||||
FMOD::Studio::EventDescription* GetEventDescription() const;
|
||||
void PlayEvent();
|
||||
void PauseEvent();
|
||||
void StopEvent();
|
||||
void SetParameterValue(int32 ParameterIdx, float Value);
|
||||
TArray<float>& GetParameterValues();
|
||||
|
||||
/** IToolkit interface */
|
||||
virtual FName GetToolkitFName() const override;
|
||||
virtual FText GetBaseToolkitName() const override;
|
||||
virtual FString GetWorldCentricTabPrefix() const override;
|
||||
virtual FLinearColor GetWorldCentricTabColorScale() const override;
|
||||
|
||||
TArray<float> ParameterValues;
|
||||
|
||||
private:
|
||||
|
||||
FMOD::Studio::EventInstance* CurrentPreviewEventInstance;
|
||||
|
||||
void HandlePreBanksReloaded();
|
||||
void HandleBanksReloaded();
|
||||
void HandleBeginPIE(bool bSimulating);
|
||||
|
||||
/** Creates all internal widgets for the tabs to point at */
|
||||
void CreateInternalWidgets();
|
||||
|
||||
/** Spawns the tab with the FMOD event inside */
|
||||
TSharedRef<SDockTab> SpawnTab_EventEditor(const FSpawnTabArgs& Args);
|
||||
|
||||
TSharedPtr<class SFMODEventEditorPanel> FMODEventEditorPanel;
|
||||
TSharedPtr<SDockTab> OwnerTab;
|
||||
|
||||
/** The tab id for the event editor tab */
|
||||
static const FName EventEditorTabId;
|
||||
|
||||
/** FMOD event editor app identifier string */
|
||||
static const FName FMODEventEditorAppIdentifier;
|
||||
|
||||
class UFMODEvent* EditedEvent;
|
||||
|
||||
FDelegateHandle BeginPIEDelegateHandle;
|
||||
};
|
||||
@@ -0,0 +1,872 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#include "FMODStudioEditorPrivatePCH.h"
|
||||
|
||||
#include "FMODStudioEditorModule.h"
|
||||
#include "FMODStudioModule.h"
|
||||
#include "FMODStudioStyle.h"
|
||||
#include "FMODAudioComponent.h"
|
||||
#include "FMODAssetBroker.h"
|
||||
#include "FMODSettings.h"
|
||||
#include "FMODUtils.h"
|
||||
|
||||
#include "FMODEventEditor.h"
|
||||
#include "FMODAudioComponentVisualizer.h"
|
||||
#include "FMODAmbientSoundDetails.h"
|
||||
|
||||
#include "SlateBasics.h"
|
||||
#include "AssetTypeActions_FMODEvent.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "SNotificationList.h"
|
||||
#include "ISettingsModule.h"
|
||||
#include "ISettingsSection.h"
|
||||
#include "Editor.h"
|
||||
#include "SceneViewport.h"
|
||||
#include "LevelEditor.h"
|
||||
#include "SocketSubsystem.h"
|
||||
#include "Sockets.h"
|
||||
#include "IPAddress.h"
|
||||
|
||||
#include "fmod_studio.hpp"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FMODStudio"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogFMOD);
|
||||
|
||||
class FFMODStudioLink
|
||||
{
|
||||
public:
|
||||
FFMODStudioLink()
|
||||
: SocketSubsystem(nullptr),
|
||||
Socket(nullptr)
|
||||
{
|
||||
SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
|
||||
}
|
||||
|
||||
~FFMODStudioLink()
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
bool Connect()
|
||||
{
|
||||
if (!SocketSubsystem) return false;
|
||||
|
||||
Disconnect();
|
||||
Socket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT("FMOD Studio Connection"), false);
|
||||
|
||||
TSharedRef<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();
|
||||
bool Valid = false;
|
||||
Addr->SetIp(TEXT("127.0.0.1"), Valid);
|
||||
if (!Valid) return false;
|
||||
|
||||
Addr->SetPort(3663);
|
||||
return Socket->Connect(*Addr);
|
||||
}
|
||||
|
||||
void Disconnect()
|
||||
{
|
||||
if (SocketSubsystem && Socket)
|
||||
{
|
||||
SocketSubsystem->DestroySocket(Socket);
|
||||
Socket = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Execute(const TCHAR* Message, FString& OutMessage)
|
||||
{
|
||||
OutMessage = TEXT("");
|
||||
if (!Socket)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UE_LOG(LogFMOD, Log, TEXT("Sent studio message: %s"), Message);
|
||||
|
||||
FTCHARToUTF8 MessageChars(Message);
|
||||
int32 BytesSent = 0;
|
||||
if (!Socket->Send((const uint8*)MessageChars.Get(), MessageChars.Length(), BytesSent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
FString BackMessage;
|
||||
if (!ReadMessage(BackMessage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
UE_LOG(LogFMOD, Log, TEXT("Received studio message: %s"), *BackMessage);
|
||||
if (BackMessage.StartsWith(TEXT("out(): ")))
|
||||
{
|
||||
OutMessage = BackMessage.Mid(7).TrimTrailing();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep going
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
bool ReadMessage(FString& OutMessage)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
for (int32 i=0; i<ReceivedMessage.Num(); ++i)
|
||||
{
|
||||
if (ReceivedMessage[i] == '\0')
|
||||
{
|
||||
OutMessage = FString(UTF8_TO_TCHAR(ReceivedMessage.GetData()));
|
||||
ReceivedMessage.RemoveAt(0, i + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int32 ExtraSpace = 64;
|
||||
int32 CurrentSize = ReceivedMessage.Num();
|
||||
ReceivedMessage.SetNum(CurrentSize + ExtraSpace);
|
||||
int32 ActualRead = 0;
|
||||
if (!Socket->Wait(ESocketWaitConditions::WaitForRead, FTimespan::FromSeconds(10)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!Socket->Recv((uint8*)ReceivedMessage.GetData() + CurrentSize, ExtraSpace, ActualRead))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ReceivedMessage.SetNum(CurrentSize + ActualRead);
|
||||
}
|
||||
}
|
||||
|
||||
ISocketSubsystem* SocketSubsystem;
|
||||
FSocket* Socket;
|
||||
TArray<char> ReceivedMessage;
|
||||
};
|
||||
|
||||
class FFMODStudioEditorModule : public IFMODStudioEditorModule
|
||||
{
|
||||
public:
|
||||
/** IModuleInterface implementation */
|
||||
FFMODStudioEditorModule() :
|
||||
bSimulating(false),
|
||||
bIsInPIE(false),
|
||||
bRegisteredComponentVisualizers(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void StartupModule() override;
|
||||
virtual void PostLoadCallback() override;
|
||||
virtual void ShutdownModule() override;
|
||||
|
||||
bool HandleSettingsSaved();
|
||||
|
||||
/** Called after all banks were reloaded by the studio module */
|
||||
void HandleBanksReloaded();
|
||||
|
||||
/** Show notification */
|
||||
void ShowNotification(const FText& Text, SNotificationItem::ECompletionState State);
|
||||
|
||||
void BeginPIE(bool simulating);
|
||||
void EndPIE(bool simulating);
|
||||
void PausePIE(bool simulating);
|
||||
void ResumePIE(bool simulating);
|
||||
|
||||
void ViewportDraw(UCanvas* Canvas, APlayerController*);
|
||||
|
||||
bool Tick( float DeltaTime );
|
||||
|
||||
/** Add extensions to menu */
|
||||
void AddHelpMenuExtension(FMenuBuilder& MenuBuilder);
|
||||
void AddFileMenuExtension(FMenuBuilder& MenuBuilder);
|
||||
|
||||
/** Show FMOD version */
|
||||
void ShowVersion();
|
||||
/** Open CHM */
|
||||
void OpenCHM();
|
||||
/** Open web page to online docs */
|
||||
void OpenOnlineDocs();
|
||||
/** Open Video tutorials page */
|
||||
void OpenVideoTutorials();
|
||||
/** Set Studio build path */
|
||||
void ValidateFMOD();
|
||||
|
||||
/** Reload banks */
|
||||
void ReloadBanks();
|
||||
|
||||
TArray<FName> RegisteredComponentClassNames;
|
||||
void RegisterComponentVisualizer(FName ComponentClassName, TSharedPtr<FComponentVisualizer> Visualizer);
|
||||
|
||||
/** The delegate to be invoked when this profiler manager ticks. */
|
||||
FTickerDelegate OnTick;
|
||||
|
||||
/** Handle for registered delegates. */
|
||||
FDelegateHandle TickDelegateHandle;
|
||||
FDelegateHandle BeginPIEDelegateHandle;
|
||||
FDelegateHandle EndPIEDelegateHandle;
|
||||
FDelegateHandle PausePIEDelegateHandle;
|
||||
FDelegateHandle ResumePIEDelegateHandle;
|
||||
FDelegateHandle HandleBanksReloadedDelegateHandle;
|
||||
|
||||
/** Hook for drawing viewport */
|
||||
FDebugDrawDelegate ViewportDrawingDelegate;
|
||||
FDelegateHandle ViewportDrawingDelegateHandle;
|
||||
|
||||
TSharedPtr<IComponentAssetBroker> AssetBroker;
|
||||
|
||||
/** The extender to pass to the level editor to extend it's window menu */
|
||||
TSharedPtr<FExtender> MainMenuExtender;
|
||||
|
||||
/** Asset type actions for events (edit, play, stop) */
|
||||
TSharedPtr<FAssetTypeActions_FMODEvent> FMODEventAssetTypeActions;
|
||||
|
||||
bool bSimulating;
|
||||
bool bIsInPIE;
|
||||
bool bRegisteredComponentVisualizers;
|
||||
};
|
||||
|
||||
IMPLEMENT_MODULE( FFMODStudioEditorModule, FMODStudioEditor )
|
||||
|
||||
void FFMODStudioEditorModule::StartupModule()
|
||||
{
|
||||
UE_LOG(LogFMOD, Log, TEXT("FFMODStudioEditorModule startup"));
|
||||
|
||||
AssetBroker = MakeShareable(new FFMODAssetBroker);
|
||||
FComponentAssetBrokerage::RegisterBroker(AssetBroker, UFMODAudioComponent::StaticClass(), true, true);
|
||||
|
||||
if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
|
||||
{
|
||||
ISettingsSectionPtr SettingsSection = SettingsModule->RegisterSettings("Project", "Plugins", "FMODStudio",
|
||||
LOCTEXT("FMODStudioSettingsName", "FMOD Studio"),
|
||||
LOCTEXT("FMODStudioDescription", "Configure the FMOD Studio plugin"),
|
||||
GetMutableDefault<UFMODSettings>()
|
||||
);
|
||||
|
||||
if (SettingsSection.IsValid())
|
||||
{
|
||||
SettingsSection->OnModified().BindRaw(this, &FFMODStudioEditorModule::HandleSettingsSaved);
|
||||
}
|
||||
}
|
||||
|
||||
// Register the details customizations
|
||||
{
|
||||
FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
||||
PropertyModule.RegisterCustomClassLayout("FMODAmbientSound", FOnGetDetailCustomizationInstance::CreateStatic(&FFMODAmbientSoundDetails::MakeInstance));
|
||||
PropertyModule.NotifyCustomizationModuleChanged();
|
||||
}
|
||||
|
||||
// Need to load the editor module since it gets created after us, and we can't re-order ourselves otherwise our asset registration stops working!
|
||||
// It only works if we are running the editor, not a commandlet
|
||||
if (!IsRunningCommandlet())
|
||||
{
|
||||
MainMenuExtender = MakeShareable(new FExtender);
|
||||
MainMenuExtender->AddMenuExtension("HelpBrowse", EExtensionHook::After, NULL, FMenuExtensionDelegate::CreateRaw(this, &FFMODStudioEditorModule::AddHelpMenuExtension));
|
||||
MainMenuExtender->AddMenuExtension("FileLoadAndSave", EExtensionHook::After, NULL, FMenuExtensionDelegate::CreateRaw(this, &FFMODStudioEditorModule::AddFileMenuExtension));
|
||||
|
||||
FLevelEditorModule* LevelEditor = FModuleManager::LoadModulePtr<FLevelEditorModule>(TEXT("LevelEditor"));
|
||||
if (LevelEditor)
|
||||
{
|
||||
LevelEditor->GetMenuExtensibilityManager()->AddExtender(MainMenuExtender);
|
||||
}
|
||||
}
|
||||
|
||||
// Register AssetTypeActions
|
||||
IAssetTools& AssetTools = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools").Get();
|
||||
|
||||
FMODEventAssetTypeActions = MakeShareable(new FAssetTypeActions_FMODEvent);
|
||||
AssetTools.RegisterAssetTypeActions(FMODEventAssetTypeActions.ToSharedRef());
|
||||
|
||||
// Register slate style overrides
|
||||
FFMODStudioStyle::Initialize();
|
||||
|
||||
BeginPIEDelegateHandle = FEditorDelegates::BeginPIE.AddRaw(this, &FFMODStudioEditorModule::BeginPIE);
|
||||
EndPIEDelegateHandle = FEditorDelegates::EndPIE.AddRaw(this, &FFMODStudioEditorModule::EndPIE);
|
||||
PausePIEDelegateHandle = FEditorDelegates::PausePIE.AddRaw(this, &FFMODStudioEditorModule::PausePIE);
|
||||
ResumePIEDelegateHandle = FEditorDelegates::ResumePIE.AddRaw(this, &FFMODStudioEditorModule::ResumePIE);
|
||||
|
||||
ViewportDrawingDelegate = FDebugDrawDelegate::CreateRaw(this, &FFMODStudioEditorModule::ViewportDraw);
|
||||
ViewportDrawingDelegateHandle = UDebugDrawService::Register(TEXT("Editor"), ViewportDrawingDelegate);
|
||||
|
||||
OnTick = FTickerDelegate::CreateRaw( this, &FFMODStudioEditorModule::Tick );
|
||||
TickDelegateHandle = FTicker::GetCoreTicker().AddTicker( OnTick );
|
||||
|
||||
// This module is loaded after FMODStudioModule
|
||||
HandleBanksReloadedDelegateHandle = IFMODStudioModule::Get().BanksReloadedEvent().AddRaw(this, &FFMODStudioEditorModule::HandleBanksReloaded);
|
||||
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::AddHelpMenuExtension(FMenuBuilder& MenuBuilder)
|
||||
{
|
||||
MenuBuilder.BeginSection("FMODHelp", LOCTEXT("FMODHelpLabel", "FMOD Help"));
|
||||
MenuBuilder.AddMenuEntry(
|
||||
LOCTEXT("FMODVersionMenuEntryTitle", "About FMOD Studio"),
|
||||
LOCTEXT("FMODVersionMenuEntryToolTip", "Shows the informationa about FMOD Studio."),
|
||||
FSlateIcon(),
|
||||
FUIAction(FExecuteAction::CreateRaw(this, &FFMODStudioEditorModule::ShowVersion)));
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
MenuBuilder.AddMenuEntry(
|
||||
LOCTEXT("FMODHelpCHMTitle", "FMOD Documentation..."),
|
||||
LOCTEXT("FMODHelpCHMToolTip", "Opens the local FMOD documentation."),
|
||||
FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.BrowseAPIReference"),
|
||||
FUIAction(FExecuteAction::CreateRaw(this, &FFMODStudioEditorModule::OpenCHM)));
|
||||
#endif
|
||||
|
||||
MenuBuilder.AddMenuEntry(
|
||||
LOCTEXT("FMODHelpOnlineTitle", "FMOD Online Documentation..."),
|
||||
LOCTEXT("FMODHelpOnlineToolTip", "Go to the online FMOD documentation."),
|
||||
FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.BrowseDocumentation"),
|
||||
FUIAction(FExecuteAction::CreateRaw(this, &FFMODStudioEditorModule::OpenOnlineDocs)));
|
||||
|
||||
MenuBuilder.AddMenuEntry(
|
||||
LOCTEXT("FMODHelpVideosTitle", "FMOD Tutorial Videos..."),
|
||||
LOCTEXT("FMODHelpVideosToolTip", "Go to the online FMOD tutorial videos."),
|
||||
FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tutorials"),
|
||||
FUIAction(FExecuteAction::CreateRaw(this, &FFMODStudioEditorModule::OpenVideoTutorials)));
|
||||
|
||||
MenuBuilder.AddMenuEntry(
|
||||
LOCTEXT("FMODSetStudioBuildTitle", "Validate FMOD"),
|
||||
LOCTEXT("FMODSetStudioBuildToolTip", "Verifies that FMOD and FMOD Studio are working as expected."),
|
||||
FSlateIcon(),
|
||||
FUIAction(FExecuteAction::CreateRaw(this, &FFMODStudioEditorModule::ValidateFMOD)));
|
||||
|
||||
MenuBuilder.EndSection();
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::AddFileMenuExtension(FMenuBuilder& MenuBuilder)
|
||||
{
|
||||
MenuBuilder.BeginSection("FMODFile", LOCTEXT("FMODFileLabel", "FMOD"));
|
||||
MenuBuilder.AddMenuEntry(
|
||||
LOCTEXT("FMODFileMenuEntryTitle", "Reload Banks"),
|
||||
LOCTEXT("FMODFileMenuEntryToolTip", "Force a manual reload of all FMOD Studio banks."),
|
||||
FSlateIcon(),
|
||||
FUIAction(FExecuteAction::CreateRaw(this, &FFMODStudioEditorModule::ReloadBanks)));
|
||||
MenuBuilder.EndSection();
|
||||
}
|
||||
|
||||
unsigned int GetDLLVersion()
|
||||
{
|
||||
// Just grab it from the audition context which is always valid
|
||||
unsigned int DLLVersion = 0;
|
||||
FMOD::Studio::System* StudioSystem = IFMODStudioModule::Get().GetStudioSystem(EFMODSystemContext::Auditioning);
|
||||
if (StudioSystem)
|
||||
{
|
||||
FMOD::System* LowLevelSystem = nullptr;
|
||||
if (StudioSystem->getLowLevelSystem(&LowLevelSystem) == FMOD_OK)
|
||||
{
|
||||
LowLevelSystem->getVersion(&DLLVersion);
|
||||
}
|
||||
}
|
||||
return DLLVersion;
|
||||
}
|
||||
unsigned int StripPatch(unsigned int FullVersion)
|
||||
{
|
||||
return FullVersion & ~0xFF;
|
||||
}
|
||||
FString VersionToString(unsigned int FullVersion)
|
||||
{
|
||||
return FString::Printf(TEXT("%x.%02x.%02x"), (FullVersion>>16), (FullVersion>>8) & 0xFF, FullVersion & 0xFF);
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::ShowVersion()
|
||||
{
|
||||
unsigned int HeaderVersion = FMOD_VERSION;
|
||||
unsigned int DLLVersion = GetDLLVersion();
|
||||
|
||||
FText VersionMessage = FText::Format(
|
||||
LOCTEXT("FMODStudio_About", "FMOD Studio\n\nBuilt Version: {0}\nDLL Version: {1}\n\nCopyright Firelight Technologies Pty Ltd"),
|
||||
FText::FromString(VersionToString(HeaderVersion)),
|
||||
FText::FromString(VersionToString(DLLVersion)));
|
||||
FMessageDialog::Open(EAppMsgType::Ok, VersionMessage);
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::OpenCHM()
|
||||
{
|
||||
FString APIPath = FPaths::Combine(*FPaths::EngineDir(), TEXT("Plugins/FMODStudio/Docs/FMOD UE4 Integration.chm"));
|
||||
if( IFileManager::Get().FileSize( *APIPath ) != INDEX_NONE )
|
||||
{
|
||||
FString AbsoluteAPIPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*APIPath);
|
||||
FPlatformProcess::LaunchFileInDefaultExternalApplication(*AbsoluteAPIPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("Documentation", "CannotFindFMODIntegration", "Cannot open FMOD Studio Integration CHM reference; help file not found."));
|
||||
}
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::OpenOnlineDocs()
|
||||
{
|
||||
FPlatformProcess::LaunchFileInDefaultExternalApplication(TEXT("http://www.fmod.org/documentation"));
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::OpenVideoTutorials()
|
||||
{
|
||||
FPlatformProcess::LaunchFileInDefaultExternalApplication(TEXT("http://www.youtube.com/user/FMODTV"));
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::ValidateFMOD()
|
||||
{
|
||||
int ProblemsFound = 0;
|
||||
|
||||
FFMODStudioLink StudioLink;
|
||||
bool Connected = StudioLink.Connect();
|
||||
if (!Connected)
|
||||
{
|
||||
if (EAppReturnType::No == FMessageDialog::Open(EAppMsgType::YesNo, LOCTEXT("SetStudioBuildStudioNotRunning", "FMODStudio does not appear to be running. Only some validation will occur. Do you want to continue anyway?")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
unsigned int HeaderVersion = FMOD_VERSION;
|
||||
unsigned int DLLVersion = GetDLLVersion();
|
||||
unsigned int StudioVersion = 0;
|
||||
if (Connected)
|
||||
{
|
||||
FString StudioVersionString;
|
||||
if (StudioLink.Execute(TEXT("studio.version"), StudioVersionString))
|
||||
{
|
||||
int Super = 0;
|
||||
int Major = 0;
|
||||
int Minor = 0;
|
||||
sscanf(TCHAR_TO_UTF8(*StudioVersionString), "Version %x.%x.%x", &Super, &Major, &Minor);
|
||||
StudioVersion = (Super<<16) | (Major<<8) | Minor;
|
||||
}
|
||||
}
|
||||
if (StripPatch(HeaderVersion) != StripPatch(DLLVersion))
|
||||
{
|
||||
FText VersionMessage = FText::Format(
|
||||
LOCTEXT("SetStudioBuildStudio_Status", "The FMOD DLL version is different to the version the integration was built against. This may cause problems running the game.\nBuilt Version: {0}\nDLL Version: {1}\n"),
|
||||
FText::FromString(VersionToString(HeaderVersion)),
|
||||
FText::FromString(VersionToString(DLLVersion)));
|
||||
FMessageDialog::Open(EAppMsgType::Ok, VersionMessage);
|
||||
ProblemsFound++;
|
||||
}
|
||||
if (StudioVersion > DLLVersion)
|
||||
{
|
||||
FText VersionMessage = FText::Format(
|
||||
LOCTEXT("SetStudioBuildStudio_Version", "The Studio tool is newer than the version the integration was built against. The integration may not be able to load the banks that the tool builds.\n\nBuilt Version: {0}\nDLL Version: {1}\nStudio Version: {2}\n\nWe recommend using the Studio tool that matches the integration.\n\nDo you want to continue with the validation?"),
|
||||
FText::FromString(VersionToString(HeaderVersion)),
|
||||
FText::FromString(VersionToString(DLLVersion)),
|
||||
FText::FromString(VersionToString(StudioVersion)));
|
||||
if (EAppReturnType::No == FMessageDialog::Open(EAppMsgType::YesNo, VersionMessage))
|
||||
{
|
||||
return;
|
||||
}
|
||||
ProblemsFound++;
|
||||
}
|
||||
|
||||
const UFMODSettings& Settings = *GetDefault<UFMODSettings>();
|
||||
FString FullBankPath = Settings.BankOutputDirectory.Path;
|
||||
if (FPaths::IsRelative(FullBankPath))
|
||||
{
|
||||
FullBankPath = FPaths::GameContentDir() / FullBankPath;
|
||||
}
|
||||
FString PlatformBankPath = Settings.GetFullBankPath();
|
||||
FullBankPath = FPaths::ConvertRelativePathToFull(FullBankPath);
|
||||
PlatformBankPath = FPaths::ConvertRelativePathToFull(PlatformBankPath);
|
||||
|
||||
if (Connected)
|
||||
{
|
||||
// File path was added in FMOD Studio 1.07.00
|
||||
FString StudioProjectPath;
|
||||
FString StudioProjectDir;
|
||||
if (StudioVersion >= 0x00010700)
|
||||
{
|
||||
StudioLink.Execute(TEXT("studio.project.filePath"), StudioProjectPath);
|
||||
if (StudioProjectPath.IsEmpty() || StudioProjectPath == TEXT("undefined"))
|
||||
{
|
||||
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("SetStudioBuildStudio_NewProject", "FMOD Studio has an empty project. Please go to FMOD Studio, and press Save to create your new project."));
|
||||
// Just try to save anyway
|
||||
FString Result;
|
||||
StudioLink.Execute(TEXT("studio.project.save()"), Result);
|
||||
}
|
||||
StudioLink.Execute(TEXT("studio.project.filePath"), StudioProjectPath);
|
||||
if (StudioProjectPath != TEXT("undefined"))
|
||||
{
|
||||
StudioProjectDir = FPaths::GetPath(StudioProjectPath);
|
||||
}
|
||||
}
|
||||
|
||||
FString StudioPathString;
|
||||
StudioLink.Execute(TEXT("studio.project.workspace.builtBanksOutputDirectory"), StudioPathString);
|
||||
if (StudioPathString == TEXT("undefined"))
|
||||
{
|
||||
StudioPathString = TEXT("");
|
||||
}
|
||||
|
||||
FString CanonicalBankPath = FullBankPath;
|
||||
FPaths::CollapseRelativeDirectories(CanonicalBankPath);
|
||||
FPaths::NormalizeDirectoryName(CanonicalBankPath);
|
||||
FPaths::RemoveDuplicateSlashes(CanonicalBankPath);
|
||||
FPaths::NormalizeDirectoryName(CanonicalBankPath);
|
||||
|
||||
FString CanonicalStudioPath = StudioPathString;
|
||||
if (FPaths::IsRelative(CanonicalStudioPath) && !StudioProjectDir.IsEmpty() && !StudioPathString.IsEmpty())
|
||||
{
|
||||
CanonicalStudioPath = FPaths::Combine(*StudioProjectDir, *CanonicalStudioPath);
|
||||
}
|
||||
FPaths::CollapseRelativeDirectories(CanonicalStudioPath);
|
||||
FPaths::NormalizeDirectoryName(CanonicalStudioPath);
|
||||
FPaths::RemoveDuplicateSlashes(CanonicalStudioPath);
|
||||
FPaths::NormalizeDirectoryName(CanonicalStudioPath);
|
||||
if (!FPaths::IsSamePath(CanonicalBankPath, CanonicalStudioPath))
|
||||
{
|
||||
FString BankPathToSet = FullBankPath;
|
||||
// Extra logic - if we have put the studio project inside the game project, then make it relative
|
||||
if (!StudioProjectDir.IsEmpty())
|
||||
{
|
||||
FString GameBaseDir = FPaths::ConvertRelativePathToFull(FPaths::GameDir());
|
||||
FString BankPathFromGameProject = FullBankPath;
|
||||
FString StudioProjectFromGameProject = StudioProjectDir;
|
||||
if (FPaths::MakePathRelativeTo(BankPathFromGameProject, *GameBaseDir) && !BankPathFromGameProject.Contains(TEXT("..")) &&
|
||||
FPaths::MakePathRelativeTo(StudioProjectFromGameProject, *GameBaseDir) && !StudioProjectFromGameProject.Contains(TEXT("..")))
|
||||
{
|
||||
FPaths::MakePathRelativeTo(BankPathToSet, *(StudioProjectDir + TEXT("/")));
|
||||
}
|
||||
}
|
||||
ProblemsFound++;
|
||||
|
||||
FText AskMessage = FText::Format(
|
||||
LOCTEXT("SetStudioBuildStudio_Ask", "FMOD Studio build path should be set up.\n\nCurrent Studio build path: {0}\nNew build path: {1}\n\nDo you want to fix up the project now?"),
|
||||
FText::FromString(StudioPathString),
|
||||
FText::FromString(BankPathToSet));
|
||||
if (EAppReturnType::Yes == FMessageDialog::Open(EAppMsgType::YesNo, AskMessage))
|
||||
{
|
||||
FString Result;
|
||||
StudioLink.Execute(*FString::Printf(TEXT("studio.project.workspace.builtBanksOutputDirectory = \"%s\";"), *BankPathToSet), Result);
|
||||
StudioLink.Execute(TEXT("studio.project.workspace.builtBanksOutputDirectory"), Result);
|
||||
if (Result != BankPathToSet)
|
||||
{
|
||||
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("SetStudioBuildStudio_Save", "Failed to set bank directory. Please go to FMOD Studio, and set the bank path in FMOD Studio project settings."));
|
||||
}
|
||||
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("SetStudioBuildStudio_Save", "Please go to FMOD Studio, save your project and build banks."));
|
||||
// Just try to do it again anyway
|
||||
StudioLink.Execute(TEXT("studio.project.save()"), Result);
|
||||
StudioLink.Execute(TEXT("studio.project.build()"), Result);
|
||||
// Pretend settings have changed which will force a reload
|
||||
IFMODStudioModule::Get().RefreshSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
bool AnyBankFiles = false;
|
||||
|
||||
if (!FPaths::DirectoryExists(FullBankPath) || !FPaths::DirectoryExists(PlatformBankPath))
|
||||
{
|
||||
FText DirMessage = FText::Format(
|
||||
LOCTEXT("SetStudioBuildStudio_Dir", "The FMOD Content directory does not exist. Please make sure FMOD Studio is exporting banks into the correct location.\n\nBanks should be exported to: {0}\nBanks files should exist in: {1}\n"),
|
||||
FText::FromString(FullBankPath),
|
||||
FText::FromString(PlatformBankPath));
|
||||
FMessageDialog::Open(EAppMsgType::Ok, DirMessage);
|
||||
ProblemsFound++;
|
||||
}
|
||||
else
|
||||
{
|
||||
TArray<FString> BankFiles;
|
||||
Settings.GetAllBankPaths(BankFiles, true);
|
||||
if (BankFiles.Num() != 0)
|
||||
{
|
||||
AnyBankFiles = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
FText EmptyBankDirMessage = FText::Format(
|
||||
LOCTEXT("SetStudioBuildStudio_EmptyBankDir", "The FMOD Content directory does not have any bank files in them. Please make sure FMOD Studio is exporting banks into the correct location.\n\nBanks should be exported to: {0}\nBanks files should exist in: {1}\n"),
|
||||
FText::FromString(FullBankPath),
|
||||
FText::FromString(PlatformBankPath));
|
||||
FMessageDialog::Open(EAppMsgType::Ok, EmptyBankDirMessage);
|
||||
ProblemsFound++;
|
||||
}
|
||||
}
|
||||
if (AnyBankFiles)
|
||||
{
|
||||
FMOD::Studio::System* StudioSystem = IFMODStudioModule::Get().GetStudioSystem(EFMODSystemContext::Auditioning);
|
||||
int BankCount = 0;
|
||||
StudioSystem->getBankCount(&BankCount);
|
||||
TArray<FString> FailedBanks = IFMODStudioModule::Get().GetFailedBankLoads(EFMODSystemContext::Auditioning);
|
||||
if (BankCount == 0 || FailedBanks.Num() != 0)
|
||||
{
|
||||
FString CombinedBanks;
|
||||
for (auto Bank : FailedBanks)
|
||||
{
|
||||
CombinedBanks += Bank;
|
||||
CombinedBanks += TEXT("\n");
|
||||
}
|
||||
FText BankLoadMessage;
|
||||
if (BankCount == 0 && FailedBanks.Num() == 0)
|
||||
{
|
||||
BankLoadMessage = LOCTEXT("SetStudioBuildStudio_BankLoad", "Failed to load banks\n");
|
||||
}
|
||||
else if (BankCount == 0)
|
||||
{
|
||||
BankLoadMessage = FText::Format(
|
||||
LOCTEXT("SetStudioBuildStudio_BankLoad", "Failed to load banks:\n{0}\n"),
|
||||
FText::FromString(CombinedBanks));
|
||||
}
|
||||
else
|
||||
{
|
||||
BankLoadMessage = FText::Format(
|
||||
LOCTEXT("SetStudioBuildStudio_BankLoad", "Some banks failed to load:\n{0}\n"),
|
||||
FText::FromString(CombinedBanks));
|
||||
}
|
||||
FMessageDialog::Open(EAppMsgType::Ok, BankLoadMessage);
|
||||
ProblemsFound++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int TotalEventCount = 0;
|
||||
TArray<FMOD::Studio::Bank*> Banks;
|
||||
Banks.SetNum(BankCount);
|
||||
StudioSystem->getBankList(Banks.GetData(), BankCount, &BankCount);
|
||||
for (FMOD::Studio::Bank* Bank : Banks)
|
||||
{
|
||||
int EventCount = 0;
|
||||
Bank->getEventCount(&EventCount);
|
||||
TotalEventCount += EventCount;
|
||||
}
|
||||
if (TotalEventCount == 0)
|
||||
{
|
||||
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("SetStudioBuildStudio_NoEvents", "Banks have been loaded but they didn't have any events in them. Please make sure you have added some events to banks."));
|
||||
ProblemsFound++;
|
||||
}
|
||||
}
|
||||
}
|
||||
TArray<FString> RequiredPlugins = IFMODStudioModule::Get().GetRequiredPlugins();
|
||||
if (RequiredPlugins.Num() != 0 && Settings.PluginFiles.Num() == 0)
|
||||
{
|
||||
FString CombinedPlugins;
|
||||
for (auto Name : RequiredPlugins)
|
||||
{
|
||||
CombinedPlugins += Name;
|
||||
CombinedPlugins += TEXT("\n");
|
||||
}
|
||||
FText PluginMessage = FText::Format(
|
||||
LOCTEXT("SetStudioBuildStudio_Plugins", "The banks require the following plugins, but no plugin filenames are listed in the settings:\n{0}\n"),
|
||||
FText::FromString(CombinedPlugins));
|
||||
FMessageDialog::Open(EAppMsgType::Ok, PluginMessage);
|
||||
ProblemsFound++;
|
||||
}
|
||||
|
||||
if (ProblemsFound)
|
||||
{
|
||||
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("SetStudioBuildStudio_FinishedBad", "Finished validation. Problems were detected.\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("SetStudioBuildStudio_FinishedGood", "Finished validation. No problems detected.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::ReloadBanks()
|
||||
{
|
||||
// Pretend settings have changed which will force a reload
|
||||
IFMODStudioModule::Get().RefreshSettings();
|
||||
}
|
||||
|
||||
bool FFMODStudioEditorModule::Tick( float DeltaTime )
|
||||
{
|
||||
if (!bRegisteredComponentVisualizers && GUnrealEd != nullptr)
|
||||
{
|
||||
// Register component visualizers (GUnrealED is required for this, but not initialized before this module loads, so we have to wait until GUnrealEd is available)
|
||||
RegisterComponentVisualizer(UFMODAudioComponent::StaticClass()->GetFName(), MakeShareable(new FFMODAudioComponentVisualizer));
|
||||
|
||||
bRegisteredComponentVisualizers = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::BeginPIE(bool simulating)
|
||||
{
|
||||
UE_LOG(LogFMOD, Verbose, TEXT("FFMODStudioEditorModule BeginPIE: %d"), simulating);
|
||||
bSimulating = simulating;
|
||||
bIsInPIE = true;
|
||||
IFMODStudioModule::Get().SetInPIE(true, simulating);
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::EndPIE(bool simulating)
|
||||
{
|
||||
UE_LOG(LogFMOD, Verbose, TEXT("FFMODStudioEditorModule EndPIE: %d"), simulating);
|
||||
bSimulating = false;
|
||||
bIsInPIE = false;
|
||||
IFMODStudioModule::Get().SetInPIE(false, simulating);
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::PausePIE(bool simulating)
|
||||
{
|
||||
UE_LOG(LogFMOD, Verbose, TEXT("FFMODStudioEditorModule PausePIE%d"));
|
||||
IFMODStudioModule::Get().SetSystemPaused(true);
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::ResumePIE(bool simulating)
|
||||
{
|
||||
UE_LOG(LogFMOD, Verbose, TEXT("FFMODStudioEditorModule ResumePIE"));
|
||||
IFMODStudioModule::Get().SetSystemPaused(false);
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::PostLoadCallback()
|
||||
{
|
||||
UE_LOG(LogFMOD, Verbose, TEXT("FFMODStudioEditorModule PostLoadCallback"));
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::ViewportDraw(UCanvas* Canvas, APlayerController*)
|
||||
{
|
||||
// Only want to update based on viewport in simulate mode.
|
||||
// In PIE/game, we update from the player controller instead.
|
||||
if (!bSimulating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FSceneView* View = Canvas->SceneView;
|
||||
|
||||
if (View->Drawer == GCurrentLevelEditingViewportClient)
|
||||
{
|
||||
UWorld* World = GCurrentLevelEditingViewportClient->GetWorld();
|
||||
const FVector& ViewLocation = GCurrentLevelEditingViewportClient->GetViewLocation();
|
||||
|
||||
FMatrix CameraToWorld = View->ViewMatrices.ViewMatrix.InverseFast();
|
||||
FVector ProjUp = CameraToWorld.TransformVector(FVector(0, 1000, 0));
|
||||
FVector ProjRight = CameraToWorld.TransformVector(FVector(1000, 0, 0));
|
||||
|
||||
FTransform ListenerTransform(FRotationMatrix::MakeFromZY(ProjUp, ProjRight));
|
||||
ListenerTransform.SetTranslation(ViewLocation);
|
||||
ListenerTransform.NormalizeRotation();
|
||||
|
||||
IFMODStudioModule::Get().SetListenerPosition(0, World, ListenerTransform, 0.0f);
|
||||
IFMODStudioModule::Get().FinishSetListenerPosition(1, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::ShutdownModule()
|
||||
{
|
||||
UE_LOG(LogFMOD, Verbose, TEXT("FFMODStudioEditorModule shutdown"));
|
||||
|
||||
if (UObjectInitialized())
|
||||
{
|
||||
// Unregister tick function.
|
||||
FTicker::GetCoreTicker().RemoveTicker(TickDelegateHandle);
|
||||
|
||||
FEditorDelegates::BeginPIE.Remove(BeginPIEDelegateHandle);
|
||||
FEditorDelegates::EndPIE.Remove(EndPIEDelegateHandle);
|
||||
FEditorDelegates::PausePIE.Remove(PausePIEDelegateHandle);
|
||||
FEditorDelegates::ResumePIE.Remove(ResumePIEDelegateHandle);
|
||||
|
||||
if (ViewportDrawingDelegate.IsBound())
|
||||
{
|
||||
UDebugDrawService::Unregister(ViewportDrawingDelegateHandle);
|
||||
}
|
||||
|
||||
FComponentAssetBrokerage::UnregisterBroker(AssetBroker);
|
||||
|
||||
if (MainMenuExtender.IsValid())
|
||||
{
|
||||
FLevelEditorModule* LevelEditorModule = FModuleManager::GetModulePtr<FLevelEditorModule>( "LevelEditor" );
|
||||
if (LevelEditorModule)
|
||||
{
|
||||
LevelEditorModule->GetMenuExtensibilityManager()->RemoveExtender(MainMenuExtender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
|
||||
{
|
||||
SettingsModule->UnregisterSettings("Project", "Plugins", "FMODStudio");
|
||||
}
|
||||
|
||||
// Unregister AssetTypeActions
|
||||
if (FModuleManager::Get().IsModuleLoaded("AssetTools"))
|
||||
{
|
||||
IAssetTools& AssetTools = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools").Get();
|
||||
|
||||
AssetTools.UnregisterAssetTypeActions(FMODEventAssetTypeActions.ToSharedRef());
|
||||
}
|
||||
|
||||
// Unregister component visualizers
|
||||
if (GUnrealEd != nullptr)
|
||||
{
|
||||
// Iterate over all class names we registered for
|
||||
for (FName ClassName : RegisteredComponentClassNames)
|
||||
{
|
||||
GUnrealEd->UnregisterComponentVisualizer(ClassName);
|
||||
}
|
||||
}
|
||||
|
||||
IFMODStudioModule::Get().BanksReloadedEvent().Remove(HandleBanksReloadedDelegateHandle);
|
||||
}
|
||||
|
||||
bool FFMODStudioEditorModule::HandleSettingsSaved()
|
||||
{
|
||||
IFMODStudioModule::Get().RefreshSettings();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::HandleBanksReloaded()
|
||||
{
|
||||
// Show a reload notification
|
||||
TArray<FString> FailedBanks = IFMODStudioModule::Get().GetFailedBankLoads(EFMODSystemContext::Auditioning);
|
||||
FText Message;
|
||||
SNotificationItem::ECompletionState State;
|
||||
if (FailedBanks.Num() == 0)
|
||||
{
|
||||
Message = LOCTEXT("FMODBanksReloaded", "Reloaded FMOD Banks\n");
|
||||
State = SNotificationItem::CS_Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
FString CombinedMessage = "Problem loading FMOD Banks:";
|
||||
for (auto Entry : FailedBanks)
|
||||
{
|
||||
CombinedMessage += TEXT("\n");
|
||||
CombinedMessage += Entry;
|
||||
|
||||
UE_LOG(LogFMOD, Warning, TEXT("Problem loading FMOD Bank: %s"), *Entry);
|
||||
}
|
||||
|
||||
Message = FText::Format(
|
||||
LOCTEXT("FMODBanksReloaded", "{0}"),
|
||||
FText::FromString(CombinedMessage));
|
||||
State = SNotificationItem::CS_Fail;
|
||||
}
|
||||
ShowNotification(Message, State);
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::ShowNotification(const FText& Text, SNotificationItem::ECompletionState State)
|
||||
{
|
||||
FNotificationInfo Info(Text);
|
||||
Info.Image = FEditorStyle::GetBrush(TEXT("NoBrush"));
|
||||
Info.FadeInDuration = 0.1f;
|
||||
Info.FadeOutDuration = 0.5f;
|
||||
Info.ExpireDuration = State == SNotificationItem::CS_Fail ? 6.0f : 1.5f;
|
||||
Info.bUseThrobber = false;
|
||||
Info.bUseSuccessFailIcons = true;
|
||||
Info.bUseLargeFont = true;
|
||||
Info.bFireAndForget = false;
|
||||
Info.bAllowThrottleWhenFrameRateIsLow = false;
|
||||
auto NotificationItem = FSlateNotificationManager::Get().AddNotification(Info);
|
||||
NotificationItem->SetCompletionState(State);
|
||||
NotificationItem->ExpireAndFadeout();
|
||||
|
||||
if (GCurrentLevelEditingViewportClient)
|
||||
{
|
||||
// Refresh any 3d event visualization
|
||||
GCurrentLevelEditingViewportClient->bNeedsRedraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
void FFMODStudioEditorModule::RegisterComponentVisualizer(FName ComponentClassName, TSharedPtr<FComponentVisualizer> Visualizer)
|
||||
{
|
||||
if (GUnrealEd != nullptr)
|
||||
{
|
||||
GUnrealEd->RegisterComponentVisualizer(ComponentClassName, Visualizer);
|
||||
}
|
||||
|
||||
RegisteredComponentClassNames.Add(ComponentClassName);
|
||||
|
||||
if (Visualizer.IsValid())
|
||||
{
|
||||
Visualizer->OnRegister();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
#pragma once
|
||||
|
||||
#include "Engine.h"
|
||||
#include "UnrealEd.h"
|
||||
#include "Components/SceneComponent.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogFMOD, Log, All);
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#include "FMODStudioEditorPrivatePCH.h"
|
||||
#include "FMODStudioStyle.h"
|
||||
#include "SlateStyle.h"
|
||||
#include "EditorStyle.h"
|
||||
|
||||
#define IMAGE_BRUSH(RelativePath, ...) FSlateImageBrush(Style.RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)
|
||||
#define BOX_BRUSH(RelativePath, ...) FSlateBoxBrush(Style.RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// FFMODStudioStyle
|
||||
|
||||
TSharedPtr<FSlateStyleSet> FFMODStudioStyle::StyleInstance = NULL;
|
||||
|
||||
void FFMODStudioStyle::Initialize()
|
||||
{
|
||||
if (!StyleInstance.IsValid())
|
||||
{
|
||||
StyleInstance = Create();
|
||||
}
|
||||
|
||||
SetStyle(StyleInstance.ToSharedRef());
|
||||
}
|
||||
|
||||
void FFMODStudioStyle::Shutdown()
|
||||
{
|
||||
ResetToDefault();
|
||||
ensure(StyleInstance.IsUnique());
|
||||
StyleInstance.Reset();
|
||||
}
|
||||
|
||||
TSharedRef<FSlateStyleSet> FFMODStudioStyle::Create()
|
||||
{
|
||||
IEditorStyleModule& EditorStyle = FModuleManager::LoadModuleChecked<IEditorStyleModule>(TEXT("EditorStyle"));
|
||||
TSharedRef< FSlateStyleSet > StyleRef = EditorStyle.CreateEditorStyleInstance();
|
||||
FSlateStyleSet& Style = StyleRef.Get();
|
||||
|
||||
const FVector2D Icon20x20(20.0f, 20.0f);
|
||||
const FVector2D Icon40x40(40.0f, 40.0f);
|
||||
|
||||
Style.Set( "ClassIcon.FMODAmbientSound", new IMAGE_BRUSH( "Icons/AssetIcons/AmbientSound_16x", FVector2D(16.0f, 16.0f) ) );
|
||||
Style.Set( "ClassThumbnail.FMODAmbientSound", new IMAGE_BRUSH( "Icons/AssetIcons/AmbientSound_64x", FVector2D(64.0f, 64.0f) ) );
|
||||
|
||||
Style.Set( "ClassIcon.FMODAudioComponent", new IMAGE_BRUSH( "Icons/ActorIcons/SoundActor_16x", FVector2D(16.0f, 16.0f) ) );
|
||||
//Style.Set( "ClassThumbnail.FMODAudioComponent", new IMAGE_BRUSH( "Icons/ActorIcons/SoundActor_64x", FVector2D(64.0f, 64.0f) ) );
|
||||
|
||||
Style.Set( "ClassIcon.FMODAsset", new IMAGE_BRUSH( "Icons/ActorIcons/SoundActor_16x", FVector2D(16.0f,16.0f) ) );
|
||||
//Style.Set( "ClassThumbnail.FMODAsset", new IMAGE_BRUSH( "Icons/ActorIcons/SoundActor_64x", FVector2D(64.0f, 64.0f) ) );
|
||||
|
||||
return StyleRef;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#undef IMAGE_BRUSH
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#pragma once
|
||||
|
||||
class FFMODStudioStyle : public FEditorStyle
|
||||
{
|
||||
public:
|
||||
static void Initialize();
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
private:
|
||||
static TSharedRef<class FSlateStyleSet> Create();
|
||||
|
||||
private:
|
||||
static TSharedPtr<class FSlateStyleSet> StyleInstance;
|
||||
|
||||
private:
|
||||
FFMODStudioStyle() {}
|
||||
};
|
||||
@@ -0,0 +1,375 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#include "FMODStudioEditorPrivatePCH.h"
|
||||
#include "SFMODEventEditorPanel.h"
|
||||
#include "FMODStudioModule.h"
|
||||
#include "FMODUtils.h"
|
||||
#include "Input/Reply.h"
|
||||
#include "SNumericEntryBox.h"
|
||||
#include "SExpandableArea.h"
|
||||
#include "fmod_studio.hpp"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FMODEventEditor"
|
||||
|
||||
SFMODEventEditorPanel::~SFMODEventEditorPanel()
|
||||
{
|
||||
}
|
||||
|
||||
void SFMODEventEditorPanel::Construct(const FArguments& InArgs)
|
||||
{
|
||||
FMODEventEditorPtr = InArgs._FMODEventEditor;
|
||||
|
||||
FMOD::Studio::EventDescription* EventDescription = FMODEventEditorPtr.Pin()->GetEventDescription();
|
||||
|
||||
TSharedRef<SBorder> ToolbarBorder = ConstructToolbar(EventDescription);
|
||||
TSharedRef<SExpandableArea> InfoArea = ConstructInfo(EventDescription);
|
||||
TSharedRef<SExpandableArea> ParametersArea = ConstructParameters(EventDescription);
|
||||
TSharedRef<SExpandableArea> UserPropertiesArea = ConstructUserProperties(EventDescription);
|
||||
|
||||
TSharedRef<SVerticalBox> ChildWidget =
|
||||
SNew(SVerticalBox)
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
.Padding(0.0f, 3.0f)
|
||||
[
|
||||
InfoArea
|
||||
]
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
.Padding(0.0f, 3.0f)
|
||||
[
|
||||
ParametersArea
|
||||
]
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
.Padding(0.0f, 3.0f)
|
||||
[
|
||||
UserPropertiesArea
|
||||
];
|
||||
|
||||
ChildSlot
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
.Padding(0.0f, 3.0f)
|
||||
[
|
||||
ToolbarBorder
|
||||
]
|
||||
+ SVerticalBox::Slot()
|
||||
.FillHeight(1.0f)
|
||||
[
|
||||
SNew(SScrollBox)
|
||||
+ SScrollBox::Slot()
|
||||
.Padding(0.0f)
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
.Padding(0.0f)
|
||||
[
|
||||
ChildWidget
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
TSharedRef<SBorder> SFMODEventEditorPanel::ConstructToolbar(FMOD::Studio::EventDescription* EventDescription)
|
||||
{
|
||||
float MinDistance = 0.0f;
|
||||
float MaxDistance = 0.0f;
|
||||
int32 EventLengthMS = 0;
|
||||
bool bIsOneshot = false, bIsStream = false, bIs3D = false;
|
||||
if (EventDescription != nullptr)
|
||||
{
|
||||
EventDescription->getMinimumDistance(&MinDistance);
|
||||
EventDescription->getMaximumDistance(&MaxDistance);
|
||||
EventDescription->getLength(&EventLengthMS);
|
||||
EventDescription->isOneshot(&bIsOneshot);
|
||||
EventDescription->isStream(&bIsStream);
|
||||
EventDescription->is3D(&bIs3D);
|
||||
}
|
||||
|
||||
const FTimespan EventLength = FTimespan::FromMilliseconds((double)EventLengthMS);
|
||||
const FString EventLengthString = EventLength.GetHours() <= 0 ? EventLength.ToString(TEXT("%m:%s.%f")) : EventLength.ToString(TEXT("%h:%m:%s.%f"));
|
||||
|
||||
const FText RadiusText = FText::Format(LOCTEXT("RadiusFormat", "Distance Attenuation: {0}m to {1}m"), FText::AsNumber(MinDistance), FText::AsNumber(MaxDistance));
|
||||
const FText LengthText = FText::Format(LOCTEXT("LengthFormat", "Length: {0}"), FText::FromString(EventLengthString));
|
||||
|
||||
FText EventInfoText;
|
||||
if (bIs3D && bIsOneshot)
|
||||
{
|
||||
EventInfoText = FText::Format(LOCTEXT("RadiusLengthFormat", "{0} - {1}"), RadiusText, LengthText);
|
||||
}
|
||||
else if (!bIs3D && bIsOneshot)
|
||||
{
|
||||
EventInfoText = LengthText;
|
||||
}
|
||||
else if (bIs3D && !bIsOneshot)
|
||||
{
|
||||
EventInfoText = RadiusText;
|
||||
}
|
||||
|
||||
return SNew(SBorder)
|
||||
.BorderImage(FEditorStyle::Get().GetBrush("ToolPanel.GroupBorder"))
|
||||
.Padding(6.0f)
|
||||
.Content()
|
||||
[
|
||||
SNew(SHorizontalBox)
|
||||
+ SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.Padding(0.0f, 0.0f, 2.0f, 0.0f)
|
||||
.VAlign(VAlign_Center)
|
||||
.HAlign(HAlign_Left)
|
||||
[
|
||||
SNew(SButton)
|
||||
.VAlign(VAlign_Center)
|
||||
.Text(LOCTEXT("Play", "Play"))
|
||||
.ContentPadding(4)
|
||||
.OnClicked(this, &SFMODEventEditorPanel::OnClickedPlay)
|
||||
]
|
||||
+ SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.Padding(2.0f, 0.0f)
|
||||
.VAlign(VAlign_Center)
|
||||
.HAlign(HAlign_Left)
|
||||
[
|
||||
SNew(SButton)
|
||||
.Text(LOCTEXT("Pause", "Pause"))
|
||||
.ContentPadding(4)
|
||||
.OnClicked(this, &SFMODEventEditorPanel::OnClickedPause)
|
||||
]
|
||||
+ SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.Padding(2.0f, 0.0f)
|
||||
.VAlign(VAlign_Center)
|
||||
.HAlign(HAlign_Left)
|
||||
[
|
||||
SNew(SButton)
|
||||
.VAlign(VAlign_Center)
|
||||
.Text(LOCTEXT("Stop", "Stop"))
|
||||
.ContentPadding(4)
|
||||
.OnClicked(this, &SFMODEventEditorPanel::OnClickedStop)
|
||||
]
|
||||
+ SHorizontalBox::Slot()
|
||||
.FillWidth(1.0f)
|
||||
.Padding(2.0f, 0.0f)
|
||||
.VAlign(VAlign_Center)
|
||||
.HAlign(HAlign_Right)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(EventInfoText)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
void AddTextField(TSharedRef<SVerticalBox>& InfoBox, const TCHAR* Name, const FText& Value)
|
||||
{
|
||||
InfoBox->AddSlot()
|
||||
.Padding(4.0f, 3.0f)
|
||||
[
|
||||
SNew(SHorizontalBox)
|
||||
+ SHorizontalBox::Slot()
|
||||
.FillWidth(0.3f)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(FText::FromString(Name))
|
||||
]
|
||||
+ SHorizontalBox::Slot()
|
||||
[
|
||||
SNew(SEditableText)
|
||||
.Text(Value)
|
||||
.IsReadOnly(true)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
void AddBoolField(TSharedRef<SVerticalBox>& InfoBox, const TCHAR* Name, bool bValue)
|
||||
{
|
||||
AddTextField(InfoBox, Name, bValue ? LOCTEXT("True","True") : LOCTEXT("False","False"));
|
||||
}
|
||||
|
||||
void AddFloatField(TSharedRef<SVerticalBox>& InfoBox, const TCHAR* Name, float Value)
|
||||
{
|
||||
AddTextField(InfoBox, Name, FText::AsNumber(Value));
|
||||
}
|
||||
|
||||
TSharedRef<SExpandableArea> MakeBox(TSharedRef<SVerticalBox>& InfoBox, const FText& Value)
|
||||
{
|
||||
return SNew(SExpandableArea)
|
||||
.AreaTitle(Value)
|
||||
.InitiallyCollapsed(false)
|
||||
.BodyContent()
|
||||
[
|
||||
SNew(SBorder)
|
||||
.BorderImage(FCoreStyle::Get().GetBrush("NoBorder"))
|
||||
.Padding(4.0f)
|
||||
.Content()
|
||||
[
|
||||
InfoBox
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
TSharedRef<SExpandableArea> SFMODEventEditorPanel::ConstructInfo(FMOD::Studio::EventDescription* EventDescription)
|
||||
{
|
||||
TSharedRef<SVerticalBox> InfoBox = SNew(SVerticalBox);
|
||||
|
||||
if (EventDescription != nullptr)
|
||||
{
|
||||
FString EventPath = FMODUtils::GetPath(EventDescription);
|
||||
FGuid Guid = FMODUtils::GetID(EventDescription);
|
||||
|
||||
int Length = 0.0f;
|
||||
float MinDist = 0.0f;
|
||||
float MaxDist = 0.0f;
|
||||
EventDescription->getLength(&Length);
|
||||
EventDescription->getMinimumDistance(&MinDist);
|
||||
EventDescription->getMaximumDistance(&MaxDist);
|
||||
|
||||
bool bOneShot = false;
|
||||
bool bStream = false;
|
||||
bool b3D = false;
|
||||
EventDescription->isOneshot(&bOneShot);
|
||||
EventDescription->isStream(&bStream);
|
||||
EventDescription->is3D(&b3D);
|
||||
|
||||
AddTextField(InfoBox, TEXT("Path"), FText::FromString(EventPath));
|
||||
AddTextField(InfoBox, TEXT("Guid"), FText::FromString(Guid.ToString(EGuidFormats::DigitsWithHyphensInBraces)));
|
||||
AddBoolField(InfoBox, TEXT("OneShot"), bOneShot);
|
||||
AddBoolField(InfoBox, TEXT("Streaming"), bStream);
|
||||
AddBoolField(InfoBox, TEXT("3D"), b3D);
|
||||
|
||||
AddFloatField(InfoBox, TEXT("Length"), static_cast<float>(Length));
|
||||
if (b3D)
|
||||
{
|
||||
AddFloatField(InfoBox, TEXT("Min Dist"), MinDist);
|
||||
AddFloatField(InfoBox, TEXT("Max Dist"), MaxDist);
|
||||
}
|
||||
}
|
||||
|
||||
return MakeBox(InfoBox, LOCTEXT("EventInfo", "Event Info"));
|
||||
}
|
||||
|
||||
TSharedRef<SExpandableArea> SFMODEventEditorPanel::ConstructParameters(FMOD::Studio::EventDescription* EventDescription)
|
||||
{
|
||||
auto EventEditor = FMODEventEditorPtr.Pin();
|
||||
TSharedRef<SVerticalBox> ParametersBox = SNew(SVerticalBox);
|
||||
|
||||
FNumberFormattingOptions Options;
|
||||
Options.MinimumFractionalDigits = 1;
|
||||
|
||||
if (EventDescription != nullptr)
|
||||
{
|
||||
int32 ParameterCount;
|
||||
EventDescription->getParameterCount(&ParameterCount);
|
||||
for (int32 ParamIdx = 0; ParamIdx < ParameterCount; ParamIdx++)
|
||||
{
|
||||
FMOD_STUDIO_PARAMETER_DESCRIPTION Parameter;
|
||||
EventDescription->getParameterByIndex(ParamIdx, &Parameter);
|
||||
|
||||
EventEditor->GetParameterValues().Add(Parameter.minimum);
|
||||
|
||||
const FString ParameterName = Parameter.type == FMOD_STUDIO_PARAMETER_GAME_CONTROLLED ? FString(UTF8_TO_TCHAR(Parameter.name)) : FMODUtils::ParameterTypeToString(Parameter.type);
|
||||
const FText ToolTipText = FText::Format(LOCTEXT("ParameterTooltipFormat", "{0} (Min Value: {1} - Max Value: {2})"),
|
||||
FText::FromString(ParameterName), FText::AsNumber(Parameter.minimum, &Options), FText::AsNumber(Parameter.maximum, &Options));
|
||||
|
||||
ParametersBox->AddSlot()
|
||||
.Padding(4.0f, 2.0f)
|
||||
[
|
||||
SNew(SHorizontalBox)
|
||||
.ToolTipText(ToolTipText)
|
||||
+ SHorizontalBox::Slot()
|
||||
.FillWidth(0.3f)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(FText::FromString(ParameterName))
|
||||
]
|
||||
+ SHorizontalBox::Slot()
|
||||
.MaxWidth(200.0f)
|
||||
[
|
||||
SNew(SNumericEntryBox<float>)
|
||||
.Value(this, &SFMODEventEditorPanel::GetParameterValue, ParamIdx)
|
||||
.OnValueChanged(this, &SFMODEventEditorPanel::OnParameterValueChanged, ParamIdx)
|
||||
.AllowSpin(true)
|
||||
.MinValue(Parameter.minimum)
|
||||
.MaxValue(Parameter.maximum)
|
||||
.MinSliderValue(Parameter.minimum)
|
||||
.MaxSliderValue(Parameter.maximum)
|
||||
.Delta(0.01f)
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return MakeBox(ParametersBox, LOCTEXT("EventParameters", "Event Parameters"));
|
||||
}
|
||||
|
||||
TSharedRef<SExpandableArea> SFMODEventEditorPanel::ConstructUserProperties(FMOD::Studio::EventDescription* EventDescription)
|
||||
{
|
||||
TSharedRef<SVerticalBox> UserPropertiesBox = SNew(SVerticalBox);
|
||||
|
||||
if (EventDescription != nullptr)
|
||||
{
|
||||
int32 UserPropertyCount;
|
||||
EventDescription->getUserPropertyCount(&UserPropertyCount);
|
||||
for (int32 PropertyIdx = 0; PropertyIdx < UserPropertyCount; PropertyIdx++)
|
||||
{
|
||||
FMOD_STUDIO_USER_PROPERTY UserProperty;
|
||||
EventDescription->getUserPropertyByIndex(PropertyIdx, &UserProperty);
|
||||
|
||||
FText PropertyText;
|
||||
switch (UserProperty.type)
|
||||
{
|
||||
case FMOD_STUDIO_USER_PROPERTY_TYPE_INTEGER:
|
||||
PropertyText = FText::AsNumber(UserProperty.intValue);
|
||||
break;
|
||||
case FMOD_STUDIO_USER_PROPERTY_TYPE_BOOLEAN:
|
||||
PropertyText = UserProperty.boolValue ? LOCTEXT("True", "True") : LOCTEXT("False", "False");
|
||||
break;
|
||||
case FMOD_STUDIO_USER_PROPERTY_TYPE_FLOAT:
|
||||
PropertyText = FText::AsNumber(UserProperty.floatValue);
|
||||
break;
|
||||
case FMOD_STUDIO_USER_PROPERTY_TYPE_STRING:
|
||||
PropertyText = FText::FromString(UTF8_TO_TCHAR(UserProperty.stringValue));
|
||||
break;
|
||||
}
|
||||
|
||||
FString UserName(UTF8_TO_TCHAR(UserProperty.name));
|
||||
AddTextField(UserPropertiesBox, *UserName, PropertyText);
|
||||
}
|
||||
}
|
||||
|
||||
return MakeBox(UserPropertiesBox, LOCTEXT("EventUserProperties", "Event User Properties"));
|
||||
}
|
||||
|
||||
FReply SFMODEventEditorPanel::OnClickedPlay()
|
||||
{
|
||||
FMODEventEditorPtr.Pin()->PlayEvent();
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
FReply SFMODEventEditorPanel::OnClickedStop()
|
||||
{
|
||||
FMODEventEditorPtr.Pin()->StopEvent();
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
FReply SFMODEventEditorPanel::OnClickedPause()
|
||||
{
|
||||
FMODEventEditorPtr.Pin()->PauseEvent();
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
void SFMODEventEditorPanel::OnParameterValueChanged(float NewValue, int32 ParameterIdx)
|
||||
{
|
||||
FMODEventEditorPtr.Pin()->SetParameterValue(ParameterIdx, NewValue);
|
||||
}
|
||||
|
||||
TOptional<float> SFMODEventEditorPanel::GetParameterValue(int32 ParameterIdx) const
|
||||
{
|
||||
return FMODEventEditorPtr.Pin()->GetParameterValues()[ParameterIdx];
|
||||
}
|
||||
|
||||
#undef LOC_NAMESPACE
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FMODEventEditor.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
namespace Studio
|
||||
{
|
||||
class EventDescription;
|
||||
}
|
||||
}
|
||||
|
||||
class SFMODEventEditorPanel : public SCompoundWidget
|
||||
{
|
||||
public:
|
||||
|
||||
SLATE_BEGIN_ARGS(SFMODEventEditorPanel)
|
||||
{}
|
||||
SLATE_ARGUMENT(TWeakPtr<FFMODEventEditor>, FMODEventEditor)
|
||||
SLATE_END_ARGS()
|
||||
|
||||
~SFMODEventEditorPanel();
|
||||
|
||||
/** SCompoundWidget interface */
|
||||
void Construct(const FArguments& InArgs);
|
||||
|
||||
private:
|
||||
|
||||
TSharedRef<SBorder> ConstructToolbar(FMOD::Studio::EventDescription* EventDescription);
|
||||
TSharedRef<SExpandableArea> ConstructInfo(FMOD::Studio::EventDescription* EventDescription);
|
||||
TSharedRef<SExpandableArea> ConstructParameters(FMOD::Studio::EventDescription* EventDescription);
|
||||
TSharedRef<SExpandableArea> ConstructUserProperties(FMOD::Studio::EventDescription* EventDescription);
|
||||
|
||||
/** Editor that owns this panel */
|
||||
TWeakPtr<FFMODEventEditor> FMODEventEditorPtr;
|
||||
|
||||
FReply OnClickedPlay();
|
||||
FReply OnClickedStop();
|
||||
FReply OnClickedPause();
|
||||
|
||||
TOptional<float> GetParameterValue(int32 ParameterIdx) const;
|
||||
void OnParameterValueChanged(float NewValue, int32 ParameterIdx);
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ModuleManager.h"
|
||||
|
||||
/**
|
||||
* The public interface to this module
|
||||
*/
|
||||
class IFMODStudioEditorModule : public IModuleInterface
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Singleton-like access to this module's interface. This is just for convenience!
|
||||
* Beware of calling this during the shutdown phase, though. Your module might have been unloaded already.
|
||||
*
|
||||
* @return Returns singleton instance, loading the module on demand if needed
|
||||
*/
|
||||
static inline IFMODStudioEditorModule& Get()
|
||||
{
|
||||
return FModuleManager::LoadModuleChecked< IFMODStudioEditorModule >( "FMODStudioEditor" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true.
|
||||
*
|
||||
* @return True if the module is loaded and ready to use
|
||||
*/
|
||||
static inline bool IsAvailable()
|
||||
{
|
||||
return FModuleManager::Get().IsModuleLoaded( "FMODStudioEditor" );
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user