recp / cglm

📽 Highly Optimized 2D / 3D Graphics Math (glm) for C
MIT License
2.35k stars 231 forks source link

Make API C++-friendly #182

Open legends2k opened 3 years ago

legends2k commented 3 years ago

In #83, I see one of the comments

Also I would recommend against caring about or supporting C++. Realisitically no one would use this library over GLM if you're using C++. GLM is just a more mature, stable library. Keep your focus and energy on everything C related.

No, this isn't true. I'm writing a C++ program and I like cglm more than glm :)

I'd really appreciate if cglm has an API that' easy to use with a C++ compiler. For example

glm_lookat(vec3{50.f, 10.f, 20.f}, GLM_VEC3_ZERO, GLM_ZUP);

doesn't compile on g++ 10. It screams

Error: taking address of temporary

This is because I used the array API and so vec3 eye decays into float *eye and vec3{50.f, 10.f, 20.f} is a temporary.

Now I know cglm is a C-centric library and I appreciate and respect it. However, the idea proposed in #83 is pretty good:

#ifdef __cplusplus
#define GLM_IN(X)    const X&
#define GLM_INOUT(X)       X& 
#define GLM_OUT(X)         X&
#else
#define GLM_IN(X)    const X
#define GLM_INOUT(X)       X
#define GLM_OUT(X)         X
#endif

/* C and C++ version */
glm_vec3_norm((vec3){1, 2, 3});

/* C++ version if const X& is enabled otherwise: compiler error like 'No matching function for call to...' */
glm_vec3_norm({1, 2, 3});

I think GLM_IN, GLM_OUT, GLM_INOUT macros will make C and C++ happy

This would be useful for the ones who prefer the array API over the struct one. Thanks!

recp commented 3 years ago

@legends2k I agree with you. I think cglm could work better with C++. Added to my TODOs.

With GLM_IN, GLM_OUT, GLM_INOUT macros, we could add compiler specific attributes maybe if we neeed any in the future. Let's think about it and try to find better solution.

Also there is an issue with const, see https://github.com/recp/cglm/issues/83 maybe we could ignore const for C for now, I'll try to re-focus this issue later.

Also, any feedbacks, help are always welcome

awsdert commented 3 years ago

Taking a cursory glance at this I'd say the simplest solution would be to have macros like glm_lookat (at least I assume it's a macro, haven't looked at details yet) have solid functions as alternatives so for example: var cglm_func_lookat( float *vec, uint pos, uint flags ) { return cglm_lookat( vec, pos, flags ); }

recp commented 3 years ago

@awsdert thanks for your feedbacks,

Actually there is an interest to convert implemenntations to macro to avoid duplicate raw implementations for double:

https://github.com/recp/cglm/issues/196

so there is no need to prefix functions with cglm_func_. For C++, we could go with GLM_IN, GLM_OUT, GLM_INOUT which mentioned above

PQCraft commented 3 years ago

https://github.com/g-truc/glm

legends2k commented 3 years ago

@PQCraft GLM isn't that good with SIMD or inlining IIRC. Of course, those may not be important to some projects.

FWIW Realtime Math's Introduction article does a comparison of

recp commented 3 years ago

+1 for "Make API C++-friendly"

@legends2k thanks for sharing that, FWIW cglm implemen[ted]/[ing] NEON and other SIMDs or hardware features time by time so the comparison may not reflect latest cglm

TheRektafire commented 2 years ago

Personally I'm totally OK with cglm being made more c++ friendly as long as no performance is lost from having to stoop down to c++s level ;) if course if that becomes and issue I'm sure c and c++ versions of the functions could be offered separately

awsdert commented 2 years ago

I think it might be better to just use inline functions, no macros, and revert to normal functions in C89 with some macros called BUILD_CGLM_ABI and BUILD_CGLM_LIB, the lib would be for .so/.dll libraries while the abi would be for defining the contents of the functions that otherwise would be just declarations. If inlining is available then the abi macro can be ignored providing the speedup that later specifications allow but gracefully falling back to normal functions when inlining is not available, in both cases proper typedefs can be used, C++ is perfectly happy to use both so it's not a problem, at most you would slap some wrapper classes around the inline/normal functions and maybe some overloaded functions for anything not suited for a class