Force a draw - outside of the ::draw() method?

I have a function in my ofApp which loads some stuff from disk, and performs some initializations. In doing so, it completely hogs the default draw() method for about 5-10 second, which I’ve confirmed with:

void ofApp::draw() {
    ofLogNotice() << "   draw! ";
    ...
}

Basically, no message is output during while initialization function does its stuff and hogs the rest.

I am aware that this should probably be solved somehow using threads, but for now, I’d just like to draw a line on screen, to indicate something is happening. Initially I would have added an ofDrawLine in the draw() method, but since it doesn’t run while hogging, it doesn’t help me with much. So, I thought of inserting ofDrawLine directly in my function that inits (and hogs):

void ofApp::LoadAndInit() {
    ofSetColor(ofColor::green);
    ofSetLineWidth(3);
    ofDrawLine(50, 50, -50, -50); // start indication
    // do hog stuff part 1
    ofDrawLine(60, 60, -60, -60);
    // do hog stuff part 2
    ....
}

I would have expected the lines to overlap with the last rendered image (as the full draw() is not called, and the rendering process would not clear the window) - however, I am not having anything shown at all.

Is there anything I could do (maybe call some function), so that the ofDrawLine is forced to draw from this function - regardless if it is not called from the actual draw()? I tried using events().notifyDraw(); after the ofDrawLine, but unfortunately I still cannot see any of these lines drawn…

Hi,

One way to do it would be to load stuff on the second frame. So on the first frame you do nothing but draw something to the screen to show it’s not completely crashed, on the second frame you initiate the load, get stuck and eventually continue drawing.

1 Like

Many thanks for the reply, @hahakid :

One way to do it would be to load stuff on the second frame. So on the
first frame you do nothing but draw something to the screen to show it’s
not completely crashed, on the second frame you initiate the load, get
stuck and eventually continue drawing.

Ok, just to make sure - this implies I should have some sort of management, e.g. via variables, to initiate loading right after the second frame is drawn, right? Say:

onClick: set doLoadHeavyStuff = true

… and then:

void ofApp::draw() {
    // rest of draw....
    if (doLoadHeavyStuff) {
      myfont.drawString("Loading...", 100,100);
      ofDrawLine(50, 50, -50, -50); // start indication
      LoadAndInit(); // this hogs; at end sets doLoadHeavyStuff = false;
      return; //bail out early
    }
    // rest of draw....
}

Also, is it OK that I hog the draw() directly as shown in the little snippet above - or would it be better that I set up an event listener, and then dispatch an event from the draw()?

Hi, something like this should do it:

//-----------------------------------------------------------------------------------------
//
class ofApp : public ofBaseApp
{
	public:


		//----------------------------------
		void setup()
		{
			loaded = false;
		}

		//----------------------------------
		void update()
		{
			if( !loaded && ofGetFrameNum() > 1 ) 
			{
				// LoadHeavyStuff();
				loaded = true;
			}

		}

		//----------------------------------
		void draw()
		{
			if( !loaded )
			{
				// draw something saying you're loading
			}
			else
			{
				draw normally
			}
		}		

		bool loaded;
};
1 Like

Thanks for the example @hahakid - however, I couldn’t really apply it to my use case. So I made a buildable minimal “working” example, based on examples/emptyExample. Use standard Makefile and main.cpp; and then:

ofApp.h

#pragma once

#include "ofMain.h"

#define BUFLEN 2000000

class ofApp : public ofBaseApp{
  public:
    unsigned char myBuf[BUFLEN];
    int state = 0;
    bool doLoad;
    void LoadAndInitHeavyHog();
    ofTrueTypeFont myfont;

        void setup();
        void update();
        void draw();

        void keyPressed(int key);
        void keyReleased(int key);
        void mouseMoved(int x, int y);
        void mouseDragged(int x, int y, int button);
        void mousePressed(int x, int y, int button);
        void mouseReleased(int x, int y, int button);
        void mouseEntered(int x, int y);
        void mouseExited(int x, int y);
        void windowResized(int w, int h);
        void dragEvent(ofDragInfo dragInfo);
        void gotMessage(ofMessage msg);
};

ofApp.cpp

#include "ofApp.h"

void ofApp::LoadAndInitHeavyHog(){
  for(unsigned long i=0; i<BUFLEN; i++) {
    unsigned char val = ((i + i/3)/150)%255;
    myBuf[i] = val;
    if ( (i%25) == 0 ) {
      ofLogNotice() << " ... i: " << i; //hog even more by dumping to stdout
    }
  }
  state = 1;
  doLoad = false;
}


//--------------------------------------------------------------
void ofApp::setup(){
  ofSetLogLevel(OF_LOG_NOTICE);
  state = 0;
  doLoad = false;
  myfont.load("arial.ttf", 32);
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){
  if (state == 0) {
    myfont.drawString("State 0 - click anywhere", 100,100);
  }
  if ((state == 0) && (doLoad)) {
    myfont.drawString(" --- LOADING --- ", 100,100);
    LoadAndInitHeavyHog();
  }
  if (state == 1) {
    myfont.drawString("State 1 - loaded...", 100,100);
  }
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
  ofLogNotice() << "::mousePressed ";
  if (state == 0) {
    doLoad = true;
  }
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}

In this example, when I build it on Linux, the " — LOADING — " message is not shown when I click the window, however, as evidenced by the log messages in stdout, the LoadAndInitHeavyHog() runs - and when it’s done, I do get “State 1 - loaded…” shown…

Any hints on how do I get the LOADING message to show in this case?

One way to do it is to add a “loading screen shown” variable that is set to false when the loading action is initiated (e.g. by clicking the mouse in the example).

void ofApp::draw(){
  if (state == 0) {
    myfont.drawString("State 0 - click anywhere", 100,100);
  }

  if ((state == 0) && (doLoad)) {
    if (loadingScreenShown) {
      LoadAndInitHeavyHog();
    } else {
      myfont.drawString(" --- LOADING --- ", 100,100);
      loadingScreenShown = true;
    }
  }

  if (state == 1) {
    myfont.drawString("State 1 - loaded...", 100,100);
  }
}

I think this should work, but it does require another variable.

1 Like

Thanks for that @hardmanko - it does work (although the if/then would need to be arranged differently, so the screen is erased before the LOADING is shown). I was also thinking about something similar in the meantime, based on @hahakid’s ofGetFrameNum() > 1: my mistake was to set the string in draw(), and then call the hogging function immediately afterwards - which doesn’t allow the draw() to complete and therefore no LOADING string was shown. So I thought that in draw(), I should save the value of the current frame number, and otherwise set the LOADING string and let the draw() continue so its rendered, and only in the next frame call the hogging function. However, you’ve solved it with a boolean, and works just as well.

Thanks for the help, guys - cheers!