Logo Search packages:      
Sourcecode: pymol version File versions  Download package

RepSphere.c

/* 
   A* -------------------------------------------------------------------
   B* This file contains source code for the PyMOL computer program
   C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific. 
   D* -------------------------------------------------------------------
   E* It is unlawful to modify or remove this copyright notice.
   F* -------------------------------------------------------------------
   G* Please see the accompanying LICENSE file for further information. 
   H* -------------------------------------------------------------------
   I* Additional authors of this source file include:
   -* 
   -* 
   -*
   Z* -------------------------------------------------------------------
*/

#include"os_predef.h"
#include"os_std.h"
#include"os_gl.h"

#include"Base.h"
#include"OOMac.h"
#include"RepSphere.h"
#include"Color.h"
#include"Sphere.h"
#include"Map.h"
#include"Setting.h"
#include"main.h"
#include"Util.h"
#include"Feedback.h"

#ifdef NT
#undef NT
#endif

typedef struct RepSphere {
  Rep R;
  float *V; /* triangle vertices (if any) */
  float *VC; /* sphere centers, colors, alpha, and radii */
  float *VN; /* normals (if any) */
  SphereRec *SP;
  int *NT;
  int N,NC,NP;
  int cullFlag,spheroidFlag;
  int *LastVisib;
  int *LastColor;
  float LastVertexScale;
  int VariableAlphaFlag;
  int shader_flag;
  
  GLint programs[2];
} RepSphere;

#include"ObjectMolecule.h"

#ifdef _PYMOL_OPENGL_SHADERS

/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */ 
#ifdef WIN32
static PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
static PFNGLBINDPROGRAMARBPROC glBindProgramARB;
static PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
static PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
static PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB;
static PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
#endif
/* END PROPRIETARY CODE SEGMENT */

/* NOTE -- right now this shader program only runs in perspective mode */

typedef char ShaderCode[255];
ShaderCode vert_prog[] = {
  "!!ARBvp1.0\n",
  "\n",
  "# input contains the sphere radius in model coordinates\n",
  "PARAM sphereRadius = program.env[0];\n",
  "PARAM half = {0.5, 0.5, 0.0, 2.0 };\n",
  "PARAM zero = {0.0, 0.0, 0.0, 1.0 };\n",
  "\n",
  "ATTRIB vertexPosition  = vertex.position;\n",
  "ATTRIB vertexNormal    = vertex.normal;\n",
  "ATTRIB textureCoord    = vertex.texcoord;\n",
  "OUTPUT outputPosition  = result.position;\n",
  "\n",
  "TEMP   pos, rad, shf, txt, tip;\n",
  "\n",
  "# Transform the vertex by the modelview matrix to get into the frame of the camera\n",
  "\n",
  "DP4    pos.x, state.matrix.modelview.row[0], vertexPosition;\n",
  "DP4    pos.y, state.matrix.modelview.row[1], vertexPosition;\n",
  "DP4    pos.z, state.matrix.modelview.row[2], vertexPosition;\n",
  "DP4    pos.w, state.matrix.modelview.row[3], vertexPosition;\n",
  "\n",
  "# copy current texture coords\n",
  "MOV    txt.xyzw, textureCoord.xyzw;\n",
  "\n",
  "# scale the radius by a factor of two\n",
  "MUL    rad.xy, 2.0, sphereRadius.z;\n",
  "\n",
  "# shift the texture coordinates to the origin\n",
  "SUB    shf.xy, textureCoord, {0.5, 0.5, 0.0, 0.0};\n",
  "\n",
  "# multiply them to get the vertex offset\n",
  "\n",
  "MUL    shf.xy, rad, shf;\n",
  "\n",
  "# define the new vertex for corner of sphere\n",
  "\n",
  "ADD    pos.xy, pos, shf;\n",
  "\n",
  "# apply the projection matrix to get clip coordinates \n",
  "DP4    outputPosition.x, state.matrix.projection.row[0], pos;\n",
  "DP4    outputPosition.y, state.matrix.projection.row[1], pos;\n",
  "DP4    shf.z, state.matrix.projection.row[2], pos;\n",
  "DP4    shf.w, state.matrix.projection.row[3], pos;\n",
  "MOV    outputPosition.zw, shf;\n",
  "\n",
  "# compute camera position for front tip of the sphere\n",
  "ADD    pos.z, pos.z, sphereRadius;\n",
  "\n",
  "# compute Zc and Wc for front tip of the sphere\n",
  "DP4    tip.z, state.matrix.projection.row[2], pos;\n",
  "DP4    tip.w, state.matrix.projection.row[3], pos;\n",
  "\n",
  "# compute 1/Wc for sphere tip \n",
  "RCP    rad.z, tip.w;\n",
  "\n",
  "# put sphere center Zc into tip.w \n",
  "MOV    tip.w, shf.z;\n",
  "\n",
  "# compute 1/Wc for sphere center \n",
  "RCP    rad.w, shf.w;\n",
  "\n",
  "# compute Z/Wc for both sphere tip (->txt.z) and center (->txt.w) \n",
  "MUL    txt.zw, tip, rad;\n",
  "\n",
  "# move into range 0.0-1.0 to get the normalized depth coordinate (0.5*(Zc/Wc)+0.5) \n",
  "ADD    txt.zw, {0.0,0.0,1.0,1.0}, txt;\n",
  "MUL    txt.zw, {0.0,0.0,0.5,0.5}, txt;\n",
  "\n",
  "# Pass the color through\n",
  "MOV    result.color, vertex.color;\n",
  "\n",
  "# Pass texture through\n",
  "MOV    result.texcoord, txt;\n",
  "\n",
  "END\n",
  "\n",
  ""
};

ShaderCode frag_prog[] = {
  "!!ARBfp1.0\n",
  "\n",
  "PARAM fogInfo = program.env[0];\n",
  "PARAM fogColor = state.fog.color;\n",
  "ATTRIB fogCoord = fragment.fogcoord;\n",
  "\n",
  "TEMP pln, norm, depth, color, light, spec, fogFactor;\n",
  "\n",
  "# fully clip spheres that hit the camera\n",
  "KIL fragment.texcoord.z;\n",
  "\n",
  "# move texture coordinates to origin\n",
  "\n",
  "MOV norm.z, 0;\n",
  "SUB norm.xy, fragment.texcoord, {0.5,0.5,0.0,0.0};\n",
  "\n",
  "# compute x^2 + y^2, if > 0.25 then kill the pixel -- not in sphere\n",
  "\n",
  "# kill pixels that aren't in the center circle\n",
  "DP3 pln.z, norm, norm;\n",
  "SUB pln.z, 0.25, pln.z;\n",
  "KIL pln.z;\n",
  "\n",
  "# build a complete unit normal\n",
  "MUL pln.z, 4.0, pln.z;\n",
  "RSQ pln.z, pln.z;\n",
  "MUL norm.xy, 2.0, norm;\n",
  "RCP norm.z, pln.z;\n",
  "\n",
  "# interpolate the Zndc coordinate on the sphere \n",
  "LRP depth.z, norm.z, fragment.texcoord.z, fragment.texcoord.w;\n",
  "MOV result.depth.z, depth.z;\n",
  "\n",
  "# light0\n",
  "\n",
  "DP3 light, state.light[1].half, norm;\n",
  "MOV light.w, 60.0;\n",
  "LIT light, light;\n",
  "\n",
  "# ambient\n",
  "MOV color.xyzw, {0.06,0.06,0.06,1.0};\n",
  "ADD color.xyz, light.y, 0.1;\n",
  "MUL color.xyz, fragment.color, color;\n",
  "MUL spec.xyz, light.z, 0.5;\n",
  "ADD color.xyz, color,spec;\n",
  "\n",
  "# apply fog using linear interp over Zndc\n",
  "MAX fogFactor.x, depth.z, fogInfo.x;\n",
  "SUB fogFactor.x, fogFactor.x, fogInfo.x;\n",
  "MUL fogFactor.x, fogFactor.x, fogInfo.y;\n",
  "LRP color.xyz, fogFactor.x, fogColor, color;\n",
  "MOV result.color, color;\n",
  "\n",
  "END\n",
  "\n",
  ""
};

