Hi folks,
I have a big problem with textures, alpha-channel and the blend function. If I use simple GL_QUADS with the same color as the background, different alpha values for the box should result in the same color (and “invisibility” of the box). That’s fine, but if I now use textures with an alpha channel, the behaviour is odd.
I use gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA) and gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE) to replace the color of the rectangle with an texture created from an BufferedImage with type BufferedImage.TYPE_INT_ARGB. But only for an alpha value of 0.0 and 1.0 the result is correct. As you can see in the attached image, you can see three of five rectangles, where you shouldn’t none of them.
What makes me believe that this is a bug, is the fact, that a quick implementation with C++ works as expected (both with and without texturing). Does anyone has a clue, where the problem could be?
Also strange is, that the texturing of the small demo program is broken on a third windows machine.
import java.awt.Color;
import java.awt.image.BufferedImage;
import javax.media.opengl.DebugGL;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;
import com.sun.opengl.util.FPSAnimator;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureIO;
public class TextureTest implements GLEventListener {
private JFrame m_frame;
private int m_height = 128;
private int m_width = 128;
private Texture m_t1, m_t2, m_t3, m_t4, m_t5;
private int m_list1, m_list2, m_list3, m_list4, m_list5;
private boolean m_useTexture = !true;
TextureTest() {
m_frame = new JFrame("TextureTest");
m_frame.setSize(800, 600);
m_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GLCapabilities glCaps = new GLCapabilities();
glCaps.setRedBits(8);
glCaps.setBlueBits(8);
glCaps.setGreenBits(8);
glCaps.setAlphaBits(8);
glCaps.setStencilBits(8);
glCaps.setDoubleBuffered(true);
GLCanvas canvas = new GLCanvas(glCaps);
canvas.addGLEventListener(this);
m_frame.add(canvas);
m_frame.setVisible(true);
m_height = canvas.getHeight();
m_width = canvas.getWidth();
FPSAnimator animator = new FPSAnimator(canvas, 30);
animator.setRunAsFastAsPossible(false);
animator.start();
}
public void display(GLAutoDrawable _drawable) {
GL gl = _drawable.getGL();
gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
if (m_useTexture) {
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(GL.GL_BLEND);
gl.glEnable(GL.GL_TEXTURE_2D);
}
gl.glTranslatef(-0.8f, 0.0f, 0.0f);
gl.glCallList(m_list1);
gl.glLoadIdentity();
gl.glTranslatef(-0.4f, 0.0f, 0.0f);
gl.glCallList(m_list2);
gl.glLoadIdentity();
gl.glCallList(m_list3);
gl.glTranslatef(0.4f, 0.0f, 0.0f);
gl.glCallList(m_list4);
gl.glLoadIdentity();
gl.glTranslatef(0.8f, 0.0f, 0.0f);
gl.glCallList(m_list5);
gl.glLoadIdentity();
if (m_useTexture) {
gl.glDisable(GL.GL_TEXTURE_2D);
gl.glDisable(GL.GL_BLEND);
}
}
public void displayChanged(GLAutoDrawable _drawable, boolean _modeChanged, boolean _deviceChanged) {}
public void init(GLAutoDrawable _drawable) {
_drawable.setGL(new DebugGL(_drawable.getGL()));
System.out.println("Chosen GL capabilities: " + _drawable.getChosenGLCapabilities());
System.out.println("GL_VENDOR: " + _drawable.getGL().glGetString(GL.GL_VENDOR));
System.out.println("GL_RENDERER: " + _drawable.getGL().glGetString(GL.GL_RENDERER));
System.out.println("GL_VERSION: " + _drawable.getGL().glGetString(GL.GL_VERSION));
GL gl = _drawable.getGL();
// create textures
m_t1 = createTexture(gl, m_width, m_height, 0.5f, 0.0f);
m_t2 = createTexture(gl, m_width, m_height, 0.5f, 0.25f);
m_t3 = createTexture(gl, m_width, m_height, 0.5f, 0.5f);
m_t4 = createTexture(gl, m_width, m_height, 0.5f, 0.75f);
m_t5 = createTexture(gl, m_width, m_height, 0.5f, 1.0f);
m_list1 = createTexturedBox(gl, 0.4, 0.4, 0.5f, 0.0f, m_t1);
m_list2 = createTexturedBox(gl, 0.4, 0.4, 0.5f, 0.25f, m_t2);
m_list3 = createTexturedBox(gl, 0.4, 0.4, 0.5f, 0.5f, m_t3);
m_list4 = createTexturedBox(gl, 0.4, 0.4, 0.5f, 0.75f, m_t4);
m_list5 = createTexturedBox(gl, 0.4, 0.4, 0.5f, 1.0f, m_t5);
}
public void reshape(GLAutoDrawable _drawable, int _x, int _y, int _width, int _height) {
GL gl = _drawable.getGL();
double h = (double)_width / (double)_height;
double viewWidth = 2 * h;
double viewLeft = -(viewWidth / 2.0);
double viewRight = viewWidth / 2.0;
gl.glViewport(0, 0, _width, _height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
GLU glu = new GLU();
glu.gluOrtho2D(viewLeft, viewRight, -1.0, 1.0);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
}
private Texture createTexture(GL _gl, int _width, int _height, float _intensity, float _alpha) {
Color color = new Color(_intensity, _intensity, _intensity, _alpha);
BufferedImage image = new BufferedImage(_width, _height, BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < _width; x++) {
for (int y = 0; y < _height; y++) {
image.setRGB(x, y, color.getRGB());
}
}
Texture tmpTexture = TextureIO.newTexture(image, false);
tmpTexture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
tmpTexture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
return tmpTexture;
}
private int createTexturedBox(GL _gl, double _width, double _height, float _intensity, float _alpha, Texture _texture) {
int list = _gl.glGenLists(1);
_gl.glNewList(list, GL.GL_COMPILE);
_texture.bind();
_gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
_gl.glColor4f(_intensity, _intensity, _intensity, _alpha);
_gl.glBegin(GL.GL_QUADS);
_gl.glTexCoord2d(0.0, 0.0);
_gl.glVertex2d(-_width/2.0, -_height/2.0);
_gl.glTexCoord2d(0.0, 1.0);
_gl.glVertex2d(-_width/2.0, _height/2.0);
_gl.glTexCoord2d(1.0, 1.0);
_gl.glVertex2d(_width/2.0, _height/2.0);
_gl.glTexCoord2d(1.0, 0.0);
_gl.glVertex2d(_width/2.0, -_height/2.0);
_gl.glEnd();
_gl.glEndList();
return list;
}
public static void main(String[] unused) {
new TextureTest();
}
}