RGSS/Bitmap

Aus Scientia
Wechseln zu: Navigation, Suche

Die Bitmap Klasse speichert Bildinformationen, um im RGSS Player Grafiken anzuzeigen. Zur Anzeige werden Spriteobjekte (Sprite) verwendet, die ein Bitmap als Attribut haben.

Wie alle RGSS Komponenten ist diese Klasse in die RGSS-DLL kompiliert, und nicht frei einsehbar. Ihre Struktur wurde inzwischen aber, bis auf ein paar unbekannte Werte innerhalb der Struktur, entschlüsselt.

Für das Laden von Grafikdateien (also statischen Bildern deren Aussehen sich nicht ändert) wird im RPG Maker das Cache-Modul verwendet, welches geladene Bitmap Instanzen in einem Hash speichert, sodass mehrere Sprites sich das selbe Bitmap teilen. Wird das Bitmap aber dynamisch verändert, indem darauf Text oder andere Bitmaps gezeichnet werden, so sollte jeweils eine neue Instanz angelegt werden.

Code Beispiel für eine mögliche Verwendung

# Um das epische Spiel um die epische Saga meines epischen Helden
# etwas aufzulockern, gibt es ein kleines Minispiel wo der Spieler
# an Glorias Malblock sich lustige Bilder "zusammenstempeln" kann.
# Hierfür gibt es einen Array mit Bitmaps die die Stempel enthalten
# der in der Variable +@stempel+ abgelegt ist.
# Ausserdem die Variable +@zeichenfläche+, die das Bitmap hält auf
# das gemalt/gestempelt wird.
# Nun lege ich die Methode an, mit der der Stempel aufs Bild gesetzt
# wird.
def chop_down( arg_cx, arg_cy, arg_index )
  src_bitmap = @stempel[ arg_index ]
  # Die übergebenen Koordinaten beschreiben den Mittelpunkt, wo der
  # Stempel gesetzt werden soll - ich muss also die Ziel Koordinaten
  # etwas verschieben, damit die Bildmitte des Stempels auf den
  # übergebenen Koordinanten liegt.
  chop_x     = arg_cx - src_bitmap.width / 2
  chop_y     = arg_cy - src_bitmap.height / 2
  # Stempel auf der Zeichenfläche abbilden.
  @zeichenfläche.blt( chop_x, chop_y, src_bitmap, src_bitmap.rect )
end

Klassen Methoden

new

Bitmap.new(filename)
Lädt die Grafikdatei und erstellt eine neue Instanz mit diesem Bild.

Es werden automatisch das RTP Verzeichnis sowie verschlüsselte Spielarchive nach dieser Datei durchsucht. Die Dateiendung kann weggelassen werden, wenn es nicht mehrere Dateien gleichen Names gibt, die nur duch ihre Endung sich unterscheiden.


Bitmap.new(width, height)
Erstellt eine neue Bitmap Instanz mit der angegebenen Breite und Höhe.

Seit Version 1.00a des RGSS, wurde diese Größe auf 2048×2048 Pixel begrenzt. Versucht man eine größere Bitmap zu erstellen, so wird eine Exception geworfen, dass das Erstellen des Bitmaps fehlschlug.

Da RGSS Bitmaps 4 Bytes pro Pixel speichern, nur um die Farbe festzulegen, sollte man bedacht sein nicht zu große Grafiken in den RAM zu laden.

Methoden

dispose

Gibt den für die Farbtabelle alokierten Speicher wieder frei. Wenn dieser Speicher bereits freigegeben wurde, passiert gar nichts.

disposed?

Gibt einen Wahrheitswert zurück, ob die Farbtabelle freigegeben wurde.

width

Die Breite der Bitmap.

height

Die Höhe der Bitmap.

rect

Gibt ein Rect zurück, welches Breite und Höhe des Bitmaps beschreibt. X und Y des Rects sind Null.

def rect
  Rect.new( 0, 0, self.width, self.height)
end

blt

blt(x, y, src_bitmap, src_rect[, opacity])
Bildet den Bildausschnitt src_rect (Rect) aus dem Bild src_bitmap auf dieses Bitmap am Punkt (x|y) ab.

Die Deckkraft (opacity) kann zwischen 0 und 255 gewählt werden, wobei 255 der default Wert ist.

stretch_blt

stretch_blt(dest_rect, src_bitmap, src_rect[, opacity])
Bildet den Bildausschnitt src_rect aus dem Bild src_bitmap, gestreckt oder gestaucht in das Rect dest_rect auf diesem Bitmap ab.

Die Deckkraft (opacity) kann zwischen 0 und 255 gewählt werden, wobei 255 der default Wert ist.

fill_rect

fill_rect(x, y, width, height, color)
fill_rect(rect, color)
Füllt den rechteckigen Bereich der durch die Koordinaten oder das Rect beschrieben ist, mit der in color angegebenen Farbe.

gradient_fill_rect (RGSS2)

gradient_fill_rect(x, y, width, height, color1, color2[, vertical])
gradient_fill_rect(rect, color1, color2[, vertical])
Füllt den rechteckigen Bereich der durch die Koordinaten oder das Rect beschrieben ist, mit einem Farbverlauf von color1 zu color2.

Der optionale Parameter +vertical+ ist per Standard false - wird er auf true gesetzt, wird der Farbverlauf noch horizontal sondern vertikal gezeichnet.

clear

Entfernt alle Pixel von der Bitmap, sodass sie nichts anzeigt.

