|
|
@@ -15,6 +15,25 @@
|
|
|
namespace anki
|
|
|
{
|
|
|
|
|
|
+class Canvas::DrawingState
|
|
|
+{
|
|
|
+public:
|
|
|
+ ShaderProgramPtr m_program;
|
|
|
+ Array<U8, 128 - sizeof(Vec4)> m_extraPushConstants;
|
|
|
+ U32 m_extraPushConstantSize = 0;
|
|
|
+};
|
|
|
+
|
|
|
+/// Custom command that can manipulate the drawing state.
|
|
|
+class Canvas::CustomCommand
|
|
|
+{
|
|
|
+public:
|
|
|
+ virtual ~CustomCommand()
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void operator()(DrawingState& state) = 0;
|
|
|
+};
|
|
|
+
|
|
|
Canvas::Canvas(UiManager* manager)
|
|
|
: UiObject(manager)
|
|
|
{
|
|
|
@@ -53,7 +72,11 @@ Error Canvas::init(FontPtr font, U32 fontHeight, U32 width, U32 height)
|
|
|
samplerInit.m_minMagFilter = SamplingFilter::LINEAR;
|
|
|
samplerInit.m_mipmapFilter = SamplingFilter::LINEAR;
|
|
|
samplerInit.m_addressing = SamplingAddressing::REPEAT;
|
|
|
- m_sampler = m_manager->getGrManager().newSampler(samplerInit);
|
|
|
+ m_linearLinearRepeatSampler = m_manager->getGrManager().newSampler(samplerInit);
|
|
|
+
|
|
|
+ samplerInit.m_minMagFilter = SamplingFilter::NEAREST;
|
|
|
+ samplerInit.m_mipmapFilter = SamplingFilter::NEAREST;
|
|
|
+ m_nearestNearestRepeatSampler = m_manager->getGrManager().newSampler(samplerInit);
|
|
|
|
|
|
// Allocator
|
|
|
m_stackAlloc = StackAllocator<U8>(getAllocator().getMemoryPool().getAllocationCallback(),
|
|
|
@@ -241,8 +264,6 @@ void Canvas::appendToCommandBufferInternal(CommandBufferPtr& cmdb)
|
|
|
|
|
|
cmdb->bindIndexBuffer(indicesToken.m_buffer, indicesToken.m_offset, IndexType::U16);
|
|
|
|
|
|
- cmdb->bindSampler(0, 0, m_sampler);
|
|
|
-
|
|
|
// Will project scissor/clipping rectangles into framebuffer space
|
|
|
const Vec2 clipOff = drawData.DisplayPos; // (0,0) unless using multi-viewports
|
|
|
const Vec2 clipScale = drawData.FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
|
|
@@ -250,6 +271,7 @@ void Canvas::appendToCommandBufferInternal(CommandBufferPtr& cmdb)
|
|
|
// Render
|
|
|
U32 vertOffset = 0;
|
|
|
U32 idxOffset = 0;
|
|
|
+ DrawingState state;
|
|
|
for(I32 n = 0; n < drawData.CmdListsCount; n++)
|
|
|
{
|
|
|
const ImDrawList& cmdList = *drawData.CmdLists[n];
|
|
|
@@ -259,7 +281,9 @@ void Canvas::appendToCommandBufferInternal(CommandBufferPtr& cmdb)
|
|
|
if(pcmd.UserCallback)
|
|
|
{
|
|
|
// User callback (registered via ImDrawList::AddCallback)
|
|
|
- pcmd.UserCallback(&cmdList, &pcmd);
|
|
|
+ CustomCommand* userCmd = static_cast<CustomCommand*>(pcmd.UserCallbackData);
|
|
|
+ (*userCmd)(state);
|
|
|
+ m_stackAlloc.deleteInstance(userCmd);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
@@ -286,25 +310,48 @@ void Canvas::appendToCommandBufferInternal(CommandBufferPtr& cmdb)
|
|
|
cmdb->setScissor(U32(clipRect.x()), U32(clipRect.y()), U32(clipRect.z() - clipRect.x()),
|
|
|
U32(clipRect.w() - clipRect.y()));
|
|
|
|
|
|
- if(pcmd.TextureId)
|
|
|
+ // Program
|
|
|
+ if(state.m_program.isCreated())
|
|
|
+ {
|
|
|
+ cmdb->bindShaderProgram(state.m_program);
|
|
|
+ }
|
|
|
+ else if(pcmd.TextureId)
|
|
|
{
|
|
|
cmdb->bindShaderProgram(m_grProgs[RGBA_TEX]);
|
|
|
-
|
|
|
- TextureView* view = static_cast<TextureView*>(pcmd.TextureId);
|
|
|
- cmdb->bindTexture(0, 1, TextureViewPtr(view), TextureUsageBit::SAMPLED_FRAGMENT);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
cmdb->bindShaderProgram(m_grProgs[NO_TEX]);
|
|
|
}
|
|
|
|
|
|
- // Push constants. TODO: Set them once
|
|
|
- Vec4 transform;
|
|
|
- transform.x() = 2.0f / drawData.DisplaySize.x;
|
|
|
- transform.y() = -2.0f / drawData.DisplaySize.y;
|
|
|
- transform.z() = (drawData.DisplayPos.x / drawData.DisplaySize.x) * 2.0f - 1.0f;
|
|
|
- transform.w() = -((drawData.DisplayPos.y / drawData.DisplaySize.y) * 2.0f - 1.0f);
|
|
|
- cmdb->setPushConstants(&transform, sizeof(transform));
|
|
|
+ // Bindings
|
|
|
+ if(pcmd.TextureId)
|
|
|
+ {
|
|
|
+ UiImageId id(pcmd.TextureId);
|
|
|
+ TextureViewPtr view(numberToPtr<TextureView*>(id.m_bits.m_textureViewPtr));
|
|
|
+
|
|
|
+ cmdb->bindSampler(0, 0,
|
|
|
+ (id.m_bits.m_pointSampling) ? m_nearestNearestRepeatSampler
|
|
|
+ : m_linearLinearRepeatSampler);
|
|
|
+ cmdb->bindTexture(0, 1, view, TextureUsageBit::SAMPLED_FRAGMENT);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Push constants
|
|
|
+ class PC
|
|
|
+ {
|
|
|
+ public:
|
|
|
+ Vec4 m_transform;
|
|
|
+ Array<U8, sizeof(DrawingState::m_extraPushConstants)> m_extra;
|
|
|
+ } pc;
|
|
|
+ pc.m_transform.x() = 2.0f / drawData.DisplaySize.x;
|
|
|
+ pc.m_transform.y() = -2.0f / drawData.DisplaySize.y;
|
|
|
+ pc.m_transform.z() = (drawData.DisplayPos.x / drawData.DisplaySize.x) * 2.0f - 1.0f;
|
|
|
+ pc.m_transform.w() = -((drawData.DisplayPos.y / drawData.DisplaySize.y) * 2.0f - 1.0f);
|
|
|
+ if(state.m_extraPushConstantSize)
|
|
|
+ {
|
|
|
+ memcpy(&pc.m_extra[0], &state.m_extraPushConstants[0], state.m_extraPushConstantSize);
|
|
|
+ }
|
|
|
+ cmdb->setPushConstants(&pc, sizeof(Vec4) + state.m_extraPushConstantSize);
|
|
|
|
|
|
// Draw
|
|
|
cmdb->drawElements(PrimitiveTopology::TRIANGLES, pcmd.ElemCount, 1, idxOffset, vertOffset);
|
|
|
@@ -320,4 +367,45 @@ void Canvas::appendToCommandBufferInternal(CommandBufferPtr& cmdb)
|
|
|
cmdb->setCullMode(FaceSelectionBit::BACK);
|
|
|
}
|
|
|
|
|
|
+void Canvas::setShaderProgram(ShaderProgramPtr program, const void* extraPushConstants, U32 extraPushConstantSize)
|
|
|
+{
|
|
|
+ class Command : public CustomCommand
|
|
|
+ {
|
|
|
+ public:
|
|
|
+ ShaderProgramPtr m_prog;
|
|
|
+ Array<U8, sizeof(DrawingState::m_extraPushConstants)> m_extraPushConstants;
|
|
|
+ U32 m_extraPushConstantSize;
|
|
|
+
|
|
|
+ void operator()(DrawingState& state) override
|
|
|
+ {
|
|
|
+ state.m_program = m_prog;
|
|
|
+ if(m_extraPushConstantSize)
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(m_extraPushConstantSize <= sizeof(m_extraPushConstants));
|
|
|
+ memcpy(&state.m_extraPushConstants[0], &m_extraPushConstants[0], m_extraPushConstantSize);
|
|
|
+ }
|
|
|
+ state.m_extraPushConstantSize = m_extraPushConstantSize;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ Command* newcmd = m_stackAlloc.newInstance<Command>();
|
|
|
+ newcmd->m_prog = program;
|
|
|
+ if(extraPushConstantSize)
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(extraPushConstants);
|
|
|
+ memcpy(&newcmd->m_extraPushConstants[0], extraPushConstants, extraPushConstantSize);
|
|
|
+ newcmd->m_extraPushConstantSize = extraPushConstantSize;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ newcmd->m_extraPushConstantSize = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ ImGui::GetWindowDrawList()->AddCallback(
|
|
|
+ [](const ImDrawList* list, const ImDrawCmd* cmd) {
|
|
|
+ // Do nothing, only care about the user data
|
|
|
+ },
|
|
|
+ newcmd);
|
|
|
+}
|
|
|
+
|
|
|
} // end namespace anki
|