I'm looking for some method to draw half transparent figures within the draw2d framework.
Currently I'm using setAlpha() of org.eclipse.draw2d.Graphics. The problem is that it slows down the whole UI, if I draw more than one half transparent figure.
Here was another question regarding the perfomance of it [1]. It targets SWT on Linux, I target both Linux and Windows. The windows (Win7) system has a 3D capable graphic card and a i7 q720. The Linux machine is even better equipped and has also 3D, so I think it's not a performance issue of the platform.
My question is: Is there a performant way to achieve alpha blending in draw2d?
I've tried to use OpenGL respectivly LWJGL. Since draw2d and OpenGL can't be mixed up and I must rely on draw2d, I thought I could do something like this: draw2d -> OpenGL -> draw2d
here where canvas is the Canvas where the OpenGL drawing happens and c1 is the Canvas where I want to get the drawn OpenGL picture. But my attempt to copy the OpenGL drawings doesn't work it gets me just the underlying Canvas (canvas) background. Besides this I'm not sure if this would improve the "perormance" anyway...
Thanks,
atx
This issue is known but unsolved. On the mailing list of draw2d there is a thread regarding this issue: mailing list
TL;DR: A possible solution was dropped because of license issues between LWJGL and Eclipse.
Make sure all your src/dest images are of the same depth (eg. ARGB)
Otherwise, expensive conversions happen during copy (src->dest)
GCs don't allow access to their underlying buffers, afaik.
MemoryImageSource might be a way to go.
You can grab your OpenGL drawing images using something like:
BufferedImage capture = new Robot().createScreenCapture(new Rectangle( canvas.getX(), canvas.getY(), canvas.getWidth(), canvas.getHeight() ) );
Kind of fiddly, but very fast.
I use it to save jpegs of my live animation frames to a folder.
VirtualDub then creates a movie from the frames. Have to play with the frame rate ;)
Great for producing youtube teasers!
You can see one here!
Related
I'm developing an app that will connect to (my own) oscilloscope, read data via USB and display plots - so just normal oscilloscope.
USB is ok, now I have to draw the graphs.
As you know (or not) in oscilloscope there are really fast-changing signals, so I have to render graphs really fast.
So I'm looking for a fast way to do it.
I've read that GLSurfaceView uses OpenGL and GPU so it is used for games, but will I benefit from it in my project?
GL is really complicated (to draw a square or just lines, not to mention about text...) while SurfaceView has its Canvas so it's much easier.
I really care for performance, but have not much time and nerver used OpenGL so what do you think?
It is complicated, but you will benefit from GLES when using a SurfaceView.
Canvas on SurfaceView is not hardware-accelerated, so on some devices you'll have trouble hitting 60fps. (See for example the "multi-surface test" in Grafika. Tap the "bounce" button to cause it to animate. On some devices it'll do 60fps, on others it won't hit 30fps.)
One alternative would be to create a custom View. That way the rendering would be accelerated by hardware.
1) Re-Draw Vs Draw
Kind of a philosophical question, but... what is the "correct" or "accepted" way to render a game (2d, I understand how OGL perspecives work...) at different resolutions? Should I include separate sizes for my images (like Android APKs) and resize each object individually at draw on one canvas, or should I draw on a set-resolution drawing canvas, then resize that image onto another display canvas? I'm speaking generally, but, if you need me to be specific I'm using Java to build the engine.
Foreseeable benefits/issues:
#1) Resize at Draw
+ No additional drawing step
+ Sweet resolution
- Possible math/physics/placement issues
- Tons of math each step for scale
- Lots of resources
#2) Resize at Render
+ No additional math; one step
+ One set of images; smaller res. package
+ One set canvas size (easier to do math/phys./placement)
- Additional drawing step
- Poor resolution =(
It would seem that #2 is the obvious choice because of the number of benefits vs issues, but... is it? Is there a standard way to resize 2D games?
2) JOGL + Java2D + Java Swing
Would it be cumbersome to use JOGL, Java2D, and Java Swing at the same time? Would it be worth it to do 2D or layouts in JOGL? Why or why not?
EDIT: Using a BufferedImage to draw on and rendering the BufferedImage to the size of the panel with respect to aspect ratio is incredibly inefficient in swing. Apparently it's better to draw immediately to the panel, while resizing each image/element individually. Not my first hypothesis...
EDIT 2: Silly me... just scale and translate the graphics context to the size of the adjusted resolution before any other operations. The performance boost is super-dooper awesome. THIS is the correct answer to the question. DRAW ONCE, to scale/translation. B)
I can't answer your second question fully as I do not have much experience with JOGL or Java2D, but I don't see any reason for them to ever conflict or be cumbersome.
For your first question, I can definitely say that it depends. What's your target audience? Is your game memory intensive (Ever notice that many games have a high res/low res option)? Is this a game that will be available for vastly different screen sizes? If so you might want to provide 2-3 different "packages" of your assets, each scaled at a different size of the original (the largest one). The math to draw the images isn't as much as you think.
In addition:
If you build the game the right way, you wouldn't have to do much math at all. If you have some sort of Camera class that takes care of the viewing of your GameWorld then you simply have to scale the Camera's image instead of scaling each image independently.
You see that ?
Each brick of each house is an image of 16x16 pixels.
What you can see here a version based on simple JavaFX, with some Imageview moved on X and Y to give the effect of "construction".
I just adapt this to Swing using paintComponent.
The problem:
- With JavaFX: my computer has trouble. What you see on the picture took 2 seconds to load and it is then moving very slow and jerky.
- With Swing: I do not know how to adapt each block according to brightness, shadows, etc.. So it looks like this:
What method should I chose? Both have major drawbacks. I would have liked to keep the JavaFX method but also to find something else than Imageview. It should not be a good idea.
For information on Swing optimizations and implementations, see other answers as my answer is JavaFX specific.
Should you stick with a JavaFX implementation, here are a couple of things to try:
Use node.setCache(true) to switch on node caching.
Use node.setCacheHint(CacheHint.SPEED) to enable high speed node transforms.
Provide an implementation with no effects and another with effects and see if the one without effects performs noticeably better. (If that's the case you may need to use a more efficient effect chain or forgo some effects altogether).
Check the JavaFX system requirements to ensure that your setup meets the minimum requirements for hardware acceleration in terms of hardware/os/driver combinations.
If you are using Regions and css based processing be careful that the css system is not causing too much overhead (by, for example, having a version of the code which does not use css and comparing it's performance).
If needed, implement a level of detail zoom, (e.g. when zoomed out provide a single image for the entire house rather than a separate image for each house tile).
Make sure you are only loading a given Image once and reusing it in multiple ImageViews.
Use a profiler to identify bottlenecks.
Vary the test cpu or graphics card to see if either of those are a bottleneck.
Try a Java 8 preview, which features many internal performance optimizations for JavaFX.
If you are loading a lot of images, use background loading and have an animation or progress bar playing in front while the images are loading.
If you are loading lots of images, scale them upfront in the Image constructor so that they don't take up too much memory or require (potentially) extra processing power for the extra pixels (only really a consideration if you are using a lot of different very high resolution textures - which you don't seem to be doing).
For example:
Image tile = new Image("tile.png");
Group house = new Group();
house.setCache(true);
house.setCacheHint(CacheHint.SPEED);
Effect lighting = new Lighting();
for (int i = 0; i < houseWidth; i++) {
// here is the critical part => don't do new ImageView(new Image("tile.png"))
ImageView tileView = new ImageView(tile));
tileView.setEffect(lighting);
tileView.setCache(true);
tileView.setCacheHint(CacheHint.SPEED);
house.add(tileView);
}
Mantrid's suggestions are interesting. I do believe that, with JavaFX you don't need to implement a dirty rectangle algorithm yourself (as the underlying platform is able to take care of dirty region processing for you). It may be that, because it is a generic mechanism, it isn't providing the level of optimization required for your specific case, in which case you need to handle the dirty processing yourself (e.g. by removing nodes from the scenegraph and re-adding them as appropriate).
Additionally, pre-calculating the blur/brightness/etc on the images could be done by defining effects in JavaFX, applying the effects to an offscreen ImageView node, then taking a snapshot of the offscreen ImageView node to get a pre-calculated image. This technique would allow you to reuse your existing JavaFX effects pipeline without the need to re-implement it using the ConvolveOp mechanism. Perhaps you may get the same performance level by just setting cache to true and cacheHint to speed on the ImageView nodes, as I believe this does a similar kind of thing behind the scene (i.e. increases speed at the cost of increased memory usage).
The JavaFX scenegraph is pretty efficient and can handle thousands of nodes. However, you may have more than that in your application. If the above optimization points don't help you, you may want to calculate your node count and post a reference to your question (and perhaps some source) to the open-jfx mailing list where the JavaFX developers who know the details of JavaFX application optimization are.
JavaFX 8 has far better support for 3D scenegraphs in than the (mostly useless) 3D scenegraph in JavaFX 2.2. It seems that your current application is psuedo-3d where you transform 2D objects, individually apply lighting effects and adjust the brightness of each tile to get a 3D look. If that's the case, using a fully hardware accelerated 3D scenegraph with a unified 3D lighting model may end up performing better, looking better and being easier to work with - you would have to evaluate it in the context of your application to see if it is worth switching your app from a 2D JavaFX scenegraph to a 3D JavaFX scenegraph or from JavaFX to Swing or some other tech like libgdx.
Addendum
Answers to some of Mizur's additional questions:
So why are they so power-consuming?
As can be seen from my answer, there are many aspects that go into performance, so singling out one particular reason as to why something is power-consuming is sometimes difficult and often not possible. Sometimes it is a combination of things which contribute to performance issues. The biggest wins usually come from optimizing stuff executed in inner most loops or by changing the strategy used to solve a problem.
If they need so much, please let me move tiles, or please just be displayed, no?
In terms of only consuming resources for the stuff you move, the JavaFX scenegraph has some optimizations for that and things like the cachehints can further improve performance for that. Perhaps they aren't enough for your particular use case or the way in which you are using the system. You may need to change your algorithms to reduce the system load.
Is there a way to generate images of each building with this technique of Imageview, then to integrate these images of buildings in the final scene?
Yes - you could render a building to an offscreen scene using many images and nodes, snapshot the offscreen scene to create a single image, then overlay that image over your final scene.
modifying blur/brightness/etc on the images before they are drawn
I haven't used it myself, but here's a hint - use Swing/AWT Kernel+ConvolveOp mechanism: http://www.java-tips.org/java-se-tips/java.awt.image/styling-digital-images-with-convolveop.html
BufferedImage biSrc = ...
BufferedImage biDest = ...
float[] data = new float[] { 0.0625f, 0.125f, 0.0625f, 0.125f, 0.25f, 0.125f, 0.0625f, 0.125f, 0.0625f };
Kernel kernel = new Kernel(3, 3, data);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
convolve.filter(biSrc, biDest);
operations are defined via a 3x3 matrix (data). you can do a search for examples for brigthness, blur etc.
the picture took 2 seconds to load but it is moving very slow and jerky after
use Dirty Rectangles algorithm: Dirty Rectangles
I want to be able to draw consecutive bitmaps (of type BufferedImage.TYPE_INT_RGB) of a video as quickly as possible in java. I want to know the best method in doing so. Does anyone have any advice where I should start? From what I've read, 2 options are:
1) Use GDI/GDI+ routines in a JNI dll working with JAWT (Im on Windows)
2) Use Java3D and apply Textures to a Box's face and rotate it to the camera
Im interesting in any advice on these topics as well as any others.
I have done a decent amount of GDI/GDI+ programming in VB when i created an ActiveX control, so using GDI should be painless, but im guessing Java3D will utilize the GPU more (I could be wrong) and give better performance. What do you think? GDI and JAWT with my previous experience, or start and new API journey with Java3D.
Thanks in advance. :)
To obtain a fluid animation (if it what you want to get), you need to use double buffering. For doing this, you will need to create a new java.awt.Image (or a subclass like BufferedImage, or if you want OpenGL accelerated processing, VolatileImage) for each frame you want to display. If you haven't already done so, call Image.getGraphics() to get a java.awt.Graphics object (can also be useful to add your content to the Image). At the end, when you hidden Image is complete, call Graphics.draw() to replace the current display smoothly.
VolatileImage is OpenGL accelerated and much faster. When VolatileImage.getGraphics() is called, it actually returns a Graphics2D, which is also part of the accelerated graphic pipeline.
It works on Windows, Linux and Solaris, but you need to have OpenGL drivers installed for your graphic card.
Some additional refs:
Accelerated graphic pipeline:
http://download.oracle.com/javase/1.5.0/docs/guide/2d/new_features.html
http://www.javalobby.org/forums/thread.jspa?threadID=16840&tstart=0
Double buffering:
http://www.java2s.com/Code/Java/2D-Graphics-GUI/Smoothmoveusingdoublebuffer.htm
http://www.heatonresearch.com/articles/23/page2.html
http://www.javacooperation.gmxhome.de/BildschirmflackernEng.html
I'm trying to create thumbnails for uploaded images in a JRuby/Rails app using the Image Voodoo plugin - the problem is the resized thumbnails look like... ass.
It seems that the code to generate the thumbnails is absolutely doing everything correctly to set the interpolation rendering hint to "bicubic", but it isn't honoring them on our dev environment (OS X), or on the production web server (Linux).
I've extracted out the code to generate the thumbnails, rewritten it as a straight Java app (ie kicked off from a main() method) with the interpolation rendering hint explicitly set to "bicubic", and have reproduced the (lack of) bicubic and bilinear resizing.
As expected on both OS X and Linux the thumbanils are ugly and pixelated, but on Windows, it resizes the images nicely with bicubic interpolation used.
Is there any JVM environment setting and/or additional libraries that I'm missing to make it work? I'm doing a lot of banging of head against wall for this one.
I realize this question was asked a while ago, but incase anyone else is still running into this.
The reason the thumbnails look like ass are caused by two things (primarily the first one):
Non-incremental image scaling in Java is very rough, throws a lot of pixel data out and averages the result once regardless of the rendering hint.
Processing a poorly supported BufferedImage type in Java2D (typically GIFs) can result in very poor looking/dithered results.
As it turns out the old AreaAveragingScaleFilter does a decent job of making good looking thumbnails, but it is slow and deprecated by the Java2D team -- unfortunately they didn't replace it with any nice out-of-the-box alternative and left us sort of on our own.
Chris Campbell (from the Java2D team) addressed this a few years ago with the concept of incremental scaling -- instead of going from your starting resolution to the target resolution in one operation, you do it in steps, and the result looks much better.
Given that the code for this is decently large, I wrote all the best-practices up into a library called imgscalr and released it under the Apache 2 license.
The most basic usage looks like this:
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 640);
In this use-case the library uses what is called it's "automatic" scaling mode and will fit the resulting image (honoring it's proportions) within a bounding box of 640x640. So if the image is not a square and is a standard 4:3 image, it will resize it to 640x480 -- the argument is just it's largest dimension.
There are a slew of other methods on the Scalr class (all static and easy to use) that allow you to control everything.
For the best looking thumbnails possible, the command would look like this:
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY,
150, 100, Scalr.OP_ANTIALIAS);
The Scalr.OP_ANTIALIAS is optional, but a lot of users feel that when you scale down to a small enough thumbnail in Java, some of the transitions between pixel values are a little too discrete and make the image look "sharp", so a lot of users asked for a way to soften the thumbnail a bit.
That is done through a ConvolveOp and if you have never used them before, trying to figure out the right "kernel" to use is... a pain in the ass. That OP_ANTIALIAS constant defined on the class it the best looking anti-aliasing op I found after a week of testing with another user who had deployed imgscalr into their social network in Brazil (used to scale the profile photos). I included it to make everyone's life a bit easier.
Also, ontop of all these examples, you might have noticed when you scale GIFs and some other types of images (BMPs) that sometimes the scaled result looks TERRIBLE compared to the original... that is because of the image being in a poorly supported BufferedImage type and Java2D falling back to using it's software rendering pipeline instead of the hardware accelerated one for better supported image types.
imgscalr will take care of all of that for you and keep the image in the best supported image type possible to avoid that.
Anyway, that is a REALLY long way of saying "You can use imgscalr to do all that for you and not have to worry about anything".
maybe is this a solution for you:
public BufferedImage resizeImage(BufferedImage source, int width, int height)
{
BufferedImage result = new BufferedImage(widht, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = result.getGraphics();
g.drawImage(source, 0, 0, widht, height, null);
g.dispose();
return result;
}
In the end, upgrading to the latest version of ImageVoodoo seemed to improve quality.
Looking through the source code, it looks like they're doing some funky AWT rendering, and then pulling that out. Nasty, but it seems to work.
Still not as good as ImageMagick, but better than it was.
#Riyad, the code for incremental scaling isn't "decently large", it's quite small (As you can see from a post back in 2007, http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html#creating-scaled-instances) having a library that gives other options might be useful, but making a library to use a library is nonsense.