diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f2bcf0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +scr/junkyard/ diff --git a/.travis.yml b/.travis.yml old mode 100755 new mode 100644 diff --git a/LICENSE.md b/LICENSE.md old mode 100755 new mode 100644 diff --git a/README.md b/README.md old mode 100755 new mode 100644 diff --git a/src/GLFW/callbacks.jl b/src/GLFW/callbacks.jl new file mode 100644 index 0000000..10b30b6 --- /dev/null +++ b/src/GLFW/callbacks.jl @@ -0,0 +1,203 @@ +import GLFW: Window + +""" +Returns a signal, which is true as long as the window is open. +returns `Bool` +[GLFW Docs](http://www.glfw.org/docs/latest/group__window.html#gaade9264e79fae52bdb78e2df11ee8d6a) +""" +function window_open(window::Window, s::Bool=false) + GLFW.SetWindowCloseCallback(window, (window,) -> s) + s +end + +""" +Size of the window. Must not correlate to the real pixel size. +This is why there is also framebuffer_size. +returns `NTuple{2,Int}}` +[GLFW Docs](http://www.glfw.org/docs/latest/group__window.html#gaaca1c2715759d03da9834eac19323d4a) +""" +function window_size(window::Window, s::NTuple{2,Int}=GLFW.GetWindowSize(window)) + GLFW.SetWindowSizeCallback(window, (window, w::Cint, h::Cint,) -> begin + s = Vec{2,Int}(w, h) + end) + s +end +""" +Size of window in pixel. +returns `NTuple{2,Int}}` +[GLFW Docs](http://www.glfw.org/docs/latest/group__window.html#ga311bb32e578aa240b6464af494debffc) +""" +function framebuffer_size(window::Window, s::NTuple{2, Int}=GLFW.GetFramebufferSize(window)) + GLFW.SetFramebufferSizeCallback(window, (window, w::Cint, h::Cint) -> begin + s = (Int(w), Int(h)) + end) + s +end +""" +Position of the window in screen coordinates. +returns `NTuple{2,Int}}` +[GLFW Docs](http://www.glfw.org/docs/latest/group__window.html#ga1c36e52549efd47790eb3f324da71924) +""" +function window_position(window::Window, s::NTuple{2,Int}=(0,0)) + GLFW.SetWindowPosCallback(window, (window, x::Cint, y::Cint,) -> begin + s = (Int(x), Int(y)) + end) + s +end +""" +Registers a callback for the mouse buttons + modifiers +returns `NTuple{4, Int}` +[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#ga1e008c7a8751cea648c8f42cc91104cf) +""" +function keyboard_buttons(window::Window, s::NTuple{4, Int}=(0,0,0,0)) + keydict = Dict{Int, Bool}() + GLFW.SetKeyCallback(window, (window, button::Cint, scancode::Cint, action::Cint, mods::Cint) -> begin + s = (Int(button), Int(scancode), Int(action), Int(mods)) + end) + s +end +""" +Registers a callback for the mouse buttons + modifiers +returns an `NTuple{3, Int}`, +containing the pressed button the action and modifiers. +[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#ga1e008c7a8751cea648c8f42cc91104cf) +""" +function mouse_buttons(window::Window, s::NTuple{3, Int}=(0,0,0)) + GLFW.SetMouseButtonCallback(window, (window, button::Cint, action::Cint, mods::Cint) -> begin + s = (Int(button), Int(action), Int(mods)) + end) + s +end +""" +Registers a callback for drag and drop of files. +returns `Vector{String}`, which are absolute file paths +[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#gacc95e259ad21d4f666faa6280d4018fd) +""" +function dropped_files(window::Window, s::Vector{String}=String[]) + GLFW.SetDropCallback(window, (window, files) -> begin + s = map(String, files) + end) + s +end + +""" +Registers a callback for keyboard unicode input. +returns an `Vector{Char}`, +containing the pressed char. Is empty, if no key is pressed. +[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#ga1e008c7a8751cea648c8f42cc91104cf) +""" +function unicode_input(window::Window, s::Vector{Char}=Char[]) + GLFW.SetCharCallback(window, (window, c::Char) -> begin + push!(s, c) + end) + s +end +""" +Registers a callback for the mouse cursor position. +returns an `NTuple{2, Float64}`, +which is not in screen coordinates, with the upper left window corner being 0 +[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#ga1e008c7a8751cea648c8f42cc91104cf) +""" +function cursor_position(window::Window, s::NTuple{2, Float64}=(0.,0.)) + GLFW.SetCursorPosCallback(window, (window, x::Cdouble, y::Cdouble) -> begin + s = (x, y) + end) + s +end +""" +Registers a callback for the mouse scroll. +returns an `NTuple{2, Float64}`, +which is an x and y offset. +[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#gacc95e259ad21d4f666faa6280d4018fd) +""" +function scroll(window::Window, s::NTuple{2, Float64}=(0.,0.)) + GLFW.SetScrollCallback(window, (window, xoffset::Cdouble, yoffset::Cdouble) -> begin + s = (xoffset, yoffset) + end) + s +end +""" +Registers a callback for the focus of a window. +returns a `Bool`, +which is true whenever the window has focus. +[GLFW Docs](http://www.glfw.org/docs/latest/group__window.html#ga6b5f973531ea91663ad707ba4f2ac104) +""" +function hasfocus(window::Window, s::Bool=false) + GLFW.SetWindowFocusCallback(window, (window, focus::Bool) -> begin + s = focus + end) + s +end +""" +Registers a callback for if the mouse has entered the window. +returns a `Bool`, +which is true whenever the cursor enters the window. +[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#ga762d898d9b0241d7e3e3b767c6cf318f) +""" +function entered_window(window::Window, s::Bool=false) + GLFW.SetCursorEnterCallback(window, (window, entered::Bool) -> begin + s = entered + end) + s +end + +""" +Takes a window and registers a list of callback functions. +Returns a dict{Symbol, Signal}(name_of_callback => signal) +""" +function register_callbacks(window::Window, callbacks::Vector{Function}) + tmp = map(callbacks) do f + (Symbol(last(split(string(f),"."))), f(window)) + end + Dict{Symbol, Any}(tmp) +end + +#Came from GLWindow/events.jl +""" +Builds a Set of keys, accounting for released and pressed keys +""" +function currently_pressed_keys(v0::Set{Int}, button_action_mods) + button, action, mods = button_action_mods + if button != GLFW.KEY_UNKNOWN + if action == GLFW.PRESS + push!(v0, button) + elseif action == GLFW.RELEASE + delete!(v0, button) + elseif action == GLFW.REPEAT + # nothing needs to be done, besides returning the same set of keys + else + error("Unrecognized enum value for GLFW button press action: $action") + end + end + return v0 +end + +function remove_scancode(button_scancode_action_mods) + button, scancode, action, mods = button_scancode_action_mods + button, action, mods +end +isreleased(button) = button[2] == GLFW.RELEASE +isdown(button) = button[2] == GLFW.PRESS + +#question: do we need this? +# """ +# Creates high level signals from the raw GLFW button signals. +# Returns a dictionary with button released and down signals. +# It also creates a signal, which is the set of all currently pressed buttons. +# `name` is used to name the dictionary keys. +# `buttons` is a tuple of (button, action, mods)::NTuple{3, Int} +# """ +# function button_signals(buttons::NTuple{3, Int}, name::Symbol) +# keyset = Set{Int}() +# sizehint!(keyset, 10) # make it less suspicable to growing/shrinking +# released = filter(isreleased, buttons.value, buttons) +# down = filter(isdown, buttons.value, buttons) +# Dict{Symbol, Any}( +# Symbol("$(name)_released") => map(first, released), +# Symbol("$(name)_down") => map(first, down), +# Symbol("$(name)s_pressed") => foldp( +# currently_pressed_keys, keyset, buttons +# ) +# ) +# end + diff --git a/src/GLFW/func_ext.jl b/src/GLFW/func_ext.jl new file mode 100644 index 0000000..6939811 --- /dev/null +++ b/src/GLFW/func_ext.jl @@ -0,0 +1,44 @@ +#Extensions to GLFW functionality +import GLFW: Window + +function Base.isopen(window::Window) + window.handle == C_NULL && return false + !WindowShouldClose(window) +end + +function Base.resize!(x::Window, w::Integer, h::Integer) + SetWindowSize(x, w, h) +end + + +function swapbuffers(window::Window) + window.handle == C_NULL && return + SwapBuffers(window) + return +end +#Came from GLWindow.jl/screen.jl +#question: Is this correct? +""" +Takes a Window and registers a list of callback functions. +Returns a Dict{Symbol, Any}(name_of_callback => signal) +""" +function register_callbacks(window::Window, callbacks::Vector{Function}) + tmp = map(callbacks) do f + (Symbol(last(split(string(f),"."))), f(window)) + end + Dict{Symbol, Any}(tmp) +end + +function poll_glfw() + PollEvents() +end + +function to_arrow_symbol(button_set) + for b in button_set + KEY_RIGHT == b && return :right + KEY_LEFT == b && return :left + KEY_DOWN == b && return :down + KEY_UP == b && return :up + end + return :nothing +end \ No newline at end of file diff --git a/src/GLFW/screen.jl b/src/GLFW/screen.jl new file mode 100644 index 0000000..bf40de1 --- /dev/null +++ b/src/GLFW/screen.jl @@ -0,0 +1,120 @@ + +mutable struct GLFWScreen <: Screen + name ::Symbol + id ::Int + area ::Tuple{Int,Int} + parent ::GLFWScreen + window ::GLFW.Window + children ::Vector{GLFWScreen} + callbacks ::Dict{Symbol, Any} + visible ::Bool # if window is visible. Will still render + hidden ::Bool # if window is hidden. Will not render + clear ::Bool + function GLFWScreen( + name ::Symbol, + area ::NamedTuple, + parent ::Union{Screen, Void}, + children ::Vector{Screen}, + callbacks ::Dict{Symbol, Any}, + hidden, + clear ::Bool, + ) + screen = new() + if parent != nothing + screen.parent = parent + end + screen.name = name + screen.area = area + screen.children = children + screen.callbacks = callbacks + screen.hidden = hidden + screen.clear = clear + screen.id = new_id() + screen + end +end +""" +Most basic Screen constructor, which is usually used to create a parent screen. +It creates an OpenGL context and registeres all the callbacks +from the kw_arg `callbacks`. +You can change the OpenGL version with `major` and `minor`. +Also `windowhints` and `contexthints` can be given. +You can query the standard context and window hints +with `GLWindow.standard_context_hints` and `GLWindow.standard_window_hints`. +Finally you have the kw_args color and resolution. The first sets the background +color of the window and the other the resolution of the window. +""" +function GLFWScreen(name = "GLWindow"; + resolution = standard_screen_resolution(), + debugging = false, + major = 3, + minor = 3,# this is what GLVisualize needs to offer all features + windowhints = standard_window_hints(), + contexthints = standard_context_hints(major, minor), + callbacks = standard_callbacks(), + clear = true, + hidden = false, + visible = true, + focus = false, + fullscreen = false, + monitor = nothing + + ) + # create glcontext + + window = GLFW.Window( + name, + resolution = resolution, debugging = debugging, + major = major, minor = minor, + windowhints = windowhints, contexthints=contexthints, + visible = visible, focus = focus, + fullscreen = fullscreen, + monitor = monitor + ) + #create standard signals + callback_dict = register_callbacks(window, callbacks) + + area = (x=0, y=0, w=resolution[1], h=resolution[2]) + GLFW.SwapInterval(0) # deactivating vsync seems to make everything quite a bit smoother + screen = Screen( + Symbol(name), area, nothing, + Screen[], callback_dict, + (), hidden, clear + ) + signal_dict[:mouseinside] = droprepeats( + const_lift(isinside, screen, signal_dict[:mouseposition]) + ) + screen +end + +"Create a screen from a parent screen" +function GLFWScreen( + parent::GLFWScreen; + name = gensym(parent.name), + area = zeroposition(parent.area), + children::Vector{GLFWScreen} = GLFWScreen[], + callbacks::Dict{Symbol, Any} = copy(parent.callbacks), + hidden = parent.hidden, + clear::Bool = parent.clear, + ) + screen = GLFWScreen(name, area, parent, children, callbacks, hidden, clear) + push!(parent.children, screen) + screen +end + +nativewindow(s::Screen) = s.glcontext.window + +function destroywindow!(screen::GLFWScreen) + nw = nativewindow(screen) + if nw.handle != C_NULL + GLFW.DestroyWindow(nw) + nw.handle = C_NULL + end +end + +make_fullscreen!(screen::GLFWScreen, monitor::GLFW.Monitor = GLFW.GetPrimaryMonitor()) = make_fullscreen!(nativewindow(screen), monitor) + +function scaling_factor(nw) + w, fb = GLFW.GetWindowSize(nw), GLFW.GetFramebufferSize(nw) + scaling_factor((w,w), (fb,fb)) +end \ No newline at end of file diff --git a/src/GLWindow.jl b/src/GLWindow.jl old mode 100755 new mode 100644 index 3f407ea..95bdb43 --- a/src/GLWindow.jl +++ b/src/GLWindow.jl @@ -1,56 +1,9 @@ __precompile__(true) module GLWindow -using ModernGL -using GLAbstraction -using GLFW -using Reactive -using StaticArrays -using GeometryTypes -using ColorTypes -using FixedPointNumbers -using FileIO + using GLFW -import GLFW: Window, Monitor -import GLAbstraction: render, N0f8 -import GeometryTypes: widths - - -include("types.jl") - -include("core.jl") -include("events.jl") -export pressed, dragged, clicked - -include("callbacks.jl") -include("render.jl") -include("screen.jl") - -export createwindow -export swapbuffers -export poll_glfw -export Screen -export UnicodeInput -export KeyPressed -export MouseClicked -export MouseMoved -export EnteredWindow -export WindowResized -export MouseDragged -export Scrolled -export Window -export leftclickdown -export Screen -export primarymonitorresolution -export renderloop -export render_frame -export screenshot -export screenbuffer -export zeroposition -export create_glcontext -export renderlist -export destroy! -export robj_from_camera -export AbstractContext + include("callbacks.jl") + include("screen.jl") end diff --git a/src/callbacks.jl b/src/callbacks.jl index 9a526d8..51bdc3d 100644 --- a/src/callbacks.jl +++ b/src/callbacks.jl @@ -1,160 +1,22 @@ -""" -Returns a signal, which is true as long as the window is open. -returns `Signal{Bool}` -[GLFW Docs](http://www.glfw.org/docs/latest/group__window.html#gaade9264e79fae52bdb78e2df11ee8d6a) -""" -function window_open(window, s::Signal{Bool}=Signal(true)) - GLFW.SetWindowCloseCallback(window, (window,) -> begin - push!(s, false) - end) - s -end -""" -Size of the window. Must not correlate to the real pixel size. -This is why there is also framebuffer_size. -returns `Signal{Vec{2,Int}}` -[GLFW Docs](http://www.glfw.org/docs/latest/group__window.html#gaaca1c2715759d03da9834eac19323d4a) -""" -function window_size(window, s::Signal{Vec{2,Int}}=Signal(Vec{2,Int}(GLFW.GetWindowSize(window)))) - GLFW.SetWindowSizeCallback(window, (window, w::Cint, h::Cint,) -> begin - push!(s, Vec{2,Int}(w, h)) - end) - s -end -""" -Size of window in pixel. -returns `Signal{Vec{2,Int}}` -[GLFW Docs](http://www.glfw.org/docs/latest/group__window.html#ga311bb32e578aa240b6464af494debffc) -""" -function framebuffer_size(window, s::Signal{Vec{2, Int}}=Signal(Vec{2, Int}(GLFW.GetFramebufferSize(window)))) - GLFW.SetFramebufferSizeCallback(window, (window, w::Cint, h::Cint) -> begin - push!(s, Vec(Int(w), Int(h))) - end) - s -end -""" -Position of the window in screen coordinates. -returns `Signal{Vec{2,Int}}` -[GLFW Docs](http://www.glfw.org/docs/latest/group__window.html#ga1c36e52549efd47790eb3f324da71924) -""" -function window_position(window, s::Signal{Vec{2,Int}} = Signal(Vec(0,0))) - GLFW.SetWindowPosCallback(window, (window, x::Cint, y::Cint,) -> begin - push!(s, Vec(Int(x), Int(y))) - end) - s -end -""" -Registers a callback for the mouse buttons + modifiers -returns `Signal{NTuple{4, Int}}` -[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#ga1e008c7a8751cea648c8f42cc91104cf) -""" -function keyboard_buttons(window, s::Signal{NTuple{4, Int}}=Signal((0,0,0,0))) - keydict = Dict{Int, Bool}() - GLFW.SetKeyCallback(window, (window, button::Cint, scancode::Cint, action::Cint, mods::Cint) -> begin - push!(s, (Int(button), Int(scancode), Int(action), Int(mods))) - end) - s -end -""" -Registers a callback for the mouse buttons + modifiers -returns an `Signal{NTuple{3, Int}}`, -containing the pressed button the action and modifiers. -[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#ga1e008c7a8751cea648c8f42cc91104cf) -""" -function mouse_buttons(window, s::Signal{NTuple{3, Int}}=Signal((0,0,0))) - GLFW.SetMouseButtonCallback(window, (window, button::Cint, action::Cint, mods::Cint) -> begin - push!(s, (Int(button), Int(action), Int(mods))) - end) - s -end -""" -Registers a callback for drag and drop of files. -returns `Signal{Vector{String}}`, which are absolute file paths -[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#gacc95e259ad21d4f666faa6280d4018fd) -""" -function dropped_files(window, s::Signal{Vector{String}}=Signal(String[])) - GLFW.SetDropCallback(window, (window, files) -> begin - push!(s, map(String, files)) - end) - s -end +#each backend should provide these callbacks i think. +include("GLFW/callbacks.jl") """ -Registers a callback for keyboard unicode input. -returns an `Signal{Vector{Char}}`, -containing the pressed char. Is empty, if no key is pressed. -[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#ga1e008c7a8751cea648c8f42cc91104cf) -""" -function unicode_input(window, s::Signal{Vector{Char}} = Signal(Char[])) - GLFW.SetCharCallback(window, (window, c::Char) -> begin - vals = value(s) - push!(vals, c) - push!(s, vals) - empty!(vals) - push!(s, vals) - end) - s -end -""" -Registers a callback for the mouse cursor position. -returns an `Signal{Vec{2, Float64}}`, -which is not in screen coordinates, with the upper left window corner being 0 -[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#ga1e008c7a8751cea648c8f42cc91104cf) -""" -function cursor_position(window, s::Signal{Vec{2, Float64}}=Signal(Vec(0.,0.))) - GLFW.SetCursorPosCallback(window, (window, x::Cdouble, y::Cdouble) -> begin - push!(s, Vec{2, Float64}(x, y)) - end) - s -end -""" -Registers a callback for the mouse scroll. -returns an `Signal{Vec{2, Float64}}`, -which is an x and y offset. -[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#gacc95e259ad21d4f666faa6280d4018fd) -""" -function scroll(window, s::Signal{Vec{2, Float64}}=Signal(Vec(0.,0.))) - GLFW.SetScrollCallback(window, (window, xoffset::Cdouble, yoffset::Cdouble) -> begin - push!(s, Vec{2, Float64}(xoffset, yoffset)) - push!(s, Vec{2, Float64}(0)) - end) - s -end -""" -Registers a callback for the focus of a window. -returns an `Signal{Bool}`, -which is true whenever the window has focus. -[GLFW Docs](http://www.glfw.org/docs/latest/group__window.html#ga6b5f973531ea91663ad707ba4f2ac104) -""" -function hasfocus(window, s::Signal{Bool}=Signal(false)) - GLFW.SetWindowFocusCallback(window, (window, focus::Bool) -> begin - push!(s, focus) - end) - s -end -""" -Registers a callback for if the mouse has entered the window. -returns an `Signal{Bool}`, -which is true whenever the cursor enters the window. -[GLFW Docs](http://www.glfw.org/docs/latest/group__input.html#ga762d898d9b0241d7e3e3b767c6cf318f) -""" -function entered_window(window, s::Signal{Bool}=Signal(false)) - GLFW.SetCursorEnterCallback(window, (window, entered::Bool) -> begin - push!(s, entered) - end) - s -end - -""" -Takes a screen and registers a list of callback functions. -Returns a dict{Symbol, Signal}(name_of_callback => signal) -""" -function register_callbacks(window::GLFW.Window, callbacks::Vector{Function}) - tmp = map(callbacks) do f - (Symbol(last(split(string(f),"."))), f(window)) - end - Dict{Symbol, Any}(tmp) -end -function register_callbacks(window::Screen, callbacks::Vector{Function}) - register_callbacks(window.nativewindow, callbacks) -end +Standard set of callback functions +""" +function standard_callbacks() + Function[ + window_open, + window_size, + window_position, + keyboard_buttons, + mouse_buttons, + dropped_files, + framebuffer_size, + unicode_input, + cursor_position, + scroll, + hasfocus, + entered_window, + ] +end \ No newline at end of file diff --git a/src/copy.frag b/src/copy.frag deleted file mode 100644 index 0e6031b..0000000 --- a/src/copy.frag +++ /dev/null @@ -1,15 +0,0 @@ -{{GLSL_VERSION}} - -uniform sampler2D color_texture; -in vec2 frag_uv; -out vec4 fragment_color; - -void main(void) -{ - vec4 color = texture(color_texture, frag_uv); - if(color.a <= 0){ - discard; - } - fragment_color.rgb = color.rgb; - fragment_color.a = 1.0; -} diff --git a/src/core.jl b/src/core.jl deleted file mode 100644 index 9085712..0000000 --- a/src/core.jl +++ /dev/null @@ -1,55 +0,0 @@ -#= -Functions that are derived from Base or other packages -=# -function Base.show(io::IO, m::MonitorProperties) - println(io, "name: ", m.name) - println(io, "physicalsize: ", m.physicalsize[1], "x", m.physicalsize[2]) - println(io, "resolution: ", m.videomode.width, "x", m.videomode.height) - println(io, "dpi: ", m.dpi[1], "x", m.dpi[2]) -end -function Base.show(io::IO, m::Screen) - println(io, "name: ", m.name) - println(io, "children: ", length(m.children)) - println(io, "Inputs:") - for (key, value) in m.inputs - println(io, " ", key, " => ", typeof(value)) - end -end - -""" -mouse position is in coorditnates relative to `screen` -""" -function GeometryTypes.isinside(screen::Screen, mpos) - isinside(zeroposition(value(screen.area)), mpos[1], mpos[2]) || return false - for s in screen.children - # if inside any children, it's not inside screen - isinside(value(s.area), mpos[1], mpos[2]) && return false - end - true -end - -""" -Args: `screens_mpos` -> Tuple{Vector{Screen}, Vec{2,T}} -""" -function isoutside(screens_mouseposition) - screens, mpos = screens_mouseposition - for screen in screens - isinside(screen, mpos) && return false - end - true -end - -""" -Returns the monitor resolution of the primary monitor. -""" -function primarymonitorresolution() - props = MonitorProperties(GLFW.GetPrimaryMonitor()) - w,h = props.videomode.width, props.videomode.height - Vec(Int(w),Int(h)) -end - -""" -Create a new rectangle with x,y == 0,0 while taking the widths from the original -Rectangle -""" -zeroposition(r::SimpleRectangle{T}) where {T} = SimpleRectangle(zero(T), zero(T), r.w, r.h) diff --git a/src/events.jl b/src/events.jl deleted file mode 100644 index ec3cb2b..0000000 --- a/src/events.jl +++ /dev/null @@ -1,127 +0,0 @@ - -function to_arrow_symbol(button_set) - for b in button_set - GLFW.KEY_RIGHT == b && return :right - GLFW.KEY_LEFT == b && return :left - GLFW.KEY_DOWN == b && return :down - GLFW.KEY_UP == b && return :up - end - return :nothing -end - -function mousedragg_objectid(mouse_dragg, mouse_hover) - map(mouse_dragg) do dragg - value(mouse_hover), dragg - end -end - -function add_complex_signals!(screen) - @materialize keyboard_buttons, mouse_buttons = screen.inputs - - no_scancode = map(remove_scancode, keyboard_buttons) - - button_s = merge( - button_signals(no_scancode, :button), - button_signals(mouse_buttons, :mouse_button) - ) - - arrow_navigation = const_lift(to_arrow_symbol, button_s[:buttons_pressed]) - - merge!( - screen.inputs, - Dict{Symbol, Any}( - :arrow_navigation => arrow_navigation - ), - button_s - ) - screen.inputs[:key_pressed] = const_lift(GLAbstraction.singlepressed, - screen.inputs[:mouse_buttons_pressed], - GLFW.MOUSE_BUTTON_LEFT - ) - return -end - - -""" -Builds a Set of keys, accounting for released and pressed keys -""" -function currently_pressed_keys(v0::Set{Int}, button_action_mods) - button, action, mods = button_action_mods - if button != GLFW.KEY_UNKNOWN - if action == GLFW.PRESS - push!(v0, button) - elseif action == GLFW.RELEASE - delete!(v0, button) - elseif action == GLFW.REPEAT - # nothing needs to be done, besides returning the same set of keys - else - error("Unrecognized enum value for GLFW button press action: $action") - end - end - return v0 -end - -function remove_scancode(button_scancode_action_mods) - button, scancode, action, mods = button_scancode_action_mods - button, action, mods -end -isreleased(button) = button[2] == GLFW.RELEASE -isdown(button) = button[2] == GLFW.PRESS - -""" -Creates high level signals from the raw GLFW button signals. -Returns a dictionary with button released and down signals. -It also creates a signal, which is the set of all currently pressed buttons. -`name` is used to name the dictionary keys. -`buttons` is a tuple of (button, action, mods)::NTuple{3, Int} -""" -function button_signals(buttons::Signal{NTuple{3, Int}}, name::Symbol) - keyset = Set{Int}() - sizehint!(keyset, 10) # make it less suspicable to growing/shrinking - released = filter(isreleased, buttons.value, buttons) - down = filter(isdown, buttons.value, buttons) - Dict{Symbol, Any}( - Symbol("$(name)_released") => map(first, released), - Symbol("$(name)_down") => map(first, down), - Symbol("$(name)s_pressed") => foldp( - currently_pressed_keys, keyset, buttons - ) - ) -end - -""" -Selection of random objects on the screen is realized by rendering an -object id + plus an arbitrary index into the framebuffer. -The index can be used for e.g. instanced geometries. -""" -struct SelectionID{T <: Integer} <: FieldVector{2, T} - id::T - index::T - # function SelectionID(args::NTuple{2, T}) - # new{T}(args[1], args[2]) - # end -end - -const selection_data = Base.RefValue{SelectionID{UInt16}}() -const old_mouse_position = Base.RefValue(Vec{2, Float64}(0)) - -function push_selectionqueries!(screen) - mouse_position = value(mouseposition(screen)) - selection_signal = mouse2id(screen) - window_size = widths(screen) - buff = framebuffer(screen).objectid - if old_mouse_position[] != mouse_position - glReadBuffer(GL_COLOR_ATTACHMENT1) - x, y = Vec{2, Int}(floor.(mouse_position)) - w, h = window_size - if x > 0 && y > 0 && x <= w && y <= h - glReadPixels(x, y, 1, 1, buff.format, buff.pixeltype, selection_data) - val = convert(SelectionID{Int}, selection_data[]) - push!(selection_signal, val) - end - old_mouse_position[] = mouse_position - end -end - - -export screenshot, screenbuffer diff --git a/src/fullscreen.vert b/src/fullscreen.vert deleted file mode 100644 index aba2c5e..0000000 --- a/src/fullscreen.vert +++ /dev/null @@ -1,15 +0,0 @@ -{{GLSL_VERSION}} - -out vec2 frag_uv; - -void main() { - vec2 uv = vec2(0,0); - if((gl_VertexID & 1) != 0) - uv.x = 1; - if((gl_VertexID & 2) != 0) - uv.y = 1; - - frag_uv = uv * 2; - gl_Position.xy = (uv * 4) - 1; - gl_Position.zw = vec2(0,1); -} diff --git a/src/fxaa.frag b/src/fxaa.frag deleted file mode 100644 index 85851c5..0000000 --- a/src/fxaa.frag +++ /dev/null @@ -1,1049 +0,0 @@ -{{GLSL_VERSION}} - -#define FXAA_PC 1 -#define FXAA_GLSL_130 1 -#define FXAA_QUALITY__PRESET 12 -#define FXAA_GREEN_AS_LUMA 0 -#define FXAA_GATHER4_ALPHA 0 -/*--------------------------------------------------------------------------*/ -#ifndef FXAA_PC_CONSOLE - // - // The console algorithm for PC is included - // for developers targeting really low spec machines. - // Likely better to just run FXAA_PC, and use a really low preset. - // - #define FXAA_PC_CONSOLE 0 -#endif -/*--------------------------------------------------------------------------*/ -#ifndef FXAA_GLSL_120 - #define FXAA_GLSL_120 0 -#endif -/*--------------------------------------------------------------------------*/ -#ifndef FXAA_GLSL_130 - #define FXAA_GLSL_130 0 -#endif -/*--------------------------------------------------------------------------*/ -#ifndef FXAA_HLSL_3 - #define FXAA_HLSL_3 0 -#endif -/*--------------------------------------------------------------------------*/ -#ifndef FXAA_HLSL_4 - #define FXAA_HLSL_4 0 -#endif -/*--------------------------------------------------------------------------*/ -#ifndef FXAA_HLSL_5 - #define FXAA_HLSL_5 0 -#endif -/*==========================================================================*/ -#ifndef FXAA_GREEN_AS_LUMA - // - // For those using non-linear color, - // and either not able to get luma in alpha, or not wanting to, - // this enables FXAA to run using green as a proxy for luma. - // So with this enabled, no need to pack luma in alpha. - // - // This will turn off AA on anything which lacks some amount of green. - // Pure red and blue or combination of only R and B, will get no AA. - // - // Might want to lower the settings for both, - // fxaaConsoleEdgeThresholdMin - // fxaaQualityEdgeThresholdMin - // In order to insure AA does not get turned off on colors - // which contain a minor amount of green. - // - // 1 = On. - // 0 = Off. - // - #define FXAA_GREEN_AS_LUMA 0 -#endif -/*--------------------------------------------------------------------------*/ -#ifndef FXAA_EARLY_EXIT - // - // Controls algorithm's early exit path. - // On PS3 turning this ON adds 2 cycles to the shader. - // On 360 turning this OFF adds 10ths of a millisecond to the shader. - // Turning this off on console will result in a more blurry image. - // So this defaults to on. - // - // 1 = On. - // 0 = Off. - // - #define FXAA_EARLY_EXIT 1 -#endif -/*--------------------------------------------------------------------------*/ -#ifndef FXAA_DISCARD - // - // Only valid for PC OpenGL currently. - // Probably will not work when FXAA_GREEN_AS_LUMA = 1. - // - // 1 = Use discard on pixels which don't need AA. - // For APIs which enable concurrent TEX+ROP from same surface. - // 0 = Return unchanged color on pixels which don't need AA. - // - #define FXAA_DISCARD 0 -#endif -/*--------------------------------------------------------------------------*/ -#ifndef FXAA_FAST_PIXEL_OFFSET - // - // Used for GLSL 120 only. - // - // 1 = GL API supports fast pixel offsets - // 0 = do not use fast pixel offsets - // - #ifdef GL_EXT_gpu_shader4 - #define FXAA_FAST_PIXEL_OFFSET 1 - #endif - #ifdef GL_NV_gpu_shader5 - #define FXAA_FAST_PIXEL_OFFSET 1 - #endif - #ifdef GL_ARB_gpu_shader5 - #define FXAA_FAST_PIXEL_OFFSET 1 - #endif - #ifndef FXAA_FAST_PIXEL_OFFSET - #define FXAA_FAST_PIXEL_OFFSET 0 - #endif -#endif -/*--------------------------------------------------------------------------*/ -#ifndef FXAA_GATHER4_ALPHA - // - // 1 = API supports gather4 on alpha channel. - // 0 = API does not support gather4 on alpha channel. - // - #if (FXAA_HLSL_5 == 1) - #define FXAA_GATHER4_ALPHA 1 - #endif - #ifdef GL_ARB_gpu_shader5 - #define FXAA_GATHER4_ALPHA 1 - #endif - #ifdef GL_NV_gpu_shader5 - #define FXAA_GATHER4_ALPHA 1 - #endif - #ifndef FXAA_GATHER4_ALPHA - #define FXAA_GATHER4_ALPHA 0 - #endif -#endif - - -/*============================================================================ - FXAA QUALITY - TUNING KNOBS ------------------------------------------------------------------------------- -NOTE the other tuning knobs are now in the shader function inputs! -============================================================================*/ -#ifndef FXAA_QUALITY__PRESET - // - // Choose the quality preset. - // This needs to be compiled into the shader as it effects code. - // Best option to include multiple presets is to - // in each shader define the preset, then include this file. - // - // OPTIONS - // ----------------------------------------------------------------------- - // 10 to 15 - default medium dither (10=fastest, 15=highest quality) - // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality) - // 39 - no dither, very expensive - // - // NOTES - // ----------------------------------------------------------------------- - // 12 = slightly faster then FXAA 3.9 and higher edge quality (default) - // 13 = about same speed as FXAA 3.9 and better than 12 - // 23 = closest to FXAA 3.9 visually and performance wise - // _ = the lowest digit is directly related to performance - // _ = the highest digit is directly related to style - // - #define FXAA_QUALITY__PRESET 12 -#endif - - -/*============================================================================ - - FXAA QUALITY - PRESETS - -============================================================================*/ - -/*============================================================================ - FXAA QUALITY - MEDIUM DITHER PRESETS -============================================================================*/ -#if (FXAA_QUALITY__PRESET == 10) - #define FXAA_QUALITY__PS 3 - #define FXAA_QUALITY__P0 1.5 - #define FXAA_QUALITY__P1 3.0 - #define FXAA_QUALITY__P2 12.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 11) - #define FXAA_QUALITY__PS 4 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 3.0 - #define FXAA_QUALITY__P3 12.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 12) - #define FXAA_QUALITY__PS 5 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 4.0 - #define FXAA_QUALITY__P4 12.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 13) - #define FXAA_QUALITY__PS 6 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 4.0 - #define FXAA_QUALITY__P5 12.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 14) - #define FXAA_QUALITY__PS 7 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 4.0 - #define FXAA_QUALITY__P6 12.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 15) - #define FXAA_QUALITY__PS 8 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 4.0 - #define FXAA_QUALITY__P7 12.0 -#endif - -/*============================================================================ - FXAA QUALITY - LOW DITHER PRESETS -============================================================================*/ -#if (FXAA_QUALITY__PRESET == 20) - #define FXAA_QUALITY__PS 3 - #define FXAA_QUALITY__P0 1.5 - #define FXAA_QUALITY__P1 2.0 - #define FXAA_QUALITY__P2 8.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 21) - #define FXAA_QUALITY__PS 4 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 8.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 22) - #define FXAA_QUALITY__PS 5 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 8.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 23) - #define FXAA_QUALITY__PS 6 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 8.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 24) - #define FXAA_QUALITY__PS 7 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 3.0 - #define FXAA_QUALITY__P6 8.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 25) - #define FXAA_QUALITY__PS 8 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 4.0 - #define FXAA_QUALITY__P7 8.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 26) - #define FXAA_QUALITY__PS 9 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 2.0 - #define FXAA_QUALITY__P7 4.0 - #define FXAA_QUALITY__P8 8.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 27) - #define FXAA_QUALITY__PS 10 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 2.0 - #define FXAA_QUALITY__P7 2.0 - #define FXAA_QUALITY__P8 4.0 - #define FXAA_QUALITY__P9 8.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 28) - #define FXAA_QUALITY__PS 11 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 2.0 - #define FXAA_QUALITY__P7 2.0 - #define FXAA_QUALITY__P8 2.0 - #define FXAA_QUALITY__P9 4.0 - #define FXAA_QUALITY__P10 8.0 -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 29) - #define FXAA_QUALITY__PS 12 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 2.0 - #define FXAA_QUALITY__P7 2.0 - #define FXAA_QUALITY__P8 2.0 - #define FXAA_QUALITY__P9 2.0 - #define FXAA_QUALITY__P10 4.0 - #define FXAA_QUALITY__P11 8.0 -#endif - -/*============================================================================ - FXAA QUALITY - EXTREME QUALITY -============================================================================*/ -#if (FXAA_QUALITY__PRESET == 39) - #define FXAA_QUALITY__PS 12 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.0 - #define FXAA_QUALITY__P2 1.0 - #define FXAA_QUALITY__P3 1.0 - #define FXAA_QUALITY__P4 1.0 - #define FXAA_QUALITY__P5 1.5 - #define FXAA_QUALITY__P6 2.0 - #define FXAA_QUALITY__P7 2.0 - #define FXAA_QUALITY__P8 2.0 - #define FXAA_QUALITY__P9 2.0 - #define FXAA_QUALITY__P10 4.0 - #define FXAA_QUALITY__P11 8.0 -#endif - - - -/*============================================================================ - - API PORTING - -============================================================================*/ -#if (FXAA_GLSL_120 == 1) || (FXAA_GLSL_130 == 1) - #define FxaaBool bool - #define FxaaDiscard discard - #define FxaaFloat float - #define FxaaFloat2 vec2 - #define FxaaFloat3 vec3 - #define FxaaFloat4 vec4 - #define FxaaHalf float - #define FxaaHalf2 vec2 - #define FxaaHalf3 vec3 - #define FxaaHalf4 vec4 - #define FxaaInt2 ivec2 - #define FxaaSat(x) clamp(x, 0.0, 1.0) - #define FxaaTex sampler2D -#else - #define FxaaBool bool - #define FxaaDiscard clip(-1) - #define FxaaFloat float - #define FxaaFloat2 float2 - #define FxaaFloat3 float3 - #define FxaaFloat4 float4 - #define FxaaHalf half - #define FxaaHalf2 half2 - #define FxaaHalf3 half3 - #define FxaaHalf4 half4 - #define FxaaSat(x) saturate(x) -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_GLSL_120 == 1) - // Requires, - // #version 120 - // And at least, - // #extension GL_EXT_gpu_shader4 : enable - // (or set FXAA_FAST_PIXEL_OFFSET 1 to work like DX9) - #define FxaaTexTop(t, p) texture2DLod(t, p, 0.0) - #if (FXAA_FAST_PIXEL_OFFSET == 1) - #define FxaaTexOff(t, p, o, r) texture2DLodOffset(t, p, 0.0, o) - #else - #define FxaaTexOff(t, p, o, r) texture2DLod(t, p + (o * r), 0.0) - #endif - #if (FXAA_GATHER4_ALPHA == 1) - // use #extension GL_ARB_gpu_shader5 : enable - #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) - #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) - #define FxaaTexGreen4(t, p) textureGather(t, p, 1) - #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) - #endif -#endif -/*--------------------------------------------------------------------------*/ -#if (FXAA_GLSL_130 == 1) - // Requires "#version 130" or better - #define FxaaTexTop(t, p) textureLod(t, p, 0.0) - #define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o) - #if (FXAA_GATHER4_ALPHA == 1) - // use #extension GL_ARB_gpu_shader5 : enable - #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) - #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) - #define FxaaTexGreen4(t, p) textureGather(t, p, 1) - #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) - #endif -#endif -/*--------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------*/ -#if (FXAA_HLSL_5 == 1) - #define FxaaInt2 int2 - struct FxaaTex { SamplerState smpl; Texture2D tex; }; - #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) - #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) - #define FxaaTexAlpha4(t, p) t.tex.GatherAlpha(t.smpl, p) - #define FxaaTexOffAlpha4(t, p, o) t.tex.GatherAlpha(t.smpl, p, o) - #define FxaaTexGreen4(t, p) t.tex.GatherGreen(t.smpl, p) - #define FxaaTexOffGreen4(t, p, o) t.tex.GatherGreen(t.smpl, p, o) -#endif - - -/*============================================================================ - GREEN AS LUMA OPTION SUPPORT FUNCTION -============================================================================*/ -#if (FXAA_GREEN_AS_LUMA == 0) - FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.a; } -#else - FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; } -#endif - - - - -/*============================================================================ - - FXAA3 QUALITY - PC - -============================================================================*/ -#if (FXAA_PC == 1) -/*--------------------------------------------------------------------------*/ -FxaaFloat4 FxaaPixelShader( - // - // Use noperspective interpolation here (turn off perspective interpolation). - // {xy} = center of pixel - FxaaFloat2 pos, - // - // Used only for FXAA Console, and not used on the 360 version. - // Use noperspective interpolation here (turn off perspective interpolation). - // {xy__} = upper left of pixel - // {__zw} = lower right of pixel - FxaaFloat4 fxaaConsolePosPos, - // - // Input color texture. - // {rgb_} = color in linear or perceptual color space - // if (FXAA_GREEN_AS_LUMA == 0) - // {___a} = luma in perceptual color space (not linear) - FxaaTex tex, - // - // Only used on the optimized 360 version of FXAA Console. - // For everything but 360, just use the same input here as for "tex". - // For 360, same texture, just alias with a 2nd sampler. - // This sampler needs to have an exponent bias of -1. - FxaaTex fxaaConsole360TexExpBiasNegOne, - // - // Only used on the optimized 360 version of FXAA Console. - // For everything but 360, just use the same input here as for "tex". - // For 360, same texture, just alias with a 3nd sampler. - // This sampler needs to have an exponent bias of -2. - FxaaTex fxaaConsole360TexExpBiasNegTwo, - // - // Only used on FXAA Quality. - // This must be from a constant/uniform. - // {x_} = 1.0/screenWidthInPixels - // {_y} = 1.0/screenHeightInPixels - FxaaFloat2 fxaaQualityRcpFrame, - // - // Only used on FXAA Console. - // This must be from a constant/uniform. - // This effects sub-pixel AA quality and inversely sharpness. - // Where N ranges between, - // N = 0.50 (default) - // N = 0.33 (sharper) - // {x___} = -N/screenWidthInPixels - // {_y__} = -N/screenHeightInPixels - // {__z_} = N/screenWidthInPixels - // {___w} = N/screenHeightInPixels - FxaaFloat4 fxaaConsoleRcpFrameOpt, - // - // Only used on FXAA Console. - // Not used on 360, but used on PS3 and PC. - // This must be from a constant/uniform. - // {x___} = -2.0/screenWidthInPixels - // {_y__} = -2.0/screenHeightInPixels - // {__z_} = 2.0/screenWidthInPixels - // {___w} = 2.0/screenHeightInPixels - FxaaFloat4 fxaaConsoleRcpFrameOpt2, - // - // Only used on FXAA Console. - // Only used on 360 in place of fxaaConsoleRcpFrameOpt2. - // This must be from a constant/uniform. - // {x___} = 8.0/screenWidthInPixels - // {_y__} = 8.0/screenHeightInPixels - // {__z_} = -4.0/screenWidthInPixels - // {___w} = -4.0/screenHeightInPixels - FxaaFloat4 fxaaConsole360RcpFrameOpt2, - // - // Only used on FXAA Quality. - // This used to be the FXAA_QUALITY__SUBPIX define. - // It is here now to allow easier tuning. - // Choose the amount of sub-pixel aliasing removal. - // This can effect sharpness. - // 1.00 - upper limit (softer) - // 0.75 - default amount of filtering - // 0.50 - lower limit (sharper, less sub-pixel aliasing removal) - // 0.25 - almost off - // 0.00 - completely off - FxaaFloat fxaaQualitySubpix, - // - // Only used on FXAA Quality. - // This used to be the FXAA_QUALITY__EDGE_THRESHOLD define. - // It is here now to allow easier tuning. - // The minimum amount of local contrast required to apply algorithm. - // 0.333 - too little (faster) - // 0.250 - low quality - // 0.166 - default - // 0.125 - high quality - // 0.063 - overkill (slower) - FxaaFloat fxaaQualityEdgeThreshold, - // - // Only used on FXAA Quality. - // This used to be the FXAA_QUALITY__EDGE_THRESHOLD_MIN define. - // It is here now to allow easier tuning. - // Trims the algorithm from processing darks. - // 0.0833 - upper limit (default, the start of visible unfiltered edges) - // 0.0625 - high quality (faster) - // 0.0312 - visible limit (slower) - // Special notes when using FXAA_GREEN_AS_LUMA, - // Likely want to set this to zero. - // As colors that are mostly not-green - // will appear very dark in the green channel! - // Tune by looking at mostly non-green content, - // then start at zero and increase until aliasing is a problem. - FxaaFloat fxaaQualityEdgeThresholdMin, - // - // Only used on FXAA Console. - // This used to be the FXAA_CONSOLE__EDGE_SHARPNESS define. - // It is here now to allow easier tuning. - // This does not effect PS3, as this needs to be compiled in. - // Use FXAA_CONSOLE__PS3_EDGE_SHARPNESS for PS3. - // Due to the PS3 being ALU bound, - // there are only three safe values here: 2 and 4 and 8. - // These options use the shaders ability to a free *|/ by 2|4|8. - // For all other platforms can be a non-power of two. - // 8.0 is sharper (default!!!) - // 4.0 is softer - // 2.0 is really soft (good only for vector graphics inputs) - FxaaFloat fxaaConsoleEdgeSharpness, - // - // Only used on FXAA Console. - // This used to be the FXAA_CONSOLE__EDGE_THRESHOLD define. - // It is here now to allow easier tuning. - // This does not effect PS3, as this needs to be compiled in. - // Use FXAA_CONSOLE__PS3_EDGE_THRESHOLD for PS3. - // Due to the PS3 being ALU bound, - // there are only two safe values here: 1/4 and 1/8. - // These options use the shaders ability to a free *|/ by 2|4|8. - // The console setting has a different mapping than the quality setting. - // Other platforms can use other values. - // 0.125 leaves less aliasing, but is softer (default!!!) - // 0.25 leaves more aliasing, and is sharper - FxaaFloat fxaaConsoleEdgeThreshold, - // - // Only used on FXAA Console. - // This used to be the FXAA_CONSOLE__EDGE_THRESHOLD_MIN define. - // It is here now to allow easier tuning. - // Trims the algorithm from processing darks. - // The console setting has a different mapping than the quality setting. - // This only applies when FXAA_EARLY_EXIT is 1. - // This does not apply to PS3, - // PS3 was simplified to avoid more shader instructions. - // 0.06 - faster but more aliasing in darks - // 0.05 - default - // 0.04 - slower and less aliasing in darks - // Special notes when using FXAA_GREEN_AS_LUMA, - // Likely want to set this to zero. - // As colors that are mostly not-green - // will appear very dark in the green channel! - // Tune by looking at mostly non-green content, - // then start at zero and increase until aliasing is a problem. - FxaaFloat fxaaConsoleEdgeThresholdMin, - // - // Extra constants for 360 FXAA Console only. - // Use zeros or anything else for other platforms. - // These must be in physical constant registers and NOT immedates. - // Immedates will result in compiler un-optimizing. - // {xyzw} = float4(1.0, -1.0, 0.25, -0.25) - FxaaFloat4 fxaaConsole360ConstDir -) { -/*--------------------------------------------------------------------------*/ - FxaaFloat2 posM; - posM.x = pos.x; - posM.y = pos.y; - #if (FXAA_GATHER4_ALPHA == 1) - #if (FXAA_DISCARD == 0) - FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); - #if (FXAA_GREEN_AS_LUMA == 0) - #define lumaM rgbyM.w - #else - #define lumaM rgbyM.y - #endif - #endif - #if (FXAA_GREEN_AS_LUMA == 0) - FxaaFloat4 luma4A = FxaaTexAlpha4(tex, posM); - FxaaFloat4 luma4B = FxaaTexOffAlpha4(tex, posM, FxaaInt2(-1, -1)); - #else - FxaaFloat4 luma4A = FxaaTexGreen4(tex, posM); - FxaaFloat4 luma4B = FxaaTexOffGreen4(tex, posM, FxaaInt2(-1, -1)); - #endif - #if (FXAA_DISCARD == 1) - #define lumaM luma4A.w - #endif - #define lumaE luma4A.z - #define lumaS luma4A.x - #define lumaSE luma4A.y - #define lumaNW luma4B.w - #define lumaN luma4B.z - #define lumaW luma4B.x - #else - FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); - #if (FXAA_GREEN_AS_LUMA == 0) - #define lumaM rgbyM.w - #else - #define lumaM rgbyM.y - #endif - FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0, 1), fxaaQualityRcpFrame.xy)); - FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 0), fxaaQualityRcpFrame.xy)); - FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0,-1), fxaaQualityRcpFrame.xy)); - FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 0), fxaaQualityRcpFrame.xy)); - #endif -/*--------------------------------------------------------------------------*/ - FxaaFloat maxSM = max(lumaS, lumaM); - FxaaFloat minSM = min(lumaS, lumaM); - FxaaFloat maxESM = max(lumaE, maxSM); - FxaaFloat minESM = min(lumaE, minSM); - FxaaFloat maxWN = max(lumaN, lumaW); - FxaaFloat minWN = min(lumaN, lumaW); - FxaaFloat rangeMax = max(maxWN, maxESM); - FxaaFloat rangeMin = min(minWN, minESM); - FxaaFloat rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold; - FxaaFloat range = rangeMax - rangeMin; - FxaaFloat rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled); - FxaaBool earlyExit = range < rangeMaxClamped; -/*--------------------------------------------------------------------------*/ - if(earlyExit) - #if (FXAA_DISCARD == 1) - FxaaDiscard; - #else - return rgbyM; - #endif -/*--------------------------------------------------------------------------*/ - #if (FXAA_GATHER4_ALPHA == 0) - FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1,-1), fxaaQualityRcpFrame.xy)); - FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 1), fxaaQualityRcpFrame.xy)); - FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1,-1), fxaaQualityRcpFrame.xy)); - FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); - #else - FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(1, -1), fxaaQualityRcpFrame.xy)); - FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); - #endif -/*--------------------------------------------------------------------------*/ - FxaaFloat lumaNS = lumaN + lumaS; - FxaaFloat lumaWE = lumaW + lumaE; - FxaaFloat subpixRcpRange = 1.0/range; - FxaaFloat subpixNSWE = lumaNS + lumaWE; - FxaaFloat edgeHorz1 = (-2.0 * lumaM) + lumaNS; - FxaaFloat edgeVert1 = (-2.0 * lumaM) + lumaWE; -/*--------------------------------------------------------------------------*/ - FxaaFloat lumaNESE = lumaNE + lumaSE; - FxaaFloat lumaNWNE = lumaNW + lumaNE; - FxaaFloat edgeHorz2 = (-2.0 * lumaE) + lumaNESE; - FxaaFloat edgeVert2 = (-2.0 * lumaN) + lumaNWNE; -/*--------------------------------------------------------------------------*/ - FxaaFloat lumaNWSW = lumaNW + lumaSW; - FxaaFloat lumaSWSE = lumaSW + lumaSE; - FxaaFloat edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2); - FxaaFloat edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2); - FxaaFloat edgeHorz3 = (-2.0 * lumaW) + lumaNWSW; - FxaaFloat edgeVert3 = (-2.0 * lumaS) + lumaSWSE; - FxaaFloat edgeHorz = abs(edgeHorz3) + edgeHorz4; - FxaaFloat edgeVert = abs(edgeVert3) + edgeVert4; -/*--------------------------------------------------------------------------*/ - FxaaFloat subpixNWSWNESE = lumaNWSW + lumaNESE; - FxaaFloat lengthSign = fxaaQualityRcpFrame.x; - FxaaBool horzSpan = edgeHorz >= edgeVert; - FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; -/*--------------------------------------------------------------------------*/ - if(!horzSpan) lumaN = lumaW; - if(!horzSpan) lumaS = lumaE; - if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; - FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM; -/*--------------------------------------------------------------------------*/ - FxaaFloat gradientN = lumaN - lumaM; - FxaaFloat gradientS = lumaS - lumaM; - FxaaFloat lumaNN = lumaN + lumaM; - FxaaFloat lumaSS = lumaS + lumaM; - FxaaBool pairN = abs(gradientN) >= abs(gradientS); - FxaaFloat gradient = max(abs(gradientN), abs(gradientS)); - if(pairN) lengthSign = -lengthSign; - FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); -/*--------------------------------------------------------------------------*/ - FxaaFloat2 posB; - posB.x = posM.x; - posB.y = posM.y; - FxaaFloat2 offNP; - offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; - offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; - if(!horzSpan) posB.x += lengthSign * 0.5; - if( horzSpan) posB.y += lengthSign * 0.5; -/*--------------------------------------------------------------------------*/ - FxaaFloat2 posN; - posN.x = posB.x - offNP.x * FXAA_QUALITY__P0; - posN.y = posB.y - offNP.y * FXAA_QUALITY__P0; - FxaaFloat2 posP; - posP.x = posB.x + offNP.x * FXAA_QUALITY__P0; - posP.y = posB.y + offNP.y * FXAA_QUALITY__P0; - FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; - FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); - FxaaFloat subpixE = subpixC * subpixC; - FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); -/*--------------------------------------------------------------------------*/ - if(!pairN) lumaNN = lumaSS; - FxaaFloat gradientScaled = gradient * 1.0/4.0; - FxaaFloat lumaMM = lumaM - lumaNN * 0.5; - FxaaFloat subpixF = subpixD * subpixE; - FxaaBool lumaMLTZero = lumaMM < 0.0; -/*--------------------------------------------------------------------------*/ - lumaEndN -= lumaNN * 0.5; - lumaEndP -= lumaNN * 0.5; - FxaaBool doneN = abs(lumaEndN) >= gradientScaled; - FxaaBool doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1; - FxaaBool doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1; -/*--------------------------------------------------------------------------*/ - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2; -/*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 3) - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3; -/*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 4) - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4; -/*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 5) - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5; -/*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 6) - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6; -/*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 7) - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7; -/*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 8) - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8; -/*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 9) - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9; -/*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 10) - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10; -/*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 11) - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11; -/*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 12) - if(doneNP) { - if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); - if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); - if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; - if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; - doneN = abs(lumaEndN) >= gradientScaled; - doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12; - doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12; -/*--------------------------------------------------------------------------*/ - } - #endif -/*--------------------------------------------------------------------------*/ - } - #endif -/*--------------------------------------------------------------------------*/ - } - #endif -/*--------------------------------------------------------------------------*/ - } - #endif -/*--------------------------------------------------------------------------*/ - } - #endif -/*--------------------------------------------------------------------------*/ - } - #endif -/*--------------------------------------------------------------------------*/ - } - #endif -/*--------------------------------------------------------------------------*/ - } - #endif -/*--------------------------------------------------------------------------*/ - } - #endif -/*--------------------------------------------------------------------------*/ - } - #endif -/*--------------------------------------------------------------------------*/ - } -/*--------------------------------------------------------------------------*/ - FxaaFloat dstN = posM.x - posN.x; - FxaaFloat dstP = posP.x - posM.x; - if(!horzSpan) dstN = posM.y - posN.y; - if(!horzSpan) dstP = posP.y - posM.y; -/*--------------------------------------------------------------------------*/ - FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; - FxaaFloat spanLength = (dstP + dstN); - FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; - FxaaFloat spanLengthRcp = 1.0/spanLength; -/*--------------------------------------------------------------------------*/ - FxaaBool directionN = dstN < dstP; - FxaaFloat dst = min(dstN, dstP); - FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP; - FxaaFloat subpixG = subpixF * subpixF; - FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5; - FxaaFloat subpixH = subpixG * fxaaQualitySubpix; -/*--------------------------------------------------------------------------*/ - FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0; - FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH); - if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; - if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; - #if (FXAA_DISCARD == 1) - return FxaaTexTop(tex, posM); - #else - return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM); - #endif -} -/*==========================================================================*/ -#endif - - - - -//---------------------------------------------------------------------------------- -// File: es3-kepler/FXAA/assets/shaders/FXAA_Extreme_Quality.frag -// SDK Version: v2.11 -// Email: gameworks@nvidia.com -// Site: http://developer.nvidia.com/ -// -// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of NVIDIA CORPORATION nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -//---------------------------------------------------------------------------------- - -precision highp float; - -uniform sampler2D color_texture; -uniform vec2 RCPFrame; -in vec2 frag_uv; - -out vec4 fragment_color; - -void main(void) -{ - //fragment_color = texture(color_texture, frag_uv); - fragment_color = FxaaPixelShader( - frag_uv, - FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f), // FxaaFloat4 fxaaConsolePosPos, - color_texture, // FxaaTex tex, - color_texture, // FxaaTex fxaaConsole360TexExpBiasNegOne, - color_texture, // FxaaTex fxaaConsole360TexExpBiasNegTwo, - RCPFrame, // FxaaFloat2 fxaaQualityRcpFrame, - FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f), // FxaaFloat4 fxaaConsoleRcpFrameOpt, - FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f), // FxaaFloat4 fxaaConsoleRcpFrameOpt2, - FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f), // FxaaFloat4 fxaaConsole360RcpFrameOpt2, - 0.75f, // FxaaFloat fxaaQualitySubpix, - 0.166f, // FxaaFloat fxaaQualityEdgeThreshold, - 0.0833f, // FxaaFloat fxaaQualityEdgeThresholdMin, - 0.0f, // FxaaFloat fxaaConsoleEdgeSharpness, - 0.0f, // FxaaFloat fxaaConsoleEdgeThreshold, - 0.0f, // FxaaFloat fxaaConsoleEdgeThresholdMin, - FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f) // FxaaFloat fxaaConsole360ConstDir, - ); -} diff --git a/src/globals.jl b/src/globals.jl new file mode 100644 index 0000000..7e7f497 --- /dev/null +++ b/src/globals.jl @@ -0,0 +1,8 @@ + +using Base.RefValue +#This should be put in some kind of globals.jl file, like where the contexts are being counted. +const screen_id_counter = RefValue(0) +# start from new and hope we don't display all displays at once. +# TODO make it clearer if we reached max num, or if we just created +# a lot of small screens and display them simultanously +new_id() = (screen_id_counter[] = mod1(screen_id_counter[] + 1, 255); screen_id_counter[])[] \ No newline at end of file diff --git a/src/postprocess.frag b/src/postprocess.frag deleted file mode 100644 index fbf420e..0000000 --- a/src/postprocess.frag +++ /dev/null @@ -1,27 +0,0 @@ -{{GLSL_VERSION}} - -in vec2 frag_uv; - -uniform sampler2D color_texture; - -layout(location=0) out vec4 fragment_color; - -vec3 linear_tone_mapping(vec3 color, float gamma) -{ - color = clamp(color, 0., 1.); - color = pow(color, vec3(1. / gamma)); - return color; -} - -void main(void) -{ - vec4 color = texture(color_texture, frag_uv).rgba; - if(color.a <= 0){ - discard; - } - // do tonemapping - //opaque = linear_tone_mapping(color.rgb, 1.8); // linear color output - fragment_color.rgb = color.rgb; - // save luma in alpha for FXAA - fragment_color.a = dot(color.rgb, vec3(0.299, 0.587, 0.114)); // compute luma -} diff --git a/src/render.jl b/src/render.jl deleted file mode 100644 index 57d8940..0000000 --- a/src/render.jl +++ /dev/null @@ -1,203 +0,0 @@ - -function clear_all!(window) - wh = widths(window) - glViewport(0,0, wh...) - fb = framebuffer(window) - glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) - glDrawBuffers(2, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1]) - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - glBindFramebuffer(GL_FRAMEBUFFER, fb.id[2]) - glClear(GL_COLOR_BUFFER_BIT) - glBindFramebuffer(GL_FRAMEBUFFER, 0) - glClear(GL_COLOR_BUFFER_BIT) - return -end - - -""" -Sleep is pretty imprecise. E.g. anything under `0.001s` is not guaranteed to wake -up before `0.001s`. So this timer is pessimistic in the way, that it will never -sleep more than `time`. -""" -@inline function sleep_pessimistic(sleep_time) - st = convert(Float64,sleep_time) - 0.002 - start_time = time() - while (time() - start_time) < st - sleep(0.001) # sleep for the minimal amount of time - end -end -function reactive_run_till_now() - max_yield = Base.n_avail(Reactive._messages) * 2 - for i=1:max_yield - if !isready(Reactive._messages) - break - end - yield() - end -end -function renderloop(window::Screen; framerate = 1/60, - prerender = () -> nothing) - while isopen(window) - t = time() - prerender() - render_frame(window) - swapbuffers(window) - poll_glfw() - yield() - sleep_pessimistic(framerate - (time() - t)) # - end - destroy!(window) - return -end - - -function waiting_renderloop(screen; framerate = 1/60, - prerender = () -> nothing) - - while isopen(screen) - t = time() - poll_glfw() # GLFW poll - prerender() - if Base.n_avail(Reactive._messages) > 0 - reactive_run_till_now() - render_frame(screen) - swapbuffers(screen) - end - t = time() - t - sleep_pessimistic(framerate - t) - end - destroy!(screen) - return -end - -function shape_prerender() - glDisable(GL_DEPTH_TEST) - glDepthMask(GL_FALSE) - glDisable(GL_CULL_FACE) - glDisable(GL_BLEND) - return -end - -function setup_window(window, strokepass, pa = value(window.area)) - if isopen(window) && !ishidden(window) - sa = value(window.area) - sa = SimpleRectangle(pa.x+sa.x, pa.y+sa.y, sa.w, sa.h) - if !strokepass - glScissor(sa.x, sa.y, sa.w, sa.h) - glClearStencil(window.id) - bits = GL_STENCIL_BUFFER_BIT - if window.clear - c = window.color - glClearColor(red(c), green(c), blue(c), alpha(c)) - bits |= GL_COLOR_BUFFER_BIT - end - glClear(bits) - end - if window.stroke[1] > 0 && strokepass - s, c = window.stroke - # not the best way to draw stroke, but quite simple and should be fast - glClearColor(red(c), green(c), blue(c), alpha(c)) - glScissor(sa.x, sa.y, s, sa.h) - glClear(GL_COLOR_BUFFER_BIT) - glScissor(sa.x, sa.y, sa.w, s) - glClear(GL_COLOR_BUFFER_BIT) - glScissor(sa.x+sa.w-s, sa.y, s, sa.h) - glClear(GL_COLOR_BUFFER_BIT) - glScissor(sa.x, sa.y+sa.h-s, sa.w, s) - glClear(GL_COLOR_BUFFER_BIT) - end - for elem in window.children - setup_window(elem, strokepass, sa) - end - end - return -end - -""" -Renders a single frame of a `window` -""" -function render_frame(window) - !isopen(window) && return - fb = GLWindow.framebuffer(window) - wh = 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) - 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) - setup_window(window, true) - glDisable(GL_SCISSOR_TEST) - glViewport(0,0, wh...) - #Read all the selection queries - GLWindow.push_selectionqueries!(window) - glBindFramebuffer(GL_FRAMEBUFFER, 0) # transfer back to window - glClearColor(0,0,0,0) - glClear(GL_COLOR_BUFFER_BIT) - GLAbstraction.render(fb.postprocess[3]) # copy postprocess - return -end - -function GLAbstraction.render(x::Screen, fxaa::Bool, parent::Screen=x, context=x.area.value) - if isopen(x) && !ishidden(x) - sa = value(x.area) - sa = SimpleRectangle(context.x+sa.x, context.y+sa.y, sa.w, sa.h) # bring back to absolute values - pa = context - sa_pa = intersect(pa, sa) # intersection with parent - if ( - sa_pa != SimpleRectangle(0,0,0,0) && # if it is in the parent area - (sa_pa.w > 0 && sa_pa.h > 0) - ) # if it is in the parent area - glViewport(sa) - glStencilFunc(GL_EQUAL, x.id, 0xff) - if fxaa - render(x.renderlist_fxaa) - else - render(x.renderlist) - end - for window in x.children - render(window, fxaa, x, sa) - end - end - end - return -end diff --git a/src/screen.jl b/src/screen.jl index d32c571..2163d2a 100644 --- a/src/screen.jl +++ b/src/screen.jl @@ -1,384 +1,136 @@ +abstract type Screen end +#each screen backend should be able to do following functions. -""" -Callback which can be used to catch OpenGL errors. -""" -function openglerrorcallback( - source::GLenum, typ::GLenum, - id::GLuint, severity::GLenum, - length::GLsizei, message::Ptr{GLchar}, - userParam::Ptr{Void} - ) - errormessage = """ - ________________________________________________________________ - | - | OpenGL Error! - | source: $(GLENUM(source).name) :: type: $(GLENUM(typ).name) - | $(String(message, length)) - |________________________________________________________________ - """ - output = typ == GL_DEBUG_TYPE_ERROR ? error : info - output(errormessage) - nothing -end +include(joinpath(@__DIR__,"GLFW/screen.jl")) -global const _openglerrorcallback = cfunction( - openglerrorcallback, Void, - (GLenum, GLenum,GLuint, GLenum, GLsizei, Ptr{GLchar}, Ptr{Void}) -) - - -""" -Screen constructor cnstructing a new screen from a parant screen. -""" -function Screen( - parent::Screen; - name = gensym(parent.name), - area = map(zeroposition, parent.area), - children::Vector{Screen} = Screen[], - inputs::Dict{Symbol, Any} = copy(parent.inputs), - renderlist::Tuple = (), - hidden = parent.hidden, - clear::Bool = parent.clear, - color = RGBA{Float32}(1,1,1,1), - stroke = (0f0, color), - glcontext::AbstractContext = parent.glcontext, - cameras = Dict{Symbol, Any}(), - position = Vec3f0(2), - lookat = Vec3f0(0) - ) - screen = Screen(name, - area, parent, children, inputs, - renderlist, hidden, clear, color, stroke, - cameras, glcontext - ) - pintersect = const_lift(x->intersect(zeroposition(value(parent.area)), x), area) - relative_mousepos = map(inputs[:mouseposition]) do mpos - Point{2, Float64}(mpos[1]-value(pintersect).x, mpos[2]-value(pintersect).y) +function Base.show(io::IO, m::Screen) + println(io, "name: ", m.name) + println(io, "children: ", length(m.children)) + println(io, "callbacks:") + for (key, value) in m.callbacks + println(io, " ", key, " => ", typeof(value)) end - #checks if mouse is inside screen and not inside any children - insidescreen = droprepeats(const_lift(isinside, screen, relative_mousepos)) - merge!(screen.inputs, Dict( - :mouseinside => insidescreen, - :mouseposition => relative_mousepos, - :window_area => area - )) - push!(parent.children, screen) - screen end - -""" -On OSX retina screens, the window size is different from the -pixel size of the actual framebuffer. With this function we -can find out the scaling factor. -""" -function scaling_factor(window::Vec{2, Int}, fb::Vec{2, Int}) - (window[1] == 0 || window[2] == 0) && return Vec{2, Float64}(1.0) - Vec{2, Float64}(fb) ./ Vec{2, Float64}(window) +function isroot(s::Screen) + !isdefined(s, :parent) end -function scaling_factor(nw) - w, fb = GLFW.GetWindowSize(nw), GLFW.GetFramebufferSize(nw) - scaling_factor(Vec{2, Int}(w), Vec{2, Int}(fb)) + +function rootscreen(s::Screen) + while !isroot(s) + s = s.parent + end + s end """ -Correct OSX scaling issue and move the 0,0 coordinate to left bottom. +Check if a Screen is opened. """ -function corrected_coordinates( - window_size::Signal{Vec{2,Int}}, - framebuffer_width::Signal{Vec{2,Int}}, - mouse_position::Vec{2,Float64} - ) - s = scaling_factor(window_size.value, framebuffer_width.value) - Vec{2,Float64}(mouse_position[1], window_size.value[2] - mouse_position[2]) .* s +function Base.isopen(screen::Screen) + isopen(nativewindow(screen)) end - """ -Standard set of callback functions +mouse position is in coorditnates relative to `screen` """ -function standard_callbacks() - Function[ - window_open, - window_size, - window_position, - keyboard_buttons, - mouse_buttons, - dropped_files, - framebuffer_size, - unicode_input, - cursor_position, - scroll, - hasfocus, - entered_window, - ] +function isinside(screen::Screen, mpos) + isinside(zeroposition(screen.area), mpos[1], mpos[2]) || return false + for s in screen.children + # if inside any children, it's not inside screen + isinside(s.area, mpos[1], mpos[2]) && return false + end + true end """ -Tries to create sensible context hints! -Taken from lessons learned at: -[GLFW](http://www.glfw.org/docs/latest/window.html) +Args: `screens_mpos` -> Tuple{Vector{Screen}, Vec{2,T}} """ -function standard_context_hints(major, minor) - # this is spaar...Modern OpenGL !!!! - major < 3 && error("OpenGL major needs to be at least 3.0. Given: $major") - # core profile is only supported for OpenGL 3.2+ (and a must for OSX, so - # for the sake of homogenity, we try to default to it for everyone!) - if (major > 3 || (major == 3 && minor >= 2 )) - profile = GLFW.OPENGL_CORE_PROFILE - else - profile = GLFW.OPENGL_ANY_PROFILE +function isoutside(screens_mouseposition) + screens, mpos = screens_mouseposition + for screen in screens + isinside(screen, mpos) && return false end - [ - (GLFW.CONTEXT_VERSION_MAJOR, major), - (GLFW.CONTEXT_VERSION_MINOR, minor), - (GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE), - (GLFW.OPENGL_PROFILE, profile) - ] + true end -""" -Takes half the resolution of the primary monitor. -This should make for sensible defaults! -""" -function standard_screen_resolution() - w, h = primarymonitorresolution() - (div(w,2), div(h,2)) # half of total resolution seems like a good fit! +function Base.resize!(x::Screen, w::Integer, h::Integer) + nw = nativewindow(x) + if isroot(x) + resize!(nw, w, h) + end + area = x.area + f = scaling_factor(nw) + # There was some performance issue with round.(Int, SVector) - not sure if resolved. + wf, hf = round.(f .* (w, h)) + x.area = (x=area[:x], y=area[:y], w=Int(wf), h=Int(hf)) end +widths(s::Screen) = widths(value(s.area)) +function abs_area(s::Screen) + area = s.area + while !isroot(s) + s = s.parent + pa = s.area + area = (x=area[:x] + pa[:x], y=area[:y] + pa[:y], w=area[:w], h=area[:h]) + end + area +end """ -Standard window hints for creating a plain context without any multisampling -or extra buffers beside the color buffer +Swap the framebuffers on the Screen. """ -function standard_window_hints() - [ - (GLFW.SAMPLES, 0), - (GLFW.DEPTH_BITS, 0), - - (GLFW.ALPHA_BITS, 8), - (GLFW.RED_BITS, 8), - (GLFW.GREEN_BITS, 8), - (GLFW.BLUE_BITS, 8), - - (GLFW.STENCIL_BITS, 0), - (GLFW.AUX_BUFFERS, 0) - ] +function swapbuffers(screen::Screen) + swapbuffers(nativewindow(screen)) end - -full_screen_usage_message() = """ -Keyword arg fullscreen accepts: - Integer: The number of the Monitor to Select - Bool: if true, primary monitor gets fullscreen, false no fullscren (default) - GLFW.Monitor: Fullscreens on the passed monitor """ - -""" -Function to create a pure GLFW OpenGL window +Empties the content of the renderlist """ -function create_glcontext( - name = "GLWindow"; - resolution = standard_screen_resolution(), - debugging = false, - major = 3, - minor = 3,# this is what GLVisualize needs to offer all features - windowhints = standard_window_hints(), - contexthints = standard_context_hints(major, minor), - visible = true, - focus = false, - fullscreen = false, - monitor = nothing - ) - # we create a new context, so we need to clear the shader cache. - # TODO, cache shaders in GLAbstraction per GL context - GLFW.WindowHint(GLFW.VISIBLE, visible) - GLFW.WindowHint(GLFW.FOCUSED, focus) - GLAbstraction.empty_shader_cache!() - for ch in contexthints - GLFW.WindowHint(ch[1], ch[2]) - end - for wh in windowhints - GLFW.WindowHint(wh[1], wh[2]) - end - - @static if is_apple() - if debugging - warn("OpenGL debug message callback not available on osx") - debugging = false - end - end - - GLFW.WindowHint(GLFW.OPENGL_DEBUG_CONTEXT, Cint(debugging)) - - monitor = if monitor == nothing - GLFW.GetPrimaryMonitor() - elseif isa(monitor, Integer) - GLFW.GetMonitors()[monitor] - elseif isa(monitor, GLFW.Monitor) - monitor - else - error("Monitor needs to be nothing, int, or GLFW.Monitor. Found: $monitor") - end - - window = GLFW.CreateWindow(resolution..., String(name)) - - if fullscreen - GLFW.SetKeyCallback(window, (_1, button, _2, _3, _4) -> begin - button == GLFW.KEY_ESCAPE && GLWindow.make_windowed!(window) - end) - GLWindow.make_fullscreen!(window, monitor) - end - - GLFW.MakeContextCurrent(window) - # tell GLAbstraction that we created a new context. - # This is important for resource tracking - GLAbstraction.new_context() - - debugging && glDebugMessageCallbackARB(_openglerrorcallback, C_NULL) - window -end - -make_fullscreen!(screen::Screen, monitor::GLFW.Monitor = GLFW.GetPrimaryMonitor()) = make_fullscreen!(nativewindow(screen), monitor) -function make_fullscreen!(window::GLFW.Window, monitor::GLFW.Monitor = GLFW.GetPrimaryMonitor()) - vidmodes = GLFW.GetVideoModes(monitor)[end] - GLFW.SetWindowMonitor(window, monitor, 0, 0, vidmodes.width, vidmodes.height, GLFW.DONT_CARE) +function Base.empty!(screen::Screen) + foreach(destroy!, copy(screen.children)) # children delete themselves from screen.children return end -make_windowed!(screen::Screen) = make_windowed!(nativewindow(screen)) -function make_windowed!(window::GLFW.Window) - width, height = standard_screen_resolution() - GLFW.SetWindowMonitor(window, GLFW.Monitor(C_NULL), 0, 0, width, height, GLFW.DONT_CARE) +function destroy!(screen::Screen) + empty!(screen) # remove all children and renderobjects + # close(screen.area, false) + if isroot(screen) # close gl context (aka ultimate parent) + destroywindow!(screen) + else # delete from parent + filter!(s-> !(s===screen), screen.parent.children) # remove from parent + end + empty!(screen.callbacks) return end """ -Most basic Screen constructor, which is usually used to create a parent screen. -It creates an OpenGL context and registeres all the callbacks -from the kw_arg `callbacks`. -You can change the OpenGL version with `major` and `minor`. -Also `windowhints` and `contexthints` can be given. -You can query the standard context and window hints -with `GLWindow.standard_context_hints` and `GLWindow.standard_window_hints`. -Finally you have the kw_args color and resolution. The first sets the background -color of the window and the other the resolution of the window. +Takes a screen and registers a list of callback functions. +Returns a dict{Symbol, Signal}(name_of_callback => signal) """ -function Screen(name = "GLWindow"; - resolution = standard_screen_resolution(), - debugging = false, - major = 3, - minor = 3,# this is what GLVisualize needs to offer all features - windowhints = standard_window_hints(), - contexthints = standard_context_hints(major, minor), - callbacks = standard_callbacks(), - clear = true, - color = RGBA{Float32}(1,1,1,1), - stroke = (0f0, color), - hidden = false, - visible = true, - focus = false, - fullscreen = false, - monitor = nothing - - ) - # create glcontext - - window = create_glcontext( - name, - resolution = resolution, debugging = debugging, - major = major, minor = minor, - windowhints = windowhints, contexthints=contexthints, - visible = visible, focus = focus, - fullscreen = fullscreen, - monitor = monitor - ) - #create standard signals - signal_dict = register_callbacks(window, callbacks) - @materialize window_position, window_size, hasfocus = signal_dict - @materialize framebuffer_size, cursor_position = signal_dict - - # make sure we get newest updates from glfw and reactive! - push!(framebuffer_size, Vec(GLFW.GetFramebufferSize(window))) - - window_area = map(SimpleRectangle, - Signal(Vec(0,0)), - framebuffer_size - ) - - signal_dict[:window_area] = window_area - # seems to be necessary to set this as early as possible - fb_size = value(framebuffer_size) - glViewport(0, 0, fb_size...) - - # GLFW uses different coordinates from OpenGL, and on osx, the coordinates - # are not in pixel coordinates - # we coorect them to always be in pixel coordinates with 0,0 in left down corner - signal_dict[:mouseposition] = const_lift(corrected_coordinates, - Signal(window_size), Signal(framebuffer_size), cursor_position - ) - signal_dict[:mouse2id] = Signal(SelectionID{Int}(-1, -1)) - - GLFW.SwapInterval(0) # deactivating vsync seems to make everything quite a bit smoother - screen = Screen( - Symbol(name), window_area, nothing, - Screen[], signal_dict, - (), hidden, clear, color, stroke, - Dict{Symbol, Any}(), - GLContext(window, GLFramebuffer(framebuffer_size), visible) - ) - signal_dict[:mouseinside] = droprepeats( - const_lift(isinside, screen, signal_dict[:mouseposition]) - ) - screen +function register_callbacks(screen::Screen, callbacks::Vector{Function}) + register_callbacks(nativewindow(screen), callbacks) end +#make_fullscreen is implemented by each backend specifically +make_windowed!(screen::Screen) = make_windowed!(nativewindow(screen)) + """ -Function that creates a screenshot from `window` and saves it to `path`. -You can choose the channel of the framebuffer, which is usually: -`color`, `depth` and `objectid` +If hidden, window will stop rendering. """ -function screenshot(window; path="screenshot.png", channel=:color) - save(path, screenbuffer(window, channel), true) -end +ishidden(s::Screen) = s.hidden """ -Returns the contents of the framebuffer of `window` as a Julia Array. -You can choose the channel of the framebuffer, which is usually: -`color`, `depth` and `objectid` +Sets visibility of OpenGL window. Will still render if not visible. +Only applies to the root screen holding the opengl context. """ -function screenbuffer(window, channel = :color) - fb = framebuffer(window) - channels = fieldnames(fb)[2:end] - area = abs_area(window) - w = widths(area) - x1, x2 = max(area.x, 1), min(area.x + w[1], size(fb.color, 1)) - y1, y2 = max(area.y, 1), min(area.y + w[2], size(fb.color, 2)) - if channel == :depth - w, h = x2 - x1 + 1, y2 - y1 + 1 - data = Matrix{Float32}(w, h) - glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) - glDisable(GL_SCISSOR_TEST) - glDisable(GL_STENCIL_TEST) - glReadPixels(x1 - 1, y1 - 1, w, h, GL_DEPTH_COMPONENT, GL_FLOAT, data) - return rotl90(data) - elseif channel in channels - buff = gpu_data(getfield(fb, channel)) - img = view(buff, x1:x2, y1:y2) - if channel == :color - img = RGB{N0f8}.(img) - end - return rotl90(img) +function set_visibility!(screen::Screen, visible::Bool) + if screen.visiblie != visible + set_visibility!(nativewindow(screen), visible) + screen.visible = visible end - error("Channel $channel does not exist. Only these channels are available: $channels") end -""" -If hidden, window will stop rendering. -""" -ishidden(s::Screen) = value(s.hidden) - """ Hides a window and stops it from being rendered. """ @@ -386,8 +138,9 @@ function hide!(s::Screen) if isroot(s) set_visibility!(s, false) end - push!(s.hidden, true) + s.hidden = true end + """ Shows a window and turns rendering back on """ @@ -395,196 +148,6 @@ function show!(s::Screen) if isroot(s) set_visibility!(s, true) end - push!(s.hidden, false) + s.hidden = false end - -""" -Sets visibility of OpenGL window. Will still render if not visible. -Only applies to the root screen holding the opengl context. -""" -function set_visibility!(screen::Screen, visible::Bool) - set_visibility!(screen.glcontext, visible) - return -end -function set_visibility!(glc::AbstractContext, visible::Bool) - if glc.visible != visible - set_visibility!(glc.window, visible) - glc.visible = visible - end - return -end -function set_visibility!(screen::GLFW.Window, visible::Bool) - if visible - GLFW.ShowWindow(screen) - else !visible - GLFW.HideWindow(screen) - end - return -end - - -widths(s::Screen) = widths(value(s.area)) -framebuffer(s::Screen) = s.glcontext.framebuffer -nativewindow(s::Screen) = s.glcontext.window - -""" -Check if a Screen is opened. -""" -function Base.isopen(window::Screen) - isopen(nativewindow(window)) -end -function Base.isopen(window::GLFW.Window) - window.handle == C_NULL && return false - !GLFW.WindowShouldClose(window) -end -""" -Swap the framebuffers on the Screen. -""" -function swapbuffers(window::Screen) - swapbuffers(nativewindow(window)) -end -function swapbuffers(window::GLFW.Window) - window.handle == C_NULL && return - GLFW.SwapBuffers(window) - return -end -function Base.resize!(x::Screen, w::Integer, h::Integer) - nw = GLWindow.nativewindow(x) - if isroot(x) - resize!(nw, w, h) - end - area = value(x.area) - f = scaling_factor(nw) - # There was some performance issue with round.(Int, SVector) - not sure if resolved. - wf, hf = round.(f .* Vec(w, h)) - push!(x.area, SimpleRectangle(area.x, area.y, Int(wf), Int(hf))) -end -function Base.resize!(x::GLFW.Window, w::Integer, h::Integer) - GLFW.SetWindowSize(x, w, h) -end - -""" -Poll events on the screen which will propogate signals through react. -""" -function poll_glfw() - GLFW.PollEvents() -end - -function mouse2id(s::Screen) - s.inputs[:mouse2id] -end -export mouse2id -function mouseposition(s::Screen) - s.inputs[:mouseposition] -end -""" -Empties the content of the renderlist -""" -function Base.empty!(screen::Screen) - screen.renderlist = () # remove references and empty lists - screen.renderlist_fxaa = () # remove references and empty lists - foreach(destroy!, copy(screen.children)) # children delete themselves from screen.children - return -end - -""" -returns a copy of the renderlist -""" -function GLAbstraction.renderlist(s::Screen) - vcat(s.renderlist..., s.renderlist_fxaa...) -end -function destroy!(screen::Screen) - empty!(screen) # remove all children and renderobjects - close(screen.area, false) - empty!(screen.cameras) - if isroot(screen) # close gl context (aka ultimate parent) - nw = nativewindow(screen) - for (k, s) in screen.inputs - close(s, false) - end - if nw.handle != C_NULL - GLFW.DestroyWindow(nw) - nw.handle = C_NULL - end - else # delete from parent - filter!(s-> !(s===screen), screen.parent.children) # remove from parent - end - empty!(screen.inputs) - - return -end - -get_id(x::Integer) = x -get_id(x::RenderObject) = x.id -function delete_robj!(list, robj) - for (i, id) in enumerate(list) - if get_id(id) == robj.id - splice!(list, i) - return true, i - end - end - false, 0 -end -function Base.delete!(screen::Screen, c::Composable) - deleted = false - for elem in GLAbstraction.extract_renderable(c) - deleted &= delete!(screen, elem) - end - deleted # TODO This is not really correct... -end -function Base.delete!(screen::Screen, robj::RenderObject) - for renderlist in screen.renderlist - deleted, i = delete_robj!(renderlist, robj) - deleted && return true - end - for renderlist in screen.renderlist_fxaa - deleted, i = delete_robj!(renderlist, robj) - deleted && return true - end - false -end - -function GLAbstraction.robj_from_camera(window, camera) - cam = window.cameras[camera] - return filter(renderlist(window)) do robj - robj[:projection] == cam.projection - end -end - -function isroot(s::Screen) - !isdefined(s, :parent) -end -function rootscreen(s::Screen) - while !isroot(s) - s = s.parent - end - s -end - -function abs_area(s::Screen) - area = value(s.area) - while !isroot(s) - s = s.parent - pa = value(s.area) - area = SimpleRectangle(area.x + pa.x, area.y + pa.y, area.w, area.h) - end - area -end - -function Base.push!(screen::Screen, robj::RenderObject{Pre}) where Pre - # since fxaa is the default, if :fxaa not in uniforms --> needs fxaa - sym = Bool(get(robj.uniforms, :fxaa, true)) ? :renderlist_fxaa : :renderlist - # find renderlist specialized to current prerender function - index = findfirst(getfield(screen, sym)) do renderlist - prerendertype(eltype(renderlist)) == Pre - end - if index == 0 - # add new specialised renderlist, if none found - setfield!(screen, sym, (getfield(screen, sym)..., RenderObject{Pre}[])) - index = length(getfield(screen, sym)) - end - # only add to renderlist if not already in there - in(robj, getfield(screen, sym)[index]) || push!(getfield(screen, sym)[index], robj) - nothing -end diff --git a/src/types.jl b/src/types.jl deleted file mode 100644 index d9e2667..0000000 --- a/src/types.jl +++ /dev/null @@ -1,248 +0,0 @@ -using Base: RefValue - - -function draw_fullscreen(vao_id) - glBindVertexArray(vao_id) - glDrawArrays(GL_TRIANGLES, 0, 3) - glBindVertexArray(0) -end -struct PostprocessPrerender -end -function (sp::PostprocessPrerender)() - glDepthMask(GL_TRUE) - glDisable(GL_DEPTH_TEST) - glDisable(GL_BLEND) - glDisable(GL_STENCIL_TEST) - glStencilMask(0xff) - glDisable(GL_CULL_FACE) - nothing -end - -const PostProcessROBJ = RenderObject{PostprocessPrerender} -mutable struct GLFramebuffer - id ::NTuple{2, GLuint} - color ::Texture{RGBA{N0f8}, 2} - objectid ::Texture{Vec{2, GLushort}, 2} - depth ::GLuint - color_luma ::Texture{RGBA{N0f8}, 2} - postprocess::NTuple{3, PostProcessROBJ} -end - -Base.size(fb::GLFramebuffer) = size(fb.color) # it's guaranteed, that they all have the same size - -loadshader(name) = joinpath(dirname(@__FILE__), name) - - -rcpframe(x) = 1f0./Vec2f0(x[1], x[2]) - -""" -Creates a postprocessing render object. -This will transfer the pixels from the color texture of the Framebuffer -to the screen and while at it, it can do some postprocessing (not doing it right now): -E.g fxaa anti aliasing, color correction etc. -""" -function postprocess(color, color_luma, framebuffer_size) - shader1 = LazyShader( - loadshader("fullscreen.vert"), - loadshader("postprocess.frag") - ) - data1 = Dict{Symbol, Any}( - :color_texture => color - ) - pass1 = RenderObject(data1, shader1, PostprocessPrerender(), nothing) - pass1.postrenderfunction = () -> draw_fullscreen(pass1.vertexarray.id) - shader2 = LazyShader( - loadshader("fullscreen.vert"), - loadshader("fxaa.frag") - ) - data2 = Dict{Symbol, Any}( - :color_texture => color_luma, - :RCPFrame => map(rcpframe, framebuffer_size) - ) - pass2 = RenderObject(data2, shader2, PostprocessPrerender(), nothing) - - pass2.postrenderfunction = () -> draw_fullscreen(pass2.vertexarray.id) - - shader3 = LazyShader( - GLWindow.loadshader("fullscreen.vert"), - GLWindow.loadshader("copy.frag") - ) - - data3 = Dict{Symbol, Any}( - :color_texture => color - ) - - pass3 = RenderObject(data3, shader3, GLWindow.PostprocessPrerender(), nothing) - - pass3.postrenderfunction = () -> GLWindow.draw_fullscreen(pass3.vertexarray.id) - - - (pass1, pass2, pass3) -end - -function attach_framebuffer(t::Texture{T, 2}, attachment) where T - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, t.id, 0) -end - - - -function GLFramebuffer(fb_size) - render_framebuffer = glGenFramebuffers() - - glBindFramebuffer(GL_FRAMEBUFFER, render_framebuffer) - - buffersize = tuple(value(fb_size)...) - - color_buffer = Texture(RGBA{N0f8}, buffersize, minfilter=:nearest, x_repeat=:clamp_to_edge) - - objectid_buffer = Texture(Vec{2, GLushort}, buffersize, minfilter=:nearest, x_repeat=:clamp_to_edge) - - depth_stencil_rb = Ref{GLuint}() - glGenRenderbuffers(1, depth_stencil_rb) - glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_rb[]) - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, buffersize...) - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_stencil_rb[]) - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depth_stencil_rb[]) - - attach_framebuffer(color_buffer, GL_COLOR_ATTACHMENT0) - - attach_framebuffer(objectid_buffer, GL_COLOR_ATTACHMENT1) - - status = glCheckFramebufferStatus(GL_FRAMEBUFFER) - @assert status == GL_FRAMEBUFFER_COMPLETE - - color_luma = Texture(RGBA{N0f8}, buffersize, minfilter=:linear, x_repeat=:clamp_to_edge) - color_luma_framebuffer = glGenFramebuffers() - glBindFramebuffer(GL_FRAMEBUFFER, color_luma_framebuffer) - attach_framebuffer(color_luma, GL_COLOR_ATTACHMENT0) - @assert status == GL_FRAMEBUFFER_COMPLETE - - glBindFramebuffer(GL_FRAMEBUFFER, 0) - - p = postprocess(color_buffer, color_luma, fb_size) - - fb = GLFramebuffer( - (render_framebuffer, color_luma_framebuffer), - color_buffer, objectid_buffer, depth_stencil_rb[], - color_luma, - p - ) - fb -end - -function Base.resize!(fb::GLFramebuffer, window_size) - ws = window_size[1], window_size[2] - if ws!=size(fb) && all(x->x>0, window_size) - buffersize = tuple(window_size...) - resize_nocopy!(fb.color, buffersize) - resize_nocopy!(fb.color_luma, buffersize) - resize_nocopy!(fb.objectid, buffersize) - glBindRenderbuffer(GL_RENDERBUFFER, fb.depth) - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, buffersize...) - glBindRenderbuffer(GL_RENDERBUFFER, 0) - end - nothing -end - - -struct MonitorProperties - name::String - isprimary::Bool - position::Vec{2, Int} - physicalsize::Vec{2, Int} - videomode::GLFW.VidMode - videomode_supported::Vector{GLFW.VidMode} - dpi::Vec{2, Float64} - monitor::Monitor -end - -function MonitorProperties(monitor::Monitor) - name = GLFW.GetMonitorName(monitor) - isprimary = GLFW.GetPrimaryMonitor() == monitor - position = Vec{2, Int}(GLFW.GetMonitorPos(monitor)...) - physicalsize = Vec{2, Int}(GLFW.GetMonitorPhysicalSize(monitor)...) - videomode = GLFW.GetVideoMode(monitor) - sfactor = is_apple() ? 2.0 : 1.0 - dpi = Vec(videomode.width * 25.4, videomode.height * 25.4) * sfactor ./ Vec{2, Float64}(physicalsize) - videomode_supported = GLFW.GetVideoModes(monitor) - - MonitorProperties(name, isprimary, position, physicalsize, videomode, videomode_supported, dpi, monitor) -end - -abstract type AbstractContext end - -mutable struct GLContext <: AbstractContext - window::GLFW.Window - framebuffer::GLFramebuffer - visible::Bool - cache::Dict -end -GLContext(window, framebuffer, visible) = GLContext(window, framebuffer, visible, Dict()) - -const screen_id_counter = RefValue(0) -# start from new and hope we don't display all displays at once. -# TODO make it clearer if we reached max num, or if we just created -# a lot of small screens and display them simultanously -new_id() = (screen_id_counter[] = mod1(screen_id_counter[] + 1, 255); screen_id_counter[])[] - - -mutable struct Screen - name ::Symbol - area ::Signal{SimpleRectangle{Int}} - parent ::Screen - children ::Vector{Screen} - inputs ::Dict{Symbol, Any} - isleaf_signal ::Dict{Symbol, Bool} - renderlist_fxaa::Tuple # a tuple of specialized renderlists - renderlist ::Tuple # a tuple of specialized renderlists - visible ::Bool # if window is visible. Will still render - hidden ::Signal{Bool} # if window is hidden. Will not render - clear ::Bool - color ::RGBA{Float32} - stroke ::Tuple{Float32, RGBA{Float32}} - - cameras ::Dict{Symbol, Any} - - glcontext ::AbstractContext - id ::Int - - function Screen( - name ::Symbol, - area ::Signal{SimpleRectangle{Int}}, - parent ::Union{Screen, Void}, - children ::Vector{Screen}, - inputs ::Dict{Symbol, Any}, - renderlist ::Tuple, - hidden, - clear ::Bool, - color ::Colorant, - stroke ::Tuple, - cameras ::Dict{Symbol, Any}, - context ::AbstractContext - ) - screen = new() - if parent != nothing - screen.parent = parent - end - leaves = Dict{Symbol, Bool}() - for (k, v) in inputs - leaves[k] = isempty(v.actions) - end - screen.name = name - screen.area = area - screen.children = children - screen.inputs = inputs - screen.isleaf_signal = leaves - screen.renderlist = renderlist - screen.renderlist_fxaa = () - screen.hidden = isa(hidden, Signal) ? hidden : Signal(hidden) - screen.clear = clear - screen.color = RGBA{Float32}(color) - screen.stroke = (Float32(stroke[1]), RGBA{Float32}(stroke[2])) - screen.cameras = cameras - screen.glcontext = context - screen.id = new_id() - screen - end -end diff --git a/src/utils.jl b/src/utils.jl new file mode 100644 index 0000000..7dd850a --- /dev/null +++ b/src/utils.jl @@ -0,0 +1,39 @@ +#Came from screen.jl +#I think in general at this level, GeometryTypes is fine to be using'd. What I did remove is all the signal stuff, where it made sense to remove them, +#the rest I'm throwing in the junkyard for now. +""" +On OSX retina screens, the window size is different from the +pixel size of the actual framebuffer. With this function we +can find out the scaling factor. +""" +function scaling_factor(window::NTuple{2, Int}, fb::NTuple{2, Int}) + (window[1] == 0 || window[2] == 0) && return (1.0, 1.0) + fb ./ window +end + +""" +Correct OSX scaling issue and move the 0,0 coordinate to left bottom. +""" +function corrected_coordinates( + window_size::NTuple{2,Int}, + framebuffer_width::NTuple{2,Int}, + mouse_position::NTuple{2,Float64} + ) + s = scaling_factor(window_size, framebuffer_width) + (mouse_position[1], window_size.value[2] - mouse_position[2]) .* s +end + +""" +Sleep is pretty imprecise. E.g. anything under `0.001s` is not guaranteed to wake +up before `0.001s`. So this timer is pessimistic in the way, that it will never +sleep more than `time`. +""" +@inline function sleep_pessimistic(sleep_time) + st = convert(Float64,sleep_time) - 0.002 + start_time = time() + while (time() - start_time) < st + sleep(0.001) # sleep for the minimal amount of time + end +end + +zeroposition(area::NamedTuple) = (x=0, y=0, w=area[:w], h=area[:h]) \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl old mode 100755 new mode 100644