Panda3D WebGL Port!

Thanks @rdb That was the problem.

How do I generate the .bc files like those used in the --preload-file argument in freezify.py?

I’m trying to get a project with multiple files running. I assume generating .bc files would be the best way to do this, but I don’t know if it would be the most easy to use for others once I have it setup.

Now, I have the editor working in an Angular JS project. Hopefully, it’s a short ride to Android using Cordova after that. If anyone’s interested, I plan to post a seed project to Github. (I tried Angular 6 & 7, but I couldn’t get it to play nice after ~10 days. Angular JS took 2.)

It seems I’m close to getting a project up using freezer.addModule. Now I’m getting errors about missing Python modules. This one and another from collections saying no operator module exists. I see an “operator.bc” and an “itertools.bc” in the python-modules folder. So, I’m not sure why the error?

File "heapq", line 132, in 
ImportError: No module named itertools

When I add these to the bottom of your main.py I get the following error.

import itertools
import operator
import collections
import heapq

" Loading…
Downloading data…
Running…
Invalid function pointer called with signature ‘vii’. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)
Build with ASSERTIONS=2 for more info.
48"

The .bc files are emscripten-generated bytecode files produced as result of building Python and Panda3D.

This is not the same as the files that are passed to --preload-file, which become part of emscripten’s virtual file system. You can just pass any files you like using as many of these options as it takes. It is also possible to package all your assets as a .mf and then mount that in your Panda game using the virtual file system, though.

Make sure that the itertools.bc is actually being added by freezify as part of the command-line.

As for the error message, this indicates an issue with CPython which violates the C standard on casting incompatible function pointers in a lot of different places. I’ve fixed many cases where it does this, but there may be missing cases. If you add -s ASSERTIONS=2 it will add more debugging information which will help track down which specific function call needs to be fixed in CPython.

I posted an angular project with some instructions on how to git it running. With the instructions and those I gave above, you should be able to compile your own and switch it out for the /app/panda-engine/panda-engine27.js file.

It’s just a starting point. I believe you can use Cordova to get on Android or IPhone, but I haven’t gotten that far.

Does anyone know how to get past this? I suspect it started when I added render to texture to my project.

:display:gsg:gles2gsg(warning): Immutable texture storage advertised as supported by OpenGL runtime, but could not get pointers to extension functions.

:display:gsg:gles2gsg(warning): Indirect draw advertised as supported by OpenGL runtime, but could not get pointers to extension functions.

WebGL: INVALID_ENUM: getParameter: invalid parameter name, WEBGL_draw_buffers not enabled

WebGL: INVALID_ENUM: getParameter: invalid parameter name

WebGL: INVALID_ENUM: getParameter: invalid parameter name

:display:gsg:gles2gsg(warning): GL_ARB_sampler_objects advertised as supported by OpenGL runtime, but could not get pointers to extension function.

In case anyone else runs into this.
Adding “#version 300 es, got rid of” to my shaders got rid of “WEBGL_draw_buffers not enabled”

EDIT (I can’t add what I’ve done without editing this post)

To get rid of the WEBGL_draw_buffers error without adding the 3.0 version to the shader I added the first #ifdef __EMSCRIPTEN__ calling for drawBuffers to panda/src/glstuff/glGraphicsStateGuardian_src.cxx. I bet this can be coded better. I tested #version 100 es

#if defined(OPENGLES_1)
  _glDrawBuffers = NULL;
  _max_color_targets = 1;

#elif defined(OPENGLES_2)
  if (is_at_least_gles_version(3, 0)) {
  #ifdef __EMSCRIPTEN__
    _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
      get_extension_func("drawBuffers");
  #else
    _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
      get_extension_func("glDrawBuffers");
  #endif
#ifdef __EMSCRIPTEN__
  } else if (has_extension("WEBGL_draw_buffers")) {
    _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
      get_extension_func("glDrawBuffers");
#endif  // EMSCRIPTEN

There’s no glTexStorage1D in WebGL, best I can tell.
https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml

This does not account for any down stream calls to _glTexStorage1D. I replaced this first block with that below:

  if (_supports_tex_storage) {
    if (_glTexStorage1D == NULL || _glTexStorage2D == NULL || _glTexStorage3D == NULL) {
      GLCAT.warning()
        << "Immutable texture storage advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
      _supports_tex_storage = false;
    }
  }



  if (_supports_tex_storage) {
#ifdef OPENGLES
    if (_glTexStorage2D == NULL || _glTexStorage3D == NULL) {
#else
    if (_glTexStorage1D == NULL || _glTexStorage2D == NULL || _glTexStorage3D == NULL) {
#endif
      GLCAT.warning()
        << "Immutable texture storage advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
      _supports_tex_storage = false;
    }
  }

I successfully compiled the WebGL port, but get this error when trying to run the music box program. abort(To use dlopen, you need to use Emscripten’s linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking).

Hi, you would need to use “-s MAIN_MODULE=1” to activate dlfcn support, but note that emsdk upstream (clang 10) version does not actually support that but is the version that will replace fastcomp sooner or later.

So be sure to have selected “fastcomp” branch

Meanwhile you may want to watch https://github.com/emscripten-core/emscripten/issues/9516 about when webgl port will be able to use upstream emscripten. or you can modify makepanda to statically link everything and call initializer yourself via C ( eg after python init )

Thanks for the info. Where do I put the “-s MAIN_MODULE=1”? I am using freezify.py from this zip file http://rdb.name/webgl-music-box.zip.

Sorry that’s a long time i did not use freezify, it was first used with python2. i’ve switched to python 3.7/3.8, web assembly and a more generic approach for cross compiling both android and emscripten.

maybe try linkExe with “-s MAIN_MODULE=1 -s EXPORT_ALL=1 -ldl” ?

sidenote libpython is ready as can be seen there https://pmp-p.github.io/python-next/test.html
but panda3d libraries are more exigeant and will need few months work to run (they already build) with emscripten upstream.

now it works fine https://pmp-p.github.io/panda3d-next/py3/

maybe help try porting some demos with https://github.com/pmp-p/pydk-applications

I am getting this error. error: Linking globals named ‘Py_FrozenMain’: symbol multiply defined!
shared:ERROR: Failed to run llvm optimizations:

I updated this archive to contain a build of Python 3.8 instead of the deprecated Python 2.7:
http://rdb.name/webgl-editor-and-dependencies.zip
It also includes the patch and command I used to build it. The Roaming Ralph sample and build script are included.

I also committed WebGL 2 support to the webgl-port branch, and I updated the online editor demo to use Python 3.8, WebAssembly and WebGL 2:
http://rdb.name/panda3d-webgl/editor.html

3 Likes

Some updates: I have created two modules, emscripten and browser, that enable more interoperability with the browser and the JavaScript runtime.

With these modules, it’s now possible to make a call to any JavaScript or Web API directly from Python. It’s even possible to use Python functions as callbacks, but it’s not possible to store any other Python objects inside the JavaScript runtime, or access Python objects from JS.

I updated my editor.html link with a few extra samples showing how this is used. For example, you can use the browser’s XMLHttpRequest API or the newer Fetch API to download resources (although note that the emscripten module provides a more convenient and efficient, albeit less powerful, interface for downloading files).

To use these modules, download these files:
http://rdb.name/panda3d-webgl/browsermodule.c
http://rdb.name/panda3d-webgl/emscriptenmodule.c
… and add them to your build. It’s easiest to just add these two lines to the top of your frozenMainCode:

#include "emscriptenmodule.c"
#include "browsermodule.c"

… and adding them to sys.modules, after initializing the Python interpreter:

    PyObject *sys_modules = PySys_GetObject("modules");
    PyDict_SetItemString(sys_modules, "emscripten", PyInit_emscripten());
    PyDict_SetItemString(sys_modules, "browser", PyInit_browser());

I may decide to bundle these with the Python distribution, since they’re not Panda-specific.

1 Like

I would like to embed Panda3D in a Jupiter notebook cell. Do you think it is doable ? And if so, do you think it is a lot of working to get pre-compiled binaries with cross-platform compatibility ?

I don’t know anything about how Jupyter works, sorry.

Hello, I want to use Enscriptem to compile a Panda example to html and Js so I can run it on localhost. I’m not sure what the steps are to do this. Any help would be appreciated!

I’ve updated the WebGL branch with a new feature: the HTTPClient and HTTPChannel APIs are now supported in the browser. As a consequence, we can use Panda’s HTTP mount system to mount web folders to the virtual file system. By default, Panda will mount the current web root to the root of the virtual file system.

This means it is no longer necessary to add files to the preload bundle. You can just load a texture or model and if the file is not present in the preload bundle, it will be automatically downloaded relative to the current directory on the server!

I have also updated https://rdb.name/webgl-editor-and-dependencies.zip, updated for the latest emscripten version and the Python version is now updated to 3.8.10.

I have also created some documentation that explains how to compile the WebGL port and how to build an application for the web:
https://rdb.name/panda3d-webgl.md.html

4 Likes

Thanks @rdb for pushing up the changes and adding docs! This is super exciting stuff.

I tried running through the WebGL compilation guide but am getting stuck at step 1.3:

cd editor
python3.8 -OO freezify.py

I edited my freezify.py to point to the correct directories. When I run it, emscripten complains:

emcc: error: /home/.../panda3d/built/lib/libp3openal_audio.a: No such file or directory
("/home/.../panda3d/built/lib/libp3openal_audio.a" was expected to be an input file,
based on the commandline arguments provided)

I’m not sure where to get this static library file libp3openal_audio.a. FWIW, I’ve attempted to build third party dependencies using makepanda.py --everything on both master and webgl-port.

I do have libp3openal_audio.so instead. However if I disable the PANDA_STATIC flag in order to use dynamic libs, emscripten complains with something different:

emcc: error: /home/.../panda3d/built/panda3d/core.o: No such file or directory
("/home/.../panda3d/built/panda3d/core.o" was expected to be an input file,
based on the commandline arguments provided)

I’m not sure how to emit this core.o object file.

If anyone could provide some pointers on how to get one or both of libp3openal_audio.a or core.o it would be greatly appreciated :slight_smile:

Are you following these instructions? They include a makepanda command for building the WebGL port, which includes the --static flag (along with some other required flags, like --target emscripten). That’s what I recommend that since that’s what I use and it works well.

I am not sure exactly how the Python modules like core.o are emitted by makepanda in a non-static build—do they simply have the .so extension? Please take a look in the built/panda3d directory to see if they were built at all or what they were called.

If they weren’t built at all, look at the output of the makepanda command in the webgl-port branch, it may give some clues.

Ah my bad, looks like in my debugging I cleared the built folder and never ended up rerunning makepanda.py with the right flags. Everything’s working now, appreciate the help (and this awesome update)!