marinos.giannoukakis Posted August 28, 2017 Posted August 28, 2017 (edited) Integrating Spout with Unigine by making a plugin, have an issue passing the strings to spout receiver classes that are using *char instead of const *char. So I get the message "can't convert string to char * __ptr64", when trying to pass a string from UnigineScript. I have read this post from UncleBob, how do I solve this given that I don t want to change Spout source..... (wouldn't even know what that could cause later...!!) is there a good way of converting the strings so they can be passed as arguments to the Spout Receiver class...? Edited August 28, 2017 by marinos.giannoukakis
alexander Posted August 29, 2017 Posted August 29, 2017 Hi! Use const_cast in your C++ plugin to convert "const char*" to "char*". For example: const char * string_from_UnigineScript; char * string_to_Spout; string_to_Spout = const_cast<char *>(string_from_UnigineScript); Best regards, Alexander
marinos.giannoukakis Posted August 29, 2017 Author Posted August 29, 2017 Awesome I was hoping exactly for something like that, thanks Alexander....!!!! The thing is that this type of casting is going to be needed in other libraries I am working on and still keeps the plugin modularity.....will try it and let you know....
marinos.giannoukakis Posted September 2, 2017 Author Posted September 2, 2017 Hi I have implemented the plugin but most of the time trying to initialize it I get a Unigine fatal error that the System::Allocator::allocate() can't allocate -1232124151(this number changes) bytes somehow I am not using the Unigine::Image class right. What would be the right way to create an empty image in order for it to receive the textures send from a Spout sender...??? Some times the plugin initializes correctly (have not tried to receive a texture yet so can' t be totally sure) and I don't get the Unigine fatal error message.
silent Posted September 5, 2017 Posted September 5, 2017 Hi Marinos, Any relevant code with Image class usage? Maybe some small sample (even without Spout) just to see what is going on? Thanks! How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN
marinos.giannoukakis Posted September 5, 2017 Author Posted September 5, 2017 Yes I am going to post something tomorrow, Thanks Silent....
marinos.giannoukakis Posted September 6, 2017 Author Posted September 6, 2017 (edited) so there you go the full plugin (almost)... or at least one of the many versions...this crashes Unigine.... memory leaks all over the place prob.... does not like the opengl texture function calls (texture.getGLTextureID(), texture.getGLTarget()) etc.... not sure how to point a Unigine Image or Texture to the spout received one and then pass it to Uniginescript.... any help would be appreciated... I am trying to implement the Receiver class first for now.... #include "Spout.h" #include "SpoutCopy.h" #include "resource.h" // for custom icon #include <string> #include "SpoutReceiver.h" using namespace Unigine; /******************************************************************************\ * * a SpoutSender Class for Unigine * \******************************************************************************/ class SpoutSenderUnit : public SpoutSender { public: SpoutSenderUnit(); ~SpoutSenderUnit(); bool init(string channelName, int initialWidth = 64, int initialHeight = 64); void release(); bool isInitialized() const; bool isMemoryShareMode(); bool send(const Texture &, bool flipY = false); // replace with Unigine Texture string getChannelName() const; bool setVerticalSync(bool); bool getVerticalSync(); Spout spout; protected: string channelName; SpoutSender * spoutSender; int width, height; }; /******************************************************************************\ * * a SpoutReceiver Class for Unigine * \******************************************************************************/ class SpoutReceiverUnit:public SpoutReceiver { public: SpoutReceiverUnit(); ~SpoutReceiverUnit(); bool init(const char *channelName = ""); void release(); bool isInitialized() const; bool receive(Texture &); // will automatically allocate the texture need to replace with Unigine Texture bool selectSenderPanel(); const char * getChannelName() const; float getWidth() const; float getHeight() const; Spout spout; ImagePtr SpoutImageCreate(); protected: const char * channelName; Materials *materials; Image *image; ImagePtr _image; //Texture *texture; SpoutReceiver *spoutReceiver; int width; int height; const int defaultFormat; // = GL_RGBA. If you're using anything else then make sure to allocate your texture manually Material *material; }; SpoutReceiverUnit::SpoutReceiverUnit() : defaultFormat(GL_RGBA) { this->spoutReceiver = nullptr; this->width = 0; this->height = 0; } //---------- SpoutReceiverUnit::~SpoutReceiverUnit() { this->release(); } //---------- bool SpoutReceiverUnit::init(const char* channelName) { this->release(); try { this->spoutReceiver = new SpoutReceiver(); char * mutableName = const_cast<char *>(channelName); unsigned int mutableWidth, mutableHeight; /* if (!this->spoutReceiver->CreateReceiver(mutableName, mutableWidth, mutableHeight, channelName.empty())) { throw("Can't create receiver"); }*/ // dont need the above i think this->channelName = (mutableName); this->width = mutableWidth; this->height = mutableHeight; this->image->Image::create(); // create material library this->materials = Materials::get(); this->materials->create("spout_library"); this->materials->inheritMaterial("mesh_base","spout_library","spout_material"); this->materials->findMaterial("spout_material"); //this->texture->Texture::create(); return true; } catch (const char * e) { Log::warning("Spout::Sender::init:%d Channel : %d", channelName,e ); //this needs to change and replace %d with string return false; } } void SpoutReceiverUnit::release() { if (this->isInitialized()) { this->spoutReceiver->ReleaseReceiver(); delete this->spoutReceiver; this->spoutReceiver = nullptr; this->width = 0; this->height = 0; } } //---------- bool SpoutReceiverUnit::isInitialized() const { if (this->spoutReceiver) { return true; } else { return false; } } //---------- bool SpoutReceiverUnit::receive(Texture & texture) { try { //check if we're initialised if (!this->isInitialized()) { throw("Not initialized"); } //prepare the channel name, allow it to be changed if different channels are available unsigned int mutableWidth, mutableHeight; char * mutableName = const_cast<char *>(channelName); //check if the texture is allocated correctly, if not, allocate it if (texture.getWidth() != this->width || texture.getHeight() != this->height) { texture.create2D(width, height, texture.getFormat(), 0) ? texture.getFormat(): this->defaultFormat; texture.create2D(width, height, texture.getFormat(), 0); // Texture *textureMaterial; // textureMaterial->&texture; // this->material->setImageTexture (texture->getGLTextureID(), format) ; } //pull data into the texture (keep any existing fbo attachments) GLint drawFboId = 0; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFboId); if (!this->spoutReceiver->ReceiveTexture(mutableName, mutableWidth, mutableHeight, texture.getGLTextureID(), texture.getGLTarget(), false, drawFboId)) { throw("Can't receive texture"); } //update our local settings incase anything changed this->channelName = mutableName; this->width = mutableWidth; this->height = mutableHeight; return true; } catch (const char * e) { Log::warning("Spout::Receiver::receive->", e); return false; } } //---------- bool SpoutReceiverUnit::selectSenderPanel() { try { if (!this->isInitialized()) { throw("Not initialized"); } this->spoutReceiver->SelectSenderPanel(); return true; } catch (const char * e) { Log::warning("Spout::Receiver::selectSenderPanel", e); return false; } } //----------- const char * SpoutReceiverUnit::getChannelName() const { return this->channelName; } //---------- float SpoutReceiverUnit::getWidth() const { return this->width; } //---------- float SpoutReceiverUnit::getHeight() const { return this->height; } /* */ /******************************************************************************\ * * SpoutPlugin * \******************************************************************************/ /* */ class SpoutPlugin : public Plugin { public: SpoutPlugin() { Log::warning("SpoutPlugin::SpoutPlugin(): called\n"); } virtual ~SpoutPlugin() { Log::warning("SpoutPlugin::~SpoutPlugin(): called\n"); } // plugin data virtual void *get_data() { return this; } // initialize plugin virtual int init(); // shutdown plugin virtual int shutdown(); // destroy plugin virtual void destroy(); // initialize world virtual int initWorld(); // shutdown world virtual int shutdownWorld(); }; /* */ int SpoutPlugin::init() { Log::warning("SpoutPlugin::init(): called\n"); // export extern class SpoutReceiver ExternClass<SpoutReceiverUnit> *spout_receiver = MakeExternClass<SpoutReceiverUnit>(); spout_receiver->addConstructor(); spout_receiver->addFunction("init",&SpoutReceiverUnit::init); spout_receiver->addFunction("release",&SpoutReceiverUnit::release); spout_receiver->addFunction("isInitialized",&SpoutReceiverUnit::isInitialized); spout_receiver->addFunction("receive",&SpoutReceiverUnit::receive); spout_receiver->addFunction("selectSenderPanel",&SpoutReceiverUnit::selectSenderPanel); spout_receiver->addFunction("getChannelName",&SpoutReceiverUnit::getChannelName); spout_receiver->addFunction("getWidth",&SpoutReceiverUnit::getWidth); spout_receiver->addFunction("getHeight",&SpoutReceiverUnit::getHeight); //spout_receiver->addFunction("spoutImageCreate",&SpoutReceiverUnit::SpoutImageCreate); Interpreter::addExternClass("SpoutReceiverUnit",spout_receiver); return 1; } int SpoutPlugin::shutdown() { Log::warning("SpoutPlugin::shutdown(): called\n"); // remove function // Interpreter::removeExternFunction("my_print"); // remove extern class Interpreter::removeExternClass("SpoutSenderUnit"); Interpreter::removeExternClass("SpoutReceiverUnit"); return 1; } /* */ void SpoutPlugin::destroy() { Log::warning("SpoutPlugin::destroy(): called\n"); } /* */ int SpoutPlugin::initWorld() { Log::error("\nSpoutPlugin::initWorld(): called\n\n"); return 1; } int SpoutPlugin::shutdownWorld() { Log::error("\nSpoutPlugin::shutdownWorld(): called\n\n"); return 1; } /******************************************************************************\ * * Plugin export * \******************************************************************************/ /* */ extern "C" UNIGINE_API void *CreatePlugin() { return new SpoutPlugin(); } extern "C" UNIGINE_API void ReleasePlugin(void *plugin) { delete static_cast<SpoutPlugin*>(plugin); } Edited September 6, 2017 by marinos.giannoukakis
alexander Posted September 7, 2017 Posted September 7, 2017 Hi Marinos, The main problem that i see: Use ImagePtr/TexturePtr instead of Image*/Texture* because Image::create() returns to you ImagePtr which controls Image object. If ImagePtr is destroyed (goes out of scope), Image will also be removed from the memory. If you need direct access to the Image class instead of ImagePtr, use image_ptr.get() method. For example: this->image->Image::create(); // image - is object of Image type _image = Image::create(); // _image - is ImagePtr object or: bool SpoutReceiverUnit::receive(Texture & texture) { texture.create2D(width, height, texture.getFormat(), 0); bool SpoutReceiverUnit::receive(const TexturePtr & texture) { texture->create2D(width, height, texture->getFormat(), 0); More about memory management you can see here: https://developer.unigine.com/en/docs/2.5/code/fundamentals/memory_management Best regards, Alexander
marinos.giannoukakis Posted September 7, 2017 Author Posted September 7, 2017 Thank you I ll change it to pointers.....I will let you know of results....
marinos.giannoukakis Posted September 11, 2017 Author Posted September 11, 2017 (edited) Hi again I am posting the code using pointers. This compiles but when I load the material on an object (I am inheriting from mesh_base), I am getting an "OpenGL error: invalid enumeration" message... I am guessing there is a conflict between the OpenGL GL_RBGA format, and the Unigine texture formats. Do you have any suggestions to get over this......???? Again I am going to say that for now I am focusing on the SpoutReceiverUnit Class rather than the sender... The rest of the functions seem to work fine and the plugin recognises all the active senders and the textures they send (size etc...).... the problem comes when loading these textures to local Unigine texture formats... so whatever suggestion and solution is very much appreciated..... Thank you.... using namespace Unigine; /******************************************************************************\ * * a SpoutSender Class for Unigine * \******************************************************************************/ class SpoutSenderUnit : public SpoutSender { public: SpoutSenderUnit(); ~SpoutSenderUnit(); bool init(string channelName, int initialWidth = 64, int initialHeight = 64); void release(); bool isInitialized() const; bool isMemoryShareMode(); bool send(const Texture &, bool flipY = false); // replace with Unigine Texture string getChannelName() const; bool setVerticalSync(bool); bool getVerticalSync(); Spout spout; protected: string channelName; SpoutSender * spoutSender; int width, height; }; /******************************************************************************\ * * a SpoutReceiver Class for Unigine * \******************************************************************************/ class SpoutReceiverUnit:public SpoutReceiver { public: SpoutReceiverUnit(); ~SpoutReceiverUnit(); bool init(const char *channelName = ""); void release(); bool isInitialized() const; bool receive(); // will automatically allocate the texture need to replace with Unigine Texture bool selectSenderPanel(); const char * getChannelName() const; float getWidth() const; float getHeight() const; Spout spout; // create material library Materials *materials; ImagePtr SpoutImageCreate(); protected: const char * channelName; ImagePtr image; TexturePtr texture; MaterialPtr material; SpoutReceiver *spoutReceiver; int width; int height; const int defaultFormat; // = GL_RGBA. If you're using anything else then make sure to allocate your texture manually }; SpoutReceiverUnit::SpoutReceiverUnit() : defaultFormat(GL_RGBA) { this->spoutReceiver = nullptr; this->width = 0; this->height = 0; } //---------- SpoutReceiverUnit::~SpoutReceiverUnit() { this->release(); } //---------- bool SpoutReceiverUnit::init(const char* channelName) { this->release(); char * mutableName = const_cast<char *>(channelName); try { this->spoutReceiver = new SpoutReceiver(); unsigned int mutableWidth, mutableHeight; this->channelName = (mutableName); this->width = mutableWidth; this->height = mutableHeight; image = Image::create(); texture = Texture::create(); //this->image->create2D(width, height, defaultFormat); //unsigned char *d = image->getPixels2D(); //this->texture->create2D(width,height, defaultFormat); //this->texture->getImage(image); // create material library Materials *materials = Materials::get(); materials->create("spout_library"); materials->inheritMaterial("mesh_base","spout_library","spout_material"); this->material = materials->findMaterial("spout_material"); return true; } catch (const char * e) { Log::warning("Spout::Sender::init:%d Channel : %d", channelName,e ); //this needs to change and replace %d with string return false; } } void SpoutReceiverUnit::release() { if (this->isInitialized()) { this->spoutReceiver->ReleaseReceiver(); delete this->spoutReceiver; this->spoutReceiver = nullptr; this->width = 0; this->height = 0; } } //---------- bool SpoutReceiverUnit::isInitialized() const { if (this->spoutReceiver) { return true; } else { return false; } } //---------- bool SpoutReceiverUnit::receive() { char * mutableName = const_cast<char *>(channelName); int texture_id = this->texture->getGLTextureID(); int texture_format = this->texture->getFormat(); int texture_target = this->texture->getGLTarget(); try { //check if we're initialised if (!this->isInitialized()) { throw("Not initialized"); } //prepare the channel name, allow it to be changed if different channels are available unsigned int mutableWidth, mutableHeight; //check if the texture is allocated correctly, if not, allocate it if (this->texture->getWidth() != this->width || this->texture->getHeight() != this->height) { int format = this->texture->getFormat() ? texture->getFormat(): this->defaultFormat; this->texture = Texture::create(); //int num = material->findTexture("diffuse_0"); //if(num != -1) material->setImageTexture(num,texture); } //pull data into the texture (keep any existing fbo attachments) GLint drawFboId = 1; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFboId); if (!this->spoutReceiver->ReceiveTexture(mutableName, mutableWidth, mutableHeight,this->texture->getGLTextureID(), this->texture->getGLTarget())) { throw("Can't receive texture"); } //update our local settings incase anything changed this->channelName = mutableName; this->width = mutableWidth; this->height = mutableHeight; int num = material->findTexture("diffuse"); if(num != -1) material->setImageTexture(num,texture); return true; } catch (const char * e) { Log::warning("Spout::Receiver::receive->", e); return false; } } //---------- bool SpoutReceiverUnit::selectSenderPanel() { try { if (!this->isInitialized()) { throw("Not initialized"); } this->spoutReceiver->SelectSenderPanel(); return true; } catch (const char * e) { Log::warning("Spout::Receiver::selectSenderPanel", e); return false; } } //----------- const char * SpoutReceiverUnit::getChannelName() const { return this->channelName; } //---------- float SpoutReceiverUnit::getWidth() const { return this->width; } //---------- float SpoutReceiverUnit::getHeight() const { return this->height; } ImagePtr SpoutReceiverUnit::SpoutImageCreate() { return image; } /* */ /******************************************************************************\ * * SpoutPlugin * \******************************************************************************/ /* */ class SpoutPlugin : public Plugin { public: SpoutPlugin() { Log::warning("SpoutPlugin::SpoutPlugin(): called\n"); } virtual ~SpoutPlugin() { Log::warning("SpoutPlugin::~SpoutPlugin(): called\n"); } // plugin data virtual void *get_data() { return this; } // initialize plugin virtual int init(); // shutdown plugin virtual int shutdown(); // destroy plugin virtual void destroy(); // initialize world virtual int initWorld(); // shutdown world virtual int shutdownWorld(); }; /* */ int SpoutPlugin::init() { Log::warning("SpoutPlugin::init(): called\n"); // export extern class SpoutReceiver ExternClass<SpoutReceiverUnit> *spout_receiver = MakeExternClass<SpoutReceiverUnit>(); spout_receiver->addConstructor(); spout_receiver->addFunction("init",&SpoutReceiverUnit::init); spout_receiver->addFunction("release",&SpoutReceiverUnit::release); spout_receiver->addFunction("isInitialized",&SpoutReceiverUnit::isInitialized); spout_receiver->addFunction("receive",&SpoutReceiverUnit::receive); spout_receiver->addFunction("selectSenderPanel",&SpoutReceiverUnit::selectSenderPanel); spout_receiver->addFunction("getChannelName",&SpoutReceiverUnit::getChannelName); spout_receiver->addFunction("getWidth",&SpoutReceiverUnit::getWidth); spout_receiver->addFunction("getHeight",&SpoutReceiverUnit::getHeight); //spout_receiver->addFunction("spoutImageCreate",&SpoutReceiverUnit::SpoutImageCreate); Interpreter::addExternClass("SpoutReceiverUnit",spout_receiver); return 1; } int SpoutPlugin::shutdown() { Log::warning("SpoutPlugin::shutdown(): called\n"); // remove function // Interpreter::removeExternFunction("my_print"); // remove extern class Interpreter::removeExternClass("SpoutSenderUnit"); Interpreter::removeExternClass("SpoutReceiverUnit"); return 1; } /* */ void SpoutPlugin::destroy() { Log::warning("SpoutPlugin::destroy(): called\n"); } /* */ int SpoutPlugin::initWorld() { Log::error("\nSpoutPlugin::initWorld(): called\n\n"); return 1; } int SpoutPlugin::shutdownWorld() { Log::error("\nSpoutPlugin::shutdownWorld(): called\n\n"); return 1; } /******************************************************************************\ * * Plugin export * \******************************************************************************/ /* */ extern "C" UNIGINE_API void *CreatePlugin() { return new SpoutPlugin(); } extern "C" UNIGINE_API void ReleasePlugin(void *plugin) { delete static_cast<SpoutPlugin*>(plugin); } Edited September 19, 2017 by marinos.giannoukakis
silent Posted September 12, 2017 Posted September 12, 2017 Hi Marinos, If you will launch debug engine build with -video_debug 1 parameter - will it print some additional errors in console? You also can try to run in DX11 mode with video_debug 1 to see if there will be more versbose errors. If no, could you please send us minimal test scene for reproduction (including sender binary)? Thanks! How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN
marinos.giannoukakis Posted September 12, 2017 Author Posted September 12, 2017 I will send the scene straight away...
marinos.giannoukakis Posted September 12, 2017 Author Posted September 12, 2017 (edited) this is the test scene the Spout Sender app is inside Spout_Plugin_1 folder. Edited September 13, 2017 by marinos.giannoukakis
silent Posted September 13, 2017 Posted September 13, 2017 Hi Marinos, Are you still using Unigine 1? I'm afraid it's not really supported anymore, so right now we could not debug and test your plugin, sorry. We can continue to debugging if you will be able to port your project into 2.5. You also can try to debug it on your side to give us more information at which exact cases this error is happens. Sorry for the inconvenience caused. How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN
alexander Posted September 13, 2017 Posted September 13, 2017 Hi Marinos, I looked at your test scene. Unfortunately, I couldn't run it due to the missing "Unigine_x86.dll" file (and I couldn't determine version of the engine you are using).However, I opened the code. And I couldn't find the line "Spout DX11 CPU Sender" (or something similar). I could not find Log::message(), which use it. I don't understand on which line the "OpenGL error: invalid enum" error is caused, because when I'm run an empty project with "load the material on an object (I am inheriting from mesh_base)" i don't see such error (Unigine 2.5). Best regards, Alexander
marinos.giannoukakis Posted September 13, 2017 Author Posted September 13, 2017 sorry I thought I needed to say that I am doing all my development in an older machine that has Unigine 1 installed... sorry for that is more convenient for me .... I ll either try to port it or debug it myself... please hold on a bit more, I ll get back to you the next few days....
marinos.giannoukakis Posted September 14, 2017 Author Posted September 14, 2017 By the way Alexander the error comes up when you actually load the material. It does not occur when the material is NOT loaded.... I am guessing the enum error has to do with the texture type... Spout uses GL_RGBA as default, and Unigine possibly does not understand it?? I don t know I am guessing here.... Concerning the receiving name is here: bool SpoutReceiverUnit::receive() { char * mutableName = const_cast<char *>(channelName); and the channelName is an empty const char, initialized here, init(const char *channelName = ""); in the UnigineScript there is an exported from the plugin getChannelName function... the empty strings means that it will get the first active sender spotted.....
marinos.giannoukakis Posted September 14, 2017 Author Posted September 14, 2017 gonna port to 2.5 the next few days... hopefully not much will change...
marinos.giannoukakis Posted September 16, 2017 Author Posted September 16, 2017 I tried to port but this is not a small task... I literally have to rewrite everything (which is why some stuff like that I still work on Unigine 1). Is there a way I could send you the whole Unigine folder and give it a try with that....? I think that I am gonna run in the same issue in Unigine 2.5 and I want to deal with it before I spend another significant amount of time for rewriting....
marinos.giannoukakis Posted September 19, 2017 Author Posted September 19, 2017 (edited) I ported to Unigine 2.5, now a Unigine fatal error appears related to Unigine::Texture:getTextureID. I feel this is a total different issue from the one in Unigine1. In any case here are the 'ported' files. They compile, but Unigine won't start.... Spout_Plugin.zip Edited September 19, 2017 by marinos.giannoukakis
marinos.giannoukakis Posted September 19, 2017 Author Posted September 19, 2017 I forgot to include the SpoutSender.exe here it is in case you need to test SpoutSender.zip
marinos.giannoukakis Posted September 21, 2017 Author Posted September 21, 2017 Hi guys, any updates on this......???
binstream Posted September 21, 2017 Posted September 21, 2017 Marinos, at the moment the team is focused on 2.6 release, so there will be slower responses.
Recommended Posts