Giter VIP home page Giter VIP logo

handmademath's Introduction

Handmade Math

A single-file, cross-platform, public domain graphics math library for both C and C++. Supports vectors, matrices, quaternions, and all the utilities you'd expect.

To get started, go download the latest release.

If you are upgrading to Handmade Math 2.0, save yourself some time and use our automatic update tool.

Here's what sets Handmade Math apart:

  • A simple single-header library. Just #include "HandmadeMath.h".
  • Supports both C and C++. While libraries like GLM only support C++, Handmade Math supports both C and C++, with convenient overloads wherever possible. For example, C++ codebases get operator overloading, and C11 codebases get _Generic versions of common operations.
  • Supports all graphics APIs. Handmade Math has left- and right-handed versions of each operation, as well as support for zero-to-one and negative-one-to-one NDC conventions.
  • Swizzling, sort of. Handmade Math's vector types use unions to provide several ways of accessing the same underlying data. For example, the components of an HMM_Vec3 can be accessed as XYZ, RGB, or UVW - or subsets can be accessed like .XY and .YZ.
  • Your choice of angle unit. While Handmade Math uses radians by default, you can configure it to use degrees or turns instead.

Usage

Simply #include "HandmadeMath.h". All functions are static inline, so there is no need for an "implementation" file as with some other single-header libraries.

A few config options are available. See the header comment in the source for details.

FAQ

What conventions does HMM use, e.g. row vs. column major, handedness, etc.?

Handmade Math's matrices are column-major, i.e. data is stored by columns, then rows. It also assumes column vectors, i.e. vectors are written vertically and matrix-vector multiplication is M * V instead of V * M. For more information, see this issue.

For other properties, we provide variants for each common convention. Functions that care about handedness have left-handed (LH) and right-handed (RH) variants. Projection functions have zero-to-one (ZO) and negative-one-to-one (NO) variants for different NDC conventions.

What if I don't want the HMM_ prefix?

Do a find and replace in the library source.

What's the license?

This library is in the public domain. You can do whatever you want with it.

Where can I contact you to ask questions?

Feel free to make GitHub issues for any questions, concerns, or problems you encounter.

handmademath's People

Contributors

b-y-p avatar bvisness avatar danielgibson avatar dev-dwarf avatar gsxcasper avatar ijzerbaard avatar jack-punter avatar jorgenpt avatar kevinmoran avatar kiljacken avatar occivink avatar strangezak avatar timgates42 avatar valmar33 avatar yaram avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

handmademath's Issues

New prefix features need robust testing

The work done in #114 needs a better way to be tested. It's easy to forget to prefix a name, either in the definition or in internal usage.

We are really getting to the point where we might need to start auto-generating some things.

Functions in the HANDMADE_MATH_IMPLEMENTATION section are missing the HMM_PREFIX(...) macro

As mentioned in the title, all the functions defined within HANDMADE_MATH_IMPLEMENTATION do hardcode the HMM_ prefix (for example HMM_Rotate instead of HMM_PREFIX(Rotate)).
This causes linking to fail to those who define HMM_PREFIX and use those functions.

(btw I tried to open a pr with the fix but I don't have permission to push. I'm not sure if I need to be whitelisted to this repo in order to push?)

Bug in HMM_Perspecive

Values in projection matrix are in the wrong places, apart from that if we decided to use tangens instead of cotangents in the [0][0] position aspect ratio also have to be inverted so:

float TanThetaOver2 = HMM_TanF(FOV * (HMM_PI32 / 360.0f));

Result.Elements[0][0] = 1.0f / AspectRatio / TanThetaOver2;
Result.Elements[1][1] = 1.0f / TanThetaOver2;

Or just compute cotangent up front:

float CoTanThetaOver2 = 1.0f / HMM_TanF(FOV * (HMM_PI32 / 360.0f));

Result.Elements[0][0] = CoTanThetaOver2 / AspectRatio;
Result.Elements[1][1] = CoTanThetaOver2;

Make coordinate system more clear in function naming (LH, RH, NO, ZO)

When porting old games from D3D -> OpenGL, it's very useful to understand what type of coordinate system you're using. I think pushing this information into the function names could be useful.

