diff --git a/examples/SpoutDataReceiver/SpoutDataReceiver.pde b/examples/SpoutDataReceiver/SpoutDataReceiver.pde new file mode 100644 index 0000000..eb80b3b --- /dev/null +++ b/examples/SpoutDataReceiver/SpoutDataReceiver.pde @@ -0,0 +1,229 @@ +// +// SpoutDataReceiver +// +// Receive texture and data from a Spout sender +// +// Spout 2.007 +// https://spout.zeal.co +// + +// IMPORT THE SPOUT LIBRARY +import spout.*; + +PGraphics pgr; // Canvas to receive a texture +PImage img; // Image to receive a texture + +// VARIABLES FOR DATA EXCHANGE +// (mouse coordinates and button status in this example) +int[] mousedata; +XML xml, mx, my, butn, press, drag; +// For line draw +ArrayList senderpoints; +int sendermousex = 0; +int sendermousey = 0; +int senderbutton = 0; +int senderpressed = 0; +int senderdragged = 0; +// String received +String senderdata = ""; + +// DECLARE A SPOUT OBJECT +Spout spout; + +void setup() { + + // Initial window size + size(640, 360, P3D); + + // Screen text size + textSize(16); + + // Needed for resizing the window to the sender size + // Processing 3+ only + surface.setResizable(true); + + // Create a canvas or an image to receive the data. + // Objects can be created at any size. + // Their dimensions are changed to match the sender + // that the receiver connects to. + pgr = createGraphics(width, height, PConstants.P2D); + img = createImage(width, height, ARGB); + + // A 5 integer array for received data + mousedata = new int[5]; + + // Sender points to draw + senderpoints = new ArrayList(); + + // CREATE A NEW SPOUT OBJECT + spout = new Spout(this); + + // Set the frame rate lower that the SpoutDataSender sketch + // to demonstrate frame sync functions. + frameRate(30.0); + +} + + +void draw() { + + background(0); + + // RECEIVE FROM A SENDER + + // Receive and draw the shared texture + if(spout.receiveTexture()) { + + spout.drawTexture(); + + // + // RECEIVE DATA + // + + // + // Method 1 (string) + // + // The content is expected (Refer to the SpoutDataSender example). + // + senderdata = spout.getSenderData(); + + // In this example, the received string contains + // mouse coordinates and button status. + if(senderdata.length() > 0) { + + println(senderdata); + // Convert the string to integers + mousedata = int(split(senderdata, ' ')); + // And the integer array to variables for legibility + if(mousedata.length >= 5) { + sendermousex = mousedata[0]; + sendermousey = mousedata[1]; + senderbutton = mousedata[2]; + senderpressed = mousedata[3]; + senderdragged = mousedata[4]; + } + } // end string method + + /* + // + // Method 1 (xml) + // + // The received string is in XML format. + // + // In this example we will receive : + // + // 000 + // 000 + // + // 00 + // 0 + // + // + String senderdata = spout.getSenderData(); + + if(senderdata.length() > 0) { + // Parse the mouse coords and button status + xml = parseXML(senderdata); + mx = xml.getChild("mousex"); + my = xml.getChild("mousey"); + butn = xml.getChild("button"); + press = xml.getChild("pressed"); + drag = xml.getChild("dragged"); + + sendermousex = mx.getIntContent(0); + sendermousey = my.getIntContent(0); + senderbutton = butn.getIntContent(0); + senderpressed = press.getIntContent(0); + senderdragged = drag.getIntContent(0); + + } // End xml method + */ + + // + // Method 3 - depends on what the sender produced. + // + + + } // endif received texture + + // Draw a circle at the sender mouse position. + // Click and drag on the sender sketch window to draw a line. + if(spout.isConnected() && senderdata.length() > 0) { + + // Accumulate a line if the sender mouse is dragged + if (senderdragged == 1) + senderpoints.add(new PVector(sendermousex, sendermousey)); + + // Draw accumulated points in yellow + if(senderpoints.size() > 1) { + noFill(); + strokeWeight(2); + stroke(255, 255, 0); + beginShape(); + for (PVector p : senderpoints) + curveVertex(p.x, p.y); + endShape(); + } + + // Clear points on sender RH button click + if (senderbutton == RIGHT && senderpoints.size() > 0) { + for (int i = senderpoints.size() - 1; i >= 0; i--) + senderpoints.remove(i); + } + + // Draw a ball at the sender mouse position + noStroke(); // no outline + if(senderpressed == 1 && senderbutton == LEFT) + fill(255, 255, 0); // yellow if the sender mouse is pressed + else + fill(255, 0, 0); // default red + circle(sendermousex, sendermousey, 24); + + } + + // Display sender info + showInfo(); + + // OPTION + // To avoid missing frames, send a ready signal for the sender + // to wait on. Sender framerate will synchronise with the receiver. + // (Refer to the SpoutDataSender example). + spout.setFrameSync(spout.getSenderName()); + +} + +void showInfo() { + + fill(255); + + if(spout.isReceiverConnected()) { + // Report sender fps and frame number if the option is activated + // Applications < Spout 2.007 will have no frame information + if(spout.getSenderFrame() > 0) { + text("Receiving from : " + spout.getSenderName() + " (" + + spout.getSenderWidth() + "x" + + spout.getSenderHeight() + ") - fps " + + spout.getSenderFps() + " : frame " + + spout.getSenderFrame(), 15, 30); + } + else { + text("Receiving from : " + spout.getSenderName() + " (" + + spout.getSenderWidth() + "x" + + spout.getSenderHeight() + ")", 15, 30); + } + } + else { + text("No sender", 30, 30); + } +} + +// RH click to select a sender +void mousePressed() { + // SELECT A SPOUT SENDER + if (mouseButton == RIGHT) { + // Bring up a dialog to select a sender. + // Spout installation required + spout.selectSender(); + } +} + diff --git a/examples/SpoutDataSender/SpoutDataSender.pde b/examples/SpoutDataSender/SpoutDataSender.pde new file mode 100644 index 0000000..2eb6866 --- /dev/null +++ b/examples/SpoutDataSender/SpoutDataSender.pde @@ -0,0 +1,258 @@ +// +// Spout Data Sender +// +// Send data together with a texture to a Spout receiver +// +// Spout 2.007 +// https://spout.zeal.co +// +// Texture Cube by Dave Bollinger +// http://processing.org/examples/texturecube.html +// + +// IMPORT THE SPOUT LIBRARY +import spout.*; + +PImage img; // image to use for the rotating cube +PGraphics pgr; // Graphics for demo + +// DECLARE A SPOUT OBJECT +Spout spout; + +// VARIABLES FOR DATA EXCHANGE +int pressed = 0; +int dragged = 0; +XML xml, mx, my, butn, press, drag; + + +void setup() { + + // Initial window size + size(640, 360, P3D); + textureMode(NORMAL); + + // Screen text size + textSize(16); + + // Create a graphics object + pgr = createGraphics(1280, 720, P3D); + + // Load an image + img = loadImage("SpoutLogoMarble3.bmp"); + + // CREATE A NEW SPOUT OBJECT + spout = new Spout(this); + + // CREATE XML FOR THIS EXAMPLE + xml = new XML("mouse"); + mx = xml.addChild("mousex"); + my = xml.addChild("mousey"); + butn = xml.addChild("button"); + press = xml.addChild("pressed"); + drag = xml.addChild("dragged"); + + // GIVE THE SENDER A NAME + // A sender can be given any name. + // Otherwise the sketch folder name is used + // the first time "sendTexture" is called. + spout.setSenderName("Spout Data Sender"); + + // CREATE SHARED MEMORY FOR DATA EXCHANGE + // A sender name must be established first. + // + // The memory is created large enough to contain at least the maximum + // number of bytes required. + // + // For example, the xml method shown below requires between 110 and 115 + // bytes, so the memory should be created at least 115 bytes in size. + // + // If the sending data size is not precisely known, the shared memory can be + // created larger. For example, a 256 byte buffer is plenty for this example. + // + spout.createSenderBuffer(256); + + // OPTION - set the sketch frame rate. + // In this example, the sender waits for a ready signal from + // the receiver and will synchronise with receiver framerate + // (Refer to the SpoutDataReceiver example) + // frameRate(60); + +} + +void draw() { + + background(0, 90, 100); + noStroke(); + + // + // OPTION - frame synchronisation + // + // To avoid the receiver from missing frames, the sender can wait + // until the receiver signals that it is ready to read more data. + // Use a timeout greater than the expected delay. + // + // Sync is necessary if the sending and receiving applications require + // frame accuracy and missed frames are not acceptable. + // + // The sender will then run at the same framerate as the receiver. + // For example, if connected to the data receiver example, this will + // be 30fps instead of the 60fps established in Setup(). + // + // Sync is not required for this simple example but is included to + // demonstrate the functions (Refer to the SpoutDataReceiver example). + // + spout.waitFrameSync(spout.getSenderName(), 67); + + // Draw the rotating cube + pushMatrix(); + translate(width/2.0, height/2.0, -100); + rotateX(frameCount/60.0); + rotateY(frameCount/60.0); + scale(110); + TexturedCube(img); + popMatrix(); + + // Send the texture of the drawing sufrface + spout.sendTexture(); + + // + // SEND DATA + // Often known as "per-frame metadata". + // + // In this example, send mouse coordinates and button status. + // The receiver should expect the same data format. + // (Refer to the SpoutDataReceiver example). + + // + // Method 1 (string) + // + + // Here the coordinates are converted to a String. + String senderdata = + str(mouseX) + " " + + str(mouseY) + " " + + str(mouseButton) + " " + + str(pressed) + " " + + str(dragged); + + // Write the string to shared memory. + // The receiver can then split the string and convert back to integers. + // (Refer to the SpoutDataReceiver example) + spout.setSenderData(senderdata); + + // end string method + + /* + // + // Method 2 - XML + // XML might be appropriate for some applications. + // + // In this example we create : + // + // + // 000 + // 000 + // + // 0 + // 0 + // + // + + // Set the mouse data to xml + mx.setContent(str(mouseX)); + my.setContent(str(mouseY)); + butn.setContent(str(mouseButton)); + press.setContent(str(pressed)); + drag.setContent(str(dragged)); + + // Save the xml data as a string + String senderdata = xml.toString(); + + // Write the string data to shared memory. + // The receiver can parse the xml data, expecting the format sent. + spout.setSenderData(senderdata); + + // end xml method + */ + + // + // These are just examples. There are sure to be other applications. + // + + // Display info + text("Sending as : " + + spout.getSenderName() + " (" + + spout.getSenderWidth() + "x" + + spout.getSenderHeight() + ") - fps : " + + spout.getSenderFps() + " : frame " + + spout.getSenderFrame(), 15, 30); + +} + +void TexturedCube(PImage tex) { + + beginShape(QUADS); + texture(tex); + + // +Z "front" face + vertex(-1, -1, 1, 0, 0); + vertex( 1, -1, 1, 1, 0); + vertex( 1, 1, 1, 1, 1); + vertex(-1, 1, 1, 0, 1); + + // -Z "back" face + vertex( 1, -1, -1, 0, 0); + vertex(-1, -1, -1, 1, 0); + vertex(-1, 1, -1, 1, 1); + vertex( 1, 1, -1, 0, 1); + + // +Y "bottom" face + vertex(-1, 1, 1, 0, 0); + vertex( 1, 1, 1, 1, 0); + vertex( 1, 1, -1, 1, 1); + vertex(-1, 1, -1, 0, 1); + + // -Y "top" face + vertex(-1, -1, -1, 0, 0); + vertex( 1, -1, -1, 1, 0); + vertex( 1, -1, 1, 1, 1); + vertex(-1, -1, 1, 0, 1); + + // +X "right" face + vertex( 1, -1, 1, 0, 0); + vertex( 1, -1, -1, 1, 0); + vertex( 1, 1, -1, 1, 1); + vertex( 1, 1, 1, 0, 1); + + // -X "left" face + vertex(-1, -1, -1, 0, 0); + vertex(-1, -1, 1, 1, 0); + vertex(-1, 1, 1, 1, 1); + vertex(-1, 1, -1, 0, 1); + + endShape(); +} + +void mousePressed() +{ + pressed = 1; + dragged = 0; +} + +void mouseReleased() +{ + pressed = 0; + dragged = 0; +} + +void mouseMoved() +{ + pressed = 0; + dragged = 0; +} + +void mouseDragged() +{ + pressed = 1; + dragged = 1; +} diff --git a/examples/SpoutDataSender/SpoutDataSenderString_working.bak b/examples/SpoutDataSender/SpoutDataSenderString_working.bak new file mode 100644 index 0000000..ad87fe5 --- /dev/null +++ b/examples/SpoutDataSender/SpoutDataSenderString_working.bak @@ -0,0 +1,260 @@ +// +// Spout Data Sender +// +// Send data together with a texture to a Spout receiver +// +// Spout 2.007 +// https://spout.zeal.co +// +// Texture Cube by Dave Bollinger +// http://processing.org/examples/texturecube.html +// + +// IMPORT THE SPOUT LIBRARY +import spout.*; + +PImage img; // image to use for the rotating cube +PGraphics pgr; // Graphics for demo + +// DECLARE A SPOUT OBJECT +Spout spout; + +// Variables for data exchange +int pressed = 0; +int dragged = 0; +XML xml; +XML mx, my, butn, press, drag; + +void setup() { + + // Initial window size + size(640, 360, P3D); + textureMode(NORMAL); + + // Screen text size + textSize(16); + + // Create a graphics object + pgr = createGraphics(1280, 720, P3D); + + // Load an image + img = loadImage("SpoutLogoMarble3.bmp"); + + // CREATE A NEW SPOUT OBJECT + spout = new Spout(this); + + // Create the format for the XML example + xml = new XML("mouse"); + mx = xml.addChild("mousex"); + my = xml.addChild("mousey"); + butn = xml.addChild("button"); + press = xml.addChild("pressed"); + drag = xml.addChild("dragged"); + + // GIVE THE SENDER A NAME + // A sender can be given any name. + // Otherwise the sketch folder name is used + // the first time "sendTexture" is called. + spout.setSenderName("Spout Data Sender"); + + // Option - set the sketch frame rate. + // In this example, the sender waits for a ready signal from + // the receiver and will synchronise with receiver framerate + // (Refer to the SpoutDataReceiver example) + frameRate(60); + +} + +void draw() { + + background(0, 90, 100); + noStroke(); + + // + // OPTION + // + // To avoid the receiver missing frames, the sender can wait + // until the receiver is ready to receive more data. + // If connected to the SpoutDataReceiver example, the sender will + // will run at the same framerate (30fps) instead of 60 fps. + // Use a timeout greater than the expected delay. + // + // This is only necessary if the applications require frame accuracy. + // It is not needed here but is included for demonstration. + // (Refer to the SpoutDataReceiver example). + // + spout.waitFrameSync(spout.getSenderName(), 67); + + // Draw the rotating cube + pushMatrix(); + translate(width/2.0, height/2.0, -100); + rotateX(frameCount/60.0); + rotateY(frameCount/60.0); + scale(110); + TexturedCube(img); + popMatrix(); + + // Send the texture of the drawing sufrface + spout.sendTexture(); + + // + // Send a data buffer + // + + // The string to send contains byte data, often known as per-frame metadata. + // This example sends mouse coordinates and pressed status to the receiver. + // (Refer to the SpoutDataReceiver example). + + // + // Method 1 (string) + // The receiver can split the string and convert to integers + // (Refer to the SpoutDataReceiver example) + // + // Convert the coordinates to a string (between 9 - 15 bytes). + String senderdata = + str(mouseX) + " " + // 2-4 bytes + str(mouseY) + " " + // 2-4 + str(mouseButton) + " " + // 2-3 + str(pressed) + " " + // 2 + str(dragged) + " "; // 2 + + // Now write the string to shared memory + spout.setSenderData(senderdata); + + /* + // + // The size of the shared memory is fixed and established + // on the first call to writeMemoryBuffer. + // + // However, in this example, the string length can vary. + // The shared memory buffer must be created in advance so that + // it can contain at least the maximum string length (15). + // + + // if(spout.getMemoryBufferSize(spout.getSenderName()) == 0) + if(spout.getMemoryBufferSize() == 0) + spout.createMemoryBuffer(spout.getSenderName(), 15); + + // Now write the string to shared memory + spout.writeMemoryBuffer(spout.getSenderName(), senderdata, senderdata.length()); + */ + + + /* + // + // Method 2 - XML + // XML might be appropriate for more flexibility. + // The receiver can parse the data. + // + // In this example we will end up with : + // + // + // 000 + // 000 + // + // 00 + // 0 + // + // + + // Set the mouse data to xml + mx.setContent(str(mouseX)); + my.setContent(str(mouseY)); + butn.setContent(str(mouseButton)); + press.setContent(str(pressed)); + drag.setContent(str(dragged)); + + // Save the xml data as a string (109 - 114 bytes) + String senderdata = xml.toString(); + + // Again, the string size will change and the fixed size + // shared memory buffer must be created in advance. + if(spout.getMemoryBufferSize(spout.getSenderName()) == 0) + spout.createMemoryBuffer(spout.getSenderName(), 114); + + // Write the string data to shared memory.. + // The receiver can parse the xml data, expecting the format sent. + spout.writeMemoryBuffer(spout.getSenderName(), senderdata, senderdata.length()); + + // The receiver can parse the data + // XML recxml = parseXML(senderdata); + // println(senderdata.length()); + */ + + // Display info + text("Sending as : " + + spout.getSenderName() + " (" + + spout.getSenderWidth() + "x" + + spout.getSenderHeight() + ") - fps : " + + spout.getSenderFps() + " : frame " + + spout.getSenderFrame(), 15, 30); + +} + +void TexturedCube(PImage tex) { + + beginShape(QUADS); + texture(tex); + + // +Z "front" face + vertex(-1, -1, 1, 0, 0); + vertex( 1, -1, 1, 1, 0); + vertex( 1, 1, 1, 1, 1); + vertex(-1, 1, 1, 0, 1); + + // -Z "back" face + vertex( 1, -1, -1, 0, 0); + vertex(-1, -1, -1, 1, 0); + vertex(-1, 1, -1, 1, 1); + vertex( 1, 1, -1, 0, 1); + + // +Y "bottom" face + vertex(-1, 1, 1, 0, 0); + vertex( 1, 1, 1, 1, 0); + vertex( 1, 1, -1, 1, 1); + vertex(-1, 1, -1, 0, 1); + + // -Y "top" face + vertex(-1, -1, -1, 0, 0); + vertex( 1, -1, -1, 1, 0); + vertex( 1, -1, 1, 1, 1); + vertex(-1, -1, 1, 0, 1); + + // +X "right" face + vertex( 1, -1, 1, 0, 0); + vertex( 1, -1, -1, 1, 0); + vertex( 1, 1, -1, 1, 1); + vertex( 1, 1, 1, 0, 1); + + // -X "left" face + vertex(-1, -1, -1, 0, 0); + vertex(-1, -1, 1, 1, 0); + vertex(-1, 1, 1, 1, 1); + vertex(-1, 1, -1, 0, 1); + + endShape(); +} + +void mousePressed() +{ + pressed = 1; + dragged = 0; +} + +void mouseReleased() +{ + pressed = 0; + dragged = 0; +} + +void mouseMoved() +{ + pressed = 0; + dragged = 0; +} + +void mouseDragged() +{ + pressed = 1; + dragged = 1; +} diff --git a/examples/SpoutDataSender/SpoutDataSender_not-working.bak b/examples/SpoutDataSender/SpoutDataSender_not-working.bak new file mode 100644 index 0000000..1c04432 --- /dev/null +++ b/examples/SpoutDataSender/SpoutDataSender_not-working.bak @@ -0,0 +1,189 @@ +// +// Spout Data Sender +// +// Send texture and data to a Spout receiver +// +// Spout 2.007 +// https://spout.zeal.co +// +// Texture Cube by Dave Bollinger +// http://processing.org/examples/texturecube.html +// + +// IMPORT THE SPOUT LIBRARY +import spout.*; + +PImage img; // image to use for the rotating cube +PGraphics pgr; // Graphics for demo + +// DECLARE A SPOUT OBJECT +Spout spout; + +int pressed = 0; +int dragged = 0; + +void setup() { + + // Initial window size + size(640, 360, P3D); + textureMode(NORMAL); + + // Screen text size + textSize(16); + + // Create a graphics object + pgr = createGraphics(1280, 720, P3D); + + // Load an image + img = loadImage("SpoutLogoMarble3.bmp"); + + // CREATE A NEW SPOUT OBJECT + spout = new Spout(this); + + // GIVE THE SENDER A NAME + // A sender can be given any name. + // Otherwise the sketch folder name is used + // the first time "sendTexture" is called. + spout.setSenderName("Spout Data Sender"); + + // Option - set the sketch frame rate. + // In this example, the sender waits for a ready signal from + // the receiver and will synchronise with receiver framerate + // (Refer to the SpoutDataReceiver example) + frameRate(60); + +} + +void draw() { + + background(0, 90, 100); + noStroke(); + + // + // OPTION + // + // To avoid the receiver missing frames, the sender can wait + // until the receiver is ready to receive more data. + // If connected to the SpoutDataReceiver example, the sender will + // will run at the same framerate (30fps) instead of 60 fps. + // Use a timeout greater than the expected delay. + // + // This is only necessary if the applications require frame accuracy. + // It is not needed here but is included for demonstration. + // (Refer to the SpoutDataReceiver example). + // + spout.waitFrameSync(spout.getSenderName(), 67); + + // Draw the rotating cube + pushMatrix(); + translate(width/2.0, height/2.0, -100); + rotateX(frameCount/60.0); + rotateY(frameCount/60.0); + scale(110); + TexturedCube(img); + popMatrix(); + + // Send the texture of the drawing sufrface + spout.sendTexture(); + + // + // Send a data buffer + // + // The string contains byte data, often known as per-frame metadata, + // which might be used for various purposes. + // + // This example sends mouse coordinates and pressed status to the receiver. + // (Refer to the SpoutDataReceiver example). + // + // int pressed = mousePressed?1:0; // convert boolean to int + + // Convert the coordinates to a string. + String senderdata = str(mouseX) + " " + str(mouseY) + " " + str(pressed); + + // + // The size of the memory buffer is established on the first call + // to writeMemoryBuffer. In this example, we need at least 10 characters + // for two mouse coordinates and pressed status. + // Three characters each for the coordinates and one for status. + // separated by a space and terminated with a null. + // (3+1+3+1+1+1 = 10 bytes). + // + spout.writeMemoryBuffer(spout.getSenderName(), senderdata, 10); + + // Display info + text("Sending as : " + + spout.getSenderName() + " (" + + spout.getSenderWidth() + "x" + + spout.getSenderHeight() + ") - fps : " + + spout.getSenderFps() + " : frame " + + spout.getSenderFrame(), 15, 30); + +} + +void TexturedCube(PImage tex) { + + beginShape(QUADS); + texture(tex); + + // +Z "front" face + vertex(-1, -1, 1, 0, 0); + vertex( 1, -1, 1, 1, 0); + vertex( 1, 1, 1, 1, 1); + vertex(-1, 1, 1, 0, 1); + + // -Z "back" face + vertex( 1, -1, -1, 0, 0); + vertex(-1, -1, -1, 1, 0); + vertex(-1, 1, -1, 1, 1); + vertex( 1, 1, -1, 0, 1); + + // +Y "bottom" face + vertex(-1, 1, 1, 0, 0); + vertex( 1, 1, 1, 1, 0); + vertex( 1, 1, -1, 1, 1); + vertex(-1, 1, -1, 0, 1); + + // -Y "top" face + vertex(-1, -1, -1, 0, 0); + vertex( 1, -1, -1, 1, 0); + vertex( 1, -1, 1, 1, 1); + vertex(-1, -1, 1, 0, 1); + + // +X "right" face + vertex( 1, -1, 1, 0, 0); + vertex( 1, -1, -1, 1, 0); + vertex( 1, 1, -1, 1, 1); + vertex( 1, 1, 1, 0, 1); + + // -X "left" face + vertex(-1, -1, -1, 0, 0); + vertex(-1, -1, 1, 1, 0); + vertex(-1, 1, 1, 1, 1); + vertex(-1, 1, -1, 0, 1); + + endShape(); +} + +void mousePressed() +{ + pressed = 1; + dragged = 0; +} + +void mouseReleased() +{ + pressed = 0; + dragged = 0; +} + +void mouseMoved() +{ + pressed = 0; + dragged = 0; +} + +void mouseDragged() +{ + pressed = 1; + dragged = 1; +} diff --git a/examples/SpoutDataSender/data/SpoutLogoMarble3.bmp b/examples/SpoutDataSender/data/SpoutLogoMarble3.bmp new file mode 100644 index 0000000..a1b7423 Binary files /dev/null and b/examples/SpoutDataSender/data/SpoutLogoMarble3.bmp differ diff --git a/examples/SpoutReceiver/SpoutReceiver.pde b/examples/SpoutReceiver/SpoutReceiver.pde index f4c3847..b4aa01b 100644 --- a/examples/SpoutReceiver/SpoutReceiver.pde +++ b/examples/SpoutReceiver/SpoutReceiver.pde @@ -55,7 +55,7 @@ void draw() { // OPTION 1: Receive and draw the shared texture if(spout.receiveTexture()) spout.drawTexture(); - + // OPTION 2: Receive into PGraphics // pgr = spout.receiveTexture(pgr); // if(pgr.loaded) @@ -67,15 +67,17 @@ void draw() { // if(img.loaded) // image(img, 0, 0, width, height); - // Optionally resize the window to match the sender + // Option: resize the window to match the sender // spout.resizeFrame(); - + // Display sender info showInfo(); } void showInfo() { + + fill(255); if(spout.isReceiverConnected()) { // Report sender fps and frame number if the option is activated diff --git a/examples/SpoutSender/SpoutSender.pde b/examples/SpoutSender/SpoutSender.pde index 2a9f5bb..69092a0 100644 --- a/examples/SpoutSender/SpoutSender.pde +++ b/examples/SpoutSender/SpoutSender.pde @@ -96,7 +96,7 @@ void draw() { background(0, 90, 100); noStroke(); - + // OPTION 1: SEND THE TEXTURE OF THE DRAWING SURFACE // Draw the rotating cube pushMatrix(); @@ -106,6 +106,7 @@ void draw() { scale(110); TexturedCube(img); popMatrix(); + // Send at the size of the window spout.sendTexture(); @@ -134,29 +135,17 @@ void draw() { // Send at the size of the image spout.sendTexture(img); */ - + // Display info text("Sending as : " + spout.getSenderName() + " (" + spout.getSenderWidth() + "x" + spout.getSenderHeight() + ") - fps : " - + (int)(round(frameRate+0.5)), 35, 30); - + + spout.getSenderFps() + " : frame " + + spout.getSenderFrame(), 15, 30); + } -// LJ DEBUG -void exit() { - println("exiting"); - super.exit(); -} - -// LJ DEBUG -void stop() { - println("stopping"); - super.stop(); -} - - void TexturedCube(PImage tex) { beginShape(QUADS); diff --git a/lib/JNISpout_32.dll b/lib/JNISpout_32.dll index 877582a..c6519a4 100644 Binary files a/lib/JNISpout_32.dll and b/lib/JNISpout_32.dll differ diff --git a/lib/JNISpout_64.dll b/lib/JNISpout_64.dll index 5fc1a7c..99d8fad 100644 Binary files a/lib/JNISpout_64.dll and b/lib/JNISpout_64.dll differ diff --git a/resources/build.properties b/resources/build.properties index 311f58b..1a476f4 100644 --- a/resources/build.properties +++ b/resources/build.properties @@ -148,7 +148,7 @@ library.version = 7 # The version as the user will see it. -library.prettyVersion = 2.0.7.0 +library.prettyVersion = 2.0.7.2 # The min and max revision of Processing compatible with your Library. diff --git a/resources/library.properties b/resources/library.properties index d2e4d15..9d85097 100644 --- a/resources/library.properties +++ b/resources/library.properties @@ -45,7 +45,7 @@ version = 7 # The version as the user will see it. If blank, the version attribute will be # used here. This should be a single word, with no spaces. -prettyVersion = 2.0.7.0 +prettyVersion = 2.0.7.2 # The min and max revision of Processing compatible with your Library. # Note that these fields use the revision and not the version of Processing, diff --git a/src/spout/JNISpout.java b/src/spout/JNISpout.java index bbb7d33..7a91b9f 100644 --- a/src/spout/JNISpout.java +++ b/src/spout/JNISpout.java @@ -76,6 +76,16 @@ else if(sunDataModel.equals("64")) protected static native void closeSenderMemory(long ptr); protected static native long lockSenderMemory(long ptr); protected static native void unlockSenderMemory(long ptr); - + + // Sync event signals + protected static native void setFrameSync(String SenderName, long ptr); + protected static native boolean waitFrameSync(String SenderName, int dwTimeout, long ptr); + + // Per-frame metadata + protected static native boolean writeMemoryBuffer(String name, String data, int length, long ptr); + protected static native String readMemoryBuffer(String name, int maxlength, long ptr); + protected static native boolean createMemoryBuffer(String name, int length, long ptr); + protected static native boolean deleteMemoryBuffer(long ptr); + protected static native int getMemoryBufferSize(String name, long ptr); } diff --git a/src/spout/Spout.java b/src/spout/Spout.java index 317e21a..c4cc20c 100644 --- a/src/spout/Spout.java +++ b/src/spout/Spout.java @@ -86,6 +86,12 @@ // TODO : sender graphics resize // Rebuild for revised 2.007 SpoutGL and updated JNISpout library (Processing 3.5.4) // 24.01.21 Rebuild for 2.007 release Version 2.0.7.1 +// 13.04.21 Add setFrameSync, waitFrameSync, writeMemoryBuffer, readMemoryBuffer +// 21.05.21 Rebuild JNI/Processing libraries +// 22.05.21 Add data sender/receiver examples +// 27.05.21 Add createMemoryBuffer +// 14.06.21 Rebuild for 2.007e release Version 2.0.7.2 +// // // ======================================================================================================== @@ -120,6 +126,7 @@ public class Spout { boolean bPixelsLoaded; int receiverType; // 0 - parent, 1 - graphics, 2 - image int invertMode; // User setting for texture invert + int bufferSize; // shared memory buffer size /** * Create a Spout Object. @@ -1003,7 +1010,171 @@ public void unlockSenderMemory() { JNISpout.unlockSenderMemory(spoutPtr); } + + // =========================================== // + // Sync event signals + // =========================================== // + + /** + * Signal sync event. + * Create a named sync event and set for test + * + */ + public void setFrameSync(String sendername) + { + JNISpout.setFrameSync(sendername, spoutPtr); + } + + /** + * Wait or test for named sync event. + * Wait until the sync event is signalled or the timeout elapses. + * Events are typically created based on the sender name and are + * effective between a single sender/receiver pair. + * - For testing for a signal, use a wait timeout of zero. + * - For synchronization, use a timeout greater than the expected delay + * + * @return success of wait + */ + public boolean waitFrameSync(String sendername, int timeout) + { + return JNISpout.waitFrameSync(sendername, timeout, spoutPtr); + } + + // =========================================== // + // Per frame metadata + // =========================================== // + + /** + * Write a string to a sender shared memory buffer. + * Create a shared memory map of the required size if it does not exist. + * Subsequently the map size is fixed. To allow for varying string length + * create shared memory of sufficient size in advance. + * The map is closed when the sender is released. + * + * @return success of write + */ + public boolean setSenderData(String data) + { + // A sender name is required + if(!bSenderInitialized) + return false; + + // writeMemoryBuffer creates a map if not already + return JNISpout.writeMemoryBuffer(senderName, data, data.length(), spoutPtr); + + } + + /** + * Read sender shared memory buffer to a string. + * + * @return the string read + */ + public String getSenderData() + { + // A connected sender name is required + if(!bReceiverConnected) + return ""; + + // The memory map is created by the sender + if(bufferSize == 0) + bufferSize = JNISpout.getMemoryBufferSize(senderName, spoutPtr); + + return JNISpout.readMemoryBuffer(senderName, bufferSize, spoutPtr); + + } + + /** + * Create sender shared memory buffer. + * Create a shared memory map of the required size. + * The map is closed when the sender is released. + * + * @return success of create + */ + public boolean createSenderBuffer(int length) + { + // A sender name is required + // but sender initialization is not + if(senderName == "") + return false; + + if(JNISpout.createMemoryBuffer(senderName, length, spoutPtr)) { + bufferSize = length; + return true; + } + return false; + } + + + /** + * Write buffer to sender shared memory. + * Create a shared memory map of the required size if it does not exist. + * The map is closed when the sender is released. + * + * @return success of write + */ + public boolean writeMemoryBuffer(String sendername, String data, int length) + { + if(JNISpout.writeMemoryBuffer(sendername, data, length, spoutPtr)) { + if(bufferSize == 0) + bufferSize = JNISpout.getMemoryBufferSize(sendername, spoutPtr); + return true; + } + return false; + } + + /** + * Read sender shared memory to buffer. + * Open a sender memory map and retain the handle. + * The map is closed when the receiver is released. + * + * @return number of bytes read + */ + public String readMemoryBuffer(String sendername, int maxlength) + { + return JNISpout.readMemoryBuffer(sendername, maxlength, spoutPtr); + } + + /** + * Create sender shared memory buffer. + * Create a shared memory map of the required size. + * The map is closed when the sender is released. + * + * @return success of create + */ + public boolean createMemoryBuffer(String sendername, int length) + { + if(JNISpout.createMemoryBuffer(sendername, length, spoutPtr)) { + bufferSize = length; + return true; + } + return false; + } + + /** + * Delete sender shared memory buffer. + * + * @return success of delete + */ + public boolean deleteMemoryBuffer() + { + if(JNISpout.deleteMemoryBuffer(spoutPtr)) { + bufferSize = 0; + return true; + } + return false; + } + + /** + * Get sender shared memory buffer size. + * + * @return size of memory map + */ + public int getMemoryBufferSize() + { + return bufferSize; // JNISpout.getMemoryBufferSize(spoutPtr); + } + // =========================================== // // UTILITY // // =========================================== //