Danach kann man wieder etwas neues darauf zeichnen.

clear_rect (RGSS2)

clear_rect(x, y, width, height)
clear_rect(rect)
Säubert den rechteckigen Bereich der durch die Koordinaten oder das Rect beschrieben ist, indem alle gesetzten Pixel entfernt werden.

Dies ist das selbe wie:

def clear_rect( *args )
  fill_rect( *args, Color.new(0,0,0,0))
end

get_pixel

get_pixel(x, y)
Gibt die Farbe (Color) im Pixel (x|y) auf der Bitmap zurück.

set_pixel

set_pixel(x, y, color)
Setzt die Farbe (Color) die im Pixel (x|y) auf der Bitmap dargestellt werden soll.

hue_change

hue_change(hue)
Ändert den Farbton der Bitmap (0 bis 360°).

Diese Operation ist zeitintensiv. Weiterhin, können wiederholte hue changes zu Farbverlust führen.

blur (RGSS2)

Führt einen Unschärfeeffekt auf dem Bitmap aus.

Diese Operation ist zeitintensiv.

radial_blur (RGSS2)

radial_blur(angle, division)
Führt einen Unschärfeeffekt auf dem Bitmap aus. +angle+ gibt einen Grad-Winkel an, indem der Effekt wirken soll.

+division+ ist der Teiler zwischen 2 und 100. Je größer dieser Teiler ist, desto weicher ist der Effekt. Diese Operation kann sehr zeitintensiv sein.

draw_text

draw_text(x, y, width, height, str[, align])
draw_text(rect, str[, align])
Zeichnet den String +str+ in den Bereich auf der Bitmap, der durch die Koordinaten oder das Rect beschrieben ist.

In RGSS2 wird +str+ automatisch per to_s Methode in einen String umgewandelt, sodas auch ein Objekt was kein String ist übergeben werden kann.

Ist der Text zu lang, um in den angegebenen Bereich zu passen wird er automatisch gestaucht um bis zu 60% sodass er passt.

Die Angabe der Ausrichtung ist optional. Wird +align+ nicht angegeben, wird 0 (linksbündig) übernommen. Man kann auch 1 (zentriert) oder 2 (rechtsbündig) angeben.

Wird der Text vertikal gezeichnet, so geschieht das immer horizontal zentriert.

Da das zeichnen von Text zeitintensiv ist, ist es nicht üblich den Text jedes Frame neu aufs Bitmap zu zeichnen, sondern nur wenn er sich ändert.

text_size

text_size(str)
Gibt ein Rect zurück, welches die Breite und Höhe beschreibt, die ein String einnehmen würde, wenn man ihn mit der draw_text Methode auf dieses Bitmap zeichnet. Dabei ist nicht einberechnet ob der Text kursiv gezeichnet wird, wodurch Breite und Höhe gering abweichen würden.

In RGSS2 wird der angegebene Parameter vor der Prozedur mit der to_s Methode in einen String umgewandelt, falls es kein String ist.

Attribute

font

Die Schriftart (Font) die verwendet wird, um Strings mit der Methode +draw_text+ auf das Bitmap zu zeichnen.

Data-Struktur

struct bgra {
	uint8_t blue;
	uint8_t green;
	uint8_t red;
	uint8_t alpha;
};
 
struct bitmap_data {
	uint32_t unknown[2];
	PBITMAPINFOHEADER header;
	struct bgra *scan0;
	struct bgra *last_scan;
	uint32_t unknown2;
	int32_t stride;
	uint32_t unknown3;
	PBITMAPINFO info;
	uint32_t unknown4[2];
	HBITMAP hbitmap;
	HDC hdc;  // unused?
};
 
struct bitmap {
	uint8_t unknown[8];
	struct bitmap_data *data;  // disposed if NULL
};

Nicht nur in C kann diese Information verwendet werden. Beispielsweise kann man sich in Ruby einen Zwischenspeicher anlegen, der groß genug ist, um alle Pixeldaten zu halten und dann mit der RtlMoveMemory-Funktion der WinAPI sich die Pixeldaten kopieren.

class Bitmap
  #--------------------------------------------------------------------------
  # * Memory Übertragungsfunktion
  #--------------------------------------------------------------------------
  RtlMoveMemory = Win32API.new('Kernel32.dll', 'RtlMoveMemory', 'pii', 'i')
  #--------------------------------------------------------------------------
  # * Pixeldaten als Bytearray (String) holen
  #--------------------------------------------------------------------------
  def _get_color_data
    data  = "bgra" * width * height               #Buffer erstellen
    bsize = data.length                           #Buffer Größe ermitteln
    RtlMoveMemory.call(data, self.address, bsize) #Farbinformationen kopieren
    return data
  end
  #--------------------------------------------------------------------------
  # * Beginn der Rohdaten am Offset: (((bitmap.object_id * 2 + 16) + 8) + 16)
  #--------------------------------------------------------------------------
  def address
    buffer = "xxxx"
    ad     = self.object_id * 2 + 16
    RtlMoveMemory.call(buffer, ad, 4); ad = buffer.unpack("L").first +  8
    RtlMoveMemory.call(buffer, ad, 4); ad = buffer.unpack("L").first + 16
    RtlMoveMemory.call(buffer, ad, 4); return buffer.unpack("L").first
  end
  private :address
end

Anmerkung: Man sollte jetzt nicht auf die blöde Idee kommen, Bitmaps serialisieren zu wollen.

Verwandte Themen

Links