In Android, I'm attempting to layer two images (In this case, Bitmap objects) in a FrameLayout. One image is placed on top, with the other image inserted below it at that image's first transparent pixel.
Currently, I'm attempting the following using Bitmap.getPixel() to locate the transparent pixel:
for (int i = 0; i < image_count; i++)
{
//load page from internal memory
topImages[i] = getImage("p"+i+".png");
for (int x = 0; x < topImages[i].getWidth(); x++)
{
for (int y = 0; y < topImages[i].getHeight(); y++)
{
if (topImages[i].getPixel(x, y) == Color.TRANSPARENT)
{
bottomX[i] = x;
bottomY[i] = y;
break;
}
}
}
}
I then add the images to a Frame Layout, using two ImageViews, and use these values to position the lower image:
bottomView.setTranslationX(bottomX[position]);
bottomView.setTranslationY(bottomY[position]);
However, the placement of the bottom image is always inaccurate, usually by a margin down and to the right that is different (but always the same) for each given image. I've also tried setX() and setY(), as well as using parameters to set the TOP and LEFT values similarly, with the same results). What can I do to ensure that the placement is always consistent, with the image's top-left at (or close to) the first transparent pixel?
If you want to only display the images, you can add them as different frames in FrameLayout. In your xml, first declare the one you want to show as transparent pixels, then declare the one which will have transparent pixels.
Related
So i have a lot of questions to this but first here is my assignment.
Write a method public Picture authenticate(Picture p) which checks to
see if ”this” picture and the picture p are identical. It returns a
new picture that it the same size as ”this” picture. For each pixel
position in the original picture ”this”, compare the color of that
pixel with the color of the pixel in the same position from second
picture. If the two pixels have the same color (i.e. the original is
not modified in the copy), set the color of this position in the
resulting picture to white. If the two pixels do not have the same
color, set the color of this position in the resulting picture to the
color of the pixel from the original picture. Return the resulting
picture. If the two pictures are not the same size, the resulting
picture should contain all black pixels
This is my code as of right now
public Picture Authenticate(Picture p)
{
Pixel sourcePixel = null;
Pixel targetPixel = null;
Picture result = new Picture(this.getWidth(), this.getHeight());
for(int sourceX = 0, targetX= getWidth()-1; sourceX < getWidth(); sourceX++,targetX++)
{
for(int sourceY = 0, targetY= getHeight(); sourceY< getHeight(); sourceY++,targetY++)
{
sourcePixel = this.getPixel(sourceX,sourceY);
targetPixel = result.getPixel(targetX, targetY);
}
if (sourcePixel.getColor() == targetPixel.getColor())
targetPixel.setColor(Color.WHITE);
else
targetPixel.setColor(Color.BLACK);
}
return result;
}
Here are my questions:
How do i make p in the authenticate parameter fit into this?
Am i going about this the right way within the loop?
With my if and else statement, i feel as if that is not even close
to changing the pixel i need tooa
How do i make p in the authenticate parameter fit into this?
this is your source image; p is the target image; result is where you place the output pixels resulting from comparing the source and target.
Am i going about this the right way within the loop?
Yes, but the if/else statement belongs inside the inner loop
With my if and else statement, i feel as if that is not even close to changing the pixel i need to
You are close. Keep working on it and step through the code in your debugger to see what is actually happening.
Don't get discouraged, this is closer than you think.
I am currently developing a 2D Java game using Swing as my primary drawing component. Every object has a shadow (BufferedImage) but every shadow overlaps other shadows. Is it possible to only have the shadows not overlap each other? Because I still want the shadows to draw over the player if the object is beneath it, and not if the object is above of the player. Here is a picture for clarity:
I have looked at alpha compositing, I guess I need Source Out? I also thought of having all the shadows (with no transparency) draw on one layer and then draw it with transparency but then it won't draw over the player and other objects like before.
I have a Draw object which is a JPanel and overrides the paintComponent method. Within this method I draw the floor of the current room and then I iterate over the list of objects that belongs to the current room and call each objects' draw method to draw everything.
The object draw method:
public void draw(Graphics g) {
if (visible && checkInScreen()) {
// The required drawing location
int drawLocationX = getX() - globalCameraX;
int drawLocationY = getY() - globalCameraY;
if (shadow) {
g.drawImage(shadowImages.get(imageIndex),
drawLocationX + shadowOffset.x + (getImageWidth()/2),
drawLocationY + shadowOffset.y, null);
}
g.drawImage(images.get(imageIndex), drawLocationX, drawLocationY, null);
//Collisionbox
if (SHOW_COLLISION_BOXES){
g.setColor(Color.WHITE);
g.drawRect(drawLocationX + getCollBoxX(), drawLocationY + getCollBoxY(), getCollBoxW() - getCollBoxX(), getCollBoxH() - getCollBoxY());
}
}
}
My apologies if this question has already been asked but I couldn't find something similar like this.
What I would do to solve this is to have a shadow-layer bitmap. By which I mean:
have your shadow textures saved as a 2D array of boolean values (representing the position of a shadow pixel).
What you can do with this is to then logically or the shadow maps together to create a single layer, which can be layered behind the tree textures to create the shadows.
You may want to change the booleans to floats to represent the colour/intensity of the shadow, then have a larger calculation to merge the shadows together.
The below ShadowMap class is used to store the data for each shadow:
class ShadowMap {
public int xPos, yPos;
public boolean[][] array;
public ShadowMap(int xPos, int yPos, boolean[][] array) {
this.xPos = xPos;
this.yPos = yPos;
this.array = array;
}
}
The ShadowLayer class creates a 2D array for the entire screen, containing if a shadow is present for each pixel:
class ShadowLayer {
public static boolean[][] array = new boolean[SCREEN_WIDTH][SCREEN_HEIGHT];
public static makeNew(ShadowMap[] shadows) {
for (int x = 0; x < SCREEN_WIDTH; x++) {
for (int y = 0; y < SCREEN_HEIGHT; y++) {
array[x][y] = false;
}
}
for (ShadowMap map : shadows) {
for (int i = 0; i < SCREEN_WIDTH; i++) {
for (int j = 0; j < SCREEN_HEIGHT; j++) {
// Logical or such that the pixel at (x, y) has a shadow
// if any shadow map also has a shadow at pixel (x, y)
array[i + map.xPos][j + map.yPos] |= map.array[i][j];
}
}
}
}
}
Using this ShadowLayer class, you just need to darken each pixel on the screen if the ShadowMap has a shadow on the same pixel:
public static Color ajustPixelForShadows(int x, int y, Color pixel) {
return ShadowMap.array[x][y] ? pixel.darken() : pixel;
}
I admit I'm not familiar with Swing so I'm not sure it is possible with that specific interface but the below solution could be used in a variety of 2D graphics engines.
You'll need an off-screen "shadow layer" to draw to that matches the screen dimensions. Initialize the shadow layer to being pure white.
For each object you draw from back to front (y-sorting), do the following, in order, with the shadow layer:
Draw the object's shadow shape in a single solid dark grey color to the shadow layer
Draw the object itself to the shadow layer as a pure white sprite (i.e. all non-transparent pixels in the object's bitmap are white)
Of course, also draw the object itself to the screen.
Then, once all objects have been drawn to both the screen and the shadow layer, draw the shadow layer to the screen using multiply blending. The multiply blend guarantees shadows will darken whatever they are drawn over (unlike alpha blend which, with very light shadows, could potentially actually lighten the colors they are drawn over). It will also make the pure white portions of the layer do nothing, which is what you want.
The above steps mean that after each object draws a shadow, it erases any shadows that would be underneath it in the final scene when it draws itself in white to the shadow layer. Therefore it won't cast a shadow on itself, and objects won't cast shadows over other objects that are technically in front of them.
Objects will still cast shadows onto other objects that are behind them as you wanted, since any parts of the shadow that haven't been erased by an overlapping object will still apply (or if they are erased, will be potentially re-drawn by a later object). And, since you are drawing the shadows as a single non-translucent color to the shadow layer, multiple shadows overlapping won't affect each other either, which was of course the main point.
You could modify this technique depending on what you have available. For example, instead of white you could use a fully transparent shadow layer initially and an "erase" blend mode [(src * 0) + (dst * (1 - srcAlpha))] to draw the objects that erase shadows underneath them. You could then use alpha instead of multiply blend if you prefer for drawing the shadow layer to the screen.
I've been trying to resolve this issue I have been having with displaying a texture correctly on my libgdx desktop program.
I have an Orthographic camera with which when I set as:
camera.setOrtho(false);
I get this image:
And when I set it as:
camera.setOrtho(true);
I get this image:
The red image is drawn with a SpriteBatch:
batch.draw(texture, x, y, width, height);
While the white image is drawn from individual points plotted based on if their alpha value was 1.
TextureData td = texture.getTextureData();
td.prepare;
Pixmap map = td.consumePixmap();
for (int i = 0; i < map.getWidth(); i++)
for (int j = 0; j < map.getHeight(); j++)
if (new Color(map.getPixel(i, j)).a == 1)
points.add(new Point(i, j));
Above is the code used to get all the non-transparent pixels.
They are displayed as the white image, and seem to be the inverse of the original texture.
However, the points plotted and the image itself is always an inverse of one another.
Is there any way of resolving this issue?
Thank you.
PS: I've tried multiple ways of trying to fix this:
Using Sprites and flipping them
Using TextureRegions and flipping them
Absolutely nothing seems to work.
Yes this is very anoying, Libgdx is not consistent with it's coordinate system. Like font.draw() draws from top downward. Alter the way you iterate over you draw/plot inside your loop, basically you have to flip it manually. So when j == 0 then y would become the highest value and if j == map.getHeight y would become the lowest value. Then interpolate linearly within these values. If you shown whats inside your loop I could help out a bit more.
I would like to know if anybody can help me with a better method of drawing a Tile map for my android game.
Currently, I use a for loop to draw the required Bitmaps to the screen but when doing this for the amount of tiles I need to render at once (enough to cover the screen and a bit more), when the map scrolls, you can notice the map become jolty with its movement, because of the for loop having to loop through all the tiles. The tiles are drawn simular to this:
for(int i = 0; i < 170; i++) {
canvas.drawBitmap(bitmap, x + i * bitmap.getWidth(), y, null);
}
The method I am currently using uses a few bitmaps to save memory, and draws them in different locations.
A different method i can think of to draw the map would be to create a larger Bitmap from the tiles and move the position of that larger bitmap to create movement. The problem with this is that is does require lots of memory and gets out of memory errors.
So, i need to try and find out a method of drawing multiple tiles preferably without the use of a for-loop (I believe the for-loop is causing the jolty, un-smooth movement of the map).
For more details just ask, thanks.
The for loop is the correct way to draw it, your problem is probably the amount of data you are trying to draw in one frame and/or the number of pixels you are trying to push through the system.
If you want good performance on Android your best bet will be to use the graphics hardware it provides. There are various game frameworks available that will make that easier for you and give you much better performance than you will get otherwise.
If not then you will need to break up the drawing and still run the same effective logic but spread out so you draw a few tiles per frame.
is it really required to draw ALL tiles at once?
if it is possible for you, maybe you can determine the 'visible view port' and then just draw those tiles, which need to be drawn?!?
int width = getWidth()/Tiles.width; // do it once before any rendering
// thats the amount of tiles per line
int height = getHeight()/Tiles.height; // do it once before any rendering
// thats the amount of tiles per row
Point pos = ...; // you should know the position of your 'figure' within the map
// could as well be the scroll position
//now draw only those tile from the 'viewport':
for (int dy = 0; dy < width; dy++){
for (int dx = 0; dy < height; dy++){
int xOnMap = pos.x + x;
int yOnMap = pos.y + dy;
int index = yOnMap*height+yOnMap; //index in list
canvas.drawBitmap(bitmap,
x * bitmap.getWidth(), y * bitMap.getHeight(), null);
}
}
so you just have to draw some tile and that would always be the same amount...
i must confess i wrote that code onstackoverflow so there is a chance i did a syntax terror ^^
I have two TIF files, one is background (overlay) and the other is foreground. The following code is currently used for combining two TIFs.
// Background color of foreground image
int w = Color.WHITE.getRGB();
// Fill all pixels which are not background color
for (int i = 0; i < foregroundImage.getWidth(); i++)
{
for (int j = 0; j < foregroundImage.getHeight(); j++)
{
int x = foregroundImage.getRGB(i, j);
if (x != w)
backgroundImage.setRGB(i, j, x);
}
}
Is there any other way that has a better performance to do this?
You can make the Color.white pixels transparent using RGBImageFilter, shown here, or LookupOp, mentioned here. Then you can use the AlphaComposite.SRC_OVER rule to combine the images. AlphaCompositeDemo is an example that lets one explore the available modes, and there's related example here. Of course, you'll need to profile both approaches to see which is faster.