summaryrefslogtreecommitdiffstats
path: root/hacks/glx/glsl-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/glx/glsl-utils.c')
-rw-r--r--hacks/glx/glsl-utils.c391
1 files changed, 391 insertions, 0 deletions
diff --git a/hacks/glx/glsl-utils.c b/hacks/glx/glsl-utils.c
new file mode 100644
index 0000000..e4d5d31
--- /dev/null
+++ b/hacks/glx/glsl-utils.c
@@ -0,0 +1,391 @@
+/* glsl-utils.c --- support functions for GLSL in OpenGL hacks.
+ * Copyright (c) 2020-2021 Carsten Steger <carsten@mirsanmir.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+#include "screenhackI.h"
+#include "glsl-utils.h"
+
+#include <math.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#ifdef HAVE_GLSL
+
+extern const char *progname;
+
+/* Copy a 4x4 column-major matrix: c = m. */
+void glsl_CopyMatrix(GLfloat c[16], GLfloat m[16])
+{
+ int i, j;
+
+ for (j=0; j<4; j++)
+ for (i=0; i<4; i++)
+ c[GLSL__LINCOOR(i,j,4)] = m[GLSL__LINCOOR(i,j,4)];
+}
+
+
+/* Create a 4x4 column-major identity matrix. */
+void glsl_Identity(GLfloat c[16])
+{
+ int i, j;
+
+ for (j=0; j<4; j++)
+ for (i=0; i<4; i++)
+ c[GLSL__LINCOOR(i,j,4)] = (i==j);
+}
+
+
+/* Multiply two 4x4 column-major matrices: c = c*m. */
+void glsl_MultMatrix(GLfloat c[16], GLfloat m[16])
+{
+ int i, j;
+ GLfloat t[16];
+
+ /* Copy c to t. */
+ glsl_CopyMatrix(t,c);
+ /* Compute c = t*m. */
+ for (j=0; j<4; j++)
+ for (i=0; i<4; i++)
+ c[GLSL__LINCOOR(i,j,4)] =
+ (t[GLSL__LINCOOR(i,0,4)]*m[GLSL__LINCOOR(0,j,4)]+
+ t[GLSL__LINCOOR(i,1,4)]*m[GLSL__LINCOOR(1,j,4)]+
+ t[GLSL__LINCOOR(i,2,4)]*m[GLSL__LINCOOR(2,j,4)]+
+ t[GLSL__LINCOOR(i,3,4)]*m[GLSL__LINCOOR(3,j,4)]);
+}
+
+
+/* Multiply a 4x4 column-major matrix by a rotation matrix that rotates
+ around the axis (x,y,z) by the angle angle: c = c*r(angle,x,y,z). */
+void glsl_Rotate(GLfloat c[16], GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+{
+ GLfloat l, t, ct, st, omct, n[3], r[16];
+
+ l = sqrtf(x*x+y*y+z*z);
+ n[0] = x/l;
+ n[1] = y/l;
+ n[2] = z/l;
+ t = angle*180.0f/M_PI;
+ ct = cosf(t);
+ st = sinf(t);
+ omct = 1.0f-ct;
+
+ r[GLSL__LINCOOR(0,0,4)] = n[0]*n[0]*omct+ct;
+ r[GLSL__LINCOOR(1,0,4)] = n[0]*n[1]*omct+n[2]*st;
+ r[GLSL__LINCOOR(2,0,4)] = n[0]*n[2]*omct-n[1]*st;
+ r[GLSL__LINCOOR(3,0,4)] = 0.0f;
+
+ r[GLSL__LINCOOR(0,1,4)] = n[0]*n[1]*omct-n[2]*st;
+ r[GLSL__LINCOOR(1,1,4)] = n[1]*n[1]*omct+ct;
+ r[GLSL__LINCOOR(2,1,4)] = n[1]*n[2]*omct+n[0]*st;
+ r[GLSL__LINCOOR(3,1,4)] = 0.0f;
+
+ r[GLSL__LINCOOR(0,2,4)] = n[0]*n[2]*omct+n[1]*st;
+ r[GLSL__LINCOOR(1,2,4)] = n[1]*n[2]*omct-n[0]*st;
+ r[GLSL__LINCOOR(2,2,4)] = n[2]*n[2]*omct+ct;
+ r[GLSL__LINCOOR(3,2,4)] = 0.0f;
+
+ r[GLSL__LINCOOR(0,3,4)] = 0.0f;
+ r[GLSL__LINCOOR(1,3,4)] = 0.0f;
+ r[GLSL__LINCOOR(2,3,4)] = 0.0f;
+ r[GLSL__LINCOOR(3,3,4)] = 1.0f;
+
+ glsl_MultMatrix(c,r);
+}
+
+
+/* Multiply a 4x4 column-major matrix by a matrix that stretches, shrinks,
+ or reflects an object along the axes: c = c*m(sx,sy,sz). */
+void glsl_Scale(GLfloat c[16], GLfloat sx, GLfloat sy, GLfloat sz)
+{
+ int i;
+
+ for (i=0; i<4; i++)
+ {
+ c[GLSL__LINCOOR(i,0,4)] *= sx;
+ c[GLSL__LINCOOR(i,1,4)] *= sy;
+ c[GLSL__LINCOOR(i,2,4)] *= sz;
+ }
+}
+
+
+/* Multiply a 4x4 column-major matrix by a matrix that translates an object
+ by a translation vector: c = c*t(tx,ty,tz). */
+void glsl_Translate(GLfloat c[16], GLfloat tx, GLfloat ty, GLfloat tz)
+{
+ int i;
+
+ for (i=0; i<4; i++)
+ {
+ c[GLSL__LINCOOR(i,3,4)] = (tx*c[GLSL__LINCOOR(i,0,4)]+
+ ty*c[GLSL__LINCOOR(i,1,4)]+
+ tz*c[GLSL__LINCOOR(i,2,4)]+
+ c[GLSL__LINCOOR(i,3,4)]);
+ }
+}
+
+
+/* Add a perspective projection to a 4x4 column-major matrix. */
+void glsl_Perspective(GLfloat c[16], GLfloat fovy, GLfloat aspect,
+ GLfloat z_near, GLfloat z_far)
+{
+ GLfloat m[16];
+ double s, cot, dz;
+ double rad;
+
+ rad = fovy*(0.5f*(float)M_PI/180.0f);
+ dz = z_far-z_near;
+ s = sinf(rad);
+ if (dz == 0.0f || s == 0.0f || aspect == 0.0f)
+ return;
+ cot = cosf(rad)/s;
+
+ glsl_Identity(m);
+ m[GLSL__LINCOOR(0,0,4)] = cot/aspect;
+ m[GLSL__LINCOOR(1,1,4)] = cot;
+ m[GLSL__LINCOOR(2,2,4)] = -(z_far+z_near)/dz;
+ m[GLSL__LINCOOR(3,2,4)] = -1.0f;
+ m[GLSL__LINCOOR(2,3,4)] = -2.0f*z_near*z_far/dz;
+ m[GLSL__LINCOOR(3,3,4)] = 0.0f;
+ glsl_MultMatrix(c,m);
+}
+
+
+/* Add an orthographic projection to a 4x4 column-major matrix. */
+void glsl_Orthographic(GLfloat c[16], GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat nearval, GLfloat farval)
+{
+ GLfloat m[16];
+
+ if (left == right || bottom == top || nearval == farval)
+ return;
+
+ glsl_Identity(m);
+ m[GLSL__LINCOOR(0,0,4)] = 2.0f/(right-left);
+ m[GLSL__LINCOOR(0,3,4)] = -(right+left)/(right-left);
+ m[GLSL__LINCOOR(1,1,4)] = 2.0f/(top-bottom);
+ m[GLSL__LINCOOR(1,3,4)] = -(top+bottom)/(top-bottom);
+ m[GLSL__LINCOOR(2,2,4)] = -2.0f/(farval-nearval);
+ m[GLSL__LINCOOR(2,3,4)] = -(farval+nearval)/(farval-nearval);
+ glsl_MultMatrix(c,m);
+}
+
+
+/* Get the OpenGL and GLSL versions. */
+GLboolean glsl_GetGlAndGlslVersions(GLint *gl_major, GLint *gl_minor,
+ GLint *glsl_major, GLint *glsl_minor,
+ GLboolean *gl_gles3)
+{
+ const char *gl_version, *glsl_version;
+ int n;
+ const char *err = 0;
+
+ *gl_major = -1;
+ *gl_minor = -1;
+ *glsl_major = 1;
+ *glsl_minor = -1;
+ *gl_gles3 = GL_FALSE;
+ gl_version = (const char *)glGetString(GL_VERSION);
+ glsl_version = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
+ if (gl_version == NULL || glsl_version == NULL)
+ {
+ err = "GL version unknown";
+ goto DONE;
+ }
+ if (!strncmp(gl_version,"OpenGL ES",9))
+ {
+ if (!strncmp(glsl_version,"OpenGL ES GLSL ES",17))
+ *gl_gles3 = GL_TRUE;
+ else
+ {
+ err = "GLSL not supported";
+ goto DONE;
+ }
+ }
+ if (*gl_gles3)
+ n = sscanf(&gl_version[9],"%d.%d",gl_major,gl_minor);
+ else
+ n = sscanf(gl_version,"%d.%d",gl_major,gl_minor);
+ if (n != 2)
+ {
+ err = "GL version number unparsable";
+ goto DONE;
+ }
+ if (*gl_gles3)
+ n = sscanf(&glsl_version[17],"%d.%d",glsl_major,glsl_minor);
+ else
+ n = sscanf(glsl_version,"%d.%d",glsl_major,glsl_minor);
+ if (n != 2)
+ {
+ err = "GLSL version number unparsable";
+ goto DONE;
+ }
+
+ DONE:
+
+#if 0/*# ifndef __OPTIMIZE__*/
+ if (err)
+ fprintf (stderr, "%s: GLSL: %s\n", progname, err);
+ else
+ fprintf (stderr, "%s: GLSL available: GL=%d.%d, GLSL=%d.%d GLES3=%d\n",
+ progname,
+ *gl_major, *gl_minor,
+ *glsl_major, *glsl_minor,
+ *gl_gles3 ? 1 : 0);
+# endif
+
+ return (err ? GL_FALSE : GL_TRUE);
+}
+
+
+#define PRINT_ERRORS
+/* #undef PRINT_ERRORS */
+
+#ifdef PRINT_ERRORS
+
+#define PRINT_COMPILE_ERROR(shader) print_compile_error(shader)
+#define PRINT_LINK_ERROR(program) print_link_error(program)
+
+static void print_compile_error(GLuint shader)
+{
+ GLint length_log;
+ GLsizei length;
+ GLchar *log;
+
+ glGetShaderiv(shader,GL_INFO_LOG_LENGTH,&length_log);
+ if (length_log > 0)
+ {
+ log = malloc(length_log*sizeof(*log));
+ if (log != NULL)
+ {
+ glGetShaderInfoLog(shader,length_log,&length,log);
+ fprintf(stderr,"%s: %s",progname,log);
+ }
+ free(log);
+ }
+}
+
+
+static void print_link_error(GLuint program)
+{
+ GLint length_log;
+ GLsizei length;
+ GLchar *log;
+
+ glGetProgramiv(program,GL_INFO_LOG_LENGTH,&length_log);
+ if (length_log > 0)
+ {
+ log = malloc(length_log*sizeof(*log));
+ if (log != NULL)
+ {
+ glGetProgramInfoLog(program,length_log,&length,log);
+ fprintf(stderr,"%s: %s",progname,log);
+ }
+ free(log);
+ }
+}
+
+#else
+
+#define PRINT_COMPILE_ERROR(shader)
+#define PRINT_LINK_ERROR(program)
+
+#endif
+
+
+/* Compile and link a vertex and a Fragment shader into a GLSL program. */
+GLboolean glsl_CompileAndLinkShaders(GLsizei vertex_shader_count,
+ const GLchar **vertex_shader_source,
+ GLsizei fragment_shader_count,
+ const GLchar **fragment_shader_source,
+ GLuint *shader_program)
+{
+ GLuint vertex_shader, fragment_shader;
+ GLint status;
+ const char *err = 0;
+
+ /* Create and compile the vertex shader. */
+ vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+ if (vertex_shader == 0)
+ return GL_FALSE;
+ fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+ if (fragment_shader == 0)
+ {
+ glDeleteShader(vertex_shader);
+ err = "unable to create fragment shader";
+ goto DONE;
+ }
+ glShaderSource(vertex_shader,vertex_shader_count,vertex_shader_source,
+ NULL);
+ glShaderSource(fragment_shader,fragment_shader_count,fragment_shader_source,
+ NULL);
+ glCompileShader(vertex_shader);
+ glGetShaderiv(vertex_shader,GL_COMPILE_STATUS,&status);
+ if (status == GL_FALSE)
+ {
+ PRINT_COMPILE_ERROR(vertex_shader);
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+ err = "vertex shader compilation failed";
+ goto DONE;
+ }
+ glCompileShader(fragment_shader);
+ glGetShaderiv(fragment_shader,GL_COMPILE_STATUS,&status);
+ if (status == GL_FALSE)
+ {
+ PRINT_COMPILE_ERROR(fragment_shader);
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+ err = "fragment shader compilation failed";
+ goto DONE;
+ }
+ *shader_program = glCreateProgram();
+ if (*shader_program == 0)
+ {
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+ err = "shader creation failed";
+ goto DONE;
+ }
+ glAttachShader(*shader_program,vertex_shader);
+ glAttachShader(*shader_program,fragment_shader);
+ glLinkProgram(*shader_program);
+ glGetProgramiv(*shader_program,GL_LINK_STATUS,&status);
+ if (status == GL_FALSE)
+ {
+ PRINT_LINK_ERROR(*shader_program);
+ glDeleteProgram(*shader_program);
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+ err = "shader attachment failed";
+ goto DONE;
+ }
+ /* Once the shader program has compiled successfully, we can delete the
+ vertex and fragment shaders. */
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+
+ DONE:
+ if (err)
+ fprintf (stderr, "%s: GLSL: %s\n", progname, err);
+#if 0/*# ifndef __OPTIMIZE__*/
+ else
+ fprintf (stderr, "%s: GLSL: shaders initialized\n", progname);
+# endif
+
+ return (err ? GL_FALSE : GL_TRUE);
+}
+
+
+#endif /* HAVE_GLSL */