diff --git a/DasherVR.uplugin b/DasherVR.uplugin index 5697244bb824b2d5ab7d1092a8b3ac431876bb83..b36b042eda04d4b521a7fd80db5a18e0e7f11ad7 100644 --- a/DasherVR.uplugin +++ b/DasherVR.uplugin @@ -20,5 +20,15 @@ "Type": "Runtime", "LoadingPhase": "PreDefault" } + ], + "Plugins": [ + { + "Name": "nDisplay", + "Enabled": true + }, + { + "Name": "RWTHVRToolkit", + "Enabled": true + } ] } diff --git a/Source/DasherVR/DasherVR.Build.cs b/Source/DasherVR/DasherVR.Build.cs index b1cd040debb4fc13a1c73e8acbbf980e8b524e4f..bf038bb08991a927c5ae61bfe0a2ecadc83a9817 100644 --- a/Source/DasherVR/DasherVR.Build.cs +++ b/Source/DasherVR/DasherVR.Build.cs @@ -42,7 +42,9 @@ public class DasherVR : ModuleRules "Slate", "SlateCore", "UMG", - "RenderCore" + "RenderCore", + "DisplayCluster", + "RWTHVRToolkit" // ... add private dependencies that you statically link with here ... } ); diff --git a/Source/DasherVR/Private/SDasherWidget.cpp b/Source/DasherVR/Private/SDasherWidget.cpp index 255d07b34c576cde7e033bac5136d116a26118ae..25c546ec9feacecd0eb39f40d1ca0d4a4fff468d 100644 --- a/Source/DasherVR/Private/SDasherWidget.cpp +++ b/Source/DasherVR/Private/SDasherWidget.cpp @@ -5,8 +5,15 @@ #include "Rendering/DrawElements.h" #include "DasherInterface.h" +#include "IDisplayCluster.h" +#include "Cluster/DisplayClusterClusterEvent.h" +#include "Cluster/IDisplayClusterClusterManager.h" + #include "Components/SlateWrapperTypes.h" #include "Framework/Application/SlateApplication.h" +#include "Serialization/BufferArchive.h" +#include "Serialization/BufferWriter.h" +#include "Utility/RWTHVRUtilities.h" BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION @@ -17,16 +24,18 @@ 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() { + if (!URWTHVRUtilities::IsPrimaryNode()) return; InputPaused = true; } //Unpause the input void SDasherWidget::UnpauseInput() { + if (!URWTHVRUtilities::IsPrimaryNode()) return; InputPaused = false; } @@ -45,17 +54,17 @@ FReply SDasherWidget::HandleMouseMoveEvent(const FGeometry& Geometry, const FPoi FReply SDasherWidget::HandleMouseDownEvent(const FGeometry& Geometry, const FPointerEvent& MouseEvent) { - if (!InputPaused) - { - if (CurrentlyUsingVectorInput) + if (!InputPaused) { - CurrentlyUsingVectorInput = false; - return FReply::Handled().LockMouseToWidget(AsShared()); + if (CurrentlyUsingVectorInput) + { + CurrentlyUsingVectorInput = false; + return FReply::Handled().LockMouseToWidget(AsShared()); + } + DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), Dasher::Keys::Primary_Input); + MouseDownListeners.ExecuteIfBound(); } - DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), Dasher::Keys::Primary_Input); - MouseDownListeners.ExecuteIfBound(); - } - return FReply::Handled().LockMouseToWidget(AsShared()); + return FReply::Handled().LockMouseToWidget(AsShared()); } FReply SDasherWidget::HandleMouseUpEvent(const FGeometry& Geometry, const FPointerEvent& MouseEvent) @@ -82,28 +91,29 @@ FReply SDasherWidget::HandleMouseDoubleClickEvent(const FGeometry& Geometry, con } DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), Dasher::Keys::Primary_Input); } - return FReply::Handled(); + 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 (!URWTHVRUtilities::IsPrimaryNode()) return; if (!InputPaused) { if (!CurrentlyUsingVectorInput) return; CursorPosition = DasherMainInterface->ConvertDasher2Screen(Dasher::CDasherModel::ORIGIN_X, Dasher::CDasherModel::ORIGIN_Y) @@ -113,6 +123,7 @@ void SDasherWidget::InputVector(const FVector2D InputVector) void SDasherWidget::InputButton(bool Pressed) { + if (!URWTHVRUtilities::IsPrimaryNode()) return; if (!InputPaused) { CurrentlyUsingVectorInput = true; if (Pressed) @@ -125,219 +136,273 @@ void SDasherWidget::InputButton(bool Pressed) } } +void SDasherWidget::HandleClusterEvent(const FDisplayClusterClusterEventBinary& Event) +{ + if(!URWTHVRUtilities::IsPrimaryNode()) UE_LOG(LogTemp, Log, TEXT("Non Primary Receive")); + + FMemoryReader r(Event.EventData); + + BackBuffer->Empty(); + + r << NDisplayBuffer; + + GeometryType t; + bool readError = false; + while(!r.AtEnd() && !readError) + { + r << t; + switch (t) + { + case GeometryType::Rectangle: + BackBuffer->Add(FFilledRect::Deserialize(r)); + break; + case GeometryType::Writing: + BackBuffer->Add(FWriting::Deserialize(r)); + break; + case GeometryType::PolyLine: + BackBuffer->Add(FPolyLine::Deserialize(r)); + break; + default: + readError = true; + break; + } + } + + std::swap(FrontBuffer, BackBuffer); + BackBuffer->Empty(); +} + //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); - - //initialize the font measuring service. - FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService(); - - //Setting up Dasher - static Dasher::XMLErrorDisplay display; - Dasher::XmlSettingsStore* Settings = new Dasher::XmlSettingsStore("Settings.xml", &display); //Gets deleted somewhere else - Settings->Load(); - Settings->Save(); - DasherMainInterface = MakeShared<Dasher::DasherInterface>(Settings); - DasherMainInterface->GetModuleManager()->RegisterInputDeviceModule(this, true); - - DasherMainInterface->SetScreen(this); - DasherMainInterface->SetBuffer(0); - - 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. - //You could add Slate Code here for child slots etc. +{ + //Initial resize, needed for setup + Width = InArgs._width; + Height = InArgs._height; + resize(Width, Height); + + //initialize the font measuring service. + FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService(); + + //Setting up Dasher + static Dasher::XMLErrorDisplay display; + Dasher::XmlSettingsStore* Settings = new Dasher::XmlSettingsStore("Settings.xml", &display); //Gets deleted somewhere else + Settings->Load(); + Settings->Save(); + DasherMainInterface = MakeShared<Dasher::DasherInterface>(Settings); + DasherMainInterface->GetModuleManager()->RegisterInputDeviceModule(this, true); + + DasherMainInterface->SetScreen(this); + DasherMainInterface->SetBuffer(0); + + DasherMainInterface->SetCharEnteredCallback([this](FString Char, FString Buffer) {CharacterEnteredFlag = true; AlteredChar = Char; }); + DasherMainInterface->SetCharDeletedCallback([this](FString Char, FString Buffer) {CharacterDeletedFlag = true; AlteredChar = Char; }); + + // Bind the cluster events that manage the door state. + IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr(); + if (ClusterManager && !ClusterEvent.IsBound()) + { + ClusterEvent = + FOnClusterEventBinaryListener::CreateSP(this, &SDasherWidget::HandleClusterEvent); + ClusterManager->AddClusterEventBinaryListener(ClusterEvent); + } + + //Set up the Event Handlers for Mouse Movement etc. + if (URWTHVRUtilities::IsPrimaryNode()) + { + 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. + } } -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::SetParameter(FString& ParameterName, bool Value) { + DasherMainInterface->SetBoolParameter(Dasher::Settings::GetParameter(TCHAR_TO_UTF8(*ParameterName)).first, Value); } -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::SetParameter(FString& ParameterName, int64 Value) { + DasherMainInterface->SetLongParameter(Dasher::Settings::GetParameter(TCHAR_TO_UTF8(*ParameterName)).first, Value); } -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; - } +void SDasherWidget::SetParameter(FString& ParameterName, FString Value) { + DasherMainInterface->SetStringParameter(Dasher::Settings::GetParameter(TCHAR_TO_UTF8(*ParameterName)).first, TCHAR_TO_UTF8(*Value)); } //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())); + //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 GeometryType::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 GeometryType::Writing: + WritingObject = static_cast<FWriting*>(GeneralObject.Get()); 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, LineObject->AntiAliasing, LineObject->linewidth); - break; - default: break; + FSlateDrawElement::MakeText(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(FSlateLayoutTransform(1, FVector2D(WritingObject->pos.X, WritingObject->pos.Y))), WritingObject->label, Font, ESlateDrawEffect::None, WritingObject->color); + break; + case GeometryType::PolyLine: + LineObject = static_cast<FPolyLine*>(GeneralObject.Get()); + FSlateDrawElement::MakeLines(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(), LineObject->points, ESlateDrawEffect::None, LineObject->color, LineObject->AntiAliasing, LineObject->linewidth); + break; + default: break; + } } - } - return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); //call the parent onPaint + 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 && !InputPaused) { - SCompoundWidget::Tick(AllotedGeometry, InCurrentTime, InDeltaTime); + //don't tick in the editor + if (!IsEditor && !InputPaused && URWTHVRUtilities::IsPrimaryNode()) { + 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(); - - 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; + + if (URWTHVRUtilities::IsRoomMountedMode()) + { + auto start = std::chrono::high_resolution_clock::now(); + FDisplayClusterClusterEventBinary BinaryClusterEvent; + BinaryClusterEvent.EventData.Reserve(100000); // 100kb of data + FMemoryWriter m(BinaryClusterEvent.EventData); + + m << NDisplayBuffer; + + for(auto& e : *BackBuffer) + { + e->Serialize(m); + } + + IDisplayCluster::Get().GetClusterMgr()->EmitClusterEventBinary(BinaryClusterEvent, false); + } + else + { + 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, const Dasher::ColorPalette::Color& color, const Dasher::ColorPalette::Color& outlineColor, int iThickness) { - if(outlineColor == Dasher::ColorPalette::noColor) iThickness = 0; // Draw till brim if no outline color is given + if (outlineColor == Dasher::ColorPalette::noColor) iThickness = 0; // Draw till brim if no outline color is given - if(color != Dasher::ColorPalette::noColor && !color.isFullyTransparent()) - { - BackBuffer->Add(MakeUnique<FFilledRect>(FVector2D(x1 + iThickness, y1 + iThickness), FVector2D(x2 - iThickness, y2 - iThickness), FLinearColor(color.Red / 255.0f, color.Green / 255.0f, color.Blue / 255.0f, color.Alpha / 255.0f))); - } + if (color != Dasher::ColorPalette::noColor && !color.isFullyTransparent()) + { + BackBuffer->Add(MakeUnique<FFilledRect>(FVector2D(x1 + iThickness, y1 + iThickness), FVector2D(x2 - iThickness, y2 - iThickness), FLinearColor(color.Red / 255.0f, color.Green / 255.0f, color.Blue / 255.0f, color.Alpha / 255.0f))); + } - if (iThickness && outlineColor != Dasher::ColorPalette::noColor && !outlineColor.isFullyTransparent()) - { + if (iThickness && outlineColor != Dasher::ColorPalette::noColor && !outlineColor.isFullyTransparent()) + { const float hThickness = iThickness / 2.0f; - const FVector2D CornerMin = FVector2D(x1 + hThickness, y1 + hThickness); - const FVector2D CornerMax = FVector2D(x2 - hThickness, y2 - hThickness); + const FVector2D CornerMin = FVector2D(x1 + hThickness, y1 + hThickness); + const FVector2D CornerMax = FVector2D(x2 - hThickness, y2 - hThickness); const FLinearColor oColor = FLinearColor(outlineColor.Red / 255.0, outlineColor.Green / 255.0, outlineColor.Blue / 255.0, outlineColor.Alpha / 255.0f); - BackBuffer->Add(MakeUnique<FPolyLine>(TArray({FVector2D(CornerMin.X, CornerMin.Y - hThickness),FVector2D(CornerMin.X, CornerMax.Y + hThickness)}), static_cast<float>(iThickness), oColor, false)); - BackBuffer->Add(MakeUnique<FPolyLine>(TArray({FVector2D(CornerMin.X - hThickness, CornerMax.Y),FVector2D(CornerMax.X + hThickness, CornerMax.Y)}), static_cast<float>(iThickness), oColor, false)); - BackBuffer->Add(MakeUnique<FPolyLine>(TArray({FVector2D(CornerMax.X, CornerMax.Y + hThickness),FVector2D(CornerMax.X, CornerMin.Y - hThickness)}), static_cast<float>(iThickness), oColor, false)); - BackBuffer->Add(MakeUnique<FPolyLine>(TArray({FVector2D(CornerMax.X + hThickness, CornerMin.Y),FVector2D(CornerMin.X - hThickness, CornerMin.Y)}), static_cast<float>(iThickness), oColor, false)); - } + BackBuffer->Add(MakeUnique<FPolyLine>(TArray({ FVector2D(CornerMin.X, CornerMin.Y - hThickness),FVector2D(CornerMin.X, CornerMax.Y + hThickness) }), static_cast<float>(iThickness), oColor, false)); + BackBuffer->Add(MakeUnique<FPolyLine>(TArray({ FVector2D(CornerMin.X - hThickness, CornerMax.Y),FVector2D(CornerMax.X + hThickness, CornerMax.Y) }), static_cast<float>(iThickness), oColor, false)); + BackBuffer->Add(MakeUnique<FPolyLine>(TArray({ FVector2D(CornerMax.X, CornerMax.Y + hThickness),FVector2D(CornerMax.X, CornerMin.Y - hThickness) }), static_cast<float>(iThickness), oColor, false)); + BackBuffer->Add(MakeUnique<FPolyLine>(TArray({ FVector2D(CornerMax.X + hThickness, CornerMin.Y),FVector2D(CornerMin.X - hThickness, CornerMin.Y) }), static_cast<float>(iThickness), oColor, false)); + } } void SDasherWidget::DrawString(CDasherScreen::Label* lab, screenint x1, screenint y1, unsigned int iSize, const Dasher::ColorPalette::Color& color) { - BackBuffer->Add(MakeUnique<FWriting>(lab, FVector2D(x1, y1), static_cast<int>(iSize), FLinearColor(color.Red / 255.0, color.Green / 255.0, color.Blue / 255.0, color.Alpha / 255.0f))); + BackBuffer->Add(MakeUnique<FWriting>(UTF8_TO_TCHAR(lab->m_strText.c_str()), FVector2D(x1, y1), static_cast<int>(iSize), FLinearColor(color.Red / 255.0, color.Green / 255.0, color.Blue / 255.0, color.Alpha / 255.0f))); } void SDasherWidget::Polyline(CDasherScreen::point* points, int number, int iwidth, const Dasher::ColorPalette::Color& color) { - 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), FLinearColor(color.Red / 255.0, color.Green / 255.0, color.Blue / 255.0, color.Alpha / 255.0f), true)); + 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), FLinearColor(color.Red / 255.0, color.Green / 255.0, color.Blue / 255.0, color.Alpha / 255.0f), true)); } //techincally polygons are just multiple polylines. Dasher doesn't actually draw polygons in our case. void SDasherWidget::Polygon(CDasherScreen::point* points, int number, const Dasher::ColorPalette::Color& fillcolor, const Dasher::ColorPalette::Color& outlinecolor, int iwidth) { - 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), FLinearColor(outlinecolor.Red / 255.0, outlinecolor.Green / 255.0, outlinecolor.Blue / 255.0, outlinecolor.Alpha / 255.0), true)); + 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), FLinearColor(outlinecolor.Red / 255.0, outlinecolor.Green / 255.0, outlinecolor.Blue / 255.0, outlinecolor.Alpha / 255.0), true)); } //We pass through the contents of the dasher buffer FString SDasherWidget::GetBuffer() const { - return DasherMainInterface->GetBuffer(); + return (URWTHVRUtilities::IsPrimaryNode()) ? DasherMainInterface->GetBuffer() : NDisplayBuffer; } void SDasherWidget::ResetBuffer() { - DasherMainInterface->ResetBuffer(); + DasherMainInterface->ResetBuffer(); + NDisplayBuffer = ""; } 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/Public/SDasherWidget.h b/Source/DasherVR/Public/SDasherWidget.h index ead5b120b45b995fbc2ea9b333dcb94f63164ebd..765919e21de9c86df68f60ae8d861ae5d4a6ab46 100644 --- a/Source/DasherVR/Public/SDasherWidget.h +++ b/Source/DasherVR/Public/SDasherWidget.h @@ -5,21 +5,22 @@ #include <utility> #include "DasherInterface.h" +#include "Cluster/DisplayClusterClusterEvent.h" #include "Math/Vector2D.h" #include "Fonts/FontMeasure.h" #include "Widgets/DeclarativeSyntaxSupport.h" -//using namespace Dasher; - +#include "Cluster/IDisplayClusterClusterManager.h" +//using namespace Dasher; //Structs to hold the elements making up the UI -enum GeometryType +enum class GeometryType : uint8 { - Rectangle, - Writing, - PolyLine + Rectangle = 0, + Writing = 1, + PolyLine = 2 }; struct DasherDrawGeometry @@ -27,23 +28,60 @@ struct DasherDrawGeometry GeometryType Type; DasherDrawGeometry(GeometryType Type) : Type(Type) {} virtual ~DasherDrawGeometry() {}; + + virtual void Serialize(FMemoryWriter& ar) = 0; }; -struct FFilledRect : DasherDrawGeometry{ +struct FFilledRect : DasherDrawGeometry { FVector2D top; FVector2D bottom; FLinearColor color; - - FFilledRect(FVector2D Top, FVector2D Bottom, FLinearColor Color) : DasherDrawGeometry(Rectangle), top(Top), bottom(Bottom), color(Color) {} + void Serialize(FMemoryWriter& ar) + { + ar << Type; + ar << top; + ar << bottom; + ar << color; + } + static TUniquePtr<DasherDrawGeometry> Deserialize(FMemoryReader& ar) + { + TUniquePtr<FFilledRect> g = MakeUnique<FFilledRect>(); + ar << g->top; + ar << g->bottom; + ar << g->color; + return g; + } + + FFilledRect(FVector2D Top, FVector2D Bottom, FLinearColor Color) : DasherDrawGeometry(GeometryType::Rectangle), top(Top), bottom(Bottom), color(Color) {} + FFilledRect() : DasherDrawGeometry(GeometryType::Rectangle) {} }; struct FWriting : DasherDrawGeometry{ - Dasher::CDasherScreen::Label *label; + FString label; FVector2D pos; int size; FLinearColor color; - FWriting(Dasher::CDasherScreen::Label *Label, FVector2D Pos, int Size, FLinearColor Color) : DasherDrawGeometry(Writing), label(Label), pos(Pos), size(Size), color(Color) {} + void Serialize(FMemoryWriter& ar) + { + ar << Type; + ar << pos; + ar << size; + ar << color; + ar << label; + } + static TUniquePtr<DasherDrawGeometry> Deserialize(FMemoryReader& ar) + { + TUniquePtr<FWriting> g = MakeUnique<FWriting>(); + ar << g->pos; + ar << g->size; + ar << g->color; + ar << g->label; + return g; + } + + FWriting(FString Label, FVector2D Pos, int Size, FLinearColor Color) : DasherDrawGeometry(GeometryType::Writing), label(Label), pos(Pos), size(Size), color(Color) {} + FWriting() : DasherDrawGeometry(GeometryType::Writing) {} }; struct FPolyLine : DasherDrawGeometry{ @@ -52,7 +90,26 @@ struct FPolyLine : DasherDrawGeometry{ bool AntiAliasing; FLinearColor color; - FPolyLine(TArray<FVector2D> Points, float LineWidth, FLinearColor Color, bool AntiAliasing): DasherDrawGeometry(PolyLine), points(Points), linewidth(LineWidth), AntiAliasing(AntiAliasing), color(Color) {} + void Serialize(FMemoryWriter& ar) + { + ar << Type; + ar << points; + ar << linewidth; + ar << AntiAliasing; + ar << color; + } + static TUniquePtr<DasherDrawGeometry> Deserialize(FMemoryReader& ar) + { + TUniquePtr<FPolyLine> g = MakeUnique<FPolyLine>(); + ar << g->points; + ar << g->linewidth; + ar << g->AntiAliasing; + ar << g->color; + return g; + } + + FPolyLine(TArray<FVector2D> Points, float LineWidth, FLinearColor Color, bool AntiAliasing): DasherDrawGeometry(GeometryType::PolyLine), points(Points), linewidth(LineWidth), AntiAliasing(AntiAliasing), color(Color) {} + FPolyLine(): DasherDrawGeometry(GeometryType::PolyLine) {} }; DECLARE_DELEGATE(FDasherMouseUpDelegate); @@ -79,9 +136,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 SetParameter(FString ParameterName, bool Value); - void SetParameter(FString ParameterName, int64 Value); - void SetParameter(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; @@ -129,6 +186,7 @@ public: void InputVector(FVector2D InputVector); void InputButton(bool Pressed); + void HandleClusterEvent(const FDisplayClusterClusterEventBinary& Event); FVector2D GetCursorPosition(); //Allows to Pause Input @@ -166,6 +224,10 @@ private: //set up the font measure service to ... measure fonts. TSharedPtr<FSlateFontMeasure> FontMeasureService; +private: + FString NDisplayBuffer = ""; + FOnClusterEventBinaryListener ClusterEvent; + protected: // stores color information TSharedPtr<Dasher::DasherInterface> DasherMainInterface; diff --git a/Source/Thirdparty/CMakeLists.txt b/Source/Thirdparty/CMakeLists.txt index 4c001d32bb46711687653f3ba04b89fd51750962..4d2f8bc7d3a4fadaa50b4a6126eb3a809e1390cf 100644 --- a/Source/Thirdparty/CMakeLists.txt +++ b/Source/Thirdparty/CMakeLists.txt @@ -18,7 +18,7 @@ project("DasherLib") ############################################################################################################ # Set this to your libc++ path included with Unreal ############################################################################################################ -set(LIBC_PATH "/home/unreal/UE4_Build_426/Engine/Source/ThirdParty/Linux/LibCxx/") +set(LIBC_PATH "/home/ue4/UnrealEngine/Engine/Source/ThirdParty/Unix/LibCxx/") if (UNIX) @@ -28,9 +28,9 @@ if (UNIX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) - add_compile_definitions(HAVE_ROUND XML_STATIC _CRT_SECURE_NO_WARNINGS HAVE_OWN_FILEUTILS HAVE_OWN_FILELOGGER) + add_compile_definitions(HAVE_ROUND XML_STATIC _CRT_SECURE_NO_WARNINGS HAVE_OWN_FILEUTILS HAVE_OWN_FILELOGGER PUGIXML_NO_EXCEPTIONS) set(CMAKE_SUPPRESS_REGENERATION true) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++17 -stdlib=libc++ -nostdinc++ -I${LIBC_PATH}include/c++/v1 -L${LIBC_PATH}lib -Wl -rpath ${LIBC_PATH}lib") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++17 -nostdinc++ -I${LIBC_PATH}include/c++/v1 -L${LIBC_PATH}lib ${LIBC_PATH}lib") set(CMAKE_EXE_LINKER_FLAGS "-stdlib=libc++") diff --git a/Source/Thirdparty/Dasher/DasherCore b/Source/Thirdparty/Dasher/DasherCore index a4df257624722cae45b8d9dd5d14dea8ce1dc4a5..0f0d1953f3ff1d4c20a1387d4bde2ede3b86f254 160000 --- a/Source/Thirdparty/Dasher/DasherCore +++ b/Source/Thirdparty/Dasher/DasherCore @@ -1 +1 @@ -Subproject commit a4df257624722cae45b8d9dd5d14dea8ce1dc4a5 +Subproject commit 0f0d1953f3ff1d4c20a1387d4bde2ede3b86f254 diff --git a/Source/Thirdparty/Dasher/Lib/DasherCore.a b/Source/Thirdparty/Dasher/Lib/DasherCore.a new file mode 100644 index 0000000000000000000000000000000000000000..00410eed404cdbd6929169e1a7c3eedba2c9a311 Binary files /dev/null and b/Source/Thirdparty/Dasher/Lib/DasherCore.a differ