From d7228172c4d5455159cd91782b49304a971bb444 Mon Sep 17 00:00:00 2001 From: John McCardle Date: Thu, 21 Mar 2024 21:39:15 -0400 Subject: [PATCH] Messy, but monumental: PyTexture::pyObject works this also coincidentally fixes a weird bug I encountered while (mis?)using tp_alloc: by using PyType_GenericAlloc, I avoid the segfault that tp_alloc sometimes causes. See the horrible UIDrawable retrieval macro that I use in UI.h for a workaround that can probably be replaced with this technique --- src/McRFPy_API.cpp | 23 ++++++++----- src/PyTexture.cpp | 35 ++++++++++++++++++++ src/PyTexture.h | 82 +++++++++++++++++++++++----------------------- src/UI.cpp | 7 ++++ src/UI.h | 14 ++++++-- 5 files changed, 110 insertions(+), 51 deletions(-) diff --git a/src/McRFPy_API.cpp b/src/McRFPy_API.cpp index 113c13a..9a65a61 100644 --- a/src/McRFPy_API.cpp +++ b/src/McRFPy_API.cpp @@ -55,30 +55,37 @@ PyObject* PyInit_mcrfpy() // This code runs, but Python segfaults when accessing the UIFrame type. //std::cout << "Adding UIFrame object to module\n"; + using namespace mcrfpydef; + PyTypeObject* pytypes[] = {&PyColorType, &PyFontType, &PyUICaptionType, &PyTextureType, &PyUISpriteType, &PyUIFrameType, &PyUICollectionType, + &PyUICollectionIterType, &PyUIGridPointType, &PyUIGridPointStateType, &PyUIEntityType, &PyUIEntityCollectionType, + &PyUIEntityCollectionIterType, &PyUIGridType, nullptr}; + int i = 0; + auto t = pytypes[i]; + while (t != nullptr) + { + PyType_Ready(t); + PyModule_AddType(m, t); + t = pytypes[i++]; + } + /* PyModule_AddType(m, &mcrfpydef::PyColorType); PyModule_AddType(m, &mcrfpydef::PyFontType); PyModule_AddType(m, &mcrfpydef::PyUICaptionType); PyModule_AddType(m, &mcrfpydef::PyTextureType); PyModule_AddType(m, &mcrfpydef::PyUISpriteType); - if (PyModule_AddType(m, &mcrfpydef::PyUIFrameType) < 0) - { - std::cout << "Error adding UIFrame type to module; aborting" << std::endl; - Py_DECREF(&mcrfpydef::PyUIFrameType); - return NULL; - } + PyModule_AddType(m, &mcrfpydef::PyUIFrameType); PyModule_AddType(m, &mcrfpydef::PyUICollectionType); PyModule_AddType(m, &mcrfpydef::PyUICollectionIterType); PyModule_AddType(m, &mcrfpydef::PyUIGridPointType); PyModule_AddType(m, &mcrfpydef::PyUIGridPointStateType); PyModule_AddType(m, &mcrfpydef::PyUIEntityType); - PyModule_AddType(m, &mcrfpydef::PyUIEntityCollectionIterType); PyModule_AddType(m, &mcrfpydef::PyUIEntityCollectionType); PyModule_AddType(m, &mcrfpydef::PyUIGridType); - + */ return m; diff --git a/src/PyTexture.cpp b/src/PyTexture.cpp index 55e1c20..f21311e 100644 --- a/src/PyTexture.cpp +++ b/src/PyTexture.cpp @@ -1,4 +1,6 @@ #include "PyTexture.h" +using namespace mcrfpydef; + PyTexture::PyTexture(std::string filename, int sprite_w, int sprite_h) : source(filename), sprite_width(sprite_w), sprite_height(sprite_h) @@ -15,6 +17,17 @@ PyTexture::PyTexture(std::string filename, int sprite_w, int sprite_h) } } +/* // bit misguided here: holding self might prevent the shared_ptr from ever being released. +PyTexture::~PyTexture() +{ + if (self != NULL) + { + (PyTextureObject*)self->data.reset(); + Py_DECREF(self); + } +} +*/ + sf::Sprite PyTexture::sprite(int index, sf::Vector2f pos, sf::Vector2f s) { int tx = index % sheet_width, ty = index / sheet_width; @@ -25,6 +38,28 @@ sf::Sprite PyTexture::sprite(int index, sf::Vector2f pos, sf::Vector2f s) return sprite; } +PyObject* PyTexture::pyObject() +{ + //PyTextureObject* self = (PyTextureObject*)pynew(&mcrfpydef::PyTextureType, NULL, NULL); + std::cout << "tp_alloc (GenericAlloc)" << std::endl; + //PyObject* obj = ((&PyTextureType)->tp_alloc(&PyTextureType, 0)); + //PyObject* obj = pynew(&PyTextureType); + PyObject* obj = PyType_GenericAlloc(&PyTextureType, 0); + std::cout << "alloc worked" << std::endl; + //Py_INCREF(self); + try { + std::cout << "assign data to self" << std::endl; + ((PyTextureObject*)obj)->data = shared_from_this(); + } + catch (std::bad_weak_ptr& e) + { + std::cout << "Bad weak ptr: shared_from_this() failed" << std::endl; + } + // TODO - shared_from_this will raise an exception if the object does not have a shared pointer. Constructor should be made private; write a factory function + std::cout << "returning PyObject" << std::endl; + return obj; +} + Py_hash_t PyTexture::hash(PyObject* obj) { auto self = (PyTextureObject*)obj; diff --git a/src/PyTexture.h b/src/PyTexture.h index 0cf56bc..9e7a7bc 100644 --- a/src/PyTexture.h +++ b/src/PyTexture.h @@ -2,48 +2,48 @@ #include "Common.h" #include "Python.h" -class PyTexture; - -typedef struct { - PyObject_HEAD - std::shared_ptr data; -} PyTextureObject; - -class PyTexture -{ -private: - sf::Texture texture; - std::string source; - int sheet_width, sheet_height; -protected: - PyObject* self = 0; -public: - int sprite_width, sprite_height; // just use them read only, OK? - PyTexture(std::string filename, int sprite_w, int sprite_h); - sf::Sprite sprite(int index, sf::Vector2f pos = sf::Vector2f(0, 0), sf::Vector2f s = sf::Vector2f(1.0, 1.0)); - - PyObject* pyObject(); - static Py_hash_t hash(PyObject*); - static int init(PyTextureObject*, PyObject*, PyObject*); - static PyObject* pynew(PyTypeObject*, PyObject*, PyObject*); -}; -/* -static int PyTexture_init(PyTextureObject* self, PyObject* args, PyObject* kwds) -{ - //std::cout << "Init called\n"; - static const char* keywords[] = { "filename", "grid_size", "grid_width", "grid_height", nullptr }; - char* filename; - int grid_size, grid_width, grid_height; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "siii", const_cast(keywords), &filename, &grid_size, &grid_width, &grid_height)) - { - return -1; - } - self->data = std::make_shared(filename, grid_size, grid_size); - return 0; -} -*/ namespace mcrfpydef { + class PyTexture; + + typedef struct { + PyObject_HEAD + std::shared_ptr data; + } PyTextureObject; + + class PyTexture : public std::enable_shared_from_this + { + private: + sf::Texture texture; + std::string source; + int sheet_width, sheet_height; + protected: + //PyObject* self = 0; + public: + int sprite_width, sprite_height; // just use them read only, OK? + PyTexture(std::string filename, int sprite_w, int sprite_h); + sf::Sprite sprite(int index, sf::Vector2f pos = sf::Vector2f(0, 0), sf::Vector2f s = sf::Vector2f(1.0, 1.0)); + + PyObject* pyObject(); + static Py_hash_t hash(PyObject*); + static int init(PyTextureObject*, PyObject*, PyObject*); + static PyObject* pynew(PyTypeObject* type, PyObject* args=NULL, PyObject* kwds=NULL); + }; + /* + static int PyTexture_init(PyTextureObject* self, PyObject* args, PyObject* kwds) + { + //std::cout << "Init called\n"; + static const char* keywords[] = { "filename", "grid_size", "grid_width", "grid_height", nullptr }; + char* filename; + int grid_size, grid_width, grid_height; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "siii", const_cast(keywords), &filename, &grid_size, &grid_width, &grid_height)) + { + return -1; + } + self->data = std::make_shared(filename, grid_size, grid_size); + return 0; + } + */ static PyTypeObject PyTextureType = { .tp_name = "mcrfpy.Texture", .tp_basicsize = sizeof(PyTextureObject), diff --git a/src/UI.cpp b/src/UI.cpp index b47fa1e..116e6b4 100644 --- a/src/UI.cpp +++ b/src/UI.cpp @@ -2,6 +2,8 @@ #include "Resources.h" #include "GameEngine.h" +using namespace mcrfpydef; + /* //callability fields & methods PyObject* click_callable; virtual UIDrawable* click_at(sf::Vector2f point); @@ -520,3 +522,8 @@ PyObjectsEnum UIGrid::derived_type() { return PyObjectsEnum::UIGRID; } + +std::shared_ptr UIGrid::getTexture() +{ + return ptex; +} diff --git a/src/UI.h b/src/UI.h index a90715b..a803a32 100644 --- a/src/UI.h +++ b/src/UI.h @@ -8,6 +8,8 @@ #include "PyCallable.h" #include "PyTexture.h" +using namespace mcrfpydef; + enum PyObjectsEnum : int { UIFRAME = 1, @@ -187,6 +189,7 @@ public: sf::RectangleShape box; float center_x, center_y, zoom; //IndexTexture* itex; + std::shared_ptr getTexture(); sf::Sprite sprite, output; sf::RenderTexture renderTexture; std::vector points; @@ -1215,7 +1218,8 @@ static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* c static PyObject* PyUISprite_get_texture(PyUISpriteObject* self, void* closure) { - return NULL; + std::cout << "Calling pyObject" << std::endl; + return self->data->getTexture()->pyObject(); } static int PyUISprite_set_texture(PyUISpriteObject* self, PyObject* value, void* closure) @@ -1791,6 +1795,12 @@ static PyObject* PyUIGrid_get_texture(PyUIGridObject* self, void* closure) { return self->texture; } */ +static PyObject* PyUIGrid_get_texture(PyUIGridObject* self, void* closure) { + //return self->data->getTexture()->pyObject(); + PyTextureObject* obj = (PyTextureObject*)((&PyTextureType)->tp_alloc(&PyTextureType, 0)); + obj->data = self->data->getTexture(); + return (PyObject*)obj; +} static PyObject* PyUIGrid_at(PyUIGridObject* self, PyObject* o) { @@ -1842,7 +1852,7 @@ static PyGetSetDef PyUIGrid_getsetters[] = { {"click", (getter)PyUIDrawable_get_click, (setter)PyUIDrawable_set_click, "Object called with (x, y, button) when clicked", (void*)PyObjectsEnum::UIGRID}, - //{"texture", (getter)PyUIGrid_get_texture, NULL, "Texture of the grid", NULL}, //TODO 7DRL-day2-item5 + {"texture", (getter)PyUIGrid_get_texture, NULL, "Texture of the grid", NULL}, //TODO 7DRL-day2-item5 {NULL} /* Sentinel */ };