// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Delegate.h"
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Platform/CriticalSection.h"
#include "Engine/Scripting/ScriptingObjectReference.h"
#include "Engine/Scripting/ScriptingType.h"
#include "PostProcessBase.h"
#include "RenderView.h"
class GPUDevice;
class GPUContext;
class GPUTexture;
class GPUTextureView;
class GPUSwapChain;
class RenderBuffers;
struct RenderContext;
class Camera;
class Actor;
///
/// Allows to perform custom rendering using graphics pipeline.
///
API_CLASS() class FLAXENGINE_API RenderTask : public PersistentScriptingObject
{
DECLARE_SCRIPTING_TYPE(RenderTask);
///
/// List with all registered tasks
///
static Array Tasks;
///
/// Static locker for render tasks list
///
static CriticalSection TasksLocker;
///
/// Amount of tasks rendered during last frame
///
static int32 TasksDoneLastFrame;
///
/// Draws all tasks. Called only during rendering by the graphics device.
///
static void DrawAll();
private:
RenderTask* _prevTask = nullptr;
public:
///
/// Finalizes an instance of the class.
///
virtual ~RenderTask();
public:
///
/// Gets or sets a value indicating whether task is enabled.
///
API_FIELD() bool Enabled = true;
///
/// The order of the task. Used for tasks rendering order. Lower first, higher later.
///
API_FIELD() int32 Order = 0;
///
/// The amount of frames rendered by this task. It is auto incremented on task drawing.
///
API_FIELD(ReadOnly) int32 FrameCount = 0;
///
/// The output window swap chain. Optional, used only when rendering to native window backbuffer.
///
GPUSwapChain* SwapChain = nullptr;
///
/// The index of the frame when this task was last time rendered.
///
uint64 LastUsedFrame = 0;
///
/// Action fired on task rendering.
///
API_EVENT() Delegate Render;
///
/// Action fired on task rendering begin.
///
API_EVENT() Delegate Begin;
///
/// Action fired on task rendering end.
///
API_EVENT() Delegate End;
///
/// Action fired just after frame present.
///
API_EVENT() Delegate Present;
///
/// Determines whether this task can be rendered.
///
/// true if this task can be rendered; otherwise, false.
API_PROPERTY() virtual bool CanDraw() const;
///
/// Called by graphics device to draw this task. Can be used to invoke task rendering nested inside another task - use on own risk!
///
API_FUNCTION() virtual void OnDraw();
///
/// Called on task rendering begin.
///
/// The GPU context.
virtual void OnBegin(GPUContext* context);
///
/// Called on task rendering.
///
/// The GPU context.
virtual void OnRender(GPUContext* context);
///
/// Called on task rendering end.
///
/// The GPU context.
virtual void OnEnd(GPUContext* context);
///
/// Presents frame to the output.
///
/// True if use vertical synchronization to lock frame rate.
virtual void OnPresent(bool vsync);
///
/// Changes the buffers and output size. Does nothing if size won't change. Called by window or user to resize rendering buffers.
///
/// The width.
/// The height.
/// True if cannot resize the buffers.
API_FUNCTION() virtual bool Resize(int32 width, int32 height);
public:
bool operator<(const RenderTask& other) const
{
return Order < other.Order;
}
};
///
/// Defines actors to draw sources.
///
API_ENUM(Attributes="Flags") enum class ActorsSources
{
///
/// The actors won't be rendered.
///
None = 0,
///
/// The actors from the loaded scenes.
///
Scenes = 1,
///
/// The actors from the custom collection.
///
CustomActors = 2,
///
/// The actors from the loaded scenes and custom collection.
///
ScenesAndCustomActors = Scenes | CustomActors,
};
DECLARE_ENUM_OPERATORS(ActorsSources);
///
/// Wrapper for PostProcessBase that allows to render to customized managed postFx.
/// TODO: add support for managed inheritance of custom native types with proper spawn handling (like for ManagedScript)
///
///
class ManagedPostProcessEffect : public PostProcessBase
{
public:
///
/// The script to use. Inherits from C# class 'PostProcessEffect'.
///
Script* Target = nullptr;
public:
///
/// Fetches the information about the PostFx location from the managed object.
///
void FetchInfo();
public:
// [PostProcessBase]
bool IsLoaded() const override;
void Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output) override;
};
///
/// Render task which draws scene actors into the output buffer.
///
///
API_CLASS() class FLAXENGINE_API SceneRenderTask : public RenderTask
{
DECLARE_SCRIPTING_TYPE(SceneRenderTask);
///
/// Finalizes an instance of the class.
///
~SceneRenderTask();
public:
///
/// True if the current frame is after the camera cut. Used to clear the temporal effects history and prevent visual artifacts blended from the previous frames.
///
bool IsCameraCut = true;
///
/// Marks the next rendered frame as camera cut. Used to clear the temporal effects history and prevent visual artifacts blended from the previous frames.
///
API_FUNCTION() void CameraCut()
{
IsCameraCut = true;
}
///
/// The output texture (can be null if using rendering to window swap chain). Can be sued to redirect the default scene rendering output to a texture.
///
API_FIELD() GPUTexture* Output = nullptr;
///
/// The scene rendering buffers. Created and managed by the task.
///
API_FIELD(ReadOnly) RenderBuffers* Buffers = nullptr;
///
/// The scene rendering camera. Can be used to override the rendering view properties based on the current camera setup.
///
API_FIELD() Camera* Camera = nullptr;
///
/// The render view description.
///
API_FIELD() RenderView View;
///
/// The actors source to use (configures what objects to render).
///
API_FIELD() ActorsSources ActorsSource = ActorsSources::Scenes;
///
/// The custom set of actors to render.
///
Array CustomActors;
///
/// Adds the custom actor to the rendering.
///
/// The actor.
API_FUNCTION() void AddCustomActor(Actor* actor)
{
CustomActors.Add(actor);
}
///
/// Removes the custom actor from the rendering.
///
/// The actor.
API_FUNCTION() void RemoveCustomActor(Actor* actor)
{
CustomActors.Remove(actor);
}
///
/// The custom post fx to render (managed).
///
Array CustomPostFx;
public:
///
/// The action called on view rendering to collect draw calls. It allows to extend rendering pipeline and draw custom geometry non-existing in the scene or custom actors set.
///
API_EVENT() Delegate CollectDrawCalls;
///
/// Calls collecting postFx volumes for rendering.
///
/// The rendering context.
virtual void CollectPostFxVolumes(RenderContext& renderContext);
///
/// Calls drawing scene objects.
///
/// The rendering context.
virtual void OnCollectDrawCalls(RenderContext& renderContext);
///
/// The action called after scene rendering. Can be used to render additional visual elements to the output.
///
API_EVENT() Delegate PostRender;
///
/// Called after scene rendering. Can be used to render additional visual elements to the output.
///
/// The GPU commands context.
/// The rendering context.
virtual void OnPostRender(GPUContext* context, RenderContext& renderContext);
public:
///
/// Gets the rendering render task viewport.
///
API_PROPERTY() Viewport GetViewport() const;
///
/// Gets the rendering output view.
///
API_PROPERTY() GPUTextureView* GetOutputView() const;
public:
// [RenderTask]
bool Resize(int32 width, int32 height) override;
bool CanDraw() const override;
void OnBegin(GPUContext* context) override;
void OnRender(GPUContext* context) override;
void OnEnd(GPUContext* context) override;
};
///
/// The main game rendering task used by the engine.
///
///
/// For Main Render Task its may be null because game can be rendered directly to the native window backbuffer.
/// This allows to increase game rendering performance (reduced memory usage and data transfer).
/// User should use post effects pipeline to modify the final frame.
///
///
API_CLASS() class FLAXENGINE_API MainRenderTask : public SceneRenderTask
{
DECLARE_SCRIPTING_TYPE(MainRenderTask);
///
/// Finalizes an instance of the class.
///
~MainRenderTask();
public:
///
/// Gets the main game rendering task. Use it to plug custom rendering logic for your game.
///
API_FIELD(ReadOnly) static MainRenderTask* Instance;
public:
// [SceneRenderTask]
void OnBegin(GPUContext* context) override;
};
///
/// The high-level renderer context. Used to collect the draw calls for the scene rendering. Can be used to perform a custom rendering.
///
API_STRUCT() struct RenderContext
{
DECLARE_SCRIPTING_TYPE_MINIMAL(RenderContext);
///
/// The render buffers.
///
API_FIELD() RenderBuffers* Buffers = nullptr;
///
/// The render list.
///
API_FIELD() RenderList* List = nullptr;
///
/// The render view.
///
API_FIELD() RenderView View;
///
/// The proxy render view used to synchronize objects level of detail during rendering (eg. during shadow maps rendering passes). It's optional.
///
API_FIELD() RenderView* LodProxyView = nullptr;
///
/// The scene rendering task that is a source of renderable objects (optional).
///
API_FIELD() SceneRenderTask* Task = nullptr;
RenderContext()
{
}
RenderContext(SceneRenderTask* task);
};