Übersicht

TextSuite 2.0 ist eine Weiterentwicklung oder eher eine Reimplementierung der TextSuite von Steffen Xonna (aka Lossy eX).

TextSuite 2.0 ist eine Klassensammlung um Texte in einer Objekt-orientierter Weiße zu verwalten, zu manipulieren und zu zeichnen. Es werden mehrere Renderer, wie OpenGL oder OpenGLES, und einige Font Creator wie GDI oder FreeType unterstützt.

Die Idee hinter TextSuite ist, dass man einen Font Renderer entsprechend seiner Anwendung (z.B. OpenGL) instanziiert. Wenn man dann einen Text zeichnen will, zerlegt die TextSuite diesen Text in einzelne Glyphen und prüft ob diese bereits im Cache des Renderers bekannt sind. Wenn nicht werden diese mit Hilfe eines Font Creators nachgeladen. Man kann mehrere Font Creator in einer Anwendung nutzen (z.B. GDI und FreeType). Die von Font Renderer geladenen Glyphen werden in einer Image zwischengespeichert. Bevor die Image dann im Cache des Renderers abgelegt wird, kann man mehrere Post Prozessoren auf die Image anwenden. Beispiele für Post Prozessoren sind Border, Color Fill, Pattern Fill oder Shadow. Sobald alle Glyphen, die für den Text benötigt werden, geladen sind platziert TextSuite diese auf dem Bildschirm. Zeilenumbrüche und Einschübe werden dabei automatisch von der TextSuite berechnet.

TextSuite ist modular aufgebaut, so kann man jederzeit seine eigenen Font Creator, Font Rederer oder Post Prozessoren implementieren.

Links

Beispiele

Um den Einstieg in die Arbeit mit der TextSuite zu vereinfachen folgen nun zwei einfache Beispiele. Das erste Beispiel zeichnet einen Text der zuvor mit GDI geladen wurde. Das zweite Beispiel zeigt wie man mit Post Prozessoren arbeitet.

Einfaches GDI Beispiel

Als erstes muss man den TextSuite Context, den Font Renderer und den Font Creator erstellen. Im Context werden alle Daten die für die TextSuite benötigt werden abgelegt. Es sollte, wenn möglich, nur ein Context pro Anwendung erstellt werden. Außerdem ist sicherzustellen das ein gültiger OpenGL Context gebunden ist, bevor der Font Renderer erzeugt wird.

var
  tsContext: TtsContext;
  tsRenderer: TtsRendererOpenGL;
  tsFontCreator: TtsFontCreatorGDI;
tsContext  := TtsContext.Create;
tsRenderer := TtsRendererOpenGL.Create(tsContext, TtsFormat.tsFormatAlpha8);
tsCreator  := TtsFontCreatorGDI.Create(tsContext);

Das ist das Basis-Setup, das für jede Anwendung benötigt wird. Jetzt kann man damit beginnen Fonts zu laden. Wenn ein Font wiederholt genutzt werden soll, dann empfiehlt es sich diesen zwischen zu speichern und nicht bei jedem Aufruf neu zu erzeugen.

var tsFont: TtsFont;
tsFont := tsCreator.GetFontByFile('./my-font-file.ttf', 20, [], TtsAntiAliasing.tsAANormal);

Nachdem alle Objekte die für das Zeichnen benötigt werden angelegt wurden, kann man jetzt damit beginnen seinen Text zu zeichnen.

var
  block: TtsTextBlock; 
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
block := tsRenderer.BeginBlock(0, 0, 480, 320, [TtsBlockFlag.tsBlockFlagWordWrap])
try
  block.HorzAlign := TtsHorzAlignment.tsHorzAlignJustify;
  block.ChangeFont(tsFont);
  block.ChangeColor(tsColor4f(1.0, 1.0, 1.0, 1.0));
  block.TextOutW('Lorem ipsum dolor sit amet...');     
finally
  tsRenderer.EndBlock(block);
end;
glDisable(GL_BLEND);

Der Text Block wird dazu genutzt um die Text Informationen zu speichern. Die TextOut Methode speichert den übergebenen Text mit den aktuellen Einstellungen ab. Das bedeutet, dass man Text mit mehreren Farben in einem Text Block zeichnen kann. Farbe setzen, Text übergeben, Farbe ändern, weiteren Text übergeben. Mit EndBlock wird der Text, der im Text Block gespeichert ist mit den entsprechenden Format Informationen gezeichnet und anschließend wird der Text Block automatisch freigegeben.

Post Prozessor Beispiel

Bevor man mit dem eigentlichen Post Prozessor Beispiel starten kann, benötigt man, wie im letzten Beispiel, einen Context, einen Font Renderer und einen Font Creator.

var
  tsContext: TtsContext;
  tsRenderer: TtsRendererOpenGL;
  tsFontCreator: TtsFontCreatorGDI;
tsContext  := TtsContext.Create;
tsRenderer := TtsRendererOpenGL.Create(tsContext, TtsFormat.tsFormatAlpha8);
tsCreator  := TtsFontCreatorGDI.Create(tsContext);

Jetzt kann man die Post Prozessoren erstellen. Im Beispiel werden zwei Post Prozessor Listen erstellt. Die erste füllt alle Buchstaben die in der Menge [L, o, r, e, m] enthalten sind mit schwarzer Farbe und alle anderen mit roter Farbe. Der zweite Post Prozessor füllt alle Zeichen der Menge [L, o, r, e, m] mit einem gestreiften Muster, alle Buchstaben gleich ‚e‘ mit dunklem Blau und alle Buchstaben ungleich ‚e‘ bekommenen einen grünen Rand.

var
  pp: TtsPostProcessor;
  img: TtsImage;
  tsPostProcessor1: TtsPostProcessorList;
  tsPostProcessor2: TtsPostProcessorList;
const
  PATTER_DATA: array[0..15] of Byte = (
    $FF, $BF, $7F, $BF,
    $BF, $FF, $BF, $7F,
    $7F, $BF, $FF, $BF,
    $BF, $7F, $BF, $FF); 
 
{ Post Prozessor 1 }
tsPostProcessor1 := TtsPostProcessorList.Create(ftsContext, true);
 
// alle Zeichen der Menge [L, o, r, e, m] mit Schwarz füllen
pp := TtsPostProcessorFillColor.Create(ftsContext, tsColor4f(0, 0, 0, 1), TS_IMAGE_MODES_REPLACE_ALL, TS_COLOR_CHANNELS_RGB);
pp.AddChars(TtsCharRangeUsage.tsUsageExclude, 'Lorem');
tsPostProcessor1.Add(pp);  
 
// alle Zeichen die nicht in der Menge [L, o, r, e, m] sind mit Rot füllen
pp := TtsPostProcessorFillColor.Create(ftsContext, tsColor4f(1.0, 0.0, 0.0, 1.0), TS_IMAGE_MODES_MODULATE_ALL, TS_COLOR_CHANNELS_RGB);
pp.AddChars(TtsCharRangeUsage.tsUsageInclude, 'Lorem');
tsPostProcessor1.Add(pp);      
 
{ Post Prozessor 2 }
tsPostProcessor2 := TtsPostProcessorList.Create(ftsContext, true);
 
// alle Zeichen der Menge [L, o, r, e, m] mit gestreiftem Muster füllen
img := TtsImage.Create(ftsContext);
img.CreateEmpty(TtsFormat.tsFormatAlpha8, 4, 4);
Move(PATTER_DATA[0], img.Data^, 16);
pp := TtsPostProcessorFillPattern.Create(ftsContext, img, true, tsPosition(0, 0), TS_IMAGE_MODES_MODULATE_ALL, TS_COLOR_CHANNELS_RGBA);
pp.AddChars(TtsCharRangeUsage.tsUsageInclude, 'Lorem');
tsPostProcessor2.Add(pp);   
 
// alle Buchstaben gleich 'e' mit dunklem Blau füllen
pp := TtsPostProcessorFillColor.Create(ftsContext, tsColor4f(0, 0, 0.5, 1), TS_IMAGE_MODES_REPLACE_ALL, TS_COLOR_CHANNELS_RGB);
pp.AddChars(TtsCharRangeUsage.tsUsageExclude, 'e');
tsPostProcessor2.Add(pp); 
 
// allen Buchstaben ungleich 'e' einen grünen Rand geben
pp := TtsPostProcessorBorder.Create(ftsContext, 3.0, 0.5, tsColor4f(0.0, 0.5, 0.0, 1.0), true);
pp.AddChars(TtsCharRangeUsage.tsUsageInclude, 'e');
tsPostProcessor2.Add(pp);

Nachdem nun die Post Prozessoren erstellt sind, ist das einzige was noch fehlt, die Fonts zu laden und ihnen die Post Prozessoren zuzuweisen

var 
  tsFont1: TtsFont; 
  tsFont2: TtsFont; 
 
ftsFont1 := ftsCreator.GetFontByFile('./my-font-file.ttf', 40, [], TtsAntiAliasing.tsAANormal);
tsFont1.PostProcessor := tsPostProcessor1;
 
tsFont2 := ftsCreator.GetFontByFile('./my-font-file.ttf', 40, [], TtsAntiAliasing.tsAANormal);
tsFont2.PostProcessor := tsPostProcessor2;

Und jetzt wird gerendert!

var
  block: TtsTextBlock; 
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
block := tsRenderer.BeginBlock(0, 0, 480, 320, [TtsBlockFlag.tsBlockFlagWordWrap])
try
    block.HorzAlign := TtsHorzAlignment.tsHorzAlignJustify;
 
    block.ChangeFont(tsFont1);
    block.TextOutW('Lorem ipsum dolor sit amet...' + sLineBreak);
 
    block.ChangeFont(tsFont2);
    block.TextOutW('Lorem ipsum dolor sit amet...');   
finally
  tsRenderer.EndBlock(block);
end;
glDisable(GL_BLEND);

Leave a Reply

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert