Cropping a section of screen

Hey,

I am working on an app that allows the user to select a particle system and display it in a preview “window” / box on the screen. The problem I am having is that the particles overlap the edge of the box when they get close. I was wondering if there is a way that if a particle (could be rendered as an ofCircle or ofImage, etc) is overlapping the bounds, that I only render the part of it that is inside?

I have detection in place to know if they are out of the bounds of the box (and this will either bounce them or reset them depending on the system).

Ideally I’d like to be able to draw all my particles to the screen, then just crop the display box at the end. Is they anything built into OF or openGL to do this? I’m thinking something like temporarily resizing the openGL viewport would do the trick… but I’m not exactly sure the correct way to do this with messing with the rest of OF’s rendering.

As a pure OF solution/hack, I thought of rendering my particles, then using ofImage.grabScreen to capture the section I want, then clearing the screen and redrawing the captured section. The problem with that is that clearing the screen would kill the rest of the stuff I am drawing to screen… and also that this method definitely wouldn’t be the most optimized for this purpose.

Ok, well I am making some progress based on information from the glViewport tutorial at http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=42 … I managed to get it rendering only inside the box, but now I’m having some problems with how the co-ordinates are being offset… and also I think there might be a more correct way for setting my viewport’s bounds (I’m using a bit of a magic number hack to offset the y…)

Here is the code I have at this point for my draw method…

  
  
void PartyklezWindow::draw(float x, float y, float w, float h){  
	if(this->partyklez != NULL){  
		float ratioX = w/ofGetWidth();  
		float ratioY = h/ofGetHeight();  
		float ratioAspect=0.0;  
		  
/**** the w-1, h-1 makes sense to me (because I have a 1px border being drawn behind) ... I don't know why I need to do such calculations for the y value though... just got to these value by experimenting with them ****/  
		glViewport(x, y+y+h*ratioY-11, w-1, h-1);  
		  
		// this stuff is copied from the ofGraphics.cpp::void ofSetupScreen() method  
		float halfFov, theTan, screenFov, aspect;  
		screenFov 		= 60.0f;  
		float eyeX 		= (float)w / 2.0;  
		float eyeY 		= (float)h / 2.0;  
		halfFov 		= PI * screenFov / 360.0;  
		theTan 			= tanf(halfFov);  
		float dist 		= eyeY / theTan;  
		float nearDist 	= dist / 10.0;	// near / far clip plane  
		float farDist 	= dist * 10.0;  
		aspect 			= (float)w/(float)h;  
		  
		glMatrixMode(GL_PROJECTION);  
		glLoadIdentity();  
		gluPerspective(screenFov, aspect, nearDist, farDist);  
		  
		glMatrixMode(GL_MODELVIEW);  
		glLoadIdentity();  
		gluLookAt(eyeX, eyeY, dist, eyeX, eyeY, 0.0, 0.0, 1.0, 0.0);  
		  
		glClear(GL_DEPTH_BUFFER_BIT);  
  
/**** this is the experimental part I am having troubles with ****/  
		float xScale = w / ofGetWidth();  
		float yScale = h / ofGetHeight();  
		  
//		cout << "scale:" << xScale << "," << yScale << ":" << endl;  
		glScalef(1, -1, 1);           // invert Y axis so increasing Y goes down.  
		glTranslatef(0, -h, 0);       // shift origin up to upper-left corner.  
		  
		this->partyklez->draw();  
		  
		glFlush();  
		  
		glViewport(0, 0, ofGetWidth(), ofGetHeight());  
		ofSetupScreen();  
	}  
}  
  

Well, I know it’s probably a bit tricky for anyone to actually test… but if anyone knows much about openGL viewports and matrices and can see something I’m missing, that would be awesome!!

Thanks in advance!

opengl thinks 0,0 is the bottom left, not top left corner. this means any opengl commands that take world coordinates needs to be adjusted.

this is off the top of my head, but something like:

(x,ofGetHeight()-y-h,w,h)

instead of

(x,y,w,h)

might work better ?

hope that helps …

take care!
zach

ahh yeah, thanks!! That got the positioning right… now I’m just trying to get the glTranslatef() working correctly. At least now that the position is correct, it gives me a more solid starting point :slight_smile:

And also, was wondering if you had any pointers for the matrix setup stuff… besides copying and pasting it from ofGraphics.cpp::void ofSetupScreen()?

I will post a final version once I get it all working.

woohoo!! got it working now! Thanks again for the help zach!

Here is the working version of my code… You should be able to adapt this for anything that implements the draw(float x, float y, float w, float h); method… just replace the this->partyklez references with whatever you’re drawing :slight_smile:

  
  
void PartyklezWindow::draw(float x, float y, float w, float h){  
	if(this->partyklez != NULL){  
		glViewport(x, ofGetHeight()-y-h, w-1, h-1);  
		  
		// all the matrix setup is copied from the ofGraphics.cpp::void ofSetupScreen() method.  
		float halfFov, theTan, screenFov, aspect;  
		screenFov 		= 60.0f;  
		float eyeX 		= (float)w / 2.0;  
		float eyeY 		= (float)h / 2.0;  
		halfFov 		= PI * screenFov / 360.0;  
		theTan 			= tanf(halfFov);  
		float dist 		= eyeY / theTan;  
		float nearDist 	= dist / 10.0;	// near / far clip plane  
		float farDist 	= dist * 10.0;  
		aspect 			= (float)w/(float)h;  
		  
		glMatrixMode(GL_PROJECTION);  
		glLoadIdentity();  
		gluPerspective(screenFov, aspect, nearDist, farDist);  
		  
		glMatrixMode(GL_MODELVIEW);  
		glLoadIdentity();  
		gluLookAt(eyeX, eyeY, dist, eyeX, eyeY, 0.0, 0.0, 1.0, 0.0);  
		  
		glClear(GL_DEPTH_BUFFER_BIT);  
				  
		glScalef(1, -1, 1);           // invert Y axis so increasing Y goes down.  
		glTranslatef(-x, -y-h, 0);       // shift origin up to upper-left corner.  
		  
		// draw the particle system  
		this->partyklez->draw();  
		  
		// reset viewport back to main screen  
		glFlush();  
		glViewport(0, 0, ofGetWidth(), ofGetHeight());  
		ofSetupScreen();  
	}  
}  
  

I was thinking it might be cool to include this type of sub-viewport setup in the OF core or something… Or maybe I will see about making a little ofxViewports add-on… but I’d still have a bit of concern about copying the matrix setup values from the core function (in case the core changes or something)…

1 Like

Thanks so much for posting this code snippet. It helped me a great deal.

stephan.