Problem with glScissors

Started by
20 comments, last by mldaalder 18 years, 4 months ago
The height correction looks right. I'd bet its GLint nYtoUse = viewport[3] - nY - nH; thats doing it. Maybe try GLint nYtoUse = viewport[3] - nY;
Advertisement
It's not that.

Free Image Hosting at www.ImageShack.us
What are your x and y coordinates relative to? And your widths and heights?

You know, this is going to turn out to be really obvious with hindersight, I can just tell...
Quote:Original post by Bezben
What are your x and y coordinates relative to? And your widths and heights?

The red square is 0.1:0.1 to the upper left corner of the window.
The green square is 0.1:0.1 to the upper left corner of the red square.
The blue square is -0.1:-0.1 to the upper left corner of the green square.

Widths and heights are relative to the x and y coordinates of the node.

I think I may have found something, if I disable translations, then it, sort of, renders correctly, scissor space wise.

Free Image Hosting at www.ImageShack.us

On second thought, it may even be wrong as well...

Quote:You know, this is going to turn out to be really obvious with hindersight, I can just tell...

If there is anything as sure as 1+1=2, then your statement would be it.

If thats the case then it might be the fact that you are scaling by the size of the viewport could well be the problem, you need to scale by the current scissor rect width instead.
Quote:Original post by Bezben
If thats the case then it might be the fact that you are scaling by the size of the viewport could well be the problem, you need to scale by the current scissor rect width instead.

I don't think that it would be the sollution, that would scale the UI to the scissor rect, instead of the viewport.

After a quick test, it isn't.

Strangly (to my idea anyway) it works for the green rectangle, but not the blue one. It is now too small and it now pops out on the left.


Now, please bear with me.

Before I took into account that glScissors was based from the lower left corner, the size is correct, just the position that was wrong (nY was wrong).

I don't suppose it could be something to do that nH could be wrong as well?
I don't think so, but I'm starting to think all of the possible reasons, how unlikly they might be.
Right now I'd bet that is the issue. Work them out on paper. Make sure they match watch actually is there.

You definitely can't just scale by the view port if you are mapping a windows coordinates to a fixed range. I think you need to scale by the viewport for the first window, then scale by the width of that window in pixels for its children... I'd have thought that would be the previous scissor rect width though. The problem though would be when you have sibling child windows, because you'll have the previous siblings scissor rect set, not the parents. I get around this with a clipper stack. You might be able to do it with clever use of the glScissor calls...

void GUINode::Render(){  // Render the component, doing it this way ensures us that the end user won't "forget" to do certain things  this->RenderComponent();  // Retrieve viewport and scissor size  GLint* viewport = new GLint[4];  GLint* scissor  = new GLint[4];  glGetIntegerv(GL_VIEWPORT, viewport);  glGetIntegerv(GL_SCISSOR_BOX, scissor);  // Calculate new scissor size (if it would be the root node)  GLint nX,nY,nW,nH;  nX = (GLint)(scalar(viewport[2])*x)+scissor[0];  nY = (GLint)(scalar(viewport[3])*y);//+scissor[1];// The +scissor[1] isn't making any diffrence?  nW = (GLint)(scalar(viewport[2])*w);  nH = (GLint)(scalar(viewport[3])*h);  GLint nYtoUse = viewport[3] - nY - nH;  //std::cout<<nYtoUse<<":"<<scissor[1]<<std::endl;  //std::cout<<nH<<":"<<scissor[3]<<std::endl;  /*std::cout<<"Requested:"<<nX<<":"<<nY<<":"<<nW<<":"<<nH<<std::endl;  std::cout<<"Got:      "<<(scissor[0] > nX ? scissor[0] : nX)<<":"<<                           (scissor[1] > nY ? scissor[1] : nY)<<":"<<                           (scissor[2] < nW ? scissor[2] : nW)<<":"<<                           (scissor[3] < nH ? scissor[3] : nH)<<std::endl;*/  // Make the scissor size always smaller  /* This means that the X and Y values can only get bigger   * And that the W and H values can only get smaller*/  // Go through the child nodes and render them into the visible space of this node// I don't actually know what BOOST_FOREACH does, but you'll get the idea...  BOOST_FOREACH(boost::shared_ptr<GUINode>& node, children){  // Draw current GUI  glTranslated(x,y,0);  glScissor((scissor[0] > nX ? scissor[0] : nX),            (scissor[1] > nYtoUse ? scissor[1] : nYtoUse),//nY),            (scissor[2] < nW ? scissor[2] : nW),            (scissor[3] < nH ? scissor[3] : nH));    node->Render();  glTranslated(-x,-y,0);  // Reset scissor for the siblings  glScissor(scissor[0],scissor[1],            scissor[2],scissor[3]);}//end the for each here  // Reset translation for the siblings  delete[] viewport;  delete[] scissor;}
I believe the actual calculations you want are (assuming top left coordinate system, otherwise change the names appropriately):
GLint newLeft = (viewport[2] * x) + scissor[0];GLint newTop = (viewport[3] * y) + scissor[1];GLint newRight = left + (viewport[2] * w);GLint newBottom = top + (viewport[3] * h);GLint oldLeft = scissor[0];GLint oldTop = scissor[1];GLint oldRight = scissor[0] + scissor[2];GLint oldBottom = scissor[1] + scissor[3];GLint clippedLeft = std::max(newLeft, oldLeft);GLint clippedTop = std::max(newTop, oldTop);GLint clippedRight = std::min(newRight, oldRight);GLint clippedLeft = std::min(newBottom, oldBottom);glScissor(clippedLeft, clippedTop, clippedRight - clippedLeft, clippedBottom - clippedTop);

Obviously you could also achieve the end result by following your current approach, but the above is (in my opinion) much clearer (and would be even more so if new, old and clipped were encapsulated in a bounds or rectangle class). And please drop the new GLint[4]s and just use stack arrays. There's really no need to invoke dynamic memory allocation and needlessly fragment your heap and add extra exception paths to your code.

Enigma
I think my current code supports siblings correctly.

It's the
glScissor(scissor[0],scissor[1], scissor[2],scissor[3]);
part at the end of the Render function that should garuantee for this.

Basicly, each node ensures that it the scissor and translations get restored at the end of it's rendering function.


I've tried to work it out several times, but I can't seem to get it right...
Must be my brains shutting down after trying to design a system for school which by it's very definition and idea on how it should work resists all logic.:P

I got this:
0x0x800x600red:0.1x0.1x0.5x0.580x60x400x30080x60x400x300green:0.1x0.1x0.5x0.580x60x400x300160x120x400x300blue:-0.15x-0.15x0.5x0.5-120x-90x400x300160x120x400x300

An explanation, the first line of each node is the floating point notation.
The second one are the resulting values for the offset to point 0x0 (or the parents offset point).
The third line is the result of the "stack".

Something else that I've just tried, I tried outputting the result of this part:
  // Make the scissor size always smaller  /* This means that the X and Y values can only get bigger   * And that the W and H values can only get smaller*/  glScissor((scissor[0] > nX ? scissor[0] : nX),            (scissor[1] > nYtoUse ? scissor[1] : nYtoUse),            (scissor[2] < nW ? scissor[2] : nW),            (scissor[3] < nH ? scissor[3] : nH));


The result was:
scissor1:80:240:400:300scissor2:1:0:800:600scissor1:160:240:400:300scissor2:1:240:400:300scissor1:160:240:400:300scissor2:1:240:400:300 

Which would suggest an error in my logic.


Or a flaw in my programming, since the line which outputs the scissor1 part is:
std::cout<<"scissor1:"<<(scissor[0] > nX ? scissor[0] : nX)<<":"<<                             (scissor[1] > nYtoUse ? scissor[1] : nYtoUse)<<":"<<                             (scissor[2] < nW ? scissor[2] : nW)<<":"<<                             (scissor[3] < nH ? scissor[3] : nH)<<std::endl;
Sorry for the double post, but it took me some time to type out my previous post (hence I didn't see Enigma's post).


Thanks for your help, it also explains why it would be better to use stack arrays.
I hadn't thought of the heap as of yet.

I'll edit this post ounce I get a result.


[EDIT]
Here is my current situation:
Free Image Hosting at www.ImageShack.us

I think it is an improvement, because now the problem is consistent.^_^

This is the code I'm currently using:
void GUINode::Render(){  if(!visible)    return;  glTranslated(x,y,0);  this->RenderComponent();  GLint viewport[4];  GLint scissor[4];  glGetIntegerv(GL_VIEWPORT, viewport);  glGetIntegerv(GL_SCISSOR_BOX, scissor);  GLint newLeft = GLint(scalar(viewport[2]) * x) + scissor[0];  GLint newTop = GLint(scalar(viewport[3]) * y) + scissor[1];  GLint newRight = newLeft + GLint(scalar(viewport[2]) * w);  GLint newBottom = newTop + GLint(scalar(viewport[3]) * h);  GLint oldLeft = scissor[0];  GLint oldTop = scissor[1];  GLint oldRight = scissor[0] + scissor[2];  GLint oldBottom = scissor[1] + scissor[3];  GLint clippedLeft = std::max(newLeft, oldLeft);  GLint clippedTop = std::max(newTop, oldTop);  GLint clippedRight = std::min(newRight, oldRight);  GLint clippedBottom = std::min(newBottom, oldBottom);  glScissor(clippedLeft, clippedTop, clippedRight - clippedLeft, clippedBottom - clippedTop);  // Go through the child nodes and render them into the visible space of this node  BOOST_FOREACH(boost::shared_ptr<GUINode>& node, children)    node->Render();  // Reset translation for the siblings  glTranslated(-x,-y,0);  // Reset scissor for the siblings  glScissor(scissor[0],scissor[1],            scissor[2],scissor[3]);}



[Edited by - mldaalder on December 15, 2005 5:22:38 PM]

This topic is closed to new replies.

Advertisement