├── .gitignore ├── .vscode ├── c_cpp_properties.json └── settings.json ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── examples ├── example.ps └── example.psobj ├── logo.png └── src ├── definitions.hpp ├── interpreter.cpp ├── lexer.cpp ├── main.cpp ├── parser.cpp ├── propscript.hpp └── quickmath.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | [Bb]uild/ -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win64", 5 | "includePath": [ 6 | "${workspaceFolder}/src/", 7 | "C:/vcpkg/installed/x64-windows/include/", 8 | "C:/Program Files/VulkanSDK/1.3.231.1/Include" 9 | ], 10 | "defines": [ 11 | "_DEBUG", 12 | "UNICODE", 13 | "_UNICODE" 14 | ], 15 | "compileCommands": "${default}", 16 | "windowsSdkVersion": "10.0.18362.0", 17 | "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.27.29110/bin/Hostx64/x64/cl.exe", 18 | "cStandard": "c17", 19 | "cppStandard": "c++17", 20 | "intelliSenseMode": "windows-msvc-x64" 21 | } 22 | ], 23 | "version": 4 24 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.configureSettings": { 3 | "CMAKE_TOOLCHAIN_FILE" : "C:/vcpkg/scripts/buildsystems/vcpkg.cmake", 4 | "VCPKG_TARGET_TRIPLET": "x64-windows" 5 | }, 6 | 7 | "files.associations": { 8 | "atomic": "cpp", 9 | "bit": "cpp", 10 | "cctype": "cpp", 11 | "clocale": "cpp", 12 | "cmath": "cpp", 13 | "compare": "cpp", 14 | "concepts": "cpp", 15 | "cstddef": "cpp", 16 | "cstdint": "cpp", 17 | "cstdio": "cpp", 18 | "cstdlib": "cpp", 19 | "cstring": "cpp", 20 | "ctime": "cpp", 21 | "cwchar": "cpp", 22 | "exception": "cpp", 23 | "initializer_list": "cpp", 24 | "ios": "cpp", 25 | "iosfwd": "cpp", 26 | "iostream": "cpp", 27 | "istream": "cpp", 28 | "iterator": "cpp", 29 | "limits": "cpp", 30 | "memory": "cpp", 31 | "new": "cpp", 32 | "ostream": "cpp", 33 | "stdexcept": "cpp", 34 | "streambuf": "cpp", 35 | "system_error": "cpp", 36 | "tuple": "cpp", 37 | "type_traits": "cpp", 38 | "typeinfo": "cpp", 39 | "utility": "cpp", 40 | "xfacet": "cpp", 41 | "xiosbase": "cpp", 42 | "xlocale": "cpp", 43 | "xlocinfo": "cpp", 44 | "xlocnum": "cpp", 45 | "xmemory": "cpp", 46 | "xstddef": "cpp", 47 | "xstring": "cpp", 48 | "xtr1common": "cpp", 49 | "xutility": "cpp", 50 | "string": "cpp", 51 | "vector": "cpp", 52 | "*.rh": "cpp", 53 | "algorithm": "cpp", 54 | "optional": "cpp", 55 | "set": "cpp", 56 | "xtree": "cpp", 57 | "fstream": "cpp", 58 | "sstream": "cpp", 59 | "array": "cpp" 60 | } 61 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | set(CMAKE_CXX_STANDARD 17) 3 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 4 | 5 | # allows us to set msvc working directory 6 | cmake_policy(SET CMP0091 NEW) 7 | 8 | # set source files: 9 | project(propscript VERSION 1.0) 10 | file(GLOB_RECURSE propscript_src CONFIGURE_DEPENDS "src/*.cpp") 11 | add_executable(${PROJECT_NAME} ${propscript_src}) 12 | 13 | # set working directory: 14 | set_property(TARGET ${PROJECT_NAME} PROPERTY WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/") 15 | if(MSVC) 16 | set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/") 17 | set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DPI_AWARE "PerMonitor") # set dpi awareness (only works on windows) 18 | set_property(TARGET ${PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY MultiThreadedDLL) 19 | endif() -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Daniel Elwell 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 |

2 | 3 |

4 | 5 | # PropScript 6 | PropScript is a small, interpreted programming language designed for scripting. I wrote it to facilitate the development of Terra Toy, my video game. It has a similar syntax to Python and was written in ~2500 lines of code with 0 dependencies. Please note that this is merely a hobby project; It is lacking in many features, error messages are vague, and there are likely to be a number of yet undiscovered issues. 7 | 8 | ## Features 9 | - Basic Arithmetic (int, float, vec2, vec3, vec4, quaternion) 10 | - If/Else Statements 11 | - Functions (declared with "func" keyword) 12 | - For Loops (declared similar to python: "for var in range(...)") 13 | - Support for adding functions & constants defined in C++ 14 | - Saving and loading the abstract syntax tree to disk (similar to an object file) 15 | 16 | Overall, the syntax is mostly identifcal to that of Python, with the one notable difference being that multi-line code blocks must be enclosed in curly braces, tabs and all other whitespace is completely ignored. Additionally, individual elements of vectors are accesed as arrays, not with a "." operator (such as ".x"). The first element of a vector is accesed as "myVector[0]", for example. 17 | 18 | ## Does NOT Support 19 | - While/Do-While Loops 20 | - String Literals 21 | - Structs/Classes 22 | - Arrays 23 | - And Much More :) 24 | 25 | ## Building 26 | The project can be built using the included CMake file, no dependencies are required. The main function shows how to lex, parse, and execute an example script. The example script, which prints prime numbers, can be found in "examples/example.ps". 27 | -------------------------------------------------------------------------------- /examples/example.ps: -------------------------------------------------------------------------------- 1 | func is_prime(x) 2 | { 3 | for i in range(2, x / 2) 4 | if x % i == 0 5 | ret 0 6 | 7 | ret 1 8 | } 9 | 10 | for i in range(2, 100) 11 | if is_prime(i) 12 | print(i) -------------------------------------------------------------------------------- /examples/example.psobj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozein/PropScript/cbb7613a23b943111c694bd4e3efbbb585609cda/examples/example.psobj -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozein/PropScript/cbb7613a23b943111c694bd4e3efbbb585609cda/logo.png -------------------------------------------------------------------------------- /src/definitions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DEFINITIONS_HPP 2 | #define DEFINITIONS_HPP 3 | 4 | #include 5 | #include 6 | 7 | #define PS_KEYWORD_FUNC "func" 8 | #define PS_KEYWORD_RETURN "ret" 9 | #define PS_KEYWORD_IF "if" 10 | #define PS_KEYWORD_ELSE "else" 11 | #define PS_KEYWORD_FOR "for" 12 | #define PS_KEYWORD_BREAK "break" 13 | #define PS_KEYWORD_CONTINUE "continue" 14 | 15 | //basically operators, but treated as keyword since we dont want lexer to treat them as ops: 16 | #define PS_KEYWORD_IN "in" 17 | #define PS_KEYWORD_AND "and" 18 | #define PS_KEYWORD_OR "or" 19 | 20 | const std::vector PS_KEYWORDS = { 21 | PS_KEYWORD_FUNC, 22 | PS_KEYWORD_RETURN, 23 | PS_KEYWORD_IF, 24 | PS_KEYWORD_ELSE, 25 | PS_KEYWORD_FOR, 26 | PS_KEYWORD_IN 27 | }; 28 | 29 | //--------------------------------------------------------------------------------------------------------------------------------// 30 | 31 | #define PS_OP_MULT "*" 32 | #define PS_OP_DIV "/" 33 | #define PS_OP_MOD "%" 34 | #define PS_OP_ADD "+" 35 | #define PS_OP_SUB "-" 36 | #define PS_OP_EQUAL "=" 37 | #define PS_OP_MULTEQUAL "*=" 38 | #define PS_OP_DIVEQUAL "/=" 39 | #define PS_OP_MODEQUAL "%=" 40 | #define PS_OP_ADDEQUAL "+=" 41 | #define PS_OP_SUBEQUAL "-=" 42 | #define PS_OP_LESSTHAN "<" 43 | #define PS_OP_GREATERTHAN ">" 44 | #define PS_OP_LESSTHANEQUAL "<=" 45 | #define PS_OP_GREATERTHANEQUAL ">=" 46 | #define PS_OP_EQUALITY "==" 47 | #define PS_OP_NONEQUALITY "!=" 48 | 49 | #define PS_SEPERATOR_PAREN_OPEN "(" 50 | #define PS_SEPERATOR_PAREN_CLOSE ")" 51 | #define PS_SEPERATOR_CURLY_OPEN "{" 52 | #define PS_SEPERATOR_CURLY_CLOSE "}" 53 | #define PS_SEPERATOR_SQUARE_OPEN "[" 54 | #define PS_SEPERATOR_SQUARE_CLOSE "]" 55 | #define PS_SEPERATOR_COMMA "," 56 | 57 | #define PS_COMMENT "#" 58 | 59 | //operators as seen by the parser 60 | const std::vector PS_OPERATORS = { 61 | PS_OP_ADD, 62 | PS_OP_SUB, 63 | PS_OP_MULT, 64 | PS_OP_DIV, 65 | PS_OP_MOD, 66 | PS_OP_EQUAL, 67 | PS_OP_ADDEQUAL, 68 | PS_OP_SUBEQUAL, 69 | PS_OP_MULTEQUAL, 70 | PS_OP_DIVEQUAL, 71 | PS_OP_LESSTHAN, 72 | PS_OP_GREATERTHAN, 73 | PS_OP_LESSTHANEQUAL, 74 | PS_OP_GREATERTHANEQUAL, 75 | PS_OP_EQUALITY, 76 | PS_OP_NONEQUALITY, 77 | PS_KEYWORD_AND, 78 | PS_KEYWORD_OR 79 | }; 80 | 81 | //operators as seen by the lexer 82 | const std::vector PS_LEXER_OPERATORS = { 83 | PS_OP_ADD, 84 | PS_OP_SUB, 85 | PS_OP_MULT, 86 | PS_OP_DIV, 87 | PS_OP_MOD, 88 | PS_OP_EQUAL, 89 | PS_OP_ADDEQUAL, 90 | PS_OP_SUBEQUAL, 91 | PS_OP_MULTEQUAL, 92 | PS_OP_DIVEQUAL, 93 | PS_OP_LESSTHAN, 94 | PS_OP_GREATERTHAN, 95 | PS_OP_LESSTHANEQUAL, 96 | PS_OP_GREATERTHANEQUAL, 97 | PS_OP_EQUALITY, 98 | PS_OP_NONEQUALITY, 99 | 100 | PS_SEPERATOR_PAREN_OPEN, 101 | PS_SEPERATOR_PAREN_CLOSE, 102 | PS_SEPERATOR_CURLY_OPEN, 103 | PS_SEPERATOR_CURLY_CLOSE, 104 | PS_SEPERATOR_SQUARE_OPEN, 105 | PS_SEPERATOR_SQUARE_CLOSE, 106 | PS_SEPERATOR_COMMA, 107 | 108 | PS_COMMENT //added so lexer can easily identify comments 109 | }; 110 | 111 | const std::vector PS_CLOSED_SEPERATORS = { 112 | PS_SEPERATOR_PAREN_CLOSE, 113 | PS_SEPERATOR_CURLY_CLOSE, 114 | PS_SEPERATOR_SQUARE_CLOSE, 115 | PS_SEPERATOR_COMMA 116 | }; 117 | 118 | #endif -------------------------------------------------------------------------------- /src/interpreter.cpp: -------------------------------------------------------------------------------- 1 | #include "propscript.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #define _USE_MATH_DEFINES 7 | #include 8 | 9 | //--------------------------------------------------------------------------------------------------------------------------------// 10 | 11 | enum class PSruntimeError 12 | { 13 | INVALID_ASSIGNMENT, 14 | INVALID_OP, 15 | UNSUPPORTED_NODE_TYPE, 16 | UNDEFINED_VARIABLE, 17 | UNDEFINED_FUNCTION, 18 | INVALID_PARAMS, 19 | INVALID_INDEX, 20 | INVALID_CONDITION, 21 | INVALID_BREAK_CONTINUE, 22 | FUNCTION_REDEFINITION, 23 | ARGUMENT_NAME_REDEFINITION 24 | }; 25 | 26 | //executes a set of statements with their own scope 27 | static void _ps_execute_statements(PSast* ast, const std::vector& nodes); 28 | //evaluates a single statement 29 | static PSdata _ps_evaluate_statement(PSast* ast, const PSnode& node, std::vector& addedFuncs, std::vector& addedVars); 30 | //executes a programmer-defined function 31 | static inline PSdata _ps_execute_function(PSast* ast, const PSnode& node, std::vector& addedFuncs, std::vector& addedVars); 32 | 33 | //gets the scalar value from a PSdata struct, or throws an error if the data type is not a scalar 34 | static inline float _ps_get_scalar(PSdata data, PSruntimeError potentialError, const PSnode& node); 35 | //throws an exception and sets the global error flags 36 | static inline void _ps_error(PSruntimeError error, PSnode errorNode); 37 | 38 | //OPERATOR FUNCTIONS: 39 | static inline PSdata _ps_mult(const PSdata& left, const PSdata& right, const PSnode& node); 40 | static inline PSdata _ps_div (const PSdata& left, const PSdata& right, const PSnode& node); 41 | static inline PSdata _ps_mod (const PSdata& left, const PSdata& right, const PSnode& node); 42 | 43 | static inline PSdata _ps_add(const PSdata& left, const PSdata& right, const PSnode& node); 44 | static inline PSdata _ps_sub(const PSdata& left, const PSdata& right, const PSnode& node); 45 | 46 | static inline PSdata _ps_equal(PSast* ast, const PSnode& var, const PSdata& val, std::vector& addedFuncs, std::vector& addedVars); 47 | 48 | static inline PSdata _ps_lessthan (const PSdata& left, const PSdata& right, const PSnode& node); 49 | static inline PSdata _ps_greaterthan (const PSdata& left, const PSdata& right, const PSnode& node); 50 | static inline PSdata _ps_lessthanequal (const PSdata& left, const PSdata& right, const PSnode& node); 51 | static inline PSdata _ps_greaterthanequal(const PSdata& left, const PSdata& right, const PSnode& node); 52 | static inline PSdata _ps_equality (const PSdata& left, const PSdata& right, const PSnode& node); 53 | 54 | static inline PSdata _ps_and(const PSdata& left, const PSdata& right, const PSnode& node); 55 | static inline PSdata _ps_or (const PSdata& left, const PSdata& right, const PSnode& node); 56 | 57 | //DEFAULT LIBRARY FUNCTIONS (more will be added as i need them): 58 | static PSdata _ps_range(const std::vector& params, const PSnode& node, void* userData); 59 | static PSdata _ps_print(const std::vector& params, const PSnode& node, void* userData); 60 | static PSdata _ps_rand (const std::vector& params, const PSnode& node, void* userData); 61 | 62 | static PSdata _ps_int (const std::vector& params, const PSnode& node, void* userData); 63 | static PSdata _ps_vec2 (const std::vector& params, const PSnode& node, void* userData); 64 | static PSdata _ps_vec3 (const std::vector& params, const PSnode& node, void* userData); 65 | static PSdata _ps_vec4 (const std::vector& params, const PSnode& node, void* userData); 66 | static PSdata _ps_quaternion(const std::vector& params, const PSnode& node, void* userData); 67 | 68 | static PSdata _ps_sqrt(const std::vector& params, const PSnode& node, void* userData); 69 | static PSdata _ps_pow (const std::vector& params, const PSnode& node, void* userData); 70 | static PSdata _ps_abs (const std::vector& params, const PSnode& node, void* userData); 71 | 72 | static PSdata _ps_sin (const std::vector& params, const PSnode& node, void* userData); 73 | static PSdata _ps_cos (const std::vector& params, const PSnode& node, void* userData); 74 | static PSdata _ps_tan (const std::vector& params, const PSnode& node, void* userData); 75 | static PSdata _ps_asin(const std::vector& params, const PSnode& node, void* userData); 76 | static PSdata _ps_acos(const std::vector& params, const PSnode& node, void* userData); 77 | static PSdata _ps_atan(const std::vector& params, const PSnode& node, void* userData); 78 | 79 | //--------------------------------------------------------------------------------------------------------------------------------// 80 | 81 | static PSruntimeError g_psError; 82 | static PSnode g_psErrorNode; 83 | 84 | const std::vector PS_DEFAULT_LIB_FUNCTIONS = { 85 | {"range" , _ps_range}, 86 | {"print" , _ps_print}, 87 | {"rand" , _ps_rand}, 88 | {"int" , _ps_int}, 89 | {"vec2" , _ps_vec2}, 90 | {"vec3" , _ps_vec3}, 91 | {"vec4" , _ps_vec4}, 92 | {"quaternion", _ps_quaternion}, 93 | {"sqrt" , _ps_sqrt}, 94 | {"pow" , _ps_pow}, 95 | {"abs" , _ps_abs}, 96 | {"sin" , _ps_sin}, 97 | {"cos" , _ps_cos}, 98 | {"tan" , _ps_tan}, 99 | {"asin" , _ps_asin}, 100 | {"acos" , _ps_acos}, 101 | {"atan" , _ps_atan}, 102 | }; 103 | 104 | const std::vector PS_DEFAULT_CONSTANTS = { 105 | {"M_PI" , PSdata(PSdata::FLOAT, (float)M_PI)}, 106 | {"M_TAU", PSdata(PSdata::FLOAT, 2.0f * (float)M_PI)}, 107 | {"M_E" , PSdata(PSdata::FLOAT, (float)M_E) } 108 | }; 109 | 110 | static std::unordered_map g_psLibFunctions; 111 | static std::unordered_map g_psConstants; 112 | static void* g_psLibFunctionUserData = nullptr; 113 | 114 | static std::unordered_map g_psFunctions; 115 | static std::unordered_map g_psVariables; 116 | 117 | static bool g_psInLoop = false; 118 | 119 | static bool g_psReturnFlag = false; 120 | static bool g_psBreakFlag = false; 121 | static bool g_psContinueFlag = false; 122 | static PSdata g_psReturnVal = {}; 123 | 124 | //--------------------------------------------------------------------------------------------------------------------------------// 125 | 126 | void ps_set_functions(const std::vector& functions) 127 | { 128 | g_psLibFunctions.clear(); 129 | 130 | for(int i = 0; i < PS_DEFAULT_LIB_FUNCTIONS.size(); i++) 131 | g_psLibFunctions[PS_DEFAULT_LIB_FUNCTIONS[i].name] = PS_DEFAULT_LIB_FUNCTIONS[i]; 132 | 133 | for(int i = 0; i < functions.size(); i++) 134 | g_psLibFunctions[functions[i].name] = functions[i]; 135 | } 136 | 137 | void ps_set_constants(const std::vector& constants) 138 | { 139 | g_psConstants.clear(); 140 | 141 | for(int i = 0; i < PS_DEFAULT_CONSTANTS.size(); i++) 142 | g_psConstants[PS_DEFAULT_CONSTANTS[i].name] = PS_DEFAULT_CONSTANTS[i].val; 143 | 144 | for(int i = 0; i < constants.size(); i++) 145 | g_psConstants[constants[i].name] = constants[i].val; 146 | } 147 | 148 | void ps_set_function_user_data(void* userData) 149 | { 150 | g_psLibFunctionUserData = userData; 151 | } 152 | 153 | void ps_throw_invalid_param_error(PSnode node) 154 | { 155 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 156 | } 157 | 158 | void ps_execute(PSast* ast) 159 | { 160 | if(g_psLibFunctions.size() == 0) 161 | ps_set_functions({}); 162 | 163 | if(g_psConstants.size() == 0) 164 | ps_set_constants({}); 165 | 166 | try 167 | { 168 | _ps_execute_statements(ast, ast->parentNodes); 169 | 170 | if(g_psReturnFlag) 171 | g_psReturnFlag = false; 172 | } 173 | catch(std::exception e) 174 | { 175 | std::string errMsg; 176 | PSnode testNode = g_psErrorNode; 177 | switch(g_psError) 178 | { 179 | case PSruntimeError::INVALID_ASSIGNMENT: 180 | errMsg = "INVALID ASSIGNMENT"; 181 | break; 182 | case PSruntimeError::INVALID_OP: 183 | errMsg = "INVALID OPERATION"; 184 | break; 185 | case PSruntimeError::UNSUPPORTED_NODE_TYPE: 186 | errMsg = "UNSUPPORTED NODE TYPE (i must've forgot to implement something in the interpreter)"; 187 | break; 188 | case PSruntimeError::UNDEFINED_VARIABLE: 189 | errMsg = "UNDEFINED VARIABLE"; 190 | break; 191 | case PSruntimeError::UNDEFINED_FUNCTION: 192 | errMsg = "UNDEFINED FUNCTION"; 193 | break; 194 | case PSruntimeError::INVALID_PARAMS: 195 | errMsg = "INVALID PARAMETERS"; 196 | break; 197 | case PSruntimeError::INVALID_INDEX: 198 | errMsg = "INVALID INDEX"; 199 | break; 200 | case PSruntimeError::INVALID_CONDITION: 201 | errMsg = "INVALID CONDITION"; 202 | break; 203 | case PSruntimeError::INVALID_BREAK_CONTINUE: 204 | errMsg = "INVALID BREAK/CONTINUE"; 205 | break; 206 | case PSruntimeError::FUNCTION_REDEFINITION: 207 | errMsg = "FUNCTION REDEFINITION"; 208 | break; 209 | case PSruntimeError::ARGUMENT_NAME_REDEFINITION: 210 | errMsg = "ARGUMENT NAME REDEFINITION"; 211 | break; 212 | } 213 | 214 | std::cout << "PROPSCRIPT RUNTIME ERROR: " << errMsg << " ON LINE " << g_psErrorNode.lineNum << std::endl; 215 | 216 | //there might be uncleared vars/funcs if we run into an error: 217 | g_psFunctions.clear(); 218 | g_psVariables.clear(); 219 | } 220 | } 221 | 222 | //--------------------------------------------------------------------------------------------------------------------------------// 223 | 224 | static void _ps_execute_statements(PSast* ast, const std::vector& nodes) 225 | { 226 | std::vector addedFuncs; 227 | std::vector addedVars; 228 | 229 | for(int i = 0; i < nodes.size(); i++) 230 | { 231 | _ps_evaluate_statement(ast, ast->nodePool[nodes[i]], addedFuncs, addedVars); 232 | 233 | if(g_psReturnFlag || g_psBreakFlag || g_psContinueFlag) 234 | break; 235 | } 236 | 237 | for(int i = 0; i < addedFuncs.size(); i++) 238 | g_psFunctions.erase(addedFuncs[i]); 239 | for(int i = 0; i < addedVars.size(); i++) 240 | g_psVariables.erase(addedVars[i]); 241 | } 242 | 243 | static PSdata _ps_evaluate_statement(PSast* ast, const PSnode& node, std::vector& addedFuncs, std::vector& addedVars) 244 | { 245 | switch(node.type) 246 | { 247 | case PSnode::OP: 248 | { 249 | if(node.op.type == PSnode::OP::EQUAL) 250 | return _ps_equal(ast, ast->nodePool[node.op.left], _ps_evaluate_statement(ast, ast->nodePool[node.op.right], addedFuncs, addedVars), addedFuncs, addedVars); 251 | 252 | PSdata left = _ps_evaluate_statement(ast, ast->nodePool[node.op.left ], addedFuncs, addedVars); 253 | PSdata right = _ps_evaluate_statement(ast, ast->nodePool[node.op.right], addedFuncs, addedVars); 254 | 255 | switch(node.op.type) 256 | { 257 | case PSnode::OP::MULT: 258 | return _ps_mult(left, right, node); 259 | case PSnode::OP::DIV: 260 | return _ps_div(left, right, node); 261 | case PSnode::OP::MOD: 262 | return _ps_mod(left, right, node); 263 | case PSnode::OP::ADD: 264 | return _ps_add(left, right, node); 265 | case PSnode::OP::SUB: 266 | return _ps_sub(left, right, node); 267 | case PSnode::OP::MULTEQUAL: 268 | return _ps_equal(ast, ast->nodePool[node.op.left], _ps_mult(left, right, node), addedFuncs, addedVars); 269 | case PSnode::OP::DIVEQUAL: 270 | return _ps_equal(ast, ast->nodePool[node.op.left], _ps_div(left, right, node), addedFuncs, addedVars); 271 | case PSnode::OP::MODEQUAL: 272 | return _ps_equal(ast, ast->nodePool[node.op.left], _ps_mod(left, right, node), addedFuncs, addedVars); 273 | case PSnode::OP::ADDEQUAL: 274 | return _ps_equal(ast, ast->nodePool[node.op.left], _ps_add(left, right, node), addedFuncs, addedVars); 275 | case PSnode::OP::SUBEQUAL: 276 | return _ps_equal(ast, ast->nodePool[node.op.left], _ps_sub(left, right, node), addedFuncs, addedVars); 277 | case PSnode::OP::LESSTHAN: 278 | return _ps_lessthan(left, right, node); 279 | case PSnode::OP::GREATERTHAN: 280 | return _ps_greaterthan(left, right, node); 281 | case PSnode::OP::LESSTHANEQUAL: 282 | return _ps_lessthanequal(left, right, node); 283 | case PSnode::OP::GREATERTHANEQUAL: 284 | return _ps_greaterthanequal(left, right, node); 285 | case PSnode::OP::EQUALITY: 286 | return _ps_equality(left, right, node); 287 | case PSnode::OP::NONEQUALITY: 288 | { 289 | PSdata equality = _ps_equality(left, right, node); 290 | equality.intVal = !equality.intVal; 291 | return equality; 292 | } 293 | case PSnode::OP::AND: 294 | return _ps_and(left, right, node); 295 | case PSnode::OP::OR: 296 | return _ps_or(left, right, node); 297 | default: 298 | _ps_error(PSruntimeError::UNSUPPORTED_NODE_TYPE, node); 299 | } 300 | 301 | return {}; 302 | } 303 | case PSnode::ID: 304 | { 305 | if(node.id.type == PSnode::ID::FUNC) 306 | { 307 | std::vector params; 308 | for(int i = 0; i < node.id.params.size(); i++) 309 | params.push_back(_ps_evaluate_statement(ast, ast->nodePool[node.id.params[i]], addedFuncs, addedVars)); 310 | 311 | if(g_psLibFunctions.count(node.id.name) > 0) 312 | return g_psLibFunctions[node.id.name].func(params, node, g_psLibFunctionUserData); 313 | else if(g_psFunctions.count(node.id.name) > 0) 314 | return _ps_execute_function(ast, node, addedFuncs, addedVars); 315 | else 316 | _ps_error(PSruntimeError::UNDEFINED_FUNCTION, node); 317 | } 318 | else 319 | { 320 | if(g_psConstants.count(node.id.name) == 1) 321 | return g_psConstants[node.id.name]; 322 | 323 | if(g_psVariables.count(node.id.name) == 0) 324 | _ps_error(PSruntimeError::UNDEFINED_VARIABLE, node); 325 | 326 | PSdata var = g_psVariables[node.id.name]; 327 | if(node.id.params.size() == 0) 328 | return var; 329 | 330 | if(var.type == PSdata::INT || var.type == PSdata::FLOAT) 331 | _ps_error(PSruntimeError::INVALID_INDEX, node); 332 | 333 | PSdata index = _ps_evaluate_statement(ast, ast->nodePool[node.id.params[0]], addedFuncs, addedVars); 334 | if(index.type != PSdata::INT) 335 | _ps_error(PSruntimeError::INVALID_INDEX, node); 336 | 337 | PSdata result; 338 | result.type = PSdata::FLOAT; 339 | 340 | if(var.type == PSdata::VEC2 && index.intVal <= 1) 341 | result.floatVal = *((float*)&var.vec2Val + index.intVal); 342 | else if(var.type == PSdata::VEC3 && index.intVal <= 2) 343 | result.floatVal = *((float*)&var.vec3Val + index.intVal); 344 | else if(var.type == PSdata::VEC4 && index.intVal <= 3) 345 | result.floatVal = *((float*)&var.vec4Val + index.intVal); 346 | else 347 | _ps_error(PSruntimeError::INVALID_INDEX, node); 348 | 349 | return result; 350 | } 351 | 352 | return {}; 353 | } 354 | case PSnode::NUMBER: 355 | { 356 | PSdata num; 357 | 358 | if(node.literal.type == PSnode::Literal::INT) 359 | { 360 | num.type = PSdata::INT; 361 | num.intVal = node.literal.intNum; 362 | } 363 | else 364 | { 365 | num.type = PSdata::FLOAT; 366 | num.floatVal = node.literal.floatNum; 367 | } 368 | 369 | return num; 370 | } 371 | case PSnode::KEYWORD: 372 | { 373 | switch(node.keyword.type) 374 | { 375 | case PSnode::Keyword::IF: 376 | { 377 | PSdata condition = _ps_evaluate_statement(ast, ast->nodePool[node.keyword.condition], addedVars, addedFuncs); 378 | if(_ps_get_scalar(condition, PSruntimeError::INVALID_CONDITION, node) != 0.0f) 379 | _ps_execute_statements(ast, node.keyword.code); 380 | else if(node.keyword.hasElse) 381 | _ps_execute_statements(ast, node.keyword.elseCode); 382 | 383 | return {}; 384 | } 385 | case PSnode::Keyword::FOR: 386 | { 387 | if(ast->nodePool[node.keyword.condition].type != PSnode::OP || 388 | ast->nodePool[node.keyword.condition].op.type != PSnode::OP::IN) 389 | _ps_error(PSruntimeError::INVALID_CONDITION, node); 390 | 391 | PSnode var = ast->nodePool[ast->nodePool[node.keyword.condition].op.left]; 392 | if(var.type != PSnode::ID || var.id.type != PSnode::ID::VAR || g_psVariables.count(var.id.name) > 0) 393 | _ps_error(PSruntimeError::INVALID_CONDITION, node); 394 | 395 | std::vector forFuncs; 396 | std::vector forVars; 397 | 398 | PSdata range = _ps_evaluate_statement(ast, ast->nodePool[ast->nodePool[node.keyword.condition].op.right], forFuncs, forVars); 399 | if(range.type != PSdata::VEC2) 400 | _ps_error(PSruntimeError::INVALID_CONDITION, node); 401 | 402 | bool outermostLoop = false; 403 | if(!g_psInLoop) 404 | { 405 | outermostLoop = true; 406 | g_psInLoop = true; 407 | } 408 | 409 | int32_t min = (int32_t)ceilf (range.vec2Val.x); 410 | int32_t max = (int32_t)floorf(range.vec2Val.y); 411 | for(int32_t i = min; i <= max; i++) 412 | { 413 | PSdata val; 414 | val.type = PSdata::INT; 415 | val.intVal = i; 416 | _ps_equal(ast, var, val, forFuncs, forVars); 417 | 418 | _ps_execute_statements(ast, node.keyword.code); 419 | 420 | if(g_psBreakFlag) 421 | { 422 | g_psBreakFlag = false; 423 | break; 424 | } 425 | 426 | if(g_psContinueFlag) 427 | { 428 | g_psContinueFlag = false; 429 | continue; 430 | } 431 | } 432 | 433 | for(int i = 0; i < forFuncs.size(); i++) 434 | g_psFunctions.erase(forFuncs[i]); 435 | for(int i = 0; i < forVars.size(); i++) 436 | g_psVariables.erase(forVars[i]); 437 | 438 | if(outermostLoop) 439 | g_psInLoop = false; 440 | 441 | return {}; 442 | } 443 | case PSnode::Keyword::FUNC: 444 | { 445 | if(g_psFunctions.count(node.keyword.name) > 0) 446 | _ps_error(PSruntimeError::FUNCTION_REDEFINITION, node); 447 | 448 | g_psFunctions[node.keyword.name] = node; 449 | addedFuncs.push_back(node.keyword.name); 450 | 451 | return {}; 452 | } 453 | case PSnode::Keyword::RETURN: 454 | { 455 | g_psReturnFlag = true; 456 | 457 | if(node.keyword.returnVal < UINT32_MAX) 458 | g_psReturnVal = _ps_evaluate_statement(ast, ast->nodePool[node.keyword.returnVal], addedFuncs, addedVars); 459 | else 460 | g_psReturnVal = {}; 461 | 462 | return {}; 463 | } 464 | case PSnode::Keyword::BREAK: 465 | { 466 | if(!g_psInLoop) 467 | _ps_error(PSruntimeError::INVALID_BREAK_CONTINUE, node); 468 | 469 | g_psBreakFlag = true; 470 | return {}; 471 | } 472 | case PSnode::Keyword::CONTINUE: 473 | { 474 | if(!g_psInLoop) 475 | _ps_error(PSruntimeError::INVALID_BREAK_CONTINUE, node); 476 | 477 | g_psContinueFlag = true; 478 | return {}; 479 | } 480 | default: 481 | _ps_error(PSruntimeError::UNSUPPORTED_NODE_TYPE, node); 482 | } 483 | 484 | return {}; 485 | } 486 | default: 487 | _ps_error(PSruntimeError::UNSUPPORTED_NODE_TYPE, node); 488 | return {}; 489 | } 490 | } 491 | 492 | static inline PSdata _ps_execute_function(PSast* ast, const PSnode& node, std::vector& addedFuncs, std::vector& addedVars) 493 | { 494 | PSnode funcNode = g_psFunctions[node.id.name]; 495 | 496 | if(funcNode.keyword.paramNames.size() != node.id.params.size()) 497 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 498 | 499 | std::unordered_map funcVars; 500 | 501 | for(int i = 0; i < funcNode.keyword.paramNames.size(); i++) 502 | { 503 | if(funcVars.count(funcNode.keyword.paramNames[i]) > 0) 504 | _ps_error(PSruntimeError::ARGUMENT_NAME_REDEFINITION, funcNode); 505 | 506 | funcVars[funcNode.keyword.paramNames[i]] = _ps_evaluate_statement(ast, ast->nodePool[node.id.params[i]], addedFuncs, addedVars); 507 | } 508 | 509 | funcVars.swap(g_psVariables); 510 | _ps_execute_statements(ast, funcNode.keyword.code); 511 | funcVars.swap(g_psVariables); 512 | 513 | for(int i = 0; i < funcNode.keyword.paramNames.size(); i++) 514 | g_psVariables.erase(funcNode.keyword.paramNames[i]); 515 | 516 | if(g_psReturnFlag) 517 | { 518 | g_psReturnFlag = false; 519 | return g_psReturnVal; 520 | } 521 | else 522 | return {}; 523 | } 524 | 525 | //--------------------------------------------------------------------------------------------------------------------------------// 526 | 527 | static inline float _ps_get_scalar(PSdata data, PSruntimeError potentialError, const PSnode& node) 528 | { 529 | if(data.type == PSdata::INT) 530 | return (float)data.intVal; 531 | else if(data.type == PSdata::FLOAT) 532 | return data.floatVal; 533 | else 534 | _ps_error(potentialError, node); 535 | 536 | return 0.0f; 537 | } 538 | 539 | static inline void _ps_error(PSruntimeError error, PSnode errorNode) 540 | { 541 | g_psError = error; 542 | g_psErrorNode = errorNode; 543 | throw std::exception(); 544 | } 545 | 546 | //--------------------------------------------------------------------------------------------------------------------------------// 547 | 548 | static inline PSdata _ps_mult(const PSdata& left, const PSdata& right, const PSnode& node) 549 | { 550 | PSdata result; 551 | 552 | if(left.type == PSdata::INT && right.type == PSdata::INT) 553 | { 554 | result.type = PSdata::INT; 555 | result.intVal = left.intVal * right.intVal; 556 | } 557 | else if(left.type == PSdata::FLOAT && right.type == PSdata::FLOAT) 558 | { 559 | result.type = PSdata::FLOAT; 560 | result.floatVal = left.floatVal * right.floatVal; 561 | } 562 | else if((left.type == PSdata::INT && right.type == PSdata::FLOAT) || 563 | (left.type == PSdata::FLOAT && right.type == PSdata::INT)) 564 | { 565 | result.type = PSdata::FLOAT; 566 | result.floatVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) * _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 567 | } 568 | else if(left.type == PSdata::VEC2 && right.type == PSdata::VEC2) 569 | { 570 | result.type = PSdata::VEC2; 571 | result.vec2Val = left.vec2Val * right.vec2Val; 572 | } 573 | else if(left.type == PSdata::VEC3 && right.type == PSdata::VEC3) 574 | { 575 | result.type = PSdata::VEC3; 576 | result.vec3Val = left.vec3Val * right.vec3Val; 577 | } 578 | else if(left.type == PSdata::VEC4 && right.type == PSdata::VEC4) 579 | { 580 | result.type = PSdata::VEC4; 581 | result.vec4Val = left.vec4Val * right.vec4Val; 582 | } 583 | else if(left.type == PSdata::QUATERNION && right.type == PSdata::QUATERNION) 584 | { 585 | result.type = PSdata::QUATERNION; 586 | result.quatVal = left.quatVal * right.quatVal; 587 | } 588 | else if(left.type == PSdata::VEC2 && (right.type == PSdata::INT || right.type == PSdata::FLOAT)) 589 | { 590 | result.type = PSdata::VEC2; 591 | result.vec2Val = left.vec2Val * _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 592 | } 593 | else if((left.type == PSdata::INT || left.type == PSdata::FLOAT) && right.type == PSdata::VEC2) 594 | { 595 | result.type = PSdata::VEC2; 596 | result.vec2Val = right.vec2Val * _ps_get_scalar(left, PSruntimeError::INVALID_OP, node); 597 | } 598 | else if(left.type == PSdata::VEC3 && (right.type == PSdata::INT || right.type == PSdata::FLOAT)) 599 | { 600 | result.type = PSdata::VEC3; 601 | result.vec3Val = left.vec3Val * _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 602 | } 603 | else if((left.type == PSdata::INT || left.type == PSdata::FLOAT) && right.type == PSdata::VEC3) 604 | { 605 | result.type = PSdata::VEC3; 606 | result.vec3Val = right.vec3Val * _ps_get_scalar(left, PSruntimeError::INVALID_OP, node); 607 | } 608 | else if(left.type == PSdata::VEC4 && (right.type == PSdata::INT || right.type == PSdata::FLOAT)) 609 | { 610 | result.type = PSdata::VEC4; 611 | result.vec4Val = left.vec4Val * _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 612 | } 613 | else if((left.type == PSdata::INT || left.type == PSdata::FLOAT) && right.type == PSdata::VEC4) 614 | { 615 | result.type = PSdata::VEC4; 616 | result.vec4Val = right.vec4Val * _ps_get_scalar(left, PSruntimeError::INVALID_OP, node); 617 | } 618 | else if(left.type == PSdata::QUATERNION && (right.type == PSdata::INT || right.type == PSdata::FLOAT)) 619 | { 620 | result.type = PSdata::QUATERNION; 621 | result.quatVal = left.quatVal * _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 622 | } 623 | else if((left.type == PSdata::INT || left.type == PSdata::FLOAT) && right.type == PSdata::QUATERNION) 624 | { 625 | result.type = PSdata::QUATERNION; 626 | result.quatVal = right.quatVal * _ps_get_scalar(left, PSruntimeError::INVALID_OP, node); 627 | } 628 | else 629 | _ps_error(PSruntimeError::INVALID_OP, node); 630 | 631 | return result; 632 | } 633 | 634 | static inline PSdata _ps_div(const PSdata& left, const PSdata& right, const PSnode& node) 635 | { 636 | PSdata result; 637 | 638 | if(left.type == PSdata::INT && right.type == PSdata::INT) 639 | { 640 | result.type = PSdata::INT; 641 | result.intVal = left.intVal / right.intVal; 642 | } 643 | else if(left.type == PSdata::FLOAT && right.type == PSdata::FLOAT) 644 | { 645 | result.type = PSdata::FLOAT; 646 | result.floatVal = left.floatVal / right.floatVal; 647 | } 648 | else if((left.type == PSdata::INT && right.type == PSdata::FLOAT) || 649 | (left.type == PSdata::FLOAT && right.type == PSdata::INT)) 650 | { 651 | result.type = PSdata::FLOAT; 652 | result.floatVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) / _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 653 | } 654 | else if(left.type == PSdata::VEC2 && right.type == PSdata::VEC2) 655 | { 656 | result.type = PSdata::VEC2; 657 | result.vec2Val = left.vec2Val / right.vec2Val; 658 | } 659 | else if(left.type == PSdata::VEC3 && right.type == PSdata::VEC3) 660 | { 661 | result.type = PSdata::VEC3; 662 | result.vec3Val = left.vec3Val / right.vec3Val; 663 | } 664 | else if(left.type == PSdata::VEC4 && right.type == PSdata::VEC4) 665 | { 666 | result.type = PSdata::VEC4; 667 | result.vec4Val = left.vec4Val / right.vec4Val; 668 | } 669 | else if(left.type == PSdata::VEC2 && (right.type == PSdata::INT || right.type == PSdata::FLOAT)) 670 | { 671 | result.type = PSdata::VEC2; 672 | result.vec2Val = left.vec2Val / _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 673 | } 674 | else if((left.type == PSdata::INT || left.type == PSdata::FLOAT) && right.type == PSdata::VEC2) 675 | { 676 | result.type = PSdata::VEC2; 677 | result.vec2Val = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) / right.vec2Val; 678 | } 679 | else if(left.type == PSdata::VEC3 && (right.type == PSdata::INT || right.type == PSdata::FLOAT)) 680 | { 681 | result.type = PSdata::VEC3; 682 | result.vec3Val = left.vec3Val / _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 683 | } 684 | else if((left.type == PSdata::INT || left.type == PSdata::FLOAT) && right.type == PSdata::VEC3) 685 | { 686 | result.type = PSdata::VEC3; 687 | result.vec3Val = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) / right.vec3Val; 688 | } 689 | else if(left.type == PSdata::VEC4 && (right.type == PSdata::INT || right.type == PSdata::FLOAT)) 690 | { 691 | result.type = PSdata::VEC4; 692 | result.vec4Val = left.vec4Val / _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 693 | } 694 | else if((left.type == PSdata::INT || left.type == PSdata::FLOAT) && right.type == PSdata::VEC4) 695 | { 696 | result.type = PSdata::VEC4; 697 | result.vec4Val = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) / right.vec4Val; 698 | } 699 | else if(left.type == PSdata::QUATERNION && (right.type == PSdata::INT || right.type == PSdata::FLOAT)) 700 | { 701 | result.type = PSdata::QUATERNION; 702 | result.quatVal = left.quatVal / _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 703 | } 704 | else if((left.type == PSdata::INT || left.type == PSdata::FLOAT) && right.type == PSdata::QUATERNION) 705 | { 706 | result.type = PSdata::QUATERNION; 707 | result.quatVal = right.quatVal / _ps_get_scalar(left, PSruntimeError::INVALID_OP, node); 708 | } 709 | else 710 | _ps_error(PSruntimeError::INVALID_OP, node); 711 | 712 | return result; 713 | } 714 | 715 | static inline PSdata _ps_mod(const PSdata& left, const PSdata& right, const PSnode& node) 716 | { 717 | PSdata result; 718 | 719 | if(left.type == PSdata::INT && right.type == PSdata::INT) 720 | { 721 | result.type = PSdata::INT; 722 | result.intVal = left.intVal % right.intVal; 723 | } 724 | else 725 | _ps_error(PSruntimeError::INVALID_OP, node); 726 | 727 | return result; 728 | } 729 | 730 | static inline PSdata _ps_add(const PSdata& left, const PSdata& right, const PSnode& node) 731 | { 732 | PSdata result; 733 | 734 | if(left.type == PSdata::INT && right.type == PSdata::INT) 735 | { 736 | result.type = PSdata::INT; 737 | result.intVal = left.intVal + right.intVal; 738 | } 739 | else if(left.type == PSdata::FLOAT && right.type == PSdata::FLOAT) 740 | { 741 | result.type = PSdata::FLOAT; 742 | result.floatVal = left.floatVal + right.floatVal; 743 | } 744 | else if((left.type == PSdata::INT && right.type == PSdata::FLOAT) || 745 | (left.type == PSdata::FLOAT && right.type == PSdata::INT)) 746 | { 747 | result.type = PSdata::FLOAT; 748 | result.floatVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) + _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 749 | } 750 | else if(left.type == PSdata::VEC2 && right.type == PSdata::VEC2) 751 | { 752 | result.type = PSdata::VEC2; 753 | result.vec2Val = left.vec2Val + right.vec2Val; 754 | } 755 | else if(left.type == PSdata::VEC3 && right.type == PSdata::VEC3) 756 | { 757 | result.type = PSdata::VEC3; 758 | result.vec3Val = left.vec3Val + right.vec3Val; 759 | } 760 | else if(left.type == PSdata::VEC4 && right.type == PSdata::VEC4) 761 | { 762 | result.type = PSdata::VEC4; 763 | result.vec4Val = left.vec4Val + right.vec4Val; 764 | } 765 | else if(left.type == PSdata::QUATERNION && right.type == PSdata::QUATERNION) 766 | { 767 | result.type = PSdata::QUATERNION; 768 | result.quatVal = left.quatVal + right.quatVal; 769 | } 770 | else 771 | _ps_error(PSruntimeError::INVALID_OP, node); 772 | 773 | return result; 774 | } 775 | 776 | static inline PSdata _ps_sub(const PSdata& left, const PSdata& right, const PSnode& node) 777 | { 778 | PSdata result; 779 | 780 | if(left.type == PSdata::INT && right.type == PSdata::INT) 781 | { 782 | result.type = PSdata::INT; 783 | result.intVal = left.intVal - right.intVal; 784 | } 785 | else if(left.type == PSdata::FLOAT && right.type == PSdata::FLOAT) 786 | { 787 | result.type = PSdata::FLOAT; 788 | result.floatVal = left.floatVal - right.floatVal; 789 | } 790 | else if((left.type == PSdata::INT && right.type == PSdata::FLOAT) || 791 | (left.type == PSdata::FLOAT && right.type == PSdata::INT)) 792 | { 793 | result.type = PSdata::FLOAT; 794 | result.floatVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) - _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 795 | } 796 | else if(left.type == PSdata::VEC2 && right.type == PSdata::VEC2) 797 | { 798 | result.type = PSdata::VEC2; 799 | result.vec2Val = left.vec2Val - right.vec2Val; 800 | } 801 | else if(left.type == PSdata::VEC3 && right.type == PSdata::VEC3) 802 | { 803 | result.type = PSdata::VEC3; 804 | result.vec3Val = left.vec3Val - right.vec3Val; 805 | } 806 | else if(left.type == PSdata::VEC4 && right.type == PSdata::VEC4) 807 | { 808 | result.type = PSdata::VEC4; 809 | result.vec4Val = left.vec4Val - right.vec4Val; 810 | } 811 | else if(left.type == PSdata::QUATERNION && right.type == PSdata::QUATERNION) 812 | { 813 | result.type = PSdata::QUATERNION; 814 | result.quatVal = left.quatVal - right.quatVal; 815 | } 816 | else 817 | _ps_error(PSruntimeError::INVALID_OP, node); 818 | 819 | return result; 820 | } 821 | 822 | static inline PSdata _ps_equal(PSast* ast, const PSnode& var, const PSdata& val, std::vector& addedFuncs, std::vector& addedVars) 823 | { 824 | if(var.type != PSnode::ID || var.id.type != PSnode::ID::VAR) 825 | _ps_error(PSruntimeError::INVALID_ASSIGNMENT, var); 826 | 827 | if(val.type == PSdata::VOID) 828 | _ps_error(PSruntimeError::INVALID_ASSIGNMENT, var); 829 | 830 | if(g_psVariables.count(var.id.name) > 0) 831 | { 832 | if(g_psVariables[var.id.name].type == PSdata::FLOAT && val.type == PSdata::INT) 833 | { 834 | g_psVariables[var.id.name].floatVal = (float)val.intVal; 835 | return g_psVariables[var.id.name]; 836 | } 837 | else if(var.id.params.size() == 1) 838 | { 839 | PSdata index = _ps_evaluate_statement(ast, ast->nodePool[var.id.params[0]], addedFuncs, addedVars); 840 | if(index.type != PSdata::INT) 841 | _ps_error(PSruntimeError::INVALID_INDEX, var); 842 | 843 | PSdata* varRef = &g_psVariables[var.id.name]; 844 | float floatVal = _ps_get_scalar(val, PSruntimeError::INVALID_ASSIGNMENT, var); 845 | 846 | if(varRef->type == PSdata::VEC2 && index.intVal <= 1) 847 | *((float*)&varRef->vec2Val + index.intVal) = floatVal; 848 | else if(varRef->type == PSdata::VEC3 && index.intVal <= 2) 849 | *((float*)&varRef->vec3Val + index.intVal) = floatVal; 850 | else if(varRef->type == PSdata::VEC4 && index.intVal <= 3) 851 | *((float*)&varRef->vec4Val + index.intVal) = floatVal; 852 | else 853 | _ps_error(PSruntimeError::INVALID_INDEX, var); 854 | 855 | PSdata result; 856 | result.type = PSdata::FLOAT; 857 | result.floatVal = floatVal; 858 | return result; 859 | } 860 | else if(g_psVariables[var.id.name].type != val.type) 861 | _ps_error(PSruntimeError::INVALID_ASSIGNMENT, var); 862 | } 863 | else if(var.id.params.size() != 0) 864 | _ps_error(PSruntimeError::INVALID_INDEX, var); 865 | else 866 | addedVars.push_back(var.id.name); 867 | 868 | g_psVariables[var.id.name] = val; 869 | return val; 870 | } 871 | 872 | static inline PSdata _ps_lessthan(const PSdata& left, const PSdata& right, const PSnode& node) 873 | { 874 | PSdata result; 875 | result.type = PSdata::INT; 876 | 877 | result.intVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) < _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 878 | 879 | return result; 880 | } 881 | 882 | static inline PSdata _ps_greaterthan(const PSdata& left, const PSdata& right, const PSnode& node) 883 | { 884 | PSdata result; 885 | result.type = PSdata::INT; 886 | 887 | result.intVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) > _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 888 | 889 | return result; 890 | } 891 | 892 | static inline PSdata _ps_lessthanequal(const PSdata& left, const PSdata& right, const PSnode& node) 893 | { 894 | PSdata result; 895 | result.type = PSdata::INT; 896 | 897 | result.intVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) <= _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 898 | 899 | return result; 900 | } 901 | 902 | static inline PSdata _ps_greaterthanequal(const PSdata& left, const PSdata& right, const PSnode& node) 903 | { 904 | PSdata result; 905 | result.type = PSdata::INT; 906 | 907 | result.intVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) >= _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 908 | 909 | return result; 910 | } 911 | 912 | static inline PSdata _ps_equality(const PSdata& left, const PSdata& right, const PSnode& node) 913 | { 914 | PSdata result; 915 | result.type = PSdata::INT; 916 | 917 | if((left.type == PSdata::INT || left.type == PSdata::FLOAT) && (right.type == PSdata::INT || right.type == PSdata::FLOAT)) 918 | result.intVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) == _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 919 | else if(left.type == PSdata::VEC2 && right.type == PSdata::VEC2) 920 | result.intVal = left.vec2Val == right.vec2Val; 921 | else if(left.type == PSdata::VEC3 && right.type == PSdata::VEC3) 922 | result.intVal = left.vec3Val == right.vec3Val; 923 | else if(left.type == PSdata::VEC4 && right.type == PSdata::VEC4) 924 | result.intVal = left.vec4Val == right.vec4Val; 925 | else 926 | _ps_error(PSruntimeError::INVALID_OP, node); 927 | 928 | return result; 929 | } 930 | 931 | static inline PSdata _ps_and(const PSdata& left, const PSdata& right, const PSnode& node) 932 | { 933 | PSdata result; 934 | result.type = PSdata::INT; 935 | 936 | result.intVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) && _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 937 | 938 | return result; 939 | } 940 | 941 | static inline PSdata _ps_or (const PSdata& left, const PSdata& right, const PSnode& node) 942 | { 943 | PSdata result; 944 | result.type = PSdata::INT; 945 | 946 | result.intVal = _ps_get_scalar(left, PSruntimeError::INVALID_OP, node) || _ps_get_scalar(right, PSruntimeError::INVALID_OP, node); 947 | 948 | return result; 949 | } 950 | 951 | //--------------------------------------------------------------------------------------------------------------------------------// 952 | 953 | static PSdata _ps_range(const std::vector& params, const PSnode& node, void* userData) 954 | { 955 | if(params.size() != 2 || params[0].type != PSdata::INT || params[1].type != PSdata::INT) 956 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 957 | 958 | PSdata result; 959 | result.type = PSdata::VEC2; 960 | result.vec2Val = {(float)params[0].intVal, (float)params[1].intVal}; 961 | return result; 962 | } 963 | 964 | static PSdata _ps_print(const std::vector& params, const PSnode& node, void* userData) 965 | { 966 | for(int i = 0; i < params.size(); i++) 967 | { 968 | switch(params[i].type) 969 | { 970 | case PSdata::INT: 971 | std::cout << params[i].intVal; 972 | break; 973 | case PSdata::FLOAT: 974 | std::cout << params[i].floatVal; 975 | break; 976 | case PSdata::VEC2: 977 | std::cout << "(" << params[i].vec2Val.x << ", " << params[i].vec2Val.y << ")"; 978 | break; 979 | case PSdata::VEC3: 980 | std::cout << "(" << params[i].vec3Val.x << ", " << params[i].vec3Val.y << ", " << params[i].vec3Val.z << ")"; 981 | break; 982 | case PSdata::VEC4: 983 | std::cout << "(" << params[i].vec4Val.x << ", " << params[i].vec4Val.y << ", " << params[i].vec4Val.z << ", " << params[i].vec4Val.w << ")"; 984 | break; 985 | default: 986 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 987 | } 988 | 989 | if(i < params.size() - 1) 990 | std::cout << ", "; 991 | } 992 | 993 | std::cout << std::endl; 994 | 995 | return {}; 996 | } 997 | 998 | float _ps_scalar_rand(float min, float max) 999 | { 1000 | return (float)rand() / RAND_MAX * (max - min) + min; 1001 | } 1002 | 1003 | static PSdata _ps_rand(const std::vector& params, const PSnode& node, void* userData) 1004 | { 1005 | if(params.size() != 2) 1006 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1007 | 1008 | PSdata result; 1009 | 1010 | if(params[0].type == PSdata::VEC2 && params[1].type == PSdata::VEC2) 1011 | { 1012 | qm::vec2 min = params[0].vec2Val; 1013 | qm::vec2 max = params[1].vec2Val; 1014 | 1015 | result.type = PSdata::VEC2; 1016 | result.vec2Val.x = _ps_scalar_rand(min.x, max.x); 1017 | result.vec2Val.y = _ps_scalar_rand(min.y, max.y); 1018 | } 1019 | else if(params[0].type == PSdata::VEC3 && params[1].type == PSdata::VEC3) 1020 | { 1021 | qm::vec3 min = params[0].vec3Val; 1022 | qm::vec3 max = params[1].vec3Val; 1023 | 1024 | result.type = PSdata::VEC3; 1025 | result.vec3Val.x = _ps_scalar_rand(min.x, max.x); 1026 | result.vec3Val.y = _ps_scalar_rand(min.y, max.y); 1027 | result.vec3Val.z = _ps_scalar_rand(min.z, max.z); 1028 | } 1029 | else if(params[0].type == PSdata::VEC4 && params[1].type == PSdata::VEC4) 1030 | { 1031 | qm::vec4 min = params[0].vec4Val; 1032 | qm::vec4 max = params[1].vec4Val; 1033 | 1034 | result.type = PSdata::VEC4; 1035 | result.vec4Val.x = _ps_scalar_rand(min.x, max.x); 1036 | result.vec4Val.y = _ps_scalar_rand(min.y, max.y); 1037 | result.vec4Val.z = _ps_scalar_rand(min.z, max.z); 1038 | result.vec4Val.w = _ps_scalar_rand(min.w, max.w); 1039 | } 1040 | else if(params[0].type == PSdata::INT && params[1].type == PSdata::INT) 1041 | { 1042 | int min = params[0].intVal; 1043 | int max = params[1].intVal; 1044 | 1045 | result.type = PSdata::INT; 1046 | result.intVal = rand() % (max - min) + min; 1047 | } 1048 | else 1049 | { 1050 | float min = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1051 | float max = _ps_get_scalar(params[1], PSruntimeError::INVALID_PARAMS, node); 1052 | 1053 | result.type = PSdata::FLOAT; 1054 | result.floatVal = _ps_scalar_rand(min, max); 1055 | } 1056 | 1057 | return result; 1058 | } 1059 | 1060 | static PSdata _ps_int(const std::vector& params, const PSnode& node, void* userData) 1061 | { 1062 | if(params.size() != 1) 1063 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1064 | 1065 | PSdata result; 1066 | result.type = PSdata::INT; 1067 | result.intVal = (int)_ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1068 | 1069 | return result; 1070 | } 1071 | 1072 | static PSdata _ps_vec2(const std::vector& params, const PSnode& node, void* userData) 1073 | { 1074 | PSdata result; 1075 | result.type = PSdata::VEC2; 1076 | 1077 | switch(params.size()) 1078 | { 1079 | case 0: 1080 | { 1081 | result.vec2Val = {0.0f, 0.0f}; 1082 | break; 1083 | } 1084 | case 1: 1085 | { 1086 | float val = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1087 | result.vec2Val = {val, val}; 1088 | break; 1089 | } 1090 | case 2: 1091 | { 1092 | float x = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1093 | float y = _ps_get_scalar(params[1], PSruntimeError::INVALID_PARAMS, node); 1094 | result.vec2Val = {x, y}; 1095 | break; 1096 | } 1097 | default: 1098 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1099 | } 1100 | 1101 | return result; 1102 | } 1103 | 1104 | static PSdata _ps_vec3(const std::vector& params, const PSnode& node, void* userData) 1105 | { 1106 | PSdata result; 1107 | result.type = PSdata::VEC3; 1108 | 1109 | switch(params.size()) 1110 | { 1111 | case 0: 1112 | { 1113 | result.vec3Val = {0.0f, 0.0f, 0.0f}; 1114 | break; 1115 | } 1116 | case 1: 1117 | { 1118 | float val = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1119 | result.vec3Val = {val, val, val}; 1120 | break; 1121 | } 1122 | case 2: 1123 | { 1124 | if(params[0].type != PSdata::VEC2) 1125 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1126 | 1127 | qm::vec2 vecVal = params[0].vec2Val; 1128 | float val = _ps_get_scalar(params[1], PSruntimeError::INVALID_PARAMS, node); 1129 | result.vec3Val = {vecVal.x, vecVal.y, val}; 1130 | break; 1131 | } 1132 | case 3: 1133 | { 1134 | float x = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1135 | float y = _ps_get_scalar(params[1], PSruntimeError::INVALID_PARAMS, node); 1136 | float z = _ps_get_scalar(params[2], PSruntimeError::INVALID_PARAMS, node); 1137 | result.vec3Val = {x, y, z}; 1138 | break; 1139 | } 1140 | default: 1141 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1142 | } 1143 | 1144 | return result; 1145 | } 1146 | 1147 | static PSdata _ps_vec4(const std::vector& params, const PSnode& node, void* userData) 1148 | { 1149 | PSdata result; 1150 | result.type = PSdata::VEC4; 1151 | 1152 | switch(params.size()) 1153 | { 1154 | case 0: 1155 | { 1156 | result.vec4Val = {0.0f, 0.0f, 0.0f, 0.0f}; 1157 | break; 1158 | } 1159 | case 1: 1160 | { 1161 | float val = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1162 | result.vec4Val = {val, val, val, val}; 1163 | break; 1164 | } 1165 | case 2: 1166 | { 1167 | if(params[0].type != PSdata::VEC3) 1168 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1169 | 1170 | qm::vec3 vecVal = params[0].vec3Val; 1171 | float val = _ps_get_scalar(params[1], PSruntimeError::INVALID_PARAMS, node); 1172 | result.vec4Val = {vecVal.x, vecVal.y, vecVal.z, val}; 1173 | break; 1174 | } 1175 | case 3: 1176 | { 1177 | float x = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1178 | float y = _ps_get_scalar(params[1], PSruntimeError::INVALID_PARAMS, node); 1179 | float z = _ps_get_scalar(params[2], PSruntimeError::INVALID_PARAMS, node); 1180 | float w = _ps_get_scalar(params[3], PSruntimeError::INVALID_PARAMS, node); 1181 | result.vec4Val = {x, y, z, w}; 1182 | break; 1183 | } 1184 | default: 1185 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1186 | } 1187 | 1188 | return result; 1189 | } 1190 | 1191 | static PSdata _ps_quaternion(const std::vector& params, const PSnode& node, void* userData) 1192 | { 1193 | if(params.size() > 0 && params[0].type != PSdata::VEC3) 1194 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1195 | 1196 | PSdata result; 1197 | result.type = PSdata::QUATERNION; 1198 | 1199 | if(params.size() == 0) 1200 | { 1201 | result.quatVal = qm::quaternion_identity(); 1202 | } 1203 | else if(params.size() == 1) 1204 | { 1205 | qm::vec3 angles = params[0].vec3Val; 1206 | angles.x = qm::rad_to_deg(angles.x); 1207 | angles.y = qm::rad_to_deg(angles.y); 1208 | angles.z = qm::rad_to_deg(angles.z); 1209 | result.quatVal = qm::quaternion_from_euler(angles); 1210 | } 1211 | else if(params.size() == 2) 1212 | { 1213 | qm::vec3 axis = params[0].vec3Val; 1214 | float angle = _ps_get_scalar(params[1], PSruntimeError::INVALID_PARAMS, node); 1215 | angle = qm::rad_to_deg(angle); 1216 | result.quatVal = qm::quaternion_from_axis_angle(axis, angle); 1217 | } 1218 | else 1219 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1220 | 1221 | return result; 1222 | } 1223 | 1224 | static PSdata _ps_sqrt(const std::vector& params, const PSnode& node, void* userData) 1225 | { 1226 | if(params.size() != 1) 1227 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1228 | 1229 | float input = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1230 | 1231 | PSdata result; 1232 | result.type = PSdata::FLOAT; 1233 | result.floatVal = sqrtf(input); 1234 | 1235 | return result; 1236 | } 1237 | 1238 | static PSdata _ps_pow(const std::vector& params, const PSnode& node, void* userData) 1239 | { 1240 | if(params.size() != 2) 1241 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1242 | 1243 | float base = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1244 | float exp = _ps_get_scalar(params[1], PSruntimeError::INVALID_PARAMS, node); 1245 | 1246 | PSdata result; 1247 | result.type = PSdata::FLOAT; 1248 | result.floatVal = powf(base, exp); 1249 | 1250 | return result; 1251 | } 1252 | 1253 | static PSdata _ps_abs(const std::vector& params, const PSnode& node, void* userData) 1254 | { 1255 | if(params.size() != 1) 1256 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1257 | 1258 | PSdata result; 1259 | result.type = params[0].type; 1260 | 1261 | if(params[0].type == PSdata::INT) 1262 | result.intVal = abs(params[0].intVal); 1263 | else if(params[0].type == PSdata::FLOAT) 1264 | result.floatVal = fabsf(params[0].floatVal); 1265 | else if(params[0].type == PSdata::VEC2) 1266 | { 1267 | result.vec2Val.x = fabsf(params[0].vec2Val.x); 1268 | result.vec2Val.y = fabsf(params[0].vec2Val.y); 1269 | } 1270 | else if(params[0].type == PSdata::VEC3) 1271 | { 1272 | result.vec3Val.x = fabsf(params[0].vec3Val.x); 1273 | result.vec3Val.y = fabsf(params[0].vec3Val.y); 1274 | result.vec3Val.z = fabsf(params[0].vec3Val.z); 1275 | } 1276 | else if(params[0].type == PSdata::VEC4) 1277 | { 1278 | result.vec4Val.x = fabsf(params[0].vec4Val.x); 1279 | result.vec4Val.y = fabsf(params[0].vec4Val.y); 1280 | result.vec4Val.z = fabsf(params[0].vec4Val.z); 1281 | result.vec4Val.w = fabsf(params[0].vec4Val.w); 1282 | } 1283 | else 1284 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1285 | 1286 | return result; 1287 | } 1288 | 1289 | static PSdata _ps_sin(const std::vector& params, const PSnode& node, void* userData) 1290 | { 1291 | if(params.size() != 1) 1292 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1293 | 1294 | float input = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1295 | 1296 | PSdata result; 1297 | result.type = PSdata::FLOAT; 1298 | result.floatVal = sinf(input); 1299 | 1300 | return result; 1301 | } 1302 | 1303 | static PSdata _ps_cos(const std::vector& params, const PSnode& node, void* userData) 1304 | { 1305 | if(params.size() != 1) 1306 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1307 | 1308 | float input = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1309 | 1310 | PSdata result; 1311 | result.type = PSdata::FLOAT; 1312 | result.floatVal = cosf(input); 1313 | 1314 | return result; 1315 | } 1316 | 1317 | static PSdata _ps_tan(const std::vector& params, const PSnode& node, void* userData) 1318 | { 1319 | if(params.size() != 1) 1320 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1321 | 1322 | float input = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1323 | 1324 | PSdata result; 1325 | result.type = PSdata::FLOAT; 1326 | result.floatVal = tanf(input); 1327 | 1328 | return result; 1329 | } 1330 | 1331 | static PSdata _ps_asin(const std::vector& params, const PSnode& node, void* userData) 1332 | { 1333 | if(params.size() != 1) 1334 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1335 | 1336 | float input = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1337 | 1338 | PSdata result; 1339 | result.type = PSdata::FLOAT; 1340 | result.floatVal = asinf(input); 1341 | 1342 | return result; 1343 | } 1344 | 1345 | static PSdata _ps_acos(const std::vector& params, const PSnode& node, void* userData) 1346 | { 1347 | if(params.size() != 1) 1348 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1349 | 1350 | float input = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1351 | 1352 | PSdata result; 1353 | result.type = PSdata::FLOAT; 1354 | result.floatVal = acosf(input); 1355 | 1356 | return result; 1357 | } 1358 | 1359 | static PSdata _ps_atan(const std::vector& params, const PSnode& node, void* userData) 1360 | { 1361 | if(params.size() != 1) 1362 | _ps_error(PSruntimeError::INVALID_PARAMS, node); 1363 | 1364 | float input = _ps_get_scalar(params[0], PSruntimeError::INVALID_PARAMS, node); 1365 | 1366 | PSdata result; 1367 | result.type = PSdata::FLOAT; 1368 | result.floatVal = atanf(input); 1369 | 1370 | return result; 1371 | } -------------------------------------------------------------------------------- /src/lexer.cpp: -------------------------------------------------------------------------------- 1 | #include "propscript.hpp" 2 | 3 | #include 4 | #include 5 | 6 | //--------------------------------------------------------------------------------------------------------------------------------// 7 | 8 | //returns whether or not the given character exists in an operator at the given index 9 | bool is_op_char(char ch, size_t idx); 10 | //returns whether a given string is an operator 11 | bool is_op_str(std::string op); 12 | //adds an id token to the token list if idLen is not 0 13 | void try_add_id_token(std::string idString, size_t& idLen, uint32_t lineNum, std::vector& tokens); 14 | 15 | //--------------------------------------------------------------------------------------------------------------------------------// 16 | 17 | size_t g_maxOpLen; 18 | 19 | //--------------------------------------------------------------------------------------------------------------------------------// 20 | 21 | std::vector ps_lex_file(std::string path) 22 | { 23 | //GET MAX OPERATOR LEN: 24 | for(int i = 0; i < PS_LEXER_OPERATORS.size(); i++) 25 | if(PS_LEXER_OPERATORS[i].length() > g_maxOpLen) 26 | g_maxOpLen = PS_LEXER_OPERATORS[i].length(); 27 | 28 | //LEX: 29 | std::vector tokens; 30 | std::ifstream file(path); 31 | if(!file.is_open()) 32 | { 33 | std::cout << "PROPSCRIPT LEX ERROR: FAILED TO OPEN \"" << path << "\" FOR READING" << std::endl; 34 | return {}; 35 | } 36 | 37 | bool inComment = false; 38 | 39 | uint32_t curLine = 1; 40 | 41 | std::string idString(64, ' '); 42 | size_t idLen = 0; 43 | 44 | while(!file.eof()) 45 | { 46 | char curCh = file.get(); 47 | if(file.eof()) 48 | break; 49 | 50 | if(curCh == '\n') 51 | { 52 | try_add_id_token(idString, idLen, curLine, tokens); 53 | 54 | //remove duplicate newlines: 55 | if(tokens.size() > 1 && tokens[tokens.size() - 1].type != PStoken::NEWLINE) 56 | { 57 | PStoken newlineToken; 58 | newlineToken.type = PStoken::NEWLINE; 59 | newlineToken.lineNum = curLine; 60 | tokens.push_back(newlineToken); 61 | } 62 | 63 | inComment = false; 64 | curLine++; 65 | } 66 | else if(inComment) 67 | { 68 | continue; 69 | } 70 | else if(std::isspace(curCh)) 71 | { 72 | try_add_id_token(idString, idLen, curLine, tokens); 73 | } 74 | else if(is_op_char(curCh, 0)) 75 | { 76 | try_add_id_token(idString, idLen, curLine, tokens); 77 | 78 | std::string opString(g_maxOpLen, curCh); 79 | size_t opLen = 1; 80 | 81 | while(is_op_char(file.peek(), opLen)) 82 | { 83 | curCh = file.get(); 84 | opString[opLen++] = curCh; 85 | } 86 | 87 | while(!is_op_str(opString.substr(0, opLen))) 88 | { 89 | opLen--; 90 | file.unget(); 91 | } 92 | 93 | opString = opString.substr(0, opLen); 94 | 95 | if(opString == PS_COMMENT) 96 | inComment = true; 97 | else if(opLen > 0) 98 | { 99 | PStoken opToken; 100 | opToken.type = PStoken::OP; 101 | opToken.str = opString; 102 | opToken.lineNum = curLine; 103 | tokens.push_back(opToken); 104 | } 105 | } 106 | else 107 | { 108 | idString[idLen++] = curCh; 109 | if(idLen >= idString.length()) 110 | idString.resize(idString.length() * 2); 111 | } 112 | } 113 | 114 | try_add_id_token(idString, idLen, curLine, tokens); 115 | 116 | //make sure tokens end with newline: 117 | if(tokens[tokens.size() - 1].type != PStoken::NEWLINE) 118 | { 119 | PStoken newlineToken; 120 | newlineToken.type = PStoken::NEWLINE; 121 | newlineToken.lineNum = curLine; 122 | tokens.push_back(newlineToken); 123 | } 124 | 125 | file.close(); 126 | return tokens; 127 | } 128 | 129 | //--------------------------------------------------------------------------------------------------------------------------------// 130 | 131 | bool is_op_char(char ch, size_t idx) 132 | { 133 | for(int i = 0; i < PS_LEXER_OPERATORS.size(); i++) 134 | if(PS_LEXER_OPERATORS[i][idx] == ch) 135 | return true; 136 | 137 | return false; 138 | } 139 | 140 | bool is_op_str(std::string str) 141 | { 142 | for(int i = 0; i < PS_LEXER_OPERATORS.size(); i++) 143 | if(PS_LEXER_OPERATORS[i] == str) 144 | return true; 145 | 146 | return false; 147 | } 148 | 149 | void try_add_id_token(std::string idString, size_t& idLen, uint32_t lineNum, std::vector& tokens) 150 | { 151 | if(idLen <= 0) 152 | return; 153 | 154 | PStoken idToken; 155 | idToken.type = PStoken::ID; 156 | 157 | idString = idString.substr(0, idLen); 158 | if(idString == PS_KEYWORD_AND || idString == PS_KEYWORD_OR || idString == PS_KEYWORD_IN) 159 | idToken.type = PStoken::OP; 160 | 161 | idToken.str = idString; 162 | idToken.lineNum = lineNum; 163 | tokens.push_back(idToken); 164 | idLen = 0; 165 | } -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "propscript.hpp" 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector tokens = ps_lex_file("examples/example.ps"); 8 | 9 | PSast* ast = ps_parse_tokens(tokens); 10 | if(!ast) 11 | return -1; 12 | 13 | ps_execute(ast); 14 | 15 | ps_save_ast("examples/example.psobj", ast); 16 | ps_free_ast(ast); 17 | 18 | return 0; 19 | } -------------------------------------------------------------------------------- /src/parser.cpp: -------------------------------------------------------------------------------- 1 | #include "propscript.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | //--------------------------------------------------------------------------------------------------------------------------------// 9 | 10 | enum class PSparseError 11 | { 12 | EXPECTED_CLOSING_PAREN, 13 | UNEXPECTED_OPERATOR, 14 | EXPECTED_OPERATOR, 15 | INVALID_TOKEN, 16 | EXPECTED_OPENING_CURLY 17 | }; 18 | 19 | //parses a single statement 20 | static PSnodeHandle _ps_parse_statement(PSast* ast, const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens); 21 | 22 | //parses any token that is not an operator or control flow (statement in parens, variable, function, literal) 23 | static PSnodeHandle _ps_parse_non_op(PSast* ast, const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens); 24 | //parses a statement that is in parenthesis 25 | static PSnodeHandle _ps_parse_statement_in_parens(PSast* ast, const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens); 26 | //parses an identifier (variable, function, literal) 27 | static PSnodeHandle _ps_parse_id(PSast* ast, const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens); 28 | //returns the node for a given operator 29 | static PSnode _ps_get_op_node(PSast* ast, const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens); 30 | 31 | //adds a node to the ast 32 | static inline PSnodeHandle _ps_add_node(PSast* ast, PSnode node); 33 | //removes a newline from the token list if there are unclosed parenthesis 34 | static inline void _ps_continue_statement(const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens); 35 | //removes a newline from the token list 36 | static inline void _ps_remove_newline(const std::vector& tokens, uint32_t& curTokenIdx); 37 | //returns the operator precedence of a given operator 38 | static inline int _ps_precedence(PSnode::OP::Type op); 39 | //throws an exception if the given token is not an identifier 40 | static inline void _ps_force_id(PStoken token); 41 | //throws an exception and sets the global error variables 42 | static void _ps_error(PSparseError error, PStoken errorToken); 43 | 44 | //--------------------------------------------------------------------------------------------------------------------------------// 45 | 46 | static PSparseError g_psError; 47 | static PStoken g_psErrorToken; 48 | 49 | const std::unordered_map PS_STRING_TO_OP_TYPE = { 50 | {PS_KEYWORD_IN , PSnode::OP::Type::IN}, 51 | {PS_OP_MULT , PSnode::OP::Type::MULT}, 52 | {PS_OP_DIV , PSnode::OP::Type::DIV}, 53 | {PS_OP_MOD , PSnode::OP::Type::MOD}, 54 | {PS_OP_ADD , PSnode::OP::Type::ADD}, 55 | {PS_OP_SUB , PSnode::OP::Type::SUB}, 56 | {PS_OP_EQUAL , PSnode::OP::Type::EQUAL}, 57 | {PS_OP_MULTEQUAL , PSnode::OP::Type::MULTEQUAL}, 58 | {PS_OP_DIVEQUAL , PSnode::OP::Type::DIVEQUAL}, 59 | {PS_OP_MODEQUAL , PSnode::OP::Type::MODEQUAL}, 60 | {PS_OP_ADDEQUAL , PSnode::OP::Type::ADDEQUAL}, 61 | {PS_OP_SUBEQUAL , PSnode::OP::Type::SUBEQUAL}, 62 | {PS_OP_LESSTHAN , PSnode::OP::Type::LESSTHAN}, 63 | {PS_OP_GREATERTHAN , PSnode::OP::Type::GREATERTHAN}, 64 | {PS_OP_LESSTHANEQUAL , PSnode::OP::Type::LESSTHANEQUAL}, 65 | {PS_OP_GREATERTHANEQUAL, PSnode::OP::Type::GREATERTHANEQUAL}, 66 | {PS_OP_EQUALITY , PSnode::OP::Type::EQUALITY}, 67 | {PS_OP_NONEQUALITY , PSnode::OP::Type::NONEQUALITY}, 68 | }; 69 | 70 | //--------------------------------------------------------------------------------------------------------------------------------// 71 | 72 | PSast* ps_parse_tokens(const std::vector& tokens) 73 | { 74 | PSast* result = new PSast; 75 | 76 | try 77 | { 78 | uint32_t curTokenIdx = 0; 79 | uint32_t numOpenParens = 0; 80 | 81 | while(curTokenIdx < tokens.size()) 82 | { 83 | result->parentNodes.push_back(_ps_parse_statement(result, tokens, curTokenIdx, numOpenParens)); 84 | _ps_remove_newline(tokens, curTokenIdx); 85 | } 86 | } 87 | catch(std::exception e) 88 | { 89 | std::string errMsg; 90 | switch(g_psError) 91 | { 92 | case PSparseError::EXPECTED_CLOSING_PAREN: 93 | errMsg = "EXPECTED CLOSING PARENTHESIS"; 94 | break; 95 | case PSparseError::UNEXPECTED_OPERATOR: 96 | errMsg = "UNEXPECTED OPERATOR \"" + g_psErrorToken.str + "\""; 97 | break; 98 | case PSparseError::EXPECTED_OPERATOR: 99 | errMsg = "EXPECTED OPERATOR"; 100 | break; 101 | case PSparseError::INVALID_TOKEN: 102 | errMsg = "INVALID TOKEN \"" + g_psErrorToken.str + "\""; 103 | break; 104 | case PSparseError::EXPECTED_OPENING_CURLY: 105 | errMsg = "EXPECTED OPENING CURLY BRACE"; 106 | break; 107 | } 108 | 109 | std::cout << "PROPSCRIPT PARSE ERROR: " << errMsg << " ON LINE " << g_psErrorToken.lineNum << std::endl; 110 | delete result; 111 | return nullptr; 112 | } 113 | 114 | return result; 115 | } 116 | 117 | void ps_free_ast(PSast* ast) 118 | { 119 | delete ast; 120 | } 121 | 122 | void ps_save_ast(std::string path, PSast* ast) 123 | { 124 | std::ofstream file(path, std::ios_base::binary); 125 | if(!file.is_open()) 126 | { 127 | std::cout << "ERROR OPENING FILE \"" << path << "\" FOR WRITING" << std::endl; 128 | return; 129 | } 130 | 131 | ps_save_ast(file, ast); 132 | 133 | file.close(); 134 | } 135 | 136 | void ps_save_ast(std::ofstream& file, PSast* ast) 137 | { 138 | size_t parentNodeSize = ast->parentNodes.size(); 139 | size_t nodePoolSize = ast->nodePool.size(); 140 | 141 | file.write((const char*)&parentNodeSize, sizeof(size_t)); 142 | file.write((const char*)ast->parentNodes.data(), sizeof(PSnodeHandle) * parentNodeSize); 143 | 144 | file.write((const char*)&nodePoolSize, sizeof(size_t)); 145 | for(int i = 0; i < nodePoolSize; i++) 146 | { 147 | PSnode& node = ast->nodePool[i]; 148 | file.write((const char*)&node.type, sizeof(PSnode::Type)); 149 | file.write((const char*)&node.lineNum, sizeof(uint32_t)); 150 | 151 | switch(node.type) 152 | { 153 | case PSnode::Type::OP: 154 | { 155 | file.write((const char*)&node.op, sizeof(PSnode::OP)); 156 | file.write((const char*)&node.op.left, sizeof(PSnodeHandle)); 157 | file.write((const char*)&node.op.right, sizeof(PSnodeHandle)); 158 | break; 159 | } 160 | case PSnode::Type::KEYWORD: 161 | { 162 | file.write((const char*)&node.keyword.type, sizeof(PSnode::Keyword::Type)); 163 | 164 | size_t codeSize = node.keyword.code.size(); 165 | size_t elseCodeSize = node.keyword.elseCode.size(); 166 | size_t paramNameSize = node.keyword.paramNames.size(); 167 | 168 | file.write((const char*)&codeSize, sizeof(size_t)); 169 | file.write((const char*)node.keyword.code.data(), sizeof(PSnodeHandle) * codeSize); 170 | 171 | file.write((const char*)&node.keyword.condition, sizeof(PSnodeHandle)); 172 | 173 | file.write((const char*)&node.keyword.hasElse, sizeof(bool)); 174 | file.write((const char*)&elseCodeSize, sizeof(size_t)); 175 | file.write((const char*)node.keyword.elseCode.data(), sizeof(PSnodeHandle) * elseCodeSize); 176 | 177 | size_t nameLen = node.keyword.name.length(); 178 | file.write((const char*)&nameLen, sizeof(size_t)); 179 | file.write((const char*)node.keyword.name.data(), sizeof(char) * nameLen); 180 | file.write((const char*)¶mNameSize, sizeof(size_t)); 181 | for(int j = 0; j < paramNameSize; j++) 182 | { 183 | size_t paramNameLen = node.keyword.paramNames[j].length(); 184 | file.write((const char*)¶mNameLen, sizeof(size_t)); 185 | file.write((const char*)node.keyword.paramNames[j].data(), sizeof(char) * paramNameLen); 186 | } 187 | 188 | file.write((const char*)&node.keyword.returnVal, sizeof(PSnodeHandle)); 189 | 190 | break; 191 | } 192 | case PSnode::ID: 193 | { 194 | file.write((const char*)&node.id.type, sizeof(PSnode::ID::Type)); 195 | 196 | size_t nameLen = node.id.name.length(); 197 | file.write((const char*)&nameLen, sizeof(size_t)); 198 | file.write((const char*)node.id.name.data(), sizeof(char) * nameLen); 199 | 200 | size_t paramSize = node.id.params.size(); 201 | file.write((const char*)¶mSize, sizeof(size_t)); 202 | file.write((const char*)node.id.params.data(), sizeof(PSnodeHandle) * paramSize); 203 | 204 | break; 205 | } 206 | case PSnode::NUMBER: 207 | { 208 | file.write((const char*)&node.literal.type, sizeof(PSnode::Literal::Type)); 209 | file.write((const char*)&node.literal.intNum, sizeof(int32_t)); 210 | file.write((const char*)&node.literal.floatNum, sizeof(float)); 211 | 212 | break; 213 | } 214 | } 215 | } 216 | } 217 | 218 | PSast* ps_load_ast(std::string path) 219 | { 220 | std::ifstream file(path, std::ios_base::binary); 221 | if(!file.is_open()) 222 | { 223 | std::cout << "ERROR OPENING FILE \"" << path << "\" FOR READING" << std::endl; 224 | return nullptr; 225 | } 226 | 227 | PSast* result = ps_load_ast(file); 228 | 229 | file.close(); 230 | return result; 231 | } 232 | 233 | PSast* ps_load_ast(std::ifstream& file) 234 | { 235 | PSast* result = new PSast; 236 | 237 | size_t parentNodeSize; 238 | size_t nodePoolSize; 239 | 240 | file.read((char*)&parentNodeSize, sizeof(size_t)); 241 | result->parentNodes.resize(parentNodeSize); 242 | file.read((char*)result->parentNodes.data(), sizeof(PSnodeHandle) * parentNodeSize); 243 | 244 | file.read((char*)&nodePoolSize, sizeof(size_t)); 245 | for(int i = 0; i < nodePoolSize; i++) 246 | { 247 | PSnode node; 248 | file.read((char*)&node.type, sizeof(PSnode::Type)); 249 | file.read((char*)&node.lineNum, sizeof(uint32_t)); 250 | 251 | switch(node.type) 252 | { 253 | case PSnode::Type::OP: 254 | { 255 | file.read((char*)&node.op, sizeof(PSnode::OP)); 256 | file.read((char*)&node.op.left, sizeof(PSnodeHandle)); 257 | file.read((char*)&node.op.right, sizeof(PSnodeHandle)); 258 | break; 259 | } 260 | case PSnode::Type::KEYWORD: 261 | { 262 | file.read((char*)&node.keyword.type, sizeof(PSnode::Keyword::Type)); 263 | 264 | size_t codeSize; 265 | size_t elseCodeSize; 266 | size_t paramNameSize; 267 | 268 | file.read((char*)&codeSize, sizeof(size_t)); 269 | node.keyword.code.resize(codeSize); 270 | file.read((char*)node.keyword.code.data(), sizeof(PSnodeHandle) * codeSize); 271 | 272 | file.read((char*)&node.keyword.condition, sizeof(PSnodeHandle)); 273 | 274 | file.read((char*)&node.keyword.hasElse, sizeof(bool)); 275 | file.read((char*)&elseCodeSize, sizeof(size_t)); 276 | node.keyword.elseCode.resize(elseCodeSize); 277 | file.read((char*)node.keyword.elseCode.data(), sizeof(PSnodeHandle) * elseCodeSize); 278 | 279 | size_t nameLen; 280 | file.read((char*)&nameLen, sizeof(size_t)); 281 | node.keyword.name.resize(nameLen); 282 | file.read(node.keyword.name.data(), sizeof(char) * nameLen); 283 | file.read((char*)¶mNameSize, sizeof(size_t)); 284 | node.keyword.paramNames.resize(paramNameSize); 285 | for(int j = 0; j < paramNameSize; j++) 286 | { 287 | size_t paramNameLen; 288 | file.read((char*)¶mNameLen, sizeof(size_t)); 289 | node.keyword.paramNames[j].resize(paramNameLen); 290 | file.read(node.keyword.paramNames[j].data(), sizeof(char) * paramNameLen); 291 | } 292 | 293 | file.read((char*)&node.keyword.returnVal, sizeof(PSnodeHandle)); 294 | 295 | break; 296 | } 297 | case PSnode::ID: 298 | { 299 | file.read((char*)&node.id.type, sizeof(PSnode::ID::Type)); 300 | 301 | size_t nameLen; 302 | file.read((char*)&nameLen, sizeof(size_t)); 303 | node.id.name.resize(nameLen); 304 | file.read(node.id.name.data(), sizeof(char) * nameLen); 305 | 306 | size_t paramSize; 307 | file.read((char*)¶mSize, sizeof(size_t)); 308 | node.id.params.resize(paramSize); 309 | file.read((char*)node.id.params.data(), sizeof(PSnodeHandle) * paramSize); 310 | 311 | break; 312 | } 313 | case PSnode::NUMBER: 314 | { 315 | file.read((char*)&node.literal.type, sizeof(PSnode::Literal::Type)); 316 | file.read((char*)&node.literal.intNum, sizeof(int32_t)); 317 | file.read((char*)&node.literal.floatNum, sizeof(float)); 318 | 319 | break; 320 | } 321 | } 322 | 323 | result->nodePool.push_back(node); 324 | } 325 | 326 | return result; 327 | } 328 | 329 | //--------------------------------------------------------------------------------------------------------------------------------// 330 | 331 | static PSnodeHandle _ps_parse_statement(PSast* ast, const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens) 332 | { 333 | //CHECK IF CONTROL FLOW STATEMENT: 334 | if(tokens[curTokenIdx].str == PS_KEYWORD_IF || tokens[curTokenIdx].str == PS_KEYWORD_FOR) 335 | { 336 | bool isFor = tokens[curTokenIdx].str == PS_KEYWORD_FOR; 337 | 338 | if(numOpenParens > 0) 339 | _ps_error(PSparseError::INVALID_TOKEN, tokens[curTokenIdx]); 340 | 341 | PSnode controlNode; 342 | controlNode.type = PSnode::KEYWORD; 343 | controlNode.lineNum = tokens[curTokenIdx].lineNum; 344 | controlNode.keyword.type = isFor ? PSnode::Keyword::FOR : PSnode::Keyword::IF; 345 | 346 | //GET CONDITION: 347 | controlNode.keyword.condition = _ps_parse_statement(ast, tokens, ++curTokenIdx, numOpenParens); 348 | _ps_remove_newline(tokens, curTokenIdx); 349 | 350 | //GET CODE: 351 | if(tokens[curTokenIdx].str == PS_SEPERATOR_CURLY_OPEN) //multi-line 352 | { 353 | curTokenIdx++; 354 | _ps_remove_newline(tokens, curTokenIdx); 355 | 356 | while(tokens[curTokenIdx].str != PS_SEPERATOR_CURLY_CLOSE) 357 | { 358 | controlNode.keyword.code.push_back(_ps_parse_statement(ast, tokens, curTokenIdx, numOpenParens)); 359 | _ps_remove_newline(tokens, curTokenIdx); 360 | } 361 | 362 | curTokenIdx++; 363 | } 364 | else //single-line 365 | controlNode.keyword.code.push_back(_ps_parse_statement(ast, tokens, curTokenIdx, numOpenParens)); 366 | 367 | //IF FOR LOOP, NO ELSE STATEMENT POSSIBLE SO JUST RETURN 368 | if(isFor) 369 | return _ps_add_node(ast, controlNode); 370 | 371 | //CHECK FOR ELSE: 372 | _ps_remove_newline(tokens, curTokenIdx); 373 | 374 | if(tokens[curTokenIdx].str == PS_KEYWORD_ELSE) 375 | { 376 | controlNode.keyword.hasElse = true; 377 | 378 | curTokenIdx++; 379 | _ps_remove_newline(tokens, curTokenIdx); 380 | if(tokens[curTokenIdx].str == PS_SEPERATOR_CURLY_OPEN) //multi-line 381 | { 382 | curTokenIdx++; 383 | _ps_remove_newline(tokens, curTokenIdx); 384 | 385 | while(tokens[curTokenIdx].str != PS_SEPERATOR_CURLY_CLOSE) 386 | { 387 | controlNode.keyword.elseCode.push_back(_ps_parse_statement(ast, tokens, curTokenIdx, numOpenParens)); 388 | _ps_remove_newline(tokens, curTokenIdx); 389 | } 390 | 391 | curTokenIdx++; 392 | } 393 | else //single-line / else-if 394 | controlNode.keyword.elseCode.push_back(_ps_parse_statement(ast, tokens, curTokenIdx, numOpenParens)); 395 | } 396 | else 397 | controlNode.keyword.hasElse = false; 398 | 399 | return _ps_add_node(ast, controlNode); 400 | } 401 | 402 | //CHECK IF FUNCTION DEFINITION: 403 | if(tokens[curTokenIdx].str == PS_KEYWORD_FUNC) 404 | { 405 | PSnode funcNode; 406 | funcNode.type = PSnode::KEYWORD; 407 | funcNode.lineNum = tokens[curTokenIdx].lineNum; 408 | funcNode.keyword.type = PSnode::Keyword::FUNC; 409 | 410 | curTokenIdx++; 411 | _ps_remove_newline(tokens, curTokenIdx); 412 | 413 | _ps_force_id(tokens[curTokenIdx]); 414 | 415 | funcNode.keyword.name = tokens[curTokenIdx].str; 416 | curTokenIdx++; 417 | _ps_remove_newline(tokens, curTokenIdx); 418 | 419 | if(tokens[curTokenIdx].str == PS_SEPERATOR_PAREN_OPEN) //has parameters 420 | { 421 | curTokenIdx++; 422 | numOpenParens++; 423 | _ps_continue_statement(tokens, curTokenIdx, numOpenParens); 424 | 425 | //argument names: 426 | while(true) 427 | { 428 | _ps_force_id(tokens[curTokenIdx]); 429 | funcNode.keyword.paramNames.push_back(tokens[curTokenIdx].str); 430 | curTokenIdx++; 431 | 432 | if(tokens[curTokenIdx].str == PS_SEPERATOR_PAREN_CLOSE) 433 | break; 434 | else if(tokens[curTokenIdx].str != PS_SEPERATOR_COMMA) 435 | _ps_error(PSparseError::EXPECTED_OPERATOR, tokens[curTokenIdx]); 436 | 437 | curTokenIdx++; 438 | _ps_continue_statement(tokens, curTokenIdx, numOpenParens); 439 | } 440 | 441 | curTokenIdx++; 442 | numOpenParens--; 443 | } 444 | 445 | _ps_remove_newline(tokens, curTokenIdx); 446 | 447 | //GET CODE: 448 | if(tokens[curTokenIdx].str != PS_SEPERATOR_CURLY_OPEN) //ensure open curly brace found 449 | _ps_error(PSparseError::EXPECTED_OPENING_CURLY, tokens[curTokenIdx]); 450 | 451 | curTokenIdx++; 452 | _ps_remove_newline(tokens, curTokenIdx); 453 | 454 | while(tokens[curTokenIdx].str != PS_SEPERATOR_CURLY_CLOSE) 455 | { 456 | funcNode.keyword.code.push_back(_ps_parse_statement(ast, tokens, curTokenIdx, numOpenParens)); 457 | _ps_remove_newline(tokens, curTokenIdx); 458 | } 459 | 460 | curTokenIdx++; 461 | 462 | return _ps_add_node(ast, funcNode); 463 | } 464 | 465 | //CHECK IF RETURN STATEMENT: 466 | if(tokens[curTokenIdx].str == PS_KEYWORD_RETURN) 467 | { 468 | PSnode returnNode; 469 | returnNode.type = PSnode::KEYWORD; 470 | returnNode.lineNum = tokens[curTokenIdx].lineNum; 471 | returnNode.keyword.type = PSnode::Keyword::RETURN; 472 | 473 | curTokenIdx++; 474 | if(tokens[curTokenIdx].type != PStoken::NEWLINE && 475 | std::find(PS_CLOSED_SEPERATORS.begin(), PS_CLOSED_SEPERATORS.end(), tokens[curTokenIdx].str) == PS_CLOSED_SEPERATORS.end()) //get return value if not a void return 476 | returnNode.keyword.returnVal = _ps_parse_statement(ast, tokens, curTokenIdx, numOpenParens); 477 | else 478 | returnNode.keyword.returnVal = UINT32_MAX; 479 | 480 | return _ps_add_node(ast, returnNode); 481 | } 482 | 483 | //CHECK IF BREAK/CONTINUE STATEMENT: 484 | if(tokens[curTokenIdx].str == PS_KEYWORD_BREAK || tokens[curTokenIdx].str == PS_KEYWORD_CONTINUE) 485 | { 486 | PSnode breakNode; 487 | breakNode.type = PSnode::KEYWORD; 488 | breakNode.lineNum = tokens[curTokenIdx].lineNum; 489 | breakNode.keyword.type = tokens[curTokenIdx].str == PS_KEYWORD_BREAK ? PSnode::Keyword::BREAK : PSnode::Keyword::CONTINUE; 490 | 491 | curTokenIdx++; 492 | if(tokens[curTokenIdx].type != PStoken::NEWLINE && 493 | std::find(PS_CLOSED_SEPERATORS.begin(), PS_CLOSED_SEPERATORS.end(), tokens[curTokenIdx].str) == PS_CLOSED_SEPERATORS.end()) //get return value if not a void return 494 | _ps_error(PSparseError::INVALID_TOKEN, tokens[curTokenIdx]); 495 | 496 | return _ps_add_node(ast, breakNode); 497 | } 498 | 499 | //MUST BE REGULAR OPERATION: 500 | PSnodeHandle left; 501 | PSnodeHandle right; 502 | 503 | //GET LEFT TOKEN: 504 | left = _ps_parse_non_op(ast, tokens, curTokenIdx, numOpenParens); 505 | 506 | //CHECK IF LINE ENDED: 507 | if(tokens[curTokenIdx].type == PStoken::NEWLINE || tokens[curTokenIdx].str == PS_SEPERATOR_CURLY_OPEN || 508 | std::find(PS_CLOSED_SEPERATORS.begin(), PS_CLOSED_SEPERATORS.end(), tokens[curTokenIdx].str) != PS_CLOSED_SEPERATORS.end()) 509 | return left; 510 | 511 | //GET OP TOKEN: 512 | PSnode opNode = _ps_get_op_node(ast, tokens, curTokenIdx, numOpenParens); 513 | 514 | //GET RIGHT TOKEN: 515 | right = _ps_parse_non_op(ast, tokens, curTokenIdx, numOpenParens); 516 | 517 | //CONSTRUCT OP NODE: 518 | opNode.op.inParens = false; 519 | opNode.op.left = left; 520 | opNode.op.right = right; 521 | 522 | //ITERATE TO GET REST OF NODES: 523 | while(curTokenIdx < tokens.size() && tokens[curTokenIdx].type != PStoken::NEWLINE && tokens[curTokenIdx].str != PS_SEPERATOR_CURLY_OPEN && 524 | std::find(PS_CLOSED_SEPERATORS.begin(), PS_CLOSED_SEPERATORS.end(), tokens[curTokenIdx].str) == PS_CLOSED_SEPERATORS.end()) 525 | { 526 | PSnode newOp = _ps_get_op_node(ast, tokens, curTokenIdx, numOpenParens); 527 | 528 | right = _ps_parse_non_op(ast, tokens, curTokenIdx, numOpenParens); 529 | 530 | //ADD TO EXISTING NODES WITH CORRECT ORDER OF OPERATIONS: 531 | if(_ps_precedence(newOp.op.type) >= _ps_precedence(opNode.op.type)) 532 | { 533 | newOp.op.left = _ps_add_node(ast, opNode); 534 | newOp.op.right = right; 535 | opNode = newOp; 536 | } 537 | else 538 | { 539 | //find rightmost op with lesser order: 540 | PSnode* rightMost = &opNode; 541 | PSnode rightModeRight = ast->nodePool[rightMost->op.right]; 542 | while(rightModeRight.type == PSnode::OP && 543 | _ps_precedence(newOp.op.type) < _ps_precedence(rightModeRight.op.type) && 544 | !rightModeRight.op.inParens) 545 | { 546 | rightMost = &ast->nodePool[rightMost->op.right]; 547 | rightModeRight = ast->nodePool[rightMost->op.right]; 548 | } 549 | 550 | newOp.op.left = rightMost->op.right; 551 | newOp.op.right = right; 552 | rightMost->op.right = _ps_add_node(ast, newOp); 553 | } 554 | } 555 | 556 | return _ps_add_node(ast, opNode); 557 | } 558 | 559 | //--------------------------------------------------------------------------------------------------------------------------------// 560 | 561 | static PSnodeHandle _ps_parse_non_op(PSast* ast, const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens) 562 | { 563 | PSnodeHandle node; 564 | 565 | if(tokens[curTokenIdx].str == PS_SEPERATOR_PAREN_OPEN) 566 | node = _ps_parse_statement_in_parens(ast, tokens, curTokenIdx, numOpenParens); 567 | else 568 | node = _ps_parse_id(ast, tokens, curTokenIdx, numOpenParens); 569 | 570 | _ps_continue_statement(tokens, curTokenIdx, numOpenParens); 571 | return node; 572 | } 573 | 574 | static PSnodeHandle _ps_parse_statement_in_parens(PSast* ast, const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens) 575 | { 576 | PSnodeHandle node = _ps_parse_statement(ast, tokens, ++curTokenIdx, ++numOpenParens); 577 | if(tokens[curTokenIdx].str != PS_SEPERATOR_PAREN_CLOSE) 578 | _ps_error(PSparseError::EXPECTED_CLOSING_PAREN, tokens[curTokenIdx]); 579 | 580 | ast->nodePool[node].op.inParens = true; 581 | 582 | numOpenParens--; 583 | curTokenIdx++; 584 | return node; 585 | } 586 | 587 | static PSnodeHandle _ps_parse_id(PSast* ast, const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens) 588 | { 589 | bool negative = false; 590 | if(tokens[curTokenIdx].str == PS_OP_SUB) 591 | { 592 | negative = true; 593 | curTokenIdx++; 594 | } 595 | 596 | _ps_force_id(tokens[curTokenIdx]); 597 | 598 | //FUNCTION: 599 | if(tokens[curTokenIdx + 1].str == PS_SEPERATOR_PAREN_OPEN) 600 | { 601 | PSnode funcNode; 602 | funcNode.type = PSnode::ID; 603 | funcNode.lineNum = tokens[curTokenIdx].lineNum; 604 | funcNode.id.type = PSnode::ID::FUNC; 605 | funcNode.id.name = tokens[curTokenIdx].str; 606 | 607 | curTokenIdx += 2; 608 | numOpenParens++; 609 | _ps_continue_statement(tokens, curTokenIdx, numOpenParens); 610 | 611 | //0 argument function: 612 | if(tokens[curTokenIdx].str == PS_SEPERATOR_PAREN_CLOSE) 613 | { 614 | curTokenIdx++; 615 | numOpenParens--; 616 | return _ps_add_node(ast, funcNode); 617 | } 618 | 619 | //arguments: 620 | while(true) 621 | { 622 | funcNode.id.params.push_back(_ps_parse_statement(ast, tokens, curTokenIdx, numOpenParens)); 623 | 624 | if(tokens[curTokenIdx].str == PS_SEPERATOR_PAREN_CLOSE) 625 | break; 626 | else if(tokens[curTokenIdx].str != PS_SEPERATOR_COMMA) 627 | _ps_error(PSparseError::EXPECTED_OPERATOR, tokens[curTokenIdx]); 628 | 629 | curTokenIdx++; 630 | _ps_continue_statement(tokens, curTokenIdx, numOpenParens); 631 | } 632 | 633 | curTokenIdx++; 634 | numOpenParens--; 635 | 636 | if(negative) 637 | { 638 | PSnode minusNode; 639 | minusNode.type = PSnode::OP; 640 | minusNode.lineNum = tokens[curTokenIdx].lineNum; 641 | minusNode.op.type = PSnode::OP::SUB; 642 | 643 | PSnode negOne; 644 | negOne.type = PSnode::NUMBER; 645 | negOne.lineNum = tokens[curTokenIdx].lineNum; 646 | negOne.literal.type = PSnode::Literal::INT; 647 | negOne.literal.intNum = -1; 648 | 649 | minusNode.op.left = _ps_add_node(ast, negOne); 650 | minusNode.op.right = _ps_add_node(ast, funcNode); 651 | return _ps_add_node(ast, minusNode); 652 | } 653 | else 654 | return _ps_add_node(ast, funcNode); 655 | } 656 | 657 | PStoken token = tokens[curTokenIdx++]; 658 | 659 | //NUMBER: 660 | if(std::isdigit(token.str[0]) || token.str[0] == '.') 661 | { 662 | bool isFloat = false; 663 | for(int i = 0; i < token.str.length(); i++) 664 | { 665 | if(token.str[i] == '.') 666 | { 667 | if(isFloat) 668 | _ps_error(PSparseError::INVALID_TOKEN, tokens[curTokenIdx]); 669 | else 670 | isFloat = true; 671 | } 672 | else if(!std::isdigit(token.str[i])) 673 | _ps_error(PSparseError::INVALID_TOKEN, tokens[curTokenIdx]); 674 | } 675 | 676 | PSnode numNode; 677 | numNode.type = PSnode::NUMBER; 678 | numNode.lineNum = tokens[curTokenIdx - 1].lineNum; 679 | 680 | if(isFloat) 681 | { 682 | numNode.literal.type = PSnode::Literal::FLOAT; 683 | numNode.literal.floatNum = std::stof(token.str); 684 | if(negative) 685 | numNode.literal.floatNum *= -1.0f; 686 | } 687 | else 688 | { 689 | numNode.literal.type = PSnode::Literal::INT; 690 | numNode.literal.intNum = std::stoi(token.str); 691 | if(negative) 692 | numNode.literal.intNum *= -1; 693 | } 694 | 695 | return _ps_add_node(ast, numNode); 696 | } 697 | 698 | //VARIABLE: 699 | PSnode varNode; 700 | varNode.type = PSnode::ID; 701 | varNode.lineNum = tokens[curTokenIdx].lineNum; 702 | varNode.id.type = PSnode::ID::VAR; 703 | varNode.id.name = token.str; 704 | 705 | //index into variable: 706 | if(tokens[curTokenIdx].str == PS_SEPERATOR_SQUARE_OPEN) 707 | { 708 | numOpenParens++; 709 | _ps_continue_statement(tokens, curTokenIdx, numOpenParens); 710 | 711 | varNode.id.params.push_back(_ps_parse_statement(ast, tokens, ++curTokenIdx, numOpenParens)); 712 | 713 | _ps_continue_statement(tokens, curTokenIdx, numOpenParens); 714 | if(tokens[curTokenIdx].str != PS_SEPERATOR_SQUARE_CLOSE) 715 | _ps_error(PSparseError::EXPECTED_CLOSING_PAREN, tokens[curTokenIdx]); 716 | 717 | numOpenParens--; 718 | curTokenIdx++; 719 | } 720 | 721 | if(negative) 722 | { 723 | PSnode minusNode; 724 | minusNode.type = PSnode::OP; 725 | minusNode.lineNum = tokens[curTokenIdx].lineNum; 726 | minusNode.op.type = PSnode::OP::SUB; 727 | 728 | PSnode negOne; 729 | negOne.type = PSnode::NUMBER; 730 | negOne.lineNum = tokens[curTokenIdx].lineNum; 731 | negOne.literal.type = PSnode::Literal::INT; 732 | negOne.literal.intNum = -1; 733 | 734 | minusNode.op.left = _ps_add_node(ast, negOne); 735 | minusNode.op.right = _ps_add_node(ast, varNode); 736 | return _ps_add_node(ast, minusNode); 737 | } 738 | else 739 | return _ps_add_node(ast, varNode); 740 | } 741 | 742 | static PSnode _ps_get_op_node(PSast* ast, const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens) 743 | { 744 | //ENSURE ACTUALLY AN OP: 745 | if(tokens[curTokenIdx].type != PStoken::OP) 746 | _ps_error(PSparseError::EXPECTED_OPERATOR, tokens[curTokenIdx]); 747 | 748 | PSnode opNode; 749 | opNode.type = PSnode::OP; 750 | opNode.lineNum = tokens[curTokenIdx].lineNum; 751 | if(PS_STRING_TO_OP_TYPE.count(tokens[curTokenIdx].str) == 0) 752 | _ps_error(PSparseError::INVALID_TOKEN, tokens[curTokenIdx]); 753 | else 754 | opNode.op.type = PS_STRING_TO_OP_TYPE.at(tokens[curTokenIdx].str); 755 | 756 | curTokenIdx++; 757 | _ps_continue_statement(tokens, curTokenIdx, numOpenParens); 758 | return opNode; 759 | } 760 | 761 | //--------------------------------------------------------------------------------------------------------------------------------// 762 | 763 | static inline PSnodeHandle _ps_add_node(PSast* ast, PSnode node) 764 | { 765 | ast->nodePool.push_back(node); 766 | return ast->nodePool.size() - 1; 767 | } 768 | 769 | static inline void _ps_continue_statement(const std::vector& tokens, uint32_t& curTokenIdx, uint32_t& numOpenParens) 770 | { 771 | if(tokens[curTokenIdx].type == PStoken::NEWLINE && numOpenParens != 0) 772 | { 773 | curTokenIdx++; 774 | if(curTokenIdx >= tokens.size()) 775 | _ps_error(PSparseError::EXPECTED_CLOSING_PAREN, tokens[curTokenIdx - 1]); 776 | } 777 | } 778 | 779 | static inline void _ps_remove_newline(const std::vector& tokens, uint32_t& curTokenIdx) 780 | { 781 | if(tokens[curTokenIdx].type == PStoken::NEWLINE) 782 | curTokenIdx++; 783 | } 784 | 785 | static inline int _ps_precedence(PSnode::OP::Type op) 786 | { 787 | return (int)op / 10; 788 | } 789 | 790 | static inline void _ps_force_id(PStoken token) 791 | { 792 | if(token.type != PStoken::ID) 793 | _ps_error(PSparseError::UNEXPECTED_OPERATOR, token); 794 | 795 | if(std::find(PS_KEYWORDS.begin(), PS_KEYWORDS.end(), token.str) != PS_KEYWORDS.end()) 796 | _ps_error(PSparseError::INVALID_TOKEN, token); 797 | } 798 | 799 | static void _ps_error(PSparseError error, PStoken errorToken) 800 | { 801 | g_psError = error; 802 | g_psErrorToken = errorToken; 803 | throw std::exception(); 804 | } -------------------------------------------------------------------------------- /src/propscript.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PROPSCRIPT_HPP 2 | #define PROPSCRIPT_HPP 3 | 4 | #include "definitions.hpp" 5 | #include "vector" 6 | #include "string" 7 | 8 | #include 9 | #include "quickmath.hpp" 10 | 11 | //--------------------------------------------------------------------------------------------------------------------------------// 12 | //LEXER AND PARSER STRUCTS: 13 | 14 | //a lexical token 15 | struct PStoken 16 | { 17 | enum Type 18 | { 19 | ID, 20 | OP, 21 | NEWLINE 22 | } type; 23 | 24 | std::string str; 25 | uint32_t lineNum; 26 | }; 27 | 28 | //a handle to an abstract syntax tree node 29 | typedef uint32_t PSnodeHandle; 30 | 31 | //an abstract syntax tree node 32 | struct PSnode 33 | { 34 | enum Type : uint32_t 35 | { 36 | OP, 37 | KEYWORD, 38 | ID, 39 | NUMBER 40 | } type; 41 | uint32_t lineNum; 42 | 43 | //----------------------// 44 | //OPERATOR: 45 | 46 | struct OP 47 | { 48 | enum Type : uint32_t 49 | { 50 | IN = 0, //operator precedence 51 | 52 | MULT = 10, 53 | DIV, 54 | MOD, 55 | 56 | ADD = 20, 57 | SUB, 58 | 59 | EQUAL = 30, 60 | MULTEQUAL, 61 | DIVEQUAL, 62 | MODEQUAL, 63 | ADDEQUAL, 64 | SUBEQUAL, 65 | 66 | LESSTHAN = 40, 67 | GREATERTHAN, 68 | LESSTHANEQUAL, 69 | GREATERTHANEQUAL, 70 | EQUALITY, 71 | NONEQUALITY, 72 | 73 | AND = 50, 74 | OR 75 | } type; 76 | 77 | PSnodeHandle left; //the left side of the operator 78 | PSnodeHandle right; //the right side of the operator 79 | bool inParens; //whether the operator is in parenthesis 80 | } op; 81 | 82 | //----------------------// 83 | //KEYWORD: 84 | 85 | struct Keyword 86 | { 87 | enum Type 88 | { 89 | IF, 90 | FOR, 91 | FUNC, 92 | RETURN, 93 | BREAK, 94 | CONTINUE 95 | } type; 96 | 97 | //code for body of control flow statement: 98 | std::vector code; 99 | 100 | //if statement condition / for stataement iteration rule: 101 | PSnodeHandle condition; 102 | 103 | //else statement stuff: 104 | bool hasElse; 105 | std::vector elseCode; 106 | 107 | //function names: 108 | std::string name; 109 | std::vector paramNames; 110 | 111 | //return value: 112 | PSnodeHandle returnVal; 113 | } keyword; 114 | 115 | //----------------------// 116 | //IDENTIFIER: 117 | 118 | struct ID 119 | { 120 | enum Type : uint32_t 121 | { 122 | FUNC, 123 | VAR 124 | } type; 125 | 126 | std::string name; 127 | std::vector params; //if type is a variable, also represents the index into that variable 128 | } id; 129 | 130 | //----------------------// 131 | //LITERAL: 132 | 133 | struct Literal 134 | { 135 | enum Type : uint32_t 136 | { 137 | INT, 138 | FLOAT 139 | } type; 140 | 141 | int32_t intNum; 142 | float floatNum; 143 | } literal; 144 | 145 | PSnode () {}; 146 | ~PSnode() {}; 147 | }; 148 | 149 | //an abstract syntax tree 150 | struct PSast 151 | { 152 | std::vector parentNodes; 153 | std::vector nodePool; 154 | }; 155 | 156 | //--------------------------------------------------------------------------------------------------------------------------------// 157 | //INTERPRETER STRUCTS: 158 | 159 | //a generic struct representing any possible data type 160 | struct PSdata 161 | { 162 | enum Type 163 | { 164 | VOID, 165 | 166 | INT, 167 | FLOAT, 168 | VEC2, 169 | VEC3, 170 | VEC4, 171 | QUATERNION 172 | } type; 173 | 174 | union 175 | { 176 | int32_t intVal; 177 | float floatVal; 178 | qm::vec2 vec2Val; 179 | qm::vec3 vec3Val; 180 | qm::vec4 vec4Val; 181 | qm::quaternion quatVal; 182 | }; 183 | 184 | PSdata() {}; 185 | PSdata(Type t, int32_t val) { type = t, intVal = val; }; 186 | PSdata(Type t, float val) { type = t, floatVal = val; }; 187 | PSdata(Type t, qm::vec2 val) { type = t, vec2Val = val; }; 188 | PSdata(Type t, qm::vec3 val) { type = t, vec3Val = val; }; 189 | PSdata(Type t, qm::vec4 val) { type = t, vec4Val = val; }; 190 | PSdata(Type t, qm::quaternion val) { type = t, quatVal = val; }; 191 | }; 192 | 193 | //a function signature 194 | struct PSfunctionSignature 195 | { 196 | std::string name; 197 | PSdata (*func)(const std::vector& params, const PSnode& node, void* userData); 198 | }; 199 | 200 | //a constant value 201 | struct PSconstant 202 | { 203 | std::string name; 204 | PSdata val; 205 | }; 206 | 207 | //--------------------------------------------------------------------------------------------------------------------------------// 208 | 209 | /* Lexes and tokenizes a source file 210 | * @param path the path to the source file 211 | * @returns the vector of tokens extracted from the spurce file 212 | */ 213 | std::vector ps_lex_file(std::string path); 214 | 215 | /* Parses a list of tokens into an abstract syntax tree 216 | * @param tokens the list of tokens 217 | * @returns the generated abstract syntax tree 218 | */ 219 | PSast* ps_parse_tokens(const std::vector& tokens); 220 | /* Frees an abstract syntax tree 221 | * @param ast the abstract syntax tree to free 222 | */ 223 | void ps_free_ast(PSast* ast); 224 | /* Serializes an abstract syntax tree to disk 225 | * @param path the path to the file to save to 226 | * @param ast the abstact syntax tree to save 227 | */ 228 | void ps_save_ast(std::string path, PSast* ast); 229 | /* Serializes an abstract syntax tree to disk 230 | * @param file the file pointer to save to 231 | * @param ast the abstact syntax tree to save 232 | */ 233 | void ps_save_ast(std::ofstream& file, PSast* ast); 234 | /* Loads an abstract syntax tree from disk 235 | * @param path the path to the file to load from 236 | * @returns the loaded abstract syntax tree 237 | */ 238 | PSast* ps_load_ast(std::string path); 239 | /* Loads an abstract syntax tree from disk 240 | * @param file the file pointer to load from 241 | * @returns the loaded abstract syntax tree 242 | */ 243 | PSast* ps_load_ast(std::ifstream& file); 244 | 245 | /* Sets a list of user defined functions to include in execution 246 | * @param functions the list of user defined functions to include 247 | */ 248 | void ps_set_functions(const std::vector& functions); 249 | /* Sets a list of user defined constants to include in execution 250 | * @param constnats the list of user defined constants to include 251 | */ 252 | void ps_set_constants(const std::vector& constants); 253 | /* Sets the pointer to the user data that gets passed to each function call 254 | * @param userData the pointer to be passed to each function call 255 | */ 256 | void ps_set_function_user_data(void* userData); 257 | /* Throws an invalid parameter error, call inside a user-defined function if the parameter list is invalid 258 | * @param node the node passed to the function 259 | */ 260 | void ps_throw_invalid_param_error(PSnode node); 261 | /* Executes the code in an abstract syntax tree 262 | * @param ast the abstract syntax tree to execute 263 | */ 264 | void ps_execute(PSast* ast); 265 | 266 | #endif -------------------------------------------------------------------------------- /src/quickmath.hpp: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------ 2 | * 3 | * quickmath.hpp 4 | * author: Daniel Elwell (2022) 5 | * license: MIT 6 | * description: a single-header library for common vector, matrix, and quaternion math 7 | * functions designed for games and graphics programming. 8 | * 9 | * ------------------------------------------------------------------------ 10 | * 11 | * all the types and functions provided by this library are under the the "qm" namespace 12 | * 13 | * if you wish not to use SSE3 intrinsics (if they are not supported for example), 14 | * change the macro on line 101 to "#define QM_USE_SSE 0" 15 | * 16 | * if you wish not to include in your project, simply change the macro on line 109 17 | * to "#define QM_INCLUDE_IOSTREAM 0" and any iostream related functions will not be compiled 18 | * 19 | * to disable the need to link with the C runtime library, change the macros beginning 20 | * on line 116 and the #include on line 114 to the appropirate functions/files 21 | * 22 | * ------------------------------------------------------------------------ 23 | * 24 | * the following functions are defined: 25 | * (vecn means a vector of dimension, 2, 3, or 4, named vec2, vec3, and vec4) 26 | * (matn means a matrix of dimensions 3x3 or 4x4, named mat3 and mat4) 27 | * 28 | * vecn dot (vecn v1, vecn v2); 29 | * vec3 cross (vec3 v1, vec3 v2); 30 | * float length (vecn v); 31 | * vecn normalize (vecn v); 32 | * float distance (vecn v1, vecn v2); 33 | * vecn min (vecn v1, vecn v2); 34 | * vecn max (vecn v1, vecn v2); 35 | * 36 | * matn matn_identity (); 37 | * matn transpose (matn m); 38 | * matn inverse (matn m); 39 | * 40 | * mat3 translate (vec2 t); 41 | * mat4 translate (vec3 t); 42 | * mat3 scale (vec2 s); 43 | * mat4 scale (vec3 s); 44 | * mat3 rotate (float angle); 45 | * mat4 rotate (vec3 axis, float angle); 46 | * mat4 rotate (vec3 euler); 47 | * mat3 top_left (mat4 m); 48 | * 49 | * mat4 perspective (float fov, float aspect, float near, float far); 50 | * mat4 orthographic (float left, float right, float bot, float top, float near, float far); 51 | * mat4 look (vec3 pos, vec3 dir , vec3 up); 52 | * mat4 lookat (vec3 pos, vec3 target, vec3 up); 53 | * 54 | * quaternion quaternion_identity (); 55 | * quaternion dot (quaternion q1, quaternion q2); 56 | * float length (quaternion q); 57 | * quaternion normalize (quaternion q); 58 | * quaternion conjugate (quaternion q); 59 | * quaternion inverse (quaternion q); 60 | * quaternion slerp (quaternion q1, quaternion q2, float a); 61 | * quaternion quaternion_from_axis_angle (vec3 axis, float angle); 62 | * quaternion quaternion_from_euler (vec3 angles); 63 | * mat4 quaternion_to_mat4 (quaternion q); 64 | * 65 | * the following operators are defined: 66 | * (vecn means a vector of dimension, 2, 3, or 4, named vec2, vec3, and vec4) 67 | * (matn means a matrix of dimensions 3x3 or 4x4, named mat3 and mat4) 68 | * 69 | * vecn + vecn -> vecn 70 | * vecn - vecn -> vecn 71 | * vecn * vecn -> vecn 72 | * vecn / vecn -> vecn 73 | * vecn * float -> vecn 74 | * float * vecn -> vecn 75 | * vecn / float -> vecn 76 | * float / vecn -> vecn 77 | * vecn == vecn -> bool 78 | * vecn != vecn -> bool 79 | * 80 | * matn + matn -> matn 81 | * matn - matn -> matn 82 | * matn * matn -> matn 83 | * matn * vecn -> vecn 84 | * 85 | * quaternion + quaternion -> quaternion 86 | * quaternion - quaternion -> quaternion 87 | * quaternion * quaternion -> quaternion 88 | * quaternion * float -> quaternion 89 | * float * quaternion -> quaternion 90 | * quaternion / float -> quaternion 91 | * float / quaternion -> quaternion 92 | * quaternion == quaternion -> bool 93 | * quaternion != quaternion -> bool 94 | */ 95 | 96 | #ifndef QM_MATH_H 97 | #define QM_MATH_H 98 | 99 | //if you wish NOT to use SSE3 SIMD intrinsics, simply change the 100 | //#define to 0 101 | #define QM_USE_SSE 1 102 | #if QM_USE_SSE 103 | #include 104 | #include 105 | #endif 106 | 107 | //if you wish NOT to include iostream, simply change the 108 | //#define to 0 109 | #define QM_INCLUDE_IOSTREAM 1 110 | #if QM_INCLUDE_IOSTREAM 111 | #include 112 | #endif 113 | 114 | //if you wish to not use any of the CRT functions, you must #define your 115 | //own versions of the below functions and #include the appropriate header 116 | #include 117 | 118 | #define QM_SQRTF sqrtf 119 | #define QM_SINF sinf 120 | #define QM_COSF cosf 121 | #define QM_TANF tanf 122 | #define QM_ACOSF acosf 123 | 124 | namespace qm 125 | { 126 | 127 | //----------------------------------------------------------------------// 128 | //STRUCT DEFINITIONS: 129 | 130 | //a 2-dimensional vector of floats 131 | union vec2 132 | { 133 | float v[2] = {}; 134 | struct{ float x, y; }; 135 | struct{ float w, h; }; 136 | 137 | vec2() {}; 138 | vec2(float _x, float _y) { x = _x, y = _y; }; 139 | 140 | inline float& operator[](size_t i) { return v[i]; }; 141 | }; 142 | 143 | //a 3-dimensional vector of floats 144 | union vec3 145 | { 146 | float v[3] = {}; 147 | struct{ float x, y, z; }; 148 | struct{ float w, h, d; }; 149 | struct{ float r, g, b; }; 150 | 151 | vec3() {}; 152 | vec3(float _x, float _y, float _z) { x = _x, y = _y, z = _z; }; 153 | vec3(vec2 _xy, float _z) { x = _xy.x, y = _xy.y, z = _z; }; 154 | vec3(float _x, vec3 _yz) { x = _x, y = _yz.x, z = _yz.y; }; 155 | 156 | inline float& operator[](size_t i) { return v[i]; }; 157 | }; 158 | 159 | //a 4-dimensional vector of floats 160 | union vec4 161 | { 162 | float v[4] = {}; 163 | struct{ float x, y, z, w; }; 164 | struct{ float r, g, b, a; }; 165 | 166 | #if QM_USE_SSE 167 | 168 | __m128 packed; 169 | 170 | #endif 171 | 172 | vec4() {}; 173 | vec4(float _x, float _y, float _z, float _w) { x = _x, y = _y, z = _z, w = _w; }; 174 | vec4(vec3 _xyz, float _w) { x = _xyz.x, y = _xyz.y, z = _xyz.z, w = _w; }; 175 | vec4(float _x, vec3 _yzw) { x = _x, y = _yzw.x, z = _yzw.y, w = _yzw.z; }; 176 | vec4(vec2 _xy, vec2 _zw) { x = _xy.x, y = _xy.y, z = _zw.x, w = _zw.y; }; 177 | 178 | inline float& operator[](size_t i) { return v[i]; }; 179 | }; 180 | 181 | //-----------------------------// 182 | //matrices are column-major 183 | 184 | union mat3 185 | { 186 | float m[3][3] = {}; 187 | vec3 v[3]; 188 | 189 | mat3() {}; 190 | 191 | inline vec3& operator[](size_t i) { return v[i]; }; 192 | }; 193 | 194 | union mat4 195 | { 196 | float m[4][4] = {}; 197 | vec4 v[4]; 198 | 199 | #if QM_USE_SSE 200 | 201 | __m128 packed[4]; //array of columns 202 | 203 | #endif 204 | 205 | mat4() {}; 206 | 207 | inline vec4& operator[](size_t i) { return v[i]; }; 208 | }; 209 | 210 | //-----------------------------// 211 | 212 | union quaternion 213 | { 214 | float q[4] = {}; 215 | struct{ float x, y, z, w; }; 216 | 217 | #if QM_USE_SSE 218 | 219 | __m128 packed; 220 | 221 | #endif 222 | 223 | quaternion() {}; 224 | quaternion(float _x, float _y, float _z, float _w) { x = _x, y = _y, z = _z, w = _w; }; 225 | quaternion(vec3 _xyz, float _w) { x = _xyz.x, y = _xyz.y, z = _xyz.z, w = _w; }; 226 | quaternion(float _x, vec3 _yzw) { x = _x, y = _yzw.x, z = _yzw.y, w = _yzw.z; }; 227 | quaternion(vec2 _xy, vec2 _zw) { x = _xy.x, y = _xy.y, z = _zw.x, w = _zw.y; }; 228 | 229 | inline float operator[](size_t i) { return q[i]; }; 230 | }; 231 | 232 | //----------------------------------------------------------------------// 233 | //HELPER FUNCS: 234 | 235 | #define QM_MIN(x, y) ((x) < (y) ? (x) : (y)) 236 | #define QM_MAX(x, y) ((x) > (y) ? (x) : (y)) 237 | #define QM_ABS(x) ((x) > 0 ? (x) : -(x)) 238 | 239 | inline float rad_to_deg(float rad) 240 | { 241 | return rad * 57.2957795131f; 242 | } 243 | 244 | inline float deg_to_rad(float deg) 245 | { 246 | return deg * 0.01745329251f; 247 | } 248 | 249 | #if QM_USE_SSE 250 | 251 | inline __m128 mat4_mult_column_sse(__m128 c1, mat4 m2) 252 | { 253 | __m128 result; 254 | 255 | result = _mm_mul_ps(_mm_shuffle_ps(c1, c1, _MM_SHUFFLE(0, 0, 0, 0)), m2.packed[0]); 256 | result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(c1, c1, _MM_SHUFFLE(1, 1, 1, 1)), m2.packed[1])); 257 | result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(c1, c1, _MM_SHUFFLE(2, 2, 2, 2)), m2.packed[2])); 258 | result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(c1, c1, _MM_SHUFFLE(3, 3, 3, 3)), m2.packed[3])); 259 | 260 | return result; 261 | } 262 | 263 | #endif 264 | 265 | //----------------------------------------------------------------------// 266 | //VECTOR FUNCTIONS: 267 | 268 | #if QM_INCLUDE_IOSTREAM 269 | 270 | //output: 271 | 272 | inline std::ostream& operator<<(std::ostream& os, const vec2& v) 273 | { 274 | os << v.x << ", " << v.y; 275 | return os; 276 | } 277 | 278 | inline std::ostream& operator<<(std::ostream& os, const vec3& v) 279 | { 280 | os << v.x << ", " << v.y << ", " << v.z; 281 | return os; 282 | } 283 | 284 | inline std::ostream& operator<<(std::ostream& os, const vec4& v) 285 | { 286 | os << v.x << ", " << v.y << ", " << v.z << ", " << v.w; 287 | return os; 288 | } 289 | 290 | //input: 291 | 292 | inline std::istream& operator>>(std::istream& is, vec2& v) 293 | { 294 | is >> v.x >> v.y; 295 | return is; 296 | } 297 | 298 | inline std::istream& operator>>(std::istream& is, vec3& v) 299 | { 300 | is >> v.x >> v.y >> v.z; 301 | return is; 302 | } 303 | 304 | inline std::istream& operator>>(std::istream& is, vec4& v) 305 | { 306 | is >> v.x >> v.y >> v.z >> v.w; 307 | return is; 308 | } 309 | 310 | #endif 311 | 312 | //addition: 313 | 314 | inline vec2 operator+(const vec2& v1, const vec2& v2) 315 | { 316 | vec2 result; 317 | 318 | result.x = v1.x + v2.x; 319 | result.y = v1.y + v2.y; 320 | 321 | return result; 322 | } 323 | 324 | inline vec3 operator+(const vec3& v1, const vec3& v2) 325 | { 326 | vec3 result; 327 | 328 | result.x = v1.x + v2.x; 329 | result.y = v1.y + v2.y; 330 | result.z = v1.z + v2.z; 331 | 332 | return result; 333 | } 334 | 335 | inline vec4 operator+(const vec4& v1, const vec4& v2) 336 | { 337 | vec4 result; 338 | 339 | #if QM_USE_SSE 340 | 341 | result.packed = _mm_add_ps(v1.packed, v2.packed); 342 | 343 | #else 344 | 345 | result.x = v1.x + v2.x; 346 | result.y = v1.y + v2.y; 347 | result.z = v1.z + v2.z; 348 | result.w = v1.w + v2.w; 349 | 350 | #endif 351 | 352 | return result; 353 | } 354 | 355 | //subtraction: 356 | 357 | inline vec2 operator-(const vec2& v1, const vec2& v2) 358 | { 359 | vec2 result; 360 | 361 | result.x = v1.x - v2.x; 362 | result.y = v1.y - v2.y; 363 | 364 | return result; 365 | } 366 | 367 | inline vec3 operator-(const vec3& v1, const vec3& v2) 368 | { 369 | vec3 result; 370 | 371 | result.x = v1.x - v2.x; 372 | result.y = v1.y - v2.y; 373 | result.z = v1.z - v2.z; 374 | 375 | return result; 376 | } 377 | 378 | inline vec4 operator-(const vec4& v1, const vec4& v2) 379 | { 380 | vec4 result; 381 | 382 | #if QM_USE_SSE 383 | 384 | result.packed = _mm_sub_ps(v1.packed, v2.packed); 385 | 386 | #else 387 | 388 | result.x = v1.x - v2.x; 389 | result.y = v1.y - v2.y; 390 | result.z = v1.z - v2.z; 391 | result.w = v1.w - v2.w; 392 | 393 | #endif 394 | 395 | return result; 396 | } 397 | 398 | //multiplication: 399 | 400 | inline vec2 operator*(const vec2& v1, const vec2& v2) 401 | { 402 | vec2 result; 403 | 404 | result.x = v1.x * v2.x; 405 | result.y = v1.y * v2.y; 406 | 407 | return result; 408 | } 409 | 410 | inline vec3 operator*(const vec3& v1, const vec3& v2) 411 | { 412 | vec3 result; 413 | 414 | result.x = v1.x * v2.x; 415 | result.y = v1.y * v2.y; 416 | result.z = v1.z * v2.z; 417 | 418 | return result; 419 | } 420 | 421 | inline vec4 operator*(const vec4& v1, const vec4& v2) 422 | { 423 | vec4 result; 424 | 425 | #if QM_USE_SSE 426 | 427 | result.packed = _mm_mul_ps(v1.packed, v2.packed); 428 | 429 | #else 430 | 431 | result.x = v1.x * v2.x; 432 | result.y = v1.y * v2.y; 433 | result.z = v1.z * v2.z; 434 | result.w = v1.w * v2.w; 435 | 436 | #endif 437 | 438 | return result; 439 | } 440 | 441 | //division: 442 | 443 | inline vec2 operator/(const vec2& v1, const vec2& v2) 444 | { 445 | vec2 result; 446 | 447 | result.x = v1.x / v2.x; 448 | result.y = v1.y / v2.y; 449 | 450 | return result; 451 | } 452 | 453 | inline vec3 operator/(const vec3& v1, const vec3& v2) 454 | { 455 | vec3 result; 456 | 457 | result.x = v1.x / v2.x; 458 | result.y = v1.y / v2.y; 459 | result.z = v1.z / v2.z; 460 | 461 | return result; 462 | } 463 | 464 | inline vec4 operator/(const vec4& v1, const vec4& v2) 465 | { 466 | vec4 result; 467 | 468 | #if QM_USE_SSE 469 | 470 | result.packed = _mm_div_ps(v1.packed, v2.packed); 471 | 472 | #else 473 | 474 | result.x = v1.x / v2.x; 475 | result.y = v1.y / v2.y; 476 | result.z = v1.z / v2.z; 477 | result.w = v1.w / v2.w; 478 | 479 | #endif 480 | 481 | return result; 482 | } 483 | 484 | //scalar multiplication: 485 | 486 | inline vec2 operator*(const vec2& v, float s) 487 | { 488 | vec2 result; 489 | 490 | result.x = v.x * s; 491 | result.y = v.y * s; 492 | 493 | return result; 494 | } 495 | 496 | inline vec3 operator*(const vec3& v, float s) 497 | { 498 | vec3 result; 499 | 500 | result.x = v.x * s; 501 | result.y = v.y * s; 502 | result.z = v.z * s; 503 | 504 | return result; 505 | } 506 | 507 | inline vec4 operator*(const vec4& v, float s) 508 | { 509 | vec4 result; 510 | 511 | #if QM_USE_SSE 512 | 513 | __m128 scale = _mm_set1_ps(s); 514 | result.packed = _mm_mul_ps(v.packed, scale); 515 | 516 | #else 517 | 518 | result.x = v.x * s; 519 | result.y = v.y * s; 520 | result.z = v.z * s; 521 | result.w = v.w * s; 522 | 523 | #endif 524 | 525 | return result; 526 | } 527 | 528 | inline vec2 operator*(float s, const vec2& v) 529 | { 530 | return v * s; 531 | } 532 | 533 | inline vec3 operator*(float s, const vec3& v) 534 | { 535 | return v * s; 536 | } 537 | 538 | inline vec4 operator*(float s, const vec4& v) 539 | { 540 | return v * s; 541 | } 542 | 543 | //scalar division: 544 | 545 | inline vec2 operator/(const vec2& v, float s) 546 | { 547 | vec2 result; 548 | 549 | result.x = v.x / s; 550 | result.y = v.y / s; 551 | 552 | return result; 553 | } 554 | 555 | inline vec3 operator/(const vec3& v, float s) 556 | { 557 | vec3 result; 558 | 559 | result.x = v.x / s; 560 | result.y = v.y / s; 561 | result.z = v.z / s; 562 | 563 | return result; 564 | } 565 | 566 | inline vec4 operator/(const vec4& v, float s) 567 | { 568 | vec4 result; 569 | 570 | #if QM_USE_SSE 571 | 572 | __m128 scale = _mm_set1_ps(s); 573 | result.packed = _mm_div_ps(v.packed, scale); 574 | 575 | #else 576 | 577 | result.x = v.x / s; 578 | result.y = v.y / s; 579 | result.z = v.z / s; 580 | result.w = v.w / s; 581 | 582 | #endif 583 | 584 | return result; 585 | } 586 | 587 | inline vec2 operator/(float s, const vec2& v) 588 | { 589 | vec2 result; 590 | 591 | result.x = s / v.x; 592 | result.y = s / v.y; 593 | 594 | return result; 595 | } 596 | 597 | inline vec3 operator/(float s, const vec3& v) 598 | { 599 | vec3 result; 600 | 601 | result.x = s / v.x; 602 | result.y = s / v.y; 603 | result.z = s / v.z; 604 | 605 | return result; 606 | } 607 | 608 | inline vec4 operator/(float s, const vec4& v) 609 | { 610 | vec4 result; 611 | 612 | #if QM_USE_SSE 613 | 614 | __m128 scale = _mm_set1_ps(s); 615 | result.packed = _mm_div_ps(scale, v.packed); 616 | 617 | #else 618 | 619 | result.x = s / v.x; 620 | result.y = s / v.y; 621 | result.z = s / v.z; 622 | result.w = s / v.w; 623 | 624 | #endif 625 | 626 | return result; 627 | } 628 | 629 | //dot product: 630 | 631 | inline float dot(const vec2& v1, const vec2& v2) 632 | { 633 | float result; 634 | 635 | result = v1.x * v2.x + v1.y * v2.y; 636 | 637 | return result; 638 | } 639 | 640 | inline float dot(const vec3& v1, const vec3& v2) 641 | { 642 | float result; 643 | 644 | result = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; 645 | 646 | return result; 647 | } 648 | 649 | inline float dot(const vec4& v1, const vec4& v2) 650 | { 651 | float result; 652 | 653 | #if QM_USE_SSE 654 | 655 | __m128 r = _mm_mul_ps(v1.packed, v2.packed); 656 | r = _mm_hadd_ps(r, r); 657 | r = _mm_hadd_ps(r, r); 658 | _mm_store_ss(&result, r); 659 | 660 | #else 661 | 662 | result = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w; 663 | 664 | #endif 665 | 666 | return result; 667 | } 668 | 669 | //cross product 670 | 671 | inline vec3 cross(const vec3& v1, const vec3& v2) 672 | { 673 | vec3 result; 674 | 675 | result.x = (v1.y * v2.z) - (v1.z * v2.y); 676 | result.y = (v1.z * v2.x) - (v1.x * v2.z); 677 | result.z = (v1.x * v2.y) - (v1.y * v2.x); 678 | 679 | return result; 680 | } 681 | 682 | //length: 683 | 684 | inline float length(const vec2& v) 685 | { 686 | float result; 687 | 688 | result = QM_SQRTF(dot(v, v)); 689 | 690 | return result; 691 | } 692 | 693 | inline float length(const vec3& v) 694 | { 695 | float result; 696 | 697 | result = QM_SQRTF(dot(v, v)); 698 | 699 | return result; 700 | } 701 | 702 | inline float length(const vec4& v) 703 | { 704 | float result; 705 | 706 | result = QM_SQRTF(dot(v, v)); 707 | 708 | return result; 709 | } 710 | 711 | //normalize: 712 | 713 | inline vec2 normalize(const vec2& v) 714 | { 715 | vec2 result; 716 | 717 | float len = length(v); 718 | if(len != 0.0f) 719 | result = v / len; 720 | 721 | return result; 722 | } 723 | 724 | inline vec3 normalize(const vec3& v) 725 | { 726 | vec3 result; 727 | 728 | float len = length(v); 729 | if(len != 0.0f) 730 | result = v / len; 731 | 732 | return result; 733 | } 734 | 735 | inline vec4 normalize(const vec4& v) 736 | { 737 | vec4 result; 738 | 739 | float len = length(v); 740 | result = v / len; 741 | 742 | return result; 743 | } 744 | 745 | //distance: 746 | 747 | inline float distance(const vec2& v1, const vec2& v2) 748 | { 749 | float result; 750 | 751 | vec2 to = v1 - v2; 752 | result = length(to); 753 | 754 | return result; 755 | } 756 | 757 | inline float distance(const vec3& v1, const vec3& v2) 758 | { 759 | float result; 760 | 761 | vec3 to = v1 - v2; 762 | result = length(to); 763 | 764 | return result; 765 | } 766 | 767 | inline float distance(const vec4& v1, const vec4& v2) 768 | { 769 | float result; 770 | 771 | vec4 to = v1 - v2; 772 | result = length(to); 773 | 774 | return result; 775 | } 776 | 777 | //equality: 778 | 779 | inline bool operator==(const vec2& v1, const vec2& v2) 780 | { 781 | bool result; 782 | 783 | result = (v1.x == v2.x) && (v1.y == v2.y); 784 | 785 | return result; 786 | } 787 | 788 | inline bool operator==(const vec3& v1, const vec3& v2) 789 | { 790 | bool result; 791 | 792 | result = (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z); 793 | 794 | return result; 795 | } 796 | 797 | inline bool operator==(const vec4& v1, const vec4& v2) 798 | { 799 | bool result; 800 | 801 | //TODO: there are SIMD instructions for floating point equality, find a way to get a single bool from them 802 | result = (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z) && (v1.w == v2.w); 803 | 804 | return result; 805 | } 806 | 807 | inline bool operator!=(const vec2& v1, const vec2& v2) 808 | { 809 | bool result; 810 | 811 | result = (v1.x != v2.x) || (v1.y != v2.y); 812 | 813 | return result; 814 | } 815 | 816 | inline bool operator!=(const vec3& v1, const vec3& v2) 817 | { 818 | bool result; 819 | 820 | result = (v1.x != v2.x) || (v1.y != v2.y) || (v1.z != v2.z); 821 | 822 | return result; 823 | } 824 | 825 | inline bool operator!=(const vec4& v1, const vec4& v2) 826 | { 827 | bool result; 828 | 829 | result = (v1.x != v2.x) || (v1.y != v2.y) || (v1.z != v2.z) || (v1.w != v2.w); 830 | 831 | return result; 832 | } 833 | 834 | //min: 835 | 836 | inline vec2 min(const vec2& v1, const vec2& v2) 837 | { 838 | vec2 result; 839 | 840 | result.x = QM_MIN(v1.x, v2.x); 841 | result.y = QM_MIN(v1.y, v2.y); 842 | 843 | return result; 844 | } 845 | 846 | inline vec3 min(const vec3& v1, const vec3& v2) 847 | { 848 | vec3 result; 849 | 850 | result.x = QM_MIN(v1.x, v2.x); 851 | result.y = QM_MIN(v1.y, v2.y); 852 | result.z = QM_MIN(v1.z, v2.z); 853 | 854 | return result; 855 | } 856 | 857 | inline vec4 min(const vec4& v1, const vec4& v2) 858 | { 859 | vec4 result; 860 | 861 | #if QM_USE_SSE 862 | 863 | result.packed = _mm_min_ps(v1.packed, v2.packed); 864 | 865 | #else 866 | 867 | result.x = QM_MIN(v1.x, v2.x); 868 | result.y = QM_MIN(v1.y, v2.y); 869 | result.z = QM_MIN(v1.z, v2.z); 870 | result.w = QM_MIN(v1.w, v2.w); 871 | 872 | #endif 873 | 874 | return result; 875 | } 876 | 877 | //max: 878 | 879 | inline vec2 max(const vec2& v1, const vec2& v2) 880 | { 881 | vec2 result; 882 | 883 | result.x = QM_MAX(v1.x, v2.x); 884 | result.y = QM_MAX(v1.y, v2.y); 885 | 886 | return result; 887 | } 888 | 889 | inline vec3 max(const vec3& v1, const vec3& v2) 890 | { 891 | vec3 result; 892 | 893 | result.x = QM_MAX(v1.x, v2.x); 894 | result.y = QM_MAX(v1.y, v2.y); 895 | result.z = QM_MAX(v1.z, v2.z); 896 | 897 | return result; 898 | } 899 | 900 | inline vec4 max(const vec4& v1, const vec4& v2) 901 | { 902 | vec4 result; 903 | 904 | #if QM_USE_SSE 905 | 906 | result.packed = _mm_max_ps(v1.packed, v2.packed); 907 | 908 | #else 909 | 910 | result.x = QM_MAX(v1.x, v2.x); 911 | result.y = QM_MAX(v1.y, v2.y); 912 | result.z = QM_MAX(v1.z, v2.z); 913 | result.w = QM_MAX(v1.w, v2.w); 914 | 915 | #endif 916 | 917 | return result; 918 | } 919 | 920 | //----------------------------------------------------------------------// 921 | //MATRIX FUNCTIONS: 922 | 923 | #if QM_INCLUDE_IOSTREAM 924 | 925 | //output: 926 | 927 | inline std::ostream& operator<<(std::ostream& os, const mat3& m) 928 | { 929 | os << m.v[0] << std::endl << m.v[1] << std::endl << m.v[2]; 930 | return os; 931 | } 932 | 933 | inline std::ostream& operator<<(std::ostream& os, const mat4& m) 934 | { 935 | os << m.v[0] << std::endl << m.v[1] << std::endl << m.v[2] << std::endl << m.v[3]; 936 | return os; 937 | } 938 | 939 | //input: 940 | 941 | inline std::istream& operator>>(std::istream& is, mat3& m) 942 | { 943 | is >> m.v[0] >> m.v[1] >> m.v[2]; 944 | return is; 945 | } 946 | 947 | inline std::istream& operator>>(std::istream& is, mat4& m) 948 | { 949 | is >> m.v[0] >> m.v[1] >> m.v[2] >> m.v[3]; 950 | return is; 951 | } 952 | 953 | #endif 954 | 955 | //initialization: 956 | 957 | inline mat3 mat3_identity() 958 | { 959 | mat3 result; 960 | 961 | result.m[0][0] = 1.0f; 962 | result.m[1][1] = 1.0f; 963 | result.m[2][2] = 1.0f; 964 | 965 | return result; 966 | } 967 | 968 | inline mat4 mat4_identity() 969 | { 970 | mat4 result; 971 | 972 | result.m[0][0] = 1.0f; 973 | result.m[1][1] = 1.0f; 974 | result.m[2][2] = 1.0f; 975 | result.m[3][3] = 1.0f; 976 | 977 | return result; 978 | } 979 | 980 | //addition: 981 | 982 | inline mat3 operator+(const mat3& m1, const mat3& m2) 983 | { 984 | mat3 result; 985 | 986 | result.m[0][0] = m1.m[0][0] + m2.m[0][0]; 987 | result.m[0][1] = m1.m[0][1] + m2.m[0][1]; 988 | result.m[0][2] = m1.m[0][2] + m2.m[0][2]; 989 | result.m[1][0] = m1.m[1][0] + m2.m[1][0]; 990 | result.m[1][1] = m1.m[1][1] + m2.m[1][1]; 991 | result.m[1][2] = m1.m[1][2] + m2.m[1][2]; 992 | result.m[2][0] = m1.m[2][0] + m2.m[2][0]; 993 | result.m[2][1] = m1.m[2][1] + m2.m[2][1]; 994 | result.m[2][2] = m1.m[2][2] + m2.m[2][2]; 995 | 996 | return result; 997 | } 998 | 999 | inline mat4 operator+(const mat4& m1, const mat4& m2) 1000 | { 1001 | mat4 result; 1002 | 1003 | #if QM_USE_SSE 1004 | 1005 | result.packed[0] = _mm_add_ps(m1.packed[0], m2.packed[0]); 1006 | result.packed[1] = _mm_add_ps(m1.packed[1], m2.packed[1]); 1007 | result.packed[2] = _mm_add_ps(m1.packed[2], m2.packed[2]); 1008 | result.packed[3] = _mm_add_ps(m1.packed[3], m2.packed[3]); 1009 | 1010 | #else 1011 | 1012 | result.m[0][0] = m1.m[0][0] + m2.m[0][0]; 1013 | result.m[0][1] = m1.m[0][1] + m2.m[0][1]; 1014 | result.m[0][2] = m1.m[0][2] + m2.m[0][2]; 1015 | result.m[0][3] = m1.m[0][3] + m2.m[0][3]; 1016 | result.m[1][0] = m1.m[1][0] + m2.m[1][0]; 1017 | result.m[1][1] = m1.m[1][1] + m2.m[1][1]; 1018 | result.m[1][2] = m1.m[1][2] + m2.m[1][2]; 1019 | result.m[1][3] = m1.m[1][3] + m2.m[1][3]; 1020 | result.m[2][0] = m1.m[2][0] + m2.m[2][0]; 1021 | result.m[2][1] = m1.m[2][1] + m2.m[2][1]; 1022 | result.m[2][2] = m1.m[2][2] + m2.m[2][2]; 1023 | result.m[2][3] = m1.m[2][3] + m2.m[2][3]; 1024 | result.m[3][0] = m1.m[3][0] + m2.m[3][0]; 1025 | result.m[3][1] = m1.m[3][1] + m2.m[3][1]; 1026 | result.m[3][2] = m1.m[3][2] + m2.m[3][2]; 1027 | result.m[3][3] = m1.m[3][3] + m2.m[3][3]; 1028 | 1029 | #endif 1030 | 1031 | return result; 1032 | } 1033 | 1034 | //subtraction: 1035 | 1036 | inline mat3 operator-(const mat3& m1, const mat3& m2) 1037 | { 1038 | mat3 result; 1039 | 1040 | result.m[0][0] = m1.m[0][0] - m2.m[0][0]; 1041 | result.m[0][1] = m1.m[0][1] - m2.m[0][1]; 1042 | result.m[0][2] = m1.m[0][2] - m2.m[0][2]; 1043 | result.m[1][0] = m1.m[1][0] - m2.m[1][0]; 1044 | result.m[1][1] = m1.m[1][1] - m2.m[1][1]; 1045 | result.m[1][2] = m1.m[1][2] - m2.m[1][2]; 1046 | result.m[2][0] = m1.m[2][0] - m2.m[2][0]; 1047 | result.m[2][1] = m1.m[2][1] - m2.m[2][1]; 1048 | result.m[2][2] = m1.m[2][2] - m2.m[2][2]; 1049 | 1050 | return result; 1051 | } 1052 | 1053 | inline mat4 operator-(const mat4& m1, const mat4& m2) 1054 | { 1055 | mat4 result; 1056 | 1057 | #if QM_USE_SSE 1058 | 1059 | result.packed[0] = _mm_sub_ps(m1.packed[0], m2.packed[0]); 1060 | result.packed[1] = _mm_sub_ps(m1.packed[1], m2.packed[1]); 1061 | result.packed[2] = _mm_sub_ps(m1.packed[2], m2.packed[2]); 1062 | result.packed[3] = _mm_sub_ps(m1.packed[3], m2.packed[3]); 1063 | 1064 | #else 1065 | 1066 | result.m[0][0] = m1.m[0][0] - m2.m[0][0]; 1067 | result.m[0][1] = m1.m[0][1] - m2.m[0][1]; 1068 | result.m[0][2] = m1.m[0][2] - m2.m[0][2]; 1069 | result.m[0][3] = m1.m[0][3] - m2.m[0][3]; 1070 | result.m[1][0] = m1.m[1][0] - m2.m[1][0]; 1071 | result.m[1][1] = m1.m[1][1] - m2.m[1][1]; 1072 | result.m[1][2] = m1.m[1][2] - m2.m[1][2]; 1073 | result.m[1][3] = m1.m[1][3] - m2.m[1][3]; 1074 | result.m[2][0] = m1.m[2][0] - m2.m[2][0]; 1075 | result.m[2][1] = m1.m[2][1] - m2.m[2][1]; 1076 | result.m[2][2] = m1.m[2][2] - m2.m[2][2]; 1077 | result.m[2][3] = m1.m[2][3] - m2.m[2][3]; 1078 | result.m[3][0] = m1.m[3][0] - m2.m[3][0]; 1079 | result.m[3][1] = m1.m[3][1] - m2.m[3][1]; 1080 | result.m[3][2] = m1.m[3][2] - m2.m[3][2]; 1081 | result.m[3][3] = m1.m[3][3] - m2.m[3][3]; 1082 | 1083 | #endif 1084 | 1085 | return result; 1086 | } 1087 | 1088 | //multiplication: 1089 | 1090 | inline mat3 operator*(const mat3& m1, const mat3& m2) 1091 | { 1092 | mat3 result; 1093 | 1094 | result.m[0][0] = m1.m[0][0] * m2.m[0][0] + m1.m[1][0] * m2.m[0][1] + m1.m[2][0] * m2.m[0][2]; 1095 | result.m[0][1] = m1.m[0][1] * m2.m[0][0] + m1.m[1][1] * m2.m[0][1] + m1.m[2][1] * m2.m[0][2]; 1096 | result.m[0][2] = m1.m[0][2] * m2.m[0][0] + m1.m[1][2] * m2.m[0][1] + m1.m[2][2] * m2.m[0][2]; 1097 | result.m[1][0] = m1.m[0][0] * m2.m[1][0] + m1.m[1][0] * m2.m[1][1] + m1.m[2][0] * m2.m[1][2]; 1098 | result.m[1][1] = m1.m[0][1] * m2.m[1][0] + m1.m[1][1] * m2.m[1][1] + m1.m[2][1] * m2.m[1][2]; 1099 | result.m[1][2] = m1.m[0][2] * m2.m[1][0] + m1.m[1][2] * m2.m[1][1] + m1.m[2][2] * m2.m[1][2]; 1100 | result.m[2][0] = m1.m[0][0] * m2.m[2][0] + m1.m[1][0] * m2.m[2][1] + m1.m[2][0] * m2.m[2][2]; 1101 | result.m[2][1] = m1.m[0][1] * m2.m[2][0] + m1.m[1][1] * m2.m[2][1] + m1.m[2][1] * m2.m[2][2]; 1102 | result.m[2][2] = m1.m[0][2] * m2.m[2][0] + m1.m[1][2] * m2.m[2][1] + m1.m[2][2] * m2.m[2][2]; 1103 | 1104 | return result; 1105 | } 1106 | 1107 | inline mat4 operator*(const mat4& m1, const mat4& m2) 1108 | { 1109 | mat4 result; 1110 | 1111 | #if QM_USE_SSE 1112 | 1113 | result.packed[0] = mat4_mult_column_sse(m2.packed[0], m1); 1114 | result.packed[1] = mat4_mult_column_sse(m2.packed[1], m1); 1115 | result.packed[2] = mat4_mult_column_sse(m2.packed[2], m1); 1116 | result.packed[3] = mat4_mult_column_sse(m2.packed[3], m1); 1117 | 1118 | #else 1119 | 1120 | result.m[0][0] = m1.m[0][0] * m2.m[0][0] + m1.m[1][0] * m2.m[0][1] + m1.m[2][0] * m2.m[0][2] + m1.m[3][0] * m2.m[0][3]; 1121 | result.m[0][1] = m1.m[0][1] * m2.m[0][0] + m1.m[1][1] * m2.m[0][1] + m1.m[2][1] * m2.m[0][2] + m1.m[3][1] * m2.m[0][3]; 1122 | result.m[0][2] = m1.m[0][2] * m2.m[0][0] + m1.m[1][2] * m2.m[0][1] + m1.m[2][2] * m2.m[0][2] + m1.m[3][2] * m2.m[0][3]; 1123 | result.m[0][3] = m1.m[0][3] * m2.m[0][0] + m1.m[1][3] * m2.m[0][1] + m1.m[2][3] * m2.m[0][2] + m1.m[3][3] * m2.m[0][3]; 1124 | result.m[1][0] = m1.m[0][0] * m2.m[1][0] + m1.m[1][0] * m2.m[1][1] + m1.m[2][0] * m2.m[1][2] + m1.m[3][0] * m2.m[1][3]; 1125 | result.m[1][1] = m1.m[0][1] * m2.m[1][0] + m1.m[1][1] * m2.m[1][1] + m1.m[2][1] * m2.m[1][2] + m1.m[3][1] * m2.m[1][3]; 1126 | result.m[1][2] = m1.m[0][2] * m2.m[1][0] + m1.m[1][2] * m2.m[1][1] + m1.m[2][2] * m2.m[1][2] + m1.m[3][2] * m2.m[1][3]; 1127 | result.m[1][3] = m1.m[0][3] * m2.m[1][0] + m1.m[1][3] * m2.m[1][1] + m1.m[2][3] * m2.m[1][2] + m1.m[3][3] * m2.m[1][3]; 1128 | result.m[2][0] = m1.m[0][0] * m2.m[2][0] + m1.m[1][0] * m2.m[2][1] + m1.m[2][0] * m2.m[2][2] + m1.m[3][0] * m2.m[2][3]; 1129 | result.m[2][1] = m1.m[0][1] * m2.m[2][0] + m1.m[1][1] * m2.m[2][1] + m1.m[2][1] * m2.m[2][2] + m1.m[3][1] * m2.m[2][3]; 1130 | result.m[2][2] = m1.m[0][2] * m2.m[2][0] + m1.m[1][2] * m2.m[2][1] + m1.m[2][2] * m2.m[2][2] + m1.m[3][2] * m2.m[2][3]; 1131 | result.m[2][3] = m1.m[0][3] * m2.m[2][0] + m1.m[1][3] * m2.m[2][1] + m1.m[2][3] * m2.m[2][2] + m1.m[3][3] * m2.m[2][3]; 1132 | result.m[3][0] = m1.m[0][0] * m2.m[3][0] + m1.m[1][0] * m2.m[3][1] + m1.m[2][0] * m2.m[3][2] + m1.m[3][0] * m2.m[3][3]; 1133 | result.m[3][1] = m1.m[0][1] * m2.m[3][0] + m1.m[1][1] * m2.m[3][1] + m1.m[2][1] * m2.m[3][2] + m1.m[3][1] * m2.m[3][3]; 1134 | result.m[3][2] = m1.m[0][2] * m2.m[3][0] + m1.m[1][2] * m2.m[3][1] + m1.m[2][2] * m2.m[3][2] + m1.m[3][2] * m2.m[3][3]; 1135 | result.m[3][3] = m1.m[0][3] * m2.m[3][0] + m1.m[1][3] * m2.m[3][1] + m1.m[2][3] * m2.m[3][2] + m1.m[3][3] * m2.m[3][3]; 1136 | 1137 | #endif 1138 | 1139 | return result; 1140 | } 1141 | 1142 | inline vec3 operator*(const mat3& m, const vec3& v) 1143 | { 1144 | vec3 result; 1145 | 1146 | result.x = m.m[0][0] * v.x + m.m[1][0] * v.y + m.m[2][0] * v.z; 1147 | result.y = m.m[0][1] * v.x + m.m[1][1] * v.y + m.m[2][1] * v.z; 1148 | result.z = m.m[0][2] * v.x + m.m[1][2] * v.y + m.m[2][2] * v.z; 1149 | 1150 | return result; 1151 | } 1152 | 1153 | inline vec4 operator*(const mat4& m, const vec4& v) 1154 | { 1155 | vec4 result; 1156 | 1157 | #if QM_USE_SSE 1158 | 1159 | result.packed = mat4_mult_column_sse(v.packed, m); 1160 | 1161 | #else 1162 | 1163 | result.x = m.m[0][0] * v.x + m.m[1][0] * v.y + m.m[2][0] * v.z + m.m[3][0] * v.w; 1164 | result.y = m.m[0][1] * v.x + m.m[1][1] * v.y + m.m[2][1] * v.z + m.m[3][1] * v.w; 1165 | result.z = m.m[0][2] * v.x + m.m[1][2] * v.y + m.m[2][2] * v.z + m.m[3][2] * v.w; 1166 | result.w = m.m[0][3] * v.x + m.m[1][3] * v.y + m.m[2][3] * v.z + m.m[3][3] * v.w; 1167 | 1168 | #endif 1169 | 1170 | return result; 1171 | } 1172 | 1173 | //transpose: 1174 | 1175 | inline mat3 transpose(const mat3& m) 1176 | { 1177 | mat3 result; 1178 | 1179 | result.m[0][0] = m.m[0][0]; 1180 | result.m[0][1] = m.m[1][0]; 1181 | result.m[0][2] = m.m[2][0]; 1182 | result.m[1][0] = m.m[0][1]; 1183 | result.m[1][1] = m.m[1][1]; 1184 | result.m[1][2] = m.m[2][1]; 1185 | result.m[2][0] = m.m[0][2]; 1186 | result.m[2][1] = m.m[1][2]; 1187 | result.m[2][2] = m.m[2][2]; 1188 | 1189 | return result; 1190 | } 1191 | 1192 | inline mat4 transpose(const mat4& m) 1193 | { 1194 | mat4 result = m; 1195 | 1196 | #if QM_USE_SSE 1197 | 1198 | _MM_TRANSPOSE4_PS(result.packed[0], result.packed[1], result.packed[2], result.packed[3]); 1199 | 1200 | #else 1201 | 1202 | result.m[0][0] = m.m[0][0]; 1203 | result.m[0][1] = m.m[1][0]; 1204 | result.m[0][2] = m.m[2][0]; 1205 | result.m[0][3] = m.m[3][0]; 1206 | result.m[1][0] = m.m[0][1]; 1207 | result.m[1][1] = m.m[1][1]; 1208 | result.m[1][2] = m.m[2][1]; 1209 | result.m[1][3] = m.m[3][1]; 1210 | result.m[2][0] = m.m[0][2]; 1211 | result.m[2][1] = m.m[1][2]; 1212 | result.m[2][2] = m.m[2][2]; 1213 | result.m[2][3] = m.m[3][2]; 1214 | result.m[3][0] = m.m[0][3]; 1215 | result.m[3][1] = m.m[1][3]; 1216 | result.m[3][2] = m.m[2][3]; 1217 | result.m[3][3] = m.m[3][3]; 1218 | 1219 | #endif 1220 | 1221 | return result; 1222 | } 1223 | 1224 | //inverse: 1225 | 1226 | inline mat3 inverse(const mat3& m) 1227 | { 1228 | mat3 result; 1229 | 1230 | float det; 1231 | float a = m.m[0][0], b = m.m[0][1], c = m.m[0][2], 1232 | d = m.m[1][0], e = m.m[1][1], f = m.m[1][2], 1233 | g = m.m[2][0], h = m.m[2][1], i = m.m[2][2]; 1234 | 1235 | result.m[0][0] = e * i - f * h; 1236 | result.m[0][1] = -(b * i - h * c); 1237 | result.m[0][2] = b * f - e * c; 1238 | result.m[1][0] = -(d * i - g * f); 1239 | result.m[1][1] = a * i - c * g; 1240 | result.m[1][2] = -(a * f - d * c); 1241 | result.m[2][0] = d * h - g * e; 1242 | result.m[2][1] = -(a * h - g * b); 1243 | result.m[2][2] = a * e - b * d; 1244 | 1245 | det = 1.0f / (a * result.m[0][0] + b * result.m[1][0] + c * result.m[2][0]); 1246 | 1247 | result.m[0][0] *= det; 1248 | result.m[0][1] *= det; 1249 | result.m[0][2] *= det; 1250 | result.m[1][0] *= det; 1251 | result.m[1][1] *= det; 1252 | result.m[1][2] *= det; 1253 | result.m[2][0] *= det; 1254 | result.m[2][1] *= det; 1255 | result.m[2][2] *= det; 1256 | 1257 | return result; 1258 | } 1259 | 1260 | inline mat4 inverse(const mat4& mat) 1261 | { 1262 | //TODO: this function is not SIMD optimized, figure out how to do it 1263 | 1264 | mat4 result; 1265 | 1266 | float tmp[6]; 1267 | float det; 1268 | float a = mat.m[0][0], b = mat.m[0][1], c = mat.m[0][2], d = mat.m[0][3], 1269 | e = mat.m[1][0], f = mat.m[1][1], g = mat.m[1][2], h = mat.m[1][3], 1270 | i = mat.m[2][0], j = mat.m[2][1], k = mat.m[2][2], l = mat.m[2][3], 1271 | m = mat.m[3][0], n = mat.m[3][1], o = mat.m[3][2], p = mat.m[3][3]; 1272 | 1273 | tmp[0] = k * p - o * l; 1274 | tmp[1] = j * p - n * l; 1275 | tmp[2] = j * o - n * k; 1276 | tmp[3] = i * p - m * l; 1277 | tmp[4] = i * o - m * k; 1278 | tmp[5] = i * n - m * j; 1279 | 1280 | result.m[0][0] = f * tmp[0] - g * tmp[1] + h * tmp[2]; 1281 | result.m[1][0] = -(e * tmp[0] - g * tmp[3] + h * tmp[4]); 1282 | result.m[2][0] = e * tmp[1] - f * tmp[3] + h * tmp[5]; 1283 | result.m[3][0] = -(e * tmp[2] - f * tmp[4] + g * tmp[5]); 1284 | 1285 | result.m[0][1] = -(b * tmp[0] - c * tmp[1] + d * tmp[2]); 1286 | result.m[1][1] = a * tmp[0] - c * tmp[3] + d * tmp[4]; 1287 | result.m[2][1] = -(a * tmp[1] - b * tmp[3] + d * tmp[5]); 1288 | result.m[3][1] = a * tmp[2] - b * tmp[4] + c * tmp[5]; 1289 | 1290 | tmp[0] = g * p - o * h; 1291 | tmp[1] = f * p - n * h; 1292 | tmp[2] = f * o - n * g; 1293 | tmp[3] = e * p - m * h; 1294 | tmp[4] = e * o - m * g; 1295 | tmp[5] = e * n - m * f; 1296 | 1297 | result.m[0][2] = b * tmp[0] - c * tmp[1] + d * tmp[2]; 1298 | result.m[1][2] = -(a * tmp[0] - c * tmp[3] + d * tmp[4]); 1299 | result.m[2][2] = a * tmp[1] - b * tmp[3] + d * tmp[5]; 1300 | result.m[3][2] = -(a * tmp[2] - b * tmp[4] + c * tmp[5]); 1301 | 1302 | tmp[0] = g * l - k * h; 1303 | tmp[1] = f * l - j * h; 1304 | tmp[2] = f * k - j * g; 1305 | tmp[3] = e * l - i * h; 1306 | tmp[4] = e * k - i * g; 1307 | tmp[5] = e * j - i * f; 1308 | 1309 | result.m[0][3] = -(b * tmp[0] - c * tmp[1] + d * tmp[2]); 1310 | result.m[1][3] = a * tmp[0] - c * tmp[3] + d * tmp[4]; 1311 | result.m[2][3] = -(a * tmp[1] - b * tmp[3] + d * tmp[5]); 1312 | result.m[3][3] = a * tmp[2] - b * tmp[4] + c * tmp[5]; 1313 | 1314 | det = 1.0f / (a * result.m[0][0] + b * result.m[1][0] 1315 | + c * result.m[2][0] + d * result.m[3][0]); 1316 | 1317 | #if QM_USE_SSE 1318 | 1319 | __m128 scale = _mm_set1_ps(det); 1320 | result.packed[0] = _mm_mul_ps(result.packed[0], scale); 1321 | result.packed[1] = _mm_mul_ps(result.packed[1], scale); 1322 | result.packed[2] = _mm_mul_ps(result.packed[2], scale); 1323 | result.packed[3] = _mm_mul_ps(result.packed[3], scale); 1324 | 1325 | #else 1326 | 1327 | result.m[0][0] = result.m[0][0] * det; 1328 | result.m[0][1] = result.m[0][1] * det; 1329 | result.m[0][2] = result.m[0][2] * det; 1330 | result.m[0][3] = result.m[0][3] * det; 1331 | result.m[1][0] = result.m[1][0] * det; 1332 | result.m[1][1] = result.m[1][1] * det; 1333 | result.m[1][2] = result.m[1][2] * det; 1334 | result.m[1][3] = result.m[1][3] * det; 1335 | result.m[2][0] = result.m[2][0] * det; 1336 | result.m[2][1] = result.m[2][1] * det; 1337 | result.m[2][2] = result.m[2][2] * det; 1338 | result.m[2][3] = result.m[2][3] * det; 1339 | result.m[3][0] = result.m[3][0] * det; 1340 | result.m[3][1] = result.m[3][1] * det; 1341 | result.m[3][2] = result.m[3][2] * det; 1342 | result.m[3][3] = result.m[3][3] * det; 1343 | 1344 | #endif 1345 | 1346 | return result; 1347 | } 1348 | 1349 | //translation: 1350 | 1351 | inline mat3 translate(const vec2& t) 1352 | { 1353 | mat3 result = mat3_identity(); 1354 | 1355 | result.m[2][0] = t.x; 1356 | result.m[2][1] = t.y; 1357 | 1358 | return result; 1359 | } 1360 | 1361 | inline mat4 translate(const vec3& t) 1362 | { 1363 | mat4 result = mat4_identity(); 1364 | 1365 | result.m[3][0] = t.x; 1366 | result.m[3][1] = t.y; 1367 | result.m[3][2] = t.z; 1368 | 1369 | return result; 1370 | } 1371 | 1372 | //scaling: 1373 | 1374 | inline mat3 scale(const vec2& s) 1375 | { 1376 | mat3 result = mat3_identity(); 1377 | 1378 | result.m[0][0] = s.x; 1379 | result.m[1][1] = s.y; 1380 | 1381 | return result; 1382 | } 1383 | 1384 | inline mat4 scale(const vec3& s) 1385 | { 1386 | mat4 result = mat4_identity(); 1387 | 1388 | result.m[0][0] = s.x; 1389 | result.m[1][1] = s.y; 1390 | result.m[2][2] = s.z; 1391 | 1392 | return result; 1393 | } 1394 | 1395 | //rotation: 1396 | 1397 | inline mat3 rotate(float angle) 1398 | { 1399 | mat3 result = mat3_identity(); 1400 | 1401 | float radians = deg_to_rad(angle); 1402 | float sine = QM_SINF(radians); 1403 | float cosine = QM_COSF(radians); 1404 | 1405 | result.m[0][0] = cosine; 1406 | result.m[1][0] = sine; 1407 | result.m[0][1] = -sine; 1408 | result.m[1][1] = cosine; 1409 | 1410 | return result; 1411 | } 1412 | 1413 | inline mat4 rotate(const vec3& axis, float angle) 1414 | { 1415 | mat4 result = mat4_identity(); 1416 | 1417 | vec3 normalized = normalize(axis); 1418 | 1419 | float radians = deg_to_rad(angle); 1420 | float sine = QM_SINF(radians); 1421 | float cosine = QM_COSF(radians); 1422 | float cosine2 = 1.0f - cosine; 1423 | 1424 | result.m[0][0] = normalized.x * normalized.x * cosine2 + cosine; 1425 | result.m[0][1] = normalized.x * normalized.y * cosine2 + normalized.z * sine; 1426 | result.m[0][2] = normalized.x * normalized.z * cosine2 - normalized.y * sine; 1427 | result.m[1][0] = normalized.y * normalized.x * cosine2 - normalized.z * sine; 1428 | result.m[1][1] = normalized.y * normalized.y * cosine2 + cosine; 1429 | result.m[1][2] = normalized.y * normalized.z * cosine2 + normalized.x * sine; 1430 | result.m[2][0] = normalized.z * normalized.x * cosine2 + normalized.y * sine; 1431 | result.m[2][1] = normalized.z * normalized.y * cosine2 - normalized.x * sine; 1432 | result.m[2][2] = normalized.z * normalized.z * cosine2 + cosine; 1433 | 1434 | return result; 1435 | } 1436 | 1437 | inline mat4 rotate(const vec3& euler) 1438 | { 1439 | mat4 result = mat4_identity(); 1440 | 1441 | vec3 radians; 1442 | radians.x = deg_to_rad(euler.x); 1443 | radians.y = deg_to_rad(euler.y); 1444 | radians.z = deg_to_rad(euler.z); 1445 | 1446 | float sinX = QM_SINF(radians.x); 1447 | float cosX = QM_COSF(radians.x); 1448 | float sinY = QM_SINF(radians.y); 1449 | float cosY = QM_COSF(radians.y); 1450 | float sinZ = QM_SINF(radians.z); 1451 | float cosZ = QM_COSF(radians.z); 1452 | 1453 | result.m[0][0] = cosY * cosZ; 1454 | result.m[0][1] = cosY * sinZ; 1455 | result.m[0][2] = -sinY; 1456 | result.m[1][0] = sinX * sinY * cosZ - cosX * sinZ; 1457 | result.m[1][1] = sinX * sinY * sinZ + cosX * cosZ; 1458 | result.m[1][2] = sinX * cosY; 1459 | result.m[2][0] = cosX * sinY * cosZ + sinX * sinZ; 1460 | result.m[2][1] = cosX * sinY * sinZ - sinX * cosZ; 1461 | result.m[2][2] = cosX * cosY; 1462 | 1463 | return result; 1464 | } 1465 | 1466 | //to mat3: 1467 | 1468 | inline mat3 top_left(const mat4& m) 1469 | { 1470 | mat3 result; 1471 | 1472 | result.m[0][0] = m.m[0][0]; 1473 | result.m[0][1] = m.m[0][1]; 1474 | result.m[0][2] = m.m[0][2]; 1475 | result.m[1][0] = m.m[1][0]; 1476 | result.m[1][1] = m.m[1][1]; 1477 | result.m[1][2] = m.m[1][2]; 1478 | result.m[2][0] = m.m[2][0]; 1479 | result.m[2][1] = m.m[2][1]; 1480 | result.m[2][2] = m.m[2][2]; 1481 | 1482 | return result; 1483 | } 1484 | 1485 | //projection: 1486 | 1487 | inline mat4 perspective(float fov, float aspect, float near, float far) 1488 | { 1489 | mat4 result; 1490 | 1491 | float scale = QM_TANF(deg_to_rad(fov * 0.5f)) * near; 1492 | 1493 | float right = aspect * scale; 1494 | float left = -right; 1495 | float top = scale; 1496 | float bot = -top; 1497 | 1498 | result.m[0][0] = near / right; 1499 | result.m[1][1] = near / top; 1500 | result.m[2][2] = -(far + near) / (far - near); 1501 | result.m[3][2] = -2.0f * far * near / (far - near); 1502 | result.m[2][3] = -1.0f; 1503 | 1504 | return result; 1505 | } 1506 | 1507 | inline mat4 orthographic(float left, float right, float bot, float top, float near, float far) 1508 | { 1509 | mat4 result = mat4_identity(); 1510 | 1511 | result.m[0][0] = 2.0f / (right - left); 1512 | result.m[1][1] = 2.0f / (top - bot); 1513 | result.m[2][2] = 2.0f / (near - far); 1514 | 1515 | result.m[3][0] = (left + right) / (left - right); 1516 | result.m[3][1] = (bot + top ) / (bot - top ); 1517 | result.m[3][2] = (near + far ) / (near - far ); 1518 | 1519 | return result; 1520 | } 1521 | 1522 | //view matrix: 1523 | 1524 | inline mat4 look(const vec3& pos, const vec3& dir, const vec3& up) 1525 | { 1526 | mat4 result; 1527 | 1528 | vec3 r = normalize(cross(up, dir)); 1529 | vec3 u = cross(dir, r); 1530 | 1531 | mat4 RUD = mat4_identity(); 1532 | RUD.m[0][0] = r.x; 1533 | RUD.m[1][0] = r.y; 1534 | RUD.m[2][0] = r.z; 1535 | RUD.m[0][1] = u.x; 1536 | RUD.m[1][1] = u.y; 1537 | RUD.m[2][1] = u.z; 1538 | RUD.m[0][2] = dir.x; 1539 | RUD.m[1][2] = dir.y; 1540 | RUD.m[2][2] = dir.z; 1541 | 1542 | vec3 oppPos = {-pos.x, -pos.y, -pos.z}; 1543 | result = RUD * translate(oppPos); 1544 | 1545 | return result; 1546 | } 1547 | 1548 | inline mat4 lookat(const vec3& pos, const vec3& target, const vec3& up) 1549 | { 1550 | mat4 result; 1551 | 1552 | vec3 dir = normalize(pos - target); 1553 | result = look(pos, dir, up); 1554 | 1555 | return result; 1556 | } 1557 | 1558 | //----------------------------------------------------------------------// 1559 | //QUATERNION FUNCTIONS: 1560 | 1561 | #if QM_INCLUDE_IOSTREAM 1562 | 1563 | inline std::ostream& operator<<(std::ostream& os, const quaternion& q) 1564 | { 1565 | os << q.x << ", " << q.y << ", " << q.z << ", " << q.w; 1566 | return os; 1567 | } 1568 | 1569 | inline std::istream& operator>>(std::istream& is, quaternion& q) 1570 | { 1571 | is >> q.x >> q.y >> q.z >> q.w; 1572 | return is; 1573 | } 1574 | 1575 | #endif 1576 | 1577 | inline quaternion quaternion_identity() 1578 | { 1579 | quaternion result; 1580 | 1581 | result.x = 0.0f; 1582 | result.y = 0.0f; 1583 | result.z = 0.0f; 1584 | result.w = 1.0f; 1585 | 1586 | return result; 1587 | } 1588 | 1589 | inline quaternion operator+(const quaternion& q1, const quaternion& q2) 1590 | { 1591 | quaternion result; 1592 | 1593 | #if QM_USE_SSE 1594 | 1595 | result.packed = _mm_add_ps(q1.packed, q2.packed); 1596 | 1597 | #else 1598 | 1599 | result.x = q1.x + q2.x; 1600 | result.y = q1.y + q2.y; 1601 | result.z = q1.z + q2.z; 1602 | result.w = q1.w + q2.w; 1603 | 1604 | #endif 1605 | 1606 | return result; 1607 | } 1608 | 1609 | inline quaternion operator-(const quaternion& q1, const quaternion& q2) 1610 | { 1611 | quaternion result; 1612 | 1613 | #if QM_USE_SSE 1614 | 1615 | result.packed = _mm_sub_ps(q1.packed, q2.packed); 1616 | 1617 | #else 1618 | 1619 | result.x = q1.x - q2.x; 1620 | result.y = q1.y - q2.y; 1621 | result.z = q1.z - q2.z; 1622 | result.w = q1.w - q2.w; 1623 | 1624 | #endif 1625 | 1626 | return result; 1627 | } 1628 | 1629 | inline quaternion operator*(const quaternion& q1, const quaternion& q2) 1630 | { 1631 | quaternion result; 1632 | 1633 | #if QM_USE_SSE 1634 | 1635 | __m128 temp1; 1636 | __m128 temp2; 1637 | 1638 | temp1 = _mm_shuffle_ps(q1.packed, q1.packed, _MM_SHUFFLE(3, 3, 3, 3)); 1639 | temp2 = q2.packed; 1640 | result.packed = _mm_mul_ps(temp1, temp2); 1641 | 1642 | temp1 = _mm_xor_ps(_mm_shuffle_ps(q1.packed, q1.packed, _MM_SHUFFLE(0, 0, 0, 0)), _mm_setr_ps(0.0f, -0.0f, 0.0f, -0.0f)); 1643 | temp2 = _mm_shuffle_ps(q2.packed, q2.packed, _MM_SHUFFLE(0, 1, 2, 3)); 1644 | result.packed = _mm_add_ps(result.packed, _mm_mul_ps(temp1, temp2)); 1645 | 1646 | temp1 = _mm_xor_ps(_mm_shuffle_ps(q1.packed, q1.packed, _MM_SHUFFLE(1, 1, 1, 1)), _mm_setr_ps(0.0f, 0.0f, -0.0f, -0.0f)); 1647 | temp2 = _mm_shuffle_ps(q2.packed, q2.packed, _MM_SHUFFLE(1, 0, 3, 2)); 1648 | result.packed = _mm_add_ps(result.packed, _mm_mul_ps(temp1, temp2)); 1649 | 1650 | temp1 = _mm_xor_ps(_mm_shuffle_ps(q1.packed, q1.packed, _MM_SHUFFLE(2, 2, 2, 2)), _mm_setr_ps(-0.0f, 0.0f, 0.0f, -0.0f)); 1651 | temp2 = _mm_shuffle_ps(q2.packed, q2.packed, _MM_SHUFFLE(2, 3, 0, 1)); 1652 | result.packed = _mm_add_ps(result.packed, _mm_mul_ps(temp1, temp2)); 1653 | 1654 | #else 1655 | 1656 | result.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y; 1657 | result.y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x; 1658 | result.z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w; 1659 | result.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z; 1660 | 1661 | #endif 1662 | 1663 | return result; 1664 | } 1665 | 1666 | inline quaternion operator*(const quaternion& q, float s) 1667 | { 1668 | quaternion result; 1669 | 1670 | #if QM_USE_SSE 1671 | 1672 | __m128 scale = _mm_set1_ps(s); 1673 | result.packed = _mm_mul_ps(q.packed, scale); 1674 | 1675 | #else 1676 | 1677 | result.x = q.x * s; 1678 | result.y = q.y * s; 1679 | result.z = q.z * s; 1680 | result.w = q.w * s; 1681 | 1682 | #endif 1683 | 1684 | return result; 1685 | } 1686 | 1687 | inline quaternion operator*(float s, const quaternion& q) 1688 | { 1689 | return q * s; 1690 | } 1691 | 1692 | inline quaternion operator/(const quaternion& q, float s) 1693 | { 1694 | quaternion result; 1695 | 1696 | #if QM_USE_SSE 1697 | 1698 | __m128 scale = _mm_set1_ps(s); 1699 | result.packed = _mm_div_ps(q.packed, scale); 1700 | 1701 | #else 1702 | 1703 | result.x = q.x / s; 1704 | result.y = q.y / s; 1705 | result.z = q.z / s; 1706 | result.w = q.w / s; 1707 | 1708 | #endif 1709 | 1710 | return result; 1711 | } 1712 | 1713 | inline quaternion operator/(float s, const quaternion& q) 1714 | { 1715 | quaternion result; 1716 | 1717 | #if QM_USE_SSE 1718 | 1719 | __m128 scale = _mm_set1_ps(s); 1720 | result.packed = _mm_div_ps(scale, q.packed); 1721 | 1722 | #else 1723 | 1724 | result.x = s / q.x; 1725 | result.y = s / q.y; 1726 | result.z = s / q.z; 1727 | result.w = s / q.w; 1728 | 1729 | #endif 1730 | 1731 | return result; 1732 | } 1733 | 1734 | inline float dot(const quaternion& q1, const quaternion& q2) 1735 | { 1736 | float result; 1737 | 1738 | #if QM_USE_SSE 1739 | 1740 | __m128 r = _mm_mul_ps(q1.packed, q2.packed); 1741 | r = _mm_hadd_ps(r, r); 1742 | r = _mm_hadd_ps(r, r); 1743 | _mm_store_ss(&result, r); 1744 | 1745 | #else 1746 | 1747 | result = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; 1748 | 1749 | #endif 1750 | 1751 | return result; 1752 | } 1753 | 1754 | inline float length(const quaternion& q) 1755 | { 1756 | float result; 1757 | 1758 | result = QM_SQRTF(dot(q, q)); 1759 | 1760 | return result; 1761 | } 1762 | 1763 | inline quaternion normalize(const quaternion& q) 1764 | { 1765 | quaternion result; 1766 | 1767 | float len = length(q); 1768 | if(len != 0.0f) 1769 | result = q / len; 1770 | 1771 | return result; 1772 | } 1773 | 1774 | inline quaternion conjugate(const quaternion& q) 1775 | { 1776 | quaternion result; 1777 | 1778 | result.x = -q.x; 1779 | result.y = -q.y; 1780 | result.z = -q.z; 1781 | result.w = q.w; 1782 | 1783 | return result; 1784 | } 1785 | 1786 | inline quaternion inverse(const quaternion& q) 1787 | { 1788 | quaternion result; 1789 | 1790 | result.x = -q.x; 1791 | result.y = -q.y; 1792 | result.z = -q.z; 1793 | result.w = q.w; 1794 | 1795 | #if QM_USE_SSE 1796 | 1797 | __m128 scale = _mm_set1_ps(dot(q, q)); 1798 | _mm_div_ps(result.packed, scale); 1799 | 1800 | #else 1801 | 1802 | float invLen2 = 1.0f / QM_PREFIX(quaternion_dot)(q, q); 1803 | 1804 | result.x *= invLen2; 1805 | result.y *= invLen2; 1806 | result.z *= invLen2; 1807 | result.w *= invLen2; 1808 | 1809 | #endif 1810 | 1811 | return result; 1812 | } 1813 | 1814 | inline quaternion slerp(const quaternion& q1, const quaternion& q2, float a) 1815 | { 1816 | quaternion result; 1817 | 1818 | float cosine = dot(q1, q2); 1819 | float angle = QM_ACOSF(cosine); 1820 | 1821 | float sine1 = QM_SINF((1.0f - a) * angle); 1822 | float sine2 = QM_SINF(a * angle); 1823 | float invSine = 1.0f / QM_SINF(angle); 1824 | 1825 | quaternion q1scaled = q1 * sine1; 1826 | quaternion q2scaled = q2 * sine2; 1827 | 1828 | result = q1scaled + q2scaled; 1829 | result = result * invSine; 1830 | 1831 | return result; 1832 | } 1833 | 1834 | inline bool operator==(const quaternion& q1, const quaternion& q2) 1835 | { 1836 | bool result; 1837 | 1838 | //TODO: there are SIMD instructions for floating point equality, find a way to get a single bool from them 1839 | result = (q1.x == q2.x) && (q1.y == q2.y) && (q1.z == q2.z) && (q1.w == q2.w); 1840 | 1841 | return result; 1842 | } 1843 | 1844 | inline bool operator!=(const quaternion& q1, const quaternion& q2) 1845 | { 1846 | bool result; 1847 | 1848 | result = (q1.x != q2.x) || (q1.y != q2.y) || (q1.z != q2.z) || (q1.w != q2.w); 1849 | 1850 | return result; 1851 | } 1852 | 1853 | inline quaternion quaternion_from_axis_angle(const vec3& axis, float angle) 1854 | { 1855 | quaternion result; 1856 | 1857 | float radians = deg_to_rad(angle * 0.5f); 1858 | vec3 normalized = normalize(axis); 1859 | float sine = QM_SINF(radians); 1860 | 1861 | result.x = normalized.x * sine; 1862 | result.y = normalized.y * sine; 1863 | result.z = normalized.z * sine; 1864 | result.w = QM_COSF(radians); 1865 | 1866 | return result; 1867 | } 1868 | 1869 | inline quaternion quaternion_from_euler(const vec3& angles) 1870 | { 1871 | quaternion result; 1872 | 1873 | vec3 radians; 1874 | radians.x = deg_to_rad(angles.x * 0.5f); 1875 | radians.y = deg_to_rad(angles.y * 0.5f); 1876 | radians.z = deg_to_rad(angles.z * 0.5f); 1877 | 1878 | float sinx = QM_SINF(radians.x); 1879 | float cosx = QM_COSF(radians.x); 1880 | float siny = QM_SINF(radians.y); 1881 | float cosy = QM_COSF(radians.y); 1882 | float sinz = QM_SINF(radians.z); 1883 | float cosz = QM_COSF(radians.z); 1884 | 1885 | #if QM_USE_SSE 1886 | 1887 | __m128 packedx = _mm_setr_ps(sinx, cosx, cosx, cosx); 1888 | __m128 packedy = _mm_setr_ps(cosy, siny, cosy, cosy); 1889 | __m128 packedz = _mm_setr_ps(cosz, cosz, sinz, cosz); 1890 | 1891 | result.packed = _mm_mul_ps(_mm_mul_ps(packedx, packedy), packedz); 1892 | 1893 | packedx = _mm_shuffle_ps(packedx, packedx, _MM_SHUFFLE(0, 0, 0, 1)); 1894 | packedy = _mm_shuffle_ps(packedy, packedy, _MM_SHUFFLE(1, 1, 0, 1)); 1895 | packedz = _mm_shuffle_ps(packedz, packedz, _MM_SHUFFLE(2, 0, 2, 2)); 1896 | 1897 | result.packed = _mm_addsub_ps(result.packed, _mm_mul_ps(_mm_mul_ps(packedx, packedy), packedz)); 1898 | 1899 | #else 1900 | 1901 | result.x = sinx * cosy * cosz - cosx * siny * sinz; 1902 | result.y = cosx * siny * cosz + sinx * cosy * sinz; 1903 | result.z = cosx * cosy * sinz - sinx * siny * cosz; 1904 | result.w = cosx * cosy * cosz + sinx * siny * sinz; 1905 | 1906 | #endif 1907 | 1908 | return result; 1909 | } 1910 | 1911 | inline mat4 quaternion_to_mat4(const quaternion& q) 1912 | { 1913 | mat4 result = mat4_identity(); 1914 | 1915 | float x2 = q.x + q.x; 1916 | float y2 = q.y + q.y; 1917 | float z2 = q.z + q.z; 1918 | float xx2 = q.x * x2; 1919 | float xy2 = q.x * y2; 1920 | float xz2 = q.x * z2; 1921 | float yy2 = q.y * y2; 1922 | float yz2 = q.y * z2; 1923 | float zz2 = q.z * z2; 1924 | float sx2 = q.w * x2; 1925 | float sy2 = q.w * y2; 1926 | float sz2 = q.w * z2; 1927 | 1928 | result.m[0][0] = 1.0f - (yy2 + zz2); 1929 | result.m[0][1] = xy2 - sz2; 1930 | result.m[0][2] = xz2 + sy2; 1931 | result.m[1][0] = xy2 + sz2; 1932 | result.m[1][1] = 1.0f - (xx2 + zz2); 1933 | result.m[1][2] = yz2 - sx2; 1934 | result.m[2][0] = xz2 - sy2; 1935 | result.m[2][1] = yz2 + sx2; 1936 | result.m[2][2] = 1.0f - (xx2 + yy2); 1937 | 1938 | return result; 1939 | } 1940 | 1941 | }; //namespace qm 1942 | 1943 | #endif //QM_MATH_H --------------------------------------------------------------------------------