001/* 002 * BGFGCanvas3D -- A Canvas3D that renders 2D background or overlay images with a 3D scene. 003 * 004 * Copyright (C) 2009-2023, by Joseph A. Huwaldt. 005 * All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public License 018 * along with this program; if not, write to the Free Software 019 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 020 * Or visit: http://www.gnu.org/licenses/lgpl.html 021 */ 022package jahuwaldt.j3d; 023 024import java.awt.GraphicsConfiguration; 025import java.awt.image.BufferedImage; 026import java.util.ArrayList; 027import java.util.Collections; 028import java.util.List; 029import static java.util.Objects.isNull; 030import static java.util.Objects.requireNonNull; 031import org.jogamp.java3d.*; 032 033/** 034 * BGFGCanvas3D is a <code>Canvas3D</code> that renders an list of arbitrary 2D 035 * {@link BGFGImage} objects either behind or over top of the 3D scene. This canvas also 036 * provides a callback that allows you to capture the contents of the canvas and write out 037 * the image information. 038 * 039 * <p> Modified by: Joseph A.Huwaldt </p> 040 * 041 * @author Joseph A. Huwaldt, Date: April 9, 2009 042 * @version June 4, 2023 043 */ 044public class BGFGCanvas3D extends ImageCaptureCanvas3D { 045 046 private static final long serialVersionUID = 1L; 047 048 // A list of background images. 049 private final List<BGFGImage> _backgrounds = Collections.synchronizedList(new ArrayList()); 050 051 // The list of overlays used by this canvas. 052 private final List<BGFGImage> _overlays = Collections.synchronizedList(new ArrayList()); 053 054 /** 055 * Constructs and initializes a new BGFGCanvas3D object that Java 3D can render into. 056 * 057 * @param gconfig A valid GraphicsConfiguration object that will be used to create the 058 * canvas. May not be null. 059 * @throws IllegalArgumentException if the specified GraphicsConfiguration does not 060 * support 3D rendering 061 */ 062 public BGFGCanvas3D(GraphicsConfiguration gconfig) { 063 super(requireNonNull(gconfig, "gconfig == null")); 064 } 065 066 /** 067 * Constructs and initializes a new BGFGCanvas3D object that Java 3D can render into. 068 * 069 * @param gconfig A valid GraphicsConfiguration object that will be used to create 070 * the canvas. May not be null. 071 * @param offscreen A flag that indicates whether this canvas is an off-screen 3D 072 * rendering canvas. Note that if offScreen is set to true, this 073 * Canvas3D object cannot be used for normal rendering; it should not 074 * be added to any Container object. 075 * @throws IllegalArgumentException if the specified GraphicsConfiguration does not 076 * support 3D rendering 077 */ 078 public BGFGCanvas3D(GraphicsConfiguration gconfig, boolean offscreen) { 079 super(requireNonNull(gconfig, "gconfig == null"), offscreen); 080 } 081 082 /** 083 * Returns the number of background images associated with this canvas. 084 * 085 * @return The number of background images. 086 */ 087 public int getNumberBackgrounds() { 088 return _backgrounds.size(); 089 } 090 091 /** 092 * Return the specified background used by this canvas. 093 * 094 * @param index The index of the background image to retrieve. 095 * @return The background image at the specified index. 096 */ 097 public BGFGImage getBackground(int index) { 098 return _backgrounds.get(index); 099 } 100 101 /** 102 * Set the specified background for use for this canvas. 103 * 104 * @param index The index for the background to set. 105 * @param background The background image to set at the specified index. May not be 106 * null. 107 * @return The image that was at the specified index location. 108 */ 109 public BGFGImage setBackground(int index, BGFGImage background) { 110 requireNonNull(background, "background == null"); 111 BGFGImage old = _backgrounds.set(index, background); 112 return old; 113 } 114 115 /** 116 * Adds the specified background to this canvas. 117 * 118 * @param background The background to add to this canvas. May not be null. 119 */ 120 public void addBackground(BGFGImage background) { 121 _backgrounds.add(requireNonNull(background, "background == null")); 122 } 123 124 /** 125 * Removes the specified background from this canvas. 126 * 127 * @param index The index for the background to remove. 128 * @return The image that used to be at the specified index. 129 */ 130 public BGFGImage removeBackground(int index) { 131 return _backgrounds.remove(index); 132 } 133 134 /** 135 * Removes the specified background from this canvas. 136 * 137 * @param background The background to remove from this canvas. May not be null. 138 * @return true if this canvas contained the specified background image. 139 */ 140 public boolean removeBackground(BGFGImage background) { 141 return _backgrounds.remove(requireNonNull(background, "background == null")); 142 } 143 144 /** 145 * Removes all the backgrounds from this canvas. 146 */ 147 public void clearBackgrounds() { 148 _backgrounds.clear(); 149 } 150 151 /** 152 * Returns the number of overlays/foregrounds associated with this canvas. 153 * 154 * @return The number of overlays. 155 */ 156 public int getNumberOverlays() { 157 return _overlays.size(); 158 } 159 160 /** 161 * Return the specified overlay used by this canvas. 162 * 163 * @param index The index of the overlay (foreground) to return. 164 * @return The overlay/foreground image at the specified index. 165 */ 166 public BGFGImage getOverlay(int index) { 167 return _overlays.get(index); 168 } 169 170 /** 171 * Set the specified overlay for use for this canvas. 172 * 173 * @param index The index for the overlay to set. 174 * @param overlay The overlay to set at the specified index location. May not be null. 175 * @return The image that was at the specified index location. 176 */ 177 public BGFGImage setOverlay(int index, BGFGImage overlay) { 178 return _overlays.set(index, requireNonNull(overlay, "overlay == null")); 179 } 180 181 /** 182 * Adds the specified overlay to this canvas. 183 * 184 * @param overlay The overlay to add. May not be null. 185 */ 186 public void addOverlay(BGFGImage overlay) { 187 _overlays.add(requireNonNull(overlay, "overlay == null")); 188 } 189 190 /** 191 * Removes the specified overlay from this canvas. 192 * 193 * @param index The index for the overlay to remove. 194 * @return The image that used to be at the specified index. 195 */ 196 public BGFGImage removeOverlay(int index) { 197 return _overlays.remove(index); 198 } 199 200 /** 201 * Removes the specified overlay from this canvas. 202 * 203 * @param overlay The overlay image to remove from this canvas. May not be null. 204 * @return true if this canvas contained the specified overlay/foreground image. 205 */ 206 public boolean removeOverlay(BGFGImage overlay) { 207 return _overlays.remove(requireNonNull(overlay, "overlay == null")); 208 } 209 210 /** 211 * Removes all the overlays from this canvas. 212 */ 213 public void clearOverlays() { 214 _overlays.clear(); 215 } 216 217 /** 218 * This routine is called by the Java 3D rendering loop after clearing the canvas and 219 * before any rendering has been done for this frame. This implementation renders any 220 * background images onto the canvas. Note that BGFGImage.getImage() is always called 221 * before getImageX() or getImageY(). 222 */ 223 @Override 224 public void preRender() { 225 super.preRender(); 226 if (!_backgrounds.isEmpty()) { 227 synchronized (_backgrounds) { 228 for (BGFGImage background : _backgrounds) { 229 // Get the overlay image. 230 BufferedImage bufim = background.getImage(); 231 if (isNull(bufim)) 232 continue; 233 234 // Get where the image should be drawn on the canvas. 235 int x = background.getImageX(); 236 int y = background.getImageY(); 237 238 // Draw and flush the image to the canvas. 239 J3DGraphics2D j3dg2d = this.getGraphics2D(); 240 j3dg2d.drawAndFlushImage(bufim, x, y, this); 241 } 242 } 243 } 244 } 245 246 /** 247 * This routine is called by the Java 3D rendering loop after completing all rendering 248 * to the canvas for this frame and before the buffer swap. This implementation 249 * renders any overlay images onto the canvas. Note that BGFGImage.getImage() is 250 * always called before getImageX() or getImageY(). 251 */ 252 @Override 253 public void postRender() { 254 super.postRender(); 255 if (!_overlays.isEmpty()) { 256 synchronized (_overlays) { 257 for (BGFGImage overlay : _overlays) { 258 // Get the overlay image. 259 BufferedImage bufim = overlay.getImage(); 260 if (isNull(bufim)) 261 continue; 262 263 // Get where the image should be drawn on the canvas. 264 int x = overlay.getImageX(); 265 int y = overlay.getImageY(); 266 267 // Draw and flush the image to the canvas. 268 J3DGraphics2D j3dg2d = this.getGraphics2D(); 269 j3dg2d.drawAndFlushImage(bufim, x, y, this); 270 } 271 } 272 } 273 } 274 275}