Skip to content

Instantly share code, notes, and snippets.

@pixeltris
Created November 30, 2014 15:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pixeltris/40fde2a6b4d8b68caeee to your computer and use it in GitHub Desktop.
Save pixeltris/40fde2a6b4d8b68caeee to your computer and use it in GitHub Desktop.
Canvas / HUD clipping for Unreal Engine using scissor rects.
#include "ClipCanvas.h"
#include "HUDEx.h"
class FCanvasScissorRectItem : public FCanvasItem
{
public:
bool bEnable;
int32 MinX;
int32 MaxX;
int32 MinY;
int32 MaxY;
FCanvasScissorRectItem(bool enable, int32 minX, int32 minY, int32 maxX, int32 maxY) :
FCanvasItem(FVector2D::ZeroVector),
bEnable(enable),
MinX(minX),
MaxX(maxX),
MinY(minY),
MaxY(maxY)
{
}
FCanvasScissorRectItem() :
FCanvasScissorRectItem(false, 0, 0, 0, 0)
{
}
public:
void Draw(FCanvas* InCanvas);
};
class FCanvasScissorRectRenderItem : public FCanvasBaseRenderItem
{
public:
FCanvasScissorRectItem ScissorInfo;
FCanvasScissorRectRenderItem(FCanvasScissorRectItem& scissorInfo)
{
ScissorInfo = scissorInfo;
}
virtual bool Render_RenderThread(FRHICommandListImmediate& RHICmdList, const FCanvas* Canvas) override
{
RHICmdList.SetScissorRect(ScissorInfo.bEnable, ScissorInfo.MinX, ScissorInfo.MinY, ScissorInfo.MaxX, ScissorInfo.MaxY);
return false;
}
virtual bool Render_GameThread(const FCanvas* Canvas) override
{
struct FCanvasScissorRectParameters
{
bool bEnable;
int32 MinX;
int32 MaxX;
int32 MinY;
int32 MaxY;
};
FCanvasScissorRectParameters ScissorParameters =
{
ScissorInfo.bEnable,
ScissorInfo.MinX,
ScissorInfo.MaxX,
ScissorInfo.MinY,
ScissorInfo.MaxY
};
ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
CanvasScissorRectCommand,
FCanvasScissorRectParameters, Parameters, ScissorParameters,
{
RHICmdList.SetScissorRect(Parameters.bEnable, Parameters.MinX, Parameters.MinY, Parameters.MaxX, Parameters.MaxY);
});
return false;
}
};
void FCanvasScissorRectItem::Draw(FCanvas* InCanvas)
{
Canvas_GetSortElement(*InCanvas, InCanvas->TopDepthSortKey()).RenderBatchArray.Add(new FCanvasScissorRectRenderItem(*this));
}
FCanvas::FCanvasSortElement& Canvas_GetSortElement(FCanvas& canvas, int32 DepthSortKey)
{
// Optimization to resuse last index so that the more expensive Find() does not
// need to be called as much.
if (canvas.SortedElements.IsValidIndex(canvas.LastElementIndex))
{
FCanvas::FCanvasSortElement & LastElement = canvas.SortedElements[canvas.LastElementIndex];
if (LastElement.DepthSortKey == DepthSortKey)
{
return LastElement;
}
}
// find the FCanvasSortElement array entry based on the sortkey
int32 ElementIdx = INDEX_NONE;
int32* ElementIdxFromMap = canvas.SortedElementLookupMap.Find(DepthSortKey);
if (ElementIdxFromMap)
{
ElementIdx = *ElementIdxFromMap;
checkSlow(canvas.SortedElements.IsValidIndex(ElementIdx));
}
// if it doesn't exist then add a new entry (no duplicates allowed)
else
{
new(canvas.SortedElements)FCanvas::FCanvasSortElement(DepthSortKey);
ElementIdx = canvas.SortedElements.Num() - 1;
// keep track of newly added array index for later lookup
canvas.SortedElementLookupMap.Add(DepthSortKey, ElementIdx);
}
canvas.LastElementIndex = ElementIdx;
return canvas.SortedElements[ElementIdx];
}
void ClipCanvas(UCanvas* canvas, bool enable, int32 minX, int32 minY, int32 maxX, int32 maxY)
{
if (canvas)
{
ClipCanvas(canvas->Canvas, enable, minX, minY, maxX, maxY);
}
}
void ClipCanvas(FCanvas* canvas, bool enable, int32 minX, int32 minY, int32 maxX, int32 maxY)
{
if (canvas)
{
FCanvasScissorRectItem item(enable, minX, minY, maxX, maxY);
canvas->DrawItem(item);
}
}
void ClipCanvas(UCanvas* canvas, int32 minX, int32 minY, int32 maxX, int32 maxY)
{
ClipCanvas(canvas, true, minX, minY, maxX, maxY);
}
void ClipCanvas(FCanvas* canvas, int32 minX, int32 minY, int32 maxX, int32 maxY)
{
ClipCanvas(canvas, true, minX, minY, maxX, maxY);
}
void ClearCanvasClip(UCanvas* canvas)
{
ClipCanvas(canvas, false, 0, 0, 0, 0);
}
void ClearCanvasClip(FCanvas* canvas)
{
ClipCanvas(canvas, false, 0, 0, 0, 0);
}
// Blueprint related code below, remove if not required
AHUDEx::AHUDEx(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP)
{
}
void AHUDEx::ClipHUD(int32 minX, int32 minY, int32 maxX, int32 maxY)
{
ClipCanvas(Canvas, true, minX, minY, maxX, maxY);
}
void AHUDEx::ClearHUDClip()
{
ClearCanvasClip(Canvas);
}
#pragma once
// Could call GetSortElement directly but it seems to cause a linker errors
FCanvas::FCanvasSortElement& Canvas_GetSortElement(FCanvas& canvas, int32 DepthSortKey);
void ClipCanvas(UCanvas* canvas, bool enable, int32 minX, int32 minY, int32 maxX, int32 maxY);
void ClipCanvas(FCanvas* canvas, bool enable, int32 minX, int32 minY, int32 maxX, int32 maxY);
void ClipCanvas(UCanvas* canvas, int32 minX, int32 minY, int32 maxX, int32 maxY);
void ClipCanvas(FCanvas* canvas, int32 minX, int32 minY, int32 maxX, int32 maxY);
void ClearCanvasClip(UCanvas* canvas);
void ClearCanvasClip(FCanvas* canvas);
#pragma once
#include "HUDEx.generated.h"
UCLASS()
class AHUDEx : public AHUD
{
GENERATED_UCLASS_BODY()
UFUNCTION(BlueprintCallable, Category = HUD, meta = (FriendlyName = "Clip"))
void ClipHUD(int32 minX, int32 minY, int32 maxX, int32 maxY);
UFUNCTION(BlueprintCallable, Category = HUD, meta = (FriendlyName = "Clear Clip"))
void ClearHUDClip();
};
@johny7
Copy link

johny7 commented Feb 25, 2020

With Unreal 4.24 ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER will look like this:

	RenderScope.EnqueueRenderCommand([ScissorParameters](FRHICommandListImmediate& RHICmdList)
	{
		RHICmdList.SetScissorRect(ScissorParameters.bEnable, ScissorParameters.MinX, ScissorParameters.MinY, ScissorParameters.MaxX, ScissorParameters.MaxY);
	});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment