Skip to content
This repository has been archived by the owner on Jul 25, 2024. It is now read-only.

Best approach for a kgl-math library? #18

Closed
nlbuescher opened this issue Feb 6, 2020 · 24 comments
Closed

Best approach for a kgl-math library? #18

nlbuescher opened this issue Feb 6, 2020 · 24 comments

Comments

@nlbuescher
Copy link
Collaborator

  • API largely on GLM, with some Kotlinic modifications to the naming
  • Native library wrapped by Kotlin classes should work well
  • glm is C++-only, so maybe cglm? Although from their readme, they seem to be missing some features of glm atm. Not sure if unaligned vectors and matrices are important.
@Dominaezzz
Copy link
Owner

There is this but it's jvm only. I attempted multi-platform, but it was too difficult.

I think a kgl-math library should be written in pure Kotlin. No C/C++ interop to complicate things.
Possibly also separated from kgl (like kotlin-imgui) to simplify the build process.

If the API is based on glm or is a glm port, might as well reconsider contributing (or forking) jglm.

@nlbuescher
Copy link
Collaborator Author

I just took a run at it, and pure kotlin seems the best way. The bindings to cglm require manual memory management, and without a destructor/finalize equivalent, the Arena I was trying to use would never be cleared and will leak nativeHeap allocations. The benefit of using cinterop is obviously enabling the use of simd for performant matrix math.

I'd actually keep the math lib in kgl since it's math designed specifically for graphics programming (obviously with no dependencies to the other modules).

jglm looks like a mess, tbh. The class names are not kotlinic and the library isn't multiplatform. A pure kotlin math lib can be written in common, making it the most portable, and types that in glm are called vec4 and vec3ui, in kotlin should be FloatVector4 and UIntVector3 following the [Type]Array pattern set by the stdlib.

@nlbuescher
Copy link
Collaborator Author

I actually already have working implementations for FloatVector2, FloatVector3, FloatVector4, FloatMatrix3x3, and FloatMatrix4x4 in my game engine project in the common source set, written purely in Kotlin.

@Dominaezzz
Copy link
Owner

SIMD is coming to Kotlin/Native 1.3.70. It's in the release notes. So that area should be covered.

I'm still not 100% about having it in kgl but I guess it can always be yanked out if need be.

Do you think there should be a FloatVector3 and MutableFloatVector3? (Like List<T> and MutableList<T>) Or should they stay as one class? I like the idea of having mutable variants.

@nlbuescher
Copy link
Collaborator Author

nlbuescher commented Feb 7, 2020

That's cool! That'll help mitigate performance issues, definitely.

I've actually thought about that too, and for completeness's sake, probably. Either, you have only immutable variants that create new objects when operations are performed, or you have both. The API in that respect should definitely follow stdlib. The explicitness makes it wordier, but also clearer.

I'll put together what I have in my other project as an example and do a WIP pull request.

@raniejade
Copy link

👋 I'm working on https://github.com/raniejade/godot-kotlin and quite interested in a kotlin (native) math library :)

@nlbuescher
Copy link
Collaborator Author

I'm actually extremely interested in your project too. I was just thinking about tinkering a little with Godot

@Dominaezzz
Copy link
Owner

Awesome. It would be nice to get more input on how this should be done.

@nlbuescher
Copy link
Collaborator Author

Do you think there should be a FloatVector3 and MutableFloatVector3? (Like List<T> and MutableList<T>) Or should they stay as one class? I like the idea of having mutable variants.

I've thought about mutability some more, and I think the best approach is to treat the Vector and Matrix types like the Array types in the stdlib, ie only have mutable variants. They will be implemented using Arrays anyway, and the name MutableFloatMatrix4x4 seems silly.

@Dominaezzz
Copy link
Owner

What if we shortened the name from MutableFloatMatrix4x4 to MutableMatrix4f? Does it still seem silly?
I don't want to give up on immutability, I'd actually prefer if all the math types were immutable but I realise how impractical that may be, so providing both would be ideal.

