/* * Kepek.java * a képkezelést technikailag (AWT-vel) megvalósító osztályok * by pts@fazekas.hu at 2001.03.16, hierarchized by pts@fazekas.hu at Sun Apr 22 16:29:47 CEST 2001 * további doksi: a README-ben és e file legkülső class-ának fejkommentjében * * Kincskereső Kisgömböc (C) Early May 2001 by eNTitánok (Rév Szilvia, * Szabó Péter <pts@inf.bme.hu>, Szurdi Miklós, Weizengruber Attila). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package eNTitanok.gfx; import eNTitanok.gfx.OkosAWT; import eNTitanok.gfx.OkosAWT.OkosFixCanvas; import java.applet.Applet; import java.awt.Canvas; import java.awt.Dimension; import java.awt.Component; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Color; import java.awt.Rectangle; import java.awt.Image; import java.awt.Font; import java.awt.Toolkit; import java.awt.MediaTracker; import java.awt.image.PixelGrabber; import java.awt.image.MemoryImageSource; // import java.awt.image.BufferedImage; // nem használjuk, mert JDK1.2 kéne import java.awt.image.ImageProducer; import java.util.Vector; import java.util.Hashtable; import java.util.Enumeration; /** * A képkezelést technikailag (AWT-vel) megvalósító osztályok. * * <P>Átkozott képkezelés! Minden baj, vesződség, inkompabitibilitás, lassúság és * bosszúság forrása. * * <P>Pedig nem kérek nehezet. Csak annyit, hogy szeretnék egy gyorsan * megjeleníthető, transparency-t is tartalmazó Image objektumot az adott * méretben. Nem, ezt Java 2-ben nem lehet. */ public class Kepek { /** * Nehany keresetlen szo a kepbetoltesrol. * Paint-tal keszitett BMP-t a Java nem tud betolteni. Punktum. * GIF-et es JPG-et be lehet tolteni. * Java Applet nem tolthet be a vinyorol akarhonnan kepet (SecurityException) * Java Applet tolthet be a sajat konyvtarabol kepet, akkor is, ha a sajat * konyvtara a vinyon van: * this.getImage(this.getCodeBase(),"kepnev.gif"); * a transparent GIF-et a Java jol tolti be. */ public static class Kepbetolto extends MediaTracker { public static class SikertelenBetoltesException extends Error {} protected Hashtable ht; // filenev->Image; Hashtable csak !null->!null-t enged meg. protected Hashtable szk; // filenev->Vector(Kep); Hashtable csak !null->!null-t enged meg. protected Vector v; // num->filenev /** * Például "eNTitanok/kkkg/design/". */ protected String resdir; public Kepbetolto() { this("eNTitanok/kkkg/design/"); } public Kepbetolto(String resdir) { // `public' bugfix by pts@fazekas.hu at Sun Apr 22 16:33:30 CEST 2001 super(OkosAWT.getMainComponent()); this.resdir=resdir; ht=new Hashtable(); szk=new Hashtable(); v=new Vector(); } public void elfelejt(String filenev) { // csak mind_meglegyen után szabad hívni!! ht.remove(filenev); } public Kep betolt(String filenev) { // filenev ap.getCodeBase()-hez relatív... Image kep; if (!ht.containsKey(filenev)) { // if (ap.getCodeBase()==null) throw new NullPointerException(); kep=OkosAWT.getImageBase(filenev); super.addImage(kep, v.size()); v.addElement(filenev); ht.put(filenev, kep); } else kep=(Image)ht.get(filenev); Kep k=new Kep(filenev, kep); Vector szv; if ((szv=(Vector)szk.get(filenev))==null) szk.put(filenev, szv=new Vector()); szv.addElement(k); return k; } /** * Egyetlen kép letöltődésére vár. Pontosan akkor true, ha sikerült. */ public boolean egyreVar(Image image) { super.addImage(image, -42); try { super.waitForID(-42); Object balul[]=super.getErrorsID(-42); boolean ret=(balul==null || balul.length==0) && image.getHeight(null)>=0 && image.getWidth(null)>=0; super.removeImage(image, -42); return ret; } catch (Exception e) { return false; } } /** * az összes folyamatban levő betöltést végigviszi */ public void mind_meglegyen() { // `public' bugfix by pts@fazekas.hu at Sun Apr 22 16:31:50 CEST 2001 boolean balulp=false; try { super.waitForAll(); } catch (InterruptedException e) { throw new SikertelenBetoltesException(); } //balul=super.getErrorsAny(); for (int i=v.size()-1;i>=0;i--) { Object balul[]=super.getErrorsID(i); String filenev=(String)v.elementAt(i); boolean ok=false; Image image=(Image)ht.get(filenev); if (balul!=null && balul.length>0) { // ha az applet/application mellett (ugyanabban a könyvtárban) nem // találtuk, akkor még mindig van esélyünk, hogy a .jar file-ban // benne van, azon belül az eNTitanok/kkkg/design/ könyvtárban. // // a getEroforras* (JDK1.1-ben) csak ott keresi a képeket, ahonnan // a KkkgAppl.class-t is betöltötte. Tehát a .jar file és a sima // file-ok közül csak az egyikben. (Tesztelve.) byte t[]=OkosAWT.getEroforrasByteTOf(OkosAWT.getMainClassLoader(), resdir+filenev); if (t!=null) { // System.err.println("Hi:"+filenev); Image ujImage=OkosAWT.getMainToolkit().createImage(t); OkosAWT.getMainComponent().prepareImage(ujImage,OkosAWT.getMainComponent()); // ^^^ ez elengedhetetlen JDK1.1-nek if (egyreVar(ujImage)) { // ^^^ ez elengedhetetlen JDK1.2-nek és JDK1.3-nak // System.err.println(t.length); // eNTitanok.util.Idozito.alszik(1000); // System.err.println(ujImage.getHeight(null)); ht.put(filenev,ujImage); // ^^^ bele _kell_ rakni, hogy mások is megkaphassák Vector szv=(Vector)szk.get(filenev); for (int h=0;h<szv.size();h++) ((Kep)szv.elementAt(h)).setImage(ujImage); ok=true; } /// IF } /// IF } else if (image.getHeight(null)>=0 && image.getWidth(null)>=0) { ok=true; } /// IF if (!ok) { java.lang.System.err.println("Letoltesi hiba kepfile='"+filenev+"'."); // OK: normál hibaüzenet, filnevekkel (kulon hash-ben) balulp=true; } super.removeImage(image, i); } // FOR if (balulp) throw new SikertelenBetoltesException(); Enumeration e=szk.keys(); while (e.hasMoreElements()) { String filenev=(String)e.nextElement(); Vector szv=(Vector)szk.get(filenev); // System.err.println("siker: "+filenev); for (int h=0;h<szv.size();h++) ((Kep)szv.elementAt(h)).betoltve(); // szk.remove(filenev); } v.setSize(0); // kiváltottuk a JDK1.2.2 `v.clear();'-jét szk.clear(); // kiválthatnánk fent egyenkénti remove()-val, de működik } } /// class Kepbetolto public static class ButaKep { /* a ButaKep egy alapvetően nem módosítható képet testesít meg. A kép pixelei * egyenként lekérdezhetők (red, green, blue, alpha), és egy külön tömbben * módosíthatók. Miután a pixelek módosultak, a képet újra kell generálni. * A kép lehet transparent (áltlátszó, alpha!=255) és nem transparent is. * A képre getGraphics() nem kérhető!! */ public static final int C_FEKETE=0, C_FEHER=0xFFFFFF, C_PIROS=0xFF0000, C_ZOLD=0x00FF00, C_KEK=0x0000FF, C_SARGA=0xFFFF00, C_LILA=0xFF00FF, C_TURKIZ=0x00FFFF, C_KEK1=0x000080, C_KEK3=0x004040; public static class GrabbingFailedException extends Error {} public static class MegToltodikException extends Error {} // public static final int winpal[]= 0, public static final int S_JONMEG=4, S_KEPOK=1, S_PIXOK=2, S_PIXKEPOK=3; protected int status=S_JONMEG; protected int width=-1, height=-1; protected Image kep; // !! protected int pixels[]; protected String filenev; protected Component co; // ^^^ csak azért kell, hogy a .createImage-et hívhassuk // Imp: remove, már mainComponent van public ButaKep(String filenev, Image kep, Component co) { this.filenev=filenev; this.kep=kep; this.co=co; } public int getWidth() { return width; } public int getHeight() { return height; } public int getStatus() { return status; } public Image getKep() { return kep; } public Image getImage() { return kep; } void setImage(Image image) { this.kep=image; } public void setDirty() { if (status==S_PIXKEPOK) status=S_PIXOK; } public String getFilenev() { return filenev; } // public void setKep(Image kep_) { kep=kep_; } // public int setStatus(int status) { return this.status=status; } // Kepbetolto allithatja public void ujraszamol() {} /** * @return új this.status */ public int betolt_probal() { if (status!=S_JONMEG) return status; width=kep.getWidth(null); if (width==-1) return status; height=kep.getHeight(null); if (height<1) throw new Kepbetolto.SikertelenBetoltesException(); if (width<1) throw new Kepbetolto.SikertelenBetoltesException(); status=S_KEPOK; ujraszamol(); return status; } protected void betolt() { if (S_JONMEG==betolt_probal()) throw new Kepbetolto.SikertelenBetoltesException(); } public void betoltve() { /* akkor hivódik meg, amikor a Képbetöltő végzett */ betolt(); } public void pixelizal() { /* lekérdezi (frissíti) a pixels tömböt kep alapján */ betolt(); if (0!=(status&S_PIXOK)) return; if (status==S_JONMEG) throw new MegToltodikException(); Image masik; if (co!=null && OkosAWT.getMainToolkit().getColorModel().getPixelSize()==16) { // !!! // ezt miért is kell külön kezelni? masik=OkosAWT.getMainComponent().createImage(width, height); Graphics g=masik.getGraphics(); g.drawImage(kep, 0, 0, null); g.dispose(); } else masik=kep; pixels=new int[width*height]; PixelGrabber pg=new PixelGrabber(kep.getSource(), 0, 0, width, height, pixels, 0, width); try { if (!pg.grabPixels(0L)) pg.grabPixels(0L); if ((pg.status() & 0x80) != 0) throw new MegToltodikException(); } catch (Exception e) { throw new MegToltodikException(); } if (masik!=kep) masik.flush(); // ?? status|=S_PIXOK; } public void kepizal() { /* újragenerálja kep-et pixels alapján */ betolt(); if (0!=(status&S_KEPOK)) return; boolean van_atlat=false; for (int i=pixels.length-1;i>=0;i++) if (0xff000000!=(pixels[i]&0xff000000)) { van_atlat=true; break; } if (van_atlat) { // transparent-et másképp készítünk, mint simát kep=OkosAWT.getMainComponent().createImage(new MemoryImageSource(width, height, pixels, 0, width)); } else { // Imp: kézzel, ciklusban felrajzolni a pixeleket kep=OkosAWT.getMainComponent().createImage(new MemoryImageSource(width, height, pixels, 0, width)); } status|=S_KEPOK; } public int[] getPixelt() { pixelizal(); return pixels; } /** * a sorokból álló tömböt adja vissza, transparency-t nem törli le */ public int[][] getPixeltt() { int x, y, t[][], u[], i=0; pixelizal(); t=new int[height][]; for (y=0;y<height;y++) { u=t[y]=new int[width]; for (x=0;x<width;x++) u[x]=pixels[i++]; } return t; } /** * a sorokból álló tömböt adja vissza, transparency-t letörli */ public int[][] getPixelttnot() { int x, y, t[][], u[], i=0; pixelizal(); t=new int[height][]; for (y=0;y<height;y++) { u=t[y]=new int[width]; for (x=0;x<width;x++) u[x]=pixels[i++]&0xFFFFFF; } return t; } /** * A sorokból álló tömböt adja vissza, transparency-t letörli, az egyes * színkomponenseket 00-ra vagy 0xff-re kerekíti. */ public int[][] getPixelttkerek() { int x, y, t[][], u[], i=0, p; pixelizal(); t=new int[height][]; for (y=0;y<height;y++) { u=t[y]=new int[width]; for (x=0;x<width;x++) { p=pixels[i++]&0xFFFFFF; if ((p&0xFF0000)>=0x700000) p|=0xFF0000; else p&=~0xFF0000; if ((p&0x00FF00)>=0x007000) p|=0x00FF00; else p&=~0x00FF00; if ((p&0x0000FF)>=0x000070) p|=0x0000FF; else p&=~0x0000FF; u[x]=p; } } return t; } public void pixelt_felejt() { if (0!=(status&S_PIXOK)) { pixels=null; status&=~S_PIXOK; } } public void kepet_felejt() { status&=~S_KEPOK; } public Object clone() { // még le nem töltődött kép nem klónozható értelmesen kepizal(); ButaKep masik=new ButaKep(filenev, kep, co); masik.width=width; masik.height=height; return masik; } public void atszinez(int ujszin) { /* az összes nem átlátszó képpont színét ujszin-re állítja */ ujszin|=0xFF000000; int t[]=getPixelt(); kepet_felejt(); for (int i=t.length-1;i>=0;i--) if (0!=(t[i]&0xFF000000)) t[i]=ujszin; kepizal(); } } /// class ButaKep public static class Betutipus { /* a Betűtípus annyival több a ButaKép-nél, hogy önmagán belül 256 * karakterpozíciót (méretekkel együtt) képes megjegyezni. A betűk alakját * egy speciális képfile-ból (.gif) töltjük be, és a file-ban tárolt kék * és piros vonalak elhelyezkedéséből automatikusan számítjuk a méreteket * A betűk mind ugyanolyan színűek, az átszínezéshez új :Betűtípus szükséges. */ // by pts@fazekas.hu at Sun Mar 18 01:28:16 CET 2001 public static class HibasBetutipusException extends Error {} public static class TulSokBetuException extends HibasBetutipusException {} public static class TulKevesBetuException extends HibasBetutipusException {} public static final int B_KEK=ButaKep.C_KEK, B_PIROS=ButaKep.C_PIROS; // ^^^ átlátszóság nem számít private static class Betu { protected int x, y; // bal felső pixel pozíciója a képen protected int gw, gh; // mekkora területet kell kirajzolni protected int w; // hány pixellel kell jobbra menni a kirajzolás után protected int bl; // a baseline hányadik sorban van (felülről, >=0) public Betu(int x, int y) { this.x=x; this.y=y; } } ButaKep kep; // átlátszó + 1 szín Betu betuk[]; public static char javit(char c) { /* kicserél néhány magyar ékezetes betűt (lényegében Unicode->Latin 2) */ return c==0x150 ? 0xD5 : c==0x151 ? 0xF5 : c==0x170 ? 0xDB : c==0x171 ? 0xFB : c; } public static String javit(String s) { /* karakterenként javít */ StringBuffer sb=new StringBuffer(); for (int i=0;i<s.length();i++) sb.append(javit(s.charAt(i))); return new String(sb); } public int nyomtat(Graphics g, int x, int y, char c) { /* (x,y): reference point (a baseline-on) * c: nyomtatandó karakter * @return: új x koordináta, miután jobbra léptünk */ Betu b=betuk[c]; Graphics g1=g.create(x, y-b.bl, b.gw, b.gh); g1.drawImage(kep.getImage(), -b.x, -b.y, null); g1.dispose(); return x+b.w; } public int nyomtatBalra(Graphics g, int x, int y, char c) { /* (x,y): reference point (a baseline-on) * c: nyomtatandó karakter * @return: új x koordináta, miután jobbra léptünk */ Betu b=betuk[c]; Graphics g1=g.create(x-b.w, y-b.bl, b.gw, b.gh); g1.drawImage(kep.getImage(), -b.x, -b.y, null); g1.dispose(); return x-b.w; } public int nyomtat(Graphics g, int x, int y, String s) { /* (x,y): reference point (a baseline-on) * s: nyomtatandó String * @return: új x koordináta, miután jobbra léptünk */ // Imp: gyorsítani, de mindig jó g.create() for (int i=0;i<s.length();i++) x=nyomtat(g, x, y, s.charAt(i)); // g.drawImage(kep.getImage(), 0, 0, null); /*System.out.println(betuk[65].x+","+betuk[65].y+" w="+betuk[65].gw+" h="+betuk[65].gh); System.out.println(betuk[65+16].x+","+betuk[65+16].y); System.out.println(""); */ return x; } /// nyomtat() public int nyomtatBalra(Graphics g, int x, int y, String s) { /* (x,y): reference point (a baseline-on) * s: nyomtatandó String * @return: új x koordináta, miután jobbra léptünk */ // Imp: gyorsítani, de mindig jó g.create() for (int i=s.length()-1;i>=0;i--) x=nyomtatBalra(g, x, y, s.charAt(i)); // g.drawImage(kep.getImage(), 0, 0, null); /*System.out.println(betuk[65].x+","+betuk[65].y+" w="+betuk[65].gw+" h="+betuk[65].gh); System.out.println(betuk[65+16].x+","+betuk[65+16].y); System.out.println(""); */ return x; } // nyomtatBalra() public Betutipus(ButaKep kep) { kep.betolt(); this.kep=kep; betuk_szamol(); } /// Betutipus() public Betutipus(ButaKep kep, int szin) { this(kep); kep.atszinez(szin); } protected void betuk_szamol() { /* felépítjük a betűk[] tömböt a `kép' alapján */ int t[][]=kep.getPixelttnot(); int u[]; int i=0; betuk=new Betu[256]; for (int y=1;y<t.length-1;y++) { u=t[y]; for (int x=2;x<u.length-1;x++) { if (u[x]==B_KEK && u[x+1]==B_KEK && t[y-1][x]==B_KEK) { if (i==betuk.length) throw new TulSokBetuException(); int xx, yy, yybl=-1, ww=x+10; for (xx=x;xx<u.length-1;xx++) { if (u[xx]!=B_KEK) break; if (t[y+1][xx]==B_PIROS) ww=xx; } for (yy=y;yy>0;yy--) { if (t[yy][x-1]==B_PIROS) yybl=yy; if (t[yy][x]!=B_KEK) break; } if (yybl==-1) throw new HibasBetutipusException(); betuk[i]=new Betu(x+1,yy+1); betuk[i].gw=xx-x-1; betuk[i].gh=y-yy-1; betuk[i].bl=yy-yybl; betuk[i].w=ww-x; // !!! i++; } /// IF betűt találtunk } /// NEXT x } /// NEXT y if (i!=betuk.length) throw new TulKevesBetuException(); } /// betuk_szamol() } /// class Betutipus public static class Kep extends ButaKep { /* a Kép annyival több a ButaKép-nél, hogy van bx1, by1, és képes * ütközésvizsgálatra, továbbá megjeleníthető sprite-ként */ protected int bx1, by1; // hany pixellel kell a bal felso sarkot feljebb kirajzolni private int bxa, bya; // bxa==bx1-arnyeka, bya==by1-arnyeka private int widtha=-1, heighta=-1; // widtha==width+2*arnyeka, ... protected boolean arnyekolt; protected int arnyeka=5; protected Sdpts sd; private Hashtable utkoztetok=new Hashtable(); // Kep->Utkozteto public Kep(String filenev, Image kep) { super(filenev,kep,null); } public Kep initi(Sdpts sd, int bx1, int by1, int arnyeka) { this.co=sd.getComponent(); this.sd=sd; this.bx1=bx1; this.by1=by1; this.arnyekolt=true; this.arnyeka=arnyeka==-9999?5:arnyeka; return this; } public Kep initi(Sdpts sd, int bx1, int by1) { this.co=sd.getComponent(); this.sd=sd; this.bx1=bx1; this.by1=by1; this.arnyekolt=false; this.arnyeka=0; return this; } public int getBx1() { return bx1; } public int getBy1() { return by1; } public boolean getArnyekolt() { return arnyekolt; } public void setArnyekolt(boolean arnyekolt, int arnyeka) { this.arnyekolt=arnyekolt; this.arnyeka=arnyeka; ujraszamol(); } public void ujraszamol() { /* bxa, bya, widtha, heighta újraszámolása */ heighta=height+2*arnyeka; widtha=width+2*arnyeka; bxa=bx1-arnyeka; bya=by1-arnyeka; } public void rarajzol(Graphics g, int x, int y) { // (x,y): pixel // java.lang.System.out.println("RR.\n"); g.drawImage(kep, x+bx1, y+by1, null); } public void felrajzol_arnyek(int x, int y) { // (x,y): pixel if (arnyekolt) sd.drawShadow(x+bxa, y+bya, widtha, heighta); } public void felrajzol_kep(int x, int y) { // (x,y): pixel if (arnyekolt) { sd.drawImage(kep, x+bx1, y+by1); sd.drawCover(x+bxa, y+bya, widtha, heighta); } else sd.drawImageCover(kep, x+bx1, y+by1, !arnyekolt); } public void utkoztetot_hozzaad(Kep masik) { if (! utkoztetok.containsKey(masik)) utkoztetok.put(masik, new Utkozteto(this,masik)); if (!masik.utkoztetok.containsKey(this )) masik.utkoztetok.put(this, new Utkozteto(masik,this)); } public boolean utkozik_e(Kep masik, int dx, int dy) { // (dx,dy): koordináta-különbség, pixelben, nem bal-felső koordináta, hanem (bxa,bya)-val eltolt Utkozteto u=(Utkozteto)utkoztetok.get(masik); if (u==null) { utkoztetot_hozzaad(masik); u=(Utkozteto)utkoztetok.get(masik); } // u: k1==this, k2==masik return u.utkoznek_e(dx, dy); } } public static class Utkozteto { /* Az Ütköztető két Kép közötti ütközési táblát tárol. k1: (x1,y1)=(0,0). */ // 2000.03.15 // Ez most jó. // Imp: test with different sizes public static class TablaFelismeresException extends Error {} Kep k1, k2; int alapy; int bt[], jt[]; public boolean utkoznek_e(int dx, int dy) { // (dx,dy): koordináta-különbség, pixelben, nem bal-felső koordináta, hanem (bxa,bya)-val eltolt // dx: k2.x-k1.x try { return dx>bt[dy+alapy] && dx<jt[dy+alapy]; } catch (ArrayIndexOutOfBoundsException e) { return false; } } public void dump_teszt() { System.out.println("alapy="+alapy+".\n"); for (int i=0;i<bt.length;i++) System.out.println(" bt["+i+"]="+bt[i]+" jt[i]="+jt[i]+"."); System.out.println("utk.veg."); } private static int kivon_min(int defa, int i, int j) { return (i==-1 || j==-1)?defa:Math.min(defa,i-j); } public Utkozteto(Kep k1, Kep k2) { /* felépítjük az ütközési táblákat stb. Lényegében felrajzoljuk a két * képet egymás közelében az összes lehetséges módon, majd megnézzük, * hogy ütköztek-e. * Ez időigényes. */ int xx, x, y, u[]; // k1 számítása this.k1=k1; int t1[][]=k1.getPixeltt(); int h1=k1.getHeight(); int b1[]=new int[h1]; int j1[]=new int[h1]; int w1=k1.getWidth(); for (y=h1-1;y>=0;y--) { u=t1[y]; for (x=0;x<w1;x++) if (0!=(u[x]&0xFF000000)) break; // Most: x: a legbaloldalibb, nem átlátszó képpont a sorban (0<=x<w1) if (x==w1) { b1[y]=j1[y]=-1; continue; } b1[y]=x; for (xx=w1-1;xx>x;xx--) if (0!=(u[xx]&0xFF000000)) break; xx++; // Most: xx: a legjobboldalibb, nem átlátszó képpont a sorban (0<=xx<w1) j1[y]=xx; //System.out.println(xx); } /*for (y=0;y<h1;y++) { for (x=0;x<w1;x++) System.out.print(-(t1[y][x]>>31)+" "); System.out.println(""); }*/ // k2 számítása this.k2=k2; int t2[][]=k2.getPixeltt(); int h2=k2.getHeight(); int b2[]=new int[h2]; int j2[]=new int[h2]; int w2=k2.getWidth(); for (y=h2-1;y>=0;y--) { u=t2[y]; for (x=0;x<w2;x++) if (0!=(u[x]&0xFF000000)) break; // Most: x: a legbaloldalibb, nem átlátszó képpont a sorban (0<=x<w2) if (x==w2) { b2[y]=j2[y]=-1; continue; } b2[y]=x; for (xx=w2-1;xx>x;xx--) if (0!=(u[xx]&0xFF000000)) break; xx++; // Most: xx: a legjobboldalibb, nem átlátszó képpont a sorban (0<=xx<w2) j2[y]=xx; } // közös számítás int dbx=k2.getBx1()-k1.getBx1(); alapy=h2-1+k2.getBy1()-k1.getBy1(); bt=new int[h1+h2-1]; jt=new int[h1+h2-1]; /*for (y=-h2+1;y<=h1-1;y++) { // bt[y+h2-1]-et és jt[y+h2-1]-et töltjük ki int y1_mar_nem=Math.min(h1,y+h2); for (int y1=0;y1<y1_mar_nem;y1++) { // k1-nek y1. sorát, k2-nek y+h2-1. sorát vizsgáljuk } }*/ for (y=0;y<=h1+h2-2;y++) { // bt[y]-t és jt[y]-t töltjük ki int y1_indul=Math.max(0,y-h2+1); int y1_mar_nem=Math.min(h1,y+1); bt[y]=jt[y]=Integer.MAX_VALUE; // System.out.println("y="+y+" y1="+y1_indul+".."+(y1_mar_nem-1)+" y2="+(y1_indul-y+h2-1)+".."+(y1_mar_nem-y+h2-1-1)); for (int y1=y1_indul;y1<y1_mar_nem;y1++) { // k1-nek y1. sorát vizsgáljuk //bt[y]=Math.min(bt[y],b1[y1]-j2[0]); //jt[y]=Math.max(jt[y],b2[0]-j1[y1]); //bt[y]=Math.min(bt[y],-b1[y1]+j2[y1-y+h2-1]); //jt[y]=Math.max(jt[y],b2[y1-y+h2-1]-j1[y1]); //bt[y]=Math.min(bt[y],kivon(bt[y],b1[y1],j2[y1-y+h2-1])); //jt[y]=Math.max(jt[y],kivon(jt[y],j1[y1],b2[y1-y+h2-1])); bt[y]=kivon_min(bt[y],b1[y1],j2[y1-y+h2-1]); jt[y]=kivon_min(jt[y],b2[y1-y+h2-1],j1[y1]); //System.out.print(" by1="+y1+": "+(b1[y1])+" ;; "+(j2[y1-y+h2-1])); //System.out.println(" y1="+y1+": "+(b2[y1-y+h2-1])+" ;; "+(j1[y1])); } if ((bt[y]==Integer.MAX_VALUE || jt[y]==Integer.MAX_VALUE) && bt[y]!=jt[y]) throw new TablaFelismeresException(); // belső hiba, soha nem következhet be if (bt[y]==Integer.MAX_VALUE) jt[y]=bt[y]=0; else { bt[y]+=dbx; jt[y]=dbx-jt[y]; } } // már kész is vagyunk :-) } ///Utkozteto() } // class Utkozteto public static class Sdpts { /* Image createEmptyTransparentImage(int w, int h) { // by pts at 2001.03.10 // toolkit.createImage?? // images created this way are read-only, so getGraphics() would fail on this image Image kep=a.createImage(new MemoryImageSource(w, h, new int[w*h], 0, width)); a.prepareImage(kep, -1, -1, null); return kep; } */ private Component a; private FontMetrics fm; private int width; private int height; private Image surface; // surface mérete: (width x 2*height); két részből áll: // felseje: előtér--rajztér, (0,0), width x height // alsaja: háttér, (0,height), width x height // width x height általában a teljes Applet téglalap mérete, ami // PacMan-nél width==224, height==288 // Kisgömböc-nél width==640, height==480 // egy width x height méretű téglalap kirajzolása a képernyőre Java-ban // viszonylag lassú művelet (főleg akkor, ha másodpercente >30-szor meg // akarjuk tenni), a fő célunk az, hogy minél többet megspóroljunk egy // ilyen kirajzolásból. Tehát mindig csak azokat a részeket frissítjük, // amelyek az utolsó kirajzolás óta módosultak. Azzal nem törődünk, hogy // egy rész többször is módosult (ekkor -- pazarlóan -- többször // frissítjük). // Ez a class végzi ezt a frissítés--cache-elést, meg miegymást. // Megjegyzés: az eredeti változat `Applet a;'-t deklarált, // de nekünk elég `java.awt.Component a' is. // Hogyan használjuk? // 1. a class double buffering-et (offscreen rajzolást) valósít meg. // 2. az offscreen buffer a surface felseje. // 3. a surface alsaját sosem rajzoljuk ki közvetlenül, kizárólag a // felsejébe másoljuk (esetleg csak egyes részeit), és majdan a // felsejét rajzoljuk ki // 4. a surface alsajában érdemes a hátteret tárolni, tehát azt az // alapképet, ami többé-kevésbé állandó, csak ritkán kell frissíteni. // Ilyen például PacMan játék esetén a pálya (labirintus) és az // életszám-kijelző. // Execution: // Sdpts sd=new Sdpts(#, #, Applet.this); // ... // Graphics g=sd.getBackgroundGraphics(); // ... // g-re rajzolgatunk -> alsaja // sd.dirtyAdd(#,#,#,#); // amit átírtunk // ... // sd.dirtyClear(); // alsaja -> felseje // sd.draw*(...); // -> felseje // ... // // Applet.this.paint(g)-ben: // sd.render(g,0,0); // (csak a megváltozott bbox-ot) vagy... // sd.renderAll(g,0,0); // egész felsejét kirajzolja // . private Image cover, shadow; private Graphics surfaceGC; // surface teljes egészére private Graphics surfaceGC1; // surface felsejére private Graphics surfaceGC2; // surface alsajára //private Graphics surfaceGC3; // surface fedőlapja //private Graphics surfaceGC4; // surface árnyéklapja private int dirtyX1; private int dirtyY1; private int dirtyX2; private int dirtyY2; private int oldDirtyX1; private int oldDirtyY1; private int oldDirtyX2; private int oldDirtyY2; private Rectangle dirtyRect[]; private int nDirty; public Sdpts(int w, int h, Component applet) { dirtyRect = new Rectangle[200]; width = w; height = h; a = applet; // surface = a.createImage(width, height * 2); surface = OkosAWT.getMainComponent().createImage(width, height * 2); if (surface==null) throw new NullPointerException(); // ^^^ Aaargh. Lüke Java nem tud képet készíteni ha a komponens még nem látszik. //surface=java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(). // getDefaultScreenDevice().getDefaultConfiguration(). // createCompatibleImage(width,2*height, // java.awt.Transparency.OPAQUE); // ^^^ BITMASK-kal nagyon elrondul, de opaque-kal olyan, mint a sima // createImage //cover=java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(). // getDefaultScreenDevice().getDefaultConfiguration(). // createCompatibleImage(width,height, // java.awt.Transparency.BITMASK); // ^^^ explorer-ben SecurityViolation :-(( // !!! /* // kempelen JDK1.2.2 és MSIE OK try { cover=((java.awt.Graphics2D)applet.getGraphics()).getDeviceConfiguration(). createCompatibleImage(width,height*2, java.awt.Transparency.BITMASK); // ^^^ cover.getType()==0 (SUN) } catch (ClassCastException ce) { cover=a.createImage(1,1); // not smaller... }*/ /* cover=createEmptyTransparentImage(width, height*2); */ // cover=(BufferedImage)a.createImage(width,height); // ^^^^ cover.getType()==5; no BufferedImage at all in MS!! // cover=new BufferedImage(width, height, alfasit(((BufferedImage)surface).getType())); // ^^^ ez siman meghal internet exploderben, hianyzik neki egy belso metodus // ^^^ cover.getType()==7; erezhetoen lassabb appletviewerben // System.out.println(cover.getType()); // System.out.println(a.prepareImage(cover, -1, -1, a)); -- always true surfaceGC = surface.getGraphics(); surfaceGC1 = surfaceGC.create(0, 0, width, height); surfaceGC2 = surfaceGC.create(0, height, width, height); // surfaceGC3 = surfaceGC.create(0, 2*height, width, height); //surfaceGC3 = cover.getGraphics().create(0, 0, width, height); //surfaceGC4 = cover.getGraphics().create(0, height, width, height); setFont("", 1, 14); for(int k = 0; k < dirtyRect.length; k++) dirtyRect[k] = new Rectangle(); surfaceGC.setColor(Color.black); surfaceGC.fillRect(0, 0, width, height * 2); } public Image createImage(int w, int h) { // by pts at 2001.03.10 // creates r/w images return a.createImage(w, h); } public Image createImage(ImageProducer ip) { // by pts at 2001.03.10 // toolkit.createImage?? // images created this way are read-only, so getGraphics() would fail on this image Image kep=a.createImage(ip); a.prepareImage(kep, -1, -1, null); return kep; } public Component getComponent() { return a; } public int getWidth() { return width; } public int getHeight() { return height; } public void invalidate(int i, int j, int k, int l) { // k: width, l: height int i1 = i + k; int j1 = j + l; if(i < dirtyX1) dirtyX1 = i; if(i1 > dirtyX2) dirtyX2 = i1; if(j < dirtyY1) dirtyY1 = j; if(j1 > dirtyY2) dirtyY2 = j1; } public void dirtyAdd(int i, int j, int k, int l) { if(nDirty == dirtyRect.length) { Rectangle arectangle[] = new Rectangle[dirtyRect.length * 2]; System.arraycopy(dirtyRect, 0, arectangle, 0, dirtyRect.length); for(int j1 = dirtyRect.length; j1 < arectangle.length; j1++) arectangle[j1] = new Rectangle(); dirtyRect = arectangle; } int i1 = i; int k1 = j; int l1 = k + i; int i2 = l + j; if(i1 < 0) i1 = 0; if(k1 < 0) k1 = 0; if(l1 < 0) l1 = 0; if(i2 < 0) i2 = 0; if(i1 > width) i1 = width; if(k1 > height) k1 = height; if(l1 > width) l1 = width; if(i2 > height) i2 = height; Rectangle rectangle = dirtyRect[nDirty++]; rectangle.x = i1; rectangle.y = k1; rectangle.width = l1 - i1; rectangle.height = i2 - k1; if(i1 < dirtyX1) dirtyX1 = i1; if(l1 > dirtyX2) dirtyX2 = l1; if(k1 < dirtyY1) dirtyY1 = k1; if(i2 > dirtyY2) dirtyY2 = i2; } public void fullCover() { // surface fedőlapját a felsejére teríti if (cover!=null) surfaceGC.drawImage(cover, 0, 0, a); // ^^^ gyors, elegáns szép (pts, 2001.03.04) :-)) } public void dirtyCover() { // surface fedőlapjáról a felsejébe másolja a felsejében megváltozott részeket int i = height*2; // if (false) for(int j = 0; j < nDirty; j++) { Rectangle rectangle = dirtyRect[j]; //surfaceGC.drawImage(((java.awt.image.BufferedImage)cover).getSubimage(rectangle.x, rectangle.y, rectangle.width, rectangle.height), // rectangle.x, rectangle.y, a); // ^^^ tök jó, de kicsit lassú Graphics g1=surfaceGC.create(rectangle.x, rectangle.y, rectangle.width, rectangle.height); if (cover!=null) g1.drawImage(cover, -rectangle.x, -rectangle.y, a); // ^^^ gyors, elegáns szép (pts, 2001.03.04) :-)) g1.dispose(); // surfaceGC.copyArea(rectangle.x, rectangle.y + i, rectangle.width, rectangle.height, 0, -i); //surfaceGC.drawImage(cover, rectangle.x, rectangle.y, rectangle.width, rectangle.height, // rectangle.x, rectangle.y, rectangle.width, rectangle.height, // a); //Graphics g1=surfaceGC.create(rectangle.x, rectangle.y, rectangle.width, rectangle.height); ////g1.drawImage(cover, 0, 0, a); //g1.setColor(Color.white); //g1.fillRect(0,0, rectangle.width, rectangle.height); // ez pont jó } } public void dirtyAddClear() { dirtyAdd(0,0,width,height); dirtyClear(); } public void dirtyAddMax() { dirtyAdd(0,0,width,height); } /** * Surface alsajából a felsejébe (!) másolja (az előző körben) megváltozott * részeket. */ public void dirtyClear() { int i = height; for(int j = 0; j < nDirty; j++) { Rectangle rectangle = dirtyRect[j]; surfaceGC.copyArea(rectangle.x, rectangle.y + i, rectangle.width, rectangle.height, 0, -i); } oldDirtyX1 = dirtyX1; oldDirtyX2 = dirtyX2; oldDirtyY1 = dirtyY1; oldDirtyY2 = dirtyY2; nDirty = 0; dirtyX1 = 0x7fffffff; dirtyX2 = 0x80000000; dirtyY1 = 0x7fffffff; dirtyY2 = 0x80000000; } public void renderAll(Graphics g, int gx, int gy) { // g:(gx,gy)-ra kirajzolja surface teljes felsejét // általában gx==0 && gy==0 Graphics g1 = g.create(gx, gy, width, height); g1.drawImage(surface, 0, 0, null); g1.dispose(); // memory leak discovered by pts!! } public void renderAll(Graphics g, int gx, int gy, int k, int l) { // g:(gx,gy)-(k,l)-re kirajzolja surface teljes felsejét g.drawImage(surface, gx, gy, k, l, 0, 0, width, height, null); } public void render(Graphics g, int i, int j) { // g:(i,j)-re kirajzolja surface felsejének a legutóbbi dirtyClear() // óta megváltozott részeit int k = Math.min(oldDirtyX1, dirtyX1); int l = Math.min(oldDirtyY1, dirtyY1); int i1 = Math.max(oldDirtyX2, dirtyX2); int j1 = Math.max(oldDirtyY2, dirtyY2); if (nDirty == 0 && (k == 0x7fffffff || l == 0x7fffffff || i1 == 0x80000000 || j1 == 0x80000000)) return; Graphics g1 = g.create(k + i, l + j, i1 - k, j1 - l); g1.drawImage(surface, -k, -l, null); g1.dispose(); // memory leak discovered by pts!! } public void burn() { // surface felsejét az alsajába másolja surfaceGC2.drawImage(surface, 0, 0, a); } public void burn(int i, int j, int k, int l) { // surface felsejének egy részét az alsajába másolja surfaceGC.copyArea(i, j, k, l, 0, height); } public Image getBackground() { // surface alsaját adja vissza új képként Image image = a.createImage(width, height); image.getGraphics().drawImage(surface, 0, -height, a); return image; } public void setColor(Color color) { surfaceGC1.setColor(color); } public void setFont(String s, int i, int j) { setFont(new Font(s, i, j)); } public void setFont(Font font) { surfaceGC1.setFont(font); fm = surfaceGC1.getFontMetrics(); } /** * Felseje grafikus kontextusa. */ public Graphics getGraphics() { return surfaceGC1; } public FontMetrics getFontMetrics() { return surfaceGC1.getFontMetrics(); } /** * Alsaja grafikus kontextusa. */ public Graphics getBackgroundGraphics() { return surfaceGC2; } public void setCover(Image cover) { this.cover=cover; if (cover!=null) a.prepareImage(cover, a); } public void setShadow(Image shadow) { this.shadow=shadow; if (shadow!=null) a.prepareImage(shadow, a); } /*public Graphics getCoverGraphics() { // extension by pts return surfaceGC3; } public Graphics getShadowGraphics() { // extension by pts return surfaceGC4; }*/ public void setBackground(Color color) { // surface alsaját kitölti color színnel surfaceGC2.setColor(color); surfaceGC2.fillRect(0, 0, width, height); dirtyAdd(0, 0, width, height); } public void setBackground(Image image, boolean flag) { // surface alsajára rárajzolja a megadott (háttér)képet surfaceGC2.drawImage(image, 0, 0, a); if(flag) dirtyAdd(0, 0, width, height); } public void fillRect(int i, int j, int k, int l) { // surface felsejére rajzol... surfaceGC1.fillRect(i, j, k, l); dirtyAdd(i, j, k, l); } public void drawString(String s, int i, int j) { // surface felsejére rajzol... int k = fm.stringWidth(s); surfaceGC1.drawString(s, i, j + fm.getAscent()); dirtyAdd(i, j, k, fm.getHeight()); } public void drawPoint(int i, int j) { // surface felsejére rajzol... surfaceGC1.drawLine(i, j, i, j); dirtyAdd(i, j, 1, 1); } public void drawPoint(int i, int j, Color color) { // surface felsejére rajzol... surfaceGC1.setColor(color); surfaceGC1.drawLine(i, j, i, j); dirtyAdd(i, j, 1, 1); } public void drawImage(Image image, int i, int j) { // surface felsejére rajzol... surfaceGC1.drawImage(image, i, j, a); dirtyAdd(i, j, image.getWidth(a), image.getHeight(a)); } public void drawImageCover(Image image, int x, int y, boolean dirty) { // surface felsejére rajzol, de felülírja előtakaróval int w=image.getWidth(a); int h=image.getHeight(a); Graphics g1=surfaceGC.create(x, y, w, h); g1.drawImage(image, 0, 0, a); if (cover!=null) g1.drawImage(cover, -x, -y, a); // ^^^ gyors, elegáns szép (pts, 2001.03.04) :-)) g1.dispose(); // if (dirty) dirtyAdd(x, y, w, h); } public void drawShadow(int x, int y, int w, int h) { // surface felsejére rajzol árnyékot Graphics g1=surfaceGC.create(x, y, w, h); // if (shadow!=null) g1.drawImage(shadow, -x, -height-y, a); if (shadow!=null) g1.drawImage(shadow, -x, -y, a); // System.out.println("shadowed"); g1.dispose(); dirtyAdd(x, y, w, h); // -- no speedup :-(( } public void drawCover(int x, int y, int w, int h) { // surface felsejére rajzol árnyékot Graphics g1=surfaceGC.create(x, y, w, h); if (cover!=null) g1.drawImage(cover, -x, -y, a); g1.dispose(); // dirtyAdd(x, y, w, h); // speedup } } // class Sdpts /** * Olyan komponens, ami egyetlen Sdpts-t jelenít meg. */ public static class SdRajzolo extends OkosFixCanvas { protected Sdpts sd; /** * Alapesetben kirajzolja az egesz teglalapot hatterszinnel teliti meg, * majd meghivja a paint-et. Azert rossz megis az alapeset, mert a * bongeszo csak a paint-et hivja, mig a repaint() az update()-et. Szóval * biztos ami biztos, mi rögtön a paint()-et hívjuk. */ public void update(Graphics g) { this.paint(g); } public void paint(Graphics g) { // Canvas újrarajzolás sd.renderAll(g, 0, 0); } /** * Olyan mint a repaint(), de szinkron módon fut, és nem esik áldozatul * a JDK elrontott frissítés-optimalizálásának. */ public void paintMost() { Graphics g=this.getGraphics(); if (g!=null) { synchronized(this) { paint(g); // valószínűleg át van definiálva } g.dispose(); } } protected void init_sd() { this.sd=new Sdpts(this.getSize().width, this.getSize().height, this); } public Sdpts getSd() { return sd; } } /// class Sdrajzolo } // class Kepek