Create more than one window of a single sketch in Processing - image

How to create more than one window of a single sketch in Processing?
Actually I want to detect and track a particular color (through webcam) in one window and display the detected co-ordinates as a point in another window.Till now I'm able to display the points in the same window where detecting it.But I want to split it into two different windows.

You need to create a new frame and a new PApplet... here's a sample sketch:
import javax.swing.*;
SecondApplet s;
void setup() {
size(640, 480);
PFrame f = new PFrame(width, height);
frame.setTitle("first window");
f.setTitle("second window");
fill(0);
}
void draw() {
background(255);
ellipse(mouseX, mouseY, 10, 10);
s.setGhostCursor(mouseX, mouseY);
}
public class PFrame extends JFrame {
public PFrame(int width, int height) {
setBounds(100, 100, width, height);
s = new SecondApplet();
add(s);
s.init();
show();
}
}
public class SecondApplet extends PApplet {
int ghostX, ghostY;
public void setup() {
background(0);
noStroke();
}
public void draw() {
background(50);
fill(255);
ellipse(mouseX, mouseY, 10, 10);
fill(0);
ellipse(ghostX, ghostY, 10, 10);
}
public void setGhostCursor(int ghostX, int ghostY) {
this.ghostX = ghostX;
this.ghostY = ghostY;
}
}

One option might be to create a sketch twice the size of your original window and just offset the detected coordinates by half the sketch's size.
Here's a very rough code snippet (assumming blob will be a detected color blob):
int camWidth = 320;
int camHeight = 240;
Capture cam;
void setup(){
size(camWidth * 2,camHeight);
//init cam/opencv/etc.
}
void draw(){
//update cam and get data
image(cam,0,0);
//draw
rect(camWidth+blob.x,blob.y,blob.width,blob.height);
}
To be honest, it might be easier to overlay the tracked information. For example, if you're doing color tracking, just display the outlines of the bounding box of the tracked area.
If you really really want to display another window, you can use a JPanel.
Have a look at this answer for a running code example.

I would recommend using G4P, a GUI library for Processing that has some functionality built in for handling multiple windows. I have used this before with a webcam and it worked well. It comes with a GWindow object that will spawn a window easily. There is a short tutorial on the website that explains the basics.
I've included some old code that I have that will show you the basic idea. What is happening in the code is that I make two GWindows and send them each a PImage to display: one gets a webcam image and the other an effected image. The way you do this is to augment the GWinData object to also include the data you would like to pass to the windows. Instead of making one specific object for each window I just made one object with the two PImages in it. Each GWindow gets its own draw loop (at the bottom of the example) where it loads the PImage from the overridden GWinData object and displays it. In the main draw loop I read the webcam and then process it to create the two images and then store them into the GWinData object.
Hopefully that gives you enough to get started.
import guicomponents.*;
import processing.video.*;
private GWindow window;
private GWindow window2;
Capture video;
PImage sorted;
PImage imgdif; // image with pixel thresholding
MyWinData data;
void setup(){
size(640, 480,P2D); // Change size to 320 x 240 if too slow at 640 x 480
// Uses the default video input, see the reference if this causes an error
video = new Capture(this, 640, 480, 24);
numPixels = video.width * video.height;
data = new MyWinData();
window = new GWindow(this, "TEST", 0,0, 640,480, true, P2D);
window.isAlwaysOnTop();
window.addData(data);
window.addDrawHandler(this, "Window1draw");
window2 = new GWindow(this, "TEST", 640,0 , 640,480, true, P2D);
window2.isAlwaysOnTop();
window2.addData(data);
window2.addDrawHandler(this, "Window2draw");
loadColors("64rev.csv");
colorlength = mycolors.length;
distances = new float[colorlength];
noCursor();
}
void draw()
{
if (video.available())
{
background(0);
video.read();
image(video,0,0);
loadPixels();
imgdif = get(); // clones the last image drawn to the screen v1.1
sorted = get();
/// Removed a lot of code here that did the processing
// hand data to our data class to pass to other windows
data.sortedimage = sorted;
data.difimage = imgdif;
}
}
class MyWinData extends GWinData {
public PImage sortedimage;
public PImage difimage;
MyWinData(){
sortedimage = createImage(640,480,RGB);
difimage = createImage(640,480,RGB);
}
}
public void Window1draw(GWinApplet a, GWinData d){
MyWinData data = (MyWinData) d;
a.image(data.sortedimage, 0,0);
}
public void Window2draw(GWinApplet a, GWinData d){
MyWinData data = (MyWinData) d;
a.image(data.difimage,0,0);
}

Related

why does object.variable work in the main class and in other classes?

I am currently building Space Invaders in Processing and I do not absolutely understand why this happens, it is hard to explain, so here is all the code that goes with the game:
SpaceInvaders.pde:
/* Jordan Green
April 11th, 2018
This is the main class for the game
Space Invaders.
This is what sets up the game.
*/
//My objects declared.
Alien aliens;
Player player;
Score score;
PImage img;
//sets up the variables and gives them values.
void setup() {
aliens = new Alien();
player = new Player();
score = new Score();
size (600, 600);
img = loadImage("Space Background.jpg");
}
//draws out the program.
void draw() {
background(0);
image(img, 0, 0, height, width);
player.show();
player.move();
player.playerLives();
player.alienDie();
aliens.show();
aliens.move();
score.show();
if (player.playerLife == 0) {
}
}
void keyPressed() {
if (key == ' ') {
player.shoot();
}
}
My question is why does an object.variable work on Processing? It's something I do not understand.
Jordan
Why wouldn't it work?
This is a fundamental feature of objects in Java, which Processing is built on top of. If you have a class that contains variables or functions, you can reference those variables or functions using the . dot operator.
Here's an example:
class MyClass{
int x = 42;
void sayHello(){
println("hello");
}
}
MyClass myInstanceOfMyClass = new MyClass();
println(myInstanceOfMyClass.x);
myInstanceOfMyClass.sayHello();
In Java you can mark variables and functions as private to restrict access, but this is less common in Processing.
You can read more about classes in the reference or in this tutorial.

Calling drawing commands externally in Processing

