Hello Guest

Rendering a bufferedImage to a LWJGL Display

  • 13 Replies
  • 31591 Views
Rendering a bufferedImage to a LWJGL Display
« on: September 26, 2012, 07:01:12 »
Hey everyone,
This is my first post in an attempt to solve a question I have been googling everywhere!
I have a bufferedImage which is stored in memory (the image itself is created in java, not from a picture) using the following code:
Code: [Select]
BufferedImage bi = new BufferedImage(700, 400, BufferedImage.TYPE_INT_ARGB);Every second this image could be modified up to 100 times and redrawn to the screen.  The only problem is, I have no idea at all how to do that!  I know I can save it as a png, then import that via slick-util but it seems like it would be far too slow.

So heres my question:  Is there any way to draw a bufferedImage directly to the LWJGL Display?  Or is there any better way that I could be doing this?

Any help is appreciated, Thanks.

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #1 on: September 27, 2012, 03:39:48 »
Java2D is completely separate from LWJGL. You cannot mingle BufferedImages and OpenGL objects.

All that LWJGL does is let you call OpenGL (https://en.wikipedia.org/wiki/OpenGL) from within Java. To use LWJGL, you are going to need to learn a bit of OpenGL, since that's the only way you can do anything - you are issuing commands to the user's graphics card, which in turn does all of the heavy lifting. This requires a lot of setup and knowledge of how to use OpenGL. The advantage of this is that your rendering becomes vastly, incredibly faster, more powerful, and more flexible.

Now, what are you trying to accomplish? Are you trying to use the BufferedImage as a canvas to render to? Or are you simply trying to render an image to the screen?

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #2 on: September 27, 2012, 11:06:38 »
Thanks for the information,
At the moment, I have a LWJGL display set up, and I create the bufferedImage as shown earlier.  I am able to work out how to change the colours of pixels and such of the bufferedImage, then I want to render the bufferedImage to the Display.

ie. I am  "simply trying to render an image to the screen"

However, I don't think it is practical to have the image saved on the hard drive and edit that constantly, but rather keep it in memory.  That is why I would like to use a bufferedImage.

Thankyou.

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #3 on: September 27, 2012, 18:49:26 »
I don't think you quite understand.

Ignore BufferedImage, ignore canvases, ignore every single part of the standard Java library relating to graphics. You cannot use them in LWJGL.

If you want to load an image file and render it, you will need to create a Texture from that data. This sounds very complicated, but there is the "Slick-util" library that has some simplified methods for doing that. Once you have the texture, however, you need to start making some OpenGL calls to render it - you should go look at some tutorials.

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #4 on: September 28, 2012, 00:51:12 »
Yes, that was my question!  So you cannot render a bufferedImage to the LWJGL OpenGL Display.  I have been using slick-util with success.
Once an Image file has been loaded into the the slick-util texture, is there any way to set individual pixels to different colours without having to reload it?

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #5 on: September 28, 2012, 06:01:29 »
Ok, so after a lot of research, I decided not to use a bufferedImage and instead use a ByteBuffer and directly render that to the Display.
here is the code that I use to do it:

Code: [Select]
private ByteBuffer textureBuffer;
private int textureID;

public Terrain() {

textureBuffer = BufferUtils.createByteBuffer(512*512*4);
textureBuffer.order(ByteOrder.nativeOrder()); //is this line necessary.  I remove it and it does nothing!
textureID = GL11.glGenTextures();
for (int i = 0; i < 512*512; i ++) {
textureBuffer.put((byte) 0);
textureBuffer.put((byte) 0);
textureBuffer.put((byte) 255);
textureBuffer.put((byte) 255);
}
textureBuffer.flip();

GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, 512, 512, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, textureBuffer);
}

private void render() {

GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);

GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0, 0);
GL11.glVertex2i(0, 0);

GL11.glTexCoord2f(1, 0);
GL11.glVertex2i(512, 0);

GL11.glTexCoord2f(1, 1);;
GL11.glVertex2i(512, 512);

GL11.glTexCoord2f(0, 1);
GL11.glVertex2i(0, 512);
GL11.glEnd();

}
There is one line in there that I am not sure what it does "textureBuffer.order(ByteOrder.nativeOrder());" is it necessary?  I have also seen in various forums about this same topic, people using Byte arrays and setting the ByteBuffer to the array.  Would it be better to do this?  At the moment to change a pixel all I do is this:
Code: [Select]
textureBuffer.put(index, (byte) 255);would change either the r, g, b, or a value.

Thankyou.

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #6 on: September 28, 2012, 12:40:42 »
What are you doing that makes pixel-per-pixel manipulation so important? To get fast graphics, the overall goal is to send as little data as possible to the GPU (that is what we are doing with OpenGL) and make OpenGL as independent as possible.

However, the best way I know of to render stuff onto textures is via using FrameBufferObjects. It lets you render to textures just like the Display. You can draw primitives, render textured geometry, use shaders, etc. and the final result is saved to a texture for use elsewhere. Plus, it's MUCH MUCH MUCH faster than setting individual pixels on the CPU and then pushing the entire thing over to the GPU.

A tutorial on framebuffers can be found here: http://www.lwjgl.org/wiki/index.php?title=Using_Frame_Buffer_Objects_(FBO)

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #7 on: September 28, 2012, 12:45:24 »
There is one line in there that I am not sure what it does "textureBuffer.order(ByteOrder.nativeOrder());" is it necessary?
The textureBuffer.order(ByteOrder.nativeOrder()) code is not very necessary as long as you are just dealing with bytes. However, as soon as you start dealing with primitives that take up more then one byte (char, int, float, etc.) then it matters a lot. See http://en.wikipedia.org/wiki/Endianness for an explanation as to why byte order matters.

I have also seen in various forums about this same topic, people using Byte arrays and setting the ByteBuffer to the array.  Would it be better to do this?  At the moment to change a pixel all I do is this:
Code: [Select]
textureBuffer.put(index, (byte) 255);would change either the r, g, b, or a value.
I assume you mean setting the ByteBuffer to an array by using textureBuffer.put(byteArray). Depending on how many pixels you are changing each frame, this could be much faster as that version of the put() method is significantly more efficient for an entire array. Just make sure you don't create a new byte array each time, but reuse the same one and just re-put it each time (only changing the pixels you need). If you are changing a bunch of pixels each frame, I would suggest trying it to see if it is faster.

EDIT: CodeBunny beat me :P, but what he says is true. If you can avoid drawing individual pixels, drawing to a framebuffer is much faster.
« Last Edit: September 28, 2012, 12:49:07 by Fool Running »
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #8 on: September 29, 2012, 00:12:40 »
I need to be doing this because there are thousands of particles that need to be rendered to the screen each frame, plus other entities and necessary information like scoreboard etc.

no, I'm not using textureBuffer.put(byteArray), but the textureBuffer.put(index, byte).  At the moment, I initialise the byteArray so all pixels are black with an alpha of 255.  Every frame I change 25 pixels (100 indexes in the byteArray for RGBA) to a random colour using this code exactly:
Code: [Select]
int index = (int) Math.floor(Math.random() * mapWidth*mapHeight*4);
byte colour = (byte) Math.floor(Math.random() * 256);
textureBuffer.put(index, colour);
This method achieves ~880fps (1.13ms) rendering a 512x512 RGBA byteArray to the Display while changing 25 pixels (100 indexes) every frame.
If I change it to 500 pixels/frame(2000 indexes) I get ~730fps (1.37ms).
If I change it to 2500 pixels/frame(10000 indexes) I get ~430fps (2.33ms).
If I change it to 25000 pixels/frame(100000 indexes) I get ~80fps (12.5ms).

But this is without the other entities and so I will be doing more intermediate OpenGL rendering slowing it down further.

I think its time I learn how to use frame buffer objects.  It sounds like a pretty good idea to me haha.  I'll have a go at implementing that and let you all know how it goes!

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #9 on: September 29, 2012, 03:32:34 »
Wait a second...

Even if I use an FBO, I'll have to use a byteBuffer to render the particles to the FBO anyway!
I cannot seem to figure out how to set this up regardless, That tutorial really doesn't seem to explain it very well.

I know this is asking a lot, but would you be able to post a simple, bare minimum example of a frame buffer object rendering to the screen (containing a few quads, pixels, etc.)?

Thankyou very much.

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #10 on: September 29, 2012, 11:46:55 »
Wrong. You do not render anything with pixel-per-pixel calculations / bytebuffer manipulation. If you attempt to do so, the performance will be so god-awful that you'll not be realistically able to render anything.

There are techniques for rendering particle systems. Use those.

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #11 on: September 29, 2012, 11:58:22 »
I really am interested in learning, its just so damned hard!!!

What are these techniques you speak of? :)

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #12 on: September 30, 2012, 02:58:23 »
Yeah, I know.  :-\ The problem is that you're getting into the world of full-on game rendering; it's a really complicated, large, difficult topic. Really the best thing you can do is to realize that the only way you'll ever be able to easily do exactly what you want is to buckle down and spend a large amount of time learning the API and concepts behind it.

I'd recommend you do some general OpenGL rendering tutorials in LWJGL. Step back from your current project and get comfortable with drawing textured geometry / using viewports and managing the display / etc. There are a lot of "noob tutorials" on this topic - people usually point to NeHe, you could start there. That way, when you come back to your project, you'll have a much better understanding of what you need to do, and you'll probably do a better job of implementing it.

Re: Rendering a bufferedImage to a LWJGL Display
« Reply #13 on: September 30, 2012, 04:52:03 »
That is very good advice, and I do recommend it to anybody else reading this!

I am not new to the world of game programming, I previously coded in Actionscript 2.0 before moving on to AS3.  Java followed a couple years after, simply using Java2D which I really got stuck into, then c++ (which I never really got into).  Now I'm back to Java and want to use OpenGL as I was previously pushing it!

I will definitely check out the NeHe tutorials, but I believe they don't have anything on frame buffer objects.  I have scoured the internet looking for some tutorials on frame buffer objects in java/LWJGL (they are all in other languages which I find hard to port) but to no avail.

To NeHe!