// if you touch something in here and stuff breaks, it is COMPLETELY your fault

#pragma once
#ifdef BUILDING_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif

#include <iostream>
#include <any>
#include <functional>
#include <string>
#include <unordered_map>

typedef std::function<void(std::vector<std::any>)> func;
typedef std::function<std::any(std::vector<std::any>)> op;

extern "C" DLL_EXPORT void init();
extern "C" DLL_EXPORT void tick();
extern "C" DLL_EXPORT void define_func(std::string name, func f);
extern "C" DLL_EXPORT void define_op(std::string name, op o);

std::unordered_map<std::string, func> bridge_funcs;
std::unordered_map<std::string, op> bridge_ops;
void define_func(std::string name, func f) {bridge_funcs[name] = f;}
void define_op(std::string name, op o) {bridge_ops[name] = o;}

// Function calling
#define f(name, params) bridge_funcs[#name](params)

// Operator calling
#define o(type, name, params) std::any_cast<type>(bridge_ops[#name](params))

#define COMMA ,

typedef enum {
    KEY_NULL            = 0,
    KEY_APOSTROPHE      = 39,
    KEY_COMMA           = 44,
    KEY_MINUS           = 45,
    KEY_PERIOD          = 46,
    KEY_SLASH           = 47,
    KEY_ZERO            = 48,
    KEY_ONE             = 49,
    KEY_TWO             = 50,
    KEY_THREE           = 51,
    KEY_FOUR            = 52,
    KEY_FIVE            = 53,
    KEY_SIX             = 54,
    KEY_SEVEN           = 55,
    KEY_EIGHT           = 56,
    KEY_NINE            = 57,
    KEY_SEMICOLON       = 59,
    KEY_EQUAL           = 61,
    KEY_A               = 65,
    KEY_B               = 66,
    KEY_C               = 67,
    KEY_D               = 68,
    KEY_E               = 69,
    KEY_F               = 70,
    KEY_G               = 71,
    KEY_H               = 72,
    KEY_I               = 73,
    KEY_J               = 74,
    KEY_K               = 75,
    KEY_L               = 76,
    KEY_M               = 77,
    KEY_N               = 78,
    KEY_O               = 79,
    KEY_P               = 80,
    KEY_Q               = 81,
    KEY_R               = 82,
    KEY_S               = 83,
    KEY_T               = 84,
    KEY_U               = 85,
    KEY_V               = 86,
    KEY_W               = 87,
    KEY_X               = 88,
    KEY_Y               = 89,
    KEY_Z               = 90,
    KEY_LEFT_BRACKET    = 91,
    KEY_BACKSLASH       = 92,
    KEY_RIGHT_BRACKET   = 93,
    KEY_GRAVE           = 96,
    KEY_SPACE           = 32,
    KEY_ESCAPE          = 256,
    KEY_ENTER           = 257,
    KEY_TAB             = 258,
    KEY_BACKSPACE       = 259,
    KEY_INSERT          = 260,
    KEY_DELETE          = 261,
    KEY_RIGHT           = 262,
    KEY_LEFT            = 263,
    KEY_DOWN            = 264,
    KEY_UP              = 265,
    KEY_PAGE_UP         = 266,
    KEY_PAGE_DOWN       = 267,
    KEY_HOME            = 268,
    KEY_END             = 269,
    KEY_CAPS_LOCK       = 280,
    KEY_SCROLL_LOCK     = 281,
    KEY_NUM_LOCK        = 282,
    KEY_PRINT_SCREEN    = 283,
    KEY_PAUSE           = 284,
    KEY_F1              = 290,
    KEY_F2              = 291,
    KEY_F3              = 292,
    KEY_F4              = 293,
    KEY_F5              = 294,
    KEY_F6              = 295,
    KEY_F7              = 296,
    KEY_F8              = 297,
    KEY_F9              = 298,
    KEY_F10             = 299,
    KEY_F11             = 300,
    KEY_F12             = 301,
    KEY_LEFT_SHIFT      = 340,
    KEY_LEFT_CONTROL    = 341,
    KEY_LEFT_ALT        = 342,
    KEY_LEFT_SUPER      = 343,
    KEY_RIGHT_SHIFT     = 344,
    KEY_RIGHT_CONTROL   = 345,
    KEY_RIGHT_ALT       = 346,
    KEY_RIGHT_SUPER     = 347,
    KEY_KB_MENU         = 348,
    KEY_KP_0            = 320,
    KEY_KP_1            = 321,
    KEY_KP_2            = 322,
    KEY_KP_3            = 323,
    KEY_KP_4            = 324,
    KEY_KP_5            = 325,
    KEY_KP_6            = 326,
    KEY_KP_7            = 327,
    KEY_KP_8            = 328,
    KEY_KP_9            = 329,
    KEY_KP_DECIMAL      = 330,
    KEY_KP_DIVIDE       = 331,
    KEY_KP_MULTIPLY     = 332,
    KEY_KP_SUBTRACT     = 333,
    KEY_KP_ADD          = 334,
    KEY_KP_ENTER        = 335,
    KEY_KP_EQUAL        = 336,
    KEY_BACK            = 4,
    KEY_MENU            = 5,
    KEY_VOLUME_UP       = 24,
    KEY_VOLUME_DOWN     = 25
} KeyboardKey;

typedef enum {
    MOUSE_BUTTON_LEFT    = 0,
    MOUSE_BUTTON_RIGHT   = 1,
	MOUSE_BUTTON_MIDDLE  = 2,
    MOUSE_BUTTON_SIDE    = 3,
    MOUSE_BUTTON_EXTRA   = 4,
    MOUSE_BUTTON_FORWARD = 5,
    MOUSE_BUTTON_BACK    = 6,
} MouseButton;

typedef enum {
    MOUSE_CURSOR_DEFAULT       = 0,
    MOUSE_CURSOR_ARROW         = 1,
    MOUSE_CURSOR_IBEAM         = 2,
    MOUSE_CURSOR_CROSSHAIR     = 3,
    MOUSE_CURSOR_POINTING_HAND = 4,
    MOUSE_CURSOR_RESIZE_EW     = 5,
    MOUSE_CURSOR_RESIZE_NS     = 6,
    MOUSE_CURSOR_RESIZE_NWSE   = 7,
    MOUSE_CURSOR_RESIZE_NESW   = 8,
    MOUSE_CURSOR_RESIZE_ALL    = 9,
    MOUSE_CURSOR_NOT_ALLOWED   = 10
} MouseCursor;

namespace Game {
	
	// Base instance class. Don't use this.
	class Instance {
		public:
		
		int id;
		
		operator int() const { return id; }
		
		template <typename T>
		T GetParent() { return (T)o(int, Instance.GetParent, {id}); }
		void SetParent(int Parent) { f(Instance.SetParent, {id COMMA Parent}); }
		std::string GetName() { return o(std::string, Instance.GetName, {id}); }
		void SetName(std::string Name) { f(Instance.SetName, {id COMMA Name}); }
		void Destroy() { f(Instance.Destroy, {id}); }
		std::vector<std::string> GetChildren() {
			auto children = o(std::unordered_map<std::string COMMA int>, Instance.GetChildren, {id});
			std::vector<std::string> out;
			for (const auto child : children) out.push_back(child.first);
			return out;
		}
		template <typename T>
		T GetChild(std::string Name) { return (T)o(int, Instance.GetChild, {id COMMA Name}); }
		std::any* Get(std::string Name) { return o(std::any*, Instance.Get, {id COMMA Name}); }
		
		Instance (int x){
			id = x;
		}
		Instance (){}
	};
	class CFrame : public Instance {
		public:
		
		CFrame (int x) {
			id = x;
		} CFrame() {
			id = o(int, Instance.New, {std::string("CFrame")});
		}
		
		std::vector<float> RightVector() { return o(std::vector<float>, CFrame.RightVector, {Get("Value")}); }
		std::vector<float> UpVector() { return o(std::vector<float>, CFrame.UpVector, {Get("Value")}); }
		std::vector<float> LookVector() { return o(std::vector<float>, CFrame.LookVector, {Get("Value")}); }
		std::vector<float> Orientation() { return o(std::vector<float>, CFrame.Orientation, {Get("Value")}); }
		std::vector<float> Position() { return o(std::vector<float>, CFrame.Position, {Get("Value")}); }
		std::vector<float> Transform() { return o(std::vector<float>, CFrame.Transform, {Get("Value")}); }
		void RotateBy(std::vector<float> Angle) { f(CFrame.RotateBy, {Get("Value") COMMA Angle}); }
		void RotateTo(std::vector<float> Angle) { f(CFrame.RotateTo, {Get("Value") COMMA Angle}); }
		void MoveBy(std::vector<float> Offset) { f(CFrame.MoveBy, {Get("Value") COMMA Offset}); }
		void MoveTo(std::vector<float> Position) { f(CFrame.MoveTo, {Get("Value") COMMA Position}); }
	};
	class Model : public Instance {
		public:
		
		Model (int x) {
			id = x;
		} Model(std::string model) {
			id = o(int, Instance.New, {std::string("Model") COMMA model});
		}
		
		std::vector<float> RightVector() { return o(std::vector<float>, CFrame.RightVecotr, {Get("CFrame")}); }
		std::vector<float> UpVector() { return o(std::vector<float>, CFrame.UpVector, {Get("CFrame")}); }
		std::vector<float> LookVector() { return o(std::vector<float>, CFrame.LookVector, {Get("CFrame")}); }
		std::vector<float> Orientation() { return o(std::vector<float>, CFrame.Orientation, {Get("CFrame")}); }
		std::vector<float> Position() { return o(std::vector<float>, CFrame.Position, {Get("CFrame")}); }
		std::vector<float> Transform() { return o(std::vector<float>, CFrame.Transform, {Get("CFrame")}); }
		void RotateBy(std::vector<float> Angle) { f(CFrame.RotateBy, {Get("CFrame") COMMA Angle}); }
		void RotateTo(std::vector<float> Angle) { f(CFrame.RotateTo, {Get("CFrame") COMMA Angle}); }
		void MoveBy(std::vector<float> Offset) { f(CFrame.MoveBy, {Get("CFrame") COMMA Offset}); }
		void MoveTo(std::vector<float> Position) { f(CFrame.MoveTo, {Get("CFrame") COMMA Position}); }
		
		std::vector<float> GetScale() { return o(std::vector<float>, Model.GetScale, {id}); }
		void SetScale(std::vector<float> Scale) { f(Model.SetScale, {id COMMA Scale}); }
		int GetColor() { return o(int, Model.GetColor, {id}); }
		void SetColor(int Color) { f(Model.SetColor, {id COMMA Color}); }
		std::string GetModel() {return o(std::string, Model.GetModel, {id}); }
		void SetModel(std::string Model) { f(Model.SetModel, {id COMMA Model}); }
	};
	class Light : public Instance {
		public:
		
		Light (int x) {
			id = x;
		} Light(std::string Type) {
			id = o(int, Instance.New, {std::string("Light") COMMA Type});
		}
		
