2.5.6 Textures: PixmapsWhen loading textures, you don't have many possibilities to modify them before using them. Also, there's no method to save a texture or to scale it properly. Or to manually access its pixel data. In fact, a texture seems to be very static.Fortunately there are also Pixmaps. A pixmaps - or "pixel maps" - job is to provide access to an images pixel data before uploading it to the video card. As it isn't stored in your video cards memory, you can easily access and modify it however you want to. Let's start with the basics: ZweiDe.Pixmap pixTemp = ZweiDe.Pixmap.Load(file); ZweiDe.Texture texTemp = pixTemp.ToTexture(texFlags, stretch);The above code equals Texture.Load and in fact, this is also excactly what Texture.Load does. So, it is possible to convert from pixmap to texture (and also backwards using texTemp.ToPixmap()) but you shouldn't try to do this in realtime as it isn't really the fastest operation: Your video card has to generate a new texture and to recieve all the pixel data. You can say that a pixmap represents an image stored in your processors memory and a texture represents it when stored in your video memory. To directly access a pixmaps pixel data using its PixelData-property and re-set it using SetPixels or use it to generate a new pixmap using Pixmap.Create. If you want to change only some of the pixmaps pixels, you may index it like a two-dimensional array [x, y] to get or set this positions RGBA value. It is also possible to resize or rescale a pixmaps pixel data. While resizing it means only to change the pixmaps boundaries, rescaling is performed fitting the image data to its new dimensions using one of four scaling filters. Take a look at the following overview: |
|
| Original image |
|
ScaleFilter.Nearest
|
|
ScaleFilter.Linear
|
|
ScaleFilter.QuadLinear
|
|
ZweiDe.Pixmap.RescaleHq3x(); |
|
2.6.1 Text: Loading bitmap fontsDisplaying textures and shapes covers a lot of 2d graphic needs but without text, it's only half the rent. Text is just neccessary.To display text messages, you first need a font to specify how excactly each glyph looks like and in ZweiDe, there are two font types that can be loaded: Bitmap fonts and TrueType fonts. We'll start with bitmap fonts. To load a font, do the following: ZweiDe.Font fntTemp = ZweiDe.Font.Load( .. );You need to specify a target file to load the font data from. This file is a text file (non-case-sensitive) holding additional information that is used to configure the font. Here is an example: Arial8.fnt
<ZweiDe BitmapFont>
CharWidth = 8
CharHeight = 8
CharPerTex = 1
CharTexture = Arial8.png
CharLeftAlign = false
CharOrder = AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz .:,;-_!"?$%&/()=0123456789+*<>|#'~@°^²³{}[]\´`ÜüÖöÄä
CharYOffset = 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0.25, 0,0, 0,0, 0,0.125, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0.25, 0,0.25, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0.25, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
CharXSizeMult = 1.0,0.625, 0.75,0.625, 0.75,0.625, 0.75,0.675, 0.75,0.55, 0.75,0.375, 0.875,0.7, 0.75,0.7, 0.375,0.25, 0.625,0.375, 0.875,0.7, 0.8,0.25, 1.0,1.0, 0.75,0.6, 0.875,0.625, 0.75,0.75, 0.875,0.625, 0.75,0.45, 0.75,0.55, 0.75,0.325, 0.75,0.625, 1.0,0.675, 1.125,1.0, 1.0,0.75, 1.0,0.75, 1.0,0.75, 0.5, 0.25, 0.25, 0.25, 0.25, 0.25, 0.75, 0.25, 0.375, 0.875, 0.75, 1.0, 1.0, 0.375, 0.375, 0.375, 0.75, 0.75, 0.5, 0.75, 0.75, 0.875, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.5, 0.675, 0.675, 0.375, 0.75, 0.25, 0.75, 0.875, 0.5, 0.75, 0.5, 0.5, 0.5, 0.5, 0.375, 0.375, 0.5, 0.25, 0.25, 0.75,0.625, 0.75,0.625, 1.0,0.7
CharDistAdd = 0.0
ReferenceHeightAdd = 0.0
Arial8.png
Now we'll take a >closer look at each line: <ZweiDe BitmapFont>This line tells ZweiDe "I'm really a ZweiDe BitmapFont and not just any file accidently loaded as Font". It is absolutely important to include this line into any ZweiDe BitmapFont configuration file. CharWidth = 8 CharHeight = 8CharWidth and CharHeight describe the dimensions of a single text glyph. CharPerTex = 1CharPerTex holds the number of glyphs referring to a single glyph texture. This is useful whenever there is no lowercase in the font. CharTexture = Arial8.pngCharTexture is a string value holding the name of the image file the glyphs are loaded from. CharLeftAlign = falseCharLeftAlign specifies whether or not the glyph images are aligned at their boundaries left. If false, they are assumed to be centered in the x-axis.
CharOrder = AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz .:,;-_!"?$%&/()=0123456789+*<>|#'~@°^²³{}[]\´`ÜüÖöÄä
The CharOrder string describes in which order the characters supported by this font file are set in the image file. If you try to write a text
using any character that is NOT supported by the active font, ZweiDe will throw an error. A character is supported if it is listed in the CharOrder string
and is assigned to valid CharYOffset and CharXSizeMult values.
CharYOffset = 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0.25, 0,0, 0,0, 0,0.125, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0.25, 0,0.25, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0.25, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0Some characters like 'y' or 'g' need to be drawn with a slight y-movement in order to fit them to the texts baseline. You can do this using CharYOffset where you assign each glyphs y-shift (percentual relating to CharHeight) as a float value. CharXSizeMult = 1.0,0.625, 0.75,0.625, 0.75,0.625, 0.75,0.675, 0.75,0.55, 0.75,0.375, 0.875,0.7, 0.75,0.7, 0.375,0.25, 0.625,0.375, 0.875,0.7, 0.8,0.25, 1.0,1.0, 0.75,0.6, 0.875,0.625, 0.75,0.75, 0.875,0.625, 0.75,0.45, 0.75,0.55, 0.75,0.325, 0.75,0.625, 1.0,0.675, 1.125,1.0, 1.0,0.75, 1.0,0.75, 1.0,0.75, 0.5, 0.25, 0.25, 0.25, 0.25, 0.25, 0.75, 0.25, 0.375, 0.875, 0.75, 1.0, 1.0, 0.375, 0.375, 0.375, 0.75, 0.75, 0.5, 0.75, 0.75, 0.875, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.5, 0.675, 0.675, 0.375, 0.75, 0.25, 0.75, 0.875, 0.5, 0.75, 0.5, 0.5, 0.5, 0.5, 0.375, 0.375, 0.5, 0.25, 0.25, 0.75,0.625, 0.75,0.625, 1.0,0.7As - in most cases - not every glyph is as wide as CharWidth specified, it is possible to set each glyphs width as a float value percentually relating to CharWidth using CharXSizeMult. CharDistAdd = 0.0The value set by CharDistAdd is added to the x-distance between each glyph when being drawn inside a text message. ReferenceHeightAdd = 0.0ReferenceHeightAdd is being added the fonts "reference height". This is a height value relating to the vertical distance between two text lines baselines. The font described here is a fully operational bitmap font loadable as described above. |
|
2.6.2 Text: Loading TrueType fontsUsing bitmap fonts has several advantages (for example the possibility to create "design"-fonts with complex graphics) but they are very hard to set up: You have to create an image holding all the glyphs, then calculate their widths and y-shift values, etc. etc.Loading TrueType fonts is much easier though you also need a configuration file. Loading itsself remains the same compared to loading a bitmap font but the configuration files content has changed. An example: tahoma12.fnt <ZweiDe FreeTypeFont> CharSize = 11 CharDPI = 196 FreeTypeFile = tahoma.ttf FaceIndex = 0 AdditionalChars = ÄäÖöÜü߀@ SharpenLevel = 0.0 Monochrome = true CharDistAdd = 0.0 ReferenceHeightAdd = 0 SpaceWidthMult = 1.0 We'll skip the obvious and directly come to the lines that may be more of a question: CharDPI = 196CharDPI describes the resolution used when generating the glyph textures. You may leave this and just set it to 196. FaceIndex = 0When using a TrueType font file that includes more than one font face, use FaceIndex to specify which font face to load. AdditionalChars = ÄäÖöÜü߀@By default, all AscII characters are supported by a TrueType font. If additional characters are neccessary, register them in AdditionalChars. SharpenLevel = 0.0If SharpenLevel is not equal zero, each glyph image is being sharpened after generation. The higher the value, the sharper it becomes. Monochrome = trueMonochrome is a boolean value specifying whether or not the glyph images are generated as monochrome images. This makes SharpenLevel obsolete when true. SpaceWidthMult = 1.0SpaceWidthMult is an optional factor modifying the width of a space character. As you can see, loading TrueType fonts is more straight-forward and less work. See how to display fonts (no matter if TrueType or bitmap) in the next chapter. |
|
2.6.3 Text: Displaying textFinally, we've completed all that font loading and configuration. Now we're able to display text! To do this, all you need to do is to bind the font you like to use and then call the drawing command:ZweiDe.Font fntTemp = ZweiDe.Font.Load( .. ); ... ZweiDe.Font.Bind(fntTemp); ZweiDe.DrawText("I'm a text", x, y);DrawText splits the text string into its characters and draws them glyph by glyph. |
|
2.6.4 Text: TextHelper objectsDrawText is easy to use and a fast solution, but it isn't really the best method to display text; rendering each glyph as single textured rect is slow. Also, transformations only affect each glyph, so there is no possibility to rotate or scale the text as whole. Two disadvantages in between two sentences.. sounds bad. Fortunately there is an alternative (and much better!) method to render text: Using TextHelper objects.So, what is a so called "TextHelper"? It is an object that accepts a text from you and renders it to a texture which it displays when calling its Draw method. It keeps track of the text set up on it and re-renders the texture whenever it is neccessary but it won't do that every frame but only as fast as the user could see it (Though you, as programmer, are able to force it via method or disable the "render pause"). To shorten it: A TextHelper does all the stuff you wouldn't want to do in order to speed up text display. Some lines of code say more than thousand words: ZweiDe.Font fntTemp = ZweiDe.Font.Load( .. ); ZweiDe.Font.Bind( fntTemp ); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper("I'm a fast dynamic prerendering text!"); ... ZweiDe.DrawText("I'm a slow realtime text", x, y); textHlp.Draw( x2, y2 ); ... textHlp.SetText("Let's update the displayed text"); ...By default, the TextHelper object uses the font that is currently bound when first updating its text. This usually happens in the same line of code in which it is being created. Later, if there is no font bound at that moment. There are several possibilities to configure a TextHelper object using its properties and methods. However, any change is being processed when re-rendering or updating the text using SetText respectively UpdateText, but only if the minimum re-render delay time has passed. This delay defaults to being inactive but it is recommended to set it to a reasonable value. If you've activated / set the minimum delay, you'll have to call SetText or UpdateText every frame when expecting regular changes. You can also force a single immeadiate text update using the Reset method before SetText / UpdateText if it is neccessary to ignore this delay once. However, another possibility is to leave the MinPrerenderDelay-property at its default null value which keeps the re-render delay deactivated. Both is not recommended if it isn't absolutely neccessary as TextHelper objects gain half of their processing speed from not updating their text data every frame. The better method is to call SetText / UpdateText every frame; it doesn't cost any performance because updating is skipped if there's noting to update (e.g. the text is currently static) and the MinPrerenderDelay is still active (updating is scheduled and skipped as long as it hasn't passed since last update). Of course, if you once set up a text that won't ever be re-set and you don't intend to change any of the TextHelpers properties or values either, you don't need to care for ever updating the TextHelper. |
|
2.6.5 Text: Text formattingA great deal using TextHelper objects is not only the performance gain but also the possibility to format the displayed text. The following overview illustrates the most important formatting and configuration options: |
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.SetText("I'm an example text, yo!"); |
Unformatted text
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.MaxWidth = 75; textHlp.SetText("I'm an example text, yo!"); |
Automatic WordWrap
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.MaxWidth = 75; textHlp.MaxHeight = 1; textHlp.SetText("I'm an example text, yo!"); |
Maximum line number
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.ForceTexSize = new Point<int>(75, 0); textHlp.SetText("I'm an example text, yo!"); |
Forced texture size (x)
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.ForceTexSize = new Point<int>(75, 10); textHlp.SetText("I'm an example text, yo!"); |
Forced texture size (both)
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.TexRenderOffset = new Point<float>(-10.0f, 5.0f); textHlp.SetText("I'm an example text, yo!"); |
Render offset
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.SetText("I'm an example/n text,/n yo!"); |
Forced newline
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.SetText("I'm an /cFF0000FFexample/cFFFFFFFF text, yo!"); |
Coloring
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.SetText("I'm/t/tan/n/t/texample/ntext,/tyo!"); |
Tabbing
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.SetText("I'm an/d[+3.5] example /d[-3.5]text, yo!"); |
Dynamic char spacing
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.SetText("--------More width!--------/n/a0I'm an/n/a1example/n/a2 text, yo!"); |
Line alignment
|
ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.SetFontPool(new ZweiDe.Font[2]{ tahoma12, tahoma12B }); textHlp.SetText("I'm an /f[1]example/f[0] text, yo!"); |
Multiple fonts
|
ZweiDe.Font.Bind(tahoma32); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.AddToTexturePool( ZweiDe.Texture.Load("icon20.png") ); textHlp.SetText("I'm /p1[0]/p3[0]/p5[0]an/nexample"); |
In-line textures
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.AddToTexturePool( ZweiDe.Texture.Load("icon20.png") ); textHlp.SetText("I'm /p0[0]/p2[0]/p4[0]an/nexample"); |
In-line textures #2
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.SetText("I'm an /n<tag>example<//tag>/n text, yo!"); |
Slash character
|
ZweiDe.Font.Bind(tahoma12); ZweiDe.TextHelper textHlp = new ZweiDe.TextHelper(); textHlp.SetText("@I'm //an /example/n text, yo!"); |
Force non-format text
|
|
It is also possible to combine each formatting possibility with each other. Conclusion: TextHelper objects are very useful when used properly. |
|
|
|
|