diff options
Diffstat (limited to 'hacks/glx/projectiveplane.c')
-rw-r--r-- | hacks/glx/projectiveplane.c | 1381 |
1 files changed, 1131 insertions, 250 deletions
diff --git a/hacks/glx/projectiveplane.c b/hacks/glx/projectiveplane.c index 5f42d60..1220772 100644 --- a/hacks/glx/projectiveplane.c +++ b/hacks/glx/projectiveplane.c @@ -2,10 +2,10 @@ that rotates in 4d or on which you can walk */ #if 0 -static const char sccsid[] = "@(#)projectiveplane.c 1.1 03/01/14 xlockmore"; +static const char sccsid[] = "@(#)projectiveplane.c 1.1 14/01/03 xlockmore"; #endif -/* Copyright (c) 2013-2020 Carsten Steger <carsten@mirsanmir.org>. */ +/* Copyright (c) 2013-2021 Carsten Steger <carsten@mirsanmir.org>. */ /* * Permission to use, copy, modify, and distribute this software and its @@ -21,9 +21,12 @@ static const char sccsid[] = "@(#)projectiveplane.c 1.1 03/01/14 xlockmore"; * other special, indirect and consequential damages. * * REVISION HISTORY: - * C. Steger - 03/01/14: Initial version - * C. Steger - 03/10/14: Moved the curlicue texture to curlicue.h - * C. Steger - 06/01/20: Added the changing colors mode. + * C. Steger - 14/01/03: Initial version + * C. Steger - 14/10/03: Moved the curlicue texture to curlicue.h + * C. Steger - 20/01/06: Added the changing colors mode + * C. Steger - 20/12/05: Added per-fragment shading + * C. Steger - 20/12/06: Moved all GLSL support code into glsl-utils.[hc] + * C. Steger - 20/12/30: Make the shader code work under macOS and iOS */ /* @@ -225,9 +228,11 @@ static const char sccsid[] = "@(#)projectiveplane.c 1.1 03/01/14 xlockmore"; #define DEF_WALK_DIRECTION "83.0" #define DEF_WALK_SPEED "20.0" + #ifdef STANDALONE -# define DEFAULTS "*delay: 10000 \n" \ +# define DEFAULTS "*delay: 25000 \n" \ "*showFPS: False \n" \ + "*prefersGLSL: True \n" \ # define release_projectiveplane 0 # include "xlockmore.h" /* from the xscreensaver distribution */ @@ -241,6 +246,7 @@ static const char sccsid[] = "@(#)projectiveplane.c 1.1 03/01/14 xlockmore"; # include <X11/keysym.h> #endif +#include "glsl-utils.h" #include "gltrackball.h" #include <float.h> @@ -355,6 +361,13 @@ ENTRYPOINT ModeSpecOpt projectiveplane_opts = #define NUMB 8 +#if !defined(__GNUC__) && !defined(__extension__) + /* don't warn about "string length is greater than the length ISO C89 + compilers are required to support" in these string constants... */ +# define __extension__ /**/ +#endif + + typedef struct { GLint WindH, WindW; GLXContext *glx_context; @@ -398,11 +411,220 @@ typedef struct { Bool button_pressed; /* A random factor to modify the rotation speeds */ float speed_scale; +#ifdef HAVE_GLSL + GLfloat uv[(NUMU+1)*(NUMV+1)][2]; + GLuint indices[4*(NUMU+1)*(NUMV+1)]; + Bool use_shaders, buffers_initialized; + GLuint shader_program; + GLint vertex_uv_index, vertex_t_index, color_index; + GLint mat_rot_index, mat_p_index, bool_persp_index; + GLint off4d_index, off3d_index; + GLint bool_textures_index, draw_lines_index; + GLint glbl_ambient_index, lt_ambient_index; + GLint lt_diffuse_index, lt_specular_index; + GLint lt_direction_index, lt_halfvect_index; + GLint front_ambient_index, back_ambient_index; + GLint front_diffuse_index, back_diffuse_index; + GLint specular_index, shininess_index; + GLint texture_sampler_index; + GLuint vertex_uv_buffer, vertex_t_buffer; + GLuint color_buffer, indices_buffer; + GLint ni, ne, nt; +#endif /* HAVE_GLSL */ } projectiveplanestruct; static projectiveplanestruct *projectiveplane = (projectiveplanestruct *) NULL; +#ifdef HAVE_GLSL + +/* The GLSL versions that correspond to different versions of OpenGL. */ +static const GLchar *shader_version_2_1 = + "#version 120\n"; +static const GLchar *shader_version_3_0 = + "#version 130\n"; +static const GLchar *shader_version_3_0_es = + "#version 300 es\n" + "precision highp float;\n" + "precision highp int;\n"; + +/* The vertex shader code is composed of code fragments that depend on + the OpenGL version and code fragments that are version-independent. + They are concatenated by glsl_CompileAndLinkShaders in the function + init_glsl(). */ +static const GLchar *vertex_shader_attribs_2_1 = + "attribute vec2 VertexUV;\n" + "attribute vec4 VertexT;\n" + "attribute vec4 VertexColor;\n" + "\n" + "varying vec3 Normal;\n" + "varying vec4 Color;\n" + "varying vec4 TexCoord;\n" + "\n"; +static const GLchar *vertex_shader_attribs_3_0 = + "in vec2 VertexUV;\n" + "in vec4 VertexT;\n" + "in vec4 VertexColor;\n" + "\n" + "out vec3 Normal;\n" + "out vec4 Color;\n" + "out vec4 TexCoord;\n" + "\n"; +static const GLchar *vertex_shader_main = + __extension__ + "uniform mat4 MatRot4D;\n" + "uniform mat4 MatProj;\n" + "uniform bool BoolPersp;\n" + "uniform vec4 Offset4D;\n" + "uniform vec4 Offset3D;\n" + "uniform bool BoolTextures;\n" + "\n" + "void main (void)\n" + "{\n" + " const float EPSILON = 1.0e-7f;\n" + " float u, v, su, cu, s2u, c2u, sv2, cv2, sv4, cv4;\n" + " vec3 p, pu, pv;\n" + " u = VertexUV.x;\n" + " v = VertexUV.y;\n" + " su = sin(u)\n;" + " cu = cos(u)\n;" + " s2u = sin(2.0f*u)\n;" + " c2u = cos(2.0f*u)\n;" + " sv2 = sin(0.5f*v)\n;" + " cv2 = cos(0.5f*v)\n;" + " sv4 = sin(0.25f*v)\n;" + " cv4 = cos(0.25f*v)\n;" + " vec4 xx = vec4(0.5f*s2u*sv4*sv4,\n" + " 0.5f*su*sv2,\n" + " 0.5f*cu*sv2,\n" + " 0.5f*(su*su*sv4*sv4-cv4*cv4));\n" + " if (v < EPSILON)\n" + " {\n" + " v = EPSILON;\n" + " sv2 = sin(0.5f*v)\n;" + " cv2 = cos(0.5f*v)\n;" + " sv4 = sin(0.25f*v)\n;" + " }\n" + " vec4 xxu = vec4(c2u*sv4*sv4,\n" + " 0.5f*cu*sv2,\n" + " -0.5f*su*sv2,\n" + " 0.5f*s2u*sv4*sv4);\n" + " vec4 xxv = vec4(0.125f*s2u*sv2,\n" + " 0.25f*su*cv2,\n" + " 0.25f*cu*cv2,\n" + " 0.125f*(su*su+1.0f)*sv2);\n" + " vec4 x = MatRot4D*xx+Offset4D;\n" + " vec4 xu = MatRot4D*xxu;\n" + " vec4 xv = MatRot4D*xxv;\n" + " if (BoolPersp)\n" + " {\n" + " vec3 r = x.xyz;\n" + " float s = x.w;\n" + " float t = s*s;\n" + " p = r/s+Offset3D.xyz;\n" + " pu = (s*xu.xyz-r*xu.w)/t;\n" + " pv = (s*xv.xyz-r*xv.w)/t;\n" + " }\n" + " else\n" + " {\n" + " p = x.xyz+Offset3D.xyz;\n" + " pu = xu.xyz;\n" + " pv = xv.xyz;\n" + " }\n" + " vec4 Position = vec4(p,1.0);\n" + " Normal = normalize(cross(pu,pv));\n" + " gl_Position = MatProj*Position;\n" + " Color = VertexColor;\n" + " if (BoolTextures)\n" + " TexCoord = VertexT;\n" + "}\n"; + +/* The fragment shader code is composed of code fragments that depend on + the OpenGL version and code fragments that are version-independent. + They are concatenated by glsl_CompileAndLinkShaders in the function + init_glsl(). */ +static const GLchar *fragment_shader_attribs_2_1 = + "varying vec3 Normal;\n" + "varying vec4 Color;\n" + "varying vec4 TexCoord;\n" + "\n"; +static const GLchar *fragment_shader_attribs_3_0 = + "in vec3 Normal;\n" + "in vec4 Color;\n" + "in vec4 TexCoord;\n" + "\n" + "out vec4 FragColor;\n" + "\n"; +static const GLchar *fragment_shader_main = + __extension__ + "uniform bool DrawLines;\n" + "uniform vec4 LtGlblAmbient;\n" + "uniform vec4 LtAmbient, LtDiffuse, LtSpecular;\n" + "uniform vec3 LtDirection, LtHalfVector;\n" + "uniform vec4 MatFrontAmbient, MatBackAmbient;\n" + "uniform vec4 MatFrontDiffuse, MatBackDiffuse;\n" + "uniform vec4 MatSpecular;\n" + "uniform float MatShininess;\n" + "uniform bool BoolTextures;\n" + "uniform sampler2D TextureSampler;" + "\n" + "void main (void)\n" + "{\n" + " vec4 color;\n" + " if (DrawLines)\n" + " {\n" + " color = Color;\n" + " }\n" + " else\n" + " {\n" + " vec3 normalDirection;\n" + " vec4 ambientColor, diffuseColor, sceneColor;\n" + " vec4 ambientLighting, diffuseReflection, specularReflection;\n" + " float ndotl, ndoth, pf;\n" + " \n" + " if (gl_FrontFacing)\n" + " {\n" + " normalDirection = normalize(Normal);\n" + " sceneColor = Color*MatFrontAmbient*LtGlblAmbient;\n" + " ambientColor = Color*MatFrontAmbient;\n" + " diffuseColor = Color*MatFrontDiffuse;\n" + " }\n" + " else\n" + " {\n" + " normalDirection = -normalize(Normal);\n" + " sceneColor = Color*MatBackAmbient*LtGlblAmbient;\n" + " ambientColor = Color*MatBackAmbient;\n" + " diffuseColor = Color*MatBackDiffuse;\n" + " }\n" + " \n" + " ndotl = max(0.0,dot(normalDirection,LtDirection));\n" + " ndoth = max(0.0,dot(normalDirection,LtHalfVector));\n" + " if (ndotl == 0.0)\n" + " pf = 0.0;\n" + " else\n" + " pf = pow(ndoth,MatShininess);\n" + " ambientLighting = ambientColor*LtAmbient;\n" + " diffuseReflection = LtDiffuse*diffuseColor*ndotl;\n" + " specularReflection = LtSpecular*MatSpecular*pf;\n" + " color = sceneColor+ambientLighting+diffuseReflection;\n"; +static const GLchar *fragment_shader_out_2_1 = + " if (BoolTextures)\n" + " color *= texture2D(TextureSampler,TexCoord.st);" + " color += specularReflection;\n" + " }\n" + " gl_FragColor = clamp(color,0.0,1.0);\n" + "}\n"; +static const GLchar *fragment_shader_out_3_0 = + " if (BoolTextures)\n" + " color *= texture(TextureSampler,TexCoord.st);" + " color += specularReflection;\n" + " }\n" + " FragColor = clamp(color,0.0,1.0);\n" + "}\n"; + +#endif /* HAVE_GLSL */ + + /* Add a rotation around the wx-plane to the matrix m. */ static void rotatewx(float m[4][4], float phi) { @@ -771,13 +993,13 @@ static void setup_projective_plane(ModeInfo *mi, double umin, double umax, else u = ur*j/NUMU+umin; v = vr*i/NUMV+vmin; - cu = cos(u); su = sin(u); - c2u = cos(2.0*u); + cu = cos(u); s2u = sin(2.0*u); + c2u = cos(2.0*u); sv2 = sin(0.5*v); - cv4 = cos(0.25*v); sv4 = sin(0.25*v); + cv4 = cos(0.25*v); w = 0.5*(su*su*sv4*sv4-cv4*cv4); if (!pp->change_colors) { @@ -800,8 +1022,8 @@ static void setup_projective_plane(ModeInfo *mi, double umin, double umax, /* Avoid degenerate tangential plane basis vectors. */ if (v < FLT_EPSILON) v = FLT_EPSILON; - cv2 = cos(0.5*v); sv2 = sin(0.5*v); + cv2 = cos(0.5*v); sv4 = sin(0.25*v); pp->xu[k][0] = c2u*sv4*sv4; pp->xu[k][1] = 0.5*cu*sv2; @@ -816,11 +1038,161 @@ static void setup_projective_plane(ModeInfo *mi, double umin, double umax, } -/* Draw a 4d embedding of the projective plane projected into 3D. */ -static int projective_plane(ModeInfo *mi, double umin, double umax, - double vmin, double vmax) +/* Compute the current walk frame, i.e., the coordinate system of the + point and direction at which the viewer is currently walking on the + projective plane. */ +static void compute_walk_frame(projectiveplanestruct *pp, float mat[4][4]) +{ + int l, m; + double u, v; + double q, r, s, t; + double cu, su, cv2, sv2, cv4, sv4, c2u, s2u; + float p[3], pu[3], pv[3], pm[3], n[3], b[3]; + double xx[4], xxu[4], xxv[4], y[4], yu[4], yv[4]; + + /* Compute the rotation that rotates the projective plane in 4D without + the trackball rotations. */ + rotateall4d(pp->zeta,pp->eta,pp->theta,mat); + + u = pp->umove; + v = pp->vmove; + su = sin(u); + cu = cos(u); + s2u = sin(2.0*u); + c2u = cos(2.0*u); + sv2 = sin(0.5*v); + sv4 = sin(0.25*v); + cv4 = cos(0.25*v); + xx[0] = 0.5*s2u*sv4*sv4; + xx[1] = 0.5*su*sv2; + xx[2] = 0.5*cu*sv2; + xx[3] = 0.5*(su*su*sv4*sv4-cv4*cv4); + /* Avoid degenerate tangential plane basis vectors. */ + if (v < FLT_EPSILON) + v = FLT_EPSILON; + sv2 = sin(0.5*v); + cv2 = cos(0.5*v); + sv4 = sin(0.25*v); + xxu[0] = c2u*sv4*sv4; + xxu[1] = 0.5*cu*sv2; + xxu[2] = -0.5*su*sv2; + xxu[3] = 0.5*s2u*sv4*sv4; + xxv[0] = 0.125*s2u*sv2; + xxv[1] = 0.25*su*cv2; + xxv[2] = 0.25*cu*cv2; + xxv[3] = 0.125*(su*su+1.0)*sv2; + for (l=0; l<4; l++) + { + y[l] = (mat[l][0]*xx[0]+mat[l][1]*xx[1]+ + mat[l][2]*xx[2]+mat[l][3]*xx[3]); + yu[l] = (mat[l][0]*xxu[0]+mat[l][1]*xxu[1]+ + mat[l][2]*xxu[2]+mat[l][3]*xxu[3]); + yv[l] = (mat[l][0]*xxv[0]+mat[l][1]*xxv[1]+ + mat[l][2]*xxv[2]+mat[l][3]*xxv[3]); + } + if (pp->projection_4d == DISP_4D_ORTHOGRAPHIC) + { + for (l=0; l<3; l++) + { + p[l] = y[l]+pp->offset4d[l]; + pu[l] = yu[l]; + pv[l] = yv[l]; + } + } + else + { + s = y[3]+pp->offset4d[3]; + q = 1.0/s; + t = q*q; + for (l=0; l<3; l++) + { + r = y[l]+pp->offset4d[l]; + p[l] = r*q; + pu[l] = (yu[l]*s-r*yu[3])*t; + pv[l] = (yv[l]*s-r*yv[3])*t; + } + } + n[0] = pu[1]*pv[2]-pu[2]*pv[1]; + n[1] = pu[2]*pv[0]-pu[0]*pv[2]; + n[2] = pu[0]*pv[1]-pu[1]*pv[0]; + t = 1.0/(pp->side*4.0*sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2])); + n[0] *= t; + n[1] *= t; + n[2] *= t; + pm[0] = pu[0]*pp->dumove+pv[0]*pp->dvmove; + pm[1] = pu[1]*pp->dumove+pv[1]*pp->dvmove; + pm[2] = pu[2]*pp->dumove+pv[2]*pp->dvmove; + t = 1.0/(4.0*sqrt(pm[0]*pm[0]+pm[1]*pm[1]+pm[2]*pm[2])); + pm[0] *= t; + pm[1] *= t; + pm[2] *= t; + b[0] = n[1]*pm[2]-n[2]*pm[1]; + b[1] = n[2]*pm[0]-n[0]*pm[2]; + b[2] = n[0]*pm[1]-n[1]*pm[0]; + t = 1.0/(4.0*sqrt(b[0]*b[0]+b[1]*b[1]+b[2]*b[2])); + b[0] *= t; + b[1] *= t; + b[2] *= t; + + /* Compute alpha, beta, delta from the three basis vectors. + | -b[0] -b[1] -b[2] | + m = | n[0] n[1] n[2] | + | -pm[0] -pm[1] -pm[2] | + */ + pp->alpha = atan2(-n[2],-pm[2])*180/M_PI; + pp->beta = atan2(-b[2],sqrt(b[0]*b[0]+b[1]*b[1]))*180/M_PI; + pp->delta = atan2(b[1],-b[0])*180/M_PI; + + /* Compute the rotation that rotates the projective plane in 4D. */ + rotateall(pp->alpha,pp->beta,pp->delta,pp->zeta,pp->eta,pp->theta,mat); + + u = pp->umove; + v = pp->vmove; + su = sin(u); + cu = cos(u); + s2u = sin(2.0*u); + sv2 = sin(0.5*v); + sv4 = sin(0.25*v); + cv4 = cos(0.25*v); + xx[0] = 0.5*s2u*sv4*sv4; + xx[1] = 0.5*su*sv2; + xx[2] = 0.5*cu*sv2; + xx[3] = 0.5*(su*su*sv4*sv4-cv4*cv4); + for (l=0; l<4; l++) + { + r = 0.0; + for (m=0; m<4; m++) + r += mat[l][m]*xx[m]; + y[l] = r; + } + if (pp->projection_4d == DISP_4D_ORTHOGRAPHIC) + { + for (l=0; l<3; l++) + p[l] = y[l]+pp->offset4d[l]; + } + else + { + s = y[3]+pp->offset4d[3]; + for (l=0; l<3; l++) + p[l] = (y[l]+pp->offset4d[l])/s; + } + + pp->offset3d[0] = -p[0]; + pp->offset3d[1] = -p[1]-DELTAY; + pp->offset3d[2] = -p[2]; +} + + +/* Draw a 4d embedding of the projective plane projected into 3D using + OpenGL's fixed functionality. */ +static int projective_plane_ff(ModeInfo *mi, double umin, double umax, + double vmin, double vmax) { - int polys = 0; + static const GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; + static const GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; + static const GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; + static const GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; + static const GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; static const GLfloat mat_diff_red[] = { 1.0, 0.0, 0.0, 1.0 }; static const GLfloat mat_diff_green[] = { 0.0, 1.0, 0.0, 1.0 }; static const GLfloat mat_diff_oneside[] = { 0.9, 0.4, 0.3, 1.0 }; @@ -828,150 +1200,105 @@ static int projective_plane(ModeInfo *mi, double umin, double umax, static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 }; static const GLfloat mat_diff_trans_oneside[] = { 0.9, 0.4, 0.3, 0.7 }; float mat_diff_dyn[4], mat_diff_dyn_compl[4]; - float p[3], pu[3], pv[3], pm[3], n[3], b[3], mat[4][4], matc[3][3]; + float pu[3], pv[3], mat[4][4], matc[3][3]; int i, j, k, l, m, o; double u, v, ur, vr; - double xx[4], xxu[4], xxv[4], y[4], yu[4], yv[4]; + double y[4], yu[4], yv[4]; double q, r, s, t; - double cu, su, cv2, sv2, cv4, sv4, c2u, s2u; float q1[4], q2[4], r1[4][4], r2[4][4]; projectiveplanestruct *pp = &projectiveplane[MI_SCREEN(mi)]; + int polys; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (pp->projection_3d == DISP_3D_PERSPECTIVE || + pp->view == VIEW_WALK || pp->view == VIEW_WALKTURN) + { + if (pp->view == VIEW_WALK || pp->view == VIEW_WALKTURN) + gluPerspective(60.0,pp->aspect,0.01,10.0); + else + gluPerspective(60.0,pp->aspect,0.1,10.0); + } + else + { + if (pp->aspect >= 1.0) + glOrtho(-0.6*pp->aspect,0.6*pp->aspect,-0.6,0.6,0.1,10.0); + else + glOrtho(-0.6,0.6,-0.6/pp->aspect,0.6/pp->aspect,0.1,10.0); + } + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if (pp->display_mode == DISP_SURFACE) + { + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); + glShadeModel(GL_SMOOTH); + glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient); + glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); + glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular); + glLightfv(GL_LIGHT0,GL_POSITION,light_position); + glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular); + glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0); + glDisable(GL_BLEND); + } + else if (pp->display_mode == DISP_TRANSPARENT) + { + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + glShadeModel(GL_SMOOTH); + glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient); + glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); + glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular); + glLightfv(GL_LIGHT0,GL_POSITION,light_position); + glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular); + glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + } + else /* pp->display_mode == DISP_WIREFRAME */ + { + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); + glShadeModel(GL_FLAT); + glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); + glDisable(GL_LIGHTING); + glDisable(GL_LIGHT0); + glDisable(GL_BLEND); + } + + if (pp->marks) + { + glEnable(GL_TEXTURE_2D); +#ifndef HAVE_JWZGLES + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR); +#endif + } + else + { + glDisable(GL_TEXTURE_2D); +#ifndef HAVE_JWZGLES + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR); +#endif + } if (pp->change_colors) rotateall3d(pp->rho,pp->sigma,pp->tau,matc); if (pp->view == VIEW_WALK || pp->view == VIEW_WALKTURN) { - /* Compute the rotation that rotates the projective plane in 4D without - the trackball rotations. */ - rotateall4d(pp->zeta,pp->eta,pp->theta,mat); - - u = pp->umove; - v = pp->vmove; - cu = cos(u); - su = sin(u); - c2u = cos(2.0*u); - s2u = sin(2.0*u); - sv2 = sin(0.5*v); - cv4 = cos(0.25*v); - sv4 = sin(0.25*v); - xx[0] = 0.5*s2u*sv4*sv4; - xx[1] = 0.5*su*sv2; - xx[2] = 0.5*cu*sv2; - xx[3] = 0.5*(su*su*sv4*sv4-cv4*cv4); - /* Avoid degenerate tangential plane basis vectors. */ - if (v < FLT_EPSILON) - v = FLT_EPSILON; - cv2 = cos(0.5*v); - sv2 = sin(0.5*v); - sv4 = sin(0.25*v); - xxu[0] = c2u*sv4*sv4; - xxu[1] = 0.5*cu*sv2; - xxu[2] = -0.5*su*sv2; - xxu[3] = 0.5*s2u*sv4*sv4; - xxv[0] = 0.125*s2u*sv2; - xxv[1] = 0.25*su*cv2; - xxv[2] = 0.25*cu*cv2; - xxv[3] = 0.125*(su*su+1.0)*sv2; - for (l=0; l<4; l++) - { - y[l] = (mat[l][0]*xx[0]+mat[l][1]*xx[1]+ - mat[l][2]*xx[2]+mat[l][3]*xx[3]); - yu[l] = (mat[l][0]*xxu[0]+mat[l][1]*xxu[1]+ - mat[l][2]*xxu[2]+mat[l][3]*xxu[3]); - yv[l] = (mat[l][0]*xxv[0]+mat[l][1]*xxv[1]+ - mat[l][2]*xxv[2]+mat[l][3]*xxv[3]); - } - if (pp->projection_4d == DISP_4D_ORTHOGRAPHIC) - { - for (l=0; l<3; l++) - { - p[l] = y[l]+pp->offset4d[l]; - pu[l] = yu[l]; - pv[l] = yv[l]; - } - } - else - { - s = y[3]+pp->offset4d[3]; - q = 1.0/s; - t = q*q; - for (l=0; l<3; l++) - { - r = y[l]+pp->offset4d[l]; - p[l] = r*q; - pu[l] = (yu[l]*s-r*yu[3])*t; - pv[l] = (yv[l]*s-r*yv[3])*t; - } - } - n[0] = pu[1]*pv[2]-pu[2]*pv[1]; - n[1] = pu[2]*pv[0]-pu[0]*pv[2]; - n[2] = pu[0]*pv[1]-pu[1]*pv[0]; - t = 1.0/(pp->side*4.0*sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2])); - n[0] *= t; - n[1] *= t; - n[2] *= t; - pm[0] = pu[0]*pp->dumove+pv[0]*pp->dvmove; - pm[1] = pu[1]*pp->dumove+pv[1]*pp->dvmove; - pm[2] = pu[2]*pp->dumove+pv[2]*pp->dvmove; - t = 1.0/(4.0*sqrt(pm[0]*pm[0]+pm[1]*pm[1]+pm[2]*pm[2])); - pm[0] *= t; - pm[1] *= t; - pm[2] *= t; - b[0] = n[1]*pm[2]-n[2]*pm[1]; - b[1] = n[2]*pm[0]-n[0]*pm[2]; - b[2] = n[0]*pm[1]-n[1]*pm[0]; - t = 1.0/(4.0*sqrt(b[0]*b[0]+b[1]*b[1]+b[2]*b[2])); - b[0] *= t; - b[1] *= t; - b[2] *= t; - - /* Compute alpha, beta, delta from the three basis vectors. - | -b[0] -b[1] -b[2] | - m = | n[0] n[1] n[2] | - | -pm[0] -pm[1] -pm[2] | - */ - pp->alpha = atan2(-n[2],-pm[2])*180/M_PI; - pp->beta = atan2(-b[2],sqrt(b[0]*b[0]+b[1]*b[1]))*180/M_PI; - pp->delta = atan2(b[1],-b[0])*180/M_PI; - - /* Compute the rotation that rotates the projective plane in 4D. */ - rotateall(pp->alpha,pp->beta,pp->delta,pp->zeta,pp->eta,pp->theta,mat); - - u = pp->umove; - v = pp->vmove; - cu = cos(u); - su = sin(u); - s2u = sin(2.0*u); - sv2 = sin(0.5*v); - cv4 = cos(0.25*v); - sv4 = sin(0.25*v); - xx[0] = 0.5*s2u*sv4*sv4; - xx[1] = 0.5*su*sv2; - xx[2] = 0.5*cu*sv2; - xx[3] = 0.5*(su*su*sv4*sv4-cv4*cv4); - for (l=0; l<4; l++) - { - r = 0.0; - for (m=0; m<4; m++) - r += mat[l][m]*xx[m]; - y[l] = r; - } - if (pp->projection_4d == DISP_4D_ORTHOGRAPHIC) - { - for (l=0; l<3; l++) - p[l] = y[l]+pp->offset4d[l]; - } - else - { - s = y[3]+pp->offset4d[3]; - for (l=0; l<3; l++) - p[l] = (y[l]+pp->offset4d[l])/s; - } - - pp->offset3d[0] = -p[0]; - pp->offset3d[1] = -p[1]-DELTAY; - pp->offset3d[2] = -p[2]; + /* Compute the walk frame. */ + compute_walk_frame(pp,mat); } else { @@ -1103,7 +1430,7 @@ static int projective_plane(ModeInfo *mi, double umin, double umax, { for (k=0; k<=1; k++) { - l = (i+k); + l = i+k; m = j; o = l*(NUMU+1)+m; glNormal3fv(pp->pn[o]); @@ -1131,7 +1458,6 @@ static int projective_plane(ModeInfo *mi, double umin, double umax, glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,pp->col[o]); } glVertex3fv(pp->pp[o]); - polys++; } } glEnd(); @@ -1152,7 +1478,7 @@ static int projective_plane(ModeInfo *mi, double umin, double umax, for (k=0; k<=1; k++) { l = i; - m = (j+k); + m = j+k; o = l*(NUMU+1)+m; glNormal3fv(pp->pn[o]); glTexCoord2fv(pp->tex[o]); @@ -1179,26 +1505,505 @@ static int projective_plane(ModeInfo *mi, double umin, double umax, glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,pp->col[o]); } glVertex3fv(pp->pp[o]); - polys++; } } glEnd(); } } - polys /= 2; + polys = 2*NUMU*NUMV; + if (pp->appearance != APPEARANCE_SOLID) + polys /= 2; + return polys; +} + + +#ifdef HAVE_GLSL + +/* Draw a 4d embedding of the projective plane projected into 3D using + OpenGL's programmable functionality. */ +static int projective_plane_pf(ModeInfo *mi, double umin, double umax, + double vmin, double vmax) +{ + static const GLfloat light_model_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; + static const GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; + static const GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; + static const GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; + static const GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; + static const GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; + static const GLfloat mat_diff_red[] = { 1.0, 0.0, 0.0, 1.0 }; + static const GLfloat mat_diff_green[] = { 0.0, 1.0, 0.0, 1.0 }; + static const GLfloat mat_diff_oneside[] = { 0.9, 0.4, 0.3, 1.0 }; + static const GLfloat mat_diff_trans_red[] = { 1.0, 0.0, 0.0, 0.7 }; + static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 }; + static const GLfloat mat_diff_trans_oneside[] = { 0.9, 0.4, 0.3, 0.7 }; + static const GLfloat mat_diff_white[] = { 1.0, 1.0, 1.0, 1.0 }; + GLfloat light_direction[3], half_vector[3], len; + GLfloat p_mat[16]; + float mat_diff_dyn[4], mat_diff_dyn_compl[4]; + float mat[4][4], matc[3][3]; + int i, j, k, l, m, o; + double u, v, ur, vr; + float q1[4], q2[4], r1[4][4], r2[4][4]; + GLsizeiptr index_offset; + projectiveplanestruct *pp = &projectiveplane[MI_SCREEN(mi)]; + int polys; + + if (!pp->use_shaders) + return 0; + + if (!pp->buffers_initialized) + { + /* The u and v values need to be computed once (or each time the value + of appearance changes, once we support that). */ + ur = umax-umin; + vr = vmax-vmin; + for (i=0; i<=NUMV; i++) + { + for (j=0; j<=NUMU; j++) + { + o = i*(NUMU+1)+j; + if (pp->appearance != APPEARANCE_DIRECTION_BANDS) + u = -ur*j/NUMU+umin; + else + u = ur*j/NUMU+umin; + v = vr*i/NUMV+vmin; + pp->uv[o][0] = u; + pp->uv[o][1] = v; + } + } + glBindBuffer(GL_ARRAY_BUFFER,pp->vertex_uv_buffer); + glBufferData(GL_ARRAY_BUFFER,2*(NUMU+1)*(NUMV+1)*sizeof(GLfloat), + pp->uv,GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER,0); + + glBindBuffer(GL_ARRAY_BUFFER,pp->vertex_t_buffer); + glBufferData(GL_ARRAY_BUFFER,2*(NUMU+1)*(NUMV+1)*sizeof(GLfloat), + pp->tex,GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER,0); + + if (!pp->change_colors && + pp->colors != COLORS_ONESIDED && pp->colors != COLORS_TWOSIDED) + { + glBindBuffer(GL_ARRAY_BUFFER,pp->color_buffer); + glBufferData(GL_ARRAY_BUFFER,4*(NUMU+1)*(NUMV+1)*sizeof(GLfloat), + pp->col,GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER,0); + } + + /* The indices only need to be computed once (or each time the value of + appearance changes, once we support that). */ + pp->ni = 0; + pp->ne = 0; + pp->nt = 0; + if (pp->display_mode != DISP_WIREFRAME) + { + if (pp->appearance != APPEARANCE_DIRECTION_BANDS) + { + for (i=0; i<NUMV; i++) + { + if (pp->appearance == APPEARANCE_DISTANCE_BANDS && + ((i & (NUMB-1)) >= NUMB/4) && ((i & (NUMB-1)) < 3*NUMB/4)) + continue; + for (j=0; j<=NUMU; j++) + { + for (k=0; k<=1; k++) + { + l = i+k; + m = j; + o = l*(NUMU+1)+m; + pp->indices[pp->ni++] = o; + } + } + pp->ne++; + } + pp->nt = 2*(NUMU+1); + } + else /* pp->appearance == APPEARANCE_DIRECTION_BANDS */ + { + for (j=0; j<NUMU; j++) + { + if ((j & (NUMB-1)) >= NUMB/2) + continue; + for (i=0; i<=NUMV; i++) + { + for (k=0; k<=1; k++) + { + l = i; + m = j+k; + o = l*(NUMU+1)+m; + pp->indices[pp->ni++] = o; + } + } + pp->ne++; + } + pp->nt = 2*(NUMV+1); + } + } + else /* pp->display_mode == DISP_WIREFRAME */ + { + if (pp->appearance != APPEARANCE_DIRECTION_BANDS) + { + for (i=0; i<=NUMV; i++) + { + if (pp->appearance == APPEARANCE_DISTANCE_BANDS && + ((i & (NUMB-1)) > NUMB/4) && ((i & (NUMB-1)) < 3*NUMB/4)) + continue; + if (pp->appearance == APPEARANCE_DISTANCE_BANDS && + ((i & (NUMB-1)) == NUMB/4)) + { + for (j=0; j<NUMU; j++) + { + pp->indices[pp->ni++] = i*(NUMU+1)+j; + pp->indices[pp->ni++] = i*(NUMU+1)+j+1; + } + continue; + } + for (j=0; j<NUMU; j++) + { + pp->indices[pp->ni++] = i*(NUMU+1)+j; + pp->indices[pp->ni++] = i*(NUMU+1)+j+1; + if (i < NUMV) + { + pp->indices[pp->ni++] = i*(NUMU+1)+j; + pp->indices[pp->ni++] = (i+1)*(NUMU+1)+j; + } + } + } + } + else /* pp->appearance == APPEARANCE_DIRECTION_BANDS */ + { + for (j=0; j<NUMU; j++) + { + if ((j & (NUMB-1)) > NUMB/2) + continue; + if ((j & (NUMB-1)) == NUMB/2) + { + for (i=0; i<NUMV; i++) + { + pp->indices[pp->ni++] = i*(NUMU+1)+j; + pp->indices[pp->ni++] = (i+1)*(NUMU+1)+j; + } + continue; + } + for (i=0; i<=NUMV; i++) + { + pp->indices[pp->ni++] = i*(NUMU+1)+j; + pp->indices[pp->ni++] = i*(NUMU+1)+j+1; + if (i < NUMV) + { + pp->indices[pp->ni++] = i*(NUMU+1)+j; + pp->indices[pp->ni++] = (i+1)*(NUMU+1)+j; + } + } + } + } + pp->ne = 1; + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,pp->indices_buffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER,pp->ni*sizeof(GLuint), + pp->indices,GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + + pp->buffers_initialized = True; + } + + if (pp->change_colors) + rotateall3d(pp->rho,pp->sigma,pp->tau,matc); + + if (pp->view == VIEW_WALK || pp->view == VIEW_WALKTURN) + { + /* Compute the walk frame. */ + compute_walk_frame(pp,mat); + } + else + { + /* Compute the rotation that rotates the projective plane in 4D, + including the trackball rotations. */ + rotateall(pp->alpha,pp->beta,pp->delta,pp->zeta,pp->eta,pp->theta,r1); + + gltrackball_get_quaternion(pp->trackballs[0],q1); + gltrackball_get_quaternion(pp->trackballs[1],q2); + quats_to_rotmat(q1,q2,r2); + + mult_rotmat(r2,r1,mat); + } + + if (pp->change_colors && + (pp->colors == COLORS_DEPTH || pp->colors == COLORS_DIRECTION || + pp->colors == COLORS_DISTANCE)) + { + ur = umax-umin; + vr = vmax-vmin; + for (i=0; i<=NUMV; i++) + { + for (j=0; j<=NUMU; j++) + { + o = i*(NUMU+1)+j; + if (pp->colors == COLORS_DEPTH) + { + color(pp,(2.0*pp->x[o][3]+1.0)*M_PI*2.0/3.0,matc,pp->col[o]); + } + else if (pp->colors == COLORS_DIRECTION) + { + u = -ur*j/NUMU+umin; + color(pp,2.0*M_PI+fmod(2.0*u,2.0*M_PI),matc,pp->col[o]); + } + else if (pp->colors == COLORS_DISTANCE) + { + v = vr*i/NUMV+vmin; + color(pp,v*(5.0/6.0),matc,pp->col[o]); + } + } + } + } + + glUseProgram(pp->shader_program); + + glsl_Identity(p_mat); + if (pp->projection_3d == DISP_3D_PERSPECTIVE || + pp->view == VIEW_WALK || pp->view == VIEW_WALKTURN) + { + if (pp->view == VIEW_WALK || pp->view == VIEW_WALKTURN) + glsl_Perspective(p_mat,60.0f,pp->aspect,0.01f,10.0f); + else + glsl_Perspective(p_mat,60.0f,pp->aspect,0.1f,10.0f); + } + else + { + if (pp->aspect >= 1.0) + glsl_Orthographic(p_mat,-0.6f*pp->aspect,0.6f*pp->aspect,-0.6f,0.6f, + 0.1f,10.0f); + else + glsl_Orthographic(p_mat,-0.6f,0.6f,-0.6f/pp->aspect,0.6f/pp->aspect, + 0.1f,10.0f); + } + glUniformMatrix4fv(pp->mat_rot_index,1,GL_TRUE,(GLfloat *)mat); + glUniformMatrix4fv(pp->mat_p_index,1,GL_FALSE,p_mat); + glUniform1i(pp->bool_persp_index,pp->projection_4d == DISP_4D_PERSPECTIVE); + glUniform4fv(pp->off4d_index,1,pp->offset4d); + glUniform4fv(pp->off3d_index,1,pp->offset3d); + + len = sqrtf(light_position[0]*light_position[0]+ + light_position[1]*light_position[1]+ + light_position[2]*light_position[2]); + light_direction[0] = light_position[0]/len; + light_direction[1] = light_position[1]/len; + light_direction[2] = light_position[2]/len; + half_vector[0] = light_direction[0]; + half_vector[1] = light_direction[1]; + half_vector[2] = light_direction[2]+1.0f; + len = sqrtf(half_vector[0]*half_vector[0]+ + half_vector[1]*half_vector[1]+ + half_vector[2]*half_vector[2]); + half_vector[0] /= len; + half_vector[1] /= len; + half_vector[2] /= len; + + if (pp->display_mode == DISP_SURFACE) + { + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + glUniform4fv(pp->glbl_ambient_index,1,light_model_ambient); + glUniform4fv(pp->lt_ambient_index,1,light_ambient); + glUniform4fv(pp->lt_diffuse_index,1,light_diffuse); + glUniform4fv(pp->lt_specular_index,1,light_specular); + glUniform3fv(pp->lt_direction_index,1,light_direction); + glUniform3fv(pp->lt_halfvect_index,1,half_vector); + glUniform4fv(pp->specular_index,1,mat_specular); + glUniform1f(pp->shininess_index,50.0f); + glUniform1i(pp->draw_lines_index,GL_FALSE); + } + else if (pp->display_mode == DISP_TRANSPARENT) + { + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + glUniform4fv(pp->glbl_ambient_index,1,light_model_ambient); + glUniform4fv(pp->lt_ambient_index,1,light_ambient); + glUniform4fv(pp->lt_diffuse_index,1,light_diffuse); + glUniform4fv(pp->lt_specular_index,1,light_specular); + glUniform3fv(pp->lt_direction_index,1,light_direction); + glUniform3fv(pp->lt_halfvect_index,1,half_vector); + glUniform4fv(pp->specular_index,1,mat_specular); + glUniform1f(pp->shininess_index,50.0f); + glUniform1i(pp->draw_lines_index,GL_FALSE); + } + else /* pp->display_mode == DISP_WIREFRAME */ + { + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + glUniform1i(pp->draw_lines_index,GL_TRUE); + } + + if (pp->marks) + glEnable(GL_TEXTURE_2D); + else + glDisable(GL_TEXTURE_2D); + + glUniform4fv(pp->front_ambient_index,1,mat_diff_white); + glUniform4fv(pp->front_diffuse_index,1,mat_diff_white); + glUniform4fv(pp->back_ambient_index,1,mat_diff_white); + glUniform4fv(pp->back_diffuse_index,1,mat_diff_white); + glVertexAttrib4f(pp->color_index,1.0f,1.0f,1.0f,1.0f); + if (!pp->change_colors) + { + if (pp->colors == COLORS_ONESIDED) + { + if (pp->display_mode == DISP_TRANSPARENT) + { + glUniform4fv(pp->front_ambient_index,1,mat_diff_trans_oneside); + glUniform4fv(pp->front_diffuse_index,1,mat_diff_trans_oneside); + glUniform4fv(pp->back_ambient_index,1,mat_diff_trans_oneside); + glUniform4fv(pp->back_diffuse_index,1,mat_diff_trans_oneside); + } + else if (pp->display_mode == DISP_SURFACE) + { + glUniform4fv(pp->front_ambient_index,1,mat_diff_oneside); + glUniform4fv(pp->front_diffuse_index,1,mat_diff_oneside); + glUniform4fv(pp->back_ambient_index,1,mat_diff_oneside); + glUniform4fv(pp->back_diffuse_index,1,mat_diff_oneside); + } + else /* pp->display_mode == DISP_WIREFRAME */ + { + glVertexAttrib4fv(pp->color_index,mat_diff_oneside); + } + } + else if (pp->colors == COLORS_TWOSIDED) + { + if (pp->display_mode == DISP_TRANSPARENT) + { + glUniform4fv(pp->front_ambient_index,1,mat_diff_trans_red); + glUniform4fv(pp->front_diffuse_index,1,mat_diff_trans_red); + glUniform4fv(pp->back_ambient_index,1,mat_diff_trans_green); + glUniform4fv(pp->back_diffuse_index,1,mat_diff_trans_green); + } + else if (pp->display_mode == DISP_SURFACE) + { + glUniform4fv(pp->front_ambient_index,1,mat_diff_red); + glUniform4fv(pp->front_diffuse_index,1,mat_diff_red); + glUniform4fv(pp->back_ambient_index,1,mat_diff_green); + glUniform4fv(pp->back_diffuse_index,1,mat_diff_green); + } + else /* pp->display_mode == DISP_WIREFRAME */ + { + glVertexAttrib4fv(pp->color_index,mat_diff_red); + } + } + } + else /* pp->change_colors */ + { + color(pp,0.0,matc,mat_diff_dyn); + if (pp->colors == COLORS_ONESIDED) + { + if (pp->display_mode == DISP_TRANSPARENT || + pp->display_mode == DISP_SURFACE) + { + glUniform4fv(pp->front_ambient_index,1,mat_diff_dyn); + glUniform4fv(pp->front_diffuse_index,1,mat_diff_dyn); + glUniform4fv(pp->back_ambient_index,1,mat_diff_dyn); + glUniform4fv(pp->back_diffuse_index,1,mat_diff_dyn); + } + else /* pp->display_mode == DISP_WIREFRAME */ + { + glVertexAttrib4fv(pp->color_index,mat_diff_dyn); + } + } + else if (pp->colors == COLORS_TWOSIDED) + { + if (pp->display_mode == DISP_TRANSPARENT || + pp->display_mode == DISP_SURFACE) + { + mat_diff_dyn_compl[0] = 1.0f-mat_diff_dyn[0]; + mat_diff_dyn_compl[1] = 1.0f-mat_diff_dyn[1]; + mat_diff_dyn_compl[2] = 1.0f-mat_diff_dyn[2]; + mat_diff_dyn_compl[3] = mat_diff_dyn[3]; + glUniform4fv(pp->front_ambient_index,1,mat_diff_dyn); + glUniform4fv(pp->front_diffuse_index,1,mat_diff_dyn); + glUniform4fv(pp->back_ambient_index,1,mat_diff_dyn_compl); + glUniform4fv(pp->back_diffuse_index,1,mat_diff_dyn_compl); + } + else /* pp->display_mode == DISP_WIREFRAME */ + { + glVertexAttrib4fv(pp->color_index,mat_diff_dyn); + } + } + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,pp->tex_name); + glUniform1i(pp->texture_sampler_index,0); + glUniform1i(pp->bool_textures_index,pp->marks); + + glEnableVertexAttribArray(pp->vertex_uv_index); + glBindBuffer(GL_ARRAY_BUFFER,pp->vertex_uv_buffer); + glVertexAttribPointer(pp->vertex_uv_index,2,GL_FLOAT,GL_FALSE,0,0); + + glEnableVertexAttribArray(pp->vertex_t_index); + glBindBuffer(GL_ARRAY_BUFFER,pp->vertex_t_buffer); + glVertexAttribPointer(pp->vertex_t_index,2,GL_FLOAT,GL_FALSE,0,0); + + if (pp->colors != COLORS_ONESIDED && pp->colors != COLORS_TWOSIDED) + { + glEnableVertexAttribArray(pp->color_index); + glBindBuffer(GL_ARRAY_BUFFER,pp->color_buffer); + if (pp->change_colors) + glBufferData(GL_ARRAY_BUFFER,4*(NUMU+1)*(NUMV+1)*sizeof(GLfloat), + pp->col,GL_STREAM_DRAW); + glVertexAttribPointer(pp->color_index,4,GL_FLOAT,GL_FALSE,0,0); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,pp->indices_buffer); + + if (pp->display_mode != DISP_WIREFRAME) + { + for (i=0; i<pp->ne; i++) + { + index_offset = pp->nt*i*sizeof(GLuint); + glDrawElements(GL_TRIANGLE_STRIP,pp->nt,GL_UNSIGNED_INT, + (const GLvoid *)index_offset); + } + } + else /* pp->display_mode == DISP_WIREFRAME */ + { + glLineWidth(1.0f); + index_offset = 0; + glDrawElements(GL_LINES,pp->ni,GL_UNSIGNED_INT, + (const void *)index_offset); + } + + glDisableVertexAttribArray(pp->vertex_uv_index); + glDisableVertexAttribArray(pp->vertex_t_index); + if (pp->colors != COLORS_ONESIDED && pp->colors != COLORS_TWOSIDED) + glDisableVertexAttribArray(pp->color_index); + glBindBuffer(GL_ARRAY_BUFFER,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + + glUseProgram(0); + + polys = 2*NUMU*NUMV; + if (pp->appearance != APPEARANCE_SOLID) + polys /= 2; return polys; } +#endif /* HAVE_GLSL */ + /* Generate a texture image that shows the orientation reversal. */ static void gen_texture(ModeInfo *mi) { projectiveplanestruct *pp = &projectiveplane[MI_SCREEN(mi)]; + glPixelStorei(GL_UNPACK_ALIGNMENT,1); glGenTextures(1,&pp->tex_name); glBindTexture(GL_TEXTURE_2D,pp->tex_name); - glPixelStorei(GL_UNPACK_ALIGNMENT,1); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); @@ -1209,13 +2014,150 @@ static void gen_texture(ModeInfo *mi) } +#ifdef HAVE_GLSL + +static void init_glsl(ModeInfo *mi) +{ + projectiveplanestruct *pp = &projectiveplane[MI_SCREEN(mi)]; + GLint gl_major, gl_minor, glsl_major, glsl_minor; + GLboolean gl_gles3; + const GLchar *vertex_shader_source[3]; + const GLchar *fragment_shader_source[4]; + + /* Determine whether to use shaders to render the projective plane. */ + pp->use_shaders = False; + pp->buffers_initialized = False; + pp->shader_program = 0; + pp->ni = 0; + pp->ne = 0; + pp->nt = 0; + + if (!glsl_GetGlAndGlslVersions(&gl_major,&gl_minor,&glsl_major,&glsl_minor, + &gl_gles3)) + return; + if (!gl_gles3) + { + if (gl_major < 3 || + (glsl_major < 1 || (glsl_major == 1 && glsl_minor < 30))) + { + if ((gl_major < 2 || (gl_major == 2 && gl_minor < 1)) || + (glsl_major < 1 || (glsl_major == 1 && glsl_minor < 20))) + return; + /* We have at least OpenGL 2.1 and at least GLSL 1.20. */ + vertex_shader_source[0] = shader_version_2_1; + vertex_shader_source[1] = vertex_shader_attribs_2_1; + vertex_shader_source[2] = vertex_shader_main; + fragment_shader_source[0] = shader_version_2_1; + fragment_shader_source[1] = fragment_shader_attribs_2_1; + fragment_shader_source[2] = fragment_shader_main; + fragment_shader_source[3] = fragment_shader_out_2_1; + } + else + { + /* We have at least OpenGL 3.0 and at least GLSL 1.30. */ + vertex_shader_source[0] = shader_version_3_0; + vertex_shader_source[1] = vertex_shader_attribs_3_0; + vertex_shader_source[2] = vertex_shader_main; + fragment_shader_source[0] = shader_version_3_0; + fragment_shader_source[1] = fragment_shader_attribs_3_0; + fragment_shader_source[2] = fragment_shader_main; + fragment_shader_source[3] = fragment_shader_out_3_0; + } + } + else /* gl_gles3 */ + { + if (gl_major < 3 || glsl_major < 3) + return; + /* We have at least OpenGL ES 3.0 and at least GLSL ES 3.0. */ + vertex_shader_source[0] = shader_version_3_0_es; + vertex_shader_source[1] = vertex_shader_attribs_3_0; + vertex_shader_source[2] = vertex_shader_main; + fragment_shader_source[0] = shader_version_3_0_es; + fragment_shader_source[1] = fragment_shader_attribs_3_0; + fragment_shader_source[2] = fragment_shader_main; + fragment_shader_source[3] = fragment_shader_out_3_0; + } + if (!glsl_CompileAndLinkShaders(3,vertex_shader_source, + 4,fragment_shader_source, + &pp->shader_program)) + return; + pp->vertex_uv_index = glGetAttribLocation(pp->shader_program,"VertexUV"); + pp->vertex_t_index = glGetAttribLocation(pp->shader_program,"VertexT"); + pp->color_index = glGetAttribLocation(pp->shader_program,"VertexColor"); + if (pp->vertex_uv_index == -1 || pp->vertex_t_index == -1 || + pp->color_index == -1) + { + glDeleteProgram(pp->shader_program); + return; + } + pp->mat_rot_index = glGetUniformLocation(pp->shader_program, + "MatRot4D"); + pp->mat_p_index = glGetUniformLocation(pp->shader_program, + "MatProj"); + pp->bool_persp_index = glGetUniformLocation(pp->shader_program, + "BoolPersp"); + pp->off4d_index = glGetUniformLocation(pp->shader_program, + "Offset4D"); + pp->off3d_index = glGetUniformLocation(pp->shader_program, + "Offset3D"); + pp->bool_textures_index = glGetUniformLocation(pp->shader_program, + "BoolTextures"); + pp->draw_lines_index = glGetUniformLocation(pp->shader_program, + "DrawLines"); + pp->glbl_ambient_index = glGetUniformLocation(pp->shader_program, + "LtGlblAmbient"); + pp->lt_ambient_index = glGetUniformLocation(pp->shader_program, + "LtAmbient"); + pp->lt_diffuse_index = glGetUniformLocation(pp->shader_program, + "LtDiffuse"); + pp->lt_specular_index = glGetUniformLocation(pp->shader_program, + "LtSpecular"); + pp->lt_direction_index = glGetUniformLocation(pp->shader_program, + "LtDirection"); + pp->lt_halfvect_index = glGetUniformLocation(pp->shader_program, + "LtHalfVector"); + pp->front_ambient_index = glGetUniformLocation(pp->shader_program, + "MatFrontAmbient"); + pp->back_ambient_index = glGetUniformLocation(pp->shader_program, + "MatBackAmbient"); + pp->front_diffuse_index = glGetUniformLocation(pp->shader_program, + "MatFrontDiffuse"); + pp->back_diffuse_index = glGetUniformLocation(pp->shader_program, + "MatBackDiffuse"); + pp->specular_index = glGetUniformLocation(pp->shader_program, + "MatSpecular"); + pp->shininess_index = glGetUniformLocation(pp->shader_program, + "MatShininess"); + pp->texture_sampler_index = glGetUniformLocation(pp->shader_program, + "TextureSampler"); + if (pp->mat_rot_index == -1 || pp->mat_p_index == -1 || + pp->bool_persp_index == -1 || pp->off4d_index == -1 || + pp->off3d_index == -1 || pp->bool_textures_index == -1 || + pp->draw_lines_index == -1 || pp->glbl_ambient_index == -1 || + pp->lt_ambient_index == -1 || pp->lt_diffuse_index == -1 || + pp->lt_specular_index == -1 || pp->lt_direction_index == -1 || + pp->lt_halfvect_index == -1 || pp->front_ambient_index == -1 || + pp->back_ambient_index == -1 || pp->front_diffuse_index == -1 || + pp->back_diffuse_index == -1 || pp->specular_index == -1 || + pp->shininess_index == -1 || pp->texture_sampler_index == -1) + { + glDeleteProgram(pp->shader_program); + return; + } + + glGenBuffers(1,&pp->vertex_uv_buffer); + glGenBuffers(1,&pp->vertex_t_buffer); + glGenBuffers(1,&pp->color_buffer); + glGenBuffers(1,&pp->indices_buffer); + + pp->use_shaders = True; +} + +#endif /* HAVE_GLSL */ + + static void init(ModeInfo *mi) { - static const GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; - static const GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; - static const GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; - static const GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; - static const GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; projectiveplanestruct *pp = &projectiveplane[MI_SCREEN(mi)]; if (walk_speed == 0.0) @@ -1265,78 +2207,16 @@ static void init(ModeInfo *mi) gen_texture(mi); setup_projective_plane(mi,0.0,2.0*M_PI,0.0,2.0*M_PI); - if (pp->marks) - glEnable(GL_TEXTURE_2D); - else - glDisable(GL_TEXTURE_2D); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (pp->projection_3d == DISP_3D_PERSPECTIVE || - pp->view == VIEW_WALK || pp->view == VIEW_WALKTURN) - { - if (pp->view == VIEW_WALK || pp->view == VIEW_WALKTURN) - gluPerspective(60.0,1.0,0.01,10.0); - else - gluPerspective(60.0,1.0,0.1,10.0); - } - else - { - glOrtho(-0.6,0.6,-0.6,0.6,0.1,10.0); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); +#ifdef HAVE_GLSL + init_glsl(mi); +#endif /* HAVE_GLSL */ -# ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */ - if (pp->display_mode == DISP_WIREFRAME) +#ifdef HAVE_ANDROID + /* glPolygonMode(...,GL_LINE) is not supported for an OpenGL ES 1.1 + context. */ + if (!pp->use_shaders && pp->display_mode == DISP_WIREFRAME) pp->display_mode = DISP_SURFACE; -# endif - - if (pp->display_mode == DISP_SURFACE) - { - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glShadeModel(GL_SMOOTH); - glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient); - glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); - glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular); - glLightfv(GL_LIGHT0,GL_POSITION,light_position); - glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular); - glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0); - glDepthMask(GL_TRUE); - glDisable(GL_BLEND); - } - else if (pp->display_mode == DISP_TRANSPARENT) - { - glDisable(GL_DEPTH_TEST); - glShadeModel(GL_SMOOTH); - glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient); - glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); - glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular); - glLightfv(GL_LIGHT0,GL_POSITION,light_position); - glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular); - glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0); - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA,GL_ONE); - } - else /* pp->display_mode == DISP_WIREFRAME */ - { - glDisable(GL_DEPTH_TEST); - glShadeModel(GL_FLAT); - glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); - glDisable(GL_LIGHTING); - glDisable(GL_LIGHT0); - glDisable(GL_BLEND); - } +#endif /* HAVE_ANDROID */ } @@ -1425,27 +2305,12 @@ static void display_projectiveplane(ModeInfo *mi) } } - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (pp->projection_3d == DISP_3D_PERSPECTIVE || - pp->view == VIEW_WALK || pp->view == VIEW_WALKTURN) - { - if (pp->view == VIEW_WALK || pp->view == VIEW_WALKTURN) - gluPerspective(60.0,pp->aspect,0.01,10.0); - else - gluPerspective(60.0,pp->aspect,0.1,10.0); - } +#ifdef HAVE_GLSL + if (pp->use_shaders) + mi->polygon_count = projective_plane_pf(mi,0.0,2.0*M_PI,0.0,2.0*M_PI); else - { - if (pp->aspect >= 1.0) - glOrtho(-0.6*pp->aspect,0.6*pp->aspect,-0.6,0.6,0.1,10.0); - else - glOrtho(-0.6,0.6,-0.6/pp->aspect,0.6/pp->aspect,0.1,10.0); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - mi->polygon_count = projective_plane(mi,0.0,2.0*M_PI,0.0,2.0*M_PI); +#endif /* HAVE_GLSL */ + mi->polygon_count = projective_plane_ff(mi,0.0,2.0*M_PI,0.0,2.0*M_PI); } @@ -1541,7 +2406,6 @@ ENTRYPOINT void init_projectiveplane(ModeInfo *mi) MI_INIT(mi, projectiveplane); pp = &projectiveplane[MI_SCREEN(mi)]; - pp->trackballs[0] = gltrackball_init(True); pp->trackballs[1] = gltrackball_init(True); pp->current_trackball = 0; @@ -1711,7 +2575,6 @@ ENTRYPOINT void init_projectiveplane(ModeInfo *mi) if ((pp->glx_context = init_GL(mi)) != NULL) { reshape_projectiveplane(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); - glDrawBuffer(GL_BACK); init(mi); } else @@ -1741,6 +2604,8 @@ ENTRYPOINT void draw_projectiveplane(ModeInfo *mi) glXMakeCurrent(display, window, *pp->glx_context); + glClearColor(0.0f,0.0f,0.0f,1.0f); + glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); @@ -1768,6 +2633,7 @@ ENTRYPOINT void change_projectiveplane(ModeInfo *mi) } #endif /* !STANDALONE */ + ENTRYPOINT void free_projectiveplane(ModeInfo *mi) { projectiveplanestruct *pp = &projectiveplane[MI_SCREEN(mi)]; @@ -1776,8 +2642,23 @@ ENTRYPOINT void free_projectiveplane(ModeInfo *mi) gltrackball_free (pp->trackballs[0]); gltrackball_free (pp->trackballs[1]); if (pp->tex_name) glDeleteTextures (1, &pp->tex_name); +#ifdef HAVE_GLSL + if (pp->use_shaders) + { + glDeleteBuffers(1,&pp->vertex_uv_buffer); + glDeleteBuffers(1,&pp->vertex_t_buffer); + glDeleteBuffers(1,&pp->color_buffer); + glDeleteBuffers(1,&pp->indices_buffer); + if (pp->shader_program != 0) + { + glUseProgram(0); + glDeleteProgram(pp->shader_program); + } + } +#endif /* HAVE_GLSL */ } + XSCREENSAVER_MODULE ("ProjectivePlane", projectiveplane) #endif /* USE_GL */ |