diff options
| author | Simon Rettberg | 2024-09-06 14:42:37 +0200 |
|---|---|---|
| committer | Simon Rettberg | 2024-09-06 14:42:37 +0200 |
| commit | badef32037f52f79abc1f1440b786cd71afdf270 (patch) | |
| tree | 412b792d4cab4a7a110db82fcf74fe8a1ac55ec1 /hacks/glx/sphereeversion.c | |
| parent | Delete pre-6.00 files (diff) | |
| download | xscreensaver-master.tar.gz xscreensaver-master.tar.xz xscreensaver-master.zip | |
Diffstat (limited to 'hacks/glx/sphereeversion.c')
| -rw-r--r-- | hacks/glx/sphereeversion.c | 3339 |
1 files changed, 0 insertions, 3339 deletions
diff --git a/hacks/glx/sphereeversion.c b/hacks/glx/sphereeversion.c deleted file mode 100644 index cd58275..0000000 --- a/hacks/glx/sphereeversion.c +++ /dev/null @@ -1,3339 +0,0 @@ -/* sphereeversion --- Shows a sphere eversion, i.e., a smooth deformation - (homotopy) that turns a sphere inside out. During the eversion, the - deformed sphere is allowed to intersect itself transversally. However, - no creases or pinch points are allowed to occur. */ - -#if 0 -static const char sccsid[] = "@(#)sphereeversion.c 1.1 20/03/22 xlockmore"; -#endif - -/* Copyright (c) 2020-2021 Carsten Steger <carsten@mirsanmir.org>. */ - -/* - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation. - * - * This file is provided AS IS with no warranties of any kind. The author - * shall have no liability with respect to the infringement of copyrights, - * trade secrets or any patents by this file or any part thereof. In no - * event will the author be liable for any lost revenue or profits or - * other special, indirect and consequential damages. - * - * REVISION HISTORY: - * C. Steger - 20/03/22: Initial version - * C. Steger - 20/04/10: Added blending between visualization modes - * C. Steger - 20/06/01: Removed blending because accumulation buffers have - * * been deprecated since OpenGL 3.0 - * C. Steger - 20/07/26: Make the polygon offset work under OpenGL ES - * C. Steger - 20/08/03: Add an easing function for one part of the animation - * C. Steger - 20/10/11: Add easing functions for more parts of the animation - * C. Steger - 21/01/03: Added per-fragment shading - * C. Steger - 21/01/05: Added blending between visualization modes using - * multiple render passes - */ - -/* - * This program shows a sphere eversion, i.e., a smooth deformation - * (homotopy) that turns a sphere inside out. During the eversion, - * the deformed sphere is allowed to intersect itself transversally. - * However, no creases or pinch points are allowed to occur. - * - * The deformed sphere can be projected to the screen either - * perspectively or orthographically. - * - * There are three display modes for the sphere: solid, transparent, - * or random. If random mode is selected, the mode is changed each - * time an eversion has been completed. - * - * The appearance of the sphere can be as a solid object, as a set of - * see-through bands, or random. The bands can be parallel bands or - * meridian bands, i.e., bands that run along the parallels (lines of - * latitude) or bands that run along the meridians (lines of - * longitude) of the sphere. If random mode is selected, the - * appearance is changed each time an eversion has been completed. - * - * It is also possible to display a graticule (i.e., a coordinate grid - * consisting of parallel and meridian lines) on top of the surface. - * The graticule mode can be set to on, off, or random. If random - * mode is selected, the graticule mode is changed each time an - * eversion has been completed. - * - * It is possible to define a surface order of the sphere eversion as - * random or as a value between 2 and 5. This determines the the - * complexity of the deformation. For higher surface orders, some - * z-fighting might occur around the central stage of the eversion, - * which might lead to some irregular flickering of the displayed - * surface if it is displayed as a solid object. For odd surface - * orders, z-fighting will occur very close to the central stage of - * the eversion since the deformed sphere is a doubly covered Boy - * surface (for surface order 3) or a doubly covered generalized Boy - * surface (for surface order 5) in this case. If you find this - * distracting, you should set the surface order to 2. If a random - * surface order is selected, the surface order is changed each time - * an eversion has been completed. - * - * The colors with with the sphere is drawn can be set to two-sided, - * parallel, meridian, or random. In two-sided mode, the sphere is - * drawn with red on one side and green on the other side. In - * parallel mode, the sphere is displayed with colors that run from - * red to cyan on one side of the surface and from green to violet on - * the other side. The colors are aligned with the parallels of the - * sphere in this mode. In meridian mode, the the sphere is displayed - * with colors that run from red to white to cyan to black and back to - * red on one side of the surface and from green to white to violet to - * black and back to green on the other side. The colors are aligned - * with the meridians of the sphere in this mode. If random mode is - * selected, the color scheme is changed each time an eversion has - * been completed. - * - * By default, the sphere is rotated to a new viewing position each - * time an eversion has been completed. In addition, it is possible - * to rotate the sphere while it is deforming. The rotation speed for - * each of the three coordinate axes around which the sphere rotates - * can be chosen arbitrarily. For best effects, however, it is - * suggested to rotate only around the z axis while the sphere is - * deforming. - * - * This program is inspired by the following paper: Adam Bednorz, - * Witold Bednorz: "Analytic sphere eversion using ruled surfaces", - * Differential Geometry and its Applications 64:59-79, 2019. - */ - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#define DISP_SURFACE 0 -#define DISP_TRANSPARENT 1 -#define NUM_DISPLAY_MODES 2 - -#define APPEARANCE_SOLID 0 -#define APPEARANCE_PARALLEL_BANDS 1 -#define APPEARANCE_MERIDIAN_BANDS 2 -#define NUM_APPEARANCES 3 - -#define COLORS_TWOSIDED 0 -#define COLORS_PARALLEL 1 -#define COLORS_MERIDIAN 2 -#define NUM_COLORS 3 - -#define DISP_PERSPECTIVE 0 -#define DISP_ORTHOGRAPHIC 1 -#define NUM_DISP_MODES 2 - -#define DEF_DISPLAY_MODE "random" -#define DEF_APPEARANCE "random" -#define DEF_GRATICULE "random" -#define DEF_COLORS "random" -#define DEF_PROJECTION "random" -#define DEF_SPEEDX "0.0" -#define DEF_SPEEDY "0.0" -#define DEF_SPEEDZ "0.0" -#define DEF_DEFORM_SPEED "10.0" -#define DEF_SURFACE_ORDER "random" - - -/* For some strange reason, the color buffer must be initialized - and used on macOS. Otherwise one- and two-sided lighting will - not work. */ -#if (defined(HAVE_COCOA) || defined(__APPLE__)) && !defined(HAVE_IPHONE) -#define VERTEXATTRIBARRAY_WORKAROUND -#endif - -#ifdef STANDALONE -# define DEFAULTS "*delay: 10000 \n" \ - "*showFPS: False \n" \ - "*prefersGLSL: True \n" \ - -# define release_sphereeversion 0 -# include "xlockmore.h" /* from the xscreensaver distribution */ -#else /* !STANDALONE */ -# include "xlock.h" /* from the xlockmore distribution */ -#endif /* !STANDALONE */ - -#ifdef USE_GL - -#include "glsl-utils.h" -#include "gltrackball.h" -#include "pow2.h" - -#include <float.h> - - -#ifdef USE_MODULES -ModStruct sphereeversion_description = -{"sphereeversion", "init_sphereeversion", "draw_sphereeversion", - NULL, "draw_sphereeversion", "change_sphereeversion", - "free_sphereeversion", &sphereeversion_opts, 25000, 1, 1, 1, 1.0, 4, "", - "Show a sphere eversion", 0, NULL}; - -#endif - - -static char *mode; -static char *appear; -static char *color_mode; -static char *graticule; -static char *proj; -static float speed_x; -static float speed_y; -static float speed_z; -static float deform_speed; -static char *surface_order; - - -static XrmOptionDescRec opts[] = -{ - {"-mode", ".displayMode", XrmoptionSepArg, 0 }, - {"-surface", ".displayMode", XrmoptionNoArg, "surface" }, - {"-transparent", ".displayMode", XrmoptionNoArg, "transparent" }, - {"-appearance", ".appearance", XrmoptionSepArg, 0 }, - {"-solid", ".appearance", XrmoptionNoArg, "solid" }, - {"-parallel-bands", ".appearance", XrmoptionNoArg, "parallel-bands" }, - {"-meridian-bands", ".appearance", XrmoptionNoArg, "meridian-bands" }, - {"-graticule", ".graticule", XrmoptionSepArg, 0 }, - {"-colors", ".colors", XrmoptionSepArg, 0 }, - {"-twosided-colors", ".colors", XrmoptionNoArg, "two-sided" }, - {"-parallel-colors", ".colors", XrmoptionNoArg, "parallel" }, - {"-meridian-colors", ".colors", XrmoptionNoArg, "meridian" }, - {"-projection", ".projection", XrmoptionSepArg, 0 }, - {"-perspective", ".projection", XrmoptionNoArg, "perspective" }, - {"-orthographic", ".projection", XrmoptionNoArg, "orthographic" }, - {"-speed-x", ".speedx", XrmoptionSepArg, 0 }, - {"-speed-y", ".speedy", XrmoptionSepArg, 0 }, - {"-speed-z", ".speedz", XrmoptionSepArg, 0 }, - {"-deformation-speed", ".deformSpeed", XrmoptionSepArg, 0 }, - {"-surface-order", ".surfaceOrder", XrmoptionSepArg, 0 }, -}; - -static argtype vars[] = -{ - { &mode, "displayMode", "DisplayMode", DEF_DISPLAY_MODE, t_String }, - { &appear, "appearance", "Appearance", DEF_APPEARANCE, t_String }, - { &graticule, "graticule", "Graticule", DEF_GRATICULE, t_String }, - { &color_mode, "colors", "Colors", DEF_COLORS, t_String }, - { &surface_order, "surfaceOrder", "SurfaceOrder", DEF_SURFACE_ORDER, t_String }, - { &proj, "projection", "Projection", DEF_PROJECTION, t_String }, - { &speed_x, "speedx", "Speedx", DEF_SPEEDX, t_Float}, - { &speed_y, "speedy", "Speedy", DEF_SPEEDY, t_Float}, - { &speed_z, "speedz", "Speedz", DEF_SPEEDZ, t_Float}, - { &deform_speed, "deformSpeed", "DeformSpeed", DEF_DEFORM_SPEED, t_Float}, -}; - -ENTRYPOINT ModeSpecOpt sphereeversion_opts = -{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, NULL}; - - -/* Shape parameters for the Bednorz sphere eversion. */ -#define BEDNORZ_OMEGA 2.0 -#define BEDNORZ_Q (2.0/3.0) -#define BEDNORZ_ETA_MIN (3.0/4.0) -#define BEDNORZ_BETA_MAX 0.1 -#define BEDNORZ_ALPHA 1.0 -#define BEDNORZ_EPS2 0.001 -#define BEDNORZ_EPS3 0.002 -#define BEDNORZ_EPS4 0.001 -#define BEDNORZ_EPS5 0.002 - -#define BEDNORZ_TAU1 (1.0/BEDNORZ_Q) -#define BEDNORZ_TAU2 2.5 -#define BEDNORZ_TAU3 4.5 -#define BEDNORZ_TAU4 6.0 - -#define BEDNORZ_TAU_MIN (-BEDNORZ_TAU4) -#define BEDNORZ_TAU_MAX (BEDNORZ_TAU4) - -/* Number of subdivisions of the surface */ -#define NUMTH 256 -#define NUMPH 256 - -/* Number of subdivisions between grid lines */ -#define NUMGRID 32 - -/* Number of subdivisions per band */ -#define NUMBDIR 16 -#define NUMBDIST 16 - -/* Animation states */ -#define ANIM_DEFORM 0 -#define ANIM_TURN 1 - -/* Angle of a single turn step */ -#define TURN_STEP 1.0 - -typedef struct { - int n; - double kappa; - double omega; - double t; - double p; - double q; - double xi; - double eta; - double alpha; - double beta; - double gamma; - double lambda; - double eps; -} bednorz_shape_par; - - -typedef struct { - GLint WindH, WindW; - GLXContext *glx_context; - /* Options */ - int display_mode[2]; - Bool random_display_mode; - int appearance[2]; - Bool random_appearance; - Bool graticule[2]; - Bool random_graticule; - int colors[2]; - Bool random_colors; - int projection; - /* 3D rotation angles */ - float alpha, beta, delta; - /* Animation state */ - int anim_state; - /* Deformation parameters */ - float tau; - int defdir; - /* Turning parameters */ - int turn_step; - int num_turn; - float qs[4], qe[4]; - /* Two global shape parameters of the Bednorz sphere eversion */ - float eta_min, beta_max; - /* The order of the Bednorz sphere eversion */ - int g; - Bool random_g; - /* The viewing offset in 3d */ - float offset3d[3]; - /* The 3d coordinates of the surface and the corresponding normal vectors */ - float *se; - float *sen; - /* The precomputed colors of the surface */ - float *colf[2]; - float *colb[2]; - /* Aspect ratio of the current window */ - float aspect; - /* Trackball states */ - trackball_state *trackball; - Bool button_pressed; - /* A random factor to modify the rotation speeds */ - float speed_scale; -#ifdef HAVE_GLSL - GLuint *solid_indices, *parallel_indices; - GLuint *meridian_indices, *line_indices; - Bool use_shaders, buffers_initialized; - GLuint poly_shader_program; - GLint poly_pos_index, poly_normal_index; - GLint poly_colorf_index, poly_colorb_index; - GLint poly_mv_index, poly_proj_index; - GLint poly_glbl_ambient_index, poly_lt_ambient_index; - GLint poly_lt_diffuse_index, poly_lt_specular_index; - GLint poly_lt_direction_index, poly_lt_halfvect_index; - GLint poly_front_ambient_index, poly_back_ambient_index; - GLint poly_front_diffuse_index, poly_back_diffuse_index; - GLint poly_specular_index, poly_shininess_index; - GLuint line_shader_program; - GLint line_pos_index, line_color_index; - GLint line_mv_index, line_proj_index; - GLint max_tex_size; - GLuint color_textures[2]; - GLuint blend_shader_program; - GLint blend_vertex_p_index, blend_vertex_t_index; - GLint blend_t_index, blend_sampler0_index, blend_sampler1_index; - GLuint vertex_pos_buffer, vertex_normal_buffer; - GLuint vertex_colorf_buffer[2], vertex_colorb_buffer[2]; - GLuint solid_indices_buffer, parallel_indices_buffer; - GLuint meridian_indices_buffer, line_indices_buffer; - GLint num_solid_strips, num_solid_triangles; - GLint num_parallel_strips, num_parallel_triangles; - GLint num_meridian_strips, num_meridian_triangles; - GLint num_lines; -#endif /* HAVE_GLSL */ -} sphereeversionstruct; - -static sphereeversionstruct *sphereeversion = (sphereeversionstruct *) 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 glShaderSource in the function init_glsl(). */ -static const GLchar *poly_vertex_shader_attribs_2_1 = - "attribute vec3 VertexPosition;\n" - "attribute vec3 VertexNormal;\n" - "attribute vec4 VertexColorF;\n" - "attribute vec4 VertexColorB;\n" - "\n" - "varying vec3 Normal;\n" - "varying vec4 ColorF;\n" - "varying vec4 ColorB;\n" - "\n"; -static const GLchar *poly_vertex_shader_attribs_3_0 = - "in vec3 VertexPosition;\n" - "in vec3 VertexNormal;\n" - "in vec4 VertexColorF;\n" - "in vec4 VertexColorB;\n" - "\n" - "out vec3 Normal;\n" - "out vec4 ColorF;\n" - "out vec4 ColorB;\n" - "\n"; -static const GLchar *poly_vertex_shader_main = - "uniform mat4 MatModelView;\n" - "uniform mat4 MatProj;\n" - "\n" - "void main (void)\n" - "{\n" - " ColorF = VertexColorF;\n" - " ColorB = VertexColorB;\n" - " Normal = normalize(MatModelView*vec4(VertexNormal,0.0f)).xyz;\n" - " vec4 Position = MatModelView*vec4(VertexPosition,1.0f);\n" - " gl_Position = MatProj*Position;\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 *poly_fragment_shader_attribs_2_1 = - "varying vec3 Normal;\n" - "varying vec4 ColorF;\n" - "varying vec4 ColorB;\n" - "\n"; -static const GLchar *poly_fragment_shader_attribs_3_0 = - "in vec3 Normal;\n" - "in vec4 ColorF;\n" - "in vec4 ColorB;\n" - "\n" - "out vec4 FragColor;\n" - "\n"; -static const GLchar *poly_fragment_shader_main = - "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" - "\n" - "void main (void)\n" - "{\n" - " vec3 normalDirection;\n" - " vec4 ambientColor, diffuseColor, sceneColor;\n" - " vec4 ambientLighting, diffuseReflection, specularReflection, color;\n" - " float ndotl, ndoth, pf;\n" - " \n" - " if (gl_FrontFacing)\n" - " {\n" - " normalDirection = normalize(Normal);\n" - " sceneColor = ColorF*MatFrontAmbient*LtGlblAmbient;\n" - " ambientColor = ColorF*MatFrontAmbient;\n" - " diffuseColor = ColorF*MatFrontDiffuse;\n" - " }\n" - " else\n" - " {\n" - " normalDirection = -normalize(Normal);\n" - " sceneColor = ColorB*MatBackAmbient*LtGlblAmbient;\n" - " ambientColor = ColorB*MatBackAmbient;\n" - " diffuseColor = ColorB*MatBackDiffuse;\n" - " }\n" - " \n" - " ndotl = max(0.0f,dot(normalDirection,LtDirection));\n" - " ndoth = max(0.0f,dot(normalDirection,LtHalfVector));\n" - " if (ndotl == 0.0f)\n" - " pf = 0.0f;\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" - " specularReflection;\n"; -static const GLchar *poly_fragment_shader_out_2_1 = - " gl_FragColor = clamp(color,0.0f,1.0f);\n" - "}\n"; -static const GLchar *poly_fragment_shader_out_3_0 = - " FragColor = clamp(color,0.0f,1.0f);\n" - "}\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 *line_vertex_shader_attribs_2_1 = - "attribute vec3 VertexPosition;\n" - "\n"; -static const GLchar *line_vertex_shader_attribs_3_0 = - "in vec3 VertexPosition;\n" - "\n"; -static const GLchar *line_vertex_shader_main = - "uniform mat4 MatModelView;\n" - "uniform mat4 MatProj;\n" - "\n" - "void main (void)\n" - "{\n" - " vec4 Position = MatModelView*vec4(VertexPosition,1.0f);\n" - " gl_Position = MatProj*Position;\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 *line_fragment_shader_attribs_2_1 = - ""; -static const GLchar *line_fragment_shader_attribs_3_0 = - "out vec4 FragColor;\n" - "\n"; -static const GLchar *line_fragment_shader_main = - "uniform vec4 LineColor;\n" - "\n" - "void main (void)\n" - "{\n"; -static const GLchar *line_fragment_shader_out_2_1 = - " gl_FragColor = LineColor;\n" - "}\n"; -static const GLchar *line_fragment_shader_out_3_0 = - " FragColor = LineColor;\n" - "}\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 *blend_vertex_shader_attribs_2_1 = - "attribute vec2 VertexP;\n" - "attribute vec2 VertexT;\n" - "\n" - "varying vec2 TexCoord;\n" - "\n"; -static const GLchar *blend_vertex_shader_attribs_3_0 = - "in vec2 VertexP;\n" - "in vec2 VertexT;\n" - "\n" - "out vec2 TexCoord;\n" - "\n"; -static const GLchar *blend_vertex_shader_main = - "void main (void)\n" - "{\n" - " gl_Position = vec4(VertexP,0.0f,1.0f);\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 *blend_fragment_shader_attribs_2_1 = - "varying vec2 TexCoord;\n" - "\n"; -static const GLchar *blend_fragment_shader_attribs_3_0 = - "in vec2 TexCoord;\n" - "\n" - "out vec4 FragColor;\n" - "\n"; -static const GLchar *blend_fragment_shader_main = - "uniform sampler2D TextureSampler0;" - "uniform sampler2D TextureSampler1;" - "uniform float T;" - "\n" - "void main (void)\n" - "{\n"; -static const GLchar *blend_fragment_shader_out_2_1 = - " vec3 Color0 = texture2D(TextureSampler0,TexCoord.st).rgb;\n" - " vec3 Color1 = texture2D(TextureSampler1,TexCoord.st).rgb;\n" - " gl_FragColor = vec4(T*Color0+(1.0f-T)*Color1,1.0f);\n" - "}\n"; -static const GLchar *blend_fragment_shader_out_3_0 = - " vec3 Color0 = texture(TextureSampler0,TexCoord.st).rgb;\n" - " vec3 Color1 = texture(TextureSampler1,TexCoord.st).rgb;\n" - " FragColor = vec4(T*Color0+(1.0f-T)*Color1,1.0f);\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) -{ - float c, s, u, v; - int i; - - phi *= M_PI/180.0; - c = cos(phi); - s = sin(phi); - for (i=0; i<3; i++) - { - u = m[i][1]; - v = m[i][2]; - m[i][1] = c*u+s*v; - m[i][2] = -s*u+c*v; - } -} - - -/* Add a rotation around the y-axis to the matrix m. */ -static void rotatey(float m[3][3], float phi) -{ - float c, s, u, v; - int i; - - phi *= M_PI/180.0; - c = cos(phi); - s = sin(phi); - for (i=0; i<3; i++) - { - u = m[i][0]; - v = m[i][2]; - m[i][0] = c*u-s*v; - m[i][2] = s*u+c*v; - } -} - - -/* Add a rotation around the z-axis to the matrix m. */ -static void rotatez(float m[3][3], float phi) -{ - float c, s, u, v; - int i; - - phi *= M_PI/180.0; - c = cos(phi); - s = sin(phi); - for (i=0; i<3; i++) - { - u = m[i][0]; - v = m[i][1]; - m[i][0] = c*u+s*v; - m[i][1] = -s*u+c*v; - } -} - - -/* Compute the rotation matrix m from the rotation angles. */ -static void rotateall(float al, float be, float de, float m[3][3]) -{ - int i, j; - - for (i=0; i<3; i++) - for (j=0; j<3; j++) - m[i][j] = (i==j); - rotatex(m,al); - rotatey(m,be); - rotatez(m,de); -} - - -/* Multiply two rotation matrices: o=m*n. */ -static void mult_rotmat(float m[3][3], float n[3][3], float o[3][3]) -{ - int i, j, k; - - for (i=0; i<3; i++) - { - for (j=0; j<3; j++) - { - o[i][j] = 0.0; - for (k=0; k<3; k++) - o[i][j] += m[i][k]*n[k][j]; - } - } -} - - -/* Compute 3D rotation angles from a unit quaternion. */ -static void quat_to_angles(float q[4], float *alpha, float *beta, float *delta) -{ - double r00, r01, r02, r12, r22; - - r00 = q[0]*q[0]+q[1]*q[1]-q[2]*q[2]-q[3]*q[3]; - r01 = 2.0*(q[1]*q[2]-q[0]*q[3]); - r02 = 2.0*(q[1]*q[3]+q[0]*q[2]); - r12 = 2.0*(q[2]*q[3]-q[0]*q[1]); - r22 = q[0]*q[0]-q[1]*q[1]-q[2]*q[2]+q[3]*q[3]; - - *alpha = atan2(-r12,r22)*180.0/M_PI; - *beta = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI; - *delta = atan2(-r01,r00)*180.0/M_PI; -} - - -/* Compute a 3D rotation matrix from an xscreensaver unit quaternion. Note - that xscreensaver has a different convention for unit quaternions than - the one that is used in this hack. */ -static void quat_to_rotmat(float p[4], float m[3][3]) -{ - float al, be, de; - double r00, r01, r02, r12, r22; - - r00 = 1.0-2.0*(p[1]*p[1]+p[2]*p[2]); - r01 = 2.0*(p[0]*p[1]+p[2]*p[3]); - r02 = 2.0*(p[2]*p[0]-p[1]*p[3]); - r12 = 2.0*(p[1]*p[2]+p[0]*p[3]); - r22 = 1.0-2.0*(p[1]*p[1]+p[0]*p[0]); - - al = atan2(-r12,r22)*180.0/M_PI; - be = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI; - de = atan2(-r01,r00)*180.0/M_PI; - rotateall(al,be,de,m); -} - - -/* Compute a quaternion from angles in degrees. */ -static void angles_to_quat(float alpha, float beta, float delta, float p[4]) -{ - alpha *= M_PI/180.0; - beta *= M_PI/180.0; - delta *= M_PI/180.0; - p[0] = (cos(0.5*alpha)*cos(0.5*beta)*cos(0.5*delta)- - sin(0.5*alpha)*sin(0.5*beta)*sin(0.5*delta)); - p[1] = (sin(0.5*alpha)*cos(0.5*beta)*cos(0.5*delta)+ - cos(0.5*alpha)*sin(0.5*beta)*sin(0.5*delta)); - p[2] = (cos(0.5*alpha)*sin(0.5*beta)*cos(0.5*delta)- - sin(0.5*alpha)*cos(0.5*beta)*sin(0.5*delta)); - p[3] = (cos(0.5*alpha)*cos(0.5*beta)*sin(0.5*delta)+ - sin(0.5*alpha)*sin(0.5*beta)*cos(0.5*delta)); -} - - -/* Perform a spherical linear interpolation between two quaternions. */ -static void quat_slerp(float t, float qs[4], float qe[4], float q[4]) -{ - double cos_t, sin_t, alpha, beta, theta, phi, l; - - alpha = t; - cos_t = qs[0]*qe[0]+qs[1]*qe[1]+qs[2]*qe[2]+qs[3]*qe[3]; - if (1.0-cos_t < FLT_EPSILON) - { - beta = 1.0-alpha; - } - else - { - theta = acos(cos_t); - phi = theta; - sin_t = sin(theta); - beta = sin(theta-alpha*phi)/sin_t; - alpha = sin(alpha*phi)/sin_t; - } - q[0] = beta*qs[0]+alpha*qe[0]; - q[1] = beta*qs[1]+alpha*qe[1]; - q[2] = beta*qs[2]+alpha*qe[2]; - q[3] = beta*qs[3]+alpha*qe[3]; - l = 1.0/sqrt(q[0]*q[0]+q[1]*q[1]+q[2]*q[2]+q[3]*q[3]); - q[0] *= l; - q[1] *= l; - q[2] *= l; - q[3] *= l; -} - - -/* Compute a fully saturated and bright color based on an angle and a color - rotation matrix. */ -static void color(sphereeversionstruct *se, float angle, float mat[3][3], - float colf[4], float colb[4]) -{ - float ca, sa; - float m; - - ca = cosf(angle); - sa = sinf(angle); - colf[0] = ca*mat[0][0]+sa*mat[0][2]; - colf[1] = ca*mat[1][0]+sa*mat[1][2]; - colf[2] = ca*mat[2][0]+sa*mat[2][2]; - m = 0.5f/fmaxf(fmaxf(fabsf(colf[0]),fabsf(colf[1])),fabsf(colf[2])); - colf[0] = m*colf[0]+0.5f; - colf[1] = m*colf[1]+0.5f; - colf[2] = m*colf[2]+0.5f; - if (se->display_mode[0] == DISP_TRANSPARENT) - colf[3] = 0.7f; - else - colf[3] = 1.0f; - - colb[0] = ca*mat[0][1]+sa*mat[0][2]; - colb[1] = ca*mat[1][1]+sa*mat[1][2]; - colb[2] = ca*mat[2][1]+sa*mat[2][2]; - m = 0.5f/fmaxf(fmaxf(fabsf(colb[0]),fabsf(colb[1])),fabsf(colb[2])); - colb[0] = m*colb[0]+0.5f; - colb[1] = m*colb[1]+0.5f; - colb[2] = m*colb[2]+0.5f; - if (se->display_mode[0] == DISP_TRANSPARENT) - colb[3] = 0.7f; - else - colb[3] = 1.0f; -} - - -/* Compute the cross product between the vectors a and b. */ -static inline void cross(float a[3], float b[3], float c[3]) -{ - c[0] = a[1]*b[2]-a[2]*b[1]; - c[1] = a[2]*b[0]-a[0]*b[2]; - c[2] = a[0]*b[1]-a[1]*b[0]; -} - - -/* Compute x^n for integers 0 <= n <= 11 efficiently. */ -static inline double ipow(double x, int n) -{ - double x2, x4, x8; - - switch (n) - { - case 0: - return 1.0; - case 1: - return x; - case 2: - x2 = x*x; - return x2; - case 3: - x2 = x*x; - return x2*x; - case 4: - x2 = x*x; - x4 = x2*x2; - return x4; - case 5: - x2 = x*x; - x4 = x2*x2; - return x4*x; - case 6: - x2 = x*x; - x4 = x2*x2; - return x4*x2; - case 7: - x2 = x*x; - x4 = x2*x2; - return x4*x2*x; - case 8: - x2 = x*x; - x4 = x2*x2; - x8 = x4*x4; - return x8; - case 9: - x2 = x*x; - x4 = x2*x2; - x8 = x4*x4; - return x8*x; - case 10: - x2 = x*x; - x4 = x2*x2; - x8 = x4*x4; - return x8*x2; - case 11: - x2 = x*x; - x4 = x2*x2; - x8 = x4*x4; - return x8*x2*x; - default: - return pow(x,n); - } -} - - -/* Compute the Bednorz shape parameter kappa based on the eversion order n. */ -static inline double bednorz_get_kappa(int n) -{ - return (n-1.0)/(2.0*n); -} - - -/* Compute the Bednorz shape parameter t based on the deformation - parameter tau. */ -static inline double bednorz_get_t(double tau) -{ - return (tau >= BEDNORZ_TAU1 ? - BEDNORZ_TAU1 : - (tau <= -BEDNORZ_TAU1 ? - -BEDNORZ_TAU1 : - tau)); -} - - -/* Compute the Bednorz shape parameter q based on the deformation - parameter tau. */ -static inline double bednorz_get_q(double tau) -{ - double abs_tau; - - abs_tau = fabs(tau); - return (abs_tau < BEDNORZ_TAU1 ? - 0.0 : - (abs_tau < BEDNORZ_TAU2 ? - BEDNORZ_Q*(abs_tau-BEDNORZ_TAU1)/(BEDNORZ_TAU2-BEDNORZ_TAU1) : - BEDNORZ_Q)); -} - - -/* Compute the Bednorz shape parameter p based on the deformation - parameter tau. */ -static inline double bednorz_get_p(double tau) -{ - return 1.0-fabs(bednorz_get_q(tau)*bednorz_get_t(tau)); -} - - -/* Compute the Bednorz shape parameter xi based on the deformation - parameter tau. */ -static inline double bednorz_get_xi(double tau) -{ - double abs_tau; - - abs_tau = fabs(tau); - return (abs_tau < BEDNORZ_TAU2 ? - 1.0 : - (abs_tau < BEDNORZ_TAU3 ? - (BEDNORZ_TAU3-abs_tau)/(BEDNORZ_TAU3-BEDNORZ_TAU2) : - 0.0)); -} - - -/* Compute the Bednorz shape parameter eta based on the deformation - parameter tau and the shape parameter eta_min. */ -static inline double bednorz_get_eta(double tau, double eta_min) -{ - double abs_tau; - - abs_tau = fabs(tau); - return (abs_tau < BEDNORZ_TAU2 ? - eta_min : - (abs_tau < BEDNORZ_TAU3 ? - (eta_min+(1.0-eta_min)* - (abs_tau-BEDNORZ_TAU2)/(BEDNORZ_TAU3-BEDNORZ_TAU2)) : - 1.0)); -} - - -/* Compute the Bednorz shape parameter alpha based on the deformation - parameter tau. */ -static inline double bednorz_get_alpha(double tau) -{ - double xi; - - xi = bednorz_get_xi(tau); - return BEDNORZ_ALPHA*ipow(xi,2); -} - - -/* Compute the Bednorz shape parameter beta based on the deformation - parameter tau and the shape parameter beta_max. */ -static inline double bednorz_get_beta(double tau, double beta_max) -{ - double xi; - - xi = bednorz_get_xi(tau); - return ipow(1.0-xi,2)+beta_max*ipow(xi,3); -} - - -/* Compute the Bednorz shape parameter gamma based on the shape - parameters alpha and beta. */ -static inline double bednorz_get_gamma(double alpha, double beta) -{ - return 2.0*sqrt(alpha*beta); -} - - -/* Compute the Bednorz shape parameter lambda based on the deformation - parameter tau. */ -static inline double bednorz_get_lambda(double tau) -{ - double abs_tau; - - abs_tau = fabs(tau); - return (abs_tau < BEDNORZ_TAU3 ? - 1.0 : - (abs_tau < BEDNORZ_TAU4 ? - (BEDNORZ_TAU4-abs_tau)/(BEDNORZ_TAU4-BEDNORZ_TAU3) : - 0.0)); -} - - -/* Compute the Bednorz shape parameter eps based on the deformation - parameter tau and the eversion order n. This is an extension to the - original approach that prevents z fighting to some extent in certain - stages of the eversion. */ -static inline double bednorz_get_eps(double tau, int n) -{ - double sgn_tau, abs_tau; - - sgn_tau = (tau < 0.0 ? -1.0 : (tau > 0.0 ? 1.0 : 0.0)); - abs_tau = fabs(tau); - switch (n) - { - case 2: - return (abs_tau < BEDNORZ_TAU1 ? - 0.0 : - (abs_tau < BEDNORZ_TAU2 ? - (BEDNORZ_EPS2*sgn_tau* - (abs_tau-BEDNORZ_TAU1)/(BEDNORZ_TAU2-BEDNORZ_TAU1)) : - (abs_tau < BEDNORZ_TAU3 ? - BEDNORZ_EPS2*sgn_tau : - (abs_tau < BEDNORZ_TAU4 ? - (BEDNORZ_EPS2*sgn_tau* - (BEDNORZ_TAU4-abs_tau)/(BEDNORZ_TAU4-BEDNORZ_TAU3)) : - 0.0)))); - case 3: - return (abs_tau < BEDNORZ_TAU1 ? - BEDNORZ_EPS3*sgn_tau*abs_tau/BEDNORZ_TAU1 : - (abs_tau < BEDNORZ_TAU3 ? - BEDNORZ_EPS3*sgn_tau : - (abs_tau < BEDNORZ_TAU4 ? - (BEDNORZ_EPS3*sgn_tau* - (BEDNORZ_TAU4-abs_tau)/(BEDNORZ_TAU4-BEDNORZ_TAU3)) : - 0.0))); - case 4: - return (abs_tau < BEDNORZ_TAU1 ? - BEDNORZ_EPS4*sgn_tau*abs_tau/BEDNORZ_TAU1 : - (abs_tau < BEDNORZ_TAU3 ? - BEDNORZ_EPS4*sgn_tau : - (abs_tau < BEDNORZ_TAU4 ? - (BEDNORZ_EPS4*sgn_tau* - (BEDNORZ_TAU4-abs_tau)/(BEDNORZ_TAU4-BEDNORZ_TAU3)) : - 0.0))); - case 5: - return (abs_tau < BEDNORZ_TAU1 ? - BEDNORZ_EPS5*sgn_tau*abs_tau/BEDNORZ_TAU1 : - (abs_tau < BEDNORZ_TAU3 ? - BEDNORZ_EPS5*sgn_tau : - (abs_tau < BEDNORZ_TAU4 ? - (BEDNORZ_EPS5*sgn_tau* - (BEDNORZ_TAU4-abs_tau)/(BEDNORZ_TAU4-BEDNORZ_TAU3)) : - 0.0))); - default: - return 0.0; - } -} - - -/* Compute the equations for a point x and its partial derivatives dxdph and - dxdth in the Bednorz sphere eversion based on the sphere parameters phi - (longitude) and theta (latitude) and the shape parameters bsp. This - corresponds to equations (4), (12), and (15) in the paper. */ -static inline void bednorz_get_p0(double phi, double theta, - bednorz_shape_par *bsp, double x[3], - double dxdph[3], double dxdth[3]) -{ - int n; - double kappa, omega, t, p, q, eta, lambda; - double ct, st, cp, sp, cnm1p, snm1p, cnp, snp; - double ctn, ictn, ictnp1, ct2, st2, ct2n, ict2n, ict2np1, ton; - double oml, omlplctn, pe1pk, tat2k, nst2pct2, ost, snpmqt; - double nm1p, ostictn, oictnp1, nst2pct2oictnp1, tcp, tsp; - double lost, tomlplctn, lostcp, lostsp, tomlplctncp, tomlplctnsp; - double tomlplctncpmlostsp, tomlplctnspplostcp, ntctnst, oct2; - double omlpe1pktat2k, nst2; - - n = bsp->n; - kappa = bsp->kappa; - omega = bsp->omega; - t = bsp->t; - p = bsp->p; - q = bsp->q; - eta = bsp->eta; - lambda = bsp->lambda; - - ct = cos(theta); - st = sin(theta); - cp = cos(phi); - sp = sin(phi); - cnp = cos(n*phi); - snp = sin(n*phi); - ctn = ipow(ct,n); - ictn = 1.0/ctn; - ictnp1 = ictn/ct; - ct2 = ct*ct; - st2 = st*st; - ton = t/n; - snpmqt = snp-q*t; - ost = omega*st; - - if (lambda >= 1.0) - { - cnm1p = cos((n-1)*phi); - snm1p = sin((n-1)*phi); - nst2pct2 = n*st2+ct2; - nm1p = (n-1)*p; - tcp = t*cp; - tsp = t*sp; - ostictn = ost*ictn; - oictnp1 = omega*ictnp1; - nst2pct2oictnp1 = nst2pct2*oictnp1; - x[0] = p*snm1p-sp*ostictn+tcp; - x[1] = p*cnm1p+cp*ostictn+tsp; - x[2] = snpmqt*ostictn-ton*cnp; - dxdph[0] = nm1p*cnm1p-cp*ostictn-tsp; - dxdph[1] = -nm1p*snm1p-sp*ostictn+tcp; - dxdph[2] = n*cnp*ostictn+t*snp; - dxdth[0] = -sp*nst2pct2oictnp1; - dxdth[1] = cp*nst2pct2oictnp1; - dxdth[2] = snpmqt*nst2pct2oictnp1; - /* The same formulas written out in full glory: - x[0] = (t*cos(phi)+ - p*sin((n-1)*phi)- - (omega*sin(theta)/ipow(cos(theta),n))*sin(phi)); - x[1] = (t*sin(phi)+ - p*cos((n-1)*phi)+ - (omega*sin(theta)/ipow(cos(theta),n))*cos(phi)); - x[2] = ((omega*sin(theta)/ipow(cos(theta),n))*sin(n*phi)- - (t/n)*cos(n*phi)- - omega*q*t*sin(theta)/ipow(cos(theta),n)); - dxdph[0] = (-t*sin(phi)+ - (n-1)*p*cos((n-1)*phi)- - (omega*sin(theta)/ipow(cos(theta),n))*cos(phi)); - dxdph[1] = (t*cos(phi)- - (n-1)*p*sin((n-1)*phi)- - (omega*sin(theta)/ipow(cos(theta),n))*sin(phi)); - dxdph[2] = ((n*omega*sin(theta)/ipow(cos(theta),n))*cos(n*phi)+ - t*sin(n*phi)); - dxdth[0] = -((omega*sin(phi)*(n*ipow(sin(theta),2)+ipow(cos(theta),2)))/ - ipow(cos(theta),n+1)); - dxdth[1] = ((omega*cos(phi)*(n*ipow(sin(theta),2)+ipow(cos(theta),2)))/ - ipow(cos(theta),n+1)); - dxdth[2] = ((omega*sin(n*phi)*(n*ipow(sin(theta),2)+ipow(cos(theta),2))/ - ipow(cos(theta),n+1))- - (omega*q*t*(n*ipow(sin(theta),2)+ipow(cos(theta),2))/ - ipow(cos(theta),n+1))); - */ - } - else - { - ct2n = ipow(ct,2*n); - ict2n = 1.0/ct2n; - ict2np1 = ict2n/ct; - oml = 1.0-lambda; - omlplctn = oml+lambda*ctn; - pe1pk = pow(eta,1.0+kappa); - tat2k = t*pow(fabs(t),2.0*kappa); - lost = lambda*ost; - lostcp = lost*cp; - lostsp = lost*sp; - tomlplctn = t*omlplctn; - tomlplctncp = tomlplctn*cp; - tomlplctnsp = tomlplctn*sp; - tomlplctncpmlostsp = tomlplctncp-lostsp; - tomlplctnspplostcp = tomlplctnsp+lostcp; - ntctnst = n*t*ctn*st; - oct2 = omega*ct2; - omlpe1pktat2k = oml*pe1pk*tat2k; - nst2 = n*st2; - x[0] = tomlplctncpmlostsp*ictn; - x[1] = tomlplctnspplostcp*ictn; - x[2] = lambda*(ost*snpmqt*ictn-ton*cnp)-omlpe1pktat2k*st*ict2n; - dxdph[0] = -tomlplctnspplostcp*ictn; - dxdph[1] = tomlplctncpmlostsp*ictn; - dxdph[2] = lambda*(omega*n*st*cnp*ictn+t*snp); - dxdth[0] = (n*tomlplctncpmlostsp*st-lambda*(ntctnst*cp+oct2*sp))*ictnp1; - dxdth[1] = (n*tomlplctnspplostcp*st-lambda*(ntctnst*sp-oct2*cp))*ictnp1; - dxdth[2] = (lambda*omega*snpmqt*(nst2+ct2)*ictnp1- - omlpe1pktat2k*(2.0*nst2+ct2)*ict2np1); - /* The same formulas written out in full glory: - x[0] = ((t*(1.0-lambda+lambda*ipow(cos(theta),n))*cos(phi)- - lambda*omega*sin(theta)*sin(phi))/ - ipow(cos(theta),n)); - x[1] = ((t*(1.0-lambda+lambda*ipow(cos(theta),n))*sin(phi)+ - lambda*omega*sin(theta)*cos(phi))/ - ipow(cos(theta),n)); - x[2] = (lambda*(omega*sin(theta)*(sin(n*phi)-q*t)/ipow(cos(theta),n)- - (t/n)*cos(n*phi))- - (1.0-lambda)*pow(eta,1.0+kappa)* - t*pow(fabs(t),2.0*kappa)*sin(theta)/ipow(cos(theta),2*n)); - dxdph[0] = ((-t*(1.0-lambda+lambda*ipow(cos(theta),n))*sin(phi)- - lambda*omega*sin(theta)*cos(phi))/ - ipow(cos(theta),n)); - dxdph[1] = ((t*(1.0-lambda+lambda*ipow(cos(theta),n))*cos(phi)- - lambda*omega*sin(theta)*sin(phi))/ - ipow(cos(theta),n)); - dxdph[2] = (lambda*(omega*n*sin(theta)*(cos(n*phi))/ipow(cos(theta),n)+ - t*sin(n*phi))); - dxdth[0] = ((n*(t*(1.0-lambda+lambda*ipow(cos(theta),n))*cos(phi)- - lambda*omega*sin(theta)*sin(phi))*sin(theta)/ - ipow(cos(theta),n+1))- - (lambda*(n*t*ipow(cos(theta),n)*sin(theta)*cos(phi)+ - omega*ipow(cos(theta),2)*sin(phi))/ - ipow(cos(theta),n+1))); - dxdth[1] = ((n*(t*(1.0-lambda+lambda*ipow(cos(theta),n))*sin(phi)+ - lambda*omega*sin(theta)*cos(phi))*sin(theta)/ - ipow(cos(theta),n+1))- - (lambda*(n*t*ipow(cos(theta),n)*sin(theta)*sin(phi)- - omega*ipow(cos(theta),2)*cos(phi))/ - ipow(cos(theta),n+1))); - dxdth[2] = ((lambda*omega*(sin(n*phi)-q*t)* - (n*ipow(sin(theta),2)+ipow(cos(theta),2))/ - ipow(cos(theta),n+1))- - ((1.0-lambda)*pow(eta,1.0+kappa)*t*pow(fabs(t),2.0*kappa)* - (2.0*n*ipow(sin(theta),2)+ipow(cos(theta),2))/ - ipow(cos(theta),2*n+1))); - */ - } -} - - -/* Compute the equations for a point y and its partial derivatives dydph and - dydth in the Bednorz sphere eversion based on the sphere parameters phi - (longitude) and theta (latitude) and the shape parameters bsp. This - corresponds to equation (7) in the paper. */ -static inline void bednorz_get_p1(double phi, double theta, - bednorz_shape_par *bsp, double y[3], - double dydph[3], double dydth[3]) -{ - double kappa, xi, eta; - double x[3], dxdph[3], dxdth[3]; - double x0, x1, x2, x02, x12, x02px12, ex02px12, xipex02px12; - double ixipex02px122, ixipex02px12k, ixipex02px12kp1; - double x0dx0dphpx1dx1dph, x0dx0dthpx1dx1dth; - double tex0dx0dphpx1dx1dph, tex0dx0dthpx1dx1dth; - double ktex0dx0dphpx1dx1dph, ktex0dx0dthpx1dx1dth; - - kappa = bsp->kappa; - xi = bsp->xi; - eta = bsp->eta; - - bednorz_get_p0(phi,theta,bsp,x,dxdph,dxdth); - - x0 = x[0]; - x1 = x[1]; - x2 = x[2]; - x02 = x0*x0; - x12 = x1*x1; - x02px12 = x02+x12; - ex02px12 = eta*x02px12; - xipex02px12 = xi+ex02px12; - ixipex02px122 = 1.0/(xipex02px12*xipex02px12); - ixipex02px12k = 1.0/pow(xipex02px12,kappa); - ixipex02px12kp1 = ixipex02px12k/xipex02px12; - x0dx0dphpx1dx1dph = x0*dxdph[0]+x1*dxdph[1]; - x0dx0dthpx1dx1dth = x0*dxdth[0]+x1*dxdth[1]; - tex0dx0dphpx1dx1dph = 2.0*eta*x0dx0dphpx1dx1dph; - tex0dx0dthpx1dx1dth = 2.0*eta*x0dx0dthpx1dx1dth; - ktex0dx0dphpx1dx1dph = kappa*tex0dx0dphpx1dx1dph; - ktex0dx0dthpx1dx1dth = kappa*tex0dx0dthpx1dx1dth; - - y[0] = x0*ixipex02px12k; - y[1] = x1*ixipex02px12k; - y[2] = x2/xipex02px12; - dydph[0] = (dxdph[0]*xipex02px12-ktex0dx0dphpx1dx1dph*x0)*ixipex02px12kp1; - dydph[1] = (dxdph[1]*xipex02px12-ktex0dx0dphpx1dx1dph*x1)*ixipex02px12kp1; - dydph[2] = (dxdph[2]*xipex02px12-tex0dx0dphpx1dx1dph*x2)*ixipex02px122; - dydth[0] = (dxdth[0]*xipex02px12-ktex0dx0dthpx1dx1dth*x0)*ixipex02px12kp1; - dydth[1] = (dxdth[1]*xipex02px12-ktex0dx0dthpx1dx1dth*x1)*ixipex02px12kp1; - dydth[2] = (dxdth[2]*xipex02px12-tex0dx0dthpx1dx1dth*x2)*ixipex02px122; - - /* The same formulas written out in full glory: - y[0] = x[0]/pow(xi+eta*(ipow(x[0],2)+ipow(x[1],2)),kappa); - y[1] = x[1]/pow(xi+eta*(ipow(x[0],2)+ipow(x[1],2)),kappa); - y[2] = x[2]/(xi+eta*(ipow(x[0],2)+ipow(x[1],2))); - dydph[0] = ((dxdph[0]*(xi+eta*(ipow(x[0],2)+ipow(x[1],2)))- - 2.0*eta*kappa*x[0]*(x[0]*dxdph[0]+x[1]*dxdph[1]))/ - pow(xi+eta*(ipow(x[0],2)+ipow(x[1],2)),kappa+1.0)); - dydph[1] = ((dxdph[1]*(xi+eta*(ipow(x[0],2)+ipow(x[1],2)))- - 2.0*eta*kappa*x[1]*(x[0]*dxdph[0]+x[1]*dxdph[1]))/ - pow(xi+eta*(ipow(x[0],2)+ipow(x[1],2)),kappa+1.0)); - dydph[2] = ((dxdph[2]*(xi+eta*(ipow(x[0],2)+ipow(x[1],2)))- - 2.0*eta*x[2]*(x[0]*dxdph[0]+x[1]*dxdph[1]))/ - ipow(xi+eta*(ipow(x[0],2)+ipow(x[1],2)),2)); - dydth[0] = ((dxdth[0]*(xi+eta*(ipow(x[0],2)+ipow(x[1],2)))- - 2.0*eta*kappa*x[0]*(x[0]*dxdth[0]+x[1]*dxdth[1]))/ - pow(xi+eta*(ipow(x[0],2)+ipow(x[1],2)),kappa+1.0)); - dydth[1] = ((dxdth[1]*(xi+eta*(ipow(x[0],2)+ipow(x[1],2)))- - 2.0*eta*kappa*x[1]*(x[0]*dxdth[0]+x[1]*dxdth[1]))/ - pow(xi+eta*(ipow(x[0],2)+ipow(x[1],2)),kappa+1.0)); - dydth[2] = ((dxdth[2]*(xi+eta*(ipow(x[0],2)+ipow(x[1],2)))- - 2.0*eta*x[2]*(x[0]*dxdth[0]+x[1]*dxdth[1]))/ - ipow(xi+eta*(ipow(x[0],2)+ipow(x[1],2)),2)); - */ -} - - -/* Compute the equations for a point z and its partial derivatives dzdph and - dzdth in the Bednorz sphere eversion based on the sphere parameters phi - (longitude) and theta (latitude) and the shape parameters bsp. This - corresponds to equations (8) and (9) in the paper. */ -static void inline bednorz_get_p2(double phi, double theta, - bednorz_shape_par *bsp, double z[3], - double dzdph[3], double dzdth[3]) -{ - double alpha, beta, gamma; - double y[3], dydph[3], dydth[3]; - double y0, y1, y2, y02, y12, y02py12, egy2, apby02py12, amby02py12; - double iapby02py12, iapby02py122, igapby02py12, igapby02py122; - double ambogapb, egy2apby02py12, egy2amby02py12, tbegy2; - double y0dy0dphpy1dy1dph, y0dy0dthpy1dy1dth; - double iy02py12, iy02py122, ty0dy0dphpy1dy1dph, ty0dy0dthpy1dy1dth; - double tbegy2y0dy0dphpy1dy1dph, tbegy2y0dy0dthpy1dy1dth; - double gigapby02py122, gegy2amby02py12; - - alpha = bsp->alpha; - beta = bsp->beta; - gamma = bsp->gamma; - - bednorz_get_p1(phi,theta,bsp,y,dydph,dydth); - - y0 = y[0]; - y1 = y[1]; - y2 = y[2]; - y02 = y0*y0; - y12 = y1*y1; - y02py12 = y02+y12; - y0dy0dphpy1dy1dph = y0*dydph[0]+y1*dydph[1]; - y0dy0dthpy1dy1dth = y0*dydth[0]+y1*dydth[1]; - - if (alpha > 0.0) - { - /* For the north and south poles, the equations in bednorz_get_p0 - and bednorz_get_p1 become singular. Therefore, we include a special - treatment here. Furthermore, we compute the surface normal vector - based on the cross product of the partial derivative vectors in - bednorz_point_normal. For the north and south poles, the partial - derivative vectors are linearly dependent and thus don't yield a - useful normal vector. Therefore, we have to include a special - treatment for the two poles. */ - if (fabs(theta-M_PI/2.0) <= 1.0e-4) - { - z[0] = 0.0; - z[1] = 0.0; - z[2] = -sqrt(alpha/beta)/(alpha+beta); - dzdph[0] = 1.0; - dzdph[1] = 0.0; - dzdph[2] = 0.0; - dzdth[0] = 0.0; - dzdth[1] = 1.0; - dzdth[2] = 0.0; - } - else if (fabs(theta+M_PI/2.0) <= 1.0e-4) - { - z[0] = 0.0; - z[1] = 0.0; - z[2] = -sqrt(alpha/beta)/(alpha+beta); - dzdph[0] = 1.0; - dzdph[1] = 0.0; - dzdph[2] = 0.0; - dzdth[0] = 0.0; - dzdth[1] = -1.0; - dzdth[2] = 0.0; - } - else - { - egy2 = exp(gamma*y2); - apby02py12 = alpha+beta*y02py12; - amby02py12 = alpha-beta*y02py12; - iapby02py12 = 1.0/apby02py12; - iapby02py122 = iapby02py12*iapby02py12; - igapby02py12 = iapby02py12/gamma; - igapby02py122 = igapby02py12*igapby02py12; - ambogapb = (alpha-beta)/(gamma*(alpha+beta)); - egy2apby02py12 = egy2*apby02py12; - egy2amby02py12 = egy2*amby02py12; - tbegy2 = 2.0*beta*egy2; - tbegy2y0dy0dphpy1dy1dph = tbegy2*y0dy0dphpy1dy1dph; - tbegy2y0dy0dthpy1dy1dth = tbegy2*y0dy0dthpy1dy1dth; - gigapby02py122 = gamma*igapby02py122; - gegy2amby02py12 = gamma*egy2amby02py12; - - z[0] = y0*egy2*iapby02py12; - z[1] = y1*egy2*iapby02py12; - z[2] = egy2amby02py12*igapby02py12-ambogapb; - dzdph[0] = ((y0*gamma*dydph[2]+dydph[0])*egy2apby02py12- - y0*tbegy2y0dy0dphpy1dy1dph)*iapby02py122; - dzdph[1] = ((y1*gamma*dydph[2]+dydph[1])*egy2apby02py12- - y1*tbegy2y0dy0dphpy1dy1dph)*iapby02py122; - dzdph[2] = (((gegy2amby02py12*dydph[2]-tbegy2y0dy0dphpy1dy1dph)* - apby02py12-tbegy2y0dy0dphpy1dy1dph*amby02py12)* - gigapby02py122); - dzdth[0] = ((y0*gamma*dydth[2]+dydth[0])*egy2apby02py12- - y0*tbegy2y0dy0dthpy1dy1dth)*iapby02py122; - dzdth[1] = ((y1*gamma*dydth[2]+dydth[1])*egy2apby02py12- - y1*tbegy2y0dy0dthpy1dy1dth)*iapby02py122; - dzdth[2] = (((gegy2amby02py12*dydth[2]-tbegy2y0dy0dthpy1dy1dth)* - apby02py12-tbegy2y0dy0dthpy1dy1dth*amby02py12)* - gigapby02py122); - } - - /* The same formulas written out in full glory: - z[0] = (y[0]*exp(gamma*y[2]))/(alpha+beta*(ipow(y[0],2)+ipow(y[1],2))); - z[1] = (y[1]*exp(gamma*y[2]))/(alpha+beta*(ipow(y[0],2)+ipow(y[1],2))); - z[2] = ((exp(gamma*y[2])*(alpha-beta*(ipow(y[0],2)+ipow(y[1],2))))/ - (gamma*(alpha+beta*(ipow(y[0],2)+ipow(y[1],2))))- - ((alpha-beta)/(gamma*(alpha+beta)))); - dzdph[0] = (((exp(gamma*y[2])*(gamma*y[0]*dydph[2]+dydph[0])* - (alpha+beta*(ipow(y[0],2)+ipow(y[1],2))))- - (2.0*beta*exp(gamma*y[2])*y[0]* - (y[0]*dydph[0]+y[1]*dydph[1])))/ - ipow(alpha+beta*(ipow(y[0],2)+ipow(y[1],2)),2)); - dzdph[1] = (((exp(gamma*y[2])*(gamma*y[1]*dydph[2]+dydph[1])* - (alpha+beta*(ipow(y[0],2)+ipow(y[1],2))))- - (2.0*beta*exp(gamma*y[2])*y[1]* - (y[0]*dydph[0]+y[1]*dydph[1])))/ - ipow(alpha+beta*(ipow(y[0],2)+ipow(y[1],2)),2)); - dzdph[2] = (((gamma*exp(gamma*y[2])* - (alpha-beta*(ipow(y[0],2)+ipow(y[1],2)))*dydph[2]- - 2.0*beta*exp(gamma*y[2])*(y[0]*dydph[0]+y[1]*dydph[1]))* - (gamma*(alpha+beta*(ipow(y[0],2)+ipow(y[1],2))))- - (2.0*gamma*beta*exp(gamma*y[2])* - (alpha-beta*(ipow(y[0],2)+ipow(y[1],2)))* - (y[0]*dydph[0]+y[1]*dydph[1])))/ - ipow(gamma*(alpha+beta*(ipow(y[0],2)+ipow(y[1],2))),2)); - dzdth[0] = (((exp(gamma*y[2])*(gamma*y[0]*dydth[2]+dydth[0])* - (alpha+beta*(ipow(y[0],2)+ipow(y[1],2))))- - (2.0*beta*exp(gamma*y[2])*y[0]* - (y[0]*dydth[0]+y[1]*dydth[1])))/ - ipow(alpha+beta*(ipow(y[0],2)+ipow(y[1],2)),2)); - dzdth[1] = (((exp(gamma*y[2])*(gamma*y[1]*dydth[2]+dydth[1])* - (alpha+beta*(ipow(y[0],2)+ipow(y[1],2))))- - (2.0*beta*exp(gamma*y[2])*y[1]* - (y[0]*dydth[0]+y[1]*dydth[1])))/ - ipow(alpha+beta*(ipow(y[0],2)+ipow(y[1],2)),2)); - dzdth[2] = (((gamma*exp(gamma*y[2])* - (alpha-beta*(ipow(y[0],2)+ipow(y[1],2)))*dydth[2]- - 2.0*beta*exp(gamma*y[2])*(y[0]*dydth[0]+y[1]*dydth[1]))* - (gamma*(alpha+beta*(ipow(y[0],2)+ipow(y[1],2))))- - (2.0*gamma*beta*exp(gamma*y[2])* - (alpha-beta*(ipow(y[0],2)+ipow(y[1],2)))* - (y[0]*dydth[0]+y[1]*dydth[1])))/ - ipow(gamma*(alpha+beta*(ipow(y[0],2)+ipow(y[1],2))),2)); - */ - } - else - { - iy02py12 = 1.0/y02py12; - iy02py122 = iy02py12*iy02py12; - ty0dy0dphpy1dy1dph = 2.0*y0dy0dphpy1dy1dph; - ty0dy0dthpy1dy1dth = 2.0*y0dy0dthpy1dy1dth; - - z[0] = y0*iy02py12; - z[1] = y1*iy02py12; - z[2] = -y2; - - /* We compute the surface normal vector based on the cross product - of the partial derivative vectors in bednorz_point_normal. For the - north and south poles, the partial derivative vectors are linearly - dependent and thus don't yield a useful normal vector. Therefore, - we have to include a special treatment for the two poles. */ - if (fabs(theta-M_PI/2.0) <= 1.0e-4) - { - dzdph[0] = 1.0; - dzdph[1] = 0.0; - dzdph[2] = 0.0; - dzdth[0] = 0.0; - dzdth[1] = 1.0; - dzdth[2] = 0.0; - } - else if (fabs(theta+M_PI/2.0) <= 1.0e-4) - { - dzdph[0] = 1.0; - dzdph[1] = 0.0; - dzdph[2] = 0.0; - dzdth[0] = 0.0; - dzdth[1] = -1.0; - dzdth[2] = 0.0; - } - else - { - dzdph[0] = (dydph[0]*y02py12-y0*ty0dy0dphpy1dy1dph)*iy02py122; - dzdph[1] = (dydph[1]*y02py12-y1*ty0dy0dphpy1dy1dph)*iy02py122; - dzdph[2] = -dydph[2]; - dzdth[0] = (dydth[0]*y02py12-y0*ty0dy0dthpy1dy1dth)*iy02py122; - dzdth[1] = (dydth[1]*y02py12-y1*ty0dy0dthpy1dy1dth)*iy02py122; - dzdth[2] = -dydth[2]; - } - - /* The same formulas written out in full glory: - z[0] = y[0]/(ipow(y[0],2)+ipow(y[1],2)); - z[1] = y[1]/(ipow(y[0],2)+ipow(y[1],2)); - z[2] = -y[2]; - dzdph[0] = ((dydph[0]*(ipow(y[0],2)+ipow(y[1],2))- - 2.0*y[0]*(y[0]*dydph[0]+y[1]*dydph[1]))/ - ipow(ipow(y[0],2)+ipow(y[1],2),2)); - dzdph[1] = ((dydph[1]*(ipow(y[0],2)+ipow(y[1],2))- - 2.0*y[1]*(y[0]*dydph[0]+y[1]*dydph[1]))/ - ipow(ipow(y[0],2)+ipow(y[1],2),2)); - dzdph[2] = -dydph[2]; - dzdth[0] = ((dydth[0]*(ipow(y[0],2)+ipow(y[1],2))- - 2.0*y[0]*(y[0]*dydth[0]+y[1]*dydth[1]))/ - ipow(ipow(y[0],2)+ipow(y[1],2),2)); - dzdth[1] = ((dydth[1]*(ipow(y[0],2)+ipow(y[1],2))- - 2.0*y[1]*(y[0]*dydth[0]+y[1]*dydth[1]))/ - ipow(ipow(y[0],2)+ipow(y[1],2),2)); - dzdth[2] = -dydth[2]; - */ - } -} - - -/* Compute a point p and its surface normal n in the Bednorz sphere - eversion based on the sphere parameters phi (longitude) and theta - (latitude) and the shape parameters bsp. */ -static void inline bednorz_point_normal(double phi, double theta, - bednorz_shape_par *bsp, - float p[3], float n[3]) -{ - double z[3], dzdph[3], dzdth[3]; - float a[3], b[3], t; - float lambda, eps, oz; - int i; - - bednorz_get_p2(phi,theta,bsp,z,dzdph,dzdth); - - for (i=0; i<3; i++) - { - p[i] = z[i]; - a[i] = dzdph[i]; - b[i] = dzdth[i]; - } - - /* In the original version of the Bednorz sphere eversion, the regions - around the north and south poles of the sphere are deformed to points - that lie very close to each other. This leads to a significant amount - of z fighting, especially for higher eversion orders, which is visually - unpleasant. Therefore, we modify the shape of the deformed sphere very - slightly to avoid or at least ameliorate the z fighting. */ - lambda = bsp->lambda; - eps = bsp->eps; - if (lambda == 1.0) - oz = eps*sin(theta); - else - oz = 0.0f; - p[2] += oz; - - cross(a,b,n); - 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; -} - - -/* Set up the surface colors for the main pass (i.e., index 0). */ -static void setup_surface_colors(ModeInfo *mi, float phi_min, float phi_max, - float theta_min, float theta_max, - int num_phi, int num_theta) -{ - int i, j, o; - float matc[3][3]; - float phi, theta, phi_range, theta_range; - sphereeversionstruct *se = &sphereeversion[MI_SCREEN(mi)]; - - if (se->colors[0] != COLORS_TWOSIDED) - { - /* Compute the rotation that rotates the color basis vectors. */ - for (i=0; i<3; i++) - for (j=0; j<3; j++) - matc[i][j] = (i==j); - rotatez(matc,-26.565051177078015); - rotatey(matc,-335.90515744788928); - rotatex(matc,-50.768479516407787); - - phi_range = phi_max-phi_min; - theta_range = theta_max-theta_min; - for (j=0; j<=num_phi; j++) - { - phi = phi_range*j/num_phi+phi_min; - for (i=0; i<=num_theta; i++) - { - o = j*(num_theta+1)+i; - theta = theta_range*i/num_theta+theta_min; - if (se->colors[0] == COLORS_PARALLEL) - color(se,(2.0f*theta+M_PI)*(2.0f/3.0f),matc,&se->colf[0][4*o], - &se->colb[0][4*o]); - else /* se->colors[0] == COLORS_MERIDIAN */ - color(se,phi+M_PI,matc,&se->colf[0][4*o],&se->colb[0][4*o]); - } - } - } -#ifdef VERTEXATTRIBARRAY_WORKAROUND - else /* se->colors[0] == COLORS_TWOSIDED */ - { - /* For some strange reason, the color buffer must be initialized - and used on macOS. Otherwise two-sided lighting will not - work. */ - int k; - for (j=0; j<=num_phi; j++) - { - for (i=0; i<=num_theta; i++) - { - o = j*(num_theta+1)+i; - for (k=0; k<4; k++) - { - se->colf[0][4*o+k] = 1.0f; - se->colb[0][4*o+k] = 1.0f; - } - } - } - } -#endif /* VERTEXATTRIBARRAY_WORKAROUND */ - -#ifdef HAVE_GLSL - if (se->use_shaders) - { - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_colorf_buffer[0]); - glBufferData(GL_ARRAY_BUFFER, - 4*(num_phi+1)*(num_theta+1)*sizeof(GLfloat), - se->colf[0],GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER,0); - - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_colorb_buffer[0]); - glBufferData(GL_ARRAY_BUFFER, - 4*(num_phi+1)*(num_theta+1)*sizeof(GLfloat), - se->colb[0],GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER,0); - } -#endif /* HAVE_GLSL */ -} - - -/* Draw the Bednorz sphere eversion using OpenGL's fixed - functionality. */ -static int bednorz_sphere_eversion_ff(ModeInfo *mi, float phi_min, - float phi_max, float theta_min, - float theta_max, int num_phi, - int num_theta, int numb_dist, - int numb_dir, int num_grid) -{ - 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_front[] = { 1.0, 0.0, 0.0, 1.0 }; - static const GLfloat mat_diff_back[] = { 0.0, 1.0, 0.0, 1.0 }; - static const GLfloat mat_diff_trans_front[] = { 1.0, 0.0, 0.0, 0.7 }; - static const GLfloat mat_diff_trans_back[] = { 0.0, 1.0, 0.0, 0.7 }; - float p[3], n[3], mat[3][3]; - int i, j, k, l, m, o; - int numb_dist_mask, numb_dist_min, numb_dist_max; - int numb_dir_mask, numb_dir_min, numb_dir_max; - float phi, theta, phi_range, theta_range; - float *xx, *xn, *cf, *cb; - float a, b, c, d, e, tau, tau_min, tau_max, r, s; - float x, y, z, zmin, zmax, rmax, scale, offset_z; - bednorz_shape_par bsp; - float qu[4], r1[3][3], r2[3][3]; - sphereeversionstruct *se = &sphereeversion[MI_SCREEN(mi)]; - int polys; - - tau = se->tau; - /* Apply easing functions to the different ranges of tau. */ - if (fabsf(tau) <= BEDNORZ_TAU4) - { - if (fabsf(tau) <= BEDNORZ_TAU1) - { - tau_min = 0.0f; - tau_max = BEDNORZ_TAU1; - } - else - if (fabsf(tau) <= BEDNORZ_TAU2) - { - tau_min = BEDNORZ_TAU1; - tau_max = BEDNORZ_TAU2; - } - else if (fabsf(tau) <= BEDNORZ_TAU3) - { - tau_min = BEDNORZ_TAU2; - tau_max = BEDNORZ_TAU3; - } - else /* fabsf(tau) <= BEDNORZ_TAU4 */ - { - tau_min = BEDNORZ_TAU3; - tau_max = BEDNORZ_TAU4; - } - e = 1.0f/(tau_min*tau_min-2.0f*tau_min*tau_max+tau_max*tau_max); - a = -2.0f*e; - b = 3.0f*(tau_min+tau_max)*e; - c = -6.0f*tau_min*tau_max*e; - d = tau_min*tau_max*(tau_min+tau_max)*e; - if (tau >= 0.0f) - tau = ((a*tau+b)*tau+c)*tau+d; - else - tau = ((a*tau-b)*tau+c)*tau-d; - } - /* Set up the shape parameters. */ - bsp.n = se->g; - bsp.kappa = bednorz_get_kappa(bsp.n); - bsp.omega = BEDNORZ_OMEGA; - bsp.t = bednorz_get_t(tau); - bsp.p = bednorz_get_p(tau); - bsp.q = bednorz_get_q(tau); - bsp.xi = bednorz_get_xi(tau); - bsp.eta = bednorz_get_eta(tau,se->eta_min); - bsp.alpha = bednorz_get_alpha(tau); - bsp.beta = bednorz_get_beta(tau,se->beta_max); - bsp.gamma = bednorz_get_gamma(bsp.alpha,bsp.beta); - bsp.lambda = bednorz_get_lambda(tau); - bsp.eps = bednorz_get_eps(tau,bsp.n); - - /* Compute the surface points and normals. */ - phi_range = phi_max-phi_min; - theta_range = theta_max-theta_min; - for (j=0; j<=num_phi; j++) - { - phi = phi_range*j/num_phi+phi_min; - for (i=0; i<=num_theta; i++) - { - o = j*(num_theta+1)+i; - theta = theta_range*i/num_theta+theta_min; - bednorz_point_normal(phi,theta,&bsp,&se->se[3*o],&se->sen[3*o]); - } - } - - /* Compute the z offset. */ - zmin = FLT_MAX; - zmax = -FLT_MAX; - for (j=0; j<=num_phi; j++) - { - for (i=0; i<=num_theta; i++) - { - o = j*(num_theta+1)+i; - z = se->se[3*o+2]; - if (z < zmin) - zmin = z; - if (z > zmax) - zmax = z; - } - } - offset_z = -0.5f*(zmin+zmax); - - /* Shift the surface in the z direction and compute the scale. */ - rmax = -FLT_MAX; - for (j=0; j<=num_phi; j++) - { - for (i=0; i<=num_theta; i++) - { - o = j*(num_theta+1)+i; - se->se[3*o+2] += offset_z; - x = se->se[3*o]; - y = se->se[3*o+1]; - z = se->se[3*o+2]; - r = x*x+y*y+z*z; - if (r > rmax) - rmax = r; - } - } - scale = 0.75f/sqrtf(rmax); - - /* Scale the surface. */ - for (j=0; j<=num_phi; j++) - { - for (i=0; i<=num_theta; i++) - { - o = j*(num_theta+1)+i; - se->se[3*o] *= scale; - se->se[3*o+1] *= scale; - se->se[3*o+2] *= scale; - } - } - - /* Compute the rotation that rotates the surface in 3D, including the - trackball rotations. */ - rotateall(se->alpha,se->beta,se->delta,r1); - - gltrackball_get_quaternion(se->trackball,qu); - quat_to_rotmat(qu,r2); - - mult_rotmat(r2,r1,mat); - - numb_dist_mask = numb_dist-1; - numb_dist_min = numb_dist/4; - numb_dist_max = 3*numb_dist/4; - numb_dir_mask = numb_dir-1; - numb_dir_min = numb_dir/4; - numb_dir_max = 3*numb_dir/4; - - glClearColor(0.0f,0.0f,0.0f,1.0f); - glClearDepth(1.0f); - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (se->projection == DISP_PERSPECTIVE) - { - gluPerspective(60.0,se->aspect,0.1,10.0); - } - else - { - if (se->aspect >= 1.0) - glOrtho(-se->aspect,se->aspect,-1.0,1.0,0.1,10.0); - else - glOrtho(-1.0,1.0,-1.0/se->aspect,1.0/se->aspect,0.1,10.0); - } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - if (se->display_mode[0] == DISP_SURFACE) - { - glDisable(GL_CULL_FACE); - 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 /* se->display_mode[0] == DISP_TRANSPARENT */ - { - glDisable(GL_CULL_FACE); - 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); - } - - if (se->colors[0] == COLORS_TWOSIDED) - { - glColor3fv(mat_diff_front); - if (se->display_mode[0] == DISP_TRANSPARENT) - { - glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_front); - glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_back); - } - else - { - glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_front); - glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_back); - } - } - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(1.0f,1.0f); - - if (se->appearance[0] == APPEARANCE_PARALLEL_BANDS) - { - for (i=0; i<num_theta; i++) - { - if (((i & numb_dist_mask) >= numb_dist_min) && - ((i & numb_dist_mask) < numb_dist_max)) - continue; - glBegin(GL_TRIANGLE_STRIP); - for (j=num_phi; j>=0; j--) - { - for (k=0; k<=1; k++) - { - l = i+k; - m = j; - o = m*(num_theta+1)+l; - phi = phi_range*m/num_phi+phi_min; - theta = theta_range*l/num_theta+theta_min; - xx = &se->se[3*o]; - xn = &se->sen[3*o]; - for (l=0; l<3; l++) - { - r = 0.0f; - s = 0.0f; - for (m=0; m<3; m++) - { - r += mat[l][m]*xx[m]; - s += mat[l][m]*xn[m]; - } - p[l] = r+se->offset3d[l]; - n[l] = s; - } - if (se->colors[0] != COLORS_TWOSIDED) - { - cf = &se->colf[0][4*o]; - cb = &se->colb[0][4*o]; - glColor3fv(cf); - glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,cf); - glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,cb); - } - glNormal3fv(n); - glVertex3fv(p); - } - } - glEnd(); - } - polys = num_theta*(num_phi+1); - } - else /* se->appearance[0] != APPEARANCE_PARALLEL_BANDS */ - { - for (j=0; j<num_phi; j++) - { - if (se->appearance[0] == APPEARANCE_MERIDIAN_BANDS && - ((j & numb_dir_mask) >= numb_dir_min) && - ((j & numb_dir_mask) < numb_dir_max)) - continue; - glBegin(GL_TRIANGLE_STRIP); - for (i=0; i<=num_theta; i++) - { - for (k=0; k<=1; k++) - { - l = i; - m = j+k; - o = m*(num_theta+1)+l; - phi = phi_range*m/num_phi+phi_min; - theta = theta_range*l/num_theta+theta_min; - xx = &se->se[3*o]; - xn = &se->sen[3*o]; - for (l=0; l<3; l++) - { - r = 0.0f; - s = 0.0f; - for (m=0; m<3; m++) - { - r += mat[l][m]*xx[m]; - s += mat[l][m]*xn[m]; - } - p[l] = r+se->offset3d[l]; - n[l] = s; - } - if (se->colors[0] != COLORS_TWOSIDED) - { - cf = &se->colf[0][4*o]; - cb = &se->colb[0][4*o]; - glColor3fv(cf); - glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,cf); - glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,cb); - } - glNormal3fv(n); - glVertex3fv(p); - } - } - glEnd(); - } - polys = 2*num_phi*(num_theta+1); - if (se->appearance[0] == APPEARANCE_MERIDIAN_BANDS) - polys /= 2; - } - - glDisable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(0.0f,0.0f); - if (se->graticule[0]) - { - glColor4f(1.0f,1.0f,1.0f,1.0f); - glLineWidth(2.0f); - glEnable(GL_LINE_SMOOTH); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_LIGHTING); - glDisable(GL_LIGHT0); - glEnable(GL_BLEND); - glHint(GL_LINE_SMOOTH_HINT,GL_DONT_CARE); - /* Draw meridians. */ - for (j=0; j<num_phi; j+=num_grid) - { - glBegin(GL_LINE_STRIP); - for (i=0; i<=num_theta; i++) - { - o = j*(num_theta+1)+i; - phi = phi_range*j/num_phi+phi_min; - theta = theta_range*i/num_theta+theta_min; - xx = &se->se[3*o]; - for (l=0; l<3; l++) - { - r = 0.0f; - for (m=0; m<3; m++) - r += mat[l][m]*xx[m]; - p[l] = r+se->offset3d[l]; - } - glVertex3fv(p); - } - glEnd(); - } - /* Draw parallels. */ - for (i=num_grid; i<=num_theta-num_grid; i+=num_grid) - { - glBegin(GL_LINE_LOOP); - for (j=num_phi-1; j>=0; j--) - { - o = j*(num_theta+1)+i; - phi = phi_range*j/num_phi+phi_min; - theta = theta_range*i/num_theta+theta_min; - xx = &se->se[3*o]; - for (l=0; l<3; l++) - { - r = 0.0f; - for (m=0; m<3; m++) - r += mat[l][m]*xx[m]; - p[l] = r+se->offset3d[l]; - } - glVertex3fv(p); - } - glEnd(); - } - glLineWidth(1.0f); - glPolygonOffset(0.0f,0.0f); - glDisable(GL_LINE_SMOOTH); - glBlendFunc(GL_SRC_ALPHA,GL_ONE); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - if (se->display_mode[0] != DISP_TRANSPARENT) - glDisable(GL_BLEND); - } - - return polys; -} - - -#ifdef HAVE_GLSL - -/* Draw the Bednorz sphere eversion using OpenGL's programmable - functionality. */ -static int bednorz_sphere_eversion_pf(ModeInfo *mi, float phi_min, - float phi_max, float theta_min, - float theta_max, int num_phi, - int num_theta, int numb_dist, - int numb_dir, int num_grid) -{ - 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_front[] = { 1.0, 0.0, 0.0, 1.0 }; - static const GLfloat mat_diff_back[] = { 0.0, 1.0, 0.0, 1.0 }; - static const GLfloat mat_diff_trans_front[] = { 1.0, 0.0, 0.0, 0.7 }; - static const GLfloat mat_diff_trans_back[] = { 0.0, 1.0, 0.0, 0.7 }; - static const GLfloat mat_diff_white[] = { 1.0, 1.0, 1.0, 1.0 }; - static const GLuint blend_indices[6] = { 0, 1, 2, 2, 3, 0 }; - static const GLfloat blend_p[4][2] = - { { -1.0, -1.0 }, { 1.0, -1.0 }, { 1.0, 1.0 }, { -1.0, 1.0 } }; - static const GLfloat blend_t[4][2] = - { { 0.0, 0.0 }, { 1.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 1.0 } }; - GLfloat light_direction[3], half_vector[3], len; - GLfloat p_mat[16], mv_mat[16], rot_mat[16]; - float mat[3][3]; - int i, j, k, l, m, o, pass, num_passes, ni; - int numb_dist_mask, numb_dist_min, numb_dist_max; - int numb_dir_mask, numb_dir_min, numb_dir_max; - float phi, theta, phi_range, theta_range; - float a, b, c, d, e, tau, tau_min, tau_max, r, t; - float x, y, z, zmin, zmax, rmax, scale, offset_z; - bednorz_shape_par bsp; - float qu[4], r1[3][3], r2[3][3]; - GLint draw_buf, read_buf; - GLsizeiptr index_offset; - sphereeversionstruct *se = &sphereeversion[MI_SCREEN(mi)]; - int polys = 0; - - if (!se->use_shaders) - return 0; - - numb_dist_mask = numb_dist-1; - numb_dist_min = numb_dist/4; - numb_dist_max = 3*numb_dist/4; - numb_dir_mask = numb_dir-1; - numb_dir_min = numb_dir/4; - numb_dir_max = 3*numb_dir/4; - - if (!se->buffers_initialized) - { - /* The indices only need to be computed once. */ - /* Compute the solid indices. */ - ni = 0; - se->num_solid_strips = 0; - se->num_solid_triangles = 0; - for (j=0; j<num_phi; j++) - { - for (i=0; i<=num_theta; i++) - { - for (k=0; k<=1; k++) - { - l = i; - m = j+k; - o = m*(num_theta+1)+l; - se->solid_indices[ni++] = o; - } - } - se->num_solid_strips++; - } - se->num_solid_triangles = 2*(num_theta+1); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,se->solid_indices_buffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER,ni*sizeof(GLuint), - se->solid_indices,GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); - - /* Compute the meridian indices. */ - ni = 0; - se->num_meridian_strips = 0; - se->num_meridian_triangles = 0; - for (j=0; j<num_phi; j++) - { - if (((j & numb_dir_mask) >= numb_dir_min) && - ((j & numb_dir_mask) < numb_dir_max)) - continue; - for (i=0; i<=num_theta; i++) - { - for (k=0; k<=1; k++) - { - l = i; - m = j+k; - o = m*(num_theta+1)+l; - se->meridian_indices[ni++] = o; - } - } - se->num_meridian_strips++; - } - se->num_meridian_triangles = 2*(num_theta+1); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,se->meridian_indices_buffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER,ni*sizeof(GLuint), - se->meridian_indices,GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); - - /* Compute the parallel indices. */ - ni = 0; - se->num_parallel_strips = 0; - se->num_parallel_triangles = 0; - for (i=0; i<num_theta; i++) - { - if (((i & numb_dist_mask) >= numb_dist_min) && - ((i & numb_dist_mask) < numb_dist_max)) - continue; - for (j=num_phi; j>=0; j--) - { - for (k=0; k<=1; k++) - { - l = i+k; - m = j; - o = m*(num_theta+1)+l; - se->parallel_indices[ni++] = o; - } - } - se->num_parallel_strips++; - } - se->num_parallel_triangles = 2*(num_phi+1); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,se->parallel_indices_buffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER,ni*sizeof(GLuint), - se->parallel_indices,GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); - - /* Compute the line indices. */ - ni = 0; - for (j=0; j<num_phi; j+=num_grid) - { - for (i=0; i<num_theta; i++) - { - se->line_indices[ni++] = j*(num_theta+1)+i; - se->line_indices[ni++] = j*(num_theta+1)+i+1; - } - } - for (i=num_grid; i<=num_theta-num_grid; i+=num_grid) - { - for (j=num_phi; j>0; j--) - { - o = j*(num_theta+1)+i; - se->line_indices[ni++] = j*(num_theta+1)+i; - se->line_indices[ni++] = (j-1)*(num_theta+1)+i; - } - } - se->num_lines = ni; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,se->line_indices_buffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER,ni*sizeof(GLuint), - se->line_indices,GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); - - se->buffers_initialized = True; - } - - tau = se->tau; - /* Apply easing functions to the different ranges of tau. */ - if (fabsf(tau) <= BEDNORZ_TAU4) - { - if (fabsf(tau) <= BEDNORZ_TAU1) - { - tau_min = 0.0f; - tau_max = BEDNORZ_TAU1; - } - else - if (fabsf(tau) <= BEDNORZ_TAU2) - { - tau_min = BEDNORZ_TAU1; - tau_max = BEDNORZ_TAU2; - } - else if (fabsf(tau) <= BEDNORZ_TAU3) - { - tau_min = BEDNORZ_TAU2; - tau_max = BEDNORZ_TAU3; - } - else /* fabsf(tau) <= BEDNORZ_TAU4 */ - { - tau_min = BEDNORZ_TAU3; - tau_max = BEDNORZ_TAU4; - } - e = 1.0f/(tau_min*tau_min-2.0f*tau_min*tau_max+tau_max*tau_max); - a = -2.0f*e; - b = 3.0f*(tau_min+tau_max)*e; - c = -6.0f*tau_min*tau_max*e; - d = tau_min*tau_max*(tau_min+tau_max)*e; - if (tau >= 0.0f) - tau = ((a*tau+b)*tau+c)*tau+d; - else - tau = ((a*tau-b)*tau+c)*tau-d; - } - /* Set up the shape parameters. */ - bsp.n = se->g; - bsp.kappa = bednorz_get_kappa(bsp.n); - bsp.omega = BEDNORZ_OMEGA; - bsp.t = bednorz_get_t(tau); - bsp.p = bednorz_get_p(tau); - bsp.q = bednorz_get_q(tau); - bsp.xi = bednorz_get_xi(tau); - bsp.eta = bednorz_get_eta(tau,se->eta_min); - bsp.alpha = bednorz_get_alpha(tau); - bsp.beta = bednorz_get_beta(tau,se->beta_max); - bsp.gamma = bednorz_get_gamma(bsp.alpha,bsp.beta); - bsp.lambda = bednorz_get_lambda(tau); - bsp.eps = bednorz_get_eps(tau,bsp.n); - - /* Compute the surface points and normals. */ - phi_range = phi_max-phi_min; - theta_range = theta_max-theta_min; - for (j=0; j<=num_phi; j++) - { - phi = phi_range*j/num_phi+phi_min; - for (i=0; i<=num_theta; i++) - { - o = j*(num_theta+1)+i; - theta = theta_range*i/num_theta+theta_min; - bednorz_point_normal(phi,theta,&bsp,&se->se[3*o],&se->sen[3*o]); - } - } - - /* Compute the z offset. */ - zmin = FLT_MAX; - zmax = -FLT_MAX; - for (j=0; j<=num_phi; j++) - { - for (i=0; i<=num_theta; i++) - { - o = j*(num_theta+1)+i; - z = se->se[3*o+2]; - if (z < zmin) - zmin = z; - if (z > zmax) - zmax = z; - } - } - offset_z = -0.5f*(zmin+zmax); - - /* Shift the surface in the z direction and compute the scale. */ - rmax = -FLT_MAX; - for (j=0; j<=num_phi; j++) - { - for (i=0; i<=num_theta; i++) - { - o = j*(num_theta+1)+i; - se->se[3*o+2] += offset_z; - x = se->se[3*o]; - y = se->se[3*o+1]; - z = se->se[3*o+2]; - r = x*x+y*y+z*z; - if (r > rmax) - rmax = r; - } - } - scale = 0.75f/sqrtf(rmax); - - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_pos_buffer); - glBufferData(GL_ARRAY_BUFFER,3*(num_phi+1)*(num_theta+1)*sizeof(GLfloat), - se->se,GL_STREAM_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); - - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_normal_buffer); - glBufferData(GL_ARRAY_BUFFER,3*(num_phi+1)*(num_theta+1)*sizeof(GLfloat), - se->sen,GL_STREAM_DRAW); - glBindBuffer(GL_ARRAY_BUFFER,0); - - /* Compute the rotation that rotates the surface in 3D, including the - trackball rotations. */ - rotateall(se->alpha,se->beta,se->delta,r1); - - gltrackball_get_quaternion(se->trackball,qu); - quat_to_rotmat(qu,r2); - - mult_rotmat(r2,r1,mat); - - glsl_Identity(p_mat); - if (se->projection == DISP_PERSPECTIVE) - { - glsl_Perspective(p_mat,60.0f,se->aspect,0.1f,10.0f); - } - else - { - if (se->aspect >= 1.0) - glsl_Orthographic(p_mat,-se->aspect,se->aspect,-1.0f,1.0f, - 0.1f,10.0f); - else - glsl_Orthographic(p_mat,-1.0f,1.0f,-1.0f/se->aspect,1.0f/se->aspect, - 0.1f,10.0f); - } - 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,se->offset3d[0],se->offset3d[1],se->offset3d[2]); - glsl_Scale(mv_mat,scale,scale,scale); - glsl_MultMatrix(mv_mat,rot_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; - - num_passes = se->anim_state == ANIM_TURN ? 2 : 1; - - for (pass=0; pass<num_passes; pass++) - { - glUseProgram(se->poly_shader_program); - - glClearColor(0.0f,0.0f,0.0f,1.0f); - glClearDepth(1.0f); - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - - glUniformMatrix4fv(se->poly_mv_index,1,GL_FALSE,mv_mat); - glUniformMatrix4fv(se->poly_proj_index,1,GL_FALSE,p_mat); - - glUniform4fv(se->poly_front_ambient_index,1,mat_diff_white); - glUniform4fv(se->poly_front_diffuse_index,1,mat_diff_white); - glUniform4fv(se->poly_back_ambient_index,1,mat_diff_white); - glUniform4fv(se->poly_back_diffuse_index,1,mat_diff_white); - glVertexAttrib4f(se->poly_colorf_index,1.0f,1.0f,1.0f,1.0f); - glVertexAttrib4f(se->poly_colorb_index,1.0f,1.0f,1.0f,1.0f); - - if (se->display_mode[pass] == DISP_SURFACE) - { - glDisable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glDepthMask(GL_TRUE); - glDisable(GL_BLEND); - glUniform4fv(se->poly_glbl_ambient_index,1,light_model_ambient); - glUniform4fv(se->poly_lt_ambient_index,1,light_ambient); - glUniform4fv(se->poly_lt_diffuse_index,1,light_diffuse); - glUniform4fv(se->poly_lt_specular_index,1,light_specular); - glUniform3fv(se->poly_lt_direction_index,1,light_direction); - glUniform3fv(se->poly_lt_halfvect_index,1,half_vector); - glUniform4fv(se->poly_specular_index,1,mat_specular); - glUniform1f(se->poly_shininess_index,50.0f); - } - else /* se->display_mode[pass] == DISP_TRANSPARENT */ - { - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA,GL_ONE); - glUniform4fv(se->poly_glbl_ambient_index,1,light_model_ambient); - glUniform4fv(se->poly_lt_ambient_index,1,light_ambient); - glUniform4fv(se->poly_lt_diffuse_index,1,light_diffuse); - glUniform4fv(se->poly_lt_specular_index,1,light_specular); - glUniform3fv(se->poly_lt_direction_index,1,light_direction); - glUniform3fv(se->poly_lt_halfvect_index,1,half_vector); - glUniform4fv(se->poly_specular_index,1,mat_specular); - glUniform1f(se->poly_shininess_index,50.0f); - } - - if (se->colors[pass] == COLORS_TWOSIDED) - { - if (se->display_mode[pass] == DISP_TRANSPARENT) - { - glUniform4fv(se->poly_front_ambient_index,1,mat_diff_trans_front); - glUniform4fv(se->poly_front_diffuse_index,1,mat_diff_trans_front); - glUniform4fv(se->poly_back_ambient_index,1,mat_diff_trans_back); - glUniform4fv(se->poly_back_diffuse_index,1,mat_diff_trans_back); - } - else - { - glUniform4fv(se->poly_front_ambient_index,1,mat_diff_front); - glUniform4fv(se->poly_front_diffuse_index,1,mat_diff_front); - glUniform4fv(se->poly_back_ambient_index,1,mat_diff_back); - glUniform4fv(se->poly_back_diffuse_index,1,mat_diff_back); - } - } - - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(1.0f,1.0f); - - glEnableVertexAttribArray(se->poly_pos_index); - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_pos_buffer); - glVertexAttribPointer(se->poly_pos_index,3,GL_FLOAT,GL_FALSE,0,0); - - glEnableVertexAttribArray(se->poly_normal_index); - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_normal_buffer); - glVertexAttribPointer(se->poly_normal_index,3,GL_FLOAT,GL_FALSE,0,0); - - if (se->colors[pass] != COLORS_TWOSIDED) - { - glEnableVertexAttribArray(se->poly_colorf_index); - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_colorf_buffer[pass]); - glVertexAttribPointer(se->poly_colorf_index,4,GL_FLOAT,GL_FALSE,0,0); - - glEnableVertexAttribArray(se->poly_colorb_index); - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_colorb_buffer[pass]); - glVertexAttribPointer(se->poly_colorb_index,4,GL_FLOAT,GL_FALSE,0,0); - } -#ifdef VERTEXATTRIBARRAY_WORKAROUND - else /* se->colors[pass] == COLORS_TWOSIDED */ - { - glEnableVertexAttribArray(se->poly_colorf_index); - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_colorf_buffer[pass]); - glVertexAttribPointer(se->poly_colorf_index,4,GL_FLOAT,GL_FALSE,0,0); - - glEnableVertexAttribArray(se->poly_colorb_index); - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_colorb_buffer[pass]); - glVertexAttribPointer(se->poly_colorb_index,4,GL_FLOAT,GL_FALSE,0,0); - } -#endif /* VERTEXATTRIBARRAY_WORKAROUND */ - - if (se->appearance[pass] == APPEARANCE_SOLID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,se->solid_indices_buffer); - for (i=0; i<se->num_solid_strips; i++) - { - index_offset = se->num_solid_triangles*i*sizeof(GLuint); - glDrawElements(GL_TRIANGLE_STRIP,se->num_solid_triangles, - GL_UNSIGNED_INT,(const GLvoid *)index_offset); - } - polys += 2*num_phi*(num_theta+1); - } - else if (se->appearance[pass] == APPEARANCE_PARALLEL_BANDS) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,se->parallel_indices_buffer); - for (i=0; i<se->num_parallel_strips; i++) - { - index_offset = se->num_parallel_triangles*i*sizeof(GLuint); - glDrawElements(GL_TRIANGLE_STRIP,se->num_parallel_triangles, - GL_UNSIGNED_INT,(const GLvoid *)index_offset); - } - polys += num_theta*(num_phi+1); - } - else /* se->appearance[pass] == APPEARANCE_MERIDIAN_BANDS */ - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,se->meridian_indices_buffer); - for (i=0; i<se->num_meridian_strips; i++) - { - index_offset = se->num_meridian_triangles*i*sizeof(GLuint); - glDrawElements(GL_TRIANGLE_STRIP,se->num_meridian_triangles, - GL_UNSIGNED_INT,(const GLvoid *)index_offset); - } - polys += num_phi*(num_theta+1); - } - - glDisableVertexAttribArray(se->poly_pos_index); - glDisableVertexAttribArray(se->poly_normal_index); - if (se->colors[pass] != COLORS_TWOSIDED) - { - glDisableVertexAttribArray(se->poly_colorf_index); - glDisableVertexAttribArray(se->poly_colorb_index); - } -#ifdef VERTEXATTRIBARRAY_WORKAROUND - else /* se->colors[pass] != COLORS_TWOSIDED */ - { - glDisableVertexAttribArray(se->poly_colorf_index); - glDisableVertexAttribArray(se->poly_colorb_index); - } -#endif /* VERTEXATTRIBARRAY_WORKAROUND */ - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); - - glDisable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(0.0f,0.0f); - - glUseProgram(0); - - if (se->graticule[pass]) - { - glUseProgram(se->line_shader_program); - - glUniformMatrix4fv(se->line_mv_index,1,GL_FALSE,mv_mat); - glUniformMatrix4fv(se->line_proj_index,1,GL_FALSE,p_mat); - glUniform4f(se->line_color_index,1.0f,1.0f,1.0f,1.0f); - - glLineWidth(2.0f); - - glEnableVertexAttribArray(se->line_pos_index); - glBindBuffer(GL_ARRAY_BUFFER,se->vertex_pos_buffer); - glVertexAttribPointer(se->line_pos_index,3,GL_FLOAT,GL_FALSE,0,0); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,se->line_indices_buffer); - - index_offset = 0; - glDrawElements(GL_LINES,se->num_lines,GL_UNSIGNED_INT, - (const void *)index_offset); - - glDisableVertexAttribArray(se->line_pos_index); - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); - - glUseProgram(0); - } - - if (num_passes == 2) - { - /* Copy the rendered image to a texture. */ - glGetIntegerv(GL_DRAW_BUFFER0,&draw_buf); - glGetIntegerv(GL_READ_BUFFER,&read_buf); - glReadBuffer(draw_buf); - glBindTexture(GL_TEXTURE_2D,se->color_textures[pass]); - glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,se->WindW,se->WindH); - glReadBuffer(read_buf); - } - } - - if (num_passes == 2) - { - t = (float)se->turn_step/(float)se->num_turn; - /* Apply an easing function to t. */ - t = (3.0-2.0*t)*t*t; - - glUseProgram(se->blend_shader_program); - - glClearColor(0.0f,0.0f,0.0f,1.0f); - glClearDepth(1.0f); - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - glDisable(GL_BLEND); - - glUniform1f(se->blend_t_index,t); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D,se->color_textures[0]); - glUniform1i(se->blend_sampler0_index,0); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D,se->color_textures[1]); - glUniform1i(se->blend_sampler1_index,1); - - glEnableVertexAttribArray(se->blend_vertex_p_index); - glVertexAttribPointer(se->blend_vertex_p_index,2,GL_FLOAT,GL_FALSE, - 2*sizeof(GLfloat),blend_p); - - glEnableVertexAttribArray(se->blend_vertex_t_index); - glVertexAttribPointer(se->blend_vertex_t_index,2,GL_FLOAT,GL_FALSE, - 2*sizeof(GLfloat),blend_t); - - glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,blend_indices); - - glActiveTexture(GL_TEXTURE0); - - glUseProgram(0); - } - - return polys; -} - - -static void init_glsl(ModeInfo *mi) -{ - sphereeversionstruct *se = &sphereeversion[MI_SCREEN(mi)]; - GLint gl_major, gl_minor, glsl_major, glsl_minor; - GLboolean gl_gles3; - int i, wt, ht; - const GLchar *poly_vertex_shader_source[3]; - const GLchar *poly_fragment_shader_source[4]; - const GLchar *line_vertex_shader_source[3]; - const GLchar *line_fragment_shader_source[4]; - const GLchar *blend_vertex_shader_source[3]; - const GLchar *blend_fragment_shader_source[4]; - - se->solid_indices = calloc(2*NUMPH*(NUMTH+1),sizeof(float)); - se->parallel_indices = calloc(NUMPH*(NUMTH+1),sizeof(float)); - se->meridian_indices = calloc((NUMPH+1)*NUMTH,sizeof(float)); - se->line_indices = calloc(4*NUMPH*NUMTH/NUMGRID,sizeof(float)); - - /* Determine whether to use shaders to render the sphere eversion. */ - se->use_shaders = False; - se->buffers_initialized = False; - se->poly_shader_program = 0; - se->line_shader_program = 0; - se->blend_shader_program = 0; - se->max_tex_size = -1; - - 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. */ - poly_vertex_shader_source[0] = shader_version_2_1; - poly_vertex_shader_source[1] = poly_vertex_shader_attribs_2_1; - poly_vertex_shader_source[2] = poly_vertex_shader_main; - poly_fragment_shader_source[0] = shader_version_2_1; - poly_fragment_shader_source[1] = poly_fragment_shader_attribs_2_1; - poly_fragment_shader_source[2] = poly_fragment_shader_main; - poly_fragment_shader_source[3] = poly_fragment_shader_out_2_1; - - line_vertex_shader_source[0] = shader_version_2_1; - line_vertex_shader_source[1] = line_vertex_shader_attribs_2_1; - line_vertex_shader_source[2] = line_vertex_shader_main; - line_fragment_shader_source[0] = shader_version_2_1; - line_fragment_shader_source[1] = line_fragment_shader_attribs_2_1; - line_fragment_shader_source[2] = line_fragment_shader_main; - line_fragment_shader_source[3] = line_fragment_shader_out_2_1; - - blend_vertex_shader_source[0] = shader_version_2_1; - blend_vertex_shader_source[1] = blend_vertex_shader_attribs_2_1; - blend_vertex_shader_source[2] = blend_vertex_shader_main; - blend_fragment_shader_source[0] = shader_version_2_1; - blend_fragment_shader_source[1] = blend_fragment_shader_attribs_2_1; - blend_fragment_shader_source[2] = blend_fragment_shader_main; - blend_fragment_shader_source[3] = blend_fragment_shader_out_2_1; - } - else - { - /* We have at least OpenGL 3.0 and at least GLSL 1.30. */ - poly_vertex_shader_source[0] = shader_version_3_0; - poly_vertex_shader_source[1] = poly_vertex_shader_attribs_3_0; - poly_vertex_shader_source[2] = poly_vertex_shader_main; - poly_fragment_shader_source[0] = shader_version_3_0; - poly_fragment_shader_source[1] = poly_fragment_shader_attribs_3_0; - poly_fragment_shader_source[2] = poly_fragment_shader_main; - poly_fragment_shader_source[3] = poly_fragment_shader_out_3_0; - - line_vertex_shader_source[0] = shader_version_3_0; - line_vertex_shader_source[1] = line_vertex_shader_attribs_3_0; - line_vertex_shader_source[2] = line_vertex_shader_main; - line_fragment_shader_source[0] = shader_version_3_0; - line_fragment_shader_source[1] = line_fragment_shader_attribs_3_0; - line_fragment_shader_source[2] = line_fragment_shader_main; - line_fragment_shader_source[3] = line_fragment_shader_out_3_0; - - blend_vertex_shader_source[0] = shader_version_3_0; - blend_vertex_shader_source[1] = blend_vertex_shader_attribs_3_0; - blend_vertex_shader_source[2] = blend_vertex_shader_main; - blend_fragment_shader_source[0] = shader_version_3_0; - blend_fragment_shader_source[1] = blend_fragment_shader_attribs_3_0; - blend_fragment_shader_source[2] = blend_fragment_shader_main; - blend_fragment_shader_source[3] = blend_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. */ - poly_vertex_shader_source[0] = shader_version_3_0_es; - poly_vertex_shader_source[1] = poly_vertex_shader_attribs_3_0; - poly_vertex_shader_source[2] = poly_vertex_shader_main; - poly_fragment_shader_source[0] = shader_version_3_0_es; - poly_fragment_shader_source[1] = poly_fragment_shader_attribs_3_0; - poly_fragment_shader_source[2] = poly_fragment_shader_main; - poly_fragment_shader_source[3] = poly_fragment_shader_out_3_0; - - line_vertex_shader_source[0] = shader_version_3_0_es; - line_vertex_shader_source[1] = line_vertex_shader_attribs_3_0; - line_vertex_shader_source[2] = line_vertex_shader_main; - line_fragment_shader_source[0] = shader_version_3_0_es; - line_fragment_shader_source[1] = line_fragment_shader_attribs_3_0; - line_fragment_shader_source[2] = line_fragment_shader_main; - line_fragment_shader_source[3] = line_fragment_shader_out_3_0; - - blend_vertex_shader_source[0] = shader_version_3_0_es; - blend_vertex_shader_source[1] = blend_vertex_shader_attribs_3_0; - blend_vertex_shader_source[2] = blend_vertex_shader_main; - blend_fragment_shader_source[0] = shader_version_3_0_es; - blend_fragment_shader_source[1] = blend_fragment_shader_attribs_3_0; - blend_fragment_shader_source[2] = blend_fragment_shader_main; - blend_fragment_shader_source[3] = blend_fragment_shader_out_3_0; - } - - if (!glsl_CompileAndLinkShaders(3,poly_vertex_shader_source, - 4,poly_fragment_shader_source, - &se->poly_shader_program)) - return; - se->poly_pos_index = glGetAttribLocation(se->poly_shader_program, - "VertexPosition"); - se->poly_normal_index = glGetAttribLocation(se->poly_shader_program, - "VertexNormal"); - se->poly_colorf_index = glGetAttribLocation(se->poly_shader_program, - "VertexColorF"); - se->poly_colorb_index = glGetAttribLocation(se->poly_shader_program, - "VertexColorB"); - se->poly_mv_index = glGetUniformLocation(se->poly_shader_program, - "MatModelView"); - se->poly_proj_index = glGetUniformLocation(se->poly_shader_program, - "MatProj"); - se->poly_glbl_ambient_index = glGetUniformLocation(se->poly_shader_program, - "LtGlblAmbient"); - se->poly_lt_ambient_index = glGetUniformLocation(se->poly_shader_program, - "LtAmbient"); - se->poly_lt_diffuse_index = glGetUniformLocation(se->poly_shader_program, - "LtDiffuse"); - se->poly_lt_specular_index = glGetUniformLocation(se->poly_shader_program, - "LtSpecular"); - se->poly_lt_direction_index = glGetUniformLocation(se->poly_shader_program, - "LtDirection"); - se->poly_lt_halfvect_index = glGetUniformLocation(se->poly_shader_program, - "LtHalfVector"); - se->poly_front_ambient_index = glGetUniformLocation(se->poly_shader_program, - "MatFrontAmbient"); - se->poly_back_ambient_index = glGetUniformLocation(se->poly_shader_program, - "MatBackAmbient"); - se->poly_front_diffuse_index = glGetUniformLocation(se->poly_shader_program, - "MatFrontDiffuse"); - se->poly_back_diffuse_index = glGetUniformLocation(se->poly_shader_program, - "MatBackDiffuse"); - se->poly_specular_index = glGetUniformLocation(se->poly_shader_program, - "MatSpecular"); - se->poly_shininess_index = glGetUniformLocation(se->poly_shader_program, - "MatShininess"); - if (se->poly_pos_index == -1 || - se->poly_normal_index == -1 || - se->poly_colorf_index == -1 || - se->poly_colorb_index == -1 || - se->poly_mv_index == -1 || - se->poly_proj_index == -1 || - se->poly_glbl_ambient_index == -1 || - se->poly_lt_ambient_index == -1 || - se->poly_lt_diffuse_index == -1 || - se->poly_lt_specular_index == -1 || - se->poly_lt_direction_index == -1 || - se->poly_lt_halfvect_index == -1 || - se->poly_front_ambient_index == -1 || - se->poly_back_ambient_index == -1 || - se->poly_front_diffuse_index == -1 || - se->poly_back_diffuse_index == -1 || - se->poly_specular_index == -1 || - se->poly_shininess_index == -1) - { - glDeleteProgram(se->poly_shader_program); - return; - } - - if (!glsl_CompileAndLinkShaders(3,line_vertex_shader_source, - 4,line_fragment_shader_source, - &se->line_shader_program)) - { - glDeleteProgram(se->poly_shader_program); - return; - } - se->line_pos_index = glGetAttribLocation(se->line_shader_program, - "VertexPosition"); - se->line_color_index = glGetUniformLocation(se->line_shader_program, - "LineColor"); - se->line_mv_index = glGetUniformLocation(se->line_shader_program, - "MatModelView"); - se->line_proj_index = glGetUniformLocation(se->line_shader_program, - "MatProj"); - if (se->line_pos_index == -1 || - se->line_color_index == -1 || - se->line_mv_index == -1 || - se->line_proj_index == -1) - { - glDeleteProgram(se->poly_shader_program); - glDeleteProgram(se->line_shader_program); - return; - } - - if (!glsl_CompileAndLinkShaders(3,blend_vertex_shader_source, - 4,blend_fragment_shader_source, - &se->blend_shader_program)) - { - glDeleteProgram(se->poly_shader_program); - glDeleteProgram(se->line_shader_program); - return; - } - se->blend_vertex_p_index = glGetAttribLocation(se->blend_shader_program, - "VertexP"); - se->blend_vertex_t_index = glGetAttribLocation(se->blend_shader_program, - "VertexT"); - se->blend_t_index = glGetUniformLocation(se->blend_shader_program, - "T"); - se->blend_sampler0_index = glGetUniformLocation(se->blend_shader_program, - "TextureSampler0"); - se->blend_sampler1_index = glGetUniformLocation(se->blend_shader_program, - "TextureSampler1"); - if (se->blend_vertex_p_index == -1 || - se->blend_vertex_t_index == -1 || - se->blend_t_index == -1 || - se->blend_sampler0_index == -1 || - se->blend_sampler1_index == -1) - { - glDeleteProgram(se->poly_shader_program); - glDeleteProgram(se->line_shader_program); - glDeleteProgram(se->blend_shader_program); - return; - } - - glGetIntegerv(GL_MAX_TEXTURE_SIZE,&se->max_tex_size); - if (se->WindW <= se->max_tex_size || se->WindH <= se->max_tex_size) - { - wt = se->WindW; - ht = se->WindH; - } - else - { - wt = MIN(se->max_tex_size,se->WindW); - ht = MIN(se->max_tex_size,se->WindH); - } - - glGenTextures(2,se->color_textures); - for (i=0; i<2; i++) - { - glBindTexture(GL_TEXTURE_2D,se->color_textures[i]); - glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,wt,ht,0,GL_RGBA,GL_UNSIGNED_BYTE, - NULL); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); - } - - glGenBuffers(1,&se->vertex_pos_buffer); - glGenBuffers(1,&se->vertex_normal_buffer); - glGenBuffers(2,se->vertex_colorf_buffer); - glGenBuffers(2,se->vertex_colorb_buffer); - glGenBuffers(1,&se->solid_indices_buffer); - glGenBuffers(1,&se->parallel_indices_buffer); - glGenBuffers(1,&se->meridian_indices_buffer); - glGenBuffers(1,&se->line_indices_buffer); - - se->use_shaders = True; -} - -#endif /* HAVE_GLSL */ - - -static void init(ModeInfo *mi) -{ - sphereeversionstruct *se = &sphereeversion[MI_SCREEN(mi)]; - - if (deform_speed == 0.0f) - deform_speed = 10.0f; - - se->alpha = frand(120.0)-60.0; - se->beta = frand(120.0)-60.0; - se->delta = frand(360.0); - - se->eta_min = BEDNORZ_ETA_MIN; - se->beta_max = BEDNORZ_BETA_MAX; - - se->anim_state = ANIM_DEFORM; - se->tau = BEDNORZ_TAU_MAX; - se->defdir = -1; - se->turn_step = 0; - se->num_turn = 0; - - se->offset3d[0] = 0.0f; - se->offset3d[1] = 0.0f; - se->offset3d[2] = -1.8f; - - se->se = calloc(3*(NUMPH+1)*(NUMTH+1),sizeof(float)); - se->sen = calloc(3*(NUMPH+1)*(NUMTH+1),sizeof(float)); - se->colf[0] = calloc(4*(NUMPH+1)*(NUMTH+1),sizeof(float)); - se->colf[1] = calloc(4*(NUMPH+1)*(NUMTH+1),sizeof(float)); - se->colb[0] = calloc(4*(NUMPH+1)*(NUMTH+1),sizeof(float)); - se->colb[1] = calloc(4*(NUMPH+1)*(NUMTH+1),sizeof(float)); - -#ifdef HAVE_GLSL - init_glsl(mi); -#endif /* HAVE_GLSL */ - - setup_surface_colors(mi,-M_PI,M_PI,-M_PI/2.0,M_PI/2.0,NUMPH,NUMTH); -} - - -/* Redisplay the deformed surface. */ -static void display_sphereeversion(ModeInfo *mi) -{ - float alpha, beta, delta, dot, a, t, q[4]; - float *colt; - sphereeversionstruct *se = &sphereeversion[MI_SCREEN(mi)]; -#ifdef HAVE_GLSL - GLuint vertex_colort_buffer; -#endif /* HAVE_GLSL */ - - if (!se->button_pressed) - { - if (se->anim_state == ANIM_DEFORM) - { - se->tau += se->defdir*deform_speed*0.001; - if (se->tau < BEDNORZ_TAU_MIN) - { - se->tau = BEDNORZ_TAU_MIN; - se->defdir = -se->defdir; - se->anim_state = ANIM_TURN; - } - if (se->tau > BEDNORZ_TAU_MAX) - { - se->tau = BEDNORZ_TAU_MAX; - se->defdir = -se->defdir; - se->anim_state = ANIM_TURN; - } - if (se->anim_state == ANIM_TURN) - { - /* Convert the current rotation angles to a quaternion. */ - angles_to_quat(se->alpha,se->beta,se->delta,se->qs); - /* Determine random target rotation angles and convert them to the - target quaternion. */ - alpha = frand(120.0)-60.0; - beta = frand(120.0)-60.0; - delta = frand(360.0); - angles_to_quat(alpha,beta,delta,se->qe); - /* Compute the angle between qs and qe. */ - dot = (se->qs[0]*se->qe[0]+se->qs[1]*se->qe[1]+ - se->qs[2]*se->qe[2]+se->qs[3]*se->qe[3]); - if (dot < 0.0f) - { - se->qe[0] = -se->qe[0]; - se->qe[1] = -se->qe[1]; - se->qe[2] = -se->qe[2]; - se->qe[3] = -se->qe[3]; - dot = -dot; - } - a = 180.0/M_PI*acos(dot); - se->num_turn = ceil(a/TURN_STEP); - - /* Change the parameters randomly after one full eversion when a - turn to the new orientation starts. */ - /* Copy the current display modes to the values of the second pass. */ - se->display_mode[1] = se->display_mode[0]; - se->appearance[1] = se->appearance[0]; - se->colors[1] = se->colors[0]; - se->graticule[1] = se->graticule[0]; - /* Swap the front and back color buffers. */ - colt = se->colf[1]; - se->colf[1] = se->colf[0]; - se->colf[0] = colt; - colt = se->colb[1]; - se->colb[1] = se->colb[0]; - se->colb[0] = colt; -#ifdef HAVE_GLSL - /* Swap the OpenGL front and back color buffers. */ - if (se->use_shaders) - { - vertex_colort_buffer = se->vertex_colorf_buffer[1]; - se->vertex_colorf_buffer[1] = se->vertex_colorf_buffer[0]; - se->vertex_colorf_buffer[0] = vertex_colort_buffer; - vertex_colort_buffer = se->vertex_colorb_buffer[1]; - se->vertex_colorb_buffer[1] = se->vertex_colorb_buffer[0]; - se->vertex_colorb_buffer[0] = vertex_colort_buffer; - } -#endif /* HAVE_GLSL */ - /* Randomly select new display modes for the main pass. */ - if (se->random_display_mode) - se->display_mode[0] = random() % NUM_DISPLAY_MODES; - if (se->random_appearance) - se->appearance[0] = random() % NUM_APPEARANCES; - if (se->random_colors) - se->colors[0] = random() % NUM_COLORS; - if (se->random_graticule) - se->graticule[0] = random() & 1; - if (se->random_g) - se->g = random() % 4 + 2; - setup_surface_colors(mi,-M_PI,M_PI,-M_PI/2.0,M_PI/2.0,NUMPH,NUMTH); - } - } - else /* se->anim_state == ANIM_TURN */ - { - t = (float)se->turn_step/(float)se->num_turn; - /* Apply an easing function to t. */ - t = (3.0-2.0*t)*t*t; - quat_slerp(t,se->qs,se->qe,q); - quat_to_angles(q,&se->alpha,&se->beta,&se->delta); - se->turn_step++; - if (se->turn_step > se->num_turn) - { - se->turn_step = 0; - se->anim_state = ANIM_DEFORM; - } - } - - if (se->anim_state == ANIM_DEFORM) - { - se->alpha += speed_x*se->speed_scale; - if (se->alpha >= 360.0f) - se->alpha -= 360.0f; - se->beta += speed_y*se->speed_scale; - if (se->beta >= 360.0f) - se->beta -= 360.0f; - se->delta += speed_z*se->speed_scale; - if (se->delta >= 360.0f) - se->delta -= 360.0f; - } - } - -#ifdef HAVE_GLSL - if (se->use_shaders) - mi->polygon_count = bednorz_sphere_eversion_pf(mi,-M_PI,M_PI,-M_PI/2.0, - M_PI/2.0,NUMPH,NUMTH, - NUMBDIST,NUMBDIR, - NUMGRID); - else -#endif /* HAVE_GLSL */ - mi->polygon_count = bednorz_sphere_eversion_ff(mi,-M_PI,M_PI,-M_PI/2.0, - M_PI/2.0,NUMPH,NUMTH, - NUMBDIST,NUMBDIR, - NUMGRID); -} - - -ENTRYPOINT void reshape_sphereeversion(ModeInfo *mi, int width, int height) -{ - sphereeversionstruct *se = &sphereeversion[MI_SCREEN(mi)]; - int y = 0; -#ifdef HAVE_GLSL - int i, wt, ht; -#endif /* HAVE_GLSL */ - - if (width > height * 5) { /* tiny window: show middle */ - height = width; - y = -height/2; - } - - se->WindW = (GLint)width; - se->WindH = (GLint)height; - glViewport(0,y,width,height); - se->aspect = (GLfloat)width/(GLfloat)height; -#ifdef HAVE_GLSL - if (se->use_shaders) - { - if (se->WindW <= se->max_tex_size || se->WindH <= se->max_tex_size) - { - wt = se->WindW; - ht = se->WindH; - } - else - { - wt = MIN(se->max_tex_size,se->WindW); - ht = MIN(se->max_tex_size,se->WindH); - } - for (i=0; i<2; i++) - { - glBindTexture(GL_TEXTURE_2D,se->color_textures[i]); - glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,wt,ht,0,GL_RGBA,GL_UNSIGNED_BYTE, - NULL); - } - } -#endif /* HAVE_GLSL */ -} - - -ENTRYPOINT Bool sphereeversion_handle_event(ModeInfo *mi, XEvent *event) -{ - sphereeversionstruct *se = &sphereeversion[MI_SCREEN(mi)]; - - if (event->xany.type == ButtonPress && event->xbutton.button == Button1) - { - se->button_pressed = True; - gltrackball_start(se->trackball, event->xbutton.x, event->xbutton.y, - MI_WIDTH(mi), MI_HEIGHT(mi)); - return True; - } - else if (event->xany.type == ButtonRelease && - event->xbutton.button == Button1) - { - se->button_pressed = False; - return True; - } - else if (event->xany.type == MotionNotify && se->button_pressed) - { - gltrackball_track(se->trackball, event->xmotion.x, event->xmotion.y, - MI_WIDTH(mi), MI_HEIGHT(mi)); - return True; - } - - return False; -} - - -/* - *----------------------------------------------------------------------------- - *----------------------------------------------------------------------------- - * Xlock hooks. - *----------------------------------------------------------------------------- - *----------------------------------------------------------------------------- - */ - -/* - *----------------------------------------------------------------------------- - * Initialize sphereeversion. Called each time the window changes. - *----------------------------------------------------------------------------- - */ - -ENTRYPOINT void init_sphereeversion(ModeInfo *mi) -{ - sphereeversionstruct *se; - - MI_INIT(mi,sphereeversion); - se = &sphereeversion[MI_SCREEN(mi)]; - - se->trackball = gltrackball_init(True); - se->button_pressed = False; - - /* Set the surface order. */ - if (!strcasecmp(surface_order,"2")) - { - se->g = 2; - se->random_g = False; - } - else if (!strcasecmp(surface_order,"3")) - { - se->g = 3; - se->random_g = False; - } - else if (!strcasecmp(surface_order,"4")) - { - se->g = 4; - se->random_g = False; - } - else if (!strcasecmp(surface_order,"5")) - { - se->g = 5; - se->random_g = False; - } - else - { - se->g = random() % 4 + 2; - se->random_g = True; - } - - /* Set the display mode. */ - if (!strcasecmp(mode,"surface")) - { - se->display_mode[0] = DISP_SURFACE; - se->random_display_mode = False; - } - else if (!strcasecmp(mode,"transparent")) - { - se->display_mode[0] = DISP_TRANSPARENT; - se->random_display_mode = False; - } - else - { - se->display_mode[0] = random() % NUM_DISPLAY_MODES; - se->random_display_mode = True; - } - - /* Set the appearance. */ - if (!strcasecmp(appear,"solid")) - { - se->appearance[0] = APPEARANCE_SOLID; - se->random_appearance = False; - } - else if (!strcasecmp(appear,"parallel-bands")) - { - se->appearance[0] = APPEARANCE_PARALLEL_BANDS; - se->random_appearance = False; - } - else if (!strcasecmp(appear,"meridian-bands")) - { - se->appearance[0] = APPEARANCE_MERIDIAN_BANDS; - se->random_appearance = False; - } - else - { - se->appearance[0] = random() % NUM_APPEARANCES; - se->random_appearance = True; - } - - /* Set the color mode. */ - if (!strcasecmp(color_mode,"two-sided")) - { - se->colors[0] = COLORS_TWOSIDED; - se->random_colors = False; - } - else if (!strcasecmp(color_mode,"parallel")) - { - se->colors[0] = COLORS_PARALLEL; - se->random_colors = False; - } - else if (!strcasecmp(color_mode,"meridian")) - { - se->colors[0] = COLORS_MERIDIAN; - se->random_colors = False; - } - else - { - se->colors[0] = random() % NUM_COLORS; - se->random_colors = True; - } - - /* Set the graticule mode. */ - if (!strcasecmp(graticule,"on")) - { - se->graticule[0] = True; - se->random_graticule = False; - } - else if (!strcasecmp(graticule,"off")) - { - se->graticule[0] = False; - se->random_graticule = False; - } - else - { - se->graticule[0] = random() & 1; - se->random_graticule = True; - } - - /* Set the 3d projection mode. */ - if (!strcasecmp(proj,"perspective")) - { - se->projection = DISP_PERSPECTIVE; - } - else if (!strcasecmp(proj,"orthographic")) - { - se->projection = DISP_ORTHOGRAPHIC; - } - else - { - se->projection = random() % NUM_DISP_MODES; - } - - /* Make multiple screens rotate at slightly different rates. */ - se->speed_scale = 0.9+frand(0.3); - - if ((se->glx_context = init_GL(mi)) != NULL) - { - reshape_sphereeversion(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); - init(mi); - } - else - { - MI_CLEARWINDOW(mi); - } -} - -/* - *----------------------------------------------------------------------------- - * Called by the mainline code periodically to update the display. - *----------------------------------------------------------------------------- - */ -ENTRYPOINT void draw_sphereeversion(ModeInfo *mi) -{ - Display *display = MI_DISPLAY(mi); - Window window = MI_WINDOW(mi); - sphereeversionstruct *se; - - if (sphereeversion == NULL) - return; - se = &sphereeversion[MI_SCREEN(mi)]; - - MI_IS_DRAWN(mi) = True; - if (!se->glx_context) - return; - - glXMakeCurrent(display, window, *se->glx_context); - - display_sphereeversion(mi); - - if (MI_IS_FPS(mi)) - do_fps (mi); - - glFlush(); - - glXSwapBuffers(display,window); -} - - -/* - *----------------------------------------------------------------------------- - * 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_sphereeversion(ModeInfo *mi) -{ - sphereeversionstruct *ev = &sphereeversion[MI_SCREEN(mi)]; - - if (!ev->glx_context) - return; - - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *ev->glx_context); - init(mi); -} -#endif /* !STANDALONE */ - - -ENTRYPOINT void free_sphereeversion(ModeInfo *mi) -{ - sphereeversionstruct *se = &sphereeversion[MI_SCREEN(mi)]; - - if (!se->glx_context) return; - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *se->glx_context); - - if (se->se) free(se->se); - if (se->sen) free(se->sen); - if (se->colf[0]) free(se->colf[0]); - if (se->colf[1]) free(se->colf[1]); - if (se->colb[0]) free(se->colb[0]); - if (se->colb[1]) free(se->colb[1]); - gltrackball_free(se->trackball); -#ifdef HAVE_GLSL - if (se->solid_indices) free(se->solid_indices); - if (se->parallel_indices) free(se->parallel_indices); - if (se->meridian_indices) free(se->meridian_indices); - if (se->line_indices) free(se->line_indices); - if (se->use_shaders) - { - glUseProgram(0); - if (se->poly_shader_program != 0) - glDeleteProgram(se->poly_shader_program); - if (se->line_shader_program != 0) - glDeleteProgram(se->line_shader_program); - if (se->blend_shader_program != 0) - glDeleteProgram(se->blend_shader_program); - glDeleteTextures(2,se->color_textures); - glDeleteBuffers(1,&se->vertex_pos_buffer); - glDeleteBuffers(1,&se->vertex_normal_buffer); - glDeleteBuffers(2,se->vertex_colorf_buffer); - glDeleteBuffers(2,se->vertex_colorb_buffer); - glDeleteBuffers(1,&se->solid_indices_buffer); - glDeleteBuffers(1,&se->parallel_indices_buffer); - glDeleteBuffers(1,&se->meridian_indices_buffer); - glDeleteBuffers(1,&se->line_indices_buffer); - } -#endif /* HAVE_GLSL */ -} - - -XSCREENSAVER_MODULE ("SphereEversion", sphereeversion) - -#endif /* USE_GL */ |
