Aug 30/31 updates. Tinkering with shared_ptr. Working towards exposing UI objects to Python UI. Color object updated for shared_ptr structure that will be repeated for the rest of the UI objects. Still a lot of open questions, but committing here to get back on track after a few hours wasted trying to solve this problem too generally via templates.

This commit is contained in:
John McCardle 2023-08-31 13:51:56 -04:00
parent 795701c986
commit 50d926fe37
11 changed files with 293 additions and 137 deletions

View File

@ -19,6 +19,7 @@ GameEngine::GameEngine()
//std::cout << "Constructing MenuScene" << std::endl;
scenes["menu"] = new MenuScene(this);
scenes["uitest"] = new UITestScene(this);
//std::cout << "Constructed MenuScene" <<std::endl;
//scenes["play"] = new UITestScene(this);
//api = new McRFPy_API(this);
@ -119,3 +120,21 @@ void GameEngine::sUserInput()
}
}
}
std::vector<std::shared_ptr<UIDrawable>>* GameEngine::scene_ui(std::string target)
{
/*
// facts about maps
// You just can't do this during scenes["new_menu"] being assigned.
std::cout << "Current scene is: " << scene << ". Searching for: " << target << ".\n";
std::cout << "scenes.size(): " << scenes.size() << std::endl;
std::cout << "scenes.count(target): " << scenes.count(target) << std::endl;
std::cout << "scenes.find(target): " << std::distance(scenes.begin(), scenes.find(target)) << std::endl;
std::cout << "iterators: " << std::distance(scenes.begin(), scenes.begin()) << " " <<
std::distance(scenes.begin(), scenes.end()) << std::endl;
std::cout << "scenes.contains(target): " << scenes.contains(target) << std::endl;
std::cout << "scenes[target]: " << (long)(scenes[target]) << std::endl;
*/
if (scenes.count(target) == 0) return NULL;
return &scenes[target]->ui_elements;
}

View File

@ -42,4 +42,6 @@ public:
std::vector<sf::SoundBuffer> sfxbuffers;
sf::Music music;
sf::Sound sfx;
std::vector<std::shared_ptr<UIDrawable>>* scene_ui(std::string scene);
};

View File

@ -3,6 +3,7 @@
#include "GameEngine.h"
#include "Grid.h"
#include "UI.h"
#include "Resources.h"
// static class members...?
std::map<std::string, UIMenu*> McRFPy_API::menus;
@ -99,6 +100,8 @@ static PyMethodDef mcrfpyMethods[] = {
{"camFollow", McRFPy_API::_camFollow, METH_VARARGS, ""},
{"sceneUI", McRFPy_API::_sceneUI, METH_VARARGS, "sceneUI(scene) - Returns a list of UI elements"},
{NULL, NULL, 0, NULL}
};
@ -118,14 +121,17 @@ PyObject* PyInit_mcrfpy()
}
// This code runs, but Python segfaults when accessing the UIFrame type.
std::cout << "Adding UIFrame object to module\n";
//std::cout << "Adding UIFrame object to module\n";
PyModule_AddType(m, &mcrfpydef::PyColorType);
/*
if (PyModule_AddType(m, &mcrfpydef::PyUIFrameType) < 0)
{
std::cout << "Error adding UIFrame type to module; aborting" << std::endl;
Py_DECREF(&mcrfpydef::PyUIFrameType);
return NULL;
}
*/
return m;
}
@ -1115,3 +1121,14 @@ PyObject* McRFPy_API::_camFollow(PyObject* self, PyObject* args) {
Py_INCREF(Py_None);
return Py_None;
}
//McRFPy_API::_sceneUI
PyObject* McRFPy_API::_sceneUI(PyObject* self, PyObject* args) {
const char *scene_cstr;
if (!PyArg_ParseTuple(args, "s", &scene_cstr)) return NULL;
auto ui = Resources::game->scene_ui("uitest");
if(ui) std::cout << "vector returned has size=" << ui->size() << std::endl;
Py_INCREF(Py_None);
return Py_None;
}

View File

@ -113,6 +113,8 @@ public:
static void camFollow();
static PyObject* _camFollow(PyObject*, PyObject*);
static PyObject* _sceneUI(PyObject*, PyObject*);
// accept keyboard input from scene
static sf::Vector2i cursor_position;
static void player_input(int, int);

View File

@ -1,5 +1,6 @@
#include "Resources.h"
#include <list>
#include "UI.h"
// Resources class members memory allocation
sf::Font Resources::font;

View File

@ -1,4 +1,6 @@
#include "Common.h"
#include <list>
#include "UI.h"
class GameEngine; // forward declared

View File

@ -7,6 +7,8 @@
#define ACTIONPY ((name.size() > 3 && name.compare(name.size() - 3, 3, "_py") == 0))
#include "Common.h"
#include <list>
#include "UI.h"
//#include "GameEngine.h"
class GameEngine; // forward declare
@ -37,4 +39,6 @@ public:
virtual bool registerActionInjected(int, std::string);
virtual bool unregisterActionInjected(int, std::string);
std::vector<std::shared_ptr<UIDrawable>> ui_elements;
};

View File

@ -10,27 +10,33 @@ void UIDrawable::render()
UIFrame::UIFrame():
x(0), y(0), w(0), h(0), outline(0)
{
/*
pyOutlineColor = NULL;
pyFillColor = NULL;
_outlineColor = NULL;
_fillColor = NULL;
*/
}
UIFrame::UIFrame(float _x, float _y, float _w, float _h):
x(_x), y(_y), w(_w), h(_h), outline(0)
{
/*
pyOutlineColor = NULL;
pyFillColor = NULL;
_outlineColor = NULL;
_fillColor = NULL;
*/
}
UIFrame::~UIFrame()
{
/*
if (pyOutlineColor) Py_DECREF(pyOutlineColor);
else if (_outlineColor) delete _outlineColor;
if (pyFillColor) Py_DECREF(pyFillColor);
else if (_fillColor) delete _fillColor;
*/
}
/*
@ -43,68 +49,23 @@ UIFrame::~UIFrame()
void outlineColor(PyObject* pyColor); // Python setter
*/
sf::Color UIFrame::fillColor()
{
if (_fillColor == NULL) return sf::Color();
return *_fillColor;
}
void UIFrame::fillColor(sf::Color c)
{
if (pyFillColor) { Py_DECREF(pyFillColor); }
else { delete _fillColor; }
_fillColor = new sf::Color(c.r, c.g, c.b, c.a);
pyFillColor = NULL;
}
void UIFrame::fillColor(PyColorObject* pyColor)
{
if (pyFillColor) { Py_DECREF(pyFillColor); }
else { delete _fillColor; }
Py_INCREF(pyColor);
pyFillColor = pyColor;
_fillColor = &(pyFillColor->color);
}
sf::Color UIFrame::outlineColor()
{
if (_outlineColor == NULL) return sf::Color();
return *_outlineColor;
}
void UIFrame::outlineColor(sf::Color c)
{
if (pyOutlineColor) { Py_DECREF(pyOutlineColor); }
else { delete _outlineColor; }
_outlineColor = new sf::Color(c.r, c.g, c.b, c.a);
pyOutlineColor = NULL;
}
void UIFrame::outlineColor(PyColorObject* pyColor)
{
if (pyOutlineColor) { Py_DECREF(pyOutlineColor); }
else { delete _outlineColor; }
Py_INCREF(pyColor);
pyOutlineColor = pyColor;
_outlineColor = &(pyOutlineColor->color);
}
void UIFrame::render(sf::Vector2f offset)
{
//std::cout << "Rendering UIFrame w/ offset " << offset.x << ", " << offset.y << "\n";
//std::cout << "position = " << x << ", " << y << "\n";
//box.move(offset);
//Resources::game->getWindow().draw(box);
//box.move(-offset);
sf::RectangleShape box = sf::RectangleShape(sf::Vector2f(w,h));
sf::Vector2f pos = sf::Vector2f(x, y);
box.setPosition(offset + pos);
if (_fillColor) { box.setFillColor(fillColor()); }
if (_outlineColor) { box.setOutlineColor(outlineColor()); }
box.setOutlineThickness(outline);
box.move(offset);
Resources::game->getWindow().draw(box);
box.move(-offset);
//sf::RectangleShape box = sf::RectangleShape(sf::Vector2f(w,h));
//sf::Vector2f pos = sf::Vector2f(x, y);
//box.setPosition(offset + pos);
//if (_fillColor) { box.setFillColor(fillColor()); }
//if (_outlineColor) { box.setOutlineColor(outlineColor()); }
//box.setOutlineThickness(outline);
//Resources::game->getWindow().draw(box);
for (auto drawable : children) {
drawable->render(offset + pos);
drawable->render(offset + box.getPosition());
}
}

