84
84
import javax.media.j3d.J3DGraphics2D;
85
85
import javax.media.j3d.Light;
86
86
import javax.media.j3d.Node;
87
import javax.media.j3d.OrderedGroup;
87
88
import javax.media.j3d.Shape3D;
88
89
import javax.media.j3d.Texture;
89
90
import javax.media.j3d.Transform3D;
99
100
import javax.swing.JButton;
100
101
import javax.swing.JComponent;
101
102
import javax.swing.JPanel;
103
import javax.swing.JPopupMenu;
102
104
import javax.swing.KeyStroke;
103
105
import javax.swing.RepaintManager;
104
106
import javax.swing.SwingUtilities;
244
246
public void canvas3DPostRendered(Canvas3D canvas3D) {
247
// Copy reference to navigation panel image to avoid concurrency problems
248
// if it's modified in the EDT while this method draws it
249
BufferedImage navigationPanelImage = HomeComponent3D.this.navigationPanelImage;
245
250
// Render navigation panel upon canvas 3D if it exists
246
251
if (navigationPanelImage != null) {
247
252
J3DGraphics2D g2D = canvas3D.getGraphics2D();
520
525
imageSize.add(componentBounds.x + componentBounds.width,
521
526
componentBounds.y + componentBounds.height);
522
527
if (!imageSize.isEmpty()) {
528
BufferedImage updatedImage = this.navigationPanelImage;
529
// Consider that no navigation panel image is available
530
// while it's updated
531
this.navigationPanelImage = null;
524
if (this.navigationPanelImage == null
525
|| this.navigationPanelImage.getWidth() != imageSize.width
526
|| this.navigationPanelImage.getHeight() != imageSize.height) {
527
this.navigationPanelImage = new BufferedImage(
533
if (updatedImage == null
534
|| updatedImage.getWidth() != imageSize.width
535
|| updatedImage.getHeight() != imageSize.height) {
536
updatedImage = new BufferedImage(
528
537
imageSize.width, imageSize.height, BufferedImage.TYPE_INT_ARGB);
529
g2D = (Graphics2D)this.navigationPanelImage.getGraphics();
538
g2D = (Graphics2D)updatedImage.getGraphics();
532
g2D = (Graphics2D)this.navigationPanelImage.getGraphics();
541
g2D = (Graphics2D)updatedImage.getGraphics();
533
542
Composite oldComposite = g2D.getComposite();
534
543
g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0));
535
544
g2D.fill(new Rectangle2D.Double(0, 0, imageSize.width, imageSize.height));
900
911
public void mouseReleased(MouseEvent ev) {
901
912
if (!retargetMouseEventToNavigationPanelChildren(ev)) {
902
913
if (ev.isPopupTrigger()) {
903
getComponentPopupMenu().show(HomeComponent3D.this, ev.getX(), ev.getY());
914
JPopupMenu componentPopupMenu = getComponentPopupMenu();
915
if (componentPopupMenu != null) {
916
componentPopupMenu.show(HomeComponent3D.this, ev.getX(), ev.getY());
1165
1179
BranchGroup root = new BranchGroup();
1167
1181
// Build scene tree
1168
root.addChild(createHomeTree(displayShadowOnFloor, listenToHomeUpdates, waitForLoading));
1169
1182
root.addChild(createBackgroundNode(listenToHomeUpdates));
1170
root.addChild(createGroundNode(-1E5f / 2, -1E5f / 2, 1E5f, 1E5f, listenToHomeUpdates, waitForLoading));
1184
Group groundAndRoomsGroup = createExtensibleGroup(true);
1185
// Add first ground then home rooms to an ordered group to ensure ground is always drawn behind floors
1186
groundAndRoomsGroup.addChild(createGroundNode(-1E5f / 2, -1E5f / 2, 1E5f, 1E5f, listenToHomeUpdates, waitForLoading));
1187
for (Room room : this.home.getRooms()) {
1188
addObject(groundAndRoomsGroup, room, waitForLoading);
1190
root.addChild(groundAndRoomsGroup);
1192
Group wallsAndFurnitureGroup = createExtensibleGroup(false);
1193
// Add walls and pieces already available in a normal group
1194
// (transparent shapes don't work well in ordered groups)
1195
for (Wall wall : this.home.getWalls()) {
1196
addObject(wallsAndFurnitureGroup, wall, waitForLoading);
1198
for (HomePieceOfFurniture piece : this.home.getFurniture()) {
1199
addObject(wallsAndFurnitureGroup, piece, waitForLoading);
1201
if (displayShadowOnFloor) {
1202
addShadowOnFloor(groundAndRoomsGroup);
1204
root.addChild(wallsAndFurnitureGroup);
1206
// Add default lights
1171
1207
for (Light light : createLights(listenToHomeUpdates)) {
1172
1208
root.addChild(light);
1211
if (listenToHomeUpdates) {
1212
// Add wall, furniture, room listeners to home for further update
1213
addWallListener(wallsAndFurnitureGroup);
1214
addFurnitureListener(wallsAndFurnitureGroup);
1215
addRoomListener(groundAndRoomsGroup, 1);
1216
// Add environment listeners
1217
addEnvironmentListeners();
1218
// Should update shadow on floor too but in the facts
1219
// User Interface doesn't propose to modify the furniture of a home
1220
// that displays shadow on floor yet
1365
1413
(lightColor & 0xFF) / 256f * defaultColor.z));
1366
1414
clearPrintedImageCache();
1370
* Returns a <code>home</code> new tree node, with branches for each wall
1371
* and piece of furniture of <code>home</code>.
1373
private Node createHomeTree(boolean displayShadowOnFloor,
1374
boolean listenToHomeUpdates,
1375
boolean waitForLoading) {
1376
Group homeRoot = createHomeRoot();
1377
// Add walls, pieces and rooms already available
1378
for (Wall wall : this.home.getWalls()) {
1379
addObject(homeRoot, wall, waitForLoading);
1381
for (HomePieceOfFurniture piece : this.home.getFurniture()) {
1382
addObject(homeRoot, piece, waitForLoading);
1384
for (Room room : this.home.getRooms()) {
1385
addObject(homeRoot, room, waitForLoading);
1388
if (displayShadowOnFloor) {
1389
addShadowOnFloor(homeRoot);
1392
if (listenToHomeUpdates) {
1393
// Add wall, furniture, room listeners to home for further update
1394
addWallListener(homeRoot);
1395
addFurnitureListener(homeRoot);
1396
addRoomListener(homeRoot);
1397
// Add environment listeners
1398
addEnvironmentListeners();
1399
// Should update shadow on floor too but in the facts
1400
// User Interface doesn't propose to modify the furniture of a home
1401
// that displays shadow on floor yet
1407
* Returns a new group at home subtree root.
1409
private Group createHomeRoot() {
1410
Group homeGroup = new Group();
1417
* Returns a new extensible group.
1419
private Group createExtensibleGroup(boolean ordered) {
1420
Group homeGroup = ordered
1421
? new OrderedGroup()
1411
1423
// Allow group to have new children
1412
1424
homeGroup.setCapability(Group.ALLOW_CHILDREN_WRITE);
1413
1425
homeGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND);
1418
* Adds a wall listener to home walls
1419
* that updates the scene <code>homeRoot</code>, each time a wall is added, updated or deleted.
1430
* Adds a wall listener to home walls that updates the children of the given
1431
* <code>group</code>, each time a wall is added, updated or deleted.
1421
private void addWallListener(final Group homeRoot) {
1433
private void addWallListener(final Group group) {
1422
1434
this.wallChangeListener = new PropertyChangeListener() {
1423
1435
public void propertyChange(PropertyChangeEvent ev) {
1424
1436
updateWall((Wall)ev.getSource());
1433
1445
Wall wall = ev.getItem();
1434
1446
switch (ev.getType()) {
1436
addObject(homeRoot, wall, false);
1448
addObject(group, wall, false);
1437
1449
wall.addPropertyChangeListener(wallChangeListener);
1451
* Adds a furniture listener to home that updates the scene <code>homeRoot</code>,
1463
* Adds a furniture listener to home that updates the children of the given <code>group</code>,
1452
1464
* each time a piece of furniture is added, updated or deleted.
1454
private void addFurnitureListener(final Group homeRoot) {
1466
private void addFurnitureListener(final Group group) {
1455
1467
this.furnitureChangeListener = new PropertyChangeListener() {
1456
1468
public void propertyChange(PropertyChangeEvent ev) {
1457
switch (HomePieceOfFurniture.Property.valueOf(ev.getPropertyName())) {
1467
case MODEL_MIRRORED:
1469
if (HomePieceOfFurniture.Property.X.name().equals(ev.getPropertyName())
1470
|| HomePieceOfFurniture.Property.X.name().equals(ev.getPropertyName())
1471
|| HomePieceOfFurniture.Property.Y.name().equals(ev.getPropertyName())
1472
|| HomePieceOfFurniture.Property.ANGLE.name().equals(ev.getPropertyName())
1473
|| HomePieceOfFurniture.Property.WIDTH.name().equals(ev.getPropertyName())
1474
|| HomePieceOfFurniture.Property.DEPTH.name().equals(ev.getPropertyName())
1475
|| HomePieceOfFurniture.Property.HEIGHT.name().equals(ev.getPropertyName())
1476
|| HomePieceOfFurniture.Property.ELEVATION.name().equals(ev.getPropertyName())
1477
|| HomePieceOfFurniture.Property.COLOR.name().equals(ev.getPropertyName())
1478
|| HomePieceOfFurniture.Property.TEXTURE.name().equals(ev.getPropertyName())
1479
|| HomePieceOfFurniture.Property.MODEL_MIRRORED.name().equals(ev.getPropertyName())
1480
|| HomePieceOfFurniture.Property.VISIBLE.name().equals(ev.getPropertyName())) {
1469
1481
HomePieceOfFurniture piece = (HomePieceOfFurniture)ev.getSource();
1470
1482
updateObjects(Arrays.asList(new HomePieceOfFurniture [] {piece}));
1471
1483
// If piece is or contains a door or a window, update walls that intersect with piece
1472
1484
if (containsDoorsAndWindows(piece)) {
1473
1485
updateObjects(home.getWalls());
1484
1495
HomePieceOfFurniture piece = (HomePieceOfFurniture)ev.getItem();
1485
1496
switch (ev.getType()) {
1487
addObject(homeRoot, piece, false);
1498
addObject(group, piece, false);
1488
1499
piece.addPropertyChangeListener(furnitureChangeListener);
1521
* Adds a room listener to home rooms that updates the scene
1522
* <code>homeRoot</code>, each time a room is added, updated or deleted.
1532
* Adds a room listener to home rooms that updates the children of the given
1533
* <code>group</code>, each time a room is added, updated or deleted.
1524
private void addRoomListener(final Group homeRoot) {
1535
private void addRoomListener(final Group group, final int indexOffset) {
1525
1536
this.roomChangeListener = new PropertyChangeListener() {
1526
1537
public void propertyChange(PropertyChangeEvent ev) {
1527
1538
updateObjects(Arrays.asList(new Room [] {(Room)ev.getSource()}));
1536
1547
Room room = ev.getItem();
1537
1548
switch (ev.getType()) {
1539
addObject(homeRoot, room, false);
1550
// Add room to its group at the index indicated by the event
1551
// to ensure the 3D rooms are drawn in the same order as in the plan
1552
addObject(group, room, ev.getIndex() + indexOffset, false);
1540
1553
room.addPropertyChangeListener(roomChangeListener);
1576
* Adds to <code>homeRoot</code> a wall branch matching <code>wall</code>.
1578
private void addObject(Group homeRoot, Selectable homeObject, boolean waitForLoading) {
1589
* Adds to <code>group</code> a branch matching <code>homeObject</code>.
1591
private void addObject(Group group, Selectable homeObject, boolean waitForLoading) {
1592
addObject(group, homeObject, -1, waitForLoading);
1596
* Adds to <code>group</code> a branch matching <code>homeObject</code> at a given <code>index</code>.
1597
* If <code>index</code> is equal to -1, <code>homeObject</code> will be added at the end of the group.
1599
private void addObject(Group group, Selectable homeObject, int index, boolean waitForLoading) {
1579
1600
Object3DBranch object3D = createObject3D(homeObject, waitForLoading);
1580
1601
this.homeObjects.put(homeObject, object3D);
1581
homeRoot.addChild(object3D);
1603
group.addChild(object3D);
1605
group.insertChild(object3D, index);
1582
1607
clearPrintedImageCache();