~jpsamaroo/Adjutant.jl

8a8229fe1ed910ea963b69840af6fd91fcdb76c9 — Julian P Samaroo 2 years ago 57f10d1
Allow loading user's project

Loads specified project, if passed as first shell argument
Moved my own code to MyAdjutant.jl
Renamed Adjutant struct to AdjutantState
Fixed node editor debugging
Added Condition field to Processor
Working on async Processor workers
4 files changed, 38 insertions(+), 37 deletions(-)

M src/Adjutant.jl
M src/node_editor.jl
M src/processing.jl
M src/widgets.jl
M src/Adjutant.jl => src/Adjutant.jl +15 -25
@@ 1,3 1,5 @@
module Adjutant

using CImGui
using CImGui.CSyntax
using CImGui.CSyntax.CStatic


@@ 8,24 10,25 @@ using CImGui.OpenGLBackend.ModernGL

using Observables, UUIDs
using Pkg
using LinearAlgebra
#using PortAudio, SampledSignals
#audio_dev = PortAudio.devices()[1]
using ImageMagick, ImageTransformations, ColorTypes
using VideoIO

const DEBUG = get(ENV, "ADJUTANT_DEBUG", "0") == "1"

include("processing.jl")
include("widgets.jl")
include("node_editor.jl")

#using MLJ, DataFrames
#include("mlj.jl")

Base.@kwdef mutable struct Adjutant
Base.@kwdef mutable struct AdjutantState
    widgets = WidgetContainer()
end
const adj = Adjutant()
const adj = AdjutantState()

if length(ARGS) == 1
    proj_path = abspath(ARGS[1])
    @assert isdir(proj_path)
    Pkg.activate(proj_path)
    init_func = include(joinpath(proj_path, "src", "main.jl"))
    init_func(adj)
end

# OpenGL 3.2 + GLSL 150
const glsl_version = 150


@@ 102,21 105,6 @@ SetCustomKeyCallback() do window, key, scancode, action, mods
    end
end

struct TestWidget end
(tw::Widget{TestWidget})(outer) = CImGui.Text("TestWidget")
get_processor(tw::TestWidget) = Processor(["a","b","c"],["d","e"]) do p
end

vcw = VideoCameraWidget()
ow = OpenGLImageWidget()

include("node_editor.jl")
ne = NodeEditor()
push!(ne.nodes, Node(1, vcw, ImVec2(40, 50), ImVec2(100, 20), ImColor(255, 100, 100)))
push!(ne.nodes, Node(2, ow, ImVec2(40, 150), ImVec2(100, 20), ImColor(200, 100, 200)))
push!(ne.nodes, Node(3, TestWidget(), ImVec2(270, 80), ImVec2(100, 20), ImColor(0, 200, 100)))
push!(adj.widgets, ne)

push!(adj.widgets, AddWidgetButton())

clear_color = Cfloat[0.0, 0.0, 0.0, 1.0]


@@ 150,3 138,5 @@ ImGui_ImplGlfw_Shutdown()
CImGui.DestroyContext(ctx)

GLFW.DestroyWindow(window)

end

M src/node_editor.jl => src/node_editor.jl +5 -5
@@ 115,28 115,28 @@ function interact_slot(ne::Widget{NodeEditor}, kind::Symbol, node_idx, slot_idx)
                  slot_idx == modifier*ne.slot_targeted
    if CImGui.IsMouseClicked(0)
        if ne.node_targeted == 0
            ADJUTANT_DEBUG && @info "Select $kind_str $(slot_idx) from $(name(node.widget))"
            DEBUG && @info "Select $kind_str $(slot_idx) from $(name(node.widget))"
            ne.node_targeted = node_idx
            ne.slot_targeted = modifier*slot_idx
        elseif is_targeted
            ADJUTANT_DEBUG && @info "Deselect $kind_str $(slot_idx) from $(name(node.widget))"
            DEBUG && @info "Deselect $kind_str $(slot_idx) from $(name(node.widget))"
            ne.node_targeted = 0
            ne.slot_targeted = 0
        elseif can_connect
            if isconnected(ne, out_node_idx, out_slot_idx, inp_node_idx, inp_slot_idx)
                ADJUTANT_DEBUG && @info "Disconnect input $(inp_slot_idx) of $(name(ne.nodes[inp_node_idx])) from output $(out_slot_idx) of $(name(ne.nodes[out_node_idx]))"
                DEBUG && @info "Disconnect input $(inp_slot_idx) of $(name(ne.nodes[inp_node_idx])) from output $(out_slot_idx) of $(name(ne.nodes[out_node_idx]))"
                link_idx = findlink(ne, out_node_idx, out_slot_idx, inp_node_idx, inp_slot_idx)
                deleteat!(ne.links, link_idx)
                detach!(inp_proc, inputnames(inp_proc)[inp_slot_idx])
            else
                ADJUTANT_DEBUG && @info "Connect input $(inp_slot_idx) of $(name(ne.nodes[inp_node_idx])) to output $(out_slot_idx) of $(name(ne.nodes[out_node_idx]))"
                DEBUG && @info "Connect input $(inp_slot_idx) of $(name(ne.nodes[inp_node_idx])) to output $(out_slot_idx) of $(name(ne.nodes[out_node_idx]))"
                push!(ne.links, NodeLink(out_node_idx, out_slot_idx, inp_node_idx, inp_slot_idx))
                attach!(inp_proc, inputnames(inp_proc)[inp_slot_idx], out_proc, out_slot_name)
            end
            ne.node_targeted = 0
            ne.slot_targeted = 0
        else
            ADJUTANT_DEBUG && @info "Skip on $kind_str $slot_idx of $(name(node.widget))"
            DEBUG && @info "Skip on $kind_str $slot_idx of $(name(node.widget))"
        end
    elseif CImGui.IsMouseClicked(1)
        iscon = kind == :input ? isinputconnected : isoutputconnected

