Unbekannte Dateiformate von Baphomets Fluch

Status
Nicht offen für weitere Antworten.

The_S

Top Contributor
Zu deinem 4. Edit: Ja, schaut sehr interessant aus. Und sorry, hab momentan nicht so viel Zeit mich darum zu kümmern, aber ich tu was ich kann ;) .
 

dajos7

Aktives Mitglied
So es gibt neues, Hobbit das mit dem RLE hab ich auch schon gesehen. Und deine Vermutung scheint korrekt zu sein :)

RLE7 ist es um genauer zu sein. Zitat eines Mitstreiters:

RLE7. Der Frame-Block beginnt wie gehabt:

char[4] "RLE7"
uint32 Datenlänge ohne Header
uint16 Breite
uint16 Länge
int16 unbekannt
int16 unbekannt
byte[x] komprimierte Daten

Die unbekannten Werte sind gerne mal negativ, ich vermute aus dem Bauch
heraus Positionsangaben, vielleicht einen Referenzpunkt ("Zentrum") im
Frame, der bei Animationen des Sprites hilft oder etwas ähnliches.

Bei der Methode RLE7 ist der Name Programm: Es handelt sich um eine
Lauflängenkodierung, deren Längenangaben auf 7 Bits beschränkt sind:

- Lese Opcode (1 Byte)
- Falls Opcode <= 0x7f, dann:
- Lese Farbe (1 Byte)
- Wiederhole Farbe (Opcode+1)-mal
- Sonst (Opcode > 0x7f):
- Schreibe Opcode direkt als Farbe

Als Beispiel hängt eine Dekompression des ersten Frames aus 007EC3D4.1
(paris1.clu) an (rle7.gif). Für mich sieht das verdächtig nach George
aus ... (Tut mir leid wegen der primitiven ASCII-Ausgabe, aber ich
wollte auf die Schnelle keinen vollständigen Konverter bauen. ;-))

dazu 2 Bilder, die er entschlüsselt hat.

jim.gif


rle7.gif


EDIT2
Und hier noch ein Auszug aus dem SCUMMVM Source:
Code:
00677 
00678 void Screen::decompressTony(uint8 *src, uint32 compSize, uint8 *dest) {
00679     uint8 *endOfData = src + compSize;
00680     while (src < endOfData) {
00681         uint8 numFlat = *src++;
00682         if (numFlat) {
00683             memset(dest, *src, numFlat);
00684             src++;
00685             dest += numFlat;
00686         }
00687         if (src < endOfData) {
00688             uint8 numNoFlat = *src++;
00689             memcpy(dest, src, numNoFlat);
00690             src += numNoFlat;
00691             dest += numNoFlat;
00692         }
00693     }
00694 }
00695 
00696 void Screen::decompressRLE7(uint8 *src, uint32 compSize, uint8 *dest) {
00697     uint8 *compBufEnd = src + compSize;
00698     while (src < compBufEnd) {
00699         uint8 code = *src++;
00700         if ((code > 127) || (code == 0))
00701             *dest++ = code;
00702         else {
00703             code++;
00704             memset(dest, *src++, code);
00705             dest += code;
00706         }
00707     }
00708 }
00709 
00710 void Screen::decompressRLE0(uint8 *src, uint32 compSize, uint8 *dest) {
00711     uint8 *srcBufEnd = src + compSize;
00712     while (src < srcBufEnd) {
00713         uint8 color = *src++;
00714         if (color) {
00715             *dest++ = color;
00716         } else {
00717             uint8 skip = *src++;
00718             memset(dest, 0, skip);
00719             dest += skip;
00720         }
00721     }
00722 }
00723

EDIT2
Noch was neues:
Noch ein kurzes Update: Mittlerweile habe ich etwas gefunden, das
ziemlich eindeutig nach Paletten aussieht. In paris1.clu existieren
diverse Dateien mit genau 768 (= 256 * 3) Bytes Größe:

007E76D4.1
007ECEA8.2
007F0F6C.3
007F277C.3
007F915C.4
007FDAC0.5
00801A04.6
00802CC4.7
00804924.8

Die enthaltenen Bytes sind anscheinend immer <= 63, was für Farbangaben
aus der DOS-Zeit durchaus üblich ist. Durch einen einfachen Linksshift
um 2 bzw. eine Multiplikation mit 4 lassen sich die Werte in den
üblichen [0..255]-Farbraum umrechnen. Der Farbeintrag 0 (meist (0, 63,
0)) dürfte die Transparenzfarbe sein. Eigentlich ist nur noch zu klären,
in welcher Reihenfolge R, G und B gespeichert sind ...

Was -- und ob überhaupt -- die CDT damit zu tun haben, weiß ich zur Zeit
nicht. Allerdings meine ich mich zu erinnern, daß es spätestens in BS2
Transparenzeffekte gab (Person hinter Glasscheibe u.ä.) -- keine Ahnung,
ob die ältere Engine-Version das auch schon unterstützte.
 

The_S

Top Contributor
Na damit lässt sich doch arbeiten, hier eine kleine Beta-Version (erweiterbar ;) ):

Code:
	public static byte[][] getDataFromSprite(File sprite) throws IOException {
		
		ArrayList<Byte> b = new ArrayList<Byte>();
		byte[] bytes = new byte[(int)sprite.length()];
		int pointer = 0;
		boolean start = false;
		String temp = null;
		FileInputStream fis = new FileInputStream(sprite);
		fis.read(bytes);
		Byte[][] retVal = new Byte[bytes[20] + 1][0];
		
		// Header
		for (pointer = 0; pointer < (bytes[24] & 0xFF); pointer++) {
			b.add(bytes[pointer]);
		}
		retVal[0] = b.toArray(new Byte[b.size()]);
		
		// Sprites
		for (int i = 0; i < (bytes[20] & 0xFF); i++) {
			b.clear();
			start = true;
			while (pointer < bytes.length) {
				if (pointer + 3 < bytes.length) {
					temp = new String(new byte[] {bytes[pointer], bytes[pointer + 1], bytes[pointer + 2], bytes[pointer + 3]});
					if (!start && ("JIM ".equals(temp) || temp.startsWith("RLE7"))) {
						break;
					}
				}
				b.add(bytes[pointer++]);
				start = false;
			}
			retVal[i + 1] = b.toArray(new Byte[b.size()]);
		}
		return convertByteTobyte(retVal);
	}

	public static void extractSprite(File f, HashMap<Integer, Integer> map) throws IOException {
		
		byte[][] val = getDataFromSprite(f);
		for (int i = 1; i < val.length; i++) {
			ImageIO.write(convertFrame(val[i], map), "png", new File("C:/fluch/sprites/" + i + ".png"));
		}
	}

	public static BufferedImage convertFrame(byte[] frame, HashMap<Integer, Integer> map) {
		
		int alpha = new Color(0, 0, 0, 0).getRGB();
		BufferedImage img = new BufferedImage(frame[8] & 0xFF, frame[10] & 0xFF, BufferedImage.TYPE_INT_ARGB);
		if (frame[0] == 'R' && frame[1] == 'L' && frame[2] == 'E' && frame[3] == '7') { // RLE7
			for (int i = 15, x = 0, y = 0; i < frame.length; i++) {
				if ((frame[i] & 0xFF) < 128) {
					int col = 0;
					if (map.get(frame[i + 1] & 0xFF) == null) {
						col = alpha;
					}
					else {
						col = map.get(frame[i + 1] & 0xFF);
					}
					for (int j = frame[i] & 0xFF; j > -1; j--) {
						if (img.getWidth() <= x) {
							x = 0;
							y++;
						}
						img.setRGB(x++, y, col);
					}
					i++;
				}
				else {
					if (img.getWidth() <= x) {
						x = 0;
						y++;
					}
					img.setRGB(x++, y, map.get(frame[i] & 0xFF));
				}
			}
		}
		return img;
	}

	public static byte[][] convertByteTobyte(Byte[][] byt) {
		
		byte[][] ret = new byte[byt.length][0];
		for (int i = 0; i < ret.length; i++) {
			ret[i] = convertByteTobyte(byt[i]);
		}
		return ret;
	}
	
	public static byte[] convertByteTobyte(Byte[] byt) {
		
		byte[] ret = new byte[byt.length];
		for (int i = 0; i < ret.length; i++) {
			ret[i] = byt[i];
		}
		return ret;
	}

Ist nur teilweise komisch verzerrt ... vermutlich liegt da noch irgendwo ein Fehler ...

[edit] ach, gerade festgestellt, dass hier die Größe des Sprite-Headers und der Frame-Auflösung noch nicht als int32 bzw. int16 betrachtet wird. Kommt also noch zu fehlern, wenn der Sprite-Header größer als 255 oder die Auflösung größer als 255x255 ist
 

dajos7

Aktives Mitglied
und noch mehr:

Die Parallax-Layer-Dateien sind meiner Ansicht nach wie folgt aufgebaut:

char[16] "PARALLAX LAYER",0,0
uint16 Layerbreite
uint16 Layerhöhe
uint32[Layerhöhe] Zeilenoffsets
byte[x] Zeilendaten

Jedes Zeilenoffset führt zu genau einer Bildzeile des Layers innerhalb
der Datei. Da Parallax-Layer typischerweise "Bilder mit Löchern" sind,
sind die Zeilen dementsprechend aufgebaut:

// solange noch Zeilendaten vorhanden
uint8 Transparenzlänge
uint8 Farblänge
uint8[Farblänge] Farbangaben (d.h. Palettenreferenzen)

Alle Längen zusammen sollten genau die Layerbreite ergeben.

Ich habe das bisher nicht durch einen Konverter verifiziert, sondern bin
nur per Hand einige Zeileneinträge durchgegangen -- bisher scheint das
ganz gut hinzukommen.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben