Compare commits

..

17 Commits

Author SHA1 Message Date
Ben Visness
c825fe48cf Update version and release notes 2020-04-06 10:02:16 -05:00
Ben Visness
15bef820db Add ability to customize HMM_ prefix (#114)
* Add prefix macro and use it everywhere

* Add lightweight test for prefix

* Add a little doc blurb
2020-04-06 09:57:10 -05:00
Ben Visness
fe32f081f2 Suppress float equality warnings (#113)
* Add a macro to help with deprecations

* Suppress warnings about float equality
2020-04-06 09:55:40 -05:00
Zak Strange
785f19d4a7 Removed use of stdint.h (#110) 2020-01-11 17:13:09 -08:00
Ben Visness
a9b08b9147 Run tests on Linux, macOS, and Windows (#105)
* Try running tests on all three operating systems

* Try adding an MSVC build

* Make tests work on Windows

* Try reconfiguring Travis for this

* Maybe it's because we're in git bash

* Try explicitly doing something else for travis

* Remove a part I think is unnecessary

* Run the test EXEs as they compile
2019-07-31 17:22:33 -05:00
Ben Visness
f376f2a2a7 Add test coverage macros (#104)
* Add coverage features and add it, laboriously, to everything

* Fix easy tests

* Add tests for != operators

* Clean up test framework a little

* Add documentation of coverage macros

* Fix tests for mat4 to quaternion

* Slightly improve formatting of coverage output

* Trailing whitespace must die
2019-07-31 16:43:56 -05:00
Ben Visness
78e6feea82 Add HMM_Mat4ToQuaternion (#103)
* Add mat4 to quaternion method

* Capitalize variables
2019-07-31 16:38:03 -05:00
Zak Strange
21aa828a08 Fixed issue related to unsigned/signed-ness of HMM_Power (#102)
* Fixed issue related to unsigned/signed-ness of HMM_Power

* Fixes missing braces around initializer warning with -Weverything with GCC.
2019-07-17 14:48:59 -07:00
Ben Visness
93e56be543 Use vertical instead of horizontal FOV in HMM_Perspective (#101)
* Use vertical instead of horizontal FOV

* Update readme

* Fix tests
2019-07-10 11:29:51 -05:00
Ben Visness
45c91702a9 Added SSE support for Quaternion operations (#97) (#98)
* Added SSE support for Quaternion operations (#97)

* Added SSE support for Quaternion operations

O2
| Function    |     SSE         |      NO SSE      |
====================================================
| Inverse     |     163 (0.89s) |      165 (1.89s) |
| NLerp       |     330 (1.70s) |      330 (1.75s) |
| Normalize   |     169 (1.03s) |      169 (1.06s) |
| Dot         |     22  (1.15s) |      23  (1.14s) |
| DivF        |     23  (0.72s) |      23  (0.82s) |
| MulF        |     22  (0.75s) |      22  (0.79s) |
| Mul         |     24  (1.14s) |      23  (1.24s) |
| Sub         |     23  (1.17s) |      37  (1.20s) |
| Add         |     23  (1.20s) |      24  (1.19s) |



O0
| Function    |     SSE         |      NO SSE      |
====================================================
| Inverse     |     394 (1.62s) |      430 (3.05s) |
| NLerp       |     694 (2.71s) |      1035(4.81s) |
| Normalize   |     374 (1.58s) |      412 (2.95s) |
| Dot         |     81  (1.83s) |      23  (2.50s) |
| DivF        |     61  (1.12s) |      25  (2.37s) |
| MulF        |     58  (1.09s) |      23  (2.31s) |
| Mul         |     94  (1.97s) |      42  (2.88s) |
| Sub         |     75  (1.83s) |      23  (2.82s) |
| Add         |     75  (1.81s) |      23  (2.81s) |

* Fixed quaternion multiplication

Old quaternion multiplication had a bug, this is a different approach.

* Added release notes and version for 1.9.0
2019-03-11 13:12:48 -05:00
Ben Visness
f7c8e1f7d1 Add fast vector normalization (#94)
* Add fast normalization routines

* Update readme and remove version history from main file

* Update version at top of file
2018-11-29 22:02:41 -08:00
Ben Visness
5ca1d58b36 Improve grammar/spelling 2018-11-29 13:21:05 -06:00
Zak Strange
5bf727dbd5 Removed copy in operator[] (#93)
* Removed copy in operator[]

* Updated version info
2018-11-29 09:32:12 -08:00
Ben Visness
295f6c476f Rename Rows to Columns on hmm_mat4 (#91) 2018-08-17 11:02:44 -07:00
Ben Visness
e095aefaf7 Bump file version 2018-06-10 15:32:12 -04:00
Ben Visness
4e2f47db55 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-06-10 15:26:48 -04:00
Ben Visness
bee0e0c569 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-06-03 18:42:09 -05:00
58 changed files with 2088 additions and 46838 deletions

9
.editorconfig Normal file
View File

@@ -0,0 +1,9 @@
root = true
[*.{c,cpp,h}]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

3
.gitignore vendored
View File

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

3
.gitmodules vendored
View File

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

View File

@@ -1,12 +1,23 @@
language: cpp language: cpp
os:
- linux
- osx
compiler: compiler:
- clang - clang
- gcc - gcc
matrix:
include:
# Windows x64 builds (MSVC)
- os: windows
script:
- ./test.bat travis
before_install:
- eval "${MATRIX_EVAL}"
install: install:
- cd test - cd test
- make
script: script:
- build/hmm_test_c - make c
- build/hmm_test_c_no_sse - make c_no_sse
- build/hmm_test_cpp - make cpp
- build/hmm_test_cpp_no_sse - make cpp_no_sse

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,13 @@ To get started, go download [the latest release](https://github.com/HandmadeMath
Version | Changes | Version | Changes |
----------------|----------------| ----------------|----------------|
**1.11.0** | Added ability to customize or remove the default `HMM_` prefix on function names by defining a macro called `HMM_PREFIX(name)`. |
**1.10.1** | Removed stdint.h, this doesn't exist on some really old compilers and we didn't really use it anyways. |
**1.10.0** | Made HMM_Perspective use vertical FOV instead of horizontal FOV for consistency with other graphics APIs. |
**1.9.0** | Added SSE versions of quaternion operations. |
**1.8.0** | Added fast vector normalization routines that use fast inverse square roots.
**1.7.1** | Changed operator[] to take a const ref int instead of an int.
**1.7.0** | Renamed the 'Rows' member of hmm_mat4 to 'Columns'. Since our matrices are column-major, this should have been named 'Columns' from the start. 'Rows' is still present, but has been deprecated.
**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.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.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.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.

Binary file not shown.

View File

@@ -1,10 +0,0 @@
# 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

View File

@@ -1,481 +0,0 @@
# 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

View File

@@ -1,22 +0,0 @@
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

View File

@@ -1,10 +0,0 @@
# 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

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +0,0 @@
# 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

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
@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

View File

@@ -1,73 +0,0 @@
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.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Submodule example/external/glfw deleted from 617a322bd8

View File

@@ -1,22 +0,0 @@
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

@@ -1,456 +0,0 @@
/*************************************************************************
* 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_ */

View File

@@ -1,5 +0,0 @@
@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

View File

@@ -1,161 +0,0 @@
#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

View File

@@ -1,119 +0,0 @@
#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

View File

@@ -1,62 +0,0 @@
#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

View File

@@ -1,71 +0,0 @@
#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

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

View File

@@ -1,179 +0,0 @@
#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

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

View File

@@ -1,28 +0,0 @@
#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

View File

@@ -1,18 +0,0 @@
#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;
}

View File

@@ -1,19 +0,0 @@
#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

View File

@@ -1,190 +0,0 @@
#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);
}
}

View File

@@ -1,94 +0,0 @@
#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;
}

View File

@@ -1,9 +0,0 @@
#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

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +0,0 @@
#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,3 +1,7 @@
#ifndef WITHOUT_COVERAGE
#include "HandmadeTest.h"
#endif
#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

@@ -0,0 +1,12 @@
#define HMM_PREFIX(name) WOW_##name
#define HANDMADE_MATH_IMPLEMENTATION
#define HANDMADE_MATH_NO_INLINE
#include "../HandmadeMath.h"
int main() {
hmm_vec4 a = WOW_Vec4(1, 2, 3, 4);
hmm_vec4 b = WOW_Vec4(5, 6, 7, 8);
WOW_Add(a, b);
}

View File

@@ -4,6 +4,12 @@
This is Handmade Math's test framework. It is fully compatible with both C This is Handmade Math's test framework. It is fully compatible with both C
and C++, although it requires some compiler-specific features. and C++, although it requires some compiler-specific features.
To use Handmade Test, you must #define HANDMADE_TEST_IMPLEMENTATION in
exactly one C or C++ file that includes the header, like this:
#define HANDMADE_TEST_IMPLEMENTATION
#include "HandmadeTest.h"
The basic way of creating a test is using the TEST macro, which registers a The basic way of creating a test is using the TEST macro, which registers a
single test to be run: single test to be run:
@@ -11,11 +17,32 @@
// test code, including asserts/expects // test code, including asserts/expects
} }
The main function of your test code should then call hmt_run_all_tests and Handmade Test also provides macros you can use to check the coverage of
return the result: important parts of your code. Define a coverage case by using the COVERAGE
macro outside the function you wish to test, providing both a name and the
number of asserts you expect to see covered over the course of your test.
Then use the ASSERT_COVERED macro in every part of the function you wish to
check coverage on. For example:
COVERAGE(MyCoverageCase, 3)
void MyFunction(int a, int b) {
if (a > b) {
ASSERT_COVERED(MyCoverageCase);
return 10;
} else if (a < b) {
ASSERT_COVERED(MyCoverageCase);
return -10;
}
ASSERT_COVERED(MyCoverageCase);
return 0;
}
The main function of your test code should then call hmt_run_all_tests (and
optionally hmt_check_all_coverage) and return the result:
int main() { int main() {
return hmt_run_all_tests(); return hmt_run_all_tests() || hmt_check_all_coverage();
} }
============================================================================= =============================================================================
@@ -40,7 +67,7 @@
#define HMT_RED "\033[31m" #define HMT_RED "\033[31m"
#define HMT_GREEN "\033[32m" #define HMT_GREEN "\033[32m"
#define HMT_INITIAL_ARRAY_SIZE 1024 #define HMT_ARRAY_SIZE 1024
typedef struct hmt_testresult_struct { typedef struct hmt_testresult_struct {
int count_cases; int count_cases;
@@ -57,20 +84,137 @@ typedef struct hmt_test_struct {
typedef struct hmt_category_struct { typedef struct hmt_category_struct {
const char* name; const char* name;
int num_tests; int num_tests;
int tests_capacity;
hmt_test* tests; hmt_test* tests;
} hmt_category; } hmt_category;
int hmt_num_categories = 0; typedef struct hmt_covercase_struct {
int hmt_category_capacity = HMT_INITIAL_ARRAY_SIZE; const char* name;
hmt_category* categories = 0; int expected_asserts;
int actual_asserts;
int* asserted_lines;
} hmt_covercase;
hmt_category _hmt_new_category(const char* name);
hmt_test _hmt_new_test(const char* name, hmt_test_func func);
hmt_covercase _hmt_new_covercase(const char* name, int expected);
void _hmt_register_test(const char* category, const char* name, hmt_test_func func);
void _hmt_register_covercase(const char* name, const char* expected_asserts);
void _hmt_count_cover(const char* name, int line);
#define _HMT_TEST_FUNCNAME(category, name) _hmt_test_ ## category ## _ ## name
#define _HMT_TEST_FUNCNAME_INIT(category, name) _hmt_test_ ## category ## _ ## name ## _init
#define _HMT_COVERCASE_FUNCNAME_INIT(name) _hmt_covercase_ ## 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] (line %d) " HMT_RESET, __LINE__);
#define HMT_COVERAGE(name, num_asserts) \
INITIALIZER(_HMT_COVERCASE_FUNCNAME_INIT(name)) { \
_hmt_register_covercase(#name, #num_asserts); \
} \
#define HMT_ASSERT_COVERED(name) \
{ \
_hmt_count_cover(#name, __LINE__); \
} \
/*
* Asserts and expects
*/
#define HMT_EXPECT_TRUE(_actual) { \
_HMT_CASE_START(); \
if (!(_actual)) { \
_HMT_CASE_FAIL(); \
printf("Expected true but got something false"); \
} \
} \
#define HMT_EXPECT_FALSE(_actual) { \
_HMT_CASE_START(); \
if (_actual) { \
_HMT_CASE_FAIL(); \
printf("Expected false but got something true"); \
} \
} \
#define HMT_EXPECT_FLOAT_EQ(_actual, _expected) { \
_HMT_CASE_START(); \
float actual = (_actual); \
float diff = actual - (_expected); \
if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \
_HMT_CASE_FAIL(); \
printf("Expected %f, got %f", (_expected), actual); \
} \
} \
#define HMT_EXPECT_NEAR(_actual, _expected, _epsilon) { \
_HMT_CASE_START(); \
float actual = (_actual); \
float diff = actual - (_expected); \
if (diff < -(_epsilon) || (_epsilon) < diff) { \
_HMT_CASE_FAIL(); \
printf("Expected %f, got %f", (_expected), actual); \
} \
} \
#define HMT_EXPECT_LT(_actual, _expected) { \
_HMT_CASE_START(); \
if ((_actual) >= (_expected)) { \
_HMT_CASE_FAIL(); \
printf("Expected %f to be less than %f", (_actual), (_expected)); \
} \
} \
#define HMT_EXPECT_GT(_actual, _expected) { \
_HMT_CASE_START(); \
if ((_actual) <= (_expected)) { \
_HMT_CASE_FAIL(); \
printf("Expected %f to be greater than %f", (_actual), (_expected)); \
} \
} \
#ifndef HMT_SAFE_MACROS
// Friendly defines
#define TEST(category, name) HMT_TEST(category, name)
#define COVERAGE(name, expected_asserts) HMT_COVERAGE(name, expected_asserts)
#define ASSERT_COVERED(name) HMT_ASSERT_COVERED(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
#ifdef HANDMADE_TEST_IMPLEMENTATION
#ifndef HANDMADE_TEST_IMPLEMENTATION_GUARD
#define HANDMADE_TEST_IMPLEMENTATION_GUARD
int _hmt_num_categories = 0;
hmt_category* _hmt_categories = 0;
int _hmt_num_covercases = 0;
hmt_covercase* _hmt_covercases = 0;
hmt_category _hmt_new_category(const char* name) { hmt_category _hmt_new_category(const char* name) {
hmt_category cat = { hmt_category cat = {
.name = name, name, // name
.num_tests = 0, 0, // num_tests
.tests_capacity = HMT_INITIAL_ARRAY_SIZE, (hmt_test*) malloc(HMT_ARRAY_SIZE * sizeof(hmt_test)), // tests
.tests = (hmt_test*) malloc(HMT_INITIAL_ARRAY_SIZE * sizeof(hmt_test))
}; };
return cat; return cat;
@@ -78,59 +222,104 @@ hmt_category _hmt_new_category(const char* name) {
hmt_test _hmt_new_test(const char* name, hmt_test_func func) { hmt_test _hmt_new_test(const char* name, hmt_test_func func) {
hmt_test test = { hmt_test test = {
.name = name, name, // name
.func = func func, // func
}; };
return test; return test;
} }
int hmt_register_test(const char* category, const char* name, hmt_test_func func) { hmt_covercase _hmt_new_covercase(const char* name, int expected) {
hmt_covercase covercase = {
name, // name
expected, // expected_asserts
0, // actual_asserts
(int*) malloc(HMT_ARRAY_SIZE * sizeof(int)), // asserted_lines
};
return covercase;
}
void _hmt_register_test(const char* category, const char* name, hmt_test_func func) {
// initialize categories array if not initialized // initialize categories array if not initialized
if (!categories) { if (!_hmt_categories) {
categories = (hmt_category*) malloc(hmt_category_capacity * sizeof(hmt_category)); _hmt_categories = (hmt_category*) malloc(HMT_ARRAY_SIZE * sizeof(hmt_category));
} }
// Find the matching category, if possible // Find the matching category, if possible
int cat_index; int cat_index;
for (cat_index = 0; cat_index < hmt_num_categories; cat_index++) { for (cat_index = 0; cat_index < _hmt_num_categories; cat_index++) {
if (strcmp(categories[cat_index].name, category) == 0) { if (strcmp(_hmt_categories[cat_index].name, category) == 0) {
break; 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 // Add a new category if necessary
if (cat_index >= hmt_num_categories) { if (cat_index >= _hmt_num_categories) {
categories[cat_index] = _hmt_new_category(category); _hmt_categories[cat_index] = _hmt_new_category(category);
hmt_num_categories++; _hmt_num_categories++;
} }
hmt_category* cat = &categories[cat_index]; hmt_category* cat = &_hmt_categories[cat_index];
// Add the test to the category // 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->tests[cat->num_tests] = _hmt_new_test(name, func);
cat->num_tests++; cat->num_tests++;
}
void _hmt_register_covercase(const char* name, const char* expected_asserts) {
// initialize cases array if not initialized
if (!_hmt_covercases) {
_hmt_covercases = (hmt_covercase*) malloc(HMT_ARRAY_SIZE * sizeof(hmt_covercase));
}
// check for existing case with that name, because the macro can run multiple
// times in different translation units
for (int i = 0; i < _hmt_num_covercases; i++) {
if (strcmp(_hmt_covercases[i].name, name) == 0) {
return;
}
}
_hmt_covercases[_hmt_num_covercases] = _hmt_new_covercase(name, atoi(expected_asserts));
_hmt_num_covercases++;
}
hmt_covercase* _hmt_find_covercase(const char* name) {
for (int i = 0; i < _hmt_num_covercases; i++) {
if (strcmp(_hmt_covercases[i].name, name) == 0) {
return &_hmt_covercases[i];
}
}
return 0; return 0;
} }
void _hmt_count_cover(const char* name, int line) {
hmt_covercase* covercase = _hmt_find_covercase(name);
if (covercase == 0) {
printf(HMT_RED "ERROR (line %d): Could not find coverage case with name \"%s\".\n" HMT_RESET, line, name);
return;
}
// see if this line has already been covered
for (int i = 0; i < covercase->actual_asserts; i++) {
if (covercase->asserted_lines[i] == line) {
return;
}
}
covercase->asserted_lines[covercase->actual_asserts] = line;
covercase->actual_asserts++;
}
int hmt_run_all_tests() { int hmt_run_all_tests() {
int count_alltests = 0; int count_alltests = 0;
int count_allfailedtests = 0; // failed test cases int count_allfailedtests = 0; // failed test cases
int count_allfailures = 0; // failed asserts int count_allfailures = 0; // failed asserts
for (int i = 0; i < hmt_num_categories; i++) { for (int i = 0; i < _hmt_num_categories; i++) {
hmt_category cat = categories[i]; hmt_category cat = _hmt_categories[i];
int count_catfailedtests = 0; int count_catfailedtests = 0;
int count_catfailures = 0; int count_catfailures = 0;
@@ -142,8 +331,8 @@ int hmt_run_all_tests() {
printf(" %s:", test.name); printf(" %s:", test.name);
hmt_testresult result = { hmt_testresult result = {
.count_cases = 0, 0, // count_cases
.count_failures = 0 0, // count_failures
}; };
test.func(&result); test.func(&result);
@@ -177,87 +366,33 @@ int hmt_run_all_tests() {
return (count_allfailedtests > 0); return (count_allfailedtests > 0);
} }
#define _HMT_TEST_FUNCNAME(category, name) category ## _ ## name int hmt_check_all_coverage() {
#define _HMT_TEST_FUNCNAME_INIT(category, name) category ## _ ## name ## _init printf("Coverage:\n");
#define HMT_TEST(category, name) \ int count_failures = 0;
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() \ for (int i = 0; i < _hmt_num_covercases; i++) {
_result->count_cases++; hmt_covercase covercase = _hmt_covercases[i];
#define _HMT_CASE_FAIL() \ if (covercase.expected_asserts != covercase.actual_asserts) {
_result->count_failures++; \ count_failures++;
printf("\n - " HMT_RED "[FAIL] (%d) " HMT_RESET, __LINE__); printf("%s: " HMT_RED "FAIL (expected %d asserts, got %d)\n" HMT_RESET, covercase.name, covercase.expected_asserts, covercase.actual_asserts);
}
}
/* if (count_failures > 0) {
* Asserts and expects printf("\n");
*/ printf(HMT_RED);
#define HMT_EXPECT_TRUE(_actual) do { \ } else {
_HMT_CASE_START(); \ printf(HMT_GREEN);
if (!(_actual)) { \ }
_HMT_CASE_FAIL(); \ printf("%d coverage cases tested, %d failures\n", _hmt_num_covercases, count_failures);
printf("Expected true but got something false"); \ printf(HMT_RESET);
} \
} while (0)
#define HMT_EXPECT_FALSE(_actual) do { \ printf("\n");
_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 { \ return (count_failures > 0);
_HMT_CASE_START(); \ }
float actual = (_actual); \
float diff = actual - (_expected); \
if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \
_HMT_CASE_FAIL(); \
printf("Expected %f, got %f", (_expected), actual); \
} \
} while (0)
#define HMT_EXPECT_NEAR(_actual, _expected, _epsilon) do { \ #endif // HANDMADE_TEST_IMPLEMENTATION_GUARD
_HMT_CASE_START(); \ #endif // HANDMADE_TEST_IMPLEMENTATION
float actual = (_actual); \
float diff = actual - (_expected); \
if (diff < -(_epsilon) || (_epsilon) < diff) { \
_HMT_CASE_FAIL(); \
printf("Expected %f, got %f", (_expected), actual); \
} \
} while (0)
#define HMT_EXPECT_LT(_actual, _expected) do { \
_HMT_CASE_START(); \
if ((_actual) >= (_expected)) { \
_HMT_CASE_FAIL(); \
printf("Expected %f to be less than %f", (_actual), (_expected)); \
} \
} while (0)
#define HMT_EXPECT_GT(_actual, _expected) do { \
_HMT_CASE_START(); \
if ((_actual) <= (_expected)) { \
_HMT_CASE_FAIL(); \
printf("Expected %f to be greater than %f", (_actual), (_expected)); \
} \
} while (0)
#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,13 +1,18 @@
BUILD_DIR=build 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 -Wfloat-equal
all: c c_no_sse cpp cpp_no_sse all: c c_no_sse cpp cpp_no_sse build_c_without_coverage build_cpp_without_coverage build_cpp_different_prefix
build_all: build_c build_c_no_sse build_cpp build_cpp_no_sse
clean: clean:
rm -rf $(BUILD_DIR) rm -rf $(BUILD_DIR)
c: HandmadeMath.c test_impl c: build_c
$(BUILD_DIR)/hmm_test_c
build_c: HandmadeMath.c test_impl
@echo "\nCompiling in C mode" @echo "\nCompiling in C mode"
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR)\ cd $(BUILD_DIR)\
@@ -16,7 +21,10 @@ c: HandmadeMath.c test_impl
-lm \ -lm \
&& $(CC) -ohmm_test_c HandmadeMath.o hmm_test.o -lm && $(CC) -ohmm_test_c HandmadeMath.o hmm_test.o -lm
c_no_sse: HandmadeMath.c test_impl c_no_sse: build_c_no_sse
$(BUILD_DIR)/hmm_test_c_no_sse
build_c_no_sse: HandmadeMath.c test_impl
@echo "\nCompiling in C mode (no SSE)" @echo "\nCompiling in C mode (no SSE)"
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \ cd $(BUILD_DIR) \
@@ -26,7 +34,10 @@ c_no_sse: HandmadeMath.c test_impl
-lm \ -lm \
&& $(CC) -ohmm_test_c_no_sse HandmadeMath.o hmm_test.o -lm && $(CC) -ohmm_test_c_no_sse HandmadeMath.o hmm_test.o -lm
cpp: HandmadeMath.cpp test_impl cpp: build_cpp
$(BUILD_DIR)/hmm_test_cpp
build_cpp: HandmadeMath.cpp test_impl
@echo "\nCompiling in C++ mode" @echo "\nCompiling in C++ mode"
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \ cd $(BUILD_DIR) \
@@ -34,7 +45,10 @@ cpp: HandmadeMath.cpp test_impl
-DHANDMADE_MATH_CPP_MODE \ -DHANDMADE_MATH_CPP_MODE \
../HandmadeMath.cpp ../hmm_test.cpp ../HandmadeMath.cpp ../hmm_test.cpp
cpp_no_sse: HandmadeMath.cpp test_impl cpp_no_sse: build_cpp_no_sse
$(BUILD_DIR)/hmm_test_cpp_no_sse
build_cpp_no_sse: HandmadeMath.cpp test_impl
@echo "\nCompiling in C++ mode (no SSE)" @echo "\nCompiling in C++ mode (no SSE)"
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \ cd $(BUILD_DIR) \
@@ -43,3 +57,29 @@ cpp_no_sse: HandmadeMath.cpp test_impl
../HandmadeMath.cpp ../hmm_test.cpp ../HandmadeMath.cpp ../hmm_test.cpp
test_impl: hmm_test.cpp hmm_test.c test_impl: hmm_test.cpp hmm_test.c
build_c_without_coverage: HandmadeMath.c test_impl
@echo "\nCompiling in C mode"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR)\
&& $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 \
-DWITHOUT_COVERAGE \
-c ../HandmadeMath.c ../hmm_test.c \
-lm \
&& $(CC) -ohmm_test_c HandmadeMath.o hmm_test.o -lm
build_cpp_without_coverage: 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 -DWITHOUT_COVERAGE \
../HandmadeMath.cpp ../hmm_test.cpp
build_cpp_different_prefix: HandmadeMath.cpp
@echo "\nCompiling C++ with different prefix"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -ohmm_test_cpp_different_prefix \
-DHANDMADE_MATH_CPP_MODE -DDIFFERENT_PREFIX \
../HandmadeMathDifferentPrefix.cpp

View File

@@ -4,8 +4,13 @@ You can compile and run the tests yourself by running:
``` ```
make make
build/hmm_test_c ```
build/hmm_test_c_no_sse
build/hmm_test_cpp To run a specific test configuration, run one of:
build/hmm_test_cpp_no_sse
```
make c
make c_no_sse
make cpp
make cpp_no_sse
``` ```

View File

@@ -15,6 +15,9 @@ TEST(Equality, Vec2)
EXPECT_TRUE(a == b); EXPECT_TRUE(a == b);
EXPECT_FALSE(a == c); EXPECT_FALSE(a == c);
EXPECT_FALSE(a != b);
EXPECT_TRUE(a != c);
#endif #endif
} }
@@ -33,6 +36,9 @@ TEST(Equality, Vec3)
EXPECT_TRUE(a == b); EXPECT_TRUE(a == b);
EXPECT_FALSE(a == c); EXPECT_FALSE(a == c);
EXPECT_FALSE(a != b);
EXPECT_TRUE(a != c);
#endif #endif
} }
@@ -51,5 +57,8 @@ TEST(Equality, Vec4)
EXPECT_TRUE(a == b); EXPECT_TRUE(a == b);
EXPECT_FALSE(a == c); EXPECT_FALSE(a == c);
EXPECT_FALSE(a != b);
EXPECT_TRUE(a != c);
#endif #endif
} }

View File

@@ -6,7 +6,7 @@ TEST(Initialization, Vectors)
// Test vec2 // Test vec2
// //
hmm_vec2 v2 = HMM_Vec2(1.0f, 2.0f); hmm_vec2 v2 = HMM_Vec2(1.0f, 2.0f);
hmm_vec2 v2i = HMM_Vec2(1, 2); hmm_vec2 v2i = HMM_Vec2i(1, 2);
EXPECT_FLOAT_EQ(v2.X, 1.0f); EXPECT_FLOAT_EQ(v2.X, 1.0f);
EXPECT_FLOAT_EQ(v2.Y, 2.0f); EXPECT_FLOAT_EQ(v2.Y, 2.0f);

View File

@@ -1,154 +0,0 @@
#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

@@ -20,16 +20,16 @@ TEST(Projection, Perspective)
{ {
hmm_vec3 original = HMM_Vec3(5.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)); hmm_vec4 projected = HMM_MultiplyMat4ByVec4(projection, HMM_Vec4v(original, 1));
EXPECT_FLOAT_EQ(projected.X, 5.0f); EXPECT_FLOAT_EQ(projected.X, 2.5f);
EXPECT_FLOAT_EQ(projected.Y, 10.0f); EXPECT_FLOAT_EQ(projected.Y, 5.0f);
EXPECT_FLOAT_EQ(projected.Z, 15.0f); EXPECT_FLOAT_EQ(projected.Z, 15.0f);
EXPECT_FLOAT_EQ(projected.W, 15.0f); EXPECT_FLOAT_EQ(projected.W, 15.0f);
} }
{ {
hmm_vec3 original = HMM_Vec3(5.0f, 5.0f, -5.0f); hmm_vec3 original = HMM_Vec3(5.0f, 5.0f, -5.0f);
hmm_vec4 projected = HMM_MultiplyMat4ByVec4(projection, HMM_Vec4v(original, 1)); hmm_vec4 projected = HMM_MultiplyMat4ByVec4(projection, HMM_Vec4v(original, 1));
EXPECT_FLOAT_EQ(projected.X, 5.0f); EXPECT_FLOAT_EQ(projected.X, 2.5f);
EXPECT_FLOAT_EQ(projected.Y, 10.0f); EXPECT_FLOAT_EQ(projected.Y, 5.0f);
EXPECT_FLOAT_EQ(projected.Z, -5.0f); EXPECT_FLOAT_EQ(projected.Z, -5.0f);
EXPECT_FLOAT_EQ(projected.W, 5.0f); EXPECT_FLOAT_EQ(projected.W, 5.0f);
} }

View File

@@ -76,39 +76,10 @@ TEST(QuaternionOps, Slerp)
EXPECT_FLOAT_EQ(result.W, 0.86602540f); EXPECT_FLOAT_EQ(result.W, 0.86602540f);
} }
TEST(QuaternionOps, ToMat4) TEST(QuaternionOps, QuatToMat4)
{ {
const float abs_error = 0.0001f; 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_quaternion rot = HMM_Quaternion(0.707107f, 0.0f, 0.0f, 0.707107f);
hmm_mat4 result = HMM_QuaternionToMat4(rot); hmm_mat4 result = HMM_QuaternionToMat4(rot);
@@ -133,6 +104,66 @@ TEST(QuaternionOps, ToMat4)
EXPECT_NEAR(result.Elements[3][2], 0.0f, abs_error); EXPECT_NEAR(result.Elements[3][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][3], 1.0f, abs_error); EXPECT_NEAR(result.Elements[3][3], 1.0f, abs_error);
} }
TEST(QuaternionOps, Mat4ToQuat)
{
const float abs_error = 0.0001f;
// Rotate 90 degrees on the X axis
{
hmm_mat4 m = HMM_Rotate(90, HMM_Vec3(1, 0, 0));
hmm_quaternion result = HMM_Mat4ToQuaternion(m);
float cosf = 0.707107f; // cos(90/2 degrees)
float sinf = 0.707107f; // sin(90/2 degrees)
EXPECT_NEAR(result.X, sinf, abs_error);
EXPECT_NEAR(result.Y, 0.0f, abs_error);
EXPECT_NEAR(result.Z, 0.0f, abs_error);
EXPECT_NEAR(result.W, cosf, abs_error);
}
// Rotate 90 degrees on the Y axis (axis not normalized, just for fun)
{
hmm_mat4 m = HMM_Rotate(90, HMM_Vec3(0, 2, 0));
hmm_quaternion result = HMM_Mat4ToQuaternion(m);
float cosf = 0.707107f; // cos(90/2 degrees)
float sinf = 0.707107f; // sin(90/2 degrees)
EXPECT_NEAR(result.X, 0.0f, abs_error);
EXPECT_NEAR(result.Y, sinf, abs_error);
EXPECT_NEAR(result.Z, 0.0f, abs_error);
EXPECT_NEAR(result.W, cosf, abs_error);
}
// Rotate 90 degrees on the Z axis
{
hmm_mat4 m = HMM_Rotate(90, HMM_Vec3(0, 0, 1));
hmm_quaternion result = HMM_Mat4ToQuaternion(m);
float cosf = 0.707107f; // cos(90/2 degrees)
float sinf = 0.707107f; // sin(90/2 degrees)
EXPECT_NEAR(result.X, 0.0f, abs_error);
EXPECT_NEAR(result.Y, 0.0f, abs_error);
EXPECT_NEAR(result.Z, sinf, abs_error);
EXPECT_NEAR(result.W, cosf, abs_error);
}
// Rotate 45 degrees on the X axis (this hits case 4)
{
hmm_mat4 m = HMM_Rotate(45, HMM_Vec3(1, 0, 0));
hmm_quaternion result = HMM_Mat4ToQuaternion(m);
float cosf = 0.9238795325f; // cos(90/2 degrees)
float sinf = 0.3826834324f; // sin(90/2 degrees)
EXPECT_NEAR(result.X, sinf, abs_error);
EXPECT_NEAR(result.Y, 0.0f, abs_error);
EXPECT_NEAR(result.Z, 0.0f, abs_error);
EXPECT_NEAR(result.W, cosf, abs_error);
}
} }
TEST(QuaternionOps, FromAxisAngle) TEST(QuaternionOps, FromAxisAngle)

View File

@@ -8,10 +8,10 @@ TEST(SSE, LinearCombine)
hmm_mat4 MatrixTwo = HMM_Mat4d(4.0f); hmm_mat4 MatrixTwo = HMM_Mat4d(4.0f);
hmm_mat4 Result; hmm_mat4 Result;
Result.Rows[0] = HMM_LinearCombineSSE(MatrixOne.Rows[0], MatrixTwo); Result.Columns[0] = HMM_LinearCombineSSE(MatrixOne.Columns[0], MatrixTwo);
Result.Rows[1] = HMM_LinearCombineSSE(MatrixOne.Rows[1], MatrixTwo); Result.Columns[1] = HMM_LinearCombineSSE(MatrixOne.Columns[1], MatrixTwo);
Result.Rows[2] = HMM_LinearCombineSSE(MatrixOne.Rows[2], MatrixTwo); Result.Columns[2] = HMM_LinearCombineSSE(MatrixOne.Columns[2], MatrixTwo);
Result.Rows[3] = HMM_LinearCombineSSE(MatrixOne.Rows[3], MatrixTwo); Result.Columns[3] = HMM_LinearCombineSSE(MatrixOne.Columns[3], MatrixTwo);
{ {
EXPECT_FLOAT_EQ(Result.Elements[0][0], 8.0f); EXPECT_FLOAT_EQ(Result.Elements[0][0], 8.0f);
@@ -24,13 +24,11 @@ TEST(SSE, LinearCombine)
EXPECT_FLOAT_EQ(Result.Elements[1][2], 0.0f); EXPECT_FLOAT_EQ(Result.Elements[1][2], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[1][3], 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][0], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[2][1], 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][2], 8.0f);
EXPECT_FLOAT_EQ(Result.Elements[2][3], 0.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][0], 0.0f);
EXPECT_FLOAT_EQ(Result.Elements[3][1], 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][2], 0.0f);

View File

@@ -24,6 +24,14 @@ TEST(ScalarMath, Trigonometry)
EXPECT_NEAR(HMM_TanF(HMM_PI32), 0.0f, trigAbsError); EXPECT_NEAR(HMM_TanF(HMM_PI32), 0.0f, trigAbsError);
EXPECT_NEAR(HMM_TanF(-HMM_PI32 / 4), -1.0f, trigAbsError); EXPECT_NEAR(HMM_TanF(-HMM_PI32 / 4), -1.0f, trigAbsError);
EXPECT_NEAR(HMM_ATanF(0.0f), 0.0f, trigAbsError);
EXPECT_NEAR(HMM_ATanF(HMM_PI32), 1.2626272557f, trigAbsError);
EXPECT_NEAR(HMM_ATanF(-HMM_PI32), -1.2626272557f, trigAbsError);
EXPECT_NEAR(HMM_ATan2F(0.0f, 1.0f), 0.0f, trigAbsError);
EXPECT_NEAR(HMM_ATan2F(1.0f, 1.0f), HMM_PI32 / 4.0f, trigAbsError);
EXPECT_NEAR(HMM_ATan2F(1.0f, 0.0f), HMM_PI32 / 2.0f, trigAbsError);
// This isn't the most rigorous because we're really just sanity- // This isn't the most rigorous because we're really just sanity-
// checking that things work by default. // checking that things work by default.
} }
@@ -35,6 +43,18 @@ TEST(ScalarMath, ToRadians)
EXPECT_FLOAT_EQ(HMM_ToRadians(-180.0f), -HMM_PI32); EXPECT_FLOAT_EQ(HMM_ToRadians(-180.0f), -HMM_PI32);
} }
TEST(ScalarMath, ExpF)
{
EXPECT_NEAR(HMM_ExpF(0.0f), 1.0f, 0.0001f);
EXPECT_NEAR(HMM_ExpF(1.0f), 2.7182818285f, 0.0001f);
}
TEST(ScalarMath, LogF)
{
EXPECT_NEAR(HMM_LogF(1.0f), 0.0f, 0.0001f);
EXPECT_NEAR(HMM_LogF(2.7182818285f), 1.0f, 0.0001f);
}
TEST(ScalarMath, SquareRoot) TEST(ScalarMath, SquareRoot)
{ {
EXPECT_FLOAT_EQ(HMM_SquareRootF(16.0f), 4.0f); EXPECT_FLOAT_EQ(HMM_SquareRootF(16.0f), 4.0f);
@@ -54,9 +74,9 @@ TEST(ScalarMath, Power)
TEST(ScalarMath, PowerF) TEST(ScalarMath, PowerF)
{ {
EXPECT_FLOAT_EQ(HMM_PowerF(2.0f, 0), 1.0f); EXPECT_FLOAT_EQ(HMM_PowerF(2.0f, 0.0f), 1.0f);
EXPECT_NEAR(HMM_PowerF(2.0f, 4.1), 17.148376f, 0.0001f); EXPECT_NEAR(HMM_PowerF(2.0f, 4.1f), 17.148376f, 0.0001f);
EXPECT_NEAR(HMM_PowerF(2.0f, -2.5), 0.176777f, 0.0001f); EXPECT_NEAR(HMM_PowerF(2.0f, -2.5f), 0.176777f, 0.0001f);
} }
TEST(ScalarMath, Lerp) TEST(ScalarMath, Lerp)

View File

@@ -134,10 +134,108 @@ TEST(VectorOps, NormalizeZero)
#endif #endif
} }
TEST(VectorOps, FastNormalize)
{
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_FastNormalizeVec2(v2);
EXPECT_NEAR(HMM_LengthVec2(result), 1.0f, 0.001f);
EXPECT_GT(result.X, 0.0f);
EXPECT_LT(result.Y, 0.0f);
}
{
hmm_vec3 result = HMM_FastNormalizeVec3(v3);
EXPECT_NEAR(HMM_LengthVec3(result), 1.0f, 0.001f);
EXPECT_GT(result.X, 0.0f);
EXPECT_LT(result.Y, 0.0f);
EXPECT_GT(result.Z, 0.0f);
}
{
hmm_vec4 result = HMM_FastNormalizeVec4(v4);
EXPECT_NEAR(HMM_LengthVec4(result), 1.0f, 0.001f);
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_FastNormalize(v2);
EXPECT_NEAR(HMM_LengthVec2(result), 1.0f, 0.001f);
EXPECT_GT(result.X, 0.0f);
EXPECT_LT(result.Y, 0.0f);
}
{
hmm_vec3 result = HMM_FastNormalize(v3);
EXPECT_NEAR(HMM_LengthVec3(result), 1.0f, 0.001f);
EXPECT_GT(result.X, 0.0f);
EXPECT_LT(result.Y, 0.0f);
EXPECT_GT(result.Z, 0.0f);
}
{
hmm_vec4 result = HMM_FastNormalize(v4);
EXPECT_NEAR(HMM_LengthVec4(result), 1.0f, 0.001f);
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, FastNormalizeZero)
{
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_FastNormalizeVec2(v2);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
}
{
hmm_vec3 result = HMM_FastNormalizeVec3(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_FastNormalizeVec4(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_FastNormalize(v2);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
}
{
hmm_vec3 result = HMM_FastNormalize(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_FastNormalize(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) TEST(VectorOps, Cross)
{ {
{
// Normal cross
hmm_vec3 v1 = HMM_Vec3(1.0f, 2.0f, 3.0f); hmm_vec3 v1 = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 v2 = HMM_Vec3(4.0f, 5.0f, 6.0f); hmm_vec3 v2 = HMM_Vec3(4.0f, 5.0f, 6.0f);
@@ -148,18 +246,6 @@ TEST(VectorOps, Cross)
EXPECT_FLOAT_EQ(result.Z, -3.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) TEST(VectorOps, DotVec2)
{ {
hmm_vec2 v1 = HMM_Vec2(1.0f, 2.0f); hmm_vec2 v1 = HMM_Vec2(1.0f, 2.0f);
@@ -192,3 +278,43 @@ TEST(VectorOps, DotVec4)
EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 70.0f); EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 70.0f);
#endif #endif
} }
/*
* MatrixOps tests
*/
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);
}

View File

@@ -1,7 +1,9 @@
#include "HandmadeTest.h"
#include "hmm_test.h" #include "hmm_test.h"
int main() int main()
{ {
return hmt_run_all_tests(); int tests_failed = hmt_run_all_tests();
int coverage_failed = hmt_check_all_coverage();
return tests_failed || coverage_failed;
} }

View File

@@ -1,18 +1,20 @@
#include <float.h> #include <float.h>
#define HANDMADE_TEST_IMPLEMENTATION
#include "HandmadeTest.h" #include "HandmadeTest.h"
#undef COVERAGE // Make sure we don't double-define initializers from the header part
#include "../HandmadeMath.h" #include "../HandmadeMath.h"
#include "categories/ScalarMath.h"
#include "categories/Initialization.h"
#include "categories/VectorOps.h"
#include "categories/QuaternionOps.h"
#include "categories/Addition.h" #include "categories/Addition.h"
#include "categories/Subtraction.h"
#include "categories/Multiplication.h"
#include "categories/Division.h" #include "categories/Division.h"
#include "categories/Equality.h" #include "categories/Equality.h"
#include "categories/Initialization.h"
#include "categories/MatrixOps.h"
#include "categories/Multiplication.h"
#include "categories/Projection.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/Transformation.h"
#include "categories/VectorOps.h" #include "categories/SSE.h"

27
test/test.bat Normal file
View File

@@ -0,0 +1,27 @@
@echo off
if "%1%"=="travis" (
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\Common7\Tools\VsDevCmd.bat" -host_arch=amd64 -arch=amd64
) else (
where /q cl
if ERRORLEVEL 1 (
for /f "delims=" %%a in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -find VC\Auxiliary\Build\vcvarsall.bat') do (%%a x64)
)
)
if not exist "build" mkdir build
pushd build
cl /Fehmm_test_c.exe ..\HandmadeMath.c ..\hmm_test.c
hmm_test_c
cl /Fehmm_test_c_no_sse.exe /DHANDMADE_MATH_NO_SSE ..\HandmadeMath.c ..\hmm_test.c
hmm_test_c_no_sse
cl /Fehmm_test_cpp.exe ..\HandmadeMath.cpp ..\hmm_test.cpp
hmm_test_cpp
cl /Fehmm_test_cpp_no_sse.exe /DHANDMADE_MATH_NO_SSE ..\HandmadeMath.cpp ..\hmm_test.cpp
hmm_test_cpp_no_sse
popd