Repository: Zuzu-Typ/PyGLM (language: python)

Issue:
add constructor for matrices from diagonal
Hello, 
thanks again for maintaining that wonderful module.
I was wondering if it could be possible to implement an additional constructor for matrices.

Right now it's already possible to initialize a diagonal matrix from a user-given value:
```python
>>> mat3(5)
mat3x3(( 5, 0, 0 ), ( 0, 5, 0 ), ( 0, 0, 5 ))
```

However there is no shorthand to create one with custom elements on the diagonal. I was thinking to something like this:
```python
>>> mat3(1,2,3)    # option 1
mat3x3(( 1, 0, 0 ), ( 0, 2, 0 ), ( 0, 0, 3 ))

>>> mat3(vec3(1,2,3))   # options 2
mat3x3(( 1, 0, 0 ), ( 0, 2, 0 ), ( 0, 0, 3 ))

>>> diag(1,2,3)    # options 3
mat3x3(( 1, 0, 0 ), ( 0, 2, 0 ), ( 0, 0, 3 ))
```

My current way to do that job is of course:
```python
m = mat3()
m[0,0] = 1
m[1,1] = 2
m[2,2] = 3
```

What do you think of this ?


Discussion / hints:

Fix patch:
diff --git a/PyGLM/type_methods/glmArray.h b/PyGLM/type_methods/glmArray.h
index 0f05498..4c4f88c 100644
--- a/PyGLM/type_methods/glmArray.h
+++ b/PyGLM/type_methods/glmArray.h
@@ -510,11 +510,6 @@ glmArray_getbuffer(glmArray* self, Py_buffer* view, int flags) {
 		PyErr_SetString(PyExc_ValueError, "NULL view in getbuffer");
 		return -1;
 	}
-	if ((flags & PyBUF_STRIDES) != PyBUF_STRIDES || (flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) {
-		PyErr_SetString(PyExc_BufferError, "This type of buffer is not supported.");
-		view->obj = NULL;
-		return -1;
-	}
 
 	view->obj = (PyObject*)self;
 	view->buf = self->data;
@@ -534,75 +529,152 @@ glmArray_getbuffer(glmArray* self, Py_buffer* view, int flags) {
 		const int R = self->getShape(1);
 
 		view->ndim = 3;
-		if (flags & PyBUF_ND) {
+		if (flags == 0 || (flags & (PyBUF_ANY_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_C_CONTIGUOUS)) == PyBUF_STRIDES) { // strided, non contiguous buffer
 			view->shape = (Py_ssize_t*)PyMem_Malloc(3 * sizeof(Py_ssize_t));
 			if (view->shape != NULL) {
 				view->shape[0] = self->itemCount;
 				view->shape[1] = R;
 				view->shape[2] = C;
 			}
-		}
-		else {
-			view->shape = NULL;
-		}
-		if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+
 			view->strides = (Py_ssize_t*)PyMem_Malloc(3 * sizeof(Py_ssize_t));
 			if (view->strides != NULL) {
-				view->strides[0] =  self->dtSize * C * R;
+				view->strides[0] = self->dtSize * C * R;
 				view->strides[1] = self->dtSize;
 				view->strides[2] = R * self->dtSize;
 			}
 		}
-		else {
-			view->strides = NULL;
-		}
-	}
-	else if (self->glmType == PyGLM_TYPE_VEC) {
-		const int L = self->getShape();
-
-		view->ndim = 2;
-		if (flags & PyBUF_ND) {
-			view->shape = (Py_ssize_t*)PyMem_Malloc(2 * sizeof(Py_ssize_t));
+		else if ((flags & PyBUF_WRITABLE) == 0 && ((flags & PyBUF_STRIDES) == PyBUF_ND || (flags & PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS || (flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS)) {
+			view->shape = (Py_ssize_t*)PyMem_Malloc(3 * sizeof(Py_ssize_t));
 			if (view->shape != NULL) {
 				view->shape[0] = self->itemCount;
-				view->shape[1] = L;
+				view->shape[1] = R;
+				view->shape[2] = C;
+			}
+
+			view->strides = (Py_ssize_t*)PyMem_Malloc(3 * sizeof(Py_ssize_t));
+			if (view->strides != NULL) {
+				view->strides[0] = self->dtSize * C * R;
+				view->strides[1] = C * self->dtSize;
+				view->strides[2] = self->dtSize;
+			}
+
+			view->readonly = 1;
+			view->buf = PyMem_Malloc(self->nBytes);
+			if (view->buf != NULL) {
+				const ssize_t dataStride0 = self->dtSize * C * R;
+				const ssize_t bufStride0 = self->dtSize * C * R;
+				const ssize_t dataStride1 = self->dtSize;
+				const ssize_t bufStride1 = self->dtSize * C;
+				const ssize_t dataStride2 = self->dtSize * R;
+				const ssize_t bufStride2 = self->dtSize;
+
+				for (ssize_t i = 0; i < self->itemCount; i++) {
+					for (ssize_t c = 0; c < C; c++) {
+						for (ssize_t r = 0; r < R; r++) {
+							memcpy(((char*)view->buf) + (i * bufStride0 + r * bufStride1 + c * bufStride2), ((char*)self->data) + (i * dataStride0 + r * dataStride1 + c * dataStride2), self->dtSize);
+						}
+					}
+				}
 			}
 		}
-		else {
-			view->shape = NULL;
-		}
-		if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
-			view->strides = (Py_ssize_t*)PyMem_Malloc(2 * sizeof(Py_ssize_t));
+		else if ((flags & PyBUF_WRITABLE) == 0 && (flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) {
+			view->shape = (Py_ssize_t*)PyMem_Malloc(3 * sizeof(Py_ssize_t));
+			if (view->shape != NULL) {
+				view->shape[0] = self->itemCount;
+				view->shape[1] = R;
+				view->shape[2] = C;
+			}
+
+			view->strides = (Py_ssize_t*)PyMem_Malloc(3 * sizeof(Py_ssize_t));
 			if (view->strides != NULL) {
-				view->strides[0] = L * self->dtSize;
-				view->strides[1] = self->dtSize;
+				view->strides[0] = self->dtSize;
+				view->strides[1] = C * self->dtSize;
+				view->strides[2] = self->dtSize * C * R;
+			}
+
+			view->readonly = 1;
+			view->buf = PyMem_Malloc(self->nBytes);
+			if (view->buf != NULL) {
+				const ssize_t dataStride0 = self->dtSize * C * R;
+				const ssize_t bufStride0 = self->dtSize;
+				const ssize_t dataStride1 = self->dtSize;
+				const ssize_t bufStride1 = self->dtSize * C;
+				const ssize_t dataStride2 = self->dtSize * R;
+				const ssize_t bufStride2 = self->dtSize * C * R;
+
+				for (ssize_t i = 0; i < self->itemCount; i++) {
+					for (ssize_t c = 0; c < C; c++) {
+						for (ssize_t r = 0; r < R; r++) {
+							memcpy(((char*)view->buf) + (i * bufStride0 + r * bufStride1 + c * bufStride2), ((char*)self->data) + (i * dataStride0 + r * dataStride1 + c * dataStride2), self->dtSize);
+						}
+					}
+				}
 			}
 		}
 		else {
-			view->strides = NULL;
+			PyErr_SetString(PyExc_BufferError, "This type of buffer is not supported.");
+			PyMem_Free(view->format);
+			view->format = NULL;
+			view->obj = NULL;
+			view->buf = NULL;
+			return -1;
 		}
 	}
-	else if (self->glmType == PyGLM_TYPE_QUA) {
+	else if (self->glmType == PyGLM_TYPE_VEC || self->glmType == PyGLM_TYPE_QUA) {
+		const int L = (self->glmType == PyGLM_TYPE_VEC) ? self->getShape() : 4;
+
 		view->ndim = 2;
-		if (flags & PyBUF_ND) {
+		if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS && ((flags & PyBUF_WRITABLE) || L == 1)) {
 			view->shape = (Py_ssize_t*)PyMem_Malloc(2 * sizeof(Py_ssize_t));
 			if (view->shape != NULL) {
 				view->shape[0] = self->itemCount;
-				view->shape[1] = 4;
+				view->shape[1] = L;
 			}
-		}
-		else {
-			view->shape = NULL;
-		}
-		if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
 			view->strides = (Py_ssize_t*)PyMem_Malloc(2 * sizeof(Py_ssize_t));
 			if (view->strides != NULL) {
-				view->strides[0] = 4 * self->dtSize;
-				view->strides[1] = self->dtSize;
+				view->strides[0] = self->dtSize;
+				view->strides[1] = L * self->dtSize;
+			}
+
+			if (L != 1) {
+				view->readonly = 1;
+				view->buf = PyMem_Malloc(view->len);
+				if (view->buf != NULL) {
+					const ssize_t dataStride0 = self->dtSize * L;
+					const ssize_t bufStride0 = self->dtSize;
+					const ssize_t dataStride1 = self->dtSize;
+					const ssize_t bufStride1 = self->dtSize * L;
+
+					for (ssize_t i = 0; i < self->itemCount; i++) {
+						for (ssize_t l = 0; l < L; l++) {
+							memcpy(((char*)view->buf) + (i * bufStride0 + l * bufStride1), ((char*)self->data) + (i * dataStride0 + l * dataStride1), self->dtSize);
+						}
+					}
+				}
 			}
 		}
 		else {
-			view->strides = NULL;
+			if (flags & PyBUF_ND) {
+				view->shape = (Py_ssize_t*)PyMem_Malloc(2 * sizeof(Py_ssize_t));
+				if (view->shape != NULL) {
+					view->shape[0] = self->itemCount;
+					view->shape[1] = L;
+				}
+			}
+			else {
+				view->shape = NULL;
+			}
+			if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+				view->strides = (Py_ssize_t*)PyMem_Malloc(2 * sizeof(Py_ssize_t));
+				if (view->strides != NULL) {
+					view->strides[0] = L * self->dtSize;
+					view->strides[1] = self->dtSize;
+				}
+			}
+			else {
+				view->strides = NULL;
+			}
 		}
 	}
 	else if (self->glmType == PyGLM_TYPE_CTYPES) {
@@ -638,6 +710,10 @@ glmArray_releasebuffer(PyObject* self, Py_buffer* view) {
 	PyMem_Free(view->shape);
 	PyMem_Free(view->strides);
 	PyMem_Free(view->format);
+
+	if (view->readonly) {
+		PyMem_Free(view->buf);
+	}
 }
 
 
@@ -2286,8 +2362,9 @@ glmArray_init(glmArray* self, PyObject* args, PyObject* kwds) {
 		// buffer protocol
 		if (PyObject_CheckBuffer(firstElement)) {
 			Py_buffer view;
-			if (PyObject_GetBuffer(firstElement, &view, PyBUF_RECORDS_RO) == -1) {
+			if (PyObject_GetBuffer(firstElement, &view, PyBUF_RECORDS_RO) == -1 || view.buf == NULL || view.format == NULL || view.shape == NULL || view.strides == NULL) {
 				PyBuffer_Release(&view);
+				PyErr_SetString(PyExc_BufferError, "invalid buffer");
 				return -1;
 			}
 			if (view.ndim == 1) {
@@ -2399,7 +2476,7 @@ glmArray_init(glmArray* self, PyObject* args, PyObject* kwds) {
 						for (ssize_t i1 = 0; i1 < R; i1++) {
 							for (ssize_t i2 = 0; i2 < C; i2++) {
 								ssize_t origOffset = (view.strides[0] * i0 + view.strides[1] * i1 + view.strides[2] * i2);
-								ssize_t targetOffset = (self->itemCount * C * R * i0 + view.itemsize * i1 + view.itemsize * R * i2);
+								ssize_t targetOffset = (view.itemsize * C * R * i0 + view.itemsize * i1 + view.itemsize * R * i2);
 								memcpy(dataPtr + targetOffset, bufPtr + origOffset, view.itemsize);
 							}
 						}
diff --git a/PyGLM/type_methods/mat.h b/PyGLM/type_methods/mat.h
index d6768f7..79bd0ef 100644
--- a/PyGLM/type_methods/mat.h
+++ b/PyGLM/type_methods/mat.h
@@ -118,6 +118,12 @@ mat2x2_init(mat<2, 2, T> *self, PyObject *args, PyObject *)
 	}
 
 	if (arg3 == NULL) {
+		if (PyGLM_Number_Check(arg1) && PyGLM_Number_Check(arg2)) {
+			T o = PyGLM_Number_FromPyObject<T>(arg1);
+			T o2 = PyGLM_Number_FromPyObject<T>(arg2);
+			self->super_type = glm::mat<2, 2, T>(o, (T)0, (T)0, o2);
+			return 0;
+		}
 		PyGLM_PTI_Init0(arg1, (get_vec_PTI_info<2, T>()));
 		PyGLM_PTI_Init1(arg2, (get_vec_PTI_info<2, T>()));
 		if (PyGLM_PTI_IsNone(0) || PyGLM_PTI_IsNone(1)) {
@@ -230,6 +236,12 @@ mat2x3_init(mat<2, 3, T> *self, PyObject *args, PyObject *)
 	}
 
 	if (arg3 == NULL) {
+		if (PyGLM_Number_Check(arg1) && PyGLM_Number_Check(arg2)) {
+			T o = PyGLM_Number_FromPyObject<T>(arg1);
+			T o2 = PyGLM_Number_FromPyObject<T>(arg2);
+			self->super_type = glm::mat<2, 3, T>(o, (T)0, (T)0, (T)0, o2, (T)0);
+			return 0;
+		}
 		PyGLM_PTI_Init0(arg1, (get_vec_PTI_info<3, T>()));
 		PyGLM_PTI_Init1(arg2, (get_vec_PTI_info<3, T>()));
 		if (PyGLM_PTI_IsNone(0) || PyGLM_PTI_IsNone(1)) {
@@ -344,6 +356,12 @@ mat2x4_init(mat<2, 4, T> *self, PyObject *args, PyObject *)
 	}
 
 	if (arg3 == NULL) {
+		if (PyGLM_Number_Check(arg1) && PyGLM_Number_Check(arg2)) {
+			T o = PyGLM_Number_FromPyObject<T>(arg1);
+			T o2 = PyGLM_Number_FromPyObject<T>(arg2);
+			self->super_type = glm::mat<2, 4, T>(o, (T)0, (T)0, (T)0, (T)0, o2, (T)0, (T)0);
+			return 0;
+		}
 		PyGLM_PTI_Init0(arg1, (get_vec_PTI_info<4, T>()));
 		PyGLM_PTI_Init1(arg2, (get_vec_PTI_info<4, T>()));
 		if (PyGLM_PTI_IsNone(0) || PyGLM_PTI_IsNone(1)) {
@@ -456,6 +474,12 @@ mat3x2_init(mat<3, 2, T> *self, PyObject *args, PyObject *)
 	}
 
 	if (arg3 == NULL) {
+		if (PyGLM_Number_Check(arg1) && PyGLM_Number_Check(arg2)) {
+			T o = PyGLM_Number_FromPyObject<T>(arg1);
+			T o2 = PyGLM_Number_FromPyObject<T>(arg2);
+			self->super_type = glm::mat<3, 2, T>(o, (T)0, (T)0, o2, (T)0, (T)0);
+			return 0;
+		}
 		PyErr_SetString(PyExc_TypeError, "invalid argument type(s) for mat3x2()");
 		return -1;
 	}
@@ -583,6 +607,13 @@ mat3x3_init(mat<3, 3, T> *self, PyObject *args, PyObject *)
 	}
 
 	if (arg4 == NULL) {
+		if (PyGLM_Number_Check(arg1) && PyGLM_Number_Check(arg2) && PyGLM_Number_Check(arg3)) {
+			T o = PyGLM_Number_FromPyObject<T>(arg1);
+			T o2 = PyGLM_Number_FromPyObject<T>(arg2);
+			T o3 = PyGLM_Number_FromPyObject<T>(arg3);
+			self->super_type = glm::mat<3, 3, T>(o, (T)0, (T)0, (T)0, o2, (T)0, (T)0, (T)0, o3);
+			return 0;
+		}
 		PyGLM_PTI_Init0(arg1, (get_vec_PTI_info<3, T>()));
 		PyGLM_PTI_Init1(arg2, (get_vec_PTI_info<3, T>()));
 		PyGLM_PTI_Init2(arg3, (get_vec_PTI_info<3, T>()));
@@ -708,6 +739,13 @@ mat3x4_init(mat<3, 4, T> *self, PyObject *args, PyObject *)
 	}
 
 	if (arg4 == NULL) {
+		if (PyGLM_Number_Check(arg1) && PyGLM_Number_Check(arg2) && PyGLM_Number_Check(arg3)) {
+			T o = PyGLM_Number_FromPyObject<T>(arg1);
+			T o2 = PyGLM_Number_FromPyObject<T>(arg2);
+			T o3 = PyGLM_Number_FromPyObject<T>(arg3);
+			self->super_type = glm::mat<3, 4, T>(o, (T)0, (T)0, (T)0, (T)0, o2, (T)0, (T)0, (T)0, (T)0, o3, (T)0);
+			return 0;
+		}
 		PyGLM_PTI_Init0(arg1, (get_vec_PTI_info<4, T>()));
 		PyGLM_PTI_Init1(arg2, (get_vec_PTI_info<4, T>()));
 		PyGLM_PTI_Init2(arg3, (get_vec_PTI_info<4, T>()));
@@ -823,7 +861,18 @@ mat4x2_init(mat<4, 2, T> *self, PyObject *args, PyObject *)
 		return -1;
 	}
 
-	if (arg3 == NULL || arg4 == NULL) {
+	if (arg3 == NULL) {
+		if (PyGLM_Number_Check(arg1) && PyGLM_Number_Check(arg2)) {
+			T o = PyGLM_Number_FromPyObject<T>(arg1);
+			T o2 = PyGLM_Number_FromPyObject<T>(arg2);
+			self->super_type = glm::mat<4, 2, T>(o, (T)0, (T)0, o2, (T)0, (T)0, (T)0, (T)0);
+			return 0;
+		}
+		PyErr_SetString(PyExc_TypeError, "invalid argument type(s) for mat4x2()");
+		return -1;
+	}
+
+	if (arg4 == NULL) {
 		PyErr_SetString(PyExc_TypeError, "invalid argument type(s) for mat4x2()");
 		return -1;
 	}
@@ -950,7 +999,19 @@ mat4x3_init(mat<4, 3, T> *self, PyObject *args, PyObject *)
 		return -1;
 	}
 
-	if (arg3 == NULL || arg4 == NULL) {
+	if (arg3 == NULL) {
+		PyErr_SetString(PyExc_TypeError, "invalid argument type(s) for mat4x3()");
+		return -1;
+	}
+
+	if (arg4 == NULL) {
+		if (PyGLM_Number_Check(arg1) && PyGLM_Number_Check(arg2) && PyGLM_Number_Check(arg3)) {
+			T o = PyGLM_Number_FromPyObject<T>(arg1);
+			T o2 = PyGLM_Number_FromPyObject<T>(arg2);
+			T o3 = PyGLM_Number_FromPyObject<T>(arg3);
+			self->super_type = glm::mat<4, 3, T>(o, (T)0, (T)0, (T)0, o2, (T)0, (T)0, (T)0, o3, (T)0, (T)0, (T)0);
+			return 0;
+		}
 		PyErr_SetString(PyExc_TypeError, "invalid argument type(s) for mat4x3()");
 		return -1;
 	}
@@ -1087,6 +1148,14 @@ mat4x4_init(mat<4, 4, T> *self, PyObject *args, PyObject *)
 	}
 
 	if (arg5 == NULL) {
+		if (PyGLM_Number_Check(arg1) && PyGLM_Number_Check(arg2) && PyGLM_Number_Check(arg3) && PyGLM_Number_Check(arg4)) {
+			T o = PyGLM_Number_FromPyObject<T>(arg1);
+			T o2 = PyGLM_Number_FromPyObject<T>(arg2);
+			T o3 = PyGLM_Number_FromPyObject<T>(arg3);
+			T o4 = PyGLM_Number_FromPyObject<T>(arg4);
+			self->super_type = glm::mat<4, 4, T>(o, (T)0, (T)0, (T)0, (T)0, o2, (T)0, (T)0, (T)0, (T)0, o3, (T)0, (T)0, (T)0, (T)0, o4);
+			return 0;
+		}
 		PyGLM_PTI_Init0(arg1, (get_vec_PTI_info<4, T>()));
 		PyGLM_PTI_Init1(arg2, (get_vec_PTI_info<4, T>()));
 		PyGLM_PTI_Init2(arg3, (get_vec_PTI_info<4, T>()));
diff --git a/wiki/Using-matrices.md b/wiki/Using-matrices.md
index 812579a..8bb63bb 100644
--- a/wiki/Using-matrices.md
+++ b/wiki/Using-matrices.md
@@ -2,19 +2,20 @@
 
 # Using Matrices  
   
-1.  [Initialization](#Initialization)  
+1.  [Initialization](#initialization)  
     *  [with no arguments](#initialization-with-no-arguments)  
-    *  [with single number](#Initialization-with-a-single-number)  
-    *  [all components with numbers](#Initializing-all-components-with-numbers)  
-    *  [copying a matrix](#Copying-a-matrix)  
-    *  [with vectors](#Constructing-matrices-from-vectors)  
+    *  [with single number](#initialization-with-a-single-number)  
+    *  [with custom diagonal values](#initializing-the-matrix-diagonal-with-custom-values)  
+    *  [all components with numbers](#initializing-all-components-with-numbers)  
+    *  [copying a matrix](#copying-a-matrix)  
+    *  [with vectors](#constructing-matrices-from-vectors)  
     *  [Lists \(and other iterables\)](#lists-and-other-iterables)  
     *  [Buffer protocol \(numpy, bytes\)](#objects-that-support-the-buffer-protocol-numpy-bytes)  
-2.  [Methods](#Methods)  
+2.  [Methods](#methods)  
     *  [The copy protocol](#the-copy-protocol)  
     *  [Pickling](#pickling)  
     *  [To list / tuple](#to-list--tuple)  
-3.  [Operators](#Operators)  
+3.  [Operators](#operators)  
     *  [add](#add--operator)  
     *  [sub](#sub--operator)  
     *  [mul](#mul--operator)  
@@ -67,6 +68,25 @@ Example:
 [ 1.5 |   0 | 0 | 0 ]
 [   0 | 1.5 | 0 | 0 ]
  ```  
+#### Initializing the matrix diagonal with custom values  
+You can initialize a matrix' diagonal with custom values\.  
+Example:  
+``` Python
+>>> print(glm.mat2(1, 2))
+[ 1 | 0 ]
+[ 0 | 2 ]
+
+>>> print(glm.mat4(1, 2, 3, 4))
+[ 1 | 0 | 0 | 0 ]
+[ 0 | 2 | 0 | 0 ]
+[ 0 | 0 | 3 | 0 ]
+[ 0 | 0 | 0 | 4 ]
+
+>>> print(glm.mat2x4(1, 2))
+[ 1 | 0 | 0 | 0 ]
+[ 0 | 2 | 0 | 0 ]
+ ```  
+I\.e\. a ``` matNxM ``` matrix can be initialized with ``` int(sqrt(N * M)) ``` numbers\.  
 #### Initializing all components with numbers  
 A matrix ``` matNxM ``` can be initialized with *N* x *M* numbers, which will be copied \(or may be converted\) to their respective components\.&nbsp;&nbsp;  
 Example:  
diff --git a/wiki/Using-matrices.sb b/wiki/Using-matrices.sb
index 144e193..21f7128 100644
--- a/wiki/Using-matrices.sb
+++ b/wiki/Using-matrices.sb
@@ -1,18 +1,19 @@
 \h1\Using Matrices\h1\
 \lo \
-\-\ \url #Initialization \Initialization\ url\\list switch\
+\-\ \url #initialization \Initialization\ url\\list switch\
 \--\ \url #initialization-with-no-arguments \with no arguments\ url\
-\--\ \url #Initialization-with-a-single-number \with single number\ url\
-\--\ \url #Initializing-all-components-with-numbers \all components with numbers\ url\
-\--\ \url #Copying-a-matrix \copying a matrix\ url\
-\--\ \url #Constructing-matrices-from-vectors \with vectors\ url\
+\--\ \url #initialization-with-a-single-number \with single number\ url\
+\--\ \url #initializing-the-matrix-diagonal-with-custom-values \with custom diagonal values\ url\
+\--\ \url #initializing-all-components-with-numbers \all components with numbers\ url\
+\--\ \url #copying-a-matrix \copying a matrix\ url\
+\--\ \url #constructing-matrices-from-vectors \with vectors\ url\
 \--\ \url #lists-and-other-iterables \Lists (and other iterables)\ url\
 \--\ \url #objects-that-support-the-buffer-protocol-numpy-bytes \Buffer protocol (numpy, bytes)\ url\\list switch\
-\-\ \url #Methods \Methods\ url\\list switch\
+\-\ \url #methods \Methods\ url\\list switch\
 \--\ \url #the-copy-protocol \The copy protocol\ url\
 \--\ \url #pickling \Pickling\ url\
 \--\ \url #to-list--tuple \To list / tuple\ url\\list switch\
-\-\ \url #Operators \Operators\ url\\list switch\
+\-\ \url #operators \Operators\ url\\list switch\
 \--\ \url #add--operator \add\ url\
 \--\ \url #sub--operator \sub\ url\
 \--\ \url #mul--operator \mul\ url\
@@ -65,6 +66,25 @@ Example:
 [ 1.5 |   0 | 0 | 0 ]
 [   0 | 1.5 | 0 | 0 ]
 \code\
+\h4 \Initializing the matrix diagonal with custom values\ h4\
+You can initialize a matrix' diagonal with custom values.
+Example:
+\code Python \
+>>> print(glm.mat2(1, 2))
+[ 1 | 0 ]
+[ 0 | 2 ]
+
+>>> print(glm.mat4(1, 2, 3, 4))
+[ 1 | 0 | 0 | 0 ]
+[ 0 | 2 | 0 | 0 ]
+[ 0 | 0 | 3 | 0 ]
+[ 0 | 0 | 0 | 4 ]
+
+>>> print(glm.mat2x4(1, 2))
+[ 1 | 0 | 0 | 0 ]
+[ 0 | 2 | 0 | 0 ]
+\code\
+I.e. a \code\matNxM\code\ matrix can be initialized with \code\int(sqrt(N * M))\code\ numbers.
 \h4 \Initializing all components with numbers\ h4\
 A matrix \code\matNxM\code\ can be initialized with \i\N\i\ x \i\M\i\ numbers, which will be copied (or may be converted) to their respective components.  
 Example:


Test patch:
diff --git a/PyGLM_test.py b/PyGLM_test.py
index 556c681..733bb83 100644
--- a/PyGLM_test.py
+++ b/PyGLM_test.py
@@ -435,7 +435,7 @@ def test_vec4_types():
 def test_mat_types():
     for C in range(2, 5):
         for R in range(2, 5):
-            for args in gen_args("#u-_N_" + "N"*(C*R) + "_M{C}{R}__fFiI".format(C=C, R=R)): # need support for _M
+            for args in gen_args("#u-_N_" + "N"*(C*R) + "_" + "N"*(int(math.sqrt(C*R))) + "_M{C}{R}__fFiI".format(C=C, R=R)): # need support for _M
                 for T in matrix_length_dict[(C,R)]:
                     fassert(T, args)
 
@@ -1758,6 +1758,20 @@ def test_matrix_transform_2d():
         fassert(glm.scale, args)
         fassert(glm.translate, args)
 #/matrix_transform_2d #
+
+# rotate_vector #
+def test_rotate_vector():
+    for args in gen_args("V3V3__fF"):
+        fassert(glm.orientation, args)
+    for args in gen_args("V2N_V3NV3_V4NV3__fF"):
+        fassert(glm.rotate, args)
+    for args in gen_args("V3N_V4N__fF"):
+        fassert(glm.rotateX, args)
+        fassert(glm.rotateY, args)
+        fassert(glm.rotateZ, args)
+    for args in gen_args("V3V3N__fF"):
+        fassert(glm.slerp, args)
+#/rotate_vector #
 ##/UNSTABLE EXTENSIONS ##