/* * Engine Alpha ist eine anfängerorientierte 2D-Gaming Engine. * * Copyright (c) 2011 - 2014 Michael Andonie and contributors. * * 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 3 of the License, or * 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, see <http://www.gnu.org/licenses/>. */ package ea; import ea.internal.collision.Collider; import ea.internal.io.ImageLoader; import java.awt.*; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; /** * Ein Bild als Grafische Repraesentation einer Bilddatei, die gezeichnet werden kann. * * @author Michael Andonie */ public class Bild extends Raum { /** * Die Breite der Quellbilddatei */ private final int urBreite; /** * Die Höhe der Quellbilddatei */ private final int urHoehe; /** * Die effektive Breite des Bildes auf der Zeichenebene */ private int breite; /** * Die effektive Höhe des Bildes auf der Zeichenebene */ private int hoehe; /** * Gibt an, ob sich das Bild wiederholen soll.<br /> In diesem Fall wird das Bild in der * originalen Groesse ueber den Zugesprochenen Grund wiederholt. */ private boolean wiederholen; /** * Das BufferedImage, das dieses Bild darstellt. */ private BufferedImage img; /** * Minimaler Konstruktor. Erstellt ein neues Bild an der Position (0|0). * * @param verzeichnis * Der Verzeichnispfad des Bildes, das geladen werden soll. */ public Bild (String verzeichnis) { this(0, 0, verzeichnis); } /** * Der minimale Basiskonstruktor fuer Objekte der Klasse Bild.<br /> Der absolute * Standartkonstruktor, der bei allen anderen ebenfalss aufgerufen wird. Dieser gleicht die * Position an und laedt das Bild * * @param x * Die X-Position * @param y * Die Y-Position * @param verzeichnis * Der Verzeichnispfad des Bildes, das geladen werden soll. */ public Bild (float x, float y, String verzeichnis) { this.position = new Punkt(x, y); this.wiederholen = false; img = ImageLoader.loadExternalImage(verzeichnis); urHoehe = img.getHeight(); urBreite = img.getWidth(); } /** * Erweiterter Konstruktor.<br /> Hiebei wird ein Bild erstellt, wobei auch dessen Masse * variabel angegeben werden koennen. * * @param x * Die X-Position * @param y * Die Y-Position * @param breite * Die Breite, die das Bild haben soll * @param hoehe * Die Hoehe, die das Bild haben soll. * @param verzeichnis * Der Verzeichnispfad des Bildes, das geladen werden soll. */ public Bild (float x, float y, int breite, int hoehe, String verzeichnis) { this(x, y, breite, hoehe, verzeichnis, false); } /** * Erweiterter Konstruktor.<br /> Hiebei wird ein Bild erstellt, wobei auch dessen Masse * variabel angegeben werden koennen. * * @param x * Die X-Position * @param y * Die Y-Position * @param breite * Die Breite, die das Bild haben soll * @param hoehe * Die Hoehe, die das Bild haben soll. * @param verzeichnis * Der Verzeichnispfad des Bildes, das geladen werden soll. * @param wiederholen * Ob das Bild skaliert oder wiederholt werden soll. <br /> In diesem Fall wird das Bild in * der originalen Groesse ueber den Zugesprochenen Grund wiederholt: die Parameter * <code>breite</code> und <code>hoehe</code> beschreiben diesen Flaeche. */ public Bild (float x, float y, int breite, int hoehe, String verzeichnis, boolean wiederholen) { this(x, y, verzeichnis); this.wiederholen = wiederholen; this.breite = breite; this.hoehe = hoehe; this.wiederholen = wiederholen; if (!wiederholen) { img = resize(img, breite, hoehe); } } /** * Ändert ein BufferedImage von seinen Maßen her.<br /> Wird intern benutzt im Konstruktor. * * // TODO: [4.0] Change visibility * * @param img * Das zu beschraenkende Bild * @param width * Die neue Breite des Bildes * @param height * Die neue Hoehe des Bildes */ public static BufferedImage resize (BufferedImage img, int width, int height) { GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsConfiguration gc = env.getDefaultScreenDevice().getDefaultConfiguration(); BufferedImage resize = gc.createCompatibleImage(img.getWidth(), img.getHeight(), img.getTransparency()); Graphics2D g = resize.createGraphics(); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.drawImage(img, 0, 0, width, height, 0, 0, img.getWidth(), img.getHeight(), null); g.dispose(); return resize; } /** * Erstellt ein Bild, unter Eingabe dessen effektiver Größe als prozentualer Anteil an der der * Bilddatei. * * @param x * Die X-Position * @param y * Die Y-Position * @param prozent * Der prozentuale Anteil, den das Bild im Vergleich zu der urspruenglichen Bilddatei haben * soll * @param verzeichnis * Der Verzeichnispfad des Bildes, das geladen werden soll. */ public Bild (float x, float y, int prozent, String verzeichnis) { this(x, y, verzeichnis); img = resize(img, img.getWidth() * prozent / 100, (img.getHeight() * prozent) / 100); } /** * Direkter Konstruktor.<br /> Dieser erwartet direkt die Bilddatei, die es anzuzeigen gilt.<br * /> Dieser Konstruktor wird innerhalb der Engine verwendet fuer die Maus. */ public Bild (float x, float y, BufferedImage img) { this.img = img; this.positionSetzen(new Punkt(x, y)); urHoehe = img.getHeight(); urBreite = img.getWidth(); hoehe = urHoehe; breite = urBreite; } /** * Rotiert das Objekt um eine bereits definierte Rotation. * * TODO: Unterschied zu #drehen erklären * FIXME: Es wird keine neue Breite gesetzt, aber die Breite verändert sich, falls nicht um 90 * n Grad gedreht wird * * @param rot * Das Rotationsobjekt, das die Rotation beschreibt * * @see Rotation */ public void rotieren (Rotation rot) { img = rotieren(img, rot.winkelBogen()); } /** * Rotiert ein BufferedImage und gibt das neue, rotierte Bild aus. * <p/> * Es wird immer nur um die eigene Mitte gedreht!! * * @param img * Das zu rotierende Bild * @param angle * Der Winkel im Bogenmass, um den gedreht werden soll. */ public static BufferedImage rotieren (BufferedImage img, double angle) { int w = img.getWidth(); int h = img.getHeight(); BufferedImage dimg = new BufferedImage((int) (w * Math.sin(angle) + w * Math.cos(angle)), (int) (h * Math.sin(angle) + h * Math.cos(angle)), img.getType()); Graphics2D g = dimg.createGraphics(); g.rotate(angle, w / 2, h / 2); g.drawImage(img, null, (int) (Math.cos(angle) * h / 2 * Math.sin(angle)), (int) (Math.cos(angle) * h / 2 * Math.sin(angle))); g.dispose(); return dimg; } /** * Zeichnet das Objekt. * * @param g * Das zeichnende Graphics-Objekt * @param r * Das BoundingRechteck, dass die Kameraperspektive Repraesentiert.<br /> Hierbei soll * zunaechst getestet werden, ob das Objekt innerhalb der Kamera liegt, und erst dann * gezeichnet werden. */ public void zeichnen (Graphics2D g, BoundingRechteck r) { if (r.schneidetBasic(this.dimension())) { super.beforeRender(g, r); if (!wiederholen) { g.drawImage(img, (int) (position.realX() - r.x), (int) (position.realY() - r.y), null); } else { // Texturfarbe erstellen, Anchor-Rechteck hat genau die Bildmaße Paint tp = new TexturePaint(img, new Rectangle2D.Double(-r.x + position.realX(), -r.y + position.realY(), img.getWidth(), img.getHeight())); // Texturfarbe setzen g.setPaint(tp); // Rechteck füllen g.fill(new Rectangle2D.Double(position.realX() - r.x, position.realY() - r.y, breite, hoehe)); } super.afterRender(g, r); } } /** * @return Ein BoundingRechteck mit minimal nötigem Umfang, um das Objekt <b>voll * einzuschließen</b>. */ public BoundingRechteck dimension () { if (!wiederholen) { return new BoundingRechteck(position.realX(), position.realY(), img.getWidth(), img.getHeight()); } else { return new BoundingRechteck(position.realX(), position.realY(), breite, hoehe); } } /** * {@inheritDoc} Collider wird direkt aus dem das <code>Raum</code>-Objekt umfassenden * <code>BoundingRechteck</code> erzeugt, dass über die <code>dimension()</code>-Methode * berechnet wird. */ @Override public Collider erzeugeCollider () { return erzeugeLazyCollider(); } /** * Gibt die Breite der Bilddatei, aus der dieses Bild besteht, in Pixeln zurueck. * * @return Die Breite der urspruenglichen Bilddatei in Pixeln */ public int normaleBreite () { return urBreite; } /** * Gibt die Hoehe der Bilddatei, aus der dieses Bild besteht, in Pixeln zurueck. * * @return Die Hoehe der urspruenglichen Bilddatei in Pixeln */ public int normaleHoehe () { return urHoehe; } /** * Gibt das Bild als <code>BufferedImage</code> zurueck.<br /> Dies ist eine * JAVA-Standartklasse. * * @return Das Bild als <code>BufferedImage</code>. */ public BufferedImage bild () { return this.img; } public final Bild clone () { return new Bild(positionX(), positionY(), img); } }