Print Text with Bitmap Fonts in iff Format

Find quick help here to get you started with Hollywood
Post Reply
deaddisk
Posts: 8
Joined: Thu Apr 28, 2022 6:32 am

Print Text with Bitmap Fonts in iff Format

Post by deaddisk »

Hello,

I saw these cool old school Intro/Demo Remakes in Hollywood. Is there a step by step tutorial for the easiest way avaible, how I can use these

https://bmf.php5.cz/?page=gifs

as font in Hollywood?



Thanks for help and replies! 😃

plouf
Posts: 266
Joined: Sun Feb 04, 2018 11:51 pm
Location: Athens,Greece

Re: Print Text with Bitmap Fonts in iff Format

Post by plouf »

check out in Examples the SinusScroller, it does exactly that
Christos

deaddisk
Posts: 8
Joined: Thu Apr 28, 2022 6:32 am

Re: Print Text with Bitmap Fonts in iff Format

Post by deaddisk »

Thanks for your reply. I mean no scroller, just use these fonts as normal text font without animation. 😃👍🏻

plouf
Posts: 266
Joined: Sun Feb 04, 2018 11:51 pm
Location: Athens,Greece

Re: Print Text with Bitmap Fonts in iff Format

Post by plouf »

Then dont scroll ;-)
Tuis example cut image in brushes and displays it in screen

The general idea for doing this is to cut images of letter, you can do it manual and save it to 26 difffirent iff,
Then load 26 brush with id (imho) 65 A up to 90 = Z
Finaly parse the string you want to display byte by byte and display the specific byte (because if do Asc("A") =65 )

P.s. we always talking for display them in screen/image
If you need to change for example rapagui's font (aka OS's ) is nearly impossible
Christos

deaddisk
Posts: 8
Joined: Thu Apr 28, 2022 6:32 am

Re: Print Text with Bitmap Fonts in iff Format

Post by deaddisk »

Thank you for your detailed feedback. I will take a look at your tips! :)

User avatar
airsoftsoftwair
Posts: 5005
Joined: Fri Feb 12, 2010 2:33 pm
Location: Germany
Contact:

Re: Print Text with Bitmap Fonts in iff Format

Post by airsoftsoftwair »

You could also check out the cracktro Hollywood ports available here. I think they also do these things a lot.

User avatar
airsoftsoftwair
Posts: 5005
Joined: Fri Feb 12, 2010 2:33 pm
Location: Germany
Contact:

Re: Print Text with Bitmap Fonts in iff Format

Post by airsoftsoftwair »

Actually, all those nice retro fonts from https://bmf.php5.cz/?page=gifs inspired me to add a new function designed especially for the purpose of easily using those fonts with Hollywood:

Code: Select all

- New: Added CreateFont() command to construct a custom font from a brush source; you have to pass the
  character dimension as well as a character mapping string; in the brush source all characters must have
  the same size but you can adjust the character width via an optional table tag; CreateFont() can come in
  useful to easily construct fonts from images as they were often used in scene demos and 1980/90s games;
  CreateFont() supports palette brushes as well as brushes with mask or alpha channel; if the source brush
  is a 1-bit palette brush, you will also be able to change the color of the font; otherwise the font is
  treated as a color font that always uses the same color no matter what the current font color is set to;
  CreateFont() is quite flexible and could also be used as a tilemapper; just map each tile to a character
  and then draw the whole tilemap using a single call to TextOut()

jalih
Posts: 265
Joined: Fri Jun 18, 2010 8:08 pm
Location: Finland

Re: Print Text with Bitmap Fonts in iff Format

Post by jalih »

Usually bitmap fonts come as two files: the bitmap and the ".fnt" file.

It's not hard to parse ".fnt" file and make a proper drawing routine. Years ago, I did a version that supported enough functionality to be usable:

Code: Select all

