A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
VRRenderTargetManager.cpp
Go to the documentation of this file.
1// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2
4#include "Kismet/GameplayStatics.h"
5#include "GameFramework/PlayerState.h"
6#include "Net/UnrealNetwork.h"
7
8namespace RLE_Funcs
9{
24
25 template <typename DataType>
26 static bool RLEEncodeLine(TArray<DataType>* LineToEncode, TArray<uint8>* EncodedLine);
27
28 template <typename DataType>
29 static bool RLEEncodeBuffer(DataType* BufferToEncode, uint32 EncodeLength, TArray<uint8>* EncodedLine);
30
31 template <typename DataType>
32 static void RLEDecodeLine(TArray<uint8>* LineToDecode, TArray<DataType>* DecodedLine, bool bCompressed);
33
34 template <typename DataType>
35 static void RLEDecodeLine(const uint8* LineToDecode, uint32 Num, TArray<DataType>* DecodedLine, bool bCompressed);
36
37 static inline void RLEWriteContinueFlag(uint32 Count, uint8** loc);
38
39 template <typename DataType>
40 static inline void RLEWriteRunFlag(uint32 Count, uint8** loc, TArray<DataType>& Data, bool bCompressed);
41}
42
43UVRRenderTargetManager::UVRRenderTargetManager(const FObjectInitializer& ObjectInitializer)
44 : Super(ObjectInitializer)
45{
46
47 PrimaryComponentTick.bCanEverTick = true;
48 PrimaryComponentTick.bStartWithTickEnabled = true;
49
50 PollRelevancyTime = 0.1f;
51 DrawRate = 0.0333;
52
53 bIsStoringImage = false;
54 RenderTarget = nullptr;
57 ClearColor = FColor::White;
58
59 TextureBlobSize = 512;
61
64
66}
67
68bool UVRRenderTargetManager::SendDrawOperations_Validate(const TArray<FRenderManagerOperation>& RenderOperationStoreList)
69{
70 return true;
71}
72
73void UVRRenderTargetManager::SendDrawOperations_Implementation(const TArray<FRenderManagerOperation>& RenderOperationStoreList)
74{
75 if (GetNetMode() == ENetMode::NM_Client)
76 {
77 RenderOperationStore.Append(RenderOperationStoreList);
78 }
79
81}
82
83
84void UVRRenderTargetManager::AddLineDrawOperation(FVector2D Point1, FVector2D Point2, FColor Color, int32 Thickness)
85{
86 FRenderManagerOperation NewOperation;
88 NewOperation.Color = Color;
89 NewOperation.P1 = Point1;
90 NewOperation.P2 = Point2;
91 NewOperation.Thickness = (uint32)Thickness;
92
93 if (GetNetMode() < ENetMode::NM_Client)
94 RenderOperationStore.Add(NewOperation);
95 else
96 LocalRenderOperationStore.Add(NewOperation);
97
98 if (!DrawHandle.IsValid())
99 GetWorld()->GetTimerManager().SetTimer(DrawHandle, this, &UVRRenderTargetManager::DrawPoll, DrawRate, true);
100
101 // Send to server now
102}
103
104void UVRRenderTargetManager::AddTextureDrawOperation(FVector2D Position, UTexture2D* TextureToDisplay)
105{
106
107 if (!TextureToDisplay)
108 return;
109
110 FRenderManagerOperation NewOperation;
112 NewOperation.P1 = Position;
113 NewOperation.Texture = TextureToDisplay;
114
115 if (GetNetMode() < ENetMode::NM_Client)
116 RenderOperationStore.Add(NewOperation);
117 else
118 LocalRenderOperationStore.Add(NewOperation);
119
120 if (!DrawHandle.IsValid())
121 GetWorld()->GetTimerManager().SetTimer(DrawHandle, this, &UVRRenderTargetManager::DrawPoll, DrawRate, true);
122
123 // Send to server now
124}
125
127{
128
129 if (!Tris.Num())
130 return;
131
132 FRenderManagerOperation NewOperation;
134 NewOperation.Color = Tris[0].V0_Color.ToFColor(true);
135
136 NewOperation.Tris.AddUninitialized(Tris.Num());
137 int Counter = 0;
138 FRenderManagerTri RenderTri;
139 for (FCanvasUVTri Tri : Tris)
140 {
141 RenderTri.P1 = Tri.V0_Pos;
142 RenderTri.P2 = Tri.V1_Pos;
143 RenderTri.P3 = Tri.V2_Pos;
144 NewOperation.Tris[Counter++] = RenderTri;
145 }
146
147 NewOperation.Material = Material;
148
149 if (GetNetMode() < ENetMode::NM_Client)
150 RenderOperationStore.Add(NewOperation);
151 else
152 LocalRenderOperationStore.Add(NewOperation);
153
154 if (!DrawHandle.IsValid())
155 GetWorld()->GetTimerManager().SetTimer(DrawHandle, this, &UVRRenderTargetManager::DrawPoll, DrawRate, true);
156
157 // Send to server now
158}
159
161{
162 if (LocalProxy.IsValid() && LocalProxy->OwnersID == Operation.OwnerID)
163 {
164 return;
165 }
166
167 switch (Operation.OperationType)
168 {
170 {
171 FCanvasLineItem LineItem;
172 LineItem.Origin = FVector(Operation.P1.X, Operation.P1.Y, 0.f);
173 LineItem.EndPos = FVector(Operation.P2.X, Operation.P2.Y, 0.f);
174 LineItem.LineThickness = (float)Operation.Thickness;
175 LineItem.SetColor(Operation.Color.ReinterpretAsLinear());
176 Canvas->DrawItem(LineItem);
177 }break;
179 {
180 if (Operation.Texture && Operation.Texture->Resource)
181 {
182 //FTexture* RenderTextureResource = (RenderBase) ? RenderBase->Resource : GWhiteTexture;
183 FCanvasTileItem TileItem(Operation.P1, Operation.Texture->Resource, FVector2D(Operation.Texture->GetSizeX(), Operation.Texture->GetSizeY()), FVector2D(0, 0), FVector2D(1.f, 1.f), ClearColor);
184 TileItem.BlendMode = FCanvas::BlendToSimpleElementBlend(EBlendMode::BLEND_Translucent);
185 Canvas->DrawItem(TileItem);
186 }
187 }break;
189 {
190 if (Operation.Tris.Num() && Operation.Material)
191 {
192 FCanvasTriangleItem TriangleItem(FVector2D::ZeroVector, FVector2D::ZeroVector, FVector2D::ZeroVector, NULL);
193 TriangleItem.MaterialRenderProxy = Operation.Material->GetRenderProxy();
194
195 FCanvasUVTri triStore;
196 triStore.V0_Color = Operation.Color;
197 triStore.V1_Color = Operation.Color;
198 triStore.V2_Color = Operation.Color;
199
200 TriangleItem.TriangleList.Reset(Operation.Tris.Num());
201 TriangleItem.TriangleList.AddUninitialized(Operation.Tris.Num());
202 uint32 Counter = 0;
203 for (FRenderManagerTri Tri : Operation.Tris)
204 {
205 triStore.V0_Pos = Tri.P1;
206 triStore.V1_Pos = Tri.P2;
207 triStore.V2_Pos = Tri.P3;
208 TriangleItem.TriangleList[Counter++] = triStore;
209 }
210
211 Canvas->DrawItem(TriangleItem);
212 }
213 }break;
214 }
215
216}
217
219{
221 {
222 GetWorld()->GetTimerManager().ClearTimer(DrawHandle);
223 return;
224 }
225
226 if (GetNetMode() < ENetMode::NM_Client)
227 {
229 }
230 else
231 {
233 {
234 // Send operations to server
235 if (LocalProxy.IsValid())
236 {
237 LocalProxy->SendLocalDrawOperations(LocalRenderOperationStore);
238 }
239
242 }
243
245 }
246}
247
249{
250
252 {
253 if (!DrawHandle.IsValid())
254 GetWorld()->GetTimerManager().SetTimer(DrawHandle, this, &UVRRenderTargetManager::DrawPoll, DrawRate, true);
255
256 return;
257 }
258
259 if (GetNetMode() == ENetMode::NM_DedicatedServer)
260 {
261 RenderOperationStore.Empty();
262 return;
263 }
264
265 UWorld* World = GetWorld();
266
267 if (!World || !World->bBegunPlay)
268 return;
269
270 // Reference to the Render Target resource
271 FTextureRenderTargetResource* RenderTargetResource = RenderTarget->GameThread_GetRenderTargetResource();
272
273 if (!RenderTargetResource)
274 {
275 RenderOperationStore.Empty();
276 return;
277 }
278
279 // Retrieve a UCanvas form the world to avoid creating a new one each time
280 UCanvas* CanvasToUse = World->GetCanvasForDrawMaterialToRenderTarget();
281
282 // Creates a new FCanvas for rendering
283 FCanvas RenderCanvas(
284 RenderTargetResource,
285 nullptr,
286 World,
287 World->FeatureLevel);
288
289 // Setup the canvas with the FCanvas reference
290 CanvasToUse->Init(RenderTarget->SizeX, RenderTarget->SizeY, nullptr, &RenderCanvas);
291 CanvasToUse->Update();
292
293 if (CanvasToUse)
294 {
296 {
297 DrawOperation(CanvasToUse, opt);
298 }
299
300 RenderOperationStore.Empty();
301
302 // Perform the drawing
303 RenderCanvas.Flush_GameThread();
304
305 // Cleanup the FCanvas reference, to delete it
306 CanvasToUse->Canvas = NULL;
307 }
308}
309
310
311ARenderTargetReplicationProxy::ARenderTargetReplicationProxy(const FObjectInitializer& ObjectInitializer)
312 : Super(ObjectInitializer)
313{
314 bOnlyRelevantToOwner = true;
315 bNetUseOwnerRelevancy = true;
316 bReplicates = true;
317 PrimaryActorTick.bCanEverTick = false;
318 SetReplicateMovement(false);
319 bWaitingForManager = false;
320}
321
323{
324 // If our manager is valid, save off a reference to ourselves to the local copy.
325 if (OwningManager.IsValid())
326 {
327 OwningManager->LocalProxy = this;
328
329 // If we loaded a texture before the manager loaded
331 {
332 OwningManager->bIsLoadingTextureBuffer = false;
333 OwningManager->RenderTargetStore = TextureStore;
335 TextureStore.PackedData.Empty();
337 //GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Orange, FString::Printf(TEXT("Recieved Texture, total byte count: %i"), OwningManager->RenderTargetStore.PackedData.Num()));
338 OwningManager->DeCompressRenderTarget2D();
339 bWaitingForManager = false;
340 }
341 }
342}
343
344bool ARenderTargetReplicationProxy::SendLocalDrawOperations_Validate(const TArray<FRenderManagerOperation>& LocalRenderOperationStoreList)
345{
346 return true;
347}
348
349void ARenderTargetReplicationProxy::SendLocalDrawOperations_Implementation(const TArray<FRenderManagerOperation>& LocalRenderOperationStoreList)
350{
351 if (OwningManager.IsValid())
352 {
353 OwningManager->RenderOperationStore.Append(LocalRenderOperationStoreList);
354
355 // ID the render operations to the player that sent them in
356 if (APlayerController* OwningPlayer = Cast<APlayerController>(GetOwner()))
357 {
358 for (int i = (OwningManager->RenderOperationStore.Num() - LocalRenderOperationStoreList.Num()); i < OwningManager->RenderOperationStore.Num(); i++)
359 {
360 OwningManager->RenderOperationStore[i].OwnerID = OwnersID;
361 }
362 }
363
364 if (!OwningManager->DrawHandle.IsValid())
365 GetWorld()->GetTimerManager().SetTimer(OwningManager->DrawHandle, OwningManager.Get(), &UVRRenderTargetManager::DrawPoll, OwningManager->DrawRate, true);
366 }
367}
368
369void ARenderTargetReplicationProxy::ReceiveTexture_Implementation(const FBPVRReplicatedTextureStore& TextureData)
370{
371 if (OwningManager.IsValid())
372 {
373 OwningManager->RenderTargetStore = TextureData;
374 //GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Orange, FString::Printf(TEXT("Recieved Texture, byte count: %i"), TextureData.PackedData.Num()));
375 OwningManager->DeCompressRenderTarget2D();
376 }
377}
378
379void ARenderTargetReplicationProxy::InitTextureSend_Implementation(int32 Width, int32 Height, int32 TotalDataCount, int32 BlobCount, EPixelFormat PixelFormat, bool bIsZipped/*, bool bIsJPG*/)
380{
382 TextureStore.PixelFormat = PixelFormat;
383 TextureStore.bIsZipped = bIsZipped;
384 //TextureStore.bJPG = bIsJPG;
385 TextureStore.Width = Width;
386 TextureStore.Height = Height;
387
388 TextureStore.PackedData.Reset(TotalDataCount);
389 TextureStore.PackedData.AddUninitialized(TotalDataCount);
390
391 BlobNum = BlobCount;
392
393 if (OwningManager.IsValid())
394 {
395 OwningManager->bIsLoadingTextureBuffer = true;
396 }
397
398 Ack_InitTextureSend(TotalDataCount);
399}
400
401bool ARenderTargetReplicationProxy::Ack_InitTextureSend_Validate(int32 TotalDataCount)
402{
403 return true;
404}
405
406void ARenderTargetReplicationProxy::Ack_InitTextureSend_Implementation(int32 TotalDataCount)
407{
408 if (TotalDataCount == TextureStore.PackedData.Num())
409 {
410 BlobNum = 0;
411
412 // Calculate time offset to achieve our max bytes per second with the given blob size
413 float SendRate = 1.f / (MaxBytesPerSecondRate / (float)TextureBlobSize);
414
415 GetWorld()->GetTimerManager().SetTimer(SendTimer_Handle, this, &ARenderTargetReplicationProxy::SendNextDataBlob, SendRate, true);
416
417 // Start sending data blobs
418 //SendNextDataBlob();
419 }
420}
421
429
431{
432 if (this->IsPendingKill() || !this->GetOwner() || this->GetOwner()->IsPendingKill())
433 {
435 TextureStore.PackedData.Empty();
437 BlobNum = 0;
438 if (SendTimer_Handle.IsValid())
439 GetWorld()->GetTimerManager().ClearTimer(SendTimer_Handle);
440
441 return;
442 }
443
444 BlobNum++;
445 int32 TotalBlobs = TextureStore.PackedData.Num() / TextureBlobSize + (TextureStore.PackedData.Num() % TextureBlobSize > 0 ? 1 : 0);
446
447 if (BlobNum <= TotalBlobs)
448 {
449 TArray<uint8> BlobStore;
450 int32 BlobLen = (BlobNum == TotalBlobs ? TextureStore.PackedData.Num() % TextureBlobSize : TextureBlobSize);
451
452
453 BlobStore.AddUninitialized(BlobLen);
454 uint8* MemLoc = TextureStore.PackedData.GetData();
455 int32 MemCount = (BlobNum - 1) * TextureBlobSize;
456 MemLoc += MemCount;
457
458 FMemory::Memcpy(BlobStore.GetData(), MemLoc, BlobLen);
459
460 ReceiveTextureBlob(BlobStore, MemCount, BlobNum);
461 }
462 else
463 {
465 TextureStore.PackedData.Empty();
467 if (SendTimer_Handle.IsValid())
468 GetWorld()->GetTimerManager().ClearTimer(SendTimer_Handle);
469 BlobNum = 0;
470 }
471}
472
473//=============================================================================
474void ARenderTargetReplicationProxy::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty >& OutLifetimeProps) const
475{
476 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
477
478
481}
482
483void ARenderTargetReplicationProxy::ReceiveTextureBlob_Implementation(const TArray<uint8>& TextureBlob, int32 LocationInData, int32 BlobNumber)
484{
485 if (LocationInData + TextureBlob.Num() <= TextureStore.PackedData.Num())
486 {
487 uint8* MemLoc = TextureStore.PackedData.GetData();
488 MemLoc += LocationInData;
489 FMemory::Memcpy(MemLoc, TextureBlob.GetData(), TextureBlob.Num());
490
491 //GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Orange, FString::Printf(TEXT("Recieved Texture blob, byte count: %i"), TextureBlob.Num()));
492 }
493
494 if (BlobNumber == BlobNum)
495 {
497
498 // We finished, unpack and display
499 if (OwningManager.IsValid())
500 {
501 OwningManager->bIsLoadingTextureBuffer = false;
502 OwningManager->RenderTargetStore = TextureStore;
504 TextureStore.PackedData.Empty();
506 //GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Orange, FString::Printf(TEXT("Recieved Texture, total byte count: %i"), OwningManager->RenderTargetStore.PackedData.Num()));
507 OwningManager->DeCompressRenderTarget2D();
508 }
509 else
510 {
511 bWaitingForManager = true;
512 }
513 }
514
515}
516
517bool ARenderTargetReplicationProxy::Ack_ReceiveTextureBlob_Validate(int32 BlobCount)
518{
519 return true;
520}
521
522void ARenderTargetReplicationProxy::Ack_ReceiveTextureBlob_Implementation(int32 BlobCount)
523{
524 // Send next data blob
525 //SendNextDataBlob();
526
527}
528
530{
531 AActor* myOwner = GetOwner();
532
533 for (int i = NetRelevancyLog.Num() - 1; i >= 0; i--)
534 {
535 if (!NetRelevancyLog[i].PC.IsValid() || NetRelevancyLog[i].PC->IsLocalController() || !NetRelevancyLog[i].PC->GetPawn())
536 {
537 NetRelevancyLog[i].ReplicationProxy->Destroy();
538 NetRelevancyLog.RemoveAt(i);
539 }
540 else
541 {
542 if (APawn* pawn = NetRelevancyLog[i].PC->GetPawn())
543 {
544 if (!myOwner->IsNetRelevantFor(NetRelevancyLog[i].PC.Get(), pawn, pawn->GetActorLocation()))
545 {
546 NetRelevancyLog[i].bIsRelevant = false;
547 NetRelevancyLog[i].bIsDirty = false;
548 //NetRelevancyLog.RemoveAt(i);
549 }
550 }
551 }
552 }
553
554
555 bool bHadDirtyActors = false;
556
557 for (FConstPlayerControllerIterator PCIt = GetWorld()->GetPlayerControllerIterator(); PCIt; ++PCIt)
558 {
559 if (APlayerController* PC = PCIt->Get())
560 {
561 if (PC->IsLocalController())
562 continue;
563
564 if (!PC->HasClientLoadedCurrentWorld())
565 continue;
566
567 if (APawn* pawn = PC->GetPawn())
568 {
569
570 if (myOwner->IsNetRelevantFor(PC, pawn, pawn->GetActorLocation()))
571 {
572 FClientRepData* RepData = NetRelevancyLog.FindByPredicate([PC](const FClientRepData& Other)
573 {
574 return Other.PC == PC;
575 });
576
577 if (!RepData)
578 {
579 FClientRepData ClientRepData;
580
581 FTransform NewTransform = this->GetOwner()->GetActorTransform();
582 ARenderTargetReplicationProxy* RenderProxy = GetWorld()->SpawnActorDeferred<ARenderTargetReplicationProxy>(ARenderTargetReplicationProxy::StaticClass(), NewTransform, PC);
583 if (RenderProxy)
584 {
585 RenderProxy->OwnersID = ++OwnerIDCounter;
586 RenderProxy->OwningManager = this;
588 RenderProxy->TextureBlobSize = TextureBlobSize;
589 UGameplayStatics::FinishSpawningActor(RenderProxy, NewTransform);
590 }
591
592 if (RenderProxy)
593 {
594 RenderProxy->AttachToActor(this->GetOwner(), FAttachmentTransformRules::SnapToTargetIncludingScale);
595
596
597 ClientRepData.PC = PC;
598 ClientRepData.ReplicationProxy = RenderProxy;
599 ClientRepData.bIsRelevant = true;
600 ClientRepData.bIsDirty = true;
601 bHadDirtyActors = true;
602 NetRelevancyLog.Add(ClientRepData);
603 }
604 // Update this client with the new data
605 }
606 else
607 {
608 if (!RepData->bIsRelevant)
609 {
610 RepData->bIsRelevant = true;
611 RepData->bIsDirty = true;
612 bHadDirtyActors = true;
613 }
614 }
615 }
616 }
617
618 }
619 }
620
621 if (bHadDirtyActors && bInitiallyReplicateTexture && GetNetMode() != ENetMode::NM_DedicatedServer)
622 {
624 }
625}
626
628{
629 if (!RenderTarget)
630 return false;
631
633
634
635 int32 Width = RenderTargetStore.Width;
636 int32 Height = RenderTargetStore.Height;
637 EPixelFormat PixelFormat = RenderTargetStore.PixelFormat;
638 uint8 PixelFormat8 = 0;
639
640 TArray<FColor> FinalColorData;
641 FinalColorData.AddUninitialized(RenderTargetStore.UnpackedData.Num());
642
643 uint32 Counter = 0;
644 FColor ColorVal;
645 ColorVal.A = 0xFF;
646 for (uint16 CompColor : RenderTargetStore.UnpackedData)
647 {
648 //CompColor.FillTo(ColorVal);
649 ColorVal.R = CompColor << 3;
650 ColorVal.G = CompColor >> 5 << 2;
651 ColorVal.B = CompColor >> 11 << 3;
652 ColorVal.A = 0xFF;
653 FinalColorData[Counter++] = ColorVal;
654 }
655
656 // Write this to a texture2d
657 UTexture2D* RenderBase = UTexture2D::CreateTransient(Width, Height, PF_R8G8B8A8);// RenderTargetStore.PixelFormat);
658
659 // Switched to a Memcpy instead of byte by byte transer
660 uint8* MipData = (uint8*)RenderBase->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
661 FMemory::Memcpy(MipData, (void*)FinalColorData.GetData(), FinalColorData.Num() * sizeof(FColor));
662 RenderBase->PlatformData->Mips[0].BulkData.Unlock();
663
664 //Setting some Parameters for the Texture and finally returning it
665 RenderBase->PlatformData->SetNumSlices(1);
666 RenderBase->NeverStream = true;
667 RenderBase->SRGB = true;
668 //Avatar->CompressionSettings = TC_EditorIcon;
669
670 RenderBase->UpdateResource();
671
672 /*uint32 size = sizeof(FColor);
673
674 uint8* pData = new uint8[FinalColorData.Num() * sizeof(FColor)];
675 FMemory::Memcpy(pData, (void*)FinalColorData.GetData(), FinalColorData.Num() * sizeof(FColor));
676
677 UTexture2D* TexturePtr = RenderBase;
678 const uint8* TextureData = pData;
679 ENQUEUE_RENDER_COMMAND(VRRenderTargetManager_FillTexture)(
680 [TexturePtr, TextureData](FRHICommandList& RHICmdList)
681 {
682 FUpdateTextureRegion2D region;
683 region.SrcX = 0;
684 region.SrcY = 0;
685 region.DestX = 0;
686 region.DestY = 0;
687 region.Width = TexturePtr->GetSizeX();// TEX_WIDTH;
688 region.Height = TexturePtr->GetSizeY();//TEX_HEIGHT;
689
690 FTexture2DResource* resource = (FTexture2DResource*)TexturePtr->Resource;
691 RHIUpdateTexture2D(resource->GetTexture2DRHI(), 0, region, region.Width * GPixelFormats[TexturePtr->GetPixelFormat()].BlockBytes, TextureData);
692 delete[] TextureData;
693 });*/
694
695
696 // Using this as it saves custom implementation
697
698 UWorld* World = GetWorld();
699
700 // Reference to the Render Target resource
701 FTextureRenderTargetResource* RenderTargetResource = RenderTarget->GameThread_GetRenderTargetResource();
702
703 // Retrieve a UCanvas form the world to avoid creating a new one each time
704 UCanvas* CanvasToUse = World->GetCanvasForDrawMaterialToRenderTarget();
705
706 // Creates a new FCanvas for rendering
707 FCanvas RenderCanvas(
708 RenderTargetResource,
709 nullptr,
710 World,
711 World->FeatureLevel);
712
713 // Setup the canvas with the FCanvas reference
714 CanvasToUse->Init(RenderTarget->SizeX, RenderTarget->SizeY, nullptr, &RenderCanvas);
715 CanvasToUse->Update();
716
717 if (CanvasToUse)
718 {
719 FTexture* RenderTextureResource = (RenderBase) ? RenderBase->Resource : GWhiteTexture;
720 FCanvasTileItem TileItem(FVector2D(0, 0), RenderTextureResource, FVector2D(RenderTarget->SizeX, RenderTarget->SizeY), FVector2D(0, 0), FVector2D(1.f, 1.f), FLinearColor::White);
721 TileItem.BlendMode = FCanvas::BlendToSimpleElementBlend(EBlendMode::BLEND_Opaque);
722 CanvasToUse->DrawItem(TileItem);
723
724
725 // Perform the drawing
726 RenderCanvas.Flush_GameThread();
727
728 // Cleanup the FCanvas reference, to delete it
729 CanvasToUse->Canvas = NULL;
730 }
731
732 RenderBase->ReleaseResource();
733 RenderBase->MarkPendingKill();
734
735 return true;
736}
737
739{
740
741 if (!bInitiallyReplicateTexture || !RenderTarget || bIsStoringImage || GetNetMode() == ENetMode::NM_DedicatedServer)
742 {
743 return;
744 }
745
746 bIsStoringImage = true;
747
748 // Init new RenderRequest
749 FRenderDataStore* renderData = new FRenderDataStore();
750
751 // Get RenderContext
752 FTextureRenderTargetResource* renderTargetResource = RenderTarget->GameThread_GetRenderTargetResource();
753
754 if (!renderTargetResource)
755 return;
756
757 renderData->Size2D = renderTargetResource->GetSizeXY();
758 renderData->PixelFormat = RenderTarget->GetFormat();
759
760 struct FReadSurfaceContext {
761 FRenderTarget* SrcRenderTarget;
762 TArray<FColor>* OutData;
763 FIntRect Rect;
764 FReadSurfaceDataFlags Flags;
765 };
766
767 // Setup GPU command
768 FReadSurfaceContext readSurfaceContext =
769 {
770 renderTargetResource,
771 &(renderData->ColorData),
772 FIntRect(0,0,renderTargetResource->GetSizeXY().X, renderTargetResource->GetSizeXY().Y),
773 FReadSurfaceDataFlags(RCM_UNorm, CubeFace_MAX)
774 };
775
776 ENQUEUE_RENDER_COMMAND(SceneDrawCompletion)(
777 [readSurfaceContext](FRHICommandListImmediate& RHICmdList) {
778 RHICmdList.ReadSurfaceData(
779 readSurfaceContext.SrcRenderTarget->GetRenderTargetTexture(),
780 readSurfaceContext.Rect,
781 *readSurfaceContext.OutData,
782 readSurfaceContext.Flags
783 );
784 });
785
786 // Notify new task in RenderQueue
787 RenderDataQueue.Enqueue(renderData);
788
789 // Set RenderCommandFence
790 renderData->RenderFence.BeginFence();
791
792 this->SetComponentTickEnabled(true);
793}
794
795void UVRRenderTargetManager::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
796{
797 Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
798
799 // Read pixels once RenderFence is completed
800 if (!bInitiallyReplicateTexture || RenderDataQueue.IsEmpty() || GetNetMode() == ENetMode::NM_DedicatedServer)
801 {
802 SetComponentTickEnabled(false);
803 }
804 else
805 {
806 // Peek the next RenderRequest from queue
807 FRenderDataStore* nextRenderData;
808 RenderDataQueue.Peek(nextRenderData);
809
810 if (nextRenderData)
811 {
812 if (nextRenderData->RenderFence.IsFenceComplete())
813 {
814 bIsStoringImage = false;
816 uint32 SizeOfData = nextRenderData->ColorData.Num();
817
818 RenderTargetStore.UnpackedData.Reset(SizeOfData);
819 RenderTargetStore.UnpackedData.AddUninitialized(SizeOfData);
820
821 uint16 ColorVal = 0;
822 uint32 Counter = 0;
823
824 // Convert to 16bit color
825 for (FColor col : nextRenderData->ColorData)
826 {
827 ColorVal = (col.R >> 3) << 11 | (col.G >> 2) << 5 | (col.B >> 3);
828 RenderTargetStore.UnpackedData[Counter++] = ColorVal;
829 }
830
831 FIntPoint Size2D = nextRenderData->Size2D;
832 RenderTargetStore.Width = Size2D.X;
833 RenderTargetStore.Height = Size2D.Y;
834 RenderTargetStore.PixelFormat = nextRenderData->PixelFormat;
836
837
838//#if WITH_PUSH_MODEL
839 //MARK_PROPERTY_DIRTY_FROM_NAME(UVRRenderTargetManager, RenderTargetStore, this);
840//#endif
841
842
843 // Delete the first element from RenderQueue
844 RenderDataQueue.Pop();
845 delete nextRenderData;
846
847 for (int i = NetRelevancyLog.Num() - 1; i >= 0; i--)
848 {
849 if (NetRelevancyLog[i].bIsDirty && NetRelevancyLog[i].PC.IsValid() && !NetRelevancyLog[i].PC->IsLocalController())
850 {
851 if (NetRelevancyLog[i].ReplicationProxy.IsValid())
852 {
853 NetRelevancyLog[i].ReplicationProxy->TextureStore = RenderTargetStore;
854 NetRelevancyLog[i].ReplicationProxy->SendInitMessage();
855 NetRelevancyLog[i].bIsDirty = false;
856 }
857 }
858 }
859
860
861 }
862 }
863 }
864
865}
866
868{
869 Super::BeginPlay();
870
872
873 if (/*bInitiallyReplicateTexture && */GetNetMode() < ENetMode::NM_Client)
874 GetWorld()->GetTimerManager().SetTimer(NetRelevancyTimer_Handle, this, &UVRRenderTargetManager::UpdateRelevancyMap, PollRelevancyTime, true);
875}
876
877void UVRRenderTargetManager::EndPlay(const EEndPlayReason::Type EndPlayReason)
878{
879 Super::EndPlay(EndPlayReason);
880
881 FRenderDataStore* Store = nullptr;
882 while (!RenderDataQueue.IsEmpty())
883 {
884 RenderDataQueue.Dequeue(Store);
885
886 if (Store)
887 {
888 delete Store;
889 }
890 }
891
892 if (GetNetMode() < ENetMode::NM_Client)
893 GetWorld()->GetTimerManager().ClearTimer(NetRelevancyTimer_Handle);
894
895 if(DrawHandle.IsValid())
896 GetWorld()->GetTimerManager().ClearTimer(DrawHandle);
897
898 if (RenderTarget)
899 {
900 RenderTarget->ReleaseResource();
901 RenderTarget = nullptr;
902 }
903
904 for (FClientRepData& RepData : NetRelevancyLog)
905 {
906 RepData.PC = nullptr;
907 RepData.PC.Reset();
908 if (RepData.ReplicationProxy.IsValid() && !RepData.ReplicationProxy->IsPendingKill())
909 {
910 RepData.ReplicationProxy->Destroy();
911 }
912
913 RepData.ReplicationProxy.Reset();
914 }
915
916}
917
919{
920 if (this->GetNetMode() == ENetMode::NM_DedicatedServer)
921 {
922 return; // Dedicated servers cannot handle render targets
923 }
924
925 UWorld* World = GetWorld();
926
927 if (RenderTargetWidth > 0 && RenderTargetHeight > 0 && World)
928 {
929 RenderTarget = NewObject<UCanvasRenderTarget2D>(this);
930 if (RenderTarget)
931 {
932 //NewCanvasRenderTarget->World = World;
934 RenderTarget->ClearColor = ClearColor;
935 RenderTarget->bAutoGenerateMips = false;
936 RenderTarget->UpdateResourceImmediate(true);
937 }
938 else
939 {
940 RenderTarget = nullptr;
941 }
942 }
943 else
944 {
945 RenderTarget = nullptr;
946 }
947}
948
949
950bool UVRRenderTargetManager::GenerateTrisFromBoxPlaneIntersection(UPrimitiveComponent* PrimToBoxCheck, FTransform WorldTransformOfPlane, const FPlane& LocalProjectionPlane, FVector2D PlaneSize, FColor UVColor, TArray<FCanvasUVTri>& OutTris)
951{
952
953 if (!PrimToBoxCheck)
954 return false;
955
956 OutTris.Reset();
957
958 FBoxSphereBounds LocalBounds = PrimToBoxCheck->CalcLocalBounds();
959 FVector Center = LocalBounds.Origin;
960 FVector Extent = LocalBounds.BoxExtent;
961
962 // Transform into plane local space from our localspace
963 FTransform LocalTrans = PrimToBoxCheck->GetComponentTransform() * WorldTransformOfPlane.Inverse();
964
965 FVector BoxMin = Center - Extent;
966 FVector BoxMax = Center + Extent;
967
968 TArray<FVector> PointList;
969 PointList.AddUninitialized(8); // 8 Is number of points on box
970
971 PointList[0] = LocalTrans.TransformPosition(BoxMin);
972 PointList[1] = LocalTrans.TransformPosition(BoxMax);
973 PointList[2] = LocalTrans.TransformPosition(FVector(BoxMin.X, BoxMin.Y, BoxMax.Z));
974 PointList[3] = LocalTrans.TransformPosition(FVector(BoxMin.X, BoxMax.Y, BoxMin.Z));
975 PointList[4] = LocalTrans.TransformPosition(FVector(BoxMax.X, BoxMin.Y, BoxMin.Z));
976 PointList[5] = LocalTrans.TransformPosition(FVector(BoxMin.X, BoxMax.Y, BoxMax.Z));
977 PointList[6] = LocalTrans.TransformPosition(FVector(BoxMax.X, BoxMin.Y, BoxMax.Z));
978 PointList[7] = LocalTrans.TransformPosition(FVector(BoxMax.X, BoxMax.Y, BoxMin.Z));
979
980 // List of edges to check, 12 total, 2 points per edge
981 int EdgeList[24] =
982 {
983 0, 3,
984 0, 4,
985 0, 2,
986 2, 5,
987 2, 6,
988 4, 7,
989 4, 6,
990 6, 1,
991 1, 7,
992 1, 5,
993 5, 3,
994 3, 7
995 };
996
997 TArray<FVector2D> IntersectionPoints;
998
999 FVector Intersection;
1000 float Time;
1001
1002 FVector2D HalfPlane = PlaneSize / 2.f;
1003 FVector2D PtCenter;
1004 FVector2D NewPt;
1005 FVector PlanePoint;
1006 int CenterCount = 0;
1007 for (int i = 0; i < 24; i += 2)
1008 {
1009
1010 if (UKismetMathLibrary::LinePlaneIntersection(PointList[EdgeList[i]], PointList[EdgeList[i + 1]], LocalProjectionPlane, Time, Intersection))
1011 {
1012 //DrawDebugSphere(GetWorld(), WorldTransformOfPlane.TransformPosition(Intersection), 2.f, 32.f, FColor::Black);
1013 PlanePoint = Intersection;
1014
1015 if (RenderTarget)
1016 {
1017 NewPt.X = ((PlanePoint.X + HalfPlane.X) / PlaneSize.X) * RenderTarget->SizeX;
1018 NewPt.Y = ((PlanePoint.Y + HalfPlane.Y) / PlaneSize.Y) * RenderTarget->SizeY;
1019 }
1020 else
1021 {
1022 NewPt.X = ((PlanePoint.X + HalfPlane.X) / PlaneSize.X) * RenderTargetWidth;
1023 NewPt.Y = ((PlanePoint.Y + HalfPlane.Y) / PlaneSize.Y) * RenderTargetHeight;
1024 }
1025
1026 IntersectionPoints.Add(NewPt);
1027 PtCenter += NewPt;
1028 CenterCount++;
1029 }
1030 }
1031
1032 if (IntersectionPoints.Num() <= 2)
1033 {
1034 return false;
1035 }
1036
1037 // Get our center value
1038 PtCenter /= CenterCount;
1039
1040 // Sort the points clockwise
1041 struct FPointSortCompare
1042 {
1043 public:
1044 FVector2D CenterPoint;
1045 FPointSortCompare(const FVector2D& InCenterPoint)
1046 : CenterPoint(InCenterPoint)
1047 {
1048
1049 }
1050
1051 FORCEINLINE bool operator()(const FVector2D& A, const FVector2D& B) const
1052 {
1053 if (A.Y - CenterPoint.X >= 0 && B.X - CenterPoint.X < 0)
1054 return true;
1055 if (A.X - CenterPoint.X < 0 && B.X - CenterPoint.X >= 0)
1056 return false;
1057 if (A.X - CenterPoint.X == 0 && B.X - CenterPoint.X == 0) {
1058 if (A.Y - CenterPoint.Y >= 0 || B.Y - CenterPoint.Y >= 0)
1059 return A.Y > B.Y;
1060 return B.Y > A.Y;
1061 }
1062
1063 // compute the cross product of vectors (center -> a) x (center -> b)
1064 int det = (A.X - CenterPoint.X) * (B.Y - CenterPoint.Y) - (B.X - CenterPoint.X) * (A.Y - CenterPoint.Y);
1065 if (det < 0)
1066 return true;
1067 if (det > 0)
1068 return false;
1069
1070 // points a and b are on the same line from the center
1071 // check which point is closer to the center
1072 int d1 = (A.X - CenterPoint.X) * (A.X - CenterPoint.X) + (A.Y - CenterPoint.Y) * (A.Y - CenterPoint.Y);
1073 int d2 = (B.X - CenterPoint.X) * (B.X - CenterPoint.X) + (B.Y - CenterPoint.Y) * (B.Y - CenterPoint.Y);
1074 return d1 > d2;
1075 }
1076 };
1077
1078 IntersectionPoints.Sort(FPointSortCompare(PtCenter));
1079
1080 FCanvasUVTri Tri;
1081 Tri.V0_Color = UVColor;
1082 Tri.V1_Color = UVColor;
1083 Tri.V2_Color = UVColor;
1084
1085 OutTris.Reserve(IntersectionPoints.Num() - 2);
1086
1087 // Now that we have our sorted list, we can generate a tri map from it, just doing a Fan from first to last
1088 for (int i = 1; i < IntersectionPoints.Num() - 1; i++)
1089 {
1090 Tri.V0_Pos = IntersectionPoints[0];
1091 Tri.V1_Pos = IntersectionPoints[i];
1092 Tri.V2_Pos = IntersectionPoints[i + 1];
1093
1094 OutTris.Add(Tri);
1095 }
1096
1097 return true;
1098}
1099
1101{
1102 if (UnpackedData.Num() > 0)
1103 {
1104 TArray<uint8> TmpPacked;
1105 RLE_Funcs::RLEEncodeBuffer<uint16>(UnpackedData.GetData(), UnpackedData.Num(), &TmpPacked);
1106 UnpackedData.Reset();
1107
1108 /*if (TmpPacked.Num() > 30000)
1109 {
1110 IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
1111 TSharedPtr<IImageWrapper> imageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG);
1112
1113 imageWrapper->SetRaw(UnpackedData.GetData(), UnpackedData.Num(), Width, Height, ERGBFormat::RGBA, 8);
1114 const TArray64<uint8>& ImgData = imageWrapper->GetCompressed(1);
1115
1116
1117 PackedData.Reset(ImgData.Num());
1118 PackedData.AddUninitialized(ImgData.Num());
1119 FMemory::Memcpy(PackedData.GetData(), ImgData.GetData(), ImgData.Num());
1120 bJPG = true;
1121 bIsZipped = false;
1122 }
1123 else */if (TmpPacked.Num() > 512)
1124 {
1125 FArchiveSaveCompressedProxy Compressor(PackedData, NAME_Zlib, COMPRESS_BiasSpeed);
1126 Compressor << TmpPacked;
1127 Compressor.Flush();
1128 bIsZipped = true;
1129 //bJPG = false;
1130 }
1131 else
1132 {
1133 PackedData = TmpPacked;
1134 bIsZipped = false;
1135 //bJPG = false;
1136 }
1137 }
1138}
1139
1140
1142{
1143 if (PackedData.Num() > 0)
1144 {
1145
1146 /*if (bJPG)
1147 {
1148 IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
1149 TSharedPtr<IImageWrapper> imageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG);
1150
1151
1152 if (imageWrapper.IsValid() && (PackedData.Num() > 0) && imageWrapper->SetCompressed(PackedData.GetData(), PackedData.Num()))
1153 {
1154 Width = imageWrapper->GetWidth();
1155 Height = imageWrapper->GetHeight();
1156
1157 if (imageWrapper->GetRaw(ERGBFormat::BGRA, 8, UnpackedData))
1158 {
1159 //bSucceeded = true;
1160 }
1161 }
1162 }
1163 else */if (bIsZipped)
1164 {
1165 TArray<uint8> RLEEncodedData;
1166 FArchiveLoadCompressedProxy DataArchive(PackedData, NAME_Zlib);
1167 DataArchive << RLEEncodedData;
1168 RLE_Funcs::RLEDecodeLine<uint16>(&RLEEncodedData, &UnpackedData, true);
1169 }
1170 else
1171 {
1172 RLE_Funcs::RLEDecodeLine<uint16>(&PackedData, &UnpackedData, true);
1173 }
1174
1175 PackedData.Reset();
1176 }
1177}
1178
1180// Doing a custom NetSerialize here because this is sent via RPCs and should change on every update
1181bool FBPVRReplicatedTextureStore::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
1182{
1183 bOutSuccess = true;
1184
1185 //Ar.SerializeBits(&bIsJPG, 1);
1186 Ar.SerializeBits(&bIsZipped, 1);
1187 Ar.SerializeIntPacked(Width);
1188 Ar.SerializeIntPacked(Height);
1189 Ar.SerializeBits(&PixelFormat, 8);
1190
1191 Ar << PackedData;
1192
1193 //uint32 UncompressedBufferSize = PackedData.Num();
1194
1195 return bOutSuccess;
1196}
1197
1198
1199// BEGIN RLE FUNCTIONS ///
1200
1201// Followed by a count of the following voxels
1202template <typename DataType>
1203void RLE_Funcs::RLEDecodeLine(TArray<uint8>* LineToDecode, TArray<DataType>* DecodedLine, bool bCompressed)
1204{
1205 if (!LineToDecode || !DecodedLine)
1206 return;
1207
1208 RLEDecodeLine(LineToDecode->GetData(), LineToDecode->Num(), DecodedLine, bCompressed);
1209}
1210
1211// Followed by a count of the following voxels
1212template <typename DataType>
1213void RLE_Funcs::RLEDecodeLine(const uint8* LineToDecode, uint32 Num, TArray<DataType>* DecodedLine, bool bCompressed)
1214{
1215 if (!bCompressed)
1216 {
1217 DecodedLine->Empty(Num / sizeof(DataType));
1218 DecodedLine->AddUninitialized(Num / sizeof(DataType));
1219 FMemory::Memcpy(DecodedLine->GetData(), LineToDecode, Num);
1220 return;
1221 }
1222
1223 const uint8* StartLoc = LineToDecode;
1224 const uint8* EndLoc = StartLoc + Num;
1225 uint8 incr = sizeof(DataType);
1226
1227 DataType ValToWrite = *((DataType*)LineToDecode); // This is just to prevent stupid compiler warnings without disabling them
1228
1229 DecodedLine->Empty();
1230
1231 uint8 RLE_FLAG;
1232 uint32 Length32;
1233 uint32 Length8;
1234 uint32 Length16;
1235 int origLoc;
1236
1237 for (const uint8* loc = StartLoc; loc < EndLoc;)
1238 {
1239 RLE_FLAG = *loc >> 4; // Get the RLE flag from the first 4 bits of the first byte
1240
1241 switch (RLE_FLAG)
1242 {
1243 case RLE_Flags::RLE_CompressedByte:
1244 {
1245 Length8 = (*loc & ~0xF0) + 1;
1246 loc++;
1247 ValToWrite = *((DataType*)loc);
1248 loc += incr;
1249
1250 origLoc = DecodedLine->AddUninitialized(Length8);
1251
1252 for (uint32 i = origLoc; i < origLoc + Length8; i++)
1253 {
1254 (*DecodedLine)[i] = ValToWrite;
1255 }
1256
1257 }break;
1258 case RLE_Flags::RLE_CompressedShort:
1259 {
1260 Length16 = (((uint16)(*loc & ~0xF0)) << 8 | (*(loc + 1))) + 1;
1261 loc += 2;
1262 ValToWrite = *((DataType*)loc);
1263 loc += incr;
1264
1265 origLoc = DecodedLine->AddUninitialized(Length16);
1266
1267 for (uint32 i = origLoc; i < origLoc + Length16; i++)
1268 {
1269 (*DecodedLine)[i] = ValToWrite;
1270 }
1271
1272 }break;
1273 case RLE_Flags::RLE_Compressed24:
1274 {
1275 Length32 = (((uint32)(*loc & ~0xF0)) << 16 | ((uint32)(*(loc + 1))) << 8 | (uint32)(*(loc + 2))) + 1;
1276 loc += 3;
1277 ValToWrite = *((DataType*)loc);
1278 loc += incr;
1279
1280 origLoc = DecodedLine->AddUninitialized(Length32);
1281
1282 for (uint32 i = origLoc; i < origLoc + Length32; i++)
1283 {
1284 (*DecodedLine)[i] = ValToWrite;
1285 }
1286
1287 }break;
1288
1289 case RLE_Flags::RLE_NotCompressedByte:
1290 {
1291 Length8 = (*loc & ~0xF0) + 1;
1292 loc++;
1293
1294 origLoc = DecodedLine->AddUninitialized(Length8);
1295
1296 for (uint32 i = origLoc; i < origLoc + Length8; i++)
1297 {
1298 (*DecodedLine)[i] = *((DataType*)loc);
1299 loc += incr;
1300 }
1301
1302 }break;
1303 case RLE_Flags::RLE_NotCompressedShort:
1304 {
1305 Length16 = (((uint16)(*loc & ~0xF0)) << 8 | (*(loc + 1))) + 1;
1306 loc += 2;
1307
1308 origLoc = DecodedLine->AddUninitialized(Length16);
1309
1310 for (uint32 i = origLoc; i < origLoc + Length16; i++)
1311 {
1312 (*DecodedLine)[i] = *((DataType*)loc);
1313 loc += incr;
1314 }
1315
1316 }break;
1317 case RLE_Flags::RLE_NotCompressed24:
1318 {
1319 Length32 = (((uint32)(*loc & ~0xF0)) << 16 | ((uint32)(*(loc + 1))) << 8 | ((uint32)(*(loc + 2)))) + 1;
1320 loc += 3;
1321
1322 origLoc = DecodedLine->AddUninitialized(Length32);
1323
1324 for (uint32 i = origLoc; i < origLoc + Length32; i++)
1325 {
1326 (*DecodedLine)[i] = *((DataType*)loc);
1327 loc += incr;
1328 }
1329
1330 }break;
1331
1332 case RLE_Flags::RLE_ContinueRunByte:
1333 {
1334 Length8 = (*loc & ~0xF0) + 1;
1335 loc++;
1336
1337 origLoc = DecodedLine->AddUninitialized(Length8);
1338
1339 for (uint32 i = origLoc; i < origLoc + Length8; i++)
1340 {
1341 (*DecodedLine)[i] = ValToWrite;
1342 }
1343
1344 }break;
1345 case RLE_Flags::RLE_ContinueRunShort:
1346 {
1347 Length16 = (((uint16)(*loc & ~0xF0)) << 8 | (*(loc + 1))) + 1;
1348 loc += 2;
1349
1350 origLoc = DecodedLine->AddUninitialized(Length16);
1351
1352 for (uint32 i = origLoc; i < origLoc + Length16; i++)
1353 {
1354 (*DecodedLine)[i] = ValToWrite;
1355 }
1356
1357 }break;
1358 case RLE_Flags::RLE_ContinueRun24:
1359 {
1360 Length32 = (((uint32)(*loc & ~0xF0)) << 16 | ((uint32)(*(loc + 1))) << 8 | (*(loc + 2))) + 1;
1361 loc += 3;
1362
1363 origLoc = DecodedLine->AddUninitialized(Length32);
1364
1365 for (uint32 i = origLoc; i < origLoc + Length32; i++)
1366 {
1367 (*DecodedLine)[i] = ValToWrite;
1368 }
1369
1370 }break;
1371
1372 }
1373 }
1374}
1375
1376template <typename DataType>
1377bool RLE_Funcs::RLEEncodeLine(TArray<DataType>* LineToEncode, TArray<uint8>* EncodedLine)
1378{
1379 return RLEEncodeBuffer<DataType>(LineToEncode->GetData(), LineToEncode->Num(), EncodedLine);
1380}
1381
1382void RLE_Funcs::RLEWriteContinueFlag(uint32 count, uint8** loc)
1383{
1384 if (count <= 16)
1385 {
1386 **loc = (((uint8)RLE_Flags::RLE_ContinueRunByte << 4) | ((uint8)count - 1));
1387 (*loc)++;
1388 }
1389 else if (count <= 4096)
1390 {
1391 uint16 val = ((((uint16)RLE_Flags::RLE_ContinueRunShort) << 12) | ((uint16)count - 1));
1392 **loc = val >> 8;
1393 (*loc)++;
1394 **loc = (uint8)val;
1395 (*loc)++;
1396 }
1397 else
1398 {
1399 uint32 val = ((((uint32)RLE_Flags::RLE_ContinueRun24) << 20) | ((uint32)count - 1));
1400 **loc = (uint8)(val >> 16);
1401 (*loc)++;
1402 **loc = (uint8)(val >> 8);
1403 (*loc)++;
1404 **loc = (uint8)val;
1405 (*loc)++;
1406 }
1407}
1408
1409template <typename DataType>
1410void RLE_Funcs::RLEWriteRunFlag(uint32 count, uint8** loc, TArray<DataType>& Data, bool bCompressed)
1411{
1412
1413 if (count <= 16)
1414 {
1415 uint8 val;
1416 if (bCompressed)
1417 val = ((((uint8)RLE_Flags::RLE_CompressedByte) << 4) | ((uint8)count - 1));
1418 else
1419 val = ((((uint8)RLE_Flags::RLE_NotCompressedByte) << 4) | ((uint8)count - 1));
1420
1421 **loc = val;
1422 (*loc)++;
1423 }
1424 else if (count <= 4096)
1425 {
1426 uint16 val;
1427 if (bCompressed)
1428 val = ((((uint16)RLE_Flags::RLE_CompressedShort) << 12) | ((uint16)count - 1));
1429 else
1430 val = ((((uint16)RLE_Flags::RLE_NotCompressedShort) << 12) | ((uint16)count - 1));
1431
1432 **loc = (uint8)(val >> 8);
1433 (*loc)++;
1434 **loc = (uint8)val;
1435 (*loc)++;
1436 }
1437 else
1438 {
1439 uint32 val;
1440 if (bCompressed)
1441 val = ((((uint32)RLE_Flags::RLE_Compressed24) << 20) | ((uint32)count - 1));
1442 else
1443 val = ((((uint32)RLE_Flags::RLE_NotCompressed24) << 20) | ((uint32)count - 1));
1444
1445 **loc = (uint8)(val >> 16);
1446 (*loc)++;
1447 **loc = (uint8)(val >> 8);
1448 (*loc)++;
1449 **loc = (uint8)(val);
1450 (*loc)++;
1451 }
1452
1453 FMemory::Memcpy(*loc, Data.GetData(), Data.Num() * sizeof(DataType));
1454 *loc += Data.Num() * sizeof(DataType);
1455 Data.Empty(256);
1456}
1457
1458template <typename DataType>
1459bool RLE_Funcs::RLEEncodeBuffer(DataType* BufferToEncode, uint32 EncodeLength, TArray<uint8>* EncodedLine)
1460{
1461 uint32 OrigNum = EncodeLength;//LineToEncode->Num();
1462 uint8 incr = sizeof(DataType);
1463 uint32 MAX_COUNT = 1048576; // Max of 2.5 bytes as 0.5 bytes is used for control flags
1464
1465 EncodedLine->Empty((OrigNum * sizeof(DataType)) + (OrigNum * (sizeof(short))));
1466 // Reserve enough memory to account for a perfectly bad situation (original size + 3 bytes per max array value)
1467 // Remove the remaining later with RemoveAt() and a count
1468 EncodedLine->AddUninitialized((OrigNum * sizeof(DataType)) + ((OrigNum / MAX_COUNT * 3)));
1469
1470 DataType* First = BufferToEncode;// LineToEncode->GetData();
1471 DataType Last;
1472 uint32 RunCount = 0;
1473
1474 uint8* loc = EncodedLine->GetData();
1475 //uint8 * countLoc = NULL;
1476
1477 bool bInRun = false;
1478 bool bWroteStart = false;
1479 bool bContinueRun = false;
1480
1481 TArray<DataType> TempBuffer;
1482 TempBuffer.Reserve(256);
1483 uint32 TempCount = 0;
1484
1485 Last = *First;
1486 First++;
1487
1488 for (uint32 i = 0; i < OrigNum - 1; i++, First++)
1489 {
1490 if (Last == *First)
1491 {
1492 if (bWroteStart && !bInRun)
1493 {
1494 RLE_Funcs::RLEWriteRunFlag(TempCount, &loc, TempBuffer, false);
1495 bWroteStart = false;
1496 }
1497
1498 if (bInRun && TempCount < MAX_COUNT)
1499 {
1500 TempCount++;
1501
1502 if (TempCount == MAX_COUNT)
1503 {
1504 // Write run byte
1505 if (bContinueRun)
1506 {
1507 RLE_Funcs::RLEWriteContinueFlag(TempCount, &loc);
1508 }
1509 else
1510 RLE_Funcs::RLEWriteRunFlag(TempCount, &loc, TempBuffer, true);
1511
1512 bContinueRun = true;
1513 TempCount = 0;
1514 }
1515 }
1516 else
1517 {
1518 bInRun = true;
1519 bWroteStart = false;
1520 bContinueRun = false;
1521
1522 TempBuffer.Add(Last);
1523 TempCount = 1;
1524 }
1525
1526 // Begin Run Here
1527 }
1528 else if (bInRun)
1529 {
1530 bInRun = false;
1531
1532 if (bContinueRun)
1533 {
1534 TempCount++;
1535 RLE_Funcs::RLEWriteContinueFlag(TempCount, &loc);
1536 }
1537 else
1538 {
1539 TempCount++;
1540 RLE_Funcs::RLEWriteRunFlag(TempCount, &loc, TempBuffer, true);
1541 }
1542
1543 bContinueRun = false;
1544 }
1545 else
1546 {
1547 if (bWroteStart && TempCount < MAX_COUNT)
1548 {
1549 TempCount++;
1550 TempBuffer.Add(Last);
1551 }
1552 else if (bWroteStart && TempCount == MAX_COUNT)
1553 {
1554 RLE_Funcs::RLEWriteRunFlag(TempCount, &loc, TempBuffer, false);
1555
1556 bWroteStart = true;
1557 TempBuffer.Add(Last);
1558 TempCount = 1;
1559 }
1560 else
1561 {
1562 TempBuffer.Add(Last);
1563 TempCount = 1;
1564 //*countLoc = 1;
1565
1566 bWroteStart = true;
1567 }
1568 }
1569
1570 Last = *First;
1571 }
1572
1573 // Finish last num
1574 if (bInRun)
1575 {
1576 if (TempCount <= MAX_COUNT)
1577 {
1578 if (TempCount == MAX_COUNT)
1579 {
1580 // Write run byte
1581 RLE_Funcs::RLEWriteRunFlag(TempCount, &loc, TempBuffer, true);
1582 bContinueRun = true;
1583 }
1584
1585 if (bContinueRun)
1586 {
1587 TempCount++;
1588 RLE_Funcs::RLEWriteContinueFlag(TempCount, &loc);
1589 }
1590 else
1591 {
1592 TempCount++;
1593 RLE_Funcs::RLEWriteRunFlag(TempCount, &loc, TempBuffer, true);
1594 }
1595 }
1596
1597 // Begin Run Here
1598 }
1599 else
1600 {
1601 if (bWroteStart && TempCount <= MAX_COUNT)
1602 {
1603 if (TempCount == MAX_COUNT)
1604 {
1605 // Write run byte
1606 RLE_Funcs::RLEWriteRunFlag(TempCount, &loc, TempBuffer, false);
1607 TempCount = 0;
1608 }
1609
1610 TempCount++;
1611 TempBuffer.Add(Last);
1612 RLE_Funcs::RLEWriteRunFlag(TempCount, &loc, TempBuffer, false);
1613 }
1614 }
1615
1616 // Resize the out array to fit compressed contents
1617 uint32 Wrote = loc - EncodedLine->GetData();
1618 EncodedLine->RemoveAt(Wrote, EncodedLine->Num() - Wrote, true);
1619
1620 // If the compression performed worse than the original file size, throw the results array and use the original instead.
1621 // This will almost never happen with voxels but can so should be accounted for.
1622
1623 return true;
1624 // Skipping non compressed for now, the overhead is so low that it isn't worth supporting since the last revision
1625 if (Wrote > OrigNum * incr)
1626 {
1627 EncodedLine->Empty(OrigNum * incr);
1628 EncodedLine->AddUninitialized(OrigNum * incr);
1629 FMemory::Memcpy(EncodedLine->GetData(), BufferToEncode/*LineToEncode->GetData()*/, OrigNum * incr);
1630 return false; // Return that there was no compression, so the decoder can receive it later
1631 }
1632 else
1633 return true;
1634}
1635
1636template<int32 ScaleFactor, int32 MaxBitsPerComponent>
1637bool WritePackedVector2D(FVector2D Value, FArchive& Ar) // Note Value is intended to not be a reference since we are scaling it before serializing!
1638{
1639 check(Ar.IsSaving());
1640
1641 // Scale vector by quant factor first
1642 Value *= ScaleFactor;
1643
1644 // Nan Check
1645 if (Value.ContainsNaN())
1646 {
1647 logOrEnsureNanError(TEXT("WritePackedVector2D: Value contains NaN, clearing for safety."));
1648 FVector2D Dummy(0, 0);
1649 WritePackedVector2D<ScaleFactor, MaxBitsPerComponent>(Dummy, Ar);
1650 return false;
1651 }
1652
1653 float MinV = -1073741824.0f;
1654 float MaxV = 1073741760.0f;
1655
1656 // Some platforms have RoundToInt implementations that essentially reduces the allowed inputs to 2^31.
1657 const FVector2D ClampedValue = FVector2D(FMath::Clamp(Value.X, MinV, MaxV), FMath::Clamp(Value.Y, MinV, MaxV));
1658 bool bClamp = ClampedValue != Value;
1659
1660 // Do basically FVector::SerializeCompressed
1661 int32 IntX = FMath::RoundToInt(ClampedValue.X);
1662 int32 IntY = FMath::RoundToInt(ClampedValue.Y);
1663
1664 uint32 Bits = FMath::Clamp<uint32>(FMath::CeilLogTwo(1 + FMath::Max(FMath::Abs(IntX), FMath::Abs(IntY))), 1, MaxBitsPerComponent) - 1;
1665
1666 // Serialize how many bits each component will have
1667 Ar.SerializeInt(Bits, MaxBitsPerComponent);
1668
1669 int32 Bias = 1 << (Bits + 1);
1670 uint32 Max = 1 << (Bits + 2);
1671 uint32 DX = IntX + Bias;
1672 uint32 DY = IntY + Bias;
1673
1674 if (DX >= Max) { bClamp = true; DX = static_cast<int32>(DX) > 0 ? Max - 1 : 0; }
1675 if (DY >= Max) { bClamp = true; DY = static_cast<int32>(DY) > 0 ? Max - 1 : 0; }
1676
1677 Ar.SerializeInt(DX, Max);
1678 Ar.SerializeInt(DY, Max);
1679
1680 return !bClamp;
1681}
1682
1683template<uint32 ScaleFactor, int32 MaxBitsPerComponent>
1684bool ReadPackedVector2D(FVector2D& Value, FArchive& Ar)
1685{
1686 uint32 Bits = 0;
1687
1688 // Serialize how many bits each component will have
1689 Ar.SerializeInt(Bits, MaxBitsPerComponent);
1690
1691 int32 Bias = 1 << (Bits + 1);
1692 uint32 Max = 1 << (Bits + 2);
1693 uint32 DX = 0;
1694 uint32 DY = 0;
1695
1696 Ar.SerializeInt(DX, Max);
1697 Ar.SerializeInt(DY, Max);
1698
1699
1700 float fact = (float)ScaleFactor;
1701
1702 Value.X = (float)(static_cast<int32>(DX) - Bias) / fact;
1703 Value.Y = (float)(static_cast<int32>(DY) - Bias) / fact;
1704
1705 return true;
1706}
1707
1708bool FRenderManagerOperation::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
1709{
1710 bOutSuccess = true;
1711
1712
1713 Ar.SerializeIntPacked(OwnerID);
1714 Ar.SerializeBits(&OperationType, 3);
1715
1716 switch (OperationType)
1717 {
1719 {
1720 Ar << Color;
1721 Ar.SerializeIntPacked(Thickness);
1722
1723 if (Ar.IsSaving())
1724 {
1725 bOutSuccess &= WritePackedVector2D<1, 20>(P1, Ar);
1726 bOutSuccess &= WritePackedVector2D<1, 20>(P2, Ar);
1727 }
1728 else
1729 {
1730 ReadPackedVector2D<1, 20>(P1, Ar);
1731 ReadPackedVector2D<1, 20>(P2, Ar);
1732 }
1733 }break;
1735 {
1736 Ar << Texture;
1737
1738 if (Ar.IsSaving())
1739 {
1740 bOutSuccess &= WritePackedVector2D<1, 20>(P1, Ar);
1741 }
1742 else
1743 {
1744 ReadPackedVector2D<1, 20>(P1, Ar);
1745 }
1746 }break;
1748 {
1749 Ar << Color;
1750 Ar << Material;
1751
1752 uint32 ArrayCt = Tris.Num();
1753 Ar.SerializeIntPacked(ArrayCt);
1754
1755 if (Ar.IsLoading())
1756 {
1757 Tris.Reset(ArrayCt);
1758 Tris.AddUninitialized(ArrayCt);
1759
1760 FRenderManagerTri TriTemp;
1761 for (uint32 i = 0; i < ArrayCt; ++i)
1762 {
1763 ReadPackedVector2D<1, 20>(TriTemp.P1, Ar);
1764 ReadPackedVector2D<1, 20>(TriTemp.P2, Ar);
1765 ReadPackedVector2D<1, 20>(TriTemp.P3, Ar);
1766 Tris[i] = TriTemp;
1767 }
1768 }
1769 else
1770 {
1771 for (uint32 i = 0; i < ArrayCt; ++i)
1772 {
1773 WritePackedVector2D<1, 20>(Tris[i].P1, Ar);
1774 WritePackedVector2D<1, 20>(Tris[i].P2, Ar);
1775 WritePackedVector2D<1, 20>(Tris[i].P3, Ar);
1776 }
1777 }
1778
1779 }break;
1780 }
1781
1782 return bOutSuccess;
1783}
bool WritePackedVector2D(FVector2D Value, FArchive &Ar)
bool ReadPackedVector2D(FVector2D &Value, FArchive &Ar)
UCLASS(ClassGroup = (VRExpansionPlugin))
void InitTextureSend(int32 Width, int32 Height, int32 TotalDataCount, int32 BlobCount, EPixelFormat PixelFormat, bool bIsZipped)
UFUNCTION(Reliable, Client)
int32 BlobNum
UPROPERTY(Transient)
FBPVRReplicatedTextureStore TextureStore
UPROPERTY(Transient)
TWeakObjectPtr< UVRRenderTargetManager > OwningManager
UPROPERTY(Replicated, ReplicatedUsing = OnRep_Manager)
void ReceiveTextureBlob(const TArray< uint8 > &TextureBlob, int32 LocationInData, int32 BlobCount)
UFUNCTION(Reliable, Client)
void Ack_InitTextureSend(int32 TotalDataCount)
UFUNCTION(Reliable, Server, WithValidation)
uint32 OwnersID
UPROPERTY(Replicated)
ARenderTargetReplicationProxy(const FObjectInitializer &ObjectInitializer=FObjectInitializer::Get())
void Ack_ReceiveTextureBlob(int32 BlobCount)
UFUNCTION(Reliable, Server, WithValidation)
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
float DrawRate
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "RenderTargetManager")
bool bIsLoadingTextureBuffer
UPROPERTY(Transient)
UCanvasRenderTarget2D * RenderTarget
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "RenderTargetManager")
TArray< FRenderManagerOperation > LocalRenderOperationStore
bool GenerateTrisFromBoxPlaneIntersection(UPrimitiveComponent *PrimToBoxCheck, FTransform WorldTransformOfPlane, const FPlane &LocalProjectionPlane, FVector2D PlaneSize, FColor UVColor, TArray< FCanvasUVTri > &OutTris)
UFUNCTION(BlueprintCallable, Category = "VRRenderTargetManager|UtilityFunctions")
int32 TextureBlobSize
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "RenderTargetManager")
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override
void AddTextureDrawOperation(FVector2D Position, UTexture2D *TextureToDisplay)
UFUNCTION(BlueprintCallable, Category = "VRRenderTargetManager|DrawingFunctions")
void AddMaterialTrianglesDrawOperation(TArray< FCanvasUVTri > Tris, UMaterial *Material)
UFUNCTION(BlueprintCallable, Category = "VRRenderTargetManager|DrawingFunctions")
bool bIsStoringImage
UPROPERTY(Transient)
int32 MaxBytesPerSecondRate
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "RenderTargetManager")
FBPVRReplicatedTextureStore RenderTargetStore
UPROPERTY(Transient)
FTimerHandle DrawHandle
UPROPERTY()
TArray< FClientRepData > NetRelevancyLog
UPROPERTY(Transient)
TWeakObjectPtr< ARenderTargetReplicationProxy > LocalProxy
UPROPERTY(Transient)
FColor ClearColor
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "RenderTargetManager")
int32 RenderTargetHeight
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "RenderTargetManager")
UVRRenderTargetManager(const FObjectInitializer &ObjectInitializer)
TArray< FRenderManagerOperation > RenderOperationStore
bool bInitiallyReplicateTexture
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "RenderTargetManager")
void DrawOperation(UCanvas *Canvas, const FRenderManagerOperation &Operation)
float PollRelevancyTime
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "RenderTargetManager")
void SendDrawOperations(const TArray< FRenderManagerOperation > &RenderOperationStoreList)
UFUNCTION(Reliable, NetMultiCast, WithValidation)
TQueue< FRenderDataStore * > RenderDataQueue
virtual void BeginPlay() override
int32 RenderTargetWidth
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "RenderTargetManager")
void AddLineDrawOperation(FVector2D Point1, FVector2D Point2, FColor Color, int32 Thickness)
UFUNCTION(BlueprintCallable, Category = "VRRenderTargetManager|DrawingFunctions")
static void RLEWriteContinueFlag(uint32 Count, uint8 **loc)
static void RLEWriteRunFlag(uint32 Count, uint8 **loc, TArray< DataType > &Data, bool bCompressed)
static void RLEDecodeLine(TArray< uint8 > *LineToDecode, TArray< DataType > *DecodedLine, bool bCompressed)
static bool RLEEncodeLine(TArray< DataType > *LineToEncode, TArray< uint8 > *EncodedLine)
static bool RLEEncodeBuffer(DataType *BufferToEncode, uint32 EncodeLength, TArray< uint8 > *EncodedLine)
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
TArray< uint16 > UnpackedData
UPROPERTY(Transient)
TArray< uint8 > PackedData
UPROPERTY(Transient)
bool bIsZipped
UPROPERTY(Transient)
bool NetSerialize(FArchive &Ar, class UPackageMap *Map, bool &bOutSuccess)
uint32 Width
UPROPERTY(Transient)
bool bIsDirty
UPROPERTY()
bool bIsRelevant
UPROPERTY()
TWeakObjectPtr< APlayerController > PC
UPROPERTY()
TWeakObjectPtr< ARenderTargetReplicationProxy > ReplicationProxy
UPROPERTY()
FRenderCommandFence RenderFence
TArray< FColor > ColorData
ERenderManagerOperationType OperationType
UPROPERTY()
TSoftObjectPtr< UTexture2D > Texture
UPROPERTY()
TSoftObjectPtr< UMaterial > Material
UPROPERTY()
bool NetSerialize(FArchive &Ar, class UPackageMap *Map, bool &bOutSuccess)
TArray< FRenderManagerTri > Tris
UPROPERTY()