You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

85 lines
3.7 KiB

module Squib
class Deck
# So the Cairo people have said over and over again that they won't support the 3x3 matrices that would handle perspective transforms.
# Since our perspective transform needs are a bit simpler, we can use a "striping method" that does the job for us.
# It's a little bit involved, but it works well enough for limited ranges of our parameters.
# These were also helpful:
# http://kapo-cpp.blogspot.com/2008/01/perspective-effect-using-cairo.html
# http://zetcode.com/gui/pygtk/drawingII/
# :nodoc:
# @api private
def render_showcase(range,
trim, trim_radius, scale, offset, fill_color,
reflect_offset, reflect_percent, reflect_strength, margin, face_right,
dir, file_to_save)
out_width = range.size * ((@width - 2*trim) * scale * offset) + 2*margin
out_height = reflect_offset + (1.0 + reflect_percent) * (@height - 2*trim) + 2*margin
out_cc = Cairo::Context.new(Cairo::ImageSurface.new(out_width, out_height))
out_cc.set_source_color(fill_color)
out_cc.paint
cards = range.collect { |i| @cards[i] }
cards.each_with_index do |card, i|
trimmed = trim_rounded(card.cairo_surface, trim, trim_radius)
reflected = reflect(trimmed, reflect_offset, reflect_percent, reflect_strength)
perspectived = perspective(reflected, scale, face_right)
out_cc.set_source(perspectived, margin + i * perspectived.width * offset, margin)
out_cc.paint
end
out_cc.target.write_to_png("#{dir}/#{file_to_save}")
end
# :nodoc:
# @api private
def trim_rounded(src, trim, radius)
trim_cc = Cairo::Context.new(Cairo::ImageSurface.new(src.width-2.0*trim, src.height-2.0*trim))
trim_cc.rounded_rectangle(0, 0, trim_cc.target.width, trim_cc.target.height, radius, radius)
trim_cc.set_source(src, -1 * trim, -1 * trim)
trim_cc.clip
trim_cc.paint
return trim_cc.target
end
# :nodoc:
# @api private
def reflect(src, roffset, rpercent, rstrength)
tmp_cc = Cairo::Context.new(Cairo::ImageSurface.new(src.width, src.height * (1.0 + rpercent) + roffset))
tmp_cc.set_source(src, 0, 0)
tmp_cc.paint
# Flip affine magic from: http://cairographics.org/matrix_transform/
matrix = Cairo::Matrix.new(1, 0, 0, -1, 0, 2 * src.height + roffset)
tmp_cc.transform(matrix) # flips the coordinate system
top_y = src.height # top of the reflection
bottom_y = src.height * (1.0 - rpercent) + roffset # bottom of the reflection
gradient = Cairo::LinearPattern.new(0,top_y, 0,bottom_y)
gradient.add_color_stop_rgba(0.0, 0,0,0, rstrength) # start a little reflected
gradient.add_color_stop_rgba(1.0, 0,0,0, 0.0) # fade to nothing
tmp_cc.set_source(src, 0, 0)
tmp_cc.mask(gradient)
return tmp_cc.target
end
# :nodoc:
# @api private
def perspective(src, scale, face_right)
dest_cxt = Cairo::Context.new(Cairo::ImageSurface.new(src.width * scale, src.height))
in_thickness = 1 # Take strip 1 pixel-width at a time
out_thickness = 3 # Scale it to 3 pixels wider to cover any gaps
(0..src.width).step(in_thickness) do |i|
percentage = i / src.width.to_f
i = src.width - i if face_right
factor = scale + (percentage * (1.0 - scale)) #linear interpolation
dest_cxt.save
dest_cxt.translate 0, src.height / 2.0 * (1.0 - factor)
dest_cxt.scale factor * scale, factor
dest_cxt.set_source src, 0, 0
dest_cxt.rounded_rectangle i, 0, out_thickness, src.height, 0,0
dest_cxt.fill
dest_cxt.restore
end
return dest_cxt.target
end
end
end