/*
* 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