Compare commits

..

48 Commits

Author SHA1 Message Date
Ben Visness
50ab386db5 Sort of get FPS controls working
not really though, holy cow
2018-08-14 13:16:04 -05:00
Ben Visness
f5c8f23d62 Update build.bat to better contain files 2018-07-10 21:31:13 -05:00
Ben Visness
d67607d3d1 Get stuff kind of working on Windows 2018-07-10 21:26:16 -05:00
Ben Visness
fabad91c39 Get an FPS cam kind of working! (no mouse input yet) 2018-07-01 15:08:46 +02:00
Ben Visness
8332a2d907 leave a more...aggressive comment for future me 2018-07-01 15:08:46 +02:00
Ben Visness
449091185e Clean up rotation mess (and leave a comment about why it's wobbly) 2018-07-01 15:08:46 +02:00
Ben Visness
33f24a8289 Commit all this horrible rotation stuff for posterity before I delete it 2018-07-01 15:08:46 +02:00
Ben Visness
d24e33c03a Fix whitespace issues 2018-07-01 15:08:46 +02:00
Ben Visness
0a79c70dff Add more tests that actually break stuff for some reason 2018-07-01 15:08:46 +02:00
Ben Visness
eedda7ca4c First attempt at Mat4 to Quaternion (might have rows and columns swapped?) 2018-07-01 15:08:46 +02:00
Ben Visness
850efa3606 Bump file version 2018-07-01 15:08:46 +02:00
Ben Visness
9097224f37 Add array subscript operators for all types (#88)
* Add array subscript operators for all types

* Taking the parameter for the operator[] as a reference. This should allow it to be inlined

* I guess you can't do that.

* Update version and readme
2018-07-01 15:08:46 +02:00
Ben Visness
b13e3a317c WIP: Properly initialize all elements of LookAt matrix (#84)
* Properly initialize all elements of LookAt matrix

* Update version and readme

* Add a test for LookAt

good enough
2018-07-01 15:08:46 +02:00
Ben Visness
88d583e6ac WIP camera stuff. Missing some useful quaternion helpers. 2018-06-11 15:40:31 -05:00
Ben Visness
3a382212f9 Add .obj loading and rendering 2018-05-28 17:44:35 -05:00
Ben Visness
ba02e1a9c4 Rework RenderComponent to be more flexible 2018-05-28 13:21:43 -05:00
Ben Visness
ba5982b2a9 Add delta time stuff 2018-05-28 12:31:17 -05:00
Ben Visness
373e9517b4 Add a bit of a component tree 2018-05-27 21:36:00 -05:00
Ben Visness
2d71b1b11b Add an example cube (tutorials!) 2018-05-27 16:22:54 -05:00
Ben Visness
fdea881102 Start of example program 2018-05-27 15:08:07 -05:00
Ben Visness
f8b3a84cec WIP: Make tests quite a lot nicer (#81)
Make tests quite a lot nicer
2018-02-18 14:19:31 -06:00
IJzerbaard
77914405c3 Use SSE in HMM_MultiplyMat4ByVec4 (#77)
Implements HMM_MultiplyMat4ByVec4 with HMM_LinearCombineSSE if SSE is
enabled.
2018-02-11 13:24:39 -06:00
IJzerbaard
eb5c659148 Improve HMM_MultiplyMat4 (#76)
Remove all transposes, (AT BT)T = BA
2018-02-10 17:59:07 -06:00
Ben Visness
52fd5cceb4 Update README.md 2017-10-31 19:28:59 -05:00
Ben Visness
8e67482295 Update README.md 2017-10-31 11:07:07 -05:00
Ben Visness
c508ce342b Create LICENSE 2017-10-31 11:04:56 -05:00
Ben Visness
250c38e845 Update README.md 2017-10-31 11:01:31 -05:00
Ben Visness
4981d5ab89 Convert everything to new inline scheme (#57) (#72)
* Convert everything to new inline scheme

* Add both extern and inline for some SSE vs. non-SSE functions

Some functions had nice, compact SSE implementations but bulky non-SSE
implementations, so this commit inlines just the implementations that make
sense. Also updated documentation.

* Convert HINLINE and HEXTERN to HMM_INLINE and HMM_EXTERN
2017-10-31 10:16:36 -05:00
Ben Visness
5f173e0176 Update CONTRIBUTING.md 2017-10-31 10:09:27 -05:00
Ben Visness
575fcb767d Update README.md 2017-10-31 10:06:22 -05:00
strangezak
a08262b2d9 Removed old instructions 2017-10-14 19:34:51 -07:00
strangezak
53bc939d8e Updated email 2017-10-04 09:40:31 -07:00
Ben Visness
7eb4ae1846 Update README for 1.4.0 2017-10-02 11:17:11 -05:00
StrangeZak
48bd24b05e Updated docs 2017-10-01 10:32:53 -07:00
Zak Strange
064baeb5b9 V1.4 - SSE upgrades and bug fixes (#70)
* Fixed bug when using handmademath in C mode

* SSEd vec4 operations

* Fixed hmm_vec4 for non-sse builds. Added SSE option for HMM_Vec4 to load in one instruction

* Whoops. We were loading in the wrong order

* SSEd more things

* SSEd more functions

* Minor fixups

* SSE'd hmm_vec4 initialization

* Removed zeroing

* Vector normalization should be zero'd

* Removed old comments
2017-09-30 14:38:28 -07:00
Ben Visness
afd726ab0b Automatically include C++ definitions (#67) 2017-08-02 10:12:06 -05:00
strangezak
98fffbd7cc Forgot to update version 2017-07-16 21:29:26 -07:00
Ben Visness
efd9f2f4b7 Matrix Multiply SSE (#65)
* SSEd HMM_MultiplyMat4 and HMM_Transpose. And added HMM_LinearCombineSSE

* Maybe Travis doesn't support SSE?

* Fix compile process so the SSE option is consistently defined

* Fix link error

* Documentation

* Added function prototype for operator ==

* Added != operator for hmm_vec2, hmm_vec3, hmm_vec4

* Add C versions of equality checks

Also made the C++ tests actually run...😳

* Update documentation
2017-07-16 21:19:34 -07:00
Ben Visness
c8ada18370 Update README for 1.1.5 2017-06-21 09:31:20 -05:00
Zak Strange
70ac2b7e5b 1.1.5 (#64)
* Added Width, and Height to hmm_vec2, and fixed SqrtF when compiling without the CRT

* Syntax error

* Test all the vector access methods
2017-06-14 20:49:44 -07:00
Ben Visness
924ee43923 Update history to include @DanielGibson's SSE fixes 2017-06-13 11:39:42 -05:00
Ben Visness
440b885d59 Update version to 1.1.4 2017-06-13 11:26:46 -05:00
Emil Lauridsen
98f535aeec Handle zero-vector normalization. (#63)
* Handle zero-vector normalization.

When normalizing a vectors, we have to check whether vector length is
not zero, to avoid dividing by zero when normalizing zero-vectors.

* Test for normalization of zero vectors
2017-06-13 11:21:55 -05:00
Ben Visness
09524f72ed Merge branch 'sse-testing'
# Conflicts:
#	HandmadeMath.h
2017-06-11 18:54:06 -05:00
Emil Lauridsen
be30046a5a C89 style comments (#62) 2017-06-11 10:32:46 -07:00
Daniel Gibson
ff4513ff33 Make it usable on non-SSE platforms (#60)
* at one place HANDMADE_NO_SSE instead of HANDMADE_MATH_NO_SSE was used
* introduce HANDMADE_MATH__USE_SSE for the SSE #ifdefs throughout code
  - use #ifdef HANDMADE_MATH_NO_SSE at only one place
* only use SSE (#define HANDMADE_MATH__USE_SSE) if the targetplatform
  actually supports it
  => users don't have to #define HANDMADE_MATH_NO_SSE on ARM etc
* at one place HMM_SqrtF instead of HMM_SquareRootF was used
2017-06-09 17:14:24 -07:00
Ben Visness
364569abe9 Fix wrong name for square root function 2017-06-09 10:43:11 -05:00
Ben Visness
a9972e71da Test both with and without SSE 2017-06-09 10:37:38 -05:00
63 changed files with 50364 additions and 4010 deletions

6
.gitignore vendored
View File

@@ -5,7 +5,6 @@
*.slo *.slo
*.lo *.lo
*.o *.o
*.obj
*.vs *.vs
# Precompiled Headers # Precompiled Headers
@@ -31,5 +30,6 @@
*.exe *.exe
*.out *.out
*.app *.app
hmm_test
hmm_test* test/build
example/build

3
.gitmodules vendored
View File

@@ -0,0 +1,3 @@
[submodule "example/external/glfw"]
path = example/external/glfw
url = git@github.com:glfw/glfw.git

View File

@@ -6,5 +6,7 @@ install:
- cd test - cd test
- make - make
script: script:
- ./hmm_test_c - build/hmm_test_c
- ./hmm_test_cpp - build/hmm_test_c_no_sse
- build/hmm_test_cpp
- build/hmm_test_cpp_no_sse

View File

@@ -1,3 +1,9 @@
# Understanding the structure of Handmade Math
Most of the functions in Handmade Math are very short, and are the kind of functions you want to have inlined. Because of this, most functions in Handmade Math are defined with `HINLINE`, which is defined as `static inline`.
The exceptions are functions like `HMM_Rotate`, which are long enough that it doesn't make sense to inline them. These functions are defined with an `HEXTERN` prototype, and implemented in the `#ifdef HANDMADE_MATH_IMPLEMENTATION` block.
# Quick style guide # Quick style guide
* Put braces on a new line * Put braces on a new line
@@ -13,23 +19,6 @@
1.f 1.f
.0f .0f
``` ```
* Put macros and return types on a separate line from the function definition:
```cpp
HINLINE float
HMM_MyFunction()
{
// ...
}
```
* Explicitly initialize variables to zero:
```cpp
HINLINE float
HMM_MyFunction()
{
float MyFloat = 0.0f;
hmm_vec3 MyVector = {0};
}
```
* Put parentheses around the returned value: * Put parentheses around the returned value:
```cpp ```cpp
HINLINE float HINLINE float
@@ -40,7 +29,7 @@
``` ```
# Other notes ## Other style notes
* If a new function is defined with different names for different datatypes, also add C++ overloaded versions of the functions. For example, if you have `HMM_LengthVec2(hmm_vec2)` and `HMM_LengthVec3(hmm_vec3)`, also provide `HMM_Length(hmm_vec2)` and `HMM_Length(hmm_vec3)`. * If a new function is defined with different names for different datatypes, also add C++ overloaded versions of the functions. For example, if you have `HMM_LengthVec2(hmm_vec2)` and `HMM_LengthVec3(hmm_vec3)`, also provide `HMM_Length(hmm_vec2)` and `HMM_Length(hmm_vec3)`.
@@ -49,3 +38,6 @@
* Try to define functions in the same order as the prototypes. * Try to define functions in the same order as the prototypes.
* Don't forget that Handmade Math uses column-major order for matrices! * Don't forget that Handmade Math uses column-major order for matrices!
# Versioning
We use [semantic versioning](http://semver.org/) because it's reasonable.

File diff suppressed because it is too large Load Diff

116
LICENSE Normal file
View File

@@ -0,0 +1,116 @@
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@@ -1,17 +1,23 @@
# Handmade-Math # Handmade Math
------
[![Build Status](https://travis-ci.org/StrangeZak/Handmade-Math.svg?branch=master)](https://travis-ci.org/StrangeZak/Handmade-Math) [![Build Status](https://travis-ci.org/HandmadeMath/Handmade-Math.svg?branch=master)](https://travis-ci.org/StrangeZak/Handmade-Math)
Single-file cross-platform public domain game math library for C/C++ A single-file, cross-platform, public domain game math library for C/C++.
_This library is free and will stay free, but if you would like to support development, or you are a company using HandmadeMath, please consider financial support._ To get started, go download [the latest release](https://github.com/HandmadeMath/Handmade-Math/releases).
[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/strangezak) [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.me/zakarystrange) -----
Version | Changes |
Version | Changes |
----------------|----------------| ----------------|----------------|
**1.6.0** | Added array subscript operators for vector and matrix types in C++. This is provided as a convenience, but be aware that it may incur an extra function call in unoptimized builds.
**1.5.1** | Fixed a bug with uninitialized elements in HMM_LookAt.
**1.5.0** | Changed internal structure for better performance and inlining. As a result, `HANDMADE_MATH_NO_INLINE` has been removed and no longer has any effect.
**1.4.0** | Fixed bug when using C mode. SSE'd all vec4 operations. Removed zeroing for better performance.
**1.3.0** | Removed need to `#define HANDMADE_MATH_CPP_MODE`. C++ definitions are now included automatically in C++ environments.
**1.2.0** | Added equality functions for `HMM_Vec2`, `HMM_Vec3`, and `HMM_Vec4`, and SSE'd `HMM_MultiplyMat4` and `HMM_Transpose`.
**1.1.5** | Added `Width` and `Height` to `HMM_Vec2`, and made it so you can supply your own `SqrtF`.
**1.1.4** | Fixed SSE being included on platforms that don't support it, and fixed divide-by-zero errors when normalizing zero vectors.
**1.1.3** | Fixed compile error in C mode **1.1.3** | Fixed compile error in C mode
**1.1.2** | Fixed invalid HMMDEF's in the function definitions **1.1.2** | Fixed invalid HMMDEF's in the function definitions
**1.1.1** | Resolved compiler warnings on gcc and g++ **1.1.1** | Resolved compiler warnings on gcc and g++
@@ -30,7 +36,6 @@ Version | Changes |
**0.1** | Initial Version | **0.1** | Initial Version |
----- -----
_This library is free and will stay free, but if you would like to support development, or you are a company using HandmadeMath, please consider financial support._
## FAQ ## FAQ
@@ -40,4 +45,4 @@ This library is in the public domain. You can do whatever you want with it.
**Where can I contact you to ask questions?** **Where can I contact you to ask questions?**
You can email me at: Zak@Handmade.Network Feel free to make Github issues for any questions, concerns, or problems you encounter.

BIN
example/Axes.blend Normal file

Binary file not shown.

10
example/Axes.mtl Normal file
View File

@@ -0,0 +1,10 @@
# Blender MTL File: 'Axes.blend'
# Material Count: 1
newmtl None
Ns 0
Ka 0.000000 0.000000 0.000000
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2

481
example/Axes.obj Normal file
View File

@@ -0,0 +1,481 @@
# Blender v2.78 (sub 0) OBJ File: 'Axes.blend'
# www.blender.org
mtllib Axes.mtl
o Cylinder.002_Cylinder
v 0.000000 0.080000 -0.000000
v 0.000000 0.080000 2.000000
v 0.056569 0.056569 -0.000000
v 0.056569 0.056569 2.000000
v 0.080000 -0.000000 0.000000
v 0.080000 0.000000 2.000000
v 0.056569 -0.056569 0.000000
v 0.056569 -0.056568 2.000000
v -0.000000 -0.080000 0.000000
v -0.000000 -0.080000 2.000000
v -0.056569 -0.056569 0.000000
v -0.056569 -0.056568 2.000000
v -0.080000 0.000000 -0.000000
v -0.080000 0.000000 2.000000
v -0.056569 0.056569 -0.000000
v -0.056569 0.056569 2.000000
v 0.000000 0.233061 1.965651
v 0.089189 0.215320 1.965651
v 0.164799 0.164799 1.965651
v 0.215320 0.089189 1.965651
v 0.233061 0.000000 1.965651
v 0.000000 0.000000 2.431772
v 0.215320 -0.089188 1.965651
v 0.164799 -0.164799 1.965651
v 0.089189 -0.215320 1.965651
v 0.000000 -0.233061 1.965651
v -0.089188 -0.215320 1.965651
v -0.164799 -0.164799 1.965651
v -0.215320 -0.089188 1.965651
v -0.233060 0.000000 1.965651
v -0.215320 0.089189 1.965651
v -0.164799 0.164799 1.965651
v -0.089188 0.215320 1.965651
vn 0.3827 0.9239 -0.0000
vn 0.9239 0.3827 -0.0000
vn 0.9239 -0.3827 0.0000
vn 0.3827 -0.9239 0.0000
vn -0.3827 -0.9239 0.0000
vn -0.9239 -0.3827 0.0000
vn 0.0000 0.0000 1.0000
vn -0.9239 0.3827 -0.0000
vn -0.3827 0.9239 -0.0000
vn 0.0000 -0.0000 -1.0000
vn 0.1752 0.8806 0.4403
vn 0.4988 0.7465 0.4403
vn 0.7465 0.4988 0.4403
vn 0.8806 0.1752 0.4403
vn 0.8806 -0.1752 0.4403
vn 0.7465 -0.4988 0.4403
vn 0.4988 -0.7465 0.4403
vn 0.1752 -0.8806 0.4403
vn -0.1752 -0.8806 0.4403
vn -0.4988 -0.7465 0.4403
vn -0.7465 -0.4988 0.4403
vn -0.8806 -0.1752 0.4403
vn -0.8806 0.1752 0.4403
vn -0.7465 0.4988 0.4403
vn -0.4988 0.7465 0.4403
vn -0.1752 0.8806 0.4403
usemtl None
s off
f 1//1 2//1 4//1 3//1
f 3//2 4//2 6//2 5//2
f 5//3 6//3 8//3 7//3
f 7//4 8//4 10//4 9//4
f 9//5 10//5 12//5 11//5
f 11//6 12//6 14//6 13//6
f 4//7 2//7 16//7 14//7 12//7 10//7 8//7 6//7
f 13//8 14//8 16//8 15//8
f 15//9 16//9 2//9 1//9
f 1//10 3//10 5//10 7//10 9//10 11//10 13//10 15//10
f 17//11 22//11 18//11
f 18//12 22//12 19//12
f 19//13 22//13 20//13
f 20//14 22//14 21//14
f 21//15 22//15 23//15
f 23//16 22//16 24//16
f 24//17 22//17 25//17
f 25//18 22//18 26//18
f 26//19 22//19 27//19
f 27//20 22//20 28//20
f 28//21 22//21 29//21
f 29//22 22//22 30//22
f 30//23 22//23 31//23
f 31//24 22//24 32//24
f 32//25 22//25 33//25
f 33//26 22//26 17//26
f 17//10 18//10 19//10 20//10 21//10 23//10 24//10 25//10 26//10 27//10 28//10 29//10 30//10 31//10 32//10 33//10
o Cylinder.001_Cylinder
v 0.000000 0.000000 -0.080000
v 0.000000 2.000000 -0.080000
v 0.056569 0.000000 -0.056569
v 0.056569 2.000000 -0.056569
v 0.080000 0.000000 0.000000
v 0.080000 2.000000 0.000000
v 0.056569 0.000000 0.056569
v 0.056569 2.000000 0.056569
v -0.000000 0.000000 0.080000
v -0.000000 2.000000 0.080000
v -0.056569 0.000000 0.056569
v -0.056569 2.000000 0.056569
v -0.080000 0.000000 -0.000000
v -0.080000 2.000000 -0.000000
v -0.056569 0.000000 -0.056569
v -0.056569 2.000000 -0.056569
v 0.000000 1.965651 -0.233061
v 0.089189 1.965651 -0.215320
v 0.164799 1.965651 -0.164799
v 0.215320 1.965651 -0.089188
v 0.233061 1.965651 0.000000
v 0.000000 2.431772 0.000000
v 0.215320 1.965651 0.089188
v 0.164799 1.965651 0.164799
v 0.089189 1.965651 0.215320
v 0.000000 1.965651 0.233061
v -0.089188 1.965651 0.215320
v -0.164799 1.965651 0.164799
v -0.215320 1.965651 0.089188
v -0.233060 1.965651 -0.000000
v -0.215320 1.965651 -0.089188
v -0.164799 1.965651 -0.164799
v -0.089188 1.965651 -0.215320
vn 0.3827 0.0000 -0.9239
vn 0.9239 0.0000 -0.3827
vn 0.9239 0.0000 0.3827
vn 0.3827 0.0000 0.9239
vn -0.3827 0.0000 0.9239
vn -0.9239 0.0000 0.3827
vn 0.0000 1.0000 -0.0000
vn -0.9239 0.0000 -0.3827
vn -0.3827 0.0000 -0.9239
vn 0.0000 -1.0000 0.0000
vn 0.1752 0.4403 -0.8806
vn 0.4988 0.4403 -0.7465
vn 0.7465 0.4403 -0.4988
vn 0.8806 0.4403 -0.1752
vn 0.8806 0.4403 0.1752
vn 0.7465 0.4403 0.4988
vn 0.4988 0.4403 0.7465
vn 0.1752 0.4403 0.8806
vn -0.1752 0.4403 0.8806
vn -0.4988 0.4403 0.7465
vn -0.7465 0.4403 0.4988
vn -0.8806 0.4403 0.1752
vn -0.8806 0.4403 -0.1752
vn -0.7465 0.4403 -0.4988
vn -0.4988 0.4403 -0.7465
vn -0.1752 0.4403 -0.8806
usemtl None
s off
f 34//27 35//27 37//27 36//27
f 36//28 37//28 39//28 38//28
f 38//29 39//29 41//29 40//29
f 40//30 41//30 43//30 42//30
f 42//31 43//31 45//31 44//31
f 44//32 45//32 47//32 46//32
f 37//33 35//33 49//33 47//33 45//33 43//33 41//33 39//33
f 46//34 47//34 49//34 48//34
f 48//35 49//35 35//35 34//35
f 34//36 36//36 38//36 40//36 42//36 44//36 46//36 48//36
f 50//37 55//37 51//37
f 51//38 55//38 52//38
f 52//39 55//39 53//39
f 53//40 55//40 54//40
f 54//41 55//41 56//41
f 56//42 55//42 57//42
f 57//43 55//43 58//43
f 58//44 55//44 59//44
f 59//45 55//45 60//45
f 60//46 55//46 61//46
f 61//47 55//47 62//47
f 62//48 55//48 63//48
f 63//49 55//49 64//49
f 64//50 55//50 65//50
f 65//51 55//51 66//51
f 66//52 55//52 50//52
f 50//36 51//36 52//36 53//36 54//36 56//36 57//36 58//36 59//36 60//36 61//36 62//36 63//36 64//36 65//36 66//36
o Cylinder
v 0.000000 0.000000 -0.080000
v 2.000000 0.000000 -0.080000
v 0.000000 -0.056569 -0.056569
v 2.000000 -0.056568 -0.056569
v 0.000000 -0.080000 0.000000
v 2.000000 -0.080000 0.000000
v 0.000000 -0.056569 0.056569
v 2.000000 -0.056568 0.056569
v -0.000000 0.000000 0.080000
v 2.000000 0.000000 0.080000
v -0.000000 0.056569 0.056569
v 2.000000 0.056569 0.056569
v -0.000000 0.080000 -0.000000
v 2.000000 0.080000 -0.000000
v -0.000000 0.056569 -0.056569
v 2.000000 0.056569 -0.056569
v 1.965651 -0.000000 -0.233061
v 1.965651 -0.089188 -0.215320
v 1.965651 -0.164799 -0.164799
v 1.965651 -0.215320 -0.089188
v 1.965651 -0.233061 0.000000
v 2.431772 0.000000 0.000000
v 1.965651 -0.215320 0.089188
v 1.965651 -0.164799 0.164799
v 1.965651 -0.089188 0.215320
v 1.965651 -0.000000 0.233061
v 1.965651 0.089188 0.215320
v 1.965651 0.164799 0.164799
v 1.965651 0.215320 0.089188
v 1.965651 0.233061 -0.000000
v 1.965651 0.215320 -0.089188
v 1.965651 0.164799 -0.164799
v 1.965651 0.089188 -0.215320
vn 0.0000 -0.3827 -0.9239
vn 0.0000 -0.9239 -0.3827
vn 0.0000 -0.9239 0.3827
vn 0.0000 -0.3827 0.9239
vn -0.0000 0.3827 0.9239
vn -0.0000 0.9239 0.3827
vn 1.0000 -0.0000 0.0000
vn -0.0000 0.9239 -0.3827
vn -0.0000 0.3827 -0.9239
vn -1.0000 -0.0000 0.0000
vn 0.4403 -0.1752 -0.8806
vn 0.4403 -0.4988 -0.7465
vn 0.4403 -0.7465 -0.4988
vn 0.4403 -0.8806 -0.1752
vn 0.4403 -0.8806 0.1752
vn 0.4403 -0.7465 0.4988
vn 0.4403 -0.4988 0.7465
vn 0.4403 -0.1752 0.8806
vn 0.4403 0.1752 0.8806
vn 0.4403 0.4988 0.7465
vn 0.4403 0.7465 0.4988
vn 0.4403 0.8806 0.1752
vn 0.4403 0.8806 -0.1752
vn 0.4403 0.7465 -0.4988
vn 0.4403 0.4988 -0.7465
vn 0.4403 0.1752 -0.8806
usemtl None
s off
f 67//53 68//53 70//53 69//53
f 69//54 70//54 72//54 71//54
f 71//55 72//55 74//55 73//55
f 73//56 74//56 76//56 75//56
f 75//57 76//57 78//57 77//57
f 77//58 78//58 80//58 79//58
f 70//59 68//59 82//59 80//59 78//59 76//59 74//59 72//59
f 79//60 80//60 82//60 81//60
f 81//61 82//61 68//61 67//61
f 67//62 69//62 71//62 73//62 75//62 77//62 79//62 81//62
f 83//63 88//63 84//63
f 84//64 88//64 85//64
f 85//65 88//65 86//65
f 86//66 88//66 87//66
f 87//67 88//67 89//67
f 89//68 88//68 90//68
f 90//69 88//69 91//69
f 91//70 88//70 92//70
f 92//71 88//71 93//71
f 93//72 88//72 94//72
f 94//73 88//73 95//73
f 95//74 88//74 96//74
f 96//75 88//75 97//75
f 97//76 88//76 98//76
f 98//77 88//77 99//77
f 99//78 88//78 83//78
f 83//62 84//62 85//62 86//62 87//62 89//62 90//62 91//62 92//62 93//62 94//62 95//62 96//62 97//62 98//62 99//62
o Text.005
v 0.778616 0.000000 -3.449000
v 0.395616 0.000000 -3.449000
v 0.395616 0.000000 -3.369000
v 0.623616 0.000000 -3.369000
v 0.385616 0.000000 -3.000000
v 0.779616 0.000000 -3.000000
v 0.779616 0.000000 -3.080000
v 0.539616 0.000000 -3.080000
v 0.334616 0.000000 -3.267000
v 0.091616 0.000000 -3.267000
v 0.091616 0.000000 -3.174000
v 0.334616 0.000000 -3.174000
vn 0.0000 1.0000 0.0000
usemtl None
s off
f 102//79 100//79 101//79
f 102//79 103//79 100//79
f 103//79 107//79 100//79
f 104//79 107//79 103//79
f 104//79 106//79 107//79
f 104//79 105//79 106//79
f 110//79 108//79 109//79
f 110//79 111//79 108//79
o Text.004
v 1.039616 0.000000 2.551000
v 0.656616 0.000000 2.551000
v 0.656616 0.000000 2.631000
v 0.884616 0.000000 2.631000
v 0.646616 0.000000 3.000000
v 1.040616 0.000000 3.000000
v 1.040616 0.000000 2.920000
v 0.800616 0.000000 2.920000
v 0.302616 0.000000 2.411000
v 0.302616 0.000000 2.606000
v 0.107616 0.000000 2.606000
v 0.107616 0.000000 2.688000
v 0.302616 0.000000 2.688000
v 0.302616 0.000000 2.883000
v 0.384616 0.000000 2.883000
v 0.384616 0.000000 2.688000
v 0.579616 0.000000 2.688000
v 0.579616 0.000000 2.606000
v 0.384616 0.000000 2.606000
v 0.384616 0.000000 2.411000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
usemtl None
s off
f 114//80 112//80 113//80
f 114//80 115//80 112//80
f 115//80 119//80 112//80
f 116//80 119//80 115//80
f 116//80 118//80 119//80
f 116//80 117//80 118//80
f 121//80 131//80 120//80
f 121//80 130//80 131//80
f 123//80 121//80 122//80
f 123//80 130//80 121//80
f 123//80 129//80 130//80
f 123//80 128//80 129//80
f 124//81 128//81 123//81
f 125//80 127//80 124//80
f 127//81 128//81 124//81
f 125//80 126//80 127//80
o Text.003
v 0.812616 -2.551000 -0.000000
v 0.712616 -2.551000 -0.000000
v 0.596616 -2.804000 -0.000000
v 0.475616 -2.551000 -0.000000
v 0.374616 -2.551000 -0.000000
v 0.548616 -2.904000 -0.000000
v 0.395616 -3.230000 0.000000
v 0.494616 -3.230000 0.000000
v 0.334616 -2.733000 -0.000000
v 0.091616 -2.733000 -0.000000
v 0.091616 -2.826000 -0.000000
v 0.334616 -2.826000 -0.000000
vn 0.0000 0.0000 1.0000
usemtl None
s off
f 137//82 135//82 136//82
f 137//82 134//82 135//82
f 134//82 132//82 133//82
f 134//82 139//82 132//82
f 137//82 139//82 134//82
f 138//82 139//82 137//82
f 142//82 140//82 141//82
f 142//82 143//82 140//82
o Text.002
v 1.073616 3.449000 -0.000000
v 0.973616 3.449000 -0.000000
v 0.857616 3.196000 -0.000000
v 0.736616 3.449000 -0.000000
v 0.635616 3.449000 -0.000000
v 0.809616 3.096000 -0.000000
v 0.656616 2.770000 0.000000
v 0.755616 2.770000 0.000000
v 0.302616 3.589000 -0.000000
v 0.302616 3.394000 -0.000000
v 0.107616 3.394000 -0.000000
v 0.107616 3.312000 -0.000000
v 0.302616 3.312000 -0.000000
v 0.302616 3.117000 -0.000000
v 0.384616 3.117000 -0.000000
v 0.384616 3.312000 -0.000000
v 0.579616 3.312000 -0.000000
v 0.579616 3.394000 -0.000000
v 0.384616 3.394000 -0.000000
v 0.384616 3.589000 -0.000000
vn 0.0000 0.0000 1.0000
vn 0.0000 0.0000 -1.0000
usemtl None
s off
f 149//83 147//83 148//83
f 149//83 146//83 147//83
f 146//83 144//83 145//83
f 146//83 151//83 144//83
f 149//83 151//83 146//83
f 150//83 151//83 149//83
f 153//83 163//83 152//83
f 153//83 162//83 163//83
f 155//83 153//83 154//83
f 155//83 162//83 153//83
f 155//83 161//83 162//83
f 155//83 160//83 161//83
f 156//84 160//84 155//84
f 157//83 159//83 156//83
f 159//83 160//83 156//83
f 157//83 158//83 159//83
o Text.001
v -3.138384 0.000000 -0.449000
v -3.252384 0.000000 -0.449000
v -3.380384 0.000000 -0.295000
v -3.513384 0.000000 -0.449000
v -3.625384 0.000000 -0.449000
v -3.436384 0.000000 -0.228000
v -3.625384 0.000000 0.000000
v -3.513384 0.000000 0.000000
v -3.380384 0.000000 -0.161000
v -3.239384 0.000000 0.000000
v -3.125384 0.000000 0.000000
v -3.323384 0.000000 -0.228000
v -3.665384 0.000000 -0.267000
v -3.908384 0.000000 -0.267000
v -3.908384 0.000000 -0.174000
v -3.665384 0.000000 -0.174000
vn 0.0000 1.0000 0.0000
usemtl None
s off
f 169//85 167//85 168//85
f 169//85 166//85 167//85
f 166//85 164//85 165//85
f 166//85 175//85 164//85
f 169//85 175//85 166//85
f 170//85 175//85 169//85
f 170//85 172//85 175//85
f 172//85 174//85 175//85
f 170//85 171//85 172//85
f 173//85 174//85 172//85
f 178//85 176//85 177//85
f 178//85 179//85 176//85
o Text
v 4.122616 0.000000 -0.449000
v 4.008616 0.000000 -0.449000
v 3.880616 0.000000 -0.295000
v 3.747616 0.000000 -0.449000
v 3.635616 0.000000 -0.449000
v 3.824616 0.000000 -0.228000
v 3.635616 0.000000 0.000000
v 3.747616 0.000000 0.000000
v 3.880616 0.000000 -0.161000
v 4.021616 0.000000 0.000000
v 4.135616 0.000000 0.000000
v 3.937616 0.000000 -0.228000
v 3.302616 0.000000 -0.589000
v 3.302616 0.000000 -0.394000
v 3.107616 0.000000 -0.394000
v 3.107616 0.000000 -0.312000
v 3.302616 0.000000 -0.312000
v 3.302616 0.000000 -0.117000
v 3.384616 0.000000 -0.117000
v 3.384616 0.000000 -0.312000
v 3.579616 0.000000 -0.312000
v 3.579616 0.000000 -0.394000
v 3.384616 0.000000 -0.394000
v 3.384616 0.000000 -0.589000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
usemtl None
s off
f 185//86 183//86 184//86
f 185//86 182//86 183//86
f 182//86 180//86 181//86
f 182//86 191//86 180//86
f 185//86 191//86 182//86
f 186//86 191//86 185//86
f 186//86 188//86 191//86
f 188//86 190//86 191//86
f 186//86 187//86 188//86
f 189//86 190//86 188//86
f 193//86 203//86 192//86
f 193//86 202//86 203//86
f 195//86 193//86 194//86
f 195//86 202//86 193//86
f 195//86 201//86 202//86
f 195//86 200//86 201//86
f 196//87 200//87 195//87
f 197//86 199//86 196//86
f 199//87 200//87 196//87
f 197//86 198//86 199//86

22
example/Makefile Normal file
View File

@@ -0,0 +1,22 @@
BUILD_DIR=build
CXXFLAGS+=-std=c++11
clean:
rm -rf $(BUILD_DIR)
glfw:
mkdir -p $(BUILD_DIR)/glfw
cd $(BUILD_DIR)/glfw \
&& cmake -DGLFW_BUILD_TESTS=off -DGLFW_BUILD_DOCS=off -DGLFW_BUILD_EXAMPLES=off ../../external/glfw \
&& make
example:
mkdir -p $(BUILD_DIR)/example
cd $(BUILD_DIR)/example \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -ohmmexample \
-I../../external/glfw/include -I../../.. \
-L../glfw/src \
-lglew -lglfw3 \
-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo \
../../src/*.cpp

10
example/MonkeyFlat.mtl Normal file
View File

@@ -0,0 +1,10 @@
# Blender MTL File: 'None'
# Material Count: 1
newmtl None
Ns 0
Ka 0.000000 0.000000 0.000000
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2

1512
example/MonkeyFlat.obj Normal file

File diff suppressed because it is too large Load Diff

10
example/MonkeySmooth.mtl Normal file
View File

@@ -0,0 +1,10 @@
# Blender MTL File: 'None'
# Material Count: 1
newmtl None
Ns 0
Ka 0.000000 0.000000 0.000000
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2

5998
example/MonkeySmooth.obj Normal file

File diff suppressed because it is too large Load Diff

14
example/build.bat Normal file
View File

@@ -0,0 +1,14 @@
@echo off
mkdir build\example
pushd build\example
cl^
/I..\..\.. /I..\..\external\glew\include /I..\..\external\glfw-win64\include^
/MD /EHsc^
..\..\src\*.cpp^
/Fehmm_example.exe^
/link^
/LIBPATH:..\..\external\glew\lib\Release\x64 /LIBPATH:..\..\external\glfw-win64\lib-vc2015^
opengl32.lib gdi32.lib user32.lib shell32.lib glew32.lib glfw3.lib
copy ..\..\external\glew\bin\Release\x64\glew32.dll glew32.dll
popd

73
example/external/glew/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,73 @@
The OpenGL Extension Wrangler Library
Copyright (C) 2002-2007, Milan Ikits <milan ikits[]ieee org>
Copyright (C) 2002-2007, Marcelo E. Magallon <mmagallo[]debian org>
Copyright (C) 2002, Lev Povalahev
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
Mesa 3-D graphics library
Version: 7.0
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyright (c) 2007 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

2618
example/external/glew/include/GL/eglew.h vendored Normal file

File diff suppressed because it is too large Load Diff

23686
example/external/glew/include/GL/glew.h vendored Normal file

File diff suppressed because it is too large Load Diff

1775
example/external/glew/include/GL/glxew.h vendored Normal file

File diff suppressed because it is too large Load Diff

1447
example/external/glew/include/GL/wglew.h vendored Normal file

File diff suppressed because it is too large Load Diff

1
example/external/glfw vendored Submodule

Submodule example/external/glfw added at 617a322bd8

22
example/external/glfw-win64/COPYING.txt vendored Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2002-2006 Marcus Geelnard
Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would
be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,456 @@
/*************************************************************************
* GLFW 3.2 - www.glfw.org
* A library for OpenGL, window and input
*------------------------------------------------------------------------
* Copyright (c) 2002-2006 Marcus Geelnard
* Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would
* be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
*************************************************************************/
#ifndef _glfw3_native_h_
#define _glfw3_native_h_
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************************
* Doxygen documentation
*************************************************************************/
/*! @file glfw3native.h
* @brief The header of the native access functions.
*
* This is the header file of the native access functions. See @ref native for
* more information.
*/
/*! @defgroup native Native access
*
* **By using the native access functions you assert that you know what you're
* doing and how to fix problems caused by using them. If you don't, you
* shouldn't be using them.**
*
* Before the inclusion of @ref glfw3native.h, you may define exactly one
* window system API macro and zero or more context creation API macros.
*
* The chosen backends must match those the library was compiled for. Failure
* to do this will cause a link-time error.
*
* The available window API macros are:
* * `GLFW_EXPOSE_NATIVE_WIN32`
* * `GLFW_EXPOSE_NATIVE_COCOA`
* * `GLFW_EXPOSE_NATIVE_X11`
* * `GLFW_EXPOSE_NATIVE_WAYLAND`
* * `GLFW_EXPOSE_NATIVE_MIR`
*
* The available context API macros are:
* * `GLFW_EXPOSE_NATIVE_WGL`
* * `GLFW_EXPOSE_NATIVE_NSGL`
* * `GLFW_EXPOSE_NATIVE_GLX`
* * `GLFW_EXPOSE_NATIVE_EGL`
*
* These macros select which of the native access functions that are declared
* and which platform-specific headers to include. It is then up your (by
* definition platform-specific) code to handle which of these should be
* defined.
*/
/*************************************************************************
* System headers and types
*************************************************************************/
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
// example to allow applications to correctly declare a GL_ARB_debug_output
// callback) but windows.h assumes no one will define APIENTRY before it does
#undef APIENTRY
#include <windows.h>
#elif defined(GLFW_EXPOSE_NATIVE_COCOA)
#include <ApplicationServices/ApplicationServices.h>
#if defined(__OBJC__)
#import <Cocoa/Cocoa.h>
#else
typedef void* id;
#endif
#elif defined(GLFW_EXPOSE_NATIVE_X11)
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
#include <wayland-client.h>
#elif defined(GLFW_EXPOSE_NATIVE_MIR)
#include <mir_toolkit/mir_client_library.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_WGL)
/* WGL is declared by windows.h */
#endif
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
/* NSGL is declared by Cocoa.h */
#endif
#if defined(GLFW_EXPOSE_NATIVE_GLX)
#include <GL/glx.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_EGL)
#include <EGL/egl.h>
#endif
/*************************************************************************
* Functions
*************************************************************************/
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
/*! @brief Returns the adapter device name of the specified monitor.
*
* @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`)
* of the specified monitor, or `NULL` if an [error](@ref error_handling)
* occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.1.
*
* @ingroup native
*/
GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor);
/*! @brief Returns the display device name of the specified monitor.
*
* @return The UTF-8 encoded display device name (for example
* `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.1.
*
* @ingroup native
*/
GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor);
/*! @brief Returns the `HWND` of the specified window.
*
* @return The `HWND` of the specified window, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.0.
*
* @ingroup native
*/
GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_WGL)
/*! @brief Returns the `HGLRC` of the specified window.
*
* @return The `HGLRC` of the specified window, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.0.
*
* @ingroup native
*/
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_COCOA)
/*! @brief Returns the `CGDirectDisplayID` of the specified monitor.
*
* @return The `CGDirectDisplayID` of the specified monitor, or
* `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.1.
*
* @ingroup native
*/
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor);
/*! @brief Returns the `NSWindow` of the specified window.
*
* @return The `NSWindow` of the specified window, or `nil` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.0.
*
* @ingroup native
*/
GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
/*! @brief Returns the `NSOpenGLContext` of the specified window.
*
* @return The `NSOpenGLContext` of the specified window, or `nil` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.0.
*
* @ingroup native
*/
GLFWAPI id glfwGetNSGLContext(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_X11)
/*! @brief Returns the `Display` used by GLFW.
*
* @return The `Display` used by GLFW, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.0.
*
* @ingroup native
*/
GLFWAPI Display* glfwGetX11Display(void);
/*! @brief Returns the `RRCrtc` of the specified monitor.
*
* @return The `RRCrtc` of the specified monitor, or `None` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.1.
*
* @ingroup native
*/
GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
/*! @brief Returns the `RROutput` of the specified monitor.
*
* @return The `RROutput` of the specified monitor, or `None` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.1.
*
* @ingroup native
*/
GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
/*! @brief Returns the `Window` of the specified window.
*
* @return The `Window` of the specified window, or `None` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.0.
*
* @ingroup native
*/
GLFWAPI Window glfwGetX11Window(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_GLX)
/*! @brief Returns the `GLXContext` of the specified window.
*
* @return The `GLXContext` of the specified window, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.0.
*
* @ingroup native
*/
GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window);
/*! @brief Returns the `GLXWindow` of the specified window.
*
* @return The `GLXWindow` of the specified window, or `None` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.2.
*
* @ingroup native
*/
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
/*! @brief Returns the `struct wl_display*` used by GLFW.
*
* @return The `struct wl_display*` used by GLFW, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.2.
*
* @ingroup native
*/
GLFWAPI struct wl_display* glfwGetWaylandDisplay(void);
/*! @brief Returns the `struct wl_output*` of the specified monitor.
*
* @return The `struct wl_output*` of the specified monitor, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.2.
*
* @ingroup native
*/
GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
/*! @brief Returns the main `struct wl_surface*` of the specified window.
*
* @return The main `struct wl_surface*` of the specified window, or `NULL` if
* an [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.2.
*
* @ingroup native
*/
GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_MIR)
/*! @brief Returns the `MirConnection*` used by GLFW.
*
* @return The `MirConnection*` used by GLFW, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.2.
*
* @ingroup native
*/
GLFWAPI MirConnection* glfwGetMirDisplay(void);
/*! @brief Returns the Mir output ID of the specified monitor.
*
* @return The Mir output ID of the specified monitor, or zero if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.2.
*
* @ingroup native
*/
GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor);
/*! @brief Returns the `MirSurface*` of the specified window.
*
* @return The `MirSurface*` of the specified window, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.2.
*
* @ingroup native
*/
GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_EGL)
/*! @brief Returns the `EGLDisplay` used by GLFW.
*
* @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.0.
*
* @ingroup native
*/
GLFWAPI EGLDisplay glfwGetEGLDisplay(void);
/*! @brief Returns the `EGLContext` of the specified window.
*
* @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.0.
*
* @ingroup native
*/
GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window);
/*! @brief Returns the `EGLSurface` of the specified window.
*
* @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.0.
*
* @ingroup native
*/
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window);
#endif
#ifdef __cplusplus
}
#endif
#endif /* _glfw3_native_h_ */

5
example/shell.bat Normal file
View File

@@ -0,0 +1,5 @@
@echo off
if not defined ORIGINALPATH set ORIGINALPATH=%PATH%
set PATH=%ORIGINALPATH%
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64

161
example/src/Cube.h Normal file
View File

@@ -0,0 +1,161 @@
#include <HandmadeMath.h>
#include "Entity.h"
#include "RenderComponent.h"
#ifndef HMME_CUBE_H
#define HMME_CUBE_H
// Our vertices. Three consecutive floats give a 3D vertex; Three consecutive vertices give a triangle.
// A cube has 6 faces with 2 triangles each, so this makes 6*2=12 triangles, and 12*3 vertices
static const GLfloat cubeVertices[] = {
-1.0f,-1.0f,-1.0f, // triangle 1 : begin
-1.0f,-1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, // triangle 1 : end
1.0f, 1.0f,-1.0f, // triangle 2 : begin
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f,-1.0f, // triangle 2 : end
1.0f,-1.0f, 1.0f,
-1.0f,-1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f,
1.0f,-1.0f, 1.0f,
-1.0f,-1.0f, 1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f,-1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f,-1.0f,
-1.0f, 1.0f,-1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f
};
// One color for each vertex. They were generated randomly.
static const GLfloat cubeColors[] = {
0.583f, 0.771f, 0.014f,
0.609f, 0.115f, 0.436f,
0.327f, 0.483f, 0.844f,
0.822f, 0.569f, 0.201f,
0.435f, 0.602f, 0.223f,
0.310f, 0.747f, 0.185f,
0.597f, 0.770f, 0.761f,
0.559f, 0.436f, 0.730f,
0.359f, 0.583f, 0.152f,
0.483f, 0.596f, 0.789f,
0.559f, 0.861f, 0.639f,
0.195f, 0.548f, 0.859f,
0.014f, 0.184f, 0.576f,
0.771f, 0.328f, 0.970f,
0.406f, 0.615f, 0.116f,
0.676f, 0.977f, 0.133f,
0.971f, 0.572f, 0.833f,
0.140f, 0.616f, 0.489f,
0.997f, 0.513f, 0.064f,
0.945f, 0.719f, 0.592f,
0.543f, 0.021f, 0.978f,
0.279f, 0.317f, 0.505f,
0.167f, 0.620f, 0.077f,
0.347f, 0.857f, 0.137f,
0.055f, 0.953f, 0.042f,
0.714f, 0.505f, 0.345f,
0.783f, 0.290f, 0.734f,
0.722f, 0.645f, 0.174f,
0.302f, 0.455f, 0.848f,
0.225f, 0.587f, 0.040f,
0.517f, 0.713f, 0.338f,
0.053f, 0.959f, 0.120f,
0.393f, 0.621f, 0.362f,
0.673f, 0.211f, 0.457f,
0.820f, 0.883f, 0.371f,
0.982f, 0.099f, 0.879f
};
class CubeRenderComponent : public RenderComponent {
public:
GLuint vaoID;
GLuint vertexBufferID;
GLuint colorBufferID;
CubeRenderComponent() {
glGenVertexArrays(1, &vaoID);
glGenBuffers(1, &vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW);
glGenBuffers(1, &colorBufferID);
glBindBuffer(GL_ARRAY_BUFFER, colorBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeColors), cubeColors, GL_STATIC_DRAW);
}
void Draw() override {
glBindVertexArray(vaoID);
// 1st attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : colors
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorBufferID);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Shader??
// Draw the triangle!
glDrawArrays(GL_TRIANGLES, 0, 36); // Starting from vertex 0; 3 vertices total -> 1 triangle
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
};
class Cube : public Entity {
public:
float x = 0;
CubeRenderComponent rc = CubeRenderComponent();
Cube() {
// renderComponent = &rc;
}
void Tick(float deltaSeconds, Input previousInput, Input input) override {
x += deltaSeconds;
// position.X = 2.0f * HMM_SINF(x);
rotation *= HMM_QuaternionFromAxisAngle(HMM_Vec3(0.0f, 1.0f, 0.0f), deltaSeconds * HMM_ToRadians(45.0f));
}
};
#endif

119
example/src/Entity.h Normal file
View File

@@ -0,0 +1,119 @@
#include <vector>
#include <HandmadeMath.h>
#ifndef HMME_ENTITY_H
#define HMME_ENTITY_H
#include "RenderComponent.h"
class Entity {
public:
hmm_vec3 position = HMM_Vec3(0.0f, 0.0f, 0.0f);
hmm_quaternion rotation = HMM_Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
hmm_vec3 scale = HMM_Vec3(1.0f, 1.0f, 1.0f);
std::vector<Entity*> children;
void AddChild(Entity* e) {
children.push_back(e);
}
virtual void Tick(float deltaSeconds, Input previousInput, Input input) {}
RenderComponent *renderComponent = NULL;
struct CameraInfo {
float fov = 90.0f;
float aspect = 1024.0f / 768.0f;
float near = 0.1f;
float far = 100.0f;
};
CameraInfo camera;
hmm_mat4 projectionMatrix() {
return HMM_Perspective(camera.fov, camera.aspect, camera.near, camera.far);
}
hmm_mat4 viewMatrix() {
return HMM_LookAt(worldPosition(), worldPosition() + forward(), up());
}
hmm_vec3 worldPosition() {
return (modelMatrix * HMM_Vec4(0.0f, 0.0f, 0.0f, 1.0f)).XYZ;
}
hmm_vec3 up() {
return (modelMatrix * HMM_Vec4(0.0f, 1.0f, 0.0f, 1.0f)).XYZ - worldPosition();
}
hmm_vec3 forward() {
return (modelMatrix * HMM_Vec4(1.0f, 0.0f, 0.0f, 1.0f)).XYZ - worldPosition();
}
hmm_vec3 right() {
return (modelMatrix * HMM_Vec4(0.0f, 0.0f, 1.0f, 1.0f)).XYZ - worldPosition();
}
// Context for rendering and stuff
hmm_mat4 parentModelMatrix;
hmm_mat4 modelMatrix;
};
class EntityIterator {
public:
typedef struct State {
Entity *entity;
int childIndex;
State(Entity *e) {
entity = e;
childIndex = -1;
}
} State;
EntityIterator(Entity *e) {
stack.push_back(State(e));
}
bool HasNext() {
return !stack.empty();
}
Entity *Next() {
Entity *result = 0;
// Pass 1 - get a result by either grabbing the current entity or making another state
while (true) {
State *state = &stack.back();
if (state->childIndex < 0) {
result = state->entity;
state->childIndex = 0;
break;
} else {
int nextIndex = state->childIndex;
state->childIndex++;
stack.push_back(State(state->entity->children[nextIndex]));
}
}
// Pass 2 - remove exhausted states from the stack
while (!stack.empty()) {
State state = stack.back();
if (state.childIndex >= state.entity->children.size()) {
stack.pop_back();
} else {
break;
}
}
return result;
}
private:
std::vector<State> stack;
};
#endif

62
example/src/FPSCam.h Normal file
View File

@@ -0,0 +1,62 @@
#include <stdio.h>
#include <tgmath.h>
#ifndef HMME_FPSCAM_H
#define HMME_FPSCAM_H
#include "Entity.h"
#include "FollowCam.h"
#include "HandmadeMath.h"
#include "debug.h"
class FPSCam : public Entity {
public:
FollowCam cam = FollowCam(0); // TODO: Why on earth is this necessary?? Remove this and fix the error.
Entity target;
// all angles in radians
float yaw = 0;
float pitch = 0;
float sensitivity = 0.002f;
FPSCam() {
target = Entity();
target.position = HMM_Vec3(0.0f, 0.0f, -1.0f);
cam = FollowCam(&target);
AddChild(&target);
AddChild(&cam);
}
void Tick(float deltaSeconds, Input previousInput, Input input) override {
double deltaX = input.mouseX - previousInput.mouseX;
double deltaY = input.mouseY - previousInput.mouseY;
// HACK: Pitch is being weird for reasons I don't understand. It works fine for
// 360 degrees, then does something silly for 360 degrees, then repeats. I suspect
// I'm just doing something wrong with quaternions because I know they encode twice
// the angle or whatever. In any case, I've hacked around it for now to splice
// together ranges that work.
yaw = yaw + (-deltaX * sensitivity);
pitch = HMM_Clamp(-HMM_PI32 / 2, pitch + (-deltaY * sensitivity), HMM_PI32 / 2);
// HACK: MEGAHACK: why the heck is the apparent rotation twice what it should be?
float hackyPitch = HMM_PI32;
if (pitch > 0) {
hackyPitch = HMM_PI32 + pitch / 2;
} else if (pitch < 0) {
hackyPitch = 2 * HMM_PI32 + pitch / 2;
}
printf("%f\t%f\n", pitch, hackyPitch);
hmm_quaternion rotationYaw = HMM_QuaternionFromAxisAngle(HMM_Vec3(0.0f, 1.0f, 0.0f), yaw);
hmm_quaternion rotationPitch = HMM_QuaternionFromAxisAngle(HMM_Vec3(1.0f, 0.0f, 0.0f), hackyPitch);
rotation = rotationPitch * rotationYaw;
}
};
#endif

71
example/src/FollowCam.h Normal file
View File

@@ -0,0 +1,71 @@
#include <stdio.h>
#ifndef HMME_FOLLOWCAM_H
#define HMME_FOLLOWCAM_H
#include "Entity.h"
#include "HandmadeMath.h"
#include "debug.h"
class FollowCam : public Entity {
public:
Entity *target;
FollowCam(Entity *t) {
target = t;
}
void Tick(float deltaSeconds, Input previousInput, Input input) override {
// TODO: Find a way to do this rotation routine in a single quaternion. Maybe that
// just means finding a correct method, then doing some quaternion multiplication
// on paper to see how the axis and angle shake out.
rotation = GetLookAtRotation();
}
hmm_quaternion GetLookAtRotation() {
hmm_vec3 fwd = (parentModelMatrix * HMM_Vec4(1.0f, 0.0f, 0.0f, 0.0f)).XYZ;
hmm_vec3 up = (parentModelMatrix * HMM_Vec4(0.0f, 1.0f, 0.0f, 0.0f)).XYZ;
hmm_vec3 to = target->worldPosition() - worldPosition();
hmm_vec3 pointAxis = HMM_Cross(fwd, to);
hmm_quaternion justPointAt;
// TODO: proper epsilon! and probably implement some kind of nan
// protection because a single nan ruins everything.
if (HMM_ABS(HMM_Length(pointAxis)) < 0.0001f) {
// Already pointing at the thing!
justPointAt = HMM_Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
} else {
justPointAt = HMM_QuaternionFromAxisAngle(
pointAxis,
HMM_ACosF(HMM_Dot(HMM_Normalize(fwd), HMM_Normalize(to)))
);
}
hmm_vec3 newUp = (HMM_QuaternionToMat4(justPointAt) * HMM_Vec4v(up, 0.0f)).XYZ;
hmm_quaternion backUpright = HMM_QuaternionFromAxisAngle(
to,
// TODO: This angle is not quite right! After this corrective rotation,
// the new up vector will *not* necessarily align with world up! So this
// will overshoot a little bit.
//
// You should probably project the world up vector onto the plane of the
// to vector before you do the dot product. This is a good opportunity to
// add the vector projection stuff that we somehow have left out!
-HMM_ACosF(HMM_Dot(HMM_Normalize(newUp), HMM_Vec3(0.0f, 1.0f, 0.0f)))
);
return backUpright * justPointAt;
// BEN
//
// YOU MUST ALWAYS REMEMBER THAT QUATERNION MULTIPLICATION IS NOT COMMUTATIVE
// AND THAT IT GOES RIGHT TO LEFT
//
// NEVER FORGET THIS LEST YOU SUFFER THROUGH THIS MESS AGAIN
}
};
#endif

View File

@@ -0,0 +1,2 @@
#define HANDMADE_MATH_IMPLEMENTATION
#include <HandmadeMath.h>

View File

@@ -0,0 +1,179 @@
#include <string>
#include <vector>
#ifndef HMME_MESH_RENDER_COMPONENT_H
#define HMME_MESH_RENDER_COMPONENT_H
#include "tiny_obj_loader.h"
class MeshRenderComponent : public RenderComponent {
public:
bool didLoad = false;
struct Shape {
GLuint vaoID = 0;
GLuint vertexBufferID = 0;
GLuint normalBufferID = 0;
GLuint uvBufferID = 0;
GLuint colorBufferID = 0;
int numVerts = 0;
};
std::vector<Shape> renderShapes;
MeshRenderComponent(const char *filename) {
// Load the model
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename);
if (!err.empty()) { // `err` may contain warning message.
printf("Failed to load mesh: %s\n", err.c_str());
}
if (!ret) {
return;
}
for (auto shape : shapes) {
std::vector<tinyobj::real_t> vertices;
std::vector<tinyobj::real_t> normals;
std::vector<tinyobj::real_t> uvs;
std::vector<tinyobj::real_t> colors;
for (auto indices : shape.mesh.indices) {
if (indices.vertex_index > -1) {
for (int i = 0; i < 3; i++) {
int attribIndex = 3 * indices.vertex_index + i;
vertices.push_back(attrib.vertices[attribIndex]);
colors.push_back(attrib.colors[attribIndex]);
}
}
if (indices.normal_index > -1) {
for (int i = 0; i < 3; i++) {
int attribIndex = 3 * indices.normal_index + i;
normals.push_back(attrib.normals[attribIndex]);
}
}
if (indices.texcoord_index > -1) {
for (int i = 0; i < 2; i++) {
int attribIndex = 2 * indices.texcoord_index + i;
uvs.push_back(attrib.texcoords[attribIndex]);
}
}
}
Shape s; // the new shape to insert into our list
glGenVertexArrays(1, &s.vaoID);
if (!vertices.empty()) {
glGenBuffers(1, &s.vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, s.vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(tinyobj::real_t) * vertices.size(), &vertices.front(), GL_STATIC_DRAW);
glGenBuffers(1, &s.colorBufferID);
glBindBuffer(GL_ARRAY_BUFFER, s.colorBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(tinyobj::real_t) * colors.size(), &colors.front(), GL_STATIC_DRAW);
}
if (!normals.empty()) {
glGenBuffers(1, &s.normalBufferID);
glBindBuffer(GL_ARRAY_BUFFER, s.normalBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(tinyobj::real_t) * normals.size(), &normals.front(), GL_STATIC_DRAW);
}
if (!uvs.empty()) {
glGenBuffers(1, &s.uvBufferID);
glBindBuffer(GL_ARRAY_BUFFER, s.uvBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(tinyobj::real_t) * uvs.size(), &uvs.front(), GL_STATIC_DRAW);
}
s.numVerts = vertices.size() / 3;
renderShapes.push_back(s);
}
didLoad = true;
}
void Draw() override {
if (!didLoad) {
return;
}
for (auto s : renderShapes) {
glBindVertexArray(s.vaoID);
// 1st attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, s.vertexBufferID);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : colors
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, s.colorBufferID);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
if (s.normalBufferID != 0) {
// 3rd attribute buffer : normals
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, s.normalBufferID);
glVertexAttribPointer(
2, // must match the layout in the shader
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
}
if (s.uvBufferID != 0) {
// 4th attribute buffer : uvs
glEnableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, s.normalBufferID);
glVertexAttribPointer(
3, // must match the layout in the shader
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
}
// Shader??
// Draw the triangle!
glDrawArrays(GL_TRIANGLES, 0, s.numVerts); // Starting from vertex 0; 3 vertices total -> 1 triangle
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
if (s.normalBufferID != 0) {
glDisableVertexAttribArray(2);
}
if (s.uvBufferID != 0) {
glDisableVertexAttribArray(3);
}
}
}
};
#endif

View File

@@ -0,0 +1,13 @@
#include <HandmadeMath.h>
#ifndef HMME_RENDER_COMPONENT_H
#define HMME_RENDER_COMPONENT_H
#include "Entity.h"
class RenderComponent {
public:
virtual void Draw() = 0;
};
#endif

28
example/src/debug.h Normal file
View File

@@ -0,0 +1,28 @@
#include <stdio.h>
#ifndef DEBUG_H
#define DEBUG_H
#include "HandmadeMath.h"
void printVec3(hmm_vec3 v) {
printf("%f\t%f\t%f\n", v.X, v.Y, v.Z);
}
void printVec4(hmm_vec4 v) {
printf("%f\t%f\t%f\t%f\n", v.X, v.Y, v.Z, v.W);
}
void printQuaternion(hmm_quaternion q) {
printf("%f\t%f\t%f\t%f\n", q.X, q.Y, q.Z, q.W);
}
void printMat4(hmm_mat4 m) {
printf("/\n");
for (int r = 0; r < 4; r++) {
printf("| %f\t%f\t%f\t%f |\n", m[0][r], m[1][r], m[2][r], m[3][r]);
}
printf("\\\n");
}
#endif

18
example/src/fragment.glsl Normal file
View File

@@ -0,0 +1,18 @@
#version 330 core
in vec3 fragmentPosition_world;
in vec3 fragmentColor;
in vec3 fragmentNormal_world;
in vec2 fragmentUV;
out vec3 color;
void main() {
vec3 ambient = vec3(0.1, 0.1, 0.1);
vec3 toLight_world = normalize(vec3(1, 1, 1));
float cosTheta = clamp(dot(normalize(fragmentNormal_world), toLight_world), 0.1, 1);
color = cosTheta * fragmentColor + ambient;
}

19
example/src/input.h Normal file
View File

@@ -0,0 +1,19 @@
#include <GLFW/glfw3.h>
#ifndef HMME_INPUT_H
#define HMME_INPUT_H
struct Input {
double mouseX;
double mouseY;
};
Input GetInput(GLFWwindow *window) {
Input i;
glfwGetCursorPos(window, &i.mouseX, &i.mouseY);
return i;
}
#endif

190
example/src/main.cpp Normal file
View File

@@ -0,0 +1,190 @@
#include <stdio.h>
#include <chrono>
#include <unistd.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <HandmadeMath.h>
#include "input.h"
#include "shaders.h"
#include "Entity.h"
#include "Cube.h"
#include "MeshRenderComponent.h"
#include "FPSCam.h"
void TickTree(Entity *e, float deltaSeconds, Input previousInput, Input input);
void ComputeModelMatrices(Entity *ep, hmm_mat4 parentModelMatrix);
void HandleMouseMove(GLFWwindow *window, double mouseX, double mouseY);
using std::chrono::high_resolution_clock;
#define WIDTH 1024
#define HEIGHT 768
int main() {
// Initialise GLFW
glewExperimental = true; // Needed for core profile
if (!glfwInit()) {
fprintf( stderr, "Failed to initialize GLFW\n" );
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want OpenGL 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We don't want the old OpenGL
// Open a window and create its OpenGL context
GLFWwindow* window; // (In the accompanying source code, this variable is global for simplicity)
window = glfwCreateWindow(WIDTH, HEIGHT, "Handmade Math Example", NULL, NULL);
if (window == NULL) {
fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window); // Initialize GLEW
glewExperimental=true; // Needed in core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// Hide the mouse cursor
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// glfwSetCursorPos(window, WIDTH / 2, HEIGHT / 2);
// glfwSetCursorPosCallback(window, [](GLFWwindow *window, double mouseX, double mouseY) {
// printf("%f\t%f\n", mouseX, mouseY);
// // glfwSetCursorPos(window, WIDTH / 2, HEIGHT / 2);
// });
// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders("src/vertex.glsl", "src/fragment.glsl");
if (!programID) {
return 1;
}
// Get a handle for our "MVP" uniform
// Only during the initialisation
GLuint uniformID_M = glGetUniformLocation(programID, "M");
GLuint uniformID_V = glGetUniformLocation(programID, "V");
GLuint uniformID_MVP = glGetUniformLocation(programID, "MVP");
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
Cube c1 = Cube();
Entity monkey = Entity();
monkey.position = HMM_Vec3(2.1f, 0.0f, 0.0f);
monkey.renderComponent = new MeshRenderComponent("MonkeySmooth.obj");
Entity backmonkey = Entity();
backmonkey.position = HMM_Vec3(0.0f, 0.0f, 5.0f);
backmonkey.renderComponent = new MeshRenderComponent("MonkeySmooth.obj");
FPSCam fpsCam = FPSCam();
fpsCam.position = HMM_Vec3(-1.0f, 1.0f, 3.0f);
Entity *cam = &fpsCam.cam;
// Cube c = Cube();
// monkey.position = HMM_Vec3(2.1f, 0.0f, 0.0f);
// monkey.AddChild(&c);
c1.AddChild(&monkey);
Entity root = Entity();
root.AddChild(&c1);
root.AddChild(&fpsCam);
root.AddChild(&backmonkey);
Entity axes = Entity();
axes.renderComponent = new MeshRenderComponent("Axes.obj");
root.AddChild(&axes);
bool hasTicked = false;
high_resolution_clock::time_point lastTickTime;
Input previousInput = GetInput(window);
do {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Get inputs
Input input = GetInput(window);
// Tick
auto now = high_resolution_clock::now();
if (hasTicked) {
auto elapsedNanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(now - lastTickTime).count();
float elapsedSeconds = elapsedNanoseconds / 1000000000.0f;
TickTree(&root, elapsedSeconds, previousInput, input);
}
lastTickTime = now;
hasTicked = true;
previousInput = input;
// Compute model positions for rendering
ComputeModelMatrices(&root, HMM_Mat4d(1.0f));
// Render!
hmm_mat4 projection = cam->projectionMatrix();
hmm_mat4 view = cam->viewMatrix();
hmm_mat4 vp = projection * view;
auto it = EntityIterator(&root);
while (it.HasNext()) {
Entity *e = it.Next();
if (e->renderComponent) {
// Use our shader
glUseProgram(programID);
// Send uniforms
glUniformMatrix4fv(uniformID_M, 1, GL_FALSE, &e->modelMatrix.Elements[0][0]);
glUniformMatrix4fv(uniformID_V, 1, GL_FALSE, &view.Elements[0][0]);
hmm_mat4 mvp = vp * e->modelMatrix;
glUniformMatrix4fv(uniformID_MVP, 1, GL_FALSE, &mvp.Elements[0][0]);
e->renderComponent->Draw();
}
}
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} while (
// Check if the ESC key was pressed or the window was closed
glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS
&& glfwWindowShouldClose(window) == 0
);
}
void TickTree(Entity *e, float deltaSeconds, Input previousInput, Input input) {
e->Tick(deltaSeconds, previousInput, input);
for (auto child : e->children) {
TickTree(child, deltaSeconds, previousInput, input);
}
}
void ComputeModelMatrices(Entity *e, hmm_mat4 parentModelMatrix) {
e->parentModelMatrix = parentModelMatrix;
e->modelMatrix = parentModelMatrix * HMM_Translate(e->position) * HMM_QuaternionToMat4(e->rotation) * HMM_Scale(e->scale);
for (int i = 0; i < e->children.size(); i++) {
ComputeModelMatrices(e->children[i], e->modelMatrix);
}
}

94
example/src/shaders.cpp Normal file
View File

@@ -0,0 +1,94 @@
#include <stdio.h>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include "shaders.h"
GLuint LoadShaders(const char * vertex_file_path, const char * fragment_file_path) {
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open()){
std::stringstream sstr;
sstr << VertexShaderStream.rdbuf();
VertexShaderCode = sstr.str();
VertexShaderStream.close();
}else{
printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path);
return 0;
}
// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if(FragmentShaderStream.is_open()){
std::stringstream sstr;
sstr << FragmentShaderStream.rdbuf();
FragmentShaderCode = sstr.str();
FragmentShaderStream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);
}
// Compile Fragment Shader
printf("Compiling shader : %s\n", fragment_file_path);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);
}
// Link the program
printf("Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> ProgramErrorMessage(InfoLogLength+1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);
}
glDetachShader(ProgramID, VertexShaderID);
glDetachShader(ProgramID, FragmentShaderID);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}

9
example/src/shaders.h Normal file
View File

@@ -0,0 +1,9 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#ifndef HMME_SHADERS_H
#define HMME_SHADERS_H
GLuint LoadShaders(const char * vertex_file_path, const char * fragment_file_path);
#endif

View File

@@ -0,0 +1,2 @@
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"

File diff suppressed because it is too large Load Diff

28
example/src/vertex.glsl Normal file
View File

@@ -0,0 +1,28 @@
#version 330 core
// These match the values in glVertexAttribPointer
layout(location = 0) in vec3 vertexPosition_model;
layout(location = 1) in vec3 vertexColor;
layout(location = 2) in vec3 vertexNormal_model;
layout(location = 3) in vec2 vertexUV;
uniform mat4 M;
uniform mat4 V;
uniform mat4 MVP;
out vec3 fragmentPosition_world;
out vec3 fragmentColor;
out vec3 fragmentNormal_world;
out vec2 fragmentUV;
void main(){
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_model, 1);
fragmentPosition_world = (M * vec4(vertexPosition_model, 1)).xyz;
fragmentColor = vertexColor;
fragmentNormal_world = (M * vec4(vertexNormal_model, 0)).xyz;
fragmentUV = vertexUV;
}

View File

@@ -1,4 +1,3 @@
#define HANDMADE_MATH_IMPLEMENTATION #define HANDMADE_MATH_IMPLEMENTATION
#define HANDMADE_MATH_NO_INLINE #define HANDMADE_MATH_NO_INLINE
#include "../HandmadeMath.h" #include "../HandmadeMath.h"

View File

@@ -1,5 +1,2 @@
#include "HandmadeMath.c"
#define HANDMADE_MATH_IMPLEMENTATION // C++ compilers complain when compiling a .c file...
#define HANDMADE_MATH_CPP_MODE
#define HANDMADE_MATH_NO_INLINE
#include "../HandmadeMath.h"

View File

@@ -1,80 +1,263 @@
/*
HandmadeTest.h
This is Handmade Math's test framework. It is fully compatible with both C
and C++, although it requires some compiler-specific features.
The basic way of creating a test is using the TEST macro, which registers a
single test to be run:
TEST(MyCategory, MyTestName) {
// test code, including asserts/expects
}
The main function of your test code should then call hmt_run_all_tests and
return the result:
int main() {
return hmt_run_all_tests();
}
=============================================================================
If Handmade Test's macros are conflicting with existing macros in your
project, you may define HMT_SAFE_MACROS before you include HandmadeTest.h.
You may then prefix each macro with HMT_. For example, you may use HMT_TEST
instead of TEST and HMT_EXPECT_TRUE instead of EXPECT_TRUE.
*/
#ifndef HANDMADETEST_H #ifndef HANDMADETEST_H
#define HANDMADETEST_H #define HANDMADETEST_H
#include <float.h> #include <float.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
int hmt_count_tests = 0; #include "initializer.h"
int hmt_count_failedtests = 0;
int hmt_count_failures = 0;
#define RESET "\033[0m" #define HMT_RESET "\033[0m"
#define RED "\033[31m" #define HMT_RED "\033[31m"
#define GREEN "\033[32m" #define HMT_GREEN "\033[32m"
#define CATEGORY_BEGIN(name) { \ #define HMT_INITIAL_ARRAY_SIZE 1024
int count_categorytests = 0; \
int count_categoryfailedtests = 0; \ typedef struct hmt_testresult_struct {
int count_categoryfailures = 0; \ int count_cases;
printf("\n" #name ":\n"); int count_failures;
#define CATEGORY_END(name) \ } hmt_testresult;
hmt_count_tests += count_categorytests; \
hmt_count_failedtests += count_categoryfailedtests; \ typedef void (*hmt_test_func)(hmt_testresult*);
hmt_count_failures += count_categoryfailures; \
printf("%d/%d tests passed, %d failures\n", count_categorytests - count_categoryfailedtests, count_categorytests, count_categoryfailures); \ typedef struct hmt_test_struct {
const char* name;
hmt_test_func func;
} hmt_test;
typedef struct hmt_category_struct {
const char* name;
int num_tests;
int tests_capacity;
hmt_test* tests;
} hmt_category;
int hmt_num_categories = 0;
int hmt_category_capacity = HMT_INITIAL_ARRAY_SIZE;
hmt_category* categories = 0;
hmt_category _hmt_new_category(const char* name) {
hmt_category cat = {
.name = name,
.num_tests = 0,
.tests_capacity = HMT_INITIAL_ARRAY_SIZE,
.tests = (hmt_test*) malloc(HMT_INITIAL_ARRAY_SIZE * sizeof(hmt_test))
};
return cat;
} }
#define TEST_BEGIN(name) { \ hmt_test _hmt_new_test(const char* name, hmt_test_func func) {
int count_testfailures = 0; \ hmt_test test = {
count_categorytests++; \ .name = name,
printf(" " #name ":"); .func = func
#define TEST_END() \ };
count_categoryfailures += count_testfailures; \
if (count_testfailures > 0) { \ return test;
count_categoryfailedtests++; \
printf("\n"); \
} else { \
printf(GREEN " [PASS]\n" RESET); \
} \
} }
#define CASE_FAIL() \ int hmt_register_test(const char* category, const char* name, hmt_test_func func) {
count_testfailures++; \ // initialize categories array if not initialized
printf("\n - " RED "[FAIL] (%d) " RESET, __LINE__) if (!categories) {
categories = (hmt_category*) malloc(hmt_category_capacity * sizeof(hmt_category));
}
// Find the matching category, if possible
int cat_index;
for (cat_index = 0; cat_index < hmt_num_categories; cat_index++) {
if (strcmp(categories[cat_index].name, category) == 0) {
break;
}
}
// Expand the array of categories if necessary
if (cat_index >= hmt_category_capacity) {
// TODO: If/when we ever split HandmadeTest off into its own package,
// we should start with a smaller initial capacity and dynamically expand.
}
// Add a new category if necessary
if (cat_index >= hmt_num_categories) {
categories[cat_index] = _hmt_new_category(category);
hmt_num_categories++;
}
hmt_category* cat = &categories[cat_index];
// Add the test to the category
if (cat->num_tests >= cat->tests_capacity) {
// TODO: If/when we ever split HandmadeTest off into its own package,
// we should start with a smaller initial capacity and dynamically expand.
}
cat->tests[cat->num_tests] = _hmt_new_test(name, func);
cat->num_tests++;
return 0;
}
int hmt_run_all_tests() {
int count_alltests = 0;
int count_allfailedtests = 0; // failed test cases
int count_allfailures = 0; // failed asserts
for (int i = 0; i < hmt_num_categories; i++) {
hmt_category cat = categories[i];
int count_catfailedtests = 0;
int count_catfailures = 0;
printf("\n%s:\n", cat.name);
for (int j = 0; j < cat.num_tests; j++) {
hmt_test test = cat.tests[j];
printf(" %s:", test.name);
hmt_testresult result = {
.count_cases = 0,
.count_failures = 0
};
test.func(&result);
count_catfailures += result.count_failures;
if (result.count_failures > 0) {
count_catfailedtests++;
printf("\n " HMT_RED "(%d/%d passed)" HMT_RESET, result.count_cases - result.count_failures, result.count_cases);
printf("\n");
} else {
printf(HMT_GREEN " [PASS] (%d/%d passed) \n" HMT_RESET, result.count_cases - result.count_failures, result.count_cases);
}
}
count_alltests += cat.num_tests;
count_allfailedtests += count_catfailedtests;
count_allfailures += count_catfailures;
printf("%d/%d tests passed, %d failures\n", cat.num_tests - count_catfailedtests, cat.num_tests, count_catfailures);
}
if (count_allfailedtests > 0) {
printf(HMT_RED);
} else {
printf(HMT_GREEN);
}
printf("\n%d/%d tests passed overall, %d failures\n" HMT_RESET, count_alltests - count_allfailedtests, count_alltests, count_allfailures);
printf("\n");
return (count_allfailedtests > 0);
}
#define _HMT_TEST_FUNCNAME(category, name) category ## _ ## name
#define _HMT_TEST_FUNCNAME_INIT(category, name) category ## _ ## name ## _init
#define HMT_TEST(category, name) \
void _HMT_TEST_FUNCNAME(category, name)(hmt_testresult* _result); \
INITIALIZER(_HMT_TEST_FUNCNAME_INIT(category, name)) { \
hmt_register_test(#category, #name, _HMT_TEST_FUNCNAME(category, name)); \
} \
void _HMT_TEST_FUNCNAME(category, name)(hmt_testresult* _result)
#define _HMT_CASE_START() \
_result->count_cases++;
#define _HMT_CASE_FAIL() \
_result->count_failures++; \
printf("\n - " HMT_RED "[FAIL] (%d) " HMT_RESET, __LINE__);
/* /*
* Asserts and expects * Asserts and expects
*/ */
#define EXPECT_FLOAT_EQ(_actual, _expected) do { \ #define HMT_EXPECT_TRUE(_actual) do { \
_HMT_CASE_START(); \
if (!(_actual)) { \
_HMT_CASE_FAIL(); \
printf("Expected true but got something false"); \
} \
} while (0)
#define HMT_EXPECT_FALSE(_actual) do { \
_HMT_CASE_START(); \
if (_actual) { \
_HMT_CASE_FAIL(); \
printf("Expected false but got something true"); \
} \
} while (0)
#define HMT_EXPECT_FLOAT_EQ(_actual, _expected) do { \
_HMT_CASE_START(); \
float actual = (_actual); \ float actual = (_actual); \
float diff = actual - (_expected); \ float diff = actual - (_expected); \
if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \ if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \
CASE_FAIL(); \ _HMT_CASE_FAIL(); \
printf("Expected %f, got %f", (_expected), actual); \ printf("Expected %f, got %f", (_expected), actual); \
} \ } \
} while (0) } while (0)
#define EXPECT_NEAR(_actual, _expected, _epsilon) do { \ #define HMT_EXPECT_NEAR(_actual, _expected, _epsilon) do { \
_HMT_CASE_START(); \
float actual = (_actual); \ float actual = (_actual); \
float diff = actual - (_expected); \ float diff = actual - (_expected); \
if (diff < -(_epsilon) || (_epsilon) < diff) { \ if (diff < -(_epsilon) || (_epsilon) < diff) { \
CASE_FAIL(); \ _HMT_CASE_FAIL(); \
printf("Expected %f, got %f", (_expected), actual); \ printf("Expected %f, got %f", (_expected), actual); \
} \ } \
} while (0) } while (0)
#define EXPECT_LT(_actual, _expected) do { \ #define HMT_EXPECT_LT(_actual, _expected) do { \
_HMT_CASE_START(); \
if ((_actual) >= (_expected)) { \ if ((_actual) >= (_expected)) { \
CASE_FAIL(); \ _HMT_CASE_FAIL(); \
printf("Expected %f to be less than %f", (_actual), (_expected)); \ printf("Expected %f to be less than %f", (_actual), (_expected)); \
} \ } \
} while (0) } while (0)
#define EXPECT_GT(_actual, _expected) do { \ #define HMT_EXPECT_GT(_actual, _expected) do { \
_HMT_CASE_START(); \
if ((_actual) <= (_expected)) { \ if ((_actual) <= (_expected)) { \
CASE_FAIL(); \ _HMT_CASE_FAIL(); \
printf("Expected %f to be greater than %f", (_actual), (_expected)); \ printf("Expected %f to be greater than %f", (_actual), (_expected)); \
} \ } \
} while (0) } while (0)
#endif #ifndef HMT_SAFE_MACROS
// Friendly defines
#define TEST(category, name) HMT_TEST(category, name)
#define EXPECT_TRUE(_actual) HMT_EXPECT_TRUE(_actual)
#define EXPECT_FALSE(_actual) HMT_EXPECT_FALSE(_actual)
#define EXPECT_FLOAT_EQ(_actual, _expected) HMT_EXPECT_FLOAT_EQ(_actual, _expected)
#define EXPECT_NEAR(_actual, _expected, _epsilon) HMT_EXPECT_NEAR(_actual, _expected, _epsilon)
#define EXPECT_LT(_actual, _expected) HMT_EXPECT_LT(_actual, _expected)
#define EXPECT_GT(_actual, _expected) HMT_EXPECT_GT(_actual, _expected)
#endif // HMT_SAFE_MACROS
#endif // HANDMADETEST_H

View File

@@ -1,17 +1,45 @@
ROOT_DIR = .. BUILD_DIR=build
CXXFLAGS += -g -Wall -Wextra -pthread -Wno-missing-braces -Wno-missing-field-initializers CXXFLAGS+=-g -Wall -Wextra -pthread -Wno-missing-braces -Wno-missing-field-initializers
all: c cpp all: c c_no_sse cpp cpp_no_sse
clean: clean:
rm -f hmm_test_c hmm_test_cpp *.o rm -rf $(BUILD_DIR)
c: $(ROOT_DIR)/test/HandmadeMath.c test_impl c: HandmadeMath.c test_impl
$(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 -c $(ROOT_DIR)/test/HandmadeMath.c $(ROOT_DIR)/test/hmm_test.c -lm @echo "\nCompiling in C mode"
$(CC) -ohmm_test_c HandmadeMath.o hmm_test.o -lm mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR)\
&& $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 \
-c ../HandmadeMath.c ../hmm_test.c \
-lm \
&& $(CC) -ohmm_test_c HandmadeMath.o hmm_test.o -lm
cpp: $(ROOT_DIR)/test/HandmadeMath.cpp test_impl c_no_sse: HandmadeMath.c test_impl
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -ohmm_test_cpp $(ROOT_DIR)/test/HandmadeMath.cpp $(ROOT_DIR)/test/hmm_test.cpp @echo "\nCompiling in C mode (no SSE)"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 \
-DHANDMADE_MATH_NO_SSE \
-c ../HandmadeMath.c ../hmm_test.c \
-lm \
&& $(CC) -ohmm_test_c_no_sse HandmadeMath.o hmm_test.o -lm
test_impl: $(ROOT_DIR)/test/hmm_test.cpp $(ROOT_DIR)/test/hmm_test.c cpp: HandmadeMath.cpp test_impl
@echo "\nCompiling in C++ mode"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -ohmm_test_cpp \
-DHANDMADE_MATH_CPP_MODE \
../HandmadeMath.cpp ../hmm_test.cpp
cpp_no_sse: HandmadeMath.cpp test_impl
@echo "\nCompiling in C++ mode (no SSE)"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -ohmm_test_cpp_no_sse \
-DHANDMADE_MATH_CPP_MODE -DHANDMADE_MATH_NO_SSE \
../HandmadeMath.cpp ../hmm_test.cpp
test_impl: hmm_test.cpp hmm_test.c

11
test/README.md Normal file
View File

@@ -0,0 +1,11 @@
# Testing
You can compile and run the tests yourself by running:
```
make
build/hmm_test_c
build/hmm_test_c_no_sse
build/hmm_test_cpp
build/hmm_test_cpp_no_sse
```

209
test/categories/Addition.h Normal file
View File

@@ -0,0 +1,209 @@
#include "../HandmadeTest.h"
TEST(Addition, Vec2)
{
hmm_vec2 v2_1 = HMM_Vec2(1.0f, 2.0f);
hmm_vec2 v2_2 = HMM_Vec2(3.0f, 4.0f);
{
hmm_vec2 result = HMM_AddVec2(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, 4.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
}
#ifdef __cplusplus
{
hmm_vec2 result = HMM_Add(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, 4.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
}
{
hmm_vec2 result = v2_1 + v2_2;
EXPECT_FLOAT_EQ(result.X, 4.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
}
v2_1 += v2_2;
EXPECT_FLOAT_EQ(v2_1.X, 4.0f);
EXPECT_FLOAT_EQ(v2_1.Y, 6.0f);
#endif
}
TEST(Addition, Vec3)
{
hmm_vec3 v3_1 = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 v3_2 = HMM_Vec3(4.0f, 5.0f, 6.0f);
{
hmm_vec3 result = HMM_AddVec3(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, 5.0f);
EXPECT_FLOAT_EQ(result.Y, 7.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
}
#ifdef __cplusplus
{
hmm_vec3 result = HMM_Add(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, 5.0f);
EXPECT_FLOAT_EQ(result.Y, 7.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
}
{
hmm_vec3 result = v3_1 + v3_2;
EXPECT_FLOAT_EQ(result.X, 5.0f);
EXPECT_FLOAT_EQ(result.Y, 7.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
}
v3_1 += v3_2;
EXPECT_FLOAT_EQ(v3_1.X, 5.0f);
EXPECT_FLOAT_EQ(v3_1.Y, 7.0f);
EXPECT_FLOAT_EQ(v3_1.Z, 9.0f);
#endif
}
TEST(Addition, Vec4)
{
hmm_vec4 v4_1 = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
hmm_vec4 v4_2 = HMM_Vec4(5.0f, 6.0f, 7.0f, 8.0f);
{
hmm_vec4 result = HMM_AddVec4(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, 6.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f);
}
#ifdef __cplusplus
{
hmm_vec4 result = HMM_Add(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, 6.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f);
}
{
hmm_vec4 result = v4_1 + v4_2;
EXPECT_FLOAT_EQ(result.X, 6.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f);
}
v4_1 += v4_2;
EXPECT_FLOAT_EQ(v4_1.X, 6.0f);
EXPECT_FLOAT_EQ(v4_1.Y, 8.0f);
EXPECT_FLOAT_EQ(v4_1.Z, 10.0f);
EXPECT_FLOAT_EQ(v4_1.W, 12.0f);
#endif
}
TEST(Addition, Mat4)
{
hmm_mat4 m4_1 = HMM_Mat4(); // will have 1 - 16
hmm_mat4 m4_2 = HMM_Mat4(); // will have 17 - 32
// Fill the matrices
int Counter = 1;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
m4_1.Elements[Column][Row] = Counter;
++Counter;
}
}
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
m4_2.Elements[Column][Row] = Counter;
++Counter;
}
}
// Test the results
{
hmm_mat4 result = HMM_AddMat4(m4_1, m4_2);
float Expected = 18.0f;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
EXPECT_FLOAT_EQ(result.Elements[Column][Row], Expected);
Expected += 2.0f;
}
}
}
#ifdef __cplusplus
{
hmm_mat4 result = HMM_Add(m4_1, m4_2);
float Expected = 18.0f;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
EXPECT_FLOAT_EQ(result.Elements[Column][Row], Expected);
Expected += 2.0f;
}
}
}
{
hmm_mat4 result = m4_1 + m4_2;
float Expected = 18.0f;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
EXPECT_FLOAT_EQ(result.Elements[Column][Row], Expected);
Expected += 2.0f;
}
}
}
m4_1 += m4_2;
float Expected = 18.0f;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
EXPECT_FLOAT_EQ(m4_1.Elements[Column][Row], Expected);
Expected += 2.0f;
}
}
#endif
}
TEST(Addition, Quaternion)
{
hmm_quaternion q1 = HMM_Quaternion(1.0f, 2.0f, 3.0f, 4.0f);
hmm_quaternion q2 = HMM_Quaternion(5.0f, 6.0f, 7.0f, 8.0f);
{
hmm_quaternion result = HMM_AddQuaternion(q1, q2);
EXPECT_FLOAT_EQ(result.X, 6.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f);
}
#ifdef __cplusplus
{
hmm_quaternion result = HMM_Add(q1, q2);
EXPECT_FLOAT_EQ(result.X, 6.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f);
}
{
hmm_quaternion result = q1 + q2;
EXPECT_FLOAT_EQ(result.X, 6.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f);
}
q1 += q2;
EXPECT_FLOAT_EQ(q1.X, 6.0f);
EXPECT_FLOAT_EQ(q1.Y, 8.0f);
EXPECT_FLOAT_EQ(q1.Z, 10.0f);
EXPECT_FLOAT_EQ(q1.W, 12.0f);
#endif
}

325
test/categories/Division.h Normal file
View File

@@ -0,0 +1,325 @@
#include "../HandmadeTest.h"
TEST(Division, Vec2Vec2)
{
hmm_vec2 v2_1 = HMM_Vec2(1.0f, 3.0f);
hmm_vec2 v2_2 = HMM_Vec2(2.0f, 4.0f);
{
hmm_vec2 result = HMM_DivideVec2(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f);
}
#ifdef __cplusplus
{
hmm_vec2 result = HMM_Divide(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f);
}
{
hmm_vec2 result = v2_1 / v2_2;
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f);
}
v2_1 /= v2_2;
EXPECT_FLOAT_EQ(v2_1.X, 0.5f);
EXPECT_FLOAT_EQ(v2_1.Y, 0.75f);
#endif
}
TEST(Division, Vec2Scalar)
{
hmm_vec2 v2 = HMM_Vec2(1.0f, 2.0f);
float s = 2;
{
hmm_vec2 result = HMM_DivideVec2f(v2, s);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
}
#ifdef __cplusplus
{
hmm_vec2 result = HMM_Divide(v2, s);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
}
{
hmm_vec2 result = v2 / s;
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
}
v2 /= s;
EXPECT_FLOAT_EQ(v2.X, 0.5f);
EXPECT_FLOAT_EQ(v2.Y, 1.0f);
#endif
}
TEST(Division, Vec3Vec3)
{
hmm_vec3 v3_1 = HMM_Vec3(1.0f, 3.0f, 5.0f);
hmm_vec3 v3_2 = HMM_Vec3(2.0f, 4.0f, 0.5f);
{
hmm_vec3 result = HMM_DivideVec3(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
}
#ifdef __cplusplus
{
hmm_vec3 result = HMM_Divide(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
}
{
hmm_vec3 result = v3_1 / v3_2;
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
}
v3_1 /= v3_2;
EXPECT_FLOAT_EQ(v3_1.X, 0.5f);
EXPECT_FLOAT_EQ(v3_1.Y, 0.75f);
EXPECT_FLOAT_EQ(v3_1.Z, 10.0f);
#endif
}
TEST(Division, Vec3Scalar)
{
hmm_vec3 v3 = HMM_Vec3(1.0f, 2.0f, 3.0f);
float s = 2;
{
hmm_vec3 result = HMM_DivideVec3f(v3, s);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f);
}
#ifdef __cplusplus
{
hmm_vec3 result = HMM_Divide(v3, s);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f);
}
{
hmm_vec3 result = v3 / s;
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f);
}
v3 /= s;
EXPECT_FLOAT_EQ(v3.X, 0.5f);
EXPECT_FLOAT_EQ(v3.Y, 1.0f);
EXPECT_FLOAT_EQ(v3.Z, 1.5f);
#endif
}
TEST(Division, Vec4Vec4)
{
hmm_vec4 v4_1 = HMM_Vec4(1.0f, 3.0f, 5.0f, 1.0f);
hmm_vec4 v4_2 = HMM_Vec4(2.0f, 4.0f, 0.5f, 4.0f);
{
hmm_vec4 result = HMM_DivideVec4(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 0.25f);
}
#ifdef __cplusplus
{
hmm_vec4 result = HMM_Divide(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 0.25f);
}
{
hmm_vec4 result = v4_1 / v4_2;
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f);
EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 0.25f);
}
v4_1 /= v4_2;
EXPECT_FLOAT_EQ(v4_1.X, 0.5f);
EXPECT_FLOAT_EQ(v4_1.Y, 0.75f);
EXPECT_FLOAT_EQ(v4_1.Z, 10.0f);
EXPECT_FLOAT_EQ(v4_1.W, 0.25f);
#endif
}
TEST(Division, Vec4Scalar)
{
hmm_vec4 v4 = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
float s = 2;
{
hmm_vec4 result = HMM_DivideVec4f(v4, s);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f);
EXPECT_FLOAT_EQ(result.W, 2.0f);
}
#ifdef __cplusplus
{
hmm_vec4 result = HMM_Divide(v4, s);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f);
EXPECT_FLOAT_EQ(result.W, 2.0f);
}
{
hmm_vec4 result = v4 / s;
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f);
EXPECT_FLOAT_EQ(result.W, 2.0f);
}
v4 /= s;
EXPECT_FLOAT_EQ(v4.X, 0.5f);
EXPECT_FLOAT_EQ(v4.Y, 1.0f);
EXPECT_FLOAT_EQ(v4.Z, 1.5f);
EXPECT_FLOAT_EQ(v4.W, 2.0f);
#endif
}
TEST(Division, Mat4Scalar)
{
hmm_mat4 m4 = HMM_Mat4(); // will have 1 - 16
float s = 2;
// Fill the matrix
int Counter = 1;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
m4.Elements[Column][Row] = Counter;
++Counter;
}
}
// Test the results
{
hmm_mat4 result = HMM_DivideMat4f(m4, s);
EXPECT_FLOAT_EQ(result.Elements[0][0], 0.5f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 1.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 1.5f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 2.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 2.5f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 3.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 3.5f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 4.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 4.5f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 5.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 5.5f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 6.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 6.5f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 7.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 7.5f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 8.0f);
}
#ifdef __cplusplus
{
hmm_mat4 result = HMM_Divide(m4, s);
EXPECT_FLOAT_EQ(result.Elements[0][0], 0.5f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 1.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 1.5f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 2.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 2.5f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 3.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 3.5f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 4.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 4.5f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 5.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 5.5f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 6.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 6.5f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 7.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 7.5f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 8.0f);
}
{
hmm_mat4 result = m4 / s;
EXPECT_FLOAT_EQ(result.Elements[0][0], 0.5f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 1.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 1.5f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 2.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 2.5f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 3.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 3.5f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 4.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 4.5f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 5.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 5.5f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 6.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 6.5f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 7.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 7.5f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 8.0f);
}
m4 /= s;
EXPECT_FLOAT_EQ(m4.Elements[0][0], 0.5f);
EXPECT_FLOAT_EQ(m4.Elements[0][1], 1.0f);
EXPECT_FLOAT_EQ(m4.Elements[0][2], 1.5f);
EXPECT_FLOAT_EQ(m4.Elements[0][3], 2.0f);
EXPECT_FLOAT_EQ(m4.Elements[1][0], 2.5f);
EXPECT_FLOAT_EQ(m4.Elements[1][1], 3.0f);
EXPECT_FLOAT_EQ(m4.Elements[1][2], 3.5f);
EXPECT_FLOAT_EQ(m4.Elements[1][3], 4.0f);
EXPECT_FLOAT_EQ(m4.Elements[2][0], 4.5f);
EXPECT_FLOAT_EQ(m4.Elements[2][1], 5.0f);
EXPECT_FLOAT_EQ(m4.Elements[2][2], 5.5f);
EXPECT_FLOAT_EQ(m4.Elements[2][3], 6.0f);
EXPECT_FLOAT_EQ(m4.Elements[3][0], 6.5f);
EXPECT_FLOAT_EQ(m4.Elements[3][1], 7.0f);
EXPECT_FLOAT_EQ(m4.Elements[3][2], 7.5f);
EXPECT_FLOAT_EQ(m4.Elements[3][3], 8.0f);
#endif
}
TEST(Division, QuaternionScalar)
{
hmm_quaternion q = HMM_Quaternion(1.0f, 2.0f, 3.0f, 4.0f);
float f = 2.0f;
{
hmm_quaternion result = HMM_DivideQuaternionF(q, f);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f);
EXPECT_FLOAT_EQ(result.W, 2.0f);
}
#ifdef __cplusplus
{
hmm_quaternion result = HMM_Divide(q, f);
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f);
EXPECT_FLOAT_EQ(result.W, 2.0f);
}
{
hmm_quaternion result = q / f;
EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f);
EXPECT_FLOAT_EQ(result.W, 2.0f);
}
q /= f;
EXPECT_FLOAT_EQ(q.X, 0.5f);
EXPECT_FLOAT_EQ(q.Y, 1.0f);
EXPECT_FLOAT_EQ(q.Z, 1.5f);
EXPECT_FLOAT_EQ(q.W, 2.0f);
#endif
}

View File

@@ -0,0 +1,55 @@
#include "../HandmadeTest.h"
TEST(Equality, Vec2)
{
hmm_vec2 a = HMM_Vec2(1.0f, 2.0f);
hmm_vec2 b = HMM_Vec2(1.0f, 2.0f);
hmm_vec2 c = HMM_Vec2(3.0f, 4.0f);
EXPECT_TRUE(HMM_EqualsVec2(a, b));
EXPECT_FALSE(HMM_EqualsVec2(a, c));
#ifdef __cplusplus
EXPECT_TRUE(HMM_Equals(a, b));
EXPECT_FALSE(HMM_Equals(a, c));
EXPECT_TRUE(a == b);
EXPECT_FALSE(a == c);
#endif
}
TEST(Equality, Vec3)
{
hmm_vec3 a = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 b = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 c = HMM_Vec3(4.0f, 5.0f, 6.0f);
EXPECT_TRUE(HMM_EqualsVec3(a, b));
EXPECT_FALSE(HMM_EqualsVec3(a, c));
#ifdef __cplusplus
EXPECT_TRUE(HMM_Equals(a, b));
EXPECT_FALSE(HMM_Equals(a, c));
EXPECT_TRUE(a == b);
EXPECT_FALSE(a == c);
#endif
}
TEST(Equality, Vec4)
{
hmm_vec4 a = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
hmm_vec4 b = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
hmm_vec4 c = HMM_Vec4(5.0f, 6.0f, 7.0f, 8.0f);
EXPECT_TRUE(HMM_EqualsVec4(a, b));
EXPECT_FALSE(HMM_EqualsVec4(a, c));
#ifdef __cplusplus
EXPECT_TRUE(HMM_Equals(a, b));
EXPECT_FALSE(HMM_Equals(a, c));
EXPECT_TRUE(a == b);
EXPECT_FALSE(a == c);
#endif
}

View File

@@ -0,0 +1,246 @@
#include "../HandmadeTest.h"
TEST(Initialization, Vectors)
{
//
// Test vec2
//
hmm_vec2 v2 = HMM_Vec2(1.0f, 2.0f);
hmm_vec2 v2i = HMM_Vec2(1, 2);
EXPECT_FLOAT_EQ(v2.X, 1.0f);
EXPECT_FLOAT_EQ(v2.Y, 2.0f);
EXPECT_FLOAT_EQ(v2.U, 1.0f);
EXPECT_FLOAT_EQ(v2.V, 2.0f);
EXPECT_FLOAT_EQ(v2.Left, 1.0f);
EXPECT_FLOAT_EQ(v2.Right, 2.0f);
EXPECT_FLOAT_EQ(v2.Width, 1.0f);
EXPECT_FLOAT_EQ(v2.Height, 2.0f);
EXPECT_FLOAT_EQ(v2.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v2.Elements[1], 2.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(v2[0], 1.0f);
EXPECT_FLOAT_EQ(v2[1], 2.0f);
#endif
EXPECT_FLOAT_EQ(v2i.X, 1.0f);
EXPECT_FLOAT_EQ(v2i.Y, 2.0f);
EXPECT_FLOAT_EQ(v2i.U, 1.0f);
EXPECT_FLOAT_EQ(v2i.V, 2.0f);
EXPECT_FLOAT_EQ(v2i.Left, 1.0f);
EXPECT_FLOAT_EQ(v2i.Right, 2.0f);
EXPECT_FLOAT_EQ(v2i.Width, 1.0f);
EXPECT_FLOAT_EQ(v2i.Height, 2.0f);
EXPECT_FLOAT_EQ(v2i.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v2i.Elements[1], 2.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(v2i[0], 1.0f);
EXPECT_FLOAT_EQ(v2i[1], 2.0f);
#endif
//
// Test vec3
//
hmm_vec3 v3 = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 v3i = HMM_Vec3i(1, 2, 3);
EXPECT_FLOAT_EQ(v3.X, 1.0f);
EXPECT_FLOAT_EQ(v3.Y, 2.0f);
EXPECT_FLOAT_EQ(v3.Z, 3.0f);
EXPECT_FLOAT_EQ(v3.U, 1.0f);
EXPECT_FLOAT_EQ(v3.V, 2.0f);
EXPECT_FLOAT_EQ(v3.W, 3.0f);
EXPECT_FLOAT_EQ(v3.R, 1.0f);
EXPECT_FLOAT_EQ(v3.G, 2.0f);
EXPECT_FLOAT_EQ(v3.B, 3.0f);
EXPECT_FLOAT_EQ(v3.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v3.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v3.Elements[2], 3.0f);
EXPECT_FLOAT_EQ(v3.XY.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v3.XY.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v3.YZ.Elements[0], 2.0f);
EXPECT_FLOAT_EQ(v3.YZ.Elements[1], 3.0f);
EXPECT_FLOAT_EQ(v3.UV.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v3.UV.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v3.VW.Elements[0], 2.0f);
EXPECT_FLOAT_EQ(v3.VW.Elements[1], 3.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(v3[0], 1.0f);
EXPECT_FLOAT_EQ(v3[1], 2.0f);
EXPECT_FLOAT_EQ(v3[2], 3.0f);
#endif
EXPECT_FLOAT_EQ(v3i.X, 1.0f);
EXPECT_FLOAT_EQ(v3i.Y, 2.0f);
EXPECT_FLOAT_EQ(v3i.Z, 3.0f);
EXPECT_FLOAT_EQ(v3i.U, 1.0f);
EXPECT_FLOAT_EQ(v3i.V, 2.0f);
EXPECT_FLOAT_EQ(v3i.W, 3.0f);
EXPECT_FLOAT_EQ(v3i.R, 1.0f);
EXPECT_FLOAT_EQ(v3i.G, 2.0f);
EXPECT_FLOAT_EQ(v3i.B, 3.0f);
EXPECT_FLOAT_EQ(v3i.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v3i.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v3i.Elements[2], 3.0f);
EXPECT_FLOAT_EQ(v3i.XY.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v3i.XY.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v3i.YZ.Elements[0], 2.0f);
EXPECT_FLOAT_EQ(v3i.YZ.Elements[1], 3.0f);
EXPECT_FLOAT_EQ(v3i.UV.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v3i.UV.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v3i.VW.Elements[0], 2.0f);
EXPECT_FLOAT_EQ(v3i.VW.Elements[1], 3.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(v3i[0], 1.0f);
EXPECT_FLOAT_EQ(v3i[1], 2.0f);
EXPECT_FLOAT_EQ(v3i[2], 3.0f);
#endif
//
// Test vec4
//
hmm_vec4 v4 = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
hmm_vec4 v4i = HMM_Vec4i(1, 2, 3, 4);
hmm_vec4 v4v = HMM_Vec4v(v3, 4.0f);
EXPECT_FLOAT_EQ(v4.X, 1.0f);
EXPECT_FLOAT_EQ(v4.Y, 2.0f);
EXPECT_FLOAT_EQ(v4.Z, 3.0f);
EXPECT_FLOAT_EQ(v4.W, 4.0f);
EXPECT_FLOAT_EQ(v4.R, 1.0f);
EXPECT_FLOAT_EQ(v4.G, 2.0f);
EXPECT_FLOAT_EQ(v4.B, 3.0f);
EXPECT_FLOAT_EQ(v4.A, 4.0f);
EXPECT_FLOAT_EQ(v4.XY.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4.XY.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4.YZ.Elements[0], 2.0f);
EXPECT_FLOAT_EQ(v4.YZ.Elements[1], 3.0f);
EXPECT_FLOAT_EQ(v4.ZW.Elements[0], 3.0f);
EXPECT_FLOAT_EQ(v4.ZW.Elements[1], 4.0f);
EXPECT_FLOAT_EQ(v4.XY.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4.XY.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4.XYZ.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4.XYZ.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4.XYZ.Elements[2], 3.0f);
EXPECT_FLOAT_EQ(v4.RGB.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4.RGB.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4.RGB.Elements[2], 3.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(v4[0], 1.0f);
EXPECT_FLOAT_EQ(v4[1], 2.0f);
EXPECT_FLOAT_EQ(v4[2], 3.0f);
EXPECT_FLOAT_EQ(v4[3], 4.0f);
#endif
EXPECT_FLOAT_EQ(v4i.X, 1.0f);
EXPECT_FLOAT_EQ(v4i.Y, 2.0f);
EXPECT_FLOAT_EQ(v4i.Z, 3.0f);
EXPECT_FLOAT_EQ(v4i.W, 4.0f);
EXPECT_FLOAT_EQ(v4i.R, 1.0f);
EXPECT_FLOAT_EQ(v4i.G, 2.0f);
EXPECT_FLOAT_EQ(v4i.B, 3.0f);
EXPECT_FLOAT_EQ(v4i.A, 4.0f);
EXPECT_FLOAT_EQ(v4i.XY.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4i.XY.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4i.YZ.Elements[0], 2.0f);
EXPECT_FLOAT_EQ(v4i.YZ.Elements[1], 3.0f);
EXPECT_FLOAT_EQ(v4i.ZW.Elements[0], 3.0f);
EXPECT_FLOAT_EQ(v4i.ZW.Elements[1], 4.0f);
EXPECT_FLOAT_EQ(v4i.XY.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4i.XY.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4i.XYZ.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4i.XYZ.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4i.XYZ.Elements[2], 3.0f);
EXPECT_FLOAT_EQ(v4i.RGB.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4i.RGB.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4i.RGB.Elements[2], 3.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(v4i[0], 1.0f);
EXPECT_FLOAT_EQ(v4i[1], 2.0f);
EXPECT_FLOAT_EQ(v4i[2], 3.0f);
EXPECT_FLOAT_EQ(v4i[3], 4.0f);
#endif
EXPECT_FLOAT_EQ(v4v.X, 1.0f);
EXPECT_FLOAT_EQ(v4v.Y, 2.0f);
EXPECT_FLOAT_EQ(v4v.Z, 3.0f);
EXPECT_FLOAT_EQ(v4v.W, 4.0f);
EXPECT_FLOAT_EQ(v4v.R, 1.0f);
EXPECT_FLOAT_EQ(v4v.G, 2.0f);
EXPECT_FLOAT_EQ(v4v.B, 3.0f);
EXPECT_FLOAT_EQ(v4v.A, 4.0f);
EXPECT_FLOAT_EQ(v4v.XY.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4v.XY.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4v.YZ.Elements[0], 2.0f);
EXPECT_FLOAT_EQ(v4v.YZ.Elements[1], 3.0f);
EXPECT_FLOAT_EQ(v4v.ZW.Elements[0], 3.0f);
EXPECT_FLOAT_EQ(v4v.ZW.Elements[1], 4.0f);
EXPECT_FLOAT_EQ(v4v.XY.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4v.XY.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4v.XYZ.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4v.XYZ.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4v.XYZ.Elements[2], 3.0f);
EXPECT_FLOAT_EQ(v4v.RGB.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(v4v.RGB.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(v4v.RGB.Elements[2], 3.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(v4v[0], 1.0f);
EXPECT_FLOAT_EQ(v4v[1], 2.0f);
EXPECT_FLOAT_EQ(v4v[2], 3.0f);
EXPECT_FLOAT_EQ(v4v[3], 4.0f);
#endif
}
TEST(Initialization, MatrixEmpty)
{
hmm_mat4 m4 = HMM_Mat4();
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
EXPECT_FLOAT_EQ(m4.Elements[Column][Row], 0.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(m4[Column][Row], 0.0f);
#endif
}
}
}
TEST(Initialization, MatrixDiagonal)
{
hmm_mat4 m4d = HMM_Mat4d(1.0f);
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
if (Column == Row) {
EXPECT_FLOAT_EQ(m4d.Elements[Column][Row], 1.0f);
} else {
EXPECT_FLOAT_EQ(m4d.Elements[Column][Row], 0.0f);
}
}
}
}
TEST(Initialization, Quaternion)
{
hmm_quaternion q = HMM_Quaternion(1.0f, 2.0f, 3.0f, 4.0f);
EXPECT_FLOAT_EQ(q.X, 1.0f);
EXPECT_FLOAT_EQ(q.Y, 2.0f);
EXPECT_FLOAT_EQ(q.Z, 3.0f);
EXPECT_FLOAT_EQ(q.W, 4.0f);
EXPECT_FLOAT_EQ(q.Elements[0], 1.0f);
EXPECT_FLOAT_EQ(q.Elements[1], 2.0f);
EXPECT_FLOAT_EQ(q.Elements[2], 3.0f);
EXPECT_FLOAT_EQ(q.Elements[3], 4.0f);
hmm_vec4 v = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
hmm_quaternion qv = HMM_QuaternionV4(v);
EXPECT_FLOAT_EQ(qv.X, 1.0f);
EXPECT_FLOAT_EQ(qv.Y, 2.0f);
EXPECT_FLOAT_EQ(qv.Z, 3.0f);
EXPECT_FLOAT_EQ(qv.W, 4.0f);
}

154
test/categories/MatrixOps.h Normal file
View File

@@ -0,0 +1,154 @@
#include "../HandmadeTest.h"
void printQuat(hmm_quaternion quat) {
printf("\n%f %f %f %f", quat.X, quat.Y, quat.Z, quat.W);
}
TEST(MatrixOps, Transpose)
{
hmm_mat4 m4 = HMM_Mat4(); // will have 1 - 16
// Fill the matrix
int Counter = 1;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
m4.Elements[Column][Row] = Counter;
++Counter;
}
}
// Test the matrix
hmm_mat4 result = HMM_Transpose(m4);
EXPECT_FLOAT_EQ(result.Elements[0][0], 1.0f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 5.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 9.0f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 13.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 2.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 6.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 10.0f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 14.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 3.0f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 7.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 11.0f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 15.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 4.0f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 8.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 12.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 16.0f);
}
TEST(MatrixOps, ToQuaternion)
{
{ // Test 90 degree rotation about X axis
hmm_mat4 rot = {
1.0f, 0.0f, 0.0f, 0.0f, // first column (X)
0.0f, 0.0f, 1.0f, 0.0f, // second column (Y)
0.0f, -1.0f, 0.0f, 0.0f, // third column (Z)
0.0f, 0.0f, 0.0f, 0.0f
};
hmm_quaternion expected = HMM_QuaternionFromAxisAngle(HMM_Vec3(1.0f, 0.0f, 0.0f), HMM_ToRadians(90.0f));
hmm_quaternion actualResult = HMM_Mat4ToQuaternion(rot);
EXPECT_FLOAT_EQ(actualResult.X, expected.X);
EXPECT_FLOAT_EQ(actualResult.Y, expected.Y);
EXPECT_FLOAT_EQ(actualResult.Z, expected.Z);
EXPECT_FLOAT_EQ(actualResult.W, expected.W);
}
{ // Test 90 degree rotation about Y axis
hmm_mat4 rot = {
0.0f, 0.0f, -1.0f, 0.0f, // first column (X)
0.0f, 1.0f, 0.0f, 0.0f, // second column (Y)
1.0f, 0.0f, 0.0f, 0.0f, // third column (Z)
0.0f, 0.0f, 0.0f, 0.0f
};
hmm_quaternion expected = HMM_QuaternionFromAxisAngle(HMM_Vec3(0.0f, 1.0f, 0.0f), HMM_ToRadians(90.0f));
hmm_quaternion actualResult = HMM_Mat4ToQuaternion(rot);
EXPECT_FLOAT_EQ(actualResult.X, expected.X);
EXPECT_FLOAT_EQ(actualResult.Y, expected.Y);
EXPECT_FLOAT_EQ(actualResult.Z, expected.Z);
EXPECT_FLOAT_EQ(actualResult.W, expected.W);
}
{ // Test 90 degree rotation about Z axis
hmm_mat4 rot = {
0.0f, 1.0f, 0.0f, 0.0f, // first column (X)
-1.0f, 0.0f, 0.0f, 0.0f, // second column (Y)
0.0f, 0.0f, 1.0f, 0.0f, // third column (Z)
0.0f, 0.0f, 0.0f, 0.0f
};
hmm_quaternion expected = HMM_QuaternionFromAxisAngle(HMM_Vec3(0.0f, 0.0f, 1.0f), HMM_ToRadians(90.0f));
hmm_quaternion actualResult = HMM_Mat4ToQuaternion(rot);
EXPECT_FLOAT_EQ(actualResult.X, expected.X);
EXPECT_FLOAT_EQ(actualResult.Y, expected.Y);
EXPECT_FLOAT_EQ(actualResult.Z, expected.Z);
EXPECT_FLOAT_EQ(actualResult.W, expected.W);
}
{ // Test 180 degree rotation about X axis
hmm_mat4 rot = {
1.0f, 0.0f, 0.0f, 0.0f, // first column (X)
0.0f, -1.0f, 1.0f, 0.0f, // second column (Y)
0.0f, 0.0f, -1.0f, 0.0f, // third column (Z)
0.0f, 0.0f, 0.0f, 0.0f
};
hmm_quaternion expected = HMM_QuaternionFromAxisAngle(HMM_Vec3(1.0f, 0.0f, 0.0f), HMM_ToRadians(180.0f));
hmm_quaternion actualResult = HMM_Mat4ToQuaternion(rot);
printQuat(expected);
printQuat(actualResult);
EXPECT_FLOAT_EQ(actualResult.X, expected.X);
EXPECT_FLOAT_EQ(actualResult.Y, expected.Y);
EXPECT_FLOAT_EQ(actualResult.Z, expected.Z);
EXPECT_FLOAT_EQ(actualResult.W, expected.W);
}
{ // Test 180 degree rotation about Y axis
hmm_mat4 rot = {
-1.0f, 0.0f, 0.0f, 0.0f, // first column (X)
0.0f, 1.0f, 1.0f, 0.0f, // second column (Y)
0.0f, 0.0f, -1.0f, 0.0f, // third column (Z)
0.0f, 0.0f, 0.0f, 0.0f
};
hmm_quaternion expected = HMM_QuaternionFromAxisAngle(HMM_Vec3(0.0f, 1.0f, 0.0f), HMM_ToRadians(180.0f));
hmm_quaternion actualResult = HMM_Mat4ToQuaternion(rot);
printQuat(expected);
printQuat(actualResult);
EXPECT_FLOAT_EQ(actualResult.X, expected.X);
EXPECT_FLOAT_EQ(actualResult.Y, expected.Y);
EXPECT_FLOAT_EQ(actualResult.Z, expected.Z);
EXPECT_FLOAT_EQ(actualResult.W, expected.W);
}
{ // Test 180 degree rotation about Z axis
hmm_mat4 rot = {
-1.0f, 0.0f, 0.0f, 0.0f, // first column (X)
0.0f, -1.0f, 1.0f, 0.0f, // second column (Y)
0.0f, 0.0f, 1.0f, 0.0f, // third column (Z)
0.0f, 0.0f, 0.0f, 0.0f
};
hmm_quaternion expected = HMM_QuaternionFromAxisAngle(HMM_Vec3(0.0f, 0.0f, 1.0f), HMM_ToRadians(180.0f));
hmm_quaternion actualResult = HMM_Mat4ToQuaternion(rot);
printQuat(expected);
printQuat(actualResult);
EXPECT_FLOAT_EQ(actualResult.X, expected.X);
EXPECT_FLOAT_EQ(actualResult.Y, expected.Y);
EXPECT_FLOAT_EQ(actualResult.Z, expected.Z);
EXPECT_FLOAT_EQ(actualResult.W, expected.W);
}
}

View File

@@ -0,0 +1,536 @@
#include "../HandmadeTest.h"
TEST(Multiplication, Vec2Vec2)
{
hmm_vec2 v2_1 = HMM_Vec2(1.0f, 2.0f);
hmm_vec2 v2_2 = HMM_Vec2(3.0f, 4.0f);
{
hmm_vec2 result = HMM_MultiplyVec2(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f);
}
#ifdef __cplusplus
{
hmm_vec2 result = HMM_Multiply(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f);
}
{
hmm_vec2 result = v2_1 * v2_2;
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f);
}
v2_1 *= v2_2;
EXPECT_FLOAT_EQ(v2_1.X, 3.0f);
EXPECT_FLOAT_EQ(v2_1.Y, 8.0f);
#endif
}
TEST(Multiplication, Vec2Scalar)
{
hmm_vec2 v2 = HMM_Vec2(1.0f, 2.0f);
float s = 3.0f;
{
hmm_vec2 result = HMM_MultiplyVec2f(v2, s);
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
}
#ifdef __cplusplus
{
hmm_vec2 result = HMM_Multiply(v2, s);
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
}
{
hmm_vec2 result = v2 * s;
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
}
{
hmm_vec2 result = s * v2;
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
}
v2 *= s;
EXPECT_FLOAT_EQ(v2.X, 3.0f);
EXPECT_FLOAT_EQ(v2.Y, 6.0f);
#endif
}
TEST(Multiplication, Vec3Vec3)
{
hmm_vec3 v3_1 = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 v3_2 = HMM_Vec3(4.0f, 5.0f, 6.0f);
{
hmm_vec3 result = HMM_MultiplyVec3(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, 4.0f);
EXPECT_FLOAT_EQ(result.Y, 10.0f);
EXPECT_FLOAT_EQ(result.Z, 18.0f);
}
#ifdef __cplusplus
{
hmm_vec3 result = HMM_Multiply(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, 4.0f);
EXPECT_FLOAT_EQ(result.Y, 10.0f);
EXPECT_FLOAT_EQ(result.Z, 18.0f);
}
{
hmm_vec3 result = v3_1 * v3_2;
EXPECT_FLOAT_EQ(result.X, 4.0f);
EXPECT_FLOAT_EQ(result.Y, 10.0f);
EXPECT_FLOAT_EQ(result.Z, 18.0f);
}
v3_1 *= v3_2;
EXPECT_FLOAT_EQ(v3_1.X, 4.0f);
EXPECT_FLOAT_EQ(v3_1.Y, 10.0f);
EXPECT_FLOAT_EQ(v3_1.Z, 18.0f);
#endif
}
TEST(Multiplication, Vec3Scalar)
{
hmm_vec3 v3 = HMM_Vec3(1.0f, 2.0f, 3.0f);
float s = 3.0f;
{
hmm_vec3 result = HMM_MultiplyVec3f(v3, s);
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
}
#ifdef __cplusplus
{
hmm_vec3 result = HMM_Multiply(v3, s);
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
}
{
hmm_vec3 result = v3 * s;
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
}
{
hmm_vec3 result = s * v3;
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
}
v3 *= s;
EXPECT_FLOAT_EQ(v3.X, 3.0f);
EXPECT_FLOAT_EQ(v3.Y, 6.0f);
EXPECT_FLOAT_EQ(v3.Z, 9.0f);
#endif
}
TEST(Multiplication, Vec4Vec4)
{
hmm_vec4 v4_1 = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
hmm_vec4 v4_2 = HMM_Vec4(5.0f, 6.0f, 7.0f, 8.0f);
{
hmm_vec4 result = HMM_MultiplyVec4(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, 5.0f);
EXPECT_FLOAT_EQ(result.Y, 12.0f);
EXPECT_FLOAT_EQ(result.Z, 21.0f);
EXPECT_FLOAT_EQ(result.W, 32.0f);
}
#ifdef __cplusplus
{
hmm_vec4 result = HMM_Multiply(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, 5.0f);
EXPECT_FLOAT_EQ(result.Y, 12.0f);
EXPECT_FLOAT_EQ(result.Z, 21.0f);
EXPECT_FLOAT_EQ(result.W, 32.0f);
}
{
hmm_vec4 result = v4_1 * v4_2;
EXPECT_FLOAT_EQ(result.X, 5.0f);
EXPECT_FLOAT_EQ(result.Y, 12.0f);
EXPECT_FLOAT_EQ(result.Z, 21.0f);
EXPECT_FLOAT_EQ(result.W, 32.0f);
}
v4_1 *= v4_2;
EXPECT_FLOAT_EQ(v4_1.X, 5.0f);
EXPECT_FLOAT_EQ(v4_1.Y, 12.0f);
EXPECT_FLOAT_EQ(v4_1.Z, 21.0f);
EXPECT_FLOAT_EQ(v4_1.W, 32.0f);
#endif
}
TEST(Multiplication, Vec4Scalar)
{
hmm_vec4 v4 = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
float s = 3.0f;
{
hmm_vec4 result = HMM_MultiplyVec4f(v4, s);
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f);
}
#ifdef __cplusplus
{
hmm_vec4 result = HMM_Multiply(v4, s);
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f);
}
{
hmm_vec4 result = v4 * s;
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f);
}
{
hmm_vec4 result = s * v4;
EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f);
}
v4 *= s;
EXPECT_FLOAT_EQ(v4.X, 3.0f);
EXPECT_FLOAT_EQ(v4.Y, 6.0f);
EXPECT_FLOAT_EQ(v4.Z, 9.0f);
#endif
}
TEST(Multiplication, Mat4Mat4)
{
hmm_mat4 m4_1 = HMM_Mat4(); // will have 1 - 16
hmm_mat4 m4_2 = HMM_Mat4(); // will have 17 - 32
// Fill the matrices
int Counter = 1;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
m4_1.Elements[Column][Row] = Counter;
++Counter;
}
}
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
m4_2.Elements[Column][Row] = Counter;
++Counter;
}
}
// Test the results
{
hmm_mat4 result = HMM_MultiplyMat4(m4_1, m4_2);
EXPECT_FLOAT_EQ(result.Elements[0][0], 538.0f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 612.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 686.0f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 760.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 650.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 740.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 830.0f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 920.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 762.0f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 868.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 974.0f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 1080.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 874.0f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 996.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 1118.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 1240.0f);
}
#ifdef __cplusplus
{
hmm_mat4 result = HMM_Multiply(m4_1, m4_2);
EXPECT_FLOAT_EQ(result.Elements[0][0], 538.0f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 612.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 686.0f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 760.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 650.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 740.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 830.0f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 920.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 762.0f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 868.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 974.0f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 1080.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 874.0f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 996.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 1118.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 1240.0f);
}
{
hmm_mat4 result = m4_1 * m4_2;
EXPECT_FLOAT_EQ(result.Elements[0][0], 538.0f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 612.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 686.0f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 760.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 650.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 740.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 830.0f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 920.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 762.0f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 868.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 974.0f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 1080.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 874.0f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 996.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 1118.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 1240.0f);
}
// At the time I wrote this, I intentionally omitted
// the *= operator for matrices because matrix
// multiplication is not commutative. (bvisness)
#endif
}
TEST(Multiplication, Mat4Scalar)
{
hmm_mat4 m4 = HMM_Mat4(); // will have 1 - 16
float s = 3;
// Fill the matrix
int Counter = 1;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
m4.Elements[Column][Row] = Counter;
++Counter;
}
}
// Test the results
{
hmm_mat4 result = HMM_MultiplyMat4f(m4, s);
EXPECT_FLOAT_EQ(result.Elements[0][0], 3.0f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 6.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 9.0f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 12.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 15.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 18.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 21.0f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 24.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 27.0f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 30.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 33.0f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 36.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 39.0f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 42.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 45.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 48.0f);
}
#ifdef __cplusplus
{
hmm_mat4 result = HMM_Multiply(m4, s);
EXPECT_FLOAT_EQ(result.Elements[0][0], 3.0f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 6.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 9.0f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 12.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 15.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 18.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 21.0f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 24.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 27.0f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 30.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 33.0f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 36.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 39.0f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 42.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 45.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 48.0f);
}
{
hmm_mat4 result = m4 * s;
EXPECT_FLOAT_EQ(result.Elements[0][0], 3.0f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 6.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 9.0f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 12.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 15.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 18.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 21.0f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 24.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 27.0f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 30.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 33.0f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 36.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 39.0f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 42.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 45.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 48.0f);
}
{
hmm_mat4 result = s * m4;
EXPECT_FLOAT_EQ(result.Elements[0][0], 3.0f);
EXPECT_FLOAT_EQ(result.Elements[0][1], 6.0f);
EXPECT_FLOAT_EQ(result.Elements[0][2], 9.0f);
EXPECT_FLOAT_EQ(result.Elements[0][3], 12.0f);
EXPECT_FLOAT_EQ(result.Elements[1][0], 15.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 18.0f);
EXPECT_FLOAT_EQ(result.Elements[1][2], 21.0f);
EXPECT_FLOAT_EQ(result.Elements[1][3], 24.0f);
EXPECT_FLOAT_EQ(result.Elements[2][0], 27.0f);
EXPECT_FLOAT_EQ(result.Elements[2][1], 30.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 33.0f);
EXPECT_FLOAT_EQ(result.Elements[2][3], 36.0f);
EXPECT_FLOAT_EQ(result.Elements[3][0], 39.0f);
EXPECT_FLOAT_EQ(result.Elements[3][1], 42.0f);
EXPECT_FLOAT_EQ(result.Elements[3][2], 45.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 48.0f);
}
m4 *= s;
EXPECT_FLOAT_EQ(m4.Elements[0][0], 3.0f);
EXPECT_FLOAT_EQ(m4.Elements[0][1], 6.0f);
EXPECT_FLOAT_EQ(m4.Elements[0][2], 9.0f);
EXPECT_FLOAT_EQ(m4.Elements[0][3], 12.0f);
EXPECT_FLOAT_EQ(m4.Elements[1][0], 15.0f);
EXPECT_FLOAT_EQ(m4.Elements[1][1], 18.0f);
EXPECT_FLOAT_EQ(m4.Elements[1][2], 21.0f);
EXPECT_FLOAT_EQ(m4.Elements[1][3], 24.0f);
EXPECT_FLOAT_EQ(m4.Elements[2][0], 27.0f);
EXPECT_FLOAT_EQ(m4.Elements[2][1], 30.0f);
EXPECT_FLOAT_EQ(m4.Elements[2][2], 33.0f);
EXPECT_FLOAT_EQ(m4.Elements[2][3], 36.0f);
EXPECT_FLOAT_EQ(m4.Elements[3][0], 39.0f);
EXPECT_FLOAT_EQ(m4.Elements[3][1], 42.0f);
EXPECT_FLOAT_EQ(m4.Elements[3][2], 45.0f);
EXPECT_FLOAT_EQ(m4.Elements[3][3], 48.0f);
#endif
}
TEST(Multiplication, Mat4Vec4)
{
hmm_mat4 m4 = HMM_Mat4(); // will have 1 - 16
hmm_vec4 v4 = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
// Fill the matrix
int Counter = 1;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
m4.Elements[Column][Row] = Counter;
++Counter;
}
}
// Test the results
{
hmm_vec4 result = HMM_MultiplyMat4ByVec4(m4, v4);
EXPECT_FLOAT_EQ(result.X, 90.0f);
EXPECT_FLOAT_EQ(result.Y, 100.0f);
EXPECT_FLOAT_EQ(result.Z, 110.0f);
EXPECT_FLOAT_EQ(result.W, 120.0f);
}
#ifdef __cplusplus
{
hmm_vec4 result = HMM_Multiply(m4, v4);
EXPECT_FLOAT_EQ(result.X, 90.0f);
EXPECT_FLOAT_EQ(result.Y, 100.0f);
EXPECT_FLOAT_EQ(result.Z, 110.0f);
EXPECT_FLOAT_EQ(result.W, 120.0f);
}
{
hmm_vec4 result = m4 * v4;
EXPECT_FLOAT_EQ(result.X, 90.0f);
EXPECT_FLOAT_EQ(result.Y, 100.0f);
EXPECT_FLOAT_EQ(result.Z, 110.0f);
EXPECT_FLOAT_EQ(result.W, 120.0f);
}
// *= makes no sense for this particular case.
#endif
}
TEST(Multiplication, QuaternionQuaternion)
{
hmm_quaternion q1 = HMM_Quaternion(1.0f, 2.0f, 3.0f, 4.0f);
hmm_quaternion q2 = HMM_Quaternion(5.0f, 6.0f, 7.0f, 8.0f);
{
hmm_quaternion result = HMM_MultiplyQuaternion(q1, q2);
EXPECT_FLOAT_EQ(result.X, 24.0f);
EXPECT_FLOAT_EQ(result.Y, 48.0f);
EXPECT_FLOAT_EQ(result.Z, 48.0f);
EXPECT_FLOAT_EQ(result.W, -6.0f);
}
#ifdef __cplusplus
{
hmm_quaternion result = HMM_Multiply(q1, q2);
EXPECT_FLOAT_EQ(result.X, 24.0f);
EXPECT_FLOAT_EQ(result.Y, 48.0f);
EXPECT_FLOAT_EQ(result.Z, 48.0f);
EXPECT_FLOAT_EQ(result.W, -6.0f);
}
{
hmm_quaternion result = q1 * q2;
EXPECT_FLOAT_EQ(result.X, 24.0f);
EXPECT_FLOAT_EQ(result.Y, 48.0f);
EXPECT_FLOAT_EQ(result.Z, 48.0f);
EXPECT_FLOAT_EQ(result.W, -6.0f);
}
// Like with matrices, we're not implementing the *=
// operator for quaternions because quaternion multiplication
// is not commutative.
#endif
}
TEST(Multiplication, QuaternionScalar)
{
hmm_quaternion q = HMM_Quaternion(1.0f, 2.0f, 3.0f, 4.0f);
float f = 2.0f;
{
hmm_quaternion result = HMM_MultiplyQuaternionF(q, f);
EXPECT_FLOAT_EQ(result.X, 2.0f);
EXPECT_FLOAT_EQ(result.Y, 4.0f);
EXPECT_FLOAT_EQ(result.Z, 6.0f);
EXPECT_FLOAT_EQ(result.W, 8.0f);
}
#ifdef __cplusplus
{
hmm_quaternion result = HMM_Multiply(q, f);
EXPECT_FLOAT_EQ(result.X, 2.0f);
EXPECT_FLOAT_EQ(result.Y, 4.0f);
EXPECT_FLOAT_EQ(result.Z, 6.0f);
EXPECT_FLOAT_EQ(result.W, 8.0f);
}
{
hmm_quaternion result = q * f;
EXPECT_FLOAT_EQ(result.X, 2.0f);
EXPECT_FLOAT_EQ(result.Y, 4.0f);
EXPECT_FLOAT_EQ(result.Z, 6.0f);
EXPECT_FLOAT_EQ(result.W, 8.0f);
}
{
hmm_quaternion result = f * q;
EXPECT_FLOAT_EQ(result.X, 2.0f);
EXPECT_FLOAT_EQ(result.Y, 4.0f);
EXPECT_FLOAT_EQ(result.Z, 6.0f);
EXPECT_FLOAT_EQ(result.W, 8.0f);
}
q *= f;
EXPECT_FLOAT_EQ(q.X, 2.0f);
EXPECT_FLOAT_EQ(q.Y, 4.0f);
EXPECT_FLOAT_EQ(q.Z, 6.0f);
EXPECT_FLOAT_EQ(q.W, 8.0f);
#endif
}

View File

@@ -0,0 +1,36 @@
#include "../HandmadeTest.h"
TEST(Projection, Orthographic)
{
hmm_mat4 projection = HMM_Orthographic(-10.0f, 10.0f, -5.0f, 5.0f, 0.0f, -10.0f);
hmm_vec3 original = HMM_Vec3(5.0f, 5.0f, -5.0f);
hmm_vec4 projected = HMM_MultiplyMat4ByVec4(projection, HMM_Vec4v(original, 1));
EXPECT_FLOAT_EQ(projected.X, 0.5f);
EXPECT_FLOAT_EQ(projected.Y, 1.0f);
EXPECT_FLOAT_EQ(projected.Z, -2.0f);
EXPECT_FLOAT_EQ(projected.W, 1.0f);
}
TEST(Projection, Perspective)
{
hmm_mat4 projection = HMM_Perspective(90.0f, 2.0f, 5.0f, 15.0f);
{
hmm_vec3 original = HMM_Vec3(5.0f, 5.0f, -15.0f);
hmm_vec4 projected = HMM_MultiplyMat4ByVec4(projection, HMM_Vec4v(original, 1));
EXPECT_FLOAT_EQ(projected.X, 5.0f);
EXPECT_FLOAT_EQ(projected.Y, 10.0f);
EXPECT_FLOAT_EQ(projected.Z, 15.0f);
EXPECT_FLOAT_EQ(projected.W, 15.0f);
}
{
hmm_vec3 original = HMM_Vec3(5.0f, 5.0f, -5.0f);
hmm_vec4 projected = HMM_MultiplyMat4ByVec4(projection, HMM_Vec4v(original, 1));
EXPECT_FLOAT_EQ(projected.X, 5.0f);
EXPECT_FLOAT_EQ(projected.Y, 10.0f);
EXPECT_FLOAT_EQ(projected.Z, -5.0f);
EXPECT_FLOAT_EQ(projected.W, 5.0f);
}
}

View File

@@ -0,0 +1,148 @@
#include "../HandmadeTest.h"
TEST(QuaternionOps, Inverse)
{
hmm_quaternion q1 = HMM_Quaternion(1.0f, 2.0f, 3.0f, 4.0f);
hmm_quaternion inverse = HMM_InverseQuaternion(q1);
hmm_quaternion result = HMM_MultiplyQuaternion(q1, inverse);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
EXPECT_FLOAT_EQ(result.Z, 0.0f);
EXPECT_FLOAT_EQ(result.W, 1.0f);
}
TEST(QuaternionOps, Dot)
{
hmm_quaternion q1 = HMM_Quaternion(1.0f, 2.0f, 3.0f, 4.0f);
hmm_quaternion q2 = HMM_Quaternion(5.0f, 6.0f, 7.0f, 8.0f);
{
float result = HMM_DotQuaternion(q1, q2);
EXPECT_FLOAT_EQ(result, 70.0f);
}
#ifdef __cplusplus
{
float result = HMM_Dot(q1, q2);
EXPECT_FLOAT_EQ(result, 70.0f);
}
#endif
}
TEST(QuaternionOps, Normalize)
{
hmm_quaternion q = HMM_Quaternion(1.0f, 2.0f, 3.0f, 4.0f);
{
hmm_quaternion result = HMM_NormalizeQuaternion(q);
EXPECT_FLOAT_EQ(result.X, 0.1825741858f);
EXPECT_FLOAT_EQ(result.Y, 0.3651483717f);
EXPECT_FLOAT_EQ(result.Z, 0.5477225575f);
EXPECT_FLOAT_EQ(result.W, 0.7302967433f);
}
#ifdef __cplusplus
{
hmm_quaternion result = HMM_Normalize(q);
EXPECT_FLOAT_EQ(result.X, 0.1825741858f);
EXPECT_FLOAT_EQ(result.Y, 0.3651483717f);
EXPECT_FLOAT_EQ(result.Z, 0.5477225575f);
EXPECT_FLOAT_EQ(result.W, 0.7302967433f);
}
#endif
}
TEST(QuaternionOps, NLerp)
{
hmm_quaternion from = HMM_Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
hmm_quaternion to = HMM_Quaternion(0.5f, 0.5f, -0.5f, 0.5f);
hmm_quaternion result = HMM_NLerp(from, 0.5f, to);
EXPECT_FLOAT_EQ(result.X, 0.28867513f);
EXPECT_FLOAT_EQ(result.Y, 0.28867513f);
EXPECT_FLOAT_EQ(result.Z, -0.28867513f);
EXPECT_FLOAT_EQ(result.W, 0.86602540f);
}
TEST(QuaternionOps, Slerp)
{
hmm_quaternion from = HMM_Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
hmm_quaternion to = HMM_Quaternion(0.5f, 0.5f, -0.5f, 0.5f);
hmm_quaternion result = HMM_Slerp(from, 0.5f, to);
EXPECT_FLOAT_EQ(result.X, 0.28867513f);
EXPECT_FLOAT_EQ(result.Y, 0.28867513f);
EXPECT_FLOAT_EQ(result.Z, -0.28867513f);
EXPECT_FLOAT_EQ(result.W, 0.86602540f);
}
TEST(QuaternionOps, ToMat4)
{
const float abs_error = 0.0001f;
{
// Identity quaternion
hmm_quaternion rot = HMM_Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
hmm_mat4 result = HMM_QuaternionToMat4(rot);
EXPECT_NEAR(result.Elements[0][0], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[0][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][1], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[1][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][2], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[2][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][3], 1.0f, abs_error);
}
{
// Straightforward 90 degree rotation
hmm_quaternion rot = HMM_Quaternion(0.707107f, 0.0f, 0.0f, 0.707107f);
hmm_mat4 result = HMM_QuaternionToMat4(rot);
EXPECT_NEAR(result.Elements[0][0], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[0][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][2], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[1][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][1], -1.0f, abs_error);
EXPECT_NEAR(result.Elements[2][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][3], 1.0f, abs_error);
}
}
TEST(QuaternionOps, FromAxisAngle)
{
hmm_vec3 axis = HMM_Vec3(1.0f, 0.0f, 0.0f);
float angle = HMM_PI32 / 2.0f;
hmm_quaternion result = HMM_QuaternionFromAxisAngle(axis, angle);
EXPECT_NEAR(result.X, 0.707107f, FLT_EPSILON * 2);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
EXPECT_FLOAT_EQ(result.Z, 0.0f);
EXPECT_NEAR(result.W, 0.707107f, FLT_EPSILON * 2);
}

41
test/categories/SSE.h Normal file
View File

@@ -0,0 +1,41 @@
#include "../HandmadeTest.h"
#ifdef HANDMADE_MATH__USE_SSE
TEST(SSE, LinearCombine)
{
hmm_mat4 MatrixOne = HMM_Mat4d(2.0f);
hmm_mat4 MatrixTwo = HMM_Mat4d(4.0f);
hmm_mat4 Result;
Result.Rows[0] = HMM_LinearCombineSSE(MatrixOne.Rows[0], MatrixTwo);
Result.Rows[1] = HMM_LinearCombineSSE(MatrixOne.Rows[1], MatrixTwo);
Result.Rows[2] = HMM_LinearCombineSSE(MatrixOne.Rows[2], MatrixTwo);
Result.Rows[3] = HMM_LinearCombineSSE(MatrixOne.Rows[3], MatrixTwo);
{
EXPECT_FLOAT_EQ(Result.Elements[0][0], 8.0f);
EXPECT_FLOAT_EQ(Result.Elements[0][1], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[0][2], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[0][3], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[1][0], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[1][1], 8.0f);
EXPECT_FLOAT_EQ(Result.Elements[1][2], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[1][3], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[2][0], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[2][1], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[2][2], 8.0f);
EXPECT_FLOAT_EQ(Result.Elements[2][3], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[3][0], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[3][1], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[3][2], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[3][3], 8.0f);
}
}
#endif

View File

@@ -0,0 +1,74 @@
#include "../HandmadeTest.h"
TEST(ScalarMath, Trigonometry)
{
// We have to be a little looser with our equality constraint
// because of floating-point precision issues.
const float trigAbsError = 0.0001f;
EXPECT_NEAR(HMM_SinF(0.0f), 0.0f, trigAbsError);
EXPECT_NEAR(HMM_SinF(HMM_PI32 / 2), 1.0f, trigAbsError);
EXPECT_NEAR(HMM_SinF(HMM_PI32), 0.0f, trigAbsError);
EXPECT_NEAR(HMM_SinF(3 * HMM_PI32 / 2), -1.0f, trigAbsError);
EXPECT_NEAR(HMM_SinF(-HMM_PI32 / 2), -1.0f, trigAbsError);
EXPECT_NEAR(HMM_CosF(0.0f), 1.0f, trigAbsError);
EXPECT_NEAR(HMM_CosF(HMM_PI32 / 2), 0.0f, trigAbsError);
EXPECT_NEAR(HMM_CosF(HMM_PI32), -1.0f, trigAbsError);
EXPECT_NEAR(HMM_CosF(3 * HMM_PI32 / 2), 0.0f, trigAbsError);
EXPECT_NEAR(HMM_CosF(-HMM_PI32), -1.0f, trigAbsError);
EXPECT_NEAR(HMM_TanF(0.0f), 0.0f, trigAbsError);
EXPECT_NEAR(HMM_TanF(HMM_PI32 / 4), 1.0f, trigAbsError);
EXPECT_NEAR(HMM_TanF(3 * HMM_PI32 / 4), -1.0f, trigAbsError);
EXPECT_NEAR(HMM_TanF(HMM_PI32), 0.0f, trigAbsError);
EXPECT_NEAR(HMM_TanF(-HMM_PI32 / 4), -1.0f, trigAbsError);
// This isn't the most rigorous because we're really just sanity-
// checking that things work by default.
}
TEST(ScalarMath, ToRadians)
{
EXPECT_FLOAT_EQ(HMM_ToRadians(0.0f), 0.0f);
EXPECT_FLOAT_EQ(HMM_ToRadians(180.0f), HMM_PI32);
EXPECT_FLOAT_EQ(HMM_ToRadians(-180.0f), -HMM_PI32);
}
TEST(ScalarMath, SquareRoot)
{
EXPECT_FLOAT_EQ(HMM_SquareRootF(16.0f), 4.0f);
}
TEST(ScalarMath, RSquareRootF)
{
EXPECT_NEAR(HMM_RSquareRootF(10.0f), 0.31616211f, 0.0001f);
}
TEST(ScalarMath, Power)
{
EXPECT_FLOAT_EQ(HMM_Power(2.0f, 0), 1.0f);
EXPECT_FLOAT_EQ(HMM_Power(2.0f, 4), 16.0f);
EXPECT_FLOAT_EQ(HMM_Power(2.0f, -2), 0.25f);
}
TEST(ScalarMath, PowerF)
{
EXPECT_FLOAT_EQ(HMM_PowerF(2.0f, 0), 1.0f);
EXPECT_NEAR(HMM_PowerF(2.0f, 4.1), 17.148376f, 0.0001f);
EXPECT_NEAR(HMM_PowerF(2.0f, -2.5), 0.176777f, 0.0001f);
}
TEST(ScalarMath, Lerp)
{
EXPECT_FLOAT_EQ(HMM_Lerp(-2.0f, 0.0f, 2.0f), -2.0f);
EXPECT_FLOAT_EQ(HMM_Lerp(-2.0f, 0.5f, 2.0f), 0.0f);
EXPECT_FLOAT_EQ(HMM_Lerp(-2.0f, 1.0f, 2.0f), 2.0f);
}
TEST(ScalarMath, Clamp)
{
EXPECT_FLOAT_EQ(HMM_Clamp(-2.0f, 0.0f, 2.0f), 0.0f);
EXPECT_FLOAT_EQ(HMM_Clamp(-2.0f, -3.0f, 2.0f), -2.0f);
EXPECT_FLOAT_EQ(HMM_Clamp(-2.0f, 3.0f, 2.0f), 2.0f);
}

View File

@@ -0,0 +1,201 @@
#include "../HandmadeTest.h"
TEST(Subtraction, Vec2)
{
hmm_vec2 v2_1 = HMM_Vec2(1.0f, 2.0f);
hmm_vec2 v2_2 = HMM_Vec2(3.0f, 4.0f);
{
hmm_vec2 result = HMM_SubtractVec2(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, -2.0f);
EXPECT_FLOAT_EQ(result.Y, -2.0f);
}
#ifdef __cplusplus
{
hmm_vec2 result = HMM_Subtract(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, -2.0f);
EXPECT_FLOAT_EQ(result.Y, -2.0f);
}
{
hmm_vec2 result = v2_1 - v2_2;
EXPECT_FLOAT_EQ(result.X, -2.0f);
EXPECT_FLOAT_EQ(result.Y, -2.0f);
}
v2_1 -= v2_2;
EXPECT_FLOAT_EQ(v2_1.X, -2.0f);
EXPECT_FLOAT_EQ(v2_1.Y, -2.0f);
#endif
}
TEST(Subtraction, Vec3)
{
hmm_vec3 v3_1 = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 v3_2 = HMM_Vec3(4.0f, 5.0f, 6.0f);
{
hmm_vec3 result = HMM_SubtractVec3(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, -3.0f);
EXPECT_FLOAT_EQ(result.Y, -3.0f);
EXPECT_FLOAT_EQ(result.Z, -3.0f);
}
#ifdef __cplusplus
{
hmm_vec3 result = HMM_Subtract(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, -3.0f);
EXPECT_FLOAT_EQ(result.Y, -3.0f);
EXPECT_FLOAT_EQ(result.Z, -3.0f);
}
{
hmm_vec3 result = v3_1 - v3_2;
EXPECT_FLOAT_EQ(result.X, -3.0f);
EXPECT_FLOAT_EQ(result.Y, -3.0f);
EXPECT_FLOAT_EQ(result.Z, -3.0f);
}
v3_1 -= v3_2;
EXPECT_FLOAT_EQ(v3_1.X, -3.0f);
EXPECT_FLOAT_EQ(v3_1.Y, -3.0f);
EXPECT_FLOAT_EQ(v3_1.Z, -3.0f);
#endif
}
TEST(Subtraction, Vec4)
{
hmm_vec4 v4_1 = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
hmm_vec4 v4_2 = HMM_Vec4(5.0f, 6.0f, 7.0f, 8.0f);
{
hmm_vec4 result = HMM_SubtractVec4(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, -4.0f);
EXPECT_FLOAT_EQ(result.Y, -4.0f);
EXPECT_FLOAT_EQ(result.Z, -4.0f);
EXPECT_FLOAT_EQ(result.W, -4.0f);
}
#ifdef __cplusplus
{
hmm_vec4 result = HMM_Subtract(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, -4.0f);
EXPECT_FLOAT_EQ(result.Y, -4.0f);
EXPECT_FLOAT_EQ(result.Z, -4.0f);
EXPECT_FLOAT_EQ(result.W, -4.0f);
}
{
hmm_vec4 result = v4_1 - v4_2;
EXPECT_FLOAT_EQ(result.X, -4.0f);
EXPECT_FLOAT_EQ(result.Y, -4.0f);
EXPECT_FLOAT_EQ(result.Z, -4.0f);
EXPECT_FLOAT_EQ(result.W, -4.0f);
}
v4_1 -= v4_2;
EXPECT_FLOAT_EQ(v4_1.X, -4.0f);
EXPECT_FLOAT_EQ(v4_1.Y, -4.0f);
EXPECT_FLOAT_EQ(v4_1.Z, -4.0f);
EXPECT_FLOAT_EQ(v4_1.W, -4.0f);
#endif
}
TEST(Subtraction, Mat4)
{
hmm_mat4 m4_1 = HMM_Mat4(); // will have 1 - 16
hmm_mat4 m4_2 = HMM_Mat4(); // will have 17 - 32
// Fill the matrices
int Counter = 1;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
m4_1.Elements[Column][Row] = Counter;
++Counter;
}
}
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
m4_2.Elements[Column][Row] = Counter;
++Counter;
}
}
// Test the results
{
hmm_mat4 result = HMM_SubtractMat4(m4_1, m4_2);
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
EXPECT_FLOAT_EQ(result.Elements[Column][Row], -16.0f);
}
}
}
#ifdef __cplusplus
{
hmm_mat4 result = HMM_Subtract(m4_1, m4_2);
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
EXPECT_FLOAT_EQ(result.Elements[Column][Row], -16.0f);
}
}
}
{
hmm_mat4 result = m4_1 - m4_2;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
EXPECT_FLOAT_EQ(result.Elements[Column][Row], -16.0f);
}
}
}
m4_1 -= m4_2;
for (int Column = 0; Column < 4; ++Column)
{
for (int Row = 0; Row < 4; ++Row)
{
EXPECT_FLOAT_EQ(m4_1.Elements[Column][Row], -16.0f);
}
}
#endif
}
TEST(Subtraction, Quaternion)
{
hmm_quaternion q1 = HMM_Quaternion(1.0f, 2.0f, 3.0f, 4.0f);
hmm_quaternion q2 = HMM_Quaternion(5.0f, 6.0f, 7.0f, 8.0f);
{
hmm_quaternion result = HMM_SubtractQuaternion(q1, q2);
EXPECT_FLOAT_EQ(result.X, -4.0f);
EXPECT_FLOAT_EQ(result.Y, -4.0f);
EXPECT_FLOAT_EQ(result.Z, -4.0f);
EXPECT_FLOAT_EQ(result.W, -4.0f);
}
#ifdef __cplusplus
{
hmm_quaternion result = HMM_Subtract(q1, q2);
EXPECT_FLOAT_EQ(result.X, -4.0f);
EXPECT_FLOAT_EQ(result.Y, -4.0f);
EXPECT_FLOAT_EQ(result.Z, -4.0f);
EXPECT_FLOAT_EQ(result.W, -4.0f);
}
{
hmm_quaternion result = q1 - q2;
EXPECT_FLOAT_EQ(result.X, -4.0f);
EXPECT_FLOAT_EQ(result.Y, -4.0f);
EXPECT_FLOAT_EQ(result.Z, -4.0f);
EXPECT_FLOAT_EQ(result.W, -4.0f);
}
q1 -= q2;
EXPECT_FLOAT_EQ(q1.X, -4.0f);
EXPECT_FLOAT_EQ(q1.Y, -4.0f);
EXPECT_FLOAT_EQ(q1.Z, -4.0f);
EXPECT_FLOAT_EQ(q1.W, -4.0f);
#endif
}

View File

@@ -0,0 +1,77 @@
#include "../HandmadeTest.h"
TEST(Transformations, Translate)
{
hmm_mat4 translate = HMM_Translate(HMM_Vec3(1.0f, -3.0f, 6.0f));
hmm_vec3 original = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec4 translated = HMM_MultiplyMat4ByVec4(translate, HMM_Vec4v(original, 1));
EXPECT_FLOAT_EQ(translated.X, 2.0f);
EXPECT_FLOAT_EQ(translated.Y, -1.0f);
EXPECT_FLOAT_EQ(translated.Z, 9.0f);
EXPECT_FLOAT_EQ(translated.W, 1.0f);
}
TEST(Transformations, Rotate)
{
hmm_vec3 original = HMM_Vec3(1.0f, 1.0f, 1.0f);
hmm_mat4 rotateX = HMM_Rotate(90, HMM_Vec3(1, 0, 0));
hmm_vec4 rotatedX = HMM_MultiplyMat4ByVec4(rotateX, HMM_Vec4v(original, 1));
EXPECT_FLOAT_EQ(rotatedX.X, 1.0f);
EXPECT_FLOAT_EQ(rotatedX.Y, -1.0f);
EXPECT_FLOAT_EQ(rotatedX.Z, 1.0f);
EXPECT_FLOAT_EQ(rotatedX.W, 1.0f);
hmm_mat4 rotateY = HMM_Rotate(90, HMM_Vec3(0, 1, 0));
hmm_vec4 rotatedY = HMM_MultiplyMat4ByVec4(rotateY, HMM_Vec4v(original, 1));
EXPECT_FLOAT_EQ(rotatedY.X, 1.0f);
EXPECT_FLOAT_EQ(rotatedY.Y, 1.0f);
EXPECT_FLOAT_EQ(rotatedY.Z, -1.0f);
EXPECT_FLOAT_EQ(rotatedY.W, 1.0f);
hmm_mat4 rotateZ = HMM_Rotate(90, HMM_Vec3(0, 0, 1));
hmm_vec4 rotatedZ = HMM_MultiplyMat4ByVec4(rotateZ, HMM_Vec4v(original, 1));
EXPECT_FLOAT_EQ(rotatedZ.X, -1.0f);
EXPECT_FLOAT_EQ(rotatedZ.Y, 1.0f);
EXPECT_FLOAT_EQ(rotatedZ.Z, 1.0f);
EXPECT_FLOAT_EQ(rotatedZ.W, 1.0f);
}
TEST(Transformations, Scale)
{
hmm_mat4 scale = HMM_Scale(HMM_Vec3(2.0f, -3.0f, 0.5f));
hmm_vec3 original = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec4 scaled = HMM_MultiplyMat4ByVec4(scale, HMM_Vec4v(original, 1));
EXPECT_FLOAT_EQ(scaled.X, 2.0f);
EXPECT_FLOAT_EQ(scaled.Y, -6.0f);
EXPECT_FLOAT_EQ(scaled.Z, 1.5f);
EXPECT_FLOAT_EQ(scaled.W, 1.0f);
}
TEST(Transformations, LookAt)
{
const float abs_error = 0.0001f;
hmm_mat4 result = HMM_LookAt(HMM_Vec3(1.0f, 0.0f, 0.0f), HMM_Vec3(0.0f, 2.0f, 1.0f), HMM_Vec3(2.0f, 1.0f, 1.0f));
EXPECT_NEAR(result.Elements[0][0], 0.169031f, abs_error);
EXPECT_NEAR(result.Elements[0][1], 0.897085f, abs_error);
EXPECT_NEAR(result.Elements[0][2], 0.408248f, abs_error);
EXPECT_FLOAT_EQ(result.Elements[0][3], 0.0f);
EXPECT_NEAR(result.Elements[1][0], 0.507093f, abs_error);
EXPECT_NEAR(result.Elements[1][1], 0.276026f, abs_error);
EXPECT_NEAR(result.Elements[1][2], -0.816497f, abs_error);
EXPECT_FLOAT_EQ(result.Elements[1][3], 0.0f);
EXPECT_NEAR(result.Elements[2][0], -0.845154f, abs_error);
EXPECT_NEAR(result.Elements[2][1], 0.345033f, abs_error);
EXPECT_NEAR(result.Elements[2][2], -0.408248f, abs_error);
EXPECT_FLOAT_EQ(result.Elements[2][3], 0.0f);
EXPECT_NEAR(result.Elements[3][0], -0.169031f, abs_error);
EXPECT_NEAR(result.Elements[3][1], -0.897085f, abs_error);
EXPECT_NEAR(result.Elements[3][2], -0.408248f, abs_error);
EXPECT_FLOAT_EQ(result.Elements[3][3], 1.0f);
}

194
test/categories/VectorOps.h Normal file
View File

@@ -0,0 +1,194 @@
#include "../HandmadeTest.h"
TEST(VectorOps, LengthSquared)
{
hmm_vec2 v2 = HMM_Vec2(1.0f, -2.0f);
hmm_vec3 v3 = HMM_Vec3(1.0f, -2.0f, 3.0f);
hmm_vec4 v4 = HMM_Vec4(1.0f, -2.0f, 3.0f, 1.0f);
EXPECT_FLOAT_EQ(HMM_LengthSquaredVec2(v2), 5.0f);
EXPECT_FLOAT_EQ(HMM_LengthSquaredVec3(v3), 14.0f);
EXPECT_FLOAT_EQ(HMM_LengthSquaredVec4(v4), 15.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(HMM_LengthSquared(v2), 5.0f);
EXPECT_FLOAT_EQ(HMM_LengthSquared(v3), 14.0f);
EXPECT_FLOAT_EQ(HMM_LengthSquared(v4), 15.0f);
#endif
}
TEST(VectorOps, Length)
{
hmm_vec2 v2 = HMM_Vec2(1.0f, -9.0f);
hmm_vec3 v3 = HMM_Vec3(2.0f, -3.0f, 6.0f);
hmm_vec4 v4 = HMM_Vec4(2.0f, -3.0f, 6.0f, 12.0f);
EXPECT_FLOAT_EQ(HMM_LengthVec2(v2), 9.0553856f);
EXPECT_FLOAT_EQ(HMM_LengthVec3(v3), 7.0f);
EXPECT_FLOAT_EQ(HMM_LengthVec4(v4), 13.892444f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(HMM_Length(v2), 9.0553856f);
EXPECT_FLOAT_EQ(HMM_Length(v3), 7.0f);
EXPECT_FLOAT_EQ(HMM_Length(v4), 13.892444f);
#endif
}
TEST(VectorOps, Normalize)
{
hmm_vec2 v2 = HMM_Vec2(1.0f, -2.0f);
hmm_vec3 v3 = HMM_Vec3(1.0f, -2.0f, 3.0f);
hmm_vec4 v4 = HMM_Vec4(1.0f, -2.0f, 3.0f, -1.0f);
{
hmm_vec2 result = HMM_NormalizeVec2(v2);
EXPECT_FLOAT_EQ(HMM_LengthVec2(result), 1.0f);
EXPECT_GT(result.X, 0.0f);
EXPECT_LT(result.Y, 0.0f);
}
{
hmm_vec3 result = HMM_NormalizeVec3(v3);
EXPECT_FLOAT_EQ(HMM_LengthVec3(result), 1.0f);
EXPECT_GT(result.X, 0.0f);
EXPECT_LT(result.Y, 0.0f);
EXPECT_GT(result.Z, 0.0f);
}
{
hmm_vec4 result = HMM_NormalizeVec4(v4);
EXPECT_FLOAT_EQ(HMM_LengthVec4(result), 1.0f);
EXPECT_GT(result.X, 0.0f);
EXPECT_LT(result.Y, 0.0f);
EXPECT_GT(result.Z, 0.0f);
EXPECT_LT(result.W, 0.0f);
}
#ifdef __cplusplus
{
hmm_vec2 result = HMM_Normalize(v2);
EXPECT_FLOAT_EQ(HMM_LengthVec2(result), 1.0f);
EXPECT_GT(result.X, 0.0f);
EXPECT_LT(result.Y, 0.0f);
}
{
hmm_vec3 result = HMM_Normalize(v3);
EXPECT_FLOAT_EQ(HMM_LengthVec3(result), 1.0f);
EXPECT_GT(result.X, 0.0f);
EXPECT_LT(result.Y, 0.0f);
EXPECT_GT(result.Z, 0.0f);
}
{
hmm_vec4 result = HMM_Normalize(v4);
EXPECT_FLOAT_EQ(HMM_LengthVec4(result), 1.0f);
EXPECT_GT(result.X, 0.0f);
EXPECT_LT(result.Y, 0.0f);
EXPECT_GT(result.Z, 0.0f);
EXPECT_LT(result.W, 0.0f);
}
#endif
}
TEST(VectorOps, NormalizeZero)
{
hmm_vec2 v2 = HMM_Vec2(0.0f, 0.0f);
hmm_vec3 v3 = HMM_Vec3(0.0f, 0.0f, 0.0f);
hmm_vec4 v4 = HMM_Vec4(0.0f, 0.0f, 0.0f, 0.0f);
{
hmm_vec2 result = HMM_NormalizeVec2(v2);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
}
{
hmm_vec3 result = HMM_NormalizeVec3(v3);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
EXPECT_FLOAT_EQ(result.Z, 0.0f);
}
{
hmm_vec4 result = HMM_NormalizeVec4(v4);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
EXPECT_FLOAT_EQ(result.Z, 0.0f);
EXPECT_FLOAT_EQ(result.W, 0.0f);
}
#ifdef __cplusplus
{
hmm_vec2 result = HMM_Normalize(v2);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
}
{
hmm_vec3 result = HMM_Normalize(v3);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
EXPECT_FLOAT_EQ(result.Z, 0.0f);
}
{
hmm_vec4 result = HMM_Normalize(v4);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
EXPECT_FLOAT_EQ(result.Z, 0.0f);
EXPECT_FLOAT_EQ(result.W, 0.0f);
}
#endif
}
TEST(VectorOps, Cross)
{
{
// Normal cross
hmm_vec3 v1 = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 v2 = HMM_Vec3(4.0f, 5.0f, 6.0f);
hmm_vec3 result = HMM_Cross(v1, v2);
EXPECT_FLOAT_EQ(result.X, -3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, -3.0f);
}
{
// Vector with itself
hmm_vec3 v = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 result = HMM_Cross(v, v);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
EXPECT_FLOAT_EQ(result.Z, 0.0f);
}
}
TEST(VectorOps, DotVec2)
{
hmm_vec2 v1 = HMM_Vec2(1.0f, 2.0f);
hmm_vec2 v2 = HMM_Vec2(3.0f, 4.0f);
EXPECT_FLOAT_EQ(HMM_DotVec2(v1, v2), 11.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 11.0f);
#endif
}
TEST(VectorOps, DotVec3)
{
hmm_vec3 v1 = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 v2 = HMM_Vec3(4.0f, 5.0f, 6.0f);
EXPECT_FLOAT_EQ(HMM_DotVec3(v1, v2), 32.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 32.0f);
#endif
}
TEST(VectorOps, DotVec4)
{
hmm_vec4 v1 = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
hmm_vec4 v2 = HMM_Vec4(5.0f, 6.0f, 7.0f, 8.0f);
EXPECT_FLOAT_EQ(HMM_DotVec4(v1, v2), 70.0f);
#ifdef __cplusplus
EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 70.0f);
#endif
}

File diff suppressed because it is too large Load Diff

18
test/hmm_test.h Normal file
View File

@@ -0,0 +1,18 @@
#include <float.h>
#include "HandmadeTest.h"
#include "../HandmadeMath.h"
#include "categories/Addition.h"
#include "categories/Division.h"
#include "categories/Equality.h"
#include "categories/Initialization.h"
#include "categories/MatrixOps.h"
#include "categories/Multiplication.h"
#include "categories/Projection.h"
#include "categories/QuaternionOps.h"
#include "categories/ScalarMath.h"
#include "categories/SSE.h"
#include "categories/Subtraction.h"
#include "categories/Transformation.h"
#include "categories/VectorOps.h"

29
test/initializer.h Normal file
View File

@@ -0,0 +1,29 @@
// Initializer/finalizer sample for MSVC and GCC/Clang.
// 2010-2016 Joe Lowe. Released into the public domain.
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
#define _INITIALIZER_T(f) f##_t_
#define _INITIALIZER_U(f) f##_
#define INITIALIZER(f) \
static void f(void); \
struct _INITIALIZER_T(f) { _INITIALIZER_T(f)(void) { f(); } }; static _INITIALIZER_T(f) _INITIALIZER_U(f); \
static void f(void)
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif