font bitmap generator (prototype)

Share your advanced PureBasic knowledge/code with the community.
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

font bitmap generator (prototype)

Post by eddy »

Here is the prototype for the bitmap font generator. (for PB 4.40b5)
You can test it on MAC / Linux. I want to check if there's any problem with the windowed screen.

Code: Select all

EnableExplicit
CompilerIf #PB_Compiler_Unicode=0
   MessageRequester("Warning", "You didn't compile an UNICODE executable!", #PB_MessageRequester_Ok)
   End
CompilerEndIf
CompilerIf Subsystem("DirectX9")
   MessageRequester("Warning", "Don't use the DirectX9 subsystem!", #PB_MessageRequester_Ok)
   End
CompilerEndIf

Enumeration
   #win
   #status
   
   #scrollX
   #scrollY
   #editCharList
   #splitParams
   #panelParams
   #spinFontSize
   #checkBold
   #checkItalic
   #comboTexture
   #buttonGenerate
   #buttonFont
   #buttonFontColor
   #buttonBackColor
   #timerRedrawPreview
   #timerStatusProgress
   #timerRedrawSelection
   #listColorGrid
   
   #fnt
   #imageFont
   #imageGrid
   #imageFontColor
   #imageBackColor
EndEnumeration
Structure charVisible
   ;char code (UNICODE)
   code.U
   
   ;char position
   cx.i
   cy.i
   cw.i
   ch.i
EndStructure
Global NewList charVisible.charVisible()
Global charList.s
Global fnt.s="Arial"
Global fntSize=12
Global fntStyle=0
Global fntColor=RGB(255, 0, 0)
Global colorBack=RGB(100, 100, 120)
Global gridW=512
Global gridH=512

Structure colorGrid
   name.s
   c1.i
   c2.i
   imageGrid.i
EndStructure
Global NewList colorGrid.colorGrid()
With colorGrid()
   AddElement(colorGrid()) : \name="Normal" : \c1=RGB(250, 250, 250) : \c2=RGB(200, 200, 200)
   AddElement(colorGrid()) : \name="Dark  " : \c1=RGB(120, 120, 120) : \c2=RGB(100, 100, 100)
   AddElement(colorGrid()) : \name="Light " : \c1=RGB(255, 255, 255) : \c2=RGB(230, 230, 230)
   AddElement(colorGrid()) : \name="Red   " : \c1=RGB(255, 50, 50) : \c2=RGB(200, 0, 0)
   AddElement(colorGrid()) : \name="Blue  " : \c1=RGB(70, 70, 255) : \c2=RGB(50, 50, 200)
   AddElement(colorGrid()) : \name="Green " : \c1=RGB(70, 255, 70) : \c2=RGB(50, 200, 50)
EndWith

;{/// IMAGE FUNCTIONS
Procedure SaveCharPosition(code.U, cx, cy, cw, ch)
   AddElement(charVisible())
   charVisible()\code=code
   charVisible()\cx=cx
   charVisible()\cy=cy
   charVisible()\cw=cw
   charVisible()\ch=ch
   
EndProcedure
Procedure NextCharPosition(cx, cy, ch)
   Protected px=cx
   Protected py
   Protected checkPixel=fntStyle & #PB_Font_Italic
   While checkPixel
      checkPixel=0
      For py=cy To cy+ch-1
         If px>=ImageWidth(#imageFont) Or py>=ImageHeight(#imageFont)
            ;stop if outside image output
            Break
         Else
            ;check pixel (after drawing italic character)
            If (Point(px, py) & $FF000000)
               px+1
               checkPixel=1
               Break
            EndIf
         EndIf
      Next
   Wend
   
   ProcedureReturn px
EndProcedure
Procedure DrawGrid()
   Protected w=gridW
   Protected h=gridH
   With colorGrid()
      ;{/// draw grid image templates
      If \imageGrid=0
         Protected dw=1024
         Protected dh=1024
         
         ForEach colorGrid()
            \imageGrid=CreateImage(#PB_Any, dw, dh, 32)
            StartDrawing(ImageOutput(\imageGrid))
               DrawingMode(#PB_2DDrawing_Default)
               FrontColor(\c1)
               Box(0, 0, dw, dh)
               FrontColor(\c2)
               Protected k=0
               Protected x, y
               For y=0 To dh Step 32
                  If k=32 : k=0 : Else : k=32 : EndIf
                  
                  For x=k To dw Step 64
                     Box(x, y, 32, 32)
                  Next
               Next
            StopDrawing()
         Next
      EndIf
      ;}
      
      ;{/// draw grid
      CreateImage(#imageGrid, w, h, 32)
      StartDrawing(ImageOutput(#imageGrid))
         DrawingMode(#PB_2DDrawing_Default)
         DrawImage(ImageID(\imageGrid), 0, 0)
      StopDrawing()
      ;}
   EndWith
EndProcedure
Procedure DrawFont()
   Protected w=ImageWidth(#imageGrid)
   Protected h=ImageHeight(#imageGrid)
   CreateImage(#imageFont, w, h, 32)
   StartDrawing(ImageOutput(#imageFont))
      If IsFont(#fnt)
         DrawingFont(FontID(#fnt))
      EndIf
      
      #mw=4
      #mh=4
      
      DrawingMode(#PB_2DDrawing_Default)
      Box(0, 0, w, h, fntColor)
      DrawingMode(#PB_2DDrawing_AlphaChannel)
      Box(0, 0, w, h, 0)
      FrontColor(RGBA(255, 255, 255, 255))
      BackColor(RGBA(255, 0, 0, 0))
      
      ClearList(charVisible())
      If charList
         Protected c.s, cw, ch, cx=#mw, cy=#mh, lineHeight
         Protected charIndex.i
         Protected charLast=Len(charList)
         
         For charIndex=1 To charLast
            c=Mid(charList, charIndex, 1)
            cw=TextWidth(c)
            ch=TextHeight(c)
            If cw=0 Or ch=0 : Continue : EndIf
            
            ;draw char
            DrawText(cx, cy, c+" ")
            cw=NextCharPosition(cx+cw, cy, ch)-cx
            
            ;save char position
            SaveCharPosition(charIndex, cx-#mw, cy-#mh, cw+2*#mw, ch+2*#mh)
            
            ;update drawing position
            cx+cw+#mw*2
            
            ;update height of current line
            If lineHeight<ch : lineHeight=ch : EndIf
            
            ;check next char position
            If charIndex<charLast
               c=Mid(charList, charIndex+1, 1)
               cw=TextWidth(c)
               ch=TextHeight(c)
               If (cx+cw+#mw*2)>=w
                  cx=#mw
                  cy+(lineHeight+#mh*2)
                  If (cy+ch+#mh*2)>=h : Break : EndIf
                  lineHeight=0
               EndIf
            EndIf
         Next
      EndIf
   StopDrawing()
EndProcedure
Procedure DrawPreview()
   Global GlobalSelection
   
   Global screenOffsetX=-GetGadgetState(#scrollx)
   Global screenOffsetY=-GetGadgetState(#scrolly)
   
   ClearScreen(colorBack)
   StartDrawing(ScreenOutput())
      DrawingMode(#PB_2DDrawing_Default)
      DrawImage(ImageID(#imageGrid), screenOffsetX, screenOffsetY)
      If GlobalSelection>0
         Box(charVisible()\cx+screenOffsetX, charVisible()\cy+screenOffsetY, charVisible()\cw, charVisible()\ch, RGB(255, 255, 0))
      EndIf
      DrawAlphaImage(ImageID(#imageFont), screenOffsetX, screenOffsetY)
   StopDrawing()
   FlipBuffers()
EndProcedure
Procedure CreateColorBox(ID, color, w=#PB_Ignore, h=#PB_Ignore)
   If w=#PB_Ignore
      w=ImageWidth(ID)
      h=ImageHeight(ID)
   Else
      Select #PB_Compiler_OS
         Case #PB_OS_Windows
         Case #PB_OS_Linux
         Case #PB_OS_MacOS
            w-20
            h-8
      EndSelect
   EndIf
   CreateImage(ID, w, h, 32)
   StartDrawing(ImageOutput(ID))
      Box(0, 0, w, h, color)
   StopDrawing()
EndProcedure
Procedure CreateGridBox(color1, color2)
   Protected ID=CreateImage(#PB_Any, 32, 32, 32)
   StartDrawing(ImageOutput(ID))
      Box(0, 0, 32, 32, color1)
      Box(0, 0, 16, 16, color2)
      Box(16, 16, 16, 16, color2)
   StopDrawing()
   
   ProcedureReturn ImageID(ID)
EndProcedure
;}
;{/// INVOKE FUNCTIONS
Procedure InvokeUpdateScreen(timeout=-1)
   If timeout<0
      RemoveWindowTimer(#win, #timerRedrawPreview)
   Else
      AddWindowTimer(#win, #timerRedrawPreview, timeout+1)
   EndIf
EndProcedure
Procedure InvokeUpdateStatusBar(timeout=-1)
   Global GlobalStatusTimer
   
   If timeout<0
      RemoveWindowTimer(#win, #timerStatusProgress)
      
      StatusBarText(#status, 1, "Characters visible on screen: "+Str(ListSize(charVisible()))+" / "+Str(Len(charList)))
      StatusBarText(#status, 2, "Texture Size: "+Str(ImageWidth(#imageGrid))+" x "+Str(ImageHeight(#imageGrid)))
      StatusBarText(#status, 3, "")
   Else
      AddWindowTimer(#win, #timerStatusProgress, timeout+1)
   EndIf
   
   GlobalStatusTimer=0
   StatusBarProgress(#status, 0, GlobalStatusTimer, 0, 0, 100)
EndProcedure
Procedure UpdateStatusBar()
   Global GlobalStatusTimer
   
   GlobalStatusTimer=(GlobalStatusTimer+10) % 100
   StatusBarProgress(#status, 0, GlobalStatusTimer, 0, 0, 100)
EndProcedure
Procedure UpdateScreen(fastRedraw=#False)
   Global GlobalSelection
   Global screenOffsetX
   Global screenOffsetY
   
   If fastRedraw
      ;find new selection
      Protected newSelection=0
      Protected mx=WindowMouseX(#win)-screenOffsetX
      Protected my=WindowMouseY(#win)-screenOffsetY
      ForEach charVisible()
         With charVisible()
            If (mx>=\cx And mx<(\cx+\cw)) And (my>=\cy And my<(\cy+\ch))
               newSelection=ListIndex(charVisible())+1
               Break
            EndIf
         EndWith
      Next
      
      ;redraw only if selection changed
      If GlobalSelection<>newSelection
         GlobalSelection=newSelection
         DrawPreview()
      EndIf
   Else
      ;redraw preview (and update font)
      LoadFont(#fnt, fnt, fntSize, fntStyle)
      DrawFont()
      DrawPreview()
   EndIf
EndProcedure
;}
;{/// UNICODE FUNCTIONS
Procedure.s UnicodeCharList(first.U, last.U)
   If first>=0 And first<last
      Protected len.i=last-first+1
      Protected charList.s=Space(len)
      Protected i.i
      For i=0 To len-1
         PokeU(@charlist+i*SizeOf(Character), first+i)
      Next
      
      ProcedureReturn charList
   EndIf
EndProcedure
Procedure.s UChr(code.U)
   If code>=0 And code<65536
      Protected unicodeChar.s=" "
      PokeU(@unicodeChar, code)
      
      ProcedureReturn unicodeChar
   EndIf
EndProcedure
Procedure.s SplitString(s.s, max)
   Protected splittedString.s=""
   While s
      splittedString+Left(s, max)+#CRLF$
      s=Mid(s, max+1)
   Wend
   
   ProcedureReturn splittedString
EndProcedure
;}

#w=800
#h=560
InitSprite()
OpenWindow(#win, 0, 0, #w, #h, "Bitmap Font Generator", #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
SetWindowState(#win, #PB_Window_Maximize)
SmartWindowRefresh(#win, 1)
WindowBounds(#win, #w, #h, #PB_Ignore, #PB_Ignore)
;{/// STATUS
If CreateStatusBar(#status, UseGadgetList(0))
   AddStatusBarField(64)
   AddStatusBarField(350)
   AddStatusBarField(#PB_Ignore)
EndIf
;}
;{/// PREVIEW
If OpenWindowedScreen(WindowID(#win), 0, 0, 256, 256, 0, 0, 0)
   ScrollBarGadget(#scrollX, 0, 0, 0, 0, 0, 0, 0)
   ScrollBarGadget(#scrollY, 0, 0, 0, 0, 0, 0, 0, #PB_ScrollBar_Vertical)
EndIf
;}
;{/// CHAR LIST
If EditorGadget(#editCharList, 0, 0, 0, 0)
   SetGadgetText(#editCharList, SplitString(UnicodeCharList(15, 512), 30))
EndIf
;}
If PanelGadget(#panelParams, 0, 0, 0, 0)
   AddGadgetItem(#panelParams, -1, "Generator")
   ;{/// FONT EDITOR
   Global x=2, y=2, w=53, h=20
   Global w2=198, h2=22
   Global w3=80, h3=22
   Global hg=25
   TextGadget(#PB_Any, x, y+2, w, h, "Texture:")
   ComboBoxGadget(#comboTexture, x+w, y, w2, h2) : y+hg
   AddGadgetItem(#comboTexture, -1, "256 x 256")
   AddGadgetItem(#comboTexture, -1, "512 x 256")
   AddGadgetItem(#comboTexture, -1, "512 x 512")
   AddGadgetItem(#comboTexture, -1, "1024 x 512")
   AddGadgetItem(#comboTexture, -1, "1024 x 1024")
   SetGadgetState(#comboTexture, 2)
   TextGadget(#PB_Any, x, y+2, w, h, "Font:")
   ButtonGadget(#buttonFont, x+w, y, w2, h2, fnt) : y+hg
   TextGadget(#PB_Any, x, y+2, w, h, "Color:")
   CreateColorBox(#imageFontColor, fntColor, w3, h3)
   ButtonImageGadget(#buttonFontColor, x+w, y, w3, h3, ImageID(#imageFontColor)) : y+hg
   TextGadget(#PB_Any, x, y+2, w, h, "Size:")
   SpinGadget(#spinFontSize, x+w, y, w3, h3, 8, 32, #PB_Spin_Numeric) : y+hg
   SetGadgetState(#spinFontSize, fntSize)
   TextGadget(#PB_Any, x, y+2, w, h, "Style:")
   CheckBoxGadget(#checkBold, x+w, y, w2, 16, "Bold") : y+16
   CheckBoxGadget(#checkItalic, x+w, y, w2, 16, "Italic") : y+16
   SetGadgetState(#checkItalic, fntStyle & #PB_Font_Italic)
   SetGadgetState(#checkBold, fntStyle & #PB_Font_Bold)
   ;}
   AddGadgetItem(#panelParams, -1, "Settings")
   ;{///SETTINGS
   x=2
   y=2
   TextGadget(#PB_Any, x, y+2, w, h, "Screen:")
   CreateColorBox(#imageBackColor, colorBack, w3, h3)
   ButtonImageGadget(#buttonBackColor, x+w, y, w3, h3, ImageID(#imageBackColor)) : y+hg
   TextGadget(#PB_Any, x, y+2, w, h, "Grid:")
   ListIconGadget(#listColorGrid, x+w, y, w2, 73, "test", 50, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection)
   SetGadgetAttribute(#listColorGrid, #PB_ListIcon_DisplayMode, #PB_ListIcon_List)
   ForEach colorGrid()
      AddGadgetItem(#listColorGrid, -1, colorGrid()\name, CreateGridBox(colorGrid()\c1, colorGrid()\c2))
   Next   
   ;}
   CloseGadgetList()
EndIf

Repeat
   Global e=WaitWindowEvent(0)
   Global w=EventWindow()
   Global t=EventType()
   
   Select e
      Case #PB_Event_ActivateWindow
      Case #PB_Event_CloseWindow
         Break
      Case #PB_Event_SizeWindow
         ;{/// RESIZE EVENTS
         If w=#win
            Global totalH=WindowHeight(#win)-StatusBarHeight(#status)
            Global panelW=263
            Global panelH=200
            Global panelY=2
            Global panelX=WindowWidth(#win)-panelW
            
            Global screenW=WindowWidth(#win)-panelW-18
            Global screenH=WindowHeight(#win)-StatusBarHeight(#status)-18
            If OpenWindowedScreen(WindowID(#win), 0, 0, screenW, screenH, 0, 0, 0)
               DrawGrid()
               DrawFont()
               DrawPreview()
               InvokeUpdateScreen(0)
               AddWindowTimer(#win, #timerRedrawSelection, 100)
               ResizeGadget(#scrollX, 0, screenH, screenW, 16)
               ResizeGadget(#scrollY, screenW, 0, 16, screenH)
               SetGadgetAttribute(#scrollX, #PB_ScrollBar_Maximum, gridW)
               SetGadgetAttribute(#scrollX, #PB_ScrollBar_Minimum, 0)
               SetGadgetAttribute(#scrollX, #PB_ScrollBar_PageLength, screenW)
               SetGadgetAttribute(#scrollY, #PB_ScrollBar_Maximum, gridH)
               SetGadgetAttribute(#scrollY, #PB_ScrollBar_Minimum, 0)
               SetGadgetAttribute(#scrollY, #PB_ScrollBar_PageLength, screenH)
            EndIf
            ResizeGadget(#editCharList, panelX, panelY, panelW-2, totalH-panelH-5)
            ResizeGadget(#panelParams, panelX, totalH-panelH, panelW, panelH)
         EndIf
         ;}
      Case #PB_Event_Gadget
         ;{/// GADGET EVENTS
         Select EventGadget()
            Case #editCharList
               Global charListNew.s=RemoveString(RemoveString(GetGadgetText(#editCharList), #CR$), #LF$)
               If charList<>charListNew
                  charList=charListNew
                  ;invoke redraw
                  InvokeUpdateScreen(500)
                  InvokeUpdateStatusBar(50)
               EndIf
            Case #buttonFont
               If FontRequester(fnt, fntSize, 0, fntColor, fntStyle)
                  fnt=SelectedFontName()
                  fntSize=SelectedFontSize()
                  fntStyle=SelectedFontStyle()
                  SetGadgetText(#buttonFont, fnt)
                  SetGadgetState(#spinFontSize, fntSize)
                  SetGadgetState(#checkBold, fntStyle & #PB_Font_Bold)
                  SetGadgetState(#checkItalic, fntStyle & #PB_Font_Italic)
                  ;invoke redraw
                  InvokeUpdateScreen(100)
                  InvokeUpdateStatusBar(5)
               EndIf
            Case #buttonFontColor
               Global newColor=ColorRequester(fntColor)
               If newColor>-1
                  fntColor=newColor
                  CreateColorBox(#imageFontColor, fntColor)
                  SetGadgetAttribute(#buttonFontColor, #PB_Button_Image, ImageID(#imageFontColor))
                  ;invoke redraw
                  InvokeUpdateScreen(100)
                  InvokeUpdateStatusBar(50)
               EndIf
            Case #buttonBackColor
               Global newColor=ColorRequester(colorBack)
               If newColor>-1
                  colorBack=newColor
                  CreateColorBox(#imageBackColor, colorBack)
                  SetGadgetAttribute(#buttonBackColor, #PB_Button_Image, ImageID(#imageBackColor))
                  ;invoke redraw
                  InvokeUpdateScreen(100)
                  InvokeUpdateStatusBar(50)
               EndIf
               
            Case #listColorGrid
               If GetGadgetState(#listColorGrid)<>ListIndex(colorGrid())
                  SelectElement(colorGrid(), GetGadgetState(#listColorGrid))
               EndIf
               DrawGrid()
               ;invoke redraw
               InvokeUpdateScreen(50)
               InvokeUpdateStatusBar(5)
            Case #comboTexture
               Select GetGadgetState(#comboTexture)
                  Case 0
                     gridW=256
                     gridH=256
                  Case 1
                     gridW=512
                     gridH=256
                  Case 2
                     gridW=512
                     gridH=512
                  Case 3
                     gridW=1024
                     gridH=512
                  Case 4
                     gridW=1024
                     gridH=1024
               EndSelect
               If gridW<>ImageWidth(#imageGrid) Or gridH<>ImageHeight(#imageGrid)
                  DrawGrid()
                  ;invoke redraw
                  InvokeUpdateScreen(100)
                  InvokeUpdateStatusBar(20)
                  
                  SetGadgetAttribute(#scrollX, #PB_ScrollBar_Maximum, gridW)
                  SetGadgetAttribute(#scrollX, #PB_ScrollBar_Minimum, 0)
                  SetGadgetAttribute(#scrollX, #PB_ScrollBar_PageLength, screenW)
                  SetGadgetAttribute(#scrollY, #PB_ScrollBar_Maximum, gridH)
                  SetGadgetAttribute(#scrollY, #PB_ScrollBar_Minimum, 0)
                  SetGadgetAttribute(#scrollY, #PB_ScrollBar_PageLength, screenH)
                  
               EndIf
               
            Case #spinFontSize
               If fntSize<>GetGadgetState(#spinFontSize)
                  fntSize=GetGadgetState(#spinFontSize)
                  ;invoke redraw
                  InvokeUpdateScreen(500)
                  InvokeUpdateStatusBar(50)
               EndIf
               
            Case #checkBold, #checkItalic
               fntStyle=0
               If GetGadgetState(#checkBold) : fntStyle | #PB_Font_Bold : EndIf
               If GetGadgetState(#checkItalic) : fntStyle | #PB_Font_Italic : EndIf
               ;invoke redraw
               InvokeUpdateScreen(200)
               InvokeUpdateStatusBar(20)
               
            Case #scrollX, #scrollY
               ;refresh image preview
               DrawPreview()
               
            Case #buttonGenerate
               ;invoke redraw
               InvokeUpdateScreen(10)
         EndSelect
         ;}
      Case #PB_Event_Timer
         ;{///TIMER EVENTS
         Select EventTimer()
            Case #timerStatusProgress
               ;refresh statusbar
               UpdateStatusBar()
               
            Case #timerRedrawPreview
               ;refresh image preview
               UpdateScreen()
               
               ;reset timers
               InvokeUpdateScreen()
               InvokeUpdateStatusBar()
            Case #timerRedrawSelection
               ;refresh image preview
               UpdateScreen(#True)
         EndSelect
         ;}
      Case #PB_Event_SysTray
      Case #PB_Event_GadgetDrop
      Default
         ;refresh image preview
         UpdateScreen(#True)
   EndSelect
ForEver
End
Last edited by eddy on Sat Oct 31, 2009 7:09 pm, edited 1 time in total.
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
jamirokwai
Enthusiast
Enthusiast
Posts: 798
Joined: Tue May 20, 2008 2:12 am
Location: Cologne, Germany
Contact:

Re: font bitmap generator (prototype)

Post by jamirokwai »

eddy wrote:Here is the prototype for the bitmap font generator. (for PB 4.40b5)
You can test it on MAC / Linux. I want to check if there's any problem with the windowed screen.
Hi Eddy,

this line does not work: Case #PB_Event_SysTray
#PB_Event_SysTray is not known by Mac OS X

When changing the font or the size, the display won't change. Here is a screenshot of your tool. I changed the font to Baskerville to test.
Image
Regards,
JamiroKwai
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Re: font bitmap generator (prototype)

Post by eddy »

characters visible on screen : 0/0
It didn't load the character list at start of application.
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
jamirokwai
Enthusiast
Enthusiast
Posts: 798
Joined: Tue May 20, 2008 2:12 am
Location: Cologne, Germany
Contact:

Re: font bitmap generator (prototype)

Post by jamirokwai »

eddy wrote:
characters visible on screen : 0/0
It didn't load the character list at start of application.
But how may I get it to load the list at start?
Regards,
JamiroKwai
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Re: font bitmap generator (prototype)

Post by eddy »

Add this code after the line Case #PB_Event_ActivateWindow :

Code: Select all

      ;/// initialize char list
      SetGadgetText(#editCharList, "")
      SetGadgetText(#editCharList, SplitString(UnicodeCharList(15, 512), 30))
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
Post Reply