Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 32 additions & 21 deletions src/org/andengine/opengl/util/GLScissorStack.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,31 +85,42 @@ public void glPushScissor(final int pX, final int pY, final int pWidth, final in
height = pHeight;
} else {
/* Take the intersection between the current and the new scissor: */
final int currentX = this.mScissorStack[this.mScissorStackOffset - (GLSCISSOR_SIZE - GLSCISSOR_X_INDEX)];
final int currentY = this.mScissorStack[this.mScissorStackOffset - (GLSCISSOR_SIZE - GLSCISSOR_Y_INDEX)];
final int currentWidth = this.mScissorStack[this.mScissorStackOffset - (GLSCISSOR_SIZE - GLSCISSOR_WIDTH_INDEX)];
final int currentHeight = this.mScissorStack[this.mScissorStackOffset - (GLSCISSOR_SIZE - GLSCISSOR_HEIGHT_INDEX)];

final float xMin = Math.max(currentX, pX);
final float xMax = Math.min(currentX + currentWidth, pX + pWidth);

final float yMin = Math.max(currentY, pY);
final float yMax = Math.min(currentY + currentHeight, pY + pHeight);

x = (int) xMin;
y = (int) yMin;
width = (int) (xMax - xMin);
height = (int) (yMax - yMin);
final int currentX = this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_X_INDEX];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this get a value that's not set?

I.e. when the stack has been pushed once, this.mScissorStackOffset is at 4. Any value >= 4 is an uninitialized value, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it will be fine. Indeed, after glPushScissor is called once this.mScissorStackOffset equals 4, but this is where the scissor rectangle is stashed (indexes 4-7).

After each push this.mScissorStackOffset points to the values that were just stashed, instead to the empty space on stack. As a result, when we new value is pushed (i.e. in case of ClipEntity attached another ClipEntity) we're intersecting it with previously pushed rectangle (perfectly valid value)

Without these fixes code is pushing/popping like this: 123/321
It should be done like this: 123/21X (where X means no scissors)

Regular stack behaviour is of no use here.
After calling glPushScissor n-times and glPopScissor once we do not want to have n-th value, but (n-1)
After calling glPushScissor n-times and then glPopScissor n-times, we do not want to have the first value that was pushed. We want to have an infinite rectangle instead.

Just have a look at "detailed call stack" below. It will be a little bit more apparent.

glPushScissor rectangle A pushed; mScissorStackOffset is 4 after this method; no intersection done, A is saved at 4-7
glPushScissor rectangle B pushed; mScissorStackOffset is 8 after this method; proper intersection taken, B' is saved at 8-11
glPushScissor rectangle C pushed; mScissorStackOffset is 12 after this method; proper intersection taken, C' is saved at 12-15

glPopScissor rectangle B' is restored (it is read from 8-11); mScissorStackOffset is 8 after this method
glPopScissor rectangle A is restored (it is read from 4-7); mScissorStackOffset is 4 after this method
glPopScissor no scissor is used (it is read from 0-3); mScissorStackOffset is 0 after this method; this IS nasty since nothing was pushed at this position, and this value is uninitialized, but bear with me, please.

Right now It works fine, because glDisable will disable scissors anyway, so it does not matter what we read here. We might want to change behaviour to read something explicit, but I have no idea what should be considered as a default/empty/no_clip value for scissors. Maybe (-inf,-inf, inf, inf)? Or (0, 0, 0, 0)? I do not have any idea. If you'll come up with a good no_clip values they should be stored to the bottom (0-3) of the stack in the constructor- it does not matter for ClipEntity, however.

final int currentY = this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_Y_INDEX];
final int currentWidth = this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_WIDTH_INDEX];
final int currentHeight = this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_HEIGHT_INDEX];

final int xMin = Math.max(currentX, pX);
final int xMax = Math.min(currentX + currentWidth, pX + pWidth);

final int yMin = Math.max(currentY, pY);
final int yMax = Math.min(currentY + currentHeight, pY + pHeight);

if (xMax > xMin) {
x = xMin;
width = xMax - xMin;
} else {
x = pX;
width = 0;
}

if (yMax > yMin) {
y = yMin;
height = yMax - yMin;
} else {
y = pY;
height = 0;
}
}

this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_X_INDEX] = pX;
this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_Y_INDEX] = pY;
this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_WIDTH_INDEX] = pWidth;
this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_HEIGHT_INDEX] = pHeight;
this.mScissorStackOffset += GLScissorStack.GLSCISSOR_SIZE;

GLES20.glScissor(x, y, width, height);
this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_X_INDEX] = x;
this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_Y_INDEX] = y;
this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_WIDTH_INDEX] = width;
this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_HEIGHT_INDEX] = height;

this.mScissorStackOffset += GLScissorStack.GLSCISSOR_SIZE;
GLES20.glScissor(x, y, width, height);
}

public void glPopScissor() {
Expand Down