Start of test window using ultralight

This commit is contained in:
Simon Lübeß
2024-09-15 22:57:20 +02:00
parent 77c74f4cc3
commit 21ddf69d5f
3 changed files with 183 additions and 118 deletions
@@ -0,0 +1,85 @@
using Ultralight.CAPI;
namespace GlitchyEditor.Ultralight;
class UltralightEntityHierarchyWindow : UltralightWindow
{
public this() : base("Entity Hierarchy", "file:///app.html")
{
}
///
/// This callback is bound to a JavaScript function on the page.
///
static JSValueRef GetMessage(JSContextRef ctx, JSObjectRef fn, JSObjectRef thisObject, uint32 argumentCount, JSValueRef* arguments, JSValueRef* exception) {
///
/// Create a JavaScript String from a C-string, initialize it with our
/// welcome message.
///
JSStringRef str = JSStringCreateWithUTF8CString("Hello from Beef!");
///
/// Create a garbage-collected JSValue using the String we just created.
///
/// **Note**:
/// Both JSValueRef and JSObjectRef types are garbage-collected types. (And actually,
/// JSObjectRef is just a typedef of JSValueRef, they share definitions).
///
/// The garbage collector in JavaScriptCore periodically scans the entire stack to check if
/// there are any active JSValueRefs, and marks those with no references for destruction.
///
/// If you happen to store a JSValueRef/JSObjectRef in heap memory or in memory unreachable
/// by the stack-based garbage-collector, you should explicitly call JSValueProtect() and
/// JSValueUnprotect() on the reference to ensure it is kept alive.
///
JSValueRef value = JSValueMakeString(ctx, str);
///
/// Release the string we created earlier (we only Release what we Create).
///
JSStringRelease(str);
return value;
}
protected override void OnDOMReady(C_View* caller, uint64 frame_id, bool is_main_frame, C_String* url)
{
///
/// Acquire the page's JavaScript execution context.
///
/// This locks the JavaScript context so we can modify it safely on this thread, we need to
/// unlock it when we're done via ulViewUnlockJSContext().
///
JSContextRef ctx = ulViewLockJSContext(_view);
///
/// Create a JavaScript String containing the name of our callback.
///
JSStringRef name = JSStringCreateWithUTF8CString("GetMessage");
///
/// Create a garbage-collected JavaScript function that is bound to our native C callback
/// 'GetMessage()'.
///
JSObjectRef func = JSObjectMakeFunctionWithCallback(ctx, name, => GetMessage);
///
/// Store our function in the page's global JavaScript object so that it is accessible from the
/// page as 'GetMessage()'.
///
/// The global JavaScript object is also known as 'window' in JS.
///
JSObjectSetProperty(ctx, JSContextGetGlobalObject(ctx), name, func, 0, null);
///
/// Release the JavaScript String we created earlier.
///
JSStringRelease(name);
///
/// Unlock the JS context so other threads can modify JavaScript state.
///
ulViewUnlockJSContext(_view);
}
}
+83 -111
View File
@@ -9,25 +9,65 @@ using Ultralight.CAPI;
namespace GlitchyEditor.Ultralight; namespace GlitchyEditor.Ultralight;
class UltralightWindow abstract class UltralightWindow
{ {
private Window _window ~ delete _; protected Window _window ~ delete _;
private ULView _view; protected ULView _view;
private int2 _cursorPosition; private int2 _cursorPosition;
private Texture2D _texture ~ _.ReleaseRef(); private Texture2D _texture ~ _.ReleaseRef();
public this() protected this(StringView title = "GlitchyEngine ♥ Ultralight", StringView startUrl = "file:///app.html")
{ {
WindowDescription windowDesc = .Default; WindowDescription windowDesc = .Default;
windowDesc.Title = "GlitchyEngine ♥ Ultralight"; windowDesc.Title = title;
_window = new Window(windowDesc); _window = new Window(windowDesc);
_window.EventCallback = new => EventHandler; _window.EventCallback = new => EventHandler;
CreateView(); Init(startUrl);
}
#region Init
private void Init(StringView startUrl)
{
InitView();
InitCallbacks();
LoadUrl(startUrl);
CreateTexture();
}
private void InitView()
{
ULViewConfig viewConfig = ulCreateViewConfig();
ulViewConfigSetIsAccelerated(viewConfig, false);
_view = ulCreateView(UltralightLayer.renderer, _window.SwapChain.Width, _window.SwapChain.Height, viewConfig, null);
ulDestroyViewConfig(viewConfig);
}
private void InitCallbacks()
{
void* userData = Internal.UnsafeCastToPtr(this);
ulViewSetDOMReadyCallback(_view, => OnDOMReady, userData);
ulViewSetFailLoadingCallback(_view, => OnFailedLoading, userData);
}
#endregion Init
protected void LoadUrl(StringView targetUrl)
{
ULString url = ulCreateString(targetUrl.ToScopeCStr!());
ulViewLoadURL(_view, url);
ulDestroyString(url);
} }
private void CopybitmapToTexture(ULBitmap bitmap) private void CopybitmapToTexture(ULBitmap bitmap)
@@ -44,7 +84,7 @@ class UltralightWindow
ulBitmapUnlockPixels(bitmap); ulBitmapUnlockPixels(bitmap);
} }
public void Render() private void CopyToImmediateTexture()
{ {
ULBitmapSurface surface = ulViewGetSurface(_view); ULBitmapSurface surface = ulViewGetSurface(_view);
@@ -53,7 +93,10 @@ class UltralightWindow
CopybitmapToTexture(ulBitmapSurfaceGetBitmap(surface)); CopybitmapToTexture(ulBitmapSurfaceGetBitmap(surface));
ulSurfaceClearDirtyBounds(surface); ulSurfaceClearDirtyBounds(surface);
} }
}
private void CopyToBackBuffer()
{
if (_window == null) if (_window == null)
return; return;
@@ -72,28 +115,28 @@ class UltralightWindow
FullscreenQuad.Draw(); FullscreenQuad.Draw();
} }
private void CreateView() public void Render()
{ {
ULViewConfig viewConfig = ulCreateViewConfig(); CopyToImmediateTexture();
ulViewConfigSetIsAccelerated(viewConfig, false); CopyToBackBuffer();
_view = ulCreateView(UltralightLayer.renderer, _window.SwapChain.Width, _window.SwapChain.Height, viewConfig, null);
ulViewSetDOMReadyCallback(_view, => OnDOMReady, Internal.UnsafeCastToPtr(this));
ulDestroyViewConfig(viewConfig);
ulViewSetFailLoadingCallback(_view, (user_data, caller, frame_id, is_main_frame, url, description, error_domain, error_code) => {
Log.ClientLogger.Error("Error");
}, null);
ULString url = ulCreateString("file:///app.html");
ulViewLoadURL(_view, url);
ulDestroyString(url);
CreateTexture();
} }
private void CreateTexture()
{
if (_texture?.Width == _window.SwapChain.Width && _texture?.Height == _window.SwapChain.Height)
return;
Texture2DDesc desc = .(_window.SwapChain.Width, _window.SwapChain.Height, .B8G8R8A8_UNorm, usage: .Default, cpuAccess: .Write);
Texture2D newTexture = new Texture2D(desc);
newTexture.SamplerState = SamplerStateManager.PointClamp;
_texture?.ReleaseRef();
_texture = newTexture;
}
#region Events
private void EventHandler(Event e) private void EventHandler(Event e)
{ {
EventDispatcher dispatcher = EventDispatcher(e); EventDispatcher dispatcher = EventDispatcher(e);
@@ -121,20 +164,6 @@ class UltralightWindow
return true; return true;
} }
private void CreateTexture()
{
if (_texture?.Width == _window.SwapChain.Width && _texture?.Height == _window.SwapChain.Height)
return;
Texture2DDesc desc = .(_window.SwapChain.Width, _window.SwapChain.Height, .B8G8R8A8_UNorm, usage: .Default, cpuAccess: .Write);
Texture2D newTexture = new Texture2D(desc);
newTexture.SamplerState = SamplerStateManager.PointClamp;
_texture?.ReleaseRef();
_texture = newTexture;
}
private bool CharTypedEvent(KeyTypedEvent e) private bool CharTypedEvent(KeyTypedEvent e)
{ {
String s = scope String(); String s = scope String();
@@ -192,8 +221,6 @@ class UltralightWindow
private bool MouseMoved(MouseMovedEvent e) private bool MouseMoved(MouseMovedEvent e)
{ {
Log.EngineLogger.Warning($"{e.PositionX}");
ULMouseEvent evt = ulCreateMouseEvent(.kMouseEventType_MouseMoved, e.PositionX, e.PositionY, ULMouseEvent evt = ulCreateMouseEvent(.kMouseEventType_MouseMoved, e.PositionX, e.PositionY,
Input.IsMouseButtonPressed(.LeftButton) ? .kMouseButton_Left : .kMouseButton_None); Input.IsMouseButtonPressed(.LeftButton) ? .kMouseButton_Left : .kMouseButton_None);
ulViewFireMouseEvent(_view, evt); ulViewFireMouseEvent(_view, evt);
@@ -223,39 +250,9 @@ class UltralightWindow
return true; return true;
} }
/// #endregion Events
/// This callback is bound to a JavaScript function on the page.
///
static JSValueRef GetMessage(JSContextRef ctx, JSObjectRef fn, JSObjectRef thisObject, uint32 argumentCount, JSValueRef* arguments, JSValueRef* exception) {
///
/// Create a JavaScript String from a C-string, initialize it with our
/// welcome message.
///
JSStringRef str = JSStringCreateWithUTF8CString("Hello from Beef!");
/// #region Ultralight Callbacks
/// Create a garbage-collected JSValue using the String we just created.
///
/// **Note**:
/// Both JSValueRef and JSObjectRef types are garbage-collected types. (And actually,
/// JSObjectRef is just a typedef of JSValueRef, they share definitions).
///
/// The garbage collector in JavaScriptCore periodically scans the entire stack to check if
/// there are any active JSValueRefs, and marks those with no references for destruction.
///
/// If you happen to store a JSValueRef/JSObjectRef in heap memory or in memory unreachable
/// by the stack-based garbage-collector, you should explicitly call JSValueProtect() and
/// JSValueUnprotect() on the reference to ensure it is kept alive.
///
JSValueRef value = JSValueMakeString(ctx, str);
///
/// Release the string we created earlier (we only Release what we Create).
///
JSStringRelease(str);
return value;
}
private static void OnDOMReady(void* user_data, ULView caller, uint64 frame_id, bool is_main_frame, ULString url) private static void OnDOMReady(void* user_data, ULView caller, uint64 frame_id, bool is_main_frame, ULString url)
{ {
@@ -263,43 +260,18 @@ class UltralightWindow
window.OnDOMReady(caller, frame_id, is_main_frame, url); window.OnDOMReady(caller, frame_id, is_main_frame, url);
} }
protected virtual void OnDOMReady(ULView caller, uint64 frame_id, bool is_main_frame, ULString url) protected virtual void OnDOMReady(ULView caller, uint64 frame_id, bool is_main_frame, ULString url) { }
private static void OnFailedLoading(void* user_data, C_View* caller, uint64 frame_id, bool is_main_frame, C_String* url, C_String* description, C_String* error_domain, int32 error_code)
{ {
/// UltralightWindow window = (UltralightWindow)Internal.UnsafeCastToObject(user_data);
/// Acquire the page's JavaScript execution context. window.OnFailedLoading(caller, frame_id, is_main_frame, url, description, error_domain, error_code);
///
/// This locks the JavaScript context so we can modify it safely on this thread, we need to
/// unlock it when we're done via ulViewUnlockJSContext().
///
JSContextRef ctx = ulViewLockJSContext(_view);
///
/// Create a JavaScript String containing the name of our callback.
///
JSStringRef name = JSStringCreateWithUTF8CString("GetMessage");
///
/// Create a garbage-collected JavaScript function that is bound to our native C callback
/// 'GetMessage()'.
///
JSObjectRef func = JSObjectMakeFunctionWithCallback(ctx, name, => GetMessage);
///
/// Store our function in the page's global JavaScript object so that it is accessible from the
/// page as 'GetMessage()'.
///
/// The global JavaScript object is also known as 'window' in JS.
///
JSObjectSetProperty(ctx, JSContextGetGlobalObject(ctx), name, func, 0, null);
///
/// Release the JavaScript String we created earlier.
///
JSStringRelease(name);
///
/// Unlock the JS context so other threads can modify JavaScript state.
///
ulViewUnlockJSContext(_view);
} }
protected virtual void OnFailedLoading(C_View* caller, uint64 frame_id, bool is_main_frame, C_String* url, C_String* description, C_String* error_domain, int32 error_code)
{
Log.EngineLogger.Error("Error while loading view.");
}
#endregion Ultralight Callbacks
} }
+10 -2
View File
@@ -17,15 +17,23 @@ class UltralightLayer : Layer
private List<UltralightWindow> _windows = new .() ~ DeleteContainerAndItems!(_); private List<UltralightWindow> _windows = new .() ~ DeleteContainerAndItems!(_);
public UltralightEntityHierarchyWindow EntityHierarchyWindow;
private static Self _instance;
public static Self Instance => _instance;
public this() public this()
{ {
_instance = this;
InitUltralight(); InitUltralight();
_windows.Add(new UltralightWindow()); EntityHierarchyWindow = new UltralightEntityHierarchyWindow();
_windows.Add(EntityHierarchyWindow);
_copyEffect = Content.LoadAsset("Resources/Shaders/Copy.hlsl"); _copyEffect = Content.LoadAsset("Resources/Shaders/Copy.hlsl");
} }
private static void InitClipboard() private static void InitClipboard()
{ {
ULClipboard clipboard = .(); ULClipboard clipboard = .();