[SOLVED] Alpha value not working correctly

Hey, so I’m rendering images onto the screen pixel-by-pixel. I created a BufferedImage with the width and height of the screen with type INT_ARGB in which its pixels are modified when I render something. When loading the sprites, I take the pixel data from the full sprite sheet and place it inside a new BufferedImage again with a type of INT_ARGB, as the original sprite sheet is of type 3BYTE_BGR. Not sure if it even matters since I then take the pixel data from the new BufferedImage, but it seems to have no effect. After taking the pixel data from the new BufferedImage, I change each color to a number between 0 and 3, for a total of four different colors being used in each sprite. I then take the corresponding pixel data for each sprite from the full pixel array of the whole sprite sheet and place it inside a HashMap with an Integer as a key. When rendering a sprite, I use its tile number to find it and take the pixel data from it, replacing each number (0-3) with that of the corresponding color inside an int[] array. The int[] array contains four colors, each of which have an alpha, red, green, and blue value. The issue is that when I specify a certain transparency, it doesn’t do anything, and when setting the transparency to 1, it does some strange fade effect when it starts up.

Here’s all the relevant code:

The SpriteSheet class, where I load all the sprites.


import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;

public class SpriteSheet {
   
   public int w, h;
   
   private Map<Integer, byte[]> sprites = new HashMap<Integer, byte[]>();
   
   public SpriteSheet(BufferedImage image) {
      if(image.getType() != BufferedImage.TYPE_INT_ARGB) System.out.println("[1] Not ARGB, " + image.getType()); // TYPE_3BYTE_BGR
      w = image.getWidth();
      h = image.getHeight();
      
      BufferedImage newImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
      
      int[] oldPixels = image.getRGB(0, 0, w, h, null, 0, w); // Not sure if these two lines are needed.
      newImg.setRGB(0, 0, w, h, oldPixels, 0, w);
      
      int[] pixels = newImg.getRGB(0, 0, w, h, null, 0, w);
      int tiles = (w * h) / 64;
      
      for(int i = 0; i < pixels.length; i++) {
         pixels[i] = (pixels[i] & 0xff) / 64;
      }
      
      byte[] sprite;
      for(int i = 0; i < tiles; i++) {
         sprite = new byte[64];
         int xTile = i % 8;
         int yTile = i / 8;
         int toffs = xTile * 8 + yTile * 8 * w;
         
         for(int y = 0; y < 8; y++) {
            for(int x = 0; x < 8; x++) {
               sprite[x + y * 8] = (byte) pixels[x + y * w + toffs];
            }
         }
         
         sprites.put(i, sprite);
      }
   }
   
   public byte[] getSprite(int tile) {
      if(tile > (w / 8) * (h / 8) - 1) return sprites.get(0);
      return sprites.get(tile);
   }
}

My render method, in my Game class.


int[] cols = {Color.getColor(0, 255, 0, 0)/*Should be 100% translucent, but instead it's an almost-white color*/, Color.getColor(255, 0, 255, 0), Color.getColor(255, 0, 0, 255), Color.getColor(255, 0, 0, 0)};
	private void render() {
		screen.clear(Color.getColor(100, 0, 0, 0)); // The screen should have a slightly translucent, black background, but instead it's solid black.
		screen.render(25, 25, 0, cols, 0);
		
		bs.getDrawGraphics().drawImage(image, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null); // image is "TYPE_INT_ARGB"
		bs.getDrawGraphics().dispose();
		
		Toolkit.getDefaultToolkit().sync();
		bs.show();
		
		fps++;
	}

The getColor() method in my Color class.


public static int getColor(int a, int r, int g, int b) {
		return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);
	}

And the render method in my Screen class. The code is partly borrowed from Minicraft, though it doesn’t shift any bits here.


int yy, xx;
	boolean mirrorX, mirrorY;
	public void render(int xp, int yp, int tile, int[] cols, int bits) {
		mirrorX = (bits & 0x01) > 0;
		mirrorY = (bits & 0x02) > 0;
		
		for(int y = 0; y < 8; y++) {
			yy = y;
			if(mirrorY) yy = 7 - y;
			if (y + yp < 0 || y + yp >= h) continue;
			for(int x = 0; x < 8; x++) {
				if (x + xp < 0 || x + xp >= w) continue;
				xx = x;
				if(mirrorX) xx = 7 - x;
				
				int col = cols[sheet.getSprite(tile)[xx + yy * 8]];
				pixels[(x + xp) + (y + yp) * w] = col;
			}
		}
	}

Here are some images showing what the error is:


This is what happens when I set the background color to black with an alpha value of 1. It fades from completely translucent to a slightly translucent black when it starts up.

Any help would be greatly appreciated. I tried everything and can’t figure out why the alpha value isn’t working right. ???


	public void paint(Graphics g) {
		super.paint(g);
		final Graphics2D g2d = (Graphics2D) g;
		/* Grab your original Composite */
		Composite originalComposite = g2d.getComposite();
		float alpha = 0.1F;
		/* Set your Transparency */
		g2d.setComposite(makeComposite(alpha));
		/* Draw Transparent stuff here =D */
		g2d.setColor(Color.white);
		g2d.fillRect(0, 0, 100, 100);
		/* Restore back to Original Composite */
		g2d.setComposite(originalComposite);
	}

Methods needed:


	public AlphaComposite makeComposite(float transparency) {
		return  AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transparency);
	}

Imports needed:


import java.awt.Composite;
import java.awt.AlphaComposite;

Or for your BufferedImage >> http://www.java-gaming.org/topics/transparancy-fairly-simple/25711/msg/222543/view.html#msg222543
Hope it helps
http://user-generated-content.java-gaming.org/img-vault/63357042043e0532d9c9a4396c95f3b49c066031de9913084e94ee850cf7605d.gif

I tried to use the method for the BufferedImage in the thread you linked, but it doesn’t seem to do… anything, strangely. Though it appears that it just completely removes a certain color; what I’m trying to do is modify the alpha value so I can set it to anything between 0 and 255. Your other method using a Graphics object and the paint method won’t work either, as I user neither the paint() method or any Graphics objects in this game. :frowning:

Basically, this HashMap: private Map<Integer, byte[]> sprites = new HashMap<Integer, byte[]>(); contains the pixel data for each sprite. Each pixel has a value of 0, 1, 2, or 3. When I render the sprite, I pass an int[] array containing four integers, each containing a color, as a parameter. Depending on the pixel data, it takes the corresponding color from the int[] array. So a pixel with a value of 0 would get the color in index 0 of the int[] array. A pixel value of 1 would get the color in index 1 of the int[] array, etc. The four colors in the int[] array come from my Color class, using the method I posted above. But something happens and the alpha value doesn’t work properly. Setting it to zero changes the color to an almost white color (the red, green, and blue values are all 238, and the alpha value is 255), and setting it to 1 causes the strange fade effect as seen in the GIF I posted. I’m not sure where the problem is or why it’s happening. :clue:

Not too familiar with BufferStrategy’s but, cant you just cast a Graphics Object down from your BufferStrategy?


        	// Something along these lines..
        	Graphics g = (Graphics) bs.getDrawGraphics();
        	Graphics2D g2d = (Graphics2D) g;

I could, but I’m not able to use a Graphics object with how I coded it. All rendering is basically modifying a pixel array which belongs to a BufferedImage in my Game class, and afterwards I draw the BufferedImage on the screen (lines six and seven of the render method in my Game class in my original post). And I don’t want the whole BufferedImage to be translucent, just parts of it. For example, lets say I have a sprite that looks like this:

When passed through my SpriteSheet class, the pixels in the black stripe would get converted to 0, in the darker gray stripe 1, the ligher gray stripe 2, and the white stripe 3. When I want to render it, the color in index 0 of the int[] array in the render method in my Screen class would be used to set all the pixels with a value of 0 in the sprite. Same goes for index 1, 2, and 3. Now lets say I want to remove the dark gray stripe. In this case, I would set the alpha value to 0 so it’s completely see-through. But it doesn’t work for some reason. :-\

(Just realized the solution while writing this post)
Turns out transparency wasn’t working because I was using only one BufferedImage, of which I modify the pixel data when I render something. This meant that if I render pixel A to be 50% transparent, any other pixels that were there would have been replaced with a half-transparent pixel, and since the previous pixels were replaced, they’re never shown, and it appeared as though nothing was transparent. I solved this by getting the pixel that was there before, and combining it with the one being drawn like so:


int col = cols[sheet.getSprite(tile)[xx + yy * 8]]; // The pixel about to be drawn
int pCol = pixels[(x + xp) + (y + yp) * w]; // The pixel already there
int alpha = (col >> 24) & 0xff; // The alpha value of the pixel about to be drawn
if(alpha < 255) col = (col | pCol); // If the alpha value is less than 255, combine them.

Thanks for all the help, even if I figured it out on my own. :smiley: