-
Notifications
You must be signed in to change notification settings - Fork 34
Integration into Gtk or equivalent #195
Comments
Hi Loic, Best, |
I mad a prototype, which segfaults when I add sliders... I hope i can fix that tomorrow and get you started! |
Sounds awesome! Well, besides the segfault -- the most annoying word to see in a terminal ... I can also get started without the slider support if you want an independent validation of the current state of the prototype. Cheers |
Wonderful -- I'm gonna check it out |
First, this is beautiful! A couple follow ups ;):
It seems however that Is there an easy way to make that work or is that more deeply rooted into how GLVisualize work?
Thanks a bunch! |
I see what's going on. I cache the timer signal for each window to save some performance, but that needs to have a current screen (https://github.com/JuliaGL/GLVisualize.jl/blob/master/src/renderloop.jl#L90). 2.) That's the next step for the prototype. I already have code for Visualize.jl, but it uses the new trait system. I will need to rewrite it a bit to push into the signal dict. Here is the piece of code. What needs to be done is pretty much to replace all the function add!(window::GtkWindow, ::Type{Area})
function callback_w(widget::Gtk.GtkGLArea, width::Int32, height::Int32)
rect = window[Area]
window[Area] = IRect(minimum(rect), width, height)
return true
end
signal_connect(callback_w, window[Window], "Scroll")
add_events(window[Window], GConstants.GdkEventMask.SCROLL)
return
end
function add!(window::GtkWindow, ::Type{Mouse.Scroll})
function callback(widget::Gtk.GtkGLArea, s::Gtk.GdkEventScroll)
window[Scroll] = (s.x, s.y)
return true
end
signal_connect(callback, window[NativeWindow], "scroll-event")
add_events(window[NativeWindow], GConstants.GdkEventMask.SCROLL)
return
end
function add!(window::GtkWindow, ::Type{Mouse.Position})
function callback(widget::Gtk.GtkGLArea, s::Gtk.GdkEventMotion)
window[Mouse.Position] = (s.x, s.y)
return true
end
add_events(window[NativeWindow], GConstants.GdkEventMask.POINTER_MOTION)
signal_connect(callback, window[NativeWindow], "motion-notify-event")
return true
end
function to_mouse_button(x)
if x == 1
Mouse.left
elseif x == 2
Mouse.middle
elseif x == 3
Mouse.right
else
# TODO turn into error
warn("Button is $x, while $(Gtk.GdkModifierType.BUTTON1)")
Mouse.left
end
end
function add!(window::GtkWindow, ::Type{Mouse.Buttons})
function callback(widget::Gtk.GtkGLArea, event::Gtk.GdkEventButton)
button = to_mouse_button(event.button)
action = event.event_type
set = window[Mouse.Buttons]
if action in (GdkEventType.BUTTON_PRESS:GdkEventType.TRIPLE_BUTTON_PRESS)
push!(set, button)
elseif action == GdkEventType.BUTTON_RELEASE
delete!(set, button)
else
warn("unknown action: $(action)")
end
window[Mouse.Buttons] = set # trigger setfield event!
return true
end
add_events(window[NativeWindow],
GConstants.GdkEventMask.GDK_BUTTON_PRESS_MASK |
GConstants.GdkEventMask.GDK_BUTTON_RELEASE_MASK
)
signal_connect(callback, window[NativeWindow], "button_press_event")
signal_connect(callback, window[NativeWindow], "button_release_event")
return
end |
where renderloop is not happy:
|
Ah, didn't realize that you actually call
Just call them to start having GTK push to the signals in screen.inputs ;) |
That's because I added it after the fact ;) I tried without it first, the cat renders but it does not rotate. I attached the code in case it is supposed t work and something is off with my system. Ah, I'll play with that and see if I get it ! |
Ah sorry, forgot about Gtk trying to smartly render new frames, but that the signal update is actually opaque to it. So you need to insert using Gtk, GLWindow, GLAbstraction, Reactive, GeometryTypes, Colors, GLVisualize
using GtkReactive
using Gtk.GConstants, ModernGL
mutable struct GtkContext <: GLWindow.AbstractContext
window::Gtk.GLArea
framebuffer::GLWindow.GLFramebuffer
end
function make_context_current(screen::Screen)
gl_area = screen.glcontext.window
Gtk.make_current(gl_area)
end
GLWindow.isopen(x::Gtk.GLArea) = true
global screen = Ref{Screen}()
function init_screen(gl_area, resolution, mesh_color)
Gtk.make_current(gl_area)
gtk_context = GtkContext(gl_area, GLWindow.GLFramebuffer(Signal(resolution)))
window_area = Signal(SimpleRectangle(0, 0, resolution...))
signals = Dict(
:mouse_button_released => Reactive.Signal(0),
:mouse_buttons_pressed => Reactive.Signal(Set(Int[])),
:scroll => Reactive.Signal(Vec(0.0, 0.0)),
:buttons_pressed => Reactive.Signal(Set(Int[])),
:window_size => Reactive.Signal(Vec(resolution...)),
:window_area => window_area,
:cursor_position => Reactive.Signal(Vec(0.0,0.0)),
:mouseinside => Reactive.Signal(true),
:mouse_button_down => Reactive.Signal(0),
:mouseposition => Reactive.Signal(Vec(0.0, 0.0)),
:framebuffer_size => Reactive.Signal(Vec(resolution...)),
:button_down => Reactive.Signal(0),
:button_released => Reactive.Signal(0),
:window_open => Reactive.Signal(true),
:keyboard_buttons => Reactive.Signal((0,0,0,0)),
:mouse2id => Signal(GLWindow.SelectionID{Int}(-1, -1))
)
screen[] = Screen(
Symbol("GLVisualize"), window_area, nothing,
Screen[], signals,
(), false, true, RGBA(1f0,1f0,1f0,1f0), (0f0, RGBA(0f0,0f0,0f0,0f0)),
Dict{Symbol, Any}(),
gtk_context
)
GLVisualize.add_screen(screen[])
timesignal = loop(linspace(0f0,1f0,360))
rotation_angle = const_lift(*, timesignal, 2f0*pi)
start_rotation = Signal(rotationmatrix_x(deg2rad(90f0)))
rotation = map(rotationmatrix_y, rotation_angle)
final_rotation = map(*, start_rotation, rotation)
foreach(final_rotation) do x
# render a frame each time rotation updates
Gtk.queue_render(gl_area)
return
end
_view(visualize(loadasset("cat.obj"), color = mesh_color, model = final_rotation), screen[])
# renderloop(screen[])
end
function render_gtk(window, gtk_area)
!isopen(window) && return
fb = GLWindow.framebuffer(window)
wh = GeometryTypes.widths(window)
resize!(fb, wh)
w, h = wh
#prepare for geometry in need of anti aliasing
glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) # color framebuffer
glDrawBuffers(2, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1])
# setup stencil and backgrounds
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)
glEnable(GL_SCISSOR_TEST)
GLWindow.setup_window(window, false)
glDisable(GL_SCISSOR_TEST)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
# deactivate stencil write
glEnable(GL_STENCIL_TEST)
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)
glStencilMask(0x00)
GLAbstraction.render(window, 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)
glClearColor(0,0,0,0)
glClear(GL_COLOR_BUFFER_BIT)
glViewport(0, 0, w, h)
GLAbstraction.render(fb.postprocess[1]) # add luma and preprocess
glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) # transfer to non fxaa framebuffer
glDrawBuffer(GL_COLOR_ATTACHMENT0)
GLAbstraction.render(fb.postprocess[2]) # copy with fxaa postprocess
#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(window, false)
glDisable(GL_STENCIL_TEST)
# draw strokes
glEnable(GL_SCISSOR_TEST)
GLWindow.setup_window(window, true)
glDisable(GL_SCISSOR_TEST)
glViewport(0,0, wh...)
#Read all the selection queries
GLWindow.push_selectionqueries!(window)
Gtk.attach_buffers(gtk_area) # transfer back to window
glClearColor(0,0,0,0)
glClear(GL_COLOR_BUFFER_BIT)
GLAbstraction.render(fb.postprocess[3]) # copy postprocess
return
end
function connect_renderloop(gl_area, resolution, mesh_color)
end
function setup_screen()
resolution = (600, 500)
name = "GTK + GLVisualize"
parent = Gtk.Window(name, resolution..., true, true)
Gtk.visible(parent, true)
Gtk.setproperty!(parent, Symbol("is-focus"), false)
box = Gtk.Box(:v)
push!(parent, box)
# sl = GtkReactive.slider(linspace(0.0, 1.0, 100))
# push!(box, sl)
# mesh_color = map(sl) do val
# RGBA{Float32}(val, 0,0,1)
# end
mesh_color = Signal(RGBA{Float32}(1,0,0,1))
gl_area = Gtk.GLArea()
Gtk.gl_area_set_required_version(gl_area, 3, 3)
GLAbstraction.new_context()
push!(box, gl_area)
Gtk.setproperty!(box, :expand, gl_area, true)
Gtk.showall(parent)
Gtk.signal_connect(gl_area, "render") do gl_area, gdk_context
if !isassigned(screen)
init_screen(gl_area, resolution, mesh_color)
end
render_gtk(screen[], gl_area)
glFlush()
return false
end
return parent
end
parent = setup_screen();
Gtk.showall(parent) |
Nice! It works! As for the mouse interactions, something like: (I commented in the code things I am not sure about)
Similar question with |
Looks good! Some changes: function addScroll!(window::GLWindow.Screen)
function callback_w(widget::Gtk.GtkGLArea, width::Int32, height::Int32)
rect_signal = window.inputs[:window_area]
push!(rect_signal, IRect(minimum(value(rect_signal)), width, height) )
return true
end
gl_area = window.glcontext.window # the Gtk.gl_area
signal_connect(callback_w, gl_area, "Scroll")
add_events(gl_area, GConstants.GdkEventMask.SCROLL) # same
return
end |
hahaha I was missing quite a few pieces. |
Ah, you changed the value in It needs to be: "scroll-event", not "Scroll".... Zoom, etc should come automatically once the window signals are "live". |
Hi Simon! I finally have some time to get back to implementing Gtk + GLVisualize, yay! And it's starting to work but I have a few problems I cannot seem to get passed for 1) mouse interactions, 2) plotting after the initial screen set up. I modified the prototype to have these features in, as well as a basic gtk gui to experiment with. Nominally, this code will render a red cat on the bottom right half screen and a cat with the user defined color on the top half upon pressing the "visualize!" button.
julia> 1 : #version 150
2 :
3 : #extension GL_ARB_conservative_depth: enable
4 : #define DETPH_LAYOUT
5 :
6 : layout(location=0) out vec4 fragment_color;
7 : layout(location=1) out uvec2 fragment_groupid;
8 :
9 : #ifdef DEPTH_LAYOUT
10 : layout (depth_greater) out float gl_FragDepth;
11 : #endif
12 : void write2framebuffer(vec4 color, uvec2 id){
13 : fragment_color = color;
14 : if (color.a > 0.5){
15 : gl_FragDepth = gl_FragCoord.z;
16 : }else{
17 : gl_FragDepth = 1.0;
18 : }
19 : fragment_groupid = id;
20 : }
21 :
WARNING: shader C:\Users\astrolabsVR\.julia\v0.6\GLVisualize\src\..\assets\shader\fragment_output.frag didn't compile.
0(6) : error C7548: 'layout(location)' requires "#extension GL_ARB_explicit_attrib_location : enable" before use
0(6) : error C0000: ... or #extension GL_ARB_separate_shader_objects : enable
0(6) : error C0000: ... or #version 330
0(7) : error C7548: 'layout(location)' requires "#extension GL_ARB_explicit_attrib_location : enable" before use
0(7) : error C0000: ... or #extension GL_ARB_separate_shader_objects : enable
0(7) : error C0000: ... or #version 330
WARNING: Executing #1:
ERROR: program 28 not linked. Error in:
C:\Users\astrolabsVR\.julia\v0.6\GLVisualize\src\..\assets\shader\fragment_output.frag or C:\Users\astrolabsVR\.julia\v0.6\GLVisualize\src\..\assets\shader\util.vert or C:\Users\astrolabsVR\.julia\v0.6\GLVisualize\src\..\assets\shader\standard.vert or C:\Users\astrolabsVR\.julia\v0.6\GLVisualize\src\..\assets\shader\standard.frag
Fragment info
-------------
0(6) : error C7548: 'layout(location)' requires "#extension GL_ARB_explicit_attrib_location : enable" before use
0(6) : error C0000: ... or #extension GL_ARB_separate_shader_objects : enable
0(6) : error C0000: ... or #version 330
0(7) : error C7548: 'layout(location)' requires "#extension GL_ARB_explicit_attrib_location : enable" before use
0(7) : error C0000: ... or #extension GL_ARB_separate_shader_objects : enable
0(7) : error C0000: ... or #version 330
(0) : error C2003: incompatible options for link
Stacktrace:
[1] compile_program(::Array{GLAbstraction.Shader,1}, ::Array{Tuple{Int64,String},1}) at C:\Users\astrolabsVR\.julia\v0.6\GLAbstraction\src\GLShader.jl:205
[2] (::GLAbstraction.##76#82{Dict{Symbol,Any},NTuple{4,String}})() at C:\Users\astrolabsVR\.julia\v0.6\GLAbstraction\src\GLShader.jl:270
[3] get!(::GLAbstraction.##76#82{Dict{Symbol,Any},NTuple{4,String}}, ::Dict{Any,GLAbstraction.GLProgram}, ::Tuple{NTuple{4,String},Array{Array{String,1},1}}) at .\dict.jl:449
[4] gl_convert(::GLVisualize.GLVisualizeShader, ::Dict{Symbol,Any}) at C:\Users\astrolabsVR\.julia\v0.6\GLAbstraction\src\GLShader.jl:262
[5] GLAbstraction.RenderObject(::Dict{Symbol,Any}, ::GLVisualize.GLVisualizeShader, ::GLAbstraction.StandardPrerender, ::Void, ::Reactive.Signal{GeometryTypes.HyperRectangle{3,Float32}}, ::Void) at C:\Users\astrolabsVR\.julia\v0.6\GLAbstraction\src\GLTypes.jl:309
[6] assemble_robj(::Dict{Symbol,Any}, ::GLVisualize.GLVisualizeShader, ::Reactive.Signal{GeometryTypes.HyperRectangle{3,Float32}}, ::UInt32, ::Void, ::Void) at C:\Users\astrolabsVR\.julia\v0.6\GLVisualize\src\utils.jl:36
[7] assemble_shader(::Dict{Symbol,Any}) at C:\Users\astrolabsVR\.julia\v0.6\GLVisualize\src\utils.jl:63
[8] visualize(::Any, ::GLAbstraction.Style{:default}, ::Dict{Symbol,Any}) at C:\Users\astrolabsVR\.julia\v0.6\GLVisualize\src\visualize_interface.jl:21
[9] (::GLVisualize.#kw##visualize)(::Array{Any,1}, ::GLVisualize.#visualize, ::Any, ::Symbol) at .\<missing>:0 (repeats 2 times)
[10] viz_test(::ColorTypes.RGBA{Float32}, ::GLWindow.Screen) at D:\Loic\DSAT\dev\test.jl:279
[11] (::##1#2{Gtk.GtkScaleLeaf,Gtk.GtkScaleLeaf})(::Gtk.GtkButtonLeaf) at D:\Loic\DSAT\dev\test.jl:33
[12] (::Gtk.GLib.##91#93{Ptr{Gtk.GLib.GValue},UInt32,Ptr{Gtk.GLib.GValue}})() at C:\Users\astrolabsVR\.julia\v0.6\Gtk\src\GLib\signals.jl:88
[13] g_siginterruptible(::Gtk.GLib.##91#93{Ptr{Gtk.GLib.GValue},UInt32,Ptr{Gtk.GLib.GValue}}, ::Function) at C:\Users\astrolabsVR\.julia\v0.6\Gtk\src\GLib\signals.jl:207
[14] GClosureMarshal(::Ptr{Void}, ::Ptr{Gtk.GLib.GValue}, ::UInt32, ::Ptr{Gtk.GLib.GValue}, ::Ptr{Void}, ::Ptr{Void}) at C:\Users\astrolabsVR\.julia\v0.6\Gtk\src\GLib\signals.jl:59 Any insight much appreciated :) Thanks! The full code: # module gtk_glviz
# export openmainwind
using Gtk, GLWindow, GLAbstraction, Reactive, GeometryTypes, Colors, GLVisualize
using GtkReactive
using Gtk.GConstants, ModernGL
"""
A basic GTK gui for testing purpose -- some of the setup hacked from Simon's
prototype
"""
function openmainwind()
resolution = (1920, 1080)
name = "Test"
mainwin = Gtk.Window(name, resolution..., true, true)
Gtk.visible(mainwin, true)
Gtk.setproperty!(mainwin, Symbol("is-focus"), false)
glvizbox = Gtk.Box(:h)
guibox= Gtk.Box(:v)
a = GtkScale(false, 0:255)
b = GtkScale(false, 0:255)
c = GtkScale(false, 0:255)
vizbut = Gtk.Button("Visualize!")
# --- Signal to add another cat on second screen: fails!
vis_s = Gtk.signal_connect(vizbut,"clicked") do widget
r = getproperty(GtkAdjustment(a),:value,Int64)
g = getproperty(GtkAdjustment(b),:value,Int64)
b = getproperty(GtkAdjustment(c),:value,Int64)
mesh_color = RGBA{Float32}(r,g,b,1)
viz_test(mesh_color, sc2)
end
push!(guibox,a,b,c,vizbut)
push!(glvizbox, guibox) # not legenat but I am having trouble making it work wiht a grid
push!(mainwin,glvizbox)
viz = setup_screen()
push!(glvizbox, viz)
Gtk.setproperty!(glvizbox, :expand, viz, true)
return mainwin
# Gtk.showall(mainwin)
end
"""
Other misc. functions to make this work for multiple screens
"""
function y_part(area, percent)
amount = percent / 100.0
p = const_lift(area) do r
(
SimpleRectangle{Int}(r.x, r.y, r.w, round(Int, r.h*amount)),
SimpleRectangle{Int}(r.x, r.y+round(Int, r.h*amount), r.w, round(Int, r.h*(1-amount)))
)
end
return map(first, p), map(last, p)
end
function x_part(area, percent)
amount = percent / 100.0
p = const_lift(area) do r
(
SimpleRectangle{Int}(r.x, r.y, round(Int, r.w*amount), r.h ),
SimpleRectangle{Int}(r.x+round(Int, r.w*amount), r.y, round(Int, r.w*(1-amount)), r.h)
)
end
return map(first, p), map(last, p)
end
"""
Mouse events adapted from Simon's Visualize mod by Loic -- probably all wrong ...
"""
function addScrollEvt!(window::GLWindow.Screen)
function callback_w(widget::Gtk.GtkGLArea, width::Int32, height::Int32)
rect_signal = window.inputs[:window_area]
push!(rect_signal, IRect(minimum(value(rect_signal)), width, height) )
return true
end
gl_area = window.glcontext.window # the Gtk.gl_area
signal_connect(callback_w, gl_area, "scroll-event")
add_events(gl_area, GConstants.GdkEventMask.SCROLL) # same
return
end
function addScroll!(window::GLWindow.Screen)
function callback(widget::Gtk.GtkGLArea, s::Gtk.GdkEventScroll)
scro = window.inputs[:scroll]
push!(scro, (s.x, s.y))
return true
end
gl_area = window.glcontext.window # the Gtk.gl_area
signal_connect(callback, gl_area, "scroll-event")
add_events(gl_area, GConstants.GdkEventMask.SCROLL) # same
return
end
function addMouse!(window::GLWindow.Screen)
function callback(widget::Gtk.GtkGLArea, s::Gtk.GdkEventMotion)
pos = window.inputs[:mouseposition]
push!(pos,(s.x, s.y))
return true
end
gl_area = window.glcontext.window # the Gtk.gl_area
add_events(gl_area, GConstants.GdkEventMask.POINTER_MOTION)
signal_connect(callback, gl_area, "motion-notify-event")
return true
end
# function to_mouse_button(x)
# if x == 1
# Mouse.left
# elseif x == 2
# Mouse.middle
# elseif x == 3
# Mouse.right
# else
# # TODO turn into error
# warn("Button is $x, while $(Gtk.GdkModifierType.BUTTON1)")
# Mouse.left
# end
# end
# function addMouseBut!(window::GLWindow.Screen)
# function callback(widget::Gtk.GtkGLArea, event::Gtk.GdkEventButton)
# button = to_mouse_button(event.button)
# action = event.event_type
# set = window.inputs[:mouse_buttons]
# if action in (GdkEventType.BUTTON_PRESS:GdkEventType.TRIPLE_BUTTON_PRESS)
# push!(set, button)
# elseif action == GdkEventType.BUTTON_RELEASE
# delete!(set, button)
# else
# warn("unknown action: $(action)")
# end
# push!(window.inputs[:mouse_buttons],set) # trigger setfield event!
# return true
# end
# gl_area = window.glcontext.window # the Gtk.gl_area
# add_events(gl_area,
# GConstants.GdkEventMask.GDK_BUTTON_PRESS_MASK |
# GConstants.GdkEventMask.GDK_BUTTON_RELEASE_MASK
# )
# signal_connect(callback, gl_area, "button_press_event")
# signal_connect(callback, gl_area, "button_release_event")
# return
# end
"""
Simon's GTK + GLVISUALIZE prototype, modified by Loic for experimental purposes...
"""
mutable struct GtkContext <: GLWindow.AbstractContext
window::Gtk.GLArea
framebuffer::GLWindow.GLFramebuffer
end
function make_context_current(screen::Screen)
gl_area = screen.glcontext.window
Gtk.make_current(gl_area)
end
GLWindow.isopen(x::Gtk.GLArea) = true
global screen = Ref{Screen}()
function init_screen(gl_area, resolution, mesh_color)
Gtk.make_current(gl_area)
gtk_context = GtkContext(gl_area, GLWindow.GLFramebuffer(Signal(resolution)))
window_area = Signal(SimpleRectangle(0, 0, resolution...))
signals = Dict(
:mouse_button_released => Reactive.Signal(0),
:mouse_buttons_pressed => Reactive.Signal(Set(Int[])),
:scroll => Reactive.Signal(Vec(0.0, 0.0)),
:buttons_pressed => Reactive.Signal(Set(Int[])),
:window_size => Reactive.Signal(Vec(resolution...)),
:window_area => window_area,
:cursor_position => Reactive.Signal(Vec(0.0,0.0)),
:mouseinside => Reactive.Signal(true),
:mouse_button_down => Reactive.Signal(0),
:mouseposition => Reactive.Signal(Vec(0.0, 0.0)),
:framebuffer_size => Reactive.Signal(Vec(resolution...)),
:button_down => Reactive.Signal(0),
:button_released => Reactive.Signal(0),
:window_open => Reactive.Signal(true),
:keyboard_buttons => Reactive.Signal((0,0,0,0)),
:mouse2id => Signal(GLWindow.SelectionID{Int}(-1, -1))
)
screen[] = Screen(
Symbol("GLVisualize"), window_area, nothing,
Screen[], signals,
(), false, true, RGBA(1f0,1f0,1f0,1f0), (0f0, RGBA(0f0,0f0,0f0,0f0)),
Dict{Symbol, Any}(),
gtk_context
)
addScroll!(screen[])
addScrollEvt!(screen[])
GLVisualize.add_screen(screen[])
a1, a2 = y_part(screen[].area, 50)
global sc1
global sc2 # (failed) attempt to return "screens" from signal and plot more later
sc1 = Screen(screen[], area=a1)
sc2 = Screen(screen[], area=a2)
timesignal = viz_test(mesh_color, sc1)
foreach(timesignal) do x
# render a frame each time rotation updates
Gtk.queue_render(gl_area)
return
end
end
function render_gtk(window, gtk_area)
!isopen(window) && return
fb = GLWindow.framebuffer(window)
wh = GeometryTypes.widths(window)
resize!(fb, wh)
w, h = wh
#prepare for geometry in need of anti aliasing
glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) # color framebuffer
glDrawBuffers(2, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1])
# setup stencil and backgrounds
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)
glEnable(GL_SCISSOR_TEST)
GLWindow.setup_window(window, false)
glDisable(GL_SCISSOR_TEST)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
# deactivate stencil write
glEnable(GL_STENCIL_TEST)
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)
glStencilMask(0x00)
GLAbstraction.render(window, 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)
glClearColor(0,0,0,0)
glClear(GL_COLOR_BUFFER_BIT)
glViewport(0, 0, w, h)
GLAbstraction.render(fb.postprocess[1]) # add luma and preprocess
glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) # transfer to non fxaa framebuffer
glDrawBuffer(GL_COLOR_ATTACHMENT0)
GLAbstraction.render(fb.postprocess[2]) # copy with fxaa postprocess
#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(window, false)
glDisable(GL_STENCIL_TEST)
# draw strokes
glEnable(GL_SCISSOR_TEST)
GLWindow.setup_window(window, true)
glDisable(GL_SCISSOR_TEST)
glViewport(0,0, wh...)
#Read all the selection queries
GLWindow.push_selectionqueries!(window)
Gtk.attach_buffers(gtk_area) # transfer back to window
glClearColor(0,0,0,0)
glClear(GL_COLOR_BUFFER_BIT)
GLAbstraction.render(fb.postprocess[3]) # copy postprocess
return
end
function connect_renderloop(gl_area, resolution, mesh_color)
end
function viz_test(mesh_color, win)
timesignal = loop(linspace(0f0,1f0,360))
rotation_angle = const_lift(*, timesignal, 2f0*pi)
start_rotation = Signal(rotationmatrix_x(deg2rad(90f0)))
rotation = map(rotationmatrix_y, rotation_angle)
final_rotation = map(*, start_rotation, rotation)
_view(visualize(loadasset("cat.obj"), color = mesh_color, model = final_rotation), win)
return timesignal
end
function setup_screen()
resolution = (1920, 1080)
mesh_color = Signal(RGBA{Float32}(1,0,0,1))
gl_area = Gtk.GLArea()
Gtk.gl_area_set_required_version(gl_area, 3, 3)
GLAbstraction.new_context()
Gtk.signal_connect(gl_area, "render") do gl_area, gdk_context
if !isassigned(screen)
init_screen(gl_area, resolution, mesh_color)
end
render_gtk(screen[], gl_area)
glFlush()
return false
end
return gl_area
end
# end
# using Gtk
# using gtk_glviz
"""
Test run
"""
win = openmainwind()
Gtk.showall(win) |
so did you actually get around the segfault? |
You mean the one because of the slider that was intially in init_screen? If so, no. Haven't tried to fix it. The sliders and other elements I added are gtk widgets, to emulate my tool GUI and GLVisualize integration. I have however been battling with some odd behavior with GLWindow. On my Ubuntu box, this code I sent segfault, even with only the gtk GUI stuff, no GLVisualize, only gtk and GLWindow "imported". Runs fine on Windows. Even weirder, I have implemented the same prototype within my full fledged GUI and I cannot reproduce the segfault... Regardless, I'm stuck on the issues note above at the moment 😅 |
Hm, your MWE gives me a segfault :( |
I thought i could quickly debug this, but the code is a bit too magical for a quick debugging session. |
Yes -- for some reason Gtk and GLWindow don't seem to always play nice. Overall tho, as I am using both Windows and Ubuntu -- and if your are, too -- and are able to put together a quick fix for the issues mentioned above -- the seg fault on Linux notwithstanding -- that would be great! Loic |
The above shader problem is a bit hard to debug for me, since it segfaults ;) |
Ah of course. # module gtk_glviz
# export openmainwind
using Gtk, GLWindow, GLAbstraction, Reactive, GeometryTypes, Colors, GLVisualize
using GtkReactive
using Gtk.GConstants, ModernGL
"""
A basic GTK gui for testing purpose -- some of the setup hacked from Simon's
prototype
"""
function openmainwind()
resolution = (1920, 1080)
name = "Test"
mainwin = Gtk.Window(name, resolution..., true, true)
Gtk.visible(mainwin, true)
Gtk.setproperty!(mainwin, Symbol("is-focus"), false)
glvizbox = Gtk.Box(:h)
guibox= Gtk.Box(:v)
# a = GtkScale(false, 0:255)
# b = GtkScale(false, 0:255)
# c = GtkScale(false, 0:255)
vizbut = Gtk.Button("")
# --- Signal to add another cat on second screen: fails!
vis_s = Gtk.signal_connect(vizbut,"clicked") do widget
# r = getproperty(GtkAdjustment(a),:value,Int64)
# g = getproperty(GtkAdjustment(b),:value,Int64)
# b = getproperty(GtkAdjustment(c),:value,Int64)
# mesh_color = RGBA{Float32}(r,g,b,1)
mesh_color = Signal(RGBA{Float32}(1,0,0,1))
viz_test(mesh_color, sc2)
end
push!(guibox,vizbut)
# push!(guibox,a,b,c,vizbut)
push!(glvizbox, guibox) # not legenat but I am having trouble making it work wiht a grid
push!(mainwin,glvizbox)
viz = setup_screen()
push!(glvizbox, viz)
Gtk.setproperty!(glvizbox, :expand, viz, true)
return mainwin
# Gtk.showall(mainwin)
end
"""
Other misc. functions to make this work for multiple screens
"""
function y_part(area, percent)
amount = percent / 100.0
p = const_lift(area) do r
(
SimpleRectangle{Int}(r.x, r.y, r.w, round(Int, r.h*amount)),
SimpleRectangle{Int}(r.x, r.y+round(Int, r.h*amount), r.w, round(Int, r.h*(1-amount)))
)
end
return map(first, p), map(last, p)
end
function x_part(area, percent)
amount = percent / 100.0
p = const_lift(area) do r
(
SimpleRectangle{Int}(r.x, r.y, round(Int, r.w*amount), r.h ),
SimpleRectangle{Int}(r.x+round(Int, r.w*amount), r.y, round(Int, r.w*(1-amount)), r.h)
)
end
return map(first, p), map(last, p)
end
"""
Mouse events adapted from Simon's Visualize mod by Loic -- probably all wrong ...
"""
function addScrollEvt!(window::GLWindow.Screen)
function callback_w(widget::Gtk.GtkGLArea, width::Int32, height::Int32)
rect_signal = window.inputs[:window_area]
push!(rect_signal, IRect(minimum(value(rect_signal)), width, height) )
return true
end
gl_area = window.glcontext.window # the Gtk.gl_area
signal_connect(callback_w, gl_area, "scroll-event")
add_events(gl_area, GConstants.GdkEventMask.SCROLL) # same
return
end
function addScroll!(window::GLWindow.Screen)
function callback(widget::Gtk.GtkGLArea, s::Gtk.GdkEventScroll)
scro = window.inputs[:scroll]
push!(scro, (s.x, s.y))
return true
end
gl_area = window.glcontext.window # the Gtk.gl_area
signal_connect(callback, gl_area, "scroll-event")
add_events(gl_area, GConstants.GdkEventMask.SCROLL) # same
return
end
function addMouse!(window::GLWindow.Screen)
function callback(widget::Gtk.GtkGLArea, s::Gtk.GdkEventMotion)
pos = window.inputs[:mouseposition]
push!(pos,(s.x, s.y))
return true
end
gl_area = window.glcontext.window # the Gtk.gl_area
add_events(gl_area, GConstants.GdkEventMask.POINTER_MOTION)
signal_connect(callback, gl_area, "motion-notify-event")
return true
end
# function to_mouse_button(x)
# if x == 1
# Mouse.left
# elseif x == 2
# Mouse.middle
# elseif x == 3
# Mouse.right
# else
# # TODO turn into error
# warn("Button is $x, while $(Gtk.GdkModifierType.BUTTON1)")
# Mouse.left
# end
# end
# function addMouseBut!(window::GLWindow.Screen)
# function callback(widget::Gtk.GtkGLArea, event::Gtk.GdkEventButton)
# button = to_mouse_button(event.button)
# action = event.event_type
# set = window.inputs[:mouse_buttons]
# if action in (GdkEventType.BUTTON_PRESS:GdkEventType.TRIPLE_BUTTON_PRESS)
# push!(set, button)
# elseif action == GdkEventType.BUTTON_RELEASE
# delete!(set, button)
# else
# warn("unknown action: $(action)")
# end
# push!(window.inputs[:mouse_buttons],set) # trigger setfield event!
# return true
# end
# gl_area = window.glcontext.window # the Gtk.gl_area
# add_events(gl_area,
# GConstants.GdkEventMask.GDK_BUTTON_PRESS_MASK |
# GConstants.GdkEventMask.GDK_BUTTON_RELEASE_MASK
# )
# signal_connect(callback, gl_area, "button_press_event")
# signal_connect(callback, gl_area, "button_release_event")
# return
# end
"""
Simon's GTK + GLVISUALIZE prototype, modified by Loic for experimental purposes...
"""
mutable struct GtkContext <: GLWindow.AbstractContext
window::Gtk.GLArea
framebuffer::GLWindow.GLFramebuffer
end
function make_context_current(screen::Screen)
gl_area = screen.glcontext.window
Gtk.make_current(gl_area)
end
GLWindow.isopen(x::Gtk.GLArea) = true
global screen = Ref{Screen}()
function init_screen(gl_area, resolution, mesh_color)
Gtk.make_current(gl_area)
gtk_context = GtkContext(gl_area, GLWindow.GLFramebuffer(Signal(resolution)))
window_area = Signal(SimpleRectangle(0, 0, resolution...))
signals = Dict(
:mouse_button_released => Reactive.Signal(0),
:mouse_buttons_pressed => Reactive.Signal(Set(Int[])),
:scroll => Reactive.Signal(Vec(0.0, 0.0)),
:buttons_pressed => Reactive.Signal(Set(Int[])),
:window_size => Reactive.Signal(Vec(resolution...)),
:window_area => window_area,
:cursor_position => Reactive.Signal(Vec(0.0,0.0)),
:mouseinside => Reactive.Signal(true),
:mouse_button_down => Reactive.Signal(0),
:mouseposition => Reactive.Signal(Vec(0.0, 0.0)),
:framebuffer_size => Reactive.Signal(Vec(resolution...)),
:button_down => Reactive.Signal(0),
:button_released => Reactive.Signal(0),
:window_open => Reactive.Signal(true),
:keyboard_buttons => Reactive.Signal((0,0,0,0)),
:mouse2id => Signal(GLWindow.SelectionID{Int}(-1, -1))
)
screen[] = Screen(
Symbol("GLVisualize"), window_area, nothing,
Screen[], signals,
(), false, true, RGBA(1f0,1f0,1f0,1f0), (0f0, RGBA(0f0,0f0,0f0,0f0)),
Dict{Symbol, Any}(),
gtk_context
)
addScroll!(screen[])
addScrollEvt!(screen[])
GLVisualize.add_screen(screen[])
a1, a2 = y_part(screen[].area, 50)
global sc1
global sc2 # (failed) attempt to return "screens" from signal and plot more later
sc1 = Screen(screen[], area=a1)
sc2 = Screen(screen[], area=a2)
timesignal = viz_test(mesh_color, sc1)
foreach(timesignal) do x
# render a frame each time rotation updates
Gtk.queue_render(gl_area)
return
end
end
function render_gtk(window, gtk_area)
!isopen(window) && return
fb = GLWindow.framebuffer(window)
wh = GeometryTypes.widths(window)
resize!(fb, wh)
w, h = wh
#prepare for geometry in need of anti aliasing
glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) # color framebuffer
glDrawBuffers(2, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1])
# setup stencil and backgrounds
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)
glEnable(GL_SCISSOR_TEST)
GLWindow.setup_window(window, false)
glDisable(GL_SCISSOR_TEST)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
# deactivate stencil write
glEnable(GL_STENCIL_TEST)
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)
glStencilMask(0x00)
GLAbstraction.render(window, 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)
glClearColor(0,0,0,0)
glClear(GL_COLOR_BUFFER_BIT)
glViewport(0, 0, w, h)
GLAbstraction.render(fb.postprocess[1]) # add luma and preprocess
glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) # transfer to non fxaa framebuffer
glDrawBuffer(GL_COLOR_ATTACHMENT0)
GLAbstraction.render(fb.postprocess[2]) # copy with fxaa postprocess
#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(window, false)
glDisable(GL_STENCIL_TEST)
# draw strokes
glEnable(GL_SCISSOR_TEST)
GLWindow.setup_window(window, true)
glDisable(GL_SCISSOR_TEST)
glViewport(0,0, wh...)
#Read all the selection queries
GLWindow.push_selectionqueries!(window)
Gtk.attach_buffers(gtk_area) # transfer back to window
glClearColor(0,0,0,0)
glClear(GL_COLOR_BUFFER_BIT)
GLAbstraction.render(fb.postprocess[3]) # copy postprocess
return
end
function connect_renderloop(gl_area, resolution, mesh_color)
end
function viz_test(mesh_color, win)
timesignal = loop(linspace(0f0,1f0,360))
rotation_angle = const_lift(*, timesignal, 2f0*pi)
start_rotation = Signal(rotationmatrix_x(deg2rad(90f0)))
rotation = map(rotationmatrix_y, rotation_angle)
final_rotation = map(*, start_rotation, rotation)
_view(visualize(loadasset("cat.obj"), color = mesh_color, model = final_rotation), win)
return timesignal
end
function setup_screen()
resolution = (1920, 1080)
mesh_color = Signal(RGBA{Float32}(1,0,0,1))
gl_area = Gtk.GLArea()
Gtk.gl_area_set_required_version(gl_area, 3, 3)
GLAbstraction.new_context()
Gtk.signal_connect(gl_area, "render") do gl_area, gdk_context
if !isassigned(screen)
init_screen(gl_area, resolution, mesh_color)
end
render_gtk(screen[], gl_area)
glFlush()
return false
end
return gl_area
end
# end
# using Gtk
# using gtk_glviz
"""
Test run
"""
win = openmainwind()
Gtk.showall(win) As for the OpenGL versioning, I am running Ubunty 16.04 LTS and it should be up to date -- although I've learned not to trust that too much. CHecking OpenGL specifically,
which seems to show that the OpenGL Shading language version is more than enough. I tracked the error to the attempt to compile:
in fragment_output.frag in GLVisdualize/assets/shader where |
Oh, that'd be a classic... I think you would need to resolve that on os level, there is no API in OpenGL to select the GPU.... |
Ah I can reproduce it :) Gtk has a few contexts, maybe it just doesn't make the 3.3 context current. Let me check |
Btw, I think we can get rid of the segfault by removing GLFW from the dependencies, which should be possible since we use Gtk for everything that GLWindow use GLFW for. Should be a medium sized refactor, which we probably need to do for a smooth Gtk integration anyways |
Yeah, you need a function viz_test(mesh_color, win)
make_context_current(win)
timesignal = loop(linspace(0f0,1f0,360))
rotation_angle = const_lift(*, timesignal, 2f0*pi)
start_rotation = Signal(rotationmatrix_x(deg2rad(90f0)))
rotation = map(rotationmatrix_y, rotation_angle)
final_rotation = map(*, start_rotation, rotation)
_view(visualize(loadasset("cat.obj"), color = mesh_color, model = final_rotation), win)
return timesignal
end |
Ooooohhhhhh nice !!!! It does work on my end as well. The last thing I was stuck on are the signals for the mouse interactions... Next, I am going to look back at Makie since it looks awesome and I think it's be handy for some of the technical plotting I'm trying to implement. I do have it working somewhat well purely in GLVisualize for now. |
Hm kind of, but you would also need to remove all using statements and remove all code that breaks after the using is removed :P And then you might want to do it in a way, that it doesn't break GLWindows for other users... |
hahaha yes -- I meant as a local experiment |
Ah yeah :) just searching for |
If you get the chance, the last thing I'd bug you with (at least for a bit) is the mouse interaction integration. In that same code, I have (tentatively) updated the callback functions but for |
Has this been tested on Max OSX? I get a message saying 'Not implemented on OSX'. It seems like the glArea widget doesn't work on OSX? There were some issues on Gtk.jl related to OSX but none of those fixes impacted this. |
I don't really know much about Gtk and I can't test on osx. Can you show the stack trace from where that's coming? I can't find any error message like that in the source code of Gtk. |
Yeah, seems like a Gtk issue ;) |
a libgtk or an Gtk.jl issue? |
This hooks up the signals for perspective camera to work: |
Oh nice!
I tried both on Ubuntu and Windows with the same result. I also tried to checkout GLWindow to no avail. |
Never mind! I moved:
at the end of the |
Is there more to be done for other cameras? It does not seem to allow to interact with the play slider, build as:
|
Hi Simon!
I know you're working on Visualize and that it should have Gtk support but in the mean time, is there some way or hack to include/pipe/attach a GLVisualize.glscreen() into a Gtk.jl gui? Maybe through GLArea?
The GUI we're developing for our spacecraft constellation toolkit is coming along and it would be really cool to have embedded GLVisualize renderings through the design process! Right now, I have "Visualize" buttons that call whatever visualization and create a separate window --it works -- but it's not there yet.
Thanks,
Loic
The text was updated successfully, but these errors were encountered: