ZZText
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()