Click here to Skip to main content
15,886,067 members
Articles / Game Development
Tip/Trick

Procedural Gyph Language

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
19 Oct 2012CPOL2 min read 14.3K   87   3   3
A New UI Language
 


Image 1




Image 2

Introduction

I thought it would be kinda cool to teach the computer to auto generate glyphs that uniquely represent words, but do so procedurally like some sci-fi alien language. Kanji and other glyph/stroke based symbols evolved over time and there isn't a programmatic pattern to generate the symbols from an alphabet. Because I've always been interested in things that improve efficiency such as short hand, I figured it might be interesting to procedurally generate glyphs/Kanji like symbols from text.

Background

Well, this is what happens when I watch too much Dr. Who.

Languages are cool, so I created a sort of "procedural" generation of glyphs like "kanji" for Japanese, but it's just an alphabet translation.  

Using the Code

First text is split into words, then the letters are "found" in a map, then the map locations are turned into a cursive like stroke connecting 2-3 points at a time to generate a glyph. There are a few cool tricks in the code. First I created a 2D map of the text (array of strings, each string is a row). When a character is found, it's location is the row/column in the map. This is then translated into a graphic location, and appended to the list. This list is then broken into pieces in a way to generally make 2-4 locations into a stroke, like a curved stroke of a brush. This also checks for double letters (adding additional markings) and makes sure that if there were say, 10 location it doesn't get broken into 2 strokes of 4 points and a two point in the end, but into a 4 pnt, and two 3 pnt strokes. 

The code is also a decent example of double buffering and of drawing curves.

Map

The points are selected from the map:

string[] map = {
               "1234567890",
               "QWERTYUIOP",
               "qwertyuiop",
               "`~!@#$%^&**()-_=+",
               "ASDFGHJKL",
               "asdfghjkl",
               ",<.>/?;:'\"[{]}\\|",
               "ZXCVBNM",
               "zxcvbnm",
               };
pnts.Add(new PointF(xInd, yInd));
for (int j = 0; j < words[i].Length; j++)
{
    float x = 0;
    float y = 0;
    char c = words[i][j];
    for (int k = 0; k < map.Length; k++)
    {
        int m = map[k].IndexOf(c);
        if (m >= 0)
        {
            // location is kth row, mth thing.
            // Dividing vertically by map rows, we have the y value.
            y = k * wordHeightScale;
            x = m * wordWidthScale;
            break;
        }
    }
    pnts.Add(new PointF(x + xInd, y + yInd));
}
if (pnts.Count > 1)
{
    renderLine(g, pnts, wordWidthScale, wordHeightScale);
}

Line Rendering

Rendering the line means breaking first into strokes, drawing a stroke then dealing with duplicate letters.

formSegments(pntsArray, segs);
using (Pen p = new Pen(Color.Black, 1.5f))
{
    // This is just for artistic stuff.
    for (int i = 0; i < segs.Count; i++)
    {
        renderStroke(g, p, segs[i]);
    }
... Duplicate letter code.

Segments are made:

protected void formSegments(PointF[] pnts, List<PointF[]> segs)
{
    // The goal is no stroke is less than 3 points, and ideally all are 4 point.
    // if needed do the last (or only) as a 5 point stroke.
    int start = 0;
    while ((start < pnts.Length) && (segs.Count < 20))
    {
        int rem = pnts.Length - start;
        if (rem > 6)
        {
            // If greater than 6, take a 4 stroke bite.
            PointF[] p = new PointF[4];
            for (int i = 0; i < 4; i++) p[i] = pnts[start + i];
            start += 4;
            rem -= 4;
            segs.Add(p);
        }
        if (rem > 5)
        {
            // Remainder is 6 or more, so taking a stroke of three is good.
            PointF[] p = new PointF[3];
            for (int i = 0; i < 3; i++) p[i] = pnts[start + i];
            start += 3;
            rem -= 3;
            segs.Add(p);
        }
        if (rem <= 5)
        {
            PointF[] p = new PointF[rem];
            for (int i = 0; i < rem; i++) p[i] = pnts[start + i];
            start += rem;
            segs.Add(p);
        }
    }
}

Then the lines get drawn:

C#
protected void renderStroke(Graphics g, Pen p, PointF[] pntsArray)
{
    g.DrawCurve(p, pntsArray, 0.75f);

    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < pntsArray.Length; j++)
        {
            pntsArray[j].X += i * 0.1f;
            pntsArray[j].Y += i * 0.2f;
        }
        g.DrawCurve(p, pntsArray, 0.75f);
    }
}

Use in Applications

The glyphs are interesting for decoration, or to create different UI experiences.

One way to think of this submission is as art, or another as looking at different ways a computer could communicate with another computer in a more graceful way than just binary or bar codes. Another thing that might be neat is to use phonetics, and mix in color.

In any case, it's for fun and I hope someone has fun with it. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
United States United States
Phil is a Principal Software developer focusing on weird yet practical algorithms that run the gamut of embedded and desktop (PID loops, Kalman filters, FFTs, client-server SOAP bindings, ASIC design, communication protocols, game engines, robotics).

In his personal life he is a part time mad scientist, full time dad, and studies small circle jujitsu, plays guitar and piano.

Comments and Discussions

 
GeneralMy vote of 4 Pin
DrABELL9-Oct-12 13:26
DrABELL9-Oct-12 13:26 
GeneralRe: My vote of 4 Pin
HoshiKata10-Oct-12 10:54
HoshiKata10-Oct-12 10:54 
GeneralRe: My vote of 4 Pin
DrABELL10-Oct-12 11:05
DrABELL10-Oct-12 11:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.