Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8232823

JVM crash when setting ObeservableFloatArray for points of TriangleMesh

    Details

    • Type: Bug
    • Status: Open
    • Priority: P4
    • Resolution: Unresolved
    • Affects Version/s: 8u221
    • Fix Version/s: tbd
    • Component/s: javafx
    • Labels:
    • Subcomponent:
    • CPU:
      x86_64
    • OS:
      windows_10

      Description

      ADDITIONAL SYSTEM INFORMATION :
      Windows 10, JRE version: Java(TM) SE Runtime Environment (8.0_221-b11) (build 1.8.0_221-b11)

      A DESCRIPTION OF THE PROBLEM :
      Fatal error (EXCEPTION_ACCESS_VIOLATION) when I modify the ObservableFloatArray for the points of a TriangleMesh of javafx after the mesh is rendered. But the crash happens even if I set its MeshView to be not visible and use Platform.runLater to set the points and make it visible.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Image: 948 x 946
      Mesh: 118 x 118
      27848 faces
      #
      # A fatal error has been detected by the Java Runtime Environment:
      #
      # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffc3e76caa7, pid=9812, tid=0x00000000000017bc
      #
      # JRE version: Java(TM) SE Runtime Environment (8.0_221-b11) (build 1.8.0_221-b11)
      # Java VM: Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode windows-amd64 compressed oops)
      # Problematic frame:
      # C [vcruntime140.dll+0xcaa7]
      #
      # Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
      #
      # An error report file with more information is saved as:
      # D:\workspace\JavaFX\hs_err_pid9812.log
      #
      # If you would like to submit a bug report, please visit:
      # http://bugreport.java.com/bugreport/crash.jsp
      # The crash happened outside the Java Virtual Machine in native code.
      # See problematic frame for where to report the bug.
      #


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Create a TriangleMesh (with VertexFormat.POINT_TEXCOORD), render it in a Scene and then modify the points with code like:
      private void randomize() {
      final int n=mesh.getPoints().size();
      double sum=0.0;
      for(int i=0;i<n;i++) {
      sum+=mesh.getPoints().get(i);
      }
      double mean = sum/n;
      float[] newValues = new float[n];
      for(int i=0;i<n;i++) {
      //int x=random.nextInt(numberOfTrianglesWidth);
      //int y=random.nextInt(numberOfTrianglesHeight);
      float f = mesh.getPoints().get(i);
      f += 0.1*mean*(random.nextFloat()-0.5f);
      newValues[i]=f;
      }
      mesh.getPoints().setAll(newValues); // Crash happens here
      }


      ---------- BEGIN SOURCE ----------
      import java.awt.Graphics2D;
      import java.awt.RenderingHints;
      import java.awt.image.BufferedImage;
      import java.io.File;
      import java.util.Map;
      import java.util.Random;
      import java.util.TreeMap;

      import javax.swing.JFileChooser;
      import javax.swing.filechooser.FileNameExtensionFilter;

      import javafx.application.Application;
      import javafx.application.Platform;
      import javafx.event.EventHandler;
      import javafx.geometry.Point3D;
      import javafx.scene.Cursor;
      import javafx.scene.DepthTest;
      import javafx.scene.Group;
      import javafx.scene.Node;
      import javafx.scene.PerspectiveCamera;
      import javafx.scene.Scene;
      import javafx.scene.image.Image;
      import javafx.scene.image.PixelReader;
      import javafx.scene.input.KeyEvent;
      import javafx.scene.input.MouseEvent;
      import javafx.scene.paint.Color;
      import javafx.scene.paint.PhongMaterial;
      import javafx.scene.shape.Box;
      import javafx.scene.shape.DrawMode;
      import javafx.scene.shape.MeshView;
      import javafx.scene.shape.Sphere;
      import javafx.scene.shape.TriangleMesh;
      import javafx.scene.shape.VertexFormat;
      import javafx.scene.transform.Rotate;
      import javafx.scene.transform.Translate;
      import javafx.stage.Stage;

      public class ExtrudeByColor extends Application {
      private final static int WIDTH = 1600;
      private final static int HEIGHT = 900;
      private static final Random random = new Random();
      private static final Map<Integer,PhongMaterial> mapFromColorToMaterial = new TreeMap<>();
      private final PerspectiveCamera camera = new PerspectiveCamera(true);
      private final XformCamera cameraXform = new XformCamera();
      private static double cameraInitialZ = -1300;
      private static double cameraInitialY = 50;
      private static final double CAMERA_NEAR_CLIP = 0.1;
      private static final double CAMERA_FAR_CLIP = 200000.0;
      private double mousePosX, mousePosY, mousePressX, mousePressY, mouseDeltaX, mouseDeltaY;
      private final Group root = new Group();
      private final XformWorld world = new XformWorld();
      private boolean adjustingSizes = false;
      private Stage primaryStage;
      private String titlePrefix = "3D Extruder";
      private final TriangleMesh mesh = new TriangleMesh();
      private int numberOfTrianglesWidth;
      private int numberOfTrianglesHeight;
      private static File imageFile = null;
      private static EventHandler<? super MouseEvent> sphereClickHandler =
      click -> {
      System.out.println("Click on " + click.getPickResult());
      Node node = click.getPickResult().getIntersectedNode();
      if (node instanceof Sphere) {
      if (click.isShiftDown()) {
      node.setTranslateZ(1+node.getTranslateZ());
      } else {
      node.setTranslateZ(-1+node.getTranslateZ());
      }
      }
      };
      private Box floor;
      private Group threeDImageGroup;
      //---
      // -------------------------
      private static class XformCamera extends Group {
      final Translate t = new Translate(0.0, 0.0, 0.0);
      final Rotate rx = new Rotate(0, 0, 0, 0, Rotate.X_AXIS);
      final Rotate ry = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS);
      final Rotate rz = new Rotate(0, 0, 0, 0, Rotate.Z_AXIS);

      public XformCamera() {
      super();
      this.getTransforms().addAll(t, rx, ry, rz);
      }
      }
      // -------------------------
      private static class XformWorld extends Group {
      final Translate t = new Translate(0.0, 0.0, 0.0);
      final Rotate rx = new Rotate(0, 0, 0, 0, Rotate.X_AXIS);
      final Rotate ry = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS);
      final Rotate rz = new Rotate(0, 0, 0, 0, Rotate.Z_AXIS);

      public XformWorld() {
      super();
      this.getTransforms().addAll(t, rx, ry, rz);
      }
      }
      private void buildCamera() {
      root.getChildren().add(cameraXform);
      cameraXform.getChildren().add(camera);
      camera.setNearClip(CAMERA_NEAR_CLIP);
      camera.setFarClip(CAMERA_FAR_CLIP);
      camera.setTranslateZ(cameraInitialZ);
      camera.setTranslateY(cameraInitialY);
      }
      //--------------------
      private void handleKeyEvents(Scene scene) {
      scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
      public void handle(KeyEvent ke) {
      switch (ke.getCode()) {
      case Q:
      System.exit(0);
      break;
      case H:
      floor.setVisible(!floor.isVisible());
      break;
      case A:
      adjustingSizes = !adjustingSizes;
      System.out.println((adjustingSizes ? "A": "Not a") + "djusting sizes");
      Platform.runLater(new Runnable() {
      @Override
      public void run() {
      primaryStage.getScene().setCursor(adjustingSizes? Cursor.OPEN_HAND: Cursor.DEFAULT);
      }
      });
      break;
      case R:
      randomize();
      // cameraXform.t.setZ(0);
      // cameraXform.rx.setAngle(0);
      // cameraXform.ry.setAngle(0);
      // camera.setTranslateX(0);
      // camera.setTranslateY(cameraInitialY);
      // camera.setTranslateZ(cameraInitialZ);
      break;
      case LEFT:
      camera.setTranslateX(camera.getTranslateX() - 10);
      break;
      case RIGHT:
      camera.setTranslateX(camera.getTranslateX() + 10);
      break;
      case UP:
      if (ke.isShiftDown()) {
      camera.setTranslateY(camera.getTranslateY() - 10);
      } else {
      camera.setTranslateZ(camera.getTranslateZ()+10);
      }
      break;
      case DOWN:
      if (ke.isShiftDown()) {
      camera.setTranslateY(camera.getTranslateY() + 10);
      } else {
      camera.setTranslateZ(camera.getTranslateZ()-10);
      }
      break;
      case PAGE_UP:
      break;
      case PAGE_DOWN:
      case C:
      if (ke.isShiftDown()) {
      } else {
      }
      break;
      default:
      }
      }
      });
      }
      //--------------------------------------
      private void adjustSizes(MouseEvent event) {

      }

      private void addFloor(Image image) {
      PhongMaterial floorMaterial = new PhongMaterial();
      floor = new Box(image.getWidth(), image.getHeight(),1);
      //floorMaterial.setDiffuseMap(new Image("file:imgs/wood6.jpg"));
      floorMaterial.setDiffuseMap(image);
      floor.setMaterial(floorMaterial);
      floor.setTranslateX(-300);
      floor.setTranslateY(0);
      floor.setTranslateZ(300); // +Z is in towards the screen
      root.getChildren().add(floor);
      }
      //-------------------------------
      private void handleMouse(Scene scene) {
      final double bigSize = 10;
      scene.setOnMousePressed((MouseEvent me) -> {
      mousePosX = me.getSceneX();
      mousePosY = me.getSceneY();
      mousePressX = me.getSceneX();
      mousePressY = me.getSceneY();
      //adjustingSizes= me.isShiftDown();
      if (adjustingSizes) {
      System.out.println("Starting adjusting sizes");
      primaryStage.setTitle(titlePrefix + " (Drag and release to select the area to extrude)");
      }
      // this is done after clicking and the rotations are apparently
      // performed in coordinates that are NOT rotated with the camera.
      // (pls activate the two lines below for clicking)
      // cameraXform.rx.setAngle(-90.0);
      // cameraXform.ry.setAngle(180.0);

      });
      scene.setOnMouseReleased((MouseEvent me) -> {
      if (adjustingSizes) {
      mousePosX = me.getSceneX();
      mousePosY = me.getSceneY();
      primaryStage.setTitle(titlePrefix + " (Use arrow keys to extrude up or down)");
      System.out.println("Released during adjustingSizes");
      }
      });
      // scene.setOnDragEntered(me -> {
      // });
      // scene.setOnMouseDragExited((MouseEvent me) -> {
      // });
      scene.setOnMouseDragged((MouseEvent me) -> {
      if (adjustingSizes) {
      return;
      }
      mousePressX = mousePosX;
      mousePressY = mousePosY;
      mousePosX = me.getSceneX();
      mousePosY = me.getSceneY();
      mouseDeltaX = (mousePosX - mousePressX);
      mouseDeltaY = (mousePosY - mousePressY);
      if (me.isPrimaryButtonDown() && me.isSecondaryButtonDown()) {
      world.t.setZ(world.t.getZ() + mouseDeltaX);
      } else if (me.isPrimaryButtonDown()) {
      // this is done when the mouse is dragged and each rotation is
      // performed in coordinates, that are rotated with the camera.
      world.ry.setAngle(world.ry.getAngle() - mouseDeltaX * 0.2);
      world.rx.setAngle(world.rx.getAngle() + mouseDeltaY * 0.2);

      // world.ry.setAngle(world.ry.getAngle() + mouseDeltaX * 0.2);
      // world.rx.setAngle(world.rx.getAngle() - mouseDeltaY * 0.2);
      } else if (me.isSecondaryButtonDown()) {
      world.t.setY(world.t.getY() + mouseDeltaY);
      world.t.setX(world.t.getX() + mouseDeltaX);
      }
      });
      }

      public static BufferedImage scale(BufferedImage original, int newWidth, int newHeight) {
                  BufferedImage resized = new BufferedImage(newWidth, newHeight, original.getType());
                  Graphics2D g = resized.createGraphics();
                  g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                      RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                  g.drawImage(original, 0, 0, newWidth, newHeight, 0, 0, original.getWidth(),
                      original.getHeight(), null);
                  g.dispose();
                  return resized;
          }
      private static void chooseImageFile() {
      String directoryPath = "d:/pictures";
      JFileChooser chooser = new JFileChooser(directoryPath);
      FileNameExtensionFilter filter = new FileNameExtensionFilter(
      "Image", "jpg", "png", "JPG");
      chooser.setFileFilter(filter);
      int returnVal = chooser.showOpenDialog(null);
      String inFilename=null;
      if(returnVal == JFileChooser.APPROVE_OPTION) {
      inFilename = chooser.getSelectedFile().getAbsolutePath();
      imageFile = new File(inFilename);
      } else {
      System.exit(0);
      }
      }

      //-------------------------------
      public static Group create3DWithSpheresFromImage(BufferedImage image) {
      final int target =640;
      if (image.getWidth()>= image.getHeight() && image.getWidth() > target) {
      double newHeight = ((0.0+target)/image.getWidth())*image.getHeight();
      image = scale(image, target, (int)newHeight);
      } else if (image.getHeight()> target) {
      double newWidth = ((0.0+target)/image.getHeight())* image.getWidth();
      image = scale(image, (int)newWidth, target);
      }
      final Group group = new Group();
      int width=image.getWidth();
      int height = image.getHeight();
      int countSpheres = 0;
      for(int row=0;row<height;row++) {
      for(int col=0;col<width;col++) {
      if (random.nextInt(4)>0) {
      continue;
      }
      Integer colorInt=image.getRGB(col,row);
      int blue = colorInt&255;
      int green = (colorInt>>8)&255;
      int red = (colorInt>>16)&255;
      if (red+blue+green < 32) {
      continue;
      }
      countSpheres++;
      PhongMaterial material = mapFromColorToMaterial.get(colorInt);
      if (material == null) {
      Color color = new Color(red/255.0, green/255.0, blue/255.0,1);
      material = new PhongMaterial(color);
      mapFromColorToMaterial.put(colorInt, material);
      }
      Sphere sphere = new Sphere(1);
      //sphere.setScaleX((red+50)/10);
      //sphere.setScaleY((blue+50)/10);
      //sphere.setScaleZ((green+50)/10);
      sphere.setOnMouseClicked( sphereClickHandler);
      sphere.setScaleZ((0.5+material.getDiffuseColor().getBrightness())*30);
      sphere.setMaterial(material);
      sphere.setTranslateX(col);
      sphere.setTranslateY(row);
      group.getChildren().add(sphere);
      }
      }
      System.out.println(countSpheres + " spheres, " + mapFromColorToMaterial.size() + " entries in mapFromColorToMaterial");
      return group;
      }
      //-------------------------------
      /**
      *
      * @param image
      * @param quality 1 = highest (slow!)
      * @return
      */
      private TriangleMesh create3DWithMeshFromImage(Image image, int quality) {
      final int imageWidth=(int)image.getWidth();
      final int imageHeight = (int)image.getHeight();
      System.out.println("Image: " + imageWidth + " x " + imageHeight);
      numberOfTrianglesWidth = (int)(image.getWidth()/quality);
      numberOfTrianglesHeight = (int) (image.getHeight()/quality);
      System.out.println("Mesh: " + numberOfTrianglesWidth + " x " + numberOfTrianglesHeight);

      final PixelReader pixelReader = image.getPixelReader();
      final float colorFactor = 0.0f; //-25.0f;
      mesh.setVertexFormat(VertexFormat.POINT_TEXCOORD);
      int pointIndex=0;
      int texIndex=0;
      int faces=0;
      for(int x= 0;x<numberOfTrianglesWidth;x++) {
      final float x1=x+1.0f;
      for(int y=0;y<numberOfTrianglesHeight;y++) {
      final float y1 = y+1.0f;
      // Add 4 points, 2 faces, and 4 tex coordinates
      // TODO: make z depend on color
      final float x0Ratio = (x+0.0f)/numberOfTrianglesWidth;
      final float y0Ratio = (y+0.0f)/numberOfTrianglesHeight;
      final float x1Ratio = 0.9999f*x1/numberOfTrianglesWidth;
      final float y1Ratio = 0.9999f*y1/numberOfTrianglesHeight;
      Color colorUpperLeft = pixelReader.getColor((int)Math.floor(x0Ratio*imageWidth), (int)Math.floor(y0Ratio*imageHeight));
      Color colorUpperRight = pixelReader.getColor((int)Math.floor(x1Ratio*imageWidth), (int)Math.floor(y0Ratio*imageHeight));
      Color colorLowerLeft = pixelReader.getColor((int)Math.floor(x0Ratio*imageWidth), (int)Math.floor(y1Ratio*imageHeight));
      Color colorLowerRight = pixelReader.getColor((int)Math.floor(x1Ratio*imageWidth), (int)Math.floor(y1Ratio*imageHeight));
      mesh.getPoints().addAll(
      x,y,colorFactor*(float)colorUpperLeft.getBrightness(), // upper-left
      x+1,y,colorFactor*(float)colorUpperRight.getBrightness(), // upper-right
      x+1,y+1,colorFactor*(float)colorLowerRight.getBrightness(), // lower-right
      x,y+1,colorFactor*(float)colorLowerLeft.getBrightness()); // lower-left
      mesh.getTexCoords().addAll(
      x0Ratio, y0Ratio, // upper-left
      x1Ratio, y0Ratio, // upper-right
      x1Ratio, y1Ratio, // lower-right
      x0Ratio, y1Ratio // lower-left
      );
      mesh.getFaces().addAll(
      pointIndex,texIndex,
      pointIndex+1, texIndex+1,
      pointIndex+2, texIndex+2,
      //
      pointIndex+2, texIndex+2,
      pointIndex+3,texIndex+3,
      pointIndex, texIndex
      );
      pointIndex+=4;
      texIndex+=4;
      faces+=2;
      }
      }
      System.out.println(faces + " faces");
      return mesh;
      }

      private void randomize() {
      final int n=mesh.getPoints().size();
      double sum=0.0;
      for(int i=0;i<n;i++) {
      sum+=mesh.getPoints().get(i);
      }
      double mean = sum/n;
      float[] newValues = new float[n];
      for(int i=0;i<n;i++) {
      //int x=random.nextInt(numberOfTrianglesWidth);
      //int y=random.nextInt(numberOfTrianglesHeight);
      float f = mesh.getPoints().get(i);
      f += 0.1*mean*(random.nextFloat()-0.5f);
      newValues[i]=f;
      }
      mesh.getPoints().setAll(newValues);
      }

      @Override
      public void start(Stage primaryStage) throws Exception {
      this.primaryStage = primaryStage;
      Image image = new Image("file:" + imageFile.getAbsolutePath());
      TriangleMesh mesh = create3DWithMeshFromImage(image,8);
      MeshView meshView = new MeshView(mesh);
      meshView.setDrawMode(DrawMode.FILL);
      PhongMaterial material = new PhongMaterial();
      material.setDiffuseMap(image);
      meshView.setMaterial(material);
      threeDImageGroup = // create3DWithSpheresFromImage(image);
      new Group();
      threeDImageGroup.getChildren().add(meshView);
      threeDImageGroup.setTranslateX(-150);
      threeDImageGroup.setTranslateY(-50);
      threeDImageGroup.setScaleX(2.5);
      threeDImageGroup.setScaleY(2.5);
      threeDImageGroup.setRotationAxis(new Point3D(0,1,0));
      threeDImageGroup.setRotate(180);

      world.getChildren().add(threeDImageGroup);
      addFloor(image);
      floor.setVisible(false);
      root.getChildren().add(world);
      root.setDepthTest(DepthTest.ENABLE);
      Scene scene = new Scene(root, WIDTH, HEIGHT, true);
      scene.setFill(Color.DARKGREY.darker().darker());
      primaryStage.setTitle(titlePrefix );
      primaryStage.setScene(scene);
      handleMouse(scene);
      handleKeyEvents(scene);
      buildCamera();
      scene.setCamera(camera);
      primaryStage.show();
      }


      public static void main(String[] args) {
      try {
      chooseImageFile();
      launch(args);
      } catch (Throwable thr) {
      thr.printStackTrace();
      System.exit(1);
      }
      }
      }

      ---------- END SOURCE ----------

      FREQUENCY : always


        Attachments

          Activity

            People

            • Assignee:
              kcr Kevin Rushforth
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated: