swing offscreen rendering with simulated input - java

I am trying to do render a swing UI into an OpenGl texture. All that works so far is this piece of code (btw it is Scala, but it should be obvious)
var image = new BufferedImage( width, height, BufferedImage.TYPE_4BYTE_ABGR)
mainFrame.paint(image.getGraphics)
var outputfile = new File("saved.png")
ImageIO.write(image, "png", outputfile)
But those things are still missisg:
I need to be notified when anything in the swing components changes, so that I can update the glTextures when needed.
The rendering to a swing window should be disabled
A virtual mouse would be nice, so that I can use my projected mouse position on the texture
Dynamic keyboard processing, so that I can activate keyboard processing as long as the UI is active. Else I would use LWJGL input processing.
I think the best way to approach the first two issues would be a Decorator to the Graphics object used to draw all the swing components, but I did not find any way to implant my variation of that class into Swing.
I hope that's it. But if you know a library that has already solved my problem you are welcome, but please do not recommend TWL.

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());

Questions About The JavaFX Canvas

I have been writing a game in Java2D with Canvas for a while, And want to port it to JavaFX. I took a look at the JavaFX Canvas, And i have a few questions about it:
Currently, I have the game running on a separate thread from the application. The thread updates and renders the game. But with the JavaFX canvas, You cant draw to it unless it is on the JavaFX Application Thread. Do you know of any ways to get around this?
The Java2D Canvas has a BufferStratagy that can be used for triple buffering. But the JavaFX Canvas only has a built in double buffer. I am guessing it would be possible to write a triple buffer manually (I know how to do it with a double buffer). Can you explain how i could do this?
Would it be best just to stick with java2D instead of switching to JavaFX?
Thanks for your help. :)

saving bufferedimage to gif

I have an application that plots images on a JPanel. I want to dispose of the GUI altogether, so that the application is called from code only, with no user interface, and so that the images are saved to a gif file only.
I have experimented with code from this question, and it seems to work fine when I call the save gif code from within the old GUI. However, the save gif code is not seeming to work when I remove the GUI, and I am wondering if that might be because the JPanel it is trying to print has not actually made it to a GUI container like a JFrame, etc.
The reason I am not posting code is that it is too verbose, an I am just asking for a simple, boilerplate answer.
I have experimented with writeablerasters for other applications. But that would require a major recoding project for this application, which paints by using the graphics.drawLine() method. Can anyone suggest a code-efficient way to take contents of a "phantom" JPanel, get it into a BufferedImage, and then save it as a gif without ever putting the JPanel in a GUI?
Since your application draws on a JPanel then it just needs a Graphics object. You can use one from a BufferedImage which then you will save to file. Example code:
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
// Pass this graphics object to your application to perform the drawing
g.setColor(Color.red);
g.drawRoundRect(10, 10, 20, 20, 5, 5);
// save it to disk
ImageIO.write(image, "png", new File("test.png"));
This is difficult to answer without any example code, however.
If the component you are trying to render is not displayed on the screen, it is likely that it has not being laid out.
Before painting, you should make sure you size the component.
componentToBePainted.setSize(componentToBePainted.getPreferredSize());
You should also be using print or printAll over paint. When not attached to a native peer, paint can cause issue

JavaFX - painting a rgb array as an image

We are using vlcj to capture a webcam video and display it on the user screen. We capture it frame by frame, a 1280x720 image at around 30fps.
Our app UI is entirely JavaFX, and we are having problems displaying said frame.
Using Swing, we would do something like:
BufferedImage image; //create compatible image
public void onDisplay(int[] rgbBuffer){
image.setRGB(0,0,width, height, rgbBuffer, 0, width);
myJPane.repaint();
}
But JavaFX's Image class offers no such methods, and creating a BufferedImage just to convert it to a JavaFX Image (by using Image.impl_fromPlatformImage()) is highly costly.
Question: How does one create a JavaFX Image, that can be set to an ImageView, based on a rgb int[]? Is there a better (as in "faster") way to display it?
This functionality is not yet part of the JavaFX platform - for now I believe you have to use the BufferedImage method you are currently using.
You can track the feature Image Ops request. Anybody can sign up for a jira account and vote for the issue/add comments/detail use cases/etc or provide input to the design on the JavaFX development mailing list.

VolatileImage JFrame on multiple screens

I have a JFrame in which I am using Graphics2D to draw a VolatileImage using this tutorial. I have mainly copied the code to see how it works, but have slightly edited it for my game. I am running my computer with two screens.
The problem arises when I drag the window of the game onto the other screen which the window did not originally appear on. The window goes grey and no graphics are shown on screen, even the simple rectangles I have drawn with the Graphics2D. This only happens when I call for the draw method of the volatileimage as shown in the tutorial.
I believe it may have something to do with this...
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
...but I am not sure.
Any help would be greatly appreciated. It would also be interesting to know if VolatileImage is the way I should be going for my game or if BufferedImage or something else is a better method for performance and frame rate.
Yes, you are correct. VolatileImage is device-specific. From "The VolatileImage API User Guide" you can read:
A VolatileImage is device-specific: if you created a VolatileImage with one
GraphicsDevice, you might not be able to copy that VolatileImage to another
GraphicsDevice. For this reason, you need to call validate before attempting to copy the
VolatileImage.
and
If the code is IMAGE_INCOMPATIBLE then the VolatileImage is not
compatible with the current GraphicsConfiguration. This
incompatibility can occur if the image was created with one
GraphicsConfiguration and then drawn into another. For example,
in a multiple-monitor situation, the VolatileImage exists is
associated with a particular GraphicsConfiguration. Copying that
image onto a different GraphicsConfiguration could cause
unpredictable results. To correct this problem, you need to create a
new VolatileImage that is compatible with the current
GraphicsConfiguration
When dragging your frame to another screen device you need to check the result from the VolatileImage.validate(gc) method of your and recreate the image to the new device. Note that there are cases when you cannot create a VolatileImage, in those cases you need to fall back on another Image implementation like BufferedImage.

Categories

Resources