=begin
  RGSSType Alpha 0.1
  Author: 晴兰 Seiran
  Website: http://seiran.mist.so
  License:
    Copyright (c) 2013, Seiran
    All rights reserved.
    Redistribution and use in source and binary forms, with or without 
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright notice, 
    this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
    this list of conditions and the following disclaimer in the documentation 
    and/or other materials provided with the distribution.
    3. Neither the name of the seiran.mist.so nor the names of its contributors 
    may be used to endorse or promote products derived from this software 
    without specific prior written permission.
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
    POSSIBILITY OF SUCH DAMAGE.
=end
 
#encoding:UTF-8
module SAFX
  module_function
 
  def to_param(a)
    case a when Integer then "L" when String then "p" end
  end
 
  def to_ptr(a)
    case a  when Integer then a when String then [a].pack('p').unpack("L").first end
  end
 
  def api(dll,func)
    lambda{|*args|
       Win32API.new(dll,func,args.map{|x|to_param(x)}, 'i').call(*args)
    }
  end
 
  def to_wc(str, cp = 65001)
    (buf = ""*str.length)[0, 2*api('Kernel32', 'MultiByteToWideChar').call(cp, 
    0, to_ptr(str), -1, buf, buf.length)]
  end
 
  def to_mb(str, cp = 65001)
    (buf = ""* str.length)[0, api('Kernel32', 'WideCharToMultiByte').call(cp, 
    0, to_ptr(str), -1, buf, buf.length, 0, 0)]
  end
 
end
 
class RGSSType
  module API
    FUNC = {}
    HANDLES  = [DL::dlopen('gdi32'), DL::dlopen("KERNEL32"), 
    DL::dlopen("USER32")]
    def self.method_missing(sym, *args)
      FUNC[sym] ||= DL::CFunc.new(
        HANDLES.map{|x| x[sym.to_s] rescue nil}.compact[0] ,
        DL::TYPE_VOIDP, '', :stdcall
      )      
      FUNC[sym].call(args.map{|x| DL::CPtr[x]})
    end
  end
 
  attr_accessor :font
 
  def initialize(font = ::Font.new ,w = 300, h = 300)
    @font = font
    @dc = API.CreateCompatibleDC(0)
    @ptr = DL.malloc(w * h * 4)
    @bitmap = API.CreateBitmap(w, h, 1, 32, @ptr)
    @w, @h = w, h
    DL.free(@ptr)
    resetfont
  end
 
  def resetfont
    API.DeleteObject(@hfont) if @hfont != nil
    API.SelectOBject(@dc, @hold) if @hold != nil
    @hold = nil
    @hfont = nil
  end
 
  def bits
    buf = [].pack("x#{@w * @h * 4}")
    API.GetBitmapBits(@bitmap, buf.size, buf)
    buf
  end
 
  def boolvalue a
    a ? 1 : 0
  end
 
  def dispose
    resetfont
    API.DeleteObject(@bitmap)
    API.ReleaseDC(@dc)
  end
 
  def createfont
    resetfont
    args = [@font.size, 0, 0, 0, 
            @font.bold ? 700 : 400, 
            boolvalue(@font.italic), 
            0,0,
            1, #default_charset
            0,0,4,0,
            SAFX.to_wc(@font.name+"")]
    #                        here^
    @hfont = API.CreateFontW(*args)
    @hold = API.SelectObject(@dc, @hfont)
  end
 
  def getchar8b(a)
    API.GetGlyphIndicesW(@dc, SAFX.to_wc(a+""), 1, (index=[].pack("x4")), 0)
    #                                    here^
    index = index.unpack("L").first
    glyph = [].pack("x24")
    mat   = [0,1,0,0,0,0,0,1].pack("S*")
    len   = API.GetGlyphOutline(@dc, index, 0x85, glyph, 0, 0, mat)
    buf   = [].pack "x#{len}"
    len = API.GetGlyphOutline(@dc, index, 0x85, glyph, len, buf, mat)
    bx, by, ox, oy, cx, cy = glyph.unpack("llllss")
    [buf, bx, by, ox, oy, cx, cy, len]
  end
 
  def char_height(ch)
    u =  getchar8b(ch)
    height = u[5]
  end
 
  def writechar8b(bitmap, ch, cx, cy, color, height = nil)
    u =  getchar8b(ch)
    r,g,b,a=color.red, color.green, color.blue, color.alpha
    return [0, 0] if u[0].size == 0
    colors = 256.times.map{|x|
      Color.new(r * x  * 4 / 256, g * x  * 4 / 256, b * x  * 4 / 256, a)
    }
    i = 0
    height ||= u[0].size / ((u[1] + 3) / 4 * 4)
    v = u[0].unpack("C*")
    u[2].times{|y|
      u[1].times{|x|
         bitmap.set_pixel(x + cx + u[3], cy + height - u[4] + y, colors[v[i]*4])
         i += 1
      }
      i = (i + 3) >> 2 << 2
    }
    [u[5], u[6]]
  end
 
  def writetext(bitmap, text, cx, cy, color)
    createfont
    height = text.split(//).map{|x| char_height(x)}.max
    text.split(//).each{|ch|
      w,h = writechar8b(bitmap, ch, cx, cy, color, height)
      cx += w
    }
  end
end