224
src/UI.h
View File

@ -1,3 +1,4 @@
#pragma once
#include "Common.h"
#include "Python.h"
#include "structmember.h"
@ -14,12 +15,18 @@ public:
std::string action;
};
//PyColorObject struct required to embed Python colors into UIFrame
//Python object types & forward declarations
/*
typedef struct {
PyObject_HEAD
sf::Color color;
} PyColorObject;
*/
typedef struct {
PyObject_HEAD
std::shared_ptr<sf::Color> data;
} PyColorObject;
class UIFrame: public UIDrawable
{
@ -27,14 +34,15 @@ public:
UIFrame(float, float, float, float);
UIFrame();
~UIFrame();
//sf::RectangleShape box;
sf::RectangleShape box;
//Simulate RectangleShape
float x, y, w, h, outline;
std::vector<UIDrawable*> children;
std::vector<std::shared_ptr<UIDrawable>> children;
void render(sf::Vector2f) override final;
void move(sf::Vector2f);
/*
sf::Color fillColor(); // getter
void fillColor(sf::Color c); // C++ setter
void fillColor(PyColorObject* pyColor); // Python setter
@ -42,10 +50,14 @@ public:
sf::Color outlineColor(); // getter
void outlineColor(sf::Color c); // C++ setter
void outlineColor(PyColorObject* pyColor); // Python setter
*/
private:
//std::shared_ptr<sf::Color> fillColor, outlineColor;
/*
sf::Color *_fillColor, *_outlineColor;
PyColorObject *pyFillColor, *pyOutlineColor;
*/
};
class UICaption: public UIDrawable
@ -64,45 +76,72 @@ public:
sf::Sprite sprite;
};
/*
template<typename T>
struct CPythonSharedObject {
PyObject_HEAD
std::shared_ptr<T> data;
};
typedef CPythonSharedObject<UIFrame> PyUIFrameObject;
*/
//equivalent
/*
typedef struct {
PyObject_HEAD
std::shared_ptr<UIFrame> data;
} PyUIFrameObject;
*/
typedef struct {
PyObject_HEAD
std::shared_ptr<UICaption> data;
} PyUICaptionObject;
typedef struct {
PyObject_HEAD
std::shared_ptr<UISprite> data;
} PyUISpriteObject;
namespace mcrfpydef {
// Color Definitions
// struct, members, new, set_member, PyTypeObject
/* for reference: the structs to implement
typedef struct {
PyObject_HEAD
std::shared_ptr<sf::Color> data;
} PyColorObject;
static PyMemberDef PyColor_members[]
{
{"r", T_BYTE, offsetof(PyColorObject, color.r), 0},
{"g", T_BYTE, offsetof(PyColorObject, color.g), 0},
{"b", T_BYTE, offsetof(PyColorObject, color.b), 0},
{"a", T_BYTE, offsetof(PyColorObject, color.a), 0},
{NULL}
};
typedef struct {
PyObject_HEAD
std::shared_ptr<UIFrame> data;
} PyUIFrameObject;
static PyObject* PyColor_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
{
PyColorObject* self = (PyColorObject*)type->tp_alloc(type, 0);
if (self != NULL)
{
self->color.r = 0;
self->color.g = 0;
self->color.b = 0;
self->color.a = 255;
}
return (PyObject*) self;
}
typedef struct {
PyObject_HEAD
std::shared_ptr<UICaption> data;
} PyUICaptionObject;
typedef struct {
PyObject_HEAD
std::shared_ptr<UISprite> data;
} PyUISpriteObject;
*/
static PyObject* PyColor_get_member(PyColorObject* self, void* closure)
{
auto member_ptr = reinterpret_cast<long>(closure);
if (member_ptr == offsetof(PyColorObject, color.r))
return PyLong_FromLong(self->color.r);
else if (member_ptr == offsetof(PyColorObject, color.g))
return PyLong_FromLong(self->color.g);
else if (member_ptr == offsetof(PyColorObject, color.b))
return PyLong_FromLong(self->color.b);
else if (member_ptr == offsetof(PyColorObject, color.a))
return PyLong_FromLong(self->color.a);
if (member_ptr == 0)
return PyLong_FromLong(self->data->r);
else if (member_ptr == 1)
return PyLong_FromLong(self->data->g);
else if (member_ptr == 2)
return PyLong_FromLong(self->data->b);
else if (member_ptr == 3)
return PyLong_FromLong(self->data->a);
else
{
PyErr_SetString(PyExc_AttributeError, "Invalid attribute");
@ -120,14 +159,14 @@ namespace mcrfpydef {
else if (int_val > 255)
int_val = 255;
auto member_ptr = reinterpret_cast<long>(closure);
if (member_ptr == offsetof(PyColorObject, color.r))
self->color.r = static_cast<sf::Uint8>(int_val);
else if (member_ptr == offsetof(PyColorObject, color.g))
self->color.g = static_cast<sf::Uint8>(int_val);
else if (member_ptr == offsetof(PyColorObject, color.b))
self->color.b = static_cast<sf::Uint8>(int_val);
else if (member_ptr == offsetof(PyColorObject, color.a))
self->color.a = static_cast<sf::Uint8>(int_val);
if (member_ptr == 0)
self->data->r = static_cast<sf::Uint8>(int_val);
else if (member_ptr == 1)
self->data->g = static_cast<sf::Uint8>(int_val);
else if (member_ptr == 2)
self->data->b = static_cast<sf::Uint8>(int_val);
else if (member_ptr == 3)
self->data->a = static_cast<sf::Uint8>(int_val);
}
else
{
@ -138,18 +177,67 @@ namespace mcrfpydef {
}
static PyGetSetDef PyColor_getsetters[] = {
{"r", (getter)PyColor_get_member, (setter)PyColor_set_member, "Red component", (void*)offsetof(PyColorObject, color.r)},
{"g", (getter)PyColor_get_member, (setter)PyColor_set_member, "Green component", (void*)offsetof(PyColorObject, color.g)},
{"b", (getter)PyColor_get_member, (setter)PyColor_set_member, "Blue component", (void*)offsetof(PyColorObject, color.b)},
{"a", (getter)PyColor_get_member, (setter)PyColor_set_member, "Alpha component", (void*)offsetof(PyColorObject, color.a)},
{"r", (getter)PyColor_get_member, (setter)PyColor_set_member, "Red component", (void*)0},
{"g", (getter)PyColor_get_member, (setter)PyColor_set_member, "Green component", (void*)1},
{"b", (getter)PyColor_get_member, (setter)PyColor_set_member, "Blue component", (void*)2},
{"a", (getter)PyColor_get_member, (setter)PyColor_set_member, "Alpha component", (void*)3},
{NULL}
};
static PyTypeObject PyColorType = {
static PyTypeObject PyColorType = {
//PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "mcrfpy.Color",
.tp_basicsize = sizeof(PyColorObject),
.tp_itemsize = 0,
.tp_dealloc = (destructor)[](PyObject* self)
{
PyColorObject* obj = (PyColorObject*)self;
obj->data.reset();
Py_TYPE(self)->tp_free(self);
},
//.tp_repr = (reprfunc)PyUIFrame_repr,
//.tp_hash = NULL,
//.tp_iter
//.tp_iternext
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = PyDoc_STR("SFML Color object (RGBA)"),
//.tp_methods = PyUIFrame_methods,
//.tp_members = PyColor_members,
.tp_getset = PyColor_getsetters,
//.tp_base = NULL,
//.tp_init = (initproc)PyUIFrame_init,
.tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject*
{
PyColorObject* self = (PyColorObject*)type->tp_alloc(type, 0);
if (self) self->data = std::make_shared<sf::Color>();
return (PyObject*)self;
}
};
/*
static PyTypeObject PyUIFrameType = {
.tp_name = "mcrfpy.Frame",
.tp_basicsize = sizeof(PyUIFrameObject),
.tp_itemsize = 0,
.tp_dealloc = (destructor)[](PyObject* self) {
PyUIFrameObject* obj = (PyUIFrameObject*)self;
obj->data.reset();
Py_TYPE(self)->tp_free(self);
},
//.tp_init = (initproc)PyUIFrame_init, // needs implementation
//.tp_new = PyUIFrame_new, // needs implementation
};
*/
/*
static PyTypeObject PyUIFrameType = {
//PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "mcrfpy.Frame",
.tp_basicsize = sizeof(PyColorObject),
.tp_itemsize = 0,
//.tp_dealloc = [](PyObject* obj) { Py_TYPE(obj)->tp_free(obj); },
//.tp_repr = (reprfunc)PyUIFrame_repr,
//.tp_hash = NULL,
@ -165,10 +253,50 @@ namespace mcrfpydef {
.tp_new = PyColor_new, //PyType_GenericNew ?
};
static PyTypeObject PyCaptionType = {
//PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "mcrfpy.Caption",
.tp_basicsize = sizeof(PyColorObject),
.tp_itemsize = 0,
//.tp_dealloc = [](PyObject* obj) { Py_TYPE(obj)->tp_free(obj); },
//.tp_repr = (reprfunc)PyUIFrame_repr,
//.tp_hash = NULL,
//.tp_iter
//.tp_iternext
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = PyDoc_STR("SFML Color object (RGBA)"),
//.tp_methods = PyUIFrame_methods,
//.tp_members = PyColor_members,
.tp_getset = PyColor_getsetters,
//.tp_base = NULL,
//.tp_init = (initproc)PyUIFrame_init,
.tp_new = PyColor_new, //PyType_GenericNew ?
};
static PyTypeObject PySpriteType = {
//PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "mcrfpy.Sprite",
.tp_basicsize = sizeof(PyColorObject),
.tp_itemsize = 0,
//.tp_dealloc = [](PyObject* obj) { Py_TYPE(obj)->tp_free(obj); },
//.tp_repr = (reprfunc)PyUIFrame_repr,
//.tp_hash = NULL,
//.tp_iter
//.tp_iternext
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = PyDoc_STR("SFML Color object (RGBA)"),
//.tp_methods = PyUIFrame_methods,
//.tp_members = PyColor_members,
.tp_getset = PyColor_getsetters,
//.tp_base = NULL,
//.tp_init = (initproc)PyUIFrame_init,
.tp_new = PyColor_new, //PyType_GenericNew ?
};
*/
// UIFrame Definitions
// new, init, repr, set_size, methods, members, PyTypeObject
/*
static PyObject* PyUIFrame_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
{
std::cout << "New called\n";
@ -221,6 +349,7 @@ namespace mcrfpydef {
"Set the width and height of the UIFrame's visible box"},
{NULL, NULL, 0, NULL}
};
*/
/*
static PyMemberDef PyUIFrame_members[] = {
@ -229,6 +358,7 @@ namespace mcrfpydef {
};
*/
/*
static PyTypeObject PyUIFrameType = {
//PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "mcrfpy.UIFrame",
@ -247,6 +377,6 @@ namespace mcrfpydef {
.tp_init = (initproc)PyUIFrame_init,
.tp_new = PyUIFrame_new, //PyType_GenericNew ?
};
*/
}

View File

@ -1,5 +1,6 @@
#include "UITestScene.h"
#include "ActionCode.h"
#include "Resources.h"
UITestScene::UITestScene(GameEngine* g) : Scene(g)
{
@ -12,37 +13,50 @@ UITestScene::UITestScene(GameEngine* g) : Scene(g)
//registerAction(ActionCode::KEY + sf::Keyboard::Up, "up");
//registerAction(ActionCode::KEY + sf::Keyboard::Down, "down");
auto ui = Resources::game->scene_ui("uitest");
if (ui)
{
std::cout << "Got back a UI vector from Resources::game.\n";
} else {
std::cout << "No UI vector was returned.\n";
}
// Create a UI element or three?
e1 = UIFrame(100,150,400,400);
//e1.box.setPosition(100, 150);
//e1.box.setSize(sf::Vector2f(400,400));
//e1.box.setFillColor(sf::Color(255, 0, 0));
e1.fillColor(sf::Color(255,0,0));
auto e1 = std::make_shared<UIFrame>(100,150,400,400);
e1->box.setPosition(100, 150);
e1->box.setSize(sf::Vector2f(400,400));
e1->box.setFillColor(sf::Color(255, 0, 0));
//e1.fillColor(sf::Color(255,0,0));
//if (ui) ui->push_back(e1);
ui_elements.push_back(e1);
e1a = UIFrame(50,50,200,200);
//e1a.box.setPosition(50, 50);
//e1a.box.setSize(sf::Vector2f(200,200));
//e1a.box.setFillColor(sf::Color(0, 255, 0));
e1a.fillColor(sf::Color(0, 255, 0));
e1.children.push_back(&e1a);
auto e1a = std::make_shared<UIFrame>(50,50,200,200);
e1a->box.setPosition(50, 50);
e1a->box.setSize(sf::Vector2f(200,200));
e1a->box.setFillColor(sf::Color(0, 255, 0));
//e1a.fillColor(sf::Color(0, 255, 0));
e1->children.push_back(e1a);
e1aa = UIFrame(5,5,100,100);
//e1aa.box.setPosition(5, 5);
//e1aa.box.setSize(sf::Vector2f(100,100));
//e1aa.box.setFillColor(sf::Color(0, 0, 255));
e1aa.fillColor(sf::Color(0, 0, 255));
e1a.children.push_back(&e1aa);
auto e1aa = std::make_shared<UIFrame>(5,5,100,100);
e1aa->box.setPosition(5, 5);
e1aa->box.setSize(sf::Vector2f(100,100));
e1aa->box.setFillColor(sf::Color(0, 0, 255));
//e1aa.fillColor(sf::Color(0, 0, 255));
e1a->children.push_back(e1aa);
e2 = UICaption();
e2.text.setFont(game->getFont());
e2.text.setString("Hello World.");
auto e2 = std::make_shared<UICaption>();
e2->text.setFont(game->getFont());
e2->text.setString("Hello World.");
//e2.text.setColor(sf::Color(255, 255, 255));
e2.text.setPosition(50, 250);
e2->text.setPosition(50, 250);
ui_elements.push_back(&e1);
ui_elements.push_back(&e2);
//if (ui) ui->push_back(e2);
ui_elements.push_back(e2);
//ui_elements.push_back(&e1);
//ui_elements.push_back(&e2);
if (ui)
std::cout << "pointer to ui_elements now shows size=" << ui->size() << std::endl;
}
void UITestScene::update()
@ -70,10 +84,14 @@ void UITestScene::sRender()
game->getWindow().draw(text);
// draw all UI elements
//for (auto e: ui_elements)
//auto ui = Resources::game->scene_ui("uitest");
//if (ui)
for (auto e: ui_elements)
{
//std::cout << "Rendering element\n";
e->render();
if (e)
e->render();
}
//e1.render(sf::Vector2f(0, 0));

View File

@ -3,15 +3,15 @@
#include "Common.h"
#include "Scene.h"
#include "GameEngine.h"
#include <list>
#include "UI.h"
//#include <list>
//#include "UI.h"
class UITestScene: public Scene
{
sf::Text text;
UIFrame e1, e1a, e1aa;
UICaption e2;
std::vector<UIDrawable*> ui_elements;
//UIFrame e1, e1a, e1aa;
//UICaption e2;
//std::vector<UIDrawable*> ui_elements;
public:
UITestScene(GameEngine*);