/*
  normal depth routine...does not work!  why?
  "#MAD_SAT fogFactor.x, fogInfo.x, fragment.texcoord.w, fogInfo.y;\n",
  "#LRP color.xyz, fogFactor.x, color, fogColor;\n",
*/

#endif

void RepSphereFree(RepSphere *I);
int RepSphereSameVis(RepSphere *I,CoordSet *cs);


void RepSphereFree(RepSphere *I)
{
#ifdef _PYMOL_OPENGL_SHADERS
  if(I->R.G->HaveGUI && I->R.G->ValidContext) {
    if(I->shader_flag) {

    }
  }
#endif

  FreeP(I->VC);
  FreeP(I->V);
  FreeP(I->VN);
  FreeP(I->NT);
  FreeP(I->LastColor);
  FreeP(I->LastVisib);
  RepPurge(&I->R);
  OOFreeP(I);
}

#ifdef _PYMOL_OPENGL_SHADERS
 
static GLboolean ProgramStringIsNative(PyMOLGlobals *G,
                                       GLenum target, GLenum format,   
                                       GLsizei len, const GLvoid *string)  
{  
  GLint errorPos, isNative;  
  glProgramStringARB(target, format, len, string);  
  glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);  
  glGetProgramivARB(target,
                    GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &isNative);  
  if ((errorPos == -1) && (isNative == 1))  
    return GL_TRUE;  
  else if(errorPos >=0) {
    if(Feedback(G,FB_OpenGL, FB_Errors)) {
      printf("OpenGL-Error: ARB shader error at char %d\n---->%s\n",errorPos,((char*)string)+errorPos);
    }
  }
  return GL_FALSE;
}
 
static char *read_code_str(ShaderCode *ptr)
{
  ShaderCode *p = ptr;
  char *buffer,*q;
  int size = 0;
  while(*p[0]) {
    size += strlen(*p);
    p++;
  }
  buffer=Calloc(char,size+1);
  p = ptr;
  q = buffer;
  while(*p[0]) {
    strcat(q,*p);
    q+=strlen(q);
    p++;
  }
  return buffer;
}

#if 0
static char *read_file(char *name)
{
  char *buffer = NULL;
  FILE *f=fopen(name,"rb");
  size_t size;
  fseek(f,0,SEEK_END);
  size=ftell(f);
  fseek(f,0,SEEK_SET);
  buffer=(char*)mmalloc(size+1);
  fseek(f,0,SEEK_SET);
  fread(buffer,size,1,f);
  buffer[size]=0;
  fclose(f);
  return buffer;
}
#endif
#endif

static void RepSphereRender(RepSphere *I,RenderInfo *info)
{
  CRay *ray = info->ray;
  Picking **pick = info->pick;
  PyMOLGlobals *G=I->R.G;
  float *v=I->V,*vc,*vn=I->VN;
  int c=I->N;
  int cc=0,*nt=NULL;
  int a;
  int flag;
  SphereRec *sp = I->SP;
  float restart;
  float alpha;

#ifdef _PYMOL_OPENGL_SHADERS
  /* TO DO -- garbage collect -- IMPORTANT! */
  {
    int sphere_mode = SettingGet_i(G,I->R.cs->Setting,
                                   I->R.obj->Setting,
                                   cSetting_sphere_mode);
    
    
    if((!ray) && (sphere_mode==5) && G->HaveGUI && G->ValidContext &&
       (!(I->programs[0]||I->programs[1]))) {
      char *vp = read_code_str(vert_prog);
      char *fp = read_code_str(frag_prog);

      /* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */ 
#ifdef WIN32
      if(!(glGenProgramsARB && glBindProgramARB && 
           glDeleteProgramsARB && glProgramStringARB && 
           glProgramEnvParameter4fARB)) {
        glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) wglGetProcAddress("glGenProgramsARB");
        glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) wglGetProcAddress("glBindProgramARB");
        glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) wglGetProcAddress("glDeleteProgramsARB");
        glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) wglGetProcAddress("glProgramStringARB");
        glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) wglGetProcAddress("glProgramEnvParameter4fARB");
        glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) wglGetProcAddress("glGetProgramivARB");
      }

      if(glGenProgramsARB && glBindProgramARB && 
         glDeleteProgramsARB && glProgramStringARB && 
         glProgramEnvParameter4fARB)
#endif
        /* END PROPRIETARY CODE SEGMENT */

        {
          /*                  
                              char *vp = read_file("vert.txt");
                              char *fp = read_file("frag.txt");
          */
          if(vp&&fp) {            
            int ok=true;
            glGenProgramsARB(2,(GLuint*)I->programs);
            
            /* load the vertex program */
            glBindProgramARB(GL_VERTEX_PROGRAM_ARB,I->programs[0]);
            
            ok = ok && (ProgramStringIsNative(G,GL_VERTEX_PROGRAM_ARB, 
                                              GL_PROGRAM_FORMAT_ASCII_ARB, 
                                              strlen(vp),vp));
            
            if(Feedback(G,FB_OpenGL,FB_Debugging))
              PyMOLCheckOpenGLErr("loading vertex program");
            
            /* load the fragment program */
            glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,I->programs[1]);
            
            ok = ok && (ProgramStringIsNative(G,GL_FRAGMENT_PROGRAM_ARB, 
                                              GL_PROGRAM_FORMAT_ASCII_ARB, 
                                              strlen(fp),fp));
            
            if(Feedback(G,FB_OpenGL,FB_Debugging))
              PyMOLCheckOpenGLErr("loading fragment program");
            if(ok) {
              I->shader_flag=true;
            } else {
              I->shader_flag=false;
              glDeleteProgramsARB(2,(GLuint*)I->programs);
            }
          }
          FreeP(vp);
          FreeP(fp);
        }
    }
  }
#endif

  alpha = SettingGet_f(G,I->R.cs->Setting,I->R.obj->Setting,cSetting_sphere_transparency);
  alpha=1.0F-alpha;
  if(fabs(alpha-1.0)<R_SMALL4)
    alpha=1.0F;
  if(ray) {
    ray->fTransparentf(ray,1.0-alpha);
    if(I->spheroidFlag) {
      if(sp) {
        while(c--)
          {
            vc = v;
            v+=3;
            for(a=0;a<sp->NStrip;a++) {
              cc=sp->StripLen[a];
              while((cc--)>2) {
                ray->fTriangle3fv(ray,v+3,v+9,v+15,v,v+6,v+12,vc,vc,vc);
                v+=6;
              }
              v+=12;
            }
          }
      }
    } else {
      int variable_alpha = I->VariableAlphaFlag;
      v=I->VC;
      c=I->NC;
      while(c--) {
        if(variable_alpha) {
          ray->fTransparentf(ray,1.0F-v[3]);
        }
        ray->fColor3fv(ray,v);
        v+=4;

#if 0
        /* temp code for testing ellipsoids */
        {
          float n1[3] = {1.0F, 0.0F, 0.0F};
          float n2[3] = {0.0F, 0.75F, 0.0F};
          float n3[3] = {0.0F, 0.0F, 0.35F};
          ray->fEllipsoid3fv(ray,v,*(v+3),n1,n2,n3);
        }
#else
        ray->fSphere3fv(ray,v,*(v+3));
#endif          
        v+=4;
      }
    }
    ray->fTransparentf(ray,0.0);
  } else if(G->HaveGUI && G->ValidContext) {
    if(pick) {
      int trans_pick_mode = SettingGet_i(G,I->R.cs->Setting,
                                         I->R.obj->Setting,
                                         cSetting_transparency_picking_mode);
        
      if(I->R.P&&((trans_pick_mode==1)||((trans_pick_mode==2)&&(alpha>0.9F)))) {
        int i,j;
        Pickable *p;
        i=(*pick)->src.index;
          
        p=I->R.P;
          
        if(I->spheroidFlag && sp) {
          while(c--) {
            int skip = (p[1].index<0);
            if(!skip) {
              i++;          
              if(!(*pick)[0].src.bond) {
                /* pass 1 - low order bits *            */
                glColor3ub((uchar)((i&0xF)<<4),(uchar)((i&0xF0)|0x8),(uchar)((i&0xF00)>>4)); 
                VLACheck((*pick),Picking,i);
                p++;
                (*pick)[i].src = *p; /* copy object and atom info */
                (*pick)[i].context = I->R.context;
              } else { 
                /* pass 2 - high order bits */           
                j=i>>12;            
                glColor3ub((uchar)((j&0xF)<<4),(uchar)((j&0xF0)|0x8),(uchar)((j&0xF00)>>4));             
              }                
            } else {
              p++;
            }
            
            v+=4;
            for(a=0;a<sp->NStrip;a++) {
              cc=sp->StripLen[a];
              if(!skip) {
                glBegin(GL_TRIANGLE_STRIP);
                while((cc--)>0) {
                  glNormal3fv(v);
                  glVertex3fv(v+3);
                  v+=6;
                }
                glEnd();
              } else {
                while((cc--)>0) {
                  v+=6;
                }
              }
            }
          }
        } else {
          register float last_radius = -1.0F;
          register float cur_radius;
          register float pixel_scale = 1.0F/info->vertex_scale;
          register float max_size = SettingGet_f(G,I->R.cs->Setting,I->R.obj->Setting,
                                                 cSetting_sphere_point_max_size) * 3;
          register int clamp_size_flag = (max_size>=0.0F);
          register float size;
          int sphere_mode = SettingGet_i(G,I->R.cs->Setting,
                                         I->R.obj->Setting,
                                         cSetting_sphere_mode);
          
          if(!sp) {
            switch(sphere_mode) {
            case 5: 
            case 4:
            case 3:
            case 8:
              glEnable(GL_POINT_SMOOTH);
              glAlphaFunc(GL_GREATER, 0.5F);
              glEnable(GL_ALPHA_TEST);
              glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
              glPointSize(1.0F);
              pixel_scale *= 2.0F;
              break;
            case 2:
            case 7:
              glHint(GL_POINT_SMOOTH_HINT,GL_FASTEST);
              glDisable(GL_POINT_SMOOTH);
              glDisable(GL_ALPHA_TEST);
              pixel_scale *= 1.4F;
              break;
            default:
              glHint(GL_POINT_SMOOTH_HINT,GL_FASTEST);
              glDisable(GL_POINT_SMOOTH);
              glDisable(GL_ALPHA_TEST);
              glPointSize(SettingGet_f(G,I->R.cs->Setting,I->R.obj->Setting,cSetting_sphere_point_size));
              break;
            }
            glBegin(GL_POINTS);
          }
          v=I->VC;
          c=I->NC;
          while(c--) {
            int skip = (p[1].index<0);
            if(!skip) {
              i++;          
              if(!(*pick)[0].src.bond) {
                /* pass 1 - low order bits *            */
                glColor3ub((uchar)((i&0xF)<<4),(uchar)((i&0xF0)|0x8),(uchar)((i&0xF00)>>4)); 
                VLACheck((*pick),Picking,i);
                p++;
                (*pick)[i].src = *p; /* copy object and atom info */
                (*pick)[i].context = I->R.context;
              } else { 
                /* pass 2 - high order bits */           
                j=i>>12;            
                glColor3ub((uchar)((j&0xF)<<4),(uchar)((j&0xF0)|0x8),(uchar)((j&0xF00)>>4));             
              }                
            } else {
              p++;
            }
              
            if(sp) {
              if(!skip) {
                int *s,*q,b;
                float *v0,vdw;
                
                v0 = v+4;
                vdw = v[7];
                q=sp->Sequence;
                s=sp->StripLen;
                for(b=0;b<sp->NStrip;b++) {
                  glBegin(GL_TRIANGLE_STRIP);
                  for(cc=0;cc<(*s);cc++)  {
                    glNormal3f(sp->dot[*q][0],
                               sp->dot[*q][1],
                               sp->dot[*q][2]);
                    glVertex3f(v0[0]+vdw*sp->dot[*q][0],
                               v0[1]+vdw*sp->dot[*q][1],
                               v0[2]+vdw*sp->dot[*q][2]);
                    q++;
                  }
                  glEnd();
                  s++;
                }
              }
              v+=8;
            } else {
              switch(sphere_mode) {
              case 2:
              case 3:
              case 4:
              case 5:
              case 7:
              case 8:
                if(!skip) {
                  if(last_radius!=(cur_radius=v[7])) {
                    size = cur_radius*pixel_scale;
                    glEnd();
                    if(clamp_size_flag) 
                      if(size>max_size)
                        size=max_size;
                    glPointSize(size);
                    glBegin(GL_POINTS);
                    last_radius = cur_radius;
                  }
                }
                v+=4;
                if(!skip) glVertex3fv(v);
                v+=4;
                break;
              default: /* simple, default point width points*/
                v+=4;
                if(!skip) glVertex3fv(v);
                v+=4;
                break;
              }
            }
          }
          if(!sp) {
            switch(sphere_mode) {
            case 3:
            case 4:
            case 8:
              glDisable(GL_POINT_SMOOTH);
              glAlphaFunc(GL_GREATER, 0.05F);
              break;
            default:
              glEnable(GL_ALPHA_TEST);
              break;
            }
            glEnd();
          }
        }
        (*pick)[0].src.index = i;
      }
    } else { /* not pick */
        
      if(!sp) {
        /* no sp -- we're rendering as points */
        int use_dlst;
        int sphere_mode = SettingGet_i(G,I->R.cs->Setting,
                                       I->R.obj->Setting,
                                       cSetting_sphere_mode);
        v=I->VC;
        c=I->NC;
          
        if(((sphere_mode>=2)&&(sphere_mode<=3))||
           ((sphere_mode>=7)&&(sphere_mode<=8))) { /* scaleable reps... */ 
          if(I->R.displayList) { 
            if(I->LastVertexScale != info->vertex_scale) {
              glDeleteLists(I->R.displayList,1);
              I->R.displayList = 0;
            }
          }
        }
        I->LastVertexScale = info->vertex_scale;
          
        use_dlst = (int)SettingGet(G,cSetting_use_display_lists);
        switch(sphere_mode) {
        case 4:
        case 5:
          use_dlst = 0;
          break;
        }
        if(use_dlst&&I->R.displayList) {
          glCallList(I->R.displayList);
        } else { /* display list */
            
          if(use_dlst) {
            if(!I->R.displayList) {
              I->R.displayList = glGenLists(1);
              if(I->R.displayList) {
                glNewList(I->R.displayList,GL_COMPILE_AND_EXECUTE);
              }
            }
          }
            
          glDisable(GL_LIGHTING);
            
          switch(sphere_mode) {
          case 2:
          case 3:
          case 4:
          case 7:
          case 8:
#ifdef _PYMOL_OPENGL_SHADERS
          case 5:
#endif
            {
              register float _1 = 1.0F;
              register float _2 = 2.0F;
              register float last_radius = -_1;
              register float cur_radius;
              register float pixel_scale = 1.0F/info->vertex_scale;
              register float max_size = SettingGet_f(G,I->R.cs->Setting,I->R.obj->Setting,
                                                     cSetting_sphere_point_max_size);
              register int clamp_size_flag = (max_size>=0.0F);
              register float size;
               
              if((sphere_mode==5) && (!I->shader_flag))
                sphere_mode=4;

              switch(sphere_mode) {
                
              case 2:
              case 3:
              case 7:
              case 8:
                if((sphere_mode==3)||(sphere_mode==8)) {
                  pixel_scale *= 2.0F;
                  glEnable(GL_POINT_SMOOTH);
                  glAlphaFunc(GL_GREATER, 0.5F);
                  glEnable(GL_ALPHA_TEST);
                  glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
                  glPointSize(1.0F);
                } else {
                  glHint(GL_POINT_SMOOTH_HINT,GL_FASTEST);
                  glDisable(GL_POINT_SMOOTH);
                  glDisable(GL_ALPHA_TEST);
                  pixel_scale *= 1.4F;
                }
                if((sphere_mode==7)||(sphere_mode==8))
                  glEnable(GL_LIGHTING);
                glBegin(GL_POINTS);
                while(c--) {
                  if(last_radius!=(cur_radius=v[7])) {
                    size = cur_radius*pixel_scale;
                    glEnd();
                    if(clamp_size_flag) 
                      if(size>max_size)
                        size=max_size;
                    glPointSize(size);
                    glBegin(GL_POINTS);
                    last_radius = cur_radius;
                  }
                  glColor3fv(v);
                  v+=4;
                  if(vn) {
                    glNormal3fv(vn);
                    vn+=3;
                  }
                  glVertex3fv(v);
                  v+=4;
                }
                glEnd();
                if(sphere_mode==3) {
                  glDisable(GL_POINT_SMOOTH);
                  glAlphaFunc(GL_GREATER, 0.05F);
                } else {
                  glEnable(GL_ALPHA_TEST);
                }
                break;
              case 4: /* draw multiple points of different radii and Z position */
#ifndef _PYMOL_OPENGL_SHADERS
              case 5:
#endif
                {
                  int repeat = true;
                  register float x_add= 0.0F, y_add= 0.0F, z_add = 0.0F;
                  register float z_factor=0.0F, r_factor = 1.0F;
                  register float largest;
                  register float r, g, b;
                  register float s_factor=0.0F;
                  register float zz_factor;
                  register float clamp_radius;
                  register float last_size;
                  int pass = 0;
                  glEnable(GL_POINT_SMOOTH);
                  glEnable(GL_ALPHA_TEST);
                  glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
                  glPointSize(1.0F);
                  
                  pixel_scale *= 2.0F;
                  while(repeat) {
                    v=I->VC;
                    c=I->NC;
                    largest = 0.0F;
                    zz_factor = _1 - (float)pow(_1-z_factor,2);
                    if(zz_factor<0.45F)
                      zz_factor=0.45F;
                    
                    last_radius = -1.0F;
                    last_size = -1.0F;
                    repeat = false;
                    glBegin(GL_POINTS);
                    while(c--) {
                      if(last_radius!=(cur_radius=v[7])) {
                        size = cur_radius*pixel_scale;
                        clamp_radius = cur_radius;                        
                        if(clamp_size_flag) 
                          if(size>max_size) {
                            size=max_size;
                            clamp_radius = size / pixel_scale;
                          }
                        size *= r_factor;
                        if( size != last_size ) {
                          glEnd();
                          if(size>largest)
                            largest = size;
                          if(size<_2) {
                            if(!pass) {
                              zz_factor=1.0F;
                              s_factor = 0.0F;
                            }
                          }
                          if(size<_1) {
                            size=_1;
                            glDisable(GL_POINT_SMOOTH);
                            glDisable(GL_ALPHA_TEST);
                          } else {
                            glEnable(GL_POINT_SMOOTH);
                            glEnable(GL_ALPHA_TEST);
                          }
                          glPointSize(size);
                          glBegin(GL_POINTS);
                        }
                        x_add = z_factor*clamp_radius*info->view_normal[0];
                        y_add = z_factor*clamp_radius*info->view_normal[1];
                        z_add = z_factor*clamp_radius*info->view_normal[2];
                        last_radius = cur_radius;
                        last_size = size;
                      }
                      r = zz_factor*v[0] + s_factor;
                      g = zz_factor*v[1] + s_factor;
                      b = zz_factor*v[2] + s_factor;
                      
                      glColor3f(r > _1 ? _1 : r,
                                g > _1 ? _1 : g,
                                b > _1 ? _1 : b);
                                
                      v+=4;
                      glVertex3f(v[0]+x_add, v[1]+y_add, v[2]+z_add);
                      v+=4;
                    }
                    glEnd();

                    if(largest>2.0F) {
                      float reduce = (largest-2.0F)/largest;
                      r_factor *= reduce;
                      z_factor = (float)sqrt1f(1.0F-(r_factor*r_factor));
                      s_factor = (float)pow(z_factor,20.0F)*0.5F;
                      repeat = true;
                      pass++;
                    }
                  }
                  glDisable(GL_POINT_SMOOTH);
                }
                break;
#ifdef _PYMOL_OPENGL_SHADERS
              case 5: /* use vertex/fragment program */
                if (I->shader_flag) {
                  float fog_info[3];
                  float _00[2] = { 0.0F, 0.0F};
                  float _01[2] = { 0.0F, 1.0F};
                  float _11[2] = { 1.0F, 1.0F};
                  float _10[2] = { 1.0F, 0.0F};
                  register float v0,v1,v2,nv0, nv1, nv2, nv3,v3;
                  register float *m = info->pmv_matrix;                  
                  register float cutoff = 1.2F;
                  register float m_cutoff = -cutoff;
                        register float z_front, z_back;
                  /* compute -Ze = (Wc) of fog start */
                          nv3 = (info->front + (info->back - info->front)*SettingGetGlobal_f(G,cSetting_fog_start));
                          /* compute Zc of fog start using std. perspective transformation */
                          nv2 = (nv3 * (info->back + info->front) - 2*(info->back * info->front))/(info->back - info->front);
                          /* compute Zc/Wc to get normalized depth coordinate of fog start */
                          nv0 = (nv2/nv3);
                          fog_info[0] = (nv0*0.5)+0.5;
                          /* printf("%8.3f %8.3f %8.3f %8.3f\n", nv3, nv2, nv0, fog_info[0]); */
                          fog_info[1] = 1.0F/(1.0-fog_info[0]); /* effective range of fog */
                          
                  z_front = info->stereo_front;
                  z_back = info->back+((info->back+info->front)*0.25);
                        
                  if(Feedback(G,FB_OpenGL,FB_Debugging))
                    PyMOLCheckOpenGLErr("before shader");

                  /* load the vertex program */
                  glBindProgramARB(GL_VERTEX_PROGRAM_ARB,I->programs[0]);
                   
                  /* load the fragment program */
                  glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,I->programs[1]);
                   
                  /* load some safe initial values  */

                  glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB,
                                             0, 0.0F, 0.0F, 1.0, 0.0F);
                  glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB,
                                             0, 0.5F, 2.0F, 0.0F, 0.0F);
                        
                  glEnable(GL_VERTEX_PROGRAM_ARB);
                  glEnable(GL_FRAGMENT_PROGRAM_ARB);
                   
                  {
                    last_radius = -1.0F;
                     
                    glNormal3fv(info->view_normal);
                    glBegin(GL_QUADS);
                    v+=4;

                    while(c--) {
                       
                      v3 = v[3];

                      v0 = v[0];
                      v1 = v[1];
                      v2 = v[2];

                      if(last_radius!=(cur_radius=v3)) {
                        glEnd();
                        glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB,
                                                   0, 0.0F, 0.0F, v3, 0.0F);
                        glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB,
                                                   0, fog_info[0], fog_info[1], 0.0F, 0.0F);
                        glBegin(GL_QUADS);
                        last_radius = cur_radius;
                      }
                       
                      /*  MatrixTransformC44f4f(info->pmv_matrix, v, nv);*/
                                 
                      nv3 = m[ 3]*v0+m[ 7]*v1+m[11]*v2+m[15]; /* compute Wc */ 
                                 
                      if(((nv3-cur_radius)>z_front) && (nv3<z_back)) { /* is it within the viewing volume? */
                        nv0 = m[ 0]*v0+m[ 4]*v1+m[ 8]*v2+m[12];
                                       
                        nv3 = _1/nv3;
                        nv1 = m[ 1]*v0+m[ 5]*v1+m[ 9]*v2+m[13];
                        nv0 *= nv3;
                        nv1 *= nv3;
                                       
                                       
                        if((nv0<cutoff)&&(nv0>m_cutoff)&&
                           (nv1<cutoff)&&(nv1>m_cutoff)) {
                                             
                          glColor3fv(v-4);                          
                                             
                          glTexCoord2fv(_00);
                          glVertex3fv(v);
                                             
                          glTexCoord2fv(_10);
                          glVertex3fv(v);
                                             
                          glTexCoord2fv(_11);
                          glVertex3fv(v);
                                             
                          glTexCoord2fv(_01);
                          glVertex3fv(v);
                        }
                      }
                      v+=8;
                    }
                    glEnd();
                  }
                   
                  glDisable(GL_FRAGMENT_PROGRAM_ARB);
                  glDisable(GL_VERTEX_PROGRAM_ARB);
                  if(Feedback(G,FB_OpenGL,FB_Debugging))
                    PyMOLCheckOpenGLErr("after shader");
                }
                break;
#endif
              }
            }
            break;
          default: /* simple, default point width points -- modes 1 or 6 */
            glHint(GL_POINT_SMOOTH_HINT,GL_FASTEST);
            glDisable(GL_POINT_SMOOTH);
            glDisable(GL_ALPHA_TEST);

            glPointSize(SettingGet_f(G,I->R.cs->Setting,I->R.obj->Setting,cSetting_sphere_point_size));
            glBegin(GL_POINTS);
            if(alpha==1.0) {
              if(vn) {
                glEnd();
                glEnable(GL_LIGHTING);
                glBegin(GL_POINTS);
                while(c--) {
                  glColor3fv(v);
                  v+=4;
                  glNormal3fv(vn);
                  vn+=3;
                  glVertex3fv(v);
                  v+=4;
                }
              } else {
                while(c--) {
                  glColor3fv(v);
                  v+=4;
                  glVertex3fv(v);
                  v+=4;
                }
              }
            } else {
              if(vn) {
                glEnd();
                glEnable(GL_LIGHTING);
                glBegin(GL_POINTS);
                while(c--) {
                  glColor4f(v[0],v[1],v[2],alpha);
                  v+=4;
                  glNormal3fv(vn);
                  vn+=3;
                  glVertex3fv(v);
                  v+=4;
                }
              } else {
                while(c--) {
                  glColor4f(v[0],v[1],v[2],alpha);
                  v+=4;
                  glVertex3fv(v);
                  v+=4;
                }
              }
            }
            glEnd();
            glEnable(GL_ALPHA_TEST);
            break;
              
          }
          glEnable(GL_LIGHTING);
            
          if(use_dlst&&I->R.displayList) {
            glEndList();
          }
        }
      } else { /* real spheres, drawn with triangles -- not points or impostors */
        int variable_alpha = I->VariableAlphaFlag;
        int use_dlst;
        
        use_dlst = (int)SettingGet(G,cSetting_use_display_lists);
        
        if(use_dlst&&I->R.displayList) {
          glCallList(I->R.displayList);
        } else { /* display list */
          
          if(use_dlst) {
            if(!I->R.displayList) {
              I->R.displayList = glGenLists(1);
              if(I->R.displayList) {
                glNewList(I->R.displayList,GL_COMPILE_AND_EXECUTE);
              }
            }
          }
          if(I->cullFlag) {
            
            if((alpha==1.0)&&(!variable_alpha)) {
              
              nt=I->NT; /* number of passes for each sphere */
              while(c--) { /* iterate through all atoms */
                glColor3fv(v);
                v+=4;
                cc=*(nt++);
                flag=0;
                glBegin(GL_TRIANGLE_STRIP);
                while(cc--) { /* execute loop this many times */
                  restart=*(v++);
                  if(restart) {
                    if(flag) {
                      glEnd();
                      glBegin(GL_TRIANGLE_STRIP);
                    }
                    if(restart==2.0) { /* swap triangle polarity */
                      glNormal3fv(v);
                      glVertex3fv(v+3);
                    }
                    glNormal3fv(v);
                    v+=3;
                    glVertex3fv(v);
                    v+=3;
                    glNormal3fv(v);
                    v+=3;
                    glVertex3fv(v);
                    v+=3;
                  }
                  glNormal3fv(v);
                  v+=3;
                  glVertex3fv(v);
                  v+=3;
                  flag=1;
                }
                glEnd();
              }
            } else {
              
              nt=I->NT; /* number of passes for each sphere */
              while(c--) { /* iterate through all atoms */
                
                glColor4f(v[0],v[1],v[2],v[3]);
                v+=4;
                cc=*(nt++);
                flag=0;
                glBegin(GL_TRIANGLE_STRIP);
                while(cc--) { /* execute loop this many times */
                  restart=*(v++);
                  if(restart) {
                    if(flag) {
                      glEnd();
                      glBegin(GL_TRIANGLE_STRIP);
                    }
                    if(restart==2.0) { /* swap triangle polarity */
                      glNormal3fv(v);
                      glVertex3fv(v+3);
                    }
                    glNormal3fv(v);
                    v+=3;
                    glVertex3fv(v);
                    v+=3;
                    glNormal3fv(v);
                    v+=3;
                    glVertex3fv(v);
                    v+=3;
                  }
                  glNormal3fv(v);
                  v+=3;
                  glVertex3fv(v);
                  v+=3;
                  flag=1;
                }
                glEnd();
              }
            }
          } else if(sp) {
            if((alpha==1.0)&&!variable_alpha) {
              while(c--) {
                glColor3fv(v);
                v+=4;
                for(a=0;a<sp->NStrip;a++) {
                  glBegin(GL_TRIANGLE_STRIP);
                  cc=sp->StripLen[a];
                  while(cc--) {
                    glNormal3fv(v);
                    v+=3;
                    glVertex3fv(v);
                    v+=3;
                  }
                  glEnd();
                }
              }
            } else {
              while(c--) {
                glColor4f(v[0],v[1],v[2],v[3]);
                v+=4;
                for(a=0;a<sp->NStrip;a++) {
                  glBegin(GL_TRIANGLE_STRIP);
                  cc=sp->StripLen[a];
                  while(cc--) {
                    glNormal3fv(v);
                    v+=3;
                    glVertex3fv(v);
                    v+=3;
                  }
                  glEnd();
                }
              }
            }
          } 
          if(use_dlst&&I->R.displayList) {
            glEndList();
          }
        }
      }
    }
  }
}

