int RayTraceThread()

in layer1/Ray.cpp [3185:4528]


int RayTraceThread(CRayThreadInfo * T)
{
  CRay *I = T->ray;
  int x, y, yy;
  float excess = 0.0F;
  float dotgle;
  float bright, direct_cmp, reflect_cmp, fc[4];
  float ambient, direct, lreflect, ft, ffact = 0.0F, ffact1m;
  unsigned int cc0, cc1, cc2, cc3;
  int i;
  RayInfo r1, r2;
  int fogFlag = false;
  int fogRangeFlag = false;
  int opaque_back = 0, orig_opaque_back = 0;
  int n_hit = 0;
  int two_sided_lighting;
  float fog;
  float inter[3] = { 0.0F, 0.0F, 0.0F };
  float fog_start = 0.0F;
  /*    float gamma,inp,sig=1.0F; */
  float persist, persist_inv;
  float new_front;
  int pass;
  unsigned int last_pixel = 0, *pixel;
  int exclude1, exclude2;
  float lit;
  int backface_cull;
  float project_triangle;
  float excl_trans;
  int shadows;
  int trans_shadows;
  int trans_mode;
  float first_excess;
  int pixel_flag;
  float ray_trans_spec, ray_lab_spec;
  float shadow_fudge;
  int label_shadow_mode;
  int interior_color;
  int interior_flag;
  int interior_shadows;
  int interior_wobble;
  int interior_mode;
  float interior_reflect;
  int wobble_save;
  float settingPower, settingReflectPower, settingSpecPower, settingSpecReflect,
    settingSpecDirect;
  float settingSpecDirectPower;
  float invHgt, invFrontMinusBack, inv1minusFogStart, invWdth, invHgtRange;
  float invWdthRange, vol0;
  float vol2;
  CBasis *bp1, *bp2;
  int render_height;
  int offset = 0;
  BasisCallRec BasisCall[MAX_BASIS];
  float border_offset;
  int edge_sampling = false;
  unsigned int edge_avg[4] = { 0, 0, 0, 0 };
  unsigned int edge_alpha_avg[4] = { 0, 0, 0, 0 };
  int edge_cnt = 0;
  float edge_base[2] = { 0.0F, 0.0F };
  float interior_normal[3] = {0.0F, 0.0F, 0.0F};
  float edge_width = 0.35356F;
  float edge_height = 0.35356F;
  float trans_spec_cut, trans_spec_scale, trans_oblique, oblique_power;
  float direct_shade;
  float red_blend = 0.0F;
  float blue_blend = 0.0F;
  float green_blend = 0.0F;
  float trans_cont;
  float pixel_base[3];
  float inv_trans_cont = 1.0F;
  float trans_cutoff, persist_cutoff;
  int trans_cont_flag = false;
  int blend_colors;
  int max_pass;
  float BasisFudge0, BasisFudge1;
  int perspective = T->perspective;
  float eye[3] = { 0.0F, 0.0F, 0.0F };
  float start[3] = { 0.0F, 0.0F, 0.0F };
  float nudge[3] = { 0.0F, 0.0F, 0.0F };
  float back_pact[3];
  float *depth = T->depth;
  float ray_scatter = SettingGetGlobal_f(I->G, cSetting_ray_scatter);
  const float shadow_decay = SettingGetGlobal_f(I->G, cSetting_ray_shadow_decay_factor);
  const float shadow_range = SettingGetGlobal_f(I->G, cSetting_ray_shadow_decay_range);
  const int clip_shadows = SettingGetGlobal_b(I->G, cSetting_ray_clip_shadows);
  const int spec_local = SettingGetGlobal_i(I->G, cSetting_ray_spec_local);
  float legacy = SettingGetGlobal_f(I->G, cSetting_ray_legacy_lighting);
  int spec_count = SettingGetGlobal_i(I->G, cSetting_spec_count);
  const float _0 = 0.0F;
  const float _1 = 1.0F;
  const float _p5 = 0.5F;
  const float _2 = 2.0F;
  const float _255 = 255.0F;
  const float _p499 = 0.499F;
  const float _persistLimit = 0.0001F;
  float legacy_1m = _1 - legacy;
  int n_basis = I->NBasis;
  int bg_image_mode = SettingGetGlobal_i(I->G, cSetting_bg_image_mode);
  int bg_image_linear = SettingGetGlobal_b(I->G, cSetting_bg_image_linear);
  auto bg_image_tilesize = SettingGet<const float*>(I->G, cSetting_bg_image_tilesize);
  float hpixelx = floor(T->width/2.f)  - floor(T->bgWidth / 2.f),
    hpixely = floor(T->height/2.f) - floor(T->bgHeight / 2.f);
  float hl;
  float wr = T->bgWidth/(float)T->width, hr = T->bgHeight/(float)T->height;
  float bg_rgb[3];
  const float *tmpf;
  int chromadepth;

  tmpf = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb));
  mult3f(tmpf, 255.f, bg_rgb);

  /*   MemoryDebugDump();
     printf("%d\n",sizeof(CPrimitive));
   */

  {
    float fudge = SettingGetGlobal_f(I->G, cSetting_ray_triangle_fudge);

    BasisFudge0 = 0.0F - fudge;
    BasisFudge1 = 1.0F + fudge;
  }
  if(spec_count < 0) {
    spec_count = SettingGetGlobal_i(I->G, cSetting_light_count);
  }
  /* SETUP */

  /*  if(T->n_thread>1)
     printf(" Ray: Thread %d: Spawned.\n",T->phase+1);
   */

  interior_shadows = SettingGetGlobal_i(I->G, cSetting_ray_interior_shadows);
  interior_wobble = SettingGetGlobal_i(I->G, cSetting_ray_interior_texture);
  interior_color = SettingGetGlobal_i(I->G, cSetting_ray_interior_color);
  interior_reflect = 1.0F - SettingGetGlobal_f(I->G, cSetting_ray_interior_reflect);
  interior_mode = SettingGetGlobal_i(I->G, cSetting_ray_interior_mode);
  label_shadow_mode = SettingGetGlobal_i(I->G, cSetting_label_shadow_mode);
  project_triangle = SettingGetGlobal_f(I->G, cSetting_ray_improve_shadows);
  shadows = SettingGetGlobal_i(I->G, cSetting_ray_shadows);
  trans_shadows = SettingGetGlobal_i(I->G, cSetting_ray_transparency_shadows);

  backface_cull = SettingGetGlobal_i(I->G, cSetting_backface_cull);
  opaque_back = SettingGetGlobal_i(I->G, cSetting_ray_opaque_background);
  if(opaque_back < 0)
    opaque_back = SettingGetGlobal_i(I->G, cSetting_opaque_background);
  orig_opaque_back = opaque_back;

  if (T->bkrd_data){
    opaque_back = 1;
  }

  two_sided_lighting = SettingGetGlobal_i(I->G, cSetting_two_sided_lighting);
  if(two_sided_lighting<0) {
    if(SettingGetGlobal_i(I->G, cSetting_surface_cavity_mode))
      two_sided_lighting = true;
    else
      two_sided_lighting = false;
  }
  
  ray_trans_spec = SettingGetGlobal_f(I->G, cSetting_ray_transparency_specular);
  ray_lab_spec = SettingGetGlobal_f(I->G, cSetting_ray_label_specular);
  trans_cont = SettingGetGlobal_f(I->G, cSetting_ray_transparency_contrast);
  trans_mode = SettingGetGlobal_i(I->G, cSetting_transparency_mode);
  trans_oblique = SettingGetGlobal_f(I->G, cSetting_ray_transparency_oblique);
  oblique_power = SettingGetGlobal_f(I->G, cSetting_ray_transparency_oblique_power);
  trans_cutoff = SettingGetGlobal_f(I->G, cSetting_ray_trace_trans_cutoff);
  persist_cutoff = SettingGetGlobal_f(I->G, cSetting_ray_trace_persist_cutoff);
  chromadepth = SettingGetGlobal_i(I->G, cSetting_chromadepth);

  if(trans_mode == 1)
    two_sided_lighting = true;
  if(trans_cont > 1.0F) {
    trans_cont_flag = true;
    inv_trans_cont = 1.0F / trans_cont;
  }
  ambient = T->ambient;
  /* divide up the reflected light component over all lights */
  {
    float reflect_scale = SceneGetReflectScaleValue(I->G, 10);
    lreflect = reflect_scale * (SettingGetGlobal_f(I->G, cSetting_reflect) - ray_scatter);
    if(lreflect < _0)
      lreflect = _0;
    ray_scatter = ray_scatter * reflect_scale;
  }
  direct = SettingGetGlobal_f(I->G, cSetting_direct);

  /* apply legacy adjustments */

  ambient *= (1.0F - legacy) + (legacy * (0.22F / 0.12F));
  lreflect *= (1.0F - legacy) + (legacy * (0.72F / 0.45F));
  direct *= (1.0F - legacy) + (legacy * (0.24F / 0.45F));

  direct_shade = SettingGetGlobal_f(I->G, cSetting_ray_direct_shade);
  trans_spec_cut = SettingGetGlobal_f(I->G, cSetting_ray_transparency_spec_cut);
  blend_colors = SettingGetGlobal_i(I->G, cSetting_ray_blend_colors);
  max_pass = SettingGetGlobal_i(I->G, cSetting_ray_max_passes);
  if(blend_colors) {
    red_blend = SettingGetGlobal_f(I->G, cSetting_ray_blend_red);
    green_blend = SettingGetGlobal_f(I->G, cSetting_ray_blend_green);
    blue_blend = SettingGetGlobal_f(I->G, cSetting_ray_blend_blue);
  }

  if(trans_spec_cut < _1)
    trans_spec_scale = _1 / (_1 - trans_spec_cut);
  else
    trans_spec_scale = _0;

  /* COOP */
  settingPower = SettingGetGlobal_f(I->G, cSetting_power);
  settingReflectPower = SettingGetGlobal_f(I->G, cSetting_reflect_power);

  SceneGetAdjustedLightValues(I->G,
      &settingSpecReflect,
      &settingSpecPower,
      &settingSpecDirect,
      &settingSpecDirectPower, 10);

  if((interior_color != -1) || (two_sided_lighting) || (trans_mode == 1)
     || I->CheckInterior)
    backface_cull = 0;

  shadow_fudge = SettingGetGlobal_f(I->G, cSetting_ray_shadow_fudge);

  inv1minusFogStart = _1;

  fog = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog);
  if(fog < 0.0F) {
    if(SettingGetGlobal_b(I->G, cSetting_depth_cue)) {
      fog = SettingGetGlobal_f(I->G, cSetting_fog);
    } else
      fog = _0;
  }

  if(fog != _0) {
    fogFlag = true;
    fog_start = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog_start);
    if(fog_start < 0.0F)
      fog_start = SettingGetGlobal_f(I->G, cSetting_fog_start);
    if(fog_start > 1.0F)
      fog_start = 1.0F;
    if(fog_start < 0.0F)
      fog_start = 0.0F;
    if(fog_start > R_SMALL4) {
      fogRangeFlag = true;
      if(fabs(fog_start - 1.0F) < R_SMALL4)     /* prevent div/0 */
        fogFlag = false;
    }
    inv1minusFogStart = _1 / (_1 - fog_start);
  }

  /* ray-trace */

  if(T->border) {
    invHgt = _1 / (float) (T->height - (3.0F + T->border));
    invWdth = _1 / (float) (T->width - (3.0F + T->border));
  } else {

    invHgt = _1 / (float) (T->height);
    invWdth = _1 / (float) (T->width);
  }

  if(perspective) {
    float height_range, width_range;

    /* subpixel-offsets for antialiasing naturally correspond to
       effective pixel sizes at the front of the visible slab... */

    height_range = (T->front) * 2 * ((float) tan((T->fov / 2.0F) * PI / 180.0F));
    width_range = height_range * (I->Range[0] / I->Range[1]);
    invWdthRange = invWdth * width_range;
    invHgtRange = invHgt * height_range;
    vol0 = eye[0] - width_range / 2.0F;
    vol2 = eye[1] - height_range / 2.0F;
  } else {
    invWdthRange = invWdth * I->Range[0];
    invHgtRange = invHgt * I->Range[1];
    vol0 = I->Volume[0];
    vol2 = I->Volume[2];
  }
  invFrontMinusBack = _1 / (T->front - T->back);

  edge_width *= invWdthRange;
  edge_height *= invHgtRange;

  bp1 = I->Basis + 1;
  if(I->NBasis > 2)
    bp2 = I->Basis + 2;
  else
    bp2 = NULL;

  render_height = T->y_stop - T->y_start;

  if(render_height) {
    offset = (T->phase * render_height / T->n_thread);
    offset = offset - (offset % T->n_thread) + T->phase;
  }
  if((interior_color != -1) || I->CheckInterior) {

    if(interior_color != -1)
      ColorGetEncoded(I->G, interior_color, inter);
    if(bp2) {
      interior_normal[0] = interior_reflect * bp2->LightNormal[0];
      interior_normal[1] = interior_reflect * bp2->LightNormal[1];
      interior_normal[2] = 1.0F + interior_reflect * bp2->LightNormal[2];
    } else {
      interior_normal[0] = 0.0;
      interior_normal[1] = 0.0;
      interior_normal[2] = 1.0F;
    }
    normalize3f(interior_normal);
  }

  r1.base[2] = _0;

  BasisCall[0].Basis = I->Basis + 1;
  BasisCall[0].rr = &r1;
  BasisCall[0].vert2prim = I->Vert2Prim;
  BasisCall[0].prim = I->Primitive;
  BasisCall[0].shadow = false;
  BasisCall[0].back = T->back;
  BasisCall[0].trans_shadows = trans_shadows;
  BasisCall[0].nearest_shadow = (shadow_decay != _0);
  BasisCall[0].check_interior = ((interior_color != -1) || I->CheckInterior);
  BasisCall[0].fudge0 = BasisFudge0;
  BasisCall[0].fudge1 = BasisFudge1;

  MapCacheInit(&BasisCall[0].cache, I->Basis[1].Map, T->phase, cCache_map_scene_cache);

  if(shadows && (n_basis > 2)) {
    int bc;
    for(bc = 2; bc < n_basis; bc++) {
      BasisCall[bc].Basis = I->Basis + bc;
      BasisCall[bc].rr = &r2;
      BasisCall[bc].vert2prim = I->Vert2Prim;
      BasisCall[bc].prim = I->Primitive;
      BasisCall[bc].shadow = true;
      BasisCall[bc].front = _0;
      BasisCall[bc].back = _0;
      BasisCall[bc].excl_trans = _0;
      BasisCall[bc].trans_shadows = trans_shadows;
      BasisCall[bc].nearest_shadow = (shadow_decay != _0) || (clip_shadows);
      BasisCall[bc].check_interior = false;
      BasisCall[bc].fudge0 = BasisFudge0;
      BasisCall[bc].fudge1 = BasisFudge1;
      BasisCall[bc].label_shadow_mode = label_shadow_mode;
      MapCacheInit(&BasisCall[bc].cache, I->Basis[bc].Map, T->phase,
                   cCache_map_shadow_cache);
    }
  }

  if(T->border) {
    border_offset = -1.50F + T->border / 2.0F;
  } else {
    border_offset = 0.0F;
  }

  unsigned int back_mask = 0x00000000;
  if (T->bkrd_is_gradient){
    if(opaque_back) {
      if(I->BigEndian)
	back_mask = 0x000000FF;
      else
	back_mask = 0xFF000000;
    }
  }
  for(yy = T->y_start; (yy < T->y_stop); yy++) {
    float perc, bkrd[4] = {0.f, 0.f, 0.f, 1.f};
    unsigned int bkrd_value = 0;
    short isOutsideInY = 0;

    if(I->G->Interrupt)
      break;

    y = T->y_start + ((yy - T->y_start) + offset) % (render_height);    /* make sure threads write to different pages */
    if (T->bkrd_data){
      switch (bg_image_mode){
      case 1: // isCentered
	{
	  float tmpy = floor(y - hpixely);
	  isOutsideInY = (tmpy < 0.f || tmpy > (float)T->bgHeight);
	  hl = fmodpos(tmpy, (float)T->bgHeight);
	}
	break;
      case 2: // isTiled
	hl = (float)T->bgHeight * (fmodpos((float)y, bg_image_tilesize[1])/bg_image_tilesize[1]);
	break;
      case 3: // isCenteredRepeated
	hl = fmodpos(floor(y - hpixely), (float)T->bgHeight);
	break;
      default:
	hl = y * hr;
	break;
      }
    } else if (T->bkrd_is_gradient){
      /* for RayTraceThread, y is from bottom to top */
      perc = y/(float)T->height;
      bkrd[0] = T->bkrd_bottom[0] + perc * (T->bkrd_top[0] - T->bkrd_bottom[0]);
      bkrd[1] = T->bkrd_bottom[1] + perc * (T->bkrd_top[1] - T->bkrd_bottom[1]);
      bkrd[2] = T->bkrd_bottom[2] + perc * (T->bkrd_top[2] - T->bkrd_bottom[2]);
      bkrd[3] = 1.f;
      if(T->ray->BigEndian){
	bkrd_value = back_mask | 
	  ((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))) << 24) |
	  ((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 16) |
	  ((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 8);
      } else {
	bkrd_value = back_mask | 
	  ((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 16) |
	  ((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 8) |
	  ((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))));
      }
    } else {
      bkrd_value = T->background;
      bkrd[0] = T->bkrd_top[0];
      bkrd[1] = T->bkrd_top[1];
      bkrd[2] = T->bkrd_top[2];
      if (orig_opaque_back){
	bkrd[3] = 1.f;
      } else {
	bkrd[3] = 0.f;
      }
    }
    if((!T->phase) && !(yy & 0xF)) {    /* don't slow down rendering too much */
      if(T->edging_cutoff) {
        if(T->edging) {
          OrthoBusyFast(I->G, (int) (2.5F * T->height / 3 + 0.5F * y), 4 * T->height / 3);
        } else {
          OrthoBusyFast(I->G, (int) (T->height / 3 + 0.5F * y), 4 * T->height / 3);
        }
      } else {
        OrthoBusyFast(I->G, T->height / 3 + y, 4 * T->height / 3);
      }
    }
    pixel = T->image + (T->width * y) + T->x_start;

    if((y % T->n_thread) == T->phase) { /* this is my scan line */
      pixel_base[1] = ((y + 0.5F + border_offset) * invHgtRange) + vol2;

      for(x = T->x_start; (x < T->x_stop); x++) {
	if (T->bkrd_data){
	  // Need to compute background for every pixel if image-based
	  unsigned char bkrd_uc[4];
	  compute_background_for_pixel(bkrd_uc, isOutsideInY,
              bg_image_mode, bg_image_tilesize, bg_rgb, bg_image_linear,
              (unsigned char*) T->bkrd_data, T->bgWidth, T->bgHeight,
              x, wr, hl, hpixelx, orig_opaque_back );
	  bkrd[0] = bkrd_uc[0] / 255.f;
	  bkrd[1] = bkrd_uc[1] / 255.f;
	  bkrd[2] = bkrd_uc[2] / 255.f;
	  bkrd[3] = bkrd_uc[3] / 255.f;
	  if(T->ray->BigEndian){
	    bkrd_value = back_mask | 
	      ((0xFF & ((unsigned int) (bkrd_uc[0] * 255 + _p499))) << 24) |
	      ((0xFF & ((unsigned int) (bkrd_uc[1] * 255 + _p499))) << 16) |
	      ((0xFF & ((unsigned int) (bkrd_uc[2] * 255 + _p499))) << 8);
	  } else {
	    bkrd_value = back_mask | 
	      ((0xFF & ((unsigned int) (bkrd_uc[2] * 255 + _p499))) << 16) |
	      ((0xFF & ((unsigned int) (bkrd_uc[1] * 255 + _p499))) << 8) |
	      ((0xFF & ((unsigned int) (bkrd_uc[0] * 255 + _p499))));
	  }
	}

        pixel_base[0] = (((x + 0.5F + border_offset)) * invWdthRange) + vol0;

        while(1) {
          if(T->edging) {
            if(!edge_sampling) {
              if(x && y && (x < (T->width - 1)) && (y < (T->height - 1))) {     /* not on the edge... */
                if(find_edge(T->edging + (pixel - T->image),
                             depth + (pixel - T->image),
                             T->width, T->edging_cutoff, bkrd_value)) {
                  unsigned char *pixel_c = (unsigned char *) pixel;
                  unsigned int c1, c2, c3, c4;
                  edge_cnt = 1;
                  edge_sampling = true;

                  edge_avg[0] = (c1 = pixel_c[0]);
                  edge_avg[1] = (c2 = pixel_c[1]);
                  edge_avg[2] = (c3 = pixel_c[2]);
                  edge_avg[3] = (c4 = pixel_c[3]);

                  edge_alpha_avg[0] = c1 * c4;
                  edge_alpha_avg[1] = c2 * c4;
                  edge_alpha_avg[2] = c3 * c4;
                  edge_alpha_avg[3] = c4;

                  edge_base[0] = pixel_base[0];
                  edge_base[1] = pixel_base[1];
                }
              }
            }
            if(edge_sampling) {
              if(edge_cnt == 5) {
                /* done with edging, so store averaged value */

                unsigned char *pixel_c = (unsigned char *) pixel;
                unsigned int c1, c2, c3, c4;

                edge_sampling = false;
                /* done with edging, so store averaged value */

                if(edge_alpha_avg[3]) {
                  c4 = edge_alpha_avg[3];
                  c1 = edge_alpha_avg[0] / c4;
                  c2 = edge_alpha_avg[1] / c4;
                  c3 = edge_alpha_avg[2] / c4;
                  c4 /= edge_cnt;
                } else {
                  c1 = edge_avg[0] / edge_cnt;
                  c2 = edge_avg[1] / edge_cnt;
                  c3 = edge_avg[2] / edge_cnt;
                  c4 = edge_avg[3] / edge_cnt;
                }
                pixel_c[0] = c1;
                pixel_c[1] = c2;
                pixel_c[2] = c3;
                pixel_c[3] = c4;

		/* Need to account for alpha, if exists */
		if (orig_opaque_back && c4 < 255){
		  float bkpart = (255 - c4) / 255.f;
		  float ppart = 1.f - bkpart;
		  pixel_c[0] = pymol_roundf(bkpart * bkrd[0] * 255 + ppart * pixel_c[0]);
		  pixel_c[1] = pymol_roundf(bkpart * bkrd[1] * 255 + ppart * pixel_c[1]);
		  pixel_c[2] = pymol_roundf(bkpart * bkrd[2] * 255 + ppart * pixel_c[2]);
		  pixel_c[3] = 255;
		}

                /* restore X,Y coordinates */
                r1.base[0] = pixel_base[0];
                r1.base[1] = pixel_base[1];

              } else {
                *pixel = 0;
		//                *pixel = bkrd_value;
                switch (edge_cnt) {
                case 1:
                  r1.base[0] = edge_base[0] + edge_width;
                  r1.base[1] = edge_base[1] + edge_height;
                  break;
                case 2:
                  r1.base[0] = edge_base[0] + edge_width;
                  r1.base[1] = edge_base[1] - edge_height;
                  break;
                case 3:
                  r1.base[0] = edge_base[0] - edge_width;
                  r1.base[1] = edge_base[1] + edge_height;
                  break;
                case 4:
                  r1.base[0] = edge_base[0] - edge_width;
                  r1.base[1] = edge_base[1] - edge_height;
                  break;
                }

              }
            }
            if(!edge_sampling)  /* not oversampling this edge or already done... */
              break;
          } else {
            r1.base[0] = pixel_base[0];
            r1.base[1] = pixel_base[1];
          }

          exclude1 = -1;
          exclude2 = -1;
          persist = _1;
          first_excess = _0;
          excl_trans = _0;
          pass = 0;
          new_front = T->front;

          if(perspective) {
            r1.base[2] = -T->front;
            r1.dir[0] = (r1.base[0] - eye[0]);
            r1.dir[1] = (r1.base[1] - eye[1]);
            r1.dir[2] = (r1.base[2] - eye[2]);
            if(BasisCall[0].check_interior) {
              start[0] = r1.base[0];
              start[1] = r1.base[1];
              start[2] = r1.base[2];
            }
            normalize3f(r1.dir);
            {
              float scale = I->max_box[2] / r1.base[2];

              r1.skip[0] = r1.base[0] * scale;
              r1.skip[1] = r1.base[1] * scale;
              r1.skip[2] = I->max_box[2];
            }

          }
          while((persist > _persistLimit) && (pass <= max_pass)) {
            char fogFlagTmp = fogFlag;
            pixel_flag = false;
            BasisCall[0].except1 = exclude1;
            BasisCall[0].except2 = exclude2;
            BasisCall[0].front = new_front;
            BasisCall[0].excl_trans = excl_trans;
            BasisCall[0].interior_flag = false;
            BasisCall[0].pass = pass;

            if(perspective) {
              if(pass) {
                add3f(nudge, r1.base, r1.base);
                copy3f(r1.base, r1.skip);
              }
              BasisCall[0].back_dist = -(T->back + r1.base[2]) / r1.dir[2];
              i = BasisHitPerspective(&BasisCall[0]);
            } else {
              i = BasisHitOrthoscopic(&BasisCall[0]);
            }
            interior_flag = BasisCall[0].interior_flag && (!pass);

            if(((i >= 0) || interior_flag) && (pass < max_pass)) {
	      int n_basis_tmp = r1.prim->no_lighting ? 0 : n_basis;
              pixel_flag = true;
              n_hit++;
              if(((r1.trans = r1.prim->trans) != _0) && trans_cont_flag) {
                r1.trans = (float) pow(r1.trans, inv_trans_cont);
              }
              if(interior_flag) {
                copy3f(interior_normal, r1.surfnormal);
                if(perspective) {
                  copy3f(start, r1.impact);
                  r1.dist = _0;
                } else {
                  copy3f(r1.base, r1.impact);
                  r1.dist = T->front;
                  r1.impact[2] -= T->front;
                }

                if(interior_wobble >= 0) {
                  wobble_save = r1.prim->wobble;        /* This is a no-no for multithreading! */
                  r1.prim->wobble = interior_wobble;

                  RayReflectAndTexture(I, &r1, perspective);

                  r1.prim->wobble = wobble_save;
                } else
                  RayReflectAndTexture(I, &r1, perspective);

                dotgle = -r1.dotgle;
                if((interior_color < 0) && (interior_color > cColorExtCutoff)) {
                  copy3f(r1.prim->ic, fc);
                } else {
                  copy3f(inter, fc);
                }
              } else {
                if(!perspective)
                  new_front = r1.dist;

                switch (r1.prim->type) {
                case cPrimTriangle:

                  BasisGetTriangleNormal(bp1, &r1, i, fc, perspective);
                  r1.trans = (float) pow(r1.trans, inv_trans_cont);

                  if(r1.prim->ramped) {
                    RayPrimGetColorRamped(I->G, I->ModelView, &r1, fc);
                  }
                  if(bp2) {
                    RayProjectTriangle(I, &r1, bp2->LightNormal,
                                       bp1->Vertex + i * 3,
                                       bp1->Normal + bp1->Vert2Normal[i] * 3 + 3,
                                       project_triangle);
                  }

                  RayReflectAndTexture(I, &r1, perspective);
                  if(perspective) {
                    BasisGetTriangleFlatDotglePerspective(bp1, &r1, i);
                  } else {
                    BasisGetTriangleFlatDotgle(bp1, &r1, i);
                  }
                  break;
                case cPrimCharacter:
                  BasisGetTriangleNormal(bp1, &r1, i, fc, perspective);

                  r1.trans = CharacterInterpolate(I->G, r1.prim->char_id, fc);
		  fogFlagTmp = false;
                  RayReflectAndTexture(I, &r1, perspective);
                  BasisGetTriangleFlatDotgle(bp1, &r1, i);
                  break;

                case cPrimEllipsoid:

                  BasisGetEllipsoidNormal(bp1, &r1, i, perspective);
                  RayReflectAndTexture(I, &r1, perspective);

                  fc[0] = r1.prim->c1[0];
                  fc[1] = r1.prim->c1[1];
                  fc[2] = r1.prim->c1[2];
                  break;

                default:       /* sphere, cylinder, sausage, etc. */

                  /* must be a sphere (effectively speaking) */

                  if(perspective) {
                    RayGetSphereNormalPerspective(I, &r1);
                  } else {
                    RayGetSphereNormal(I, &r1);
                  }

                  RayReflectAndTexture(I, &r1, perspective);

                  if(r1.prim->ramped) {
                    RayPrimGetColorRamped(I->G, I->ModelView, &r1, fc);
                  } else {
                    switch (r1.prim->type) {
                    case cPrimCylinder:
                    case cPrimSausage:
                    case cPrimCone:
                      ft = r1.tri1;
                      fc[0] = (r1.prim->c1[0] * (_1 - ft)) + (r1.prim->c2[0] * ft);
                      fc[1] = (r1.prim->c1[1] * (_1 - ft)) + (r1.prim->c2[1] * ft);
                      fc[2] = (r1.prim->c1[2] * (_1 - ft)) + (r1.prim->c2[2] * ft);
                      break;
                    default:
                      fc[0] = r1.prim->c1[0];
                      fc[1] = r1.prim->c1[1];
                      fc[2] = r1.prim->c1[2];
                      break;
                    }
                  }
                  break;
                }

                if((trans_oblique != _0) && (r1.trans != _0)) {
                  if((r1.surfnormal[2] > _0) || two_sided_lighting) {
                    float oblique_factor = r1.surfnormal[2];
                    if(oblique_factor < _0)
                      oblique_factor = -oblique_factor;
                    if(oblique_factor != _1) {
                      if(oblique_factor > _p5) {
                        oblique_factor =
                          (float) (_p5 +
                                   _p5 * (_1 -
                                          pow((_1 - oblique_factor) * _2,
                                              oblique_power)));
                      } else {
                        oblique_factor =
                          (float) (_p5 * pow(oblique_factor * _2, oblique_power));
                      }
                    }
                    r1.trans *= (trans_oblique * oblique_factor) + (1.0F - trans_oblique);
                    if(r1.trans < 0.06F)
                      r1.trans = 0.06F; /* don't allow transparent to become opaque */
                  }
                }

                dotgle = -r1.dotgle;

                if(r1.flat_dotgle < _0) {
                  if((!two_sided_lighting) && (BasisCall[0].check_interior)
                     && (interior_mode != 2)) {
                    interior_flag = true;
                    copy3f(interior_normal, r1.surfnormal);
                    if(perspective) {
                      copy3f(start, r1.impact);
                      r1.dist = _0;
                    } else {
                      copy3f(r1.base, r1.impact);
                      r1.impact[2] -= T->front;
                      r1.dist = T->front;
                    }

                    if(interior_wobble >= 0) {
                      wobble_save = r1.prim->wobble;
                      r1.prim->wobble = interior_wobble;
                      RayReflectAndTexture(I, &r1, perspective);
                      r1.prim->wobble = wobble_save;
                    } else {
                      RayReflectAndTexture(I, &r1, perspective);
                    }

                    dotgle = -r1.dotgle;
                    if((interior_color < 0) && (interior_color > cColorExtCutoff)) {
                      copy3f(r1.prim->ic, fc);
                    } else {
                      copy3f(inter, fc);
                    }
                  }
                }

                if((r1.flat_dotgle < _0) && (!interior_flag)) {
                  if(two_sided_lighting) {
                    dotgle = -dotgle;
                    invert3f(r1.surfnormal);
                  }
                }
              }

              {
                double pow_dotgle;
                float pow_surfnormal2;

                if(settingPower != _1) {
                  pow_dotgle = pow(dotgle, settingPower);
                  pow_surfnormal2 = (float) pow(r1.surfnormal[2], settingPower);
                } else {
                  pow_dotgle = dotgle;
                  pow_surfnormal2 = r1.surfnormal[2];
                }
                direct_cmp = legacy_1m * pow_surfnormal2 +      /* new model */
                  legacy * ((float) (dotgle + pow_dotgle) * _p5);       /* legacy model */
              }

              reflect_cmp = _0;
              if(settingSpecDirect != _0) {
                if(r1.surfnormal[2] > _0) {
                  excess =
                    (float) (pow(r1.surfnormal[2], settingSpecDirectPower) *
                             settingSpecDirect);
                } else {
                  excess = _0;
                }
              } else {
                excess = _0;
              }

              lit = _1;
              if(n_basis_tmp < 3) {
                reflect_cmp = direct_cmp;
              } else {
                int bc;
                CBasis *bp;
                for(bc = 2; bc < n_basis; bc++) {
                  lit = _1;
                  bp = I->Basis + bc;

                  if(shadows && ((!interior_flag) || (interior_shadows)) &&
                     ((r1.prim->type != cPrimCharacter) || (label_shadow_mode & 0x1))) {
                    matrix_transform33f3f(bp->Matrix, r1.impact, r2.base);
                    r2.base[2] -= shadow_fudge;
                    BasisCall[bc].except2 = -1;
                    BasisCall[bc].except1 = i;  /* exclude current prim from shadow comp */
                    if(BasisHitShadow(&BasisCall[bc]) > -1) {
                      if((!clip_shadows) || (bp->LightNormal[2] >= _0) ||
                         ((T->front + r1.impact[2] - (r2.dist * bp->LightNormal[2])) <
                          _0)) {
                        lit = (float) pow(r2.trans, _p5);
                        if((shadow_decay != _0) && (r2.dist > shadow_range)) {
                          if(shadow_decay > 0) {
                            lit +=
                              ((_1 - lit) * (_1 -
                                             _1 / exp((r2.dist - shadow_range) *
                                                      shadow_decay)));
                          } else {
                            lit +=
                              ((_1 - lit) * (_1 -
                                             _1 / pow(r2.dist / shadow_range,
                                                      -shadow_decay)));
                          }
                        }
                      }
                    }
                  }

                  if(lit > _0) {
                    {
                      double pow_dotgle;

                      dotgle = -dot_product3f(r1.surfnormal, bp->LightNormal);
                      if(dotgle < _0)
                        dotgle = _0;

                      if(settingReflectPower != _1)
                        pow_dotgle = pow(dotgle, settingReflectPower);
                      else
                        pow_dotgle = dotgle;

                      reflect_cmp += legacy_1m * ((float) (lit * pow_dotgle)) + /* new model */
                        legacy * ((float) (lit * (dotgle + pow_dotgle) * _p5)); /* legacy model */
                    }

                    if(bc < (spec_count + 2)) {

                      if(ray_scatter != _0)     /* scattered specular light */
                        excess += ray_scatter * dotgle;

                      if(spec_local && perspective) {
                        /* slower, C4D-like local specular */
                        float tmp[3];

                        add3f(r1.surfnormal, r1.surfnormal, tmp);
                        add3f(tmp, bp->LightNormal, tmp);
                        normalize3f(tmp);
                        dotgle = -(dot_product3f(r1.dir, tmp)) * 1.004F;
                        if(dotgle > _1)
                          dotgle = _1;
                        else if(dotgle < _0)
                          dotgle = _0;
                        dotgle = powf(dotgle, 0.29F);
                      } else {
                        dotgle = -dot_product3f(r1.surfnormal, bp->SpecNormal); /* fast OpenGL-like global specular */
                      }
                      if(dotgle < _0)
                        dotgle = _0;
                      if(r1.prim->type != cPrimCharacter) {
                        excess +=
                          (float) (pow(dotgle, settingSpecPower) * settingSpecReflect *
                                   lit);
                      } else {
                        excess +=
                          (float) (pow(dotgle, settingSpecPower) * settingSpecReflect *
                                   lit * ray_lab_spec);
                      }
                    }
                  }
                }
                if (chromadepth > 0) {
                  float d = -(r1.impact[2] + T->front) / (T->back - T->front);
                  const float margin = 1. / 4.;
                  float h = d * (1. + 2. * margin) - margin;
                  if (h < 0.0) h = 0.0;
                  if (h > 1.0) h = 1.0;
                  float hue6 = 6. * 240. / 360. * h;
                  float rgb[3];
                  rgb[0] = fabs(hue6 - 3.) - 1.;
                  rgb[1] = 2. - fabs(hue6 - 2.);
                  rgb[2] = 2. - fabs(hue6 - 4.);
                  clamp3f(rgb);
                  if (chromadepth == 2) {
                      float lum = 0.30 * fc[0] + 0.59 * fc[1] + 0.11 * fc[2];
                      rgb[0] *= lum;
                      rgb[1] *= lum;
                      rgb[2] *= lum;
                  }
                  copy3(rgb, fc);
                }
              }

              if(fc[0] <= ((float) cColorExtCutoff)) {  /* ramped color */
                inverse_transformC44f3f(I->ModelView, r1.impact, back_pact);
                ColorGetRamped(I->G, (int) (fc[0] - 0.1F), back_pact, fc, -1);
              }

              bright = ambient + (((_1 - direct_shade) + direct_shade * lit) * direct * direct_cmp + lreflect * reflect_cmp * (legacy_1m + legacy * direct_cmp));       /* blend legacy */
              if(excess > _1)
                excess = _1;
              if(bright > _1)
                bright = _1;
              else if(bright < _0)
                bright = _0;

              /*                      bright *= (_1-excess); */

              fc[0] = (bright * fc[0] + excess);
              fc[1] = (bright * fc[1] + excess);
              fc[2] = (bright * fc[2] + excess);

              if(n_basis_tmp && fogFlagTmp) {
                if(perspective) {
                  ffact = (T->front + r1.impact[2]) * invFrontMinusBack;
                } else {
                  ffact = (T->front - r1.dist) * invFrontMinusBack;
                }
                if(fogRangeFlag)
                  ffact = (ffact - fog_start) * inv1minusFogStart;

                ffact *= fog;

                if(ffact < _0)
                  ffact = _0;
                if(ffact > _1)
                  ffact = _1;

                ffact1m = _1 - ffact;

		if(orig_opaque_back) {
		  fc[0] = ffact * bkrd[0] + fc[0] * ffact1m;
		  fc[1] = ffact * bkrd[1] + fc[1] * ffact1m;
		  fc[2] = ffact * bkrd[2] + fc[2] * ffact1m;
		  fc[3] = _1;
		} else {
                  fc[3] = ffact1m * (_1 - r1.trans);
		}

                if(!pass) {
                  if(r1.trans < trans_spec_cut) {
                    first_excess = excess * ffact1m * ray_trans_spec;
                  } else {
                    first_excess = excess * ffact1m * ray_trans_spec *
                      trans_spec_scale * (_1 - r1.trans);
                  }
                } else {
                  fc[0] += first_excess;        /* dubious? */
                  fc[1] += first_excess;
                  fc[2] += first_excess;
                }
              } else {
                if(!pass) {
                  if(r1.trans < trans_spec_cut) {
                    first_excess = excess * ray_trans_spec;
                  } else {
                    first_excess = excess * ray_trans_spec *
                      trans_spec_scale * (_1 - r1.trans);
                  }
                } else {
                  fc[0] += first_excess;
                  fc[1] += first_excess;
                  fc[2] += first_excess;
                }
                if(orig_opaque_back) {
                  fc[3] = _1;
		} else {
		  fc[3] = _1 - r1.trans;
                }
              }
            } else if(pass) {
              /* hit nothing, and we're on on second or greater pass,
                 or we're on the last pass of a dead-end loop */
              i = -1;

	      fc[0] = first_excess + bkrd[0];
	      fc[1] = first_excess + bkrd[1];
	      fc[2] = first_excess + bkrd[2];

	      if(orig_opaque_back) {
                fc[3] = _1;
	      } else {
		fc[3] = _0;
		//		fc[3] = bkrd[3];
	      }

              ffact = 1.0F;
              ffact1m = 0.0F;

              pixel_flag = true;
              if(trans_cont_flag)
                persist = (float) pow(persist, trans_cont);

            }

            if(pixel_flag) {
              /*
                 inp    = (fc[0]+fc[1]+fc[2]) * _inv3;
                 if(inp < R_SMALL4) 
                 sig = _1;
                 else
                 sig = (float)(pow(inp,gamma) / inp);

                 cc0 = (uint)(sig * fc[0] * _255);
                 cc1 = (uint)(sig * fc[1] * _255);
                 cc2 = (uint)(sig * fc[2] * _255);
               */

              cc0 = (uint) (fc[0] * _255);
              cc1 = (uint) (fc[1] * _255);
              cc2 = (uint) (fc[2] * _255);

              if(cc0 > 255)
                cc0 = 255;
              if(cc1 > 255)
                cc1 = 255;
              if(cc2 > 255)
                cc2 = 255;

              if(orig_opaque_back) {
                if(I->BigEndian)
                  *pixel = T->fore_mask | (cc0 << 24) | (cc1 << 16) | (cc2 << 8);
                else
                  *pixel = T->fore_mask | (cc2 << 16) | (cc1 << 8) | cc0;
              } else {
                /* use alpha channel for fog with transparent backgrounds */
                cc3 = (uint) (fc[3] * _255);
                if(cc3 > 255)
                  cc3 = 255;

                if(I->BigEndian)
                  *pixel = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;
                else
                  *pixel = (cc3 << 24) | (cc2 << 16) | (cc1 << 8) | cc0;
              }
            }
            if(pass && persist < 1.f) {          /* average all four channels */
              float mix_in;
              if(i >= 0) {
                if(fogFlagTmp) {
                  if(trans_cont_flag && (ffact > _p5)) {
                    mix_in =
                      2 * (persist * (_1 - ffact) +
                           ((float) pow(persist, trans_cont) * (ffact - _p5)))
                      * (_1 - r1.trans * ffact);
                  } else {
                    mix_in = persist * (_1 - r1.trans * ffact);
                  }
                } else {
                  mix_in = persist * (_1 - r1.trans);
                }
              } else {
                mix_in = persist;
              }

              persist_inv = _1 - mix_in;

              if(!orig_opaque_back) {
                if(i < 0) {     /* hit nothing -- so don't blend */
                  fc[0] = (float) (0xFF & (last_pixel >> 24));
                  fc[1] = (float) (0xFF & (last_pixel >> 16));
                  fc[2] = (float) (0xFF & (last_pixel >> 8));
                  fc[3] = (float) (0xFF & (last_pixel));
                  if(trans_cont_flag) { /* unless we are increasing contrast */
                    float m;
                    if(I->BigEndian) {
                      m = _1 - (float) (0xFF & (last_pixel)) / _255;
                    } else {
                      m = _1 - (float) (0xFF & (last_pixel >> 24)) / _255;
                    }
                    m = _1 - (float) pow(m, trans_cont);
                    if(I->BigEndian) {
                      fc[3] = m * _255 + _p499;
                    } else {
                      fc[0] = m * _255 + _p499;
                    }
                  }
                } else {        /* hit something -- so keep blend and compute cumulative alpha */

                  fc[0] =
                    (0xFF & ((*pixel) >> 24)) * mix_in +
                    (0xFF & (last_pixel >> 24)) * persist_inv;
                  fc[1] =
                    (0xFF & ((*pixel) >> 16)) * mix_in +
                    (0xFF & (last_pixel >> 16)) * persist_inv;
                  fc[2] =
                    (0xFF & ((*pixel) >> 8)) * mix_in +
                    (0xFF & (last_pixel >> 8)) * persist_inv;
                  fc[3] =
                    (0xFF & ((*pixel))) * mix_in + (0xFF & (last_pixel)) * persist_inv;

                  if(i >= 0) {  /* make sure opaque objects get opaque alpha */
                    float o1, o2;
                    float m;

                    if(I->BigEndian) {
                      o1 = (float) (0xFF & (last_pixel)) / _255;
                      o2 = (float) (0xFF & (*pixel)) / _255;
                    } else {
                      o1 = (float) (0xFF & (last_pixel >> 24)) / _255;
                      o2 = (float) (0xFF & ((*pixel) >> 24)) / _255;
                    }

                    if(o1 < o2) {       /* make sure o1 is largest opacity */
                      m = o1;
                      o1 = o2;
                      o2 = m;
                    }
                    m = o1 + (1.0F - o1) * o2;
                    if(I->BigEndian) {
                      fc[3] = m * _255 + _p499;
                    } else {
                      fc[0] = m * _255 + _p499;
                    }
                  }
                }
              } else {          /* opaque background, so just blend */
                fc[0] =
                  (0xFF & ((*pixel) >> 24)) * mix_in +
                  (0xFF & (last_pixel >> 24)) * persist_inv;
                fc[1] =
                  (0xFF & ((*pixel) >> 16)) * mix_in +
                  (0xFF & (last_pixel >> 16)) * persist_inv;
                fc[2] =
                  (0xFF & ((*pixel) >> 8)) * mix_in +
                  (0xFF & (last_pixel >> 8)) * persist_inv;
                fc[3] =
                  (0xFF & ((*pixel))) * mix_in + (0xFF & (last_pixel)) * persist_inv;
              }

              cc0 = (uint) (fc[0]);
              cc1 = (uint) (fc[1]);
              cc2 = (uint) (fc[2]);
              cc3 = (uint) (fc[3]);

              if(cc0 > 255)
                cc0 = 255;
              if(cc1 > 255)
                cc1 = 255;
              if(cc2 > 255)
                cc2 = 255;
              if(cc3 > 255)
                cc3 = 255;

              *pixel = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;

            }

            if(depth && (i >= 0) &&
               (r1.trans < trans_cutoff) && (persist > persist_cutoff)) {
              depth[pixel - T->image] = (T->front + r1.impact[2]);
            }

            if(i >= 0) {
              if(r1.prim->type == cPrimSausage) {       /* carry ray through the stick */
                if(perspective)
                  excl_trans = (2 * r1.surfnormal[2] * r1.prim->r1 / r1.dir[2]);
                else
                  excl_trans = new_front + (2 * r1.surfnormal[2] * r1.prim->r1);
              }

              if((!backface_cull) && (trans_mode != 2))
                persist = persist * r1.trans;
              else {
                if(!r1.prim->no_lighting && (persist < 0.9999F) && (r1.trans > 0.05F)) {
                  /* don't combine transparent surfaces */
                  *pixel = last_pixel;
                } else {
                  persist = persist * r1.trans;
                }
              }
            }

            if(i < 0) {         /* nothing hit */
              break;
            } else {
              if(perspective) {
                if(r1.prim->type != cPrimCharacter) {
                  float extend = r1.dist + 0.00001F;
                  scale3f(r1.dir, extend, nudge);
                } else {
                  float extend = r1.dist;
                  scale3f(r1.dir, extend, nudge);
                }
              }
              last_pixel = *pixel;
              exclude2 = exclude1;
              exclude1 = i;
              pass++;
            }

          }                     /* end of ray while */

          if(blend_colors) {

            float red_min = _0;
            float green_min = _0;
            float blue_min = _0;
            float red_part;
            float green_part;
            float blue_part;

            if(I->BigEndian) {
              fc[0] = (float) (0xFF & (*pixel >> 24));
              fc[1] = (float) (0xFF & (*pixel >> 16));
              fc[2] = (float) (0xFF & (*pixel >> 8));
              cc3 = (0xFF & (*pixel));
            } else {
              cc3 = (0xFF & (*pixel >> 24));
              fc[2] = (float) (0xFF & (*pixel >> 16));
              fc[1] = (float) (0xFF & (*pixel >> 8));
              fc[0] = (float) (0xFF & (*pixel));
            }

            red_part = red_blend * fc[0];
            green_part = green_blend * fc[1];
            blue_part = blue_blend * fc[2];

            red_min = (green_part > blue_part) ? green_part : blue_part;
            green_min = (red_part > blue_part) ? red_part : blue_part;
            blue_min = (green_part > red_part) ? green_part : red_part;

            if(fc[0] < red_min)
              fc[0] = red_min;
            if(fc[1] < green_min)
              fc[1] = green_min;
            if(fc[2] < blue_min)
              fc[2] = blue_min;

            cc0 = (uint) (fc[0]);
            cc1 = (uint) (fc[1]);
            cc2 = (uint) (fc[2]);

            if(cc0 > 255)
              cc0 = 255;
            if(cc1 > 255)
              cc1 = 255;
            if(cc2 > 255)
              cc2 = 255;

            if(I->BigEndian)
              *pixel = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;
            else
              *pixel = (cc3 << 24) | (cc2 << 16) | (cc1 << 8) | cc0;
          }

	  {
	    /* If final pixel has alpha, then the background should be 
	       blended into it */
	    unsigned char *pixel_c = (unsigned char *) pixel;
	    if (pixel_c[3] < 255){
	      float pixa = (pixel_c[3]/255.f);
	      float pixam1 = _1 - pixa;
	      float pixam1255 = pixam1 * 255.f;
	      if (T->bkrd_data || T->bkrd_is_gradient){
		pixel_c[0] = (unsigned char)pymol_roundf(pixel_c[0] * pixa + bkrd[0] * pixam1255);
		pixel_c[1] = (unsigned char)pymol_roundf(pixel_c[1] * pixa + bkrd[1] * pixam1255);
		pixel_c[2] = (unsigned char)pymol_roundf(pixel_c[2] * pixa + bkrd[2] * pixam1255);
		pixel_c[3] = (unsigned char)pymol_roundf(pixel_c[3] * pixa + bkrd[3] * pixam1255);
	      }
	    }
	  }

          if(!T->edging)
            break;
          /* if here, then we're edging...
             so accumulate averages */
          {

            unsigned char *pixel_c = (unsigned char *) pixel;
            unsigned int c1, c2, c3, c4;

            edge_avg[0] += (c1 = pixel_c[0]);
            edge_avg[1] += (c2 = pixel_c[1]);
            edge_avg[2] += (c3 = pixel_c[2]);
            edge_avg[3] += (c4 = pixel_c[3]);

            edge_alpha_avg[0] += c1 * c4;
            edge_alpha_avg[1] += c2 * c4;
            edge_alpha_avg[2] += c3 * c4;
            edge_alpha_avg[3] += c4;

            edge_cnt++;
          }

        }                       /* end of edging while */
        pixel++;
      }                         /* end of for */

    }
    /* end of if */
  }                             /* end of for */
  /*  if(T->n_thread>1) 
     printf(" Ray: Thread %d: Complete.\n",T->phase+1); */
  MapCacheFree(&BasisCall[0].cache, T->phase, cCache_map_scene_cache);

  if(shadows && (I->NBasis > 2)) {
    int bc;
    for(bc = 2; bc < I->NBasis; bc++) {
      MapCacheFree(&BasisCall[bc].cache, T->phase, cCache_map_shadow_cache);
    }
  }
  return (n_hit);
}