Skip to content
Snippets Groups Projects
Commit 4f2ac1c1 authored by Sebastian Pape's avatar Sebastian Pape
Browse files

Initial Commit

parents
Branches
Tags
1 merge request!4Develop
Showing with 572 additions and 0 deletions
# Visual Studio 2015 user specific files
.vs/
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
*.ipa
# These project files can be generated by the engine
*.xcodeproj
*.xcworkspace
*.sln
*.suo
*.opensdf
*.sdf
*.VC.db
*.VC.opendb
# Precompiled Assets
SourceArt/**/*.png
SourceArt/**/*.tga
# Binary Files
Binaries/*
Plugins/*/Binaries/*
# Builds
Build/*
# Whitelist PakBlacklist-<BuildConfiguration>.txt files
!Build/*/
Build/*/**
!Build/*/PakBlacklist*.txt
# Don't ignore icon files in Build
!Build/**/*.ico
# Configuration files generated by the Editor
Saved/*
# Compiled source files for the engine to use
Intermediate/*
Plugins/*/Intermediate/*
# Cache files for the editor to use
DerivedDataCache/*
LocalDerivedDataCache/*
\ No newline at end of file
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "CAVEOverlay",
"Description": "Adds the ability to black out the CAVE Doors and display the magic tape",
"Category": "Other",
"CreatedBy": "",
"CreatedByURL": "",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "",
"CanContainContent": true,
"IsBetaVersion": false,
"Installed": false,
"Modules": [
{
"Name": "CAVEOverlay",
"Type": "Runtime",
"LoadingPhase": "Default"
}
],
"Plugins": [
{
"Name": "nDisplay",
"Enabled": true
}
],
"Plugins": [
{
"Name": "nDisplayExtensions",
"Enabled": true
}
]
}
\ No newline at end of file
File added
File added
File added
File added
File added
Resources/Icon128.png

7.33 KiB

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class CAVEOverlay : ModuleRules
{
public CAVEOverlay(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"UMG",
"DisplayCluster",
"DisplayClusterExtensions",
"InputCore"
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
}
}
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "CAVEOverlay.h"
#define LOCTEXT_NAMESPACE "FCAVEOverlayModule"
void FCAVEOverlayModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
}
void FCAVEOverlayModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FCAVEOverlayModule, CAVEOverlay)
\ No newline at end of file
// Fill out your copyright notice in the Description page of Project Settings.
#include "CAVEOverlayController.h"
DEFINE_LOG_CATEGORY(CAVEOverlayLog);
template<std::size_t SIZE> bool containsFString(const std::array<FString, SIZE> &a, const FString &s) {
for (FString cs : a) {
if (cs.Equals(s, ESearchCase::IgnoreCase)) return true;
}
return false;
}
UStaticMeshComponent* ACAVEOverlayController::createMeshComponent(const FName &name, UMaterialInterface* material, UStaticMesh* mesh, USceneComponent* parent) {
UStaticMeshComponent* result = CreateDefaultSubobject<UStaticMeshComponent>(name);
result->SetStaticMesh(mesh);
result->SetMaterial(0, material);
result->SetupAttachment(parent);
result->SetVisibility(false);
return result;
}
template<typename T> bool loadAsset(const FString &path, T* &result) {
ConstructorHelpers::FObjectFinder<T> loader(*path);
result = loader.Object;
if(!loader.Succeeded()) UE_LOG(CAVEOverlayLog, Error, TEXT("Could not find %s. Have you renamed it?"), *path);
return loader.Succeeded();
}
// Sets default values
ACAVEOverlayController::ACAVEOverlayController()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
AutoReceiveInput = EAutoReceiveInput::Player0;
ConstructorHelpers::FClassFinder<UDoorOverlayData> WidgetClassFinder(TEXT("Blueprint'/CAVEOverlay/DoorOverlay'"));
if (WidgetClassFinder.Succeeded()) {
overlay_class_ = WidgetClassFinder.Class;
} else {
UE_LOG(CAVEOverlayLog, Error, TEXT("Could not find the DoorOverlay class. Have you renamed it?"));
}
//Creation of subcomponents
root = CreateDefaultSubobject<USceneComponent>(TEXT("DefaultSceneRoot"));
SetRootComponent(root);
tape_root = CreateDefaultSubobject<USceneComponent>(TEXT("TapeRoot"));
sign_root = CreateDefaultSubobject<USceneComponent>(TEXT("SignRoot"));
tape_root->SetupAttachment(root);
sign_root->SetupAttachment(root);
//Loading of Materials and Meshes
loadAsset(TEXT("/CAVEOverlay/Stripes"), tape_material_);
loadAsset(TEXT("/CAVEOverlay/StopMaterial"), sign_material_);
loadAsset(TEXT("/CAVEOverlay/Plane"), plane_mesh_);
tape_material_dynamic_ = UMaterialInstanceDynamic::Create(tape_material_, tape_material_);
sign_material_dynamic_ = UMaterialInstanceDynamic::Create(sign_material_, sign_material_);
tape_negative_y = createMeshComponent(FName("TapeNegY"), tape_material_dynamic_, plane_mesh_, tape_root);
tape_negative_x = createMeshComponent(FName("TapeNegX"), tape_material_dynamic_, plane_mesh_, tape_root);
tape_positive_y = createMeshComponent(FName("TapePosY"), tape_material_dynamic_, plane_mesh_, tape_root);
tape_positive_x = createMeshComponent(FName("TapePosX"), tape_material_dynamic_, plane_mesh_, tape_root);
sign_negative_y = createMeshComponent(FName("SignNegY"), sign_material_dynamic_, plane_mesh_, sign_root);
sign_negative_x = createMeshComponent(FName("SignNegX"), sign_material_dynamic_, plane_mesh_, sign_root);
sign_positive_y = createMeshComponent(FName("SignPosY"), sign_material_dynamic_, plane_mesh_, sign_root);
sign_positive_x = createMeshComponent(FName("SignPosX"), sign_material_dynamic_, plane_mesh_, sign_root);
//Set initial Position, Rotation and Scale of Tape
tape_negative_y->SetRelativeLocationAndRotation(FVector(0, -wall_distance_, 0), FRotator(0, 0, 90));
tape_positive_y->SetRelativeLocationAndRotation(FVector(0, +wall_distance_, 0), FRotator(0, 180, 90));
tape_negative_x->SetRelativeLocationAndRotation(FVector(-wall_distance_, 0, 0), FRotator(0, -90, 90));
tape_positive_x->SetRelativeLocationAndRotation(FVector(+wall_distance_, 0, 0), FRotator(0, 90, 90));
tape_negative_y->SetRelativeScale3D(FVector(wall_distance_ / 100 * 2, 0.15, 1));
tape_positive_y->SetRelativeScale3D(FVector(wall_distance_ / 100 * 2, 0.15, 1));
tape_negative_x->SetRelativeScale3D(FVector(wall_distance_ / 100 * 2, 0.15, 1));
tape_positive_x->SetRelativeScale3D(FVector(wall_distance_ / 100 * 2, 0.15, 1));
//Set initial Position, Rotation and Scale of Signs
sign_negative_y->SetRelativeLocationAndRotation(FVector(0, -wall_distance_, 0), FRotator(0, 0, 90));
sign_positive_y->SetRelativeLocationAndRotation(FVector(0, +wall_distance_, 0), FRotator(0, 180, 90));
sign_negative_x->SetRelativeLocationAndRotation(FVector(-wall_distance_, 0, 0), FRotator(0, -90, 90));
sign_positive_x->SetRelativeLocationAndRotation(FVector(+wall_distance_, 0, 0), FRotator(0, 90, 90));
sign_negative_y->SetRelativeScale3D(FVector(0.5f));
sign_positive_y->SetRelativeScale3D(FVector(0.5f));
sign_negative_x->SetRelativeScale3D(FVector(0.5f));
sign_positive_x->SetRelativeScale3D(FVector(0.5f));
}
void ACAVEOverlayController::CycleDoorType()
{
door_current_mode_ = static_cast<DOOR_MODE>((door_current_mode_ + 1) % DOOR_NUM_MODES);
SetDoorMode(door_current_mode_);
}
void ACAVEOverlayController::SetDoorMode(DOOR_MODE m)
{
switch (door_current_mode_) {
case DOOR_MODE::DOOR_PARTIAL_OPEN:
door_current_opening_width_absolute_ = door_opening_width_absolute_;
if (screen_type_ == SCREEN_DOOR_PARTIAL) overlay_->BlackBox->SetRenderScale(FVector2D(door_opening_width_relative_, 1));
if (screen_type_ == SCREEN_MASTER) overlay_->BlackBox->SetRenderScale(FVector2D(door_opening_width_relative_, 1));
overlay_->BlackBox->SetVisibility(ESlateVisibility::Visible);
break;
case DOOR_MODE::DOOR_OPEN:
door_current_opening_width_absolute_ = wall_distance_ * 2;
if (screen_type_ == SCREEN_DOOR_PARTIAL) overlay_->BlackBox->SetRenderScale(FVector2D(1, 1));
if (screen_type_ == SCREEN_MASTER) overlay_->BlackBox->SetRenderScale(FVector2D(1, 1));
overlay_->BlackBox->SetVisibility(ESlateVisibility::Visible);
break;
case DOOR_MODE::DOOR_CLOSED:
door_current_opening_width_absolute_ = 0;
if (screen_type_ == SCREEN_DOOR_PARTIAL) overlay_->BlackBox->SetRenderScale(FVector2D(0, 1));
if (screen_type_ == SCREEN_MASTER) overlay_->BlackBox->SetRenderScale(FVector2D(0, 1));
overlay_->BlackBox->SetVisibility(ESlateVisibility::Hidden);
break;
}
if (screen_type_ == SCREEN_DOOR_PARTIAL) overlay_->BlackBox->SetRenderScale(FVector2D(0, 1)); //No black overlay
UE_LOG(CAVEOverlayLog, Log, TEXT("Switched door state to '%s'. New opening width is %f."), *door_mode_names_[door_current_mode_], door_current_opening_width_absolute_);
overlay_->CornerText->SetText(FText::FromString(door_mode_names_[door_current_mode_]));
}
// Called when the game starts or when spawned
void ACAVEOverlayController::BeginPlay()
{
Super::BeginPlay();
if (hmd_mode_ || !display_cluster_mode_) return; // Not our business
//Actor config
InputComponent->BindAction("DisplayClusterAction1", EInputEvent::IE_Pressed, this, &ACAVEOverlayController::CycleDoorType);
InputComponent->BindKey(EKeys::F10, EInputEvent::IE_Pressed, this, &ACAVEOverlayController::CycleDoorType);
//Read situation
hmd_mode_ = GEngine->XRSystem.IsValid() && GEngine->XRSystem->IsHeadTrackingAllowed();
display_cluster_mode_ = IDisplayCluster::Get().GetOperationMode() == EDisplayClusterOperationMode::Cluster;
//Determine the screentype for later usage
screen_type_ = SCREEN_NORMAL;
if (IDisplayCluster::Get().GetClusterMgr()->GetNodeId().Equals(screen_main, ESearchCase::IgnoreCase)) {
screen_type_ = SCREEN_MASTER;
}
else if (containsFString(screens_door_, IDisplayCluster::Get().GetClusterMgr()->GetNodeId())) {
screen_type_ = SCREEN_DOOR;
}
else if (containsFString(screens_door_partial_, IDisplayCluster::Get().GetClusterMgr()->GetNodeId())) {
screen_type_ = SCREEN_DOOR_PARTIAL;
}
overlay_ = CreateWidget<UDoorOverlayData>(GetWorld()->GetFirstPlayerController(), overlay_class_);
overlay_->AddToViewport(0);
SetDoorMode(door_current_mode_);
overlay_->CornerText->SetText(FText::FromString("")); //Set Text to "" until someone presses the key for the first time
player_pawn_ = Cast<AVirtualRealityPawn>(GetWorld()->GetFirstPlayerController()->GetPawn());
TArray<UDisplayClusterSceneComponent*> pawn_components;
player_pawn_->GetComponents<UDisplayClusterSceneComponent>(pawn_components);
for (UDisplayClusterSceneComponent* c : pawn_components) {
if (c->GetName().Equals("cave_origin", ESearchCase::IgnoreCase)) cave_origin_ = c;
if (c->GetName().Equals("shutter_glasses", ESearchCase::IgnoreCase)) cave_origin_ = c;
}
}
float ACAVEOverlayController::calculateOpacityFromPosition(FVector position) {
return FMath::Clamp(((FVector2D(position).GetAbs() - FVector2D(wall_distance_ - wall_close_distance_, wall_distance_ - wall_close_distance_)) / wall_fade_distance_).GetAbsMax(), 0.0f, 1.0f);
}
bool ACAVEOverlayController::positionInDoorOpening(FVector position) {
return FMath::IsWithinInclusive(position.X, wall_distance_ + 10 - 20 - wall_close_distance_, wall_distance_ + 10) //Overlap both sides 10cm
&& FMath::IsWithinInclusive(position.Y, wall_distance_ + 10 - door_current_opening_width_absolute_, wall_distance_ + 10); //Overlap one side 10cm
}
// Called every frame
void ACAVEOverlayController::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (hmd_mode_ || !display_cluster_mode_) return; // Not our business
//Move complete actor around
SetActorLocationAndRotation(cave_origin_->GetComponentLocation(), cave_origin_->GetComponentQuat());
//Tape Logic
FVector shutter_position = shutter_glasses_->GetRelativeTransform().GetLocation();
bool overlay_visible = FMath::IsWithinInclusive(shutter_position.GetAbsMax(), wall_distance_ - wall_close_distance_, wall_distance_);
if (overlay_visible && !positionInDoorOpening(shutter_position)) {
tape_root->SetVisibility(true, true);
tape_root->SetRelativeLocation(shutter_position * FVector(0, 0, 1)); //Only apply Z
float tape_opacity = calculateOpacityFromPosition(shutter_position);
tape_material_dynamic_->SetScalarParameterValue(FName("BarrierOpacity"), tape_opacity);
if (FMath::IsWithin(FVector2D(shutter_position).GetAbsMax(), wall_distance_ - wall_warning_distance_, wall_distance_)) { //in warning distance == red tape
tape_material_dynamic_->SetVectorParameterValue(FName("StripeColor"), FVector(1, 0, 0));
}
else {
tape_material_dynamic_->SetVectorParameterValue(FName("StripeColor"), FVector(1, 1, 0));
}
} else {
tape_root->SetVisibility(false, true);
}
//Sign Logic
UDisplayClusterSceneComponent* flystick = IDisplayCluster::Get().GetGameMgr()->GetNodeById(TEXT("flystick"));
if (flystick) {
FVector flystick_position = flystick->GetRelativeTransform().GetLocation();
bool flystick_in_door = positionInDoorOpening(flystick_position);
float sign_opacity = calculateOpacityFromPosition(flystick_position);
sign_negative_x->SetRelativeLocation(FVector(-wall_distance_, flystick_position.Y, flystick_position.Z));
sign_negative_y->SetRelativeLocation(FVector(flystick_position.X, -wall_distance_, flystick_position.Z));
sign_positive_x->SetRelativeLocation(FVector(+wall_distance_, flystick_position.Y, flystick_position.Z));
sign_positive_y->SetRelativeLocation(FVector(flystick_position.X, +wall_distance_, flystick_position.Z));
sign_negative_x->SetVisibility(FMath::IsWithin(-flystick_position.X, wall_distance_ - wall_close_distance_, wall_distance_) && !flystick_in_door);
sign_negative_y->SetVisibility(FMath::IsWithin(-flystick_position.Y, wall_distance_ - wall_close_distance_, wall_distance_) && !flystick_in_door);
sign_positive_x->SetVisibility(FMath::IsWithin(+flystick_position.X, wall_distance_ - wall_close_distance_, wall_distance_) && !flystick_in_door);
sign_positive_y->SetVisibility(FMath::IsWithin(+flystick_position.Y, wall_distance_ - wall_close_distance_, wall_distance_) && !flystick_in_door);
sign_material_dynamic_->SetScalarParameterValue(FName("SignOpacity"), sign_opacity);
} else {
sign_negative_x->SetVisibility(false);
sign_negative_y->SetVisibility(false);
sign_positive_x->SetVisibility(false);
sign_positive_y->SetVisibility(false);
}
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "DoorOverlayData.h"
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FCAVEOverlayModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "DoorOverlayData.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "IDisplayCluster.h"
#include "Engine/Engine.h"
#include "IXRTrackingSystem.h"
#include "Components/InputComponent.h"
#include "Cluster/IDisplayClusterClusterManager.h"
#include "IDisplayClusterGameManager.h"
#include "InputCoreTypes.h"
#include "UObject/ConstructorHelpers.h"
#include <array>
#include "Components/StaticMeshComponent.h"
#include "Engine/Engine.h"
#include "Materials/Material.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "DisplayClusterExtensions/Public/VirtualRealityPawn.h"
#include "DisplayCluster/Public/DisplayClusterSceneComponent.h"
#include "CAVEOverlayController.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(CAVEOverlayLog, Log, All);
UCLASS()
class CAVEOVERLAY_API ACAVEOverlayController : public AActor
{
GENERATED_BODY()
public:
ACAVEOverlayController();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
private:
//Execution Modes
bool hmd_mode_ = false;
bool display_cluster_mode_ = false;
//Screen Types
enum SCREEEN_TYPE { SCREEN_MASTER, SCREEN_NORMAL, SCREEN_DOOR_PARTIAL, SCREEN_DOOR };
SCREEEN_TYPE screen_type_ = SCREEN_NORMAL;
const std::array<FString, 4> screens_door_ = {"node_bul_left_eye", "node_bul_right_eye", "node_bll_left_eye", "node_bll_right_eye"};
const std::array<FString, 4> screens_door_partial_ = {"node_bur_left_eye", "node_bur_right_eye", "node_blr_left_eye", "node_blr_right_eye"};
const FString screen_main = "node_main";
//Door Mode
enum DOOR_MODE { DOOR_CLOSED = 0, DOOR_OPEN = 1, DOOR_PARTIAL_OPEN = 2, DOOR_NUM_MODES = 3};
const FString door_mode_names_[DOOR_NUM_MODES] = {"Partial Open", "Closed", "Open" };
DOOR_MODE door_current_mode_ = DOOR_PARTIAL_OPEN;
const float door_opening_width_relative_ = 0.522; //%, used for the overlay width on the screen
const float door_opening_width_absolute_ = 165; //cm, used for the non tape part at the door
const float wall_distance_ = 262.5; //cm, distance from center to a wall, *2 = wall width
const float wall_close_distance_ = 75; //cm, the distance considered to be too close to the walls
const float wall_fade_distance_ = 35; //cm, the distance over which the tape is faded
const float wall_warning_distance_ = 40; //cm, distance on which the tape turns red, measurred from wall
float door_current_opening_width_absolute_ = 0;
//Overlay
TSubclassOf<class UDoorOverlayData> overlay_class_;
UDoorOverlayData* overlay_;
//Geometry and Material
UStaticMeshComponent* createMeshComponent(const FName &name, UMaterialInterface* material, UStaticMesh* mesh, USceneComponent* parent);
UMaterial* tape_material_ = nullptr;
UMaterial* sign_material_ = nullptr;
float calculateOpacityFromPosition(FVector position);
bool positionInDoorOpening(FVector position);
//Pawn Components
AVirtualRealityPawn* player_pawn_;
UDisplayClusterSceneComponent* cave_origin_;
UDisplayClusterSceneComponent* shutter_glasses_;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
void CycleDoorType();
void SetDoorMode(DOOR_MODE m);
//Signs and Banners
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) USceneComponent* root = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) USceneComponent* tape_root = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) USceneComponent* sign_root = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent* tape_negative_y = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent* tape_negative_x = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent* tape_positive_y = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent* tape_positive_x = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent* sign_negative_y = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent* sign_negative_x = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent* sign_positive_y = nullptr;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent* sign_positive_x = nullptr;
UMaterialInstanceDynamic* tape_material_dynamic_ = nullptr;
UMaterialInstanceDynamic* sign_material_dynamic_ = nullptr;
UStaticMesh* plane_mesh_ = nullptr;
};
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "TextBlock.h"
#include "Border.h"
#include "DoorOverlayData.generated.h"
/**
*
*/
UCLASS()
class CAVEOVERLAY_API UDoorOverlayData : public UUserWidget
{
GENERATED_BODY()
public:
//These declarations are magically bound to the UMG blueprints elements,
//if they are named the same
UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
UTextBlock* CornerText;
UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
UBorder* BlackBox;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment