Short: Objective-C Frameworks in MonoTouch verwenden

Die letzten Tage habe ich mich, aufgrund des aktuellen Projektes in der Firma, intensiv mit dem Wrapping von Objective-C Bibliotheken in MonoTouch beschäftigt.
Dank der Unmengen an Dokumentation *hust* hat das einiges an Frust und Zeit gekostet, weshalb ich nun ein paar Infos teilen möchte, um es anderen Entwicklern hoffentlich etwas zu erleichtern.

Konkret habe ich an der Implementierung von AdMob und OpenFeint gearbeitet. AdMob war hierbei kein großes Problem, da man direkt von der Google-Seite eine “.a”-Library herunterladen kann.
Bei den Extra-Argumenten für den MonoTouch Linker muss man folgende Argumente hinzufügen:
“-L${ProjectDir} -GoogleAdMobAds -force_load ${ProjectDir}/libGoogleAdMobAds.a”
und schon kann man munter an seinen Wrapper-Klassen programmieren. Alles kein Problem.

Die Probleme fangen an, wenn man sich von OpenFeint das SDK für iOS herunterlädt und sich fragt, wo die “.a”-Library ist ^^.
Was man bekommt, sind lediglich diverse Resource-Bundles und einen Ordner namens “OpenFeint.framework”. In diesem framework-Ordner befindet sich eine Binär-Datei und die Header-Dateien des Frameworks.
Nach einer ergebnislosen Suche im Internet und einer E-Mail zu Xamarin, stellte sich heraus das man die Binär-Datei aus dem “OpenFeint.framework”-Ordner herauskopieren muss und die Endung “.a” selbstständig hinzufügen muss. Dann kann man sie genauso wie bei AdMob einfach zum Linking hinzufügen und schon funktioniert es!
Interessant ist, dass anscheinend noch keiner darüber etwas im Internet geschrieben hat, außer dies ist ein Problem, dass lediglich OpenFeint keine “.a”-Datei direkt mitliefert.

Nachdem man nun weiß, wie man das Framework hineinlinken kann, ist es dank den Headern von OpenFeint recht leicht, die Wrapper-Klassen zu programmieren, sollte man sich etwas mit Objective-C auskennen, versteht sich ;) .

Direkt vom MonoTouch-Team gibts es übrigens ein wunderbares Repository auf GitHub, welches bereits für einige Libraries die Bindings zur Verfügung stellt.
https://github.com/mono/monotouch-bindings

Tutorial: Android Geräte USB-Treiber installieren

Der Titel mag einigen vielleicht merkwürdig vorkommen, “Das macht Windows7 doch schon alles automatisch!”.
Eigentlich sind Geräte schon lange kein Problem mehr, an den PC angeschlossen und in Null-Komma-Nix läuft es. Doch seitdem ich auf der Arbeit viel mit den unterschiedlichsten Android Geräten arbeite, musste ich zusehen wie dieser Grundsatz sich aufzulösen schien. Es wurde zwar oft soweit ein USB-Treiber installiert das ich auf die SD-Card zugreifen konnte, doch Debugging oder das Benutzen des DDMS-Tools war in den seltensten Fällen möglich.

Als Treiber-Pfad habe ich dann immer den Ordner usb-driver im Android-SDK verwendet, doch auch dies half nicht, bis ich auf eine Hilfe im Internet stieß, die die Lösung wusste.
Man muss oftmals nur 2-4 Zeilen pro Gerät in einer Datei im SDK-Treiber hinzufügen und schon geht alles reibungslos. Es konnte doch so einfach sein ^^

Damit vielleicht dem ein oder anderen dieser beschwerliche Weg erspart bleibt möchte ich die Lösung nun hier mit euch teilen. Damit ich regelmäßig die nötigen Zeilen für weitere Geräte hinzufügen kann ohne einen schon längst verschwundenen Post editieren zu müssen, habe ich eine Tutorial-Seite erstellt: Android USB Driver.

Wenn ihr noch weitere Geräte in der Liste vermisst oder die Zeilen für weitere Geräte habt, freu ich mich über einen Kommentar :)

AC.AL Version 1.3 und Linux

Leider habe ich länger nichts mehr geschrieben, was allerdings nicht heißt, das ich untätig gewesen bin ;)

Ich bin stolz die neue Version von AC.AL präsentieren zu können (v. 1.3), welche nun auch auf Linux funktioniert!

Für den nächsten Release ist Music-Streaming und evtl. auch schon MacOS-Support geplant. Mal schauen, was die Zeit so mit sich bringt.

Den Release könnt ihr wie immer auf der Codeplex-Seite herunterladen:
http://acal.codeplex.com/

P.S.: Wer einen guten Artikel zu native invokes unter Windows und Linux mit .NET und Mono sucht, findet hier einen ausgezeichneten Artikel:
http://rogue-modron.blogspot.com/2011/11/invoking-native.html

Version 1.0 von AC.AL veröffentlicht

Die letzten Tage war ich dabei, meinen OpenAL Wrapper für .NET mal wieder etwas aufzuarbeiten.

Da er recht übersichtlich und einfach zu benutzen ist, dachte ich mir das vielleicht ein paar Programmierer dort draußen, die in das Thema neu einsteigen, diesen als Grundlage gebrauchen könnten.

Neben der Wrapper-Funktion unterstützt die Bibliothek auch RIFF Wave und Ogg Vorbis Dateien.

Nun habe ich mich entschlossen ihn als OpenSource bei Codeplex zu veröffentlichen! Lizenz ist die MIT-Lizenz, was soviel bedeutet wie das ihr alles damit machen könnt, solange der Copyright- und der Lizenz-Hinweis mit dem Projekt mitgeliefert werden.

Über Credits und Kritik jeglicher Art bin ich natürlich immer dankbar und hoffe das es bei einigen Verwendung finden kann. :)

Aber genug des Geschwafels ;) , hier ist der Link zur Codeplex-Seite:
http://acal.codeplex.com/

Vlc für Videos in Spielen

Die letzten Tage hatte ich mal wieder einiges in der Firma zu knobeln. Für Videos in Spielen benutzen wir auf Windows Vlc, doch das Problem war, das die .NET Interop Bibliothek seit 2+ Jahren nicht mehr aktualisiert wurde und schon gar nicht mit der neuesten Vlc Version kompatibel ist. Mal wird das Video zu klein abgespielt, mal ist der Bildschirm komplett schwarz und manchmal öffnet sich ein extra Fenster, in welchem das Video abgespielt wird. Somit war es völlig unbrauchbar. Allerdings hatten wir bisher noch keine gute Alternative gefunden.

Doch dann hat sich ein netter kleiner Blogeintrag, von 2009 doch auch aktualisiert, gefunden. Dieser hat sich zum Ziel genommen gehabt, einen Kontrapunkt zu den vielen Outdated oder total überdimensionierten Bibliotheken zu setzten, indem er einfach nur einen Startpunkt zum eigenen kleinen Interop liefert.

Gesagt getan war in kurzer Zeit ein kleiner aber feiner Wrapper gebaut und alle Probleme haben sich in Nichts aufgelöst.

Fazit: Auch wenn man oft davor zurückschreckt, es lohnt sich oft auch mal das Rad neu zu erfinden um die beste Lösung zu erhalten. Gerade da Vlc nunmal nicht mit dem Gedanken der Spieleprogrammierung geschaffen wurde, ist es sinnvoll sich die Features herauszupicken, die man braucht.

Ein Großer Dank geht hier an Helyar.net für den wunderbaren Blogpost.

Part 1
Part 2

Ich hoffe es hilft, diese Lösung etwas mehr zu verbreiten und wenn ich Zeit finde, werde ich mal einen kleinen Interop speziell für Spiele in .NET erstellen und hier veröffentlichen.

Stay tuned.

Short: Boolean und die Größe – Fixed

In den letzten Tagen war ich auf der Suche nach einer Lösung für das Boolean Problem und habe nun eine recht gute gefunden.

Erst einmal möchte ich noch ein Beispiel für die standard Größe zeigen:

1
2
3
4
struct testStruct
{
  bool bool1, bool2, bool3, bool4, bool5, bool6, bool7, bool8, bool9, bool10;
}
struct testStruct
{
  bool bool1, bool2, bool3, bool4, bool5, bool6, bool7, bool8, bool9, bool10;
}

Wenn wir das Ganze mit Marshal.SizeOf ausgeben lassen, erhalten wir 40 bytes.
Nun hatte ich mich an die StructLayout-Möglichkeiten erinnert und ausprobiert, was es noch gibt. Für das Wrappen von Typen in Unmanaged Typen gibt es ein Attribut, names “MarshalAs”, mit der Eigenschaft “UnmanagedType”. Das ist auch schon eine mögliche Lösung. Wir fügen in einem Struct einfach das Attribut zu den boolean Variablen hinzu und geben als UnmanagedType “I1″ an.

1
2
3
4
5
struct testStruct
{
  [MarshalAs(UnmanagedType.I1)]
  bool bool1, bool2, bool3, bool4, bool5, bool6, bool7, bool8, bool9, bool10;
}
struct testStruct
{
  [MarshalAs(UnmanagedType.I1)]
  bool bool1, bool2, bool3, bool4, bool5, bool6, bool7, bool8, bool9, bool10;
}

Wenn wir das ganze nun wieder überprüfen, erhalten wir 10. Demnach hat nun jeder boolean ein einzelnes Byte, so wie wir uns das gewünscht hatten. :)

Nun hat man aber nicht immer ein Struct in welchem wir booleans benutzen und das Attribut reicht in Klassen nicht allein. Damit das Ganze auch für Klassen funktioniert, müssen wir der Klasse das “StructLayout” Attribut anfügen und als “LayoutKind” “Sequential” wählen.

So kann man nun seine Structs auch wieder Speichereffizienter nutzen ;)

Wissenswert: Boolean und die Größe

Jeder kennt es, jeder benutzt es und viele erschrecken sich, wenn sie merken wieviel Speicher eigentlich eine boolean Variable verwendet.
Ein Boolean kann 2 Status annehmen, True oder False, 1 oder 0. Da denkt man eigentlich das ein Bit völlig ausreichen würde oder wenn man in der kleinsten Einheit in vielen Programmiersprachen ausgeht, einem Byte.
Doch auf normalen Rechnern wird für einen boolean entweder 32 Bit oder 64 Bit verwendet, je nach Architektur. Das heißt ein boolean verwendet 4 oder 8 Byte! Begründet wird dies mit der besseren/schnelleren Verwendbarkeit der Variable im CPU.

Jetzt werden einige Sagen, wenn ich sizeof(bool) ausgeben lasse, kommt dort 1, also ein Byte. Das ist soweit richtig, da C# einen boolean wie ein byte handhabt, doch wenn man sich einmal die Größe einer boolean Variable mit Marshal.SizeOf anzeigen lässt, steht bei 32 Bit Systemen dort 4.

1
2
bool test = true;
Marshal.SizeOf(test);
bool test = true;
Marshal.SizeOf(test);

Der Unterschied hier ist, das sizeof(bool) die C# Variante der Größe wiedergibt und Marshal.SizeOf die Unmanaged Größe angibt. Demnach kann man davon ausgehen, das intern ein C# Boolean auch als 4/8 Byte gespeichert wird.

Auch Wikipedia sagt zu diesem Thema:

[...]Aus technischen Gründen wird jedoch in der Regel eine andere Repräsentation gewählt, meist abhängig von der Wortbreite des konkreten Systems.[...]
Quelle: Wikipedia

Daher muss man sich Gedanken machen, wenn es um die Größe von z.b. einem struct geht, ob man nicht lieber eine byte Variable verwendet. Dies ist zwar nicht so sicher da man mehr als nur 2 Status darin speichern kann, doch spart es recht viel Speicher. Und wenn man oft structs hin und her kopieren muss, oder neue Instanzen erstellen muss, kann das schonmal perfomance fressen.

Short: Button Status erweitern

Zurzeit überarbeite ich den Input-Teil meiner Engine und möchte nun eine Möglichkeit präsentieren, wie man den doch recht simplen ButtonState von XNA erweiter kann.

Erst einmal zur Erinnerung: Die ButtonState Enumeration für z.b. den Mouse LeftButton bietet nur zwei States an. Pressed und Released. Für den Anfang mag das vollkommen ausreichend sein, doch wenn man erweiterte UI Features wie das Ändern des Buttonbildes beim Klick einbaut möchte man oft mehr State-Informationen haben.

Daher habe ich nun folgende States zusammengefasst:

  • NotPressed: Der Button ist nicht gedrückt, er wurde noch nie gedrückt, oder der vorherige Status war Released.
  • JustPressed: Der Button wurde gerade gedrückt, der vorherige Status war NotPressed.
  • Pressed: Der Button ist weiterhin gedrückt, der vorherige Status war JustPressed.
  • Released: Der Button wurde losgelassen und der vorherige Status war JustPressed oder Pressed.

Das sind nun schon einige Möglichkeiten mehr, auf die man zurückgreifen kann. Man kann überprüfen ob der Button schnell geklickt wurde (JustPressed dann Released), oder mit JustPressed beginnt z.b. ein Dragging, bei Pressed wird das Dragging fortgesetzt und bei Released beendet. Da finden sich einige Anwendungsfälle.

Aber wie kann man mit hilfe der zwei States von XNA nun diese vier setzten? Das ist recht einfach. Dafür habe ich mir folgende Methode gebaut, welche für alle Buttons verwendbar ist:

1
2
3
4
5
6
7
8
9
10
11
12
13
private ExtendedButtonState HandleButton(bool pressed, bool previousPressed)
{
  if (pressed && previousPressed == false)
    return ExtendedButtonState.JustPressed;
 
  if (pressed && previousPressed)
    return ExtendedButtonState.Pressed;
 
  if (pressed == false && previousPressed)
    return ExtendedButtonState.Released;
 
  return ExtendedButtonState.NotPressed;
}
private ExtendedButtonState HandleButton(bool pressed, bool previousPressed)
{
  if (pressed && previousPressed == false)
    return ExtendedButtonState.JustPressed;

  if (pressed && previousPressed)
    return ExtendedButtonState.Pressed;

  if (pressed == false && previousPressed)
    return ExtendedButtonState.Released;

  return ExtendedButtonState.NotPressed;
}

Die Methode bekommt ganz einfach einen boolean, welcher angibt ob der aktuelle ButtonState Pressed ist und einen weiteren boolean, ob der letzte State Pressed war. Mehr brauchen wir gar nicht.

Dann überprüfen wir:

  • Ist der Button jetzt gedrückt und war vorher nicht gedrückt? Also JustPressed.
  • Ist der Button gedrückt und wurde vorher schon gedrückt? Also Pressed.
  • Ist der Button nicht mehr gedrückt und war vorher gedrückt? Dann Released.
  • Und wenn nichts davon zutrifft, dann haben wir den NotPressed Status.

Und schon hat man eine sehr viel detailierte Übersicht über den aktuellen Button-Status. Hier noch kurz der Aufruf der Methode:

1
2
3
4
5
6
7
8
LeftButton = HandleButton(state.LeftButton == ButtonState.Pressed,
  lastState.LeftButton == ButtonState.Pressed);
 
MiddleButton = HandleButton(state.MiddleButton == ButtonState.Pressed,
  lastState.MiddleButton == ButtonState.Pressed);
 
RightButton = HandleButton(state.RightButton == ButtonState.Pressed,
  lastState.RightButton == ButtonState.Pressed);
LeftButton = HandleButton(state.LeftButton == ButtonState.Pressed,
  lastState.LeftButton == ButtonState.Pressed);

MiddleButton = HandleButton(state.MiddleButton == ButtonState.Pressed,
  lastState.MiddleButton == ButtonState.Pressed);

RightButton = HandleButton(state.RightButton == ButtonState.Pressed,
  lastState.RightButton == ButtonState.Pressed);

Short: Videos für XNA konvertieren

Da wir in der Firma unseren kompletten Content automatisiert in die richtigen Formate, für die jeweiligen Platformen, konvertieren lassen, war ich auf der Suche nach einem passenden Tool für XNA Videos. Das Problem bei der Sache ist, dass XNA ganz spezielle Anforderungen für Video Content hat. Das Video muss als SinglePass WMV9 enkodiert sein, muss einen Audiokanal haben und darf keine variable Bitrate besitzen. Das sind schon einige Restriktionen.

Normalerweise ist das Konvertieren von Videos kein Problem, man öffnet einfach den Movie Maker oder ähnliche Programme und speichert das richtige Format. Da wir aber alles automatisiert machen, wurde die Suche schwieriger. Das Program musste entweder per Kommandozeile steuerbar sein oder man müsste eine Programmieranbindung haben. Und das ist schon das größte Problem. Klasse Programme wie ffmpeg haben WMV9 nicht integriert da Microsoft die Hand über das Format hält und es auch keine richtige Dokumentation darüber gibt.

Nach langer Suche hat sich dann aber doch eine Möglichkeit gefunden und das sogar direkt von Microsoft selbst. Das Program Expression Encoder liefert neben dem Program auch ein SDK für C# mit, womit man direkt im eigenen Program die Videos konvertieren kann und alle möglichen Einstellungen vornehmen kann. Und am besten ist, es kann WMV9.

Damit hat sich das Problem gelöst und für alle die ebenfalls davor stehen, hier einmal ein kleiner Codeschnipsel, wie man Videos für XNA enkodieren kann:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Job job = new Job();
MediaItem item = new MediaItem(SourceFilePath);
job.MediaItems.Add(item);
job.OutputDirectory = "C:\\";
job.CreateSubfolder = false;
 
item.OutputFormat.VideoProfile = new AdvancedVC1VideoProfile()
{
  Size = item.MainMediaFile.VideoStreams[0].VideoSize,
  Bitrate = new ConstantBitrate(1000),
};
 
item.OutputFormat.AudioProfile = new WmaAudioProfile()
{
  Channels = 2,
};
 
job.Encode();
Job job = new Job();
MediaItem item = new MediaItem(SourceFilePath);
job.MediaItems.Add(item);
job.OutputDirectory = "C:\\";
job.CreateSubfolder = false;

item.OutputFormat.VideoProfile = new AdvancedVC1VideoProfile()
{
  Size = item.MainMediaFile.VideoStreams[0].VideoSize,
  Bitrate = new ConstantBitrate(1000),
};

item.OutputFormat.AudioProfile = new WmaAudioProfile()
{
  Channels = 2,
};

job.Encode();

Und falls man noch als Zusatzinformation wissen möchte, wie lang das Video ist, oder aber auch andere Information, kann man das über das MediaItem machen:

1
float timeLength = (float)item.FileDuration.TotalSeconds;
float timeLength = (float)item.FileDuration.TotalSeconds;

Short: Die Notfalltextur

Manchmal, wenn man einfach nur mal eben einen Grafiktest machen will, oder auch generell falls eine Content Datei fehlt steht man immer vor der Frage: was macht man? Sucht man sich irgendwoher eine kleine Textur zum testen raus, oder lässt man das Spiel abstürzen wenn der Content fehlt?

Die Lösung lautet CheckerMap, oder aber die “Notfalltextur”.

Hierbei handelt es sich um eine zur Laufzeit generierte, 4×4 Pixel große Schachbrettmuster-Textur, welche fehlende Bilddaten zum testen ersetzten kann.

Meist benutzt man dazu einfaches Grau und Silber. Das Schachbrettmuster daher, damit man z.b. die UV-Koordinaten, oder Übergänge auch mit der Testtextur erkennen kann.

In diesem Beispiel wollen wir die CheckerMap mit Hilfe des XNA-Frameworks erstellen.

Da die Textur keinerlei Alpha oder besondere Farbenvielfalt benötigt, können wir zusätzlich die Texturgröße im Speicher ziemlich gering halten. Benutzen tun wir das Bildformat Bgr565, welches 5 bits für blau und rot verwendet und 6 bits für den grünen Kanal. Demnach benötigen wir pro Pixel nur 16 bits, wodurch wir perfekt den ushort Datentyp verwenden können. Für das “Silber” verwenden wir dann den ushort Wert “38034″ und für das “Grau” den Wert “12678″.

Aber nun zum Code:

1
Texture2D texture = new Texture2D(GraphicsDevice, 4, 4, false, SurfaceFormat.Bgr565);
Texture2D texture = new Texture2D(GraphicsDevice, 4, 4, false, SurfaceFormat.Bgr565);

Dieser Einzeiler erstellt uns eine neue Instanz von Texture2D welche 4×4 Pixel groß ist, keine Mipmaps generiert (was bei der CheckerMap unnötig wäre) und das Format Bgr565 für die Daten benutzt.

Aber noch haben wir eine leere Textur, deshalb füllen wir sie nun mit unserem Schachbrettmuster. Dafür speichern wir uns erst einmal unsere zwei Pixel-UShorts:

1
2
ushort silver = 38034;
ushort gray = 12678;
ushort silver = 38034;
ushort gray = 12678;

und füllen jetzt die Textur:

1
2
3
4
5
6
7
texture.SetData<ushort>(new ushort[]
{
  gray, silver, gray, silver,
  silver, gray, silver, gray,
  gray, silver, gray, silver,
  silver, gray, silver, gray,
});
texture.SetData<ushort>(new ushort[]
{
  gray, silver, gray, silver,
  silver, gray, silver, gray,
  gray, silver, gray, silver,
  silver, gray, silver, gray,
});

Und schon haben wir eine wunderschöne, naja zweckmäßige, Textur falls es mal schnell gehen soll. Wenn man eine eigene kleine Engine schreibt ist es hilfreich diese Hilfstextur direkt darin zu intergrieren, damit man sie immer ohne große Umschweife zur Verfügung hat.

Eine wichtige Sache abschließend wäre noch das Filtering der Textur! Da es nur 4×4 Pixel sind wird die Textur in fast allen Fällen skaliert. Dadurch wird die Textur bei Standardshadern schnell schwammig und verliert das Schachbrettmuster. Daher ist es wichtig immer für diese Textur den MinFilter und MagFilter auf Nearest zu stellen. Somit ist das Muster in jeder Größe garantiert. :)