Agreed, I'm currently taking a similar approach, but forgoing pointers as much as possible as well. This leads to structs being passed by value, and const abuse.
Ray h_cast(const Hero hero, const Hit hit, const Sheer sheer, const int yres, const int xres)
{
const Point end = p_sub(hit.where, hero.where);
const Point corrected = p_turn(end, -hero.yaw);
const Line trace = { hero.where, hit.where };
const Projection projection = p_project(yres, xres, hero.fov.a.x, hero.pitch, corrected, hero.height);
const Ray ray = { trace, corrected, p_sheer(projection, sheer), hit.surface, hit.offset, hero.torch };
return ray;
}
It leads to some nice somewhat functional styles. I estimate its 80% pure, given its C99 alone. I've adopted this style in my Age of Empires 2 engine rewrite if anyone is curious: https://github.com/glouw/openempires
As for performance I am heavily relying on LTO. I seem to get a 50% performance boost with pass by values on structs - as I've sedded openempires to replace occurrences of _Type name_ with C++'s _Type& name_ for all functions arguments - and the added pointer aliasing and de-references bogged the engine down in heavily forested areas.
Compilers love singly assigned const values, and seem to suffer under heavy pointer aliasing.
If it's a static method (or in an anonymous namespace in C++), it should get fixed at any optimisation level. However if it's a global method, you'll need to pass -flto to defer optimisations to link time to make it work.
As for performance I am heavily relying on LTO. I seem to get a 50% performance boost with pass by values on structs - as I've sedded openempires to replace occurrences of _Type name_ with C++'s _Type& name_ for all functions arguments - and the added pointer aliasing and de-references bogged the engine down in heavily forested areas.
Compilers love singly assigned const values, and seem to suffer under heavy pointer aliasing.