Merge pull request #2157 from SiboVG/issue-2076

[#2076] Support transparent rendering and exporting of PS images
This commit is contained in:
Sibo Van Gool 2023-04-01 09:44:14 +02:00 committed by GitHub
commit 57c3522f6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 9 deletions

View File

@ -2334,6 +2334,7 @@ PhotoSettingsConfig.lbl.lightAz = Light Azimuth
PhotoSettingsConfig.lbl.lightAlt = Light Altitude
PhotoSettingsConfig.lbl.sky = Sky
PhotoSettingsConfig.lbl.skyColor = Sky Color
PhotoSettingsConfig.lbl.skyColorOpacity = Sky Color Opacity
PhotoSettingsConfig.lbl.skyImage = Sky Image
PhotoSettingsConfig.lbl.skyCredit = Image Credit

View File

@ -156,6 +156,7 @@ public class PhotoPanel extends JPanel implements GLEventListener {
final GLProfile glp = GLProfile.get(GLProfile.GL2);
final GLCapabilities caps = new GLCapabilities(glp);
caps.setBackgroundOpaque(false);
if (Application.getPreferences().getBoolean(
Preferences.OPENGL_ENABLE_AA, true)) {
@ -169,10 +170,12 @@ public class PhotoPanel extends JPanel implements GLEventListener {
Preferences.OPENGL_USE_FBO, false)) {
log.trace("GL - Creating GLJPanel");
canvas = new GLJPanel(caps);
((GLJPanel) canvas).setOpaque(false);
} else {
log.trace("GL - Creating GLCanvas");
canvas = new GLCanvas(caps);
}
canvas.setBackground(new java.awt.Color(0, 0, 0, 0));
((GLAutoDrawable) canvas).addGLEventListener(this);
this.add(canvas, BorderLayout.CENTER);
@ -277,7 +280,7 @@ public class PhotoPanel extends JPanel implements GLEventListener {
if (!imageCallbacks.isEmpty()) {
BufferedImage i = (new AWTGLReadBufferUtil(
GLProfile.get(GLProfile.GL2), false))
GLProfile.get(GLProfile.GL2), true)) // Set the second parameter to true
.readPixelsToBufferedImage(drawable.getGL(), 0, 0,
drawable.getSurfaceWidth(), drawable.getSurfaceHeight(), true);
final Vector<ImageCallback> cbs = new Vector<PhotoPanel.ImageCallback>(
@ -298,18 +301,41 @@ public class PhotoPanel extends JPanel implements GLEventListener {
out[0] = 1;
out[1] = 1;
out[2] = 0;
out[3] = 1;
} else {
out[0] = (float) color.getRed() / 255f;
out[1] = (float) color.getGreen() / 255f;
out[2] = (float) color.getBlue() / 255f;
out[3] = (float) color.getAlpha() / 255f;
}
}
/**
* Blend two colors
* @param color1 first color to blend
* @param color2 second color to blend
* @param ratio blend ratio. 0 = full color 1, 0.5 = mid-blend, 1 = full color 2
* @return blended color
*/
private static Color blendColors(Color color1, Color color2, double ratio) {
if (ratio < 0 || ratio > 1) {
throw new IllegalArgumentException("Blend ratio must be between 0 and 1");
}
double inverseRatio = 1 - ratio;
int r = (int) ((color1.getRed() * inverseRatio) + (color2.getRed() * ratio));
int g = (int) ((color1.getGreen() * inverseRatio) + (color2.getGreen() * ratio));
int b = (int) ((color1.getBlue() * inverseRatio) + (color2.getBlue() * ratio));
return new Color(r, g, b);
}
private void draw(final GLAutoDrawable drawable, float dx) {
GL2 gl = drawable.getGL().getGL2();
GLU glu = new GLU();
float[] color = new float[3];
float[] color = new float[4];
gl.glEnable(GL.GL_MULTISAMPLE);
@ -333,8 +359,16 @@ public class PhotoPanel extends JPanel implements GLEventListener {
new float[] { spc * color[0], spc * color[1], spc * color[2], 1 },
0);
convertColor(p.getSkyColor(), color);
gl.glClearColor(color[0], color[1], color[2], 1);
// Machines that don't use off-screen rendering can't render transparent background, so we create it
// artificially by blending the sky color with white (= color that is rendered as transparent background)
if (!Application.getPreferences().getBoolean(
Preferences.OPENGL_USE_FBO, false)) {
convertColor(blendColors(p.getSkyColor(), new Color(255, 255, 255), 1-p.getSkyColorOpacity()),
color);
} else {
convertColor(p.getSkyColor(), color);
}
gl.glClearColor(color[0], color[1], color[2], color[3]);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);

View File

@ -24,6 +24,7 @@ public class PhotoSettings extends AbstractChangeSource implements FlameSettings
private double ambiance = .3f;
private Color skyColor = new Color(55, 95, 155);
private double skyColorOpacity = 1.0;
private boolean motionBlurred = false;
@ -186,9 +187,20 @@ public class PhotoSettings extends AbstractChangeSource implements FlameSettings
public void setSkyColor(Color skyColor) {
this.skyColor = skyColor;
this.skyColorOpacity = skyColor.getAlpha() / 255f;
fireChangeEvent();
}
public double getSkyColorOpacity() {
return skyColorOpacity;
}
public void setSkyColorOpacity(double skyColorOpacity) {
this.skyColorOpacity = skyColorOpacity;
skyColor.setAlpha((int) (skyColorOpacity * 255));
fireChangeEvent();
}
public Color getFlameColor() {
return flameColor;
}

View File

@ -256,10 +256,10 @@ public class PhotoSettingsConfig extends JTabbedPane {
/// Light altitude
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.lightAlt")));
DoubleModel lightAltModle = new DoubleModel(p, "LightAlt", UnitGroup.UNITS_ANGLE, -Math.PI / 2, Math.PI / 2);
add(new EditableSpinner(lightAltModle.getSpinnerModel()), "growx, split 2");
add(new UnitSelector(lightAltModle));
add(new BasicSlider(lightAltModle.getSliderModel(-Math.PI / 2, Math.PI / 2)), "wrap");
DoubleModel lightAltModel = new DoubleModel(p, "LightAlt", UnitGroup.UNITS_ANGLE, -Math.PI / 2, Math.PI / 2);
add(new EditableSpinner(lightAltModel.getSpinnerModel()), "growx, split 2");
add(new UnitSelector(lightAltModel));
add(new BasicSlider(lightAltModel.getSliderModel(-Math.PI / 2, Math.PI / 2)), "wrap");
// Sky
add(new StyledLabel(trans.get("PhotoSettingsConfig.lbl.sky"), Style.BOLD), "split, span, gapright para");
@ -269,6 +269,17 @@ public class PhotoSettingsConfig extends JTabbedPane {
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.skyColor")));
add(skyColorButton, "wrap");
/// Sky color opacity
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.skyColorOpacity")));
DoubleModel skyColorOpacityModel = new DoubleModel(p, "SkyColorOpacity", UnitGroup.UNITS_RELATIVE, 0, 1);
EditableSpinner skyColorOpacitySpinner = new EditableSpinner(skyColorOpacityModel.getSpinnerModel());
add(skyColorOpacitySpinner, "growx, split 2");
UnitSelector skyColorOpacityUnitSelector = new UnitSelector(skyColorOpacityModel);
add(skyColorOpacityUnitSelector);
BasicSlider skyColorOpacitySlider = new BasicSlider(skyColorOpacityModel.getSliderModel());
add(skyColorOpacitySlider, "wrap");
p.addChangeListener(skyColorOpacityModel);
/// Sky image
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.skyImage")));
@ -293,9 +304,15 @@ public class PhotoSettingsConfig extends JTabbedPane {
if (s instanceof Sky && s != noSky) {
p.setSky((Sky) s);
skyColorButton.setEnabled(false);
skyColorOpacitySpinner.setEnabled(false);
skyColorOpacityUnitSelector.setEnabled(false);
skyColorOpacitySlider.setEnabled(false);
} else if (s == noSky) {
p.setSky(null);
skyColorButton.setEnabled(true);
skyColorOpacitySpinner.setEnabled(true);
skyColorOpacityUnitSelector.setEnabled(true);
skyColorOpacitySlider.setEnabled(true);
}
}
});