@INCLUDE "../parser/parser.hws"
@INCLUDE "../primitives/HGFbase.hws"
@INCLUDE "../primitives/HGFdraw.hws"

HGFbmf = {}

Function HGFbmf:new(dir, fnt)
  Const #infosym = 100
  Const #fontsym = 101
  Const #sizesym = 102
  Const #boldsym = 103
  Const #italicsym = 104
  Const #charsetsym = 105
  Const #unicodesym = 106
  Const #stretchHsym = 107
  Const #smoothsym = 108
  Const #aasym = 109
  Const #paddingsym = 110
  Const #spacingsym = 111
  Const #commonsym = 112
  Const #lineHeightsym = 113
  Const #basesym = 114
  Const #scaleWsym = 115
  Const #scaleHsym = 116
  Const #pagessym = 117
  Const #packedsym = 118
  Const #pagesym = 119
  Const #idnumsym = 120
  Const #filesym = 121
  Const #charssym = 122
  Const #countsym = 123
  Const #charsym = 124
  Const #xsym = 125
  Const #ysym = 126
  Const #widthsym = 127
  Const #heightsym = 128
  Const #xoffsetsym = 129  
  Const #yoffsetsym = 130 
  Const #xadvancesym = 131 
  Const #chnlsym = 132 
  Const #lettersym = 133
  Const #facesym = 134
  Const #outlinesym = 135
  Const #alphaChnlsym = 136  
  Const #redChnlsym = 137  
  Const #greenChnlsym = 138  
  Const #blueChnlsym = 139  
 
  Local keywords = {}
  keywords[0]  = "info"
  keywords[1]  = "font"
  keywords[2]  = "size"
  keywords[3]  = "bold"
  keywords[4]  = "italic"
  keywords[5]  = "charset"
  keywords[6]  = "unicode"
  keywords[7]  = "stretchH"
  keywords[8]  = "smooth"
  keywords[9]  = "aa"
  keywords[10] = "padding"
  keywords[11] = "spacing"
  keywords[12] = "common"
  keywords[13] = "lineHeight"
  keywords[14] = "base"
  keywords[15] = "scaleW"
  keywords[16] = "scaleH"
  keywords[17] = "pages"
  keywords[18] = "packed"
  keywords[19] = "page"
  keywords[20] = "id"
  keywords[21] = "file"
  keywords[22] = "chars"
  keywords[23] = "count"
  keywords[24] = "char"
  keywords[25] = "x"
  keywords[26] = "y"
  keywords[27] = "width"
  keywords[28] = "height"
  keywords[29] = "xoffset"
  keywords[30] = "yoffset"
  keywords[31] = "xadvance"
  keywords[32] = "chnl"
  keywords[33] = "letter"
  keywords[34] = "face"
  keywords[35] = "outline"
  keywords[36] = "alphaChnl"
  keywords[37] = "redChnl"
  keywords[38] = "greenChnl"
  keywords[39] = "blueChnl"
  keywords[40] =  ""

  Local keysyms = {}
  keysyms[0]  = #infosym
  keysyms[1]  = #fontsym
  keysyms[2]  = #sizesym
  keysyms[3]  = #boldsym
  keysyms[4]  = #italicsym
  keysyms[5]  = #charsetsym
  keysyms[6]  = #unicodesym
  keysyms[7]  = #stretchHsym
  keysyms[8]  = #smoothsym
  keysyms[9]  = #aasym
  keysyms[10] = #paddingsym
  keysyms[11] = #spacingsym
  keysyms[12] = #commonsym
  keysyms[13] = #lineHeightsym
  keysyms[14] = #basesym
  keysyms[15] = #scaleWsym
  keysyms[16] = #scaleHsym
  keysyms[17] = #pagessym
  keysyms[18] = #packedsym
  keysyms[19] = #pagesym
  keysyms[20] = #idnumsym
  keysyms[21] = #filesym
  keysyms[22] = #charssym
  keysyms[23] = #countsym
  keysyms[24] = #charsym
  keysyms[25] = #xsym
  keysyms[26] = #ysym
  keysyms[27] = #widthsym
  keysyms[28] = #heightsym
  keysyms[29] = #xoffsetsym
  keysyms[30] = #yoffsetsym
  keysyms[31] = #xadvancesym
  keysyms[32] = #chnlsym
  keysyms[33] = #lettersym 
  keysyms[34] = #facesym
  keysyms[35] = #outlinesym
  keysyms[36] = #alphaChnlsym
  keysyms[37] = #redChnlsym
  keysyms[38] = #greenChnlsym
  keysyms[39] = #blueChnlsym    
  keysyms[40] = #idsym
  
  Local bmf = {}
  
  Local p = Parser:new()
  p:begin_parse(dir.."/"..fnt, keywords, keysyms)
  ; Parse info block
  p:expect(#infosym)
  bmf.info = {}
  If Not p:accept(#fontsym) Then p:accept(#facesym)
  p:expect(#eqlsym)
  p:expect(#litstrsym)
  bmf.info.font = p:getlitstr()
  p:expect(#sizesym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.info.size = p:getval()
  p:expect(#boldsym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.info.bold = p:getval() 
  p:expect(#italicsym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.info.italic = p:getval()
  p:expect(#charsetsym)
  p:expect(#eqlsym)
  p:expect(#litstrsym)
  bmf.info.charset = p:getlitstr()
  p:expect(#unicodesym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.info.unicode = p:getval() 
  p:expect(#stretchHsym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.info.stretchH = p:getval() 
  p:expect(#smoothsym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.info.smooth = p:getval() 
  p:expect(#aasym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.info.aa = p:getval()
  p:expect(#paddingsym)
  bmf.info.padding = {}
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.info.padding[0] = p:getval()
  p:expect(#comma)  
  p:expect(#numbersym)
  bmf.info.padding[1] = p:getval()
  p:expect(#comma)
  p:expect(#numbersym)
  bmf.info.padding[2] = p:getval()
  p:expect(#comma)
  p:expect(#numbersym)
  bmf.info.padding[3] = p:getval()
  p:expect(#spacingsym)
  bmf.info.spacing = {}
  p:expect(#eqlsym)
  p:expect(#numbersym)  
  bmf.info.spacing[0] = p:getval()
  p:expect(#comma)
  p:expect(#numbersym)  
  bmf.info.spacing[1] = p:getval()
  If p:accept(#outlinesym)
    p:expect(#eqlsym)
    p:expect(#numbersym)
  EndIf   
  ; Parse common block
  p:expect(#commonsym)
  bmf.common = {}
  p:expect(#lineHeightsym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.common.lineHeight = p:getval()
  p:expect(#basesym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.common.base = p:getval()
  p:expect(#scaleWsym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.common.scaleW = p:getval()
  p:expect(#scaleHsym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.common.scaleH = p:getval()
  p:expect(#pagessym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.common.pagessym = p:getval()
  p:expect(#packedsym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.common.packed = p:getval()
  If p:accept(#alphaChnlsym)
    p:expect(#eqlsym)
    p:expect(#numbersym)
  EndIf   
  If p:accept(#redChnlsym)
    p:expect(#eqlsym)
    p:expect(#numbersym)
  EndIf
  If p:accept(#greenChnlsym)
    p:expect(#eqlsym)
    p:expect(#numbersym)
  EndIf   
  If p:accept(#blueChnlsym)
    p:expect(#eqlsym)
    p:expect(#numbersym)
  EndIf   
  ; Parse page block
  bmf.page = {}
  bmf.brush = {}
  bmf.img = {}
  While p:accept(#pagesym)
    p:expect(#idnumsym)
    p:expect(#eqlsym)
    p:expect(#numbersym)
    Local id = p:getval()
    p:expect(#filesym)
    p:expect(#eqlsym)
    p:expect(#litstrsym)
    bmf.page[id] = p:getlitstr()
    bmf.brush[id] = LoadBrush(Nil, dir.."/"..bmf.page[id], { Hardware = True, LoadAlpha = True } )
    bmf.img[id] = Image:new(bmf.brush[id])
  Wend
  ; Parse chars block
  p:expect(#charssym)
  bmf.chars = {}
  p:expect(#countsym)
  p:expect(#eqlsym)
  p:expect(#numbersym)
  bmf.chars.count = p:getval()
  ; Parse character data
  bmf.char = {}
  While p:accept(#charsym)
    p:expect(#idnumsym)
    p:expect(#eqlsym)
    p:expect(#numbersym)      
    Local id = p:getval()
    p:expect(#xsym)
    p:expect(#eqlsym)
    p:expect(#numbersym)      
    Local x = p:getval()
    p:expect(#ysym)
    p:expect(#eqlsym)
    p:expect(#numbersym)      
    Local y = p:getval()
    p:expect(#widthsym)
    p:expect(#eqlsym)
    p:expect(#numbersym)      
    Local width = p:getval()
    p:expect(#heightsym)
    p:expect(#eqlsym)
    p:expect(#numbersym)      
    Local height = p:getval()
    Local xoffset
    p:expect(#xoffsetsym)
    p:expect(#eqlsym)
    If p:accept(#minus)
      p:expect(#numbersym)      
      xoffset = -p:getval()
    Else
      p:expect(#numbersym)      
      xoffset = p:getval()
    EndIf
    Local yoffset     
    p:expect(#yoffsetsym)
    p:expect(#eqlsym)
    If p:accept(#minus) 
      p:expect(#numbersym)      
      yoffset = -p:getval()
    Else
      p:expect(#numbersym)      
      yoffset = p:getval()
    EndIf 
    p:expect(#xadvancesym)
    p:expect(#eqlsym)
    p:expect(#numbersym)      
    Local xadvance = p:getval()
    p:expect(#pagesym)
    p:expect(#eqlsym)
    p:expect(#numbersym)      
    Local page = p:getval()
    p:expect(#chnlsym)
    p:expect(#eqlsym)
    p:expect(#numbersym)      
    Local chnl = p:getval()
    Local letter
    If p:accept(#lettersym)
      p:expect(#eqlsym)
      p:expect(#litstrsym)      
      letter = p:getlitstr()
    Else
      letter = chr(id)
    EndIf

    bmf.char[letter] = {}
    bmf.char[letter].pos = Point:new( { x = x, y = y } )
    bmf.char[letter].r = Rect:new( { min = Point:new(), max = { x = width, y = height } } )
    bmf.char[letter].offset = Point:new( { x = xoffset, y = yoffset } )    
    bmf.char[letter].advance = Point:new( { x = xadvance, y = 0 } )
    bmf.char[letter].page = page      
  Wend
  
  p:end_parse()
  
  SetMetaTable(bmf, self)
  self.__index = self

  Return(bmf)
   
EndFunction


Function HGFbmf:draw(buffer, str, x, y)
  Local cursor = Point:new( { x = x, y = y } )

  For Local i = 0 to StrLen(str)-1
    Local ch = MidStr(str, i, 1)
    If HaveItem(self.char, ch)
      buffer:drawImg((self.char[ch].r:addpt(cursor:add(self.char[ch].offset)):clip(buffer.r)), self.img[self.char[ch].page], self.char[ch].pos )
      cursor = cursor:add(self.char[ch].advance)
    EndIf 
  Next

EndFunction

;
; This is only for testing purposes.
;
;buffer = HGFdraw:new()
;b = HGFbmf:new(".", "font.fnt")
;b:draw(buffer, "a = b:0", 100, 100)
;WaitLeftMouse()
It's included in my old HGF library and requires support routines from the library.

Post Reply