0

I'm currently working on a project using libgdx. As im tired of bad UI-libraries, I would like to use HTML, CSS and JS.

On my first attempt, I tried java-chromium-embedded and also managed to integrate it into my project. With a few reflections I was able to get the bytebuffer of the browser and render it on top of my game. The problem is that there is only a precompiled win 64 version, but I would also like to support other platforms.

As I wasn't able to compile chromium by myself, I took a look at the javafx Browser. It seems to be much more complicated than the java-chromium-embedded java code so that I wasn't able to get the bytebuffer. Maybe someone could help me, finding the bytebuffer.

I am currently searching in:

  • com.sun.webkit.WebPage

    • public void paint(WCGraphicsContext gc, int x, int y, int w, int h)

    • private void paint2GC(WCGraphicsContext gc)

  • com.sun.webkit.graphics.WCRenderQueue

But there are so many buffers and lists of buffers, that I don't now where the "real" bytebuffer is.

1 Answers1

0

Using undocumented com.sun APIs is not recommended.

Instead you could snapshot the WebView Node, and use a PixelReader from the snapshot Image to get a pixel Buffer.

I am not sure if that is exactly what you are trying to do. There are probably other ways to achieve what you want (such as overlaying windows rather than working with buffers).

Here is an example of continuously taking snapshots of an animated WebView node (playing a video) into an ImageView.

The top of the image is the original web view. The bottom of the image is a snapshot of the original image with a frame-rate overlaid (approx 60fps when run on a Retina MacBook when the original source WebView is sized to full-screen). The W and H values in the sample code can be modified to check performance for different image capture sizes.

big buck

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class VideoPlayerWithFrameByFrameSnapshot extends Application {
    private static final int W = 800;
    private static final int H = 400;

    private final long[] frameTimes = new long[100];
    private int frameTimeIndex = 0 ;
    private boolean arrayFilled = false ;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        // create a WebView
        WebView webview = new WebView();
        webview.setMinSize(W, H);
        webview.setPrefSize(W, H);
        webview.setMaxSize(W, H);

        // create an image viewer for a WebView snapshot
        WritableImage image = new WritableImage(W, H);
        ImageView imageview = new ImageView(image);

        Label framerateLabel = new Label();

        // continuously snapshot the webview and measure current framerate.
        AnimationTimer timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                webview.snapshot(null, image);

                long oldFrameTime = frameTimes[frameTimeIndex] ;
                frameTimes[frameTimeIndex] = now ;
                frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length ;
                if (frameTimeIndex == 0) {
                    arrayFilled = true ;
                }
                if (arrayFilled) {
                    long elapsedNanos = now - oldFrameTime ;
                    long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
                    double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
                    framerateLabel.setText(
                        String.format(
                            "Current frame rate: %.3f", 
                            frameRate
                        )
                    );
                }
            }
        };

        // start the snapshot process once the web view load succeeds. 
        webview.getEngine().getLoadWorker().stateProperty().addListener(
            (observable, oldValue, newValue) -> {
                System.out.println(newValue);
                if (Worker.State.SUCCEEDED == newValue) {
                    timer.start();
                }
            }
        );

        // load up the big buck bunny video. 
        webview.getEngine().load(
                "http://camendesign.com/code/video_for_everybody/test.html"
        );

        // layout the scene. 
        VBox layout = new VBox(
                webview,
                new StackPane(
                        imageview,
                        framerateLabel
                )
        );
        StackPane.setAlignment(framerateLabel, Pos.TOP_LEFT);

        stage.setScene(new Scene(layout));
        stage.show();
    }
}

Framerate measurement code comes from James_D's answer to:

As an aside: If you want to make a game with a pure HTML UI, then I don't understand why you would involve libgdx and wish to access low level drawing primitives for capturing the graphic output of an embedded browser (rather than just displaying the HTML UI in the user's default browser or directly in an embedded browser you ship with your game), but I guess you have your reasons for pursuing this approach. In the future I will try to refrain from attempting to answer questions where the motivation and objective is quite unclear. It's not a bad question, it's just a question for which I don't think I can be of much assistance.

Community
  • 1
  • 1
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • The Problem here is, that snapshot it is too slow, as I need 60 fps for my game. – Schwuchtelini Jun 18 '15 at 13:07
  • How do you know the snapshot is too slow, did you try it? Why do you need to take a snapshot every game frame anyway? Most web content is static and doesn't change much. Also if you are loading the web content over the network or using lots of JavaScript, most of the delay will be due to network loading or JavaScript processing. Do you have animated content in a web page that you are trying to snapshot and overlay on your game screen? What is the pixel size of the page? If there are constraints on your problem, you should always try to list those constraints in your question. – jewelsea Jun 18 '15 at 17:32
  • Also check that you are using an appropriate [PixelFormat for image data](https://community.oracle.com/thread/2436712) as that can have a bearing on the performance of these kinds of operations. – jewelsea Jun 18 '15 at 17:36
  • Yes, snapshot was actually my first attempt. I bench marked the whole snapshot to bytebuffer process and it came out, that just the method snapshot was the one which made it slow. I want to make the WHOLE GAME UI with HTML. Therefore I am loading local html-files into the browser. The size of the page will be the size of the player's monitor. PS: I already get 60fps with java chromium embedded and can e.g. watch youtube videos. – Schwuchtelini Jun 18 '15 at 20:01
  • OK. Seems like I called the snapshot method like this: webview.snapshot(null, NULL); – Schwuchtelini Jun 21 '15 at 13:33
  • So I would maybe be able to get 60 fps, but I have to refresh my texture of the browser every frame, as I don't know if the browser changed something. With chromium embedded java I only have to update my browser texture if the browser actually changed the screen. As I need much performance for my game, I don't think this solution is good enough for me, but thanks for your help. – Schwuchtelini Jun 21 '15 at 13:41