diff --git a/.github/workflows/Docs.yml b/.github/workflows/Docs.yml index 6323a40ab13..7a8b1e62a65 100644 --- a/.github/workflows/Docs.yml +++ b/.github/workflows/Docs.yml @@ -3,13 +3,13 @@ on: pull_request: branches: - master - - breaking-0.21 + - breaking-0.22 push: tags: - '*' branches: - master - - breaking-0.21 + workflow_dispatch: concurrency: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 518c92598ee..c8a692178af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ on: - '*.md' branches: - master + - breaking-0.22 push: tags: - '*' @@ -46,6 +47,9 @@ jobs: pkg"registry up" Pkg.update() pkg"dev . ./MakieCore" + pkg"add GeometryBasics#master" + pkg"add MeshIO#ff/GeometryBasics_refactor" + pkg"add ShaderAbstractions#ff/GeometryBasics_refactor" Pkg.test("Makie"; coverage=true) - uses: julia-actions/julia-processcoverage@v1 diff --git a/.github/workflows/compilation-benchmark.yaml b/.github/workflows/compilation-benchmark.yaml index 17cb146fed4..15e2313279b 100644 --- a/.github/workflows/compilation-benchmark.yaml +++ b/.github/workflows/compilation-benchmark.yaml @@ -6,6 +6,7 @@ on: - '*.md' branches: - master + - breaking-0.22 concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} diff --git a/.github/workflows/reference_tests.yml b/.github/workflows/reference_tests.yml index 69496a3ae67..6f0783899b4 100644 --- a/.github/workflows/reference_tests.yml +++ b/.github/workflows/reference_tests.yml @@ -6,6 +6,7 @@ on: - '*.md' branches: - master + - breaking-0.22 push: tags: - '*' @@ -45,6 +46,9 @@ jobs: # dev mono repo versions pkg"registry up" Pkg.update() + pkg"add MeshIO#ff/GeometryBasics_refactor" + pkg"add GeometryBasics#master" + pkg"add ShaderAbstractions#ff/GeometryBasics_refactor" pkg"dev . ./MakieCore ./CairoMakie ./ReferenceTests" - name: Run the tests continue-on-error: true @@ -95,6 +99,9 @@ jobs: # dev mono repo versions pkg"registry up" Pkg.update() + pkg"add MeshIO#ff/GeometryBasics_refactor" + pkg"add GeometryBasics#master" + pkg"add ShaderAbstractions#ff/GeometryBasics_refactor" pkg"dev . ./MakieCore ./GLMakie ./ReferenceTests" - name: Run the tests id: referencetests @@ -145,6 +152,9 @@ jobs: # dev mono repo versions pkg"registry up" Pkg.update() + pkg"add MeshIO#ff/GeometryBasics_refactor" + pkg"add GeometryBasics#master" + pkg"add ShaderAbstractions#ff/GeometryBasics_refactor" pkg"dev . ./MakieCore ./WGLMakie ./ReferenceTests" - name: Run the tests continue-on-error: true diff --git a/.github/workflows/relocatability.yml b/.github/workflows/relocatability.yml index d3e62f5c33f..9cf62a6c58b 100644 --- a/.github/workflows/relocatability.yml +++ b/.github/workflows/relocatability.yml @@ -6,6 +6,7 @@ on: - '*.md' branches: - master + - breaking-0.22 push: tags: - '*' diff --git a/.github/workflows/rprmakie.yaml b/.github/workflows/rprmakie.yaml index 73d37684e1d..3a8b052f16a 100644 --- a/.github/workflows/rprmakie.yaml +++ b/.github/workflows/rprmakie.yaml @@ -6,6 +6,7 @@ on: - '*.md' branches: - master + - breaking-0.22 push: tags: - '*' @@ -43,6 +44,9 @@ jobs: using Pkg; pkg"registry up" Pkg.update() + pkg"add GeometryBasics#master" + pkg"add MeshIO#ff/GeometryBasics_refactor" + pkg"add ShaderAbstractions#ff/GeometryBasics_refactor" # dev mono repo versions pkg"dev . ./MakieCore ./RPRMakie ./ReferenceTests" - name: Run the tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 2045a7854b5..8c1911b112d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ if the width is exceeded [#4293](https://github.com/MakieOrg/Makie.jl/pull/4293) - Changed image, heatmap and surface picking indices to correctly index the relevant matrix arguments. [#4459](https://github.com/MakieOrg/Makie.jl/pull/4459) - Improved performance of `record` by avoiding unnecessary copying in common cases [#4475](https://github.com/MakieOrg/Makie.jl/pull/4475). +- Updated to GeoemtryBasic 0.5 [#4319](https://github.com/MakieOrg/Makie.jl/pull/4319) - Fix usage of `AggMean()` and other aggregations operating on 3d data for `datashader` [#4346](https://github.com/MakieOrg/Makie.jl/pull/4346). - Use polys for axis3 [#4463](https://github.com/MakieOrg/Makie.jl/pull/4463). - Changed default for `circular_rotation` in Camera3D to false, so that the camera doesn't change rotation direction anymore [4492](https://github.com/MakieOrg/Makie.jl/pull/4492) diff --git a/CairoMakie/Project.toml b/CairoMakie/Project.toml index e3dbf0c22ce..9939d8ea035 100644 --- a/CairoMakie/Project.toml +++ b/CairoMakie/Project.toml @@ -1,7 +1,7 @@ name = "CairoMakie" uuid = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" author = ["Simon Danisch "] -version = "0.12.14" +version = "0.13.0" [deps] CRC32c = "8bf52ea8-c179-5cab-976a-9e18b702a9bc" @@ -24,7 +24,7 @@ FileIO = "1.1" FreeType = "3, 4.0" GeometryBasics = "0.4.11" LinearAlgebra = "1.0, 1.6" -Makie = "=0.21.14" +Makie = "=0.22.0" PrecompileTools = "1.0" julia = "1.3" diff --git a/CairoMakie/src/display.jl b/CairoMakie/src/display.jl index 65a2671b37c..9e7f9f6e8d2 100644 --- a/CairoMakie/src/display.jl +++ b/CairoMakie/src/display.jl @@ -80,7 +80,7 @@ function Makie.backend_show(screen::Screen{SVG}, io::IO, ::MIME"image/svg+xml", # xlink:href="someid" (but not xlink:href="data:someothercontent" which is how image data is attached) # url(#someid) svg = replace(svg, r"((?:(?:id|xlink:href)=\"(?!data:)[^\"]+)|url\(#[^)]+)" => SubstitutionString("\\1-$salt")) - + print(io, svg) return screen end diff --git a/CairoMakie/src/overrides.jl b/CairoMakie/src/overrides.jl index 1788064c0f0..6b7e0d6ef2e 100644 --- a/CairoMakie/src/overrides.jl +++ b/CairoMakie/src/overrides.jl @@ -10,7 +10,7 @@ function draw_plot(scene::Scene, screen::Screen, poly::Poly) # dispatch on input arguments to poly to use smarter drawing methods than # meshes if possible. # however, since recipes exist, we can't explicitly handle all cases here - # so, we should also take a look at converted + # so, we should also take a look at converted # First, we check whether a `draw_poly` method exists for the input arguments # before conversion: return if Base.hasmethod(draw_poly, Tuple{Scene, Screen, typeof(poly), typeof.(to_value.(poly.args))...}) @@ -85,10 +85,14 @@ draw_poly(scene::Scene, screen::Screen, poly, rect::Rect2) = draw_poly(scene, sc draw_poly(scene::Scene, screen::Screen, poly, bezierpath::BezierPath) = draw_poly(scene, screen, poly, [bezierpath]) function draw_poly(scene::Scene, screen::Screen, poly, shapes::Vector{<:Union{Rect2, BezierPath}}) - model = poly.model[] - space = to_value(get(poly, :space, :data)) - clipped_shapes = clip_shape.(Ref(poly.clip_planes[]), shapes, space, Ref(model)) - projected_shapes = project_shape.(Ref(poly), space, clipped_shapes, Ref(model)) + model = poly.model[]::Mat4d + space = to_value(get(poly, :space, :data))::Symbol + planes = poly.clip_planes[]::Vector{Plane3f} + + projected_shapes = map(shapes) do shape + clipped = clip_shape(planes, shape, space, model) + return project_shape(poly, space, clipped, model) + end color = to_cairo_color(poly.color[], poly) @@ -188,7 +192,7 @@ end function draw_poly(scene::Scene, screen::Screen, poly, polygons::AbstractArray{<: MultiPolygon}) model = poly.model[] space = to_value(get(poly, :space, :data)) - projected_polys = map(polygons) do polygon + projected_polys = map(polygons) do polygon project_multipolygon(poly, space, polygon, poly.clip_planes[], model) end diff --git a/CairoMakie/src/precompiles.jl b/CairoMakie/src/precompiles.jl index a654e938544..5f06373c6e9 100644 --- a/CairoMakie/src/precompiles.jl +++ b/CairoMakie/src/precompiles.jl @@ -15,6 +15,7 @@ let include(shared_precompile) end end +precompile(openurl, (String,)) precompile(draw_atomic_scatter, (Scene, Cairo.CairoContext, Tuple{typeof(identity),typeof(identity)}, Vector{ColorTypes.RGBA{Float32}}, Vec{2,Float32}, ColorTypes.RGBA{Float32}, Float32, BezierPath, Vec{2,Float32}, Quaternionf, diff --git a/CairoMakie/src/primitives.jl b/CairoMakie/src/primitives.jl index 795359670ca..c5c491665d4 100644 --- a/CairoMakie/src/primitives.jl +++ b/CairoMakie/src/primitives.jl @@ -9,22 +9,6 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio isempty(positions) && return - # workaround for a LineSegments object created from a GLNormalMesh - # the input argument is a view of points using faces, which results in - # a vector of tuples of two points. we convert those to a list of points - # so they don't trip up the rest of the pipeline - # TODO this shouldn't be necessary anymore! - if positions isa SubArray{<:Point3, 1, P, <:Tuple{Array{<:AbstractFace}}} where P - positions = let - pos = Point3f[] - for tup in positions - push!(pos, tup[1]) - push!(pos, tup[2]) - end - pos - end - end - # color is now a color or an array of colors # if it's an array of colors, each segment must be stroked separately color = to_color(primitive.calculated_colors[]) @@ -912,7 +896,7 @@ function draw_mesh2D(scene, screen, @nospecialize(plot::Makie.Mesh), @nospeciali space = to_value(get(plot, :space, :data))::Symbol transform_func = Makie.transform_func(plot) model = plot.model[]::Mat4d - vs = project_position(scene, transform_func, space, GeometryBasics.metafree(GeometryBasics.coordinates(mesh)), model)::Vector{Point2f} + vs = project_position(scene, transform_func, space, GeometryBasics.coordinates(mesh), model)::Vector{Point2f} fs = decompose(GLTriangleFace, mesh)::Vector{GLTriangleFace} uv = decompose_uv(mesh)::Union{Nothing, Vector{Vec2f}} # Note: This assume the function is only called from mesh plots @@ -1200,7 +1184,7 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki pos = primitive[1][] # For correct z-ordering we need to be in view/camera or screen space - model = copy(model) + model = copy(model)::Mat4d view = scene.camera.view[] zorder = sortperm(pos, by = p -> begin @@ -1253,9 +1237,9 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki pos = Makie.voxel_positions(primitive) scale = Makie.voxel_size(primitive) colors = Makie.voxel_colors(primitive) - marker = GeometryBasics.normal_mesh(Rect3f(Point3f(-0.5), Vec3f(1))) - - # Face culling + marker = GeometryBasics.expand_faceviews(normal_mesh(Rect3f(Point3f(-0.5), Vec3f(1)))) + + if !isempty(primitive.clip_planes[]) && Makie.is_data_space(primitive.space[]) valid = [is_visible(primitive.clip_planes[], p) for p in pos] pos = pos[valid] @@ -1263,7 +1247,7 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki end # For correct z-ordering we need to be in view/camera or screen space - model = copy(primitive.model[]) + model = copy(primitive.model[])::Mat4d view = scene.camera.view[] zorder = sortperm(pos, by = p -> begin diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index fcf49b1d2ad..193627a41c5 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -14,7 +14,7 @@ end # much faster than dot-ing `project_position` because it skips all the repeated mat * mat function project_position( - scene::Scene, space::Symbol, ps::Vector{<: VecTypes{N, T1}}, + scene::Scene, space::Symbol, ps::Vector{<: VecTypes{N, T1}}, indices::Vector{<:Integer}, model::Mat4, yflip::Bool = true ) where {N, T1} @@ -44,7 +44,7 @@ function _project_position(scene::Scene, space, ps::AbstractArray{<: VecTypes{N, end function project_position( - scene::Scene, space::Symbol, ps::AbstractArray{<: VecTypes{N, T1}}, + scene::Scene, space::Symbol, ps::AbstractArray{<: VecTypes{N, T1}}, indices::Base.OneTo, model::Mat4, yflip::Bool = true ) where {N, T1} @@ -149,14 +149,15 @@ function clip_shape(clip_planes::Vector{Plane3f}, shape::Rect2, space::Symbol, m if !Makie.is_data_space(space) || isempty(clip_planes) return shape end - + xy = origin(shape) w, h = widths(shape) - ps = [xy, xy + Vec2(w, 0), xy + Vec2f(w, h), xy + Vec2(0, h)] + ps = Vec2f[xy, xy + Vec2f(w, 0), xy + Vec2f(w, h), xy + Vec2f(0, h)] if any(p -> Makie.is_clipped(clip_planes, p), ps) push!(ps, xy) ps = clip_poly(clip_planes, ps, space, model) - return BezierPath([MoveTo(ps[1]), LineTo.(ps[2:end])..., ClosePath()]) + commands = Makie.PathCommand[MoveTo(ps[1]), LineTo.(ps[2:end])..., ClosePath()] + return BezierPath(commands::Vector{Makie.PathCommand}) else return shape end @@ -173,7 +174,7 @@ function project_polygon(@nospecialize(scenelike), space, poly::Polygon{N, T}, c ext_proj = PT[project(p) for p in clip_poly(clip_planes, ext, space, model)] interiors_proj = Vector{PT}[ - PT[project(p) for p in clip_poly(clip_planes, decompose(PT, points), space, model)] + PT[project(p) for p in clip_poly(clip_planes, decompose(PT, points), space, model)] for points in poly.interiors] return Polygon(ext_proj, interiors_proj) @@ -195,7 +196,7 @@ end # at clip planes per_point_colors = colors <: AbstractArray per_point_linewidths = (T <: Lines) && (linewidths <: AbstractArray) - + quote @get_attribute(plot, (space, model)) @@ -207,7 +208,7 @@ end @inbounds for (i, point) in enumerate(points) clip_points[i] = transform * to_ndim(Vec4d, to_ndim(Vec3d, point, 0), 1) end - + # yflip and clip -> screen/pixel coords res = scene.camera.resolution[] @@ -219,14 +220,14 @@ end end # Fix lines with points far outside the clipped region not drawing at all - # TODO this can probably be done more efficiently by checking -1 ≤ x, y ≤ 1 + # TODO this can probably be done more efficiently by checking -1 ≤ x, y ≤ 1 # directly and calculating intersections directly (1D) push!(clip_planes, Plane3f(Vec3f(-1, 0, 0), -1f0), Plane3f(Vec3f(+1, 0, 0), -1f0), Plane3f(Vec3f(0, -1, 0), -1f0), Plane3f(Vec3f(0, +1, 0), -1f0) ) - + # outputs screen_points = sizehint!(Vec2f[], length(clip_points)) $(if per_point_colors @@ -314,8 +315,8 @@ end end) elseif !hidden # if not hidden, always push the first element to 1:end-1 line points - - # if the start of the segment is disconnected (moved), make sure the + + # if the start of the segment is disconnected (moved), make sure the # line separates before it if disconnect1 && !last_is_nan push!(screen_points, Vec2f(NaN)) @@ -326,7 +327,7 @@ end :(push!(color_output, c1)) end) end - + last_is_nan = false push!(screen_points, clip2screen(p1, res)) $(if per_point_linewidths @@ -336,7 +337,7 @@ end :(push!(color_output, c1)) end) - # if the end of the segment is disconnected (moved), add the adjusted + # if the end of the segment is disconnected (moved), add the adjusted # point and separate it from from the next segment if disconnect2 last_is_nan = true @@ -351,8 +352,8 @@ end end end - # If last_is_nan == true, the last segment is either hidden or the moved - # end point has been added. If it is false we're missing the last regular + # If last_is_nan == true, the last segment is either hidden or the moved + # end point has been added. If it is false we're missing the last regular # clip_points if !last_is_nan push!(screen_points, clip2screen(clip_points[end], res)) @@ -365,7 +366,7 @@ end end else # LineSegments - + for i in 1:2:length(clip_points)-1 $(if per_point_colors quote @@ -525,8 +526,8 @@ end """ cairo_scatter_marker(marker) -Convert a Makie marker to a Cairo-compatible marker. This defaults to calling -`Makie.to_spritemarker`, but can be overridden for specific markers that can +Convert a Makie marker to a Cairo-compatible marker. This defaults to calling +`Makie.to_spritemarker`, but can be overridden for specific markers that can be directly rendered to vector formats using Cairo. """ cairo_scatter_marker(marker) = Makie.to_spritemarker(marker) diff --git a/GLMakie/Project.toml b/GLMakie/Project.toml index cbd5fe66c22..d299a50ec2f 100644 --- a/GLMakie/Project.toml +++ b/GLMakie/Project.toml @@ -1,6 +1,6 @@ name = "GLMakie" uuid = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" -version = "0.10.14" +version = "0.11.0" [deps] ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" @@ -30,7 +30,7 @@ FreeTypeAbstraction = "0.10" GLFW = "3.4.3" GeometryBasics = "0.4.11" LinearAlgebra = "1.0, 1.6" -Makie = "=0.21.14" +Makie = "=0.22.0" Markdown = "1.0, 1.6" MeshIO = "0.4" ModernGL = "1" diff --git a/GLMakie/src/GLAbstraction/GLExtendedFunctions.jl b/GLMakie/src/GLAbstraction/GLExtendedFunctions.jl index 95235c2a67f..15b7fa6d0d0 100644 --- a/GLMakie/src/GLAbstraction/GLExtendedFunctions.jl +++ b/GLMakie/src/GLAbstraction/GLExtendedFunctions.jl @@ -177,7 +177,9 @@ function glGenRenderbuffers(format::GLenum, attachment::GLenum, dimensions) return renderbuffer[1] end -function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::Integer, h::Integer, d::Integer, border::Integer, format::GLenum, datatype::GLenum, data) +Makie.@noconstprop function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::Integer, + h::Integer, d::Integer, border::Integer, format::GLenum, + datatype::GLenum, data) glTexImage3D(GL_PROXY_TEXTURE_3D, level, internalFormat, w, h, d, border, format, datatype, C_NULL) for l in 0:level result = glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, l, GL_TEXTURE_WIDTH) @@ -200,7 +202,8 @@ function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::In glTexImage3D(ttype, level, internalFormat, w, h, d, border, format, datatype, data) end -function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::Integer, h::Integer, border::Integer, format::GLenum, datatype::GLenum, data) +Makie.@noconstprop function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::Integer, + h::Integer, border::Integer, format::GLenum, datatype::GLenum, data) maxsize = glGetIntegerv(GL_MAX_TEXTURE_SIZE) glTexImage2D(GL_PROXY_TEXTURE_2D, level, internalFormat, w, h, border, format, datatype, C_NULL) for l in 0:level @@ -220,7 +223,8 @@ function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::In glTexImage2D(ttype, level, internalFormat, w, h, border, format, datatype, data) end -function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::Integer, border::Integer, format::GLenum, datatype::GLenum, data) +Makie.@noconstprop function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::Integer, + border::Integer, format::GLenum, datatype::GLenum, data) glTexImage1D(GL_PROXY_TEXTURE_1D, level, internalFormat, w, border, format, datatype, C_NULL) for l in 0:level result = glGetTexLevelParameteriv(GL_PROXY_TEXTURE_1D, l, GL_TEXTURE_WIDTH) diff --git a/GLMakie/src/GLAbstraction/GLTexture.jl b/GLMakie/src/GLAbstraction/GLTexture.jl index 39d3cf3bb60..834d7b2f5a0 100644 --- a/GLMakie/src/GLAbstraction/GLTexture.jl +++ b/GLMakie/src/GLAbstraction/GLTexture.jl @@ -82,7 +82,7 @@ function set_packing_alignment(a) # at some point we should specialize to array/ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0) end -function Texture( +Makie.@noconstprop function Texture( data::Ptr{T}, dims::NTuple{NDim, Int}; internalformat::GLenum = default_internalcolorformat(T), texturetype ::GLenum = default_texturetype(NDim), @@ -139,7 +139,7 @@ function Texture(s::ShaderAbstractions.Sampler{T, N}; kwargs...) where {T, N} pointer(s.data), size(s.data), minfilter = s.minfilter, magfilter = s.magfilter, x_repeat = s.repeat[1], y_repeat = s.repeat[min(2, N)], z_repeat = s.repeat[min(3, N)], - anisotropic = s.anisotropic; kwargs... + mipmap = s.mipmap, anisotropic = s.anisotropic; kwargs... ) obsfunc = ShaderAbstractions.connect!(s, tex) push!(tex.observers, obsfunc) diff --git a/GLMakie/src/GLAbstraction/GLTypes.jl b/GLMakie/src/GLAbstraction/GLTypes.jl index b9ce99f0167..d7bbb9aa7f7 100644 --- a/GLMakie/src/GLAbstraction/GLTypes.jl +++ b/GLMakie/src/GLAbstraction/GLTypes.jl @@ -342,7 +342,6 @@ function RenderObject( pre::Pre, post, context=current_context() ) where Pre - switch_context!(context) # This is a lazy workaround for disabling updates of `requires_update` when diff --git a/GLMakie/src/GLAbstraction/GLUniforms.jl b/GLMakie/src/GLAbstraction/GLUniforms.jl index 3da13dec89c..934cd8c5485 100644 --- a/GLMakie/src/GLAbstraction/GLUniforms.jl +++ b/GLMakie/src/GLAbstraction/GLUniforms.jl @@ -108,13 +108,15 @@ function glsl_typename(t::Type{T}) where T <: Mat string(opengl_prefix(eltype(t)), "mat", M==N ? M : string(N, "x", M)) end toglsltype_string(t::Observable) = toglsltype_string(to_value(t)) -toglsltype_string(x::T) where {T<:Union{Real, Mat, StaticVector, Texture, Colorant, TextureBuffer, Nothing}} = "uniform $(glsl_typename(x))" +function toglsltype_string(x::T) where {T<:Union{Real, Mat, StaticVector, Texture, Colorant, TextureBuffer, Nothing}} + return "uniform $(glsl_typename(x))" +end #Handle GLSL structs, which need to be addressed via single fields function toglsltype_string(x::T) where T if isa_gl_struct(x) string("uniform ", T.name.name) else - error("can't splice $T into an OpenGL shader. Make sure all fields are of a concrete type and isbits(FieldType)-->true") + error("can't splice $T into an OpenGL shader. Make sure all fields are of a concrete type and isbits(FieldType)-->true\n\n$x") end end toglsltype_string(t::Union{GLBuffer{T}, GPUVector{T}}) where {T} = string("in ", glsl_typename(T)) @@ -237,7 +239,7 @@ gl_convert(a::T) where {T <: NATIVE_TYPES} = a gl_convert(s::Observable{T}) where {T <: NATIVE_TYPES} = s gl_convert(s::Observable{T}) where T = const_lift(gl_convert, s) gl_convert(x::StaticVector{N, T}) where {N, T} = map(gl_promote(T), x) -gl_convert(x::Mat{N, M, T}) where {N, M, T} = map(gl_promote(T), x) +gl_convert(x::Mat{N, M, T}) where {N, M, T} = Mat{N, M, gl_promote(T)}(x) gl_convert(a::AbstractVector{<: AbstractFace}) = indexbuffer(s) gl_convert(t::Type{T}, a::T; kw_args...) where T <: NATIVE_TYPES = a gl_convert(::Type{<: GPUArray}, a::StaticVector) = gl_convert(a) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index f364b2e3468..1b4c775413d 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -724,6 +724,7 @@ function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, plot, space= color = pop!(gl_attributes, :color) interp = to_value(pop!(gl_attributes, :interpolate, true)) interp = interp ? :linear : :nearest + if to_value(color) isa Colorant gl_attributes[:vertex_color] = color delete!(gl_attributes, :color_map) @@ -740,6 +741,10 @@ function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, plot, space= return convert_attribute(uv_transform, key"uv_transform"()) end end + elseif to_value(color) isa ShaderAbstractions.Sampler + gl_attributes[:image] = Texture(lift(el32convert, plot, color)) + delete!(gl_attributes, :color_map) + delete!(gl_attributes, :color_norm) elseif to_value(color) isa AbstractMatrix{<:Colorant} gl_attributes[:image] = Texture(lift(el32convert, plot, color), minfilter = interp) delete!(gl_attributes, :color_map) @@ -764,13 +769,14 @@ function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, plot, space= end # TODO: avoid intermediate observable - positions = map(m -> metafree(coordinates(m)), mesh) + # TODO: Should these use direct getters? (faces, normals, texturecoordinates) + positions = map(coordinates, mesh) gl_attributes[:vertices] = apply_transform_and_f32_conversion(plot, pop!(gl_attributes, :f32c), positions) gl_attributes[:faces] = lift(x-> decompose(GLTriangleFace, x), mesh) if hasproperty(to_value(mesh), :uv) gl_attributes[:texturecoordinates] = lift(decompose_uv, mesh) end - if hasproperty(to_value(mesh), :normals) && (shading !== NoShading || matcap_active) + if hasproperty(to_value(mesh), :normal) && (shading !== NoShading || matcap_active) gl_attributes[:normals] = lift(decompose_normals, mesh) end return draw_mesh(screen, gl_attributes) diff --git a/GLMakie/src/glshaders/mesh.jl b/GLMakie/src/glshaders/mesh.jl index 49808f299e2..07229a3faf3 100644 --- a/GLMakie/src/glshaders/mesh.jl +++ b/GLMakie/src/glshaders/mesh.jl @@ -1,21 +1,17 @@ function to_opengl_mesh!(result, mesh_obs::TOrSignal{<: GeometryBasics.Mesh}) - m_attr = map(convert(Observable, mesh_obs)) do m - return (m, GeometryBasics.attributes(m)) - end - - result[:faces] = indexbuffer(map(((m,_),)-> faces(m), m_attr)) - result[:vertices] = GLBuffer(map(((m, _),) -> metafree(coordinates(m)), m_attr)) - - attribs = m_attr[][2] + m = convert(Observable, mesh_obs) + + result[:faces] = indexbuffer(map(faces, m)) + result[:vertices] = GLBuffer(map(coordinates, m)) function to_buffer(name, target) - if haskey(attribs, name) - val = attribs[name] + if hasproperty(m[], name) + val = getproperty(m[], name) if mesh_obs isa Observable - val = map(((m, a),)-> a[name], m_attr) + val = map(m -> getproperty(m, name), m) end if val[] isa AbstractVector - result[target] = GLBuffer(map(metafree, val)) + result[target] = GLBuffer(val) elseif val[] isa AbstractMatrix result[target] = Texture(val) else @@ -23,16 +19,19 @@ function to_opengl_mesh!(result, mesh_obs::TOrSignal{<: GeometryBasics.Mesh}) end end end + to_buffer(:color, :vertex_color) to_buffer(:uv, :texturecoordinates) to_buffer(:uvw, :texturecoordinates) + # Only emit normals, when we shadin' shading = get(result, :shading, NoShading)::Makie.MakieCore.ShadingAlgorithm matcap_active = !isnothing(to_value(get(result, :matcap, nothing))) if matcap_active || shading != NoShading - to_buffer(:normals, :normals) + to_buffer(:normal, :normals) end to_buffer(:attribute_id, :attribute_id) + return result end diff --git a/GLMakie/src/glwindow.jl b/GLMakie/src/glwindow.jl index 7901b34c074..c40d6a23f93 100644 --- a/GLMakie/src/glwindow.jl +++ b/GLMakie/src/glwindow.jl @@ -86,7 +86,7 @@ function check_framebuffer() return enum_to_error(status) end -function GLFramebuffer(fb_size::NTuple{2, Int}) +Makie.@noconstprop function GLFramebuffer(fb_size::NTuple{2, Int}) # Create framebuffer frambuffer_id = glGenFramebuffers() glBindFramebuffer(GL_FRAMEBUFFER, frambuffer_id) diff --git a/GLMakie/src/precompiles.jl b/GLMakie/src/precompiles.jl index 87b0fda0f87..14310997284 100644 --- a/GLMakie/src/precompiles.jl +++ b/GLMakie/src/precompiles.jl @@ -4,7 +4,7 @@ macro compile(block) return quote let figlike = $(esc(block)) - Makie.colorbuffer(figlike) + Makie.colorbuffer(figlike; px_per_unit=1) return nothing end end @@ -36,7 +36,8 @@ let screen = empty_screen(false) close(screen) destroy!(screen) - + screen = empty_screen(false, false, nothing) + destroy!(screen) config = Makie.merge_screen_config(ScreenConfig, Dict{Symbol, Any}()) screen = Screen(Scene(), config, nothing, MIME"image/png"(); visible=false, start_renderloop=false) close(screen) diff --git a/GLMakie/src/screen.jl b/GLMakie/src/screen.jl index 6188b400bd3..1e847a2efa4 100644 --- a/GLMakie/src/screen.jl +++ b/GLMakie/src/screen.jl @@ -224,7 +224,11 @@ Makie.isvisible(screen::Screen) = screen.config.visible # gets removed in destroy!(screen) const ALL_SCREENS = Set{Screen}() -function empty_screen(debugging::Bool; reuse=true, window=nothing) +Makie.@noconstprop function empty_screen(debugging::Bool; reuse=true, window=nothing) + return empty_screen(debugging, reuse, window) +end + +Makie.@noconstprop function empty_screen(debugging::Bool, reuse::Bool, window) owns_glscreen = isnothing(window) initial_resolution = (10, 10) @@ -257,20 +261,17 @@ function empty_screen(debugging::Bool; reuse=true, window=nothing) ) catch e @warn(""" - - GLFW couldn't create an OpenGL window. - This likely means, you don't have an OpenGL capable Graphic Card, - or you don't have an OpenGL 3.3 capable video driver installed. - Have a look at the troubleshooting section in the GLMakie readme: - https://github.com/MakieOrg/Makie.jl/tree/master/GLMakie#troubleshooting-opengl. - """) + GLFW couldn't create an OpenGL window. + This likely means, you don't have an OpenGL capable Graphic Card, + or you don't have an OpenGL 3.3 capable video driver installed. + Have a look at the troubleshooting section in the GLMakie readme: + https://github.com/MakieOrg/Makie.jl/tree/master/GLMakie#troubleshooting-opengl. + """) rethrow(e) end # GLFW doesn't support setting the icon on OSX - if !Sys.isapple() - GLFW.SetWindowIcon(window, Makie.icon()) - end + GLFW.SetWindowIcon(window, Makie.icon()) end # tell GLAbstraction that we created a new context. @@ -446,13 +447,14 @@ function display_scene!(screen::Screen, scene::Scene) return end -function Screen(scene::Scene; start_renderloop=true, screen_config...) +Makie.@noconstprop function Screen(scene::Scene; start_renderloop=true, screen_config...) config = Makie.merge_screen_config(ScreenConfig, Dict{Symbol, Any}(screen_config)) return Screen(scene, config; start_renderloop=start_renderloop) end # Open an interactive window -function Screen(scene::Scene, config::ScreenConfig; visible=nothing, start_renderloop=true) +Makie.@noconstprop function Screen(scene::Scene, config::ScreenConfig; visible=nothing, + start_renderloop=true) screen = singleton_screen(config.debugging) !isnothing(visible) && (config.visible = visible) apply_config!(screen, config; start_renderloop=start_renderloop) @@ -461,7 +463,8 @@ function Screen(scene::Scene, config::ScreenConfig; visible=nothing, start_rende end # Screen to save a png/jpeg to file or io -function Screen(scene::Scene, config::ScreenConfig, io::Union{Nothing, String, IO}, typ::MIME; visible=nothing, start_renderloop=false) +Makie.@noconstprop function Screen(scene::Scene, config::ScreenConfig, io::Union{Nothing,String,IO}, + typ::MIME; visible=nothing, start_renderloop=false) screen = singleton_screen(config.debugging) !isnothing(visible) && (config.visible = visible) apply_config!(screen, config; start_renderloop=start_renderloop) @@ -470,7 +473,8 @@ function Screen(scene::Scene, config::ScreenConfig, io::Union{Nothing, String, I end # Screen that is efficient for `colorbuffer(screen)` -function Screen(scene::Scene, config::ScreenConfig, ::Makie.ImageStorageFormat; start_renderloop=false) +Makie.@noconstprop function Screen(scene::Scene, config::ScreenConfig, ::Makie.ImageStorageFormat; + start_renderloop=false) screen = singleton_screen(config.debugging) config.visible = false apply_config!(screen, config; start_renderloop=start_renderloop) diff --git a/MakieCore/Project.toml b/MakieCore/Project.toml index f6ec96acc73..969aca75ad3 100644 --- a/MakieCore/Project.toml +++ b/MakieCore/Project.toml @@ -1,7 +1,7 @@ name = "MakieCore" uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b" authors = ["Simon Danisch"] -version = "0.8.9" +version = "0.9.0" [deps] ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" diff --git a/Project.toml b/Project.toml index 92538749fb0..84b268f388b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Makie" uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" authors = ["Simon Danisch", "Julius Krumbiegel"] -version = "0.21.14" +version = "0.22.0" [deps] Animations = "27a7e980-b3e6-11e9-2bcd-0b925532e340" @@ -42,6 +42,7 @@ Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" MathTeXEngine = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53" Observables = "510215fc-4207-5dde-b226-833fc4488ee2" OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" +PNGFiles = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883" Packing = "19eb6ba3-879d-56ad-ad62-d5c202156566" PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043" PolygonOps = "647866c9-e3ac-4575-94e7-e3d426903924" @@ -96,11 +97,12 @@ KernelDensity = "0.5, 0.6" LaTeXStrings = "1.2" LinearAlgebra = "1.0, 1.6" MacroTools = "0.5" -MakieCore = "=0.8.9" +MakieCore = "=0.9" Markdown = "1.0, 1.6" MathTeXEngine = "0.5, 0.6" Observables = "0.5.5" OffsetArrays = "1" +PNGFiles = "0.4.3" Packing = "0.5" PlotUtils = "1.4.2" PolygonOps = "0.1.1" diff --git a/RPRMakie/Project.toml b/RPRMakie/Project.toml index 550b0291ea8..b211e151397 100644 --- a/RPRMakie/Project.toml +++ b/RPRMakie/Project.toml @@ -1,7 +1,7 @@ name = "RPRMakie" uuid = "22d9f318-5e34-4b44-b769-6e3734a732a6" authors = ["Simon Danisch"] -version = "0.7.14" +version = "0.8.0" [deps] Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" @@ -17,9 +17,9 @@ Colors = "0.9, 0.10, 0.11, 0.12" FileIO = "1.6" GeometryBasics = "0.4.11" LinearAlgebra = "1.0, 1.6" -Makie = "=0.21.14" +Makie = "=0.22.0" Printf = "1.0, 1.6" -RadeonProRender = "0.3.0" +RadeonProRender = "0.3.2" julia = "1.3" [extras] diff --git a/RPRMakie/examples/bars.jl b/RPRMakie/examples/bars.jl index ce78f20bf77..43f7c9faf3e 100644 --- a/RPRMakie/examples/bars.jl +++ b/RPRMakie/examples/bars.jl @@ -9,7 +9,7 @@ lights = [EnvironmentLight(0.5, load(RPR.assetpath("studio026.exr"))), PointLight(Vec3f(0, 0, 20), RGBf(radiance, radiance, radiance))] ax = LScene(fig[1, 1]; scenekw=(lights=lights, showaxis=false)) -rectMesh = FRect3D(Vec3f0(-0.5, -0.5, 0), Vec3f0(1)) +rectMesh = Rect(Vec3f(-0.5, -0.5, 0), Vec3f(1)) recmesh = GeometryBasics.normal_mesh(rectMesh) n = 100 pos = [Point3f(i, j, 0) ./ 10 for i in 1:n for j in 1:n] diff --git a/RPRMakie/examples/opengl_interop.jl b/RPRMakie/examples/opengl_interop.jl index 6141b833658..5c0d4a54ad5 100644 --- a/RPRMakie/examples/opengl_interop.jl +++ b/RPRMakie/examples/opengl_interop.jl @@ -9,14 +9,15 @@ u = range(0; stop=2π, length=150) v = range(0; stop=2π, length=150) radiance = 500 lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), - PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1))] + PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1)), + AmbientLight(RGBf(0.5, 0.5, 0.5))] fig = Figure(; size=(1500, 1000)) ax = LScene(fig[1, 1]; show_axis=false, scenekw=(lights=lights,)) screen = RPRMakie.Screen(size(ax.scene); plugin=RPR.Northstar, resource=RPR.RPR_CREATION_FLAGS_ENABLE_GPU0) material = RPR.UberMaterial(screen.matsys) -surface!(ax, f.(u, v'), g.(u, v'), h.(u, v'); ambient=Vec3f(0.5), diffuse=Vec3f(1), specular=0.5, +surface!(ax, f.(u, v'), g.(u, v'), h.(u, v'); diffuse=Vec3f(1), specular=0.5, colormap=:balance, material=material) function Input(fig, val::RGB) diff --git a/RPRMakie/src/meshes.jl b/RPRMakie/src/meshes.jl index d635d58a8f7..873eac16e0e 100644 --- a/RPRMakie/src/meshes.jl +++ b/RPRMakie/src/meshes.jl @@ -172,7 +172,7 @@ function to_rpr_object(context, matsys, scene, plot::Makie.Surface) faces = decompose(GLTriangleFace, r) uv = decompose_uv(r) # with this we can beuild a mesh - mesh = GeometryBasics.Mesh(meta(vec(positions[]), uv=uv), faces) + mesh = GeometryBasics.Mesh(vec(positions[]), faces, uv = uv) rpr_mesh = RPR.Shape(context, mesh) color = plot.color[] diff --git a/ReferenceTests/src/tests/examples3d.jl b/ReferenceTests/src/tests/examples3d.jl index 49b5025051e..c6f861a4ac1 100644 --- a/ReferenceTests/src/tests/examples3d.jl +++ b/ReferenceTests/src/tests/examples3d.jl @@ -24,7 +24,7 @@ end function colormesh((geometry, color)) mesh1 = normal_mesh(geometry) npoints = length(GeometryBasics.coordinates(mesh1)) - return GeometryBasics.pointmeta(mesh1; color=fill(color, npoints)) + return GeometryBasics.mesh(mesh1; color=fill(color, npoints)) end # create an array of differently colored boxes in the direction of the 3 axes x = Vec3f(0); baselen = 0.2f0; dirlen = 1f0 @@ -315,7 +315,7 @@ end N = 3; nbfacese = 30; radius = 0.02 large_sphere = Sphere(Point3f(0), 1f0) - positions = decompose(Point3f, large_sphere, 30) + positions = decompose(Point3f, Tesselation(large_sphere, 30)) np = length(positions) pts = [positions[k][l] for k = 1:length(positions), l = 1:3] pts = vcat(pts, 1.1 .* pts + RNG.randn(size(pts)) / perturbfactor) # light position influence ? @@ -411,7 +411,7 @@ end end @reference_test "Normals of a Cat" begin - x = loadasset("cat.obj") + x = GeometryBasics.expand_faceviews(loadasset("cat.obj")) f, a, p = mesh(x, color=:black) pos = map(decompose(Point3f, x), GeometryBasics.normals(x)) do p, n p => p .+ Point(normalize(n) .* 0.05f0) @@ -434,7 +434,7 @@ end function colormesh((geometry, color)) mesh1 = normal_mesh(geometry) npoints = length(GeometryBasics.coordinates(mesh1)) - return GeometryBasics.pointmeta(mesh1; color=fill(color, npoints)) + return GeometryBasics.mesh(mesh1; color=fill(color, npoints)) end # create an array of differently colored boxes in the direction of the 3 axes x = Vec3f(0); baselen = 0.2f0; dirlen = 1f0 diff --git a/ReferenceTests/src/tests/generic_components.jl b/ReferenceTests/src/tests/generic_components.jl index 1e55b31af39..4af0ccc1fd7 100644 --- a/ReferenceTests/src/tests/generic_components.jl +++ b/ReferenceTests/src/tests/generic_components.jl @@ -1,6 +1,7 @@ # For things that aren't as plot related -@reference_test "picking" begin +# @reference_test "picking" +begin scene = Scene(size = (230, 370)) campixel!(scene) @@ -23,7 +24,7 @@ # reversed axis i2 = image!(scene, 210..180, 20..50, rand(RGBf, 2, 2)) - s2 = surface!(scene, 210..180, 80..110, rand(2, 2)) + s2 = surface!(scene, 210..180, 80..110, [1 2; 3 4], interpolate = false) hm2 = heatmap!(scene, [210, 180], [140, 170], [1 2; 3 4]) scene # for easy reviewing of the plot @@ -33,8 +34,8 @@ # verify that heatmap path is used for heatmaps if Symbol(Makie.current_backend()) == :WGLMakie - @test length(faces(WGLMakie.create_shader(scene, hm).vertexarray)) > 2 - @test length(faces(WGLMakie.create_shader(scene, hm2).vertexarray)) > 2 + @test length(WGLMakie.create_shader(scene, hm).vertexarray.buffers[:faces]) > 2 + @test length(WGLMakie.create_shader(scene, hm2).vertexarray.buffers[:faces]) > 2 elseif Symbol(Makie.current_backend()) == :GLMakie screen = scene.current_screens[1] for plt in (hm, hm2) diff --git a/ReferenceTests/src/tests/primitives.jl b/ReferenceTests/src/tests/primitives.jl index f13448dd51d..178068dcd4d 100644 --- a/ReferenceTests/src/tests/primitives.jl +++ b/ReferenceTests/src/tests/primitives.jl @@ -602,7 +602,7 @@ end f, a, p = surface(1..10, 1..10, ns, colormap = [:lightblue, :lightblue]) # plot a wireframe so we can see what's going on, and in which cells. m = Makie.surface2mesh(to_value.(p.converted)...) - scatter!(a, m.position, color = isnan.(m.normals), depth_shift = -1f-3) + scatter!(a, m.position, color = isnan.(m.normal), depth_shift = -1f-3) wireframe!(a, m, depth_shift = -1f-3, color = :black) f end diff --git a/WGLMakie/Project.toml b/WGLMakie/Project.toml index 5d469a901af..ae52b935145 100644 --- a/WGLMakie/Project.toml +++ b/WGLMakie/Project.toml @@ -1,7 +1,7 @@ name = "WGLMakie" uuid = "276b4fcb-3e11-5398-bf8b-a0c2d153d008" authors = ["SimonDanisch "] -version = "0.10.14" +version = "0.11.0" [deps] Bonito = "824d6782-a2ef-11e9-3a09-e5662e0c26f8" @@ -27,7 +27,7 @@ FreeTypeAbstraction = "0.10" GeometryBasics = "0.4.11" Hyperscript = "0.0.3, 0.0.4, 0.0.5" LinearAlgebra = "1.0, 1.6" -Makie = "=0.21.14" +Makie = "=0.22.0" Observables = "0.5.1" PNGFiles = "0.3, 0.4" PrecompileTools = "1.0" diff --git a/WGLMakie/assets/mesh.vert b/WGLMakie/assets/mesh.vert index 1852cfe7b8f..6b263917066 100644 --- a/WGLMakie/assets/mesh.vert +++ b/WGLMakie/assets/mesh.vert @@ -96,7 +96,7 @@ void main(){ } vec4 position_world = model * vec4(vertex_position, 1); - render(position_world, get_normals(), view, projection); + render(position_world, get_normal(), view, projection); frag_uv = apply_uv_transform(get_uv_transform(), get_uv()); frag_color = vertex_color(get_color(), get_colorrange(), colormap); diff --git a/WGLMakie/assets/particles.vert b/WGLMakie/assets/particles.vert index f62770b5de4..5367a067ddb 100644 --- a/WGLMakie/assets/particles.vert +++ b/WGLMakie/assets/particles.vert @@ -87,7 +87,7 @@ void main(){ // get_* gets the global inputs (uniform, sampler, position array) // those functions will get inserted by the shader creation pipeline vec3 vertex_position = get_markersize() * to_vec3(get_position()); - vec3 N = get_normals() / get_markersize(); // see issue #3702 + vec3 N = get_normal() / get_markersize(); // see issue #3702 rotate(get_rotation(), vertex_position, N); vertex_position = to_vec3(get_offset()) + vertex_position; vec4 position_world = model * vec4(vertex_position, 1); diff --git a/WGLMakie/src/Serialization.js b/WGLMakie/src/Serialization.js index 09de2ff7e8f..c594ccaf43a 100644 --- a/WGLMakie/src/Serialization.js +++ b/WGLMakie/src/Serialization.js @@ -66,6 +66,7 @@ export function delete_plots(plot_uuids) { function convert_texture(scene, data) { const tex = create_texture(scene, data); tex.needsUpdate = true; + tex.generateMipmaps = data.mipmap; tex.minFilter = THREE[data.minFilter]; tex.magFilter = THREE[data.magFilter]; tex.anisotropy = data.anisotropy; @@ -266,12 +267,13 @@ function connect_uniforms(mesh, updater) { function convert_RGB_to_RGBA(rgbArray) { const length = rgbArray.length; const rgbaArray = new rgbArray.constructor((length / 3) * 4); + const a = (rgbArray instanceof Uint8Array) ? 255 : 1.0; for (let i = 0, j = 0; i < length; i += 3, j += 4) { rgbaArray[j] = rgbArray[i]; // R rgbaArray[j + 1] = rgbArray[i + 1]; // G rgbaArray[j + 2] = rgbArray[i + 2]; // B - rgbaArray[j + 3] = 1.0; // A + rgbaArray[j + 3] = a; // A } return rgbaArray; diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index 0406f3ddb8f..e11363944bb 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -25,15 +25,19 @@ function create_shader(mscene::Scene, plot::Surface) # https://github.com/MakieOrg/Makie.jl/pull/2598#discussion_r1152552196 uv = Buffer(lift(plot, rect) do r Nx, Ny = r.nvertices - f = Vec2f(1 / Nx, 1 / Ny) - [f .* Vec2f(0.5 + i, 0.5 + j) for j in Ny-1:-1:0 for i in 0:Nx-1] + if (Nx, Ny) == (2, 2) + Vec2f[(0,1), (1,1), (1,0), (0,0)] + else + f = Vec2f(1 / Nx, 1 / Ny) + [f .* Vec2f(0.5 + i, 0.5 + j) for j in Ny-1:-1:0 for i in 0:Nx-1] + end end) normals = Buffer(lift(plot, ps, fs, plot.invert_normals) do ps, fs, invert ns = Makie.nan_aware_normals(ps, fs) return invert ? -ns : ns end) - per_vertex = Dict(:positions => positions, :faces => faces, :uv => uv, :normals => normals) + per_vertex = Dict(:positions => positions, :faces => faces, :uv => uv, :normal => normals) uniforms = Dict(:uniform_color => color, :color => false, :model => model, :PICKING_INDEX_FROM_UV => true) # TODO: allow passing Mat{2, 3, Float32} (and nothing) @@ -54,7 +58,7 @@ function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) f32c, model = Makie.patch_model(plot) mesh = limits_to_uvmesh(plot, f32c) uniforms = Dict( - :normals => Vec3f(0), + :normal => Vec3f(0), :shading => false, :diffuse => Vec3f(0), :specular => Vec3f(0), diff --git a/WGLMakie/src/meshes.jl b/WGLMakie/src/meshes.jl index 240465e6efa..238fa885c99 100644 --- a/WGLMakie/src/meshes.jl +++ b/WGLMakie/src/meshes.jl @@ -26,6 +26,8 @@ function handle_color!(plot, uniforms, buffers, uniform_color_name = :uniform_co if color[] isa Colorant uniforms[uniform_color_name] = color + elseif color[] isa ShaderAbstractions.Sampler + uniforms[uniform_color_name] = to_value(color) elseif color[] isa AbstractVector buffers[:color] = Buffer(color) elseif color[] isa Makie.AbstractPattern @@ -94,23 +96,22 @@ function draw_mesh(mscene::Scene, per_vertex, plot, uniforms; permute_tex=true) get!(uniforms, :PICKING_INDEX_FROM_UV, false) pos = pop!(per_vertex, :positions) faces = pop!(per_vertex, :faces) - mesh = GeometryBasics.Mesh(meta(pos; per_vertex...), faces) + mesh = GeometryBasics.Mesh(pos, faces; per_vertex...) return Program(WebGL(), lasset("mesh.vert"), lasset("mesh.frag"), mesh, uniforms) end function create_shader(scene::Scene, plot::Makie.Mesh) # Potentially per instance attributes mesh_signal = plot[1] - mattributes = GeometryBasics.attributes get_attribute(mesh, key) = lift(x -> getproperty(x, key), plot, mesh) - data = mattributes(mesh_signal[]) + data = GeometryBasics.vertex_attributes(mesh_signal[]) uniforms = Dict{Symbol,Any}() attributes = Dict{Symbol,Any}() uniforms[:interpolate_in_fragment_shader] = get(plot, :interpolate_in_fragment_shader, true) - for (key, default) in (:uv => Vec2f(0), :normals => Vec3f(0)) + for (key, default) in (:uv => Vec2f(0), :normal => Vec3f(0)) if haskey(data, key) attributes[key] = Buffer(get_attribute(mesh_signal, key)) else diff --git a/WGLMakie/src/serialization.jl b/WGLMakie/src/serialization.jl index a2942c681b3..b1e980744ed 100644 --- a/WGLMakie/src/serialization.jl +++ b/WGLMakie/src/serialization.jl @@ -31,17 +31,6 @@ function lift_convert(key, value, plot) end end -_pairs(any) = Base.pairs(any) -function _pairs(mesh::GeometryBasics.Mesh) - return (kv for kv in GeometryBasics.attributes(mesh)) -end - -# Don't overload faces to not invalidate -_faces(x::VertexArray) = _faces(getfield(x, :data)) -function _faces(x) - return GeometryBasics.faces(x) -end - tlength(T) = length(T) tlength(::Type{<:Real}) = 1 @@ -63,7 +52,7 @@ function serialize_three(array::Buffer) return serialize_three(flatten_buffer(array)) end -function serialize_three(array::AbstractArray{T}) where {T<:Union{UInt8,Int32,UInt32,Float32,Float16,Float64}} +function serialize_three(array::AbstractArray{T}) where {T<:Union{N0f8,UInt8,Int32,UInt32,Float32,Float16,Float64}} vec(convert(Array, array)) end @@ -89,6 +78,10 @@ three_type(::Type{UInt8}) = "UnsignedByteType" function three_filter(sym::Symbol) sym === :linear && return "LinearFilter" sym === :nearest && return "NearestFilter" + sym == :nearest_mipmap_nearest && return "NearestMipmapNearestFilter" + sym == :nearest_mipmap_linear && return "NearestMipmapLinearFilter" + sym == :linear_mipmap_nearest && return "LinearMipmapNearestFilter" + sym == :linear_mipmap_linear && return "LinearMipmapLinearFilter" error("Unknown filter mode '$sym'") end @@ -100,12 +93,16 @@ function three_repeat(s::Symbol) end function serialize_three(color::Sampler{T,N}) where {T,N} - tex = Dict(:type => "Sampler", :data => serialize_three(color.data), - :size => Int32[size(color.data)...], :three_format => three_format(T), + tex = Dict(:type => "Sampler", + :data => serialize_three(color.data), + :size => Int32[size(color.data)...], + :three_format => three_format(T), :three_type => three_type(eltype(T)), :minFilter => three_filter(color.minfilter), :magFilter => three_filter(color.magfilter), - :wrapS => three_repeat(color.repeat[1]), :anisotropy => color.anisotropic) + :wrapS => three_repeat(color.repeat[1]), + :mipmap => color.mipmap, + :anisotropy => color.anisotropic) if N > 1 tex[:wrapT] = three_repeat(color.repeat[2]) end @@ -189,25 +186,22 @@ function serialize_buffer_attribute(buffer::AbstractVector{T}) where {T} return Dict(:flat => serialize_three(buffer), :type_length => tlength(T)) end -function serialize_named_buffer(buffer) - return Dict(map(_pairs(buffer)) do (name, buff) +function serialize_named_buffer(va::ShaderAbstractions.VertexArray) + return Dict(map(ShaderAbstractions.buffers(va)) do (name, buff) return name => serialize_buffer_attribute(buff) end) end -function register_geometry_updates(@nospecialize(plot), update_buffer::Observable, named_buffers) - for (name, buffer) in _pairs(named_buffers) - if buffer isa Buffer - on(plot, ShaderAbstractions.updater(buffer).update) do (f, args) - - # update to replace the whole buffer! - if f === ShaderAbstractions.update! - new_array = args[1] - flat = flatten_buffer(new_array) - update_buffer[] = [name, serialize_three(flat), length(new_array)] - end - return +function register_geometry_updates(@nospecialize(plot), update_buffer::Observable, named_buffers::ShaderAbstractions.VertexArray) + for (name::Symbol, buffer::Buffer) in ShaderAbstractions.buffers(named_buffers) + on(plot, ShaderAbstractions.updater(buffer).update) do (f, args) + # update to replace the whole buffer! + if f === ShaderAbstractions.update! + new_array = args[1] + flat = flatten_buffer(new_array) + update_buffer[] = [name, serialize_three(flat), length(new_array)] end + return end end return update_buffer @@ -263,7 +257,7 @@ end function serialize_three(@nospecialize(plot), program::Program) - facies = reinterpret_faces(plot, _faces(program.vertexarray)) + facies = reinterpret_faces(plot, ShaderAbstractions.indexbuffer(program.vertexarray)) indices = convert(Observable, facies) uniforms = serialize_uniforms(program.uniforms) attribute_updater = Observable(["", [], 0]) diff --git a/WGLMakie/src/wglmakie.bundled.js b/WGLMakie/src/wglmakie.bundled.js index 34a6cd90b0b..8713bafc9da 100644 --- a/WGLMakie/src/wglmakie.bundled.js +++ b/WGLMakie/src/wglmakie.bundled.js @@ -21278,6 +21278,7 @@ function delete_plots(plot_uuids) { function convert_texture(scene, data) { const tex = create_texture(scene, data); tex.needsUpdate = true; + tex.generateMipmaps = data.mipmap; tex.minFilter = mod[data.minFilter]; tex.magFilter = mod[data.magFilter]; tex.anisotropy = data.anisotropy; @@ -22516,11 +22517,12 @@ function connect_uniforms(mesh, updater) { function convert_RGB_to_RGBA(rgbArray) { const length = rgbArray.length; const rgbaArray = new rgbArray.constructor(length / 3 * 4); + const a = rgbArray instanceof Uint8Array ? 255 : 1.0; for(let i = 0, j = 0; i < length; i += 3, j += 4){ rgbaArray[j] = rgbArray[i]; rgbaArray[j + 1] = rgbArray[i + 1]; rgbaArray[j + 2] = rgbArray[i + 2]; - rgbaArray[j + 3] = 1.0; + rgbaArray[j + 3] = a; } return rgbaArray; } diff --git a/assets/icons/icon-128.png b/assets/icons/icon-128.png index 50d46d4d841..749e6e93024 100644 Binary files a/assets/icons/icon-128.png and b/assets/icons/icon-128.png differ diff --git a/assets/icons/icon-16.png b/assets/icons/icon-16.png index a567bf686a9..ba884c8da98 100644 Binary files a/assets/icons/icon-16.png and b/assets/icons/icon-16.png differ diff --git a/assets/icons/icon-24.png b/assets/icons/icon-24.png index 4e5cfcaac4c..5025e243af0 100644 Binary files a/assets/icons/icon-24.png and b/assets/icons/icon-24.png differ diff --git a/assets/icons/icon-256.png b/assets/icons/icon-256.png index d0518606061..2c604e3893a 100644 Binary files a/assets/icons/icon-256.png and b/assets/icons/icon-256.png differ diff --git a/assets/icons/icon-32.png b/assets/icons/icon-32.png index 6ede90689d6..6acc8f92992 100644 Binary files a/assets/icons/icon-32.png and b/assets/icons/icon-32.png differ diff --git a/assets/icons/icon-64.png b/assets/icons/icon-64.png index 0cbf044e0a9..1096160e1e3 100644 Binary files a/assets/icons/icon-64.png and b/assets/icons/icon-64.png differ diff --git a/docs/makedocs.jl b/docs/makedocs.jl index 5ceb92f3170..142c809e250 100644 --- a/docs/makedocs.jl +++ b/docs/makedocs.jl @@ -1,6 +1,7 @@ using Pkg cd(@__DIR__) Pkg.activate(".") +pkg"add GeometryBasics#master ShaderAbstractions#ff/GeometryBasics_refactor MeshIO#ff/GeometryBasics_refactor" pkg"dev .. ../MakieCore ../CairoMakie ../GLMakie ../WGLMakie ../RPRMakie" Pkg.precompile() @@ -137,7 +138,7 @@ pages = [ "reference/plots/voxels.md", "reference/plots/vspan.md", "reference/plots/waterfall.md", - "reference/plots/wireframe.md", + "reference/plots/wireframe.md", ], "Scene" => [ "reference/scene/lighting.md", diff --git a/docs/src/explanations/backends/rprmakie.md b/docs/src/explanations/backends/rprmakie.md index e697f59db95..8163b802cf8 100644 --- a/docs/src/explanations/backends/rprmakie.md +++ b/docs/src/explanations/backends/rprmakie.md @@ -332,7 +332,7 @@ function plot_part!(scene, parent, name::String) origin = get(origins, name, nothing) if !isnothing(origin) centered = m.position .- origin - m = GeometryBasics.Mesh(meta(centered; normals=m.normals), faces(m)) + m = GeometryBasics.mesh(m, position = centered) translate!(trans, origin) else translate!(trans, -ptrans.translation[]) diff --git a/docs/src/reference/plots/mesh.md b/docs/src/reference/plots/mesh.md index a25d81b9902..27652e199eb 100644 --- a/docs/src/reference/plots/mesh.md +++ b/docs/src/reference/plots/mesh.md @@ -22,7 +22,7 @@ faces = [ colors = [:red, :green, :blue, :orange] -scene = mesh(vertices, faces, color = colors, shading = NoShading) +mesh(vertices, faces, color = colors, shading = NoShading) ``` ```@figure backend=GLMakie @@ -37,9 +37,34 @@ mesh( ) ``` +## Face colors and normals + +```@figure backend=GLMakie +using GeometryBasics + +# Reduce quality of sphere +s = Tesselation(Sphere(Point3f(0), 1f0), 12) +ps = coordinates(s) +fs = faces(s) + +# Use a FaceView to with a new set of faces which refer to one color per face. +# Each face must have the same length as the respective face in fs. +# (Using the same face type guarantees this) +FT = eltype(fs); N = length(fs) +cs = FaceView(rand(RGBf, N), [FT(i) for i in 1:N]) + +# generate normals per face (this creates a FaceView as well) +ns = face_normals(ps, fs) + +# Create mesh +m = GeometryBasics.mesh(ps, fs, normal = ns, color = cs) + +mesh(m) +``` + ## Using GeometryBasics.Mesh and Buffer/Sampler type -We can also create a mesh, to specify normals, uv coordinates: +We can also create a mesh to specify normals, uv coordinates: ```@example sampler using GeometryBasics, LinearAlgebra, GLMakie, FileIO @@ -58,9 +83,9 @@ points = vec([Point3f(xv, yv, zv) for (xv, yv, zv) in zip(x2, y2, z2)]) # The coordinates form a matrix, so to connect neighboring vertices with a face # we can just use the faces of a rectangle with the same dimension as the matrix: -faces = decompose(QuadFace{GLIndex}, Tesselation(Rect(0, 0, 1, 1), size(z2))) +_faces = decompose(QuadFace{GLIndex}, Tesselation(Rect(0, 0, 1, 1), size(z2))) # Normals of a centered sphere are easy, they're just the vertices normalized. -normals = normalize.(points) +_normals = normalize.(points) # Now we generate UV coordinates, which map the image (texture) to the vertices. # (0, 0) means lower left edge of the image, while (1, 1) means upper right corner. @@ -76,7 +101,7 @@ uv = gen_uv(0.0) # We can use a Buffer to update single elements in an array directly on the GPU # with GLMakie. They work just like normal arrays, but forward any updates written to them directly to the GPU uv_buff = Buffer(uv) -gb_mesh = GeometryBasics.Mesh(meta(points; uv=uv_buff, normals), faces) +gb_mesh = GeometryBasics.Mesh(points, _faces; uv = uv_buff, normal = _normals) f, ax, pl = mesh(gb_mesh, color = rand(100, 100), colormap=:blues) wireframe!(ax, gb_mesh, color=(:black, 0.2), linewidth=2, transparency=true) diff --git a/docs/src/reference/scene/lighting.md b/docs/src/reference/scene/lighting.md index 1a20d3e6105..6661683b9ae 100644 --- a/docs/src/reference/scene/lighting.md +++ b/docs/src/reference/scene/lighting.md @@ -150,7 +150,7 @@ ps = [ for theta in range(-20, 20, length = 21) for phi in range(60, 340, length=30) ] faces = [QuadFace(30j + i, 30j + mod1(i+1, 30), 30*(j+1) + mod1(i+1, 30), 30*(j+1) + i) for j in 0:19 for i in 1:29] -marker_mesh = GeometryBasics.Mesh(meta(ps, normals = ps), decompose(GLTriangleFace, faces)) +marker_mesh = GeometryBasics.mesh(ps, faces, normal = ps) lights = [PointLight(RGBf(10, 4, 2), Point3f(0, 0, 0), 5)] @@ -201,7 +201,7 @@ function to_mesh(l::RectLight) positions = [p, p + l.u1[], p + l.u2[], p + l.u1[] + l.u2[]] faces = GLTriangleFace[(1,2,3), (2,3,4)] normals = [n,n,n,n] - return GeometryBasics.Mesh(meta(positions, normals = normals), faces) + return GeometryBasics.Mesh(positions, faces, normal = normals) end fig = Figure(backgroundcolor = :black) diff --git a/docs/src/tutorials/scenes.md b/docs/src/tutorials/scenes.md index 91d98e929b4..e0ffaed6ccc 100644 --- a/docs/src/tutorials/scenes.md +++ b/docs/src/tutorials/scenes.md @@ -282,7 +282,7 @@ function plot_part!(scene, parent, name::String) # center the mesh to its origin, if we have one if !isnothing(origin) centered = m.position .- origin - m = GeometryBasics.Mesh(meta(centered; normals=m.normals), faces(m)) + m = GeometryBasics.mesh(m, position = centered) translate!(child, origin) else # if we don't have an origin, we need to correct for the parents translation diff --git a/metrics/ttfp/run-benchmark.jl b/metrics/ttfp/run-benchmark.jl index 84374eae260..82431077be3 100644 --- a/metrics/ttfp/run-benchmark.jl +++ b/metrics/ttfp/run-benchmark.jl @@ -222,6 +222,7 @@ end pkgs = NamedTuple[(; path="./MakieCore"), (; path="."), (; path="./$Package")] # cd("dev/Makie") Pkg.develop(pkgs) +pkg"add GeometryBasics#master MeshIO#ff/GeometryBasics_refactor ShaderAbstractions#ff/GeometryBasics_refactor" Pkg.add([(; name="JSON")]) @time Pkg.precompile() @@ -231,6 +232,7 @@ Pkg.activate(project2) pkgs = [(; rev=base_branch, name="MakieCore"), (; rev=base_branch, name="Makie"), (; rev=base_branch, name="$Package"), (;name="JSON")] Package == "WGLMakie" && push!(pkgs, (; name="Electron")) Pkg.add(pkgs) + @time Pkg.precompile() projects = [project1, project2] diff --git a/relocatability.jl b/relocatability.jl index b036ef4903f..c1f7bd2d900 100644 --- a/relocatability.jl +++ b/relocatability.jl @@ -20,6 +20,8 @@ cd(tmpdir) Pkg.generate("MakieApp") Pkg.activate("MakieApp") +pkg"add GeometryBasics#master MeshIO#ff/GeometryBasics_refactor ShaderAbstractions#ff/GeometryBasics_refactor" + makie_dir = @__DIR__ commit = cd(makie_dir) do chomp(read(`git rev-parse --verify HEAD`, String)) diff --git a/src/Makie.jl b/src/Makie.jl index 6d6a6452068..f85d00136cb 100644 --- a/src/Makie.jl +++ b/src/Makie.jl @@ -16,7 +16,6 @@ using Base64 # When loading Electron for WGLMakie, which depends on FilePaths # It invalidates half of Makie. Simplest fix is to load it early on in Makie # So that the bulk of Makie gets compiled after FilePaths invalidadet Base code -# import FilePaths using LaTeXStrings using MathTeXEngine @@ -109,6 +108,18 @@ const NativeFont = FreeTypeAbstraction.FTFont const ASSETS_DIR = RelocatableFolders.@path joinpath(@__DIR__, "..", "assets") assetpath(files...) = normpath(joinpath(ASSETS_DIR, files...)) + +# 1.6 compatible way to disable constprop for compile time improvements (and also disable inlining) +# We use this mainly in GLMakie to avoid a few bigger OpenGL based functions to get constant propagation +# (e.g. GLFrameBuffer((width, height)), which should not profit from any constant propagation) +macro noconstprop(expr) + if isdefined(Base, Symbol("@constprop")) + return esc(:(Base.@constprop :none @noinline $(expr))) + else + return esc(:(@noinline $(expr))) + end +end + include("documentation/docstringextension.jl") include("utilities/quaternions.jl") include("utilities/stable-hashing.jl") @@ -331,16 +342,23 @@ export Pattern export ReversibleScale export assetpath + +using PNGFiles + # default icon for Makie +function load_icon(name::String)::Matrix{NTuple{4,UInt8}} + img = PNGFiles.load(name)::Matrix{RGBA{Colors.N0f8}} + return reinterpret(NTuple{4,UInt8}, img) +end + function icon() path = assetpath("icons") - imgs = FileIO.load.(joinpath.(path, readdir(path))) - icons = map(img-> RGBA{Colors.N0f8}.(img), imgs) - return reinterpret.(NTuple{4,UInt8}, icons) + icons = readdir(path; join=true) + return map(load_icon, icons) end function logo() - FileIO.load(assetpath("logo.png")) + return PNGFiles.load(assetpath("logo.png")) end # populated by __init__() diff --git a/src/basic_recipes/arrows.jl b/src/basic_recipes/arrows.jl index a3a36421a8d..ef872dd0290 100644 --- a/src/basic_recipes/arrows.jl +++ b/src/basic_recipes/arrows.jl @@ -51,7 +51,7 @@ function _mantle(origin, extremity, r1, r2, N) faces[2i] = GLTriangleFace(mod1(2i+1, 2N), mod1(2i+2, 2N), 2i) end - GeometryBasics.Mesh(meta(coords; normals=normals), faces) + GeometryBasics.mesh(coords, faces; normal = normals) end # GeometryBasics.Circle doesn't work with Point3f... @@ -68,7 +68,7 @@ function _circle(origin, r, normal, N) end coords[N+1] = origin - GeometryBasics.Mesh(meta(coords; normals=normals), faces) + GeometryBasics.mesh(coords, faces; normal = normals) end function convert_arguments(::Type{<: Arrows}, x, y, u, v) diff --git a/src/basic_recipes/bracket.jl b/src/basic_recipes/bracket.jl index 73d41401cd9..0ef965c33ee 100644 --- a/src/basic_recipes/bracket.jl +++ b/src/basic_recipes/bracket.jl @@ -77,7 +77,7 @@ function plot!(pl::Bracket) v = p2 - p1 d1 = normalize(v) - d2 = [0 -1; 1 0] * d1 + d2 = Point2(-d1[2], d1[1]) orientation in (:up, :down) || error("Orientation must be :up or :down but is $(repr(orientation)).") if (orientation == :up) != (d2[2] >= 0) d2 = -d2 diff --git a/src/basic_recipes/poly.jl b/src/basic_recipes/poly.jl index e1706d5c82a..fad3016b285 100644 --- a/src/basic_recipes/poly.jl +++ b/src/basic_recipes/poly.jl @@ -62,21 +62,21 @@ end # Poly conversion function poly_convert(geometries::AbstractVector, transform_func=identity) - # TODO is this a problem with Float64 meshes? - isempty(geometries) && return typeof(GeometryBasics.Mesh(Point2f[], GLTriangleFace[]))[] + isempty(geometries) && return GeometryBasics.SimpleMesh{2, Float64, GLTriangleFace}[] return poly_convert.(geometries, (transform_func,)) end -function poly_convert(geometry::AbstractGeometry{N, T}, transform_func=identity) where {N, T} - return GeometryBasics.mesh(geometry; pointtype=Point{N,float_type(T)}, facetype=GLTriangleFace) +function poly_convert(geometry::AbstractGeometry{2, T}, transform_func=identity) where {T} + return GeometryBasics.mesh(geometry; pointtype=Point{2,float_type(T)}, facetype=GLTriangleFace) end poly_convert(meshes::AbstractVector{<:AbstractMesh}, transform_func=identity) = poly_convert.(meshes, (transform_func,)) -function poly_convert(polys::AbstractVector{<:Polygon}, transform_func=identity) - # GLPlainMesh2D is not concrete? - # TODO is this a problem with Float64 meshes? - T = GeometryBasics.Mesh{2, Float32, GeometryBasics.Ngon{2, Float32, 3, Point2f}, SimpleFaceView{2, Float32, 3, GLIndex, Point2f, GLTriangleFace}} +function poly_convert(polys::AbstractVector{PT}, transform_func=identity) where {PT <: Polygon} + get_eltype(::Type{<: Polygon{2, T}}) where {T} = float_type(T) + get_eltype(::Type{<: Polygon}) = Float64 # assuming mixed type + + T = GeometryBasics.SimpleMesh{2, get_eltype(PT), GLTriangleFace} return isempty(polys) ? T[] : poly_convert.(polys, (transform_func,)) end @@ -84,16 +84,20 @@ function poly_convert(multipolygons::AbstractVector{<:MultiPolygon}, transform_f return [merge(poly_convert.(multipoly.polygons, (transform_func,))) for multipoly in multipolygons] end +function poly_convert(multipolygon::MultiPolygon, transform_func=identity) + return poly_convert.(multipolygon.polygons, (transform_func,)) +end + poly_convert(mesh::GeometryBasics.Mesh, transform_func=identity) = mesh function poly_convert(polygon::Polygon, transform_func=identity) - outer = metafree(coordinates(polygon.exterior)) + outer = coordinates(polygon.exterior) # TODO consider applying f32 convert here too. We would need to identify this though... PT = float_type(outer) points = Vector{PT}[apply_transform(transform_func, outer)] points_flat = PT[outer;] for inner in polygon.interiors - inner_points = metafree(coordinates(inner)) + inner_points = coordinates(inner) append!(points_flat, inner_points) push!(points, apply_transform(transform_func, inner_points)) end @@ -110,7 +114,7 @@ function poly_convert(polygon::AbstractVector{<:VecTypes{2, T}}, transform_func= points_transformed = apply_transform(transform_func, points) faces = GeometryBasics.earcut_triangulate([points_transformed]) # TODO, same as above! - return GeometryBasics.Mesh(points, faces) + return GeometryBasics.Mesh(points, faces)::GeometryBasics.SimpleMesh{2, float_type(T), GLTriangleFace} end function poly_convert(polygons::AbstractVector{<:AbstractVector{<:VecTypes}}, transform_func=identity) @@ -145,7 +149,7 @@ function to_lines(polygon::AbstractVector{<: VecTypes}) return result end -function plot!(plot::Poly{<: Tuple{<: Union{Polygon, AbstractVector{<: PolyElements}}}}) +function plot!(plot::Poly{<: Tuple{<: Union{Polygon, MultiPolygon, AbstractVector{<: PolyElements}}}}) geometries = plot[1] transform_func = plot.transformation.transform_func meshes = lift(poly_convert, plot, geometries, transform_func) diff --git a/src/basic_recipes/voronoiplot.jl b/src/basic_recipes/voronoiplot.jl index 48ce36ee476..ffea935c99c 100644 --- a/src/basic_recipes/voronoiplot.jl +++ b/src/basic_recipes/voronoiplot.jl @@ -52,7 +52,7 @@ function _clip_polygon(poly::Polygon, circle::Circle) return A + AB * t end - input = Point2f.(first.(poly.exterior)) + input = Point2f.(poly.exterior) output = sizehint!(Point2f[], length(input)) for i in eachindex(input) diff --git a/src/bezier.jl b/src/bezier.jl index 20107e0bdbf..8ed278f84d1 100644 --- a/src/bezier.jl +++ b/src/bezier.jl @@ -28,7 +28,7 @@ LineTo(x, y) = LineTo(Point2d(x, y)) CurveTo(cx1::Real, cy1::Real, cx2::Real, cy2::Real, px::Real, py::Real) A path command for use within a `BezierPath` which continues the current subpath with a cubic -bezier curve to point `p`, with the first control point `c1` and the second control point `c2`. +bezier curve to point `p`, with the first control point `c1` and the second control point `c2`. """ struct CurveTo c1::Point2d @@ -357,7 +357,11 @@ bp = BezierPath(str, fit = true) scatter(1:10, marker = bp, markersize = 20) ``` """ -function BezierPath(svg::AbstractString; fit = false, bbox = nothing, flipy = false, flipx = false, keep_aspect = true) +@noconstprop function BezierPath(svg::AbstractString; fit = false, bbox = nothing, flipy = false, flipx = false, keep_aspect = true) + BezierPath(svg, fit, bbox, flipy, flipx, keep_aspect) +end + +@noconstprop function BezierPath(svg::AbstractString, fit::Bool, bbox, flipy::Bool, flipx::Bool, keep_aspect::Bool) commands = parse_bezier_commands(svg) p = BezierPath(commands) if flipy @@ -377,7 +381,6 @@ function BezierPath(svg::AbstractString; fit = false, bbox = nothing, flipy = fa end function parse_bezier_commands(svg) - # args = [e.match for e in eachmatch(r"([a-zA-Z])|(\-?\d*\.?\d+)", svg)] args = [e.match for e in eachmatch(r"(?:0(?=\d))|(?:[a-zA-Z])|(?:\-?\d*\.?\d+)", svg)] @@ -541,7 +544,7 @@ Usually, four arcs can be constructed between two points given these ellipse par One of them is chosen using two boolean flags: If `largearc === true`, the arc will be longer than 180 degrees. -If `sweepflag === true`, the arc will sweep through increasing angles. +If `sweepflag === true`, the arc will sweep through increasing angles. """ function EllipticalArc(x1, y1, x2, y2, rx, ry, ϕ, largearc::Bool, sweepflag::Bool) # https://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes diff --git a/src/conversions.jl b/src/conversions.jl index 81fdad94dcc..9ac4b6c7864 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -169,32 +169,31 @@ Takes an input `Rect` `x` and decomposes it to points. `P` is the plot Type (it is optional). """ function convert_arguments(P::PointBased, x::Rect2{T}) where T - # TODO fix the order of decompose - return convert_arguments(P, decompose(Point2{float_type(T)}, x)[[1, 2, 4, 3]]) + return convert_arguments(P, decompose(Point2{float_type(T)}, x)) end function convert_arguments(P::PointBased, mesh::AbstractMesh) return convert_arguments(P, coordinates(mesh)) end -function convert_arguments(PB::PointBased, linesegments::FaceView{<:Line, P}) where {P<:AbstractPoint} - # TODO FaceView should be natively supported by backends! - return convert_arguments(PB, collect(reinterpret(P, linesegments))) -end +# function convert_arguments(PB::PointBased, linesegments::FaceView{<:Line, P}) where {P<:Point} +# # TODO FaceView should be natively supported by backends! +# return convert_arguments(PB, collect(reinterpret(P, linesegments))) +# end function convert_arguments(::PointBased, rect::Rect3{T}) where {T} return (decompose(Point3{float_type(T)}, rect),) end function convert_arguments(P::Type{<: LineSegments}, rect::Rect3{T}) where {T} - f = decompose(LineFace{Int}, rect) + f = GeometryBasics.remove_duplicates(decompose(LineFace{Int}, rect)) p = connect(decompose(Point3{float_type(T)}, rect), f) return convert_arguments(P, p) end function convert_arguments(::Type{<: Lines}, rect::Rect3{T}) where {T} PT = Point3{float_type(T)} - points = unique(decompose(PT, rect)) + points = decompose(PT, rect) push!(points, PT(NaN)) # use to seperate linesegments return (points[[1, 2, 3, 4, 1, 5, 6, 2, 9, 6, 8, 3, 9, 5, 7, 4, 9, 7, 8]],) end @@ -490,9 +489,8 @@ end ################################################################################ function convert_arguments(::Type{<: Lines}, x::Rect2{T}) where T - # TODO fix the order of decompose points = decompose(Point2{float_type(T)}, x) - return (points[[1, 2, 4, 3, 1]],) + return (points[[1, 2, 3, 4, 1]],) end ################################################################################ @@ -508,9 +506,8 @@ function convert_arguments(::Type{<: LineSegments}, positions::AbstractVector{E} end function convert_arguments(::Type{<: LineSegments}, x::Rect2{T}) where T - # TODO fix the order of decompose points = decompose(Point2{float_type(T)}, x) - return (points[[1, 2, 2, 4, 4, 3, 3, 1]],) + return (points[[1, 2, 2, 3, 3, 4, 4, 1]],) end ################################################################################ @@ -545,28 +542,22 @@ function convert_arguments( end function convert_arguments(::Type{<:Mesh}, mesh::GeometryBasics.Mesh{N, T}) where {N, T} - T_out = float_type(T) - # Make sure we have normals! - if !hasproperty(mesh, :normals) - n = normals(metafree(decompose(Point, mesh)), faces(mesh)) - # Normals can be nothing, when it's impossible to calculate the normals (e.g. 2d mesh) - if !isnothing(n) - mesh = GeometryBasics.pointmeta(mesh; normals=decompose(Vec3f, n)) - end - end - # If already correct eltypes for GL, we can pass the mesh through as is - if eltype(metafree(coordinates(mesh))) == Point{N, T_out} && eltype(faces(mesh)) == GLTriangleFace - return (mesh,) - else - # Else, we need to convert it! - return (GeometryBasics.mesh(mesh, pointtype=Point{N, T_out}, facetype=GLTriangleFace),) + n = nothing + if !hasproperty(mesh, :normal) + n = normals(coordinates(mesh), faces(mesh), normaltype = Vec3f) end + + mesh = GeometryBasics.mesh(mesh, facetype = GLTriangleFace, pointtype = Point{N, float_type(T)}, normal = n) + mesh = GeometryBasics.expand_faceviews(mesh) # TODO: can we do this (more) in-place? + + return (mesh,) end function convert_arguments( ::Type{<:Mesh}, meshes::AbstractVector{<: Union{AbstractMesh, AbstractPolygon}} ) + # TODO: clear faceviews return (meshes,) end @@ -578,7 +569,7 @@ end # TODO GeometryBasics can't deal with this directly for Integer Points? function convert_arguments( MT::Type{<:Mesh}, - xyz::AbstractVector{<: AbstractPoint{2}} + xyz::AbstractVector{<: Point{2}} ) ps = float_convert(xyz) m = GeometryBasics.mesh(ps; pointtype=eltype(ps), facetype=GLTriangleFace) @@ -588,7 +579,10 @@ end function convert_arguments(::Type{<:Mesh}, geom::GeometryPrimitive{N, T}) where {N, T <: Real} # we convert to UV mesh as default, because otherwise the uv informations get lost # - we can still drop them, but we can't add them later on - m = GeometryBasics.mesh(geom; pointtype=Point{N,float_type(T)}, uv=Vec2f, normaltype=Vec3f, facetype=GLTriangleFace) + m = GeometryBasics.expand_faceviews(GeometryBasics.uv_normal_mesh( + geom; pointtype = Point{N, float_type(T)}, + uvtype = Vec2f, normaltype = Vec3f, facetype = GLTriangleFace + )) return (m,) end @@ -622,10 +616,10 @@ function convert_arguments( fs = to_triangles(indices) if eltype(vs) <: Point{3} ns = Vec3f.(normals(vs, fs)) - m = GeometryBasics.Mesh(meta(vs; normals=ns), fs) + m = GeometryBasics.Mesh(vs, fs; normal = ns) else # TODO, we don't need to add normals here, but maybe nice for type stability? - m = GeometryBasics.Mesh(meta(vs; normals=fill(Vec3f(0, 0, 1), length(vs))), fs) + m = GeometryBasics.Mesh(vs, fs; normal = fill(Vec3f(0, 0, 1), length(vs))) end return (m,) end @@ -1943,7 +1937,7 @@ function convert_attribute(value::Symbol, ::key"marker", ::key"meshscatter") end function convert_attribute(value::AbstractGeometry, ::key"marker", ::key"meshscatter") - return normal_mesh(value) + return GeometryBasics.expand_faceviews(normal_mesh(value)) end convert_attribute(value, ::key"diffuse") = Vec3f(value) diff --git a/src/interfaces.jl b/src/interfaces.jl index 2d9905153f5..edafbd4a09f 100644 --- a/src/interfaces.jl +++ b/src/interfaces.jl @@ -23,8 +23,7 @@ function calculated_attributes!(::Type{<: AbstractPlot}, plot) end function calculated_attributes!(::Type{<: Mesh}, plot) - mesha = lift(GeometryBasics.attributes, plot, plot.mesh) - color = haskey(mesha[], :color) ? lift(x-> x[:color], plot, mesha) : plot.color + color = hasproperty(plot.mesh[], :color) ? lift(x -> x.color, plot, plot.mesh) : plot.color color_and_colormap!(plot, color) return end diff --git a/src/layouting/text_layouting.jl b/src/layouting/text_layouting.jl index b8853eabe82..ce3bab23f17 100644 --- a/src/layouting/text_layouting.jl +++ b/src/layouting/text_layouting.jl @@ -8,7 +8,7 @@ end function attribute_per_char(string, attribute) n_words = 0 - if attribute isa GeometryBasics.StaticArray + if attribute isa GeometryBasics.StaticVector return one_attribute_per_char(attribute, string) elseif attribute isa AbstractVector if length(attribute) == length(string) diff --git a/src/makielayout/interactions.jl b/src/makielayout/interactions.jl index 5d75285b5d3..fdaa7dca1f0 100644 --- a/src/makielayout/interactions.jl +++ b/src/makielayout/interactions.jl @@ -208,7 +208,7 @@ function positivize(r::Rect2) negwidths = r.widths .< 0 newori = ifelse.(negwidths, r.origin .+ r.widths, r.origin) newwidths = ifelse.(negwidths, -r.widths, r.widths) - return Rect2(newori, newwidths) + return Rect2(Point2(newori), Vec2(newwidths)) end function process_interaction(::LimitReset, event::MouseEvent, ax::Axis) diff --git a/src/precompiles.jl b/src/precompiles.jl index 1ed6f3e0054..c76599dafe5 100644 --- a/src/precompiles.jl +++ b/src/precompiles.jl @@ -25,6 +25,8 @@ precompile(MakieCore.convert_arguments, (Type{Scatter}, UnitRange{Int64})) precompile(Makie.assemble_colors, (UnitRange{Int64}, Any, Any)) let @compile_workload begin + icon() + logo() f = Figure() ax = Axis(f[1, 1]) Makie.initialize_block!(ax) @@ -52,3 +54,5 @@ precompile(convert_command, (MoveTo,)) precompile(plot!, (MakieCore.Text{Tuple{Vector{Point{2, Float32}}}},)) precompile(Vec2{Float64}, (Tuple{Int64,Int64},)) precompile(MakieCore._create_plot, (typeof(scatter), Dict{Symbol,Any}, UnitRange{Int64})) +precompile(BezierPath, (String,)) +precompile(BezierPath, (String, Bool, Nothing, Bool, Bool, Bool)) diff --git a/src/utilities/Plane.jl b/src/utilities/Plane.jl index 03aea04e121..e90aa9adf08 100644 --- a/src/utilities/Plane.jl +++ b/src/utilities/Plane.jl @@ -228,7 +228,7 @@ function to_mesh(plane::Plane3{T}; origin = Point3f(0), scale = 1) where T ps = Point3f[_origin - v1 - v2, _origin - v1 + v2, _origin + v1 - v2, _origin + v1 + v2] ns = [plane.normal for _ in 1:4] fs = GLTriangleFace[(1,2,3), (2, 3, 4)] - return GeometryBasics.Mesh(GeometryBasics.meta(ps; normals=ns), fs) + return GeometryBasics.Mesh(ps, fs; normal = ns) end function to_clip_space(cam::Camera, planes::Vector{<: Plane3}) diff --git a/src/utilities/utilities.jl b/src/utilities/utilities.jl index ee44ed34814..e9effd5b154 100644 --- a/src/utilities/utilities.jl +++ b/src/utilities/utilities.jl @@ -398,13 +398,12 @@ which ignores all contributions from points with `NaN` components. Equivalent in application to `GeometryBasics.normals`. """ -function nan_aware_normals(vertices::AbstractVector{<:AbstractPoint{3,T}}, faces::AbstractVector{F}) where {T,F<:NgonFace} +function nan_aware_normals(vertices::AbstractVector{<:Point{3,T}}, faces::AbstractVector{F}) where {T,F<:NgonFace} normals_result = zeros(Vec3f, length(vertices)) - free_verts = GeometryBasics.metafree.(vertices) for face in faces - v1, v2, v3 = free_verts[face] + v1, v2, v3 = vertices[face] # we can get away with two edges since faces are planar. n = nan_aware_orthogonal_vector(v1, v2, v3) @@ -417,15 +416,10 @@ function nan_aware_normals(vertices::AbstractVector{<:AbstractPoint{3,T}}, faces return normals_result end -function nan_aware_normals(vertices::AbstractVector{<:AbstractPoint{2,T}}, faces::AbstractVector{F}) where {T,F<:NgonFace} +function nan_aware_normals(vertices::AbstractVector{<:Point{2,T}}, faces::AbstractVector{F}) where {T,F<:NgonFace} return Vec2f.(nan_aware_normals(map(v -> Point3{T}(v..., 0), vertices), faces)) end - -function nan_aware_normals(vertices::AbstractVector{<:GeometryBasics.PointMeta{D,T}}, faces::AbstractVector{F}) where {D,T,F<:NgonFace} - return nan_aware_normals(collect(GeometryBasics.metafree.(vertices)), faces) -end - function surface2mesh(xs, ys, zs::AbstractMatrix, transform_func = identity, space = :data) # crate a `Matrix{Point3}` # ps = matrix_grid(identity, xs, ys, zs) @@ -441,7 +435,7 @@ function surface2mesh(xs, ys, zs::AbstractMatrix, transform_func = identity, spa # uv = map(x-> Vec2f(1f0 - x[2], 1f0 - x[1]), decompose_uv(rect)) uv = decompose_uv(rect) # return a mesh with known uvs and normals. - return GeometryBasics.Mesh(GeometryBasics.meta(ps; uv=uv, normals = nan_aware_normals(ps, faces)), faces, ) + return GeometryBasics.Mesh(ps, faces; uv=uv, normal = nan_aware_normals(ps, faces)) end @@ -468,7 +462,11 @@ function matrix_grid(x::ClosedInterval, y::ClosedInterval, z::AbstractMatrix) end function matrix_grid(x::AbstractArray, y::AbstractArray, z::AbstractMatrix) - ps = [Point3(get_dim(x, i, 1, size(z)), get_dim(y, i, 2, size(z)), z[i]) for i in CartesianIndices(z)] + if size(z) == (2, 2) # untesselated Rect2 is defined in counter-clockwise fashion + ps = Point3.(x[[1,2,2,1]], y[[1,1,2,2]], z[[1,2,2,1], [1,1,2,2]]) + else + ps = [Point3(get_dim(x, i, 1, size(z)), get_dim(y, i, 2, size(z)), z[i]) for i in CartesianIndices(z)] + end return vec(ps) end diff --git a/test/conversions.jl b/test/conversions.jl index fe725b1c9ae..281a3573bc2 100644 --- a/test/conversions.jl +++ b/test/conversions.jl @@ -459,7 +459,7 @@ end cs = zeros(10, 10) for (p, c) in zip(polys, polycols) # calculate center of poly, round to indices - i, j = clamp.(round.(Int, sum(first.(p.exterior)) / length(p.exterior)), 1, 10) + i, j = clamp.(round.(Int, sum(p.exterior) / length(p.exterior)), 1, 10) cs[i, j] = c end diff --git a/test/quaternions.jl b/test/quaternions.jl index 77fd813a030..0afbbef09fe 100644 --- a/test/quaternions.jl +++ b/test/quaternions.jl @@ -15,21 +15,21 @@ Base.cos(θ::Degree) = cos(θ.θ * π/180) c = cos(theta); s = sin(theta) Rx = [1 0 0; 0 c -s; 0 s c] - @test Mat3f(qx) ≈ Rx + @test Mat3f(qx) ≈ Mat3f(Rx) theta = pi / 6 qy = qrotation(Vec(0.0, 1.0, 0.0), theta) c = cos(theta); s = sin(theta) Ry = [c 0 s; 0 1 0; -s 0 c] - @test Mat3f(qy) ≈ Ry + @test Mat3f(qy) ≈ Mat3f(Ry) theta = 4pi / 3 qz = qrotation(Vec(0.0, 0.0, 1.0), theta) c = cos(theta); s = sin(theta) Rz = [c -s 0; s c 0; 0 0 1] - @test Mat3f(qz) ≈ Rz + @test Mat3f(qz) ≈ Mat3f(Rz) - @test Mat3f(qx * qy * qz) ≈ Rx * Ry * Rz - @test Mat3f(qy * qx * qz) ≈ Ry * Rx * Rz - @test Mat3f(qz * qx * qy) ≈ Rz * Rx * Ry + @test Mat3f(qx * qy * qz) ≈ Mat3f(Rx * Ry * Rz) + @test Mat3f(qy * qx * qz) ≈ Mat3f(Ry * Rx * Rz) + @test Mat3f(qz * qx * qy) ≈ Mat3f(Rz * Rx * Ry) a, b = qrotation(Vec(0.0, 0.0, 1.0), deg2rad(0)), qrotation(Vec(0.0, 0.0, 1.0), deg2rad(180)) # @test slerp(a, b, 0.0) ≈ a diff --git a/test/ray_casting.jl b/test/ray_casting.jl index 1d159fc0e75..9a9d6399e28 100644 --- a/test/ray_casting.jl +++ b/test/ray_casting.jl @@ -135,7 +135,7 @@ p = mesh!(scene, Rect3f(Point3f(0), Vec3f(1)), transformation = transform) cam3d!(scene) ray = Makie.Ray(scene, (86.0, 204.0)) - pos = Makie.position_on_plot(p, 19, ray, apply_transform = true) + pos = Makie.position_on_plot(p, 8, ray, apply_transform = true) @test pos ≈ Point3f(1.3195645, -0.036446463, 0.6827639) # Surface (3D) @@ -213,7 +213,7 @@ p = mesh!(scene, Rect3f(Point3f(0), Vec3f(1)), transformation = transform) cam3d!(scene) ray = Makie.Ray(scene, (172.0, 282.0)) - pos = Makie.position_on_plot(p, 24, ray, apply_transform = true) + pos = Makie.position_on_plot(p, 15, ray, apply_transform = true) @test pos ≈ Point3f(0.7139215, 0.40438107, 1.344213) # Surface (3D) @@ -250,7 +250,6 @@ pos = Makie.position_on_plot(p, 527, ray, apply_transform = true) @test pos ≈ Point3f(0.27489948, -0.24948473, -0.9936166) end - end # For recreating the above: (may not work on unfocused window, needs transform definitions above)