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

Integration into Gtk or equivalent #195

Closed
astrolabshub opened this issue Aug 24, 2017 · 41 comments
Closed

Integration into Gtk or equivalent #195

astrolabshub opened this issue Aug 24, 2017 · 41 comments

Comments

@astrolabshub
Copy link

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

@SimonDanisch
Copy link
Member

Hi Loic,
I didn't have much time to work on this.
Let me see if I can write up a simple first prototype of this today.

Best,
Simon

@SimonDanisch
Copy link
Member

I mad a prototype, which segfaults when I add sliders... I hope i can fix that tomorrow and get you started!

@loicspace
Copy link

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

@SimonDanisch
Copy link
Member

@loicspace
Copy link

Wonderful -- I'm gonna check it out

@loicspace
Copy link

First, this is beautiful!

A couple follow ups ;):

  1. I tried to modify this prototype with the same logic as in rotate_robj.jl example: adding the rotation of the cat, as my own visuals include spacecraft moving around a planet, a.ka., subbing in init_screen(args):
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), screen[])

It seems however that loop and renderloop are tied to glscreen:
ERROR: No screen available. Consider creating one with the function glscreen()

Is there an easy way to make that work or is that more deeply rooted into how GLVisualize work?

  1. There does not seem to be any mouse interactions (pan or zoom) -- would I need to update the signal dictionary in init_screen(args)?

Thanks a bunch!

@SimonDanisch
Copy link
Member

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).
Maybe the easiest is just to register the screen with GLVisualize with add_screen(screen[]).

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 window[Attribute] = newvalue, with push!(window.inputs[:attribute], newvalue) and give the functions unique names, since we don't have the traits like Mouse.Scroll available:

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

@loicspace
Copy link

  1. I added GLVisualize.add_screen(screen[]) which got me through to the last line of:
		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)
                _view(visualize(loadasset("cat.obj"), color = mesh_color, model = final_rotation), screen[])
		renderloop(screen[])

where renderloop is not happy:

ERROR: MethodError: no method matching swapbuffers(::Gtk.GtkGLAreaLeaf)
Closest candidates are:
  swapbuffers(::GLFW.Window) at /home/loic/.julia/v0.6/GLWindow/src/screen.jl:438
  swapbuffers(::GLWindow.Screen) at /home/loic/.julia/v0.6/GLWindow/src/screen.jl:435
