示例#1
0
		/// <summary>
		/// Lädt die SLP-Daten.
		/// </summary>
		/// <param name="buffer">Ein Puffer mit den SLP-Daten. Die Leseposition wird entsprechend der Datenlänge erhöht.</param>
		/// <remarks></remarks>
		private void loadData(RAMBuffer buffer)
		{
			// Header

			#region SLP-Header

			_headers.Version = buffer.ReadString(4);
			_headers.FrameCount = buffer.ReadUInteger();
			_headers.Comment = buffer.ReadString(24);

			#endregion SLP-Header

			// Frame-Informationen: Header

			#region Frame-Header

			for(int i = 0; i < _headers.FrameCount; i++)
			{
				// Neues Frame-Header-Objekt erstellen
				FrameInformationHeader aktFIH = new FrameInformationHeader();

				// Der Zeichenindex in der SLP-Datei, an dem die Kommandotabelle des Frames beginnt
				aktFIH.FrameCommandsOffset = buffer.ReadUInteger();

				// Der Zeichenindex in der SLP-Datei, an dem die Umrissdaten (RowEdge) des Frames gespeichert sind
				aktFIH.FrameOutlineOffset = buffer.ReadUInteger();

				// Der Zeichenindex in der SLP-Datei, an dem die Farbpalette des Frames definiert ist; Genaueres ist nicht bekannt
				aktFIH.PaletteOffset = buffer.ReadUInteger();

				// Die Frame-Eigenschaften; die Bedeutung dieses Werts ist unbekannt
				aktFIH.Properties = buffer.ReadUInteger();

				// Die Abmessungen des Frames
				aktFIH.Width = buffer.ReadUInteger();
				aktFIH.Height = buffer.ReadUInteger();

				// Die Anker (Mittelpunkt) des Frames
				aktFIH.AnchorX = buffer.ReadInteger();
				aktFIH.AnchorY = buffer.ReadInteger();

				// Frame-Header in die zentrale Liste schreiben
				_frameInformationHeaders.Add(aktFIH);
			}

			#endregion Frame-Header

			// Frameinformationen: Daten

			#region Frame-Daten (RowEdge und Kommandotabelle)

			// Gefundene Einstellungen merken
			bool useTransp = false;
			bool useOutline1 = false;
			bool useOutline2 = false;
			bool usePlayerColor = false;
			bool useShadow = false;

			// Frames einzeln durchgehen
			for(int i = 0; i < _headers.FrameCount; i++)
			{
				// Spielernummer einer ggf. ausgegebenen Einheit
				const byte Spielernummer = 0; // Spieler 1 => Blau

				// Frame-Header-Daten abrufen
				FrameInformationHeader aktFIH = _frameInformationHeaders[i];

				// Neues Frame-Daten-Objekt erstellen
				FrameInformationData aktFID = new FrameInformationData();

				// RowEdge (leere Fläche [=> Transparenz, ohne Kommandos], von den Bildrändern ausgehend)

				#region RowEdge-Daten

				// Arrays initialisieren: Das RowEdge-Array und das BinaryRowEdge-Array, um bei unveränderten Frames dieses nicht neu berechnen zu müssen und direkt schreiben zu können
				aktFID.RowEdge = new ushort[aktFIH.Height, 2];
				aktFID.BinaryRowEdge = new BinaryRowedge[aktFIH.Height];
				for(int j = 0; j < aktFIH.Height; j++)
				{
					// Werte einlesen
					ushort left = buffer.ReadUShort(); // Links
					ushort right = buffer.ReadUShort(); // Rechts

					// Evtl. falsche Werte korrigieren
					{
						// Links
						if(left > aktFIH.Width)
						{
							left = (ushort)aktFIH.Width;
						}

						// Rechts
						if(right > aktFIH.Width)
						{
							right = (ushort)aktFIH.Width;
						}
					}

					// Werte speichern
					aktFID.RowEdge[j, 0] = left;
					aktFID.RowEdge[j, 1] = right;

					// Binäres RowEdge mitschreiben
					aktFID.BinaryRowEdge[j] = new BinaryRowedge(left, right);
				}

				#endregion RowEdge-Daten

				// Kommandotabellen-Offsets abrufen

				#region Kommandotabellen-Offsets

				aktFID.CommandTableOffsets = new uint[aktFIH.Height];
				for(int j = 0; j < aktFIH.Height; j++)
				{
					aktFID.CommandTableOffsets[j] = buffer.ReadUInteger();
				}

				#endregion Kommandotabellen-Offsets

				// Kommandotabelle zeilenweise auslesen und umgewandelte Kommandotabelle erzeugen

				#region Kommandotabelle

				// Gleichzeitig wird die binaryCommands-Variable miterzeugt, um unveränderte Frames ggf. ohne Umweg über eine Neuerstellung der Kommandos wieder in die *.slp schreiben zu können
				aktFID.CommandTable = new int[aktFIH.Height, aktFIH.Width];
				aktFID.BinaryCommandTable = new List<BinaryCommand>();
				for(int j = 0; j < aktFIH.Height; j++)
				{
					// Gibt die aktuelle X-Position innerhalb des generierten Bildes (in Pixeln) an
					int aktPtr = 0;

					// Linker RowEdge-Bereich ist leer => transparent, also -1
					for(int k = 0; k < aktFID.RowEdge[j, 0]; k++)
					{
						aktFID.CommandTable[j, aktPtr + k] = -1;
					}

					// Linker RowEdge-Bereich ist komplett in das Bild geschrieben worden
					aktPtr += aktFID.RowEdge[j, 0];

					// Wird false, wenn ein Zeilenumbruch erreicht wurde
					bool Weiter = true;

					// Kommando für Kommando lesen
					while(Weiter)
					{
						// Das aktuelle Kommandobyte
						byte aktKommandoByte = buffer.ReadByte();

						// Das aktuelle Kommando (die ersten vier Bits des Kommandobytes) Wird berechnet, um das oft mit der Datenlänge korrelierte Kommandobyte bestimmen zu können (es müssen nur die Werte 0 bis 15 abgefragt werden, statt eigentlich 0 bis 255; weiterhin geben immer die ersten 2 oder 4 Bits das Kommando an, die anderen 4 oder 6 meist nur die jeweilige Länge)
						byte aktKommando = (byte)(aktKommandoByte & 0x0F);

						// Das Kommando auswerten
						switch(aktKommando)
						{
							// Farbblock (klein)
							case 0x00:
							case 0x04:
							case 0x08:
							case 0x0C:
								{
									// Länge ermitteln
									int len = aktKommandoByte >> 2;

									// Daten einlesen
									byte[] dat = buffer.ReadByteArray(len);

									// Daten in die Kommandotabelle schreiben
									for(int k = 0; k < len; k++)
									{
										aktFID.CommandTable[j, aktPtr + k] = dat[k];
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdColor(ref aktFID, dat);

									break;
								}

							// Transparenz (klein)
							case 0x01:
							case 0x05:
							case 0x09:
							case 0x0D:
								{
									// Länge ermitteln
									int len = aktKommandoByte >> 2;

									// Transparenz in die Kommandotabelle schreiben
									for(int k = 0; k < len; k++)
									{
										aktFID.CommandTable[j, aktPtr + k] = -1;
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdTransp(ref aktFID, len);

									// Transparenz wurde gefunden
									useTransp = true;

									break;
								}

							// Großer Farbblock
							case 0x02:
								{
									// Hilfs-Kommandobyte auslesen
									byte byte2 = buffer.ReadByte();

									// Länge ermitteln
									int len = ((aktKommandoByte & 0xF0) << 4) + byte2;

									// Daten einlesen
									byte[] dat = buffer.ReadByteArray(len);

									// Daten in die Kommandotabelle schreiben
									for(int k = 0; k < len; k++)
									{
										aktFID.CommandTable[j, aktPtr + k] = dat[k];
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdColor(ref aktFID, dat);

									break;
								}

							// Großer Transparenzblock
							case 0x03:
								{
									// Hilfs-Kommandobyte auslesen
									byte byte2 = buffer.ReadByte();

									// Länge ermitteln
									int len = ((aktKommandoByte & 0xF0) << 4) + byte2;

									// Transparenz in die Kommandotabelle schreiben
									for(int k = 0; k < len; k++)
									{
										aktFID.CommandTable[j, aktPtr + k] = -1;
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdTransp(ref aktFID, len);

									// Transparenz wurde gefunden
									useTransp = true;

									break;
								}

							// Spielerfarbenblock
							case 0x06:
								{
									// Die oberen 4 Bits bestimmen
									byte next4Bits = (byte)(aktKommandoByte & 0xF0);

									// Die Länge der Daten
									int len = 0;

									// Die oberen 4 Bits sind 0, wenn die Länge im nächsten Byte angegeben ist; ansonsten werden diese um 4 nach rechts verschoben und sind somit als Längenangabe verwendbar
									if(next4Bits == 0)
									{
										len = buffer.ReadByte();
									}
									else
									{
										len = next4Bits >> 4;
									}

									// Daten auslesen
									byte[] dat = buffer.ReadByteArray(len);

									// Daten durchgehen
									for(int k = 0; k < len; k++)
									{
										// Das aktuelle Byte
										byte aktVal = dat[k];

										// Farbindex berechnen: Die Spielerfarben liegen zwischen 16 und 13. Beim SLP-Schreiben wurde von allen Werten 16 subtrahiert => aktVal liegt zwischen 0 und 7. Zwischen den Spielerfarben auf der Palette liegen immer 16 Einheiten. Angegeben wird die Spielerfarbe durch: 16 + (Spielernummer - 1) * 16, wobei die Spielernummer zwischen 1 und 8 liegt.
										aktVal = (byte)(aktVal + 16 + 16 * Spielernummer);

										// Wert in das Bild schreiben
										aktFID.CommandTable[j, aktPtr + k] = aktVal;

										// Wert zurück in Array schreiben, um das Schreiben der Binary-Daten zu erleichtern
										dat[k] += 16;
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdPlayerColor(ref aktFID, dat);

									// Spielerfarben wurden gefunden
									usePlayerColor = true;

									break;
								}

							// Einfarbiger Block
							case 0x07:
								{
									// Die oberen 4 Bits bestimmen
									byte next4Bits = (byte)(aktKommandoByte & 0xF0);

									// Die Länge der Daten
									int len = 0;

									// Die oberen 4 Bits sind 0, wenn die Länge im nächsten Byte angegeben ist; ansonsten werden diese um 4 nach rechts verschoben und sind somit als Längenangabe verwendbar
									if(next4Bits == 0)
									{
										len = buffer.ReadByte();
									}
									else
									{
										len = next4Bits >> 4;
									}

									// Das nächste Byte gibt die Farbe an
									byte farbe = buffer.ReadByte();

									// Hilfsvariable für das Binary-Schreiben
									byte[] dat = new byte[len];

									// Betroffene Pixel durchgehen
									for(int k = 0; k < len; k++)
									{
										// Farbe in das Bild schreiben
										aktFID.CommandTable[j, aktPtr + k] = farbe;

										// Farbe in das Array übernehmen
										dat[k] = farbe;
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdColor(ref aktFID, dat);

									break;
								}

							// Einfarbiger Spielerfarben-Block
							case 0x0A:
								{
									// Die oberen 4 Bits bestimmen
									byte next4Bits = (byte)(aktKommandoByte & 0xF0);

									// Die Länge der Daten
									int len = 0;

									// Die oberen 4 Bits sind 0, wenn die Länge im nächsten Byte angegeben ist; ansonsten werden diese um 4 nach rechts verschoben und sind somit als Längenangabe verwendbar
									if(next4Bits == 0)
									{
										len = buffer.ReadByte();
									}
									else
									{
										len = next4Bits >> 4;
									}

									// Das nächste Byte gibt die Grundfarbe an
									byte farbe = buffer.ReadByte();

									// Hilfsvariable für das Binary-Schreiben
									byte[] dat = new byte[len];

									// Daten durchgehen
									for(int k = 0; k < len; k++)
									{
										// Das aktuelle Byte
										byte aktVal = farbe;

										// Farbindex berechnen: Die Spielerfarben liegen zwischen 16 und 13. Beim SLP-Schreiben wurde von allen Werten 16 subtrahiert => aktVal liegt zwischen 0 und 7. Zwischen den Spielerfarben auf der Palette liegen immer 16 Einheiten. Angegeben wird die Spielerfarbe durch: 16 + (Spielernummer - 1) * 16, wobei die Spielernummer zwischen 1 und 8 liegt.
										aktVal = (byte)(aktVal + 16 + 16 * Spielernummer);

										// Wert in das Bild schreiben
										aktFID.CommandTable[j, aktPtr + k] = aktVal;

										// Wert zurück in Array schreiben, um das Schreiben der Binary-Daten zu erleichtern
										dat[k] = (byte)(farbe + 16);
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdPlayerColor(ref aktFID, dat);

									// Spielerfarben wurden gefunden
									usePlayerColor = true;

									break;
								}

							// Schattenblock
							case 0x0B:
								{
									// Die oberen 4 Bits bestimmen
									byte next4Bits = (byte)(aktKommandoByte & 0xF0);

									// Die Länge der Daten
									int len = 0;

									// Die oberen 4 Bits sind 0, wenn die Länge im nächsten Byte angegeben ist; ansonsten werden diese um 4 nach rechts verschoben und sind somit als Längenangabe verwendbar
									if(next4Bits == 0)
									{
										len = buffer.ReadByte();
									}
									else
									{
										len = next4Bits >> 4;
									}

									// Schattenpixel einzeln durchgehen
									for(int k = 0; k < len; k++)
									{
										// Schatten in Bild schreiben
										aktFID.CommandTable[j, aktPtr + k] = -4;
									}

									// Es wurden len Pixel eingelesen
									aktPtr += len;

									// Binary-Wert erstellen
									cmdShadow(ref aktFID, len);

									// Schatten wurde gefunden
									useShadow = true;

									break;
								}

							// Outline-Kommandos: Hängen von Kommandobyte ab ("E" am Ende bei allen gemeinsam)
							case 0x0E:
								{
									switch(aktKommandoByte)
									{
										// Outline1-Pixel
										case 0x4E:
											{
												// Outline auf Bild schreiben
												aktFID.CommandTable[j, aktPtr] = -2;

												// Es wurde ein Pixel eingelesen
												aktPtr += 1;

												// Binary-Wert erstellen
												cmdOutline1(ref aktFID, 1);

												// Outline1 wurde gefunden
												useOutline1 = true;

												break;
											}

										// Outline2-Pixel
										case 0x6E:
											{
												// Outline auf Bild schreiben
												aktFID.CommandTable[j, aktPtr] = -3;

												// Es wurde ein Pixel eingelesen
												aktPtr += 1;

												// Binary-Wert erstellen
												cmdOutline2(ref aktFID, 1);

												// Outline2 wurde gefunden
												useOutline2 = true;

												break;
											}

										// Outline1-Block
										case 0x5E:
											{
												// Blocklänge abrufen
												int len = buffer.ReadByte();

												// Outlinepixel in der angegebenen Anzahl auf das Bild schreiben
												for(int k = 0; k < len; k++)
												{
													aktFID.CommandTable[j, aktPtr + k] = -2;
												}

												// Es wurden len Pixel eingelesen
												aktPtr += len;

												// Binary-Wert erstellen
												cmdOutline1(ref aktFID, len);

												// Outline1 wurde gefunden
												useOutline1 = true;

												break;
											}

										// Outline2-Block
										case 0x7E:
											{
												// Blocklänge abrufen
												int len = buffer.ReadByte();

												// Outlinepixel in der angegebenen Anzahl auf das Bild schreiben
												for(int k = 0; k < len; k++)
												{
													aktFID.CommandTable[j, aktPtr + k] = -3;
												}

												// Es wurden len Pixel eingelesen
												aktPtr += len;

												// Binary-Wert erstellen
												cmdOutline2(ref aktFID, len);

												// Outline2 wurde gefunden
												useOutline2 = true;

												break;
											}
									}
									break;
								}

							// Zeilenende
							case 0x0F:
								{
									// Kein weiterer while-Schleifen-Durchlauf => nächste Zeile (for-Schleife)
									Weiter = false;

									// Binary-Wert erstellen
									cmdEOL(ref aktFID);

									break;
								}
						} // Ende switch: Kommando auswerten
					} // Ende while: Kommando für Kommando

					// Rechtes RowEdge einfügen (leere Bereiche) Leere Bereiche sind transparent, also erstmal -1 als Palettenindex schreiben
					for(int k = 0; k < aktFID.RowEdge[j, 1]; k++)
					{
						aktFID.CommandTable[j, aktPtr + k] = -1;
					}
					aktPtr += aktFID.RowEdge[j, 1];
				} // Ende for: Zeile für Zeile

				#endregion Kommandotabelle

				// Framedaten zur zentralen Liste hinzufügen
				_frameInformationData.Add(aktFID);
			} // Ende for: Frame für Frame

			// Einstellungen speichern
			_settings = (useTransp ? Settings.UseTransparency : 0)
				| (useOutline1 ? Settings.UseOutline1 : 0)
				| (useOutline2 ? Settings.UseOutline2 : 0)
				| (usePlayerColor ? Settings.UsePlayerColor : 0)
				| (useShadow ? Settings.UseShadow : 0);

			#endregion Frame-Daten (RowEdge und Kommandotabelle)
		}
示例#2
0
		private void computeCmdBytes(ref FrameInformationData fid, ref int destCommandFullLength)
		{
			// Gesamtzahl der Kommandos und die Gesamt-Kommandolänge berechnen
			int total = 0;
			for(int i = 0; i < fid.BinaryCommandTable.Count; i++)
			{
				total += fid.BinaryCommandTable[i].CommandLength;
			}

			// Wert über Referenz zurück an die aufrufende Funktion übergeben
			destCommandFullLength = total;
		}
示例#3
0
		private int cmdByteLengthInLine(ref FrameInformationData fid, int line)
		{
			// Positionsvariablen
			int aktLine = 0;
			int aktLength = 0;

			// Alle Kommandos durchlaufen
			for(int i = 0; i < fid.BinaryCommandTable.Count; i++)
			{
				// Kommandolänge hinzuaddieren
				aktLength += fid.BinaryCommandTable[i].CommandLength;

				// Wurde ein Zeilenende erreicht?
				if(fid.BinaryCommandTable[i]._cmdbyte == 0x0F)
				{
					// Liegt die gesuchte Zeile vor?
					if(aktLine == line)
					{
						// Zeilenlänge zurückgeben
						return aktLength;
					}
					else
					{
						// Nächste Zeile
						aktLine++;
						aktLength = 0;
					}
				}
			}

			// Zeile nicht gefunden?
			return 0;
		}
示例#4
0
		private void cmdShadow(ref FrameInformationData fid, int length)
		{
			// Das Kommandobyte
			byte command = 0x0B;

			// Zu lange Schatten-Blöcke in rekursiv behandelte Teilstücke zerlegen
			if(length >= 256)
			{
				// Array links und rechts halbieren und Funktion erneut aufrufen (rekursiv) Längen der beiden Seiten (Mittelpunkt suchen)
				int left, right;

				// Mittelpunkt suchen, nach ungeraden und geraden Längen unterscheiden
				if(length % 2 == 0) // Gerade
				{
					// Beide Seiten sind gleich lang
					left = length / 2;
					right = length / 2;
				}
				else
				{
					// Links ist kürzer als rechts
					left = (length - 1) / 2;
					right = (length + 1) / 2;
				}

				// Neuaufruf
				cmdShadow(ref fid, left);
				cmdShadow(ref fid, right);

				// Fertig
				return;
			}

			// Das nächste Byte kommt in...
			byte nextByte = (byte)length;

			// Kommando anfügen
			fid.BinaryCommandTable.Add(new BinaryCommand(command, nextByte));
		}
示例#5
0
		private void cmdEOL(ref FrameInformationData fid)
		{
			// Das Kommandobyte
			byte command = 0x0F;

			// Kommando anfügen
			fid.BinaryCommandTable.Add(new BinaryCommand(command));
		}
示例#6
0
		private void cmdColorBlock(ref FrameInformationData fid, byte[] array, bool usePlayerColor)
		{
			// Länge der Daten
			int aLength = array.Length;

			// Positions- und Zustandsvariablen erstellen
			int start = 0;
			int length = 0;
			int playerColorStart = 0;
			int playerColorLength = 0; // Gibt an, wie lange schon eine Spielerfarbe vorliegt
			bool isPrevPlayerColor = false;

			// Aktuelle Position
			int pos = 0;

			// Prüfen, ob schon am Anfang eine Spielerfarbe vorliegt
			isPrevPlayerColor = ((array[pos] >= 16 && array[pos] <= 23) && usePlayerColor);
			if(isPrevPlayerColor)
			{
				playerColorStart = 0;
				playerColorLength = 1;
			}
			else
			{
				start = 0;
				length = 1;
			}

			// Byte für Byte das Array durchgehen
			pos = 1;
			while(pos < aLength)
			{
				// Liegt eine Spielerfarbe vor?
				bool isPlayerColor = ((array[pos] >= 16 && array[pos] <= 23) && usePlayerColor);
				if(isPlayerColor && !isPrevPlayerColor)
				{
					// Es beginnt eine neue Spielerfarbe, also den vorherigen Farbblock abschließen und schreiben
					byte[] toWrite = new byte[length];
					for(int i = 0; i < length; i++)
					{
						toWrite[i] = array[start + i];
					}
					cmdColor(ref fid, toWrite);

					// Neuen Spielerfarben-Block anfangen
					playerColorStart = pos;
					playerColorLength = 1;

					// Es liegt eine Spielerfarbe vor
					isPrevPlayerColor = true;
				}
				else if(!isPlayerColor && isPrevPlayerColor)
				{
					// Es endet ein Spielerfarben-Block, also muss dieser geschrieben werden
					byte[] toWrite = new byte[playerColorLength];
					for(int i = 0; i < playerColorLength; i++)
					{
						toWrite[i] = array[playerColorStart + i];
					}
					cmdPlayerColor(ref fid, toWrite);

					// Neuen Farbblock beginnen
					start = pos;
					length = 1;

					// Es liegt keine Spielerfarbe mehr vor
					isPrevPlayerColor = false;
				}
				else if(isPlayerColor)
				{
					// Der laufende Spielerfarbenblock geht weiter
					playerColorLength++;
				}
				else
				{
					// Der laufende Farbblock geht weiter
					length++;
				}

				// Nächster Index
				pos++;
			}

			// Den letzten Block noch abschließen
			if(isPrevPlayerColor)
			{
				// Spielerfarbe
				byte[] toWrite = new byte[playerColorLength];
				for(int i = 0; i < playerColorLength; i++)
				{
					toWrite[i] = array[playerColorStart + i];
				}
				cmdPlayerColor(ref fid, toWrite);
			}
			else
			{
				// Normale Farbe
				byte[] toWrite = new byte[length];
				for(int i = 0; i < length; i++)
				{
					toWrite[i] = array[start + i];
				}
				cmdColor(ref fid, toWrite);
			}
		}
示例#7
0
		private void cmdOutline2(ref FrameInformationData fid, int length)
		{
			// Das Kommandobyte
			byte command;

			// Anhand der Länge entscheiden, ob ein Block vorliegt oder nicht
			if(length == 1)
			{
				// Einfacher Umriss-Pixel
				command = 0x6E;
				fid.BinaryCommandTable.Add(new BinaryCommand(command));
			}
			else
			{
				// Block
				command = 0x7E;
				byte nextByte = (byte)length;
				fid.BinaryCommandTable.Add(new BinaryCommand(command, nextByte));
			}
		}
示例#8
0
		private void cmdPlayerColor(ref FrameInformationData fid, byte[] array)
		{
			// Das Kommandobyte ist schon bekannt
			byte command = 0x06;

			// Array-Länge bestimmen
			int length = array.Length;

			// Zweitarray (Zielarray) erstellen
			byte[] array2 = new byte[length];

			// Bei zu großer Array-Länge die zu schreibenden Daten rekursiv aufteilen
			if(length >= 256)
			{
				// Array links und rechts halbieren und Funktion erneut aufrufen (rekursiv) Längen der beiden Seiten (Mittelpunkt suchen)
				int left, right;

				// Mittelpunkt suchen, nach ungeraden und geraden Längen unterscheiden
				if(length % 2 == 0) // Gerade
				{
					// Beide Seiten sind gleich lang
					left = length / 2;
					right = length / 2;
				}
				else
				{
					// Links ist kürzer als rechts
					left = (length - 1) / 2;
					right = (length + 1) / 2;
				}

				// Die beiden Arrays initialisieren
				byte[] aLeft = new byte[left];
				byte[] aRight = new byte[right];

				// Die Werte verschieben
				for(int i = 0; i < left; i++)
				{
					aLeft[i] = array[i];
				}
				for(int i = 0; i < right; i++)
				{
					aRight[i] = array[left + i];
				}

				// Rekursiver Neu-Aufruf mit den beiden neuen Arrays
				cmdPlayerColor(ref fid, aLeft);
				cmdPlayerColor(ref fid, aRight);

				// Ende
				return;
			}

			// Das nächste Byte definieren (unnötige Variable, eher der Übersichtlichkeit halber)
			byte nextByte = (byte)length;

			// Ergebnisarray erstellen
			for(int i = 0; i < length; i++)
			{
				array2[i] = (byte)(array[i] - 16);
			}

			// Kommando erstellen
			fid.BinaryCommandTable.Add(new BinaryCommand(command, nextByte, array2));
		}
示例#9
0
		private void cmdColor(ref FrameInformationData fid, byte[] array)
		{
			// Array-Länge bestimmen
			int length = array.Length;

			// Bei Längen >= 64 das Array aufspalten
			if(length >= 64)
			{
				// Array links und rechts halbieren und Funktion erneut aufrufen (rekursiv) Längen der beiden Seiten (Mittelpunkt suchen)
				int left, right;

				// Mittelpunkt suchen, nach ungeraden und geraden Längen unterscheiden
				if(length % 2 == 0) // Gerade
				{
					// Beide Seiten sind gleich lang
					left = length / 2;
					right = length / 2;
				}
				else
				{
					// Links ist kürzer als rechts
					left = (length - 1) / 2;
					right = (length + 1) / 2;
				}

				// Die beiden Arrays initialisieren
				byte[] aLeft = new byte[left];
				byte[] aRight = new byte[right];

				// Die Werte verschieben
				for(int i = 0; i < left; i++)
				{
					aLeft[i] = array[i];
				}
				for(int i = 0; i < right; i++)
				{
					aRight[i] = array[left + i];
				}

				// Rekursiver Neu-Aufruf mit den beiden neuen Arrays
				cmdColor(ref fid, aLeft);
				cmdColor(ref fid, aRight);

				// Ende
				return;
			}

			// Akzeptable Länge, Kommando-Byte erstellen
			byte command = (byte)(length << 2);

			// Kommando der Auflistung hinzufügen
			fid.BinaryCommandTable.Add(new BinaryCommand(command, array));
		}
示例#10
0
		private void cmdTransp(ref FrameInformationData fid, int length)
		{
			// Bei Längen >= 64 das Array aufspalten
			if(length >= 64)
			{
				// Array links und rechts halbieren und Funktion erneut aufrufen (rekursiv) Längen der beiden Seiten (Mittelpunkt suchen)
				int left, right;

				// Mittelpunkt suchen, nach ungeraden und geraden Längen unterscheiden
				if(length % 2 == 0) // Gerade
				{
					// Beide Seiten sind gleich lang
					left = length / 2;
					right = length / 2;
				}
				else
				{
					// Links ist kürzer als rechts
					left = (length - 1) / 2;
					right = (length + 1) / 2;
				}

				// Neuaufruf
				cmdTransp(ref fid, left);
				cmdTransp(ref fid, right);

				// Fertig
				return;
			}

			// Das Kommandobyte
			byte command = (byte)(length << 2);

			// Wert des Kommandobytes um 1 erhöhen, da sonst Zweideutigkeit mit den Farbkommandos entsteht (ebenfalls 0, 4, 8, 12...)
			int commandNibbleLeft = (int)(command & 0x0C);
			if(commandNibbleLeft == 0 || commandNibbleLeft == 4 || commandNibbleLeft == 8 || commandNibbleLeft == 12)
			{
				command = (byte)(((int)command & 0xFF) + 1); // "& 0xFF", um Überläufe zu verhindern
			}

			// Kommando anfügen
			fid.BinaryCommandTable.Add(new BinaryCommand(command));
		}
示例#11
0
		/// <summary>
		/// Erstellt für die angegebenen Framedaten die binäre Kommando-Tabelle
		/// </summary>
		/// <param name="fid">Die Framedaten.</param>
		/// <param name="width">Die Breite des Frames.</param>
		/// <param name="height">Die Höhe des Frames.</param>
		/// <param name="settings">Die Einstellungen des Frames.</param>
		public void CreateBinaryCommandTable(FrameInformationData fid, int width, int height, Settings settings)
		{
			// Zeilenweise vorgehen
			for(int y = 0; y < height; y++)
			{
				// Der vorherige Pixel
				int prev = -5; // -5 ist ein Wert, den kein Pixel annehmen kann (nur -4 bis 255)

				// Bereich festlegen, in dem sich überhaupt etwas anderes als Transparenz befindet (vom Bildrand ausgehend)
				int start = fid.BinaryRowEdge[y]._left;
				int end = width - fid.BinaryRowEdge[y]._right - 1;

				// Aktuelle Position (Beginn dort, wo sich keine Transparenz mehr befindet)
				int pos = start;

				// Anzahl der Blöcke vom gleichen Typ
				int typeCount = 0;

				// Der aktuelle Typ
				string type = "null";

				// Positionsvariablen für Farbblöcke
				int colorStart = -1;
				int colorLength = -1;

				// Alle Pixel bis zum Bereichsende durchgehen
				while(pos <= end)
				{
					// Der aktuelle Pixel
					int currentPixel = fid.CommandTable[y, pos];

					// Liegt keine Farbe/Spielerfarbe mehr vor und beginnt ein Masken-Block (negativer Wert) bzw. beginnt ein anderer Masken-Block als der aktuell laufende?
					if(currentPixel != prev && currentPixel < 0)
					{
						// Wenn aktuell eine Maske läuft, diese in die Kommandotabelle übernehmen
						if(type != "null" && type != "color")
						{
							if(type == "transp")
								cmdTransp(ref fid, typeCount);
							else if(type == "outline1")
								cmdOutline1(ref fid, typeCount);
							else if(type == "outline2")
								cmdOutline2(ref fid, typeCount);
							else if(type == "shadow")
								cmdShadow(ref fid, typeCount);
						}
						else if(type == "color")
						{
							// Farben in Byte-Array schreiben
							byte[] colors = new byte[colorLength];
							for(int i = 0; i < colorLength; i++)
							{
								colors[i] = (byte)fid.CommandTable[y, colorStart + i];
							}

							// Farben in Kommandotabelle übernehmen
							cmdColorBlock(ref fid, colors, (settings & Settings.UsePlayerColor) == Settings.UsePlayerColor);

							// Der Farbblock ist zuende
							colorStart = -1;
							colorLength = -1;
						}

						// Neuen Typen erstellen
						typeCount = 1;
						if(currentPixel == -1)
							type = "transp";
						else if(currentPixel == -2)
							type = "outline1";
						else if(currentPixel == -3)
							type = "outline2";
						else if(currentPixel == -4)
							type = "shadow";

						// Aktuellen Pixelwert speichern, um ihn beim nächsten Durchlauf wieder verwenden zu können
						prev = currentPixel;
					}
					else if(currentPixel != prev && prev < 0) // Wechsel von Maske zu Farbe
					{
						// Den vorherigen Block schreiben
						if(type == "transp")
							cmdTransp(ref fid, typeCount);
						else if(type == "outline1")
							cmdOutline1(ref fid, typeCount);
						else if(type == "outline2")
							cmdOutline2(ref fid, typeCount);
						else if(type == "shadow")
							cmdShadow(ref fid, typeCount);

						// Neuen Typen erstellen
						typeCount = 1;
						type = "color";

						// Farbblockeigenschaften festlegen
						colorStart = pos;
						colorLength = 1;

						// Aktuellen Pixelwert speichern, um ihn beim nächsten Durchlauf wieder verwenden zu können
						prev = currentPixel;
					}
					else if(type == "color") // Farbblock geht weiter
					{
						// Farbblock verlängern (egal, welche Farbe)
						colorLength++;
						typeCount = 1;

						// Aktuellen Pixel speichern
						prev = currentPixel;
					}
					else // Maske geht weiter
					{
						// Anzahl erhöhen, der letzte Pixel ist natürlich der gleiche wie der aktuelle
						typeCount++;
					}

					// Nächster Pixel
					pos++;
				}

				// Letzten offenen Block noch beenden
				if(type == "color") // Farbblock
				{
					// Farben in Byte-Array schreiben
					byte[] colors = new byte[colorLength];
					for(int i = 0; i < colorLength; i++)
					{
						colors[i] = (byte)fid.CommandTable[y, colorStart + i];
					}

					// Farben in Kommandotabelle übernehmen
					cmdColorBlock(ref fid, colors, (settings & Settings.UsePlayerColor) == Settings.UsePlayerColor);

					// Der Farbblock ist zuende
					colorStart = -1;
					colorLength = -1;
				}
				else // Maske
				{
					// Den Maskenblock schreiben
					if(type == "transp")
						cmdTransp(ref fid, typeCount);
					else if(type == "outline1")
						cmdOutline1(ref fid, typeCount);
					else if(type == "outline2")
						cmdOutline2(ref fid, typeCount);
					else if(type == "shadow")
						cmdShadow(ref fid, typeCount);
				}

				// Zeilenende schreiben
				cmdEOL(ref fid);
			}
		}
示例#12
0
		/// <summary>
		/// Ersetzt einen vorhandenen Frame oder fügt einen neuen am Ende hinzu.
		/// </summary>
		/// <param name="frameID">Die ID des Frames (bei Ersetzung) oder -1 für einen neuen Frame.</param>
		/// <param name="frameBitmap">Die Bilddaten, die in Kommando-Daten umgewandelt werden sollen (mit 50500er-Palette versehen).</param>
		/// <param name="pal">Die zu verwendende Farbpalette.</param>
		/// <param name="ankerX">Die X-Koordinate des Mittelpunkts der Grafik.</param>
		/// <param name="ankerY">Die Y-Koordinate des Mittelpunkts der Grafik.</param>
		/// <param name="settings">Die Einstellungen als Wert der Settings-Enumeration.</param>
		public void addReplaceFrame(int frameID, BitmapLoader frameBitmap, ColorTable pal, int ankerX, int ankerY, Settings settings)
		{
			#region Grundlegenes und Initialisierungen

			// Größen ermitteln
			int height = frameBitmap.Height;
			int width = frameBitmap.Width;

			// Framedaten
			FrameInformationData aktFID;
			FrameInformationHeader aktFIH;

			// Neuer Frame?
			if(frameID < 0 || frameID >= _frameInformationData.Count)
			{
				// Neue Framedaten erstellen
				aktFID = new FrameInformationData();
				_frameInformationData.Add(aktFID);
				aktFIH = new FrameInformationHeader();
				_frameInformationHeaders.Add(aktFIH);

				// Neue Frame-ID ermitteln
				frameID = _frameInformationData.Count - 1;
			}
			else
			{
				// Frame laden
				aktFID = _frameInformationData[frameID];
				aktFIH = _frameInformationHeaders[frameID];
			}

			// Anker speichern
			aktFIH.AnchorX = ankerX;
			aktFIH.AnchorY = ankerY;

			// Speichern der Abmessungen
			aktFIH.Width = (uint)width;
			aktFIH.Height = (uint)height;

			// RowEdge initialisieren
			aktFID.BinaryRowEdge = new BinaryRowedge[height];
			for(int i = 0; i < height; i++)
			{
				aktFID.BinaryRowEdge[i] = new BinaryRowedge();
			}

			// Kommando-Offset-Array initalisieren
			aktFID.CommandTableOffsets = new uint[height];

			// Kommando-Array initialisieren
			aktFID.BinaryCommandTable = new List<BinaryCommand>();

			#endregion Grundlegenes und Initialisierungen

			// Bild in umgesetzte Kommandodaten umwandeln

			#region Umwandlung in umgesetzte Kommandodaten (Masken + Farbenindizes)

			int[,] xCommandTable; // [Y, X] => Hilfsvariable für effizienteren Zugriff, enthält alle Palettenverweise des Bilds bzw. die negativen Masken-Pixel
			aktFID.CommandTable = new int[height, width];
			{
				// Bildindizes (Daten) in die umgesetzte Kommandotabelle schreiben
				for(int i = 0; i < height; i++)
				{
					for(int j = 0; j < width; j++)
					{
						aktFID.CommandTable[i, j] = frameBitmap[j, i];
					}
				}

				// Aus Effizienzgründen die umgewandelte Kommandotabelle in ein nahezu Objekt-freies int-Array kopieren (Direktzugriff ohne Umwege über unnötige OOP)
				xCommandTable = (int[,])aktFID.CommandTable.Clone();

				// Berechnen der Masken

				#region Maskenberechnung

				{
					// Unsichtbar wird immer 255er-Weiß
					int _transMaskIndex = 255;

					// Transparenz
					if((settings & Settings.UseTransparency) == Settings.UseTransparency)
					{
						// Jedem transparenten 255er-Pixel den Index -1 verpassen
						for(int y = 0; y < height; y++)
						{
							for(int x = 0; x < width; x++)
							{
								if(xCommandTable[y, x] == _transMaskIndex)
									xCommandTable[y, x] = -1;
							}
						}
					}

					// Sämtliche Transparenz hat nun den Wert -1
					_transMaskIndex = -1;

					// Umriss 1 (Outline 1): Der Umriss des Objekts in der Grafik (wenn das Objekt hinter einem anderen steht, werden diese Umrisse in der Spielerfarbe dargestellt) Es müssen alle vier Richtungen durchgerechnet werden
					if((settings & Settings.UseOutline1) == Settings.UseOutline1)
					{
						// Waagerecht
						for(int y = 0; y < height; y++)
						{
							// Nach rechts
							for(int x = 0; x < width - 1; x++)
							{
								// Befindet sich beim nächsten Pixel keine Transparenz und auch kein Umriss 1? => Umriss
								if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y, x + 1] != _transMaskIndex && xCommandTable[y, x + 1] != -2)
								{
									xCommandTable[y, x] = -2;
								}
							}

							// Nach links
							for(int x = width - 1; x > 0; x--)
							{
								// Befindet sich beim nächsten Pixel keine Transparenz und auch kein Umriss 1? => Umriss
								if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y, x - 1] != _transMaskIndex && xCommandTable[y, x - 1] != -2)
								{
									xCommandTable[y, x] = -2;
								}
							}
						}

						// Senkrecht
						for(int x = 0; x < width; x++)
						{
							// Nach unten
							for(int y = 0; y < height - 1; y++)
							{
								// Befindet sich beim nächsten Pixel keine Transparenz und auch kein Umriss 1? => Umriss
								if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y + 1, x] != _transMaskIndex && xCommandTable[y + 1, x] != -2)
								{
									xCommandTable[y, x] = -2;
								}
							}

							// Nach oben
							for(int y = height - 1; y > 0; y--)
							{
								// Befindet sich beim nächsten Pixel keine Transparenz und auch kein Umriss 1? => Umriss
								if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y - 1, x] != _transMaskIndex && xCommandTable[y - 1, x] != -2)
								{
									xCommandTable[y, x] = -2;
								}
							}
						}
					}

					// Umriss 2 (Outline 2): Zweiter Umriss, umschließt Umriss 1
					if((settings & Settings.UseOutline2) == Settings.UseOutline2)
					{
						// Zuerst Outline 1 für das Outline 2-Array neu berechnen (falls dies noch nicht passiert ist)
						if((settings & Settings.UseOutline1) != Settings.UseOutline1)
						{
							// Waagerecht
							for(int y = 0; y < height; y++)
							{
								// Nach rechts
								for(int x = 0; x < width - 1; x++)
								{
									// Befindet sich beim nächsten Pixel keine Transparenz und auch kein Umriss 1? => Umriss
									if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y, x + 1] != _transMaskIndex && xCommandTable[y, x + 1] != -2)
									{
										xCommandTable[y, x] = -2;
									}
								}

								// Nach links
								for(int x = width - 1; x > 0; x--)
								{
									// Befindet sich beim nächsten Pixel keine Transparenz und auch kein Umriss 1? => Umriss
									if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y, x - 1] != _transMaskIndex && xCommandTable[y, x - 1] != -2)
									{
										xCommandTable[y, x] = -2;
									}
								}
							}

							// Senkrecht
							for(int x = 0; x < width; x++)
							{
								// Nach unten
								for(int y = 0; y < height - 1; y++)
								{
									// Befindet sich beim nächsten Pixel keine Transparenz und auch kein Umriss 1? => Umriss
									if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y + 1, x] != _transMaskIndex && xCommandTable[y + 1, x] != -2)
									{
										xCommandTable[y, x] = -2;
									}
								}

								// Nach oben
								for(int y = height - 1; y > 0; y--)
								{
									// Befindet sich beim nächsten Pixel keine Transparenz und auch kein Umriss 1? => Umriss
									if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y - 1, x] != _transMaskIndex && xCommandTable[y - 1, x] != -2)
									{
										xCommandTable[y, x] = -2;
									}
								}
							}
						}

						// Outline 2 auf Outline 1 basierend erstellen (Umriss 1 wird wie eine gewöhnliche Farbe behandelt)
						{
							// Waagerecht
							for(int y = 0; y < height; y++)
							{
								// Nach rechts
								for(int x = 0; x < width - 1; x++)
								{
									// Befindet sich beim nächsten Pixel keine Transparenz? => Umriss
									if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y, x + 1] != _transMaskIndex && (x + 1 != width - 1))
									{
										xCommandTable[y, x] = -3;
									}
								}

								// Nach links
								for(int x = width - 1; x > 0; x--)
								{
									// Befindet sich beim nächsten Pixel keine Transparenz? => Umriss
									if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y, x - 1] != _transMaskIndex && (x + 1 != width - 1))
									{
										xCommandTable[y, x] = -3;
									}
								}
							}

							// Senkrecht
							for(int x = 0; x < width; x++)
							{
								// Nach unten
								for(int y = 0; y < height - 1; y++)
								{
									// Befindet sich beim nächsten Pixel keine Transparenz? => Umriss
									if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y + 1, x] != _transMaskIndex)
									{
										xCommandTable[y, x] = -3;
									}
								}

								// Nach oben
								for(int y = height - 1; y > 0; y--)
								{
									// Befindet sich beim nächsten Pixel keine Transparenz? => Umriss
									if(xCommandTable[y, x] == _transMaskIndex && xCommandTable[y - 1, x] != _transMaskIndex)
									{
										xCommandTable[y, x] = -3;
									}
								}
							}
						}
					}

					// Schatten (Farbindex 131)
					if((settings & Settings.UseShadow) == Settings.UseShadow)
					{
						// Jeden Schattenpixel mit -4 markieren
						for(int y = 0; y < height; y++)
						{
							for(int x = 0; x < width; x++)
							{
								if(xCommandTable[y, x] == 131)
									xCommandTable[y, x] = -4;
							}
						}
					}
				} // Ende Maskenberechnung

				#endregion Maskenberechnung

				// Kommandotabelle zwischenspeichern
				aktFID.CommandTable = (int[,])xCommandTable.Clone();
			} // Ende Umwandlung in umgesetzte Kommandodaten

			#endregion Umwandlung in umgesetzte Kommandodaten (Masken + Farbenindizes)

			// Generieren der RowEdge-Daten (Außenränder, Bestimmung waagerecht)

			#region Generierung der RowEdge-Daten

			for(int y = 0; y < height; y++)
			{
				// Von links nach rechts
				int left = 0;
				for(int x = 0; x < width; x++)
				{
					if(xCommandTable[y, x] != -1)
						break;
					else
						left++;
				}

				// Von rechts nach links
				int right = 0;
				for(int x = width - 1; x >= 0; x--)
				{
					if(xCommandTable[y, x] != -1)
						break;
					else
						right++;
				}

				// Liegt eine leere Zeile vor?
				if(left == width)
				{
					// Leere Zeile
					right = 0;
				}

				// Werte speichern
				aktFID.BinaryRowEdge[y] = new BinaryRowedge(left, right);
			}

			#endregion Generierung der RowEdge-Daten

			// Ziel-Kommando-Tabelle erstellen
			CreateBinaryCommandTable(aktFID, width, height, settings);

			// Frame-Daten-Variablen speichern
			_frameInformationHeaders[frameID] = aktFIH;
			_frameInformationData[frameID] = aktFID;

			// Sicherheitshalber Frame-Anzahl im Header aktualisieren
			_headers.FrameCount = (uint)_frameInformationHeaders.Count;

			// Fertig: RowEdge-Daten und Kommandotabelle vollständig erstellt.
		}