じ☆ve冰风 发表于 2024-4-19 17:15:37

【正式发布】RM BitmapCanvas 2D绘图插件

不依赖SEP,插入默认工程应该就可以使用
提供20个绘图指令,无论如何应该够用了

Q&A:
Q:这个脚本能用来干什么?
A:绘制异型血槽(如环状)、绘制能力雷达(六边形战士)、绘制渐变转场中的渐变分隔线、异型透视窗格、等等……
Q:绘图指令具体如何调用?
A:参见脚本前面的说明。
Q:能用虚线绘制矩形和直线以外的形状吗?
A:不能。
Q:为什么可填充的形状中不包括矩形?
A:参见Bitmap#fill_rect,如果你使用RGD或者SEP Core那么还有Bitmap#gradient_fill_rect
Q:我想用平行四边形切一个位图传送怎么办?默认只有Bitmap#blt,而你这个插件也只能用正多边形切正方形或者菱形?
A:请找到四边形的四个顶点,然后调用blt_polygon,所有平行四边形都是多边形的一种。
Q:我的位图传送后被切边了,不完整?
A:只有用位图填充,即fill系指令时,你给的位图会被插件自动重复成图案以保证填满。仅单纯的传送不会复制位图,如果你的位图比传送的区域小,尝试使用填充指令而不是传送指令,或者你看看是不是参照点没有写对导致传歪了。
Q:渐变的效率怎么样?
A:肯定是不如GDI+,但是比draw_text快,反正你用足够了。

RUBY 代码
#==============================================================================
# ■ 位图画布处理核心 v1.1 by SailCat
#------------------------------------------------------------------------------
#   方法:本脚本插入Main之前使用
#   依赖:无
#   版本:v1.1 (Build 221121)
#   效果:
#   1. 可以用简单指令在位图对象上绘制图形,可以绘制从直线到封闭曲线的15种图形
#   2. 可以用简单指令在位图对象上叠加以不同形状(共5种)剪裁的其他位图
#   配置:画笔线形的配置
#   冲突:无
#   说明:
#   1. 绘制直线:
#      draw_line(起始x, 起始y, 结束x, 结束y, 颜色, 线形)
#   2. 绘制矩形(空心):
#       a) draw_rect(左上x, 左上y, 长, 宽, 颜色, 线形)
#       b) draw_rect(矩形, 颜色, 线形)
#   3. 绘制渐变色直线:
#      gradient_draw_line(起始x, 起始y, 结束x, 结束y, 颜色1, 颜色2)
#   4. 绘制路径(连续直线):
#      draw_path(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 颜色)
#   5. 绘制多边形(连续封闭直线):
#      draw_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 颜色)
#   6. 绘制正多边形:
#      draw_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 颜色)
#   7. 绘制椭圆:
#      draw_ellipse(圆心x, 圆心y, 半横径,半纵径, 颜色)
#   8. 绘制圆:
#      draw_circle(圆心x, 圆心y, 半径,颜色)
#   9. 绘制曲线:
#      draw_curve(起始x, 起始y, 中继点Ax, 中继点Ay, 中继点Bx, 中继点By[,
#          中继点Cx, 中继点Cy[, ...]], 结束x, 结束y, 颜色)
#   10. 绘制封闭曲线:
#      draw_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By,
#          点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]],
#          颜色)
#   11.填涂多边形:
#       a) fill_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 边框颜色[,
#          填充颜色1[, 填充颜色2[, 渐变方向]]])
#       b) fill_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 边框颜色,
#          填充位图[, 不透明度])
#   12.填涂正多边形:
#       a) fill_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 边框颜色[,
#          填充颜色1[, 填充颜色2[, 渐变方向]]])
#       b) fill_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 边框颜色,
#          填充位图[, 不透明度])
#   13.填涂椭圆:
#       a) fill_ellipse(圆心x, 圆心y, 半横径,半纵径, 边框颜色[, 填充颜色1[,
#          填充颜色2[, 渐变方向]]])
#       b) fill_ellipse(圆心x, 圆心y, 半横径,半纵径, 边框颜色, 填充位图[,
#          不透明度])
#   14.填涂圆:
#       a) fill_circle(圆心x, 圆心y, 半径,边框颜色[, 填充颜色1[, 填充颜色2[,
#          渐变方向]]])
#       b) fill_circle(圆心x, 圆心y, 半径,边框颜色, 填充位图[, 不透明度])
#   15.填涂封闭曲线:
#       a) fill_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By,
#          点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]],
#          边框颜色[, 填充颜色1[, 填充颜色2[, 渐变方向]]])
#       b) fill_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By,
#          点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]],
#          边框颜色, 填充位图[, 不透明度])
#   16.传送多边形:
#      blt_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 源位图,
#          参考点1x, 参考点1y[, 不透明度])
#   17.传送正多边形:
#      blt_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 源位图, 参考心x,
#          参考心y[, 不透明度])
#   18.传送椭圆:
#      blt_ellipse(圆心x, 圆心y, 半横径,半纵径, 源位图, 参考心x, 参考心y[,
#          不透明度])
#   19.传送圆:
#      blt_circle(圆心x, 圆心y, 半径,源位图, 参考心x, 参考心y[, 不透明度])
#   20.传送封闭曲线:
#      blt_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By,
#          点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]],
#          源位图, 参考点1x, 参考点1y[, 不透明度])
#==============================================================================
#==============================================================================
# ■ SailCat's 插件公用
#==============================================================================
module SailCat
#--------------------------------------------------------------------------
# ● 脚本配置区
#--------------------------------------------------------------------------
module Canvas_Config
    CANVAS_LINE_DOTTED =                # 点线画笔
    CANVAS_LINE_DASHED =          # 短虚线画笔
    CANVAS_LINE_LONGDASH = # 长虚线画笔
    CANVAS_LINE_DASHDOT = # 点划线画笔
    CANVAS_LINE_BROKEN =             # 散点画笔
end
end

#==============================================================================
# ■ Bitmap
#==============================================================================
class Bitmap
includeSailCat::Canvas_Config
#--------------------------------------------------------------------------
# ● 常量
#--------------------------------------------------------------------------
CANVAS_LINE_SOLID =                      # 实心画笔,该常量禁止修改配置
#--------------------------------------------------------------------------
# ● 绘制直线
#   x1 : 起始的 X 坐标
#   y1 : 起始的 Y 坐标
#   x2 : 结束的 X 坐标
#   y2 : 结束的 Y 坐标
#   color : 直线的颜色 (Color)
#   style : 直线的线型
#--------------------------------------------------------------------------
def draw_line(x1, y1, x2, y2, color, style = CANVAS_LINE_SOLID)
    return set_pixel(x1, y1, color)if x1 == x2 and y1 == y2
    dx = (x2 - x1).abs
    dy = (y2 - y1).abs
    x = x1
    y = y1
    rx = x2 - x10
    ry = y2 - y10
    b_index = 0
    b_size = style.size
    if dx == 0and style == CANVAS_LINE_SOLID
      fill_rect(x1, .min, 1, dy + 1, color)
    elsif dy == 0and style == CANVAS_LINE_SOLID
      fill_rect(.min, y1, dx + 1, 1, color)
    elsif dxyk
          yj += 1
          xj += dx
      end
      edges ||= []
      edges.push()
      end
    end
    returnunless max_y - min_y > 1and max_x - min_x > 1
    dw = max_x - min_x - 1
    dh = max_y - min_y - 1
    if fill_mode == 0
      if fill1 != fill2
      dr = (fill2.red - fill1.red) / dh
      dg = (fill2.green - fill1.green) / dh
      db = (fill2.blue - fill1.blue) / dh
      da = (fill2.alpha - fill1.alpha) / dh
      gradient = true
      end
      f = fill1.clone
      aet = edges.each{|edge| edge += edge}.sort!
      for y in min_y + 1..max_y - 1
      aet.concat(edges).sort! if edges
      0.step(aet.size - 2, 2)do |i|
          xi = aet.round
          xj = aet.round
          xi += 1until xi == width - 1or get_pixel(xi, y) != color
          xj -= 1until xj == 0or get_pixel(xj, y) != color
          fill_rect(xi, y, xj - xi + 1, 1, f)if xj >= xi
      end
      aet.reject! {|edge| edge == y}
      aet.each{|edge| edge += edge}.sort!
      f.set(f.red + dr, f.green + dg, f.blue + db, f.alpha + da)if gradient
      end
    else
      if fill_mode == 2
      src = Bitmap.new(dw, fill_pattern.height)
      0.step(dw - 1, fill_pattern.width)do |x|
          src.blt(x, 0, fill_pattern, fill_pattern.rect, fill_opacity)
      end
      else
      src = Bitmap.new(dw, 1)
      src.gradient_draw_line(0, 0, dw - 1, 0, fill1, fill2)
      end
      ox = -1 - min_x
      y_index = 0
      aet = edges.each{|edge| edge += edge}.sort!
      for y in min_y + 1..max_y - 1
      aet.concat(edges).sort! if edges
      0.step(aet.size - 2, 2)do |i|
          xi = aet.round
          xj = aet.round
          xi += 1until xi == width - 1or get_pixel(xi, y) != color
          xj -= 1until xj == 0or get_pixel(xj, y) != color
          blt(xi, y, src, Rect.new(xi + ox, y_index, xj - xi + 1, 1))
      end
      aet.reject! {|edge| edge == y}
      aet.each{|edge| edge += edge}.sort!
      y_index = (y_index + 1) % src.height
      end
      src.dispose
    end
end
#--------------------------------------------------------------------------
# ● 传送位图多边形
#   x1 : 第一点的 X 坐标
#   y1 : 第一点的 Y 坐标
#   x2 : 第二点的 X 坐标
#   y2 : 第二点的 Y 坐标
#   x3 : 第三点的 X 坐标
#   y3 : 第三点的 Y 坐标
#   args : 后续的参数(加多个点,最后是位图, 偏移x,偏移y,(可选)不透明度)
#            偏移x和偏移y的位置参考第一个点
#--------------------------------------------------------------------------
def blt_polygon(x1, y1, x2, y2, x3, y3, *args)
    if args[-3].is_a?(Bitmap)
      src, x0, y0 = args[-3, 3]
      opacity = 255
      nodes = .concat(args)
    elsif args[-4].is_a?(Bitmap)
      src, x0, y0, opacity = args[-4, 4]
      nodes = .concat(args)
    else
      raiseArgumentError
    end
    raiseArgumentErrorunless nodes.size == 0
    edges = {}
    min_y = height
    max_y = 0
    ox = x0 - x1
    oy = y0 - y1
    0.step(nodes.size - 2, 2)do |i|
      xi, yi = nodes
      min_y = .min
      max_y = .max
      xj, yj = nodes[(i + 2) % nodes.size, 2]
      dx = 1.0 * (xi - xj) / (yi - yj)
      if yi < yj
      delta = -1
      delta -= 2until(yh = nodes[(i + delta) % nodes.size]) != yi
      if yh < yi
          yi += 1
          xi += dx
      end
      edges ||= []
      edges.push()
      elsif yi > yj
      delta = 5
      delta += 2until(yk = nodes[(i + delta) % nodes.size]) != yj
      if yj > yk
          yj += 1
          xj += dx
      end
      edges ||= []
      edges.push()
      end
    end
    aet = []
    for y in min_y..max_y
      aet.concat(edges).sort! if edges
      0.step(aet.size - 1, 2)do |i|
      xi = aet.round
      xj = aet.round
      blt(xi, y, src, Rect.new(xi + ox, y + oy, xj - xi + 1, 1), opacity)
      end
      aet.reject! {|edge| edge == y}
      aet.each{|edge| edge += edge}.sort!
    end
end
#--------------------------------------------------------------------------
# ● 绘制正多边形
#   x : 正多边形外接圆心 X 坐标
#   y : 正多边形外接圆心 Y 坐标
#   rad : 正多边形外接圆 半径
#   edges : 正多边形的边数
#   angle : 正多边形旋转角度
#   color : 正多边形的颜色 (Color)
#--------------------------------------------------------------------------
def draw_isogon(x, y, rad, edges, angle, color)
    raiseArgumentErrorif edges < 3
    step = Math::PI * 2 / edges
    args = []
    angle_i = Math::PI * (270 + angle) / 180
    edges.timesdo
      args.push((x + rad * Math.cos(angle_i)).round,
      (y + rad * Math.sin(angle_i)).round)
      angle_i += step
    end
    draw_polygon(*args.push(color))
