diff --git a/libzhl/IsaacRepentance_static.cpp b/libzhl/IsaacRepentance_static.cpp index 352a60547..1d26f561a 100644 --- a/libzhl/IsaacRepentance_static.cpp +++ b/libzhl/IsaacRepentance_static.cpp @@ -201,6 +201,21 @@ bool Isaac::IsInGame() { return g_Manager->GetState() == 2 && g_Game; } +Vector * Isaac::WorldToScreen(Vector * ret, Vector* pos) { + Game * game = g_Game; + if (!game) { + ret = pos; + return ret; + } + float scale = g_DisplayPixelsPerPoint * g_PointScale; + Room* room = game->_room; + float f1 = floor((((g_WIDTH - 338.0f) * 0.5f + (pos->x - 60.0f) * 0.65f) * scale + 0.5f)); + float f2 = floor((((g_HEIGHT - 182.0f) * 0.5f + (pos->y - 140.0f) * 0.65f) * scale + 0.5f)); + ret->x = f1 / scale + room->_renderScrollOffset.x + game->_screenShakeOffset.x; + ret->y = f2 / scale + room->_renderScrollOffset.y + game->_screenShakeOffset.y; + return ret; +} + bool Entity_Player::AddSmeltedTrinket(int trinketID, bool firstTime) { bool trinketAdded = false; diff --git a/libzhl/LuaCore.cpp b/libzhl/LuaCore.cpp index bb6f484d9..fa4ad8915 100644 --- a/libzhl/LuaCore.cpp +++ b/libzhl/LuaCore.cpp @@ -737,6 +737,7 @@ namespace lua { const char* CollectionMenuMT = "CollectionMenu"; const char* ConsoleMT = "Console"; const char* ControllerSelectMenuMT = "ControllerSelectMenu"; + const char* CordMT = "Cord"; const char* ColorModifierMT = "ColorModifier"; const char* CustomChallengeMenuMT = "CustomChallengeMenu"; const char* CutscenesMenuMT = "CutscenesMenu"; @@ -788,6 +789,7 @@ namespace lua { const char* PlayerManagerMT = "PlayerManager"; const char* PocketItemMT = "PocketItem"; const char* PointMT = "Point"; + const char* PointDequeMT = "PointDeque"; const char* ProceduralEffectMT = "ProceduralEffect"; const char* ProceduralItemMT = "ProceduralItem"; const char* ProceduralItemManagerMT = "ProceduralItemManager"; diff --git a/libzhl/LuaCore.h b/libzhl/LuaCore.h index ee3ef65b5..b63e374ea 100644 --- a/libzhl/LuaCore.h +++ b/libzhl/LuaCore.h @@ -173,6 +173,7 @@ namespace lua { extern LIBZHL_API const char* ConsoleMT; extern LIBZHL_API const char* ControllerSelectMenuMT; extern LIBZHL_API const char* ColorModifierMT; + extern LIBZHL_API const char* CordMT; extern LIBZHL_API const char* CustomChallengeMenuMT; extern LIBZHL_API const char* CutscenesMenuMT; extern LIBZHL_API const char* GridEntitiesSaveStateVectorMT; @@ -223,6 +224,7 @@ namespace lua { extern LIBZHL_API const char* PlayerManagerMT; extern LIBZHL_API const char* PocketItemMT; extern LIBZHL_API const char* PointMT; + extern LIBZHL_API const char* PointDequeMT; extern LIBZHL_API const char* ProceduralEffectMT; extern LIBZHL_API const char* ProceduralItemMT; extern LIBZHL_API const char* ProceduralItemManagerMT; diff --git a/libzhl/functions/BeamRenderer.zhl b/libzhl/functions/BeamRenderer.zhl index f7672d38e..961e7d93d 100644 --- a/libzhl/functions/BeamRenderer.zhl +++ b/libzhl/functions/BeamRenderer.zhl @@ -12,7 +12,7 @@ static void BeamRenderer::End(); // we don't actually use Point here, just a deque, but for some reason // the deque insists that Point must be defined before BeamRenderer -struct BeamRenderer depends (ANM2, Point) { +struct BeamRenderer depends (ANM2, PointDeque) { {{ BeamRenderer(ANM2& anm2, unsigned int layer, bool useOverlayData, bool unkBool) : _anm2(anm2), _layer(layer), _useOverlayData(useOverlayData), _unkBool(unkBool) {} @@ -25,5 +25,5 @@ struct BeamRenderer depends (ANM2, Point) { unsigned int _layer : 0x4; bool _useOverlayData : 0x8; bool _unkBool : 0x9; - deque_Point _points : 0xc; -} : 0x30; \ No newline at end of file + PointDeque _points : 0xc; +} : 0x20; \ No newline at end of file diff --git a/libzhl/functions/Isaac.zhl b/libzhl/functions/Isaac.zhl index 544b99a39..8cfcba709 100644 --- a/libzhl/functions/Isaac.zhl +++ b/libzhl/functions/Isaac.zhl @@ -55,5 +55,6 @@ static __x86_64_output Vector Isaac::GetCollectibleSpawnPosition(Vector* target) struct Isaac { {{ LIBZHL_API static bool IsInGame(); + LIBZHL_API static Vector * WorldToScreen(Vector * buffer, Vector * pos); }} } : 0; diff --git a/libzhl/functions/Point.zhl b/libzhl/functions/Point.zhl index 850863de6..15199c8fc 100644 --- a/libzhl/functions/Point.zhl +++ b/libzhl/functions/Point.zhl @@ -1,11 +1,14 @@ -"558bec83ec10568bf1f30f1046": -__thiscall void Point::UpdateNormal(Vector* unk); - struct Point depends (Vector) { {{ - Point() : _pos(Vector()), _spritesheetCoordinate(0.0f), _width(1.0f) {} - Point(Vector const& pos, float spritesheetCoordinate, float width) : _pos(pos), _spritesheetCoordinate(spritesheetCoordinate), _width(width) {} + Point() : _pos(Vector()), _lastPos(_pos), _target(nullptr), _spritesheetCoordinate(0.0f), _width(1.0f), _fixed(false) {} + Point(Vector pos, Entity* target, float spritesheetCoordinate, float width, bool fixed) : _pos(pos), _lastPos(pos), _target(target), _spritesheetCoordinate(spritesheetCoordinate), _width(width) , _fixed(fixed) {} }} - Vector _pos : 0x0; - float _width : 0x8, _spritesheetCoordinate : 0xc; -} : 0x10; \ No newline at end of file + Vector _pos : 0x0, _lastPos : 0x8; + Entity * _target : 0x10; + float _width : 0x14, _spritesheetCoordinate : 0x18; + bool _fixed : 0x1c; +} : 0x20; + +struct PointDeque depends (Point) { + deque_Point deque : 0x0; +} : 0x14; \ No newline at end of file diff --git a/libzhl/functions/Room.zhl b/libzhl/functions/Room.zhl index e2d1f99c7..7eb18a377 100644 --- a/libzhl/functions/Room.zhl +++ b/libzhl/functions/Room.zhl @@ -87,7 +87,7 @@ __thiscall float Room::GetTimeScale(Vector* unused, Entity* ent); "558bec8b55??56578b02": __thiscall void Room::TriggerEffectRemoved(ItemConfig_Item* item, int unused); -struct Room depends (EntityList, RoomDescriptor, TemporaryEffects, RailManager) { +struct Room depends (EntityList, RoomDescriptor, TemporaryEffects, RailManager, Vector) { {{ inline Camera* GetCamera() { return *(Camera**)((char*)this + 0x11F8); } inline bool GetRedHeartDamage() { return *(bool*)((char*)this + 0x120C); } @@ -124,7 +124,8 @@ struct Room depends (EntityList, RoomDescriptor, TemporaryEffects, RailManager) GridEntity* _doors[8] : 0x724; uint32_t _doorGridPositions[8] : 0x744; int _roomClearDelay : 0x11ec; - Camera *_Camera : 0x11f8; + Camera *_Camera : 0x11f8; //0x11F8 + Vector _renderScrollOffset : 0x1204; bool _redHeartDamage : 0x120c; EntityList _entityList : 0x1218; int _greedWaveTimer : 0x7130; diff --git a/libzhl/functions/Vector2.zhl b/libzhl/functions/Vector2.zhl index 9854ec6e7..26c69e8cd 100644 --- a/libzhl/functions/Vector2.zhl +++ b/libzhl/functions/Vector2.zhl @@ -29,6 +29,20 @@ struct Vector { {{ y *= amount; return *this; } + + Vector& operator+=(const Vector& other) + { + x += other.x; + y += other.y; + return *this; + } + + Vector& operator-=(const Vector& other) + { + x -= other.x; + y -= other.y; + return *this; + } }} float x : 0x0, y : 0x4; } : 0x8; diff --git a/repentogon/LuaInterfaces/LuaBeamRenderer.cpp b/repentogon/LuaInterfaces/LuaBeamRenderer.cpp index 396b9b7eb..3f44fac46 100644 --- a/repentogon/LuaInterfaces/LuaBeamRenderer.cpp +++ b/repentogon/LuaInterfaces/LuaBeamRenderer.cpp @@ -48,12 +48,6 @@ LUA_FUNCTION(Lua_CreateBeamDummy) { return 1; } -void ConstructPoint(lua_State* L, Point& point, uint8_t offset) { - point._pos = *lua::GetUserdata(L, offset, lua::Metatables::VECTOR, "Vector"); - point._spritesheetCoordinate = (float)luaL_checknumber(L, offset+1); - point._width = (float)luaL_optnumber(L, offset+2, 1.0f); -} - LUA_FUNCTION(Lua_BeamAdd) { BeamRenderer* beam = lua::GetUserdata(L, 1, lua::metatables::BeamMT); Point point; @@ -62,9 +56,11 @@ LUA_FUNCTION(Lua_BeamAdd) { } else { - ConstructPoint(L, point, 2); + point._pos = *lua::GetUserdata(L, 2, lua::Metatables::VECTOR, "Vector"); + point._spritesheetCoordinate = (float)luaL_checknumber(L, 3); + point._width = (float)luaL_optnumber(L, 4, 1.0f); } - beam->_points.push_back(point); + beam->_points.deque.push_back(point); return 0; } @@ -74,7 +70,7 @@ LUA_FUNCTION(Lua_BeamRender) { int8_t error = -1; bool clearPoints = lua::luaL_optboolean(L, 2, true); - if (beam->_points.size() < 2) { + if (beam->_points.deque.size() < 2) { error = 0; goto funcEnd; } @@ -99,7 +95,7 @@ LUA_FUNCTION(Lua_BeamRender) { #pragma warning(suppress:4533) ColorMod color; - for (auto it = beam->_points.begin(); it != beam->_points.end(); ++it) { + for (auto it = beam->_points.deque.begin(); it != beam->_points.deque.end(); ++it) { g_BeamRenderer->Add(&it->_pos, &color, it->_width, it->_spritesheetCoordinate); } @@ -109,7 +105,7 @@ LUA_FUNCTION(Lua_BeamRender) { funcEnd: if (clearPoints) { - beam->_points.clear(); + beam->_points.deque.clear(); } if (error != -1) { @@ -234,10 +230,10 @@ LUA_FUNCTION(Lua_BeamRenderer__gc) { LUA_FUNCTION(Lua_BeamGetPoints) { BeamRenderer* beam = lua::GetUserdata(L, 1, lua::metatables::BeamMT); lua_newtable(L); - for (size_t i = 0; i < beam->_points.size(); ++i) { + for (size_t i = 0; i < beam->_points.deque.size(); ++i) { lua_pushinteger(L, i + 1); Point* ud = (Point*)lua_newuserdata(L, sizeof(Point)); - *ud = beam->_points[i]; + *ud = beam->_points.deque[i]; luaL_setmetatable(L, lua::metatables::PointMT); lua_rawset(L, -3); } @@ -266,60 +262,12 @@ LUA_FUNCTION(Lua_BeamSetPoints) { list.push_back(*lua::GetUserdata(L, -1, lua::metatables::PointMT)); lua_pop(L, 1); } - beam->_points = list; + beam->_points.deque = list; } return 0; } -LUA_FUNCTION(Lua_PointConstructor) { - Point point; - ConstructPoint(L, point, 1); - - Point* toLua = lua::place(L, lua::metatables::PointMT); - *toLua = point; - luaL_setmetatable(L, lua::metatables::PointMT); - - return 1; -} - -LUA_FUNCTION(Lua_PointGetSpritesheetCoordinate) { - Point* point = lua::GetUserdata(L, 1, lua::metatables::PointMT); - lua_pushnumber(L, point->_spritesheetCoordinate); - return 1; -} - -LUA_FUNCTION(Lua_PointSetSpritesheetCoordinate) { - Point* point = lua::GetUserdata(L, 1, lua::metatables::PointMT); - point->_spritesheetCoordinate = (float)luaL_checknumber(L, 2); - return 0; -} - -LUA_FUNCTION(Lua_PointGetWidth) { - Point* point = lua::GetUserdata(L, 1, lua::metatables::PointMT); - lua_pushnumber(L, point->_width); - return 1; -} - -LUA_FUNCTION(Lua_PointSetWidth) { - Point* point = lua::GetUserdata(L, 1, lua::metatables::PointMT); - point->_width = (float)luaL_checknumber(L, 2); - return 0; -} - -LUA_FUNCTION(Lua_PointGetPosition) { - Point* point = lua::GetUserdata(L, 1, lua::metatables::PointMT); - Vector* toLua = lua::luabridge::UserdataValue::place(L, lua::GetMetatableKey(lua::Metatables::VECTOR)); - *toLua = point->_pos; - return 1; -} - -LUA_FUNCTION(Lua_PointSetPosition) { - Point* point = lua::GetUserdata(L, 1, lua::metatables::PointMT); - point->_pos = *lua::GetUserdata(L, 2, lua::Metatables::VECTOR, "Vector"); - return 0; -} - static void RegisterBeamRenderer(lua_State* L) { luaL_Reg functions[] = { { "Add", Lua_BeamAdd}, @@ -334,24 +282,12 @@ static void RegisterBeamRenderer(lua_State* L) { { "SetUnkBool", Lua_BeamSetUnkBool}, { "GetPoints", Lua_BeamGetPoints}, { "SetPoints", Lua_BeamSetPoints}, + { "GetFixed", Lua_BeamGetPoints}, + { "SetFixed", Lua_BeamSetPoints}, { NULL, NULL } }; lua::RegisterNewClass(L, lua::metatables::BeamMT, lua::metatables::BeamMT, functions, Lua_BeamRenderer__gc); lua_register(L, lua::metatables::BeamMT, Lua_CreateBeamDummy); - - luaL_Reg pointFunctions[] = { - { "GetSpritesheetCoordinate", Lua_PointGetSpritesheetCoordinate}, - { "SetSpritesheetCoordinate", Lua_PointSetSpritesheetCoordinate}, - { "GetHeight", Lua_PointGetSpritesheetCoordinate}, // deprecated - { "SetHeight", Lua_PointSetSpritesheetCoordinate}, // deprecated - { "GetWidth", Lua_PointGetWidth}, - { "SetWidth", Lua_PointSetWidth}, - { "GetPosition", Lua_PointGetPosition}, - { "SetPosition", Lua_PointSetPosition}, - { NULL, NULL } - }; - lua::RegisterNewClass(L, lua::metatables::PointMT, lua::metatables::PointMT, pointFunctions); - lua_register(L, lua::metatables::PointMT, Lua_PointConstructor); } HOOK_METHOD(LuaEngine, RegisterClasses, () -> void) { diff --git a/repentogon/LuaInterfaces/LuaCord.cpp b/repentogon/LuaInterfaces/LuaCord.cpp new file mode 100644 index 000000000..1cf3cedd9 --- /dev/null +++ b/repentogon/LuaInterfaces/LuaCord.cpp @@ -0,0 +1,103 @@ +#include "IsaacRepentance.h" +#include "LuaCore.h" +#include "HookSystem.h" + +#include "../Reimplementations/Rope.hpp" + +LUA_FUNCTION(Lua_CreateCord) { + printf("lua: creating cord\n"); + int numPoints = (int)luaL_optinteger(L, 1, 2); + float timestep = (float)luaL_optnumber(L, 2, 0.01); + int iterations = (int)luaL_optinteger(L, 3, 50); + float stretchHeight = (float)luaL_optnumber(L, 4, 1.0); + float stretchWidth = (float)luaL_optnumber(L, 5, 1.0); + Rope* toLua = lua::place(L, lua::metatables::CordMT, numPoints, timestep, iterations, stretchHeight, stretchWidth); + luaL_setmetatable(L, lua::metatables::CordMT); + return 1; +} + +LUA_FUNCTION(Lua_CordInit) { + Rope* rope = lua::GetUserdata(L, 1, lua::metatables::CordMT); + rope->Init(); + return 0; +} + +LUA_FUNCTION(Lua_CordUpdate) { + Rope* rope = lua::GetUserdata(L, 1, lua::metatables::CordMT); + rope->Update(); + return 0; +} + +LUA_FUNCTION(Lua_CordRender) { + Rope* rope = lua::GetUserdata(L, 1, lua::metatables::CordMT); + ANM2* anm2 = lua::GetUserdata(L, 2, lua::Metatables::SPRITE, "Sprite"); + int layerID = (int)luaL_checkinteger(L, 3); + bool useOverlay = lua::luaL_checkboolean(L, 4); + bool unk = lua::luaL_optboolean(L, 5, false); + rope->Render(anm2, layerID, useOverlay, unk); + return 0; +} + +LUA_FUNCTION(Lua_CordGetPoints) { + printf("lua: cord getting pointdeque\n"); + Rope* rope = lua::GetUserdata(L, 1, lua::metatables::CordMT); + PointDeque** luaDeque = (PointDeque**)lua_newuserdata(L, sizeof(PointDeque*)); + printf("lua: cord setting luaDeque to %p\n", &rope->_points); + *luaDeque = &rope->_points; + luaL_setmetatable(L, lua::metatables::PointDequeMT); + return 1; +} + +LUA_FUNCTION(Lua_CordGetTimestep) { + Rope* rope = lua::GetUserdata(L, 1, lua::metatables::CordMT); + lua_pushnumber(L, rope->_timestep); + return 1; +} + +LUA_FUNCTION(Lua_CordSetTimestep) { + Rope* rope = lua::GetUserdata(L, 1, lua::metatables::CordMT); + rope->_timestep = (float)luaL_checknumber(L, 2); + return 0; +} + +LUA_FUNCTION(Lua_CordGetIterations) { + Rope* rope = lua::GetUserdata(L, 1, lua::metatables::CordMT); + lua_pushinteger(L, rope->_iterations); + return 1; +} + +LUA_FUNCTION(Lua_CordSetIterations) { + Rope* rope = lua::GetUserdata(L, 1, lua::metatables::CordMT); + rope->_iterations = (int)luaL_checkinteger(L, 2); + return 0; +} + +LUA_FUNCTION(Lua_Cord__gc) { + printf("cord gc\n"); + Rope* rope = lua::GetUserdata(L, 1, lua::metatables::CordMT); + rope->~Rope(); + return 0; +} + +static void RegisterCord(lua_State* L) { + luaL_Reg functions[] = { + { "Init", Lua_CordInit}, + { "Update", Lua_CordUpdate}, + { "Render", Lua_CordRender}, + { "GetTimestep", Lua_CordGetTimestep}, + { "SetTimestep", Lua_CordSetTimestep}, + { "GetIterations", Lua_CordGetIterations}, + { "SetIterations", Lua_CordSetIterations}, + { "GetPoints", Lua_CordGetPoints}, + { NULL, NULL } + }; + lua::RegisterNewClass(L, lua::metatables::CordMT, lua::metatables::CordMT, functions, Lua_Cord__gc); + lua_register(L, lua::metatables::CordMT, Lua_CreateCord); +} + +HOOK_METHOD(LuaEngine, RegisterClasses, () -> void) { + super(); + + lua::LuaStackProtector protector(_state); + RegisterCord(_state); +} \ No newline at end of file diff --git a/repentogon/LuaInterfaces/LuaPoint.cpp b/repentogon/LuaInterfaces/LuaPoint.cpp new file mode 100644 index 000000000..eb9fcbc88 --- /dev/null +++ b/repentogon/LuaInterfaces/LuaPoint.cpp @@ -0,0 +1,246 @@ +#include "IsaacRepentance.h" +#include "LuaCore.h" +#include "HookSystem.h" + +LUA_FUNCTION(Lua_PointConstructor) { + Point point; + point._pos = *lua::GetUserdata(L, 1, lua::Metatables::VECTOR, "Vector"); + point._spritesheetCoordinate = (float)luaL_checknumber(L, 2); + point._width = (float)luaL_optnumber(L, 3, 1.0f); + Entity* target = nullptr; + if (lua_type(L, 4) == LUA_TUSERDATA) { + target = lua::GetUserdata(L, 4, lua::Metatables::ENTITY, "Entity"); + } + point._target = target; + + Point* toLua = lua::place(L, lua::metatables::PointMT); + *toLua = point; + luaL_setmetatable(L, lua::metatables::PointMT); + + return 1; +} + +LUA_FUNCTION(Lua_PointGetSpritesheetCoordinate) { + Point* point = *lua::GetUserdata(L, 1, lua::metatables::PointMT); + lua_pushnumber(L, point->_spritesheetCoordinate); + return 1; +} + +LUA_FUNCTION(Lua_PointSetSpritesheetCoordinate) { + Point* point = *lua::GetUserdata(L, 1, lua::metatables::PointMT); + point->_spritesheetCoordinate = (float)luaL_checknumber(L, 2); + return 0; +} + +LUA_FUNCTION(Lua_PointGetWidth) { + Point* point = *lua::GetUserdata(L, 1, lua::metatables::PointMT); + lua_pushnumber(L, point->_width); + return 1; +} + +LUA_FUNCTION(Lua_PointSetWidth) { + Point* point = *lua::GetUserdata(L, 1, lua::metatables::PointMT); + point->_width = (float)luaL_checknumber(L, 2); + return 0; +} + +LUA_FUNCTION(Lua_PointGetPosition) { + Point* point = *lua::GetUserdata(L, 1, lua::metatables::PointMT); + Vector* toLua = lua::luabridge::UserdataValue::place(L, lua::GetMetatableKey(lua::Metatables::VECTOR)); + *toLua = point->_pos; + return 1; +} + +LUA_FUNCTION(Lua_PointSetPosition) { + Point* point = *lua::GetUserdata(L, 1, lua::metatables::PointMT); + point->_lastPos = point->_pos; + point->_pos = *lua::GetUserdata(L, 2, lua::Metatables::VECTOR, "Vector"); + return 0; +} + +LUA_FUNCTION(Lua_PointGetFixed) { + Point* point = *lua::GetUserdata(L, 1, lua::metatables::PointMT); + lua_pushboolean(L, point->_fixed); + return 1; +} + +LUA_FUNCTION(Lua_PointSetFixed) { + Point* point = *lua::GetUserdata(L, 1, lua::metatables::PointMT); + point->_fixed = lua::luaL_checkboolean(L, 2); + if (point->_fixed) + point->_lastPos = point->_pos; + return 0; +} + +LUA_FUNCTION(Lua_PointGetTarget) { + Point* point = *lua::GetUserdata(L, 1, lua::metatables::PointMT); + if (!point->_target) { + lua_pushnil(L); + } + else + { + lua::luabridge::UserdataPtr::push(L, point->_target, lua::GetMetatableKey(lua::Metatables::ENTITY)); + } + return 1; +} + +LUA_FUNCTION(Lua_PointSetTarget) { + Point* point = *lua::GetUserdata(L, 1, lua::metatables::PointMT); + if (lua_isnil(L, 2)) { + point->_target = nullptr; + } + else + { + point->_target = lua::GetUserdata(L, 2, lua::Metatables::ENTITY, "Entity"); + } + return 0; +} + +/*//////////////////// +//// Deque time +*///////////////////// + +LUA_FUNCTION(Lua_PointDequePushBack) { + PointDeque* d = *lua::GetUserdata(L, 1, lua::metatables::PointDequeMT); + Point* point = lua::GetUserdata(L, 2, lua::metatables::PointMT); + d->deque.push_back(*point); + + return 0; +} + +LUA_FUNCTION(Lua_PointDequePushFront) { + PointDeque* d = *lua::GetUserdata(L, 1, lua::metatables::PointDequeMT); + Point* point = lua::GetUserdata(L, 2, lua::metatables::PointMT); + d->deque.push_front(*point); + + return 0; +} + +LUA_FUNCTION(Lua_PointDequePopBack) { + PointDeque* d = *lua::GetUserdata(L, 1, lua::metatables::PointDequeMT); + printf("PointDeque::PopBack: address %p, size %d\n", d, d->deque.size()); + d->deque.pop_back(); + + return 0; +} + +LUA_FUNCTION(Lua_PointDequePopFront) { + PointDeque* d = *lua::GetUserdata(L, 1, lua::metatables::PointDequeMT); + d->deque.pop_front(); + + return 0; +} + +LUA_FUNCTION(Lua_PointDequeGet) { + PointDeque* d = *lua::GetUserdata(L, 1, lua::metatables::PointDequeMT); + printf("PointDeque::Get: size %d\n", d->deque.size()); + Point* p = &d->deque.at((int)luaL_checkinteger(L, 2)); + printf("PointDeque::Get: p = %p\n", p); + if (!p) { + printf("PointDeque::Get: it's nothing!\n"); + lua_pushnil(L); + } + else + { + printf("PointDeque::Get: pushing %p\n", p); + Point** toLua = (Point**)lua_newuserdata(L, sizeof(Point*)); + *toLua = p; + luaL_setmetatable(L, lua::metatables::PointMT); + } + + return 1; +} + +LUA_FUNCTION(Lua_PointDequeGetFront) { + PointDeque* d = *lua::GetUserdata(L, 1, lua::metatables::PointDequeMT); + printf("PointDeque::GetFront: deque %p, size %d\n", d, d->deque.size()); + Point* p = &d->deque.front(); + printf("PointDeque::GetFront: p = %p\n", p); + if (!p) { + printf("PointDeque::GetFront: it's nothing!\n"); + lua_pushnil(L); + } + else + { + printf("PointDeque::GetFront: pushing %p\n", p); + Point** toLua = (Point**)lua_newuserdata(L, sizeof(Point*)); + *toLua = p; + luaL_setmetatable(L, lua::metatables::PointMT); + } + + return 1; +} + +LUA_FUNCTION(Lua_PointDequeGetBack) { + PointDeque* d = *lua::GetUserdata(L, 1, lua::metatables::PointDequeMT); + printf("PointDeque::GetBack: deque %p, size %d\n", d, d->deque.size()); + Point* p = &d->deque.back(); + printf("PointDeque::GetBack: p = %p\n", p); + if (!p) { + printf("PointDeque::GetBack: it's nothing!\n"); + lua_pushnil(L); + } + else + { + printf("PointDeque::GetBack: pushing %p\n", p); + Point** toLua = (Point**)lua_newuserdata(L, sizeof(Point*)); + *toLua = p; + luaL_setmetatable(L, lua::metatables::PointMT); + } + + return 1; +} + +LUA_FUNCTION(Lua_PointDeque__len) { + PointDeque* d = *lua::GetUserdata(L, 1, lua::metatables::PointDequeMT); + lua_pushinteger(L, d->deque.size()); + + return 1; +} + +LUA_FUNCTION(Lua_PointDeque__gc) { + PointDeque* d = *lua::GetUserdata(L, 1, lua::metatables::PointDequeMT); + d->~PointDeque(); + return 0; +} + +static void RegisterPoint(lua_State* L) { + luaL_Reg pointFunctions[] = { + { "GetSpritesheetCoordinate", Lua_PointGetSpritesheetCoordinate}, + { "SetSpritesheetCoordinate", Lua_PointSetSpritesheetCoordinate}, + { "GetHeight", Lua_PointGetSpritesheetCoordinate}, // deprecated + { "SetHeight", Lua_PointSetSpritesheetCoordinate}, // deprecated + { "GetWidth", Lua_PointGetWidth}, + { "SetWidth", Lua_PointSetWidth}, + { "GetPosition", Lua_PointGetPosition}, + { "SetPosition", Lua_PointSetPosition}, + { "GetTarget", Lua_PointGetTarget}, + { "SetTarget", Lua_PointSetTarget}, + { NULL, NULL } + }; + + lua::RegisterNewClass(L, lua::metatables::PointMT, lua::metatables::PointMT, pointFunctions); + lua_register(L, lua::metatables::PointMT, Lua_PointConstructor); + + luaL_Reg dequeFunctions[] = { + { "PushBack", Lua_PointDequePushBack}, + { "PushFront", Lua_PointDequePushFront }, + { "PopBack", Lua_PointDequePopBack }, + { "PopFront", Lua_PointDequePopFront }, + { "Get", Lua_PointDequeGet }, + { "GetFront", Lua_PointDequeGetFront }, + { "GetBack", Lua_PointDequeGetBack }, + { "__len", Lua_PointDeque__len }, + { NULL, NULL } + }; + + lua::RegisterNewClass(L, lua::metatables::PointDequeMT, lua::metatables::PointDequeMT, dequeFunctions, Lua_PointDeque__gc); + //lua_register(L, lua::metatables::PointDequeMT, Lua_PointConstructor); +} + +HOOK_METHOD(LuaEngine, RegisterClasses, () -> void) { + super(); + + lua::LuaStackProtector protector(_state); + RegisterPoint(_state); +} \ No newline at end of file diff --git a/repentogon/Reimplementations/Rope.hpp b/repentogon/Reimplementations/Rope.hpp new file mode 100644 index 000000000..cf49ea9cd --- /dev/null +++ b/repentogon/Reimplementations/Rope.hpp @@ -0,0 +1,228 @@ +/* + This is an adaptation of work from Franciszek Szewczyk, who made an intuitive article + explaining 2D rope physics and methods of implementation. + The gist: https://gist.github.com/fszewczyk/46915c02a34a1833d83a3c2fd851b7a0 + The article: https://medium.com/@szewczyk.franciszek02/rope-simulator-in-c-a595a3ef956c + + The main changes here are the removal of gravity, the adaptation of types to IsaacRepentance ones, + and handling rendering through BeamRenderer. +*/ + +#pragma once + +#include "IsaacRepentance.h" +#include +#include +#include + +class Rope { + public: + Rope(unsigned int nPoints, float timestep, unsigned int iterations, float spriteStretchHeight, float spriteStretchWidth) { + printf("Rope: constructing, this %p\n", this); + _numPoints = nPoints; + _timestep = timestep; + _iterations = iterations; + _spriteStretch = spriteStretchHeight; + _spriteWidth = spriteStretchWidth; + _desiredDistance = 0.0f; + Vector const zero; + + for (unsigned int i = 0; i < 2; i++) { + printf("Rope: making point #%d\n", i); + Point p(zero, (Entity*)nullptr, 0.0f, spriteStretchWidth, false); + printf("Rope: pushing point #%d\n", i); + _points.deque.push_back(p); + } + printf("Rope: points %p, %p\n", &_points.deque.front(), &_points.deque.back()); + printf("Rope: done constructing\n"); + } + + void Init() { + printf("Rope::Init starting, this %p, deque %p\n", this, &_points); + if (_points.deque.size() < 2) { + printf("not enough points\n"); + return; + } + Point* startPoint = &_points.deque.front(); + Point endPoint = _points.deque.back(); + Vector* startPos = startPoint->_target ? startPoint->_target->GetPosition() : &startPoint->_pos; + Vector* endPos = endPoint._target ? endPoint._target->GetPosition() : &endPoint._pos; + + printf("startPos: %f %f, endPos: %f %f\n", startPos->x, startPos->y, endPos->x, endPos->y); + + _ropeLength = distanceFunc(*startPos, *endPos); + + // There is one less segment than there are Points + _numSegments = _numPoints - 1; + + _desiredDistance = _ropeLength / _numSegments; + + printf("length: %f, segments : %d, avg distance: %f\n", _ropeLength, _numSegments, _desiredDistance); + + printf("point #0: %p\n", &_points.deque.front()); + _points.deque.pop_back(); + for (unsigned int i = 1; i < _numPoints; i++) { + // percent distance from start to end, 0.0->1.0 + float w = (float)i / (_numPoints - 1); + + Vector pos(w * endPos->x + (1 - w) * startPos->x, w * endPos->y + (1 - w) * startPos->y); + float spritesheetCoord = _ropeLength * w * _spriteStretch; + + if (i == _numPoints - 1) { + endPoint._pos = pos; + endPoint._spritesheetCoordinate = spritesheetCoord; + _points.deque.push_back(endPoint); + //printf("end point #%d, addr %p, deque addr %p, pos %f, %f with coord %f and fixed %d\n", i, &endPoint, &_points.deque.back(), endPoint._pos.x, endPoint._pos.y, endPoint._spritesheetCoordinate, endPoint._target != nullptr); + } + else + { + Point p(pos, nullptr, spritesheetCoord, _spriteWidth, false); + _points.deque.push_back(p); + printf("point #%d, addr %p, deque addr %p, pos %f, %f with coord %f and fixed %d\n", i, &p, &_points.deque.back(), p._pos.x, p._pos.y, p._spritesheetCoordinate, p._fixed); + } + } + _initialized = true; + printf("Rope::Init ending, size %d\n", _points.deque.size()); + _backup = _points; // miserable + //__debugbreak(); + } + + void Update() { + _points = _backup; + //printf("Rope::Update starting, this %p, deque %p, size %d\n", this, &_points, _points.deque.size()); + //printf("%f %f, %f %f\n", _points.deque.front()._pos.x, _points.deque.front()._pos.y, _points.deque.back()._pos.x, _points.deque.back()._pos.y); + //_desiredDistance = _numSegments / distanceFunc(_points.deque.front()._pos, _points.deque.back()._pos); + if (!_initialized) { + //printf("Rope::Update: not initialzed\n"); + return; + } + verletIntegration(); + enforceConstraints(); + //printf("Rope::Update finished\n"); + } + + void Render(ANM2* anm2, unsigned int layerID, bool useOverlay, bool unk) { + //printf("Rope::Render starting, using deque %p\n", &_points); + if (_points.deque.size() < 2) { + //printf("Rope::Render: < 2 points, size is %d\n", _points.deque.size()); + return; + } + if (!_initialized) { + //printf("Rope::Render: not initialzed\n"); + return; + } + + g_BeamRenderer->Begin(anm2, layerID, useOverlay, unk); + + #pragma warning(suppress:4533) + ColorMod color; + Vector buffer; + for (Point& p : _points.deque) { + Isaac::WorldToScreen(&buffer, &p._pos); + g_BeamRenderer->Add(&buffer, &color, p._width, p._spritesheetCoordinate); + } + + g_BeamRenderer->End(); + } + + // We need to store our Points somewhere + PointDeque _points, _backup; + + // Target distance of a single segment + float _desiredDistance; + float _ropeLength; + float _timestep = 0.01f; + float _spriteStretch, _spriteWidth = 1; + unsigned int _numPoints = 2; + unsigned int _iterations = 10; + unsigned int _numSegments = 1; + bool _initialized = false; + + private: + inline float distanceFunc(Vector a, Vector b) { + return (float)sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2)); + } + + inline bool isFixed(Point p) { + return (p._fixed || p._target != nullptr); + } + + void verletIntegration() { + //printf("verletIntegration: deque %p, size %d\n", &_points, _points.deque.size()); + //int i = 0; + for (Point& p : _points.deque) { + if (p._target) { + p._lastPos = p._pos; + p._pos = *p._target->GetPosition(); + //printf("updated position to %f, %f\n", p._pos.x, p._pos.y); + continue; + } + // We do not want to move fixed Points + if (p._fixed) + continue; + + Vector copy = p._pos; + + // Calculating previous velocity + Vector velocity((p._pos.x - p._lastPos.x) / _timestep, (p._pos.y - p._lastPos.y) / _timestep); + + // Updating Point's position + p._pos += velocity * _timestep; + + p._lastPos = copy; + //i++; + } + //printf("verletIntegration: ran %d times, deque size %d\n", i, _points.deque.size()); + } + + void enforceConstraints() { + // We perform the enforcement multiple times + for (unsigned int iteration = 0; iteration < _iterations; iteration++) { + //float distanceTotal = 0.0f; + //printf("iteration %d: ", iteration); + // We iterate over each pair of points + for (size_t i = 1; i < _points.deque.size(); i++) { + Point& p1 = _points.deque[i - 1]; + Point& p2 = _points.deque[i]; + + // Calculating distance between the Points + float distance = (float)sqrt(pow(p1._pos.x - p2._pos.x, 2) + pow(p1._pos.y - p2._pos.y, 2)); + float distanceError = distance - _desiredDistance; + + //printf("distance %f, error %f, ", distance, distanceError); + + // The direction in which Points should be pulled or pushed + Vector difference(p2._pos.x - p1._pos.x, p2._pos.y - p1._pos.y); + //printf("difference %f, %f, ", difference.x, difference.y); + + // We need to make it a unit vector + // This will allow us to easily scale the impact we have + // on each Point's position. + Vector direction(difference.x / (float)sqrt(pow(difference.x, 2) + pow(difference.y, 2)), difference.y / (float)sqrt(pow(difference.x, 2) + pow(difference.y, 2))); + //printf("direction %f, %f\n", difference.x, difference.y); + + // Finally, we can update Points' positions + // We need to remember that fixed Points should stay in place + if (isFixed(p1) && !isFixed(p2)) { + p2._pos -= direction * distanceError; + //printf("moved p2, now %f, %f\n", p2._pos.x, p2._pos.y); + } + else if (isFixed(p2) && !isFixed(p1)) { + p1._pos += direction * distanceError; + //printf("moved p1, now %f, %f\n", p1._pos.x, p1._pos.y); + // keeping this comparison in case both points are fixed + } + else if (!isFixed(p1) && !isFixed(p2)) { + p2._pos -= direction * distanceError * 0.5; + //printf("moved p2 halfway, now %f, %f\n", p2._pos.x, p2._pos.y); + p1._pos += direction * distanceError * 0.5; + //printf("moved p1 halfway, now %f, %f\n", p1._pos.x, p1._pos.y); + } + //printf("distance: %f\n", distanceFunc(p1._pos, p2._pos)); + //distanceTotal += distanceFunc(p1._pos, p2._pos); + //__debugbreak(); + } + //printf("total length: %f, target: %f\n", distanceTotal, _ropeLength); + } + } +};