Gemini and Lib Text Candy

| Comments

I have reached a milestone of sorts with Gemini. One of my goals has always been to be compatible enough with the Corona APIs to take advantage of some of the key third party Corona tools. One tool in particular that provides excellent capabilities is the Text Candy library. This library makes it really easy to create great looking text labels and text effects in Corona apps.

In the last few weeks I have made a lot of progress with Gemini and Text Candy. I was planning to write some of this up and show a demo earlier, but then X-Pressive had to go and drop a new version last week, grrrr!. Actually, version 1.0.12 provides one great new feature – it imports Glyph Designer font files directly now that Glyph designer exports to Text Candy Lua format. I have updated my code for this newest release.

Read on to see Text Candy in action on Gemini.

Glyph Designer is a simple yet powerful tool that allows you to export any font on your Mac as a texture file and a descriptor file. It lets you choose which characters you want to include and add special effects likes drop shadows. Below is an example image file (OpenGL texture) output from Glyph Designer:

And the following is the (abridged) Lua code generated for Text Candy:

(chilopod_gd.lua) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
local Font = {}

Font.info =
    {
    face              = "Chilopod-Regular",
    file              = "chilopod_gd.png",
    size              = 64,
    bold              = 0,
    italic            = 0,
    charset           = "",
    unicode           = 0,
    stretchH          = 100,
    smooth            = 1,
    aa                = 1,
    padding           = {0, 0, 0, 0},
    spacing           = 2,
    charsCount        = 95,
    kerningsCounts    = 316,
    }

Font.common =
    {
    lineHeight        = 67,
    base              = 55,
    scaleW            = 512,
    scaleH            = 512,
    pages             = 1,
    packed            = 0,
    }

Font.chars =
    {
    {id=123,x=2,y=2,width=21,height=61,xoffset=1,yoffset=39,xadvance=21,page=0,chnl=0,letter="{"},
    {id=125,x=25,y=2,width=20,height=61,xoffset=1,yoffset=39,xadvance=21,page=0,chnl=0,letter="}"},
    {id=91,x=47,y=2,width=17,height=61,xoffset=1,yoffset=39,xadvance=17,page=0,chnl=0,letter="["},
    {id=93,x=66,y=2,width=17,height=61,xoffset=1,yoffset=39,xadvance=17,page=0,chnl=0,letter="]"},

  -- abridged for brevity

  {first=45, second=106, amount=-4},
    {first=45, second=74, amount=-4},
    {first=95, second=33, amount=-5},
    {first=32, second=114, amount=-6},
    }

return Font

Because I have made a point of implementing the portions of the API that Text Cany requires first, it was surprisingly easy to get the basics working. Text Candy essentially works by creating sprites and display groups, which was some of the first functionality I implemented for Gemini. I only had to modify about a dozen or so lines in Text Candy to make it work with Gemini.
Most of these were related to the fact that Gemini uses a right handed coordinate system with the y-axis pointing up, ala OpenGL, whereas in Corona the y-axis points down (with y=0 representing the top of the screen). I don’t have all of the Text Candy functionality working yet, but just getting some of the basic stuff working is pretty exciting.

Creating a font in Gemini using Text Candy is trivial. First load the Text Candy library then create a font with the data files:

Using Text Candy
1
2
TextCandy = require("lib_text_candy")
TextCandy.AddCharsetFromGlyphDesigner( "FONT1", "chilopod_gd", 32)

These two lines create a font name FONT1. This font can be used to create multiple labels and varying sizes, each with its own special effect. Creating a label is similarly trivial:

A Simple Label
1
2
3
4
5
6
7
8
9
10
11
12
13
local circleLabel = TextCandy.CreateText({
    fontName   = "FONT1",
  x        = 480,
  y        = 350,
  text     = "This text is in a  circle",
  originX      = "CENTER",
  originY      = "CENTER",
  textFlow     = "CENTER",
  wrapWidth    = 350,
  lineSpacing  = -4,
  charBaseLine = "TOP",
  showOrigin   = false          
}) 

The CreateText method takes a Lua table that describes the text, including its position. Adding effects to labels is also easy. The following code takes the label from above and warps it into a circle:

A Circular Label
1
2
3
4
5
6
7
8
9
circleLabel:applyDeform({
  type        = TextCandy.DEFORM_CIRCLE,
  radius       = 90,
  radiusChange     = 0,
  angleStep    = 12,
  stepChange   = .175,
  autoStep     = false,
  ignoreSpaces = false
})

The labels created by Text Candy are Gemini display objects, so they can be manipulated like any other display object. The following code applies a transition to our circle label, causing it two go through two full rotations over a twenty second interval:

Spinning Label
1
transition.to(circleLabel, {time=20000, rotation=720})

While all this is no doubt fascinating, you are probably wanting to actaully see something move at this point. The video screen capture from the iOS simulator shown below shows our spinning label, a horizontal marquee label, plus a running horse sprite thrown in for good measure.

The code for this demo is given below. I will explain the rest of it in another post.

(text_candy_test.lua) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
gemini = require('gemini')
display = require('display')
sprite = require('sprite')
TextCandy = require("lib_text_candy")
horse = require('horse')

TextCandy.AddCharsetFromGlyphDesigner( "FONT1", "chilopod_gd", 32)
TextCandy.ScaleCharset("FONT1", .5)

layer2 = display.newLayer(1)
layer2:setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

-- create our sprite for the running horse
horseSpriteSheet = sprite.newSpriteSheetFromData("horses.png", horse.getSpriteSheetData())
horseSpriteSet = sprite.newSpriteSet(horseSpriteSheet, 1, 8)
horseSprite = sprite.newSprite(horseSpriteSet)
horseSprite.x = 500
horseSprite.y = 350
layer2:insert(horseSprite)
horseSprite:prepare()
horseSprite:play()


-- creatae a label that will follow a circle
local circleLabel = TextCandy.CreateText({
    fontName   = "FONT1",
  x        = 480,
  y        = 350,
  text     = "This text is in a  circle",
  originX      = "CENTER",
  originY      = "CENTER",
  textFlow     = "CENTER",
  wrapWidth    = 350,
  lineSpacing  = -4,
  charBaseLine = "TOP",
  showOrigin   = false          
}) 

circleLabel.xScale = 2.0
circleLabel.yScale = 2.0

-- warp the label into a circle
circleLabel:applyDeform({
  type        = TextCandy.DEFORM_CIRCLE,
  radius       = 90,
  radiusChange     = 0,
  angleStep    = 12,
  stepChange   = .175,
  autoStep     = false,
  ignoreSpaces = false
})

-- make the circular label spin two rotations in twenty seconds
transition.to(circleLabel, {time=20000, rotation=720})


local marqueeLabel = TextCandy.CreateText({
    fontName   = "FONT1",
  x        = 100,
    y      = 590,
    text       = "This is a very long test text.  ",
    originX        = "CENTER",
    originY        = "CENTER",
    textFlow   = "CENTER",
    wrapWidth  = 350,
    lineSpacing    = -4,
    charBaseLine = "CENTER",
    showOrigin     = false
}) 

marqueeLabel.xScale = 2.0
marqueeLabel.yScale = 2.0

marqueeLabel:startMarquee(18, 1)

Hopefully this has given you some idea of the kinds of things you will be able to do with Gemini in the near future. I will continue to add support for other Text Candy effects. For now, simply being able to use Text Candy and Glyph Designer for generating labels is huge.

Comments