Skip to content

Commit

Permalink
Merge branch 'master' into ff/spaces
Browse files Browse the repository at this point in the history
  • Loading branch information
ffreyer committed Jul 13, 2023
2 parents 4d75594 + bd315b4 commit 0c950ad
Show file tree
Hide file tree
Showing 20 changed files with 751 additions and 564 deletions.
43 changes: 33 additions & 10 deletions CairoMakie/src/infrastructure.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function cairo_draw(screen::Screen, scene::Scene)
Cairo.save(screen.context)
draw_background(screen, scene)

allplots = get_all_plots(scene)
allplots = Makie.collect_atomic_plots(scene; is_atomic_plot = is_cairomakie_atomic_plot)
zvals = Makie.zvalue2d.(allplots)
permute!(allplots, sortperm(zvals))

Expand All @@ -23,10 +23,12 @@ function cairo_draw(screen::Screen, scene::Scene)

Cairo.save(screen.context)
for p in allplots
to_value(get(p, :visible, true)) || continue
check_parent_plots(p) do plot
to_value(get(plot, :visible, true))
end || continue
# only prepare for scene when it changes
# this should reduce the number of unnecessary clipping masks etc.
pparent = p.parent::Scene
pparent = Makie.parent_scene(p)
pparent.visible[] || continue
if pparent != last_scene
Cairo.restore(screen.context)
Expand All @@ -36,8 +38,8 @@ function cairo_draw(screen::Screen, scene::Scene)
end
Cairo.save(screen.context)

# When a plot is too large to save with a reasonable file size on a vector backend,
# the user can choose to rasterize it when plotting to vector backends, by using the
# When a plot is too large to save with a reasonable file size on a vector backend,
# the user can choose to rasterize it when plotting to vector backends, by using the
# `rasterize` keyword argument. This can be set to a Bool or an Int which describes
# the density of rasterization (in terms of a direct scaling factor.)
# TODO: In future, this can also be set to a Tuple{Module, Int} which describes
Expand All @@ -54,12 +56,33 @@ function cairo_draw(screen::Screen, scene::Scene)
return
end

function get_all_plots(scene, plots = AbstractPlot[])
append!(plots, scene.plots)
for c in scene.children
get_all_plots(c, plots)
"""
is_cairomakie_atomic_plot(plot::Combined)::Bool
Returns whether the plot is considered atomic for the CairoMakie backend.
This is overridden for `Poly`, `Band`, and `Tricontourf` so we can apply
CairoMakie can treat them as atomic plots and render them directly.
Plots with children are by default recursed into. This can be overridden
by defining specific dispatches for `is_cairomakie_atomic_plot` for a given plot type.
"""
is_cairomakie_atomic_plot(plot::Combined) = isempty(plot.plots) || to_value(get(plot, :rasterize, false)) != false

"""
check_parent_plots(f, plot::Combined)::Bool
Returns whether the plot's parent tree satisfies the predicate `f`.
`f` must return a `Bool` and take a plot as its only argument.
"""
function check_parent_plots(f, plot::Combined)
if f(plot)
check_parent_plots(f, parent(plot))
else
return false
end
plots
end

function check_parent_plots(f, scene::Scene)
return true
end

function prepare_for_scene(screen::Screen, scene::Scene)
Expand Down
16 changes: 16 additions & 0 deletions CairoMakie/src/overrides.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ function draw_plot(scene::Scene, screen::Screen, @nospecialize(poly::Poly))
draw_poly(scene, screen, poly, to_value.(poly.input_args)...)
end

# Override `is_cairomakie_atomic_plot` to allow `poly` to remain a unit,
# instead of auto-decomposing in lines and mesh.
is_cairomakie_atomic_plot(plot::Poly) = true

"""
Fallback method for args without special treatment.
"""
Expand Down Expand Up @@ -177,6 +181,12 @@ function draw_plot(scene::Scene, screen::Screen,
nothing
end

# Override `is_cairomakie_atomic_plot` to allow this dispatch of `band` to remain a unit,
# instead of auto-decomposing in lines and mesh.
function is_cairomakie_atomic_plot(plot::Band{<:Tuple{<:AbstractVector{<:Point2},<:AbstractVector{<:Point2}}})
return true
end

#################################################################################
# Tricontourf #
# Tricontourf creates many disjoint polygons that are adjacent and form contour #
Expand Down Expand Up @@ -207,3 +217,9 @@ function draw_plot(scene::Scene, screen::Screen, tric::Tricontourf)

return
end

# Override `is_cairomakie_atomic_plot` to allow `Tricontourf` to remain a unit,
# instead of auto-decomposing in lines and mesh.
function is_cairomakie_atomic_plot(plot::Tricontourf)
return true
end
23 changes: 18 additions & 5 deletions GLMakie/assets/shader/lines.geom
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,21 @@ vec3 screen_space(vec4 vertex)
// Manual uv calculation
// - position in screen space (double resolution as generally used)
// - uv with uv.u normalized (0..1), uv.v unnormalized (0..pattern_length)
void emit_vertex(vec3 position, vec2 uv, int index)
void emit_vertex(vec3 position, vec2 uv, int index, float thickness)
{
f_uv = uv;
f_color = g_color[index];
gl_Position = vec4((position.xy / resolution), position.z, 1.0);
f_id = g_id[index];
// linewidth scaling may shrink the effective linewidth
f_thickness = abs(uv.y) - AA_THICKNESS;
f_thickness = thickness;
EmitVertex();
}
// default for miter joins
void emit_vertex(vec3 position, vec2 uv, int index)
{
emit_vertex(position, uv, index, g_thickness[index]);
}

// For center point
void emit_vertex(vec3 position, vec2 uv)
Expand All @@ -72,15 +77,20 @@ void emit_vertex(vec3 position, vec2 uv)
}

// Debug
void emit_vertex(vec3 position, vec2 uv, int index, vec4 color)
void emit_vertex(vec3 position, vec2 uv, int index, vec4 color, float thickness)
{
f_uv = uv;
f_color = color;
gl_Position = vec4((position.xy / resolution), position.z, 1.0);
f_id = g_id[index];
f_thickness = abs(uv.y) - AA_THICKNESS;
f_thickness = thickness;
EmitVertex();
}
// default for miter joins
void emit_vertex(vec3 position, vec2 uv , int index, vec4 color)
{
emit_vertex(position, uv , index, color, g_thickness[index]);
}
void emit_vertex(vec3 position, vec2 uv, vec4 color)
{
f_uv = uv;
Expand All @@ -98,8 +108,11 @@ void emit_vertex(vec3 position, vec2 offset, vec2 line_dir, vec2 uv, int index)
emit_vertex(
position + vec3(offset, 0),
vec2(uv.x + px2uv * dot(line_dir, offset), uv.y),
index
index,
abs(uv.y) - AA_THICKNESS
);
// `abs(uv.y) - AA_THICKNESS` corrects for enlarged AA padding between
// segments of different linewidth, see #2953
}

void emit_vertex(vec3 position, vec2 offset, vec2 line_dir, vec2 uv)
Expand Down
6 changes: 3 additions & 3 deletions GLMakie/src/screen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ mutable struct ScreenConfig
end
end

const LAST_INLINE = Ref{Union{Makie.Automatic, Bool}}(Makie.automatic)
const LAST_INLINE = Ref{Union{Makie.Automatic, Bool}}(false)

"""
GLMakie.activate!(; screen_config...)
Expand Down Expand Up @@ -518,7 +518,7 @@ end
function Base.delete!(screen::Screen, scene::Scene, plot::AbstractPlot)
if !isempty(plot.plots)
# this plot consists of children, so we flatten it and delete the children instead
for cplot in Makie.flatten_plots(plot)
for cplot in Makie.collect_atomic_plots(plot)
delete!(screen, scene, cplot)
end
else
Expand Down Expand Up @@ -919,7 +919,7 @@ function renderloop(screen)
end

function plot2robjs(screen::Screen, plot)
plots = Makie.flatten_plots(plot)
plots = Makie.collect_atomic_plots(plot)
return map(x-> screen.cache[objectid(x)], plots)
end

Expand Down
7 changes: 6 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@

## master

- Deprecated `flatten_plots` in favor of `collect_atomic_plots`. Using the new `collect_atomic_plots` fixed a bug in CairoMakie where the z-level of plots within recipes was not respected. [#2793](https://github.com/MakieOrg/Makie.jl/pull/2793)
- Fixed incorrect line depth in GLMakie [#2843](https://github.com/MakieOrg/Makie.jl/pull/2843)
- Fixed incorrect line alpha in dense lines in GLMakie [#2843](https://github.com/MakieOrg/Makie.jl/pull/2843)
- Fixed DataInspector interaction with transformations [#3002](https://github.com/MakieOrg/Makie.jl/pull/3002)
- Added option `WGLMakie.activate!(resize_to_body=true)`, to make plots resize to the VSCode plotpane. Resizes to the HTML body element, so may work outside VSCode [#3044](https://github.com/MakieOrg/Makie.jl/pull/3044), [#3042](https://github.com/MakieOrg/Makie.jl/pull/3042).
- Fixed DataInspector interaction with transformations [#3002](https://github.com/MakieOrg/Makie.jl/pull/3002).
- Fix incomplete stroke with some Bezier markers in CairoMakie and blurry strokes in GLMakie [#2961](https://github.com/MakieOrg/Makie.jl/pull/2961)
- Added the ability to use custom triangulations from DelaunayTriangulation.jl [#2896](https://github.com/MakieOrg/Makie.jl/pull/2896).
- Adjusted scaling of scatter/text stroke, glow and anti-aliasing width under non-uniform 2D scaling (Vec2f markersize/fontsize) in GLMakie [#2950](https://github.com/MakieOrg/Makie.jl/pull/2950).
- Scaled `errorbar` whiskers and `bracket` correctly with transformations [#3012](https://github.com/MakieOrg/Makie.jl/pull/3012).
- Updated `bracket` when the screen is resized or transformations change [#3012](https://github.com/MakieOrg/Makie.jl/pull/3012).

- Added auto-resizing functionality to WGLMakie plot figures [#3042](https://github.com/MakieOrg/Makie.jl/pull/3042)

## v0.19.6

Expand Down
25 changes: 25 additions & 0 deletions ReferenceTests/src/tests/examples2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1019,3 +1019,28 @@ end
end
f
end

@reference_test "Z-translation within a recipe" begin
# This is testing whether backends respect the
# z-level of plots within recipes in 2d.
# Ideally, the output of this test
# would be a blue line with red scatter markers.
# However, if a backend does not correctly pick up on translations,
# then this will be drawn in the drawing order, and blue
# will completely obscure red.

# It seems like we can't define recipes in `@reference_test` yet,
# so we'll have to fake a recipe's structure.

fig = Figure(resolution = (600, 600))
# Create a recipe plot
ax, plot_top = heatmap(fig[1, 1], randn(10, 10))
# Plot some recipes at the level below the contour
scatterlineplot_1 = scatterlines!(plot_top, 1:10, 1:10; linewidth = 20, markersize = 20, color = :red)
scatterlineplot_2 = scatterlines!(plot_top, 1:10, 1:10; linewidth = 20, markersize = 30, color = :blue)
# Translate the lowest level plots (scatters)
translate!(scatterlineplot_1.plots[2], 0, 0, 1)
translate!(scatterlineplot_2.plots[2], 0, 0, -1)
# Display
fig
end
12 changes: 7 additions & 5 deletions WGLMakie/src/Camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,23 @@ export function attach_3d_camera(canvas, makie_camera, cam3d, scene) {
camera.up = new THREE.Vector3(...cam3d.upvector);
camera.position.set(...cam3d.eyeposition);
camera.lookAt(center);

function update() {
camera.updateProjectionMatrix();
camera.updateWorldMatrix();
const view = camera.matrixWorldInverse;
const projection = camera.projectionMatrix;
const [width, height] = makie_camera.resolution.value;
const [width, height] = cam3d.resolution.value;
const [x, y, z] = camera.position;
camera.aspect = width / height;
camera.updateProjectionMatrix();
camera.updateWorldMatrix();

makie_camera.update_matrices(
view.elements,
projection.elements,
[width, height],
[x, y, z]
);
);
}
cam3d.resolution.on(update);

function addMouseHandler(domObject, drag, zoomIn, zoomOut) {
let startDragX = null;
Expand Down
5 changes: 3 additions & 2 deletions WGLMakie/src/display.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const WEB_MIMES = (
"""
struct ScreenConfig
framerate::Float64 # =30.0
resize_to_body::Bool # false
end

"""
Expand Down Expand Up @@ -205,7 +206,7 @@ function session2image(session::Session, scene::Scene)
to_data = js"""function (){
return $(scene).then(scene => {
const {renderer} = scene.screen
WGLMakie.render_scene(scene)
WGL.render_scene(scene)
const img = renderer.domElement.toDataURL()
return img
})
Expand Down Expand Up @@ -342,7 +343,7 @@ const DISABLE_JS_FINALZING = Base.RefValue(false)
const DELETE_QUEUE = LockfreeQueue{Tuple{Screen,String,Vector{String}}}(delete_plot!)

function Base.delete!(screen::Screen, scene::Scene, plot::Combined)
atomics = Makie.flatten_plots(plot) # delete all atomics
atomics = Makie.collect_atomic_plots(plot) # delete all atomics
# only queue atomics to actually delete on js
if !DISABLE_JS_FINALZING[]
push!(DELETE_QUEUE, (screen, js_uuid(scene), js_uuid.(atomics)))
Expand Down
3 changes: 3 additions & 0 deletions WGLMakie/src/events.jl
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ function connect_scene_events!(scene::Scene, comm::Observable)
e.keyboardbutton[] = KeyEvent(code_to_keyboard(keyup), Keyboard.release)
end
end
@handle msg.resize begin
resize!(scene, tuple(resize...))
end
catch err
@warn "Error in window event callback" exception=(err, Base.catch_backtrace())
end
Expand Down
8 changes: 4 additions & 4 deletions WGLMakie/src/picking.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function pick_native(screen::Screen, rect::Rect2i)
if isempty(matrix)
return empty
else
all_children = Makie.flatten_plots(scene)
all_children = Makie.collect_atomic_plots(scene)
lookup = Dict(Pair.(js_uuid.(all_children), all_children))
return map(matrix) do (uuid, index)
!haskey(lookup, uuid) && return (nothing, 0)
Expand All @@ -27,7 +27,7 @@ function pick_native(screen::Screen, rect::Rect2i)
end

function plot_lookup(scene::Scene)
all_plots = Makie.flatten_plots(scene)
all_plots = Makie.collect_atomic_plots(scene)
return Dict(Pair.(js_uuid.(all_plots), all_plots))
end

Expand Down Expand Up @@ -93,7 +93,7 @@ App() do session
}
\"\"\"
tooltip = WGLMakie.ToolTip(f, on_click_callback; plots=pl)
tooltip = WGL.ToolTip(f, on_click_callback; plots=pl)
return DOM.div(f, tooltip)
end
```
Expand All @@ -107,7 +107,7 @@ struct ToolTip
if isnothing(plots)
plots = scene.plots
end
all_plots = WGLMakie.js_uuid.(filter!(x-> x.inspectable[], Makie.flatten_plots(plots)))
all_plots = js_uuid.(filter!(x-> x.inspectable[], Makie.collect_atomic_plots(plots)))
new(scene, callback, all_plots)
end
end
Expand Down
4 changes: 3 additions & 1 deletion WGLMakie/src/serialization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,9 @@ function serialize_scene(scene::Scene)

cam3d_state = if cam_controls isa Camera3D
fields = (:lookat, :upvector, :eyeposition, :fov, :near, :far)
Dict((f => serialize_three(getfield(cam_controls, f)[]) for f in fields))
dict = Dict((f => serialize_three(getfield(cam_controls, f)[]) for f in fields))
dict[:resolution] = lift(res -> Int32[res...], scene.camera.resolution)
dict
else
nothing
end
Expand Down
12 changes: 5 additions & 7 deletions WGLMakie/src/three_plot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ js_uuid(object) = string(objectid(object))
function all_plots_scenes(scene::Scene; scene_uuids=String[], plot_uuids=String[])
push!(scene_uuids, js_uuid(scene))
for plot in scene.plots
append!(plot_uuids, (js_uuid(p) for p in Makie.flatten_plots(plot)))
append!(plot_uuids, (js_uuid(p) for p in Makie.collect_atomic_plots(plot)))
end
for child in scene.children
all_plots_scenes(child, plot_uuids=plot_uuids, scene_uuids=scene_uuids)
Expand All @@ -15,7 +15,7 @@ function all_plots_scenes(scene::Scene; scene_uuids=String[], plot_uuids=String[
end

function JSServe.print_js_code(io::IO, plot::AbstractPlot, context::JSServe.JSSourceContext)
uuids = js_uuid.(Makie.flatten_plots(plot))
uuids = js_uuid.(Makie.collect_atomic_plots(plot))
# This is a bit more complicated then it has to be, since evaljs / on_document_load
# isn't guaranteed to run after plot initialization in an App... So, if we don't find any plots,
# we have to check again after inserting new plots
Expand Down Expand Up @@ -45,17 +45,15 @@ function three_display(session::Session, scene::Scene; screen_config...)
window_open = scene.events.window_open
width, height = size(scene)
canvas_width = lift(x -> [round.(Int, widths(x))...], pixelarea(scene))
canvas = DOM.um("canvas"; tabindex="0")
wrapper = DOM.div(canvas)
canvas = DOM.m("canvas"; tabindex="0", style="display: block")
wrapper = DOM.div(canvas; style="width: 100%; height: 100%")
comm = Observable(Dict{String,Any}())
done_init = Observable(false)
# Keep texture atlas in parent session, so we don't need to send it over and over again
ta = JSServe.Retain(TEXTURE_ATLAS)
evaljs(session, js"""
$(WGL).then(WGL => {
// well.... not nice, but can't deal with the `Promise` in all the other functions
window.WGLMakie = WGL
WGL.create_scene($wrapper, $canvas, $canvas_width, $scene_serialized, $comm, $width, $height, $(config.framerate), $(ta))
WGL.create_scene($wrapper, $canvas, $canvas_width, $scene_serialized, $comm, $width, $height, $(ta), $(config.framerate), $(config.resize_to_body))
$(done_init).notify(true)
})
""")
Expand Down
Loading

0 comments on commit 0c950ad

Please sign in to comment.