diff --git a/Content/InstanceMaterial.uasset b/Content/InstanceMaterial.uasset new file mode 100644 index 0000000000000000000000000000000000000000..2fb267b53bfd278ae16752cd0e518422e251670e --- /dev/null +++ b/Content/InstanceMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd8257ab5d1829b9ff175b290de9ffed71b9cb974d838f525de39089fdda5e02 +size 49757 diff --git a/Content/textmaterial.uasset b/Content/textmaterial.uasset new file mode 100644 index 0000000000000000000000000000000000000000..ecb4b3901b8284e446d840a556f5dc86a565083c --- /dev/null +++ b/Content/textmaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28e0e621930bd6cfba91edf24730fcf6cde5528501d697e984309a2d4447753f +size 24983 diff --git a/Source/DasherVR/Private/Dasher3DWidget.cpp b/Source/DasherVR/Private/Dasher3DWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74980edc57a08939c5efe6dd4ef822208be4a773 --- /dev/null +++ b/Source/DasherVR/Private/Dasher3DWidget.cpp @@ -0,0 +1,302 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Dasher3DWidget.h" +#include "Math/Rotator.h" +#include "Engine/Texture2DArray.h" +// Sets default values +ADasher3DWidget::ADasher3DWidget() : DasherParents() +{ + // 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; + + ActorRootComponent = CreateDefaultSubobject<UStaticMeshComponent>("Root"); + SetRootComponent(ActorRootComponent); + + CubeInstances = CreateDefaultSubobject<UInstancedStaticMeshComponent>("Cubes"); + CubeInstances->SetupAttachment(GetRootComponent()); + CubeInstances->SetFlags(RF_Transactional); + CubeInstances->NumCustomDataFloats = 6; //Full Linear Color + CubeInstances->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore); + this->AddInstanceComponent(CubeInstances); + + LetterInstances = CreateDefaultSubobject<UInstancedStaticMeshComponent>("Letters"); + LetterInstances->SetupAttachment(GetRootComponent()); + LetterInstances->SetFlags(RF_Transactional); + LetterInstances->NumCustomDataFloats = 5; //Full Linear Color + LetterInstances->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore); + this->AddInstanceComponent(LetterInstances); + +} + +// Called when the game starts or when spawned +void ADasher3DWidget::BeginPlay() +{ + Super::BeginPlay(); + //Setting up Dasher + InitializeDasher(); + //Setting up the Texture array for the font + InitializeTextureArray(); +} + +// Called every frame +void ADasher3DWidget::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + DasherMainInterface->Tick(static_cast<unsigned long>(GetGameTimeSinceCreation() * 1000.0)); //we need to provide ticks in milliseconds + + //TODO subscribe to some resizing event + const FVector AbsoluteSize = GetActorScale(); + if (SlateSize.X != AbsoluteSize.X || SlateSize.Y != AbsoluteSize.Y) { + SlateSize.X = AbsoluteSize.X; + SlateSize.Y = AbsoluteSize.Y; + resize(SlateSize.X * DrawingSize.X, SlateSize.Y * DrawingSize.Y); + DefaultTranslation = FVector(-SlateSize.X * DrawingSize.X / 2.0f, -SlateSize.Y / 2.0f * DrawingSize.Y, 0); + //tell dasher we resized the screen, but only if there's actually a screen + if (SlateSize.X && SlateSize.Y) DasherMainInterface->ScreenResized(this); + }; + + + //TODO: REMOVE, DEBUG LINES + //CursorPosition = FVector2D(500, 500); + DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); +} + +std::pair<Dasher::screenint, Dasher::screenint> ADasher3DWidget::TextSize(Label* label, unsigned iFontSize) +{ + const char letter = label->m_strText[0]; + int letterindex = letter; + if (letterindex < 33) letterindex = 33; + + const int TextureIndex = DisplayFont->Characters[letterindex].TextureIndex; + const float emWidth = DisplayFont->Characters['M'].USize; //To get width of an emdash + const float TextureSizeU = TextureArray->SourceTextures[TextureIndex]->GetSizeX(); // Pixel Sizes + const float TextureSizeV = TextureArray->SourceTextures[TextureIndex]->GetSizeY(); // Pixel Sizes + const float CharacterOffsetU = DisplayFont->Characters[letterindex].StartU; //Upper left corner + const float CharacterOffsetV = DisplayFont->Characters[letterindex].StartV; //Upper left corner + const float CharacterSizeU = DisplayFont->Characters[letterindex].USize; // Pixel Sizes for actual character without blank space + const float CharacterSizeV = DisplayFont->Characters[letterindex].VSize; // Pixel Sizes for actual character without blank space + const float CharacterVerticalOffset = DisplayFont->Characters[letterindex].VerticalOffset; //vertical offset in pixels + FVector2D FontToPixels = FVector2D(iFontSize, iFontSize); // Since Font to meter was font * (meters/pixel) assumption: font in pixels + const FVector2D Scale = FontToPixels * FVector2D( + CharacterSizeU / emWidth, // width + (CharacterSizeV / CharacterSizeU) * (CharacterSizeU / emWidth)); // (Height/Width * Width) + return { static_cast<Dasher::screenint>(Scale.X), static_cast<Dasher::screenint>(Scale.Y) }; + +} + +void ADasher3DWidget::DrawString(Label* label, Dasher::screenint x, Dasher::screenint y, unsigned iFontSize, int iColour){} + +void ADasher3DWidget::DrawCube(Dasher::screenint posX, Dasher::screenint posY, Dasher::screenint sizeX, Dasher::screenint sizeY, Dasher::myint extrusionLevel, int Colour, int iOutlineColour, int iThickness) { + + if (sizeX == 0 || sizeY == 0) return; + const FVector Scale = FVector(sizeX, sizeY, sqrt(extrusionLevel * 10)) / DrawingSize; + const FVector Translation = FVector(posX, posY, 0) + DefaultTranslation - FVector(SlateSize / 2.0f, 0); + + FLinearColor RectColor; + + if (ColorPalette) { + RectColor = FLinearColor(ColorPalette->Colors[Colour].Red / 255.0, ColorPalette->Colors[Colour].Green / 255.0, ColorPalette->Colors[Colour].Blue / 255.0); + } + else { + RectColor = FLinearColor::Blue; + } + + BackBuffer->first.Add(FTransform(FQuat::Identity, Translation / DrawingSize * 100.0f, Scale)); + BackBuffer->second.Add(RectColor.R); + BackBuffer->second.Add(RectColor.G); + BackBuffer->second.Add(RectColor.B); + BackBuffer->second.Add(Scale.X); + BackBuffer->second.Add(Scale.Y); + BackBuffer->second.Add(Scale.Z); +} + + +auto ADasher3DWidget::GetLetterTransformData(int letterindex, int iFontSize, int x, int y, int extrusionLevel, int position) { + if (letterindex < 32) letterindex = 32; // replace non-printable characters with spaces. + + const int TextureIndex = DisplayFont->Characters[letterindex].TextureIndex; + const float emWidth = DisplayFont->Characters['M'].USize; //To get width of an emdash + const float TextureSizeU = TextureArray->SourceTextures[TextureIndex]->GetSizeX(); // Pixel Sizes + const float TextureSizeV = TextureArray->SourceTextures[TextureIndex]->GetSizeY(); // Pixel Sizes + const float CharacterOffsetU = DisplayFont->Characters[letterindex].StartU; //Upper left corner + const float CharacterOffsetV = DisplayFont->Characters[letterindex].StartV; //Upper left corner + const float CharacterSizeU = DisplayFont->Characters[letterindex].USize; // Pixel Sizes for actual character without blank space + const float CharacterSizeV = DisplayFont->Characters[letterindex].VSize; // Pixel Sizes for actual character without blank space + const float CharacterVerticalOffset = DisplayFont->Characters[letterindex].VerticalOffset; //vertical offset in pixels + const FVector FontToMeters = FVector(iFontSize / DrawingSize.X, iFontSize / DrawingSize.Y, 1); // From Font to Meter + + TArray<float> FontData = { + CharacterOffsetU / TextureSizeU, // Upper Left Corner given in UV + CharacterOffsetV / TextureSizeV, // Upper Left Corner given in UV + CharacterSizeU / TextureSizeU, // Size given in UV + CharacterSizeV / TextureSizeV, // Size given in UV + static_cast<float>(TextureIndex) }; // Texture Page + // X & Y are given as upper left corner of the character + + + const FVector Scale = FontToMeters * FVector( + CharacterSizeU / emWidth, // width + (CharacterSizeV / CharacterSizeU) * (CharacterSizeU / emWidth), // (Height/Width * Width) + 1); + + + const FVector Translation = FVector( + x / DrawingSize.X * 100.0f + Scale.X * 0.5f * 100.0f + position * emWidth, // offsetting by position for multpile character strings + y / DrawingSize.Y * 100.0f + CharacterVerticalOffset / emWidth * iFontSize / DrawingSize.Y * 100.0f, //+ Scale.Y * 0.5f * 100.0f + sqrt(extrusionLevel * 10 + 1)) + + (-FVector(SlateSize / 2.0f, 0) + DefaultTranslation) / DrawingSize * 100.0f; // Move to upper left corner + + + const FTransform Transform = FTransform(FQuat::Identity, Translation, Scale); + + struct LetterData { + FTransform transform; + TArray<float> FontData; + }; + return LetterData{ Transform, FontData }; +} + + +void ADasher3DWidget::Draw3DLabel(Label* label, Dasher::screenint x, Dasher::screenint y, Dasher::myint extrusionLevel, unsigned int iFontSize, int iColour) { + //TODO: expand to all Labels + const std::string labeltext = label->m_strText; + + for (int i = 0; i < labeltext.size(); i++) + { + int letterindex = labeltext[i]; + auto [Transform, FontData] = GetLetterTransformData(letterindex, iFontSize, x, y, extrusionLevel, i); + LabelBackBuffer->first.Add(Transform); + LabelBackBuffer->second.Add(FontData); + } +} + + + + + + +void ADasher3DWidget::DrawRectangle(Dasher::screenint x1, Dasher::screenint y1, Dasher::screenint x2, Dasher::screenint y2, int Colour, int iOutlineColour, int iThickness) +{ + // we're not drawing rectangles +} + +void ADasher3DWidget::DrawCircle(Dasher::screenint iCX, Dasher::screenint iCY, Dasher::screenint iR, int iFillColour, int iLineColour, int iLineWidth) +{ + //Todo +} + +void ADasher3DWidget::Polyline(point* Points, int Number, int iWidth, int Colour) +{ + //Todo +} + +void ADasher3DWidget::Polygon(point* Points, int Number, int fillColour, int outlineColour, int lineWidth) +{ + //Todo +} + +void ADasher3DWidget::Display() +{ + std::swap(FrontBuffer, BackBuffer); + BackBuffer->first.Empty(); + BackBuffer->second.Empty(); + CubeInstances->ClearInstances(); + CubeInstances->AddInstances(FrontBuffer->first, false); + + TArray<float> ColorScale = {0,0,0,0,0,0}; + for(int i = 0; i < FrontBuffer->first.Num(); i++) + { + ColorScale = { + FrontBuffer->second[i*CubeInstances->NumCustomDataFloats], + FrontBuffer->second[i*CubeInstances->NumCustomDataFloats+1], + FrontBuffer->second[i*CubeInstances->NumCustomDataFloats+2], + FrontBuffer->second[i*CubeInstances->NumCustomDataFloats+3], + FrontBuffer->second[i*CubeInstances->NumCustomDataFloats+4], + FrontBuffer->second[i*CubeInstances->NumCustomDataFloats+5] + }; + CubeInstances->SetCustomData(i, ColorScale); + } + + + std::swap(LabelFrontBuffer, LabelBackBuffer); + LabelBackBuffer->first.Empty(); + LabelBackBuffer->second.Empty(); + LetterInstances->ClearInstances(); + LetterInstances->AddInstances(LabelFrontBuffer->first, false); + + for (int i = 0; i < LabelFrontBuffer->first.Num(); i++) + { + TArray<float> data = LabelFrontBuffer->second[i]; + LetterInstances->SetCustomData(i, data); + } + +} + +void ADasher3DWidget::SetColourScheme(const Dasher::CColourIO::ColourInfo* pColourScheme) +{ + ColorPalette = pColourScheme; +} + +bool ADasher3DWidget::IsPointVisible(Dasher::screenint x, Dasher::screenint y) +{ + return true; +} + +bool ADasher3DWidget::GetScreenCoords(Dasher::screenint& iX, Dasher::screenint& iY, Dasher::CDasherView* pView) +{ + const FVector2D Position = GetCursorPosition(); + + iX = Position.X; + iY = Position.Y; + + return true; +} + +void ADasher3DWidget::SetMouseLocation(FVector2D InputVector) +{ + CursorPosition = FVector2D((InputVector.X * 10 + DrawingSize.X/2.0f) * SlateSize.X, (InputVector.Y * 10 + DrawingSize.Y / 2.0f) * SlateSize.Y);//FVector2D(500, 500);// +} + +void ADasher3DWidget::InitializeTextureArray() +{ + TextureArray = NewObject<UTexture2DArray>(); + for (int i = 0; i < DisplayFont->Textures.Num(); i++) + { + TextureArray->SourceTextures.Add(DisplayFont->Textures[i]); + } + TextureArray->UpdateSourceFromSourceTextures(true); + MaxVSize = 0; + MaxUSize = 0; + for (int i = 65; i < 91; i++) + { + if (DisplayFont->Characters[i].VSize > MaxVSize) MaxVSize = DisplayFont->Characters[i].VSize; + if (DisplayFont->Characters[i].USize > MaxUSize) MaxUSize = DisplayFont->Characters[i].USize; + } +} + +void ADasher3DWidget::InitializeDasher() { + SlateSize = FVector2D(GetActorScale().X, GetActorScale().Y); + DefaultTranslation = FVector(-SlateSize.X * DrawingSize.X / 2.0f, -SlateSize.Y / 2.0f * DrawingSize.Y, 0); + resize(SlateSize.X * DrawingSize.X, SlateSize.Y * DrawingSize.Y); + + static Dasher::XMLErrorDisplay display; + Dasher::XmlSettingsStore* Settings = new Dasher::XmlSettingsStore("Settings.xml"/*, &fileUtils*/, &display); //Gets deleted somewhere else + Settings->Load(); + Settings->Save(); + DasherMainInterface = MakeShared<Dasher::DasherInterface>(Settings); + DasherMainInterface->SetDefaultInputDevice(this); + //change dasher parameters + DasherMainInterface->SetBoolParameter(Dasher::BP_AUTO_SPEEDCONTROL, false); //Auto Speed Control + DasherMainInterface->SetLongParameter(Dasher::LP_DASHER_FONTSIZE, 22); + DasherMainInterface->SetLongParameter(Dasher::LP_MAX_BITRATE, 400); //Maximum Speed + //DasherMainInterface->SetStringParameter(Dasher::SP_INPUT_FILTER, "Normal"); //On Hold + DasherMainInterface->SetStringParameter(Dasher::SP_ALPHABET_ID, "German without punctuation"); + DasherMainInterface->SetLongParameter(Dasher::LP_MIN_NODE_SIZE, 15); + DasherMainInterface->SetLongParameter(Dasher::LP_SHAPE_TYPE, Dasher::Options::CUBE); + + DasherMainInterface->SetScreen(this); + DasherMainInterface->SetBuffer(0); + DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); + + DasherMainInterface->SetLongParameter(Dasher::LP_ORIENTATION, Dasher::Options::ScreenOrientations::LeftToRight); +} \ No newline at end of file diff --git a/Source/DasherVR/Private/DasherFileUtils.cpp b/Source/DasherVR/Private/DasherFileUtils.cpp index 8f346a33bc02e3dee5e606b181ea025213995991..8e1f40a87d2f571c44af9affe5bd94e1cea891da 100644 --- a/Source/DasherVR/Private/DasherFileUtils.cpp +++ b/Source/DasherVR/Private/DasherFileUtils.cpp @@ -2,6 +2,8 @@ #include "DasherCoreWrapper.h" #include "HAL/FileManagerGeneric.h" #include "Misc/FileHelper.h" +#include "Misc/Paths.h" +#include "Internationalization/Regex.h" namespace Dasher { diff --git a/Source/DasherVR/Private/DasherInterface.cpp b/Source/DasherVR/Private/DasherInterface.cpp index 9eaea7b3d89e0c61bf010850ada712ac7c84353a..bf2a2eb4c6c2d4e3105b84f382138ba1038cad70 100644 --- a/Source/DasherVR/Private/DasherInterface.cpp +++ b/Source/DasherVR/Private/DasherInterface.cpp @@ -129,7 +129,7 @@ namespace Dasher NewFrame(time, true); } - void DasherInterface::SetScreen(SDasherWidget* screen) + void DasherInterface::SetScreen(CDasherScreen* screen) { //set the widget as screen that dasher will be displayed on ChangeScreen(screen); diff --git a/Source/DasherVR/Private/DasherVRPrivatePCH.h b/Source/DasherVR/Private/DasherVRPrivatePCH.h new file mode 100644 index 0000000000000000000000000000000000000000..e9cda3f89f2a68c2afdae9ce7dc82a88b39841fb --- /dev/null +++ b/Source/DasherVR/Private/DasherVRPrivatePCH.h @@ -0,0 +1,3 @@ +#pragma once +#include "CoreMinimal.h" +#include "DasherVR.h" \ No newline at end of file diff --git a/Source/DasherVR/Private/SDasherWidget.cpp b/Source/DasherVR/Private/SDasherWidget.cpp index 3e770e343de12e02f56c4f435d14aed58303401e..dc69aa944c744f8b58e626cd678c7eb8fbc0e293 100644 --- a/Source/DasherVR/Private/SDasherWidget.cpp +++ b/Source/DasherVR/Private/SDasherWidget.cpp @@ -6,6 +6,7 @@ #include "DasherInterface.h" #include "Components/SlateWrapperTypes.h" +#include "Framework/Application/SlateApplication.h" BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION @@ -16,331 +17,375 @@ BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION //Set the state if we're in the editor or not. void SDasherWidget::SetEditor(bool EditorState) { - IsEditor = EditorState; + IsEditor = EditorState; +} +//Pause the input +void SDasherWidget::PauseInput() +{ + InputPaused = true; +} +//Unpause the input +void SDasherWidget::UnpauseInput() +{ + InputPaused = false; } + //Event Handlers //Mouse position saved for mouse Input FReply SDasherWidget::HandleMouseMoveEvent(const FGeometry& Geometry, const FPointerEvent& MouseEvent) { - if (CurrentlyUsingVectorInput) return FReply::Unhandled(); - //The mouse event only contains the Screen Space Position - CursorPosition = Geometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()); - return FReply::Handled(); + if (!InputPaused) + { + if (CurrentlyUsingVectorInput) return FReply::Unhandled(); + //The mouse event only contains the Screen Space Position + CursorPosition = Geometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()); + } + return FReply::Handled(); } FReply SDasherWidget::HandleMouseDownEvent(const FGeometry& Geometry, const FPointerEvent& MouseEvent) { - if (CurrentlyUsingVectorInput) - { - CurrentlyUsingVectorInput = false; - return FReply::Handled().LockMouseToWidget(AsShared()); - } - DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB - MouseDownListeners.ExecuteIfBound(); - return FReply::Handled().LockMouseToWidget(AsShared()); + if (!InputPaused) + { + if (CurrentlyUsingVectorInput) + { + CurrentlyUsingVectorInput = false; + return FReply::Handled().LockMouseToWidget(AsShared()); + } + DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB + MouseDownListeners.ExecuteIfBound(); + } + return FReply::Handled().LockMouseToWidget(AsShared()); } FReply SDasherWidget::HandleMouseUpEvent(const FGeometry& Geometry, const FPointerEvent& MouseEvent) { - if (CurrentlyUsingVectorInput) - { - CurrentlyUsingVectorInput = false; - return FReply::Handled().ReleaseMouseLock(); - } - DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB + if (CurrentlyUsingVectorInput) + { + CurrentlyUsingVectorInput = false; + return FReply::Handled().ReleaseMouseLock(); + } + DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB MouseUpListeners.ExecuteIfBound(); - return FReply::Handled().ReleaseMouseLock(); + + return FReply::Handled().ReleaseMouseLock(); } FReply SDasherWidget::HandleMouseDoubleClickEvent(const FGeometry& Geometry, const FPointerEvent& MouseEvent) { - if(CurrentlyUsingVectorInput) - { - CurrentlyUsingVectorInput = false; - return FReply::Handled(); - } - DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB - return FReply::Handled(); + if (!InputPaused) + { + if (CurrentlyUsingVectorInput) + { + CurrentlyUsingVectorInput = false; + return FReply::Handled(); + } + DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB + } + return FReply::Handled(); } //Set in the HandleMouseMoveEvent or via Set InputVector //See tick for geometry things that could be use to modify this. FVector2D SDasherWidget::GetCursorPosition() { - return CursorPosition; + return CursorPosition; } bool SDasherWidget::GetScreenCoords(screenint& iX, screenint& iY, Dasher::CDasherView* pView) { - const FVector2D Position = GetCursorPosition(); - - iX = Position.X; - iY = Position.Y; + const FVector2D Position = GetCursorPosition(); + + iX = Position.X; + iY = Position.Y; - return true; + return true; } void SDasherWidget::InputVector(const FVector2D InputVector) { - if (!CurrentlyUsingVectorInput) return; - CursorPosition = DasherMainInterface->ConvertDasher2Screen(Dasher::CDasherModel::ORIGIN_X, Dasher::CDasherModel::ORIGIN_Y) - + InputVector * FVector2D(1.0f,-1.0f) * (GetHeight() / 2); + if (!InputPaused) { + if (!CurrentlyUsingVectorInput) return; + CursorPosition = DasherMainInterface->ConvertDasher2Screen(Dasher::CDasherModel::ORIGIN_X, Dasher::CDasherModel::ORIGIN_Y) + + InputVector * FVector2D(1.0f, -1.0f) * (GetHeight() / 2); + } } void SDasherWidget::InputButton(bool Pressed) { - CurrentlyUsingVectorInput = true; - if(Pressed) - { - DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB - } - else { - DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB - } + if (!InputPaused) { + CurrentlyUsingVectorInput = true; + if (Pressed) + { + DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB + } + else { + DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB + } + } } //The construction of the Dasher Widget, Dasher parameters are set here, a function to set them outside is not provided, but can be easily implemented void SDasherWidget::Construct(const FArguments& InArgs) { - //Initial resize, needed for setup - Width = InArgs._width; - Height = InArgs._height; - resize(Width, Height); + //Initial resize, needed for setup + Width = InArgs._width; + Height = InArgs._height; + resize(Width, Height); - //initialize the font measuring service. - FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService(); + //initialize the font measuring service. + FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService(); - //Setting up Dasher - static Dasher::XMLErrorDisplay display; + //Setting up Dasher + static Dasher::XMLErrorDisplay display; Dasher::XmlSettingsStore* Settings = new Dasher::XmlSettingsStore("Settings.xml", &display); //Gets deleted somewhere else Settings->Load(); - Settings->Save(); + Settings->Save(); DasherMainInterface = MakeShared<Dasher::DasherInterface>(Settings); - DasherMainInterface->SetDefaultInputDevice(this); + DasherMainInterface->SetDefaultInputDevice(this); - DasherMainInterface->SetScreen(this); - DasherMainInterface->SetBuffer(0); + DasherMainInterface->SetScreen(this); + DasherMainInterface->SetBuffer(0); - DasherMainInterface->SetCharEnteredCallback([this](FString Char, FString Buffer){CharacterEntered.ExecuteIfBound(Char, Buffer);}); - DasherMainInterface->SetCharDeletedCallback([this](FString Char, FString Buffer){CharacterDeleted.ExecuteIfBound(Char, Buffer);}); + DasherMainInterface->SetCharEnteredCallback([this](FString Char, FString Buffer) {CharacterEnteredFlag = true; AlteredChar = Char; }); + DasherMainInterface->SetCharDeletedCallback([this](FString Char, FString Buffer) {CharacterDeletedFlag = true; AlteredChar = Char; }); - //Set up the Event Handlers for Mouse Movement etc. - SetOnMouseMove(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseMoveEvent(Geometry, MouseEvent) ; })); - SetOnMouseButtonDown(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseDownEvent(Geometry, MouseEvent); })); - SetOnMouseButtonUp(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseUpEvent(Geometry, MouseEvent); })); - SetOnMouseDoubleClick(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseDoubleClickEvent(Geometry, MouseEvent); })); //We treat a double click of the mouse as a lift of the mouse button. + //Set up the Event Handlers for Mouse Movement etc. + SetOnMouseMove(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseMoveEvent(Geometry, MouseEvent) ; })); + SetOnMouseButtonDown(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseDownEvent(Geometry, MouseEvent); })); + SetOnMouseButtonUp(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseUpEvent(Geometry, MouseEvent); })); + SetOnMouseDoubleClick(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseDoubleClickEvent(Geometry, MouseEvent); })); //We treat a double click of the mouse as a lift of the mouse button. //You could add Slate Code here for child slots etc. } -void SDasherWidget::SetBoolParamter(FString ParameterName, bool Value) -{ - for(Dasher::Settings::bp_table Setting : Dasher::Settings::boolparamtable) - { - if(FString(Setting.regName).Compare(ParameterName, ESearchCase::IgnoreCase)) - { - DasherMainInterface->SetBoolParameter(Setting.key, Value); - return; - } - } +void SDasherWidget::SetParameter(FString ParameterName, bool Value) { + for (auto param = Dasher::Settings::parameter_defaults.begin(); param != Dasher::Settings::parameter_defaults.end(); ++param) + if (param->second.name == TCHAR_TO_UTF8(*ParameterName)) { + DasherMainInterface->SetBoolParameter(param->first, Value); + return; + } } -void SDasherWidget::SetLongParamter(FString ParameterName, int64 Value) -{ - for(Dasher::Settings::bp_table Setting : Dasher::Settings::boolparamtable) - { - if(FString(Setting.regName).Compare(ParameterName, ESearchCase::IgnoreCase)) - { - DasherMainInterface->SetLongParameter(Setting.key, Value); - return; - } - } +void SDasherWidget::SetParameter(FString ParameterName, int64 Value) { + for (auto param = Dasher::Settings::parameter_defaults.begin(); param != Dasher::Settings::parameter_defaults.end(); ++param) + if (param->second.name == TCHAR_TO_UTF8(*ParameterName)) { + DasherMainInterface->SetLongParameter(param->first, Value); + return; + } } -void SDasherWidget::SetStringParamter(FString ParameterName, FString Value) -{ - for(Dasher::Settings::bp_table Setting : Dasher::Settings::boolparamtable) - { - if(FString(Setting.regName).Compare(ParameterName, ESearchCase::IgnoreCase)) - { - DasherMainInterface->SetStringParameter(Setting.key, TCHAR_TO_UTF8(*Value)); - return; - } - } +void SDasherWidget::SetParameter(FString ParameterName, FString Value) { + for (auto param = Dasher::Settings::parameter_defaults.begin(); param != Dasher::Settings::parameter_defaults.end(); ++param) + if (param->second.name == TCHAR_TO_UTF8(*ParameterName)) { + DasherMainInterface->SetStringParameter(param->first, TCHAR_TO_UTF8(*Value)); + return; + } } + + //Set the colour Scheme for dasher void SDasherWidget::SetColourScheme(const Dasher::CColourIO::ColourInfo* pcolours) { - ColorPalette = pcolours; + ColorPalette = pcolours; } //paints our stuff, then lets compoundwidget (super::) draw its stuff //This draws from bottom to top rectangles->lines->labels, this is enough for our use, but for more complex scenarios a proper layering system might have to be implemented int32 SDasherWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { - //this doesn't draw anything red, we just need a brush. Could probably find a better "empty" brush - auto MyBrush = FSlateColorBrush(FColor::Red); - - FFilledRect* RectObject; - FWriting* WritingObject; - FPolyLine* LineObject; - FVector2D Size; - FString Text; - FSlateFontInfo Font; - - TArray<TUniquePtr<DasherDrawGeometry>>& GeometryBuffer = *FrontBuffer; - for(TUniquePtr<DasherDrawGeometry>& GeneralObject : GeometryBuffer) { - switch(GeneralObject->Type) - { - case Rectangle: - RectObject = static_cast<FFilledRect*>(GeneralObject.Get()); - Size = {FMath::Abs(RectObject->top.X - RectObject->bottom.X), FMath::Abs(RectObject->top.Y - RectObject->bottom.Y)}; - FSlateDrawElement::MakeBox(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(Size, FSlateLayoutTransform(1, RectObject->top)), &MyBrush, ESlateDrawEffect::None, RectObject->color); //actually adds the box to the geometry - break; - case Writing: - WritingObject = static_cast<FWriting*>(GeneralObject.Get()); - Text = FString(UTF8_TO_TCHAR(WritingObject->label->m_strText.c_str())); - - Font = FCoreStyle::GetDefaultFontStyle("Roboto", WritingObject->size, FFontOutlineSettings::NoOutline); //get the font - FSlateDrawElement::MakeText(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(FSlateLayoutTransform(1, FVector2D(WritingObject->pos.X, WritingObject->pos.Y))), Text , Font, ESlateDrawEffect::None, WritingObject->color); - break; - case PolyLine: - LineObject = static_cast<FPolyLine*>(GeneralObject.Get()); - FSlateDrawElement::MakeLines(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(), LineObject->points, ESlateDrawEffect::None, LineObject->color, true, LineObject->linewidth); - break; - default: break; - } - } - - return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); //call the parent onPaint + //this doesn't draw anything red, we just need a brush. Could probably find a better "empty" brush + auto MyBrush = FSlateColorBrush(FColor::Red); + + FFilledRect* RectObject; + FWriting* WritingObject; + FPolyLine* LineObject; + FVector2D Size; + FString Text; + FSlateFontInfo Font; + + TArray<TUniquePtr<DasherDrawGeometry>>& GeometryBuffer = *FrontBuffer; + for(TUniquePtr<DasherDrawGeometry>& GeneralObject : GeometryBuffer) { + switch(GeneralObject->Type) + { + case Rectangle: + RectObject = static_cast<FFilledRect*>(GeneralObject.Get()); + Size = { FMath::Abs(RectObject->top.X - RectObject->bottom.X), FMath::Abs(RectObject->top.Y - RectObject->bottom.Y) }; + FSlateDrawElement::MakeBox(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(Size, FSlateLayoutTransform(1, RectObject->top)), &MyBrush, ESlateDrawEffect::None, RectObject->color); //actually adds the box to the geometry + break; + case Writing: + WritingObject = static_cast<FWriting*>(GeneralObject.Get()); + Text = FString(UTF8_TO_TCHAR(WritingObject->label->m_strText.c_str())); + + Font = FCoreStyle::GetDefaultFontStyle("Roboto", WritingObject->size, FFontOutlineSettings::NoOutline); //get the font + FSlateDrawElement::MakeText(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(FSlateLayoutTransform(1, FVector2D(WritingObject->pos.X, WritingObject->pos.Y))), Text , Font, ESlateDrawEffect::None, WritingObject->color); + break; + case PolyLine: + LineObject = static_cast<FPolyLine*>(GeneralObject.Get()); + FSlateDrawElement::MakeLines(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(), LineObject->points, ESlateDrawEffect::None, LineObject->color, true, LineObject->linewidth); + break; + default: break; + } + } + + return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); //call the parent onPaint } //The tick function, we tick dasher in it and update the screen size for dasher void SDasherWidget::Tick(const FGeometry& AllotedGeometry, const double InCurrentTime, const float InDeltaTime) { - //don't tick in the editor - if (!IsEditor) { - SCompoundWidget::Tick(AllotedGeometry, InCurrentTime, InDeltaTime); + //don't tick in the editor + if (!IsEditor && !InputPaused) { + SCompoundWidget::Tick(AllotedGeometry, InCurrentTime, InDeltaTime); - DasherMainInterface->Tick(static_cast<unsigned long>(InCurrentTime * 1000.0)); //we need to provide ticks in milliseconds + DasherMainInterface->Tick(static_cast<unsigned long>(InCurrentTime * 1000.0)); //we need to provide ticks in milliseconds - //This probably doesn't have to be done every tick, but it does not seem to have a huge hit on performance + //This probably doesn't have to be done every tick, but it does not seem to have a huge hit on performance const FGeometry Geometry = GetTickSpaceGeometry(); const FIntPoint AbsoluteSize = Geometry.Size.IntPoint(); - if (Width != AbsoluteSize.X || Height != AbsoluteSize.Y) { - Width = AbsoluteSize.X; - Height = AbsoluteSize.Y; - resize(Width, Height); - //tell dasher we resized the screen, but only if there's actually a screen - if (Width && Height) DasherMainInterface->ScreenResized(this); - }; - } + if (Width != AbsoluteSize.X || Height != AbsoluteSize.Y) { + Width = AbsoluteSize.X; + Height = AbsoluteSize.Y; + resize(Width, Height); + //tell dasher we resized the screen, but only if there's actually a screen + if (Width && Height) DasherMainInterface->ScreenResized(this); + }; + } } std::pair<SDasherWidget::screenint, SDasherWidget::screenint> SDasherWidget::TextSize(CDasherScreen::Label* Label, unsigned Size) { - const FSlateFontInfo Font = FCoreStyle::GetDefaultFontStyle("Roboto", Size, FFontOutlineSettings::NoOutline); //get the font - const FVector2D TextSize = FontMeasureService->Measure(FString(UTF8_TO_TCHAR(Label->m_strText.c_str())), Font, 1); //get the real size of the text, using the fontmeasuring service - return {static_cast<screenint>(TextSize.X), static_cast<screenint>(TextSize.Y)}; + const FSlateFontInfo Font = FCoreStyle::GetDefaultFontStyle("Roboto", Size, FFontOutlineSettings::NoOutline); //get the font + const FVector2D TextSize = FontMeasureService->Measure(FString(UTF8_TO_TCHAR(Label->m_strText.c_str())), Font, 1); //get the real size of the text, using the fontmeasuring service + return {static_cast<screenint>(TextSize.X), static_cast<screenint>(TextSize.Y)}; } //Double Buffers are rotated here. void SDasherWidget::Display() { - std::swap(FrontBuffer, BackBuffer); - BackBuffer->Empty(); + std::swap(FrontBuffer, BackBuffer); + BackBuffer->Empty(); + + if (CharacterEnteredFlag && CharacterDeletedFlag) { + CharacterSwitched.ExecuteIfBound(AlteredChar, GetBuffer()); + } + else if (CharacterEnteredFlag) { + CharacterEntered.ExecuteIfBound(AlteredChar, GetBuffer()); + } + else if (CharacterDeletedFlag) { + CharacterDeleted.ExecuteIfBound(AlteredChar, GetBuffer()); + } + + CharacterEnteredFlag = false; + CharacterDeletedFlag = false; } - //Functions for Drawing void SDasherWidget::DrawRectangle(Dasher::screenint x1, Dasher::screenint y1, Dasher::screenint x2, Dasher::screenint y2, int colour, int iOutlineColour, int iThickness) { - const FVector2D Top(x1, y1); - const FVector2D Bottom(x2, y2); - - FLinearColor RectColor; - - if (ColorPalette) { - RectColor = FLinearColor(ColorPalette->Colors[colour].Red/255.0, ColorPalette->Colors[colour].Green / 255.0, ColorPalette->Colors[colour].Blue / 255.0); - } - else { - RectColor = FLinearColor::Blue; - } - - BackBuffer->Add(MakeUnique<FFilledRect>(Top, Bottom, RectColor)); + FLinearColor RectColorFG = FLinearColor(0, 0, 0); + FLinearColor RectColorBG = FLinearColor(0, 0, 0); + + FVector2D TopBG = FVector2D(x1, y1); + FVector2D BottomBG = FVector2D(x2, y2); + FVector2D TopFG(x1, y1); + FVector2D BottomFG(x2, y2); + + if (iThickness && !(colour == 99 || colour == 96)) + { + const int BGColour = iOutlineColour == -1 ? 3 : iOutlineColour; + TopFG = FVector2D(x1+iThickness, y1+iThickness); + BottomFG = FVector2D(x2-iThickness, y2-iThickness); + + RectColorBG = FLinearColor(ColorPalette->Colors[BGColour].Red / 255.0, ColorPalette->Colors[BGColour].Green / 255.0, ColorPalette->Colors[BGColour].Blue / 255.0); + BackBuffer->Add(MakeUnique<FFilledRect>(TopBG, BottomBG, RectColorBG)); + } + + + if (colour == 99 || colour == 96) + { + RectColorFG = FLinearColor(ColorPalette->Colors[colour].Red / 255.0, ColorPalette->Colors[colour].Green / 255.0, ColorPalette->Colors[colour].Blue / 255.0, 0.5); + } + else + { + RectColorFG = FLinearColor(ColorPalette->Colors[colour].Red / 255.0, ColorPalette->Colors[colour].Green / 255.0, ColorPalette->Colors[colour].Blue / 255.0); + } + + BackBuffer->Add(MakeUnique<FFilledRect>(TopFG, BottomFG, RectColorFG)); } void SDasherWidget::DrawString(CDasherScreen::Label* lab, screenint x1, screenint y1, unsigned int iSize, int colour) { - const FVector2D Pos(x1, y1); - - FLinearColor TextColor; - - if (ColorPalette) { - TextColor = FLinearColor(ColorPalette->Colors[colour].Red / 255.0, ColorPalette->Colors[colour].Green / 255.0, ColorPalette->Colors[colour].Blue / 255.0); - } - else { - TextColor = FLinearColor::Black; - } - - BackBuffer->Add(MakeUnique<FWriting>(lab, Pos, static_cast<int>(iSize), TextColor)); + const FVector2D Pos(x1, y1); + + FLinearColor TextColor; + + if (ColorPalette) { + TextColor = FLinearColor(ColorPalette->Colors[colour].Red / 255.0, ColorPalette->Colors[colour].Green / 255.0, ColorPalette->Colors[colour].Blue / 255.0); + } + else { + TextColor = FLinearColor::Black; + } + + BackBuffer->Add(MakeUnique<FWriting>(lab, Pos, static_cast<int>(iSize), TextColor)); } void SDasherWidget::Polyline(CDasherScreen::point* points, int number, int iwidth, int colour) { - - FLinearColor LinearColor; - - if (ColorPalette) { - LinearColor = FLinearColor(ColorPalette->Colors[colour].Red / 255.0, ColorPalette->Colors[colour].Green / 255.0, ColorPalette->Colors[colour].Blue / 255.0); - } - else { - LinearColor = FLinearColor::Blue; - } - - TArray<FVector2D> PointArray; - for (int i = 0; i < number; i++) { - FVector2D Point(points[i].x, points[i].y); - PointArray.Add(Point); - } - - BackBuffer->Add(MakeUnique<FPolyLine>(PointArray, static_cast<float>(iwidth), LinearColor)); + + FLinearColor LinearColor; + + if (ColorPalette) { + LinearColor = FLinearColor(ColorPalette->Colors[colour].Red / 255.0, ColorPalette->Colors[colour].Green / 255.0, ColorPalette->Colors[colour].Blue / 255.0); + } + else { + LinearColor = FLinearColor::Blue; + } + + TArray<FVector2D> PointArray; + for (int i = 0; i < number; i++) { + FVector2D Point(points[i].x, points[i].y); + PointArray.Add(Point); + } + + BackBuffer->Add(MakeUnique<FPolyLine>(PointArray, static_cast<float>(iwidth), LinearColor)); } //techincally polygons are just multiple polylines. Dasher doesn't actually draw polygons in our case. void SDasherWidget::Polygon(CDasherScreen::point* points, int number, int fillcolour, int outlinecolour, int iwidth) { - FLinearColor LinearColor; - - if (ColorPalette) { - LinearColor = FLinearColor(ColorPalette->Colors[outlinecolour].Red / 255.0, ColorPalette->Colors[outlinecolour].Green / 255.0, ColorPalette->Colors[outlinecolour].Blue / 255.0); - } - else { - LinearColor = FLinearColor::Blue; - } - - TArray<FVector2D> PointArray; - for (int i = 0; i < number; i++) { - FVector2D Point(points[i].x, points[i].y); - PointArray.Add(Point); - } - PointArray.Add(FVector2D(points[0].x, points[0].y)); - - BackBuffer->Add(MakeUnique<FPolyLine>(PointArray, static_cast<float>(iwidth), LinearColor)); + FLinearColor LinearColor; + + if (ColorPalette) { + LinearColor = FLinearColor(ColorPalette->Colors[outlinecolour].Red / 255.0, ColorPalette->Colors[outlinecolour].Green / 255.0, ColorPalette->Colors[outlinecolour].Blue / 255.0); + } + else { + LinearColor = FLinearColor::Blue; + } + + TArray<FVector2D> PointArray; + for (int i = 0; i < number; i++) { + FVector2D Point(points[i].x, points[i].y); + PointArray.Add(Point); + } + PointArray.Add(FVector2D(points[0].x, points[0].y)); + + BackBuffer->Add(MakeUnique<FPolyLine>(PointArray, static_cast<float>(iwidth), LinearColor)); } //We pass through the contents of the dasher buffer FString SDasherWidget::GetBuffer() const { - return DasherMainInterface->GetBuffer(); + return DasherMainInterface->GetBuffer(); } void SDasherWidget::ResetBuffer() { - DasherMainInterface->ResetBuffer(); + DasherMainInterface->ResetBuffer(); } void SDasherWidget::StartTraining(FString PathToTextFile) { - DasherMainInterface->ImportTrainingFile(TCHAR_TO_UTF8(*FPaths::ConvertRelativePathToFull(PathToTextFile))); + DasherMainInterface->ImportTrainingFile(TCHAR_TO_UTF8(*FPaths::ConvertRelativePathToFull(PathToTextFile))); } + // ++ We need to undefine this namespace after we finish creating the Slate widget #undef LOCTEXT_NAMESPACE diff --git a/Source/DasherVR/Private/UDasherWidget.cpp b/Source/DasherVR/Private/UDasherWidget.cpp index 29031715ffeb8bf132a0e7b038f7b8eeec9bfcec..b5482574059a07465e738949d71e87d5c52e0c1d 100644 --- a/Source/DasherVR/Private/UDasherWidget.cpp +++ b/Source/DasherVR/Private/UDasherWidget.cpp @@ -1,5 +1,5 @@ /* - Adapted from JoySoftEdgeImage by Rama https://nerivec.github.io/old-ue4-wiki/pages/umg-custom-widget-components-and-render-code-usable-in-umg-designer.html + Adapted from JoySoftEdgeImage by Rama https://nerivec.github.io/old-ue4-wiki/pages/umg-custom-widget-components-and-render-code-usable-in-umg-designer.html */ #include "UDasherWidget.h" @@ -9,89 +9,105 @@ ///////////////////////////////////////////////////// // UDasherWidget UDasherWidget::UDasherWidget(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) + : Super(ObjectInitializer) { - //Default Values Set Here, see above + //Default Values Set Here, see above } //Rebuild using custom Slate Widget TSharedRef<SWidget> UDasherWidget::RebuildWidget() { - if (!DasherScreen) - { - DasherScreen = SNew(SDasherWidget).height(1080).width(1920); - } - return DasherScreen.ToSharedRef(); + if (!DasherScreen) + { + DasherScreen = SNew(SDasherWidget).height(1080).width(1920); + } + return DasherScreen.ToSharedRef(); } void UDasherWidget::SynchronizeProperties() { - Super::SynchronizeProperties(); - - //Check if we're in Editor - DasherScreen->SetEditor(IsDesignTime()); - DasherScreen->CharacterEntered.BindLambda([this](FString Char, FString Buffer) - { - CharacterEntered.Broadcast(Char, Buffer); - BufferAltered.Broadcast(Buffer); - }); - DasherScreen->CharacterDeleted.BindLambda([this](FString Char, FString Buffer) - { - CharacterDeleted.Broadcast(Char, Buffer); - BufferAltered.Broadcast(Buffer); - }); - DasherScreen->MouseUpListeners.BindLambda([this]() {MouseEvent.Broadcast(false); }); - DasherScreen->MouseDownListeners.BindLambda([this]() {MouseEvent.Broadcast(true); }); + Super::SynchronizeProperties(); + + //Check if we're in Editor + DasherScreen->SetEditor(IsDesignTime()); + DasherScreen->CharacterEntered.BindLambda([this](FString Char, FString Buffer) + { + CharacterEntered.Broadcast(Char, Buffer); + BufferAltered.Broadcast(Buffer); + }); + DasherScreen->CharacterDeleted.BindLambda([this](FString Char, FString Buffer) + { + CharacterDeleted.Broadcast(Char, Buffer); + BufferAltered.Broadcast(Buffer); + }); + DasherScreen->CharacterSwitched.BindLambda([this](FString Char, FString Buffer) + { + CharacterSwitched.Broadcast(Char, Buffer); + BufferAltered.Broadcast(Buffer); + }); + DasherScreen->MouseUpListeners.BindLambda([this]() {MouseEvent.Broadcast(false); }); + DasherScreen->MouseDownListeners.BindLambda([this]() {MouseEvent.Broadcast(true); }); } void UDasherWidget::ReleaseSlateResources(bool bReleaseChildren) { - Super::ReleaseSlateResources(bReleaseChildren); + Super::ReleaseSlateResources(bReleaseChildren); - DasherScreen.Reset(); + DasherScreen.Reset(); } FString UDasherWidget::GetBuffer() { - return DasherScreen->GetBuffer(); + return DasherScreen->GetBuffer(); } void UDasherWidget::ResetBuffer() { - DasherScreen->ResetBuffer(); - BufferAltered.Broadcast(""); + DasherScreen->ResetBuffer(); + BufferAltered.Broadcast(""); } void UDasherWidget::StartTraining(FString PathToTextFile) { - DasherScreen->StartTraining(PathToTextFile); + DasherScreen->StartTraining(PathToTextFile); } void UDasherWidget::SetBoolParamter(FString ParameterName, bool Value) { - DasherScreen->SetBoolParamter(ParameterName, Value); + DasherScreen->SetParameter(ParameterName, Value); } void UDasherWidget::SetLongParamter(FString ParameterName, int64 Value) { - DasherScreen->SetLongParamter(ParameterName, Value); + DasherScreen->SetParameter(ParameterName, Value); } void UDasherWidget::SetStringParamter(FString ParameterName, FString Value) { - DasherScreen->SetStringParamter(ParameterName, Value); + DasherScreen->SetParameter(ParameterName, Value); } void UDasherWidget::InputButton(bool Pressed) { - DasherScreen->InputButton(Pressed); + DasherScreen->InputButton(Pressed); } void UDasherWidget::InputVector(FVector2D InputVector) { - DasherScreen->InputVector(InputVector); + DasherScreen->InputVector(InputVector); } +void UDasherWidget::PauseInput() +{ + DasherScreen->PauseInput(); +} + +void UDasherWidget::UnpauseInput() +{ + DasherScreen->UnpauseInput(); +} + + #if WITH_EDITOR //const FSlateBrush* UDasherWidget::GetEditorIcon() @@ -101,7 +117,7 @@ void UDasherWidget::InputVector(FVector2D InputVector) const FText UDasherWidget::GetPaletteCategory() { - return LOCTEXT("Common", "Common"); + return LOCTEXT("Common", "Common"); } #endif diff --git a/Source/DasherVR/Public/Dasher3DWidget.h b/Source/DasherVR/Public/Dasher3DWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..cb45f47c259b676f124604cccdd8c17b0e7d95b9 --- /dev/null +++ b/Source/DasherVR/Public/Dasher3DWidget.h @@ -0,0 +1,96 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Engine/Font.h" +#include "GameFramework/Actor.h" +#include "DasherCoreWrapper.h" +#include "DasherInterface.h" +#include "Fonts/FontMeasure.h" +#include "Components/InstancedStaticMeshComponent.h" +#include "Dasher3DWidget.generated.h" + +class DasherParents : public Dasher::CDasherScreen, public Dasher::CScreenCoordInput +{ +public: + DasherParents() : CDasherScreen(0,0), CScreenCoordInput(0, _("Mouse Input")){}; +}; + + +UCLASS() +class DASHERVR_API ADasher3DWidget : public AActor, public DasherParents +{ + GENERATED_BODY() + +public: + // Sets default values for this actor's properties + ADasher3DWidget(); + +protected: + // Called when the game starts or when spawned + virtual void BeginPlay() override; + void InitializeDasher(); + void InitializeTextureArray(); + auto GetLetterTransformData(int letterindex, int iFontSize, int x, int y, int extrusionLevel, int position); + +public: + // Called every frame + virtual void Tick(float DeltaTime) override; + + virtual std::pair<Dasher::screenint, Dasher::screenint> TextSize(Label* label, unsigned iFontSize) override; + virtual void DrawString(Label* label, Dasher::screenint x, Dasher::screenint y, unsigned iFontSize, int iColour) override; + virtual void DrawRectangle(Dasher::screenint x1, Dasher::screenint y1, Dasher::screenint x2, Dasher::screenint y2, int Colour, int iOutlineColour, int iThickness); + virtual void DrawCube(Dasher::screenint posX, Dasher::screenint posY, Dasher::screenint sizeX, Dasher::screenint sizeY, Dasher::myint extrusionLevel, int Colour, int iOutlineColour, int iThickness) override; + virtual void Draw3DLabel(Label* label, Dasher::screenint x, Dasher::screenint y, Dasher::myint extrusionLevel, unsigned int iFontSize, int iColour) override; + virtual void DrawCircle(Dasher::screenint iCX, Dasher::screenint iCY, Dasher::screenint iR, int iFillColour, int iLineColour, int iLineWidth) override; + virtual void Polyline(point* Points, int Number, int iWidth, int Colour) override; + virtual void Polygon(point* Points, int Number, int fillColour, int outlineColour, int lineWidth) override; + virtual void Display() override; + virtual void SetColourScheme(const Dasher::CColourIO::ColourInfo* pColourScheme) override; + virtual bool IsPointVisible(Dasher::screenint x, Dasher::screenint y) override; + virtual bool GetScreenCoords(Dasher::screenint& iX, Dasher::screenint& iY, Dasher::CDasherView* pView) override; + virtual bool MultiSizeFonts() override { return true; } + virtual void SendMarker(int Marker){}; + + + + FVector2D GetCursorPosition(){return CursorPosition;}; + + UPROPERTY(VisibleAnywhere, Category = "Components") UStaticMeshComponent* ActorRootComponent = nullptr; + UPROPERTY(VisibleAnywhere, Category = "Components") UInstancedStaticMeshComponent* CubeInstances = nullptr; + UPROPERTY(VisibleAnywhere, Category = "Components") UInstancedStaticMeshComponent* LetterInstances = nullptr; + UPROPERTY(EditAnywhere) UFont* DisplayFont; + UPROPERTY(EditAnywhere) UMaterial* FontMaterial; + + UFUNCTION(BlueprintCallable) void SetMouseLocation(FVector2D InputVector); + + +private: + + + + // stores color information + const Dasher::CColourIO::ColourInfo* ColorPalette = nullptr; + FVector2D CursorPosition; + FVector2D SlateSize; + FVector DrawingSize = {1000,1000, 100}; // Multiplied with the Scaling of the plane, so actually pixels per meter + TSharedPtr<Dasher::DasherInterface> DasherMainInterface; + UPROPERTY() UMaterialInstanceDynamic* MaterialInstance; + UPROPERTY() UTexture2DArray* TextureArray; + int MaxVSize; + int MaxUSize; + + FVector DefaultTranslation; + std::pair<TArray<FTransform>, TArray<float>> GeometryBufferA; + std::pair<TArray<FTransform>, TArray<float>> GeometryBufferB; + std::pair<TArray<FTransform>, TArray<float>>* BackBuffer = &GeometryBufferA; + std::pair<TArray<FTransform>, TArray<float>>* FrontBuffer = &GeometryBufferB; + + + std::pair<TArray<FTransform>, TArray<TArray<float>>> LabelGeometryBufferA; + std::pair<TArray<FTransform>, TArray<TArray<float>>> LabelGeometryBufferB; + std::pair<TArray<FTransform>, TArray<TArray<float>>>* LabelBackBuffer = &LabelGeometryBufferA; + std::pair<TArray<FTransform>, TArray<TArray<float>>>* LabelFrontBuffer = &LabelGeometryBufferB; + +}; diff --git a/Source/DasherVR/Public/DasherInterface.h b/Source/DasherVR/Public/DasherInterface.h index b7427f2e4032b97ff8fecff814108aab6a60592b..bc2de9c7651949b6664df88755feda0884b8d0a9 100644 --- a/Source/DasherVR/Public/DasherInterface.h +++ b/Source/DasherVR/Public/DasherInterface.h @@ -75,7 +75,7 @@ namespace Dasher void Tick(unsigned long time); // set the screen, needed for maximum spaghetti, to make changeScreen accessible to the outside aka SDasherWidget - virtual void SetScreen(SDasherWidget* screen); + virtual void SetScreen(CDasherScreen* screen); //Sets the Training Filename virtual void ImportTrainingFile(std::string filename); diff --git a/Source/DasherVR/Public/DasherVR.h b/Source/DasherVR/Public/DasherVR.h index 5aa2e2597631e06f77ab8e30ca5af57361e6da16..8a2bcca67e14c89f4d9b16b6196193fb26aa6964 100644 --- a/Source/DasherVR/Public/DasherVR.h +++ b/Source/DasherVR/Public/DasherVR.h @@ -3,6 +3,7 @@ #include "CoreMinimal.h" #include "DasherCoreWrapper.h" +#include "Modules/ModuleInterface.h" class FDasherVRModule : public IModuleInterface { diff --git a/Source/DasherVR/Public/SDasherWidget.h b/Source/DasherVR/Public/SDasherWidget.h index 31c993f819e6d1ddbdea130627718ba11dd8855c..74eac990ba6ce8de6bd73557d60c4b3990ea9ee7 100644 --- a/Source/DasherVR/Public/SDasherWidget.h +++ b/Source/DasherVR/Public/SDasherWidget.h @@ -7,6 +7,7 @@ #include "DasherInterface.h" #include "Math/Vector2D.h" #include "Fonts/FontMeasure.h" +#include "Widgets/DeclarativeSyntaxSupport.h" //using namespace Dasher; @@ -77,9 +78,9 @@ public: // Constructs this widget with InArgs. Needed for every widget. Builds this widget and any of its children void Construct(const FArguments& InArgs); - void SetBoolParamter(FString ParameterName, bool Value); - void SetLongParamter(FString ParameterName, int64 Value); - void SetStringParamter(FString ParameterName, FString Value); + void SetParameter(FString ParameterName, bool Value); + void SetParameter(FString ParameterName, int64 Value); + void SetParameter(FString ParameterName, FString Value); virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; @@ -132,11 +133,16 @@ public: void InputVector(FVector2D InputVector); void InputButton(bool Pressed); FVector2D GetCursorPosition(); + + //Allows to Pause Input + void PauseInput(); + void UnpauseInput(); FDasherMouseUpDelegate MouseUpListeners; FDasherMouseUpDelegate MouseDownListeners; FBufferManiputlationDelegate CharacterEntered; FBufferManiputlationDelegate CharacterDeleted; + FBufferManiputlationDelegate CharacterSwitched; private: @@ -151,9 +157,14 @@ private: bool HasBeenPainted = false; bool CurrentlyUsingVectorInput = false; FVector2D CursorPosition; + bool CharacterEnteredFlag = false; + bool CharacterDeletedFlag = false; + FString AlteredChar = ""; //are we in the Editor? bool IsEditor = true; + //is the input paused + bool InputPaused = false; //set up the font measure service to ... measure fonts. TSharedPtr<FSlateFontMeasure> FontMeasureService; diff --git a/Source/DasherVR/Public/UDasherWidget.h b/Source/DasherVR/Public/UDasherWidget.h index ae0cb7aecbcd3251e6438442002f72955648f02d..849b3f18dd56781b6d47fd2534552aae1ac997cb 100644 --- a/Source/DasherVR/Public/UDasherWidget.h +++ b/Source/DasherVR/Public/UDasherWidget.h @@ -40,8 +40,12 @@ public: UFUNCTION(BlueprintCallable) void InputButton(bool Pressed); UFUNCTION(BlueprintCallable) void InputVector(FVector2D InputVector); + UFUNCTION(BlueprintCallable) void PauseInput(); + UFUNCTION(BlueprintCallable) void UnpauseInput(); + UPROPERTY(BlueprintAssignable) FCharManipulatedEvent CharacterEntered; UPROPERTY(BlueprintAssignable) FCharManipulatedEvent CharacterDeleted; + UPROPERTY(BlueprintAssignable) FCharManipulatedEvent CharacterSwitched; UPROPERTY(BlueprintAssignable) FBufferManipulatedEvent BufferAltered; UPROPERTY(BlueprintAssignable) FMouseEvent MouseEvent; diff --git a/Source/DasherVR/Public/pch_plugin.h b/Source/DasherVR/Public/pch_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..6f70f09beec2219624baeca92e2cd7deaa104fb4 --- /dev/null +++ b/Source/DasherVR/Public/pch_plugin.h @@ -0,0 +1 @@ +#pragma once