diff --git a/CHANGELOG.md b/CHANGELOG.md index b72f75f4f0c..400f0204c24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Fixed bugs with format strings and add new features by switching to Format.jl [#3633](https://github.com/MakieOrg/Makie.jl/pull/3633). - Fixed an issue where CairoMakie would unnecessarily rasterize polygons [#3605](https://github.com/MakieOrg/Makie.jl/pull/3605). - Added `PointBased` conversion trait to `scatterlines` recipe [#3603](https://github.com/MakieOrg/Makie.jl/pull/3603). +- Fixed a bug with line/text/scatter resolutions getting disconnected by `empty!()` in GLMakie and re-enabled camera caching. [#3640](https://github.com/MakieOrg/Makie.jl/pull/3640) - Multiple small fixes for `map_latest`, `WGLMakie` picking and `PlotSpec` [#3637](https://github.com/MakieOrg/Makie.jl/pull/3637). - Fixed PolarAxis `rticks` being incompatible with rich text. [#3615](https://github.com/MakieOrg/Makie.jl/pull/3615) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index 704e456b927..3d109cefe42 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -142,12 +142,21 @@ function connect_camera!(plot, gl_attributes, cam, space = gl_attributes[:space] # Overwrite these, user defined attributes shouldn't use those! gl_attributes[key] = lift(identity, plot, getfield(cam, key)) end + get!(gl_attributes, :view) do - # get!(cam.calculated_values, Symbol("view_$(space[])")) do - return lift(plot, cam.view, space) do view, space - return is_data_space(space) ? view : Mat4f(I) - end - # end + return lift(cam.view, space) do _, space + return Makie.get_cached_matrix(cam, :view, space) + end + end + get!(gl_attributes, :projection) do + return lift(cam.projection, cam.pixel_space, space) do _, _, space + return Makie.get_cached_matrix(cam, :projection, space) + end + end + get!(gl_attributes, :projectionview) do + return lift(cam.projectionview, cam.pixel_space, space) do _, _, space + return Makie.get_cached_matrix(cam, :projectionview, space) + end end # for lighting @@ -165,25 +174,17 @@ function connect_camera!(plot, gl_attributes, cam, space = gl_attributes[:space] return transpose(inv(v[i, i] * m[i, i])) end end - get!(gl_attributes, :projection) do - # return get!(cam.calculated_values, Symbol("projection_$(space[])")) do - return lift(plot, cam.projection, cam.pixel_space, space) do _, _, space - return Makie.space_to_clip(cam, space, false) - end - # end - end - get!(gl_attributes, :projectionview) do - # get!(cam.calculated_values, Symbol("projectionview_$(space[])")) do - return lift(plot, cam.projectionview, cam.pixel_space, space) do _, _, space - Makie.space_to_clip(cam, space, true) - end - # end - end + # resolution in real hardware pixels, not scaled pixels/units get!(gl_attributes, :resolution) do - get!(cam.calculated_values, :resolution) do - return lift(*, plot, gl_attributes[:px_per_unit], cam.resolution) - end + # Note: + # robj cleanup deletes all uniforms so to avoid deleting the cached + # resolution we need to create a copy here. + # TODO closing the screen should delete the cached entry as px_per_unit + # could be different in the next screen + return lift(identity, get!(cam.calculated_values, :px_resolution) do + return lift(*, gl_attributes[:px_per_unit], cam.resolution) + end) end delete!(gl_attributes, :space) diff --git a/GLMakie/test/unit_tests.jl b/GLMakie/test/unit_tests.jl index 409247bc075..52c184eb747 100644 --- a/GLMakie/test/unit_tests.jl +++ b/GLMakie/test/unit_tests.jl @@ -443,3 +443,25 @@ end im[3][] = zeros(RGBf, 25, 15) # larger size GLMakie.closeall() end + +@testset "Camera caching" begin + f=Figure(size=(200,200)) + screen = display(f, visible = false) + ax=Axis(f[1,1]) + lines!(ax,sin.(0.0:0.1:2pi)) + text!(ax,10.0,0.0,text="sine wave") + expected_keys = [ + :projection_data, :view_data, :projectionview_pixel, :projectionview_data, + :px_resolution, :projection_pixel, :view_pixel + ] + for key in expected_keys + @test haskey(ax.scene.camera.calculated_values, key) + @test !isempty(ax.scene.camera.calculated_values[key].inputs) + end + empty!(ax) + for key in expected_keys + @test haskey(ax.scene.camera.calculated_values, key) + @test !isempty(ax.scene.camera.calculated_values[key].inputs) + end + GLMakie.closeall() +end \ No newline at end of file diff --git a/src/camera/camera.jl b/src/camera/camera.jl index 2d75f3dc9ca..1188d8d6e01 100644 --- a/src/camera/camera.jl +++ b/src/camera/camera.jl @@ -123,3 +123,30 @@ function is_mouseinside(scene::Scene) # is_mouseinside(child) && return false # end end + +function get_cached_obs(cam::Camera, name::Symbol, space::Symbol) + fullname = Symbol("$(name)_$(space)") + obs = get!(cam.calculated_values, fullname) do + # These run at max priority so they update before default priority + # listeners to projectionview etc are called. + if name == :view + return lift(cam.view, priority = typemax(Int)) do view + return is_data_space(space) ? view : Mat4f(I) + end + elseif name == :projection + return lift(cam.projection, cam.pixel_space, priority = typemax(Int)) do _, _ + return Makie.space_to_clip(cam, space, false) + end + elseif name == :projectionview + return lift(cam.projectionview, cam.pixel_space, priority = typemax(Int)) do _, _ + return Makie.space_to_clip(cam, space, true) + end + else + error("Cannot create a cached Observable for unrecognized camera matrix :$(name).") + end + end + return obs +end +@inline function get_cached_matrix(cam::Camera, name::Symbol, space::Symbol) + return get_cached_obs(cam, name, space)[] +end \ No newline at end of file