-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Open
Labels
Description
Description
Changing an offscreen graphics context's translation or scaling affects the main graphics context. This behaviour appears with P2D but not JAVA2D.
Expected Behavior
The main graphics window isn't scaled or translated.
Current Behavior
The main graphics window is improperly scaled or translated for P2D but behaves properly for JAVA2D.
Steps to Reproduce
The following code shows different scaling and translation with P2D vs. JAVA2D renderers. The comments at the top show different things to try. The first thing I'd suggest is to change the renderer to JAVA2D to see the difference.
// This sketch illustrates how P2D somehow lets the scaling of a child graphics
// object affect the main display. The JAVA2D renderer works as expected.
//
// Comment out this line to see the effect without the overlay:
// overlay(sketchG, 0.4f);
// You'll notice that the scaling and translation of the "main" line is
// different. The overlay shouldn't affect the main graphic drawn to sketchG.
//
// Also try commenting out the following line without commenting out the above
// overlay draw line:
// pg.blend(overlayG, 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height, BLEND);
// You'll notice that just changing the scaling and translation of the child
// graphics object, without actually drawing anything to sketchG, affects the
// main scaling.
static final int WHITE = 0xffffffff;
static final int LIGHT_BACKGROUND = 0xffffcccc;
static final int RED = 0xffff0000;
static final int BLACK = 0xff000000;
/** Sketch-specific graphics. */
PGraphics sketchG;
/** Overlay graphics. */
PGraphics overlayG;
/** Logo aspect ratio. */
float aspectRatio = 23.0f / 12.0f;
void settings() {
size(300, 180, P2D); // <-- JAVA2D works normally
}
void setup() {
sketchG = createGraphics(30, 18, sketchRenderer());
sketchG.smooth();
overlayG = createGraphics(sketchG.width, sketchG.height, sketchRenderer());
overlayG.smooth();
}
void draw() {
// Draw the sketch onto an offscreen buffer
sketchG.beginDraw();
sketchG.background(WHITE);
sketchG.stroke(BLACK);
sketchG.strokeWeight(sketchG.width/2);
sketchG.line(0, 0, 0, sketchG.height/2);
overlay(sketchG, 0.4f); // <-- comment this line to see the "normal" sketch without the overlay
sketchG.endDraw();
// Don't really need the 'copy' and 'filter' here, but I'm going to include
// them because it's part of a larger system, and I want things to match as
// best I can to the bug
PImage src = sketchG.copy();
src.filter(OPAQUE);
copy(src, 0, 0, src.width, src.height, 0, 0, width, height);
}
/**
* Draws a graphic overlay.
*
* @param pg the graphics object
* @param alpha an alpha value for the overlay
*/
protected void overlay(PGraphics pg, float alpha) {
if (alpha <= 0.0f || 1.0f < alpha) {
return;
}
overlayG.beginDraw();
overlayG.background(LIGHT_BACKGROUND);
float scale = pg.width / aspectRatio;
overlayG.translate(0, (pg.height - scale) / 2); // Center the overlay
overlayG.scale(scale);
drawLogo(overlayG);
int a = (int) (alpha * 255) << 24;
overlayG.loadPixels();
// For some reason, filling a rectangle with an alpha-valued white does
// not blend, so we need to go pixel-by-pixel
// --> Why is this? <--
for (int i = overlayG.pixels.length; --i >= 0; ) {
int c = overlayG.pixels[i];
overlayG.pixels[i] = a | (c & 0x00ffffff);
}
overlayG.updatePixels();
overlayG.endDraw();
// Comment the following to see that even if we don't draw the image,
// the scaling is still messed up
pg.blend(overlayG, 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height, BLEND);
// Uncomment the following for a "plain" flash to see differences
// (And comment the above code)
//pg.pushStyle();
//pg.noStroke();
//pg.fill(((int) (alpha * 255) << 24) | 0x00ffffff);
//pg.rectMode(CORNER);
//pg.rect(0, 0, width, height);
//pg.popStyle();
}
/**
* Draws some logo. It is assumed that the position and scale are already
* set up. Note that to get a line thickness of 1.0, the strokeWeight must
* be scaled to the inverse of the coordinate system scale.
* <p>
* At the end of this method, the graphics will have its blend mode set to
* BLEND.
*/
void drawLogo(PGraphics pg) {
pg.pushStyle();
pg.ellipseMode(CORNER);
pg.noStroke();
pg.fill(RED);
pg.ellipse(0, 0, aspectRatio, 1.0f);
pg.popStyle();
// The follwing line isn't needed, but it's closer to the "real" code,
// so I'll leave it in
pg.blendMode(BLEND);
}Your Environment
- Processing version: 3.4
- Operating System and OS version: OSX 10.14.2
- Other information:
Possible Causes / Solutions
Perhaps there's some OpenGL state somewhere that needs to be reverted properly when setting transformations on an offscreen P2D graphics context?