Gnimuc / CImGui.jl

Julia wrapper for cimgui
https://github.com/cimgui/cimgui
MIT License
259 stars 25 forks source link

Adapt Renderer.jl to new API #67

Closed zsoerenm closed 2 years ago

zsoerenm commented 2 years ago

This will adapt Renderer.jl to the new API. I tried out the master version because I got a segfault with the previous version (v1.79.0) see here: https://gist.github.com/sairus7/19778c05ffba7c677a3414f752a0f9cb#gistcomment-3981509

However, even if I use the new API with the adaption in this pull request, I will still get a segfault, when I click on one of the collapsing headers.

Here is the code that I tried:

include("Renderer.jl")

using .Renderer
using CImGui
using CImGui.CSyntax
using CImGui.CSyntax.CStatic
import CImGui.LibCImGui: ImGuiCond_Always, ImGuiCond_Once
using ImPlot

using UnPack

# GUI state
Base.@kwdef mutable struct MyStates
    show_another_window = false

    # make up some data
    xs1 = Float64.(collect(1:100))
    ys1 = rand(6000)
    noise = rand(length(xs1))
    bar_vals = Vector{Vector{Float64}}(undef, 5)
    bar_maxes = zeros(5)
    bar_mins = zeros(5)
    bar_max = 0.0
    bar_min = 0.0
    bar_counter = 1

    shaded_x = 1:1000
    shaded_y1 = [sin(x) for x in range(0,2π, length = length(shaded_x))]
    shaded_y_ref = -2.0
end

# something that cannot be brought to MyStates constructor
function init(state::MyStates)
    @unpack bar_vals, bar_maxes, bar_mins, shaded_x, shaded_y1 = state
    for i in 1:length(bar_vals)
        bar_vals[i] = Float64.(collect(range(rand(1:10), step=rand([-2,-1,1,2]), length=120)))
        bar_maxes[i] = maximum(bar_vals[i])
        bar_mins[i] = minimum(bar_vals[i])
    end
    state.bar_max = maximum(bar_maxes)
    state.bar_min = minimum(bar_mins)
end

function update(state::MyStates)
    @unpack show_another_window, xs1, ys1, noise, bar_vals, bar_maxes, bar_mins, bar_max, bar_min, bar_counter, 
            shaded_x, shaded_y1, shaded_y_ref = state

    ys1 .= rand(6000)
    noise .= xs1 .+ rand(-5.0:0.1:5.0, length(xs1))

    if bar_counter == 120
        state.bar_counter = 1
    else
        state.bar_counter += 1
    end
end

# this is the UI function, whenever the structure of `MyStates` is changed, 
function ui(state::MyStates)
    @unpack show_another_window, xs1, ys1, noise, bar_vals, bar_maxes, bar_mins, bar_max, bar_min, bar_counter, 
            shaded_x, shaded_y1, shaded_y_ref = state

    CImGui.Begin("Example Plots")

    @c CImGui.Checkbox("Show Examples", &state.show_another_window)
    #CImGui.Text("Application average $(1000 / CImGui.GetIO().Framerate) ms/frame ($(CImGui.GetIO().Framerate) FPS)")

    CImGui.End()

    if state.show_another_window
        @c CImGui.Begin("Examples Window", &state.show_another_window)
        if CImGui.CollapsingHeader("Line plots")

            ImPlot.SetNextPlotLimits(0.0, 6000, 0.0, 1.0, ImGuiCond_Always)
            # Using '##' in the label name hides the plot label, but lets 
            # us keep the label ID unique for modifying styling etc.
            if ImPlot.BeginPlot("##line", "x1", "y1", CImGui.ImVec2(-1,300))
                ImPlot.PlotLine(ys1)
                ImPlot.EndPlot()
            end
        end
        if CImGui.CollapsingHeader("Scatter plot")

            ImPlot.SetNextPlotLimits(0,100,-5,105, ImGuiCond_Always)
            if ImPlot.BeginPlot("##scatter", "x2", "y2", CImGui.ImVec2(-1,300))
                ImPlot.PlotScatter(xs1, noise)
                ImPlot.EndPlot()
            end
        end
        if CImGui.CollapsingHeader("Bar plot")

            bar_val_step = [bar_vals[j][bar_counter] for j in 1:length(bar_vals)]

            ImPlot.SetNextPlotLimits(-0.5, 4.5, bar_min, bar_max, ImGuiCond_Always)
            if ImPlot.BeginPlot("##bars", "", "", CImGui.ImVec2(-1,300))
                ImPlot.PlotBars(bar_val_step)
                ImPlot.EndPlot()
            end

        end
        if CImGui.CollapsingHeader("Shaded plot")
            ImPlot.SetNextPlotLimits(0,1000,-2,1, ImGuiCond_Always)
            if ImPlot.BeginPlot("##shaded", "", "", CImGui.ImVec2(-1,300))
                ImPlot.PlotShaded(shaded_x, shaded_y1, shaded_y_ref)
                ImPlot.EndPlot()
            end
        end
        CImGui.End()
    end
end

state = MyStates()
init(state)
update(state) # initial update

Renderer.render(()->ui(state), width = 360, height = 480, title = "A simple UI")

function infinite_loop(state::MyStates)
    @async while true
        update(state)
        yield()
    end
end

infinite_loop(state) # animate the plot

Here is the segfault

signal (11): Speicherzugriffsfehler
in expression starting at none:0
_ZN6ImPlot9BeginPlotEPKcS1_S1_RK6ImVec2iiiii at /home/zorn/.julia/artifacts/0cc6a080633fafa03677619f4e0789ff30bba3e8/lib/libcimplot.so (unknown line)
ImPlot_BeginPlot at /home/zorn/.julia/artifacts/0cc6a080633fafa03677619f4e0789ff30bba3e8/lib/libcimplot.so (unknown line)
BeginPlot at /home/zorn/.julia/packages/ImPlot/wx3uZ/src/libcimplot/libcimplot_api.jl:8
#BeginPlot#1 at /home/zorn/.julia/packages/ImPlot/wx3uZ/src/ImPlot.jl:27 [inlined]
BeginPlot at /home/zorn/.julia/packages/ImPlot/wx3uZ/src/ImPlot.jl:27 [inlined]
ui at /home/zorn/Dokumente/Projekte/Dissertation/Analyse/src/test2.jl:77
#34 at /home/zorn/Dokumente/Projekte/Dissertation/Analyse/src/test2.jl:116
renderloop at /home/zorn/Dokumente/Projekte/Dissertation/Analyse/src/Renderer.jl:64
#4 at ./task.jl:423
unknown function (ip: 0x7f993a1e46cf)
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1788 [inlined]
start_task at /buildworker/worker/package_linux64/build/src/task.c:877
Allocations: 29516996 (Pool: 29511402; Big: 5594); GC: 2501
zsh: segmentation fault (core dumped)  julia

Fixes https://github.com/Gnimuc/CImGui.jl/issues/66

BTW I'm using Julia v1.7

Gnimuc commented 2 years ago

Looks like the segfault is from Implot. Does Implot support the CImGui latest master branch now?

cc @wsphillips

zsoerenm commented 2 years ago

The segfault also appears with v1.79.0 of CImGui as stated here: https://gist.github.com/sairus7/19778c05ffba7c677a3414f752a0f9cb#gistcomment-3981509 It looks like ImPlot is the culprit. I have opened a new issue at ImPlot.jl https://github.com/wsphillips/ImPlot.jl/issues/24 I guess, this is ready to be merged then.

Gnimuc commented 2 years ago

Thanks!