From 2deb6273c2588c7dd008daed7f15a627d8b880e4 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sun, 20 Aug 2023 13:39:20 -0300 Subject: [PATCH 01/36] Replace defunct IRC channel in readme with subreddit link --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 11f9f2d6f..c7910663f 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,7 @@ Documentation ------------- We use our [wiki][wiki] for documentation. -If you need further help, feel free to ask on our [forums][forums], our [Discord server][discord], or our IRC channel [#love on OFTC][irc]. +If you need further help, feel free to ask on our [forums][forums], our [Discord server][discord], or our [subreddit][subreddit]. Repository ---------- @@ -99,7 +99,7 @@ Dependencies [wiki]: https://love2d.org/wiki [forums]: https://love2d.org/forums [discord]: https://discord.gg/rhUets9 -[irc]: irc://irc.oftc.net/love +[subreddit]: https://www.reddit.com/r/love2d [dependencies-apple]: https://github.com/love2d/love-apple-dependencies [dependencies-ios]: https://github.com/love2d/love/releases [megasource]: https://github.com/love2d/megasource From 51b439822b33269e687cc4bd8c5a56e0884d36f6 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Wed, 4 Oct 2023 19:56:22 -0300 Subject: [PATCH 02/36] Add convenience functions for creating a Body+Shape+Fixture all at once. #1130. - Add love.physics.newCircleBody(world, bodytype, x, y, radius) - Add love.physics.newRectangleBody(world, bodytype, x, y, w, h [, angle]) - Add love.physics.newPolygonBody(world, bodytype, coords) - Add love.physics.newEdgeBody(world, bodytype, x1, y1, x2, y2 [, onesided]) - Add love.physics.newChainBody(world, bodytype, loop, coords) All new functions return a Body object. The body's world position is at the center of the given coordinates, and the shape's local origin is at its center. --- src/modules/physics/box2d/Physics.cpp | 176 ++++++-------- src/modules/physics/box2d/Physics.h | 36 +-- src/modules/physics/box2d/wrap_Physics.cpp | 267 ++++++++++++++++++++- 3 files changed, 350 insertions(+), 129 deletions(-) diff --git a/src/modules/physics/box2d/Physics.cpp b/src/modules/physics/box2d/Physics.cpp index abf26e2da..5c3a134f9 100644 --- a/src/modules/physics/box2d/Physics.cpp +++ b/src/modules/physics/box2d/Physics.cpp @@ -63,9 +63,69 @@ Body *Physics::newBody(World *world, Body::Type type) return new Body(world, b2Vec2(0, 0), type); } -CircleShape *Physics::newCircleShape(float radius) +Body *Physics::newCircleBody(World *world, Body::Type type, float x, float y, float radius) { - return newCircleShape(0, 0, radius); + StrongRef body(newBody(world, x, y, type), Acquire::NORETAIN); + StrongRef shape(newCircleShape(0, 0, radius), Acquire::NORETAIN); + StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + body->retain(); + return body.get(); +} + +Body *Physics::newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle) +{ + StrongRef body(newBody(world, x, y, type), Acquire::NORETAIN); + StrongRef shape(newRectangleShape(0, 0, w, h, angle), Acquire::NORETAIN); + StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + body->retain(); + return body.get(); +} + +Body *Physics::newPolygonBody(World *world, Body::Type type, const Vector2 *coords, int count) +{ + Vector2 origin(0, 0); + + for (int i = 0; i < count; i++) + origin += coords[i] / count; + + std::vector localcoords; + for (int i = 0; i < count; i++) + localcoords.push_back(coords[i] - origin); + + StrongRef body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN); + StrongRef shape(newPolygonShape(localcoords.data(), count), Acquire::NORETAIN); + StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + body->retain(); + return body.get(); +} + +Body *Physics::newEdgeBody(World *world, Body::Type type, float x1, float y1, float x2, float y2, bool oneSided) +{ + float wx = (x2 - x1) / 2.0f; + float wy = (y2 - y1) / 2.0f; + StrongRef body(newBody(world, wx, wy, type), Acquire::NORETAIN); + StrongRef shape(newEdgeShape(x1 - wx, y1 - wy, x2 - wx, y2 - wy, oneSided), Acquire::NORETAIN); + StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + body->retain(); + return body.get(); +} + +Body *Physics::newChainBody(World *world, Body::Type type, bool loop, const Vector2 *coords, int count) +{ + Vector2 origin(0, 0); + + for (int i = 0; i < count; i++) + origin += coords[i] / count; + + std::vector localcoords; + for (int i = 0; i < count; i++) + localcoords.push_back(coords[i] - origin); + + StrongRef body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN); + StrongRef shape(newChainShape(loop, localcoords.data(), count), Acquire::NORETAIN); + StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + body->retain(); + return body.get(); } CircleShape *Physics::newCircleShape(float x, float y, float radius) @@ -76,16 +136,6 @@ CircleShape *Physics::newCircleShape(float x, float y, float radius) return new CircleShape(s); } -PolygonShape *Physics::newRectangleShape(float w, float h) -{ - return newRectangleShape(0, 0, w, h, 0); -} - -PolygonShape *Physics::newRectangleShape(float x, float y, float w, float h) -{ - return newRectangleShape(x, y, w, h, 0); -} - PolygonShape *Physics::newRectangleShape(float x, float y, float w, float h, float angle) { b2PolygonShape *s = new b2PolygonShape(); @@ -109,54 +159,24 @@ EdgeShape *Physics::newEdgeShape(float x1, float y1, float x2, float y2, bool on return new EdgeShape(s); } -int Physics::newPolygonShape(lua_State *L) +PolygonShape *Physics::newPolygonShape(const Vector2 *coords, int count) { - int argc = lua_gettop(L); - - bool istable = lua_istable(L, 1); - - if (istable) - argc = (int) luax_objlen(L, 1); - - if (argc % 2 != 0) - return luaL_error(L, "Number of vertex components must be a multiple of two."); - // 3 to 8 (b2_maxPolygonVertices) vertices - int vcount = argc / 2; - if (vcount < 3) - return luaL_error(L, "Expected a minimum of 3 vertices, got %d.", vcount); - else if (vcount > b2_maxPolygonVertices) - return luaL_error(L, "Expected a maximum of %d vertices, got %d.", b2_maxPolygonVertices, vcount); + if (count < 3) + throw love::Exception("Expected a minimum of 3 vertices, got %d.", count); + else if (count > b2_maxPolygonVertices) + throw love::Exception("Expected a maximum of %d vertices, got %d.", b2_maxPolygonVertices, count); b2Vec2 vecs[b2_maxPolygonVertices]; - if (istable) - { - for (int i = 0; i < vcount; i++) - { - lua_rawgeti(L, 1, 1 + i * 2); - lua_rawgeti(L, 1, 2 + i * 2); - float x = (float)luaL_checknumber(L, -2); - float y = (float)luaL_checknumber(L, -1); - vecs[i] = Physics::scaleDown(b2Vec2(x, y)); - lua_pop(L, 2); - } - } - else - { - for (int i = 0; i < vcount; i++) - { - float x = (float)luaL_checknumber(L, 1 + i * 2); - float y = (float)luaL_checknumber(L, 2 + i * 2); - vecs[i] = Physics::scaleDown(b2Vec2(x, y)); - } - } + for (int i = 0; i < count; i++) + vecs[i] = Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y)); b2PolygonShape *s = new b2PolygonShape(); try { - s->Set(vecs, vcount); + s->Set(vecs, count); } catch (love::Exception &) { @@ -164,72 +184,32 @@ int Physics::newPolygonShape(lua_State *L) throw; } - PolygonShape *p = new PolygonShape(s); - luax_pushtype(L, p); - p->release(); - return 1; + return new PolygonShape(s); } -int Physics::newChainShape(lua_State *L) +ChainShape *Physics::newChainShape(bool loop, const Vector2 *coords, int count) { - int argc = lua_gettop(L)-1; // first argument is looping + std::vector vecs; - bool istable = lua_istable(L, 2); - - if (istable) - argc = (int) luax_objlen(L, 2); - - if (argc == 0 || argc % 2 != 0) - return luaL_error(L, "Number of vertex components must be a multiple of two."); - - int vcount = argc/2; - bool loop = luax_checkboolean(L, 1); - b2Vec2 *vecs = new b2Vec2[vcount]; - - if (istable) - { - for (int i = 0; i < vcount; i++) - { - lua_rawgeti(L, 2, 1 + i * 2); - lua_rawgeti(L, 2, 2 + i * 2); - float x = (float)lua_tonumber(L, -2); - float y = (float)lua_tonumber(L, -1); - vecs[i] = Physics::scaleDown(b2Vec2(x, y)); - lua_pop(L, 2); - } - } - else - { - for (int i = 0; i < vcount; i++) - { - float x = (float)luaL_checknumber(L, 2 + i * 2); - float y = (float)luaL_checknumber(L, 3 + i * 2); - vecs[i] = Physics::scaleDown(b2Vec2(x, y)); - } - } + for (int i = 0; i < count; i++) + vecs.push_back(Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y))); b2ChainShape *s = new b2ChainShape(); try { if (loop) - s->CreateLoop(vecs, vcount); + s->CreateLoop(vecs.data(), count); else - s->CreateChain(vecs, vcount, vecs[0], vecs[vcount-1]); + s->CreateChain(vecs.data(), count, vecs[0], vecs[count - 1]); } catch (love::Exception &) { - delete[] vecs; delete s; throw; } - delete[] vecs; - - ChainShape *c = new ChainShape(s); - luax_pushtype(L, c); - c->release(); - return 1; + return new ChainShape(s); } DistanceJoint *Physics::newDistanceJoint(Body *body1, Body *body2, float x1, float y1, float x2, float y2, bool collideConnected) diff --git a/src/modules/physics/box2d/Physics.h b/src/modules/physics/box2d/Physics.h index 6d3305dcd..9c81ffe41 100644 --- a/src/modules/physics/box2d/Physics.h +++ b/src/modules/physics/box2d/Physics.h @@ -23,6 +23,8 @@ // LOVE #include "common/Module.h" +#include "common/Vector.h" + #include "World.h" #include "Contact.h" #include "Body.h" @@ -93,10 +95,15 @@ public: Body *newBody(World *world, Body::Type type); /** - * Creates a new CircleShape at (0, 0). - * @param radius The radius of the circle. + * Convenience functions for creating a Body, Shape, and Fixture all in one + * call. The body's world position is the center/average of the given + * coordinates, and the shape is centered at the local origin. **/ - CircleShape *newCircleShape(float radius); + Body *newCircleBody(World *world, Body::Type type, float x, float y, float radius); + Body *newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle); + Body *newPolygonBody(World *world, Body::Type type, const Vector2 *coords, int count); + Body *newEdgeBody(World *world, Body::Type type, float x1, float y1, float x2, float y2, bool oneSided); + Body *newChainBody(World *world, Body::Type type, bool loop, const Vector2 *coords, int count); /** * Creates a new CircleShape at (x,y) in local coordinates. @@ -106,24 +113,6 @@ public: **/ CircleShape *newCircleShape(float x, float y, float radius); - /** - * Shorthand for creating rectangular PolygonShapes. The rectangle - * will be created at the local origin. - * @param w The width of the rectangle. - * @param h The height of the rectangle. - **/ - PolygonShape *newRectangleShape(float w, float h); - - /** - * Shorthand for creating rectangular PolygonShapes. The rectangle - * will be created at (x,y) in local coordinates. - * @param x The offset along the x-axis. - * @param y The offset along the y-axis. - * @param w The width of the rectangle. - * @param h The height of the rectangle. - **/ - PolygonShape *newRectangleShape(float x, float y, float w, float h); - /** * Shorthand for creating rectangular PolygonShapes. The rectangle * will be created at (x,y) in local coordinates. @@ -148,12 +137,13 @@ public: /** * Creates a new PolygonShape from a variable number of vertices. **/ - int newPolygonShape(lua_State *L); + //int newPolygonShape(lua_State *L); + PolygonShape *newPolygonShape(const Vector2 *coords, int count); /** * Creates a new ChainShape from a variable number of vertices. **/ - int newChainShape(lua_State *L); + ChainShape *newChainShape(bool loop, const Vector2 *coords, int count); /** * Creates a new DistanceJoint connecting body1 with body2. diff --git a/src/modules/physics/box2d/wrap_Physics.cpp b/src/modules/physics/box2d/wrap_Physics.cpp index 29c3e2e62..7b755f92e 100644 --- a/src/modules/physics/box2d/wrap_Physics.cpp +++ b/src/modules/physics/box2d/wrap_Physics.cpp @@ -83,6 +83,177 @@ int w_newBody(lua_State *L) return 1; } +int w_newCircleBody(lua_State *L) +{ + World *world = luax_checkworld(L, 1); + + const char *typestr = luaL_checkstring(L, 2); + Body::Type btype = Body::BODY_STATIC; + if (!Body::getConstant(typestr, btype)) + return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr); + + float x = (float)luaL_checknumber(L, 3); + float y = (float)luaL_checknumber(L, 4); + float radius = (float)luaL_checknumber(L, 5); + + Body *body = nullptr; + luax_catchexcept(L, [&]() { body = instance()->newCircleBody(world, btype, x, y, radius); }); + + luax_pushtype(L, body); + body->release(); + return 1; +} + +int w_newRectangleBody(lua_State *L) +{ + World *world = luax_checkworld(L, 1); + + const char *typestr = luaL_checkstring(L, 2); + Body::Type btype = Body::BODY_STATIC; + if (!Body::getConstant(typestr, btype)) + return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr); + + float x = (float)luaL_checknumber(L, 3); + float y = (float)luaL_checknumber(L, 4); + float w = (float)luaL_checknumber(L, 5); + float h = (float)luaL_checknumber(L, 6); + float angle = (float)luaL_optnumber(L, 7, 0.0); + + Body *body = nullptr; + luax_catchexcept(L, [&]() { body = instance()->newRectangleBody(world, btype, x, y, w, h, angle); }); + + luax_pushtype(L, body); + body->release(); + return 1; +} + +int w_newPolygonBody(lua_State *L) +{ + World *world = luax_checkworld(L, 1); + + const char *typestr = luaL_checkstring(L, 2); + Body::Type btype = Body::BODY_STATIC; + if (!Body::getConstant(typestr, btype)) + return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr); + + int argc = lua_gettop(L); + + bool istable = lua_istable(L, 3); + if (istable) + argc = (int)luax_objlen(L, 3); + + if (argc % 2 != 0) + return luaL_error(L, "Number of vertex components must be a multiple of two."); + + int vcount = argc / 2; + std::vector coords; + + if (istable) + { + for (int i = 0; i < vcount; i++) + { + lua_rawgeti(L, 3, 1 + i * 2); + lua_rawgeti(L, 3, 2 + i * 2); + float x = (float)luaL_checknumber(L, -2); + float y = (float)luaL_checknumber(L, -1); + coords.emplace_back(x, y); + lua_pop(L, 2); + } + } + else + { + for (int i = 0; i < vcount; i++) + { + float x = (float)luaL_checknumber(L, 3 + i * 2); + float y = (float)luaL_checknumber(L, 4 + i * 2); + coords.emplace_back(x, y); + } + } + + Body *body = nullptr; + luax_catchexcept(L, [&]() { body = instance()->newPolygonBody(world, btype, coords.data(), (int)coords.size()); }); + + luax_pushtype(L, body); + body->release(); + return 1; +} + +int w_newEdgeBody(lua_State *L) +{ + World *world = luax_checkworld(L, 1); + + const char *typestr = luaL_checkstring(L, 2); + Body::Type btype = Body::BODY_STATIC; + if (!Body::getConstant(typestr, btype)) + return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr); + + float x1 = (float)luaL_checknumber(L, 3); + float y1 = (float)luaL_checknumber(L, 4); + float x2 = (float)luaL_checknumber(L, 5); + float y2 = (float)luaL_checknumber(L, 6); + bool oneSided = luax_optboolean(L, 7, false); + + Body *body = nullptr; + luax_catchexcept(L, [&]() { body = instance()->newEdgeBody(world, btype, x1, y1, x2, y2, oneSided); }); + + luax_pushtype(L, body); + body->release(); + return 1; +} + +int w_newChainBody(lua_State *L) +{ + World *world = luax_checkworld(L, 1); + + const char *typestr = luaL_checkstring(L, 2); + Body::Type btype = Body::BODY_STATIC; + if (!Body::getConstant(typestr, btype)) + return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr); + + bool loop = luax_checkboolean(L, 3); + + int argc = lua_gettop(L) - 3; + + bool istable = lua_istable(L, 4); + if (istable) + argc = (int)luax_objlen(L, 4); + + if (argc == 0 || argc % 2 != 0) + return luaL_error(L, "Number of vertex components must be a multiple of two."); + + int vcount = argc / 2; + std::vector coords; + + if (istable) + { + for (int i = 0; i < vcount; i++) + { + lua_rawgeti(L, 4, 1 + i * 2); + lua_rawgeti(L, 4, 2 + i * 2); + float x = (float)lua_tonumber(L, -2); + float y = (float)lua_tonumber(L, -1); + coords.emplace_back(x, y); + lua_pop(L, 2); + } + } + else + { + for (int i = 0; i < vcount; i++) + { + float x = (float)luaL_checknumber(L, 4 + i * 2); + float y = (float)luaL_checknumber(L, 5 + i * 2); + coords.emplace_back(x, y); + } + } + + Body *body = nullptr; + luax_catchexcept(L, [&]() { body = instance()->newChainBody(world, btype, loop, coords.data(), (int)coords.size()); }); + + luax_pushtype(L, body); + body->release(); + return 1; +} + int w_newFixture(lua_State *L) { Body *body = luax_checkbody(L, 1); @@ -103,7 +274,7 @@ int w_newCircleShape(lua_State *L) { float radius = (float)luaL_checknumber(L, 1); CircleShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(radius); }); + luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(0, 0, radius); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -132,7 +303,7 @@ int w_newRectangleShape(lua_State *L) float w = (float)luaL_checknumber(L, 1); float h = (float)luaL_checknumber(L, 2); PolygonShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(w, h); }); + luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(0, 0, w, h, 0); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -170,16 +341,91 @@ int w_newEdgeShape(lua_State *L) int w_newPolygonShape(lua_State *L) { - int ret = 0; - luax_catchexcept(L, [&](){ ret = instance()->newPolygonShape(L); }); - return ret; + int argc = lua_gettop(L); + + bool istable = lua_istable(L, 1); + + if (istable) + argc = (int)luax_objlen(L, 1); + + if (argc % 2 != 0) + return luaL_error(L, "Number of vertex components must be a multiple of two."); + + int vcount = argc / 2; + std::vector coords; + + if (istable) + { + for (int i = 0; i < vcount; i++) + { + lua_rawgeti(L, 1, 1 + i * 2); + lua_rawgeti(L, 1, 2 + i * 2); + float x = (float)luaL_checknumber(L, -2); + float y = (float)luaL_checknumber(L, -1); + coords.emplace_back(x, y); + lua_pop(L, 2); + } + } + else + { + for (int i = 0; i < vcount; i++) + { + float x = (float)luaL_checknumber(L, 1 + i * 2); + float y = (float)luaL_checknumber(L, 2 + i * 2); + coords.emplace_back(x, y); + } + } + + PolygonShape *shape = nullptr; + luax_catchexcept(L, [&](){ shape = instance()->newPolygonShape(coords.data(), (int)coords.size()); }); + luax_pushtype(L, shape); + shape->release(); + return 1; } int w_newChainShape(lua_State *L) { - int ret = 0; - luax_catchexcept(L, [&](){ ret = instance()->newChainShape(L); }); - return ret; + int argc = lua_gettop(L) - 1; // first argument is looping + + bool istable = lua_istable(L, 2); + + if (istable) + argc = (int)luax_objlen(L, 2); + + if (argc == 0 || argc % 2 != 0) + return luaL_error(L, "Number of vertex components must be a multiple of two."); + + int vcount = argc / 2; + bool loop = luax_checkboolean(L, 1); + std::vector coords; + + if (istable) + { + for (int i = 0; i < vcount; i++) + { + lua_rawgeti(L, 2, 1 + i * 2); + lua_rawgeti(L, 2, 2 + i * 2); + float x = (float)lua_tonumber(L, -2); + float y = (float)lua_tonumber(L, -1); + coords.emplace_back(x, y); + lua_pop(L, 2); + } + } + else + { + for (int i = 0; i < vcount; i++) + { + float x = (float)luaL_checknumber(L, 2 + i * 2); + float y = (float)luaL_checknumber(L, 3 + i * 2); + coords.emplace_back(x, y); + } + } + + ChainShape *shape = nullptr; + luax_catchexcept(L, [&]() { shape = instance()->newChainShape(loop, coords.data(), coords.size()); }); + luax_pushtype(L, shape); + shape->release(); + return 1; } int w_newDistanceJoint(lua_State *L) @@ -573,6 +819,11 @@ static const luaL_Reg functions[] = { { "newWorld", w_newWorld }, { "newBody", w_newBody }, + { "newCircleBody", w_newCircleBody }, + { "newRectangleBody", w_newRectangleBody }, + { "newPolygonBody", w_newPolygonBody }, + { "newEdgeBody", w_newEdgeBody }, + { "newChainBody", w_newChainBody }, { "newFixture", w_newFixture }, { "newCircleShape", w_newCircleShape }, { "newRectangleShape", w_newRectangleShape }, From 2702004bb2780ac89bda56a43b3dad0f659383dc Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Wed, 4 Oct 2023 20:00:44 -0300 Subject: [PATCH 03/36] Add Body:getFixture. Convenience method to get the first Fixture attached to the body. --- src/modules/physics/box2d/Body.cpp | 13 +++++++++++++ src/modules/physics/box2d/Body.h | 5 +++++ src/modules/physics/box2d/wrap_Body.cpp | 12 ++++++++++++ 3 files changed, 30 insertions(+) diff --git a/src/modules/physics/box2d/Body.cpp b/src/modules/physics/box2d/Body.cpp index a21f0be4d..2c8acfd64 100644 --- a/src/modules/physics/box2d/Body.cpp +++ b/src/modules/physics/box2d/Body.cpp @@ -461,6 +461,19 @@ World *Body::getWorld() const return world; } +Fixture *Body::getFixture() const +{ + b2Fixture *f = body->GetFixtureList(); + if (f == nullptr) + return nullptr; + + Fixture *fixture = (Fixture *)(f->GetUserData().pointer); + if (!fixture) + throw love::Exception("A fixture has escaped Memoizer!"); + + return fixture; +} + int Body::getFixtures(lua_State *L) const { lua_newtable(L); diff --git a/src/modules/physics/box2d/Body.h b/src/modules/physics/box2d/Body.h index 563812fe2..0be88c6c7 100644 --- a/src/modules/physics/box2d/Body.h +++ b/src/modules/physics/box2d/Body.h @@ -390,6 +390,11 @@ public: */ World *getWorld() const; + /** + * Gets the first Fixture attached to this Body. + **/ + Fixture *getFixture() const; + /** * Get an array of all the Fixtures attached to this Body. * @return An array of Fixtures. diff --git a/src/modules/physics/box2d/wrap_Body.cpp b/src/modules/physics/box2d/wrap_Body.cpp index 479e5bc27..6ed39ef2e 100644 --- a/src/modules/physics/box2d/wrap_Body.cpp +++ b/src/modules/physics/box2d/wrap_Body.cpp @@ -599,6 +599,17 @@ int w_Body_getWorld(lua_State *L) return 1; } +int w_Body_getFixture(lua_State *L) +{ + Body *t = luax_checkbody(L, 1); + Fixture *f = t->getFixture(); + if (f) + luax_pushtype(L, f); + else + lua_pushnil(L); + return 1; +} + int w_Body_getFixtures(lua_State *L) { Body *t = luax_checkbody(L, 1); @@ -713,6 +724,7 @@ static const luaL_Reg w_Body_functions[] = { "isFixedRotation", w_Body_isFixedRotation }, { "isTouching", w_Body_isTouching }, { "getWorld", w_Body_getWorld }, + { "getFixture", w_Body_getFixture }, { "getFixtures", w_Body_getFixtures }, { "getJoints", w_Body_getJoints }, { "getContacts", w_Body_getContacts }, From ac9ae8252410cd7dc3117259ed7bef8b52516cda Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 7 Oct 2023 15:17:24 -0300 Subject: [PATCH 04/36] love.physics: simplify Body and Shape API. #1130 - Shapes are now directly attached to Bodies when they're created (similar to love 0.7 and older). - Fixtures are removed. - All methods that were in Fixtures now exist in Shapes. - All APIs that used or returned a Fixture now do the same with a Shape. - Add new love.physics.new*Shape variants that take a Body as the first parameter. - Deprecate the new*Shape APIs that don't take a Body. - Deprecate love.physics.newFixture (the deprecated function now returns a Shape). - Replace Body:getFixture and Body:getFixtures with Body:getShape and Body:getShapes (Body:getFixtures is deprecated). - Replace World:queryFixturesInArea and World:getFixturesInArea with World:queryShapesInArea and World:getShapesInArea (queryFixturesInArea is deprecated). - Replace Contact:getFixtures with Contact:getShapes (Contact:getFixtures is deprecated). - Replace all love.physics callback Fixture parameters with Shape parameters. - Deprecate ChainShape:getChildEdge. --- CMakeLists.txt | 4 - src/common/deprecation.cpp | 6 + src/common/deprecation.h | 2 + src/modules/physics/box2d/Body.cpp | 22 +- src/modules/physics/box2d/Body.h | 11 +- src/modules/physics/box2d/ChainShape.cpp | 29 +- src/modules/physics/box2d/ChainShape.h | 2 +- src/modules/physics/box2d/CircleShape.cpp | 8 +- src/modules/physics/box2d/CircleShape.h | 2 +- src/modules/physics/box2d/Contact.cpp | 17 +- src/modules/physics/box2d/Contact.h | 4 +- src/modules/physics/box2d/EdgeShape.cpp | 11 +- src/modules/physics/box2d/EdgeShape.h | 2 +- src/modules/physics/box2d/Fixture.cpp | 349 ---------------- src/modules/physics/box2d/Fixture.h | 216 ---------- src/modules/physics/box2d/Physics.cpp | 135 +++--- src/modules/physics/box2d/Physics.h | 35 +- src/modules/physics/box2d/PolygonShape.cpp | 6 +- src/modules/physics/box2d/PolygonShape.h | 2 +- src/modules/physics/box2d/Shape.cpp | 395 ++++++++++++++++-- src/modules/physics/box2d/Shape.h | 132 +++++- src/modules/physics/box2d/World.cpp | 80 ++-- src/modules/physics/box2d/World.h | 15 +- src/modules/physics/box2d/wrap_Body.cpp | 26 +- src/modules/physics/box2d/wrap_ChainShape.cpp | 15 +- .../physics/box2d/wrap_CircleShape.cpp | 8 +- src/modules/physics/box2d/wrap_Contact.cpp | 26 +- src/modules/physics/box2d/wrap_EdgeShape.cpp | 14 +- src/modules/physics/box2d/wrap_Fixture.cpp | 311 -------------- src/modules/physics/box2d/wrap_Fixture.h | 43 -- src/modules/physics/box2d/wrap_Physics.cpp | 127 +++--- .../physics/box2d/wrap_PolygonShape.cpp | 8 +- src/modules/physics/box2d/wrap_Shape.cpp | 293 ++++++++++++- src/modules/physics/box2d/wrap_Shape.h | 1 + src/modules/physics/box2d/wrap_World.cpp | 16 +- 35 files changed, 1137 insertions(+), 1236 deletions(-) delete mode 100644 src/modules/physics/box2d/Fixture.cpp delete mode 100644 src/modules/physics/box2d/Fixture.h delete mode 100644 src/modules/physics/box2d/wrap_Fixture.cpp delete mode 100644 src/modules/physics/box2d/wrap_Fixture.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 644f71410..550d20fef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -837,8 +837,6 @@ set(LOVE_SRC_MODULE_PHYSICS_BOX2D src/modules/physics/box2d/DistanceJoint.h src/modules/physics/box2d/EdgeShape.cpp src/modules/physics/box2d/EdgeShape.h - src/modules/physics/box2d/Fixture.cpp - src/modules/physics/box2d/Fixture.h src/modules/physics/box2d/FrictionJoint.cpp src/modules/physics/box2d/FrictionJoint.h src/modules/physics/box2d/GearJoint.cpp @@ -881,8 +879,6 @@ set(LOVE_SRC_MODULE_PHYSICS_BOX2D src/modules/physics/box2d/wrap_DistanceJoint.h src/modules/physics/box2d/wrap_EdgeShape.cpp src/modules/physics/box2d/wrap_EdgeShape.h - src/modules/physics/box2d/wrap_Fixture.cpp - src/modules/physics/box2d/wrap_Fixture.h src/modules/physics/box2d/wrap_FrictionJoint.cpp src/modules/physics/box2d/wrap_FrictionJoint.h src/modules/physics/box2d/wrap_GearJoint.cpp diff --git a/src/common/deprecation.cpp b/src/common/deprecation.cpp index f0b0cae72..84f1b264f 100644 --- a/src/common/deprecation.cpp +++ b/src/common/deprecation.cpp @@ -107,8 +107,12 @@ std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere) if (info.apiType == API_FUNCTION) notice << "function "; + else if (info.apiType == API_FUNCTION_VARIANT) + notice << "function variant in "; else if (info.apiType == API_METHOD) notice << "method "; + else if (info.apiType == API_METHOD_VARIANT) + notice << "method variant in "; else if (info.apiType == API_CALLBACK) notice << "callback "; else if (info.apiType == API_FIELD) @@ -188,7 +192,9 @@ MarkDeprecated::~MarkDeprecated() STRINGMAP_BEGIN(APIType, API_MAX_ENUM, apiType) { { "function", API_FUNCTION }, + { "functionvariant", API_FUNCTION_VARIANT }, { "method", API_METHOD }, + { "methodvariant", API_METHOD_VARIANT }, { "callback", API_CALLBACK }, { "field", API_FIELD }, { "constant", API_CONSTANT }, diff --git a/src/common/deprecation.h b/src/common/deprecation.h index 7ac407cb3..55b0e89e2 100644 --- a/src/common/deprecation.h +++ b/src/common/deprecation.h @@ -32,7 +32,9 @@ namespace love enum APIType { API_FUNCTION, + API_FUNCTION_VARIANT, API_METHOD, + API_METHOD_VARIANT, API_CALLBACK, API_FIELD, API_CONSTANT, diff --git a/src/modules/physics/box2d/Body.cpp b/src/modules/physics/box2d/Body.cpp index 2c8acfd64..a3e7ee110 100644 --- a/src/modules/physics/box2d/Body.cpp +++ b/src/modules/physics/box2d/Body.cpp @@ -23,12 +23,12 @@ #include "common/math.h" #include "Shape.h" -#include "Fixture.h" #include "World.h" #include "Physics.h" // Needed for luax_pushjoint. #include "wrap_Joint.h" +#include "wrap_Shape.h" namespace love { @@ -461,20 +461,20 @@ World *Body::getWorld() const return world; } -Fixture *Body::getFixture() const +Shape *Body::getShape() const { b2Fixture *f = body->GetFixtureList(); if (f == nullptr) return nullptr; - Fixture *fixture = (Fixture *)(f->GetUserData().pointer); - if (!fixture) - throw love::Exception("A fixture has escaped Memoizer!"); + Shape *shape = (Shape *)(f->GetUserData().pointer); + if (!shape) + throw love::Exception("A Shape has escaped Memoizer!"); - return fixture; + return shape; } -int Body::getFixtures(lua_State *L) const +int Body::getShapes(lua_State *L) const { lua_newtable(L); b2Fixture *f = body->GetFixtureList(); @@ -483,10 +483,10 @@ int Body::getFixtures(lua_State *L) const { if (!f) break; - Fixture *fixture = (Fixture *)(f->GetUserData().pointer); - if (!fixture) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, fixture); + Shape *shape = (Shape *)(f->GetUserData().pointer); + if (!shape) + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, shape); lua_rawseti(L, -2, i); i++; } diff --git a/src/modules/physics/box2d/Body.h b/src/modules/physics/box2d/Body.h index 0be88c6c7..1d0b2d770 100644 --- a/src/modules/physics/box2d/Body.h +++ b/src/modules/physics/box2d/Body.h @@ -39,7 +39,6 @@ namespace box2d // Forward declarations. class World; class Shape; -class Fixture; /** * A Body is an entity which has position and orientation @@ -57,7 +56,6 @@ public: friend class CircleShape; friend class PolygonShape; friend class Shape; - friend class Fixture; // Public because joints et al ask for b2body b2Body *body; @@ -391,15 +389,14 @@ public: World *getWorld() const; /** - * Gets the first Fixture attached to this Body. + * Gets the first Shape attached to this Body. **/ - Fixture *getFixture() const; + Shape *getShape() const; /** - * Get an array of all the Fixtures attached to this Body. - * @return An array of Fixtures. + * Get an array of all the Shapes attached to this Body. **/ - int getFixtures(lua_State *L) const; + int getShapes(lua_State *L) const; /** * Get an array of all Joints attached to this Body. diff --git a/src/modules/physics/box2d/ChainShape.cpp b/src/modules/physics/box2d/ChainShape.cpp index 9bfef155c..7a2390ab0 100644 --- a/src/modules/physics/box2d/ChainShape.cpp +++ b/src/modules/physics/box2d/ChainShape.cpp @@ -34,8 +34,8 @@ namespace box2d love::Type ChainShape::type("ChainShape", &Shape::type); -ChainShape::ChainShape(b2ChainShape *c, bool own) - : Shape(c, own) +ChainShape::ChainShape(Body *body, const b2ChainShape &c) + : Shape(body, c) { } @@ -45,6 +45,7 @@ ChainShape::~ChainShape() void ChainShape::setNextVertex(float x, float y) { + throwIfShapeNotValid(); b2Vec2 v(x, y); b2ChainShape *c = (b2ChainShape *)shape; c->m_nextVertex = Physics::scaleDown(v); @@ -52,6 +53,7 @@ void ChainShape::setNextVertex(float x, float y) void ChainShape::setPreviousVertex(float x, float y) { + throwIfShapeNotValid(); b2Vec2 v(x, y); b2ChainShape *c = (b2ChainShape *)shape; c->m_prevVertex = Physics::scaleDown(v); @@ -59,44 +61,40 @@ void ChainShape::setPreviousVertex(float x, float y) b2Vec2 ChainShape::getNextVertex() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; - return Physics::scaleUp(c->m_nextVertex); } b2Vec2 ChainShape::getPreviousVertex() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; - return Physics::scaleUp(c->m_prevVertex); } EdgeShape *ChainShape::getChildEdge(int index) const { + throwIfShapeNotValid(); + b2ChainShape *c = (b2ChainShape *)shape; - b2EdgeShape *e = new b2EdgeShape; - try - { - c->GetChildEdge(e, index); - } - catch (love::Exception &) - { - delete e; - throw; - } + b2EdgeShape e; + c->GetChildEdge(&e, index); - return new EdgeShape(e, true); + return new EdgeShape(nullptr, e); } int ChainShape::getVertexCount() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; return c->m_count; } b2Vec2 ChainShape::getPoint(int index) const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; if (index < 0 || index >= c->m_count) throw love::Exception("Physics error: index out of bounds"); @@ -106,6 +104,7 @@ b2Vec2 ChainShape::getPoint(int index) const const b2Vec2 *ChainShape::getPoints() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; return c->m_vertices; } diff --git a/src/modules/physics/box2d/ChainShape.h b/src/modules/physics/box2d/ChainShape.h index 07f89f440..2b2ee14e1 100644 --- a/src/modules/physics/box2d/ChainShape.h +++ b/src/modules/physics/box2d/ChainShape.h @@ -45,7 +45,7 @@ public: * Create a new ChainShape from a Box2D chain shape. * @param c The chain shape. **/ - ChainShape(b2ChainShape *c, bool own = true); + ChainShape(Body *body, const b2ChainShape &c); virtual ~ChainShape(); diff --git a/src/modules/physics/box2d/CircleShape.cpp b/src/modules/physics/box2d/CircleShape.cpp index 545620f81..628b96bb0 100644 --- a/src/modules/physics/box2d/CircleShape.cpp +++ b/src/modules/physics/box2d/CircleShape.cpp @@ -34,8 +34,8 @@ namespace box2d love::Type CircleShape::type("CircleShape", &Shape::type); -CircleShape::CircleShape(b2CircleShape *c, bool own) - : Shape(c, own) +CircleShape::CircleShape(Body *body, const b2CircleShape &c) + : Shape(body, c) { } @@ -45,16 +45,19 @@ CircleShape::~CircleShape() float CircleShape::getRadius() const { + throwIfShapeNotValid(); return Physics::scaleUp(shape->m_radius); } void CircleShape::setRadius(float r) { + throwIfShapeNotValid(); shape->m_radius = Physics::scaleDown(r); } void CircleShape::getPoint(float &x_o, float &y_o) const { + throwIfShapeNotValid(); b2CircleShape *c = (b2CircleShape *) shape; x_o = Physics::scaleUp(c->m_p.x); y_o = Physics::scaleUp(c->m_p.y); @@ -62,6 +65,7 @@ void CircleShape::getPoint(float &x_o, float &y_o) const void CircleShape::setPoint(float x, float y) { + throwIfShapeNotValid(); b2CircleShape *c = (b2CircleShape *) shape; c->m_p = Physics::scaleDown(b2Vec2(x, y)); } diff --git a/src/modules/physics/box2d/CircleShape.h b/src/modules/physics/box2d/CircleShape.h index 438034bb8..20e5e3bac 100644 --- a/src/modules/physics/box2d/CircleShape.h +++ b/src/modules/physics/box2d/CircleShape.h @@ -50,7 +50,7 @@ public: * Create a new CircleShape from the a Box2D CircleShape definition. * @param c The CircleShape definition. **/ - CircleShape(b2CircleShape *c, bool own = true); + CircleShape(Body *body, const b2CircleShape &c); virtual ~CircleShape(); diff --git a/src/modules/physics/box2d/Contact.cpp b/src/modules/physics/box2d/Contact.cpp index 46e2b2a89..63b51ef04 100644 --- a/src/modules/physics/box2d/Contact.cpp +++ b/src/modules/physics/box2d/Contact.cpp @@ -35,7 +35,6 @@ Contact::Contact(World *world, b2Contact *contact) : contact(contact) , world(world) { - //contact->user world->registerObject(contact, this); } @@ -46,16 +45,16 @@ Contact::~Contact() void Contact::invalidate() { - if (contact != NULL) + if (contact != nullptr) { world->unregisterObject(contact); - contact = NULL; + contact = nullptr; } } bool Contact::isValid() { - return contact != NULL; + return contact != nullptr; } int Contact::getPositions(lua_State *L) @@ -144,13 +143,13 @@ void Contact::getChildren(int &childA, int &childB) childB = contact->GetChildIndexB(); } -void Contact::getFixtures(Fixture *&fixtureA, Fixture *&fixtureB) +void Contact::getShapes(Shape *&shapeA, Shape *&shapeB) { - fixtureA = (Fixture *) (contact->GetFixtureA()->GetUserData().pointer); - fixtureB = (Fixture *) (contact->GetFixtureB()->GetUserData().pointer); + shapeA = (Shape *) (contact->GetFixtureA()->GetUserData().pointer); + shapeB = (Shape *) (contact->GetFixtureB()->GetUserData().pointer); - if (!fixtureA || !fixtureB) - throw love::Exception("A fixture has escaped Memoizer!"); + if (!shapeA || !shapeB) + throw love::Exception("A Shape has escaped Memoizer!"); } } // box2d diff --git a/src/modules/physics/box2d/Contact.h b/src/modules/physics/box2d/Contact.h index afbe587d6..1287ca285 100644 --- a/src/modules/physics/box2d/Contact.h +++ b/src/modules/physics/box2d/Contact.h @@ -151,9 +151,9 @@ public: void getChildren(int &childA, int &childB); /** - * Gets the Fixtures associated with this Contact. + * Gets the Shapes associated with this Contact. **/ - void getFixtures(Fixture *&fixtureA, Fixture *&fixtureB); + void getShapes(Shape *&shapeA, Shape *&shapeB); private: diff --git a/src/modules/physics/box2d/EdgeShape.cpp b/src/modules/physics/box2d/EdgeShape.cpp index e4f3c146f..f49925783 100644 --- a/src/modules/physics/box2d/EdgeShape.cpp +++ b/src/modules/physics/box2d/EdgeShape.cpp @@ -34,8 +34,8 @@ namespace box2d love::Type EdgeShape::type("EdgeShape", &Shape::type); -EdgeShape::EdgeShape(b2EdgeShape *e, bool own) - : Shape(e, own) +EdgeShape::EdgeShape(Body *body, const b2EdgeShape &e) + : Shape(body, e) { } @@ -45,6 +45,7 @@ EdgeShape::~EdgeShape() void EdgeShape::setNextVertex(float x, float y) { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; b2Vec2 v(x, y); e->m_vertex3 = Physics::scaleDown(v); @@ -52,13 +53,14 @@ void EdgeShape::setNextVertex(float x, float y) b2Vec2 EdgeShape::getNextVertex() const { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; - return Physics::scaleUp(e->m_vertex3); } void EdgeShape::setPreviousVertex(float x, float y) { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; b2Vec2 v(x, y); e->m_vertex0 = Physics::scaleDown(v); @@ -66,13 +68,14 @@ void EdgeShape::setPreviousVertex(float x, float y) b2Vec2 EdgeShape::getPreviousVertex() const { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; - return Physics::scaleUp(e->m_vertex0); } int EdgeShape::getPoints(lua_State *L) { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; b2Vec2 v1 = Physics::scaleUp(e->m_vertex1); b2Vec2 v2 = Physics::scaleUp(e->m_vertex2); diff --git a/src/modules/physics/box2d/EdgeShape.h b/src/modules/physics/box2d/EdgeShape.h index 4db2383ce..9445e5b62 100644 --- a/src/modules/physics/box2d/EdgeShape.h +++ b/src/modules/physics/box2d/EdgeShape.h @@ -45,7 +45,7 @@ public: * Create a new EdgeShape from a Box2D edge shape. * @param e The edge shape. **/ - EdgeShape(b2EdgeShape *e, bool own = true); + EdgeShape(Body *body, const b2EdgeShape &e); virtual ~EdgeShape(); diff --git a/src/modules/physics/box2d/Fixture.cpp b/src/modules/physics/box2d/Fixture.cpp deleted file mode 100644 index 12fc9b2d7..000000000 --- a/src/modules/physics/box2d/Fixture.cpp +++ /dev/null @@ -1,349 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "Fixture.h" - -// Module -#include "Body.h" -#include "World.h" -#include "Physics.h" - -// STD -#include - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -love::Type Fixture::type("Fixture", &Object::type); - -Fixture::Fixture(Body *body, Shape *shape, float density) - : body(body) - , fixture(nullptr) -{ - b2FixtureDef def; - def.shape = shape->shape; - def.userData.pointer = (uintptr_t)this; - def.density = density; - fixture = body->body->CreateFixture(&def); - this->retain(); -} - -Fixture::~Fixture() -{ - if (ref) - delete ref; -} - -void Fixture::checkCreateShape() -{ - if (shape.get() != nullptr || fixture == nullptr || fixture->GetShape() == nullptr) - return; - - b2Shape *bshape = fixture->GetShape(); - - switch (bshape->GetType()) - { - case b2Shape::e_circle: - shape.set(new CircleShape((b2CircleShape *) bshape, false), Acquire::NORETAIN); - break; - case b2Shape::e_edge: - shape.set(new EdgeShape((b2EdgeShape *) bshape, false), Acquire::NORETAIN); - break; - case b2Shape::e_polygon: - shape.set(new PolygonShape((b2PolygonShape *) bshape, false), Acquire::NORETAIN); - break; - case b2Shape::e_chain: - shape.set(new ChainShape((b2ChainShape *) bshape, false), Acquire::NORETAIN); - break; - default: - break; - } -} - -Shape::Type Fixture::getType() -{ - checkCreateShape(); - if (shape.get() == nullptr) - return Shape::SHAPE_INVALID; - else - return shape->getType(); -} - -void Fixture::setFriction(float friction) -{ - fixture->SetFriction(friction); -} - -void Fixture::setRestitution(float restitution) -{ - fixture->SetRestitution(restitution); -} - -void Fixture::setDensity(float density) -{ - fixture->SetDensity(density); -} - -void Fixture::setSensor(bool sensor) -{ - fixture->SetSensor(sensor); -} - -float Fixture::getFriction() const -{ - return fixture->GetFriction(); -} - -float Fixture::getRestitution() const -{ - return fixture->GetRestitution(); -} - -float Fixture::getDensity() const -{ - return fixture->GetDensity(); -} - -bool Fixture::isSensor() const -{ - return fixture->IsSensor(); -} - -Body *Fixture::getBody() const -{ - return body; -} - -Shape *Fixture::getShape() -{ - checkCreateShape(); - return shape; -} - -bool Fixture::isValid() const -{ - return fixture != nullptr; -} - -void Fixture::setFilterData(int *v) -{ - b2Filter f; - f.categoryBits = (uint16) v[0]; - f.maskBits = (uint16) v[1]; - f.groupIndex = (int16) v[2]; - fixture->SetFilterData(f); -} - -void Fixture::getFilterData(int *v) -{ - b2Filter f = fixture->GetFilterData(); - v[0] = (int) f.categoryBits; - v[1] = (int) f.maskBits; - v[2] = (int) f.groupIndex; -} - -int Fixture::setCategory(lua_State *L) -{ - b2Filter f = fixture->GetFilterData(); - f.categoryBits = (uint16)getBits(L); - fixture->SetFilterData(f); - return 0; -} - -int Fixture::setMask(lua_State *L) -{ - b2Filter f = fixture->GetFilterData(); - f.maskBits = ~(uint16)getBits(L); - fixture->SetFilterData(f); - return 0; -} - -void Fixture::setGroupIndex(int index) -{ - b2Filter f = fixture->GetFilterData(); - f.groupIndex = (uint16)index; - fixture->SetFilterData(f); -} - -int Fixture::getGroupIndex() const -{ - b2Filter f = fixture->GetFilterData(); - return f.groupIndex; -} - -int Fixture::getCategory(lua_State *L) -{ - return pushBits(L, fixture->GetFilterData().categoryBits); -} - -int Fixture::getMask(lua_State *L) -{ - return pushBits(L, ~(fixture->GetFilterData().maskBits)); -} - -uint16 Fixture::getBits(lua_State *L) -{ - // Get number of args. - bool istable = lua_istable(L, 1); - int argc = istable ? (int) luax_objlen(L, 1) : lua_gettop(L); - - // The new bitset. - std::bitset<16> b; - - for (int i = 1; i <= argc; i++) - { - size_t bpos = 0; - - if (istable) - { - lua_rawgeti(L, 1, i); - bpos = (size_t) (lua_tointeger(L, -1) - 1); - lua_pop(L, 1); - } - else - bpos = (size_t) (lua_tointeger(L, i) - 1); - - if (bpos >= 16) - luaL_error(L, "Values must be in range 1-16."); - - b.set(bpos, true); - } - - return (uint16)b.to_ulong(); -} - -int Fixture::pushBits(lua_State *L, uint16 bits) -{ - // Create a bitset. - std::bitset<16> b((int)bits); - - // Push all set bits. - for (int i = 0; i<16; i++) - if (b.test(i)) - lua_pushinteger(L, i+1); - - // Count number of set bits. - return (int)b.count(); -} - -int Fixture::setUserData(lua_State *L) -{ - love::luax_assert_argc(L, 1, 1); - - if(!ref) - ref = new Reference(); - - ref->ref(L); - - return 0; -} - -int Fixture::getUserData(lua_State *L) -{ - if (ref != nullptr) - ref->push(L); - else - lua_pushnil(L); - - return 1; -} - -bool Fixture::testPoint(float x, float y) const -{ - return fixture->TestPoint(Physics::scaleDown(b2Vec2(x, y))); -} - -int Fixture::rayCast(lua_State *L) const -{ - float p1x = Physics::scaleDown((float)luaL_checknumber(L, 1)); - float p1y = Physics::scaleDown((float)luaL_checknumber(L, 2)); - float p2x = Physics::scaleDown((float)luaL_checknumber(L, 3)); - float p2y = Physics::scaleDown((float)luaL_checknumber(L, 4)); - float maxFraction = (float)luaL_checknumber(L, 5); - int childIndex = (int) luaL_optinteger(L, 6, 1) - 1; // Convert from 1-based index - b2RayCastInput input; - input.p1.Set(p1x, p1y); - input.p2.Set(p2x, p2y); - input.maxFraction = maxFraction; - b2RayCastOutput output; - if (!fixture->RayCast(&output, input, childIndex)) - return 0; // Nothing hit. - lua_pushnumber(L, output.normal.x); - lua_pushnumber(L, output.normal.y); - lua_pushnumber(L, output.fraction); - return 3; -} - -int Fixture::getBoundingBox(lua_State *L) const -{ - int childIndex = (int) luaL_optinteger(L, 1, 1) - 1; // Convert from 1-based index - b2AABB box; - luax_catchexcept(L, [&]() { box = fixture->GetAABB(childIndex); }); - box = Physics::scaleUp(box); - lua_pushnumber(L, box.lowerBound.x); - lua_pushnumber(L, box.lowerBound.y); - lua_pushnumber(L, box.upperBound.x); - lua_pushnumber(L, box.upperBound.y); - return 4; -} - -int Fixture::getMassData(lua_State *L) const -{ - b2MassData data; - fixture->GetMassData(&data); - b2Vec2 center = Physics::scaleUp(data.center); - lua_pushnumber(L, center.x); - lua_pushnumber(L, center.y); - lua_pushnumber(L, data.mass); - lua_pushnumber(L, data.I); - return 4; -} - -void Fixture::destroy(bool implicit) -{ - if (body->world->world->IsLocked()) - { - // Called during time step. Save reference for destruction afterwards. - this->retain(); - body->world->destructFixtures.push_back(this); - return; - } - - shape.set(nullptr); - - if (!implicit && fixture != nullptr) - body->body->DestroyFixture(fixture); - fixture = nullptr; - - // Remove userdata reference to avoid it sticking around after GC - if (ref) - ref->unref(); - - // Box2D fixture destroyed. Release its reference to the love Fixture. - this->release(); -} - -} // box2d -} // physics -} // love diff --git a/src/modules/physics/box2d/Fixture.h b/src/modules/physics/box2d/Fixture.h deleted file mode 100644 index 4f0d54e99..000000000 --- a/src/modules/physics/box2d/Fixture.h +++ /dev/null @@ -1,216 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#ifndef LOVE_PHYSICS_BOX2D_FIXTURE_H -#define LOVE_PHYSICS_BOX2D_FIXTURE_H - -// LOVE -#include "physics/Shape.h" -#include "physics/box2d/Body.h" -#include "physics/box2d/Shape.h" -#include "common/Object.h" -#include "common/Reference.h" - -// Box2D -#include - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -class World; - -/** - * A Fixture is used to attach a shape to a body for collision detection. - * A Fixture inherits its transform from its parent. Fixtures hold - * additional non-geometric data such as friction, collision filters, - * etc. - **/ -class Fixture : public Object -{ -public: - friend class Physics; - - static love::Type type; - - /** - * Creates a Fixture. - **/ - Fixture(Body *body, Shape *shape, float density); - - virtual ~Fixture(); - - /** - * Gets the type of the Fixture's Shape. Useful for - * debug drawing. - **/ - Shape::Type getType(); - - /** - * Gets the Shape attached to this Fixture. - **/ - Shape *getShape(); - - /** - * Returns true if the fixture is active in a Box2D world. - **/ - bool isValid() const; - - /** - * Checks whether this Fixture acts as a sensor. - * @return True if sensor, false otherwise. - **/ - bool isSensor() const; - - /** - * Set whether this Fixture should be a sensor or not. - * @param sensor True if sensor, false if not. - **/ - void setSensor(bool sensor); - - /** - * Gets the Body this Fixture is attached to. - **/ - Body *getBody() const; - - /** - * Sets the filter data. An integer array is used even though the - * first two elements are unsigned shorts. The elements are: - * category (16-bits), mask (16-bits) and group (32-bits/int). - **/ - void setFilterData(int *v); - - /** - * Gets the filter data. An integer array is used even though the - * first two elements are unsigned shorts. The elements are: - * category (16-bits), mask (16-bits) and group (32-bits/int). - **/ - void getFilterData(int *v); - - /** - * This function stores an in-C reference to - * arbitrary Lua data in the Box2D Fixture object. - **/ - int setUserData(lua_State *L); - - /** - * Gets the data set with setData. If no - * data is set, nil is returned. - **/ - int getUserData(lua_State *L); - - /** - * Sets the friction of the Fixture. - * @param friction The new friction. - **/ - void setFriction(float friction); - - /** - * Sets the restitution for the Fixture. - * @param restitution The restitution. - **/ - void setRestitution(float restitution); - - /** - * Sets the density of the Fixture. - * @param density The density of the Fixture. - **/ - void setDensity(float density); - - /** - * Gets the friction of the Fixture. - * @returns The friction. - **/ - float getFriction() const; - - /** - * Gets the restitution of the Fixture. - * @return The restitution of the Fixture. - **/ - float getRestitution() const; - - /** - * Gets the density of the Fixture. - * @return The density. - **/ - float getDensity() const; - - /** - * Checks if a point is inside the Fixture. - * @param x The x-component of the point. - * @param y The y-component of the point. - **/ - bool testPoint(float x, float y) const; - - /** - * Cast a ray against this Fixture. - **/ - int rayCast(lua_State *L) const; - - void setGroupIndex(int index); - int getGroupIndex() const; - - int setCategory(lua_State *L); - int setMask(lua_State *L); - int getCategory(lua_State *L); - int getMask(lua_State *L); - uint16 getBits(lua_State *L); - int pushBits(lua_State *L, uint16 bits); - - /** - * Gets the bounding box for this Fixture. - * The function returns eight values which can be - * passed directly to love.graphics.polygon. - **/ - int getBoundingBox(lua_State *L) const; - - /** - * Gets the mass data for this Fixture. - * This operation may be expensive. - **/ - int getMassData(lua_State *L) const; - - /** - * Destroys this fixture. - **/ - void destroy(bool implicit = false); - -protected: - - void checkCreateShape(); - - Body *body; - b2Fixture *fixture; - - // Reference to arbitrary data. - Reference* ref = nullptr; - - StrongRef shape; - -}; - -} // box2d -} // physics -} // love - -#endif // LOVE_PHYSICS_BOX2D_FIXTURE_H diff --git a/src/modules/physics/box2d/Physics.cpp b/src/modules/physics/box2d/Physics.cpp index 5c3a134f9..6fb860b18 100644 --- a/src/modules/physics/box2d/Physics.cpp +++ b/src/modules/physics/box2d/Physics.cpp @@ -35,6 +35,7 @@ namespace box2d float Physics::meter = Physics::DEFAULT_METER; Physics::Physics() + : blockAllocator() { meter = DEFAULT_METER; } @@ -66,8 +67,7 @@ Body *Physics::newBody(World *world, Body::Type type) Body *Physics::newCircleBody(World *world, Body::Type type, float x, float y, float radius) { StrongRef body(newBody(world, x, y, type), Acquire::NORETAIN); - StrongRef shape(newCircleShape(0, 0, radius), Acquire::NORETAIN); - StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + StrongRef shape(newCircleShape(body, 0, 0, radius), Acquire::NORETAIN); body->retain(); return body.get(); } @@ -75,8 +75,7 @@ Body *Physics::newCircleBody(World *world, Body::Type type, float x, float y, fl Body *Physics::newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle) { StrongRef body(newBody(world, x, y, type), Acquire::NORETAIN); - StrongRef shape(newRectangleShape(0, 0, w, h, angle), Acquire::NORETAIN); - StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + StrongRef shape(newRectangleShape(body, 0, 0, w, h, angle), Acquire::NORETAIN); body->retain(); return body.get(); } @@ -93,8 +92,7 @@ Body *Physics::newPolygonBody(World *world, Body::Type type, const Vector2 *coor localcoords.push_back(coords[i] - origin); StrongRef body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN); - StrongRef shape(newPolygonShape(localcoords.data(), count), Acquire::NORETAIN); - StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + StrongRef shape(newPolygonShape(body, localcoords.data(), count), Acquire::NORETAIN); body->retain(); return body.get(); } @@ -104,8 +102,7 @@ Body *Physics::newEdgeBody(World *world, Body::Type type, float x1, float y1, fl float wx = (x2 - x1) / 2.0f; float wy = (y2 - y1) / 2.0f; StrongRef body(newBody(world, wx, wy, type), Acquire::NORETAIN); - StrongRef shape(newEdgeShape(x1 - wx, y1 - wy, x2 - wx, y2 - wy, oneSided), Acquire::NORETAIN); - StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + StrongRef shape(newEdgeShape(body, x1 - wx, y1 - wy, x2 - wx, y2 - wy, oneSided), Acquire::NORETAIN); body->retain(); return body.get(); } @@ -122,44 +119,75 @@ Body *Physics::newChainBody(World *world, Body::Type type, bool loop, const Vect localcoords.push_back(coords[i] - origin); StrongRef body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN); - StrongRef shape(newChainShape(loop, localcoords.data(), count), Acquire::NORETAIN); - StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN); + StrongRef shape(newChainShape(body, loop, localcoords.data(), count), Acquire::NORETAIN); body->retain(); return body.get(); } -CircleShape *Physics::newCircleShape(float x, float y, float radius) +Shape *Physics::newAttachedShape(Body *body, Shape *prototype, float density) { - b2CircleShape *s = new b2CircleShape(); - s->m_p = Physics::scaleDown(b2Vec2(x, y)); - s->m_radius = Physics::scaleDown(radius); - return new CircleShape(s); + if (prototype->isValid()) + throw love::Exception("The given Shape must not be part of the World."); + + Shape *shape = nullptr; + + switch (prototype->getType()) + { + case Shape::SHAPE_CIRCLE: + shape = new CircleShape(body, *(b2CircleShape *) prototype->shape); + break; + case Shape::SHAPE_POLYGON: + shape = new PolygonShape(body, *(b2PolygonShape *) prototype->shape); + break; + case Shape::SHAPE_EDGE: + shape = new EdgeShape(body, *(b2EdgeShape *) prototype->shape); + break; + case Shape::SHAPE_CHAIN: + shape = new ChainShape(body, *(b2ChainShape *) prototype->shape); + break; + default: + throw love::Exception("Unknown shape type."); + break; + } + + shape->setDensity(density); + body->resetMassData(); + + return shape; } -PolygonShape *Physics::newRectangleShape(float x, float y, float w, float h, float angle) +CircleShape *Physics::newCircleShape(Body *body, float x, float y, float radius) { - b2PolygonShape *s = new b2PolygonShape(); - s->SetAsBox(Physics::scaleDown(w/2.0f), Physics::scaleDown(h/2.0f), Physics::scaleDown(b2Vec2(x, y)), angle); - return new PolygonShape(s); + b2CircleShape s; + s.m_p = Physics::scaleDown(b2Vec2(x, y)); + s.m_radius = Physics::scaleDown(radius); + return new CircleShape(body, s); } -EdgeShape *Physics::newEdgeShape(float x1, float y1, float x2, float y2, bool oneSided) +PolygonShape *Physics::newRectangleShape(Body *body, float x, float y, float w, float h, float angle) { - b2EdgeShape *s = new b2EdgeShape(); + b2PolygonShape s; + s.SetAsBox(Physics::scaleDown(w/2.0f), Physics::scaleDown(h/2.0f), Physics::scaleDown(b2Vec2(x, y)), angle); + return new PolygonShape(body, s); +} + +EdgeShape *Physics::newEdgeShape(Body *body, float x1, float y1, float x2, float y2, bool oneSided) +{ + b2EdgeShape s; if (oneSided) { b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1)); b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); - s->SetOneSided(v1, v1, v2, v2); + s.SetOneSided(v1, v1, v2, v2); } else { - s->SetTwoSided(Physics::scaleDown(b2Vec2(x1, y1)), Physics::scaleDown(b2Vec2(x2, y2))); + s.SetTwoSided(Physics::scaleDown(b2Vec2(x1, y1)), Physics::scaleDown(b2Vec2(x2, y2))); } - return new EdgeShape(s); + return new EdgeShape(body, s); } -PolygonShape *Physics::newPolygonShape(const Vector2 *coords, int count) +PolygonShape *Physics::newPolygonShape(Body *body, const Vector2 *coords, int count) { // 3 to 8 (b2_maxPolygonVertices) vertices if (count < 3) @@ -172,44 +200,28 @@ PolygonShape *Physics::newPolygonShape(const Vector2 *coords, int count) for (int i = 0; i < count; i++) vecs[i] = Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y)); - b2PolygonShape *s = new b2PolygonShape(); + b2PolygonShape s; - try - { - s->Set(vecs, count); - } - catch (love::Exception &) - { - delete s; - throw; - } + s.Set(vecs, count); - return new PolygonShape(s); + return new PolygonShape(body, s); } -ChainShape *Physics::newChainShape(bool loop, const Vector2 *coords, int count) +ChainShape *Physics::newChainShape(Body *body, bool loop, const Vector2 *coords, int count) { std::vector vecs; for (int i = 0; i < count; i++) vecs.push_back(Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y))); - b2ChainShape *s = new b2ChainShape(); + b2ChainShape s; - try - { - if (loop) - s->CreateLoop(vecs.data(), count); - else - s->CreateChain(vecs.data(), count, vecs[0], vecs[count - 1]); - } - catch (love::Exception &) - { - delete s; - throw; - } + if (loop) + s.CreateLoop(vecs.data(), count); + else + s.CreateChain(vecs.data(), count, vecs[0], vecs[count - 1]); - return new ChainShape(s); + return new ChainShape(body, s); } DistanceJoint *Physics::newDistanceJoint(Body *body1, Body *body2, float x1, float y1, float x2, float y2, bool collideConnected) @@ -287,16 +299,10 @@ MotorJoint *Physics::newMotorJoint(Body *body1, Body *body2, float correctionFac return new MotorJoint(body1, body2, correctionFactor, collideConnected); } - -Fixture *Physics::newFixture(Body *body, Shape *shape, float density) -{ - return new Fixture(body, shape, density); -} - int Physics::getDistance(lua_State *L) { - Fixture *fixtureA = luax_checktype(L, 1); - Fixture *fixtureB = luax_checktype(L, 2); + Shape *shapeA = luax_checktype(L, 1); + Shape *shapeB = luax_checktype(L, 2); b2DistanceProxy pA, pB; b2DistanceInput i; b2DistanceOutput o; @@ -304,12 +310,15 @@ int Physics::getDistance(lua_State *L) c.count = 0; luax_catchexcept(L, [&]() { - pA.Set(fixtureA->fixture->GetShape(), 0); - pB.Set(fixtureB->fixture->GetShape(), 0); + if (!shapeA->isValid() || !shapeB->isValid()) + throw love::Exception("The given Shape is not active in the physics World."); + + pA.Set(shapeA->fixture->GetShape(), 0); + pB.Set(shapeB->fixture->GetShape(), 0); i.proxyA = pA; i.proxyB = pB; - i.transformA = fixtureA->fixture->GetBody()->GetTransform(); - i.transformB = fixtureB->fixture->GetBody()->GetTransform(); + i.transformA = shapeA->fixture->GetBody()->GetTransform(); + i.transformB = shapeB->fixture->GetBody()->GetTransform(); i.useRadii = true; b2Distance(&o, &c, &i); }); diff --git a/src/modules/physics/box2d/Physics.h b/src/modules/physics/box2d/Physics.h index 9c81ffe41..c198a7b78 100644 --- a/src/modules/physics/box2d/Physics.h +++ b/src/modules/physics/box2d/Physics.h @@ -28,7 +28,6 @@ #include "World.h" #include "Contact.h" #include "Body.h" -#include "Fixture.h" #include "Shape.h" #include "CircleShape.h" #include "PolygonShape.h" @@ -95,9 +94,9 @@ public: Body *newBody(World *world, Body::Type type); /** - * Convenience functions for creating a Body, Shape, and Fixture all in one - * call. The body's world position is the center/average of the given - * coordinates, and the shape is centered at the local origin. + * Convenience functions for creating a Body and Shape all in one call. The + * body's world position is the center/average of the given coordinates, + * and the shape is centered at the local origin. **/ Body *newCircleBody(World *world, Body::Type type, float x, float y, float radius); Body *newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle); @@ -105,13 +104,16 @@ public: Body *newEdgeBody(World *world, Body::Type type, float x1, float y1, float x2, float y2, bool oneSided); Body *newChainBody(World *world, Body::Type type, bool loop, const Vector2 *coords, int count); + // Necessary to support the deprecated newFixture API. + Shape *newAttachedShape(Body *body, Shape *prototype, float density); + /** * Creates a new CircleShape at (x,y) in local coordinates. * @param x The offset along the x-axis. * @param y The offset along the y-axis. * @param radius The radius of the circle. **/ - CircleShape *newCircleShape(float x, float y, float radius); + CircleShape *newCircleShape(Body *body, float x, float y, float radius); /** * Shorthand for creating rectangular PolygonShapes. The rectangle @@ -122,7 +124,7 @@ public: * @param h The height of the rectangle. * @param angle The angle of the rectangle. (rad) **/ - PolygonShape *newRectangleShape(float x, float y, float w, float h, float angle); + PolygonShape *newRectangleShape(Body *body, float x, float y, float w, float h, float angle); /** * Creates a new EdgeShape. The edge will be created from @@ -132,18 +134,17 @@ public: * @param x2 The x coordinate of the second point. * @param y2 The y coordinate of the second point. **/ - EdgeShape *newEdgeShape(float x1, float y1, float x2, float y2, bool oneSided); + EdgeShape *newEdgeShape(Body *body, float x1, float y1, float x2, float y2, bool oneSided); /** * Creates a new PolygonShape from a variable number of vertices. **/ - //int newPolygonShape(lua_State *L); - PolygonShape *newPolygonShape(const Vector2 *coords, int count); + PolygonShape *newPolygonShape(Body *body, const Vector2 *coords, int count); /** * Creates a new ChainShape from a variable number of vertices. **/ - ChainShape *newChainShape(bool loop, const Vector2 *coords, int count); + ChainShape *newChainShape(Body *body, bool loop, const Vector2 *coords, int count); /** * Creates a new DistanceJoint connecting body1 with body2. @@ -263,15 +264,6 @@ public: MotorJoint *newMotorJoint(Body *body1, Body *body2); MotorJoint *newMotorJoint(Body *body1, Body *body2, float correctionFactor, bool collideConnected); - /** - * Creates a new Fixture attaching shape to body. - * @param body The body to attach the Fixture to. - * @param shape The shape to attach to the Fixture, - * @param density The density of the Fixture. - **/ - - Fixture *newFixture(Body *body, Shape *shape, float density); - /** * Calculates the distance between two Fixtures. * @param fixtureA The first Fixture. @@ -393,10 +385,15 @@ public: **/ static void computeAngularFrequency(float &frequency, float &ratio, float stiffness, float damping, b2Body *bodyA, b2Body *bodyB); + b2BlockAllocator *getBlockAllocator() { return &blockAllocator; } + private: // The length of one meter in pixels. static float meter; + + b2BlockAllocator blockAllocator; + }; // Physics } // box2d diff --git a/src/modules/physics/box2d/PolygonShape.cpp b/src/modules/physics/box2d/PolygonShape.cpp index 4655c8cc4..12b314f02 100644 --- a/src/modules/physics/box2d/PolygonShape.cpp +++ b/src/modules/physics/box2d/PolygonShape.cpp @@ -34,8 +34,8 @@ namespace box2d love::Type PolygonShape::type("PolygonShape", &Shape::type); -PolygonShape::PolygonShape(b2PolygonShape *p, bool own) - : Shape(p, own) +PolygonShape::PolygonShape(Body *body, const b2PolygonShape &p) + : Shape(body, p) { } @@ -45,6 +45,7 @@ PolygonShape::~PolygonShape() int PolygonShape::getPoints(lua_State *L) { + throwIfShapeNotValid(); love::luax_assert_argc(L, 0); b2PolygonShape *p = (b2PolygonShape *)shape; int count = p->m_count; @@ -59,6 +60,7 @@ int PolygonShape::getPoints(lua_State *L) bool PolygonShape::validate() const { + throwIfShapeNotValid(); b2PolygonShape *p = (b2PolygonShape *)shape; return p->Validate(); } diff --git a/src/modules/physics/box2d/PolygonShape.h b/src/modules/physics/box2d/PolygonShape.h index 9a632ae6d..5d400553f 100644 --- a/src/modules/physics/box2d/PolygonShape.h +++ b/src/modules/physics/box2d/PolygonShape.h @@ -48,7 +48,7 @@ public: * Create a new PolygonShape from a Box2D polygon definition. * @param p The polygon definition. **/ - PolygonShape(b2PolygonShape *p, bool own = true); + PolygonShape(Body *body, const b2PolygonShape &p); virtual ~PolygonShape(); diff --git a/src/modules/physics/box2d/Shape.cpp b/src/modules/physics/box2d/Shape.cpp index e65807582..c47c4c7ff 100644 --- a/src/modules/physics/box2d/Shape.cpp +++ b/src/modules/physics/box2d/Shape.cpp @@ -35,54 +35,348 @@ namespace physics namespace box2d { -Shape::Shape() +Shape::Shape(Body *body, const b2Shape &shape) : shape(nullptr) , own(false) + , shapeType(SHAPE_INVALID) + , body(body) + , fixture(nullptr) { -} + if (body) + { + b2FixtureDef def; + def.shape = &shape; + def.userData.pointer = (uintptr_t)this; + def.density = 1.0f; + fixture = body->body->CreateFixture(&def); + this->shape = fixture->GetShape(); + retain(); // Shape::destroy does the release(). + } + else + { + // Path to support deprecated APIs. + auto physics = Module::getInstance(Module::M_PHYSICS); + this->shape = shape.Clone(physics->getBlockAllocator()); + own = true; + } -Shape::Shape(b2Shape *shape, bool own) - : shape(shape) - , own(own) -{ + switch (this->shape->GetType()) + { + case b2Shape::e_circle: + shapeType = SHAPE_CIRCLE; + break; + case b2Shape::e_polygon: + shapeType = SHAPE_POLYGON; + break; + case b2Shape::e_edge: + shapeType = SHAPE_EDGE; + break; + case b2Shape::e_chain: + shapeType = SHAPE_CHAIN; + break; + default: + shapeType = SHAPE_INVALID; + break; + } } Shape::~Shape() { if (shape && own) - delete shape; + { + auto physics = Module::getInstance(Module::M_PHYSICS); + auto allocator = physics->getBlockAllocator(); + + // Taken from b2Fixture::Destroy. Not very pretty... + switch (shapeType) + { + case SHAPE_CIRCLE: + { + b2CircleShape *s = (b2CircleShape*)shape; + s->~b2CircleShape(); + allocator->Free(s, sizeof(b2CircleShape)); + break; + } + case SHAPE_EDGE: + { + b2EdgeShape *s = (b2EdgeShape*)shape; + s->~b2EdgeShape(); + allocator->Free(s, sizeof(b2EdgeShape)); + break; + } + case SHAPE_POLYGON: + { + b2PolygonShape *s = (b2PolygonShape*)shape; + s->~b2PolygonShape(); + allocator->Free(s, sizeof(b2PolygonShape)); + break; + } + case SHAPE_CHAIN: + { + b2ChainShape *s = (b2ChainShape*)shape; + s->~b2ChainShape(); + allocator->Free(s, sizeof(b2ChainShape)); + break; + } + default: + break; + } + } + + if (ref) + delete ref; +} + +void Shape::destroy(bool implicit) +{ + if (fixture == nullptr) + return; + + if (body->world->world->IsLocked()) + { + // Called during time step. Save reference for destruction afterwards. + this->retain(); + body->world->destructShapes.push_back(this); + return; + } + + if (!implicit && fixture != nullptr) + body->body->DestroyFixture(fixture); + + fixture = nullptr; shape = nullptr; + body = nullptr; + + // Remove userdata reference to avoid it sticking around after GC + if (ref) + ref->unref(); + + // Box2D fixture destroyed. Release its reference to the love Shape. + release(); +} + +void Shape::throwIfFixtureNotValid() const +{ + if (fixture == nullptr) + throw love::Exception("Shape must be active in the physics World to use this method."); +} + +void Shape::throwIfShapeNotValid() const +{ + if (shape == nullptr) + throw love::Exception("Cannot call this method on a destroyed Shape."); } Shape::Type Shape::getType() const { - switch (shape->GetType()) - { - case b2Shape::e_circle: - return SHAPE_CIRCLE; - case b2Shape::e_polygon: - return SHAPE_POLYGON; - case b2Shape::e_edge: - return SHAPE_EDGE; - case b2Shape::e_chain: - return SHAPE_CHAIN; - default: - return SHAPE_INVALID; - } + return shapeType; +} + +void Shape::setFriction(float friction) +{ + throwIfFixtureNotValid(); + fixture->SetFriction(friction); +} + +void Shape::setRestitution(float restitution) +{ + throwIfFixtureNotValid(); + fixture->SetRestitution(restitution); +} + +void Shape::setDensity(float density) +{ + throwIfFixtureNotValid(); + fixture->SetDensity(density); +} + +void Shape::setSensor(bool sensor) +{ + throwIfFixtureNotValid(); + fixture->SetSensor(sensor); +} + +float Shape::getFriction() const +{ + throwIfFixtureNotValid(); + return fixture->GetFriction(); +} + +float Shape::getRestitution() const +{ + throwIfFixtureNotValid(); + return fixture->GetRestitution(); +} + +float Shape::getDensity() const +{ + throwIfFixtureNotValid(); + return fixture->GetDensity(); +} + +bool Shape::isSensor() const +{ + throwIfFixtureNotValid(); + return fixture->IsSensor(); +} + +Body *Shape::getBody() const +{ + return body; } float Shape::getRadius() const { + throwIfShapeNotValid(); return Physics::scaleUp(shape->m_radius); } int Shape::getChildCount() const { + throwIfShapeNotValid(); return shape->GetChildCount(); } +void Shape::setFilterData(int *v) +{ + throwIfFixtureNotValid(); + b2Filter f; + f.categoryBits = (uint16) v[0]; + f.maskBits = (uint16) v[1]; + f.groupIndex = (int16) v[2]; + fixture->SetFilterData(f); +} + +void Shape::getFilterData(int *v) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + v[0] = (int) f.categoryBits; + v[1] = (int) f.maskBits; + v[2] = (int) f.groupIndex; +} + +int Shape::setCategory(lua_State *L) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + f.categoryBits = (uint16)getBits(L); + fixture->SetFilterData(f); + return 0; +} + +int Shape::setMask(lua_State *L) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + f.maskBits = ~(uint16)getBits(L); + fixture->SetFilterData(f); + return 0; +} + +void Shape::setGroupIndex(int index) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + f.groupIndex = (uint16)index; + fixture->SetFilterData(f); +} + +int Shape::getGroupIndex() const +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + return f.groupIndex; +} + +int Shape::getCategory(lua_State *L) +{ + throwIfFixtureNotValid(); + return pushBits(L, fixture->GetFilterData().categoryBits); +} + +int Shape::getMask(lua_State *L) +{ + throwIfFixtureNotValid(); + return pushBits(L, ~(fixture->GetFilterData().maskBits)); +} + +uint16 Shape::getBits(lua_State *L) +{ + // Get number of args. + bool istable = lua_istable(L, 1); + int argc = istable ? (int) luax_objlen(L, 1) : lua_gettop(L); + + // The new bitset. + std::bitset<16> b; + + for (int i = 1; i <= argc; i++) + { + size_t bpos = 0; + + if (istable) + { + lua_rawgeti(L, 1, i); + bpos = (size_t) (lua_tointeger(L, -1) - 1); + lua_pop(L, 1); + } + else + bpos = (size_t) (lua_tointeger(L, i) - 1); + + if (bpos >= 16) + luaL_error(L, "Values must be in range 1-16."); + + b.set(bpos, true); + } + + return (uint16)b.to_ulong(); +} + +int Shape::pushBits(lua_State *L, uint16 bits) +{ + // Create a bitset. + std::bitset<16> b((int)bits); + + // Push all set bits. + for (int i = 0; i<16; i++) + if (b.test(i)) + lua_pushinteger(L, i+1); + + // Count number of set bits. + return (int)b.count(); +} + +int Shape::setUserData(lua_State *L) +{ + love::luax_assert_argc(L, 1, 1); + + if(!ref) + ref = new Reference(); + + ref->ref(L); + + return 0; +} + +int Shape::getUserData(lua_State *L) +{ + if (ref != nullptr) + ref->push(L); + else + lua_pushnil(L); + + return 1; +} + +bool Shape::testPoint(float x, float y) const +{ + throwIfFixtureNotValid(); + return fixture->TestPoint(Physics::scaleDown(b2Vec2(x, y))); +} + bool Shape::testPoint(float x, float y, float r, float px, float py) const { + throwIfShapeNotValid(); b2Vec2 point(px, py); b2Transform transform(Physics::scaleDown(b2Vec2(x, y)), b2Rot(r)); return shape->TestPoint(transform, Physics::scaleDown(point)); @@ -95,18 +389,34 @@ int Shape::rayCast(lua_State *L) const float p2x = Physics::scaleDown((float)luaL_checknumber(L, 3)); float p2y = Physics::scaleDown((float)luaL_checknumber(L, 4)); float maxFraction = (float)luaL_checknumber(L, 5); - float x = Physics::scaleDown((float)luaL_checknumber(L, 6)); - float y = Physics::scaleDown((float)luaL_checknumber(L, 7)); - float r = (float)luaL_checknumber(L, 8); - int childIndex = (int) luaL_optinteger(L, 9, 1) - 1; // Convert from 1-based index + b2RayCastInput input; + b2RayCastOutput output; input.p1.Set(p1x, p1y); input.p2.Set(p2x, p2y); input.maxFraction = maxFraction; - b2Transform transform(b2Vec2(x, y), b2Rot(r)); - b2RayCastOutput output; - if (!shape->RayCast(&output, input, transform, childIndex)) - return 0; // No hit. + + if (lua_isnoneornil(L, 7)) + { + throwIfFixtureNotValid(); + int childIndex = (int) luaL_optinteger(L, 6, 1) - 1; // Convert from 1-based index + if (!fixture->RayCast(&output, input, childIndex)) + return 0; // Nothing hit. + } + else + { + throwIfShapeNotValid(); + float x = Physics::scaleDown((float)luaL_checknumber(L, 6)); + float y = Physics::scaleDown((float)luaL_checknumber(L, 7)); + float r = (float)luaL_checknumber(L, 8); + int childIndex = (int) luaL_optinteger(L, 9, 1) - 1; // Convert from 1-based index + + b2Transform transform(b2Vec2(x, y), b2Rot(r)); + + if (!shape->RayCast(&output, input, transform, childIndex)) + return 0; // No hit. + } + lua_pushnumber(L, output.normal.x); lua_pushnumber(L, output.normal.y); lua_pushnumber(L, output.fraction); @@ -115,6 +425,7 @@ int Shape::rayCast(lua_State *L) const int Shape::computeAABB(lua_State *L) const { + throwIfShapeNotValid(); float x = Physics::scaleDown((float)luaL_checknumber(L, 1)); float y = Physics::scaleDown((float)luaL_checknumber(L, 2)); float r = (float)luaL_checknumber(L, 3); @@ -132,6 +443,7 @@ int Shape::computeAABB(lua_State *L) const int Shape::computeMass(lua_State *L) const { + throwIfShapeNotValid(); float density = (float)luaL_checknumber(L, 1); b2MassData data; shape->ComputeMass(&data, density); @@ -143,6 +455,33 @@ int Shape::computeMass(lua_State *L) const return 4; } +int Shape::getBoundingBox(lua_State *L) const +{ + throwIfFixtureNotValid(); + int childIndex = (int) luaL_optinteger(L, 1, 1) - 1; // Convert from 1-based index + b2AABB box; + luax_catchexcept(L, [&]() { box = fixture->GetAABB(childIndex); }); + box = Physics::scaleUp(box); + lua_pushnumber(L, box.lowerBound.x); + lua_pushnumber(L, box.lowerBound.y); + lua_pushnumber(L, box.upperBound.x); + lua_pushnumber(L, box.upperBound.y); + return 4; +} + +int Shape::getMassData(lua_State *L) const +{ + throwIfFixtureNotValid(); + b2MassData data; + fixture->GetMassData(&data); + b2Vec2 center = Physics::scaleUp(data.center); + lua_pushnumber(L, center.x); + lua_pushnumber(L, center.y); + lua_pushnumber(L, data.mass); + lua_pushnumber(L, data.I); + return 4; +} + } // box2d } // physics } // love diff --git a/src/modules/physics/box2d/Shape.h b/src/modules/physics/box2d/Shape.h index 94b314dc9..6eb4e0586 100644 --- a/src/modules/physics/box2d/Shape.h +++ b/src/modules/physics/box2d/Shape.h @@ -24,6 +24,7 @@ // LOVE #include "physics/Shape.h" #include "physics/box2d/Body.h" +#include "common/Reference.h" // Box2D #include @@ -45,34 +46,155 @@ class Shape : public love::physics::Shape { public: - friend class Fixture; + friend class Physics; /** * Creates a Shape. **/ - Shape(); - Shape(b2Shape *shape, bool own = true); + Shape(Body *body, const b2Shape &shape); virtual ~Shape(); + void destroy(bool implicit = false); + + /** + * Returns true if the shape is active in a Box2D world. + **/ + bool isValid() const { return fixture != nullptr; } + + /** + * Returns true if the shape has not been destroyed. + **/ + bool isShapeValid() const { return shape != nullptr; } + + /** + * Checks whether this Shape acts as a sensor. + **/ + bool isSensor() const; + + /** + * Set whether this Shape should be a sensor or not. + **/ + void setSensor(bool sensor); + + /** + * Gets the Body this Shape is attached to. + **/ + Body *getBody() const; + + /** + * Sets the filter data. An integer array is used even though the + * first two elements are unsigned shorts. The elements are: + * category (16-bits), mask (16-bits) and group (32-bits/int). + **/ + void setFilterData(int *v); + + /** + * Gets the filter data. An integer array is used even though the + * first two elements are unsigned shorts. The elements are: + * category (16-bits), mask (16-bits) and group (32-bits/int). + **/ + void getFilterData(int *v); + + /** + * This function stores an in-C reference to + * arbitrary Lua data in the Shape object. + **/ + int setUserData(lua_State *L); + + /** + * Gets the data set with setUserData. If no + * data is set, nil is returned. + **/ + int getUserData(lua_State *L); + + /** + * Sets the friction of the Shape. + **/ + void setFriction(float friction); + + /** + * Sets the restitution for the Shape. + **/ + void setRestitution(float restitution); + + /** + * Sets the density of the Shape. + **/ + void setDensity(float density); + + /** + * Gets the friction of the Shape. + **/ + float getFriction() const; + + /** + * Gets the restitution of the Shape. + **/ + float getRestitution() const; + + /** + * Gets the density of the Shape. + **/ + float getDensity() const; + + /** + * Checks if a point is inside the Shape. + **/ + bool testPoint(float x, float y) const; + bool testPoint(float x, float y, float r, float px, float py) const; + /** * Gets the type of Shape. Useful for * debug drawing. **/ Type getType() const; + float getRadius() const; int getChildCount() const; - bool testPoint(float x, float y, float r, float px, float py) const; int rayCast(lua_State *L) const; int computeAABB(lua_State *L) const; int computeMass(lua_State *L) const; + void setGroupIndex(int index); + int getGroupIndex() const; + + int setCategory(lua_State *L); + int setMask(lua_State *L); + int getCategory(lua_State *L); + int getMask(lua_State *L); + uint16 getBits(lua_State *L); + int pushBits(lua_State *L, uint16 bits); + + /** + * Gets the bounding box for this Shape. + **/ + int getBoundingBox(lua_State *L) const; + + /** + * Gets the mass data for this Shape. + * This operation may be expensive. + **/ + int getMassData(lua_State *L) const; + + void throwIfFixtureNotValid() const; + void throwIfShapeNotValid() const; + protected: // The Box2D shape. b2Shape *shape; bool own; -}; + + Shape::Type shapeType; + + Body *body; + b2Fixture *fixture; + + // Reference to arbitrary data. + Reference* ref = nullptr; + +}; // Shape } // box2d } // physics diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index 8e37940c7..b90c4a3c7 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -20,7 +20,6 @@ #include "World.h" -#include "Fixture.h" #include "Shape.h" #include "Contact.h" #include "Physics.h" @@ -28,6 +27,7 @@ // Needed for World::getJoints. It should be moved to wrapper code... #include "wrap_Joint.h" +#include "wrap_Shape.h" namespace love { @@ -58,22 +58,22 @@ void World::ContactCallback::process(b2Contact *contact, const b2ContactImpulse { ref->push(L); - // Push first fixture. + // Push first shape. { - Fixture *a = (Fixture *)(contact->GetFixtureA()->GetUserData().pointer); + Shape *a = (Shape *)(contact->GetFixtureA()->GetUserData().pointer); if (a != nullptr) - luax_pushtype(L, a); + luax_pushshape(L, a); else - throw love::Exception("A fixture has escaped Memoizer!"); + throw love::Exception("A Shape has escaped Memoizer!"); } - // Push second fixture. + // Push second shape. { - Fixture *b = (Fixture *)(contact->GetFixtureB()->GetUserData().pointer); + Shape *b = (Shape *)(contact->GetFixtureB()->GetUserData().pointer); if (b != nullptr) - luax_pushtype(L, b); + luax_pushshape(L, b); else - throw love::Exception("A fixture has escaped Memoizer!"); + throw love::Exception("A Shape has escaped Memoizer!"); } Contact *cobj = (Contact *)world->findObject(contact); @@ -112,7 +112,7 @@ World::ContactFilter::~ContactFilter() delete ref; } -bool World::ContactFilter::process(Fixture *a, Fixture *b) +bool World::ContactFilter::process(Shape *a, Shape *b) { // Handle masks, reimplemented from the manual int filterA[3], filterB[3]; @@ -133,8 +133,8 @@ bool World::ContactFilter::process(Fixture *a, Fixture *b) if (ref != nullptr && L != nullptr) { ref->push(L); - luax_pushtype(L, a); - luax_pushtype(L, b); + luax_pushshape(L, a); + luax_pushshape(L, b); lua_call(L, 2, 1); return luax_toboolean(L, -1); } @@ -159,10 +159,10 @@ bool World::QueryCallback::ReportFixture(b2Fixture *fixture) if (L != nullptr) { lua_pushvalue(L, funcidx); - Fixture *f = (Fixture *)(fixture->GetUserData().pointer); + Shape *f = (Shape *)(fixture->GetUserData().pointer); if (!f) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, f); + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, f); for (int i = 1; i <= userargs; i++) lua_pushvalue(L, funcidx + i); lua_call(L, 1 + userargs, 1); @@ -191,10 +191,10 @@ bool World::CollectCallback::ReportFixture(b2Fixture *f) if (categoryMask != 0xFFFF && (categoryMask & f->GetFilterData().categoryBits) == 0) return true; - Fixture *fixture = (Fixture *)(f->GetUserData().pointer); - if (!fixture) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, fixture); + Shape *shape = (Shape *)(f->GetUserData().pointer); + if (!shape) + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, shape); lua_rawseti(L, -2, i); i++; return true; @@ -218,10 +218,10 @@ float World::RayCastCallback::ReportFixture(b2Fixture *fixture, const b2Vec2 &po if (L != nullptr) { lua_pushvalue(L, funcidx); - Fixture *f = (Fixture *)(fixture->GetUserData().pointer); + Shape *f = (Shape *)(fixture->GetUserData().pointer); if (!f) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, f); + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, f); b2Vec2 scaledPoint = Physics::scaleUp(point); lua_pushnumber(L, scaledPoint.x); lua_pushnumber(L, scaledPoint.y); @@ -267,9 +267,9 @@ float World::RayCastOneCallback::ReportFixture(b2Fixture *fixture, const b2Vec2 void World::SayGoodbye(b2Fixture *fixture) { - Fixture *f = (Fixture *)(fixture->GetUserData().pointer); + Shape *s = (Shape *)(fixture->GetUserData().pointer); // Hint implicit destruction with true. - if (f) f->destroy(true); + if (s) s->destroy(true); } void World::SayGoodbye(b2Joint *joint) @@ -336,11 +336,11 @@ void World::update(float dt, int velocityIterations, int positionIterations) // Release for reference in vector. b->release(); } - for (Fixture *f : destructFixtures) + for (Shape *s : destructShapes) { - if (f->isValid()) f->destroy(); + if (s->isValid()) s->destroy(); // Release for reference in vector. - f->release(); + s->release(); } for (Joint *j : destructJoints) { @@ -349,7 +349,7 @@ void World::update(float dt, int velocityIterations, int positionIterations) j->release(); } destructBodies.clear(); - destructFixtures.clear(); + destructShapes.clear(); destructJoints.clear(); if (destructWorld) @@ -384,11 +384,11 @@ void World::PostSolve(b2Contact *contact, const b2ContactImpulse *impulse) bool World::ShouldCollide(b2Fixture *fixtureA, b2Fixture *fixtureB) { - // Fixtures should be memoized, if we created them - Fixture *a = (Fixture *)(fixtureA->GetUserData().pointer); - Fixture *b = (Fixture *)(fixtureB->GetUserData().pointer); + // Shapes should be memoized, if we created them + Shape *a = (Shape *)(fixtureA->GetUserData().pointer); + Shape *b = (Shape *)(fixtureB->GetUserData().pointer); if (!a || !b) - throw love::Exception("A fixture has escaped Memoizer!"); + throw love::Exception("A Shape has escaped Memoizer!"); return filter.process(a, b); } @@ -597,7 +597,7 @@ b2Body *World::getGroundBody() const return groundBody; } -int World::queryFixturesInArea(lua_State *L) +int World::queryShapesInArea(lua_State *L) { b2AABB box; float lx = (float)luaL_checknumber(L, 1); @@ -612,7 +612,7 @@ int World::queryFixturesInArea(lua_State *L) return 0; } -int World::getFixturesInArea(lua_State *L) +int World::getShapesInArea(lua_State *L) { float lx = (float)luaL_checknumber(L, 1); float ly = (float)luaL_checknumber(L, 2); @@ -654,10 +654,10 @@ int World::rayCastAny(lua_State *L) world->RayCast(&raycast, v1, v2); if (raycast.hitFixture) { - Fixture *f = (Fixture *)(raycast.hitFixture->GetUserData().pointer); + Shape *f = (Shape *)(raycast.hitFixture->GetUserData().pointer); if (f == nullptr) - return luaL_error(L, "A fixture has escaped Memoizer!"); - luax_pushtype(L, f); + return luaL_error(L, "A Shape has escaped Memoizer!"); + luax_pushshape(L, f); b2Vec2 hitPoint = Physics::scaleUp(raycast.hitPoint); lua_pushnumber(L, hitPoint.x); @@ -683,10 +683,10 @@ int World::rayCastClosest(lua_State *L) world->RayCast(&raycast, v1, v2); if (raycast.hitFixture) { - Fixture *f = (Fixture *)(raycast.hitFixture->GetUserData().pointer); + Shape *f = (Shape *)(raycast.hitFixture->GetUserData().pointer); if (f == nullptr) - return luaL_error(L, "A fixture has escaped Memoizer!"); - luax_pushtype(L, f); + return luaL_error(L, "A Shape has escaped Memoizer!"); + luax_pushshape(L, f); b2Vec2 hitPoint = Physics::scaleUp(raycast.hitPoint); lua_pushnumber(L, hitPoint.x); diff --git a/src/modules/physics/box2d/World.h b/src/modules/physics/box2d/World.h index 94d2a1e09..2c7eb78b7 100644 --- a/src/modules/physics/box2d/World.h +++ b/src/modules/physics/box2d/World.h @@ -42,7 +42,6 @@ namespace box2d class Contact; class Body; -class Fixture; class Joint; /** @@ -65,7 +64,7 @@ public: friend class DistanceJoint; friend class MouseJoint; friend class Body; - friend class Fixture; + friend class Shape; static love::Type type; @@ -87,7 +86,7 @@ public: lua_State *L; ContactFilter(); ~ContactFilter(); - bool process(Fixture *a, Fixture *b); + bool process(Shape *a, Shape *b); }; class QueryCallback : public b2QueryCallback @@ -302,14 +301,14 @@ public: b2Body *getGroundBody() const; /** - * Calls a callback on all fixtures that overlap a given bounding box. + * Calls a callback on all Shapes that overlap a given bounding box. **/ - int queryFixturesInArea(lua_State *L); + int queryShapesInArea(lua_State *L); /** - * Gets all fixtures that overlap a given bounding box. + * Gets all Shapes that overlap a given bounding box. **/ - int getFixturesInArea(lua_State *L); + int getShapesInArea(lua_State *L); /** * Raycasts the World for all Fixtures in the path of the ray. @@ -338,7 +337,7 @@ private: // The list of to be destructed bodies. std::vector destructBodies; - std::vector destructFixtures; + std::vector destructShapes; std::vector destructJoints; bool destructWorld; diff --git a/src/modules/physics/box2d/wrap_Body.cpp b/src/modules/physics/box2d/wrap_Body.cpp index 6ed39ef2e..f0d4dd865 100644 --- a/src/modules/physics/box2d/wrap_Body.cpp +++ b/src/modules/physics/box2d/wrap_Body.cpp @@ -20,6 +20,7 @@ #include "wrap_Body.h" #include "wrap_Physics.h" +#include "wrap_Shape.h" namespace love { @@ -599,26 +600,32 @@ int w_Body_getWorld(lua_State *L) return 1; } -int w_Body_getFixture(lua_State *L) +int w_Body_getShape(lua_State *L) { Body *t = luax_checkbody(L, 1); - Fixture *f = t->getFixture(); - if (f) - luax_pushtype(L, f); + Shape *s = t->getShape(); + if (s) + luax_pushshape(L, s); else lua_pushnil(L); return 1; } -int w_Body_getFixtures(lua_State *L) +int w_Body_getShapes(lua_State *L) { Body *t = luax_checkbody(L, 1); lua_remove(L, 1); int n = 0; - luax_catchexcept(L, [&](){ n = t->getFixtures(L); }); + luax_catchexcept(L, [&](){ n = t->getShapes(L); }); return n; } +int w_Body_getFixtures(lua_State *L) +{ + luax_markdeprecated(L, 1, "Body:getFixtures", API_METHOD, DEPRECATED_REPLACED, "Body:getShapes"); + return w_Body_getShapes(L); +} + int w_Body_getJoints(lua_State *L) { Body *t = luax_checkbody(L, 1); @@ -724,8 +731,8 @@ static const luaL_Reg w_Body_functions[] = { "isFixedRotation", w_Body_isFixedRotation }, { "isTouching", w_Body_isTouching }, { "getWorld", w_Body_getWorld }, - { "getFixture", w_Body_getFixture }, - { "getFixtures", w_Body_getFixtures }, + { "getShape", w_Body_getShape }, + { "getShapes", w_Body_getShapes }, { "getJoints", w_Body_getJoints }, { "getContacts", w_Body_getContacts }, { "destroy", w_Body_destroy }, @@ -733,6 +740,9 @@ static const luaL_Reg w_Body_functions[] = { "setUserData", w_Body_setUserData }, { "getUserData", w_Body_getUserData }, + // Deprecated + { "getFixtures", w_Body_getFixtures }, + { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_ChainShape.cpp b/src/modules/physics/box2d/wrap_ChainShape.cpp index 52c94ef70..d0597e778 100644 --- a/src/modules/physics/box2d/wrap_ChainShape.cpp +++ b/src/modules/physics/box2d/wrap_ChainShape.cpp @@ -54,9 +54,10 @@ int w_ChainShape_setPreviousVertex(lua_State *L) int w_ChainShape_getChildEdge(lua_State *L) { + luax_markdeprecated(L, 1, "ChainShape:getChildEdge", API_METHOD, DEPRECATED_NO_REPLACEMENT, nullptr); ChainShape *c = luax_checkchainshape(L, 1); int index = (int) luaL_checkinteger(L, 2) - 1; // Convert from 1-based index - EdgeShape *e = 0; + EdgeShape *e = nullptr; luax_catchexcept(L, [&](){ e = c->getChildEdge(index); }); luax_pushtype(L, e); e->release(); @@ -66,7 +67,8 @@ int w_ChainShape_getChildEdge(lua_State *L) int w_ChainShape_getVertexCount(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - int count = c->getVertexCount(); + int count = 0; + luax_catchexcept(L, [&]() { count = c->getVertexCount(); }); lua_pushinteger(L, count); return 1; } @@ -85,7 +87,8 @@ int w_ChainShape_getPoint(lua_State *L) int w_ChainShape_getNextVertex(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - b2Vec2 v = c->getNextVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = c->getNextVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -94,7 +97,8 @@ int w_ChainShape_getNextVertex(lua_State *L) int w_ChainShape_getPreviousVertex(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - b2Vec2 v = c->getPreviousVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = c->getPreviousVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -103,7 +107,8 @@ int w_ChainShape_getPreviousVertex(lua_State *L) int w_ChainShape_getPoints(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - const b2Vec2 *verts = c->getPoints(); + const b2Vec2 *verts; + luax_catchexcept(L, [&]() { verts = c->getPoints(); }); int count = c->getVertexCount(); if (!lua_checkstack(L, count*2)) return luaL_error(L, "Too many return values"); diff --git a/src/modules/physics/box2d/wrap_CircleShape.cpp b/src/modules/physics/box2d/wrap_CircleShape.cpp index f9ec8394a..99bc524d6 100644 --- a/src/modules/physics/box2d/wrap_CircleShape.cpp +++ b/src/modules/physics/box2d/wrap_CircleShape.cpp @@ -35,7 +35,9 @@ CircleShape *luax_checkcircleshape(lua_State *L, int idx) int w_CircleShape_getRadius(lua_State *L) { CircleShape *c = luax_checkcircleshape(L, 1); - lua_pushnumber(L, c->getRadius()); + float r = 0; + luax_catchexcept(L, [&]() { r = c->getRadius(); }); + lua_pushnumber(L, r); return 1; } @@ -43,7 +45,7 @@ int w_CircleShape_setRadius(lua_State *L) { CircleShape *c = luax_checkcircleshape(L, 1); float r = (float)luaL_checknumber(L, 2); - c->setRadius(r); + luax_catchexcept(L, [&]() { c->setRadius(r); }); return 0; } @@ -51,7 +53,7 @@ int w_CircleShape_getPoint(lua_State *L) { CircleShape *c = luax_checkcircleshape(L, 1); float x, y; - c->getPoint(x, y); + luax_catchexcept(L, [&]() { c->getPoint(x, y); }); lua_pushnumber(L, x); lua_pushnumber(L, y); return 2; diff --git a/src/modules/physics/box2d/wrap_Contact.cpp b/src/modules/physics/box2d/wrap_Contact.cpp index d18d39402..a61c6a72b 100644 --- a/src/modules/physics/box2d/wrap_Contact.cpp +++ b/src/modules/physics/box2d/wrap_Contact.cpp @@ -19,7 +19,7 @@ **/ #include "wrap_Contact.h" -#include "Fixture.h" +#include "wrap_Shape.h" namespace love { @@ -139,18 +139,24 @@ int w_Contact_getChildren(lua_State *L) return 2; } -int w_Contact_getFixtures(lua_State *L) +int w_Contact_getShapes(lua_State *L) { Contact *t = luax_checkcontact(L, 1); - Fixture *a = nullptr; - Fixture *b = nullptr; - luax_catchexcept(L, [&](){ t->getFixtures(a, b); }); + Shape *a = nullptr; + Shape *b = nullptr; + luax_catchexcept(L, [&](){ t->getShapes(a, b); }); - luax_pushtype(L, a); - luax_pushtype(L, b); + luax_pushshape(L, a); + luax_pushshape(L, b); return 2; } +int w_Contact_getFixtures(lua_State *L) +{ + luax_markdeprecated(L, 1, "Contact:getFixtures", API_METHOD, DEPRECATED_REPLACED, "Contact:getShapes"); + return w_Contact_getShapes(L); +} + int w_Contact_isDestroyed(lua_State *L) { Contact *c = luax_checktype(L, 1); @@ -174,8 +180,12 @@ static const luaL_Reg w_Contact_functions[] = { "setTangentSpeed", w_Contact_setTangentSpeed }, { "getTangentSpeed", w_Contact_getTangentSpeed }, { "getChildren", w_Contact_getChildren }, - { "getFixtures", w_Contact_getFixtures }, + { "getShapes", w_Contact_getShapes }, { "isDestroyed", w_Contact_isDestroyed }, + + // Deprecated + { "getFixtures", w_Contact_getFixtures }, + { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_EdgeShape.cpp b/src/modules/physics/box2d/wrap_EdgeShape.cpp index fbc0c0574..a97b115a5 100644 --- a/src/modules/physics/box2d/wrap_EdgeShape.cpp +++ b/src/modules/physics/box2d/wrap_EdgeShape.cpp @@ -37,7 +37,7 @@ int w_EdgeShape_setNextVertex(lua_State *L) EdgeShape *t = luax_checkedgeshape(L, 1); float x = (float)luaL_checknumber(L, 2); float y = (float)luaL_checknumber(L, 3); - t->setNextVertex(x, y); + luax_catchexcept(L, [&]() { t->setNextVertex(x, y); }); return 0; } @@ -46,14 +46,15 @@ int w_EdgeShape_setPreviousVertex(lua_State *L) EdgeShape *t = luax_checkedgeshape(L, 1); float x = (float)luaL_checknumber(L, 2); float y = (float)luaL_checknumber(L, 3); - t->setPreviousVertex(x, y); + luax_catchexcept(L, [&]() { t->setPreviousVertex(x, y); }); return 0; } int w_EdgeShape_getNextVertex(lua_State *L) { EdgeShape *t = luax_checkedgeshape(L, 1); - b2Vec2 v = t->getNextVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = t->getNextVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -62,7 +63,8 @@ int w_EdgeShape_getNextVertex(lua_State *L) int w_EdgeShape_getPreviousVertex(lua_State *L) { EdgeShape *t = luax_checkedgeshape(L, 1); - b2Vec2 v = t->getPreviousVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = t->getPreviousVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -72,7 +74,9 @@ int w_EdgeShape_getPoints(lua_State *L) { EdgeShape *t = luax_checkedgeshape(L, 1); lua_remove(L, 1); - return t->getPoints(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getPoints(L); }); + return ret; } static const luaL_Reg w_EdgeShape_functions[] = diff --git a/src/modules/physics/box2d/wrap_Fixture.cpp b/src/modules/physics/box2d/wrap_Fixture.cpp deleted file mode 100644 index 4056874c9..000000000 --- a/src/modules/physics/box2d/wrap_Fixture.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "wrap_Fixture.h" -#include "common/StringMap.h" - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -Fixture *luax_checkfixture(lua_State *L, int idx) -{ - Fixture *f = luax_checktype(L, idx); - if (!f->isValid()) - luaL_error(L, "Attempt to use destroyed fixture."); - return f; -} - -int w_Fixture_getType(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - const char *type = ""; - Shape::getConstant(t->getType(), type); - lua_pushstring(L, type); - return 1; -} - -int w_Fixture_setFriction(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - t->setFriction(arg1); - return 0; -} - -int w_Fixture_setRestitution(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - t->setRestitution(arg1); - return 0; -} - -int w_Fixture_setDensity(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - luax_catchexcept(L, [&](){ t->setDensity(arg1); }); - return 0; -} - -int w_Fixture_setSensor(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - bool arg1 = luax_checkboolean(L, 2); - t->setSensor(arg1); - return 0; -} - -int w_Fixture_getFriction(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_pushnumber(L, t->getFriction()); - return 1; -} - -int w_Fixture_getRestitution(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_pushnumber(L, t->getRestitution()); - return 1; -} - -int w_Fixture_getDensity(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_pushnumber(L, t->getDensity()); - return 1; -} - -int w_Fixture_isSensor(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - luax_pushboolean(L, t->isSensor()); - return 1; -} - -int w_Fixture_getBody(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - Body *body = t->getBody(); - if (body == 0) - return 0; - luax_pushtype(L, body); - return 1; -} - -int w_Fixture_getShape(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - Shape * shape = t->getShape(); - if (shape == nullptr) - return 0; - switch (shape->getType()) - { - case Shape::SHAPE_EDGE: - luax_pushtype(L, dynamic_cast(shape)); - break; - case Shape::SHAPE_CHAIN: - luax_pushtype(L, dynamic_cast(shape)); - break; - case Shape::SHAPE_CIRCLE: - luax_pushtype(L, dynamic_cast(shape)); - break; - case Shape::SHAPE_POLYGON: - luax_pushtype(L, dynamic_cast(shape)); - break; - default: - luax_pushtype(L, shape); - break; - } - return 1; -} - -int w_Fixture_testPoint(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float x = (float)luaL_checknumber(L, 2); - float y = (float)luaL_checknumber(L, 3); - luax_pushboolean(L, t->testPoint(x, y)); - return 1; -} - -int w_Fixture_rayCast(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - int ret = 0; - luax_catchexcept(L, [&](){ ret = t->rayCast(L); }); - return ret; -} - -int w_Fixture_setFilterData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int v[3]; - v[0] = (int) luaL_checkinteger(L, 2); - v[1] = (int) luaL_checkinteger(L, 3); - v[2] = (int) luaL_checkinteger(L, 4); - t->setFilterData(v); - return 0; -} - -int w_Fixture_getFilterData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int v[3]; - t->getFilterData(v); - lua_pushinteger(L, v[0]); - lua_pushinteger(L, v[1]); - lua_pushinteger(L, v[2]); - return 3; -} - -int w_Fixture_setCategory(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->setCategory(L); -} - -int w_Fixture_getCategory(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getCategory(L); -} - -int w_Fixture_setMask(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->setMask(L); -} - -int w_Fixture_getMask(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getMask(L); -} - -int w_Fixture_setUserData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->setUserData(L); -} - -int w_Fixture_getUserData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getUserData(L); -} - -int w_Fixture_getBoundingBox(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getBoundingBox(L); -} - -int w_Fixture_getMassData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getMassData(L); -} - -int w_Fixture_getGroupIndex(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int i = t->getGroupIndex(); - lua_pushinteger(L, i); - return 1; -} - -int w_Fixture_setGroupIndex(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int i = (int) luaL_checkinteger(L, 2); - t->setGroupIndex(i); - return 0; -} - -int w_Fixture_destroy(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - luax_catchexcept(L, [&](){ t->destroy(); }); - return 0; -} - -int w_Fixture_isDestroyed(lua_State *L) -{ - Fixture *f = luax_checktype(L, 1); - luax_pushboolean(L, !f->isValid()); - return 1; -} - -static const luaL_Reg w_Fixture_functions[] = -{ - { "getType", w_Fixture_getType }, - { "setFriction", w_Fixture_setFriction }, - { "setRestitution", w_Fixture_setRestitution }, - { "setDensity", w_Fixture_setDensity }, - { "setSensor", w_Fixture_setSensor }, - { "getFriction", w_Fixture_getFriction }, - { "getRestitution", w_Fixture_getRestitution }, - { "getDensity", w_Fixture_getDensity }, - { "getBody", w_Fixture_getBody }, - { "getShape", w_Fixture_getShape }, - { "isSensor", w_Fixture_isSensor }, - { "testPoint", w_Fixture_testPoint }, - { "rayCast", w_Fixture_rayCast }, - { "setFilterData", w_Fixture_setFilterData }, - { "getFilterData", w_Fixture_getFilterData }, - { "setCategory", w_Fixture_setCategory }, - { "getCategory", w_Fixture_getCategory }, - { "setMask", w_Fixture_setMask }, - { "getMask", w_Fixture_getMask }, - { "setUserData", w_Fixture_setUserData }, - { "getUserData", w_Fixture_getUserData }, - { "getBoundingBox", w_Fixture_getBoundingBox }, - { "getMassData", w_Fixture_getMassData }, - { "getGroupIndex", w_Fixture_getGroupIndex }, - { "setGroupIndex", w_Fixture_setGroupIndex }, - { "destroy", w_Fixture_destroy }, - { "isDestroyed", w_Fixture_isDestroyed }, - { 0, 0 } -}; - -extern "C" int luaopen_fixture(lua_State *L) -{ - return luax_register_type(L, &Fixture::type, w_Fixture_functions, nullptr); -} - -} // box2d -} // physics -} // love - diff --git a/src/modules/physics/box2d/wrap_Fixture.h b/src/modules/physics/box2d/wrap_Fixture.h deleted file mode 100644 index 0d31d6fa0..000000000 --- a/src/modules/physics/box2d/wrap_Fixture.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#ifndef LOVE_PHYSICS_BOX2D_WRAP_FIXTURE_H -#define LOVE_PHYSICS_BOX2D_WRAP_FIXTURE_H - -// LOVE -#include "common/runtime.h" -#include "Fixture.h" -#include "wrap_Physics.h" - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -Fixture *luax_checkfixture(lua_State *L, int idx); -extern "C" int luaopen_fixture(lua_State *L); - -} // box2d -} // physics -} // love - -#endif // LOVE_PHYSICS_BOX2D_WRAP_FIXTURE_H diff --git a/src/modules/physics/box2d/wrap_Physics.cpp b/src/modules/physics/box2d/wrap_Physics.cpp index 7b755f92e..917cdf812 100644 --- a/src/modules/physics/box2d/wrap_Physics.cpp +++ b/src/modules/physics/box2d/wrap_Physics.cpp @@ -23,7 +23,6 @@ #include "wrap_World.h" #include "wrap_Contact.h" #include "wrap_Body.h" -#include "wrap_Fixture.h" #include "wrap_Shape.h" #include "wrap_CircleShape.h" #include "wrap_PolygonShape.h" @@ -256,36 +255,56 @@ int w_newChainBody(lua_State *L) int w_newFixture(lua_State *L) { + luax_markdeprecated(L, 1, "love.physics.newFixture", API_FUNCTION, DEPRECATED_REPLACED, "love.physics.newCircle/Rectangle/Polygon/Edge/ChainShape"); + Body *body = luax_checkbody(L, 1); Shape *shape = luax_checkshape(L, 2); float density = (float)luaL_optnumber(L, 3, 1.0f); - Fixture *fixture; - luax_catchexcept(L, [&](){ fixture = instance()->newFixture(body, shape, density); }); - luax_pushtype(L, fixture); - fixture->release(); + + Shape *newShape; + luax_catchexcept(L, [&]() { + newShape = instance()->newAttachedShape(body, shape, density); + newShape->setDensity(density); + body->resetMassData(); + }); + + luax_pushshape(L, newShape); + newShape->release(); return 1; } +static Body *luax_optbodyforshape(lua_State *L, int idx, const char *name) +{ + if (luax_istype(L, idx, Body::type)) + return luax_checkbody(L, idx); + + luax_markdeprecated(L, 1, name, API_FUNCTION_VARIANT, DEPRECATED_REPLACED, "variant with Body parameter"); + return nullptr; +} + int w_newCircleShape(lua_State *L) { - int top = lua_gettop(L); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newCircleShape"); + int bodyidx = body ? 1 : 0; + + int top = lua_gettop(L) - bodyidx; if (top == 1) { - float radius = (float)luaL_checknumber(L, 1); + float radius = (float)luaL_checknumber(L, bodyidx + 1); CircleShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(0, 0, radius); }); + luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(body, 0, 0, radius); }); luax_pushtype(L, shape); shape->release(); return 1; } else if (top == 3) { - float x = (float)luaL_checknumber(L, 1); - float y = (float)luaL_checknumber(L, 2); - float radius = (float)luaL_checknumber(L, 3); + float x = (float)luaL_checknumber(L, bodyidx + 1); + float y = (float)luaL_checknumber(L, bodyidx + 2); + float radius = (float)luaL_checknumber(L, bodyidx + 3); CircleShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(x, y, radius); }); + luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(body, x, y, radius); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -296,27 +315,30 @@ int w_newCircleShape(lua_State *L) int w_newRectangleShape(lua_State *L) { - int top = lua_gettop(L); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newRectangleShape"); + int bodyidx = body ? 1 : 0; + + int top = lua_gettop(L) - bodyidx; if (top == 2) { - float w = (float)luaL_checknumber(L, 1); - float h = (float)luaL_checknumber(L, 2); + float w = (float)luaL_checknumber(L, bodyidx + 1); + float h = (float)luaL_checknumber(L, bodyidx + 2); PolygonShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(0, 0, w, h, 0); }); + luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(body, 0, 0, w, h, 0); }); luax_pushtype(L, shape); shape->release(); return 1; } else if (top == 4 || top == 5) { - float x = (float)luaL_checknumber(L, 1); - float y = (float)luaL_checknumber(L, 2); - float w = (float)luaL_checknumber(L, 3); - float h = (float)luaL_checknumber(L, 4); - float angle = (float)luaL_optnumber(L, 5, 0); + float x = (float)luaL_checknumber(L, bodyidx + 1); + float y = (float)luaL_checknumber(L, bodyidx + 2); + float w = (float)luaL_checknumber(L, bodyidx + 3); + float h = (float)luaL_checknumber(L, bodyidx + 4); + float angle = (float)luaL_optnumber(L, bodyidx + 5, 0); PolygonShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(x, y, w, h, angle); }); + luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(body, x, y, w, h, angle); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -327,13 +349,16 @@ int w_newRectangleShape(lua_State *L) int w_newEdgeShape(lua_State *L) { - float x1 = (float)luaL_checknumber(L, 1); - float y1 = (float)luaL_checknumber(L, 2); - float x2 = (float)luaL_checknumber(L, 3); - float y2 = (float)luaL_checknumber(L, 4); - bool oneSided = luax_optboolean(L, 5, false); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newEdgeShape"); + int bodyidx = body ? 1 : 0; + + float x1 = (float)luaL_checknumber(L, bodyidx + 1); + float y1 = (float)luaL_checknumber(L, bodyidx + 2); + float x2 = (float)luaL_checknumber(L, bodyidx + 3); + float y2 = (float)luaL_checknumber(L, bodyidx + 4); + bool oneSided = luax_optboolean(L, bodyidx + 5, false); EdgeShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newEdgeShape(x1, y1, x2, y2, oneSided); }); + luax_catchexcept(L, [&](){ shape = instance()->newEdgeShape(body, x1, y1, x2, y2, oneSided); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -341,12 +366,15 @@ int w_newEdgeShape(lua_State *L) int w_newPolygonShape(lua_State *L) { - int argc = lua_gettop(L); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newPolygonShape"); + int bodyidx = body ? 1 : 0; - bool istable = lua_istable(L, 1); + int argc = lua_gettop(L) - bodyidx; + + bool istable = lua_istable(L, bodyidx + 1); if (istable) - argc = (int)luax_objlen(L, 1); + argc = (int)luax_objlen(L, bodyidx + 1); if (argc % 2 != 0) return luaL_error(L, "Number of vertex components must be a multiple of two."); @@ -358,8 +386,8 @@ int w_newPolygonShape(lua_State *L) { for (int i = 0; i < vcount; i++) { - lua_rawgeti(L, 1, 1 + i * 2); - lua_rawgeti(L, 1, 2 + i * 2); + lua_rawgeti(L, bodyidx + 1, 1 + i * 2); + lua_rawgeti(L, bodyidx + 1, 2 + i * 2); float x = (float)luaL_checknumber(L, -2); float y = (float)luaL_checknumber(L, -1); coords.emplace_back(x, y); @@ -370,14 +398,14 @@ int w_newPolygonShape(lua_State *L) { for (int i = 0; i < vcount; i++) { - float x = (float)luaL_checknumber(L, 1 + i * 2); - float y = (float)luaL_checknumber(L, 2 + i * 2); + float x = (float)luaL_checknumber(L, bodyidx + 1 + i * 2); + float y = (float)luaL_checknumber(L, bodyidx + 2 + i * 2); coords.emplace_back(x, y); } } PolygonShape *shape = nullptr; - luax_catchexcept(L, [&](){ shape = instance()->newPolygonShape(coords.data(), (int)coords.size()); }); + luax_catchexcept(L, [&](){ shape = instance()->newPolygonShape(body, coords.data(), (int)coords.size()); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -385,26 +413,29 @@ int w_newPolygonShape(lua_State *L) int w_newChainShape(lua_State *L) { - int argc = lua_gettop(L) - 1; // first argument is looping + Body *body = luax_optbodyforshape(L, 1, "love.physics.newChainShape"); + int bodyidx = body ? 1 : 0; - bool istable = lua_istable(L, 2); + int argc = lua_gettop(L) - 1 - bodyidx; // first argument is looping + + bool istable = lua_istable(L, bodyidx + 2); if (istable) - argc = (int)luax_objlen(L, 2); + argc = (int)luax_objlen(L, bodyidx + 2); if (argc == 0 || argc % 2 != 0) return luaL_error(L, "Number of vertex components must be a multiple of two."); int vcount = argc / 2; - bool loop = luax_checkboolean(L, 1); + bool loop = luax_checkboolean(L, bodyidx + 1); std::vector coords; if (istable) { for (int i = 0; i < vcount; i++) { - lua_rawgeti(L, 2, 1 + i * 2); - lua_rawgeti(L, 2, 2 + i * 2); + lua_rawgeti(L, bodyidx + 2, 1 + i * 2); + lua_rawgeti(L, bodyidx + 2, 2 + i * 2); float x = (float)lua_tonumber(L, -2); float y = (float)lua_tonumber(L, -1); coords.emplace_back(x, y); @@ -415,14 +446,14 @@ int w_newChainShape(lua_State *L) { for (int i = 0; i < vcount; i++) { - float x = (float)luaL_checknumber(L, 2 + i * 2); - float y = (float)luaL_checknumber(L, 3 + i * 2); + float x = (float)luaL_checknumber(L, bodyidx + 2 + i * 2); + float y = (float)luaL_checknumber(L, bodyidx + 3 + i * 2); coords.emplace_back(x, y); } } ChainShape *shape = nullptr; - luax_catchexcept(L, [&]() { shape = instance()->newChainShape(loop, coords.data(), coords.size()); }); + luax_catchexcept(L, [&]() { shape = instance()->newChainShape(body, loop, coords.data(), coords.size()); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -824,7 +855,6 @@ static const luaL_Reg functions[] = { "newPolygonBody", w_newPolygonBody }, { "newEdgeBody", w_newEdgeBody }, { "newChainBody", w_newChainBody }, - { "newFixture", w_newFixture }, { "newCircleShape", w_newCircleShape }, { "newRectangleShape", w_newRectangleShape }, { "newPolygonShape", w_newPolygonShape }, @@ -848,6 +878,10 @@ static const luaL_Reg functions[] = { "computeLinearFrequency", w_computeLinearFrequency }, { "computeAngularStiffness", w_computeAngularStiffness }, { "computeAngularFrequency", w_computeAngularFrequency }, + + // Deprecated + { "newFixture", w_newFixture }, + { 0, 0 }, }; @@ -856,7 +890,6 @@ static const lua_CFunction types[] = luaopen_world, luaopen_contact, luaopen_body, - luaopen_fixture, luaopen_shape, luaopen_circleshape, luaopen_polygonshape, diff --git a/src/modules/physics/box2d/wrap_PolygonShape.cpp b/src/modules/physics/box2d/wrap_PolygonShape.cpp index 522b1bf9f..e558f000e 100644 --- a/src/modules/physics/box2d/wrap_PolygonShape.cpp +++ b/src/modules/physics/box2d/wrap_PolygonShape.cpp @@ -36,13 +36,17 @@ int w_PolygonShape_getPoints(lua_State *L) { PolygonShape *t = luax_checkpolygonshape(L, 1); lua_remove(L, 1); - return t->getPoints(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getPoints(L); }); + return ret; } int w_PolygonShape_validate(lua_State *L) { PolygonShape *t = luax_checkpolygonshape(L, 1); - luax_pushboolean(L, t->validate()); + bool valid = false; + luax_catchexcept(L, [&]() { valid = t->validate(); }); + luax_pushboolean(L, valid); return 1; } diff --git a/src/modules/physics/box2d/wrap_Shape.cpp b/src/modules/physics/box2d/wrap_Shape.cpp index 497f5d95f..7b32cac13 100644 --- a/src/modules/physics/box2d/wrap_Shape.cpp +++ b/src/modules/physics/box2d/wrap_Shape.cpp @@ -33,6 +33,35 @@ Shape *luax_checkshape(lua_State *L, int idx) return luax_checktype(L, idx); } +void luax_pushshape(lua_State *L, Shape *shape) +{ + if (shape != nullptr) + { + switch (shape->getType()) + { + case Shape::SHAPE_CIRCLE: + luax_pushtype(L, (CircleShape *) shape); + break; + case Shape::SHAPE_POLYGON: + luax_pushtype(L, (PolygonShape *) shape); + break; + case Shape::SHAPE_EDGE: + luax_pushtype(L, (EdgeShape *) shape); + break; + case Shape::SHAPE_CHAIN: + luax_pushtype(L, (ChainShape *) shape); + break; + default: + luax_pushtype(L, shape); + break; + } + } + else + { + lua_pushnil(L); + } +} + int w_Shape_getType(lua_State *L) { Shape *t = luax_checkshape(L, 1); @@ -45,7 +74,8 @@ int w_Shape_getType(lua_State *L) int w_Shape_getRadius(lua_State *L) { Shape *t = luax_checkshape(L, 1); - float radius = t->getRadius(); + float radius = 0; + luax_catchexcept(L, [&]() { radius = t->getRadius(); }); lua_pushnumber(L, radius); return 1; } @@ -53,20 +83,115 @@ int w_Shape_getRadius(lua_State *L) int w_Shape_getChildCount(lua_State *L) { Shape *t = luax_checkshape(L, 1); - int childCount = t->getChildCount(); + int childCount = 0; + luax_catchexcept(L, [&]() { childCount = t->getChildCount(); }); lua_pushinteger(L, childCount); return 1; } +int w_Shape_setFriction(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float arg1 = (float)luaL_checknumber(L, 2); + luax_catchexcept(L, [&]() { t->setFriction(arg1); }); + return 0; +} + +int w_Shape_setRestitution(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float arg1 = (float)luaL_checknumber(L, 2); + luax_catchexcept(L, [&]() { t->setRestitution(arg1); }); + return 0; +} + +int w_Shape_setDensity(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float arg1 = (float)luaL_checknumber(L, 2); + luax_catchexcept(L, [&](){ t->setDensity(arg1); }); + return 0; +} + +int w_Shape_setSensor(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + bool arg1 = luax_checkboolean(L, 2); + luax_catchexcept(L, [&]() { t->setSensor(arg1); }); + return 0; +} + +int w_Shape_getFriction(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float friction = 0; + luax_catchexcept(L, [&]() { friction = t->getFriction(); }); + lua_pushnumber(L, friction); + return 1; +} + +int w_Shape_getRestitution(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float r = 0; + luax_catchexcept(L, [&]() { r = t->getRestitution(); }); + lua_pushnumber(L, r); + return 1; +} + +int w_Shape_getDensity(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float d = 0; + luax_catchexcept(L, [&]() { d = t->getDensity(); }); + lua_pushnumber(L, d); + return 1; +} + +int w_Shape_isSensor(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + bool sensor = false; + luax_catchexcept(L, [&]() { sensor = t->isSensor(); }); + luax_pushboolean(L, sensor); + return 1; +} + +int w_Shape_getBody(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + Body *body = t->getBody(); + if (body == nullptr) + return 0; + luax_pushtype(L, body); + return 1; +} + +int w_Shape_getShape(lua_State *L) +{ + luax_markdeprecated(L, 1, "Fixture:getShape", API_METHOD, DEPRECATED_NO_REPLACEMENT, nullptr); + Shape *t = luax_checkshape(L, 1); + luax_pushshape(L, t); + return 1; +} + int w_Shape_testPoint(lua_State *L) { Shape *t = luax_checkshape(L, 1); float x = (float)luaL_checknumber(L, 2); float y = (float)luaL_checknumber(L, 3); - float r = (float)luaL_checknumber(L, 4); - float px = (float)luaL_checknumber(L, 5); - float py = (float)luaL_checknumber(L, 6); - bool result = t->testPoint(x, y, r, px, py); + bool result = false; + if (!lua_isnoneornil(L, 4)) + { + float r = (float)luaL_checknumber(L, 4); + float px = (float)luaL_checknumber(L, 5); + float py = (float)luaL_checknumber(L, 6); + result = luax_catchexcept(L, [&]() { t->testPoint(x, y, r, px, py); }); + } + else + { + result = luax_catchexcept(L, [&]() { t->testPoint(x, y); }); + } lua_pushboolean(L, result); return 1; } @@ -84,14 +209,143 @@ int w_Shape_computeAABB(lua_State *L) { Shape *t = luax_checkshape(L, 1); lua_remove(L, 1); - return t->computeAABB(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->computeAABB(L); }); + return ret; } int w_Shape_computeMass(lua_State *L) { Shape *t = luax_checkshape(L, 1); lua_remove(L, 1); - return t->computeMass(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->computeMass(L); }); + return ret; +} + +int w_Shape_setFilterData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int v[3]; + v[0] = (int) luaL_checkinteger(L, 2); + v[1] = (int) luaL_checkinteger(L, 3); + v[2] = (int) luaL_checkinteger(L, 4); + luax_catchexcept(L, [&]() { t->setFilterData(v); }); + return 0; +} + +int w_Shape_getFilterData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int v[3]; + luax_catchexcept(L, [&]() { t->getFilterData(v); }); + lua_pushinteger(L, v[0]); + lua_pushinteger(L, v[1]); + lua_pushinteger(L, v[2]); + return 3; +} + +int w_Shape_setCategory(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->setCategory(L); }); + return ret; +} + +int w_Shape_getCategory(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getCategory(L); }); + return ret; +} + +int w_Shape_setMask(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->setMask(L); }); + return ret; +} + +int w_Shape_getMask(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getMask(L); }); + return ret; +} + +int w_Shape_setUserData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->setUserData(L); }); + return ret; +} + +int w_Shape_getUserData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getUserData(L); }); + return ret; +} + +int w_Shape_getBoundingBox(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getBoundingBox(L); }); + return ret; +} + +int w_Shape_getMassData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getMassData(L); }); + return ret; +} + +int w_Shape_getGroupIndex(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int i = 0; + luax_catchexcept(L, [&]() { i = t->getGroupIndex(); }); + lua_pushinteger(L, i); + return 1; +} + +int w_Shape_setGroupIndex(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int i = (int) luaL_checkinteger(L, 2); + luax_catchexcept(L, [&]() { t->setGroupIndex(i); }); + return 0; +} + +int w_Shape_destroy(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + luax_catchexcept(L, [&](){ t->destroy(); }); + return 0; +} + +int w_Shape_isDestroyed(lua_State *L) +{ + Shape *f = luax_checktype(L, 1); + luax_pushboolean(L, !f->isValid()); + return 1; } const luaL_Reg w_Shape_functions[] = @@ -99,10 +353,33 @@ const luaL_Reg w_Shape_functions[] = { "getType", w_Shape_getType }, { "getRadius", w_Shape_getRadius }, { "getChildCount", w_Shape_getChildCount }, + { "setFriction", w_Shape_setFriction }, + { "setRestitution", w_Shape_setRestitution }, + { "setDensity", w_Shape_setDensity }, + { "setSensor", w_Shape_setSensor }, + { "getFriction", w_Shape_getFriction }, + { "getRestitution", w_Shape_getRestitution }, + { "getDensity", w_Shape_getDensity }, + { "getBody", w_Shape_getBody }, + { "isSensor", w_Shape_isSensor }, { "testPoint", w_Shape_testPoint }, { "rayCast", w_Shape_rayCast }, { "computeAABB", w_Shape_computeAABB }, { "computeMass", w_Shape_computeMass }, + { "setFilterData", w_Shape_setFilterData }, + { "getFilterData", w_Shape_getFilterData }, + { "setCategory", w_Shape_setCategory }, + { "getCategory", w_Shape_getCategory }, + { "setMask", w_Shape_setMask }, + { "getMask", w_Shape_getMask }, + { "setUserData", w_Shape_setUserData }, + { "getUserData", w_Shape_getUserData }, + { "getBoundingBox", w_Shape_getBoundingBox }, + { "getMassData", w_Shape_getMassData }, + { "getGroupIndex", w_Shape_getGroupIndex }, + { "setGroupIndex", w_Shape_setGroupIndex }, + { "destroy", w_Shape_destroy }, + { "isDestroyed", w_Shape_isDestroyed }, { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_Shape.h b/src/modules/physics/box2d/wrap_Shape.h index e5cd01cbe..960945c1c 100644 --- a/src/modules/physics/box2d/wrap_Shape.h +++ b/src/modules/physics/box2d/wrap_Shape.h @@ -34,6 +34,7 @@ namespace box2d { Shape *luax_checkshape(lua_State *L, int idx); +void luax_pushshape(lua_State *L, Shape *shape); extern "C" int luaopen_shape(lua_State *L); extern const luaL_Reg w_Shape_functions[]; diff --git a/src/modules/physics/box2d/wrap_World.cpp b/src/modules/physics/box2d/wrap_World.cpp index b80b9ae65..1659374df 100644 --- a/src/modules/physics/box2d/wrap_World.cpp +++ b/src/modules/physics/box2d/wrap_World.cpp @@ -178,25 +178,25 @@ int w_World_getContacts(lua_State *L) return ret; } -int w_World_queryFixturesInArea(lua_State *L) +int w_World_queryShapesInArea(lua_State *L) { World *t = luax_checkworld(L, 1); lua_remove(L, 1); - return t->queryFixturesInArea(L); + return t->queryShapesInArea(L); } int w_World_queryBoundingBox(lua_State *L) { - luax_markdeprecated(L, 1, "World:queryBoundingBox", API_METHOD, DEPRECATED_RENAMED, "World:queryFixturesInArea"); - return w_World_queryFixturesInArea(L); + luax_markdeprecated(L, 1, "World:queryBoundingBox", API_METHOD, DEPRECATED_RENAMED, "World:queryShapesInArea"); + return w_World_queryShapesInArea(L); } -int w_World_getFixturesInArea(lua_State *L) +int w_World_getShapesInArea(lua_State *L) { World *t = luax_checkworld(L, 1); lua_remove(L, 1); int ret = 0; - luax_catchexcept(L, [&](){ ret = t->getFixturesInArea(L); }); + luax_catchexcept(L, [&](){ ret = t->getShapesInArea(L); }); return ret; } @@ -260,8 +260,8 @@ static const luaL_Reg w_World_functions[] = { "getBodies", w_World_getBodies }, { "getJoints", w_World_getJoints }, { "getContacts", w_World_getContacts }, - { "queryFixturesInArea", w_World_queryFixturesInArea }, - { "getFixturesInArea", w_World_getFixturesInArea }, + { "queryShapesInArea", w_World_queryShapesInArea }, + { "getShapesInArea", w_World_getShapesInArea }, { "rayCast", w_World_rayCast }, { "rayCastAny", w_World_rayCastAny }, { "rayCastClosest", w_World_rayCastClosest }, From b8e2b1b6c52496eb99d83039fea00eaaf522fd46 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 7 Oct 2023 15:19:49 -0300 Subject: [PATCH 05/36] Update Xcode project to account for removed files --- .../xcode/liblove.xcodeproj/project.pbxproj | 30 ++++--------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 4aab7711e..605e07e02 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -51,6 +51,9 @@ 217DFC111D9F6D490055D849 /* usocket.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBD51D9F6D490055D849 /* usocket.c */; }; 217DFC121D9F6D490055D849 /* usocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 217DFBD61D9F6D490055D849 /* usocket.h */; }; D923E7D3296B85B9002FF1B3 /* harfbuzz.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = D923E7D2296B85B9002FF1B3 /* harfbuzz.xcframework */; }; + D943E58E2A24D56000D80361 /* PhysfsIo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D943E58C2A24D56000D80361 /* PhysfsIo.cpp */; }; + D943E58F2A24D56000D80361 /* PhysfsIo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D943E58C2A24D56000D80361 /* PhysfsIo.cpp */; }; + D943E5902A24D56000D80361 /* PhysfsIo.h in Headers */ = {isa = PBXBuildFile; fileRef = D943E58D2A24D56000D80361 /* PhysfsIo.h */; }; D9DAB9222961F0EE00C64820 /* HarfbuzzShaper.h in Headers */ = {isa = PBXBuildFile; fileRef = D9DAB9202961F0EE00C64820 /* HarfbuzzShaper.h */; }; D9DAB9232961F0EE00C64820 /* HarfbuzzShaper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9DAB9212961F0EE00C64820 /* HarfbuzzShaper.cpp */; }; D9DAB9242961F0EE00C64820 /* HarfbuzzShaper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9DAB9212961F0EE00C64820 /* HarfbuzzShaper.cpp */; }; @@ -61,9 +64,6 @@ D9DAB92D2961F10000C64820 /* TextShaper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9DAB9282961F10000C64820 /* TextShaper.cpp */; }; D9DAB92E2961F10000C64820 /* TextShaper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9DAB9282961F10000C64820 /* TextShaper.cpp */; }; D9DAB9322963CD7500C64820 /* harfbuzz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9DAB9312963CD7500C64820 /* harfbuzz.framework */; }; - D943E58E2A24D56000D80361 /* PhysfsIo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D943E58C2A24D56000D80361 /* PhysfsIo.cpp */; }; - D943E58F2A24D56000D80361 /* PhysfsIo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D943E58C2A24D56000D80361 /* PhysfsIo.cpp */; }; - D943E5902A24D56000D80361 /* PhysfsIo.h in Headers */ = {isa = PBXBuildFile; fileRef = D943E58D2A24D56000D80361 /* PhysfsIo.h */; }; FA0A3A5F23366CE9001C269E /* floattypes.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0A3A5D23366CE9001C269E /* floattypes.h */; }; FA0A3A6023366CE9001C269E /* floattypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0A3A5E23366CE9001C269E /* floattypes.cpp */; }; FA0A3A6123366CE9001C269E /* floattypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0A3A5E23366CE9001C269E /* floattypes.cpp */; }; @@ -407,9 +407,6 @@ FA0B7E091A95902C000E1D17 /* EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C291A95902C000E1D17 /* EdgeShape.cpp */; }; FA0B7E0A1A95902C000E1D17 /* EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C291A95902C000E1D17 /* EdgeShape.cpp */; }; FA0B7E0B1A95902C000E1D17 /* EdgeShape.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C2A1A95902C000E1D17 /* EdgeShape.h */; }; - FA0B7E0C1A95902C000E1D17 /* Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C2B1A95902C000E1D17 /* Fixture.cpp */; }; - FA0B7E0D1A95902C000E1D17 /* Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C2B1A95902C000E1D17 /* Fixture.cpp */; }; - FA0B7E0E1A95902C000E1D17 /* Fixture.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C2C1A95902C000E1D17 /* Fixture.h */; }; FA0B7E0F1A95902C000E1D17 /* FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C2D1A95902C000E1D17 /* FrictionJoint.cpp */; }; FA0B7E101A95902C000E1D17 /* FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C2D1A95902C000E1D17 /* FrictionJoint.cpp */; }; FA0B7E111A95902C000E1D17 /* FrictionJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C2E1A95902C000E1D17 /* FrictionJoint.h */; }; @@ -473,9 +470,6 @@ FA0B7E4B1A95902C000E1D17 /* wrap_EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C551A95902C000E1D17 /* wrap_EdgeShape.cpp */; }; FA0B7E4C1A95902C000E1D17 /* wrap_EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C551A95902C000E1D17 /* wrap_EdgeShape.cpp */; }; FA0B7E4D1A95902C000E1D17 /* wrap_EdgeShape.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C561A95902C000E1D17 /* wrap_EdgeShape.h */; }; - FA0B7E4E1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C571A95902C000E1D17 /* wrap_Fixture.cpp */; }; - FA0B7E4F1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C571A95902C000E1D17 /* wrap_Fixture.cpp */; }; - FA0B7E501A95902C000E1D17 /* wrap_Fixture.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C581A95902C000E1D17 /* wrap_Fixture.h */; }; FA0B7E511A95902C000E1D17 /* wrap_FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C591A95902C000E1D17 /* wrap_FrictionJoint.cpp */; }; FA0B7E521A95902C000E1D17 /* wrap_FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C591A95902C000E1D17 /* wrap_FrictionJoint.cpp */; }; FA0B7E531A95902C000E1D17 /* wrap_FrictionJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C5A1A95902C000E1D17 /* wrap_FrictionJoint.h */; }; @@ -1406,6 +1400,8 @@ 217DFBD51D9F6D490055D849 /* usocket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = usocket.c; sourceTree = ""; }; 217DFBD61D9F6D490055D849 /* usocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usocket.h; sourceTree = ""; }; D923E7D2296B85B9002FF1B3 /* harfbuzz.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = harfbuzz.xcframework; path = ios/libraries/harfbuzz.xcframework; sourceTree = ""; }; + D943E58C2A24D56000D80361 /* PhysfsIo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PhysfsIo.cpp; sourceTree = ""; }; + D943E58D2A24D56000D80361 /* PhysfsIo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhysfsIo.h; sourceTree = ""; }; D9DAB9202961F0EE00C64820 /* HarfbuzzShaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HarfbuzzShaper.h; sourceTree = ""; }; D9DAB9212961F0EE00C64820 /* HarfbuzzShaper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HarfbuzzShaper.cpp; sourceTree = ""; }; D9DAB9252961F0FF00C64820 /* GenericShaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenericShaper.h; sourceTree = ""; }; @@ -1413,8 +1409,6 @@ D9DAB9272961F0FF00C64820 /* TextShaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextShaper.h; sourceTree = ""; }; D9DAB9282961F10000C64820 /* TextShaper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextShaper.cpp; sourceTree = ""; }; D9DAB9312963CD7500C64820 /* harfbuzz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = harfbuzz.framework; path = macosx/Frameworks/harfbuzz.framework; sourceTree = ""; }; - D943E58C2A24D56000D80361 /* PhysfsIo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PhysfsIo.cpp; sourceTree = ""; }; - D943E58D2A24D56000D80361 /* PhysfsIo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhysfsIo.h; sourceTree = ""; }; FA08F5AE16C7525600F007B5 /* liblove-macosx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "liblove-macosx.plist"; path = "macosx/liblove-macosx.plist"; sourceTree = ""; }; FA0A3A5D23366CE9001C269E /* floattypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = floattypes.h; sourceTree = ""; }; FA0A3A5E23366CE9001C269E /* floattypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = floattypes.cpp; sourceTree = ""; }; @@ -1652,8 +1646,6 @@ FA0B7C281A95902C000E1D17 /* DistanceJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DistanceJoint.h; sourceTree = ""; }; FA0B7C291A95902C000E1D17 /* EdgeShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EdgeShape.cpp; sourceTree = ""; }; FA0B7C2A1A95902C000E1D17 /* EdgeShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EdgeShape.h; sourceTree = ""; }; - FA0B7C2B1A95902C000E1D17 /* Fixture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Fixture.cpp; sourceTree = ""; }; - FA0B7C2C1A95902C000E1D17 /* Fixture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Fixture.h; sourceTree = ""; }; FA0B7C2D1A95902C000E1D17 /* FrictionJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrictionJoint.cpp; sourceTree = ""; }; FA0B7C2E1A95902C000E1D17 /* FrictionJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrictionJoint.h; sourceTree = ""; }; FA0B7C2F1A95902C000E1D17 /* GearJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GearJoint.cpp; sourceTree = ""; }; @@ -1696,8 +1688,6 @@ FA0B7C541A95902C000E1D17 /* wrap_DistanceJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_DistanceJoint.h; sourceTree = ""; }; FA0B7C551A95902C000E1D17 /* wrap_EdgeShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_EdgeShape.cpp; sourceTree = ""; }; FA0B7C561A95902C000E1D17 /* wrap_EdgeShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_EdgeShape.h; sourceTree = ""; }; - FA0B7C571A95902C000E1D17 /* wrap_Fixture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Fixture.cpp; sourceTree = ""; }; - FA0B7C581A95902C000E1D17 /* wrap_Fixture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Fixture.h; sourceTree = ""; }; FA0B7C591A95902C000E1D17 /* wrap_FrictionJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_FrictionJoint.cpp; sourceTree = ""; }; FA0B7C5A1A95902C000E1D17 /* wrap_FrictionJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_FrictionJoint.h; sourceTree = ""; }; FA0B7C5B1A95902C000E1D17 /* wrap_GearJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_GearJoint.cpp; sourceTree = ""; }; @@ -3165,8 +3155,6 @@ FA0B7C281A95902C000E1D17 /* DistanceJoint.h */, FA0B7C291A95902C000E1D17 /* EdgeShape.cpp */, FA0B7C2A1A95902C000E1D17 /* EdgeShape.h */, - FA0B7C2B1A95902C000E1D17 /* Fixture.cpp */, - FA0B7C2C1A95902C000E1D17 /* Fixture.h */, FA0B7C2D1A95902C000E1D17 /* FrictionJoint.cpp */, FA0B7C2E1A95902C000E1D17 /* FrictionJoint.h */, FA0B7C2F1A95902C000E1D17 /* GearJoint.cpp */, @@ -3209,8 +3197,6 @@ FA0B7C541A95902C000E1D17 /* wrap_DistanceJoint.h */, FA0B7C551A95902C000E1D17 /* wrap_EdgeShape.cpp */, FA0B7C561A95902C000E1D17 /* wrap_EdgeShape.h */, - FA0B7C571A95902C000E1D17 /* wrap_Fixture.cpp */, - FA0B7C581A95902C000E1D17 /* wrap_Fixture.h */, FA0B7C591A95902C000E1D17 /* wrap_FrictionJoint.cpp */, FA0B7C5A1A95902C000E1D17 /* wrap_FrictionJoint.h */, FA0B7C5B1A95902C000E1D17 /* wrap_GearJoint.cpp */, @@ -4272,7 +4258,6 @@ FAFEB29B28F210550025D7D0 /* unixdgram.h in Headers */, FA0B7E051A95902C000E1D17 /* Contact.h in Headers */, FA4F2BE41DE6650600CA37D7 /* Transform.h in Headers */, - FA0B7E0E1A95902C000E1D17 /* Fixture.h in Headers */, FA6A2B661F5F7B6B0074C308 /* wrap_Data.h in Headers */, FA18CEE423DBC6E000263725 /* Graphics.h in Headers */, 217DFBE81D9F6D490055D849 /* inet.h in Headers */, @@ -4467,7 +4452,6 @@ FA4F2B7A1DE0125B00CA37D7 /* xxhash.h in Headers */, FA0B7DDE1A95902C000E1D17 /* wrap_BezierCurve.h in Headers */, FA0B7DED1A95902C000E1D17 /* Cursor.h in Headers */, - FA0B7E501A95902C000E1D17 /* wrap_Fixture.h in Headers */, FA28EBD71E352DB5003446F4 /* FenceSync.h in Headers */, FADF542C1E3DAADA00012CC0 /* wrap_Mesh.h in Headers */, FAA3A9B01B7D465A00CED060 /* android.h in Headers */, @@ -4707,7 +4691,6 @@ FA3C5E431F8C368C0003C579 /* ShaderStage.cpp in Sources */, FA0B7E191A95902C000E1D17 /* MotorJoint.cpp in Sources */, FAF1406F1E20934C00F898D2 /* Initialize.cpp in Sources */, - FA0B7E4F1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */, FA0B7EBF1A95902C000E1D17 /* Thread.cpp in Sources */, FACA02F91F5E39790084B28F /* Compressor.cpp in Sources */, FABDAA002552448300B5C523 /* b2_time_of_impact.cpp in Sources */, @@ -4725,7 +4708,6 @@ FA4F2C111DE936FE00CA37D7 /* unix.c in Sources */, FA1BA0A31E16D97500AA2803 /* wrap_Font.cpp in Sources */, FABDA9842552448200B5C523 /* b2_chain_polygon_contact.cpp in Sources */, - FA0B7E0D1A95902C000E1D17 /* Fixture.cpp in Sources */, FADF53FE1E3D74F200012CC0 /* TextBatch.cpp in Sources */, FA0B7D191A95902C000E1D17 /* TrueTypeRasterizer.cpp in Sources */, FAC271E723B5B5B400C200D3 /* renderstate.cpp in Sources */, @@ -5140,7 +5122,6 @@ FAF140971E20934C00F898D2 /* PpTokens.cpp in Sources */, FAF140A91E20934C00F898D2 /* SymbolTable.cpp in Sources */, FA0B7E181A95902C000E1D17 /* MotorJoint.cpp in Sources */, - FA0B7E4E1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */, FA18CEC523D3AE6700263725 /* wrap_Buffer.cpp in Sources */, FAF6C9F423C2DE2900D7B5BC /* Logger.cpp in Sources */, FABDA9FF2552448300B5C523 /* b2_time_of_impact.cpp in Sources */, @@ -5159,7 +5140,6 @@ FABDA9832552448200B5C523 /* b2_chain_polygon_contact.cpp in Sources */, FA0B7AD61A958EA3000E1D17 /* win32.c in Sources */, FADF54341E3DAE6E00012CC0 /* wrap_SpriteBatch.cpp in Sources */, - FA0B7E0C1A95902C000E1D17 /* Fixture.cpp in Sources */, FA0B7D181A95902C000E1D17 /* TrueTypeRasterizer.cpp in Sources */, FA84DE6627791C36002674C6 /* GraphicsReadback.cpp in Sources */, FA0B7CFA1A95902C000E1D17 /* Filesystem.cpp in Sources */, From a1e4b649ce7c840b0a2d46c2162c0da489b91498 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 7 Oct 2023 15:33:01 -0300 Subject: [PATCH 06/36] Fix compile errors on macOS --- src/modules/physics/box2d/World.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/physics/box2d/World.h b/src/modules/physics/box2d/World.h index 2c7eb78b7..9b8af3b89 100644 --- a/src/modules/physics/box2d/World.h +++ b/src/modules/physics/box2d/World.h @@ -42,6 +42,7 @@ namespace box2d class Contact; class Body; +class Shape; class Joint; /** From de3a0c014205696978f86b15026982c400057962 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 7 Oct 2023 15:33:15 -0300 Subject: [PATCH 07/36] Improve error checking in love.physics.new*Shape --- src/modules/physics/box2d/wrap_Physics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/physics/box2d/wrap_Physics.cpp b/src/modules/physics/box2d/wrap_Physics.cpp index 917cdf812..d54a65f54 100644 --- a/src/modules/physics/box2d/wrap_Physics.cpp +++ b/src/modules/physics/box2d/wrap_Physics.cpp @@ -275,7 +275,7 @@ int w_newFixture(lua_State *L) static Body *luax_optbodyforshape(lua_State *L, int idx, const char *name) { - if (luax_istype(L, idx, Body::type)) + if (lua_isnoneornil(L, idx) || luax_istype(L, idx, Object::type)) return luax_checkbody(L, idx); luax_markdeprecated(L, 1, name, API_FUNCTION_VARIANT, DEPRECATED_REPLACED, "variant with Body parameter"); From 5b4758819ee5b6094d76e56cd888bcce3a01357c Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 7 Oct 2023 15:35:00 -0300 Subject: [PATCH 08/36] nogame screen uses non-deprecated APIs --- src/scripts/nogame.lua | 10 +++++----- src/scripts/nogame.lua.h | 28 ++++++++++++---------------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/scripts/nogame.lua b/src/scripts/nogame.lua index ea66f72af..cc4961499 100644 --- a/src/scripts/nogame.lua +++ b/src/scripts/nogame.lua @@ -2948,9 +2948,8 @@ function love.nogame() self.body = love.physics.newBody(world, x, y, "dynamic") self.body:setLinearDamping(0.8) self.body:setAngularDamping(0.8) - self.shape = love.physics.newPolygonShape(-55, -60, 0, 90, 55, -60) - self.fixture = love.physics.newFixture(self.body, self.shape, 1) - self.fixture:setRestitution(0.5) + self.shape = love.physics.newPolygonShape(self.body, -55, -60, 0, 90, 55, -60) + self.shape:setRestitution(0.5) self.img_normal = img_duckloon_normal self.img_blink = img_duckloon_blink self.img = self.img_normal @@ -3041,8 +3040,9 @@ function love.nogame() link.body = love.physics.newBody(world, link.x, link.y, "dynamic") link.body:setLinearDamping(0.5) link.body:setAngularDamping(0.5) - link.shape = love.physics.newCircleShape(link.radius) - link.fixture = love.physics.newFixture(link.body, link.shape, 0.1 / i) + link.shape = love.physics.newCircleShape(link.body, link.radius) + link.shape:setDensity(0.1 / i) + link.body:resetMassData() link.state = State(link.body) -- Note: every link must also be attached to the Duckloon. Otherwise the diff --git a/src/scripts/nogame.lua.h b/src/scripts/nogame.lua.h index 3bcdeb681..b618cd035 100644 --- a/src/scripts/nogame.lua.h +++ b/src/scripts/nogame.lua.h @@ -27,7 +27,7 @@ const unsigned char nogame_lua[] = 0x2d, 0x2d, 0x5b, 0x5b, 0x0a, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, - 0x2d, 0x32, 0x30, 0x32, 0x31, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x2d, 0x32, 0x30, 0x32, 0x33, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, @@ -11440,14 +11440,11 @@ const unsigned char nogame_lua[] = 0x75, 0x6c, 0x61, 0x72, 0x44, 0x61, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x2e, 0x38, 0x29, 0x0a, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x50, 0x6f, 0x6c, 0x79, 0x67, - 0x6f, 0x6e, 0x53, 0x68, 0x61, 0x70, 0x65, 0x28, 0x2d, 0x35, 0x35, 0x2c, 0x20, 0x2d, 0x36, 0x30, 0x2c, 0x20, - 0x30, 0x2c, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x35, 0x35, 0x2c, 0x20, 0x2d, 0x36, 0x30, 0x29, 0x0a, - 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x66, 0x69, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x3d, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x46, 0x69, 0x78, - 0x74, 0x75, 0x72, 0x65, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2c, 0x20, 0x73, 0x65, - 0x6c, 0x66, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2c, 0x20, 0x31, 0x29, 0x0a, - 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x66, 0x69, 0x78, 0x74, 0x75, 0x72, 0x65, 0x3a, 0x73, 0x65, 0x74, - 0x52, 0x65, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x2e, 0x35, 0x29, 0x0a, + 0x6f, 0x6e, 0x53, 0x68, 0x61, 0x70, 0x65, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2c, + 0x20, 0x2d, 0x35, 0x35, 0x2c, 0x20, 0x2d, 0x36, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x39, 0x30, 0x2c, 0x20, + 0x35, 0x35, 0x2c, 0x20, 0x2d, 0x36, 0x30, 0x29, 0x0a, + 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x3a, 0x73, 0x65, 0x74, 0x52, 0x65, + 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x2e, 0x35, 0x29, 0x0a, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x69, 0x6d, 0x67, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x69, 0x6d, 0x67, 0x5f, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x6f, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x0a, @@ -11619,13 +11616,12 @@ const unsigned char nogame_lua[] = 0x67, 0x75, 0x6c, 0x61, 0x72, 0x44, 0x61, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x2e, 0x35, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x43, 0x69, 0x72, 0x63, - 0x6c, 0x65, 0x53, 0x68, 0x61, 0x70, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x75, - 0x73, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x66, 0x69, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x3d, 0x20, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x46, 0x69, - 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2c, 0x20, 0x6c, - 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2c, 0x20, 0x30, 0x2e, 0x31, 0x20, 0x2f, 0x20, 0x69, - 0x29, 0x0a, + 0x6c, 0x65, 0x53, 0x68, 0x61, 0x70, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2c, + 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x3a, 0x73, 0x65, 0x74, 0x44, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x28, 0x30, 0x2e, 0x31, 0x20, 0x2f, 0x20, 0x69, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x72, 0x65, 0x73, 0x65, 0x74, + 0x4d, 0x61, 0x73, 0x73, 0x44, 0x61, 0x74, 0x61, 0x28, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x0a, 0x0a, From ff45c308f4881505b21adb5bcaafe45c40b3f76a Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 7 Oct 2023 17:03:40 -0300 Subject: [PATCH 09/36] macOS: increase minimum supported OS from 10.9 to 10.13 The most recent macOS SDK fails to link when the deployment target is set to 10.9. --- platform/xcode/liblove.xcodeproj/project.pbxproj | 6 +++--- platform/xcode/love.xcodeproj/project.pbxproj | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 605e07e02..e591d2743 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -5511,7 +5511,7 @@ ); IPHONEOS_DEPLOYMENT_TARGET = 9.0; LIBRARY_SEARCH_PATHS = ""; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = NO; SDKROOT = macosx; USE_HEADERMAP = NO; @@ -5577,7 +5577,7 @@ ); IPHONEOS_DEPLOYMENT_TARGET = 9.0; LIBRARY_SEARCH_PATHS = ""; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; USE_HEADERMAP = NO; @@ -5716,7 +5716,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LIBRARY_SEARCH_PATHS = ""; LLVM_LTO = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = NO; SDKROOT = macosx; USE_HEADERMAP = NO; diff --git a/platform/xcode/love.xcodeproj/project.pbxproj b/platform/xcode/love.xcodeproj/project.pbxproj index 0d7b4911a..00d46f5b2 100644 --- a/platform/xcode/love.xcodeproj/project.pbxproj +++ b/platform/xcode/love.xcodeproj/project.pbxproj @@ -564,7 +564,7 @@ INFOPLIST_FILE = "love-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = love; SDKROOT = macosx; @@ -640,7 +640,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; LLVM_LTO = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = NO; PRODUCT_NAME = love; SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; @@ -874,7 +874,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; LLVM_LTO = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = NO; PRODUCT_NAME = love; SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; From 1396e2662631921c46d2a452076a808691e6da9d Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sun, 8 Oct 2023 12:32:10 -0300 Subject: [PATCH 10/36] auto.lua: fix consistency on Windows --- src/scripts/auto.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripts/auto.lua b/src/scripts/auto.lua index ce59487f6..f9fa450ea 100644 --- a/src/scripts/auto.lua +++ b/src/scripts/auto.lua @@ -77,13 +77,14 @@ local function auto(name) local out_data = "" --go through the input file line-by-line for line in src_file:lines() do + line = line:gsub("\r", "") --if the line is non-empty if #line > 0 then --set the counter to -1 --this will start a new line (see tohex) counter = -1 --append the output to what we had, plus a newline character (0x0a is newline) - out_data = ("%s%s0x0a,"):format(out_data, line:gsub("\r", ""):gsub(".", tohex)) + out_data = ("%s%s0x0a,"):format(out_data, line:gsub(".", tohex)) else out_data = out_data .. "\n\t0x0a," end From 112a09ceb78bdd9eacd69b196a75c22275f7fc26 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sun, 8 Oct 2023 12:43:27 -0300 Subject: [PATCH 11/36] Shape:setDensity no longer needs Body:resetMassData unless the Body already has custom mass data. Add Body:hasCustomMassData. If the Body has custom mass data, attaching a Shape to it doesn't automatically reset its mass data. --- src/modules/physics/box2d/Body.cpp | 5 +++++ src/modules/physics/box2d/Body.h | 4 ++++ src/modules/physics/box2d/Shape.cpp | 11 ++++++++++- src/modules/physics/box2d/wrap_Body.cpp | 8 ++++++++ src/modules/physics/box2d/wrap_Physics.cpp | 6 +----- src/scripts/nogame.lua | 1 - src/scripts/nogame.lua.h | 2 -- 7 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/modules/physics/box2d/Body.cpp b/src/modules/physics/box2d/Body.cpp index a3e7ee110..a939de73b 100644 --- a/src/modules/physics/box2d/Body.cpp +++ b/src/modules/physics/box2d/Body.cpp @@ -39,6 +39,7 @@ namespace box2d Body::Body(World *world, b2Vec2 p, Body::Type type) : world(world) + , hasCustomMass(false) { b2BodyDef def; def.position = Physics::scaleDown(p); @@ -249,6 +250,7 @@ void Body::setLinearDamping(float d) void Body::resetMassData() { body->ResetMassData(); + hasCustomMass = false; } void Body::setMassData(float x, float y, float m, float i) @@ -258,6 +260,7 @@ void Body::setMassData(float x, float y, float m, float i) massData.mass = m; massData.I = Physics::scaleDown(Physics::scaleDown(i)); body->SetMassData(&massData); + hasCustomMass = true; } void Body::setMass(float m) @@ -266,6 +269,7 @@ void Body::setMass(float m) body->GetMassData(&data); data.mass = m; body->SetMassData(&data); + hasCustomMass = true; } void Body::setInertia(float i) @@ -275,6 +279,7 @@ void Body::setInertia(float i) massData.mass = body->GetMass(); massData.I = Physics::scaleDown(Physics::scaleDown(i)); body->SetMassData(&massData); + hasCustomMass = true; } void Body::setGravityScale(float scale) diff --git a/src/modules/physics/box2d/Body.h b/src/modules/physics/box2d/Body.h index 1d0b2d770..1c5ae8a37 100644 --- a/src/modules/physics/box2d/Body.h +++ b/src/modules/physics/box2d/Body.h @@ -137,6 +137,8 @@ public: **/ int getMassData(lua_State *L); + bool hasCustomMassData() const { return hasCustomMass; } + /** * Gets the Body's angular damping. **/ @@ -433,6 +435,8 @@ private: // unowned? World *world; + bool hasCustomMass; + // Reference to arbitrary data. Reference* ref = nullptr; diff --git a/src/modules/physics/box2d/Shape.cpp b/src/modules/physics/box2d/Shape.cpp index c47c4c7ff..b7c0ddece 100644 --- a/src/modules/physics/box2d/Shape.cpp +++ b/src/modules/physics/box2d/Shape.cpp @@ -47,9 +47,16 @@ Shape::Shape(Body *body, const b2Shape &shape) b2FixtureDef def; def.shape = &shape; def.userData.pointer = (uintptr_t)this; - def.density = 1.0f; + + // 0 density stops CreateFixture from calling b2Body::ResetMassData(). + def.density = body->hasCustomMassData() ? 0.0f : 1.0f; + fixture = body->body->CreateFixture(&def); this->shape = fixture->GetShape(); + + if (body->hasCustomMassData()) + setDensity(1.0f); + retain(); // Shape::destroy does the release(). } else @@ -188,6 +195,8 @@ void Shape::setDensity(float density) { throwIfFixtureNotValid(); fixture->SetDensity(density); + if (!body->hasCustomMassData()) + body->resetMassData(); } void Shape::setSensor(bool sensor) diff --git a/src/modules/physics/box2d/wrap_Body.cpp b/src/modules/physics/box2d/wrap_Body.cpp index f0d4dd865..44bda7c0e 100644 --- a/src/modules/physics/box2d/wrap_Body.cpp +++ b/src/modules/physics/box2d/wrap_Body.cpp @@ -162,6 +162,13 @@ int w_Body_getMassData(lua_State *L) return t->getMassData(L); } +int w_Body_hasCustomMassData(lua_State *L) +{ + Body *t = luax_checkbody(L, 1); + luax_pushboolean(L, t->hasCustomMassData()); + return 1; +} + int w_Body_getAngularDamping(lua_State *L) { Body *t = luax_checkbody(L, 1); @@ -688,6 +695,7 @@ static const luaL_Reg w_Body_functions[] = { "getMass", w_Body_getMass }, { "getInertia", w_Body_getInertia }, { "getMassData", w_Body_getMassData }, + { "hasCustomMassData", w_Body_hasCustomMassData }, { "getAngularDamping", w_Body_getAngularDamping }, { "getLinearDamping", w_Body_getLinearDamping }, { "getGravityScale", w_Body_getGravityScale }, diff --git a/src/modules/physics/box2d/wrap_Physics.cpp b/src/modules/physics/box2d/wrap_Physics.cpp index d54a65f54..34dfb81ff 100644 --- a/src/modules/physics/box2d/wrap_Physics.cpp +++ b/src/modules/physics/box2d/wrap_Physics.cpp @@ -262,11 +262,7 @@ int w_newFixture(lua_State *L) float density = (float)luaL_optnumber(L, 3, 1.0f); Shape *newShape; - luax_catchexcept(L, [&]() { - newShape = instance()->newAttachedShape(body, shape, density); - newShape->setDensity(density); - body->resetMassData(); - }); + luax_catchexcept(L, [&]() { newShape = instance()->newAttachedShape(body, shape, density); }); luax_pushshape(L, newShape); newShape->release(); diff --git a/src/scripts/nogame.lua b/src/scripts/nogame.lua index cc4961499..39e473140 100644 --- a/src/scripts/nogame.lua +++ b/src/scripts/nogame.lua @@ -3042,7 +3042,6 @@ function love.nogame() link.body:setAngularDamping(0.5) link.shape = love.physics.newCircleShape(link.body, link.radius) link.shape:setDensity(0.1 / i) - link.body:resetMassData() link.state = State(link.body) -- Note: every link must also be attached to the Duckloon. Otherwise the diff --git a/src/scripts/nogame.lua.h b/src/scripts/nogame.lua.h index b618cd035..b467c5eff 100644 --- a/src/scripts/nogame.lua.h +++ b/src/scripts/nogame.lua.h @@ -11620,8 +11620,6 @@ const unsigned char nogame_lua[] = 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x3a, 0x73, 0x65, 0x74, 0x44, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x28, 0x30, 0x2e, 0x31, 0x20, 0x2f, 0x20, 0x69, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x72, 0x65, 0x73, 0x65, 0x74, - 0x4d, 0x61, 0x73, 0x73, 0x44, 0x61, 0x74, 0x61, 0x28, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x0a, 0x0a, From 27c45696972869c8d6fbe2b9bd315f50a35aee6a Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sun, 8 Oct 2023 14:06:55 -0300 Subject: [PATCH 12/36] love.physics: clean up some internal collision processing code --- src/modules/physics/box2d/World.cpp | 30 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index b90c4a3c7..1ec53926e 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -114,22 +114,6 @@ World::ContactFilter::~ContactFilter() bool World::ContactFilter::process(Shape *a, Shape *b) { - // Handle masks, reimplemented from the manual - int filterA[3], filterB[3]; - // [0] categoryBits - // [1] maskBits - // [2] groupIndex - a->getFilterData(filterA); - b->getFilterData(filterB); - - if (filterA[2] != 0 && // 0 is the default group, so this does not count - filterA[2] == filterB[2]) // if they are in the same group - return filterA[2] > 0; // Negative indexes mean you don't collide - - if ((filterA[1] & filterB[0]) == 0 || - (filterB[1] & filterA[0]) == 0) - return false; // A and B aren't set to collide - if (ref != nullptr && L != nullptr) { ref->push(L); @@ -138,6 +122,7 @@ bool World::ContactFilter::process(Shape *a, Shape *b) lua_call(L, 2, 1); return luax_toboolean(L, -1); } + return true; } @@ -384,11 +369,24 @@ void World::PostSolve(b2Contact *contact, const b2ContactImpulse *impulse) bool World::ShouldCollide(b2Fixture *fixtureA, b2Fixture *fixtureB) { + const b2Filter &filterA = fixtureA->GetFilterData(); + const b2Filter &filterB = fixtureB->GetFilterData(); + + // From b2_world_callbacks.cpp + // 0 is the default group index. If they're customized to be the same group, + // allow collisions if it's positive and disallow if it's negative. + if (filterA.groupIndex != 0 && filterA.groupIndex == filterB.groupIndex) + return filterA.groupIndex > 0; + + if ((filterA.maskBits & filterB.categoryBits) == 0 || (filterA.categoryBits & filterB.maskBits) == 0) + return false; + // Shapes should be memoized, if we created them Shape *a = (Shape *)(fixtureA->GetUserData().pointer); Shape *b = (Shape *)(fixtureB->GetUserData().pointer); if (!a || !b) throw love::Exception("A Shape has escaped Memoizer!"); + return filter.process(a, b); } From b8cbb62bc315f6ff52e4f5e0c9b4a2b0d3aa6b7d Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sun, 8 Oct 2023 21:08:59 -0300 Subject: [PATCH 13/36] opengl: scissor and color mask no longer affects love.graphics.clear. This makes it more consistent with other backends. --- src/modules/graphics/opengl/Graphics.cpp | 44 ++++++--------------- src/modules/graphics/opengl/OpenGL.cpp | 49 ++++++++++++++++++++++++ src/modules/graphics/opengl/OpenGL.h | 19 +++++++++ src/modules/graphics/opengl/Texture.cpp | 43 ++++++++------------- 4 files changed, 95 insertions(+), 60 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 664d26fa7..c2e5222dd 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -922,36 +922,23 @@ void Graphics::clear(OptionalColorD c, OptionalInt stencil, OptionalDouble depth flags |= GL_COLOR_BUFFER_BIT; } - uint32 stencilwrites = gl.getStencilWriteMask(); - if (stencil.hasValue) { - if (stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(LOVE_UINT32_MAX); - glClearStencil(stencil.value); 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; } if (flags != 0) + { + OpenGL::CleanClearState cs(flags); glClear(flags); - - if (stencil.hasValue && stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(stencilwrites); - - if (depth.hasValue && !hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); + } if (c.hasValue && gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current) { @@ -1041,36 +1028,23 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten GLbitfield flags = 0; - uint32 stencilwrites = gl.getStencilWriteMask(); - if (stencil.hasValue) { - if (stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(LOVE_UINT32_MAX); - glClearStencil(stencil.value); 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; } if (flags != 0) + { + OpenGL::CleanClearState cs(flags); glClear(flags); - - if (stencil.hasValue && stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(stencilwrites); - - if (depth.hasValue && !hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); + } if (gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current) { @@ -1568,7 +1542,11 @@ void Graphics::setColorMask(ColorChannelMask mask) { flushBatchedDraws(); - glColorMask(mask.r, mask.g, mask.b, mask.a); + uint32 maskbits = + ((mask.r ? 1 : 0) << 1) | ((mask.g ? 1 : 0) << 2) | + ((mask.g ? 1 : 0) << 3) | ((mask.a ? 1 : 0) << 4); + + gl.setColorWriteMask(maskbits); states.back().colorMask = mask; } diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index b169a06a9..df3a0b9b8 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -91,12 +91,49 @@ OpenGL::TempDebugGroup::~TempDebugGroup() } } +OpenGL::CleanClearState::CleanClearState(GLbitfield clearFlags) + : clearFlags(clearFlags) + , colorWriteMask(gl.getColorWriteMask()) + , stencilWriteMask(gl.getStencilWriteMask()) + , depthWrites(gl.hasDepthWrites()) + , scissor(gl.isStateEnabled(ENABLE_SCISSOR_TEST)) +{ + if (clearFlags & GL_COLOR_BUFFER_BIT) + gl.setColorWriteMask(LOVE_UINT32_MAX); + + if (clearFlags & GL_DEPTH_BUFFER_BIT) + gl.setDepthWrites(false); + + if (clearFlags & GL_STENCIL_BUFFER_BIT) + gl.setStencilWriteMask(LOVE_UINT32_MAX); + + if (clearFlags != 0) + gl.setEnableState(ENABLE_SCISSOR_TEST, false); +} + +OpenGL::CleanClearState::~CleanClearState() +{ + if (clearFlags & GL_COLOR_BUFFER_BIT) + gl.setColorWriteMask(colorWriteMask); + + if (clearFlags & GL_DEPTH_BUFFER_BIT) + gl.setDepthWrites(depthWrites); + + if (clearFlags & GL_STENCIL_BUFFER_BIT) + gl.setStencilWriteMask(stencilWriteMask); + + if (clearFlags != 0) + gl.setEnableState(ENABLE_SCISSOR_TEST, scissor); +} + OpenGL::OpenGL() : stats() + , bugs() , contextInitialized(false) , pixelShaderHighpSupported(false) , baseVertexSupported(false) , maxAnisotropy(1.0f) + , maxLODBias(0.0f) , max2DTextureSize(0) , max3DTextureSize(0) , maxCubeTextureSize(0) @@ -284,6 +321,7 @@ void OpenGL::setupContext() setDepthWrites(state.depthWritesEnabled); setStencilWriteMask(state.stencilWriteMask); + setColorWriteMask(state.colorWriteMask); createDefaultTexture(); @@ -1125,6 +1163,17 @@ uint32 OpenGL::getStencilWriteMask() const return state.stencilWriteMask; } +void OpenGL::setColorWriteMask(uint32 mask) +{ + glColorMask(mask & (1 << 0), mask & (1 << 1), mask & (1 << 2), mask & (1 << 3)); + state.colorWriteMask = mask; +} + +uint32 OpenGL::getColorWriteMask() const +{ + return state.colorWriteMask; +} + void OpenGL::useProgram(GLuint program) { glUseProgram(program); diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 6f2d26746..3690c6baa 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -124,6 +124,21 @@ public: ~TempDebugGroup(); }; + // glClear() is affected by various OpenGL state... + class CleanClearState + { + public: + CleanClearState(GLbitfield clearFlags); + ~CleanClearState(); + + private: + GLenum clearFlags; + uint32 colorWriteMask; + uint32 stencilWriteMask; + bool depthWrites; + bool scissor; + }; + struct Stats { int shaderSwitches; @@ -301,6 +316,9 @@ public: void setStencilWriteMask(uint32 mask); uint32 getStencilWriteMask() const; + void setColorWriteMask(uint32 mask); + uint32 getColorWriteMask() const; + /** * Calls glUseProgram. **/ @@ -528,6 +546,7 @@ private: bool depthWritesEnabled = true; uint32 stencilWriteMask = LOVE_UINT32_MAX; + uint32 colorWriteMask = LOVE_UINT32_MAX; GLuint boundFramebuffers[2]; diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index 70fdbd344..01a451e8f 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -80,31 +80,22 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo if (clear) { - if (isPixelFormatDepthStencil(format)) + bool ds = isPixelFormatDepthStencil(format); + + GLbitfield clearflags = ds ? GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT : GL_COLOR_BUFFER_BIT; + OpenGL::CleanClearState cleanClearState(clearflags); + + if (ds) { - bool hadDepthWrites = gl.hasDepthWrites(); - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); - - uint32 stencilwrite = gl.getStencilWriteMask(); - if (stencilwrite != LOVE_UINT32_MAX) - gl.setStencilWriteMask(LOVE_UINT32_MAX); - gl.clearDepth(1.0); glClearStencil(0); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - if (!hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); - - if (stencilwrite != LOVE_UINT32_MAX) - gl.setStencilWriteMask(stencilwrite); } else { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); } + + glClear(clearflags); } } } @@ -167,25 +158,23 @@ static GLenum newRenderbuffer(int width, int height, int &samples, PixelFormat p if (status == GL_FRAMEBUFFER_COMPLETE) { - if (isPixelFormatDepthStencil(pixelformat)) - { - bool hadDepthWrites = gl.hasDepthWrites(); - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); + bool ds = isPixelFormatDepthStencil(pixelformat); + GLbitfield clearflags = ds ? GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT : GL_COLOR_BUFFER_BIT; + OpenGL::CleanClearState cleanClearState(clearflags); + + if (ds) + { gl.clearDepth(1.0); glClearStencil(0); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - if (!hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); } else { // Initialize the buffer to transparent black. glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); } + + glClear(clearflags); } else { From 2789e5eabf642d10aee8ad69486722a2d698a291 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sun, 8 Oct 2023 21:36:10 -0300 Subject: [PATCH 14/36] opengl: fix clearing integer format Canvases. --- src/modules/graphics/opengl/Graphics.cpp | 24 ++++++++++ src/modules/graphics/opengl/Texture.cpp | 57 ++++++++++++++++++------ 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index c2e5222dd..790afa564 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -909,6 +909,30 @@ void Graphics::endPass(bool presenting) void Graphics::clear(OptionalColorD c, OptionalInt stencil, OptionalDouble depth) { + if (c.hasValue) + { + bool hasintegerformat = false; + + const auto &rts = states.back().renderTargets; + for (const auto &rt : rts.colors) + { + if (rt.texture.get() && isPixelFormatInteger(rt.texture->getPixelFormat())) + hasintegerformat = true; + } + + // This variant of clear() uses glClear() which can't clear integer formats, + // so we switch to the MRT variant if needed. + if (hasintegerformat) + { + std::vector colors(rts.colors.size()); + for (size_t i = 0; i < colors.size(); i++) + colors[i] = c; + + clear(colors, stencil, depth); + return; + } + } + if (c.hasValue || stencil.hasValue || depth.hasValue) flushBatchedDraws(); diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index 01a451e8f..1b6eb69f1 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -78,7 +78,21 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo gl.framebufferTexture(attachment, texType, texture, mip, layer, face); } - if (clear) + if (clear && isPixelFormatInteger(format)) + { + PixelFormatType datatype = getPixelFormatInfo(format).dataType; + if (datatype == PIXELFORMATTYPE_SINT) + { + const GLint carray[] = { 0, 0, 0, 0 }; + glClearBufferiv(GL_COLOR, 0, carray); + } + else + { + const GLuint carray[] = { 0, 0, 0, 0 }; + glClearBufferuiv(GL_COLOR, 0, carray); + } + } + else if (clear) { bool ds = isPixelFormatDepthStencil(format); @@ -158,23 +172,40 @@ static GLenum newRenderbuffer(int width, int height, int &samples, PixelFormat p if (status == GL_FRAMEBUFFER_COMPLETE) { - bool ds = isPixelFormatDepthStencil(pixelformat); - - GLbitfield clearflags = ds ? GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT : GL_COLOR_BUFFER_BIT; - OpenGL::CleanClearState cleanClearState(clearflags); - - if (ds) + if (isPixelFormatInteger(pixelformat)) { - gl.clearDepth(1.0); - glClearStencil(0); + PixelFormatType datatype = getPixelFormatInfo(pixelformat).dataType; + if (datatype == PIXELFORMATTYPE_SINT) + { + const GLint carray[] = { 0, 0, 0, 0 }; + glClearBufferiv(GL_COLOR, 0, carray); + } + else + { + const GLuint carray[] = { 0, 0, 0, 0 }; + glClearBufferuiv(GL_COLOR, 0, carray); + } } else { - // Initialize the buffer to transparent black. - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - } + bool ds = isPixelFormatDepthStencil(pixelformat); - glClear(clearflags); + GLbitfield clearflags = ds ? GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT : GL_COLOR_BUFFER_BIT; + OpenGL::CleanClearState cleanClearState(clearflags); + + if (ds) + { + gl.clearDepth(1.0); + glClearStencil(0); + } + else + { + // Initialize the buffer to transparent black. + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + } + + glClear(clearflags); + } } else { From 8f8afe3de592190ce94f8c0263c27b0563087e99 Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 9 Oct 2023 15:31:23 +0200 Subject: [PATCH 15/36] vulkan: fix crash when using love.window.close() --- src/modules/graphics/vulkan/Graphics.cpp | 274 +++++++++--------- src/modules/graphics/vulkan/Graphics.h | 15 +- .../graphics/vulkan/GraphicsReadback.cpp | 6 +- 3 files changed, 158 insertions(+), 137 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 8a4f7500f..2432dad27 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -65,22 +65,88 @@ const char *Graphics::getName() const return "love.graphics.vulkan"; } -const VkDevice Graphics::getDevice() const +VkDevice Graphics::getDevice() const { return device; } -const VmaAllocator Graphics::getVmaAllocator() const +VmaAllocator Graphics::getVmaAllocator() const { return vmaAllocator; } +static void checkOptionalInstanceExtensions(OptionalInstanceExtensions& ext) +{ + uint32_t count; + + vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr); + + std::vector extensions(count); + + vkEnumerateInstanceExtensionProperties(nullptr, &count, extensions.data()); + + for (const auto& extension : extensions) + { + if (strcmp(extension.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0) + ext.physicalDeviceProperties2 = true; + } +} + Graphics::Graphics() { if (SDL_Vulkan_LoadLibrary(nullptr)) throw love::Exception("could not find vulkan"); volkInitializeCustom((PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr()); + + if (isDebugEnabled() && !checkValidationSupport()) + throw love::Exception("validation layers requested, but not available"); + + VkApplicationInfo appInfo{}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "LOVE"; + appInfo.applicationVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); // get this version from somewhere else? + appInfo.pEngineName = "LOVE Game Framework"; + appInfo.engineVersion = VK_MAKE_API_VERSION(0, VERSION_MAJOR, VERSION_MINOR, VERSION_REV); + appInfo.apiVersion = VK_API_VERSION_1_3; + + VkInstanceCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &appInfo; + createInfo.pNext = nullptr; + + // GetInstanceExtensions works with a null window parameter as long as + // SDL_Vulkan_LoadLibrary has been called (which we do earlier). + unsigned int count; + if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, nullptr) != SDL_TRUE) + throw love::Exception("couldn't retrieve sdl vulkan extensions"); + + std::vector extensions = {}; + + checkOptionalInstanceExtensions(optionalInstanceExtensions); + + if (optionalInstanceExtensions.physicalDeviceProperties2) + extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + + size_t additional_extension_count = extensions.size(); + extensions.resize(additional_extension_count + count); + + if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, extensions.data() + additional_extension_count) != SDL_TRUE) + throw love::Exception("couldn't retrieve sdl vulkan extensions"); + + createInfo.enabledExtensionCount = static_cast(extensions.size()); + createInfo.ppEnabledExtensionNames = extensions.data(); + + if (isDebugEnabled()) + { + createInfo.enabledLayerCount = static_cast(validationLayers.size()); + createInfo.ppEnabledLayerNames = validationLayers.data(); + } + + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) + throw love::Exception("couldn't create vulkan instance"); + + volkLoadInstance(instance); } Graphics::~Graphics() @@ -88,6 +154,10 @@ Graphics::~Graphics() defaultConstantColor.set(nullptr); defaultTexture.set(nullptr); + Volatile::unloadAll(); + cleanup(); + vkDestroyInstance(instance, nullptr); + SDL_Vulkan_UnloadLibrary(); } @@ -302,14 +372,14 @@ void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) startRenderPass(); } -void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData) +void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallbackData) { flushBatchedDraws(); if (renderPassState.active) endRenderPass(); - if (present) + if (submitMode == SUBMIT_PRESENT) { if (pendingScreenshotCallbacks.empty()) Vulkan::cmdTransitionImageLayout( @@ -435,7 +505,7 @@ void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData) VkFence fence = VK_NULL_HANDLE; - if (present) + if (submitMode == SUBMIT_PRESENT) { submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = signalSemaphores; @@ -447,7 +517,7 @@ void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData) if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, fence) != VK_SUCCESS) throw love::Exception("failed to submit draw command buffer"); - if (!present) + if (submitMode == SUBMIT_NOPRESENT || submitMode == SUBMIT_RESTART) { vkQueueWaitIdle(graphicsQueue); @@ -458,7 +528,8 @@ void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData) callbacks.clear(); } - startRecordingGraphicsCommands(); + if (submitMode == SUBMIT_RESTART) + startRecordingGraphicsCommands(); } } @@ -475,7 +546,7 @@ void Graphics::present(void *screenshotCallbackdata) deprecations.draw(this); - submitGpuCommands(true, screenshotCallbackdata); + submitGpuCommands(SUBMIT_PRESENT, screenshotCallbackdata); VkPresentInfoKHR presentInfo{}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; @@ -540,64 +611,80 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int readbackCallbacks.clear(); readbackCallbacks.resize(MAX_FRAMES_IN_FLIGHT); - createVulkanInstance(); + bool createBaseObjects = physicalDevice == VK_NULL_HANDLE; + createSurface(); - pickPhysicalDevice(); - createLogicalDevice(); - createPipelineCache(); - initVMA(); - initCapabilities(); + + if (createBaseObjects) + { + pickPhysicalDevice(); + createLogicalDevice(); + createPipelineCache(); + initVMA(); + initCapabilities(); + } + + msaaSamples = getMsaaCount(requestedMsaa); + createSwapChain(); createImageViews(); createScreenshotCallbackBuffers(); - createSyncObjects(); createColorResources(); createDepthResources(); transitionColorDepthLayouts = true; - createCommandPool(); - createCommandBuffers(); + + if (createBaseObjects) + { + createCommandPool(); + createCommandBuffers(); + createSyncObjects(); + } beginFrame(); - if (batchedDrawState.vb[0] == nullptr) + if (createBaseObjects) { - // Initial sizes that should be good enough for most cases. It will - // resize to fit if needed, later. - batchedDrawState.vb[0] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1); - batchedDrawState.vb[1] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 256 * 1024 * 1); - batchedDrawState.indexBuffer = new StreamBuffer(this, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX); - } + if (batchedDrawState.vb[0] == nullptr) + { + // Initial sizes that should be good enough for most cases. It will + // resize to fit if needed, later. + batchedDrawState.vb[0] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1); + batchedDrawState.vb[1] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 256 * 1024 * 1); + batchedDrawState.indexBuffer = new StreamBuffer(this, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX); + } - // sometimes the VertexTexCoord is not set, so we manually adjust it to (0, 0) - if (defaultConstantTexCoord == nullptr) - { - float zeroTexCoord[2] = { 0.0f, 0.0f }; - Buffer::DataDeclaration format("ConstantTexCoord", DATAFORMAT_FLOAT_VEC2); - Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC); - defaultConstantTexCoord = newBuffer(settings, { format }, zeroTexCoord, sizeof(zeroTexCoord), 1); - } + // sometimes the VertexTexCoord is not set, so we manually adjust it to (0, 0) + if (defaultConstantTexCoord == nullptr) + { + float zeroTexCoord[2] = { 0.0f, 0.0f }; + Buffer::DataDeclaration format("ConstantTexCoord", DATAFORMAT_FLOAT_VEC2); + Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC); + defaultConstantTexCoord = newBuffer(settings, { format }, zeroTexCoord, sizeof(zeroTexCoord), 1); + } - // sometimes the VertexColor is not set, so we manually adjust it to white color - if (defaultConstantColor == nullptr) - { - uint8 whiteColor[] = { 255, 255, 255, 255 }; - Buffer::DataDeclaration format("ConstantColor", DATAFORMAT_UNORM8_VEC4); - Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC); - defaultConstantColor = newBuffer(settings, { format }, whiteColor, sizeof(whiteColor), 1); - } + // sometimes the VertexColor is not set, so we manually adjust it to white color + if (defaultConstantColor == nullptr) + { + uint8 whiteColor[] = { 255, 255, 255, 255 }; + Buffer::DataDeclaration format("ConstantColor", DATAFORMAT_UNORM8_VEC4); + Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC); + defaultConstantColor = newBuffer(settings, { format }, whiteColor, sizeof(whiteColor), 1); + } - createDefaultTexture(); - createDefaultShaders(); - Shader::current = Shader::standardShaders[Shader::StandardShader::STANDARD_DEFAULT]; - createQuadIndexBuffer(); - createFanIndexBuffer(); + createDefaultTexture(); + createDefaultShaders(); + Shader::current = Shader::standardShaders[Shader::StandardShader::STANDARD_DEFAULT]; + createQuadIndexBuffer(); + createFanIndexBuffer(); + + frameCounter = 0; + currentFrame = 0; + } restoreState(states.back()); Vulkan::resetShaderSwitches(); - frameCounter = 0; - currentFrame = 0; created = true; drawCalls = 0; drawCallsBatched = 0; @@ -659,14 +746,12 @@ void Graphics::getAPIStats(int &shaderswitches) const void Graphics::unSetMode() { - renderPassUsages.clear(); - framebufferUsages.clear(); - pipelineUsages.clear(); - + submitGpuCommands(SUBMIT_NOPRESENT); + created = false; - vkDeviceWaitIdle(device); - Volatile::unloadAll(); - cleanup(); + + cleanupSwapChain(); + vkDestroySurfaceKHR(instance, surface, nullptr); } void Graphics::setActive(bool enable) @@ -1332,75 +1417,6 @@ const OptionalDeviceExtensions &Graphics::getEnabledOptionalDeviceExtensions() c return optionalDeviceExtensions; } -static void checkOptionalInstanceExtensions(OptionalInstanceExtensions &ext) -{ - uint32_t count; - - vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr); - - std::vector extensions(count); - - vkEnumerateInstanceExtensionProperties(nullptr, &count, extensions.data()); - - for (const auto &extension : extensions) - { - if (strcmp(extension.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0) - ext.physicalDeviceProperties2 = true; - } -} - -void Graphics::createVulkanInstance() -{ - if (isDebugEnabled() && !checkValidationSupport()) - throw love::Exception("validation layers requested, but not available"); - - VkApplicationInfo appInfo{}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pApplicationName = "LOVE"; - appInfo.applicationVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); // get this version from somewhere else? - appInfo.pEngineName = "LOVE Game Framework"; - appInfo.engineVersion = VK_MAKE_API_VERSION(0, VERSION_MAJOR, VERSION_MINOR, VERSION_REV); - appInfo.apiVersion = VK_API_VERSION_1_3; - - VkInstanceCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.pApplicationInfo = &appInfo; - createInfo.pNext = nullptr; - - // GetInstanceExtensions works with a null window parameter as long as - // SDL_Vulkan_LoadLibrary has been called (which we do earlier). - unsigned int count; - if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, nullptr) != SDL_TRUE) - throw love::Exception("couldn't retrieve sdl vulkan extensions"); - - std::vector extensions = {}; - - checkOptionalInstanceExtensions(optionalInstanceExtensions); - - if (optionalInstanceExtensions.physicalDeviceProperties2) - extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - - size_t additional_extension_count = extensions.size(); - extensions.resize(additional_extension_count + count); - - if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, extensions.data() + additional_extension_count) != SDL_TRUE) - throw love::Exception("couldn't retrieve sdl vulkan extensions"); - - createInfo.enabledExtensionCount = static_cast(extensions.size()); - createInfo.ppEnabledExtensionNames = extensions.data(); - - if (isDebugEnabled()) - { - createInfo.enabledLayerCount = static_cast(validationLayers.size()); - createInfo.ppEnabledLayerNames = validationLayers.data(); - } - - if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) - throw love::Exception("couldn't create vulkan instance"); - - volkLoadInstance(instance); -} - bool Graphics::checkValidationSupport() { uint32_t layerCount; @@ -1458,7 +1474,6 @@ void Graphics::pickPhysicalDevice() minUniformBufferOffsetAlignment = properties.limits.minUniformBufferOffsetAlignment; deviceApiVersion = properties.apiVersion; - msaaSamples = getMsaaCount(requestedMsaa); depthStencilFormat = findDepthFormat(); } @@ -3040,8 +3055,6 @@ void Graphics::createDefaultTexture() void Graphics::cleanup() { - cleanupSwapChain(); - for (auto &cleanUpFns : cleanUpFunctions) for (auto &cleanUpFn : cleanUpFns) cleanUpFn(); @@ -3076,8 +3089,6 @@ void Graphics::cleanup() vkDestroyCommandPool(device, commandPool, nullptr); vkDestroyPipelineCache(device, pipelineCache, nullptr); vkDestroyDevice(device, nullptr); - vkDestroySurfaceKHR(instance, surface, nullptr); - vkDestroyInstance(instance, nullptr); } void Graphics::cleanupSwapChain() @@ -3087,8 +3098,11 @@ void Graphics::cleanupSwapChain() vmaDestroyBuffer(vmaAllocator, readbackBuffer.buffer, readbackBuffer.allocation); vmaDestroyImage(vmaAllocator, readbackBuffer.image, readbackBuffer.imageAllocation); } - vkDestroyImageView(device, colorImageView, nullptr); - vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation); + if (colorImage) + { + vkDestroyImageView(device, colorImageView, nullptr); + vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation); + } vkDestroyImageView(device, depthImageView, nullptr); vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation); for (const auto &swapChainImageView : swapChainImageViews) diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 04161b9e8..7d90542b8 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -256,6 +256,14 @@ struct ScreenshotReadbackBuffer VmaAllocation imageAllocation; }; +enum SubmitMode +{ + SUBMIT_PRESENT, + SUBMIT_NOPRESENT, + SUBMIT_RESTART, + SUBMIT_MAXENUM, +}; + class Graphics final : public love::graphics::Graphics { public: @@ -300,12 +308,12 @@ public: // internal functions. - const VkDevice getDevice() const; - const VmaAllocator getVmaAllocator() const; + VkDevice getDevice() const; + VmaAllocator getVmaAllocator() const; VkCommandBuffer getCommandBufferForDataTransfer(); void queueCleanUp(std::function cleanUp); void addReadbackCallback(std::function callback); - void submitGpuCommands(bool present, void *screenshotCallbackData = nullptr); + void submitGpuCommands(SubmitMode, void *screenshotCallbackData = nullptr); const VkDeviceSize getMinUniformBufferOffsetAlignment() const; VkSampler getCachedSampler(const SamplerState &sampler); void setComputeShader(Shader *computeShader); @@ -326,7 +334,6 @@ protected: void setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) override; private: - void createVulkanInstance(); bool checkValidationSupport(); void pickPhysicalDevice(); int rateDeviceSuitability(VkPhysicalDevice device); diff --git a/src/modules/graphics/vulkan/GraphicsReadback.cpp b/src/modules/graphics/vulkan/GraphicsReadback.cpp index 51a8a01b8..257a3b219 100644 --- a/src/modules/graphics/vulkan/GraphicsReadback.cpp +++ b/src/modules/graphics/vulkan/GraphicsReadback.cpp @@ -44,7 +44,7 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod if (method == READBACK_IMMEDIATE) { - vgfx->submitGpuCommands(false); + vgfx->submitGpuCommands(SUBMIT_RESTART); if (stagingBuffer.get()) { status = readbackBuffer(stagingBuffer, 0, size); gfx->releaseTemporaryBuffer(stagingBuffer); @@ -79,7 +79,7 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod }); if (method == READBACK_IMMEDIATE) - vgfx->submitGpuCommands(false); + vgfx->submitGpuCommands(SUBMIT_RESTART); } GraphicsReadback::~GraphicsReadback() @@ -89,7 +89,7 @@ GraphicsReadback::~GraphicsReadback() void GraphicsReadback::wait() { if (status == STATUS_WAITING) - vgfx->submitGpuCommands(false); + vgfx->submitGpuCommands(SUBMIT_RESTART); } void GraphicsReadback::update() From 51d5b4851566e1f82ab625c841b3b106ef90b869 Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 9 Oct 2023 15:32:17 +0200 Subject: [PATCH 16/36] vulkan: fix incorrect device extension --- src/modules/graphics/vulkan/Graphics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 2432dad27..3fddecbce 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1588,7 +1588,7 @@ static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, Option optionalDeviceExtensions.memoryRequirements2 = true; if (strcmp(extension.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0) optionalDeviceExtensions.dedicatedAllocation = true; - if (strcmp(extension.extensionName, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) == 0) + if (strcmp(extension.extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0) optionalDeviceExtensions.memoryBudget = true; if (strcmp(extension.extensionName, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME) == 0) optionalDeviceExtensions.shaderFloatControls = true; From 21182d1428c681d138783b94fac903b67fd56bc9 Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 9 Oct 2023 16:04:25 +0200 Subject: [PATCH 17/36] vulkan: fix memory leak --- src/modules/graphics/vulkan/Graphics.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 3fddecbce..b51db2154 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -151,6 +151,7 @@ Graphics::Graphics() Graphics::~Graphics() { + defaultConstantTexCoord.set(nullptr); defaultConstantColor.set(nullptr); defaultTexture.set(nullptr); From cf26e39d1b0d7a075bfc7b060a78e67b69bdb5f0 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Mon, 9 Oct 2023 13:13:37 -0300 Subject: [PATCH 18/36] vulkan: potential fix for compressed textures with mipmaps --- src/modules/graphics/vulkan/Texture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index 60c55b9a8..6ae53c1c1 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -150,7 +150,7 @@ bool Texture::loadVolatile() createTextureImageView(); textureSampler = vgfx->getCachedSampler(samplerState); - if (!isPixelFormatDepthStencil(format) && mipmapCount > 1 && getMipmapsMode() != MIPMAPS_NONE) + if (!isPixelFormatDepthStencil(format) && slices.getMipmapCount() <= 1 && getMipmapsMode() != MIPMAPS_NONE) generateMipmaps(); if (renderTarget) From 4787d500787f752b1922116f9d7dbee3f1d1520c Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Mon, 9 Oct 2023 14:10:24 -0300 Subject: [PATCH 19/36] opengl: fix color mask --- src/modules/graphics/opengl/Graphics.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 790afa564..a0d05f6ec 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1567,8 +1567,8 @@ void Graphics::setColorMask(ColorChannelMask mask) flushBatchedDraws(); uint32 maskbits = - ((mask.r ? 1 : 0) << 1) | ((mask.g ? 1 : 0) << 2) | - ((mask.g ? 1 : 0) << 3) | ((mask.a ? 1 : 0) << 4); + ((mask.r ? 1 : 0) << 0) | ((mask.g ? 1 : 0) << 1) | + ((mask.g ? 1 : 0) << 2) | ((mask.a ? 1 : 0) << 3); gl.setColorWriteMask(maskbits); states.back().colorMask = mask; From 88272c68558c1c0dc3af8b37a0157c62c45629da Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 9 Oct 2023 20:07:32 +0200 Subject: [PATCH 20/36] vulkan: correctly identify boolean uniforms --- src/modules/graphics/Shader.cpp | 10 +++++++++- src/modules/graphics/vulkan/Shader.cpp | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index f6c314420..5ace1031d 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -1010,8 +1010,16 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, values[i].u = convertData((*constarray)[i]); } break; - case glslang::EbtInt: case glslang::EbtBool: + u.dataType = DATA_BASETYPE_BOOL; + if (constarray != nullptr) + { + values.resize(constarray->size()); + for (int i = 0; i < constarray->size(); i++) + values[i].u = convertData((*constarray)[i]); + } + break; + case glslang::EbtInt: default: u.dataType = DATA_BASETYPE_INT; if (constarray != nullptr) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 3ad661164..932a4f7c8 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -614,6 +614,9 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross:: std::string name = basename + comp.get_member_name(type.self, uindex); + if (name == "Debug") + float x = 1.0f; + switch (memberType.basetype) { case SPIRType::Struct: @@ -656,6 +659,9 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross:: if (reflectionIt != validationReflection.localUniforms.end()) { const auto &localUniform = reflectionIt->second; + if (localUniform.dataType == DATA_BASETYPE_BOOL) + u.baseType = UNIFORM_BOOL; + const auto &values = localUniform.initializerValues; if (!values.empty()) memcpy( From 2749209fc7220d85d050b6cccc7a63a5da034d2e Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 9 Oct 2023 20:12:13 +0200 Subject: [PATCH 21/36] vulkan: fix crash when using wrong uniform name --- src/modules/graphics/vulkan/Shader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 932a4f7c8..086aad259 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -551,7 +551,8 @@ int Shader::getVertexAttributeIndex(const std::string &name) const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const { - return &uniformInfos.at(name); + const auto it = uniformInfos.find(name); + return it != uniformInfos.end() ? &(it->second) : nullptr; } const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const From 8958d155abbb7625b4783cad5e17f58cc750a66b Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Mon, 9 Oct 2023 15:13:03 -0300 Subject: [PATCH 22/36] opengl: Fix blue component of love.graphics.setColorMask --- src/modules/graphics/opengl/Graphics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index a0d05f6ec..50f0a3e79 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1568,7 +1568,7 @@ void Graphics::setColorMask(ColorChannelMask mask) uint32 maskbits = ((mask.r ? 1 : 0) << 0) | ((mask.g ? 1 : 0) << 1) | - ((mask.g ? 1 : 0) << 2) | ((mask.a ? 1 : 0) << 3); + ((mask.b ? 1 : 0) << 2) | ((mask.a ? 1 : 0) << 3); gl.setColorWriteMask(maskbits); states.back().colorMask = mask; From 5dc7b7d05b4783af0081a5fdf516dfe7161390e6 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Mon, 9 Oct 2023 15:13:47 -0300 Subject: [PATCH 23/36] remove some redundant OpenGL API calls when clearing Canvases --- src/modules/graphics/opengl/OpenGL.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index df3a0b9b8..ad8a4b66e 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -98,31 +98,31 @@ OpenGL::CleanClearState::CleanClearState(GLbitfield clearFlags) , depthWrites(gl.hasDepthWrites()) , scissor(gl.isStateEnabled(ENABLE_SCISSOR_TEST)) { - if (clearFlags & GL_COLOR_BUFFER_BIT) + if ((clearFlags & GL_COLOR_BUFFER_BIT) != 0 && colorWriteMask != LOVE_UINT32_MAX) gl.setColorWriteMask(LOVE_UINT32_MAX); - if (clearFlags & GL_DEPTH_BUFFER_BIT) + if ((clearFlags & GL_DEPTH_BUFFER_BIT) != 0 && depthWrites) gl.setDepthWrites(false); - if (clearFlags & GL_STENCIL_BUFFER_BIT) + if ((clearFlags & GL_STENCIL_BUFFER_BIT) != 0 && (stencilWriteMask & 0xFF) != 0xFF) gl.setStencilWriteMask(LOVE_UINT32_MAX); - if (clearFlags != 0) + if (clearFlags != 0 && scissor) gl.setEnableState(ENABLE_SCISSOR_TEST, false); } OpenGL::CleanClearState::~CleanClearState() { - if (clearFlags & GL_COLOR_BUFFER_BIT) + if ((clearFlags & GL_COLOR_BUFFER_BIT) != 0 && colorWriteMask != LOVE_UINT32_MAX) gl.setColorWriteMask(colorWriteMask); - if (clearFlags & GL_DEPTH_BUFFER_BIT) + if ((clearFlags & GL_DEPTH_BUFFER_BIT) != 0 && depthWrites) gl.setDepthWrites(depthWrites); - if (clearFlags & GL_STENCIL_BUFFER_BIT) + if ((clearFlags & GL_STENCIL_BUFFER_BIT) != 0 && (stencilWriteMask & 0xFF) != 0xFF) gl.setStencilWriteMask(stencilWriteMask); - if (clearFlags != 0) + if (clearFlags != 0 && scissor) gl.setEnableState(ENABLE_SCISSOR_TEST, scissor); } From 88f6bb880e4c9bdd4f44590700e15be81f980e10 Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 9 Oct 2023 20:16:01 +0200 Subject: [PATCH 24/36] remove debug code --- src/modules/graphics/vulkan/Shader.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 086aad259..473623f42 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -615,9 +615,6 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross:: std::string name = basename + comp.get_member_name(type.self, uindex); - if (name == "Debug") - float x = 1.0f; - switch (memberType.basetype) { case SPIRType::Struct: From 86eb6df05c7f72c63384c1df27f456f87bdaf6f0 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Mon, 9 Oct 2023 20:22:04 -0300 Subject: [PATCH 25/36] vulkan: don't hold onto ImageData references after loading an image. Reduces CPU memory usage. --- src/modules/graphics/vulkan/Texture.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index 6ae53c1c1..8a979789c 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -41,6 +41,10 @@ Texture::Texture(love::graphics::Graphics *gfx, const Settings &settings, const slices = *data; loadVolatile(); + + // ImageData is referenced by the first loadVolatile call, but we don't + // hang on to it after that so we can save memory. + slices.clear(); } bool Texture::loadVolatile() From ba693500c439b7bf5d7b9bb2f8b34d7331793453 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Wed, 11 Oct 2023 22:05:33 -0300 Subject: [PATCH 26/36] Fix love.font.newBMFontRasterizer when it's given a single file param. --- src/modules/font/wrap_Font.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/font/wrap_Font.cpp b/src/modules/font/wrap_Font.cpp index 1ed3149a1..ffbb720fe 100644 --- a/src/modules/font/wrap_Font.cpp +++ b/src/modules/font/wrap_Font.cpp @@ -154,7 +154,7 @@ int w_newBMFontRasterizer(lua_State *L) lua_pop(L, 1); } } - else + else if (!lua_isnoneornil(L, 2)) { convimagedata(L, 2); image::ImageData *id = luax_checktype(L, 2); From 0b0bef31add03f6bd68c5ba029fb31fb498743a3 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Thu, 12 Oct 2023 13:33:28 +0800 Subject: [PATCH 27/36] Linux: Install libcurl4-openssl-dev before building. --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 50c0236c1..f3922d769 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,8 @@ jobs: libxfixes-dev libxi-dev libxinerama-dev libxxf86vm-dev libxss-dev \ libgl1-mesa-dev libdbus-1-dev libudev-dev libgles2-mesa-dev \ libegl1-mesa-dev libibus-1.0-dev fcitx-libs-dev libsamplerate0-dev \ - libsndio-dev libwayland-dev libxkbcommon-dev libdrm-dev libgbm-dev + libsndio-dev libwayland-dev libxkbcommon-dev libdrm-dev libgbm-dev \ + libcurl4-openssl-dev - name: Checkout love-appimage-source uses: actions/checkout@v3 with: From 386586835851c586c5482b73898b5eb7249d7670 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Fri, 13 Oct 2023 21:41:32 -0300 Subject: [PATCH 28/36] Fix creating a linear rgba8 canvas when gamma correct rendering is on. Fixes #1973 --- src/modules/graphics/Texture.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index e9b7ab1f7..d70bf1d8b 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -168,7 +168,7 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) , computeWrite(settings.computeWrite) , readable(true) , mipmapsMode(settings.mipmaps) - , sRGB(isGammaCorrect() && !settings.linear) + , sRGB(false) , width(settings.width) , height(settings.height) , depth(settings.type == TEXTURE_VOLUME ? settings.layers : 1) @@ -204,7 +204,7 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) love::image::ImageDataBase *slice = slices->get(0, 0); format = slice->getFormat(); - if (sRGB) + if (isGammaCorrect() && !settings.linear) format = getSRGBPixelFormat(format); pixelWidth = slice->getWidth(); @@ -236,6 +236,7 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) readable = !renderTarget || !isPixelFormatDepthStencil(format); format = gfx->getSizedFormat(format, renderTarget, readable); + sRGB = isPixelFormatSRGB(format) || (isCompressed() && isGammaCorrect() && !settings.linear); if (mipmapsMode == MIPMAPS_AUTO && isCompressed()) mipmapsMode = MIPMAPS_MANUAL; From 983ea6c0e6885b169e2c89ad145fc1c6a220f931 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Fri, 13 Oct 2023 21:53:45 -0300 Subject: [PATCH 29/36] Remove explicit support for systems that don't support rgba8 canvases. This is just a very small number of really old OpenGL ES 2 drivers. --- src/modules/graphics/Graphics.cpp | 16 ++++++++++++ src/modules/graphics/Graphics.h | 2 +- src/modules/graphics/Texture.cpp | 2 +- src/modules/graphics/metal/Graphics.h | 1 - src/modules/graphics/metal/Graphics.mm | 23 ++---------------- src/modules/graphics/opengl/Graphics.cpp | 31 ++---------------------- src/modules/graphics/opengl/Graphics.h | 1 - src/modules/graphics/vulkan/Graphics.cpp | 21 +--------------- src/modules/graphics/vulkan/Graphics.h | 1 - 9 files changed, 23 insertions(+), 75 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 098c886cc..be2b979e0 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -2389,6 +2389,22 @@ const Graphics::Capabilities &Graphics::getCapabilities() const return capabilities; } +PixelFormat Graphics::getSizedFormat(PixelFormat format) const +{ + switch (format) + { + case PIXELFORMAT_NORMAL: + if (isGammaCorrect()) + return PIXELFORMAT_RGBA8_UNORM_sRGB; + else + return PIXELFORMAT_RGBA8_UNORM; + case PIXELFORMAT_HDR: + return PIXELFORMAT_RGBA16_FLOAT; + default: + return format; + } +} + Graphics::Stats Graphics::getStats() const { Stats stats; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 456e5d28f..f9a51eab3 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -819,7 +819,7 @@ public: /** * Converts PIXELFORMAT_NORMAL and PIXELFORMAT_HDR into a real format. **/ - virtual PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const = 0; + PixelFormat getSizedFormat(PixelFormat format) const; /** * Gets whether the specified pixel format usage is supported. diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index d70bf1d8b..5cda31dae 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -235,7 +235,7 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) else readable = !renderTarget || !isPixelFormatDepthStencil(format); - format = gfx->getSizedFormat(format, renderTarget, readable); + format = gfx->getSizedFormat(format); sRGB = isPixelFormatSRGB(format) || (isCompressed() && isGammaCorrect() && !settings.linear); if (mipmapsMode == MIPMAPS_AUTO && isCompressed()) diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index ab2e8fc2b..ea8894f4c 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -110,7 +110,6 @@ public: void setWireframe(bool enable) override; - PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override; bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override; Renderer getRenderer() const override; bool usesGLSLES() const override; diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index f07433cd6..ca6c76b82 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -1864,28 +1864,9 @@ void Graphics::setWireframe(bool enable) } } -PixelFormat Graphics::getSizedFormat(PixelFormat format, bool /*rendertarget*/, bool /*readable*/) const -{ - switch (format) - { - case PIXELFORMAT_NORMAL: - if (isGammaCorrect()) - return PIXELFORMAT_RGBA8_UNORM_sRGB; - else - return PIXELFORMAT_RGBA8_UNORM; - case PIXELFORMAT_HDR: - return PIXELFORMAT_RGBA16_FLOAT; - default: - return format; - } -} - bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) { - bool rendertarget = (usage & PIXELFORMATUSAGEFLAGS_RENDERTARGET) != 0; - bool readable = (usage & PIXELFORMATUSAGEFLAGS_SAMPLE) != 0; - - format = getSizedFormat(format, rendertarget, readable); + format = getSizedFormat(format); if (sRGB) format = getSRGBPixelFormat(format); @@ -1902,7 +1883,7 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG uint32 flags = PIXELFORMATUSAGEFLAGS_NONE; - if (isPixelFormatCompressed(format) && rendertarget) + if (isPixelFormatCompressed(format) && (usage & rt) != 0) return false; // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 50f0a3e79..651978742 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1734,31 +1734,6 @@ void Graphics::initCapabilities() } } -PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const -{ - uint32 requiredflags = 0; - if (rendertarget) - requiredflags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET; - if (readable) - requiredflags |= PIXELFORMATUSAGEFLAGS_SAMPLE; - - switch (format) - { - case PIXELFORMAT_NORMAL: - if (isGammaCorrect()) - return PIXELFORMAT_RGBA8_UNORM_sRGB; - else if ((OpenGL::getPixelFormatUsageFlags(PIXELFORMAT_RGBA8_UNORM) & requiredflags) != requiredflags) - // 32-bit render targets don't have guaranteed support on GLES2. - return PIXELFORMAT_RGBA4_UNORM; - else - return PIXELFORMAT_RGBA8_UNORM; - case PIXELFORMAT_HDR: - return PIXELFORMAT_RGBA16_FLOAT; - default: - return format; - } -} - uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable) { uint32 usage = OpenGL::getPixelFormatUsageFlags(format); @@ -1844,11 +1819,9 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG if (sRGB) format = getSRGBPixelFormat(format); - bool rendertarget = (usage & PIXELFORMATUSAGEFLAGS_RENDERTARGET) != 0; + format = getSizedFormat(format); + bool readable = (usage & PIXELFORMATUSAGEFLAGS_SAMPLE) != 0; - - format = getSizedFormat(format, rendertarget, readable); - return (usage & pixelFormatUsage[format][readable ? 1 : 0]) == usage; } diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 997239c15..d27c96791 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -106,7 +106,6 @@ public: void setWireframe(bool enable) override; - PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override; bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override; Renderer getRenderer() const override; bool usesGLSLES() const override; diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index b51db2154..39228f335 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1057,28 +1057,9 @@ void Graphics::setWireframe(bool enable) states.back().wireframe = enable; } -PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const -{ - switch (format) - { - case PIXELFORMAT_NORMAL: - if (isGammaCorrect()) - return PIXELFORMAT_RGBA8_UNORM_sRGB; - else - return PIXELFORMAT_RGBA8_UNORM; - case PIXELFORMAT_HDR: - return PIXELFORMAT_RGBA16_FLOAT; - default: - return format; - } -} - bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) { - bool rendertarget = (usage & PIXELFORMATUSAGEFLAGS_RENDERTARGET) != 0; - bool readable = (usage & PIXELFORMATUSAGEFLAGS_SAMPLE) != 0; - - format = getSizedFormat(format, rendertarget, readable); + format = getSizedFormat(format); auto vulkanFormat = Vulkan::getTextureFormat(format, sRGB); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 7d90542b8..69ae238b5 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -297,7 +297,6 @@ public: void setBlendState(const BlendState &blend) override; void setPointSize(float size) override; void setWireframe(bool enable) override; - PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override; bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) override; Renderer getRenderer() const override; bool usesGLSLES() const override; From 9eec1754e76d150067d02787a18a912b9e7d3132 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 14 Oct 2023 10:30:51 -0300 Subject: [PATCH 30/36] opengl: fix clearing the depth buffer. --- src/modules/graphics/opengl/OpenGL.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index ad8a4b66e..9166b8c9f 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -101,8 +101,8 @@ OpenGL::CleanClearState::CleanClearState(GLbitfield clearFlags) if ((clearFlags & GL_COLOR_BUFFER_BIT) != 0 && colorWriteMask != LOVE_UINT32_MAX) gl.setColorWriteMask(LOVE_UINT32_MAX); - if ((clearFlags & GL_DEPTH_BUFFER_BIT) != 0 && depthWrites) - gl.setDepthWrites(false); + if ((clearFlags & GL_DEPTH_BUFFER_BIT) != 0 && !depthWrites) + gl.setDepthWrites(true); if ((clearFlags & GL_STENCIL_BUFFER_BIT) != 0 && (stencilWriteMask & 0xFF) != 0xFF) gl.setStencilWriteMask(LOVE_UINT32_MAX); @@ -116,7 +116,7 @@ OpenGL::CleanClearState::~CleanClearState() if ((clearFlags & GL_COLOR_BUFFER_BIT) != 0 && colorWriteMask != LOVE_UINT32_MAX) gl.setColorWriteMask(colorWriteMask); - if ((clearFlags & GL_DEPTH_BUFFER_BIT) != 0 && depthWrites) + if ((clearFlags & GL_DEPTH_BUFFER_BIT) != 0 && !depthWrites) gl.setDepthWrites(depthWrites); if ((clearFlags & GL_STENCIL_BUFFER_BIT) != 0 && (stencilWriteMask & 0xFF) != 0xFF) From 343d192f1008e0c46576d173154db55a6a607cdf Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 14 Oct 2023 15:01:01 -0300 Subject: [PATCH 31/36] Compressed texture formats have explicit sRGB variants --- src/common/pixelformat.cpp | 389 ++++++++++++++--------- src/common/pixelformat.h | 61 +++- src/modules/graphics/Graphics.cpp | 4 +- src/modules/graphics/Graphics.h | 2 +- src/modules/graphics/Texture.cpp | 8 +- src/modules/graphics/Texture.h | 2 - src/modules/graphics/metal/Graphics.h | 2 +- src/modules/graphics/metal/Graphics.mm | 66 ++-- src/modules/graphics/metal/Metal.h | 2 +- src/modules/graphics/metal/Metal.mm | 215 +++++++++---- src/modules/graphics/metal/Texture.mm | 2 +- src/modules/graphics/opengl/Graphics.cpp | 15 +- src/modules/graphics/opengl/Graphics.h | 2 +- src/modules/graphics/opengl/OpenGL.cpp | 328 ++++++++++++------- src/modules/graphics/opengl/OpenGL.h | 4 +- src/modules/graphics/opengl/Shader.cpp | 3 +- src/modules/graphics/opengl/Texture.cpp | 15 +- src/modules/graphics/vulkan/Graphics.cpp | 8 +- src/modules/graphics/vulkan/Graphics.h | 2 +- src/modules/graphics/vulkan/Texture.cpp | 6 +- src/modules/graphics/vulkan/Vulkan.cpp | 167 +++++++--- src/modules/graphics/vulkan/Vulkan.h | 2 +- src/modules/graphics/wrap_Graphics.cpp | 13 +- src/modules/image/magpie/ASTCHandler.cpp | 28 +- src/modules/image/magpie/KTXHandler.cpp | 28 +- src/modules/image/magpie/PVRHandler.cpp | 28 +- 26 files changed, 890 insertions(+), 512 deletions(-) diff --git a/src/common/pixelformat.cpp b/src/common/pixelformat.cpp index fad2611e7..42325510f 100644 --- a/src/common/pixelformat.cpp +++ b/src/common/pixelformat.cpp @@ -26,101 +26,126 @@ namespace love static PixelFormatInfo formatInfo[] = { - // components, blockW, blockH, blockSize, color, depth, stencil, compressed, dataType - { 0, 1, 1, 0, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_UNKNOWN + // components, blockW, blockH, blockSize, color, depth, stencil, compressed, sRGB, dataType + { 0, 1, 1, 0, false, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_UNKNOWN - { 0, 1, 1, 0, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_NORMAL - { 0, 1, 1, 0, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_HDR + { 0, 1, 1, 0, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_NORMAL + { 0, 1, 1, 0, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_HDR - { 1, 1, 1, 1, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_R8_UNORM - { 1, 1, 1, 1, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R8_INT - { 1, 1, 1, 1, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R8_UINT - { 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_R16_UNORM - { 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_R16_FLOAT - { 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R16_INT - { 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R16_UINT - { 1, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_R32_FLOAT - { 1, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R32_INT - { 1, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R32_UINT + { 1, 1, 1, 1, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_R8_UNORM + { 1, 1, 1, 1, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R8_INT + { 1, 1, 1, 1, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R8_UINT + { 1, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_R16_UNORM + { 1, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_R16_FLOAT + { 1, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R16_INT + { 1, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R16_UINT + { 1, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_R32_FLOAT + { 1, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R32_INT + { 1, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R32_UINT - { 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RG8_UNORM - { 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG8_INT - { 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG8_UINT - { 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_LA8_UNORM - { 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RG16_UNORM - { 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RG16_FLOAT - { 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG16_INT - { 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG16_UINT - { 2, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RG32_FLOAT - { 2, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG32_INT - { 2, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG32_UINT + { 2, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RG8_UNORM + { 2, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG8_INT + { 2, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG8_UINT + { 2, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_LA8_UNORM + { 2, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RG16_UNORM + { 2, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RG16_FLOAT + { 2, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG16_INT + { 2, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG16_UINT + { 2, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RG32_FLOAT + { 2, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG32_INT + { 2, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG32_UINT - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA8_UNORM - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA8_UNORM_sRGB - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BGRA8_UNORM - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BGRA8_UNORM_sRGB - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA8_INT - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA8_UINT - { 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA16_UNORM - { 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RGBA16_FLOAT - { 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA16_INT - { 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA16_UINT - { 4, 1, 1, 16, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RGBA32_FLOAT - { 4, 1, 1, 16, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA32_INT - { 4, 1, 1, 16, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA32_UINT + { 4, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA8_UNORM + { 4, 1, 1, 4, true, false, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA8_sRGB + { 4, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BGRA8_UNORM + { 4, 1, 1, 4, true, false, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BGRA8_sRGB + { 4, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA8_INT + { 4, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA8_UINT + { 4, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA16_UNORM + { 4, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RGBA16_FLOAT + { 4, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA16_INT + { 4, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA16_UINT + { 4, 1, 1, 16, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RGBA32_FLOAT + { 4, 1, 1, 16, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA32_INT + { 4, 1, 1, 16, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA32_UINT - { 4, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA4_UNORM - { 4, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB5A1_UNORM - { 3, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB565_UNORM - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB10A2_UNORM - { 3, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UFLOAT }, // PIXELFORMAT_RG11B10_FLOAT + { 4, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA4_UNORM + { 4, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB5A1_UNORM + { 3, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB565_UNORM + { 4, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB10A2_UNORM + { 3, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UFLOAT }, // PIXELFORMAT_RG11B10_FLOAT - { 1, 1, 1, 1, false, false, true , false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_STENCIL8 - { 1, 1, 1, 2, false, true, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH16_UNORM - { 1, 1, 1, 3, false, true, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH24_UNORM - { 1, 1, 1, 4, false, true, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_DEPTH32_FLOAT - { 2, 1, 1, 4, false, true, true , false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH24_UNORM_STENCIL8 - { 2, 1, 1, 5, false, true, true , false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_DEPTH32_FLOAT_STENCIL8 + { 1, 1, 1, 1, false, false, true , false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_STENCIL8 + { 1, 1, 1, 2, false, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH16_UNORM + { 1, 1, 1, 3, false, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH24_UNORM + { 1, 1, 1, 4, false, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_DEPTH32_FLOAT + { 2, 1, 1, 4, false, true, true , false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH24_UNORM_STENCIL8 + { 2, 1, 1, 5, false, true, true , false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_DEPTH32_FLOAT_STENCIL8 - { 3, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT1_UNORM - { 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT3_UNORM - { 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT5_UNORM - { 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC4_UNORM - { 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_BC4_SNORM - { 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC5_UNORM - { 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_BC5_SNORM - { 3, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UFLOAT }, // PIXELFORMAT_BC6H_UFLOAT - { 3, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_BC6H_FLOAT - { 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC7_UNORM + { 3, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT1_UNORM + { 3, 4, 4, 8, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT1_sRGB + { 4, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT3_UNORM + { 4, 4, 4, 16, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT3_sRGB + { 4, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT5_UNORM + { 4, 4, 4, 16, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT5_sRGB + { 1, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC4_UNORM + { 1, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_BC4_SNORM + { 2, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC5_UNORM + { 2, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_BC5_SNORM + { 3, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UFLOAT }, // PIXELFORMAT_BC6H_UFLOAT + { 3, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_BC6H_FLOAT + { 4, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC7_UNORM + { 4, 4, 4, 16, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC7_sRGB - { 3, 16, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB2_UNORM - { 3, 8, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB4_UNORM - { 4, 16, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA2_UNORM - { 4, 8, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA4_UNORM + { 3, 16, 8, 32, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB2_UNORM + { 3, 16, 8, 32, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB2_sRGB + { 3, 8, 8, 32, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB4_UNORM + { 3, 8, 8, 32, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB4_sRGB + { 4, 16, 8, 32, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA2_UNORM + { 4, 16, 8, 32, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA2_sRGB + { 4, 8, 8, 32, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA4_UNORM + { 4, 8, 8, 32, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA4_sRGB - { 3, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC1_UNORM - { 3, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGB_UNORM - { 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA_UNORM - { 4, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA1_UNORM - { 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_EAC_R_UNORM - { 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_EAC_R_SNORM - { 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_EAC_RG_UNORM - { 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_EAC_RG_SNORM + { 3, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC1_UNORM + { 3, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGB_UNORM + { 3, 4, 4, 8, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGB_sRGB + { 4, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA_UNORM + { 4, 4, 4, 16, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA_sRGB + { 4, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA1_UNORM + { 4, 4, 4, 8, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA1_sRGB + { 1, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_EAC_R_UNORM + { 1, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_EAC_R_SNORM + { 2, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_EAC_RG_UNORM + { 2, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_EAC_RG_SNORM - { 4, 4, 4, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_4x4 - { 4, 5, 4, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x4 - { 4, 5, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x5 - { 4, 6, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x5 - { 4, 6, 6, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x6 - { 4, 8, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x5 - { 4, 8, 6, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x6 - { 4, 8, 8, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x8 - { 4, 8, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x5 - { 4, 10, 6, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x6 - { 4, 10, 8, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x8 - { 4, 10, 10, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x10 - { 4, 12, 10, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x10 - { 4, 12, 12, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x12 + { 4, 4, 4, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_4x4_UNORM + { 4, 5, 4, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x4_UNORM + { 4, 5, 5, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x5_UNORM + { 4, 6, 5, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x5_UNORM + { 4, 6, 6, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x6_UNORM + { 4, 8, 5, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x5_UNORM + { 4, 8, 6, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x6_UNORM + { 4, 8, 8, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x8_UNORM + { 4, 8, 5, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x5_UNORM + { 4, 10, 6, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x6_UNORM + { 4, 10, 8, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x8_UNORM + { 4, 10, 10, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x10_UNORM + { 4, 12, 10, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x10_UNORM + { 4, 12, 12, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x12_UNORM + { 4, 4, 4, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_4x4_sRGB + { 4, 5, 4, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x4_sRGB + { 4, 5, 5, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x5_sRGB + { 4, 6, 5, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x5_sRGB + { 4, 6, 6, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x6_sRGB + { 4, 8, 5, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x5_sRGB + { 4, 8, 6, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x6_sRGB + { 4, 8, 8, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x8_sRGB + { 4, 8, 5, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x5_sRGB + { 4, 10, 6, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x6_sRGB + { 4, 10, 8, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x8_sRGB + { 4, 10, 10, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x10_sRGB + { 4, 12, 10, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x10_sRGB + { 4, 12, 12, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x12_sRGB }; static_assert(sizeof(formatInfo) / sizeof(PixelFormatInfo) == PIXELFORMAT_MAX_ENUM, "Update the formatInfo array when adding or removing a PixelFormat"); @@ -155,19 +180,19 @@ static StringMap::Entry formatEntries[] = { "rg32i", PIXELFORMAT_RG32_INT }, { "rg32ui", PIXELFORMAT_RG32_UINT }, - { "rgba8", PIXELFORMAT_RGBA8_UNORM }, - { "srgba8", PIXELFORMAT_RGBA8_UNORM_sRGB }, - { "bgra8", PIXELFORMAT_BGRA8_UNORM }, - { "bgra8srgb", PIXELFORMAT_BGRA8_UNORM_sRGB }, - { "rgba8i", PIXELFORMAT_RGBA8_INT }, - { "rgba8ui", PIXELFORMAT_RGBA8_UINT }, - { "rgba16", PIXELFORMAT_RGBA16_UNORM }, - { "rgba16f", PIXELFORMAT_RGBA16_FLOAT }, - { "rgba16i", PIXELFORMAT_RGBA16_INT }, - { "rgba16ui", PIXELFORMAT_RGBA16_UINT }, - { "rgba32f", PIXELFORMAT_RGBA32_FLOAT }, - { "rgba32i", PIXELFORMAT_RGBA32_INT }, - { "rgba32ui", PIXELFORMAT_RGBA32_UINT }, + { "rgba8", PIXELFORMAT_RGBA8_UNORM }, + { "srgba8", PIXELFORMAT_RGBA8_sRGB }, + { "bgra8", PIXELFORMAT_BGRA8_UNORM }, + { "bgra8srgb", PIXELFORMAT_BGRA8_sRGB }, + { "rgba8i", PIXELFORMAT_RGBA8_INT }, + { "rgba8ui", PIXELFORMAT_RGBA8_UINT }, + { "rgba16", PIXELFORMAT_RGBA16_UNORM }, + { "rgba16f", PIXELFORMAT_RGBA16_FLOAT }, + { "rgba16i", PIXELFORMAT_RGBA16_INT }, + { "rgba16ui", PIXELFORMAT_RGBA16_UINT }, + { "rgba32f", PIXELFORMAT_RGBA32_FLOAT }, + { "rgba32i", PIXELFORMAT_RGBA32_INT }, + { "rgba32ui", PIXELFORMAT_RGBA32_UINT }, { "rgba4", PIXELFORMAT_RGBA4_UNORM }, { "rgb5a1", PIXELFORMAT_RGB5A1_UNORM }, @@ -182,43 +207,70 @@ static StringMap::Entry formatEntries[] = { "depth24stencil8", PIXELFORMAT_DEPTH24_UNORM_STENCIL8 }, { "depth32fstencil8", PIXELFORMAT_DEPTH32_FLOAT_STENCIL8 }, - { "DXT1", PIXELFORMAT_DXT1_UNORM }, - { "DXT3", PIXELFORMAT_DXT3_UNORM }, - { "DXT5", PIXELFORMAT_DXT5_UNORM }, - { "BC4", PIXELFORMAT_BC4_UNORM }, - { "BC4s", PIXELFORMAT_BC4_SNORM }, - { "BC5", PIXELFORMAT_BC5_UNORM }, - { "BC5s", PIXELFORMAT_BC5_SNORM }, - { "BC6h", PIXELFORMAT_BC6H_UFLOAT }, - { "BC6hs", PIXELFORMAT_BC6H_FLOAT }, - { "BC7", PIXELFORMAT_BC7_UNORM }, - { "PVR1rgb2", PIXELFORMAT_PVR1_RGB2_UNORM }, - { "PVR1rgb4", PIXELFORMAT_PVR1_RGB4_UNORM }, - { "PVR1rgba2", PIXELFORMAT_PVR1_RGBA2_UNORM }, - { "PVR1rgba4", PIXELFORMAT_PVR1_RGBA4_UNORM }, - { "ETC1", PIXELFORMAT_ETC1_UNORM }, - { "ETC2rgb", PIXELFORMAT_ETC2_RGB_UNORM }, - { "ETC2rgba", PIXELFORMAT_ETC2_RGBA_UNORM }, - { "ETC2rgba1", PIXELFORMAT_ETC2_RGBA1_UNORM }, - { "EACr", PIXELFORMAT_EAC_R_UNORM }, - { "EACrs", PIXELFORMAT_EAC_R_SNORM }, - { "EACrg", PIXELFORMAT_EAC_RG_UNORM }, - { "EACrgs", PIXELFORMAT_EAC_RG_SNORM }, + { "DXT1", PIXELFORMAT_DXT1_UNORM }, + { "DXT1srgb", PIXELFORMAT_DXT1_sRGB }, + { "DXT3", PIXELFORMAT_DXT3_UNORM }, + { "DXT3srgb", PIXELFORMAT_DXT3_sRGB }, + { "DXT5", PIXELFORMAT_DXT5_UNORM }, + { "DXT5srgb", PIXELFORMAT_DXT5_sRGB }, + { "BC4", PIXELFORMAT_BC4_UNORM }, + { "BC4s", PIXELFORMAT_BC4_SNORM }, + { "BC5", PIXELFORMAT_BC5_UNORM }, + { "BC5s", PIXELFORMAT_BC5_SNORM }, + { "BC6h", PIXELFORMAT_BC6H_UFLOAT }, + { "BC6hs", PIXELFORMAT_BC6H_FLOAT }, + { "BC7", PIXELFORMAT_BC7_UNORM }, + { "BC7srgb", PIXELFORMAT_BC7_sRGB }, - { "ASTC4x4", PIXELFORMAT_ASTC_4x4 }, - { "ASTC5x4", PIXELFORMAT_ASTC_5x4 }, - { "ASTC5x5", PIXELFORMAT_ASTC_5x5 }, - { "ASTC6x5", PIXELFORMAT_ASTC_6x5 }, - { "ASTC6x6", PIXELFORMAT_ASTC_6x6 }, - { "ASTC8x5", PIXELFORMAT_ASTC_8x5 }, - { "ASTC8x6", PIXELFORMAT_ASTC_8x6 }, - { "ASTC8x8", PIXELFORMAT_ASTC_8x8 }, - { "ASTC10x5", PIXELFORMAT_ASTC_10x5 }, - { "ASTC10x6", PIXELFORMAT_ASTC_10x6 }, - { "ASTC10x8", PIXELFORMAT_ASTC_10x8 }, - { "ASTC10x10", PIXELFORMAT_ASTC_10x10 }, - { "ASTC12x10", PIXELFORMAT_ASTC_12x10 }, - { "ASTC12x12", PIXELFORMAT_ASTC_12x12 }, + { "PVR1rgb2", PIXELFORMAT_PVR1_RGB2_UNORM }, + { "PVR1rgb2srgb", PIXELFORMAT_PVR1_RGB2_sRGB }, + { "PVR1rgb4", PIXELFORMAT_PVR1_RGB4_UNORM }, + { "PVR1rgb4srgb", PIXELFORMAT_PVR1_RGB4_sRGB }, + { "PVR1rgba2", PIXELFORMAT_PVR1_RGBA2_UNORM }, + { "PVR1rgba2srgb", PIXELFORMAT_PVR1_RGBA2_sRGB }, + { "PVR1rgba4", PIXELFORMAT_PVR1_RGBA4_UNORM }, + { "PVR1rgba4srgb", PIXELFORMAT_PVR1_RGBA4_sRGB }, + + { "ETC1", PIXELFORMAT_ETC1_UNORM }, + { "ETC2rgb", PIXELFORMAT_ETC2_RGB_UNORM }, + { "ETC2srgb", PIXELFORMAT_ETC2_RGB_sRGB }, + { "ETC2rgba", PIXELFORMAT_ETC2_RGBA_UNORM }, + { "ETC2srgba", PIXELFORMAT_ETC2_RGBA_sRGB }, + { "ETC2rgba1", PIXELFORMAT_ETC2_RGBA1_UNORM }, + { "ETC2srgba1", PIXELFORMAT_ETC2_RGBA1_sRGB }, + { "EACr", PIXELFORMAT_EAC_R_UNORM }, + { "EACrs", PIXELFORMAT_EAC_R_SNORM }, + { "EACrg", PIXELFORMAT_EAC_RG_UNORM }, + { "EACrgs", PIXELFORMAT_EAC_RG_SNORM }, + + { "ASTC4x4", PIXELFORMAT_ASTC_4x4_UNORM }, + { "ASTC5x4", PIXELFORMAT_ASTC_5x4_UNORM }, + { "ASTC5x5", PIXELFORMAT_ASTC_5x5_UNORM }, + { "ASTC6x5", PIXELFORMAT_ASTC_6x5_UNORM }, + { "ASTC6x6", PIXELFORMAT_ASTC_6x6_UNORM }, + { "ASTC8x5", PIXELFORMAT_ASTC_8x5_UNORM }, + { "ASTC8x6", PIXELFORMAT_ASTC_8x6_UNORM }, + { "ASTC8x8", PIXELFORMAT_ASTC_8x8_UNORM }, + { "ASTC10x5", PIXELFORMAT_ASTC_10x5_UNORM }, + { "ASTC10x6", PIXELFORMAT_ASTC_10x6_UNORM }, + { "ASTC10x8", PIXELFORMAT_ASTC_10x8_UNORM }, + { "ASTC10x10", PIXELFORMAT_ASTC_10x10_UNORM }, + { "ASTC12x10", PIXELFORMAT_ASTC_12x10_UNORM }, + { "ASTC12x12", PIXELFORMAT_ASTC_12x12_UNORM }, + { "ASTC4x4srgb", PIXELFORMAT_ASTC_4x4_sRGB }, + { "ASTC5x4srgb", PIXELFORMAT_ASTC_5x4_sRGB }, + { "ASTC5x5srgb", PIXELFORMAT_ASTC_5x5_sRGB }, + { "ASTC6x5srgb", PIXELFORMAT_ASTC_6x5_sRGB }, + { "ASTC6x6srgb", PIXELFORMAT_ASTC_6x6_sRGB }, + { "ASTC8x5srgb", PIXELFORMAT_ASTC_8x5_sRGB }, + { "ASTC8x6srgb", PIXELFORMAT_ASTC_8x6_sRGB }, + { "ASTC8x8srgb", PIXELFORMAT_ASTC_8x8_sRGB }, + { "ASTC10x5srgb", PIXELFORMAT_ASTC_10x5_sRGB }, + { "ASTC10x6srgb", PIXELFORMAT_ASTC_10x6_sRGB }, + { "ASTC10x8srgb", PIXELFORMAT_ASTC_10x8_sRGB }, + { "ASTC10x10srgb", PIXELFORMAT_ASTC_10x10_sRGB }, + { "ASTC12x10srgb", PIXELFORMAT_ASTC_12x10_sRGB }, + { "ASTC12x12srgb", PIXELFORMAT_ASTC_12x12_sRGB }, }; static_assert(sizeof(formatEntries) / sizeof(formatEntries[0]) == (size_t) PIXELFORMAT_MAX_ENUM, "pixel format string map is missing entries!"); @@ -275,7 +327,7 @@ bool isPixelFormatStencil(PixelFormat format) bool isPixelFormatSRGB(PixelFormat format) { - return format == PIXELFORMAT_RGBA8_UNORM_sRGB || format == PIXELFORMAT_BGRA8_UNORM_sRGB; + return formatInfo[format].sRGB; } bool isPixelFormatInteger(PixelFormat format) @@ -286,19 +338,70 @@ bool isPixelFormatInteger(PixelFormat format) PixelFormat getSRGBPixelFormat(PixelFormat format) { - if (format == PIXELFORMAT_RGBA8_UNORM) - return PIXELFORMAT_RGBA8_UNORM_sRGB; - else if (format == PIXELFORMAT_BGRA8_UNORM) - return PIXELFORMAT_BGRA8_UNORM_sRGB; + switch (format) + { + case PIXELFORMAT_RGBA8_UNORM: return PIXELFORMAT_RGBA8_sRGB; + case PIXELFORMAT_BGRA8_UNORM: return PIXELFORMAT_BGRA8_sRGB; + case PIXELFORMAT_PVR1_RGB2_UNORM: return PIXELFORMAT_PVR1_RGB2_sRGB; + case PIXELFORMAT_PVR1_RGB4_UNORM: return PIXELFORMAT_PVR1_RGB4_sRGB; + case PIXELFORMAT_PVR1_RGBA2_UNORM: return PIXELFORMAT_PVR1_RGBA2_sRGB; + case PIXELFORMAT_PVR1_RGBA4_UNORM: return PIXELFORMAT_PVR1_RGBA4_sRGB; + case PIXELFORMAT_ETC1_UNORM: return PIXELFORMAT_ETC2_RGB_sRGB; // ETC2 can load ETC1 data. + case PIXELFORMAT_ETC2_RGB_UNORM: return PIXELFORMAT_ETC2_RGB_sRGB; + case PIXELFORMAT_ETC2_RGBA_UNORM: return PIXELFORMAT_ETC2_RGBA_sRGB; + case PIXELFORMAT_ETC2_RGBA1_UNORM: return PIXELFORMAT_ETC2_RGBA1_sRGB; + case PIXELFORMAT_ASTC_4x4_UNORM: return PIXELFORMAT_ASTC_4x4_sRGB; + case PIXELFORMAT_ASTC_5x4_UNORM: return PIXELFORMAT_ASTC_5x4_sRGB; + case PIXELFORMAT_ASTC_5x5_UNORM: return PIXELFORMAT_ASTC_5x5_sRGB; + case PIXELFORMAT_ASTC_6x5_UNORM: return PIXELFORMAT_ASTC_6x5_sRGB; + case PIXELFORMAT_ASTC_6x6_UNORM: return PIXELFORMAT_ASTC_6x6_sRGB; + case PIXELFORMAT_ASTC_8x5_UNORM: return PIXELFORMAT_ASTC_8x5_sRGB; + case PIXELFORMAT_ASTC_8x6_UNORM: return PIXELFORMAT_ASTC_8x6_sRGB; + case PIXELFORMAT_ASTC_8x8_UNORM: return PIXELFORMAT_ASTC_8x8_sRGB; + case PIXELFORMAT_ASTC_10x5_UNORM: return PIXELFORMAT_ASTC_10x5_sRGB; + case PIXELFORMAT_ASTC_10x6_UNORM: return PIXELFORMAT_ASTC_10x6_sRGB; + case PIXELFORMAT_ASTC_10x8_UNORM: return PIXELFORMAT_ASTC_10x8_sRGB; + case PIXELFORMAT_ASTC_10x10_UNORM: return PIXELFORMAT_ASTC_10x10_sRGB; + case PIXELFORMAT_ASTC_12x10_UNORM: return PIXELFORMAT_ASTC_12x10_sRGB; + case PIXELFORMAT_ASTC_12x12_UNORM: return PIXELFORMAT_ASTC_12x12_sRGB; + default: + break; + } + return format; } PixelFormat getLinearPixelFormat(PixelFormat format) { - if (format == PIXELFORMAT_RGBA8_UNORM_sRGB) - return PIXELFORMAT_RGBA8_UNORM; - else if (format == PIXELFORMAT_BGRA8_UNORM_sRGB) - return PIXELFORMAT_BGRA8_UNORM; + switch (format) + { + case PIXELFORMAT_RGBA8_sRGB: return PIXELFORMAT_RGBA8_UNORM; + case PIXELFORMAT_BGRA8_sRGB: return PIXELFORMAT_BGRA8_UNORM; + case PIXELFORMAT_PVR1_RGB2_sRGB: return PIXELFORMAT_PVR1_RGB2_UNORM; + case PIXELFORMAT_PVR1_RGB4_sRGB: return PIXELFORMAT_PVR1_RGB4_UNORM; + case PIXELFORMAT_PVR1_RGBA2_sRGB: return PIXELFORMAT_PVR1_RGBA2_UNORM; + case PIXELFORMAT_PVR1_RGBA4_sRGB: return PIXELFORMAT_PVR1_RGBA4_UNORM; + case PIXELFORMAT_ETC2_RGB_sRGB: return PIXELFORMAT_ETC2_RGB_UNORM; + case PIXELFORMAT_ETC2_RGBA_sRGB: return PIXELFORMAT_ETC2_RGBA_UNORM; + case PIXELFORMAT_ETC2_RGBA1_sRGB: return PIXELFORMAT_ETC2_RGBA1_UNORM; + case PIXELFORMAT_ASTC_4x4_sRGB: return PIXELFORMAT_ASTC_4x4_UNORM; + case PIXELFORMAT_ASTC_5x4_sRGB: return PIXELFORMAT_ASTC_5x4_UNORM; + case PIXELFORMAT_ASTC_5x5_sRGB: return PIXELFORMAT_ASTC_5x5_UNORM; + case PIXELFORMAT_ASTC_6x5_sRGB: return PIXELFORMAT_ASTC_6x5_UNORM; + case PIXELFORMAT_ASTC_6x6_sRGB: return PIXELFORMAT_ASTC_6x6_UNORM; + case PIXELFORMAT_ASTC_8x5_sRGB: return PIXELFORMAT_ASTC_8x5_UNORM; + case PIXELFORMAT_ASTC_8x6_sRGB: return PIXELFORMAT_ASTC_8x6_UNORM; + case PIXELFORMAT_ASTC_8x8_sRGB: return PIXELFORMAT_ASTC_8x8_UNORM; + case PIXELFORMAT_ASTC_10x5_sRGB: return PIXELFORMAT_ASTC_10x5_UNORM; + case PIXELFORMAT_ASTC_10x6_sRGB: return PIXELFORMAT_ASTC_10x6_UNORM; + case PIXELFORMAT_ASTC_10x8_sRGB: return PIXELFORMAT_ASTC_10x8_UNORM; + case PIXELFORMAT_ASTC_10x10_sRGB: return PIXELFORMAT_ASTC_10x10_UNORM; + case PIXELFORMAT_ASTC_12x10_sRGB: return PIXELFORMAT_ASTC_12x10_UNORM; + case PIXELFORMAT_ASTC_12x12_sRGB: return PIXELFORMAT_ASTC_12x12_UNORM; + default: + break; + } + return format; } diff --git a/src/common/pixelformat.h b/src/common/pixelformat.h index a2f52a4db..b928f92d7 100644 --- a/src/common/pixelformat.h +++ b/src/common/pixelformat.h @@ -60,9 +60,9 @@ enum PixelFormat // 4-channel normal formats PIXELFORMAT_RGBA8_UNORM, - PIXELFORMAT_RGBA8_UNORM_sRGB, + PIXELFORMAT_RGBA8_sRGB, PIXELFORMAT_BGRA8_UNORM, - PIXELFORMAT_BGRA8_UNORM_sRGB, + PIXELFORMAT_BGRA8_sRGB, PIXELFORMAT_RGBA8_INT, PIXELFORMAT_RGBA8_UINT, PIXELFORMAT_RGBA16_UNORM, @@ -90,8 +90,11 @@ enum PixelFormat // compressed formats PIXELFORMAT_DXT1_UNORM, + PIXELFORMAT_DXT1_sRGB, PIXELFORMAT_DXT3_UNORM, + PIXELFORMAT_DXT3_sRGB, PIXELFORMAT_DXT5_UNORM, + PIXELFORMAT_DXT5_sRGB, PIXELFORMAT_BC4_UNORM, PIXELFORMAT_BC4_SNORM, PIXELFORMAT_BC5_UNORM, @@ -99,32 +102,57 @@ enum PixelFormat PIXELFORMAT_BC6H_UFLOAT, PIXELFORMAT_BC6H_FLOAT, PIXELFORMAT_BC7_UNORM, + PIXELFORMAT_BC7_sRGB, + PIXELFORMAT_PVR1_RGB2_UNORM, + PIXELFORMAT_PVR1_RGB2_sRGB, PIXELFORMAT_PVR1_RGB4_UNORM, + PIXELFORMAT_PVR1_RGB4_sRGB, PIXELFORMAT_PVR1_RGBA2_UNORM, + PIXELFORMAT_PVR1_RGBA2_sRGB, PIXELFORMAT_PVR1_RGBA4_UNORM, + PIXELFORMAT_PVR1_RGBA4_sRGB, + PIXELFORMAT_ETC1_UNORM, PIXELFORMAT_ETC2_RGB_UNORM, + PIXELFORMAT_ETC2_RGB_sRGB, PIXELFORMAT_ETC2_RGBA_UNORM, + PIXELFORMAT_ETC2_RGBA_sRGB, PIXELFORMAT_ETC2_RGBA1_UNORM, + PIXELFORMAT_ETC2_RGBA1_sRGB, PIXELFORMAT_EAC_R_UNORM, PIXELFORMAT_EAC_R_SNORM, PIXELFORMAT_EAC_RG_UNORM, PIXELFORMAT_EAC_RG_SNORM, - PIXELFORMAT_ASTC_4x4, - PIXELFORMAT_ASTC_5x4, - PIXELFORMAT_ASTC_5x5, - PIXELFORMAT_ASTC_6x5, - PIXELFORMAT_ASTC_6x6, - PIXELFORMAT_ASTC_8x5, - PIXELFORMAT_ASTC_8x6, - PIXELFORMAT_ASTC_8x8, - PIXELFORMAT_ASTC_10x5, - PIXELFORMAT_ASTC_10x6, - PIXELFORMAT_ASTC_10x8, - PIXELFORMAT_ASTC_10x10, - PIXELFORMAT_ASTC_12x10, - PIXELFORMAT_ASTC_12x12, + + PIXELFORMAT_ASTC_4x4_UNORM, + PIXELFORMAT_ASTC_5x4_UNORM, + PIXELFORMAT_ASTC_5x5_UNORM, + PIXELFORMAT_ASTC_6x5_UNORM, + PIXELFORMAT_ASTC_6x6_UNORM, + PIXELFORMAT_ASTC_8x5_UNORM, + PIXELFORMAT_ASTC_8x6_UNORM, + PIXELFORMAT_ASTC_8x8_UNORM, + PIXELFORMAT_ASTC_10x5_UNORM, + PIXELFORMAT_ASTC_10x6_UNORM, + PIXELFORMAT_ASTC_10x8_UNORM, + PIXELFORMAT_ASTC_10x10_UNORM, + PIXELFORMAT_ASTC_12x10_UNORM, + PIXELFORMAT_ASTC_12x12_UNORM, + PIXELFORMAT_ASTC_4x4_sRGB, + PIXELFORMAT_ASTC_5x4_sRGB, + PIXELFORMAT_ASTC_5x5_sRGB, + PIXELFORMAT_ASTC_6x5_sRGB, + PIXELFORMAT_ASTC_6x6_sRGB, + PIXELFORMAT_ASTC_8x5_sRGB, + PIXELFORMAT_ASTC_8x6_sRGB, + PIXELFORMAT_ASTC_8x8_sRGB, + PIXELFORMAT_ASTC_10x5_sRGB, + PIXELFORMAT_ASTC_10x6_sRGB, + PIXELFORMAT_ASTC_10x8_sRGB, + PIXELFORMAT_ASTC_10x10_sRGB, + PIXELFORMAT_ASTC_12x10_sRGB, + PIXELFORMAT_ASTC_12x12_sRGB, PIXELFORMAT_MAX_ENUM }; @@ -149,6 +177,7 @@ struct PixelFormatInfo bool depth; bool stencil; bool compressed; + bool sRGB; PixelFormatType dataType; }; diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index be2b979e0..3d32b727b 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -925,7 +925,7 @@ void Graphics::setRenderTargets(const RenderTargets &rts) PixelFormat dsformat = PIXELFORMAT_STENCIL8; if (wantsdepth && wantsstencil) dsformat = PIXELFORMAT_DEPTH24_UNORM_STENCIL8; - else if (wantsdepth && isPixelFormatSupported(PIXELFORMAT_DEPTH24_UNORM, PIXELFORMATUSAGEFLAGS_RENDERTARGET, false)) + else if (wantsdepth && isPixelFormatSupported(PIXELFORMAT_DEPTH24_UNORM, PIXELFORMATUSAGEFLAGS_RENDERTARGET)) dsformat = PIXELFORMAT_DEPTH24_UNORM; else if (wantsdepth) dsformat = PIXELFORMAT_DEPTH16_UNORM; @@ -2395,7 +2395,7 @@ PixelFormat Graphics::getSizedFormat(PixelFormat format) const { case PIXELFORMAT_NORMAL: if (isGammaCorrect()) - return PIXELFORMAT_RGBA8_UNORM_sRGB; + return PIXELFORMAT_RGBA8_sRGB; else return PIXELFORMAT_RGBA8_UNORM; case PIXELFORMAT_HDR: diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index f9a51eab3..d2989213d 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -824,7 +824,7 @@ public: /** * Gets whether the specified pixel format usage is supported. **/ - virtual bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) = 0; + virtual bool isPixelFormatSupported(PixelFormat format, uint32 usage) = 0; /** * Gets the renderer used by love.graphics. diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 5cda31dae..4d0e59fcf 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -168,7 +168,6 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) , computeWrite(settings.computeWrite) , readable(true) , mipmapsMode(settings.mipmaps) - , sRGB(false) , width(settings.width) , height(settings.height) , depth(settings.type == TEXTURE_VOLUME ? settings.layers : 1) @@ -236,7 +235,8 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) readable = !renderTarget || !isPixelFormatDepthStencil(format); format = gfx->getSizedFormat(format); - sRGB = isPixelFormatSRGB(format) || (isCompressed() && isGammaCorrect() && !settings.linear); + if (!isGammaCorrect() || settings.linear) + format = getLinearPixelFormat(format); if (mipmapsMode == MIPMAPS_AUTO && isCompressed()) mipmapsMode = MIPMAPS_MANUAL; @@ -291,7 +291,7 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) if (computeWrite) usage |= PIXELFORMATUSAGEFLAGS_COMPUTEWRITE; - if (!gfx->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage, sRGB)) + if (!gfx->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage)) { const char *fstr = "unknown"; love::getConstant(format, fstr); @@ -622,7 +622,7 @@ bool Texture::isCompressed() const bool Texture::isFormatLinear() const { - return isGammaCorrect() && !sRGB && !isPixelFormatSRGB(format); + return isGammaCorrect() && !isPixelFormatSRGB(format); } bool Texture::isValidSlice(int slice, int mip) const diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 2132bf741..56fda383e 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -325,8 +325,6 @@ protected: MipmapsMode mipmapsMode; - bool sRGB; - int width; int height; diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index ea8894f4c..610f7d5de 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -110,7 +110,7 @@ public: void setWireframe(bool enable) override; - bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override; + bool isPixelFormatSupported(PixelFormat format, uint32 usage) override; Renderer getRenderer() const override; bool usesGLSLES() const override; RendererInfo getRendererInfo() const override; diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index ca6c76b82..0feab35dd 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -503,7 +503,7 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh backbufferMSAA.set(nullptr); if (settings.msaa > 1) { - settings.format = isGammaCorrect() ? PIXELFORMAT_BGRA8_UNORM_sRGB : PIXELFORMAT_BGRA8_UNORM; + settings.format = isGammaCorrect() ? PIXELFORMAT_BGRA8_sRGB : PIXELFORMAT_BGRA8_UNORM; backbufferMSAA.set(newTexture(settings), Acquire::NORETAIN); } @@ -681,7 +681,7 @@ id Graphics::useRenderEncoder() attachmentStoreActions.stencil = MTLStoreActionDontCare; auto &key = lastRenderPipelineKey; - key.colorRenderTargetFormats = isGammaCorrect() ? PIXELFORMAT_BGRA8_UNORM_sRGB : PIXELFORMAT_BGRA8_UNORM; + key.colorRenderTargetFormats = isGammaCorrect() ? PIXELFORMAT_BGRA8_sRGB : PIXELFORMAT_BGRA8_UNORM; key.depthStencilFormat = backbufferDepthStencil->getPixelFormat(); key.msaa = backbufferMSAA ? (uint8) backbufferMSAA->getMSAA() : 1; } @@ -1864,13 +1864,10 @@ void Graphics::setWireframe(bool enable) } } -bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) +bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage) { format = getSizedFormat(format); - if (sRGB) - format = getSRGBPixelFormat(format); - const uint32 sample = PIXELFORMATUSAGEFLAGS_SAMPLE; const uint32 filter = PIXELFORMATUSAGEFLAGS_LINEAR; const uint32 rt = PIXELFORMATUSAGEFLAGS_RENDERTARGET; @@ -1958,8 +1955,8 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG case PIXELFORMAT_BGRA8_UNORM: flags |= all; break; - case PIXELFORMAT_RGBA8_UNORM_sRGB: - case PIXELFORMAT_BGRA8_UNORM_sRGB: + case PIXELFORMAT_RGBA8_sRGB: + case PIXELFORMAT_BGRA8_sRGB: if (families.apple[1] || families.mac[1] || families.macCatalyst[1]) flags |= commonsample | commonrender; if (families.apple[2]) @@ -2058,8 +2055,11 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG break; case PIXELFORMAT_DXT1_UNORM: + case PIXELFORMAT_DXT1_sRGB: case PIXELFORMAT_DXT3_UNORM: + case PIXELFORMAT_DXT3_sRGB: case PIXELFORMAT_DXT5_UNORM: + case PIXELFORMAT_DXT5_sRGB: case PIXELFORMAT_BC4_UNORM: case PIXELFORMAT_BC4_SNORM: case PIXELFORMAT_BC5_UNORM: @@ -2067,22 +2067,30 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG case PIXELFORMAT_BC6H_UFLOAT: case PIXELFORMAT_BC6H_FLOAT: case PIXELFORMAT_BC7_UNORM: + case PIXELFORMAT_BC7_sRGB: if (families.mac[1] || families.macCatalyst[1]) flags |= commonsample; break; case PIXELFORMAT_PVR1_RGB2_UNORM: + case PIXELFORMAT_PVR1_RGB2_sRGB: case PIXELFORMAT_PVR1_RGB4_UNORM: + case PIXELFORMAT_PVR1_RGB4_sRGB: case PIXELFORMAT_PVR1_RGBA2_UNORM: + case PIXELFORMAT_PVR1_RGBA2_sRGB: case PIXELFORMAT_PVR1_RGBA4_UNORM: + case PIXELFORMAT_PVR1_RGBA4_sRGB: if (families.apple[1]) flags |= commonsample; break; case PIXELFORMAT_ETC1_UNORM: case PIXELFORMAT_ETC2_RGB_UNORM: + case PIXELFORMAT_ETC2_RGB_sRGB: case PIXELFORMAT_ETC2_RGBA_UNORM: + case PIXELFORMAT_ETC2_RGBA_sRGB: case PIXELFORMAT_ETC2_RGBA1_UNORM: + case PIXELFORMAT_ETC2_RGBA1_sRGB: case PIXELFORMAT_EAC_R_UNORM: case PIXELFORMAT_EAC_R_SNORM: case PIXELFORMAT_EAC_RG_UNORM: @@ -2091,20 +2099,34 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG flags |= commonsample; break; - case PIXELFORMAT_ASTC_4x4: - case PIXELFORMAT_ASTC_5x4: - case PIXELFORMAT_ASTC_5x5: - case PIXELFORMAT_ASTC_6x5: - case PIXELFORMAT_ASTC_6x6: - case PIXELFORMAT_ASTC_8x5: - case PIXELFORMAT_ASTC_8x6: - case PIXELFORMAT_ASTC_8x8: - case PIXELFORMAT_ASTC_10x5: - case PIXELFORMAT_ASTC_10x6: - case PIXELFORMAT_ASTC_10x8: - case PIXELFORMAT_ASTC_10x10: - case PIXELFORMAT_ASTC_12x10: - case PIXELFORMAT_ASTC_12x12: + case PIXELFORMAT_ASTC_4x4_UNORM: + case PIXELFORMAT_ASTC_5x4_UNORM: + case PIXELFORMAT_ASTC_5x5_UNORM: + case PIXELFORMAT_ASTC_6x5_UNORM: + case PIXELFORMAT_ASTC_6x6_UNORM: + case PIXELFORMAT_ASTC_8x5_UNORM: + case PIXELFORMAT_ASTC_8x6_UNORM: + case PIXELFORMAT_ASTC_8x8_UNORM: + case PIXELFORMAT_ASTC_10x5_UNORM: + case PIXELFORMAT_ASTC_10x6_UNORM: + case PIXELFORMAT_ASTC_10x8_UNORM: + case PIXELFORMAT_ASTC_10x10_UNORM: + case PIXELFORMAT_ASTC_12x10_UNORM: + case PIXELFORMAT_ASTC_12x12_UNORM: + case PIXELFORMAT_ASTC_4x4_sRGB: + case PIXELFORMAT_ASTC_5x4_sRGB: + case PIXELFORMAT_ASTC_5x5_sRGB: + case PIXELFORMAT_ASTC_6x5_sRGB: + case PIXELFORMAT_ASTC_6x6_sRGB: + case PIXELFORMAT_ASTC_8x5_sRGB: + case PIXELFORMAT_ASTC_8x6_sRGB: + case PIXELFORMAT_ASTC_8x8_sRGB: + case PIXELFORMAT_ASTC_10x5_sRGB: + case PIXELFORMAT_ASTC_10x6_sRGB: + case PIXELFORMAT_ASTC_10x8_sRGB: + case PIXELFORMAT_ASTC_10x10_sRGB: + case PIXELFORMAT_ASTC_12x10_sRGB: + case PIXELFORMAT_ASTC_12x12_sRGB: if (families.apple[2]) flags |= commonsample; break; diff --git a/src/modules/graphics/metal/Metal.h b/src/modules/graphics/metal/Metal.h index e38b8f529..2283d9d87 100644 --- a/src/modules/graphics/metal/Metal.h +++ b/src/modules/graphics/metal/Metal.h @@ -43,7 +43,7 @@ public: API_AVAILABLE(macos(10.15), ios(13.0)) MTLTextureSwizzleChannels swizzle; }; - static PixelFormatDesc convertPixelFormat(id device, PixelFormat format, bool &isSRGB); + static PixelFormatDesc convertPixelFormat(id device, PixelFormat format); }; // Metal diff --git a/src/modules/graphics/metal/Metal.mm b/src/modules/graphics/metal/Metal.mm index d547c3028..589329b4f 100644 --- a/src/modules/graphics/metal/Metal.mm +++ b/src/modules/graphics/metal/Metal.mm @@ -28,17 +28,11 @@ namespace graphics namespace metal { -Metal::PixelFormatDesc Metal::convertPixelFormat(id device, PixelFormat format, bool &isSRGB) +Metal::PixelFormatDesc Metal::convertPixelFormat(id device, PixelFormat format) { MTLPixelFormat mtlformat = MTLPixelFormatInvalid; PixelFormatDesc desc = {}; - if (isSRGB) - format = getSRGBPixelFormat(format); - - if (!isPixelFormatCompressed(format) && !isPixelFormatSRGB(format)) - isSRGB = false; - switch (format) { case PIXELFORMAT_R8_UNORM: @@ -50,13 +44,13 @@ Metal::PixelFormatDesc Metal::convertPixelFormat(id device, PixelForm case PIXELFORMAT_RGBA8_UNORM: mtlformat = MTLPixelFormatRGBA8Unorm; break; - case PIXELFORMAT_RGBA8_UNORM_sRGB: + case PIXELFORMAT_RGBA8_sRGB: mtlformat = MTLPixelFormatRGBA8Unorm_sRGB; break; case PIXELFORMAT_BGRA8_UNORM: mtlformat = MTLPixelFormatBGRA8Unorm; break; - case PIXELFORMAT_BGRA8_UNORM_sRGB: + case PIXELFORMAT_BGRA8_sRGB: mtlformat = MTLPixelFormatBGRA8Unorm_sRGB; break; case PIXELFORMAT_R16_UNORM: @@ -205,177 +199,264 @@ Metal::PixelFormatDesc Metal::convertPixelFormat(id device, PixelForm case PIXELFORMAT_DXT1_UNORM: #ifndef LOVE_IOS - mtlformat = isSRGB ? MTLPixelFormatBC1_RGBA_sRGB : MTLPixelFormatBC1_RGBA; + mtlformat = MTLPixelFormatBC1_RGBA; +#endif + break; + case PIXELFORMAT_DXT1_sRGB: +#ifndef LOVE_IOS + mtlformat = MTLPixelFormatBC1_RGBA_sRGB; #endif break; case PIXELFORMAT_DXT3_UNORM: #ifndef LOVE_IOS - mtlformat = isSRGB ? MTLPixelFormatBC2_RGBA_sRGB : MTLPixelFormatBC2_RGBA; + mtlformat = MTLPixelFormatBC2_RGBA; +#endif + break; + case PIXELFORMAT_DXT3_sRGB: +#ifndef LOVE_IOS + mtlformat = MTLPixelFormatBC2_RGBA_sRGB; #endif break; case PIXELFORMAT_DXT5_UNORM: #ifndef LOVE_IOS - mtlformat = isSRGB ? MTLPixelFormatBC3_RGBA_sRGB : MTLPixelFormatBC3_RGBA; + mtlformat = MTLPixelFormatBC3_RGBA; +#endif + break; + case PIXELFORMAT_DXT5_sRGB: +#ifndef LOVE_IOS + mtlformat = MTLPixelFormatBC3_RGBA_sRGB; #endif break; case PIXELFORMAT_BC4_UNORM: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC4_RUnorm; #endif break; case PIXELFORMAT_BC4_SNORM: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC4_RSnorm; #endif break; case PIXELFORMAT_BC5_UNORM: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC5_RGUnorm; #endif break; case PIXELFORMAT_BC5_SNORM: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC5_RGSnorm; #endif break; case PIXELFORMAT_BC6H_UFLOAT: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC6H_RGBUfloat; #endif break; case PIXELFORMAT_BC6H_FLOAT: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC6H_RGBFloat; #endif break; case PIXELFORMAT_BC7_UNORM: #ifndef LOVE_IOS - mtlformat = isSRGB ? MTLPixelFormatBC7_RGBAUnorm_sRGB : MTLPixelFormatBC7_RGBAUnorm; + mtlformat = MTLPixelFormatBC7_RGBAUnorm; +#endif + break; + case PIXELFORMAT_BC7_sRGB: +#ifndef LOVE_IOS + mtlformat = MTLPixelFormatBC7_RGBAUnorm_sRGB; #endif break; case PIXELFORMAT_PVR1_RGB2_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatPVRTC_RGB_2BPP_sRGB : MTLPixelFormatPVRTC_RGB_2BPP; + mtlformat = MTLPixelFormatPVRTC_RGB_2BPP; + break; + case PIXELFORMAT_PVR1_RGB2_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatPVRTC_RGB_2BPP_sRGB; break; case PIXELFORMAT_PVR1_RGB4_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatPVRTC_RGB_4BPP_sRGB : MTLPixelFormatPVRTC_RGB_4BPP; + mtlformat = MTLPixelFormatPVRTC_RGB_4BPP; + break; + case PIXELFORMAT_PVR1_RGB4_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatPVRTC_RGB_4BPP_sRGB; break; case PIXELFORMAT_PVR1_RGBA2_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatPVRTC_RGB_2BPP_sRGB : MTLPixelFormatPVRTC_RGBA_2BPP; + mtlformat = MTLPixelFormatPVRTC_RGBA_2BPP; + break; + case PIXELFORMAT_PVR1_RGBA2_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatPVRTC_RGB_2BPP_sRGB; break; case PIXELFORMAT_PVR1_RGBA4_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatPVRTC_RGB_4BPP_sRGB : MTLPixelFormatPVRTC_RGBA_4BPP; + mtlformat = MTLPixelFormatPVRTC_RGBA_4BPP; break; + case PIXELFORMAT_PVR1_RGBA4_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatPVRTC_RGB_4BPP_sRGB; + break; + case PIXELFORMAT_ETC1_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatETC2_RGB8_sRGB : MTLPixelFormatETC2_RGB8; + mtlformat = MTLPixelFormatETC2_RGB8; break; case PIXELFORMAT_ETC2_RGB_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatETC2_RGB8_sRGB : MTLPixelFormatETC2_RGB8; + mtlformat = MTLPixelFormatETC2_RGB8; + break; + case PIXELFORMAT_ETC2_RGB_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatETC2_RGB8_sRGB; break; case PIXELFORMAT_ETC2_RGBA_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatEAC_RGBA8_sRGB : MTLPixelFormatEAC_RGBA8; + mtlformat = MTLPixelFormatEAC_RGBA8; + break; + case PIXELFORMAT_ETC2_RGBA_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatEAC_RGBA8_sRGB; break; case PIXELFORMAT_ETC2_RGBA1_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatETC2_RGB8A1_sRGB : MTLPixelFormatETC2_RGB8A1; + mtlformat = MTLPixelFormatETC2_RGB8A1; + break; + case PIXELFORMAT_ETC2_RGBA1_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatETC2_RGB8A1_sRGB; break; case PIXELFORMAT_EAC_R_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - { - isSRGB = false; mtlformat = MTLPixelFormatEAC_R11Unorm; - } break; case PIXELFORMAT_EAC_R_SNORM: if (@available(macOS 11.0, iOS 8.0, *)) - { - isSRGB = false; mtlformat = MTLPixelFormatEAC_R11Snorm; - } break; case PIXELFORMAT_EAC_RG_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - { - isSRGB = false; mtlformat = MTLPixelFormatEAC_RG11Unorm; - } break; case PIXELFORMAT_EAC_RG_SNORM: if (@available(macOS 11.0, iOS 8.0, *)) - { - isSRGB = false; mtlformat = MTLPixelFormatEAC_RG11Snorm; - } break; - case PIXELFORMAT_ASTC_4x4: + case PIXELFORMAT_ASTC_4x4_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_4x4_sRGB : MTLPixelFormatASTC_4x4_LDR; + mtlformat = MTLPixelFormatASTC_4x4_LDR; break; - case PIXELFORMAT_ASTC_5x4: + case PIXELFORMAT_ASTC_5x4_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_5x4_sRGB : MTLPixelFormatASTC_5x4_LDR; + mtlformat = MTLPixelFormatASTC_5x4_LDR; break; - case PIXELFORMAT_ASTC_5x5: + case PIXELFORMAT_ASTC_5x5_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_5x5_sRGB : MTLPixelFormatASTC_5x5_LDR; + mtlformat = MTLPixelFormatASTC_5x5_LDR; break; - case PIXELFORMAT_ASTC_6x5: + case PIXELFORMAT_ASTC_6x5_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_6x5_sRGB : MTLPixelFormatASTC_6x5_LDR; + mtlformat = MTLPixelFormatASTC_6x5_LDR; break; - case PIXELFORMAT_ASTC_6x6: + case PIXELFORMAT_ASTC_6x6_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_6x6_sRGB : MTLPixelFormatASTC_6x6_LDR; + mtlformat = MTLPixelFormatASTC_6x6_LDR; break; - case PIXELFORMAT_ASTC_8x5: + case PIXELFORMAT_ASTC_8x5_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_8x5_sRGB : MTLPixelFormatASTC_8x5_LDR; + mtlformat = MTLPixelFormatASTC_8x5_LDR; break; - case PIXELFORMAT_ASTC_8x6: + case PIXELFORMAT_ASTC_8x6_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_8x6_sRGB : MTLPixelFormatASTC_8x6_LDR; + mtlformat = MTLPixelFormatASTC_8x6_LDR; break; - case PIXELFORMAT_ASTC_8x8: + case PIXELFORMAT_ASTC_8x8_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_8x8_sRGB : MTLPixelFormatASTC_8x8_LDR; + mtlformat = MTLPixelFormatASTC_8x8_LDR; break; - case PIXELFORMAT_ASTC_10x5: + case PIXELFORMAT_ASTC_10x5_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_10x5_sRGB : MTLPixelFormatASTC_10x5_LDR; + mtlformat = MTLPixelFormatASTC_10x5_LDR; break; - case PIXELFORMAT_ASTC_10x6: + case PIXELFORMAT_ASTC_10x6_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_10x6_sRGB : MTLPixelFormatASTC_10x6_LDR; + mtlformat = MTLPixelFormatASTC_10x6_LDR; break; - case PIXELFORMAT_ASTC_10x8: + case PIXELFORMAT_ASTC_10x8_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_10x8_sRGB : MTLPixelFormatASTC_10x8_LDR; + mtlformat = MTLPixelFormatASTC_10x8_LDR; break; - case PIXELFORMAT_ASTC_10x10: + case PIXELFORMAT_ASTC_10x10_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_10x10_sRGB : MTLPixelFormatASTC_10x10_LDR; + mtlformat = MTLPixelFormatASTC_10x10_LDR; break; - case PIXELFORMAT_ASTC_12x10: + case PIXELFORMAT_ASTC_12x10_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_12x10_sRGB : MTLPixelFormatASTC_12x10_LDR; + mtlformat = MTLPixelFormatASTC_12x10_LDR; break; - case PIXELFORMAT_ASTC_12x12: + case PIXELFORMAT_ASTC_12x12_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_12x12_sRGB : MTLPixelFormatASTC_12x12_LDR; + mtlformat = MTLPixelFormatASTC_12x12_LDR; + break; + case PIXELFORMAT_ASTC_4x4_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_4x4_sRGB; + break; + case PIXELFORMAT_ASTC_5x4_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_5x4_sRGB; + break; + case PIXELFORMAT_ASTC_5x5_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_5x5_sRGB; + break; + case PIXELFORMAT_ASTC_6x5_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_6x5_sRGB; + break; + case PIXELFORMAT_ASTC_6x6_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_6x6_sRGB; + break; + case PIXELFORMAT_ASTC_8x5_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_8x5_sRGB; + break; + case PIXELFORMAT_ASTC_8x6_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_8x6_sRGB; + break; + case PIXELFORMAT_ASTC_8x8_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_8x8_sRGB; + break; + case PIXELFORMAT_ASTC_10x5_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_10x5_sRGB; + break; + case PIXELFORMAT_ASTC_10x6_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_10x6_sRGB; + break; + case PIXELFORMAT_ASTC_10x8_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_10x8_sRGB; + break; + case PIXELFORMAT_ASTC_10x10_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_10x10_sRGB; + break; + case PIXELFORMAT_ASTC_12x10_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_12x10_sRGB; + break; + case PIXELFORMAT_ASTC_12x12_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_12x12_sRGB; break; case PIXELFORMAT_UNKNOWN: diff --git a/src/modules/graphics/metal/Texture.mm b/src/modules/graphics/metal/Texture.mm index 8421cbcc1..0efd7d21a 100644 --- a/src/modules/graphics/metal/Texture.mm +++ b/src/modules/graphics/metal/Texture.mm @@ -62,7 +62,7 @@ Texture::Texture(love::graphics::Graphics *gfxbase, id device, const desc.mipmapLevelCount = mipmapCount; desc.textureType = getMTLTextureType(texType, 1); - auto formatdesc = Metal::convertPixelFormat(device, format, sRGB); + auto formatdesc = Metal::convertPixelFormat(device, format); desc.pixelFormat = formatdesc.format; if (formatdesc.swizzled) { diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 651978742..e76da4ad7 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -250,7 +250,7 @@ void Graphics::updateBackbuffer(int width, int height, int /*pixelwidth*/, int p settings.renderTarget = true; settings.readable.set(false); - settings.format = isGammaCorrect() ? PIXELFORMAT_RGBA8_UNORM_sRGB : PIXELFORMAT_RGBA8_UNORM; + settings.format = isGammaCorrect() ? PIXELFORMAT_RGBA8_sRGB : PIXELFORMAT_RGBA8_UNORM; internalBackbuffer.set(newTexture(settings), Acquire::NORETAIN); settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8; @@ -1189,8 +1189,7 @@ GLuint Graphics::bindCachedFBO(const RenderTargets &targets) auto attachRT = [&](const RenderTarget &rt) { bool renderbuffer = msaa > 1 || !rt.texture->isReadable(); - bool srgb = false; - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(rt.texture->getPixelFormat(), renderbuffer, srgb); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(rt.texture->getPixelFormat(), renderbuffer); if (fmt.framebufferAttachments[0] == GL_COLOR_ATTACHMENT0) { @@ -1754,9 +1753,8 @@ uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable) { GLuint texture = 0; GLuint renderbuffer = 0; - bool sRGB = isPixelFormatSRGB(format); - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, !readable, sRGB); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, !readable); GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL); @@ -1778,7 +1776,7 @@ uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable) s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; gl.setSamplerState(TEXTURE_2D, s); - gl.rawTexStorage(TEXTURE_2D, 1, format, sRGB, 1, 1); + gl.rawTexStorage(TEXTURE_2D, 1, format, 1, 1); } else { @@ -1814,11 +1812,8 @@ uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable) return usage; } -bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) +bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage) { - if (sRGB) - format = getSRGBPixelFormat(format); - format = getSizedFormat(format); bool readable = (usage & PIXELFORMATUSAGEFLAGS_SAMPLE) != 0; diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index d27c96791..09b01ce10 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -106,7 +106,7 @@ public: void setWireframe(bool enable) override; - bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override; + bool isPixelFormatSupported(PixelFormat format, uint32 usage) override; Renderer getRenderer() const override; bool usesGLSLES() const override; RendererInfo getRendererInfo() const override; diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 9166b8c9f..7ad47cb08 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -646,11 +646,9 @@ void OpenGL::createDefaultTexture() const GLubyte *p = datatype == DATA_BASETYPE_FLOAT ? pix : intpix; - bool isSRGB = false; - rawTexStorage(type, 1, format, isSRGB, 1, 1); - - TextureFormat fmt = convertPixelFormat(format, false, isSRGB); + rawTexStorage(type, 1, format, 1, 1); + TextureFormat fmt = convertPixelFormat(format, false); int slices = type == TEXTURE_CUBE ? 6 : 1; for (int slice = 0; slice < slices; slice++) @@ -1433,10 +1431,10 @@ void OpenGL::setSamplerState(TextureType target, SamplerState &s) } } -bool OpenGL::rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, bool &isSRGB, int width, int height, int depth) +bool OpenGL::rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, int width, int height, int depth) { GLenum gltarget = getGLTextureType(target); - TextureFormat fmt = convertPixelFormat(pixelformat, false, isSRGB); + TextureFormat fmt = convertPixelFormat(pixelformat, false); // This shouldn't be needed for glTexStorage, but some drivers don't follow // the spec apparently. @@ -1700,16 +1698,14 @@ OpenGL::Vendor OpenGL::getVendor() const return vendor; } -OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB) +OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool renderbuffer) { TextureFormat f; f.framebufferAttachments[0] = GL_COLOR_ATTACHMENT0; f.framebufferAttachments[1] = GL_NONE; - if (isSRGB) - pixelformat = getSRGBPixelFormat(pixelformat); - else if (pixelformat == PIXELFORMAT_ETC1_UNORM) + if (pixelformat == PIXELFORMAT_ETC1_UNORM) { // The ETC2 format can load ETC1 textures. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility) @@ -1742,7 +1738,7 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r f.externalformat = GL_RGBA; f.type = GL_UNSIGNED_BYTE; break; - case PIXELFORMAT_RGBA8_UNORM_sRGB: + case PIXELFORMAT_RGBA8_sRGB: f.internalformat = GL_SRGB8_ALPHA8; f.type = GL_UNSIGNED_BYTE; if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0) @@ -1751,7 +1747,7 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r f.externalformat = GL_RGBA; break; case PIXELFORMAT_BGRA8_UNORM: - case PIXELFORMAT_BGRA8_UNORM_sRGB: + case PIXELFORMAT_BGRA8_sRGB: // Not supported right now. break; case PIXELFORMAT_R16_UNORM: @@ -2026,123 +2022,190 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r break; case PIXELFORMAT_DXT1_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + f.internalformat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case PIXELFORMAT_DXT1_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; break; case PIXELFORMAT_DXT3_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + f.internalformat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case PIXELFORMAT_DXT3_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; break; case PIXELFORMAT_DXT5_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + f.internalformat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case PIXELFORMAT_DXT5_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; break; case PIXELFORMAT_BC4_UNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_RED_RGTC1; break; case PIXELFORMAT_BC4_SNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_SIGNED_RED_RGTC1; break; case PIXELFORMAT_BC5_UNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_RG_RGTC2; break; case PIXELFORMAT_BC5_SNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_SIGNED_RG_RGTC2; break; case PIXELFORMAT_BC6H_UFLOAT: - isSRGB = false; f.internalformat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; break; case PIXELFORMAT_BC6H_FLOAT: - isSRGB = false; f.internalformat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; break; case PIXELFORMAT_BC7_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM : GL_COMPRESSED_RGBA_BPTC_UNORM; + f.internalformat = GL_COMPRESSED_RGBA_BPTC_UNORM; break; + case PIXELFORMAT_BC7_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; + break; + case PIXELFORMAT_PVR1_RGB2_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT : GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + f.internalformat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + break; + case PIXELFORMAT_PVR1_RGB2_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT; break; case PIXELFORMAT_PVR1_RGB4_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT : GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + f.internalformat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + break; + case PIXELFORMAT_PVR1_RGB4_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT; break; case PIXELFORMAT_PVR1_RGBA2_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT : GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + f.internalformat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + break; + case PIXELFORMAT_PVR1_RGBA2_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT; break; case PIXELFORMAT_PVR1_RGBA4_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT : GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + f.internalformat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; + case PIXELFORMAT_PVR1_RGBA4_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT; + break; + case PIXELFORMAT_ETC1_UNORM: - isSRGB = false; f.internalformat = GL_ETC1_RGB8_OES; break; case PIXELFORMAT_ETC2_RGB_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ETC2 : GL_COMPRESSED_RGB8_ETC2; + f.internalformat = GL_COMPRESSED_RGB8_ETC2; + break; + case PIXELFORMAT_ETC2_RGB_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ETC2; break; case PIXELFORMAT_ETC2_RGBA_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : GL_COMPRESSED_RGBA8_ETC2_EAC; + f.internalformat = GL_COMPRESSED_RGBA8_ETC2_EAC; + break; + case PIXELFORMAT_ETC2_RGBA_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; break; case PIXELFORMAT_ETC2_RGBA1_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + f.internalformat = GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + break; + case PIXELFORMAT_ETC2_RGBA1_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; break; case PIXELFORMAT_EAC_R_UNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_R11_EAC; break; case PIXELFORMAT_EAC_R_SNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_SIGNED_R11_EAC; break; case PIXELFORMAT_EAC_RG_UNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_RG11_EAC; break; case PIXELFORMAT_EAC_RG_SNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_SIGNED_RG11_EAC; break; - case PIXELFORMAT_ASTC_4x4: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : GL_COMPRESSED_RGBA_ASTC_4x4_KHR; + + case PIXELFORMAT_ASTC_4x4_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; - case PIXELFORMAT_ASTC_5x4: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : GL_COMPRESSED_RGBA_ASTC_5x4_KHR; + case PIXELFORMAT_ASTC_4x4_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR; break; - case PIXELFORMAT_ASTC_5x5: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : GL_COMPRESSED_RGBA_ASTC_5x5_KHR; + case PIXELFORMAT_ASTC_5x4_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_5x4_KHR; break; - case PIXELFORMAT_ASTC_6x5: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : GL_COMPRESSED_RGBA_ASTC_6x5_KHR; + case PIXELFORMAT_ASTC_5x4_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR; break; - case PIXELFORMAT_ASTC_6x6: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : GL_COMPRESSED_RGBA_ASTC_6x6_KHR; + case PIXELFORMAT_ASTC_5x5_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_5x5_KHR; break; - case PIXELFORMAT_ASTC_8x5: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : GL_COMPRESSED_RGBA_ASTC_8x5_KHR; + case PIXELFORMAT_ASTC_5x5_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR; break; - case PIXELFORMAT_ASTC_8x6: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : GL_COMPRESSED_RGBA_ASTC_8x6_KHR; + case PIXELFORMAT_ASTC_6x5_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_6x5_KHR; break; - case PIXELFORMAT_ASTC_8x8: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : GL_COMPRESSED_RGBA_ASTC_8x8_KHR; + case PIXELFORMAT_ASTC_6x5_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR; break; - case PIXELFORMAT_ASTC_10x5: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : GL_COMPRESSED_RGBA_ASTC_10x5_KHR; + case PIXELFORMAT_ASTC_6x6_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_6x6_KHR; break; - case PIXELFORMAT_ASTC_10x6: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : GL_COMPRESSED_RGBA_ASTC_10x6_KHR; + case PIXELFORMAT_ASTC_6x6_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR; break; - case PIXELFORMAT_ASTC_10x8: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : GL_COMPRESSED_RGBA_ASTC_10x8_KHR; + case PIXELFORMAT_ASTC_8x5_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_8x5_KHR; break; - case PIXELFORMAT_ASTC_10x10: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : GL_COMPRESSED_RGBA_ASTC_10x10_KHR; + case PIXELFORMAT_ASTC_8x5_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR; break; - case PIXELFORMAT_ASTC_12x10: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : GL_COMPRESSED_RGBA_ASTC_12x10_KHR; + case PIXELFORMAT_ASTC_8x6_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_8x6_KHR; break; - case PIXELFORMAT_ASTC_12x12: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : GL_COMPRESSED_RGBA_ASTC_12x12_KHR; + case PIXELFORMAT_ASTC_8x6_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR; + break; + case PIXELFORMAT_ASTC_8x8_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; + break; + case PIXELFORMAT_ASTC_8x8_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR; + break; + case PIXELFORMAT_ASTC_10x5_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_10x5_KHR; + break; + case PIXELFORMAT_ASTC_10x5_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR; + break; + case PIXELFORMAT_ASTC_10x6_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_10x6_KHR; + break; + case PIXELFORMAT_ASTC_10x6_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR; + break; + case PIXELFORMAT_ASTC_10x8_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_10x8_KHR; + break; + case PIXELFORMAT_ASTC_10x8_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR; + break; + case PIXELFORMAT_ASTC_10x10_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_10x10_KHR; + break; + case PIXELFORMAT_ASTC_10x10_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR; + break; + case PIXELFORMAT_ASTC_12x10_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_12x10_KHR; + break; + case PIXELFORMAT_ASTC_12x10_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR; + break; + case PIXELFORMAT_ASTC_12x12_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_12x12_KHR; + break; + case PIXELFORMAT_ASTC_12x12_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR; break; default: @@ -2164,9 +2227,6 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r { f.internalformat = f.externalformat; } - - if (!isPixelFormatSRGB(pixelformat)) - isSRGB = false; } return f; @@ -2198,7 +2258,7 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_1) flags |= computewrite; break; - case PIXELFORMAT_RGBA8_UNORM_sRGB: + case PIXELFORMAT_RGBA8_sRGB: if (gl.bugs.brokenSRGB) break; if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB) @@ -2210,7 +2270,7 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) flags |= computewrite; break; case PIXELFORMAT_BGRA8_UNORM: - case PIXELFORMAT_BGRA8_UNORM_sRGB: + case PIXELFORMAT_BGRA8_sRGB: // Not supported right now. break; case PIXELFORMAT_R16_UNORM: @@ -2278,47 +2338,47 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) flags |= computewrite; break; - case PIXELFORMAT_R8_INT: - case PIXELFORMAT_R8_UINT: - case PIXELFORMAT_RG8_INT: - case PIXELFORMAT_RG8_UINT: - case PIXELFORMAT_RGBA8_INT: - case PIXELFORMAT_RGBA8_UINT: - case PIXELFORMAT_R16_INT: - case PIXELFORMAT_R16_UINT: - case PIXELFORMAT_RG16_INT: - case PIXELFORMAT_RG16_UINT: - case PIXELFORMAT_RGBA16_INT: - case PIXELFORMAT_RGBA16_UINT: - case PIXELFORMAT_R32_INT: - case PIXELFORMAT_R32_UINT: - case PIXELFORMAT_RG32_INT: - case PIXELFORMAT_RG32_UINT: - case PIXELFORMAT_RGBA32_INT: - case PIXELFORMAT_RGBA32_UINT: - if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0) - flags |= PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_RENDERTARGET; - if (GLAD_VERSION_4_3) - flags |= computewrite; - if (GLAD_ES_VERSION_3_1) + case PIXELFORMAT_R8_INT: + case PIXELFORMAT_R8_UINT: + case PIXELFORMAT_RG8_INT: + case PIXELFORMAT_RG8_UINT: + case PIXELFORMAT_RGBA8_INT: + case PIXELFORMAT_RGBA8_UINT: + case PIXELFORMAT_R16_INT: + case PIXELFORMAT_R16_UINT: + case PIXELFORMAT_RG16_INT: + case PIXELFORMAT_RG16_UINT: + case PIXELFORMAT_RGBA16_INT: + case PIXELFORMAT_RGBA16_UINT: + case PIXELFORMAT_R32_INT: + case PIXELFORMAT_R32_UINT: + case PIXELFORMAT_RG32_INT: + case PIXELFORMAT_RG32_UINT: + case PIXELFORMAT_RGBA32_INT: + case PIXELFORMAT_RGBA32_UINT: + if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0) + flags |= PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_RENDERTARGET; + if (GLAD_VERSION_4_3) + flags |= computewrite; + if (GLAD_ES_VERSION_3_1) + { + switch (pixelformat) { - switch (pixelformat) - { - case PIXELFORMAT_RGBA8_INT: - case PIXELFORMAT_RGBA8_UINT: - case PIXELFORMAT_RGBA16_INT: - case PIXELFORMAT_RGBA16_UINT: - case PIXELFORMAT_R32_INT: - case PIXELFORMAT_R32_UINT: - case PIXELFORMAT_RGBA32_INT: - case PIXELFORMAT_RGBA32_UINT: - flags |= computewrite; - break; - default: - break; - } + case PIXELFORMAT_RGBA8_INT: + case PIXELFORMAT_RGBA8_UINT: + case PIXELFORMAT_RGBA16_INT: + case PIXELFORMAT_RGBA16_UINT: + case PIXELFORMAT_R32_INT: + case PIXELFORMAT_R32_UINT: + case PIXELFORMAT_RGBA32_INT: + case PIXELFORMAT_RGBA32_UINT: + flags |= computewrite; + break; + default: + break; } - break; + } + break; case PIXELFORMAT_LA8_UNORM: flags |= commonsample; @@ -2380,14 +2440,17 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) break; case PIXELFORMAT_DXT1_UNORM: + case PIXELFORMAT_DXT1_sRGB: if (GLAD_EXT_texture_compression_s3tc || GLAD_EXT_texture_compression_dxt1) flags |= commonsample; break; case PIXELFORMAT_DXT3_UNORM: + case PIXELFORMAT_DXT3_sRGB: if (GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt3) flags |= commonsample; break; case PIXELFORMAT_DXT5_UNORM: + case PIXELFORMAT_DXT5_sRGB: if (GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt5) flags |= commonsample; break; @@ -2401,6 +2464,7 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) case PIXELFORMAT_BC6H_UFLOAT: case PIXELFORMAT_BC6H_FLOAT: case PIXELFORMAT_BC7_UNORM: + case PIXELFORMAT_BC7_sRGB: if (GLAD_VERSION_4_2 || GLAD_ARB_texture_compression_bptc) flags |= commonsample; break; @@ -2411,14 +2475,24 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) if (GLAD_IMG_texture_compression_pvrtc) flags |= commonsample; break; + case PIXELFORMAT_PVR1_RGB2_sRGB: + case PIXELFORMAT_PVR1_RGB4_sRGB: + case PIXELFORMAT_PVR1_RGBA2_sRGB: + case PIXELFORMAT_PVR1_RGBA4_sRGB: + if (GLAD_EXT_pvrtc_sRGB) + flags |= commonsample; + break; case PIXELFORMAT_ETC1_UNORM: // ETC2 support guarantees ETC1 support as well. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility || GLAD_OES_compressed_ETC1_RGB8_texture) flags |= commonsample; break; case PIXELFORMAT_ETC2_RGB_UNORM: + case PIXELFORMAT_ETC2_RGB_sRGB: case PIXELFORMAT_ETC2_RGBA_UNORM: + case PIXELFORMAT_ETC2_RGBA_sRGB: case PIXELFORMAT_ETC2_RGBA1_UNORM: + case PIXELFORMAT_ETC2_RGBA1_sRGB: case PIXELFORMAT_EAC_R_UNORM: case PIXELFORMAT_EAC_R_SNORM: case PIXELFORMAT_EAC_RG_UNORM: @@ -2426,20 +2500,34 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility) flags |= commonsample; break; - case PIXELFORMAT_ASTC_4x4: - case PIXELFORMAT_ASTC_5x4: - case PIXELFORMAT_ASTC_5x5: - case PIXELFORMAT_ASTC_6x5: - case PIXELFORMAT_ASTC_6x6: - case PIXELFORMAT_ASTC_8x5: - case PIXELFORMAT_ASTC_8x6: - case PIXELFORMAT_ASTC_8x8: - case PIXELFORMAT_ASTC_10x5: - case PIXELFORMAT_ASTC_10x6: - case PIXELFORMAT_ASTC_10x8: - case PIXELFORMAT_ASTC_10x10: - case PIXELFORMAT_ASTC_12x10: - case PIXELFORMAT_ASTC_12x12: + case PIXELFORMAT_ASTC_4x4_UNORM: + case PIXELFORMAT_ASTC_5x4_UNORM: + case PIXELFORMAT_ASTC_5x5_UNORM: + case PIXELFORMAT_ASTC_6x5_UNORM: + case PIXELFORMAT_ASTC_6x6_UNORM: + case PIXELFORMAT_ASTC_8x5_UNORM: + case PIXELFORMAT_ASTC_8x6_UNORM: + case PIXELFORMAT_ASTC_8x8_UNORM: + case PIXELFORMAT_ASTC_10x5_UNORM: + case PIXELFORMAT_ASTC_10x6_UNORM: + case PIXELFORMAT_ASTC_10x8_UNORM: + case PIXELFORMAT_ASTC_10x10_UNORM: + case PIXELFORMAT_ASTC_12x10_UNORM: + case PIXELFORMAT_ASTC_12x12_UNORM: + case PIXELFORMAT_ASTC_4x4_sRGB: + case PIXELFORMAT_ASTC_5x4_sRGB: + case PIXELFORMAT_ASTC_5x5_sRGB: + case PIXELFORMAT_ASTC_6x5_sRGB: + case PIXELFORMAT_ASTC_6x6_sRGB: + case PIXELFORMAT_ASTC_8x5_sRGB: + case PIXELFORMAT_ASTC_8x6_sRGB: + case PIXELFORMAT_ASTC_8x8_sRGB: + case PIXELFORMAT_ASTC_10x5_sRGB: + case PIXELFORMAT_ASTC_10x6_sRGB: + case PIXELFORMAT_ASTC_10x8_sRGB: + case PIXELFORMAT_ASTC_10x10_sRGB: + case PIXELFORMAT_ASTC_12x10_sRGB: + case PIXELFORMAT_ASTC_12x12_sRGB: if (GLAD_ES_VERSION_3_2 || GLAD_KHR_texture_compression_astc_ldr) flags |= commonsample; break; diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 3690c6baa..e3cbff100 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -381,7 +381,7 @@ public: * to glTexImage2D/3D for all levels and slices of a texture otherwise. * NOTE: this does not handle compressed texture formats. **/ - bool rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, bool &isSRGB, int width, int height, int depth = 1); + bool rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, int width, int height, int depth = 1); bool isTextureTypeSupported(TextureType type) const; bool isBufferUsageSupported(BufferUsage usage) const; @@ -475,7 +475,7 @@ public: static GLint getGLWrapMode(SamplerState::WrapMode wmode); static GLint getGLCompareMode(CompareMode mode); - static TextureFormat convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB); + static TextureFormat convertPixelFormat(PixelFormat pixelformat, bool renderbuffer); static bool isTexStorageSupported(); static uint32 getPixelFormatUsageFlags(PixelFormat pixelformat); diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index d4d2b65ca..bfd728a1e 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -175,8 +175,7 @@ void Shader::mapActiveUniforms() else if ((u.access & ACCESS_READ) != 0) binding.access = GL_READ_ONLY; - bool sRGB = false; - auto fmt = OpenGL::convertPixelFormat(u.storageTextureFormat, false, sRGB); + auto fmt = OpenGL::convertPixelFormat(u.storageTextureFormat, false); binding.internalFormat = fmt.internalformat; for (int i = 0; i < u.count; i++) diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index 1b6eb69f1..8a9ad9655 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -56,8 +56,7 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo glReadBuffer(GL_NONE); } - bool unusedSRGB = false; - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, false, unusedSRGB); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, false); int faces = texType == TEXTURE_CUBE ? 6 : 1; @@ -125,8 +124,7 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo static GLenum newRenderbuffer(int width, int height, int &samples, PixelFormat pixelformat, GLuint &buffer) { - bool unusedSRGB = false; - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, true, unusedSRGB); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, true); GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL); @@ -282,7 +280,7 @@ void Texture::createTexture() // remember some driver issues on some old Android systems, maybe... // For now, the base class enforces data on init for compressed textures. if (!isCompressed()) - gl.rawTexStorage(texType, mipcount, format, sRGB, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers); + gl.rawTexStorage(texType, mipcount, format, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers); // rawTexStorage handles this for uncompressed textures. if (isCompressed() && (GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0)) @@ -292,7 +290,7 @@ void Texture::createTexture() int h = pixelHeight; int d = depth; - OpenGL::TextureFormat fmt = gl.convertPixelFormat(format, false, sRGB); + OpenGL::TextureFormat fmt = gl.convertPixelFormat(format, false); for (int mip = 0; mip < mipcount; mip++) { @@ -460,7 +458,7 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t s gl.bindTextureToUnit(this, 0, false); - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, false, sRGB); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, false); GLenum gltarget = OpenGL::getGLTextureType(texType); if (texType == TEXTURE_CUBE) @@ -508,8 +506,7 @@ void Texture::readbackInternal(int slice, int mipmap, const Rect &rect, int dest gl.bindTextureToUnit(this, 0, false); - bool isSRGB = false; - OpenGL::TextureFormat fmt = gl.convertPixelFormat(format, false, isSRGB); + OpenGL::TextureFormat fmt = gl.convertPixelFormat(format, false); if (gl.isCopyTextureToBufferSupported()) { diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 39228f335..c3a7c5c73 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1057,11 +1057,11 @@ void Graphics::setWireframe(bool enable) states.back().wireframe = enable; } -bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) +bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage) { format = getSizedFormat(format); - auto vulkanFormat = Vulkan::getTextureFormat(format, sRGB); + auto vulkanFormat = Vulkan::getTextureFormat(format); VkFormatProperties formatProperties; vkGetPhysicalDeviceFormatProperties(physicalDevice, vulkanFormat.internalFormat, &formatProperties); @@ -2444,12 +2444,12 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b RenderPassConfiguration renderPassConfiguration{}; for (const auto &color : rts.colors) renderPassConfiguration.colorAttachments.push_back({ - Vulkan::getTextureFormat(color.texture->getPixelFormat(), isPixelFormatSRGB(color.texture->getPixelFormat())).internalFormat, + Vulkan::getTextureFormat(color.texture->getPixelFormat()).internalFormat, VK_ATTACHMENT_LOAD_OP_LOAD, dynamic_cast(color.texture)->getMsaaSamples() }); if (rts.depthStencil.texture != nullptr) renderPassConfiguration.staticData.depthStencilAttachment = { - Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat(), false).internalFormat, + Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat()).internalFormat, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, dynamic_cast(rts.depthStencil.texture)->getMsaaSamples() }; diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 69ae238b5..e2ae0541b 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -297,7 +297,7 @@ public: void setBlendState(const BlendState &blend) override; void setPointSize(float size) override; void setWireframe(bool enable) override; - bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) override; + bool isPixelFormatSupported(PixelFormat format, uint32 usage) override; Renderer getRenderer() const override; bool usesGLSLES() const override; RendererInfo getRendererInfo() const override; diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index 8a979789c..4eea47722 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -59,7 +59,7 @@ bool Texture::loadVolatile() if (isPixelFormatColor(format)) imageAspect |= VK_IMAGE_ASPECT_COLOR_BIT; - auto vulkanFormat = Vulkan::getTextureFormat(format, sRGB); + auto vulkanFormat = Vulkan::getTextureFormat(format); VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | @@ -277,7 +277,7 @@ VkImageLayout Texture::getImageLayout() const void Texture::createTextureImageView() { - auto vulkanFormat = Vulkan::getTextureFormat(format, sRGB); + auto vulkanFormat = Vulkan::getTextureFormat(format); VkImageViewCreateInfo viewInfo{}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -349,7 +349,7 @@ void Texture::clear() VkClearColorValue Texture::getClearValue() { - auto vulkanFormat = Vulkan::getTextureFormat(format, sRGB); + auto vulkanFormat = Vulkan::getTextureFormat(format); VkClearColorValue clearColor{}; switch (vulkanFormat.internalFormatRepresentation) diff --git a/src/modules/graphics/vulkan/Vulkan.cpp b/src/modules/graphics/vulkan/Vulkan.cpp index 817f6fdb7..afd991fcd 100644 --- a/src/modules/graphics/vulkan/Vulkan.cpp +++ b/src/modules/graphics/vulkan/Vulkan.cpp @@ -130,16 +130,10 @@ VkFormat Vulkan::getVulkanVertexFormat(DataFormat format) } } -TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) +TextureFormat Vulkan::getTextureFormat(PixelFormat format) { TextureFormat textureFormat{}; - if (sRGB) - format = getSRGBPixelFormat(format); - - if (!isPixelFormatCompressed(format) && !isPixelFormatSRGB(format)) - sRGB = false; - switch (format) { case PIXELFORMAT_UNKNOWN: @@ -231,13 +225,13 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) case PIXELFORMAT_RGBA8_UNORM: textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UNORM; break; - case PIXELFORMAT_RGBA8_UNORM_sRGB: + case PIXELFORMAT_RGBA8_sRGB: textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB; break; case PIXELFORMAT_BGRA8_UNORM: textureFormat.internalFormat = VK_FORMAT_B8G8R8A8_UNORM; break; - case PIXELFORMAT_BGRA8_UNORM_sRGB: + case PIXELFORMAT_BGRA8_sRGB: textureFormat.internalFormat = VK_FORMAT_B8G8R8A8_SRGB; break; case PIXELFORMAT_RGBA8_INT: @@ -308,13 +302,22 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) textureFormat.internalFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; break; case PIXELFORMAT_DXT1_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_BC1_RGBA_SRGB_BLOCK : VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + break; + case PIXELFORMAT_DXT1_sRGB: + textureFormat.internalFormat = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; break; case PIXELFORMAT_DXT3_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_BC2_UNORM_BLOCK; + break; + case PIXELFORMAT_DXT3_sRGB: + textureFormat.internalFormat = VK_FORMAT_BC2_SRGB_BLOCK; break; case PIXELFORMAT_DXT5_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_BC3_UNORM_BLOCK; + break; + case PIXELFORMAT_DXT5_sRGB: + textureFormat.internalFormat = VK_FORMAT_BC3_SRGB_BLOCK; break; case PIXELFORMAT_BC4_UNORM: textureFormat.internalFormat = VK_FORMAT_BC4_UNORM_BLOCK; @@ -335,31 +338,55 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) textureFormat.internalFormat = VK_FORMAT_BC6H_SFLOAT_BLOCK; break; case PIXELFORMAT_BC7_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_BC7_UNORM_BLOCK; + break; + case PIXELFORMAT_BC7_sRGB: + textureFormat.internalFormat = VK_FORMAT_BC7_SRGB_BLOCK; break; case PIXELFORMAT_PVR1_RGB2_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG : VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + textureFormat.internalFormat = VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + break; + case PIXELFORMAT_PVR1_RGB2_sRGB: + textureFormat.internalFormat = VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; break; case PIXELFORMAT_PVR1_RGB4_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG : VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + textureFormat.internalFormat = VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + break; + case PIXELFORMAT_PVR1_RGB4_sRGB: + textureFormat.internalFormat = VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; break; case PIXELFORMAT_PVR1_RGBA2_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG : VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + textureFormat.internalFormat = VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + break; + case PIXELFORMAT_PVR1_RGBA2_sRGB: + textureFormat.internalFormat = VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; break; case PIXELFORMAT_PVR1_RGBA4_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG : VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + textureFormat.internalFormat = VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + break; + case PIXELFORMAT_PVR1_RGBA4_sRGB: + textureFormat.internalFormat = VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; break; case PIXELFORMAT_ETC1_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; break; case PIXELFORMAT_ETC2_RGB_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + break; + case PIXELFORMAT_ETC2_RGB_sRGB: + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK; break; case PIXELFORMAT_ETC2_RGBA_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + break; + case PIXELFORMAT_ETC2_RGBA_sRGB: + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK; break; case PIXELFORMAT_ETC2_RGBA1_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; + break; + case PIXELFORMAT_ETC2_RGBA1_sRGB: + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK; break; case PIXELFORMAT_EAC_R_UNORM: textureFormat.internalFormat = VK_FORMAT_EAC_R11_UNORM_BLOCK; @@ -373,47 +400,89 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) case PIXELFORMAT_EAC_RG_SNORM: textureFormat.internalFormat = VK_FORMAT_EAC_R11G11_SNORM_BLOCK; break; - case PIXELFORMAT_ASTC_4x4: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK; + case PIXELFORMAT_ASTC_4x4_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_4x4_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_5x4: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK; + case PIXELFORMAT_ASTC_5x4_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_5x4_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_5x5: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK; + case PIXELFORMAT_ASTC_5x5_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_5x5_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_6x5: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK; + case PIXELFORMAT_ASTC_6x5_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_6x5_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_6x6: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK; + case PIXELFORMAT_ASTC_6x6_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_6x6_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_8x5: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK; + case PIXELFORMAT_ASTC_8x5_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x5_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_8x6: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK; + case PIXELFORMAT_ASTC_8x6_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x6_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_8x8: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK; + case PIXELFORMAT_ASTC_8x8_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x8_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_10x5: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK; + case PIXELFORMAT_ASTC_10x5_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x5_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_10x6: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK; + case PIXELFORMAT_ASTC_10x6_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x6_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_10x8: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK; + case PIXELFORMAT_ASTC_10x8_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x8_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_10x10: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK; + case PIXELFORMAT_ASTC_10x10_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x10_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_12x10: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK; + case PIXELFORMAT_ASTC_12x10_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_12x10_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_12x12: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK; + case PIXELFORMAT_ASTC_12x12_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_12x12_UNORM_BLOCK; + break; + case PIXELFORMAT_ASTC_4x4_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_4x4_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_5x4_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_5x4_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_5x5_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_5x5_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_6x5_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_6x5_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_6x6_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_6x6_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_8x5_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x5_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_8x6_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x6_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_8x8_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x8_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_10x5_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x5_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_10x6_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x6_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_10x8_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x8_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_10x10_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x10_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_12x10_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_12x10_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_12x12_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_12x12_SRGB_BLOCK; break; default: throw love::Exception("unknown pixel format"); diff --git a/src/modules/graphics/vulkan/Vulkan.h b/src/modules/graphics/vulkan/Vulkan.h index 2e512ab9d..46d27519f 100644 --- a/src/modules/graphics/vulkan/Vulkan.h +++ b/src/modules/graphics/vulkan/Vulkan.h @@ -59,7 +59,7 @@ public: static void resetShaderSwitches(); static VkFormat getVulkanVertexFormat(DataFormat format); - static TextureFormat getTextureFormat(PixelFormat, bool sRGB); + static TextureFormat getTextureFormat(PixelFormat format); static std::string getVendorName(uint32_t vendorId); static std::string getVulkanApiVersion(uint32_t apiVersion); static VkPrimitiveTopology getPrimitiveTypeTopology(graphics::PrimitiveType); diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 3a2eb613a..c5b9648ce 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -2783,7 +2783,6 @@ int w_getTextureFormats(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); bool rt = luax_checkboolflag(L, 1, Texture::getConstant(Texture::SETTING_RENDER_TARGET)); - bool linear = luax_boolflag(L, 1, Texture::getConstant(Texture::SETTING_LINEAR), false); bool computewrite = luax_boolflag(L, 1, Texture::getConstant(Texture::SETTING_COMPUTE_WRITE), false); OptionalBool readable; @@ -2808,8 +2807,6 @@ int w_getTextureFormats(lua_State *L) if (rt && isPixelFormatDepth(format)) continue; - bool sRGB = isGammaCorrect() && !linear; - uint32 usage = PIXELFORMATUSAGEFLAGS_NONE; if (rt) usage |= PIXELFORMATUSAGEFLAGS_RENDERTARGET; @@ -2818,7 +2815,7 @@ int w_getTextureFormats(lua_State *L) if (computewrite) usage |= PIXELFORMATUSAGEFLAGS_COMPUTEWRITE; - luax_pushboolean(L, instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage, sRGB)); + luax_pushboolean(L, instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage)); lua_setfield(L, -2, name); } @@ -2862,14 +2859,14 @@ int w_getCanvasFormats(lua_State *L) supported = [](PixelFormat format) -> bool { const uint32 usage = PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_RENDERTARGET; - return instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage, false); + return instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage); }; } else { supported = [](PixelFormat format) -> bool { - return instance()->isPixelFormatSupported(format, PIXELFORMATUSAGEFLAGS_RENDERTARGET, false); + return instance()->isPixelFormatSupported(format, PIXELFORMATUSAGEFLAGS_RENDERTARGET); }; } } @@ -2881,7 +2878,7 @@ int w_getCanvasFormats(lua_State *L) uint32 usage = PIXELFORMATUSAGEFLAGS_RENDERTARGET; if (readable) usage |= PIXELFORMATUSAGEFLAGS_SAMPLE; - return instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage, false); + return instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage); }; } @@ -2894,7 +2891,7 @@ int w_getImageFormats(lua_State *L) const auto supported = [](PixelFormat format) -> bool { - return instance()->isPixelFormatSupported(format, PIXELFORMATUSAGEFLAGS_SAMPLE, false); + return instance()->isPixelFormatSupported(format, PIXELFORMATUSAGEFLAGS_SAMPLE); }; const auto ignore = [](PixelFormat format) -> bool diff --git a/src/modules/image/magpie/ASTCHandler.cpp b/src/modules/image/magpie/ASTCHandler.cpp index 8f2fb569f..fb9a395c2 100644 --- a/src/modules/image/magpie/ASTCHandler.cpp +++ b/src/modules/image/magpie/ASTCHandler.cpp @@ -54,33 +54,33 @@ static PixelFormat convertFormat(uint32 blockX, uint32 blockY, uint32 blockZ) return PIXELFORMAT_UNKNOWN; if (blockX == 4 && blockY == 4) - return PIXELFORMAT_ASTC_4x4; + return PIXELFORMAT_ASTC_4x4_UNORM; else if (blockX == 5 && blockY == 4) - return PIXELFORMAT_ASTC_5x4; + return PIXELFORMAT_ASTC_5x4_UNORM; else if (blockX == 5 && blockY == 5) - return PIXELFORMAT_ASTC_5x5; + return PIXELFORMAT_ASTC_5x5_UNORM; else if (blockX == 6 && blockY == 5) - return PIXELFORMAT_ASTC_6x5; + return PIXELFORMAT_ASTC_6x5_UNORM; else if (blockX == 6 && blockY == 6) - return PIXELFORMAT_ASTC_6x6; + return PIXELFORMAT_ASTC_6x6_UNORM; else if (blockX == 8 && blockY == 5) - return PIXELFORMAT_ASTC_8x5; + return PIXELFORMAT_ASTC_8x5_UNORM; else if (blockX == 8 && blockY == 6) - return PIXELFORMAT_ASTC_8x6; + return PIXELFORMAT_ASTC_8x6_UNORM; else if (blockX == 8 && blockY == 8) - return PIXELFORMAT_ASTC_8x8; + return PIXELFORMAT_ASTC_8x8_UNORM; else if (blockX == 10 && blockY == 5) - return PIXELFORMAT_ASTC_10x5; + return PIXELFORMAT_ASTC_10x5_UNORM; else if (blockX == 10 && blockY == 6) - return PIXELFORMAT_ASTC_10x6; + return PIXELFORMAT_ASTC_10x6_UNORM; else if (blockX == 10 && blockY == 8) - return PIXELFORMAT_ASTC_10x8; + return PIXELFORMAT_ASTC_10x8_UNORM; else if (blockX == 10 && blockY == 10) - return PIXELFORMAT_ASTC_10x10; + return PIXELFORMAT_ASTC_10x10_UNORM; else if (blockX == 12 && blockY == 10) - return PIXELFORMAT_ASTC_12x10; + return PIXELFORMAT_ASTC_12x10_UNORM; else if (blockX == 12 && blockY == 12) - return PIXELFORMAT_ASTC_12x12; + return PIXELFORMAT_ASTC_12x12_UNORM; return PIXELFORMAT_UNKNOWN; } diff --git a/src/modules/image/magpie/KTXHandler.cpp b/src/modules/image/magpie/KTXHandler.cpp index ac7f7ef03..758642b68 100644 --- a/src/modules/image/magpie/KTXHandler.cpp +++ b/src/modules/image/magpie/KTXHandler.cpp @@ -221,59 +221,59 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB) case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_4x4_KHR: - return PIXELFORMAT_ASTC_4x4; + return PIXELFORMAT_ASTC_4x4_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_5x4_KHR: - return PIXELFORMAT_ASTC_5x4; + return PIXELFORMAT_ASTC_5x4_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_5x5_KHR: - return PIXELFORMAT_ASTC_5x5; + return PIXELFORMAT_ASTC_5x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_6x5_KHR: - return PIXELFORMAT_ASTC_6x5; + return PIXELFORMAT_ASTC_6x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_6x6_KHR: - return PIXELFORMAT_ASTC_6x6; + return PIXELFORMAT_ASTC_6x6_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_8x5_KHR: - return PIXELFORMAT_ASTC_8x5; + return PIXELFORMAT_ASTC_8x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_8x6_KHR: - return PIXELFORMAT_ASTC_8x6; + return PIXELFORMAT_ASTC_8x6_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_8x8_KHR: - return PIXELFORMAT_ASTC_8x8; + return PIXELFORMAT_ASTC_8x8_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_10x5_KHR: - return PIXELFORMAT_ASTC_10x5; + return PIXELFORMAT_ASTC_10x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_10x6_KHR: - return PIXELFORMAT_ASTC_10x6; + return PIXELFORMAT_ASTC_10x6_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_10x8_KHR: - return PIXELFORMAT_ASTC_10x8; + return PIXELFORMAT_ASTC_10x8_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_10x10_KHR: - return PIXELFORMAT_ASTC_10x10; + return PIXELFORMAT_ASTC_10x10_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_12x10_KHR: - return PIXELFORMAT_ASTC_12x10; + return PIXELFORMAT_ASTC_12x10_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: sRGB = true; case KTX_GL_COMPRESSED_RGBA_ASTC_12x12_KHR: - return PIXELFORMAT_ASTC_12x12; + return PIXELFORMAT_ASTC_12x12_UNORM; default: return PIXELFORMAT_UNKNOWN; } diff --git a/src/modules/image/magpie/PVRHandler.cpp b/src/modules/image/magpie/PVRHandler.cpp index 21ebe6f0a..1259536ca 100644 --- a/src/modules/image/magpie/PVRHandler.cpp +++ b/src/modules/image/magpie/PVRHandler.cpp @@ -256,33 +256,33 @@ static PixelFormat convertFormat(PVRV3PixelFormat format, PVRV3ChannelType chann case ePVRTPF_EAC_RG: return snorm ? PIXELFORMAT_EAC_RG_SNORM : PIXELFORMAT_EAC_RG_UNORM; case ePVRTPF_ASTC_4x4: - return PIXELFORMAT_ASTC_4x4; + return PIXELFORMAT_ASTC_4x4_UNORM; case ePVRTPF_ASTC_5x4: - return PIXELFORMAT_ASTC_5x4; + return PIXELFORMAT_ASTC_5x4_UNORM; case ePVRTPF_ASTC_5x5: - return PIXELFORMAT_ASTC_5x5; + return PIXELFORMAT_ASTC_5x5_UNORM; case ePVRTPF_ASTC_6x5: - return PIXELFORMAT_ASTC_6x5; + return PIXELFORMAT_ASTC_6x5_UNORM; case ePVRTPF_ASTC_6x6: - return PIXELFORMAT_ASTC_6x6; + return PIXELFORMAT_ASTC_6x6_UNORM; case ePVRTPF_ASTC_8x5: - return PIXELFORMAT_ASTC_8x5; + return PIXELFORMAT_ASTC_8x5_UNORM; case ePVRTPF_ASTC_8x6: - return PIXELFORMAT_ASTC_8x6; + return PIXELFORMAT_ASTC_8x6_UNORM; case ePVRTPF_ASTC_8x8: - return PIXELFORMAT_ASTC_8x8; + return PIXELFORMAT_ASTC_8x8_UNORM; case ePVRTPF_ASTC_10x5: - return PIXELFORMAT_ASTC_10x5; + return PIXELFORMAT_ASTC_10x5_UNORM; case ePVRTPF_ASTC_10x6: - return PIXELFORMAT_ASTC_10x6; + return PIXELFORMAT_ASTC_10x6_UNORM; case ePVRTPF_ASTC_10x8: - return PIXELFORMAT_ASTC_10x8; + return PIXELFORMAT_ASTC_10x8_UNORM; case ePVRTPF_ASTC_10x10: - return PIXELFORMAT_ASTC_10x10; + return PIXELFORMAT_ASTC_10x10_UNORM; case ePVRTPF_ASTC_12x10: - return PIXELFORMAT_ASTC_12x10; + return PIXELFORMAT_ASTC_12x10_UNORM; case ePVRTPF_ASTC_12x12: - return PIXELFORMAT_ASTC_12x12; + return PIXELFORMAT_ASTC_12x12_UNORM; default: return PIXELFORMAT_UNKNOWN; } From bd55100d56f150d03a07dda4a05f0d3a361b4a00 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 14 Oct 2023 15:02:28 -0300 Subject: [PATCH 32/36] metal: fix compile error --- src/modules/graphics/metal/Shader.mm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/modules/graphics/metal/Shader.mm b/src/modules/graphics/metal/Shader.mm index 5929e73ab..c9ffb8f21 100644 --- a/src/modules/graphics/metal/Shader.mm +++ b/src/modules/graphics/metal/Shader.mm @@ -1087,8 +1087,7 @@ id Shader::getCachedRenderPipeline(const RenderPipelineK MTLRenderPipelineColorAttachmentDescriptor *attachment = desc.colorAttachments[i]; - bool isSRGB = false; - auto formatdesc = Metal::convertPixelFormat(device, format, isSRGB); + auto formatdesc = Metal::convertPixelFormat(device, format); attachment.pixelFormat = formatdesc.format; if (key.blend.enable) @@ -1124,8 +1123,7 @@ id Shader::getCachedRenderPipeline(const RenderPipelineK { // We already don't really support metal on older systems, this just // silences a compiler warning about it. - bool isSRGB = false; - auto formatdesc = Metal::convertPixelFormat(device, dsformat, isSRGB); + auto formatdesc = Metal::convertPixelFormat(device, dsformat); if (isPixelFormatDepth(dsformat)) desc.depthAttachmentPixelFormat = formatdesc.format; if (isPixelFormatStencil(dsformat)) From 8c13943f64750ab3f4b962e9716c003c9917a53e Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 14 Oct 2023 20:48:21 -0300 Subject: [PATCH 33/36] ImageData can track whether they're meant to be loaded into a Texture with a non-sRGB format when gamma correct rendering is enabled. Fixes #1556. * Add ImageData/CompressedImageData:setLinear and ImageData/CompressedImageData:isLinear. The flag is used as a hint when loading a texture from the data to determine if the format should not be treated as sRGB-encoded. The 'linear' flag in newImage overrides this. * love.graphics.readbackTexture automatically sets the linear flag on ImageData it returns when the texture's format is linear. This allows an ImageData generated via readback to be fed back into a new Texture and the format will match the original Canvas. * Also clean up some image decoding code. --- src/common/pixelformat.cpp | 10 +-- src/modules/graphics/GraphicsReadback.cpp | 4 +- src/modules/graphics/GraphicsReadback.h | 1 + src/modules/graphics/Texture.cpp | 6 +- src/modules/image/CompressedImageData.cpp | 18 ++++-- src/modules/image/CompressedImageData.h | 4 +- src/modules/image/CompressedSlice.cpp | 2 - src/modules/image/CompressedSlice.h | 2 - src/modules/image/FormatHandler.cpp | 2 +- src/modules/image/FormatHandler.h | 3 +- src/modules/image/ImageData.cpp | 9 ++- src/modules/image/ImageData.h | 3 +- src/modules/image/ImageDataBase.cpp | 11 ++++ src/modules/image/ImageDataBase.h | 5 +- src/modules/image/magpie/ASTCHandler.cpp | 4 +- src/modules/image/magpie/ASTCHandler.h | 2 +- src/modules/image/magpie/KTXHandler.cpp | 56 ++++++++--------- src/modules/image/magpie/KTXHandler.h | 2 +- src/modules/image/magpie/PKMHandler.cpp | 4 +- src/modules/image/magpie/PKMHandler.h | 2 +- src/modules/image/magpie/PVRHandler.cpp | 7 ++- src/modules/image/magpie/PVRHandler.h | 2 +- src/modules/image/magpie/ddsHandler.cpp | 61 +++++++++++-------- src/modules/image/magpie/ddsHandler.h | 2 +- .../image/wrap_CompressedImageData.cpp | 16 +++++ src/modules/image/wrap_ImageData.cpp | 16 +++++ 26 files changed, 149 insertions(+), 105 deletions(-) diff --git a/src/common/pixelformat.cpp b/src/common/pixelformat.cpp index 42325510f..ce8a3a690 100644 --- a/src/common/pixelformat.cpp +++ b/src/common/pixelformat.cpp @@ -364,11 +364,8 @@ PixelFormat getSRGBPixelFormat(PixelFormat format) case PIXELFORMAT_ASTC_10x10_UNORM: return PIXELFORMAT_ASTC_10x10_sRGB; case PIXELFORMAT_ASTC_12x10_UNORM: return PIXELFORMAT_ASTC_12x10_sRGB; case PIXELFORMAT_ASTC_12x12_UNORM: return PIXELFORMAT_ASTC_12x12_sRGB; - default: - break; + default: return format; } - - return format; } PixelFormat getLinearPixelFormat(PixelFormat format) @@ -398,11 +395,8 @@ PixelFormat getLinearPixelFormat(PixelFormat format) case PIXELFORMAT_ASTC_10x10_sRGB: return PIXELFORMAT_ASTC_10x10_UNORM; case PIXELFORMAT_ASTC_12x10_sRGB: return PIXELFORMAT_ASTC_12x10_UNORM; case PIXELFORMAT_ASTC_12x12_sRGB: return PIXELFORMAT_ASTC_12x12_UNORM; - default: - break; + default: return format; } - - return format; } size_t getPixelFormatBlockSize(PixelFormat format) diff --git a/src/modules/graphics/GraphicsReadback.cpp b/src/modules/graphics/GraphicsReadback.cpp index 935499ab5..0289bddf7 100644 --- a/src/modules/graphics/GraphicsReadback.cpp +++ b/src/modules/graphics/GraphicsReadback.cpp @@ -81,6 +81,7 @@ GraphicsReadback::GraphicsReadback(Graphics *gfx, ReadbackMethod method, Texture } textureFormat = getLinearPixelFormat(texture->getPixelFormat()); + isFormatLinear = isGammaCorrect() && !isPixelFormatSRGB(texture->getPixelFormat()); if (!image::ImageData::validPixelFormat(textureFormat)) { @@ -96,7 +97,7 @@ GraphicsReadback::GraphicsReadback(Graphics *gfx, ReadbackMethod method, Texture if (isRT && !caps.features[Graphics::FEATURE_COPY_RENDER_TARGET_TO_BUFFER]) throw love::Exception("readbackTextureAsync is not supported on this system."); else if (!isRT && !caps.features[Graphics::FEATURE_COPY_TEXTURE_TO_BUFFER]) - throw love::Exception("readbackTextureAsync a with non-render-target textures is not supported on this system."); + throw love::Exception("readbackTextureAsync with a non-render-target texture is not supported on this system."); } else { @@ -158,6 +159,7 @@ void *GraphicsReadback::prepareReadbackDest(size_t size) throw love::Exception("The love.image module must be loaded for readbackTexture."); imageData.set(module->newImageData(rect.w, rect.h, textureFormat, nullptr), Acquire::NORETAIN); + imageData->setLinear(isFormatLinear); return imageData->getData(); } } diff --git a/src/modules/graphics/GraphicsReadback.h b/src/modules/graphics/GraphicsReadback.h index 0524d4c2b..8990314d3 100644 --- a/src/modules/graphics/GraphicsReadback.h +++ b/src/modules/graphics/GraphicsReadback.h @@ -103,6 +103,7 @@ protected: StrongRef imageData; Rect rect = {}; PixelFormat textureFormat = PIXELFORMAT_UNKNOWN; + bool isFormatLinear = false; int imageDataX = 0; int imageDataY = 0; diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 4d0e59fcf..2071ce6f1 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -203,7 +203,7 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) love::image::ImageDataBase *slice = slices->get(0, 0); format = slice->getFormat(); - if (isGammaCorrect() && !settings.linear) + if (isGammaCorrect() && !slice->isLinear()) format = getSRGBPixelFormat(format); pixelWidth = slice->getWidth(); @@ -886,6 +886,7 @@ bool Texture::Slices::validate() const int w = firstdata->getWidth(); int h = firstdata->getHeight(); PixelFormat format = firstdata->getFormat(); + bool linear = firstdata->isLinear(); if (textureType == TEXTURE_CUBE && w != h) throw love::Exception("Cube textures must have equal widths and heights for each cube face."); @@ -925,6 +926,9 @@ bool Texture::Slices::validate() const if (format != slicedata->getFormat()) throw love::Exception("All texture slices and mipmaps must have the same pixel format."); + + if (linear != slicedata->isLinear()) + throw love::Exception("All texture slices and mipmaps must have the same linear setting."); } mipw = std::max(mipw / 2, 1); diff --git a/src/modules/image/CompressedImageData.cpp b/src/modules/image/CompressedImageData.cpp index 0ff04cb5d..724367a12 100644 --- a/src/modules/image/CompressedImageData.cpp +++ b/src/modules/image/CompressedImageData.cpp @@ -30,7 +30,6 @@ love::Type CompressedImageData::type("CompressedImageData", &Data::type); CompressedImageData::CompressedImageData(const std::list &formats, Data *filedata) : format(PIXELFORMAT_UNKNOWN) - , sRGB(false) { FormatHandler *parser = nullptr; @@ -46,7 +45,7 @@ CompressedImageData::CompressedImageData(const std::list &forma if (parser == nullptr) throw love::Exception("Could not parse compressed data: Unknown format."); - memory = parser->parseCompressed(filedata, dataImages, format, sRGB); + memory = parser->parseCompressed(filedata, dataImages, format); if (memory == nullptr) throw love::Exception("Could not parse compressed data."); @@ -56,11 +55,14 @@ CompressedImageData::CompressedImageData(const std::list &forma if (dataImages.size() == 0 || memory->getSize() == 0) throw love::Exception("Could not parse compressed data: No valid data?"); + + // This throws away some information the decoder could give us, but we + // can't really rely on it I think... + format = getLinearPixelFormat(format); } CompressedImageData::CompressedImageData(const CompressedImageData &c) : format(c.format) - , sRGB(c.sRGB) { memory.set(c.memory->clone(), Acquire::NORETAIN); @@ -134,9 +136,15 @@ PixelFormat CompressedImageData::getFormat() const return format; } -bool CompressedImageData::isSRGB() const +void CompressedImageData::setLinear(bool linear) { - return sRGB; + for (auto &slice : dataImages) + slice->setLinear(linear); +} + +bool CompressedImageData::isLinear() const +{ + return dataImages.empty() ? false : dataImages[0]->isLinear(); } CompressedSlice *CompressedImageData::getSlice(int slice, int miplevel) const diff --git a/src/modules/image/CompressedImageData.h b/src/modules/image/CompressedImageData.h index e834935b1..70e55cc19 100644 --- a/src/modules/image/CompressedImageData.h +++ b/src/modules/image/CompressedImageData.h @@ -93,14 +93,14 @@ public: **/ PixelFormat getFormat() const; - bool isSRGB() const; + void setLinear(bool linear); + bool isLinear() const; CompressedSlice *getSlice(int slice, int miplevel) const; protected: PixelFormat format; - bool sRGB; // Single block of memory containing all of the sub-images. StrongRef memory; diff --git a/src/modules/image/CompressedSlice.cpp b/src/modules/image/CompressedSlice.cpp index a4ab37d6f..f2116a1d9 100644 --- a/src/modules/image/CompressedSlice.cpp +++ b/src/modules/image/CompressedSlice.cpp @@ -31,7 +31,6 @@ CompressedSlice::CompressedSlice(PixelFormat format, int width, int height, Byte , memory(memory) , offset(offset) , dataSize(size) - , sRGB(false) { } @@ -40,7 +39,6 @@ CompressedSlice::CompressedSlice(const CompressedSlice &s) , memory(s.memory) , offset(s.offset) , dataSize(s.dataSize) - , sRGB(s.sRGB) { } diff --git a/src/modules/image/CompressedSlice.h b/src/modules/image/CompressedSlice.h index 581641b9c..09d009adc 100644 --- a/src/modules/image/CompressedSlice.h +++ b/src/modules/image/CompressedSlice.h @@ -46,7 +46,6 @@ public: CompressedSlice *clone() const override; void *getData() const override { return (uint8 *) memory->getData() + offset; } size_t getSize() const override { return dataSize; } - bool isSRGB() const override { return sRGB; } size_t getOffset() const { return offset; } private: @@ -54,7 +53,6 @@ private: StrongRef memory; size_t offset; size_t dataSize; - bool sRGB; }; // CompressedSlice diff --git a/src/modules/image/FormatHandler.cpp b/src/modules/image/FormatHandler.cpp index b75b9a226..692d38e70 100644 --- a/src/modules/image/FormatHandler.cpp +++ b/src/modules/image/FormatHandler.cpp @@ -60,7 +60,7 @@ bool FormatHandler::canParseCompressed(Data* /*data*/) return false; } -StrongRef FormatHandler::parseCompressed(Data* /*filedata*/, std::vector>& /*images*/, PixelFormat& /*format*/, bool& /*sRGB*/) +StrongRef FormatHandler::parseCompressed(Data* /*filedata*/, std::vector>& /*images*/, PixelFormat& /*format*/) { throw love::Exception("Compressed image parsing is not implemented for this format backend."); } diff --git a/src/modules/image/FormatHandler.h b/src/modules/image/FormatHandler.h index 9fc6cab16..762905f82 100644 --- a/src/modules/image/FormatHandler.h +++ b/src/modules/image/FormatHandler.h @@ -106,13 +106,12 @@ public: * @param[out] images The list of sub-images generated. Byte data is a * pointer to the returned data. * @param[out] format The format of the Compressed Data. - * @param[out] sRGB Whether the texture is sRGB-encoded. * * @return The single block of memory containing the parsed images. **/ virtual StrongRef parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB); + PixelFormat &format); /** * Frees raw pixel memory allocated by the format handler. diff --git a/src/modules/image/ImageData.cpp b/src/modules/image/ImageData.cpp index 108a945ae..377569cc3 100644 --- a/src/modules/image/ImageData.cpp +++ b/src/modules/image/ImageData.cpp @@ -152,6 +152,10 @@ void ImageData::decode(Data *data) else delete[] this->data; + // This throws away some information the decoder could give us, but we + // can't really rely on it I think... + decodedimage.format = getLinearPixelFormat(decodedimage.format); + this->width = decodedimage.width; this->height = decodedimage.height; this->data = decodedimage.data; @@ -247,11 +251,6 @@ void *ImageData::getData() const return data; } -bool ImageData::isSRGB() const -{ - return false; -} - bool ImageData::inside(int x, int y) const { return x >= 0 && x < getWidth() && y >= 0 && y < getHeight(); diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index fa43a848c..c0fad8dba 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -62,7 +62,7 @@ public: static love::Type type; ImageData(Data *data); - ImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8_UNORM); + ImageData(int width, int height, PixelFormat format); ImageData(int width, int height, PixelFormat format, void *data, bool own); ImageData(const ImageData &c); virtual ~ImageData(); @@ -116,7 +116,6 @@ public: ImageData *clone() const override; void *getData() const override; size_t getSize() const override; - bool isSRGB() const override; size_t getPixelSize() const; diff --git a/src/modules/image/ImageDataBase.cpp b/src/modules/image/ImageDataBase.cpp index 1e7248c9c..56b698757 100644 --- a/src/modules/image/ImageDataBase.cpp +++ b/src/modules/image/ImageDataBase.cpp @@ -29,6 +29,7 @@ ImageDataBase::ImageDataBase(PixelFormat format, int width, int height) : format(format) , width(width) , height(height) + , linear(false) { } @@ -47,5 +48,15 @@ int ImageDataBase::getHeight() const return height; } +void ImageDataBase::setLinear(bool linear) +{ + this->linear = linear; +} + +bool ImageDataBase::isLinear() const +{ + return linear; +} + } // image } // love diff --git a/src/modules/image/ImageDataBase.h b/src/modules/image/ImageDataBase.h index 0f4f523ee..237f9872f 100644 --- a/src/modules/image/ImageDataBase.h +++ b/src/modules/image/ImageDataBase.h @@ -40,7 +40,8 @@ public: int getWidth() const; int getHeight() const; - virtual bool isSRGB() const = 0; + void setLinear(bool linear); + bool isLinear() const; protected: @@ -50,6 +51,8 @@ protected: int width; int height; + bool linear; + }; // ImageDataBase } // image diff --git a/src/modules/image/magpie/ASTCHandler.cpp b/src/modules/image/magpie/ASTCHandler.cpp index fb9a395c2..1f56d6d3f 100644 --- a/src/modules/image/magpie/ASTCHandler.cpp +++ b/src/modules/image/magpie/ASTCHandler.cpp @@ -105,7 +105,7 @@ bool ASTCHandler::canParseCompressed(Data *data) return true; } -StrongRef ASTCHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef ASTCHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format) { if (!canParseCompressed(filedata)) throw love::Exception("Could not decode compressed data (not an .astc file?)"); @@ -138,8 +138,6 @@ StrongRef ASTCHandler::parseCompressed(Data *filedata, std::vector parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB) override; + PixelFormat &format) override; }; // ASTCHandler diff --git a/src/modules/image/magpie/KTXHandler.cpp b/src/modules/image/magpie/KTXHandler.cpp index 758642b68..37313735c 100644 --- a/src/modules/image/magpie/KTXHandler.cpp +++ b/src/modules/image/magpie/KTXHandler.cpp @@ -137,10 +137,8 @@ enum KTXGLInternalFormat KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD }; -PixelFormat convertFormat(uint32 glformat, bool &sRGB) +PixelFormat convertFormat(uint32 glformat) { - sRGB = false; - // hnnngg ASTC... switch (glformat) @@ -160,18 +158,15 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB) case KTX_GL_COMPRESSED_RGB8_ETC2: return PIXELFORMAT_ETC2_RGB_UNORM; case KTX_GL_COMPRESSED_SRGB8_ETC2: - sRGB = true; - return PIXELFORMAT_ETC2_RGB_UNORM; + return PIXELFORMAT_ETC2_RGB_sRGB; case KTX_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: return PIXELFORMAT_ETC2_RGBA1_UNORM; case KTX_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: - sRGB = true; - return PIXELFORMAT_ETC2_RGBA1_UNORM; + return PIXELFORMAT_ETC2_RGBA1_sRGB; case KTX_GL_COMPRESSED_RGBA8_ETC2_EAC: return PIXELFORMAT_ETC2_RGBA_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: - sRGB = true; - return PIXELFORMAT_ETC2_RGBA_UNORM; + return PIXELFORMAT_ETC2_RGBA_sRGB; // PVRTC. case KTX_GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: @@ -185,15 +180,15 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB) // DXT. case KTX_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: - sRGB = true; + return PIXELFORMAT_DXT1_sRGB; case KTX_GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return PIXELFORMAT_DXT1_UNORM; case KTX_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: - sRGB = true; + return PIXELFORMAT_DXT3_sRGB; case KTX_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return PIXELFORMAT_DXT3_UNORM; case KTX_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - sRGB = true; + return PIXELFORMAT_DXT5_sRGB; case KTX_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return PIXELFORMAT_DXT5_UNORM; @@ -209,7 +204,7 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB) // BC6 and BC7. case KTX_GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: - sRGB = true; + return PIXELFORMAT_BC7_sRGB; case KTX_GL_COMPRESSED_RGBA_BPTC_UNORM: return PIXELFORMAT_BC7_UNORM; case KTX_GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: @@ -219,59 +214,59 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB) // ASTC. case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_4x4_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_4x4_KHR: return PIXELFORMAT_ASTC_4x4_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_5x4_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_5x4_KHR: return PIXELFORMAT_ASTC_5x4_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_5x5_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_5x5_KHR: return PIXELFORMAT_ASTC_5x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_6x5_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_6x5_KHR: return PIXELFORMAT_ASTC_6x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_6x6_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_6x6_KHR: return PIXELFORMAT_ASTC_6x6_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_8x5_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_8x5_KHR: return PIXELFORMAT_ASTC_8x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_8x6_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_8x6_KHR: return PIXELFORMAT_ASTC_8x6_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_8x8_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_8x8_KHR: return PIXELFORMAT_ASTC_8x8_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_10x5_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_10x5_KHR: return PIXELFORMAT_ASTC_10x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_10x6_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_10x6_KHR: return PIXELFORMAT_ASTC_10x6_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_10x8_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_10x8_KHR: return PIXELFORMAT_ASTC_10x8_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_10x10_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_10x10_KHR: return PIXELFORMAT_ASTC_10x10_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_12x10_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_12x10_KHR: return PIXELFORMAT_ASTC_12x10_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_12x12_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_12x12_KHR: return PIXELFORMAT_ASTC_12x12_UNORM; default: @@ -298,7 +293,7 @@ bool KTXHandler::canParseCompressed(Data *data) return true; } -StrongRef KTXHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef KTXHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format) { if (!canParseCompressed(filedata)) throw love::Exception("Could not decode compressed data (not a KTX file?)"); @@ -314,8 +309,7 @@ StrongRef KTXHandler::parseCompressed(Data *filedata, std::vector KTXHandler::parseCompressed(Data *filedata, std::vector parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB) override; + PixelFormat &format) override; }; // KTXHandler diff --git a/src/modules/image/magpie/PKMHandler.cpp b/src/modules/image/magpie/PKMHandler.cpp index 1fa13283f..746265aa3 100644 --- a/src/modules/image/magpie/PKMHandler.cpp +++ b/src/modules/image/magpie/PKMHandler.cpp @@ -114,7 +114,7 @@ bool PKMHandler::canParseCompressed(Data *data) return true; } -StrongRef PKMHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef PKMHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format) { if (!canParseCompressed(filedata)) throw love::Exception("Could not decode compressed data (not a PKM file?)"); @@ -148,8 +148,6 @@ StrongRef PKMHandler::parseCompressed(Data *filedata, std::vector parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB) override; + PixelFormat &format) override; }; // PKMHandler diff --git a/src/modules/image/magpie/PVRHandler.cpp b/src/modules/image/magpie/PVRHandler.cpp index 1259536ca..f30f01b8b 100644 --- a/src/modules/image/magpie/PVRHandler.cpp +++ b/src/modules/image/magpie/PVRHandler.cpp @@ -475,7 +475,7 @@ bool PVRHandler::canParseCompressed(Data *data) return false; } -StrongRef PVRHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef PVRHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format) { if (!canParseCompressed(filedata)) throw love::Exception("Could not decode compressed data (not a PVR file?)"); @@ -510,6 +510,9 @@ StrongRef PVRHandler::parseCompressed(Data *filedata, std::vector PVRHandler::parseCompressed(Data *filedata, std::vector parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB) override; + PixelFormat &format) override; }; // PVRHandler diff --git a/src/modules/image/magpie/ddsHandler.cpp b/src/modules/image/magpie/ddsHandler.cpp index 974dec24e..cfe903b1d 100644 --- a/src/modules/image/magpie/ddsHandler.cpp +++ b/src/modules/image/magpie/ddsHandler.cpp @@ -32,13 +32,10 @@ namespace image namespace magpie { -static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, bool &bgra) +static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat) { using namespace dds::dxinfo; - sRGB = false; - bgra = false; - switch (dxformat) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: @@ -65,9 +62,9 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b case DXGI_FORMAT_R8G8B8A8_TYPELESS: case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB); return PIXELFORMAT_RGBA8_UNORM; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return PIXELFORMAT_RGBA8_sRGB; case DXGI_FORMAT_R16G16_TYPELESS: case DXGI_FORMAT_R16G16_FLOAT: @@ -98,21 +95,21 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b case DXGI_FORMAT_BC1_TYPELESS: case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_BC1_UNORM_SRGB); return PIXELFORMAT_DXT1_UNORM; + case DXGI_FORMAT_BC1_UNORM_SRGB: + return PIXELFORMAT_DXT1_sRGB; case DXGI_FORMAT_BC2_TYPELESS: case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_BC2_UNORM_SRGB); return PIXELFORMAT_DXT3_UNORM; + case DXGI_FORMAT_BC2_UNORM_SRGB: + return PIXELFORMAT_DXT3_sRGB; case DXGI_FORMAT_BC3_TYPELESS: case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_BC3_UNORM_SRGB); return PIXELFORMAT_DXT5_UNORM; + case DXGI_FORMAT_BC3_UNORM_SRGB: + return PIXELFORMAT_DXT5_sRGB; case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC4_UNORM: @@ -136,10 +133,9 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_TYPELESS: + return PIXELFORMAT_BGRA8_UNORM; case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB); - bgra = true; - return PIXELFORMAT_RGBA8_UNORM; + return PIXELFORMAT_BGRA8_sRGB; case DXGI_FORMAT_BC6H_TYPELESS: case DXGI_FORMAT_BC6H_UF16: @@ -150,9 +146,9 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b case DXGI_FORMAT_BC7_TYPELESS: case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_BC7_UNORM_SRGB); return PIXELFORMAT_BC7_UNORM; + case DXGI_FORMAT_BC7_UNORM_SRGB: + return PIXELFORMAT_BC7_sRGB; default: return PIXELFORMAT_UNKNOWN; @@ -164,9 +160,13 @@ bool DDSHandler::canDecode(Data *data) using namespace dds::dxinfo; DXGIFormat dxformat = dds::getDDSPixelFormat(data->getData(), data->getSize()); - bool isSRGB = false; - bool bgra = false; - PixelFormat format = convertFormat(dxformat, isSRGB, bgra); + PixelFormat format = convertFormat(dxformat); + + // We convert BGRA to RGBA + if (format == PIXELFORMAT_BGRA8_UNORM) + format = PIXELFORMAT_RGBA8_UNORM; + else if (format == PIXELFORMAT_BGRA8_sRGB) + format = PIXELFORMAT_RGBA8_sRGB; return ImageData::validPixelFormat(format); } @@ -177,9 +177,19 @@ FormatHandler::DecodedImage DDSHandler::decode(Data *data) dds::Parser parser(data->getData(), data->getSize()); - bool isSRGB = false; + img.format = convertFormat(parser.getFormat()); + bool bgra = false; - img.format = convertFormat(parser.getFormat(), isSRGB, bgra); + if (img.format == PIXELFORMAT_BGRA8_UNORM) + { + img.format = PIXELFORMAT_RGBA8_UNORM; + bgra = true; + } + else if (img.format == PIXELFORMAT_BGRA8_sRGB) + { + img.format = PIXELFORMAT_RGBA8_sRGB; + bgra = true; + } if (!ImageData::validPixelFormat(img.format)) throw love::Exception("Could not parse DDS pixel data: Unsupported format."); @@ -229,14 +239,12 @@ bool DDSHandler::canParseCompressed(Data *data) return dds::isCompressedDDS(data->getData(), data->getSize()); } -StrongRef DDSHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef DDSHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format) { if (!dds::isCompressedDDS(filedata->getData(), filedata->getSize())) throw love::Exception("Could not decode compressed data (not a DDS file?)"); PixelFormat texformat = PIXELFORMAT_UNKNOWN; - bool isSRGB = false; - bool bgra = false; size_t dataSize = 0; @@ -245,7 +253,7 @@ StrongRef DDSHandler::parseCompressed(Data *filedata, std::vectorgetData(), filedata->getSize()); - texformat = convertFormat(parser.getFormat(), isSRGB, bgra); + texformat = convertFormat(parser.getFormat()); if (texformat == PIXELFORMAT_UNKNOWN) throw love::Exception("Could not parse compressed data: Unsupported format."); @@ -280,7 +288,6 @@ StrongRef DDSHandler::parseCompressed(Data *filedata, std::vector parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB) override; + PixelFormat &format) override; }; // DDSHandler diff --git a/src/modules/image/wrap_CompressedImageData.cpp b/src/modules/image/wrap_CompressedImageData.cpp index 15f8908e2..ee8655326 100644 --- a/src/modules/image/wrap_CompressedImageData.cpp +++ b/src/modules/image/wrap_CompressedImageData.cpp @@ -103,6 +103,20 @@ int w_CompressedImageData_getFormat(lua_State *L) return 1; } +int w_CompressedImageData_setLinear(lua_State *L) +{ + CompressedImageData *t = luax_checkcompressedimagedata(L, 1); + t->setLinear(luax_checkboolean(L, 2)); + return 0; +} + +int w_CompressedImageData_isLinear(lua_State *L) +{ + CompressedImageData *t = luax_checkcompressedimagedata(L, 1); + luax_pushboolean(L, t->isLinear()); + return 1; +} + static const luaL_Reg w_CompressedImageData_functions[] = { { "clone", w_CompressedImageData_clone }, @@ -111,6 +125,8 @@ static const luaL_Reg w_CompressedImageData_functions[] = { "getDimensions", w_CompressedImageData_getDimensions }, { "getMipmapCount", w_CompressedImageData_getMipmapCount }, { "getFormat", w_CompressedImageData_getFormat }, + { "setLinear", w_CompressedImageData_setLinear }, + { "isLinear", w_CompressedImageData_isLinear }, { 0, 0 }, }; diff --git a/src/modules/image/wrap_ImageData.cpp b/src/modules/image/wrap_ImageData.cpp index 754ad01c5..e717a0fb3 100644 --- a/src/modules/image/wrap_ImageData.cpp +++ b/src/modules/image/wrap_ImageData.cpp @@ -66,6 +66,20 @@ int w_ImageData_getFormat(lua_State *L) return 1; } +int w_ImageData_setLinear(lua_State *L) +{ + ImageData *t = luax_checkimagedata(L, 1); + t->setLinear(luax_checkboolean(L, 2)); + return 0; +} + +int w_ImageData_isLinear(lua_State *L) +{ + ImageData *t = luax_checkimagedata(L, 1); + luax_pushboolean(L, t->isLinear()); + return 1; +} + int w_ImageData_getWidth(lua_State *L) { ImageData *t = luax_checkimagedata(L, 1); @@ -314,6 +328,8 @@ static const luaL_Reg w_ImageData_functions[] = { { "clone", w_ImageData_clone }, { "getFormat", w_ImageData_getFormat }, + { "setLinear", w_ImageData_setLinear }, + { "isLinear", w_ImageData_isLinear }, { "getWidth", w_ImageData_getWidth }, { "getHeight", w_ImageData_getHeight }, { "getDimensions", w_ImageData_getDimensions }, From 5a0a6a1a27dec0fbd429c98a8c4b11989fb0b719 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Fri, 20 Oct 2023 20:19:30 -0300 Subject: [PATCH 34/36] All constructors for making a TrueType font take an optional settings table. This supersedes the existing optional hinting and dpi scale parameters. The table's fields are: { hinting = "normal", dpiscale = 1, -- nil will default to the current window DPI scale. } --- src/common/Optional.h | 2 +- src/modules/font/Font.cpp | 16 +--- src/modules/font/Font.h | 7 +- src/modules/font/TrueTypeRasterizer.h | 7 ++ src/modules/font/freetype/Font.cpp | 15 ++-- src/modules/font/freetype/Font.h | 3 +- .../font/freetype/TrueTypeRasterizer.cpp | 8 +- .../font/freetype/TrueTypeRasterizer.h | 2 +- src/modules/font/wrap_Font.cpp | 81 ++++++++++++------- src/modules/graphics/Deprecations.cpp | 6 +- src/modules/graphics/Graphics.cpp | 9 ++- src/modules/graphics/Graphics.h | 2 +- 12 files changed, 84 insertions(+), 74 deletions(-) diff --git a/src/common/Optional.h b/src/common/Optional.h index fe3b4b2ef..d0fc11ea9 100644 --- a/src/common/Optional.h +++ b/src/common/Optional.h @@ -46,7 +46,7 @@ struct Optional hasValue = true; } - T get(T defaultVal) + T get(T defaultVal) const { return hasValue ? value : defaultVal; } diff --git a/src/modules/font/Font.cpp b/src/modules/font/Font.cpp index 818e3facf..f3f85bfa5 100644 --- a/src/modules/font/Font.cpp +++ b/src/modules/font/Font.cpp @@ -45,14 +45,9 @@ Font::Font() defaultFontData.set(new data::ByteData(fontdata, rawsize, true), Acquire::NORETAIN); } -Rasterizer *Font::newTrueTypeRasterizer(int size, TrueTypeRasterizer::Hinting hinting) +Rasterizer *Font::newTrueTypeRasterizer(int size, const TrueTypeRasterizer::Settings &settings) { - return newTrueTypeRasterizer(defaultFontData.get(), size, hinting); -} - -Rasterizer *Font::newTrueTypeRasterizer(int size, float dpiscale, TrueTypeRasterizer::Hinting hinting) -{ - return newTrueTypeRasterizer(defaultFontData.get(), size, dpiscale, hinting); + return newTrueTypeRasterizer(defaultFontData.get(), size, settings); } Rasterizer *Font::newBMFontRasterizer(love::filesystem::FileData *fontdef, const std::vector &images, float dpiscale) @@ -78,12 +73,7 @@ Rasterizer *Font::newImageRasterizer(love::image::ImageData *data, const std::st throw love::Exception("UTF-8 decoding error: %s", e.what()); } - return newImageRasterizer(data, &glyphs[0], (int) glyphs.size(), extraspacing, dpiscale); -} - -Rasterizer *Font::newImageRasterizer(love::image::ImageData *data, uint32 *glyphs, int numglyphs, int extraspacing, float dpiscale) -{ - return new ImageRasterizer(data, glyphs, numglyphs, extraspacing, dpiscale); + return new ImageRasterizer(data, glyphs.data(), (int) glyphs.size(), extraspacing, dpiscale); } GlyphData *Font::newGlyphData(Rasterizer *r, const std::string &text) diff --git a/src/modules/font/Font.h b/src/modules/font/Font.h index ed01557df..3b217a33a 100644 --- a/src/modules/font/Font.h +++ b/src/modules/font/Font.h @@ -48,15 +48,12 @@ public: virtual Rasterizer *newRasterizer(love::filesystem::FileData *data) = 0; - virtual Rasterizer *newTrueTypeRasterizer(int size, TrueTypeRasterizer::Hinting hinting); - virtual Rasterizer *newTrueTypeRasterizer(int size, float dpiscale, TrueTypeRasterizer::Hinting hinting); - virtual Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, TrueTypeRasterizer::Hinting hinting) = 0; - virtual Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, float dpiscale, TrueTypeRasterizer::Hinting hinting) = 0; + Rasterizer *newTrueTypeRasterizer(int size, const TrueTypeRasterizer::Settings &settings); + virtual Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, const TrueTypeRasterizer::Settings &settings) = 0; virtual Rasterizer *newBMFontRasterizer(love::filesystem::FileData *fontdef, const std::vector &images, float dpiscale); virtual Rasterizer *newImageRasterizer(love::image::ImageData *data, const std::string &glyphs, int extraspacing, float dpiscale); - virtual Rasterizer *newImageRasterizer(love::image::ImageData *data, uint32 *glyphs, int length, int extraspacing, float dpiscale); virtual GlyphData *newGlyphData(Rasterizer *r, const std::string &glyph); virtual GlyphData *newGlyphData(Rasterizer *r, uint32 glyph); diff --git a/src/modules/font/TrueTypeRasterizer.h b/src/modules/font/TrueTypeRasterizer.h index 62b225927..62d7253ab 100644 --- a/src/modules/font/TrueTypeRasterizer.h +++ b/src/modules/font/TrueTypeRasterizer.h @@ -24,6 +24,7 @@ // LOVE #include "Rasterizer.h" #include "common/StringMap.h" +#include "common/Optional.h" namespace love { @@ -44,6 +45,12 @@ public: HINTING_MAX_ENUM }; + struct Settings + { + Hinting hinting = HINTING_NORMAL; + OptionalFloat dpiScale; + }; + virtual ~TrueTypeRasterizer() {} static bool getConstant(const char *in, Hinting &out); diff --git a/src/modules/font/freetype/Font.cpp b/src/modules/font/freetype/Font.cpp index ec7fe9c27..9a52f7b08 100644 --- a/src/modules/font/freetype/Font.cpp +++ b/src/modules/font/freetype/Font.cpp @@ -49,26 +49,21 @@ Font::~Font() Rasterizer *Font::newRasterizer(love::filesystem::FileData *data) { if (TrueTypeRasterizer::accepts(library, data)) - return newTrueTypeRasterizer(data, 12, TrueTypeRasterizer::HINTING_NORMAL); + return newTrueTypeRasterizer(data, 12, font::TrueTypeRasterizer::Settings()); else if (BMFontRasterizer::accepts(data)) return newBMFontRasterizer(data, {}, 1.0f); throw love::Exception("Invalid font file: %s", data->getFilename().c_str()); } -Rasterizer *Font::newTrueTypeRasterizer(love::Data *data, int size, TrueTypeRasterizer::Hinting hinting) +Rasterizer *Font::newTrueTypeRasterizer(love::Data *data, int size, const font::TrueTypeRasterizer::Settings &settings) { - float dpiscale = 1.0f; + float defaultdpiscale = 1.0f; auto window = Module::getInstance(Module::M_WINDOW); if (window != nullptr) - dpiscale = window->getDPIScale(); + defaultdpiscale = window->getDPIScale(); - return newTrueTypeRasterizer(data, size, dpiscale, hinting); -} - -Rasterizer *Font::newTrueTypeRasterizer(love::Data *data, int size, float dpiscale, TrueTypeRasterizer::Hinting hinting) -{ - return new TrueTypeRasterizer(library, data, size, dpiscale, hinting); + return new TrueTypeRasterizer(library, data, size, settings, defaultdpiscale); } const char *Font::getName() const diff --git a/src/modules/font/freetype/Font.h b/src/modules/font/freetype/Font.h index 8d023cf48..0a4c70e86 100644 --- a/src/modules/font/freetype/Font.h +++ b/src/modules/font/freetype/Font.h @@ -45,8 +45,7 @@ public: // Implements Font Rasterizer *newRasterizer(love::filesystem::FileData *data) override; - Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, TrueTypeRasterizer::Hinting hinting) override; - Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, float dpiscale, TrueTypeRasterizer::Hinting hinting) override; + Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, const font::TrueTypeRasterizer::Settings &settings) override; // Implement Module const char *getName() const override; diff --git a/src/modules/font/freetype/TrueTypeRasterizer.cpp b/src/modules/font/freetype/TrueTypeRasterizer.cpp index b48f63cb2..1baed329a 100644 --- a/src/modules/font/freetype/TrueTypeRasterizer.cpp +++ b/src/modules/font/freetype/TrueTypeRasterizer.cpp @@ -33,12 +33,12 @@ namespace font namespace freetype { -TrueTypeRasterizer::TrueTypeRasterizer(FT_Library library, love::Data *data, int size, float dpiscale, Hinting hinting) +TrueTypeRasterizer::TrueTypeRasterizer(FT_Library library, love::Data *data, int size, const Settings &settings, float defaultdpiscale) : data(data) - , hinting(hinting) + , hinting(settings.hinting) { - this->dpiScale = dpiscale; - size = floorf(size * dpiscale + 0.5f); + dpiScale = settings.dpiScale.get(defaultdpiscale); + size = floorf(size * dpiScale + 0.5f); if (size <= 0) throw love::Exception("Invalid TrueType font size: %d", size); diff --git a/src/modules/font/freetype/TrueTypeRasterizer.h b/src/modules/font/freetype/TrueTypeRasterizer.h index e97e91967..e26b79646 100644 --- a/src/modules/font/freetype/TrueTypeRasterizer.h +++ b/src/modules/font/freetype/TrueTypeRasterizer.h @@ -44,7 +44,7 @@ class TrueTypeRasterizer : public love::font::TrueTypeRasterizer { public: - TrueTypeRasterizer(FT_Library library, love::Data *data, int size, float dpiscale, Hinting hinting); + TrueTypeRasterizer(FT_Library library, love::Data *data, int size, const Settings &settings, float defaultdpiscale); virtual ~TrueTypeRasterizer(); // Implement Rasterizer diff --git a/src/modules/font/wrap_Font.cpp b/src/modules/font/wrap_Font.cpp index 499583b03..e2ec84f08 100644 --- a/src/modules/font/wrap_Font.cpp +++ b/src/modules/font/wrap_Font.cpp @@ -64,6 +64,42 @@ int w_newRasterizer(lua_State *L) } } +static TrueTypeRasterizer::Settings luax_checktruetypesettings(lua_State* L, int startidx) +{ + TrueTypeRasterizer::Settings s; + + if (lua_type(L, startidx) == LUA_TSTRING) + { + // Legacy parameters. + const char *hintstr = lua_isnoneornil(L, startidx) ? nullptr : luaL_checkstring(L, startidx); + if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, s.hinting)) + luax_enumerror(L, "TrueType font hinting mode", TrueTypeRasterizer::getConstants(s.hinting), hintstr); + + if (!lua_isnoneornil(L, startidx + 1)) + s.dpiScale.set((float)luaL_checknumber(L, startidx + 1)); + } + else + { + luaL_checktype(L, startidx, LUA_TTABLE); + + lua_getfield(L, startidx, "hinting"); + if (!lua_isnoneornil(L, -1)) + { + const char *hintstr = luaL_checkstring(L, -1); + if (!TrueTypeRasterizer::getConstant(hintstr, s.hinting)) + luax_enumerror(L, "TrueType font hinting mode", TrueTypeRasterizer::getConstants(s.hinting), hintstr); + } + lua_pop(L, 1); + + lua_getfield(L, startidx, "dpiscale"); + if (!lua_isnoneornil(L, -1)) + s.dpiScale.set((float)luaL_checknumber(L, -1)); + lua_pop(L, 1); + } + + return s; +} + int w_newTrueTypeRasterizer(lua_State *L) { Rasterizer *t = nullptr; @@ -74,20 +110,20 @@ int w_newTrueTypeRasterizer(lua_State *L) // First argument is a number: use the default TrueType font. int size = (int) luaL_optinteger(L, 1, 13); - const char *hintstr = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2); - if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting)) - return luax_enumerror(L, "TrueType font hinting mode", TrueTypeRasterizer::getConstants(hinting), hintstr); + TrueTypeRasterizer::Settings settings; + if (!lua_isnoneornil(L, 2)) + settings = luax_checktruetypesettings(L, 2); - if (lua_isnoneornil(L, 3)) - luax_catchexcept(L, [&](){ t = instance()->newTrueTypeRasterizer(size, hinting); }); - else - { - float dpiscale = (float) luaL_checknumber(L, 3); - luax_catchexcept(L, [&](){ t = instance()->newTrueTypeRasterizer(size, dpiscale, hinting); }); - } + luax_catchexcept(L, [&](){ t = instance()->newTrueTypeRasterizer(size, settings); }); } else { + int size = (int) luaL_optinteger(L, 2, 12); + + TrueTypeRasterizer::Settings settings; + if (!lua_isnoneornil(L, 3)) + settings = luax_checktruetypesettings(L, 3); + love::Data *d = nullptr; if (luax_istype(L, 1, love::Data::type)) @@ -98,27 +134,10 @@ int w_newTrueTypeRasterizer(lua_State *L) else d = filesystem::luax_getfiledata(L, 1); - int size = (int) luaL_optinteger(L, 2, 12); - - const char *hintstr = lua_isnoneornil(L, 3) ? nullptr : luaL_checkstring(L, 3); - if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting)) - return luax_enumerror(L, "TrueType font hinting mode", TrueTypeRasterizer::getConstants(hinting), hintstr); - - if (lua_isnoneornil(L, 4)) - { - luax_catchexcept(L, - [&]() { t = instance()->newTrueTypeRasterizer(d, size, hinting); }, - [&](bool) { d->release(); } - ); - } - else - { - float dpiscale = (float) luaL_checknumber(L, 4); - luax_catchexcept(L, - [&]() { t = instance()->newTrueTypeRasterizer(d, size, dpiscale, hinting); }, - [&](bool) { d->release(); } - ); - } + luax_catchexcept(L, + [&]() { t = instance()->newTrueTypeRasterizer(d, size, settings); }, + [&](bool) { d->release(); } + ); } luax_pushtype(L, t); diff --git a/src/modules/graphics/Deprecations.cpp b/src/modules/graphics/Deprecations.cpp index 92a5d51c5..6e43a9350 100644 --- a/src/modules/graphics/Deprecations.cpp +++ b/src/modules/graphics/Deprecations.cpp @@ -74,12 +74,12 @@ void Deprecations::draw(Graphics *gfx) if (font.get() == nullptr) { - auto hinting = font::TrueTypeRasterizer::HINTING_NORMAL; + font::TrueTypeRasterizer::Settings settings; if (!isGammaCorrect() && gfx->getScreenDPIScale() <= 1.0) - hinting = font::TrueTypeRasterizer::HINTING_LIGHT; + settings.hinting = font::TrueTypeRasterizer::HINTING_LIGHT; - font.set(gfx->newDefaultFont(9, hinting), Acquire::NORETAIN); + font.set(gfx->newDefaultFont(9, settings), Acquire::NORETAIN); } gfx->flushBatchedDraws(); diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 3d32b727b..4704daabc 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -294,13 +294,13 @@ Font *Graphics::newFont(love::font::Rasterizer *data) return new Font(data, states.back().defaultSamplerState); } -Font *Graphics::newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting) +Font *Graphics::newDefaultFont(int size, const font::TrueTypeRasterizer::Settings &settings) { auto fontmodule = Module::getInstance(M_FONT); if (!fontmodule) throw love::Exception("Font module has not been loaded."); - StrongRef r(fontmodule->newTrueTypeRasterizer(size, hinting), Acquire::NORETAIN); + StrongRef r(fontmodule->newTrueTypeRasterizer(size, settings), Acquire::NORETAIN); return newFont(r.get()); } @@ -731,7 +731,10 @@ void Graphics::checkSetDefaultFont() // Create a new default font if we don't have one yet. if (!defaultFont.get()) - defaultFont.set(newDefaultFont(13, font::TrueTypeRasterizer::HINTING_NORMAL), Acquire::NORETAIN); + { + font::TrueTypeRasterizer::Settings settings; + defaultFont.set(newDefaultFont(13, settings), Acquire::NORETAIN); + } states.back().font.set(defaultFont.get()); } diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index d2989213d..32ac208b0 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -459,7 +459,7 @@ public: Quad *newQuad(Quad::Viewport v, double sw, double sh); Font *newFont(love::font::Rasterizer *data); - Font *newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting); + Font *newDefaultFont(int size, const font::TrueTypeRasterizer::Settings &settings); Video *newVideo(love::video::VideoStream *stream, float dpiscale); SpriteBatch *newSpriteBatch(Texture *texture, int size, BufferDataUsage usage); From 6aaf0b22bf0ff91fd48c8254de2b9689f8e33e7c Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Sat, 21 Oct 2023 13:55:43 -0300 Subject: [PATCH 35/36] Address some compiler warnings --- src/modules/data/wrap_ByteData.cpp | 2 +- src/modules/font/freetype/HarfbuzzShaper.cpp | 12 ++++++------ src/modules/font/freetype/HarfbuzzShaper.h | 2 +- src/modules/font/wrap_Font.cpp | 1 - src/modules/image/magpie/PVRHandler.cpp | 2 +- src/modules/sensor/sdl/Sensor.cpp | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/modules/data/wrap_ByteData.cpp b/src/modules/data/wrap_ByteData.cpp index e299cbae3..57ff5f975 100644 --- a/src/modules/data/wrap_ByteData.cpp +++ b/src/modules/data/wrap_ByteData.cpp @@ -56,7 +56,7 @@ int w_ByteData_setString(lua_State *L) if (size == 0) return 0; - if (offset < 0 || offset + size > (int64) t->getSize()) + if (offset < 0 || offset + (int64) size > (int64) t->getSize()) return luaL_error(L, "The given string offset and size don't fit within the Data's size."); memcpy((char *) t->getData() + (size_t) offset, str, size); diff --git a/src/modules/font/freetype/HarfbuzzShaper.cpp b/src/modules/font/freetype/HarfbuzzShaper.cpp index 70767dada..f7828cecf 100644 --- a/src/modules/font/freetype/HarfbuzzShaper.cpp +++ b/src/modules/font/freetype/HarfbuzzShaper.cpp @@ -153,18 +153,18 @@ void HarfbuzzShaper::computeBufferRanges(const ColoredCodepoints &codepoints, Ra hb_shape(hbFonts[rasti], hbb, nullptr, 0); - int glyphcount = (int)hb_buffer_get_length(hbb); + size_t glyphcount = (size_t)hb_buffer_get_length(hbb); const hb_glyph_info_t *glyphinfos = hb_buffer_get_glyph_infos(hbb, nullptr); hb_direction_t direction = hb_buffer_get_direction(hbb); fallbackranges.clear(); - for (int i = 0; i < glyphcount; i++) + for (size_t i = 0; i < glyphcount; i++) { if (isValidGlyph(glyphinfos[i].codepoint, codepoints.cps, glyphinfos[i].cluster)) { if (bufferranges.empty() || bufferranges.back().index != rasti || bufferranges.back().range.getMax() + 1 != i) - bufferranges.push_back({(int)rasti, (int)glyphinfos[i].cluster, Range(i, 1)}); + bufferranges.push_back({rasti, (int)glyphinfos[i].cluster, Range(i, 1)}); else bufferranges.back().range.last++; } @@ -247,7 +247,7 @@ void HarfbuzzShaper::computeGlyphPositions(const ColoredCodepoints &codepoints, // TODO: this doesn't handle situations where the user inserted a color // change in the middle of some characters that get combined into a single // cluster. - if (colors && colorindex < ncolors && codepoints.colors[colorindex].index == info.cluster) + if (colors && colorindex < ncolors && codepoints.colors[colorindex].index == (int)info.cluster) { colorToAdd.set(codepoints.colors[colorindex].color); colorindex++; @@ -273,7 +273,7 @@ void HarfbuzzShaper::computeGlyphPositions(const ColoredCodepoints &codepoints, continue; // This is a glyph index at this point, despite the name. - GlyphIndex gindex = { (int) info.codepoint, bufferrange.index }; + GlyphIndex gindex = { (int) info.codepoint, (int)bufferrange.index }; if (clustercodepoint == '\t' && isUsingSpacesForTab()) { @@ -390,7 +390,7 @@ int HarfbuzzShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ra if (newwidth > wraplimit) { // If this is the first character, wrap from the next one instead of this one. - int wrapindex = info.cluster > (int) range.first ? info.cluster : (int) range.first + 1; + int wrapindex = (int)info.cluster > (int)range.first ? (int)info.cluster : (int)range.first + 1; // Rewind to after the last seen space when wrapping. if (firstindexafterspace != -1) diff --git a/src/modules/font/freetype/HarfbuzzShaper.h b/src/modules/font/freetype/HarfbuzzShaper.h index 3a71a5b8b..8324b0a7c 100644 --- a/src/modules/font/freetype/HarfbuzzShaper.h +++ b/src/modules/font/freetype/HarfbuzzShaper.h @@ -53,7 +53,7 @@ private: struct BufferRange { - int index; + size_t index; int codepointStart; Range range; }; diff --git a/src/modules/font/wrap_Font.cpp b/src/modules/font/wrap_Font.cpp index e2ec84f08..8a843c413 100644 --- a/src/modules/font/wrap_Font.cpp +++ b/src/modules/font/wrap_Font.cpp @@ -103,7 +103,6 @@ static TrueTypeRasterizer::Settings luax_checktruetypesettings(lua_State* L, int int w_newTrueTypeRasterizer(lua_State *L) { Rasterizer *t = nullptr; - TrueTypeRasterizer::Hinting hinting = TrueTypeRasterizer::HINTING_NORMAL; if (lua_type(L, 1) == LUA_TNUMBER || lua_isnone(L, 1)) { diff --git a/src/modules/image/magpie/PVRHandler.cpp b/src/modules/image/magpie/PVRHandler.cpp index f30f01b8b..ef074f0f8 100644 --- a/src/modules/image/magpie/PVRHandler.cpp +++ b/src/modules/image/magpie/PVRHandler.cpp @@ -511,7 +511,7 @@ StrongRef PVRHandler::parseCompressed(Data *filedata, std::vector Sensor::getHandles() { std::vector nativeSensor; - for (const std::pair &data: sensors) + for (std::pair data : sensors) { if (data.second) nativeSensor.push_back(data.second); From 17362b68441e62fcd75c60b529181c79334a541e Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Mon, 30 Oct 2023 18:55:26 -0300 Subject: [PATCH 36/36] Restore no-parameter variant of love.graphics.setColorMask. --- src/modules/graphics/wrap_Graphics.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index c5b9648ce..27338cdc6 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -2355,7 +2355,11 @@ int w_setColorMask(lua_State *L) { ColorChannelMask mask; - if (lua_gettop(L) <= 1) + if (lua_isnoneornil(L, 1)) + { + mask.r = mask.g = mask.b = mask.a = true; + } + else if (lua_gettop(L) <= 1) { // Set all color components if a single argument is given. mask.r = mask.g = mask.b = mask.a = luax_checkboolean(L, 1);