end
#--------------------------------------------------------------------------
# ● 绘制实心正多边形
#   x : 正多边形外接圆心 X 坐标
#   y : 正多边形外接圆心 Y 坐标
#   rad : 正多边形外接圆 半径
#   edges : 正多边形的边数
#   angle : 正多边形旋转角度
#   color : 边框的颜色 (Color)
#   fill : 填充选项,具体的填充选项有:
#            2个颜色 + true/false : 两个颜色以垂直/水平方式渐变填充
#            2个颜色 : 两个颜色以水平方向渐变填充
#            1个颜色 : 实心填充
#            位图 + 数值 : 以位图图案填充,数值为不透明度
#            位图 : 以位图图案填充,不透明度固定为255
#            省略 : 用边框色实心填充
#--------------------------------------------------------------------------
def fill_isogon(x, y, rad, edges, angle, color, *fill)
    raiseArgumentErrorif edges < 3
    step = Math::PI * 2 / edges
    args = []
    angle_i = Math::PI * (270 + angle) / 180
    edges.timesdo
      args.push((x + rad * Math.cos(angle_i)).round,
      (y + rad * Math.sin(angle_i)).round)
      angle_i += step
    end
    fill_polygon(*args.push(color).concat(fill))
end
#--------------------------------------------------------------------------
# ● 传送位图正多边形
#   x : 正多边形外接圆心 X 坐标
#   y : 正多边形外接圆心 Y 坐标
#   rad : 正多边形外接圆 半径
#   edges : 正多边形的边数
#   angle : 正多边形旋转角度
#   src_bitmap : 传送元位图
#   x0 : 传送圆心 X 坐标
#   y0 : 传送圆心 Y 坐标
#   opacity : 不透明度
#--------------------------------------------------------------------------
def blt_isogon(x, y, rad, edges, angle, src_bitmap, x0, y0, opacity = 255)
    raiseArgumentErrorif edges < 3
    step = Math::PI * 2 / edges
    args = []
    angle_i = Math::PI * (270 + angle) / 180
    edges.timesdo
      args.push((x + rad * Math.cos(angle_i)).round,
      (y + rad * Math.sin(angle_i)).round)
      angle_i += step
    end
    args.push(src_bitmap, x0 - x + args, y0 - y + args, opacity)
    blt_polygon(*args)
end
#--------------------------------------------------------------------------
# ● 绘制圆
#   x : 圆心 X 坐标
#   y : 圆心 Y 坐标
#   rad : 半径
#   color : 圆的颜色 (Color)
#--------------------------------------------------------------------------
def draw_circle(x, y, rad, color)
    draw_ellipse(x, y, rad, rad, color)
end
#--------------------------------------------------------------------------
# ● 绘制椭圆
#   x : 圆心 X 坐标
#   y : 圆心 Y 坐标
#   rad_x : 水平半径
#   rad_y : 垂直半径
#   color : 椭圆的颜色 (Color)
#--------------------------------------------------------------------------
def draw_ellipse(x, y, rad_x, rad_y, color)
    fill_ellipse(x, y, rad_x, rad_y, color, nil)
end
#--------------------------------------------------------------------------
# ● 绘制实心圆
#   x : 圆心 X 坐标
#   y : 圆心 Y 坐标
#   rad : 半径
#   border_color : 圆的边框颜色 (Color)
#   fill : 填充选项,具体的填充选项有:
#            nil : 不填充
#            2个颜色 + true/false : 两个颜色以垂直/水平方式渐变填充
#            2个颜色 : 两个颜色以水平方向渐变填充
#            1个颜色 : 实心填充
#            位图 + 数值 : 以位图图案填充,数值为不透明度
#            位图 : 以位图图案填充,不透明度固定为255
#            省略 : 用边框色实心填充
#--------------------------------------------------------------------------
def fill_circle(x, y, rad, border_color, *fill)
    fill_ellipse(x, y, rad, rad, border_color, *fill)
end
#--------------------------------------------------------------------------
# ● 绘制实心椭圆
#   x : 圆心 X 坐标
#   y : 圆心 Y 坐标
#   rad_x : 水平半径
#   rad_y : 垂直半径
#   border_color : 椭圆的边框颜色 (Color)
#   fill : 填充选项,具体的填充选项有:
#            nil : 不填充
#            2个颜色 + true/false : 两个颜色以垂直/水平方式渐变填充
#            2个颜色 : 两个颜色以水平方向渐变填充
#            1个颜色 : 实心填充
#            位图 + 数值 : 以位图图案填充,数值为不透明度
#            位图 : 以位图图案填充,不透明度固定为255
#            省略 : 用边框色实心填充
#--------------------------------------------------------------------------
def fill_ellipse(x, y, rad_x, rad_y, border_color, *fill)
    raiseArgumentErrorif rad_x < 0or rad_y < 0
    return set_pixel(x, y, border_color)if rad_x == 0and rad_y == 0
    return fill_rect(x - rad_x, y, rad_x
页: [1]
查看完整版本: 【正式发布】RM BitmapCanvas 2D绘图插件