// Class starwarsscroller // // (C) Søren Holstebroe 2 oct. 1997 // //[Adding some functionalities Philippe Guilbert 02-04-2000] import java.util.*; import java.awt.*; import java.io.*; import java.awt.image.*; import java.applet.*; import java.net.URL; import java.net.MalformedURLException; public class starwarsscroller extends Applet implements Runnable { // // Defaults // private final int DELAY = 10; // delay between frames in ms private final int FONTSIZE = 20; private final String FONTNAME = "SansSerif"; private final double SCROLLSPEED = 0.5; private final int DECIMAL = 16; // bits used for integer decimal private final int MAXLINES = 256; private final int LINESPACE = 0; private final int ZOOM = 100; private final int DIST = 200; private final double ANGLE = 1.3; private final String DEFAULTURL = "http://www.rhk.dk/users/seap/starwars.txt"; private final Color BGCOLOR = Color.black; private final Color FONTCOLOR = Color.yellow; private final int LOOPSPACE = 0; Color fontColor,bgColor; Image textimg,img; Graphics textg; // textbuffer Thread killme = null; MemoryImageSource source; boolean loop; // default : text will be displayed only once boolean started; // to interrupt the thread without the crashing "stop()" method int[] pixels; // display pixels int width,height; // display dimensions int[] textpixels; // source pixels int textwidth,textheight; // source dimensions String urlname; // name of url of text to scroll String fontname; // name of font to scroll int fontsize; // size of above font int linespace; // space in pixels between lines of text to be scrolled int maxlines; // maximum number of lines to be scrolled int loopSpace; // maximum space in pixels between two loops int delay; double scroll_offset, scroll_speed, scroll_begin; double cos_vx,sin_vx,vx; double theEnd; // maximum height of the text... untill it is not visible any more double dist,zoom; public void init() { setBackground(BGCOLOR); int i; URL url; String s; width = getSize().width; // width of viewport reserved by browser height = getSize().height; // height of viewport reserved by browser // // Load parameters // urlname = getParameter("url"); if (urlname == null) { urlname = DEFAULTURL; } fontname = getParameter("fontname"); if (fontname == null) fontname = FONTNAME; s = getParameter("fontsize"); if (s != null) fontsize = parseNum(s,FONTSIZE); else fontsize = FONTSIZE; s = getParameter("linespace"); if (s != null) linespace = parseNum(s,LINESPACE); else linespace = LINESPACE; s = getParameter("maxlines"); if (s != null) maxlines = parseNum(s,MAXLINES); else maxlines = MAXLINES; s = getParameter("zoom"); if (s != null) zoom = (double) parseNum(s,ZOOM); else zoom = ZOOM; s = getParameter("angle"); if (s == null) vx = ANGLE; else vx = Double.valueOf(s).doubleValue(); cos_vx = Math.cos(vx); sin_vx = Math.sin(vx); s = getParameter("scrollspeed"); if (s == null) scroll_speed = SCROLLSPEED; else scroll_speed = Double.valueOf(s).doubleValue(); s = getParameter("delay"); if (s != null) delay = parseNum(s,DELAY); else delay = DELAY; s = getParameter("fontcolor"); if ((s == null) || (s.equals(""))) fontColor = FONTCOLOR; else fontColor = defineColor(s,"font"); System.err.println("fontcolor : >"+s+"< \r"); System.err.println("fontcolor :"+fontColor.toString()); s = getParameter("bgcolor"); if ((s == null)||(s.equals(""))) bgColor = BGCOLOR; else bgColor = defineColor(s,"bg"); s = getParameter("loop"); if ((s != null)&&(s.toLowerCase().equals("yes"))) loop = true; else loop = false; s = getParameter("loopspace"); if (s != null) loopSpace = parseNum(s,LOOPSPACE); else loopSpace = LOOPSPACE; Font font = new Font(fontname,Font.BOLD,fontsize); try { url = new URL(getCodeBase(),urlname); } catch (MalformedURLException e1) { System.out.println("Malformed URL ERROR using default"); try { url = new URL(DEFAULTURL); } catch (MalformedURLException e2) { System.out.println("ERROR! Could not init default url"); return; } } textimg = url2image(url,font); System.out.println("W = "+textimg.getWidth(this)+" H = "+textimg.getHeight(this)); // INIT TEXTIMAGE textwidth = textimg.getWidth(this); textheight = textimg.getHeight(this); textpixels = getPixels(textimg); // convert Image to integer array (pixels) textimg = createImage(new MemoryImageSource(textwidth, textheight, textpixels, 0, textwidth)); // Load parameter "dist" s = getParameter("dist"); if (s == null) { dist = DIST; // Calculate DIST // We want to adjust DIST in such way, that width of the text fits the width of the screen // // // temp = dist / (cos_vx * zoom + (height-height/4) * sin_vx); // 0 = (-textwidth/2)/(cos_vx * temp)+width/2; // -(width/2)*(cos_vx * temp)=(-textwidth/2) // temp = (textwidth/2)/((width/2) * cos_vx) // dist = (cos_vx * zoom + (height-height/4) * sin_vx)*(textwidth/2)/((width/2) * cos_vx) dist = (cos_vx * zoom + (height-height/4) * sin_vx) * (textwidth/2)/((width/2) * cos_vx); // System.out.println("DIST = "+dist); } else dist = (double) Integer.parseInt(s); // Calculate scroll_offset /* The following equation tells with what scroll_offset the text is _just_ out of sight below the screen. temp = dist / (cos_vx * zoom + (height-height/4) * sin_vx); 0 = scroll_offset + ((height-height/4) * temp) */ scroll_offset = -(height-height/4.0) * (dist / (cos_vx * zoom + (height-height/4.0) * sin_vx)); scroll_begin = scroll_offset; theEnd = (double) (scroll_begin+textheight*2+loopSpace); // INIT DISPLAYIMAGE pixels = new int[width*height]; for (i=0;i<width*height;i++) // init pixels pixels[i] = 0xff000000; source = new MemoryImageSource(width, height, pixels, 0, width); source.setAnimated(true); img = createImage(source); } // // convert Image to array of pixels // public int [] getPixels(Image img) { int [] pixels; // Create pixelarray pixels = new int[img.getWidth(this) * img.getHeight(this)]; PixelGrabber pg = new PixelGrabber(img, 0, 0, img.getWidth(this), img.getHeight(this), pixels, 0, img.getWidth(this)); try { pg.grabPixels(); } catch (InterruptedException e) { System.err.println("interrupted waiting for pixels!"); } if ((pg.getStatus() & ImageObserver.ABORT) != 0) { System.err.println("image fetch aborted or errored"); } return(pixels); } // // Read url and write text in Image // public Image url2image(URL url, Font font) { InputStream urlstream; String urlline[]; int line = 0; int textwidth,textheight,i,tmp; urlline = new String [maxlines]; urlstream = System.in; try { urlstream = url.openStream();} // get url as stream (throws IOEx) catch (IOException IOE) { System.out.println("IOexception\n"); } BufferedReader brin = new BufferedReader(new InputStreamReader(urlstream)); FontMetrics fontM = getFontMetrics(font); try {urlline[line++] = brin.readLine();} catch (IOException IOE) {System.out.println("IOexception\n");} while (urlline[line-1] != null && line < maxlines) { try {urlline[line++] = brin.readLine();} catch (IOException IOE) {System.out.println("IOexception\n");} } line--; textwidth = 0; for (i=0;i<line;i++) // Find max width { tmp = fontM.stringWidth(urlline[i]); if (tmp > textwidth) textwidth = tmp; } textheight = (fontM.getHeight()+linespace)*line; // INIT TEXTIMAGE textimg = createImage(textwidth,textheight); textg = textimg.getGraphics(); textg.setColor(bgColor); textg.fillRect(0,0,textwidth,textheight); textg.setColor(fontColor); textg.setFont(font); for (i=0;i<line;i++) textg.drawString(urlline[i],0,(i+1)*(fontM.getHeight()+linespace)-3-fontM.getMaxDescent()); return(textimg); } private void next_scrollimage() { /* ; X-AXIS rotation ; ; z = -y * sin vx ; y = y * cos vx ; ; **** vector projection: **** ; z = -y * sin vx ; y = y * cos vx ; x = x * (zoom / (z + dist)) ; y = y * (zoom / (z + dist)) ; **** invers vector projection: **** ; temp = cos vx * zoom + y * sin vx ; Yo = y * dist / temp ; Xo = x * cos vx * dist / temp */ int x,y,y0,xStart,xEnd,yStart,yStart2,yEnd,tOffset,sOffset; int colorMask,maxY0,minY0,dx0,x0; double temp; // find perspective point yStart = (int) (-cos_vx * zoom/sin_vx) + height/4; if (yStart<0) yStart = 0; // perspective point is above screen else yStart++; // perspective point is on or below screen, increase to avoid div 0 // find start of text // temp = dist / (cos_vx * zoom + (y-height/4) * sin_vx); // y = height/4 - (scroll_offset*(cos_vx * zoom + (y-height/4) * sin_vx)) / dist) yEnd = height; for (y=yStart;y<yEnd;y++) { temp = dist / (cos_vx * zoom + (y-height/4) * sin_vx); y0 = (int) (scroll_offset + ((y-height/4) * temp)); if (y0<0 || y0>=textheight) continue; maxY0 = (int)(((height-1)-height/4) * temp); minY0 = (int)((yStart-height/4) * temp); colorMask = 0xff000000 + 0x00010100* (int)(((y-height/4) * temp-minY0)*255/(maxY0-minY0)); // init x0 x0 = (int)((1<<DECIMAL)*(textwidth/2 + (-width/2) * cos_vx * temp)); if (x0<0) x0 = 0; dx0 = (int)(cos_vx * temp * (1<<DECIMAL)); // x0 increase each pixel // find where x enters and leaves textwindow /* 0 = textwidth/2 + (x-width/2) * cos_vx * temp (x-width/2) * cos_vx * temp = -textwidth/2 (x-width/2) = (-textwidth/2)/(cos_vx * temp) x = (-textwidth/2)/(cos_vx * temp)+width/2; */ xStart = (int)((-textwidth/2)/(cos_vx * temp))+width/2; if (xStart<0) xStart = 0; // startpoint is left to screen xEnd = width-xStart; // asuming symetry // draw text tOffset = y0*textwidth; sOffset = xStart+y*width; for ( x = xStart;x<xEnd;x++) { // if (x0 >= 0 && x0 < textwidth && y0 >= 0 && y0 < textheight) pixels[sOffset++] = textpixels[tOffset+(x0>>DECIMAL)]&colorMask; // else // pixels[x+y*width] = 0xffff00ff; // Test: farv blå hvis vi er uden for grænsen x0 += dx0; } } scroll_offset += scroll_speed; if (scroll_offset>=theEnd) //testing if loop=true and looping { if (loop) scroll_offset = scroll_begin; else stop(); } } public void start() { if(killme == null) { killme = new Thread(this); killme.start(); } } public void stop() { if (killme != null && killme.isAlive()) killme = null; } public void run() { while (true) { repaint(); try {Thread.sleep(delay);} catch (InterruptedException e){} } } public void paint(Graphics g) { next_scrollimage(); source.newPixels(0, 0, width, height); g.drawImage(img,0,0,this); } public void update(Graphics g) { paint(g); } private int parseNum(String st, int constant) { if (st.equals("")) return constant; try { int num = Integer.parseInt(st); return num; } catch (NumberFormatException nbe) { return constant; } } private Color defineColor(String s, String type) { StringTokenizer stk = new StringTokenizer(s,","); int counter = 0; int value[] = new int[3]; String temp = null; while (stk.hasMoreTokens()) { temp = stk.nextToken(); try { value[counter]=Integer.parseInt(temp); ++counter; } catch (NumberFormatException nbe) { System.err.println("Error in defining the colors..."); if (type.equals("font")) return FONTCOLOR; if (type.equals("bg")) return BGCOLOR; } } return new Color(value[0],value[1],value[2]); } }