Advertisement
FeynmanTech

TPTLua Font Generator

Oct 5th, 2013
145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.52 KB | None | 0 0
  1. --[[
  2.  
  3.     USAGE:
  4.  
  5.     Start a new font:
  6.  
  7.     makeFont(Font width (number), Font height (number), Font name (string))
  8.  
  9.     -Makes a new file usable by the texter
  10.  
  11.     -Sets up the font data used throughout the program
  12.  
  13.  
  14.  
  15.     Make all the letters in a font:
  16.  
  17.     autoGen()
  18.  
  19.  
  20.  
  21.     GUI Usage:
  22.  
  23.     Click a pixel to toggle it
  24.  
  25.     Click outside of the GUI to move to the next character
  26.  
  27.     At the top-right corner of the GUI, there is:
  28.  
  29.         a) A display telling you which character you are on, and
  30.         b) A pixel preview of your letter at a 1:1 scale.
  31.  
  32.  
  33.  
  34.     To exit the GUI before you have completed your font:
  35.  
  36.     Type 'done()' into the console. It will exit the GUI, finish your font, and write it to a file.
  37.  
  38. ]]
  39.  
  40. -- Make a matrix of all the characters
  41. local charchart = {}
  42.  
  43. -- Make the file opened wit makeFont visible to other functions that need it
  44. local f
  45.  
  46. -- Set up the info needed to make a font file
  47. function makeFont(w, h, name)
  48.     -- Globally visible metrics data
  49.     ftf_w = w
  50.     ftf_h = h
  51.     -- Globally visible font name
  52.     ftf_name = name
  53.     -- Generic character header - 'char' will be replaced by the character name,
  54.     -- and '_KERN' with the kerning data. 'texter_font' is replaced by the font
  55.     -- name.
  56.     charStr = ({string.gsub([[
  57. texter_font[char] = {
  58.     ['descender'] = -2,
  59.     ['kerning'] = _KERN,
  60.     ['pixels']  = {
  61. ]], 'texter_font', name)})[1]
  62.     f = io.open(name .. '.txt', 'w')
  63.     -- Write the font header - '_NAME' is replaced by the font name, '_W is
  64.     -- replaced by the default character width (when kerning is set to 0), and
  65.     -- '_H' is replaced with the font height.
  66.     f:write(tostring(({string.gsub(string.gsub(string.gsub([[
  67. _NAME = {}
  68. _NAME['width'] = _W
  69. _NAME['height'] = _H
  70.     ]], '_NAME', name), '_W', w), '_H', h)})[1]))
  71. end
  72.  
  73. -- Takes a table returned by the GUI and converts it to readable character data
  74. local function makeLetterFromGui(char, currentfont_pixels)
  75.     -- Kerning data
  76.     local kern, doBreak
  77.     -- Calculate the kerning for the character
  78.     for x = 0, ftf_w - 1 do
  79.         for y = 1, ftf_h do
  80.             if currentfont_pixels[y][ftf_w - x - 1] == 1 then
  81.                 kern = -x
  82.                 doBreak = true -- Break out of for loops?
  83.                 break
  84.             end
  85.             if doBreak == true then
  86.                 break
  87.             end
  88.         end
  89.         if doBreak == true then
  90.             break
  91.         end
  92.     end
  93.     -- Default kerning to 0
  94.     if not kern then kern = 0 end
  95.     -- Replace  the '_KERN' in the character header with real kerning data
  96.     local charStr = ({string.gsub(charStr, '_KERN', kern)})[1]
  97.     -- Replace the 'char' in the character header with the character name and write it
  98.     f:write(({string.gsub(charStr, 'char', string.format('%q', char))})[1])
  99.     for y = 1, ftf_h + 2 do
  100.         for x = 1, ftf_w do
  101.             -- Writing font data to the file
  102.             if x == 1 then
  103.                 -- First pixel in a row
  104.                 f:write('\t\t{', currentfont_pixels[y][x] and tostring(currentfont_pixels[y][x]) or '0', ', ')
  105.             elseif x == ftf_w then
  106.                 -- Last pixel
  107.                 if y == ftf_h + 2 then
  108.                     f:write('\n')
  109.                 -- Other edge pixels
  110.                 else
  111.                     f:write(',\n')
  112.                 end
  113.             else
  114.                 -- All the other pixels
  115.                 f:write(currentfont_pixels[y][x] and tostring(currentfont_pixels[y][x]) or '0', ', ')
  116.             end
  117.         end
  118.     end
  119.     -- Close off the character data
  120.     f:write('\t}\n}\n')
  121. end
  122.  
  123. -- Autopilot Character Set
  124. local charstr = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~`!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?'
  125. -- Current character in the autopilot
  126. local n = 0
  127. -- GUI Stopper
  128. local endMatGet
  129. -- Weird bugfix, if you delete this, it breaks, but I have no idea why.
  130. local getmcoords, rectSetGui, rectDrawGui, testForEnd
  131. -- The GUI!
  132. function autoGen()
  133.     n = n + 1
  134.     -- Current character
  135.     local char = string.sub(charstr, n, n)
  136.     -- Width and height data
  137.     local w, h = ftf_w, ftf_h + 2
  138.     -- Distance between rectangles
  139.     local rstep = 340 / h
  140.     -- Size of rectangles
  141.     local wsize = w * rstep
  142.     -- Character data table
  143.     local mat = {}
  144.     -- Make the character data table 2-D
  145.     for k = 1, h + 2 do
  146.         mat[k] = {}
  147.     end
  148.     -- Predefine the mouse coords - I don't know why, but sometimes they don't get defined
  149.     local rectInMX, rectInMY = 1, 1
  150.     -- Calculate which box the cursor is on
  151.     function getmcoords()
  152.         rectInMX = math.floor((tpt.mousex + rstep) / rstep) - 1
  153.         rectInMY = math.floor((tpt.mousey + rstep) / rstep) - 1
  154.     end
  155.     tpt.register_step(getmcoords)
  156.     -- Variable, not important
  157.     -- Modify the table as you click!
  158.     function rectSetGui(x, y, button, event)
  159.         if event == 2 then
  160.             if mat[rectInMY][rectInMX] ~= 1 then
  161.                 mat[rectInMY][rectInMX] = 1
  162.             else
  163.                 mat[rectInMY][rectInMX] = 0
  164.             end
  165.             -- Stop the GUI if you click outside the character map
  166.             if rectInMX > w or rectInMY > h then endMatGet = true end
  167.         end
  168.         return false
  169.     end
  170.     tpt.register_mouseclick(rectSetGui)
  171.     -- Draw the GUI itself
  172.     function rectDrawGui()
  173.         for y = 1, h do
  174.             for x = 1, w do
  175.                 -- Drawing rectangles, boring stuff
  176.                 tpt.drawrect(x * rstep, y * rstep, rstep - 2, rstep - 2, 255, 255, 255, 255)
  177.                 tpt.fillrect(rectInMX * rstep, rectInMY * rstep, rstep - 2, rstep - 2, 75, 75, 75)
  178.                 -- Draw the current character
  179.                 if mat[y][x] == 1 then
  180.                     tpt.fillrect(x * rstep, y * rstep, rstep - 2, rstep - 2, 125, 125, 125)
  181.                     -- Pixel Preview
  182.                     tpt.drawpixel(w * rstep + rstep + 2 + x, 46 + y, 255, 255, 255, 255)
  183.                 end
  184.             end
  185.         end
  186.         -- Tell the user which character they are drawing
  187.         tpt.drawtext(w * rstep + rstep + 2, 38, 'Current character: ' .. char, 255, 255, 0, 255)
  188.     end
  189.     tpt.register_step(rectDrawGui)
  190.     -- Check whether the program should be stopping
  191.     function testForEnd()
  192.         if endMatGet then
  193.             -- Stop all the GUI stuff
  194.             tpt.unregister_step(getmcoords)
  195.             tpt.unregister_step(rectDrawGui)
  196.             tpt.unregister_mouseclick(rectSetGui)
  197.             -- Save the current character unless done() has closed the file
  198.             if endMatGet ~= 'DONE' then
  199.                 makeLetterFromGui(string.sub(charstr, n, n), mat)
  200.             end
  201.             -- Recurse until it reaches the end of the character list or until done() is called
  202.             if n <= #charstr and endMatGet ~= 'DONE' then
  203.                 autoGen()
  204.                 endMatGet = nil
  205.             end
  206.         end
  207.     end
  208.     tpt.register_step(testForEnd)
  209. end
  210.  
  211. -- Finish up the font and write it
  212. function done()
  213.     -- Write the NULL character, it can break without it
  214.     f:write('\n' .. ftf_name .. [[['NULL'] = {
  215.     ['descender'] = 0,
  216.     ['kerning'] = 0,
  217.     ['pixels']  = {
  218.         {1, 1, 1, 1, 1},
  219.         {1, 0, 0, 1, 1},
  220.         {1, 1, 1, 0, 1},
  221.         {1, 1, 0, 1, 1},
  222.         {1, 1, 1, 1, 1},
  223.         {1, 1, 0, 1, 1},
  224.         {1, 1, 1, 1, 1},
  225.         {0, 0, 0, 0, 0},
  226.         {0, 0, 0, 0, 0}
  227.     }
  228. }]])
  229.     -- Stop the GUI
  230.     endMatGet = 'DONE'
  231.     tpt.unregister_step(testForEnd)
  232.     -- Close the file
  233.     f:close()
  234. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement