예제 #1
0
  public void reset(int[] rotation, int cx, int cy, int cz) {
    this.projected.removeAllElements();
    this.rotation = rotation;
    this.rotationMatrix = new int[3][3];
    MatrixMath.getRotationMatrix(this.rotationMatrix, rotation);

    this.cx = cx;
    this.cy = cy;
    this.cz = cz;
  }
예제 #2
0
  public void project(Body body) {
    Shape shape = body.shape;

    int dx = body.center[0] - cx;
    int dy = body.center[1] - cy;
    int dz = body.center[2] - cz;

    int[] dpoints = new int[] {dx, dy, dz};

    int[] rotateddpoints = MatrixMath.multiplyVector(dpoints, dpoints, this.rotationMatrix);

    int rdxf = rotateddpoints[0];
    int rdyf = rotateddpoints[1];
    int rdzf = rotateddpoints[2];

    int rdx = FixedMath.getInteger(rdxf);
    int rdy = FixedMath.getInteger(rdyf);
    int rdz = FixedMath.getInteger(rdzf);

    int radius = FixedMath.getInteger(shape.getMaxRadius());

    // TODO : rotate the body center around the viewers center by the view angle

    boolean mightBeVisible;
    // check that the body is actually visible at all (not sure about deye check)

    if ((rdz - radius) < -this.deye && rdz < 0) {

      // double pow = Math.pow(2,
      // Math.abs((double)FixedMath.getInteger(dz)/(double)this.shrinkage));
      int adjustedRadius = (radius * deye) / -rdz;
      // check that the mesh isn't so small that it won't be visible or should
      // be simplified to a point

      if (adjustedRadius >= this.minRadius) {
        int screenycenter = (rdy * deye) / -rdz;
        if ((screenycenter - adjustedRadius < this.height / 2)
            && (screenycenter + adjustedRadius > -this.height / 2)) {
          int screenxcenter = (rdx * deye) / -rdz;
          mightBeVisible =
              ((screenxcenter - adjustedRadius < this.width / 2)
                  && (screenxcenter + adjustedRadius > -this.width / 2));
          //                    if(!mightBeVisible)
          //                    {
          //                        System.out.println("outside x bounds of screen");
          //                    }
        } else {
          mightBeVisible = false;
          // System.out.println("outside y bounds of screen "+rdy+" "+screenycenter);
        }
      } else {
        // TODO : simplify to a point if it's reasonably close
        // too far away
        mightBeVisible = false;
        // System.out.println("too small "+body.center[2]+" "+rdz+" "+radius+" -> "+adjustedRadius);
      }
    } else {
      mightBeVisible = false;
      // System.out.println("behind pane "+rdz);
    }

    // mightBeVisible = (rdz - radius) <= 0;

    if (mightBeVisible) {
      if (shape instanceof Mesh) {
        Mesh mesh = (Mesh) shape;
        int[][] working = body.rotatedMatrix;
        if (working == null) {
          int[][] points = mesh.baseMatrix;
          working = new int[points.length][points[0].length];
          body.rotatedMatrix = working;
        }
        addMesh(mesh, body, working, rdxf, rdyf, rdzf);
      } else if (shape instanceof Composite) {
        Composite composite = (Composite) shape;
        addComposite(composite, body, rdxf, rdyf, rdzf);
      } else if (shape instanceof Sphere) {
        // TODO : sphere
      } else {
        throw new IllegalArgumentException("unrecognised shape type : " + shape.getClass());
      }
    }
  }
예제 #3
0
  private void addMesh(Mesh mesh, Body body, int[][] working, int rdxf, int rdyf, int rdzf) {
    int[][] points = mesh.baseMatrix;
    // MatrixMath.translate(points, working, dx, dy, dz);
    // project onto the view plane

    // int[][] target = new int[mesh.baseMatrix.length][mesh.baseMatrix[0].length];
    int[][] target = working;
    int[] rotation = new int[5];
    int[][] rotationProjection = new int[3][3];
    if (mesh instanceof AnimatedMesh) {
      // we need to redo the rotation
      AnimatedMesh animatedMesh = (AnimatedMesh) mesh;
      //            MatrixMath.multiplyQuaternion(rotation, body.rotation,
      // animatedMesh.animation.getRotation());
      //            MatrixMath.multiplyQuaternion(rotation, rotation, this.rotation);
      MatrixMath.multiplyQuaternion(rotation, animatedMesh.animation.getRotation(), body.rotation);
      MatrixMath.multiplyQuaternion(rotation, rotation, this.rotation);
      MatrixMath.getRotationMatrix(rotationProjection, rotation);
    } else {
      MatrixMath.multiplyQuaternion(rotation, body.rotation, this.rotation);
      MatrixMath.getRotationMatrix(rotationProjection, rotation);
    }

    MatrixMath.multiply(target, points, rotationProjection);
    // MatrixMath.rotate(target, points, new int[4][4], rx, ry, rz);
    points = target;

    for (int row = points.length; row > 0; ) {
      row--;
      points[row][0] += rdxf;
      points[row][1] += rdyf;
      points[row][2] += rdzf;
    }

    // TODO : replace with single multiplied out matrix from above!!

    for (int row = points.length; row > 0; ) {
      row--;
      // points[row][0] += rdx;
      // points[row][1] += rdy;
      // points[row][2] += rdz;
      for (int col = 3; col > 0; ) {
        col--;
        // points[row][col] += points[points.length-1][col];
        // convert back to pixel values, after all, that's all the precision we'll need from now on
        // points[row][col] += points[points.length-1][col];
        points[row][col] = FixedMath.getInteger(points[row][col]);
      }

      // perspective
      // TODO : have a cut off point for when we even stop representing dots

      int z = points[row][2];
      if (z >= 0) {
        z = -1;
      }
      points[row][0] = (points[row][0] * deye) / -z;
      points[row][1] = (points[row][1] * deye) / -z;
    }

    ProjectionMesh projectionMesh = new ProjectionMesh(points);
    byte[][] faces = mesh.faces;
    projectionMesh.color = mesh.color;

    // work out the mesh's convex hull for intersections and rendering beauty
    // TODO : reuse working somehow
    byte[] stack = new byte[points.length];
    int stackLength = getConvexHull(points, new byte[points.length], stack);
    projectionMesh.hull = stack;
    projectionMesh.hullLength = stackLength;

    // add the convex hull to the lines
    // to reduce intersection detection and allow accurate
    // outlining
    for (int i = stackLength; i > 0; ) {
      i--;
      byte fromIndex = stack[i];
      byte nextIndex = stack[(i + 1) % stackLength];
      int[] from = points[fromIndex];
      int[] next = points[nextIndex];
      ProjectionLine line = new ProjectionLine(from, next, fromIndex, nextIndex, true);
      projectionMesh.lines.addElement(line);
    }

    for (int i = faces.length; i > 0; ) {
      i--;
      byte[] faceIndices = faces[i];

      // beckface removal
      int minFaceIndex = faceIndices.length - 1;
      int minIndex = faceIndices[minFaceIndex];
      int miny = points[minIndex][1];
      int minx = points[minIndex][0];
      for (int j = faceIndices.length - 1; j > 0; ) {
        j--;
        int index = (int) faceIndices[j];
        if (points[index][1] < miny || (points[index][1] == miny && points[index][0] < minx)) {
          minFaceIndex = j;
          miny = points[index][1];
          minx = points[index][0];
        }
      }

      int preIndex = minFaceIndex - 1;
      if (preIndex < 0) {
        preIndex = faceIndices.length - 1;
      }
      preIndex = faceIndices[preIndex];
      int postIndex = faceIndices[(minFaceIndex + 1) % faceIndices.length];

      int prex = points[preIndex][0];
      int prey = points[preIndex][1];
      int postx = points[postIndex][0];
      int posty = points[postIndex][1];

      int predx = prex - minx;
      int predy = prey - miny;
      int postdx = postx - minx;
      int postdy = posty - miny;

      boolean faceOK;
      if (predx == 0 && postdx == 0) {
        // it's flat, don't draw it
        // System.out.println("no dx");
        faceOK = false;
      } else if (predx == 0) {
        // the incoming line comes from the right
        // System.out.println("no predx "+preIndex+"("+prex+","+prey+")
        // "+minIndex+"("+minx+","+miny+") "+postIndex+"("+postx+","+posty+")");
        faceOK = postdx > 0;
      } else if (postdx == 0) {
        // the outbound line goes to the right
        // System.out.println("no postdx "+preIndex+"("+prex+","+prey+")
        // "+minIndex+"("+minx+","+miny+") "+postIndex+"("+postx+","+posty+")");

        faceOK = predx < 0;
      } else {
        // multiply it out a bit, we're losing precision, preferably this multiplier will be the
        // width
        // of the screen since that will ensure that it's longer than almost any value of dx
        int prem = (predy * 1024) / predx;
        int postm = (postdy * 1024) / postdx;
        // System.out.println("not vertical "+preIndex+"("+prex+","+prey+")
        // "+minIndex+"("+minx+","+miny+") "+postIndex+"("+postx+","+posty+")");
        if (prem == postm) {
          // it's flat
          faceOK = false;
        } else if (prem < 0 && postm < 0 || prem >= 0 && postm >= 0) {
          faceOK = prem > postm;
        } else {
          faceOK = prem < 0 && postm >= 0;
        }
        // or, more accurately (negatives dys and zeros are impossible in this context)
        // faceOK = predy * postdx > predx * postdy;
        //                    double prem =
        // (double)FixedMath.getInteger(predy)/(double)FixedMath.getInteger(predx);
        //                    double postm =
        // (double)FixedMath.getInteger(postdy)/(double)FixedMath.getInteger(postdx);
        //                    double preAngle = Math.atan(prem);
        //                    double postAngle = Math.atan(postm);
        //                    System.out.println(preAngle);
        //                    System.out.println(postAngle);
        //                    faceOK = preAngle < postAngle;
      }

      if (faceOK) {
        for (int j = faceIndices.length; j > 0; ) {
          j--;
          byte index = faceIndices[j];
          byte nextIndex = faceIndices[(j + 1) % faceIndices.length];

          // if a line with the same indices exists then we don't need to
          // add it again
          boolean found = false;
          for (int k = projectionMesh.lines.size(); k > 0; ) {
            k--;
            ProjectionLine line = (ProjectionLine) projectionMesh.lines.elementAt(k);
            if (line.fromIndex == index && line.toIndex == nextIndex
                || line.toIndex == index && line.fromIndex == nextIndex) {
              found = true;
              break;
            } else if (line.perimeter) {
              // the line's as long as it can be, hence may contain other lines
              if (line.fromIndex == index) {
                int[] common = points[index];
                int[] linePoint = points[line.toIndex];
                int[] testPoint = points[nextIndex];
                if (this.isLeft(common, linePoint, testPoint) == 0) {
                  found = true;
                  break;
                }
              } else if (line.toIndex == index) {
                int[] common = points[index];
                int[] linePoint = points[line.fromIndex];
                int[] testPoint = points[nextIndex];
                if (this.isLeft(common, linePoint, testPoint) == 0) {
                  found = true;
                  break;
                }
              } else if (line.fromIndex == nextIndex) {
                int[] common = points[nextIndex];
                int[] linePoint = points[line.toIndex];
                int[] testPoint = points[index];
                if (this.isLeft(common, linePoint, testPoint) == 0) {
                  found = true;
                  break;
                }
              } else if (line.toIndex == nextIndex) {
                int[] common = points[nextIndex];
                int[] linePoint = points[line.fromIndex];
                int[] testPoint = points[index];
                if (this.isLeft(common, linePoint, testPoint) == 0) {
                  found = true;
                  break;
                }
              } else {
                // TODO : implement this...
                // test to see if the line sits within the other although this
                // is probably a very unusual case
                found = false;
              }
            }
          }
          if (!found) {
            ProjectionLine line = new ProjectionLine(projectionMesh, index, nextIndex, false);
            projectionMesh.lines.addElement(line);
          }
        }
      } else {
        // System.out.println("culled "+i);
      }
    }

    this.projected.addElement(projectionMesh);
  }