From 38886de0c3e9ea5729ef23e4c653fa2822f52e8f Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 6 Apr 2021 14:43:39 +0200 Subject: xscreensaver 6.00 --- hacks/glx/romanboy.c | 1611 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 1259 insertions(+), 352 deletions(-) (limited to 'hacks/glx/romanboy.c') diff --git a/hacks/glx/romanboy.c b/hacks/glx/romanboy.c index 6957556..544fb96 100644 --- a/hacks/glx/romanboy.c +++ b/hacks/glx/romanboy.c @@ -3,10 +3,10 @@ smoothly between the Roman surface and the Boy surface. */ #if 0 -static const char sccsid[] = "@(#)romanboy.c 1.1 03/10/14 xlockmore"; +static const char sccsid[] = "@(#)romanboy.c 1.1 14/10/03 xlockmore"; #endif -/* Copyright (c) 2014-2020 Carsten Steger . */ +/* Copyright (c) 2014-2021 Carsten Steger . */ /* * Permission to use, copy, modify, and distribute this software and its @@ -22,8 +22,10 @@ static const char sccsid[] = "@(#)romanboy.c 1.1 03/10/14 xlockmore"; * other special, indirect and consequential damages. * * REVISION HISTORY: - * C. Steger - 03/10/14: Initial version - * C. Steger - 06/01/20: Added the changing colors mode. + * C. Steger - 14/10/03: Initial version + * C. Steger - 20/01/06: Added the changing colors mode + * C. Steger - 20/12/19: Added per-fragment shading + * C. Steger - 20/12/30: Make the shader code work under macOS and iOS */ /* @@ -31,7 +33,7 @@ static const char sccsid[] = "@(#)romanboy.c 1.1 03/10/14 xlockmore"; * smoothly deforms between the Roman surface and the Boy surface. * You can walk on the projective plane or turn in 3d. The smooth * deformation (homotopy) between these two famous immersions of the - * real projective plane was constructed by François Apéry. + * real projective plane was constructed by François Apéry. * * The real projective plane is a non-orientable surface. To make * this apparent, the two-sided color mode can be used. @@ -159,7 +161,7 @@ static const char sccsid[] = "@(#)romanboy.c 1.1 03/10/14 xlockmore"; * in an immersion of the halfway model of Morin's sphere eversion (if * the deformation is switched off). * - * This program is inspired by François Apéry's book "Models of the + * This program is inspired by François Apéry's book "Models of the * Real Projective Plane", Vieweg, 1987. */ @@ -210,9 +212,11 @@ static const char sccsid[] = "@(#)romanboy.c 1.1 03/10/14 xlockmore"; #define DEF_INIT_DEFORM "1000.0" #define DEF_SURFACE_ORDER "3" + #ifdef STANDALONE -# define DEFAULTS "*delay: 10000 \n" \ +# define DEFAULTS "*delay: 25000 \n" \ "*showFPS: False \n" \ + "*prefersGLSL: True \n" \ # define release_romanboy 0 # include "xlockmore.h" /* from the xscreensaver distribution */ @@ -226,6 +230,7 @@ static const char sccsid[] = "@(#)romanboy.c 1.1 03/10/14 xlockmore"; # include #endif +#include "glsl-utils.h" #include "gltrackball.h" #include @@ -364,7 +369,7 @@ typedef struct { int g; /* The viewing offset in 3d */ float offset3d[3]; - /* The 3d coordinates of the projective plane and their derivatives */ + /* The 3d coordinates of the projective plane and their normals */ float *pp; float *pn; /* The precomputed colors of the projective plane */ @@ -380,11 +385,227 @@ typedef struct { Bool button_pressed; /* A random factor to modify the rotation speeds */ float speed_scale; +#ifdef HAVE_GLSL + GLfloat *uv; + GLuint *indices; + Bool use_shaders, buffers_initialized; + GLuint shader_program; + GLint vertex_uv_index, vertex_t_index, color_index; + GLint mat_mv_index, mat_p_index, g_index, d_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 */ } romanboystruct; static romanboystruct *romanboy = (romanboystruct *) 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 = + "uniform mat4 MatModelView;\n" + "uniform mat4 MatProj;\n" + "uniform int G;\n" + "uniform float D;\n" + "uniform bool BoolTextures;\n" + "\n" + "void main (void)\n" + "{\n" + " const float EPSILON = 1.19e-6f;\n" + " const float M_PI = 3.14159265359f;\n" + " const float M_SQRT2 = 1.41421356237f;\n" + " float g = float(G);\n" + " float u = VertexUV.x;\n" + " float v = VertexUV.y;\n" + " float sqrt2og = M_SQRT2/g;\n" + " float h1m1og = 0.5f*(1.0f-1.0f/g);\n" + " float gm1 = g-1.0f;\n" + " float cu = cos(u);\n" + " float su = sin(u);\n" + " float cgu = cos(g*u);\n" + " float sgu = sin(g*u);\n" + " float cgm1u = cos(gm1*u);\n" + " float sgm1u = sin(gm1*u);\n" + " float cv = cos(v);\n" + " float c2v = cos(2.0f*v);\n" + " float s2v = sin(2.0f*v);\n" + " float cv2 = cv*cv;\n" + " float nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu;\n" + " float nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su;\n" + " float nomux = -sqrt2og*cv2*gm1*sgm1u-h1m1og*s2v*su;\n" + " float nomuy = sqrt2og*cv2*gm1*cgm1u-h1m1og*s2v*cu;\n" + " float nomvx = -sqrt2og*s2v*cgm1u+2.0f*h1m1og*c2v*cu;\n" + " float nomvy = -sqrt2og*s2v*sgm1u-2.0f*h1m1og*c2v*su;\n" + " float den = 1.0f/(1.0f-0.5f*M_SQRT2*D*s2v*sgu);\n" + " float den2 = den*den;\n" + " float denu = 0.5f*M_SQRT2*D*g*cgu*s2v;\n" + " float denv = M_SQRT2*D*sgu*c2v;\n" + " vec3 x = vec3(nomx*den,\n" + " nomy*den,\n" + " cv2*den);\n" + " if (0.5f*M_PI-abs(v) < EPSILON)\n" + " {\n" + " if (0.5f*M_PI-v < EPSILON)\n" + " v = 0.5f*M_PI-EPSILON;\n" + " else\n" + " v = -0.5f*M_PI+EPSILON;\n" + " cv = cos(v);\n" + " c2v = cos(2.0f*v);\n" + " s2v = sin(2.0f*v);\n" + " cv2 = cv*cv;\n" + " nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu;\n" + " nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su;\n" + " nomux = -sqrt2og*cv2*gm1*sgm1u-h1m1og*s2v*su;\n" + " nomuy = sqrt2og*cv2*gm1*cgm1u-h1m1og*s2v*cu;\n" + " nomvx = -sqrt2og*s2v*cgm1u+2.0f*h1m1og*c2v*cu;\n" + " nomvy = -sqrt2og*s2v*sgm1u-2.0f*h1m1og*c2v*su;\n" + " den = 1.0f/(1.0f-0.5f*M_SQRT2*D*s2v*sgu);\n" + " den2 = den*den;\n" + " denu = 0.5f*M_SQRT2*D*g*cgu*s2v;\n" + " denv = M_SQRT2*D*sgu*c2v;\n" + " }\n" + " vec3 xu = vec3(nomux*den+nomx*denu*den2,\n" + " nomuy*den+nomy*denu*den2,\n" + " cv2*denu*den2);\n" + " vec3 xv = vec3(nomvx*den+nomx*denv*den2,\n" + " nomvy*den+nomy*denv*den2,\n" + " -s2v*den+cv2*denv*den2);\n" + " vec4 Position = MatModelView*vec4(x,1.0f);\n" + " vec4 pu = MatModelView*vec4(xu,0.0f);\n" + " vec4 pv = MatModelView*vec4(xv,0.0f);\n" + " Normal = normalize(cross(pu.xyz,pv.xyz));\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 = + "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 x-axis to the matrix m. */ static void rotatex(float m[3][3], float phi) { @@ -615,11 +836,168 @@ static void setup_roman_boy_color_texture(ModeInfo *mi, double umin, } -/* Draw a 3d immersion of the projective plane. */ -static int roman_boy(ModeInfo *mi, double umin, double umax, - double vmin, double vmax, int numu, int numv) +/* 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(romanboystruct *pp, int g, float d, + float radius, float oz, float mat[3][3]) { - int polys = 0; + float p[3], pu[3], pv[3], pm[3], n[3], b[3]; + int l, m; + float u, v; + float xx[3], xxu[3], xxv[3]; + float r, t; + float cu, su, cgu, sgu, cgm1u, sgm1u, cv, c2v, s2v, cv2; + float sqrt2og, h1m1og, gm1, nomx, nomy, nomux, nomuy, nomvx, nomvy; + float den, den2, denu, denv; + + u = pp->umove; + v = pp->vmove; + if (g & 1) + v = 0.5f*(float)M_PI-0.25f*v; + else + v = 0.5f*(float)M_PI-0.5f*v; + sqrt2og = (float)M_SQRT2/g; + h1m1og = 0.5f*(1.0f-1.0f/g); + gm1 = g-1.0f; + cu = cosf(u); + su = sinf(u); + cgu = cosf(g*u); + sgu = sinf(g*u); + cgm1u = cosf(gm1*u); + sgm1u = sinf(gm1*u); + cv = cosf(v); + c2v = cosf(2.0f*v); + s2v = sinf(2.0f*v); + cv2 = cv*cv; + nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu; + nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su; + nomux = -sqrt2og*cv2*gm1*sgm1u-h1m1og*s2v*su; + nomuy = sqrt2og*cv2*gm1*cgm1u-h1m1og*s2v*cu; + nomvx = -sqrt2og*s2v*cgm1u+2.0f*h1m1og*c2v*cu; + nomvy = -sqrt2og*s2v*sgm1u-2.0f*h1m1og*c2v*su; + den = 1.0f/(1.0f-0.5f*(float)M_SQRT2*d*s2v*sgu); + den2 = den*den; + denu = 0.5f*(float)M_SQRT2*d*g*cgu*s2v; + denv = (float)M_SQRT2*d*sgu*c2v; + xx[0] = nomx*den; + xx[1] = nomy*den; + xx[2] = cv2*den-oz; + /* Avoid degenerate tangential plane basis vectors. */ + if (0.5f*(float)M_PI-fabsf(v) < 10.0f*(float)FLT_EPSILON) + { + if (0.5f*(float)M_PI-v < 10.0f*(float)FLT_EPSILON) + v = 0.5f*(float)M_PI-10.0f*(float)FLT_EPSILON; + else + v = -0.5f*(float)M_PI+10.0f*(float)FLT_EPSILON; + cv = cosf(v); + c2v = cosf(2.0f*v); + s2v = sinf(2.0f*v); + cv2 = cv*cv; + nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu; + nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su; + nomux = -sqrt2og*cv2*gm1*sgm1u-h1m1og*s2v*su; + nomuy = sqrt2og*cv2*gm1*cgm1u-h1m1og*s2v*cu; + nomvx = -sqrt2og*s2v*cgm1u+2.0f*h1m1og*c2v*cu; + nomvy = -sqrt2og*s2v*sgm1u-2.0f*h1m1og*c2v*su; + den = 1.0f/(1.0f-0.5f*(float)M_SQRT2*d*s2v*sgu); + den2 = den*den; + denu = 0.5f*(float)M_SQRT2*d*g*cgu*s2v; + denv = (float)M_SQRT2*d*sgu*c2v; + } + xxu[0] = nomux*den+nomx*denu*den2; + xxu[1] = nomuy*den+nomy*denu*den2; + xxu[2] = cv2*denu*den2; + xxv[0] = nomvx*den+nomx*denv*den2; + xxv[1] = nomvy*den+nomy*denv*den2; + xxv[2] = -s2v*den+cv2*denv*den2; + for (l=0; l<3; l++) + { + p[l] = xx[l]*radius; + pu[l] = xxu[l]*radius; + pv[l] = xxv[l]*radius; + } + 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.0f/(pp->side*4.0f*sqrtf(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]*0.25f*pp->dvmove; + pm[1] = pu[1]*pp->dumove-pv[1]*0.25f*pp->dvmove; + pm[2] = pu[2]*pp->dumove-pv[2]*0.25f*pp->dvmove; + t = 1.0f/(4.0f*sqrtf(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.0f/(4.0f*sqrtf(b[0]*b[0]+b[1]*b[1]+b[2]*b[2])); + b[0] *= t; + b[1] *= t; + b[2] *= t; + + /* Compute alpha, beta, gamma 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 = atan2f(-n[2],-pm[2])*180.0f/(float)M_PI; + pp->beta = atan2f(-b[2],sqrtf(b[0]*b[0]+b[1]*b[1]))*180.0f/(float)M_PI; + pp->delta = atan2f(b[1],-b[0])*180.0f/(float)M_PI; + + /* Compute the rotation that rotates the projective plane in 3D. */ + rotateall(pp->alpha,pp->beta,pp->delta,mat); + + u = pp->umove; + v = pp->vmove; + if (g & 1) + v = 0.5f*(float)M_PI-0.25f*v; + else + v = 0.5f*(float)M_PI-0.5f*v; + sqrt2og = (float)M_SQRT2/g; + h1m1og = 0.5f*(1.0f-1.0f/g); + gm1 = g-1.0f; + cu = cosf(u); + su = sinf(u); + sgu = sinf(g*u); + cgm1u = cosf(gm1*u); + sgm1u = sinf(gm1*u); + cv = cosf(v); + s2v = sinf(2.0f*v); + cv2 = cv*cv; + nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu; + nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su; + den = 1.0f/(1.0f-0.5f*(float)M_SQRT2*d*s2v*sgu); + xx[0] = nomx*den; + xx[1] = nomy*den; + xx[2] = cv2*den-oz; + for (l=0; l<3; l++) + { + r = 0.0; + for (m=0; m<3; m++) + r += mat[l][m]*xx[m]; + p[l] = r*radius; + } + + pp->offset3d[0] = -p[0]; + pp->offset3d[1] = -p[1]-DELTAY; + pp->offset3d[2] = -p[2]; +} + + +/* Draw a 3d immersion of the projective plane using OpenGL's fixed + functionality. */ +static int roman_boy_ff(ModeInfo *mi, double umin, double umax, + double vmin, double vmax, int numu, int numv) +{ + 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 }; @@ -627,164 +1005,115 @@ static int roman_boy(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[3][3], matc[3][3]; + float p[3], pu[3], pv[3], n[3], mat[3][3], matc[3][3]; int i, j, k, l, m, o, g; - double u, v, ur, vr, oz; - double xx[3], xxu[3], xxv[3]; - double r, s, t; - double d, dd, radius; - double cu, su, cgu, sgu, cgm1u, sgm1u, cv, c2v, s2v, cv2; - double sqrt2og, h1m1og, gm1, nomx, nomy, nomux, nomuy, nomvx, nomvy; - double den, den2, denu, denv; + float u, v, ur, vr, oz; + float xx[3], xxu[3], xxv[3]; + float r, s, t; + float d, dd, radius; + float cu, su, cgu, sgu, cgm1u, sgm1u, cv, c2v, s2v, cv2; + float sqrt2og, h1m1og, gm1, nomx, nomy, nomux, nomuy, nomvx, nomvy; + float den, den2, denu, denv; float qu[4], r1[3][3], r2[3][3]; romanboystruct *pp = &romanboy[MI_SCREEN(mi)]; + int polys; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (pp->projection == DISP_PERSPECTIVE || pp->view == VIEW_WALK) + { + if (pp->view == VIEW_WALK) + 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(-pp->aspect,pp->aspect,-1.0,1.0,0.1,10.0); + else + glOrtho(-1.0,1.0,-1.0/pp->aspect,1.0/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 + } g = pp->g; dd = pp->dd; - d = ((6.0*dd-15.0)*dd+10.0)*dd*dd*dd; - r = 1.0+d*d*(1.0/2.0+d*d*(1.0/6.0+d*d*(1.0/3.0))); - radius = 1.0/r; - oz = 0.5*r; + d = ((6.0f*dd-15.0f)*dd+10.0f)*dd*dd*dd; + r = 1.0f+d*d*(1.0f/2.0f+d*d*(1.0f/6.0f+d*d*(1.0f/3.0f))); + radius = 1.0f/r; + oz = 0.5f*r; if (pp->change_colors) rotateall(pp->rho,pp->sigma,pp->tau,matc); if (pp->view == VIEW_WALK) { - u = pp->umove; - v = pp->vmove; - if (g & 1) - v = 0.5*M_PI-0.25*v; - else - v = 0.5*M_PI-0.5*v; - sqrt2og = M_SQRT2/g; - h1m1og = 0.5*(1.0-1.0/g); - gm1 = g-1.0; - cu = cos(u); - su = sin(u); - cgu = cos(g*u); - sgu = sin(g*u); - cgm1u = cos(gm1*u); - sgm1u = sin(gm1*u); - cv = cos(v); - c2v = cos(2.0*v); - s2v = sin(2.0*v); - cv2 = cv*cv; - nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu; - nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su; - nomux = -sqrt2og*cv2*gm1*sgm1u-h1m1og*s2v*su; - nomuy = sqrt2og*cv2*gm1*cgm1u-h1m1og*s2v*cu; - nomvx = -sqrt2og*s2v*cgm1u+2.0*h1m1og*c2v*cu; - nomvy = -sqrt2og*s2v*sgm1u-2.0*h1m1og*c2v*su; - den = 1.0/(1.0-0.5*M_SQRT2*d*s2v*sgu); - den2 = den*den; - denu = 0.5*M_SQRT2*d*g*cgu*s2v; - denv = M_SQRT2*d*sgu*c2v; - xx[0] = nomx*den; - xx[1] = nomy*den; - xx[2] = cv2*den-oz; - /* Avoid degenerate tangential plane basis vectors. */ - if (0.5*M_PI-fabs(v) < FLT_EPSILON) - { - if (0.5*M_PI-v < FLT_EPSILON) - v = 0.5*M_PI-FLT_EPSILON; - else - v = -0.5*M_PI+FLT_EPSILON; - cv = cos(v); - c2v = cos(2.0*v); - s2v = sin(2.0*v); - cv2 = cv*cv; - nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu; - nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su; - nomux = -sqrt2og*cv2*gm1*sgm1u-h1m1og*s2v*su; - nomuy = sqrt2og*cv2*gm1*cgm1u-h1m1og*s2v*cu; - nomvx = -sqrt2og*s2v*cgm1u+2.0*h1m1og*c2v*cu; - nomvy = -sqrt2og*s2v*sgm1u-2.0*h1m1og*c2v*su; - den = 1.0/(1.0-0.5*M_SQRT2*d*s2v*sgu); - den2 = den*den; - denu = 0.5*M_SQRT2*d*g*cgu*s2v; - denv = M_SQRT2*d*sgu*c2v; - } - xxu[0] = nomux*den+nomx*denu*den2; - xxu[1] = nomuy*den+nomy*denu*den2; - xxu[2] = cv2*denu*den2; - xxv[0] = nomvx*den+nomx*denv*den2; - xxv[1] = nomvy*den+nomy*denv*den2; - xxv[2] = -s2v*den+cv2*denv*den2; - for (l=0; l<3; l++) - { - p[l] = xx[l]*radius; - pu[l] = xxu[l]*radius; - pv[l] = xxv[l]*radius; - } - 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]*0.25*pp->dvmove; - pm[1] = pu[1]*pp->dumove-pv[1]*0.25*pp->dvmove; - pm[2] = pu[2]*pp->dumove-pv[2]*0.25*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, gamma 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 3D. */ - rotateall(pp->alpha,pp->beta,pp->delta,mat); - - u = pp->umove; - v = pp->vmove; - if (g & 1) - v = 0.5*M_PI-0.25*v; - else - v = 0.5*M_PI-0.5*v; - sqrt2og = M_SQRT2/g; - h1m1og = 0.5*(1.0-1.0/g); - gm1 = g-1.0; - cu = cos(u); - su = sin(u); - sgu = sin(g*u); - cgm1u = cos(gm1*u); - sgm1u = sin(gm1*u); - cv = cos(v); - s2v = sin(2.0*v); - cv2 = cv*cv; - nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu; - nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su; - den = 1.0/(1.0-0.5*M_SQRT2*d*s2v*sgu); - xx[0] = nomx*den; - xx[1] = nomy*den; - xx[2] = cv2*den-oz; - for (l=0; l<3; l++) - { - r = 0.0; - for (m=0; m<3; m++) - r += mat[l][m]*xx[m]; - p[l] = r*radius; - } - - pp->offset3d[0] = -p[0]; - pp->offset3d[1] = -p[1]-DELTAY; - pp->offset3d[2] = -p[2]; + /* Compute the walk frame. */ + compute_walk_frame(pp,g,d,radius,oz,mat); } else { @@ -875,56 +1204,56 @@ static int roman_boy(ModeInfo *mi, double umin, double umax, color(pp,v*(5.0/6.0),matc,&pp->col[4*o]); } if (g & 1) - v = 0.5*M_PI-0.25*v; + v = 0.5f*(float)M_PI-0.25f*v; else - v = 0.5*M_PI-0.5*v; - sqrt2og = M_SQRT2/g; - h1m1og = 0.5*(1.0-1.0/g); - gm1 = g-1.0; - cu = cos(u); - su = sin(u); - cgu = cos(g*u); - sgu = sin(g*u); - cgm1u = cos(gm1*u); - sgm1u = sin(gm1*u); - cv = cos(v); - c2v = cos(2.0*v); - s2v = sin(2.0*v); + v = 0.5f*(float)M_PI-0.5f*v; + sqrt2og = (float)M_SQRT2/g; + h1m1og = 0.5f*(1.0f-1.0f/g); + gm1 = g-1.0f; + cu = cosf(u); + su = sinf(u); + cgu = cosf(g*u); + sgu = sinf(g*u); + cgm1u = cosf(gm1*u); + sgm1u = sinf(gm1*u); + cv = cosf(v); + c2v = cosf(2.0f*v); + s2v = sinf(2.0f*v); cv2 = cv*cv; nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu; nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su; nomux = -sqrt2og*cv2*gm1*sgm1u-h1m1og*s2v*su; nomuy = sqrt2og*cv2*gm1*cgm1u-h1m1og*s2v*cu; - nomvx = -sqrt2og*s2v*cgm1u+2.0*h1m1og*c2v*cu; - nomvy = -sqrt2og*s2v*sgm1u-2.0*h1m1og*c2v*su; - den = 1.0/(1.0-0.5*M_SQRT2*d*s2v*sgu); + nomvx = -sqrt2og*s2v*cgm1u+2.0f*h1m1og*c2v*cu; + nomvy = -sqrt2og*s2v*sgm1u-2.0f*h1m1og*c2v*su; + den = 1.0f/(1.0f-0.5f*(float)M_SQRT2*d*s2v*sgu); den2 = den*den; - denu = 0.5*M_SQRT2*d*g*cgu*s2v; - denv = M_SQRT2*d*sgu*c2v; + denu = 0.5f*(float)M_SQRT2*d*g*cgu*s2v; + denv = (float)M_SQRT2*d*sgu*c2v; xx[0] = nomx*den; xx[1] = nomy*den; xx[2] = cv2*den-oz; /* Avoid degenerate tangential plane basis vectors. */ - if (0.5*M_PI-fabs(v) < FLT_EPSILON) + if (0.5f*(float)M_PI-fabsf(v) < 10.0f*(float)FLT_EPSILON) { - if (0.5*M_PI-v < FLT_EPSILON) - v = 0.5*M_PI-FLT_EPSILON; + if (0.5f*(float)M_PI-v < 10.0f*(float)FLT_EPSILON) + v = 0.5f*(float)M_PI-10.0f*(float)FLT_EPSILON; else - v = -0.5*M_PI+FLT_EPSILON; - cv = cos(v); - c2v = cos(2.0*v); - s2v = sin(2.0*v); + v = -0.5f*(float)M_PI+10.0f*(float)FLT_EPSILON; + cv = cosf(v); + c2v = cosf(2.0f*v); + s2v = sinf(2.0f*v); cv2 = cv*cv; nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu; nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su; nomux = -sqrt2og*cv2*gm1*sgm1u-h1m1og*s2v*su; nomuy = sqrt2og*cv2*gm1*cgm1u-h1m1og*s2v*cu; - nomvx = -sqrt2og*s2v*cgm1u+2.0*h1m1og*c2v*cu; - nomvy = -sqrt2og*s2v*sgm1u-2.0*h1m1og*c2v*su; - den = 1.0/(1.0-0.5*M_SQRT2*d*s2v*sgu); + nomvx = -sqrt2og*s2v*cgm1u+2.0f*h1m1og*c2v*cu; + nomvy = -sqrt2og*s2v*sgm1u-2.0f*h1m1og*c2v*su; + den = 1.0f/(1.0f-0.5f*(float)M_SQRT2*d*s2v*sgu); den2 = den*den; - denu = 0.5*M_SQRT2*d*g*cgu*s2v; - denv = M_SQRT2*d*sgu*c2v; + denu = 0.5f*(float)M_SQRT2*d*g*cgu*s2v; + denv = (float)M_SQRT2*d*sgu*c2v; } xxu[0] = nomux*den+nomx*denu*den2; xxu[1] = nomuy*den+nomy*denu*den2; @@ -934,9 +1263,9 @@ static int roman_boy(ModeInfo *mi, double umin, double umax, xxv[2] = -s2v*den+cv2*denv*den2; for (l=0; l<3; l++) { - r = 0.0; - s = 0.0; - t = 0.0; + r = 0.0f; + s = 0.0f; + t = 0.0f; for (m=0; m<3; m++) { r += mat[l][m]*xx[m]; @@ -950,7 +1279,7 @@ static int roman_boy(ModeInfo *mi, double umin, double umax, 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/sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); + t = 1.0f/sqrtf(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); n[0] *= t; n[1] *= t; n[2] *= t; @@ -983,56 +1312,56 @@ static int roman_boy(ModeInfo *mi, double umin, double umax, color(pp,v*(5.0/6.0),matc,&pp->col[4*o]); } if (g & 1) - v = 0.5*M_PI-0.25*v; + v = 0.5f*(float)M_PI-0.25f*v; else - v = 0.5*M_PI-0.5*v; - sqrt2og = M_SQRT2/g; - h1m1og = 0.5*(1.0-1.0/g); - gm1 = g-1.0; - cu = cos(u); - su = sin(u); - cgu = cos(g*u); - sgu = sin(g*u); - cgm1u = cos(gm1*u); - sgm1u = sin(gm1*u); - cv = cos(v); - c2v = cos(2.0*v); - s2v = sin(2.0*v); + v = 0.5f*(float)M_PI-0.5f*v; + sqrt2og = (float)M_SQRT2/g; + h1m1og = 0.5f*(1.0f-1.0f/g); + gm1 = g-1.0f; + cu = cosf(u); + su = sinf(u); + cgu = cosf(g*u); + sgu = sinf(g*u); + cgm1u = cosf(gm1*u); + sgm1u = sinf(gm1*u); + cv = cosf(v); + c2v = cosf(2.0f*v); + s2v = sinf(2.0f*v); cv2 = cv*cv; nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu; nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su; nomux = -sqrt2og*cv2*gm1*sgm1u-h1m1og*s2v*su; nomuy = sqrt2og*cv2*gm1*cgm1u-h1m1og*s2v*cu; - nomvx = -sqrt2og*s2v*cgm1u+2.0*h1m1og*c2v*cu; - nomvy = -sqrt2og*s2v*sgm1u-2.0*h1m1og*c2v*su; - den = 1.0/(1.0-0.5*M_SQRT2*d*s2v*sgu); + nomvx = -sqrt2og*s2v*cgm1u+2.0f*h1m1og*c2v*cu; + nomvy = -sqrt2og*s2v*sgm1u-2.0f*h1m1og*c2v*su; + den = 1.0f/(1.0f-0.5f*(float)M_SQRT2*d*s2v*sgu); den2 = den*den; - denu = 0.5*M_SQRT2*d*g*cgu*s2v; - denv = M_SQRT2*d*sgu*c2v; + denu = 0.5f*(float)M_SQRT2*d*g*cgu*s2v; + denv = (float)M_SQRT2*d*sgu*c2v; xx[0] = nomx*den; xx[1] = nomy*den; xx[2] = cv2*den-oz; /* Avoid degenerate tangential plane basis vectors. */ - if (0.5*M_PI-fabs(v) < FLT_EPSILON) + if (0.5f*(float)M_PI-fabsf(v) < 10.0f*(float)FLT_EPSILON) { - if (0.5*M_PI-v < FLT_EPSILON) - v = 0.5*M_PI-FLT_EPSILON; + if (0.5f*(float)M_PI-v < 10.0f*(float)FLT_EPSILON) + v = 0.5f*(float)M_PI-10.0f*(float)FLT_EPSILON; else - v = -0.5*M_PI+FLT_EPSILON; - cv = cos(v); - c2v = cos(2.0*v); - s2v = sin(2.0*v); + v = -0.5f*(float)M_PI+10.0f*(float)FLT_EPSILON; + cv = cosf(v); + c2v = cosf(2.0f*v); + s2v = sinf(2.0f*v); cv2 = cv*cv; nomx = sqrt2og*cv2*cgm1u+h1m1og*s2v*cu; nomy = sqrt2og*cv2*sgm1u-h1m1og*s2v*su; nomux = -sqrt2og*cv2*gm1*sgm1u-h1m1og*s2v*su; nomuy = sqrt2og*cv2*gm1*cgm1u-h1m1og*s2v*cu; - nomvx = -sqrt2og*s2v*cgm1u+2.0*h1m1og*c2v*cu; - nomvy = -sqrt2og*s2v*sgm1u-2.0*h1m1og*c2v*su; - den = 1.0/(1.0-0.5*M_SQRT2*d*s2v*sgu); + nomvx = -sqrt2og*s2v*cgm1u+2.0f*h1m1og*c2v*cu; + nomvy = -sqrt2og*s2v*sgm1u-2.0f*h1m1og*c2v*su; + den = 1.0f/(1.0f-0.5f*(float)M_SQRT2*d*s2v*sgu); den2 = den*den; - denu = 0.5*M_SQRT2*d*g*cgu*s2v; - denv = M_SQRT2*d*sgu*c2v; + denu = 0.5f*(float)M_SQRT2*d*g*cgu*s2v; + denv = (float)M_SQRT2*d*sgu*c2v; } xxu[0] = nomux*den+nomx*denu*den2; xxu[1] = nomuy*den+nomy*denu*den2; @@ -1042,9 +1371,9 @@ static int roman_boy(ModeInfo *mi, double umin, double umax, xxv[2] = -s2v*den+cv2*denv*den2; for (l=0; l<3; l++) { - r = 0.0; - s = 0.0; - t = 0.0; + r = 0.0f; + s = 0.0f; + t = 0.0f; for (m=0; m<3; m++) { r += mat[l][m]*xx[m]; @@ -1058,7 +1387,7 @@ static int roman_boy(ModeInfo *mi, double umin, double umax, 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/sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); + t = 1.0f/sqrtf(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); n[0] *= t; n[1] *= t; n[2] *= t; @@ -1087,7 +1416,7 @@ static int roman_boy(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; glTexCoord2fv(&pp->tex[2*o]); @@ -1099,11 +1428,13 @@ static int roman_boy(ModeInfo *mi, double umin, double umax, } glNormal3fv(&pp->pn[3*o]); glVertex3fv(&pp->pp[3*o]); - polys++; } } glEnd(); } + polys = 2*numv*(numu+1); + if (pp->appearance == APPEARANCE_DISTANCE_BANDS) + polys /= 2; } else /* pp->appearance == APPEARANCE_DIRECTION_BANDS */ { @@ -1120,7 +1451,7 @@ static int roman_boy(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; glTexCoord2fv(&pp->tex[2*o]); if (pp->colors != COLORS_ONESIDED && pp->colors != COLORS_TWOSIDED) @@ -1131,26 +1462,525 @@ static int roman_boy(ModeInfo *mi, double umin, double umax, } glNormal3fv(&pp->pn[3*o]); glVertex3fv(&pp->pp[3*o]); - polys++; } } glEnd(); } + polys = numu*(numv+1); + } + + return polys; +} + + +#ifdef HAVE_GLSL + +/* Draw a 3d immersion of the projective plane using OpenGL's programmable + functionality. */ +static int roman_boy_pf(ModeInfo *mi, double umin, double umax, + double vmin, double vmax, int numu, int numv) +{ + 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], mv_mat[16], rot_mat[16]; + float mat_diff_dyn[4], mat_diff_dyn_compl[4]; + float mat[3][3], matc[3][3]; + int i, j, k, l, m, o, g; + float u, v, ur, vr, oz; + float r; + float d, dd, radius; + float qu[4], r1[3][3], r2[3][3]; + GLsizeiptr index_offset; + romanboystruct *pp = &romanboy[MI_SCREEN(mi)]; + int polys; + + if (!pp->use_shaders) + return 0; + + g = pp->g; + dd = pp->dd; + d = ((6.0f*dd-15.0f)*dd+10.0f)*dd*dd*dd; + r = 1.0f+d*d*(1.0f/2.0f+d*d*(1.0f/6.0f+d*d*(1.0f/3.0f))); + radius = 1.0f/r; + oz = 0.5f*r; + + 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; + if (g & 1) + v = 0.5f*(float)M_PI-0.25f*v; + else + v = 0.5f*(float)M_PI-0.5f*v; + pp->uv[2*o+0] = u; + pp->uv[2*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; iappearance == 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= 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; jindices[pp->ni++] = i*(numu+1)+j; + pp->indices[pp->ni++] = i*(numu+1)+j+1; + } + continue; + } + for (j=0; jindices[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 NUMB/2) + continue; + if ((j & (NUMB-1)) == NUMB/2) + { + for (i=0; iindices[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) + rotateall(pp->rho,pp->sigma,pp->tau,matc); + + if (pp->view == VIEW_WALK) + { + /* Compute the walk frame. */ + compute_walk_frame(pp,g,d,radius,oz,mat); + } + else + { + /* Compute the rotation that rotates the projective plane in 3D, + including the trackball rotations. */ + rotateall(pp->alpha,pp->beta,pp->delta,r1); + + gltrackball_get_quaternion(pp->trackball,qu); + quat_to_rotmat(qu,r2); + + mult_rotmat(r2,r1,mat); + } + + if (pp->change_colors && + (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->appearance != APPEARANCE_DIRECTION_BANDS) + u = ur*j/numu+umin; + else + u = -ur*j/numu+umin; + v = vr*i/numv+vmin; + if (pp->colors == COLORS_DIRECTION) + color(pp,2.0*M_PI-fmod(2.0*u,2.0*M_PI),matc,&pp->col[4*o]); + else if (pp->colors == COLORS_DISTANCE) + color(pp,v*(5.0/6.0),matc,&pp->col[4*o]); + } + } + } + + glUseProgram(pp->shader_program); + + glUniform1i(pp->g_index,g); + glUniform1f(pp->d_index,d); + + glsl_Identity(p_mat); + if (pp->projection == DISP_PERSPECTIVE || pp->view == VIEW_WALK) + { + if (pp->view == VIEW_WALK) + 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,-pp->aspect,pp->aspect,-1.0f,1.0f, + 0.1f,10.0f); + else + glsl_Orthographic(p_mat,-1.0f,1.0f,-1.0f/pp->aspect,1.0f/pp->aspect, + 0.1f,10.0f); + } + glUniformMatrix4fv(pp->mat_p_index,1,GL_FALSE,p_mat); + glsl_Identity(rot_mat); + for (i=0; i<3; i++) + for (j=0; j<3; j++) + rot_mat[GLSL__LINCOOR(i,j,4)] = mat[i][j]; + glsl_Identity(mv_mat); + glsl_Translate(mv_mat,pp->offset3d[0],pp->offset3d[1],pp->offset3d[2]); + glsl_Scale(mv_mat,radius,radius,radius); + glsl_MultMatrix(mv_mat,rot_mat); + glsl_Translate(mv_mat,0.0f,0.0f,-oz); + glUniformMatrix4fv(pp->mat_mv_index,1,GL_FALSE,mv_mat); + + 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; + + 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->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); + + 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,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; ine; 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); + + if (pp->appearance != APPEARANCE_DIRECTION_BANDS) + { + polys = 2*numv*(numu+1); + if (pp->appearance == APPEARANCE_DISTANCE_BANDS) + polys /= 2; + } + else /* pp->appearance == APPEARANCE_DIRECTION_BANDS */ + { + polys = numu*(numv+1); } - polys /= 2; return polys; } +#endif /* HAVE_GLSL */ + /* Generate a texture image that shows the orientation reversal. */ static void gen_texture(ModeInfo *mi) { romanboystruct *pp = &romanboy[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); @@ -1161,13 +1991,151 @@ static void gen_texture(ModeInfo *mi) } +#ifdef HAVE_GLSL + +static void init_glsl(ModeInfo *mi) +{ + romanboystruct *pp = &romanboy[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]; + + pp->uv = calloc(2*pp->g*(NUMU+1)*(NUMV+1),sizeof(float)); + pp->indices = calloc(4*pp->g*(NUMU+1)*(NUMV+1),sizeof(float)); + + /* 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_mv_index = glGetUniformLocation(pp->shader_program, + "MatModelView"); + pp->mat_p_index = glGetUniformLocation(pp->shader_program, + "MatProj"); + pp->g_index = glGetUniformLocation(pp->shader_program, + "G"); + pp->d_index = glGetUniformLocation(pp->shader_program, + "D"); + 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_mv_index == -1 || pp->mat_p_index == -1 || + pp->g_index == -1 || pp->d_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 }; romanboystruct *pp = &romanboy[MI_SCREEN(mi)]; if (deform_speed == 0.0) @@ -1214,84 +2182,28 @@ static void init(ModeInfo *mi) pp->offset3d[1] = 0.0; pp->offset3d[2] = -1.8; + pp->pp = calloc(3*pp->g*(NUMU+1)*(NUMV+1),sizeof(float)); + pp->pn = calloc(3*pp->g*(NUMU+1)*(NUMV+1),sizeof(float)); + pp->col = calloc(4*pp->g*(NUMU+1)*(NUMV+1),sizeof(float)); + pp->tex = calloc(2*pp->g*(NUMU+1)*(NUMV+1),sizeof(float)); + gen_texture(mi); setup_roman_boy_color_texture(mi,0.0,2.0*M_PI,0.0,2.0*M_PI,pp->g*NUMU,NUMV); - if (pp->marks) - glEnable(GL_TEXTURE_2D); - else - glDisable(GL_TEXTURE_2D); +#ifdef HAVE_GLSL + init_glsl(mi); +#endif /* HAVE_GLSL */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (pp->projection == DISP_PERSPECTIVE || pp->view == VIEW_WALK) - { - if (pp->view == VIEW_WALK) - gluPerspective(60.0,1.0,0.01,10.0); - else - gluPerspective(60.0,1.0,0.1,10.0); - } - else - { - glOrtho(-1.0,1.0,-1.0,1.0,0.1,10.0); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - -# 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_GLSL */ } -/* Redisplay the Klein bottle. */ +/* Redisplay the projective plane. */ static void display_romanboy(ModeInfo *mi) { romanboystruct *pp = &romanboy[MI_SCREEN(mi)]; @@ -1369,26 +2281,14 @@ static void display_romanboy(ModeInfo *mi) } } - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (pp->projection == DISP_PERSPECTIVE || pp->view == VIEW_WALK) - { - if (pp->view == VIEW_WALK) - 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 = roman_boy_pf(mi,0.0,2.0*M_PI,0.0,2.0*M_PI, + pp->g*NUMU,NUMV); else - { - if (pp->aspect >= 1.0) - glOrtho(-pp->aspect,pp->aspect,-1.0,1.0,0.1,10.0); - else - glOrtho(-1.0,1.0,-1.0/pp->aspect,1.0/pp->aspect,0.1,10.0); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - mi->polygon_count = roman_boy(mi,0.0,2.0*M_PI,0.0,2.0*M_PI,pp->g*NUMU,NUMV); +#endif /* HAVE_GLSL */ + mi->polygon_count = roman_boy_ff(mi,0.0,2.0*M_PI,0.0,2.0*M_PI, + pp->g*NUMU,NUMV); } @@ -1459,11 +2359,6 @@ ENTRYPOINT void init_romanboy(ModeInfo *mi) else pp->g = surface_order; - pp->pp = calloc(3*pp->g*(NUMU+1)*(NUMV+1),sizeof(float)); - pp->pn = calloc(3*pp->g*(NUMU+1)*(NUMV+1),sizeof(float)); - pp->col = calloc(4*pp->g*(NUMU+1)*(NUMV+1),sizeof(float)); - pp->tex = calloc(2*pp->g*(NUMU+1)*(NUMV+1),sizeof(float)); - pp->trackball = gltrackball_init(True); pp->button_pressed = False; @@ -1595,7 +2490,6 @@ ENTRYPOINT void init_romanboy(ModeInfo *mi) if ((pp->glx_context = init_GL(mi)) != NULL) { reshape_romanboy(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); - glDrawBuffer(GL_BACK); init(mi); } else @@ -1625,6 +2519,8 @@ ENTRYPOINT void draw_romanboy(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(); @@ -1639,12 +2535,19 @@ ENTRYPOINT void draw_romanboy(ModeInfo *mi) } -/* - *----------------------------------------------------------------------------- - * The display is being taken away from us. Free up malloc'ed - * memory and X resources that we've alloc'ed. - *----------------------------------------------------------------------------- - */ +#ifndef STANDALONE +ENTRYPOINT void change_romanboy(ModeInfo *mi) +{ + romanboystruct *pp = &romanboy[MI_SCREEN(mi)]; + + if (!pp->glx_context) + return; + + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *pp->glx_context); + init(mi); +} +#endif /* !STANDALONE */ + ENTRYPOINT void free_romanboy(ModeInfo *mi) { @@ -1659,20 +2562,24 @@ ENTRYPOINT void free_romanboy(ModeInfo *mi) if (pp->tex) free(pp->tex); gltrackball_free (pp->trackball); if (pp->tex_name) glDeleteTextures (1, &pp->tex_name); +#ifdef HAVE_GLSL + if (pp->uv) free(pp->uv); + if (pp->indices) free(pp->indices); + 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 */ } -#ifndef STANDALONE -ENTRYPOINT void change_romanboy(ModeInfo *mi) -{ - romanboystruct *pp = &romanboy[MI_SCREEN(mi)]; - - if (!pp->glx_context) - return; - - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *pp->glx_context); - init(mi); -} -#endif /* !STANDALONE */ XSCREENSAVER_MODULE ("RomanBoy", romanboy) -- cgit v1.2.3-55-g7522