赞 | 342 |
VIP | 10 |
好人卡 | 8 |
积分 | 262 |
经验 | 235776 |
最后登录 | 2024-9-23 |
在线时间 | 2387 小时 |
Lv5.捕梦者 (版主) 遠航の猫咪
- 梦石
- 3
- 星屑
- 23206
- 在线时间
- 2387 小时
- 注册时间
- 2005-10-15
- 帖子
- 1166
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 SailCat 于 2022-3-1 22:07 编辑
不依赖SEP Core运行,所以独立发一下
但是……谢谢大家的测试我只能说[泪目]……看来这个功能做出来终究还是有它的可取之处的,那就后续再更新一下吧~
就是写着顺手就写出来了……
#============================================================================== # ■ [Bitmap Canvas] 位图画布处理核心 v1.0 by SailCat #------------------------------------------------------------------------------ # 方法:本脚本插入Main之前使用 # 依赖:无 # 版本:v1.0 (Build 220228) # 效果: # 1. 可以用简单指令在位图对象上画图 # 配置:画笔线形的配置 # 冲突:无 # 说明: # 1. 绘制直线: # draw_line(起始x, 起始y, 结束x, 结束y, 颜色, 线形) # 2. 绘制渐变色直线: # gradient_draw_line(起始x, 起始y, 结束x, 结束y, 颜色1, 颜色2) # 3. 绘制路径(连续直线): # draw_path(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 颜色) # 4. 绘制多边形(连续封闭直线): # draw_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 颜色) # 5. 绘制正多边形: # draw_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 颜色) # 6. 绘制椭圆: # draw_ellipse(圆心x, 圆心y, 半横径,半纵径, 颜色) # 7. 绘制圆: # draw_circle(圆心x, 圆心y, 半径,颜色) # 8. 填涂多边形: # fill_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 边框颜色[, # 填充颜色1[, 填充颜色2]]) # 9. 填涂正多边形: # fill_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 边框颜色[, # 填充颜色1[, 填充颜色2]]) # 10.填涂椭圆: # fill_ellipse(圆心x, 圆心y, 半横径,半纵径, 边框颜色[, 填充颜色1[, # 填充颜色2]]) # 11.填涂圆: # fill_circle(圆心x, 圆心y, 半径,边框颜色[, 填充颜色1[, 填充颜色2]]) # 12.传送多边形: # blt_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 源位图, # 参考点1, 参考点1y[, 不透明度]) # 13.传送正多边形: # blt_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 源位图, 参考心x, # 参考心y[, 不透明度]) # 14.传送椭圆: # blt_ellipse(圆心x, 圆心y, 半横径,半纵径, 源位图, 参考心x, 参考心y[, # 不透明度]) # 15.传送圆: # blt_circle(圆心x, 圆心y, 半径,源位图, 参考心x, 参考心y[, 不透明度]) #============================================================================== #============================================================================== # ■ SailCat's 插件公用 #============================================================================== module SailCat #-------------------------------------------------------------------------- # ● 脚本配置区 #-------------------------------------------------------------------------- module Canvas_Config CANVAS_LINE_DOTTED = [1, 0] # 点线画笔 CANVAS_LINE_DASHED = [1, 1, 0, 1] # 短虚线画笔 CANVAS_LINE_LONGDASH = [1, 1, 0, 0, 1, 1] # 长虚线画笔 CANVAS_LINE_DASHDOT = [1, 0, 1, 1, 1, 0] # 点划线画笔 CANVAS_LINE_BROKEN = [1, 0, 0] # 散点画笔 end end #============================================================================== # ■ Bitmap #============================================================================== class Bitmap include SailCat::Canvas_Config #-------------------------------------------------------------------------- # ● 常量 #-------------------------------------------------------------------------- CANVAS_LINE_SOLID = [1] # 实心画笔,该常量禁止修改配置 #-------------------------------------------------------------------------- # ● 绘制直线 # 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 - x1 <=> 0 ry = y2 - y1 <=> 0 b_index = 0 b_size = style.size if dx == 0 and style == CANVAS_LINE_SOLID fill_rect(x1, [y1, y2].min, 1, dy + 1, color) elsif dy == 0 and style == CANVAS_LINE_SOLID fill_rect([x1, x2].min, y1, dx + 1, 1, color) elsif dx <= dy f = dx.to_f * rx / dy dy.times do set_pixel(x.round, y, color) if style[b_index] == 1 x += f y += ry b_index += 1 b_index %= b_size end set_pixel(x.round, y, color) else f = dy.to_f * ry / dx dx.times do set_pixel(x, y.round, color) if style[b_index] == 1 x += rx y += f b_index += 1 b_index %= b_size end set_pixel(x, y.round, color) end end #-------------------------------------------------------------------------- # ● 绘制渐变直线 # x1 : 起始的 X 坐标 # y1 : 起始的 Y 坐标 # x2 : 结束的 X 坐标 # y2 : 结束的 Y 坐标 # color1 : 直线的起始颜色 (Color) # color2 : 直线的终止颜色 (Color) #-------------------------------------------------------------------------- def gradient_draw_line(x1, y1, x2, y2, color1, color2) return set_pixel(x1, y1, color) if x1 == x2 and y1 == y2 return draw_line(x1, y1, x2, y2, color1) if color1 == color2 dx = (x2 - x1).abs dy = (y2 - y1).abs rx = x2 - x1 <=> 0 ry = y2 - y1 <=> 0 c = color1.clone if dx <= dy f = dx.to_f / dy * rx x = x1.to_f y = y1 dr = (color2.red - color1.red) / dy dg = (color2.green - color1.green) / dy db = (color2.blue - color1.blue) / dy da = (color2.alpha - color1.alpha) / dy dy.times do set_pixel(x.round, y, c) x += f y += ry c.set(c.red + dr, c.green + dg, c.blue + db, c.alpha + da) end else f = dy.to_f / dx * ry x = x1 y = y1.to_f dr = (color2.red - color1.red) / dx dg = (color2.green - color1.green) / dx db = (color2.blue - color1.blue) / dx da = (color2.alpha - color1.alpha) / dx dx.times do set_pixel(x, y.round, c) x += rx y += f c.set(c.red + dr, c.green + dg, c.blue + db, c.alpha + da) end end end #-------------------------------------------------------------------------- # ● 绘制路径 # x1 : 第一点的 X 坐标 # y1 : 第一点的 Y 坐标 # x2 : 第二点的 X 坐标 # y2 : 第二点的 Y 坐标 # x3 : 第三点的 X 坐标 # y3 : 第三点的 Y 坐标 # args : 后续的参数(可以加多个点,至少要包括颜色) #-------------------------------------------------------------------------- def draw_path(x1, y1, x2, y2, x3, y3, *args) raise ArgumentError if args.size % 2 == 0 or not args[-1].is_a?(Color) color = args[-1] nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-1]) 0.step(nodes.size - 4, 2) {|i| draw_line(*(nodes[i, 4].concat([color])))} end #-------------------------------------------------------------------------- # ● 绘制多边形 # x1 : 第一点的 X 坐标 # y1 : 第一点的 Y 坐标 # x2 : 第二点的 X 坐标 # y2 : 第二点的 Y 坐标 # x3 : 第三点的 X 坐标 # y3 : 第三点的 Y 坐标 # args : 后续的参数(可以加多个点,至少要包括颜色) #-------------------------------------------------------------------------- def draw_polygon(x1, y1, x2, y2, x3, y3, *args) raise ArgumentError if args.size % 2 == 0 or not args[-1].is_a?(Color) args.insert(-2, x1, y1) draw_path(x1, y1, x2, y2, x3, y3, *args) end #-------------------------------------------------------------------------- # ● 绘制实心多边形 # x1 : 第一点的 X 坐标 # y1 : 第一点的 Y 坐标 # x2 : 第二点的 X 坐标 # y2 : 第二点的 Y 坐标 # x3 : 第三点的 X 坐标 # y3 : 第三点的 Y 坐标 # args : 后续的参数(可以加多个点,至少要包括一个颜色,至多可有三个颜色) #-------------------------------------------------------------------------- def fill_polygon(x1, y1, x2, y2, x3, y3, *args) raise ArgumentError unless args[-1].is_a?(Color) fill2 = args[-3].is_a?(Color) ? args.pop : args[-1] fill1 = args[-2].is_a?(Color) ? args.pop : args[-1] draw_polygon(x1, y1, x2, y2, x3, y3, *args) color = args[-1] nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-1]) edges = {} min_y = height max_y = 0 0.step(nodes.size - 2, 2) do |i| xi, yi = nodes[i, 2] min_y = [min_y, yi].min max_y = [max_y, yi].max xj, yj = nodes[(i + 2) % nodes.size, 2] dx = 1.0 * (xi - xj) / (yi - yj) if yi < yj yh = nodes[i - 1] if yh < yi yi += 1 xi += dx end edges[yi] ||= [] edges[yi].push([xi, dx, yj]) elsif yi > yj yk = nodes[(i + 5) % nodes.size] if yj > yk yj += 1 xj += dx end edges[yj] ||= [] edges[yj].push([xj, dx, yi]) end end return unless max_y - min_y > 1 aet = edges[min_y] aet.each {|edge| edge[0] += edge[1]} aet.sort! if fill1 != fill2 dh = max_y - min_y - 1 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 for y in min_y + 1..max_y - 1 if edges[y] aet.concat(edges[y]) aet.sort! end 0.step(aet.size - 1, 2) do |i| xi = aet[i][0].round xj = aet[i + 1][0].round xi += 1 until xi == width - 1 or get_pixel(xi, y) != color xj -= 1 until xj == 0 or get_pixel(xj, y) != color if xj >= xi fill_rect(xi, y, xj - xi + 1, 1, f) end aet.reject! {|edge| edge[2] == y} aet.each {|edge| edge[0] += edge[1]} aet.sort! f.set(f.red + dr, f.green + dg, f.blue + db, f.alpha + da) if gradient end 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 = [x1, y1, x2, y2, x3, y3].concat(args[0...-3]) elsif args[-4].is_a?(Bitmap) src, x0, y0, opacity = args[-4, 4] nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-4]) else raise ArgumentError end raise ArgumentError unless nodes.size[0] == 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[i, 2] min_y = [min_y, yi].min max_y = [max_y, yi].max xj, yj = nodes[(i + 2) % nodes.size, 2] dx = 1.0 * (xi - xj) / (yi - yj) if yi < yj yh = nodes[i - 1] if yh < yi yi += 1 xi += dx end edges[yi] ||= [] edges[yi].push([xi, dx, yj]) elsif yi > yj yk = nodes[(i + 5) % nodes.size] if yj > yk yj += 1 xj += dx end edges[yj] ||= [] edges[yj].push([xj, dx, yi]) end end aet = [] for y in min_y..max_y if edges[y] aet.concat(edges[y]) aet.sort! end 0.step(aet.size - 1, 2) do |i| xi = aet[i][0].round xj = aet[i + 1][0].round blt(xi, y, src, Rect.new(xi + ox, y + oy, xj - xi + 1, 1), opacity) aet.reject! {|edge| edge[2] == y} aet.each {|edge| edge[0] += edge[1]} aet.sort! end end end #-------------------------------------------------------------------------- # ● 绘制正多边形 # x : 正多边形外接圆心 X 坐标 # y : 正多边形外接圆心 Y 坐标 # rad : 正多边形外接圆 半径 # edges : 正多边形的边数 # angle : 正多边形旋转角度 # color : 正多边形的颜色 (Color) #-------------------------------------------------------------------------- def draw_isogon(x, y, rad, edges, angle, color) raise ArgumentError if edges < 3 step = Math::PI * 2 / edges args = [] angle_i = Math::PI * (270 + angle) / 180 edges.times do args.push((x + rad * Math.cos(angle_i)).round, (y + rad * Math.sin(angle_i)).round) angle_i += step end args.push(color) draw_polygon(*args) end #-------------------------------------------------------------------------- # ● 绘制实心正多边形 # x : 正多边形外接圆心 X 坐标 # y : 正多边形外接圆心 Y 坐标 # rad : 正多边形外接圆 半径 # edges : 正多边形的边数 # angle : 正多边形旋转角度 # border_color : 正多边形的边框颜色 (Color) # fill_color1 : 填充渐变的上颜色 (Color) # fill_color2 : 填充渐变的下颜色 (Color) #-------------------------------------------------------------------------- def fill_isogon(x, y, rad, edges, angle, border_color, fill_color1 = border_color, fill_color2 = fill_color1) raise ArgumentError if edges < 3 step = Math::PI * 2 / edges args = [] angle_i = Math::PI * (270 + angle) / 180 edges.times do args.push((x + rad * Math.cos(angle_i)).round, (y + rad * Math.sin(angle_i)).round) angle_i += step end args.push(border_color, fill_color1, fill_color2) fill_polygon(*args) 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) raise ArgumentError if edges < 3 step = Math::PI * 2 / edges args = [] angle_i = Math::PI * (270 + angle) / 180 edges.times do 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[0], y0 - y + args[1], opacity) blt_polygon(*args) end #-------------------------------------------------------------------------- # ● 绘制圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad : 半径 # color : 圆的颜色 (Color) #-------------------------------------------------------------------------- def draw_circle(x, y, rad, color) raise ArgumentError if rad < 0 return set_pixel(x, y, color) if rad == 0 draw_ellipse(x, y, rad, rad, color) end #-------------------------------------------------------------------------- # ● 绘制椭圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad_x : 水平半径 # rad_y : 垂直半径 # color : 椭圆的颜色 (Color) # fill1 : 填充的颜色1 (Color) # fill2 : 填充的颜色2 (Color) #-------------------------------------------------------------------------- def draw_ellipse(x, y, rad_x, rad_y, color, fill1 = nil, fill2 = nil) raise ArgumentError if rad_x < 0 or rad_y < 0 return set_pixel(x, y, color) if rad_x == 0 and rad_y == 0 return fill_rect(x - rad_x, y, rad_x << 1, 1, color) if rad_y == 0 return fill_rect(x, y - rad_y, 1, rad_y << 1, color) if rad_x == 0 ry2 = rad_y * rad_y rx2 = rad_x * rad_x d = ry2 + rx2 * (0.25 - rad_y) dx = 0 last_dy = dy = rad_y f = fill1 && fill1.clone if fill2 f2 = fill2.clone dr = (fill2.red - fill1.red) / ((rad_y << 1) - 1) dg = (fill2.green - fill1.green) / ((rad_y << 1) - 1) db = (fill2.blue - fill1.blue) / ((rad_y << 1) - 1) da = (fill2.alpha - fill1.alpha) / ((rad_y << 1) - 1) end begin set_pixel(x + dx, y + dy, color) set_pixel(x + dx, y - dy, color) set_pixel(x - dx, y - dy, color) set_pixel(x - dx, y + dy, color) if f and dx > 1 and dy < rad_y and last_dy != dy last_dy = dy fill_rect(x - dx + 1, y - dy, (dx << 1) - 1, 1, f) fill_rect(x - dx + 1, y + dy, (dx << 1) - 1, 1, f2) if fill2 f.set(f.red + dr, f.green + dg, f.blue + db, f.alpha + da) f2.set(f2.red - dr, f2.green - dg, f2.blue - db, f2.alpha - da) end end if d <= -1e-6 d += ry2 * ((dx << 1) + 3) else d += ry2 * ((dx << 1) + 3) + rx2 * (1 - dy << 1) dy -= 1 end dx += 1 end while ry2 * (dx + 1) < rx2 * (dy - 0.5) d = ry2 * (dx + 0.5) * (dx + 0.5) + rx2 * (dy - 1) * (dy - 1) - rx2 * ry2 begin set_pixel(x + dx, y + dy, color) set_pixel(x + dx, y - dy, color) set_pixel(x - dx, y - dy, color) set_pixel(x - dx, y + dy, color) if f and dx > 1 and dy < rad_y and last_dy != dy last_dy = dy fill_rect(x - dx + 1, y - dy, (dx << 1) - 1, 1, f) fill_rect(x - dx + 1, y + dy, (dx << 1) - 1, 1, f2) if fill2 f.set(f.red + dr, f.green + dg, f.blue + db, f.alpha + da) f2.set(f2.red - dr, f2.green - dg, f2.blue - db, f2.alpha - da) end end if d <= -1e-6 d += ry2 * (dx + 1 << 1) + rx2 * (3 - (dy << 1)) dx += 1 else d += rx2 * (3 - (dy << 1)) end dy -= 1 end while dy >= 0 end #-------------------------------------------------------------------------- # ● 绘制实心圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad : 半径 # border_color : 圆的边框颜色 (Color) # fill_color1 : 填充渐变的上颜色 (Color) # fill_color2 : 填充渐变的下颜色 (Color) #-------------------------------------------------------------------------- def fill_circle(x, y, rad, border_color, fill_color1 = border_color, fill_color2 = fill_color1) draw_ellipse(x, y, rad, rad, border_color, fill_color1, fill_color2) end #-------------------------------------------------------------------------- # ● 绘制实心椭圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad_x : 水平半径 # rad_y : 垂直半径 # border_color : 椭圆的边框颜色 (Color) # fill_color1 : 填充渐变的上颜色 (Color) # fill_color2 : 填充渐变的下颜色 (Color) #-------------------------------------------------------------------------- def fill_ellipse(x, y, rad_x, rad_y, border_color, fill_color1 = border_color, fill_color2 = fill_color1) draw_ellipse(x, y, rad_x, rad_y, border_color, fill_color1, fill_color2) end #-------------------------------------------------------------------------- # ● 传送位图圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad : 半径 # src_bitmap : 传送元位图 # x0 : 传送圆心 X 坐标 # y0 : 传送圆心 Y 坐标 # opacity : 不透明度 #-------------------------------------------------------------------------- def blt_circle(x, y, rad, src_bitmap, x0, y0, opacity = 255) blt_ellipse(x, y, rad, rad, src_bitmap, x0, y0, opacity) end #-------------------------------------------------------------------------- # ● 传送位图椭圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad_x : 水平半径 # rad_y : 垂直半径 # src_bitmap : 传送元位图 # x0 : 传送圆心 X 坐标 # y0 : 传送圆心 Y 坐标 # opacity : 不透明度 #-------------------------------------------------------------------------- def blt_ellipse(x, y, rad_x, rad_y, src_bitmap, x0, y0, opacity = 255) raise ArgumentError if rad_x < 0 or rad_y < 0 return blt(x - rad_x, y, src_bitmap, Rect.new(x0 - rad_x, y0, rad_x << 1, 1), opacity) if rad_y == 0 return blt(x, y - rad_y, src_bitmap, Rect.new(x0, y0 - rad_y, 1, rad_y << 1), opacity) if rad_x == 0 ry2 = rad_y * rad_y rx2 = rad_x * rad_x d = ry2 + rx2 * (0.25 - rad_y) dx = 0 dy = rad_y last_dy = nil begin if last_dy != dy last_dy = dy blt(x - dx + 1, y - dy, src_bitmap, Rect.new(x0 - dx + 1, y0 - dy, (dx << 1) - 1, 1), opacity) blt(x - dx + 1, y + dy, src_bitmap, Rect.new(x0 - dx + 1, y0 + dy, (dx << 1) - 1, 1), opacity) end if d <= -1e-6 d += ry2 * ((dx << 1) + 3) else d += ry2 * ((dx << 1) + 3) + rx2 * (1 - dy << 1) dy -= 1 end dx += 1 end while ry2 * (dx + 1) < rx2 * (dy - 0.5) d = ry2 * (dx + 0.5) * (dx + 0.5) + rx2 * (dy - 1) * (dy - 1) - rx2 * ry2 begin if last_dy != dy last_dy = dy blt(x - dx + 1, y - dy, src_bitmap, Rect.new(x0 - dx + 1, y0 - dy, (dx << 1) - 1, 1), opacity) blt(x - dx + 1, y + dy, src_bitmap, Rect.new(x0 - dx + 1, y0 + dy, (dx << 1) - 1, 1), opacity) end if d <= -1e-6 d += ry2 * (dx + 1 << 1) + rx2 * (3 - (dy << 1)) dx += 1 else d += rx2 * (3 - (dy << 1)) end dy -= 1 end while dy >= 0 end end
#==============================================================================
# ■ [Bitmap Canvas] 位图画布处理核心 v1.0 by SailCat
#------------------------------------------------------------------------------
# 方法:本脚本插入Main之前使用
# 依赖:无
# 版本:v1.0 (Build 220228)
# 效果:
# 1. 可以用简单指令在位图对象上画图
# 配置:画笔线形的配置
# 冲突:无
# 说明:
# 1. 绘制直线:
# draw_line(起始x, 起始y, 结束x, 结束y, 颜色, 线形)
# 2. 绘制渐变色直线:
# gradient_draw_line(起始x, 起始y, 结束x, 结束y, 颜色1, 颜色2)
# 3. 绘制路径(连续直线):
# draw_path(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 颜色)
# 4. 绘制多边形(连续封闭直线):
# draw_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 颜色)
# 5. 绘制正多边形:
# draw_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 颜色)
# 6. 绘制椭圆:
# draw_ellipse(圆心x, 圆心y, 半横径,半纵径, 颜色)
# 7. 绘制圆:
# draw_circle(圆心x, 圆心y, 半径,颜色)
# 8. 填涂多边形:
# fill_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 边框颜色[,
# 填充颜色1[, 填充颜色2]])
# 9. 填涂正多边形:
# fill_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 边框颜色[,
# 填充颜色1[, 填充颜色2]])
# 10.填涂椭圆:
# fill_ellipse(圆心x, 圆心y, 半横径,半纵径, 边框颜色[, 填充颜色1[,
# 填充颜色2]])
# 11.填涂圆:
# fill_circle(圆心x, 圆心y, 半径,边框颜色[, 填充颜色1[, 填充颜色2]])
# 12.传送多边形:
# blt_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 源位图,
# 参考点1, 参考点1y[, 不透明度])
# 13.传送正多边形:
# blt_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 源位图, 参考心x,
# 参考心y[, 不透明度])
# 14.传送椭圆:
# blt_ellipse(圆心x, 圆心y, 半横径,半纵径, 源位图, 参考心x, 参考心y[,
# 不透明度])
# 15.传送圆:
# blt_circle(圆心x, 圆心y, 半径,源位图, 参考心x, 参考心y[, 不透明度])
#==============================================================================
#==============================================================================
# ■ SailCat's 插件公用
#==============================================================================
module SailCat
#--------------------------------------------------------------------------
# ● 脚本配置区
#--------------------------------------------------------------------------
module Canvas_Config
CANVAS_LINE_DOTTED = [1, 0] # 点线画笔
CANVAS_LINE_DASHED = [1, 1, 0, 1] # 短虚线画笔
CANVAS_LINE_LONGDASH = [1, 1, 0, 0, 1, 1] # 长虚线画笔
CANVAS_LINE_DASHDOT = [1, 0, 1, 1, 1, 0] # 点划线画笔
CANVAS_LINE_BROKEN = [1, 0, 0] # 散点画笔
end
end
#==============================================================================
# ■ Bitmap
#==============================================================================
class Bitmap
include SailCat::Canvas_Config
#--------------------------------------------------------------------------
# ● 常量
#--------------------------------------------------------------------------
CANVAS_LINE_SOLID = [1] # 实心画笔,该常量禁止修改配置
#--------------------------------------------------------------------------
# ● 绘制直线
# 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 - x1 <=> 0
ry = y2 - y1 <=> 0
b_index = 0
b_size = style.size
if dx == 0 and style == CANVAS_LINE_SOLID
fill_rect(x1, [y1, y2].min, 1, dy + 1, color)
elsif dy == 0 and style == CANVAS_LINE_SOLID
fill_rect([x1, x2].min, y1, dx + 1, 1, color)
elsif dx <= dy
f = dx.to_f * rx / dy
dy.times do
set_pixel(x.round, y, color) if style[b_index] == 1
x += f
y += ry
b_index += 1
b_index %= b_size
end
set_pixel(x.round, y, color)
else
f = dy.to_f * ry / dx
dx.times do
set_pixel(x, y.round, color) if style[b_index] == 1
x += rx
y += f
b_index += 1
b_index %= b_size
end
set_pixel(x, y.round, color)
end
end
#--------------------------------------------------------------------------
# ● 绘制渐变直线
# x1 : 起始的 X 坐标
# y1 : 起始的 Y 坐标
# x2 : 结束的 X 坐标
# y2 : 结束的 Y 坐标
# color1 : 直线的起始颜色 (Color)
# color2 : 直线的终止颜色 (Color)
#--------------------------------------------------------------------------
def gradient_draw_line(x1, y1, x2, y2, color1, color2)
return set_pixel(x1, y1, color) if x1 == x2 and y1 == y2
return draw_line(x1, y1, x2, y2, color1) if color1 == color2
dx = (x2 - x1).abs
dy = (y2 - y1).abs
rx = x2 - x1 <=> 0
ry = y2 - y1 <=> 0
c = color1.clone
if dx <= dy
f = dx.to_f / dy * rx
x = x1.to_f
y = y1
dr = (color2.red - color1.red) / dy
dg = (color2.green - color1.green) / dy
db = (color2.blue - color1.blue) / dy
da = (color2.alpha - color1.alpha) / dy
dy.times do
set_pixel(x.round, y, c)
x += f
y += ry
c.set(c.red + dr, c.green + dg, c.blue + db, c.alpha + da)
end
else
f = dy.to_f / dx * ry
x = x1
y = y1.to_f
dr = (color2.red - color1.red) / dx
dg = (color2.green - color1.green) / dx
db = (color2.blue - color1.blue) / dx
da = (color2.alpha - color1.alpha) / dx
dx.times do
set_pixel(x, y.round, c)
x += rx
y += f
c.set(c.red + dr, c.green + dg, c.blue + db, c.alpha + da)
end
end
end
#--------------------------------------------------------------------------
# ● 绘制路径
# x1 : 第一点的 X 坐标
# y1 : 第一点的 Y 坐标
# x2 : 第二点的 X 坐标
# y2 : 第二点的 Y 坐标
# x3 : 第三点的 X 坐标
# y3 : 第三点的 Y 坐标
# args : 后续的参数(可以加多个点,至少要包括颜色)
#--------------------------------------------------------------------------
def draw_path(x1, y1, x2, y2, x3, y3, *args)
raise ArgumentError if args.size % 2 == 0 or not args[-1].is_a?(Color)
color = args[-1]
nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-1])
0.step(nodes.size - 4, 2) {|i| draw_line(*(nodes[i, 4].concat([color])))}
end
#--------------------------------------------------------------------------
# ● 绘制多边形
# x1 : 第一点的 X 坐标
# y1 : 第一点的 Y 坐标
# x2 : 第二点的 X 坐标
# y2 : 第二点的 Y 坐标
# x3 : 第三点的 X 坐标
# y3 : 第三点的 Y 坐标
# args : 后续的参数(可以加多个点,至少要包括颜色)
#--------------------------------------------------------------------------
def draw_polygon(x1, y1, x2, y2, x3, y3, *args)
raise ArgumentError if args.size % 2 == 0 or not args[-1].is_a?(Color)
args.insert(-2, x1, y1)
draw_path(x1, y1, x2, y2, x3, y3, *args)
end
#--------------------------------------------------------------------------
# ● 绘制实心多边形
# x1 : 第一点的 X 坐标
# y1 : 第一点的 Y 坐标
# x2 : 第二点的 X 坐标
# y2 : 第二点的 Y 坐标
# x3 : 第三点的 X 坐标
# y3 : 第三点的 Y 坐标
# args : 后续的参数(可以加多个点,至少要包括一个颜色,至多可有三个颜色)
#--------------------------------------------------------------------------
def fill_polygon(x1, y1, x2, y2, x3, y3, *args)
raise ArgumentError unless args[-1].is_a?(Color)
fill2 = args[-3].is_a?(Color) ? args.pop : args[-1]
fill1 = args[-2].is_a?(Color) ? args.pop : args[-1]
draw_polygon(x1, y1, x2, y2, x3, y3, *args)
color = args[-1]
nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-1])
edges = {}
min_y = height
max_y = 0
0.step(nodes.size - 2, 2) do |i|
xi, yi = nodes[i, 2]
min_y = [min_y, yi].min
max_y = [max_y, yi].max
xj, yj = nodes[(i + 2) % nodes.size, 2]
dx = 1.0 * (xi - xj) / (yi - yj)
if yi < yj
yh = nodes[i - 1]
if yh < yi
yi += 1
xi += dx
end
edges[yi] ||= []
edges[yi].push([xi, dx, yj])
elsif yi > yj
yk = nodes[(i + 5) % nodes.size]
if yj > yk
yj += 1
xj += dx
end
edges[yj] ||= []
edges[yj].push([xj, dx, yi])
end
end
return unless max_y - min_y > 1
aet = edges[min_y]
aet.each {|edge| edge[0] += edge[1]}
aet.sort!
if fill1 != fill2
dh = max_y - min_y - 1
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
for y in min_y + 1..max_y - 1
if edges[y]
aet.concat(edges[y])
aet.sort!
end
0.step(aet.size - 1, 2) do |i|
xi = aet[i][0].round
xj = aet[i + 1][0].round
xi += 1 until xi == width - 1 or get_pixel(xi, y) != color
xj -= 1 until xj == 0 or get_pixel(xj, y) != color
if xj >= xi
fill_rect(xi, y, xj - xi + 1, 1, f)
end
aet.reject! {|edge| edge[2] == y}
aet.each {|edge| edge[0] += edge[1]}
aet.sort!
f.set(f.red + dr, f.green + dg, f.blue + db, f.alpha + da) if gradient
end
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 = [x1, y1, x2, y2, x3, y3].concat(args[0...-3])
elsif args[-4].is_a?(Bitmap)
src, x0, y0, opacity = args[-4, 4]
nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-4])
else
raise ArgumentError
end
raise ArgumentError unless nodes.size[0] == 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[i, 2]
min_y = [min_y, yi].min
max_y = [max_y, yi].max
xj, yj = nodes[(i + 2) % nodes.size, 2]
dx = 1.0 * (xi - xj) / (yi - yj)
if yi < yj
yh = nodes[i - 1]
if yh < yi
yi += 1
xi += dx
end
edges[yi] ||= []
edges[yi].push([xi, dx, yj])
elsif yi > yj
yk = nodes[(i + 5) % nodes.size]
if yj > yk
yj += 1
xj += dx
end
edges[yj] ||= []
edges[yj].push([xj, dx, yi])
end
end
aet = []
for y in min_y..max_y
if edges[y]
aet.concat(edges[y])
aet.sort!
end
0.step(aet.size - 1, 2) do |i|
xi = aet[i][0].round
xj = aet[i + 1][0].round
blt(xi, y, src, Rect.new(xi + ox, y + oy, xj - xi + 1, 1), opacity)
aet.reject! {|edge| edge[2] == y}
aet.each {|edge| edge[0] += edge[1]}
aet.sort!
end
end
end
#--------------------------------------------------------------------------
# ● 绘制正多边形
# x : 正多边形外接圆心 X 坐标
# y : 正多边形外接圆心 Y 坐标
# rad : 正多边形外接圆 半径
# edges : 正多边形的边数
# angle : 正多边形旋转角度
# color : 正多边形的颜色 (Color)
#--------------------------------------------------------------------------
def draw_isogon(x, y, rad, edges, angle, color)
raise ArgumentError if edges < 3
step = Math::PI * 2 / edges
args = []
angle_i = Math::PI * (270 + angle) / 180
edges.times do
args.push((x + rad * Math.cos(angle_i)).round,
(y + rad * Math.sin(angle_i)).round)
angle_i += step
end
args.push(color)
draw_polygon(*args)
end
#--------------------------------------------------------------------------
# ● 绘制实心正多边形
# x : 正多边形外接圆心 X 坐标
# y : 正多边形外接圆心 Y 坐标
# rad : 正多边形外接圆 半径
# edges : 正多边形的边数
# angle : 正多边形旋转角度
# border_color : 正多边形的边框颜色 (Color)
# fill_color1 : 填充渐变的上颜色 (Color)
# fill_color2 : 填充渐变的下颜色 (Color)
#--------------------------------------------------------------------------
def fill_isogon(x, y, rad, edges, angle, border_color, fill_color1 =
border_color, fill_color2 = fill_color1)
raise ArgumentError if edges < 3
step = Math::PI * 2 / edges
args = []
angle_i = Math::PI * (270 + angle) / 180
edges.times do
args.push((x + rad * Math.cos(angle_i)).round,
(y + rad * Math.sin(angle_i)).round)
angle_i += step
end
args.push(border_color, fill_color1, fill_color2)
fill_polygon(*args)
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)
raise ArgumentError if edges < 3
step = Math::PI * 2 / edges
args = []
angle_i = Math::PI * (270 + angle) / 180
edges.times do
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[0], y0 - y + args[1], opacity)
blt_polygon(*args)
end
#--------------------------------------------------------------------------
# ● 绘制圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad : 半径
# color : 圆的颜色 (Color)
#--------------------------------------------------------------------------
def draw_circle(x, y, rad, color)
raise ArgumentError if rad < 0
return set_pixel(x, y, color) if rad == 0
draw_ellipse(x, y, rad, rad, color)
end
#--------------------------------------------------------------------------
# ● 绘制椭圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad_x : 水平半径
# rad_y : 垂直半径
# color : 椭圆的颜色 (Color)
# fill1 : 填充的颜色1 (Color)
# fill2 : 填充的颜色2 (Color)
#--------------------------------------------------------------------------
def draw_ellipse(x, y, rad_x, rad_y, color, fill1 = nil, fill2 = nil)
raise ArgumentError if rad_x < 0 or rad_y < 0
return set_pixel(x, y, color) if rad_x == 0 and rad_y == 0
return fill_rect(x - rad_x, y, rad_x << 1, 1, color) if rad_y == 0
return fill_rect(x, y - rad_y, 1, rad_y << 1, color) if rad_x == 0
ry2 = rad_y * rad_y
rx2 = rad_x * rad_x
d = ry2 + rx2 * (0.25 - rad_y)
dx = 0
last_dy = dy = rad_y
f = fill1 && fill1.clone
if fill2
f2 = fill2.clone
dr = (fill2.red - fill1.red) / ((rad_y << 1) - 1)
dg = (fill2.green - fill1.green) / ((rad_y << 1) - 1)
db = (fill2.blue - fill1.blue) / ((rad_y << 1) - 1)
da = (fill2.alpha - fill1.alpha) / ((rad_y << 1) - 1)
end
begin
set_pixel(x + dx, y + dy, color)
set_pixel(x + dx, y - dy, color)
set_pixel(x - dx, y - dy, color)
set_pixel(x - dx, y + dy, color)
if f and dx > 1 and dy < rad_y and last_dy != dy
last_dy = dy
fill_rect(x - dx + 1, y - dy, (dx << 1) - 1, 1, f)
fill_rect(x - dx + 1, y + dy, (dx << 1) - 1, 1, f2)
if fill2
f.set(f.red + dr, f.green + dg, f.blue + db, f.alpha + da)
f2.set(f2.red - dr, f2.green - dg, f2.blue - db, f2.alpha - da)
end
end
if d <= -1e-6
d += ry2 * ((dx << 1) + 3)
else
d += ry2 * ((dx << 1) + 3) + rx2 * (1 - dy << 1)
dy -= 1
end
dx += 1
end while ry2 * (dx + 1) < rx2 * (dy - 0.5)
d = ry2 * (dx + 0.5) * (dx + 0.5) + rx2 * (dy - 1) * (dy - 1) - rx2 * ry2
begin
set_pixel(x + dx, y + dy, color)
set_pixel(x + dx, y - dy, color)
set_pixel(x - dx, y - dy, color)
set_pixel(x - dx, y + dy, color)
if f and dx > 1 and dy < rad_y and last_dy != dy
last_dy = dy
fill_rect(x - dx + 1, y - dy, (dx << 1) - 1, 1, f)
fill_rect(x - dx + 1, y + dy, (dx << 1) - 1, 1, f2)
if fill2
f.set(f.red + dr, f.green + dg, f.blue + db, f.alpha + da)
f2.set(f2.red - dr, f2.green - dg, f2.blue - db, f2.alpha - da)
end
end
if d <= -1e-6
d += ry2 * (dx + 1 << 1) + rx2 * (3 - (dy << 1))
dx += 1
else
d += rx2 * (3 - (dy << 1))
end
dy -= 1
end while dy >= 0
end
#--------------------------------------------------------------------------
# ● 绘制实心圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad : 半径
# border_color : 圆的边框颜色 (Color)
# fill_color1 : 填充渐变的上颜色 (Color)
# fill_color2 : 填充渐变的下颜色 (Color)
#--------------------------------------------------------------------------
def fill_circle(x, y, rad, border_color, fill_color1 = border_color,
fill_color2 = fill_color1)
draw_ellipse(x, y, rad, rad, border_color, fill_color1, fill_color2)
end
#--------------------------------------------------------------------------
# ● 绘制实心椭圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad_x : 水平半径
# rad_y : 垂直半径
# border_color : 椭圆的边框颜色 (Color)
# fill_color1 : 填充渐变的上颜色 (Color)
# fill_color2 : 填充渐变的下颜色 (Color)
#--------------------------------------------------------------------------
def fill_ellipse(x, y, rad_x, rad_y, border_color, fill_color1 =
border_color, fill_color2 = fill_color1)
draw_ellipse(x, y, rad_x, rad_y, border_color, fill_color1, fill_color2)
end
#--------------------------------------------------------------------------
# ● 传送位图圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad : 半径
# src_bitmap : 传送元位图
# x0 : 传送圆心 X 坐标
# y0 : 传送圆心 Y 坐标
# opacity : 不透明度
#--------------------------------------------------------------------------
def blt_circle(x, y, rad, src_bitmap, x0, y0, opacity = 255)
blt_ellipse(x, y, rad, rad, src_bitmap, x0, y0, opacity)
end
#--------------------------------------------------------------------------
# ● 传送位图椭圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad_x : 水平半径
# rad_y : 垂直半径
# src_bitmap : 传送元位图
# x0 : 传送圆心 X 坐标
# y0 : 传送圆心 Y 坐标
# opacity : 不透明度
#--------------------------------------------------------------------------
def blt_ellipse(x, y, rad_x, rad_y, src_bitmap, x0, y0, opacity = 255)
raise ArgumentError if rad_x < 0 or rad_y < 0
return blt(x - rad_x, y, src_bitmap, Rect.new(x0 - rad_x, y0,
rad_x << 1, 1), opacity) if rad_y == 0
return blt(x, y - rad_y, src_bitmap, Rect.new(x0, y0 - rad_y,
1, rad_y << 1), opacity) if rad_x == 0
ry2 = rad_y * rad_y
rx2 = rad_x * rad_x
d = ry2 + rx2 * (0.25 - rad_y)
dx = 0
dy = rad_y
last_dy = nil
begin
if last_dy != dy
last_dy = dy
blt(x - dx + 1, y - dy, src_bitmap, Rect.new(x0 - dx + 1, y0 - dy,
(dx << 1) - 1, 1), opacity)
blt(x - dx + 1, y + dy, src_bitmap, Rect.new(x0 - dx + 1, y0 + dy,
(dx << 1) - 1, 1), opacity)
end
if d <= -1e-6
d += ry2 * ((dx << 1) + 3)
else
d += ry2 * ((dx << 1) + 3) + rx2 * (1 - dy << 1)
dy -= 1
end
dx += 1
end while ry2 * (dx + 1) < rx2 * (dy - 0.5)
d = ry2 * (dx + 0.5) * (dx + 0.5) + rx2 * (dy - 1) * (dy - 1) - rx2 * ry2
begin
if last_dy != dy
last_dy = dy
blt(x - dx + 1, y - dy, src_bitmap, Rect.new(x0 - dx + 1, y0 - dy,
(dx << 1) - 1, 1), opacity)
blt(x - dx + 1, y + dy, src_bitmap, Rect.new(x0 - dx + 1, y0 + dy,
(dx << 1) - 1, 1), opacity)
end
if d <= -1e-6
d += ry2 * (dx + 1 << 1) + rx2 * (3 - (dy << 1))
dx += 1
else
d += rx2 * (3 - (dy << 1))
end
dy -= 1
end while dy >= 0
end
end
测试用的代码:
r = Sprite.new b = Bitmap.new(640, 480) r.bitmap = b b.gradient_draw_line(14, 41, 99, 78, Color.new(254, 243, 239), Color.new(37, 48, 65)) b.gradient_draw_line(99, 41, 14, 78, Color.new(254, 243, 239), Color.new(37, 48, 65)) b.gradient_draw_line(114, 78, 199, 41, Color.new(254, 243, 239), Color.new(37, 48, 65)) b.gradient_draw_line(199, 78, 114, 41, Color.new(254, 243, 239), Color.new(37, 48, 65)) b.fill_polygon(27,68,155,261,167,116,605,18,Color.new(255, 255, 255), Color.new(255,0,0), Color.new(232, 141, 232)) b.fill_ellipse(220,320,100,100,Color.new(255,255,255), Color.new(255, 0, 0), Color.new(0, 255, 0)) b.fill_isogon(320,240,85,7,45, Color.new(234,110,86), Color.new(0,78,89), Color.new(153, 57, 217)) b.draw_line(0, 420, 420, 420, Color.new(120,240,120), SailCat::Canvas_Config::CANVAS_LINE_BROKEN) r.x = 0 r.y = 0 loop do Graphics.update Input.update exit if Input.trigger?(Input::B) end
r = Sprite.new
b = Bitmap.new(640, 480)
r.bitmap = b
b.gradient_draw_line(14, 41, 99, 78, Color.new(254, 243, 239), Color.new(37, 48, 65))
b.gradient_draw_line(99, 41, 14, 78, Color.new(254, 243, 239), Color.new(37, 48, 65))
b.gradient_draw_line(114, 78, 199, 41, Color.new(254, 243, 239), Color.new(37, 48, 65))
b.gradient_draw_line(199, 78, 114, 41, Color.new(254, 243, 239), Color.new(37, 48, 65))
b.fill_polygon(27,68,155,261,167,116,605,18,Color.new(255, 255, 255), Color.new(255,0,0), Color.new(232, 141, 232))
b.fill_ellipse(220,320,100,100,Color.new(255,255,255), Color.new(255, 0, 0), Color.new(0, 255, 0))
b.fill_isogon(320,240,85,7,45, Color.new(234,110,86), Color.new(0,78,89), Color.new(153, 57, 217))
b.draw_line(0, 420, 420, 420, Color.new(120,240,120), SailCat::Canvas_Config::CANVAS_LINE_BROKEN)
r.x = 0
r.y = 0
loop do
Graphics.update
Input.update
exit if Input.trigger?(Input::B)
end
效率方面没有问题,毕竟全屏也就640x480而已,而填充矩形操作其实很快,横向渐变本质是填充1高矩形,所以很快……纵向我知道慢8倍左右所以就不做了……
实际效率测试(i7-1065G7)
Bitmap#draw_ellipse 画和屏幕一样大的椭圆,约40次/帧(1600次/秒)
Bitmap#fill_ellipse,填涂和屏幕一样大的椭圆(无渐变),约20次/帧(808次/秒)
Bitmap#fill_ellipse,填涂和屏幕一样大的椭圆(有渐变),约16次/帧(638次/秒)
Bitmap#draw_isogon,画和屏幕一样大的正十六边形,约31次/帧(1240次/秒)
Bitmap#fill_isogon,填涂和屏幕一样大的正十六边形,约8次/帧(292次/秒)
Bitmap#blt_isogon,裁切和屏幕一样大的正十六边形,约12次/帧(474次/秒)
评价一下
ruby的效率,实话说确实不能算高,尤其是1.x版本,这也是为什么RMXP把分辨率限在640x480,VX和VA为了做能到60帧/秒,把分辨率降到了544x416的原因,太大的屏幕确实很难渲染过来(VX和XP是一样的1.81,VA是1.92)
但ruby的效率虽然不高,内建的Bitmap提供的接口方法效率却并不差,因为很早之前我就测试过,单是set_pixel这一个操作,每一帧(注意是帧,不是秒,是1/40秒)可以做大几千次,get_pixel能做上万次
有童鞋说这没法和WINAPI32调RtlMovememory来比,那个不在我们的讨论范围里,想想我就是为了在屏幕上画点儿东西,犯得着上WinAPI32吗?
而且RGSS从1到3,Bitmap类的方法和存储方式连变都没有变过,不得不说这是十几年前的制作工具至少还算得上“能用”的一个好处了。
这次写的插件,其实真的就是随便写的(我最开始只是需要一个Bitmap#draw_line方法,写着写着就跑偏了……),不算后面blt(那个也就花了半小时)的修改,大概总体上用了三四个小时修改+调试
细节的优化之处肯定还存在,比如draw_ellipse里面那8个很扎眼的set_pixel,可以封装的,但是意义不大了。这种代码封装得好看点未必说效率就能多高。减少不必要的执行量才是最重要的。
我倒是没有想过大家这么热情,反复测试,菜刀还提出了实际的应用场景,看起来这确实还是有一些用的吧。
效率的话上面已经测试过了,实话说,两个字:够用。要知道连draw_text做“屏幕一样大的”文字渲染都能给你卡的要死要活的,我这里所有的测试都是直接上和屏幕一样大的绘图。
这里面draw系列的方法,其复杂度是o(w+h),说人话就是,和你绘制的图形的周长正相关,因为屏幕640+480=1120,所以你就是画满了一圈2240个点,事实上和屏幕一样大的不论是圆,椭圆,矩形还是别的什么,还真的就是2240个点
fill系列的方法(包括blt),其复杂度从算法上讲都是o(w*h),也就是说和你绘制的图形的面积正相关(废话,要填充啊),这个时候,set_pixel是绝对不能用了,一帧能做8000次,一秒就是480000次,一秒只能渲染一个半屏幕的像素,那样会卡到没法用。而这个前提是除了set_pixel什么也别做,什么也别计算。
但是这些fill的方法,涉及到查找边缘,正交等复杂数学算法,全都是慢的不行不行的浮点计算,所以一秒能渲染一个屏幕就是顶天了,卡一秒刷一个图片,绝对没法忍受。
幸好,所有的fill方法,我全部调用的是逐行填充的fill_rect,由于Bitmap内部的存储方式,做横行填充要比纵列填充快近8倍。所以默认的实现,全部都使用了横行填充的方式,不论你渐变还是不渐变。
事实上所有的计算机图形学教程也都是教你怎么横行填充,内存的速度是一方面,还有另一个纵列填充很要命的问题:数学计算没法表示tan90度的值,绕不开的,需要你自己写东西来特别处理
fill_rect已经被证明一帧可以在全屏尺度(640*1像素)上执行两千多次,所以这里在加了形状限制的情况下,连上计算,大约每帧能做十几次,已经足够用了。
因为你实际使用是不需要填涂这么大的矩形的
像draw_ellipse(320,240,320,240)一帧能做40次,那draw_ellipse(320,240,32,24)一帧也不过就是做400次
而fill_ellipse(320,240,320,240)一帧能16次,fill_ellipse(320,240,32,24)一帧能做的次数就有200次之多。菜刀那个50大小的头像,真的是随便渲染,还有以前我记得有人提出的半环式血条什么的,也是随便搞,完全都不会卡,大概就是在你渲染的时候帧率会从40变成38或者39这个样子。
要知道自写界面最卡的是什么?是Sprite的旋转和缩放,是永远回避不了的draw_text方法
而不是这些简单的2D绘图指令
感谢大家给了我动力,我可能会研究一波曲线的画法然后这几天更新出来
能不能用,相信你们的测试和兴趣已经说明,这个插件并没那么莫名其妙了
所以标题改啦~
另(理论上VA可以用,我没试,因为Bitmap结构是一样的,VA区的童鞋有兴趣可以拿走拿走别客气)
|
评分
-
查看全部评分
|