Lwjgl3: Bullet C API first thoughts

Created on 19 Nov 2018  Â·  66Comments  Â·  Source: LWJGL/lwjgl3

Hi! This is more of an opinion but now that I've been trying to port my stuff to Bullet's C API and worked a bit with it I'm having doubts about it.

The API itself is very awkward to use. I didn't think it'd be a problem but all the indirect handles and indices you have to keep around to operate on things are very annoying.

The API refuses to work with structs directly, since it's thought as a client-server architecture, what you have on the "client side" are usually int64 handles or int32 indices referring to some item on the server side, and a set of many functions that each mutate/read a field of the logical structure on the server side, one by one.

The API is robotics and Python oriented, so I am guessing it only exposes what is useful and practical for both of them.

This means that something really useful in games like collision filters isn't there by default, you have to enable it through a plugin. Moreover, something like a kinematic body (like say, a player) isn't there at all, so instead of setting the velocity of the player you have to move it around with instantaneous forces (unless there is actually a way and I'm an idiot), using forces this way is very hard to fine tune player movement or anything really.

This also means there is a lot of fluff there that isn't relevant for games at all. There are a lot of core functions there purely dedicated to work with the included visualizer of the physics simulation. Until very recently the only way to load an arbitrary mesh body was through a robotics focused file format, instead of you know, an array of vertices.

What I am trying to say is that the client-server layer between the user and Bullet isn't helping at all. It's just bloat a game doesn't needs.

Now the thing is that for 3D there aren't many physics libraries to use out there. And out of them all, Bullet is probably the most documented and widely used, although that's the case for the plain C++ library, not the C API, I doubt there is any game made with it.

It doesn't means there aren't any alternatives:

Newton Dynamics has a C API, seems pretty clean and it has been used on a few relevant games(Mount & Blade, Frictional Games stuff, ie SOMA and Amnesia). Even less examples although it has a demo project with a bunch of things. It's zlib licenced.

Open Dynamics Engine has been used on a bunch of games (Techland stuff, ie Call of Juarez, Dead Island) and I've read it has a C API... I just don't understand enough of the repo to know where to look for it. Looking for examples I get results from 2006. It's BSD or LGPL licenced. There is a Java port of it but it uses 64 bit floats everywhere and the first issue you see in the repo is an unresolved high garbage creation complaint from 2015, both of them bad signs.

I think I like more Newton Dynamics since it looks more like what you'd expect of a "proper" C library. Like a single header with most of the structs and function definitions for starters. I don't really know how hard it'd be to have bindings for it too so people (like me!) can try it out.

In any case, for now I'll keep trying to work with Bullet's C API and probably nag the author about some missing functionality as/if I find it, since as I've said in another occasion, with it I can get rid of libGDX as a dependency in my project which is a big plus for me.

Maintenance

Most helpful comment

You may want to wait a few days before attempting to create new bindings. I've been working on a tool that extracts LWJGL template definitions from C/C++ headers. I'm currently in the process of trying different headers to fix corner cases and polish it up.

The tool uses libclang (via new Clang/LLVM bindings) to parse the headers and traverse the AST. It detects both declarations and associated comments for documentation. Comments in doxygen format are supported and can be traversed to detect e.g. param/return documentation, but the tool tries to attach any comments it can find.

This is what it currently generates for Newton.h with a single click.

All 66 comments

Unrelated to LWJGL, but you can try ode4j if you do not mind pure Java solution.

There is a Java port of it but it uses 64 bit floats everywhere and the first issue you see in the repo is an unresolved high garbage creation complaint from 2015, both of them bad signs.

I do mind.

You can also take a look at jMonkeyengine bullet wrapper
https://wiki.jmonkeyengine.org/jme3/advanced/physics.html#technical-overview
https://github.com/jMonkeyEngine/jmonkeyengine

And if you want a sever side bullet physic simulation with an EntityComponentSystem design like what I am doing for my mmorpg, you can consider
https://hub.jmonkeyengine.org/t/ecs-in-complex-3d-games-how-deep-should-it-go/40665/5?u=ali_rs
https://hub.jmonkeyengine.org/t/is-jmonkey-the-right-engine-for-simulating-basic-physics/40714/13?u=ali_rs

it will add bunch of dependencies though ;)

it will add bunch of dependencies though ;)

Yeah, trading libGDX for jMonkeyInterop is a side step for me, maybe a step back since jme is even bigger.

In any case, I think this is an issue better suited for a native lib rather than a Java solution, the question is which one.

I didn't know there were other physics engines with a C API, for some reason I thought the other physics engines were C++ only like Bullet was. So I suggested Bullet's C API to Spasi as soon as I found it existed out of ignorance mostly, didn't know about Newton Engine's .

My line of thinking was "Hey, I used Bullet before and it was really straightforward and easy to integrate, its C API cant be that much different!". I was wrong.

Well I cloned Newton's repo and LWJGL's repo since this is a good moment as any to try learn how to make a new binding with it (not that I have the expectation of getting something usable out of my attempt).

From what I've read in https://github.com/LWJGL/lwjgl3/tree/master/doc what I ought to do, since I've followed the setup steps and everything seems to work, is just grab this header file, create a newton.kt and NewtonTypes.kt file, grab a cup of coffee and start typing the data type definitions, and the function definitions?

For the function definitions a chunk of the work could be done with some clever find+replace, but for the data type definitions it seems it's just a lot of typing.

You may want to wait a few days before attempting to create new bindings. I've been working on a tool that extracts LWJGL template definitions from C/C++ headers. I'm currently in the process of trying different headers to fix corner cases and polish it up.

The tool uses libclang (via new Clang/LLVM bindings) to parse the headers and traverse the AST. It detects both declarations and associated comments for documentation. Comments in doxygen format are supported and can be traversed to detect e.g. param/return documentation, but the tool tries to attach any comments it can find.

This is what it currently generates for Newton.h with a single click.

That is awesome, dude! Really, really cool.

Sadly now you solved the part I thought I understood better, and now I have to actually try to compile the thing :smile:

On the Bullet bindings: I'm considering disabling Bullet for the 3.2.1 release until there's more feedback.

The bindings will still be available in snapshots after the release. This should give us enough time (until 3.2.2?) to evaluate other options before committing to anything. Maintenance effort should not be wasted on bindings that no one is going to use.

I agree. I do think that LWJGL should offer a physics engine binding, since at least for game development it'd leave LWJGL more rounded. I just don't think Bullet's C API is the one.

I've been using Newton lately and the C API is indeed very clean and nice to work with :100: . It would be a great addition to lwjgl

Any updates on the template generator tool magic thingy?

I gave a quick jab at making that gist working. It's missing a couple things. For example, the definition of the type 'long_long' (which I believe it'd just map like an int64_t), also _Bool,
and after all the types were defined, it was missing the initial section that goes something like:

val Newton = "Nuklear".nativeClass(Module.NEWTON, prefix = "", prefixMethod = "", library = "lwjgl_newton") {
// yadda yadda
}

And I'm getting an NPE while ant generate'ing NewtonUserMeshCollisionRayHitCallback that I don't understand because I have zero clue about Kotlin :smile:

Probably there is more stuff I haven't reached yet.

Any updates on the template generator tool magic thingy?

Yes, it's been available for a while. It's fully featured now, but I'm sure there are still corner cases that are not handled properly, so please consider it a beta and report any issues you face.

You'll need to download or build LLVM/Clang on your machine, then run the tool with:

ant extract -Dclang=<path to libclang>

Ah cool, then I already had it and didn't notice it :smile: Thanks!

To try out the tool, it seems I have to compile first LLVM bindings. So I try to do that with just enabling LLVM in build-bindings.xml, then doing 'ant compile-templates' but I'm having issues.

First there is this:
https://github.com/LWJGL/lwjgl3/blob/master/modules/lwjgl/llvm/src/templates/kotlin/llvm/templates/ClangIndex.kt#L3059

long_long seems to be missing from the type definitions:
https://github.com/LWJGL/lwjgl3/blob/master/modules/generator/src/main/kotlin/org/lwjgl/generator/GlobalTypes.kt

I add it like:

val long_long = IntegerType("long long", PrimitiveMapping.LONG)

And if I try to compile again, I get an "overload resolution ambiguity" error on those long_long returning functions.

EDIT: Nevermind, I mixed up with the old 'long_long' I had added for Newton, turns out LLVM's bindings had its own long_long defined which clashed with the global one I added.

I can launch the tool, but once I add Newton's folders and headers, I get this exception:

java.lang.NoClassDefFoundError: Could not initialize class org.lwjgl.llvm.ClangIndex$Functions
    at org.lwjgl.llvm.ClangIndex.clang_createIndex(ClangIndex.java:2706)
    at org.lwjgl.extract.ExtractionContext.<init>(Extract.kt:60)
    at org.lwjgl.extract.ExtractKt.parse(Extract.kt:174)

It's like ClangIndex is there, but the inner Functions class isn't.

EDIT: Yeah I really don't get it, inspecting the generated ClangIndex.class and ClangIndex$Functions.class, they're there. No idea why the tool can't find it.
EDIT2: Tried re-compiling and and running everything in both Java 8 and Java 11, still having the same issue.
EDIT3: I can't for the life of me make IDEA debug the ant process. I use the debug configuration "GENERATOR" but it wont stop at any breakpoint on the Kotlin code.

This usually means that static initialization of the inner Functions class failed. For example, it can happen if you're using an older libclang version that doesn't expose a newer function pointer. I haven't done any work on versioning the LLVM/Clang bindings, it's likely that the latest version is required.

Try running the tool with:

ant extract -Dclang=<path to libclang> -Djvmargs="-Dorg.lwjgl.util.Debug=true -Dorg.lwjgl.util.DebugLoader=true"

Is there any useful output?

I use the debug configuration "GENERATOR" but it wont stop at any breakpoint on the Kotlin code.

Probably because this launches the Generator via Ant in a forked JVM process. Try setting fork to false (build.xml:271).

I'm not entirely sure why but I fired up IntelliJ today and it started generating like half of the JNI.java class, a lot of "invokeXYZ" functions were missing. I just reverted it to the repo's version since that had everything but I have no clue what went wrong.

In any case:

Probably because this launches the Generator via Ant in a forked JVM process

You're right, changed the fork to false and breakpoints started working.

Is there any useful output?

It launches normally but there isn't any additional output. I mean, it launches in a separate process like you said at first, so there is no debug output (or any output) from the terminal where I launch it.

If I prevent the 'extract' tool to be forked with the flags, I can no longer pass the required arguments to the process (like clang's path). They seem to be getting ignored.

I mean, if I launch with the debugger from IntelliJ like:

ant extract

It complains that Dclang wasn't passed, if I pass it like:

ant extract -Dclang=path

It complains "-Dorg.lwjgl.llvm.clang.libname=path" wasn't passed. If I pass that like:

ant extract -Dclang=path -Dorg.lwjgl.llvm.clang.libname=path
// or
ant extract -Dclang=path -Djvmargs="-Dorg.lwjgl.llvm.clang.libname=path"

It also gets ignored, it doesn't seems to reach the Configuration class.

I also tried setting it directly from the build.xml file like

 <jvmarg value="-Dorg.lwjgl.llvm.clang.libname=path"/>

But it's still null in the program when I put a breakpoint in main.

I'm guessing the debug flags are getting ignored too.

All right. Managed to get the debugger working via adding a bunch of flags to the extract tool in build.xml (Xdebug, debugging agent and friends) then attaching IntelliJ's debugger after the ant task forked the process and adding an exception breakpoint.

With that I managed to inspect the inner exceptions on a "ExceptionInitializerError" that occurred the first time (after that the JVM just throws the NoClassDefFoundError exception if you try to extract the definitions again).

Turns out the message is:

A required function is missing: clang_Type_getObjCObjectBaseType

... But Google knows nothing about "getObjCObjectBaseType"

In any case, my libclang version is 7.0.1-1, from Debian's "testing" repositories, is that recent enough? Or am I pointing to the wrong .so?

ant extract -Dclang=/usr/lib/llvm-7/lib/libclang.so.1

EDIT: Turns out 'experimental' repositories have libclang 8, so I used that instead and now ClangIndex gets initialized correctly, but I am getting an UnsatisfiedLinkError on JNI.invokeP when ClangIndex.clang_createIndex gets called. I'm not understanding if it means there is some clang stuff missing, or if the native core of LWJGL isn't getting loaded.

EDIT2: Well turns out that even the native part of the JNI.java class got halfway generated so it was also missing a bunch of invokeXYZ functions, that's why invokeP threw an unsatisfied link error. So I recompiled that, with the complete .c file, and now my grand error message is:

о&�>

Your tool hates me, Spasi.

started generating like half of the JNI.java class

The LWJGL generator gathers all native calls necessary to support the various bindings and creates a deduplicated set (based on call convention and signature) that goes into the JNI.java class. This makes the core LWJGL shared library smaller. When some bindings are disabled, the set usually becomes smaller, so that's what's happening.

Your tool hates me, Spasi.

Hmm, yeah, ant extract also uses fork="true" spawn="true". Fwiw, if I change a ClangIndex function name to something random, I can see the stacktrace in the tool's "console" panel. With spawn="false", I also get the same output on the terminal that runs ant extract.

Anyway, you can run the tool from within IntelliJ with the Template Extraction Tool run configuration. Just edit it to set the correct org.lwjgl.llvm.clang.libname. You should be able to debug normally like that.

What version of clang are you using?

EDIT:

When some bindings are disabled, the set usually becomes smaller, so that's what's happening.

So I only had LLVM/Clang bindings enabled, but the generated JNI.java class (and its native counterpart) didn't have invokeP and others in it, which is used by the LLVM/Clang bindings. Is that ok?

Anyway, you can run the tool from within IntelliJ with the Template Extraction Tool

Geezus you're right, why didn't I see it before. That launches the tool fine, if I point to Clang 7 I get the initialization error, if I point to Clang 8 I get a segfault so the debugger ain't much help there.

First segfault was in some deep Swing code, second was in a native stack frame I think. So it looks like a memory corruption thingy. Kinda weird.

What I do is:

  1. Launch it from IntelliJ pointing to libclang 8.
  2. Add dNewton, dgNewton and dgCore to the include paths.
  3. Add dgNewton/Newton.h as the main header.
  4. Click extract.

Am I doing something wrong?

EDIT2:

Even if I cant use the generator, I can try with the gist you posted earlier. So far I'm stuck on the generate part. First thing I noticed was that the order of declaration was important in the type definitions. I was getting NPEs on the callbacks since those used structs that were defined later in the file.

Once I got that sorted out I started to get "Data pointer not validated" exceptions on a few of the functions like:
https://gist.github.com/Spasi/0d064d5382ab2e037d04eca42aefa459#file-newton-kt-L1054
https://gist.github.com/Spasi/0d064d5382ab2e037d04eca42aefa459#file-newton-kt-L1062

What does it means? I can just add "Unsafe.." to them but I'm not sure what is it doing, what kind of validation is it expecting? Like a length/size parameter?

What version of clang are you using?

I'm using version 8, built from source (~Oct 27), on Windows.

if I point to Clang 8 I get a segfault

Please attach a crash dump, it might be helpful.

When I have time, I'll do some testing on Linux. I'll also try to make 8.0 functions optional, so that the tool can run on a stable 7 build.

For now, I have updated the gist above to the latest Newton.h. I did have some trouble parsing it, because the tool runs in C mode basically and the header had some invalid constructs (that are valid in C++). Fixed them manually and I also had to add --include=stdbool.h to the compiler arguments.

I was getting NPEs on the callbacks since those used structs that were defined later in the file.

Yes, this might happen, the tool outputs callbacks before structs. I can probably change this so that the header order is respected.

What does it means? I can just add "Unsafe.." to them but I'm not sure what is it doing, what kind of validation is it expecting? Like a length/size parameter?

Adding appropriate modifiers to pointer parameters is the most important part of creating LWJGL bindings and it's something that cannot be automated. You must carefully examine the documentation/implementation of each function and, at the very least, add the following modifiers:

  • nullable to optional pointer parameters/members. When missing, LWJGL ensures (at runtime) that such values are never NULL.
  • Check to pointer parameters/members with known length (Check(1) is very common).
  • AutoSize/AutoSizeResult to integer parameters/members that specify the size of other, pointer parameters/members or return values. Several different cases here, you can find examples in other bindings.
  • char<Encoding> to null-terminated string parameters/members (e.g. plugInPath in NewtonLoadPlugins). This is not a modifier, you simply change the char type to a more specific one.
  • Unsafe to pointer parameters/members that cannot be made safe with any of the above (e.g. ptr in NewtonFree).

Please attach a crash dump, it might be helpful.

hs_err_pid10248.log

For some reason I get a segfault if I launch it from IDEA. If I launch it from a terminal, then attach the debugger, I get garbled console output in the tool. This is testing with libllvm 8.

I'm using version 8, built from source (~Oct 27), on Windows.

I'm using libllvm 8 from revision 350193 in their SVN repo, which is ~700 commits behind current master (350916), it's what Debian 'experimental' repos have. The 'testing' repos have libllvm 7.0.1

I have updated the gist above to the latest Newton.h
I'll do some testing on Linux. I'll also try to make 8.0 functions optional, so that the tool can run on a stable 7 build.

Awesome, thanks!

Yes, this might happen, the tool outputs callbacks before structs. I can probably change this so that the header order is respected.

Yeah I think that'd be good.

Adding appropriate modifiers to pointer parameters is the most important part of creating LWJGL bindings [...] You must carefully examine the documentation/implementation of each function

Ah so you're saying I should know what I am doing, any more unreasonable requests? :smile:

I have one question, when you do the 'nativeClass' extension method, the "prefixMethod" is the string that every method will be prefixed with ("Newton" in this case), but what is the plain "prefix"? Is it for constants?

I found this thing with the generator, look at this callback:

    typedef dLong (*NewtonGetTimeInMicrosencondsCallback) ();

Seems fine, no args and returns a long.

Now the generated template for this is:

val NewtonGetTimeInMicrosencondsCallback = Module.NEWTON.callback {
    long_long(
        "NewtonGetTimeInMicrosencondsCallback",
        "",
        void()
    ) {
        documentation = "Instances of this interface may be passed to the #FIXME() method."
    }
}

Which generates a callback with a void argument. Legal in C, not so legal in Java.

This has the problem that when you ask it to generate the .java files, it does this:

        @Override
        public long invoke(void *) {
            return delegate.invoke(*);
        }

Which is invalid. The C code seems fine so I'm guessing this is something the template generator has to transform? Or the template processor should not add an argument if it's void?

EDIT:
Going a bit further, it seems the tool also confuses multi dimensional arrays. There are a couple fields in Newton's C code that are like:

dFloat m_offsetMatrix[4][4]

With the tool seemingly generating:

float.p("m_offsetMatrix", "")[4]

Which causes issues later on on .java code generation, since it tries to pass a FloatBuffer to a function that doesn't accepts one when generating the accessor for that field.

I fixed it with

float("m_offsetMatrix", "")[16]

EDIT2:

Well I wanted to try out just generating bindings for one of Newton's C examples, so far I got the types and I'd need to generate bindings for a couple functions only.

I got NewtonTypes.kt working, so I wanted to try out the native compilation step before making the few function bindings in Newton.kt.

I'm not understanding the build process, is it trying to download compiled artifacts from your build server? I'm getting exceptions like:

 Can't get https://build.lwjgl.org/nightly/linux/x64/newton/libdVehicle.a to /home/user/git/lwjgl3/bin/libs/linux/x64/newton/libdVehicle.a

EDIT4:

I think I understand, I copied the build section from Bullet, and that one has a bunch of sections.

<!-- NEWTON -->
<build module="newton" simple="true" linker="g++" if:true="${binding.newton}">
    <beforeLink>
        <mkdir dir="${lib}/${platform}/${build.arch}/newton"/>
        <parallel threadsPerProcessor="2" failonany="true" unless:set="lib-uptodate">
            <update-dependency name="Newton01" artifact="${build.arch}/newton/libdMath.a"/>
            <update-dependency name="Newton02" artifact="${build.arch}/newton/libdgCore.a"/>
            <update-dependency name="Newton03" artifact="${build.arch}/newton/libdScene.a"/>
            <update-dependency name="Newton04" artifact="${build.arch}/newton/libnewton.a"/>
            <update-dependency name="Newton05" artifact="${build.arch}/newton/libdNewton.a"/>
            <update-dependency name="Newton06" artifact="${build.arch}/newton/libdVehicle.a"/>
            <update-dependency name="Newton07" artifact="${build.arch}/newton/libdgPhysics.a"/>
            <update-dependency name="Newton08" artifact="${build.arch}/newton/libdAnimation.a"/>
            <update-dependency name="Newton09" artifact="${build.arch}/newton/libdContainers.a"/>
            <update-dependency name="Newton10" artifact="${build.arch}/newton/libdCustomJoints.a"/>
            <update-dependency name="Newton11" artifact="${build.arch}/newton/libtinyxml.a"/>
        </parallel>
    </beforeLink>
    <link>
        <arg value="-ldl"/>
        <arg value="-L${lib}/${platform}/${build.arch}/newton"/>
        <arg value="-lNewton01"/>
        <arg value="-lNewton02"/>
        <arg value="-lNewton03"/>
        <arg value="-lNewton04"/>
        <arg value="-lNewton05"/>
        <arg value="-lNewton06"/>
        <arg value="-lNewton07"/>
        <arg value="-lNewton08"/>
        <arg value="-lNewton09"/>
        <arg value="-lNewton10"/>
        <arg value="-lNewton11"/>
    </link>
</build>

I'm guessing those kind of libraries are the ones you don't commit to the repo because they're too big, so you make it download the artifacts from a build server, right?

Which generates a callback with a void argument. Legal in C, not so legal in Java.

Not related to Java. The template DSL is supposed to look like C and it actually has some of its quirks (e.g. using (void) on functions with no arguments). This must be the first time it's occurred on a callback though. It's a minor bug and will be fixed soon. For now, simply drop void().

it seems the tool also confuses multi dimensional arrays

Thanks, will have a look.

I'm guessing those kind of libraries are the ones you don't commit to the repo because they're too big, so you make it download the artifacts from a build server, right?

Correct. Unfortunately, Bullet doesn't support shared library builds, so LWJGL links it statically. We should use Newton as a shared library if possible.

This must be the first time it's occurred on a callback though.

Literally uncharted lands :smile:

We should use Newton as a shared library if possible.

Yeah it has a shared library flag and everything. But now I'm wondering, it looks like it wont be possible to build it with just the script, it has a bunch of CMakeLists.txt inside defining each a separate module, this means I'd have to pull all .so files from somewhere in my local file system for now.

How do I do that? <update-dependency> tries to fetch it from your build server.

Also I'm not understanding if LWJGL supports loading multiple .so/.dll for a single library, or if it expects everything to be packaged into a single dependency. Which one is it?

EDIT:

I just found out that you can make a single .so out of multiple .a with GCC, by simply sitting on the output folder and doing:

gcc -shared -o newton.so -Wl,--whole-archive libdAnimation.a libdContainers.a libdCustomJoints.a libdgCore.a libdgPhysics.a libdMath.a libdNewton.a libdScene.a libdVehicle.a libnewton.a libtinyxml.a -Wl,--no-whole-archive

I had read it before but I didn't understood what it was until Newton guy pointed it out to me. I'm not entirely sure if there is any drawback in using it that way instead of going and editing the ~10 CMakeLists.txt in Newton so it outputs a single .so, maybe some optimizations are lost in the way since it works with pre-compiled code? No idea honestly.

EDIT2:

Well I think I managed to compile something, I mean, a 1.2MB liblwjgl_newton.so file at least. I ended up with this build config:

<!-- NEWTON -->
<build module="newton" simple="true" linker="g++" if:true="${binding.newton}">
    <beforeLink>
        <mkdir dir="${lib}/${platform}/${build.arch}/newton"/>
        <copy todir="${lib}/${platform}/${build.arch}/newton" flatten="true">
            <path>
                <pathelement path="${src.main}/src/build/lib/libdMath.a"/>
                <pathelement path="${src.main}/src/build/lib/libdgCore.a"/>
                <pathelement path="${src.main}/src/build/lib/libdScene.a"/>
                <pathelement path="${src.main}/src/build/lib/libnewton.a"/>
                <pathelement path="${src.main}/src/build/lib/libdNewton.a"/>
                <pathelement path="${src.main}/src/build/lib/libdVehicle.a"/>
                <pathelement path="${src.main}/src/build/lib/libdgPhysics.a"/>
                <pathelement path="${src.main}/src/build/lib/libdAnimation.a"/>
                <pathelement path="${src.main}/src/build/lib/libdContainers.a"/>
                <pathelement path="${src.main}/src/build/lib/libdCustomJoints.a"/>
                <pathelement path="${src.main}/src/build/lib/libtinyxml.a"/>
            </path>
        </copy>
    </beforeLink>
    <link>
        <arg value="-ldl"/>
        <arg value="-L${lib}/${platform}/${build.arch}/newton"/>
        <arg value="-ldMath"/>
        <arg value="-ldgCore"/>
        <arg value="-ldScene"/>
        <arg value="-lnewton"/>
        <arg value="-ldNewton"/>
        <arg value="-ldVehicle"/>
        <arg value="-ldgPhysics"/>
        <arg value="-ldAnimation"/>
        <arg value="-ldContainers"/>
        <arg value="-ldCustomJoints"/>
        <arg value="-ltinyxml"/>
    </link>
</build>

That is, cmake && make'ing the library manually, then letting the script copy back the resulting .a, then linking them up all together into a single .so.

I noticed I wasn't getting any generated C file and I didn't realize that the libraries have a "nativeDirective" call in the template to include the required header files. So I copied Newton.h into the main/c folder, fixed two warnings, and compiled all the types plus just two random functions (WorldGetVersion and something else) to try it out.

Now, given that I have a lwjgl_newton.so, and a bunch of .class files, how do I package all of this up?

tries to fetch it from your build server.

If you export the LWJGL_BUILD_OFFLINE=true environment variable, the Ant build will stop looking online for anything.

I'm not understanding if LWJGL supports loading multiple .so/.dll for a single library, or if it expects everything to be packaged into a single dependency. Which one is it?

Multiple shared libraries for a single binding should be fine. Currently the LLVM/Clang bindings work like that. The CUDA bindings will also use multiple shared libraries soon, when more CUDA Toolkit libraries are supported.

In case multiple shared libraries need to be bundled with LWJGL, the release-module target must be configured with a custom natives definition (examples: GLFW, OpenAL, OpenVR).

you can make a single .so out of multiple .a with GCC

This is the preferred solution. Should be done for all platforms in CI, then LWJGL simply downloads and bundles a single shared library (like bgfx, GLFW, OpenAL, etc.).

Well I think I managed to compile something [...] how do I package all of this up?

This is different from using a shared library and calling it via org.lwjgl.system.JNI (the preferred solution I mentioned above). Sounds like it's exactly the same setup as Bullet, so use that as a reference (search for binding.bullet in the Ant scripts).

Just to be clear:

  • Solution A: CI builds a shared library that exports all Newton functions. The LWJGL build downloads and bundles the shared library. At runtime, LWJGL loads the shared library and the function addresses, calls them via org.lwjgl.system.JNI. There is no generated C code in this case (i.e. no liblwjgl_newton.so, just a libnewton.so) and you don't need to add the Newton headers anywhere.

  • Solution B: CI builds a bunch of static libraries. LWJGL downloads the static libraries, links them to a shared library that exports JNI functions (that call the corresponding Newton functions). There is generated C code in this case (so you need the Newton headers and appropriate nativeDirective calls) and there should be a liblwjgl_newton.so that will be used by LWJGL at runtime.

The first solution is very simple to configure in LWJGL, but you'll need to worry about bundling the static libraries as a shared library in the CI scripts. Doing this for all 3 platforms and making sure the functions are properly exported (see _NEWTON_BUILD_DLL in Newton's header, is there a CMake option that sets it?) might be a bit of work.

So I found the release target while searching for binding.bullet but it fails with:

[module-info-gen] core: OK
[module-info-gen] core.natives: OK
[module-info-gen] nuklear: FAILED
[module-info-gen] compiler.err.package.empty.or.not.found
[module-info-gen] ERROR
[module-info-gen] 180
[module-info-gen] 171
[module-info-gen] 187
[module-info-gen] org.lwjgl.generator.util.ModuleInfoGen$1MemoryJavaFileObject[file:///home/user/git/lwjgl3/modules/lwjgl/nuklear/src/main/java/module-info.java]
[module-info-gen] package is empty or does not exist: org.lwjgl.newton

The only binding I (think) have enabled is Newton. I dont understand why it says "nuklear: FAILED", it isn't even compiled.

I have no clue why it says the "package is empty or does not exist" either. The Newton .class files are generated and with that exact package... Although I don't see a module-info.class in the Newton folder inside bin now that I think of it. I added it in newton/src/resources/module-java.info though.

I was launching the ant generate/compile/etc tasks with Java 8 as JAVA_HOME, should I have used Java 11?

Both issues sound odd. Is there a fork/branch somewhere I could clone and test locally?

I was launching the ant generate/compile/etc tasks with Java 8 as JAVA_HOME, should I have used Java 11?

No, Java 8 is fine. Later versions are only used in release (for ModuleInfoGen and javadoc generation).

All right, I've made a fork with the stuff I changed.

https://github.com/dustContributor/lwjgl3

I omitted the generated stuff, Newton's source code and some IDEA files.

The Newton revision I'm trying is:

https://github.com/MADEAPPS/newton-dynamics/tree/4b82923fd3172c4ddbccc3dfe2ed68b5652d8376

This was after the author saw some GCC incompatibility that I stumbled upon trying to compile it, he fixed it in that commit.

Newton's source was placed in modules/lwjgl/newton/src/main/c/ like the other bindings. It's CMake lists config was:

option("NEWTON_BUILD_SANDBOX_DEMOS" "generates demos projects" OFF)
option("NEWTON_BUILD_PROFILER" "build profiler" OFF)
option("NEWTON_BUILD_MULTI_THREADED" "multi threaded" ON)
option("NEWTON_DOUBLE_PRECISION" "Generate double precision" OFF)
option("NEWTON_STATIC_RUNTIME_LIBRARIES" "use windows static libraries" OFF)
option("NEWTON_WITH_SSE_PLUGIN" "adding asse parallel solver" OFF)
option("NEWTON_WITH_SSE4_PLUGIN" "adding avx parallel solver" OFF)
option("NEWTON_WITH_AVX_PLUGIN" "adding avx parallel solver" ON)
option("NEWTON_WITH_AVX2_PLUGIN" "adding avx parallel solver" OFF)
option("NEWTON_WITH_DX12_PLUGIN" "adding direct compute 12 parallel solver" OFF)
option("NEWTON_BUILD_SHARED_LIBS" "Build shared library" OFF)

I built it manually from the console and had that build step in linux/build.xml copy back the .a files and link them together.

I also copied Newton.h into modules/lwjgl/newton/src/main/c/ so the #include Newton.h would work on the generated C code.

As you can see the .kt files have a lot of stuff commented out because I wanted to just try to see if I could get a few functions working and the structures.

Also my build-bindings.xml file has everything disabled but newton bindings.

That's about it. Give me a heads up if you need anything else.

I've fixed some of the issues mentioned above:

  • The LLVM/Clang bindings now require version 5.0 or higher (down from 8.0).
  • void() can now be used in callbacks with no parameters.
  • Multi-dimensional arrays are now supported. Both in the extract tool and in the LWJGL generator's type system.

I'm now changing the extract tool so that it respects the order of declarations in parsed headers, then I'll have a look at your fork.

Hey @dustContributor, please try the following:

  • Rebase your commit against the current master HEAD (f376e5a95937154715c4e057578e33a2c2fdd3c4).
  • Apply this patch.
  • Run ant clean compile-templates compile-native. This should produce a working liblwjgl_newton.so than you can test.

I've fixed a few issues, did some cleanup and other tedious stuff (license, README, gradle, etc.) and uploaded Linux & Win64 static libraries for Newton to build.lwjgl.org. This commit, built locally, I'll set up LWJGL-CI at a later time. Use LWJGL_BUILD_OFFLINE=true if you'd like to replace them with a newer build.

If you'd like, open a pull request, which will give me access to push more fixes directly to your branch.

Thank you Spasi, I'm on it.

Receiving objects:  24% (1885/7828), 284.00 KiB | 11.00 KiB/s 

... albeit slowly :smile:

uploaded Linux & Win64 static libraries for Newton to build.lwjgl.org [...] Use LWJGL_BUILD_OFFLINE=true if you'd like to replace them with a newer build.

No problem, If I can get my thingy to be able to push boxes around again I'll be happy. Besides it seems Julio is coding away some crazy inverse kinematics stuff currently, dunno when he will make a stable(ish) release.

I have one question, in the patch you have:

<build simple="true" module="nuklear" if:true="${binding.nuklear}">

Was that the reason it was trying to build Nuklear regardless of the configuration? I thought I had deleted the 'if:true' check by mistake or something but I see the flag check isn't in master either.

Was that the reason it was trying to build Nuklear regardless of the configuration?

I could not reproduce the ant release issue (tried it after working on everything else), but probably not. That flag controls native compilation only. I think the issue was in Newton's module-info.java, the module name was wrong (module org.lwjgl.nuklear).

Btw, don't bother with ant release, it doesn't support local builds yet. It always tries to download artifacts from build.lwjgl.org.

I think the issue was in Newton's module-info.java, the module name was wrong (module org.lwjgl.nuklear).

Ah duh, I didn't notice it. Yeah probably it was that.

don't bother with ant release

Hmm... So what do I use to package the module into a .jar then? Besides doing it myself by stuffing a .zip file I mean.

Hmm... So what do I use to package the module into a .jar then?

Normally I don't need this when working on new bindings, because all tests & samples are written within LWJGL. It is not necessary to package anything to run them. But since many users have made this request, I added support for offline releases and incomplete local Maven deployments with 9485e8b7c9471d9aac3d5dc6c9ad95e1eeaaaff9.

When the LWJGL_BUILD_OFFLINE=true environment variable is set, ant release will copy files from bin/libs instead of downloading anything from build.lwjgl.org. Missing files (e.g. shared libraries for other platforms) will be ignored and the corresponding .jar files won't be generated. You can comment out the javadoc generation section of release-module for faster builds.

The Gradle build now also supports incomplete deployments to the local Maven repository. Source, javadoc and natives artifacts that are missing will be silently ignored. I would recommend adding a -LOCAL suffix to such builds (see build.gradle, line 44).

Great! In this case since you set it up I was going to use your uploaded natives.

... But I'm having issues with them:

  [get] Error opening connection java.io.IOException: Server returned HTTP response code: 403 for URL: https://build.lwjgl.org/nightly/linux/x64/liblwjgl_newton.so

Since it returns access denied on everything (ie, can't navigate it like an FTP directory) I'm not sure if they're missing or what exactly is happening.

https://build.lwjgl.org/nightly/linux/x64/liblwjgl_newton.so

I have not uploaded liblwjgl_newton.so, just Newton's various .a libraries (see nightly/linux/x64/newton). Using the above patch you should be able to easily build liblwjgl_newton.so. With 9485e8b7c9471d9aac3d5dc6c9ad95e1eeaaaff9, you can then do an offline ant release.

You're right, I misunderstood your instructions, it worked like you said. I managed to get all the lwjgl-newton*.jar files.

Now I should be able to setup some test code...

public static final void main ( final String[] args ) {
  System.out.println( Newton.NewtonWorldGetVersion() );
  System.out.println( Newton.NewtonGetMemoryUsed() );
}
0

Wooo! Hopefully the next two functions wont take me 3 months and asking you what do I do 40 times :smile:

I have a question about opaque pointers, of which Newton makes heavy use of for its C bindings.

When you have a pair pf functions like:

    NewtonWorld.p(
        "Create",
        "",
        void()
    )
    void(
        "Destroy",
        "",
        NewtonWorld.const.p.const("newtonWorld", "")
    )

While NewtonWorld's definition being:

val NewtonWorld = "NewtonWorld".opaque

LWJGL essentially treats it as a void*, since makes it so it returns a long, and methods that accept NewtonWorld instances just accept a long.

    @NativeType("NewtonWorld *")
    public static native long NewtonCreate();
    public static void NewtonDestroy(@NativeType("NewtonWorld const * const") long newtonWorld)

Is there a difference between using SomeType.opaque and just using void.p?

Since it doesn't seems to generate a NewtonWorld class for the opaque pointer, looks like type safety is lost along the way. ie, NewtonCreate just returns a long, and NewtonDestroy(long) just receives a long in Java side, instead of returning and accepting a NewtonWorld instance respectively.

Is this done on purpose? Or am I doing something wrong?

On a different issue, this function here:

    void(
        "SetMemorySystem",
        "",

        NewtonAllocMemory("malloc", ""),
        NewtonFreeMemory("free", "")
    )

Where NewtonAllocMemory is a callback that receives an int parameter and returns a void, and NewtonFreeMemory is a callback that receives a void and returns nothing.

I'm getting this bit of native code generated for it in the first line:

void * (*) (int) malloc = (void * (*) (int))(intptr_t)mallocAddress;

Which I think it's trying to cast the address to the callback/function pointer type, but my compiler (GCC 8.2) complains:

void * (*) (int) malloc = (void * (*) (int))(intptr_t)mallocAddress;
         ^ 
error: expected identifier or ‘(’ before ‘)’ token

I'm unfamiliar with C so I don't outright understand if the syntax is really okay or not.

EDIT1:

Disregard what I said, it happens the same on a callback that doesn't returns void*, C glue code wont compile:

// Callback definition
typedef void (*NewtonApplyForceAndTorque) (const NewtonBody* const body, dFloat timestep, int threadIndex);
// Function that uses it
NEWTON_API void  NewtonBodySetForceAndTorqueCallback (const NewtonBody* const body, NewtonApplyForceAndTorque callback);
// Generated C code that doesn't compiles
JNIEXPORT void JNICALL JavaCritical_org_lwjgl_newton_Newton_nNewtonBodySetForceAndTorqueCallback(jlong bodyAddress, jlong callbackAddress) {
    NewtonBody const * const body = (NewtonBody const * const)(intptr_t)bodyAddress;
    void (*) (NewtonBody const * const, float, int) callback = (void (*) (NewtonBody const * const, float, int))(intptr_t)callbackAddress;
    NewtonBodySetForceAndTorqueCallback(body, callback);
}

Kotlin code:

val NewtonApplyForceAndTorque = Module.NEWTON.callback {
    void(
        "NewtonApplyForceAndTorque",
        "",
        NewtonBody.const.p.const("body", ""),
        float("timestep", ""),
        int("threadIndex", "")
    ) {
        // documentation = "Instances of this interface may be passed to the #FIXME() method."
    }
    void(
        "BodySetForceAndTorqueCallback",
        "",

        NewtonBody.const.p.const("body", ""),
        NewtonApplyForceAndTorque("callback", "")
    )
}

Is there a difference between using SomeType.opaque and just using void.p?

Yes, they're mapped differently in the Java API.

"SomeType".handle and "SomeType".opaque.p are always mapped to long. They both represent handles (i.e. pointers to opaque structures). Their data is private to the native library and never accessed directly.

void.p is mapped to ByteBuffer and sometimes to IntBuffer/FloatBuffer/etc. when it makes sense (using the MultiType modifier). For example, glBufferData takes a void.const.p and glMapBuffer returns a void.p. The data can be anything, but the application knows what it is and can directly manipulate it.

There's no difference in the native API of course, both are passed as jlong to JNI.

<...> looks like type safety is lost along the way. <..> Is this done on purpose? Or am I doing something wrong?

That's correct, handles are not type-safe in LWJGL. This is a trade-off that favors performance, i.e. avoiding (Java) allocation overhead for handles. Many handles have long life-cycles and cannot benefit from escape analysis as much as data pointers wrapped in NIO buffers. Also, most handles in non-demo code are wrapped & encapsulated in other Java classes anyway, so the drawbacks are limited in practice.

This is all going to change in LWJGL 4 of course, handles will become value types (see Project Valhalla), which are type-safe and zero-overhead.

I think it's trying to cast the address to the callback/function pointer type, but my compiler (GCC 8.2) complains

The callback definitions are missing native typedefs. I've fixed the template extraction tool to emit them and updated the Newton gist (callbacks have a nativeType parameter now). I'll also fix the generator to support function protos without a typedef as function parameters, they're currently supported as struct members only.

Yes, they're mapped differently in the Java API.

Right, forgot void.p is mapped to a XYZBuffer, which doesn't makes sense for an opaque pointer.

That's correct, handles are not type-safe in LWJGL. This is a trade-off that favors performance

Yeah I imagined it to be the case.

This is all going to change in LWJGL 4 of course, handles will become value types (see Project Valhalla), which are type-safe and zero-overhead.

And coming in like 2021 with a lot of luck :smile: I don't know about struct passing but it seems GraalVM doesn't uses JNI for its native interop. I wonder if they'll test drive a JNI 2.0 with that.

The callback definitions are missing native typedefs. I've fixed the template extraction tool to emit them and updated the Newton gist

Cool, thanks! Although...

I botched my merge of those changes :sob: :sob: :sob: I had a conflict, apparently I messed up the resolution, and now I'm missing commits all the while git says everything is up to date... I think I'll fork again :pensive:

All right, re-made my fork and updated with the latest changes. Now, of course, I'm hitting another error:

[Generator] Caused by: java.lang.IllegalStateException: Failed to resolve link: #FIXME() in NewtonWorldDestructorCallback
[Generator]     at org.lwjgl.generator.GeneratorTarget$processDocumentation$1.invoke(GeneratorTarget.kt:254)

The error makes sense, because it isn't a valid javadoc link, but I am not entirely sure why it didn't pop up before since I never touched the "FIXME" links.

I'm checking the history of GeneratorTarget.kt and CallbackFunction.kt but I don't see any recent changes that would have changed this behavior.

EDIT: I just replaced all #FIXME() with whatever else so it doesn't tries to resolve them as javadoc links for now.

EDIT2: Wohoo, made this tiny example work in Java.

public static final void main ( final String[] args ) {
    var world = Newton.NewtonCreate();
    long body;
    var force = new Vector3f( 0, 1, 0 ).get( MemoryUtil.memCallocFloat( 3 ) );
    try ( var mem = MemoryStack.stackPush() ) {
        var mat = new Matrix4f().identity().get( mem.mallocFloat( 16 ) );
        var empty = mem.callocFloat( 16 );
        var coll = Newton.NewtonCreateSphere( world, 1.0f, 0, empty );
        body = Newton.NewtonCreateDynamicBody( world, coll, mat );
        Newton.NewtonBodySetMassMatrix( body, 1.0f, 1, 1, 1 );
        Newton.NewtonBodySetForceAndTorqueCallback( body, ( bod,tstep,thi ) -> {
            Newton.NewtonBodySetForce( bod, force );
        } );
    }
    for ( int i = 0; i < 60; i++ ) {
        Newton.NewtonUpdate( world, 1.0f / 60.0f );
        if ( (i % 5) == 0 ) {
            try ( var mem = MemoryStack.stackPush() ) {
                var bmat = mem.mallocFloat( 16 );
                Newton.NewtonBodyGetMatrix( body, bmat );
                System.out.println( new Matrix4f().set( bmat ) );
            }
        }
    }
    System.out.println( "used before: " + Newton.NewtonGetMemoryUsed() );
    Newton.NewtonDestroyAllBodies( world );
    Newton.NewtonDestroy( world );
    System.out.println( "used after: " + Newton.NewtonGetMemoryUsed() );
}

Kinda impressed it didn't SIGSEGV immediatly :smile:

EDIT4: While this is very good, to be completely honest I skimmed Newton's forums and the author... scares me a little.

I am not entirely sure why it didn't pop up before since I never touched the "FIXME" links.

Callbacks are evaluated in a final step after the generation of all bindings has succeeded. Most likely, you were hitting errors earlier in the process and never got to generating callbacks before.

So, I'll be waiting your evaluation on how the Newton bindings feel. My biggest worry is that there are too many callback types and upcalls are super-slow via JNI (at least an order of magnitude slower than downcalls). I'm not familiar with Newton's API, but if the number of callback invocations depends on scene complexity, JNI overhead will probably limit scalability.

Most likely, you were hitting errors earlier in the process and never got to generating callbacks before

Yeah, now that you mention it, you're probably right.

My biggest worry is that there are too many callback types and upcalls are super-slow via JNI

It's true, but I don't think it can be helped. AFAIK most physics engines do most of their contact/collision/intersection events through callbacks, I don't think Newton is "special" in that regard.

So would it be possible to include Newton in the latest nightly or provide other means of download?
I'd very much appreciate being able to test it, too.

I got new developments :smile:

https://gfycat.com/happygoluckyaltruisticanemonecrab

This is using the few implemented Newton functions in my LWJGL fork. Apparently the "apply force and torque" callback is called for all bodies every "tick" in Newton, unless the body is static (ie, mass 0). Kinda curious too that you have to apply gravity in said callback "manually", instead of having a "NewtonSetWorldGravity(long handle, float gravity)" like you'd have in other libraries.

I guess it could impact performance like Spasi said.

Anyway, next milestone is implementing a 'kinematic' body for the "player", that is, a body that is moved by forces outside the simulation that still can collide and stuff.

So would it be possible to include Newton in the latest nightly or provide other means of download?

You could try to clone my LWJGL fork I guess... Then try to build it. This isn't something Spasi is upstreaming, rather it's just stuff I am doing on my own LWJGL fork so Spasi can keep working on The Great Plan undisturbed by my incessant questions.

Hey @Spasi I have some issues, I am trying to map this function:

void* NewtonWorldAddListener (const NewtonWorld* const newtonWorld, const char* const nameId, void* const listenerUserData)

Afaik the void* listenerUserData is an unsafe pointer.

The char* nameId apparently is a fixed length string. I mean, Newton inside copies it back, and that m_name has a fixed length . It isn't in the docs, what's the approach to take here? Check(32)..charUTF8.const.p? Unsafe..charUTF8.const.p?

In any case, even if I add those, it complains on the sizing of the returned pointer:

    void.p(
        "WorldAddListener",
        "",

        NewtonWorld.const.p.const("newtonWorld", ""),
        Check(32)..charUTF8.const.p.const("nameId", ""),
        Unsafe..void.p.const("listenerUserData", "")
    )

Gives:

Caused by: java.lang.IllegalStateException: No AutoSizeResult parameter could be found.

That's an opaque pointer I think, and I have no clue how to tell LWJGL not to worry about it. I CTRL+F'd around for a bit and I haven't found templates that does this.

NanoVG's ctx pointer is opaque, and the template works like this:

val NVGcontext = "NVGcontext".opaque

... 

val ctx = NVGcontext.p

That's a type definition, not a function definition. I am trying to define a function, as you can see in the code I wrote.

EDIT: Unless I'm missing something I've been looking over 15 bindings and nothing has an un-sized void* as a return value :thinking:

This case is similar, though I guess not enough perhaps. This makes a proper opaque return for the NVGContext struct. See the return usage at https://github.com/LWJGL/lwjgl3/blob/master/modules/lwjgl/nanovg/src/templates/kotlin/nanovg/templates/nanovg_gl2.kt#L61.

The corresponding C for that function is: NVGcontext* nvgCreateGL2(int flags);, and NVGContext is
simply typedef struct NVGcontext NVGcontext;.

I would think you can do something similar with void by doing "void".opaque, but perhaps the lack of size breaks something. Though, considering that it's a _pointer_, why does size matter? The pointer size is always the same.

Well using "void".opaque works on the return type, it generates this on the native side:

JNIEXPORT jlong JNICALL JavaCritical_org_lwjgl_newton_Newton_nNewtonWorldAddListener(jlong newtonWorldAddress, jlong nameIdAddress, jlong listenerUserDataAddress) {
    NewtonWorld const * const newtonWorld = (NewtonWorld const * const)(intptr_t)newtonWorldAddress;
    char const * const nameId = (char const * const)(intptr_t)nameIdAddress;
    void * const listenerUserData = (void * const)(intptr_t)listenerUserDataAddress;
    return (jlong)(intptr_t)NewtonWorldAddListener(newtonWorld, nameId, listenerUserData);
}

I guess that would work, both on 32 and 64 bit, but I'm not sure if it's how it should be used. In any case, that's enough for trying stuff out stuff, thanks!

Cool! I also used it for the functions that expected the void* listener as a parameter, since LWJGL would generate a ByteBuffer parameter with Unsafe..void.p which doesn't really makes sense in this context.

Hey @dustContributor,

The char* nameId apparently is a fixed length string. I mean, Newton inside copies it back, and that m_name has a fixed length . It isn't in the docs, what's the approach to take here? Check(32)..charUTF8.const.p? Unsafe..charUTF8.const.p?

No, use charUTF8.const.p.const without a modifier, i.e. a simple null-terminated string. It's safe because the 32 value passed to strncpy is the maximum string size. The copy will stop when it encounters a \0 or when it reaches 32 characters, whichever comes first.

Check(32) would make the function require a string with at-least 32 characters, which is wrong. Unsafe would simply remove the null-termination check, which is... unsafe.

That's an opaque pointer I think, and I have no clue how to tell LWJGL not to worry about it

There's opaque_p in GlobalTypes, which is just a reusable "void".opaque.p. Use it like this:

opaque_p(
    "WorldAddListener",
    "",

    NewtonWorld.const.p.const("newtonWorld", ""),
    charUTF8.const.p.const("nameId", ""),
    opaque_p.const("listenerUserData", "")
)

There's opaque_p in GlobalTypes

Ah right, I think I've seen it before but I forgot about it.

use charUTF8.const.p.const without a modifier, i.e. a simple null-terminated string

Makes sense, thanks!

I hit an issue when adding a bunch of functions:

Error:

[Linker] /usr/bin/ld: /tmp/ccekMsSv.ltrans0.ltrans.o: in function `JavaCritical_org_lwjgl_newton_Newton_nNewtonHingeCalculateStopAlpha':
[Linker] <artificial>:(.text+0x601): undefined reference to `NewtonHingeCalculateStopAlpha'

Function definition in Newton.h

NEWTON_API dFloat NewtonHingeCalculateStopAlpha (const NewtonJoint* const hinge, const NewtonHingeSliderUpdateDesc* const desc, dFloat angle);

Binding in templates/Newton.kt

    float(
        "HingeCalculateStopAlpha",
        "",
        NewtonJoint.const.p.const("hinge", ""),
        NewtonHingeSliderUpdateDesc.const.p.const("desc", ""),
        float("angle", "")
    )

Generated native glue in org_lwjgl_newton_Newton.c

JNIEXPORT jfloat JNICALL JavaCritical_org_lwjgl_newton_Newton_nNewtonHingeCalculateStopAlpha(jlong hingeAddress, jlong descAddress, jfloat angle) {
    NewtonJoint const * const hinge = (NewtonJoint const * const)(intptr_t)hingeAddress;
    NewtonHingeSliderUpdateDesc const * const desc = (NewtonHingeSliderUpdateDesc const * const)(intptr_t)descAddress;
    return (jfloat)NewtonHingeCalculateStopAlpha(hinge, desc, angle);
}
JNIEXPORT jfloat JNICALL Java_org_lwjgl_newton_Newton_nNewtonHingeCalculateStopAlpha(JNIEnv *__env, jclass clazz, jlong hingeAddress, jlong descAddress, jfloat angle) {
    UNUSED_PARAMS(__env, clazz)
    return JavaCritical_org_lwjgl_newton_Newton_nNewtonHingeCalculateStopAlpha(hingeAddress, descAddress, angle);
}

I don't understand, the function looks ok, the parameters look ok, the generated glue looks ok. I have the same issue with 3-4 more functions.

On a side note, after using it for a bit I've realized that a whole bunch of Newton code isn't and probably wont be exposed to Java.

There is the core API, afaik defined in dgNewton, dgPhysics, dgCore, and probably dMath and dNewton although I'm not sure. This is exposed as C functions through Newton.h, but there are a lot of side modules (dVehicle, dAnimation, dCustomJoints, dScene, etc) that look more like convenience C++ classes that use the base C API to do a bunch of things.

This means I don't think we'd really need most of the dXYZ libraries linked into the main .so for the base C API to work, this is probably what the CMake 'NEWTON_BUILD_CORE_ONLY' flag does.

Looks like there's no implementation for this function in Newton.cpp. Better report this to Newton's developers.

Duh it didn't occur to me to look at the .cpp, thanks, I'll comment them out for now then.

Spasi, I have a question about callbacks. I have a call like this:

var contacts = NewtonWorldConvexCast(newtonWorld,
        mat4Buffer,
        vec3Buffer,
        collider,
        float1Buffer,
        MemoryUtil.NULL,
        (body, shape, u) -> owner.body == body ? 0 : 1, // Capturing lambda
        contactBuffer,
        0);

The capturing lambda is a callback with the signature (long, long, long) -> int. It's a filter for the cast call, so the filter is run for each body colliding with the convex shape, and returns if it should be included in the resulting contact list or not.

If I do that inside a loop, LWJGL will allocate in native memory a new callback every time right? I mean, those have to be freed manually? Is there a way to stack allocate them? Or this isn't the case?

If I do that inside a loop, LWJGL will allocate in native memory a new callback every time right?

Yes.

I mean, those have to be freed manually?

Yes. If the debug allocator is enabled, it will tell you if you're leaking callbacks.

Is there a way to stack allocate them?

No. Callbacks must live in executable memory.

The best approach is to instantiate (and reuse) a callback instance instead of a lambda. Note that each callback type is mapped to a CBTypeI interface and a CBType abstract class. You can create a CBType instance using either an anonymous inner class or the CBType.create(<lambda>) factory method.

You can use the userData parameter to "capture" per-invocation data. You could also use Java-based solutions (ThreadLocal?) if that's not enough.

I see, thanks! Do ThreadLocals work if the callbacks are called from threads created on the native side? That is, do they get run under a JVM thread regardless when transitioning back to Java-land?

Another thing I am wondering is that unless I am misunderstanding something, there isn't a way to reuse callback instances without giving up the "type safe" call.

For instance, if I have a signature like Lib#LibMethod(FloatBuffer, FloatBuffer, SomeCallbackI) where both FloatBuffers are checked so they can hold 3 floats and are non-null.

Whatever I pass as SomeCallbackI instance, it calls SomeCallbackI#address inside that LibMethod function, then delegates to nLibMethod. That 'address' call will in turn call Callback#create, which will allocate a new executable callback right?

So if I want to have a reusable callback, I have to do it like:

// In a constructor/init method/somewhere
this.callbackAddress = ((SomeCallbackI)(a) -> doStuff(a)).address();
// then when calling the native method in a loop
Lib.nLibMethod(memAddress(fba), memAddress(fbb), this.callbackAddress);

So I got my reusable callback, but I had to give up the automatic null/size checks for those float buffers since I am using the 'n' version of the method.

Is this is how its done? Or am I missing something?

Do ThreadLocals work if the callbacks are called from threads created on the native side? That is, do they get run under a JVM thread regardless when transitioning back to Java-land?

Foreign threads that attach (dynamically and asynchronously) to the JVM are mapped to a java.lang.Thread and ThreadLocal should work. But I'm not sure how that would be useful.

I was talking about calling a function from Java that does some work and triggers callbacks back into Java. Those callbacks will be invoked on the same thread that initiated the action (a good example is glfwPollEvents). In such a case, you could prepare a ThreadLocal before the call and it'll have the expected value when read from inside the callback.

there isn't a way to reuse callback instances without giving up the "type safe" call

There is a way, I have explained how in my previous reply:

The best approach is to instantiate (and reuse) a callback instance instead of a lambda. Note that each callback type is mapped to a CBTypeI interface and a CBType abstract class. You can create a CBType instance using either an anonymous inner class or the CBType.create(<lambda>) factory method.

Using your example:

SomeCallback cb = SomeCallback.create(a -> doStuff(a)); // reusable
Lib.LibMethod(fba, fbb, cb);

SomeCallback implements SomeCallbackI and the above works. Calling .address() on SomeCallback does not create a new callback every time.

Ahh right, I didn't see that Callback#address override that just returns the long field, makes sense, thanks!

There's another bullet C wrapper here: https://github.com/AndresTraks/BulletSharpPInvoke/tree/master/libbulletc that is a lot closer to the C++ API. I don't know if it is better than Newton or not.

We now have another version of the Bullet bindings (libbulletc #480). The API is a straightforward wrapper around the C++ API, which is as bad as it sounds, but still better than the "official" client/server C API. It should be available for testing in the first snapshots after the 3.2.3 release.

Interestingly, like Newton, the C++ API has too many callbacks. Newton has 54 callback types and it looks like Bullet has more than that. Also, you end up calling tons of trivial C++ methods (e.g. btPersistentManifold_getContactPoint), whereas in a sanely designed C API you'd simply get a buffer back and iterate in the managed language.

JNI overhead is going to hurt.

So, yeah, it doesn't look good on the physics front. We'll probably have bindings for both Bullet and Newton soon, to gather user feedback, but I'm still open to better suggestions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SpinyOwl picture SpinyOwl  Â·  3Comments

knokko picture knokko  Â·  4Comments

nickclark2016 picture nickclark2016  Â·  5Comments

erikmartinessanches picture erikmartinessanches  Â·  3Comments

Hugobros3 picture Hugobros3  Â·  7Comments