16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 23:19:19 +02:00

milek7/sim branch python taskqueue code import

This commit is contained in:
tmj-fstate
2020-02-22 01:41:34 +01:00
parent 6b1ab6c125
commit fcc8460d88
9 changed files with 304 additions and 79 deletions

View File

@@ -859,6 +859,16 @@ global_settings::ConfigParse(cParser &Parser) {
Parser >> gfx_shadergamma; Parser >> gfx_shadergamma;
} }
*/ */
else if (token == "python.threadedupload")
{
Parser.getTokens(1);
Parser >> python_threadedupload;
}
else if (token == "python.uploadmain")
{
Parser.getTokens(1);
Parser >> python_uploadmain;
}
else if (token == "python.mipmaps") else if (token == "python.mipmaps")
{ {
Parser.getTokens(1); Parser.getTokens(1);

View File

@@ -196,6 +196,8 @@ struct global_settings {
std::string fullscreen_monitor; std::string fullscreen_monitor;
bool python_mipmaps = true; bool python_mipmaps = true;
bool python_threadedupload = true;
bool python_uploadmain = true;
int gfx_framebuffer_width = -1; int gfx_framebuffer_width = -1;
int gfx_framebuffer_height = -1; int gfx_framebuffer_height = -1;

190
PyInt.cpp
View File

@@ -13,16 +13,44 @@ http://mozilla.org/MPL/2.0/.
#include "dictionary.h" #include "dictionary.h"
#include "application.h" #include "application.h"
#include "Logs.h" #include "Logs.h"
#include "Globals.h"
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wwrite-strings"
#endif
void render_task::run() { void render_task::run() {
// convert provided input to a python dictionary // convert provided input to a python dictionary
auto *input = PyDict_New(); auto *input = PyDict_New();
if( input == nullptr ) { goto exit; } if (input == nullptr) {
cancel();
return;
}
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->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->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->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->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;
// call the renderer // call the renderer
auto *output { PyObject_CallMethod( m_renderer, "render", "O", input ) }; auto *output { PyObject_CallMethod( m_renderer, "render", "O", input ) };
@@ -33,39 +61,81 @@ void render_task::run() {
auto *outputheight { PyObject_CallMethod( m_renderer, "get_height", nullptr ) }; auto *outputheight { PyObject_CallMethod( m_renderer, "get_height", nullptr ) };
// upload texture data // upload texture data
if( ( outputwidth != nullptr ) if( ( outputwidth != nullptr )
&& ( outputheight != nullptr ) ) { && ( outputheight != nullptr )
&& m_target) {
int width = PyInt_AsLong( outputwidth );
int height = PyInt_AsLong( outputheight );
int components, format;
::glBindTexture( GL_TEXTURE_2D, m_target ); const unsigned char *image = reinterpret_cast<const unsigned char *>( PyString_AsString( output ) );
// build texture
::glTexImage2D( std::lock_guard<std::mutex> guard(m_target->mutex);
GL_TEXTURE_2D, 0, if (m_target->image)
( Global.GfxFramebufferSRGB ? GL_SRGB8 : GL_RGBA8 ), delete[] m_target->image;
PyInt_AsLong( outputwidth ), PyInt_AsLong( outputheight ), 0,
GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLubyte const *>( PyString_AsString( output ) ) ); if (!Global.gfx_usegles)
// setup texture parameters {
if( ( Global.AnisotropicFiltering >= 0 ) int size = width * height * 3;
&& ( GL_EXT_texture_filter_anisotropic != 0 ) ) { format = GL_SRGB8;
// anisotropic filtering components = GL_RGB;
::glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, Global.AnisotropicFiltering ); m_target->image = new unsigned char[size];
memcpy(m_target->image, image, size);
} }
if( Global.python_mipmaps ) { else
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); {
::glGenerateMipmap( GL_TEXTURE_2D ); format = GL_SRGB8_ALPHA8;
components = GL_RGBA;
m_target->image = new unsigned char[width * height * 4];
int w = width;
int h = height;
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++)
{
m_target->image[(y * w + x) * 4 + 0] = image[(y * w + x) * 3 + 0];
m_target->image[(y * w + x) * 4 + 1] = image[(y * w + x) * 3 + 1];
m_target->image[(y * w + x) * 4 + 2] = image[(y * w + x) * 3 + 2];
m_target->image[(y * w + x) * 4 + 3] = 0xFF;
} }
else {
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
} }
// all done
::glFlush(); m_target->width = width;
m_target->height = height;
m_target->components = components;
m_target->format = format;
m_target->timestamp = std::chrono::high_resolution_clock::now();
} }
if( outputheight != nullptr ) { Py_DECREF( outputheight ); } if( outputheight != nullptr ) { Py_DECREF( outputheight ); }
if( outputwidth != nullptr ) { Py_DECREF( outputwidth ); } if( outputwidth != nullptr ) { Py_DECREF( outputwidth ); }
Py_DECREF( output ); Py_DECREF( output );
} }
}
void render_task::upload()
{
if (Global.python_uploadmain && m_target->image)
{
glBindTexture(GL_TEXTURE_2D, m_target->shared_tex);
glTexImage2D(
GL_TEXTURE_2D, 0,
m_target->format,
m_target->width, m_target->height, 0,
m_target->components, GL_UNSIGNED_BYTE, m_target->image);
if (Global.python_mipmaps)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
if (Global.python_threadedupload)
glFlush();
}
exit:
// clean up after yourself
delete m_input;
delete this; delete this;
} }
@@ -88,9 +158,21 @@ auto python_taskqueue::init() -> bool {
Py_SetPythonHome("linuxpython64"); Py_SetPythonHome("linuxpython64");
else else
Py_SetPythonHome("linuxpython"); Py_SetPythonHome("linuxpython");
#elif __APPLE__
if (sizeof(void*) == 8)
Py_SetPythonHome("macpython64");
else
Py_SetPythonHome("macpython");
#endif #endif
Py_Initialize(); Py_Initialize();
PyEval_InitThreads(); PyEval_InitThreads();
m_initialized = true;
PyObject *stringiomodule { nullptr };
PyObject *stringioclassname { nullptr };
PyObject *stringioobject { nullptr };
// do the setup work while we hold the lock // do the setup work while we hold the lock
m_main = PyImport_ImportModule("__main__"); m_main = PyImport_ImportModule("__main__");
if (m_main == nullptr) { if (m_main == nullptr) {
@@ -98,15 +180,15 @@ auto python_taskqueue::init() -> bool {
goto release_and_exit; goto release_and_exit;
} }
auto *stringiomodule { PyImport_ImportModule( "cStringIO" ) }; stringiomodule = PyImport_ImportModule( "cStringIO" );
auto *stringioclassname { ( stringioclassname = (
stringiomodule != nullptr ? stringiomodule != nullptr ?
PyObject_GetAttrString( stringiomodule, "StringIO" ) : PyObject_GetAttrString( stringiomodule, "StringIO" ) :
nullptr ) }; nullptr );
auto *stringioobject { ( stringioobject = (
stringioclassname != nullptr ? stringioclassname != nullptr ?
PyObject_CallObject( stringioclassname, nullptr ) : PyObject_CallObject( stringioclassname, nullptr ) :
nullptr ) }; nullptr );
m_stderr = { ( m_stderr = { (
stringioobject == nullptr ? nullptr : stringioobject == nullptr ? nullptr :
PySys_SetObject( "stderr", stringioobject ) != 0 ? nullptr : PySys_SetObject( "stderr", stringioobject ) != 0 ? nullptr :
@@ -117,15 +199,17 @@ auto python_taskqueue::init() -> bool {
// release the lock, save the state for future use // release the lock, save the state for future use
m_mainthread = PyEval_SaveThread(); m_mainthread = PyEval_SaveThread();
WriteLog( "Python Interpreter: setup complete" ); WriteLog( "Python Interpreter setup complete" );
// init workers // init workers
for( auto &worker : m_workers ) { for( auto &worker : m_workers ) {
auto *openglcontextwindow { Application.window( -1 ) }; GLFWwindow *openglcontextwindow = nullptr;
if (Global.python_threadedupload)
openglcontextwindow = Application.window( -1 );
worker = std::thread( worker = std::thread(
&python_taskqueue::run, this, &python_taskqueue::run, this,
openglcontextwindow, std::ref( m_tasks ), std::ref( m_condition ), std::ref( m_exit ) ); openglcontextwindow, std::ref( m_tasks ), std::ref(m_uploadtasks), std::ref( m_condition ), std::ref( m_exit ) );
if( false == worker.joinable() ) { return false; } if( false == worker.joinable() ) { return false; }
} }
@@ -139,11 +223,15 @@ release_and_exit:
// shuts down the module // shuts down the module
void python_taskqueue::exit() { void python_taskqueue::exit() {
if (!m_initialized)
return;
// let the workers know we're done with them // let the workers know we're done with them
m_exit = true; m_exit = true;
m_condition.notify_all(); m_condition.notify_all();
// let them free up their shit before we proceed // let them free up their shit before we proceed
for( auto &worker : m_workers ) { for( auto &worker : m_workers ) {
if (worker.joinable())
worker.join(); worker.join();
} }
// get rid of the leftover tasks // get rid of the leftover tasks
@@ -161,8 +249,7 @@ auto python_taskqueue::insert( task_request const &Task ) -> bool {
if( ( Task.renderer.empty() ) if( ( Task.renderer.empty() )
|| ( Task.input == nullptr ) || ( Task.input == nullptr )
|| ( Task.target == 0 ) || ( Task.target == 0 ) ) { return false; }
|| ( Task.target == (GLuint)-1 ) ) { return false; }
auto *renderer { fetch_renderer( Task.renderer ) }; auto *renderer { fetch_renderer( Task.renderer ) };
if( renderer == nullptr ) { return false; } if( renderer == nullptr ) { return false; }
@@ -199,7 +286,8 @@ auto python_taskqueue::run_file( std::string const &File, std::string const &Pat
if( lookup.first.empty() ) { return false; } if( lookup.first.empty() ) { return false; }
std::ifstream inputfile { lookup.first + lookup.second }; std::ifstream inputfile { lookup.first + lookup.second };
std::string const input { std::istreambuf_iterator<char>( inputfile ), std::istreambuf_iterator<char>() }; std::string input;
input.assign( std::istreambuf_iterator<char>( inputfile ), std::istreambuf_iterator<char>() );
if( PyRun_SimpleString( input.c_str() ) != 0 ) { if( PyRun_SimpleString( input.c_str() ) != 0 ) {
error(); error();
@@ -232,6 +320,7 @@ auto python_taskqueue::fetch_renderer( std::string const Renderer ) -> PyObject
auto const file { Renderer.substr( path.size() ) }; auto const file { Renderer.substr( path.size() ) };
PyObject *renderer { nullptr }; PyObject *renderer { nullptr };
PyObject *rendererarguments { nullptr }; PyObject *rendererarguments { nullptr };
PyObject *renderername { nullptr };
acquire_lock(); acquire_lock();
{ {
if( m_main == nullptr ) { if( m_main == nullptr ) {
@@ -242,7 +331,7 @@ auto python_taskqueue::fetch_renderer( std::string const Renderer ) -> PyObject
if( false == run_file( file, path ) ) { if( false == run_file( file, path ) ) {
goto cache_and_return; goto cache_and_return;
} }
auto *renderername{ PyObject_GetAttrString( m_main, file.c_str() ) }; renderername = PyObject_GetAttrString( m_main, file.c_str() );
if( renderername == nullptr ) { if( renderername == nullptr ) {
ErrorLog( "Python Renderer: class \"" + file + "\" not defined" ); ErrorLog( "Python Renderer: class \"" + file + "\" not defined" );
goto cache_and_return; goto cache_and_return;
@@ -271,9 +360,11 @@ cache_and_return:
return renderer; return renderer;
} }
void python_taskqueue::run( GLFWwindow *Context, rendertask_sequence &Tasks, threading::condition_variable &Condition, std::atomic<bool> &Exit ) { void python_taskqueue::run( GLFWwindow *Context, rendertask_sequence &Tasks, uploadtask_sequence &Upload_Tasks, threading::condition_variable &Condition, std::atomic<bool> &Exit ) {
if (Context)
glfwMakeContextCurrent( Context ); glfwMakeContextCurrent( Context );
// create a state object for this thread // create a state object for this thread
PyEval_AcquireLock(); PyEval_AcquireLock();
auto *threadstate { PyThreadState_New( m_mainthread->interp ) }; auto *threadstate { PyThreadState_New( m_mainthread->interp ) };
@@ -302,9 +393,15 @@ void python_taskqueue::run( GLFWwindow *Context, rendertask_sequence &Tasks, thr
{ {
// execute python code // execute python code
task->run(); task->run();
if( PyErr_Occurred() != nullptr ) { if (Context)
error(); task->upload();
else
{
std::lock_guard<std::mutex> lock(Upload_Tasks.mutex);
Upload_Tasks.data.push_back(task);
} }
if( PyErr_Occurred() != nullptr )
error();
} }
// clear the thread state // clear the thread state
PyEval_SaveThread(); PyEval_SaveThread();
@@ -323,10 +420,19 @@ void python_taskqueue::run( GLFWwindow *Context, rendertask_sequence &Tasks, thr
PyEval_ReleaseLock(); PyEval_ReleaseLock();
} }
void python_taskqueue::update()
{
std::lock_guard<std::mutex> lock(m_uploadtasks.mutex);
for (auto &task : m_uploadtasks.data)
task->upload();
m_uploadtasks.data.clear();
}
void void
python_taskqueue::error() { python_taskqueue::error() {
ErrorLog( "Python Interpreter: encountered error" );
if( m_stderr != nullptr ) { if( m_stderr != nullptr ) {
// std err pythona jest buforowane // std err pythona jest buforowane
PyErr_Print(); PyErr_Print();
@@ -362,3 +468,7 @@ python_taskqueue::error() {
} }
} }
} }
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

69
PyInt.h
View File

@@ -7,7 +7,25 @@ obtain one at
http://mozilla.org/MPL/2.0/. http://mozilla.org/MPL/2.0/.
*/ */
#pragma once #ifndef PYINT_H
#define PYINT_H
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#ifdef _XOPEN_SOURCE
#undef _XOPEN_SOURCE
#endif
#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 5033 )
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wregister"
#endif
#ifdef _DEBUG #ifdef _DEBUG
#undef _DEBUG // bez tego macra Py_DECREF powoduja problemy przy linkowaniu #undef _DEBUG // bez tego macra Py_DECREF powoduja problemy przy linkowaniu
@@ -16,35 +34,63 @@ http://mozilla.org/MPL/2.0/.
#else #else
#include "Python.h" #include "Python.h"
#endif #endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#include "Classes.h" #include "Classes.h"
#include "utilities.h"
#define PyGetFloat(param) PyFloat_FromDouble(param) #define PyGetFloat(param) PyFloat_FromDouble(param)
#define PyGetInt(param) PyInt_FromLong(param) #define PyGetInt(param) PyInt_FromLong(param)
#define PyGetBool(param) param ? Py_True : Py_False #define PyGetBool(param) param ? Py_True : Py_False
#define PyGetString(param) PyString_FromString(param) #define PyGetString(param) PyString_FromString(param)
// python rendertarget
struct python_rt {
std::mutex mutex;
GLuint shared_tex;
int format;
int components;
int width;
int height;
unsigned char *image = nullptr;
std::chrono::high_resolution_clock::time_point timestamp;
~python_rt() {
if (image)
delete[] image;
}
};
// TODO: extract common base and inherit specialization from it // TODO: extract common base and inherit specialization from it
class render_task { class render_task {
public: public:
// constructors // constructors
render_task( PyObject *Renderer, dictionary_source *Input, GLuint Target ) : render_task( PyObject *Renderer, dictionary_source *Input, std::shared_ptr<python_rt> Target ) :
m_renderer( Renderer ), m_input( Input ), m_target( Target ) m_renderer( Renderer ), m_input( Input ), m_target( Target )
{} {}
// methods // methods
void run(); void run();
void upload();
void cancel(); void cancel();
auto target() const -> texture_handle { return m_target; } auto target() const -> std::shared_ptr<python_rt> { return m_target; }
private: private:
// members // members
PyObject *m_renderer {nullptr}; PyObject *m_renderer {nullptr};
dictionary_source *m_input { nullptr }; dictionary_source *m_input { nullptr };
GLuint m_target { 0 }; std::shared_ptr<python_rt> m_target { nullptr };
}; };
class python_taskqueue { class python_taskqueue {
public: public:
@@ -53,7 +99,7 @@ public:
std::string const &renderer; std::string const &renderer;
dictionary_source *input; dictionary_source *input;
GLuint target; std::shared_ptr<python_rt> target;
}; };
// constructors // constructors
python_taskqueue() = default; python_taskqueue() = default;
@@ -71,14 +117,17 @@ public:
// releases the python gil and swaps the main thread out // releases the python gil and swaps the main thread out
void release_lock(); void release_lock();
void update();
private: private:
// types // types
static int const WORKERCOUNT { 1 }; static int const WORKERCOUNT { 1 };
using worker_array = std::array<std::thread, WORKERCOUNT >; using worker_array = std::array<std::thread, WORKERCOUNT >;
using rendertask_sequence = threading::lockable< std::deque<render_task *> >; using rendertask_sequence = threading::lockable< std::deque<render_task *> >;
using uploadtask_sequence = threading::lockable< std::deque<render_task *> >;
// methods // methods
auto fetch_renderer( std::string const Renderer ) -> PyObject *; auto fetch_renderer( std::string const Renderer ) -> PyObject *;
void run( GLFWwindow *Context, rendertask_sequence &Tasks, threading::condition_variable &Condition, std::atomic<bool> &Exit ); void run(GLFWwindow *Context, rendertask_sequence &Tasks, uploadtask_sequence &Upload_Tasks, threading::condition_variable &Condition, std::atomic<bool> &Exit );
void error(); void error();
// members // members
PyObject *m_main { nullptr }; PyObject *m_main { nullptr };
@@ -89,4 +138,8 @@ private:
std::atomic<bool> m_exit { false }; // signals the workers to quit std::atomic<bool> m_exit { false }; // signals the workers to quit
std::unordered_map<std::string, PyObject *> m_renderers; // cache of python classes std::unordered_map<std::string, PyObject *> m_renderers; // cache of python classes
rendertask_sequence m_tasks; rendertask_sequence m_tasks;
uploadtask_sequence m_uploadtasks;
bool m_initialized { false };
}; };
#endif

View File

@@ -293,7 +293,10 @@ opengl_texture::make_request() {
auto *dictionary { new dictionary_source( components.back() ) }; auto *dictionary { new dictionary_source( components.back() ) };
if( dictionary == nullptr ) { return; } if( dictionary == nullptr ) { return; }
Application.request( { ToLower( components.front() ), dictionary, id } ); auto rt = std::make_shared<python_rt>();
rt->shared_tex = id;
Application.request( { ToLower( components.front() ), dictionary, rt } );
} }
void void

View File

@@ -35,6 +35,8 @@ struct opengl_texture {
// releases resources allocated on the opengl end, storing local copy if requested // releases resources allocated on the opengl end, storing local copy if requested
void void
release(); release();
void
make_stub();
void void
alloc_rendertarget( GLint format, GLint components, int width, int height, int layers = 1, int samples = 1, GLint wrap = GL_CLAMP_TO_EDGE ); alloc_rendertarget( GLint format, GLint components, int width, int height, int layers = 1, int samples = 1, GLint wrap = GL_CLAMP_TO_EDGE );
void void
@@ -65,7 +67,6 @@ struct opengl_texture {
private: private:
// methods // methods
void make_stub();
void make_request(); void make_request();
void load_BMP(); void load_BMP();
void load_DDS(); void load_DDS();

View File

@@ -6913,7 +6913,12 @@ bool TTrain::Update( double const Deltatime )
&& ( false == FreeFlyModeFlag ) ) { // don't bother if we're outside && ( false == FreeFlyModeFlag ) ) { // don't bother if we're outside
fScreenTimer = 0.f; fScreenTimer = 0.f;
for( auto const &screen : m_screens ) { for( auto const &screen : m_screens ) {
Application.request( { screen.first, GetTrainState(), GfxRenderer->Texture( screen.second ).id } ); auto state_dict = GetTrainState();
/*
state_dict->insert("touches", *screen.touch_list);
screen.touch_list->clear();
*/
Application.request({ screen.rendererpath, state_dict, screen.rt } );
} }
} }
// sounds // sounds
@@ -7707,7 +7712,15 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
>> submodelname >> submodelname
>> renderername; >> renderername;
auto const *submodel { ( DynamicObject->mdKabina ? DynamicObject->mdKabina->GetFromName( submodelname ) : nullptr ) }; 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") {
submodel = ( DynamicObject->mdKabina ? DynamicObject->mdKabina->GetFromName( submodelname ) : nullptr );
if( submodel == nullptr ) { if( submodel == nullptr ) {
WriteLog( "Python Screen: submodel " + submodelname + " not found - Ignoring screen" ); WriteLog( "Python Screen: submodel " + submodelname + " not found - Ignoring screen" );
continue; continue;
@@ -7718,12 +7731,34 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
WriteLog( "Python Screen: invalid texture id " + std::to_string( material ) + " - Ignoring screen" ); WriteLog( "Python Screen: invalid texture id " + std::to_string( material ) + " - Ignoring screen" );
continue; continue;
} }
tex = &GfxRenderer->Texture(GfxRenderer->Material(material).textures[0]);
}
else {
// TODO: fix leak
tex = new opengl_texture();
tex->make_stub();
}
tex->create();
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 // record renderer and material binding for future update requests
m_screens.emplace_back( m_screens.emplace_back();
( substr_path(renderername).empty() ? // supply vehicle folder as path if none is provided m_screens.back().rendererpath = rendererpath;
DynamicObject->asBaseDir + renderername : m_screens.back().rt = rt;
renderername ), /*
GfxRenderer->Material( material ).textures[0] ); m_screens.back().touch_list = touch_list;
if (Global.python_displaywindows)
m_screens.back().viewer = std::make_unique<python_screen_viewer>(rt, touch_list, rendererpath);
*/
} }
// btLampkaUnknown.Init("unknown",mdKabina,false); // btLampkaUnknown.Init("unknown",mdKabina,false);
} while (token != ""); } while (token != "");

13
Train.h
View File

@@ -110,6 +110,17 @@ class TTrain {
bool springbrake_active; bool springbrake_active;
}; };
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;
// constructors // constructors
TTrain(); TTrain();
// methods // methods
@@ -760,7 +771,7 @@ private:
float fPPress, fNPress; float fPPress, fNPress;
bool m_mastercontrollerinuse { false }; bool m_mastercontrollerinuse { false };
float m_mastercontrollerreturndelay { 0.f }; float m_mastercontrollerreturndelay { 0.f };
std::vector<std::pair<std::string, texture_handle>> m_screens; screen_map m_screens;
uint16_t vid { 0 }; // train network recipient id uint16_t vid { 0 }; // train network recipient id
float m_distancecounter { -1.f }; // distance traveled since meter was activated or -1 if inactive float m_distancecounter { -1.f }; // distance traveled since meter was activated or -1 if inactive
double m_brakehandlecp{ 0.0 }; double m_brakehandlecp{ 0.0 };

View File

@@ -306,7 +306,7 @@ eu07_application::run() {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// TODO: re-enable after python changes merge // TODO: re-enable after python changes merge
// m_taskqueue.update(); m_taskqueue.update();
if (!GfxRenderer->Render()) if (!GfxRenderer->Render())
return 0; return 0;