Help us understand the problem. What is going on with this article?

軽量ブラウザ Ultralight を OpenSiv3D で動かす

20191225-225953-457.png

Ultralight とは

https://ultralig.ht/

Ultralight とはゲームやデスクトップアプリなどに HTML UI を組み込むための C++ ライブラリです。
HTML 描画が主目的のため Web ブラウザとしての機能は少なめ(動画や音の再生に非対応)ですが、その代わりに組み込みの容易さと軽さを特徴としています。
使用ライセンスは 非商用利用 or 年間10万ドル未満の商用利用 に限り無料で使うことができます。
ブラウザ部分は WebKit の実装をベースにしており、レンダラは OpenGL, DirectX, Metal をサポートしています。

使い方

Ultralight の DirectX 版の実装を OpenSiv3D に組み込んでみました。

https://github.com/agehama/OpenSiv3D/tree/ultralight
ここからクローンして OpenSiv3D/WindowsDesktop/OpenSiv3D.sln をビルドすれば動かすことができます。(Windows 限定)

例1. URL を読み込んで描画する

WebSample1.cpp
#include <Siv3D.hpp> // OpenSiv3D v0.4.2
#include "BrowserRect.hpp"

void Main()
{
    Window::Resize(1280, 720);
    Scene::SetBackground(ColorF(0.8, 0.9, 1.0));

    BrowserRect browser(Scene::Rect().stretched(-50));
    browser.view()->LoadURL("https://qiita.com/advent-calendar/2019/siv3d");

    while (System::Update())
    {
        browser.update();
        browser.drawRounded(10.0);
    }
}

BrowserRect::view() は Ultralight のビューにアクセスするための関数で、ここから URL や HTML の読み込みなどを行うことができます。
BrowserRect::update() でマウス入力などブラウザの更新処理と内部のテクスチャ更新を行います。
BrowserRect::draw() で内部のテクスチャを画面に表示します。drawRounded() は角丸版です。

20191225-000908-341.png

例2. JavaScript から C++ の関数を呼ぶ

JavaScript から C++ の関数を呼び出すには JSGlobalObject() に呼びたい関数を事前に登録しておくことで JavaScript からグローバル関数として呼び出すことができるようになります。
逆に C++ から JavaScript を呼び出すには JSEval() 関数に JavaScript の式を渡すことで呼べます。

WebSample2.cpp
#include <Siv3D.hpp> // OpenSiv3D v0.4.2
#include "BrowserRect.hpp"

class Text
{
public:
    Text(const String& str, const Vec2& pos):
        str(str), pos(pos)
    {}
    String str;
    Vec2 pos;
};

class Listener : public ultralight::LoadListener
{
public:
    void DropText(const ultralight::JSObject& thisObject, const ultralight::JSArgs& args)
    {
        char* str = static_cast<ultralight::String>(args[0].ToString()).utf8().data();
        texts.emplace_back(Unicode::FromUTF8(str), RandomVec2({ 0,Scene::Width() }, 0));
    }

    void OnDOMReady(ultralight::View* caller) override
    {
        ultralight::SetJSContext(caller->js_context());
        ultralight::JSObject global = ultralight::JSGlobalObject();

        using ultralight::JSCallback;
        global["DropText"] = BindJSCallback(&Listener::DropText);
    }

    Array<Text> texts;
};

void Main()
{
    Window::Resize(1280, 720);
    Scene::SetBackground(ColorF(0.8, 0.9, 1.0));
    Font font(50, Typeface::Heavy);

    BrowserRect browser(Scene::Rect().stretched(-100));

    Listener listener;
    browser.view()->set_load_listener(&listener);

    browser.view()->LoadHTML(R"(
<html>
<style type="text/css">
body { font-family: sans-serif; text-align: center; }
</style>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<body>
<form class="w3-container w3-card-4" action="/action_page.php">
  <h2 class="w3-text-blue">OpenSiv3D Web Sample</h2>
  <p>input some characters</p>
  <p><input id="textBox" class="w3-input w3-border" name="text1" type="text" value=""></p>
  <p><button class="w3-btn w3-blue w3-xxxlarge" onclick="DropText(document.getElementById('textBox').value);">Go!</button></p>
</form>
</body>
</html>
)");

    while (System::Update())
    {
        browser.update();
        browser.draw();

        for (auto& text : listener.texts)
        {
            text.pos += Vec2(0, 0.5);
            font(text.str).draw(text.pos, RandomHSV({ 0,360 }, { 1,1 }, { 1,1 }));
        }
    }
}

テキストを入力してボタンを押すと上からテキストが点滅しながら降ってくるサンプルです。
(描画が微妙にバグっているのとテキスト入力があまりスムーズにいかないバグがありますがおそらくどちらも雑に組み込んでしまったのが原因です…)

20191225-213703-764.png

Ultralight の使い方の詳細な説明は https://docs.ultralig.ht/docs にあります。

まとめ

現在の Ultralight はまだ CSS などの互換性が甘いためどうしても描画の粗が気になってしまいます。
しかしこれでも v1.0.0 に比べるとかなり良くなった方で、日々開発も進んでいるようなので今後に期待ですね。

いずれはこの記事のようにゲーム中の GUI 実装の選択肢としても使えるようになると嬉しいですね。
Nintendo Switchの中ではReactが動いてる!Nintendo eShop開発秘話を聞いてきた - HTML5Experts.jp

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away