private void calcLightingContribution(int vIndex,
                                        float[] contribution,
                                        boolean normalIsWorld) {
    float[] v = vertices[vIndex];

    float sr = v[SPR];
    float sg = v[SPG];
    float sb = v[SPB];

    float wx = v[VX];
    float wy = v[VY];
    float wz = v[VZ];
    float shine = v[SHINE];

    float nx = v[NX];
    float ny = v[NY];
    float nz = v[NZ];

    if (!normalIsWorld) {
//      System.out.println("um, hello?");
//      calcLightingNorm.set(nx, ny, nz);
//      //modelviewInv.mult(calcLightingNorm, calcLightingWorldNorm);
//
////      PMatrix3D mvi = modelViewInv;
////      float ox = mvi.m00*nx + mvi.m10*ny + mvi*m20+nz +
//      modelviewInv.cmult(calcLightingNorm, calcLightingWorldNorm);
//
//      calcLightingWorldNorm.normalize();
//      nx = calcLightingWorldNorm.x;
//      ny = calcLightingWorldNorm.y;
//      nz = calcLightingWorldNorm.z;

      toWorldNormal(v[NX], v[NY], v[NZ], worldNormal);
      nx = worldNormal[X];
      ny = worldNormal[Y];
      nz = worldNormal[Z];

//      float wnx = modelviewInv.multX(nx, ny, nz);
//      float wny = modelviewInv.multY(nx, ny, nz);
//      float wnz = modelviewInv.multZ(nx, ny, nz);
//      float wnw = modelviewInv.multW(nx, ny, nz);

//      if (wnw != 0 && wnw != 1) {
//        wnx /= wnw;
//        wny /= wnw;
//        wnz /= wnw;
//      }
//      float nlen = mag(wnx, wny, wnw);
//      if (nlen != 0 && nlen != 1) {
//        nx = wnx / nlen;
//        ny = wny / nlen;
//        nz = wnz / nlen;
//      } else {
//        nx = wnx;
//        ny = wny;
//        nz = wnz;
//      }
//      */
    } else {
      nx = v[NX];
      ny = v[NY];
      nz = v[NZ];
    }

    // Since the camera space == world space,
    // we can test for visibility by the dot product of
    // the normal with the direction from pt. to eye.
    float dir = dot(nx, ny, nz, -wx, -wy, -wz);
    // If normal is away from camera, choose its opposite.
    // If we add backface culling, this will be backfacing
    // (but since this is per vertex, it's more complicated)
    if (dir < 0) {
      nx = -nx;
      ny = -ny;
      nz = -nz;
    }

    // These two terms will sum the contributions from the various lights
    contribution[LIGHT_AMBIENT_R] = 0;
    contribution[LIGHT_AMBIENT_G] = 0;
    contribution[LIGHT_AMBIENT_B] = 0;

    contribution[LIGHT_DIFFUSE_R] = 0;
    contribution[LIGHT_DIFFUSE_G] = 0;
    contribution[LIGHT_DIFFUSE_B] = 0;

    contribution[LIGHT_SPECULAR_R] = 0;
    contribution[LIGHT_SPECULAR_G] = 0;
    contribution[LIGHT_SPECULAR_B] = 0;

    // for (int i = 0; i < MAX_LIGHTS; i++) {
    // if (!light[i]) continue;
    for (int i = 0; i < lightCount; i++) {

      float denom = lightFalloffConstant[i];
      float spotTerm = 1;

      if (lightType[i] == AMBIENT) {
        if (lightFalloffQuadratic[i] != 0 || lightFalloffLinear[i] != 0) {
          // Falloff depends on distance
          float distSq = mag(lightPosition[i].x - wx,
                             lightPosition[i].y - wy,
                             lightPosition[i].z - wz);
          denom +=
            lightFalloffQuadratic[i] * distSq +
            lightFalloffLinear[i] * sqrt(distSq);
        }
        if (denom == 0) denom = 1;

        contribution[LIGHT_AMBIENT_R] += lightDiffuse[i][0] / denom;
        contribution[LIGHT_AMBIENT_G] += lightDiffuse[i][1] / denom;
        contribution[LIGHT_AMBIENT_B] += lightDiffuse[i][2] / denom;

      } else {
        // If not ambient, we must deal with direction

        // li is the vector from the vertex to the light
        float lix, liy, liz;
        float lightDir_dot_li = 0;
        float n_dot_li = 0;

        if (lightType[i] == DIRECTIONAL) {
          lix = -lightNormal[i].x;
          liy = -lightNormal[i].y;
          liz = -lightNormal[i].z;
          denom = 1;
          n_dot_li = (nx * lix + ny * liy + nz * liz);
          // If light is lighting the face away from the camera, ditch
          if (n_dot_li <= 0) {
            continue;
          }
        } else { // Point or spot light (must deal also with light location)
          lix = lightPosition[i].x - wx;
          liy = lightPosition[i].y - wy;
          liz = lightPosition[i].z - wz;
          // normalize
          float distSq = mag(lix, liy, liz);
          if (distSq != 0) {
            lix /= distSq;
            liy /= distSq;
            liz /= distSq;
          }
          n_dot_li = (nx * lix + ny * liy + nz * liz);
          // If light is lighting the face away from the camera, ditch
          if (n_dot_li <= 0) {
            continue;
          }

          if (lightType[i] == SPOT) { // Must deal with spot cone
            lightDir_dot_li =
              -(lightNormal[i].x * lix +
                lightNormal[i].y * liy +
                lightNormal[i].z * liz);
            // Outside of spot cone
            if (lightDir_dot_li <= lightSpotAngleCos[i]) {
              continue;
            }
            spotTerm = (float) Math.pow(lightDir_dot_li, lightSpotConcentration[i]);
          }

          if (lightFalloffQuadratic[i] != 0 || lightFalloffLinear[i] != 0) {
            // Falloff depends on distance
            denom +=
              lightFalloffQuadratic[i] * distSq +
              lightFalloffLinear[i] * (float) sqrt(distSq);
          }
        }
        // Directional, point, or spot light:

        // We know n_dot_li > 0 from above "continues"

        if (denom == 0)
          denom = 1;
        float mul = n_dot_li * spotTerm / denom;
        contribution[LIGHT_DIFFUSE_R] += lightDiffuse[i][0] * mul;
        contribution[LIGHT_DIFFUSE_G] += lightDiffuse[i][1] * mul;
        contribution[LIGHT_DIFFUSE_B] += lightDiffuse[i][2] * mul;

        // SPECULAR

        // If the material and light have a specular component.
        if ((sr > 0 || sg > 0 || sb > 0) &&
            (lightSpecular[i][0] > 0 ||
             lightSpecular[i][1] > 0 ||
             lightSpecular[i][2] > 0)) {

          float vmag = mag(wx, wy, wz);
          if (vmag != 0) {
            wx /= vmag;
            wy /= vmag;
            wz /= vmag;
          }
          float sx = lix - wx;
          float sy = liy - wy;
          float sz = liz - wz;
          vmag = mag(sx, sy, sz);
          if (vmag != 0) {
            sx /= vmag;
            sy /= vmag;
            sz /= vmag;
          }
          float s_dot_n = (sx * nx + sy * ny + sz * nz);

          if (s_dot_n > 0) {
            s_dot_n = (float) Math.pow(s_dot_n, shine);
            mul = s_dot_n * spotTerm / denom;
            contribution[LIGHT_SPECULAR_R] += lightSpecular[i][0] * mul;
            contribution[LIGHT_SPECULAR_G] += lightSpecular[i][1] * mul;
            contribution[LIGHT_SPECULAR_B] += lightSpecular[i][2] * mul;
          }

        }
      }
    }