mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
python leak fix, python touchscreens
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
25
PyInt.cpp
25
PyInt.cpp
@@ -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;
|
||||
|
||||
35
Train.cpp
35
Train.cpp
@@ -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 != "");
|
||||
|
||||
9
Train.h
9
Train.h
@@ -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
|
||||
|
||||
@@ -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 ); }
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
27
renderer.cpp
27
renderer.cpp
@@ -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 *) {});
|
||||
|
||||
@@ -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;
|
||||
|
||||
9
shaders/pick_surface.frag
Normal file
9
shaders/pick_surface.frag
Normal 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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user