Bitmap Font?

Started by Zexion, January 07, 2014, 03:50:11 pm

Previous topic - Next topic

Zexion

I've seen scripts that include bitmaps with numbers and font used in the script and I was wondering how I would go about using a complete bitmap font. Can someone make a tutorial or explain to me how I would do this? My reason for this is to include commercial styled fonts without actually installing the commercial fonts on the system. It also makes using custom fonts easier by not only bypassing the whole installing a custom font bit but eliminating the problems that could arise from it.

KK20

What exactly do you need help with? There's a really basic script made by Paradox and Trickster that helps you with that.

Here's an edited one in the Fire Emblem Engine to get an idea of how to improve it:
Spoiler: ShowHide

#==============================================================================
# Image Fonts
#------------------------------------------------------------------------------
# Author   : Paradox (& Trickster)
# Revision : 1
# Date     : January 2, 2007
#==============================================================================
# ** Bitmap
#------------------------------------------------------------------------------
#  This class is a type pertaining to images.
#==============================================================================
class Bitmap
  NUM_WIDTHS = {
      'FE7_Text' =>       [8,8,8,8,8,8,8,8,8,8],
      'FE7_Text_Info' =>  [7,7,7,7,7,7,7,7,7,7],
      'FE7_Text_Info2' => [8,8,8,8,8,8,8,8,8,8],
      'FE7_Convo' =>      [6,4,6,6,7,6,6,6,6,6],
  }
 
  #--------------------------------------------------------------------------
  # * Text Width
  #--------------------------------------------------------------------------
  def self.text_width(text, font = 'FE7_Text', color = 'White', dash = false)
    test_bmp = Bitmap.new(16,16)
    test_bmp.bitmap_font(0,0,text, font, color, dash)
    width = $placement
    test_bmp.dispose
    return width
  end
  #--------------------------------------------------------------------------
  # * Bitmap Font (Integer)
  #  modifies the bitmap font placement based on the text-number's value
  #--------------------------------------------------------------------------
  def bitmap_font_int(*args)
    x = args[0]
    text = args[2]
    font = (args[3].nil? ? 'FE7_Text' : args[3])
    text = text.to_s
    if text.is_a_number?
      num = text.to_i
      if num < 0
        x -= 7
        num *= -1
      end
      last_digit = num % 10
      x -= NUM_WIDTHS[font][last_digit]
      num /= 10
      while num > 0
        last_digit = num % 10
        x -= NUM_WIDTHS[font][last_digit]
        num /= 10
      end
      args[0] = x
    end
    bitmap_font(*args)
  end
  #--------------------------------------------------------------------------
  # * Bitmap Font
  #  x    :  the x of the starting letter
  #  y    :  the y of the starting letter
  #  text :  the text to display
  #  font :  the font to render (optional)
  #  color:  the font color, adjusts filename (optional)
  #--------------------------------------------------------------------------
  def bitmap_font(x, y, text, font = 'FE7_Text', color = 'White', dash = false)
    text = text.to_s
    colorless_font_name = font
    if ['FE7_Text', 'FE7_TextL'].include?(font)
      large_text = (font == 'FE7_TextL')
      colorless_font_name = 'FE7_Text'
      # Create the font
      font = 'FE7_Text' + '_' + color
      font_image = RPG::Cache.font(font)
      $placement = 0
      # Loop through each letter.
      text.length.times do |index|
        # Determine sizing.
        char_width  = 8 #font_image.width  / 26
        char_height = 14 #font_image.height / 3
        # Get the Byte.
        byte = text[index]
        # Get Letter
        letter = byte.chr
        # If it is a letter
        if letter =~ /[A-Z]/
          iX = (byte - 65) * char_width
          iY = char_height * (large_text ? 3 : 1)
          if large_text or color == 'Combat'
            char_width = 8
          else
            if letter == 'W' or letter == 'M' or letter == 'V' or
                letter == 'Q' or letter == 'X' or letter == 'Y' or letter == 'T'
              char_width = 7
            elsif letter == 'I' or letter == 'L'
              char_width = 5
            else
              char_width = 6
            end
          end
        elsif letter =~ /[a-z]/
          iX =(byte - 97) * char_width
          iY = 0
          if letter == 'a' or letter == 'm' or letter == 'v' or
              letter == 'w' or letter == 'x'
            char_width = 7
          elsif letter == 'f' or letter == 'j' or letter == 'r' or letter == 't'
            char_width = 5
          elsif letter == 'i' or letter == 'l'
            char_width = 3
          else
            char_width = 6
          end
        # If it is a number
        elsif letter =~ /[0-9]/
          iX = letter.to_i * char_width
          iY = 2 * char_height
          char_width = NUM_WIDTHS[colorless_font_name][letter.to_i]
        # Otherwise it's a symbol
        else
          unless letter == ' ' or letter == ''
            # Define the order
            order = ['.', ',', '$', '!', '(', ')', '-', '/', '\\', '?', ';',
                ':', '#', '&', '"', "'", '+']
            begin
              iX = (order.index(letter) + 10) * char_width
            rescue
              raise ("Unrenderable character: '" + letter +
                  "' in string:\n'" + text + "'")
            end
            iY = 2 * char_height
          end
          if ['.', ',', ';', ':', "'"].include?(letter)
            char_width = 3
          elsif letter == '(' or letter == ')'
            char_width = 5
          elsif letter == '"' or letter == '!'
            char_width = 5
          elsif letter == '#'
            char_width = 6
          elsif letter == '-' or letter == '?'
            if color == 'Combat'
              char_width = 8
            else
              char_width = 7
            end
            #$placement += 1
          elsif letter == '$' # Equipped/Experience 'E'
            char_width = 8
          elsif letter == '+'
            char_width = 8
          else
            char_width = 7
          end
        end
        (letter == ' ' or letter == "") ? (char_width = 4) : nil
        # If it's not a space, draw it
        if letter != ' ' and letter != ""
          rect = Rect.new(iX, iY, char_width, char_height)
          # Blit it to the screen
          self.blt($placement + x, y, font_image, rect)
        end
        $placement += char_width - 1
        $placement += 1 if (letter =~ /[A-Z]/ and (
            large_text or color == 'Combat'))
        $placement += 1 if (letter =~ /[0-9]/)
        $placement += 1 if (letter == '+')
        $placement += 1 if (letter == '?' and color == 'Combat')
        $placement += 1 if (letter == '-' and (dash or color == 'Combat'))
        $placement += 2 if (letter == '-' and !(dash or (color == 'Combat')))
      end
    end
    if ['FE7_Text_Info', 'FE7_Text_Info2'].include?(font)
      # Create the font
      font_image = RPG::Cache.font('FE7_Text_Info')
      $placement = 0
      # Loop through each letter.
      text.length.times do |index|
        # Determine sizing.
        char_width  = 8 #font_image.width  / 26
        char_height = 14 #font_image.height / 3
        # Get the Byte.
        byte = text[index]
        # Get Letter
        letter = byte.chr
        # If it is a letter
        if letter =~ /[A-Z]/
          iX = (byte - 65) * char_width
          iY = char_height * (large_text ? 3 : 1)
          if large_text
            char_width = 8
          else
            if letter == 'W' or letter == 'M' or letter == 'V' or
                letter == 'Q' or letter == 'X' or letter == 'Y' or letter == 'T'
              char_width = 7
            elsif letter == 'I' or letter == 'L'
              char_width = 5
            else
              char_width = 6
            end
          end
        elsif letter =~ /[a-z]/
          iX =(byte - 97) * char_width
          iY = 0
          if letter == 'a' or letter == 'm' or letter == 'v' or
              letter == 'w' or letter == 'x'
            char_width = 7
          elsif letter == 'f' or letter == 'j' or letter == 'r' or letter == 't'
            char_width = 5
          elsif letter == 'i' or letter == 'l'
            char_width = 3
          else
            char_width = 6
          end
        # If it is a number
        elsif letter =~ /[0-9]/
          iX = letter.to_i * char_width
          iY = 2 * char_height
          char_width = NUM_WIDTHS[colorless_font_name][letter.to_i]
        # Otherwise it's a symbol
        else
          unless letter == ' ' or letter == ''
            # Define the order
            order = ['.', ',', '$', '!', '(', ')', '-', '/', '\\', '?', ';',
                ':', '#', '&', '"', "'", '+']
            iX = (order.index(letter) + 10) * char_width
            iY = 2 * char_height
          end
          if ['.', ',', ';', ':', "'"].include?(letter)
            char_width = 3
          elsif letter == '(' or letter == ')'
            char_width = 5
          elsif letter == '"' or letter == '!'
            char_width = 5
          elsif letter == '#'
            char_width = 6
          elsif letter == '-' or letter == '?'
            if color == 'Combat'
              char_width = 8
            else
              char_width = 7
            end
            #$placement += 1
          elsif letter == '$' # Equipped/Experience 'E'
            char_width = 8
          else
            char_width = 7
          end
        end
        (letter == ' ' or letter == "") ? (char_width = 4) : nil
        # If it's not a space, draw it
        if letter != ' ' and letter != ""
          rect = Rect.new(iX, iY, char_width, char_height)
          # Blit it to the screen
          self.blt($placement + x, y, font_image, rect)
        end
        $placement += char_width - 1
        $placement += 1 if (letter =~ /[A-Z]/ and large_text)
        $placement += 1 if (letter =~ /[0-9]/)
        $placement += 1 if (letter == '?' and color == 'Combat')
        $placement += 1 if (letter == '-' and (dash or color == 'Combat'))
        $placement += 2 if (letter == '-' and !(dash or (color == 'Combat')))
      end
    end
    if font == 'FE7_Convo'
      # Create the font
      font = 'FE7_Convo' + '_' + color
      font_image = RPG::Cache.font(font)
      $placement = 0
      # Loop through each letter.
      text.length.times do |index|
        # Determine sizing.
        char_width  = 8 #font_image.width  / 26
        char_height = 16 #font_image.height / 3
        # Get the Byte.
        byte = text[index]
        # Get Letter
        letter = byte.chr
        # If it is a letter
        if letter =~ /[A-Z]/
          iX = (byte - 65) * char_width
          iY = char_height
          if ['M', 'W', 'X'].include?(letter)
            char_width = 8
          elsif ['Q', 'S'].include?(letter)
            char_width = 7
          elsif letter == 'I'
            char_width = 4
          else
            char_width = 6
          end
        elsif letter =~ /[a-z]/
          iX =(byte - 97) * char_width
          iY = 0
          if letter == 'g'
            char_width = 7
          elsif ['a', 'm', 'v', 'w', 'x'].include?(letter)
            char_width = 6
          elsif letter == 'r' or letter == 't'
            char_width = 4
          elsif letter == 'j'
            char_width = 3
          elsif letter == 'i' or letter == 'l'
            char_width = 2
          else
            char_width = 5
          end
        # If it is a number
        elsif letter =~ /[0-9]/
          iX = letter.to_i * char_width
          iY = 2 * char_height
          char_width = NUM_WIDTHS[colorless_font_name][letter.to_i]
        # Otherwise it's a symbol
        else
          unless letter == ' ' or letter == ''
            # Define the order
            order = ['.', ',', '$', '!', '(', ')', '-', '/', '\\', '?', ';',
                ':', '#', '&', '"', "'", '+', '%']
            if !order.include?(letter)
              next
            end
            iX = (order.index(letter) + 10) * char_width
            iY = 2 * char_height
          end
          if ['.', ',', ';', ':', "'"].include?(letter)
            char_width = 2
          elsif ['!'].include?(letter)
            char_width = 3
          elsif ['-', '(', ')', '"'].include?(letter)
            char_width = 4
          elsif [].include?(letter)
            char_width = 5
          elsif letter == '#'
            char_width = 6
          elsif ['%', '+', '$'].include?(letter) # $ = Equipped/Experience 'E'
            char_width = 8
          else
            char_width = 7
          end
        end
        char_width = 4 if (letter == ' ' or letter == "")
        # If it's not a space, draw it
        if letter != ' ' and letter != ""
          rect = Rect.new(iX, iY, char_width, char_height)
          # Blit it to the screen
          self.blt($placement + x, y, font_image, rect)
        end
        $placement += char_width
        #$placement += 1 if (letter =~ /[A-Z]/ and large_text)
        #$placement += 1 if (letter =~ /[0-9]/)
        #$placement += 1 if (letter == '-' and (dash or color == 'Combat'))
        #$placement += 2 if (letter == '-' and !(dash or (color == 'Combat')))
      end
    end
    if font == 'FE7_Reel'
      # Create the font
      font = 'FE7_Reel' + '_' + color
      font_image = RPG::Cache.font(font)
      $placement = 0
      base_width = 16
      # Loop through each letter.
      text.length.times do |index|
        # Determine sizing.
        char_width  = 12 #font_image.width  / 26
        char_height = 32 #font_image.height / 3
        # Get the Byte.
        byte = text[index]
        # Get Letter
        letter = byte.chr
        # If it is a letter
        if letter =~ /[A-Z]/
          iX = (byte - 65) * base_width
          iY = char_height
        elsif letter =~ /[a-z]/
          iX =(byte - 97) * base_width
          iY = 0
        end
        char_width = 6 if (letter == ' ' or letter == "")
        # If it's not a space, draw it
        unless (letter == ' ' or letter == "")
          rect = Rect.new(iX, iY, base_width, char_height)
          # Blit it to the screen
          self.blt($placement + x, y, font_image, rect)
        end
        $placement += char_width
      end
    end
    if font == 'FE7_Reel2'
      # Create the font
      font_image = RPG::Cache.font(font)
      $placement = 0
      base_width = 16
      # Loop through each letter.
      text.length.times do |index|
        # Determine sizing.
        char_width  = 16 #font_image.width  / 26
        char_height = 24 #font_image.height / 3
        # Get the Byte.
        byte = text[index]
        # Get Letter
        letter = byte.chr
        # If it is a letter
        if letter =~ /[A-Z]/
          iX = (byte - 65) * char_width
          iY = char_height
          if ['I'].include?(letter)
            char_width = 11
          elsif ['P', 'S'].include?(letter)
            char_width = 12
          elsif ['B', 'G', 'L', 'T', 'Z'].include?(letter)
            char_width = 13
          elsif ['C', 'O', 'N', 'R'].include?(letter)
            char_width = 14
          elsif ['A', 'D', 'E', 'F', 'H',
                'J', 'K', 'M', 'U', 'V'].include?(letter)
            char_width = 15
          elsif ['Q', 'W', 'X'].include?(letter)
            char_width = 16
          end
        elsif letter =~ /[a-z]/
          iX =(byte - 97) * char_width
          iY = 0
          if ['l', 's'].include?(letter)
            char_width = 6
          elsif ['c', 'e', 'i', 'r', 't'].include?(letter)
            char_width = 7
          elsif ['a', 'b', 'd', 'f', 'h',
                'j', 'k', 'n', 'o', 'y'].include?(letter)
            char_width = 8
          elsif ['u'].include?(letter)
            char_width = 9
          elsif ['q', 'g', 'v', 'z'].include?(letter)
            char_width = 10
          elsif ['p', 'x'].include?(letter)
          #elsif ['x'].include?(letter)
            char_width = 11
          elsif ['w'].include?(letter)
          #elsif ['p', 'w'].include?(letter)
            char_width = 12
          elsif ['m'].include?(letter)
            char_width = 14
          end
        end
        if ['K', 'R', 'T', 'f', 'g', 'j'].include?(letter)
          $placement -= 1
        elsif ['p'].include?(letter)
          $placement -= 3#2
        end
        char_width = 4 if (letter == ' ' or letter == "")
        # If it's not a space, draw it
        unless (letter == ' ' or letter == "")
          rect = Rect.new(iX, iY, base_width, char_height)
          # Blit it to the screen
          self.blt($placement + x, y, font_image, rect)
        end
        $placement += char_width
      end
    end
    if ['FE7_Chapter', 'FE7_Chapter_Data'].include?(font)
      # Create the font
      font_image = RPG::Cache.font(font)
      $placement = 0
      base_width = 16
      # Loop through each letter.
      text.length.times do |index|
        # Determine sizing.
        char_width  = 16 #font_image.width  / 26
        char_height = 16 #font_image.height / 3
        # Get the Byte.
        byte = text[index]
        # Get Letter
        letter = byte.chr
        # If it is a letter
        if letter =~ /[A-Z]/
          iX = (byte - 65) * char_width
          iY = char_height
          case letter
          when 'I'
            char_width = 5
          when 'P', 'S'
            char_width = 7
          when 'L', 'N', 'O', 'U'
            char_width = 9
          when 'H', 'K', 'M'
            char_width = 10
          when 'W'
            char_width = 13
          when 'E', 'J', 'Q', 'V', 'X', 'Y', 'Z' # Unknown
            char_width = 8
          else
            char_width = 8
          end
        elsif letter =~ /[a-z]/
          iX =(byte - 97) * char_width
          iY = 0
          case letter
          when 'i', 'l', 't'
            char_width = 4
          when 'f', 'r'
            char_width = 5
          when 'b', 'd', 'g', 'h', 'k', 'n'
            char_width = 7
          when 'w'
            char_width = 8
          when 'm'
            char_width = 9
          when 'j', 'q', 'y', 'z' # Unknown
            char_width = 6
          else
            char_width = 6
          end
        # If it is a number
        elsif letter =~ /[0-9]/
          iX = letter.to_i * char_width
          iY = 2 * char_height
          case letter
          when '7'
            char_width = 7
          else
            char_width = 6
          end
        # Otherwise it's a symbol
        else
          unless letter == ' ' or letter == ''
            # Define the order
            order = ['.', ',', '$', '!', '(', ')', '-', '/', '\\', '?', ';',
                ':', '#', '&', '"', "'", '+', '%']
            if !order.include?(letter)
              next
            end
            iX = (order.index(letter) + 10) * base_width
            iY = 2 * char_height
          end
          if ["'"].include?(letter)
            char_width = 3
          else
            char_width = 6
          end
        end
        char_width = 3 if (letter == ' ' or letter == "")
        # If it's not a space, draw it
        unless (letter == ' ' or letter == "")
          rect = Rect.new(iX, iY, base_width, char_height)
          # Blit it to the screen
          self.blt($placement + x, y, font_image, rect)
        end
        $placement += char_width
      end
    end
  end
end

And these are a couple of the font files used by it.
Spoiler: ShowHide

FE7_Text


FE7_Convo


Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!

Zexion

I just needed something to work with. I didn't know where to find a nice script and I also wanted someone to explain how to use it. Thanks for the help though! The post explains what I needed to know and I'll try out this script in a bit :D

Blizzard

Yes, yes! Trickster's script, that was the one I was thinking of. I couldn't remember who wrote it. I actually made one myself, but I would have to tear it out of LL4. xD
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

KK20

It's just a shame that it has to use Bitmap#blt for every single character. :\

Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!

ForeverZer0

Quote from: Zexion on January 07, 2014, 03:50:11 pm
My reason for this is to include commercial styled fonts without actually installing the commercial fonts on the system. It also makes using custom fonts easier by not only bypassing the whole installing a custom font bit but eliminating the problems that could arise from it.


Was why I got the idea to write this little script this morning.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

sekiraze

could the fireemblem script work with your resolution script? so the lines are longer?

Zexion

I don't think so... it is used to make use of fonts that are saved on a picture file rather that a .ttf file. Doesn't really have any other effect on the window itself.

sekiraze

ow man ._. all i want is longer lines, i just do not want to make the textbox smaller. i want to believe  :negative: