001/* 002 * To change this license header, choose License Headers in Project Properties. 003 * To change this template file, choose Tools | Templates 004 * and open the template in the editor. 005 */ 006 007package org.openstreetmap.josm.plugins.streetside.cubemap; 008 009import java.awt.image.BufferedImage; 010 011import org.openstreetmap.josm.plugins.streetside.utils.GraphicsUtils; 012 013import javafx.animation.AnimationTimer; 014import javafx.beans.property.DoubleProperty; 015import javafx.beans.property.SimpleDoubleProperty; 016import javafx.geometry.Rectangle2D; 017import javafx.scene.Group; 018import javafx.scene.PerspectiveCamera; 019import javafx.scene.image.Image; 020import javafx.scene.image.ImageView; 021import javafx.scene.transform.Affine; 022import javafx.scene.transform.Rotate; 023import javafx.scene.transform.Transform; 024 025/** 026 * @author renerr18 027 */ 028@SuppressWarnings("restriction") 029public class CubemapBox extends Group { 030 031 public enum CubemapBoxImageType { 032 MULTIPLE, SINGLE 033 } 034 035 private final Affine affine = new Affine(); 036 037 private final ImageView front = new ImageView(), right = new ImageView(), back = new ImageView(), 038 left = new ImageView(), up = new ImageView(), down = new ImageView(); 039 040 { 041 front.setId(CubemapUtils.CubemapFaces.FRONT.getValue()); 042 right.setId(CubemapUtils.CubemapFaces.RIGHT.getValue()); 043 back.setId(CubemapUtils.CubemapFaces.BACK.getValue()); 044 left.setId(CubemapUtils.CubemapFaces.LEFT.getValue()); 045 up.setId(CubemapUtils.CubemapFaces.UP.getValue()); 046 down.setId(CubemapUtils.CubemapFaces.DOWN.getValue()); 047 048 } 049 private final ImageView[] views = new ImageView[] { front, right, back, left, up, down }; 050 051 private Image frontImg, rightImg, backImg, leftImg, upImg, downImg, singleImg; 052 053 private final PerspectiveCamera camera; 054 private AnimationTimer timer; 055 private final CubemapBoxImageType imageType; 056 057 public CubemapBox( 058 Image frontImg, Image rightImg, Image backImg, Image leftImg, Image upImg, Image downImg, double size, 059 PerspectiveCamera camera) { 060 061 super(); 062 063 imageType = CubemapBoxImageType.MULTIPLE; 064 065 this.frontImg = frontImg; 066 this.rightImg = rightImg; 067 this.backImg = backImg; 068 this.leftImg = leftImg; 069 this.upImg = upImg; 070 this.downImg = downImg; 071 this.size.set(size); 072 this.camera = camera; 073 074 loadImageViews(); 075 076 getTransforms().add(affine); 077 078 getChildren().addAll(views); 079 080 startTimer(); 081 } 082 083 public void loadImageViews() { 084 085 for (ImageView iv : views) { 086 iv.setSmooth(true); 087 iv.setPreserveRatio(true); 088 } 089 090 validateImageType(); 091 } 092 093 private void layoutViews() { 094 095 for (ImageView v : views) { 096 v.setFitWidth(getSize()); 097 v.setFitHeight(getSize()); 098 } 099 100 back.setTranslateX(-0.5 * getSize()); 101 back.setTranslateY(-0.5 * getSize()); 102 back.setTranslateZ(-0.5 * getSize()); 103 104 front.setTranslateX(-0.5 * getSize()); 105 front.setTranslateY(-0.5 * getSize()); 106 front.setTranslateZ(0.5 * getSize()); 107 front.setRotationAxis(Rotate.Z_AXIS); 108 front.setRotate(-180); 109 front.getTransforms().add(new Rotate(180, front.getFitHeight() / 2, 0, 0, Rotate.X_AXIS)); 110 front.setTranslateY(front.getTranslateY() - getSize()); 111 112 up.setTranslateX(-0.5 * getSize()); 113 up.setTranslateY(-1 * getSize()); 114 up.setRotationAxis(Rotate.X_AXIS); 115 up.setRotate(-90); 116 117 down.setTranslateX(-0.5 * getSize()); 118 down.setTranslateY(0); 119 down.setRotationAxis(Rotate.X_AXIS); 120 down.setRotate(90); 121 122 left.setTranslateX(-1 * getSize()); 123 left.setTranslateY(-0.5 * getSize()); 124 left.setRotationAxis(Rotate.Y_AXIS); 125 left.setRotate(90); 126 127 right.setTranslateX(0); 128 right.setTranslateY(-0.5 * getSize()); 129 right.setRotationAxis(Rotate.Y_AXIS); 130 right.setRotate(-90); 131 132 } 133 134 /** 135 * for single image creates viewports and sets all views(image) to singleImg for multiple... sets images per view. 136 */ 137 private void validateImageType() { 138 switch (imageType) { 139 case SINGLE: 140 loadSingleImageViewports(); 141 break; 142 case MULTIPLE: 143 setMultipleImages(); 144 break; 145 } 146 } 147 148 private void loadSingleImageViewports() { 149 layoutViews(); 150 double width = singleImg.getWidth(), height = singleImg.getHeight(); 151 152 // simple check to see if cells will be square 153 if (width / 4 != height / 3) { 154 throw new UnsupportedOperationException("Image does not comply with size constraints"); 155 } 156 double cellSize = singleImg.getWidth() - singleImg.getHeight(); 157 158 recalculateSize(cellSize); 159 160 double topx = cellSize, topy = 0, 161 162 botx = cellSize, boty = cellSize * 2, 163 164 leftx = 0, lefty = cellSize, 165 166 rightx = cellSize * 2, righty = cellSize, 167 168 fwdx = cellSize, fwdy = cellSize, 169 170 backx = cellSize * 3, backy = cellSize; 171 172 // add top padding x+, y+, width-, height 173 up.setViewport(new Rectangle2D(topx, topy, cellSize, cellSize)); 174 175 // add left padding x, y+, width, height- 176 left.setViewport(new Rectangle2D(leftx, lefty, cellSize - 1, cellSize - 1)); 177 178 // add front padding x+, y+, width-, height 179 front.setViewport(new Rectangle2D(fwdx, fwdy, cellSize, cellSize)); 180 181 // add right padding x, y+, width, height- 182 right.setViewport(new Rectangle2D(rightx, righty, cellSize, cellSize)); 183 184 // add back padding x, y+, width, height- 185 back.setViewport(new Rectangle2D(backx + 1, backy - 1, cellSize - 1, cellSize - 1)); 186 187 // add bottom padding x+, y, width-, height- 188 down.setViewport(new Rectangle2D(botx, boty, cellSize, cellSize)); 189 190 for (ImageView v : views) { 191 v.setImage(singleImg); 192 } 193 } 194 195 private void recalculateSize(double cell) { 196 double factor = Math.floor(getSize() / cell); 197 setSize(cell * factor); 198 } 199 200 public synchronized void setImage(BufferedImage img, int position) { 201 views[position].setImage(GraphicsUtils.convertBufferedImage2JavaFXImage(img)); 202 203 } 204 205 private void setMultipleImages() { 206 GraphicsUtils.PlatformHelper.run(() -> { 207 layoutViews(); 208 front.setImage(frontImg); 209 right.setImage(rightImg); 210 back.setImage(backImg); 211 left.setImage(leftImg); 212 up.setImage(upImg); 213 down.setImage(downImg); 214 215 }); 216 } 217 218 public void startTimer() { 219 timer = new AnimationTimer() { 220 @Override 221 public void handle(long now) { 222 Transform ct = (camera != null) ? camera.getLocalToSceneTransform() : null; 223 if (ct != null) { 224 affine.setTx(ct.getTx()); 225 affine.setTy(ct.getTy()); 226 affine.setTz(ct.getTz()); 227 } 228 } 229 }; 230 timer.start(); 231 } 232 233 /* 234 * Properties 235 */ 236 private final DoubleProperty size = new SimpleDoubleProperty() { 237 @Override 238 protected void invalidated() { 239 switch (imageType) { 240 case SINGLE: 241 layoutViews(); 242 break; 243 case MULTIPLE: 244 break; 245 } 246 247 } 248 }; 249 250 public final double getSize() { 251 return size.get(); 252 } 253 254 public final void setSize(double value) { 255 size.set(value); 256 } 257 258 public DoubleProperty sizeProperty() { 259 return size; 260 } 261 262 public ImageView[] getViews() { 263 return views; 264 } 265}