I am trying to use g4p-controls library in Processing to create a button that executes a drawing command in another window. In this library, a child window is created by the code
GWindow window = GWindow.getWindow(this, "Main", 100, 50, 500, 500, JAVA2D);
where this is the main applet, and the other arguments specify the name, position, and renderer.
GWindow is a subclass of PApplet, so I should feasibly be able to call a drawing command, for example window.background(0);, from anywhere in my code to paint that window black. However, this does not work, and I cannot figure out why. After all, the same code works when I put it in a handler function and add it to the window:
window.addDrawHandler(this, "windowDraw");
where the windowDraw method is
public void windowDraw(PApplet app, GWinData data) {
app.background(0);
}
Looking into the source code, the draw handler method windowDraw is invoked by the GWindow object with the first argument this, which is exactly the object referred to when I attempted window.background(0);. So window should be the object whose background() method is called to paint the canvas black.
If I am misunderstanding something fundamental about event-driven programming, please let me know. It does seem like the handlers take the relevant applet as an argument for a reason, but I really cannot see what's different about invocation inside and outside the handler functions.
Some additional notes: calling window.background(0); works if it's inside the main draw() function. It does not work if it's in the setup() function, and unfortunately for me, it doesn't work if it's in a button handler method:
public void handleButtonEvents(GButton button, GEvent event) {
if (this.button == button) {
if (event == GEvent.PRESSED) {
window.background(0);
}
}
}
Obviously, I have made sure this code actually runs when I press the button.
Even more strangely, if I substitute the above drawing call to window with something like window.strokeWeight(10), the change actually takes place, and subsequent lines in that canvas are drawn thicker. It only fails to actually draw things. I am just at a loss.
In the future, please try to post a MCVE instead of a bunch of disconnected code snippets. Here's an example:
import g4p_controls.*;
GWindow window;
void setup(){
window = GWindow.getWindow(this, "Main", 100, 50, 500, 500, JAVA2D);
}
void draw(){
background(255, 0, 0);
window.ellipse(mouseX, mouseY, 25, 25);
window.draw();
}
void mousePressed(){
window.background(0, 255, 0);
}
I would expect this code to draw circles in the second window, and to draw green in the second window when I press the mouse in the first window. However, it seems to only draw those things very sporadically.
In fact, here's the same type of program, in "pure Processing" without using the G4P library:
SecondApplet sa;
void setup() {
String[] args = {"TwoFrameTest"};
sa = new SecondApplet();
PApplet.runSketch(args, sa);
}
void settings() {
size(200, 200);
}
void draw() {
background(0);
sa.ellipse(mouseX, mouseY, 25, 25);
}
void mousePressed() {
sa.background(255, 0, 0);
}
public class SecondApplet extends PApplet {
public void settings() {
size(200, 200);
}
void draw() {
}
}
I would also expect this to work, but we see a similar gray window for the second sketch. I've filed a bug here to get feedback from the Processing devs about whether this is expected behavior.
In the meantime, you'll have better luck if you do something like this:
SecondApplet sa;
float drawMouseX;
float drawMouseY;
color drawBackground = #0000ff;
void setup() {
String[] args = {"TwoFrameTest"};
sa = new SecondApplet();
PApplet.runSketch(args, sa);
}
void settings() {
size(200, 200);
}
void draw() {
background(0);
drawMouseX = mouseX;
drawMouseY = mouseY;
}
void mousePressed() {
drawBackground = #00ff00;
}
public class SecondApplet extends PApplet {
public void settings() {
size(200, 200);
}
void draw() {
background(drawBackground);
ellipse(drawMouseX, drawMouseY, 25, 25);
}
}
Instead of calling the drawing functions directly, we're now setting some variables that are then used in the second applet's draw() function. There are a bunch of ways to do this, but the idea is the same: just don't call the draw functions directly, and call them from the draw() function instead.
Update: I heard back from Ben Fry (a founder of Processing) and codeanticode (a developer of Processing) on the bug I filed on GitHub, and I understand better now why this doesn't work.
The reason it doesn't work is because each sketch has its own UI thread, which is responsible for drawing and handling events. You can't draw to a sketch from a different thread, otherwise weird things happen. But you're trying to draw to a second sketch from the first sketche's event thread, which is not the second sketch's drawing thread, which is why it doesn't work.
See the bug for a discussion on alternative approaches, but honestly your best bet is probably to go with the approach I outlined of just sharing variables between the sketches.

LibGDX / Box2d - only one rectangle is being rendered by debugrenderer

