/* * @(#)Cthru.java * * Copyright (c) 1997 NAKAGAWA Masami * * Permission to use, copy, modify, and distribute this software * for NON-COMMERCIAL purpose and without fee is hereby granted. */ import java.awt.*; import java.applet.*; import java.awt.image.*; import java.util.*; /** * @author Nakagawa Masami * @version 1.4, 26 Aug 1997 */ public class Cthru extends Applet implements Runnable { MediaTracker mt; Thread thread; Image offImage; Graphics offScreen; Graphics onScreen; int boundX; int boundY; int speedX; int speedY; int interval = 50; Image backImage; Image foreImage; Image scrollImage; Image fImage; Image bImage; Image sImage; Dimension imgSize; Dimension aplSize; Color[] thruColor; int range = 0x20; int rate = 0; int sdwX; int sdwY; Color backColor; Color scrollColor = Color.white; Color shadowColor = Color.black; public void init() { mt = new MediaTracker(this); String s = getParameter("foreImage"); if (s != null) { fImage = getImage(getDocumentBase(), s); mt.addImage(fImage, 0); } s = getParameter("backImage"); if (s != null) { bImage = getImage(getDocumentBase(), s); mt.addImage(bImage, 0); } s = getParameter("scrollImage"); if (s != null) { sImage = getImage(getDocumentBase(), s); mt.addImage(sImage, 0); } s = getParameter("speedX"); if (s != null) { speedX = Integer.parseInt(s); } s = getParameter("speedY"); if (s != null) { speedY = Integer.parseInt(s); } s = getParameter("shadowX"); if (s != null) { sdwX = Integer.parseInt(s); } s = getParameter("shadowY"); if (s != null) { sdwY = Integer.parseInt(s); } s = getParameter("range"); if (s != null) { range = Integer.parseInt(s, 16); } s = getParameter("rate"); if (s != null) { rate = Integer.parseInt(s, 16); } s = getParameter("backColor"); if (s != null) { backColor = new Color(Integer.parseInt(s, 16)); } s = getParameter("scrollColor"); if (s != null) { scrollColor = new Color(Integer.parseInt(s, 16)); } s = getParameter("shadowColor"); if (s != null) { shadowColor = new Color(Integer.parseInt(s, 16)); } s = getParameter("interval"); if (s != null) { interval = Integer.parseInt(s); if (interval < 10) interval = 10; } s = getParameter("color"); if (s != null) { StringTokenizer st = new StringTokenizer(s, "|"); thruColor = new Color[st.countTokens()]; for (int i = 0; st.hasMoreTokens(); i++) { thruColor[i] = new Color(Integer.parseInt(st.nextToken(), 16)); } } aplSize = size(); offImage = createImage(aplSize.width, aplSize.height + 1); offScreen = offImage.getGraphics(); onScreen = getGraphics(); } private Dimension getImageSize(Image image) { int w = 0; int h = 0; try { do { w = image.getWidth(null); h = image.getHeight(null); Thread.currentThread().sleep(100); } while (w < 0 || h < 0); } catch (InterruptedException e) { e.printStackTrace(); } return new Dimension(w, h); } private Image fillImage(Image image, Dimension ap, Color color) { Dimension d; if (image != null) { d = getImageSize(image); } else { d = aplSize; } int fillw = (ap.width / d.width + 1) * d.width; int fillh = (ap.height / d.height + 1) * d.height; Image fill = createImage(fillw, fillh); Graphics g = fill.getGraphics(); g.setColor(color); g.fillRect(0, 0, fillw, fillh); if (image != null) { for (int x = 0; x < fillw; x+=d.width) { for (int y = 0; y < fillh; y+=d.height) { g.drawImage(image, x, y, null); } } } return fill; } private Image drawShadow(Image image) { Dimension d = getImageSize(image); int w = d.width; int h = d.height; int[] pixels = new int[w*h]; int[] newpix = new int[w*(h+1)]; PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, pixels, 0, w); try { pg.grabPixels(); System.arraycopy(pixels, 0, newpix, w, w*h); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { int sx = x - sdwX; int sy = y - sdwY; if (sx < 0 || sx >= w || sy < 0 || sy >= h) continue; if ((pixels[y*w+x] & 0xFF000000) != 0xFF000000 && ((pixels[sy*w+sx] & 0xFF000000) == 0xFF000000) ) { newpix[(y+1)*w+x] = shadowColor.getRGB(); } } } MemoryImageSource mis = new MemoryImageSource(w, h+1, newpix, 0, w); return Toolkit.getDefaultToolkit().createImage(mis); } catch (InterruptedException e) { e.printStackTrace(); return image; } } public void start() { if (thread == null) { thread = new Thread(this); thread.start(); } } public void stop() { if (thread != null) { thread.stop(); } thread = null; } public void paint(Graphics g) { if (offImage != null) { g.drawImage(offImage, 0, 0, null); } } public void update(Graphics g) { paint(g); } private void drawMessage(Graphics g, String s) { g.setColor(Color.black); g.fillRect(0, 0, aplSize.width, aplSize.height); g.setColor(Color.cyan); g.drawString(s, 10, 20); } public void run() { // loading... drawMessage(offScreen, "Loading images..."); repaint(); try { mt.waitForAll(); } catch (InterruptedException e) { e.printStackTrace(); } if (mt.isErrorAny()) { drawMessage(offScreen, "ERROR: Loading images..."); repaint(); return; } // processing... drawMessage(offScreen, "Processing images..."); onScreen.drawImage(offImage, 0, 0, null); scrollImage = fillImage(sImage, aplSize, scrollColor); if (bImage != null) { backImage = fillImage(bImage, aplSize, backColor); if (fImage != null) { Graphics g = backImage.getGraphics(); g.drawImage(fImage, 0, 0, null); } } else { // for Mac backImage = fImage; } imgSize = getImageSize(scrollImage); ImageFilter f = new CthruFilter(thruColor, range, rate, backColor); ImageProducer producer = new FilteredImageSource(backImage.getSource(), f); foreImage = drawShadow( createImage(producer) ); while(true) { offScreen.drawImage(scrollImage, boundX, boundY, null); if (boundX > 0) { offScreen.drawImage(scrollImage, boundX-imgSize.width, boundY, null); } if (boundY > 0) { offScreen.drawImage(scrollImage, boundX, boundY-imgSize.height, null); } if (boundX > 0 && boundY > 0) { offScreen.drawImage(scrollImage, boundX-imgSize.width, boundY-imgSize.height, null); } offScreen.drawImage(foreImage, 0, 0, null); onScreen.drawImage(offImage, 0, -1, null); boundX += speedX; boundY += speedY; if (boundX < 0) { boundX += imgSize.width; } else if (boundX >= imgSize.width) { boundX -= imgSize.width; } if (boundY < 0) { boundY += imgSize.height; } else if (boundY >= imgSize.height) { boundY -= imgSize.height; } try { thread.sleep(interval); } catch (InterruptedException e) { e.printStackTrace(); } } } } class CthruFilter extends RGBImageFilter { private Color[] color; private int range; private int rate; private Color backColor; public CthruFilter(Color[] color, int range, int rate, Color backColor) { this.color = color; this.range = range; this.rate = (rate<<24) | 0x00FFFFFF; this.backColor = backColor; canFilterIndexColorModel = true; } private boolean nearColor(int rgb, Color col) { int r = (rgb & 0x00FF0000) >> 16; int g = (rgb & 0x0000FF00) >> 8; int b = (rgb & 0x000000FF); if ((Math.abs(r - col.getRed()) <= range) && (Math.abs(g - col.getGreen()) <= range) && (Math.abs(b - col.getBlue()) <= range)) { return true; } return false; } public int filterRGB(int x, int y, int rgb) { if (color == null) return rgb; if (backColor != null && (rgb & 0xFF000000) == 0) return backColor.getRGB(); boolean flag = false; for (int i = 0; i < color.length; i++) { if (nearColor(rgb, color[i])) { flag = true; break; } } if (flag) { return rate & rgb; } else { return rgb; } } }