├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── data └── teapot.zip ├── docs └── sample.jpg ├── include ├── application.hpp ├── math │ ├── mat3.hpp │ ├── mat4.hpp │ ├── quat.hpp │ ├── simd_float4.hpp │ ├── simd_float8.hpp │ ├── simd_mat4x4.hpp │ ├── simd_mat4x8.hpp │ ├── simd_vec4x4.hpp │ ├── simd_vec4x8.hpp │ ├── transform.hpp │ ├── utility.hpp │ ├── vec2.hpp │ ├── vec3.hpp │ └── vec4.hpp └── rasterator.hpp ├── sample ├── CMakeLists.txt └── main.cpp └── src ├── CMakeLists.txt ├── application.cpp └── rasterator.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | 9 | # Precompiled Headers 10 | *.gch 11 | *.pch 12 | 13 | # Compiled Dynamic libraries 14 | *.so 15 | *.dylib 16 | *.dll 17 | 18 | # Fortran module files 19 | *.mod 20 | *.smod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | 33 | external/* 34 | external/ 35 | build/* 36 | build/ 37 | bin/ 38 | lib/ 39 | x64/ 40 | x64/* 41 | libs/libs_debug_vs2017.7z 42 | libs/libs_release_vs2017.7z 43 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/stb"] 2 | path = external/stb 3 | url = https://github.com/nothings/stb 4 | [submodule "external/SDL"] 5 | path = external/SDL 6 | url = https://github.com/spurious/SDL-mirror.git 7 | [submodule "external/assimp"] 8 | path = external/assimp 9 | url = https://github.com/assimp/assimp.git 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8 FATAL_ERROR) 2 | 3 | project("Rasterator") 4 | 5 | IF(APPLE) 6 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++14") 7 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") 8 | ENDIF() 9 | 10 | # Include paths 11 | set(RASTERATOR_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}/external/SDL/include" 12 | "${PROJECT_SOURCE_DIR}/external/SDL/include" 13 | "${CMAKE_CURRENT_BINARY_DIR}/external/assimp/include" 14 | "${PROJECT_SOURCE_DIR}/external/assimp/include" 15 | "${PROJECT_SOURCE_DIR}/external/stb" 16 | "${PROJECT_SOURCE_DIR}/include") 17 | 18 | include_directories("${RASTERATOR_INCLUDE_DIRS}") 19 | 20 | if (NOT EMSCRIPTEN) 21 | add_subdirectory(external/SDL) 22 | endif() 23 | 24 | add_subdirectory(external/assimp) 25 | 26 | add_subdirectory("${PROJECT_SOURCE_DIR}/src") 27 | add_subdirectory("${PROJECT_SOURCE_DIR}/sample") -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Dihara Wijetunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: MIT](https://img.shields.io/packagist/l/doctrine/orm.svg)](https://opensource.org/licenses/MIT) 2 | 3 | # Rasterator 4 | 5 | ## What is it? 6 | A Real-time, C++ toy software rasterizer created for understanding the graphics pipeline. 7 | 8 | ## Features 9 | * Near-complete implementation of the graphics pipeline 10 | * Interactive framerates 11 | * Depth buffering 12 | * Perspective-correct vertex attribute interpolation 13 | * OpenMP multithreading 14 | * Texture mapping 15 | * Bilinear texture filtering 16 | * Cross platform (Windows, macOS, Linux, Emscripten) 17 | 18 | ## Screenshots 19 | ![Sample](docs/sample.jpg) 20 | 21 | ## Building 22 | 23 | ### Windows/macOS/Linux 24 | Recursively clone the repository and use CMake to generate a project of your choice. 25 | 26 | ### Emscripten 27 | Make sure to have the Emscripten SDK installed. Then use CMake with the Emscripten toolchain to generate a makefile (or MinGW makefile on Windows). 28 | 29 | NOTE: Emscripten build is pretty slow, so use a lower resolution. 30 | 31 | ## Roadmap 32 | * SIMD Acceleration (SSE/AVX) 33 | * Normal mapping 34 | * Specular mapping 35 | * Trilinear texture filtering 36 | 37 | ## Dependencies 38 | * [SDL2](https://www.libsdl.org/download-2.0.php) 39 | * [Assimp](https://github.com/assimp/assimp) 40 | * [stb](https://github.com/nothings/stb) 41 | 42 | ## License 43 | ``` 44 | Copyright (c) 2019 Dihara Wijetunga 45 | 46 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 47 | associated documentation files (the "Software"), to deal in the Software without restriction, 48 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 49 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 50 | subject to the following conditions: 51 | 52 | The above copyright notice and this permission notice shall be included in all copies or substantial 53 | portions of the Software. 54 | 55 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 56 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 57 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 58 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 59 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 60 | ``` 61 | -------------------------------------------------------------------------------- /data/teapot.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/rasterator/d05dc6eba0b7ea91d8fba47eca44a25a8017ec4f/data/teapot.zip -------------------------------------------------------------------------------- /docs/sample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/rasterator/d05dc6eba0b7ea91d8fba47eca44a25a8017ec4f/docs/sample.jpg -------------------------------------------------------------------------------- /include/application.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define RST_DECLARE_MAIN(APP_CLASS) \ 5 | int main(int argc, char* argv[]) \ 6 | { \ 7 | APP_CLASS app; \ 8 | return app.run(argc, argv); \ 9 | } 10 | 11 | #define RST_SAFE_DELETE(OBJECT) if(OBJECT) { delete OBJECT; OBJECT = nullptr; } 12 | #define RST_SAFE_DELETE_ARRAY(OBJECT) if(OBJECT) { delete[] OBJECT; OBJECT = nullptr; } 13 | #define RST_COLOR_ARGB(RED, GREEN, BLUE, ALPHA) (static_cast(ALPHA * 255.0f) << 24) | (static_cast(RED * 255.0f) << 16) | (static_cast(GREEN * 255.0f) << 8) | static_cast(BLUE * 255.0f) 14 | #define RST_COLOR_RGBA(RED, GREEN, BLUE, ALPHA) (static_cast(RED * 255.0f) << 24) | (static_cast(GREEN * 255.0f) << 16) | static_cast(BLUE * 255.0f) << 8 | static_cast(ALPHA * 255.0f) 15 | 16 | class Application 17 | { 18 | public: 19 | Application(); 20 | ~Application(); 21 | int run(int argc, char* argv[]); 22 | 23 | private: 24 | #ifdef __EMSCRIPTEN__ 25 | static void _main_loop(void* arg); 26 | #endif 27 | void _frame(); 28 | void _event_loop(); 29 | bool _initialize(); 30 | void _shutdown(); 31 | void _update_delta_time(); 32 | void _clear_screen(uint8_t r, uint8_t b, uint8_t g, uint8_t a); 33 | void _present(); 34 | 35 | protected: 36 | virtual bool initialize() = 0; 37 | virtual void frame() = 0; 38 | virtual void shutdown() = 0; 39 | void update_backbuffer(void* pixels); 40 | 41 | private: 42 | bool m_is_running; 43 | SDL_Window* m_sdl_window; 44 | SDL_Renderer* m_sdl_renderer; 45 | SDL_Texture* m_sdl_backbuffer; 46 | uint32_t m_last_delta_time; 47 | 48 | protected: 49 | float m_delta_time; 50 | uint32_t m_width; 51 | uint32_t m_height; 52 | std::string m_title; 53 | }; 54 | -------------------------------------------------------------------------------- /include/math/mat3.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace math 6 | { 7 | 8 | template 9 | struct mat3 10 | { 11 | union 12 | { 13 | struct 14 | { 15 | // m[row][column] 16 | T m11, m21, m31, m12, m22, m32, m13, m23, m33; 17 | }; 18 | float elem[9]; 19 | vec3 column[3]; 20 | }; 21 | 22 | mat3() 23 | { 24 | for (int i = 0; i < 9; i++) 25 | elem[i] = 0; 26 | 27 | m11 = 1; 28 | m22 = 1; 29 | m33 = 1; 30 | } 31 | 32 | mat3(float _m11, float _m12, float _m13, 33 | float _m21, float _m22, float _m23, 34 | float _m31, float _m32, float _m33) 35 | { 36 | m11 = _m11; 37 | m12 = _m12; 38 | m13 = _m13; 39 | 40 | m21 = _m21; 41 | m22 = _m22; 42 | m23 = _m23; 43 | 44 | m31 = _m31; 45 | m32 = _m32; 46 | m33 = _m33; 47 | } 48 | 49 | mat3(vec3 _c1, vec3 _c2, vec3 _c3) 50 | { 51 | m11 = _c1.x; 52 | m21 = _c1.y; 53 | m31 = _c1.z; 54 | 55 | m12 = _c2.x; 56 | m22 = _c2.y; 57 | m32 = _c2.z; 58 | 59 | m13 = _c3.x; 60 | m23 = _c3.y; 61 | m33 = _c3.z; 62 | } 63 | 64 | inline mat3 transpose() const 65 | { 66 | mat3 r; 67 | 68 | r.m11 = m11; 69 | r.m21 = m12; 70 | r.m31 = m13; 71 | 72 | r.m12 = m21; 73 | r.m22 = m22; 74 | r.m32 = m23; 75 | 76 | r.m13 = m31; 77 | r.m23 = m32; 78 | r.m33 = m33; 79 | 80 | return r; 81 | } 82 | 83 | inline T determinant() const 84 | { 85 | return (m11 * ((m22 * m33) - (m23 * m32))) - (m12 * ((m21 * m33) - (m23 * m31))) - (m13 * ((m21 * m32) - (m22 * m31))); 86 | } 87 | 88 | inline mat3 adjoint() const 89 | { 90 | mat3 r; 91 | 92 | r.m11 = (m22 * m33) - (m23 * m32); 93 | r.m12 = -((m21 * m33) - (m23 * m31)); 94 | r.m13 = (m21 * m32) - (m22 * m31); 95 | 96 | r.m21 = -((m12 * m33) - (m13 * m32)); 97 | r.m22 = (m11 * m33) - (m13 * m31); 98 | r.m23 = -((m11 * m32) - (m12 * m31)); 99 | 100 | r.m31 = (m12 * m23) - (m13 * m22); 101 | r.m32 = -((m11 * m23) - (m13 * m21)); 102 | r.m33 = (m11 * m22) - (m12 * m21); 103 | 104 | return r.transpose(); 105 | } 106 | 107 | inline mat3 inverse() const 108 | { 109 | return adjoint() / determinant(); // @NOTE(Dihara): Watch out for divide by zero! 110 | } 111 | 112 | inline void print() const 113 | { 114 | printf("[%f, %f, %f]\n", m11, m12, m13); 115 | printf("[%f, %f, %f]\n", m21, m22, m23); 116 | printf("[%f, %f, %f]\n", m31, m32, m33); 117 | } 118 | 119 | inline const vec3& operator[] (unsigned index) const 120 | { 121 | assert(index < 3); 122 | return column[index]; 123 | } 124 | 125 | inline vec3& operator[] (unsigned index) 126 | { 127 | assert(index < 3); 128 | return column[index]; 129 | } 130 | 131 | friend mat3 operator*(const mat3& lhs, const T& rhs) 132 | { 133 | mat3 r; 134 | 135 | for (int i = 0; i < 9; i++) 136 | r.elem[i] = lhs.elem[i] * rhs; 137 | 138 | return r; 139 | } 140 | 141 | friend vec3 operator*(const mat3& lhs, const vec3& rhs) 142 | { 143 | vec3 r; 144 | 145 | r.x = (lhs.m11 * rhs.x) + (lhs.m12 * rhs.y) + (lhs.m13 * rhs.z); 146 | r.y = (lhs.m21 * rhs.x) + (lhs.m22 * rhs.y) + (lhs.m23 * rhs.z); 147 | r.z = (lhs.m31 * rhs.x) + (lhs.m32 * rhs.y) + (lhs.m33 * rhs.z); 148 | 149 | return r; 150 | } 151 | 152 | friend mat3 operator*(const mat3& lhs, const mat3& rhs) 153 | { 154 | mat3 r; 155 | 156 | r.m11 = (lhs.m11 * rhs.m11) + (lhs.m12 * rhs.m21) + (lhs.m13 * rhs.m31); 157 | r.m12 = (lhs.m11 * rhs.m12) + (lhs.m12 * rhs.m22) + (lhs.m13 * rhs.m32); 158 | r.m13 = (lhs.m11 * rhs.m13) + (lhs.m12 * rhs.m23) + (lhs.m13 * rhs.m33); 159 | 160 | r.m21 = (lhs.m21 * rhs.m11) + (lhs.m22 * rhs.m21) + (lhs.m23 * rhs.m31); 161 | r.m22 = (lhs.m21 * rhs.m12) + (lhs.m22 * rhs.m22) + (lhs.m23 * rhs.m32); 162 | r.m23 = (lhs.m21 * rhs.m13) + (lhs.m22 * rhs.m23) + (lhs.m23 * rhs.m33); 163 | 164 | r.m31 = (lhs.m31 * rhs.m11) + (lhs.m32 * rhs.m21) + (lhs.m33 * rhs.m31); 165 | r.m32 = (lhs.m31 * rhs.m12) + (lhs.m32 * rhs.m22) + (lhs.m33 * rhs.m32); 166 | r.m33 = (lhs.m31 * rhs.m13) + (lhs.m32 * rhs.m23) + (lhs.m33 * rhs.m33); 167 | 168 | return r; 169 | } 170 | }; 171 | 172 | using mat3f = mat3; 173 | 174 | } -------------------------------------------------------------------------------- /include/math/mat4.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace math 7 | { 8 | 9 | template 10 | struct mat4 11 | { 12 | union 13 | { 14 | struct 15 | { 16 | // m[row][column] 17 | T m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44; 18 | }; 19 | float elem[16]; 20 | vec4 column[4]; 21 | }; 22 | 23 | mat4() 24 | { 25 | for (int i = 0; i < 16; i++) 26 | elem[i] = 0; 27 | 28 | m11 = 1; 29 | m22 = 1; 30 | m33 = 1; 31 | m44 = 1; 32 | } 33 | 34 | mat4(const float& _m11, const float& _m12, const float& _m13, const float& _m14, 35 | const float& _m21, const float& _m22, const float& _m23, const float& _m24, 36 | const float& _m31, const float& _m32, const float& _m33, const float& _m34, 37 | const float& _m41, const float& _m42, const float& _m43, const float& _m44) 38 | { 39 | m11 = _m11; 40 | m12 = _m12; 41 | m13 = _m13; 42 | m14 = _m14; 43 | 44 | m21 = _m21; 45 | m22 = _m22; 46 | m23 = _m23; 47 | m24 = _m24; 48 | 49 | m31 = _m31; 50 | m32 = _m32; 51 | m33 = _m33; 52 | m34 = _m34; 53 | 54 | m41 = _m41; 55 | m42 = _m42; 56 | m43 = _m43; 57 | m44 = _m44; 58 | } 59 | 60 | mat4(const vec4& _c1, const vec4& _c2, const vec4& _c3, const vec4& _c4) 61 | { 62 | m11 = _c1.x; 63 | m21 = _c1.y; 64 | m31 = _c1.z; 65 | m41 = _c1.w; 66 | 67 | m12 = _c2.x; 68 | m22 = _c2.y; 69 | m32 = _c2.z; 70 | m42 = _c2.w; 71 | 72 | m13 = _c3.x; 73 | m23 = _c3.y; 74 | m33 = _c3.z; 75 | m43 = _c3.w; 76 | 77 | m14 = _c4.x; 78 | m24 = _c4.y; 79 | m34 = _c4.z; 80 | m44 = _c4.w; 81 | } 82 | 83 | inline mat4 transpose() const 84 | { 85 | mat4 r; 86 | 87 | r.m11 = m11; 88 | r.m21 = m12; 89 | r.m31 = m13; 90 | r.m41 = m14; 91 | 92 | r.m12 = m21; 93 | r.m22 = m22; 94 | r.m32 = m23; 95 | r.m42 = m24; 96 | 97 | r.m13 = m31; 98 | r.m23 = m32; 99 | r.m33 = m33; 100 | r.m43 = m34; 101 | 102 | r.m14 = m41; 103 | r.m24 = m42; 104 | r.m34 = m43; 105 | r.m44 = m44; 106 | 107 | return r; 108 | } 109 | 110 | inline T determinant() const 111 | { 112 | return (m11 * (m22 * ((m33 * m44) - (m34 * m43)) + m23 * ((m34 * m42) - (m32 * m44)) + m24 * ((m32 * m43) - (m33 * m42)))) 113 | - (m12 * (m21 * ((m33 * m44) - (m34 * m43)) + m23 * ((m34 * m41) - (m31 * m44)) + m24 * ((m31 * m43) - (m33 * m41)))) 114 | + (m13 * (m21 * ((m32 * m44) - (m34 * m42)) + m22 * ((m34 * m41) - (m31 * m44)) + m24 * ((m31 * m42) - (m32 * m41)))) 115 | - (m14 * (m21 * ((m32 * m43) - (m33 * m42)) + m22 * ((m33 * m41) - (m31 * m43)) + m23 * ((m31 * m42) - (m32 * m41)))); 116 | } 117 | 118 | inline mat4 adjoint() const 119 | { 120 | mat4 r; 121 | 122 | r.m11 = (m22 * m33 * m44) + (m23 * m34 * m42) + (m24 * m32 * m43) - (m22 * m34 * m43) - (m23 * m32 * m44) - (m24 * m33 * m42); 123 | r.m12 = -((m21 * m33 * m44) + (m23 * m34 * m41) + (m24 * m31 * m42) - (m21 * m34 * m43) - (m23 * m31 * m44) - (m24 * m33 * m41)); 124 | r.m13 = (m21 * m32 * m44) + (m22 * m34 * m42) + (m24 * m32 * m43) - (m21 * m34 * m42) - (m22 * m31 * m44) - (m24 * m32 * m41); 125 | r.m14 = -((m21 * m32 * m43) + (m22 * m33 * m41) + (m23 * m31 * m42) - (m21 * m33 * m42) - (m22 * m31 * m43) - (m23 * m32 * m41)); 126 | 127 | r.m21 = -((m12 * m33 * m44) + (m13 * m34 * m42) + (m14 * m32 * m43) - (m12 * m34 * m43) - (m13 * m32 * m44) - (m14 * m33 * m42)); 128 | r.m22 = (m11 * m33 * m44) + (m13 * m34 * m41) + (m14 * m31 * m43) - (m11 * m34 * m43) - (m13 * m31 * m44) - (m14 * m33 * m41); 129 | r.m23 = -((m11 * m32 * m44) + (m12 * m34 * m41) + (m14 * m31 * m42) - (m11 * m34 * m42) - (m12 * m31 * m44) - (m14 * m32 * m41)); 130 | r.m24 = (m11 * m32 * m43) + (m12 * m33 * m41) + (m13 * m31 * m42) - (m11 * m33 * m42) - (m12 * m31 * m43) - (m13 * m32 * m41); 131 | 132 | r.m31 = (m12 * m23 * m44) + (m13 * m24 * m42) + (m14 * m22 * m43) - (m12 * m24 * m43) - (m13 * m22 * m44) - (m14 * m23 * m42); 133 | r.m32 = -((m11 * m23 * m44) + (m13 * m24 * m41) + (m14 * m21 * m43) - (m11 * m24 * m43) - (m13 * m21 * m44) - (m14 * m23 * m41)); 134 | r.m33 = (m11 * m22 * m44) + (m12 * m24 * m41) + (m14 * m21 * m42) - (m11 * m24 * m42) - (m12 * m21 * m44) - (m14 * m22 * m41); 135 | r.m34 = -((m11 * m22 * m43) + (m12 * m23 * m41) + (m13 * m21 * m42) - (m11 * m23 * m42) - (m12 * m21 * m43) - (m13 * m22 * m41)); 136 | 137 | r.m41 = -((m12 * m23 * m34) + (m13 * m24 * m32) + (m14 * m22 * m33) - (m12 * m24 * m33) - (m13 * m22 * m34) - (m14 * m23 * m32)); 138 | r.m42 = (m11 * m23 * m34) + (m13 * m24 * m31) + (m14 * m21 * m33) - (m11 * m24 * m33) - (m13 * m21 * m34) - (m14 * m23 * m31); 139 | r.m43 = -((m11 * m22 * m34) + (m12 * m24 * m31) + (m14 * m21 * m32) - (m11 * m24 * m32) - (m12 * m21 * m34) - (m14 * m22 * m31)); 140 | r.m44 = (m11 * m22 * m33) + (m12 * m23 * m31) + (m13 * m21 * m32) - (m11 * m23 * m32) - (m12 * m21 * m33) - (m13 * m22 * m31); 141 | 142 | return r.transpose(); 143 | } 144 | 145 | inline mat4 inverse() const 146 | { 147 | return adjoint() / determinant(); // @NOTE(Dihara): Watch out for divide by zero! 148 | } 149 | 150 | inline void print() const 151 | { 152 | printf("[%f, %f, %f, %f]\n", m11, m12, m13, m14); 153 | printf("[%f, %f, %f, %f]\n", m21, m22, m23, m24); 154 | printf("[%f, %f, %f, %f]\n", m31, m32, m33, m34); 155 | printf("[%f, %f, %f, %f]\n", m41, m42, m43, m44); 156 | } 157 | 158 | inline const vec4& operator[] (unsigned index) const 159 | { 160 | assert(index < 4); 161 | return column[index]; 162 | } 163 | 164 | inline vec4& operator[] (unsigned index) 165 | { 166 | assert(index < 4); 167 | return column[index]; 168 | } 169 | 170 | friend mat4 operator*(const mat4& lhs, const T& rhs) 171 | { 172 | mat4 r; 173 | 174 | for (int i = 0; i < 16; i++) 175 | r.elem[i] = lhs.elem[i] * rhs; 176 | 177 | return r; 178 | } 179 | 180 | friend mat4 operator/(const mat4& lhs, const T& rhs) 181 | { 182 | mat4 r; 183 | 184 | for (int i = 0; i < 16; i++) 185 | r.elem[i] = lhs.elem[i] / rhs; 186 | 187 | return r; 188 | } 189 | 190 | friend vec4 operator*(const mat4& lhs, const vec4& rhs) 191 | { 192 | vec4 r; 193 | 194 | r.x = (lhs.m11 * rhs.x) + (lhs.m12 * rhs.y) + (lhs.m13 * rhs.z) + (lhs.m14 * rhs.w); 195 | r.y = (lhs.m21 * rhs.x) + (lhs.m22 * rhs.y) + (lhs.m23 * rhs.z) + (lhs.m24 * rhs.w); 196 | r.z = (lhs.m31 * rhs.x) + (lhs.m32 * rhs.y) + (lhs.m33 * rhs.z) + (lhs.m34 * rhs.w); 197 | r.w = (lhs.m41 * rhs.x) + (lhs.m42 * rhs.y) + (lhs.m43 * rhs.z) + (lhs.m44 * rhs.w); 198 | 199 | return r; 200 | } 201 | 202 | friend mat4 operator*(const mat4& lhs, const mat4& rhs) 203 | { 204 | mat4 r; 205 | 206 | r.m11 = (lhs.m11 * rhs.m11) + (lhs.m12 * rhs.m21) + (lhs.m13 * rhs.m31) + (lhs.m14 * rhs.m41); 207 | r.m12 = (lhs.m11 * rhs.m12) + (lhs.m12 * rhs.m22) + (lhs.m13 * rhs.m32) + (lhs.m14 * rhs.m42); 208 | r.m13 = (lhs.m11 * rhs.m13) + (lhs.m12 * rhs.m23) + (lhs.m13 * rhs.m33) + (lhs.m14 * rhs.m43); 209 | r.m14 = (lhs.m11 * rhs.m14) + (lhs.m12 * rhs.m24) + (lhs.m13 * rhs.m34) + (lhs.m14 * rhs.m44); 210 | 211 | r.m21 = (lhs.m21 * rhs.m11) + (lhs.m22 * rhs.m21) + (lhs.m23 * rhs.m31) + (lhs.m24 * rhs.m41); 212 | r.m22 = (lhs.m21 * rhs.m12) + (lhs.m22 * rhs.m22) + (lhs.m23 * rhs.m32) + (lhs.m24 * rhs.m42); 213 | r.m23 = (lhs.m21 * rhs.m13) + (lhs.m22 * rhs.m23) + (lhs.m23 * rhs.m33) + (lhs.m24 * rhs.m43); 214 | r.m24 = (lhs.m21 * rhs.m14) + (lhs.m22 * rhs.m24) + (lhs.m23 * rhs.m34) + (lhs.m24 * rhs.m44); 215 | 216 | r.m31 = (lhs.m31 * rhs.m11) + (lhs.m32 * rhs.m21) + (lhs.m33 * rhs.m31) + (lhs.m34 * rhs.m41); 217 | r.m32 = (lhs.m31 * rhs.m12) + (lhs.m32 * rhs.m22) + (lhs.m33 * rhs.m32) + (lhs.m34 * rhs.m42); 218 | r.m33 = (lhs.m31 * rhs.m13) + (lhs.m32 * rhs.m23) + (lhs.m33 * rhs.m33) + (lhs.m34 * rhs.m43); 219 | r.m34 = (lhs.m31 * rhs.m14) + (lhs.m32 * rhs.m24) + (lhs.m33 * rhs.m34) + (lhs.m34 * rhs.m44); 220 | 221 | r.m41 = (lhs.m41 * rhs.m11) + (lhs.m42 * rhs.m21) + (lhs.m43 * rhs.m31) + (lhs.m44 * rhs.m41); 222 | r.m42 = (lhs.m41 * rhs.m12) + (lhs.m42 * rhs.m22) + (lhs.m43 * rhs.m32) + (lhs.m44 * rhs.m42); 223 | r.m43 = (lhs.m41 * rhs.m13) + (lhs.m42 * rhs.m23) + (lhs.m43 * rhs.m33) + (lhs.m44 * rhs.m43); 224 | r.m44 = (lhs.m41 * rhs.m14) + (lhs.m42 * rhs.m24) + (lhs.m43 * rhs.m34) + (lhs.m44 * rhs.m44); 225 | 226 | return r; 227 | } 228 | }; 229 | 230 | 231 | 232 | using mat4f = mat4; 233 | 234 | } 235 | -------------------------------------------------------------------------------- /include/math/quat.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace math 7 | { 8 | struct quat 9 | { 10 | float w; 11 | vec3f v; 12 | 13 | quat() : w(1.0f), v(0.0f, 0.0f, 0.0f) { } 14 | 15 | quat(const float& _w, const float& _x, const float& _y, const float& _z) : w(_w), v(_x, _y, _z) { } 16 | 17 | quat(const float& _radians, const vec3f& _axis) 18 | { 19 | w = cosf(_radians / 2.0f); // @NOTE(Dihara): Is the half-angle supposed to be in radians or degrees? 20 | v = _axis * sinf(_radians / 2.0f); 21 | } 22 | 23 | friend quat operator*(const quat& lhs, const quat& rhs) 24 | { 25 | quat q; 26 | 27 | q.w = (lhs.w * rhs.w) - (lhs.v.dot(rhs.v)); 28 | q.v = rhs.v * lhs.w + lhs.v * rhs.w + (lhs.v.cross(rhs.v)); 29 | 30 | return q; 31 | } 32 | 33 | friend quat operator-(const quat& lhs, const quat& rhs) 34 | { 35 | return rhs * lhs.inverse(); 36 | } 37 | 38 | inline float magnitude() const 39 | { 40 | float v_mag = v.length(); 41 | return sqrtf((w * w) + (v_mag * v_mag)); 42 | } 43 | 44 | inline quat conjugate() const 45 | { 46 | return quat(w, -v.x, -v.y, -v.z); 47 | } 48 | 49 | inline quat inverse() const 50 | { 51 | // q^-1 = q* / ||q|| 52 | 53 | quat q = conjugate(); 54 | float m = magnitude(); 55 | 56 | q.w /= m; 57 | q.v = q.v / m; 58 | 59 | return q; // @NOTE(Dihara): Beware of divide-by-zero! 60 | } 61 | 62 | inline float dot(const quat& rhs) const 63 | { 64 | return (w * rhs.w) + (v.x * rhs.v.x) + (v.y * rhs.v.y) + (v.z * rhs.v.z); 65 | } 66 | 67 | inline quat exp(const float& e) const 68 | { 69 | quat q; 70 | 71 | if (fabs(w) < 0.9999f) 72 | { 73 | float alpha = acos(w); 74 | float new_alpha = alpha * e; 75 | 76 | q.w = cos(new_alpha); 77 | 78 | float mult = sin(new_alpha) / sin(alpha); 79 | q.v = v * mult; 80 | } 81 | 82 | return q; 83 | } 84 | 85 | inline quat slerp(const quat& q2, const float& t) const 86 | { 87 | quat q1 = *this; 88 | quat d = q1 - q2; 89 | quat d_exp = d.exp(t); 90 | return d_exp * q1; 91 | } 92 | }; 93 | } -------------------------------------------------------------------------------- /include/math/simd_float4.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace math 6 | { 7 | namespace simd 8 | { 9 | struct float4 10 | { 11 | __m128 data; 12 | 13 | inline float4(const float& _x = 0.0f, const float& _y = 0.0f, const float& _z = 0.0f, const float& _w = 0.0f) 14 | { 15 | float v[] = { _x, _y, _z, _w }; 16 | load(&v[0]); 17 | } 18 | 19 | inline float4(__m128 _data) : data(_data) 20 | { 21 | 22 | } 23 | 24 | inline float4(const float* _data) 25 | { 26 | load(_data); 27 | } 28 | 29 | inline float4(const float4& rhs) : data(rhs.data) 30 | { 31 | 32 | } 33 | 34 | inline float4& operator=(const __m128& rhs) 35 | { 36 | data = rhs; 37 | return *this; 38 | } 39 | 40 | inline float4& operator=(const float4& rhs) 41 | { 42 | data = rhs.data; 43 | return *this; 44 | } 45 | 46 | inline void load(const float* _data) 47 | { 48 | data = _mm_load_ps(_data); 49 | } 50 | 51 | inline void store(float* _data) 52 | { 53 | _mm_store_ps(_data, data); 54 | } 55 | 56 | friend float4 operator+(const float4& lhs, const float4& rhs) 57 | { 58 | return _mm_add_ps(lhs.data, rhs.data); 59 | } 60 | 61 | friend float4 operator-(const float4& lhs, const float4& rhs) 62 | { 63 | return _mm_sub_ps(lhs.data, rhs.data); 64 | } 65 | 66 | friend float4 operator*(const float4& lhs, const float4& rhs) 67 | { 68 | return _mm_mul_ps(lhs.data, rhs.data); 69 | } 70 | 71 | friend float4 operator/(const float4& lhs, const float4& rhs) 72 | { 73 | return _mm_div_ps(lhs.data, rhs.data); 74 | } 75 | }; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /include/math/simd_float8.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace math 6 | { 7 | namespace simd 8 | { 9 | struct float8 10 | { 11 | __m256 data; 12 | 13 | inline static void zero_upper() 14 | { 15 | _mm256_zeroupper(); 16 | } 17 | 18 | inline float8(const float& _v0 = 0.0f, const float& _v1 = 0.0f, const float& _v2 = 0.0f, const float& _v3 = 0.0f, const float& _v4 = 0.0f, const float& _v5 = 0.0f, const float& _v6 = 0.0f, const float& _v7 = 0.0f) 19 | { 20 | float v[] = { _v0, _v1, _v2, _v3, _v4, _v5, _v6, _v7 }; 21 | load(&v[0]); 22 | } 23 | 24 | inline float8(__m256 _data) : data(_data) 25 | { 26 | 27 | } 28 | 29 | inline float8(const float* _data) 30 | { 31 | load(_data); 32 | } 33 | 34 | inline float8(const float8& rhs) : data(rhs.data) 35 | { 36 | 37 | } 38 | 39 | inline float8& operator=(const __m256& rhs) 40 | { 41 | data = rhs; 42 | return *this; 43 | } 44 | 45 | inline float8& operator=(const float8& rhs) 46 | { 47 | data = rhs.data; 48 | return *this; 49 | } 50 | 51 | inline void load(const float* _data) 52 | { 53 | data = _mm256_load_ps(_data); 54 | } 55 | 56 | inline void store(float* _data) 57 | { 58 | _mm256_store_ps(_data, data); 59 | } 60 | 61 | friend float8 operator+(const float8& lhs, const float8& rhs) 62 | { 63 | return _mm256_add_ps(lhs.data, rhs.data); 64 | } 65 | 66 | friend float8 operator-(const float8& lhs, const float8& rhs) 67 | { 68 | return _mm256_sub_ps(lhs.data, rhs.data); 69 | } 70 | 71 | friend float8 operator*(const float8& lhs, const float8& rhs) 72 | { 73 | return _mm256_mul_ps(lhs.data, rhs.data); 74 | } 75 | 76 | friend float8 operator/(const float8& lhs, const float8& rhs) 77 | { 78 | return _mm256_div_ps(lhs.data, rhs.data); 79 | } 80 | }; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /include/math/simd_mat4x4.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace math 6 | { 7 | namespace simd 8 | { 9 | struct mat4fx4 10 | { 11 | vec4fx4 col[4]; 12 | 13 | inline mat4fx4(const vec4fx4& _col0 = vec4fx4(), const vec4fx4& _col1 = vec4fx4(), const vec4fx4& _col2 = vec4fx4(), const vec4fx4& _col3 = vec4fx4()) 14 | { 15 | col[0] = _col0; 16 | col[1] = _col1; 17 | col[2] = _col2; 18 | col[3] = _col3; 19 | } 20 | 21 | inline mat4fx4(const mat4fx4& rhs) 22 | { 23 | col[0] = rhs.col[0]; 24 | col[1] = rhs.col[1]; 25 | col[2] = rhs.col[2]; 26 | col[3] = rhs.col[3]; 27 | } 28 | 29 | inline mat4fx4& operator=(const mat4fx4& rhs) 30 | { 31 | col[0] = rhs.col[0]; 32 | col[1] = rhs.col[1]; 33 | col[2] = rhs.col[2]; 34 | col[3] = rhs.col[3]; 35 | return *this; 36 | } 37 | 38 | inline friend vec4fx4 operator*(const mat4fx4& lhs, const vec4fx4& rhs) 39 | { 40 | vec4fx4 v; 41 | 42 | v.x = lhs.col[0].x * rhs.x + lhs.col[1].x * rhs.y + lhs.col[2].x * rhs.z + lhs.col[3].x * rhs.w; 43 | v.y = lhs.col[0].y * rhs.x + lhs.col[1].y * rhs.y + lhs.col[2].y * rhs.z + lhs.col[3].y * rhs.w; 44 | v.z = lhs.col[0].z * rhs.x + lhs.col[1].z * rhs.y + lhs.col[2].z * rhs.z + lhs.col[3].z * rhs.w; 45 | v.w = lhs.col[0].w * rhs.x + lhs.col[1].w * rhs.y + lhs.col[2].w * rhs.z + lhs.col[3].w * rhs.w; 46 | 47 | return v; 48 | } 49 | 50 | inline friend mat4fx4 operator*(const mat4fx4& lhs, const mat4fx4& rhs) 51 | { 52 | mat4fx4 m; 53 | 54 | m.col[0] = lhs * rhs.col[0]; 55 | m.col[1] = lhs * rhs.col[1]; 56 | m.col[2] = lhs * rhs.col[2]; 57 | m.col[3] = lhs * rhs.col[3]; 58 | 59 | return m; 60 | } 61 | }; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /include/math/simd_mat4x8.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace math 6 | { 7 | namespace simd 8 | { 9 | struct mat4fx8 10 | { 11 | vec4fx8 col[4]; 12 | 13 | inline mat4fx8(const vec4fx8& _col0 = vec4fx8(), const vec4fx8& _col1 = vec4fx8(), const vec4fx8& _col2 = vec4fx8(), const vec4fx8& _col3 = vec4fx8()) 14 | { 15 | col[0] = _col0; 16 | col[1] = _col1; 17 | col[2] = _col2; 18 | col[3] = _col3; 19 | } 20 | 21 | inline mat4fx8(const mat4fx8& rhs) 22 | { 23 | col[0] = rhs.col[0]; 24 | col[1] = rhs.col[1]; 25 | col[2] = rhs.col[2]; 26 | col[3] = rhs.col[3]; 27 | } 28 | 29 | inline mat4fx8& operator=(const mat4fx8& rhs) 30 | { 31 | col[0] = rhs.col[0]; 32 | col[1] = rhs.col[1]; 33 | col[2] = rhs.col[2]; 34 | col[3] = rhs.col[3]; 35 | return *this; 36 | } 37 | 38 | inline friend vec4fx8 operator*(const mat4fx8& lhs, const vec4fx8& rhs) 39 | { 40 | vec4fx8 v; 41 | 42 | v.x = lhs.col[0].x * rhs.x + lhs.col[1].x * rhs.y + lhs.col[2].x * rhs.z + lhs.col[3].x * rhs.w; 43 | v.y = lhs.col[0].y * rhs.x + lhs.col[1].y * rhs.y + lhs.col[2].y * rhs.z + lhs.col[3].y * rhs.w; 44 | v.z = lhs.col[0].z * rhs.x + lhs.col[1].z * rhs.y + lhs.col[2].z * rhs.z + lhs.col[3].z * rhs.w; 45 | v.w = lhs.col[0].w * rhs.x + lhs.col[1].w * rhs.y + lhs.col[2].w * rhs.z + lhs.col[3].w * rhs.w; 46 | 47 | return v; 48 | } 49 | 50 | inline friend mat4fx8 operator*(const mat4fx8& lhs, const mat4fx8& rhs) 51 | { 52 | mat4fx8 m; 53 | 54 | m.col[0] = lhs * rhs.col[0]; 55 | m.col[1] = lhs * rhs.col[1]; 56 | m.col[2] = lhs * rhs.col[2]; 57 | m.col[3] = lhs * rhs.col[3]; 58 | 59 | return m; 60 | } 61 | }; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /include/math/simd_vec4x4.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace math 6 | { 7 | namespace simd 8 | { 9 | struct vec4fx4 10 | { 11 | float4 x; 12 | float4 y; 13 | float4 z; 14 | float4 w; 15 | 16 | inline vec4fx4(const float4& _x = float4(), const float4& _y = float4(), const float4& _z = float4(), const float4& _w = float4()) : x(_x), y(_y), z(_z), w(_w) { } 17 | 18 | inline vec4fx4(const vec4fx4& rhs) : x(rhs.x), y(rhs.y), z(rhs.z), w(rhs.w) 19 | { 20 | 21 | } 22 | 23 | inline vec4fx4& operator=(const vec4fx4& rhs) 24 | { 25 | x = rhs.x; 26 | y = rhs.y; 27 | z = rhs.z; 28 | w = rhs.w; 29 | return *this; 30 | } 31 | 32 | inline friend vec4fx4 operator+(const vec4fx4& lhs, const vec4fx4& rhs) 33 | { 34 | return vec4fx4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); 35 | } 36 | 37 | inline friend vec4fx4 operator-(const vec4fx4& lhs, const vec4fx4& rhs) 38 | { 39 | return vec4fx4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); 40 | } 41 | 42 | inline float4 dot(const vec4fx4& rhs) 43 | { 44 | return x * rhs.x + y * rhs.y + z * rhs.z + w * rhs.w; 45 | } 46 | 47 | inline vec4fx4 cross(const vec4fx4& rhs) 48 | { 49 | return vec4fx4(y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x); 50 | } 51 | }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /include/math/simd_vec4x8.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace math 6 | { 7 | namespace simd 8 | { 9 | struct vec4fx8 10 | { 11 | float8 x; 12 | float8 y; 13 | float8 z; 14 | float8 w; 15 | 16 | inline vec4fx8(const float8& _x = float8(), const float8& _y = float8(), const float8& _z = float8(), const float8& _w = float8()) : x(_x), y(_y), z(_z), w(_w) { } 17 | 18 | inline vec4fx8(const vec4fx8& rhs) : x(rhs.x), y(rhs.y), z(rhs.z), w(rhs.w) 19 | { 20 | 21 | } 22 | 23 | inline vec4fx8& operator=(const vec4fx8& rhs) 24 | { 25 | x = rhs.x; 26 | y = rhs.y; 27 | z = rhs.z; 28 | w = rhs.w; 29 | return *this; 30 | } 31 | 32 | inline friend vec4fx8 operator+(const vec4fx8& lhs, const vec4fx8& rhs) 33 | { 34 | return vec4fx8(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); 35 | } 36 | 37 | inline friend vec4fx8 operator-(const vec4fx8& lhs, const vec4fx8& rhs) 38 | { 39 | return vec4fx8(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); 40 | } 41 | 42 | inline float8 dot(const vec4fx8& rhs) 43 | { 44 | return x * rhs.x + y * rhs.y + z * rhs.z + w * rhs.w; 45 | } 46 | 47 | inline vec4fx8 cross(const vec4fx8& rhs) 48 | { 49 | return vec4fx8(y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x); 50 | } 51 | }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /include/math/transform.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define TE_RIGHT_HANDED 8 | 9 | namespace math 10 | { 11 | inline mat4f lookat_lh(const vec3f& _eye, const vec3f& _origin, const vec3f& _up) 12 | { 13 | vec3f front = _eye.direction(_origin); 14 | vec3f right = _up.cross(front).normalize(); 15 | vec3f up = front.cross(right).normalize(); 16 | 17 | mat4f m; 18 | 19 | m.m11 = right.x; 20 | m.m12 = right.y; 21 | m.m13 = right.z; 22 | 23 | m.m21 = up.x; 24 | m.m22 = up.y; 25 | m.m23 = up.z; 26 | 27 | m.m31 = front.x; 28 | m.m32 = front.y; 29 | m.m33 = front.z; 30 | 31 | m.m14 = -right.dot(_eye); 32 | m.m24 = -up.dot(_eye); 33 | m.m34 = -front.dot(_eye); 34 | 35 | return m; 36 | } 37 | 38 | inline mat4f lookat_rh(const vec3f& _eye, const vec3f& _origin, const vec3f& _up) 39 | { 40 | vec3f front = (_origin - _eye).normalize(); 41 | vec3f right = front.cross(_up).normalize(); 42 | vec3f up = right.cross(front).normalize(); 43 | 44 | mat4f m; 45 | 46 | m.m11 = right.x; 47 | m.m12 = right.y; 48 | m.m13 = right.z; 49 | 50 | m.m21 = up.x; 51 | m.m22 = up.y; 52 | m.m23 = up.z; 53 | 54 | m.m31 = -front.x; 55 | m.m32 = -front.y; 56 | m.m33 = -front.z; 57 | 58 | m.m14 = -right.dot(_eye); 59 | m.m24 = -up.dot(_eye); 60 | m.m34 = front.dot(_eye); 61 | 62 | return m; 63 | } 64 | 65 | inline mat4f lookat(const vec3f& eye, const vec3f& origin, const vec3f& up) 66 | { 67 | # if defined(TE_RIGHT_HANDED) 68 | return lookat_rh(eye, origin, up); 69 | # else 70 | return lookat_lh(eye, origin, up); 71 | # endif 72 | } 73 | 74 | inline mat4f perspective_lh_zo(const float& _aspect, const float& _fov, const float& _near, const float& _far) 75 | { 76 | mat4f m; 77 | 78 | float tanFoV2 = tanf(_fov / 2.0f); 79 | 80 | m.m11 = 1.0f / (_aspect * tanFoV2); 81 | m.m22 = 1.0f / tanFoV2; 82 | m.m33 = _far / (_far - _near); 83 | m.m34 = -(_far * _near) / (_far - _near); 84 | m.m43 = 1.0f; 85 | m.m44 = 0.0f; 86 | 87 | return m; 88 | } 89 | 90 | inline mat4f perspective_lh_no(const float& _aspect, const float& _fov, const float& _near, const float& _far) 91 | { 92 | mat4f m; 93 | 94 | float tanFoV2 = tanf(_fov / 2.0f); 95 | 96 | m.m11 = 1.0f / (_aspect * tanFoV2); 97 | m.m22 = 1.0f / tanFoV2; 98 | m.m33 = (_far + _near) / (_far - _near); 99 | m.m34 = -(2.0f * _far * _near) / (_far - _near); 100 | m.m43 = 1.0f; 101 | m.m44 = 0.0f; 102 | 103 | return m; 104 | } 105 | 106 | inline mat4f perspective_rh_zo(const float& _aspect, const float& _fov, const float& _near, const float& _far) 107 | { 108 | mat4f m; 109 | 110 | float tanFoV2 = tanf(_fov / 2.0f); 111 | 112 | m.m11 = 1.0f / (_aspect * tanFoV2); 113 | m.m22 = 1.0f / tanFoV2; 114 | m.m33 = _far / (_near - _far); 115 | m.m34 = -(_far * _near) / (_far - _near); 116 | m.m43 = -1.0f; 117 | m.m44 = 0.0f; 118 | 119 | return m; 120 | } 121 | 122 | inline mat4f perspective_rh_no(const float& _aspect, const float& _fov, const float& _near, const float& _far) 123 | { 124 | mat4f m; 125 | 126 | float tanFoV2 = tanf(_fov / 2.0f); 127 | 128 | m.m11 = 1.0f / (_aspect * tanFoV2); 129 | m.m22 = 1.0f / tanFoV2; 130 | m.m33 = -(_far + _near) / (_far - _near); 131 | m.m34 = -(2.0f * _far * _near) / (_far - _near); 132 | m.m43 = -1.0f; 133 | m.m44 = 0.0f; 134 | 135 | return m; 136 | } 137 | 138 | inline mat4f perspective(const float& _aspect, const float& _fov, const float& _near, const float& _far) 139 | { 140 | #if defined(TE_RIGHT_HANDED) 141 | # if defined(TE_ZERO_TO_ONE) 142 | return perspective_rh_zo(_aspect, _fov, _near, _far); 143 | # else 144 | return perspective_rh_no(_aspect, _fov, _near, _far); 145 | # endif 146 | #else 147 | # if defined(TE_ZERO_TO_ONE) 148 | return perspective_lh_zo(_aspect, _fov, _near, _far); 149 | # else 150 | return perspective_lh_no(_aspect, _fov, _near, _far); 151 | # endif 152 | #endif 153 | } 154 | 155 | inline mat4f ortho_lh_zo(const float& _l, const float& _r, const float& _b, const float& _t, const float& _n, const float& _f) 156 | { 157 | mat4f m; 158 | 159 | m.m11 = 2.0f / (_r - _l); 160 | m.m22 = 2.0f / (_t - _b); 161 | m.m33 = 1.0f / (_f - _n); 162 | m.m14 = -(_r + _l) / (_r - _l); 163 | m.m24 = -(_t + _b) / (_t - _b); 164 | m.m34 = -_n / (_f - _n); 165 | 166 | return m; 167 | } 168 | 169 | inline mat4f ortho_lh_no(const float& _l, const float& _r, const float& _b, const float& _t, const float& _n, const float& _f) 170 | { 171 | mat4f m; 172 | 173 | m.m11 = 2.0f / (_r - _l); 174 | m.m22 = 2.0f / (_t - _b); 175 | m.m33 = 2.0f / (_f - _n); 176 | m.m14 = -(_r + _l) / (_r - _l); 177 | m.m24 = -(_t + _b) / (_t - _b); 178 | m.m34 = -(_f + _n) / (_f - _n); 179 | 180 | return m; 181 | } 182 | 183 | inline mat4f ortho_rh_zo(const float& _l, const float& _r, const float& _b, const float& _t, const float& _n, const float& _f) 184 | { 185 | mat4f m; 186 | 187 | m.m11 = 2.0f / (_r - _l); 188 | m.m22 = 2.0f / (_t - _b); 189 | m.m33 = -1.0f / (_f - _n); 190 | m.m14 = -(_r + _l) / (_r - _l); 191 | m.m24 = -(_t + _b) / (_t - _b); 192 | m.m34 = -_n / (_f - _n); 193 | 194 | return m; 195 | } 196 | 197 | inline mat4f ortho_rh_no(const float& _l, const float& _r, const float& _b, const float& _t, const float& _n, const float& _f) 198 | { 199 | mat4f m; 200 | 201 | m.m11 = 2.0f / (_r - _l); 202 | m.m22 = 2.0f / (_t - _b); 203 | m.m33 = -2.0f / (_f - _n); 204 | m.m14 = -(_r + _l) / (_r - _l); 205 | m.m24 = -(_t + _b) / (_t - _b); 206 | m.m34 = -(_f + _n) / (_f - _n); 207 | 208 | return m; 209 | } 210 | 211 | inline mat4f ortho(const float& _l, const float& _r, const float& _b, const float& _t, const float& _n, const float& _f) 212 | { 213 | #if defined(TE_RIGHT_HANDED) 214 | # if defined(TE_ZERO_TO_ONE) 215 | return ortho_rh_zo(_l, _r, _b, _t, _n, _f); 216 | # else 217 | return ortho_rh_no(_l, _r, _b, _t, _n, _f); 218 | # endif 219 | #else 220 | # if defined(TE_ZERO_TO_ONE) 221 | return ortho_lh_zo(_l, _r, _b, _t, _n, _f); 222 | # else 223 | return ortho_lh_no(_l, _r, _b, _t, _n, _f); 224 | # endif 225 | #endif 226 | } 227 | 228 | inline mat4f rotation(const float& _radians, const vec3f& _axis) 229 | { 230 | mat4f m; 231 | 232 | float cosTheta = cosf(_radians); 233 | float sinTheta = sinf(_radians); 234 | 235 | m.m11 = powf(_axis.x, 2.0f) * (1.0f - cosTheta) + cosTheta; 236 | m.m12 = _axis.x * _axis.y * (1.0f - cosTheta) - _axis.z * sinTheta; 237 | m.m13 = _axis.x * _axis.z * (1.0f - cosTheta) + _axis.y * sinTheta; 238 | 239 | m.m21 = _axis.x * _axis.y * (1.0f - cosTheta) + _axis.z * sinTheta; 240 | m.m22 = powf(_axis.y, 2.0f) * (1.0f - cosTheta) + cosTheta; 241 | m.m23 = _axis.y * _axis.z * (1.0f - cosf(_radians)) - _axis.x * sinTheta; 242 | 243 | m.m31 = _axis.x * _axis.z * (1.0f - cosTheta) - _axis.y * sinTheta; 244 | m.m32 = _axis.y * _axis.z * (1.0f - cosTheta) + _axis.x * sinTheta; 245 | m.m33 = powf(_axis.z, 2.0f) * (1.0f - cosTheta) + cosTheta; 246 | 247 | return m; 248 | } 249 | 250 | inline mat4f rotation(const float& _x, const float& _y, const float& _z) 251 | { 252 | mat4f B, P, H; 253 | 254 | P.m22 = cosf(_x); 255 | P.m23 = -sinf(_x); 256 | 257 | P.m32 = sinf(_x); 258 | P.m33 = cosf(_x); 259 | 260 | H.m11 = cosf(_y); 261 | H.m13 = sinf(_y); 262 | 263 | H.m31 = -sinf(_y); 264 | H.m33 = cosf(_y); 265 | 266 | B.m11 = cosf(_z); 267 | B.m12 = -sinf(_z); 268 | 269 | B.m21 = sinf(_z); 270 | B.m22 = cosf(_z); 271 | 272 | return H * P * B; 273 | } 274 | 275 | inline mat4f translation(const vec3f& _position) 276 | { 277 | mat4f m; 278 | 279 | m.m14 = _position.x; 280 | m.m24 = _position.y; 281 | m.m34 = _position.z; 282 | 283 | return m; 284 | } 285 | 286 | inline mat4f scale(const vec3f& _scale) 287 | { 288 | mat4f m; 289 | 290 | m.m11 = _scale.x; 291 | m.m22 = _scale.y; 292 | m.m33 = _scale.z; 293 | 294 | return m; 295 | } 296 | 297 | inline mat4f scale(const float& _scale, const vec3f& _axis) 298 | { 299 | mat4f m; 300 | 301 | m.m11 = 1.0f + (_scale - 1.0f) * powf(_axis.x, 2.0f); 302 | m.m12 = (_scale - 1.0f) * _axis.x * _axis.y; 303 | m.m13 = (_scale - 1.0f) * _axis.x * _axis.z; 304 | 305 | m.m21 = (_scale - 1.0f) * _axis.x * _axis.y; 306 | m.m22 = 1.0f + (_scale - 1.0f) * powf(_axis.y, 2.0f); 307 | m.m23 = (_scale - 1.0f) * _axis.y * _axis.z; 308 | 309 | m.m31 = (_scale - 1.0f) * _axis.x * _axis.z; 310 | m.m32 = (_scale - 1.0f) * _axis.y * _axis.z; 311 | m.m33 = 1.0f + (_scale - 1.0f) * powf(_axis.z, 2.0f); 312 | 313 | return m; 314 | } 315 | 316 | inline mat4f euler_to_mat4(const float& _x, const float& _y, const float& _z) 317 | { 318 | mat4f m; 319 | 320 | float ch = cosf(_y); 321 | float cb = cosf(_z); 322 | float cp = cosf(_x); 323 | float sh = sinf(_y); 324 | float sb = sinf(_z); 325 | float sp = sinf(_x); 326 | 327 | m.m11 = ch * cb + sh * sp * sb; 328 | m.m12 = ch * sb + sh * sp * cb; 329 | m.m13 = sh * cp; 330 | 331 | m.m21 = sb * cp; 332 | m.m22 = cb * cp; 333 | m.m23 = -sp; 334 | 335 | m.m31 = -sh * cb + ch * sp * sb; 336 | m.m32 = sb * sh + ch * sp * cb; 337 | m.m33 = ch * cp; 338 | 339 | return m; 340 | } 341 | 342 | inline mat4f quat_to_mat4(const quat& _quat) 343 | { 344 | mat4f m; 345 | 346 | m.m11 = 1.0f - (2.0f * (_quat.v.y * _quat.v.y)) - (2.0f * (_quat.v.z * _quat.v.z)); 347 | m.m12 = (2.0f * (_quat.v.x * _quat.v.y)) - (2.0f * (_quat.w * _quat.v.z)); 348 | m.m13 = (2.0f * (_quat.v.x * _quat.v.z)) + (2.0f * (_quat.w * _quat.v.y)); 349 | 350 | m.m21 = (2.0f * (_quat.v.x * _quat.v.y)) + (2.0f * (_quat.w * _quat.v.z)); 351 | m.m22 = 1.0f - (2.0f * (_quat.v.x * _quat.v.z)) - (2.0f * (_quat.v.z * _quat.v.z)); 352 | m.m23 = (2.0f * (_quat.v.y * _quat.v.z)) + (2.0f * (_quat.w * _quat.v.x)); 353 | 354 | m.m31 = (2.0f * (_quat.v.x * _quat.v.y)) - (2.0f * (_quat.w * _quat.v.z)); 355 | m.m32 = (2.0f * (_quat.v.y * _quat.v.z)) + (2.0f * (_quat.w * _quat.v.x)); 356 | m.m33 = 1.0f - (2.0f * (_quat.v.x * _quat.v.x)) - (2.0f * (_quat.v.y * _quat.v.y)); 357 | 358 | return m; 359 | } 360 | 361 | inline quat mat4_to_quat(const mat4f& _mat) 362 | { 363 | quat q; 364 | 365 | float fourWSquaredMinus1 = _mat.m11 + _mat.m22 + _mat.m33; 366 | float fourXSquaredMinus1 = _mat.m11 - _mat.m22 - _mat.m33; 367 | float fourYSquaredMinus1 = _mat.m22 - _mat.m11 - _mat.m33; 368 | float fourZSquaredMinus1 = _mat.m33 - _mat.m11 - _mat.m22; 369 | 370 | int biggestIndex = 0; 371 | float fourBiggestSquaredMinus1 = fourWSquaredMinus1; 372 | 373 | if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) 374 | { 375 | fourBiggestSquaredMinus1 = fourXSquaredMinus1; 376 | biggestIndex = 1; 377 | } 378 | if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) 379 | { 380 | fourBiggestSquaredMinus1 = fourYSquaredMinus1; 381 | biggestIndex = 2; 382 | } 383 | if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) 384 | { 385 | fourBiggestSquaredMinus1 = fourZSquaredMinus1; 386 | biggestIndex = 3; 387 | } 388 | 389 | float biggestVal = sqrt(fourBiggestSquaredMinus1 + 1.0f) * 0.5f; 390 | float mult = 0.25f / biggestVal; 391 | 392 | switch (biggestIndex) 393 | { 394 | case 0: 395 | { 396 | q.w = biggestVal; 397 | q.v.x = (_mat.m32 - _mat.m23) * mult; 398 | q.v.y = (_mat.m13 - _mat.m31) * mult; 399 | q.v.z = (_mat.m21 - _mat.m12) * mult; 400 | break; 401 | } 402 | case 1: 403 | { 404 | q.v.x = biggestVal; 405 | q.w = (_mat.m32 - _mat.m23) * mult; 406 | q.v.y = (_mat.m21 - _mat.m12) * mult; 407 | q.v.z = (_mat.m13 - _mat.m31) * mult; 408 | break; 409 | } 410 | case 2: 411 | { 412 | q.v.y = biggestVal; 413 | q.w = (_mat.m13 - _mat.m31) * mult; 414 | q.v.x = (_mat.m21 - _mat.m12) * mult; 415 | q.v.z = (_mat.m32 - _mat.m23) * mult; 416 | break; 417 | } 418 | case 3: 419 | { 420 | q.v.z = biggestVal; 421 | q.w = (_mat.m21 - _mat.m12) * mult; 422 | q.v.x = (_mat.m13 - _mat.m31) * mult; 423 | q.v.y = (_mat.m32 - _mat.m23) * mult; 424 | break; 425 | } 426 | } 427 | 428 | return q; 429 | } 430 | 431 | inline quat euler_to_quat(const float& _x, const float& _y, const float& _z) 432 | { 433 | quat q; 434 | 435 | q.w = cosf(_y / 2.0f) * cosf(_x / 2.0f) * cosf(_z / 2.0f) + sinf(_y / 2.0f) * sinf(_x / 2.0f) * sinf(_z / 2.0f); 436 | q.v.x = cosf(_y / 2.0f) * sinf(_x / 2.0f) * cosf(_z / 2.0f) - sinf(_y / 2.0f) * cosf(_x / 2.0f) * sinf(_z / 2.0f); 437 | q.v.y = cosf(_y / 2.0f) * sinf(_x / 2.0f) * sinf(_z / 2.0f) - sinf(_y / 2.0f) * cosf(_x / 2.0f) * cosf(_z / 2.0f); 438 | q.v.z = sinf(_y / 2.0f) * sinf(_x / 2.0f) * cosf(_z / 2.0f) - cosf(_y / 2.0f) * cosf(_x / 2.0f) * sinf(_z / 2.0f); 439 | 440 | return q; 441 | } 442 | 443 | inline vec3f mat4_to_euler(const mat4f& _mat) 444 | { 445 | vec3f euler; 446 | 447 | float sp = -_mat.m23; 448 | 449 | if (sp <= -1.0f) 450 | { 451 | euler.x = -1.570796f; 452 | } 453 | else if (sp >= 1.0f) 454 | euler.x = 1.570796f; 455 | else 456 | euler.x = asinf(sp); 457 | 458 | if (fabs(sp) > 0.9999f) 459 | { 460 | euler.z = 0.0f; 461 | euler.y = atan2(-_mat.m31, _mat.m11); 462 | } 463 | else 464 | { 465 | euler.y = atan2(_mat.m31, _mat.m11); 466 | euler.z = atan2(_mat.m21, _mat.m22); 467 | } 468 | 469 | return euler; 470 | } 471 | 472 | inline vec3f quat_to_euler(const quat& _quat) 473 | { 474 | vec3f e; 475 | 476 | float sp = -2.0f * (_quat.v.y - _quat.w * _quat.v.x); 477 | 478 | if (fabs(sp) > 0.9999f) 479 | { 480 | e.x = 1.570796f * sp; 481 | e.y = atan2(-_quat.v.x * _quat.v.z + _quat.w * _quat.v.y, 0.5f - _quat.v.y * _quat.v.y - _quat.v.z * _quat.v.z); 482 | e.z = 0.0f; 483 | } 484 | else 485 | { 486 | e.x = asin(sp); 487 | e.y = atan2(_quat.v.x * _quat.v.z + _quat.w * _quat.v.y, 0.5f - _quat.v.x * _quat.v.x - _quat.v.y * _quat.v.y); 488 | e.z = atan2(_quat.v.x * _quat.v.y + _quat.w * _quat.v.z, 0.5f - _quat.v.x * _quat.v.x - _quat.v.z * _quat.v.z); 489 | } 490 | 491 | return e; 492 | } 493 | } 494 | -------------------------------------------------------------------------------- /include/math/utility.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | namespace math 7 | { 8 | inline float radians(const float& _degrees) 9 | { 10 | return (_degrees * M_PI) / 180.0f; 11 | } 12 | 13 | inline float degrees(const float& _radians) 14 | { 15 | return (_radians * 180.0f) / float(M_PI); 16 | } 17 | 18 | inline float lerp(float a, float b, float t) 19 | { 20 | return t < 0.0f ? a : (t > 1.0f ? b : (a * (1.0f - t) + b * t)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /include/math/vec2.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace math 8 | { 9 | 10 | template 11 | struct vec2 12 | { 13 | union 14 | { 15 | struct 16 | { 17 | T x, y; 18 | }; 19 | T data[2]; 20 | }; 21 | 22 | vec2() : x(0.0), y(0.0) {} 23 | vec2(const T& v) : x(v), y(v) {} 24 | vec2(const T& _x, const T& _y) : x(_x), y(_y) {} 25 | 26 | friend vec2 operator+(const vec2& lhs, const vec2& rhs) 27 | { 28 | return vec2(lhs.x + rhs.x, lhs.y + rhs.y); 29 | } 30 | 31 | friend vec2 operator-(const vec2& lhs, const vec2& rhs) 32 | { 33 | return vec2(lhs.x - rhs.x, lhs.y - rhs.y); 34 | } 35 | 36 | friend vec2 operator*(const vec2& lhs, const T& rhs) 37 | { 38 | return vec2(lhs.x * rhs, lhs.y * rhs); 39 | } 40 | 41 | friend vec2 operator*(const T& lhs, const vec2& rhs) 42 | { 43 | return vec2(lhs * rhs.x, lhs * rhs.y); 44 | } 45 | 46 | friend vec2 operator/(const vec2& lhs, const T& rhs) 47 | { 48 | return vec2(lhs.x / rhs, lhs.y / rhs); 49 | } 50 | 51 | inline const T& operator[] (unsigned index) const 52 | { 53 | assert(index < 2); 54 | return data[index]; 55 | } 56 | 57 | inline T& operator[] (unsigned index) 58 | { 59 | assert(index < 2); 60 | return data[index]; 61 | } 62 | 63 | inline float length() const 64 | { 65 | return sqrt(x*x + y * y); 66 | } 67 | 68 | inline float distance(const vec2& v) const 69 | { 70 | auto r = *this - v; 71 | return r.length(); 72 | } 73 | 74 | inline float dot(vec2& b) const 75 | { 76 | return x * b.x + y * b.y; 77 | } 78 | 79 | inline vec2 normalize() const 80 | { 81 | auto l = length(); 82 | return vec2(x / l, y / l); 83 | } 84 | 85 | inline vec2 direction(const vec2& to) const 86 | { 87 | auto v = to - *this; 88 | return v.normalize(); 89 | } 90 | 91 | inline vec2 lerp(const vec2& b, float t) const 92 | { 93 | return t < 0.0f ? *this : (t > 1.0f ? b : (*this * (1.0f - t) + b * t));; 94 | } 95 | 96 | inline void print() const 97 | { 98 | printf("[%f, %f]\n", x, y); 99 | } 100 | }; 101 | 102 | using vec2f = vec2; 103 | using vec2i = vec2; 104 | using vec2u = vec2; 105 | 106 | } -------------------------------------------------------------------------------- /include/math/vec3.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace math 9 | { 10 | 11 | template 12 | struct vec3 13 | { 14 | union 15 | { 16 | struct 17 | { 18 | T x, y, z; 19 | }; 20 | T data[3]; 21 | }; 22 | 23 | vec3() : x(0.0), y(0.0), z(0.0) {} 24 | vec3(const T& v) : x(v), y(v), z(v) {} 25 | vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {} 26 | 27 | friend vec3 operator+(const vec3& lhs, const vec3& rhs) 28 | { 29 | return vec3(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z); 30 | } 31 | 32 | friend vec3 operator-(const vec3& lhs, const vec3& rhs) 33 | { 34 | return vec3(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z); 35 | } 36 | 37 | friend vec3 operator*(const vec3& lhs, const T& rhs) 38 | { 39 | return vec3(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs); 40 | } 41 | 42 | friend vec3 operator*(const T& lhs, const vec3& rhs) 43 | { 44 | return vec3(lhs * rhs.x, lhs * rhs.y, lhs* rhs.z); 45 | } 46 | 47 | friend vec3 operator/(const vec3& lhs, const T& rhs) 48 | { 49 | return vec3(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs); 50 | } 51 | 52 | inline const T& operator[] (unsigned index) const 53 | { 54 | assert(index < 3); 55 | return data[index]; 56 | } 57 | 58 | inline T& operator[] (unsigned index) 59 | { 60 | assert(index < 3); 61 | return data[index]; 62 | } 63 | 64 | inline float length() const 65 | { 66 | return sqrt(x * x + y * y + z * z); 67 | } 68 | 69 | inline float distance(const vec3& v) const 70 | { 71 | auto r = *this - v; 72 | return r.length(); 73 | } 74 | 75 | inline float dot(const vec3& b) const 76 | { 77 | return x * b.x + y * b.y + z * b.z; 78 | } 79 | 80 | inline vec3 cross(const vec3& b) const 81 | { 82 | return vec3(y * b.z - z * b.y, 83 | z * b.x - x * b.z, 84 | x * b.y - y * b.x); 85 | } 86 | 87 | inline vec3 normalize() const 88 | { 89 | auto l = length(); 90 | return vec3(x / l, y / l, z / l); 91 | } 92 | 93 | inline vec3 direction(const vec3& to) const 94 | { 95 | auto v = to - *this; 96 | return v.normalize(); 97 | } 98 | 99 | inline vec3 lerp(const vec3& b, float t) const 100 | { 101 | return t < 0.0f ? *this : (t > 1.0f ? b : (*this * (1.0f - t) + b * t));; 102 | } 103 | 104 | inline void print() const 105 | { 106 | printf("[%f, %f, %f]\n", x, y, z); 107 | } 108 | }; 109 | 110 | using vec3f = vec3; 111 | using vec3i = vec3; 112 | using vec3u = vec3; 113 | 114 | } -------------------------------------------------------------------------------- /include/math/vec4.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace math 9 | { 10 | 11 | template 12 | struct vec4 13 | { 14 | union 15 | { 16 | struct 17 | { 18 | T x, y, z, w; 19 | }; 20 | T data[4]; 21 | }; 22 | 23 | vec4() : x(0.0), y(0.0), z(0.0), w(0.0) {} 24 | vec4(const T v) : x(v), y(v), z(v), w(v) {} 25 | vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {} 26 | 27 | inline vec4 operator+(const vec4& other) const 28 | { 29 | return vec4(x + other.x, y + other.y, z + other.z, w + other.w); 30 | } 31 | 32 | inline vec4 operator-(const vec4& other) const 33 | { 34 | return vec4(x - other.x, y - other.y, z - other.z, w - other.w); 35 | } 36 | 37 | inline vec4 operator*(const T& s) const 38 | { 39 | return vec4(x * s, y * s, z * s, w * s); 40 | } 41 | 42 | inline vec4 operator/(const T& s) const 43 | { 44 | return vec4(x / s, y / s, z / s, w / s); 45 | } 46 | 47 | inline const T& operator[] (unsigned index) const 48 | { 49 | assert(index < 4); 50 | return data[index]; 51 | } 52 | 53 | inline T& operator[] (unsigned index) 54 | { 55 | assert(index < 4); 56 | return data[index]; 57 | } 58 | 59 | inline float length() const 60 | { 61 | return sqrt(x * x + y * y + z * z + w * w); 62 | } 63 | 64 | inline float dot(const vec4& b) const 65 | { 66 | return x * b.x + y * b.y + z * b.z + w * b.w; 67 | } 68 | 69 | inline vec4 normalize() const 70 | { 71 | auto l = length(); 72 | return vec4(x / l, y / l, z / l, w / l); 73 | } 74 | 75 | inline vec4 lerp(const vec4& b, float t) const 76 | { 77 | return t < 0.0f ? *this : (t > 1.0f ? b : (*this * (1.0f - t) + b * t));; 78 | } 79 | 80 | inline void print() const 81 | { 82 | printf("[%f, %f, %f, %f]\n", x, y, z, w); 83 | } 84 | }; 85 | 86 | using vec4f = vec4; 87 | using vec4i = vec4; 88 | using vec4u = vec4; 89 | 90 | } 91 | -------------------------------------------------------------------------------- /include/rasterator.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace math; 10 | 11 | #define RST_DECLARE_MAIN(APP_CLASS) \ 12 | int main(int argc, char* argv[]) \ 13 | { \ 14 | APP_CLASS app; \ 15 | return app.run(argc, argv); \ 16 | } 17 | 18 | #define RST_SAFE_DELETE(OBJECT) if(OBJECT) { delete OBJECT; OBJECT = nullptr; } 19 | #define RST_SAFE_DELETE_ARRAY(OBJECT) if(OBJECT) { delete[] OBJECT; OBJECT = nullptr; } 20 | #define RST_COLOR_ARGB(RED, GREEN, BLUE, ALPHA) (static_cast(BLUE * 255.0f) << 24) | (static_cast(GREEN * 255.0f) << 16) | (static_cast(RED * 255.0f) << 8) | static_cast(ALPHA * 255.0f) 21 | #define RST_COLOR_RGBA(RED, GREEN, BLUE, ALPHA) (static_cast(RED * 255.0f) << 24) | (static_cast(GREEN * 255.0f) << 16) | static_cast(BLUE * 255.0f) << 8 | static_cast(ALPHA * 255.0f) 22 | 23 | namespace rst 24 | { 25 | class Color; 26 | 27 | class Texture 28 | { 29 | public: 30 | Color* m_pixels; 31 | float* m_depth; 32 | uint32_t m_width; 33 | uint32_t m_height; 34 | 35 | public: 36 | Texture(uint32_t width, uint32_t height, bool depth = false); 37 | Texture(const std::string& name); 38 | ~Texture(); 39 | void set_depth(float depth, uint32_t x, uint32_t y); 40 | void set_color(uint32_t color, uint32_t x, uint32_t y); 41 | uint32_t sample(float x, float y); 42 | void clear(); 43 | void clear(float r, float g, float b, float a); 44 | }; 45 | 46 | class Color 47 | { 48 | public: 49 | union 50 | { 51 | uint32_t pixel; 52 | struct 53 | { 54 | uint8_t r; 55 | uint8_t g; 56 | uint8_t b; 57 | uint8_t a; 58 | }; 59 | }; 60 | 61 | Color(uint8_t _r = 255, uint8_t _g = 255, uint8_t _b = 255, uint8_t _a = 255); 62 | Color(uint32_t _pixel); 63 | Color operator + (const Color &c) const; 64 | Color operator - (const Color &c) const; 65 | Color operator * (float f) const; 66 | }; 67 | 68 | struct Vertex 69 | { 70 | vec3f position; 71 | vec3f normal; 72 | vec3f tangent; 73 | vec2f texcoord; 74 | }; 75 | 76 | struct VertexBuffer 77 | { 78 | std::vector vertices; 79 | }; 80 | 81 | struct IndexBuffer 82 | { 83 | std::vector indices; 84 | }; 85 | 86 | struct Material 87 | { 88 | Texture* diffuse; 89 | Texture* normal; 90 | Texture* specular; 91 | 92 | Material(); 93 | ~Material(); 94 | }; 95 | 96 | struct SubModel 97 | { 98 | uint32_t base_index = 0; 99 | uint32_t index_count = 0; 100 | uint32_t base_vertex = 0; 101 | Material* material; 102 | 103 | SubModel(); 104 | ~SubModel(); 105 | }; 106 | 107 | struct Model 108 | { 109 | std::vector submodels; 110 | std::vector materials; 111 | VertexBuffer vertex_buffer; 112 | IndexBuffer index_buffer; 113 | 114 | Model(); 115 | ~Model(); 116 | }; 117 | 118 | enum TextureType 119 | { 120 | TEXTURE_DIFFUSE = 0, 121 | TEXTURE_NORMAL = 1, 122 | TEXTURE_SPECULAR = 2 123 | }; 124 | 125 | struct DirectionalLight 126 | { 127 | vec3f direction; 128 | vec3f color; 129 | }; 130 | 131 | struct PointLight 132 | { 133 | vec3f position; 134 | vec3f color; 135 | float constant; 136 | float linear; 137 | float quadratic; 138 | }; 139 | 140 | extern bool create_model(const std::string& file, Model& model); 141 | extern void initialize(); 142 | extern void set_vertex_buffer(VertexBuffer* vb); 143 | extern void set_index_buffer(IndexBuffer* ib); 144 | extern void set_directional_lights(uint32_t count, DirectionalLight* lights); 145 | extern void set_point_lights(uint32_t count, PointLight* lights); 146 | extern void set_render_target(Texture* color, Texture* depth); 147 | extern void set_model_matrix(const mat4f& model); 148 | extern void set_view_matrix(const mat4f& view); 149 | extern void set_projection_matrix(const mat4f& projection); 150 | extern void set_texture(const uint32_t& type, Texture* texture); 151 | extern void draw(uint32_t first_index, uint32_t count); 152 | extern void draw_indexed(uint32_t count); 153 | extern void draw_indexed_base_vertex(uint32_t index_count, uint32_t base_index, uint32_t base_vertex); 154 | } -------------------------------------------------------------------------------- /sample/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8 FATAL_ERROR) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 5 | 6 | # Sources 7 | set(SAMPLE_SOURCES "${PROJECT_SOURCE_DIR}/sample/main.cpp") 8 | 9 | # Source groups 10 | source_group("Sources" FILES ${SAMPLE_SOURCES}) 11 | 12 | if(APPLE) 13 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++14") 14 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") 15 | 16 | add_executable(sample MACOSX_BUNDLE ${SAMPLE_SOURCES}) 17 | set(MACOSX_BUNDLE_BUNDLE_NAME "com.dihara.rasterator") 18 | elseif(WIN32) 19 | add_executable(sample ${SAMPLE_SOURCES}) 20 | elseif(EMSCRIPTEN) 21 | message(STATUS "Building for Emscripten...") 22 | set(CMAKE_EXECUTABLE_SUFFIX ".html") 23 | add_executable(sample ${SAMPLE_SOURCES}) 24 | set_target_properties(sample PROPERTIES LINK_FLAGS "-O3 --embed-file ${PROJECT_SOURCE_DIR}/data/african_head.obj@african_head.obj --embed-file ${PROJECT_SOURCE_DIR}/data/african_head_diffuse.tga@african_head_diffuse.tga -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s USE_SDL=2") 25 | else() 26 | message(STATUS "Building for default platform...") 27 | add_executable(sample ${SAMPLE_SOURCES}) 28 | endif() 29 | 30 | target_link_libraries(sample Rasterator) 31 | -------------------------------------------------------------------------------- /sample/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | class Demo : public Application 12 | { 13 | mat4f m_view; 14 | mat4f m_projection; 15 | mat4f m_model; 16 | mat4f m_vp; 17 | mat4f m_mvp; 18 | vec3f m_position; 19 | vec3f m_direction; 20 | 21 | rst::DirectionalLight m_dir_light; 22 | rst::PointLight m_point_light; 23 | rst::Model m_obj_model; 24 | std::unique_ptr m_color_tex; 25 | std::unique_ptr m_depth_tex; 26 | 27 | private: 28 | 29 | 30 | protected: 31 | bool initialize() override 32 | { 33 | m_color_tex = std::make_unique(m_width, m_height); 34 | m_depth_tex = std::make_unique(m_width, m_height, true); 35 | 36 | m_position = vec3f(0.0f, 35.0f, 150.0f); 37 | m_direction = vec3f(0.0f, 0.0f, -1.0f); 38 | 39 | m_view = lookat(m_position, m_position + m_direction, vec3f(0.0f, 1.0f, 0.0f)); 40 | m_projection = perspective(float(m_width) / float(m_height), radians(60.0f), 0.1f, 100.0f); 41 | m_vp = m_projection * m_view; 42 | 43 | if (!rst::create_model("teapot.obj", m_obj_model)) 44 | { 45 | std::cout << "failed to load mesh" << std::endl; 46 | return false; 47 | } 48 | 49 | rst::initialize(); 50 | 51 | m_dir_light.color = vec3f(1.0f, 1.0f, 1.0f); 52 | m_dir_light.direction = vec3f(1.0f, -1.0f, 0.0f).normalize(); 53 | 54 | m_point_light.color = vec3f(1.0f, 1.0f, 1.0f); 55 | m_point_light.position = vec3f(0.0f, 0.0f, 150.0f); 56 | m_point_light.constant = 1.0f; 57 | m_point_light.linear = 0.0014; 58 | m_point_light.quadratic = 0.000007; 59 | 60 | return true; 61 | } 62 | 63 | void frame() override 64 | { 65 | m_depth_tex->clear(); 66 | m_color_tex->clear(0.0f, 0.0f, 0.0f, 1.0f); 67 | 68 | m_model = rotation(radians(SDL_GetTicks() * 0.05f), vec3f(0.0f, 1.0f, 0.0f)); 69 | 70 | // Set lights 71 | rst::set_directional_lights(1, &m_dir_light); 72 | 73 | // Set render targets 74 | rst::set_render_target(m_color_tex.get(), m_depth_tex.get()); 75 | 76 | // Set buffers 77 | rst::set_vertex_buffer(&m_obj_model.vertex_buffer); 78 | rst::set_index_buffer(&m_obj_model.index_buffer); 79 | 80 | // Set matrices 81 | rst::set_projection_matrix(m_projection); 82 | rst::set_view_matrix(m_view); 83 | rst::set_model_matrix(m_model); 84 | 85 | // For each submodel in model... 86 | for (const auto& submodel : m_obj_model.submodels) 87 | { 88 | // Bind material, if available 89 | if (submodel.material) 90 | { 91 | rst::set_texture(rst::TEXTURE_DIFFUSE, submodel.material->diffuse); 92 | rst::set_texture(rst::TEXTURE_NORMAL, submodel.material->normal); 93 | rst::set_texture(rst::TEXTURE_SPECULAR, submodel.material->specular); 94 | } 95 | 96 | // Draw each submodel 97 | rst::draw_indexed_base_vertex(submodel.index_count, submodel.base_index, submodel.base_vertex); 98 | } 99 | 100 | update_backbuffer(m_color_tex->m_pixels); 101 | } 102 | 103 | void shutdown() override 104 | { 105 | 106 | } 107 | }; 108 | 109 | RST_DECLARE_MAIN(Demo); 110 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8 FATAL_ERROR) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 5 | 6 | include(FindOpenMP) 7 | 8 | if(OPENMP_FOUND) 9 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 11 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") 12 | endif() 13 | 14 | # Headers 15 | set(RASTERATOR_HEADERS "${PROJECT_SOURCE_DIR}/include/application.hpp" 16 | "${PROJECT_SOURCE_DIR}/include/rasterator.hpp" 17 | "${PROJECT_SOURCE_DIR}/include/math/mat3.hpp" 18 | "${PROJECT_SOURCE_DIR}/include/math/mat4.hpp" 19 | "${PROJECT_SOURCE_DIR}/include/math/quat.hpp" 20 | "${PROJECT_SOURCE_DIR}/include/math/simd_float4.hpp" 21 | "${PROJECT_SOURCE_DIR}/include/math/simd_float8.hpp" 22 | "${PROJECT_SOURCE_DIR}/include/math/simd_mat4x4.hpp" 23 | "${PROJECT_SOURCE_DIR}/include/math/simd_mat4x8.hpp" 24 | "${PROJECT_SOURCE_DIR}/include/math/simd_vec4x4.hpp" 25 | "${PROJECT_SOURCE_DIR}/include/math/simd_vec4x8.hpp" 26 | "${PROJECT_SOURCE_DIR}/include/math/transform.hpp" 27 | "${PROJECT_SOURCE_DIR}/include/math/utility.hpp" 28 | "${PROJECT_SOURCE_DIR}/include/math/vec2.hpp" 29 | "${PROJECT_SOURCE_DIR}/include/math/vec3.hpp" 30 | "${PROJECT_SOURCE_DIR}/include/math/vec4.hpp") 31 | 32 | # Sources 33 | set(RASTERATOR_SOURCES "${PROJECT_SOURCE_DIR}/src/application.cpp" 34 | "${PROJECT_SOURCE_DIR}/src/rasterator.cpp") 35 | 36 | # Source groups 37 | source_group("Headers" FILES ${RASTERATOR_HEADERS}) 38 | source_group("Sources" FILES ${RASTERATOR_SOURCES}) 39 | 40 | add_library(Rasterator ${RASTERATOR_HEADERS} ${RASTERATOR_SOURCES}) 41 | 42 | if (NOT EMSCRIPTEN) 43 | target_link_libraries(Rasterator SDL2-static) 44 | target_link_libraries(Rasterator SDL2main) 45 | else() 46 | set_target_properties(Rasterator PROPERTIES LINK_FLAGS "-O3 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s USE_SDL=2") 47 | endif() 48 | 49 | target_link_libraries(Rasterator assimp) 50 | -------------------------------------------------------------------------------- /src/application.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef __EMSCRIPTEN__ 6 | #include 7 | #endif 8 | 9 | Application::Application() : m_is_running(false), 10 | m_sdl_window(nullptr), 11 | m_delta_time(0), 12 | m_last_delta_time(0), 13 | #ifdef __EMSCRIPTEN__ 14 | m_width(640), 15 | m_height(360) 16 | #else 17 | m_width(1280), 18 | m_height(720) 19 | #endif 20 | { 21 | 22 | } 23 | 24 | Application::~Application() 25 | { 26 | 27 | } 28 | 29 | int Application::run(int argc, char* argv[]) 30 | { 31 | if(!_initialize()) 32 | return 1; 33 | 34 | #ifdef __EMSCRIPTEN__ 35 | emscripten_set_main_loop_arg(_main_loop, this, 0, true); 36 | #else 37 | while (m_is_running) 38 | { 39 | _frame(); 40 | } 41 | #endif 42 | 43 | _shutdown(); 44 | 45 | return 0; 46 | } 47 | 48 | #ifdef __EMSCRIPTEN__ 49 | void Application::_main_loop(void* arg) 50 | { 51 | static_cast(arg)->_frame(); 52 | } 53 | #endif 54 | 55 | void Application::_frame() 56 | { 57 | _clear_screen(0, 0, 0, 255); 58 | _event_loop(); 59 | 60 | frame(); 61 | 62 | _update_delta_time(); 63 | _present(); 64 | } 65 | 66 | void Application::_update_delta_time() 67 | { 68 | uint32_t ticks = SDL_GetTicks(); 69 | m_delta_time = ticks - m_last_delta_time; 70 | m_last_delta_time = ticks; 71 | 72 | std::string msg = m_title + std::to_string(m_delta_time) + "ms"; 73 | SDL_SetWindowTitle(m_sdl_window, msg.c_str()); 74 | } 75 | 76 | void Application::_clear_screen(uint8_t r, uint8_t b, uint8_t g, uint8_t a) 77 | { 78 | SDL_SetRenderDrawColor(m_sdl_renderer, r, b, g, a); 79 | SDL_RenderClear(m_sdl_renderer); 80 | } 81 | 82 | void Application::_present() 83 | { 84 | SDL_RenderPresent(m_sdl_renderer); 85 | } 86 | 87 | bool Application::_initialize() 88 | { 89 | m_title = "Software Rasterizer | Dihara Wijetunga (c) 2018 | "; 90 | 91 | Uint32 flags = SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_EVENTS; 92 | 93 | if (SDL_Init(flags) != 0) 94 | return false; 95 | 96 | m_sdl_window = SDL_CreateWindow(m_title.c_str(), 97 | SDL_WINDOWPOS_CENTERED, 98 | SDL_WINDOWPOS_CENTERED, 99 | m_width, 100 | m_height, 101 | SDL_WINDOW_OPENGL); 102 | if (!m_sdl_window) 103 | return false; 104 | 105 | m_sdl_renderer = SDL_CreateRenderer(m_sdl_window, -1, SDL_RENDERER_ACCELERATED); 106 | m_sdl_backbuffer = SDL_CreateTexture(m_sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, m_width, m_height); 107 | 108 | if (!initialize()) 109 | return false; 110 | 111 | m_is_running = true; 112 | return true; 113 | } 114 | 115 | void Application::_shutdown() 116 | { 117 | shutdown(); 118 | 119 | SDL_DestroyTexture(m_sdl_backbuffer); 120 | SDL_DestroyRenderer(m_sdl_renderer); 121 | SDL_DestroyWindow(m_sdl_window); 122 | 123 | SDL_Quit(); 124 | } 125 | 126 | void Application::_event_loop() 127 | { 128 | SDL_Event event; 129 | 130 | while (SDL_PollEvent(&event)) 131 | { 132 | switch (event.type) 133 | { 134 | case SDL_MOUSEWHEEL: 135 | break; 136 | 137 | case SDL_MOUSEMOTION: 138 | { 139 | SDL_bool relative = SDL_GetRelativeMouseMode(); 140 | break; 141 | } 142 | 143 | case SDL_MOUSEBUTTONUP: 144 | case SDL_MOUSEBUTTONDOWN: 145 | { 146 | 147 | break; 148 | } 149 | 150 | case SDL_KEYUP: 151 | case SDL_KEYDOWN: 152 | { 153 | if(event.key.repeat == 0) 154 | { 155 | 156 | } 157 | break; 158 | } 159 | 160 | case SDL_QUIT: 161 | m_is_running = false; 162 | break; 163 | 164 | default: 165 | break; 166 | } 167 | } 168 | } 169 | 170 | void Application::update_backbuffer(void* pixels) 171 | { 172 | SDL_UpdateTexture(m_sdl_backbuffer, NULL, pixels, m_width * sizeof(uint32_t)); 173 | SDL_RenderCopy(m_sdl_renderer, m_sdl_backbuffer, NULL, NULL); 174 | } 175 | -------------------------------------------------------------------------------- /src/rasterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #define STB_IMAGE_IMPLEMENTATION 12 | #include 13 | 14 | #include 15 | 16 | namespace rst 17 | { 18 | // Global state. 19 | VertexBuffer* g_current_vb = nullptr; 20 | IndexBuffer* g_current_ib = nullptr; 21 | Texture* g_current_color_target = nullptr; 22 | Texture* g_current_depth_target = nullptr; 23 | Texture* g_current_textures[3]; 24 | mat4f g_current_model_mat; 25 | mat4f g_current_view_mat; 26 | mat4f g_current_projection_mat; 27 | uint32_t g_dir_light_count = 0; 28 | DirectionalLight* g_current_dir_lights = nullptr; 29 | uint32_t g_point_light_count = 0; 30 | PointLight* g_current_point_lights = nullptr; 31 | 32 | // ----------------------------------------------------------------------------------------------------------------------------------- 33 | 34 | Color::Color(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a) 35 | { 36 | r = _r; 37 | g = _g; 38 | b = _b; 39 | a = _a; 40 | } 41 | 42 | // ----------------------------------------------------------------------------------------------------------------------------------- 43 | 44 | Color::Color(uint32_t _pixel) 45 | { 46 | pixel = _pixel; 47 | } 48 | 49 | // ----------------------------------------------------------------------------------------------------------------------------------- 50 | 51 | Color Color::operator + (const Color &c) const 52 | { 53 | return Color(std::min(255, r + c.r), std::min(255, g + c.g), std::min(255, b + c.b), std::min(255, a + c.a)); 54 | } 55 | 56 | // ----------------------------------------------------------------------------------------------------------------------------------- 57 | 58 | Color Color::operator - (const Color &c) const 59 | { 60 | return Color(r - c.r, g - c.g, b - c.b, a - c.a); 61 | } 62 | 63 | // ----------------------------------------------------------------------------------------------------------------------------------- 64 | 65 | Color Color::operator * (float f) const 66 | { 67 | return Color(r * f, g * f, b * f, a * f); 68 | } 69 | 70 | // ----------------------------------------------------------------------------------------------------------------------------------- 71 | 72 | Texture::Texture(uint32_t width, uint32_t height, bool depth) : m_width(width), m_height(height) 73 | { 74 | if (depth) 75 | { 76 | m_pixels = nullptr; 77 | m_depth = new float[width * height]; 78 | } 79 | else 80 | { 81 | m_pixels = new Color[width * height]; 82 | m_depth = nullptr; 83 | } 84 | } 85 | 86 | // ----------------------------------------------------------------------------------------------------------------------------------- 87 | 88 | Texture::Texture(const std::string& name) 89 | { 90 | int x, y, comp; 91 | 92 | std::string base_path = SDL_GetBasePath(); 93 | std::string path = base_path + name; 94 | Color* data = (Color*)stbi_load(path.c_str(), &x, &y, &comp, 4); 95 | 96 | m_width = x; 97 | m_height = y; 98 | 99 | m_pixels = new Color[x * y]; 100 | m_depth = nullptr; 101 | 102 | int size = x * y; 103 | 104 | for (int i = 0; i < size; i++) 105 | { 106 | Color& c = data[i]; 107 | m_pixels[i] = Color(c.b, c.g, c.r, 255); 108 | } 109 | 110 | stbi_image_free(data); 111 | } 112 | 113 | // ----------------------------------------------------------------------------------------------------------------------------------- 114 | 115 | Texture::~Texture() 116 | { 117 | RST_SAFE_DELETE_ARRAY(m_pixels); 118 | RST_SAFE_DELETE_ARRAY(m_depth); 119 | } 120 | 121 | // ----------------------------------------------------------------------------------------------------------------------------------- 122 | 123 | void Texture::set_depth(float depth, uint32_t x, uint32_t y) 124 | { 125 | y = m_height - y - 1; 126 | 127 | if (m_depth) 128 | { 129 | if (x > m_width - 1 || x < 0) 130 | return; 131 | 132 | if (y > m_height - 1 || y < 0) 133 | return; 134 | 135 | m_depth[y * m_width + x] = depth; 136 | } 137 | } 138 | 139 | // ----------------------------------------------------------------------------------------------------------------------------------- 140 | 141 | void Texture::set_color(uint32_t color, uint32_t x, uint32_t y) 142 | { 143 | y = m_height - y - 1; 144 | 145 | if (m_pixels) 146 | { 147 | if (x > m_width - 1) 148 | return; 149 | 150 | if (y > m_height - 1) 151 | return; 152 | 153 | m_pixels[y * m_width + x] = color; 154 | } 155 | } 156 | 157 | // ----------------------------------------------------------------------------------------------------------------------------------- 158 | 159 | inline Color bilinear_interpolation(const float& tx, const float& ty, const Color& c00, const Color& c01, const Color& c10, const Color& c11) 160 | { 161 | Color a = c00 * (1 - tx) + c10 * tx; 162 | Color b = c01 * (1 - tx) + c11 * tx; 163 | return a * (1 - ty) + b * ty; 164 | } 165 | #define BILINEAR 166 | uint32_t Texture::sample(float x, float y) 167 | { 168 | #if defined(BILINEAR) 169 | // Bilinear Filtering 170 | float x_coord = x * (float(m_width) - 1.0f); 171 | float y_coord = y * (float(m_height) - 1.0f); 172 | 173 | // Get floor value of coordinate 174 | uint32_t x_floor = uint32_t(x_coord); 175 | uint32_t y_floor = uint32_t(y_coord); 176 | 177 | // Get ceil value of coordinate 178 | uint32_t x_ceil = ceil(x_coord); 179 | uint32_t y_ceil = ceil(y_coord); 180 | 181 | // Calculate tx, ty 182 | float tx = x_coord - x_floor; 183 | float ty = y_coord - y_floor; 184 | 185 | Color& c00 = m_pixels[y_floor * m_width + x_floor]; 186 | Color& c01 = m_pixels[y_ceil * m_width + x_floor]; 187 | Color& c10 = m_pixels[y_floor * m_width + x_ceil]; 188 | Color& c11 = m_pixels[y_ceil * m_width + x_ceil]; 189 | 190 | return bilinear_interpolation(tx, ty, c00, c01, c10, c11).pixel; 191 | #else 192 | uint32_t x_coord = x * (m_width - 1); 193 | uint32_t y_coord = y * (m_height - 1); 194 | 195 | return m_pixels[y_coord * m_width + x_coord].pixel; 196 | #endif 197 | } 198 | 199 | // ----------------------------------------------------------------------------------------------------------------------------------- 200 | 201 | void Texture::clear() 202 | { 203 | if (m_depth) 204 | { 205 | uint32_t size = m_width * m_height; 206 | float depth = INFINITY; 207 | 208 | for (uint32_t i = 0; i < size; i++) 209 | m_depth[i] = depth; 210 | } 211 | } 212 | 213 | // ----------------------------------------------------------------------------------------------------------------------------------- 214 | 215 | void Texture::clear(float r, float g, float b, float a) 216 | { 217 | if (m_pixels) 218 | { 219 | Color color = Color(b * 255.0f, g * 255.0f, r * 255.0f, a * 255.0f); 220 | uint32_t size = m_width * m_height; 221 | 222 | for (uint32_t i = 0; i < size; i++) 223 | m_pixels[i] = color.pixel; 224 | } 225 | } 226 | 227 | // ----------------------------------------------------------------------------------------------------------------------------------- 228 | 229 | Material::Material() 230 | { 231 | diffuse = nullptr; 232 | normal = nullptr; 233 | specular = nullptr; 234 | } 235 | 236 | // ----------------------------------------------------------------------------------------------------------------------------------- 237 | 238 | Material::~Material() 239 | { 240 | RST_SAFE_DELETE(diffuse); 241 | RST_SAFE_DELETE(normal); 242 | RST_SAFE_DELETE(specular); 243 | } 244 | 245 | // ----------------------------------------------------------------------------------------------------------------------------------- 246 | 247 | SubModel::SubModel() 248 | { 249 | material = nullptr; 250 | } 251 | 252 | // ----------------------------------------------------------------------------------------------------------------------------------- 253 | 254 | SubModel::~SubModel() 255 | { 256 | 257 | } 258 | 259 | // ----------------------------------------------------------------------------------------------------------------------------------- 260 | 261 | Model::Model() 262 | { 263 | 264 | } 265 | 266 | // ----------------------------------------------------------------------------------------------------------------------------------- 267 | 268 | Model::~Model() 269 | { 270 | for (auto mat : materials) 271 | RST_SAFE_DELETE(mat); 272 | } 273 | 274 | // ----------------------------------------------------------------------------------------------------------------------------------- 275 | 276 | static const aiTextureType kTextureTypes[] = 277 | { 278 | aiTextureType_DIFFUSE, 279 | aiTextureType_SPECULAR, 280 | aiTextureType_AMBIENT, 281 | aiTextureType_EMISSIVE, 282 | aiTextureType_HEIGHT, 283 | aiTextureType_NORMALS, 284 | aiTextureType_SHININESS, 285 | aiTextureType_OPACITY, 286 | aiTextureType_DISPLACEMENT, 287 | aiTextureType_LIGHTMAP, 288 | aiTextureType_REFLECTION 289 | }; 290 | 291 | static const char* kTextureTypeStrings[] = 292 | { 293 | "aiTextureType_DIFFUSE", 294 | "aiTextureType_SPECULAR", 295 | "aiTextureType_AMBIENT", 296 | "aiTextureType_EMISSIVE", 297 | "aiTextureType_HEIGHT", 298 | "aiTextureType_NORMALS", 299 | "aiTextureType_SHININESS", 300 | "aiTextureType_OPACITY", 301 | "aiTextureType_DISPLACEMENT", 302 | "aiTextureType_LIGHTMAP", 303 | "aiTextureType_REFLECTION" 304 | }; 305 | 306 | // ----------------------------------------------------------------------------------------------------------------------------------- 307 | // Assimp loader helper method definitions 308 | // ----------------------------------------------------------------------------------------------------------------------------------- 309 | 310 | std::string assimp_get_texture_path(aiMaterial* material, aiTextureType texture_type) 311 | { 312 | aiString path; 313 | aiReturn result = material->GetTexture(texture_type, 0, &path); 314 | 315 | if (result == aiReturn_FAILURE) 316 | return ""; 317 | else 318 | { 319 | std::string cppStr = std::string(path.C_Str()); 320 | 321 | if (cppStr == "") 322 | return ""; 323 | 324 | return cppStr; 325 | } 326 | } 327 | 328 | // ----------------------------------------------------------------------------------------------------------------------------------- 329 | 330 | bool assimp_does_material_exist(std::vector &materials, unsigned int ¤t_material) 331 | { 332 | for (auto it : materials) 333 | { 334 | if (it == current_material) 335 | return true; 336 | } 337 | 338 | return false; 339 | } 340 | 341 | // ----------------------------------------------------------------------------------------------------------------------------------- 342 | 343 | bool create_model(const std::string& file, Model& model) 344 | { 345 | const aiScene* Scene; 346 | Assimp::Importer Importer; 347 | 348 | std::string base_path = SDL_GetBasePath(); 349 | std::string path = base_path + file; 350 | 351 | Scene = Importer.ReadFile(path, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_CalcTangentSpace); 352 | 353 | uint32_t mesh_count = Scene->mNumMeshes; 354 | uint32_t index_count = 0; 355 | uint32_t vertex_count = 0; 356 | 357 | aiMaterial* TempMaterial; 358 | uint8_t materialIndex = 0; 359 | 360 | aiMaterial* temp_material; 361 | std::vector processed_mat_id; 362 | std::unordered_map mat_id_mapping; 363 | 364 | // Resize submodel vector 365 | model.submodels.resize(mesh_count); 366 | 367 | for (int i = 0; i < mesh_count; i++) 368 | { 369 | SubModel& submodel = model.submodels[i]; 370 | 371 | bool has_least_one_texture = false; 372 | 373 | submodel.index_count = Scene->mMeshes[i]->mNumFaces * 3; 374 | submodel.base_index = index_count; 375 | submodel.base_vertex = vertex_count; 376 | 377 | vertex_count += Scene->mMeshes[i]->mNumVertices; 378 | index_count += submodel.index_count; 379 | 380 | std::string diffuse_path; 381 | std::string normal_path; 382 | std::string specular_path; 383 | 384 | if (mat_id_mapping.find(Scene->mMeshes[i]->mMaterialIndex) == mat_id_mapping.end()) 385 | { 386 | std::string current_mat_name; 387 | 388 | temp_material = Scene->mMaterials[Scene->mMeshes[i]->mMaterialIndex]; 389 | current_mat_name = path + std::to_string(i); 390 | 391 | // Find Diffuse 392 | diffuse_path = assimp_get_texture_path(temp_material, aiTextureType_DIFFUSE); 393 | 394 | if (diffuse_path != "") 395 | { 396 | std::replace(diffuse_path.begin(), diffuse_path.end(), '\\', '/'); 397 | 398 | if (diffuse_path.length() > 4 && diffuse_path[0] != ' ') 399 | { 400 | std::cout << "Found Diffuse Map : " + diffuse_path << std::endl; 401 | has_least_one_texture = true; 402 | } 403 | } 404 | 405 | // Find Normal 406 | normal_path = assimp_get_texture_path(temp_material, aiTextureType_HEIGHT); 407 | 408 | if (normal_path != "") 409 | { 410 | std::replace(normal_path.begin(), normal_path.end(), '\\', '/'); 411 | 412 | if (normal_path.length() > 4 && normal_path[0] != ' ') 413 | { 414 | std::cout << "Found Normal Map : " + normal_path << std::endl; 415 | has_least_one_texture = true; 416 | } 417 | } 418 | 419 | // Find Specular 420 | specular_path = assimp_get_texture_path(temp_material, aiTextureType_SPECULAR); 421 | 422 | if (specular_path != "") 423 | { 424 | std::replace(specular_path.begin(), specular_path.end(), '\\', '/'); 425 | 426 | if (specular_path.length() > 4 && specular_path[0] != ' ') 427 | { 428 | std::cout << "Found Specular Map : " + specular_path << std::endl; 429 | has_least_one_texture = true; 430 | } 431 | } 432 | 433 | if (has_least_one_texture) 434 | { 435 | submodel.material = new Material();//std::make_unique(); 436 | 437 | if (diffuse_path != "") 438 | submodel.material->diffuse = new Texture(diffuse_path); 439 | 440 | if (normal_path != "") 441 | submodel.material->normal = new Texture(normal_path); 442 | 443 | if (specular_path != "") 444 | submodel.material->specular = new Texture(specular_path); 445 | 446 | mat_id_mapping[Scene->mMeshes[i]->mMaterialIndex] = submodel.material;//submodel.material.get(); 447 | model.materials.push_back(submodel.material); 448 | } 449 | 450 | } 451 | else // if already exists, find the pointer. 452 | submodel.material = mat_id_mapping[Scene->mMeshes[i]->mMaterialIndex];//std::unique_ptr(mat_id_mapping[Scene->mMeshes[i]->mMaterialIndex]); 453 | } 454 | 455 | aiMesh* TempMesh; 456 | int idx = 0; 457 | int vertexIndex = 0; 458 | 459 | for (int i = 0; i < mesh_count; i++) 460 | { 461 | TempMesh = Scene->mMeshes[i]; 462 | 463 | for (int k = 0; k < Scene->mMeshes[i]->mNumVertices; k++) 464 | { 465 | Vertex vert; 466 | 467 | vert.position = vec3f(TempMesh->mVertices[k].x, TempMesh->mVertices[k].y, TempMesh->mVertices[k].z); 468 | vec3f n = vec3f(TempMesh->mNormals[k].x, TempMesh->mNormals[k].y, TempMesh->mNormals[k].z); 469 | vec3f t = vec3f(TempMesh->mTangents[k].x, TempMesh->mTangents[k].y, TempMesh->mTangents[k].z); 470 | vec3f b = vec3f(TempMesh->mBitangents[k].x, TempMesh->mBitangents[k].y, TempMesh->mBitangents[k].z); 471 | 472 | // @NOTE: Assuming right handed coordinate space 473 | if (n.cross(t).dot(b) < 0.0f) 474 | t = t * -1.0f; // Flip tangent 475 | 476 | vert.normal = n; 477 | vert.tangent = t; 478 | 479 | if (TempMesh->HasTextureCoords(0)) 480 | vert.texcoord = vec2f(TempMesh->mTextureCoords[0][k].x, TempMesh->mTextureCoords[0][k].y); 481 | 482 | vertexIndex++; 483 | 484 | model.vertex_buffer.vertices.push_back(vert); 485 | } 486 | 487 | for (int j = 0; j < TempMesh->mNumFaces; j++) 488 | { 489 | model.index_buffer.indices.push_back(TempMesh->mFaces[j].mIndices[0]); 490 | model.index_buffer.indices.push_back(TempMesh->mFaces[j].mIndices[1]); 491 | model.index_buffer.indices.push_back(TempMesh->mFaces[j].mIndices[2]); 492 | } 493 | } 494 | 495 | return true; 496 | } 497 | 498 | // ----------------------------------------------------------------------------------------------------------------------------------- 499 | 500 | inline float edge_function(const vec2f &a, const vec2f &b, const vec2f &c) 501 | { 502 | return (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x); 503 | } 504 | 505 | // ----------------------------------------------------------------------------------------------------------------------------------- 506 | 507 | inline vec2f convert_to_screen_space(const float& x, const float& y, const uint32_t& width, const uint32_t& height) 508 | { 509 | return vec2f(int((((x + 1) * width) * 0.5f) + 0.5f), int((((y + 1) * height) * 0.5f) + 0.5f)); 510 | } 511 | 512 | // ----------------------------------------------------------------------------------------------------------------------------------- 513 | 514 | inline void triangle(const Vertex& v0, const Vertex& v1, const Vertex& v2, const mat4f& vp, Texture* color_tex, Texture* depth_tex) 515 | { 516 | uint32_t width = color_tex->m_width; 517 | uint32_t height = color_tex->m_height; 518 | 519 | // Convert to world space 520 | vec4f v0world = g_current_model_mat * vec4f(v0.position.x, v0.position.y, v0.position.z, 1.0f); 521 | vec4f v1world = g_current_model_mat * vec4f(v1.position.x, v1.position.y, v1.position.z, 1.0f); 522 | vec4f v2world = g_current_model_mat * vec4f(v2.position.x, v2.position.y, v2.position.z, 1.0f); 523 | 524 | // Convert to screen space 525 | vec4f v0ndc = vp * v0world; 526 | vec4f v1ndc = vp * v1world; 527 | vec4f v2ndc = vp * v2world; 528 | 529 | // Keep view space Z around for perspective correct interpolation 530 | float v0view_z = v0ndc.w; 531 | float v1view_z = v1ndc.w; 532 | float v2view_z = v2ndc.w; 533 | 534 | // Perspective division 535 | v0ndc = v0ndc / v0ndc.w; 536 | v1ndc = v1ndc / v1ndc.w; 537 | v2ndc = v2ndc / v2ndc.w; 538 | 539 | // Screen coords 540 | vec2f v0screen = convert_to_screen_space(v0ndc.x, v0ndc.y, width, height); 541 | vec2f v1screen = convert_to_screen_space(v1ndc.x, v1ndc.y, width, height); 542 | vec2f v2screen = convert_to_screen_space(v2ndc.x, v2ndc.y, width, height); 543 | 544 | // Find triangle bounding box 545 | vec2f bboxmin(std::numeric_limits::max(), std::numeric_limits::max()); 546 | vec2f bboxmax(-std::numeric_limits::max(), -std::numeric_limits::max()); 547 | 548 | vec2f clamp(width - 1, height - 1); 549 | 550 | // Min 551 | bboxmin.x = std::max(0.0f, std::min(bboxmin.x, v0screen.x)); 552 | bboxmin.x = std::max(0.0f, std::min(bboxmin.x, v1screen.x)); 553 | bboxmin.x = std::max(0.0f, std::min(bboxmin.x, v2screen.x)); 554 | 555 | bboxmin.y = std::max(0.0f, std::min(bboxmin.y, v0screen.y)); 556 | bboxmin.y = std::max(0.0f, std::min(bboxmin.y, v1screen.y)); 557 | bboxmin.y = std::max(0.0f, std::min(bboxmin.y, v2screen.y)); 558 | 559 | // Max 560 | bboxmax.x = std::min(clamp.x, std::max(bboxmax.x, v0screen.x)); 561 | bboxmax.x = std::min(clamp.x, std::max(bboxmax.x, v1screen.x)); 562 | bboxmax.x = std::min(clamp.x, std::max(bboxmax.x, v2screen.x)); 563 | 564 | bboxmax.y = std::min(clamp.y, std::max(bboxmax.y, v0screen.y)); 565 | bboxmax.y = std::min(clamp.y, std::max(bboxmax.y, v1screen.y)); 566 | bboxmax.y = std::min(clamp.y, std::max(bboxmax.y, v2screen.y)); 567 | 568 | // Divide vertex attributes by view space Z for perspective correct interpolation 569 | vec2f v0tc = v0.texcoord / v0view_z; 570 | vec2f v1tc = v1.texcoord / v1view_z; 571 | vec2f v2tc = v2.texcoord / v2view_z; 572 | 573 | vec3f v0n = v0.normal / v0view_z; 574 | vec3f v1n = v1.normal / v1view_z; 575 | vec3f v2n = v2.normal / v2view_z; 576 | 577 | vec3f v0w = vec3f(v0world.x, v0world.y, v0world.z) / v0view_z; 578 | vec3f v1w = vec3f(v1world.x, v1world.y, v1world.z) / v1view_z; 579 | vec3f v2w = vec3f(v2world.x, v2world.y, v2world.z) / v2view_z; 580 | 581 | // One over view Z 582 | v0view_z = 1.0f / v0view_z; 583 | v1view_z = 1.0f / v1view_z; 584 | v2view_z = 1.0f / v2view_z; 585 | 586 | // Triangle area 587 | float area = edge_function(v0screen, v1screen, v2screen); 588 | 589 | vec2f p; 590 | 591 | // Iterate over pixels in triangle bounding box 592 | for (p.x = bboxmin.x; p.x <= bboxmax.x; p.x++) 593 | { 594 | for (p.y = bboxmin.y; p.y <= bboxmax.y; p.y++) 595 | { 596 | // Calculate barycentric coordinates 597 | float w0 = edge_function(v1screen, v2screen, p); 598 | float w1 = edge_function(v2screen, v0screen, p); 599 | float w2 = edge_function(v0screen, v1screen, p); 600 | 601 | // Is the current pixel within the triangle? 602 | if (w0 >= 0 && w1 >= 0 && w2 >= 0) 603 | { 604 | w0 /= area; 605 | w1 /= area; 606 | w2 /= area; 607 | 608 | // Calculate interpolated pixel depth 609 | float z = 1.0f / (v0view_z * w0 + v1view_z * w1 + v2view_z * w2); 610 | 611 | // Perform depth test 612 | if (z < depth_tex->m_depth[int(p.x + p.y * depth_tex->m_width)]) 613 | { 614 | // Update depth buffer value if depth test is passesd 615 | depth_tex->m_depth[int(p.x + p.y * depth_tex->m_width)] = z; 616 | 617 | // Interpolate attributes 618 | vec2f texcoord = v0tc * w0 + v1tc * w1 + v2tc * w2; 619 | texcoord = texcoord * z; 620 | 621 | vec3f normal = v0n * w0 + v1n * w1 + v2n * w2; 622 | normal = (normal * z).normalize(); 623 | 624 | vec3f world_position = v0w * w0 + v1w * w1 + v2w * w2; 625 | world_position = world_position * z; 626 | 627 | // @TODO: Transform normal into world space. 628 | 629 | // Fetch texture sample 630 | Texture* diffuse_texture = g_current_textures[TEXTURE_DIFFUSE]; 631 | 632 | Color diffuse = diffuse_texture ? diffuse_texture->sample(texcoord.x, texcoord.y) : RST_COLOR_RGBA(1.0f, 1.0f, 1.0f, 1.0f); 633 | Color ambient = diffuse * 0.3f; 634 | 635 | Color result = Color(0.0f, 0.0f, 0.0f, 1.0f); 636 | 637 | // Accumulate directional light contribution 638 | for (uint32_t i = 0; i < g_dir_light_count; i++) 639 | { 640 | float lambert = std::max(0.0f, normal.dot(g_current_dir_lights[i].direction * -1.0f)); 641 | result = result + diffuse * lambert + ambient; 642 | } 643 | 644 | // Accumulate directional light contribution 645 | for (uint32_t i = 0; i < g_point_light_count; i++) 646 | { 647 | PointLight& light = g_current_point_lights[i]; 648 | 649 | float distance = world_position.distance(light.position); 650 | float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); 651 | 652 | vec3f direction = world_position.direction(light.position); 653 | 654 | float lambert = std::max(0.0f, normal.dot(direction)); 655 | result = result + diffuse * lambert * attenuation + ambient; 656 | } 657 | 658 | // Write new pixel color 659 | color_tex->set_color(result.pixel, p.x, p.y); 660 | } 661 | } 662 | } 663 | } 664 | } 665 | 666 | // ----------------------------------------------------------------------------------------------------------------------------------- 667 | 668 | void initialize() 669 | { 670 | for (int i = 0; i < 3; i++) 671 | g_current_textures[i] = nullptr; 672 | } 673 | 674 | // ----------------------------------------------------------------------------------------------------------------------------------- 675 | 676 | void set_vertex_buffer(VertexBuffer* vb) 677 | { 678 | g_current_vb = vb; 679 | } 680 | 681 | // ----------------------------------------------------------------------------------------------------------------------------------- 682 | 683 | void set_index_buffer(IndexBuffer* ib) 684 | { 685 | g_current_ib = ib; 686 | } 687 | 688 | // ----------------------------------------------------------------------------------------------------------------------------------- 689 | 690 | void set_directional_lights(uint32_t count, DirectionalLight* lights) 691 | { 692 | if (lights) 693 | { 694 | g_dir_light_count = count; 695 | g_current_dir_lights = lights; 696 | } 697 | else 698 | { 699 | g_dir_light_count = 0; 700 | g_current_dir_lights = nullptr; 701 | } 702 | } 703 | 704 | // ----------------------------------------------------------------------------------------------------------------------------------- 705 | 706 | void set_point_lights(uint32_t count, PointLight* lights) 707 | { 708 | if (lights) 709 | { 710 | g_point_light_count = count; 711 | g_current_point_lights = lights; 712 | } 713 | else 714 | { 715 | g_point_light_count = 0; 716 | g_current_point_lights = nullptr; 717 | } 718 | } 719 | 720 | // ----------------------------------------------------------------------------------------------------------------------------------- 721 | 722 | void set_render_target(Texture* color, Texture* depth) 723 | { 724 | g_current_color_target = color; 725 | g_current_depth_target = depth; 726 | } 727 | 728 | // ----------------------------------------------------------------------------------------------------------------------------------- 729 | 730 | void set_model_matrix(const mat4f& model) 731 | { 732 | g_current_model_mat = model; 733 | } 734 | 735 | // ----------------------------------------------------------------------------------------------------------------------------------- 736 | 737 | void set_view_matrix(const mat4f& view) 738 | { 739 | g_current_view_mat = view; 740 | } 741 | 742 | // ----------------------------------------------------------------------------------------------------------------------------------- 743 | 744 | void set_projection_matrix(const mat4f& projection) 745 | { 746 | g_current_projection_mat = projection; 747 | } 748 | 749 | // ----------------------------------------------------------------------------------------------------------------------------------- 750 | 751 | void set_texture(const uint32_t& type, Texture* texture) 752 | { 753 | if (type > TEXTURE_SPECULAR) 754 | { 755 | std::cout << "ERROR: Invalid texture type!" << std::endl; 756 | return; 757 | } 758 | 759 | g_current_textures[type] = texture; 760 | } 761 | 762 | // ----------------------------------------------------------------------------------------------------------------------------------- 763 | 764 | void draw(uint32_t first_index, uint32_t count) 765 | { 766 | if (!g_current_vb) 767 | { 768 | std::cout << "DRAW ERROR: No vertex buffer bound!" << std::endl; 769 | return; 770 | } 771 | 772 | // Retrieve vertices vector from vertex buffer. 773 | std::vector& vertices = g_current_vb->vertices; 774 | 775 | // Compute MVP matrix. 776 | mat4f vp = g_current_projection_mat * g_current_view_mat; 777 | 778 | // Iterate over vertices. 779 | #pragma omp parallel for 780 | for (int i = 0; i < count; i += 3) 781 | { 782 | // Rasterize triangle. 783 | triangle(vertices[first_index + i], vertices[first_index + i + 1], vertices[first_index + i + 2], vp, g_current_color_target, g_current_depth_target); 784 | } 785 | } 786 | 787 | // ----------------------------------------------------------------------------------------------------------------------------------- 788 | 789 | void draw_indexed(uint32_t count) 790 | { 791 | if (!g_current_vb) 792 | { 793 | std::cout << "DRAW INDEXED ERROR: No vertex buffer bound!" << std::endl; 794 | return; 795 | } 796 | 797 | if (!g_current_ib) 798 | { 799 | std::cout << "DRAW INDEXED ERROR: No index buffer bound!" << std::endl; 800 | return; 801 | } 802 | 803 | // Retrieve vertices and indices vectors from vertex and index buffers. 804 | std::vector& indices = g_current_ib->indices; 805 | std::vector& vertices = g_current_vb->vertices; 806 | 807 | // Compute MVP matrix. 808 | mat4f vp = g_current_projection_mat * g_current_view_mat; 809 | 810 | // Iterate over vertices, 811 | #pragma omp parallel for 812 | for (int i = 0; i < count; i += 3) 813 | { 814 | // Rasterize triangle. 815 | triangle(vertices[indices[i]], vertices[indices[i + 1]], vertices[indices[i + 2]], vp, g_current_color_target, g_current_depth_target); 816 | } 817 | } 818 | 819 | // ----------------------------------------------------------------------------------------------------------------------------------- 820 | 821 | void draw_indexed_base_vertex(uint32_t index_count, uint32_t base_index, uint32_t base_vertex) 822 | { 823 | if (!g_current_vb) 824 | { 825 | std::cout << "DRAW INDEXED ERROR: No vertex buffer bound!" << std::endl; 826 | return; 827 | } 828 | 829 | if (!g_current_ib) 830 | { 831 | std::cout << "DRAW INDEXED ERROR: No index buffer bound!" << std::endl; 832 | return; 833 | } 834 | 835 | // Retrieve vertices and indices vectors from vertex and index buffers. 836 | std::vector& indices = g_current_ib->indices; 837 | std::vector& vertices = g_current_vb->vertices; 838 | 839 | // Compute MVP matrix. 840 | mat4f vp = g_current_projection_mat * g_current_view_mat; 841 | 842 | // Iterate over vertices. 843 | #pragma omp parallel for 844 | for (int i = 0; i < index_count; i += 3) 845 | { 846 | // Rasterize triangle. 847 | triangle(vertices[base_vertex + indices[base_index + i]], vertices[base_vertex + indices[base_index + i + 1]], vertices[base_vertex + indices[base_index + i + 2]], vp, g_current_color_target, g_current_depth_target); 848 | } 849 | } 850 | 851 | // ----------------------------------------------------------------------------------------------------------------------------------- 852 | } // namespace rst 853 | --------------------------------------------------------------------------------