Currently I'm trying to create something to display a "2D view" for a Grid which can be used for various proporses, such as a simple 2D game.
After doing a wrap work with a simple Core class (this holds all information to my visual stuff, including pixels values for sprites) I started the visual work. As my aim is to do this with plain swing/awt in Java I just created a custom JComponent to this.
In my JComponent I tried some approaches and decided to test draw my pixels info in a BufferedImage and at other hand draw the pixels directly in Graphics object.
Looking through internet I found some ways to draw a pixel/dot on screen, like this. In this case, I wrapped this in a method:
private void drawSpritePixels(ArrayList<Spr.Pixel> pixels, int startX, int startY, Graphics2D g) {
for (Spr.Pixel p : pixels){
g.setColor(p.color);
g.fillRect(p.x + startX, p.y + startY, 1, 1);
}
}
For drawing my data onto a BufferedImage, I'm using this:
public BufferedImage spriteImage(int spriteAddress) {
BufferedImage img = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDefaultConfiguration()
.createCompatibleImage(32, 32, Transparency.TRANSLUCENT);
for (Pixel p : getSpriteInfo(spriteAddresses.get(spriteAddress))) {
img.setRGB(p.x, p.y, p.color.getRGB());
}
return img;
}
As title says, the performance was better using BufferedImage approach. Im my tests BufferedImage takes 40ms to finish while Pixels takes 200ms+ to the same amount of "work".
Then, why this is so different? Should do I avoid any iterations in pixels approach?
Related
I'm trying to extract an images of the application window's components in java.
I've created a class that overrides java.awt.GraphicsConfiguration and looks very similar to sun.awt.Win32GraphicsConfig. The problem is that when I call the createAcceleratedImage function with component (for example application window) and 2x larger dimensions than the real one, the java renders it small in the image on the top left corner and the rest of the image is empty space.
My createAcceleratedImage function is same as in sun.awt.Win32GraphicsConfig:
public Image createAcceleratedImage(Component target, int w, int h) {
ColorModel localColorModel = getColorModel(Transparency.OPAQUE);
WritableRaster localWritableRaster = localColorModel.createCompatibleWritableRaster(w, h);
return new OffScreenImage(target, localColorModel, localWritableRaster, localColorModel.isAlphaPremultiplied());
}
I apologize if I forgot to mention more information, If you need more information please ask in comments.
Thank you for help.
I used VolatileImage instead of OffScreenImage inside my CustomComponentPeer.
public VolatileImage createVolatileImage(int width, int height) {
GraphicsConfiguration graphicsConfig = getGraphicsConfiguration();
return graphicsConfig.createCompatibleVolatileImage(width, height);
}
I found that drawImage function in Graphics2D support high resolution rendering only for MultiResolutionImage and VolatileImage. Rendering in high DPI using OffScreenImage is not supported.
I need to move already made BufferedImage by x,y coordinates and then draw another things on it with Graphics2D object. I tried to use this code to do that :
Graphics2D g = img.createGraphics();
g.translate(x, y);
but it doesn't work. Is there any way to move everything in Graphics2D object and then draw on it or I have to use this code to do that:
BufferedImage temp = new BufferedImage(img.getWidth(),img.getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics2D g = temp.createGraphics();
g.drawImage(img,x, y,null);
Using this code and then drawing only few elements rather than making whole image from scratch isn't big leap in performance so I think making new BufferedImage then drawing image on it isn't best way. I would rather just create Graphics2D object from already made image and then just move it by a few pixels diagonally, but I couldn't find the way to do that.
From the Graphics2d docs when you use translate:
All coordinates used in subsequent rendering operations on this graphics context are relative to this new origin.
You are defining a transformation that affects future operations. After calling translate if you were to call a method on graphics like draw3DRect(0, 0, ... snipped ... ) the starting coordinates 0,0 would be translated by x,y.
I think your best bet might be to use the methods of BufferedImage to move all the pixels before you get the graphics object. You have getRgb and setRgb
A naive example of moving the pixels:
BufferedImage buffImg = ImageIO.read(img);
int width = buffImg.getWidth();
int horizontalOffset = 10;
int verticalOffset = 10;
int widthToMove = width - horizontalOffset;
int heightToMove = buffImg.getHeight() - verticalOffset;
int[] rgb = buffImg.getRGB(0, 0, widthToMove, heightToMove, null, 0, widthToMove);
buffImg.setRGB(horizontalOffset,verticalOffset,widthToMove, heightToMove,rgb, 0, widthToMove);
This still leaves you with some work to do because there is a strip at the top and to the left that you need to fill with background colour.
If it's going to be used on big images you might want to use a buffer int[] and pass it to getRGB in a loop, getting and setting in chunks.
I am a relative newbie in game programming. I know how to draw pixels to a BufferedImage using setPixel(). It is horribly slow on larger formats so I moved on and found VolatileImage (took me a week or so). It is fairly easy to draw lines, strings, rects, etc but I can't draw individual pixels. I already tried using drawLine(x,y,x,y) but I get 3-4 FPS on an 800x600 image.
The fact that java didn't include setPixel() or setRGB() in the VolatileImage makes me pretty angry and confused.
I have 4 questions:
Is there a way to draw individual pixels on a VolatileImage? (on 1440x900 formats with FPS > 40)
Can I draw pixels in a BufferedImage with a faster method? (same 1440x900, FPS > 40)
Is there any other way to draw pixels fast enough for 3D games?
Can I make my BufferedImage hardware accelerated( tried using setAccelerationPriority(1F) but it doesn't work)
Please if you have any idea tell me. I can't continue making my game wihout this information. I already made 3D rendering algorithms but i need to be able to draw fast pixels. I have got a good feeling about this game.
Here's the code if it can help you help me:
public static void drawImageRendered (int x, int y, int w, int h) { // This is just a method to test the performance
int a[] = new int[3]; // The array containing R, G and B value for each pixel
bImg = Launcher.contObj.getGraphicsConfiguration().createCompatibleImage(800, 600); // Creates a compatible image for the JPanel object i am working with (800x600)
bImg.setAccelerationPriority(1F); // I am trying to get this image accelerated
WritableRaster wr = bImg.getRaster(); // The image's writable raster
for (int i = 0; i < bImg.getWidth(); i++) {
for (int j = 0; j < bImg.getHeight(); j++) {
a[0] = i % 256;
a[2] = j % 256;
a[1] = (j * i) % 256;
wr.setPixel(i, j, a); // Sets the pixels (You get a nice pattern)
}
}
g.drawImage(bImg, x, y, w, h, null);
}
I would much prefer not using OpenGL or any other external libraries, just plain Java.
Well you're basically drawing one pixel after the other using the CPU. There's no way that this can be accelerated, thus such a method does simply not make any sense for a VolatileImage. The low FPS you get suggest that this even causes a significant overhead, as each pixel drawing operation is sent to the graphics card (with information such as location & colour), which takes longer than to modify 3 or 4 bytes of RAM.
I suggest to either stop drawing each pixel separately or to figure out a way to make your drawing algorithm run directly on the graphics card (which most likely requires another language than Java).
It's been over 4 years since this post got an answer. I was looking for an answer to this question as well and stumbled on this post. After some more searching, I got it to work. Below I'll post the source to rendering pixels with a VolatileImage.
It seems Java hides our ability to plot pixels directly to a VolatileImage, but we can draw buffered images to it. For good reason. Using the software to plot a pixel doesn't really help with acceleration(in Java it seems). If you can plot pixels to a BufferedImage, and then render it on a VolatileImage, you may get a speed bonus since it's hardware accelerated from that point.
The source down below is a self-contained example. You can copy-pasta practically all of it to your project and run it.
https://github.com/Miekpeeps/JavaSnippets-repo/blob/master/src/graphics_rendering/pixels_03/PlottingVolatile.java
In the constructor I save the Graphics environment of the app/game.
private GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
private GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
Then, when I call a method to enable hardware we create a buffer. I set the transparency to Opaque. In my little engine, I deal with transparency/alpha blending on another thread in the pipeline.
public void setHardwareAcceleration(Boolean hw)
{
useHW = hw;
if (hw)
{
vbuffer = gc.createCompatibleVolatileImage(width, height, Transparency.OPAQUE);
System.setProperty("sun.java2d.opengl", hw.toString()); // may not be needed.
}
}
For each frame I update, I get the Graphics from the VolatileImage and render my buffer there. Nothing gets rendered if I dont flush().
#Override
public void paintComponent(Graphics g)
{
if(useHW)
{
g = vbuffer.getGraphics();
g.drawImage(buffer, 0, 0, null);
vbuffer.flush();
}
else
{
g.drawImage(buffer, 0, 0, null);
buffer.flush();
}
}
There is still a little bit of overhead when calling to plot a pixel on the BufferedImage writable raster. But when we update the screen, we get a speed boost when using the Volatile image instead of using the Buffered image.
Hope this helps some folks out. Cheers.
I'm trying to draw one image onto another using graphics.drawImage() but it's only working accurately for some images, others it messes up. My code's below, I've made sure texture is the right image when it enters the method so that's definitely not it. Any ideas?
private BufferedImage currentSheet;
public void swapRegionWithTexture(Rectangle region, Image texture) {
Graphics sheetGraphics = currentSheet.createGraphics();
for (int ix = region.x; ix < region.x + region.width; ix++) {
for (int iy = region.y; iy < region.y + region.height; iy++) {
currentSheet.setRGB(ix, iy, 0x000000);
}
}
sheetGraphics.drawImage(texture, region.x, region.y, null);
sheetGraphics.dispose();
}
The general idea is:
Grab the graphics to draw to.
Clear out the section of the graphics that will be drawn on.
Draw the image at the given location on the graphics.
Dispose of the graphics.
Your current atomic steps are thus:
create a new buffered image
write to that buffered image some crazy manipulation of the original texture (looks like you're reversing it?)
write the original image to the current sheet.
So what if you change this
sheetGraphics.drawImage(texture, region.x, region.y, null);
to this
sheetGraphics.drawImage(bufferedTexture, region.x, region.y, null);
Otherwise you're spending time reversing the image and putting into buffered texture and then never doing anything with that buffer... so chances are you intended to use that buffered texture somewhere.
I have loaded a jpg image in which I want to draw letters and circles, given a x,y coordinate.
I have been trying to figure out the paintIcon of the ImageIcon class
public void paintIcon(Component c,
Graphics g,
int x,
int y)
Does this method allow me to edit jpg images the way I want to? What are supposd to be the Component c and Graphics g paramethers? What would I add to its body to paint circles or letters?
I'm working on Netbeans 6.5, do I have anything builtin for this task (instead of ImageIcon)?
The pure-Java way is to use ImageIO to load the image as a BufferedImage. Then you can call createGraphics() to get a Graphics2D object; you can then draw whatever you want onto the image.
You can use an ImageIcon embedded in a JLabel to do the displaying, and you can add a MouseListener and/or a MouseMotionListener to the JLabel if you're trying to allow the user to edit the image.
Manipulating images in Java can be achieved by using the Graphics or Graphics2D contexts.
Loading images such as JPEG and PNG can be performed by using the ImageIO class. The ImageIO.read method takes in a File to read in and returns a BufferedImage, which can be used to manipulate the image via its Graphics2D (or the Graphics, its superclass) context.
The Graphics2D context can be used to perform many image drawing and manipulation tasks. For information and examples, the Trail: 2D Graphics of The Java Tutorials would be a very good start.
Following is a simplified example (untested) which will open a JPEG file, and draw some circles and lines (exceptions are ignored):
// Open a JPEG file, load into a BufferedImage.
BufferedImage img = ImageIO.read(new File("image.jpg"));
// Obtain the Graphics2D context associated with the BufferedImage.
Graphics2D g = img.createGraphics();
// Draw on the BufferedImage via the graphics context.
int x = 10;
int y = 10;
int width = 10;
int height = 10;
g.drawOval(x, y, width, height);
g.drawLine(0, 0, 50, 50);
// Clean up -- dispose the graphics context that was created.
g.dispose();
The above code will open an JPEG image, and draw an oval and a line. Once these operations are performed to manipulate the image, the BufferedImage can be handled like any other Image, as it is a subclass of Image.
For example, by creating an ImageIcon using the BufferedImage, one can embed the image into a JButton or JLabel:
JLabel l = new JLabel("Label with image", new ImageIcon(img));
JButton b = new JButton("Button with image", new ImageIcon(img));
The JLabel and JButton both have constructors which take in an ImageIcon, so that can be an easy way to add an image to a Swing component.
Use a library to do just that. One that you might try is JMagick.
I have used Java Advanced Imaging library (http://java.sun.com/products/java-media/jai/forDevelopers/jaifaq.html), but you can also look at ImageJ (http://rsbweb.nih.gov/ij/index.html)
I imagen you could use this method to overlay the elements you need every time the image is drawn in the UI (this would happen numerous times as you are not drawing ON the image data its self) but may be suitable to your purposes (and advantageous if the overlay changes over time).
Something like:
new ImageIcon("someUrl.png"){
public void paintIcon(Component c, Graphics g, int x, int y) {
super(c, g, x, y);
g.translate(x, y);
g.drawOval(0, 0, 10, 10);
...
g.translate(-x, -y);
}
};
Having said that, mmyers' answer is much better if you want to modify the image data.