This question already has answers here:
Java getSubimage() outside of raster
(2 answers)
Closed 6 years ago.
I have made a small piece of code to split spritesheets into seperate images...
private BufferedImage sheet, dirt, grass, rock, tree, water;
int width = 64, height = 64;
public void split() {
dirt = sheet.getSubimage(0,0,width,height);
grass = sheet.getSubimage(width,0,width*2,height);
rock = sheet.getSubimage(width*2,0,width*3,height);
tree = sheet.getSubimage(0,height,width,height*2);
water = sheet.getSubimage(width,height,width*2,height*2);
}
Now, the first two (dirt and grass) go well as expected. However, the issue is with the rock cropping line. For some reason it drops an exception...
"
Exception in thread "Thread-0" java.awt.image.RasterFormatException: (x + width) is outside of Raster
at sun.awt.image.ByteInterleavedRaster.createWritableChild(ByteInterleavedRaster.java:1245)
"
So apparently the issue is to do with the x value being "out of bounds". But the x value is (width * 2), so 128pix, which is well in bounds of this image (192x128), which I've attached as proof.
I've also changed the code a little to crop with the x value being 1 for rock but I still get the issue, same with using the same dimensions for anothe bufferedImage.
Sorry for anything wrong in this post, it's my first time.
Thanks in advance
The image
Answering off my comment.
So you are on the right path, but not quite understanding how getSubimage() works.
The docs say
Parameters:
x - the X coordinate of the upper-left corner of the specified rectangular region
y - the Y coordinate of the upper-left corner of the specified rectangular region
w - the width of the specified rectangular region
h - the height of the specified rectangular region
You are correctly setting you x and y values, however you are mistaken in setting you width and height values.
Since you are starting at point (x,y) you do not need to compensate for the width and the height like you are, instead just use them as they are.
So, you code would be
public void split() {
dirt = sheet.getSubimage(0,0,width,height);
grass = sheet.getSubimage(width,0,width,height);
rock = sheet.getSubimage(width*2,0,width,height);
tree = sheet.getSubimage(0,height,width,height);
water = sheet.getSubimage(width,height,width,height);
}
Related
I have tried to make an algorithm in java to rotate a 2-d pixel array(Not restricted to 90 degrees), the only problem i have with this is: the end result leaves me with dots/holes within the image.
Here is the code :
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
int xp = (int) (nx + Math.cos(rotation) * (x - width / 2) + Math
.cos(rotation + Math.PI / 2) * (y - height / 2));
int yp = (int) (ny + Math.sin(rotation) * (x - width / 2) + Math
.sin(rotation + Math.PI / 2) * (y - height / 2));
int pixel = pixels[x + y * width];
Main.pixels[xp + yp * Main.WIDTH] = pixel;
}
}
'Main.pixels' is an array connected to a canvas display, this is what is displayed onto the monitor.
'pixels' and the function itself, is within a sprite class. The sprite class grabs the pixels from a '.png' image at initialization of the program.
I've tried looking at the 'Rotation Matrix' solutions. But they are too complicated for me. I have noticed that when the image gets closer to a point of 45 degrees, the image is some-what stretched ? What is going wrong? And what is the correct code; that adds the pixels to a larger scale array(E.g. Main.pixels[]).
Needs to be java! and relative to the code format above. I am not looking for complex examples, simply because i will not understand(As said above). Simple and straight to the point, is what i am looking for.
How id like the question to be answered.
Your formula is wrong because ....
Do this and the effect will be...
Simplify this...
Id recommend...
Im sorry if im asking to much, but i have looked for an answer relative to this question, that i can understand and use. But to always either be given a rotation of 90 degrees, or an example from another programming language.
You are pushing the pixels forward, and not every pixel is hit by the discretized rotation map. You can get rid of the gaps by calculating the source of each pixel instead.
Instead of
for each pixel p in the source
pixel q = rotate(p, theta)
q.setColor(p.getColor())
try
for each pixel q in the image
pixel p = rotate(q, -theta)
q.setColor(p.getColor())
This will still have visual artifacts. You can improve on this by interpolating instead of rounding the coordinates of the source pixel p to integer values.
Edit: Your rotation formulas looked odd, but they appear ok after using trig identities like cos(r+pi/2) = -sin(r) and sin(r+pi/2)=cos(r). They should not be the cause of any stretching.
To avoid holes you can:
compute the source coordinate from destination
(just reverse the computation to your current state) it is the same as Douglas Zare answer
use bilinear or better filtering
use less then single pixel step
usually 0.75 pixel is enough for covering the holes but you need to use floats instead of ints which sometimes is not possible (due to performance and or missing implementation or other reasons)
Distortion
if your image get distorted then you do not have aspect ratio correctly applied so x-pixel size is different then y-pixel size. You need to add scale to one axis so it matches the device/transforms applied. Here few hints:
Is the source image and destination image separate (not in place)? so Main.pixels and pixels are not the same thing... otherwise you are overwriting some pixels before their usage which could be another cause of distortion.
Just have realized you have cos,cos and sin,sin in rotation formula which is non standard and may be you got the angle delta wrongly signed somewhere so
Just to be sure here an example of the bullet #1. (reverse) with standard rotation formula (C++):
float c=Math.cos(-rotation);
float s=Math.sin(-rotation);
int x0=Main.width/2;
int y0=Main.height/2;
int x1= width/2;
int y1= height/2;
for (int a=0,y=0; y < Main.height; y++)
for (int x=0; x < Main.width; x++,a++)
{
// coordinate inside dst image rotation center biased
int xp=x-x0;
int yp=y-y0;
// rotate inverse
int xx=int(float(float(xp)*c-float(yp)*s));
int yy=int(float(float(xp)*s+float(yp)*c));
// coordinate inside src image
xp=xx+x1;
yp=yy+y1;
if ((xp>=0)&&(xp<width)&&(yp>=0)&&(yp<height))
Main.pixels[a]=pixels[xp + yp*width]; // copy pixel
else Main.pixels[a]=0; // out of src range pixel is black
}
I believe this is more of a logic question than a java question, sorry.
My intent is rather straightforward, i want the ship to move and rotate with a matrix, with the bitmap ship1 being the center pivot of the rotation. The code works great except the pivot is off by a strange offset. (picture of conundrum linked at bottom)
The default value rotation at 0 works but all the other values seem to slide away from the center, with 180 being the furthest from the center.
centerX = playerValues[Matrix.MTRANS_X] + ship1.getWidth()/2;
centerY = playerValues[Matrix.MTRANS_Y] + ship1.getHeight()/2;
newRotation = ((float) Math.toDegrees(Math.atan2(fingery1 - centerY, fingerx1 - centerX)));
matrix.postRotate((newRotation - prevRotation), centerX, centerY);
prevRotation = newRotation;
if (fingerx1 > playerX) {
xspeed = 1;
} else
if (fingerx1 < playerX) {
xspeed = 0;
} else
if (fingery1 > playerY) {
yspeed = 1;
} else
if (fingery1 < playerY) {
yspeed = 0;
}
matrix.postTranslate(xspeed, yspeed);
matrix.getValues(playerValues);
I tried to draw how the relation of the bitmap looks at different angles. (the blue dot is where I intend to rotate the bitmap around, the arrow pointing right is the only correct one).
http://i.stack.imgur.com/2Yw76.png
Please let me know if you see any errors or any feedback helps! I just need a second pair of eyes on this because mine are going to explode soon.
Consider studying a good computer graphics text re matrix math. Foley and Van Dam is always a safe bet.
The matrix A is applied to point x with multiplication Ax. You have A = RT a rotation with translation post multiplied. The result is RTx which is R (T x) meaning the point is translated then rotated, when you probably meant the opposite.
Additionally it appears you are concatenating incremental changes repeatedly. Floating point errors will accumulate, visible as worsening distortions. Instead maintain orientation parameters x, y, theta for each ship. These are controlled by the UI. Set the matrix from these in each rendering. The transform will be rotation about the point (w/2, h/2) followed by translation to (x, y). But the matrix to effect this is the translation post multiplied by the rotation! Also you must reset the matrix for each ship.
Im developing simple game. I have cca. 50 rectangles arranged in 10 columns and 5 rows. It wasn't problem to put them somehow to fit the whole screen. But when I rotate the canvas, let's say about 7° angle, the old coordinates does't fit in the new position of the coordinates. In constructor I already create and define the position of that rectangles, in onDraw method I'm drawing this rectangles (of course there are aready rotated) bud I need some method that colliding with the current rectangle. I tried to use something like this (i did rotation around the center point of the screen)
int newx = (int) ((x * Math.cos(ROTATE_ANGLE) - (y * Math.sin(ROTATE_ANGLE))) + width / 2);
int newy = (int) ((y * Math.cos(ROTATE_ANGLE) + (x * Math.sin(ROTATE_ANGLE))) + height / 2);
but it doesn't works (becuase it gives me absolute wrong new coordinates). x and y are coordinates of the touch that I'm trying to calculate new position in manner of rotation. ROTATE_ANGLE is the angle of rotation the screen.
Does anybody know how to solve this problem, I already go thorough many articles, wiki, wolframalpha categories but not luck. Maybe I just need some link to understand problem more.
Thank you
You use a rotation matrix.
Matrix mat = new Matrix(); //mat is identity
mat.postRotate(ROTATE_ANGLE); //mat is a rotation matrix of ROTATE_ANGLE degrees
float point[] = {10.0, 20.0}; //create a new float array representing the point (10, 20)
mat.mapPoints(point); //rotate the point by the requested amount
Ok, find the solution.
First it is important to convert from angle to radian
Then I personly need to negate that radian value.
That's all, this solution is correct
I was working on my game today and I found that the top of my trees have a weird texture problem where they overlap each other with a black box. It is only the top of the trees and the tops are split up into 9 blocks all with their own image. The 9 images are transparent, each is 32x32, and I've tried it a bunch of different ways with no luck. Does anyone know what the problem with the texture is? This isn't a generation question but an OpenGL/Slick2D question about textures. Here's a screenshot of the problem: Screenshot
EDIT: Here's a piece of the rendering code.
for (int x = (int) (World.instance.camera.getX() / Block.WIDTH); x < width; x++)
{
for (int y = (int) (World.instance.camera.getY() / Block.HEIGHT); y < height; y++)
{
try
{
if (blocks[x][y] != Block.AIR.getId())
{
g.drawImage(textureCache.get(blocks[x][y]), x * Block.WIDTH, y * Block.HEIGHT);
}
}
catch(Exception ex)
{
}
}
}
Looking at your code, it seems that you are only drawing a single image at each 32x32 square. So if tree A is in front of tree B, but tree A only partly fills a square, then tree A is the one listed in your blocks array and therefore retrieved from your "texture cache"; and not tree B. So tree A is all that is drawn.
To resolve this, your blocks structure would need to be three dimensional - basically, for each 32x32 square, you'd need some kind of "stack" of references to all the images whose corresponding object is found in that square. Then when you draw that square, draw all of the images in order, from the back to the front.
My assignment is to implement an algorithm to color a closed shape starting from a given (x,y) coordinate and "spread" via recursive calls untill it reaches the borders of the shape. So far this is what I've come up with:
private void color(int x, int y) {
g2d.draw(new Line2D.Double(x, y, x, y));
if (!robot.getPixelColor(x - 1, y).equals(Color.BLACK) &&
!robot.getPixelColor(x - 1, y).equals(Color.RED)) {
color(x - 1, y);
} else if (!robot.getPixelColor(x + 1, y).equals(Color.BLACK) &&
!robot.getPixelColor(x - 1, y).equals(Color.RED)) {
color(x + 1, y);
} else if (!robot.getPixelColor(x, y - 1).equals(Color.BLACK) &&
!robot.getPixelColor(x - 1, y).equals(Color.RED)) {
color(x, y - 1);
} else if (!robot.getPixelColor(x, y + 1).equals(Color.BLACK) &&
!robot.getPixelColor(x - 1, y).equals(Color.RED)) {
color(x, y + 1);
}
}
The Robot class' getPixelColor is the only way I found to get the color of a given pixel (as far as I know another would be getRGB, but that only works on Image objects). To my understanding this should work, as the outer lines of the shape are definitely black, and the initial x and y values come from a MouseListener, so they are inside the shape, however I get the following error:
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at sun.java2d.pipe.BufferedContext.validateContext(BufferedContext.java:110)
at sun.java2d.d3d.D3DRenderer.validateContextAA(D3DRenderer.java:42)
at sun.java2d.pipe.BufferedRenderPipe$AAParallelogramPipe.fillParallelogram(BufferedRenderPipe.java:445)
at sun.java2d.pipe.PixelToParallelogramConverter.drawGeneralLine(PixelToParallelogramConverter.java:264)
at sun.java2d.pipe.PixelToParallelogramConverter.draw(PixelToParallelogramConverter.java:121)
at sun.java2d.SunGraphics2D.draw(SunGraphics2D.java:2336)
at dline.DrawingSpace.color(DrawingSpace.java:87)
at dline.DrawingSpace.color(DrawingSpace.java:93)
at dline.DrawingSpace.color(DrawingSpace.java:90)
at dline.DrawingSpace.color(DrawingSpace.java:93)
at dline.DrawingSpace.color(DrawingSpace.java:90)
(drawingSpace is a sub-class of JPanel)
The teacher did tell us that this is memory consuming, however it's supposed to be a working algorithm, so I'm doing something wrong, obviously. Any help would be much appriciated, thank you.
You can try to increase the Stack size: How to increase the Java stack size?
Probably you have a bug in your algorithm, or the shape is too big. What helps if you 'draw' your algorithm on a piece of graph paper. That way you can check your algorithm.
I'm guessing that you're backtracking onto previously visited pixels. The pixel you just drew probably won't be visible to robot until after you return from color, so it will not appear red from the previous painting.
Do you have a reference to the java.awt.Shape? A much simpler way than using the robot would be to use Shape.contains(Point) to see whether it's in the shape you're supposed to draw.
The basic algorithm either way is depth-first traveral. To do a DFS when there are possible cycles, you can record the pixels you've already drawn.
//java.awt.Point
Set<Point> paintedPixels = new HashSet<Point>();
private void color(int x, int y) {
if ( paintedPixels.contains(new Point(x, y)) ) {
//already painted
return;
}
paintedPixels.add(new Point(x, y));
//...
}
Now, this could still result in a very deep search. You might consider instead using a non-recursive breadth-first traveral. See the Wikipedia article on Flood Fill.
The problem with implementing this as a recursive algorithm is that it has (for bigger images) a very high recursion depth.
In Java (and most other imperative programming languages, too) the maximal recursion depth is limited by the amount of stack space for each thread, since it must keep a stack frame for each method invocation there.
You may try smaller images first, and try to increase the stack size with the -xss parameter.
Edit: As pointed out by Mark, the Robot will not get any pixels until your drawing is complete, since often your drawing is double-buffered (i.e. the Swing engine lets you paint first on an image, and draws then the complete image to the screen).
Also, you are not converting between device (screen) and user (component) coordinates for the lookup.
You wrote:
The Robot class' getPixelColor is the only way I found to get the color of a given pixel (as far as I know another would be getRGB, but that only works on Image objects).
So, why don't you use an Image object? Fill your shape while drawing on the Image, and then draw the whole image at once to the screen.
And your method can be made much more readable if you transfer the "is already painted" test inside the recursive call:
private void color(int x, int y) {
// getPixel invokes something in the image - or replace it here.
Color org = getPixel(x,y);
if (org.equals(Color.BLACK)) {
// reached the border
return;
}
if (org.equals(Color.RED)) {
// already painted before
return;
}
g2d.draw(new Line2D.Double(x, y, x, y));
color(x-1, y);
color(x+1, y);
color(x, y-1);
color(x, y-1);
}