001 package com.croftsoft.apps.tile; 002 003 import java.applet.*; 004 import java.awt.*; 005 import java.awt.image.BufferStrategy; 006 import java.awt.event.*; 007 import java.awt.geom.*; 008 import java.awt.image.BufferedImage; 009 import java.io.*; 010 import java.net.URL; 011 import java.util.*; 012 import javax.imageio.ImageIO; 013 import javax.swing.*; 014 import javax.swing.event.*; 015 016 import com.croftsoft.core.CroftSoftConstants; 017 import com.croftsoft.core.animation.*; 018 import com.croftsoft.core.animation.animator.*; 019 import com.croftsoft.core.animation.icon.ColorTileIcon; 020 import com.croftsoft.core.animation.sprite.*; 021 import com.croftsoft.core.animation.painter.*; 022 import com.croftsoft.core.animation.updater.*; 023 import com.croftsoft.core.applet.AppletLib; 024 import com.croftsoft.core.awt.image.ImageLib; 025 import com.croftsoft.core.io.SerializableLib; 026 import com.croftsoft.core.jnlp.JnlpLib; 027 import com.croftsoft.core.lang.StringLib; 028 import com.croftsoft.core.lang.lifecycle.Lifecycle; 029 import com.croftsoft.core.math.MathConstants; 030 031 /********************************************************************* 032 * Plane of modifiable tiles. 033 * 034 * @version 035 * 2003-08-11 036 * @since 037 * 2003-03-08 038 * @author 039 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 040 *********************************************************************/ 041 042 public final class Tile 043 extends AnimatedApplet 044 ////////////////////////////////////////////////////////////////////// 045 ////////////////////////////////////////////////////////////////////// 046 { 047 048 ////////////////////////////////////////////////////////////////////// 049 // Applet constants 050 ////////////////////////////////////////////////////////////////////// 051 052 private static final String VERSION 053 = "2003-08-11"; 054 055 private static final String TITLE 056 = "CroftSoft Tile"; 057 058 private static final String APPLET_INFO 059 = "\n" + TITLE + "\n" 060 + CroftSoftConstants.COPYRIGHT + "\n" 061 + CroftSoftConstants.HOME_PAGE + "\n" 062 + "Version " + VERSION + "\n" 063 + "Programming.....: David Wallace Croft\n" 064 + "Tile Graphics...: Shannon Kristine Croft\n"; 065 066 ////////////////////////////////////////////////////////////////////// 067 // Frame constants 068 ////////////////////////////////////////////////////////////////////// 069 070 private static final String FRAME_TITLE = TITLE; 071 072 private static final String FRAME_ICON_FILENAME 073 = "/images/croftsoft.png"; 074 075 private static final Dimension FRAME_SIZE = null; 076 077 private static final String SHUTDOWN_CONFIRMATION_PROMPT 078 = "Close " + TITLE + "?"; 079 080 ////////////////////////////////////////////////////////////////////// 081 // animation constants 082 ////////////////////////////////////////////////////////////////////// 083 084 private static final Color BACKGROUND_COLOR = Color.BLACK; 085 086 private static final Cursor CURSOR 087 = new Cursor ( Cursor.CROSSHAIR_CURSOR ); 088 089 ////////////////////////////////////////////////////////////////////// 090 // persistence constants 091 ////////////////////////////////////////////////////////////////////// 092 093 private static final String LATEST_FILENAME 094 = ".croftsoft/tile/tile_new.dat"; 095 096 private static final String BACKUP_FILENAME 097 = ".croftsoft/tile/tile_old.dat"; 098 099 private static final String FILE_CONTENTS_SPEC 100 = "Tile"; 101 102 private static final String PERSISTENCE_KEY 103 = FILE_CONTENTS_SPEC; 104 105 private static final String RESOURCE_PATH_FILENAME 106 = "apps/tile/tile.dat"; 107 108 ////////////////////////////////////////////////////////////////////// 109 // graphics constants 110 ////////////////////////////////////////////////////////////////////// 111 112 private static final long RANDOM_SEED = 0L; 113 114 private static final String TILE_MAP_IMAGE_FILENAME 115 = "apps/tile/tile_map.png"; 116 117 private static final String TILE_DIR = "apps/tile/tiles/"; 118 119 private static final String TILE_FILENAME_EXTENSION = ".png"; 120 121 /** Default width and height of tile data. */ 122 private static final int DEFAULT_MAP_SIZE = 100; 123 124 private static final Dimension DEFAULT_TILE_SIZE 125 = new Dimension ( 40, 40 ); 126 127 private static final int [ ] DEFAULT_PALETTE = new int [ ] { 128 0xFF000000, // black 129 0xFF0000FF, // blue 130 0xFF00FF00, // green 131 0xFF00FFFF, // cyan 132 0xFFFF0000, // red 133 0xFFFF00FF, // magenta 134 0xFFFFFF00, // yellow 135 0xFFFFFFFF }; // white 136 137 private static final int DEFAULT_PALETTE_INDEX = 0; // black 138 139 private static final int SMOOTHING_LOOPS = 1000; 140 141 ////////////////////////////////////////////////////////////////////// 142 // instance variables 143 ////////////////////////////////////////////////////////////////////// 144 145 private int [ ] palette; 146 147 private byte [ ] [ ] tileMap; 148 149 private EdgeScrollUpdater edgeScrollUpdater; 150 151 private Rectangle componentBounds; 152 153 private TilePainter tilePainter; 154 155 private Ellipse2D.Double tileEllipse2D; 156 157 private Point mousePoint; 158 159 private boolean dataIsDirty; 160 161 private Rectangle clipBounds; 162 163 ////////////////////////////////////////////////////////////////////// 164 ////////////////////////////////////////////////////////////////////// 165 166 public static void main ( String [ ] args ) 167 ////////////////////////////////////////////////////////////////////// 168 { 169 launch ( new Tile ( ) ); 170 } 171 172 public static AnimationInit createAnimationInit ( ) 173 ////////////////////////////////////////////////////////////////////// 174 { 175 AnimationInit animationInit 176 = new AnimationInit ( ); 177 178 animationInit.setAppletInfo ( APPLET_INFO ); 179 180 animationInit.setBackgroundColor ( BACKGROUND_COLOR ); 181 182 animationInit.setCursor ( CURSOR ); 183 184 animationInit.setFrameIconFilename ( FRAME_ICON_FILENAME ); 185 186 animationInit.setFrameSize ( FRAME_SIZE ); 187 188 animationInit.setFrameTitle ( FRAME_TITLE ); 189 190 animationInit.setShutdownConfirmationPrompt ( 191 SHUTDOWN_CONFIRMATION_PROMPT ); 192 193 return animationInit; 194 } 195 196 ////////////////////////////////////////////////////////////////////// 197 ////////////////////////////////////////////////////////////////////// 198 199 public Tile ( ) 200 ////////////////////////////////////////////////////////////////////// 201 { 202 super ( createAnimationInit ( ) ); 203 } 204 205 ////////////////////////////////////////////////////////////////////// 206 ////////////////////////////////////////////////////////////////////// 207 208 public void init ( ) 209 ////////////////////////////////////////////////////////////////////// 210 { 211 super.init ( ); 212 213 TileData tileData = null; 214 215 try 216 { 217 tileData = ( TileData ) SerializableLib.load ( 218 LATEST_FILENAME, 219 BACKUP_FILENAME, 220 FILE_CONTENTS_SPEC, 221 ( Applet ) this, 222 PERSISTENCE_KEY, 223 getClass ( ).getClassLoader ( ), 224 RESOURCE_PATH_FILENAME ); 225 } 226 catch ( Exception ex ) 227 { 228 ex.printStackTrace ( ); 229 } 230 231 if ( tileData == null ) 232 { 233 try 234 { 235 tileData = TileData.loadTileDataFromImage ( 236 TILE_MAP_IMAGE_FILENAME, 237 getClass ( ).getClassLoader ( ) ); 238 } 239 catch ( IOException ex ) 240 { 241 ex.printStackTrace ( ); 242 } 243 } 244 245 if ( tileData != null ) 246 { 247 palette = tileData.getPalette ( ); 248 249 tileMap = tileData.getTileMap ( ); 250 } 251 252 try 253 { 254 TileData.remapToPalette ( palette, tileMap, DEFAULT_PALETTE_INDEX ); 255 } 256 catch ( IllegalArgumentException ex ) 257 { 258 palette = new int [ ] { 259 0xFF0000FF, // blue water 260 0xFF00FF00 }; // green land 261 262 tileMap = TileData.generateRandomTileMap ( 263 new Random ( RANDOM_SEED ), 264 palette, 265 DEFAULT_MAP_SIZE, // rows 266 DEFAULT_MAP_SIZE, // columns 267 SMOOTHING_LOOPS ); 268 } 269 270 Dimension tileSize = DEFAULT_TILE_SIZE; 271 272 Icon [ ] tileIcons = new Icon [ palette.length ]; 273 274 for ( int i = 0; i < palette.length; i++ ) 275 { 276 int argb = palette [ i ]; 277 278 Image tileImage = null; 279 280 try 281 { 282 String iconFilename 283 = TILE_DIR 284 + StringLib.padLeft ( Integer.toHexString ( argb ), '0', 8 ) 285 + TILE_FILENAME_EXTENSION; 286 287 tileImage = ImageLib.loadAutomaticImage ( 288 iconFilename, 289 Transparency.OPAQUE, 290 animatedComponent, 291 getClass ( ).getClassLoader ( ), 292 tileSize ); 293 } 294 catch ( IllegalArgumentException ex ) 295 { 296 } 297 catch ( Exception ex ) 298 { 299 ex.printStackTrace ( ); 300 } 301 302 if ( tileImage == null ) 303 { 304 tileIcons [ i ] 305 = new ColorTileIcon ( new Color ( argb ), tileSize ); 306 } 307 else 308 { 309 tileIcons [ i ] = new ImageIcon ( tileImage ); 310 } 311 } 312 313 componentBounds = animatedComponent.getBounds ( ); 314 315 tileEllipse2D = new Ellipse2D.Double ( 316 0, 0, componentBounds.width, componentBounds.height ); 317 318 tilePainter = new TilePainter ( 319 0, 320 0, 321 tileIcons, 322 tileMap, 323 tileSize, 324 tileEllipse2D ); 325 326 edgeScrollUpdater = new EdgeScrollUpdater ( 327 animatedComponent, 328 tilePainter.getTileColumns ( ) * tilePainter.getTileWidth ( ), 329 tilePainter.getTileRows ( ) * tilePainter.getTileHeight ( ), 330 ( Dimension ) null, // edgeSize 331 10, // scrollRate 332 true ); // wrapAround 333 334 animatedComponent.addMouseListener ( 335 new MouseAdapter ( ) 336 { 337 public void mousePressed ( MouseEvent mouseEvent ) 338 { 339 mousePoint = mouseEvent.getPoint ( ); 340 } 341 } ); 342 343 clipBounds = new Rectangle ( ); 344 } 345 346 public void destroy ( ) 347 ////////////////////////////////////////////////////////////////////// 348 { 349 if ( dataIsDirty ) 350 { 351 try 352 { 353 SerializableLib.save ( 354 new TileData ( palette, tileMap ), 355 LATEST_FILENAME, 356 BACKUP_FILENAME, 357 FILE_CONTENTS_SPEC, 358 ( Applet ) this, 359 PERSISTENCE_KEY ); 360 } 361 catch ( Exception ex ) 362 { 363 ex.printStackTrace ( ); 364 } 365 } 366 367 super.destroy ( ); 368 } 369 370 ////////////////////////////////////////////////////////////////////// 371 // interface ComponentAnimator methods 372 ////////////////////////////////////////////////////////////////////// 373 374 public void update ( JComponent component ) 375 ////////////////////////////////////////////////////////////////////// 376 { 377 edgeScrollUpdater.update ( component ); 378 379 component.getBounds ( componentBounds ); 380 381 tileEllipse2D.x = -edgeScrollUpdater.getTranslateX ( ); 382 383 tileEllipse2D.y = -edgeScrollUpdater.getTranslateY ( ); 384 385 tileEllipse2D.width = componentBounds.width; 386 387 tileEllipse2D.height = componentBounds.height; 388 389 if ( mousePoint != null ) 390 { 391 edgeScrollUpdater.translateReverse ( mousePoint ); 392 393 if ( tileEllipse2D.contains ( mousePoint ) ) 394 { 395 int tileRow = tilePainter.getTileRow ( mousePoint ); 396 397 int tileColumn = tilePainter.getTileColumn ( mousePoint ); 398 399 int paletteIndex = 0xFF & tileMap [ tileRow ] [ tileColumn ]; 400 401 paletteIndex = ( paletteIndex + 1 ) % palette.length; 402 403 tileMap [ tileRow ] [ tileColumn ] = ( byte ) paletteIndex; 404 405 dataIsDirty = true; 406 407 component.repaint ( ); 408 } 409 410 mousePoint = null; 411 } 412 } 413 414 public void paint ( 415 JComponent component, 416 Graphics2D graphics ) 417 ////////////////////////////////////////////////////////////////////// 418 { 419 graphics.setColor ( BACKGROUND_COLOR ); 420 421 graphics.fillRect ( 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE ); 422 423 edgeScrollUpdater.translate ( graphics ); 424 425 tilePainter.paint ( component, graphics ); 426 } 427 428 ////////////////////////////////////////////////////////////////////// 429 ////////////////////////////////////////////////////////////////////// 430 }