mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
Add (low level) functionality to allow rendering 3D Meshes.
- Add love.graphics.setDepthMode(testcomparison, enablewrites). - Add love.graphics.setMeshCullMode. - Add love.graphics.setFrontFaceWinding. Depth testing and depth writes require a depth buffer to work. The mesh cull mode controls whether front/back faces of a mesh are culled. The front face winding determines whether a clockwise or counterclockwise-oriented face in a mesh is considered front facing. --HG-- branch : minor
This commit is contained in:
@@ -4012,7 +4012,7 @@
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0900;
|
||||
LastUpgradeCheck = 0920;
|
||||
TargetAttributes = {
|
||||
FA0B78DC1A958B90000E1D17 = {
|
||||
CreatedOnToolsVersion = 6.1.1;
|
||||
|
||||
@@ -326,7 +326,7 @@
|
||||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0900;
|
||||
LastUpgradeCheck = 0920;
|
||||
TargetAttributes = {
|
||||
FA0B7F051A95AAF3000E1D17 = {
|
||||
CreatedOnToolsVersion = 6.1.1;
|
||||
|
||||
@@ -382,16 +382,17 @@ Matrix4 Matrix4::inverse() const
|
||||
return inv;
|
||||
}
|
||||
|
||||
Matrix4 Matrix4::ortho(float left, float right, float bottom, float top)
|
||||
Matrix4 Matrix4::ortho(float left, float right, float bottom, float top, float near, float far)
|
||||
{
|
||||
Matrix4 m;
|
||||
|
||||
m.e[0] = 2.0f / (right - left);
|
||||
m.e[5] = 2.0f / (top - bottom);
|
||||
m.e[10] = -1.0;
|
||||
m.e[10] = -2.0f / (far - near);
|
||||
|
||||
m.e[12] = -(right + left) / (right - left);
|
||||
m.e[13] = -(top + bottom) / (top - bottom);
|
||||
m.e[14] = -(far + near) / (far - near);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
+2
-3
@@ -218,10 +218,9 @@ public:
|
||||
Matrix4 inverse() const;
|
||||
|
||||
/**
|
||||
* Creates a new orthographic projection matrix with depth in the range of
|
||||
* [-1, 1].
|
||||
* Creates a new orthographic projection matrix.
|
||||
**/
|
||||
static Matrix4 ortho(float left, float right, float bottom, float top);
|
||||
static Matrix4 ortho(float left, float right, float bottom, float top, float near, float far);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -471,7 +471,7 @@ std::vector<Font::DrawCommand> Font::generateVertices(const ColoredCodepoints &c
|
||||
// Add kerning to the current horizontal offset.
|
||||
dx += getKerning(prevglyph, g);
|
||||
|
||||
if (glyph.texture != 0)
|
||||
if (glyph.texture != nullptr)
|
||||
{
|
||||
// Copy the vertices and set their colors and relative positions.
|
||||
for (int j = 0; j < 4; j++)
|
||||
|
||||
@@ -374,6 +374,10 @@ void Graphics::restoreState(const DisplayState &s)
|
||||
setScissor();
|
||||
|
||||
setStencilTest(s.stencilCompare, s.stencilTestValue);
|
||||
setDepthMode(s.depthTest, s.depthWrite);
|
||||
|
||||
setMeshCullMode(s.meshCullMode);
|
||||
setFrontFaceWinding(s.winding);
|
||||
|
||||
setFont(s.font.get());
|
||||
setShader(s.shader.get());
|
||||
@@ -417,6 +421,14 @@ void Graphics::restoreStateChecked(const DisplayState &s)
|
||||
if (s.stencilCompare != cur.stencilCompare || s.stencilTestValue != cur.stencilTestValue)
|
||||
setStencilTest(s.stencilCompare, s.stencilTestValue);
|
||||
|
||||
if (s.depthTest != cur.depthTest || s.depthWrite != cur.depthWrite)
|
||||
setDepthMode(s.depthTest, s.depthWrite);
|
||||
|
||||
setMeshCullMode(s.meshCullMode);
|
||||
|
||||
if (s.winding != cur.winding)
|
||||
setFrontFaceWinding(s.winding);
|
||||
|
||||
setFont(s.font.get());
|
||||
setShader(s.shader.get());
|
||||
|
||||
@@ -788,13 +800,46 @@ bool Graphics::getScissor(Rect &rect) const
|
||||
return state.scissor;
|
||||
}
|
||||
|
||||
void Graphics::getStencilTest(CompareMode &compare, int &value)
|
||||
void Graphics::setStencilTest()
|
||||
{
|
||||
setStencilTest(COMPARE_ALWAYS, 0);
|
||||
}
|
||||
|
||||
void Graphics::getStencilTest(CompareMode &compare, int &value) const
|
||||
{
|
||||
const DisplayState &state = states.back();
|
||||
compare = state.stencilCompare;
|
||||
value = state.stencilTestValue;
|
||||
}
|
||||
|
||||
void Graphics::setDepthMode()
|
||||
{
|
||||
setDepthMode(COMPARE_ALWAYS, false);
|
||||
}
|
||||
|
||||
void Graphics::getDepthMode(CompareMode &compare, bool &write) const
|
||||
{
|
||||
const DisplayState &state = states.back();
|
||||
compare = state.depthTest;
|
||||
write = state.depthWrite;
|
||||
}
|
||||
|
||||
void Graphics::setMeshCullMode(CullMode cull)
|
||||
{
|
||||
// Handled inside the draw() graphics API implementations.
|
||||
states.back().meshCullMode = cull;
|
||||
}
|
||||
|
||||
CullMode Graphics::getMeshCullMode() const
|
||||
{
|
||||
return states.back().meshCullMode;
|
||||
}
|
||||
|
||||
vertex::Winding Graphics::getFrontFaceWinding() const
|
||||
{
|
||||
return states.back().winding;
|
||||
}
|
||||
|
||||
Graphics::ColorMask Graphics::getColorMask() const
|
||||
{
|
||||
return states.back().colorMask;
|
||||
@@ -1051,14 +1096,26 @@ void Graphics::flushStreamDraws()
|
||||
if (sbstate.indexCount > 0)
|
||||
{
|
||||
usedsizes[2] = sizeof(uint16) * sbstate.indexCount;
|
||||
size_t offset = sbstate.indexBuffer->unmap(usedsizes[2]);
|
||||
|
||||
DrawIndexedCommand cmd(&attributes, &buffers, sbstate.indexBuffer);
|
||||
cmd.primitiveType = sbstate.primitiveMode;
|
||||
cmd.indexCount = sbstate.indexCount;
|
||||
cmd.indexType = INDEX_UINT16;
|
||||
cmd.indexBufferOffset = sbstate.indexBuffer->unmap(usedsizes[2]);
|
||||
cmd.texture = sbstate.texture;
|
||||
draw(cmd);
|
||||
|
||||
sbstate.indexBufferMap = StreamBuffer::MapInfo();
|
||||
|
||||
drawIndexed(sbstate.primitiveMode, sbstate.indexCount, 1, INDEX_UINT16, sbstate.indexBuffer, offset, attributes, buffers, sbstate.texture);
|
||||
}
|
||||
else
|
||||
draw(sbstate.primitiveMode, 0, sbstate.vertexCount, 1, attributes, buffers, sbstate.texture);
|
||||
{
|
||||
DrawCommand cmd(&attributes, &buffers);
|
||||
cmd.primitiveType = sbstate.primitiveMode;
|
||||
cmd.vertexStart = 0;
|
||||
cmd.vertexCount = sbstate.vertexCount;
|
||||
cmd.texture = sbstate.texture;
|
||||
draw(cmd);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
|
||||
@@ -250,6 +250,54 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct DrawCommand
|
||||
{
|
||||
PrimitiveType primitiveType = PRIMITIVE_TRIANGLES;
|
||||
|
||||
const vertex::Attributes *attributes;
|
||||
const vertex::Buffers *buffers;
|
||||
|
||||
int vertexStart = 0;
|
||||
int vertexCount = 0;
|
||||
int instanceCount = 1;
|
||||
|
||||
Texture *texture = nullptr;
|
||||
|
||||
// TODO: This should be moved out to a state transition API?
|
||||
CullMode cullMode = CULL_NONE;
|
||||
|
||||
DrawCommand(const vertex::Attributes *attribs, const vertex::Buffers *buffers)
|
||||
: attributes(attribs)
|
||||
, buffers(buffers)
|
||||
{}
|
||||
};
|
||||
|
||||
struct DrawIndexedCommand
|
||||
{
|
||||
PrimitiveType primitiveType = PRIMITIVE_TRIANGLES;
|
||||
|
||||
const vertex::Attributes *attributes;
|
||||
const vertex::Buffers *buffers;
|
||||
|
||||
int indexCount = 0;
|
||||
int instanceCount = 1;
|
||||
|
||||
IndexDataType indexType = INDEX_UINT16;
|
||||
Resource *indexBuffer;
|
||||
size_t indexBufferOffset = 0;
|
||||
|
||||
Texture *texture = nullptr;
|
||||
|
||||
// TODO: This should be moved out to a state transition API?
|
||||
CullMode cullMode = CULL_NONE;
|
||||
|
||||
DrawIndexedCommand(const vertex::Attributes *attribs, const vertex::Buffers *buffers, Resource *indexbuffer)
|
||||
: attributes(attribs)
|
||||
, buffers(buffers)
|
||||
, indexBuffer(indexbuffer)
|
||||
{}
|
||||
};
|
||||
|
||||
struct StreamDrawCommand
|
||||
{
|
||||
PrimitiveType primitiveMode = PRIMITIVE_TRIANGLES;
|
||||
@@ -537,8 +585,18 @@ public:
|
||||
* Sets whether stencil testing is enabled.
|
||||
**/
|
||||
virtual void setStencilTest(CompareMode compare, int value) = 0;
|
||||
virtual void setStencilTest() = 0;
|
||||
void getStencilTest(CompareMode &compare, int &value);
|
||||
void setStencilTest();
|
||||
void getStencilTest(CompareMode &compare, int &value) const;
|
||||
|
||||
virtual void setDepthMode(CompareMode compare, bool write) = 0;
|
||||
void setDepthMode();
|
||||
void getDepthMode(CompareMode &compare, bool &write) const;
|
||||
|
||||
void setMeshCullMode(CullMode cull);
|
||||
CullMode getMeshCullMode() const;
|
||||
|
||||
virtual void setFrontFaceWinding(vertex::Winding winding) = 0;
|
||||
vertex::Winding getFrontFaceWinding() const;
|
||||
|
||||
/**
|
||||
* Sets the enabled color components when rendering.
|
||||
@@ -769,8 +827,8 @@ public:
|
||||
Vector2 transformPoint(Vector2 point);
|
||||
Vector2 inverseTransformPoint(Vector2 point);
|
||||
|
||||
virtual void draw(PrimitiveType primtype, int vertexstart, int vertexcount, int instancecount, const vertex::Attributes &attribs, const vertex::Buffers &buffers, Texture *texture) = 0;
|
||||
virtual void drawIndexed(PrimitiveType primtype, int indexcount, int instancecount, IndexDataType datatype, Resource *indexbuffer, size_t indexoffset, const vertex::Attributes &attribs, const vertex::Buffers &buffers, Texture *texture) = 0;
|
||||
virtual void draw(const DrawCommand &cmd) = 0;
|
||||
virtual void draw(const DrawIndexedCommand &cmd) = 0;
|
||||
|
||||
void flushStreamDraws();
|
||||
StreamVertexData requestStreamDraw(const StreamDrawCommand &command);
|
||||
@@ -852,6 +910,12 @@ protected:
|
||||
CompareMode stencilCompare = COMPARE_ALWAYS;
|
||||
int stencilTestValue = 0;
|
||||
|
||||
CompareMode depthTest = COMPARE_ALWAYS;
|
||||
bool depthWrite = false;
|
||||
|
||||
CullMode meshCullMode = CULL_NONE;
|
||||
vertex::Winding winding = vertex::WINDING_CCW;
|
||||
|
||||
StrongRef<Font> font;
|
||||
StrongRef<Shader> shader;
|
||||
|
||||
|
||||
@@ -633,37 +633,49 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
|
||||
|
||||
Graphics::TempTransform transform(gfx, m);
|
||||
|
||||
int start = 0;
|
||||
int count = 0;
|
||||
|
||||
if (useIndexBuffer && ibo != nullptr && indexCount > 0)
|
||||
{
|
||||
// Make sure the index buffer isn't mapped (sends data to GPU if needed.)
|
||||
ibo->unmap();
|
||||
|
||||
start = std::min(std::max(0, rangeStart), (int) indexCount - 1);
|
||||
Graphics::DrawIndexedCommand cmd(&attributes, &buffers, ibo);
|
||||
|
||||
count = (int) indexCount;
|
||||
cmd.primitiveType = primitiveType;
|
||||
cmd.indexType = indexDataType;
|
||||
cmd.instanceCount = instancecount;
|
||||
cmd.texture = texture;
|
||||
cmd.cullMode = gfx->getMeshCullMode();
|
||||
|
||||
int start = std::min(std::max(0, rangeStart), (int) indexCount - 1);
|
||||
cmd.indexBufferOffset = start * vertex::getIndexDataSize(indexDataType);
|
||||
|
||||
cmd.indexCount = (int) indexCount;
|
||||
if (rangeCount > 0)
|
||||
count = std::min(count, rangeCount);
|
||||
cmd.indexCount = std::min(cmd.indexCount, rangeCount);
|
||||
|
||||
count = std::min(count, (int) indexCount - start);
|
||||
cmd.indexCount = std::min(cmd.indexCount, (int) indexCount - start);
|
||||
|
||||
size_t offset = start * vertex::getIndexDataSize(indexDataType);
|
||||
if (count > 0)
|
||||
gfx->drawIndexed(primitiveType, count, instancecount, indexDataType, ibo, offset, attributes, buffers, texture);
|
||||
if (cmd.indexCount > 0)
|
||||
gfx->draw(cmd);
|
||||
}
|
||||
else
|
||||
else if (vertexCount > 0)
|
||||
{
|
||||
start = std::min(std::max(0, rangeStart), (int) vertexCount - 1);
|
||||
Graphics::DrawCommand cmd(&attributes, &buffers);
|
||||
|
||||
count = (int) vertexCount;
|
||||
cmd.primitiveType = primitiveType;
|
||||
cmd.vertexStart = std::min(std::max(0, rangeStart), (int) vertexCount - 1);
|
||||
|
||||
cmd.vertexCount = (int) vertexCount;
|
||||
if (rangeCount > 0)
|
||||
count = std::min(count, rangeCount);
|
||||
cmd.vertexCount = std::min(cmd.vertexCount, rangeCount);
|
||||
|
||||
count = std::min(count, (int) vertexCount - start);
|
||||
cmd.vertexCount = std::min(cmd.vertexCount, (int) vertexCount - cmd.vertexStart);
|
||||
cmd.instanceCount = instancecount;
|
||||
cmd.texture = texture;
|
||||
cmd.cullMode = gfx->getMeshCullMode();
|
||||
|
||||
gfx->draw(primitiveType, start, count, instancecount, attributes, buffers, texture);
|
||||
if (cmd.vertexCount > 0)
|
||||
gfx->draw(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1101,8 +1101,13 @@ void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m)
|
||||
|
||||
Graphics::TempTransform transform(gfx, m);
|
||||
|
||||
int count = quadIndices.getIndexCount(getCount());
|
||||
gfx->drawIndexed(PRIMITIVE_TRIANGLES, count, 1, quadIndices.getType(), quadIndices.getBuffer(), 0, vertexAttributes, vertexbuffers, texture);
|
||||
Graphics::DrawIndexedCommand cmd(&vertexAttributes, &vertexbuffers, quadIndices.getBuffer());
|
||||
cmd.primitiveType = PRIMITIVE_TRIANGLES;
|
||||
cmd.indexBufferOffset = 0;
|
||||
cmd.indexCount = (int) quadIndices.getIndexCount(pCount);
|
||||
cmd.indexType = quadIndices.getType();
|
||||
cmd.texture = texture;
|
||||
gfx->draw(cmd);
|
||||
}
|
||||
|
||||
bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out)
|
||||
|
||||
@@ -385,6 +385,8 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
}
|
||||
}
|
||||
|
||||
Graphics::DrawIndexedCommand cmd(&attributes, &buffers, quad_indices.getBuffer());
|
||||
|
||||
int start = std::min(std::max(0, range_start), next - 1);
|
||||
|
||||
int count = next;
|
||||
@@ -393,13 +395,15 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
|
||||
count = std::min(count, next - start);
|
||||
|
||||
size_t indexbytestart = quad_indices.getIndexCount(start) * quad_indices.getElementSize();
|
||||
size_t indexcount = quad_indices.getIndexCount(count);
|
||||
cmd.indexBufferOffset = quad_indices.getIndexCount(start) * quad_indices.getElementSize();
|
||||
cmd.indexCount = (int) quad_indices.getIndexCount(count);
|
||||
cmd.indexType = quad_indices.getType();
|
||||
cmd.texture = texture;
|
||||
|
||||
Graphics::TempTransform transform(gfx, m);
|
||||
|
||||
if (count > 0)
|
||||
gfx->drawIndexed(PRIMITIVE_TRIANGLES, indexcount, 1, quad_indices.getType(), quad_indices.getBuffer(), indexbytestart, attributes, buffers, texture);
|
||||
gfx->draw(cmd);
|
||||
}
|
||||
|
||||
} // graphics
|
||||
|
||||
@@ -266,15 +266,16 @@ void Text::draw(Graphics *gfx, const Matrix4 &m)
|
||||
|
||||
Graphics::TempTransform transform(gfx, m);
|
||||
|
||||
Graphics::DrawIndexedCommand drawcmd(&vertexAttributes, &vertexBuffers, quadIndices.getBuffer());
|
||||
drawcmd.indexType = quadIndices.getType();
|
||||
size_t elemsize = quadIndices.getElementSize();
|
||||
IndexDataType datatype = quadIndices.getType();
|
||||
Buffer *indexbuffer = quadIndices.getBuffer();
|
||||
|
||||
for (const Font::DrawCommand &cmd : draw_commands)
|
||||
{
|
||||
int count = (cmd.vertexcount / 4) * 6;
|
||||
size_t offset = (cmd.startvertex / 4) * 6 * elemsize;
|
||||
gfx->drawIndexed(PRIMITIVE_TRIANGLES, count, 1, datatype, indexbuffer, offset, vertexAttributes, vertexBuffers, cmd.texture);
|
||||
drawcmd.indexCount = (cmd.vertexcount / 4) * 6;
|
||||
drawcmd.indexBufferOffset = (cmd.startvertex / 4) * 6 * elemsize;
|
||||
drawcmd.texture = cmd.texture;
|
||||
gfx->draw(drawcmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,19 +34,12 @@ CompareMode getReversedCompareMode(CompareMode mode)
|
||||
return COMPARE_GREATER;
|
||||
case COMPARE_LEQUAL:
|
||||
return COMPARE_GEQUAL;
|
||||
case COMPARE_EQUAL:
|
||||
return COMPARE_EQUAL;
|
||||
case COMPARE_GEQUAL:
|
||||
return COMPARE_LEQUAL;
|
||||
case COMPARE_GREATER:
|
||||
return COMPARE_LESS;
|
||||
case COMPARE_NOTEQUAL:
|
||||
return COMPARE_NOTEQUAL;
|
||||
case COMPARE_ALWAYS:
|
||||
return COMPARE_ALWAYS;
|
||||
case COMPARE_MAX_ENUM:
|
||||
default:
|
||||
return COMPARE_MAX_ENUM;
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +64,7 @@ static StringMap<CompareMode, COMPARE_MAX_ENUM>::Entry compareModeEntries[] =
|
||||
{ "greater", COMPARE_GREATER },
|
||||
{ "notequal", COMPARE_NOTEQUAL },
|
||||
{ "always", COMPARE_ALWAYS },
|
||||
{ "never", COMPARE_NEVER },
|
||||
};
|
||||
|
||||
static StringMap<CompareMode, COMPARE_MAX_ENUM> compareModes(compareModeEntries, sizeof(compareModeEntries));
|
||||
|
||||
@@ -48,6 +48,7 @@ enum CompareMode
|
||||
COMPARE_GREATER,
|
||||
COMPARE_NOTEQUAL,
|
||||
COMPARE_ALWAYS,
|
||||
COMPARE_NEVER,
|
||||
COMPARE_MAX_ENUM
|
||||
};
|
||||
|
||||
|
||||
@@ -68,9 +68,16 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo
|
||||
|
||||
if (isPixelFormatDepthStencil(format))
|
||||
{
|
||||
bool hadDepthWrites = gl.hasDepthWrites();
|
||||
if (!hadDepthWrites) // glDepthMask also affects glClear.
|
||||
gl.setDepthWrites(true);
|
||||
|
||||
gl.clearDepth(1.0);
|
||||
glClearStencil(0);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
if (!hadDepthWrites)
|
||||
gl.setDepthWrites(hadDepthWrites);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -128,9 +135,16 @@ static bool createRenderbuffer(int width, int height, int &samples, PixelFormat
|
||||
{
|
||||
if (isPixelFormatDepthStencil(pixelformat))
|
||||
{
|
||||
bool hadDepthWrites = gl.hasDepthWrites();
|
||||
if (!hadDepthWrites) // glDepthMask also affects glClear.
|
||||
gl.setDepthWrites(true);
|
||||
|
||||
gl.clearDepth(1.0);
|
||||
glClearStencil(0);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
if (!hadDepthWrites)
|
||||
gl.setDepthWrites(hadDepthWrites);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -149,7 +149,7 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
|
||||
setScissor(states.back().scissorRect);
|
||||
|
||||
// Set up the projection matrix
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0);
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0, -10.0f, 10.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
|
||||
|| GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB)
|
||||
{
|
||||
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
|
||||
gl.setFramebufferSRGB(isGammaCorrect());
|
||||
gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, isGammaCorrect());
|
||||
}
|
||||
else
|
||||
setGammaCorrect(false);
|
||||
@@ -316,38 +316,40 @@ void Graphics::setActive(bool enable)
|
||||
active = enable;
|
||||
}
|
||||
|
||||
void Graphics::draw(PrimitiveType primtype, int vertexstart, int vertexcount, int instancecount, const vertex::Attributes &attribs, const vertex::Buffers &buffers, love::graphics::Texture *texture)
|
||||
void Graphics::draw(const DrawCommand &cmd)
|
||||
{
|
||||
gl.prepareDraw();
|
||||
gl.setVertexAttributes(attribs, buffers);
|
||||
gl.bindTextureToUnit(texture, 0, false);
|
||||
gl.setVertexAttributes(*cmd.attributes, *cmd.buffers);
|
||||
gl.bindTextureToUnit(cmd.texture, 0, false);
|
||||
gl.setCullMode(cmd.cullMode);
|
||||
|
||||
GLenum glprimitivetype = OpenGL::getGLPrimitiveType(primtype);
|
||||
GLenum glprimitivetype = OpenGL::getGLPrimitiveType(cmd.primitiveType);
|
||||
|
||||
if (instancecount > 1)
|
||||
glDrawArraysInstanced(glprimitivetype, vertexstart, vertexcount, instancecount);
|
||||
if (cmd.instanceCount > 1)
|
||||
glDrawArraysInstanced(glprimitivetype, cmd.vertexStart, cmd.vertexCount, cmd.instanceCount);
|
||||
else
|
||||
glDrawArrays(glprimitivetype, vertexstart, vertexcount);
|
||||
glDrawArrays(glprimitivetype, cmd.vertexStart, cmd.vertexCount);
|
||||
|
||||
++drawCalls;
|
||||
}
|
||||
|
||||
void Graphics::drawIndexed(PrimitiveType primtype, int indexcount, int instancecount, IndexDataType datatype, Resource *indexbuffer, size_t indexoffset, const vertex::Attributes &attribs, const vertex::Buffers &buffers, love::graphics::Texture *texture)
|
||||
void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||
{
|
||||
gl.prepareDraw();
|
||||
gl.setVertexAttributes(attribs, buffers);
|
||||
gl.bindTextureToUnit(texture, 0, false);
|
||||
gl.setVertexAttributes(*cmd.attributes, *cmd.buffers);
|
||||
gl.bindTextureToUnit(cmd.texture, 0, false);
|
||||
gl.setCullMode(cmd.cullMode);
|
||||
|
||||
const void *gloffset = BUFFER_OFFSET(indexoffset);
|
||||
GLenum glprimitivetype = OpenGL::getGLPrimitiveType(primtype);
|
||||
GLenum gldatatype = OpenGL::getGLIndexDataType(datatype);
|
||||
const void *gloffset = BUFFER_OFFSET(cmd.indexBufferOffset);
|
||||
GLenum glprimitivetype = OpenGL::getGLPrimitiveType(cmd.primitiveType);
|
||||
GLenum gldatatype = OpenGL::getGLIndexDataType(cmd.indexType);
|
||||
|
||||
gl.bindBuffer(BUFFER_INDEX, indexbuffer->getHandle());
|
||||
gl.bindBuffer(BUFFER_INDEX, cmd.indexBuffer->getHandle());
|
||||
|
||||
if (instancecount > 1)
|
||||
glDrawElementsInstanced(glprimitivetype, indexcount, gldatatype, gloffset, instancecount);
|
||||
if (cmd.instanceCount > 1)
|
||||
glDrawElementsInstanced(glprimitivetype, cmd.indexCount, gldatatype, gloffset, cmd.instanceCount);
|
||||
else
|
||||
glDrawElements(glprimitivetype, indexcount, gldatatype, gloffset);
|
||||
glDrawElements(glprimitivetype, cmd.indexCount, gldatatype, gloffset);
|
||||
|
||||
++drawCalls;
|
||||
}
|
||||
@@ -424,20 +426,22 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix
|
||||
|
||||
gl.setViewport({0, 0, pixelw, pixelh});
|
||||
|
||||
// Flip front face winding when rendering to a canvas, since our projection
|
||||
// matrix is flipped.
|
||||
glFrontFace(state.winding == vertex::WINDING_CW ? GL_CCW : GL_CW);
|
||||
|
||||
// Re-apply the scissor if it was active, since the rectangle passed to
|
||||
// glScissor is affected by the viewport dimensions.
|
||||
if (state.scissor)
|
||||
setScissor(state.scissorRect);
|
||||
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) w, 0.0, (float) h);
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) w, 0.0, (float) h, -10.0f, 10.0f);
|
||||
|
||||
// Make sure the correct sRGB setting is used when drawing to the canvases.
|
||||
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
|
||||
{
|
||||
if (hasSRGBcanvas && !gl.hasFramebufferSRGB())
|
||||
gl.setFramebufferSRGB(true);
|
||||
else if (!hasSRGBcanvas && gl.hasFramebufferSRGB())
|
||||
gl.setFramebufferSRGB(false);
|
||||
if (hasSRGBcanvas != gl.isStateEnabled(OpenGL::ENABLE_FRAMEBUFFER_SRGB))
|
||||
gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, hasSRGBcanvas);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,6 +457,10 @@ void Graphics::setCanvas()
|
||||
flushStreamDraws();
|
||||
endPass();
|
||||
|
||||
// Re-apply the correct front face winding, since it may have been flipped
|
||||
// if we were previously rendering to a canvas.
|
||||
glFrontFace(state.winding == vertex::WINDING_CW ? GL_CW : GL_CCW);
|
||||
|
||||
state.renderTargets = RenderTargetsStrongRef();
|
||||
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, gl.getDefaultFBO());
|
||||
@@ -466,14 +474,12 @@ void Graphics::setCanvas()
|
||||
|
||||
// The projection matrix is flipped compared to rendering to a canvas, due
|
||||
// to OpenGL considering (0,0) bottom-left instead of top-left.
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0);
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0, -10.0f, 10.0f);
|
||||
|
||||
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
|
||||
{
|
||||
if (isGammaCorrect() && !gl.hasFramebufferSRGB())
|
||||
gl.setFramebufferSRGB(true);
|
||||
else if (!isGammaCorrect() && gl.hasFramebufferSRGB())
|
||||
gl.setFramebufferSRGB(false);
|
||||
if (isGammaCorrect() != gl.isStateEnabled(OpenGL::ENABLE_FRAMEBUFFER_SRGB))
|
||||
gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, isGammaCorrect());
|
||||
}
|
||||
|
||||
canvasSwitchCount++;
|
||||
@@ -571,8 +577,13 @@ void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth
|
||||
flags |= GL_STENCIL_BUFFER_BIT;
|
||||
}
|
||||
|
||||
bool hadDepthWrites = gl.hasDepthWrites();
|
||||
|
||||
if (depth.hasValue)
|
||||
{
|
||||
if (!hadDepthWrites) // glDepthMask also affects glClear.
|
||||
gl.setDepthWrites(true);
|
||||
|
||||
gl.clearDepth(depth.value);
|
||||
flags |= GL_DEPTH_BUFFER_BIT;
|
||||
}
|
||||
@@ -580,6 +591,9 @@ void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth
|
||||
if (flags != 0)
|
||||
glClear(flags);
|
||||
|
||||
if (depth.hasValue && !hadDepthWrites)
|
||||
gl.setDepthWrites(hadDepthWrites);
|
||||
|
||||
if (c.hasValue && gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current)
|
||||
{
|
||||
// This seems to be enough to fix the bug for me. Other methods I've
|
||||
@@ -652,8 +666,13 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt sten
|
||||
flags |= GL_STENCIL_BUFFER_BIT;
|
||||
}
|
||||
|
||||
bool hadDepthWrites = gl.hasDepthWrites();
|
||||
|
||||
if (depth.hasValue)
|
||||
{
|
||||
if (!hadDepthWrites) // glDepthMask also affects glClear.
|
||||
gl.setDepthWrites(true);
|
||||
|
||||
gl.clearDepth(depth.value);
|
||||
flags |= GL_DEPTH_BUFFER_BIT;
|
||||
}
|
||||
@@ -661,6 +680,9 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt sten
|
||||
if (flags != 0)
|
||||
glClear(flags);
|
||||
|
||||
if (depth.hasValue && !hadDepthWrites)
|
||||
gl.setDepthWrites(hadDepthWrites);
|
||||
|
||||
if (gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current)
|
||||
{
|
||||
// This seems to be enough to fix the bug for me. Other methods I've
|
||||
@@ -986,7 +1008,8 @@ void Graphics::setScissor(const Rect &rect)
|
||||
|
||||
DisplayState &state = states.back();
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
if (!gl.isStateEnabled(OpenGL::ENABLE_SCISSOR_TEST))
|
||||
gl.setEnableState(OpenGL::ENABLE_SCISSOR_TEST, true);
|
||||
|
||||
double dpiscale = getCurrentDPIScale();
|
||||
|
||||
@@ -1009,7 +1032,9 @@ void Graphics::setScissor()
|
||||
flushStreamDraws();
|
||||
|
||||
states.back().scissor = false;
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
if (gl.isStateEnabled(OpenGL::ENABLE_SCISSOR_TEST))
|
||||
gl.setEnableState(OpenGL::ENABLE_SCISSOR_TEST, false);
|
||||
}
|
||||
|
||||
void Graphics::drawToStencilBuffer(StencilAction action, int value)
|
||||
@@ -1055,7 +1080,9 @@ void Graphics::drawToStencilBuffer(StencilAction action, int value)
|
||||
}
|
||||
|
||||
// The stencil test must be enabled in order to write to the stencil buffer.
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
if (!gl.isStateEnabled(OpenGL::ENABLE_STENCIL_TEST))
|
||||
gl.setEnableState(OpenGL::ENABLE_STENCIL_TEST, true);
|
||||
|
||||
glStencilFunc(GL_ALWAYS, value, 0xFFFFFFFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, glaction);
|
||||
}
|
||||
@@ -1093,7 +1120,8 @@ void Graphics::setStencilTest(CompareMode compare, int value)
|
||||
|
||||
if (compare == COMPARE_ALWAYS)
|
||||
{
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
if (gl.isStateEnabled(OpenGL::ENABLE_STENCIL_TEST))
|
||||
gl.setEnableState(OpenGL::ENABLE_STENCIL_TEST, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1107,14 +1135,48 @@ void Graphics::setStencilTest(CompareMode compare, int value)
|
||||
**/
|
||||
GLenum glcompare = OpenGL::getGLCompareMode(getReversedCompareMode(compare));
|
||||
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
if (!gl.isStateEnabled(OpenGL::ENABLE_STENCIL_TEST))
|
||||
gl.setEnableState(OpenGL::ENABLE_STENCIL_TEST, true);
|
||||
|
||||
glStencilFunc(glcompare, value, 0xFFFFFFFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
}
|
||||
|
||||
void Graphics::setStencilTest()
|
||||
void Graphics::setDepthMode(CompareMode compare, bool write)
|
||||
{
|
||||
setStencilTest(COMPARE_ALWAYS, 0);
|
||||
DisplayState &state = states.back();
|
||||
|
||||
if (state.depthTest != compare || state.depthWrite != write)
|
||||
flushStreamDraws();
|
||||
|
||||
state.depthTest = compare;
|
||||
state.depthWrite = write;
|
||||
|
||||
bool depthenable = compare != COMPARE_ALWAYS || write;
|
||||
|
||||
if (depthenable != gl.isStateEnabled(OpenGL::ENABLE_DEPTH_TEST))
|
||||
gl.setEnableState(OpenGL::ENABLE_DEPTH_TEST, depthenable);
|
||||
|
||||
if (depthenable)
|
||||
{
|
||||
glDepthFunc(OpenGL::getGLCompareMode(compare));
|
||||
glDepthMask(write ? GL_TRUE : GL_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::setFrontFaceWinding(vertex::Winding winding)
|
||||
{
|
||||
DisplayState &state = states.back();
|
||||
|
||||
if (state.winding != winding)
|
||||
flushStreamDraws();
|
||||
|
||||
state.winding = winding;
|
||||
|
||||
if (isCanvasActive())
|
||||
winding = winding == vertex::WINDING_CW ? vertex::WINDING_CCW : vertex::WINDING_CW;
|
||||
|
||||
glFrontFace(winding == vertex::WINDING_CW ? GL_CW : GL_CCW);
|
||||
}
|
||||
|
||||
void Graphics::setColor(Colorf c)
|
||||
@@ -1142,12 +1204,6 @@ void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode)
|
||||
if (mode != states.back().blendMode || alphamode != states.back().blendAlphaMode)
|
||||
flushStreamDraws();
|
||||
|
||||
GLenum func = GL_FUNC_ADD;
|
||||
GLenum srcRGB = GL_ONE;
|
||||
GLenum srcA = GL_ONE;
|
||||
GLenum dstRGB = GL_ZERO;
|
||||
GLenum dstA = GL_ZERO;
|
||||
|
||||
if (mode == BLEND_LIGHTEN || mode == BLEND_DARKEN)
|
||||
{
|
||||
if (!capabilities.features[FEATURE_LIGHTEN])
|
||||
@@ -1170,6 +1226,12 @@ void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode)
|
||||
}
|
||||
}
|
||||
|
||||
GLenum func = GL_FUNC_ADD;
|
||||
GLenum srcRGB = GL_ONE;
|
||||
GLenum srcA = GL_ONE;
|
||||
GLenum dstRGB = GL_ZERO;
|
||||
GLenum dstA = GL_ZERO;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case BLEND_ALPHA:
|
||||
|
||||
@@ -69,8 +69,8 @@ public:
|
||||
|
||||
void setActive(bool active) override;
|
||||
|
||||
void draw(PrimitiveType primtype, int vertexstart, int vertexcount, int instancecount, const vertex::Attributes &attribs, const vertex::Buffers &buffers, Texture *texture) override;
|
||||
void drawIndexed(PrimitiveType primtype, int indexcount, int instancecount, IndexDataType datatype, Resource *indexbuffer, size_t indexoffset, const vertex::Attributes &attribs, const vertex::Buffers &buffers, Texture *texture) override;
|
||||
void draw(const DrawCommand &cmd) override;
|
||||
void draw(const DrawIndexedCommand &cmd) override;
|
||||
|
||||
void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) override;
|
||||
void clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth) override;
|
||||
@@ -90,7 +90,10 @@ public:
|
||||
void stopDrawToStencilBuffer() override;
|
||||
|
||||
void setStencilTest(CompareMode compare, int value) override;
|
||||
void setStencilTest() override;
|
||||
|
||||
void setDepthMode(CompareMode compare, bool write) override;
|
||||
|
||||
void setFrontFaceWinding(vertex::Winding winding) override;
|
||||
|
||||
void setColorMask(ColorMask mask) override;
|
||||
|
||||
|
||||
@@ -191,13 +191,22 @@ void OpenGL::setupContext()
|
||||
state.boundFramebuffers[i] = std::numeric_limits<GLuint>::max();
|
||||
bindFramebuffer(FRAMEBUFFER_ALL, getDefaultFBO());
|
||||
|
||||
setEnableState(ENABLE_DEPTH_TEST, state.enableState[ENABLE_DEPTH_TEST]);
|
||||
setEnableState(ENABLE_STENCIL_TEST, state.enableState[ENABLE_STENCIL_TEST]);
|
||||
setEnableState(ENABLE_SCISSOR_TEST, state.enableState[ENABLE_SCISSOR_TEST]);
|
||||
setEnableState(ENABLE_FACE_CULL, state.enableState[ENABLE_FACE_CULL]);
|
||||
|
||||
if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB
|
||||
|| GLAD_EXT_sRGB_write_control)
|
||||
{
|
||||
state.framebufferSRGBEnabled = (glIsEnabled(GL_FRAMEBUFFER_SRGB) == GL_TRUE);
|
||||
setEnableState(ENABLE_FRAMEBUFFER_SRGB, state.enableState[ENABLE_FRAMEBUFFER_SRGB]);
|
||||
}
|
||||
else
|
||||
state.framebufferSRGBEnabled = false;
|
||||
state.enableState[ENABLE_FRAMEBUFFER_SRGB] = false;
|
||||
|
||||
GLint faceCull = GL_BACK;
|
||||
glGetIntegerv(GL_CULL_FACE_MODE, &faceCull);
|
||||
state.faceCullMode = faceCull;
|
||||
|
||||
for (int i = 0; i < (int) BUFFER_MAX_ENUM; i++)
|
||||
{
|
||||
@@ -228,6 +237,8 @@ void OpenGL::setupContext()
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
state.curTextureUnit = 0;
|
||||
|
||||
setDepthWrites(state.depthWritesEnabled);
|
||||
|
||||
createDefaultTexture();
|
||||
|
||||
contextInitialized = true;
|
||||
@@ -673,6 +684,24 @@ void OpenGL::setVertexAttributes(const vertex::Attributes &attributes, const ver
|
||||
glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void OpenGL::setCullMode(CullMode mode)
|
||||
{
|
||||
bool enabled = mode != CULL_NONE;
|
||||
|
||||
if (enabled != isStateEnabled(ENABLE_FACE_CULL))
|
||||
setEnableState(ENABLE_FACE_CULL, enabled);
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
GLenum glmode = mode == CULL_BACK ? GL_BACK : GL_FRONT;
|
||||
if (glmode != state.faceCullMode)
|
||||
{
|
||||
glCullFace(glmode);
|
||||
state.faceCullMode = glmode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGL::clearDepth(double value)
|
||||
{
|
||||
if (GLAD_ES_VERSION_2_0)
|
||||
@@ -729,19 +758,42 @@ float OpenGL::getPointSize() const
|
||||
return state.pointSize;
|
||||
}
|
||||
|
||||
void OpenGL::setFramebufferSRGB(bool enable)
|
||||
void OpenGL::setEnableState(EnableState enablestate, bool enable)
|
||||
{
|
||||
if (enable)
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
else
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
GLenum glstate = GL_NONE;
|
||||
|
||||
state.framebufferSRGBEnabled = enable;
|
||||
switch (enablestate)
|
||||
{
|
||||
case ENABLE_DEPTH_TEST:
|
||||
glstate = GL_DEPTH_TEST;
|
||||
break;
|
||||
case ENABLE_STENCIL_TEST:
|
||||
glstate = GL_STENCIL_TEST;
|
||||
break;
|
||||
case ENABLE_SCISSOR_TEST:
|
||||
glstate = GL_SCISSOR_TEST;
|
||||
break;
|
||||
case ENABLE_FACE_CULL:
|
||||
glstate = GL_CULL_FACE;
|
||||
break;
|
||||
case ENABLE_FRAMEBUFFER_SRGB:
|
||||
glstate = GL_FRAMEBUFFER_SRGB;
|
||||
break;
|
||||
case ENABLE_MAX_ENUM:
|
||||
break;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
glEnable(glstate);
|
||||
else
|
||||
glDisable(glstate);
|
||||
|
||||
state.enableState[enablestate] = enable;
|
||||
}
|
||||
|
||||
bool OpenGL::hasFramebufferSRGB() const
|
||||
bool OpenGL::isStateEnabled(EnableState enablestate) const
|
||||
{
|
||||
return state.framebufferSRGBEnabled;
|
||||
return state.enableState[enablestate];
|
||||
}
|
||||
|
||||
void OpenGL::bindFramebuffer(FramebufferTarget target, GLuint framebuffer)
|
||||
@@ -816,6 +868,17 @@ void OpenGL::framebufferTexture(GLenum attachment, TextureType texType, GLuint t
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGL::setDepthWrites(bool enable)
|
||||
{
|
||||
glDepthMask(enable ? GL_TRUE : GL_FALSE);
|
||||
state.depthWritesEnabled = enable;
|
||||
}
|
||||
|
||||
bool OpenGL::hasDepthWrites() const
|
||||
{
|
||||
return state.depthWritesEnabled;
|
||||
}
|
||||
|
||||
void OpenGL::useProgram(GLuint program)
|
||||
{
|
||||
glUseProgram(program);
|
||||
@@ -954,7 +1017,6 @@ GLint OpenGL::getGLWrapMode(Texture::WrapMode wmode)
|
||||
case Texture::WRAP_MIRRORED_REPEAT:
|
||||
return GL_MIRRORED_REPEAT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GLint OpenGL::getGLCompareMode(CompareMode mode)
|
||||
@@ -975,6 +1037,8 @@ GLint OpenGL::getGLCompareMode(CompareMode mode)
|
||||
return GL_NOTEQUAL;
|
||||
case COMPARE_ALWAYS:
|
||||
return GL_ALWAYS;
|
||||
case COMPARE_NEVER:
|
||||
return GL_NEVER;
|
||||
default:
|
||||
return GL_NEVER;
|
||||
}
|
||||
|
||||
@@ -92,6 +92,16 @@ public:
|
||||
FRAMEBUFFER_ALL = (FRAMEBUFFER_READ | FRAMEBUFFER_DRAW),
|
||||
};
|
||||
|
||||
enum EnableState
|
||||
{
|
||||
ENABLE_DEPTH_TEST,
|
||||
ENABLE_STENCIL_TEST,
|
||||
ENABLE_SCISSOR_TEST,
|
||||
ENABLE_FACE_CULL,
|
||||
ENABLE_FRAMEBUFFER_SRGB,
|
||||
ENABLE_MAX_ENUM
|
||||
};
|
||||
|
||||
struct TextureFormat
|
||||
{
|
||||
GLenum internalformat = 0;
|
||||
@@ -204,6 +214,11 @@ public:
|
||||
**/
|
||||
void setVertexAttributes(const vertex::Attributes &attributes, const vertex::Buffers &buffers);
|
||||
|
||||
/**
|
||||
* Wrapper for glCullFace which eliminates redundant state setting.
|
||||
**/
|
||||
void setCullMode(CullMode mode);
|
||||
|
||||
/**
|
||||
* Wrapper for glClearDepth and glClearDepthf.
|
||||
**/
|
||||
@@ -236,10 +251,10 @@ public:
|
||||
float getPointSize() const;
|
||||
|
||||
/**
|
||||
* Calls glEnable/glDisable(GL_FRAMEBUFFER_SRGB).
|
||||
* State-tracked version of glEnable.
|
||||
**/
|
||||
void setFramebufferSRGB(bool enable);
|
||||
bool hasFramebufferSRGB() const;
|
||||
void setEnableState(EnableState state, bool enable);
|
||||
bool isStateEnabled(EnableState state) const;
|
||||
|
||||
/**
|
||||
* Binds a Framebuffer Object to the specified target.
|
||||
@@ -250,6 +265,12 @@ public:
|
||||
|
||||
void framebufferTexture(GLenum attachment, TextureType texType, GLuint texture, int level, int layer = 0, int face = 0);
|
||||
|
||||
/**
|
||||
* Calls glDepthMask.
|
||||
**/
|
||||
void setDepthWrites(bool enable);
|
||||
bool hasDepthWrites() const;
|
||||
|
||||
/**
|
||||
* Calls glUseProgram.
|
||||
**/
|
||||
@@ -415,7 +436,10 @@ private:
|
||||
// Texture unit state (currently bound texture for each texture unit.)
|
||||
std::vector<GLuint> boundTextures[TEXTURE_MAX_ENUM];
|
||||
|
||||
// Currently active texture unit.
|
||||
bool enableState[ENABLE_MAX_ENUM];
|
||||
|
||||
GLenum faceCullMode;
|
||||
|
||||
int curTextureUnit;
|
||||
|
||||
uint32 enabledAttribArrays;
|
||||
@@ -429,9 +453,9 @@ private:
|
||||
|
||||
float pointSize;
|
||||
|
||||
GLuint boundFramebuffers[2];
|
||||
bool depthWritesEnabled;
|
||||
|
||||
bool framebufferSRGBEnabled;
|
||||
GLuint boundFramebuffers[2];
|
||||
|
||||
GLuint defaultTexture[TEXTURE_MAX_ENUM];
|
||||
|
||||
|
||||
@@ -327,6 +327,23 @@ static StringMap<DataType, DATA_MAX_ENUM>::Entry dataTypeEntries[] =
|
||||
|
||||
static StringMap<DataType, DATA_MAX_ENUM> dataTypes(dataTypeEntries, sizeof(dataTypeEntries));
|
||||
|
||||
static StringMap<CullMode, CULL_MAX_ENUM>::Entry cullModeEntries[] =
|
||||
{
|
||||
{ "none", CULL_NONE },
|
||||
{ "back", CULL_BACK },
|
||||
{ "front", CULL_FRONT },
|
||||
};
|
||||
|
||||
static StringMap<CullMode, CULL_MAX_ENUM> cullModes(cullModeEntries, sizeof(cullModeEntries));
|
||||
|
||||
static StringMap<Winding, WINDING_MAX_ENUM>::Entry windingEntries[] =
|
||||
{
|
||||
{ "cw", WINDING_CW },
|
||||
{ "ccw", WINDING_CCW },
|
||||
};
|
||||
|
||||
static StringMap<Winding, WINDING_MAX_ENUM> windings(windingEntries, sizeof(windingEntries));
|
||||
|
||||
bool getConstant(const char *in, VertexAttribID &out)
|
||||
{
|
||||
return attribNames.find(in, out);
|
||||
@@ -412,6 +429,36 @@ std::vector<std::string> getConstants(DataType)
|
||||
return dataTypes.getNames();
|
||||
}
|
||||
|
||||
bool getConstant(const char *in, CullMode &out)
|
||||
{
|
||||
return cullModes.find(in, out);
|
||||
}
|
||||
|
||||
bool getConstant(CullMode in, const char *&out)
|
||||
{
|
||||
return cullModes.find(in, out);
|
||||
}
|
||||
|
||||
std::vector<std::string> getConstants(CullMode)
|
||||
{
|
||||
return cullModes.getNames();
|
||||
}
|
||||
|
||||
bool getConstant(const char *in, Winding &out)
|
||||
{
|
||||
return windings.find(in, out);
|
||||
}
|
||||
|
||||
bool getConstant(Winding in, const char *&out)
|
||||
{
|
||||
return windings.find(in, out);
|
||||
}
|
||||
|
||||
std::vector<std::string> getConstants(Winding)
|
||||
{
|
||||
return windings.getNames();
|
||||
}
|
||||
|
||||
} // vertex
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -86,6 +86,14 @@ enum AttributeStep
|
||||
STEP_MAX_ENUM
|
||||
};
|
||||
|
||||
enum CullMode
|
||||
{
|
||||
CULL_NONE,
|
||||
CULL_BACK,
|
||||
CULL_FRONT,
|
||||
CULL_MAX_ENUM
|
||||
};
|
||||
|
||||
namespace vertex
|
||||
{
|
||||
|
||||
@@ -106,6 +114,13 @@ enum DataType
|
||||
DATA_MAX_ENUM
|
||||
};
|
||||
|
||||
enum Winding
|
||||
{
|
||||
WINDING_CW,
|
||||
WINDING_CCW,
|
||||
WINDING_MAX_ENUM
|
||||
};
|
||||
|
||||
enum class TriangleIndexMode
|
||||
{
|
||||
NONE,
|
||||
@@ -305,6 +320,14 @@ bool getConstant(const char *in, DataType &out);
|
||||
bool getConstant(DataType in, const char *&out);
|
||||
std::vector<std::string> getConstants(DataType);
|
||||
|
||||
bool getConstant(const char *in, CullMode &out);
|
||||
bool getConstant(CullMode in, const char *&out);
|
||||
std::vector<std::string> getConstants(CullMode);
|
||||
|
||||
bool getConstant(const char *in, Winding &out);
|
||||
bool getConstant(Winding in, const char *&out);
|
||||
std::vector<std::string> getConstants(Winding);
|
||||
|
||||
} // vertex
|
||||
|
||||
typedef vertex::XYf_STf_RGBAub Vertex;
|
||||
|
||||
@@ -1962,6 +1962,84 @@ int w_getPointSize(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_setDepthMode(lua_State *L)
|
||||
{
|
||||
if (lua_isnoneornil(L, 1) && lua_isnoneornil(L, 2))
|
||||
luax_catchexcept(L, [&]() { instance()->setDepthMode(); });
|
||||
else
|
||||
{
|
||||
CompareMode compare = COMPARE_ALWAYS;
|
||||
const char *str = luaL_checkstring(L, 1);
|
||||
bool write = luax_checkboolean(L, 2);
|
||||
|
||||
if (!getConstant(str, compare))
|
||||
return luax_enumerror(L, "compare mode", getConstants(compare), str);
|
||||
|
||||
luax_catchexcept(L, [&]() { instance()->setDepthMode(compare, write); });
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getDepthMode(lua_State *L)
|
||||
{
|
||||
CompareMode compare = COMPARE_ALWAYS;
|
||||
bool write = false;
|
||||
instance()->getDepthMode(compare, write);
|
||||
|
||||
const char *str;
|
||||
if (!getConstant(compare, str))
|
||||
return luaL_error(L, "Unknown compare mode");
|
||||
|
||||
lua_pushstring(L, str);
|
||||
luax_pushboolean(L, write);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_setMeshCullMode(lua_State *L)
|
||||
{
|
||||
const char *str = luaL_checkstring(L, 1);
|
||||
CullMode mode;
|
||||
|
||||
if (!vertex::getConstant(str, mode))
|
||||
return luax_enumerror(L, "cull mode", vertex::getConstants(mode), str);
|
||||
|
||||
luax_catchexcept(L, [&]() { instance()->setMeshCullMode(mode); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getMeshCullMode(lua_State *L)
|
||||
{
|
||||
CullMode mode = instance()->getMeshCullMode();
|
||||
const char *str;
|
||||
if (!vertex::getConstant(mode, str))
|
||||
return luaL_error(L, "Unknown cull mode");
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_setFrontFaceWinding(lua_State *L)
|
||||
{
|
||||
const char *str = luaL_checkstring(L, 1);
|
||||
vertex::Winding winding;
|
||||
|
||||
if (!vertex::getConstant(str, winding))
|
||||
return luax_enumerror(L, "vertex winding", vertex::getConstants(winding), str);
|
||||
|
||||
luax_catchexcept(L, [&]() { instance()->setFrontFaceWinding(winding); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getFrontFaceWinding(lua_State *L)
|
||||
{
|
||||
vertex::Winding winding = instance()->getFrontFaceWinding();
|
||||
const char *str;
|
||||
if (!vertex::getConstant(winding, str))
|
||||
return luaL_error(L, "Unknown vertex winding");
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_setWireframe(lua_State *L)
|
||||
{
|
||||
instance()->setWireframe(luax_checkboolean(L, 1));
|
||||
@@ -2858,6 +2936,12 @@ static const luaL_Reg functions[] =
|
||||
{ "getLineJoin", w_getLineJoin },
|
||||
{ "setPointSize", w_setPointSize },
|
||||
{ "getPointSize", w_getPointSize },
|
||||
{ "setDepthMode", w_setDepthMode },
|
||||
{ "getDepthMode", w_getDepthMode },
|
||||
{ "setMeshCullMode", w_setMeshCullMode },
|
||||
{ "getMeshCullMode", w_getMeshCullMode },
|
||||
{ "setFrontFaceWinding", w_setFrontFaceWinding },
|
||||
{ "getFrontFaceWinding", w_getFrontFaceWinding },
|
||||
{ "setWireframe", w_setWireframe },
|
||||
{ "isWireframe", w_isWireframe },
|
||||
|
||||
|
||||
Reference in New Issue
Block a user