# HG changeset patch
# User John Tsiombikas <nuclear@member.fsf.org>
# Date 1411208573 -10800
# Node ID 3d9ec6fe97d7cb51ffc6cc1e3323787fc3f13906
# Parent  6896f9cf96210fe5fa4657201c5a644dd4eba9de
- added distortion mesh generation for the OpenHMD module (unfinished)
- changed internal implementation function naming to use the vrimp_ prefix
- added an opengl helper function to load extension entry points

diff -r 6896f9cf9621 -r 3d9ec6fe97d7 example/src/main.c
--- a/example/src/main.c	Fri Sep 19 15:16:51 2014 +0300
+++ b/example/src/main.c	Sat Sep 20 13:22:53 2014 +0300
@@ -139,8 +139,8 @@
 void display(void)
 {
 	int i;
-	float proj_mat[16];
-	float rot_mat[16], view_mat[16];
+	float proj_mat[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
+	float view_mat[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
 
 	/* start drawing onto our texture render target */
 	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
@@ -164,7 +164,7 @@
 		 * use glLoadTransposeMatrixf instead of glLoadMatrixf to load it.
 		 */
 		if(vr_proj_matrix(i, 0.5, 500.0, proj_mat)) {
-			glLoadTransposeMatrixf(proj_mat);
+			glLoadMatrixf(proj_mat);
 		} else {
 			glLoadIdentity();
 			gluPerspective(50.0, (float)fb_width / 2.0 / (float)fb_height, 0.5, 500.0);
@@ -176,7 +176,7 @@
 		 */
 		glMatrixMode(GL_MODELVIEW);
 		vr_view_matrix(i, view_mat);
-		glLoadTransposeMatrixf(view_mat);
+		glLoadMatrixf(view_mat);
 		/* move the camera to the eye level of the user */
 		glTranslatef(0, -vr_get_optf(VR_OPT_EYE_HEIGHT), 0);
 
diff -r 6896f9cf9621 -r 3d9ec6fe97d7 src/mathutil.c
--- a/src/mathutil.c	Fri Sep 19 15:16:51 2014 +0300
+++ b/src/mathutil.c	Sat Sep 20 13:22:53 2014 +0300
@@ -6,7 +6,7 @@
 
 static const float idmat[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
 
-void rotation_matrix(const float *quat, float *matrix)
+void vrimp_rotation_matrix(const float *quat, float *matrix)
 {
 	matrix[0] = 1.0 - 2.0 * quat[1] * quat[1] - 2.0 * quat[2] * quat[2];
 	matrix[1] = 2.0 * quat[0] * quat[1] + 2.0 * quat[3] * quat[2];
@@ -26,10 +26,10 @@
 	matrix[12] = matrix[13] = matrix[14] = 0.0f;
 	matrix[15] = 1.0f;
 
-	transpose_matrix(matrix);
+	vrimp_transpose_matrix(matrix);
 }
 
-void translation_matrix(const float *vec, float *matrix)
+void vrimp_translation_matrix(const float *vec, float *matrix)
 {
 	memcpy(matrix, idmat, sizeof idmat);
 	matrix[12] = vec[0];
@@ -37,7 +37,7 @@
 	matrix[14] = vec[2];
 }
 
-void mult_matrix(float *dest, const float *m1, const float *m2)
+void vrimp_mult_matrix(float *dest, const float *m1, const float *m2)
 {
 	int i, j;
 	float tmp[16];
@@ -51,7 +51,7 @@
 	memcpy(dest, tmp, sizeof tmp);
 }
 
-void transpose_matrix(float *matrix)
+void vrimp_transpose_matrix(float *matrix)
 {
 	int i, j;
 	float tmp[16];
@@ -64,7 +64,7 @@
 	memcpy(matrix, tmp, sizeof tmp);
 }
 
-void print_matrix(const float *matrix)
+void vrimp_print_matrix(const float *matrix)
 {
 	int i, j;
 
diff -r 6896f9cf9621 -r 3d9ec6fe97d7 src/mathutil.h
--- a/src/mathutil.h	Fri Sep 19 15:16:51 2014 +0300
+++ b/src/mathutil.h	Sat Sep 20 13:22:53 2014 +0300
@@ -1,13 +1,13 @@
 #ifndef MATHUTIL_H_
 #define MATHUTIL_H_
 
-void rotation_matrix(const float *quat, float *matrix);
-void translation_matrix(const float *vec, float *matrix);
+void vrimp_rotation_matrix(const float *quat, float *matrix);
+void vrimp_translation_matrix(const float *vec, float *matrix);
 
-void mult_matrix(float *dest, const float *m1, const float *m2);
+void vrimp_mult_matrix(float *dest, const float *m1, const float *m2);
 
-void transpose_matrix(float *matrix);
+void vrimp_transpose_matrix(float *matrix);
 
-void print_matrix(const float *matrix);
+void vrimp_print_matrix(const float *matrix);
 
 #endif	/* MATHUTIL_H_ */
diff -r 6896f9cf9621 -r 3d9ec6fe97d7 src/mesh.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mesh.c	Sat Sep 20 13:22:53 2014 +0300
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "opengl.h"
+#include "mesh.h"
+
+static void distort_texcoords(float *tc, float aspect, float lens_center_offset, float scale,
+		const float *dist_factors);
+static float barrel_scale(float rad, const float *k);
+
+/* let's avoid a glew dependency in the library just for this */
+#ifndef GL_ARRAY_BUFFER
+#define GL_ARRAY_BUFFER			0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_STATIC_DRAW			0x88E4
+#endif
+
+#if !defined(GL_VERSION_1_5) || !defined(GL_GLEXT_PROTOTYPES)
+static void (*glGenBuffers)(GLsizei, GLuint*);
+static void (*glDeleteBuffers)(GLsizei, GLuint*);
+static void (*glBufferData)(GLenum, unsigned int, const GLvoid*, GLenum);
+static void (*glBindBuffer)(GLenum, GLuint);
+#endif
+
+int vrimp_mesh_init(struct mesh *m)
+{
+	m->prim = GL_TRIANGLES;
+
+	m->varr = 0;
+	m->iarr = 0;
+	m->num_verts = m->num_faces = 0;
+	m->vbo = m->ibo = 0;
+
+	if(!glGenBuffers) {
+		glGenBuffers = vrimp_glfunc("glGenBuffersARB");
+		glDeleteBuffers = vrimp_glfunc("glDeleteBuffersARB");
+		glBufferData = vrimp_glfunc("glBufferDataARB");
+		glBindBuffer = vrimp_glfunc("glBindBufferARB");
+
+		if(!(glGenBuffers && glDeleteBuffers && glBufferData && glBindBuffer)) {
+			fprintf(stderr, "Failed to load VBO functions\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+void vrimp_mesh_destroy(struct mesh *m)
+{
+	free(m->varr);
+	free(m->iarr);
+
+	if(m->vbo) glDeleteBuffers(1, &m->vbo);
+	if(m->ibo) glDeleteBuffers(1, &m->ibo);
+}
+
+void vrimp_mesh_draw(struct mesh *m)
+{
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	glBindBuffer(GL_ARRAY_BUFFER, m->vbo);
+	glVertexPointer(3, GL_FLOAT, sizeof(struct vertex), 0);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), (void*)offsetof(struct vertex, tx));
+
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo);
+	glDrawElements(GL_TRIANGLES, m->num_faces * 3, GL_UNSIGNED_INT, 0);
+
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+int vrimp_mesh_barrel_distortion(struct mesh *m, int usub, int vsub, float aspect,
+		float lens_center_offset, float scale, const float *dist_factors,
+		float tex_scale_x, float tex_scale_y)
+{
+	int i, j;
+	int uverts, vverts;
+	int num_verts, num_quads, num_tris;
+	struct vertex *varr, *vptr;
+	unsigned int *iarr, *iptr;
+	float du, dv;
+
+	uverts = usub + 1;
+	vverts = vsub + 1;
+
+	num_verts = uverts * vverts;
+	num_quads = usub * vsub;
+	num_tris = num_quads * 2;
+
+	if(!(varr = malloc(num_verts * sizeof *varr))) {
+		return -1;
+	}
+	if(!(iarr = malloc(num_tris * 3 * sizeof *iarr))) {
+		free(varr);
+		return -1;
+	}
+
+	du = 1.0 / (float)usub;
+	dv = 1.0 / (float)vsub;
+
+	vptr = varr;
+	for(i=0; i<vverts; i++) {
+		float v = (float)i * dv;
+		float y = 2.0 * v - 1.0;
+
+		for(j=0; j<uverts; j++) {
+			float u = (float)j * du;
+			float x = 2.0 * u - 1.0;
+			float tc[2];
+			tc[0] = u;
+			tc[1] = v;
+
+			distort_texcoords(tc, aspect, lens_center_offset, scale, dist_factors);
+
+			vptr->x = x;
+			vptr->y = y;
+			vptr->z = 0;
+			vptr->tx = tc[0] * tex_scale_x;
+			vptr->ty = tc[1] * tex_scale_y;
+			vptr++;
+		}
+	}
+
+	iptr = iarr;
+	for(i=0; i<vsub; i++) {
+		for(j=0; j<usub; j++) {
+			*iptr++ = i * uverts + j;
+			*iptr++ = (i + 1) * uverts + j;
+			*iptr++ = (i + 1) * uverts + (j + 1);
+
+			*iptr++ = i * uverts + j;
+			*iptr++ = (i + 1) * uverts + (j + 1);
+			*iptr++ = i * uverts + (j + 1);
+		}
+	}
+
+	glGenBuffers(1, &m->vbo);
+	glGenBuffers(1, &m->ibo);
+	glBindBuffer(GL_ARRAY_BUFFER, m->vbo);
+	glBufferData(GL_ARRAY_BUFFER, num_verts * sizeof *varr, varr, GL_STATIC_DRAW);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo);
+	glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_tris * 3 * sizeof *iarr, iarr, GL_STATIC_DRAW);
+
+	m->prim = GL_TRIANGLES;
+	m->num_verts = num_verts;
+	m->num_faces = num_tris;
+	return 0;
+}
+
+static void distort_texcoords(float *tc, float aspect, float lens_center_offset, float scale,
+		const float *dist_factors)
+{
+	/* map tc [0, 1] -> [-1, 1] */
+	float ptx = tc[0] * 2.0 - 1.0;
+	float pty = tc[1] * 2.0 - 1.0;
+	float rad;
+
+	ptx += lens_center_offset * 2.0;
+	pty /= aspect;	/* correct for aspect ratio */
+
+	rad = barrel_scale(ptx * ptx + pty * pty, dist_factors);
+	ptx *= rad;	/* scale the point by the computer distortion radius */
+	pty *= rad;
+
+	ptx /= scale;
+	pty /= scale;
+
+	pty *= aspect;
+	ptx -= lens_center_offset * 2.0;
+
+	/* map back to range [0, 1] */
+	tc[0] = ptx * 0.5 + 0.5;
+	tc[1] = pty * 0.5 + 0.5;
+}
+
+static float barrel_scale(float rad, const float *k)
+{
+	float radsq = rad * rad;
+	float radquad = radsq * radsq;
+	return k[0] + k[1] * radsq + k[2] * radquad + k[3] * radquad * radsq;
+}
diff -r 6896f9cf9621 -r 3d9ec6fe97d7 src/mesh.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mesh.h	Sat Sep 20 13:22:53 2014 +0300
@@ -0,0 +1,27 @@
+#ifndef MESH_H_
+#define MESH_H_
+
+struct vertex {
+	float x, y, z;
+	float tx, ty;
+};
+
+struct mesh {
+	int prim;
+	struct vertex *varr;
+	unsigned int *iarr;
+	int num_verts, num_faces;
+	unsigned int vbo, ibo;
+};
+
+int vrimp_mesh_init(struct mesh *m);
+void vrimp_mesh_destroy(struct mesh *m);
+
+void vrimp_mesh_draw(struct mesh *m);
+
+int vrimp_mesh_barrel_distortion(struct mesh *m, int usub, int vsub, float aspect,
+		float lens_center_offset, float scale, const float *dist_factors,
+		float tex_scale_x, float tex_scale_y);
+
+
+#endif	/* MESH_H_ */
diff -r 6896f9cf9621 -r 3d9ec6fe97d7 src/opengl.c
--- a/src/opengl.c	Fri Sep 19 15:16:51 2014 +0300
+++ b/src/opengl.c	Sat Sep 20 13:22:53 2014 +0300
@@ -1,18 +1,28 @@
 #include "opengl.h"
 
 #ifdef __unix__
-void vr_gl_swap_buffers(void)
+void vrimp_swap_buffers(void)
 {
 	Display *dpy = glXGetCurrentDisplay();
 	Drawable win = glXGetCurrentDrawable();
 	glXSwapBuffers(dpy, win);
 }
+
+void (*vrimp_glfunc(const char *name))()
+{
+	return glXGetProcAddress((const unsigned char*)name);
+}
 #endif
 
 #ifdef WIN32
-void vr_gl_swap_buffers(void)
+void vrimp_swap_buffers(void)
 {
 	HDC dc = wglGetCurrentDC();
 	SwapBuffers(dc);
 }
+
+void (*vrimp_glfunc(const char *name))()
+{
+	return wglGetProcAddress(name);
+}
 #endif
diff -r 6896f9cf9621 -r 3d9ec6fe97d7 src/opengl.h
--- a/src/opengl.h	Fri Sep 19 15:16:51 2014 +0300
+++ b/src/opengl.h	Sat Sep 20 13:22:53 2014 +0300
@@ -16,6 +16,8 @@
 #include <GL/glx.h>
 #endif
 
-void vr_gl_swap_buffers(void);
+void vrimp_swap_buffers(void);
+
+void (*vrimp_glfunc(const char *name))();
 
 #endif	/* VR_OPENGL_H_ */
diff -r 6896f9cf9621 -r 3d9ec6fe97d7 src/vr.c
--- a/src/vr.c	Fri Sep 19 15:16:51 2014 +0300
+++ b/src/vr.c	Sat Sep 20 13:22:53 2014 +0300
@@ -198,9 +198,9 @@
 	offs[1] = -offs[1];
 	offs[2] = -offs[2];
 
-	translation_matrix(offs, tmat);
-	rotation_matrix(quat, rmat);
-	mult_matrix(mat, tmat, rmat);
+	vrimp_translation_matrix(offs, tmat);
+	vrimp_rotation_matrix(quat, rmat);
+	vrimp_mult_matrix(mat, tmat, rmat);
 	return 1;
 }
 
@@ -238,7 +238,7 @@
 
 	if(!res) {
 		fallback_present();
-		vr_gl_swap_buffers();
+		vrimp_swap_buffers();
 	}
 	return 0;
 }
diff -r 6896f9cf9621 -r 3d9ec6fe97d7 src/vr.h
--- a/src/vr.h	Fri Sep 19 15:16:51 2014 +0300
+++ b/src/vr.h	Sat Sep 20 13:22:53 2014 +0300
@@ -1,16 +1,18 @@
 #ifndef VR_H_
 #define VR_H_
 
+/* unit: pixels */
 #define VR_OPT_DISPLAY_WIDTH	"display-xres"
 #define VR_OPT_DISPLAY_HEIGHT	"display-yres"
 #define VR_OPT_LEYE_XRES	"left-eye-xres"
 #define VR_OPT_LEYE_YRES	"left-eye-yres"
 #define VR_OPT_REYE_XRES	"right-eye-xres"
 #define VR_OPT_REYE_YRES	"right-eye-yres"
+#define VR_OPT_WIN_XOFFS	"win-xoffset"
+#define VR_OPT_WIN_YOFFS	"win-yoffset"
+/* unit: meters */
 #define VR_OPT_EYE_HEIGHT	"eye-height"
 #define VR_OPT_IPD			"ipd"
-#define VR_OPT_WIN_XOFFS	"win-xoffset"
-#define VR_OPT_WIN_YOFFS	"win-yoffset"
 
 enum {
 	VR_EYE_LEFT,
diff -r 6896f9cf9621 -r 3d9ec6fe97d7 src/vr_openhmd.c
--- a/src/vr_openhmd.c	Fri Sep 19 15:16:51 2014 +0300
+++ b/src/vr_openhmd.c	Sat Sep 20 13:22:53 2014 +0300
@@ -27,6 +27,7 @@
 static int init(void)
 {
 	int i, num_hmds;
+	float distort_k[6];
 
 	if(!(ctx = ohmd_ctx_create())) {
 		fprintf(stderr, "failed to create OpenHMD context\n");
@@ -69,6 +70,14 @@
 		set_option_int(optdb, VR_OPT_REYE_YRES, (int)(disp_height * FB_EMBIGGEN));
 	}
 
+	ohmd_device_getf(dev, OHMD_DISTORTION_K, distort_k);
+	printf("k: %g %g %g   %g %g %g\n", distort_k[0], distort_k[1], distort_k[2],
+			distort_k[3], distort_k[4], distort_k[5]);
+	/* TODO: DK2 returns all zeros here ... maybe we should detect that and switch to
+	 * using the DK2 distortion mesh from the Oculus SDK. I'll have to connect the DK1
+	 * again to finish the barrel distortion method.
+	 */
+
 	return 0;
 }
 
@@ -184,7 +193,7 @@
 		m.proj_matrix = proj_matrix;
 		m.begin = begin;
 		m.present = present;
-		m.set_eye_texture = set_eye_texture;
+		/*m.set_eye_texture = set_eye_texture;*/
 		m.recenter = recenter;
 	}
 	return &m;