Example #1
0
 /**
  * Matches normals for adjacent mesh sections to create a seamless overall mesh. We use temporary
  * normals here. We will convert normals to normixes later.
  *
  * @param i
  * @param nPer
  */
 void adjustCartoonSeamNormals(int i, int nPer) {
   if (bsTemp == null) bsTemp = Normix.newVertexBitSet();
   if (i == iNext - 1
       && iNext < monomerCount
       && monomers[i].getStrucNo() == monomers[iNext].getStrucNo()
       && meshReady[i]
       && meshReady[iNext]) {
     try {
       V3[] normals2 = meshes[iNext].getNormalsTemp();
       V3[] normals = meshes[i].getNormalsTemp();
       int normixCount = normals.length;
       if (doCap0) normixCount -= nPer;
       for (int j = 1; j <= nPer; ++j) {
         norml.add2(normals[normixCount - j], normals2[nPer - j]);
         norml.normalize();
         meshes[i].normalsTemp[normixCount - j].setT(norml);
         meshes[iNext].normalsTemp[nPer - j].setT(norml);
       }
     } catch (Exception e) {
     }
   }
 }
Example #2
0
  /**
   * Cartoon meshes are triangulated objects.
   *
   * @param i
   * @param madBeg
   * @param madMid
   * @param madEnd
   * @param aspectRatio
   * @param tension
   * @return true if deferred rendering is required due to normals averaging
   */
  private boolean createMesh(
      int i, int madBeg, int madMid, int madEnd, float aspectRatio, int tension) {
    setNeighbors(i);
    if (controlPoints[i].distanceSquared(controlPoints[iNext]) == 0) return false;

    // options:

    // isEccentric == not just a tube
    boolean isEccentric = (aspectRatio != 1 && wingVectors != null);
    // isFlatMesh == using mesh even for hermiteLevel = 0 (for exporters)
    boolean isFlatMesh = (aspectRatio == 0);
    // isElliptical == newer cartoonFancy business
    boolean isElliptical = (cartoonsFancy || hermiteLevel >= 6);

    // parameters:

    int nHermites = (hermiteLevel + 1) * 2 + 1; // 5 for hermiteLevel = 1; 13 for hermitelevel 5
    int nPer =
        (isFlatMesh
            ? 4
            : (hermiteLevel + 1) * 4 - 2); // 6 for hermiteLevel 1; 22 for hermiteLevel 5
    float angle = (float) ((isFlatMesh ? Math.PI / (nPer - 1) : 2 * Math.PI / nPer));
    Mesh mesh = meshes[i] = new Mesh().mesh1("mesh_" + shapeID + "_" + i, (short) 0, i);
    boolean variableRadius = (madBeg != madMid || madMid != madEnd);

    // control points and vectors:

    if (controlHermites == null || controlHermites.length < nHermites + 1) {
      controlHermites = new P3[nHermites + 1];
    }
    GData.getHermiteList(
        tension,
        controlPoints[iPrev],
        controlPoints[i],
        controlPoints[iNext],
        controlPoints[iNext2],
        controlPoints[iNext3],
        controlHermites,
        0,
        nHermites,
        true);
    // wing hermites determine the orientation of the cartoon
    if (wingHermites == null || wingHermites.length < nHermites + 1) {
      wingHermites = new V3[nHermites + 1];
    }

    wing.setT(wingVectors[iPrev]);
    if (madEnd == 0) wing.scale(2.0f); // adds a flair to an arrow
    GData.getHermiteList(
        tension,
        wing,
        wingVectors[i],
        wingVectors[iNext],
        wingVectors[iNext2],
        wingVectors[iNext3],
        wingHermites,
        0,
        nHermites,
        false);
    //    }
    // radius hermites determine the thickness of the cartoon
    float radius1 = madBeg / 2000f;
    float radius2 = madMid / 2000f;
    float radius3 = madEnd / 2000f;
    if (variableRadius) {
      if (radiusHermites == null || radiusHermites.length < ((nHermites + 1) >> 1) + 1) {
        radiusHermites = new P3[((nHermites + 1) >> 1) + 1];
      }
      ptPrev.set(radius1, radius1, 0);
      pt.set(radius1, radius2, 0);
      pt1.set(radius2, radius3, 0);
      ptNext.set(radius3, radius3, 0);
      // two for the price of one!
      GData.getHermiteList(
          4, ptPrev, pt, pt1, ptNext, ptNext, radiusHermites, 0, (nHermites + 1) >> 1, true);
    }

    // now create the cartoon polygon

    int nPoints = 0;
    int iMid = nHermites >> 1;
    int kpt1 = (nPer + 2) / 4;
    int kpt2 = (3 * nPer + 2) / 4;
    int mode =
        (!isEccentric
            ? MODE_TUBE
            : isFlatMesh ? MODE_FLAT : isElliptical ? MODE_ELLIPTICAL : MODE_NONELLIPTICAL);
    boolean useMat = (mode == MODE_TUBE || mode == MODE_NONELLIPTICAL);
    for (int p = 0; p < nHermites; p++) {
      norm.sub2(controlHermites[p + 1], controlHermites[p]);
      float scale =
          (!variableRadius ? radius1 : p < iMid ? radiusHermites[p].x : radiusHermites[p - iMid].y);
      wing.setT(wingHermites[p]);
      wing1.setT(wing);
      switch (mode) {
        case MODE_FLAT:
          // hermiteLevel = 0 and not exporting
          break;
        case MODE_ELLIPTICAL:
          // cartoonFancy
          wing1.cross(norm, wing);
          wing1.normalize();
          wing1.scale(wing.length() / aspectRatio);
          break;
        case MODE_NONELLIPTICAL:
          // older nonelliptical hermiteLevel > 0
          wing.scale(2 / aspectRatio);
          wing1.sub(wing);
          break;
        case MODE_TUBE:
          // not helix or sheet
          wing.cross(wing, norm);
          wing.normalize();
          break;
      }
      wing.scale(scale);
      wing1.scale(scale);
      if (useMat) {
        aa.setVA(norm, angle);
        mat.setAA(aa);
      }
      pt1.setT(controlHermites[p]);
      float theta = (isFlatMesh ? 0 : angle);
      for (int k = 0; k < nPer; k++, theta += angle) {
        if (useMat && k > 0) mat.rotate(wing);
        switch (mode) {
          case MODE_FLAT:
            wingT.setT(wing1);
            wingT.scale((float) Math.cos(theta));
            break;
          case MODE_ELLIPTICAL:
            wingT.setT(wing1);
            wingT.scale((float) Math.sin(theta));
            wingT.scaleAdd2((float) Math.cos(theta), wing, wingT);
            break;
          case MODE_NONELLIPTICAL:
            wingT.setT(wing);
            if (k == kpt1 || k == kpt2) wing1.scale(-1);
            wingT.add(wing1);
            break;
          case MODE_TUBE:
            wingT.setT(wing);
            break;
        }
        pt.add2(pt1, wingT);
        mesh.addV(pt, true);
      }
      if (p > 0) {
        int nLast = (isFlatMesh ? nPer - 1 : nPer);
        for (int k = 0; k < nLast; k++) {
          // draw the triangles of opposing quads congruent, so they won't clip
          // esp. for high ribbonAspectRatio values
          int a = nPoints - nPer + k;
          int b = nPoints - nPer + ((k + 1) % nPer);
          int c = nPoints + ((k + 1) % nPer);
          int d = nPoints + k;
          if (k < nLast / 2) mesh.addQuad(a, b, c, d);
          else mesh.addQuad(b, c, d, a);
        }
      }
      nPoints += nPer;
    }
    if (!isFlatMesh) {
      int nPointsPreCap = nPoints;
      // copying vertices here so that the caps are not connected to the rest of
      // the mesh preventing light leaking around the sharp edges
      if (doCap0) {
        for (int l = 0; l < nPer; l++) mesh.addV(mesh.vs[l], true);
        nPoints += nPer;
        for (int k = hermiteLevel * 2; --k >= 0; )
          mesh.addQuad(
              nPoints - nPer + k + 2,
              nPoints - nPer + k + 1,
              nPoints - nPer + (nPer - k) % nPer,
              nPoints - k - 1);
      }
      if (doCap1) {
        for (int l = 0; l < nPer; l++) mesh.addV(mesh.vs[nPointsPreCap - nPer + l], true);
        nPoints += nPer;
        for (int k = hermiteLevel * 2; --k >= 0; )
          mesh.addQuad(
              nPoints - k - 1,
              nPoints - nPer + (nPer - k) % nPer,
              nPoints - nPer + k + 1,
              nPoints - nPer + k + 2);
      }
    }
    meshReady[i] = true;
    adjustCartoonSeamNormals(i, nPer);
    mesh.setVisibilityFlags(1);
    return true;
  }