M src/processing.jl => src/processing.jl +12 -7
@@ 13,6 13,7 @@ mutable struct Processor
    func
    in_map::Dict{String,Union{UUID,Nothing}}
    out_map::Dict{String,UUID}
    update_cond::Threads.Condition
end
function Processor(func, in_map::Dict{String,Union{UUID,Nothing}}, out_slots::Vector{String})
    out_map = Dict{String,UUID}()


@@ 20,7 21,7 @@ function Processor(func, in_map::Dict{String,Union{UUID,Nothing}}, out_slots::Ve
        uuid, _ = newslot()
        out_map[name] = uuid
    end
    return Processor(func, in_map, out_map)
    return Processor(func, in_map, out_map, Threads.Condition())
end
Processor(func, in_map::Vector{String}, out_slots::Vector{String}) =
    Processor(func, Dict{String,Union{UUID,Nothing}}(map(x->x=>nothing, in_map)), out_slots)


@@ 30,7 31,7 @@ Processor(func, in_map, out_slots::Nothing) =
    Processor(func, in_map, String[])
Processor(func, in_map::Nothing, out_slots::Nothing) =
    Processor(func, Dict{String,Union{UUID,Nothing}}(), String[])
Processor() = Processor(p -> (), Dict{String,Union{UUID,Nothing}}(), Dict{String,UUID}())
Processor() = Processor(p -> (), Dict{String,Union{UUID,Nothing}}(), Dict{String,UUID}(), Threads.Condition())

(p::Processor)() = allinputsmapped(p) && p.func(p)
getslot(p::Processor, name::String) = getslot(p.in_map[name])


@@ 53,15 54,19 @@ function register_processor!(p::Processor)
    @assert allinputsmapped(p) "Processor is not fully input mapped"
    uuid = uuid4()
    PROCESSORS[uuid] = p
    tsk = Threads.@spawn begin
    tsk = Task(()->processor_worker(p))
    schedule(tsk)
    PROCESSOR_TASKS[uuid] = tsk
    return uuid, tsk
end

function processor_worker(p::Processor, name::String, kind::Symbol)
    schedule(@task begin
        while true
            # Wait on any input to change, and then process
            select([(:take, SLOTS[inp]) for inp in values(p.in_map)])
            p()
        end
    end
    PROCESSOR_TASKS[uuid] = tsk
    return uuid, tsk
    end)
end

### Demo ###

M src/widgets.jl => src/widgets.jl +6 -0
@@ 80,6 80,7 @@ function (awb::Widget{AddWidgetButton})(outer)
end
push!(known_widgets, AddWidgetButton)

#=
### Image Widgets ###

mutable struct VideoCameraWidget


@@ 134,6 135,7 @@ function render_widget_form(::Type{TextWidget}, fields, outer)
    str = fields[:str]
    CImGui.InputText("Text", str, length(str))
end
=#

struct ClosureWidget
    func


@@ 141,3 143,7 @@ end
(cw::Widget{ClosureWidget})(outer) = cw.func(outer)
push!(known_widgets, ClosureWidget)

struct TestWidget end
(tw::Widget{TestWidget})(outer) = CImGui.Text("TestWidget")
get_processor(tw::TestWidget) = Processor(["a","b","c"],["d","e"]) do p
end