GLM supports all these variations. However, even if you decided to support "the one true way" (whatever way that is hehe), then at least being clear about what that one way (is in the function name) might be good.

Note, this is not a feature request to support all these alternate coordinate systems, if you don't already (browsing the source, I think not?). If that were interesting, I think it should probably be a separate ticket.

Quaternion from Mat4?

Is there a way to use a LookAt function and end up with a quaternion? I know HMM_LookAt gives you a mat4, but I don't see a way to convert a mat4 to a quaternion.

Ultimately, I'm trying to find a way to construct a quaternion and specify it's Up vector. LookAt seems to be the only available function that does that.

Inconsistent use of radians vs. degrees

The trigonometric functions in Handmade Math use radians for angles. HMM_Perspective, on the other hand, uses degrees.

We should make this usage consistent between the two, or find a way to clarify which uses radians and which uses degrees.

HMM_Inner and HMM_Dot are redundant and limited

HMM_Inner and HMM_Dot both perform exactly the same type of vector multiplication, and are thus redundant. However, only HMM_Inner is used internally.

In addition, both of these functions only support hmm_vec3. We should consider adding versions of this function for all three types of vectors.

Orthographics Matrix

This might just be me being stupid or me not doing something correct with OpenGL, but i think our Orthographics Matrix might be screwed can anyone with a working application throw a Orthographic matrix on their camera and see if anything is screwed up.

Remove the implementation section, shove it all in the header

I know we've gone back and forth on this before (#57) but I don't think we need to have a separate implementation section in Handmade Math.

Most of the function implementations are inline, since that gives the compiler the most context for optimizations (and math needs to be optimized!). The ones that are not inline were made that way because we were worried about redundant definitions between translation units, but with link-time optimization, compilers are mostly able to prevent that from happening.

So basically we are forcing the user to set up the HANDMADE_MATH_IMPLEMENTATION part for about three functions, and for little to no benefit.

I propose that we make everything in Handmade Math inline for 2.0, and rip out HANDMADE_MATH_IMPLEMENTATION completely.

HMM_LookAt Using/Returning Partially Uninitialized Matrix

Hi there. I was struggling to debug an issue and traced it back to HMM_LookAt...

The issue has been marked below with comments.

hmm_mat4 Result; // uninitialized    

hmm_vec3 F = HMM_NormalizeVec3(HMM_SubtractVec3(Center, Eye));
hmm_vec3 S = HMM_NormalizeVec3(HMM_Cross(F, Up));
hmm_vec3 U = HMM_Cross(S, F);

Result.Elements[0][0] = S.X;
Result.Elements[0][1] = U.X;
Result.Elements[0][2] = -F.X;
// not setting the element at [0][3]

Result.Elements[1][0] = S.Y;
Result.Elements[1][1] = U.Y;
Result.Elements[1][2] = -F.Y;
// (or at [1][3])

Result.Elements[2][0] = S.Z;
Result.Elements[2][1] = U.Z;
Result.Elements[2][2] = -F.Z;
// (or [2][3])

Result.Elements[3][0] = -HMM_DotVec3(S, Eye);
Result.Elements[3][1] = -HMM_DotVec3(U, Eye);
Result.Elements[3][2] = HMM_DotVec3(F, Eye);
Result.Elements[3][3] = 1.0f;

// result returned without initializing the totality of the bottom row
return (Result);

It was fixed by initializing Result to HMM_Mat4d(1.f), but am unsure how you'd like to solve this particularly (it's probably better to just directly write to those elements that weren't initialized).

NEON Support

Just wanted to get some opinions on if its worth it or not to optimize Handmade Math for NEON (Arm CPU SIMD instructions). Its something i've been thinking about doing recently although i am not comfortable with the instructions so it would require quiet a bit of work.

I am willing to do it though, im just looking to see if there's interest / anyone using handmade math on a ARM based CPU.

Smooth Transition for GLM to Handmade Math

@kiljacken @bvisness Someone is having a issue with handmade-math there's no reason they should have to transpose there matrices when submitting them to OpenGL right? It seem like the transition from GLM to Handmade Math is not as easy as i thought it was.

Here's the Twitter thread to that kinda explains whats going on, on his side, this shows the complete conversation: https://twitter.com/JesseRMeyer/status/768281652682366976

Anyone have any idea whats going on?

Vec2i, Vec3i, Vec4i are unnecessary?

What is the purpose of having HMM_Vec2i, HMM_Vec3i, and HMM_Vec4i? All three functions simply cast their integer arguments to floats. And there is no loss of precision when converting int to float, so compilers should be able to do this conversion implicitly in the float versions of these functions.

(This may just be my relative inexperience programming in plain old C.)

HMM_LengthSquareRoot is poorly named

This is not a bug, exactly, but when I was integrating Handmade Math into my project I was confused by the naming of HMM_LengthSquareRoot. I expected HMM_LengthSquared, or something, since the function actually produces the length of the vector squared. (No square root has happened yet!)

HMM_Quaternion(...), HMM_Length(hmm_vecx) not defined as inline?

Is there a reason why these functions are not defined with inline? My first assumption is that this is simply a typo since the defintions have HMMDEF. If the header is included in multiple translation units, these functions not being declared inline can cause multiply defined symbols, which I just ran into.

Remove CRT

Remove use of the CRT (Math.h) in HandmadeMath, this involved replacing Sin, Con, and Tan with our own version of these operations.

The Road to 1.0

This isn't a issue at all, but i was just thinking, what do we need / what are we missing (besides testing) to be able to bring this thing into 1.0. I figured it was just good to open up a conversation over this,

I would love everybody s opinion on this :)

Vector normalization could easily be faster

When digging into #80, I decided to see how GLM implemented vector normalization. Turns out their approach is pretty clever:

v * inversesqrt(dot(v, v));

This avoids both an actual square root and a division by exploiting the fact that inverse square roots are cheap and that dot(v, v) gives you the magnitude of the vector squared.

I ran some quickbench benchmarks with the following results:

No optimization

mvvejpkmjxu3mpknfoa1whqmzs4

-O1

0zwafdosmgwfq43wf8hckdzw6tw

-O3

myohu5vuuoqvmrfxfiz8zl9xygo

This is a pretty nice speedup for unoptimized builds (about 25%) and it could really help performance on processor architectures that hate square roots and divisions. (See concerns in #80.) So, we should probably do this.

HMM_SquareRoot and HMM_FastInverseSquareRoot not defined

These two function headers have no function definitions and cause linker errors if used in a project:

HMMDEF float HMM_SquareRoot(float Float);
HMMDEF float HMM_FastInverseSquareRoot(float Number);

HMM_SquareRoot in particular seems redundant since HMM_SqrtF is already present above. HMM_FastInverseSquareRoot is completely missing.

Handmade Math Speed

One of the things ive been thinking about recently is how handmade-math's speed fairs up against the other major math libraries.

Is there some sort of tool we can use to speed test all of our function just to get an idea where our bottlenecks are.

Orthographic matrix clip plane math wrong?

I haven't run tests to see what results I get, but while reading through the implementation of HMM_Orthographic, I noticed that all of the clip plane calculations are doing (Near - Far), rather than (Far - Near). Same for the additions.

I double checked the orthographic projection matrix online, and also cross-checked a couple other math libraries I've used in the past, and they all say (Far - Near). I'm guessing this is a typo?

Mat4 SSE definition looks row-major

Our definition of hmm_mat4 has an SSE variable called Rows. This should really be Columns, since our matrices are column-major. Apparently we're doing all the math correctly, but we should probably rename the variable to avoid confusion.

@StrangeZak is this ok to do, or am I misunderstanding something about our SSE implementation?

Potential efficiency problem in HMM_Normalize

Here is the full function body for HMM_Normalize(hmm_vec3):

HINLINE hmm_vec3
HMM_Normalize(hmm_vec3 A)
{
    hmm_vec3 Result = {0};

    Result.X = A.X * (1.0f / HMM_Length(A));
    Result.Y = A.Y * (1.0f / HMM_Length(A));
    Result.Z = A.Z * (1.0f / HMM_Length(A));

    return (Result);
}

HMM_Length(A) is called three times during this process, even though the value is the same in all three cases.

I am no expert on what low-level shenanigans are in play when this code is compiled, but I suspect that compilers would not be able to optimize this. We should save the result and then use it in all three divisions.

SSE all Quaternion ops

Quaternions are the only part of Handmade Math that are not SSEd yet. Lets just finish this

Alternative implementations for vec4 normalization

Normalization could be implemented with rsqrt and a Newton step to get it up to a decent (though not full) accuracy. I have some benchmarks here: http://quick-bench.com/rhPor3bWaoa906sYDP1OA674GXY

However, this is not a clear cut win. For example, the Newton step requires two constants. Calling that function in isolation may not be fast, since those constants may not be in cache. The low-accuracy version does not have that problem, but it has a significantly lower accuracy. The version with Newton step is not 100% accurate but should be acceptable for regular use.

Furthermore, the actual improvement depends quite strongly on the microarchitecture it is being run on. For example, on Nehalem the division and square root take approximately forever and are not pipelined to any significant degree, so sqrt+div is horrible. On the other hand both rqsrt and mulps used to have a lower latency. Starting with Broadwell, sqrt+div is not quite so bad any more. For example on Skylake, a single precision square root (vector or scalar) takes 12 cycles but can be performed once every 3 cycles, on an old Core2 65nm it could take anywhere between 6 and 29 cycles depending on how "nice" the input was (powers of 2 are nice, typical input is not nice) and the next square root could start one cycle before the last square root is done. Scalar square root is usually no better than vector square root, except on Broadwell and some AMD processors - so for a few specific processor it would be better to compute a scalar and shuffle it into all lanes, but for everything else it's better to just redundantly compute 4 equal square roots just to save the shuffle.

In short, on a new Intel processor, rsqrt and a Newton step (which costs 4 multiplications and a subtraction) still has a better throughput than sqrt+div, but the difference is nowhere near as big as it used to be. The latency has become about the same. So it can still help to do rsqrt and a Newton step but it's mainly good for Haswell and older, otherwise it's only a small improvement.

I'm not sure why normalizing the zero vector to zero is necessary, but I've kept that in. Obviously this costs time, but not that much.

Something that would help a lot more is an SoA version of normalize, that normalizes 4 vectors simultaneously and the 4 vectors are stored per-coordinate instead of per-vector. This would allow using a square root and division (or rsqrt and Newton step) to its full potential, with 4 different vector lengths in the 4 lanes. That would allow normalizing 4 vectors at about the same cost that 1 vector costs now (with 3 extra multiplications of course, OTOH no shuffles). But there is no SoA stuff in HMM at all so it seems somewhat out of place.

Here's a benchmark that includes an SoA version as well: http://quick-bench.com/goExus65xkv04_I7OXf9QtMk_uM

SSE Support

Add SSE support for all Vector, and Matrix Operations

Visual Studio can't compile aligned function parameters

When compiling using Visual Studio 2017 I get the following errors:

c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(707): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(707): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(744): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(744): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(802): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(802): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(818): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(877): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(877): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(893): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(924): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(924): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(945): error C2719: 'VecOne': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(945): error C2719: 'VecTwo': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(996): error C2719: 'A': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1017): error C2719: 'A': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1057): error C2719: 'A': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1088): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1125): error C2719: 'Matrix': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1138): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1138): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1154): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1154): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1168): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1168): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1172): error C2719: 'Matrix': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1187): error C2719: 'Matrix': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1187): error C2719: 'Vector': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1191): error C2719: 'Matrix': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1287): error C2719: 'Vector': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1416): error C2719: 'A': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1437): error C2719: 'A': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1458): error C2719: 'A': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1486): error C2719: 'VecOne': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1486): error C2719: 'VecTwo': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1514): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1514): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1521): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1521): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1549): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1549): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1556): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1556): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1598): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1598): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1605): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1612): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1612): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1619): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1626): error C2719: 'Matrix': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1626): error C2719: 'Vector': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1675): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1675): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1682): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1689): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1717): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1717): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1738): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1738): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1745): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1745): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1773): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1773): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1780): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1780): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1808): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1808): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1815): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1815): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1843): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1850): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1878): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1885): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1899): error C2719: 'Matrix': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1899): error C2719: 'Vector': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1920): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1920): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1941): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1948): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1972): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1977): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(1997): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2002): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2022): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2062): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2102): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2102): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2117): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2117): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2208): error C2719: 'Left': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2208): error C2719: 'Right': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2263): error C2719: 'Matrix': formal parameter with requested alignment of 16 won't be aligned
c:\users\pmckenna\documents\experiments\src\Handmade-Math/HandmadeMath.h(2263): error C2719: 'Vector': formal parameter with requested alignment of 16 won't be aligned

These function parameters could be const references instead of copies as this SO post suggests, no?
https://stackoverflow.com/questions/28488986/formal-parameter-with-declspecalign16-wont-be-aligned

Making unit tests embeddable

Hello all,

I am using handmade math in a project, using a unity build. I'd like to keep this structure.

My project also has a mechanism for running unit tests. I'd like to fold the HMM unit tests in so they run seamlessly in my build.

This could be accomplished by splitting test/hmm_test.c into a test/hmm_test_runner.c and test/hmm_tests.h.

test_runner.c would contain the infrastructure necessary to run tests in a separate executable, and hmm_tests.h would contain the test "definitions". I would then use the test/hmm_tests.h file in my project, and provide my own macro set to map to my unit test structure.

I might also prefix the unit test related macros with HMMT to make it clear what's going on.

Before I jump in and implement this -- any objections? Alternate ideas?

What is LinearCombineSSE and do we need it?

I have no idea what it does, and it looks to me like it's mainly used as an implementation helper for multiplication. I'm wondering if it needs to be an actually "public" part of Handmade Math.

SSE for everything!

your library's speed could easily be improved signficantly but having vec2 and vec3 be padded to be 16 bytes long, you then can use SSE for all of those calculations. Also consider directly passing __m128 instead of passing a union, that should also give you a performance boost, I'd love to go through and edit the library myself but I'm working on my own right now, jut thought I'd leave this suggestion here to share what I found.

Do we need the overloaded C++ functions?

I'm not sure we gain anything by having the overloaded versions of things like HMM_Multiply or HMM_Add. They are not really less verbose than the full names, we provide operator overloads for all the important ones, and they are a lot of work to maintain.

Obviously we can keep them if they are useful to people, but I figured I'd ask the question. I personally have stopped using overloaded functions completely in my own code and haven't minded. (Thanks, Go.)

Functions without prototypes and prototypes without functions

There are many function prototypes in the HANDMADE_MATH_CPP_MODE headers that do not have function bodies. (These start on line 379 at the time of this issue.) Further, most of these function prototypes don't make any sense:

HMMDEF hmm_vec4 HMM_Add(int X, int Y, int Z, int W);

What is that even supposed to do?

There are also lots of functions in the HANDMADE_MATH_CPP_MODE implementations that do not have associated prototypes, so they are uncallable except by the file that defines HANDMADE_MATH_IMPLEMENTATION:

HINLINE hmm_vec2
Add(hmm_vec2 Left, hmm_vec2 Right)
{
    hmm_vec2 Result = HMM_AddVec2(Left, Right);

    return (Result);
}

I suspect that these two problems are related, since I see that version 2.0 was supposed to prefix all functions, but presumably missed these.


I suspect that the desired behavior was as follows:

  • Provide C-compatible headers like HMM_AddVec4 for each function (since C does not support function overloading)
  • For C++ mode, provide overloaded functions like HMM_Add so that code can be more concise.
  • For C++ mode, provide operator overloading so that code can be mathy!

If those assumptions are correct, I'd be happy to get going on a fix for this.

HANDMADE_MATH_CPP_MODE instructions?

The instructions for HANDMADE_MATH_CPP_MODE are as follows:

  For overloaded and operator overloaded versions of the base C functions,
  you MUST
  
     #define HANDMADE_MATH_CPP_MODE
     
  in EXACTLY one C or C++ file that includes this header, BEFORE the
  include, like this:
  
     #define HANDMADE_MATH_IMPLEMENTATION
     #define HANDMADE_MATH_CPP_MODE
     #include "HandmadeMath.h"
     
  All other files should just #include "HandmadeMath.h" without the #define.

By defining HANDMADE_MATH_CPP_MODE, HandmadeMath.h enables the following:

  1. Declarations of overloaded functions
  2. Declarations of operator overloads
  3. Definitions of overloaded functions
  4. Definitions of operator overloads

The documentation says other files should just include HandmadeMath.h without the #define, but if that's the case, those other files won't see the declarations of the functions. Either this doesn't work or there's something I don't understand.

SSE improvements

Don't do this:

__m128 In = _mm_load_ss(&Value);
__m128 Out = _mm_sqrt_ss(In);
_mm_store_ss(&Result, Out);

Do this instead:

__m128 In = _mm_set_ss(Value);
__m128 Out = _mm_sqrt_ss(In);
Result = _mm_cvtss_f32(Out);

load/store operations makes compiler to store float to memory (if it is not smart enough to optimize what is going on here), and that is bad. Because on x86_64 architecture floats arguments and result uses SSE register, so you are forcing Value to be first stored to memory for _mm_load_ss immediately afterwards to load it from memory. Similarly with Result - it is forced to be stored to memory with _mm_store_ss just load it afterwards for returning it.

set/cvtss operations generate single MOV instruction each (if needed at all). For x86_64 they won't generate any code at all because input argument already is in SSE register and result also need to be in SSE register.

And a bit unrelated comment to SEE - HMM_Power can be greatly improved by doing squaring algorithm: https://en.wikipedia.org/wiki/Exponentiation_by_squaring

Introduce "safe" float comparison

Introduce a safe form of comparing floating point. == and != should not be used when comparing floating numbers.

./HandmadeMath.h:854:31: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y); ~~~~~~ ^ ~~~~~~~ ./HandmadeMath.h:854:52: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y); ~~~~~~ ^ ~~~~~~~ ./HandmadeMath.h:861:31: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z); ~~~~~~ ^ ~~~~~~~ ./HandmadeMath.h:861:52: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z); ~~~~~~ ^ ~~~~~~~ ./HandmadeMath.h:861:73: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z); ~~~~~~ ^ ~~~~~~~ ./HandmadeMath.h:868:31: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W); ~~~~~~ ^ ~~~~~~~ ./HandmadeMath.h:868:52: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W); ~~~~~~ ^ ~~~~~~~ ./HandmadeMath.h:868:73: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W); ~~~~~~ ^ ~~~~~~~ ./HandmadeMath.h:868:94: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W);

Test independence from CRT

A certain type called hmm_bool is of type int32_t and imports stdint.h to make it work. Oops.

We should fix this, and find a way to test that adding all math functions actually does allow you to compile it without the CRT or any standard libraries.

HMM_Power does not support fractional exponents

The function signature for HMM_Power is currently HMM_Power(float Base, int Exponent). Because Exponent is an int, it is not possible to use fractional exponents at all.

This would add to the complexity of the function, so it would perhaps be wise to add an HMM_PowerF or something to preserve performance for the (probably more common) integer exponent case.

mat3

Hi, do we have to extend the library if we want a 3x3 matrix and 2x2 matrix?

No way to run tests on Windows

Wondering if there's any interest in making project files (or some other build solution?) for running the test suite in MSVC.

I am happy to put them together if they'd be useful. I have VS 2015 and got those projects working there. Not sure if VS 2017 requires a separate solution version, but I could also make that project if it does.

I cannot get VS 2012 working without modifying the tests. C99 designated initializers weren't supported until VS 2013, it seems, and the tests use those. I could convert the tests to not use that feature (if the lib itself doesn't use it). I wanted to gauge interest in all this before starting that.

HMM_RSquareRootF has different precision between SSE and non-SSE

As of this writing, here is what HMM_RSquareRootF looks like:

HMM_INLINE float HMM_RSquareRootF(float Float)
{
    float Result;

#ifdef HANDMADE_MATH__USE_SSE
    __m128 In = _mm_set_ss(Float);
    __m128 Out = _mm_rsqrt_ss(In);
    Result = _mm_cvtss_f32(Out);
#else
    Result = 1.0f/HMM_SquareRootF(Float);
#endif

    return(Result);
}

This means that SSE builds will use an approximation, but non-SSE builds will not.

What do we want to do to fix this? Making the SSE version more precise or making the non-SSE version faster would both be breaking changes. But, I suspect that someone who's deliberately using an inverse square root would expect it to use an approximation.

Better benchmarks

We should come up with a proper benchmarking solution for Handmade Math. Since we care a lot about performance, it would be worth having automatic benchmarks that run on every build.

It would be nice if our benchmarking tools could display historical data to us in some way so that we can easily judge the speedup of a particular change.

This issue inspired by @IJzerbaard's very helpful quick-bench benchmarks.

Doesn't build in C (non-C++) mode

It currently doesn't build in C mode, because NLerp uses HMM_Normalize() instead of HMM_NormalizeQuaternion().

I also doubt that a compiler enforcing real C99 mode would be very happy about your usage of inline in the implementation.
Having function declarations like extern float HMM_CosF(float Angle); and then the implementation as inline float HMM_CosF(float Angle) looks very wrong.
And C99 and newer has that weird thing where functions declared inline in the header must be implemented twice: inline in the header and not-inline in the implementation - which is pretty much the opposite of what you're doing there (to get classic/C++ inline behavior one would just supply a static inline implementation in the header).

Add support for matrix inverses

From some discussion on the Handmade Network Discord, the issue of matrix inverses has come up. I think it would be good to beef up Handmade Math's handling of matrices in general (being that we only support mat4), but even just doing inverses of mat4's would be useful.

We would want to expose the determinant calculation as well. Also, not all matrices are invertible, but we could follow the example of the glsl spec and just say that the inverse is undefined for singular matrices.

Rotate vector by quaternion?

I don't know if I'm not seeing it or if it isn't available. Right now I can accomplish it by converting the quaternion to a mat4 and multiplying the vector by that. But I'd like to skip the mat4 step if possible, since it defeats the purpose of the quaternion.

Clarify ambiguous term "Column-major"

Re issue #89: I'm confused. Isn't this true? Or is there something I'm not understanding about row vs. column major?
For example:

#include <stdio.h>
#include "HandmadeMath.h"

typedef hmm_mat4 mat4;
mat4 mat4Identity()
{
	return HMM_Mat4d(1.f);
}

void mat4Print(mat4 mat)
{
	int row = 0;
	while (row < 4)
	{
		printf("%d [%f %f %f %f]\n", row, mat[row][0], mat[row][1], mat[row][2], mat[row][3]);
		++row;
	}
}

int main()
{
	mat4 matA = mat4Identity();
	mat4Print(HMM_MultiplyMat4(matA, HMM_Translate({1.f, 2.f, 3.f})));
	mat4Print(HMM_Rotate(45.f, gUpAxis));
	return 0;
}

outputs:

0 [1.000000 0.000000 0.000000 0.000000]
1 [0.000000 1.000000 0.000000 0.000000]
2 [0.000000 0.000000 1.000000 0.000000]
3 [1.000000 2.000000 3.000000 1.000000]

0 [0.707107 0.000000 -0.707107 0.000000]
1 [0.000000 1.000000 0.000000 0.000000]
2 [0.707107 0.000000 0.707107 0.000000]
3 [0.000000 0.000000 0.000000 1.000000]

Which is what I expect: the translation (1.f, 2.f, 3.f) is properly stored in the 4th row of the matrix, where columns 1, 2, and 3 are contiguous in memory.

I did some more reading, and found this thorough discussion: Column Vectors vs. Row Vectors. I don't fully understand what they were getting at, but I think the terminology really should be clarified in Handmade Math.

Whether it's row-major or column-major depends on how you write it. My mat4Print prints it row-major, as if you were printing a pixel array (and not destroying your cache).

To clarify, the matrices are stored in row-major order, but you can choose to think of them in column-major order, right? I'm used to matrices being both stored and thought-of in row-major order, as if rendering the matrix out as a image stored from the top left corner, row by row.

However, it is row vector, which is what I expected, and what confused me when seeing "column-major". I think the terminology should be updated to say row-vector instead of column-major, because the latter is an ambiguous term.

Needs unit testing

Just wanted to open up the discussion about how unit testing should be implemented for Handmade Math. We could use a full C++ unit testing framework like Google Test, or maybe just roll our own thing with asserts.

I personally would lean toward a full framework for ease of running multiple tests and nice test output. Plus, it would likely be easier to get up and running with Travis CI or some other automated tool, if we decide to go that route.

No matrix transpose function

We do not have a function for transposing hmm_mat4s. Adding one seems like the responsible thing to do! Probably call it HMM_Transpose(hmm_mat4 Matrix).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.