common/VectorUtils4.h
b23636c9
 // VectorUtils4, header only version!
 // You must define MAIN in only one file (typically the main
 // program) in order to only complile the implementation section once!
 // The #define must be BEFORE the "include of this file!
 
 // VectorUtils
 // Vector and matrix manipulation library for OpenGL, a package of the most essential functions.
 // This is intended as a mini version of GLM.
 // Includes:
 // - Basic vector operations: Add, subtract, scale, dot product, cross product.
 // - Basic matrix operations: Multiply matrix to matrix, matric to vector, transpose.
 // - Creation of transformation matrixces: Translation, scaling, rotation.
 // - A few more special operations: Orthonormalizaton of a matrix, CrossMatrix,
 // - Replacements of some GLU functions: lookAt, frustum, perspective.
 // - Inverse and inverse transpose for creating normal matrices.
 // Supports both C and C++. The C interface makes it accessible from most languages if desired.
 
 // A note on completeness:
 // All operations may not be 100% symmetrical over all types, and some GLSL types are
 // missing (like vec2). These will be added if proven important. There are already
 // some calls of minor importance (mat3 * mat3, mat3 * vec3) included only for
 // symmetry. I don't want the code to grow a lot for such reasons, I want it to be
 // compact and to the point.
 
 // Current open design questions:
 // Naming conventions: Lower case or capitalized? (Frustum/frustum)
 // Prefix for function calls? (The cost would be more typing and making the code harder to read.)
 // Add vector operations for vec4? Other *essential* symmetry issues?
 // Names for functions when supporting both vec3 and vec4, mat3 and mat4? (vec3Add, vec4Add?)
 
 
 // History:
 
 // VectorUtils is a small (but growing) math unit by Ingemar Ragnemalm.
 // It originated as "geom3d" by Andrew Meggs, but that unit is no more
 // than inspiration today. The original VectorUtils(1) was based on it,
 // while VectorUtils2 was a rewrite primarily to get rid of the over-use
 // of arrays in the original.
 
 // New version 120201:
 // Defaults to matrices "by the book". Can also be configured to the flipped
 // column-wise matrices that old OpenGL required (and we all hated).
 // This is freshly implemented, limited testing, so there can be bugs.
 // But it seems to work just fine on my tests with translation, rotations
 // and matrix multiplications.
 
 // 1208??: Added lookAt, perspective, frustum
 // Also made Transpose do what it should. TransposeRotation is the old function.
 // 120913: Fixed perspective. Never trust other's code...
 // 120925: Transposing in CrossMatrix
 // 121119: Fixed one more glitch in perspective.
 
 // 130227 First draft to a version 3.
 // C++ operators if accessed from C++
 // Vectors by value when possible. Return values on the stack.
 // (Why was this not the case in VectorUtils2? Beause I tried to stay compatible
 // with an old C compiler. Older C code generally prefers all non-scalar data by
 // reference. But I'd like to move away from that now.)
 // Types conform with GLSL as much as possible (vec3, mat4)
 // Added some operations for mat3 and vec4, but most of them are more for
 // completeness than usefulness; I find vec3's and mat4's to be what I use
 // most of the time.
 // Also added InvertMat3 and InversTranspose to support creation of normal matrices.
 // Marked some calls for removal: CopyVector, TransposeRotation, CopyMatrix.
 // 130308: Added InvertMat4 and some more vec3/vec4 operators (+= etc)
 // 130922: Fixed a vital bug in CrossMatrix.
 // 130924: Fixed a bug in mat3tomat4.
 // 131014: Added TransposeMat3 (although I doubt its importance)
 // 140213: Corrected mat3tomat4. (Were did the correction in 130924 go?)
 // 151210: Added printMat4 and printVec3.
 // 160302: Added empty constuctors for vec3 and vec4.
 // 170221: Uses _WIN32 instead of WIN32
 // 170331: Added stdio.h for printMat4 and printVec3
 // 180314: Added some #defines for moving closer to GLSL (dot, cross...).
 // 2021-05-15: Constructors for vec3 etc replaced in order to avoid
e797f203
 // problems with some C++ compilers.
b23636c9
 
 // 2022-05-05: Created VectorUtils4, now only a header file!
 // You must define MAIN in only one file (typically the main
 // program) in order to only complile the implementation section once!
 // This means:
 // + Only ONE file
 // + I can now safely re-introduce the constructors again!
 // + I can move closer to GLM and GLSL syntax
 // - You must #define MAIN in the main program
 // This means that VectorUtils can still be used from C and thereby many other languages,
 // while taking more advantage of C++ features when using C++.
49ca15c4
 // 20220525: Revised perpective() to conform with the reference manual as well as GLM.
 // 20230205: Added new helper functions, uploadMat4ToShader etc.
 // Made a better #ifdef for handling multiple inclusions.
5973d707
 // 20230227: Fixed the mat4(mat3) constructor.
b23636c9
 
 // You may use VectorUtils as you please. A reference to the origin is appreciated
 // but if you grab some snippets from it without reference... no problem.
 
49ca15c4
 // VectorUtils4 interface part
 // See implementation part for more information
b23636c9
 
 #ifndef VECTORUTILS4
 #define VECTORUTILS4
 
 #ifdef __APPLE__
 	#define GL_SILENCE_DEPRECATION
 	#include <OpenGL/gl3.h>
 #else
 	#if defined(_WIN32)
 		#include "glew.h"
 	#endif
 	#include <GL/gl.h>
 #endif
 #include <math.h>
 #include <stdio.h>
 
 
 #ifndef M_PI
 #define M_PI           3.14159265358979323846
 #endif
 
 // GLSL-style
 // These are already changed, here I define the intermediate type names that I use in some demos.
 #define Point3D vec3
 #define Matrix3D mat3
 #define Matrix4D mat4
 #define DotProduct dot
 #define CrossProduct cross
 #define Normalize normalize
 #define Transpose transpose
 // Furthermore, SplitVector should be revised to conform with reflect()
 
 // Note 210515: I have removed the constructors from my structs below in order to please
 // some compilers. They did work but the compilers were upset about C using these
 // without knowing about the constructors, while the C++ code happily used them.
 // However, we do not need them; you can initialize with SetVec* instead of
 // vec*() and it will work.
49ca15c4
 // Note 2022: These are now back (and more), which is possible when doing this as a header only unit
 // so it works with both C and C++ and still allows the constructors.
 	
b23636c9
 	typedef struct vec4 vec4;
49ca15c4
 	
b23636c9
 	// vec3 is very useful
 	typedef struct vec3
 	{
 //		GLfloat x, y, z;
 		union
 		{GLfloat x; GLfloat r;};
 		union
 		{GLfloat y; GLfloat g;};
 		union
 		{GLfloat z; GLfloat b;};
 		#ifdef __cplusplus
             vec3() {}
 			vec3(GLfloat x2, GLfloat y2, GLfloat z2) : x(x2), y(y2), z(z2) {}
 			vec3(GLfloat x2) : x(x2), y(x2), z(x2) {}
 //			vec3(vec4 v) : x(v.x), y(v.y), z(v.z) {}
 			vec3(vec4 v);
 		#endif
 	} vec3, *vec3Ptr;
49ca15c4
 	
b23636c9
 	// vec4 is not as useful. Can be a color with alpha, or a quaternion, but IMHO you
 	// rarely need homogenous coordinate vectors on the CPU.
 	typedef struct vec4
 	{
 //		GLfloat x, y, z, w; // w or h
 		union
 		{GLfloat x; GLfloat r;};
 		union
 		{GLfloat y; GLfloat g;};
 		union
 		{GLfloat z; GLfloat b;};
 		union
 		{GLfloat h; GLfloat w; GLfloat a;};
 		#ifdef __cplusplus
             vec4() {}
 			vec4(GLfloat x2, GLfloat y2, GLfloat z2, GLfloat w2) : x(x2), y(y2), z(z2), w(w2) {}
 			vec4(GLfloat xyz, GLfloat w2) : x(xyz), y(xyz), z(xyz), w(w2) {}
 			vec4(vec3 v, GLfloat w2) : x(v.x), y(v.y), z(v.z), w(w2) {}
 			vec4(vec3 v) : x(v.x), y(v.y), z(v.z), w(1) {}
 		#endif
 	} vec4, *vec4Ptr;
 
 // vec2 is mostly used for texture cordinates, so I havn't bothered defining any operations for it
 	typedef struct vec2
 	{
 //		GLfloat x, y;
 		union
 		{GLfloat x; GLfloat s;};
 		union
 		{GLfloat y; GLfloat t;};
49ca15c4
 		
b23636c9
 		#ifdef __cplusplus
             vec2() {}
 			vec2(GLfloat x2, GLfloat y2) : x(x2), y(y2) {}
 		#endif
 	} vec2, *vec2Ptr;
49ca15c4
 	
b23636c9
 	typedef struct mat3 mat3;
 	typedef struct mat4
 	{
 		GLfloat m[16];
 		#ifdef __cplusplus
             mat4() {}
 			mat4(GLfloat x2)
 			{
 				m[0] = x2; m[1] = 0; m[2] = 0; m[3] = 0;
 				m[4] = 0; m[5] = x2; m[6] = 0; m[7] = 0;
 				m[8] = 0; m[9] = 0; m[10] = x2; m[11] = 0;
 				m[12] = 0; m[13] = 0; m[14] = 0; m[15] = x2;
 			}
 			mat4(GLfloat p0, GLfloat p1, GLfloat p2, GLfloat p3,
 				GLfloat p4, GLfloat p5, GLfloat p6, GLfloat p7,
49ca15c4
 				GLfloat p8, GLfloat p9, GLfloat p10, GLfloat p11, 
b23636c9
 				GLfloat p12, GLfloat p13, GLfloat p14, GLfloat p15)
 			{
 				m[0] = p0; m[1] = p1; m[2] = p2; m[3] = p3;
 				m[4] = p4; m[5] = p5; m[6] = p6; m[7] = p7;
 				m[8] = p8; m[9] = p9; m[10] = p10; m[11] = p11;
 				m[12] = p12; m[13] = p13; m[14] = p14; m[15] = p15;
 			}
 			mat4(mat3 x);
 		#endif
 	} mat4;
 	typedef struct mat3
 	{
 		GLfloat m[9];
 		#ifdef __cplusplus
             mat3() {}
 			mat3(GLfloat x2)
 			{
 				m[0] = x2; m[1] = 0; m[2] = 0;
 				m[3] = 0; m[4] = x2; m[5] = 0;
 				m[6] = 0; m[7] = 0; m[8] = x2;
 			}
 			mat3(GLfloat p0, GLfloat p1, GLfloat p2,
 				GLfloat p3, GLfloat p4, GLfloat p5,
 				GLfloat p6, GLfloat p7, GLfloat p8)
 			{
 				m[0] = p0; m[1] = p1; m[2] = p2;
 				m[3] = p3; m[4] = p4; m[5] = p5;
 				m[6] = p6; m[7] = p7; m[8] = p8;
 			}
 			mat3(mat4 x)
 			{
 				m[0] = x.m[0]; m[1] = x.m[1]; m[2] = x.m[2];
 				m[3] = x.m[4]; m[4] = x.m[5]; m[5] = x.m[6];
 				m[6] = x.m[8]; m[7] = x.m[9]; m[8] = x.m[10];
 			}
 			mat3(vec3 x1, vec3 x2, vec3 x3)
 			{
 				m[0] = x1.x; m[1] = x1.y; m[2] = x1.z;
 				m[3] = x2.x; m[4] = x2.y; m[5] = x2.z;
 				m[6] = x3.x; m[7] = x3.y; m[8] = x3.z;
 			}
 		#endif
 	} mat3;
 
 #ifdef __cplusplus
5973d707
 // This needed to be compiled only once - moved to implementation.
 // This most likely must be done with several more!
 //	vec3::vec3(vec4 v) : x(v.x), y(v.y), z(v.z) {}
 //	mat4::mat4(mat3 x)
 //	{
 //		m[0] = x.m[0]; m[1] = x.m[1]; m[2] = x.m[2]; m[3] = 0;
 //		m[4] = x.m[3]; m[5] = x.m[4]; m[6] = x.m[5]; m[7] = 0;
 //		m[8] = x.m[6]; m[9] = x.m[7]; m[10] = x.m[8]; m[11] = 0;
 //		m[12] = x.m[0]; m[13] = x.m[0]; m[14] = x.m[0]; m[15] = 1;
 //	}
b23636c9
 #endif
 
 //#ifdef __cplusplus
 //extern "C" {
 //#endif
 
 // New better name for SetVector and replacements for constructors
 	vec2 SetVec2(GLfloat x, GLfloat y);
 	vec3 SetVec3(GLfloat x, GLfloat y, GLfloat z);
 	vec4 SetVec4(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
 
 	vec3 SetVector(GLfloat x, GLfloat y, GLfloat z);
 	mat3 SetMat3(GLfloat p0, GLfloat p1, GLfloat p2, GLfloat p3, GLfloat p4, GLfloat p5, GLfloat p6, GLfloat p7, GLfloat p8);
 	mat4 SetMat4(GLfloat p0, GLfloat p1, GLfloat p2, GLfloat p3,
 				GLfloat p4, GLfloat p5, GLfloat p6, GLfloat p7,
49ca15c4
 				GLfloat p8, GLfloat p9, GLfloat p10, GLfloat p11, 
b23636c9
 				GLfloat p12, GLfloat p13, GLfloat p14, GLfloat p15
 				);
 // Basic vector operations on vec3's. (vec4 not included since I never need them.)
 // Note: C++ users can also use operator overloading, defined below.
 	vec3 VectorSub(vec3 a, vec3 b);
 	vec3 VectorAdd(vec3 a, vec3 b);
 	vec3 cross(vec3 a, vec3 b);
 	GLfloat dot(vec3 a, vec3 b);
 	vec3 ScalarMult(vec3 a, GLfloat s);
 	GLfloat Norm(vec3 a);
 	vec3 normalize(vec3 a);
 	vec3 CalcNormalVector(vec3 a, vec3 b, vec3 c);
 	void SplitVector(vec3 v, vec3 n, vec3 *vn, vec3 *vp);
 
 // Matrix operations primarily on 4x4 matrixes!
 // Row-wise by default but can be configured to column-wise (see SetTransposed)
 
 	mat4 IdentityMatrix();
 	mat4 Rx(GLfloat a);
 	mat4 Ry(GLfloat a);
 	mat4 Rz(GLfloat a);
 	mat4 T(GLfloat tx, GLfloat ty, GLfloat tz);
 	mat4 S(GLfloat sx, GLfloat sy, GLfloat sz);
 	mat4 Mult(mat4 a, mat4 b); // dest = a * b - rename to MultMat4 considered but I don't like to make the name of the most common operation longer
 	// but for symmetry, MultMat4 is made a synonym:
 	#define MultMat4 Mult
 
 	vec3 MultVec3(mat4 a, vec3 b); // result = a * b
 	vec4 MultVec4(mat4 a, vec4 b);
 
 // Mat3 operations (new)
 	mat3 MultMat3(mat3 a, mat3 b); // m = a * b
 	vec3 MultMat3Vec3(mat3 a, vec3 b); // result = a * b
 
 	void OrthoNormalizeMatrix(mat4 *R);
 	mat4 transpose(mat4 m);
 	mat3 TransposeMat3(mat3 m);
 	mat4 ArbRotate(vec3 axis, GLfloat fi);
 	mat4 CrossMatrix(vec3 a);
 	mat4 MatrixAdd(mat4 a, mat4 b);
 
 // Configure, i.e. if you want matrices to be column-wise
 	void SetTransposed(char t);
 
 // GLU replacement functions
 	mat4 lookAtv(vec3 p, vec3 l, vec3 v);
49ca15c4
 	mat4 lookAt(GLfloat px, GLfloat py, GLfloat pz, 
b23636c9
 			GLfloat lx, GLfloat ly, GLfloat lz,
 			GLfloat vx, GLfloat vy, GLfloat vz);
 	mat4 perspective(float fovyInDegrees, float aspectRatio,
                       float znear, float zfar);
 	mat4 frustum(float left, float right, float bottom, float top,
                   float znear, float zfar);
 	mat4 ortho(GLfloat left, GLfloat right, GLfloat bottom,
 			GLfloat top, GLfloat near, GLfloat far);
 
 // For creating a normal matrix
 	mat3 InvertMat3(mat3 in);
 	mat3 InverseTranspose(mat4 in);
 	mat4 InvertMat4(mat4 a);
 
 // Simple conversions
 	mat3 mat4tomat3(mat4 m);
 	mat4 mat3tomat4(mat3 m);
 	vec3 vec4tovec3(vec4 v);
 	vec4 vec3tovec4(vec3 v);
 
 // Convenient printing calls
 	void printMat4(mat4 m);
 	void printVec3(vec3 in);
 
e797f203
 /* Utility functions for easier uploads to shaders with error messages. */
 // NEW as prototype 2022, added to VU 2023
49ca15c4
 	void uploadMat4ToShader(GLuint shader, const char *nameInShader, mat4 m);
 	void uploadUniformIntToShader(GLuint shader, const char *nameInShader, GLint i);
 	void uploadUniformFloatToShader(GLuint shader, const char *nameInShader, GLfloat f);
 	void uploadUniformFloatArrayToShader(GLuint shader, const char *nameInShader, GLfloat *f, int arrayLength);
 	void uploadUniformVec3ToShader(GLuint shader, const char *nameInShader, vec3 v);
 	void uploadUniformVec3ArrayToShader(GLuint shader, const char *nameInShader, vec3 *a, int arrayLength);
e797f203
 	void bindTextureToTextureUnit(GLuint tex, int unit);
 
b23636c9
 #ifdef __cplusplus
 // Convenient overloads for C++, closer to GLSL
 	mat3 inverse(mat3 m);
 	mat4 inverse(mat4 m);
 	mat3 transpose(mat3 m);
 	mat4 S(GLfloat s);
 	mat4 S(vec3 s);
 	mat4 lookAt(vec3 p, vec3 l, vec3 u);
 #endif
 
 //#ifdef __cplusplus
 //}
 //#endif
 
 #ifdef __cplusplus
 // Some C++ operator overloads
 // Non-member C++ operators!
5973d707
 // New version 2021-05-2x: Constructors for vec3 etc replaced in order to avoid
b23636c9
 // problems with some C++ compilers.
 
 // --- vec3 operations ---
 inline
 vec3 operator+(const vec3 &a, const vec3 &b) // vec3+vec3
 {
 	return SetVector(a.x+b.x, a.y+b.y, a.z+b.z);
 }
 
 inline
 vec3 operator-(const vec3 &a, const vec3 &b) // vec3-vec3
 {
 	return SetVector(a.x-b.x, a.y-b.y, a.z-b.z);
 }
 
 inline
 vec3 operator-(const vec3 &a)
 {
 		return SetVector(-a.x, -a.y, -a.z);
 }
 
 	// Questionable, not like GLSL
 inline
 float operator*(const vec3 &a, const vec3 &b) // vec3 dot vec3
 {
 	return (a.x*b.x+ a.y*b.y+ a.z*b.z);
 }
 
 inline
 vec3 operator*(const vec3 &b, double a) // vec3 * scalar
 {
 	return SetVector(a*b.x, a*b.y, a*b.z);
 }
 
 inline
 vec3 operator*(double a, const vec3 &b) // scalar * vec3
 {
 	return SetVector(a*b.x, a*b.y, a*b.z);
 }
 
 inline
 vec3 operator/(const vec3 &b, double a) // vec3 / scalar
 {
 	return SetVector(b.x/a, b.y/a, b.z/a);
 }
 
 inline
 void operator+=(vec3 &a, const vec3 &b) // vec3+=vec3
 {
 	a = a + b;
 }
 
 inline
 void operator-=(vec3 &a, const vec3 &b) // vec3-=vec3
 {
 	a = a - b;
 }
 
 inline
 void operator*=(vec3 &a, const float &b) // vec3*=scalar
 {
 	a = a * b;
 }
 
 inline
 void operator/=(vec3 &a, const float &b) // vec3/=scalar
 {
 	a = a / b;
 }
 
 // --- vec4 operations ---
 
 inline
 vec4 operator+(const vec4 &a, const vec4 &b) // vec4+vec4
 {
 	return SetVec4(a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w);
 }
 
 inline
 vec4 operator-(const vec4 &a, const vec4 &b) // vec4-vec4
 {
 	return SetVec4(a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w);
 }
 
 	// Questionable, not like GLSL
 inline
 float operator*(const vec4 &a, const vec4 &b) // vec4 dot vec4
 {
 	return (a.x*b.x+ a.y*b.y+ a.z*b.z+ a.w*b.w);
 }
 
 inline
 vec4 operator*(const vec4 &b, double a) // vec4 * scalar
 {
 	return SetVec4(a*b.x, a*b.y, a*b.z, a*b.w);
 }
 
 inline
 vec4 operator*(double a, const vec4 &b) // scalar * vec4
 {
 	return SetVec4(a*b.x, a*b.y, a*b.z, a*b.w);
 }
 
 inline
 vec4 operator/(const vec4 &b, double a) // vec4 / scalar
 {
 	return SetVec4(b.x/a, b.y/a, b.z/a, b.w/a);
 }
 
 
 inline
 void operator+=(vec4 &a, const vec4 &b) // vec4+=vec4
 {
 	a = a + b;
 }
 
 inline
 void operator-=(vec4 &a, const vec4 &b) // vec4-=vec4
 {
 	a = a - b;
 }
 
 inline
 void operator*=(vec4 &a, const float &b) // vec4 *= scalar
 {
 	a = a * b;
 }
 
 inline
 void operator/=(vec4 &a, const float &b) // vec4 /= scalar
 {
 	a = a / b;
 }
 
 // --- Matrix multiplication ---
 
 // mat4 * mat4
 inline
 mat4 operator*(const mat4 &a, const mat4 &b)
 {
 	return (Mult(a, b));
 }
 
 // mat3 * mat3
 inline
 mat3 operator*(const mat3 &a, const mat3 &b)
 {
 	return (MultMat3(a, b));
 }
 
 // mat4 * vec3
 inline
 vec3 operator*(const mat4 &a, const vec3 &b)
 {
 	return MultVec3(a, b); // result = a * b
 }
 
 // mat4 * vec4
 inline
 vec4 operator*(const mat4 &a, const vec4 &b)
 {
 	return MultVec4(a, b); // result = a * b
 }
 
 // mat3 * vec3
 inline
 vec3 operator*(const mat3 &a, const vec3 &b)
 {
 	return MultMat3Vec3(a, b); // result = a * b
 }
 
 #endif
49ca15c4
 #endif
b23636c9
 
 // ********** implementation section ************
 
 #ifdef MAIN
49ca15c4
 
 // Make sure this is included once
 #ifndef VECTORUTILS4_MAIN
 #define VECTORUTILS4_MAIN
b23636c9
 
 // VS doesn't define NAN properly
 #ifdef _WIN32
     #ifndef NAN
         static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
         #define NAN (*(const float *) __nan)
     #endif
 #endif
 
 char transposed = 0;
 
 	vec3 SetVector(GLfloat x, GLfloat y, GLfloat z)
 	{
 		vec3 v;
49ca15c4
 		
b23636c9
 		v.x = x;
 		v.y = y;
 		v.z = z;
 		return v;
 	}
 
 // New better name
 	vec2 SetVec2(GLfloat x, GLfloat y)
 	{
 		vec2 v;
49ca15c4
 		
b23636c9
 		v.x = x;
 		v.y = y;
 		return v;
 	}
 
 	vec3 SetVec3(GLfloat x, GLfloat y, GLfloat z)
 	{
 		vec3 v;
49ca15c4
 		
b23636c9
 		v.x = x;
 		v.y = y;
 		v.z = z;
 		return v;
 	}
 
 	vec4 SetVec4(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
 	{
 		vec4 v;
49ca15c4
 		
b23636c9
 		v.x = x;
 		v.y = y;
 		v.z = z;
 		v.w = w;
 		return v;
 	}
 
 // Modern C doesn't need this, but Visual Studio insists on old-fashioned C and needs this.
 	mat3 SetMat3(GLfloat p0, GLfloat p1, GLfloat p2, GLfloat p3, GLfloat p4, GLfloat p5, GLfloat p6, GLfloat p7, GLfloat p8)
 	{
 		mat3 m;
 		m.m[0] = p0;
 		m.m[1] = p1;
 		m.m[2] = p2;
 		m.m[3] = p3;
 		m.m[4] = p4;
 		m.m[5] = p5;
 		m.m[6] = p6;
 		m.m[7] = p7;
 		m.m[8] = p8;
 		return m;
 	}
 
 // Like above; Modern C doesn't need this, but Visual Studio insists on old-fashioned C and needs this.
 	mat4 SetMat4(GLfloat p0, GLfloat p1, GLfloat p2, GLfloat p3,
 				GLfloat p4, GLfloat p5, GLfloat p6, GLfloat p7,
49ca15c4
 				GLfloat p8, GLfloat p9, GLfloat p10, GLfloat p11, 
b23636c9
 				GLfloat p12, GLfloat p13, GLfloat p14, GLfloat p15
 				)
 	{
 		mat4 m;
 		m.m[0] = p0;
 		m.m[1] = p1;
 		m.m[2] = p2;
 		m.m[3] = p3;
 		m.m[4] = p4;
 		m.m[5] = p5;
 		m.m[6] = p6;
 		m.m[7] = p7;
 		m.m[8] = p8;
 		m.m[9] = p9;
 		m.m[10] = p10;
 		m.m[11] = p11;
 		m.m[12] = p12;
 		m.m[13] = p13;
 		m.m[14] = p14;
 		m.m[15] = p15;
 		return m;
 	}
 
 
 	// vec3 operations
 	// vec4 operations can easily be added but I havn't seen much need for them.
 	// Some are defined as C++ operators though.
 
 	vec3 VectorSub(vec3 a, vec3 b)
 	{
 		vec3 result;
49ca15c4
 		
b23636c9
 		result.x = a.x - b.x;
 		result.y = a.y - b.y;
 		result.z = a.z - b.z;
 		return result;
 	}
49ca15c4
 	
b23636c9
 	vec3 VectorAdd(vec3 a, vec3 b)
 	{
 		vec3 result;
49ca15c4
 		
b23636c9
 		result.x = a.x + b.x;
 		result.y = a.y + b.y;
 		result.z = a.z + b.z;
 		return result;
 	}
 
 	vec3 cross(vec3 a, vec3 b)
 	{
 		vec3 result;
 
 		result.x = a.y*b.z - a.z*b.y;
 		result.y = a.z*b.x - a.x*b.z;
 		result.z = a.x*b.y - a.y*b.x;
49ca15c4
 		
b23636c9
 		return result;
 	}
 
 	GLfloat dot(vec3 a, vec3 b)
 	{
 		return a.x * b.x + a.y * b.y + a.z * b.z;
 	}
 
 	vec3 ScalarMult(vec3 a, GLfloat s)
 	{
 		vec3 result;
49ca15c4
 		
b23636c9
 		result.x = a.x * s;
 		result.y = a.y * s;
 		result.z = a.z * s;
49ca15c4
 		
b23636c9
 		return result;
 	}
 
 	GLfloat Norm(vec3 a)
 	{
 		GLfloat result;
 
 		result = (GLfloat)sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
 		return result;
 	}
 
 	vec3 normalize(vec3 a)
 	{
 		GLfloat norm;
 		vec3 result;
 
 		norm = (GLfloat)sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
 		result.x = a.x / norm;
 		result.y = a.y / norm;
 		result.z = a.z / norm;
 		return result;
 	}
 
 	vec3 CalcNormalVector(vec3 a, vec3 b, vec3 c)
 	{
 		vec3 n;
 
 		n = cross(VectorSub(a, b), VectorSub(a, c));
 		n = ScalarMult(n, 1/Norm(n));
49ca15c4
 		
b23636c9
 		return n;
 	}
 
 // Splits v into vn (parallell to n) and vp (perpendicular). Does not demand n to be normalized.
 	void SplitVector(vec3 v, vec3 n, vec3 *vn, vec3 *vp)
 	{
 		GLfloat nlen;
 		GLfloat nlen2;
 
 		nlen = DotProduct(v, n);
 		nlen2 = n.x*n.x+n.y*n.y+n.z*n.z; // Squared length
 		if (nlen2 == 0)
 		{
 			*vp = v;
 			*vn = SetVector(0, 0, 0);
 		}
 		else
 		{
 			*vn = ScalarMult(n, nlen/nlen2);
 			*vp = VectorSub(v, *vn);
 		}
 	}
 
 // Matrix operations primarily on 4x4 matrixes!
 // Row-wise by default but can be configured to column-wise (see SetTransposed)
 
 	mat4 IdentityMatrix()
 	{
 		mat4 m;
 		int i;
 
 		for (i = 0; i <= 15; i++)
 			m.m[i] = 0;
 		for (i = 0; i <= 3; i++)
 			m.m[i * 5] = 1; // 0,5,10,15
 		return m;
 	}
 
 	mat4 Rx(GLfloat a)
 	{
 		mat4 m;
 		m = IdentityMatrix();
 		m.m[5] = (GLfloat)cos(a);
 		if (transposed)
 			m.m[9] = (GLfloat)-sin(a);
 		else
 			m.m[9] = (GLfloat)sin(a);
 		m.m[6] = -m.m[9]; //sin(a);
 		m.m[10] = m.m[5]; //cos(a);
 		return m;
 	}
 
 	mat4 Ry(GLfloat a)
 	{
 		mat4 m;
 		m = IdentityMatrix();
 		m.m[0] = (GLfloat)cos(a);
 		if (transposed)
 			m.m[8] = (GLfloat)sin(a); // Was flipped
 		else
 			m.m[8] = (GLfloat)-sin(a);
 		m.m[2] = -m.m[8]; //sin(a);
 		m.m[10] = m.m[0]; //cos(a);
 		return m;
 	}
 
 	mat4 Rz(GLfloat a)
 	{
 		mat4 m;
 		m = IdentityMatrix();
 		m.m[0] = (GLfloat)cos(a);
 		if (transposed)
 			m.m[4] = (GLfloat)-sin(a);
 		else
 			m.m[4] = (GLfloat)sin(a);
 		m.m[1] = -m.m[4]; //sin(a);
 		m.m[5] = m.m[0]; //cos(a);
 		return m;
 	}
 
 	mat4 T(GLfloat tx, GLfloat ty, GLfloat tz)
 	{
 		mat4 m;
 		m = IdentityMatrix();
 		if (transposed)
 		{
 			m.m[12] = tx;
 			m.m[13] = ty;
 			m.m[14] = tz;
 		}
 		else
 		{
 			m.m[3] = tx;
 			m.m[7] = ty;
 			m.m[11] = tz;
 		}
 		return m;
 	}
 
 	mat4 S(GLfloat sx, GLfloat sy, GLfloat sz)
 	{
 		mat4 m;
 		m = IdentityMatrix();
 		m.m[0] = sx;
 		m.m[5] = sy;
 		m.m[10] = sz;
 		return m;
 	}
 
 	mat4 Mult(mat4 a, mat4 b) // m = a * b
 	{
 		mat4 m;
 
 		int x, y;
 		for (x = 0; x <= 3; x++)
 			for (y = 0; y <= 3; y++)
 				if (transposed)
 					m.m[x*4 + y] =	a.m[y+4*0] * b.m[0+4*x] +
 								a.m[y+4*1] * b.m[1+4*x] +
 								a.m[y+4*2] * b.m[2+4*x] +
 								a.m[y+4*3] * b.m[3+4*x];
 				else
 					m.m[y*4 + x] =	a.m[y*4+0] * b.m[0*4+x] +
 								a.m[y*4+1] * b.m[1*4+x] +
 								a.m[y*4+2] * b.m[2*4+x] +
 								a.m[y*4+3] * b.m[3*4+x];
 
 		return m;
 	}
 
 //	mat4 Mult(mat4 a, mat4 b) // m = a * b
 //	{
 //		mat4 m;
 
 //		if (transposed)
 //		{
 //			a = transpose(a);
 //			b = transpose(b);
 //		}
 
 //		int x, y;
 //		for (x = 0; x <= 3; x++)
 //			for (y = 0; y <= 3; y++)
 //					m.m[y*4 + x] =	a.m[y*4+0] * b.m[0*4+x] +
 //								a.m[y*4+1] * b.m[1*4+x] +
 //								a.m[y*4+2] * b.m[2*4+x] +
 //								a.m[y*4+3] * b.m[3*4+x];
 
 //		if (transposed)
 //			m = transpose(m);
 
 //		return m;
 //	}
 
 
 	// Ej testad!
 	mat3 MultMat3(mat3 a, mat3 b) // m = a * b
 	{
 		mat3 m;
 
 		int x, y;
 		for (x = 0; x <= 2; x++)
 			for (y = 0; y <= 2; y++)
 				if (transposed)
 					m.m[x*3 + y] =	a.m[y+3*0] * b.m[0+3*x] +
 								a.m[y+3*1] * b.m[1+3*x] +
 								a.m[y+3*2] * b.m[2+3*x];
 				else
 					m.m[y*3 + x] =	a.m[y*3+0] * b.m[0*3+x] +
 								a.m[y*3+1] * b.m[1*3+x] +
 								a.m[y*3+2] * b.m[2*3+x];
 
 		return m;
 	}
 
 	// mat4 * vec3
 	// The missing homogenous coordinate is implicitly set to 1.
 	vec3 MultVec3(mat4 a, vec3 b) // result = a * b
 	{
 		vec3 r;
 
 		if (!transposed)
 		{
 			r.x = a.m[0]*b.x + a.m[1]*b.y + a.m[2]*b.z + a.m[3];
 			r.y = a.m[4]*b.x + a.m[5]*b.y + a.m[6]*b.z + a.m[7];
 			r.z = a.m[8]*b.x + a.m[9]*b.y + a.m[10]*b.z + a.m[11];
 		}
 		else
 		{
 			r.x = a.m[0]*b.x + a.m[4]*b.y + a.m[8]*b.z + a.m[12];
 			r.y = a.m[1]*b.x + a.m[5]*b.y + a.m[9]*b.z + a.m[13];
 			r.z = a.m[2]*b.x + a.m[6]*b.y + a.m[10]*b.z + a.m[14];
 		}
 
 		return r;
 	}
 
 	// mat3 * vec3
 	vec3 MultMat3Vec3(mat3 a, vec3 b) // result = a * b
 	{
 		vec3 r;
49ca15c4
 		
b23636c9
 		if (!transposed)
 		{
 			r.x = a.m[0]*b.x + a.m[1]*b.y + a.m[2]*b.z;
 			r.y = a.m[3]*b.x + a.m[4]*b.y + a.m[5]*b.z;
 			r.z = a.m[6]*b.x + a.m[7]*b.y + a.m[8]*b.z;
 		}
 		else
 		{
 			r.x = a.m[0]*b.x + a.m[3]*b.y + a.m[6]*b.z;
 			r.y = a.m[1]*b.x + a.m[4]*b.y + a.m[7]*b.z;
 			r.z = a.m[2]*b.x + a.m[5]*b.y + a.m[8]*b.z;
 		}
49ca15c4
 		
b23636c9
 		return r;
 	}
 
 	// mat4 * vec4
 	vec4 MultVec4(mat4 a, vec4 b) // result = a * b
 	{
 		vec4 r;
 
 		if (!transposed)
 		{
 			r.x = a.m[0]*b.x + a.m[1]*b.y + a.m[2]*b.z + a.m[3]*b.w;
 			r.y = a.m[4]*b.x + a.m[5]*b.y + a.m[6]*b.z + a.m[7]*b.w;
 			r.z = a.m[8]*b.x + a.m[9]*b.y + a.m[10]*b.z + a.m[11]*b.w;
 			r.w = a.m[12]*b.x + a.m[13]*b.y + a.m[14]*b.z + a.m[15]*b.w;
 		}
 		else
 		{
 			r.x = a.m[0]*b.x + a.m[4]*b.y + a.m[8]*b.z + a.m[12]*b.w;
 			r.y = a.m[1]*b.x + a.m[5]*b.y + a.m[9]*b.z + a.m[13]*b.w;
 			r.z = a.m[2]*b.x + a.m[6]*b.y + a.m[10]*b.z + a.m[14]*b.w;
 			r.w = a.m[3]*b.x + a.m[7]*b.y + a.m[11]*b.z + a.m[15]*b.w;
 		}
 
 		return r;
 	}
 
 
 // Unnecessary
 // Will probably be removed
 //	void CopyMatrix(GLfloat *src, GLfloat *dest)
 //	{
 //		int i;
 //		for (i = 0; i <= 15; i++)
 //			dest[i] = src[i];
 //	}
 
 
 // Added for lab 3 (TSBK03)
 
 	// Orthonormalization of Matrix4D. Assumes rotation only, translation/projection ignored
 	void OrthoNormalizeMatrix(mat4 *R)
 	{
 		vec3 x, y, z;
 
 		if (transposed)
 		{
 			x = SetVector(R->m[0], R->m[1], R->m[2]);
 			y = SetVector(R->m[4], R->m[5], R->m[6]);
 //		SetVector(R[8], R[9], R[10], &z);
 			// Kryssa fram ur varandra
 			// Normera
 			z = CrossProduct(x, y);
 			z = Normalize(z);
 			x = Normalize(x);
 			y = CrossProduct(z, x);
 			R->m[0] = x.x;
 			R->m[1] = x.y;
 			R->m[2] = x.z;
 			R->m[4] = y.x;
 			R->m[5] = y.y;
 			R->m[6] = y.z;
 			R->m[8] = z.x;
 			R->m[9] = z.y;
 			R->m[10] = z.z;
 
 			R->m[3] = 0.0;
 			R->m[7] = 0.0;
 			R->m[11] = 0.0;
 			R->m[12] = 0.0;
 			R->m[13] = 0.0;
 			R->m[14] = 0.0;
 			R->m[15] = 1.0;
 		}
 		else
 		{
 		// NOT TESTED
 			x = SetVector(R->m[0], R->m[4], R->m[8]);
 			y = SetVector(R->m[1], R->m[5], R->m[9]);
 //		SetVector(R[2], R[6], R[10], &z);
 			// Kryssa fram ur varandra
 			// Normera
 			z = CrossProduct(x, y);
 			z = Normalize(z);
 			x = Normalize(x);
 			y = CrossProduct(z, x);
 			R->m[0] = x.x;
 			R->m[4] = x.y;
 			R->m[8] = x.z;
 			R->m[1] = y.x;
 			R->m[5] = y.y;
 			R->m[9] = y.z;
 			R->m[2] = z.x;
 			R->m[6] = z.y;
 			R->m[10] = z.z;
 
 			R->m[3] = 0.0;
 			R->m[7] = 0.0;
 			R->m[11] = 0.0;
 			R->m[12] = 0.0;
 			R->m[13] = 0.0;
 			R->m[14] = 0.0;
 			R->m[15] = 1.0;
 		}
 	}
 
 
 // Commented out since I plan to remove it if I can't see a good reason to keep it.
 //	// Only transposes rotation part.
 //	mat4 TransposeRotation(mat4 m)
 //	{
 //		mat4 a;
49ca15c4
 //		
b23636c9
 //		a.m[0] = m.m[0]; a.m[4] = m.m[1]; a.m[8] = m.m[2];      a.m[12] = m.m[12];
 //		a.m[1] = m.m[4]; a.m[5] = m.m[5]; a.m[9] = m.m[6];      a.m[13] = m.m[13];
 //		a.m[2] = m.m[8]; a.m[6] = m.m[9]; a.m[10] = m.m[10];    a.m[14] = m.m[14];
 //		a.m[3] = m.m[3]; a.m[7] = m.m[7]; a.m[11] = m.m[11];    a.m[15] = m.m[15];
49ca15c4
 //		
b23636c9
 //		return a;
 //	}
 
 	// Complete transpose!
 	mat4 transpose(mat4 m)
 	{
 		mat4 a;
49ca15c4
 		
b23636c9
 		a.m[0] = m.m[0]; a.m[4] = m.m[1]; a.m[8] = m.m[2];      a.m[12] = m.m[3];
 		a.m[1] = m.m[4]; a.m[5] = m.m[5]; a.m[9] = m.m[6];      a.m[13] = m.m[7];
 		a.m[2] = m.m[8]; a.m[6] = m.m[9]; a.m[10] = m.m[10];    a.m[14] = m.m[11];
 		a.m[3] = m.m[12]; a.m[7] = m.m[13]; a.m[11] = m.m[14];    a.m[15] = m.m[15];
49ca15c4
 		
b23636c9
 		return a;
 	}
 
 	// Complete transpose!
 	mat3 TransposeMat3(mat3 m)
 	{
 		mat3 a;
49ca15c4
 		
b23636c9
 		a.m[0] = m.m[0]; a.m[3] = m.m[1]; a.m[6] = m.m[2];
 		a.m[1] = m.m[3]; a.m[4] = m.m[4]; a.m[7] = m.m[5];
 		a.m[2] = m.m[6]; a.m[5] = m.m[7]; a.m[8] = m.m[8];
49ca15c4
 		
b23636c9
 		return a;
 	}
 
 // Rotation around arbitrary axis (rotation only)
 mat4 ArbRotate(vec3 axis, GLfloat fi)
 {
 	vec3 x, y, z;
 	mat4 R, Rt, Raxel, m;
 
 // Check if parallel to Z
 	if (axis.x < 0.0000001) // Below some small value
 	if (axis.x > -0.0000001)
 	if (axis.y < 0.0000001)
 	if (axis.y > -0.0000001)
 	{
 		if (axis.z > 0)
 		{
 			m = Rz(fi);
 			return m;
 		}
 		else
 		{
 			m = Rz(-fi);
 			return m;
 		}
 	}
 
 	x = Normalize(axis);
 	z = SetVector(0,0,1); // Temp z
 	y = Normalize(CrossProduct(z, x)); // y' = z^ x x'
 	z = CrossProduct(x, y); // z' = x x y
 
 	if (transposed)
 	{
 		R.m[0] = x.x; R.m[4] = x.y; R.m[8] = x.z;  R.m[12] = 0.0;
 		R.m[1] = y.x; R.m[5] = y.y; R.m[9] = y.z;  R.m[13] = 0.0;
 		R.m[2] = z.x; R.m[6] = z.y; R.m[10] = z.z;  R.m[14] = 0.0;
 
 		R.m[3] = 0.0; R.m[7] = 0.0; R.m[11] = 0.0;  R.m[15] = 1.0;
 	}
 	else
 	{
 		R.m[0] = x.x; R.m[1] = x.y; R.m[2] = x.z;  R.m[3] = 0.0;
 		R.m[4] = y.x; R.m[5] = y.y; R.m[6] = y.z;  R.m[7] = 0.0;
 		R.m[8] = z.x; R.m[9] = z.y; R.m[10] = z.z;  R.m[11] = 0.0;
 
 		R.m[12] = 0.0; R.m[13] = 0.0; R.m[14] = 0.0;  R.m[15] = 1.0;
 	}
 
7dcf10dc
 	Rt = Transpose(R); // Transpose = Invert -> felet ej i Transpose, och det är en ortonormal matris
b23636c9
 
 	Raxel = Rx(fi); // Rotate around x axis
 
 	// m := Rt * Rx * R
 	m = Mult(Mult(Rt, Raxel), R);
49ca15c4
 	
b23636c9
 	return m;
 }
 
 
 // Not tested much
 mat4 CrossMatrix(vec3 a) // Matrix for cross product
 {
 	mat4 m;
49ca15c4
 	
b23636c9
 	if (transposed)
 	{
 		m.m[0] =    0; m.m[4] =-a.z; m.m[8] = a.y; m.m[12] = 0.0;
 		m.m[1] = a.z; m.m[5] =    0; m.m[9] =-a.x; m.m[13] = 0.0;
 		m.m[2] =-a.y; m.m[6] = a.x; m.m[10]=    0; m.m[14] = 0.0;
 		m.m[3] =  0.0; m.m[7] =  0.0; m.m[11]=  0.0; m.m[15] = 0.0;
 		// NOTE! 0.0 in the homogous coordinate. Thus, the matrix can
 		// not be generally used, but is fine for matrix differentials
 	}
 	else
 	{
 		m.m[0] =    0; m.m[1] =-a.z; m.m[2] = a.y; m.m[3] = 0.0;
 		m.m[4] = a.z; m.m[5] =    0; m.m[6] =-a.x; m.m[7] = 0.0;
 		m.m[8] =-a.y; m.m[9] = a.x; m.m[10]=    0; m.m[11] = 0.0;
 		m.m[12] =  0.0; m.m[13] =  0.0; m.m[14]=  0.0; m.m[15] = 0.0;
 		// NOTE! 0.0 in the homogous coordinate. Thus, the matrix can
 		// not be generally used, but is fine for matrix differentials
 	}
49ca15c4
 	
b23636c9
 	return m;
 }
 
 mat4 MatrixAdd(mat4 a, mat4 b)
 {
 	mat4 dest;
49ca15c4
 	
b23636c9
 	int i;
 	for (i = 0; i < 16; i++)
 		dest.m[i] = a.m[i] + b.m[i];
49ca15c4
 	
b23636c9
 	return dest;
 }
 
 // 0 = row-wise defined matrices
 // 1 = column-wise
 void SetTransposed(char t)
 {
 	transposed = t;
 }
 
 
 // Build standard matrices
 
 mat4 lookAtv(vec3 p, vec3 l, vec3 v)
 {
 	vec3 n, u;
 	mat4 rot, trans;
 
 	n = Normalize(VectorSub(p, l));
 	u = Normalize(CrossProduct(v, n));
 	v = CrossProduct(n, u);
 
 	if (transposed)
 	rot = SetMat4(u.x, v.x, n.x, 0,
                   u.y, v.y, n.y, 0,
                   u.z, v.z, n.z, 0,
                   0,   0,   0,   1);
 	else
 	rot = SetMat4(u.x, u.y, u.z, 0,
                   v.x, v.y, v.z, 0,
                   n.x, n.y, n.z, 0,
                   0,   0,   0,   1);
 	trans = T(-p.x, -p.y, -p.z);
 	mat4 m = Mult(rot, trans);
 	return m;
 }
 
49ca15c4
 mat4 lookAt(GLfloat px, GLfloat py, GLfloat pz, 
b23636c9
 			GLfloat lx, GLfloat ly, GLfloat lz,
 			GLfloat vx, GLfloat vy, GLfloat vz)
 {
 	vec3 p, l, v;
49ca15c4
 	
b23636c9
 	p = SetVector(px, py, pz);
 	l = SetVector(lx, ly, lz);
 	v = SetVector(vx, vy, vz);
49ca15c4
 	
b23636c9
 	return lookAtv(p, l, v);
 }
 
 // From http://www.opengl.org/wiki/GluPerspective_code
 // Changed names and parameter order to conform with VU style
 // Rewritten 120913 because it was all wrong...
49ca15c4
 
 // Creates a projection matrix like gluPerspective or glFrustum.
 // Upload to your shader as usual.
 // Error fixed 20220525: 180, not 360!
 // Also made it conform to the reference manual.
b23636c9
 mat4 perspective(float fovyInDegrees, float aspectRatio,
                       float znear, float zfar)
 {
49ca15c4
 	float f = 1/tan(fovyInDegrees / 2);
b23636c9
 	mat4 m = SetMat4(f/aspectRatio, 0, 0, 0,
 					0, f, 0, 0,
 					0, 0, (zfar+znear)/(znear-zfar), 2*zfar*znear/(znear-zfar),
 					0, 0, -1, 0);
 	if (transposed)
 		m = transpose(m);
 	return m;
 }
 
 mat4 frustum(float left, float right, float bottom, float top,
                   float znear, float zfar)
 {
     float temp, temp2, temp3, temp4;
     mat4 matrix;
49ca15c4
     
b23636c9
     temp = 2.0f * znear;
     temp2 = right - left;
     temp3 = top - bottom;
     temp4 = zfar - znear;
     matrix.m[0] = temp / temp2; // 2*near/(right-left)
     matrix.m[1] = 0.0;
     matrix.m[2] = 0.0;
     matrix.m[3] = 0.0;
     matrix.m[4] = 0.0;
     matrix.m[5] = temp / temp3; // 2*near/(top - bottom)
     matrix.m[6] = 0.0;
     matrix.m[7] = 0.0;
     matrix.m[8] = (right + left) / temp2; // A = r+l / r-l
     matrix.m[9] = (top + bottom) / temp3; // B = t+b / t-b
     matrix.m[10] = (-zfar - znear) / temp4; // C = -(f+n) / f-n
     matrix.m[11] = -1.0;
     matrix.m[12] = 0.0;
     matrix.m[13] = 0.0;
     matrix.m[14] = (-temp * zfar) / temp4; // D = -2fn / f-n
     matrix.m[15] = 0.0;
49ca15c4
     
b23636c9
     if (!transposed)
     	matrix = Transpose(matrix);
49ca15c4
     
b23636c9
     return matrix;
 }
 
 // Not tested!
 mat4 ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far)
 {
         float a = 2.0f / (right - left);
         float b = 2.0f / (top - bottom);
         float c = -2.0f / (far - near);
 
         float tx = - (right + left)/(right - left);
         float ty = - (top + bottom)/(top - bottom);
         float tz = - (far + near)/(far - near);
 
         mat4 o = SetMat4(
             a, 0, 0, tx,
             0, b, 0, ty,
             0, 0, c, tz,
             0, 0, 0, 1);
 
         if (transposed)
    			o = Transpose(o);
 
         return o;
 }
 
 // The code below is based on code from:
 // http://www.dr-lex.be/random/matrix_inv.html
 
 // Inverts mat3 (row-wise matrix)
 // (For a more general inverse, try a gaussian elimination.)
 mat3 InvertMat3(mat3 in)
 {
 	float a11, a12, a13, a21, a22, a23, a31, a32, a33;
 	mat3 out, nanout;
 	float DET;
49ca15c4
 	
b23636c9
 	// Copying to internal variables both clarify the code and
 	// buffers data so the output may be identical to the input!
 	a11 = in.m[0];
 	a12 = in.m[1];
 	a13 = in.m[2];
 	a21 = in.m[3];
 	a22 = in.m[4];
 	a23 = in.m[5];
 	a31 = in.m[6];
 	a32 = in.m[7];
 	a33 = in.m[8];
 	DET = a11*(a33*a22-a32*a23)-a21*(a33*a12-a32*a13)+a31*(a23*a12-a22*a13);
 	if (DET != 0)
 	{
 		out.m[0] = (a33*a22-a32*a23)/DET;
 		out.m[1] = -(a33*a12-a32*a13)/DET;
 		out.m[2] = (a23*a12-a22*a13)/DET;
 		out.m[3] = -(a33*a21-a31*a23)/DET;
 		out.m[4] = (a33*a11-a31*a13)/DET;
 		out.m[5] = -(a23*a11-a21*a13)/DET;
 		out.m[6] = (a32*a21-a31*a22)/DET;
 		out.m[7] = -(a32*a11-a31*a12)/DET;
 		out.m[8] = (a22*a11-a21*a12)/DET;
 	}
 	else
 	{
 		nanout = SetMat3(NAN, NAN, NAN,
 								NAN, NAN, NAN,
 								NAN, NAN, NAN);
 		out = nanout;
 	}
49ca15c4
 	
b23636c9
 	return out;
 }
 
 // For making a normal matrix from a model-to-view matrix
 // Takes a mat4 in, ignores 4th row/column (should just be translations),
 // inverts as mat3 (row-wise matrix) and returns the transpose
 mat3 InverseTranspose(mat4 in)
 {
 	float a11, a12, a13, a21, a22, a23, a31, a32, a33;
 	mat3 out, nanout;
 	float DET;
49ca15c4
 	
b23636c9
 	// Copying to internal variables
 	a11 = in.m[0];
 	a12 = in.m[1];
 	a13 = in.m[2];
 	a21 = in.m[4];
 	a22 = in.m[5];
 	a23 = in.m[6];
 	a31 = in.m[8];
 	a32 = in.m[9];
 	a33 = in.m[10];
 	DET = a11*(a33*a22-a32*a23)-a21*(a33*a12-a32*a13)+a31*(a23*a12-a22*a13);
 	if (DET != 0)
 	{
 		out.m[0] = (a33*a22-a32*a23)/DET;
 		out.m[3] = -(a33*a12-a32*a13)/DET;
 		out.m[6] = (a23*a12-a22*a13)/DET;
 		out.m[1] = -(a33*a21-a31*a23)/DET;
 		out.m[4] = (a33*a11-a31*a13)/DET;
 		out.m[7] = -(a23*a11-a21*a13)/DET;
 		out.m[2] = (a32*a21-a31*a22)/DET;
 		out.m[5] = -(a32*a11-a31*a12)/DET;
 		out.m[8] = (a22*a11-a21*a12)/DET;
 	}
 	else
 	{
 		nanout = SetMat3(NAN, NAN, NAN,
 								NAN, NAN, NAN,
 								NAN, NAN, NAN);
 		out = nanout;
 	}
 
 	return out;
 }
 
 
 // Simple conversions
 mat3 mat4tomat3(mat4 m)
 {
 	mat3 result;
49ca15c4
 	
b23636c9
 	result.m[0] = m.m[0];
 	result.m[1] = m.m[1];
 	result.m[2] = m.m[2];
 	result.m[3] = m.m[4];
 	result.m[4] = m.m[5];
 	result.m[5] = m.m[6];
 	result.m[6] = m.m[8];
 	result.m[7] = m.m[9];
 	result.m[8] = m.m[10];
 	return result;
 }
 
 mat4 mat3tomat4(mat3 m)
 {
 	mat4 result;
49ca15c4
 	
b23636c9
 	result.m[0] = m.m[0];
 	result.m[1] = m.m[1];
 	result.m[2] = m.m[2];
 	result.m[3] = 0;
 	result.m[4] = m.m[3];
 	result.m[5] = m.m[4];
 	result.m[6] = m.m[5];
 	result.m[7] = 0;
 	result.m[8] = m.m[6];
 	result.m[9] = m.m[7];
 	result.m[10] = m.m[8];
 	result.m[11] = 0;
 
 	result.m[12] = 0;
 	result.m[13] = 0;
 	result.m[14] = 0;
 	result.m[15] = 1;
 	return result;
 }
 
 vec3 vec4tovec3(vec4 v)
 {
 	vec3 result;
 	result.x = v.x;
 	result.y = v.y;
 	result.z = v.z;
 	return result;
 }
 
 vec4 vec3tovec4(vec3 v)
 {
 	vec4 result;
 	result.x = v.x;
 	result.y = v.y;
 	result.z = v.z;
 	result.w = 1;
 	return result;
 }
 
 
 // Stol... I mean adapted from glMatrix (WebGL math unit). Almost no
 // changes despite changing language! But I just might replace it with
 // a gaussian elimination some time.
 mat4 InvertMat4(mat4 a)
 {
    mat4 b;
49ca15c4
      
b23636c9
    float c=a.m[0],d=a.m[1],e=a.m[2],g=a.m[3],
 	f=a.m[4],h=a.m[5],i=a.m[6],j=a.m[7],
 	k=a.m[8],l=a.m[9],o=a.m[10],m=a.m[11],
 	n=a.m[12],p=a.m[13],r=a.m[14],s=a.m[15],
 	A=c*h-d*f,
 	B=c*i-e*f,
 	t=c*j-g*f,
 	u=d*i-e*h,
 	v=d*j-g*h,
 	w=e*j-g*i,
 	x=k*p-l*n,
 	y=k*r-o*n,
 	z=k*s-m*n,
 	C=l*r-o*p,
 	D=l*s-m*p,
 	E=o*s-m*r,
 	q=1/(A*E-B*D+t*C+u*z-v*y+w*x);
 	b.m[0]=(h*E-i*D+j*C)*q;
 	b.m[1]=(-d*E+e*D-g*C)*q;
 	b.m[2]=(p*w-r*v+s*u)*q;
 	b.m[3]=(-l*w+o*v-m*u)*q;
 	b.m[4]=(-f*E+i*z-j*y)*q;
 	b.m[5]=(c*E-e*z+g*y)*q;
 	b.m[6]=(-n*w+r*t-s*B)*q;
 	b.m[7]=(k*w-o*t+m*B)*q;
 	b.m[8]=(f*D-h*z+j*x)*q;
 	b.m[9]=(-c*D+d*z-g*x)*q;
 	b.m[10]=(n*v-p*t+s*A)*q;
 	b.m[11]=(-k*v+l*t-m*A)*q;
 	b.m[12]=(-f*C+h*y-i*x)*q;
 	b.m[13]=(c*C-d*y+e*x)*q;
 	b.m[14]=(-n*u+p*B-r*A)*q;
 	b.m[15]=(k*u-l*B+o*A)*q;
 	return b;
 };
 
 
 // Two convenient printing functions suggested by Christian Luckey 2015.
 // Added printMat3 2019.
 void printMat4(mat4 m)
 {
 	unsigned int i;
 	printf(" ---------------------------------------------------------------\n");
 	for (i = 0; i < 4; i++)
 	{
 		int n = i * 4;
 		printf("| %11.5f\t| %11.5f\t| %11.5f\t| %11.5f\t|\n",
 			m.m[n], m.m[n+1], m.m[n+2], m.m[n+3]);
 	}
 	printf(" ---------------------------------------------------------------\n");
 }
 
 void printMat3(mat3 m)
 {
 	unsigned int i;
 	printf(" ---------------------------------------------------------------\n");
 	for (i = 0; i < 3; i++)
 	{
 		int n = i * 3;
 		printf("| %11.5f\t| %11.5f\t| %11.5f\t| \n",
 			m.m[n], m.m[n+1], m.m[n+2]);
 	}
 	printf(" ---------------------------------------------------------------\n");
 }
 
49ca15c4
 void printVec3(vec3 in) 
b23636c9
 {
 	printf("(%f, %f, %f)\n", in.x, in.y, in.z);
 }
 
e797f203
 /* Utility functions for easier uploads to shaders with error messages. */
 // NEW as prototype 2022, added to VU 2023
 
 #define NUM_ERRORS 8
 
 static void ReportError(const char *caller, const char *name)
 {
 	static unsigned int draw_error_counter = 0; 
 	if(draw_error_counter < NUM_ERRORS)
 	{
 		fprintf(stderr, "%s warning: '%s' not found in shader!\n", caller, name);
 		draw_error_counter++;
 	}
 	else if(draw_error_counter == NUM_ERRORS)
 	{
 		fprintf(stderr, "%s: Number of errors bigger than %i. No more vill be printed.\n", caller, NUM_ERRORS);
 		draw_error_counter++;
 	}
 }
 
49ca15c4
 void uploadMat4ToShader(GLuint shader, const char *nameInShader, mat4 m)
e797f203
 {
 	if (nameInShader == NULL) return;
 	glUseProgram(shader);
 	GLint loc = glGetUniformLocation(shader, nameInShader);
 	if (loc >= 0)
 		glUniformMatrix4fv(loc, 1, GL_TRUE, m.m);
 	else
 		ReportError("uploadMat4ToShader", nameInShader);
 }
 
49ca15c4
 void uploadUniformIntToShader(GLuint shader, const char *nameInShader, GLint i)
e797f203
 {
 	if (nameInShader == NULL) return;
 	glUseProgram(shader);
 	GLint loc = glGetUniformLocation(shader, nameInShader);
 	if (loc >= 0)
 		glUniform1i(loc, i);
 	else
 		ReportError("uploadUniformIntToShader", nameInShader);
 }
 
49ca15c4
 void uploadUniformFloatToShader(GLuint shader, const char *nameInShader, GLfloat f)
e797f203
 {
 	if (nameInShader == NULL) return;
 	glUseProgram(shader);
 	GLint loc = glGetUniformLocation(shader, nameInShader);
 	if (loc >= 0)
 		glUniform1f(loc, f);
 	else
 		ReportError("uploadUniformFloatToShader", nameInShader);
 }
 
49ca15c4
 void uploadUniformFloatArrayToShader(GLuint shader, const char *nameInShader, GLfloat *f, int arrayLength)
e797f203
 {
 	if (nameInShader == NULL) return;
 	glUseProgram(shader);
 	GLint loc = glGetUniformLocation(shader, nameInShader);
 	if (loc >= 0)
 		glUniform1fv(loc, arrayLength, f);
 	else
 		ReportError("uploadUniformFloatToShader", nameInShader);
 }
 
49ca15c4
 void uploadUniformVec3ToShader(GLuint shader, const char *nameInShader, vec3 v)
e797f203
 {
 	if (nameInShader == NULL) return;
 	glUseProgram(shader);
 	GLint loc = glGetUniformLocation(shader, nameInShader);
 	if (loc >= 0)
 		glUniform3f(loc, v.x, v.y, v.z);
 	else
 		ReportError("uploadUniformVec3ToShader", nameInShader);
 }
 
49ca15c4
 void uploadUniformVec3ArrayToShader(GLuint shader, const char *nameInShader, vec3 *a, int arrayLength)
e797f203
 {
 	if (nameInShader == NULL) return;
 	glUseProgram(shader);
 	GLint loc = glGetUniformLocation(shader, nameInShader);
 	if (loc >= 0)
 		glUniform3fv(loc, arrayLength, (GLfloat *)a);
 	else
 		ReportError("uploadUniformVec3ArrayToShader", nameInShader);
 }
 
 void bindTextureToTextureUnit(GLuint tex, int unit)
 {
 	glActiveTexture(GL_TEXTURE0 + unit);
 	glBindTexture(GL_TEXTURE_2D, tex);
 }
 
b23636c9
 #ifdef __cplusplus
 mat3 inverse(mat3 m)
 {
 	return InvertMat3(m);
 }
 mat4 inverse(mat4 m)
 {
 	return InvertMat4(m);
 }
 mat3 transpose(mat3 m)
 {
 	return TransposeMat3(m);
 }
 mat4 S(GLfloat s)
 {
 	return S(s, s, s);
 }
 mat4 S(vec3 s)
 {
 	return S(s.x, s.y, s.z);
 }
 mat4 lookAt(vec3 p, vec3 l, vec3 u)
 {
 	return lookAtv(p, l, u);
 }
 
5973d707
 
 #ifdef __cplusplus
 	vec3::vec3(vec4 v) : x(v.x), y(v.y), z(v.z) {}
 	// Was wrong, fixed 2023-02-27
 	mat4::mat4(mat3 x)
 	{
 		m[0]  = x.m[0]; m[1]  = x.m[1]; m[2] =  x.m[2]; m[3]  = 0;
 		m[4]  = x.m[3]; m[5]  = x.m[4]; m[6] =  x.m[5]; m[7]  = 0;
 		m[8]  = x.m[6]; m[9]  = x.m[7]; m[10] = x.m[8]; m[11] = 0;
 		m[12] = 0;      m[13] = 0;      m[14] = 0;      m[15] = 1;
 	}
 #endif
 
 
b23636c9
 #endif
 #endif
 #endif