Emscripten port

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Emscripten port

Post by LunaRebirth »

CuteAlien wrote:(but I can't rest right now as I'm on wrong OS)
If you are on Windows, I followed the steps like you would normally follow for the Linux build and it seems to work fine with a regular command prompt on Windows. I'll check the SDL outputs in a bit
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Emscripten port

Post by LunaRebirth »

CuteAlien wrote:Maybe enable the line with os::Printer::log in CIrrDeviceSDL::run() to see if you get any events.
No events seem to be outputted after uncommenting that line and rebuilding for Emscripten.

Edit: Events from the 13.RenderToTexture_emscripten tutorial seem to be outputting ok. Only difference I see in mine is that I'm not using an FPS camera.
Last edited by LunaRebirth on Tue Jul 24, 2018 10:06 pm, edited 1 time in total.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Emscripten port

Post by CuteAlien »

Guess I will have to find some time to check. Can't tell right now. But if you use some Makefile - please post that so I can use same settings (several stuff for emscripten is controlled by link-flags).

edit: Important flags in my Makefile where probable these (but stuff like memory and preload-file depends on project):
all_emscripten: CXXFLAGS += -fno-exceptions -fno-rtti -fstrict-aliasing -std=gnu++11 -U__STRICT_ANSI__
all_emscripten: CXXFLAGS += --shell-file shell_minimal.html
all_emscripten: LDFLAGS += -lGL -lSDL --preload-file ../media@/media -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=1
all_emscripten: LDFLAGS += -s TOTAL_MEMORY=268435456
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Emscripten port

Post by CuteAlien »

Hm, so example works? Could be it does some mouse-cursor locking due to fps-camera (when it hides cursor maybe - but just guessing right now).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Emscripten port

Post by LunaRebirth »

Makefile:

Code: Select all

Target := Test
Sources := ../main.cpp
CPPFLAGS += -I../include/ -I../include/ext/ -I../include/Lua/ -I../ -I../../irrlicht-ogl-es/include/ -I../../libs/zlib-1.2.11 -I/usr/X11r6/include
CXXFLAGS += -g -Wall -fno-rtti -fstrict-aliasing -std=gnu++11 -U__STRICT_ANSI__
LDFLAGS += -s DEMANGLE_SUPPORT=1 -L../../irrlicht-ogl-es/lib/emscripten -lIrrlicht -lGL -lSDL --preload-file ../../irrlicht-ogl-es/media@/media -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=1 -s DISABLE_EXCEPTION_CATCHING=0 -s FULL_ES2=1 -D_IRR_EMSCRIPTEN_PLATFORM_
DESTPATH = bin/Test.html
all:
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(Sources) -o $(DESTPATH) $(LDFLAGS)
 
ifeq ($(HOSTTYPE), x86_64)
LIBSELECT=64
endif
ifeq ($HOSTTYPE), sun4)
LDFLAGS += -lrt
endif
CuteAlien wrote:Hm, so example works? Could be it does some mouse-cursor locking due to fps-camera (when it hides cursor maybe - but just guessing right now).
Mouse doesn't hide, but it does print "event: #" while moving cursor, clicking, etc.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Emscripten port

Post by CuteAlien »

Thanks. Thought if example works now I'm probably not too much help anymore. Unless you can figure out how to break it.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Emscripten port

Post by LunaRebirth »

So it seems this code is absolutely essential in the one_iter() function:

Code: Select all

#if defined(_IRR_EMSCRIPTEN_PLATFORM_)
if(!device->run())
{
    emscripten_cancel_main_loop();
    return;
}
#endif
Without it, the program "freezes" (what I thought was events not being triggered), but the loop still runs successfully with no errors in the developer console.. This happens not only in my application, but also in tutorial 13.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Emscripten port

Post by CuteAlien »

That sounds like run() fails once in a while. Thought wouldnt emscripten_cancel_main_loop quit the app? Interesting, will check it out.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Emscripten port

Post by LunaRebirth »

This question is probably more suitable for an Emscripten forum, but is there a way to get the browser size?

I set the Emscripten canvas (canvas.emscripten) width and height to 100% in the .HTML so it would take up the whole browser screen.

Unfortunately, I'm unable to use emscripten_get_canvas_element_size() to get the width/height (it always returns 640x480 -- the size I set when initializing the Irrlicht driver). Unfortunately, this stretches my application rather than actually updating the size (like a regular .exe would do).
Using emscripten_set_resize_callback(), I can see when the browser was resized.

I see that the Irrlicht Emscripten example has a function to check for window size updates, but is never used (I'm assuming because it also didn't return the absolute width/height of the browser?)

I'm unsure whether this is an Emscripten issue or an Irrlicht issue.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Emscripten port

Post by CuteAlien »

Yeah, that one is tricky. But first, sorry I messed something up badly. I had worked in another folder than the one I checked-in I think. Because I just found out the official folder was missing the html and instead had some stupid useless tutorial.html in there. I checked-in the real one now.

Now... that one is some improvement, but likely still not handling it correct. Because in the project I worked on after doing the example I did fight some more with exact this problem. I found some solution, but don't know if it's good.

What I used is some Javascript stuff to call a function in the c++ code:

Code: Select all

 
<script type='text/javascript'>
 
    var __appContextReady = false;
 
    function resize(canvas) {
        // Based on https://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
        // Lookup the size the browser is displaying the canvas in CSS pixels
        // and compute a size needed to make our drawingbuffer match it in
        // device pixels.
        var realToCSSPixels = window.devicePixelRatio;                  
        var displayWidth  = Math.floor(canvas.clientWidth  * realToCSSPixels);
        var displayHeight = Math.floor(canvas.clientHeight * realToCSSPixels);
 
        // Check if the canvas is not the same size.
        if (canvas.width  != displayWidth ||
            canvas.height != displayHeight) {
 
            // Make the canvas the same size
            canvas.width  = displayWidth;
            canvas.height = displayHeight;
        }
        console.log("resize:"  + canvas.width + "x" + canvas.height );          
        if ( __appContextReady ) {
            console.log("cpp_code_resize_canvas" );
            Module.ccall('cpp_code_resize_canvas', null,  ['number', 'number'], [canvas.width, canvas.height]);
        }
    }
 
    function onResize() {
        console.log("onResize");
        resize( document.getElementsByTagName('canvas')[0] );
    }
    
    function appContextReady()  {
        __appContextReady = true;
        console.log("appContextReady");
        resize( document.getElementsByTagName('canvas')[0] );
        
        var projectId = 0;  // set to 0 for choice with edit-box
        Module.ccall('i4_set_project_id', null, ['number'], [projectId]);
    }
</script>
 
To make sure it's called (I hope that's the correct way - I have no clue about JS/html really...):

Code: Select all

 
<body onresize="onResize()">
 
Oh and I had another call for it in preRun:

Code: Select all

 
preRun: (function() { 
            console.log("preRun");
            onResize(); 
        })(),
 
And on cpp side I had something like:

Code: Select all

 
#include <emscripten.h>
 
// Functions which can to be called from js/html
extern "C"
{
    EMSCRIPTEN_KEEPALIVE void cpp_code_resize_canvas(int width, int height)
    {
        // Not my real code - as you have to get "driver" from somewhere here (involved more classes originally)
        int w, h, fs;
        emscripten_get_canvas_size(&w, &h, &fs);
        const core::dimension2d<u32> canvasDim(w,h);
        const core::dimension2d<u32> screenSize = driver->getScreenSize();
        if ( w > 0 && h > 0)    // going fullscreen w and h tend to be 0 sometimes -not sure yet how to handle this
        {
            //printf("w:%d h:%d screenW:%ud screenH:%ud \n", w, h, screenSize.Width, screenSize.Height);
            if ( canvasDim != screenSize )
            {
                driver->OnResize(canvasDim);
                driver->setViewPort(irr::core::rect<irr::s32>(0,0,w,h));
                //env->getRootGUIElement()->setRelativePosition(irr::core::rect<irr::s32>(0,0,w,h));
                //printf("setRelativePosition w:%d h:%d\n", w, h);
            }
 
            if ( smgr->getActiveCamera() )
            {
                irr::f32 aspect = (irr::f32)w / (irr::f32)h;
                smgr->getActiveCamera()->setAspectRatio(aspect);
            }
        }
    }
}
 
And I called the following js function from cpp after the Irrlicht device is set-up (to avoid the js tries calling cpp functions in onResize before the code is loaded as html is there before the binary code):

Code: Select all

 
EM_ASM( appContextReady() );
 
I should update example again, I just don't find any time currently :-(
Hope it helps a little and sorry again for the messup with wrong .html - I really should have noticed that one earlier.
It's not even tested now yet with the one I just checked-in (did this over lunch-time). I hope I find some time/energy on weekend to take another look.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Emscripten port

Post by LunaRebirth »

Wow, very cool. Would not have figured that out without your help.

Also note that I had to add "-s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall']"" to my makefile LDFLAGS in order to call C functions from JavaScript :)
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Emscripten port

Post by CuteAlien »

Hm, no idea why you needed to export ccall (I don't have that). But good to know.

Still not sure about the reason why the program freezed without "if(!device->run())" - probably it crashes somehow when we try to render without a working device.

I realized by now why I didn't add my html - as emscripten auto-generates one otherwise. And for the one I had the resize didn't work yet. Guess I will have to add the stuff I just posted here.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Emscripten port

Post by LunaRebirth »

I wrote a really basic Python script to generate the Makefile, run emmake, and then modify the HTML output to remove the Emscripten stuff (logo, loading bar, etc) and add the onResize functions.
Maybe you could add it (or change it up to be better .. I didn't make it the best code to look at) to the example to make the output HTML from Emscripten how you want.

Source:

Code: Select all

import os, sys
from subprocess import call
from collections import OrderedDict
 
#########################################
####       MAKEFILE GENERATION       ####
#########################################
#########################################
 
# Makefile generation information
properties = {
    "emmake" : "C:\\emsdk\\emscripten\\1.38.9\\emmake.bat",
    "debug": False,
    "name": "IrrlichtExample",
    "dest": "bin/",
    "sources": {
        "paths": [ "" ], # If you have .cpp files in another folder, could add "folder/" to compile the sources
        "extensions": [ ".cpp", ".c" ]
    },
    "includes": {
        "paths": [ "../../include/" ]
    },
    "CXXFLAGS": {
        "debug": ["-O3"],
        "release": ["-g", "-Wall"],
        "all": ["-fstrict-aliasing", "-std=gnu++11", "-U__STRICT_ANSI__"]
    },
    "LDFLAGS": {
        "debug": ["-O3"],
        "release": ["-s", "DEMANGLE_SUPPORT=1"],
        "all": ["-L../../lib/emscripten", "-lIrrlicht", "-lGL", "-lSDL", "--preload-file", "../../irrlicht-ogl-es/media@/media", "-s ALLOW_MEMORY_GROWTH=1", "-s NO_EXIT_RUNTIME=1", "-s DISABLE_EXCEPTION_CATCHING=0", "-s FULL_ES2=1", "-s EXTRA_EXPORTED_RUNTIME_METHODS=\"['ccall']\""]
        # "-s WEBSOCKET_URL=\"wss://\""] # Uncomment to use https:// instead of http://
    },
    "defines": ["-D_IRR_EMSCRIPTEN_PLATFORM_"]
}
 
# Get properties based on if the application is being built for Release or Debug mode
def getDebugReleaseProperties(property):
    lst = []
    
    if properties["debug"]:
        for flag in properties[property]["debug"]:
            lst.append(flag)
    else:
        for flag in properties[property]["release"]:
            lst.append(flag)
    for flag in properties[property]["all"]:
        lst.append(flag)
    
    return lst
 
# Grab all of the source files
sources = ""
for path in properties["sources"]["paths"]:
    files = os.listdir(path)
    for file in files:
        # Make sure the file has the correct extension
        inExtensions = False
        for extension in properties["sources"]["extensions"]:
            if file[0-(len(extension)) : ] == extension:
                inExtensions = True
                break
        if inExtensions:
            sources += path + file + " "
sources = sources[ : -1]
 
# Append the source files together into a string
includes = ""
for path in properties["includes"]["paths"]:
    includes += "-I" + path + " "
includes = includes[ : -1]
 
# Append the flags together into a string
CXXFLAGS = ""
for flag in getDebugReleaseProperties("CXXFLAGS"):
    CXXFLAGS += flag + " "
CXXFLAGS = CXXFLAGS[ : -1]
 
# Append the flags together into a string
LDFLAGS = ""
for flag in getDebugReleaseProperties("LDFLAGS"):
    LDFLAGS += flag + " "
for define in properties["defines"]:
    LDFLAGS += define + " ";
LDFLAGS = LDFLAGS[ : -1]
 
# Generate the Makefile output
output =                                                                \
"Target := " + properties["name"]                                       + "\n" + \
"Sources := " + sources                                                 + "\n" + \
"CPPFLAGS += " + includes + " -I/usr/X11r6/include"                     + "\n" + \
"CXXFLAGS += " + CXXFLAGS                                               + "\n" + \
"LDFLAGS += " + LDFLAGS                                                 + "\n" + \
"DESTPATH = " + properties["dest"] + properties["name"] + ".html"       + "\n" + \
"all:"                                                                  + "\n" + \
"   $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(Sources) -o $(DESTPATH) $(LDFLAGS)"+ "\n" + \
""                                                                      + "\n" + \
"ifeq ($(HOSTTYPE), x86_64)"                                            + "\n" + \
"LIBSELECT=64"                                                          + "\n" + \
"endif"                                                                 + "\n" + \
"ifeq ($HOSTTYPE), sun4)"                                               + "\n" + \
"LDFLAGS += -lrt"                                                       + "\n" + \
"endif"
 
f = open("Makefile", "w")
f.write(output)
f.close()
 
# Now run emmake make all
call("emmake make all", shell=True)
 
#########################################
####       HTML MODIFICATIONS        ####
#########################################
#########################################
 
htmlFileName = properties["dest"] + properties["name"] + ".html"
htmlLines = open(htmlFileName, "r")
htmlLines = htmlLines.readlines();
 
# Finds the beginning and end lines as well as beginning and end position of an HTML tag.
# If endTag starts with two spaces "  ", then we make sure the endTag is on it's own line
#     May need to change this in the future, but for now it's a simple fix without having
#     a bracket counter.
def findTag(tag, endTag="", beg=0, end=-1):
    if endTag == "":
        endTag = tag[0] + "/" + tag[1 :]
    if end == -1:
        end = len(htmlLines)
        
    endIsOnItsOwnLine = False
    if endTag.find("  ") == 0:
        endTag = endTag[2:]
        endIsOnItsOwnLine = True
    
    foundBeg = -1
    foundBegPos = -1
    foundEnd = -1
    foundEndPos = -1
    for i in range(len(htmlLines)):
        line = htmlLines[i]
        if foundBeg == -1 and line.find(tag) >= 0:
            foundBeg = i
            foundBegPos = line.find(tag) + len(tag)
        if foundBeg >= 0 and foundEnd == -1 and line.find(endTag) >= 0 and (endIsOnItsOwnLine== False or line.strip().find(endTag) == 0):
            foundEnd = i
            foundEndPos = line.find(endTag)
        if foundBeg >= 0 and foundEnd >= 0:
            break
    
    if foundBeg >= 0 and foundEnd >= 0:
        return foundBeg, foundBegPos, foundEnd, foundEndPos
    return -1
 
# Replaces the contents of a tag
def setTag(tag, newVal, endTag=""):
    data_ = findTag(tag, endTag)
    
    if data_ == -1:
        return
        
    if data_[0] == data_[2]:
        htmlLines[data_[0]] = htmlLines[data_[0]][:data_[1]] + newVal + htmlLines[data_[2]][data_[3]:]
    else:
        spacing = ""
        for c in htmlLines[data_[0]]:
            if c.isspace():
                spacing += c
            else:
                break
    
        htmlLines[data_[0]] = htmlLines[data_[0]][:data_[1]] + "\n"
        for i in range(data_[2]-1, data_[0], -1):
            del htmlLines[i]
        newLinePos = data_[2]-(data_[2]-data_[0])+1 # We del lines, so the new pos after deletion
        
        if len(newVal) > 0:
            newVal = spacing + "\t" + newVal + "\n"
        
        htmlLines[newLinePos] = newVal + spacing + htmlLines[newLinePos][data_[3]:]
 
# Removes a tag
def removeTag(tag, endTag):
    data_ = findTag(tag, endTag)
    if data_ == -1:
        return
    
    for i in range(data_[2], data_[0]-1, -1):
        del htmlLines[i]
 
# Adds a javascript source.
# Probably needs to be re-implemented. This was just a super easy way to handle it.
def addScript(script):
    data_ = findTag("<script type='text/javascript'>", "</script>")
    if data_ == -1:
        return
        
    onLine = 0
    for line in script:
        htmlLines.insert(data_[0]-1+onLine, line + "\n")
        onLine += 1
 
# Sets the application title.
setTag("<title>", "Irrlicht Example", "</title>")
# Removes the Emscripten border.
setTag("div.emscripten_border {", "border-width: 0px none;", "}")
# Makes the Emscripten canvas cover the entire browser window.
setTag("canvas.emscripten { border: 0px none;", "position: absolute; top: 0px; left: 0px; margin: 0px; width: 100%; height: 100%; overflow: hidden; display: block; background-color: transparent;", "}")
# Remove the Emscripten logo
setTag("#emscripten_logo {", "visibility: hidden;", "  }")
# Remove the Emscripten loading spinner
setTag(".spinner {", "visibility: hidden;", "  }")
# Remove unnecessary stuff
removeTag("@-webkit-keyframes rotation {", "  }")
removeTag("@-moz-keyframes rotation {", "  }")
removeTag("@-o-keyframes rotation {", "  }")
removeTag("@keyframes rotation {", "  }")
setTag("#status {", "", "  }")
setTag("#progress {", "visibility: hidden;", "  }")
setTag("#controls {", "visibility: hidden;", "  }")
setTag("#output {", "visibility: hidden;", "  }")
# Remove the Emscripten link
removeTag("<a href=\"http://emscripten.org\">", "</a>")
# Allow the window to be told when it is resized
setTag("preRun: ", "( function() { console.log(\"preRun\"); onResize(); } )()", ",")
setTag("<body", " onresize=\"onResize()\"", ">")
# Script to call the C++ resize function
addScript(
    ["  <script type='text/javascript'>",
    "       var __appContextReady = false;",
    "",
    "       function resize(canvas) {",
    "           var realToCSSPixels = window.devicePixelRatio;",
    "           var displayWidth  = Math.floor(canvas.clientWidth  * realToCSSPixels);",
    "           var displayHeight = Math.floor(canvas.clientHeight * realToCSSPixels);",
    "",
    "           // Check if the canvas is not the same size.",
    "           if (canvas.width  != displayWidth ||",
    "               canvas.height != displayHeight) {",
    "",
    "               // Make the canvas the same size",
    "               canvas.width  = displayWidth;",
    "               canvas.height = displayHeight;",
    "           }",
    "           console.log(\"resize:\"  + canvas.width + \"x\" + canvas.height );",
    "           if ( __appContextReady ) {",
    "               console.log(\"cpp_code_resize_canvas\" );",
    "               Module.ccall('cpp_code_resize_canvas', null,  ['number', 'number'], [canvas.width, canvas.height]);",
    "           }",
    "       }",
    "",
    "       function onResize() {",
    "           console.log(\"onResize\");",
    "           resize( document.getElementsByTagName('canvas')[0] );",
    "       }",
    "",
    "       function appContextReady()  {",
    "           if ( __appContextReady == false ) { // Was giving me problems without this. Probably needs to be looked at again.",
    "               __appContextReady = true;",
    "               console.log(\"appContextReady\");",
    "               resize( document.getElementsByTagName('canvas')[0] );",
    "",
    "               var projectId = 0;  // set to 0 for choice with edit-box",
    "               // Module.ccall('i4_set_project_id', null, ['number'], [projectId]); // i4_set_project_id doesn't exist for me. Removing it still works fine though",
    "           }",
    "       }",
    "   </script>"
    ]
    )
 
newCont = ""
for line in htmlLines:
    newCont += line
 
# Overwrite the HTML file with our new HTML contents
f = open(htmlFileName, "w")
f.write(newCont)
f.close()
Again, it's not very good code, but it does all of the work it's intended to do.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Emscripten port

Post by CuteAlien »

You can pass custom html's (I've added documentation in the Makefile for the flag you need for that).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
lunariusis
Posts: 2
Joined: Fri Aug 24, 2018 11:34 pm

Re: Emscripten port

Post by lunariusis »

Hello. I have some problem on compilation example/

my command on compilation:
emcc -v --separate-asm -std=c++11 -O3 --bind -I../include -I/usr/X11R6/include --preload-file ../media@/media -s NO_EXIT_RUNTIME=1 -s VERBOSE=1 -s EMCC_DEBUG=1 -s ASSERTIONS=1 -s DEMANGLE_SUPPORT=1 -L../lib/emscripten -lIrrlicht -lGL -lSDL -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=1 -s DISABLE_EXCEPTION_CATCHING=0 -s FULL_ES2=1 -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall']" -D_IRR_EMSCRIPTEN_PLATFORM_ -std=gnu++11 -U__STRICT_ANSI__ -fno-exceptions -fstrict-aliasing -s TOTAL_MEMORY=268435456 -o ./01.HelloWorld/bin/hello1.html ./01.HelloWorld/main.cpp

warning: unresolved symbol: createDevice

in web console i have this error
hello1.html:1249 missing function: createDevice
Post Reply