mirror of
https://github.com/HandmadeMath/HandmadeMath.git
synced 2025-12-28 15:44:33 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea1b8c3fdf | ||
|
|
066df8dc02 | ||
|
|
cee57ba573 | ||
|
|
c66971850a | ||
|
|
43b5686636 | ||
|
|
49f274249f | ||
|
|
f1297e7f31 | ||
|
|
d3d09f8352 | ||
|
|
68d2af495c | ||
|
|
a9b08b9147 | ||
|
|
f376f2a2a7 | ||
|
|
78e6feea82 | ||
|
|
21aa828a08 | ||
|
|
93e56be543 | ||
|
|
45c91702a9 |
9
.editorconfig
Normal file
9
.editorconfig
Normal 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
3
.gitignore
vendored
@@ -31,4 +31,7 @@
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
test/build
|
||||
example/build
|
||||
example/lib/flextgl/*
|
||||
|
||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@@ -0,0 +1,9 @@
|
||||
[submodule "example/lib/glfw"]
|
||||
path = example/lib/glfw
|
||||
url = git@github.com:glfw/glfw.git
|
||||
[submodule "example/lib/flextgl-gen"]
|
||||
path = example/lib/flextgl-gen
|
||||
url = git@github.com:mosra/flextgl.git
|
||||
[submodule "example/lib/EGL-Registry"]
|
||||
path = example/lib/EGL-Registry
|
||||
url = git@github.com:KhronosGroup/EGL-Registry.git
|
||||
|
||||
21
.travis.yml
21
.travis.yml
@@ -1,12 +1,23 @@
|
||||
language: cpp
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
matrix:
|
||||
include:
|
||||
# Windows x64 builds (MSVC)
|
||||
- os: windows
|
||||
script:
|
||||
- ./test.bat travis
|
||||
|
||||
before_install:
|
||||
- eval "${MATRIX_EVAL}"
|
||||
install:
|
||||
- cd test
|
||||
- make
|
||||
script:
|
||||
- build/hmm_test_c
|
||||
- build/hmm_test_c_no_sse
|
||||
- build/hmm_test_cpp
|
||||
- build/hmm_test_cpp_no_sse
|
||||
- make c
|
||||
- make c_no_sse
|
||||
- make cpp
|
||||
- make cpp_no_sse
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# Understanding the structure of Handmade Math
|
||||
|
||||
Most of the functions in Handmade Math are very short, and are the kind of functions you want to have inlined. Because of this, most functions in Handmade Math are defined with `HINLINE`, which is defined as `static inline`.
|
||||
|
||||
The exceptions are functions like `HMM_Rotate`, which are long enough that it doesn't make sense to inline them. These functions are defined with an `HEXTERN` prototype, and implemented in the `#ifdef HANDMADE_MATH_IMPLEMENTATION` block.
|
||||
Most of the functions in Handmade Math are very short, and all are the kind of functions you want to be easily inlined for performance. Because of this, all functions in Handmade Math are defined with `HMM_INLINE`, which is defined as `static inline`.
|
||||
|
||||
# Quick style guide
|
||||
|
||||
@@ -14,7 +12,7 @@ The exceptions are functions like `HMM_Rotate`, which are long enough that it do
|
||||
0.5f;
|
||||
1.0f;
|
||||
3.14159f;
|
||||
|
||||
|
||||
// Bad
|
||||
1.f
|
||||
.0f
|
||||
|
||||
3373
HandmadeMath.h
3373
HandmadeMath.h
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,10 @@ To get started, go download [the latest release](https://github.com/HandmadeMath
|
||||
|
||||
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.
|
||||
|
||||
34
example/Makefile
Normal file
34
example/Makefile
Normal file
@@ -0,0 +1,34 @@
|
||||
ifeq ($(OS),Windows_NT)
|
||||
RM = del /Q /F
|
||||
RMDIR = rmdir /Q /S
|
||||
CP = copy /Y
|
||||
PYTHON = python
|
||||
PIP = pip
|
||||
else
|
||||
RM = rm -rf
|
||||
RMDIR = rm -rf
|
||||
CP = cp -f
|
||||
PYTHON = python3
|
||||
PIP = pip3
|
||||
endif
|
||||
|
||||
BUILD_DIR=build
|
||||
|
||||
all: example
|
||||
|
||||
example: lib/flextgl/flextgl.h
|
||||
$(RMDIR) $(BUILD_DIR)
|
||||
mkdir $(BUILD_DIR)
|
||||
cd $(BUILD_DIR) \
|
||||
&& $(CC) -std=c99 -c -lm \
|
||||
-I../lib/glfw/include \
|
||||
-I../lib/flextgl \
|
||||
-I../lib/EGL-Registry/api \
|
||||
../src/main.c ../lib/flextgl/flextGL.c \
|
||||
&& $(CC) -ohmm_example.exe main.o -lm
|
||||
|
||||
flextgl-deps:
|
||||
$(PIP) install --user wheezy.template
|
||||
|
||||
lib/flextgl/flextgl.h lib/flextgl/flextgl.c: flextgl-deps
|
||||
$(PYTHON) lib/flextgl-gen/flextGLgen.py -D lib/flextgl -T glfw3 flextgl-profile.txt
|
||||
19
example/build.bat
Normal file
19
example/build.bat
Normal file
@@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
|
||||
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)
|
||||
)
|
||||
|
||||
python lib\flextgl-gen\flextGLgen.py -D lib\flextgl -T glfw3 flextgl-profile.txt
|
||||
|
||||
if not exist "build" mkdir build
|
||||
pushd build
|
||||
|
||||
cl ^
|
||||
/Feexample.exe /MD ^
|
||||
/I..\lib\glfw\include /I..\lib\flextgl /I..\lib\EGL-Registry\api ^
|
||||
..\src\main.c ..\lib\flextgl\flextGL.c ^
|
||||
/link user32.lib shell32.lib gdi32.lib opengl32.lib ..\lib\glfw\lib-vc2017\glfw3.lib
|
||||
|
||||
popd
|
||||
1
example/flextgl-profile.txt
Normal file
1
example/flextgl-profile.txt
Normal file
@@ -0,0 +1 @@
|
||||
version 3.3 core
|
||||
3
example/install.bat
Normal file
3
example/install.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
|
||||
pip install --user wheezy.template
|
||||
1
example/lib/EGL-Registry
Submodule
1
example/lib/EGL-Registry
Submodule
Submodule example/lib/EGL-Registry added at 1147890444
1
example/lib/flextgl-gen
Submodule
1
example/lib/flextgl-gen
Submodule
Submodule example/lib/flextgl-gen added at 79d13a2ba7
5874
example/lib/glfw/include/GLFW/glfw3.h
Normal file
5874
example/lib/glfw/include/GLFW/glfw3.h
Normal file
File diff suppressed because it is too large
Load Diff
525
example/lib/glfw/include/GLFW/glfw3native.h
Normal file
525
example/lib/glfw/include/GLFW/glfw3native.h
Normal file
@@ -0,0 +1,525 @@
|
||||
/*************************************************************************
|
||||
* GLFW 3.3 - www.glfw.org
|
||||
* A library for OpenGL, window and input
|
||||
*------------------------------------------------------------------------
|
||||
* Copyright (c) 2002-2006 Marcus Geelnard
|
||||
* Copyright (c) 2006-2018 Camilla Löwy <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
|
||||
* @brief Functions related to accessing native handles.
|
||||
*
|
||||
* **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 zero or more
|
||||
* 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`
|
||||
*
|
||||
* The available context API macros are:
|
||||
* * `GLFW_EXPOSE_NATIVE_WGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_NSGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_GLX`
|
||||
* * `GLFW_EXPOSE_NATIVE_EGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_OSMESA`
|
||||
*
|
||||
* 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) || defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
// 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
|
||||
#if defined(GLFW_APIENTRY_DEFINED)
|
||||
#undef APIENTRY
|
||||
#undef GLFW_APIENTRY_DEFINED
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||
#if defined(__OBJC__)
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
typedef void* id;
|
||||
#endif
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||
#include <wayland-client.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
|
||||
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
|
||||
#include <GL/osmesa.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);
|
||||
|
||||
/*! @brief Sets the current primary selection to the specified string.
|
||||
*
|
||||
* @param[in] string A UTF-8 encoded string.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @pointer_lifetime The specified string is copied before this function
|
||||
* returns.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref clipboard
|
||||
* @sa glfwGetX11SelectionString
|
||||
* @sa glfwSetClipboardString
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI void glfwSetX11SelectionString(const char* string);
|
||||
|
||||
/*! @brief Returns the contents of the current primary selection as a string.
|
||||
*
|
||||
* If the selection is empty or if its contents cannot be converted, `NULL`
|
||||
* is returned and a @ref GLFW_FORMAT_UNAVAILABLE error is generated.
|
||||
*
|
||||
* @return The contents of the selection as a UTF-8 encoded string, or `NULL`
|
||||
* if an [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @pointer_lifetime The returned string is allocated and freed by GLFW. You
|
||||
* should not free it yourself. It is valid until the next call to @ref
|
||||
* glfwGetX11SelectionString or @ref glfwSetX11SelectionString, or until the
|
||||
* library is terminated.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref clipboard
|
||||
* @sa glfwSetX11SelectionString
|
||||
* @sa glfwGetClipboardString
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI const char* glfwGetX11SelectionString(void);
|
||||
#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_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
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
|
||||
/*! @brief Retrieves the color buffer associated with the specified window.
|
||||
*
|
||||
* @param[in] window The window whose color buffer to retrieve.
|
||||
* @param[out] width Where to store the width of the color buffer, or `NULL`.
|
||||
* @param[out] height Where to store the height of the color buffer, or `NULL`.
|
||||
* @param[out] format Where to store the OSMesa pixel format of the color
|
||||
* buffer, or `NULL`.
|
||||
* @param[out] buffer Where to store the address of the color buffer, or
|
||||
* `NULL`.
|
||||
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` 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.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, int* height, int* format, void** buffer);
|
||||
|
||||
/*! @brief Retrieves the depth buffer associated with the specified window.
|
||||
*
|
||||
* @param[in] window The window whose depth buffer to retrieve.
|
||||
* @param[out] width Where to store the width of the depth buffer, or `NULL`.
|
||||
* @param[out] height Where to store the height of the depth buffer, or `NULL`.
|
||||
* @param[out] bytesPerValue Where to store the number of bytes per depth
|
||||
* buffer element, or `NULL`.
|
||||
* @param[out] buffer Where to store the address of the depth buffer, or
|
||||
* `NULL`.
|
||||
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` 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.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, int* height, int* bytesPerValue, void** buffer);
|
||||
|
||||
/*! @brief Returns the `OSMesaContext` of the specified window.
|
||||
*
|
||||
* @return The `OSMesaContext` 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.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _glfw3_native_h_ */
|
||||
|
||||
315
example/src/main.c
Normal file
315
example/src/main.c
Normal file
@@ -0,0 +1,315 @@
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "flextGL.h"
|
||||
#define SOKOL_IMPL
|
||||
#define SOKOL_GLCORE33
|
||||
#include "sokol_gfx.h"
|
||||
|
||||
#include "../../HandmadeMath.h"
|
||||
|
||||
// TODO: Remove this
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
hmm_mat4 mvp;
|
||||
hmm_vec4 color;
|
||||
} uniforms_t;
|
||||
|
||||
typedef struct {
|
||||
sg_bindings bindings;
|
||||
int numVerts;
|
||||
} model_t;
|
||||
|
||||
model_t triangle;
|
||||
model_t cube;
|
||||
model_t cylinder;
|
||||
|
||||
model_t initModel(sg_buffer vbuf, sg_buffer ibuf, size_t sizeOfIndices) {
|
||||
model_t result = {
|
||||
.bindings = (sg_bindings) {
|
||||
.vertex_buffers[0] = vbuf,
|
||||
.index_buffer = ibuf,
|
||||
},
|
||||
.numVerts = sizeOfIndices / sizeof(uint16_t),
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define NUM_CYLINDER_SIDES 32
|
||||
|
||||
void initModels() {
|
||||
{
|
||||
// triangle
|
||||
const hmm_vec3 verts[] = {
|
||||
HMM_Vec3( 0.0f, 0.5f, 0.0f), HMM_Vec3(0.0f, 0.0f, 1.0f),
|
||||
HMM_Vec3( 0.5f, -0.5f, 0.0f), HMM_Vec3(0.0f, 0.0f, 1.0f),
|
||||
HMM_Vec3(-0.5f, -0.5f, 0.0f), HMM_Vec3(0.0f, 0.0f, 1.0f),
|
||||
};
|
||||
const uint16_t indices[] = { 0, 1, 2 };
|
||||
sg_buffer vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(verts),
|
||||
.content = verts,
|
||||
});
|
||||
sg_buffer ibuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER,
|
||||
.size = sizeof(indices),
|
||||
.content = indices,
|
||||
});
|
||||
triangle = initModel(vbuf, ibuf, sizeof(indices));
|
||||
}
|
||||
|
||||
{
|
||||
// cube
|
||||
const hmm_vec3 verts[] = {
|
||||
// front
|
||||
HMM_Vec3(-0.5f, 0.5f, 0.5f), HMM_Vec3(0.0f, 0.0f, 1.0f),
|
||||
HMM_Vec3(-0.5f, -0.5f, 0.5f), HMM_Vec3(0.0f, 0.0f, 1.0f),
|
||||
HMM_Vec3( 0.5f, 0.5f, 0.5f), HMM_Vec3(0.0f, 0.0f, 1.0f),
|
||||
HMM_Vec3( 0.5f, -0.5f, 0.5f), HMM_Vec3(0.0f, 0.0f, 1.0f),
|
||||
|
||||
// back
|
||||
HMM_Vec3( 0.5f, 0.5f, -0.5f), HMM_Vec3(0.0f, 0.0f, -1.0f),
|
||||
HMM_Vec3( 0.5f, -0.5f, -0.5f), HMM_Vec3(0.0f, 0.0f, -1.0f),
|
||||
HMM_Vec3(-0.5f, 0.5f, -0.5f), HMM_Vec3(0.0f, 0.0f, -1.0f),
|
||||
HMM_Vec3(-0.5f, -0.5f, -0.5f), HMM_Vec3(0.0f, 0.0f, -1.0f),
|
||||
|
||||
// left
|
||||
HMM_Vec3(-0.5f, 0.5f, -0.5f), HMM_Vec3(-1.0f, 0.0f, 0.0f),
|
||||
HMM_Vec3(-0.5f, -0.5f, -0.5f), HMM_Vec3(-1.0f, 0.0f, 0.0f),
|
||||
HMM_Vec3(-0.5f, 0.5f, 0.5f), HMM_Vec3(-1.0f, 0.0f, 0.0f),
|
||||
HMM_Vec3(-0.5f, -0.5f, 0.5f), HMM_Vec3(-1.0f, 0.0f, 0.0f),
|
||||
|
||||
// right
|
||||
HMM_Vec3(0.5f, 0.5f, 0.5f), HMM_Vec3(1.0f, 0.0f, 0.0f),
|
||||
HMM_Vec3(0.5f, -0.5f, 0.5f), HMM_Vec3(1.0f, 0.0f, 0.0f),
|
||||
HMM_Vec3(0.5f, 0.5f, -0.5f), HMM_Vec3(1.0f, 0.0f, 0.0f),
|
||||
HMM_Vec3(0.5f, -0.5f, -0.5f), HMM_Vec3(1.0f, 0.0f, 0.0f),
|
||||
|
||||
// top
|
||||
HMM_Vec3(-0.5f, 0.5f, -0.5f), HMM_Vec3(0.0f, 1.0f, 0.0f),
|
||||
HMM_Vec3(-0.5f, 0.5f, 0.5f), HMM_Vec3(0.0f, 1.0f, 0.0f),
|
||||
HMM_Vec3( 0.5f, 0.5f, -0.5f), HMM_Vec3(0.0f, 1.0f, 0.0f),
|
||||
HMM_Vec3( 0.5f, 0.5f, 0.5f), HMM_Vec3(0.0f, 1.0f, 0.0f),
|
||||
|
||||
// bottom
|
||||
HMM_Vec3(-0.5f, -0.5f, 0.5f), HMM_Vec3(0.0f, -1.0f, 0.0f),
|
||||
HMM_Vec3(-0.5f, -0.5f, -0.5f), HMM_Vec3(0.0f, -1.0f, 0.0f),
|
||||
HMM_Vec3( 0.5f, -0.5f, 0.5f), HMM_Vec3(0.0f, -1.0f, 0.0f),
|
||||
HMM_Vec3( 0.5f, -0.5f, -0.5f), HMM_Vec3(0.0f, -1.0f, 0.0f),
|
||||
};
|
||||
const uint16_t indices[] = {
|
||||
0, 1, 2, 2, 1, 3,
|
||||
4, 5, 6, 6, 5, 7,
|
||||
8, 9, 10, 10, 9, 11,
|
||||
12, 13, 14, 14, 13, 15,
|
||||
16, 17, 18, 18, 17, 19,
|
||||
20, 21, 22, 22, 21, 23,
|
||||
};
|
||||
sg_buffer vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(verts),
|
||||
.content = verts,
|
||||
});
|
||||
sg_buffer ibuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER,
|
||||
.size = sizeof(indices),
|
||||
.content = indices,
|
||||
});
|
||||
cube = initModel(vbuf, ibuf, sizeof(indices));
|
||||
}
|
||||
|
||||
{
|
||||
// cylinder
|
||||
|
||||
// the vertex order will be:
|
||||
// top middle, bottom middle, top cap ring, bottom cap ring, top side ring, bottom side ring
|
||||
|
||||
hmm_vec3 verts[(2 * (1 + NUM_CYLINDER_SIDES) + (2 * NUM_CYLINDER_SIDES)) * 2];
|
||||
verts[0] = HMM_Vec3(0.0f, 0.5f, 0.0f); verts[1] = HMM_Vec3(0.0f, 1.0f, 0.0f);
|
||||
verts[2] = HMM_Vec3(0.0f, -0.5f, 0.0f); verts[3] = HMM_Vec3(0.0f, -1.0f, 0.0f);
|
||||
|
||||
const int baseVertIndexTopCapRing = 4; // middles are vert, normal, vert, normal
|
||||
const int baseVertIndexBottomCapRing = baseVertIndexTopCapRing + (NUM_CYLINDER_SIDES * 2);
|
||||
const int baseVertIndexTopSideRing = baseVertIndexBottomCapRing + (NUM_CYLINDER_SIDES * 2);
|
||||
const int baseVertIndexBottomSideRing = baseVertIndexTopSideRing + (NUM_CYLINDER_SIDES * 2);
|
||||
|
||||
for (int i = 0; i < NUM_CYLINDER_SIDES; i++) {
|
||||
float t = 2 * HMM_PI32 * (i / (float)NUM_CYLINDER_SIDES);
|
||||
float x = HMM_CosF(t);
|
||||
float z = HMM_SinF(t);
|
||||
hmm_vec3 top = HMM_Vec3(x, 0.5f, z);
|
||||
hmm_vec3 bottom = HMM_Vec3(x, -0.5f, z);
|
||||
hmm_vec3 sideNormal = HMM_NormalizeVec3(HMM_Vec3(x, 0.0f, z));
|
||||
verts[baseVertIndexTopCapRing + (2 * i) ] = top;
|
||||
verts[baseVertIndexTopCapRing + (2 * i) + 1] = HMM_Vec3(0.0f, 1.0f, 0.0f);
|
||||
verts[baseVertIndexBottomCapRing + (2 * i) ] = bottom;
|
||||
verts[baseVertIndexBottomCapRing + (2 * i) + 1] = HMM_Vec3(0.0f, -1.0f, 0.0f);
|
||||
verts[baseVertIndexTopSideRing + (2 * i) ] = top;
|
||||
verts[baseVertIndexTopSideRing + (2 * i) + 1] = sideNormal;
|
||||
verts[baseVertIndexBottomSideRing + (2 * i) ] = bottom;
|
||||
verts[baseVertIndexBottomSideRing + (2 * i) + 1] = sideNormal;
|
||||
}
|
||||
|
||||
uint16_t indices[3 * NUM_CYLINDER_SIDES + 3 * NUM_CYLINDER_SIDES + 3 * 2 * NUM_CYLINDER_SIDES];
|
||||
|
||||
// top cap
|
||||
for (int i = 0; i < NUM_CYLINDER_SIDES; i++) {
|
||||
indices[3 * i] = 0;
|
||||
indices[3 * i + 1] = 2 + i;
|
||||
indices[3 * i + 2] = 2 + ((i + 1) % NUM_CYLINDER_SIDES);
|
||||
}
|
||||
|
||||
// bottom cap
|
||||
const int bottomCapBaseIndex = 3 * NUM_CYLINDER_SIDES;
|
||||
for (int i = 0; i < NUM_CYLINDER_SIDES; i++) {
|
||||
indices[bottomCapBaseIndex + 3 * i] = 1;
|
||||
indices[bottomCapBaseIndex + 3 * i + 1] = (2 + NUM_CYLINDER_SIDES) + ((i + 1) % NUM_CYLINDER_SIDES);
|
||||
indices[bottomCapBaseIndex + 3 * i + 2] = (2 + NUM_CYLINDER_SIDES) + i;
|
||||
}
|
||||
|
||||
const int sideBaseIndex = bottomCapBaseIndex + 3 * NUM_CYLINDER_SIDES;
|
||||
const int topSideRingStart = 2 + NUM_CYLINDER_SIDES + NUM_CYLINDER_SIDES;
|
||||
const int bottomSideRingStart = topSideRingStart + NUM_CYLINDER_SIDES;
|
||||
for (int i = 0; i < NUM_CYLINDER_SIDES; i++) {
|
||||
indices[sideBaseIndex + 6 * i] = topSideRingStart + i;
|
||||
indices[sideBaseIndex + 6 * i + 1] = bottomSideRingStart + i;
|
||||
indices[sideBaseIndex + 6 * i + 2] = topSideRingStart + ((i + 1) % NUM_CYLINDER_SIDES);
|
||||
indices[sideBaseIndex + 6 * i + 3] = topSideRingStart + ((i + 1) % NUM_CYLINDER_SIDES);
|
||||
indices[sideBaseIndex + 6 * i + 4] = bottomSideRingStart + i;
|
||||
indices[sideBaseIndex + 6 * i + 5] = bottomSideRingStart + ((i + 1) % NUM_CYLINDER_SIDES);
|
||||
}
|
||||
|
||||
sg_buffer vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(verts),
|
||||
.content = verts,
|
||||
});
|
||||
sg_buffer ibuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER,
|
||||
.size = sizeof(indices),
|
||||
.content = indices,
|
||||
});
|
||||
cylinder = initModel(vbuf, ibuf, sizeof(indices));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
/* create window and GL context via GLFW */
|
||||
glfwInit();
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
GLFWwindow* w = glfwCreateWindow(640, 480, "Sokol Triangle GLFW", 0, 0);
|
||||
glfwMakeContextCurrent(w);
|
||||
glfwSwapInterval(1);
|
||||
flextInit(w);
|
||||
|
||||
/* setup sokol_gfx */
|
||||
sg_setup(&(sg_desc){0});
|
||||
|
||||
initModels();
|
||||
|
||||
sg_layout_desc layout = {
|
||||
.attrs = {
|
||||
[0].format=SG_VERTEXFORMAT_FLOAT3,
|
||||
[1].format=SG_VERTEXFORMAT_FLOAT3,
|
||||
}
|
||||
};
|
||||
|
||||
sg_shader shd = sg_make_shader(&(sg_shader_desc){
|
||||
.vs = {
|
||||
.source =
|
||||
"#version 330\n"
|
||||
"uniform mat4 mvp;"
|
||||
"uniform vec4 color0;"
|
||||
"layout(location=0) in vec4 position;\n"
|
||||
"out vec4 color;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = mvp * position;\n"
|
||||
" color = color0;\n"
|
||||
"}\n",
|
||||
.uniform_blocks[0] = {
|
||||
.size = sizeof(uniforms_t),
|
||||
.uniforms = {
|
||||
[0] = { .name="mvp", .type=SG_UNIFORMTYPE_MAT4 },
|
||||
[1] = { .name="color0", .type=SG_UNIFORMTYPE_FLOAT4 },
|
||||
},
|
||||
},
|
||||
},
|
||||
.fs.source =
|
||||
"#version 330\n"
|
||||
"in vec4 color;\n"
|
||||
"out vec4 frag_color;\n"
|
||||
"void main() {\n"
|
||||
" frag_color = color;\n"
|
||||
"}\n",
|
||||
});
|
||||
|
||||
/* a pipeline state object (default render states are fine for triangle) */
|
||||
sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
.shader = shd,
|
||||
.layout = layout,
|
||||
.index_type = SG_INDEXTYPE_UINT16,
|
||||
.depth_stencil = {
|
||||
.depth_compare_func = SG_COMPAREFUNC_LESS_EQUAL,
|
||||
.depth_write_enabled = true,
|
||||
},
|
||||
.rasterizer = (sg_rasterizer_state) {
|
||||
.cull_mode = SG_CULLMODE_BACK,
|
||||
.face_winding = SG_FACEWINDING_CCW,
|
||||
},
|
||||
});
|
||||
|
||||
/* default pass action (clear to grey) */
|
||||
sg_pass_action pass_action = {0};
|
||||
|
||||
double previousTime = glfwGetTime();
|
||||
|
||||
/* draw loop */
|
||||
while (!glfwWindowShouldClose(w)) {
|
||||
double time = glfwGetTime();
|
||||
double deltaTime = time - previousTime;
|
||||
double previousTime = time;
|
||||
|
||||
int cur_width, cur_height;
|
||||
glfwGetFramebufferSize(w, &cur_width, &cur_height);
|
||||
sg_begin_default_pass(&pass_action, cur_width, cur_height);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
model_t model = cylinder;
|
||||
|
||||
hmm_mat4 scale = HMM_Scale(HMM_Vec3(0.25f, 0.5f, 0.25f));
|
||||
hmm_mat4 rotateZ = HMM_Rotate(HMM_PI32 * i, HMM_Vec3(0.0f, 0.0f, 1.0f));
|
||||
hmm_mat4 rotateY = HMM_Rotate(HMM_PI32 / 2.0f * time, HMM_Vec3(0.0f, 1.0f, 0.0f));
|
||||
hmm_mat4 rotate = HMM_MultiplyMat4(rotateY, rotateZ);
|
||||
hmm_mat4 translate = HMM_Translate(HMM_Vec3(-0.5f + 0.5f * i, -0.5f + 0.5f * j, 0.0f));
|
||||
hmm_mat4 m = HMM_MultiplyMat4(translate, HMM_MultiplyMat4(rotate, scale));
|
||||
|
||||
hmm_mat4 v = HMM_Translate(HMM_Vec3(0.0f, 0.0f, -1.0f));
|
||||
|
||||
hmm_mat4 p = HMM_Perspective(HMM_PI32 / 2.0f, 1.0f, 0.01f, 10.0f);
|
||||
|
||||
uniforms_t uniforms = {
|
||||
.mvp = HMM_MultiplyMat4(p, HMM_MultiplyMat4(v, m)),
|
||||
.color = HMM_Vec4((i + j) + 1 & 2, ((i + j) % 2) == 1, ((i + j) % 4) == 2, 1.0f),
|
||||
};
|
||||
|
||||
sg_apply_pipeline(pip);
|
||||
sg_apply_bindings(&model.bindings);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &uniforms, sizeof(uniforms));
|
||||
sg_draw(0, model.numVerts, 1);
|
||||
}
|
||||
}
|
||||
|
||||
sg_end_pass();
|
||||
sg_commit();
|
||||
glfwSwapBuffers(w);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
sg_shutdown();
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
}
|
||||
11943
example/src/sokol_gfx.h
Normal file
11943
example/src/sokol_gfx.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,5 @@
|
||||
#define HANDMADE_MATH_IMPLEMENTATION
|
||||
#define HANDMADE_MATH_NO_INLINE
|
||||
#ifndef WITHOUT_COVERAGE
|
||||
#include "HandmadeTest.h"
|
||||
#endif
|
||||
|
||||
#include "../HandmadeMath.h"
|
||||
|
||||
12
test/HandmadeMathDifferentPrefix.cpp
Normal file
12
test/HandmadeMathDifferentPrefix.cpp
Normal 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);
|
||||
}
|
||||
@@ -4,19 +4,46 @@
|
||||
This is Handmade Math's test framework. It is fully compatible with both C
|
||||
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
|
||||
single test to be run:
|
||||
|
||||
TEST(MyCategory, MyTestName) {
|
||||
TEST(MyCategory, MyTestName) {
|
||||
// test code, including asserts/expects
|
||||
}
|
||||
}
|
||||
|
||||
The main function of your test code should then call hmt_run_all_tests and
|
||||
return the result:
|
||||
Handmade Test also provides macros you can use to check the coverage of
|
||||
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:
|
||||
|
||||
int main() {
|
||||
return hmt_run_all_tests();
|
||||
}
|
||||
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() {
|
||||
return hmt_run_all_tests() || hmt_check_all_coverage();
|
||||
}
|
||||
|
||||
=============================================================================
|
||||
|
||||
@@ -40,7 +67,7 @@
|
||||
#define HMT_RED "\033[31m"
|
||||
#define HMT_GREEN "\033[32m"
|
||||
|
||||
#define HMT_INITIAL_ARRAY_SIZE 1024
|
||||
#define HMT_ARRAY_SIZE 1024
|
||||
|
||||
typedef struct hmt_testresult_struct {
|
||||
int count_cases;
|
||||
@@ -57,20 +84,137 @@ typedef struct hmt_test_struct {
|
||||
typedef struct hmt_category_struct {
|
||||
const char* name;
|
||||
int num_tests;
|
||||
int tests_capacity;
|
||||
hmt_test* tests;
|
||||
} hmt_category;
|
||||
|
||||
int hmt_num_categories = 0;
|
||||
int hmt_category_capacity = HMT_INITIAL_ARRAY_SIZE;
|
||||
hmt_category* categories = 0;
|
||||
typedef struct hmt_covercase_struct {
|
||||
const char* name;
|
||||
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 cat = {
|
||||
.name = name,
|
||||
.num_tests = 0,
|
||||
.tests_capacity = HMT_INITIAL_ARRAY_SIZE,
|
||||
.tests = (hmt_test*) malloc(HMT_INITIAL_ARRAY_SIZE * sizeof(hmt_test))
|
||||
name, // name
|
||||
0, // num_tests
|
||||
(hmt_test*) malloc(HMT_ARRAY_SIZE * sizeof(hmt_test)), // tests
|
||||
};
|
||||
|
||||
return cat;
|
||||
@@ -78,60 +222,105 @@ hmt_category _hmt_new_category(const char* name) {
|
||||
|
||||
hmt_test _hmt_new_test(const char* name, hmt_test_func func) {
|
||||
hmt_test test = {
|
||||
.name = name,
|
||||
.func = func
|
||||
name, // name
|
||||
func, // func
|
||||
};
|
||||
|
||||
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
|
||||
if (!categories) {
|
||||
categories = (hmt_category*) malloc(hmt_category_capacity * sizeof(hmt_category));
|
||||
if (!_hmt_categories) {
|
||||
_hmt_categories = (hmt_category*) malloc(HMT_ARRAY_SIZE * sizeof(hmt_category));
|
||||
}
|
||||
|
||||
// Find the matching category, if possible
|
||||
int cat_index;
|
||||
for (cat_index = 0; cat_index < hmt_num_categories; cat_index++) {
|
||||
if (strcmp(categories[cat_index].name, category) == 0) {
|
||||
for (cat_index = 0; cat_index < _hmt_num_categories; cat_index++) {
|
||||
if (strcmp(_hmt_categories[cat_index].name, category) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Expand the array of categories if necessary
|
||||
if (cat_index >= hmt_category_capacity) {
|
||||
// TODO: If/when we ever split HandmadeTest off into its own package,
|
||||
// we should start with a smaller initial capacity and dynamically expand.
|
||||
}
|
||||
|
||||
// Add a new category if necessary
|
||||
if (cat_index >= hmt_num_categories) {
|
||||
categories[cat_index] = _hmt_new_category(category);
|
||||
hmt_num_categories++;
|
||||
if (cat_index >= _hmt_num_categories) {
|
||||
_hmt_categories[cat_index] = _hmt_new_category(category);
|
||||
_hmt_num_categories++;
|
||||
}
|
||||
|
||||
hmt_category* cat = &categories[cat_index];
|
||||
hmt_category* cat = &_hmt_categories[cat_index];
|
||||
|
||||
// Add the test to the category
|
||||
if (cat->num_tests >= cat->tests_capacity) {
|
||||
// TODO: If/when we ever split HandmadeTest off into its own package,
|
||||
// we should start with a smaller initial capacity and dynamically expand.
|
||||
}
|
||||
cat->tests[cat->num_tests] = _hmt_new_test(name, func);
|
||||
cat->num_tests++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 count_alltests = 0;
|
||||
int count_allfailedtests = 0; // failed test cases
|
||||
int count_allfailures = 0; // failed asserts
|
||||
|
||||
for (int i = 0; i < hmt_num_categories; i++) {
|
||||
hmt_category cat = categories[i];
|
||||
int count_catfailedtests = 0;
|
||||
for (int i = 0; i < _hmt_num_categories; i++) {
|
||||
hmt_category cat = _hmt_categories[i];
|
||||
int count_catfailedtests = 0;
|
||||
int count_catfailures = 0;
|
||||
|
||||
printf("\n%s:\n", cat.name);
|
||||
@@ -142,8 +331,8 @@ int hmt_run_all_tests() {
|
||||
printf(" %s:", test.name);
|
||||
|
||||
hmt_testresult result = {
|
||||
.count_cases = 0,
|
||||
.count_failures = 0
|
||||
0, // count_cases
|
||||
0, // count_failures
|
||||
};
|
||||
test.func(&result);
|
||||
|
||||
@@ -177,87 +366,33 @@ int hmt_run_all_tests() {
|
||||
return (count_allfailedtests > 0);
|
||||
}
|
||||
|
||||
#define _HMT_TEST_FUNCNAME(category, name) category ## _ ## name
|
||||
#define _HMT_TEST_FUNCNAME_INIT(category, name) category ## _ ## name ## _init
|
||||
int hmt_check_all_coverage() {
|
||||
printf("Coverage:\n");
|
||||
|
||||
#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)
|
||||
int count_failures = 0;
|
||||
|
||||
#define _HMT_CASE_START() \
|
||||
_result->count_cases++;
|
||||
for (int i = 0; i < _hmt_num_covercases; i++) {
|
||||
hmt_covercase covercase = _hmt_covercases[i];
|
||||
|
||||
#define _HMT_CASE_FAIL() \
|
||||
_result->count_failures++; \
|
||||
printf("\n - " HMT_RED "[FAIL] (%d) " HMT_RESET, __LINE__);
|
||||
if (covercase.expected_asserts != covercase.actual_asserts) {
|
||||
count_failures++;
|
||||
printf("%s: " HMT_RED "FAIL (expected %d asserts, got %d)\n" HMT_RESET, covercase.name, covercase.expected_asserts, covercase.actual_asserts);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Asserts and expects
|
||||
*/
|
||||
#define HMT_EXPECT_TRUE(_actual) do { \
|
||||
_HMT_CASE_START(); \
|
||||
if (!(_actual)) { \
|
||||
_HMT_CASE_FAIL(); \
|
||||
printf("Expected true but got something false"); \
|
||||
} \
|
||||
} while (0)
|
||||
if (count_failures > 0) {
|
||||
printf("\n");
|
||||
printf(HMT_RED);
|
||||
} else {
|
||||
printf(HMT_GREEN);
|
||||
}
|
||||
printf("%d coverage cases tested, %d failures\n", _hmt_num_covercases, count_failures);
|
||||
printf(HMT_RESET);
|
||||
|
||||
#define HMT_EXPECT_FALSE(_actual) do { \
|
||||
_HMT_CASE_START(); \
|
||||
if (_actual) { \
|
||||
_HMT_CASE_FAIL(); \
|
||||
printf("Expected false but got something true"); \
|
||||
} \
|
||||
} while (0)
|
||||
printf("\n");
|
||||
|
||||
#define HMT_EXPECT_FLOAT_EQ(_actual, _expected) do { \
|
||||
_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)
|
||||
return (count_failures > 0);
|
||||
}
|
||||
|
||||
#define HMT_EXPECT_NEAR(_actual, _expected, _epsilon) do { \
|
||||
_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); \
|
||||
} \
|
||||
} 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
|
||||
#endif // HANDMADE_TEST_IMPLEMENTATION_GUARD
|
||||
#endif // HANDMADE_TEST_IMPLEMENTATION
|
||||
|
||||
@@ -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:
|
||||
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"
|
||||
mkdir -p $(BUILD_DIR)
|
||||
cd $(BUILD_DIR)\
|
||||
@@ -16,7 +21,10 @@ c: HandmadeMath.c test_impl
|
||||
-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)"
|
||||
mkdir -p $(BUILD_DIR)
|
||||
cd $(BUILD_DIR) \
|
||||
@@ -26,7 +34,10 @@ c_no_sse: HandmadeMath.c test_impl
|
||||
-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"
|
||||
mkdir -p $(BUILD_DIR)
|
||||
cd $(BUILD_DIR) \
|
||||
@@ -34,7 +45,10 @@ cpp: HandmadeMath.cpp test_impl
|
||||
-DHANDMADE_MATH_CPP_MODE \
|
||||
../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)"
|
||||
mkdir -p $(BUILD_DIR)
|
||||
cd $(BUILD_DIR) \
|
||||
@@ -43,3 +57,29 @@ cpp_no_sse: HandmadeMath.cpp test_impl
|
||||
../HandmadeMath.cpp ../hmm_test.cpp
|
||||
|
||||
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
|
||||
|
||||
@@ -4,8 +4,13 @@ You can compile and run the tests yourself by running:
|
||||
|
||||
```
|
||||
make
|
||||
build/hmm_test_c
|
||||
build/hmm_test_c_no_sse
|
||||
build/hmm_test_cpp
|
||||
build/hmm_test_cpp_no_sse
|
||||
```
|
||||
|
||||
To run a specific test configuration, run one of:
|
||||
|
||||
```
|
||||
make c
|
||||
make c_no_sse
|
||||
make cpp
|
||||
make cpp_no_sse
|
||||
```
|
||||
|
||||
@@ -37,7 +37,7 @@ TEST(Addition, Vec3)
|
||||
hmm_vec3 result = HMM_AddVec3(v3_1, v3_2);
|
||||
EXPECT_FLOAT_EQ(result.X, 5.0f);
|
||||
EXPECT_FLOAT_EQ(result.Y, 7.0f);
|
||||
EXPECT_FLOAT_EQ(result.Z, 9.0f);
|
||||
EXPECT_FLOAT_EQ(result.Z, 9.0f);
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
{
|
||||
@@ -64,7 +64,7 @@ TEST(Addition, Vec4)
|
||||
{
|
||||
hmm_vec4 v4_1 = HMM_Vec4(1.0f, 2.0f, 3.0f, 4.0f);
|
||||
hmm_vec4 v4_2 = HMM_Vec4(5.0f, 6.0f, 7.0f, 8.0f);
|
||||
|
||||
|
||||
{
|
||||
hmm_vec4 result = HMM_AddVec4(v4_1, v4_2);
|
||||
EXPECT_FLOAT_EQ(result.X, 6.0f);
|
||||
|
||||
@@ -15,6 +15,9 @@ TEST(Equality, Vec2)
|
||||
|
||||
EXPECT_TRUE(a == b);
|
||||
EXPECT_FALSE(a == c);
|
||||
|
||||
EXPECT_FALSE(a != b);
|
||||
EXPECT_TRUE(a != c);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -33,6 +36,9 @@ TEST(Equality, Vec3)
|
||||
|
||||
EXPECT_TRUE(a == b);
|
||||
EXPECT_FALSE(a == c);
|
||||
|
||||
EXPECT_FALSE(a != b);
|
||||
EXPECT_TRUE(a != c);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -51,5 +57,8 @@ TEST(Equality, Vec4)
|
||||
|
||||
EXPECT_TRUE(a == b);
|
||||
EXPECT_FALSE(a == c);
|
||||
|
||||
EXPECT_FALSE(a != b);
|
||||
EXPECT_TRUE(a != c);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ TEST(Initialization, Vectors)
|
||||
{
|
||||
//
|
||||
// Test vec2
|
||||
//
|
||||
//
|
||||
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.Y, 2.0f);
|
||||
|
||||
@@ -15,21 +15,21 @@ TEST(Projection, Orthographic)
|
||||
|
||||
TEST(Projection, Perspective)
|
||||
{
|
||||
hmm_mat4 projection = HMM_Perspective(90.0f, 2.0f, 5.0f, 15.0f);
|
||||
hmm_mat4 projection = HMM_Perspective(HMM_ToRadians(90.0f), 2.0f, 5.0f, 15.0f);
|
||||
|
||||
{
|
||||
hmm_vec3 original = HMM_Vec3(5.0f, 5.0f, -15.0f);
|
||||
hmm_vec4 projected = HMM_MultiplyMat4ByVec4(projection, HMM_Vec4v(original, 1));
|
||||
EXPECT_FLOAT_EQ(projected.X, 5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 10.0f);
|
||||
EXPECT_FLOAT_EQ(projected.X, 2.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 15.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 15.0f);
|
||||
}
|
||||
{
|
||||
hmm_vec3 original = HMM_Vec3(5.0f, 5.0f, -5.0f);
|
||||
hmm_vec4 projected = HMM_MultiplyMat4ByVec4(projection, HMM_Vec4v(original, 1));
|
||||
EXPECT_FLOAT_EQ(projected.X, 5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 10.0f);
|
||||
EXPECT_FLOAT_EQ(projected.X, 2.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 5.0f);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ TEST(QuaternionOps, Slerp)
|
||||
EXPECT_FLOAT_EQ(result.W, 0.86602540f);
|
||||
}
|
||||
|
||||
TEST(QuaternionOps, ToMat4)
|
||||
TEST(QuaternionOps, QuatToMat4)
|
||||
{
|
||||
const float abs_error = 0.0001f;
|
||||
|
||||
@@ -105,6 +105,67 @@ TEST(QuaternionOps, ToMat4)
|
||||
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(HMM_ToRadians(90.0f), 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(HMM_ToRadians(90.0f), 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(HMM_ToRadians(90.0f), 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(HMM_ToRadians(45.0f), 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)
|
||||
{
|
||||
hmm_vec3 axis = HMM_Vec3(1.0f, 0.0f, 0.0f);
|
||||
@@ -115,4 +176,4 @@ TEST(QuaternionOps, FromAxisAngle)
|
||||
EXPECT_FLOAT_EQ(result.Y, 0.0f);
|
||||
EXPECT_FLOAT_EQ(result.Z, 0.0f);
|
||||
EXPECT_NEAR(result.W, 0.707107f, FLT_EPSILON * 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,33 +7,33 @@ TEST(SSE, LinearCombine)
|
||||
hmm_mat4 MatrixOne = HMM_Mat4d(2.0f);
|
||||
hmm_mat4 MatrixTwo = HMM_Mat4d(4.0f);
|
||||
hmm_mat4 Result;
|
||||
|
||||
|
||||
Result.Columns[0] = HMM_LinearCombineSSE(MatrixOne.Columns[0], MatrixTwo);
|
||||
Result.Columns[1] = HMM_LinearCombineSSE(MatrixOne.Columns[1], MatrixTwo);
|
||||
Result.Columns[2] = HMM_LinearCombineSSE(MatrixOne.Columns[2], 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][1], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][2], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][3], 0.0f);
|
||||
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][0], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][1], 8.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][1], 8.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][2], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][3], 0.0f);
|
||||
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][0], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][1], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][1], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][2], 8.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][3], 0.0f);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][0], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][1], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][1], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][2], 0.0f);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], 8.0f);
|
||||
}
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], 8.0f);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,10 +24,25 @@ TEST(ScalarMath, Trigonometry)
|
||||
EXPECT_NEAR(HMM_TanF(HMM_PI32), 0.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-
|
||||
// checking that things work by default.
|
||||
}
|
||||
|
||||
TEST(ScalarMath, ToDegrees)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(HMM_ToDegrees(0.0f), 0.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_ToDegrees(HMM_PI32), 180.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_ToDegrees(-HMM_PI32), -180.0f);
|
||||
}
|
||||
|
||||
TEST(ScalarMath, ToRadians)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(HMM_ToRadians(0.0f), 0.0f);
|
||||
@@ -35,6 +50,18 @@ TEST(ScalarMath, ToRadians)
|
||||
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)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(HMM_SquareRootF(16.0f), 4.0f);
|
||||
@@ -48,27 +75,27 @@ TEST(ScalarMath, RSquareRootF)
|
||||
TEST(ScalarMath, Power)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(HMM_Power(2.0f, 0), 1.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Power(2.0f, 4), 16.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Power(2.0f, 4), 16.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Power(2.0f, -2), 0.25f);
|
||||
}
|
||||
|
||||
TEST(ScalarMath, PowerF)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(HMM_PowerF(2.0f, 0), 1.0f);
|
||||
EXPECT_NEAR(HMM_PowerF(2.0f, 4.1), 17.148376f, 0.0001f);
|
||||
EXPECT_NEAR(HMM_PowerF(2.0f, -2.5), 0.176777f, 0.0001f);
|
||||
EXPECT_FLOAT_EQ(HMM_PowerF(2.0f, 0.0f), 1.0f);
|
||||
EXPECT_NEAR(HMM_PowerF(2.0f, 4.1f), 17.148376f, 0.0001f);
|
||||
EXPECT_NEAR(HMM_PowerF(2.0f, -2.5f), 0.176777f, 0.0001f);
|
||||
}
|
||||
|
||||
TEST(ScalarMath, Lerp)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(HMM_Lerp(-2.0f, 0.0f, 2.0f), -2.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Lerp(-2.0f, 0.5f, 2.0f), 0.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Lerp(-2.0f, 0.0f, 2.0f), -2.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Lerp(-2.0f, 0.5f, 2.0f), 0.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Lerp(-2.0f, 1.0f, 2.0f), 2.0f);
|
||||
}
|
||||
|
||||
TEST(ScalarMath, Clamp)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(HMM_Clamp(-2.0f, 0.0f, 2.0f), 0.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Clamp(-2.0f, -3.0f, 2.0f), -2.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Clamp(-2.0f, 0.0f, 2.0f), 0.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Clamp(-2.0f, -3.0f, 2.0f), -2.0f);
|
||||
EXPECT_FLOAT_EQ(HMM_Clamp(-2.0f, 3.0f, 2.0f), 2.0f);
|
||||
}
|
||||
|
||||
@@ -17,21 +17,23 @@ TEST(Transformations, Rotate)
|
||||
{
|
||||
hmm_vec3 original = HMM_Vec3(1.0f, 1.0f, 1.0f);
|
||||
|
||||
hmm_mat4 rotateX = HMM_Rotate(90, HMM_Vec3(1, 0, 0));
|
||||
float angle = HMM_ToRadians(90.0f);
|
||||
|
||||
hmm_mat4 rotateX = HMM_Rotate(angle, HMM_Vec3(1, 0, 0));
|
||||
hmm_vec4 rotatedX = HMM_MultiplyMat4ByVec4(rotateX, HMM_Vec4v(original, 1));
|
||||
EXPECT_FLOAT_EQ(rotatedX.X, 1.0f);
|
||||
EXPECT_FLOAT_EQ(rotatedX.Y, -1.0f);
|
||||
EXPECT_FLOAT_EQ(rotatedX.Z, 1.0f);
|
||||
EXPECT_FLOAT_EQ(rotatedX.W, 1.0f);
|
||||
|
||||
hmm_mat4 rotateY = HMM_Rotate(90, HMM_Vec3(0, 1, 0));
|
||||
hmm_mat4 rotateY = HMM_Rotate(angle, HMM_Vec3(0, 1, 0));
|
||||
hmm_vec4 rotatedY = HMM_MultiplyMat4ByVec4(rotateY, HMM_Vec4v(original, 1));
|
||||
EXPECT_FLOAT_EQ(rotatedY.X, 1.0f);
|
||||
EXPECT_FLOAT_EQ(rotatedY.Y, 1.0f);
|
||||
EXPECT_FLOAT_EQ(rotatedY.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(rotatedY.W, 1.0f);
|
||||
|
||||
hmm_mat4 rotateZ = HMM_Rotate(90, HMM_Vec3(0, 0, 1));
|
||||
hmm_mat4 rotateZ = HMM_Rotate(angle, HMM_Vec3(0, 0, 1));
|
||||
hmm_vec4 rotatedZ = HMM_MultiplyMat4ByVec4(rotateZ, HMM_Vec4v(original, 1));
|
||||
EXPECT_FLOAT_EQ(rotatedZ.X, -1.0f);
|
||||
EXPECT_FLOAT_EQ(rotatedZ.Y, 1.0f);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
TEST(VectorOps, LengthSquared)
|
||||
{
|
||||
hmm_vec2 v2 = HMM_Vec2(1.0f, -2.0f);
|
||||
hmm_vec3 v3 = HMM_Vec3(1.0f, -2.0f, 3.0f);
|
||||
hmm_vec3 v3 = HMM_Vec3(1.0f, -2.0f, 3.0f);
|
||||
hmm_vec4 v4 = HMM_Vec4(1.0f, -2.0f, 3.0f, 1.0f);
|
||||
|
||||
EXPECT_FLOAT_EQ(HMM_LengthSquaredVec2(v2), 5.0f);
|
||||
@@ -37,7 +37,7 @@ TEST(VectorOps, Length)
|
||||
TEST(VectorOps, Normalize)
|
||||
{
|
||||
hmm_vec2 v2 = HMM_Vec2(1.0f, -2.0f);
|
||||
hmm_vec3 v3 = HMM_Vec3(1.0f, -2.0f, 3.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);
|
||||
|
||||
{
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "HandmadeTest.h"
|
||||
#include "hmm_test.h"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include <float.h>
|
||||
|
||||
#define HANDMADE_TEST_IMPLEMENTATION
|
||||
#include "HandmadeTest.h"
|
||||
|
||||
#undef COVERAGE // Make sure we don't double-define initializers from the header part
|
||||
#include "../HandmadeMath.h"
|
||||
|
||||
#include "categories/ScalarMath.h"
|
||||
|
||||
27
test/test.bat
Normal file
27
test/test.bat
Normal 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 || popd && exit /B
|
||||
hmm_test_c
|
||||
|
||||
cl /Fehmm_test_c_no_sse.exe /DHANDMADE_MATH_NO_SSE ..\HandmadeMath.c ..\hmm_test.c || popd && exit /B
|
||||
hmm_test_c_no_sse
|
||||
|
||||
cl /Fehmm_test_cpp.exe ..\HandmadeMath.cpp ..\hmm_test.cpp || popd && exit /B
|
||||
hmm_test_cpp
|
||||
|
||||
cl /Fehmm_test_cpp_no_sse.exe /DHANDMADE_MATH_NO_SSE ..\HandmadeMath.cpp ..\hmm_test.cpp || popd && exit /B
|
||||
hmm_test_cpp_no_sse
|
||||
|
||||
popd
|
||||
Reference in New Issue
Block a user