Ancurio / mkxp

Free Software implementation of the Ruby Game Scripting System (RGSS)
GNU General Public License v2.0
532 stars 140 forks source link

Some (maybe) helpful font size stuff! #223

Open KilloZapit opened 5 years ago

KilloZapit commented 5 years ago

Hi! I wanted to share this a while ago, but wasn't sure if this program was still being actively developed. But I decided I might as well! Anyway, while working on my own little RPG Maker VX Ace game, I have been making it with mkxp support in mind. I noticed that there were issues with font sizes and such (and I am pretty sure there still are), which sort of bugged me for a while but I actually found a kind of work around for it! I ended up writing a little ruby script:

# Allows setting the size of fonts using 'px' units 
# (kinda anyway, not sure if it's 100% accurate to how px units work)
# To do this set a font's size to a string with a number and px at the end like "18px".
# Also works with Font.default_size
# Should size diffrently shaped fonts to be about the same.
# Also should kinda fix mkxp sizing fonts in a wacky way.

class Font

  alias_method :set_size, :size=
  def size=(value)
    if value.is_a?(String)
      if value.downcase =~ /(\d+)\s*px/
        value = self.font_pixel_size($1.to_i)
      else
        value = value.to_i
      end
    end
    set_size(value)
  end

  def font_pixel_size(px)
    table = Font.font_size_table(self.name)
    key = table.keys.min_by{|x| (px-x).abs}
    return table[key]
  end

  class << self

    alias_method :set_default_size, :default_size=
    def default_size=(value)
      # Make a temp font and pass the size to it to figure out the proper size.
      tmpfnt = Font.new
      tmpfnt.size = value
      set_default_size(tmpfnt.size)
    end

    def font_size_table(name)
      if table = ((@size_table ||= {})[name])
        return table
      end
      table = {}
      i = 1
      # We need a bitmap for the .text_size method.
      tmpbitmap = Cache.empty_bitmap
      tmpbitmap.font = Font.new(name)
      loop do
        break if i > 100
        begin
          tmpbitmap.font.set_size(i)
        rescue
          i += 1
          next
        end
        # Pixel size of capital M, width or height what ever is lower
        key = [tmpbitmap.text_size('M').width, tmpbitmap.text_size('M').height].min
        unless table[key]
          #puts name.to_s + ': ' + key.to_s + ' = ' + i.to_s
          table[key] = i
        end
        i += 1
      end
      tmpbitmap.dispose
      @size_table[name] = table
    end

  end

end

It basically creates a hash table to compare font sizes with the actual pixel size. This might be a helpful tool for tracking down the possible factors making mkxp not render fonts exactly the same perhaps? It's not really a direct solution to the problem, but it might be a good way to more rigorously test how the numbers compare between the different versions of game.exe and mkxp. Might be more helpful to compare the width and height rather then whatever one is smaller like I do, not sure.

I doubt anyone really cares, but hey someone may find it helpful, either to debug mkxp or just to use in their own game, so why not post it here?

Edit: Thought I would double check but it looks to me like the font size in VX Ace at least is equal to the vertical height of the em box (approximated by the result of .text_size for the letter 'M') in pixels? Might depend on the font though. It may simply be that VX Ace just doesn't use point units for fonts and mkxp does.

Edit 2: But in mkxp, when I look at the width and height of the fonts in pixels, the comparable height for the equivalent width is muuuuch different on some fonts, even if they look the same to me... Curiouser and curiouser... How deep will this rabbit hole go?