		std::string GetType() { return o(std::string, Light.GetType, {id}); }
		bool IsActive() { return o(bool, Light.IsActive, {id}); }
		void Toggle() { f(Light.Toggle, {id}); }
		void SetState(bool State) { f(Light.SetState, {id COMMA State}); }
		int GetColor() { return o(int, Light.GetColor, {id}); }
		void SetColor(int Color) { f(Light.SetColor, {id COMMA Color}); }
		std::vector<float> GetPosition() { return o(std::vector<float>, Light.GetPosition, {id}); }
		void SetPosition(std::vector<float> Position) { f(Light.SetPosition, {id COMMA Position}); }
		std::vector<float> GetDirection() { return o(std::vector<float>, Light.GetDirection, {id}); }
		void SetDirection(std::vector<float> Direction) { f(Light.SetDirection, {id COMMA Direction}); }
		float GetEnergy() { return o(float, Light.GetEnergy, {id}); }
		void SetEnergy(float Energy) { f(Light.SetEnergy, {id COMMA Energy}); }
		float GetSpecular() { return o(float, Light.GetSpecular, {id}); }
		void SetSpecular(float Specular) { f(Light.SetSpecular, {id COMMA Specular}); }
		float GetRange() { return o(float, Light.GetRange, {id}); }
		void SetRange(float Range) { f(Light.SetRange, {id COMMA Range}); }
		float GetAttenuation() { return o(float, Light.GetAttenuation, {id}); }
		void SetAttenuation(float Attenuation) { f(Light.SetAttenuation, {id COMMA Attenuation}); }
		float GetInnerCutoff() { return o(float, Light.GetInnerCutoff, {id}); }
		void SetInnerCutoff(float Cutoff) { f(Light.SetInnerCutoff, {id COMMA Cutoff}); }
		float GetOuterCutoff() { return o(float, Light.GetOuterCutoff, {id}); }
		void SetOuterCutoff(float Cutoff) { f(Light.SetOuterCutoff, {id COMMA Cutoff}); }
		void EnableShadow() { f(Light.EnableShadow, {id}); }
		void DisableShadow() { f(Light.DisableShadow, {id}); }
		bool IsShadowEnabled() { return o(bool, Light.IsShadowEnabled, {id}); }
		std::string GetShadowUpdateMode() { return o(std::string, Light.GetShadowUpdateMode, {id}); }
		void SetShadowUpdateMode(std::string Mode) { f(Light.SetShadowUpdateMode, {id COMMA Mode}); }
		int GetShadowUpdateFrequency() { return o(int, Light.GetShadowUpdateFrequency, {id}); }
		void SetShadowUpdateFrequency(int msec) { f(Light.SetShadowUpdateFrequency, {id COMMA msec}); }
		void UpdateShadow() { f(Light.UpdateShadow, {id}); }
		float GetSoftness() { return o(float, Light.GetSoftness, {id}); }
		void SetSoftness(float Softness) { f(Light.SetSoftness, {id COMMA Softness}); }
		float GetDepthBias() { return o(float, Light.GetDepthBias, {id}); }
		void SetDepthBias(float Bias) { f(Light.SetDepthBias, {id COMMA Bias}); }
		float GetSlopeBias() { return o(float, Light.GetSlopeBias, {id}); }
		void SetSlopeBias(float Bias) { f(Light.SetSlopeBias, {id COMMA Bias}); }
	};
	class RaycastSingle {
		public:
		
		bool hit;
		float distance;
		std::vector<float> point;
		std::vector<float> normal;
		
		RaycastSingle(Model model, std::vector<float> position, std::vector<float> direction) {
			auto collision = o(std::vector<std::any>, RaycastSingle, {model.id COMMA position COMMA direction});
			hit = std::any_cast<bool>(collision[0]);
			distance = std::any_cast<float>(collision[1]);
			point = std::any_cast<std::vector<float>>(collision[2]);
			normal = std::any_cast<std::vector<float>>(collision[3]);
		};
	};
	
	Instance Root(1);
	
	bool IsKeyPressed(int key) { return o(bool, IsKeyPressed, {key}); }
	bool IsKeyPressedRepeat(int key) { return o(bool, IsKeyPressedRepeat, {key}); }
	bool IsKeyDown(int key) { return o(bool, IsKeyDown, {key}); }
	bool IsKeyReleased(int key) { return o(bool, IsKeyReleased, {key}); }
	bool IsKeyUp(int key) { return o(bool, IsKeyUp, {key}); }
	int GetKeyPressed() { return o(int, GetKeyPressed, {}); }
	char GetCharPressed() { return o(int, GetCharPressed, {}); }
	void SetExitKey(int key) { f(SetExitKey, {key}); }
	
	bool IsMouseButtonPressed(int button) { return o(bool, IsMouseButtonPressed, {button}); }
	bool IsMouseButtonDown(int button) { return o(bool, IsMouseButtonDown, {button}); }
	bool IsMouseButtonReleased(int button) { return o(bool, IsMouseButtonReleased, {button}); }
	bool IsMouseButtonUp(int button) { return o(bool, IsMouseButtonUp, {button}); }
	int GetMouseX() { return o(int, GetMouseX, {}); }
	int GetMouseY() { return o(int, GetMouseY, {}); }
	auto GetMousePosition() { return o(std::vector<float>, GetMousePosition, {}); }
	auto GetMouseDelta() { return o(std::vector<float>, GetMouseDelta, {}); }
	void SetMousePosition(std::vector<float> Position) { f(SetMousePosition, {Position}); }
	void SetMouseOffset(std::vector<float> Offset) { f(SetMouseOffset, {Offset}); }
	auto GetMouseWheel() { return o(std::vector<float>, GetMouseWheel, {}); }
	void SetMouseCursor(int Cursor) { f(SetMouseCursor, {Cursor}); }
	void ShowCursor() { f(ShowCursor, {}); }
	void HideCursor() { f(HideCursor, {}); }
	auto IsCursorHidden() { return o(bool, IsCursorHidden, {}); }
	void EnableCursor() { f(EnableCursor, {}); }
	void DisableCursor() { f(DisableCursor, {}); }
	auto IsCursorOnScreen() { return o(bool, IsCursorOnScreen, {}); }
	
	void SetCameraLookDirection(std::vector<float> Direction) { f(SetCameraLookDirection, {Direction}); }
	void SetCameraUpDirection(std::vector<float> Direction) { f(SetCameraUpDirection, {Direction}); }
	void SetCameraPosition(std::vector<float> Position) { f(SetCameraPosition, {Position}); }
	void SetCameraFOV(float FOV) { f(SetCameraFOV, {FOV}); }
	
	float DeltaTime() { return o(float, DeltaTime, {}); }
	void LoadModel(std::string name, std::string path, int max) { f(LoadModel, {name COMMA path COMMA max}); }
	void UnloadModel(std::string name) { f(UnloadModel, {name}); }
	
	namespace Vector2 {
		auto Zero() {
			return o(std::vector<float>, Vector2Zero, {});
		}
		auto One() {
			return o(std::vector<float>, Vector2One, {});
		}
		auto Add(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector2Add, {v1 COMMA v2}); 
		}
		auto AddValue(std::vector<float> v, float add) {
			return o(std::vector<float>, Vector2AddValue, {v COMMA add});
		}
		auto Subtract(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector2Subtract, {v1 COMMA v2});
		}
		auto SubtractValue(std::vector<float> v, float sub) {
			return o(std::vector<float>, Vector2SubtractValue, {v COMMA sub});
		}
		auto Length(std::vector<float> v) {
			return o(float, Vector2Length, {v});
		}
		auto LengthSqr(std::vector<float> v) {
			return o(float, Vector2LengthSqr, {v});
		}
		auto DotProduct(std::vector<float> v1, std::vector<float> v2) {
			return o(float, Vector2DotProduct, {v1 COMMA v2});
		}
		auto Distance(std::vector<float> v1, std::vector<float> v2) {
			return o(float, Vector2Distance, {v1 COMMA v2});
		}
		auto DistanceSqr(std::vector<float> v1, std::vector<float> v2) {
			return o(float, Vector2DistanceSqr, {v1 COMMA v2});
		}
		auto Angle(std::vector<float> v1, std::vector<float> v2) {
			return o(float, Vector2Angle, {v1 COMMA v2});
		}
		auto LineAngle(std::vector<float> start, std::vector<float> end) {
			return o(float, Vector2LineAngle, {start COMMA end});
		}
		auto Scale(std::vector<float> v, float scale) {
			return o(std::vector<float>, Vector2Scale, {v COMMA scale});
		}
		auto Multiply(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector2Multiply, {v1 COMMA v2});
		}
		auto Negate(std::vector<float> v) {
			return o(std::vector<float>, Vector2Negate, {v});
		}
		auto Divide(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector2Divide, {v1 COMMA v2});
		}
		auto Normalize(std::vector<float> v) {
			return o(std::vector<float>, Vector2Normalize, {v});
		}
		auto Transform(std::vector<float> v, std::vector<float> mat) {
			return o(std::vector<float>, Vector2Transform, {v COMMA mat});
		}
		auto Lerp(std::vector<float> v1, std::vector<float> v2, float amount) {
			return o(std::vector<float>, Vector2Lerp, {v1 COMMA v2 COMMA amount});
		}
		auto Reflect(std::vector<float> v, std::vector<float> normal) {
			return o(std::vector<float>, Vector2Reflect, {v COMMA normal});
		}
		auto Min(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector2Min, {v1 COMMA v2});
		}
		auto Max(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector2Max, {v1 COMMA v2});
		}
		auto Rotate(std::vector<float> v, float angle) {
			return o(std::vector<float>, Vector2Rotate, {v COMMA angle});
		}
		auto MoveTowards(std::vector<float> v, std::vector<float> target, float maxDistance) {
			return o(std::vector<float>, Vector2MoveTowards, {v COMMA target COMMA maxDistance});
		}
		auto Invert(std::vector<float> v) {
			return o(std::vector<float>, Vector2Invert, {v});
		}
		auto Clamp(std::vector<float> v, std::vector<float> min, std::vector<float> max) {
			return o(std::vector<float>, Vector2Clamp, {v COMMA min COMMA max});
		}
		auto ClampValue(std::vector<float> v, float min, float max) {
			return o(std::vector<float>, Vector2ClampValue, {v COMMA min COMMA max});
		}
		auto Equals(std::vector<float> v1, std::vector<float> v2) {
			return o(bool, Vector2Equals, {v1 COMMA v2});
		}
		auto Refract(std::vector<float> v, std::vector<float> n, float r) {
			return o(std::vector<float>, Vector2Refract, {v COMMA n COMMA r});
		}
	}
	namespace Vector3 {
		auto Zero() {
			return o(std::vector<float>, Vector3Zero, {});
		}
		auto One() {
			return o(std::vector<float>, Vector3One, {});
		}
		auto Add(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector3Add, {v1 COMMA v2});
		}
		auto AddValue(std::vector<float> v, float add) {
			return o(std::vector<float>, Vector3AddValue, {v COMMA add});
		}
		auto Subtract(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector3Subtract, {v1 COMMA v2});
		}
		auto SubtractValue(std::vector<float> v, float sub) {
			return o(std::vector<float>, Vector3SubtractValue, {v COMMA sub});
		}
		auto Scale(std::vector<float> v, float scalar) {
			return o(std::vector<float>, Vector3Scale, {v COMMA scalar});
		}
		auto Multiply(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector3Multiply, {v1 COMMA v2});
		}
		auto CrossProduct(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector3CrossProduct, {v1 COMMA v2});
		}
		auto Perpendicular(std::vector<float> v) {
			return o(std::vector<float>, Vector3Perpendicular, {v});
		}
		auto Length(std::vector<float> v) {
			return o(float, Vector3Length, {v});
		}
		auto LengthSqr(std::vector<float> v) {
			return o(float, Vector3LengthSqr, {v});
		}
		auto DotProduct(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector3DotProduct, {v1 COMMA v2});
		}
		auto Distance(std::vector<float> v1, std::vector<float> v2) {
			return o(float, Vector3Distance, {v1 COMMA v2});
		}
		auto DistanceSqr(std::vector<float> v1, std::vector<float> v2) {
			return o(float, Vector3DistanceSqr, {v1 COMMA v2});
		}
		auto Angle(std::vector<float> v1, std::vector<float> v2) {
			return o(float, Vector3Angle, {v1 COMMA v2});
		}
		auto Negate(std::vector<float> v) {
			return o(std::vector<float>, Vector3Negate, {v});
		}
		auto Divide(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector3Divide, {v1 COMMA v2});
		}
		auto Normalize(std::vector<float> v) {
			return o(std::vector<float>, Vector3Normalize, {v});
		}
		auto Project(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector3Project, {v1 COMMA v2});
		}
		auto Reject(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector3Reject, {v1 COMMA v2});
		}
		auto Transform(std::vector<float> v, std::vector<float> mat) {
			return o(std::vector<float>, Vector3Transform, {v COMMA mat});
		}
		auto RotateByAxisAngle(std::vector<float> v, std::vector<float> axis, float angle) {
			return o(std::vector<float>, Vector3RotateByAxisAngle, {v COMMA axis COMMA angle});
		}
		auto MoveTowards(std::vector<float> v, std::vector<float> target, float maxDistance) {
			return o(std::vector<float>, Vector3MoveTowards, {v COMMA target COMMA maxDistance});
		}
		auto Lerp(std::vector<float> v1, std::vector<float> v2, float amount) {
			return o(std::vector<float>, Vector2Lerp, {v1 COMMA v2 COMMA amount});
		}
		auto CubicHermite(std::vector<float> v1, std::vector<float> t1, std::vector<float> v2, std::vector<float> t2, float amount) {
			return o(std::vector<float>, Vector3CubicHermit, {v1 COMMA t1 COMMA v2 COMMA t2 COMMA amount});
		}
		auto Reflect(std::vector<float> v, std::vector<float> normal) {
			return o(std::vector<float>, Vector3Reflect, {v COMMA normal});
		}
		auto Min(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector3Min, {v1 COMMA v2});
		}
		auto Max(std::vector<float> v1, std::vector<float> v2) {
			return o(std::vector<float>, Vector3Max, {v1 COMMA v2});
		}
		auto Barycenter(std::vector<float> p, std::vector<float> a, std::vector<float> b, std::vector<float> c) {
			return o(std::vector<float>, Vector3Barycenter, {p COMMA a COMMA b COMMA c});
		}
		auto Invert(std::vector<float> v) {
			return o(std::vector<float>, Vector3Invert, {v});
		}
		auto Clamp(std::vector<float> v, std::vector<float> min, std::vector<float> max) {
			return o(std::vector<float>, Vector3Clamp, {v COMMA min COMMA max});
		}
		auto ClampValue(std::vector<float> v, float min, float max) {
			return o(std::vector<float>, Vector3ClampValue, {v COMMA min COMMA max});
		}
		auto Equals(std::vector<float> p, std::vector<float> q) {
			return o(bool, Vector3Equals, {p COMMA q});
		}
		auto Refract(std::vector<float> v, std::vector<float> n, float r) {
			return o(std::vector<float>, Vector3Refract, {v COMMA n COMMA r});
		}
	}
	namespace Matrix {
		auto Determinant (std::vector<float> mat) {
			return o(float, MatrixDeterminant, {mat});
		}
		auto Trace (std::vector<float> mat) {
			return o(float, MatrixTrace, {mat});
		}
		auto Transpose (std::vector<float> mat) {
			return o(std::vector<float>, MatrixTranspose, {mat});
		}
		auto Identity () {
			return o(std::vector<float>, MatrixIdentity, {});
		}
		auto Add (std::vector<float> left, std::vector<float> right) {
			return o(std::vector<float>, MatrixAdd, {left COMMA right});
		}
		auto Subtract(std::vector<float> left, std::vector<float> right) {
			return o(std::vector<float>, MatrixSubtract, {left COMMA right});
		}
		auto Multiply(std::vector<float> left, std::vector<float> right) {
			return o(std::vector<float>, MatrixMultiply, {left COMMA right});
		}
		auto Translate(float x, float y, float z) {
			return o(std::vector<float>, MatrixTranslate, {x COMMA y COMMA z});
		}
		auto Rotate(std::vector<float> axis, float angle) {
			return o(std::vector<float>, MatrixRotate, {axis COMMA angle});
		}
		auto RotateXYZ(std::vector<float> angle) {
			return o(std::vector<float>, MatrixRotateXYZ, {angle});
		}
		auto Scale(float x, float y, float z) {
			return o(std::vector<float>, MatrixScale, {x COMMA y COMMA z});
		}
	}
}
#undef f
#undef o
#undef COMMA