Skip to content
This repository has been archived by the owner on Jul 14, 2021. It is now read-only.

Commit

Permalink
Merge pull request #35 from JuliaPlots/sd-new_version
Browse files Browse the repository at this point in the history
new version
  • Loading branch information
SimonDanisch committed Jul 13, 2019
2 parents 3714714 + 4b5b502 commit a954fd8
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 127 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "GLMakie"
uuid = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
version = "0.0.6"
version = "0.0.7"

[deps]
AbstractPlotting = "537997a7-5e4e-5d89-9595-2241ea00577e"
Expand Down
5 changes: 5 additions & 0 deletions src/GLAbstraction/GLTypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ julia2glenum(x::Type{GLint}) = GL_INT
julia2glenum(x::Type{GLfloat}) = GL_FLOAT
julia2glenum(x::Type{GLdouble}) = GL_DOUBLE
julia2glenum(x::Type{Float16}) = GL_HALF_FLOAT

struct DepthStencil_24_8 <: Real end
Base.eltype(::Type{<: DepthStencil_24_8}) = DepthStencil_24_8
julia2glenum(x::Type{DepthStencil_24_8}) = GL_UNSIGNED_INT_24_8

function julia2glenum(::Type{T}) where T
error("Type: $T not supported as opengl number datatype")
end
Expand Down
9 changes: 5 additions & 4 deletions src/drawing_primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -378,19 +378,20 @@ function surface_contours(volume::Volume)
shader = makieshader(paths..., frag)
model = volume[:model]
x, y, z, vol = volume[1], volume[2], volume[3], volume[4]
model2 = lift(model, x, y, z) do m, xyz...
model2 = lift(x, y, z) do xyz...
mi = minimum.(xyz)
maxi = maximum.(xyz)
w = maxi .- mi
m2 = Mat4f0(
return Mat4f0(
w[1], 0, 0, 0,
0, w[2], 0, 0,
0, 0, w[3], 0,
mi[1], mi[2], mi[3], 1
)
convert(Mat4f0, m) * m2
end
modelinv = lift(inv, model2)

modelinv = lift((a,b)-> inv(b) * inv(a), model, model2)
model2 = lift(*, model, model2)
hull = AABB{Float32}(Vec3f0(0), Vec3f0(1))
gl_data = Dict(
:hull => GLUVWMesh(hull),
Expand Down
11 changes: 5 additions & 6 deletions src/glwindow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ function (sp::PostprocessPrerender)()
glDepthMask(GL_TRUE)
glDisable(GL_DEPTH_TEST)
glDisable(GL_BLEND)
glDisable(GL_STENCIL_TEST)
glStencilMask(0xff)
glDisable(GL_CULL_FACE)
nothing
end
Expand All @@ -31,7 +29,7 @@ mutable struct GLFramebuffer
id ::NTuple{2, GLuint}
color ::Texture{RGBA{N0f8}, 2}
objectid ::Texture{Vec{2, GLushort}, 2}
depth ::Texture{Float32, 2}
depth ::Texture{GLAbstraction.DepthStencil_24_8, 2}
color_luma ::Texture{RGBA{N0f8}, 2}
postprocess::NTuple{3, PostProcessROBJ}
end
Expand Down Expand Up @@ -104,16 +102,17 @@ function GLFramebuffer(fb_size::NTuple{2, Int})
objectid_buffer = Texture(Vec{2, GLushort}, fb_size, minfilter = :nearest, x_repeat = :clamp_to_edge)

depth_buffer = Texture(
Float32, fb_size,
Ptr{GLAbstraction.DepthStencil_24_8}(C_NULL), fb_size,
minfilter = :nearest, x_repeat = :clamp_to_edge,
internalformat = GL_DEPTH_COMPONENT32F,
format = GL_DEPTH_COMPONENT
internalformat = GL_DEPTH24_STENCIL8,
format = GL_DEPTH_STENCIL
)


attach_framebuffer(color_buffer, GL_COLOR_ATTACHMENT0)
attach_framebuffer(objectid_buffer, GL_COLOR_ATTACHMENT1)
attach_framebuffer(depth_buffer, GL_DEPTH_ATTACHMENT)
attach_framebuffer(depth_buffer, GL_STENCIL_ATTACHMENT)

status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
@assert status == GL_FRAMEBUFFER_COMPLETE
Expand Down
98 changes: 66 additions & 32 deletions src/rendering.jl
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
function renderloop(screen::Screen; framerate = 1/30, prerender = () -> nothing)
try
while isopen(screen)
t = time()
GLFW.PollEvents() # GLFW poll
prerender()
make_context_current(screen)
render_frame(screen)
GLFW.SwapBuffers(to_native(screen))
diff = framerate - (time() - t)
if diff > 0
sleep(diff)
else # if we don't sleep, we need to yield explicitely
yield()
# Somehow errors get sometimes ignored, so we at least print them here
try
t = time()
GLFW.PollEvents() # GLFW poll
prerender()
make_context_current(screen)
render_frame(screen)
GLFW.SwapBuffers(to_native(screen))
diff = framerate - (time() - t)
if diff > 0
sleep(diff)
else # if we don't sleep, we need to yield explicitely
yield()
end
catch e
@error "Error in renderloop!" exception=e
rethrow(e)
end
end
catch e
destroy!(screen)
@error "Error in renderloop!" exception=e
rethrow(e)
finally
destroy!(screen)
end
destroy!(screen)
return
end

Expand All @@ -35,11 +42,14 @@ function setup!(screen)
a = rect[]
rt = (minimum(a)..., widths(a)...)
glViewport(rt...)
bits = GL_STENCIL_BUFFER_BIT
glClearStencil(id)
if clear[]
c = color[]
glScissor(rt...)
glClearColor(red(c), green(c), blue(c), alpha(c))
glClear(GL_COLOR_BUFFER_BIT)
bits |= GL_COLOR_BUFFER_BIT
glClear(bits)
end
end
end
Expand All @@ -60,15 +70,24 @@ function render_frame(screen::Screen)
wh = Int.(framebuffer_size(nw))
resize!(fb, wh)
w, h = wh
glDisable(GL_STENCIL_TEST)
glEnable(GL_STENCIL_TEST)
#prepare for geometry in need of anti aliasing
glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) # color framebuffer
glDrawBuffers(2, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1])
glEnable(GL_STENCIL_TEST)
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)
glStencilMask(0xff)
glClearStencil(0)
glClearColor(0,0,0,0)
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT)
setup!(screen)

glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)
glStencilMask(0x00)
GLAbstraction.render(screen, true)
glDisable(GL_STENCIL_TEST)

# transfer color to luma buffer and apply fxaa
glBindFramebuffer(GL_FRAMEBUFFER, fb.id[2]) # luma framebuffer
glDrawBuffer(GL_COLOR_ATTACHMENT0)
Expand All @@ -85,12 +104,11 @@ function render_frame(screen::Screen)
#prepare for non anti aliased pass
glDrawBuffers(2, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1])

glEnable(GL_STENCIL_TEST)
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)
glStencilMask(0x00)
GLAbstraction.render(screen, false)
#Read all the selection queries
glReadBuffer(GL_COLOR_ATTACHMENT1)
for query_func in selection_queries
query_func(fb.objectid, w, h)
end
glDisable(GL_STENCIL_TEST)
glBindFramebuffer(GL_FRAMEBUFFER, 0) # transfer back to window
glViewport(0, 0, w, h)
glClearColor(0, 0, 0, 0)
Expand All @@ -102,23 +120,39 @@ end
function id2rect(screen, id1)
# TODO maybe we should use a different data structure
for (id2, rect, clear, color) in screen.screens
id1 == id2 && return true, rect
id1 == id2 && return true, rect, clear[]
end
false, IRect(0,0,0,0)
false, IRect(0,0,0,0), false
end

function GLAbstraction.render(screen::Screen, fxaa::Bool)
for (zindex, screenid, elem) in screen.renderlist
found, rect = id2rect(screen, screenid)
found || continue
a = rect[]
glViewport(minimum(a)..., widths(a)...)
if fxaa && elem[:fxaa][]
render(elem)
end
if !fxaa && !elem[:fxaa][]
render(elem)
# Somehow errors in here get ignored silently!?
try
# sort by overdraw, so that overdrawing objects get drawn last!
# sort!(screen.renderlist, by = ((zi, id, robj),)-> robj.prerenderfunction.overdraw[])
for (zindex, screenid, elem) in screen.renderlist
found, rect, clear = id2rect(screen, screenid)
found || continue
a = rect[]
glViewport(minimum(a)..., widths(a)...)
if clear
glStencilFunc(GL_EQUAL, screenid, 0xff)
else
# if we don't clear, that means we have a screen that is overlaid
# on top of another, which means it doesn't have a stencil value
# so we can't do the stencil test
glStencilFunc(GL_ALWAYS, screenid, 0xff)
end
if fxaa && elem[:fxaa][]
render(elem)
end
if !fxaa && !elem[:fxaa][]
render(elem)
end
end
catch e
@error "Error while rendering!" exception=e
rethrow(e)
end
return
end
95 changes: 11 additions & 84 deletions src/screen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ end
GeometryTypes.widths(x::Screen) = size(x.framebuffer.color)

Base.wait(x::Screen) = isassigned(x.rendertask) && wait(x.rendertask[])
Base.wait(scene::Scene) = wait(global_gl_screen()) # TODO per scene screen
Base.wait(scene::Scene) = wait(AbstractPlotting.getscreen(scene))
Base.show(io::IO, screen::Screen) = print(io, "GLMakie.Screen(...)")
Base.size(x::Screen) = size(x.framebuffer)

Expand Down Expand Up @@ -337,18 +337,14 @@ function global_gl_screen(resolution::Tuple, visibility::Bool, tries = 1)
screen
end

# TODO per scene screen
getscreen(scene) = global_gl_screen()

function pick_native(scene::SceneLike, xy::VectorTypes{2}, sid = Base.RefValue{SelectionID{UInt16}}())
screen = getscreen(scene)
screen == nothing && return SelectionID{Int}(0, 0)
function pick_native(screen::Screen, xy::Vec{2, Float64})
sid = Base.RefValue{SelectionID{UInt16}}()
window_size = widths(screen)
fb = screen.framebuffer
buff = fb.objectid
glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1])
glReadBuffer(GL_COLOR_ATTACHMENT1)
x, y = Int.(floor.(xy))
x, y = floor.(Int, xy)
w, h = window_size
if x > 0 && y > 0 && x <= w && y <= h
glReadPixels(x, y, 1, 1, buff.format, buff.pixeltype, sid)
Expand All @@ -357,87 +353,18 @@ function pick_native(scene::SceneLike, xy::VectorTypes{2}, sid = Base.RefValue{S
return SelectionID{Int}(0, 0)
end

pick(scene::SceneLike, xy...) = pick(scene, Float64.(xy))

function pick(scene::SceneLike, xy::VectorTypes{2})
sid = pick_native(scene, xy)
screen = getscreen(scene)
if screen != nothing && haskey(screen.cache2plot, sid.id)
function AbstractPlotting.pick(scene::SceneLike, screen::Screen, xy::Vec{2, Float64})
sid = pick_native(screen, xy)
if haskey(screen.cache2plot, sid.id)
plot = screen.cache2plot[sid.id]
return (plot, sid.index)
end
return (nothing, 0)
end

# TODO does this actually needs to be a global?
const _mouse_selection_id = Base.RefValue{SelectionID{UInt16}}()
function mouse_selection_native(scene::SceneLike)
function query_mouse(buff, w, h)
xy = events(scene).mouseposition[]
x, y = Int.(floor.(xy))
if x > 0 && y > 0 && x <= w && y <= h
glReadPixels(x, y, 1, 1, buff.format, buff.pixeltype, _mouse_selection_id)
end
return
end
if !(query_mouse in selection_queries)
push!(selection_queries, query_mouse)
# TODO, this is not optimal since it does way more
# than calling query_mouse() on first click,
# but otherwise it might get into an inconsistent state.
render_frame(getscreen(scene))
end
convert(SelectionID{Int}, _mouse_selection_id[])
end

function mouse_selection(scene::SceneLike)
sid = mouse_selection_native(scene)
screen = getscreen(scene)
if screen != nothing && haskey(screen.cache2plot, sid.id)
plot = screen.cache2plot[sid.id]
return (plot, sid.index)
end
return (nothing, 0)
end

function mouseover(scene::SceneLike, plots::AbstractPlot...)
p, idx = mouse_selection(scene)
p in flatten_plots(plots)
end

function flatten_plots(x::Atomic, plots = AbstractPlot[])
if isempty(x.plots)
push!(plots, x)
else
flatten_plots(x.plots, plots)
end
plots
end

function flatten_plots(x::Combined, plots = AbstractPlot[])
for elem in x.plots
flatten_plots(elem, plots)
end
plots
end

function flatten_plots(array, plots = AbstractPlot[])
for elem in array
flatten_plots(elem, plots)
return (nothing, 0)
end
plots
end

function onpick(f, scene::SceneLike, plots::AbstractPlot...)
fplots = flatten_plots(plots)
map_once(events(scene).mouseposition) do mp
p, idx = mouse_selection(scene)
(p in fplots) && f(idx)
return
end
end

function pick(screen::Screen, rect::IRect2D)
function AbstractPlotting.pick(screen::Screen, rect::IRect2D)
window_size = widths(screen)
buff = screen.framebuffer.objectid
sid = zeros(SelectionID{UInt16}, widths(rect)...)
Expand All @@ -448,8 +375,8 @@ function pick(screen::Screen, rect::IRect2D)
if x > 0 && y > 0 && x <= w && y <= h
glReadPixels(x, y, rw, rh, buff.format, buff.pixeltype, sid)
return map(unique(vec(SelectionID{Int}.(sid)))) do sid
screen.cache2plot[sid.id], Int(sid.index)
(screen.cache2plot[sid.id], sid.index)
end
end
return SelectionID{Int}[]
return Tuple{AbstractPlot, Int}[]
end

0 comments on commit a954fd8

Please sign in to comment.