Also, I'm not sure about Arrays for vectors, perhaps if they were inlined but otherwise it seems like more indirection that necessary. They are useful for pinning but I don't think that it is worth it.

@nlbuescher
Copy link
Collaborator Author

What if we shortened the name from MutableFloatMatrix4x4 to MutableMatrix4f? Does it still seem silly?

Even more so, actually, since that goes against Kotlin naming conventions set up in the stdlib. The main issue with a long class name is using the constructor, and Vector2 and Vector3 types would be used fairly often.

I don't want to give up on immutability, I'd actually prefer if all the math types were immutable but I realise how impractical that may be, so providing both would be ideal.

I do agree with this. I'm still wrapping my head around the auto-boxing thing. This occurs only with generics, correct? So normal inheritance is not an issue?

Also, I'm not sure about Arrays for vectors, perhaps if they were inlined but otherwise it seems like more indirection that necessary. They are useful for pinning but I don't think that it is worth it.

I intended to use arrays in order to spare having to allocate memory for an array every time you pass the Vector or Matrix to a native GL function. We could benchmark using arrays vs using other methods though to see what's faster.

@Dominaezzz
Copy link
Owner

Also, do we really need other types other than Float? Given this is just for gamedev. 😛 . (Options are nice I guess).

Yes, normal inheritance is fine, boxing only happens with generics (or nullability but that could be optimized away). A useful way to wrap your head around it, is to write it in Java because you'll immediately be forced to box the float.
Kotlin adds so much sugar that it's fairly difficult to notice this and micro optimize your code. (Whether that's a good thing or bad thing is debatable).

Ah, that's a good idea. Benchmark! kotlinx-benchmark should help with that when the time comes.

@nlbuescher
Copy link
Collaborator Author

I would include the other types for completeness and because GLM also includes them. They probably won't be used very much, though, as you said, but I'm working on codegen that generates the classes from a list of types and zero values, so it's not hard to add new primitive type vectors to the list.

@elect86
Copy link

elect86 commented Mar 6, 2020

jglm looks like a mess, tbh. The class names are not kotlinic and the library isn't multiplatform. A pure kotlin math lib can be written in common, making it the most portable, and types that in glm are called vec4 and vec3ui, in kotlin should be FloatVector4 and UIntVector3 following the [Type]Array pattern set by the stdlib.

Hi, I take care of glm port, why does it look like a mess to you? Class names can be more kotlin-friendly if it makes sense..

Library isnt multiplatform because there was till yet not reason for me to work on that..

However the main reason for the current naming scheme is the best I could come up with in order to find a reasonable compromise between glsl and jvm syntax.

@nlbuescher
Copy link
Collaborator Author

Hi @elect86! As I mentioned above, I was concerned about both the naming and the lack of multiplatform support. Dominic also mentioned above that he tried to implement muliplatform in a PR and couldn't, hence this library implementation.

@aouerf
Copy link

aouerf commented Apr 27, 2020

Also, do we really need other types other than Float? Given this is just for gamedev. . (Options are nice I guess).

I think a good compromise would be to implement the other numeric types as well but use typealiases for the Float variants to define the default variant. For example, Vector2 would be a typealias of FloatVector2 (or MutableFloatVector2). This also somewhat addresses the issue of having longer names (FloatVector2 vs Vector2f). And since the other type variations are going to be generated, there's no need to worry about maintainability.

I don't want to give up on immutability, I'd actually prefer if all the math types were immutable but I realise how impractical that may be, so providing both would be ideal.

While I do agree with prioritizing immutability, especially since many common operations don't modify the data anyways (dot, inverse), there are many use cases (for users) where it makes more sense to use a mutable data type to avoid having to recreate and reassign to a variable just to change a value. However, for the library functions, I think that it would make sense to return immutables wherever possible.

@nlbuescher
Copy link
Collaborator Author

@aouerfelli Thanks for the input! I'll probably implement the typealias for Float types as you suggested.