Stacktrace:
 [1] #renderloop#39(::Float64, ::GLWindow.##40#42, ::Function, ::GLWindow.Screen) at /home/loic/.julia/v0.6/GLWindow/src/render.jl:44
 [2] renderloop(::GLWindow.Screen) at /home/loic/.julia/v0.6/GLWindow/src/render.jl:40
 [3] init_screen(::Gtk.GtkGLAreaLeaf, ::Tuple{Int64,Int64}, ::Reactive.Signal{ColorTypes.RGBA{Float32}}) at /home/loic/Tools/gtk_glvisualize.jl:53
 [4] (::##3#4{Tuple{Int64,Int64},Reactive.Signal{ColorTypes.RGBA{Float32}}})(::Gtk.GtkGLAreaLeaf, ::Gtk.GLib.GObjectLeaf) at /home/loic/Tools/gtk_glvisualize.jl:143
 [5] (::Gtk.GLib.##91#93{Ptr{Gtk.GLib.GValue},UInt32,Ptr{Gtk.GLib.GValue}})() at /home/loic/.julia/v0.6/Gtk/src/GLib/signals.jl:88
 [6] g_siginterruptible(::Gtk.GLib.##91#93{Ptr{Gtk.GLib.GValue},UInt32,Ptr{Gtk.GLib.GValue}}, ::Function) at /home/loic/.julia/v0.6/Gtk/src/GLib/signals.jl:207
 [7] GClosureMarshal(::Ptr{Void}, ::Ptr{Gtk.GLib.GValue}, ::UInt32, ::Ptr{Gtk.GLib.GValue}, ::Ptr{Void}, ::Ptr{Void}) at /home/loic/.julia/v0.6/Gtk/src/GLib/signals.jl:59
 [8] (::Gtk.##229#230)() at /home/loic/.julia/v0.6/Gtk/src/events.jl:2
 [9] g_sigatom(::Any) at /home/loic/.julia/v0.6/Gtk/src/GLib/signals.jl:167
 [10] gtk_main() at /home/loic/.julia/v0.6/Gtk/src/events.jl:1

  1. I understand the need for the substitution, I am not clear though on what to with the new add_x! functions.

@SimonDanisch
Copy link
Member

SimonDanisch commented Aug 30, 2017

Ah, didn't realize that you actually call renderloop. That's not needed, since it doesn't work well with GTK. This is the new "renderloop" for GTK:

    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

am not clear though on what to with the new add_x! functions.

Just call them to start having GTK push to the signals in screen.inputs ;)

@loicspace
Copy link

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.
gtk_glvisualize.jl.zip

Ah, I'll play with that and see if I get it !

@SimonDanisch
Copy link
Member

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 Gtk.queue_render(gl_area) somewhere, e.g. here:

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)

@loicspace
Copy link

Nice! It works!

As for the mouse interactions, something like: (I commented in the code things I am not sure about)
addScroll!(screen[]) # not sure if that should be screen[] or another Gtk parent

function addScroll!(window::GtkWindow)  # Need to change type here to match screen[] ?
    function callback_w(widget::Gtk.GtkGLArea, width::Int32, height::Int32)
        rect = window.inputs[:window_area]
        push!(window.inputs[:window_area],  IRect(minimum(rect), width, height) )
        return true
    end
    signal_connect(callback_w, window[Window], "Scroll")    # not sure of the equivalent w/o the trait, should that be "parent"?
    add_events(window[Window], GConstants.GdkEventMask.SCROLL) # same
    return
end

Similar question with window[NativeWindow]

@SimonDanisch
Copy link
Member

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

@loicspace
Copy link

hahaha I was missing quite a few pieces.
I get this warning though:
(julia6:31970): GLib-GObject-WARNING **: /build/glib2.0-prJhLS/glib2.0-2.48.2/./gobject/gsignal.c:2417: signal 'Scroll' is invalid for instance '0x7fb42c00d7c0' of type 'GtkGLArea'
Assuming I can (not mess up and) update the other functions, will that allow to move around the cat? And because I don't think I was clear the first time I asked, I just mean being able to zoom in and out, rotate around the scene. (Like it is possible in rotate_rob.jl example from GLVisualize) Would it be more "GLVisualiz-y" to add a camera with those inputs?

@SimonDanisch
Copy link
Member

Ah, you changed the value in signal_connect:

It needs to be: "scroll-event", not "Scroll"....

Zoom, etc should come automatically once the window signals are "live".

@loicspace
Copy link

loicspace commented Nov 23, 2017

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.

  1. Mouse interactions: I have attempted to adapt the mouse signals from what you had sent before, but I'm failing. Generally, but also specifically on how to adapt the traits Mouse.left and such for the mouse interactions "add!" functions (the coded is pasted below)

  2. I have defined two screens in the init_screen function, one to plot immediately and one to plot when the button is pressed. I am giving the gtk signal "sc1" -- the screen defined as a global variable in init_screen -- but that fails with the error:

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)

@SimonDanisch
Copy link
Member

so did you actually get around the segfault?

@loicspace
Copy link

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 😅

@SimonDanisch
Copy link
Member

Hm, your MWE gives me a segfault :(

@SimonDanisch
Copy link
Member

I thought i could quickly debug this, but the code is a bit too magical for a quick debugging session.
See: JuliaGraphics/Gtk.jl#336

@loicspace
Copy link

Yes -- for some reason Gtk and GLWindow don't seem to always play nice.
Weirdly, It does seem to be reproducible on Windows.
Even weirder, it does not seg fault in my "full implementation" -- full gui for my tool + this prototype --
and I am not able to tease out what the relevant implementation difference is that makes it seg fault

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

@SimonDanisch
Copy link
Member

The above shader problem is a bit hard to debug for me, since it segfaults ;)
But at the core of it is, that you don't seem to get an OpenGL context with a new enough OpenGL version.
See the #version 150 in the shader... that version should be #version 330, suggesting that something with Gtk.gl_area_set_required_version(gl_area, 3, 3) must have failed... Or do you happen to be on a very old system?

@loicspace
Copy link

Ah of course.
I removed the seg faulty gtk elements, the code below does not seg fault on my Ubuntu, it looks somewhat silly tho, the button to trigger the additional viz -- which causes the shader error on my machine -- is a tiny button at the top left of the window:

# 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,

loic@loic-astro:~$ glxinfo | grep "OpenGL version"
OpenGL version string: 4.5.0 NVIDIA 384.90
loic@loic-astro:~$ glxinfo | grep 'version'
server glx version string: 1.4
client glx version string: 1.4
GLX version: 1.4
OpenGL core profile version string: 4.5.0 NVIDIA 384.90
OpenGL core profile shading language version string: 4.50 NVIDIA
OpenGL version string: 4.5.0 NVIDIA 384.90
OpenGL shading language version string: 4.50 NVIDIA
OpenGL ES profile version string: OpenGL ES 3.2 NVIDIA 384.90
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
    GL_EXT_shader_group_vote, GL_EXT_shader_implicit_conversions, 

which seems to show that the OpenGL Shading language version is more than enough. I tracked the error to the attempt to compile:


{{GLSL_VERSION}}
{{GLSL_EXTENSIONS}}
{{SUPPORTED_EXTENSIONS}}

layout(location=0) out vec4 fragment_color;
layout(location=1) out uvec2 fragment_groupid;

#ifdef DEPTH_LAYOUT
    layout (depth_greater) out float gl_FragDepth;
#endif
void write2framebuffer(vec4 color, uvec2 id){
    fragment_color = color;
    if (color.a > 0.5){
        gl_FragDepth = gl_FragCoord.z;
    }else{
        gl_FragDepth = 1.0;
    }
    fragment_groupid = id;
}

in fragment_output.frag in GLVisdualize/assets/shader where {{GLSL_VERSION}} points to #version 150 somehow.
Wonder if it does not see the NVIDIA drivers and defaults back to the integrated graphics, which may be out of date.

@SimonDanisch
Copy link
Member

Wonder if it does not see the NVIDIA drivers and defaults back to the integrated graphics, which may be out of date.

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....

@SimonDanisch
Copy link
Member

Ah I can reproduce it :) Gtk has a few contexts, maybe it just doesn't make the 3.3 context current. Let me check

