Flash
Flash

Reputation: 3021

Implementing a glyph patterns in C

I have read this implementation of glyphs in the Expert C Programming by Peter Van Der Linden. He states this method to draw a glyph pattern. This question is strictly restricted to the context of C programming.

static unsigned short stopwatch[] = {
    0x07C6,
    0x1FF7,
    0x383B,
    0x600C,
    0x600C,
    0xC006,
    0xC006,
    0xDF06,
    0xC106,
    0xC106,
    0x610C,
    0x610C,
    0x3838,
    0x1FF0,
    0x07C0,
    0x0000
};

and then define

#define X )*2+1
#define _ )*2
#define s ((((((((((((((((0

for drawing glyphs 16-bits wide.

Then the above array is converted to a glyph pattern of a StopWatch.

How do we draw those glyphs on the screen without using the graphics? Is there any method to draw the glyph patterns of other objects like outline of maps, face of a person roughly without having to plot each of the pixels, and without using the regular C graphics?

Are there any algorithms that were followed?

Upvotes: 3

Views: 787

Answers (2)

artless-noise-bye-due2AI
artless-noise-bye-due2AI

Reputation: 22460

Here is an update of the code which does an 'Ascii Art' of the stopwatch in source. See history for versions that are faithful to the book.

#include <stdio.h>

#define ____ 0
#define ___X 1
#define __X_ 2
#define __XX 3
#define _X__ 4
#define _X_X 5
#define _XX_ 6
#define _XXX 7
#define X___ 8
#define X__X 9
#define X_X_ 10
#define X_XX 11
#define XX__ 12
#define XX_X 13
#define XXX_ 14
#define XXXX 15
#define D16(A,B,C,D) ((A)<<12|(B<<8)|(C<<4)|D)

#define ALEN(A) (sizeof(A)/sizeof(A[0]))

static unsigned short stopwatch[] = {
 D16(____,_XXX,XX__,_XX_),  // 0x07c6
 D16(___X,XXXX,XXXX,_XXX),  // 0x1ff7
 D16(__XX,X___,__XX,X_XX),  // 0x383b
 D16(_XX_,____,____,XX__),  // 0x600c
 D16(_XX_,____,____,XX__),  // 0x600c
 D16(XX__,____,____,_XX_),  // 0xc006
 D16(XX__,____,____,_XX_),  // 0xc006
 D16(XX_X,XXXX,____,_XX_),  // 0xdf06
 D16(XX__,___X,____,_XX_),  // 0xc106
 D16(XX__,___X,____,_XX_),  // 0xc106
 D16(_XX_,___X,____,XX__),  // 0x610c
 D16(_XX_,___X,____,XX__),  // 0x610c
 D16(__XX,X___,__XX,X___),  // 0x3838
 D16(___X,XXXX,XXXX,____),  // 0x1ff0
 D16(____,_XXX,XX__,____),  // 0x07c0
};

int main(void)
{
    unsigned int i, idx;
    const char *pattern[] = {
        "____", /* 0 */  "___X", /* 1 */  "__X_", /* 2 */  "__XX", /* 3 */
        "_X__", /* 4 */  "_X_X", /* 5 */  "_XX_", /* 6 */  "_XXX", /* 7 */
        "X___", /* 8 */  "X__X", /* 9 */  "X_X_", /* 10 */ "X_XX", /* 11 */
        "XX__", /* 12 */ "XX_X", /* 13 */ "XXX_", /* 14 */ "XXXX"  /* 15 */
    };
    for (i = 0; i < ALEN(stopwatch); i++)
    {
        printf("D16(");
        idx = (stopwatch[i] >> 12) & 0xf;
        printf("%s,", pattern[idx]);
        idx = (stopwatch[i] >> 8) & 0xf;
        printf("%s,", pattern[idx]);
        idx = (stopwatch[i] >> 4) & 0xf;
        printf("%s,", pattern[idx]);
        idx = (stopwatch[i]) & 0xf;
        printf("%s),  // 0x%04x\n", pattern[idx], stopwatch[i]);
    }
}

NB: The main idea is that you can substitute the original hex array in stopwatch data and the code will generate the same array as the sample above. Ie, the hex array and the ASCII ART are equivalent when combined with the macros.

This is most helpful in font libraries that are linked into source. Ie, this stopwatch array is much easier to visualize in the source versus the hex array.

Hmm...But we need to find out the array to implement any other object's glyph ...Are there any other ways to implement this .. ?

I think this is an important point that I did not see expressed anywhere. The binary version can be sent to bitmapped hardware. However, the 'ASCII ART' representation is much easier to comprehend than a hex array. Another way to do this is with binary constants, although the visualization is not as good.

Here is another question where you might want to support a bit depth larger than a single bit for grey scale images. So, you need to make a define for each 'colour depth' and then encode that. If you are writing a program that translates SVG/BMP, etc to a 'C' array this would be a better way to create the output (as well as a traditional "MACHINE GENERATE CONTENT" comment).

You need to limit the palette to make it 'valid C'. The additional restriction of an identifier in 'C' limits the character space to upper and lower letter, numbers and the underbar. For instance, '.' period is not allowed. 'W' and 'R' are other candidates (besides X). So the 'palette' for grey scale images maybe limited.

I think I also saw this used in some BDF font definitions. There was also a blog post on coding standards in regards to whitespace. The whitespace does not matter to a compiler. However, it matters to a human. So while the hex array is equivalent to the machine, it is helpful. For instance, over time, the application might have two stopwatch glyphs and then you wonder which one the hex array is defining.


My original goal was to find a good way to implement the 'ASCII Art' that is consumable by a compiler. I took 'Peter Van Der Linden' macros (which may originate from UseNet) and concatenated an nibble. These are much less likely to cause name conflicts. It does have a downside of having commas interspersed, but I think the glyph is still recognizable, a little more compact and the macros are much easier to understand. [See this posts history for a variant using the original macros].

Upvotes: 2

mvds
mvds

Reputation: 47114

There is just a few lines of code missing:

int main()
{
    int i,j;
    for ( i=0;stopwatch[i];i++ )
    {
        for ( j=1<<16;j;j>>=1 ) printf("%c",stopwatch[i]&j?'o':' ');
        printf("\n");
    }
}

voila, stopwatch:

      ooooo   oo 
    ooooooooo ooo
   ooo     ooo oo
  oo         oo  
  oo         oo  
 oo           oo 
 oo           oo 
 oo ooooo     oo 
 oo     o     oo 
 oo     o     oo 
  oo    o    oo  
  oo    o    oo  
   ooo     ooo   
    ooooooooo    
      ooooo      

The define statements are a shorthand to arrive at the magic values in that list:

$ gcc -E -x c -
#define X )*2+1
#define _ )*2
#define s ((((((((((((((((0 

s _ _ _ _ _ _ X X X X _ _ _ _ _ _

// will be preprocessed to:
^D

((((((((((((((((0 )*2 )*2 )*2 )*2 )*2 )*2 )*2+1 )*2+1 )*2+1 )*2+1 )*2 )*2 )*2 )*2 )*2 )*2

That last blurb is an expression which leads to some value (in this case 960 or 0x03c0) you could use in that "stopwatch" list.

Upvotes: 1

Related Questions