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

Removing 3D Version as TextureArray2D is not supported outside of the editor

parent 1c1c21b5
Branches
No related tags found
1 merge request!2Backporting many features from the study on top of the Dasher3D-Core
// Fill out your copyright notice in the Description page of Project Settings.
#include "Dasher3DWidget.h"
#include "Math/Rotator.h"
#include "Engine/Texture2DArray.h"
#include "Engine/World.h"
#include "GameFramework/WorldSettings.h"
#include "Materials/MaterialInstanceDynamic.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");
ActorRootComponent->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
SetRootComponent(ActorRootComponent);
CubeInstances = CreateDefaultSubobject<UInstancedStaticMeshComponent>("Cubes");
CubeInstances->SetupAttachment(GetRootComponent());
CubeInstances->SetFlags(RF_Transactional);
CubeInstances->NumCustomDataFloats = 7; //Color(3), Scale(3), LineWidth(1)
CubeInstances->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
this->AddInstanceComponent(CubeInstances);
LetterInstances = CreateDefaultSubobject<UInstancedStaticMeshComponent>("Letters");
LetterInstances->SetupAttachment(GetRootComponent());
LetterInstances->SetFlags(RF_Transactional);
LetterInstances->NumCustomDataFloats = 5; //UV(2), Size(2), TexturePage(1)
LetterInstances->SetCollisionResponseToAllChannels(ECR_Ignore);
this->AddInstanceComponent(LetterInstances);
}
void ADasher3DWidget::PostInitializeComponents()
{
Super::PostInitializeComponents();
CubeMaterialInstanceDynamic = UMaterialInstanceDynamic::Create(CubeInstances->GetMaterial(0), CubeInstances);
CubeInstances->SetMaterial(0, CubeMaterialInstanceDynamic);
LetterMaterialInstanceDynamic = UMaterialInstanceDynamic::Create(LetterInstances->GetMaterial(0), LetterInstances);
LetterInstances->SetMaterial(0, LetterMaterialInstanceDynamic);
}
// 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();
WorldToMeters = GetWorld()->GetWorldSettings()->WorldToMeters;
CubeMaterialInstanceDynamic->SetVectorParameterValue("DrawingSizeBorderWidth", FVector(DrawingSize, 0));
}
// 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
}
std::pair<Dasher::screenint, Dasher::screenint> ADasher3DWidget::TextSize(Label* label, unsigned iFontSize)
{
FString labelText = UTF8_TO_TCHAR(label->m_strText.c_str());
TCHAR CurrentChar = labelText[0];
if (CurrentChar < 32) CurrentChar = 32; // replace non-printable characters with spaces.
CurrentChar = DisplayFont->RemapChar(CurrentChar);
const float FontScale = iFontSize / DisplayFont->ImportOptions.Height;
const float CharacterSizeU = DisplayFont->Characters[CurrentChar].USize; // Pixel Sizes for actual character without blank space
const float CharacterSizeV = DisplayFont->Characters[CurrentChar].VSize; // Pixel Sizes for actual character without blank space
const float CharacterVerticalOffset = DisplayFont->Characters[CurrentChar].VerticalOffset;
const FVector2D CharScale = FVector2D(
(CharacterSizeU / CharacterSizeV) * CharacterSizeV, // (Width/Height * Height)
CharacterSizeV + CharacterVerticalOffset // Height + Vertical Offset, as the vertical offset also counts towards the height for line-height calculations
) * FontScale;
return {CharScale.X, CharScale.Y};
}
void ADasher3DWidget::DrawString(Label* label, Dasher::screenint x, Dasher::screenint y, unsigned iFontSize, const Dasher::ColorPalette::Color& color){}
void ADasher3DWidget::DrawCube(Dasher::screenint posX, Dasher::screenint posY, Dasher::screenint sizeX, Dasher::screenint sizeY, Dasher::myint extrusionLevel, Dasher::myint groupRecursionDepth, const Dasher::ColorPalette::Color& color, const Dasher::ColorPalette::Color& outlineColor, int iThickness) {
if (sizeX == 0 || sizeY == 0) return;
const FVector Scale = FVector(FVector2D(sizeX, sizeY) / DrawingSize,
FMath::Max(ExtrusionLevelToHeight(extrusionLevel), 0.001) + groupRecursionDepth*0.001) // Min Depth 1mm
+ FVector(extrusionLevel,extrusionLevel,0)*FLT_EPSILON;
const FVector2D Translation = FVector2D(posX, posY) / DrawingSize - FVector2D(0.5f, 0.5f);
const FLinearColor RectColor = FLinearColor(color.Red / 255.0, color.Green / 255.0, color.Blue / 255.0, color.Alpha / 255.0);
BackBuffer->first.Add(FTransform(FQuat::Identity, FVector(Translation, 0) * WorldToMeters, 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);
BackBuffer->second.Add(0.5f * iThickness * (outlineColor.isFullyTransparent() ? 0.0f : 1.0f)); //Allows for individual adjustment
}
// x & y are given as upper left corner of the character
void ADasher3DWidget::Draw3DLabel(Label* label, Dasher::screenint x, Dasher::screenint y, Dasher::myint extrusionLevel, Dasher::myint groupRecursionDepth, unsigned int iFontSize, const Dasher::ColorPalette::Color& color) {
float CharacterOffset = 0; // in Meters
if(LabelBackBuffer->first.Max() < LabelBackBuffer->first.Num() + label->m_strText.length()) LabelBackBuffer->first.Reserve(LabelBackBuffer->first.Num() + label->m_strText.length());
if(LabelBackBuffer->second.Max() < LabelBackBuffer->second.Num() + label->m_strText.length()) LabelBackBuffer->second.Reserve(LabelBackBuffer->second.Num() + label->m_strText.length());
FString labelText = UTF8_TO_TCHAR(label->m_strText.c_str());
for (int i = 0; i < labelText.Len(); i++)
{
TCHAR CurrentChar = labelText[i];
if (CurrentChar < 32) CurrentChar = 32; // replace non-printable characters with spaces.
const TCHAR RemappedChar = DisplayFont->RemapChar(CurrentChar);
const int TextureIndex = DisplayFont->Characters[RemappedChar].TextureIndex;
const float FontScale = iFontSize / DisplayFont->ImportOptions.Height;
const float TextureSizeU = DisplayFont->Textures[TextureIndex]->GetSizeX(); // Pixel Sizes
const float TextureSizeV = DisplayFont->Textures[TextureIndex]->GetSizeY(); // Pixel Sizes
const float CharacterOffsetU = DisplayFont->Characters[RemappedChar].StartU; //Upper left corner
const float CharacterOffsetV = DisplayFont->Characters[RemappedChar].StartV; //Upper left corner
const float CharacterSizeU = DisplayFont->Characters[RemappedChar].USize; // Pixel Sizes for actual character without blank space
const float CharacterSizeV = DisplayFont->Characters[RemappedChar].VSize; // Pixel Sizes for actual character without blank space
const float CharacterVerticalOffset = DisplayFont->Characters[RemappedChar].VerticalOffset * FontScale; //vertical offset in pixels
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
};
const FVector2D CharScale = FVector2D(
(CharacterSizeU / CharacterSizeV) * CharacterSizeV, // (Width/Height * Height)
CharacterSizeV // Height
) * FontScale / DrawingSize; // From Pixel to "Meter" (afterwards scaled by parent)
const FVector CharTranslation = FVector(
(x / DrawingSize.X + CharScale.X * 0.5f) * WorldToMeters + CharacterOffset,
((y + CharacterVerticalOffset) / DrawingSize.Y) * WorldToMeters,
(FMath::Max(ExtrusionLevelToHeight(extrusionLevel), 0.001) + groupRecursionDepth*0.001) * WorldToMeters + 0.05f
)
- FVector(0.5f, 0.5f, 0) * WorldToMeters; // Move to upper left corner of parent
LabelBackBuffer->first.Add(FTransform(FQuat::Identity, CharTranslation, FVector(CharScale, 1.0f)));
LabelBackBuffer->second.Add(FontData);
CharacterOffset += CharScale.X * WorldToMeters; // characterOffset is accumulated for multiple character strings
}
}
void ADasher3DWidget::FinishRender3D(Dasher::myint originX, Dasher::myint originY, Dasher::myint originExtrusionLevel)
{
Origin = FVector(originX / DrawingSize.X, originY / DrawingSize.Y, 0) * WorldToMeters;
CubeInstances->SetRelativeLocation({0,0,-ExtrusionLevelToHeight(originExtrusionLevel) * WorldToMeters});
LetterInstances->SetRelativeLocation({0,0,-ExtrusionLevelToHeight(originExtrusionLevel) * WorldToMeters});
}
void ADasher3DWidget::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)
{
DrawCube((x2 - x1)/2 + x1, (y2-y1)/2 + y1, x2-x1, y2-y1, 1, 0, color, outlineColor, iThickness);
}
void ADasher3DWidget::DrawCircle(Dasher::screenint iCX, Dasher::screenint iCY, Dasher::screenint iR, const Dasher::ColorPalette::Color& fillColor, const Dasher::ColorPalette::Color& lineColor, int iLineWidth)
{
//Todo
}
void ADasher3DWidget::Polyline(point* Points, int Number, int iWidth, const Dasher::ColorPalette::Color& color)
{
for(int i = 1; i < Number; i++)
{
const point& p1 = Points[i-1];
const point& p2 = Points[i];
const FVector Scale = FVector(FVector2D(sqrt(powf(p1.x - p2.x, 2)+powf(p1.y - p2.y, 2)), iWidth) / DrawingSize, ExtrusionLevelToHeight(2));
const FVector2D Translation = FVector2D((p2.x - p1.x)/2.0f + p1.x, (p2.y - p1.y)/2.0f + p1.y) / DrawingSize - FVector2D(0.5f, 0.5f);
const FQuat Rotation = FQuat().MakeFromEuler({0,0,FMath::RadiansToDegrees(FMath::Atan2(static_cast<float>(p2.y - p1.y), static_cast<float>(p2.x - p1.x)))});
const FLinearColor RectColor = FLinearColor(color.Red / 255.0, color.Green / 255.0, color.Blue / 255.0, color.Alpha / 255.0);
BackBuffer->first.Add(FTransform(Rotation, FVector(Translation, 0) * WorldToMeters, 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);
BackBuffer->second.Add(0);
}
}
void ADasher3DWidget::Polygon(point* Points, int Number, const Dasher::ColorPalette::Color& fillColor, const Dasher::ColorPalette::Color& outlineColor, 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],
FrontBuffer->second[i*CubeInstances->NumCustomDataFloats+6]
};
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);
}
//Events:
const FString Buffer = DasherMainInterface->GetBuffer();
if (CharacterEnteredFlag && CharacterDeletedFlag) {
CharacterSwitched(AlteredChar, Buffer);
BufferAltered(Buffer);
}
else if (CharacterEnteredFlag) {
CharacterEntered(AlteredChar, Buffer);
BufferAltered(Buffer);
}
else if (CharacterDeletedFlag) {
CharacterDeleted(AlteredChar, Buffer);
BufferAltered(Buffer);
}
CharacterEnteredFlag = false;
CharacterDeletedFlag = false;
}
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(FVector WorldLocation)
{
MousePos = ActorRootComponent->GetComponentToWorld().InverseTransformPosition(WorldLocation) + FVector(0.5f,0.5f,0) * WorldToMeters;
CursorPosition = FVector2D(MousePos) / WorldToMeters * DrawingSize; //convert to pixels
}
void ADasher3DWidget::SimulateClick(FKey Key, bool pressed)
{
if(!(Key == EKeys::LeftMouseButton || Key == EKeys::RightMouseButton)) return;
if(pressed)
{
DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), (Key == EKeys::LeftMouseButton) ? Dasher::Keys::Primary_Input : Dasher::Keys::Secondary_Input);
}
else
{
DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), (Key == EKeys::LeftMouseButton) ? Dasher::Keys::Primary_Input : Dasher::Keys::Secondary_Input);
}
}
void ADasher3DWidget::InitializeTextureArray()
{
TextureArray = NewObject<UTexture2DArray>();
for (int i = 0; i < DisplayFont->Textures.Num(); i++)
{
TextureArray->SourceTextures.Add(DisplayFont->Textures[i]);
}
TextureArray->UpdateSourceFromSourceTextures(true);
LetterMaterialInstanceDynamic->SetTextureParameterValue("TextureArray", TextureArray);
}
float ADasher3DWidget::ExtrusionLevelToHeight(float level)
{
return level*DepthScale;
}
void ADasher3DWidget::InitializeDasher() {
resize(DrawingSize.X, DrawingSize.Y);
static Dasher::XMLErrorDisplay display;
Dasher::XmlSettingsStore* Settings = new Dasher::XmlSettingsStore("Settings3D.xml"/*, &fileUtils*/, &display); //Gets deleted somewhere else
Settings->Load();
Settings->Save();
DasherMainInterface = MakeShared<Dasher::DasherInterface>(Settings);
DasherMainInterface->GetModuleManager()->RegisterInputDeviceModule(this, true);
DasherMainInterface->SetCharEnteredCallback([this](FString Char, FString Buffer) {CharacterEnteredFlag = true; AlteredChar = Char; });
DasherMainInterface->SetCharDeletedCallback([this](FString Char, FString Buffer) {CharacterDeletedFlag = true; AlteredChar = Char; });
DasherMainInterface->SetScreen(this);
DasherMainInterface->SetBuffer(0);
}
// 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 "Components/InstancedStaticMeshComponent.h"
#include "Engine/Texture2DArray.h"
#include "Materials/Material.h"
class DasherParents : public Dasher::CDasherScreen, public Dasher::CScreenCoordInput
{
public:
DasherParents() : CDasherScreen(0,0), CScreenCoordInput("Mouse Input"){};
};
#include "Dasher3DWidget.generated.h"
UCLASS(BlueprintType)
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();
virtual float ExtrusionLevelToHeight(float level);
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, const Dasher::ColorPalette::Color& color) override;
virtual void 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) override;
virtual void DrawCube(Dasher::screenint posX, Dasher::screenint posY, Dasher::screenint sizeX, Dasher::screenint sizeY, Dasher::myint extrusionLevel, Dasher::myint groupRecursionDepth, const Dasher::ColorPalette::Color& color, const Dasher::ColorPalette::Color& outlineColor, int iThickness) override;
virtual void Draw3DLabel(Label* label, Dasher::screenint x, Dasher::screenint y, Dasher::myint extrusionLevel, Dasher::myint groupRecursionDepth, unsigned int iFontSize, const Dasher::ColorPalette::Color& color) override;
virtual void FinishRender3D(Dasher::myint originX, Dasher::myint originY, Dasher::myint originExtrusionLevel) override;
virtual void DrawCircle(Dasher::screenint iCX, Dasher::screenint iCY, Dasher::screenint iR, const Dasher::ColorPalette::Color& fillColor, const Dasher::ColorPalette::Color& lineColor, int iLineWidth) override;
virtual void Polyline(point* Points, int Number, int iWidth, const Dasher::ColorPalette::Color& color) override;
virtual void Polygon(point* Points, int Number, const Dasher::ColorPalette::Color& fillColor, const Dasher::ColorPalette::Color& outlineColor, int lineWidth) override;
virtual void Display() 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 void SendMarker(int Marker) override {};
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;
UPROPERTY(EditAnywhere) float DepthScale = 0.1;
UPROPERTY(EditAnywhere, BlueprintReadOnly) FVector Origin = {0,0,0};
UPROPERTY(EditAnywhere, BlueprintReadOnly) FVector MousePos = {0,0,0};
UFUNCTION(BlueprintCallable) void SetMouseLocation(FVector WorldLocation);
UFUNCTION(BlueprintCallable) void SimulateClick(FKey Key, bool pressed);
virtual void PostInitializeComponents() override;
public:
UFUNCTION(BlueprintImplementableEvent) void CharacterEntered(const FString& Char, const FString& Buffer);
UFUNCTION(BlueprintImplementableEvent) void CharacterDeleted(const FString& Char, const FString& Buffer);
UFUNCTION(BlueprintImplementableEvent) void CharacterSwitched(const FString& Char, const FString& Buffer);
UFUNCTION(BlueprintImplementableEvent) void BufferAltered(const FString& Buffer);
private:
bool CharacterEnteredFlag = false;
bool CharacterDeletedFlag = false;
FString AlteredChar = "";
private:
FVector2D CursorPosition;
float WorldToMeters; // normally 100
FVector2D DrawingSize = {1000,1000}; // Rendering Resolution
TSharedPtr<Dasher::DasherInterface> DasherMainInterface;
UPROPERTY() UMaterialInstanceDynamic* CubeMaterialInstanceDynamic;
UPROPERTY() UMaterialInstanceDynamic* LetterMaterialInstanceDynamic;
UPROPERTY() UTexture2DArray* TextureArray;
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;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment