mirror of
https://github.com/love2d/love.git
synced 2026-08-16 16:20:42 +02:00
Merge branch '12.0-development' into metal
This commit is contained in:
@@ -179,7 +179,7 @@ Graphics::Graphics()
|
||||
, created(false)
|
||||
, active(true)
|
||||
, batchedDrawState()
|
||||
, projectionMatrix()
|
||||
, deviceProjectionMatrix()
|
||||
, renderTargetSwitchCount(0)
|
||||
, drawCalls(0)
|
||||
, drawCallsBatched(0)
|
||||
@@ -541,6 +541,11 @@ void Graphics::restoreState(const DisplayState &s)
|
||||
setWireframe(s.wireframe);
|
||||
|
||||
setDefaultSamplerState(s.defaultSamplerState);
|
||||
|
||||
if (s.useCustomProjection)
|
||||
updateDeviceProjection(s.customProjection);
|
||||
else
|
||||
resetProjection();
|
||||
}
|
||||
|
||||
void Graphics::restoreStateChecked(const DisplayState &s)
|
||||
@@ -625,6 +630,11 @@ void Graphics::restoreStateChecked(const DisplayState &s)
|
||||
setWireframe(s.wireframe);
|
||||
|
||||
setDefaultSamplerState(s.defaultSamplerState);
|
||||
|
||||
if (s.useCustomProjection)
|
||||
setCustomProjection(s.customProjection);
|
||||
else if (cur.useCustomProjection)
|
||||
resetProjection();
|
||||
}
|
||||
|
||||
Colorf Graphics::getColor() const
|
||||
@@ -878,6 +888,8 @@ void Graphics::setRenderTargets(const RenderTargets &rts)
|
||||
std::swap(state.renderTargets, refs);
|
||||
|
||||
renderTargetSwitchCount++;
|
||||
|
||||
resetProjection();
|
||||
}
|
||||
|
||||
void Graphics::setRenderTarget()
|
||||
@@ -892,6 +904,8 @@ void Graphics::setRenderTarget()
|
||||
|
||||
state.renderTargets = RenderTargetsStrongRef();
|
||||
renderTargetSwitchCount++;
|
||||
|
||||
resetProjection();
|
||||
}
|
||||
|
||||
Graphics::RenderTargets Graphics::getRenderTargets() const
|
||||
@@ -2097,9 +2111,9 @@ const Matrix4 &Graphics::getTransform() const
|
||||
return transformStack.back();
|
||||
}
|
||||
|
||||
const Matrix4 &Graphics::getProjection() const
|
||||
const Matrix4 &Graphics::getDeviceProjection() const
|
||||
{
|
||||
return projectionMatrix;
|
||||
return deviceProjectionMatrix;
|
||||
}
|
||||
|
||||
void Graphics::pushTransform()
|
||||
@@ -2179,6 +2193,81 @@ Vector2 Graphics::inverseTransformPoint(Vector2 point)
|
||||
return p;
|
||||
}
|
||||
|
||||
void Graphics::setOrthoProjection(float w, float h, float near, float far)
|
||||
{
|
||||
if (near >= far)
|
||||
throw love::Exception("Orthographic projection Z far value must be greater than the Z near value.");
|
||||
|
||||
Matrix4 m = Matrix4::ortho(0.0f, w, 0.0f, h, near, far);
|
||||
setCustomProjection(m);
|
||||
}
|
||||
|
||||
void Graphics::setPerspectiveProjection(float verticalfov, float aspect, float near, float far)
|
||||
{
|
||||
if (near <= 0.0f)
|
||||
throw love::Exception("Perspective projection Z near value must be greater than 0.");
|
||||
|
||||
if (near >= far)
|
||||
throw love::Exception("Perspective projection Z far value must be greater than the Z near value.");
|
||||
|
||||
Matrix4 m = Matrix4::perspective(verticalfov, aspect, near, far);
|
||||
setCustomProjection(m);
|
||||
}
|
||||
|
||||
void Graphics::setCustomProjection(const Matrix4 &m)
|
||||
{
|
||||
flushBatchedDraws();
|
||||
|
||||
auto &state = states.back();
|
||||
|
||||
state.useCustomProjection = true;
|
||||
state.customProjection = m;
|
||||
|
||||
updateDeviceProjection(m);
|
||||
}
|
||||
|
||||
void Graphics::resetProjection()
|
||||
{
|
||||
flushBatchedDraws();
|
||||
|
||||
auto &state = states.back();
|
||||
int w = getWidth();
|
||||
int h = getHeight();
|
||||
|
||||
const auto &rt = state.renderTargets.getFirstTarget();
|
||||
if (rt.texture.get())
|
||||
{
|
||||
w = rt.texture->getWidth(rt.mipmap);
|
||||
h = rt.texture->getHeight(rt.mipmap);
|
||||
}
|
||||
|
||||
state.useCustomProjection = false;
|
||||
|
||||
updateDeviceProjection(Matrix4::ortho(0.0f, w, 0.0f, h, -10.0f, 10.0f));
|
||||
}
|
||||
|
||||
void Graphics::updateDeviceProjection(const Matrix4 &projection)
|
||||
{
|
||||
// Note: graphics implementations define computeDeviceProjection.
|
||||
deviceProjectionMatrix = computeDeviceProjection(projection, isRenderTargetActive());
|
||||
}
|
||||
|
||||
Matrix4 Graphics::calculateDeviceProjection(const Matrix4 &projection, uint32 flags) const
|
||||
{
|
||||
Matrix4 m = projection;
|
||||
bool reverseZ = (flags & DEVICE_PROJECTION_REVERSE_Z) != 0;
|
||||
|
||||
if (flags & DEVICE_PROJECTION_FLIP_Y)
|
||||
m.setRow(1, -m.getRow(1));
|
||||
|
||||
if (flags & DEVICE_PROJECTION_Z_01) // Go from Z [-1, 1] to Z [0, 1].
|
||||
m.setRow(2, m.getRow(2) * (reverseZ ? -0.5f : 0.5f) + m.getRow(3));
|
||||
else if (reverseZ)
|
||||
m.setRow(2, -m.getRow(2));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
STRINGMAP_CLASS_BEGIN(Graphics, Graphics::DrawMode, Graphics::DRAW_MAX_ENUM, drawMode)
|
||||
{
|
||||
{ "line", Graphics::DRAW_LINE },
|
||||
|
||||
@@ -834,7 +834,7 @@ public:
|
||||
void pop();
|
||||
|
||||
const Matrix4 &getTransform() const;
|
||||
const Matrix4 &getProjection() const;
|
||||
const Matrix4 &getDeviceProjection() const;
|
||||
|
||||
void rotate(float r);
|
||||
void scale(float x, float y = 1.0f);
|
||||
@@ -848,6 +848,13 @@ public:
|
||||
Vector2 transformPoint(Vector2 point);
|
||||
Vector2 inverseTransformPoint(Vector2 point);
|
||||
|
||||
void setOrthoProjection(float w, float h, float near, float far);
|
||||
void setPerspectiveProjection(float verticalfov, float aspect, float near, float far);
|
||||
void setCustomProjection(const Matrix4 &m);
|
||||
void resetProjection();
|
||||
|
||||
virtual Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const = 0;
|
||||
|
||||
virtual void draw(const DrawCommand &cmd) = 0;
|
||||
virtual void draw(const DrawIndexedCommand &cmd) = 0;
|
||||
virtual void drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, Texture *texture) = 0;
|
||||
@@ -882,6 +889,14 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
enum DeviceProjectionFlags
|
||||
{
|
||||
DEVICE_PROJECTION_DEFAULT = 0,
|
||||
DEVICE_PROJECTION_FLIP_Y = (1 << 0),
|
||||
DEVICE_PROJECTION_Z_01 = (1 << 1),
|
||||
DEVICE_PROJECTION_REVERSE_Z = (1 << 2),
|
||||
};
|
||||
|
||||
struct DisplayState
|
||||
{
|
||||
DisplayState();
|
||||
@@ -917,6 +932,9 @@ protected:
|
||||
|
||||
bool wireframe = false;
|
||||
|
||||
bool useCustomProjection = false;
|
||||
Matrix4 customProjection;
|
||||
|
||||
// Default mipmap filter is set in the DisplayState constructor.
|
||||
SamplerState defaultSamplerState = SamplerState();
|
||||
};
|
||||
@@ -978,6 +996,9 @@ protected:
|
||||
void pushIdentityTransform();
|
||||
void popTransform();
|
||||
|
||||
void updateDeviceProjection(const Matrix4 &projection);
|
||||
Matrix4 calculateDeviceProjection(const Matrix4 &projection, uint32 flags) const;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int pixelWidth;
|
||||
@@ -993,7 +1014,7 @@ protected:
|
||||
BatchedDrawState batchedDrawState;
|
||||
|
||||
std::vector<Matrix4> transformStack;
|
||||
Matrix4 projectionMatrix;
|
||||
Matrix4 deviceProjectionMatrix;
|
||||
|
||||
std::vector<double> pixelScaleStack;
|
||||
|
||||
|
||||
@@ -177,6 +177,18 @@ love::graphics::Buffer *Graphics::newBuffer(const Buffer::Settings &settings, co
|
||||
return new Buffer(this, settings, format, data, size, arraylength);
|
||||
}
|
||||
|
||||
Matrix4 Graphics::computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const
|
||||
{
|
||||
uint32 flags = DEVICE_PROJECTION_DEFAULT;
|
||||
|
||||
// The projection matrix is flipped compared to rendering to a texture, due
|
||||
// to OpenGL considering (0,0) bottom-left instead of top-left.
|
||||
if (!rendertotexture)
|
||||
flags |= DEVICE_PROJECTION_FLIP_Y;
|
||||
|
||||
return calculateDeviceProjection(projection, flags);
|
||||
}
|
||||
|
||||
void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight)
|
||||
{
|
||||
this->width = width;
|
||||
@@ -194,8 +206,7 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
|
||||
if (states.back().scissor)
|
||||
setScissor(states.back().scissorRect);
|
||||
|
||||
// Set up the projection matrix
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0, -10.0f, 10.0f);
|
||||
resetProjection();
|
||||
}
|
||||
|
||||
updateBackbuffer(width, height, pixelwidth, pixelheight, requestedBackbufferMSAA);
|
||||
@@ -731,7 +742,7 @@ void Graphics::setDebug(bool enable)
|
||||
::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n");
|
||||
}
|
||||
|
||||
void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBtexture)
|
||||
void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int /*w*/, int /*h*/, int pixelw, int pixelh, bool hasSRGBtexture)
|
||||
{
|
||||
const DisplayState &state = states.back();
|
||||
|
||||
@@ -745,19 +756,14 @@ void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int w, int h,
|
||||
if (iswindow)
|
||||
{
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getInternalBackbufferFBO());
|
||||
|
||||
// The projection matrix is flipped compared to rendering to a texture,
|
||||
// due to OpenGL considering (0,0) bottom-left instead of top-left.
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) w, (float) h, 0.0, -10.0f, 10.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
bindCachedFBO(rts);
|
||||
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) w, 0.0, (float) h, -10.0f, 10.0f);
|
||||
|
||||
// Flip front face winding when rendering to a texture, since our
|
||||
// projection matrix is flipped.
|
||||
// Note: projection matrix is set at a higher level.
|
||||
vertexwinding = vertexwinding == WINDING_CW ? WINDING_CCW : WINDING_CW;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ public:
|
||||
love::graphics::Texture *newTexture(const Texture::Settings &settings, const Texture::Slices *data = nullptr) override;
|
||||
love::graphics::Buffer *newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength) override;
|
||||
|
||||
Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override;
|
||||
|
||||
void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
|
||||
bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;
|
||||
void unSetMode() override;
|
||||
|
||||
@@ -969,7 +969,7 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW,
|
||||
BuiltinUniformData data;
|
||||
|
||||
data.transformMatrix = gfx->getTransform();
|
||||
data.projectionMatrix = gfx->getProjection();
|
||||
data.projectionMatrix = gfx->getDeviceProjection();
|
||||
|
||||
// The normal matrix is the transpose of the inverse of the rotation portion
|
||||
// (top-left 3x3) of the transform matrix.
|
||||
|
||||
@@ -1836,21 +1836,22 @@ int w_newIndexBuffer(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static PrimitiveType luax_optmeshdrawmode(lua_State *L, int idx, PrimitiveType def)
|
||||
static PrimitiveType luax_checkmeshdrawmode(lua_State *L, int idx)
|
||||
{
|
||||
const char *modestr = lua_isnoneornil(L, idx) ? nullptr : luaL_checkstring(L, idx);
|
||||
const char *modestr = luaL_checkstring(L, idx);
|
||||
|
||||
if (modestr && !getConstant(modestr, def))
|
||||
luax_enumerror(L, "mesh draw mode", getConstants(def), modestr);
|
||||
PrimitiveType mode = PRIMITIVE_TRIANGLES;
|
||||
if (!getConstant(modestr, mode))
|
||||
luax_enumerror(L, "mesh draw mode", getConstants(mode), modestr);
|
||||
|
||||
return def;
|
||||
return mode;
|
||||
}
|
||||
|
||||
static Mesh *newStandardMesh(lua_State *L)
|
||||
{
|
||||
Mesh *t = nullptr;
|
||||
|
||||
PrimitiveType drawmode = luax_optmeshdrawmode(L, 2, PRIMITIVE_TRIANGLE_FAN);
|
||||
PrimitiveType drawmode = luax_checkmeshdrawmode(L, 2);
|
||||
BufferDataUsage usage = luax_optdatausage(L, 3, BUFFERDATAUSAGE_DYNAMIC);
|
||||
|
||||
std::vector<Buffer::DataDeclaration> format = Mesh::getDefaultVertexFormat();
|
||||
@@ -1912,7 +1913,7 @@ static Mesh *newCustomMesh(lua_State *L)
|
||||
// the number of vertices.
|
||||
std::vector<Buffer::DataDeclaration> vertexformat;
|
||||
|
||||
PrimitiveType drawmode = luax_optmeshdrawmode(L, 3, PRIMITIVE_TRIANGLE_FAN);
|
||||
PrimitiveType drawmode = luax_checkmeshdrawmode(L, 3);
|
||||
BufferDataUsage usage = luax_optdatausage(L, 4, BUFFERDATAUSAGE_DYNAMIC);
|
||||
|
||||
lua_rawgeti(L, 1, 1);
|
||||
@@ -3572,6 +3573,34 @@ int w_inverseTransformPoint(lua_State *L)
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_setOrthoProjection(lua_State *L)
|
||||
{
|
||||
float w = (float) luaL_checknumber(L, 1);
|
||||
float h = (float) luaL_checknumber(L, 2);
|
||||
float near = (float) luaL_optnumber(L, 3, -10.0);
|
||||
float far = (float) luaL_optnumber(L, 4, 10.0);
|
||||
|
||||
luax_catchexcept(L, [&]() { instance()->setOrthoProjection(w, h, near, far); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_setPerspectiveProjection(lua_State *L)
|
||||
{
|
||||
float verticalfov = (float) luaL_checknumber(L, 1);
|
||||
float aspect = (float) luaL_checknumber(L, 2);
|
||||
float near = (float) luaL_checknumber(L, 3);
|
||||
float far = (float) luaL_checknumber(L, 4);
|
||||
|
||||
luax_catchexcept(L, [&]() { instance()->setPerspectiveProjection(verticalfov, aspect, near, far); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_resetProjection(lua_State */*L*/)
|
||||
{
|
||||
instance()->resetProjection();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// List of functions to wrap.
|
||||
static const luaL_Reg functions[] =
|
||||
@@ -3710,6 +3739,10 @@ static const luaL_Reg functions[] =
|
||||
{ "transformPoint", w_transformPoint },
|
||||
{ "inverseTransformPoint", w_inverseTransformPoint },
|
||||
|
||||
{ "setOrthoProjection", w_setOrthoProjection },
|
||||
{ "setPerspectiveProjection", w_setPerspectiveProjection },
|
||||
{ "resetProjection", w_resetProjection },
|
||||
|
||||
// Deprecated
|
||||
{ "newImage", w_newImage },
|
||||
{ "newArrayImage", w_newArrayImage },
|
||||
|
||||
Reference in New Issue
Block a user