I recently took look at how the Unity engine implements math functionality, and I've been struggling with creating complete feature parity to glm in a Kotlinic way because of all the C++ constructs (eg the Long and unsigned vector types basically only exist right now to enable really niche functions to exist). I've been thinking about what exactly the goal of kgl-math should be.

@Dominaezzz Should we aim to port glm for kotlin multiplatform, or is it good enough to create a math library to use for 3D calculations (such as in game engines)? So far I've been trying to do the former, but translating C++ has been slowing me down a lot.

@Dominaezzz
Copy link
Owner

I think we should completely forget about glm and just do the latter.

@nlbuescher
Copy link
Collaborator Author

I agree. It's a lot easier to make something useful first, and then add any missing functionality later. I realized recently that GLM was created based on the glsl standard, and that's something we don't need to mess around with.

@elect86
Copy link

elect86 commented May 25, 2020

A quick update, because I think this might also be interesting for you, guys

I just did a refresh to the multiplatform branch Dominaezzz started by modifying the build.gradle.

I basically did a tabula rasa, I removed:

  • all the source, except a dummy glm object and an empty Mat4 class (names can be different, I dont hold on anything-)
  • the test module
  • all external dependencies (except lwjgl ones)
  • the groovy build.gradle and settings.gradle

And then I create a build.gradle.kts (and the corresponding settings.gradle.kts) following the tutorial on the official website

But since I don't have multiplatform experience at all, it's quite hard for me to continue without anybody assisting me

If someone would like to jump in and contribute, don't hesitate, I'll add you right away

I truly believe on collaboration, that's why I moved all the projects into an organization when I saw there was potential for a community of shared interests, where everybody could benefits from open-source and community-driven development

I think it will be a waste resources-wise if anybody goes its own direction..

There is a lot of potential and common ground: I have a friend working on MPP library for fonts and images and I look forward to a standalone MPP glfw project as well

@nlbuescher
Copy link
Collaborator Author

@elect86 I'll take a look. I actually recently started over with my work too and am close to a basis for view projections in game math. what other features need to be added I'm not sure, will depend on community, but I definitely think that a math library should be independent of glm. So far all of what I've written is implemented in a common module.

@elect86
Copy link

elect86 commented May 26, 2020

@elect86 I'll take a look. I actually recently started over with my work too and am close to a basis for view projections in game math. what other features need to be added I'm not sure, will depend on community, but I definitely think that a math library should be independent of glm. So far all of what I've written is implemented in a common module.

It depends what you mean by independent. Porting 1 to 1 C glm to Jvm/Kotlin doesn't make sense.

Having the same semantic and the same logic (and almost the same functions signature) is, instead, a big advantage.

You can port things from C/C++ world without taking care of "translating" the mathematical part. This means:

  • lower curve to move to learn it
  • a much bigger (experienced) audience/community when you need support
  • bigger chance somebody already did what you want to do

Also, given OpenGL shaders are based on GLSL and you can compile them also for Vulkan, and kgl actually support exactly these two APIs, I honestly don't see any reason why anybody would like to avoid the GLSL standard (which is however quite logical and clear though).

Having the possibility to test shaders in kotlin with very small changes it's also a big plus (take a look at this video from Romain Guy at KotlinKonf '18)

Moreover, since today most of (advanced) real time 3d graphic is dominated by the C/C++ language, I believe it makes sense if we follow (as much as it makes sense in a kotlinic way of course) the standards there established instead creating our owns

Of course this is a process that is best tested on and crafted by the field. That means we start small and we see how it plays with native, jvm, its performances, its usability, pro and vs, and then we react and drive the development accordingly.

My 2 cents

@nlbuescher
Copy link
Collaborator Author

To wrap up the discussion, I think the best approach is to focus efforts of a glm-like library for game dev on kotlin-graphics/glm going forward.

@elect86
Copy link

elect86 commented Nov 23, 2021

Just as an info, I've picked up again interested in this and trying to move the current glm to multiplatform + code generation via KSP

If anyone wants to give some feedbacks, that's the moment :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants