Loading...
Logo
Processing Forum
hi everybody!
First of all, I am new to the forum and I would like to thank everybody for the great work!

and here is my question...

I am trying to develop a multitouch application that make use of fiducials as well. I would like to create a menu with controlP5 every time I add a fiducial to my application. For developing I am using the TUIO simulator. As starting point I am using the TUIO demo sketch that comes with the TUIO library.
the problem is that most of the time (but not always!) when I initiate a new controller inside the addTuioObject() function I get a 'java.lang.NullPointerException'
my doubt is if it's possible to create a controller outside the setup() function and if I am doing it the right way...
moreover, after I've added a certain number of controllers to my sketch I also get this other exception 'Exception in thread "Animation Thread" java.lang.RuntimeException: pushMatrix() cannot use push more than 32 times'.
I am not sure, but I think those two errors are connected.

Here is the code, hope someone could help me out!
thanx in advance


import TUIO.*;
import controlP5.*;

TuioProcessing tuioClient;
ControlP5 controlP5;
Button menu;
ListBox lista;
// 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;

void setup()
{
 //size(screen.width,screen.height);
 size(640,480);
 noStroke();
 fill(0);
 
 loop();
 frameRate(30);
 //noLoop();
 
 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);
 controlP5 = new ControlP5(this);
 
}

// within the draw method we retrieve a Vector (List) of TuioObject and TuioCursor (polling)
// from the TuioProcessing client and then loop over both lists to draw the graphical feedback.
void draw() {
 background(255);
 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);
    stroke(0);
    fill(0);
    pushMatrix();
    translate(tobj.getScreenX(width),tobj.getScreenY(height));
           rotate(tobj.getAngle());
    rect(-obj_size/2,-obj_size/2,obj_size,obj_size);
    popMatrix();
    fill(255);
    text(""+tobj.getSymbolID(), tobj.getScreenX(width), tobj.getScreenY(height));
  }
}

// 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());
        menu = controlP5.addButton("menu"+tobj.getSymbolID(), 0, (int)(width*tobj.getX())+35, (int)(height*tobj.getY())-30,20,60);
menu.setId(tobj.getSymbolID());
lista = controlP5.addListBox("video"+tobj.getSymbolID(),(int)(width*tobj.getX())+35, (int)(height*tobj.getY())-30,100,100);
lista.setId(tobj.getSymbolID());
for(int i=0;i<5;i++) {
 lista.addItem("video"+(i+1),i);
}
}

// called when an object is removed from the scene
void removeTuioObject(TuioObject tobj) {
 println("remove object "+tobj.getSymbolID()+" ("+tobj.getSessionID()+")");
//          menu.remove();
//          lista.remove();
}

// 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 after each message bundle
// representing the end of an image frame
void refresh(TuioTime bundleTime) { 
 redraw();
}

Replies(5)

Welcome to the forum! I take the opportunity to remind that nearly all questions are programming questions, so it is better to choose the most specific forum to ask questions: here one cannot test without having the same libraries, so it belongs to the Contributed libraries section. I moved the thread.

I looked at your code but I know nothing about TUIO and not much about controlP5, so I cannot tell if there is an error. At least, the pushMatrix I see is balanced with a popMatrix. You create controlP5 objects on the fly, but are they always on screen? Maybe you need to remove or hide them and reuse them. I also don't see events associated to these controls, how they are used.
yes you can create controlP5 Controls outside of setup. simply test it by putting it in keyPressed().
but like philho said, it might be better to initiate everything needed and then just hide and show the controllers
http://www.sojamo.de/libraries/controlP5/reference/index.html
you can also group them and simply show and hide the group.



hi, as cedric already mentioned, controllers can be created outside of setup(). in your case i suspect that there is a threading related conflict. your sketch and TUIO are running in 2 separate threads, making changes across threads can result in conflicts, like in your case the exception that complains about push/popMatrix(), which is probably caused because controlP5 is drawing lista but at the same time items of the list are modified which ends up with an exception.

i have attached a keyPressed example to demonstrate cedric's suggestion. here only one button and one list is used, if you need to display a button and a list for each active/visible TUIOobject, you could work with arrays or a changeFlag as described below.

to avoid the threading issues you could for example work with a changeFlag (boolean) which is activated(set to true) for each TUIOobject-change and is then checked inside your draw() function. if the flag has been activated, changes to the button and the list will be performed (or new buttons and lists will be added) accordingly and the flag will be set back to false.


Copy code
  1. import controlP5.*;

  2. ControlP5 controlP5;

  3. Button menu;
  4. ListBox lista;

  5. void setup() {
  6.   size(640,480);   
  7.   frameRate(30);
  8.   controlP5 = new ControlP5(this);
  9.   // initialize controllers and place them outside 
  10.   // the visible area of your window
  11.   menu = controlP5.addButton("menu",0,-1000,-1000,20,60);
  12.   lista = controlP5.addListBox("video",-1000,-1000,100,100);
  13. }

  14. void draw() {
  15.   background(255);
  16. }

  17. void keyPressed() {
  18.   int id = (int)random(1000);
  19.   int x = mouseX + 35;
  20.   int y = mouseY + 30;
  21.   
  22.   // move your button to a given xy-location
  23.   menu.setPosition(x,y);
  24.   menu.setCaptionLabel(""+id);
  25.   menu.setId(id);
  26.   
  27.   // instead of adding a new list to controlP5,
  28.   // clear your list.
  29.   lista.clear();
  30.   // move your list to a given xy-location
  31.   lista.setPosition(x+20,y);
  32.   lista.setId(id); 
  33.   // add new list items to your empty list
  34.   for(int i=0;i<5;i++) {
  35.     lista.addItem("video"+(i+1),i);
  36.   }
  37. }


  38. void controlEvent(ControlEvent theEvent) {
  39.   // events from controlP5 will trigger a controlEvent
  40.   // inside your sketch. 
  41.   println("Got an event from "+theEvent.name());
  42. }


Thanx all!
at the end I managed to solve my probleme as you suggested. I hav created an array of controllers in setup and hide them.
Then everytime I add or remove a fiducial I show or hide the corresponding menu according to the ID.

thnx a lot

cool. In my example i initially positioned both controllers (button and list) outside of the visible area of the display window. This is not necessarily a good solution to hide controllers, a better approach is to use controller.show() and controller.hide(). (Hiding controllers that way will ignore them from drawing. positioning controllers outside of the display window will still result in a call to a controller's draw() method.)