int RepSphereSameVis(RepSphere *I,CoordSet *cs)
{
  int same = true;
  int *lv,*lc,*cc;
  int a;
  AtomInfoType *ai;
  if(I->LastVisib && I->LastColor) {
    ai = cs->Obj->AtomInfo;
    lv = I->LastVisib;
    lc = I->LastColor;
    cc = cs->Color;
    
    for(a=0;a<cs->NIndex;a++)
      {
        if(*(lv++)!=(ai + cs->IdxToAtm[a])->visRep[cRepSphere] ) {
          same=false;
          break;
        }
        if(*(lc++)!=*(cc++)) {
          same=false;
          break;
        }
      }
  } else {
    same=false;
  }
  return(same);
}

static int RadiusOrder(float *list,int a,int b)
{
  return(list[a*7+6]<=list[b*7+6]);
}


Rep *RepSphereNew(CoordSet *cs,int state)
{
  PyMOLGlobals *G=cs->State.G;
  ObjectMolecule *obj;
  int a,b,c,a1,c1,a2,i,j,k,h,l;
  float *v,*v0,*vc,vdw,v1[3];
  float restart;
  int *q, *s,q0,q1,q2;
  int *lv,*lc,*cc;
  SphereRec *sp = G->Sphere->Sphere[0];
  int ds,*nt,flag;
  int *visFlag = NULL;
  MapType *map = NULL;
  int vFlag;
  AtomInfoType *ai2;
  int spheroidFlag = false;
  float spheroid_scale;
  float *sphLen,sphTmp,*sphNorm,*sphTmpN;
  float sphere_scale,sphere_add=0.0;
  int sphere_color;
  int *map_flag=NULL,*mf;
  int cartoon_side_chain_helper = 0;
  int ribbon_side_chain_helper = 0;
  AtomInfoType *ati1;
  int vis_flag;
  int sphere_mode;
  int *marked = NULL;
  float transp;
  int variable_alpha = false;
#ifdef _this_code_is_not_used
  float vv0[3],vv1[3],vv2[3];
  float tn[3],vt1[3],vt2[3],xtn[3],*tn0,*tn1,*tn2;
#endif

  OOCalloc(G,RepSphere);

  obj = cs->Obj;
  vFlag=false;
  if(obj->RepVisCache[cRepSphere])
    for(a=0;a<cs->NIndex;a++) {
      if(obj->AtomInfo[cs->IdxToAtm[a]].visRep[cRepSphere]) {
        vFlag=true;
        break;
      }
    }
  if(!vFlag) {
    OOFreeP(I);
    return(NULL); /* skip if no dots are visible */
  }
  marked = Calloc(int,obj->NAtom);
  RepInit(G,&I->R);
  I->shader_flag = false;
  I->programs[0] = 0;
  I->programs[1] = 0;

  ds = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_sphere_quality);
  sphere_mode = SettingGet_i(G,cs->Setting,    obj->Obj.Setting,
                             cSetting_sphere_mode);
  if(sphere_mode>0)
    ds = -1;
  if(ds<0) {
    sp = NULL;
  } else {
    if(ds>4) ds=4;
    sp = G->Sphere->Sphere[ds];
  }

  sphere_color=SettingGet_color(G,cs->Setting,obj->Obj.Setting,cSetting_sphere_color);
  cartoon_side_chain_helper = SettingGet_b(G,cs->Setting, obj->Obj.Setting,
                                           cSetting_cartoon_side_chain_helper);
  ribbon_side_chain_helper = SettingGet_b(G,cs->Setting, obj->Obj.Setting,
                                          cSetting_ribbon_side_chain_helper);
  transp = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_sphere_transparency);
  spheroid_scale=SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_spheroid_scale);
  if(sp&&spheroid_scale&&cs->Spheroid) 
    spheroidFlag=1;
  else
    spheroidFlag=0;

  sphere_scale=SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_sphere_scale);

  I->R.fRender=(void (*)(struct Rep *, RenderInfo *))RepSphereRender;
  I->R.fFree=(void (*)(struct Rep *))RepSphereFree;
  I->R.fSameVis=(int (*)(struct Rep*, struct CoordSet*))RepSphereSameVis;

  /* automatic --  OOcalloc 
     I->R.fRecolor=NULL;
     I->LastVisib=NULL;
     I->LastColor=NULL;
     I->NP = 0; 
  */

  I->LastVertexScale = -1.0F;
  I->R.obj=(CObject*)obj;
  I->R.cs = cs;
  I->R.context.object = (void*)obj;
  I->R.context.state = state;

  /* raytracing primitives */
  
  I->VC=(float*)mmalloc(sizeof(float)*cs->NIndex*8);
  ErrChkPtr(G,I->VC);
  I->NC=0;
  map_flag = Calloc(int,cs->NIndex);

  I->NT=NULL;
  nt = NULL;

  v=I->VC; 
  mf=map_flag;

  if(SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_sphere_solvent)) { /* are we generating a solvent surface? */
    sphere_add = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_solvent_radius); /* if so, get solvent radius */
  }
  
  if(SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_pickable)) {
    I->R.P=Alloc(Pickable,cs->NIndex+1);
    ErrChkPtr(G,I->R.P);
  }

  I->spheroidFlag=spheroidFlag;
  for(a=0;a<cs->NIndex;a++) {
    a1 = cs->IdxToAtm[a];
    ati1 = obj->AtomInfo+a1;
    vis_flag = ati1->visRep[cRepSphere];
    
    if(vis_flag &&
       (!ati1->hetatm) &&
       ((cartoon_side_chain_helper && ati1->visRep[cRepCartoon]) ||
        (ribbon_side_chain_helper && ati1->visRep[cRepRibbon]))) {
      
      register char *name1=ati1->name;
      register int prot1=ati1->protons;
      if(prot1 == cAN_N) { 
        if((!name1[1])&&(name1[0]=='N')) { /* N */
          register char *resn1 = ati1->resn;
          if(!((resn1[0]=='P')&&(resn1[1]=='R')&&(resn1[2]=='O')))
            vis_flag=false;
        }
      } else if(prot1 == cAN_O) { 
        if((!name1[1])&&(name1[0]=='O'))
          vis_flag=false;
      } else if(prot1 == cAN_C) {
        if((!name1[1])&&(name1[0]=='C'))
          vis_flag=false;
      }
    }
    marked[a1] = vis_flag; /* store temporary visibility information */
    
    if(vis_flag) {
      float at_sphere_scale;
      int at_sphere_color;
      float at_transp;

      AtomInfoGetSetting_f(G, ati1, cSetting_sphere_scale, sphere_scale, &at_sphere_scale);
      if(AtomInfoGetSetting_f(G, ati1, cSetting_sphere_transparency, transp, &at_transp))
        variable_alpha = true;
      AtomInfoGetSetting_color(G, ati1, cSetting_sphere_color, sphere_color, &at_sphere_color);

        
      if(I->R.P) {
        I->NP++;
        if(!ati1->masked) {
          I->R.P[I->NP].index = a1;
        } else {
          I->R.P[I->NP].index = -1;
        }
        I->R.P[I->NP].bond = -1;
      }
      
      *mf=true;
      I->NC++;
      if(at_sphere_color==-1)
        c1=*(cs->Color+a);
      else
        c1=at_sphere_color;
      v0 = cs->Coord+3*a;                  
      if(ColorCheckRamped(G,c1)) {
        ColorGetRamped(G,c1,v0,v,state);
        v+=3;
      } else {
        vc = ColorGet(G,c1); /* save new color */
        *(v++)=*(vc++);
        *(v++)=*(vc++);
        *(v++)=*(vc++);
      }
      *(v++) = 1.0F - at_transp;

      *(v++)=*(v0++); /* coordinate */
      *(v++)=*(v0++);
      *(v++)=*(v0++);
      *(v++)= obj->AtomInfo[a1].vdw*at_sphere_scale+sphere_add; /* radius */
    }
    mf++;
  }
  
  I->VariableAlphaFlag = variable_alpha;
  if(I->NC) 
    I->VC=ReallocForSure(I->VC,float,(v-I->VC));
  else
    I->VC=ReallocForSure(I->VC,float,1);
  if(I->R.P) {
    I->R.P = Realloc(I->R.P,Pickable,I->NP+1);
    I->R.P[0].index = I->NP;
  }

  if(!sp) { /* if sp==null, then we're drawing a point-based sphere rep */

    /* sort the vertices by radius */
    if(I->NC && I->VC && (!spheroidFlag) && (sphere_mode>1)) {
      int *ix = Alloc(int,I->NC);
      float *vc_tmp = Alloc(float, I->NC*8);
      Pickable *pk_tmp = Alloc(Pickable,I->NP+1);
      int a;
      if(vc_tmp&&pk_tmp&&ix) {
        UtilCopyMem(vc_tmp, I->VC, sizeof(float)*8*I->NC);
        UtilCopyMem(pk_tmp, I->R.P, sizeof(Pickable)*(I->NP+1));
        
        UtilSortIndex(I->NC,I->VC,ix,(UtilOrderFn*)RadiusOrder);
        
        UtilCopyMem(I->R.P, pk_tmp, sizeof(Pickable));
        for(a=0;a<I->NC;a++) {
          UtilCopyMem(I->VC + (a*8), vc_tmp+(8*ix[a]), sizeof(float)*8);
          UtilCopyMem(I->R.P + (a+1), pk_tmp+ix[a]+1, sizeof(Pickable));
        }
      }
      FreeP(vc_tmp);
      FreeP(ix);
      FreeP(pk_tmp);
    }

    if((sphere_mode>=6) && (sphere_mode<9) && I->NC) {
      /* compute sphere normals to approximate a surface */
      register float range = 6.0F;
      float *vc = I->VC;
      float *dot = G->Sphere->Sphere[1]->dot[0];
      int n_dot = G->Sphere->Sphere[1]->nDot;
      int nc = I->NC;
      int *active = Alloc(int,2*n_dot);
      float *v_tmp = Alloc(float,3*nc);
      {
        float *src = vc+4;
        float *dst = v_tmp;
        for(a=0;a<nc;a++) { /* create packed array of sphere centers */
          *(dst++) = *(src++);
          *(dst++) = *(src++);
          *(dst++) = *(src++);
          src+=5;
        }
        {
          map = MapNew(G,range,v_tmp,nc,NULL); 
          I->VN = Alloc(float,I->NC*3);
          if(map && I->VN) {
            float dst;
            register float *vv;
            register int nbr_flag;
            register int n_dot_active,*da;
            register float cut_mult = -1.0F;
            register float range2 = range * range;
            
            MapSetupExpress(map);
            v = vc + 4;
            v0 = I->VN;
            for(a=1;a<n_dot;a++) {
              float t_dot = dot_product3f(dot,dot+a*3);
              if(cut_mult<t_dot)
                cut_mult=t_dot;
            }
            for(a=0;a<nc;a++) {
              nbr_flag = false;
              MapLocus(map,v,&h,&k,&l);
              da = active;
              for(b=0;b<n_dot;b++) {
                *(da++)=b*3;
              }
              n_dot_active = n_dot;
              i=*(MapEStart(map,h,k,l));
              if(i) {
                j=map->EList[i++];
                while(j>=0) {
                  if(j!=a) {
                    vv = v_tmp + 3*j;
                    if(within3fret(vv,v,range,range2,v1,&dst)) {
                      register float cutoff = dst * cut_mult;
                      b = 0;
                      while(b<n_dot_active) {
                        vv = dot+active[b];
                        if(dot_product3f(v1,vv)>cutoff) {
                          n_dot_active--;
                          active[b] = active[n_dot_active];
                        }
                        b++;
                      }
                    }
                  }
                  j=map->EList[i++];
                }
              }
              if(!n_dot_active) {
                v0[0]=0.0F;
                v0[1]=0.0F;
                v0[2]=1.0F;
              } else {
                zero3f(v0);
                b = 0;
                while(b<n_dot_active) {
                  vv = dot+active[b];
                  add3f(vv,v0,v0);
                  b++;
                }
                normalize3f(v0);
              }
              v+=8;
              v0+=3;
            }
          }
        }
      }
      MapFree(map);
      map=NULL;
      FreeP(v_tmp);
      map = NULL;
      FreeP(active);
    }

    I->cullFlag = false;
    I->V = NULL;
    I->NT = NULL;
    I->N = 0;
    I->SP = NULL;

    
  } else {

    if(variable_alpha) 
      I->cullFlag = false;
    else {
      I->cullFlag = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cull_spheres);

      if(I->cullFlag<0) {
        I->cullFlag = !(obj->NCSet>1);
      }
    }
    if(spheroidFlag || (!sp) ) I->cullFlag=false;
    if((I->cullFlag<2)&&
       (SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_sculpting))) 
      /* optimize build-time performance when sculpting */
      I->cullFlag=false;
    if((I->cullFlag<2)&&
       (SettingGet(G,cSetting_roving_spheres)!=0.0F))
      I->cullFlag=false;
    if(I->cullFlag && sp) {
      I->V=(float*)mmalloc(sizeof(float)*I->NC*(sp->NVertTot*31)); /* double check 31 */
      ErrChkPtr(G,I->V);
      
      I->NT=Alloc(int,cs->NIndex);
      ErrChkPtr(G,I->NT);
      
      visFlag = Alloc(int,sp->nDot);
      ErrChkPtr(G,visFlag);
      
      /* hmm...need to compute max(sphere_scale) for all atoms...*/

      map=MapNewFlagged(G,MAX_VDW*sphere_scale+sphere_add,cs->Coord,cs->NIndex,NULL,map_flag);
      if(map) MapSetupExpress(map);
    } else {
      if(sp) 
        I->V=(float*)mmalloc(sizeof(float)*I->NC*(4+sp->NVertTot*6));
      else
        I->V=(float*)mmalloc(sizeof(float)*I->NC*7); /* one color, one alpha, one vertex per spheres */
      ErrChkPtr(G,I->V);
    }
    
    /* rendering primitives */
    
    I->N=0;
    I->SP=sp;
    v=I->V;
    nt=I->NT;
    
    for(a=0;a<cs->NIndex;a++) {
      a1 = cs->IdxToAtm[a];
      ati1 = obj->AtomInfo+a1;
      vis_flag = marked[a1];
        
      /* don't show backbone atoms if side_chain_helper is on */
        
      if(vis_flag)  {
        float at_sphere_scale;
        int at_sphere_color;
        float at_transp;

        AtomInfoGetSetting_f(G, ati1, cSetting_sphere_scale, sphere_scale, &at_sphere_scale);
        AtomInfoGetSetting_color(G, ati1, cSetting_sphere_color, sphere_color, &at_sphere_color);
        if(AtomInfoGetSetting_f(G, ati1, cSetting_sphere_transparency, transp, &at_transp))
          variable_alpha = true;

        if(at_sphere_color==-1)
          c1=*(cs->Color+a);
        else
          c1=at_sphere_color;
        v0 = cs->Coord+3*a;
        vdw = ati1->vdw*at_sphere_scale+sphere_add;
        if(ColorCheckRamped(G,c1)) {
          ColorGetRamped(G,c1,v0,v,state);
          v+=3;
        } else {
          vc = ColorGet(G,c1);
          *(v++)=*(vc++);
          *(v++)=*(vc++);
          *(v++)=*(vc++);
        }
            
        *(v++) = 1.0F - at_transp; /* alpha */

        if(I->cullFlag&&(!spheroidFlag)&&(sp)) {
          for(b=0;b<sp->nDot;b++) { /* Sphere culling mode - more strips, but many fewer atoms */
            v1[0]=v0[0]+vdw*sp->dot[b][0];
            v1[1]=v0[1]+vdw*sp->dot[b][1];
            v1[2]=v0[2]+vdw*sp->dot[b][2];
                  
            MapLocus(map,v1,&h,&k,&l);
                  
            visFlag[b]=1;
            i=*(MapEStart(map,h,k,l));
            if(i) {
              j=map->EList[i++];
              while(j>=0) {
                a2 = cs->IdxToAtm[j];
                if(marked[a2]) {
                  float at2_sphere_scale;
                  AtomInfoType *ati2 = obj->AtomInfo + a2;
                  AtomInfoGetSetting_f(G, ati2, 
                                       cSetting_sphere_scale, sphere_scale, &at2_sphere_scale);

                  if(j!=a)
                    if(within3f(cs->Coord+3*j,v1,
                                ati2->vdw * at2_sphere_scale + sphere_add)) {
                      visFlag[b]=0;
                      break;
                    }
                }
                j=map->EList[i++];
              }
            }
          }
          q=sp->Sequence;
          s=sp->StripLen;
          for(b=0;b<sp->NStrip;b++) {
            /* this is an attempt to fill in *some* of the cracks
             * by checking to see if the center of the triangle is visible 
             * IMHO - the increase in framerates is worth missing a triangle
             * here or there, and the user can always turn off sphere culling */ 
            q+=2;
            for(c=2;c<(*s);c++) {
              q0=*q;
              q1=*(q-1);
              q2=*(q-2);
                    
              if((!visFlag[q0])&&(!visFlag[q1])&&(!visFlag[q2]))

                v1[0]=v0[0]+vdw*sp->dot[q0][0];
              v1[1]=v0[1]+vdw*sp->dot[q0][1];
              v1[2]=v0[2]+vdw*sp->dot[q0][2];

              v1[0]+=v0[0]+vdw*sp->dot[q1][0];
              v1[1]+=v0[1]+vdw*sp->dot[q1][1];
              v1[2]+=v0[2]+vdw*sp->dot[q1][2];

              v1[0]+=v0[0]+vdw*sp->dot[q2][0];
              v1[1]+=v0[1]+vdw*sp->dot[q2][1];
              v1[2]+=v0[2]+vdw*sp->dot[q2][2];

              v1[0]/=3;
              v1[1]/=3;
              v1[2]/=3;

              flag=true;
              i=*(MapEStart(map,h,k,l));
              if(i) {
                j=map->EList[i++];
                while(j>=0) {
                  a2 = cs->IdxToAtm[j];
                  if(marked[a2]) {
                    if(j!=a)
                      if(within3f(cs->Coord+3*j,v1,cs->Obj->AtomInfo[a2].vdw*sphere_scale+sphere_add)) {
                        flag=false;
                        break;
                      }
                  }
                  j=map->EList[i++];
                }
              }
              if(flag)
                {
                  visFlag[q0]=1;
                  visFlag[q1]=1;
                  visFlag[q2]=1;
                }
              q++;
            }
            s++;
          }
                        
          *(nt)=0; /* how many passes through the triangle renderer? */
          q=sp->Sequence;
          s=sp->StripLen;

          for(b=0;b<sp->NStrip;b++) {
            restart=1.0; /* startin a new strip */
            for(c=0;c<(*s);c++) {
              if(c>1) { /* on third vertex or better */
                q0=*q; /* get the indices of the triangle in this strip */
                q1=*(q-1);
                q2=*(q-2);
                if(visFlag[q0]||(visFlag[q1])||(visFlag[q2])) /* visible? */ {
                  *(v++) = restart; /* store continuing string flag */
                          
                  if(restart) { /* not continuing...this is a new strip */
                    if(c&0x1) /* make sure strip starts off "right" */
                      *(v-1)=2.0;
                    *(v++)=sp->dot[q2][0]; /* normal */
                    *(v++)=sp->dot[q2][1];
                    *(v++)=sp->dot[q2][2];
                    *(v++)=v0[0]+vdw*sp->dot[q2][0]; /* point */
                    *(v++)=v0[1]+vdw*sp->dot[q2][1];
                    *(v++)=v0[2]+vdw*sp->dot[q2][2];
                    *(v++)=sp->dot[q1][0]; /* normal */
                    *(v++)=sp->dot[q1][1];
                    *(v++)=sp->dot[q1][2];
                    *(v++)=v0[0]+vdw*sp->dot[q1][0]; /* point */
                    *(v++)=v0[1]+vdw*sp->dot[q1][1];
                    *(v++)=v0[2]+vdw*sp->dot[q1][2];
                    *(v++)=sp->dot[q0][0]; /* normal */
                    *(v++)=sp->dot[q0][1];
                    *(v++)=sp->dot[q0][2];
                    *(v++)=v0[0]+vdw*sp->dot[q0][0]; /* point */
                    *(v++)=v0[1]+vdw*sp->dot[q0][1];
                    *(v++)=v0[2]+vdw*sp->dot[q0][2];
                  } else { /* continue strip */
                    *(v++)=sp->dot[q0][0]; /* normal */
                    *(v++)=sp->dot[q0][1];
                    *(v++)=sp->dot[q0][2];
                    *(v++)=v0[0]+vdw*sp->dot[q0][0]; /* point */
                    *(v++)=v0[1]+vdw*sp->dot[q0][1];
                    *(v++)=v0[2]+vdw*sp->dot[q0][2];
                  }
                  restart=0.0;
                  (*nt)++;
                } else {
                  restart = 1.0;/* next triangle is a new strip */
                }
              }
              q++;
            }
            s++;
          }
        } else if(sp) { 
          q=sp->Sequence;
          s=sp->StripLen;
          if(spheroidFlag) {
            for(b=0;b<sp->NStrip;b++)  {
              sphLen = cs->Spheroid+(sp->nDot*a1);
              sphNorm = cs->SpheroidNormal+(3*sp->nDot*a1);
              for(c=0;c<(*s);c++) {
                sphTmpN = sphNorm + 3*(*q);
                *(v++)=*(sphTmpN++);
                *(v++)=*(sphTmpN++);
                *(v++)=*(sphTmpN++);
                sphTmp = (*(sphLen+(*q)))*spheroid_scale;
                *(v++)=v0[0]+sphTmp*sp->dot[*q][0]; /* point */
                *(v++)=v0[1]+sphTmp*sp->dot[*q][1];
                *(v++)=v0[2]+sphTmp*sp->dot[*q][2];
                q++;
              }

              s++;
            }
          } else {
            for(b=0;b<sp->NStrip;b++) {
              for(c=0;c<(*s);c++) {
                *(v++)=sp->dot[*q][0]; /* normal */
                *(v++)=sp->dot[*q][1];
                *(v++)=sp->dot[*q][2];
                *(v++)=v0[0]+vdw*sp->dot[*q][0]; /* point */
                *(v++)=v0[1]+vdw*sp->dot[*q][1];
                *(v++)=v0[2]+vdw*sp->dot[*q][2];
                q++;
              }
              s++;
            }
          }
        } else { /* if sp is null, then we're simply drawing points */
          *(v++)=v0[0];
          *(v++)=v0[1];
          *(v++)=v0[2];
        }
        I->N++;
        if(nt) nt++;
      }
    }
  }  
  
  if(sp) { /* don't do this if we're trying to conserve RAM */

    if(!I->LastVisib) I->LastVisib = Alloc(int,cs->NIndex);
    if(!I->LastColor) I->LastColor = Alloc(int,cs->NIndex);
    lv = I->LastVisib;
    lc = I->LastColor;
    cc = cs->Color;
    obj=cs->Obj;
    ai2=obj->AtomInfo;
    if(sphere_color==-1) 
      for(a=0;a<cs->NIndex;a++) {
        *(lv++) = marked[cs->IdxToAtm[a]];
        *(lc++) = *(cc++);
      }
    else 
      for(a=0;a<cs->NIndex;a++) {
        *(lv++) = marked[cs->IdxToAtm[a]];
        *(lc++) = sphere_color;
      }
  }

  if(I->V) {
    if(I->N) {
      I->V=ReallocForSure(I->V,float,(v-I->V));
      if(I->NT) I->NT=ReallocForSure(I->NT,int,(nt-I->NT));
    } else {
      I->V=ReallocForSure(I->V,float,1);
      if(I->NT) I->NT=ReallocForSure(I->NT,int,1);
    }
  }
  FreeP(marked);
  FreeP(visFlag);
  FreeP(map_flag);
  if(map)  MapFree(map);
  return((void*)(struct Rep*)I);
}



Generated by  Doxygen 1.6.0   Back to index