Great news everyone ! I finally have some time to speak about programming ^^
So I will talk about a replacement for Java 2D graphics I made for my engine: GraphicsRenderer.
I made a replacement for Java2D graphics object a while ago as I thought it was missing some functionalities, and I was wondering if I could get something quicker, without using lwjgl.
I did not want to use lwjgl because I wanted my game to work on an applet, without security warnings, so I wanted a pure java solution. Now that Snorms is a downloadable game, I don’t care about that anymore, but I am still using it as it’s working quite well. Maybe I’ll change that in the future, I don’t know…
Some of the things I did not like about Java2D:
- It is quite slow when displaying hundreds of images
- Applying effects is not easy
- I didn’t need the scaling algorithms
So I tried to implement my own Graphics equivalent: GraphicsRenderer, and I was quite surprised by the results.
The GraphicsRenderer library is licensed under an Apache 2 license meaning but you can do almost whatever you want with it (modify/copy/sell/…)
Of course it’s very hard to benchmark something like that, so I’ll just take a small example. But to be honest, you have to try it, I’m pretty sure there are situations where Java2D is quicker, and others where my implementation is quicker.
In Snorms I tested my implementation in a real situation, I did a simple wrapper, and launched lots of tests to see the difference. In snorms my implementation was around 50% quicker than Java2D (for pure graphical operations).
So to make things easier, I will take for example a simple application that displays randomly in its window 100 000 times the same image. And I measure time taken. I’ve tested this under Windows XP, Linux/Oracle JRE and Linux/OpenJDK. The results for Linux/Oracle JRE are:
- GraphicsRenderer: 274 ms
- Java2D: 607 ms
So in this test case my implementation is 2.2 times quicker than Java2D (same results on other platforms), but of course this is a limited test, and as I said before, I did not need the scaling algorithms from Java 2D, so my implementation does not use them.
Of course my implementation does not use hardware acceleration for blit operations (drawing image), still it’s quicker than Java2D, but I wonder if Java2D is really using hardware acceleration on my test platforms…
GraphicsRenderer was thought to be easily wrapped around Java2D Graphics, so some functions have similar signature, and its primary use is the same.
GraphicsRenderer is a place to draw things in it, you can draw lines, circles,.. and insert images. When creating it you can specify an Java Image as the source, so that when modifying the GraphicsRenderer it will also modify the source image.
BufferedImage image = createCompatibleImage(800, 600, true); GraphicsRenderer gr = new GraphicsRenderer(image);
You can also create one directly from scratch
GraphicsRenderer gr = new GraphicsRenderer(800,600);
But in this case, in order to display it you will need to transfer it to a compatible display (ie. another GraphicsRenderer)
Then you can play with it:
- Drawing a line: public void drawLine(int x1, int y1, int x2, int y2)
- Filling a rectangle: public void fillRect(int x, int y, int width, int height)
- Inserting an image: public void drawImage(Image img, int x, int y, [...])
Functions are mostly documented, just take a look at the source code for more information.
I don’t like the way Java2D add effects, I thought of another way to do it: before drawing something, you specify which effects you want to be applied on next operations.
This solution is easy to understand, for example if you want to insert an image at 50% opacity, then you specify the opacity (0.5f) and finally you insert the image. The downside is that a single GraphicsRenderer is not multi thread compliant, which is usually not a big deal because you usually deals with more than one GraphicsRenderer.
Effects / Opactiy
public void setOpacity(float opacity)
All operations will be performed using the specified opacity, for example if you want to draw an half-visible line, then you set the opacity to 0.5f and draw the line
Effects / Light
public void setLight(float r, float g, float b) public void setLight(float darker) ...
At first this effect was used to make things darker, then I added color components for nicer effects.
Effects / Add color
public void setAddColor(Color addColor) public void setAddColor(int addColor)
This function add color components, it works almost like the light effect, except that instead of multiplying color components, it adds them to the image. Mostly used for some special effects, and Font coloring.
- Some functions are not completed, for example you can’t fill ellipse, just circles.
- Some functions are not well optimized, I have mainly worked on the blit operation (drawImage), others might be unoptimized yet
- No scaling algorithm at all, I usually create a temporary Java2D graphics to do that
- GraphicsRenderer provides a simple caching system from BufferedImage, but it is best to implement your own as current system involves keeping the BufferedImage and the cache in memory.
- Source images alpha mask is not working (binary opacity is used). It shouldn’t be too hard to implement though.
- I need to change the drawImage, in order to provide more functions according to effects to be applied, at the moment only two are provided, one with all effects, another when no effects are applied. I will update this soon.
You can download the source files here: download GraphicsRenderer library
The zip files contains the GraphicsRenderer.java library file, and a small usage example/benchmark.