python leak fix, python touchscreens

This commit is contained in:
milek7
2019-11-26 22:20:46 +01:00
parent 5b172ec663
commit e697b01296
12 changed files with 163 additions and 39 deletions

View File

@@ -218,6 +218,7 @@ public:
return m_material; }
void ParentMatrix(float4x4 *m) const;
float MaxY( float4x4 const &m );
std::shared_ptr<std::vector<glm::vec2>> screen_touch_list; // for python screen touching
std::optional<gl::query> occlusion_query;
glm::mat4 future_transform;

View File

@@ -27,10 +27,27 @@ void render_task::run() {
cancel();
return;
}
for( auto const &datapair : m_input->floats ) { PyDict_SetItemString( input, datapair.first.c_str(), PyGetFloat( datapair.second ) ); }
for( auto const &datapair : m_input->integers ) { PyDict_SetItemString( input, datapair.first.c_str(), PyGetInt( datapair.second ) ); }
for( auto const &datapair : m_input->bools ) { PyDict_SetItemString( input, datapair.first.c_str(), PyGetBool( datapair.second ) ); }
for( auto const &datapair : m_input->strings ) { PyDict_SetItemString( input, datapair.first.c_str(), PyGetString( datapair.second.c_str() ) ); }
for( auto const &datapair : m_input->floats ) { auto *value{ PyGetFloat( datapair.second ) }; PyDict_SetItemString( input, datapair.first.c_str(), value ); Py_DECREF( value ); }
for( auto const &datapair : m_input->integers ) { auto *value{ PyGetInt( datapair.second ) }; PyDict_SetItemString( input, datapair.first.c_str(), value ); Py_DECREF( value ); }
for( auto const &datapair : m_input->bools ) { auto *value{ PyGetBool( datapair.second ) }; PyDict_SetItemString( input, datapair.first.c_str(), value ); }
for( auto const &datapair : m_input->strings ) { auto *value{ PyGetString( datapair.second.c_str() ) }; PyDict_SetItemString( input, datapair.first.c_str(), value ); Py_DECREF( value ); }
for (auto const &datapair : m_input->vec2_lists) {
PyObject *list = PyList_New(datapair.second.size());
for (size_t i = 0; i < datapair.second.size(); i++) {
auto const &vec = datapair.second[i];
PyObject *tuple = PyTuple_New(2);
PyTuple_SetItem(tuple, 0, PyGetFloat(vec.x)); // steals ref
PyTuple_SetItem(tuple, 1, PyGetFloat(vec.y)); // steals ref
PyList_SetItem(list, i, tuple); // steals ref
}
PyDict_SetItemString(input, datapair.first.c_str(), list);
Py_DECREF(list);
}
delete m_input;
m_input = nullptr;

View File

@@ -589,6 +589,7 @@ dictionary_source *TTrain::GetTrainState() {
driver->TrainTimetable()->serialize( dict );
dict->insert( "train_stationstart", driver->iStationStart );
dict->insert( "train_atpassengerstop", driver->IsAtPassengerStop );
dict->insert( "train_length", driver->fLength );
// world state data
dict->insert( "scenario", Global.SceneryFile );
dict->insert( "hours", static_cast<int>( simulation::Time.data().wHour ) );
@@ -6957,8 +6958,14 @@ void TTrain::update_sounds_radio() {
void TTrain::update_screens() {
if (fScreenTimer > Global.PythonScreenUpdateRate * 0.001f) {
fScreenTimer = 0.f;
for (auto const &screen : m_screens)
Application.request( { std::get<0>(screen), GetTrainState(), std::get<1>(screen) } );
for (auto const &screen : m_screens) {
auto state_dict = GetTrainState();
state_dict->insert("touches", *screen.touch_list);
screen.touch_list->clear();
Application.request({ screen.rendererpath, state_dict, screen.rt } );
}
}
}
@@ -7398,9 +7405,15 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
>> submodelname
>> renderername;
const std::string rendererpath {
substr_path(renderername).empty() ? // supply vehicle folder as path if none is provided
DynamicObject->asBaseDir + renderername :
renderername };
opengl_texture *tex = nullptr;
TSubModel *submodel = nullptr;
if (submodelname != "none") {
auto const *submodel { ( DynamicObject->mdKabina ? DynamicObject->mdKabina->GetFromName( submodelname ) : nullptr ) };
submodel = ( DynamicObject->mdKabina ? DynamicObject->mdKabina->GetFromName( submodelname ) : nullptr );
if( submodel == nullptr ) {
WriteLog( "Python Screen: submodel " + submodelname + " not found - Ignoring screen" );
continue;
@@ -7422,19 +7435,21 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
tex->create();
const std::string rendererpath {
substr_path(renderername).empty() ? // supply vehicle folder as path if none is provided
DynamicObject->asBaseDir + renderername :
renderername };
auto touch_list = std::make_shared<std::vector<glm::vec2>>();
auto rt = std::make_shared<python_rt>();
rt->shared_tex = tex->id;
if (submodel)
submodel->screen_touch_list = touch_list;
// record renderer and material binding for future update requests
m_screens.emplace_back(rendererpath, rt, nullptr);
m_screens.emplace_back();
m_screens.back().rendererpath = rendererpath;
m_screens.back().rt = rt;
m_screens.back().touch_list = touch_list;
if (Global.python_displaywindows)
std::get<2>(m_screens.back()) = std::make_unique<python_screen_viewer>(rt, rendererpath);
m_screens.back().viewer = std::make_unique<python_screen_viewer>(rt, touch_list, rendererpath);
}
// btLampkaUnknown.Init("unknown",mdKabina,false);
} while (token != "");

View File

@@ -107,7 +107,14 @@ class TTrain {
int radio_channel;
bool springbrake_active;
};
typedef std::tuple<std::string, std::shared_ptr<python_rt>, std::unique_ptr<python_screen_viewer>> screen_entry;
struct screen_entry {
std::string rendererpath;
std::shared_ptr<python_rt> rt;
std::unique_ptr<python_screen_viewer> viewer;
std::shared_ptr<std::vector<glm::vec2>> touch_list;
};
typedef std::vector<screen_entry> screen_map;
// methods

View File

@@ -20,6 +20,7 @@ struct dictionary_source {
keyvaluepair_sequence<int> integers;
keyvaluepair_sequence<bool> bools;
keyvaluepair_sequence<std::string> strings;
keyvaluepair_sequence<std::vector<glm::vec2>> vec2_lists;
// constructors
dictionary_source() = default;
dictionary_source( std::string const &Input );
@@ -28,4 +29,5 @@ struct dictionary_source {
inline void insert( std::string const &Key, int const Value ) { integers.emplace_back( Key, Value ); }
inline void insert( std::string const &Key, bool const Value ) { bools.emplace_back( Key, Value ); }
inline void insert( std::string const &Key, std::string const Value ) { strings.emplace_back( Key, Value ); }
inline void insert( std::string const &Key, std::vector<glm::vec2> const Value ) { vec2_lists.emplace_back( Key, Value ); }
};

View File

@@ -368,11 +368,19 @@ drivermouse_input::button( int const Button, int const Action ) {
else {
// if not release then it's press
m_pickwaiting = true;
GfxRenderer.pick_control([this, Button, Action, &mousecommand](TSubModel const *control)
GfxRenderer.pick_control([this, Button, Action, &mousecommand](TSubModel const *control, const glm::vec2 pos)
{
bool pickwaiting = m_pickwaiting;
m_pickwaiting = false;
// click on python screen
if (Button == GLFW_MOUSE_BUTTON_LEFT
&& control && control->screen_touch_list) {
control->screen_touch_list->emplace_back(pos);
return;
}
auto const lookup = m_buttonbindings.find( simulation::Train->GetLabel( control ) );
if( lookup != m_buttonbindings.end() ) {
// if the recognized element under the cursor has a command associated with the pressed button, notify the recipient

View File

@@ -11,9 +11,22 @@ void texture_window_fb_resize(GLFWwindow *win, int w, int h)
texwindow->notify_window_size(win, w, h);
}
python_screen_viewer::python_screen_viewer(std::shared_ptr<python_rt> rt, std::string surfacename)
void texture_window_mouse_button(GLFWwindow *win, int button, int action, int mods)
{
python_screen_viewer *texwindow = (python_screen_viewer*)glfwGetWindowUserPointer(win);
texwindow->notify_click(win, button, action);
}
void texture_window_cursor_pos(GLFWwindow *win, double x, double y)
{
python_screen_viewer *texwindow = (python_screen_viewer*)glfwGetWindowUserPointer(win);
texwindow->notify_cursor_pos(win, x, y);
}
python_screen_viewer::python_screen_viewer(std::shared_ptr<python_rt> rt, std::shared_ptr<std::vector<glm::vec2>> touchlist, std::string surfacename)
{
m_rt = rt;
m_touchlist = touchlist;
for (const auto &viewport : Global.python_viewports) {
if (viewport.surface == surfacename) {
@@ -31,6 +44,8 @@ python_screen_viewer::python_screen_viewer(std::shared_ptr<python_rt> rt, std::s
glfwSetWindowUserPointer(conf->window, this);
glfwSetFramebufferSizeCallback(conf->window, texture_window_fb_resize);
glfwSetMouseButtonCallback(conf->window, texture_window_mouse_button);
glfwSetCursorPosCallback(conf->window, texture_window_cursor_pos);
m_windows.push_back(std::move(conf));
}
@@ -166,6 +181,34 @@ void python_screen_viewer::notify_window_size(GLFWwindow *window, int w, int h)
}
}
void python_screen_viewer::notify_cursor_pos(GLFWwindow *window, double x, double y)
{
for (auto &conf : m_windows) {
if (conf->window == window) {
conf->cursor_pos.x = x;
conf->cursor_pos.y = y;
return;
}
}
}
void python_screen_viewer::notify_click(GLFWwindow *window, int button, int action)
{
if (button != GLFW_MOUSE_BUTTON_LEFT || action != GLFW_PRESS)
return;
for (auto &conf : m_windows) {
if (conf->window == window) {
auto pos = glm::vec2(conf->cursor_pos) / glm::vec2(conf->size);
pos.y = 1.0f - pos.y;
pos = (pos + conf->offset) / conf->scale;
m_touchlist->emplace_back(pos);
return;
}
}
}
python_screen_viewer::window_state::~window_state()
{
if (!window)

View File

@@ -6,7 +6,9 @@ class python_screen_viewer
{
struct window_state {
GLFWwindow *window = nullptr;
glm::ivec2 size;
glm::ivec2 cursor_pos;
glm::vec2 offset;
glm::vec2 scale;
@@ -23,6 +25,7 @@ class python_screen_viewer
std::vector<std::unique_ptr<window_state>> m_windows;
std::shared_ptr<python_rt> m_rt;
std::shared_ptr<std::vector<glm::vec2>> m_touchlist;
std::shared_ptr<std::thread> m_renderthread;
gl::scene_ubs m_ubs;
@@ -31,8 +34,10 @@ class python_screen_viewer
void threadfunc();
public:
python_screen_viewer(std::shared_ptr<python_rt> rt, std::string name);
python_screen_viewer(std::shared_ptr<python_rt> rt, std::shared_ptr<std::vector<glm::vec2>> touchlist, std::string name);
~python_screen_viewer();
void notify_window_size(GLFWwindow *window, int w, int h);
void notify_cursor_pos(GLFWwindow *window, double x, double y);
void notify_click(GLFWwindow *window, int button, int action);
};

View File

@@ -246,6 +246,7 @@ bool opengl_renderer::Init(GLFWwindow *Window)
m_shadow_shader = make_shader("simpleuv.vert", "shadowmap.frag");
m_alpha_shadow_shader = make_shader("simpleuv.vert", "alphashadowmap.frag");
m_pick_shader = make_shader("vertexonly.vert", "pick.frag");
m_pick_surface_shader = make_shader("simpleuv.vert", "pick_surface.frag");
m_billboard_shader = make_shader("simpleuv.vert", "billboard.frag");
m_celestial_shader = make_shader("celestial.vert", "celestial.frag");
if (Global.gfx_usegles)
@@ -985,6 +986,7 @@ void opengl_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
m_pick_fb->bind();
m_pick_fb->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_picksurfaceitems.clear();
m_pickcontrolsitems.clear();
setup_matrices();
setup_drawing(false);
@@ -2661,10 +2663,19 @@ void opengl_renderer::Render(TSubModel *Submodel)
}
case rendermode::pickcontrols:
{
m_pick_shader->bind();
if (Submodel->screen_touch_list) {
// touch screen gradient
m_pick_surface_shader->bind();
model_ubs.param[0] = glm::vec4(1.0f - m_picksurfaceitems.size() / 255.0f, 0.0f, 0.0f, 1.0f);
m_picksurfaceitems.emplace_back(Submodel);
}
else {
// control picking applies individual colour for each submodel
m_pick_shader->bind();
m_pickcontrolsitems.emplace_back(Submodel);
model_ubs.param[0] = glm::vec4(pick_color(m_pickcontrolsitems.size()), 1.0f);
}
draw(Submodel->m_geometry);
break;
}
@@ -3647,15 +3658,19 @@ void opengl_renderer::Update_Pick_Control()
{
auto const controlindex = pick_index(glm::ivec3{pickreadout[0], pickreadout[1], pickreadout[2]});
TSubModel const *control{nullptr};
if ((controlindex > 0) && (controlindex <= m_pickcontrolsitems.size()))
{
glm::vec2 position(0.0f);
if ((controlindex > 0) && (controlindex <= m_pickcontrolsitems.size())) {
control = m_pickcontrolsitems[controlindex - 1];
} else if (255 - pickreadout[0] < m_picksurfaceitems.size()) {
control = m_picksurfaceitems[255 - pickreadout[0]];
position.x = pickreadout[1] / 255.0f;
position.y = pickreadout[2] / 255.0f;
}
m_pickcontrolitem = control;
for (auto f : m_control_pick_requests)
f(m_pickcontrolitem);
f(m_pickcontrolitem, position);
m_control_pick_requests.clear();
}
@@ -3716,7 +3731,7 @@ void opengl_renderer::Update_Pick_Node()
}
}
void opengl_renderer::pick_control(std::function<void(TSubModel const *)> callback)
void opengl_renderer::pick_control(std::function<void(const TSubModel *, glm::vec2)> callback)
{
m_control_pick_requests.push_back(callback);
}
@@ -3851,7 +3866,7 @@ void opengl_renderer::Update(double const Deltatime)
}
if ((true == Global.ControlPicking) && (false == FreeFlyModeFlag))
pick_control([](const TSubModel *) {});
pick_control([](const TSubModel *, const glm::vec2) {});
// temporary conditions for testing. eventually will be coupled with editor mode
if ((true == Global.ControlPicking) && (true == DebugModeFlag) && (true == FreeFlyModeFlag))
pick_node([](scene::basic_node *) {});

View File

@@ -228,7 +228,7 @@ class opengl_renderer
std::string const &info_times() const;
std::string const &info_stats() const;
void pick_control(std::function<void(TSubModel const *)> callback);
void pick_control(std::function<void(TSubModel const *, glm::vec2)> callback);
void pick_node(std::function<void(scene::basic_node *)> callback);
// members
@@ -403,6 +403,7 @@ class opengl_renderer
renderpass_config m_shadowpass; // parametrs of most recent shadowmap pass
renderpass_config m_cabshadowpass; // parameters of most recent cab shadowmap pass
std::vector<TSubModel const *> m_pickcontrolsitems;
std::vector<TSubModel const *> m_picksurfaceitems;
TSubModel const *m_pickcontrolitem{nullptr};
std::vector<scene::basic_node *> m_picksceneryitems;
scene::basic_node *m_picksceneryitem{nullptr};
@@ -420,7 +421,7 @@ class opengl_renderer
glm::mat4 ortho_projection(float left, float right, float bottom, float top, float z_near, float z_far);
glm::mat4 ortho_frustumtest_projection(float left, float right, float bottom, float top, float z_near, float z_far);
std::vector<std::function<void(TSubModel const *)>> m_control_pick_requests;
std::vector<std::function<void(TSubModel const *, glm::vec2)>> m_control_pick_requests;
std::vector<std::function<void(scene::basic_node *)>> m_node_pick_requests;
std::unique_ptr<gl::shader> m_vertex_shader;
@@ -452,6 +453,7 @@ class opengl_renderer
std::unique_ptr<gl::framebuffer> m_pick_fb;
std::unique_ptr<opengl_texture> m_pick_tex;
std::unique_ptr<gl::renderbuffer> m_pick_rb;
std::unique_ptr<gl::program> m_pick_surface_shader;
std::unique_ptr<gl::program> m_pick_shader;
std::unique_ptr<gl::cubemap> m_empty_cubemap;

View File

@@ -0,0 +1,9 @@
#include <common>
layout(location = 0) out vec4 out_color;
in vec2 f_coord;
void main()
{
out_color = vec4(param[0].r, f_coord, 1.0);
}

View File

@@ -110,7 +110,7 @@ void ui::vehicleparams_panel::render_contents()
for (const auto &viewport : Global.python_viewports) {
for (auto const &entry : screens) {
if (std::get<std::string>(entry) != viewport.surface)
if (entry.rendererpath != viewport.surface)
continue;
std::string window_name = STR("Screen") + "##" + viewport.surface;
@@ -126,7 +126,7 @@ void ui::vehicleparams_panel::render_contents()
ImVec2 size = ImGui::GetContentRegionAvail();
ImGui::Image(reinterpret_cast<void*>(std::get<1>(entry)->shared_tex), size, ImVec2(uv0.x, uv0.y), ImVec2(uv1.x, uv1.y));
ImGui::Image(reinterpret_cast<void*>(entry.rt->shared_tex), size, ImVec2(uv0.x, uv0.y), ImVec2(uv1.x, uv1.y));
}
ImGui::End();
}