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, 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 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.0F-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 {
      v=I->VC;
      c=I->NC;
      while(c--) {
        ray->fColor3fv(ray,v);
        v+=3;
        ray->fSphere3fv(ray,v,*(v+3));
        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+=3;
              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+3;
                vdw = v[6];
                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+=7;
            } else {
              switch(sphere_mode) {
              case 2:
              case 3:
              case 4:
              case 5:
              case 7:
              case 8:
                if(!skip) {
                  if(last_radius!=(cur_radius=v[6])) {
                    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+=3;
                if(!skip) glVertex3fv(v);
                v+=4;
                break;
              default: /* simple, default point width points*/
                v+=3;
                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))) { 
          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[6])) {
                    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+=3;
                  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[6])) {
                        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+=3;
                      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+=3;

                     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-3);                          
                                             
                                             glTexCoord2fv(_00);
                                             glVertex3fv(v);
                                             
                                             glTexCoord2fv(_10);
                                             glVertex3fv(v);
                                             
                                             glTexCoord2fv(_11);
                                             glVertex3fv(v);
                                             
                                             glTexCoord2fv(_01);
                                             glVertex3fv(v);
                                       }
                                 }
                       v+=7;
                     }
                     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*/
            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+=3;
                  glNormal3fv(vn);
                  vn+=3;
                  glVertex3fv(v);
                  v+=4;
                }
              } else {
                while(c--) {
                  glColor3fv(v);
                  v+=3;
                  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+=3;
                  glNormal3fv(vn);
                  vn+=3;
                  glVertex3fv(v);
                  v+=4;
                }
              } else {
                while(c--) {
                  glColor4f(v[0],v[1],v[2],alpha);
                  v+=3;
                  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 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) {
              
              nt=I->NT; /* number of passes for each sphere */
              while(c--) /* iterate through all atoms */
                {
                  glColor3fv(v);
                  v+=3;
                  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],alpha);
                  v+=3;
                  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) {
              while(c--) {
                glColor3fv(v);
                v+=3;
                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],alpha);
                v+=3;
                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 one_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;

#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];
  }


  one_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);

  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*7);
  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)
        {
          
          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(one_color==-1)
            c1=*(cs->Color+a);
          else
            c1=one_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++)=*(v0++);
          *(v++)=*(v0++);
          *(v++)=*(v0++);
          *(v++)=obj->AtomInfo[a1].vdw*sphere_scale+sphere_add;
        }
      mf++;
    }
  
  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*7);
      Pickable *pk_tmp = Alloc(Pickable,I->NP+1);
      int a;
      if(vc_tmp&&pk_tmp&&ix) {
        UtilCopyMem(vc_tmp, I->VC, sizeof(float)*7*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*7), vc_tmp+(7*ix[a]), sizeof(float)*7);
          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);
      MapType *map = MapNew(G,range,vc,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 + 3;
        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 = vc + 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+=7;
          v0+=3;
        }
      }
      MapFree(map);
      map = NULL;
      FreeP(active);
    }

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

    
  } 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*30)); /* double check 30 */
      ErrChkPtr(G,I->V);
      
      I->NT=Alloc(int,cs->NIndex);
      ErrChkPtr(G,I->NT);
      
      visFlag = Alloc(int,sp->nDot);
      ErrChkPtr(G,visFlag);
      
      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*(3+sp->NVertTot*6));
      else
        I->V=(float*)mmalloc(sizeof(float)*I->NC*6); /* one color, 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)
              {
            if(one_color==-1)
              c1=*(cs->Color+a);
            else
              c1=one_color;
            v0 = cs->Coord+3*a;
            vdw = cs->Obj->AtomInfo[a1].vdw*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++);
            }
            
            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]) {
                        if(j!=a)
                          if(within3f(cs->Coord+3*j,v1,
                                      cs->Obj->AtomInfo[a2].vdw*
                                      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(one_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++) = one_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