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
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