Clear and reuse a Canvas, or create new object? - java

My setup:
I have a GWT Canvas that displays some grafics that rely on heavy algorithms. The objects are dragable, and therefore on drag I save everything beside the dragged object on a temporary canvas and reuse this as an image behind the dragging context.
My question:
My drag canvas is a reused Canvas object, that has first to be cleared before saving the static context to it before dragging starts.
I wonder if "reuse and clear" is better than "create a new canvas object".
What do you think?
Either clear canvas everytime:
private Canvas canvas;
void buffer() {
canvas.getContext2d().clearRect(0, 0, Window.getClientWidth(), Window.getClientHeight());
//...draw
}
...or create new object:
void buffer() {
Canvas canvas = Canvas.createIfSupported();
//draw
}

"Reuse and clear" is superior. It is more efficient since it only calls the native clearRect(x, y, w, h). There are many events that fire during the addition and removal widgets. I would use a new object only if it were a logical concept. You may also want to consider Lienzo.

Related

Are layers the only way to composite graphics on JavaFX canvas?

I am working on a gui in JavaFX which needs to composite a large number of objects (often using alpha masks and similar) on the canvas.
For comparison on the HTML5 canvas this can easily be done by the drawImage function with the help of a temporary canvas object outside the DOM structure. For example to draw an image on the canvas with an alpha mask, I first draw the image on the temporary canvas, draw (i.e. blit) the mask over it using globalCompositeOperation = "destination-in", then draw the temporary canvas on the original one using composite mode source-over. The temporary canvas can be re-used for each such operation. Easy as pie.
However, from what I can see so far the recommended way of doing this in JavaFX is the use of grouped layers, i.e. multiple overlayed canvas nodes which never get "flattened".
I could have done it like this in HTML5 too but in my most recent project this would have resulted in dozens or hundreds of visible layers which is obviously extremely silly. My approach gave me excellent performance.
That being said, is there a reasonable way to do the same thing on the JavaFX canvas? I consider manually performing pixel-by-pixel copying to be a clunky last-resort thing.
What am I missing? Am I thinking about JavaFX in a wrong way?
I have done this before on JavaFx and Android I didn't know they do so on HTML 5
so anyway
you can do the same as you do on HTML 5 you can create what is called mainCanvas that canvas contains the finished version of another one let's say tempCanvas in the temp canvas you draw what ever you want and apply the masks you want too then you take a snapshot of the canvas ( as Canvas is a Node you can use this code to take a snap shot of it)
WritableImage writableImage = new WritableImage(mainCanvas.getWidth(), mainCanvas.getHeight());
tempCanvas.snapshot(null, writableImage);
GraphicsContext context = mainCanvas.getGraphicsContext2D();
context.drawImage(writableImage,mainCanvas.getWidth(), mainCanvas.getHeight());

Drawing dynamic primitives in Java SWT

I have a C++/Qt background and am now learning Java and SWT GUI programming. I need to draw some primitive shapes (circles, rectangles, etc.) on an image. The shapes need to move on the image (ie. change its position in relation to the background, imagine a real-time updating map). In Qt this could be easily done by using QGraphicsScene and QGraphicsItems but how to achieve this in SWT? I have tried to use Composite with Label which is close to what I need but I haven't found a way to add primitive shapes to the Composite.
The Canvas control is specifically for drawing on. Basic drawing operations are in the GC class.
Canvas drawWidget = new Canvas(composite, SWT.NONE);
drawWidget.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
drawWidget.addPaintListener(new PaintListener() {
#Override
public void paintControl(final PaintEvent e) {
Rectangle r = drawWidget.getClientArea();
e.gc.drawOval(0, 0, r.width - 1, r.height - 1);
}
});
Call the Canvas redraw method to request that the control be redrawn. This will call the paint listener again.
Other Eclipse packages such as Eclipse GEF provide much more sophisticated drawing APIs.

Best practice to use Sprites in a game using AndEngine GLES2

Currently I am having static reference to all my sprites and loading and initializing them in my OnCreateResource mthod of SimpleBaseGameActivity, But now I have to override onAreaTouched listener on spirtes and the way I can override it while Initializing the Sprite. But I have a static method creating Atlas and Texture Region for every sprite. And I am using these sprites in my scene class and I want to override onAreaTouched there. I can registerTouchArea for that specific sprite in my scene so that can be done But I want to Override OnAreaTouched in a way so that Code reusability can be done.
Here is how I am currently creating and loading sprites.
defualtCageSprite = createAndLoadSimpleSprite("bg.png", this, 450, 444);
And this is my Method createAndLoadSimpleSprite.
public static Sprite createAndLoadSimpleSprite(String name,
SimpleBaseGameActivity activity, int width, int height) {
BitmapTextureAtlas atlasForBGSprite = new BitmapTextureAtlas(
activity.getTextureManager(), width, height);
TextureRegion backgroundSpriteTextureRegion = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(atlasForBGSprite, activity, name, 0, 0);
Sprite sprite = new Sprite(0, 0, backgroundSpriteTextureRegion,
activity.getVertexBufferObjectManager());
activity.getTextureManager().loadTexture(atlasForBGSprite);
return sprite;
}
Now How Can I override onAreaTouched for some sprites while not losing the code reusability.
Is there any reason you need to load the textures at runtime? The normal way is to load the required textures all onto a single atlas while loading the application so that you can then quickly use them later.
As for the code reusability, Todilo's idea about enums seems to be pretty much what you need. Say for example that you have two kinds of objects - objects that disappear when you touch them and objects that fly up when you touch them. You enumerate both categories and put a piece of code into the touch event handling code that checks whether the object should disappear or fly up.
If you don't know what the objects should be doing on touch before running the application, there is a more dynamic way of achieving the same result. Just create two lists at runtime and put a reference to the object in one of the lists according to what the object should do when touched. Then in touch event handling do something like this:
if (disappearList.contains(touchedObject)) {
disappear(object)
}
if (flyUpList.contains(touchedObject)) {
flyUp(object)
}
Too bad AndEngine does not allow users to set listeners on sprites, it would make things a bit easier.
EDIT:
Added explanation of the use of BlackPawnTextureBuilder:
Your Atlas must be of type BuildableBitmapTextureAtlas, then you add all textures like this
BitmapTextureAtlasTextureRegionFactory.createFromAsset(buildableAtlas, this, "image.png"));
and after that
try {
this.buildableAtlas.build(new BlackPawnTextureBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(1));
} catch (final TextureAtlasSourcePackingException e) {
Debug.e(e);
}
I don't know whether this will work for animated Sprites or not, you will have to try it.
Also, there is no overriding onTouch, you will have to do that in the onAreaTouched method. One example of such condition is
if (pSceneMotionEvent.getAction() == MotionEvent.ACTION_DOWN && disappearList.contains(pTouchArea)) {disappear();}
Are you sure you dont want more functionality than override ontouch? How about creating a class inheriting for sprite for those that need onarea to be overriden and all other needs.

Is this bad practice? Multiple Graphics2D Objects

I've created a JPanel canvas that holds all graphics; namely JLabel. To get animated sprites to work you have to over ride the paintComponent of the extended JLabel class. I've successfully implemented animated sprites this way.
Is it bad practice to have a Graphics2D canvas and then have multiple 'images' in their own Graphics2D?
I don't think it will be too much heavyweight since the Graphics2D of your JPanel should be the same one that is passed to the JLabel but with different bounds and offsets.
What I mean is that Swing doesn't allocate a new graphics context on which you can display for every element inside a hierarchy of objects but it uses the same with different capabilities. This doesn't mean that panel.getGraphics() == label.getGraphics() but neither they are completely different obects.
In any case, if you need to do much animated work I would suggest you to have your own sprite class
class Sprite
{
Point2D position;
Rectangle2D size;
float rotation;
}
and handle everything at the same paintComponent level. Or at least I've always did that way since Java2D is not like CoreAnimation that is made to be used on a per-layer basis for moving/animated content.

How to wait until JComponent is fully painted?

I need a way to wait until a (Swing) JComponent is fully painted. This actual problem arises from an openmap application: The task is to draw a map (mapBean) with a couple of layers and create an image from that map.
Unfortunatly, and it's clearly documented, the image formatter takes the current state from the map to create the picture, and there's a chance, especially when maps become complex, that the formatter ist called before the mapBean, a JComponent, is painted.
Although explained with this openmap application, the problem is quite general and supposedly Swing related. Right now, I just wait a fixed time (one second) but that does not eliminate the risk of creating incomplete maps...
Edit
Some more details - I have to start with constructing a (OpenMap) MapPanel, which internallz creates a MapBean (JComponent subclass) and a MapHandler. Then I feed the MapHandler with geographical Layers and the Framework starts painting the geographical data 'on' the JComponent type MapBean.
After adding all layers to the Map, I use another framework class to create a JPG image (or: the byte[] that holds the image data). And this can cause problem, if I don't wait: this 'image creator' creates the image from the current state of the map bean, and if I call this 'image creator' to early, some map layers are not painted and missing. Pretty annoying...
java.awt.EventQueue.invokeLater will allow you to run a task after the paint operation has finished. If it is doing some kind of asynchronous load, then it will be API specific (as MediaTracker does for Image).
You might also try using an off screen buffer to render your image in:
MapBean map = new MapBean();
map.setData(...);
BufferedImage bi = new BufferedImage(...);
map.paintComponent(bi.getGraphics());
writeToFile(bi);
It sounds like you need to synchronize updating your JComponent's underlying data with Swing's paint cycle. You can subclass your JComponent and decorate the paintComponent() method, you might also look at ImageObserver.imageUpdate(), though I'm not sure if that is going to tell you what you want.
public class DrawingCycleAwareComponent extends MyOtherJComponent {
private final Object m_synchLock = new Object();
protected void paintComponent(Graphics g) {
synchronized (m_synchLock) {
super.paintComponent(g);
}
}
protected void updateData(Object data) {
if (SwingUtilities.isEventDispatchThread()) {
reallySetMyData(data); // don't deadlock yourself if running in swing
}
else {
synchronized (m_synchLock) {
reallySetMyData(data);
}
}
}
}

Categories

Resources