ZZText

From Second Life Wiki
Revision as of 04:51, 21 June 2008 by Salahzar Stenvaag (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

What is it

ZZText is a low-prim, low-lag, international variation of XyText with the following features:

  • can be enhanced with new fonts or UTF-8 characters using GIMP and python-fu.
  • uses only 35 textures instead of 66 for the 10 chars on prim solution (this gives a bit less quality then the original xytext, but under normal situations is acceptable.

Rationale: if you have problems with prim usage, then you can accept this compromise.

  • this particular combination of textures gives something way more rapid than xyzzy, which is very slow for big boards, and less lagger than xytext.


Credits and copyright

ZZText is heavily dependent on XyText so it shares and extends credits and copyrights.

Also this is a low prim variation of the Xyzzy-UTF8 page but downgraded to use XyText lower quality paradigm instead than the 1 character face approach.

How to generate the textures

  • You need to have GIMP 2.0 with python-fu extension installed
  • Use the mega-image maker python-fu script (see following sections)
  • Use the splitter python-fu script to produce 512x512 guides for later splitting
  • Use the filter/web/slice... button to produce 64 slices in png format to retain transparence (from 0-0 to 7-7)
  • Manually remove the empty slices (the i-j where j>i for instance 2-3, 6-7) so you have only 35 images png.
  • Manually convert each png to tga (this is solving some problems with sl uploading regarding transparence)
  • Upload the textures keeping the order 0-0 1-0 1-1 2-0 2-1 2-3 .... until 7-7)

Manual parts can be automated by another python-fu, but I was so exhausted with the others that it was ok for me doing manually :)

There is still some fix needed to do on the python-fu script. Currently characters are still a bit unevenly put so that when displaying them depending on which couple using we might see some slight asymmetric unbalancing. You can note this only when looking very closely to the chars. Whenever I fix myself this problem I will post here.

For those of you who already accept fonts I did last week, look at next sections for the 35 texture UUIDs:


So how can I use it?

  • Put the script named ZZText into each prim of your board naming each cell 1000 ---- 1099 as far as you need cells
  • Have a main script doing the following: llLinkedMessage(LINK_SET,1040,"çòàùè",NULL_KEY) to write on cell named 1040

To divide in rows, use simple modulus operations.

Variation on XyText 1.5 standard script

For not being so difficult to follow, I only publish differences between my script and XyText 1.5 so that you might be able to understand better what I did:

Change CHARACTER_GRID with our full permission textures

list    CHARACTER_GRID  = [
        "96f4578b-879e-44ae-d223-427cc615f5a4", // my slice-0-0
        "eab5360f-6653-593f-b679-69c68b0dd001", // 1-0
        "367330be-717a-277d-5205-131cd6ded458", // 1-1
        "32046675-6e7e-2425-ce77-69000b0b4d96", // 2-0
        "40085901-bde6-2dd4-40cd-b6d48d242997", // 2-1
        "205d318b-09b7-7ecc-922e-801c93a546c8", // 2-2
        "841e7826-3645-d4f0-d48b-389586dd8e90", // 3-0
        "e2db78c5-fb47-d767-4744-8cb6d84610d0", // 3-1
        "15312c89-afd4-854c-9d9b-5b9e11844aed", // 3-2
        "d180e771-0393-d09b-8cac-0af6d550ae4a", // 3-3
        "c6c1d2c8-5dfd-b13a-7f1e-c3ede8126769", // 4-0
        "bc100d0c-a445-947f-caa4-285d9cc8a9de", // 4-1
        "0b31e862-75a4-9ed3-6331-e9e700a0fedb", // 4-2
        "0eacc306-6bd5-ab31-de47-c686141a6733", // 4-3
        "b68de1d9-4890-74a0-4d25-d4d5c83a0dba", // 4-4
        "04b2bf9b-a8bb-0a39-1062-9b005229eba9", // 5-0
        "be293f10-25ec-beb9-738b-fe1892b82aef", // 5-1
        "5e9c8317-71f5-f073-76ab-7c412d3acb84", // 5-2
        "030b441b-9022-2aba-f7a7-af6810c354b8", // 5-3
        "9f455858-8ae6-3a9a-c2d4-bc5ee92430ac", // 5-4
        "ee741143-f01e-f730-667e-66a3cd57d1cc", // 5-5
        "710282bc-bd80-5a44-6987-0c4c11a4c294", // 6-0
        "c9c410db-675a-1e98-4107-debd3c73a754", // 6-1
        "486c2336-71c5-b962-266c-838a865c067c", // 6-2
        "d4722155-0b6d-3673-0208-a727729bc117", // 6-3
        "bc7af3cd-ee48-08df-fe8b-a6ca8a425733", // 6-4
        "f23d7a73-00c3-1ffd-69a7-0cca031c939d", // 6-5
        "aa95bfd1-ac80-f962-7acf-d6aeed9c7e81", // 6-6
        "53fd52e3-0e8b-dcc8-42f8-332aef421bd2", // 7-0
        "da3f6f09-3e3a-e156-8e2e-1040111a5635", // 7-1
        "409a95c0-b685-2036-d0de-75e8ab654243", // 7-2
        "14e05aca-3a61-b892-3632-dcde72324779", // 7-3
        "546c0e4f-b678-895d-2035-0f39bb7f4979", // 7-4
        "cf2fc337-109f-ba25-8ff5-786f7d6ceb5b", // 7-5
        "9943204b-a4de-868a-3cdd-8785d1864ede", // 7-6
        "765cfd9c-9703-b5ba-2c5d-f1c8bd44e0f4"  // 7-7
          ];

Enabling answering to only a specific channel instead of DISPLAY_STRING channel

This heavily helps in producing multi cell boards:

integer ME;
....
state_entry(){
....
 ME=(integer)llGetObjectName(); // need that each cell has its own number as object name starting from 1000 for instance
....
// be sure we are answering only to channel ME
link_message(integer sender, integer channel, string data, key id) {
        if (channel == (ME) {
            RenderString(data);
            return;
        }

UTF-8 character specification

This must closely match what you produced with python-fu

ResetCharIndex() {
    gCharIndex  = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`";
    // \" <-- Fixes LSL syntax highlighting bug.
    gCharIndex += "abcdefghijklmnopqrstuvwxyz{|}~";
  //        cap cedille      u:         e/            a^         a:          a/         a ring      cedille     e^           e:
  decode=  ["%C3%87", "%C3%BC", "%C3%A9", "%C3%A2", "%C3%A4", "%C3%A0", "%C3%A5", "%C3%A7", "%C3%AA", "%C3%AB",
  
    
  //                    e\           i:               i^            i\                A:          A ring          E/              ae           AE           marker >
       "%C3%A8", "%C3%AF", "%C3%AE", "%C3%AC", "%C3%84", "%C3%85", "%C3%89", "%C3%A6", "%C3%86", "%E2%96%B6" ,

  //                 o:               o/           u^          u\              y:               O:             U:          cent           pound        yen
       "%C3%B6", "%C3%B2", "%C3%BB", "%C3%B9", "%C3%BF", "%C3%96", "%C3%9C", "%C2%A2", "%C2%A3", "%C2%A5",
   
  //                 A^              a/              i/                o/            u/              n~           E:            y/              inv ?         O^
       "%C3%82", "%C3%A1", "%C3%AD", "%C3%B3", "%C3%BA", "%C3%B1", "%C3%8B", "%C3%BD", "%C2%BF", "%C3%94",

  //                   inv !             I\             I/           degree       E^              I^            o^            U^
       "%C2%A1", "%C3%8C", "%C3%8D", "%C2%B0", "%C3%8A", "%C3%8E", "%C3%B4", "%C3%9B",

  //                     Y:          euro           german ss         E\              A\           A/              U\           U/               O\           O/
       "%C3%9D", "%E2%82%AC", "%C3%9F", "%C3%88", "%C3%80", "%C3%81", "%C3%99", "%C3%9A", "%C3%92", "%C3%93",

  //                   Sv           sv             zv             Zv              Y:             I:
       "%C5%A0", "%C5%A1", "%C5%BE", "%C5%BD", "%C3%9D", "%C3%8C" ];
     
    
}

Accessing the new characters from textures

This is the most difficult part. Still need to clean up offsets, since now they are still a bit wrong.

vector GetGridOffset(vector grid_pos) {
    // Zoom in on the texture showing our character pair.
    integer Col = llRound(grid_pos.x) % 40; // PK was 20
    integer Row = llRound(grid_pos.y) % 20; // PK was 10

    // Return the offset in the texture.
    return <-0.45 + 0.025 * Col, 0.45 - 0.05 * Row, 0.0>; // PK was 0.05 and 0.1
}

ShowChars(vector grid_pos1, vector grid_pos2, vector grid_pos3, vector grid_pos4, vector grid_pos5) {
   // Set the primitive textures directly.
     
               
   llSetPrimitiveParams( [
        PRIM_TEXTURE, FACE_1, GetGridTexture(grid_pos1), <0.125, 0.05, 0>, GetGridOffset(grid_pos1) + <0.0375-0.025-0.002, 0.025, 0>, 0.0,
        PRIM_TEXTURE, FACE_2, GetGridTexture(grid_pos2), <0.05, 0.05, 0>, GetGridOffset(grid_pos2)+<-0.025-0.002, 0.025,0>, 0.0,
        PRIM_TEXTURE, FACE_3, GetGridTexture(grid_pos3), <-0.74, 0.05, 0>, GetGridOffset(grid_pos3)+ <-.34-0.002, 0.025, 0>, 0.0,
        PRIM_TEXTURE, FACE_4, GetGridTexture(grid_pos4), <0.05, 0.05, 0>, GetGridOffset(grid_pos4)+<-0.025-0.002, 0.025,0>, 0.0,
        PRIM_TEXTURE, FACE_5, GetGridTexture(grid_pos5), <0.125, 0.05, 0>, GetGridOffset(grid_pos5) + <0.0375-0.025-0.077-0.002, 0.025, 0>, 0.0
//        PRIM_TEXTURE, FACE_1, GetGridTexture(grid_pos1), <0.25, 0.1, 0>, GetGridOffset(grid_pos1) + <0.075, 0, 0>, 0.0,
//        PRIM_TEXTURE, FACE_2, GetGridTexture(grid_pos2), <0.1, 0.1, 0>, GetGridOffset(grid_pos2), 0.0,
//        PRIM_TEXTURE, FACE_3, GetGridTexture(grid_pos3), <-1.48, 0.1, 0>, GetGridOffset(grid_pos3)+ <0.37, 0, 0>, 0.0,
//        PRIM_TEXTURE, FACE_4, GetGridTexture(grid_pos4), <0.1, 0.1, 0>, GetGridOffset(grid_pos4), 0.0,
//        PRIM_TEXTURE, FACE_5, GetGridTexture(grid_pos5), <0.25, 0.1, 0>, GetGridOffset(grid_pos5) - <0.075, 0, 0>, 0.0
        
        ]);
}

integer GetIndex(string char)
{
    integer  ret=llSubStringIndex(gCharIndex, char);
    if(ret>=0) return ret;
    
    // special char do nice trick :)
    string escaped=llEscapeURL(char);
    
    if(escaped=="%E2%80%99") return 7; // remap ’
    //llSay(0,"Looking for "+escaped);
    integer found=llListFindList(decode, [escaped]);
    
    // not found
    if(found<0) return 0;
    
    // return correct index
    return llStringLength(gCharIndex)+found;
    
}

RenderString(string str) {
    // Get the grid positions for each pair of characters.
    vector GridPos1 = GetGridPos( GetIndex(llGetSubString(str, 0, 0)),
                                  GetIndex(llGetSubString(str, 1, 1)) );
    vector GridPos2 = GetGridPos( GetIndex(llGetSubString(str, 2, 2)),
                                  GetIndex(llGetSubString(str, 3, 3)) );
    vector GridPos3 = GetGridPos( GetIndex(llGetSubString(str, 4, 4)),
                                  GetIndex(llGetSubString(str, 5, 5)) );
    vector GridPos4 = GetGridPos( GetIndex(llGetSubString(str, 6, 6)),
                                  GetIndex(llGetSubString(str, 7, 7)) );
    vector GridPos5 = GetGridPos( GetIndex(llGetSubString(str, 8, 8)),
                                  GetIndex(llGetSubString(str, 9, 9)) );                                   

    // Use these grid positions to display the correct textures/offsets.
    ShowChars(GridPos1, GridPos2, GridPos3, GridPos4, GridPos5);
}

Splitter python-fu script

Very simple just tell him the 512 splitting and it will create guides.

#!/usr/bin/env python

import math
from gimpfu import *

def python_guides(timg, tdrawable, interval=100):
    timg.undo_group_start()
    x=0
    while x < timg.width:
       timg.add_vguide(x)
       x+=interval
       
    y=0
    while y < timg.height:
       timg.add_hguide(y)
       y+=interval
       
    timg.undo_group_end()
    
    gimp.displays_flush()

register(
        "python_fu_guides",
        "Guides: this will split the images in sections...",
        "Guides: this will split the images in sections...",
        "Salahzar Stenvaag",
        " ",
        "2008",
        "<Image>/Filters/Guides...",
        "RGB*, GRAY*",
        [
                (PF_INT, "interval", "Interval", 100)
        ],
        [],
        python_guides)

main()

Mega-image maker python-fu script

If you need your characters you need to change the UTF-8 codings in "decode" var

#! /usr/bin/env python
from gimpfu import *

# you can remove logging, I used it to be sure program was working since it can be a bit slow 
# to generate all the combination
def python_log_init():
    fileHandle = open( 'python.log', 'w')
    fileHandle.close()
    
def python_log(s):
    fileHandle = open ( 'python.log', 'a' )
    fileHandle.write(str(s)+"\n")
    fileHandle.close() 

def python_xytext2(font,color,size,limit):
  """Print the arguments on standard output"""
  python_log_init()
  python_log("font: %s color: <%d,%d,%d> size: %d limit: %d" % ( font, color[0], color[1], color[2], size, limit ))
  chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
  
  
  # 
  
  #        cap cedille      u:         e/            a^         a:          a/         a ring      cedille     e^           e:
  decode=  ["\xC3\x87", "\xC3\xBC", "\xC3\xA9", "\xC3\xA2", "\xC3\xA4", "\xC3\xA0", "\xC3\xA5", "\xC3\xA7", "\xC3\xAA", "\xC3\xAB" ]  
  
    
  #                    e\           i:               i^            i\                A:          A ring          E/              ae           AE           marker >
  decode+=["\xC3\xA8", "\xC3\xAF", "\xC3\xAE", "\xC3\xAC", "\xC3\x84", "\xC3\x85", "\xC3\x89", "\xC3\xA6", "\xC3\x86", "\xE2\x96\xB6" ]

  #                 o:               o/           u^          u\              y:               O:             U:          cent           pound        yen
  decode+=["\xC3\xB6", "\xC3\xB2", "\xC3\xBB", "\xC3\xB9", "\xC3\xBF", "\xC3\x96", "\xC3\x9C", "\xC2\xA2", "\xC2\xA3", "\xC2\xA5"]
   
  #                 A^              a/              i/                o/            u/              n~           E:            y/              inv ?         O^
  decode+=["\xC3\x82", "\xC3\xA1", "\xC3\xAD", "\xC3\xB3", "\xC3\xBA", "\xC3\xB1", "\xC3\x8B", "\xC3\xBD", "\xC2\xBF", "\xC3\x94" ] 

  #                   inv !             I\             I/           degree       E^              I^            o^            U^
  decode+=["\xC2\xA1", "\xC3\x8C", "\xC3\x8D", "\xC2\xB0", "\xC3\x8A", "\xC3\x8E", "\xC3\xB4", "\xC3\x9B" ]

  #                     Y:          euro           german ss         E\              A\           A/              U\           U/               O\           O/
  decode+=["\xC3\x9D", "\xE2\x82\xAC", "\xC3\x9F", "\xC3\x88", "\xC3\x80", "\xC3\x81", "\xC3\x99", "\xC3\x9A", "\xC3\x92", "\xC3\x93"   ]                  

  #                   Sv           sv             zv             Zv              Y:             I:
  decode+=[ "\xC5\xA0", "\xC5\xA1", "\xC5\xBE", "\xC5\xBD", "\xC3\x9D", "\xC3\x8C" ]
 
 
  width=5120
  height=5120
  img = gimp.Image(width, height, RGB)
  layer = gimp.Layer(img, "my font", width, height, RGB_IMAGE, 100, NORMAL_MODE)
  img.add_layer(layer, 0)
  layer.add_alpha()
  gimp.set_foreground(color)
  pdb.gimp_selection_all(img)
  pdb.gimp_edit_clear(layer)
  pdb.gimp_selection_none(img)
  size= 20 # 23 # 21.3 # 30
  
  index=0
  numtot=len(chars)+len(decode)
  #numtot=50
  if limit>0: numtot=limit
  deltay=12.8 # 13.8215 # 12.8 # 18
  deltax=25.6 # 27.6432 # 25.6 # 36
  maxchars=len(chars)
  for first in range(numtot):
  
     if(first<maxchars): 
        el1=chars[first]
     else:
        el1=decode[first-maxchars]
     
     python_log(str(first)+"/"+str(numtot)+":  "+el1)
     for second in range(first+1):

          # to save time removed function call
          if(second<maxchars): 
             el2=chars[second]
          else:
             el2=decode[second-maxchars]
                 
          y=second * deltay * 2 # horizontal distance
          x=first*deltax # line distance
          pdb.gimp_text_fontname(img,layer,y,x,el1,0,TRUE,size,PIXELS,font)
          pdb.gimp_text_fontname(img,layer,y+deltay,x,el2,0,TRUE,size,PIXELS,font)
          
          index=index+1
          
  
  # Now ready to display this image
  img.merge_visible_layers(0)
  gimp.Display(img)
   

register(
  "xytext2", "", "", "", "", "",
  "<Toolbox>/Xtns/_XyText2Char", "",
  [
  (PF_FONT, "font", "Font to use", "Arial"),
  (PF_COLOR,"color","Color to use", (255,255,255) ),
  (PF_INT,    "size", "Font size", 45          ),
  (PF_INT,  "limit", "limit font generation ", 0  ),
 
  ],
  [],
  python_xytext2
  )

main()