I'm revisiting LibGDX game programming and I am unfortunately having to re-learn stuff I used to know.
I'm currently using Tiled Map Editor to make a very simple Donkey Kong style level. I have around 20 rectangles in total for the level.
I've created a box2d world in my main GameScreen class and have a for loop to get the rectangle objects into the world and debugrenderer.
My problem is that only the bottom (and first) rectangle I drew is showing up. I have checked the scale, also I put a println() which tells me the object information has been parsed with all the rectangles info showing correct (ie. the rectangles x,y,w,h values) but as I say, only one rectangle shows up on the debugrenderer.
I've just got back into programming after around 6month break and so I'm hoping i've missed something simple. The same code in my old projects still works fine as I've tested some.
Here is my code, any help is massively appreciated. Thanks
public class GameScreen implements Screen {
SpriteBatch spriteBatch;
OrthographicCamera cam;
Viewport v;
TmxMapLoader mapLoader;
TiledMap map;
OrthogonalTiledMapRenderer mapRenderer;
World world;
Box2DDebugRenderer b2dr;
float mapScale = 10f/140f;
public GameScreen(){
spriteBatch = new SpriteBatch();
cam = new OrthographicCamera();
v = new FitViewport(Constants.V_WIDTH, Constants.V_HEIGHT, cam);
cam.setToOrtho(false, v.getWorldWidth(), v.getWorldHeight());
mapLoader = new TmxMapLoader();
map = mapLoader.load("level1.tmx");
mapRenderer = new OrthogonalTiledMapRenderer(map, mapScale);
world = new World(new Vector2(0,-9.8f), true);
b2dr = new Box2DDebugRenderer();
// box2d local variables
BodyDef bdef = new BodyDef();
PolygonShape shape = new PolygonShape();
FixtureDef fdef = new FixtureDef();
Body body;
// create platform object rectangles
for (MapObject object : map.getLayers().get(2).getObjects().getByType(RectangleMapObject.class)){
Rectangle rect = ((RectangleMapObject)object).getRectangle();
bdef.type = BodyDef.BodyType.StaticBody;
bdef.position.set(rect.getX() + rect.getWidth() / 2 * mapScale, rect.y + rect.getHeight() / 2 * mapScale);
body = world.createBody(bdef);
shape.setAsBox(rect.getWidth() / 2 * mapScale, rect.getHeight() / 2 * mapScale);
fdef.shape = shape;
body.createFixture(fdef);
}
}
#Override
public void show() {
}
#Override
public void render(float delta) {
update(delta);
clearScreen();
draw();
}
public void update(float dt){
mapRenderer.setView(cam);
}
public void clearScreen(){
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
public void draw(){
spriteBatch.setProjectionMatrix(cam.combined);
mapRenderer.render();
b2dr.render(world, cam.combined);
spriteBatch.begin();
spriteBatch.end();
}
#Override
public void resize(int width, int height) {
v.update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
spriteBatch.dispose();
}
}
Sorry for wasting time here. I have fixed this.
It was just that I hadnt applied the scale of the map also to the x,y of the rectangles. So i change one line like so, and now it works:
bdef.position.set(rect.getX() * mapScale + rect.getWidth() / 2 * mapScale, rect.y * mapScale + rect.getHeight() / 2 * mapScale);

MousePressed drawing ellipse in tuio

Hi if anyone could help me out i would be very grateful, i have a sketch that will enable a user to draw graffiti on a screen with a wireless spray can. At the minute, with the tuio code installed, when the user presses the mouse button, a spray sound is made.. but i am having difficulty in the sketch creating an ellipse when presses the mouse button.
This is my code;
import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;
Minim minim;
AudioPlayer player;
AudioInput input;
/*TUIO processing demo - part of the reacTIVision project
http://reactivision.sourceforge.net/
Copyright (c) 2005-2009 Martin Kaltenbrunner <mkalten#iua.upf.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You shgould have greceived a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// we need to import the TUIO library
// and declare a TuioProcessing client variable
import TUIO.*;
TuioProcessing tuioClient;
import java.util.*; //ADD THIS LINE TO BE ABLE TO USE TUIOCLIENT WITH PROCESSING 2+
// these are some helper variables which are used
// to create scalable graphical feedback
float cursor_size = 15;
float object_size = 60;
float table_size = 760;
float scale_factor = 1;
PFont font;
//declare a boolean to check mouse click
boolean drag = false;
int n=0;
int size[]= {20,40};
int sizeChosen;
boolean inside = false;
PImage bg;
PImage img;
PGraphics pg;
import controlP5.*;
ControlP5 cp5;
boolean mp = true;
void setup ()
{
size(1000,1000);//size(screen.width, screen.height).
smooth();
noStroke();
fill(0);
loop();
frameRate(30);
hint(ENABLE_NATIVE_FONTS);
font = createFont("Arial",18);
scale_factor = height/table_size;
// we create an instance of the TuioProcessing client
// since we add "this" class as an argument the TuioProcessing class expects
// an implementation of the TUIO callback methods (see below)
tuioClient = new TuioProcessing(this);
ellipseMode( CENTER);
//smooth();
noCursor();
background(170);
bg = loadImage("brickwall.jpg");
background(bg);
img = loadImage("instructions.jpg");
image (img,30,40,THUMB_SIZE, THUMB_SIZE);
cp5 = new ControlP5(this);//screenshot button
cp5.addButton("Save Graffiti Artwork").setPosition(0,650).setSize(200,100);//screenshot details
minim = new Minim(this);
player = minim.loadFile("spray_close.wav");
input = minim.getLineIn();
}
void draw() {
if (mp = true);
ellipse(255,0,255,0);
background(bg);
textFont(font,18*scale_factor);
float obj_size = object_size*scale_factor;
float cur_size = cursor_size*scale_factor;
Vector tuioObjectList = tuioClient.getTuioObjects();
for (int i=0;i<tuioObjectList.size();i++) {
TuioObject tobj = (TuioObject)tuioObjectList.elementAt(i);
noStroke();
fill(0);
pushMatrix();
translate(tobj.getScreenX(width), tobj.getScreenY(height));
rotate(tobj.getAngle());
// ellipse(-obj_size/2, -obj_size/2, obj_size, obj_size);
popMatrix();
//fill(255);
text(""+tobj.getSymbolID(), tobj.getScreenX(width), tobj.getScreenY(height));
if (mousePressed) {
ellipse(255,0,255,0);
// printIn("Pink");
//mouse press 1
if (tobj.getSymbolID()==12) {
ellipse(255,0,255,0);
}
}
}
Vector tuioCursorList = tuioClient.getTuioCursors();
for (int i=0;i<tuioCursorList.size();i++) {
TuioCursor tcur = (TuioCursor)tuioCursorList.elementAt(i);
Vector pointList = tcur.getPath();
if (pointList.size()>0) {
stroke(0, 0, 255);
TuioPoint start_point = (TuioPoint)pointList.firstElement();
;
for (int j=0;j<pointList.size();j++) {
TuioPoint end_point = (TuioPoint)pointList.elementAt(j);
line(start_point.getScreenX(width), start_point.getScreenY(height), end_point.getScreenX(width), end_point.getScreenY(height));
start_point = end_point;
}
stroke(192, 192, 192);
fill(192, 192, 192);
ellipse( tcur.getScreenX(width), tcur.getScreenY(height), cur_size, cur_size);
fill(0);
text(""+tcur.getCursorID(), tcur.getScreenX(width)-5, tcur.getScreenY(height)+5);
}
}
if (drag) //if drag = true, i-e if mouse click is holding, ellipse are drawing according the mouse's position
{
fill(#FF00FF); //black color
ellipse(mouseX, mouseY, 50,50); //draw ellipse with x and y mouse's position + size 10*10
//or line strokeWeight(3);stroke(0);line(mouseX,mouseY,25,25);
}
//draw palette size
for(n=0;n<2;n++)
{
fill(0);
ellipse(360,10+n*40,20*(n+1),20*(n+1));
}
}
//size selector
void mousePressed() {
//bDrawFullSize = true;
if (inside==true){
sizeChosen=size[n];
}
player.play();
mp = true;
}
void mouseReleased() {
//bDrawFullSize = true;
drag = false;
player.close();
//since close closes the file, we need to load the sound effect again.
player = minim.loadFile("spray_close.wav");
}
//function "drag and drop"
void mouseDragged() {
drag = true;
}
// these callback methods are called whenever a TUIO event occurs
// called when an object is added to the scene
void addTuioObject(TuioObject tobj) {
println("add object "+tobj.getSymbolID()+" ("+tobj.getSessionID()+") "+tobj.getX()+" "+tobj.getY()+" "+tobj.getAngle());
}
// called when an object is removed from the scene
void removeTuioObject(TuioObject tobj) {
println("remove object "+tobj.getSymbolID()+" ("+tobj.getSessionID()+")");
}
// called when an object is moved
void updateTuioObject (TuioObject tobj) {
println("update object "+tobj.getSymbolID()+" ("+tobj.getSessionID()+") "+tobj.getX()+" "+tobj.getY()+" "+tobj.getAngle()
+" "+tobj.getMotionSpeed()+" "+tobj.getRotationSpeed()+" "+tobj.getMotionAccel()+" "+tobj.getRotationAccel());
}
// called when a cursor is added to the scene
void addTuioCursor(TuioCursor tcur) {
println("add cursor "+tcur.getCursorID()+" ("+tcur.getSessionID()+ ") " +tcur.getX()+" "+tcur.getY());
}
// called when a cursor is moved
void updateTuioCursor (TuioCursor tcur) {
println("update cursor "+tcur.getCursorID()+" ("+tcur.getSessionID()+ ") " +tcur.getX()+" "+tcur.getY()
+" "+tcur.getMotionSpeed()+" "+tcur.getMotionAccel());
}
// called when a cursor is removed from the scene
void removeTuioCursor(TuioCursor tcur) {
println("remove cursor "+tcur.getCursorID()+" ("+tcur.getSessionID()+")");
}
// called after each message bundle
// representing the end of an image frame
void refresh(TuioTime bundleTime) {
redraw();
}
void keyPressed() {
endRecord();
background(bg);
// exit();
}
public void saveScreen() {
saveFrame();
player.pause();
}
// returns true if mouse is inside this rectangle
boolean inside(int left, int top, int right, int bottom ) {
if (mouseX>left && mouseX<right && mouseY>top && mouseY<bottom ) {
return true;
}
else {
return false;
}
}
Anything under the function:
void mousePressed() {
//bDrawFullSize = true;
if (inside==true){
sizeChosen=size[n];
}
player.play();
mp = true;
}
is run every frame while mouse is pressed. So you would create an ellipse (or whatever you want) here.
You can put the ellipse generation function inside branching condition that's checking on the mouse pressed state:
if (mousePressed) {
ellipse(random(0,width),random(0,height),random(0,100),random(0,100));
}
put the condition at the end of the Draw function so that it overwrites any background element

gtkD: Minimal Drawing Example?

I'm a fairly experienced programmer, but new to GUI programming. I'm trying to port a plotting library I wrote for DFL to gtkD, and I can't get drawings to show up. The following code produces a blank window for me. Can someone please tell me what's wrong with it, and/or post minimal example code for getting a few lines onto a DrawingArea and displaying the results in a MainWindow?
import gtk.DrawingArea, gtk.Main, gtk.MainWindow, gdk.GC, gdk.Drawable,
gdk.Color;
void main(string[] args) {
Main.init(args);
auto win = new MainWindow("Hello, world");
win.setDefaultSize(800, 600);
auto drawingArea = new DrawingArea(800, 600);
win.add(drawingArea);
drawingArea.realize();
auto drawable = drawingArea.getWindow();
auto gc = new GC(drawable);
gc.setForeground(new Color(255, 0, 0));
gc.setBackground(new Color(255, 255, 255));
drawable.drawLine(gc, 0, 0, 100, 100);
drawingArea.showAll();
drawingArea.queueDraw();
win.showAll();
Main.run();
}
I have no experience whatsoever in D, but lots in GTK, so with the help of the gtkD tutorial I managed to hack up a minimal example:
import gtk.DrawingArea, gtk.Main, gtk.MainWindow, gdk.GC, gdk.Drawable,
gdk.Color, gtk.Widget;
class DrawingTest : MainWindow
{
this()
{
super("Hello, world");
setDefaultSize(800, 600);
auto drawingArea = new DrawingArea(800, 600);
add(drawingArea);
drawingArea.addOnExpose(&drawStuff);
showAll();
}
bool drawStuff(GdkEventExpose *event, Widget self)
{
auto drawable = self.getWindow();
auto gc = new GC(drawable);
gc.setForeground(new Color(cast(ubyte)255, cast(ubyte)0, cast(ubyte)0));
gc.setBackground(new Color(cast(ubyte)255, cast(ubyte)255, cast(ubyte)255));
drawable.drawLine(gc, 0, 0, 100, 100);
return true;
}
}
void main(string[] args) {
Main.init(args);
new DrawingTest();
Main.run();
}
In GTK, a DrawingArea is actually just a blank widget for you to paint on, and painting on widgets must always be done in the expose-event handler. (Although I understand this will change in GTK 3!)
I understand you can't connect functions as signal callbacks, only delegates, so that's the reason for the DrawingTest class.

Resources