News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

UASM and UltraLight

Started by johnsa, March 06, 2021, 07:23:31 AM

Previous topic - Next topic

johnsa

So as a bit of an experiment...

I've played around with a bunch of UI frameworks and ways of making front-ends easier in C/C++

1) I've used CEF (works well, but Chromium is a resource pig) and CEF is a nightmare of boilerplate to actually get implemented in your project..
2) Electron, also massive bloat.. and I don't like the architecture.. I want native-code app first, UI second.

However being able to use HTML5, CSS, SVG, Canvas and so on with JS for light weight helpers backed by high performance native code is quite appealing..

So I found this: https://ultralig.ht/

Same concept as CEF, but a million times easier, 1/10th the size and not using Chromium.. it's pretty tidy and compact and has a C API.
So I thought what the hell.. and ported their C sample app into UASM.

If you get there latest SDK it has the libs/DLLs and all the C headers
I just started porting the bits that were relevant and we have (thanks to UASM C-style an almost identical implementation in ASM):

build with:
c:\jwasm\uasm64 -c -win64 -Zi8 -Zp8 vd.asm
link /subsystem:windows /entry:Main /machine:x64 /debug vd.obj

and tada.. ASM with an HTML5/JS front-end.. might not be everyones cup of tea.. but I have some stuff that I feel must be coded in ASM, but I don't want to fight with how I display the final output..

(You'll need to copy the SDK DLLs and the assets folder from their Sample6 ..)


.x64
option casemap:none
option frame:auto
option stackbase:rbp
option win64:7
option literals:on

.nolist
.nocref
WIN32_LEAN_AND_MEAN EQU 1
_WIN64 EQU 1
include C:\jwasm\wininc\Include\windows.inc
.list
.cref

include C:\jwasm\WinInc\Include\stdio.inc
include C:\jwasm\WinInc\Include\stdlib.inc

includelib <msvcrt.lib>
includelib <user32.lib>
includelib <kernel32.lib>

;JSBase.H
JSContextGroupRef            TYPEDEF PTR OpaqueJSContextGroup
JSContextRef                 TYPEDEF PTR OpaqueJSContext
JSGlobalContextRef           TYPEDEF PTR OpaqueJSContext
JSStringRef                  TYPEDEF PTR OpaqueJSString
JSClassRef                   TYPEDEF PTR OpaqueJSClass
JSPropertyNameArrayRef       TYPEDEF PTR OpaqueJSPropertyNameArray
JSPropertyNameAccumulatorRef TYPEDEF PTR OpaqueJSPropertyNameAccumulator
JSValueRef                   TYPEDEF PTR OpaqueJSValue
JSObjectRef                  TYPEDEF PTR OpaqueJSValue
JSPropertyAttributes         TYPEDEF DWORD

ULApp      TYPEDEF PTR C_App
ULWindow   TYPEDEF PTR C_Window
ULView     TYPEDEF PTR C_View
ULString   TYPEDEF PTR C_String
ULOverlay  TYPEDEF PTR C_Overlap
ULSettings TYPEDEF PTR C_Settings
ULConfig   TYPEDEF PTR C_Config
ULMonitor  TYPEDEF PTR C_Monitor
ULUpdateCallback TYPEDEF PTR

includelib <..\ultralight\lib\Ultralight.lib>
includelib <..\ultralight\lib\UltralightCore.lib>
includelib <..\ultralight\lib\WebCore.lib>
includelib <..\ultralight\lib\AppCore.lib>

ulOverlayResize               PROTO overlay:ULOverlay, vwidth:DWORD, vheight:DWORD
ulAppRun                      PROTO app:ULApp
ulDestroyOverlay              PROTO overlay:ULOverlay
ulDestroyWindow               PROTO window:ULWindow
ulDestroyApp                  PROTO app:ULApp
ulCreateSettings              PROTO (ULSettings)
ulCreateConfig                PROTO (ULConfig)
ulSettingsSetForceCPURenderer PROTO settings:ULSettings, state:BYTE
ulCreateApp                   PROTO (ULApp) settings:ULSettings, config:ULConfig
ulDestroySettings             PROTO settings:ULSettings
ulDestroyConfig               PROTO config:ULConfig
ulAppSetUpdateCallback        PROTO app:ULApp, callback:ULUpdateCallback, user_data:PTR
ulAppGetMainMonitor           PROTO app:ULApp
ulCreateWindow                PROTO (ULWindow) _monitor:ULMonitor, _width:DWORD, _height:DWORD, fullscreen:BYTE, window_flags:DWORD
ulWindowSetTitle              PROTO window:ULWindow, _title:PTR
ulWindowSetResizeCallback     PROTO window:ULWindow, callback:PTR, user_data:PTR
ulAppSetWindow                PROTO app:ULApp, window:ULWindow
ulCreateOverlay               PROTO (ULOverlay) window:ULWindow, _width:DWORD, _height:DWORD, x:SDWORD, y:SDWORD
ulWindowGetWidth              PROTO (DWORD) window:ULWindow
ulWindowGetHeight             PROTO (DWORD) window:ULWindow
ulOverlayGetView              PROTO (ULView) overlay:ULOverlay
ulViewSetDOMReadyCallback     PROTO view:ULView, callback:PTR, user_data:PTR
ulCreateString                PROTO (ULString) cStringPtr:PTR
ulDestroyString               PROTO stringPtr:ULString
ulViewLoadURL                 PROTO view:ULView, url_string:ULString

ulViewLockJSContext              PROTO (JSContextRef) view:ULView
ulViewUnlockJSContext            PROTO view:ULView
JSStringCreateWithUTF8CString    PROTO (JSStringRef) cStrPtr:PTR
JSStringRelease                  PROTO strPtr:JSStringRef
JSObjectMakeFunctionWithCallback PROTO (JSObjectRef) ctx:JSContextRef, name:JSStringRef, callback:PTR
JSContextGetGlobalObject         PROTO (JSObjectRef) ctx:JSContextRef
JSObjectSetProperty              PROTO ctx:JSContextRef, obj:JSObjectRef, propertyName:JSStringRef, value:JSValueRef, attributes:JSPropertyAttributes, exception:PTR JSValueRef
JSStringCreateWithUTF8CString    PROTO (JSStringRef) cStr:PTR
JSValueMakeString                PROTO (JSValueRef) ctx:JSContextRef, string:JSStringRef

kWindowFlags_Borderless  EQU 1 SHL 0
kWindowFlags_Titled      EQU 1 SHL 1
kWindowFlags_Resizable   EQU 1 SHL 2
kWindowFlags_Maximizable EQU 1 SHL 3

Init        PROTO
Shutdown    PROTO
OnUpdate    PROTO user_data:PTR
OnResize    PROTO user_data:PTR, vwidth:DWORD, vheight:DWORD
OnDOMReady  PROTO user_data:PTR, caller:ULView, frame_id:QWORD, is_main_frame:BYTE, url:ULString
GetCMessage PROTO ctx:JSContextRef, function:JSObjectRef, thisObject:JSObjectRef, argumentCount:DWORD, arguments:PTR JSValueRef, exception:PTR JSValueRef

.data?

.data

app     ULApp 0
window  ULWindow 0
overlay ULOverlay 0
view    ULView 0

.code

OnUpdate PROC FRAME user_data:PTR
    ; Nothing todo here
    ret
OnUpdate ENDP

OnResize PROC FRAME user_data:PTR, vwidth:DWORD, vheight:DWORD
    ulOverlayResize(overlay, vwidth, vheight)
    ret
OnResize ENDP

OnDOMReady PROC FRAME user_data:PTR, caller:ULView, frame_id:QWORD, is_main_frame:BYTE, url:ULString
    LOCAL ctx:JSContextRef
    LOCAL name:JSStringRef
    LOCAL func:JSObjectRef

    ; 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().
    mov ctx,ulViewLockJSContext(view)

    ; Create a JavaScript String containing the name of our callback.
    mov name,JSStringCreateWithUTF8CString("GetMessage")

    ; Create a garbage-collected JavaScript function that is bound to our
    ; native C callback 'GetMessage()'.
    mov func,JSObjectMakeFunctionWithCallback(ctx, name, &GetCMessage)

    ; Store our function in the page's global JavaScript object so that it
    ; accessible from the page as 'GetMessage()'.
    ; The global JavaScript object is also known as 'window' in JS.
    JSObjectSetProperty(ctx, JSContextGetGlobalObject(ctx), name, func, 0, 0)

    ; Release the JavaScript String we created earlier.
    JSStringRelease(name)

    ; Unlock the JS context so other threads can modify JavaScript state.
    ulViewUnlockJSContext(view)

    ret
OnDOMReady ENDP

GetCMessage PROC FRAME ctx:JSContextRef, function:JSObjectRef, thisObject:JSObjectRef, argumentCount:DWORD, arguments:PTR JSValueRef, exception:PTR JSValueRef
    LOCAL value:JSValueRef
    LOCAL mystr:JSStringRef

    ; Create a JavaScript String from a C-string, initialize it with our welcome message.
    mov mystr,JSStringCreateWithUTF8CString("Hello from ASM!")

    ; 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.
    mov value,JSValueMakeString(ctx, mystr)

    ; Release the string we created earlier (we only Release what we Create).
    JSStringRelease(mystr)

    mov rax,value
    ret
GetCMessage ENDP

Main PROC FRAME
    Init()
    ulAppRun(app)
    Shutdown()
    invoke ExitProcess,0
    ret
Main ENDP

Init PROC FRAME
    LOCAL settings:ULSettings
    LOCAL config:ULConfig
    LOCAL url:ULString

    mov settings,ulCreateSettings()
    ulSettingsSetForceCPURenderer(settings, TRUE)

    mov config,ulCreateConfig()

    mov app,ulCreateApp(settings, config)

    ulAppSetUpdateCallback(app, &OnUpdate, 0)

    ulDestroySettings(settings)
    ulDestroyConfig(config)

    ; Create our window, make it 500x500 with a titlebar and resize handles.
    WINFLAG = kWindowFlags_Titled OR kWindowFlags_Resizable
    mov window,ulCreateWindow(ulAppGetMainMonitor(app), 500, 500, FALSE, WINFLAG)

    ; Set our window title.
    ulWindowSetTitle(window, "My App")

    ; Register a callback to handle window resize.
    ulWindowSetResizeCallback(window, &OnResize, 0)

    ; Tell our app to use this window as the main window.
    ulAppSetWindow(app, window)

    ; Create an overlay same size as our window at 0,0 (top-left) origin.
    ; Overlays also create an HTML view for us to display content in.
    ; **Note**: Ownership of the view remains with the overlay since we don't explicitly create it.
    ulCreateOverlay(window, ulWindowGetWidth(window), ulWindowGetHeight(window), 0, 0)
    mov overlay,rax

    ; Get the overlay's view.
    mov view,ulOverlayGetView(overlay)

    ; Register a callback to handle our view's DOMReady event. We will use this
    ; event to setup any JavaScript <-> C bindings and initialize our page.
    ulViewSetDOMReadyCallback(view, &OnDOMReady, 0)

    ; Load a file from the FileSystem.
    ;  **IMPORTANT**: Make sure `file:///` has three (3) forward slashes.
    ;  **Note**: You can configure the base path for the FileSystem in the settings we passed to ulCreateApp earlier.
    mov url,ulCreateString("file:///app.html")
    ulViewLoadURL(view, url)
    ulDestroyString(url)

    ret
Init ENDP

Shutdown PROC FRAME
    ulDestroyOverlay(overlay)
    ulDestroyWindow(window)
    ulDestroyApp(app)
    ret
Shutdown ENDP

END Main

mabdelouahab

Same example works on Linux  :thumbsup:
uasm -elf64  Ultralight.asm   
gcc  -o Ultralight -fno-pie -no-pie Ultralight.o libAppCore.so libUltralight.so libUltralightCore.so libWebCore.so
./Ultralight


Without:
;include C:\jwasm\wininc\Include\windows.inc
;include C:\jwasm\WinInc\Include\stdio.inc
;include C:\jwasm\WinInc\Include\stdlib.inc
;includelib <msvcrt.lib>
;includelib <user32.lib>
;includelib <kernel32.lib>
;includelib <..\ultralight\lib\Ultralight.lib>
;includelib <..\ultralight\lib\UltralightCore.lib>
;includelib <..\ultralight\lib\WebCore.lib>
;includelib <..\ultralight\lib\AppCore.lib>

Biterider

Hi John
Very cool project.  :cool:
Fortunately, there is a version whose binaries we can obtain for free, but only for "non-commercial use".
The smallest license of USD 2000 is a bit high, but may be be fine for a well-selling product.

Biterider

six_L

Hi,johnsa
Same example works on win10. :thumbsup:
Say you, Say me, Say the codes together for ever.

TimoVJL

May the source be with you

Biterider

Hi John
A quick port to ObjAsm worked seamlessly!
Great stuff! :thumbsup:

Biterider

johnsa

It looks like the contents (the actual html) is missing, do you have the /assets folder in the same place as the executable ?
This is super cool that it works in both :)

Quote from: mabdelouahab on March 06, 2021, 09:08:59 AM
Same example works on Linux  :thumbsup:
uasm -elf64  Ultralight.asm   
gcc  -o Ultralight -fno-pie -no-pie Ultralight.o libAppCore.so libUltralight.so libUltralightCore.so libWebCore.so
./Ultralight


Without:
;include C:\jwasm\wininc\Include\windows.inc
;include C:\jwasm\WinInc\Include\stdio.inc
;include C:\jwasm\WinInc\Include\stdlib.inc
;includelib <msvcrt.lib>
;includelib <user32.lib>
;includelib <kernel32.lib>
;includelib <..\ultralight\lib\Ultralight.lib>
;includelib <..\ultralight\lib\UltralightCore.lib>
;includelib <..\ultralight\lib\WebCore.lib>
;includelib <..\ultralight\lib\AppCore.lib>


mabdelouahab

"/assets", I didn't notice that،I did the job quickly   :biggrin: