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