Jump to content

spout with Unigine


photo

Recommended Posts

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 by marinos.giannoukakis
Link to comment

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

Link to comment

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.... 

Link to comment

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.

Link to comment

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 by marinos.giannoukakis
Link to comment

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

Link to comment

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);

}

 

 

spout_plugin_Receive.png

spout_plugin_Receive_error.png

Edited by marinos.giannoukakis
Link to comment

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:

Link to comment

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:

Link to comment

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

Link to comment

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....

Link to comment

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.....

 

Link to comment

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....

Link to comment

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 by marinos.giannoukakis
Link to comment
×
×
  • Create New...