We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpSyntax Questions › Sequencing, display update, and functions
Page Index Toggle Pages: 1
Sequencing, display update, and functions (Read 1368 times)
Sequencing, display update, and functions
Mar 11th, 2009, 10:20pm
 
First time processing here.  I'm trying to wedge my other habits from programming into this language.  Right now I'm stumbling over the update of the screen outside of draw() and whether that is proper or not.

I want to write something to do a rotating set of tasks, like:

1) display image
2) display text
3) display another image

Although this is done simply inside of draw(), it gets more complex if I want to move the images/text, use functions for the images.  Right now, the only way I can see doing it is with a lot of global variables, including one which determines which section of "draw" I am currently running for the task sequence.

Based on past experience, this would be cleaner to me if I could use functions and a call inside those function loops for updating the displayed image.  Is this right or proper?

Thanks for helping this newb.
Re: Sequencing, display update, and functions
Reply #1 - Mar 11th, 2009, 10:28pm
 
There must be something in the air.  This is very similar to the thread I just revived asking approximately the same question for approximately the same reasons.

http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1229985333
Re: Sequencing, display update, and functions
Reply #2 - Mar 12th, 2009, 8:31pm
 
Haven't tried it myself, but I believe you can use noLoop() to stop processing from calling the draw() function every frame and then use reDraw() to call it yourself when you need to.
Re: Sequencing, display update, and functions
Reply #3 - Mar 12th, 2009, 9:40pm
 
Yep.  Pretty much any sketch that has user-interaction to change between different global drawing modes is going to share some attributes:

* at least 1 global variable that tracks what mode the sketch is in,
* a call to noLoop() in the setup() routine,
* event handlers (mousePressed and the like) that trigger actions in the script which will either change the drawing mode and/or alter the data being drawn in the current mode,
* a switch() statement or if/elseif/else construction to invoke different drawing code inside of the draw() routine.

It works, and once you get the knack of it, it's a pretty easy pattern to implement.  And if the presence of global variables bothers you, you can comfort yourself in knowing that a) there's really no other option, and b) they're not actually global variables; Processing packages your sketch into a java class with the same name as the .pde file, so really those variables are just fields of that class.

And at least for me, I know that if I were writing these sketches in C# or some other environment where I did have to explicitly define a whole class to encapsulate the sketch, I wouldn't feel at all bad about making fields to hold the class's state.  That's just how you do it.  The fact that the PDE hides from you the fiddly bits of hooking your code up to Processing's guts makes your good-programming-practice member fields masquerade as bad-programming-practice global variables, but really they're not.
Re: Sequencing, display update, and functions
Reply #4 - Mar 13th, 2009, 12:12am
 
Global variables don't bother me.  I cut my teeth on Fortran Common blocks and enjoy low-level programming tiny processors where all memory is "global."  And I understand how to get my Processing code to do what I want it to.

But I think this is a weakness in the Processing paradigm.  There are any number of situations where the logic:

do a bunch of stuff
update the screen
do the same stuff again
update the screen
do the same stuff again
update the screen

is just unnatural relative to the task.  And only some of these tasks have to do with user-interaction.

And the more "do the same stuff again" is really a collection of mutually exclusive code blocks selected with a big case statement, the more unnatural this paradigm feels.

The occurrence of screen updates really should be liberated from the draw() loop, and (optionally) put under direct programmer control.

Would some kind of updateDisplay() be all that difficult to add?
Re: Sequencing, display update, and functions
Reply #5 - Mar 13th, 2009, 5:14pm
 
I don't know but when you put it in those terms I have to say I 100% agree with you.  Forcing all drawing to take place inside of (or called from) draw() also cramps my style sometimes.

Since Processing is open source, why don't you see if you can hack something like that into it?  As long as you don't break existing code (remain forward compatible), and implement it in a way such that there are no weird side effects (like, for example, coordinate system transformations somehow not applying correctly when drawing gets pushed to the screen through your code), then I would imagine Fry and REAS would be receptive to something like that.

I mean, why wouldn't they?  It broadens the number of viable coding models that Processing would work with.
Re: Sequencing, display update, and functions
Reply #6 - Mar 13th, 2009, 7:00pm
 
I am not sure of the usefulness of this model. Actually, we have already noLoop() and redraw() although the latter might be deprecated and I couldn't make it work outside of an event.

Anyway, the interest of draw() is that it is called at regular intervals, making the pulse of your sketch. If you don't want to use it, you would need to make your own drawing loop or something.

I made a little demo sketch showing we can do what you wanted, and perhaps even more (animation), using the current paradigm. It might seem too complex, but it isn't, I just wanted to make it nicely object oriented and structured.

It is late, I just dump the code, if you have any question, just ask!

DrawingInSequence.pde - Code:
//ArrayList<Drawer> drawers = new ArrayList<Drawer>();
ArrayList drawers = new ArrayList();
Drawer currentDrawer;
int currentDrawerIdx;
int currentDuration;

interface Drawer
{
 public void Draw();
 public int GetDuration();
 public void SetDuration(int d);
}

abstract class DefaultDrawer implements Drawer
{
 protected int m_duration = 10;

 public abstract void Draw();
 //@Override
 public int GetDuration()
 {
   return m_duration;
 }
 //@Override
 public void SetDuration(int d)
 {
   m_duration = d;
 }
}

class Texter extends DefaultDrawer
{
 private String m_message;
 private int m_color;

 public Texter(int d, String m, int c)
 {
   m_duration = d;
   m_message = m;
   m_color = c;
 }

 //@Override
 public void Draw()
 {
   background(0);
   textAlign(CENTER);
   fill(m_color);
   noStroke();
   // Suppose textFont() have been called
   text(m_message, width / 2, height / 2);
 }
}

void setup()
{
 size(800, 800);
 PFont f = createFont("Arial", 48);
 textFont(f);
 smooth();

 drawers.add(new Texter(7, "Demonstrating drawing in sequence", #FF1100));
 drawers.add(new Texter(5, "Fill With Circles 1", #AA8800));
 drawers.add(new FillWithCircles(250, 222));
 drawers.add(new Texter(5, "Pulsating Circles", #BB7700));
 Drawer dr = new PulsatingCircles();
 dr.SetDuration(30);
 drawers.add(dr);
 drawers.add(new Texter(5, "Fill With Circles 2", #CC6600));
 drawers.add(new FillWithCircles(350, 333));
 drawers.add(new Texter(10, "END", #FF0000));
}

void draw()
{
 currentDrawer = (Drawer) drawers.get(currentDrawerIdx);
 currentDrawer.Draw();
 int time = millis() / 1000;
 if (time - currentDuration > currentDrawer.GetDuration())
 {
   currentDrawerIdx++;
   currentDuration = time;
   if (currentDrawerIdx == drawers.size())
   {
     noLoop();
   }
 }
}

Drawers.pde - Code:
// Just reusing two old sketches

class FillWithCircles extends DefaultDrawer
{
 int MIN_RAD = 10;
 int MAX_RAD = 100;
 int m_circleNb;
 int m_radius;

 FillWithCircles(int radius, int circleNb)
 {
   m_radius = radius;
   m_circleNb = circleNb;
 }

 //@Override
 void Draw()
 {
   background(255);
   noStroke();

   int centerX = width / 2;
   int centerY = height / 2;

   for (int i = 0; i < m_circleNb; i++)
   {
     float d = random(0, m_radius - MIN_RAD);
     float a = random(0, TWO_PI);
     float x = centerX + d * cos(a);
     float y = centerY + d * sin(a);
     float r = random(MIN_RAD, min(MAX_RAD, m_radius - d));
     color c = lerpColor(#00FF00, #0000FF, (1 + cos(a))/2);

     fill(c);
     ellipse(x, y, r * 2, r * 2);
   }
 }
}

class PulsatingCircles extends DefaultDrawer
{
 int rMove = +5;
 int slowDown = 1;
 int minRadius = 5, maxRadius = 100;
 int radius = minRadius;
 int xPos = 200;
 int yPos = 200;
 color c1 = #005599, c2 = #00AA99;

 PulsatingCircles() {}

 //@Override
 void Draw()
 {
   background(240);
   fill(lerpColor(c1, c2, (float) radius / (float) maxRadius));

   ellipse(xPos, yPos, radius, radius);
   if (frameCount % slowDown == 0)
   {
     radius += rMove;
     if (radius > maxRadius)
       rMove = -1;
     else if (radius < minRadius)
       rMove = +1;
   }
 }
}

[EDIT] Finally I make Texter to extend DefaultDrawer (ex. Imager).
Page Index Toggle Pages: 1