Drawing method which calls Cairo.CairoImageSurface(img)
oheil opened this issue · comments
Playing around with MiniFB and Luxor the currently only available Drawing methods turned out not to be the perfect match for MiniFB because the image buffer is copied a lot. But in Cairo.jl there is also:
CairoImageSurface(img::Matrix{T}) where {T<:Union{RGB24,ARGB32}}
where the image buffer is provided by the user.
So I forked Luxor and added this method to drawings.jl :
mutable struct Drawing
....
function Drawing(img::Matrix{T}; strokescale=false) where {T<:Union{RGB24,ARGB32}}
w,h = size(img)
bufdata = UInt8[]
iobuf = IOBuffer(bufdata, read=true, write=true)
the_surfacetype = :image
f = ""
the_surface = Cairo.CairoImageSurface(img)
the_cr = Cairo.CairoContext(the_surface)
currentdrawing = new(w, h, f, the_surface, the_cr, the_surfacetype, 0.0, 0.0, 0.0, 1.0, iobuf, bufdata, strokescale)
if isempty(CURRENTDRAWING)
push!(CURRENTDRAWING, currentdrawing)
else
CURRENTDRAWING[1] = currentdrawing
end
return currentdrawing
end
function Drawing(w, h, stype::Symbol, f::AbstractString=""; strokescale=false)
...
end
...
end
The following example shows an example which wasn't possible as smooth as it is now.
First, I wanted to have a MiniFB window which is updated automatically in the background and let's me put Luxor graphic commands at the REPL together with a FPS display as a layer on top without overwriting the image buffer:
using MiniFB, Luxor, Colors
WIDTH=800
HEIGHT=600
mutable struct MfbState
state::mfb_update_state
mousePressed::Int
end
stateArray=[MfbState( MiniFB.STATE_OK, 0 )]
window = mfb_open_ex("MiniFB", WIDTH, HEIGHT, MiniFB.WF_RESIZABLE)
function windowUpdateTask(window,buffer,stateArray,showFPS=false,singleCall=false)
sb=buffer[1:105,1:55]
stateArray[1].state=mfb_update(window,buffer)
updateCount=0
startTime=floor(Int,time())
fps="0"
while stateArray[1].state == MiniFB.STATE_OK && ! singleCall
if showFPS
elapsedTime=floor(Int,time())-startTime
if elapsedTime > 1
fps=string(round(Int,updateCount/elapsedTime))
startTime=floor(Int,time())
updateCount=0
end
sb.=buffer[1:105,1:55]
@layer begin
(dx,dy)=Point(0.0, 0.0)-getworldposition(Point(0.0, 0.0);centered=false)
setcolor((1.0, 0, 0, 0.5))
fontsize(50)
text(fps, Point(5+dx,5+dy), halign=:left, valign = :top)
end
end
stateArray[1].state=mfb_update(window,buffer)
if showFPS
buffer[1:105,1:55].=sb
end
sleep(1.0/120.0)
updateCount+=1
end
println("\nWindow closed\n")
end
buffer=zeros(ARGB32, WIDTH, HEIGHT)
d=Drawing(buffer)
@async windowUpdateTask(window,buffer,stateArray,true)
Now doing some graphics on the image buffer rendered directly in the MiniFB window.
Pressing "q" + "return" stops the while loop and brings you back to the REPL.
mutable struct Ball
position::Point
velocity::Point
end
origin()
function stick(w, h)
channel = Channel(10)
@async while true
kb = readline(stdin)
if contains(kb, "q")
put!(channel, 1)
break
end
end
colors=[rand(1:255),rand(1:255),rand(1:255)]
newcolors=[rand(1:255),rand(1:255),rand(1:255)]
c=ARGB(colors[1]/255,colors[2]/255,colors[3]/255,1.0)
balls=[Ball( rand(BoundingBox(Point(-w/2, -h/2), Point(w/2, h/2))), rand(BoundingBox(Point(-10, -10), Point(10, 10))) ) for _ in 1:2]
while true
background(0,0,0,0.05)
if colors == newcolors
newcolors=[rand(1:255),rand(1:255),rand(1:255)]
end
for (index,(col,newcol)) in enumerate(zip(colors,newcolors))
if col != newcol
col > newcol ? col-=1 : col+=1
colors[index]=col
end
end
c=ARGB(colors[1]/255,colors[2]/255,colors[3]/255,1.0)
for ball in balls
if !(-w/2 < ball.position.x < w/2)
ball.velocity = Point(-ball.velocity.x,ball.velocity.y)
end
if !(-h/2 < ball.position.y < h/2)
ball.velocity = Point(ball.velocity.x,-ball.velocity.y)
end
ball.position = ball.position + ball.velocity
end
setcolor(c)
line(balls[1].position,balls[2].position,:stroke)
sleep(1.0/120.0)
if isready(channel)
break
end
end
end
stick(WIDTH, HEIGHT)
What do you think? Do you see what I mean and why I think this is a nice way to expand on Luxor?
I can do a PR but for now, the state of my proposal is still a bit rough and needs some discussion.
It looks great! I don't use this bit of the package at all (except for answering queries
You might like to search through some of the old issues for "buffer" where people have asked about image buffer functionality, thread-safety, etc, just in case there are other considerations you haven't thought of.
Hm, thread-safety is surely nothing I can address on the way, snapshot and preview is something which would be nice to have if MiniFB is not used... I will have a look...
Closed via #233 - thanks!