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
This commit is contained in:
John McCardle 2024-03-21 21:39:15 -04:00
parent 2cf8f94310
commit d7228172c4
5 changed files with 110 additions and 51 deletions

View File

@ -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;

View File

@ -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;

View File

@ -2,48 +2,48 @@
#include "Common.h"
#include "Python.h"
class PyTexture;
typedef struct {
PyObject_HEAD
std::shared_ptr<PyTexture> 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<char**>(keywords), &filename, &grid_size, &grid_width, &grid_height))
{
return -1;
}
self->data = std::make_shared<PyTexture>(filename, grid_size, grid_size);
return 0;
}
*/
namespace mcrfpydef {
class PyTexture;
typedef struct {
PyObject_HEAD
std::shared_ptr<PyTexture> data;
} PyTextureObject;
class PyTexture : public std::enable_shared_from_this<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* 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<char**>(keywords), &filename, &grid_size, &grid_width, &grid_height))
{
return -1;
}
self->data = std::make_shared<PyTexture>(filename, grid_size, grid_size);
return 0;
}
*/
static PyTypeObject PyTextureType = {
.tp_name = "mcrfpy.Texture",
.tp_basicsize = sizeof(PyTextureObject),

View File

@ -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<PyTexture> UIGrid::getTexture()
{
return ptex;
}

View File

@ -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<PyTexture> getTexture();
sf::Sprite sprite, output;
sf::RenderTexture renderTexture;
std::vector<UIGridPoint> 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 */
};