Add love.graphics.setStencilMode. Remove old stencil API.

- Add setStencilMode(drawaction, comparemode, value = 0, readmask = 0xFF, writemask = 0xFF).
- Add getStencilMode.
- Remove love.graphics.stencil.
- Remove love.graphics.set/getStencilTest.

Note that the new setStencilMode API does not clear the stencil buffer, and does not turn off color writes (it can still be done manually), unlike love.graphics.stencil.

Fixes #1161.
Fixes #1251.
This commit is contained in:
Alex Szpakowski
2022-01-22 23:36:07 -04:00
parent 173fe3dab5
commit 6dbb7fa5de
10 changed files with 148 additions and 221 deletions
+1 -4
View File
@@ -95,10 +95,7 @@ public:
void setScissor(const Rect &rect) override;
void setScissor() override;
void drawToStencilBuffer(StencilAction action, int value) override;
void stopDrawToStencilBuffer() override;
void setStencilTest(CompareMode compare, int value) override;
void setStencilMode(StencilAction action, CompareMode compare, int value, uint32 readmask, uint32 writemask) override;
void setDepthMode(CompareMode compare, bool write) override;
+24 -50
View File
@@ -797,7 +797,15 @@ id<MTLDepthStencilState> Graphics::getCachedDepthStencilState(const DepthState &
MTLStencilDescriptor *stencildesc = [MTLStencilDescriptor new];
stencildesc.stencilCompareFunction = getMTLCompareFunction(stencil.compare);
/**
* GPUs do the comparison opposite to what makes sense for love's API. For
* example, if the compare function is GREATER then the stencil test will
* pass if the reference value is greater than the value in the stencil
* buffer. With our API it's more intuitive to assume that
* setStencilMode(STENCIL_KEEP, COMPARE_GREATER, 4) will make it pass if the
* stencil buffer has a value greater than 4.
**/
stencildesc.stencilCompareFunction = getMTLCompareFunction(getReversedCompareMode(stencil.compare));
stencildesc.stencilFailureOperation = MTLStencilOperationKeep;
stencildesc.depthFailureOperation = MTLStencilOperationKeep;
stencildesc.depthStencilPassOperation = getMTLStencilOperation(stencil.action);
@@ -922,15 +930,7 @@ void Graphics::applyRenderState(id<MTLRenderCommandEncoder> encoder, const Verte
depth.compare = state.depthTest;
depth.write = state.depthWrite;
StencilState stencil = state.stencil;
if (stencil.action != STENCIL_KEEP)
{
// FIXME
stencil.compare = COMPARE_ALWAYS;
}
id<MTLDepthStencilState> mtlstate = getCachedDepthStencilState(depth, stencil);
id<MTLDepthStencilState> mtlstate = getCachedDepthStencilState(depth, state.stencil);
[encoder setDepthStencilState:mtlstate];
}
@@ -1671,56 +1671,30 @@ void Graphics::setScissor()
}
}
void Graphics::drawToStencilBuffer(StencilAction action, int value)
void Graphics::setStencilMode(StencilAction action, CompareMode compare, int value, uint32 readmask, uint32 writemask)
{
DisplayState &state = states.back();
const auto &rts = state.renderTargets;
love::graphics::Texture *dstexture = rts.depthStencil.texture.get();
if (!isRenderTargetActive() && !windowHasStencil)
throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer.");
else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat())))
throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas.");
if (action != STENCIL_KEEP)
{
const auto &rts = state.renderTargets;
love::graphics::Texture *dstexture = rts.depthStencil.texture.get();
if (!isRenderTargetActive() && !windowHasStencil)
throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer.");
else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat())))
throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas.");
}
flushBatchedDraws();
state.stencil.action = action;
state.stencil.compare = compare;
state.stencil.value = value;
state.stencil.readMask = readmask;
state.stencil.writeMask = writemask;
dirtyRenderState |= STATEBIT_STENCIL;
// TODO
}
void Graphics::stopDrawToStencilBuffer()
{
DisplayState &state = states.back();
if (state.stencil.action == STENCIL_KEEP)
return;
flushBatchedDraws();
state.stencil.action = STENCIL_KEEP;
// Revert the color write mask.
setColorMask(state.colorMask);
// Use the user-set stencil test state when writes are disabled.
setStencilTest(state.stencil.compare, state.stencil.value);
dirtyRenderState |= STATEBIT_STENCIL;
}
void Graphics::setStencilTest(CompareMode compare, int value)
{
// TODO
DisplayState &state = states.back();
if (state.stencil.compare != compare || state.stencil.value != value)
{
state.stencil.compare = compare;
state.stencil.value = value;
dirtyRenderState |= STATEBIT_STENCIL;
}
}
void Graphics::setDepthMode(CompareMode compare, bool write)