@SimonDanisch
Copy link
Member

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

@SimonDanisch
Copy link
Member

Yeah, you need a make_context_current(win) before issuing any visualize command.
I inserted it here in your example:

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

@loicspace
Copy link

Ooooohhhhhh nice !!!! It does work on my end as well.
As for GLFW, would (a very dirty way) be to remove it from REQUIRE on all imported packages? Might break a bunch of stuff other places I imagine tho lol

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.

@SimonDanisch
Copy link
Member

As for GLFW, would (a very dirty way) be to remove it from REQUIRE on all imported packages?

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...

@loicspace
Copy link

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

@SimonDanisch
Copy link
Member

Ah yeah :) just searching for GLFW and remove all usings should get you pretty far :)
Since julia is dynamic, you don't even need to remove code that's inside a function that doesn't get called!

@loicspace
Copy link

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 function to_mouse_button(x) -- hence the commented out two functions. There may be additional issues with my updates...

@louisponet
Copy link

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.

@SimonDanisch
Copy link
Member

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.

@louisponet
Copy link

louisponet commented Dec 10, 2017

It's not really an error message, it looks like this:
screen shot 2017-12-10 at 12 41 53

This happens due to the lines:

    gl_area = Gtk.GLArea()
    Gtk.gl_area_set_required_version(gl_area, 3, 3)
    GLAbstraction.new_context()
    push!(box, gl_area)

But ok in the end I just want to show text, plots and a 3D scene, I guess I should just use GLVisualize for the entire thing, since I won't be creating complex ui's.

EDIT: This has nothing to do with GLVisualize specifically, I'm sure its about the opengl context of Gtk. Maybe this doesn't belong here, I (or you) can remove it if you want.

@SimonDanisch
Copy link
Member

Yeah, seems like a Gtk issue ;)

@lobingera
Copy link

a libgtk or an Gtk.jl issue?

@SimonDanisch
Copy link
Member

This hooks up the signals for perspective camera to work:
https://gist.github.com/SimonDanisch/803936a216739d920535aaa1a2079df6#file-gtk_signals-jl

@loicspace
Copy link

loicspace commented Dec 13, 2017

Oh nice!
I however get the error:

julia> include("gtk_signals.jl")
ERROR: LoadError: UndefRefError: access to undefined reference
Stacktrace:
 [1] getindex(::Base.RefValue{GLWindow.Screen}) at ./refpointer.jl:118
 [2] include_from_node1(::String) at ./loading.jl:576
 [3] include(::String) at ./sysimg.jl:14
while loading /home/loic/Tools/Dev/gtk_signals.jl, in expression starting on line 250

I tried both on Ubuntu and Windows with the same result. I also tried to checkout GLWindow to no avail.

@loicspace
Copy link

loicspace commented Dec 13, 2017

Never mind!
I think it is simply trying to add the callbacks before the screen is even registered/set up -- it takes a moment to GLVisualize things on my system as I am not using a compile image. I manually entered the calls to the signal functions once it was all rendered and it works just fine!

I moved:


scroll_event!(screen[])
mouse!(screen[])
mousebuttons!(screen[])

at the end of the init_screen routine and that seems to take care of that.

@loicspace
Copy link

This hooks up the signals for perspective camera to work

Is there more to be done for other cameras? It does not seem to allow to interact with the play slider, build as:

  iconsize = 8mm
  play_viz, slider_value = play_slider(edit3Dscreen, iconsize, timeanim)
  controls = Pair[:play => play_viz ]
  _view(visualize(controls,model=translationmatrix(Vec3f0(0,0.5,0)), text_scale = 4mm,width = 8iconsize),
  edit3Dscreen, camera = :fixed_pixel)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants