diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml index c988a3e785b..f94f3192e3f 100644 --- a/.github/workflows/CompatHelper.yml +++ b/.github/workflows/CompatHelper.yml @@ -1,18 +1,45 @@ name: CompatHelper on: schedule: - - cron: '0 0 * * *' # Everyday at midnight + - cron: 0 0 * * * workflow_dispatch: +permissions: + contents: write + pull-requests: write jobs: CompatHelper: runs-on: ubuntu-latest - permissions: - contents: write steps: - - name: Pkg.add("CompatHelper") - run: julia -e 'using Pkg; Pkg.add("CompatHelper")' - - name: CompatHelper.main() + - name: Check if Julia is already available in the PATH + id: julia_in_path + run: which julia + continue-on-error: true + - name: Install Julia, but only if it is not already available in the PATH + uses: julia-actions/setup-julia@v1 + with: + version: '1' + arch: ${{ runner.arch }} + if: steps.julia_in_path.outcome != 'success' + - name: "Add the General registry via Git" + run: | + import Pkg + ENV["JULIA_PKG_SERVER"] = "" + Pkg.Registry.add("General") + shell: julia --color=yes {0} + - name: "Install CompatHelper" + run: | + import Pkg + name = "CompatHelper" + uuid = "aa819f21-2bde-4658-8897-bab36330d9b7" + version = "3" + Pkg.add(; name, uuid, version) + shell: julia --color=yes {0} + - name: "Run CompatHelper" + run: | + import CompatHelper + CompatHelper.main(subdirs=["", "MakieCore", "GLMakie", "WGLMakie", "CairoMakie", "RPRMakie"]) + shell: julia --color=yes {0} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} - run: julia -e 'using CompatHelper; CompatHelper.main()' + # COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }} diff --git a/.github/workflows/Docs.yml b/.github/workflows/Docs.yml index 474e1d700c8..8ce4a27aad5 100644 --- a/.github/workflows/Docs.yml +++ b/.github/workflows/Docs.yml @@ -36,6 +36,7 @@ jobs: uses: julia-actions/setup-julia@v1 with: version: '1' + - uses: julia-actions/cache@v1 - name: Build and deploy docs env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/compilation-benchmark.yaml b/.github/workflows/compilation-benchmark.yaml index ab6c5a83942..39237841bea 100644 --- a/.github/workflows/compilation-benchmark.yaml +++ b/.github/workflows/compilation-benchmark.yaml @@ -7,6 +7,9 @@ on: branches: - master - sd/beta-20 +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true jobs: benchmark: name: ${{ matrix.package }} @@ -26,6 +29,7 @@ jobs: - uses: julia-actions/setup-julia@v1 with: version: '1' + include-all-prereleases: true arch: x64 - uses: julia-actions/cache@v1 - name: Benchmark diff --git a/.github/workflows/refimages_status.yaml b/.github/workflows/refimages_status.yaml index e3a1ee59005..28de7475326 100644 --- a/.github/workflows/refimages_status.yaml +++ b/.github/workflows/refimages_status.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Download artifact" - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: debug: true script: | @@ -39,7 +39,7 @@ jobs: run: unzip n_missing_refimages.zip - name: Add reference images status - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: debug: true github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/wglmakie.yaml b/.github/workflows/wglmakie.yaml index 5e6b308fab3..6265a58419c 100644 --- a/.github/workflows/wglmakie.yaml +++ b/.github/workflows/wglmakie.yaml @@ -12,6 +12,7 @@ on: - '*' branches: - master + concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true diff --git a/CairoMakie/Project.toml b/CairoMakie/Project.toml index 43fade2fc10..65d5a532dc8 100644 --- a/CairoMakie/Project.toml +++ b/CairoMakie/Project.toml @@ -1,10 +1,10 @@ name = "CairoMakie" uuid = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" author = ["Simon Danisch "] -version = "0.10.11" +version = "0.11.3" [deps] -Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" +CRC32c = "8bf52ea8-c179-5cab-976a-9e18b702a9bc" Cairo = "159f3aea-2a34-519c-b102-8c37f9878175" Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" @@ -13,17 +13,18 @@ FreeType = "b38be410-82b0-50bf-ab77-7b57e271db43" GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" -SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" [compat] +CRC32c = "1.0, 1.6" Cairo = "1.0.4" Colors = "0.10, 0.11, 0.12" FFTW = "1" FileIO = "1.1" FreeType = "3, 4.0" GeometryBasics = "0.4.1" -Makie = "=0.19.11" +LinearAlgebra = "1.0, 1.6" +Makie = "=0.20.2" PrecompileTools = "1.0" julia = "1.3" diff --git a/CairoMakie/src/CairoMakie.jl b/CairoMakie/src/CairoMakie.jl index b5995fe1f33..57b9940e216 100644 --- a/CairoMakie/src/CairoMakie.jl +++ b/CairoMakie/src/CairoMakie.jl @@ -2,13 +2,12 @@ module CairoMakie using Makie, LinearAlgebra using Colors, GeometryBasics, FileIO -import SHA -import Base64 +import CRC32c import Cairo using Makie: Scene, Lines, Text, Image, Heatmap, Scatter, @key_str, broadcast_foreach using Makie: convert_attribute, @extractvalue, LineSegments, to_ndim, NativeFont -using Makie: @info, @get_attribute, Combined, MakieScreen +using Makie: @info, @get_attribute, Plot, MakieScreen using Makie: to_value, to_colormap, extrema_nan using Makie.Observables using Makie: spaces, is_data_space, is_pixel_space, is_relative_space, is_clip_space diff --git a/CairoMakie/src/display.jl b/CairoMakie/src/display.jl index d5cf249942b..82faca32c97 100644 --- a/CairoMakie/src/display.jl +++ b/CairoMakie/src/display.jl @@ -76,18 +76,18 @@ function Makie.backend_show(screen::Screen{SVG}, io::IO, ::MIME"image/svg+xml", svg = replace(svg, id => "surface$i") end - # salt svg ids with the first 8 characters of the base64 encoded - # sha512 hash to avoid collisions across svgs when embedding them on - # websites. the hash and therefore the salt will always be the same for the same file + # salt svg ids with the 8 hex characters of the crc32 checksum to avoid collisions + # across svgs when embedding them on websites. + # the hash and therefore the salt will always be the same for the same file # so the output is deterministic - salt = String(Base64.base64encode(SHA.sha512(svg)))[1:8] - - ids = sort(unique(collect(m[1] for m in eachmatch(r"id\s*=\s*\"([^\"]*)\"", svg)))) - - for id in ids - svg = replace(svg, id => "$id-$salt") - end - + salt = repr(CRC32c.crc32c(svg))[end-7:end] + + # matches: + # id="someid" + # 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 @@ -117,6 +117,7 @@ end const DISABLED_MIMES = Set{String}() const SUPPORTED_MIMES = Set([ + map(x->string(x()), Makie.WEB_MIMES)..., "image/svg+xml", "application/pdf", "application/postscript", diff --git a/CairoMakie/src/infrastructure.jl b/CairoMakie/src/infrastructure.jl index 6a036a84727..46e0e3bcc2d 100644 --- a/CairoMakie/src/infrastructure.jl +++ b/CairoMakie/src/infrastructure.jl @@ -57,7 +57,7 @@ function cairo_draw(screen::Screen, scene::Scene) end """ - is_cairomakie_atomic_plot(plot::Combined)::Bool + is_cairomakie_atomic_plot(plot::Plot)::Bool Returns whether the plot is considered atomic for the CairoMakie backend. This is overridden for `Poly`, `Band`, and `Tricontourf` so we can apply @@ -66,14 +66,14 @@ 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 +is_cairomakie_atomic_plot(plot::Plot) = isempty(plot.plots) || to_value(get(plot, :rasterize, false)) != false """ - check_parent_plots(f, plot::Combined)::Bool + check_parent_plots(f, plot::Plot)::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) +function check_parent_plots(f, plot::Plot) if f(plot) check_parent_plots(f, parent(plot)) else @@ -87,11 +87,9 @@ end function prepare_for_scene(screen::Screen, scene::Scene) - # get the root area to correct for its pixel size when translating - root_area = Makie.root(scene).px_area[] - - root_area_height = widths(root_area)[2] - scene_area = pixelarea(scene)[] + # get the root area to correct for its size when translating + root_area_height = widths(Makie.root(scene))[2] + scene_area = viewport(scene)[] scene_height = widths(scene_area)[2] scene_x_origin, scene_y_origin = scene_area.origin @@ -103,7 +101,7 @@ function prepare_for_scene(screen::Screen, scene::Scene) top_offset = root_area_height - scene_height - scene_y_origin Cairo.translate(screen.context, scene_x_origin, top_offset) - # clip the scene to its pixelarea + # clip the scene to its viewport Cairo.rectangle(screen.context, 0, 0, widths(scene_area)...) Cairo.clip(screen.context) @@ -116,7 +114,7 @@ function draw_background(screen::Screen, scene::Scene) if scene.clear[] bg = scene.backgroundcolor[] Cairo.set_source_rgba(cr, red(bg), green(bg), blue(bg), alpha(bg)); - r = pixelarea(scene)[] + r = viewport(scene)[] Cairo.rectangle(cr, origin(r)..., widths(r)...) # background fill(cr) end @@ -124,7 +122,7 @@ function draw_background(screen::Screen, scene::Scene) foreach(child_scene-> draw_background(screen, child_scene), scene.children) end -function draw_plot(scene::Scene, screen::Screen, primitive::Combined) +function draw_plot(scene::Scene, screen::Screen, primitive::Plot) if to_value(get(primitive, :visible, true)) if isempty(primitive.plots) Cairo.save(screen.context) @@ -145,11 +143,11 @@ end # instead of the whole Scene # - Recognize when a screen is an image surface, and set scale to render the plot # at the scale of the device pixel -function draw_plot_as_image(scene::Scene, screen::Screen, primitive::Combined, scale::Number = 1) +function draw_plot_as_image(scene::Scene, screen::Screen, primitive::Plot, scale::Number = 1) # you can provide `p.rasterize = scale::Int` or `p.rasterize = true`, both of which are numbers - # Extract scene width in pixels - w, h = Int.(scene.px_area[].widths) + # Extract scene width in device indepentent units + w, h = size(scene) # Create a new Screen which renders directly to an image surface, # specifically for the plot's parent scene. scr = Screen(scene; px_per_unit = scale) @@ -178,3 +176,7 @@ end function draw_atomic(::Scene, ::Screen, x) @warn "$(typeof(x)) is not supported by cairo right now" end + +function draw_atomic(::Scene, ::Screen, x::Makie.PlotList) + # Doesn't need drawing +end diff --git a/CairoMakie/src/overrides.jl b/CairoMakie/src/overrides.jl index 25da6a9c9c6..8bccdca5d3c 100644 --- a/CairoMakie/src/overrides.jl +++ b/CairoMakie/src/overrides.jl @@ -9,7 +9,7 @@ complex and slower to draw than standard paths with single color. function draw_plot(scene::Scene, screen::Screen, poly::Poly) # dispatch on input arguments to poly to use smarter drawing methods than # meshes if possible - draw_poly(scene, screen, poly, to_value.(poly.input_args)...) + return draw_poly(scene, screen, poly, to_value.(poly.args)...) end # Override `is_cairomakie_atomic_plot` to allow `poly` to remain a unit, @@ -73,25 +73,26 @@ function draw_poly(scene::Scene, screen::Screen, poly, points_list::Vector{<:Vec end draw_poly(scene::Scene, screen::Screen, poly, rect::Rect2) = draw_poly(scene, screen, poly, [rect]) +draw_poly(scene::Scene, screen::Screen, poly, bezierpath::BezierPath) = draw_poly(scene, screen, poly, [bezierpath]) -function draw_poly(scene::Scene, screen::Screen, poly, rects::Vector{<:Rect2}) +function draw_poly(scene::Scene, screen::Screen, poly, shapes::Vector{<:Union{Rect2,BezierPath}}) model = poly.model[] space = to_value(get(poly, :space, :data)) - projected_rects = project_rect.(Ref(scene), space, rects, Ref(model)) + projected_shapes = project_shape.(Ref(scene), space, shapes, Ref(model)) color = to_cairo_color(poly.color[], poly) linestyle = Makie.convert_attribute(poly.linestyle[], key"linestyle"()) if isnothing(linestyle) linestyle_diffed = nothing - elseif linestyle isa AbstractVector{Float64} + elseif linestyle isa AbstractVector{<:Real} linestyle_diffed = diff(Float64.(linestyle)) else error("Wrong type for linestyle: $(poly.linestyle[]).") end strokecolor = to_cairo_color(poly.strokecolor[], poly) - broadcast_foreach(projected_rects, color, strokecolor, poly.strokewidth[]) do r, c, sc, sw - Cairo.rectangle(screen.context, origin(r)..., widths(r)...) + broadcast_foreach(projected_shapes, color, strokecolor, poly.strokewidth[]) do shape, c, sc, sw + create_shape_path!(screen.context, shape) set_source(screen.context, c) Cairo.fill_preserve(screen.context) isnothing(linestyle_diffed) || Cairo.set_dash(screen.context, linestyle_diffed .* sw) @@ -101,6 +102,31 @@ function draw_poly(scene::Scene, screen::Screen, poly, rects::Vector{<:Rect2}) end end +function project_shape(scene, space, shape::BezierPath, model) + commands = Makie.PathCommand[] + for cmd in shape.commands + if cmd isa EllipticalArc + bezier = Makie.elliptical_arc_to_beziers(cmd) + for b in bezier.commands + push!(commands, project_command(b, scene, space, model)) + end + else + push!(commands, project_command(cmd, scene, space, model)) + end + end + BezierPath(commands) +end + +function create_shape_path!(ctx, r::Rect2) + Cairo.rectangle(ctx, origin(r)..., widths(r)...) +end + +function create_shape_path!(ctx, b::BezierPath) + for cmd in b.commands + path_command(ctx, cmd) + end +end + function polypath(ctx, polygon) isempty(polygon) && return nothing ext = decompose(Point2f, polygon.exterior) diff --git a/CairoMakie/src/precompiles.jl b/CairoMakie/src/precompiles.jl index b2c6ab3155d..a654e938544 100644 --- a/CairoMakie/src/precompiles.jl +++ b/CairoMakie/src/precompiles.jl @@ -15,3 +15,9 @@ let include(shared_precompile) end end +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, + Mat4f, Vector{Point{2,Float32}}, + Mat4f, Makie.FreeTypeAbstraction.FTFont, Symbol, + Symbol)) diff --git a/CairoMakie/src/primitives.jl b/CairoMakie/src/primitives.jl index f636b129b8c..3c0f45fc64c 100644 --- a/CairoMakie/src/primitives.jl +++ b/CairoMakie/src/primitives.jl @@ -49,8 +49,8 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio Cairo.set_dash(ctx, pattern) end - if primitive isa Lines && primitive.input_args[1][] isa BezierPath - return draw_bezierpath_lines(ctx, primitive.input_args[1][], scene, color, space, model, linewidth) + if primitive isa Lines && to_value(primitive.args[1]) isa BezierPath + return draw_bezierpath_lines(ctx, to_value(primitive.args[1]), scene, color, space, model, linewidth) end if color isa AbstractArray || linewidth isa AbstractArray @@ -442,7 +442,22 @@ function draw_marker(ctx, beziermarker::BezierPath, pos, scale, strokecolor, str Cairo.restore(ctx) end -draw_path(ctx, bp::BezierPath) = foreach(x -> path_command(ctx, x), bp.commands) +function draw_path(ctx, bp::BezierPath) + for i in eachindex(bp.commands) + @inbounds command = bp.commands[i] + if command isa MoveTo + path_command(ctx, command) + elseif command isa LineTo + path_command(ctx, command) + elseif command isa CurveTo + path_command(ctx, command) + elseif command isa ClosePath + path_command(ctx, command) + elseif command isa EllipticalArc + path_command(ctx, command) + end + end +end path_command(ctx, c::MoveTo) = Cairo.move_to(ctx, c.p...) path_command(ctx, c::LineTo) = Cairo.line_to(ctx, c.p...) path_command(ctx, c::CurveTo) = Cairo.curve_to(ctx, c.c1..., c.c2..., c.p...) @@ -496,13 +511,14 @@ end function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Text{<:Tuple{<:Union{AbstractArray{<:Makie.GlyphCollection}, Makie.GlyphCollection}}})) ctx = screen.context @get_attribute(primitive, (rotation, model, space, markerspace, offset)) + transform_marker = to_value(get(primitive, :transform_marker, true))::Bool position = primitive.position[] # use cached glyph info glyph_collection = to_value(primitive[1]) draw_glyph_collection( scene, ctx, position, glyph_collection, remove_billboard(rotation), - model, space, markerspace, offset, primitive.transformation + model, space, markerspace, offset, primitive.transformation, transform_marker ) nothing @@ -511,21 +527,23 @@ end function draw_glyph_collection( scene, ctx, positions, glyph_collections::AbstractArray, rotation, - model::Mat, space, markerspace, offset, transformation + model::Mat, space, markerspace, offset, transformation, transform_marker ) # TODO: why is the Ref around model necessary? doesn't broadcast_foreach handle staticarrays matrices? broadcast_foreach(positions, glyph_collections, rotation, Ref(model), space, markerspace, offset) do pos, glayout, ro, mo, sp, msp, off - draw_glyph_collection(scene, ctx, pos, glayout, ro, mo, sp, msp, off, transformation) + draw_glyph_collection(scene, ctx, pos, glayout, ro, mo, sp, msp, off, transformation, transform_marker) end end _deref(x) = x _deref(x::Ref) = x[] -function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation, _model, space, markerspace, offsets, transformation) +function draw_glyph_collection( + scene, ctx, position, glyph_collection, rotation, _model, space, + markerspace, offsets, transformation, transform_marker) glyphs = glyph_collection.glyphs glyphoffsets = glyph_collection.origins @@ -537,7 +555,7 @@ function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation, strokecolors = glyph_collection.strokecolors model = _deref(_model) - model33 = model[Vec(1, 2, 3), Vec(1, 2, 3)] + model33 = transform_marker ? model[Vec(1, 2, 3), Vec(1, 2, 3)] : Mat3f(I) id = Mat4f(I) glyph_pos = let @@ -822,8 +840,16 @@ function draw_mesh2D(scene, screen, per_face_cols, space::Symbol, transform_func # This is a hack, which needs cleaning up in the Mesh plot type! for (f, (c1, c2, c3)) in zip(fs, per_face_cols) - pattern = Cairo.CairoPatternMesh() + t1, t2, t3 = project_position.(scene, (transform_func,), space, vs[f], (model,)) #triangle points + + # don't draw any mesh faces with NaN components. + if isnan(t1) || isnan(t2) || isnan(t3) + continue + end + + pattern = Cairo.CairoPatternMesh() + Cairo.mesh_pattern_begin_patch(pattern) Cairo.mesh_pattern_move_to(pattern, t1...) @@ -851,13 +877,13 @@ end nan2zero(x) = !isnan(x) * x -function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f0) +function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f0, rotation = Mat4f(I)) @get_attribute(attributes, (shading, diffuse, specular, shininess, faceculling)) matcap = to_value(get(attributes, :matcap, nothing)) meshpoints = decompose(Point3f, mesh)::Vector{Point3f} meshfaces = decompose(GLTriangleFace, mesh)::Vector{GLTriangleFace} - meshnormals = decompose_normals(mesh)::Vector{Vec3f} + meshnormals = decompose_normals(mesh)::Vector{Vec3f} # note: can be made NaN-aware. meshuvs = texturecoordinates(mesh)::Union{Nothing, Vector{Vec2f}} # Priorize colors of the mesh if present @@ -868,43 +894,61 @@ function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f model = attributes.model[]::Mat4f space = to_value(get(attributes, :space, :data))::Symbol func = Makie.transform_func(attributes) + + # TODO: assume Symbol here after this has been deprecated for a while + if shading isa Bool + @warn "`shading::Bool` is deprecated. Use `shading = NoShading` instead of false and `shading = FastShading` or `shading = MultiLightShading` instead of true." + shading_bool = shading + else + shading_bool = shading != NoShading + end + draw_mesh3D( - scene, screen, space, func, meshpoints, meshfaces, meshnormals, per_face_col, pos, scale, - model, shading::Bool, diffuse::Vec3f, + scene, screen, space, func, meshpoints, meshfaces, meshnormals, per_face_col, + pos, scale, rotation, + model, shading_bool::Bool, diffuse::Vec3f, specular::Vec3f, shininess::Float32, faceculling::Int ) end function draw_mesh3D( - scene, screen, space, transform_func, meshpoints, meshfaces, meshnormals, per_face_col, pos, scale, + scene, screen, space, transform_func, meshpoints, meshfaces, meshnormals, per_face_col, + pos, scale, rotation, model, shading, diffuse, specular, shininess, faceculling ) ctx = screen.context - view = ifelse(is_data_space(space), scene.camera.view[], Mat4f(I)) - projection = Makie.space_to_clip(scene.camera, space, false) + projectionview = Makie.space_to_clip(scene.camera, space, true) + eyeposition = scene.camera.eyeposition[] i = Vec(1, 2, 3) - normalmatrix = transpose(inv(view[i, i] * model[i, i])) - - # Mesh data - # transform to view/camera space + normalmatrix = transpose(inv(model[i, i])) + local_model = rotation * Makie.scalematrix(Vec3f(scale)) # pass transform_func as argument to function, so that we get a function barrier # and have `transform_func` be fully typed inside closure vs = broadcast(meshpoints, (transform_func,)) do v, f # Should v get a nan2zero? v = Makie.apply_transform(f, v, space) - p4d = to_ndim(Vec4f, scale .* to_ndim(Vec3f, v, 0f0), 1f0) - view * (model * p4d .+ to_ndim(Vec4f, pos, 0f0)) + p4d = to_ndim(Vec4f, to_ndim(Vec3f, v, 0f0), 1f0) + model * (local_model * p4d .+ to_ndim(Vec4f, pos, 0f0)) end ns = map(n -> normalize(normalmatrix * n), meshnormals) - # Liight math happens in view/camera space - pointlight = Makie.get_point_light(scene) - lightposition = if !isnothing(pointlight) - pointlight.position[] + + # Light math happens in view/camera space + dirlight = Makie.get_directional_light(scene) + if !isnothing(dirlight) + lightdirection = if dirlight.camera_relative + T = inv(scene.camera.view[][Vec(1,2,3), Vec(1,2,3)]) + normalize(T * dirlight.direction[]) + else + normalize(dirlight.direction[]) + end + c = dirlight.color[] + light_color = Vec3f(red(c), green(c), blue(c)) else - Vec3f(0) + lightdirection = Vec3f(0,0,-1) + light_color = Vec3f(0) end ambientlight = Makie.get_ambient_light(scene) @@ -915,11 +959,9 @@ function draw_mesh3D( Vec3f(0) end - lightpos = (view * to_ndim(Vec4f, lightposition, 1.0))[Vec(1, 2, 3)] - # Camera to screen space ts = map(vs) do v - clip = projection * v + clip = projectionview * v @inbounds begin p = (clip ./ clip[4])[Vec(1, 2)] p_yflip = Vec2f(p[1], -p[2]) @@ -929,6 +971,9 @@ function draw_mesh3D( return Vec3f(p[1], p[2], clip[3]) end + # vs are used as camdir (camera to vertex) for light calculation (in world space) + vs = map(v -> normalize(v[i] - eyeposition), vs) + # Approximate zorder average_zs = map(f -> average_z(ts, f), meshfaces) zorder = sortperm(average_zs) @@ -936,25 +981,24 @@ function draw_mesh3D( # Face culling zorder = filter(i -> any(last.(ns[meshfaces[i]]) .> faceculling), zorder) - draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, lightpos, shininess, diffuse, ambient, specular) + draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, lightdirection, light_color, shininess, diffuse, ambient, specular) return end -function _calculate_shaded_vertexcolors(N, v, c, lightpos, ambient, diffuse, specular, shininess) - L = normalize(lightpos .- v[Vec(1,2,3)]) - diff_coeff = max(dot(L, N), 0f0) - H = normalize(L + normalize(-v[Vec(1, 2, 3)])) - spec_coeff = max(dot(H, N), 0f0)^shininess +function _calculate_shaded_vertexcolors(N, v, c, lightdir, light_color, ambient, diffuse, specular, shininess) + L = lightdir + diff_coeff = max(dot(L, -N), 0f0) + H = normalize(L + v) + spec_coeff = max(dot(H, -N), 0f0)^shininess c = RGBAf(c) # if this is one expression it introduces allocations?? - new_c_part1 = (ambient .+ diff_coeff .* diffuse) .* Vec3f(c.r, c.g, c.b) #.+ - new_c = new_c_part1 .+ specular * spec_coeff + new_c_part1 = (ambient .+ light_color .* diff_coeff .* diffuse) .* Vec3f(c.r, c.g, c.b) #.+ + new_c = new_c_part1 .+ light_color .* specular * spec_coeff RGBAf(new_c..., c.alpha) end -function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, lightpos, shininess, diffuse, ambient, specular) +function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, lightdir, light_color, shininess, diffuse, ambient, specular) for k in reverse(zorder) - pattern = Cairo.CairoPatternMesh() f = meshfaces[k] # avoid SizedVector through Face indexing @@ -962,6 +1006,11 @@ function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, t2 = ts[f[2]] t3 = ts[f[3]] + # skip any mesh segments with NaN points. + if isnan(t1) || isnan(t2) || isnan(t3) + continue + end + facecolors = per_face_col[k] # light calculation if shading @@ -971,7 +1020,7 @@ function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, N = ns[f[i]] v = vs[f[i]] c = facecolors[i] - _calculate_shaded_vertexcolors(N, v, c, lightpos, ambient, diffuse, specular, shininess) + _calculate_shaded_vertexcolors(N, v, c, lightdir, light_color, ambient, diffuse, specular, shininess) end else c1, c2, c3 = facecolors @@ -983,6 +1032,8 @@ function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, # c2 = RGB(n2...) # c3 = RGB(n3...) + pattern = Cairo.CairoPatternMesh() + Cairo.mesh_pattern_begin_patch(pattern) Cairo.mesh_pattern_move_to(pattern, t1[1], t1[2]) @@ -1009,7 +1060,7 @@ end function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Makie.Surface)) # Pretend the surface plot is a mesh plot and plot that instead - mesh = surface2mesh(primitive[1][], primitive[2][], primitive[3][]) + mesh = Makie.surface2mesh(primitive[1][], primitive[2][], primitive[3][]) old = primitive[:color] if old[] === nothing primitive[:color] = primitive[3] @@ -1022,14 +1073,6 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki return nothing end -function surface2mesh(xs, ys, zs::AbstractMatrix) - ps = Makie.matrix_grid(p-> nan2zero.(p), xs, ys, zs) - rect = Tesselation(Rect2f(0, 0, 1, 1), size(zs)) - faces = decompose(QuadFace{Int}, rect) - uv = map(x-> Vec2f(1f0 - x[2], 1f0 - x[1]), decompose_uv(rect)) - uvm = GeometryBasics.Mesh(GeometryBasics.meta(ps; uv=uv), faces) - return GeometryBasics.normal_mesh(uvm) -end ################################################################################ # MeshScatter # @@ -1060,25 +1103,24 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki ) - if !(rotations isa Vector) - R = Makie.rotationmatrix4(to_rotation(rotations)) - submesh[:model] = model * R - end + submesh[:model] = model scales = primitive[:markersize][] for i in zorder p = pos[i] if color isa AbstractVector submesh[:calculated_colors] = color[i] end - if rotations isa Vector - R = Makie.rotationmatrix4(to_rotation(rotations[i])) - submesh[:model] = model * R - end scale = markersize isa Vector ? markersize[i] : markersize + rotation = if rotations isa Vector + Makie.rotationmatrix4(to_rotation(rotations[i])) + else + Makie.rotationmatrix4(to_rotation(rotations)) + end draw_mesh3D( scene, screen, submesh, marker, pos = p, - scale = scale isa Real ? Vec3f(scale) : to_ndim(Vec3f, scale, 1f0) + scale = scale isa Real ? Vec3f(scale) : to_ndim(Vec3f, scale, 1f0), + rotation = rotation ) end diff --git a/CairoMakie/src/screen.jl b/CairoMakie/src/screen.jl index 16de9cca42f..c11f5861af9 100644 --- a/CairoMakie/src/screen.jl +++ b/CairoMakie/src/screen.jl @@ -1,6 +1,6 @@ using Base.Docs: doc -@enum RenderType SVG IMAGE PDF EPS +@enum RenderType SVG IMAGE PDF EPS HTML Base.convert(::Type{RenderType}, ::MIME{SYM}) where SYM = mime_to_rendertype(SYM) function Base.convert(::Type{RenderType}, type::String) @@ -12,6 +12,8 @@ function Base.convert(::Type{RenderType}, type::String) return PDF elseif type == "eps" return EPS + elseif type in ("html", "text/html", "application/vnd.webio.application+html", "application/prs.juno.plotpane+html", "juliavscode/html") + return HTML else error("Unsupported cairo render type: $type") end @@ -22,6 +24,7 @@ function to_mime(type::RenderType) type == SVG && return MIME("image/svg+xml") type == PDF && return MIME("application/pdf") type == EPS && return MIME("application/postscript") + type == HTML && return MIME("text/html") return MIME("image/png") end @@ -35,6 +38,8 @@ function mime_to_rendertype(mime::Symbol)::RenderType return PDF elseif mime == Symbol("application/postscript") return EPS + elseif mime in (Symbol("text/html"), Symbol("text/html"), Symbol("application/vnd.webio.application+html"), Symbol("application/prs.juno.plotpane+html"), Symbol("juliavscode/html")) + return HTML else error("Unsupported mime: $mime") end @@ -55,7 +60,7 @@ function surface_from_output_type(type::RenderType, io, w, h) return Cairo.CairoPDFSurface(io, w, h) elseif type === EPS return Cairo.CairoEPSSurface(io, w, h) - elseif type === IMAGE + elseif type === IMAGE || type === HTML img = fill(ARGB32(0, 0, 0, 0), w, h) return Cairo.CairoImageSurface(img) else @@ -76,8 +81,8 @@ end to_cairo_antialias(aa::Int) = aa """ -* `px_per_unit = 1.0`: see [figure size docs](https://docs.makie.org/stable/documentation/figure_size/). -* `pt_per_unit = 0.75`: see [figure size docs](https://docs.makie.org/stable/documentation/figure_size/). +* `px_per_unit = 2.0`: see [figure docs](https://docs.makie.org/stable/documentation/figure_size/). +* `pt_per_unit = 0.75`: see [figure docs](https://docs.makie.org/stable/documentation/figure_size/). * `antialias::Union{Symbol, Int} = :best`: antialias modus Cairo uses to draw. Applicable options: `[:best => Cairo.ANTIALIAS_BEST, :good => Cairo.ANTIALIAS_GOOD, :subpixel => Cairo.ANTIALIAS_SUBPIXEL, :none => Cairo.ANTIALIAS_NONE]`. * `visible::Bool`: if true, a browser/image viewer will open to display rendered output. """ @@ -120,9 +125,7 @@ function activate!(; inline=LAST_INLINE[], type="png", screen_config...) # So, if we want to prefer the png mime, we disable the mimes that are usually higher up in the stack. disable_mime!("svg", "pdf") elseif type == "svg" - # SVG is usually pretty high up the priority, so we can just enable all mimes - # If we implement html display for CairoMakie, we might need to disable that. - disable_mime!() + disable_mime!("text/html", "application/vnd.webio.application+html", "application/prs.juno.plotpane+html", "juliavscode/html") else enable_only_mime!(type) end @@ -245,7 +248,7 @@ function Makie.apply_screen_config!(screen::Screen, config::ScreenConfig, scene: end function Screen(scene::Scene; screen_config...) - config = Makie.merge_screen_config(ScreenConfig, screen_config) + config = Makie.merge_screen_config(ScreenConfig, Dict{Symbol, Any}(screen_config)) return Screen(scene, config) end @@ -303,6 +306,7 @@ function Makie.colorbuffer(screen::Screen) end function Makie.colorbuffer(screen::Screen{IMAGE}) + Makie.push_screen!(screen.scene, screen) empty!(screen) cairo_draw(screen, screen.scene) return PermutedDimsArray(screen.surface.data, (2, 1)) diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index 32dd81c49ac..e22b8938dc0 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -47,7 +47,7 @@ function project_scale(scene::Scene, space, s, model = Mat4f(I)) end end -function project_rect(scenelike, space, rect::Rect, model) +function project_shape(scenelike, space, rect::Rect, model) mini = project_position(scenelike, space, minimum(rect), model) maxi = project_position(scenelike, space, maximum(rect), model) return Rect(mini, maxi .- mini) @@ -118,6 +118,15 @@ end to_uint32_color(c) = reinterpret(UInt32, convert(ARGB32, premultiplied_rgba(c))) +# handle patterns +function Cairo.CairoPattern(color::Makie.AbstractPattern) + # the Cairo y-coordinate are fliped + bitmappattern = reverse!(ARGB32.(Makie.to_image(color)); dims=2) + cairoimage = Cairo.CairoImageSurface(bitmappattern) + cairopattern = Cairo.CairoPattern(cairoimage) + return cairopattern +end + ######################################## # Common color utilities # ######################################## @@ -217,7 +226,7 @@ function per_face_colors(_color, matcap, faces, normals, uv) wsize = reverse(size(color)) wh = wsize .- 1 cvec = map(uv) do uv - x, y = clamp.(round.(Int, Tuple(uv) .* wh) .+ 1, 1, wh) + x, y = clamp.(round.(Int, Tuple(uv) .* wh) .+ 1, 1, wsize) return color[end - (y - 1), x] end # TODO This is wrong and doesn't actually interpolate @@ -231,14 +240,10 @@ function mesh_pattern_set_corner_color(pattern, id, c::Colorant) Cairo.mesh_pattern_set_corner_color_rgba(pattern, id, rgbatuple(c)...) end -# not piracy -function Cairo.CairoPattern(color::Makie.AbstractPattern) - # the Cairo y-coordinate are fliped - bitmappattern = reverse!(ARGB32.(Makie.to_image(color)); dims=2) - cairoimage = Cairo.CairoImageSurface(bitmappattern) - cairopattern = Cairo.CairoPattern(cairoimage) - return cairopattern -end +################################################################################ +# Font handling # +################################################################################ + """ Finds a font that can represent the unicode character! diff --git a/CairoMakie/test/runtests.jl b/CairoMakie/test/runtests.jl index 84330b132e7..d3dcc4c6c93 100644 --- a/CairoMakie/test/runtests.jl +++ b/CairoMakie/test/runtests.jl @@ -37,7 +37,7 @@ include(joinpath(@__DIR__, "rasterization_tests.jl")) @testset "saving pdf two times" begin # https://github.com/MakieOrg/Makie.jl/issues/2433 - fig = Figure(resolution=(480, 792)) + fig = Figure(size = (480, 792)) ax = Axis(fig[1, 1]) # The IO was shared between screens, which left the second figure empty save("fig.pdf", fig, pt_per_unit=0.5) @@ -52,17 +52,17 @@ include(joinpath(@__DIR__, "rasterization_tests.jl")) # https://github.com/MakieOrg/Makie.jl/issues/2438 # This bug was caused by using the screen size of the pdf screen, which # has a different device_scaling_factor, and therefore a different screen size - fig = scatter(1:4, figure=(; resolution=(800, 800))) + fig = scatter(1:4, figure=(; size = (800, 800))) save("test.pdf", fig) size(Makie.colorbuffer(fig)) == (800, 800) rm("test.pdf") end @testset "switching from pdf screen to png, save" begin - fig = scatter(1:4, figure=(; resolution=(800, 800))) + fig = scatter(1:4, figure=(; size = (800, 800))) save("test.pdf", fig) save("test.png", fig) - @test size(load("test.png")) == (800, 800) + @test size(load("test.png")) == (1600, 1600) rm("test.pdf") rm("test.png") end @@ -89,7 +89,7 @@ include(joinpath(@__DIR__, "rasterization_tests.jl")) @testset "changing resolution of same format" begin # see: https://github.com/MakieOrg/Makie.jl/issues/2433 # and: https://github.com/MakieOrg/AlgebraOfGraphics.jl/pull/441 - scene = Scene(resolution=(800, 800)); + scene = Scene(size = (800, 800)); load_save(s; kw...) = (save("test.png", s; kw...); load("test.png")) @test size(load_save(scene, px_per_unit=2)) == (1600, 1600) @test size(load_save(scene, px_per_unit=1)) == (800, 800) @@ -122,7 +122,7 @@ end @testset "VideoStream & screen options" begin N = 3 points = Observable(Point2f[]) - f, ax, pl = scatter(points, axis=(type=Axis, aspect=DataAspect(), limits=(0.4, N + 0.6, 0.4, N + 0.6),), figure=(resolution=(600, 800),)) + f, ax, pl = scatter(points, axis=(type=Axis, aspect=DataAspect(), limits=(0.4, N + 0.6, 0.4, N + 0.6),), figure=(size=(600, 800),)) vio = Makie.VideoStream(f; format="mp4", px_per_unit=2.0, backend=CairoMakie) @test vio.screen isa CairoMakie.Screen{CairoMakie.IMAGE} @test size(vio.screen) == size(f.scene) .* 2 @@ -134,7 +134,6 @@ end rm("test.mp4") end -using ReferenceTests excludes = Set([ "Colored Mesh", @@ -191,7 +190,7 @@ excludes = Set([ functions = [:volume, :volume!, :uv_mesh] @testset "refimages" begin - CairoMakie.activate!(type = "png") + CairoMakie.activate!(type = "png", px_per_unit = 1) ReferenceTests.mark_broken_tests(excludes, functions=functions) recorded_files, recording_dir = @include_reference_tests "refimages.jl" missing_images, scores = ReferenceTests.record_comparison(recording_dir) diff --git a/CairoMakie/test/svg_tests.jl b/CairoMakie/test/svg_tests.jl index fd474a54d97..36a03929bee 100644 --- a/CairoMakie/test/svg_tests.jl +++ b/CairoMakie/test/svg_tests.jl @@ -27,6 +27,9 @@ end fig end) @test svg_isnt_rasterized(poly(Circle(Point2f(0, 0), 10))) + @test svg_isnt_rasterized(poly(BezierPath([ + MoveTo(0.0, 0.0), LineTo(1.0, 0.0), LineTo(1.0, 1.0), CurveTo(1.0, 1.0, 0.5, 1.0, 0.5, 0.5), ClosePath() + ]))) end @testset "reproducable svg ids" begin diff --git a/GLMakie/Project.toml b/GLMakie/Project.toml index 93a7e4ab0aa..81d593d2573 100644 --- a/GLMakie/Project.toml +++ b/GLMakie/Project.toml @@ -1,6 +1,6 @@ name = "GLMakie" uuid = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" -version = "0.8.11" +version = "0.9.2" [deps] ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" @@ -16,9 +16,9 @@ Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" MeshIO = "7269a6da-0436-5bbc-96c2-40638cbb6118" ModernGL = "66fc600b-dfda-50eb-8b99-91cfa97b1301" Observables = "510215fc-4207-5dde-b226-833fc4488ee2" +PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" ShaderAbstractions = "65257c39-d410-5151-9873-9b3e5be5013e" -PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" [compat] @@ -27,13 +27,16 @@ Colors = "0.11, 0.12" FileIO = "1.6" FixedPointNumbers = "0.7, 0.8" FreeTypeAbstraction = "0.10" -GLFW = "3" +GLFW = "3.3" GeometryBasics = "0.4.1" -Makie = "=0.19.11" +Makie = "=0.20.2" MeshIO = "0.4" ModernGL = "1" Observables = "0.5.1" -ShaderAbstractions = "0.4" PrecompileTools = "1.0" +ShaderAbstractions = "0.4" StaticArrays = "0.12, 1.0" julia = "1" +LinearAlgebra = "1.0, 1.6" +Markdown = "1.0, 1.6" +Printf = "1.0, 1.6" diff --git a/GLMakie/assets/shader/distance_shape.frag b/GLMakie/assets/shader/distance_shape.frag index 1221978a1be..6fdeda71b3f 100644 --- a/GLMakie/assets/shader/distance_shape.frag +++ b/GLMakie/assets/shader/distance_shape.frag @@ -25,13 +25,12 @@ struct Nothing{ //Nothing type, to encode if some variable doesn't contain any d uniform float stroke_width; uniform float glow_width; uniform int shape; // shape is a uniform for now. Making them a in && using them for control flow is expected to kill performance -uniform vec2 resolution; +uniform float px_per_unit; uniform bool transparent_picking; flat in float f_viewport_from_u_scale; flat in float f_distancefield_scale; flat in vec4 f_color; -flat in vec4 f_bg_color; flat in vec4 f_stroke_color; flat in vec4 f_glow_color; flat in uvec2 f_id; @@ -90,7 +89,7 @@ float ellipse(vec2 uv, vec2 scale) // initial value vec2 q = wh * (p - wh); vec2 cs = normalize( (q.x1.0) ? -d : d; } -void fill(vec4 fillcolor, Nothing image, vec2 uv, float infill, inout vec4 color){ - color = mix(color, fillcolor, infill); -} -void fill(vec4 c, sampler2D image, vec2 uv, float infill, inout vec4 color){ - color.rgba = mix(color, texture(image, uv.yx), infill); -} -void fill(vec4 c, sampler2DArray image, vec2 uv, float infill, inout vec4 color){ - color = mix(color, texture(image, vec3(uv.yx, f_primitive_index)), infill); +vec4 fill(vec4 fillcolor, Nothing image, vec2 uv) { return fillcolor; } +vec4 fill(vec4 c, sampler2D image, vec2 uv) { return texture(image, uv.yx); } +vec4 fill(vec4 c, sampler2DArray image, vec2 uv) { + return texture(image, vec3(uv.yx, f_primitive_index)); } @@ -130,8 +125,10 @@ void stroke(vec4 strokecolor, float signed_distance, float width, inout vec4 col void glow(vec4 glowcolor, float signed_distance, float inside, inout vec4 color){ if (glow_width > 0.0){ - float outside = (abs(signed_distance)-stroke_width)/glow_width; - float alpha = 1-outside; + float s_stroke_width = px_per_unit * stroke_width; + float s_glow_width = px_per_unit * glow_width; + float outside = (abs(signed_distance) - s_stroke_width) / s_glow_width; + float alpha = 1 - outside; color = mix(vec4(glowcolor.rgb, glowcolor.a*alpha), color, inside); } } @@ -180,13 +177,21 @@ void main(){ // See notes in geometry shader where f_viewport_from_u_scale is computed. signed_distance *= f_viewport_from_u_scale; - float inside_start = max(-stroke_width, 0.0); + float s_stroke_width = px_per_unit * stroke_width; + float inside_start = max(-s_stroke_width, 0.0); float inside = aastep(inside_start, signed_distance); - vec4 final_color = f_bg_color; - fill(f_color, image, tex_uv, inside, final_color); - stroke(f_stroke_color, signed_distance, -stroke_width, final_color); - glow(f_glow_color, signed_distance, aastep(-stroke_width, signed_distance), final_color); + // For the initial coloring we can use the base pixel color and modulate + // its alpha value to create the shape set by the signed distance field. (i.e. inside) + vec4 final_color = fill(f_color, image, tex_uv); + final_color.a = final_color.a * inside; + + // Stroke and glow need to also modulate colors (rgb) to smoothly transition + // from one to another. + stroke(f_stroke_color, signed_distance, -s_stroke_width, final_color); + glow(f_glow_color, signed_distance, aastep(-s_stroke_width, signed_distance), final_color); + + // TODO: In 3D, we should arguably discard fragments outside the sprite // But note that this may interfere with object picking. // if (final_color == f_bg_color) diff --git a/GLMakie/assets/shader/fragment_output.frag b/GLMakie/assets/shader/fragment_output.frag index 7fb14e78a9a..837d5ccc3ec 100644 --- a/GLMakie/assets/shader/fragment_output.frag +++ b/GLMakie/assets/shader/fragment_output.frag @@ -13,7 +13,7 @@ layout(location=1) out uvec2 fragment_groupid; in vec3 o_view_pos; -in vec3 o_normal; +in vec3 o_view_normal; void write2framebuffer(vec4 color, uvec2 id){ if(color.a <= 0.0) @@ -34,7 +34,7 @@ void write2framebuffer(vec4 color, uvec2 id){ // // if transparency == false && ssao = true // fragment_color = color; // fragment_position = o_view_pos; - // fragment_normal_occlusion.xyz = o_normal; + // fragment_normal_occlusion.xyz = o_view_normal; // // else // fragment_color = color; diff --git a/GLMakie/assets/shader/heatmap.vert b/GLMakie/assets/shader/heatmap.vert index df15cab1327..380bf802328 100644 --- a/GLMakie/assets/shader/heatmap.vert +++ b/GLMakie/assets/shader/heatmap.vert @@ -13,7 +13,7 @@ out vec2 o_uv; flat out uvec2 o_objectid; out vec3 o_view_pos; -out vec3 o_normal; +out vec3 o_view_normal; ivec2 ind2sub(ivec2 dim, int linearindex){ return ivec2(linearindex % dim.x, linearindex / dim.x); @@ -22,7 +22,7 @@ ivec2 ind2sub(ivec2 dim, int linearindex){ void main(){ //Outputs for ssao, which we don't use for 2d shaders like heatmap/image o_view_pos = vec3(0); - o_normal = vec3(0); + o_view_normal = vec3(0); int index = gl_InstanceID; vec2 offset = vertices; diff --git a/GLMakie/assets/shader/lighting.frag b/GLMakie/assets/shader/lighting.frag new file mode 100644 index 00000000000..015ad495f97 --- /dev/null +++ b/GLMakie/assets/shader/lighting.frag @@ -0,0 +1,212 @@ +{{GLSL_VERSION}} +{{GLSL_EXTENSIONS}} + +// Sets which shading procedures to use +// Options: +// NO_SHADING - skip shading calculation, handled outside +// FAST_SHADING - single point light (forward rendering) +// MULTI_LIGHT_SHADING - simple shading with multiple lights (forward rendering) +{{shading}} + + +// Shared uniforms, inputs and functions +#if defined FAST_SHADING || defined MULTI_LIGHT_SHADING + +// Generic uniforms +uniform vec3 diffuse; +uniform vec3 specular; +uniform float shininess; + +uniform float backlight; + +in vec3 o_camdir; +in vec3 o_world_pos; + +float smooth_zero_max(float x) { + // This is a smoothed version of max(value, 0.0) where -1 <= value <= 1 + // This comes from: + // c = 2 ^ -a # normalizes power w/o swaps + // xswap = (1 / c / a)^(1 / (a - 1)) - 1 # xval with derivative 1 + // yswap = c * (xswap+1) ^ a # yval with derivative 1 + // ifelse.(xs .< yswap, c .* (xs .+ 1 .+ xswap .- yswap) .^ a, xs) + // a = 16 constants: (harder edge) + // const float c = 0.0000152587890625, xswap = 0.7411011265922482, yswap = 0.10881882041201549; + // a = 8 constants: (softer edge) + const float c = 0.00390625, xswap = 0.6406707120152759, yswap = 0.20508383900190955; + const float shift = 1.0 + xswap - yswap; + return x < yswap ? c * pow(x + shift, 8) : x; +} + +vec3 blinn_phong(vec3 light_color, vec3 light_dir, vec3 camdir, vec3 normal, vec3 color) { + // diffuse coefficient (how directly does light hits the surface) + float diff_coeff = smooth_zero_max(dot(light_dir, -normal)) + + backlight * smooth_zero_max(dot(light_dir, normal)); + + // DEBUG - visualize diff_coeff, i.e. the angle between light and normals + // if (diff_coeff > 0.999) + // return vec3(0, 0, 1); + // else + // return vec3(1 - diff_coeff,diff_coeff, 0.05); + + // specular coefficient (does reflected light bounce into camera?) + vec3 H = normalize(light_dir + camdir); + float spec_coeff = pow(max(dot(H, -normal), 0.0), shininess) + + backlight * pow(max(dot(H, normal), 0.0), shininess); + if (diff_coeff <= 0.0 || isnan(spec_coeff)) + spec_coeff = 0.0; + + return light_color * vec3(diffuse * diff_coeff * color + specular * spec_coeff); +} + +#else // glsl fails to compile if the shader is just empty + +vec3 illuminate(vec3 normal, vec3 base_color); + +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// FAST_SHADING // +//////////////////////////////////////////////////////////////////////////////// + + +#ifdef FAST_SHADING + +uniform vec3 ambient; +uniform vec3 light_color; +uniform vec3 light_direction; + +vec3 illuminate(vec3 world_pos, vec3 camdir, vec3 normal, vec3 base_color) { + vec3 shaded_color = blinn_phong(light_color, light_direction, camdir, normal, base_color); + return ambient * base_color + shaded_color; +} + +vec3 illuminate(vec3 normal, vec3 base_color) { + return illuminate(o_world_pos, normalize(o_camdir), normal, base_color); +} + +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// MULTI_LIGHT_SHADING // +//////////////////////////////////////////////////////////////////////////////// + + +#ifdef MULTI_LIGHT_SHADING + +{{MAX_LIGHTS}} +{{MAX_LIGHT_PARAMETERS}} + +// differentiating different light sources +const int UNDEFINED = 0; +const int Ambient = 1; +const int PointLight = 2; +const int DirectionalLight = 3; +const int SpotLight = 4; +const int RectLight = 5; + +// light parameters (maybe invalid depending on light type) +uniform int N_lights; +uniform int light_types[MAX_LIGHTS]; +uniform vec3 light_colors[MAX_LIGHTS]; +uniform float light_parameters[MAX_LIGHT_PARAMETERS]; + +vec3 calc_point_light(vec3 light_color, int idx, vec3 world_pos, vec3 camdir, vec3 normal, vec3 color) { + // extract args + vec3 position = vec3(light_parameters[idx], light_parameters[idx+1], light_parameters[idx+2]); + vec2 param = vec2(light_parameters[idx+3], light_parameters[idx+4]); + + // calculate light direction and distance + vec3 light_vec = world_pos - position; + + float dist = length(light_vec); + vec3 light_dir = normalize(light_vec); + + // How weak has the light gotten due to distance + // float attentuation = 1.0 / (1.0 + dist * dist * dist); + float attentuation = 1.0 / (1.0 + param.x * dist + param.y * dist * dist); + + return attentuation * blinn_phong(light_color, light_dir, camdir, normal, color); +} + +vec3 calc_directional_light(vec3 light_color, int idx, vec3 camdir, vec3 normal, vec3 color) { + vec3 light_dir = vec3(light_parameters[idx], light_parameters[idx+1], light_parameters[idx+2]); + return blinn_phong(light_color, light_dir, camdir, normal, color); +} + +vec3 calc_spot_light(vec3 light_color, int idx, vec3 world_pos, vec3 camdir, vec3 normal, vec3 color) { + // extract args + vec3 position = vec3(light_parameters[idx], light_parameters[idx+1], light_parameters[idx+2]); + vec3 spot_light_dir = normalize(vec3(light_parameters[idx+3], light_parameters[idx+4], light_parameters[idx+5])); + float inner_angle = light_parameters[idx+6]; // cos applied + float outer_angle = light_parameters[idx+7]; // cos applied + + vec3 light_dir = normalize(world_pos - position); + float intensity = smoothstep(outer_angle, inner_angle, dot(light_dir, spot_light_dir)); + + return intensity * blinn_phong(light_color, light_dir, camdir, normal, color); +} + +vec3 calc_rect_light(vec3 light_color, int idx, vec3 world_pos, vec3 camdir, vec3 normal, vec3 color) { + // extract args + vec3 origin = vec3(light_parameters[idx], light_parameters[idx+1], light_parameters[idx+2]); + vec3 u1 = vec3(light_parameters[idx+3], light_parameters[idx+4], light_parameters[idx+5]); + vec3 u2 = vec3(light_parameters[idx+6], light_parameters[idx+7], light_parameters[idx+8]); + vec3 light_dir = vec3(light_parameters[idx+9], light_parameters[idx+10], light_parameters[idx+11]); + + // Find t such that = + // to find the point p = world_pos + t * light_dir = origin + w1 * u1 + w2 * u2 + 0 * light_dir. + // Then check if p is inside the rectangle by computing w1 and w2. + float t = dot(origin - world_pos, light_dir); + vec3 dir = world_pos + t * light_dir - origin; + float w1 = dot(dir, u1) / dot(u1, u1); + float w2 = dot(dir, u2) / dot(u2, u2); + + // mask out light rays that do not come from inside the shape + float intensity = smoothstep(0.45, 0.55, 1-abs(w1)) * smoothstep(0.45, 0.55, 1-abs(w2)); + + // If we do not mask the plane we may want to consider light rays coming from + // the closest edge. + // vec3 position = origin + clamp(w1, -0.5, 0.5) * u1 + clamp(w2, -0.5, 0.5) * u2; + // vec3 light_dir = normalize(world_pos - position); + + return intensity * blinn_phong(light_color, light_dir, camdir, normal, color); +} + +vec3 illuminate(vec3 world_pos, vec3 camdir, vec3 normal, vec3 base_color) { + vec3 final_color = vec3(0); + int idx = 0; + for (int i = 0; i < min(N_lights, MAX_LIGHTS); i++) { + switch (light_types[i]) { + case Ambient: + final_color += light_colors[i] * base_color; + break; + case PointLight: + final_color += calc_point_light(light_colors[i], idx, world_pos, camdir, normal, base_color); + idx += 5; // 3 position, 2 attenuation params + break; + case DirectionalLight: + final_color += calc_directional_light(light_colors[i], idx, camdir, normal, base_color); + idx += 3; // 3 direction + break; + case SpotLight: + final_color += calc_spot_light(light_colors[i], idx, world_pos, camdir, normal, base_color); + idx += 8; // 3 position, 3 direction, 1 parameter + break; + case RectLight: + final_color += calc_rect_light(light_colors[i], idx, world_pos, camdir, normal, base_color); + idx += 12; + break; + default: + return vec3(1,0,1); // debug magenta + } + } + return final_color; +} + +vec3 illuminate(vec3 normal, vec3 base_color) { + return illuminate(o_world_pos, normalize(o_camdir), normal, base_color); +} + +#endif diff --git a/GLMakie/assets/shader/line_segment.geom b/GLMakie/assets/shader/line_segment.geom index 2c0f8d473ef..ad8b9399b13 100644 --- a/GLMakie/assets/shader/line_segment.geom +++ b/GLMakie/assets/shader/line_segment.geom @@ -47,12 +47,12 @@ void emit_vertex(vec3 position, vec2 uv, int index) } out vec3 o_view_pos; -out vec3 o_normal; +out vec3 o_view_normal; void main(void) { o_view_pos = vec3(0); - o_normal = vec3(0); + o_view_normal = vec3(0); // get the four vertices passed to the shader: vec3 p0 = screen_space(gl_in[0].gl_Position); // start of previous segment @@ -72,8 +72,8 @@ void main(void) vec3 AA_offset = AA_THICKNESS * v0; float AA = AA_THICKNESS * px2u; - /* 0 v0 l - | --> | + /* 0 v0 l + | --> | -thickness_aa0 - .----------------------------------. - -thickness_aa1 -g_thickness[0] - | .------------------------------. | - -g_thickness[1] | | | | @@ -95,8 +95,8 @@ void main(void) emit_vertex(p1 + thickness_aa1 * n0 + AA_offset, vec2(2*u + AA, -thickness_aa1), 1); emit_vertex(p1 - thickness_aa1 * n0 + AA_offset, vec2(2*u + AA, thickness_aa1), 1); #else - // For patterned lines AA is mostly done by the pattern sampling. We - // still set f_uv_minmax here to ensure that cut off patterns als have + // For patterned lines AA is mostly done by the pattern sampling. We + // still set f_uv_minmax here to ensure that cut off patterns als have // anti-aliasing at the start/end of this segment f_uv_minmax = vec2(0, u); emit_vertex(p0 + thickness_aa0 * n0 - AA_offset, vec2( - AA, -thickness_aa0), 0); diff --git a/GLMakie/assets/shader/line_segment.vert b/GLMakie/assets/shader/line_segment.vert index d93ee008ca3..b158327fd20 100644 --- a/GLMakie/assets/shader/line_segment.vert +++ b/GLMakie/assets/shader/line_segment.vert @@ -16,6 +16,7 @@ in float lastlen; uniform mat4 projectionview, model; uniform uint objectid; uniform float depth_shift; +uniform float px_per_unit; out uvec2 g_id; out vec4 g_color; @@ -42,7 +43,7 @@ void main() int index = gl_VertexID; g_id = uvec2(objectid, index+1); g_color = to_color(color, color_map, color_norm, index); - g_thickness = thickness; + g_thickness = px_per_unit * thickness; gl_Position = projectionview * model * to_vec4(vertex); gl_Position.z += gl_Position.w * depth_shift; } diff --git a/GLMakie/assets/shader/lines.geom b/GLMakie/assets/shader/lines.geom index 2670ad655ae..f5683063430 100644 --- a/GLMakie/assets/shader/lines.geom +++ b/GLMakie/assets/shader/lines.geom @@ -24,7 +24,7 @@ flat out uvec2 f_id; flat out vec2 f_uv_minmax; out vec3 o_view_pos; -out vec3 o_normal; +out vec3 o_view_normal; uniform vec2 resolution; uniform float pattern_length; @@ -56,7 +56,7 @@ void emit_vertex(vec3 position, vec2 uv, int index, float thickness) gl_Position = vec4((position.xy / resolution), position.z, 1.0); f_id = g_id[index]; // linewidth scaling may shrink the effective linewidth - f_thickness = thickness; + f_thickness = thickness; EmitVertex(); } // default for miter joins @@ -131,7 +131,7 @@ void emit_vertex(vec3 position, vec2 offset, vec2 line_dir, vec2 uv) // Generate line segment with 3 triangles // - p1, p2 are the line start and end points in pixel space -// - miter_a and miter_b are the offsets from p1 and p2 respectively that +// - miter_a and miter_b are the offsets from p1 and p2 respectively that // generate the line segment quad. This should include thickness and AA // - u1, u2 are the u values at p1 and p2. These should be in uv scale (px2uv applied) // - thickness_aa1, thickness_aa2 are linewidth at p1 and p2 with AA added. They @@ -162,7 +162,7 @@ void generate_line_segment( // \ / // \/ // /\ - // >--< + // >--< // Line segment has zero or negative width on short side // Pulled apart, we draw these two triangles (vertical lines added) @@ -171,9 +171,9 @@ void generate_line_segment( // X | | X // \| |/ // - // where X is u1/p1 (left) and u2/p2 (right) respectively. To avoid - // drawing outside the line segment due to AA padding, we cut off the - // left triangle on the right side at u2 via f_uv_minmax.y, and + // where X is u1/p1 (left) and u2/p2 (right) respectively. To avoid + // drawing outside the line segment due to AA padding, we cut off the + // left triangle on the right side at u2 via f_uv_minmax.y, and // analogously the right triangle at u1 via f_uv_minmax.x. // These triangles will still draw over each other like this. @@ -194,7 +194,7 @@ void generate_line_segment( // outgoing side f_uv_minmax.x = u1; f_uv_minmax.y = old; - + emit_vertex(p2, -miter_b, v1, vec2(u2, -thickness_aa2), 2); emit_vertex(p2, +miter_b, v1, vec2(u2, +thickness_aa2), 2); if (line_offset_b < 0){ // finish triangle on -miter_b side @@ -220,9 +220,9 @@ void generate_line_segment_debug( emit_vertex(p1 - vec3(miter_a, 0), vec2(u1 - px2uv * dot(v1, miter_a), thickness_aa1), 1, vec4(1, 0, 0, 0.5)); emit_vertex(p1 + vec3(miter_a, 0), vec2(u1 + px2uv * dot(v1, miter_a), -thickness_aa1), 1, vec4(1, 0, 0, 0.5)); emit_vertex(p2 - vec3(miter_b, 0), vec2(u2 - px2uv * dot(v1, miter_b), thickness_aa2), 2, vec4(1, 0, 0, 0.5)); - + EndPrimitive(); - + emit_vertex(p1 + vec3(miter_a, 0), vec2(u1 + px2uv * dot(v1, miter_a), -thickness_aa1), 1, vec4(0, 0, 1, 0.5)); emit_vertex(p2 - vec3(miter_b, 0), vec2(u2 - px2uv * dot(v1, miter_b), thickness_aa2), 2, vec4(0, 0, 1, 0.5)); emit_vertex(p2 + vec3(miter_b, 0), vec2(u2 + px2uv * dot(v1, miter_b), -thickness_aa2), 2, vec4(0, 0, 1, 0.5)); @@ -238,13 +238,13 @@ void generate_line_segment_debug( emit_vertex(p1 + vec3(miter_a, 0), vec2(u1 + px2uv * dot(v1, miter_a), -thickness_aa1), 1, vec4(1, 0, 0, 0.5)); emit_vertex(p1 - vec3(miter_a, 0), vec2(u1 - px2uv * dot(v1, miter_a), thickness_aa1), 1, vec4(1, 0, 0, 0.5)); emit_vertex(pc + vec3(miter_c, 0), vec2(uc + px2uv * dot(v1, miter_c), -thickness_aac), vec4(1, 0, 0, 0.5)); - + EndPrimitive(); - + emit_vertex(p1 - vec3(miter_a, 0), vec2(u1 - px2uv * dot(v1, miter_a), thickness_aa1), 1, vec4(0, 1, 0, 0.5)); emit_vertex(pc + vec3(miter_c, 0), vec2(uc + px2uv * dot(v1, miter_c), -thickness_aac), vec4(0, 1, 0, 0.5)); emit_vertex(p2 - vec3(miter_b, 0), vec2(u2 - px2uv * dot(v1, miter_b), thickness_aa2), 2, vec4(0, 1, 0, 0.5)); - + EndPrimitive(); emit_vertex(pc + vec3(miter_c, 0), vec2(uc + px2uv * dot(v1, miter_c), -thickness_aac), vec4(0, 0, 1, 0.5)); @@ -256,13 +256,13 @@ void generate_line_segment_debug( emit_vertex(p1 - vec3(miter_a, 0), vec2(u1 - px2uv * dot(v1, miter_a), -thickness_aa1), 1, vec4(1, 0, 0, 0.5)); emit_vertex(p1 + vec3(miter_a, 0), vec2(u1 + px2uv * dot(v1, miter_a), thickness_aa1), 1, vec4(1, 0, 0, 0.5)); emit_vertex(pc - vec3(miter_c, 0), vec2(uc - px2uv * dot(v1, miter_c), -thickness_aac), vec4(1, 0, 0, 0.5)); - + EndPrimitive(); - + emit_vertex(p1 + vec3(miter_a, 0), vec2(u1 + px2uv * dot(v1, miter_a), thickness_aa1), 1, vec4(0, 1, 0, 0.5)); emit_vertex(pc - vec3(miter_c, 0), vec2(uc - px2uv * dot(v1, miter_c), -thickness_aac), vec4(0, 1, 0, 0.5)); emit_vertex(p2 + vec3(miter_b, 0), vec2(u2 + px2uv * dot(v1, miter_b), thickness_aa2), 2, vec4(0, 1, 0, 0.5)); - + EndPrimitive(); emit_vertex(pc - vec3(miter_c, 0), vec2(uc - px2uv * dot(v1, miter_c), -thickness_aac), vec4(0, 0, 1, 0.5)); @@ -279,14 +279,14 @@ void generate_line_segment_debug( emit_vertex(p1 + vec3(miter_a, 0), vec2(u1 + px2uv * dot(v1, miter_a), thickness_aa1), 1, vec4(1, 0, 0, 0.5)); if (line_offset_a > 0){ // finish triangle on -miter_a side emit_vertex( - p1 + vec3(2 * line_offset_a * v1 - miter_a, 0), - vec2(u1 + px2uv * (2 * line_offset_a - dot(v1, miter_a)), -thickness_aa1), + p1 + vec3(2 * line_offset_a * v1 - miter_a, 0), + vec2(u1 + px2uv * (2 * line_offset_a - dot(v1, miter_a)), -thickness_aa1), 1, vec4(1, 0, 0, 0.5) ); } else { emit_vertex( - p1 + vec3(-2 * line_offset_a * v1 + miter_a, 0), - vec2(u1 + px2uv * (-2 * line_offset_a + dot(v1, miter_a)), thickness_aa1), + p1 + vec3(-2 * line_offset_a * v1 + miter_a, 0), + vec2(u1 + px2uv * (-2 * line_offset_a + dot(v1, miter_a)), thickness_aa1), 1, vec4(1, 0, 0, 0.5) ); } @@ -300,14 +300,14 @@ void generate_line_segment_debug( emit_vertex(p2 + vec3(miter_b, 0), vec2(u2 + px2uv * dot(v1, miter_b), thickness_aa2), 2, vec4(0, 0, 1, 0.5)); if (line_offset_b < 0){ // finish triangle on -miter_b side emit_vertex( - p2 + vec3(2 * line_offset_b * v1 - miter_b, 0), - vec2(u2 + px2uv * (2 * line_offset_b - dot(v1, miter_b)), -thickness_aa2), + p2 + vec3(2 * line_offset_b * v1 - miter_b, 0), + vec2(u2 + px2uv * (2 * line_offset_b - dot(v1, miter_b)), -thickness_aa2), 2, vec4(0, 0, 1, 0.5) ); } else { emit_vertex( - p2 + vec3(-2 * line_offset_b * v1 + miter_b, 0), - vec2(u2 + px2uv * (-2 * line_offset_b + dot(v1, miter_b)), thickness_aa2), + p2 + vec3(-2 * line_offset_b * v1 + miter_b, 0), + vec2(u2 + px2uv * (-2 * line_offset_b + dot(v1, miter_b)), thickness_aa2), 2, vec4(0, 0, 1, 0.5) ); } @@ -601,8 +601,8 @@ void draw_patterned_line(bool isvalid[4]) // Debug - show each triangle // generate_line_segment_debug( - // p1, miter_a, start, thickness_aa1, - // p2, miter_b, stop, thickness_aa2, + // p1, miter_a, start, thickness_aa1, + // p2, miter_b, stop, thickness_aa2, // v1.xy, segment_length // ); @@ -773,7 +773,7 @@ void main(void) { // These need to be set but don't have reasonable values here o_view_pos = vec3(0); - o_normal = vec3(0); + o_view_normal = vec3(0); // we generate very thin lines for linewidth 0, so we manually skip them: if (g_thickness[1] == 0.0 && g_thickness[2] == 0.0) { diff --git a/GLMakie/assets/shader/lines.vert b/GLMakie/assets/shader/lines.vert index b5f648c8bb2..d789fdbd04f 100644 --- a/GLMakie/assets/shader/lines.vert +++ b/GLMakie/assets/shader/lines.vert @@ -26,6 +26,7 @@ vec4 _color(Nothing color, sampler1D intensity, sampler1D color_map, vec2 color_ uniform mat4 projectionview, model; uniform uint objectid; uniform int total_length; +uniform float px_per_unit; out uvec2 g_id; out vec4 g_color; @@ -50,7 +51,7 @@ void main() int index = gl_VertexID; g_id = uvec2(objectid, index+1); g_valid_vertex = get_valid_vertex(valid_vertex); - g_thickness = thickness; + g_thickness = px_per_unit * thickness; g_color = _color(color, intensity, color_map, color_norm, index, total_length); #ifdef FAST_PATH diff --git a/GLMakie/assets/shader/mesh.frag b/GLMakie/assets/shader/mesh.frag index 26df220316d..5480da20008 100644 --- a/GLMakie/assets/shader/mesh.frag +++ b/GLMakie/assets/shader/mesh.frag @@ -4,15 +4,11 @@ struct Nothing{ //Nothing type, to encode if some variable doesn't contain any d bool _; //empty structs are not allowed }; -uniform vec3 ambient; -uniform vec3 diffuse; -uniform vec3 specular; -uniform float shininess; -uniform float backlight; +// Sets which shading procedures to use +{{shading}} -in vec3 o_normal; -in vec3 o_lightdir; -in vec3 o_camdir; +in vec3 o_world_normal; +in vec3 o_view_normal; in vec4 o_color; in vec2 o_uv; flat in uvec2 o_id; @@ -68,7 +64,8 @@ vec4 get_color(sampler2D intensity, vec2 uv, vec2 color_norm, sampler1D color_ma return get_color_from_cmap(i, color_map, color_norm); } vec4 matcap_color(sampler2D matcap){ - vec2 muv = o_normal.xy * 0.5 + vec2(0.5, 0.5); + // TODO should matcaps use view space normals? + vec2 muv = o_view_normal.xy * 0.5 + vec2(0.5, 0.5); return texture(matcap, vec2(1.0-muv.y, muv.x)); } vec4 get_color(Nothing image, vec2 uv, Nothing color_norm, Nothing color_map, sampler2D matcap){ @@ -100,25 +97,11 @@ vec4 get_pattern_color(sampler2D color){ // Needs to exist for opengl to be happy vec4 get_pattern_color(Nothing color){return vec4(1,0,1,1);} -vec3 blinnphong(vec3 N, vec3 V, vec3 L, vec3 color){ - float diff_coeff = max(dot(L, N), 0.0); - - // specular coefficient - vec3 H = normalize(L + V); - - float spec_coeff = pow(max(dot(H, N), 0.0), shininess); - if (diff_coeff <= 0.0 || isnan(spec_coeff)) - spec_coeff = 0.0; - - // final lighting model - return vec3( - diffuse * diff_coeff * color + - specular * spec_coeff - ); -} - void write2framebuffer(vec4 color, uvec2 id); +#ifndef NO_SHADING +vec3 illuminate(vec3 normal, vec3 base_color); +#endif void main(){ vec4 color; @@ -128,6 +111,8 @@ void main(){ }else{ color = get_color(image, o_uv, color_norm, color_map, matcap); } - {{light_calc}} + #ifndef NO_SHADING + color.rgb = illuminate(normalize(o_world_normal), color.rgb); + #endif write2framebuffer(color, o_id); } diff --git a/GLMakie/assets/shader/mesh.vert b/GLMakie/assets/shader/mesh.vert index 75d3f0d8b3a..018248c0c5c 100644 --- a/GLMakie/assets/shader/mesh.vert +++ b/GLMakie/assets/shader/mesh.vert @@ -14,10 +14,9 @@ uniform bool interpolate_in_fragment_shader = false; in vec3 normals; -uniform vec3 lightposition; uniform mat4 projection, view, model; -void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection, vec3 lightposition); +void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection); vec4 get_color_from_cmap(float value, sampler1D color_map, vec2 colorrange); uniform uint objectid; @@ -63,5 +62,5 @@ void main() o_uv = vec2(1.0 - tex_uv.y, tex_uv.x) * uv_scale; o_color = to_color(vertex_color, color_map, color_norm); vec3 v = to_3d(vertices); - render(model * vec4(v, 1), normals, view, projection, lightposition); + render(model * vec4(v, 1), normals, view, projection); } diff --git a/GLMakie/assets/shader/particles.vert b/GLMakie/assets/shader/particles.vert index 8676a2a682f..2d26785e54d 100644 --- a/GLMakie/assets/shader/particles.vert +++ b/GLMakie/assets/shader/particles.vert @@ -28,7 +28,6 @@ in vec3 vertices; in vec3 normals; {{texturecoordinates_type}} texturecoordinates; -uniform vec3 lightposition; uniform mat4 view, model, projection; uniform uint objectid; uniform int len; @@ -91,7 +90,7 @@ vec4 get_particle_color(sampler2D color, Nothing intensity, Nothing color_map, N return vec4(0); } -void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection, vec3 lightposition); +void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection); vec2 get_uv(Nothing x){return vec2(0.0);} vec2 get_uv(vec2 x){return vec2(1.0 - x.y, x.x);} @@ -108,5 +107,5 @@ void main(){ o_color = o_color * to_color(vertex_color); o_uv = get_uv(texturecoordinates); rotate(rotation, index, V, N); - render(model * vec4(pos + V, 1), N, view, projection, lightposition); + render(model * vec4(pos + V, 1), N, view, projection); } diff --git a/GLMakie/assets/shader/sprites.geom b/GLMakie/assets/shader/sprites.geom index d34d131a187..fc771ef63b5 100644 --- a/GLMakie/assets/shader/sprites.geom +++ b/GLMakie/assets/shader/sprites.geom @@ -85,7 +85,6 @@ void emit_vertex(vec4 vertex, vec2 uv) f_uv_texture_bbox = g_uv_texture_bbox[0]; f_primitive_index = g_primitive_index[0]; f_color = g_color[0]; - f_bg_color = vec4(g_color[0].rgb, 0); f_stroke_color = g_stroke_color[0]; f_glow_color = g_glow_color[0]; f_id = g_id[0]; @@ -99,12 +98,12 @@ mat2 diagm(vec2 v){ } out vec3 o_view_pos; -out vec3 o_normal; +out vec3 o_view_normal; void main(void) { o_view_pos = vec3(0); - o_normal = vec3(0); + o_view_normal = vec3(0); // emit quad as triangle strip // v3. ____ . v4 diff --git a/GLMakie/assets/shader/sprites.vert b/GLMakie/assets/shader/sprites.vert index 2489dddd040..ceee24efe7f 100644 --- a/GLMakie/assets/shader/sprites.vert +++ b/GLMakie/assets/shader/sprites.vert @@ -72,6 +72,7 @@ vec4 _color(Nothing color, sampler1D intensity, sampler1D color_map, vec2 color_ {{stroke_color_type}} stroke_color; {{glow_color_type}} glow_color; +uniform bool scale_primitive; uniform mat4 preprojection; uniform mat4 model; uniform uint objectid; @@ -96,7 +97,10 @@ void main(){ vec3 pos; {{position_calc}} vec4 p = preprojection * model * vec4(pos, 1); - g_position = p.xyz / p.w + mat3(model) * marker_offset; + if (scale_primitive) + g_position = p.xyz / p.w + mat3(model) * marker_offset; + else + g_position = p.xyz / p.w + marker_offset; g_offset_width.xy = quad_offset.xy; g_offset_width.zw = scale.xy; g_color = _color(color, intensity, color_map, color_norm, g_primitive_index, len); diff --git a/GLMakie/assets/shader/surface.vert b/GLMakie/assets/shader/surface.vert index 0388819e0e1..b8b16eb98d6 100644 --- a/GLMakie/assets/shader/surface.vert +++ b/GLMakie/assets/shader/surface.vert @@ -19,8 +19,6 @@ in vec2 vertices; {{position_y_type}} position_y; uniform sampler2D position_z; -uniform vec3 lightposition; - {{image_type}} image; {{color_map_type}} color_map; {{color_norm_type}} color_norm; @@ -36,16 +34,117 @@ uniform vec3 scale; uniform mat4 view, model, projection; // See util.vert for implementations -void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection, vec3 lightposition); +void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection); ivec2 ind2sub(ivec2 dim, int linearindex); vec2 grid_pos(Grid2D pos, vec2 uv); vec2 linear_index(ivec2 dims, int index); vec2 linear_index(ivec2 dims, int index, vec2 offset); vec4 linear_texture(sampler2D tex, int index, vec2 offset); -// vec3 getnormal_fast(sampler2D zvalues, ivec2 uv); -vec3 getnormal(Grid2D pos, Nothing xs, Nothing ys, sampler2D zs, vec2 uv); -vec3 getnormal(Nothing pos, sampler2D xs, sampler2D ys, sampler2D zs, vec2 uv); -vec3 getnormal(Nothing pos, sampler1D xs, sampler1D ys, sampler2D zs, vec2 uv); + + +// Normal generation + +vec3 getnormal_fast(sampler2D zvalues, ivec2 uv) +{ + vec3 a = vec3(0, 0, 0); + vec3 b = vec3(1, 1, 0); + a.z = texelFetch(zvalues, uv, 0).r; + b.z = texelFetch(zvalues, uv + ivec2(1, 1), 0).r; + return normalize(a - b); +} + +bool isinbounds(ivec2 uv, ivec2 size) +{ + return (uv.x < size.x && uv.y < size.y && uv.x >= 0 && uv.y >= 0); +} + +/* +Computes normal at s0 based on four surrounding positions s1 ... s4 and the +respective uv coordinates uv, off1, ..., off4 + + s2 + s1 s0 s3 + s4 +*/ +vec3 normal_from_points( + vec3 s0, vec3 s1, vec3 s2, vec3 s3, vec3 s4, + ivec2 off1, ivec2 off2, ivec2 off3, ivec2 off4, ivec2 size + ){ + vec3 result = vec3(0,0,0); + // isnan checks should avoid darkening around NaN positions but may not + // work with all systems + if (!isnan(s0.z)) { + bool check1 = isinbounds(off1, size) && !isnan(s1.z); + bool check2 = isinbounds(off2, size) && !isnan(s2.z); + bool check3 = isinbounds(off3, size) && !isnan(s3.z); + bool check4 = isinbounds(off4, size) && !isnan(s4.z); + if (check1 && check2) result += cross(s2-s0, s1-s0); + if (check2 && check3) result += cross(s3-s0, s2-s0); + if (check3 && check4) result += cross(s4-s0, s3-s0); + if (check4 && check1) result += cross(s1-s0, s4-s0); + } + // normal should be zero, but needs to be here, because the dead-code + // elimanation of GLSL is overly enthusiastic + return normalize(result); +} + +// Overload for surface(Matrix, Matrix, Matrix) +vec3 getnormal(Nothing pos, sampler2D xs, sampler2D ys, sampler2D zs, ivec2 uv){ + vec3 s0, s1, s2, s3, s4; + ivec2 off1 = uv + ivec2(-1, 0); + ivec2 off2 = uv + ivec2(0, 1); + ivec2 off3 = uv + ivec2(1, 0); + ivec2 off4 = uv + ivec2(0, -1); + + s0 = vec3(texelFetch(xs, uv, 0).x, texelFetch(ys, uv, 0).x, texelFetch(zs, uv, 0).x); + s1 = vec3(texelFetch(xs, off1, 0).x, texelFetch(ys, off1, 0).x, texelFetch(zs, off1, 0).x); + s2 = vec3(texelFetch(xs, off2, 0).x, texelFetch(ys, off2, 0).x, texelFetch(zs, off2, 0).x); + s3 = vec3(texelFetch(xs, off3, 0).x, texelFetch(ys, off3, 0).x, texelFetch(zs, off3, 0).x); + s4 = vec3(texelFetch(xs, off4, 0).x, texelFetch(ys, off4, 0).x, texelFetch(zs, off4, 0).x); + + return normal_from_points(s0, s1, s2, s3, s4, off1, off2, off3, off4, textureSize(zs, 0)); +} + + +// Overload for (range, range, Matrix) surface plots +// Though this is only called by surface(Matrix) +vec2 grid_pos(Grid2D position, ivec2 uv, ivec2 size); + +vec3 getnormal(Grid2D pos, Nothing xs, Nothing ys, sampler2D zs, ivec2 uv){ + vec3 s0, s1, s2, s3, s4; + ivec2 off1 = uv + ivec2(-1, 0); + ivec2 off2 = uv + ivec2(0, 1); + ivec2 off3 = uv + ivec2(1, 0); + ivec2 off4 = uv + ivec2(0, -1); + ivec2 size = textureSize(zs, 0); + + s0 = vec3(grid_pos(pos, uv, size).xy, texelFetch(zs, uv, 0).x); + s1 = vec3(grid_pos(pos, off1, size).xy, texelFetch(zs, off1, 0).x); + s2 = vec3(grid_pos(pos, off2, size).xy, texelFetch(zs, off2, 0).x); + s3 = vec3(grid_pos(pos, off3, size).xy, texelFetch(zs, off3, 0).x); + s4 = vec3(grid_pos(pos, off4, size).xy, texelFetch(zs, off4, 0).x); + + return normal_from_points(s0, s1, s2, s3, s4, off1, off2, off3, off4, size); +} + + +// Overload for surface(Vector, Vector, Matrix) +// Makie converts almost everything to this +vec3 getnormal(Nothing pos, sampler1D xs, sampler1D ys, sampler2D zs, ivec2 uv){ + vec3 s0, s1, s2, s3, s4; + ivec2 off1 = uv + ivec2(-1, 0); + ivec2 off2 = uv + ivec2(0, 1); + ivec2 off3 = uv + ivec2(1, 0); + ivec2 off4 = uv + ivec2(0, -1); + + s0 = vec3(texelFetch(xs, uv.x, 0).x, texelFetch(ys, uv.y, 0).x, texelFetch(zs, uv, 0).x); + s1 = vec3(texelFetch(xs, off1.x, 0).x, texelFetch(ys, off1.y, 0).x, texelFetch(zs, off1, 0).x); + s2 = vec3(texelFetch(xs, off2.x, 0).x, texelFetch(ys, off2.y, 0).x, texelFetch(zs, off2, 0).x); + s3 = vec3(texelFetch(xs, off3.x, 0).x, texelFetch(ys, off3.y, 0).x, texelFetch(zs, off3, 0).x); + s4 = vec3(texelFetch(xs, off4.x, 0).x, texelFetch(ys, off4.y, 0).x, texelFetch(zs, off4, 0).x); + + return normal_from_points(s0, s1, s2, s3, s4, off1, off2, off3, off4, textureSize(zs, 0)); +} uniform uint objectid; uniform vec2 uv_scale; @@ -71,5 +170,5 @@ void main() if (isnan(pos.z)) { pos.z = 0.0; } - render(model * vec4(pos, 1), normalvec, view, projection, lightposition); + render(model * vec4(pos, 1), normalvec, view, projection); } diff --git a/GLMakie/assets/shader/util.vert b/GLMakie/assets/shader/util.vert index 5d3863deff8..afb2c379945 100644 --- a/GLMakie/assets/shader/util.vert +++ b/GLMakie/assets/shader/util.vert @@ -1,5 +1,12 @@ {{GLSL_VERSION}} +// Sets which shading procedures to use +// Options: +// NO_SHADING - skip shading calculation, handled outside +// FAST_SHADING - single point light (forward rendering) +// MULTI_LIGHT_SHADING - simple shading with multiple lights (forward rendering) +{{shading}} + struct Nothing{ //Nothing type, to encode if some variable doesn't contain any data bool _; //empty structs are not allowed }; @@ -29,6 +36,12 @@ vec2 grid_pos(Grid2D position, vec2 uv){ ); } +vec2 grid_pos(Grid2D position, ivec2 uv, ivec2 size){ + return vec2( + (1.0 - (uv.x + 0.5) / size.x) * position.start[0] + (uv.x + 0.5) / size.x * position.stop[0], + (1.0 - (uv.y + 0.5) / size.y) * position.start[1] + (uv.y + 0.5) / size.y * position.stop[1] + ); +} // stretch is vec3 stretch(vec3 val, vec3 from, vec3 to){ @@ -117,25 +130,25 @@ uniform vec4 lowclip; uniform vec4 nan_color; vec4 get_color_from_cmap(float value, sampler1D color_map, vec2 colorrange) { -float cmin = colorrange.x; -float cmax = colorrange.y; -if (value <= cmax && value >= cmin) { - // in value range, continue! -} else if (value < cmin) { -return lowclip; -} else if (value > cmax) { -return highclip; -} else { - // isnan CAN be broken (of course) -.- - // so if outside value range and not smaller/bigger min/max we assume NaN -return nan_color; -} -float i01 = clamp((value - cmin) / (cmax - cmin), 0.0, 1.0); - // 1/0 corresponds to the corner of the colormap, so to properly interpolate - // between the colors, we need to scale it, so that the ends are at 1 - (stepsize/2) and 0+(stepsize/2). -float stepsize = 1.0 / float(textureSize(color_map, 0)); -i01 = (1.0 - stepsize) * i01 + 0.5 * stepsize; -return texture(color_map, i01); + float cmin = colorrange.x; + float cmax = colorrange.y; + if (value <= cmax && value >= cmin) { + // in value range, continue! + } else if (value < cmin) { + return lowclip; + } else if (value > cmax) { + return highclip; + } else { + // isnan CAN be broken (of course) -.- + // so if outside value range and not smaller/bigger min/max we assume NaN + return nan_color; + } + float i01 = clamp((value - cmin) / (cmax - cmin), 0.0, 1.0); + // 1/0 corresponds to the corner of the colormap, so to properly interpolate + // between the colors, we need to scale it, so that the ends are at 1 - (stepsize/2) and 0+(stepsize/2). + float stepsize = 1.0 / float(textureSize(color_map, 0)); + i01 = (1.0 - stepsize) * i01 + 0.5 * stepsize; + return texture(color_map, i01); } @@ -235,150 +248,47 @@ vec4 _color(Nothing color, float intensity, sampler1D color_map, vec2 color_norm return get_color_from_cmap(intensity, color_map, color_norm); } -out vec3 o_view_pos; -out vec3 o_normal; -out vec3 o_lightdir; -out vec3 o_camdir; + +uniform float depth_shift; + +// TODO maybe ifdef SSAO this stuff? // transpose(inv(view * model)) // Transformation for vectors (rather than points) -uniform mat3 normalmatrix; -uniform vec3 lightposition; +uniform mat3 view_normalmatrix; +out vec3 o_view_pos; +out vec3 o_view_normal; + + +#if defined(FAST_SHADING) || defined(MULTI_LIGHT_SHADING) +// transpose(inv(model)) +uniform mat3 world_normalmatrix; uniform vec3 eyeposition; -uniform float depth_shift; +out vec3 o_world_pos; +out vec3 o_world_normal; +out vec3 o_camdir; +#endif -void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection, vec3 lightposition) +void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection) { - // normal in world space - o_normal = normalmatrix * normal; // position in view space (as seen from camera) vec4 view_pos = view * position_world; + view_pos /= view_pos.w; + // position in clip space (w/ depth) gl_Position = projection * view_pos; gl_Position.z += gl_Position.w * depth_shift; - // direction to light - o_lightdir = normalize(view*vec4(lightposition, 1.0) - view_pos).xyz; - // direction to camera - // This is equivalent to - // normalize(view*vec4(eyeposition, 1.0) - view_pos).xyz - // (by definition `view * eyeposition = 0`) - o_camdir = normalize(-view_pos).xyz; - o_view_pos = view_pos.xyz / view_pos.w; -} -// -vec3 getnormal_fast(sampler2D zvalues, ivec2 uv) -{ - vec3 a = vec3(0, 0, 0); - vec3 b = vec3(1, 1, 0); - a.z = texelFetch(zvalues, uv, 0).r; - b.z = texelFetch(zvalues, uv + ivec2(1, 1), 0).r; - return normalize(a - b); -} + // for lighting +#if defined(FAST_SHADING) || defined(MULTI_LIGHT_SHADING) + o_world_pos = position_world.xyz / position_world.w; + o_world_normal = world_normalmatrix * normal; + // direction from camera to vertex + o_camdir = position_world.xyz / position_world.w - eyeposition; +#endif -bool isinbounds(vec2 uv) -{ - return (uv.x <= 1.0 && uv.y <= 1.0 && uv.x >= 0.0 && uv.y >= 0.0); -} - - -/* -Computes normal at s0 based on four surrounding positions s1 ... s4 and the -respective uv coordinates uv, off1, ..., off4 - - s2 - s1 s0 s3 - s4 -*/ -vec3 normal_from_points( - vec3 s0, vec3 s1, vec3 s2, vec3 s3, vec3 s4, - vec2 uv, vec2 off1, vec2 off2, vec2 off3, vec2 off4 - ){ - vec3 result = vec3(0); - if(isinbounds(off1) && isinbounds(off2)) - { - result += cross(s2-s0, s1-s0); - } - if(isinbounds(off2) && isinbounds(off3)) - { - result += cross(s3-s0, s2-s0); - } - if(isinbounds(off3) && isinbounds(off4)) - { - result += cross(s4-s0, s3-s0); - } - if(isinbounds(off4) && isinbounds(off1)) - { - result += cross(s1-s0, s4-s0); - } - // normal should be zero, but needs to be here, because the dead-code - // elimanation of GLSL is overly enthusiastic - return normalize(result); -} - -// Overload for surface(Matrix, Matrix, Matrix) -vec3 getnormal(Nothing pos, sampler2D xs, sampler2D ys, sampler2D zs, vec2 uv){ - // The +1e-6 fixes precision errors at the edge - float du = 1.0 / textureSize(zs,0).x + 1e-6; - float dv = 1.0 / textureSize(zs,0).y + 1e-6; - - vec3 s0, s1, s2, s3, s4; - vec2 off1 = uv + vec2(-du, 0); - vec2 off2 = uv + vec2(0, dv); - vec2 off3 = uv + vec2(du, 0); - vec2 off4 = uv + vec2(0, -dv); - - s0 = vec3(texture(xs, uv).x, texture(ys, uv).x, texture(zs, uv).x); - s1 = vec3(texture(xs, off1).x, texture(ys, off1).x, texture(zs, off1).x); - s2 = vec3(texture(xs, off2).x, texture(ys, off2).x, texture(zs, off2).x); - s3 = vec3(texture(xs, off3).x, texture(ys, off3).x, texture(zs, off3).x); - s4 = vec3(texture(xs, off4).x, texture(ys, off4).x, texture(zs, off4).x); - - return normal_from_points(s0, s1, s2, s3, s4, uv, off1, off2, off3, off4); -} - - -// Overload for (range, range, Matrix) surface plots -// Though this is only called by surface(Matrix) -vec3 getnormal(Grid2D pos, Nothing xs, Nothing ys, sampler2D zs, vec2 uv){ - // The +1e-6 fixes precision errors at the edge - float du = 1.0 / textureSize(zs,0).x + 1e-6; - float dv = 1.0 / textureSize(zs,0).y + 1e-6; - - vec3 s0, s1, s2, s3, s4; - vec2 off1 = uv + vec2(-du, 0); - vec2 off2 = uv + vec2(0, dv); - vec2 off3 = uv + vec2(du, 0); - vec2 off4 = uv + vec2(0, -dv); - - s0 = vec3(grid_pos(pos, uv).xy, texture(zs, uv).x); - s1 = vec3(grid_pos(pos, off1).xy, texture(zs, off1).x); - s2 = vec3(grid_pos(pos, off2).xy, texture(zs, off2).x); - s3 = vec3(grid_pos(pos, off3).xy, texture(zs, off3).x); - s4 = vec3(grid_pos(pos, off4).xy, texture(zs, off4).x); - - return normal_from_points(s0, s1, s2, s3, s4, uv, off1, off2, off3, off4); -} - - -// Overload for surface(Vector, Vector, Matrix) -// Makie converts almost everything to this -vec3 getnormal(Nothing pos, sampler1D xs, sampler1D ys, sampler2D zs, vec2 uv){ - // The +1e-6 fixes precision errors at the edge - float du = 1.0 / textureSize(zs,0).x + 1e-6; - float dv = 1.0 / textureSize(zs,0).y + 1e-6; - - vec3 s0, s1, s2, s3, s4; - vec2 off1 = uv + vec2(-du, 0); - vec2 off2 = uv + vec2(0, dv); - vec2 off3 = uv + vec2(du, 0); - vec2 off4 = uv + vec2(0, -dv); - - s0 = vec3(texture(xs, uv.x).x, texture(ys, uv.y).x, texture(zs, uv).x); - s1 = vec3(texture(xs, off1.x).x, texture(ys, off1.y).x, texture(zs, off1).x); - s2 = vec3(texture(xs, off2.x).x, texture(ys, off2.y).x, texture(zs, off2).x); - s3 = vec3(texture(xs, off3.x).x, texture(ys, off3.y).x, texture(zs, off3).x); - s4 = vec3(texture(xs, off4.x).x, texture(ys, off4.y).x, texture(zs, off4).x); - - return normal_from_points(s0, s1, s2, s3, s4, uv, off1, off2, off3, off4); + // for SSAO + o_view_pos = view_pos.xyz / view_pos.w; + // SSAO + matcap + o_view_normal = view_normalmatrix * normal; } diff --git a/GLMakie/assets/shader/volume.frag b/GLMakie/assets/shader/volume.frag index 4fdcadf3d25..1e4eef28b6d 100644 --- a/GLMakie/assets/shader/volume.frag +++ b/GLMakie/assets/shader/volume.frag @@ -1,10 +1,16 @@ {{GLSL_VERSION}} +// Sets which shading procedures to use +// Options: +// NO_SHADING - skip shading calculation, handled outside +// FAST_SHADING - single point light (forward rendering) +// MULTI_LIGHT_SHADING - simple shading with multiple lights (forward rendering) +{{shading}} + struct Nothing{ //Nothing type, to encode if some variable doesn't contain any data bool _; //empty structs are not allowed }; in vec3 frag_vert; -in vec3 o_light_dir; {{volumedata_type}} volumedata; @@ -15,11 +21,6 @@ in vec3 o_light_dir; uniform float absorption = 1.0; uniform vec3 eyeposition; -uniform vec3 ambient; -uniform vec3 diffuse; -uniform vec3 specular; -uniform float shininess; - uniform mat4 modelinv; uniform int algorithm; uniform float isovalue; @@ -72,9 +73,17 @@ vec4 color_lookup(Nothing colormap, int index) return vec4(0); } -vec3 gennormal(vec3 uvw, float d) +vec3 gennormal(vec3 uvw, float d, vec3 o) { + // uvw samples positions (0..1 values) + // d is the sampling step. Could be any small value here + // o is half the uvw distance between two voxels. A distance smaller than + // that will result in equal positions when sampling on the edge of the + // volume, generating broken normals. vec3 a, b; + + float eps = 0.001; + // handle normals at edges! if(uvw.x + d >= 1.0){ return vec3(1, 0, 0); @@ -96,32 +105,33 @@ vec3 gennormal(vec3 uvw, float d) return vec3(0, 0, -1); } - a.x = texture(volumedata, uvw - vec3(d,0.0,0.0)).r; - b.x = texture(volumedata, uvw + vec3(d,0.0,0.0)).r; + a.x = texture(volumedata, uvw - vec3(o.x, 0.0, 0.0)).r; + b.x = texture(volumedata, uvw + vec3(o.x, 0.0, 0.0)).r; - a.y = texture(volumedata, uvw - vec3(0.0,d,0.0)).r; - b.y = texture(volumedata, uvw + vec3(0.0,d,0.0)).r; + a.y = texture(volumedata, uvw - vec3(0.0, o.y, 0.0)).r; + b.y = texture(volumedata, uvw + vec3(0.0, o.y, 0.0)).r; - a.z = texture(volumedata, uvw - vec3(0.0,0.0,d)).r; - b.z = texture(volumedata, uvw + vec3(0.0,0.0,d)).r; - return normalize(a-b); + a.z = texture(volumedata, uvw - vec3(0.0, 0.0, o.z)).r; + b.z = texture(volumedata, uvw + vec3(0.0, 0.0, o.z)).r; + + vec3 diff = a - b; + float n = length(diff); + + if (n < 0.000000000001) // 1e-12 + return diff; + + return diff / n; } -// Includes front and back-facing normals (N, -N) -vec3 blinnphong(vec3 N, vec3 V, vec3 L, vec3 color){ - float diff_coeff = max(dot(L, N), 0.0) + max(dot(L, -N), 0.0); - // specular coefficient - vec3 H = normalize(L + V); - float spec_coeff = pow(max(dot(H, N), 0.0) + max(dot(H, -N), 0.0), shininess); - if (diff_coeff <= 0.0 || isnan(spec_coeff)) - spec_coeff = 0.0; - // final lighting model - return vec3( - ambient * color + - diffuse * diff_coeff * color + - specular * spec_coeff - ); +#ifndef NO_SHADING +vec3 illuminate(vec3 world_pos, vec3 camdir, vec3 normal, vec3 base_color); +#endif + +#ifdef NO_SHADING +vec3 illuminate(vec3 world_pos, vec3 camdir, vec3 normal, vec3 base_color) { + return normal; } +#endif // Simple random generator found: http://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl float rand(){ @@ -208,7 +218,8 @@ vec4 contours(vec3 front, vec3 dir) float T = 1.0; vec3 Lo = vec3(0.0); int i = 0; - vec3 camdir = normalize(-dir); + vec3 camdir = normalize(dir); + vec3 edge_gap = 0.5 / textureSize(volumedata, 0); // see gennormal {{depth_init}} // may write: float depth = 100000.0; for (i; i < num_samples; ++i) { @@ -220,9 +231,9 @@ vec4 contours(vec3 front, vec3 dir) // may write // vec4 frag_coord = projectionview * model * vec4(pos, 1); // depth = min(depth, frag_coord.z / frag_coord.w); - vec3 N = gennormal(pos, step_size); - vec3 L = normalize(o_light_dir - pos); - vec3 opaque = blinnphong(N, camdir, L, density.rgb); + vec3 N = gennormal(pos, step_size, edge_gap); + vec4 world_pos = model * vec4(pos, 1); + vec3 opaque = illuminate(world_pos.xyz / world_pos.w, camdir, N, density.rgb); Lo += (T * opacity) * opaque; T *= 1.0 - opacity; if (T <= 0.01) @@ -242,7 +253,8 @@ vec4 isosurface(vec3 front, vec3 dir) vec4 c = vec4(0.0); int i = 0; vec4 diffuse_color = color_lookup(isovalue, color_map, color_norm, color); - vec3 camdir = normalize(-dir); + vec3 camdir = normalize(dir); + vec3 edge_gap = 0.5 / textureSize(volumedata, 0); // see gennormal {{depth_init}} // may write: float depth = 100000.0; for (i; i < num_samples; ++i){ @@ -252,10 +264,10 @@ vec4 isosurface(vec3 front, vec3 dir) // may write: // vec4 frag_coord = projectionview * model * vec4(pos, 1); // depth = min(depth, frag_coord.z / frag_coord.w); - vec3 N = gennormal(pos, step_size); - vec3 L = normalize(o_light_dir - pos); + vec3 N = gennormal(pos, step_size, edge_gap); + vec4 world_pos = model * vec4(pos, 1); c = vec4( - blinnphong(N, camdir, L, diffuse_color.rgb), + illuminate(world_pos.xyz / world_pos.w, camdir, N, diffuse_color.rgb), diffuse_color.a ); break; diff --git a/GLMakie/assets/shader/volume.vert b/GLMakie/assets/shader/volume.vert index 72c60a336c8..2ca396b5763 100644 --- a/GLMakie/assets/shader/volume.vert +++ b/GLMakie/assets/shader/volume.vert @@ -3,24 +3,26 @@ in vec3 vertices; out vec3 frag_vert; -out vec3 o_light_dir; uniform mat4 projectionview, model; -uniform vec3 lightposition; uniform mat4 modelinv; uniform float depth_shift; +// SSAO out vec3 o_view_pos; -out vec3 o_normal; +out vec3 o_view_normal; + +// Lighting (unused and don't need to be available?) +// out vec3 o_world_pos; +// out vec3 o_world_normal; void main() { // TODO set these in volume.frag o_view_pos = vec3(0); - o_normal = vec3(0); + o_view_normal = vec3(0); vec4 world_vert = model * vec4(vertices, 1); frag_vert = world_vert.xyz; - o_light_dir = vec3(modelinv * vec4(lightposition, 1)); gl_Position = projectionview * world_vert; gl_Position.z += gl_Position.w * depth_shift; } diff --git a/GLMakie/src/GLAbstraction/AbstractGPUArray.jl b/GLMakie/src/GLAbstraction/AbstractGPUArray.jl index 48da57bfc8a..17b39705e4f 100644 --- a/GLMakie/src/GLAbstraction/AbstractGPUArray.jl +++ b/GLMakie/src/GLAbstraction/AbstractGPUArray.jl @@ -193,12 +193,11 @@ max_dim(t) = error("max_dim not implemented for: $(typeof(t)). This happen function (::Type{GPUArrayType})(data::Observable; kw...) where GPUArrayType <: GPUArray gpu_mem = GPUArrayType(data[]; kw...) # TODO merge these and handle update tracking during contruction - obs1 = on(_-> gpu_mem.requires_update[] = true, data) obs2 = on(new_data -> update!(gpu_mem, new_data), data) if GPUArrayType <: TextureBuffer - push!(gpu_mem.buffer.observers, obs1, obs2) + push!(gpu_mem.buffer.observers, obs2) else - push!(gpu_mem.observers, obs1, obs2) + push!(gpu_mem.observers, obs2) end return gpu_mem end diff --git a/GLMakie/src/GLAbstraction/GLBuffer.jl b/GLMakie/src/GLAbstraction/GLBuffer.jl index 6f123ade0e4..a19d789af23 100644 --- a/GLMakie/src/GLAbstraction/GLBuffer.jl +++ b/GLMakie/src/GLAbstraction/GLBuffer.jl @@ -5,7 +5,6 @@ mutable struct GLBuffer{T} <: GPUArray{T, 1} usage::GLenum context::GLContext # TODO maybe also delay upload to when render happens? - requires_update::Observable{Bool} observers::Vector{Observables.ObserverFunction} function GLBuffer{T}(ptr::Ptr{T}, buff_length::Int, buffertype::GLenum, usage::GLenum) where T @@ -18,8 +17,7 @@ mutable struct GLBuffer{T} <: GPUArray{T, 1} obj = new( id, (buff_length,), buffertype, usage, current_context(), - Observable(true), Observables.ObserverFunction[]) - + Observables.ObserverFunction[]) finalizer(free, obj) obj end @@ -68,7 +66,6 @@ function GLBuffer( au = ShaderAbstractions.updater(buffer) obsfunc = on(au.update) do (f, args) f(b, args...) # forward setindex! etc - b.requires_update[] = true return end push!(b.observers, obsfunc) diff --git a/GLMakie/src/GLAbstraction/GLRender.jl b/GLMakie/src/GLAbstraction/GLRender.jl index e48d3a11c3a..d6eb089f410 100644 --- a/GLMakie/src/GLAbstraction/GLRender.jl +++ b/GLMakie/src/GLAbstraction/GLRender.jl @@ -55,8 +55,6 @@ So rewriting this function could get us a lot of performance for scenes with a lot of objects. """ function render(renderobject::RenderObject, vertexarray=renderobject.vertexarray) - renderobject.requires_update = false - if renderobject.visible renderobject.prerenderfunction() program = vertexarray.program diff --git a/GLMakie/src/GLAbstraction/GLShader.jl b/GLMakie/src/GLAbstraction/GLShader.jl index edbc7efff8c..bddc6e61302 100644 --- a/GLMakie/src/GLAbstraction/GLShader.jl +++ b/GLMakie/src/GLAbstraction/GLShader.jl @@ -249,7 +249,7 @@ function gl_convert(cache::ShaderCache, lazyshader::AbstractLazyShader, data) template_keys[i] = template replacements[i] = String[mustache2replacement(t, v, data) for t in template] end - program = get!(cache.program_cache, (paths, replacements)) do + return get!(cache.program_cache, (paths, replacements)) do # when we're here, this means there were uncached shaders, meaning we definitely have # to compile a new program shaders = Vector{Shader}(undef, length(paths)) diff --git a/GLMakie/src/GLAbstraction/GLTexture.jl b/GLMakie/src/GLAbstraction/GLTexture.jl index 488a56fa0d5..c9d44b8595a 100644 --- a/GLMakie/src/GLAbstraction/GLTexture.jl +++ b/GLMakie/src/GLAbstraction/GLTexture.jl @@ -17,7 +17,6 @@ mutable struct Texture{T <: GLArrayEltypes, NDIM} <: OpenglTexture{T, NDIM} parameters ::TextureParameters{NDIM} size ::NTuple{NDIM, Int} context ::GLContext - requires_update ::Observable{Bool} observers ::Vector{Observables.ObserverFunction} function Texture{T, NDIM}( id ::GLuint, @@ -37,7 +36,6 @@ mutable struct Texture{T <: GLArrayEltypes, NDIM} <: OpenglTexture{T, NDIM} parameters, size, current_context(), - Observable(true), Observables.ObserverFunction[] ) finalizer(free, tex) @@ -49,11 +47,8 @@ end mutable struct TextureBuffer{T <: GLArrayEltypes} <: OpenglTexture{T, 1} texture::Texture{T, 1} buffer::GLBuffer{T} - requires_update::Observable{Bool} - function TextureBuffer(texture::Texture{T, 1}, buffer::GLBuffer{T}) where T - x = map((_, _) -> true, buffer.requires_update, texture.requires_update) - new{T}(texture, buffer, x) + new{T}(texture, buffer) end end Base.size(t::TextureBuffer) = size(t.buffer) @@ -72,7 +67,6 @@ ShaderAbstractions.switch_context!(t::TextureBuffer) = switch_context!(t.texture function unsafe_free(tb::TextureBuffer) unsafe_free(tb.texture) unsafe_free(tb.buffer) - Observables.clear(tb.requires_update) end is_texturearray(t::Texture) = t.texturetype == GL_TEXTURE_2D_ARRAY @@ -148,8 +142,7 @@ function Texture(s::ShaderAbstractions.Sampler{T, N}; kwargs...) where {T, N} anisotropic = s.anisotropic; mipmap = s.anisotropic != 1f0, kwargs... ) obsfunc = ShaderAbstractions.connect!(s, tex) - obsfunc2 = on(x -> tex.requires_update[] = true, s.updates.update) - push!(tex.observers, obsfunc, obsfunc2) + push!(tex.observers, obsfunc) return tex end diff --git a/GLMakie/src/GLAbstraction/GLTypes.jl b/GLMakie/src/GLAbstraction/GLTypes.jl index 6e7a68f9c2a..19d7123e4fa 100644 --- a/GLMakie/src/GLAbstraction/GLTypes.jl +++ b/GLMakie/src/GLAbstraction/GLTypes.jl @@ -174,21 +174,8 @@ mutable struct GLVertexArray{T} buffers::Dict{String,GLBuffer} indices::T context::GLContext - requires_update::Observable{Bool} - function GLVertexArray{T}(program, id, bufferlength, buffers, indices) where T - va = new(program, id, bufferlength, buffers, indices, current_context(), true) - if indices isa GLBuffer - on(indices.requires_update) do _ # only triggers true anyway - va.requires_update[] = true - end - end - for (name, buffer) in buffers - on(buffer.requires_update) do _ # only triggers true anyway - va.requires_update[] = true - end - end - + va = new(program, id, bufferlength, buffers, indices, current_context()) return va end end @@ -318,7 +305,6 @@ mutable struct RenderObject{Pre} prerenderfunction::Pre postrenderfunction id::UInt32 - requires_update::Bool visible::Bool function RenderObject{Pre}( @@ -326,7 +312,7 @@ mutable struct RenderObject{Pre} uniforms::Dict{Symbol,Any}, observables::Vector{Observable}, vertexarray::GLVertexArray, prerenderfunctions, postrenderfunctions, - visible, track_updates = true + visible ) where Pre fxaa = Bool(to_value(get!(uniforms, :fxaa, true))) RENDER_OBJECT_ID_COUNTER[] += one(UInt32) @@ -340,57 +326,13 @@ mutable struct RenderObject{Pre} context, uniforms, observables, vertexarray, prerenderfunctions, postrenderfunctions, - id, true, visible[] + id, visible[] ) - - if track_updates - # visible changes should always trigger updates so that plots - # actually become invisible when visible is changed. - # Other uniforms and buffers don't need to trigger updates when - # visible = false - on(visible) do visible - robj.visible = visible - robj.requires_update = true - end - - function request_update(_::Any) - if robj.visible - robj.requires_update = true - end - return - end - - # gather update requests for polling in renderloop - for uniform in values(uniforms) - if uniform isa Observable - on(request_update, uniform) - elseif uniform isa GPUArray - on(request_update, uniform.requires_update) - end - end - on(request_update, vertexarray.requires_update) - else - on(visible) do visible - robj.visible = visible - end - - # remove tracking from GPUArrays - for uniform in values(uniforms) - if uniform isa GPUArray - foreach(off, uniform.requires_update.inputs) - empty!(uniform.requires_update.inputs) - end - end - for buffer in vertexarray.buffers - if buffer isa GPUArray - foreach(off, buffer.requires_update.inputs) - empty!(buffer.requires_update.inputs) - end - end - foreach(off, vertexarray.requires_update.inputs) - empty!(vertexarray.requires_update.inputs) + push!(observables, visible) + on(visible) do visible + robj.visible = visible + return end - return robj end end @@ -474,8 +416,7 @@ function RenderObject( vertexarray, pre, post, - visible, - track_updates + visible ) # automatically integrate object ID, will be discarded if shader doesn't use it @@ -502,7 +443,6 @@ function clean_up_observables(x::T) where T foreach(off, x.observers) empty!(x.observers) end - Observables.clear(x.requires_update) end # OpenGL has the annoying habit of reusing id's when creating a new context diff --git a/GLMakie/src/GLAbstraction/GLUniforms.jl b/GLMakie/src/GLAbstraction/GLUniforms.jl index a88ad9a9f97..a51af4024bc 100644 --- a/GLMakie/src/GLAbstraction/GLUniforms.jl +++ b/GLMakie/src/GLAbstraction/GLUniforms.jl @@ -241,6 +241,7 @@ gl_convert(x::Mat{N, M, T}) where {N, M, T} = map(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) +gl_convert(x::Vector) = x function gl_convert(T::Type{<: GPUArray}, a::AbstractArray{X, N}; kw_args...) where {X, N} T(convert(AbstractArray{gl_promote(X), N}, a); kw_args...) @@ -261,16 +262,4 @@ function gl_convert(::Type{T}, a::Observable{<: AbstractArray{X, N}}; kw_args... T(s; kw_args...) end -lift_convert(a::AbstractArray, T, N) = lift(x -> convert(Array{T, N}, x), a) -function lift_convert(a::ShaderAbstractions.Sampler, T, N) - ShaderAbstractions.Sampler( - lift(x -> convert(Array{T, N}, x.data), a), - minfilter = a[].minfilter, magfilter = a[].magfilter, - x_repeat = a[].repeat[1], - y_repeat = a[].repeat[min(2, N)], - z_repeat = a[].repeat[min(3, N)], - anisotropic = a[].anisotropic, swizzle_mask = a[].swizzle_mask - ) -end - gl_convert(f::Function, a) = f(a) diff --git a/GLMakie/src/GLMakie.jl b/GLMakie/src/GLMakie.jl index 91a2b127204..5af488594da 100644 --- a/GLMakie/src/GLMakie.jl +++ b/GLMakie/src/GLMakie.jl @@ -43,7 +43,16 @@ export Sampler, Buffer const GL_ASSET_DIR = RelocatableFolders.@path joinpath(@__DIR__, "..", "assets") const SHADER_DIR = RelocatableFolders.@path joinpath(GL_ASSET_DIR, "shader") -loadshader(name) = joinpath(SHADER_DIR, name) +const LOADED_SHADERS = Dict{String, String}() + +function loadshader(name) + # Turns out, joinpath is so slow, that it actually makes sense + # To memoize it :-O + # when creating 1000 plots with the PlotSpec API, timing drop from 1.5s to 1s just from this change: + return get!(LOADED_SHADERS, name) do + return joinpath(SHADER_DIR, name) + end +end gl_texture_atlas() = Makie.get_texture_atlas(2048, 64) @@ -54,8 +63,6 @@ function __init__() activate!() end -Base.@deprecate set_window_config!(; screen_config...) GLMakie.activate!(; screen_config...) - include("precompiles.jl") end diff --git a/GLMakie/src/display.jl b/GLMakie/src/display.jl index c8d0aef1f72..5135fa1f1b5 100644 --- a/GLMakie/src/display.jl +++ b/GLMakie/src/display.jl @@ -10,4 +10,4 @@ function Base.display(screen::Screen, scene::Scene; connect=true) return screen end -Makie.backend_showable(::Type{Screen}, ::Union{MIME"image/jpeg", MIME"image/png"}) = true +Makie.backend_showable(::Type{Screen}, ::Union{MIME"image/jpeg", MIME"image/png", Makie.WEB_MIMES...}) = true diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index 5e048f45c48..9fa55f52b8e 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -2,6 +2,107 @@ using Makie: transform_func_obs, apply_transform using Makie: attribute_per_char, FastPixel, el32convert, Pixel using Makie: convert_arguments +function handle_lights(attr::Dict, screen::Screen, lights::Vector{Makie.AbstractLight}) + @inline function push_inplace!(trg, idx, src) + for i in eachindex(src) + trg[idx + i] = src[i] + end + return idx + length(src) + end + + MAX_LIGHTS = screen.config.max_lights + MAX_PARAMS = screen.config.max_light_parameters + + # Every light has a type and a color. Therefore we have these as independent + # uniforms with a max length of MAX_LIGHTS. + # Other parameters like position, direction, etc differe between light types. + # To avoid wasting a bunch of memory we squash all of them into one vector of + # size MAX_PARAMS. + attr[:N_lights] = Observable(0) + attr[:light_types] = Observable(sizehint!(Int32[], MAX_LIGHTS)) + attr[:light_colors] = Observable(sizehint!(RGBf[], MAX_LIGHTS)) + attr[:light_parameters] = Observable(sizehint!(Float32[], MAX_PARAMS)) + + on(screen.render_tick, priority = typemin(Int)) do _ + # derive number of lights from available lights. Both MAX_LIGHTS and + # MAX_PARAMS are considered for this. + n_lights = 0 + n_params = 0 + for light in lights + delta = 0 + if light isa PointLight + delta = 5 # 3 position + 2 attenuation + elseif light isa DirectionalLight + delta = 3 # 3 direction + elseif light isa SpotLight + delta = 8 # 3 position + 3 direction + 2 angles + elseif light isa RectLight + delta = 12 # 3 position + 2x 3 rect basis vectors + 3 direction + end + if n_params + delta > MAX_PARAMS || n_lights == MAX_LIGHTS + if n_params > MAX_PARAMS + @warn "Exceeded the maximum number of light parameters ($n_params > $MAX_PARAMS). Skipping lights beyond number $n_lights." + else + @warn "Exceeded the maximum number of lights ($n_lights > $MAX_LIGHTS). Skipping lights beyond number $n_lights." + end + break + end + n_params += delta + n_lights += 1 + end + + # Update number of lights + attr[:N_lights][] = n_lights + + # Update light types + trg = attr[:light_types][] + resize!(trg, n_lights) + map!(i -> Makie.light_type(lights[i]), trg, 1:n_lights) + notify(attr[:light_types]) + + # Update light colors + trg = attr[:light_colors][] + resize!(trg, n_lights) + map!(i -> Makie.light_color(lights[i]), trg, 1:n_lights) + notify(attr[:light_colors]) + + # Update other light parameters + # This precalculates world space pos/dir -> view/cam space pos/dir + parameters = attr[:light_parameters][] + resize!(parameters, n_params) + idx = 0 + for i in 1:n_lights + light = lights[i] + if light isa PointLight + idx = push_inplace!(parameters, idx, light.position[]) + idx = push_inplace!(parameters, idx, light.attenuation[]) + elseif light isa DirectionalLight + if light.camera_relative + T = inv(attr[:view][][Vec(1,2,3), Vec(1,2,3)]) + dir = normalize(T * light.direction[]) + else + dir = normalize(light.direction[]) + end + idx = push_inplace!(parameters, idx, dir) + elseif light isa SpotLight + idx = push_inplace!(parameters, idx, light.position[]) + idx = push_inplace!(parameters, idx, normalize(light.direction[])) + idx = push_inplace!(parameters, idx, cos.(light.angles[])) + elseif light isa RectLight + idx = push_inplace!(parameters, idx, light.position[]) + idx = push_inplace!(parameters, idx, light.u1[]) + idx = push_inplace!(parameters, idx, light.u2[]) + idx = push_inplace!(parameters, idx, normalize(light.direction[])) + end + end + notify(attr[:light_parameters]) + + return Consume(false) + end + + return attr +end + Makie.el32convert(x::GLAbstraction.Texture) = x gpuvec(x) = GPUVector(GLBuffer(x)) @@ -37,31 +138,51 @@ function to_glvisualize_key(k) end function connect_camera!(plot, gl_attributes, cam, space = gl_attributes[:space]) - for key in (:pixel_space, :resolution, :eyeposition) + for key in (:pixel_space, :eyeposition) # Overwrite these, user defined attributes shouldn't use those! gl_attributes[key] = lift(identity, plot, getfield(cam, key)) end get!(gl_attributes, :view) do - return lift(plot, cam.view, space) do view, space - return is_data_space(space) ? view : Mat4f(I) + # 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 + end + + # for lighting + get!(gl_attributes, :world_normalmatrix) do + return lift(plot, gl_attributes[:model]) do m + i = Vec(1, 2, 3) + return transpose(inv(m[i, i])) end end - get!(gl_attributes, :normalmatrix) do + + # for SSAO + get!(gl_attributes, :view_normalmatrix) do return lift(plot, gl_attributes[:view], gl_attributes[:model]) do v, m i = Vec(1, 2, 3) return transpose(inv(v[i, i] * m[i, i])) end end - get!(gl_attributes, :projection) do - return lift(cam.projection, cam.pixel_space, space) do _, _, space - return Makie.space_to_clip(cam, space, false) - end + # 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 - return lift(plot, cam.projectionview, cam.pixel_space, space) do _, _, space - Makie.space_to_clip(cam, space, true) + # 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 end @@ -70,9 +191,12 @@ function connect_camera!(plot, gl_attributes, cam, space = gl_attributes[:space] return nothing end -function handle_intensities!(attributes, plot) +function handle_intensities!(screen, attributes, plot) color = plot.calculated_colors if color[] isa Makie.ColorMapping + onany(plot, color[].color_scaled, color[].colorrange_scaled, color[].colormap, color[].nan_color) do args... + screen.requires_update = true + end attributes[:intensity] = color[].color_scaled interp = color[].color_mapping_type[] === Makie.continuous ? :linear : :nearest attributes[:color_map] = Texture(color[].colormap; minfilter=interp) @@ -97,53 +221,100 @@ function get_space(x) return haskey(x, :markerspace) ? x.markerspace : x.space end -function cached_robj!(robj_func, screen, scene, x::AbstractPlot) +const EXCLUDE_KEYS = Set([:transformation, :tickranges, :ticklabels, :raw, :SSAO, + :lightposition, :material, :axis_cycler, + :inspector_label, :inspector_hover, :inspector_clear, :inspectable, + :colorrange, :colormap, :colorscale, :highclip, :lowclip, :nan_color, + :calculated_colors, :space, :markerspace, :model]) + + +function cached_robj!(robj_func, screen, scene, plot::AbstractPlot) # poll inside functions to make wait on compile less prominent pollevents(screen) - robj = get!(screen.cache, objectid(x)) do - filtered = filter(x.attributes) do (k, v) - !in(k, ( - :transformation, :tickranges, :ticklabels, :raw, :SSAO, - :lightposition, :material, - :inspector_label, :inspector_hover, :inspector_clear, :inspectable, - :colorrange, :colormap, :colorscale, :highclip, :lowclip, :nan_color, - :calculated_colors - )) - end + robj = get!(screen.cache, objectid(plot)) do + filtered = filter(plot.attributes) do (k, v) + return !in(k, EXCLUDE_KEYS) + end + track_updates = screen.config.render_on_demand + if track_updates + for arg in plot.args + on(plot, arg) do x + screen.requires_update = true + end + end + on(plot, plot.model) do x + screen.requires_update = true + end + on(plot, scene.camera.projectionview) do x + screen.requires_update = true + end + end gl_attributes = Dict{Symbol, Any}(map(filtered) do key_value key, value = key_value gl_key = to_glvisualize_key(key) - gl_value = lift_convert(key, value, x) + gl_value = lift_convert(key, value, plot, screen) gl_key => gl_value end) - - pointlight = Makie.get_point_light(scene) - if !isnothing(pointlight) - gl_attributes[:lightposition] = pointlight.position + gl_attributes[:model] = plot.model + if haskey(plot, :markerspace) + gl_attributes[:markerspace] = plot.markerspace end - - ambientlight = Makie.get_ambient_light(scene) - if !isnothing(ambientlight) - gl_attributes[:ambient] = ambientlight.color + gl_attributes[:space] = plot.space + gl_attributes[:px_per_unit] = screen.px_per_unit + + handle_intensities!(screen, gl_attributes, plot) + connect_camera!(plot, gl_attributes, scene.camera, get_space(plot)) + + # TODO: remove depwarn & conversion after some time + if haskey(gl_attributes, :shading) && to_value(gl_attributes[:shading]) isa Bool + @warn "`shading::Bool` is deprecated. Use `shading = NoShading` instead of false and `shading = FastShading` or `shading = MultiLightShading` instead of true." + gl_attributes[:shading] = ifelse(gl_attributes[:shading][], FastShading, NoShading) + elseif haskey(gl_attributes, :shading) && gl_attributes[:shading] isa Observable + gl_attributes[:shading] = gl_attributes[:shading][] end - gl_attributes[:track_updates] = screen.config.render_on_demand - handle_intensities!(gl_attributes, x) - connect_camera!(x, gl_attributes, scene.camera, get_space(x)) + shading = to_value(get(gl_attributes, :shading, NoShading)) - robj = robj_func(gl_attributes) + if shading == FastShading + dirlight = Makie.get_directional_light(scene) + if !isnothing(dirlight) + gl_attributes[:light_direction] = if dirlight.camera_relative + map(gl_attributes[:view], dirlight.direction) do view, dir + return normalize(inv(view[Vec(1,2,3), Vec(1,2,3)]) * dir) + end + else + map(normalize, dirlight.direction) + end - get!(gl_attributes, :ssao, Observable(false)) - screen.cache2plot[robj.id] = x + gl_attributes[:light_color] = dirlight.color + else + gl_attributes[:light_direction] = Observable(Vec3f(0)) + gl_attributes[:light_color] = Observable(RGBf(0,0,0)) + end - robj + ambientlight = Makie.get_ambient_light(scene) + if !isnothing(ambientlight) + gl_attributes[:ambient] = ambientlight.color + else + gl_attributes[:ambient] = Observable(RGBf(0,0,0)) + end + elseif shading == MultiLightShading + handle_lights(gl_attributes, screen, scene.lights) + end + robj = robj_func(gl_attributes) # <-- here + + get!(gl_attributes, :ssao, Observable(false)) + screen.cache2plot[robj.id] = plot + return robj end push!(screen, scene, robj) return robj end -function Base.insert!(screen::Screen, scene::Scene, x::Combined) +Base.insert!(::GLMakie.Screen, ::Scene, ::Makie.PlotList) = nothing + +function Base.insert!(screen::Screen, scene::Scene, @nospecialize(x::Plot)) ShaderAbstractions.switch_context!(screen.glscreen) # poll inside functions to make wait on compile less prominent pollevents(screen) @@ -158,12 +329,6 @@ function Base.insert!(screen::Screen, scene::Scene, x::Combined) end end -function remove_automatic!(attributes) - filter!(attributes) do (k, v) - to_value(v) != automatic - end -end - index1D(x::SubArray) = parentindices(x)[1] handle_view(array::AbstractVector, attributes) = array @@ -183,12 +348,13 @@ function handle_view(array::Observable{T}, attributes) where T <: SubArray return A end -function lift_convert(key, value, plot) - return lift_convert_inner(value, Key{key}(), Key{Makie.plotkey(plot)}(), plot) +function lift_convert(key, value, plot, screen) + return lift_convert_inner(value, Key{key}(), Key{Makie.plotkey(plot)}(), plot, screen) end -function lift_convert_inner(value, key, plot_key, plot) +function lift_convert_inner(value, key, plot_key, plot, screen) return lift(plot, value) do value + screen.requires_update = true return convert_attribute(value, key, plot_key) end end @@ -209,28 +375,28 @@ end pixel2world(scene, msize::AbstractVector) = pixel2world.(scene, msize) -function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatter, MeshScatter})) - return cached_robj!(screen, scene, x) do gl_attributes +function draw_atomic(screen::Screen, scene::Scene, @nospecialize(plot::Union{Scatter, MeshScatter})) + return cached_robj!(screen, scene, plot) do gl_attributes # signals not supported for shading yet - gl_attributes[:shading] = to_value(get(gl_attributes, :shading, true)) - marker = lift_convert(:marker, pop!(gl_attributes, :marker), x) + marker = pop!(gl_attributes, :marker) - space = x.space - positions = handle_view(x[1], gl_attributes) - positions = apply_transform(transform_func_obs(x), positions, space) + space = plot.space + positions = handle_view(plot[1], gl_attributes) + positions = lift(apply_transform, plot, transform_func_obs(plot), positions, space) - if x isa Scatter - mspace = x.markerspace + if plot isa Scatter + mspace = plot.markerspace cam = scene.camera - gl_attributes[:preprojection] = map(space, mspace, cam.projectionview, cam.resolution) do space, mspace, _, _ + gl_attributes[:preprojection] = lift(plot, space, mspace, cam.projectionview, + cam.resolution) do space, mspace, _, _ return Makie.clip_to_space(cam, mspace) * Makie.space_to_clip(cam, space) end # fast pixel does its own setup if !(marker[] isa FastPixel) - gl_attributes[:billboard] = map(rot-> isa(rot, Billboard), x.rotations) + gl_attributes[:billboard] = lift(rot -> isa(rot, Billboard), plot, plot.rotations) atlas = gl_texture_atlas() isnothing(gl_attributes[:distancefield][]) && delete!(gl_attributes, :distancefield) - shape = lift(m-> Cint(Makie.marker_to_sdf_shape(m)), x, marker) + shape = lift(m -> Cint(Makie.marker_to_sdf_shape(m)), plot, marker) gl_attributes[:shape] = shape get!(gl_attributes, :distancefield) do if shape[] === Cint(DISTANCEFIELD) @@ -244,7 +410,8 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatte get!(gl_attributes, :uv_offset_width) do return Makie.primitive_uv_offset_width(atlas, marker, font) end - scale, quad_offset = Makie.marker_attributes(atlas, marker, gl_attributes[:scale], font, gl_attributes[:quad_offset]) + scale, quad_offset = Makie.marker_attributes(atlas, marker, gl_attributes[:scale], font, + gl_attributes[:quad_offset], plot) gl_attributes[:scale] = scale gl_attributes[:quad_offset] = quad_offset end @@ -259,7 +426,7 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatte end return draw_pixel_scatter(screen, positions, gl_attributes) else - if x isa MeshScatter + if plot isa MeshScatter if haskey(gl_attributes, :color) && to_value(gl_attributes[:color]) isa AbstractMatrix{<: Colorant} gl_attributes[:image] = gl_attributes[:color] end @@ -274,28 +441,31 @@ end _mean(xs) = sum(xs) / length(xs) # skip Statistics import -function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Lines)) - return cached_robj!(screen, scene, x) do gl_attributes +function draw_atomic(screen::Screen, scene::Scene, @nospecialize(plot::Lines)) + return cached_robj!(screen, scene, plot) do gl_attributes linestyle = pop!(gl_attributes, :linestyle) data = Dict{Symbol, Any}(gl_attributes) + positions = handle_view(plot[1], data) - positions = handle_view(x[1], data) - transform_func = transform_func_obs(x) - + transform_func = transform_func_obs(plot) ls = to_value(linestyle) - space = x.space + space = plot.space if isnothing(ls) data[:pattern] = ls data[:fast] = true - positions = apply_transform(transform_func, positions, space) + positions = lift(apply_transform, plot, transform_func, positions, space) else linewidth = gl_attributes[:thickness] - data[:pattern] = map((ls, lw) -> ls .* _mean(lw), linestyle, linewidth) + px_per_unit = data[:px_per_unit] + data[:pattern] = map(linestyle, linewidth, px_per_unit) do ls, lw, ppu + ppu * _mean(lw) .* ls + end data[:fast] = false - pvm = map(*, data[:projectionview], data[:model]) - positions = map(transform_func, positions, space, pvm, data[:resolution]) do f, ps, space, pvm, res + pvm = lift(*, plot, data[:projectionview], data[:model]) + positions = lift(plot, transform_func, positions, space, pvm, + data[:resolution]) do f, ps, space, pvm, res transformed = apply_transform(f, ps, space) output = Vector{Point3f}(undef, length(transformed)) scale = Vec3f(res[1], res[2], 1f0) @@ -310,48 +480,53 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Lines)) end end -function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::LineSegments)) - return cached_robj!(screen, scene, x) do gl_attributes +function draw_atomic(screen::Screen, scene::Scene, @nospecialize(plot::LineSegments)) + return cached_robj!(screen, scene, plot) do gl_attributes linestyle = pop!(gl_attributes, :linestyle) data = Dict{Symbol, Any}(gl_attributes) + px_per_unit = data[:px_per_unit] ls = to_value(linestyle) if isnothing(ls) data[:pattern] = nothing data[:fast] = true else linewidth = gl_attributes[:thickness] - data[:pattern] = ls .* _mean(to_value(linewidth)) + data[:pattern] = lift(plot, linestyle, linewidth, px_per_unit) do ls, lw, ppu + ppu * _mean(lw) .* ls + end data[:fast] = false end - positions = handle_view(x.converted[1], data) - positions = apply_transform(transform_func_obs(x), positions, x.space) + positions = handle_view(plot[1], data) + + positions = lift(apply_transform, plot, transform_func_obs(plot), positions, plot.space) if haskey(data, :intensity) data[:color] = pop!(data, :intensity) end + return draw_linesegments(screen, positions, data) end end function draw_atomic(screen::Screen, scene::Scene, - x::Text{<:Tuple{<:Union{<:Makie.GlyphCollection, <:AbstractVector{<:Makie.GlyphCollection}}}}) - return cached_robj!(screen, scene, x) do gl_attributes - glyphcollection = x[1] + plot::Text{<:Tuple{<:Union{<:Makie.GlyphCollection, <:AbstractVector{<:Makie.GlyphCollection}}}}) + return cached_robj!(screen, scene, plot) do gl_attributes + glyphcollection = plot[1] - transfunc = Makie.transform_func_obs(x) + transfunc = Makie.transform_func_obs(plot) pos = gl_attributes[:position] - space = x.space - markerspace = x.markerspace + space = plot.space + markerspace = plot.markerspace offset = pop!(gl_attributes, :offset, Vec2f(0)) atlas = gl_texture_atlas() # calculate quad metrics - glyph_data = map(pos, glyphcollection, offset, transfunc, space) do pos, gc, offset, transfunc, space - Makie.text_quads(atlas, pos, to_value(gc), offset, transfunc, space) + glyph_data = lift(plot, pos, glyphcollection, offset, transfunc, space) do pos, gc, offset, transfunc, space + return Makie.text_quads(atlas, pos, to_value(gc), offset, transfunc, space) end # unpack values from the one signal: positions, char_offset, quad_offset, uv_offset_width, scale = map((1, 2, 3, 4, 5)) do i - lift(getindex, x, glyph_data, i) + lift(getindex, plot, glyph_data, i) end @@ -363,7 +538,7 @@ function draw_atomic(screen::Screen, scene::Scene, )) # space, end - gl_attributes[:color] = lift(x, glyphcollection) do gc + gl_attributes[:color] = lift(plot, glyphcollection) do gc if gc isa AbstractArray reduce(vcat, (Makie.collect_vector(g.colors, length(g.glyphs)) for g in gc), init = RGBAf[]) @@ -371,7 +546,7 @@ function draw_atomic(screen::Screen, scene::Scene, Makie.collect_vector(gc.colors, length(gc.glyphs)) end end - gl_attributes[:stroke_color] = lift(x, glyphcollection) do gc + gl_attributes[:stroke_color] = lift(plot, glyphcollection) do gc if gc isa AbstractArray reduce(vcat, (Makie.collect_vector(g.strokecolors, length(g.glyphs)) for g in gc), init = RGBAf[]) @@ -380,7 +555,7 @@ function draw_atomic(screen::Screen, scene::Scene, end end - gl_attributes[:rotation] = lift(x, glyphcollection) do gc + gl_attributes[:rotation] = lift(plot, glyphcollection) do gc if gc isa AbstractArray reduce(vcat, (Makie.collect_vector(g.rotations, length(g.glyphs)) for g in gc), init = Quaternionf[]) @@ -395,10 +570,10 @@ function draw_atomic(screen::Screen, scene::Scene, gl_attributes[:marker_offset] = char_offset gl_attributes[:uv_offset_width] = uv_offset_width gl_attributes[:distancefield] = get_texture!(atlas) - gl_attributes[:visible] = x.visible + gl_attributes[:visible] = plot.visible cam = scene.camera # gl_attributes[:preprojection] = Observable(Mat4f(I)) - gl_attributes[:preprojection] = map(space, markerspace, cam.projectionview, cam.resolution) do s, ms, pv, res + gl_attributes[:preprojection] = lift(plot, space, markerspace, cam.projectionview, cam.resolution) do s, ms, pv, res Makie.clip_to_space(cam, ms) * Makie.space_to_clip(cam, s) end @@ -412,12 +587,12 @@ xy_convert(x::AbstractArray{Float32}, n) = copy(x) xy_convert(x::AbstractArray, n) = el32convert(x) xy_convert(x, n) = Float32[LinRange(extrema(x)..., n + 1);] -function draw_atomic(screen::Screen, scene::Scene, heatmap::Heatmap) - return cached_robj!(screen, scene, heatmap) do gl_attributes - t = Makie.transform_func_obs(heatmap) - mat = heatmap[3] - space = heatmap.space # needs to happen before connect_camera! call - xypos = lift(t, heatmap[1], heatmap[2], space) do t, x, y, space +function draw_atomic(screen::Screen, scene::Scene, plot::Heatmap) + return cached_robj!(screen, scene, plot) do gl_attributes + t = Makie.transform_func_obs(plot) + mat = plot[3] + space = plot.space # needs to happen before connect_camera! call + xypos = lift(plot, t, plot[1], plot[2], space) do t, x, y, space x1d = xy_convert(x, size(mat[], 1)) y1d = xy_convert(y, size(mat[], 2)) # Only if transform doesn't do anything, we can stay linear in 1/2D @@ -435,12 +610,12 @@ function draw_atomic(screen::Screen, scene::Scene, heatmap::Heatmap) return (x1d, y1d) end end - xpos = map(first, xypos) - ypos = map(last, xypos) + xpos = lift(first, plot, xypos) + ypos = lift(last, plot, xypos) gl_attributes[:position_x] = Texture(xpos, minfilter = :nearest) gl_attributes[:position_y] = Texture(ypos, minfilter = :nearest) # number of planes used to render the heatmap - gl_attributes[:instances] = map(xpos, ypos) do x, y + gl_attributes[:instances] = lift(plot, xpos, ypos) do x, y (length(x)-1) * (length(y)-1) end interp = to_value(pop!(gl_attributes, :interpolate)) @@ -456,22 +631,21 @@ function draw_atomic(screen::Screen, scene::Scene, heatmap::Heatmap) end end -function draw_atomic(screen::Screen, scene::Scene, x::Image) - return cached_robj!(screen, scene, x) do gl_attributes - position = lift(x, x[1], x[2]) do x, y - r = to_range(x, y) - x, y = minimum(r[1]), minimum(r[2]) - xmax, ymax = maximum(r[1]), maximum(r[2]) - rect = Rect2f(x, y, xmax - x, ymax - y) +function draw_atomic(screen::Screen, scene::Scene, plot::Image) + return cached_robj!(screen, scene, plot) do gl_attributes + position = lift(plot, plot[1], plot[2]) do x, y + xmin, xmax = extrema(x) + ymin, ymax = extrema(y) + rect = Rect2f(xmin, ymin, xmax - xmin, ymax - ymin) return decompose(Point2f, rect) end - gl_attributes[:vertices] = apply_transform(transform_func_obs(x), position, x.space) + gl_attributes[:vertices] = lift(apply_transform, plot, transform_func_obs(plot), position, plot.space) rect = Rect2f(0, 0, 1, 1) gl_attributes[:faces] = decompose(GLTriangleFace, rect) gl_attributes[:texturecoordinates] = map(decompose_uv(rect)) do uv return 1.0f0 .- Vec2f(uv[2], uv[1]) end - gl_attributes[:shading] = false + get!(gl_attributes, :shading, NoShading) _interp = to_value(pop!(gl_attributes, :interpolate, true)) interp = _interp ? :linear : :nearest if haskey(gl_attributes, :intensity) @@ -483,10 +657,10 @@ function draw_atomic(screen::Screen, scene::Scene, x::Image) end end -function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, space=:data) +function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, plot, space=:data) # signals not supported for shading yet - shading = to_value(pop!(gl_attributes, :shading)) - gl_attributes[:shading] = shading + shading = to_value(gl_attributes[:shading])::Makie.MakieCore.ShadingAlgorithm + matcap_active = !isnothing(to_value(get(gl_attributes, :matcap, nothing))) color = pop!(gl_attributes, :color) interp = to_value(pop!(gl_attributes, :interpolate, true)) interp = interp ? :linear : :nearest @@ -495,18 +669,18 @@ function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, space=:data) delete!(gl_attributes, :color_map) delete!(gl_attributes, :color_norm) elseif to_value(color) isa Makie.AbstractPattern - img = lift(x -> el32convert(Makie.to_image(x)), color) + img = lift(x -> el32convert(Makie.to_image(x)), plot, color) gl_attributes[:image] = ShaderAbstractions.Sampler(img, x_repeat=:repeat, minfilter=:nearest) get!(gl_attributes, :fetch_pixel, true) elseif to_value(color) isa AbstractMatrix{<:Colorant} - gl_attributes[:image] = Texture(const_lift(el32convert, color), minfilter = interp) + gl_attributes[:image] = Texture(lift(el32convert, plot, color), minfilter = interp) delete!(gl_attributes, :color_map) delete!(gl_attributes, :color_norm) elseif to_value(color) isa AbstractMatrix{<: Number} - gl_attributes[:image] = Texture(const_lift(el32convert, color), minfilter = interp) + gl_attributes[:image] = Texture(lift(el32convert, plot, color), minfilter = interp) gl_attributes[:color] = nothing elseif to_value(color) isa AbstractVector{<: Union{Number, Colorant}} - gl_attributes[:vertex_color] = lift(el32convert, color) + gl_attributes[:vertex_color] = lift(el32convert, plot, color) else # error("Unsupported color type: $(typeof(to_value(color)))") end @@ -528,30 +702,32 @@ function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, space=:data) if hasproperty(to_value(mesh), :uv) gl_attributes[:texturecoordinates] = lift(decompose_uv, mesh) end - if hasproperty(to_value(mesh), :normals) && shading + if hasproperty(to_value(mesh), :normals) && (shading !== NoShading || matcap_active) gl_attributes[:normals] = lift(decompose_normals, mesh) end return draw_mesh(screen, gl_attributes) end function draw_atomic(screen::Screen, scene::Scene, meshplot::Mesh) - return cached_robj!(screen, scene, meshplot) do gl_attributes + x = cached_robj!(screen, scene, meshplot) do gl_attributes t = transform_func_obs(meshplot) space = meshplot.space # needs to happen before connect_camera! call - return mesh_inner(screen, meshplot[1], t, gl_attributes, space) + x = mesh_inner(screen, meshplot[1], t, gl_attributes, meshplot, space) + return x end + + return x end -function draw_atomic(screen::Screen, scene::Scene, x::Surface) - robj = cached_robj!(screen, scene, x) do gl_attributes +function draw_atomic(screen::Screen, scene::Scene, plot::Surface) + robj = cached_robj!(screen, scene, plot) do gl_attributes color = pop!(gl_attributes, :color) img = nothing - # signals not supported for shading yet # We automatically insert x[3] into the color channel, so if it's equal we don't need to do anything if haskey(gl_attributes, :intensity) img = pop!(gl_attributes, :intensity) elseif to_value(color) isa Makie.AbstractPattern - pattern_img = lift(x -> el32convert(Makie.to_image(x)), color) + pattern_img = lift(x -> el32convert(Makie.to_image(x)), plot, color) img = ShaderAbstractions.Sampler(pattern_img, x_repeat=:repeat, minfilter=:nearest) haskey(gl_attributes, :fetch_pixel) || (gl_attributes[:fetch_pixel] = true) gl_attributes[:color_map] = nothing @@ -564,18 +740,17 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) gl_attributes[:color_norm] = nothing end - space = x.space + space = plot.space gl_attributes[:image] = img - gl_attributes[:shading] = to_value(get(gl_attributes, :shading, true)) - @assert to_value(x[3]) isa AbstractMatrix - types = map(v -> typeof(to_value(v)), x[1:2]) + @assert to_value(plot[3]) isa AbstractMatrix + types = map(v -> typeof(to_value(v)), plot[1:2]) if all(T -> T <: Union{AbstractMatrix, AbstractVector}, types) - t = Makie.transform_func_obs(x) - mat = x[3] - xypos = map(t, x[1], x[2], space) do t, x, y, space + t = Makie.transform_func_obs(plot) + mat = plot[3] + xypos = lift(plot, t, plot[1], plot[2], space) do t, x, y, space # Only if transform doesn't do anything, we can stay linear in 1/2D if Makie.is_identity_transform(t) return (x, y) @@ -590,18 +765,18 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) return (first.(matrix), last.(matrix)) end end - xpos = map(first, xypos) - ypos = map(last, xypos) + xpos = lift(first, plot, xypos) + ypos = lift(last, plot, xypos) args = map((xpos, ypos, mat)) do arg - Texture(map(x-> convert(Array, el32convert(x)), arg); minfilter=:linear) + Texture(lift(x-> convert(Array, el32convert(x)), plot, arg); minfilter=:linear) end if isnothing(img) gl_attributes[:image] = args[3] end return draw_surface(screen, args, gl_attributes) else - gl_attributes[:ranges] = to_range.(to_value.(x[1:2])) - z_data = Texture(el32convert(x[3]); minfilter=:linear) + gl_attributes[:ranges] = to_range.(to_value.(plot[1:2])) + z_data = Texture(lift(el32convert, plot, plot[3]); minfilter=:linear) if isnothing(img) gl_attributes[:image] = z_data end @@ -611,11 +786,11 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) return robj end -function draw_atomic(screen::Screen, scene::Scene, vol::Volume) - robj = cached_robj!(screen, scene, vol) do gl_attributes - model = vol[:model] - x, y, z = vol[1], vol[2], vol[3] - gl_attributes[:model] = lift(model, x, y, z) do m, xyz... +function draw_atomic(screen::Screen, scene::Scene, plot::Volume) + return cached_robj!(screen, scene, plot) do gl_attributes + model = plot.model + x, y, z = plot[1], plot[2], plot[3] + gl_attributes[:model] = lift(plot, model, x, y, z) do m, xyz... mi = minimum.(xyz) maxi = maximum.(xyz) w = maxi .- mi @@ -631,7 +806,7 @@ function draw_atomic(screen::Screen, scene::Scene, vol::Volume) intensity = pop!(gl_attributes, :intensity) return draw_volume(screen, intensity, gl_attributes) else - return draw_volume(screen, vol[4], gl_attributes) + return draw_volume(screen, plot[4], gl_attributes) end end end diff --git a/GLMakie/src/events.jl b/GLMakie/src/events.jl index 88bfb76b39a..52f631095ce 100644 --- a/GLMakie/src/events.jl +++ b/GLMakie/src/events.jl @@ -37,50 +37,50 @@ function Makie.disconnect!(window::GLFW.Window, ::typeof(window_open)) GLFW.SetWindowCloseCallback(window, nothing) end -function window_position(window::GLFW.Window) - xy = GLFW.GetWindowPos(window) - (xy.x, xy.y) -end +function Makie.window_area(scene::Scene, screen::Screen) + disconnect!(screen, window_area) -struct WindowAreaUpdater - window::GLFW.Window - dpi::Observable{Float64} - area::Observable{GeometryBasics.HyperRectangle{2, Int64}} -end + # TODO: Figure out which monitor the window is on and react to DPI changes + monitor = GLFW.GetPrimaryMonitor() + props = MonitorProperties(monitor) + scene.events.window_dpi[] = minimum(props.dpi) + + function windowsizecb(window, width::Cint, height::Cint) + area = scene.events.window_area + sf = screen.scalefactor[] -function (x::WindowAreaUpdater)(::Nothing) - ShaderAbstractions.switch_context!(x.window) - rect = x.area[] - # TODO put back window position, but right now it makes more trouble than it helps# - # x, y = GLFW.GetWindowPos(window) - # if minimum(rect) != Vec(x, y) - # event[] = Recti(x, y, framebuffer_size(window)) - # end - w, h = GLFW.GetFramebufferSize(x.window) - if Vec(w, h) != widths(rect) - monitor = GLFW.GetPrimaryMonitor() - props = MonitorProperties(monitor) - # dpi of a monitor should be the same in x y direction. - # if not, minimum seems to be a fair default - x.dpi[] = minimum(props.dpi) - x.area[] = Recti(minimum(rect), w, h) + ShaderAbstractions.switch_context!(window) + winscale = sf / (@static Sys.isapple() ? scale_factor(window) : 1) + winw, winh = round.(Int, (width, height) ./ winscale) + if Vec(winw, winh) != widths(area[]) + area[] = Recti(minimum(area[]), winw, winh) + end + return end - return -end + # TODO put back window position, but right now it makes more trouble than it helps + #function windowposcb(window, x::Cint, y::Cint) + # area = scene.events.window_area + # ShaderAbstractions.switch_context!(window) + # winscale = screen.scalefactor[] / (@static Sys.isapple() ? scale_factor(window) : 1) + # xs, ys = round.(Int, (x, y) ./ winscale) + # if Vec(xs, ys) != minimum(area[]) + # area[] = Recti(xs, ys, widths(area[])) + # end + # return + #end -function Makie.window_area(scene::Scene, screen::Screen) - disconnect!(screen, window_area) - - updater = WindowAreaUpdater( - to_native(screen), scene.events.window_dpi, scene.events.window_area - ) - on(updater, screen.render_tick) + window = to_native(screen) + GLFW.SetWindowSizeCallback(window, (win, w, h) -> windowsizecb(win, w, h)) + #GLFW.SetWindowPosCallback(window, (win, x, y) -> windowposcb(win, x, y)) + windowsizecb(window, Cint.(window_size(window))...) return end function Makie.disconnect!(screen::Screen, ::typeof(window_area)) - filter!(p -> !isa(p[2], WindowAreaUpdater), screen.render_tick.listeners) + window = to_native(screen) + #GLFW.SetWindowPosCallback(window, nothing) + GLFW.SetWindowSizeCallback(window, nothing) return end function Makie.disconnect!(::GLFW.Window, ::typeof(window_area)) @@ -168,49 +168,33 @@ function Makie.disconnect!(window::GLFW.Window, ::typeof(unicode_input)) GLFW.SetCharCallback(window, nothing) end -# TODO memoise? Or to bug ridden for the small performance gain? -function retina_scaling_factor(w, fb) - (w[1] == 0 || w[2] == 0) && return (1.0, 1.0) - fb ./ w -end - -# TODO both of these methods are slow! -# ~90µs, ~80µs -# This is too slow for events that may happen 100x per frame -function framebuffer_size(window::GLFW.Window) - wh = GLFW.GetFramebufferSize(window) - (wh.width, wh.height) -end -function window_size(window::GLFW.Window) - wh = GLFW.GetWindowSize(window) - (wh.width, wh.height) -end -function retina_scaling_factor(window::GLFW.Window) - w, fb = window_size(window), framebuffer_size(window) - retina_scaling_factor(w, fb) -end - -function correct_mouse(window::GLFW.Window, w, h) - ws, fb = window_size(window), framebuffer_size(window) - s = retina_scaling_factor(ws, fb) - (w * s[1], fb[2] - (h * s[2])) +function correct_mouse(screen::Screen, w, h) + nw = to_native(screen) + sf = screen.scalefactor[] / (@static Sys.isapple() ? scale_factor(nw) : 1) + _, winh = window_size(nw) + @static if Sys.isapple() + return w, (winh / sf) - h + else + return w / sf, (winh - h) / sf + end end struct MousePositionUpdater - window::GLFW.Window + screen::Screen mouseposition::Observable{Tuple{Float64, Float64}} hasfocus::Observable{Bool} end function (p::MousePositionUpdater)(::Nothing) !p.hasfocus[] && return - x, y = GLFW.GetCursorPos(p.window) - pos = correct_mouse(p.window, x, y) + nw = to_native(p.screen) + x, y = GLFW.GetCursorPos(nw) + pos = correct_mouse(p.screen, x, y) if pos != p.mouseposition[] @print_error p.mouseposition[] = pos # notify!(e.mouseposition) end - return + return Consume(false) end """ @@ -222,9 +206,9 @@ which is not in scene coordinates, with the upper left window corner being 0 function Makie.mouse_position(scene::Scene, screen::Screen) disconnect!(screen, mouse_position) updater = MousePositionUpdater( - to_native(screen), scene.events.mouseposition, scene.events.hasfocus + screen, scene.events.mouseposition, scene.events.hasfocus ) - on(updater, screen.render_tick) + on(updater, scene, screen.render_tick, priority = typemax(Int)) return end function Makie.disconnect!(screen::Screen, ::typeof(mouse_position)) diff --git a/GLMakie/src/gl_backend.jl b/GLMakie/src/gl_backend.jl index 1fb7a003f02..b8ed7a35dfd 100644 --- a/GLMakie/src/gl_backend.jl +++ b/GLMakie/src/gl_backend.jl @@ -75,5 +75,3 @@ include("rendering.jl") include("events.jl") include("drawing_primitives.jl") include("display.jl") - -Base.@deprecate_binding GLVisualize GLMakie true "The module `GLVisualize` has been removed and integrated into GLMakie, so simply replace all usage of `GLVisualize` with `GLMakie`." diff --git a/GLMakie/src/glshaders/image_like.jl b/GLMakie/src/glshaders/image_like.jl index 97c6fa990e8..0fd7ccbaa05 100644 --- a/GLMakie/src/glshaders/image_like.jl +++ b/GLMakie/src/glshaders/image_like.jl @@ -34,6 +34,7 @@ A matrix of Intensities will result in a contourf kind of plot function draw_heatmap(screen, data::Dict) primitive = triangle_mesh(Rect2(0f0,0f0,1f0,1f0)) to_opengl_mesh!(data, primitive) + pop!(data, :shading, FastShading) @gen_defaults! data begin intensity = nothing => Texture color_map = nothing => Texture @@ -55,6 +56,8 @@ end function draw_volume(screen, main::VolumeTypes, data::Dict) geom = Rect3f(Vec3f(0), Vec3f(1)) to_opengl_mesh!(data, const_lift(GeometryBasics.triangle_mesh, geom)) + shading = pop!(data, :shading, FastShading) + pop!(data, :backlight, 0f0) # We overwrite this @gen_defaults! data begin volumedata = main => Texture model = Mat4f(I) @@ -67,12 +70,17 @@ function draw_volume(screen, main::VolumeTypes, data::Dict) absorption = 1f0 isovalue = 0.5f0 isorange = 0.01f0 + backlight = 1f0 enable_depth = true transparency = false shader = GLVisualizeShader( screen, - "fragment_output.frag", "util.vert", "volume.vert", "volume.frag", + "util.vert", "volume.vert", + "fragment_output.frag", "lighting.frag", "volume.frag", view = Dict( + "shading" => light_calc(shading), + "MAX_LIGHTS" => "#define MAX_LIGHTS $(screen.config.max_lights)", + "MAX_LIGHT_PARAMETERS" => "#define MAX_LIGHT_PARAMETERS $(screen.config.max_light_parameters)", "depth_init" => vol_depth_init(to_value(enable_depth)), "depth_default" => vol_depth_default(to_value(enable_depth)), "depth_main" => vol_depth_main(to_value(enable_depth)), diff --git a/GLMakie/src/glshaders/lines.jl b/GLMakie/src/glshaders/lines.jl index 86a25d916cf..562460de1f6 100644 --- a/GLMakie/src/glshaders/lines.jl +++ b/GLMakie/src/glshaders/lines.jl @@ -145,13 +145,13 @@ function draw_linesegments(screen, positions::VectorTypes{T}, data::Dict) where gl_primitive = GL_LINES pattern_length = 1f0 end - if !isa(pattern, Texture) && pattern !== nothing - if !isa(pattern, Vector) - error("Pattern needs to be a Vector of floats") + if !isa(pattern, Texture) && to_value(pattern) !== nothing + if !isa(to_value(pattern), Vector) + error("Pattern needs to be a Vector of floats. Found: $(typeof(pattern))") end - tex = GLAbstraction.Texture(ticks(pattern, 100), x_repeat = :repeat) + tex = GLAbstraction.Texture(map(pt -> ticks(pt, 100), pattern), x_repeat = :repeat) data[:pattern] = tex - data[:pattern_length] = Float32((last(pattern) - first(pattern))) + data[:pattern_length] = map(pt -> Float32(last(pt) - first(pt)), pattern) end robj = assemble_shader(data) return robj diff --git a/GLMakie/src/glshaders/mesh.jl b/GLMakie/src/glshaders/mesh.jl index 678d8f7b25f..877ddf90dea 100644 --- a/GLMakie/src/glshaders/mesh.jl +++ b/GLMakie/src/glshaders/mesh.jl @@ -27,7 +27,9 @@ function to_opengl_mesh!(result, mesh_obs::TOrSignal{<: GeometryBasics.Mesh}) to_buffer(:uv, :texturecoordinates) to_buffer(:uvw, :texturecoordinates) # Only emit normals, when we shadin' - if to_value(get(result, :shading, true)) || !isnothing(to_value(get(result, :matcap, nothing))) + 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) end to_buffer(:attribute_id, :attribute_id) @@ -35,11 +37,11 @@ function to_opengl_mesh!(result, mesh_obs::TOrSignal{<: GeometryBasics.Mesh}) end function draw_mesh(screen, data::Dict) + shading = pop!(data, :shading, NoShading)::Makie.MakieCore.ShadingAlgorithm @gen_defaults! data begin vertices = nothing => GLBuffer faces = nothing => indexbuffer normals = nothing => GLBuffer - shading = true backlight = 0f0 vertex_color = nothing => GLBuffer image = nothing => Texture @@ -53,13 +55,18 @@ function draw_mesh(screen, data::Dict) interpolate_in_fragment_shader = true shader = GLVisualizeShader( screen, - "util.vert", "mesh.vert", "mesh.frag", "fragment_output.frag", + "util.vert", "mesh.vert", + "fragment_output.frag", "mesh.frag", + "lighting.frag", view = Dict( - "light_calc" => light_calc(shading), + "shading" => light_calc(shading), + "MAX_LIGHTS" => "#define MAX_LIGHTS $(screen.config.max_lights)", + "MAX_LIGHT_PARAMETERS" => "#define MAX_LIGHT_PARAMETERS $(screen.config.max_light_parameters)", "buffers" => output_buffers(screen, to_value(transparency)), "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) ) ) end + return assemble_shader(data) end diff --git a/GLMakie/src/glshaders/particles.jl b/GLMakie/src/glshaders/particles.jl index f44bec57305..90e3aab1575 100644 --- a/GLMakie/src/glshaders/particles.jl +++ b/GLMakie/src/glshaders/particles.jl @@ -57,9 +57,9 @@ function draw_mesh_particle(screen, p, data) scale = Vec3f(1) => TextureBuffer rotation = rot => TextureBuffer texturecoordinates = nothing - shading = true end + shading = pop!(data, :shading)::Makie.MakieCore.ShadingAlgorithm @gen_defaults! data begin color_map = nothing => Texture color_norm = nothing @@ -71,16 +71,19 @@ function draw_mesh_particle(screen, p, data) fetch_pixel = false interpolate_in_fragment_shader = false uv_scale = Vec2f(1) + backlight = 0f0 instances = const_lift(length, position) - shading = true transparency = false shader = GLVisualizeShader( screen, - "util.vert", "particles.vert", "mesh.frag", "fragment_output.frag", + "util.vert", "particles.vert", + "fragment_output.frag", "lighting.frag", "mesh.frag", view = Dict( "position_calc" => position_calc(position, nothing, nothing, nothing, TextureBuffer), - "light_calc" => light_calc(shading), + "shading" => light_calc(shading), + "MAX_LIGHTS" => "#define MAX_LIGHTS $(screen.config.max_lights)", + "MAX_LIGHT_PARAMETERS" => "#define MAX_LIGHT_PARAMETERS $(screen.config.max_light_parameters)", "buffers" => output_buffers(screen, to_value(transparency)), "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) ) diff --git a/GLMakie/src/glshaders/surface.jl b/GLMakie/src/glshaders/surface.jl index c4d5961fc1a..ef7810a96f8 100644 --- a/GLMakie/src/glshaders/surface.jl +++ b/GLMakie/src/glshaders/surface.jl @@ -6,23 +6,29 @@ end function normal_calc(x::Bool, invert_normals::Bool = false) i = invert_normals ? "-" : "" if x - return "$(i)getnormal(position, position_x, position_y, position_z, o_uv);" + return "$(i)getnormal(position, position_x, position_y, position_z, index2D);" else return "vec3(0, 0, $(i)1);" end end +# TODO this shouldn't be necessary function light_calc(x::Bool) - if x - """ - vec3 L = normalize(o_lightdir); - vec3 N = normalize(o_normal); - vec3 light1 = blinnphong(N, o_camdir, L, color.rgb); - vec3 light2 = blinnphong(N, o_camdir, -L, color.rgb); - color = vec4(ambient * color.rgb + light1 + backlight * light2, color.a); - """ + @error "shading::Bool is deprecated. Use `NoShading` instead of `false` and `FastShading` or `MultiLightShading` instead of true." + return light_calc(ifelse(x, FastShading, NoShading)) +end + +function light_calc(x::Makie.MakieCore.ShadingAlgorithm) + if x === NoShading + return "#define NO_SHADING" + elseif x === FastShading + return "#define FAST_SHADING" + elseif x === MultiLightShading + return "#define MULTI_LIGHT_SHADING" + # elseif x === :PBR # TODO? else - "" + @warn "Did not recognize shading value :$x. Defaulting to FastShading." + return "#define FAST_SHADING" end end @@ -32,7 +38,8 @@ function _position_calc( """ int index1D = index + offseti.x + offseti.y * dims.x + (index/(dims.x-1)); ivec2 index2D = ind2sub(dims, index1D); - vec2 index01 = vec2(index2D) / (vec2(dims)-1.0); + vec2 index01 = (vec2(index2D) + 0.5) / (vec2(dims)); + pos = vec3( texelFetch(position_x, index2D, 0).x, texelFetch(position_y, index2D, 0).x, @@ -48,7 +55,8 @@ function _position_calc( """ int index1D = index + offseti.x + offseti.y * dims.x + (index/(dims.x-1)); ivec2 index2D = ind2sub(dims, index1D); - vec2 index01 = vec2(index2D) / (vec2(dims)-1.0); + vec2 index01 = (vec2(index2D) + 0.5) / (vec2(dims)); + pos = vec3( texelFetch(position_x, index2D.x, 0).x, texelFetch(position_y, index2D.y, 0).x, @@ -76,10 +84,11 @@ function _position_calc( grid::Grid{2}, position_z::MatTypes{T}, target::Type{Texture} ) where T<:AbstractFloat """ - int index1D = index + offseti.x + offseti.y * dims.x + (index/(dims.x-1)); + int index1D = index + offseti.x + offseti.y * dims.x; // + (index/(dims.x-1)); ivec2 index2D = ind2sub(dims, index1D); - vec2 index01 = vec2(index2D) / (vec2(dims)-1.0); - float height = texture(position_z, index01).x; + vec2 index01 = (vec2(index2D) + 0.5) / (vec2(dims)); + + float height = texelFetch(position_z, index2D, 0).x; pos = vec3(grid_pos(position, index01), height); """ end @@ -110,6 +119,7 @@ end function draw_surface(screen, main, data::Dict) primitive = triangle_mesh(Rect2(0f0,0f0,1f0,1f0)) to_opengl_mesh!(data, primitive) + shading = pop!(data, :shading, FastShading)::Makie.MakieCore.ShadingAlgorithm @gen_defaults! data begin scale = nothing position = nothing @@ -117,8 +127,7 @@ function draw_surface(screen, main, data::Dict) position_y = nothing => Texture position_z = nothing => Texture image = nothing => Texture - shading = true - normal = shading + normal = shading != NoShading invert_normals = false backlight = 0f0 end @@ -138,12 +147,14 @@ function draw_surface(screen, main, data::Dict) transparency = false shader = GLVisualizeShader( screen, - "fragment_output.frag", "util.vert", "surface.vert", - "mesh.frag", + "util.vert", "surface.vert", + "fragment_output.frag", "lighting.frag", "mesh.frag", view = Dict( "position_calc" => position_calc(position, position_x, position_y, position_z, Texture), "normal_calc" => normal_calc(normal, to_value(invert_normals)), - "light_calc" => light_calc(shading), + "shading" => light_calc(shading), + "MAX_LIGHTS" => "#define MAX_LIGHTS $(screen.config.max_lights)", + "MAX_LIGHT_PARAMETERS" => "#define MAX_LIGHT_PARAMETERS $(screen.config.max_light_parameters)", "buffers" => output_buffers(screen, to_value(transparency)), "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) ) diff --git a/GLMakie/src/glshaders/visualize_interface.jl b/GLMakie/src/glshaders/visualize_interface.jl index 1633084e6b6..d9236e4f61c 100644 --- a/GLMakie/src/glshaders/visualize_interface.jl +++ b/GLMakie/src/glshaders/visualize_interface.jl @@ -176,7 +176,7 @@ function output_buffer_writes(screen::Screen, transparency = false) """ fragment_color = color; fragment_position = o_view_pos; - fragment_normal_occlusion.xyz = o_normal; + fragment_normal_occlusion.xyz = o_view_normal; """ else "fragment_color = color;" diff --git a/GLMakie/src/glwindow.jl b/GLMakie/src/glwindow.jl index df0836b308b..7901b34c074 100644 --- a/GLMakie/src/glwindow.jl +++ b/GLMakie/src/glwindow.jl @@ -129,7 +129,7 @@ function GLFramebuffer(fb_size::NTuple{2, Int}) # To allow adding postprocessors in various combinations we need to keep # track of the buffer ids that are already in use. We may also want to reuse # buffers so we give them names for easy fetching. - buffer_ids = Dict( + buffer_ids = Dict{Symbol,GLuint}( :color => GL_COLOR_ATTACHMENT0, :objectid => GL_COLOR_ATTACHMENT1, :HDR_color => GL_COLOR_ATTACHMENT2, @@ -137,31 +137,29 @@ function GLFramebuffer(fb_size::NTuple{2, Int}) :depth => GL_DEPTH_ATTACHMENT, :stencil => GL_STENCIL_ATTACHMENT, ) - buffers = Dict( - :color => color_buffer, + buffers = Dict{Symbol, Texture}( + :color => color_buffer, :objectid => objectid_buffer, :HDR_color => HDR_color_buffer, :OIT_weight => OIT_weight_buffer, - :depth => depth_buffer, - :stencil => depth_buffer + :depth => depth_buffer, + :stencil => depth_buffer ) return GLFramebuffer( fb_size_node, frambuffer_id, buffer_ids, buffers, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1] - ) + )::GLFramebuffer end -function Base.resize!(fb::GLFramebuffer, window_size) - ws = Int.((window_size[1], window_size[2])) - if ws != size(fb) && all(x-> x > 0, window_size) - for (name, buffer) in fb.buffers - resize_nocopy!(buffer, ws) - end - fb.resolution[] = ws +function Base.resize!(fb::GLFramebuffer, w::Int, h::Int) + (w > 0 && h > 0 && (w, h) != size(fb)) || return + for (name, buffer) in fb.buffers + resize_nocopy!(buffer, (w, h)) end - nothing + fb.resolution[] = (w, h) + return nothing end @@ -217,10 +215,21 @@ function destroy!(nw::GLFW.Window) was_current && ShaderAbstractions.switch_context!() end -function windowsize(nw::GLFW.Window) +function window_size(nw::GLFW.Window) + was_destroyed(nw) && return (0, 0) + return Tuple(GLFW.GetWindowSize(nw)) +end +function window_position(nw::GLFW.Window) was_destroyed(nw) && return (0, 0) - size = GLFW.GetFramebufferSize(nw) - return (size.width, size.height) + return Tuple(GLFW.GetWindowPos(window)) +end +function framebuffer_size(nw::GLFW.Window) + was_destroyed(nw) && return (0, 0) + return Tuple(GLFW.GetFramebufferSize(nw)) +end +function scale_factor(nw::GLFW.Window) + was_destroyed(nw) && return 1f0 + return minimum(GLFW.GetWindowContentScale(nw)) end function Base.isopen(window::GLFW.Window) diff --git a/GLMakie/src/picking.jl b/GLMakie/src/picking.jl index d83c4d6f9d2..ab718ba7bcc 100644 --- a/GLMakie/src/picking.jl +++ b/GLMakie/src/picking.jl @@ -6,16 +6,17 @@ function pick_native(screen::Screen, rect::Rect2i) isopen(screen) || return Matrix{SelectionID{Int}}(undef, 0, 0) ShaderAbstractions.switch_context!(screen.glscreen) - window_size = size(screen) fb = screen.framebuffer buff = fb.buffers[:objectid] glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) glReadBuffer(GL_COLOR_ATTACHMENT1) rx, ry = minimum(rect) rw, rh = widths(rect) - w, h = window_size - sid = zeros(SelectionID{UInt32}, widths(rect)...) + w, h = size(screen.root_scene) + ppu = screen.px_per_unit[] if rx > 0 && ry > 0 && rx + rw <= w && ry + rh <= h + rx, ry, rw, rh = round.(Int, ppu .* (rx, ry, rw, rh)) + sid = zeros(SelectionID{UInt32}, rw, rh) glReadPixels(rx, ry, rw, rh, buff.format, buff.pixeltype, sid) return sid else @@ -26,15 +27,16 @@ end function pick_native(screen::Screen, xy::Vec{2, Float64}) isopen(screen) || return SelectionID{Int}(0, 0) ShaderAbstractions.switch_context!(screen.glscreen) - sid = Base.RefValue{SelectionID{UInt32}}() - window_size = size(screen) fb = screen.framebuffer buff = fb.buffers[:objectid] glBindFramebuffer(GL_FRAMEBUFFER, fb.id[1]) glReadBuffer(GL_COLOR_ATTACHMENT1) x, y = floor.(Int, xy) - w, h = window_size + w, h = size(screen.root_scene) + ppu = screen.px_per_unit[] if x > 0 && y > 0 && x <= w && y <= h + x, y = round.(Int, ppu .* (x, y)) + sid = Base.RefValue{SelectionID{UInt32}}() glReadPixels(x, y, 1, 1, buff.format, buff.pixeltype, sid) return convert(SelectionID{Int}, sid[]) end @@ -65,7 +67,7 @@ end # Skips one set of allocations function Makie.pick_closest(scene::Scene, screen::Screen, xy, range) isopen(screen) || return (nothing, 0) - w, h = size(screen) + w, h = size(scene) ((1.0 <= xy[1] <= w) && (1.0 <= xy[2] <= h)) || return (nothing, 0) x0, y0 = max.(1, floor.(Int, xy .- range)) @@ -95,7 +97,7 @@ end # Skips some allocations function Makie.pick_sorted(scene::Scene, screen::Screen, xy, range) isopen(screen) || return (nothing, 0) - w, h = size(screen) + w, h = size(scene) if !((1.0 <= xy[1] <= w) && (1.0 <= xy[2] <= h)) return Tuple{AbstractPlot, Int}[] end diff --git a/GLMakie/src/postprocessing.jl b/GLMakie/src/postprocessing.jl index 3c295d158a6..60c978e07cf 100644 --- a/GLMakie/src/postprocessing.jl +++ b/GLMakie/src/postprocessing.jl @@ -163,6 +163,7 @@ function ssao_postprocessor(framebuffer, shader_cache) glDrawBuffer(normal_occ_id) # occlusion buffer glViewport(0, 0, w, h) glEnable(GL_SCISSOR_TEST) + ppu = (x) -> round.(Int, screen.px_per_unit[] .* x) for (screenid, scene) in screen.screens # Select the area of one leaf scene @@ -170,8 +171,8 @@ function ssao_postprocessor(framebuffer, shader_cache) # scenes. It should be a leaf scene to avoid repeatedly shading # the same region (though this is not guaranteed...) isempty(scene.children) || continue - a = pixelarea(scene)[] - glScissor(minimum(a)..., widths(a)...) + a = viewport(scene)[] + glScissor(ppu(minimum(a))..., ppu(widths(a))...) # update uniforms data1[:projection] = scene.camera.projection[] data1[:bias] = scene.ssao.bias[] @@ -184,8 +185,8 @@ function ssao_postprocessor(framebuffer, shader_cache) for (screenid, scene) in screen.screens # Select the area of one leaf scene isempty(scene.children) || continue - a = pixelarea(scene)[] - glScissor(minimum(a)..., widths(a)...) + a = viewport(scene)[] + glScissor(ppu(minimum(a))..., ppu(widths(a))...) # update uniforms data2[:blur_range] = scene.ssao.blur GLAbstraction.render(pass2) @@ -285,14 +286,11 @@ function to_screen_postprocessor(framebuffer, shader_cache, screen_fb_id = nothi pass.postrenderfunction = () -> draw_fullscreen(pass.vertexarray.id) full_render = screen -> begin - fb = screen.framebuffer - w, h = size(fb) - # transfer everything to the screen default_id = isnothing(screen_fb_id) ? 0 : screen_fb_id[] # GLFW uses 0, Gtk uses a value that we have to probe at the beginning of rendering glBindFramebuffer(GL_FRAMEBUFFER, default_id) - glViewport(0, 0, w, h) + glViewport(0, 0, framebuffer_size(screen.glscreen)...) glClear(GL_COLOR_BUFFER_BIT) GLAbstraction.render(pass) # copy postprocess end diff --git a/GLMakie/src/precompiles.jl b/GLMakie/src/precompiles.jl index 6ddcc86e980..d2bd372aa14 100644 --- a/GLMakie/src/precompiles.jl +++ b/GLMakie/src/precompiles.jl @@ -10,14 +10,18 @@ macro compile(block) end end + + let @setup_workload begin x = rand(5) @compile_workload begin + GLMakie.activate!() screen = GLMakie.singleton_screen(false) close(screen) destroy!(screen) + base_path = normpath(joinpath(dirname(pathof(Makie)), "..", "precompile")) shared_precompile = joinpath(base_path, "shared-precompile.jl") include(shared_precompile) @@ -26,6 +30,22 @@ let catch end Makie.CURRENT_FIGURE[] = nothing + + screen = Screen(Scene()) + close(screen) + screen = empty_screen(false) + close(screen) + 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) + + + config = Makie.merge_screen_config(ScreenConfig, Dict{Symbol,Any}()) + screen = Screen(Scene(), config; visible=false, start_renderloop=false) + close(screen) + empty!(atlas_texture_cache) closeall() @assert isempty(SCREEN_REUSE_POOL) @@ -35,3 +55,16 @@ let end nothing end + +precompile(Screen, (Scene, ScreenConfig)) +precompile(GLFramebuffer, (NTuple{2,Int},)) +precompile(glTexImage, (GLenum, Int, GLenum, Int, Int, Int, GLenum, GLenum, Ptr{Float32})) +precompile(glTexImage, (GLenum, Int, GLenum, Int, Int, Int, GLenum, GLenum, Ptr{RGBAf})) +precompile(glTexImage, (GLenum, Int, GLenum, Int, Int, Int, GLenum, GLenum, Ptr{RGBf})) +precompile(glTexImage, (GLenum, Int, GLenum, Int, Int, Int, GLenum, GLenum, Ptr{RGBA{N0f8}})) +precompile(glTexImage, + (GLenum, Int, GLenum, Int, Int, Int, GLenum, GLenum, Ptr{GLAbstraction.DepthStencil_24_8})) +precompile(glTexImage, (GLenum, Int, GLenum, Int, Int, Int, GLenum, GLenum, Ptr{Vec{2,GLuint}})) +precompile(glTexImage, (GLenum, Int, GLenum, Int, Int, Int, GLenum, GLenum, Ptr{RGBA{Float16}})) +precompile(glTexImage, (GLenum, Int, GLenum, Int, Int, Int, GLenum, GLenum, Ptr{N0f8})) +precompile(setindex!, (GLMakie.GLAbstraction.Texture{Float16,2}, Matrix{Float32}, Rect2{Int32})) diff --git a/GLMakie/src/rendering.jl b/GLMakie/src/rendering.jl index 3f9b5073c24..dda559f5ec3 100644 --- a/GLMakie/src/rendering.jl +++ b/GLMakie/src/rendering.jl @@ -1,14 +1,14 @@ - -function setup!(screen) +function setup!(screen::Screen) glEnable(GL_SCISSOR_TEST) - if isopen(screen) - glScissor(0, 0, size(screen)...) + if isopen(screen) && !isnothing(screen.root_scene) + ppu = screen.px_per_unit[] + glScissor(0, 0, round.(Int, size(screen.root_scene) .* ppu)...) glClearColor(1, 1, 1, 1) glClear(GL_COLOR_BUFFER_BIT) for (id, scene) in screen.screens if scene.visible[] - a = pixelarea(scene)[] - rt = (minimum(a)..., widths(a)...) + a = viewport(scene)[] + rt = (round.(Int, ppu .* minimum(a))..., round.(Int, ppu .* widths(a))...) glViewport(rt...) if scene.clear[] c = scene.backgroundcolor[] @@ -43,11 +43,10 @@ function render_frame(screen::Screen; resize_buffers=true) # render order here may introduce artifacts because of that. fb = screen.framebuffer - if resize_buffers - wh = Int.(framebuffer_size(nw)) - resize!(fb, wh) + if resize_buffers && !isnothing(screen.root_scene) + ppu = screen.px_per_unit[] + resize!(fb, round.(Int, ppu .* size(screen.root_scene))...) end - w, h = size(fb) # prepare stencil (for sub-scenes) glBindFramebuffer(GL_FRAMEBUFFER, fb.id) @@ -119,8 +118,9 @@ function GLAbstraction.render(filter_elem_func, screen::Screen) found, scene = id2scene(screen, screenid) found || continue scene.visible[] || continue - a = pixelarea(scene)[] - glViewport(minimum(a)..., widths(a)...) + ppu = screen.px_per_unit[] + a = viewport(scene)[] + glViewport(round.(Int, ppu .* minimum(a))..., round.(Int, ppu .* widths(a))...) render(elem) end catch e diff --git a/GLMakie/src/screen.jl b/GLMakie/src/screen.jl index 5e934f6b6d5..8133ed61ed1 100644 --- a/GLMakie/src/screen.jl +++ b/GLMakie/src/screen.jl @@ -8,8 +8,7 @@ function renderloop end """ ## Renderloop -* `renderloop = GLMakie.renderloop`: sets a function `renderloop(::GLMakie.Screen)` which starts a renderloop for the screen. - +* `renderloop = GLMakie.renderloop`: Sets a function `renderloop(::GLMakie.Screen)` which starts a renderloop for the screen. !!! warning The keyword arguments below are not effective if `renderloop` isn't set to `GLMakie.renderloop`, unless implemented in a custom renderloop function: @@ -18,6 +17,7 @@ function renderloop end * `vsync = false`: Whether to enable vsync for the window. * `render_on_demand = true`: If `true`, the scene will only be rendered if something has changed in it. * `framerate = 30.0`: Sets the currently rendered frames per second. +* `px_per_unit = automatic`: Sets the ratio between the number of rendered pixels and the `Makie` resolution. It defaults to the value of `scalefactor` but may be any positive real number. ## GLFW window attributes * `float = false`: Whether the window should float above other windows. @@ -28,13 +28,16 @@ function renderloop end * `debugging = false`: If `true`, starts the GLFW.Window/OpenGL context with debug output. * `monitor::Union{Nothing, GLFW.Monitor} = nothing`: Sets the monitor on which the window should be opened. If set to `nothing`, GLFW will decide which monitor to use. * `visible = true`: Whether or not the window should be visible when first created. +* `scalefactor = automatic`: Sets the window scaling factor, such as `2.0` on HiDPI/Retina displays. It is set automatically based on the display, but may be any positive real number. -## Postprocessor +## Rendering constants & Postprocessor * `oit = false`: Whether to enable order independent transparency for the window. * `fxaa = true`: Whether to enable fxaa (anti-aliasing) for the window. * `ssao = true`: Whether to enable screen space ambient occlusion, which simulates natural shadowing at inner edges and crevices. * `transparency_weight_scale = 1000f0`: Adjusts a factor in the rendering shaders for order independent transparency. This should be the same for all of them (within one rendering pipeline) otherwise depth "order" will be broken. +* `max_lights = 64`: The maximum number of lights with `shading = MultiLightShading` +* `max_light_parameters = 5 * N_lights`: The maximum number of light parameters that can be uploaded. These include everything other than the light color (i.e. position, direction, attenuation, angles) in terms of scalar floats. """ mutable struct ScreenConfig # Renderloop @@ -43,6 +46,7 @@ mutable struct ScreenConfig vsync::Bool render_on_demand::Bool framerate::Float64 + px_per_unit::Union{Nothing, Float32} # GLFW window attributes float::Bool @@ -53,12 +57,15 @@ mutable struct ScreenConfig debugging::Bool monitor::Union{Nothing, GLFW.Monitor} visible::Bool + scalefactor::Union{Nothing, Float32} - # Postprocessor + # Render Constants & Postprocessor oit::Bool fxaa::Bool ssao::Bool transparency_weight_scale::Float32 + max_lights::Int + max_light_parameters::Int function ScreenConfig( # Renderloop @@ -67,6 +74,7 @@ mutable struct ScreenConfig vsync::Bool, render_on_demand::Bool, framerate::Number, + px_per_unit::Union{Makie.Automatic, Number}, # GLFW window attributes float::Bool, focus_on_show::Bool, @@ -76,12 +84,15 @@ mutable struct ScreenConfig debugging::Bool, monitor::Union{Nothing, GLFW.Monitor}, visible::Bool, + scalefactor::Union{Makie.Automatic, Number}, # Preprocessor oit::Bool, fxaa::Bool, ssao::Bool, - transparency_weight_scale::Number) + transparency_weight_scale::Number, + max_lights::Int, + max_light_parameters::Int) return new( # Renderloop renderloop isa Makie.Automatic ? GLMakie.renderloop : renderloop, @@ -89,6 +100,7 @@ mutable struct ScreenConfig vsync, render_on_demand, framerate, + px_per_unit isa Makie.Automatic ? nothing : Float32(px_per_unit), # GLFW window attributes float, focus_on_show, @@ -98,11 +110,15 @@ mutable struct ScreenConfig debugging, monitor, visible, + scalefactor isa Makie.Automatic ? nothing : Float32(scalefactor), + # Preproccessor # Preprocessor oit, fxaa, ssao, - transparency_weight_scale) + transparency_weight_scale, + max_lights, + max_light_parameters) end end @@ -147,6 +163,7 @@ mutable struct Screen{GLWindow} <: MakieScreen config::Union{Nothing, ScreenConfig} stop_renderloop::Bool rendertask::Union{Task, Nothing} + px_per_unit::Observable{Float32} screen2scene::Dict{WeakRef, ScreenID} screens::Vector{ScreenArea} @@ -155,8 +172,9 @@ mutable struct Screen{GLWindow} <: MakieScreen cache::Dict{UInt64, RenderObject} cache2plot::Dict{UInt32, AbstractPlot} framecache::Matrix{RGB{N0f8}} - render_tick::Observable{Nothing} + render_tick::Observable{Nothing} # listeners must not Consume(true) window_open::Observable{Bool} + scalefactor::Observable{Float32} root_scene::Union{Scene, Nothing} reuse::Bool @@ -185,16 +203,18 @@ mutable struct Screen{GLWindow} <: MakieScreen screen = new{GLWindow}( glscreen, shader_cache, framebuffer, config, stop_renderloop, rendertask, - screen2scene, + Observable(0f0), screen2scene, screens, renderlist, postprocessors, cache, cache2plot, Matrix{RGB{N0f8}}(undef, s), Observable(nothing), - Observable(true), nothing, reuse, true, false + Observable(true), Observable(0f0), nothing, reuse, true, false ) push!(ALL_SCREENS, screen) # track all created screens return screen end end +Makie.isvisible(screen::Screen) = screen.config.visible + # for e.g. closeall, track all created screens # gets removed in destroy!(screen) const ALL_SCREENS = Set{Screen}() @@ -213,6 +233,8 @@ function empty_screen(debugging::Bool; reuse=true) (GLFW.STENCIL_BITS, 0), (GLFW.AUX_BUFFERS, 0), + + (GLFW.SCALE_TO_MONITOR, true), ] resolution = (10, 10) window = try @@ -261,7 +283,9 @@ function empty_screen(debugging::Bool; reuse=true) Dict{UInt32, AbstractPlot}(), reuse, ) - GLFW.SetWindowRefreshCallback(window, window -> refreshwindowcb(window, screen)) + GLFW.SetWindowRefreshCallback(window, refreshwindowcb(screen)) + GLFW.SetWindowContentScaleCallback(window, scalechangecb(screen)) + return screen end @@ -276,6 +300,7 @@ function reopen!(screen::Screen) end @assert isempty(screen.window_open.listeners) screen.window_open[] = true + on(scalechangeobs(screen), screen.scalefactor) @assert isopen(screen) return screen end @@ -307,8 +332,6 @@ function singleton_screen(debugging::Bool) return reopen!(screen) end -const GLFW_FOCUS_ON_SHOW = 0x0002000C - function Makie.apply_screen_config!(screen::Screen, config::ScreenConfig, scene::Scene, args...) apply_config!(screen, config) end @@ -317,7 +340,7 @@ function apply_config!(screen::Screen, config::ScreenConfig; start_renderloop::B @debug("Applying screen config! to existing screen") glw = screen.glscreen ShaderAbstractions.switch_context!(glw) - GLFW.SetWindowAttrib(glw, GLFW_FOCUS_ON_SHOW, config.focus_on_show) + GLFW.SetWindowAttrib(glw, GLFW.FOCUS_ON_SHOW, config.focus_on_show) GLFW.SetWindowAttrib(glw, GLFW.DECORATED, config.decorated) GLFW.SetWindowAttrib(glw, GLFW.FLOATING, config.float) GLFW.SetWindowTitle(glw, config.title) @@ -325,7 +348,8 @@ function apply_config!(screen::Screen, config::ScreenConfig; start_renderloop::B if !isnothing(config.monitor) GLFW.SetWindowMonitor(glw, config.monitor) end - + screen.scalefactor[] = !isnothing(config.scalefactor) ? config.scalefactor : scale_factor(glw) + screen.px_per_unit[] = !isnothing(config.px_per_unit) ? config.px_per_unit : screen.scalefactor[] function replace_processor!(postprocessor, idx) fb = screen.framebuffer shader_cache = screen.shader_cache @@ -340,6 +364,9 @@ function apply_config!(screen::Screen, config::ScreenConfig; start_renderloop::B replace_processor!(config.ssao ? ssao_postprocessor : empty_postprocessor, 1) replace_processor!(config.oit ? OIT_postprocessor : empty_postprocessor, 2) replace_processor!(config.fxaa ? fxaa_postprocessor : empty_postprocessor, 3) + + # TODO: replace shader programs with lighting to update N_lights & N_light_parameters + # Set the config screen.config = config if start_renderloop @@ -347,7 +374,9 @@ function apply_config!(screen::Screen, config::ScreenConfig; start_renderloop::B else stop_renderloop!(screen) end - + if !isnothing(screen.root_scene) + resize!(screen, size(screen.root_scene)...) + end set_screen_visibility!(screen, config.visible) return screen end @@ -358,12 +387,12 @@ function Screen(; screen_config... ) # Screen config is managed by the current active theme, so managed by Makie - config = Makie.merge_screen_config(ScreenConfig, screen_config) + config = Makie.merge_screen_config(ScreenConfig, Dict{Symbol, Any}(screen_config)) screen = screen_from_pool(config.debugging) + apply_config!(screen, config; start_renderloop=start_renderloop) if !isnothing(resolution) resize!(screen, resolution...) end - apply_config!(screen, config; start_renderloop=start_renderloop) return screen end @@ -384,7 +413,7 @@ function display_scene!(screen::Screen, scene::Scene) end function Screen(scene::Scene; start_renderloop=true, screen_config...) - config = Makie.merge_screen_config(ScreenConfig, screen_config) + config = Makie.merge_screen_config(ScreenConfig, Dict{Symbol, Any}(screen_config)) return Screen(scene, config; start_renderloop=start_renderloop) end @@ -417,8 +446,9 @@ end function pollevents(screen::Screen) ShaderAbstractions.switch_context!(screen.glscreen) - notify(screen.render_tick) GLFW.PollEvents() + notify(screen.render_tick) + return end Base.wait(x::Screen) = !isnothing(x.rendertask) && wait(x.rendertask) @@ -436,10 +466,10 @@ function Makie.insertplots!(screen::Screen, scene::Scene) push!(screen.screens, (id, scene)) screen.requires_update = true onany( - (_, _, _, _, _, _) -> screen.requires_update = true, + (args...) -> screen.requires_update = true, scene, scene.visible, scene.backgroundcolor, scene.clear, - scene.ssao.bias, scene.ssao.blur, scene.ssao.radius + scene.ssao.bias, scene.ssao.blur, scene.ssao.radius, scene.camera.projectionview, scene.camera.resolution ) return id end @@ -556,6 +586,8 @@ function Base.empty!(screen::Screen) empty!(screen.screen2scene) empty!(screen.screens) + Observables.clear(screen.px_per_unit) + Observables.clear(screen.scalefactor) Observables.clear(screen.render_tick) Observables.clear(screen.window_open) GLFW.PollEvents() @@ -569,7 +601,10 @@ function destroy!(screen::Screen) # otherwise, during rendertask clean up we may run into a destroyed window wait(screen) screen.rendertask = nothing - destroy!(screen.glscreen) + window = screen.glscreen + GLFW.SetWindowRefreshCallback(window, nothing) + GLFW.SetWindowContentScaleCallback(window, nothing) + destroy!(window) # Since those are sets, we can just delete them from there, even if they weren't in there (e.g. reuse=false) delete!(SCREEN_REUSE_POOL, screen) delete!(ALL_SCREENS, screen) @@ -622,24 +657,30 @@ function closeall() return end -function resize_native!(window::GLFW.Window, resolution...) - if isopen(window) - ShaderAbstractions.switch_context!(window) - oldsize = windowsize(window) - retina_scale = retina_scaling_factor(window) - w, h = resolution ./ retina_scale - if oldsize == (w, h) - return - end - GLFW.SetWindowSize(window, round(Int, w), round(Int, h)) +function Base.resize!(screen::Screen, w::Int, h::Int) + window = to_native(screen) + (w > 0 && h > 0 && isopen(window)) || return nothing + + # Resize the window which appears on the user desktop (if necessary). + # + # On OSX with a Retina display, the window size is given in logical dimensions and + # is automatically scaled by the OS. To support arbitrary scale factors, we must account + # for the native scale factor when calculating the effective scaling to apply. + # + # On Linux and Windows, scale from the logical size to the pixel size. + ShaderAbstractions.switch_context!(window) + winscale = screen.scalefactor[] / (@static Sys.isapple() ? scale_factor(window) : 1) + winw, winh = round.(Int, winscale .* (w, h)) + if window_size(window) != (winw, winh) + GLFW.SetWindowSize(window, winw, winh) end -end -function Base.resize!(screen::Screen, w, h) - nw = to_native(screen) - resize_native!(nw, w, h) - fb = screen.framebuffer - resize!(fb, (w, h)) + # Then resize the underlying rendering framebuffers as well, which can be scaled + # independently of the window scale factor. + fbscale = screen.px_per_unit[] + fbw, fbh = round.(Int, fbscale .* (w, h)) + resize!(screen.framebuffer, fbw, fbh) + return nothing end function fast_color_data!(dest::Array{RGB{N0f8}, 2}, source::Texture{T, 2}) where T @@ -686,7 +727,7 @@ function Makie.colorbuffer(screen::Screen, format::Makie.ImageStorageFormat = Ma ctex = screen.framebuffer.buffers[:color] # polling may change window size, when its bigger than monitor! # we still need to poll though, to get all the newest events! - # GLFW.PollEvents() + pollevents(screen) # keep current buffer size to allows larger-than-window renders render_frame(screen, resize_buffers=false) # let it render if screen.config.visible @@ -818,12 +859,32 @@ function set_framerate!(screen::Screen, fps=30) screen.config.framerate = fps end -function refreshwindowcb(window, screen) +function refreshwindowcb(screen, window) screen.render_tick[] = nothing render_frame(screen) GLFW.SwapBuffers(window) return end +refreshwindowcb(screen) = window -> refreshwindowcb(screen, window) + +function scalechangecb(screen, window, xscale, yscale) + sf = min(xscale, yscale) + if isnothing(screen.config.px_per_unit) && screen.scalefactor[] == screen.px_per_unit[] + screen.px_per_unit[] = sf + end + screen.scalefactor[] = sf + return +end +scalechangecb(screen) = (window, xscale, yscale) -> scalechangecb(screen, window, xscale, yscale) + +function scalechangeobs(screen, _) + if !isnothing(screen.root_scene) + resize!(screen, size(screen.root_scene)...) + end + return nothing +end +scalechangeobs(screen) = scalefactor -> scalechangeobs(screen, scalefactor) + # TODO add render_tick event to scene events function vsynced_renderloop(screen) @@ -865,9 +926,7 @@ function requires_update(screen::Screen) screen.requires_update = false return true end - for (_, _, robj) in screen.renderlist - robj.requires_update && return true - end + return false end diff --git a/GLMakie/test/glmakie_refimages.jl b/GLMakie/test/glmakie_refimages.jl index 5a386d5d0e8..4c08416ffda 100644 --- a/GLMakie/test/glmakie_refimages.jl +++ b/GLMakie/test/glmakie_refimages.jl @@ -81,7 +81,7 @@ end glFinish() end end - fig, ax, meshplot = meshscatter(RNG.rand(Point3f, 10^4) .* 20f0) + fig, ax, meshplot = meshscatter(RNG.rand(Point3f, 10^4) .* 20f0; color=:black) screen = display(GLMakie.Screen(;renderloop=(screen) -> nothing, start_renderloop=false), fig.scene) buff = RNG.rand(Point3f, 10^4) .* 20f0; update_loop(meshplot, buff, screen) @@ -97,9 +97,70 @@ end fig = Figure() left = LScene(fig[1, 1]) contour!(left, [sin(i+j) * sin(j+k) * sin(i+k) for i in 1:10, j in 1:10, k in 1:10], enable_depth = true) - mesh!(left, Sphere(Point3f(5), 6f0)) + mesh!(left, Sphere(Point3f(5), 6f0), color=:black) right = LScene(fig[1, 2]) volume!(right, [sin(2i) * sin(2j) * sin(2k) for i in 1:10, j in 1:10, k in 1:10], algorithm = :iso, enable_depth = true) - mesh!(right, Sphere(Point3f(5), 6f0)) + mesh!(right, Sphere(Point3f(5), 6.0f0); color=:black) fig end + +@reference_test "Complex Lighting - Ambient + SpotLights + PointLights" begin + angle2pos(phi) = Point3f(cosd(phi), sind(phi), 0) + lights = [ + AmbientLight(RGBf(0.1, 0.1, 0.1)), + SpotLight(RGBf(2,0,0), angle2pos(0), Vec3f(0, 0, -1), Vec2f(pi/5, pi/4)), + SpotLight(RGBf(0,2,0), angle2pos(120), Vec3f(0, 0, -1), Vec2f(pi/5, pi/4)), + SpotLight(RGBf(0,0,2), angle2pos(240), Vec3f(0, 0, -1), Vec2f(pi/5, pi/4)), + PointLight(RGBf(1,1,1), Point3f(-4, -4, -2.5), 10.0), + PointLight(RGBf(1,1,0), Point3f(-4, 4, -2.5), 10.0), + PointLight(RGBf(1,0,1), Point3f( 4, 4, -2.5), 10.0), + PointLight(RGBf(0,1,1), Point3f( 4, -4, -2.5), 10.0), + ] + + scene = Scene(size = (400, 400), camera = cam3d!, lights = lights) + mesh!( + scene, + Rect3f(Point3f(-10, -10, -2.99), Vec3f(20, 20, 0.02)), + color = :white, shading = MultiLightShading, specular = Vec3f(0) + ) + center!(scene) + update_cam!(scene, Vec3f(0, 0, 10), Vec3f(0, 0, 0), Vec3f(0, 1, 0)) + scene +end + +@reference_test "Complex Lighting - DirectionalLight + specular reflection" begin + angle2dir(phi) = Vec3f(cosd(phi), sind(phi), -2) + lights = [ + AmbientLight(RGBf(0.1, 0.1, 0.1)), + DirectionalLight(RGBf(1,0,0), angle2dir(0)), + DirectionalLight(RGBf(0,1,0), angle2dir(120)), + DirectionalLight(RGBf(0,0,1), angle2dir(240)), + ] + + scene = Scene(size = (400, 400), camera = cam3d!, center = false, lights = lights, backgroundcolor = :black) + mesh!( + scene, Sphere(Point3f(0), 1f0), color = :white, shading = MultiLightShading, + specular = Vec3f(1), shininess = 16f0 + ) + update_cam!(scene, Vec3f(0, 0, 3), Vec3f(0, 0, 0), Vec3f(0, 1, 0)) + scene +end + + +@reference_test "RectLight" begin + lights = Makie.AbstractLight[ + RectLight(RGBf(0.5, 0, 0), Point3f(-0.5, -1, 2), Vec3f(3, 0, 0), Vec3f(0, 3, 0)), + RectLight(RGBf(0, 0.5, 0), Rect2f(-1, 1, 1, 3)), + RectLight(RGBf(0, 0, 0.5), Point3f( 1, 0.5, 2), Vec3f(3, 0, 0), Vec3f(0, 3, 0)), + RectLight(RGBf(0.5, 0.5, 0.5), Point3f( 1, -1, 2), Vec3f(3, 0, 0), Vec3f(0, 3, 0), Vec3f(-0.3, 0.3, -1)), + ] + # Test transformations + translate!(lights[2], Vec3f(-1, 1, 2)) # translate to by default + scale!(lights[2], 3, 1) + + scene = Scene(lights = lights, camera = cam3d!, size = (400, 400)) + p = mesh!(scene, Rect3f(Point3f(-10, -10, 0.01), Vec3f(20, 20, 0.02)), color = :white) + update_cam!(scene, Vec3f(0, 0, 7), Vec3f(0, 0, 0), Vec3f(0, 1, 0)) + + scene +end \ No newline at end of file diff --git a/GLMakie/test/runtests.jl b/GLMakie/test/runtests.jl index b235938df7d..1ada23c2012 100644 --- a/GLMakie/test/runtests.jl +++ b/GLMakie/test/runtests.jl @@ -11,8 +11,7 @@ if !GLMakie.ModernGL.enable_opengl_debugging @warn("TESTING WITHOUT OPENGL DEBUGGING") end - -GLMakie.activate!(framerate=1.0) +GLMakie.activate!(framerate=1.0, scalefactor=1.0) @testset "mimes" begin Makie.inline!(true) diff --git a/GLMakie/test/unit_tests.jl b/GLMakie/test/unit_tests.jl index e1252cc934f..bb7b7b650cf 100644 --- a/GLMakie/test/unit_tests.jl +++ b/GLMakie/test/unit_tests.jl @@ -2,7 +2,7 @@ using GLMakie.Makie: getscreen function project_sp(scene, point) point_px = Makie.project(scene, point) - offset = Point2f(minimum(pixelarea(scene)[])) + offset = Point2f(minimum(viewport(scene)[])) return point_px .+ offset end @@ -103,6 +103,7 @@ end screen = display(fig) empty!(fig) @test screen in fig.scene.current_screens + @test length(fig.scene.current_screens) == 1 @testset "all got freed" begin for (_, _, robj) in screen.renderlist for (k, v) in robj.uniforms @@ -210,8 +211,9 @@ end @testset "stresstest multi displays" begin GLMakie.closeall() + set_theme!() screens = map(1:10) do i - fig = Figure(resolution=(500, 500)) + fig = Figure(size=(500, 500)) rng = Random.MersenneTwister(0) ax, pl = image(fig[1, 1], 0..1, 0..1, rand(rng, 1000, 1000)) scatter!(ax, rand(rng, Point2f, 1000), color=:red) @@ -223,13 +225,13 @@ end heatmap(fig[2, 1], rand(rng, 100, 100)) surface(fig[2, 2], 0..1, 0..1, rand(rng, 1000, 1000) ./ 2) - display(GLMakie.Screen(visible=false), fig) + display(GLMakie.Screen(visible=false, scalefactor=1), fig) end images = map(Makie.colorbuffer, screens) @test all(x-> x ≈ first(images), images) - @test Base.summarysize(screens) / 10^6 > 280 + @test Base.summarysize(screens) / 10^6 > 60 foreach(close, screens) for screen in screens @@ -243,10 +245,12 @@ end @test isempty(screen.window_open.listeners) @test isempty(screen.render_tick.listeners) + @test isempty(screen.px_per_unit.listeners) + @test isempty(screen.scalefactor.listeners) @test screen.root_scene === nothing @test screen.rendertask === nothing - @test (Base.summarysize(screen) / 10^6) < 1.2 + @test (Base.summarysize(screen) / 10^6) < 1.22 end # All should go to pool after close @test all(x-> x in GLMakie.SCREEN_REUSE_POOL, screens) @@ -255,3 +259,137 @@ end # now every screen should be gone @test isempty(GLMakie.SCREEN_REUSE_POOL) end + +@testset "HiDPI displays" begin + import FileIO: @format_str, File, load + set_theme!() + GLMakie.closeall() + + W, H = 400, 400 + N = 51 + x = collect(range(0.0, 2π, length=N)) + y = sin.(x) + fig, ax, pl = scatter(x, y, figure = (; size = (W, H))); + hidedecorations!(ax) + + # On OSX, the native window size has an underlying scale factor that we need to account + # for when interpreting native window sizes with respect to the desired figure size + # and desired scaling factor. + function scaled(screen::GLMakie.Screen, dims::Tuple{Vararg{Int}}) + sf = screen.scalefactor[] / (Sys.isapple() ? GLMakie.scale_factor(screen.glscreen) : 1) + return round.(Int, dims .* sf) + end + + screen = display(GLMakie.Screen(visible = true, scalefactor = 2), fig) + @test screen.scalefactor[] === 2f0 + @test screen.px_per_unit[] === 2f0 # inherited from scale factor + winscale = screen.scalefactor[] / (@static Sys.isapple() ? GLMakie.scale_factor(screen.glscreen) : 1) + @test size(screen.framebuffer) == (2W, 2H) + @test GLMakie.window_size(screen.glscreen) == scaled(screen, (W, H)) + + # check that picking works through the resized GL buffers + GLMakie.Makie.colorbuffer(screen) # force render + # - point pick + point_px = project_sp(ax.scene, Point2f(x[end÷2], y[end÷2])) + elem, idx = pick(ax.scene, point_px) + @test elem === pl + @test idx == length(x) ÷ 2 + # - area pick + bottom_px = project_sp(ax.scene, Point2f(π, -1)) + right_px = project_sp(ax.scene, Point2f(2π, 0)) + quadrant = Rect2i(round.(bottom_px)..., round.(right_px - bottom_px)...) + picks = pick(ax.scene, quadrant) + points = Set(Int(p[2]) for p in picks if p[1] isa Scatter) + @test points == Set(((N+1)÷2):N) + + # render at lower resolution + screen = display(GLMakie.Screen(visible = false, scalefactor = 2, px_per_unit = 1), fig) + @test screen.scalefactor[] === 2f0 + @test screen.px_per_unit[] === 1f0 + @test size(screen.framebuffer) == (W, H) + + # decrease the scale factor after-the-fact + screen.scalefactor[] = 1 + GLMakie.Makie.colorbuffer(screen) + @test GLMakie.window_size(screen.glscreen) == scaled(screen, (W, H)) + + # save images of different resolutions + mktemp() do path, io + close(io) + file = File{format"PNG"}(path) + + # save at current size + @test screen.px_per_unit[] == 1 + save(file, fig; px_per_unit=1) + img = load(file) + @test size(img) == (W, H) + # save with a different resolution + save(file, fig, px_per_unit = 2) + img = load(file) + @test size(img) == (2W, 2H) + # writing to file should not effect the visible figure + @test_broken screen.px_per_unit[] == 1 + # Make sure switching back resizes the screen correctly! + save(file, fig; px_per_unit=1) + img = load(file) + @test size(img) == (W, H) + end + + # make sure there isn't a race between changing the scale factor and window_area updater + # see https://github.com/MakieOrg/Makie.jl/pull/2544#issuecomment-1416861800 + screen = display(GLMakie.Screen(visible = false, scalefactor = 2, framerate = 60), fig) + @test GLMakie.window_size(screen.glscreen) == scaled(screen, (W, H)) + on(screen.scalefactor) do sf + sleep(0.5) + end + screen.scalefactor[] = 1 + @test GLMakie.window_size(screen.glscreen) == scaled(screen, (W, H)) + + if Sys.islinux() + # Test that GLMakie is correctly getting the default scale factor from X11 in a + # HiDPI environment. + + checkcmd = `which xrdb` & `which xsettingsd` + checkcmd = pipeline(ignorestatus(checkcmd), stdout = devnull, stderr = devnull) + hasxrdb = success(run(checkcmd)) + + # Only continue if running within an Xvfb environment where the setting is + # empty by default. Overriding during a user's session could be problematic + # (i.e. if running interactively rather than in CI). + inxvfb = hasxrdb ? isempty(readchomp(`xrdb -query`)) : false + + if hasxrdb && inxvfb + # GLFW looks for Xft.dpi resource setting. Spawn a temporary xsettingsd daemon + # to be the X resource manager + xsettingsd = run(pipeline(`xsettingsd -c /dev/null`), wait = false) + try + # Then set the DPI to 192, i.e. 2 times the default of 96dpi + run(pipeline(`echo "Xft.dpi: 192"`, `xrdb -merge`)) + + # Print out the automatically-determined scale factor from the GLScreen + jlscript = raw""" + using GLMakie + fig, ax, pl = scatter(1:2, 3:4) + screen = display(GLMakie.Screen(visible = false), fig) + print(Int(screen.scalefactor[])) + """ + cmd = ``` + $(Base.julia_cmd()) + --project=$(Base.active_project()) + --eval $jlscript + ``` + scalefactor = readchomp(cmd) + @test scalefactor == "2" + finally + # cleanup: kill the daemon before continuing with more tests + kill(xsettingsd) + end + else + @test_broken hasxrdb && inxvfb + end + else + @test_broken Sys.islinux() + end + + GLMakie.closeall() +end diff --git a/MakieCore/Project.toml b/MakieCore/Project.toml index 98b07d16e10..d2ef60aa7e1 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.6.8" +version = "0.7.1" [deps] Observables = "510215fc-4207-5dde-b226-833fc4488ee2" @@ -9,6 +9,7 @@ REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [compat] Observables = "0.5.1" +REPL = "1" julia = "1" [extras] diff --git a/MakieCore/src/attributes.jl b/MakieCore/src/attributes.jl index 2b30965c7fe..aecc9cedfc2 100644 --- a/MakieCore/src/attributes.jl +++ b/MakieCore/src/attributes.jl @@ -26,6 +26,7 @@ node_pairs(pair::Union{Pair, Tuple{Any, Any}}) = (pair[1] => node_any(value_conv node_pairs(pairs) = (node_pairs(pair) for pair in pairs) Attributes(; kw_args...) = Attributes(Dict{Symbol, Observable}(node_pairs(kw_args))) +Attributes(pairs::Dict) = Attributes(Dict{Symbol, Observable}(node_pairs(pairs))) Attributes(pairs::Pair...) = Attributes(Dict{Symbol, Observable}(node_pairs(pairs))) Attributes(pairs::AbstractVector) = Attributes(Dict{Symbol, Observable}(node_pairs.(pairs))) Attributes(pairs::Iterators.Pairs) = Attributes(collect(pairs)) @@ -58,7 +59,15 @@ function Base.deepcopy(attributes::Attributes) end Base.filter(f, x::Attributes) = Attributes(filter(f, attributes(x))) -Base.empty!(x::Attributes) = (empty!(attributes(x)); x) +function Base.empty!(x::Attributes) + attr = attributes(x) + for (key, obs) in attr + Observables.clear(obs) + end + empty!(attr) + return x +end + Base.length(x::Attributes) = length(attributes(x)) function Base.merge!(target::Attributes, args::Attributes...) @@ -78,6 +87,13 @@ function Base.getproperty(x::Union{Attributes, AbstractPlot}, key::Symbol) end end +function Base.setproperty!(x::Union{Attributes,AbstractPlot}, key::Symbol, value::NamedTuple) + x[key] = Attributes(value) +end +function Base.setindex!(x::Attributes, value::NamedTuple, key::Symbol) + return x[key] = Attributes(value) +end + function Base.setproperty!(x::Union{Attributes, AbstractPlot}, key::Symbol, value) if hasfield(typeof(x), key) setfield!(x, key, value) @@ -171,12 +187,12 @@ Base.get(x::AttributeOrPlot, key::Symbol, default) = get(()-> default, x, key) # This is a bit confusing, since for a plot it returns the attribute from the arguments # and not a plot for integer indexing. But, we want to treat plots as "atomic" # so from an interface point of view, one should assume that a plot doesn't contain subplots -# Combined plots break this assumption in some way, but the way to look at it is, -# that the plots contained in a Combined plot are not subplots, but _are_ actually +# Plot plots break this assumption in some way, but the way to look at it is, +# that the plots contained in a Plot plot are not subplots, but _are_ actually # the plot itself. Base.getindex(plot::AbstractPlot, idx::Integer) = plot.converted[idx] Base.getindex(plot::AbstractPlot, idx::UnitRange{<:Integer}) = plot.converted[idx] -Base.setindex!(plot::AbstractPlot, value, idx::Integer) = (plot.input_args[idx][] = value) +Base.setindex!(plot::AbstractPlot, value, idx::Integer) = (plot.args[idx][] = value) Base.length(plot::AbstractPlot) = length(plot.converted) function Base.getindex(x::AbstractPlot, key::Symbol) @@ -248,14 +264,15 @@ function get_attribute(dict, key, default=nothing) end function merge_attributes!(input::Attributes, theme::Attributes) - for (key, value) in theme + for (key, value) in attributes(theme) if !haskey(input, key) input[key] = value else current_value = input[key] - if value isa Attributes && current_value isa Attributes + tvalue = to_value(value) + if tvalue isa Attributes && current_value isa Attributes # if nested attribute, we merge recursively - merge_attributes!(current_value, value) + merge_attributes!(current_value, tvalue) end # we're good! input already has a value, can ignore theme end diff --git a/MakieCore/src/basic_plots.jl b/MakieCore/src/basic_plots.jl index 99381416a82..f0905cac58e 100644 --- a/MakieCore/src/basic_plots.jl +++ b/MakieCore/src/basic_plots.jl @@ -79,15 +79,16 @@ end """ ### 3D shading attributes -- `shading = true` enables lighting. -- `diffuse::Vec3f = Vec3f(0.4)` sets how strongly the red, green and blue channel react to diffuse (scattered) light. -- `specular::Vec3f = Vec3f(0.2)` sets how strongly the object reflects light in the red, green and blue channels. +- `shading = automatic` sets the lighting algorithm used. Options are `NoShading` (no lighting), `FastShading` (AmbientLight + PointLight) or `MultiLightShading` (Multiple lights, GLMakie only). Note that this does not affect RPRMakie. +- `diffuse::Vec3f = Vec3f(1.0)` sets how strongly the red, green and blue channel react to diffuse (scattered) light. +- `specular::Vec3f = Vec3f(0.4)` sets how strongly the object reflects light in the red, green and blue channels. - `shininess::Real = 32.0` sets how sharp the reflection is. +- `backlight::Float32 = 0f0` sets a weight for secondary light calculation with inverted normals. - `ssao::Bool = false` adjusts whether the plot is rendered with ssao (screen space ambient occlusion). Note that this only makes sense in 3D plots and is only applicable with `fxaa = true`. """ function shading_attributes!(attr) - attr[:shading] = true - attr[:diffuse] = 0.4 + attr[:shading] = automatic + attr[:diffuse] = 1.0 attr[:specular] = 0.2 attr[:shininess] = 32.0f0 attr[:backlight] = 0f0 @@ -121,7 +122,7 @@ calculated_attributes!(plot::T) where T = calculated_attributes!(T, plot) image(x, y, image) image(image) -Plots an image on range `x, y` (defaults to dimensions). +Plots an image on a rectangle bounded by `x` and `y` (defaults to size of image). ## Attributes @@ -146,7 +147,8 @@ end heatmap(x, y, values) heatmap(values) -Plots a heatmap as an image on `x, y` (defaults to interpretation as dimensions). +Plots a heatmap as a collection of rectangles centered at `x[i], y[j]` with +colors derived from `values[i, j]`. (Defaults to `x, y = axes(values)`.) ## Attributes @@ -215,11 +217,9 @@ end surface(x, y, z) surface(z) -Plots a surface, where `(x, y)` define a grid whose heights are the entries in `z`. +Plots a surface, where `(x, y)` define a grid whose heights are the entries in `z`. `x` and `y` may be `Vectors` which define a regular grid, **or** `Matrices` which define an irregular grid. -`Surface` has the conversion trait `ContinuousSurface <: SurfaceLike`. - ## Attributes ### Specific to `Surface` @@ -466,7 +466,8 @@ Plots one or multiple texts passed via the `text` keyword. - `strokecolor::Union{Symbol, <:Colorant} = :black` sets the color of the outline around a marker. - `glowwidth::Real = 0` sets the size of a glow effect around the marker. - `glowcolor::Union{Symbol, <:Colorant} = (:black, 0)` sets the color of the glow effect. -- `word_wrap_with::Real = -1` specifies a linewidth limit for text. If a word overflows this limit, a newline is inserted before it. Negative numbers disable word wrapping. +- `word_wrap_width::Real = -1` specifies a linewidth limit for text. If a word overflows this limit, a newline is inserted before it. Negative numbers disable word wrapping. +- `transform_marker::Bool = false` controls whether the model matrix (without translation) applies to the glyph itself, rather than just the positions. (If this is true, `scale!` and `rotate!` will affect the text glyphs.) $(Base.Docs.doc(colormap_attributes!)) @@ -488,7 +489,7 @@ $(Base.Docs.doc(MakieCore.generic_plot_attributes!)) justification = automatic, lineheight = 1.0, markerspace = :pixel, - + transform_marker = false, offset = (0.0, 0.0), word_wrap_width = -1, ) @@ -538,7 +539,7 @@ $(Base.Docs.doc(MakieCore.generic_plot_attributes!)) strokewidth = theme(scene, :patchstrokewidth), linestyle = nothing, - shading = false, + shading = NoShading, fxaa = true, cycle = [:color => :patchcolor], @@ -572,16 +573,11 @@ end colorscale = identity, quality = 32, - inspectable = theme(scene, :inspectable), markerspace = :pixel, - - diffuse=0.4, - specular=0.2, - shininess=32.0f0, - ssao = false ) generic_plot_attributes!(attr) + shading_attributes!(attr) colormap_attributes!(attr, theme(scene, :colormap)) attr[:fxaa] = automatic diff --git a/MakieCore/src/conversion.jl b/MakieCore/src/conversion.jl index 40d3f36839d..2b2b9635d2d 100644 --- a/MakieCore/src/conversion.jl +++ b/MakieCore/src/conversion.jl @@ -29,19 +29,74 @@ struct NoConversion <: ConversionTrait end # No conversion by default conversion_trait(::Type) = NoConversion() +conversion_trait(T::Type, args...) = conversion_trait(T) + convert_arguments(::NoConversion, args...) = args +""" + PointBased() <: ConversionTrait + +Plots with the `PointBased` trait convert their input data to a +`Vector{Point{D, Float32}}`. +""" struct PointBased <: ConversionTrait end conversion_trait(::Type{<: XYBased}) = PointBased() conversion_trait(::Type{<: Text}) = PointBased() -abstract type SurfaceLike <: ConversionTrait end +""" + GridBased <: ConversionTrait + +GridBased is an abstract conversion trait for data that exists on a grid. + +Child types: [`VertexGrid`](@ref), [`CellGrid`](@ref) +See also: [`ImageLike`](@ref) +Used for: Scatter, Lines +""" +abstract type GridBased <: ConversionTrait end + +""" + VertexGrid() <: GridBased <: ConversionTrait + +Plots with the `VertexGrid` trait convert their input data to +`(xs::Vector{Float32}, ys::Vector{Float32}, zs::Matrix{Float32})` such that +`(length(xs), length(ys)) == size(zs)`, or +`(xs::Matrix{Float32}, ys::Matrix{Float32}, zs::Matrix{Float32})` such that +`size(xs) == size(ys) == size(zs)`. -struct ContinuousSurface <: SurfaceLike end -conversion_trait(::Type{<: Union{Surface, Image}}) = ContinuousSurface() +See also: [`CellGrid`](@ref), [`ImageLike`](@ref) +Used for: Surface +""" +struct VertexGrid <: GridBased end +conversion_trait(::Type{<: Surface}) = VertexGrid() + +""" + CellGrid() <: GridBased <: ConversionTrait + +Plots with the `CellGrid` trait convert their input data to +`(xs::Vector{Float32}, ys::Vector{Float32}, zs::Matrix{Float32})` such that +`(length(xs), length(ys)) == size(zs) .+ 1`. After the conversion the x and y +values represent the edges of cells corresponding to z values. + +See also: [`VertexGrid`](@ref), [`ImageLike`](@ref) +Used for: Heatmap +""" +struct CellGrid <: GridBased end +conversion_trait(::Type{<: Heatmap}) = CellGrid() + +""" + ImageLike() <: ConversionTrait + +Plots with the `ImageLike` trait convert their input data to +`(xs::Interval, ys::Interval, zs::Matrix{Float32})` where xs and ys mark the +limits of a quad containing zs. + +See also: [`CellGrid`](@ref), [`VertexGrid`](@ref) +Used for: Image +""" +struct ImageLike <: ConversionTrait end +conversion_trait(::Type{<: Image}) = ImageLike() +# Rect2f(xmin, ymin, xmax, ymax) -struct DiscreteSurface <: SurfaceLike end -conversion_trait(::Type{<: Heatmap}) = DiscreteSurface() struct VolumeLike <: ConversionTrait end conversion_trait(::Type{<: Volume}) = VolumeLike() diff --git a/MakieCore/src/recipes.jl b/MakieCore/src/recipes.jl index e0cc89b5cb9..2e31672853c 100644 --- a/MakieCore/src/recipes.jl +++ b/MakieCore/src/recipes.jl @@ -1,7 +1,7 @@ not_implemented_for(x) = error("Not implemented for $(x). You might want to put: `using Makie` into your code!") to_func_name(x::Symbol) = Symbol(lowercase(string(x))) -# Fallback for Combined ... +# Fallback for Plot ... # Will get overloaded by recipe Macro plotsym(x) = :plot @@ -9,37 +9,35 @@ function func2string(func::F) where F <: Function string(F.name.mt.name) end -plotfunc(::Combined{F}) where F = F +plotfunc(::Plot{F}) where F = F plotfunc(::Type{<: AbstractPlot{Func}}) where Func = Func plotfunc(::T) where T <: AbstractPlot = plotfunc(T) plotfunc(f::Function) = f func2type(x::T) where T = func2type(T) func2type(x::Type{<: AbstractPlot}) = x -func2type(f::Function) = Combined{f} +func2type(f::Function) = Plot{f} plotkey(::Type{<: AbstractPlot{Typ}}) where Typ = Symbol(lowercase(func2string(Typ))) plotkey(::T) where T <: AbstractPlot = plotkey(T) plotkey(::Nothing) = :scatter plotkey(any) = nothing -""" - default_plot_signatures(funcname, funcname!, PlotType) -Creates all the different overloads for `funcname` that need to be supported for the plotting frontend! -Since we add all these signatures to different functions, we make it reusable with this function. -The `Core.@__doc__` macro transfers the docstring given to the Recipe into the functions. -""" -function default_plot_signatures(funcname, funcname!, PlotType) - quote - Core.@__doc__ function ($funcname)(args...; attributes...) - plot($PlotType, args...; attributes...) - end - - Core.@__doc__ function ($funcname!)(args...; attributes...) - plot!($PlotType, args...; attributes...) - end - end -end + +argtypes(::T) where {T <: Tuple} = T + +function create_axis_like end +function create_axis_like! end +function figurelike_return end +function figurelike_return! end + +function _create_plot end +function _create_plot! end + + + +plot(args...; kw...) = _create_plot(plot, Dict{Symbol, Any}(kw), args...) +plot!(args...; kw...) = _create_plot!(plot, Dict{Symbol, Any}(kw), args...) """ Each argument can be named for a certain plot type `P`. Falls back to `arg1`, `arg2`, etc. @@ -53,7 +51,7 @@ function argument_names(::Type{<:AbstractPlot}, num_args::Integer) ntuple(i -> Symbol("arg$i"), num_args) end -# Since we can use Combined like a scene in some circumstances, we define this alias +# Since we can use Plot like a scene in some circumstances, we define this alias theme(x::SceneLike, args...) = theme(x.parent, args...) theme(x::AbstractScene) = x.theme theme(x::AbstractScene, key; default=nothing) = deepcopy(get(x.theme, key, default)) @@ -103,9 +101,9 @@ We use an example to show how this works: This macro expands to several things. Firstly a type definition: - const MyPlot{ArgTypes} = Combined{myplot, ArgTypes} + const MyPlot{ArgTypes} = Plot{myplot, ArgTypes} -The type parameter of `Combined` contains the function instead of e.g. a +The type parameter of `Plot` contains the function instead of e.g. a symbol. This way the mapping from `MyPlot` to `myplot` is safer and simpler. (The downside is we always need a function `myplot` - TODO: is this a problem?) @@ -172,9 +170,10 @@ macro recipe(theme_func, Tsym::Symbol, args::Symbol...) funcname = esc(funcname_sym) expr = quote $(funcname)() = not_implemented_for($funcname) - const $(PlotType){$(esc(:ArgType))} = Combined{$funcname,$(esc(:ArgType))} + const $(PlotType){$(esc(:ArgType))} = Plot{$funcname,$(esc(:ArgType))} $(MakieCore).plotsym(::Type{<:$(PlotType)}) = $(QuoteNode(Tsym)) - $(default_plot_signatures(funcname, funcname!, PlotType)) + Core.@__doc__ ($funcname)(args...; kw...) = _create_plot($funcname, Dict{Symbol, Any}(kw), args...) + ($funcname!)(args...; kw...) = _create_plot!($funcname, Dict{Symbol, Any}(kw), args...) $(MakieCore).default_theme(scene, ::Type{<:$PlotType}) = $(esc(theme_func))(scene) export $PlotType, $funcname, $funcname! end @@ -190,25 +189,37 @@ macro recipe(theme_func, Tsym::Symbol, args::Symbol...) expr end -# Register plot / plot! using the Any type as PlotType. -# This is done so that plot(args...) / plot!(args...) can by default go -# through a pipeline where the appropriate PlotType is determined -# from the input arguments themselves. -eval(default_plot_signatures(:plot, :plot!, :Any)) - """ -Returns the Combined type that represents the signature of `args`. + Plot(args::Vararg{<:DataType,N}) + +Returns the Plot type that represents the signature of `args`. +Example: + +```julia +Plot(Vector{Point2f}) == Plot{plot, Tuple{<:Vector{Point2f}}} +``` +This can be used to more conveniently create recipes for `plot(mytype)` without the recipe macro: + +```julia +struct MyType ... end + +function Makie.plot!(plot::Plot(MyType)) + ... +end + +plot(MyType(...)) +``` """ -function Plot(args::Vararg{Any,N}) where {N} - Combined{Any,<:Tuple{args...}} +function Plot(args::Vararg{DataType,N}) where {N} + Plot{plot, <:Tuple{args...}} end -Base.@pure function Plot(::Type{T}) where {T} - Combined{Any,<:Tuple{T}} +function Plot(::Type{T}) where {T} + Plot{plot, <:Tuple{T}} end -Base.@pure function Plot(::Type{T1}, ::Type{T2}) where {T1,T2} - Combined{Any,<:Tuple{T1,T2}} +function Plot(::Type{T1}, ::Type{T2}) where {T1,T2} + Plot{plot, <:Tuple{T1,T2}} end """ @@ -221,4 +232,4 @@ e.g.: plottype(x::Array{<: AbstractFloat, 3}) = Volume ``` """ -plottype(plot_args...) = Combined{Any, Tuple{typeof.(to_value.(plot_args))...}} # default to dispatch to type recipes! +plottype(plot_args...) = Plot{plot} # default to dispatch to type recipes! diff --git a/MakieCore/src/types.jl b/MakieCore/src/types.jl index 630de518620..e80345d339c 100644 --- a/MakieCore/src/types.jl +++ b/MakieCore/src/types.jl @@ -50,23 +50,41 @@ struct Attributes attributes::Dict{Symbol, Observable} end -struct Combined{Typ, T} <: ScenePlot{Typ} - parent::SceneLike - transformation::Transformable +""" + Plot{PlotFunc}(args::Tuple, kw::Dict{Symbol, Any}) + +Creates a Plot corresponding to the recipe function `PlotFunc`. +Each recipe defines an alias for `Plot{PlotFunc}`. +Example: +```julia +const Scatter = Plot{scatter} # defined in the scatter recipe +Plot{scatter}((1:4,), Dict{Symbol, Any}(:color => :red)) isa Scatter +# Same as: +Scatter((1:4,), Dict{Symbol, Any}(:color => :red)) +``` +""" +mutable struct Plot{PlotFunc, T} <: ScenePlot{PlotFunc} + transformation::Union{Nothing, Transformable} + + # Unprocessed arguments directly from the user command e.g. `plot(args...; kw...)`` + kw::Dict{Symbol,Any} + args::Vector{Any} + + converted::NTuple{N,Observable} where {N} + # Converted and processed arguments attributes::Attributes - input_args::Tuple - converted::Tuple - plots::Vector{AbstractPlot} + + plots::Vector{Plot} deregister_callbacks::Vector{Observables.ObserverFunction} - function Combined{Typ, T}( - parent::SceneLike, transformation::Transformable, attributes::Attributes, - input_args::Tuple, converted::Tuple, plots::Vector{AbstractPlot}) where {Typ, T} - return new(parent, transformation, attributes, input_args, converted, plots, + parent::Union{AbstractScene,Plot} + + function Plot{Typ,T}(kw::Dict{Symbol, Any}, args::Vector{Any}, converted::NTuple{N, Observable}) where {Typ,T,N} + return new{Typ,T}(nothing, kw, args, converted, Attributes(), Plot[], Observables.ObserverFunction[]) end end -function Base.show(io::IO, plot::Combined) +function Base.show(io::IO, plot::Plot) print(io, typeof(plot)) end @@ -117,3 +135,9 @@ end Billboard() = Billboard(0f0) Billboard(angle::Real) = Billboard(Float32(angle)) Billboard(angles::Vector) = Billboard(Float32.(angles)) + +@enum ShadingAlgorithm begin + NoShading + FastShading + MultiLightShading +end diff --git a/NEWS.md b/NEWS.md index ee74c8bd739..81c04563add 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,7 +2,44 @@ ## master -- Fixed a bug where Axis still consumes scroll events when interactions are disabled [#3272](https://github.com/MakieOrg/Makie.jl/pull/3272) +## 0.20.2 + +- Switched from SHA512 to CRC32c salting in CairoMakie svgs, drastically improving svg rendering speed [#3435](https://github.com/MakieOrg/Makie.jl/pull/3435). +- Fixed a bug with h/vlines and h/vspan not correctly resolving transformations [#3418](https://github.com/MakieOrg/Makie.jl/pull/3418). +- Fixed a bug with h/vlines and h/vspan returning the wrong limits, causing an error in Axis [#3427](https://github.com/MakieOrg/Makie.jl/pull/3427). +- Fixed clipping when zooming out of a 3D (L)Scene [#3433](https://github.com/MakieOrg/Makie.jl/pull/3433). + +## 0.20.1 + +- Fixed bad rendering of `poly` in GLMakie by triangulating points after transformations [#3402](https://github.com/MakieOrg/Makie.jl/pull/3402). +- Fixed bug regarding inline display in VSCode Jupyter notebooks and other similar environments [#3403](https://github.com/MakieOrg/Makie.jl/pull/3403). +- Fixed issue with `plottype`, allowed `onany(...; update = true)` and fixed `Block` macro use outside Makie [#3401](https://github.com/MakieOrg/Makie.jl/pull/3401). + +## 0.20 + +- GLMakie has gained support for HiDPI (aka Retina) screens. This also enables saving images with higher resolution than screen pixel dimensions [#2544](https://github.com/MakieOrg/Makie.jl/pull/2544). +- Fixed an issue where NaN was interpreted as zero when rendering `surface` through CairoMakie [#2598](https://github.com/MakieOrg/Makie.jl/pull/2598). +- Improved 3D camera handling, hotkeys and functionality [#2746](https://github.com/MakieOrg/Makie.jl/pull/2746). +- Added `shading = :verbose` in GLMakie to allow for multiple light sources. Also added more light types, fixed light directions for the previous lighting model (now `shading = :fast`) and adjusted `backlight` to affect normals[#3246](https://github.com/MakieOrg/Makie.jl/pull/3246). +- Changed the glyph used for negative numbers in tick labels from hyphen to minus [#3379](https://github.com/MakieOrg/Makie.jl/pull/3379). +- Added new declarative API for AlgebraOfGraphics, Pluto and easier dashboards [#3281](https://github.com/MakieOrg/Makie.jl/pull/3281). +- WGLMakie got faster line rendering with less updating bugs [#3062](https://github.com/MakieOrg/Makie.jl/pull/3062). +- **Breaking** Replaced `PolarAxis.radial_distortion_threshold` with `PolarAxis.radius_at_origin`. [#3381](https://github.com/MakieOrg/Makie.jl/pull/3381) +- **Breaking** Deprecated the `resolution` keyword in favor of `size` to reflect that this value is not a pixel resolution anymore [#3343](https://github.com/MakieOrg/Makie.jl/pull/3343). +- **Breaking** Refactored the `SurfaceLike` family of traits into `VertexGrid`, `CellGrid` and `ImageLike` [#3106](https://github.com/MakieOrg/Makie.jl/pull/3106). +- **Breaking** Deprecated `pixelarea(scene)` and `scene.px_area` in favor of viewport. +- **Breaking** Refactored the `Combined` Plot object and renamed it to `Plot`, improving compile times ~2x [#3082](https://github.com/MakieOrg/Makie.jl/pull/3082). +- **Breaking** Removed old depreactions in [#3113](https://github.com/MakieOrg/Makie.jl/pull/3113/commits/3a39210ef87a0032d78cb27c0c1019faa604effd). +- **Breaking** Deprecated using AbstractVector as sides of `image` [#3395](https://github.com/MakieOrg/Makie.jl/pull/3395). +- **Breaking** `errorbars` and `rangebars` now use color cycling [#3230](https://github.com/MakieOrg/Makie.jl/pull/3230). + +## v0.19.12 + +- Added `cornerradius` attribute to `Box` for rounded corners [#3346](https://github.com/MakieOrg/Makie.jl/pull/3346). +- Fix grouping of a zero-height bar in `barplot`. Now a zero-height bar shares the same properties of the previous bar, and if the bar is the first one, its height is treated as positive if and only if there exists a bar of positive height or all bars are zero-height [#3058](https://github.com/MakieOrg/Makie.jl/pull/3058). +- Fixed a bug where Axis still consumes scroll events when interactions are disabled [#3272](https://github.com/MakieOrg/Makie.jl/pull/3272). +- Added `cornerradius` attribute to `Box` for rounded corners [#3308](https://github.com/MakieOrg/Makie.jl/pull/3308). +- Upgraded `StableHashTraits` from 1.0 to 1.1 [#3309](https://github.com/MakieOrg/Makie.jl/pull/3309). ## v0.19.11 @@ -12,9 +49,9 @@ ## v0.19.10 -- Fix bugs with Colorbar in recipes, add new API for creating a recipe colorbar and introduce experimental support for Categorical colormaps [#3090](https://github.com/MakieOrg/Makie.jl/pull/3090). -- Add experimental Datashader implementation [#2883](https://github.com/MakieOrg/Makie.jl/pull/2883). -- [Breaking] Changed the default order Polar arguments to (theta, r). [#3154](https://github.com/MakieOrg/Makie.jl/pull/3154) +- Fixed bugs with Colorbar in recipes, add new API for creating a recipe colorbar and introduce experimental support for Categorical colormaps [#3090](https://github.com/MakieOrg/Makie.jl/pull/3090). +- Added experimental Datashader implementation [#2883](https://github.com/MakieOrg/Makie.jl/pull/2883). +- **Breaking** Changed the default order Polar arguments to (theta, r). [#3154](https://github.com/MakieOrg/Makie.jl/pull/3154) - General improvements to `PolarAxis`: full rlimtis & thetalimits, more controls and visual tweaks. See pr for more details.[#3154](https://github.com/MakieOrg/Makie.jl/pull/3154) ## v0.19.9 @@ -57,7 +94,7 @@ - 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) +- Fixed 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). diff --git a/Project.toml b/Project.toml index 8a8b9ca4b31..6b3054981dd 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.19.11" +version = "0.20.2" [deps] Animations = "27a7e980-b3e6-11e9-2bcd-0b925532e340" @@ -18,6 +18,7 @@ DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" FFMPEG_jll = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" +FilePaths = "8fc22ac5-c921-52a6-82fd-178b2807b824" FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" Formatting = "59287772-0a20-5a39-b81b-1366585eb4c0" FreeType = "b38be410-82b0-50bf-ab77-7b57e271db43" @@ -34,7 +35,6 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" -Match = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf" MathTeXEngine = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53" Observables = "510215fc-4207-5dde-b226-833fc4488ee2" OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" @@ -61,6 +61,8 @@ UnicodeFun = "1cfade01-22cf-5700-b092-accc4b62d6e1" [compat] Animations = "0.4" +Base64 = "1.0, 1.6" +CRC32c = "1.0, 1.6" ColorBrewer = "0.4" ColorSchemes = "3.5" ColorTypes = "0.8, 0.9, 0.10, 0.11" @@ -69,34 +71,43 @@ Contour = "0.5, 0.6" DelaunayTriangulation = "0.8.7" Distributions = "0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25" DocStringExtensions = "0.8, 0.9" +Downloads = "1, 1.6" FileIO = "1.6" +FilePaths = "0.8" FixedPointNumbers = "0.6, 0.7, 0.8" Formatting = "0.4" FreeType = "3.0, 4.0" FreeTypeAbstraction = "0.10" GeometryBasics = "0.4.2" -GridLayoutBase = "0.9" +GridLayoutBase = "0.10" ImageIO = "0.2, 0.3, 0.4, 0.5, 0.6" +InteractiveUtils = "1.0, 1.6" IntervalSets = "0.3, 0.4, 0.5, 0.6, 0.7" Isoband = "0.1" KernelDensity = "0.5, 0.6" LaTeXStrings = "1.2" +LinearAlgebra = "1.0, 1.6" MacroTools = "0.5" -MakieCore = "=0.6.8" -Match = "1.1" +MakieCore = "=0.7.1" +Markdown = "1.0, 1.6" MathTeXEngine = "0.5" -Observables = "0.5.3" +Observables = "0.5.5" OffsetArrays = "1" Packing = "0.5" PlotUtils = "1" PolygonOps = "0.1.1" PrecompileTools = "1.0" +Printf = "1.0, 1.6" +REPL = "1.0, 1.6" +Random = "1.0, 1.6" RelocatableFolders = "0.1, 0.2, 0.3, 1.0" Setfield = "1" ShaderAbstractions = "0.4" Showoff = "0.3, 1.0.2" SignedDistanceFields = "0.4" -StableHashTraits = "1" +SparseArrays = "1.0, 1.6" +StableHashTraits = "1.1" +Statistics = "1, 1.6" StatsBase = "0.31, 0.32, 0.33, 0.34" StatsFuns = "0.9, 1.0" StructArrays = "0.3, 0.4, 0.5, 0.6" diff --git a/README.md b/README.md index 49c5a3ccaa1..7862f843e68 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ [![JOSS][joss-img]][joss-url] [![Citation Badge](https://api.juleskreuer.eu/citation-badge.php?doi=10.21105/joss.03349)](https://juleskreuer.eu/projekte/citation-badge) -[![](https://img.shields.io/badge/Twitter-@MakiePlots-1DA1F2?&logo=twitter&logoColor=white)](https://twitter.com/MakiePlots) +[![Mastodon](https://img.shields.io/badge/-mastodon-%232B90D9?style=for-the-badge&logo=mastodon&logoColor=white)](https://julialang.social/@makie) + [![chat][discord-img]][discord-url] @@ -136,7 +137,7 @@ The following examples are supposed to be self-explanatory. For further informat x = 1:0.1:10 fig = lines(x, x.^2; label = "Parabola", axis = (; xlabel = "x", ylabel = "y", title ="Title"), - figure = (; resolution = (800,600), fontsize = 22)) + figure = (; size = (800,600), fontsize = 22)) axislegend(; position = :lt) save("./assets/parabola.png", fig) fig @@ -167,8 +168,8 @@ with_theme(palette = (; patchcolor = cgrad(cmap, alpha=0.45))) do band!(x, sin.(x), approx .+= x .^ 5 / 120; label = L"n = 2") band!(x, sin.(x), approx .+= -x .^ 7 / 5040; label = L"n = 3") limits!(-3.8, 3.8, -1.5, 1.5) - axislegend(; position = :ct, bgcolor = (:white, 0.75), framecolor = :orange) - save("./assets/approxsin.png", fig, resolution = (800, 600)) + axislegend(; position = :ct, backgroundcolor = (:white, 0.75), framecolor = :orange) + save("./assets/approxsin.png", fig, size = (800, 600)) fig end ``` diff --git a/RPRMakie/Project.toml b/RPRMakie/Project.toml index ae7c328a880..42d94c21f05 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.5.11" +version = "0.6.2" [deps] Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" @@ -13,12 +13,14 @@ Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" RadeonProRender = "27029320-176d-4a42-b57d-56729d2ad457" [compat] -julia = "1.3" Colors = "0.9, 0.10, 0.11, 0.12" FileIO = "1.6" GeometryBasics = "0.4.1" -Makie = "=0.19.11" +Makie = "=0.20.2" RadeonProRender = "0.3.0" +julia = "1.3" +LinearAlgebra = "1.0, 1.6" +Printf = "1.0, 1.6" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/RPRMakie/examples/bars.jl b/RPRMakie/examples/bars.jl index a6be9abe0e6..993be72e3eb 100644 --- a/RPRMakie/examples/bars.jl +++ b/RPRMakie/examples/bars.jl @@ -3,7 +3,7 @@ using Colors, FileIO, ImageShow using Colors: N0f8 RPRMakie.activate!(plugin=RPR.Northstar, resource=RPR.GPU0) -fig = Figure(; resolution=(800, 600), fontsize=26) +fig = Figure(; size=(800, 600), fontsize=26) radiance = 10000 lights = [EnvironmentLight(0.5, load(RPR.assetpath("studio026.exr"))), PointLight(Vec3f(0, 0, 20), RGBf(radiance, radiance, radiance))] diff --git a/RPRMakie/examples/eart_topographie_sphere.jl b/RPRMakie/examples/eart_topographie_sphere.jl index 6bef6b10abc..e02ee0a2fc9 100644 --- a/RPRMakie/examples/eart_topographie_sphere.jl +++ b/RPRMakie/examples/eart_topographie_sphere.jl @@ -39,7 +39,7 @@ xetopo, yetopo, zetopo = lonlat3D(lonext, lat, dataext) begin r = 30 lights = [PointLight(Vec3f(2, 1, 3), RGBf(r, r, r))] - fig = Figure(; resolution=(1200, 1200), backgroundcolor=:black) + fig = Figure(; size=(1200, 1200), backgroundcolor=:black) ax = LScene(fig[1, 1]; show_axis=false)#, scenekw=(lights=lights,)) pltobj = surface!(ax, xetopo, yetopo, zetopo; color=dataext, colormap=:hot, colorrange=(-6000, 5000)) cam = cameracontrols(ax.scene) diff --git a/RPRMakie/examples/earth_topography.jl b/RPRMakie/examples/earth_topography.jl index 7f52cc43ca2..ceaf99ef70a 100644 --- a/RPRMakie/examples/earth_topography.jl +++ b/RPRMakie/examples/earth_topography.jl @@ -28,7 +28,7 @@ function glow_material(data_normed) end RPRMakie.activate!(iterations=32, plugin=RPR.Northstar) -fig = Figure(; resolution=(2000, 800)) +fig = Figure(; size=(2000, 800)) radiance = 30000 lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), PointLight(Vec3f(0, 100, 100), RGBf(radiance, radiance, radiance))] diff --git a/RPRMakie/examples/lego.jl b/RPRMakie/examples/lego.jl index cb364038271..fa9956c947d 100644 --- a/RPRMakie/examples/lego.jl +++ b/RPRMakie/examples/lego.jl @@ -69,7 +69,7 @@ lights = [ EnvironmentLight(1.5, rotl90(load(assetpath("sunflowers_1k.hdr"))')), PointLight(Vec3f(50, 0, 200), RGBf(radiance, radiance, radiance*1.1)), ] -s = Scene(resolution=(500, 500), lights=lights) +s = Scene(size=(500, 500), lights=lights) cam3d!(s) c = cameracontrols(s) diff --git a/RPRMakie/examples/lines.jl b/RPRMakie/examples/lines.jl index b3f2624e7f9..2fed509dc2d 100644 --- a/RPRMakie/examples/lines.jl +++ b/RPRMakie/examples/lines.jl @@ -12,7 +12,7 @@ function box!(ax, size) end begin - fig = Figure(; resolution=(1000, 1000)) + fig = Figure(; size=(1000, 1000)) radiance = 100 lights = Makie.AbstractLight[PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1))] ax = LScene(fig[1, 1]; scenekw=(; lights=lights), show_axis=false) diff --git a/RPRMakie/examples/material_x.jl b/RPRMakie/examples/material_x.jl index 415f87c7e7a..757fd825c90 100644 --- a/RPRMakie/examples/material_x.jl +++ b/RPRMakie/examples/material_x.jl @@ -7,7 +7,7 @@ img = begin radiance = 1000 lights = [EnvironmentLight(0.5, load(RPR.assetpath("studio026.exr"))), PointLight(Vec3f(5), RGBf(radiance, radiance, radiance * 1.1))] - fig = Figure(; resolution=(1500, 700)) + fig = Figure(; size=(1500, 700)) ax = LScene(fig[1, 1]; show_axis=false, scenekw=(lights=lights,)) screen = RPRMakie.Screen(ax.scene; plugin=RPR.Northstar, iterations=500, resource=RPR.GPU0) matsys = screen.matsys diff --git a/RPRMakie/examples/materials.jl b/RPRMakie/examples/materials.jl index ccdcb2209d7..80f7d9a0f2e 100644 --- a/RPRMakie/examples/materials.jl +++ b/RPRMakie/examples/materials.jl @@ -6,7 +6,7 @@ img = begin radiance = 500 lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1))] - fig = Figure(; resolution=(1500, 700)) + fig = Figure(; size=(1500, 700)) ax = LScene(fig[1, 1]; show_axis=false, scenekw=(lights=lights,)) screen = RPRMakie.Screen(ax.scene; plugin=RPR.Northstar, iterations=1000) diff --git a/RPRMakie/examples/opengl_interop.jl b/RPRMakie/examples/opengl_interop.jl index 04e7c2ccd10..6141b833658 100644 --- a/RPRMakie/examples/opengl_interop.jl +++ b/RPRMakie/examples/opengl_interop.jl @@ -11,9 +11,9 @@ radiance = 500 lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1))] -fig = Figure(; resolution=(1500, 1000)) +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_GPU1) +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, @@ -81,11 +81,12 @@ GLMakie.activate!(inline=false) display(fig; inline=false, backend=GLMakie) RPRMakie.activate!(iterations=1, plugin=RPR.Northstar, resource=RPR.GPU0) context, task = RPRMakie.replace_scene_rpr!(ax.scene, screen; refresh=refresh); +nothing # Change light parameters interactively -begin - lights[1].intensity[] = 1.5 - lights[2].radiance[] = RGBf(1000, 1000, 1000) - lights[2].position[] = Vec3f(3, 10, 10) - notify(refresh) -end +# begin +# lights[1].intensity[] = 1.5 +# lights[2].radiance[] = RGBf(1000, 1000, 1000) +# lights[2].position[] = Vec3f(3, 10, 10) +# notify(refresh) +# end diff --git a/RPRMakie/examples/sea_cables.jl b/RPRMakie/examples/sea_cables.jl index 5e1185b3653..0f78515347f 100644 --- a/RPRMakie/examples/sea_cables.jl +++ b/RPRMakie/examples/sea_cables.jl @@ -50,7 +50,7 @@ earth_img = load(Downloads.download("https://upload.wikimedia.org/wikipedia/comm # the actual plot ! RPRMakie.activate!(; iterations=100) scene = with_theme(theme_dark()) do - fig = Figure(; resolution=(1000, 1000)) + fig = Figure(; size=(1000, 1000)) radiance = 30 lights = [EnvironmentLight(0.5, load(RPR.assetpath("starmap_4k.tif"))), PointLight(Vec3f(1, 1, 3), RGBf(radiance, radiance, radiance))] diff --git a/RPRMakie/examples/volume.jl b/RPRMakie/examples/volume.jl index 7c4a86ddb63..c44b59b7dc1 100644 --- a/RPRMakie/examples/volume.jl +++ b/RPRMakie/examples/volume.jl @@ -8,7 +8,7 @@ brain = Float32.(niread(Makie.assetpath("brain.nii.gz")).raw) radiance = 5000 lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1))] -fig = Figure(; resolution=(1000, 1000)) +fig = Figure(; size=(1000, 1000)) ax = LScene(fig[1, 1]; show_axis=false, scenekw=(lights=lights,)) Makie.volume!(ax, 0..3, 0..3.78, 0..3.18, brain, algorithm=:absorption, absorption=0.3) display(ax.scene; iterations=5000) diff --git a/RPRMakie/src/RPRMakie.jl b/RPRMakie/src/RPRMakie.jl index 74bf5fc7d4d..b83ae20599e 100644 --- a/RPRMakie/src/RPRMakie.jl +++ b/RPRMakie/src/RPRMakie.jl @@ -34,11 +34,16 @@ function ScreenConfig(iterations::Int, max_recursion::Int, render_resource, rend ) end + + include("scene.jl") include("lines.jl") include("meshes.jl") include("volume.jl") +Makie.apply_screen_config!(screen::RPRMakie.Screen, ::RPRMakie.ScreenConfig, args...) = screen +Base.empty!(::RPRMakie.Screen) = nothing + """ RPRMakie.activate!(; screen_config...) diff --git a/RPRMakie/src/lines.jl b/RPRMakie/src/lines.jl index a6c91665dd4..5f85f8db0c3 100644 --- a/RPRMakie/src/lines.jl +++ b/RPRMakie/src/lines.jl @@ -31,7 +31,9 @@ function to_rpr_object(context, matsys, scene, plot::Makie.Lines) end function to_rpr_object(context, matsys, scene, plot::Makie.LineSegments) - points = decompose(Point3f, to_value(plot[1])) + arg1 = to_value(plot[1]) + isempty(arg1) && return nothing + points = decompose(Point3f, arg1) segments = TupleView{2,2}(RPR.rpr_int(0):RPR.rpr_int(length(points) - 1)) indices = RPR.rpr_int[] diff --git a/RPRMakie/src/meshes.jl b/RPRMakie/src/meshes.jl index 2c3c8af71d3..43bb3862d17 100644 --- a/RPRMakie/src/meshes.jl +++ b/RPRMakie/src/meshes.jl @@ -1,5 +1,5 @@ function extract_material(matsys, plot) - material = if haskey(plot, :material) + if haskey(plot, :material) if plot.material isa Attributes return RPR.Material(matsys, Dict(map(((k,v),)-> k => to_value(v), plot.material))) else @@ -11,26 +11,25 @@ function extract_material(matsys, plot) end function mesh_material(context, matsys, plot, color_obs = plot.color) - specular = plot.specular[] - shininess = plot.shininess[] color = to_value(color_obs) color_signal = if color isa AbstractMatrix{<:Number} tex = RPR.ImageTextureMaterial(matsys) - map(color_obs, plot.colormap, plot.colorrange) do color, cmap, crange - color_interp = Makie.interpolated_getindex.((to_colormap(cmap),), color, (crange,)) + calc_color = to_value(plot.calculated_colors) + lift(plot, color_obs, plot.colormap, plot.colorrange) do color, cmap, crange + color_interp = to_color(calc_color) img = RPR.Image(context, collect(color_interp')) tex.data = img return tex end elseif color isa AbstractMatrix{<:Colorant} tex = RPR.ImageTextureMaterial(matsys) - map(color_obs) do color + lift(plot, color_obs) do color img = RPR.Image(context, Makie.el32convert(color')) tex.data = img return tex end elseif color isa Colorant || color isa Union{String,Symbol} - map(to_color, color_obs) + lift(to_color, plot, color_obs) elseif color isa Nothing # ignore! color_obs @@ -39,7 +38,7 @@ function mesh_material(context, matsys, plot, color_obs = plot.color) end material = extract_material(matsys, plot) - map(color_signal) do color + on(plot, color_signal; update=true) do color if !isnothing(color) && hasproperty(material, :color) material.color = color end @@ -76,11 +75,9 @@ function to_rpr_object(context, matsys, scene, plot::Makie.MeshScatter) push!(instances, inst) end - color = to_color(plot.color[]) - if color isa AbstractVector{<:Number} - cmap = to_colormap(plot.colormap[]) - crange = plot.colorrange[] - color_from_num = Makie.interpolated_getindex.((cmap,), color, (crange,)) + color = plot.calculated_colors[] + if color isa Makie.ColorMapping + color_from_num = to_color(color) object_id = RPR.InputLookupMaterial(matsys) object_id.value = RPR.RPR_MATERIAL_NODE_LOOKUP_OBJECT_ID @@ -90,9 +87,7 @@ function to_rpr_object(context, matsys, scene, plot::Makie.MeshScatter) material.color = tex elseif color isa AbstractMatrix{<:Number} - cmap = to_colormap(plot.colormap[]) - crange = plot.colorrange[] - color_from_num = Makie.interpolated_getindex.((cmap,), color, (crange,)) + color_from_num = to_color(color) object_id = RPR.InputLookupMaterial(matsys) object_id.value = RPR.RPR_MATERIAL_NODE_LOOKUP_OBJECT_ID @@ -140,8 +135,8 @@ function to_rpr_object(context, matsys, scene, plot::Makie.Surface) z = plot[3] function grid(x, y, z, trans) + space = to_value(get(plot, :space, :data)) g = map(CartesianIndices(z)) do i - space = to_value(get(plot, :space, :data)) p = Point3f(Makie.get_dim(x, i, 1, size(z)), Makie.get_dim(y, i, 2, size(z)), z[i]) return Makie.apply_transform(trans, p, space) end diff --git a/RPRMakie/src/scene.jl b/RPRMakie/src/scene.jl index 07e2d491961..1e85771e6e2 100644 --- a/RPRMakie/src/scene.jl +++ b/RPRMakie/src/scene.jl @@ -26,7 +26,7 @@ function to_rpr_object(context, matsys, scene, plot) return nothing end -function insert_plots!(context, matsys, scene, mscene::Makie.Scene, @nospecialize(plot::Combined)) +function insert_plots!(context, matsys, scene, mscene::Makie.Scene, @nospecialize(plot::Plot)) if isempty(plot.plots) # if no plots inserted, this truly is an atomic object = to_rpr_object(context, matsys, mscene, plot) if !isnothing(object) @@ -43,26 +43,87 @@ function insert_plots!(context, matsys, scene, mscene::Makie.Scene, @nospecializ end end -function to_rpr_light(context::RPR.Context, light::Makie.PointLight) +to_rpr_light(ctx, rpr_scene, light, scene) = to_rpr_light(ctx, rpr_scene, light) + +# TODO attenuation +function to_rpr_light(context::RPR.Context, matsys, light::Makie.PointLight) pointlight = RPR.PointLight(context) map(light.position) do pos transform!(pointlight, Makie.translationmatrix(pos)) end - map(light.radiance) do r - setradiantpower!(pointlight, red(r), green(r), blue(r)) + map(light.color) do c + setradiantpower!(pointlight, red(c), green(c), blue(c)) end return pointlight end -function to_rpr_light(context::RPR.Context, light::Makie.AmbientLight) +# TODO: Move to RadeonProRender.jl +function RPR.RPR.rprContextCreateSpotLight(context) + out_light = Ref{RPR.rpr_light}() + RPR.RPR.rprContextCreateSpotLight(context, out_light) + return out_light[] +end + +function to_rpr_light(context::RPR.Context, rpr_scene, light::Makie.DirectionalLight, scene) + directionallight = RPR.DirectionalLight(context) + map(light.direction) do dir + if light.camera_relative + T = inv(scene.camera.view[][Vec(1,2,3), Vec(1,2,3)]) + dir = normalize(T * dir) + else + dir = normalize(dir) + end + quart = Makie.rotation_between(dir, Vec3f(0,0,-1)) + transform!(directionallight, Makie.rotationmatrix4(quart)) + end + map(light.color) do c + setradiantpower!(directionallight, red(c), green(c), blue(c)) + end + return directionallight +end + +function to_rpr_light(context::RPR.Context, rpr_scene, light::Makie.RectLight) + mesh = lift(light.position, light.u1, light.u2) do center, u1, u2 + pos = center - 0.5u1 - 0.5u2 + points = Point3f[pos, pos + u1, pos + u1 + u2, pos + u2] + faces = [GLTriangleFace(1, 2, 3), GLTriangleFace(1, 3, 4)] + return GeometryBasics.Mesh(points, faces) + end + rpr_mesh = RPR.Shape(context, mesh[]) env_img = fill(light.color[], 1, 1) img = RPR.Image(context, env_img) env_light = RPR.EnvironmentLight(context) set!(env_light, img) + setintensityscale!(env_light, 0.1) + # TODO, this doesn't seem to properly create a rectangular portal -.- + setportal!(rpr_scene, env_light, rpr_mesh) return env_light end -function to_rpr_light(context::RPR.Context, light::Makie.EnvironmentLight) +function to_rpr_light(context::RPR.Context, rpr_scene, light::Makie.SpotLight) + spotlight = RPR.SpotLight(context) + map(light.position, light.direction) do pos, dir + quart = Makie.rotation_between(dir, Vec3f(0,0,-1)) + transform!(spotlight, Makie.translationmatrix(pos) * Makie.rotationmatrix4(quart)) + end + map(light.color) do c + setradiantpower!(spotlight, red(c), green(c), blue(c)) + end + map(light.angles) do (inner, outer) + RadeonProRender.RPR.rprSpotLightSetConeShape(spotlight, inner, outer) + end + return spotlight +end + +function to_rpr_light(context::RPR.Context, rpr_scene, light::Makie.AmbientLight) + env_img = fill(light.color[], 1, 1) + img = RPR.Image(context, env_img) + env_light = RPR.EnvironmentLight(context) + set!(env_light, img) + return env_light +end + +function to_rpr_light(context::RPR.Context, rpr_scene, light::Makie.EnvironmentLight) env_light = RPR.EnvironmentLight(context) last_img = RPR.Image(context, light.image[]) set!(env_light, last_img) @@ -90,7 +151,7 @@ function to_rpr_scene(context::RPR.Context, matsys, mscene::Makie.Scene) RPR.rprSceneSetBackgroundImage(scene, img) end for light in mscene.lights - rpr_light = to_rpr_light(context, light) + rpr_light = to_rpr_light(context, scene, light, mscene) push!(scene, rpr_light) end @@ -120,23 +181,31 @@ function replace_scene_rpr!(scene::Makie.Scene, screen=Screen(scene); refresh=Ob # translate!(im, 0, 0, 1000) - clear = true + clear = Threads.Atomic{Bool}(true) onany(refresh, cam.projectionview) do _, _ - clear = true + clear[] = true return end RPR.rprContextSetParameterByKey1u(context, RPR.RPR_CONTEXT_ITERATIONS, 1) cam_values = (;) + task = @async while isopen(scene) + t = time() cam_values = update_rpr_camera!(cam_values, camera, cam_controls, cam) - framebuffer2 = render(screen; clear=clear, iterations=1) - if clear - clear = false + framebuffer2 = render(screen; clear=clear[], iterations=1) + if clear[] + clear[] = false end data = RPR.get_data(framebuffer2) im[1] = reverse(reshape(data, screen.fb_size); dims=2) - sleep(1/10) + tframe = time() - t + to_sleep = (1/10) - tframe + if to_sleep < 0.0 + yield() + else + sleep(to_sleep) + end end return context, task, rpr_scene end @@ -184,12 +253,12 @@ function Makie.apply_screen_config!(screen::Screen, config::ScreenConfig) end function Screen(fb_size::NTuple{2,<:Integer}; screen_config...) - config = Makie.merge_screen_config(ScreenConfig, screen_config) + config = Makie.merge_screen_config(ScreenConfig, Dict{Symbol, Any}(screen_config)) return Screen(fb_size, config) end function Screen(scene::Scene; screen_config...) - config = Makie.merge_screen_config(ScreenConfig, screen_config) + config = Makie.merge_screen_config(ScreenConfig, Dict{Symbol, Any}(screen_config)) return Screen(scene, config) end diff --git a/RPRMakie/test/lines.jl b/RPRMakie/test/lines.jl index e36c4698486..9dba114232c 100644 --- a/RPRMakie/test/lines.jl +++ b/RPRMakie/test/lines.jl @@ -12,7 +12,7 @@ begin emissive = RPR.EmissiveMaterial(matsys) diffuse = RPR.DiffuseMaterial(matsys) - fig = Figure(resolution=(1000, 1000)) + fig = Figure(size=(1000, 1000)) ax = LScene(fig[1, 1], show_axis=false) for i in 4:4:12 n = i + 1 diff --git a/ReferenceTests/src/database.jl b/ReferenceTests/src/database.jl index 7db2c8eafb7..090a6ada7be 100644 --- a/ReferenceTests/src/database.jl +++ b/ReferenceTests/src/database.jl @@ -33,17 +33,26 @@ macro reference_test(name, code) if $skip @test_broken false else + t1 = time() if $title in $REGISTERED_TESTS error("title must be unique. Duplicate title: $(title)") end println("running $(lpad(COUNTER[] += 1, 3)): $($title)") - Makie.set_theme!(resolution=(500, 500)) + Makie.set_theme!(; size=(500, 500), + CairoMakie=(; px_per_unit=1), + GLMakie=(; scalefactor=1, px_per_unit=1), + WGLMakie=(; scalefactor=1, px_per_unit=1)) ReferenceTests.RNG.seed_rng!() result = let $(esc(code)) end @test save_result(joinpath(RECORDING_DIR[], $title), result) push!($REGISTERED_TESTS, $title) + elapsed = round(time() - t1; digits=5) + total = Sys.total_memory() + mem = round((total - Sys.free_memory()) / 10^9; digits=3) + # TODO, write to file and create an overview in the end, similar to the benchmark results! + println("Used $(mem)gb of $(round(total / 10^9; digits=3))gb RAM, time: $(elapsed)s") end end end diff --git a/ReferenceTests/src/tests/attributes.jl b/ReferenceTests/src/tests/attributes.jl index 845a1d3e7e0..5b89c3d86bd 100644 --- a/ReferenceTests/src/tests/attributes.jl +++ b/ReferenceTests/src/tests/attributes.jl @@ -27,7 +27,7 @@ end end @reference_test "shading" begin - mesh(Sphere(Point3f(0), 1f0), color=:orange, shading=false) + mesh(Sphere(Point3f(0), 1f0), color=:orange, shading=NoShading) end @reference_test "visible" begin diff --git a/ReferenceTests/src/tests/examples2d.jl b/ReferenceTests/src/tests/examples2d.jl index 225bc4a6249..8cc85e7e075 100644 --- a/ReferenceTests/src/tests/examples2d.jl +++ b/ReferenceTests/src/tests/examples2d.jl @@ -13,7 +13,7 @@ end end @reference_test "heatmap_interpolation" begin - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) data = RNG.rand(32, 32) # the grayscale heatmap hides the problem that interpolation based on values # in GLMakie looks different than interpolation based on colors in CairoMakie @@ -110,7 +110,7 @@ end 5 8 9; ] color = [0.0, 0.0, 0.0, 0.0, -0.375, 0.0, 0.0, 0.0, 0.0] - fig, ax, meshplot = mesh(coordinates, connectivity, color=color, shading=false) + fig, ax, meshplot = mesh(coordinates, connectivity, color=color, shading=NoShading) wireframe!(ax, meshplot[1], color=(:black, 0.6), linewidth=3) fig end @@ -118,7 +118,7 @@ end @reference_test "colored triangle" begin mesh( [(0.0, 0.0), (0.5, 1.0), (1.0, 0.0)], color=[:red, :green, :blue], - shading=false + shading=NoShading ) end @@ -360,7 +360,7 @@ end @reference_test "Simple pie chart" begin - fig = Figure(resolution=(800, 800)) + fig = Figure(size=(800, 800)) pie(fig[1, 1], 1:5, color=collect(1:5), axis=(;aspect=DataAspect())) fig end @@ -420,7 +420,7 @@ end @reference_test "space 2D" begin # This should generate a regular grid with text in a circle in a box. All # sizes and positions are scaled to be equal across all options. - fig = Figure(resolution = (700, 700)) + fig = Figure(size = (700, 700)) ax = Axis(fig[1, 1], width = 600, height = 600) spaces = (:data, :pixel, :relative, :clip) xs = [ @@ -435,7 +435,7 @@ end s = 1.5scales[i] mesh!( ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), space = space, - shading = false, color = :blue) + shading = NoShading, color = :blue) lines!( ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), space = space, linewidth = 2, color = :red) @@ -462,7 +462,7 @@ end # - (x -> data) row should have stretched circle and text ain x direction # - (not data -> data) should keep aspect ratio for mesh and lines # - (data -> x) should be slightly missaligned with (not data -> x) - fig = Figure(resolution = (700, 700)) + fig = Figure(size = (700, 700)) ax = Axis(fig[1, 1], width = 600, height = 600) spaces = (:data, :pixel, :relative, :clip) xs = [ @@ -477,7 +477,7 @@ end s = 1.5scales[i] mesh!( ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), space = space, - shading = false, color = :blue) + shading = NoShading, color = :blue) lines!( ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), space = space, linewidth = 2, color = :red) @@ -496,7 +496,7 @@ end @reference_test "Scatter & Text transformations" begin # Check that transformations apply in `space = :data` fig, ax, p = scatter(Point2f(100, 0.5), marker = 'a', markersize=50) - t = text!(Point2f(100, 0.5), text = "Test", fontsize = 50) + t = text!(Point2f(100, 0.5), text = "Test", fontsize = 50, transform_marker=true) translate!(p, -100, 0, 0) translate!(t, -100, 0, 0) @@ -506,7 +506,7 @@ end scale!(p2, 0.5, 0.5, 1) # but do act on glyphs of text - t2 = text!(ax, 1, 0, text = "Test", fontsize = 50) + t2 = text!(ax, 1, 0, text = "Test", fontsize = 50, transform_marker=true) Makie.rotate!(t2, pi/4) scale!(t2, 0.5, 0.5, 1) @@ -530,11 +530,11 @@ end end @reference_test "2D surface with explicit color" begin - surface(1:10, 1:10, ones(10, 10); color = [RGBf(x*y/100, 0, 0) for x in 1:10, y in 1:10], shading = false) + surface(1:10, 1:10, ones(10, 10); color = [RGBf(x*y/100, 0, 0) for x in 1:10, y in 1:10], shading = NoShading) end @reference_test "heatmap and image colormap interpolation" begin - f = Figure(resolution=(500, 500)) + f = Figure(size=(500, 500)) crange = LinRange(0, 255, 10) len = length(crange) img = zeros(Float32, len, len + 2) @@ -561,7 +561,7 @@ end n = 100 categorical = [false, true] scales = [exp, identity, log, log10] - fig = Figure(resolution = (500, 250)) + fig = Figure(size = (500, 250)) ax = Axis(fig[1, 1]) for (i, cat) in enumerate(categorical) for (j, scale) in enumerate(scales) @@ -580,7 +580,7 @@ end @reference_test "colormap with specific values" begin cmap = cgrad([:black,:white,:orange],[0,0.2,1]) - fig = Figure(resolution=(400,200)) + fig = Figure(size=(400,200)) ax = Axis(fig[1,1]) x = range(0,1,length=50) scatter!(fig[1,1],Point2.(x,fill(0.,50)),color=x,colormap=cmap) @@ -633,7 +633,7 @@ end @reference_test "minor grid & scales" begin data = LinRange(0.01, 0.99, 200) - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) for (i, scale) in enumerate([log10, log2, log, sqrt, Makie.logit, identity]) row, col = fldmod1(i, 2) Axis(f[row, col], yscale = scale, title = string(scale), @@ -808,7 +808,7 @@ end end @reference_test "contour labels with transform_func" begin - f = Figure(resolution = (400, 400)) + f = Figure(size = (400, 400)) a = Axis(f[1, 1], xscale = log10) xs = 10 .^ range(0, 3, length=101) ys = range(1, 4, length=101) @@ -840,7 +840,7 @@ end @reference_test "trimspine" begin with_theme(Axis = (limits = (0.5, 5.5, 0.3, 3.4), spinewidth = 8, topspinevisible = false, rightspinevisible = false)) do - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) for (i, ts) in enumerate([(true, true), (true, false), (false, true), (false, false)]) Label(f[0, i], string(ts), tellwidth = false) @@ -859,7 +859,7 @@ end end @reference_test "hexbin bin int" begin - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) x = RNG.rand(300) y = RNG.rand(300) @@ -875,7 +875,7 @@ end end @reference_test "hexbin bin tuple" begin - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) x = RNG.rand(300) y = RNG.rand(300) @@ -893,7 +893,7 @@ end @reference_test "hexbin two cellsizes" begin - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) x = RNG.rand(300) y = RNG.rand(300) @@ -909,7 +909,7 @@ end end @reference_test "hexbin one cellsize" begin - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) x = RNG.rand(300) y = RNG.rand(300) @@ -925,7 +925,7 @@ end end @reference_test "hexbin threshold" begin - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) x = RNG.randn(100000) y = RNG.randn(100000) @@ -974,7 +974,7 @@ end end @reference_test "Rich text" begin - f = Figure(fontsize = 30, resolution = (800, 600)) + f = Figure(fontsize = 30, size = (800, 600)) ax = Axis(f[1, 1], limits = (1, 100, 0.001, 1), xscale = log10, @@ -1066,10 +1066,10 @@ end end @reference_test "LaTeXStrings linesegment offsets" begin - s = Scene(camera = campixel!, resolution = (600, 600)) + s = Scene(camera = campixel!, size = (600, 600)) for (i, (offx, offy)) in enumerate(zip([0, 20, 50], [0, 10, 30])) for (j, rot) in enumerate([0, pi/4, pi/2]) - scatter!(s, 150i, 150j) + scatter!(s, 150i, 150j, color=:black) text!(s, 150i, 150j, text = L"\sqrt{x+y}", offset = (offx, offy), rotation = rot, fontsize = 30) end @@ -1078,7 +1078,7 @@ end end @reference_test "Scalar colors from colormaps" begin - f = Figure(resolution = (600, 600)) + f = Figure(size = (600, 600)) ax = Axis(f[1, 1]) hidedecorations!(ax) hidespines!(ax) @@ -1107,7 +1107,7 @@ end # 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)) + fig = Figure(size = (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 @@ -1349,3 +1349,27 @@ end ylims!(ax2,-0.5,2.5) # need to make sure all generators are shown, and the bounding box is automatically updated fig end + +function ppu_test_plot(resolution, px_per_unit, scalefactor) + fig, ax, pl = scatter(1:4, markersize=100, color=1:4, figure=(; size=resolution), axis=(; titlesize=50, title="ppu: $px_per_unit, sf: $scalefactor")) + DataInspector(ax) + hidedecorations!(ax) + return fig +end + +@reference_test "px_per_unit and scalefactor" begin + resolution = (800, 800) + let st = nothing + @testset begin + matr = [(px, scale) for px in [0.5, 1, 2], scale in [0.5, 1, 2]] + imgs = map(matr) do (px_per_unit, scalefactor) + img = colorbuffer(ppu_test_plot(resolution, px_per_unit, scalefactor); px_per_unit=px_per_unit, scalefactor=scalefactor) + @test size(img) == (800, 800) .* px_per_unit + return img + end + fig = Figure() + st = Makie.RamStepper(fig, Makie.current_backend().Screen(fig.scene), vec(imgs), :png) + end + st + end +end diff --git a/ReferenceTests/src/tests/examples3d.jl b/ReferenceTests/src/tests/examples3d.jl index e32e9980322..507b476b459 100644 --- a/ReferenceTests/src/tests/examples3d.jl +++ b/ReferenceTests/src/tests/examples3d.jl @@ -1,7 +1,7 @@ @reference_test "Image on Geometry (Moon)" begin moon = loadasset("moon.png") - fig, ax, meshplot = mesh(Sphere(Point3f(0), 1f0), color=moon, shading=false, axis = (;show_axis=false)) + fig, ax, meshplot = mesh(Sphere(Point3f(0), 1f0), color=moon, shading=NoShading, axis = (;show_axis=false)) update_cam!(ax.scene, Vec3f(-2, 2, 2), Vec3f(0)) fig end @@ -9,7 +9,7 @@ end @reference_test "Image on Geometry (Earth)" begin earth = loadasset("earth.png") m = uv_mesh(Tesselation(Sphere(Point3f(0), 1f0), 60)) - mesh(m, color=earth, shading=false) + mesh(m, color=earth, shading=NoShading) end @reference_test "Orthographic Camera" begin @@ -29,19 +29,12 @@ end meshes = map(colormesh, rectangles) fig, ax, meshplot = mesh(merge(meshes)) scene = ax.scene - center!(scene) cam = cameracontrols(scene) - dir = widths(data_limits(scene)) ./ 2. - dir_scaled = Vec3f( - dir[1] * scene.transformation.scale[][1], - 0.0, - dir[3] * scene.transformation.scale[][2], - ) + cam.settings[:projectiontype][] = Makie.Orthographic + cam.settings.center[] = false # This would be set by update_cam!() cam.upvector[] = (0.0, 0.0, 1.0) - cam.lookat[] = minimum(data_limits(scene)) + dir_scaled - cam.eyeposition[] = (cam.lookat[][1], cam.lookat[][2] + 6.3, cam.lookat[][3]) - cam.attributes[:projectiontype][] = Makie.Orthographic - cam.zoom_mult[] = 0.61f0 + cam.lookat[] = Vec3f(0.595, 1.5, 0.5) + cam.eyeposition[] = (cam.lookat[][1], cam.lookat[][2] + 0.61, cam.lookat[][3]) update_cam!(scene, cam) fig end @@ -61,13 +54,13 @@ end rot = qrotation(Vec3f(1, 0, 0), 0.5pi) * qrotation(Vec3f(0, 1, 0), 0.7pi) meshscatter( 1:3, 1:3, fill(0, 3, 3), - marker=catmesh, color=img, markersize=1, rotation=rot, + marker=catmesh, color=img, markersize=1, rotations=rot, axis=(type=LScene, show_axis=false) ) end @reference_test "Load Mesh" begin - mesh(loadasset("cat.obj")) + mesh(loadasset("cat.obj"); color=:black) end @reference_test "Colored Mesh" begin @@ -201,7 +194,6 @@ end x = [cospi(φ) * sinpi(θ) for θ in θ, φ in φ] y = [sinpi(φ) * sinpi(θ) for θ in θ, φ in φ] z = [cospi(θ) for θ in θ, φ in φ] - RNG.rand([-1f0, 1f0], 3) pts = vec(Point3f.(x, y, z)) f, ax, p = surface(x, y, z, color=Makie.logo(), transparency=true) end @@ -282,7 +274,7 @@ end vy = -1:0.01:1 f(x, y) = (sin(x * 10) + cos(y * 10)) / 4 - scene = Scene(resolution=(500, 500), camera=cam3d!) + scene = Scene(size=(500, 500), camera=cam3d!) # One way to style the axis is to pass a nested dictionary / named tuple to it. psurf = surface!(scene, vx, vy, f) axis3d!(scene, frame = (linewidth = 2.0,)) @@ -452,8 +444,8 @@ end @reference_test "Line GIF" begin us = range(0, stop=1, length=100) - f, ax, p = linesegments(Rect3f(Vec3f(0, -1, 0), Vec3f(1, 2, 2))) - p = lines!(ax, us, sin.(us), zeros(100), linewidth=3, transparency=true) + f, ax, p = linesegments(Rect3f(Vec3f(0, -1, 0), Vec3f(1, 2, 2)); color=:black) + p = lines!(ax, us, sin.(us), zeros(100), linewidth=3, transparency=true, color=:black) lineplots = [p] Makie.translate!(p, 0, 0, 0) colors = to_colormap(:RdYlBu) @@ -533,7 +525,7 @@ end @reference_test "Depth Shift" begin # Up to some artifacts from fxaa the left side should be blue and the right red. - fig = Figure(resolution = (800, 400)) + fig = Figure(size = (800, 400)) prim = Rect3(Point3f(0), Vec3f(1)) ps = RNG.rand(Point3f, 10) .+ Point3f(0, 0, 1) @@ -591,7 +583,7 @@ end end end cam = cameracontrols(ax.scene) - cam.attributes.fov[] = 22f0 + cam.fov[] = 22f0 update_cam!(ax.scene, cam, Vec3f(0.625, 0, 3.5), Vec3f(0.625, 0, 0), Vec3f(0, 1, 0)) fig end @@ -601,7 +593,7 @@ end fig = Figure() for ax in [LScene(fig[1, 1]), Axis3(fig[1, 2])] mesh!(ax, Rect3(Point3f(-10), Vec3f(20)), color = :orange) - mesh!(ax, Rect2f(0.8, 0.1, 0.1, 0.8), space = :relative, color = :blue, shading = false) + mesh!(ax, Rect2f(0.8, 0.1, 0.1, 0.8), space = :relative, color = :blue, shading = NoShading) linesegments!(ax, Rect2f(-0.5, -0.5, 1, 1), space = :clip, color = :cyan, linewidth = 5) text!(ax, 0, 0.52, text = "Clip Space", align = (:center, :bottom), space = :clip) image!(ax, 0..40, 0..800, [x for x in range(0, 1, length=40), _ in 1:10], space = :pixel) diff --git a/ReferenceTests/src/tests/figures_and_makielayout.jl b/ReferenceTests/src/tests/figures_and_makielayout.jl index 2f857d415c3..6c6f46a2013 100644 --- a/ReferenceTests/src/tests/figures_and_makielayout.jl +++ b/ReferenceTests/src/tests/figures_and_makielayout.jl @@ -8,7 +8,7 @@ end @reference_test "Figure with Blocks" begin - fig = Figure(resolution = (900, 900)) + fig = Figure(size = (900, 900)) ax, sc = scatter(fig[1, 1][1, 1], RNG.randn(100, 2), axis = (;title = "Random Dots", xlabel = "Time")) sc2 = scatter!(ax, RNG.randn(100, 2) .+ 2, color = :red) ll = fig[1, 1][1, 2] = Legend(fig, [sc, sc2], ["Scatter", "Other"]) @@ -25,6 +25,17 @@ end fig end +@reference_test "Figure with boxes" begin + fig = Figure(size = (900, 900)) + Box(fig[1,1], color = :red, strokewidth = 3, linestyle = :solid, strokecolor = :black) + Box(fig[1,2], color = (:red, 0.5), strokewidth = 3, linestyle = :dash, strokecolor = :red) + Box(fig[1,3], color = :white, strokewidth = 3, linestyle = :dot, strokecolor = (:black, 0.5)) + Box(fig[2,1], color = :red, strokewidth = 3, linestyle = :solid, strokecolor = :black, cornerradius = 0) + Box(fig[2,2], color = (:red, 0.5), strokewidth = 3, linestyle = :dash, strokecolor = :red, cornerradius = 20) + Box(fig[2,3], color = :white, strokewidth = 3, linestyle = :dot, strokecolor = (:black, 0.5), cornerradius = (0, 10, 20, 30)) + fig +end + @reference_test "menus" begin fig = Figure() funcs = [sqrt, x->x^2, sin, cos] @@ -50,8 +61,8 @@ end @reference_test "Label with text wrapping" begin lorem_ipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." - fig = Figure(resolution = (1000, 660)) - m!(fig, lbl) = mesh!(fig.scene, lbl.layoutobservables.computedbbox, color = (:red, 0.5), shading=false) + fig = Figure(size = (1000, 660)) + m!(fig, lbl) = mesh!(fig.scene, lbl.layoutobservables.computedbbox, color = (:red, 0.5), shading=NoShading) lbl1 = Label(fig[1, 1:2], "HEADER "^10, fontsize = 40, word_wrap = true) m!(fig, lbl1) @@ -116,8 +127,8 @@ end lines!(ax,( 1:10) .* i, label = "$i") end # To verify that RGB values differ across entries - axislegend(ax, position = :lt, patchcolor = :red, patchsize = (100, 100), bgcolor = :gray50); - Legend(f[1, 2], ax, patchcolor = :gray80, patchsize = (100, 100), bgcolor = :gray50); + axislegend(ax, position = :lt, patchcolor = :red, patchsize = (100, 100), backgroundcolor = :gray50); + Legend(f[1, 2], ax, patchcolor = :gray80, patchsize = (100, 100), backgroundcolor = :gray50); f end end @@ -141,7 +152,7 @@ end f = Figure() ax = PolarAxis(f[1, 1]) zs = [r*cos(phi) for phi in range(0, 4pi, length=100), r in range(1, 2, length=100)] - p = surface!(ax, 0..2pi, 0..10, zs, shading = false, colormap = :coolwarm, colorrange=(-2, 2)) + p = surface!(ax, 0..2pi, 0..10, zs, shading = NoShading, colormap = :coolwarm, colorrange=(-2, 2)) rlims!(ax, 0, 11) # verify that r = 10 doesn't end up at r > 10 translate!(p, 0, 0, -200) Colorbar(f[1, 2], p) @@ -150,7 +161,7 @@ end # may fail in WGLMakie due to missing dashes @reference_test "PolarAxis scatterlines spine" begin - f = Figure(resolution = (800, 400)) + f = Figure(size = (800, 400)) ax1 = PolarAxis(f[1, 1], title = "No spine", spinevisible = false, theta_as_x = false) scatterlines!(ax1, range(0, 1, length=100), range(0, 10pi, length=100), color = 1:100) @@ -165,7 +176,7 @@ end # may fail in CairoMakie due to different text stroke handling # and in WGLMakie due to missing stroke @reference_test "PolarAxis decorations" begin - f = Figure(resolution = (400, 400), backgroundcolor = :black) + f = Figure(size = (400, 400), backgroundcolor = :black) ax = PolarAxis( f[1, 1], backgroundcolor = :black, @@ -184,7 +195,7 @@ end end @reference_test "PolarAxis limits" begin - f = Figure(resolution = (800, 600)) + f = Figure(size = (800, 600)) for (i, theta_0) in enumerate((0, -pi/6, pi/2)) for (j, thetalims) in enumerate(((0, 2pi), (-pi/2, pi/2), (0, pi/12))) po = PolarAxis(f[i, j], theta_0 = theta_0, thetalimits = thetalims, rlimits = (1 + 2(j-1), 7)) @@ -200,8 +211,25 @@ end f end +@reference_test "PolarAxis radial shift and clip" begin + phis = range(pi/4, 9pi/4, length=201) + rs = 1.0 ./ sin.(range(pi/4, 3pi/4, length=51)[1:end-1]) + rs = vcat(rs, rs, rs, rs, rs[1]) + + fig = Figure(size = (900, 300)) + ax1 = PolarAxis(fig[1, 1], clip_r = false, radius_at_origin = -2) # red square, black, blue bulging + ax2 = PolarAxis(fig[1, 2], clip_r = false, radius_at_origin = 0) # red flower, black square, blue bulging + ax3 = PolarAxis(fig[1, 3], clip_r = false, radius_at_origin = 0.5) # red large flower, black star, blue square + for ax in (ax1, ax2, ax3) + lines!(ax, phis, rs .- 2, color = :red, linewidth = 4) + lines!(ax, phis, rs, color = :black, linewidth = 4) + lines!(ax, phis, rs .+ 0.5, color = :blue, linewidth = 4) + end + fig +end + @reference_test "Axis3 axis reversal" begin - f = Figure(resolution = (1000, 1000)) + f = Figure(size = (1000, 1000)) revstr(dir, rev) = rev ? "$dir rev" : "" for (i, (x, y, z)) in enumerate(Iterators.product(fill((false, true), 3)...)) Axis3(f[fldmod1(i, 3)...], title = "$(revstr("x", x)) $(revstr("y", y)) $(revstr("z", z))", xreversed = x, yreversed = y, zreversed = z) @@ -211,7 +239,7 @@ end end @reference_test "Colorbar for recipes" begin - fig, ax, pl = barplot(1:3; color=1:3, colormap=Makie.Categorical(:viridis), figure=(;resolution=(800, 800))) + fig, ax, pl = barplot(1:3; color=1:3, colormap=Makie.Categorical(:viridis), figure=(;size=(800, 800))) Colorbar(fig[1, 2], pl; size=100) x = LinRange(-1, 1, 20) y = LinRange(-1, 1, 20) @@ -262,4 +290,4 @@ end hidedecorations!(ax) axislegend(ax) fig -end \ No newline at end of file +end diff --git a/ReferenceTests/src/tests/primitives.jl b/ReferenceTests/src/tests/primitives.jl index dbc411ac2d0..7e6083f7c9c 100644 --- a/ReferenceTests/src/tests/primitives.jl +++ b/ReferenceTests/src/tests/primitives.jl @@ -1,6 +1,6 @@ @reference_test "lines and linestyles" begin # For now disabled until we fix GLMakie linestyle - s = Scene(resolution = (800, 800), camera = campixel!) + s = Scene(size = (800, 800), camera = campixel!) scalar = 30 points = Point2f[(1, 1), (1, 2), (2, 3), (2, 1)] linestyles = [ @@ -13,6 +13,7 @@ scalar .* (points .+ Point2f(linewidth*2, i * 3.25)), linewidth = linewidth, linestyle = linestyle, + color=:black ) end end @@ -20,7 +21,7 @@ end @reference_test "lines with gaps" begin - s = Scene(resolution = (800, 800), camera = campixel!) + s = Scene(size = (800, 800), camera = campixel!) points = [ Point2f[(1, 0), (2, 0.5), (NaN, NaN), (4, 0.5), (5, 0)], Point2f[(NaN, NaN), (2, 0.5), (3, 0), (4, 0.5), (5, 0)], @@ -36,7 +37,7 @@ end end @reference_test "scatters" begin - s = Scene(resolution = (800, 800), camera = campixel!) + s = Scene(size = (800, 800), camera = campixel!) markersizes = 0:2:30 markers = [:circle, :rect, :cross, :utriangle, :dtriangle, @@ -49,6 +50,7 @@ end Point2f(i, j) .* 45, marker = m, markersize = ms, + color=:black ) end end @@ -56,7 +58,7 @@ end end @reference_test "scatter rotations" begin - s = Scene(resolution = (800, 800), camera = campixel!) + s = Scene(size = (800, 800), camera = campixel!) rotations = range(0, 2pi, length = 15) markers = [:circle, :rect, :cross, :utriangle, :dtriangle, @@ -71,6 +73,7 @@ end marker = m, markersize = 30, rotations = rot, + color=:black ) scatter!(s, p, color = :red, markersize = 6) end @@ -79,7 +82,7 @@ end end @reference_test "scatter with stroke" begin - s = Scene(resolution = (350, 700), camera = campixel!) + s = Scene(size = (350, 700), camera = campixel!) # half stroke, half glow strokes = range(1, 4, length=7) @@ -112,7 +115,7 @@ end end @reference_test "scatter with glow" begin - s = Scene(resolution = (350, 700), camera = campixel!) + s = Scene(size = (350, 700), camera = campixel!) # half stroke, half glow glows = range(4, 1, length=7) @@ -148,7 +151,7 @@ end @reference_test "scatter image markers" begin pixel_types = [ RGBA, RGBAf, RGBA{Float16}, ARGB, ARGB{Float16}, RGB, RGBf, RGB{Float16} ] rotations = [ 2pi/3 * (i-1) for i = 1:length(pixel_types) ] - s = Scene(resolution = (100+100*length(pixel_types), 400), camera = campixel!) + s = Scene(size = (100+100*length(pixel_types), 400), camera = campixel!) filename = Makie.assetpath("icon_transparent.png") marker_image = load(filename) for (i, (rot, pxtype)) in enumerate(zip(rotations, pixel_types)) @@ -166,7 +169,7 @@ end @reference_test "basic polygon shapes" begin - s = Scene(resolution = (800, 800), camera = campixel!) + s = Scene(size = (800, 800), camera = campixel!) scalefactor = 70 Pol = Makie.GeometryBasics.Polygon polys = [ @@ -219,7 +222,7 @@ end @reference_test "BezierPath markers" begin - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) ax = Axis(f[1, 1]) markers = [ @@ -255,7 +258,7 @@ end # bb = Makie.bbox(Makie.DEFAULT_MARKER_MAP[marker]) # w, h = widths(bb) # ox, oy = origin(bb) - # xy = map(pv -> Makie.project(pv, Vec2f(widths(pixelarea(scene)[])), Point2f(5, i)), scene.camera.projectionview) + # xy = map(pv -> Makie.project(pv, Vec2f(widths(viewport(scene)[])), Point2f(5, i)), scene.camera.projectionview) # bb = map(xy -> Rect2f(xy .+ 30 * Vec2f(ox, oy), 30 * Vec2f(w, h)), xy) # lines!(bb, linewidth = 1, color = :orange, space = :pixel, linestyle = :dash) # end @@ -265,7 +268,7 @@ end end @reference_test "BezierPath marker stroke" begin - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) ax = Axis(f[1, 1]) # Same as above @@ -287,7 +290,7 @@ end @reference_test "complex_bezier_markers" begin - f = Figure(resolution = (800, 800)) + f = Figure(size = (800, 800)) ax = Axis(f[1, 1]) arrow = BezierPath([ @@ -401,7 +404,7 @@ end function draw_marker_test!(scene, marker, center; markersize=300) # scatter!(scene, center, distancefield=matr, uv_offset_width=Vec4f(0, 0, 1, 1), markersize=600) - scatter!(scene, center, marker=marker, markersize=markersize, markerspace=:pixel) + scatter!(scene, center, color=:black, marker=marker, markersize=markersize, markerspace=:pixel) font = Makie.defaultfont() charextent = Makie.FreeTypeAbstraction.get_extent(font, marker) @@ -422,7 +425,7 @@ function draw_marker_test!(scene, marker, center; markersize=300) end @reference_test "marke glyph alignment" begin - scene = Scene(resolution=(1200, 1200)) + scene = Scene(size=(1200, 1200)) campixel!(scene) # marker is in front, so it should not be smaller than the background rectangle plot_row!(scene, 0, false) @@ -446,8 +449,22 @@ end scene end +@reference_test "Surface with NaN points" begin + # prepare surface data + zs = [x^2 + y^2 for x in range(-2, 0, length=10), y in range(-2, 0, length=10)] + ns = copy(zs) + ns[4, 3:6] .= NaN + # plot surface + 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) + wireframe!(a, m, depth_shift = -1f-3, color = :black) + f +end + @reference_test "barplot with TeX-ed labels" begin - fig = Figure(resolution = (800, 800)) + fig = Figure(size = (800, 800)) lab1 = L"\int f(x) dx" lab2 = lab1 # lab2 = L"\frac{a}{b} - \sqrt{b}" # this will not work until #2667 is fixed diff --git a/ReferenceTests/src/tests/refimages.jl b/ReferenceTests/src/tests/refimages.jl index 73ce26f4a42..f66d70b4e30 100644 --- a/ReferenceTests/src/tests/refimages.jl +++ b/ReferenceTests/src/tests/refimages.jl @@ -13,6 +13,9 @@ using ReferenceTests.Colors: RGB, N0f8 using ReferenceTests.DelaunayTriangulation using Makie: Record, volume +@testset "specapi" begin + include("specapi.jl") +end @testset "primitives" begin include("primitives.jl") end diff --git a/ReferenceTests/src/tests/short_tests.jl b/ReferenceTests/src/tests/short_tests.jl index c939fc60626..b28d814a8ee 100644 --- a/ReferenceTests/src/tests/short_tests.jl +++ b/ReferenceTests/src/tests/short_tests.jl @@ -132,7 +132,7 @@ end highclip = :red, lowclip = :black, nan_color = (:green, 0.5), - shading = false, + shading = NoShading, ) surface!( Axis(fig[2, 2]), @@ -141,7 +141,7 @@ end highclip = :red, lowclip = :black, nan_color = (:green, 0.5), - shading = false, + shading = NoShading, ) fig end @@ -158,7 +158,7 @@ end @reference_test "lines linesegments width test" begin res = 200 - s = Scene(camera=campixel!, resolution=(res, res)) + s = Scene(camera=campixel!, size=(res, res)) half = res / 2 linewidth = 10 xstart = half - (half/2) diff --git a/ReferenceTests/src/tests/specapi.jl b/ReferenceTests/src/tests/specapi.jl new file mode 100644 index 00000000000..f12a39585ee --- /dev/null +++ b/ReferenceTests/src/tests/specapi.jl @@ -0,0 +1,118 @@ +import Makie.SpecApi as S + +function synchronize() + # This is very unfortunate, but deletion and updates + # are async in WGLMakie and there is no way for use to synchronize on them YET + if nameof(Makie.CURRENT_BACKEND[]) == :WGLMakie + sleep(2) + end +end + +function sync_step!(stepper) + synchronize() + Makie.step!(stepper) +end + +@reference_test "FigureSpec" begin + f, _, pl = plot(S.GridLayout()) + st = Makie.Stepper(f) + sync_step!(st) + obs = pl[1] + obs[] = S.GridLayout([S.Axis(; plots=[S.Lines(1:4; color=:black, linewidth=5), S.Scatter(1:4; markersize=20)]) + S.Axis3(; plots=[S.Scatter(Rect3f(Vec3f(0), Vec3f(1)); color=:red, markersize=50)])]) + sync_step!(st) + obs[] = begin + ax = S.Axis(; plots=[S.Scatter(1:4)]) + ax2 = S.Axis3(; title="Title 0", plots=[S.Scatter(1:4; color=1:4, markersize=20)]) + c = S.Colorbar(; limits=(0, 1), colormap=:heat) + S.GridLayout([ax ax2 c]) + end + sync_step!(st) + + obs[] = begin + p1 = S.Scatter(1:4; markersize=50) + ax = S.Axis(; plots=[p1], title="Title 1") + p2 = S.Scatter(2:4; color=1:3, markersize=30) + ax2 = S.Axis3(; plots=[p2]) + c = S.Colorbar(; limits=(2, 10), colormap=:viridis, width=50) + S.GridLayout([ax ax2 c]) + end + sync_step!(st) + ax1 = S.Axis(; plots=[S.Scatter(1:4; markersize=20), S.Lines(1:4; color=:darkred, linewidth=6)]) + ax2 = S.Axis3(; plots=[S.Scatter(Rect3f(Vec3f(0), Vec3f(1)); color=(:red, 0.5), markersize=30)]) + obs[] = S.GridLayout([ax1 ax2]) + sync_step!(st) + + elem_1 = [LineElement(; color=:red, linestyle=nothing), + MarkerElement(; color=:blue, marker='x', markersize=15, + strokecolor=:black)] + + elem_2 = [PolyElement(; color=:red, strokecolor=:blue, strokewidth=1), + LineElement(; color=:black, linestyle=:dash)] + + elem_3 = LineElement(; color=:green, linestyle=nothing, + points=Point2f[(0, 0), (0, 1), (1, 0), (1, 1)]) + + obs[] = begin + S.GridLayout(S.Legend([elem_1, elem_2, elem_3], ["elem 1", "elem 2", "elem 3"], "Legend Title")) + end + sync_step!(st) + + obs[] = begin + l = S.Legend([elem_1, elem_2], ["elem 1", "elem 2"], "New Title") + S.GridLayout(l) + end + sync_step!(st) + + obs[] = S.GridLayout() + sync_step!(st) + + st +end + +struct PlotGrid + nplots::Tuple{Int,Int} +end + +function Makie.convert_arguments(::Type{<:AbstractPlot}, obj::PlotGrid) + plots = [S.Lines(1:4; linewidth=5, color=Cycled(1)), + S.Lines(2:5; linewidth=7, color=Cycled(2))] + axes = [S.Axis(; plots=plots) for i in 1:obj.nplots[1], j in 1:obj.nplots[2]] + return S.GridLayout(axes) +end + +struct LineScatter + show_lines::Bool + show_scatter::Bool +end +function Makie.convert_arguments(::Type{<:AbstractPlot}, obj::LineScatter, data...) + plots = PlotSpec[] + if obj.show_lines + push!(plots, S.Lines(data...; linewidth=5)) + end + if obj.show_scatter + push!(plots, S.Scatter(data...; markersize=20)) + end + return plots +end + +@reference_test "SpecApi in convert_arguments" begin + f = Figure() + p1 = plot(f[1, 1], PlotGrid((1, 1))) + f + ax, p2 = plot(f[1, 2], LineScatter(true, true), 1:4) + st = Makie.Stepper(f) + sync_step!(st) + p1[1] = PlotGrid((2, 2)) + p2[1] = LineScatter(false, true) + sync_step!(st) + + p1[1] = PlotGrid((3, 3)) + p2[1] = LineScatter(true, false) + sync_step!(st) + + p1[1] = PlotGrid((2, 1)) + p2[1] = LineScatter(true, true) + sync_step!(st) + st +end diff --git a/ReferenceTests/src/tests/text.jl b/ReferenceTests/src/tests/text.jl index e516fae1a8f..04e4c30626a 100644 --- a/ReferenceTests/src/tests/text.jl +++ b/ReferenceTests/src/tests/text.jl @@ -1,5 +1,5 @@ @reference_test "heatmap_with_labels" begin - fig = Figure(resolution = (600, 600)) + fig = Figure(size = (600, 600)) ax = fig[1, 1] = Axis(fig) values = RNG.rand(10, 10) @@ -28,7 +28,7 @@ end end @reference_test "single_strings_single_positions" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) + scene = Scene(camera = campixel!, size = (800, 800)) points = [Point(x, y) .* 200 for x in 1:3 for y in 1:3] scatter!(scene, points, marker = :circle, markersize = 10px) @@ -51,7 +51,7 @@ end @reference_test "multi_strings_multi_positions" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) + scene = Scene(camera = campixel!, size = (800, 800)) angles = (-pi/6, 0.0, pi/6) points = [Point(x, y) .* 200 for x in 1:3 for y in 1:3 for angle in angles] @@ -66,8 +66,7 @@ end for valign in (:top, :center, :bottom) for rotation in angles] - scatter!(scene, points, marker = :circle, markersize = 10px) - + scatter!(scene, points, marker = :circle, markersize = 10px, color=:black) text!(scene, points, text = strings, align = aligns, rotation = rotations, color = [(:black, alpha) for alpha in LinRange(0.3, 0.7, length(points))]) @@ -76,10 +75,10 @@ end end @reference_test "single_strings_single_positions_justification" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) + scene = Scene(camera = campixel!, size = (800, 800)) points = [Point(x, y) .* 200 for x in 1:3 for y in 1:3] - scatter!(scene, points, marker = :circle, markersize = 10px) + scatter!(scene, points, marker = :circle, markersize = 10px, color=:black) symbols = (:left, :center, :right) @@ -109,7 +108,7 @@ end end @reference_test "multi_boundingboxes" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) + scene = Scene(camera = campixel!, size = (800, 800)) t1 = text!(scene, fill("makie", 4), @@ -137,7 +136,7 @@ end end @reference_test "single_boundingboxes" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) + scene = Scene(camera = campixel!, size = (800, 800)) for a in pi/4:pi/2:7pi/4 @@ -176,12 +175,13 @@ end color = [cgrad(:viridis)[x] for x in LinRange(0, 1, 7)], align = (:left, :baseline), fontsize = 1, - markerspace = :data + markerspace = :data, + axis=(; type=LScene) ) end @reference_test "empty_lines" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) + scene = Scene(camera = campixel!, size = (800, 800)) t1 = text!(scene, "Line1\nLine 2\n\nLine4", position = (200, 400), align = (:center, :center), markerspace = :data) @@ -212,7 +212,7 @@ end @reference_test "Text offset" begin - f = Figure(resolution = (1000, 1000)) + f = Figure(size = (1000, 1000)) barplot(f[1, 1], 3:5) text!(1, 3, text = "bar 1", offset = (0, 10), align = (:center, :baseline)) text!([(2, 4), (3, 5)], text = ["bar 2", "bar 3"], @@ -283,7 +283,7 @@ end position = Point2f(50, 50), rotation = 0.0, markerspace = :data) - wireframe!(s, boundingbox(t)) + wireframe!(s, boundingbox(t), color=:black) s end @@ -349,7 +349,7 @@ end @reference_test "Word Wrapping" begin lorem_ipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." - fig = Figure(resolution=(600, 500)) + fig = Figure(size=(600, 500)) ax = Axis(fig[1, 1]) text!(ax, 0, 0, text = latexstring(L"$1$ " * lorem_ipsum), word_wrap_width=250, fontsize = 12, align = (:left, :bottom), justification = :left, color = :black) text!(ax, 0, 0, text = lorem_ipsum, word_wrap_width=250, fontsize = 12, align = (:left, :top), justification = :right, color = :black) @@ -368,4 +368,3 @@ end ax.zlabel[] = L"\sum_{n=1}^{\infty} 2^{-n} = 1" fig end - diff --git a/ReferenceTests/src/tests/updating.jl b/ReferenceTests/src/tests/updating.jl index 27f21af75cd..d19c97647fd 100644 --- a/ReferenceTests/src/tests/updating.jl +++ b/ReferenceTests/src/tests/updating.jl @@ -43,7 +43,7 @@ end function generate_plot(N = 3) points = Observable(Point2f[]) color = Observable(RGBAf[]) - fig, ax, pl = scatter(points, color=color, markersize=1.0, marker=Circle, markerspace=:data, axis=(type=Axis, aspect=DataAspect(), limits=(0.4, N + 0.6, 0.4, N + 0.6),), figure=(resolution=(800, 800),)) + fig, ax, pl = scatter(points, color=color, markersize=1.0, marker=Circle, markerspace=:data, axis=(type=Axis, aspect=DataAspect(), limits=(0.4, N + 0.6, 0.4, N + 0.6),), figure=(size=(800, 800),)) function update_func(ij) push!(points.val, Point2f(Tuple(ij))) push!(color.val, RGBAf((Tuple(ij)./N)..., 0, 1)) @@ -121,10 +121,14 @@ end obs = Observable(1:5) f, ax, pl = scatter(obs; markersize=150) s = display(f) - @test length(obs.listeners) == 1 + # So, for GLMakie it will be 2, since we register an additional listener for + # State changes for the on demand renderloop + @test length(obs.listeners) in (1, 2) delete!(ax, pl) @test length(obs.listeners) == 0 - sleep(1.0) + # ugh, hard to synchronize this with WGLMakie, so, we need to sleep for now to make sure the change makes it to the browser + # TODO, add synchronization primitive? + sleep(1) f end diff --git a/WGLMakie/Project.toml b/WGLMakie/Project.toml index 39678e5aa61..e26da6c4d76 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.8.15" +version = "0.9.2" [deps] Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" @@ -14,9 +14,9 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" Observables = "510215fc-4207-5dde-b226-833fc4488ee2" PNGFiles = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883" +PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" RelocatableFolders = "05181044-ff0b-4ac5-8273-598c1e38db00" ShaderAbstractions = "65257c39-d410-5151-9873-9b3e5be5013e" -PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" [compat] @@ -25,15 +25,17 @@ FileIO = "1.1" FreeTypeAbstraction = "0.10" GeometryBasics = "0.4.1" Hyperscript = "0.0.3, 0.0.4" -JSServe = "2.2" -Makie = "=0.19.11" +JSServe = "v2.3" +Makie = "=0.20.2" Observables = "0.5.1" +PNGFiles = "0.3, 0.4" +PrecompileTools = "1.0" RelocatableFolders = "0.1, 0.2, 0.3, 1.0" ShaderAbstractions = "0.4" -PrecompileTools = "1.0" StaticArrays = "0.12, 1.0" -PNGFiles = "0.3, 0.4" julia = "1.3" +LinearAlgebra = "1.0, 1.6" + [extras] MeshIO = "7269a6da-0436-5bbc-96c2-40638cbb6118" diff --git a/WGLMakie/README.md b/WGLMakie/README.md index 5ceaee50e96..a1c44e6efc2 100644 --- a/WGLMakie/README.md +++ b/WGLMakie/README.md @@ -15,7 +15,7 @@ You can also embed plots in a JSServe webpage: ```julia using JSServe -app = App(session, request) +app = App() do session, request return DOM.div( DOM.h1("Some Makie Plots:"), meshscatter(1:4, color=1:4), @@ -23,7 +23,7 @@ app = App(session, request) meshscatter(1:4, color=rand(RGBf, 4)), meshscatter(1:4, color=:red), meshscatter(rand(Point3f, 10), color=rand(RGBf, 10)), - meshscatter(rand(Point3f, 10), marker=Pyramid(Point3f(0), 1f0, 1f0)), + meshscatter(rand(Point3f, 10), marker=WGLMakie.Pyramid(Point3f(0), 1f0, 1f0)), ) end isdefined(Main, :server) && close(server) diff --git a/WGLMakie/assets/line_segments.frag b/WGLMakie/assets/line_segments.frag deleted file mode 100644 index 384921152a2..00000000000 --- a/WGLMakie/assets/line_segments.frag +++ /dev/null @@ -1,26 +0,0 @@ - -in vec4 frag_color; - -flat in uint frag_instance_id; -vec4 pack_int(uint id, uint index) { - vec4 unpack; - unpack.x = float((id & uint(0xff00)) >> 8) / 255.0; - unpack.y = float((id & uint(0x00ff)) >> 0) / 255.0; - unpack.z = float((index & uint(0xff00)) >> 8) / 255.0; - unpack.w = float((index & uint(0x00ff)) >> 0) / 255.0; - return unpack; -} - -void main() { - if (picking) { - if (frag_color.a > 0.1) { - fragment_color = pack_int(object_id, frag_instance_id); - } - return; - } - - if (frag_color.a <= 0.0){ - discard; - } - fragment_color = frag_color; -} diff --git a/WGLMakie/assets/line_segments.vert b/WGLMakie/assets/line_segments.vert deleted file mode 100644 index 9f088ad90c2..00000000000 --- a/WGLMakie/assets/line_segments.vert +++ /dev/null @@ -1,50 +0,0 @@ -uniform mat4 projection; -uniform mat4 view; - -vec2 screen_space(vec4 position) -{ - return vec2(position.xy / position.w) * get_resolution(); -} -vec3 tovec3(vec2 v){return vec3(v, 0.0);} -vec3 tovec3(vec3 v){return v;} - -vec4 tovec4(vec3 v){return vec4(v, 1.0);} -vec4 tovec4(vec4 v){return v;} - -out vec4 frag_color; - -flat out uint frag_instance_id; - -void main() -{ - mat4 pvm = projection * view * get_model(); - vec4 point1_clip = pvm * vec4(tovec3(get_segment_start()), 1); - vec4 point2_clip = pvm * vec4(tovec3(get_segment_end()), 1); - vec2 point1_screen = screen_space(point1_clip); - vec2 point2_screen = screen_space(point2_clip); - vec2 dir = normalize(point2_screen - point1_screen); - vec2 normal = vec2(-dir.y, dir.x); - vec4 anchor; - float thickness; - - if(position.x == 0.0){ - anchor = point1_clip; - frag_color = tovec4(get_color_start()); - thickness = get_linewidth_start(); - }else{ - anchor = point2_clip; - frag_color = tovec4(get_color_end()); - thickness = get_linewidth_end(); - } - frag_color.a = frag_color.a * min(1.0, thickness * 2.0); - - normal *= (thickness / get_resolution()) * anchor.w; - // quadpos y (position.y) gives us the direction to expand the line - vec4 offset = vec4(normal * position.y, 0.0, 0.0); - // start, or end of quad, need to use current or next point as anchor - gl_Position = anchor + offset; - gl_Position.z += gl_Position.w * get_depth_shift(); - - frag_instance_id = uint(gl_InstanceID); - -} diff --git a/WGLMakie/assets/lines.frag b/WGLMakie/assets/lines.frag new file mode 100644 index 00000000000..b146e66af6c --- /dev/null +++ b/WGLMakie/assets/lines.frag @@ -0,0 +1,47 @@ +precision mediump int; +precision mediump float; +precision mediump sampler2D; +precision mediump sampler3D; + +flat in vec2 f_uv_minmax; +in vec2 f_uv; +in vec4 f_color; +in float f_thickness; + +uniform float pattern_length; + +out vec4 fragment_color; + +// Half width of antialiasing smoothstep +#define ANTIALIAS_RADIUS 0.8 + +float aastep(float threshold1, float dist) { + return smoothstep(threshold1 - ANTIALIAS_RADIUS, threshold1 + ANTIALIAS_RADIUS, dist); +} + +float aastep(float threshold1, float threshold2, float dist) { + // We use 2x pixel space in the geometry shaders which passes through + // in uv.y, so we need to treat it here by using 2 * ANTIALIAS_RADIUS + float AA = 2.0f * ANTIALIAS_RADIUS; + return smoothstep(threshold1 - AA, threshold1 + AA, dist) - + smoothstep(threshold2 - AA, threshold2 + AA, dist); +} + +float aastep_scaled(float threshold1, float threshold2, float dist) { + float AA = ANTIALIAS_RADIUS / pattern_length; + return smoothstep(threshold1 - AA, threshold1 + AA, dist) - + smoothstep(threshold2 - AA, threshold2 + AA, dist); +} + +void main() { + vec4 color = vec4(f_color.rgb, 0.0f); + vec2 xy = f_uv; + + float alpha = aastep(0.0f, xy.x); + float alpha2 = aastep(-f_thickness, f_thickness, xy.y); + float alpha3 = aastep_scaled(f_uv_minmax.x, f_uv_minmax.y, f_uv.x); + + color = vec4(f_color.rgb, f_color.a * alpha * alpha2 * alpha3); + + fragment_color = color; +} diff --git a/WGLMakie/assets/lines.vert b/WGLMakie/assets/lines.vert new file mode 100644 index 00000000000..bb22d732b75 --- /dev/null +++ b/WGLMakie/assets/lines.vert @@ -0,0 +1,82 @@ +in float position; +in vec2 linepoint_prev; +in vec2 linepoint_start; +in vec2 linepoint_end; +in vec2 linepoint_next; +in float linewidth_prev; +in float linewidth_start; +in float linewidth_end; +in float linewidth_next; + +uniform vec4 is_valid; +uniform vec4 color_end; +uniform vec4 color_start; +uniform mat4 model; +uniform mat4 projectionview; +uniform vec2 resolution; + +out vec2 f_uv; +out vec4 f_color; +out float f_thickness; + +vec3 screen_space(vec3 point) { + vec4 vertex = projectionview * model * vec4(point, 1); + return vec3(vertex.xy * resolution, vertex.z) / vertex.w; +} + +vec3 screen_space(vec2 point) { + return screen_space(vec3(point, 0)); +} + + +void emit_vertex(vec3 position, vec2 uv, bool is_start) { + + f_uv = uv; + + f_color = is_start ? color_start : color_end; + + gl_Position = vec4((position.xy / resolution), position.z, 1.0); + // linewidth scaling may shrink the effective linewidth + f_thickness = is_start ? linewidth_start : linewidth_end; +} + +void main() { + vec3 p1 = screen_space(linepoint_start); + vec3 p2 = screen_space(linepoint_end); + vec2 dir = p1.xy - p2.xy; + dir = normalize(dir); + vec2 line_normal = vec2(dir.y, -dir.x); + vec2 line_offset = line_normal * (linewidth_start / 2.0); + + // triangle 1 + vec3 v0 = vec3(p1.xy - line_offset, p1.z); + if (position == 0.0) { + emit_vertex(v0, vec2(0.0, 0.0), true); + return; + } + vec3 v2 = vec3(p2.xy - line_offset, p2.z); + if (position == 1.0) { + emit_vertex(v2, vec2(0.0, 0.0), false); + return; + } + vec3 v1 = vec3(p1.xy + line_offset, p1.z); + if (position == 2.0) { + emit_vertex(v1, vec2(0.0, 0.0), true); + return; + } + + // triangle 2 + if (position == 3.0) { + emit_vertex(v2, vec2(0.0, 0.0), false); + return; + } + vec3 v3 = vec3(p2.xy + line_offset, p2.z); + if (position == 4.0) { + emit_vertex(v3, vec2(0.0, 0.0), false); + return; + } + if (position == 5.0) { + emit_vertex(v1, vec2(0.0, 0.0), true); + return; + } +} diff --git a/WGLMakie/assets/mesh.frag b/WGLMakie/assets/mesh.frag index 1355d41e6b6..efe137428e3 100644 --- a/WGLMakie/assets/mesh.frag +++ b/WGLMakie/assets/mesh.frag @@ -4,19 +4,31 @@ flat in int sample_frag_color; in vec3 o_normal; in vec3 o_camdir; -in vec3 o_lightdir; + +// Smoothes out edge around 0 light intensity, see GLMakie +float smooth_zero_max(float x) { + const float c = 0.00390625, xswap = 0.6406707120152759, yswap = 0.20508383900190955; + const float shift = 1.0 + xswap - yswap; + float pow8 = x + shift; + pow8 = pow8 * pow8; pow8 = pow8 * pow8; pow8 = pow8 * pow8; + return x < yswap ? c * pow8 : x; +} vec3 blinnphong(vec3 N, vec3 V, vec3 L, vec3 color){ - float diff_coeff = max(dot(L, N), 0.0); + float backlight = get_backlight(); + float diff_coeff = smooth_zero_max(dot(L, -N)) + + backlight * smooth_zero_max(dot(L, N)); // specular coefficient vec3 H = normalize(L + V); - float spec_coeff = pow(max(dot(H, N), 0.0), get_shininess()); + float spec_coeff = pow(max(dot(H, -N), 0.0), get_shininess()) + + backlight * pow(max(dot(H, N), 0.0), get_shininess()); if (diff_coeff <= 0.0) spec_coeff = 0.0; + // final lighting model - return vec3( + return get_light_color() * vec3( get_diffuse() * diff_coeff * color + get_specular() * spec_coeff ); @@ -100,11 +112,10 @@ void main() { vec3 shaded_color = real_color.rgb; if(get_shading()){ - vec3 L = normalize(o_lightdir); + vec3 L = get_light_direction(); vec3 N = normalize(o_normal); - vec3 light1 = blinnphong(N, o_camdir, L, real_color.rgb); - vec3 light2 = blinnphong(N, o_camdir, -L, real_color.rgb); - shaded_color = get_ambient() * real_color.rgb + light1 + get_backlight() * light2; + vec3 light = blinnphong(N, normalize(o_camdir), L, real_color.rgb); + shaded_color = get_ambient() * real_color.rgb + light; } if (picking) { diff --git a/WGLMakie/assets/mesh.vert b/WGLMakie/assets/mesh.vert index 3b354497fd7..14341fbe452 100644 --- a/WGLMakie/assets/mesh.vert +++ b/WGLMakie/assets/mesh.vert @@ -1,12 +1,12 @@ out vec2 frag_uv; out vec3 o_normal; out vec3 o_camdir; -out vec3 o_lightdir; out vec4 frag_color; uniform mat4 projection; uniform mat4 view; +uniform vec3 eyeposition; vec3 tovec3(vec2 v){return vec3(v, 0.0);} vec3 tovec3(vec3 v){return v;} @@ -61,22 +61,15 @@ vec4 vertex_color(float value, vec2 colorrange, sampler2D colormap){ } } -void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection, vec3 lightposition) +void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection) { // normal in world space o_normal = get_normalmatrix() * normal; - // position in view space (as seen from camera) - vec4 view_pos = view * position_world; // position in clip space (w/ depth) - gl_Position = projection * view_pos; + gl_Position = projection * view * position_world; // TODO consider using projectionview directly gl_Position.z += gl_Position.w * get_depth_shift(); - // direction to light - o_lightdir = normalize(view*vec4(lightposition, 1.0) - view_pos).xyz; // direction to camera - // This is equivalent to - // normalize(view*vec4(eyeposition, 1.0) - view_pos).xyz - // (by definition `view * eyeposition = 0`) - o_camdir = normalize(-view_pos).xyz; + o_camdir = position_world.xyz / position_world.w - eyeposition; } flat out uint frag_instance_id; @@ -90,7 +83,7 @@ void main(){ } vec4 position_world = model * vec4(vertex_position, 1); - render(position_world, get_normals(), view, projection, get_lightposition()); + render(position_world, get_normals(), view, projection); frag_uv = get_uv(); frag_uv = vec2(1.0 - frag_uv.y, frag_uv.x); frag_color = vertex_color(get_color(), get_colorrange(), colormap); diff --git a/WGLMakie/assets/particles.frag b/WGLMakie/assets/particles.frag index 5615fb356da..262a1fd9538 100644 --- a/WGLMakie/assets/particles.frag +++ b/WGLMakie/assets/particles.frag @@ -1,23 +1,34 @@ in vec4 frag_color; in vec3 frag_normal; in vec3 frag_position; -in vec3 frag_lightdir; +in vec3 o_camdir; + +// Smoothes out edge around 0 light intensity, see GLMakie +float smooth_zero_max(float x) { + const float c = 0.00390625, xswap = 0.6406707120152759, yswap = 0.20508383900190955; + const float shift = 1.0 + xswap - yswap; + float pow8 = x + shift; + pow8 = pow8 * pow8; pow8 = pow8 * pow8; pow8 = pow8 * pow8; + return x < yswap ? c * pow8 : x; +} vec3 blinnphong(vec3 N, vec3 V, vec3 L, vec3 color){ - float diff_coeff = max(dot(L, N), 0.0); + float backlight = get_backlight(); + float diff_coeff = smooth_zero_max(dot(L, -N)) + + backlight * smooth_zero_max(dot(L, N)); // specular coefficient - vec3 H = normalize(L+V); + vec3 H = normalize(L + V); - float spec_coeff = pow(max(dot(H, N), 0.0), 8.0); + float spec_coeff = pow(max(dot(H, -N), 0.0), get_shininess()) + + backlight * pow(max(dot(H, N), 0.0), get_shininess()); if (diff_coeff <= 0.0) spec_coeff = 0.0; // final lighting model - return vec3( - vec3(0.1) * vec3(0.3) + - vec3(0.9) * color * diff_coeff + - vec3(0.3) * spec_coeff + return get_light_color() * vec3( + get_diffuse() * diff_coeff * color + + get_specular() * spec_coeff ); } @@ -32,13 +43,12 @@ vec4 pack_int(uint id, uint index) { } void main() { - vec3 L, N, light1, light2, color; + vec3 L, N, light, color; if (get_shading()) { - L = normalize(frag_lightdir); + L = get_light_direction(); N = normalize(frag_normal); - light1 = blinnphong(N, frag_position, L, frag_color.rgb); - light2 = blinnphong(N, frag_position, -L, frag_color.rgb); - color = get_ambient() * frag_color.rgb + light1 + get_backlight() * light2; + light = blinnphong(N, normalize(o_camdir), L, frag_color.rgb); + color = get_ambient() * frag_color.rgb + light; } else { color = frag_color.rgb; } diff --git a/WGLMakie/assets/particles.vert b/WGLMakie/assets/particles.vert index f2785d2aed4..e9bd0a356c3 100644 --- a/WGLMakie/assets/particles.vert +++ b/WGLMakie/assets/particles.vert @@ -2,13 +2,12 @@ precision mediump float; uniform mat4 projection; uniform mat4 view; +uniform vec3 eyeposition; out vec3 frag_normal; out vec3 frag_position; - out vec4 frag_color; -out vec3 frag_lightdir; - +out vec3 o_camdir; vec3 qmul(vec4 q, vec3 v){ return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); @@ -31,16 +30,14 @@ 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 lightpos = vec3(20,20,20); vec3 N = get_normals(); rotate(get_rotations(), vertex_position, N); vertex_position = to_vec3(get_offset()) + vertex_position; vec4 position_world = model * vec4(vertex_position, 1); frag_normal = N; - frag_lightdir = normalize(lightpos - position_world.xyz); frag_color = to_vec4(get_color()); // direction to camera - frag_position = -position_world.xyz; + o_camdir = position_world.xyz / position_world.w - eyeposition; // screen space coordinates of the position gl_Position = projection * view * position_world; gl_Position.z += gl_Position.w * get_depth_shift(); diff --git a/WGLMakie/assets/sprites.vert b/WGLMakie/assets/sprites.vert index 42a7c4a9cc6..35f8eaedd86 100644 --- a/WGLMakie/assets/sprites.vert +++ b/WGLMakie/assets/sprites.vert @@ -61,15 +61,19 @@ void main(){ vec2 sprite_bbox_centre = get_quad_offset() + bbox_signed_radius; mat4 pview = projection * view; - // Compute transform for the offset vectors from the central point mat4 trans = get_transform_marker() ? model : mat4(1.0); - trans = (get_billboard() ? projection : pview) * qmat(get_rotations()) * trans; // Compute centre of billboard in clipping coordinates - vec4 sprite_center = trans * vec4(sprite_bbox_centre, 0, 0); + // Always transform text/scatter position argument vec4 data_point = get_preprojection() * model * vec4(tovec3(get_pos()), 1); - data_point = vec4(data_point.xyz / data_point.w + mat3(model) * tovec3(get_marker_offset()), 1); + // maybe transform marker_offset + glyph offsets + data_point = vec4(data_point.xyz / data_point.w + mat3(trans) * tovec3(get_marker_offset()), 1); data_point = pview * data_point; + + // Compute transform for the offset vectors from the central point + trans = (get_billboard() ? projection : pview) * qmat(get_rotations()) * trans; + vec4 sprite_center = trans * vec4(sprite_bbox_centre, 0, 0); + vec4 vclip = data_point + sprite_center; // Extra buffering is required around sprites which are antialiased so that @@ -88,7 +92,7 @@ void main(){ 0.0, 0.0, 1.0/vclip.w, 0.0, -vclip.xyz/(vclip.w*vclip.w), 0.0 ); - mat2 dxyv_dxys = diagm(0.5 * get_resolution()) * mat2(d_ndc_d_clip*trans); + mat2 dxyv_dxys = diagm(0.5 * px_per_unit * get_resolution()) * mat2(d_ndc_d_clip*trans); // Now, our buffer size is expressed in viewport pixels but we get back to // the sprite coordinate system using the scale factor of the // transformation (for isotropic transformations). For anisotropic diff --git a/WGLMakie/assets/volume.frag b/WGLMakie/assets/volume.frag index ec37e457671..d3048f8afee 100644 --- a/WGLMakie/assets/volume.frag +++ b/WGLMakie/assets/volume.frag @@ -2,7 +2,6 @@ struct Nothing{ //Nothing type, to encode if some variable doesn't contain any d bool _; //empty structs are not allowed }; in vec3 frag_vert; -in vec3 o_light_dir; const float max_distance = 1.3; @@ -54,16 +53,25 @@ vec3 gennormal(vec3 uvw, float d) return normalize(a-b); } +// Smoothes out edge around 0 light intensity, see GLMakie +float smooth_zero_max(float x) { + const float c = 0.00390625, xswap = 0.6406707120152759, yswap = 0.20508383900190955; + const float shift = 1.0 + xswap - yswap; + float pow8 = x + shift; + pow8 = pow8 * pow8; pow8 = pow8 * pow8; pow8 = pow8 * pow8; + return x < yswap ? c * pow8 : x; +} + vec3 blinnphong(vec3 N, vec3 V, vec3 L, vec3 color){ - float diff_coeff = max(dot(L, N), 0.0) + max(dot(L, -N), 0.0); + // TODO use backlight here too? + float diff_coeff = smooth_zero_max(dot(L, -N)) + smooth_zero_max(dot(L, N)); // specular coefficient vec3 H = normalize(L + V); - float spec_coeff = pow(max(dot(H, N), 0.0) + max(dot(H, -N), 0.0), shininess); + float spec_coeff = pow(max(dot(H, -N), 0.0) + max(dot(H, N), 0.0), shininess); // final lighting model - return vec3( - ambient * color + - diffuse * diff_coeff * color + - specular * spec_coeff + return ambient * color + get_light_color() * vec3( + get_diffuse() * diff_coeff * color + + get_specular() * spec_coeff ); } @@ -122,14 +130,14 @@ vec4 contours(vec3 front, vec3 dir) float T = 1.0; vec3 Lo = vec3(0.0); int i = 0; - vec3 camdir = normalize(-dir); + vec3 camdir = normalize(dir); for (i; i < num_samples; ++i) { float intensity = texture(volumedata, pos).x; vec4 density = color_lookup(intensity, colormap, colorrange); float opacity = density.a; if(opacity > 0.0){ vec3 N = gennormal(pos, step_size); - vec3 L = normalize(o_light_dir - pos); + vec3 L = get_light_direction(); vec3 opaque = blinnphong(N, camdir, L, density.rgb); Lo += (T * opacity) * opaque; T *= 1.0 - opacity; @@ -147,12 +155,12 @@ vec4 isosurface(vec3 front, vec3 dir) vec4 c = vec4(0.0); int i = 0; vec4 diffuse_color = color_lookup(isovalue, colormap, colorrange); - vec3 camdir = normalize(-dir); + vec3 camdir = normalize(dir); for (i; i < num_samples; ++i){ float density = texture(volumedata, pos).x; if(abs(density - isovalue) < isorange){ vec3 N = gennormal(pos, step_size); - vec3 L = normalize(o_light_dir - pos); + vec3 L = get_light_direction(); c = vec4( blinnphong(N, camdir, L, diffuse_color.rgb), diffuse_color.a diff --git a/WGLMakie/assets/volume.vert b/WGLMakie/assets/volume.vert index 42599e3e6a3..c9d00be85b8 100644 --- a/WGLMakie/assets/volume.vert +++ b/WGLMakie/assets/volume.vert @@ -1,5 +1,4 @@ out vec3 frag_vert; -out vec3 o_light_dir; uniform mat4 projection, view; @@ -7,7 +6,6 @@ void main() { frag_vert = position; vec4 world_vert = model * vec4(position, 1); - o_light_dir = vec3(modelinv * vec4(get_lightposition(), 1)); gl_Position = projection * view * world_vert; gl_Position.z += gl_Position.w * get_depth_shift(); } diff --git a/WGLMakie/src/Camera.js b/WGLMakie/src/Camera.js index 25223aca629..1a2b02d3655 100644 --- a/WGLMakie/src/Camera.js +++ b/WGLMakie/src/Camera.js @@ -1,18 +1,20 @@ -import * as THREE from "https://cdn.esm.sh/v66/three@0.136/es2021/three.js"; - -const pixelRatio = window.devicePixelRatio || 1.0; - -export function event2scene_pixel(scene, event) { - const { canvas } = scene.screen; +import * as THREE from "./THREE.js"; +import { OrbitControls } from "./OrbitControls.js"; + +// Unitless is the scene pixel unit space +// so scene.viewport, or size(scene) +// Which isn't the same as the framebuffer pixel size due to scalefactor/px_per_unit/devicePixelRatio +export function events2unitless(screen, event) { + const { canvas, winscale, renderer } = screen; const rect = canvas.getBoundingClientRect(); - const x = (event.clientX - rect.left) * pixelRatio; - const y = (rect.height - (event.clientY - rect.top)) * pixelRatio; - return [x, y]; + const x = (event.clientX - rect.left) / winscale; + const y = (event.clientY - rect.top) / winscale; + return [x, renderer._height - y]; } export function to_world(scene, x, y) { const proj_inv = scene.wgl_camera.projectionview_inverse.value; - const [_x, _y, w, h] = scene.pixelarea.value; + const [_x, _y, w, h] = scene.viewport.value; const pix_space = new THREE.Vector4( ((x - _x) / w) * 2 - 1, ((y - _y) / h) * 2 - 1, @@ -32,30 +34,42 @@ function Identity4x4() { } function in_scene(scene, mouse_event) { - const [x, y] = event2scene_pixel(scene, mouse_event); - const [sx, sy, sw, sh] = scene.pixelarea.value; + const [x, y] = events2unitless(scene.screen, mouse_event); + const [sx, sy, sw, sh] = scene.viewport.value; return x >= sx && x < sx + sw && y >= sy && y < sy + sh; } // Taken from https://andreasrohner.at/posts/Web%20Development/JavaScript/Simple-orbital-camera-controls-for-THREE-js/ -export function attach_3d_camera(canvas, makie_camera, cam3d, scene) { +export function attach_3d_camera( + canvas, + makie_camera, + cam3d, + light_dir, + scene +) { if (cam3d === undefined) { // we just support 3d cameras atm return; } const [w, h] = makie_camera.resolution.value; const camera = new THREE.PerspectiveCamera( - cam3d.fov, + cam3d.fov.value, w / h, - cam3d.near, - cam3d.far + 0.01, + 100.0 ); - const center = new THREE.Vector3(...cam3d.lookat); - camera.up = new THREE.Vector3(...cam3d.upvector); - camera.position.set(...cam3d.eyeposition); + const center = new THREE.Vector3(...cam3d.lookat.value); + camera.up = new THREE.Vector3(...cam3d.upvector.value); + camera.position.set(...cam3d.eyeposition.value); camera.lookAt(center); - function update() { + + const use_orbit_cam = () => + !(JSServe.can_send_to_julia && JSServe.can_send_to_julia()); + const controls = new OrbitControls(camera, canvas, use_orbit_cam, (e) => + in_scene(scene, e) + ); + controls.addEventListener("change", (e) => { const view = camera.matrixWorldInverse; const projection = camera.projectionMatrix; const [width, height] = cam3d.resolution.value; @@ -63,103 +77,14 @@ export function attach_3d_camera(canvas, makie_camera, cam3d, scene) { 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; - let startDragY = null; - function mouseWheelHandler(e) { - e = window.event || e; - if (!in_scene(scene, e)) { - return; - } - const delta = Math.sign(e.deltaY); - if (delta == -1) { - zoomOut(); - } else if (delta == 1) { - zoomIn(); - } - - e.preventDefault(); - } - function mouseDownHandler(e) { - if (!in_scene(scene, e)) { - return; - } - startDragX = e.clientX; - startDragY = e.clientY; - - e.preventDefault(); - } - function mouseMoveHandler(e) { - if (!in_scene(scene, e)) { - return; - } - if (startDragX === null || startDragY === null) return; - - if (drag) drag(e.clientX - startDragX, e.clientY - startDragY); - - startDragX = e.clientX; - startDragY = e.clientY; - e.preventDefault(); - } - function mouseUpHandler(e) { - if (!in_scene(scene, e)) { - return; - } - mouseMoveHandler.call(this, e); - startDragX = null; - startDragY = null; - e.preventDefault(); - } - domObject.addEventListener("wheel", mouseWheelHandler); - domObject.addEventListener("mousedown", mouseDownHandler); - domObject.addEventListener("mousemove", mouseMoveHandler); - domObject.addEventListener("mouseup", mouseUpHandler); - } - - function drag(deltaX, deltaY) { - const radPerPixel = Math.PI / 450; - const deltaPhi = radPerPixel * deltaX; - const deltaTheta = radPerPixel * deltaY; - const pos = camera.position.sub(center); - const radius = pos.length(); - let theta = Math.acos(pos.z / radius); - let phi = Math.atan2(pos.y, pos.x); - - // Subtract deltaTheta and deltaPhi - theta = Math.min(Math.max(theta - deltaTheta, 0), Math.PI); - phi -= deltaPhi; - - // Turn back into Cartesian coordinates - pos.x = radius * Math.sin(theta) * Math.cos(phi); - pos.y = radius * Math.sin(theta) * Math.sin(phi); - pos.z = radius * Math.cos(theta); - - camera.position.add(center); - camera.lookAt(center); - update(); - } - - function zoomIn() { - camera.position.sub(center).multiplyScalar(0.9).add(center); - update(); - } - - function zoomOut() { - camera.position.sub(center).multiplyScalar(1.1).add(center); - update(); - } - - addMouseHandler(canvas, drag, zoomIn, zoomOut); + ); + makie_camera.update_light_dir(light_dir.value); + }); } function mul(a, b) { @@ -239,6 +164,12 @@ export class MakieCamera { // Lazy calculation, only if a plot type requests them // will be of the form: {[space, markerspace]: THREE.Uniform(...)} this.preprojections = {}; + + // For camera-relative light directions + // TODO: intial position wrong... + this.light_direction = new THREE.Uniform( + new THREE.Vector3(-1, -1, -1).normalize() + ); } calculate_matrices() { @@ -274,6 +205,13 @@ export class MakieCamera { return; } + update_light_dir(light_dir) { + const T = new THREE.Matrix3().setFromMatrix4(this.view.value).invert(); + const new_dir = new THREE.Vector3().fromArray(light_dir); + new_dir.applyMatrix3(T).normalize(); + this.light_direction.value = new_dir; + } + clip_to_space(space) { if (space === "data") { return this.projectionview_inverse.value; diff --git a/WGLMakie/src/Lines.js b/WGLMakie/src/Lines.js new file mode 100644 index 00000000000..8fda06ae4eb --- /dev/null +++ b/WGLMakie/src/Lines.js @@ -0,0 +1,285 @@ +import { + attributes_to_type_declaration, + uniforms_to_type_declaration, + uniform_type, + attribute_type, +} from "./Shaders.js"; + +import { deserialize_uniforms } from "./Serialization.js"; + +function filter_by_key(dict, keys, default_value = false) { + const result = {}; + keys.forEach((key) => { + const val = dict[key]; + if (val) { + result[key] = val; + } else { + result[key] = default_value; + } + }); + return result; +} + +// https://github.com/glslify/glsl-aastep +// https://wwwtyro.net/2019/11/18/instanced-lines.html +// https://github.com/mrdoob/three.js/blob/dev/examples/jsm/lines/LineMaterial.js +// https://www.khronos.org/assets/uploads/developers/presentations/Crazy_Panda_How_to_draw_lines_in_WebGL.pdf +// https://github.com/gameofbombs/pixi-candles/tree/master/src +// https://github.com/wwwtyro/instanced-lines-demos/tree/master +function linesegments_vertex_shader(uniforms, attributes) { + const attribute_decl = attributes_to_type_declaration(attributes); + const uniform_decl = uniforms_to_type_declaration(uniforms); + const color = + attribute_type(attributes.color_start) || + uniform_type(uniforms.color_start); + + return `precision mediump int; + precision highp float; + + ${attribute_decl} + ${uniform_decl} + + out vec2 f_uv; + out ${color} f_color; + + vec2 get_resolution() { + // 2 * px_per_unit doesn't make any sense, but works + // TODO, figure out what's going on! + return resolution / 2.0 * px_per_unit; + } + + vec3 screen_space(vec3 point) { + vec4 vertex = projectionview * model * vec4(point, 1); + return vec3(vertex.xy * get_resolution(), vertex.z + vertex.w * depth_shift) / vertex.w; + } + + vec3 screen_space(vec2 point) { + return screen_space(vec3(point, 0)); + } + + void main() { + vec3 p_a = screen_space(linepoint_start); + vec3 p_b = screen_space(linepoint_end); + float width = (px_per_unit * (position.x == 1.0 ? linewidth_end : linewidth_start)); + f_color = position.x == 1.0 ? color_end : color_start; + f_uv = vec2(position.x, position.y + 0.5); + + vec2 pointA = p_a.xy; + vec2 pointB = p_b.xy; + + vec2 xBasis = pointB - pointA; + vec2 yBasis = normalize(vec2(-xBasis.y, xBasis.x)); + vec2 point = pointA + xBasis * position.x + yBasis * width * position.y; + + gl_Position = vec4(point.xy / get_resolution(), position.x == 1.0 ? p_b.z : p_a.z, 1.0); + } + `; +} + +function lines_fragment_shader(uniforms, attributes) { + const color = + attribute_type(attributes.color_start) || + uniform_type(uniforms.color_start); + const color_uniforms = filter_by_key(uniforms, [ + "colorrange", + "colormap", + "nan_color", + "highclip", + "lowclip", + ]); + const uniform_decl = uniforms_to_type_declaration(color_uniforms); + + return `#extension GL_OES_standard_derivatives : enable + + precision mediump int; + precision highp float; + precision mediump sampler2D; + precision mediump sampler3D; + + in vec2 f_uv; + in ${color} f_color; + ${uniform_decl} + + out vec4 fragment_color; + + // Half width of antialiasing smoothstep + #define ANTIALIAS_RADIUS 0.7071067811865476 + + vec4 get_color_from_cmap(float value, sampler2D colormap, vec2 colorrange) { + float cmin = colorrange.x; + float cmax = colorrange.y; + if (value <= cmax && value >= cmin) { + // in value range, continue! + } else if (value < cmin) { + return lowclip; + } else if (value > cmax) { + return highclip; + } else { + // isnan CAN be broken (of course) -.- + // so if outside value range and not smaller/bigger min/max we assume NaN + return nan_color; + } + float i01 = clamp((value - cmin) / (cmax - cmin), 0.0, 1.0); + // 1/0 corresponds to the corner of the colormap, so to properly interpolate + // between the colors, we need to scale it, so that the ends are at 1 - (stepsize/2) and 0+(stepsize/2). + float stepsize = 1.0 / float(textureSize(colormap, 0)); + i01 = (1.0 - stepsize) * i01 + 0.5 * stepsize; + return texture(colormap, vec2(i01, 0.0)); + } + + vec4 get_color(float color, sampler2D colormap, vec2 colorrange) { + return get_color_from_cmap(color, colormap, colorrange); + } + + vec4 get_color(vec4 color, bool colormap, bool colorrange) { + return color; + } + vec4 get_color(vec3 color, bool colormap, bool colorrange) { + return vec4(color, 1.0); + } + + float aastep(float threshold, float value) { + float afwidth = length(vec2(dFdx(value), dFdy(value))) * ANTIALIAS_RADIUS; + return smoothstep(threshold-afwidth, threshold+afwidth, value); + } + + float aastep(float threshold1, float threshold2, float dist) { + return aastep(threshold1, dist) * aastep(threshold2, 1.0 - dist); + } + + void main(){ + float xalpha = aastep(0.0, 0.0, f_uv.x); + float yalpha = aastep(0.0, 0.0, f_uv.y); + vec4 color = get_color(f_color, colormap, colorrange); + fragment_color = vec4(color.rgb, color.a); + } + `; +} + +function create_line_material(uniforms, attributes) { + const uniforms_des = deserialize_uniforms(uniforms); + return new THREE.RawShaderMaterial({ + uniforms: uniforms_des, + glslVersion: THREE.GLSL3, + vertexShader: linesegments_vertex_shader(uniforms_des, attributes), + fragmentShader: lines_fragment_shader(uniforms_des, attributes), + transparent: true, + }); +} + +function attach_interleaved_line_buffer(attr_name, geometry, points, ndim, is_segments) { + const skip_elems = is_segments ? 2 * ndim : ndim; + const buffer = new THREE.InstancedInterleavedBuffer(points, skip_elems, 1); + geometry.setAttribute( + attr_name + "_start", + new THREE.InterleavedBufferAttribute(buffer, ndim, 0) + ); // xyz1 + geometry.setAttribute( + attr_name + "_end", + new THREE.InterleavedBufferAttribute(buffer, ndim, ndim) + ); // xyz1 + return buffer; +} + +function create_line_instance_geometry() { + const geometry = new THREE.InstancedBufferGeometry(); + const instance_positions = [ + 0, -0.5, 1, -0.5, 1, 0.5, + + 0, -0.5, 1, 0.5, 0, 0.5, + ]; + geometry.setAttribute( + "position", + new THREE.Float32BufferAttribute(instance_positions, 2) + ); + geometry.boundingSphere = new THREE.Sphere(); + // don't use intersection / culling + geometry.boundingSphere.radius = 10000000000000; + geometry.frustumCulled = false; + return geometry; +} + +function create_line_buffer(geometry, buffers, name, attr, is_segments) { + const flat_buffer = attr.value.flat; + const ndims = attr.value.type_length; + const linebuffer = attach_interleaved_line_buffer( + name, + geometry, + flat_buffer, + ndims, + is_segments + ); + buffers[name] = linebuffer; + return flat_buffer; +} + +function create_line_buffers(geometry, buffers, attributes, is_segments) { + for (let name in attributes) { + const attr = attributes[name]; + create_line_buffer(geometry, buffers, name, attr, is_segments); + } +} + +function attach_updates(mesh, buffers, attributes, is_segments) { + let geometry = mesh.geometry; + for (let name in attributes) { + const attr = attributes[name]; + attr.on((new_points) => { + let buff = buffers[name]; + const ndims = new_points.type_length; + const new_line_points = new_points.flat; + const old_count = buff.array.length; + const new_count = new_line_points.length / ndims; + if (old_count < new_line_points.length) { + mesh.geometry.dispose(); + geometry = create_line_instance_geometry(); + buff = attach_interleaved_line_buffer( + name, + geometry, + new_line_points, + ndims, + is_segments + ); + mesh.geometry = geometry; + buffers[name] = buff; + } else { + buff.set(new_line_points); + } + const ls_factor = is_segments ? 2 : 1; + const offset = is_segments ? 0 : 1; + mesh.geometry.instanceCount = Math.max(0, (new_count / ls_factor) - offset); + buff.needsUpdate = true; + mesh.needsUpdate = true; + }); + } +} + +export function _create_line(line_data, is_segments) { + const geometry = create_line_instance_geometry(); + const buffers = {}; + create_line_buffers( + geometry, + buffers, + line_data.attributes, + is_segments + ); + const material = create_line_material( + line_data.uniforms, + geometry.attributes + ); + + const mesh = new THREE.Mesh(geometry, material); + const offset = is_segments ? 0 : 1; + const new_count = geometry.attributes.linepoint_start.count; + mesh.geometry.instanceCount = Math.max(0, new_count - offset); + attach_updates(mesh, buffers, line_data.attributes, is_segments); + return mesh; +} + +export function create_line(line_data) { + return _create_line(line_data, false) +} + +export function create_linesegments(line_data) { + return _create_line(line_data, true) +} diff --git a/WGLMakie/src/OrbitControls.js b/WGLMakie/src/OrbitControls.js new file mode 100644 index 00000000000..8a39fcb2332 --- /dev/null +++ b/WGLMakie/src/OrbitControls.js @@ -0,0 +1,1249 @@ +// Taken from three.js OrbitControls.js +// https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/jsm/controls/OrbitControls.js +import { + EventDispatcher, + MOUSE, + Quaternion, + Spherical, + TOUCH, + Vector2, + Vector3, + Plane, + Ray, + MathUtils, +} from "./THREE.js"; + +// OrbitControls performs orbiting, dollying (zooming), and panning. +// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). +// +// Orbit - left mouse / touch: one-finger move +// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish +// Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move + +const _changeEvent = { type: "change" }; +const _startEvent = { type: "start" }; +const _endEvent = { type: "end" }; +const _ray = new Ray(); +const _plane = new Plane(); +const TILT_LIMIT = Math.cos(70 * MathUtils.DEG2RAD); + +class OrbitControls extends EventDispatcher { + constructor(object, domElement, allow_update, is_in_scene) { + super(); + + this.object = object; + this.domElement = domElement; + this.domElement.style.touchAction = "none"; // disable touch scroll + + // Set to false to disable this control + this.enabled = true; + + // "target" sets the location of focus, where the object orbits around + this.target = new Vector3(); + + // Sets the 3D cursor (similar to Blender), from which the maxTargetRadius takes effect + this.cursor = new Vector3(); + + // How far you can dolly in and out ( PerspectiveCamera only ) + this.minDistance = 0; + this.maxDistance = Infinity; + + // How far you can zoom in and out ( OrthographicCamera only ) + this.minZoom = 0; + this.maxZoom = Infinity; + + // Limit camera target within a spherical area around the cursor + this.minTargetRadius = 0; + this.maxTargetRadius = Infinity; + + // How far you can orbit vertically, upper and lower limits. + // Range is 0 to Math.PI radians. + this.minPolarAngle = 0; // radians + this.maxPolarAngle = Math.PI; // radians + + // How far you can orbit horizontally, upper and lower limits. + // If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI ) + this.minAzimuthAngle = -Infinity; // radians + this.maxAzimuthAngle = Infinity; // radians + + // Set to true to enable damping (inertia) + // If damping is enabled, you must call controls.update() in your animation loop + this.enableDamping = false; + this.dampingFactor = 0.05; + + // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. + // Set to false to disable zooming + this.enableZoom = true; + this.zoomSpeed = 1.0; + + // Set to false to disable rotating + this.enableRotate = true; + this.rotateSpeed = 1.0; + + // Set to false to disable panning + this.enablePan = true; + this.panSpeed = 1.0; + this.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up + this.keyPanSpeed = 7.0; // pixels moved per arrow key push + this.zoomToCursor = false; + + // Set to true to automatically rotate around the target + // If auto-rotate is enabled, you must call controls.update() in your animation loop + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per orbit when fps is 60 + + // The four arrow keys + this.keys = { + LEFT: "ArrowLeft", + UP: "ArrowUp", + RIGHT: "ArrowRight", + BOTTOM: "ArrowDown", + }; + + // Mouse buttons + this.mouseButtons = { + LEFT: MOUSE.ROTATE, + MIDDLE: MOUSE.DOLLY, + RIGHT: MOUSE.PAN, + }; + + // Touch fingers + this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN }; + + // for reset + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; + + // the target DOM element for key events + this._domElementKeyEvents = null; + + // + // public methods + // + + this.getPolarAngle = function () { + return spherical.phi; + }; + + this.getAzimuthalAngle = function () { + return spherical.theta; + }; + + this.getDistance = function () { + return this.object.position.distanceTo(this.target); + }; + + this.listenToKeyEvents = function (domElement) { + domElement.addEventListener("keydown", onKeyDown); + this._domElementKeyEvents = domElement; + }; + + this.stopListenToKeyEvents = function () { + this._domElementKeyEvents.removeEventListener("keydown", onKeyDown); + this._domElementKeyEvents = null; + }; + + this.saveState = function () { + scope.target0.copy(scope.target); + scope.position0.copy(scope.object.position); + scope.zoom0 = scope.object.zoom; + }; + + this.reset = function () { + scope.target.copy(scope.target0); + scope.object.position.copy(scope.position0); + scope.object.zoom = scope.zoom0; + + scope.object.updateProjectionMatrix(); + scope.dispatchEvent(_changeEvent); + + scope.update(); + + state = STATE.NONE; + }; + + // this method is exposed, but perhaps it would be better if we can make it private... + this.update = (function () { + const offset = new Vector3(); + + // so camera.up is the orbit axis + const quat = new Quaternion().setFromUnitVectors( + object.up, + new Vector3(0, 1, 0) + ); + const quatInverse = quat.clone().invert(); + + const lastPosition = new Vector3(); + const lastQuaternion = new Quaternion(); + const lastTargetPosition = new Vector3(); + + const twoPI = 2 * Math.PI; + + return function update(deltaTime = null) { + if (!allow_update()) { + return; + } + const position = scope.object.position; + + offset.copy(position).sub(scope.target); + + // rotate offset to "y-axis-is-up" space + offset.applyQuaternion(quat); + + // angle from z-axis around y-axis + spherical.setFromVector3(offset); + + if (scope.autoRotate && state === STATE.NONE) { + rotateLeft(getAutoRotationAngle(deltaTime)); + } + + if (scope.enableDamping) { + spherical.theta += + sphericalDelta.theta * scope.dampingFactor; + spherical.phi += sphericalDelta.phi * scope.dampingFactor; + } else { + spherical.theta += sphericalDelta.theta; + spherical.phi += sphericalDelta.phi; + } + + // restrict theta to be between desired limits + + let min = scope.minAzimuthAngle; + let max = scope.maxAzimuthAngle; + + if (isFinite(min) && isFinite(max)) { + if (min < -Math.PI) min += twoPI; + else if (min > Math.PI) min -= twoPI; + + if (max < -Math.PI) max += twoPI; + else if (max > Math.PI) max -= twoPI; + + if (min <= max) { + spherical.theta = Math.max( + min, + Math.min(max, spherical.theta) + ); + } else { + spherical.theta = + spherical.theta > (min + max) / 2 + ? Math.max(min, spherical.theta) + : Math.min(max, spherical.theta); + } + } + + // restrict phi to be between desired limits + spherical.phi = Math.max( + scope.minPolarAngle, + Math.min(scope.maxPolarAngle, spherical.phi) + ); + + spherical.makeSafe(); + + // move target to panned location + + if (scope.enableDamping === true) { + scope.target.addScaledVector( + panOffset, + scope.dampingFactor + ); + } else { + scope.target.add(panOffset); + } + + // Limit the target distance from the cursor to create a sphere around the center of interest + scope.target.sub(scope.cursor); + scope.target.clampLength( + scope.minTargetRadius, + scope.maxTargetRadius + ); + scope.target.add(scope.cursor); + + // adjust the camera position based on zoom only if we're not zooming to the cursor or if it's an ortho camera + // we adjust zoom later in these cases + if ( + (scope.zoomToCursor && performCursorZoom) || + scope.object.isOrthographicCamera + ) { + spherical.radius = clampDistance(spherical.radius); + } else { + spherical.radius = clampDistance(spherical.radius * scale); + } + + offset.setFromSpherical(spherical); + + // rotate offset back to "camera-up-vector-is-up" space + offset.applyQuaternion(quatInverse); + + position.copy(scope.target).add(offset); + + scope.object.lookAt(scope.target); + + if (scope.enableDamping === true) { + sphericalDelta.theta *= 1 - scope.dampingFactor; + sphericalDelta.phi *= 1 - scope.dampingFactor; + + panOffset.multiplyScalar(1 - scope.dampingFactor); + } else { + sphericalDelta.set(0, 0, 0); + + panOffset.set(0, 0, 0); + } + + // adjust camera position + let zoomChanged = false; + if (scope.zoomToCursor && performCursorZoom) { + let newRadius = null; + if (scope.object.isPerspectiveCamera) { + // move the camera down the pointer ray + // this method avoids floating point error + const prevRadius = offset.length(); + newRadius = clampDistance(prevRadius * scale); + + const radiusDelta = prevRadius - newRadius; + scope.object.position.addScaledVector( + dollyDirection, + radiusDelta + ); + scope.object.updateMatrixWorld(); + } else if (scope.object.isOrthographicCamera) { + // adjust the ortho camera position based on zoom changes + const mouseBefore = new Vector3(mouse.x, mouse.y, 0); + mouseBefore.unproject(scope.object); + + scope.object.zoom = Math.max( + scope.minZoom, + Math.min(scope.maxZoom, scope.object.zoom / scale) + ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + const mouseAfter = new Vector3(mouse.x, mouse.y, 0); + mouseAfter.unproject(scope.object); + + scope.object.position.sub(mouseAfter).add(mouseBefore); + scope.object.updateMatrixWorld(); + + newRadius = offset.length(); + } else { + console.warn( + "WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled." + ); + scope.zoomToCursor = false; + } + + // handle the placement of the target + if (newRadius !== null) { + if (this.screenSpacePanning) { + // position the orbit target in front of the new camera position + scope.target + .set(0, 0, -1) + .transformDirection(scope.object.matrix) + .multiplyScalar(newRadius) + .add(scope.object.position); + } else { + // get the ray and translation plane to compute target + _ray.origin.copy(scope.object.position); + _ray.direction + .set(0, 0, -1) + .transformDirection(scope.object.matrix); + + // if the camera is 20 degrees above the horizon then don't adjust the focus target to avoid + // extremely large values + if ( + Math.abs(scope.object.up.dot(_ray.direction)) < + TILT_LIMIT + ) { + object.lookAt(scope.target); + } else { + _plane.setFromNormalAndCoplanarPoint( + scope.object.up, + scope.target + ); + _ray.intersectPlane(_plane, scope.target); + } + } + } + } else if (scope.object.isOrthographicCamera) { + scope.object.zoom = Math.max( + scope.minZoom, + Math.min(scope.maxZoom, scope.object.zoom / scale) + ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + } + + scale = 1; + performCursorZoom = false; + + // update condition is: + // min(camera displacement, camera rotation in radians)^2 > EPS + // using small-angle approximation cos(x/2) = 1 - x^2 / 8 + + if ( + zoomChanged || + lastPosition.distanceToSquared(scope.object.position) > + EPS || + 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > + EPS || + lastTargetPosition.distanceToSquared(scope.target) > 0 + ) { + scope.dispatchEvent(_changeEvent); + + lastPosition.copy(scope.object.position); + lastQuaternion.copy(scope.object.quaternion); + lastTargetPosition.copy(scope.target); + + zoomChanged = false; + + return true; + } + + return false; + }; + })(); + + this.dispose = function () { + scope.domElement.removeEventListener("contextmenu", onContextMenu); + + scope.domElement.removeEventListener("pointerdown", onPointerDown); + scope.domElement.removeEventListener("pointercancel", onPointerUp); + scope.domElement.removeEventListener("wheel", onMouseWheel); + + scope.domElement.removeEventListener("pointermove", onPointerMove); + scope.domElement.removeEventListener("pointerup", onPointerUp); + + if (scope._domElementKeyEvents !== null) { + scope._domElementKeyEvents.removeEventListener( + "keydown", + onKeyDown + ); + scope._domElementKeyEvents = null; + } + + //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? + }; + + // + // internals + // + + const scope = this; + + const STATE = { + NONE: -1, + ROTATE: 0, + DOLLY: 1, + PAN: 2, + TOUCH_ROTATE: 3, + TOUCH_PAN: 4, + TOUCH_DOLLY_PAN: 5, + TOUCH_DOLLY_ROTATE: 6, + }; + + let state = STATE.NONE; + + const EPS = 0.000001; + + // current position in spherical coordinates + const spherical = new Spherical(); + const sphericalDelta = new Spherical(); + + let scale = 1; + const panOffset = new Vector3(); + + const rotateStart = new Vector2(); + const rotateEnd = new Vector2(); + const rotateDelta = new Vector2(); + + const panStart = new Vector2(); + const panEnd = new Vector2(); + const panDelta = new Vector2(); + + const dollyStart = new Vector2(); + const dollyEnd = new Vector2(); + const dollyDelta = new Vector2(); + + const dollyDirection = new Vector3(); + const mouse = new Vector2(); + let performCursorZoom = false; + + const pointers = []; + const pointerPositions = {}; + + function getAutoRotationAngle(deltaTime) { + if (deltaTime !== null) { + return ((2 * Math.PI) / 60) * scope.autoRotateSpeed * deltaTime; + } else { + return ((2 * Math.PI) / 60 / 60) * scope.autoRotateSpeed; + } + } + + function getZoomScale() { + return Math.pow(0.95, scope.zoomSpeed); + } + + function rotateLeft(angle) { + sphericalDelta.theta -= angle; + } + + function rotateUp(angle) { + sphericalDelta.phi -= angle; + } + + const panLeft = (function () { + const v = new Vector3(); + + return function panLeft(distance, objectMatrix) { + v.setFromMatrixColumn(objectMatrix, 0); // get X column of objectMatrix + v.multiplyScalar(-distance); + + panOffset.add(v); + }; + })(); + + const panUp = (function () { + const v = new Vector3(); + + return function panUp(distance, objectMatrix) { + if (scope.screenSpacePanning === true) { + v.setFromMatrixColumn(objectMatrix, 1); + } else { + v.setFromMatrixColumn(objectMatrix, 0); + v.crossVectors(scope.object.up, v); + } + + v.multiplyScalar(distance); + + panOffset.add(v); + }; + })(); + + // deltaX and deltaY are in pixels; right and down are positive + const pan = (function () { + const offset = new Vector3(); + + return function pan(deltaX, deltaY) { + const element = scope.domElement; + + if (scope.object.isPerspectiveCamera) { + // perspective + const position = scope.object.position; + offset.copy(position).sub(scope.target); + let targetDistance = offset.length(); + + // half of the fov is center to top of screen + targetDistance *= Math.tan( + ((scope.object.fov / 2) * Math.PI) / 180.0 + ); + + // we use only clientHeight here so aspect ratio does not distort speed + panLeft( + (2 * deltaX * targetDistance) / element.clientHeight, + scope.object.matrix + ); + panUp( + (2 * deltaY * targetDistance) / element.clientHeight, + scope.object.matrix + ); + } else if (scope.object.isOrthographicCamera) { + // orthographic + panLeft( + (deltaX * (scope.object.right - scope.object.left)) / + scope.object.zoom / + element.clientWidth, + scope.object.matrix + ); + panUp( + (deltaY * (scope.object.top - scope.object.bottom)) / + scope.object.zoom / + element.clientHeight, + scope.object.matrix + ); + } else { + // camera neither orthographic nor perspective + console.warn( + "WARNING: OrbitControls.js encountered an unknown camera type - pan disabled." + ); + scope.enablePan = false; + } + }; + })(); + + function dollyOut(dollyScale) { + if ( + scope.object.isPerspectiveCamera || + scope.object.isOrthographicCamera + ) { + scale /= dollyScale; + } else { + console.warn( + "WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled." + ); + scope.enableZoom = false; + } + } + + function dollyIn(dollyScale) { + if ( + scope.object.isPerspectiveCamera || + scope.object.isOrthographicCamera + ) { + scale *= dollyScale; + } else { + console.warn( + "WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled." + ); + scope.enableZoom = false; + } + } + + function updateMouseParameters(event) { + if (!scope.zoomToCursor) { + return; + } + + performCursorZoom = true; + + const rect = scope.domElement.getBoundingClientRect(); + const x = event.clientX - rect.left; + const y = event.clientY - rect.top; + const w = rect.width; + const h = rect.height; + + mouse.x = (x / w) * 2 - 1; + mouse.y = -(y / h) * 2 + 1; + + dollyDirection + .set(mouse.x, mouse.y, 1) + .unproject(scope.object) + .sub(scope.object.position) + .normalize(); + } + + function clampDistance(dist) { + return Math.max( + scope.minDistance, + Math.min(scope.maxDistance, dist) + ); + } + + // + // event callbacks - update the object state + // + + function handleMouseDownRotate(event) { + rotateStart.set(event.clientX, event.clientY); + } + + function handleMouseDownDolly(event) { + updateMouseParameters(event); + dollyStart.set(event.clientX, event.clientY); + } + + function handleMouseDownPan(event) { + panStart.set(event.clientX, event.clientY); + } + + function handleMouseMoveRotate(event) { + rotateEnd.set(event.clientX, event.clientY); + + rotateDelta + .subVectors(rotateEnd, rotateStart) + .multiplyScalar(scope.rotateSpeed); + + const element = scope.domElement; + + rotateLeft((2 * Math.PI * rotateDelta.x) / element.clientHeight); // yes, height + + rotateUp((2 * Math.PI * rotateDelta.y) / element.clientHeight); + + rotateStart.copy(rotateEnd); + + scope.update(); + } + + function handleMouseMoveDolly(event) { + dollyEnd.set(event.clientX, event.clientY); + + dollyDelta.subVectors(dollyEnd, dollyStart); + + if (dollyDelta.y > 0) { + dollyOut(getZoomScale()); + } else if (dollyDelta.y < 0) { + dollyIn(getZoomScale()); + } + + dollyStart.copy(dollyEnd); + + scope.update(); + } + + function handleMouseMovePan(event) { + panEnd.set(event.clientX, event.clientY); + + panDelta + .subVectors(panEnd, panStart) + .multiplyScalar(scope.panSpeed); + + pan(panDelta.x, panDelta.y); + + panStart.copy(panEnd); + + scope.update(); + } + + function handleMouseWheel(event) { + updateMouseParameters(event); + + if (event.deltaY < 0) { + dollyIn(getZoomScale()); + } else if (event.deltaY > 0) { + dollyOut(getZoomScale()); + } + + scope.update(); + } + + function handleKeyDown(event) { + let needsUpdate = false; + + switch (event.code) { + case scope.keys.UP: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + rotateUp( + (2 * Math.PI * scope.rotateSpeed) / + scope.domElement.clientHeight + ); + } else { + pan(0, scope.keyPanSpeed); + } + + needsUpdate = true; + break; + + case scope.keys.BOTTOM: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + rotateUp( + (-2 * Math.PI * scope.rotateSpeed) / + scope.domElement.clientHeight + ); + } else { + pan(0, -scope.keyPanSpeed); + } + + needsUpdate = true; + break; + + case scope.keys.LEFT: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + rotateLeft( + (2 * Math.PI * scope.rotateSpeed) / + scope.domElement.clientHeight + ); + } else { + pan(scope.keyPanSpeed, 0); + } + + needsUpdate = true; + break; + + case scope.keys.RIGHT: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + rotateLeft( + (-2 * Math.PI * scope.rotateSpeed) / + scope.domElement.clientHeight + ); + } else { + pan(-scope.keyPanSpeed, 0); + } + + needsUpdate = true; + break; + } + + if (needsUpdate) { + // prevent the browser from scrolling on cursor keys + event.preventDefault(); + + scope.update(); + } + } + + function handleTouchStartRotate() { + if (pointers.length === 1) { + rotateStart.set(pointers[0].pageX, pointers[0].pageY); + } else { + const x = 0.5 * (pointers[0].pageX + pointers[1].pageX); + const y = 0.5 * (pointers[0].pageY + pointers[1].pageY); + + rotateStart.set(x, y); + } + } + + function handleTouchStartPan() { + if (pointers.length === 1) { + panStart.set(pointers[0].pageX, pointers[0].pageY); + } else { + const x = 0.5 * (pointers[0].pageX + pointers[1].pageX); + const y = 0.5 * (pointers[0].pageY + pointers[1].pageY); + + panStart.set(x, y); + } + } + + function handleTouchStartDolly() { + const dx = pointers[0].pageX - pointers[1].pageX; + const dy = pointers[0].pageY - pointers[1].pageY; + + const distance = Math.sqrt(dx * dx + dy * dy); + + dollyStart.set(0, distance); + } + + function handleTouchStartDollyPan() { + if (scope.enableZoom) handleTouchStartDolly(); + + if (scope.enablePan) handleTouchStartPan(); + } + + function handleTouchStartDollyRotate() { + if (scope.enableZoom) handleTouchStartDolly(); + + if (scope.enableRotate) handleTouchStartRotate(); + } + + function handleTouchMoveRotate(event) { + if (pointers.length == 1) { + rotateEnd.set(event.pageX, event.pageY); + } else { + const position = getSecondPointerPosition(event); + + const x = 0.5 * (event.pageX + position.x); + const y = 0.5 * (event.pageY + position.y); + + rotateEnd.set(x, y); + } + + rotateDelta + .subVectors(rotateEnd, rotateStart) + .multiplyScalar(scope.rotateSpeed); + + const element = scope.domElement; + + rotateLeft((2 * Math.PI * rotateDelta.x) / element.clientHeight); // yes, height + + rotateUp((2 * Math.PI * rotateDelta.y) / element.clientHeight); + + rotateStart.copy(rotateEnd); + } + + function handleTouchMovePan(event) { + if (pointers.length === 1) { + panEnd.set(event.pageX, event.pageY); + } else { + const position = getSecondPointerPosition(event); + + const x = 0.5 * (event.pageX + position.x); + const y = 0.5 * (event.pageY + position.y); + + panEnd.set(x, y); + } + + panDelta + .subVectors(panEnd, panStart) + .multiplyScalar(scope.panSpeed); + + pan(panDelta.x, panDelta.y); + + panStart.copy(panEnd); + } + + function handleTouchMoveDolly(event) { + const position = getSecondPointerPosition(event); + + const dx = event.pageX - position.x; + const dy = event.pageY - position.y; + + const distance = Math.sqrt(dx * dx + dy * dy); + + dollyEnd.set(0, distance); + + dollyDelta.set( + 0, + Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed) + ); + + dollyOut(dollyDelta.y); + + dollyStart.copy(dollyEnd); + } + + function handleTouchMoveDollyPan(event) { + if (scope.enableZoom) handleTouchMoveDolly(event); + + if (scope.enablePan) handleTouchMovePan(event); + } + + function handleTouchMoveDollyRotate(event) { + if (scope.enableZoom) handleTouchMoveDolly(event); + + if (scope.enableRotate) handleTouchMoveRotate(event); + } + + // + // event handlers - FSM: listen for events and reset state + // + + function onPointerDown(event) { + if (scope.enabled === false) return; + + if (pointers.length === 0) { + scope.domElement.setPointerCapture(event.pointerId); + + scope.domElement.addEventListener("pointermove", onPointerMove); + scope.domElement.addEventListener("pointerup", onPointerUp); + } + + // + + addPointer(event); + + if (event.pointerType === "touch") { + onTouchStart(event); + } else { + onMouseDown(event); + } + } + + function onPointerMove(event) { + if (scope.enabled === false) return; + if (!is_in_scene(event)) return; + if (event.pointerType === "touch") { + onTouchMove(event); + } else { + onMouseMove(event); + } + } + + function onPointerUp(event) { + removePointer(event); + + if (pointers.length === 0) { + scope.domElement.releasePointerCapture(event.pointerId); + + scope.domElement.removeEventListener( + "pointermove", + onPointerMove + ); + scope.domElement.removeEventListener("pointerup", onPointerUp); + } + + scope.dispatchEvent(_endEvent); + + state = STATE.NONE; + } + + function onMouseDown(event) { + let mouseAction; + + switch (event.button) { + case 0: + mouseAction = scope.mouseButtons.LEFT; + break; + + case 1: + mouseAction = scope.mouseButtons.MIDDLE; + break; + + case 2: + mouseAction = scope.mouseButtons.RIGHT; + break; + + default: + mouseAction = -1; + } + + switch (mouseAction) { + case MOUSE.DOLLY: + if (scope.enableZoom === false) return; + + handleMouseDownDolly(event); + + state = STATE.DOLLY; + + break; + + case MOUSE.ROTATE: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + if (scope.enablePan === false) return; + + handleMouseDownPan(event); + + state = STATE.PAN; + } else { + if (scope.enableRotate === false) return; + + handleMouseDownRotate(event); + + state = STATE.ROTATE; + } + + break; + + case MOUSE.PAN: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + if (scope.enableRotate === false) return; + + handleMouseDownRotate(event); + + state = STATE.ROTATE; + } else { + if (scope.enablePan === false) return; + + handleMouseDownPan(event); + + state = STATE.PAN; + } + + break; + + default: + state = STATE.NONE; + } + + if (state !== STATE.NONE) { + scope.dispatchEvent(_startEvent); + } + } + + function onMouseMove(event) { + switch (state) { + case STATE.ROTATE: + if (scope.enableRotate === false) return; + + handleMouseMoveRotate(event); + + break; + + case STATE.DOLLY: + if (scope.enableZoom === false) return; + + handleMouseMoveDolly(event); + + break; + + case STATE.PAN: + if (scope.enablePan === false) return; + + handleMouseMovePan(event); + + break; + } + } + + function onMouseWheel(event) { + if ( + scope.enabled === false || + scope.enableZoom === false || + state !== STATE.NONE || + !is_in_scene(event) + ) + return; + + event.preventDefault(); + + scope.dispatchEvent(_startEvent); + + handleMouseWheel(event); + + scope.dispatchEvent(_endEvent); + } + + function onKeyDown(event) { + if (scope.enabled === false || scope.enablePan === false) return; + + handleKeyDown(event); + } + + function onTouchStart(event) { + trackPointer(event); + + switch (pointers.length) { + case 1: + switch (scope.touches.ONE) { + case TOUCH.ROTATE: + if (scope.enableRotate === false) return; + + handleTouchStartRotate(); + + state = STATE.TOUCH_ROTATE; + + break; + + case TOUCH.PAN: + if (scope.enablePan === false) return; + + handleTouchStartPan(); + + state = STATE.TOUCH_PAN; + + break; + + default: + state = STATE.NONE; + } + + break; + + case 2: + switch (scope.touches.TWO) { + case TOUCH.DOLLY_PAN: + if ( + scope.enableZoom === false && + scope.enablePan === false + ) + return; + + handleTouchStartDollyPan(); + + state = STATE.TOUCH_DOLLY_PAN; + + break; + + case TOUCH.DOLLY_ROTATE: + if ( + scope.enableZoom === false && + scope.enableRotate === false + ) + return; + + handleTouchStartDollyRotate(); + + state = STATE.TOUCH_DOLLY_ROTATE; + + break; + + default: + state = STATE.NONE; + } + + break; + + default: + state = STATE.NONE; + } + + if (state !== STATE.NONE) { + scope.dispatchEvent(_startEvent); + } + } + + function onTouchMove(event) { + trackPointer(event); + + switch (state) { + case STATE.TOUCH_ROTATE: + if (scope.enableRotate === false) return; + + handleTouchMoveRotate(event); + + scope.update(); + + break; + + case STATE.TOUCH_PAN: + if (scope.enablePan === false) return; + + handleTouchMovePan(event); + + scope.update(); + + break; + + case STATE.TOUCH_DOLLY_PAN: + if (scope.enableZoom === false && scope.enablePan === false) + return; + + handleTouchMoveDollyPan(event); + + scope.update(); + + break; + + case STATE.TOUCH_DOLLY_ROTATE: + if ( + scope.enableZoom === false && + scope.enableRotate === false + ) + return; + + handleTouchMoveDollyRotate(event); + + scope.update(); + + break; + + default: + state = STATE.NONE; + } + } + + function onContextMenu(event) { + if (scope.enabled === false) return; + + event.preventDefault(); + } + + function addPointer(event) { + pointers.push(event); + } + + function removePointer(event) { + delete pointerPositions[event.pointerId]; + + for (let i = 0; i < pointers.length; i++) { + if (pointers[i].pointerId == event.pointerId) { + pointers.splice(i, 1); + return; + } + } + } + + function trackPointer(event) { + let position = pointerPositions[event.pointerId]; + + if (position === undefined) { + position = new Vector2(); + pointerPositions[event.pointerId] = position; + } + + position.set(event.pageX, event.pageY); + } + + function getSecondPointerPosition(event) { + const pointer = + event.pointerId === pointers[0].pointerId + ? pointers[1] + : pointers[0]; + + return pointerPositions[pointer.pointerId]; + } + + // + + scope.domElement.addEventListener("contextmenu", onContextMenu); + + scope.domElement.addEventListener("pointerdown", onPointerDown); + scope.domElement.addEventListener("pointercancel", onPointerUp); + scope.domElement.addEventListener("wheel", onMouseWheel, { + passive: false, + }); + + // force an update at start + + this.update(); + } +} + +export { OrbitControls }; diff --git a/WGLMakie/src/Serialization.js b/WGLMakie/src/Serialization.js index a9c7f4b995b..3fc7c66c5a3 100644 --- a/WGLMakie/src/Serialization.js +++ b/WGLMakie/src/Serialization.js @@ -1,5 +1,6 @@ +import * as THREE from "./THREE.js"; import * as Camera from "./Camera.js"; -import * as THREE from "https://cdn.esm.sh/v66/three@0.136/es2021/three.js"; +import { create_line, create_linesegments } from "./Lines.js"; // global scene cache to look them up for dynamic operations in Makie // e.g. insert!(scene, plot) / delete!(scene, plot) @@ -20,6 +21,7 @@ export function delete_scene(scene_id) { if (!scene) { return; } + delete_three_scene(scene); while (scene.children.length > 0) { scene.remove(scene.children[0]); } @@ -39,7 +41,10 @@ export function find_plots(plot_uuids) { export function delete_scenes(scene_uuids, plot_uuids) { plot_uuids.forEach((plot_id) => { - delete plot_cache[plot_id]; + const plot = plot_cache[plot_id]; + if (plot) { + delete_plot(plot); + } }); scene_uuids.forEach((scene_id) => { delete_scene(scene_id); @@ -53,14 +58,9 @@ export function insert_plot(scene_id, plot_data) { }); } -export function delete_plots(scene_id, plot_uuids) { - console.log(`deleting plots!: ${plot_uuids}`) - const scene = find_scene(scene_id); +export function delete_plots(plot_uuids) { const plots = find_plots(plot_uuids); - plots.forEach((p) => { - scene.remove(p); - delete plot_cache[p]; - }); + plots.forEach(delete_plot); } function convert_texture(data) { @@ -120,7 +120,7 @@ function to_uniform(data) { return data; } -function deserialize_uniforms(data) { +export function deserialize_uniforms(data) { const result = {}; // Deno may change constructor names..so... @@ -141,7 +141,16 @@ function deserialize_uniforms(data) { export function deserialize_plot(data) { let mesh; - if ("instance_attributes" in data) { + const update_visible = (v) => { + mesh.visible = v; + // don't return anything, since that will disable on_update callback + return; + }; + if (data.plot_type === "lines") { + mesh = create_line(data); + } else if (data.plot_type === "linesegments") { + mesh = create_linesegments(data); + } else if ("instance_attributes" in data) { mesh = create_instanced_mesh(data); } else { mesh = create_mesh(data); @@ -150,15 +159,12 @@ export function deserialize_plot(data) { mesh.frustumCulled = false; mesh.matrixAutoUpdate = false; mesh.plot_uuid = data.uuid; - const update_visible = (v) => { - mesh.visible = v; - // don't return anything, since that will disable on_update callback - return; - }; update_visible(data.visible.value); data.visible.on(update_visible); connect_uniforms(mesh, data.uniform_updater); - connect_attributes(mesh, data.attribute_updater); + if (!(data.plot_type === "lines" || data.plot_type === "linesegments")) { + connect_attributes(mesh, data.attribute_updater); + } return mesh; } @@ -172,7 +178,6 @@ export function add_plot(scene, plot_data) { // fill in the camera uniforms, that we don't sent in serialization per plot const cam = scene.wgl_camera; const identity = new THREE.Uniform(new THREE.Matrix4()); - if (plot_data.cam_space == "data") { plot_data.uniforms.view = cam.view; plot_data.uniforms.projection = cam.projection; @@ -192,8 +197,9 @@ export function add_plot(scene, plot_data) { plot_data.uniforms.projection = identity; plot_data.uniforms.projectionview = identity; } - + const { px_per_unit } = scene.screen; plot_data.uniforms.resolution = cam.resolution; + plot_data.uniforms.px_per_unit = new THREE.Uniform(px_per_unit); if (plot_data.uniforms.preprojection) { const { space, markerspace } = plot_data; @@ -202,8 +208,25 @@ export function add_plot(scene, plot_data) { markerspace.value ); } + + if (scene.camera_relative_light) { + plot_data.uniforms.light_direction = cam.light_direction; + scene.light_direction.on((value) => { + cam.update_light_dir(value); + }); + } else { + // TODO how update? + const light_dir = new THREE.Vector3().fromArray( + scene.light_direction.value + ); + plot_data.uniforms.light_direction = new THREE.Uniform(light_dir); + scene.light_direction.on((value) => { + plot_data.uniforms.light_direction.value.fromArray(value); + }); + } + const p = deserialize_plot(plot_data); - plot_cache[plot_data.uuid] = p; + plot_cache[p.plot_uuid] = p; scene.add(p); // execute all next insert callbacks const next_insert = new Set(ON_NEXT_INSERT); // copy @@ -239,10 +262,24 @@ function connect_uniforms(mesh, updater) { }); } +function convert_RGB_to_RGBA(rgbArray) { + const length = rgbArray.length; + const rgbaArray = new Float32Array((length / 3) * 4); + + 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 + } + + return rgbaArray; +} + function create_texture(data) { const buffer = data.data; if (data.size.length == 3) { - const tex = new THREE.DataTexture3D( + const tex = new THREE.Data3DTexture( buffer, data.size[0], data.size[1], @@ -253,13 +290,22 @@ function create_texture(data) { return tex; } else { // a little optimization to not send the texture atlas over & over again - const tex_data = - buffer == "texture_atlas" ? TEXTURE_ATLAS[0].value : buffer; + let tex_data; + if (buffer == "texture_atlas") { + tex_data = TEXTURE_ATLAS[0].value; + } else { + tex_data = buffer; + } + let format = THREE[data.three_format]; + if (data.three_format == "RGBFormat") { + tex_data = convert_RGB_to_RGBA(tex_data); + format = THREE.RGBAFormat; + } return new THREE.DataTexture( tex_data, data.size[0], data.size[1], - THREE[data.three_format], + format, THREE[data.three_type] ); } @@ -268,7 +314,7 @@ function create_texture(data) { function re_create_texture(old_texture, buffer, size) { let tex; if (size.length == 3) { - tex = new THREE.DataTexture3D(buffer, size[0], size[1], size[2]); + tex = new THREE.Data3DTexture(buffer, size[0], size[1], size[2]); tex.format = old_texture.format; tex.type = old_texture.type; } else { @@ -280,17 +326,17 @@ function re_create_texture(old_texture, buffer, size) { old_texture.type ); } - tex.minFilter = old_texture.minFilter - tex.magFilter = old_texture.magFilter - tex.anisotropy = old_texture.anisotropy - tex.wrapS = old_texture.wrapS + tex.minFilter = old_texture.minFilter; + tex.magFilter = old_texture.magFilter; + tex.anisotropy = old_texture.anisotropy; + tex.wrapS = old_texture.wrapS; if (size.length > 1) { - tex.wrapT = old_texture.wrapT + tex.wrapT = old_texture.wrapT; } if (size.length > 2) { - tex.wrapR = old_texture.wrapR + tex.wrapR = old_texture.wrapR; } - return tex + return tex; } function BufferAttribute(buffer) { const jsbuff = new THREE.BufferAttribute(buffer.flat, buffer.type_length); @@ -379,6 +425,7 @@ function create_material(program) { fragmentShader: program.fragment_source, side: is_volume ? THREE.BackSide : THREE.DoubleSide, transparent: true, + glslVersion: THREE.GLSL3, depthTest: !program.overdraw.value, depthWrite: !program.transparency.value, }); @@ -498,41 +545,59 @@ export function deserialize_scene(data, screen) { add_scene(data.uuid, scene); scene.scene_uuid = data.uuid; scene.frustumCulled = false; - scene.pixelarea = data.pixelarea; + scene.viewport = data.viewport; scene.backgroundcolor = data.backgroundcolor; + scene.backgroundcolor_alpha = data.backgroundcolor_alpha; scene.clearscene = data.clearscene; scene.visible = data.visible; + scene.camera_relative_light = data.camera_relative_light; + scene.light_direction = data.light_direction; const camera = new Camera.MakieCamera(); scene.wgl_camera = camera; - function update_cam(camera_matrices) { + function update_cam(camera_matrices, force) { + if (!force) { + // we use the threejs orbit controls, if the julia connection is gone + // at least for 3d ... 2d is still a todo, and will stay static right now + if (!(JSServe.can_send_to_julia && JSServe.can_send_to_julia())) { + return; + } + } const [view, projection, resolution, eyepos] = camera_matrices; camera.update_matrices(view, projection, resolution, eyepos); } - update_cam(data.camera.value); - if (data.cam3d_state) { - Camera.attach_3d_camera(canvas, camera, data.cam3d_state, scene); - } else { - data.camera.on(update_cam); + Camera.attach_3d_camera( + canvas, + camera, + data.cam3d_state, + data.light_direction, + scene + ); } + + update_cam(data.camera.value, true); // force update on first call + camera.update_light_dir(data.light_direction.value); + data.camera.on(update_cam); + data.plots.forEach((plot_data) => { add_plot(scene, plot_data); }); - scene.scene_children = data.children.map((child) => - deserialize_scene(child, screen) - ); + scene.scene_children = data.children.map((child) => { + const childscene = deserialize_scene(child, screen); + return childscene; + }); return scene; } export function delete_plot(plot) { delete plot_cache[plot.plot_uuid]; - const {parent} = plot + const { parent } = plot; if (parent) { - parent.remove(plot) + parent.remove(plot); } plot.geometry.dispose(); plot.material.dispose(); @@ -541,8 +606,8 @@ export function delete_plot(plot) { export function delete_three_scene(scene) { delete scene_cache[scene.scene_uuid]; scene.scene_children.forEach(delete_three_scene); - while(scene.children.length > 0) { - delete_plot(scene.children[0]) + while (scene.children.length > 0) { + delete_plot(scene.children[0]); } } diff --git a/WGLMakie/src/Shaders.js b/WGLMakie/src/Shaders.js new file mode 100644 index 00000000000..4d6959673e9 --- /dev/null +++ b/WGLMakie/src/Shaders.js @@ -0,0 +1,67 @@ +function typedarray_to_vectype(typedArray, ndim) { + if (ndim === 1) { + return "float"; + } else if (typedArray instanceof Float32Array) { + return "vec" + ndim; + } else if (typedArray instanceof Int32Array) { + return "ivec" + ndim; + } else if (typedArray instanceof Uint32Array) { + return "uvec" + ndim; + } else { + return; + } +} + +export function attribute_type(attribute) { + if (attribute) { + return typedarray_to_vectype(attribute.array, attribute.itemSize); + } else { + return; + } +} + +export function uniform_type(obj) { + if (obj instanceof THREE.Uniform) { + return uniform_type(obj.value); + } else if (typeof obj === "number") { + return "float"; + } else if (typeof obj === "boolean") { + return "bool"; + } else if (obj instanceof THREE.Vector2) { + return "vec2"; + } else if (obj instanceof THREE.Vector3) { + return "vec3"; + } else if (obj instanceof THREE.Vector4) { + return "vec4"; + } else if (obj instanceof THREE.Color) { + return "vec4"; + } else if (obj instanceof THREE.Matrix3) { + return "mat3"; + } else if (obj instanceof THREE.Matrix4) { + return "mat4"; + } else if (obj instanceof THREE.Texture) { + return "sampler2D"; + } else { + return; + } +} + +export function uniforms_to_type_declaration(uniform_dict) { + let result = ""; + for (const name in uniform_dict) { + const uniform = uniform_dict[name]; + const type = uniform_type(uniform); + result += `uniform ${type} ${name};\n`; + } + return result; +} + +export function attributes_to_type_declaration(attributes_dict) { + let result = ""; + for (const name in attributes_dict) { + const attribute = attributes_dict[name]; + const type = attribute_type(attribute); + result += `in ${type} ${name};\n`; + } + return result; +} diff --git a/WGLMakie/src/THREE.js b/WGLMakie/src/THREE.js new file mode 100644 index 00000000000..35d525a5b91 --- /dev/null +++ b/WGLMakie/src/THREE.js @@ -0,0 +1,3588 @@ +/* esm.sh - esbuild bundle(three@0.157.0) es2021 production */ +var Hc="157",zx={LEFT:0,MIDDLE:1,RIGHT:2,ROTATE:0,DOLLY:1,PAN:2},Vx={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},kd=0,rl=1,Hd=2,kx=3,Hx=0,cd=1,Gd=2,pn=3,Bn=0,Ft=1,gn=2,Gx=2,Dn=0,Wi=1,al=2,ol=3,cl=4,Wd=5,Bi=100,Xd=101,qd=102,ll=103,hl=104,Yd=200,Zd=201,Jd=202,$d=203,ld=204,hd=205,Kd=206,Qd=207,jd=208,ef=209,tf=210,nf=0,sf=1,rf=2,uo=3,af=4,of=5,cf=6,lf=7,xa=0,hf=1,uf=2,Nn=0,df=1,ff=2,pf=3,mf=4,gf=5,Gc=300,zn=301,ci=302,Ir=303,Ur=304,Vs=306,Dr=1e3,It=1001,Nr=1002,pt=1003,fo=1004,Wx=1004,Lr=1005,Xx=1005,mt=1006,ud=1007,qx=1007,li=1008,Yx=1008,On=1009,_f=1010,xf=1011,Wc=1012,dd=1013,Ln=1014,xn=1015,Ts=1016,fd=1017,pd=1018,ii=1020,vf=1021,Wt=1023,yf=1024,Mf=1025,si=1026,Yi=1027,Sf=1028,md=1029,bf=1030,gd=1031,_d=1033,wa=33776,Aa=33777,Ra=33778,Ca=33779,ul=35840,dl=35841,fl=35842,pl=35843,Ef=36196,ml=37492,gl=37496,_l=37808,xl=37809,vl=37810,yl=37811,Ml=37812,Sl=37813,bl=37814,El=37815,Tl=37816,wl=37817,Al=37818,Rl=37819,Cl=37820,Pl=37821,Pa=36492,Ll=36494,Il=36495,Tf=36283,Ul=36284,Dl=36285,Nl=36286,wf=2200,Af=2201,Rf=2202,Or=2300,Fr=2301,La=2302,zi=2400,Vi=2401,Br=2402,Xc=2500,xd=2501,Zx=0,Jx=1,$x=2,vd=3e3,ri=3001,Cf=3200,Pf=3201,mi=0,Lf=1,Xt="",vt="srgb",Mn="srgb-linear",qc="display-p3",va="display-p3-linear",zr="linear",nt="srgb",Vr="rec709",kr="p3",Kx=0,Ia=7680,Qx=7681,jx=7682,ev=7683,tv=34055,nv=34056,iv=5386,sv=512,rv=513,av=514,ov=515,cv=516,lv=517,hv=518,If=519,Uf=512,Df=513,Nf=514,Of=515,Ff=516,Bf=517,zf=518,Vf=519,Hr=35044,uv=35048,dv=35040,fv=35045,pv=35049,mv=35041,gv=35046,_v=35050,xv=35042,vv="100",Ol="300 es",po=1035,vn=2e3,Gr=2001,sn=class{addEventListener(e,t){this._listeners===void 0&&(this._listeners={});let n=this._listeners;n[e]===void 0&&(n[e]=[]),n[e].indexOf(t)===-1&&n[e].push(t)}hasEventListener(e,t){if(this._listeners===void 0)return!1;let n=this._listeners;return n[e]!==void 0&&n[e].indexOf(t)!==-1}removeEventListener(e,t){if(this._listeners===void 0)return;let i=this._listeners[e];if(i!==void 0){let r=i.indexOf(t);r!==-1&&i.splice(r,1)}}dispatchEvent(e){if(this._listeners===void 0)return;let n=this._listeners[e.type];if(n!==void 0){e.target=this;let i=n.slice(0);for(let r=0,a=i.length;r>8&255]+Et[s>>16&255]+Et[s>>24&255]+"-"+Et[e&255]+Et[e>>8&255]+"-"+Et[e>>16&15|64]+Et[e>>24&255]+"-"+Et[t&63|128]+Et[t>>8&255]+"-"+Et[t>>16&255]+Et[t>>24&255]+Et[n&255]+Et[n>>8&255]+Et[n>>16&255]+Et[n>>24&255]).toLowerCase()}function ct(s,e,t){return Math.max(e,Math.min(t,s))}function Yc(s,e){return(s%e+e)%e}function kf(s,e,t,n,i){return n+(s-e)*(i-n)/(t-e)}function Hf(s,e,t){return s!==e?(t-s)/(e-s):0}function ys(s,e,t){return(1-t)*s+t*e}function Gf(s,e,t,n){return ys(s,e,1-Math.exp(-t*n))}function Wf(s,e=1){return e-Math.abs(Yc(s,e*2)-e)}function Xf(s,e,t){return s<=e?0:s>=t?1:(s=(s-e)/(t-e),s*s*(3-2*s))}function qf(s,e,t){return s<=e?0:s>=t?1:(s=(s-e)/(t-e),s*s*s*(s*(s*6-15)+10))}function Yf(s,e){return s+Math.floor(Math.random()*(e-s+1))}function Zf(s,e){return s+Math.random()*(e-s)}function Jf(s){return s*(.5-Math.random())}function $f(s){s!==void 0&&(Fl=s);let e=Fl+=1831565813;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}function Kf(s){return s*ai}function Qf(s){return s*Zi}function mo(s){return(s&s-1)===0&&s!==0}function yd(s){return Math.pow(2,Math.ceil(Math.log(s)/Math.LN2))}function Wr(s){return Math.pow(2,Math.floor(Math.log(s)/Math.LN2))}function jf(s,e,t,n,i){let r=Math.cos,a=Math.sin,o=r(t/2),c=a(t/2),l=r((e+n)/2),h=a((e+n)/2),u=r((e-n)/2),d=a((e-n)/2),f=r((n-e)/2),m=a((n-e)/2);switch(i){case"XYX":s.set(o*h,c*u,c*d,o*l);break;case"YZY":s.set(c*d,o*h,c*u,o*l);break;case"ZXZ":s.set(c*u,c*d,o*h,o*l);break;case"XZX":s.set(o*h,c*m,c*f,o*l);break;case"YXY":s.set(c*f,o*h,c*m,o*l);break;case"ZYZ":s.set(c*m,c*f,o*h,o*l);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+i)}}function Ot(s,e){switch(e.constructor){case Float32Array:return s;case Uint32Array:return s/4294967295;case Uint16Array:return s/65535;case Uint8Array:return s/255;case Int32Array:return Math.max(s/2147483647,-1);case Int16Array:return Math.max(s/32767,-1);case Int8Array:return Math.max(s/127,-1);default:throw new Error("Invalid component type.")}}function Be(s,e){switch(e.constructor){case Float32Array:return s;case Uint32Array:return Math.round(s*4294967295);case Uint16Array:return Math.round(s*65535);case Uint8Array:return Math.round(s*255);case Int32Array:return Math.round(s*2147483647);case Int16Array:return Math.round(s*32767);case Int8Array:return Math.round(s*127);default:throw new Error("Invalid component type.")}}var yv={DEG2RAD:ai,RAD2DEG:Zi,generateUUID:kt,clamp:ct,euclideanModulo:Yc,mapLinear:kf,inverseLerp:Hf,lerp:ys,damp:Gf,pingpong:Wf,smoothstep:Xf,smootherstep:qf,randInt:Yf,randFloat:Zf,randFloatSpread:Jf,seededRandom:$f,degToRad:Kf,radToDeg:Qf,isPowerOfTwo:mo,ceilPowerOfTwo:yd,floorPowerOfTwo:Wr,setQuaternionFromProperEuler:jf,normalize:Be,denormalize:Ot},Z=class s{constructor(e=0,t=0){s.prototype.isVector2=!0,this.x=e,this.y=t}get width(){return this.x}set width(e){this.x=e}get height(){return this.y}set height(e){this.y=e}set(e,t){return this.x=e,this.y=t,this}setScalar(e){return this.x=e,this.y=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}addScalar(e){return this.x+=e,this.y+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this}subScalar(e){return this.x-=e,this.y-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this}multiply(e){return this.x*=e.x,this.y*=e.y,this}multiplyScalar(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e.x,this.y/=e.y,this}divideScalar(e){return this.multiplyScalar(1/e)}applyMatrix3(e){let t=this.x,n=this.y,i=e.elements;return this.x=i[0]*t+i[3]*n+i[6],this.y=i[1]*t+i[4]*n+i[7],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this}clampLength(e,t){let n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(e){let t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;let n=this.dot(e)/t;return Math.acos(ct(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){let t=this.x-e.x,n=this.y-e.y;return t*t+n*n}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this}equals(e){return e.x===this.x&&e.y===this.y}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this}rotateAround(e,t){let n=Math.cos(t),i=Math.sin(t),r=this.x-e.x,a=this.y-e.y;return this.x=r*n-a*i+e.x,this.y=r*i+a*n+e.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}},He=class s{constructor(e,t,n,i,r,a,o,c,l){s.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],e!==void 0&&this.set(e,t,n,i,r,a,o,c,l)}set(e,t,n,i,r,a,o,c,l){let h=this.elements;return h[0]=e,h[1]=i,h[2]=o,h[3]=t,h[4]=r,h[5]=c,h[6]=n,h[7]=a,h[8]=l,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(e){let t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],this}extractBasis(e,t,n){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(e){let t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){let n=e.elements,i=t.elements,r=this.elements,a=n[0],o=n[3],c=n[6],l=n[1],h=n[4],u=n[7],d=n[2],f=n[5],m=n[8],_=i[0],g=i[3],p=i[6],v=i[1],x=i[4],y=i[7],b=i[2],w=i[5],R=i[8];return r[0]=a*_+o*v+c*b,r[3]=a*g+o*x+c*w,r[6]=a*p+o*y+c*R,r[1]=l*_+h*v+u*b,r[4]=l*g+h*x+u*w,r[7]=l*p+h*y+u*R,r[2]=d*_+f*v+m*b,r[5]=d*g+f*x+m*w,r[8]=d*p+f*y+m*R,this}multiplyScalar(e){let t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this}determinant(){let e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],a=e[4],o=e[5],c=e[6],l=e[7],h=e[8];return t*a*h-t*o*l-n*r*h+n*o*c+i*r*l-i*a*c}invert(){let e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],a=e[4],o=e[5],c=e[6],l=e[7],h=e[8],u=h*a-o*l,d=o*c-h*r,f=l*r-a*c,m=t*u+n*d+i*f;if(m===0)return this.set(0,0,0,0,0,0,0,0,0);let _=1/m;return e[0]=u*_,e[1]=(i*l-h*n)*_,e[2]=(o*n-i*a)*_,e[3]=d*_,e[4]=(h*t-i*c)*_,e[5]=(i*r-o*t)*_,e[6]=f*_,e[7]=(n*c-l*t)*_,e[8]=(a*t-n*r)*_,this}transpose(){let e,t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this}getNormalMatrix(e){return this.setFromMatrix4(e).invert().transpose()}transposeIntoArray(e){let t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this}setUvTransform(e,t,n,i,r,a,o){let c=Math.cos(r),l=Math.sin(r);return this.set(n*c,n*l,-n*(c*a+l*o)+a+e,-i*l,i*c,-i*(-l*a+c*o)+o+t,0,0,1),this}scale(e,t){return this.premultiply(Ua.makeScale(e,t)),this}rotate(e){return this.premultiply(Ua.makeRotation(-e)),this}translate(e,t){return this.premultiply(Ua.makeTranslation(e,t)),this}makeTranslation(e,t){return e.isVector2?this.set(1,0,e.x,0,1,e.y,0,0,1):this.set(1,0,e,0,1,t,0,0,1),this}makeRotation(e){let t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,n,t,0,0,0,1),this}makeScale(e,t){return this.set(e,0,0,0,t,0,0,0,1),this}equals(e){let t=this.elements,n=e.elements;for(let i=0;i<9;i++)if(t[i]!==n[i])return!1;return!0}fromArray(e,t=0){for(let n=0;n<9;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){let n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e}clone(){return new this.constructor().fromArray(this.elements)}},Ua=new He;function Md(s){for(let e=s.length-1;e>=0;--e)if(s[e]>=65535)return!0;return!1}var ep={Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array};function ki(s,e){return new ep[s](e)}function ws(s){return document.createElementNS("http://www.w3.org/1999/xhtml",s)}function tp(){let s=ws("canvas");return s.style.display="block",s}var Bl={};function Ms(s){s in Bl||(Bl[s]=!0,console.warn(s))}var zl=new He().set(.8224621,.177538,0,.0331941,.9668058,0,.0170827,.0723974,.9105199),Vl=new He().set(1.2249401,-.2249404,0,-.0420569,1.0420571,0,-.0196376,-.0786361,1.0982735),Gs={[Mn]:{transfer:zr,primaries:Vr,toReference:s=>s,fromReference:s=>s},[vt]:{transfer:nt,primaries:Vr,toReference:s=>s.convertSRGBToLinear(),fromReference:s=>s.convertLinearToSRGB()},[va]:{transfer:zr,primaries:kr,toReference:s=>s.applyMatrix3(Vl),fromReference:s=>s.applyMatrix3(zl)},[qc]:{transfer:nt,primaries:kr,toReference:s=>s.convertSRGBToLinear().applyMatrix3(Vl),fromReference:s=>s.applyMatrix3(zl).convertLinearToSRGB()}},np=new Set([Mn,va]),Qe={enabled:!0,_workingColorSpace:Mn,get legacyMode(){return console.warn("THREE.ColorManagement: .legacyMode=false renamed to .enabled=true in r150."),!this.enabled},set legacyMode(s){console.warn("THREE.ColorManagement: .legacyMode=false renamed to .enabled=true in r150."),this.enabled=!s},get workingColorSpace(){return this._workingColorSpace},set workingColorSpace(s){if(!np.has(s))throw new Error(`Unsupported working color space, "${s}".`);this._workingColorSpace=s},convert:function(s,e,t){if(this.enabled===!1||e===t||!e||!t)return s;let n=Gs[e].toReference,i=Gs[t].fromReference;return i(n(s))},fromWorkingColorSpace:function(s,e){return this.convert(s,this._workingColorSpace,e)},toWorkingColorSpace:function(s,e){return this.convert(s,e,this._workingColorSpace)},getPrimaries:function(s){return Gs[s].primaries},getTransfer:function(s){return s===Xt?zr:Gs[s].transfer}};function Xi(s){return s<.04045?s*.0773993808:Math.pow(s*.9478672986+.0521327014,2.4)}function Da(s){return s<.0031308?s*12.92:1.055*Math.pow(s,.41666)-.055}var gi,Xr=class{static getDataURL(e){if(/^data:/i.test(e.src)||typeof HTMLCanvasElement>"u")return e.src;let t;if(e instanceof HTMLCanvasElement)t=e;else{gi===void 0&&(gi=ws("canvas")),gi.width=e.width,gi.height=e.height;let n=gi.getContext("2d");e instanceof ImageData?n.putImageData(e,0,0):n.drawImage(e,0,0,e.width,e.height),t=gi}return t.width>2048||t.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",e),t.toDataURL("image/jpeg",.6)):t.toDataURL("image/png")}static sRGBToLinear(e){if(typeof HTMLImageElement<"u"&&e instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&e instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&e instanceof ImageBitmap){let t=ws("canvas");t.width=e.width,t.height=e.height;let n=t.getContext("2d");n.drawImage(e,0,0,e.width,e.height);let i=n.getImageData(0,0,e.width,e.height),r=i.data;for(let a=0;a0&&(n.userData=this.userData),t||(e.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(e){if(this.mapping!==Gc)return e;if(e.applyMatrix3(this.matrix),e.x<0||e.x>1)switch(this.wrapS){case Dr:e.x=e.x-Math.floor(e.x);break;case It:e.x=e.x<0?0:1;break;case Nr:Math.abs(Math.floor(e.x)%2)===1?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x);break}if(e.y<0||e.y>1)switch(this.wrapT){case Dr:e.y=e.y-Math.floor(e.y);break;case It:e.y=e.y<0?0:1;break;case Nr:Math.abs(Math.floor(e.y)%2)===1?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y);break}return this.flipY&&(e.y=1-e.y),e}set needsUpdate(e){e===!0&&(this.version++,this.source.needsUpdate=!0)}get encoding(){return Ms("THREE.Texture: Property .encoding has been replaced by .colorSpace."),this.colorSpace===vt?ri:vd}set encoding(e){Ms("THREE.Texture: Property .encoding has been replaced by .colorSpace."),this.colorSpace=e===ri?vt:Xt}};St.DEFAULT_IMAGE=null;St.DEFAULT_MAPPING=Gc;St.DEFAULT_ANISOTROPY=1;var je=class s{constructor(e=0,t=0,n=0,i=1){s.prototype.isVector4=!0,this.x=e,this.y=t,this.z=n,this.w=i}get width(){return this.z}set width(e){this.z=e}get height(){return this.w}set height(e){this.w=e}set(e,t,n,i){return this.x=e,this.y=t,this.z=n,this.w=i,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this.w=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setW(e){return this.w=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=e.w!==void 0?e.w:1,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this.w*=e.w,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this}applyMatrix4(e){let t=this.x,n=this.y,i=this.z,r=this.w,a=e.elements;return this.x=a[0]*t+a[4]*n+a[8]*i+a[12]*r,this.y=a[1]*t+a[5]*n+a[9]*i+a[13]*r,this.z=a[2]*t+a[6]*n+a[10]*i+a[14]*r,this.w=a[3]*t+a[7]*n+a[11]*i+a[15]*r,this}divideScalar(e){return this.multiplyScalar(1/e)}setAxisAngleFromQuaternion(e){this.w=2*Math.acos(e.w);let t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this}setAxisAngleFromRotationMatrix(e){let t,n,i,r,c=e.elements,l=c[0],h=c[4],u=c[8],d=c[1],f=c[5],m=c[9],_=c[2],g=c[6],p=c[10];if(Math.abs(h-d)<.01&&Math.abs(u-_)<.01&&Math.abs(m-g)<.01){if(Math.abs(h+d)<.1&&Math.abs(u+_)<.1&&Math.abs(m+g)<.1&&Math.abs(l+f+p-3)<.1)return this.set(1,0,0,0),this;t=Math.PI;let x=(l+1)/2,y=(f+1)/2,b=(p+1)/2,w=(h+d)/4,R=(u+_)/4,I=(m+g)/4;return x>y&&x>b?x<.01?(n=0,i=.707106781,r=.707106781):(n=Math.sqrt(x),i=w/n,r=R/n):y>b?y<.01?(n=.707106781,i=0,r=.707106781):(i=Math.sqrt(y),n=w/i,r=I/i):b<.01?(n=.707106781,i=.707106781,r=0):(r=Math.sqrt(b),n=R/r,i=I/r),this.set(n,i,r,t),this}let v=Math.sqrt((g-m)*(g-m)+(u-_)*(u-_)+(d-h)*(d-h));return Math.abs(v)<.001&&(v=1),this.x=(g-m)/v,this.y=(u-_)/v,this.z=(d-h)/v,this.w=Math.acos((l+f+p-1)/2),this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this.w=Math.min(this.w,e.w),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this.w=Math.max(this.w,e.w),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this.w=Math.max(e.w,Math.min(t.w,this.w)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this.w=Math.max(e,Math.min(t,this.w)),this}clampLength(e,t){let n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this.w=Math.trunc(this.w),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z+this.w*e.w}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this.w+=(e.w-this.w)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this.w=e.w+(t.w-e.w)*n,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z&&e.w===this.w}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this.w=e[t+3],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e[t+3]=this.w,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this.w=e.getW(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this.w=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z,yield this.w}},go=class extends sn{constructor(e=1,t=1,n={}){super(),this.isRenderTarget=!0,this.width=e,this.height=t,this.depth=1,this.scissor=new je(0,0,e,t),this.scissorTest=!1,this.viewport=new je(0,0,e,t);let i={width:e,height:t,depth:1};n.encoding!==void 0&&(Ms("THREE.WebGLRenderTarget: option.encoding has been replaced by option.colorSpace."),n.colorSpace=n.encoding===ri?vt:Xt),n=Object.assign({generateMipmaps:!1,internalFormat:null,minFilter:mt,depthBuffer:!0,stencilBuffer:!1,depthTexture:null,samples:0},n),this.texture=new St(i,n.mapping,n.wrapS,n.wrapT,n.magFilter,n.minFilter,n.format,n.type,n.anisotropy,n.colorSpace),this.texture.isRenderTargetTexture=!0,this.texture.flipY=!1,this.texture.generateMipmaps=n.generateMipmaps,this.texture.internalFormat=n.internalFormat,this.depthBuffer=n.depthBuffer,this.stencilBuffer=n.stencilBuffer,this.depthTexture=n.depthTexture,this.samples=n.samples}setSize(e,t,n=1){(this.width!==e||this.height!==t||this.depth!==n)&&(this.width=e,this.height=t,this.depth=n,this.texture.image.width=e,this.texture.image.height=t,this.texture.image.depth=n,this.dispose()),this.viewport.set(0,0,e,t),this.scissor.set(0,0,e,t)}clone(){return new this.constructor().copy(this)}copy(e){this.width=e.width,this.height=e.height,this.depth=e.depth,this.scissor.copy(e.scissor),this.scissorTest=e.scissorTest,this.viewport.copy(e.viewport),this.texture=e.texture.clone(),this.texture.isRenderTargetTexture=!0;let t=Object.assign({},e.texture.image);return this.texture.source=new In(t),this.depthBuffer=e.depthBuffer,this.stencilBuffer=e.stencilBuffer,e.depthTexture!==null&&(this.depthTexture=e.depthTexture.clone()),this.samples=e.samples,this}dispose(){this.dispatchEvent({type:"dispose"})}},qt=class extends go{constructor(e=1,t=1,n={}){super(e,t,n),this.isWebGLRenderTarget=!0}},As=class extends St{constructor(e=null,t=1,n=1,i=1){super(null),this.isDataArrayTexture=!0,this.image={data:e,width:t,height:n,depth:i},this.magFilter=pt,this.minFilter=pt,this.wrapR=It,this.generateMipmaps=!1,this.flipY=!1,this.unpackAlignment=1}},kl=class extends qt{constructor(e=1,t=1,n=1){super(e,t),this.isWebGLArrayRenderTarget=!0,this.depth=n,this.texture=new As(null,e,t,n),this.texture.isRenderTargetTexture=!0}},qr=class extends St{constructor(e=null,t=1,n=1,i=1){super(null),this.isData3DTexture=!0,this.image={data:e,width:t,height:n,depth:i},this.magFilter=pt,this.minFilter=pt,this.wrapR=It,this.generateMipmaps=!1,this.flipY=!1,this.unpackAlignment=1}},Hl=class extends qt{constructor(e=1,t=1,n=1){super(e,t),this.isWebGL3DRenderTarget=!0,this.depth=n,this.texture=new qr(null,e,t,n),this.texture.isRenderTargetTexture=!0}},Gl=class extends qt{constructor(e=1,t=1,n=1,i={}){super(e,t,i),this.isWebGLMultipleRenderTargets=!0;let r=this.texture;this.texture=[];for(let a=0;a=0?1:-1,x=1-p*p;if(x>Number.EPSILON){let b=Math.sqrt(x),w=Math.atan2(b,p*v);g=Math.sin(g*w)/b,o=Math.sin(o*w)/b}let y=o*v;if(c=c*g+d*y,l=l*g+f*y,h=h*g+m*y,u=u*g+_*y,g===1-o){let b=1/Math.sqrt(c*c+l*l+h*h+u*u);c*=b,l*=b,h*=b,u*=b}}e[t]=c,e[t+1]=l,e[t+2]=h,e[t+3]=u}static multiplyQuaternionsFlat(e,t,n,i,r,a){let o=n[i],c=n[i+1],l=n[i+2],h=n[i+3],u=r[a],d=r[a+1],f=r[a+2],m=r[a+3];return e[t]=o*m+h*u+c*f-l*d,e[t+1]=c*m+h*d+l*u-o*f,e[t+2]=l*m+h*f+o*d-c*u,e[t+3]=h*m-o*u-c*d-l*f,e}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get w(){return this._w}set w(e){this._w=e,this._onChangeCallback()}set(e,t,n,i){return this._x=e,this._y=t,this._z=n,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this}setFromEuler(e,t){let n=e._x,i=e._y,r=e._z,a=e._order,o=Math.cos,c=Math.sin,l=o(n/2),h=o(i/2),u=o(r/2),d=c(n/2),f=c(i/2),m=c(r/2);switch(a){case"XYZ":this._x=d*h*u+l*f*m,this._y=l*f*u-d*h*m,this._z=l*h*m+d*f*u,this._w=l*h*u-d*f*m;break;case"YXZ":this._x=d*h*u+l*f*m,this._y=l*f*u-d*h*m,this._z=l*h*m-d*f*u,this._w=l*h*u+d*f*m;break;case"ZXY":this._x=d*h*u-l*f*m,this._y=l*f*u+d*h*m,this._z=l*h*m+d*f*u,this._w=l*h*u-d*f*m;break;case"ZYX":this._x=d*h*u-l*f*m,this._y=l*f*u+d*h*m,this._z=l*h*m-d*f*u,this._w=l*h*u+d*f*m;break;case"YZX":this._x=d*h*u+l*f*m,this._y=l*f*u+d*h*m,this._z=l*h*m-d*f*u,this._w=l*h*u-d*f*m;break;case"XZY":this._x=d*h*u-l*f*m,this._y=l*f*u-d*h*m,this._z=l*h*m+d*f*u,this._w=l*h*u+d*f*m;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+a)}return t!==!1&&this._onChangeCallback(),this}setFromAxisAngle(e,t){let n=t/2,i=Math.sin(n);return this._x=e.x*i,this._y=e.y*i,this._z=e.z*i,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(e){let t=e.elements,n=t[0],i=t[4],r=t[8],a=t[1],o=t[5],c=t[9],l=t[2],h=t[6],u=t[10],d=n+o+u;if(d>0){let f=.5/Math.sqrt(d+1);this._w=.25/f,this._x=(h-c)*f,this._y=(r-l)*f,this._z=(a-i)*f}else if(n>o&&n>u){let f=2*Math.sqrt(1+n-o-u);this._w=(h-c)/f,this._x=.25*f,this._y=(i+a)/f,this._z=(r+l)/f}else if(o>u){let f=2*Math.sqrt(1+o-n-u);this._w=(r-l)/f,this._x=(i+a)/f,this._y=.25*f,this._z=(c+h)/f}else{let f=2*Math.sqrt(1+u-n-o);this._w=(a-i)/f,this._x=(r+l)/f,this._y=(c+h)/f,this._z=.25*f}return this._onChangeCallback(),this}setFromUnitVectors(e,t){let n=e.dot(t)+1;return nMath.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=n):(this._x=0,this._y=-e.z,this._z=e.y,this._w=n)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=n),this.normalize()}angleTo(e){return 2*Math.acos(Math.abs(ct(this.dot(e),-1,1)))}rotateTowards(e,t){let n=this.angleTo(e);if(n===0)return this;let i=Math.min(1,t/n);return this.slerp(e,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let e=this.length();return e===0?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this}multiply(e){return this.multiplyQuaternions(this,e)}premultiply(e){return this.multiplyQuaternions(e,this)}multiplyQuaternions(e,t){let n=e._x,i=e._y,r=e._z,a=e._w,o=t._x,c=t._y,l=t._z,h=t._w;return this._x=n*h+a*o+i*l-r*c,this._y=i*h+a*c+r*o-n*l,this._z=r*h+a*l+n*c-i*o,this._w=a*h-n*o-i*c-r*l,this._onChangeCallback(),this}slerp(e,t){if(t===0)return this;if(t===1)return this.copy(e);let n=this._x,i=this._y,r=this._z,a=this._w,o=a*e._w+n*e._x+i*e._y+r*e._z;if(o<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,o=-o):this.copy(e),o>=1)return this._w=a,this._x=n,this._y=i,this._z=r,this;let c=1-o*o;if(c<=Number.EPSILON){let f=1-t;return this._w=f*a+t*this._w,this._x=f*n+t*this._x,this._y=f*i+t*this._y,this._z=f*r+t*this._z,this.normalize(),this._onChangeCallback(),this}let l=Math.sqrt(c),h=Math.atan2(l,o),u=Math.sin((1-t)*h)/l,d=Math.sin(t*h)/l;return this._w=a*u+this._w*d,this._x=n*u+this._x*d,this._y=i*u+this._y*d,this._z=r*u+this._z*d,this._onChangeCallback(),this}slerpQuaternions(e,t,n){return this.copy(e).slerp(t,n)}random(){let e=Math.random(),t=Math.sqrt(1-e),n=Math.sqrt(e),i=2*Math.PI*Math.random(),r=2*Math.PI*Math.random();return this.set(t*Math.cos(i),n*Math.sin(r),n*Math.cos(r),t*Math.sin(i))}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w}fromArray(e,t=0){return this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e}fromBufferAttribute(e,t){return this._x=e.getX(t),this._y=e.getY(t),this._z=e.getZ(t),this._w=e.getW(t),this}toJSON(){return this.toArray()}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}},A=class s{constructor(e=0,t=0,n=0){s.prototype.isVector3=!0,this.x=e,this.y=t,this.z=n}set(e,t,n){return n===void 0&&(n=this.z),this.x=e,this.y=t,this.z=n,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this}multiplyVectors(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this}applyEuler(e){return this.applyQuaternion(Wl.setFromEuler(e))}applyAxisAngle(e,t){return this.applyQuaternion(Wl.setFromAxisAngle(e,t))}applyMatrix3(e){let t=this.x,n=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[3]*n+r[6]*i,this.y=r[1]*t+r[4]*n+r[7]*i,this.z=r[2]*t+r[5]*n+r[8]*i,this}applyNormalMatrix(e){return this.applyMatrix3(e).normalize()}applyMatrix4(e){let t=this.x,n=this.y,i=this.z,r=e.elements,a=1/(r[3]*t+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*t+r[4]*n+r[8]*i+r[12])*a,this.y=(r[1]*t+r[5]*n+r[9]*i+r[13])*a,this.z=(r[2]*t+r[6]*n+r[10]*i+r[14])*a,this}applyQuaternion(e){let t=this.x,n=this.y,i=this.z,r=e.x,a=e.y,o=e.z,c=e.w,l=c*t+a*i-o*n,h=c*n+o*t-r*i,u=c*i+r*n-a*t,d=-r*t-a*n-o*i;return this.x=l*c+d*-r+h*-o-u*-a,this.y=h*c+d*-a+u*-r-l*-o,this.z=u*c+d*-o+l*-a-h*-r,this}project(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)}unproject(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)}transformDirection(e){let t=this.x,n=this.y,i=this.z,r=e.elements;return this.x=r[0]*t+r[4]*n+r[8]*i,this.y=r[1]*t+r[5]*n+r[9]*i,this.z=r[2]*t+r[6]*n+r[10]*i,this.normalize()}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this}divideScalar(e){return this.multiplyScalar(1/e)}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this}clamp(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this}clampScalar(e,t){return this.x=Math.max(e,Math.min(t,this.x)),this.y=Math.max(e,Math.min(t,this.y)),this.z=Math.max(e,Math.min(t,this.z)),this}clampLength(e,t){let n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(e,Math.min(t,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this}cross(e){return this.crossVectors(this,e)}crossVectors(e,t){let n=e.x,i=e.y,r=e.z,a=t.x,o=t.y,c=t.z;return this.x=i*c-r*o,this.y=r*a-n*c,this.z=n*o-i*a,this}projectOnVector(e){let t=e.lengthSq();if(t===0)return this.set(0,0,0);let n=e.dot(this)/t;return this.copy(e).multiplyScalar(n)}projectOnPlane(e){return Oa.copy(this).projectOnVector(e),this.sub(Oa)}reflect(e){return this.sub(Oa.copy(e).multiplyScalar(2*this.dot(e)))}angleTo(e){let t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;let n=this.dot(e)/t;return Math.acos(ct(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){let t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return t*t+n*n+i*i}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)}setFromSpherical(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)}setFromSphericalCoords(e,t,n){let i=Math.sin(t)*e;return this.x=i*Math.sin(n),this.y=Math.cos(t)*e,this.z=i*Math.cos(n),this}setFromCylindrical(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)}setFromCylindricalCoords(e,t,n){return this.x=e*Math.sin(t),this.y=n,this.z=e*Math.cos(t),this}setFromMatrixPosition(e){let t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this}setFromMatrixScale(e){let t=this.setFromMatrixColumn(e,0).length(),n=this.setFromMatrixColumn(e,1).length(),i=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=n,this.z=i,this}setFromMatrixColumn(e,t){return this.fromArray(e.elements,t*4)}setFromMatrix3Column(e,t){return this.fromArray(e.elements,t*3)}setFromEuler(e){return this.x=e._x,this.y=e._y,this.z=e._z,this}setFromColor(e){return this.x=e.r,this.y=e.g,this.z=e.b,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){let e=(Math.random()-.5)*2,t=Math.random()*Math.PI*2,n=Math.sqrt(1-e**2);return this.x=n*Math.cos(t),this.y=n*Math.sin(t),this.z=e,this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}},Oa=new A,Wl=new Ut,Qt=class{constructor(e=new A(1/0,1/0,1/0),t=new A(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=e,this.max=t}set(e,t){return this.min.copy(e),this.max.copy(t),this}setFromArray(e){this.makeEmpty();for(let t=0,n=e.length;tthis.max.x||e.ythis.max.y||e.zthis.max.z)}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(e){return!(e.max.xthis.max.x||e.max.ythis.max.y||e.max.zthis.max.z)}intersectsSphere(e){return this.clampPoint(e.center,cn),cn.distanceToSquared(e.center)<=e.radius*e.radius}intersectsPlane(e){let t,n;return e.normal.x>0?(t=e.normal.x*this.min.x,n=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,n=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,n+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,n+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,n+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,n+=e.normal.z*this.min.z),t<=-e.constant&&n>=-e.constant}intersectsTriangle(e){if(this.isEmpty())return!1;this.getCenter(cs),Ws.subVectors(this.max,cs),xi.subVectors(e.a,cs),vi.subVectors(e.b,cs),yi.subVectors(e.c,cs),Tn.subVectors(vi,xi),wn.subVectors(yi,vi),Wn.subVectors(xi,yi);let t=[0,-Tn.z,Tn.y,0,-wn.z,wn.y,0,-Wn.z,Wn.y,Tn.z,0,-Tn.x,wn.z,0,-wn.x,Wn.z,0,-Wn.x,-Tn.y,Tn.x,0,-wn.y,wn.x,0,-Wn.y,Wn.x,0];return!Fa(t,xi,vi,yi,Ws)||(t=[1,0,0,0,1,0,0,0,1],!Fa(t,xi,vi,yi,Ws))?!1:(Xs.crossVectors(Tn,wn),t=[Xs.x,Xs.y,Xs.z],Fa(t,xi,vi,yi,Ws))}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,cn).distanceTo(e)}getBoundingSphere(e){return this.isEmpty()?e.makeEmpty():(this.getCenter(e.center),e.radius=this.getSize(cn).length()*.5),e}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}applyMatrix4(e){return this.isEmpty()?this:(on[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),on[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),on[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),on[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),on[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),on[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),on[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),on[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(on),this)}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}},on=[new A,new A,new A,new A,new A,new A,new A,new A],cn=new A,_i=new Qt,xi=new A,vi=new A,yi=new A,Tn=new A,wn=new A,Wn=new A,cs=new A,Ws=new A,Xs=new A,Xn=new A;function Fa(s,e,t,n,i){for(let r=0,a=s.length-3;r<=a;r+=3){Xn.fromArray(s,r);let o=i.x*Math.abs(Xn.x)+i.y*Math.abs(Xn.y)+i.z*Math.abs(Xn.z),c=e.dot(Xn),l=t.dot(Xn),h=n.dot(Xn);if(Math.max(-Math.max(c,l,h),Math.min(c,l,h))>o)return!1}return!0}var rp=new Qt,ls=new A,Ba=new A,Yt=class{constructor(e=new A,t=-1){this.center=e,this.radius=t}set(e,t){return this.center.copy(e),this.radius=t,this}setFromPoints(e,t){let n=this.center;t!==void 0?n.copy(t):rp.setFromPoints(e).getCenter(n);let i=0;for(let r=0,a=e.length;rthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t}getBoundingBox(e){return this.isEmpty()?(e.makeEmpty(),e):(e.set(this.center,this.center),e.expandByScalar(this.radius),e)}applyMatrix4(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this}translate(e){return this.center.add(e),this}expandByPoint(e){if(this.isEmpty())return this.center.copy(e),this.radius=0,this;ls.subVectors(e,this.center);let t=ls.lengthSq();if(t>this.radius*this.radius){let n=Math.sqrt(t),i=(n-this.radius)*.5;this.center.addScaledVector(ls,i/n),this.radius+=i}return this}union(e){return e.isEmpty()?this:this.isEmpty()?(this.copy(e),this):(this.center.equals(e.center)===!0?this.radius=Math.max(this.radius,e.radius):(Ba.subVectors(e.center,this.center).setLength(e.radius),this.expandByPoint(ls.copy(e.center).add(Ba)),this.expandByPoint(ls.copy(e.center).sub(Ba))),this)}equals(e){return e.center.equals(this.center)&&e.radius===this.radius}clone(){return new this.constructor().copy(this)}},ln=new A,za=new A,qs=new A,An=new A,Va=new A,Ys=new A,ka=new A,hi=class{constructor(e=new A,t=new A(0,0,-1)){this.origin=e,this.direction=t}set(e,t){return this.origin.copy(e),this.direction.copy(t),this}copy(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this}at(e,t){return t.copy(this.origin).addScaledVector(this.direction,e)}lookAt(e){return this.direction.copy(e).sub(this.origin).normalize(),this}recast(e){return this.origin.copy(this.at(e,ln)),this}closestPointToPoint(e,t){t.subVectors(e,this.origin);let n=t.dot(this.direction);return n<0?t.copy(this.origin):t.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(e){return Math.sqrt(this.distanceSqToPoint(e))}distanceSqToPoint(e){let t=ln.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(ln.copy(this.origin).addScaledVector(this.direction,t),ln.distanceToSquared(e))}distanceSqToSegment(e,t,n,i){za.copy(e).add(t).multiplyScalar(.5),qs.copy(t).sub(e).normalize(),An.copy(this.origin).sub(za);let r=e.distanceTo(t)*.5,a=-this.direction.dot(qs),o=An.dot(this.direction),c=-An.dot(qs),l=An.lengthSq(),h=Math.abs(1-a*a),u,d,f,m;if(h>0)if(u=a*c-o,d=a*o-c,m=r*h,u>=0)if(d>=-m)if(d<=m){let _=1/h;u*=_,d*=_,f=u*(u+a*d+2*o)+d*(a*u+d+2*c)+l}else d=r,u=Math.max(0,-(a*d+o)),f=-u*u+d*(d+2*c)+l;else d=-r,u=Math.max(0,-(a*d+o)),f=-u*u+d*(d+2*c)+l;else d<=-m?(u=Math.max(0,-(-a*r+o)),d=u>0?-r:Math.min(Math.max(-r,-c),r),f=-u*u+d*(d+2*c)+l):d<=m?(u=0,d=Math.min(Math.max(-r,-c),r),f=d*(d+2*c)+l):(u=Math.max(0,-(a*r+o)),d=u>0?r:Math.min(Math.max(-r,-c),r),f=-u*u+d*(d+2*c)+l);else d=a>0?-r:r,u=Math.max(0,-(a*d+o)),f=-u*u+d*(d+2*c)+l;return n&&n.copy(this.origin).addScaledVector(this.direction,u),i&&i.copy(za).addScaledVector(qs,d),f}intersectSphere(e,t){ln.subVectors(e.center,this.origin);let n=ln.dot(this.direction),i=ln.dot(ln)-n*n,r=e.radius*e.radius;if(i>r)return null;let a=Math.sqrt(r-i),o=n-a,c=n+a;return c<0?null:o<0?this.at(c,t):this.at(o,t)}intersectsSphere(e){return this.distanceSqToPoint(e.center)<=e.radius*e.radius}distanceToPlane(e){let t=e.normal.dot(this.direction);if(t===0)return e.distanceToPoint(this.origin)===0?0:null;let n=-(this.origin.dot(e.normal)+e.constant)/t;return n>=0?n:null}intersectPlane(e,t){let n=this.distanceToPlane(e);return n===null?null:this.at(n,t)}intersectsPlane(e){let t=e.distanceToPoint(this.origin);return t===0||e.normal.dot(this.direction)*t<0}intersectBox(e,t){let n,i,r,a,o,c,l=1/this.direction.x,h=1/this.direction.y,u=1/this.direction.z,d=this.origin;return l>=0?(n=(e.min.x-d.x)*l,i=(e.max.x-d.x)*l):(n=(e.max.x-d.x)*l,i=(e.min.x-d.x)*l),h>=0?(r=(e.min.y-d.y)*h,a=(e.max.y-d.y)*h):(r=(e.max.y-d.y)*h,a=(e.min.y-d.y)*h),n>a||r>i||((r>n||isNaN(n))&&(n=r),(a=0?(o=(e.min.z-d.z)*u,c=(e.max.z-d.z)*u):(o=(e.max.z-d.z)*u,c=(e.min.z-d.z)*u),n>c||o>i)||((o>n||n!==n)&&(n=o),(c=0?n:i,t)}intersectsBox(e){return this.intersectBox(e,ln)!==null}intersectTriangle(e,t,n,i,r){Va.subVectors(t,e),Ys.subVectors(n,e),ka.crossVectors(Va,Ys);let a=this.direction.dot(ka),o;if(a>0){if(i)return null;o=1}else if(a<0)o=-1,a=-a;else return null;An.subVectors(this.origin,e);let c=o*this.direction.dot(Ys.crossVectors(An,Ys));if(c<0)return null;let l=o*this.direction.dot(Va.cross(An));if(l<0||c+l>a)return null;let h=-o*An.dot(ka);return h<0?null:this.at(h/a,r)}applyMatrix4(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this}equals(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}clone(){return new this.constructor().copy(this)}},ze=class s{constructor(e,t,n,i,r,a,o,c,l,h,u,d,f,m,_,g){s.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],e!==void 0&&this.set(e,t,n,i,r,a,o,c,l,h,u,d,f,m,_,g)}set(e,t,n,i,r,a,o,c,l,h,u,d,f,m,_,g){let p=this.elements;return p[0]=e,p[4]=t,p[8]=n,p[12]=i,p[1]=r,p[5]=a,p[9]=o,p[13]=c,p[2]=l,p[6]=h,p[10]=u,p[14]=d,p[3]=f,p[7]=m,p[11]=_,p[15]=g,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return new s().fromArray(this.elements)}copy(e){let t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],this}copyPosition(e){let t=this.elements,n=e.elements;return t[12]=n[12],t[13]=n[13],t[14]=n[14],this}setFromMatrix3(e){let t=e.elements;return this.set(t[0],t[3],t[6],0,t[1],t[4],t[7],0,t[2],t[5],t[8],0,0,0,0,1),this}extractBasis(e,t,n){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(e,t,n){return this.set(e.x,t.x,n.x,0,e.y,t.y,n.y,0,e.z,t.z,n.z,0,0,0,0,1),this}extractRotation(e){let t=this.elements,n=e.elements,i=1/Mi.setFromMatrixColumn(e,0).length(),r=1/Mi.setFromMatrixColumn(e,1).length(),a=1/Mi.setFromMatrixColumn(e,2).length();return t[0]=n[0]*i,t[1]=n[1]*i,t[2]=n[2]*i,t[3]=0,t[4]=n[4]*r,t[5]=n[5]*r,t[6]=n[6]*r,t[7]=0,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromEuler(e){let t=this.elements,n=e.x,i=e.y,r=e.z,a=Math.cos(n),o=Math.sin(n),c=Math.cos(i),l=Math.sin(i),h=Math.cos(r),u=Math.sin(r);if(e.order==="XYZ"){let d=a*h,f=a*u,m=o*h,_=o*u;t[0]=c*h,t[4]=-c*u,t[8]=l,t[1]=f+m*l,t[5]=d-_*l,t[9]=-o*c,t[2]=_-d*l,t[6]=m+f*l,t[10]=a*c}else if(e.order==="YXZ"){let d=c*h,f=c*u,m=l*h,_=l*u;t[0]=d+_*o,t[4]=m*o-f,t[8]=a*l,t[1]=a*u,t[5]=a*h,t[9]=-o,t[2]=f*o-m,t[6]=_+d*o,t[10]=a*c}else if(e.order==="ZXY"){let d=c*h,f=c*u,m=l*h,_=l*u;t[0]=d-_*o,t[4]=-a*u,t[8]=m+f*o,t[1]=f+m*o,t[5]=a*h,t[9]=_-d*o,t[2]=-a*l,t[6]=o,t[10]=a*c}else if(e.order==="ZYX"){let d=a*h,f=a*u,m=o*h,_=o*u;t[0]=c*h,t[4]=m*l-f,t[8]=d*l+_,t[1]=c*u,t[5]=_*l+d,t[9]=f*l-m,t[2]=-l,t[6]=o*c,t[10]=a*c}else if(e.order==="YZX"){let d=a*c,f=a*l,m=o*c,_=o*l;t[0]=c*h,t[4]=_-d*u,t[8]=m*u+f,t[1]=u,t[5]=a*h,t[9]=-o*h,t[2]=-l*h,t[6]=f*u+m,t[10]=d-_*u}else if(e.order==="XZY"){let d=a*c,f=a*l,m=o*c,_=o*l;t[0]=c*h,t[4]=-u,t[8]=l*h,t[1]=d*u+_,t[5]=a*h,t[9]=f*u-m,t[2]=m*u-f,t[6]=o*h,t[10]=_*u+d}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromQuaternion(e){return this.compose(ap,e,op)}lookAt(e,t,n){let i=this.elements;return zt.subVectors(e,t),zt.lengthSq()===0&&(zt.z=1),zt.normalize(),Rn.crossVectors(n,zt),Rn.lengthSq()===0&&(Math.abs(n.z)===1?zt.x+=1e-4:zt.z+=1e-4,zt.normalize(),Rn.crossVectors(n,zt)),Rn.normalize(),Zs.crossVectors(zt,Rn),i[0]=Rn.x,i[4]=Zs.x,i[8]=zt.x,i[1]=Rn.y,i[5]=Zs.y,i[9]=zt.y,i[2]=Rn.z,i[6]=Zs.z,i[10]=zt.z,this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){let n=e.elements,i=t.elements,r=this.elements,a=n[0],o=n[4],c=n[8],l=n[12],h=n[1],u=n[5],d=n[9],f=n[13],m=n[2],_=n[6],g=n[10],p=n[14],v=n[3],x=n[7],y=n[11],b=n[15],w=i[0],R=i[4],I=i[8],M=i[12],T=i[1],O=i[5],Y=i[9],$=i[13],U=i[2],z=i[6],q=i[10],H=i[14],ne=i[3],W=i[7],K=i[11],D=i[15];return r[0]=a*w+o*T+c*U+l*ne,r[4]=a*R+o*O+c*z+l*W,r[8]=a*I+o*Y+c*q+l*K,r[12]=a*M+o*$+c*H+l*D,r[1]=h*w+u*T+d*U+f*ne,r[5]=h*R+u*O+d*z+f*W,r[9]=h*I+u*Y+d*q+f*K,r[13]=h*M+u*$+d*H+f*D,r[2]=m*w+_*T+g*U+p*ne,r[6]=m*R+_*O+g*z+p*W,r[10]=m*I+_*Y+g*q+p*K,r[14]=m*M+_*$+g*H+p*D,r[3]=v*w+x*T+y*U+b*ne,r[7]=v*R+x*O+y*z+b*W,r[11]=v*I+x*Y+y*q+b*K,r[15]=v*M+x*$+y*H+b*D,this}multiplyScalar(e){let t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this}determinant(){let e=this.elements,t=e[0],n=e[4],i=e[8],r=e[12],a=e[1],o=e[5],c=e[9],l=e[13],h=e[2],u=e[6],d=e[10],f=e[14],m=e[3],_=e[7],g=e[11],p=e[15];return m*(+r*c*u-i*l*u-r*o*d+n*l*d+i*o*f-n*c*f)+_*(+t*c*f-t*l*d+r*a*d-i*a*f+i*l*h-r*c*h)+g*(+t*l*u-t*o*f-r*a*u+n*a*f+r*o*h-n*l*h)+p*(-i*o*h-t*c*u+t*o*d+i*a*u-n*a*d+n*c*h)}transpose(){let e=this.elements,t;return t=e[1],e[1]=e[4],e[4]=t,t=e[2],e[2]=e[8],e[8]=t,t=e[6],e[6]=e[9],e[9]=t,t=e[3],e[3]=e[12],e[12]=t,t=e[7],e[7]=e[13],e[13]=t,t=e[11],e[11]=e[14],e[14]=t,this}setPosition(e,t,n){let i=this.elements;return e.isVector3?(i[12]=e.x,i[13]=e.y,i[14]=e.z):(i[12]=e,i[13]=t,i[14]=n),this}invert(){let e=this.elements,t=e[0],n=e[1],i=e[2],r=e[3],a=e[4],o=e[5],c=e[6],l=e[7],h=e[8],u=e[9],d=e[10],f=e[11],m=e[12],_=e[13],g=e[14],p=e[15],v=u*g*l-_*d*l+_*c*f-o*g*f-u*c*p+o*d*p,x=m*d*l-h*g*l-m*c*f+a*g*f+h*c*p-a*d*p,y=h*_*l-m*u*l+m*o*f-a*_*f-h*o*p+a*u*p,b=m*u*c-h*_*c-m*o*d+a*_*d+h*o*g-a*u*g,w=t*v+n*x+i*y+r*b;if(w===0)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);let R=1/w;return e[0]=v*R,e[1]=(_*d*r-u*g*r-_*i*f+n*g*f+u*i*p-n*d*p)*R,e[2]=(o*g*r-_*c*r+_*i*l-n*g*l-o*i*p+n*c*p)*R,e[3]=(u*c*r-o*d*r-u*i*l+n*d*l+o*i*f-n*c*f)*R,e[4]=x*R,e[5]=(h*g*r-m*d*r+m*i*f-t*g*f-h*i*p+t*d*p)*R,e[6]=(m*c*r-a*g*r-m*i*l+t*g*l+a*i*p-t*c*p)*R,e[7]=(a*d*r-h*c*r+h*i*l-t*d*l-a*i*f+t*c*f)*R,e[8]=y*R,e[9]=(m*u*r-h*_*r-m*n*f+t*_*f+h*n*p-t*u*p)*R,e[10]=(a*_*r-m*o*r+m*n*l-t*_*l-a*n*p+t*o*p)*R,e[11]=(h*o*r-a*u*r-h*n*l+t*u*l+a*n*f-t*o*f)*R,e[12]=b*R,e[13]=(h*_*i-m*u*i+m*n*d-t*_*d-h*n*g+t*u*g)*R,e[14]=(m*o*i-a*_*i-m*n*c+t*_*c+a*n*g-t*o*g)*R,e[15]=(a*u*i-h*o*i+h*n*c-t*u*c-a*n*d+t*o*d)*R,this}scale(e){let t=this.elements,n=e.x,i=e.y,r=e.z;return t[0]*=n,t[4]*=i,t[8]*=r,t[1]*=n,t[5]*=i,t[9]*=r,t[2]*=n,t[6]*=i,t[10]*=r,t[3]*=n,t[7]*=i,t[11]*=r,this}getMaxScaleOnAxis(){let e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],n=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],i=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,n,i))}makeTranslation(e,t,n){return e.isVector3?this.set(1,0,0,e.x,0,1,0,e.y,0,0,1,e.z,0,0,0,1):this.set(1,0,0,e,0,1,0,t,0,0,1,n,0,0,0,1),this}makeRotationX(e){let t=Math.cos(e),n=Math.sin(e);return this.set(1,0,0,0,0,t,-n,0,0,n,t,0,0,0,0,1),this}makeRotationY(e){let t=Math.cos(e),n=Math.sin(e);return this.set(t,0,n,0,0,1,0,0,-n,0,t,0,0,0,0,1),this}makeRotationZ(e){let t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,0,n,t,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(e,t){let n=Math.cos(t),i=Math.sin(t),r=1-n,a=e.x,o=e.y,c=e.z,l=r*a,h=r*o;return this.set(l*a+n,l*o-i*c,l*c+i*o,0,l*o+i*c,h*o+n,h*c-i*a,0,l*c-i*o,h*c+i*a,r*c*c+n,0,0,0,0,1),this}makeScale(e,t,n){return this.set(e,0,0,0,0,t,0,0,0,0,n,0,0,0,0,1),this}makeShear(e,t,n,i,r,a){return this.set(1,n,r,0,e,1,a,0,t,i,1,0,0,0,0,1),this}compose(e,t,n){let i=this.elements,r=t._x,a=t._y,o=t._z,c=t._w,l=r+r,h=a+a,u=o+o,d=r*l,f=r*h,m=r*u,_=a*h,g=a*u,p=o*u,v=c*l,x=c*h,y=c*u,b=n.x,w=n.y,R=n.z;return i[0]=(1-(_+p))*b,i[1]=(f+y)*b,i[2]=(m-x)*b,i[3]=0,i[4]=(f-y)*w,i[5]=(1-(d+p))*w,i[6]=(g+v)*w,i[7]=0,i[8]=(m+x)*R,i[9]=(g-v)*R,i[10]=(1-(d+_))*R,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,this}decompose(e,t,n){let i=this.elements,r=Mi.set(i[0],i[1],i[2]).length(),a=Mi.set(i[4],i[5],i[6]).length(),o=Mi.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),e.x=i[12],e.y=i[13],e.z=i[14],$t.copy(this);let l=1/r,h=1/a,u=1/o;return $t.elements[0]*=l,$t.elements[1]*=l,$t.elements[2]*=l,$t.elements[4]*=h,$t.elements[5]*=h,$t.elements[6]*=h,$t.elements[8]*=u,$t.elements[9]*=u,$t.elements[10]*=u,t.setFromRotationMatrix($t),n.x=r,n.y=a,n.z=o,this}makePerspective(e,t,n,i,r,a,o=vn){let c=this.elements,l=2*r/(t-e),h=2*r/(n-i),u=(t+e)/(t-e),d=(n+i)/(n-i),f,m;if(o===vn)f=-(a+r)/(a-r),m=-2*a*r/(a-r);else if(o===Gr)f=-a/(a-r),m=-a*r/(a-r);else throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+o);return c[0]=l,c[4]=0,c[8]=u,c[12]=0,c[1]=0,c[5]=h,c[9]=d,c[13]=0,c[2]=0,c[6]=0,c[10]=f,c[14]=m,c[3]=0,c[7]=0,c[11]=-1,c[15]=0,this}makeOrthographic(e,t,n,i,r,a,o=vn){let c=this.elements,l=1/(t-e),h=1/(n-i),u=1/(a-r),d=(t+e)*l,f=(n+i)*h,m,_;if(o===vn)m=(a+r)*u,_=-2*u;else if(o===Gr)m=r*u,_=-1*u;else throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+o);return c[0]=2*l,c[4]=0,c[8]=0,c[12]=-d,c[1]=0,c[5]=2*h,c[9]=0,c[13]=-f,c[2]=0,c[6]=0,c[10]=_,c[14]=-m,c[3]=0,c[7]=0,c[11]=0,c[15]=1,this}equals(e){let t=this.elements,n=e.elements;for(let i=0;i<16;i++)if(t[i]!==n[i])return!1;return!0}fromArray(e,t=0){for(let n=0;n<16;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){let n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e[t+9]=n[9],e[t+10]=n[10],e[t+11]=n[11],e[t+12]=n[12],e[t+13]=n[13],e[t+14]=n[14],e[t+15]=n[15],e}},Mi=new A,$t=new ze,ap=new A(0,0,0),op=new A(1,1,1),Rn=new A,Zs=new A,zt=new A,Xl=new ze,ql=new Ut,Yr=class s{constructor(e=0,t=0,n=0,i=s.DEFAULT_ORDER){this.isEuler=!0,this._x=e,this._y=t,this._z=n,this._order=i}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get order(){return this._order}set order(e){this._order=e,this._onChangeCallback()}set(e,t,n,i=this._order){return this._x=e,this._y=t,this._z=n,this._order=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this}setFromRotationMatrix(e,t=this._order,n=!0){let i=e.elements,r=i[0],a=i[4],o=i[8],c=i[1],l=i[5],h=i[9],u=i[2],d=i[6],f=i[10];switch(t){case"XYZ":this._y=Math.asin(ct(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-h,f),this._z=Math.atan2(-a,r)):(this._x=Math.atan2(d,l),this._z=0);break;case"YXZ":this._x=Math.asin(-ct(h,-1,1)),Math.abs(h)<.9999999?(this._y=Math.atan2(o,f),this._z=Math.atan2(c,l)):(this._y=Math.atan2(-u,r),this._z=0);break;case"ZXY":this._x=Math.asin(ct(d,-1,1)),Math.abs(d)<.9999999?(this._y=Math.atan2(-u,f),this._z=Math.atan2(-a,l)):(this._y=0,this._z=Math.atan2(c,r));break;case"ZYX":this._y=Math.asin(-ct(u,-1,1)),Math.abs(u)<.9999999?(this._x=Math.atan2(d,f),this._z=Math.atan2(c,r)):(this._x=0,this._z=Math.atan2(-a,l));break;case"YZX":this._z=Math.asin(ct(c,-1,1)),Math.abs(c)<.9999999?(this._x=Math.atan2(-h,l),this._y=Math.atan2(-u,r)):(this._x=0,this._y=Math.atan2(o,f));break;case"XZY":this._z=Math.asin(-ct(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(d,l),this._y=Math.atan2(o,r)):(this._x=Math.atan2(-h,f),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+t)}return this._order=t,n===!0&&this._onChangeCallback(),this}setFromQuaternion(e,t,n){return Xl.makeRotationFromQuaternion(e),this.setFromRotationMatrix(Xl,t,n)}setFromVector3(e,t=this._order){return this.set(e.x,e.y,e.z,t)}reorder(e){return ql.setFromEuler(this),this.setFromQuaternion(ql,e)}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order}fromArray(e){return this._x=e[0],this._y=e[1],this._z=e[2],e[3]!==void 0&&(this._order=e[3]),this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}};Yr.DEFAULT_ORDER="XYZ";var Rs=class{constructor(){this.mask=1}set(e){this.mask=(1<>>0}enable(e){this.mask|=1<1){for(let t=0;t1){for(let n=0;n0&&(n=n.concat(a))}return n}getWorldPosition(e){return this.updateWorldMatrix(!0,!1),e.setFromMatrixPosition(this.matrixWorld)}getWorldQuaternion(e){return this.updateWorldMatrix(!0,!1),this.matrixWorld.decompose(hs,e,lp),e}getWorldScale(e){return this.updateWorldMatrix(!0,!1),this.matrixWorld.decompose(hs,hp,e),e}getWorldDirection(e){this.updateWorldMatrix(!0,!1);let t=this.matrixWorld.elements;return e.set(t[8],t[9],t[10]).normalize()}raycast(){}traverse(e){e(this);let t=this.children;for(let n=0,i=t.length;n0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),this.matrixAutoUpdate===!1&&(i.matrixAutoUpdate=!1),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),this.instanceColor!==null&&(i.instanceColor=this.instanceColor.toJSON()));function r(o,c){return o[c.uuid]===void 0&&(o[c.uuid]=c.toJSON(e)),c.uuid}if(this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(e).uuid)),this.environment&&this.environment.isTexture&&this.environment.isRenderTargetTexture!==!0&&(i.environment=this.environment.toJSON(e).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(e.geometries,this.geometry);let o=this.geometry.parameters;if(o!==void 0&&o.shapes!==void 0){let c=o.shapes;if(Array.isArray(c))for(let l=0,h=c.length;l0){i.children=[];for(let o=0;o0){i.animations=[];for(let o=0;o0&&(n.geometries=o),c.length>0&&(n.materials=c),l.length>0&&(n.textures=l),h.length>0&&(n.images=h),u.length>0&&(n.shapes=u),d.length>0&&(n.skeletons=d),f.length>0&&(n.animations=f),m.length>0&&(n.nodes=m)}return n.object=i,n;function a(o){let c=[];for(let l in o){let h=o[l];delete h.metadata,c.push(h)}return c}}clone(e){return new this.constructor().copy(this,e)}copy(e,t=!0){if(this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.rotation.order=e.rotation.order,this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.matrixWorldAutoUpdate=e.matrixWorldAutoUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.animations=e.animations.slice(),this.userData=JSON.parse(JSON.stringify(e.userData)),t===!0)for(let n=0;n0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(e,t,n,i,r){Kt.subVectors(i,t),un.subVectors(n,t),Ha.subVectors(e,t);let a=Kt.dot(Kt),o=Kt.dot(un),c=Kt.dot(Ha),l=un.dot(un),h=un.dot(Ha),u=a*l-o*o;if(u===0)return r.set(-2,-1,-1);let d=1/u,f=(l*c-o*h)*d,m=(a*h-o*c)*d;return r.set(1-f-m,m,f)}static containsPoint(e,t,n,i){return this.getBarycoord(e,t,n,i,dn),dn.x>=0&&dn.y>=0&&dn.x+dn.y<=1}static getUV(e,t,n,i,r,a,o,c){return $s===!1&&(console.warn("THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation()."),$s=!0),this.getInterpolation(e,t,n,i,r,a,o,c)}static getInterpolation(e,t,n,i,r,a,o,c){return this.getBarycoord(e,t,n,i,dn),c.setScalar(0),c.addScaledVector(r,dn.x),c.addScaledVector(a,dn.y),c.addScaledVector(o,dn.z),c}static isFrontFacing(e,t,n,i){return Kt.subVectors(n,t),un.subVectors(e,t),Kt.cross(un).dot(i)<0}set(e,t,n){return this.a.copy(e),this.b.copy(t),this.c.copy(n),this}setFromPointsAndIndices(e,t,n,i){return this.a.copy(e[t]),this.b.copy(e[n]),this.c.copy(e[i]),this}setFromAttributeAndIndices(e,t,n,i){return this.a.fromBufferAttribute(e,t),this.b.fromBufferAttribute(e,n),this.c.fromBufferAttribute(e,i),this}clone(){return new this.constructor().copy(this)}copy(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this}getArea(){return Kt.subVectors(this.c,this.b),un.subVectors(this.a,this.b),Kt.cross(un).length()*.5}getMidpoint(e){return e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(e){return s.getNormal(this.a,this.b,this.c,e)}getPlane(e){return e.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(e,t){return s.getBarycoord(e,this.a,this.b,this.c,t)}getUV(e,t,n,i,r){return $s===!1&&(console.warn("THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation()."),$s=!0),s.getInterpolation(e,this.a,this.b,this.c,t,n,i,r)}getInterpolation(e,t,n,i,r){return s.getInterpolation(e,this.a,this.b,this.c,t,n,i,r)}containsPoint(e){return s.containsPoint(e,this.a,this.b,this.c)}isFrontFacing(e){return s.isFrontFacing(this.a,this.b,this.c,e)}intersectsBox(e){return e.intersectsTriangle(this)}closestPointToPoint(e,t){let n=this.a,i=this.b,r=this.c,a,o;bi.subVectors(i,n),Ei.subVectors(r,n),Ga.subVectors(e,n);let c=bi.dot(Ga),l=Ei.dot(Ga);if(c<=0&&l<=0)return t.copy(n);Wa.subVectors(e,i);let h=bi.dot(Wa),u=Ei.dot(Wa);if(h>=0&&u<=h)return t.copy(i);let d=c*u-h*l;if(d<=0&&c>=0&&h<=0)return a=c/(c-h),t.copy(n).addScaledVector(bi,a);Xa.subVectors(e,r);let f=bi.dot(Xa),m=Ei.dot(Xa);if(m>=0&&f<=m)return t.copy(r);let _=f*l-c*m;if(_<=0&&l>=0&&m<=0)return o=l/(l-m),t.copy(n).addScaledVector(Ei,o);let g=h*m-f*u;if(g<=0&&u-h>=0&&f-m>=0)return Kl.subVectors(r,i),o=(u-h)/(u-h+(f-m)),t.copy(i).addScaledVector(Kl,o);let p=1/(g+_+d);return a=_*p,o=d*p,t.copy(n).addScaledVector(bi,a).addScaledVector(Ei,o)}equals(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}},fp=0,bt=class extends sn{constructor(){super(),this.isMaterial=!0,Object.defineProperty(this,"id",{value:fp++}),this.uuid=kt(),this.name="",this.type="Material",this.blending=Wi,this.side=Bn,this.vertexColors=!1,this.opacity=1,this.transparent=!1,this.alphaHash=!1,this.blendSrc=ld,this.blendDst=hd,this.blendEquation=Bi,this.blendSrcAlpha=null,this.blendDstAlpha=null,this.blendEquationAlpha=null,this.depthFunc=uo,this.depthTest=!0,this.depthWrite=!0,this.stencilWriteMask=255,this.stencilFunc=If,this.stencilRef=0,this.stencilFuncMask=255,this.stencilFail=Ia,this.stencilZFail=Ia,this.stencilZPass=Ia,this.stencilWrite=!1,this.clippingPlanes=null,this.clipIntersection=!1,this.clipShadows=!1,this.shadowSide=null,this.colorWrite=!0,this.precision=null,this.polygonOffset=!1,this.polygonOffsetFactor=0,this.polygonOffsetUnits=0,this.dithering=!1,this.alphaToCoverage=!1,this.premultipliedAlpha=!1,this.forceSinglePass=!1,this.visible=!0,this.toneMapped=!0,this.userData={},this.version=0,this._alphaTest=0}get alphaTest(){return this._alphaTest}set alphaTest(e){this._alphaTest>0!=e>0&&this.version++,this._alphaTest=e}onBuild(){}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(e){if(e!==void 0)for(let t in e){let n=e[t];if(n===void 0){console.warn(`THREE.Material: parameter '${t}' has value of undefined.`);continue}let i=this[t];if(i===void 0){console.warn(`THREE.Material: '${t}' is not a property of THREE.${this.type}.`);continue}i&&i.isColor?i.set(n):i&&i.isVector3&&n&&n.isVector3?i.copy(n):this[t]=n}}toJSON(e){let t=e===void 0||typeof e=="string";t&&(e={textures:{},images:{}});let n={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};n.uuid=this.uuid,n.type=this.type,this.name!==""&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),this.roughness!==void 0&&(n.roughness=this.roughness),this.metalness!==void 0&&(n.metalness=this.metalness),this.sheen!==void 0&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),this.sheenRoughness!==void 0&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity&&this.emissiveIntensity!==1&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),this.specularIntensity!==void 0&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),this.shininess!==void 0&&(n.shininess=this.shininess),this.clearcoat!==void 0&&(n.clearcoat=this.clearcoat),this.clearcoatRoughness!==void 0&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(e).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(e).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(e).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.iridescence!==void 0&&(n.iridescence=this.iridescence),this.iridescenceIOR!==void 0&&(n.iridescenceIOR=this.iridescenceIOR),this.iridescenceThicknessRange!==void 0&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(e).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(e).uuid),this.anisotropy!==void 0&&(n.anisotropy=this.anisotropy),this.anisotropyRotation!==void 0&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(e).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(e).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(e).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(e).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(e).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(e).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(e).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(e).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(e).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(e).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(e).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(e).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(e).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(e).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(e).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(e).uuid,this.combine!==void 0&&(n.combine=this.combine)),this.envMapIntensity!==void 0&&(n.envMapIntensity=this.envMapIntensity),this.reflectivity!==void 0&&(n.reflectivity=this.reflectivity),this.refractionRatio!==void 0&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(e).uuid),this.transmission!==void 0&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(e).uuid),this.thickness!==void 0&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(e).uuid),this.attenuationDistance!==void 0&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),this.attenuationColor!==void 0&&(n.attenuationColor=this.attenuationColor.getHex()),this.size!==void 0&&(n.size=this.size),this.shadowSide!==null&&(n.shadowSide=this.shadowSide),this.sizeAttenuation!==void 0&&(n.sizeAttenuation=this.sizeAttenuation),this.blending!==Wi&&(n.blending=this.blending),this.side!==Bn&&(n.side=this.side),this.vertexColors===!0&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),this.transparent===!0&&(n.transparent=!0),n.depthFunc=this.depthFunc,n.depthTest=this.depthTest,n.depthWrite=this.depthWrite,n.colorWrite=this.colorWrite,n.stencilWrite=this.stencilWrite,n.stencilWriteMask=this.stencilWriteMask,n.stencilFunc=this.stencilFunc,n.stencilRef=this.stencilRef,n.stencilFuncMask=this.stencilFuncMask,n.stencilFail=this.stencilFail,n.stencilZFail=this.stencilZFail,n.stencilZPass=this.stencilZPass,this.rotation!==void 0&&this.rotation!==0&&(n.rotation=this.rotation),this.polygonOffset===!0&&(n.polygonOffset=!0),this.polygonOffsetFactor!==0&&(n.polygonOffsetFactor=this.polygonOffsetFactor),this.polygonOffsetUnits!==0&&(n.polygonOffsetUnits=this.polygonOffsetUnits),this.linewidth!==void 0&&this.linewidth!==1&&(n.linewidth=this.linewidth),this.dashSize!==void 0&&(n.dashSize=this.dashSize),this.gapSize!==void 0&&(n.gapSize=this.gapSize),this.scale!==void 0&&(n.scale=this.scale),this.dithering===!0&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),this.alphaHash===!0&&(n.alphaHash=!0),this.alphaToCoverage===!0&&(n.alphaToCoverage=!0),this.premultipliedAlpha===!0&&(n.premultipliedAlpha=!0),this.forceSinglePass===!0&&(n.forceSinglePass=!0),this.wireframe===!0&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),this.wireframeLinecap!=="round"&&(n.wireframeLinecap=this.wireframeLinecap),this.wireframeLinejoin!=="round"&&(n.wireframeLinejoin=this.wireframeLinejoin),this.flatShading===!0&&(n.flatShading=!0),this.visible===!1&&(n.visible=!1),this.toneMapped===!1&&(n.toneMapped=!1),this.fog===!1&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData);function i(r){let a=[];for(let o in r){let c=r[o];delete c.metadata,a.push(c)}return a}if(t){let r=i(e.textures),a=i(e.images);r.length>0&&(n.textures=r),a.length>0&&(n.images=a)}return n}clone(){return new this.constructor().copy(this)}copy(e){this.name=e.name,this.blending=e.blending,this.side=e.side,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;let t=e.clippingPlanes,n=null;if(t!==null){let i=t.length;n=new Array(i);for(let r=0;r!==i;++r)n[r]=t[r].clone()}return this.clippingPlanes=n,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.alphaHash=e.alphaHash,this.alphaToCoverage=e.alphaToCoverage,this.premultipliedAlpha=e.premultipliedAlpha,this.forceSinglePass=e.forceSinglePass,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){e===!0&&this.version++}},Sd={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},Cn={h:0,s:0,l:0},Ks={h:0,s:0,l:0};function qa(s,e,t){return t<0&&(t+=1),t>1&&(t-=1),t<1/6?s+(e-s)*6*t:t<1/2?e:t<2/3?s+(e-s)*6*(2/3-t):s}var pe=class{constructor(e,t,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(e,t,n)}set(e,t,n){if(t===void 0&&n===void 0){let i=e;i&&i.isColor?this.copy(i):typeof i=="number"?this.setHex(i):typeof i=="string"&&this.setStyle(i)}else this.setRGB(e,t,n);return this}setScalar(e){return this.r=e,this.g=e,this.b=e,this}setHex(e,t=vt){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(e&255)/255,Qe.toWorkingColorSpace(this,t),this}setRGB(e,t,n,i=Qe.workingColorSpace){return this.r=e,this.g=t,this.b=n,Qe.toWorkingColorSpace(this,i),this}setHSL(e,t,n,i=Qe.workingColorSpace){if(e=Yc(e,1),t=ct(t,0,1),n=ct(n,0,1),t===0)this.r=this.g=this.b=n;else{let r=n<=.5?n*(1+t):n+t-n*t,a=2*n-r;this.r=qa(a,r,e+1/3),this.g=qa(a,r,e),this.b=qa(a,r,e-1/3)}return Qe.toWorkingColorSpace(this,i),this}setStyle(e,t=vt){function n(r){r!==void 0&&parseFloat(r)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(e)){let r,a=i[1],o=i[2];switch(a){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,t);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,t);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,t);break;default:console.warn("THREE.Color: Unknown color model "+e)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(e)){let r=i[1],a=r.length;if(a===3)return this.setRGB(parseInt(r.charAt(0),16)/15,parseInt(r.charAt(1),16)/15,parseInt(r.charAt(2),16)/15,t);if(a===6)return this.setHex(parseInt(r,16),t);console.warn("THREE.Color: Invalid hex color "+e)}else if(e&&e.length>0)return this.setColorName(e,t);return this}setColorName(e,t=vt){let n=Sd[e.toLowerCase()];return n!==void 0?this.setHex(n,t):console.warn("THREE.Color: Unknown color "+e),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(e){return this.r=e.r,this.g=e.g,this.b=e.b,this}copySRGBToLinear(e){return this.r=Xi(e.r),this.g=Xi(e.g),this.b=Xi(e.b),this}copyLinearToSRGB(e){return this.r=Da(e.r),this.g=Da(e.g),this.b=Da(e.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(e=vt){return Qe.fromWorkingColorSpace(Tt.copy(this),e),Math.round(ct(Tt.r*255,0,255))*65536+Math.round(ct(Tt.g*255,0,255))*256+Math.round(ct(Tt.b*255,0,255))}getHexString(e=vt){return("000000"+this.getHex(e).toString(16)).slice(-6)}getHSL(e,t=Qe.workingColorSpace){Qe.fromWorkingColorSpace(Tt.copy(this),t);let n=Tt.r,i=Tt.g,r=Tt.b,a=Math.max(n,i,r),o=Math.min(n,i,r),c,l,h=(o+a)/2;if(o===a)c=0,l=0;else{let u=a-o;switch(l=h<=.5?u/(a+o):u/(2-a-o),a){case n:c=(i-r)/u+(i>-l-14,n[c|256]=1024>>-l-14|32768,i[c]=-l-1,i[c|256]=-l-1):l<=15?(n[c]=l+15<<10,n[c|256]=l+15<<10|32768,i[c]=13,i[c|256]=13):l<128?(n[c]=31744,n[c|256]=64512,i[c]=24,i[c|256]=24):(n[c]=31744,n[c|256]=64512,i[c]=13,i[c|256]=13)}let r=new Uint32Array(2048),a=new Uint32Array(64),o=new Uint32Array(64);for(let c=1;c<1024;++c){let l=c<<13,h=0;for(;!(l&8388608);)l<<=1,h-=8388608;l&=-8388609,h+=947912704,r[c]=l|h}for(let c=1024;c<2048;++c)r[c]=939524096+(c-1024<<13);for(let c=1;c<31;++c)a[c]=c<<23;a[31]=1199570944,a[32]=2147483648;for(let c=33;c<63;++c)a[c]=2147483648+(c-32<<23);a[63]=3347054592;for(let c=1;c<64;++c)c!==32&&(o[c]=1024);return{floatView:e,uint32View:t,baseTable:n,shiftTable:i,mantissaTable:r,exponentTable:a,offsetTable:o}}function Nt(s){Math.abs(s)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),s=ct(s,-65504,65504),_n.floatView[0]=s;let e=_n.uint32View[0],t=e>>23&511;return _n.baseTable[t]+((e&8388607)>>_n.shiftTable[t])}function xs(s){let e=s>>10;return _n.uint32View[0]=_n.mantissaTable[_n.offsetTable[e]+(s&1023)]+_n.exponentTable[e],_n.floatView[0]}var Mv={toHalfFloat:Nt,fromHalfFloat:xs},ft=new A,Qs=new Z,et=class{constructor(e,t,n=!1){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,this.name="",this.array=e,this.itemSize=t,this.count=e!==void 0?e.length/t:0,this.normalized=n,this.usage=Hr,this.updateRange={offset:0,count:-1},this.gpuType=xn,this.version=0}onUploadCallback(){}set needsUpdate(e){e===!0&&this.version++}setUsage(e){return this.usage=e,this}copy(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this.gpuType=e.gpuType,this}copyAt(e,t,n){e*=this.itemSize,n*=t.itemSize;for(let i=0,r=this.itemSize;i0&&(e.userData=this.userData),this.parameters!==void 0){let c=this.parameters;for(let l in c)c[l]!==void 0&&(e[l]=c[l]);return e}e.data={attributes:{}};let t=this.index;t!==null&&(e.data.index={type:t.array.constructor.name,array:Array.prototype.slice.call(t.array)});let n=this.attributes;for(let c in n){let l=n[c];e.data.attributes[c]=l.toJSON(e.data)}let i={},r=!1;for(let c in this.morphAttributes){let l=this.morphAttributes[c],h=[];for(let u=0,d=l.length;u0&&(i[c]=h,r=!0)}r&&(e.data.morphAttributes=i,e.data.morphTargetsRelative=this.morphTargetsRelative);let a=this.groups;a.length>0&&(e.data.groups=JSON.parse(JSON.stringify(a)));let o=this.boundingSphere;return o!==null&&(e.data.boundingSphere={center:o.center.toArray(),radius:o.radius}),e}clone(){return new this.constructor().copy(this)}copy(e){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;let t={};this.name=e.name;let n=e.index;n!==null&&this.setIndex(n.clone(t));let i=e.attributes;for(let l in i){let h=i[l];this.setAttribute(l,h.clone(t))}let r=e.morphAttributes;for(let l in r){let h=[],u=r[l];for(let d=0,f=u.length;d0){let i=t[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,a=i.length;r(e.far-e.near)**2))&&(rh.copy(r).invert(),qn.copy(e.ray).applyMatrix4(rh),!(n.boundingBox!==null&&qn.intersectsBox(n.boundingBox)===!1)&&this._computeIntersections(e,t,qn)))}_computeIntersections(e,t,n){let i,r=this.geometry,a=this.material,o=r.index,c=r.attributes.position,l=r.attributes.uv,h=r.attributes.uv1,u=r.attributes.normal,d=r.groups,f=r.drawRange;if(o!==null)if(Array.isArray(a))for(let m=0,_=d.length;m<_;m++){let g=d[m],p=a[g.materialIndex],v=Math.max(g.start,f.start),x=Math.min(o.count,Math.min(g.start+g.count,f.start+f.count));for(let y=v,b=x;yt.far?null:{distance:l,point:rr.clone(),object:s}}function ar(s,e,t,n,i,r,a,o,c,l){s.getVertexPosition(o,wi),s.getVertexPosition(c,Ai),s.getVertexPosition(l,Ri);let h=gp(s,e,t,n,wi,Ai,Ri,sr);if(h){i&&(tr.fromBufferAttribute(i,o),nr.fromBufferAttribute(i,c),ir.fromBufferAttribute(i,l),h.uv=Un.getInterpolation(sr,wi,Ai,Ri,tr,nr,ir,new Z)),r&&(tr.fromBufferAttribute(r,o),nr.fromBufferAttribute(r,c),ir.fromBufferAttribute(r,l),h.uv1=Un.getInterpolation(sr,wi,Ai,Ri,tr,nr,ir,new Z),h.uv2=h.uv1),a&&(oh.fromBufferAttribute(a,o),ch.fromBufferAttribute(a,c),lh.fromBufferAttribute(a,l),h.normal=Un.getInterpolation(sr,wi,Ai,Ri,oh,ch,lh,new A),h.normal.dot(n.direction)>0&&h.normal.multiplyScalar(-1));let u={a:o,b:c,c:l,normal:new A,materialIndex:0};Un.getNormal(wi,Ai,Ri,u.normal),h.face=u}return h}var Ji=class s extends Ge{constructor(e=1,t=1,n=1,i=1,r=1,a=1){super(),this.type="BoxGeometry",this.parameters={width:e,height:t,depth:n,widthSegments:i,heightSegments:r,depthSegments:a};let o=this;i=Math.floor(i),r=Math.floor(r),a=Math.floor(a);let c=[],l=[],h=[],u=[],d=0,f=0;m("z","y","x",-1,-1,n,t,e,a,r,0),m("z","y","x",1,-1,n,t,-e,a,r,1),m("x","z","y",1,1,e,n,t,i,a,2),m("x","z","y",1,-1,e,n,-t,i,a,3),m("x","y","z",1,-1,e,t,n,i,r,4),m("x","y","z",-1,-1,e,t,-n,i,r,5),this.setIndex(c),this.setAttribute("position",new ve(l,3)),this.setAttribute("normal",new ve(h,3)),this.setAttribute("uv",new ve(u,2));function m(_,g,p,v,x,y,b,w,R,I,M){let T=y/R,O=b/I,Y=y/2,$=b/2,U=w/2,z=R+1,q=I+1,H=0,ne=0,W=new A;for(let K=0;K0?1:-1,h.push(W.x,W.y,W.z),u.push(G/R),u.push(1-K/I),H+=1}}for(let K=0;K0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;let n={};for(let i in this.extensions)this.extensions[i]===!0&&(n[i]=!0);return Object.keys(n).length>0&&(t.extensions=n),t}},Cs=class extends Je{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new ze,this.projectionMatrix=new ze,this.projectionMatrixInverse=new ze,this.coordinateSystem=vn}copy(e,t){return super.copy(e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this.coordinateSystem=e.coordinateSystem,this}getWorldDirection(e){return super.getWorldDirection(e).negate()}updateMatrixWorld(e){super.updateMatrixWorld(e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(e,t){super.updateWorldMatrix(e,t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return new this.constructor().copy(this)}},yt=class extends Cs{constructor(e=50,t=1,n=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=e,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=t,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=e.view===null?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this}setFocalLength(e){let t=.5*this.getFilmHeight()/e;this.fov=Zi*2*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){let e=Math.tan(ai*.5*this.fov);return .5*this.getFilmHeight()/e}getEffectiveFOV(){return Zi*2*Math.atan(Math.tan(ai*.5*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}setViewOffset(e,t,n,i,r,a){this.aspect=e/t,this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=a,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){let e=this.near,t=e*Math.tan(ai*.5*this.fov)/this.zoom,n=2*t,i=this.aspect*n,r=-.5*i,a=this.view;if(this.view!==null&&this.view.enabled){let c=a.fullWidth,l=a.fullHeight;r+=a.offsetX*i/c,t-=a.offsetY*n/l,i*=a.width/c,n*=a.height/l}let o=this.filmOffset;o!==0&&(r+=e*o/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,t,t-n,e,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){let t=super.toJSON(e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,this.view!==null&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}},Ci=-90,Pi=1,_o=class extends Je{constructor(e,t,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;let i=new yt(Ci,Pi,e,t);i.layers=this.layers,this.add(i);let r=new yt(Ci,Pi,e,t);r.layers=this.layers,this.add(r);let a=new yt(Ci,Pi,e,t);a.layers=this.layers,this.add(a);let o=new yt(Ci,Pi,e,t);o.layers=this.layers,this.add(o);let c=new yt(Ci,Pi,e,t);c.layers=this.layers,this.add(c);let l=new yt(Ci,Pi,e,t);l.layers=this.layers,this.add(l)}updateCoordinateSystem(){let e=this.coordinateSystem,t=this.children.concat(),[n,i,r,a,o,c]=t;for(let l of t)this.remove(l);if(e===vn)n.up.set(0,1,0),n.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),a.up.set(0,0,1),a.lookAt(0,-1,0),o.up.set(0,1,0),o.lookAt(0,0,1),c.up.set(0,1,0),c.lookAt(0,0,-1);else if(e===Gr)n.up.set(0,-1,0),n.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),a.up.set(0,0,-1),a.lookAt(0,-1,0),o.up.set(0,-1,0),o.lookAt(0,0,1),c.up.set(0,-1,0),c.lookAt(0,0,-1);else throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+e);for(let l of t)this.add(l),l.updateMatrixWorld()}update(e,t){this.parent===null&&this.updateMatrixWorld();let{renderTarget:n,activeMipmapLevel:i}=this;this.coordinateSystem!==e.coordinateSystem&&(this.coordinateSystem=e.coordinateSystem,this.updateCoordinateSystem());let[r,a,o,c,l,h]=this.children,u=e.getRenderTarget(),d=e.getActiveCubeFace(),f=e.getActiveMipmapLevel(),m=e.xr.enabled;e.xr.enabled=!1;let _=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,e.setRenderTarget(n,0,i),e.render(t,r),e.setRenderTarget(n,1,i),e.render(t,a),e.setRenderTarget(n,2,i),e.render(t,o),e.setRenderTarget(n,3,i),e.render(t,c),e.setRenderTarget(n,4,i),e.render(t,l),n.texture.generateMipmaps=_,e.setRenderTarget(n,5,i),e.render(t,h),e.setRenderTarget(u,d,f),e.xr.enabled=m,n.texture.needsPMREMUpdate=!0}},Ki=class extends St{constructor(e,t,n,i,r,a,o,c,l,h){e=e!==void 0?e:[],t=t!==void 0?t:zn,super(e,t,n,i,r,a,o,c,l,h),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(e){this.image=e}},xo=class extends qt{constructor(e=1,t={}){super(e,e,t),this.isWebGLCubeRenderTarget=!0;let n={width:e,height:e,depth:1},i=[n,n,n,n,n,n];t.encoding!==void 0&&(Ms("THREE.WebGLCubeRenderTarget: option.encoding has been replaced by option.colorSpace."),t.colorSpace=t.encoding===ri?vt:Xt),this.texture=new Ki(i,t.mapping,t.wrapS,t.wrapT,t.magFilter,t.minFilter,t.format,t.type,t.anisotropy,t.colorSpace),this.texture.isRenderTargetTexture=!0,this.texture.generateMipmaps=t.generateMipmaps!==void 0?t.generateMipmaps:!1,this.texture.minFilter=t.minFilter!==void 0?t.minFilter:mt}fromEquirectangularTexture(e,t){this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;let n={uniforms:{tEquirect:{value:null}},vertexShader:` + + varying vec3 vWorldDirection; + + vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); + + } + + void main() { + + vWorldDirection = transformDirection( position, modelMatrix ); + + #include + #include + + } + `,fragmentShader:` + + uniform sampler2D tEquirect; + + varying vec3 vWorldDirection; + + #include + + void main() { + + vec3 direction = normalize( vWorldDirection ); + + vec2 sampleUV = equirectUv( direction ); + + gl_FragColor = texture2D( tEquirect, sampleUV ); + + } + `},i=new Ji(5,5,5),r=new jt({name:"CubemapFromEquirect",uniforms:$i(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:Ft,blending:Dn});r.uniforms.tEquirect.value=t;let a=new Mt(i,r),o=t.minFilter;return t.minFilter===li&&(t.minFilter=mt),new _o(1,10,this).update(e,a),t.minFilter=o,a.geometry.dispose(),a.material.dispose(),this}clear(e,t,n,i){let r=e.getRenderTarget();for(let a=0;a<6;a++)e.setRenderTarget(this,a),e.clear(t,n,i);e.setRenderTarget(r)}},Ja=new A,Mp=new A,Sp=new He,mn=class{constructor(e=new A(1,0,0),t=0){this.isPlane=!0,this.normal=e,this.constant=t}set(e,t){return this.normal.copy(e),this.constant=t,this}setComponents(e,t,n,i){return this.normal.set(e,t,n),this.constant=i,this}setFromNormalAndCoplanarPoint(e,t){return this.normal.copy(e),this.constant=-t.dot(this.normal),this}setFromCoplanarPoints(e,t,n){let i=Ja.subVectors(n,t).cross(Mp.subVectors(e,t)).normalize();return this.setFromNormalAndCoplanarPoint(i,e),this}copy(e){return this.normal.copy(e.normal),this.constant=e.constant,this}normalize(){let e=1/this.normal.length();return this.normal.multiplyScalar(e),this.constant*=e,this}negate(){return this.constant*=-1,this.normal.negate(),this}distanceToPoint(e){return this.normal.dot(e)+this.constant}distanceToSphere(e){return this.distanceToPoint(e.center)-e.radius}projectPoint(e,t){return t.copy(e).addScaledVector(this.normal,-this.distanceToPoint(e))}intersectLine(e,t){let n=e.delta(Ja),i=this.normal.dot(n);if(i===0)return this.distanceToPoint(e.start)===0?t.copy(e.start):null;let r=-(e.start.dot(this.normal)+this.constant)/i;return r<0||r>1?null:t.copy(e.start).addScaledVector(n,r)}intersectsLine(e){let t=this.distanceToPoint(e.start),n=this.distanceToPoint(e.end);return t<0&&n>0||n<0&&t>0}intersectsBox(e){return e.intersectsPlane(this)}intersectsSphere(e){return e.intersectsPlane(this)}coplanarPoint(e){return e.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(e,t){let n=t||Sp.getNormalMatrix(e),i=this.coplanarPoint(Ja).applyMatrix4(e),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this}translate(e){return this.constant-=e.dot(this.normal),this}equals(e){return e.normal.equals(this.normal)&&e.constant===this.constant}clone(){return new this.constructor().copy(this)}},Yn=new Yt,or=new A,Ps=class{constructor(e=new mn,t=new mn,n=new mn,i=new mn,r=new mn,a=new mn){this.planes=[e,t,n,i,r,a]}set(e,t,n,i,r,a){let o=this.planes;return o[0].copy(e),o[1].copy(t),o[2].copy(n),o[3].copy(i),o[4].copy(r),o[5].copy(a),this}copy(e){let t=this.planes;for(let n=0;n<6;n++)t[n].copy(e.planes[n]);return this}setFromProjectionMatrix(e,t=vn){let n=this.planes,i=e.elements,r=i[0],a=i[1],o=i[2],c=i[3],l=i[4],h=i[5],u=i[6],d=i[7],f=i[8],m=i[9],_=i[10],g=i[11],p=i[12],v=i[13],x=i[14],y=i[15];if(n[0].setComponents(c-r,d-l,g-f,y-p).normalize(),n[1].setComponents(c+r,d+l,g+f,y+p).normalize(),n[2].setComponents(c+a,d+h,g+m,y+v).normalize(),n[3].setComponents(c-a,d-h,g-m,y-v).normalize(),n[4].setComponents(c-o,d-u,g-_,y-x).normalize(),t===vn)n[5].setComponents(c+o,d+u,g+_,y+x).normalize();else if(t===Gr)n[5].setComponents(o,u,_,x).normalize();else throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+t);return this}intersectsObject(e){if(e.boundingSphere!==void 0)e.boundingSphere===null&&e.computeBoundingSphere(),Yn.copy(e.boundingSphere).applyMatrix4(e.matrixWorld);else{let t=e.geometry;t.boundingSphere===null&&t.computeBoundingSphere(),Yn.copy(t.boundingSphere).applyMatrix4(e.matrixWorld)}return this.intersectsSphere(Yn)}intersectsSprite(e){return Yn.center.set(0,0,0),Yn.radius=.7071067811865476,Yn.applyMatrix4(e.matrixWorld),this.intersectsSphere(Yn)}intersectsSphere(e){let t=this.planes,n=e.center,i=-e.radius;for(let r=0;r<6;r++)if(t[r].distanceToPoint(n)0?e.max.x:e.min.x,or.y=i.normal.y>0?e.max.y:e.min.y,or.z=i.normal.z>0?e.max.z:e.min.z,i.distanceToPoint(or)<0)return!1}return!0}containsPoint(e){let t=this.planes;for(let n=0;n<6;n++)if(t[n].distanceToPoint(e)<0)return!1;return!0}clone(){return new this.constructor().copy(this)}};function Ed(){let s=null,e=!1,t=null,n=null;function i(r,a){t(r,a),n=s.requestAnimationFrame(i)}return{start:function(){e!==!0&&t!==null&&(n=s.requestAnimationFrame(i),e=!0)},stop:function(){s.cancelAnimationFrame(n),e=!1},setAnimationLoop:function(r){t=r},setContext:function(r){s=r}}}function bp(s,e){let t=e.isWebGL2,n=new WeakMap;function i(l,h){let u=l.array,d=l.usage,f=s.createBuffer();s.bindBuffer(h,f),s.bufferData(h,u,d),l.onUploadCallback();let m;if(u instanceof Float32Array)m=s.FLOAT;else if(u instanceof Uint16Array)if(l.isFloat16BufferAttribute)if(t)m=s.HALF_FLOAT;else throw new Error("THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.");else m=s.UNSIGNED_SHORT;else if(u instanceof Int16Array)m=s.SHORT;else if(u instanceof Uint32Array)m=s.UNSIGNED_INT;else if(u instanceof Int32Array)m=s.INT;else if(u instanceof Int8Array)m=s.BYTE;else if(u instanceof Uint8Array)m=s.UNSIGNED_BYTE;else if(u instanceof Uint8ClampedArray)m=s.UNSIGNED_BYTE;else throw new Error("THREE.WebGLAttributes: Unsupported buffer data format: "+u);return{buffer:f,type:m,bytesPerElement:u.BYTES_PER_ELEMENT,version:l.version}}function r(l,h,u){let d=h.array,f=h.updateRange;s.bindBuffer(u,l),f.count===-1?s.bufferSubData(u,0,d):(t?s.bufferSubData(u,f.offset*d.BYTES_PER_ELEMENT,d,f.offset,f.count):s.bufferSubData(u,f.offset*d.BYTES_PER_ELEMENT,d.subarray(f.offset,f.offset+f.count)),f.count=-1),h.onUploadCallback()}function a(l){return l.isInterleavedBufferAttribute&&(l=l.data),n.get(l)}function o(l){l.isInterleavedBufferAttribute&&(l=l.data);let h=n.get(l);h&&(s.deleteBuffer(h.buffer),n.delete(l))}function c(l,h){if(l.isGLBufferAttribute){let d=n.get(l);(!d||d.version 0 + vec4 plane; + #pragma unroll_loop_start + for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + if ( dot( vClipPosition, plane.xyz ) > plane.w ) discard; + } + #pragma unroll_loop_end + #if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES + bool clipped = true; + #pragma unroll_loop_start + for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + clipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped; + } + #pragma unroll_loop_end + if ( clipped ) discard; + #endif +#endif`,Bp=`#if NUM_CLIPPING_PLANES > 0 + varying vec3 vClipPosition; + uniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ]; +#endif`,zp=`#if NUM_CLIPPING_PLANES > 0 + varying vec3 vClipPosition; +#endif`,Vp=`#if NUM_CLIPPING_PLANES > 0 + vClipPosition = - mvPosition.xyz; +#endif`,kp=`#if defined( USE_COLOR_ALPHA ) + diffuseColor *= vColor; +#elif defined( USE_COLOR ) + diffuseColor.rgb *= vColor; +#endif`,Hp=`#if defined( USE_COLOR_ALPHA ) + varying vec4 vColor; +#elif defined( USE_COLOR ) + varying vec3 vColor; +#endif`,Gp=`#if defined( USE_COLOR_ALPHA ) + varying vec4 vColor; +#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) + varying vec3 vColor; +#endif`,Wp=`#if defined( USE_COLOR_ALPHA ) + vColor = vec4( 1.0 ); +#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) + vColor = vec3( 1.0 ); +#endif +#ifdef USE_COLOR + vColor *= color; +#endif +#ifdef USE_INSTANCING_COLOR + vColor.xyz *= instanceColor.xyz; +#endif`,Xp=`#define PI 3.141592653589793 +#define PI2 6.283185307179586 +#define PI_HALF 1.5707963267948966 +#define RECIPROCAL_PI 0.3183098861837907 +#define RECIPROCAL_PI2 0.15915494309189535 +#define EPSILON 1e-6 +#ifndef saturate +#define saturate( a ) clamp( a, 0.0, 1.0 ) +#endif +#define whiteComplement( a ) ( 1.0 - saturate( a ) ) +float pow2( const in float x ) { return x*x; } +vec3 pow2( const in vec3 x ) { return x*x; } +float pow3( const in float x ) { return x*x*x; } +float pow4( const in float x ) { float x2 = x*x; return x2*x2; } +float max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); } +float average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); } +highp float rand( const in vec2 uv ) { + const highp float a = 12.9898, b = 78.233, c = 43758.5453; + highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); + return fract( sin( sn ) * c ); +} +#ifdef HIGH_PRECISION + float precisionSafeLength( vec3 v ) { return length( v ); } +#else + float precisionSafeLength( vec3 v ) { + float maxComponent = max3( abs( v ) ); + return length( v / maxComponent ) * maxComponent; + } +#endif +struct IncidentLight { + vec3 color; + vec3 direction; + bool visible; +}; +struct ReflectedLight { + vec3 directDiffuse; + vec3 directSpecular; + vec3 indirectDiffuse; + vec3 indirectSpecular; +}; +#ifdef USE_ALPHAHASH + varying vec3 vPosition; +#endif +vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); +} +vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) { + return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz ); +} +mat3 transposeMat3( const in mat3 m ) { + mat3 tmp; + tmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x ); + tmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y ); + tmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z ); + return tmp; +} +float luminance( const in vec3 rgb ) { + const vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 ); + return dot( weights, rgb ); +} +bool isPerspectiveMatrix( mat4 m ) { + return m[ 2 ][ 3 ] == - 1.0; +} +vec2 equirectUv( in vec3 dir ) { + float u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5; + float v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5; + return vec2( u, v ); +} +vec3 BRDF_Lambert( const in vec3 diffuseColor ) { + return RECIPROCAL_PI * diffuseColor; +} +vec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) { + float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); + return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); +} +float F_Schlick( const in float f0, const in float f90, const in float dotVH ) { + float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); + return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); +} // validated`,qp=`#ifdef ENVMAP_TYPE_CUBE_UV + #define cubeUV_minMipLevel 4.0 + #define cubeUV_minTileSize 16.0 + float getFace( vec3 direction ) { + vec3 absDirection = abs( direction ); + float face = - 1.0; + if ( absDirection.x > absDirection.z ) { + if ( absDirection.x > absDirection.y ) + face = direction.x > 0.0 ? 0.0 : 3.0; + else + face = direction.y > 0.0 ? 1.0 : 4.0; + } else { + if ( absDirection.z > absDirection.y ) + face = direction.z > 0.0 ? 2.0 : 5.0; + else + face = direction.y > 0.0 ? 1.0 : 4.0; + } + return face; + } + vec2 getUV( vec3 direction, float face ) { + vec2 uv; + if ( face == 0.0 ) { + uv = vec2( direction.z, direction.y ) / abs( direction.x ); + } else if ( face == 1.0 ) { + uv = vec2( - direction.x, - direction.z ) / abs( direction.y ); + } else if ( face == 2.0 ) { + uv = vec2( - direction.x, direction.y ) / abs( direction.z ); + } else if ( face == 3.0 ) { + uv = vec2( - direction.z, direction.y ) / abs( direction.x ); + } else if ( face == 4.0 ) { + uv = vec2( - direction.x, direction.z ) / abs( direction.y ); + } else { + uv = vec2( direction.x, direction.y ) / abs( direction.z ); + } + return 0.5 * ( uv + 1.0 ); + } + vec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) { + float face = getFace( direction ); + float filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 ); + mipInt = max( mipInt, cubeUV_minMipLevel ); + float faceSize = exp2( mipInt ); + highp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0; + if ( face > 2.0 ) { + uv.y += faceSize; + face -= 3.0; + } + uv.x += face * faceSize; + uv.x += filterInt * 3.0 * cubeUV_minTileSize; + uv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize ); + uv.x *= CUBEUV_TEXEL_WIDTH; + uv.y *= CUBEUV_TEXEL_HEIGHT; + #ifdef texture2DGradEXT + return texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb; + #else + return texture2D( envMap, uv ).rgb; + #endif + } + #define cubeUV_r0 1.0 + #define cubeUV_v0 0.339 + #define cubeUV_m0 - 2.0 + #define cubeUV_r1 0.8 + #define cubeUV_v1 0.276 + #define cubeUV_m1 - 1.0 + #define cubeUV_r4 0.4 + #define cubeUV_v4 0.046 + #define cubeUV_m4 2.0 + #define cubeUV_r5 0.305 + #define cubeUV_v5 0.016 + #define cubeUV_m5 3.0 + #define cubeUV_r6 0.21 + #define cubeUV_v6 0.0038 + #define cubeUV_m6 4.0 + float roughnessToMip( float roughness ) { + float mip = 0.0; + if ( roughness >= cubeUV_r1 ) { + mip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0; + } else if ( roughness >= cubeUV_r4 ) { + mip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1; + } else if ( roughness >= cubeUV_r5 ) { + mip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4; + } else if ( roughness >= cubeUV_r6 ) { + mip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5; + } else { + mip = - 2.0 * log2( 1.16 * roughness ); } + return mip; + } + vec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) { + float mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP ); + float mipF = fract( mip ); + float mipInt = floor( mip ); + vec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt ); + if ( mipF == 0.0 ) { + return vec4( color0, 1.0 ); + } else { + vec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 ); + return vec4( mix( color0, color1, mipF ), 1.0 ); + } + } +#endif`,Yp=`vec3 transformedNormal = objectNormal; +#ifdef USE_INSTANCING + mat3 m = mat3( instanceMatrix ); + transformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) ); + transformedNormal = m * transformedNormal; +#endif +transformedNormal = normalMatrix * transformedNormal; +#ifdef FLIP_SIDED + transformedNormal = - transformedNormal; +#endif +#ifdef USE_TANGENT + vec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz; + #ifdef FLIP_SIDED + transformedTangent = - transformedTangent; + #endif +#endif`,Zp=`#ifdef USE_DISPLACEMENTMAP + uniform sampler2D displacementMap; + uniform float displacementScale; + uniform float displacementBias; +#endif`,Jp=`#ifdef USE_DISPLACEMENTMAP + transformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias ); +#endif`,$p=`#ifdef USE_EMISSIVEMAP + vec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv ); + totalEmissiveRadiance *= emissiveColor.rgb; +#endif`,Kp=`#ifdef USE_EMISSIVEMAP + uniform sampler2D emissiveMap; +#endif`,Qp="gl_FragColor = linearToOutputTexel( gl_FragColor );",jp=` +const mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3( + vec3( 0.8224621, 0.177538, 0.0 ), + vec3( 0.0331941, 0.9668058, 0.0 ), + vec3( 0.0170827, 0.0723974, 0.9105199 ) +); +const mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3( + vec3( 1.2249401, - 0.2249404, 0.0 ), + vec3( - 0.0420569, 1.0420571, 0.0 ), + vec3( - 0.0196376, - 0.0786361, 1.0982735 ) +); +vec4 LinearSRGBToLinearDisplayP3( in vec4 value ) { + return vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a ); +} +vec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) { + return vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a ); +} +vec4 LinearTransferOETF( in vec4 value ) { + return value; +} +vec4 sRGBTransferOETF( in vec4 value ) { + return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); +} +vec4 LinearToLinear( in vec4 value ) { + return value; +} +vec4 LinearTosRGB( in vec4 value ) { + return sRGBTransferOETF( value ); +}`,em=`#ifdef USE_ENVMAP + #ifdef ENV_WORLDPOS + vec3 cameraToFrag; + if ( isOrthographic ) { + cameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) ); + } else { + cameraToFrag = normalize( vWorldPosition - cameraPosition ); + } + vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); + #ifdef ENVMAP_MODE_REFLECTION + vec3 reflectVec = reflect( cameraToFrag, worldNormal ); + #else + vec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio ); + #endif + #else + vec3 reflectVec = vReflect; + #endif + #ifdef ENVMAP_TYPE_CUBE + vec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) ); + #else + vec4 envColor = vec4( 0.0 ); + #endif + #ifdef ENVMAP_BLENDING_MULTIPLY + outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity ); + #elif defined( ENVMAP_BLENDING_MIX ) + outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity ); + #elif defined( ENVMAP_BLENDING_ADD ) + outgoingLight += envColor.xyz * specularStrength * reflectivity; + #endif +#endif`,tm=`#ifdef USE_ENVMAP + uniform float envMapIntensity; + uniform float flipEnvMap; + #ifdef ENVMAP_TYPE_CUBE + uniform samplerCube envMap; + #else + uniform sampler2D envMap; + #endif + +#endif`,nm=`#ifdef USE_ENVMAP + uniform float reflectivity; + #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) + #define ENV_WORLDPOS + #endif + #ifdef ENV_WORLDPOS + varying vec3 vWorldPosition; + uniform float refractionRatio; + #else + varying vec3 vReflect; + #endif +#endif`,im=`#ifdef USE_ENVMAP + #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) + #define ENV_WORLDPOS + #endif + #ifdef ENV_WORLDPOS + + varying vec3 vWorldPosition; + #else + varying vec3 vReflect; + uniform float refractionRatio; + #endif +#endif`,sm=`#ifdef USE_ENVMAP + #ifdef ENV_WORLDPOS + vWorldPosition = worldPosition.xyz; + #else + vec3 cameraToVertex; + if ( isOrthographic ) { + cameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) ); + } else { + cameraToVertex = normalize( worldPosition.xyz - cameraPosition ); + } + vec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); + #ifdef ENVMAP_MODE_REFLECTION + vReflect = reflect( cameraToVertex, worldNormal ); + #else + vReflect = refract( cameraToVertex, worldNormal, refractionRatio ); + #endif + #endif +#endif`,rm=`#ifdef USE_FOG + vFogDepth = - mvPosition.z; +#endif`,am=`#ifdef USE_FOG + varying float vFogDepth; +#endif`,om=`#ifdef USE_FOG + #ifdef FOG_EXP2 + float fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth ); + #else + float fogFactor = smoothstep( fogNear, fogFar, vFogDepth ); + #endif + gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor ); +#endif`,cm=`#ifdef USE_FOG + uniform vec3 fogColor; + varying float vFogDepth; + #ifdef FOG_EXP2 + uniform float fogDensity; + #else + uniform float fogNear; + uniform float fogFar; + #endif +#endif`,lm=`#ifdef USE_GRADIENTMAP + uniform sampler2D gradientMap; +#endif +vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { + float dotNL = dot( normal, lightDirection ); + vec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 ); + #ifdef USE_GRADIENTMAP + return vec3( texture2D( gradientMap, coord ).r ); + #else + vec2 fw = fwidth( coord ) * 0.5; + return mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) ); + #endif +}`,hm=`#ifdef USE_LIGHTMAP + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity; + reflectedLight.indirectDiffuse += lightMapIrradiance; +#endif`,um=`#ifdef USE_LIGHTMAP + uniform sampler2D lightMap; + uniform float lightMapIntensity; +#endif`,dm=`LambertMaterial material; +material.diffuseColor = diffuseColor.rgb; +material.specularStrength = specularStrength;`,fm=`varying vec3 vViewPosition; +struct LambertMaterial { + vec3 diffuseColor; + float specularStrength; +}; +void RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_Lambert +#define RE_IndirectDiffuse RE_IndirectDiffuse_Lambert`,pm=`uniform bool receiveShadow; +uniform vec3 ambientLightColor; +#if defined( USE_LIGHT_PROBES ) + uniform vec3 lightProbe[ 9 ]; +#endif +vec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) { + float x = normal.x, y = normal.y, z = normal.z; + vec3 result = shCoefficients[ 0 ] * 0.886227; + result += shCoefficients[ 1 ] * 2.0 * 0.511664 * y; + result += shCoefficients[ 2 ] * 2.0 * 0.511664 * z; + result += shCoefficients[ 3 ] * 2.0 * 0.511664 * x; + result += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y; + result += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z; + result += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 ); + result += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z; + result += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y ); + return result; +} +vec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) { + vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); + vec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe ); + return irradiance; +} +vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) { + vec3 irradiance = ambientLightColor; + return irradiance; +} +float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) { + #if defined ( LEGACY_LIGHTS ) + if ( cutoffDistance > 0.0 && decayExponent > 0.0 ) { + return pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent ); + } + return 1.0; + #else + float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 ); + if ( cutoffDistance > 0.0 ) { + distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) ); + } + return distanceFalloff; + #endif +} +float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) { + return smoothstep( coneCosine, penumbraCosine, angleCosine ); +} +#if NUM_DIR_LIGHTS > 0 + struct DirectionalLight { + vec3 direction; + vec3 color; + }; + uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ]; + void getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) { + light.color = directionalLight.color; + light.direction = directionalLight.direction; + light.visible = true; + } +#endif +#if NUM_POINT_LIGHTS > 0 + struct PointLight { + vec3 position; + vec3 color; + float distance; + float decay; + }; + uniform PointLight pointLights[ NUM_POINT_LIGHTS ]; + void getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) { + vec3 lVector = pointLight.position - geometryPosition; + light.direction = normalize( lVector ); + float lightDistance = length( lVector ); + light.color = pointLight.color; + light.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay ); + light.visible = ( light.color != vec3( 0.0 ) ); + } +#endif +#if NUM_SPOT_LIGHTS > 0 + struct SpotLight { + vec3 position; + vec3 direction; + vec3 color; + float distance; + float decay; + float coneCos; + float penumbraCos; + }; + uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ]; + void getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) { + vec3 lVector = spotLight.position - geometryPosition; + light.direction = normalize( lVector ); + float angleCos = dot( light.direction, spotLight.direction ); + float spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos ); + if ( spotAttenuation > 0.0 ) { + float lightDistance = length( lVector ); + light.color = spotLight.color * spotAttenuation; + light.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay ); + light.visible = ( light.color != vec3( 0.0 ) ); + } else { + light.color = vec3( 0.0 ); + light.visible = false; + } + } +#endif +#if NUM_RECT_AREA_LIGHTS > 0 + struct RectAreaLight { + vec3 color; + vec3 position; + vec3 halfWidth; + vec3 halfHeight; + }; + uniform sampler2D ltc_1; uniform sampler2D ltc_2; + uniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ]; +#endif +#if NUM_HEMI_LIGHTS > 0 + struct HemisphereLight { + vec3 direction; + vec3 skyColor; + vec3 groundColor; + }; + uniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ]; + vec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) { + float dotNL = dot( normal, hemiLight.direction ); + float hemiDiffuseWeight = 0.5 * dotNL + 0.5; + vec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight ); + return irradiance; + } +#endif`,mm=`#ifdef USE_ENVMAP + vec3 getIBLIrradiance( const in vec3 normal ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); + vec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 ); + return PI * envMapColor.rgb * envMapIntensity; + #else + return vec3( 0.0 ); + #endif + } + vec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 reflectVec = reflect( - viewDir, normal ); + reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) ); + reflectVec = inverseTransformDirection( reflectVec, viewMatrix ); + vec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness ); + return envMapColor.rgb * envMapIntensity; + #else + return vec3( 0.0 ); + #endif + } + #ifdef USE_ANISOTROPY + vec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 bentNormal = cross( bitangent, viewDir ); + bentNormal = normalize( cross( bentNormal, bitangent ) ); + bentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) ); + return getIBLRadiance( viewDir, bentNormal, roughness ); + #else + return vec3( 0.0 ); + #endif + } + #endif +#endif`,gm=`ToonMaterial material; +material.diffuseColor = diffuseColor.rgb;`,_m=`varying vec3 vViewPosition; +struct ToonMaterial { + vec3 diffuseColor; +}; +void RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { + vec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_Toon +#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon`,xm=`BlinnPhongMaterial material; +material.diffuseColor = diffuseColor.rgb; +material.specularColor = specular; +material.specularShininess = shininess; +material.specularStrength = specularStrength;`,vm=`varying vec3 vViewPosition; +struct BlinnPhongMaterial { + vec3 diffuseColor; + vec3 specularColor; + float specularShininess; + float specularStrength; +}; +void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); + reflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength; +} +void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_BlinnPhong +#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong`,ym=`PhysicalMaterial material; +material.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor ); +vec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) ); +float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z ); +material.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness; +material.roughness = min( material.roughness, 1.0 ); +#ifdef IOR + material.ior = ior; + #ifdef USE_SPECULAR + float specularIntensityFactor = specularIntensity; + vec3 specularColorFactor = specularColor; + #ifdef USE_SPECULAR_COLORMAP + specularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb; + #endif + #ifdef USE_SPECULAR_INTENSITYMAP + specularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a; + #endif + material.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor ); + #else + float specularIntensityFactor = 1.0; + vec3 specularColorFactor = vec3( 1.0 ); + material.specularF90 = 1.0; + #endif + material.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor ); +#else + material.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor ); + material.specularF90 = 1.0; +#endif +#ifdef USE_CLEARCOAT + material.clearcoat = clearcoat; + material.clearcoatRoughness = clearcoatRoughness; + material.clearcoatF0 = vec3( 0.04 ); + material.clearcoatF90 = 1.0; + #ifdef USE_CLEARCOATMAP + material.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x; + #endif + #ifdef USE_CLEARCOAT_ROUGHNESSMAP + material.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y; + #endif + material.clearcoat = saturate( material.clearcoat ); material.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 ); + material.clearcoatRoughness += geometryRoughness; + material.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 ); +#endif +#ifdef USE_IRIDESCENCE + material.iridescence = iridescence; + material.iridescenceIOR = iridescenceIOR; + #ifdef USE_IRIDESCENCEMAP + material.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r; + #endif + #ifdef USE_IRIDESCENCE_THICKNESSMAP + material.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum; + #else + material.iridescenceThickness = iridescenceThicknessMaximum; + #endif +#endif +#ifdef USE_SHEEN + material.sheenColor = sheenColor; + #ifdef USE_SHEEN_COLORMAP + material.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb; + #endif + material.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 ); + #ifdef USE_SHEEN_ROUGHNESSMAP + material.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a; + #endif +#endif +#ifdef USE_ANISOTROPY + #ifdef USE_ANISOTROPYMAP + mat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x ); + vec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb; + vec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b; + #else + vec2 anisotropyV = anisotropyVector; + #endif + material.anisotropy = length( anisotropyV ); + anisotropyV /= material.anisotropy; + material.anisotropy = saturate( material.anisotropy ); + material.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) ); + material.anisotropyT = tbn[ 0 ] * anisotropyV.x - tbn[ 1 ] * anisotropyV.y; + material.anisotropyB = tbn[ 1 ] * anisotropyV.x + tbn[ 0 ] * anisotropyV.y; +#endif`,Mm=`struct PhysicalMaterial { + vec3 diffuseColor; + float roughness; + vec3 specularColor; + float specularF90; + #ifdef USE_CLEARCOAT + float clearcoat; + float clearcoatRoughness; + vec3 clearcoatF0; + float clearcoatF90; + #endif + #ifdef USE_IRIDESCENCE + float iridescence; + float iridescenceIOR; + float iridescenceThickness; + vec3 iridescenceFresnel; + vec3 iridescenceF0; + #endif + #ifdef USE_SHEEN + vec3 sheenColor; + float sheenRoughness; + #endif + #ifdef IOR + float ior; + #endif + #ifdef USE_TRANSMISSION + float transmission; + float transmissionAlpha; + float thickness; + float attenuationDistance; + vec3 attenuationColor; + #endif + #ifdef USE_ANISOTROPY + float anisotropy; + float alphaT; + vec3 anisotropyT; + vec3 anisotropyB; + #endif +}; +vec3 clearcoatSpecular = vec3( 0.0 ); +vec3 sheenSpecular = vec3( 0.0 ); +vec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) { + float x = clamp( 1.0 - dotVH, 0.0, 1.0 ); + float x2 = x * x; + float x5 = clamp( x * x2 * x2, 0.0, 0.9999 ); + return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 ); +} +float V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) { + float a2 = pow2( alpha ); + float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) ); + float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) ); + return 0.5 / max( gv + gl, EPSILON ); +} +float D_GGX( const in float alpha, const in float dotNH ) { + float a2 = pow2( alpha ); + float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; + return RECIPROCAL_PI * a2 / pow2( denom ); +} +#ifdef USE_ANISOTROPY + float V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) { + float gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) ); + float gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) ); + float v = 0.5 / ( gv + gl ); + return saturate(v); + } + float D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) { + float a2 = alphaT * alphaB; + highp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH ); + highp float v2 = dot( v, v ); + float w2 = a2 / v2; + return RECIPROCAL_PI * a2 * pow2 ( w2 ); + } +#endif +#ifdef USE_CLEARCOAT + vec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) { + vec3 f0 = material.clearcoatF0; + float f90 = material.clearcoatF90; + float roughness = material.clearcoatRoughness; + float alpha = pow2( roughness ); + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotVH = saturate( dot( viewDir, halfDir ) ); + vec3 F = F_Schlick( f0, f90, dotVH ); + float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + float D = D_GGX( alpha, dotNH ); + return F * ( V * D ); + } +#endif +vec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) { + vec3 f0 = material.specularColor; + float f90 = material.specularF90; + float roughness = material.roughness; + float alpha = pow2( roughness ); + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotVH = saturate( dot( viewDir, halfDir ) ); + vec3 F = F_Schlick( f0, f90, dotVH ); + #ifdef USE_IRIDESCENCE + F = mix( F, material.iridescenceFresnel, material.iridescence ); + #endif + #ifdef USE_ANISOTROPY + float dotTL = dot( material.anisotropyT, lightDir ); + float dotTV = dot( material.anisotropyT, viewDir ); + float dotTH = dot( material.anisotropyT, halfDir ); + float dotBL = dot( material.anisotropyB, lightDir ); + float dotBV = dot( material.anisotropyB, viewDir ); + float dotBH = dot( material.anisotropyB, halfDir ); + float V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL ); + float D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH ); + #else + float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + float D = D_GGX( alpha, dotNH ); + #endif + return F * ( V * D ); +} +vec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) { + const float LUT_SIZE = 64.0; + const float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE; + const float LUT_BIAS = 0.5 / LUT_SIZE; + float dotNV = saturate( dot( N, V ) ); + vec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) ); + uv = uv * LUT_SCALE + LUT_BIAS; + return uv; +} +float LTC_ClippedSphereFormFactor( const in vec3 f ) { + float l = length( f ); + return max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 ); +} +vec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) { + float x = dot( v1, v2 ); + float y = abs( x ); + float a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y; + float b = 3.4175940 + ( 4.1616724 + y ) * y; + float v = a / b; + float theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v; + return cross( v1, v2 ) * theta_sintheta; +} +vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) { + vec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ]; + vec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ]; + vec3 lightNormal = cross( v1, v2 ); + if( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 ); + vec3 T1, T2; + T1 = normalize( V - N * dot( V, N ) ); + T2 = - cross( N, T1 ); + mat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) ); + vec3 coords[ 4 ]; + coords[ 0 ] = mat * ( rectCoords[ 0 ] - P ); + coords[ 1 ] = mat * ( rectCoords[ 1 ] - P ); + coords[ 2 ] = mat * ( rectCoords[ 2 ] - P ); + coords[ 3 ] = mat * ( rectCoords[ 3 ] - P ); + coords[ 0 ] = normalize( coords[ 0 ] ); + coords[ 1 ] = normalize( coords[ 1 ] ); + coords[ 2 ] = normalize( coords[ 2 ] ); + coords[ 3 ] = normalize( coords[ 3 ] ); + vec3 vectorFormFactor = vec3( 0.0 ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] ); + float result = LTC_ClippedSphereFormFactor( vectorFormFactor ); + return vec3( result ); +} +#if defined( USE_SHEEN ) +float D_Charlie( float roughness, float dotNH ) { + float alpha = pow2( roughness ); + float invAlpha = 1.0 / alpha; + float cos2h = dotNH * dotNH; + float sin2h = max( 1.0 - cos2h, 0.0078125 ); + return ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI ); +} +float V_Neubelt( float dotNV, float dotNL ) { + return saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) ); +} +vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) { + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float D = D_Charlie( sheenRoughness, dotNH ); + float V = V_Neubelt( dotNV, dotNL ); + return sheenColor * ( D * V ); +} +#endif +float IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { + float dotNV = saturate( dot( normal, viewDir ) ); + float r2 = roughness * roughness; + float a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95; + float b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72; + float DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) ); + return saturate( DG * RECIPROCAL_PI ); +} +vec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { + float dotNV = saturate( dot( normal, viewDir ) ); + const vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); + const vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); + vec4 r = roughness * c0 + c1; + float a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y; + vec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw; + return fab; +} +vec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) { + vec2 fab = DFGApprox( normal, viewDir, roughness ); + return specularColor * fab.x + specularF90 * fab.y; +} +#ifdef USE_IRIDESCENCE +void computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) { +#else +void computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) { +#endif + vec2 fab = DFGApprox( normal, viewDir, roughness ); + #ifdef USE_IRIDESCENCE + vec3 Fr = mix( specularColor, iridescenceF0, iridescence ); + #else + vec3 Fr = specularColor; + #endif + vec3 FssEss = Fr * fab.x + specularF90 * fab.y; + float Ess = fab.x + fab.y; + float Ems = 1.0 - Ess; + vec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619; vec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg ); + singleScatter += FssEss; + multiScatter += Fms * Ems; +} +#if NUM_RECT_AREA_LIGHTS > 0 + void RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + vec3 normal = geometryNormal; + vec3 viewDir = geometryViewDir; + vec3 position = geometryPosition; + vec3 lightPos = rectAreaLight.position; + vec3 halfWidth = rectAreaLight.halfWidth; + vec3 halfHeight = rectAreaLight.halfHeight; + vec3 lightColor = rectAreaLight.color; + float roughness = material.roughness; + vec3 rectCoords[ 4 ]; + rectCoords[ 0 ] = lightPos + halfWidth - halfHeight; rectCoords[ 1 ] = lightPos - halfWidth - halfHeight; + rectCoords[ 2 ] = lightPos - halfWidth + halfHeight; + rectCoords[ 3 ] = lightPos + halfWidth + halfHeight; + vec2 uv = LTC_Uv( normal, viewDir, roughness ); + vec4 t1 = texture2D( ltc_1, uv ); + vec4 t2 = texture2D( ltc_2, uv ); + mat3 mInv = mat3( + vec3( t1.x, 0, t1.y ), + vec3( 0, 1, 0 ), + vec3( t1.z, 0, t1.w ) + ); + vec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y ); + reflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords ); + reflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords ); + } +#endif +void RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + #ifdef USE_CLEARCOAT + float dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) ); + vec3 ccIrradiance = dotNLcc * directLight.color; + clearcoatSpecular += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material ); + #endif + #ifdef USE_SHEEN + sheenSpecular += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness ); + #endif + reflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material ); + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { + #ifdef USE_CLEARCOAT + clearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness ); + #endif + #ifdef USE_SHEEN + sheenSpecular += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ); + #endif + vec3 singleScattering = vec3( 0.0 ); + vec3 multiScattering = vec3( 0.0 ); + vec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI; + #ifdef USE_IRIDESCENCE + computeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering ); + #else + computeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering ); + #endif + vec3 totalScattering = singleScattering + multiScattering; + vec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) ); + reflectedLight.indirectSpecular += radiance * singleScattering; + reflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance; + reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance; +} +#define RE_Direct RE_Direct_Physical +#define RE_Direct_RectArea RE_Direct_RectArea_Physical +#define RE_IndirectDiffuse RE_IndirectDiffuse_Physical +#define RE_IndirectSpecular RE_IndirectSpecular_Physical +float computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) { + return saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion ); +}`,Sm=` +vec3 geometryPosition = - vViewPosition; +vec3 geometryNormal = normal; +vec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition ); +vec3 geometryClearcoatNormal; +#ifdef USE_CLEARCOAT + geometryClearcoatNormal = clearcoatNormal; +#endif +#ifdef USE_IRIDESCENCE + float dotNVi = saturate( dot( normal, geometryViewDir ) ); + if ( material.iridescenceThickness == 0.0 ) { + material.iridescence = 0.0; + } else { + material.iridescence = saturate( material.iridescence ); + } + if ( material.iridescence > 0.0 ) { + material.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor ); + material.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi ); + } +#endif +IncidentLight directLight; +#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct ) + PointLight pointLight; + #if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0 + PointLightShadow pointLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) { + pointLight = pointLights[ i ]; + getPointLightInfo( pointLight, geometryPosition, directLight ); + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS ) + pointLightShadow = pointLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct ) + SpotLight spotLight; + vec4 spotColor; + vec3 spotLightCoord; + bool inSpotLightMap; + #if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0 + SpotLightShadow spotLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) { + spotLight = spotLights[ i ]; + getSpotLightInfo( spotLight, geometryPosition, directLight ); + #if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) + #define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX + #elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + #define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS + #else + #define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) + #endif + #if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS ) + spotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w; + inSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) ); + spotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy ); + directLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color; + #endif + #undef SPOT_LIGHT_MAP_INDEX + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + spotLightShadow = spotLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct ) + DirectionalLight directionalLight; + #if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0 + DirectionalLightShadow directionalLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) { + directionalLight = directionalLights[ i ]; + getDirectionalLightInfo( directionalLight, directLight ); + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS ) + directionalLightShadow = directionalLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea ) + RectAreaLight rectAreaLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) { + rectAreaLight = rectAreaLights[ i ]; + RE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if defined( RE_IndirectDiffuse ) + vec3 iblIrradiance = vec3( 0.0 ); + vec3 irradiance = getAmbientLightIrradiance( ambientLightColor ); + #if defined( USE_LIGHT_PROBES ) + irradiance += getLightProbeIrradiance( lightProbe, geometryNormal ); + #endif + #if ( NUM_HEMI_LIGHTS > 0 ) + #pragma unroll_loop_start + for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) { + irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal ); + } + #pragma unroll_loop_end + #endif +#endif +#if defined( RE_IndirectSpecular ) + vec3 radiance = vec3( 0.0 ); + vec3 clearcoatRadiance = vec3( 0.0 ); +#endif`,bm=`#if defined( RE_IndirectDiffuse ) + #ifdef USE_LIGHTMAP + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity; + irradiance += lightMapIrradiance; + #endif + #if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV ) + iblIrradiance += getIBLIrradiance( geometryNormal ); + #endif +#endif +#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular ) + #ifdef USE_ANISOTROPY + radiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy ); + #else + radiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness ); + #endif + #ifdef USE_CLEARCOAT + clearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness ); + #endif +#endif`,Em=`#if defined( RE_IndirectDiffuse ) + RE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); +#endif +#if defined( RE_IndirectSpecular ) + RE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); +#endif`,Tm=`#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT ) + gl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5; +#endif`,wm=`#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT ) + uniform float logDepthBufFC; + varying float vFragDepth; + varying float vIsPerspective; +#endif`,Am=`#ifdef USE_LOGDEPTHBUF + #ifdef USE_LOGDEPTHBUF_EXT + varying float vFragDepth; + varying float vIsPerspective; + #else + uniform float logDepthBufFC; + #endif +#endif`,Rm=`#ifdef USE_LOGDEPTHBUF + #ifdef USE_LOGDEPTHBUF_EXT + vFragDepth = 1.0 + gl_Position.w; + vIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) ); + #else + if ( isPerspectiveMatrix( projectionMatrix ) ) { + gl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0; + gl_Position.z *= gl_Position.w; + } + #endif +#endif`,Cm=`#ifdef USE_MAP + vec4 sampledDiffuseColor = texture2D( map, vMapUv ); + #ifdef DECODE_VIDEO_TEXTURE + sampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w ); + + #endif + diffuseColor *= sampledDiffuseColor; +#endif`,Pm=`#ifdef USE_MAP + uniform sampler2D map; +#endif`,Lm=`#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) + #if defined( USE_POINTS_UV ) + vec2 uv = vUv; + #else + vec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy; + #endif +#endif +#ifdef USE_MAP + diffuseColor *= texture2D( map, uv ); +#endif +#ifdef USE_ALPHAMAP + diffuseColor.a *= texture2D( alphaMap, uv ).g; +#endif`,Im=`#if defined( USE_POINTS_UV ) + varying vec2 vUv; +#else + #if defined( USE_MAP ) || defined( USE_ALPHAMAP ) + uniform mat3 uvTransform; + #endif +#endif +#ifdef USE_MAP + uniform sampler2D map; +#endif +#ifdef USE_ALPHAMAP + uniform sampler2D alphaMap; +#endif`,Um=`float metalnessFactor = metalness; +#ifdef USE_METALNESSMAP + vec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv ); + metalnessFactor *= texelMetalness.b; +#endif`,Dm=`#ifdef USE_METALNESSMAP + uniform sampler2D metalnessMap; +#endif`,Nm=`#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE ) + vColor *= morphTargetBaseInfluence; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + #if defined( USE_COLOR_ALPHA ) + if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ]; + #elif defined( USE_COLOR ) + if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ]; + #endif + } +#endif`,Om=`#ifdef USE_MORPHNORMALS + objectNormal *= morphTargetBaseInfluence; + #ifdef MORPHTARGETS_TEXTURE + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + if ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ]; + } + #else + objectNormal += morphNormal0 * morphTargetInfluences[ 0 ]; + objectNormal += morphNormal1 * morphTargetInfluences[ 1 ]; + objectNormal += morphNormal2 * morphTargetInfluences[ 2 ]; + objectNormal += morphNormal3 * morphTargetInfluences[ 3 ]; + #endif +#endif`,Fm=`#ifdef USE_MORPHTARGETS + uniform float morphTargetBaseInfluence; + #ifdef MORPHTARGETS_TEXTURE + uniform float morphTargetInfluences[ MORPHTARGETS_COUNT ]; + uniform sampler2DArray morphTargetsTexture; + uniform ivec2 morphTargetsTextureSize; + vec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) { + int texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset; + int y = texelIndex / morphTargetsTextureSize.x; + int x = texelIndex - y * morphTargetsTextureSize.x; + ivec3 morphUV = ivec3( x, y, morphTargetIndex ); + return texelFetch( morphTargetsTexture, morphUV, 0 ); + } + #else + #ifndef USE_MORPHNORMALS + uniform float morphTargetInfluences[ 8 ]; + #else + uniform float morphTargetInfluences[ 4 ]; + #endif + #endif +#endif`,Bm=`#ifdef USE_MORPHTARGETS + transformed *= morphTargetBaseInfluence; + #ifdef MORPHTARGETS_TEXTURE + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + if ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ]; + } + #else + transformed += morphTarget0 * morphTargetInfluences[ 0 ]; + transformed += morphTarget1 * morphTargetInfluences[ 1 ]; + transformed += morphTarget2 * morphTargetInfluences[ 2 ]; + transformed += morphTarget3 * morphTargetInfluences[ 3 ]; + #ifndef USE_MORPHNORMALS + transformed += morphTarget4 * morphTargetInfluences[ 4 ]; + transformed += morphTarget5 * morphTargetInfluences[ 5 ]; + transformed += morphTarget6 * morphTargetInfluences[ 6 ]; + transformed += morphTarget7 * morphTargetInfluences[ 7 ]; + #endif + #endif +#endif`,zm=`float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; +#ifdef FLAT_SHADED + vec3 fdx = dFdx( vViewPosition ); + vec3 fdy = dFdy( vViewPosition ); + vec3 normal = normalize( cross( fdx, fdy ) ); +#else + vec3 normal = normalize( vNormal ); + #ifdef DOUBLE_SIDED + normal *= faceDirection; + #endif +#endif +#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) + #ifdef USE_TANGENT + mat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); + #else + mat3 tbn = getTangentFrame( - vViewPosition, normal, + #if defined( USE_NORMALMAP ) + vNormalMapUv + #elif defined( USE_CLEARCOAT_NORMALMAP ) + vClearcoatNormalMapUv + #else + vUv + #endif + ); + #endif + #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED ) + tbn[0] *= faceDirection; + tbn[1] *= faceDirection; + #endif +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + #ifdef USE_TANGENT + mat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); + #else + mat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv ); + #endif + #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED ) + tbn2[0] *= faceDirection; + tbn2[1] *= faceDirection; + #endif +#endif +vec3 nonPerturbedNormal = normal;`,Vm=`#ifdef USE_NORMALMAP_OBJECTSPACE + normal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; + #ifdef FLIP_SIDED + normal = - normal; + #endif + #ifdef DOUBLE_SIDED + normal = normal * faceDirection; + #endif + normal = normalize( normalMatrix * normal ); +#elif defined( USE_NORMALMAP_TANGENTSPACE ) + vec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; + mapN.xy *= normalScale; + normal = normalize( tbn * mapN ); +#elif defined( USE_BUMPMAP ) + normal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection ); +#endif`,km=`#ifndef FLAT_SHADED + varying vec3 vNormal; + #ifdef USE_TANGENT + varying vec3 vTangent; + varying vec3 vBitangent; + #endif +#endif`,Hm=`#ifndef FLAT_SHADED + varying vec3 vNormal; + #ifdef USE_TANGENT + varying vec3 vTangent; + varying vec3 vBitangent; + #endif +#endif`,Gm=`#ifndef FLAT_SHADED + vNormal = normalize( transformedNormal ); + #ifdef USE_TANGENT + vTangent = normalize( transformedTangent ); + vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); + #endif +#endif`,Wm=`#ifdef USE_NORMALMAP + uniform sampler2D normalMap; + uniform vec2 normalScale; +#endif +#ifdef USE_NORMALMAP_OBJECTSPACE + uniform mat3 normalMatrix; +#endif +#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) ) + mat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) { + vec3 q0 = dFdx( eye_pos.xyz ); + vec3 q1 = dFdy( eye_pos.xyz ); + vec2 st0 = dFdx( uv.st ); + vec2 st1 = dFdy( uv.st ); + vec3 N = surf_norm; + vec3 q1perp = cross( q1, N ); + vec3 q0perp = cross( N, q0 ); + vec3 T = q1perp * st0.x + q0perp * st1.x; + vec3 B = q1perp * st0.y + q0perp * st1.y; + float det = max( dot( T, T ), dot( B, B ) ); + float scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det ); + return mat3( T * scale, B * scale, N ); + } +#endif`,Xm=`#ifdef USE_CLEARCOAT + vec3 clearcoatNormal = nonPerturbedNormal; +#endif`,qm=`#ifdef USE_CLEARCOAT_NORMALMAP + vec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0; + clearcoatMapN.xy *= clearcoatNormalScale; + clearcoatNormal = normalize( tbn2 * clearcoatMapN ); +#endif`,Ym=`#ifdef USE_CLEARCOATMAP + uniform sampler2D clearcoatMap; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + uniform sampler2D clearcoatNormalMap; + uniform vec2 clearcoatNormalScale; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + uniform sampler2D clearcoatRoughnessMap; +#endif`,Zm=`#ifdef USE_IRIDESCENCEMAP + uniform sampler2D iridescenceMap; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + uniform sampler2D iridescenceThicknessMap; +#endif`,Jm=`#ifdef OPAQUE +diffuseColor.a = 1.0; +#endif +#ifdef USE_TRANSMISSION +diffuseColor.a *= material.transmissionAlpha; +#endif +gl_FragColor = vec4( outgoingLight, diffuseColor.a );`,$m=`vec3 packNormalToRGB( const in vec3 normal ) { + return normalize( normal ) * 0.5 + 0.5; +} +vec3 unpackRGBToNormal( const in vec3 rgb ) { + return 2.0 * rgb.xyz - 1.0; +} +const float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.; +const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. ); +const vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. ); +const float ShiftRight8 = 1. / 256.; +vec4 packDepthToRGBA( const in float v ) { + vec4 r = vec4( fract( v * PackFactors ), v ); + r.yzw -= r.xyz * ShiftRight8; return r * PackUpscale; +} +float unpackRGBAToDepth( const in vec4 v ) { + return dot( v, UnpackFactors ); +} +vec2 packDepthToRG( in highp float v ) { + return packDepthToRGBA( v ).yx; +} +float unpackRGToDepth( const in highp vec2 v ) { + return unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) ); +} +vec4 pack2HalfToRGBA( vec2 v ) { + vec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) ); + return vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w ); +} +vec2 unpackRGBATo2Half( vec4 v ) { + return vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) ); +} +float viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) { + return ( viewZ + near ) / ( near - far ); +} +float orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) { + return depth * ( near - far ) - near; +} +float viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) { + return ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ ); +} +float perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) { + return ( near * far ) / ( ( far - near ) * depth - far ); +}`,Km=`#ifdef PREMULTIPLIED_ALPHA + gl_FragColor.rgb *= gl_FragColor.a; +#endif`,Qm=`vec4 mvPosition = vec4( transformed, 1.0 ); +#ifdef USE_INSTANCING + mvPosition = instanceMatrix * mvPosition; +#endif +mvPosition = modelViewMatrix * mvPosition; +gl_Position = projectionMatrix * mvPosition;`,jm=`#ifdef DITHERING + gl_FragColor.rgb = dithering( gl_FragColor.rgb ); +#endif`,eg=`#ifdef DITHERING + vec3 dithering( vec3 color ) { + float grid_position = rand( gl_FragCoord.xy ); + vec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 ); + dither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position ); + return color + dither_shift_RGB; + } +#endif`,tg=`float roughnessFactor = roughness; +#ifdef USE_ROUGHNESSMAP + vec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv ); + roughnessFactor *= texelRoughness.g; +#endif`,ng=`#ifdef USE_ROUGHNESSMAP + uniform sampler2D roughnessMap; +#endif`,ig=`#if NUM_SPOT_LIGHT_COORDS > 0 + varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; +#endif +#if NUM_SPOT_LIGHT_MAPS > 0 + uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ]; +#endif +#ifdef USE_SHADOWMAP + #if NUM_DIR_LIGHT_SHADOWS > 0 + uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ]; + varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; + struct DirectionalLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ]; + struct SpotLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + uniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ]; + varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; + struct PointLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + float shadowCameraNear; + float shadowCameraFar; + }; + uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; + #endif + float texture2DCompare( sampler2D depths, vec2 uv, float compare ) { + return step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) ); + } + vec2 texture2DDistribution( sampler2D shadow, vec2 uv ) { + return unpackRGBATo2Half( texture2D( shadow, uv ) ); + } + float VSMShadow (sampler2D shadow, vec2 uv, float compare ){ + float occlusion = 1.0; + vec2 distribution = texture2DDistribution( shadow, uv ); + float hard_shadow = step( compare , distribution.x ); + if (hard_shadow != 1.0 ) { + float distance = compare - distribution.x ; + float variance = max( 0.00000, distribution.y * distribution.y ); + float softness_probability = variance / (variance + distance * distance ); softness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 ); occlusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 ); + } + return occlusion; + } + float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) { + float shadow = 1.0; + shadowCoord.xyz /= shadowCoord.w; + shadowCoord.z += shadowBias; + bool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0; + bool frustumTest = inFrustum && shadowCoord.z <= 1.0; + if ( frustumTest ) { + #if defined( SHADOWMAP_TYPE_PCF ) + vec2 texelSize = vec2( 1.0 ) / shadowMapSize; + float dx0 = - texelSize.x * shadowRadius; + float dy0 = - texelSize.y * shadowRadius; + float dx1 = + texelSize.x * shadowRadius; + float dy1 = + texelSize.y * shadowRadius; + float dx2 = dx0 / 2.0; + float dy2 = dy0 / 2.0; + float dx3 = dx1 / 2.0; + float dy3 = dy1 / 2.0; + shadow = ( + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z ) + ) * ( 1.0 / 17.0 ); + #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) + vec2 texelSize = vec2( 1.0 ) / shadowMapSize; + float dx = texelSize.x; + float dy = texelSize.y; + vec2 uv = shadowCoord.xy; + vec2 f = fract( uv * shadowMapSize + 0.5 ); + uv -= f * texelSize; + shadow = ( + texture2DCompare( shadowMap, uv, shadowCoord.z ) + + texture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) + + texture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) + + mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ), + f.x ) + + mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ), + f.x ) + + mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ), + f.y ) + + mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ), + f.y ) + + mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ), + f.x ), + mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ), + f.x ), + f.y ) + ) * ( 1.0 / 9.0 ); + #elif defined( SHADOWMAP_TYPE_VSM ) + shadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z ); + #else + shadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ); + #endif + } + return shadow; + } + vec2 cubeToUV( vec3 v, float texelSizeY ) { + vec3 absV = abs( v ); + float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) ); + absV *= scaleToCube; + v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY ); + vec2 planar = v.xy; + float almostATexel = 1.5 * texelSizeY; + float almostOne = 1.0 - almostATexel; + if ( absV.z >= almostOne ) { + if ( v.z > 0.0 ) + planar.x = 4.0 - v.x; + } else if ( absV.x >= almostOne ) { + float signX = sign( v.x ); + planar.x = v.z * signX + 2.0 * signX; + } else if ( absV.y >= almostOne ) { + float signY = sign( v.y ); + planar.x = v.x + 2.0 * signY + 2.0; + planar.y = v.z * signY - 2.0; + } + return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 ); + } + float getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) { + vec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) ); + vec3 lightToPosition = shadowCoord.xyz; + float dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear ); dp += shadowBias; + vec3 bd3D = normalize( lightToPosition ); + #if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM ) + vec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y; + return ( + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp ) + ) * ( 1.0 / 9.0 ); + #else + return texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ); + #endif + } +#endif`,sg=`#if NUM_SPOT_LIGHT_COORDS > 0 + uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ]; + varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; +#endif +#ifdef USE_SHADOWMAP + #if NUM_DIR_LIGHT_SHADOWS > 0 + uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ]; + varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; + struct DirectionalLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + struct SpotLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ]; + varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; + struct PointLightShadow { + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + float shadowCameraNear; + float shadowCameraFar; + }; + uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; + #endif +#endif`,rg=`#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 ) + vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); + vec4 shadowWorldPosition; +#endif +#if defined( USE_SHADOWMAP ) + #if NUM_DIR_LIGHT_SHADOWS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { + shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 ); + vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { + shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 ); + vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end + #endif +#endif +#if NUM_SPOT_LIGHT_COORDS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) { + shadowWorldPosition = worldPosition; + #if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + shadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias; + #endif + vSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end +#endif`,ag=`float getShadowMask() { + float shadow = 1.0; + #ifdef USE_SHADOWMAP + #if NUM_DIR_LIGHT_SHADOWS > 0 + DirectionalLightShadow directionalLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { + directionalLight = directionalLightShadows[ i ]; + shadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; + } + #pragma unroll_loop_end + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + SpotLightShadow spotLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) { + spotLight = spotLightShadows[ i ]; + shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; + } + #pragma unroll_loop_end + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + PointLightShadow pointLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { + pointLight = pointLightShadows[ i ]; + shadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0; + } + #pragma unroll_loop_end + #endif + #endif + return shadow; +}`,og=`#ifdef USE_SKINNING + mat4 boneMatX = getBoneMatrix( skinIndex.x ); + mat4 boneMatY = getBoneMatrix( skinIndex.y ); + mat4 boneMatZ = getBoneMatrix( skinIndex.z ); + mat4 boneMatW = getBoneMatrix( skinIndex.w ); +#endif`,cg=`#ifdef USE_SKINNING + uniform mat4 bindMatrix; + uniform mat4 bindMatrixInverse; + uniform highp sampler2D boneTexture; + uniform int boneTextureSize; + mat4 getBoneMatrix( const in float i ) { + float j = i * 4.0; + float x = mod( j, float( boneTextureSize ) ); + float y = floor( j / float( boneTextureSize ) ); + float dx = 1.0 / float( boneTextureSize ); + float dy = 1.0 / float( boneTextureSize ); + y = dy * ( y + 0.5 ); + vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) ); + vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) ); + vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) ); + vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) ); + mat4 bone = mat4( v1, v2, v3, v4 ); + return bone; + } +#endif`,lg=`#ifdef USE_SKINNING + vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 ); + vec4 skinned = vec4( 0.0 ); + skinned += boneMatX * skinVertex * skinWeight.x; + skinned += boneMatY * skinVertex * skinWeight.y; + skinned += boneMatZ * skinVertex * skinWeight.z; + skinned += boneMatW * skinVertex * skinWeight.w; + transformed = ( bindMatrixInverse * skinned ).xyz; +#endif`,hg=`#ifdef USE_SKINNING + mat4 skinMatrix = mat4( 0.0 ); + skinMatrix += skinWeight.x * boneMatX; + skinMatrix += skinWeight.y * boneMatY; + skinMatrix += skinWeight.z * boneMatZ; + skinMatrix += skinWeight.w * boneMatW; + skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix; + objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz; + #ifdef USE_TANGENT + objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz; + #endif +#endif`,ug=`float specularStrength; +#ifdef USE_SPECULARMAP + vec4 texelSpecular = texture2D( specularMap, vSpecularMapUv ); + specularStrength = texelSpecular.r; +#else + specularStrength = 1.0; +#endif`,dg=`#ifdef USE_SPECULARMAP + uniform sampler2D specularMap; +#endif`,fg=`#if defined( TONE_MAPPING ) + gl_FragColor.rgb = toneMapping( gl_FragColor.rgb ); +#endif`,pg=`#ifndef saturate +#define saturate( a ) clamp( a, 0.0, 1.0 ) +#endif +uniform float toneMappingExposure; +vec3 LinearToneMapping( vec3 color ) { + return saturate( toneMappingExposure * color ); +} +vec3 ReinhardToneMapping( vec3 color ) { + color *= toneMappingExposure; + return saturate( color / ( vec3( 1.0 ) + color ) ); +} +vec3 OptimizedCineonToneMapping( vec3 color ) { + color *= toneMappingExposure; + color = max( vec3( 0.0 ), color - 0.004 ); + return pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) ); +} +vec3 RRTAndODTFit( vec3 v ) { + vec3 a = v * ( v + 0.0245786 ) - 0.000090537; + vec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081; + return a / b; +} +vec3 ACESFilmicToneMapping( vec3 color ) { + const mat3 ACESInputMat = mat3( + vec3( 0.59719, 0.07600, 0.02840 ), vec3( 0.35458, 0.90834, 0.13383 ), + vec3( 0.04823, 0.01566, 0.83777 ) + ); + const mat3 ACESOutputMat = mat3( + vec3( 1.60475, -0.10208, -0.00327 ), vec3( -0.53108, 1.10813, -0.07276 ), + vec3( -0.07367, -0.00605, 1.07602 ) + ); + color *= toneMappingExposure / 0.6; + color = ACESInputMat * color; + color = RRTAndODTFit( color ); + color = ACESOutputMat * color; + return saturate( color ); +} +vec3 CustomToneMapping( vec3 color ) { return color; }`,mg=`#ifdef USE_TRANSMISSION + material.transmission = transmission; + material.transmissionAlpha = 1.0; + material.thickness = thickness; + material.attenuationDistance = attenuationDistance; + material.attenuationColor = attenuationColor; + #ifdef USE_TRANSMISSIONMAP + material.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r; + #endif + #ifdef USE_THICKNESSMAP + material.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g; + #endif + vec3 pos = vWorldPosition; + vec3 v = normalize( cameraPosition - pos ); + vec3 n = inverseTransformDirection( normal, viewMatrix ); + vec4 transmitted = getIBLVolumeRefraction( + n, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90, + pos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness, + material.attenuationColor, material.attenuationDistance ); + material.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission ); + totalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission ); +#endif`,gg=`#ifdef USE_TRANSMISSION + uniform float transmission; + uniform float thickness; + uniform float attenuationDistance; + uniform vec3 attenuationColor; + #ifdef USE_TRANSMISSIONMAP + uniform sampler2D transmissionMap; + #endif + #ifdef USE_THICKNESSMAP + uniform sampler2D thicknessMap; + #endif + uniform vec2 transmissionSamplerSize; + uniform sampler2D transmissionSamplerMap; + uniform mat4 modelMatrix; + uniform mat4 projectionMatrix; + varying vec3 vWorldPosition; + float w0( float a ) { + return ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 ); + } + float w1( float a ) { + return ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 ); + } + float w2( float a ){ + return ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 ); + } + float w3( float a ) { + return ( 1.0 / 6.0 ) * ( a * a * a ); + } + float g0( float a ) { + return w0( a ) + w1( a ); + } + float g1( float a ) { + return w2( a ) + w3( a ); + } + float h0( float a ) { + return - 1.0 + w1( a ) / ( w0( a ) + w1( a ) ); + } + float h1( float a ) { + return 1.0 + w3( a ) / ( w2( a ) + w3( a ) ); + } + vec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) { + uv = uv * texelSize.zw + 0.5; + vec2 iuv = floor( uv ); + vec2 fuv = fract( uv ); + float g0x = g0( fuv.x ); + float g1x = g1( fuv.x ); + float h0x = h0( fuv.x ); + float h1x = h1( fuv.x ); + float h0y = h0( fuv.y ); + float h1y = h1( fuv.y ); + vec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; + vec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; + vec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; + vec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; + return g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) + + g1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) ); + } + vec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) { + vec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) ); + vec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) ); + vec2 fLodSizeInv = 1.0 / fLodSize; + vec2 cLodSizeInv = 1.0 / cLodSize; + vec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) ); + vec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) ); + return mix( fSample, cSample, fract( lod ) ); + } + vec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) { + vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior ); + vec3 modelScale; + modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) ); + modelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) ); + modelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) ); + return normalize( refractionVector ) * thickness * modelScale; + } + float applyIorToRoughness( const in float roughness, const in float ior ) { + return roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 ); + } + vec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) { + float lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior ); + return textureBicubic( transmissionSamplerMap, fragCoord.xy, lod ); + } + vec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) { + if ( isinf( attenuationDistance ) ) { + return vec3( 1.0 ); + } else { + vec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance; + vec3 transmittance = exp( - attenuationCoefficient * transmissionDistance ); return transmittance; + } + } + vec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor, + const in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix, + const in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness, + const in vec3 attenuationColor, const in float attenuationDistance ) { + vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); + vec3 refractedRayExit = position + transmissionRay; + vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); + vec2 refractionCoords = ndcPos.xy / ndcPos.w; + refractionCoords += 1.0; + refractionCoords /= 2.0; + vec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior ); + vec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ); + vec3 attenuatedColor = transmittance * transmittedLight.rgb; + vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness ); + float transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0; + return vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor ); + } +#endif`,_g=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + varying vec2 vUv; +#endif +#ifdef USE_MAP + varying vec2 vMapUv; +#endif +#ifdef USE_ALPHAMAP + varying vec2 vAlphaMapUv; +#endif +#ifdef USE_LIGHTMAP + varying vec2 vLightMapUv; +#endif +#ifdef USE_AOMAP + varying vec2 vAoMapUv; +#endif +#ifdef USE_BUMPMAP + varying vec2 vBumpMapUv; +#endif +#ifdef USE_NORMALMAP + varying vec2 vNormalMapUv; +#endif +#ifdef USE_EMISSIVEMAP + varying vec2 vEmissiveMapUv; +#endif +#ifdef USE_METALNESSMAP + varying vec2 vMetalnessMapUv; +#endif +#ifdef USE_ROUGHNESSMAP + varying vec2 vRoughnessMapUv; +#endif +#ifdef USE_ANISOTROPYMAP + varying vec2 vAnisotropyMapUv; +#endif +#ifdef USE_CLEARCOATMAP + varying vec2 vClearcoatMapUv; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + varying vec2 vClearcoatNormalMapUv; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + varying vec2 vClearcoatRoughnessMapUv; +#endif +#ifdef USE_IRIDESCENCEMAP + varying vec2 vIridescenceMapUv; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + varying vec2 vIridescenceThicknessMapUv; +#endif +#ifdef USE_SHEEN_COLORMAP + varying vec2 vSheenColorMapUv; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + varying vec2 vSheenRoughnessMapUv; +#endif +#ifdef USE_SPECULARMAP + varying vec2 vSpecularMapUv; +#endif +#ifdef USE_SPECULAR_COLORMAP + varying vec2 vSpecularColorMapUv; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + varying vec2 vSpecularIntensityMapUv; +#endif +#ifdef USE_TRANSMISSIONMAP + uniform mat3 transmissionMapTransform; + varying vec2 vTransmissionMapUv; +#endif +#ifdef USE_THICKNESSMAP + uniform mat3 thicknessMapTransform; + varying vec2 vThicknessMapUv; +#endif`,xg=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + varying vec2 vUv; +#endif +#ifdef USE_MAP + uniform mat3 mapTransform; + varying vec2 vMapUv; +#endif +#ifdef USE_ALPHAMAP + uniform mat3 alphaMapTransform; + varying vec2 vAlphaMapUv; +#endif +#ifdef USE_LIGHTMAP + uniform mat3 lightMapTransform; + varying vec2 vLightMapUv; +#endif +#ifdef USE_AOMAP + uniform mat3 aoMapTransform; + varying vec2 vAoMapUv; +#endif +#ifdef USE_BUMPMAP + uniform mat3 bumpMapTransform; + varying vec2 vBumpMapUv; +#endif +#ifdef USE_NORMALMAP + uniform mat3 normalMapTransform; + varying vec2 vNormalMapUv; +#endif +#ifdef USE_DISPLACEMENTMAP + uniform mat3 displacementMapTransform; + varying vec2 vDisplacementMapUv; +#endif +#ifdef USE_EMISSIVEMAP + uniform mat3 emissiveMapTransform; + varying vec2 vEmissiveMapUv; +#endif +#ifdef USE_METALNESSMAP + uniform mat3 metalnessMapTransform; + varying vec2 vMetalnessMapUv; +#endif +#ifdef USE_ROUGHNESSMAP + uniform mat3 roughnessMapTransform; + varying vec2 vRoughnessMapUv; +#endif +#ifdef USE_ANISOTROPYMAP + uniform mat3 anisotropyMapTransform; + varying vec2 vAnisotropyMapUv; +#endif +#ifdef USE_CLEARCOATMAP + uniform mat3 clearcoatMapTransform; + varying vec2 vClearcoatMapUv; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + uniform mat3 clearcoatNormalMapTransform; + varying vec2 vClearcoatNormalMapUv; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + uniform mat3 clearcoatRoughnessMapTransform; + varying vec2 vClearcoatRoughnessMapUv; +#endif +#ifdef USE_SHEEN_COLORMAP + uniform mat3 sheenColorMapTransform; + varying vec2 vSheenColorMapUv; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + uniform mat3 sheenRoughnessMapTransform; + varying vec2 vSheenRoughnessMapUv; +#endif +#ifdef USE_IRIDESCENCEMAP + uniform mat3 iridescenceMapTransform; + varying vec2 vIridescenceMapUv; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + uniform mat3 iridescenceThicknessMapTransform; + varying vec2 vIridescenceThicknessMapUv; +#endif +#ifdef USE_SPECULARMAP + uniform mat3 specularMapTransform; + varying vec2 vSpecularMapUv; +#endif +#ifdef USE_SPECULAR_COLORMAP + uniform mat3 specularColorMapTransform; + varying vec2 vSpecularColorMapUv; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + uniform mat3 specularIntensityMapTransform; + varying vec2 vSpecularIntensityMapUv; +#endif +#ifdef USE_TRANSMISSIONMAP + uniform mat3 transmissionMapTransform; + varying vec2 vTransmissionMapUv; +#endif +#ifdef USE_THICKNESSMAP + uniform mat3 thicknessMapTransform; + varying vec2 vThicknessMapUv; +#endif`,vg=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + vUv = vec3( uv, 1 ).xy; +#endif +#ifdef USE_MAP + vMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ALPHAMAP + vAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_LIGHTMAP + vLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_AOMAP + vAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_BUMPMAP + vBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_NORMALMAP + vNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_DISPLACEMENTMAP + vDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_EMISSIVEMAP + vEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_METALNESSMAP + vMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ROUGHNESSMAP + vRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ANISOTROPYMAP + vAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOATMAP + vClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + vClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + vClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_IRIDESCENCEMAP + vIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + vIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SHEEN_COLORMAP + vSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + vSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULARMAP + vSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULAR_COLORMAP + vSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + vSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_TRANSMISSIONMAP + vTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_THICKNESSMAP + vThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy; +#endif`,yg=`#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0 + vec4 worldPosition = vec4( transformed, 1.0 ); + #ifdef USE_INSTANCING + worldPosition = instanceMatrix * worldPosition; + #endif + worldPosition = modelMatrix * worldPosition; +#endif`,Mg=`varying vec2 vUv; +uniform mat3 uvTransform; +void main() { + vUv = ( uvTransform * vec3( uv, 1 ) ).xy; + gl_Position = vec4( position.xy, 1.0, 1.0 ); +}`,Sg=`uniform sampler2D t2D; +uniform float backgroundIntensity; +varying vec2 vUv; +void main() { + vec4 texColor = texture2D( t2D, vUv ); + #ifdef DECODE_VIDEO_TEXTURE + texColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w ); + #endif + texColor.rgb *= backgroundIntensity; + gl_FragColor = texColor; + #include + #include +}`,bg=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include + gl_Position.z = gl_Position.w; +}`,Eg=`#ifdef ENVMAP_TYPE_CUBE + uniform samplerCube envMap; +#elif defined( ENVMAP_TYPE_CUBE_UV ) + uniform sampler2D envMap; +#endif +uniform float flipEnvMap; +uniform float backgroundBlurriness; +uniform float backgroundIntensity; +varying vec3 vWorldDirection; +#include +void main() { + #ifdef ENVMAP_TYPE_CUBE + vec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) ); + #elif defined( ENVMAP_TYPE_CUBE_UV ) + vec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness ); + #else + vec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 ); + #endif + texColor.rgb *= backgroundIntensity; + gl_FragColor = texColor; + #include + #include +}`,Tg=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include + gl_Position.z = gl_Position.w; +}`,wg=`uniform samplerCube tCube; +uniform float tFlip; +uniform float opacity; +varying vec3 vWorldDirection; +void main() { + vec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) ); + gl_FragColor = texColor; + gl_FragColor.a *= opacity; + #include + #include +}`,Ag=`#include +#include +#include +#include +#include +#include +#include +varying vec2 vHighPrecisionZW; +void main() { + #include + #include + #ifdef USE_DISPLACEMENTMAP + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + vHighPrecisionZW = gl_Position.zw; +}`,Rg=`#if DEPTH_PACKING == 3200 + uniform float opacity; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +varying vec2 vHighPrecisionZW; +void main() { + #include + vec4 diffuseColor = vec4( 1.0 ); + #if DEPTH_PACKING == 3200 + diffuseColor.a = opacity; + #endif + #include + #include + #include + #include + #include + float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5; + #if DEPTH_PACKING == 3200 + gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity ); + #elif DEPTH_PACKING == 3201 + gl_FragColor = packDepthToRGBA( fragCoordZ ); + #endif +}`,Cg=`#define DISTANCE +varying vec3 vWorldPosition; +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #ifdef USE_DISPLACEMENTMAP + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + vWorldPosition = worldPosition.xyz; +}`,Pg=`#define DISTANCE +uniform vec3 referencePosition; +uniform float nearDistance; +uniform float farDistance; +varying vec3 vWorldPosition; +#include +#include +#include +#include +#include +#include +#include +#include +void main () { + #include + vec4 diffuseColor = vec4( 1.0 ); + #include + #include + #include + #include + float dist = length( vWorldPosition - referencePosition ); + dist = ( dist - nearDistance ) / ( farDistance - nearDistance ); + dist = saturate( dist ); + gl_FragColor = packDepthToRGBA( dist ); +}`,Lg=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include +}`,Ig=`uniform sampler2D tEquirect; +varying vec3 vWorldDirection; +#include +void main() { + vec3 direction = normalize( vWorldDirection ); + vec2 sampleUV = equirectUv( direction ); + gl_FragColor = texture2D( tEquirect, sampleUV ); + #include + #include +}`,Ug=`uniform float scale; +attribute float lineDistance; +varying float vLineDistance; +#include +#include +#include +#include +#include +#include +#include +void main() { + vLineDistance = scale * lineDistance; + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,Dg=`uniform vec3 diffuse; +uniform float opacity; +uniform float dashSize; +uniform float totalSize; +varying float vLineDistance; +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + if ( mod( vLineDistance, totalSize ) > dashSize ) { + discard; + } + vec3 outgoingLight = vec3( 0.0 ); + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include + #include +}`,Ng=`#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #if defined ( USE_ENVMAP ) || defined ( USE_SKINNING ) + #include + #include + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,Og=`uniform vec3 diffuse; +uniform float opacity; +#ifndef FLAT_SHADED + varying vec3 vNormal; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + #include + #include + #include + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + #ifdef USE_LIGHTMAP + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + reflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI; + #else + reflectedLight.indirectDiffuse += vec3( 1.0 ); + #endif + #include + reflectedLight.indirectDiffuse *= diffuseColor.rgb; + vec3 outgoingLight = reflectedLight.indirectDiffuse; + #include + #include + #include + #include + #include + #include + #include +}`,Fg=`#define LAMBERT +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include + #include +}`,Bg=`#define LAMBERT +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + vec4 diffuseColor = vec4( diffuse, opacity ); + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include + #include +}`,zg=`#define MATCAP +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; +}`,Vg=`#define MATCAP +uniform vec3 diffuse; +uniform float opacity; +uniform sampler2D matcap; +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + #include + #include + #include + #include + #include + vec3 viewDir = normalize( vViewPosition ); + vec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) ); + vec3 y = cross( viewDir, x ); + vec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5; + #ifdef USE_MATCAP + vec4 matcapColor = texture2D( matcap, uv ); + #else + vec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 ); + #endif + vec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb; + #include + #include + #include + #include + #include + #include +}`,kg=`#define NORMAL +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + varying vec3 vViewPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + vViewPosition = - mvPosition.xyz; +#endif +}`,Hg=`#define NORMAL +uniform float opacity; +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + varying vec3 vViewPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + gl_FragColor = vec4( packNormalToRGB( normal ), opacity ); + #ifdef OPAQUE + gl_FragColor.a = 1.0; + #endif +}`,Gg=`#define PHONG +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include + #include +}`,Wg=`#define PHONG +uniform vec3 diffuse; +uniform vec3 emissive; +uniform vec3 specular; +uniform float shininess; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + vec4 diffuseColor = vec4( diffuse, opacity ); + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include + #include +}`,Xg=`#define STANDARD +varying vec3 vViewPosition; +#ifdef USE_TRANSMISSION + varying vec3 vWorldPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include +#ifdef USE_TRANSMISSION + vWorldPosition = worldPosition.xyz; +#endif +}`,qg=`#define STANDARD +#ifdef PHYSICAL + #define IOR + #define USE_SPECULAR +#endif +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float roughness; +uniform float metalness; +uniform float opacity; +#ifdef IOR + uniform float ior; +#endif +#ifdef USE_SPECULAR + uniform float specularIntensity; + uniform vec3 specularColor; + #ifdef USE_SPECULAR_COLORMAP + uniform sampler2D specularColorMap; + #endif + #ifdef USE_SPECULAR_INTENSITYMAP + uniform sampler2D specularIntensityMap; + #endif +#endif +#ifdef USE_CLEARCOAT + uniform float clearcoat; + uniform float clearcoatRoughness; +#endif +#ifdef USE_IRIDESCENCE + uniform float iridescence; + uniform float iridescenceIOR; + uniform float iridescenceThicknessMinimum; + uniform float iridescenceThicknessMaximum; +#endif +#ifdef USE_SHEEN + uniform vec3 sheenColor; + uniform float sheenRoughness; + #ifdef USE_SHEEN_COLORMAP + uniform sampler2D sheenColorMap; + #endif + #ifdef USE_SHEEN_ROUGHNESSMAP + uniform sampler2D sheenRoughnessMap; + #endif +#endif +#ifdef USE_ANISOTROPY + uniform vec2 anisotropyVector; + #ifdef USE_ANISOTROPYMAP + uniform sampler2D anisotropyMap; + #endif +#endif +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + vec4 diffuseColor = vec4( diffuse, opacity ); + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse; + vec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular; + #include + vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance; + #ifdef USE_SHEEN + float sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor ); + outgoingLight = outgoingLight * sheenEnergyComp + sheenSpecular; + #endif + #ifdef USE_CLEARCOAT + float dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) ); + vec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc ); + outgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + clearcoatSpecular * material.clearcoat; + #endif + #include + #include + #include + #include + #include + #include +}`,Yg=`#define TOON +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include +}`,Zg=`#define TOON +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + vec4 diffuseColor = vec4( diffuse, opacity ); + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include +}`,Jg=`uniform float size; +uniform float scale; +#include +#include +#include +#include +#include +#include +#ifdef USE_POINTS_UV + varying vec2 vUv; + uniform mat3 uvTransform; +#endif +void main() { + #ifdef USE_POINTS_UV + vUv = ( uvTransform * vec3( uv, 1 ) ).xy; + #endif + #include + #include + #include + #include + #include + gl_PointSize = size; + #ifdef USE_SIZEATTENUATION + bool isPerspective = isPerspectiveMatrix( projectionMatrix ); + if ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z ); + #endif + #include + #include + #include + #include +}`,$g=`uniform vec3 diffuse; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + vec3 outgoingLight = vec3( 0.0 ); + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include + #include +}`,Kg=`#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,Qg=`uniform vec3 color; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + gl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) ); + #include + #include + #include +}`,jg=`uniform float rotation; +uniform vec2 center; +#include +#include +#include +#include +#include +void main() { + #include + vec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 ); + vec2 scale; + scale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) ); + scale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) ); + #ifndef USE_SIZEATTENUATION + bool isPerspective = isPerspectiveMatrix( projectionMatrix ); + if ( isPerspective ) scale *= - mvPosition.z; + #endif + vec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale; + vec2 rotatedPosition; + rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y; + rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y; + mvPosition.xy += rotatedPosition; + gl_Position = projectionMatrix * mvPosition; + #include + #include + #include +}`,e_=`uniform vec3 diffuse; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + vec3 outgoingLight = vec3( 0.0 ); + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include +}`,ke={alphahash_fragment:Ep,alphahash_pars_fragment:Tp,alphamap_fragment:wp,alphamap_pars_fragment:Ap,alphatest_fragment:Rp,alphatest_pars_fragment:Cp,aomap_fragment:Pp,aomap_pars_fragment:Lp,begin_vertex:Ip,beginnormal_vertex:Up,bsdfs:Dp,iridescence_fragment:Np,bumpmap_pars_fragment:Op,clipping_planes_fragment:Fp,clipping_planes_pars_fragment:Bp,clipping_planes_pars_vertex:zp,clipping_planes_vertex:Vp,color_fragment:kp,color_pars_fragment:Hp,color_pars_vertex:Gp,color_vertex:Wp,common:Xp,cube_uv_reflection_fragment:qp,defaultnormal_vertex:Yp,displacementmap_pars_vertex:Zp,displacementmap_vertex:Jp,emissivemap_fragment:$p,emissivemap_pars_fragment:Kp,colorspace_fragment:Qp,colorspace_pars_fragment:jp,envmap_fragment:em,envmap_common_pars_fragment:tm,envmap_pars_fragment:nm,envmap_pars_vertex:im,envmap_physical_pars_fragment:mm,envmap_vertex:sm,fog_vertex:rm,fog_pars_vertex:am,fog_fragment:om,fog_pars_fragment:cm,gradientmap_pars_fragment:lm,lightmap_fragment:hm,lightmap_pars_fragment:um,lights_lambert_fragment:dm,lights_lambert_pars_fragment:fm,lights_pars_begin:pm,lights_toon_fragment:gm,lights_toon_pars_fragment:_m,lights_phong_fragment:xm,lights_phong_pars_fragment:vm,lights_physical_fragment:ym,lights_physical_pars_fragment:Mm,lights_fragment_begin:Sm,lights_fragment_maps:bm,lights_fragment_end:Em,logdepthbuf_fragment:Tm,logdepthbuf_pars_fragment:wm,logdepthbuf_pars_vertex:Am,logdepthbuf_vertex:Rm,map_fragment:Cm,map_pars_fragment:Pm,map_particle_fragment:Lm,map_particle_pars_fragment:Im,metalnessmap_fragment:Um,metalnessmap_pars_fragment:Dm,morphcolor_vertex:Nm,morphnormal_vertex:Om,morphtarget_pars_vertex:Fm,morphtarget_vertex:Bm,normal_fragment_begin:zm,normal_fragment_maps:Vm,normal_pars_fragment:km,normal_pars_vertex:Hm,normal_vertex:Gm,normalmap_pars_fragment:Wm,clearcoat_normal_fragment_begin:Xm,clearcoat_normal_fragment_maps:qm,clearcoat_pars_fragment:Ym,iridescence_pars_fragment:Zm,opaque_fragment:Jm,packing:$m,premultiplied_alpha_fragment:Km,project_vertex:Qm,dithering_fragment:jm,dithering_pars_fragment:eg,roughnessmap_fragment:tg,roughnessmap_pars_fragment:ng,shadowmap_pars_fragment:ig,shadowmap_pars_vertex:sg,shadowmap_vertex:rg,shadowmask_pars_fragment:ag,skinbase_vertex:og,skinning_pars_vertex:cg,skinning_vertex:lg,skinnormal_vertex:hg,specularmap_fragment:ug,specularmap_pars_fragment:dg,tonemapping_fragment:fg,tonemapping_pars_fragment:pg,transmission_fragment:mg,transmission_pars_fragment:gg,uv_pars_fragment:_g,uv_pars_vertex:xg,uv_vertex:vg,worldpos_vertex:yg,background_vert:Mg,background_frag:Sg,backgroundCube_vert:bg,backgroundCube_frag:Eg,cube_vert:Tg,cube_frag:wg,depth_vert:Ag,depth_frag:Rg,distanceRGBA_vert:Cg,distanceRGBA_frag:Pg,equirect_vert:Lg,equirect_frag:Ig,linedashed_vert:Ug,linedashed_frag:Dg,meshbasic_vert:Ng,meshbasic_frag:Og,meshlambert_vert:Fg,meshlambert_frag:Bg,meshmatcap_vert:zg,meshmatcap_frag:Vg,meshnormal_vert:kg,meshnormal_frag:Hg,meshphong_vert:Gg,meshphong_frag:Wg,meshphysical_vert:Xg,meshphysical_frag:qg,meshtoon_vert:Yg,meshtoon_frag:Zg,points_vert:Jg,points_frag:$g,shadow_vert:Kg,shadow_frag:Qg,sprite_vert:jg,sprite_frag:e_},le={common:{diffuse:{value:new pe(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new He},alphaMap:{value:null},alphaMapTransform:{value:new He},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new He}},envmap:{envMap:{value:null},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new He}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new He}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new He},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new He},normalScale:{value:new Z(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new He},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new He}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new He}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new He}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new pe(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotShadowMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new pe(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new He},alphaTest:{value:0},uvTransform:{value:new He}},sprite:{diffuse:{value:new pe(16777215)},opacity:{value:1},center:{value:new Z(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new He},alphaMap:{value:null},alphaMapTransform:{value:new He},alphaTest:{value:0}}},nn={basic:{uniforms:Lt([le.common,le.specularmap,le.envmap,le.aomap,le.lightmap,le.fog]),vertexShader:ke.meshbasic_vert,fragmentShader:ke.meshbasic_frag},lambert:{uniforms:Lt([le.common,le.specularmap,le.envmap,le.aomap,le.lightmap,le.emissivemap,le.bumpmap,le.normalmap,le.displacementmap,le.fog,le.lights,{emissive:{value:new pe(0)}}]),vertexShader:ke.meshlambert_vert,fragmentShader:ke.meshlambert_frag},phong:{uniforms:Lt([le.common,le.specularmap,le.envmap,le.aomap,le.lightmap,le.emissivemap,le.bumpmap,le.normalmap,le.displacementmap,le.fog,le.lights,{emissive:{value:new pe(0)},specular:{value:new pe(1118481)},shininess:{value:30}}]),vertexShader:ke.meshphong_vert,fragmentShader:ke.meshphong_frag},standard:{uniforms:Lt([le.common,le.envmap,le.aomap,le.lightmap,le.emissivemap,le.bumpmap,le.normalmap,le.displacementmap,le.roughnessmap,le.metalnessmap,le.fog,le.lights,{emissive:{value:new pe(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:ke.meshphysical_vert,fragmentShader:ke.meshphysical_frag},toon:{uniforms:Lt([le.common,le.aomap,le.lightmap,le.emissivemap,le.bumpmap,le.normalmap,le.displacementmap,le.gradientmap,le.fog,le.lights,{emissive:{value:new pe(0)}}]),vertexShader:ke.meshtoon_vert,fragmentShader:ke.meshtoon_frag},matcap:{uniforms:Lt([le.common,le.bumpmap,le.normalmap,le.displacementmap,le.fog,{matcap:{value:null}}]),vertexShader:ke.meshmatcap_vert,fragmentShader:ke.meshmatcap_frag},points:{uniforms:Lt([le.points,le.fog]),vertexShader:ke.points_vert,fragmentShader:ke.points_frag},dashed:{uniforms:Lt([le.common,le.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:ke.linedashed_vert,fragmentShader:ke.linedashed_frag},depth:{uniforms:Lt([le.common,le.displacementmap]),vertexShader:ke.depth_vert,fragmentShader:ke.depth_frag},normal:{uniforms:Lt([le.common,le.bumpmap,le.normalmap,le.displacementmap,{opacity:{value:1}}]),vertexShader:ke.meshnormal_vert,fragmentShader:ke.meshnormal_frag},sprite:{uniforms:Lt([le.sprite,le.fog]),vertexShader:ke.sprite_vert,fragmentShader:ke.sprite_frag},background:{uniforms:{uvTransform:{value:new He},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:ke.background_vert,fragmentShader:ke.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1}},vertexShader:ke.backgroundCube_vert,fragmentShader:ke.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:ke.cube_vert,fragmentShader:ke.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:ke.equirect_vert,fragmentShader:ke.equirect_frag},distanceRGBA:{uniforms:Lt([le.common,le.displacementmap,{referencePosition:{value:new A},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:ke.distanceRGBA_vert,fragmentShader:ke.distanceRGBA_frag},shadow:{uniforms:Lt([le.lights,le.fog,{color:{value:new pe(0)},opacity:{value:1}}]),vertexShader:ke.shadow_vert,fragmentShader:ke.shadow_frag}};nn.physical={uniforms:Lt([nn.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new He},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new He},clearcoatNormalScale:{value:new Z(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new He},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new He},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new He},sheen:{value:0},sheenColor:{value:new pe(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new He},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new He},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new He},transmissionSamplerSize:{value:new Z},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new He},attenuationDistance:{value:0},attenuationColor:{value:new pe(0)},specularColor:{value:new pe(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new He},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new He},anisotropyVector:{value:new Z},anisotropyMap:{value:null},anisotropyMapTransform:{value:new He}}]),vertexShader:ke.meshphysical_vert,fragmentShader:ke.meshphysical_frag};var cr={r:0,b:0,g:0};function t_(s,e,t,n,i,r,a){let o=new pe(0),c=r===!0?0:1,l,h,u=null,d=0,f=null;function m(g,p){let v=!1,x=p.isScene===!0?p.background:null;x&&x.isTexture&&(x=(p.backgroundBlurriness>0?t:e).get(x)),x===null?_(o,c):x&&x.isColor&&(_(x,1),v=!0);let y=s.xr.getEnvironmentBlendMode();y==="additive"?n.buffers.color.setClear(0,0,0,1,a):y==="alpha-blend"&&n.buffers.color.setClear(0,0,0,0,a),(s.autoClear||v)&&s.clear(s.autoClearColor,s.autoClearDepth,s.autoClearStencil),x&&(x.isCubeTexture||x.mapping===Vs)?(h===void 0&&(h=new Mt(new Ji(1,1,1),new jt({name:"BackgroundCubeMaterial",uniforms:$i(nn.backgroundCube.uniforms),vertexShader:nn.backgroundCube.vertexShader,fragmentShader:nn.backgroundCube.fragmentShader,side:Ft,depthTest:!1,depthWrite:!1,fog:!1})),h.geometry.deleteAttribute("normal"),h.geometry.deleteAttribute("uv"),h.onBeforeRender=function(b,w,R){this.matrixWorld.copyPosition(R.matrixWorld)},Object.defineProperty(h.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),i.update(h)),h.material.uniforms.envMap.value=x,h.material.uniforms.flipEnvMap.value=x.isCubeTexture&&x.isRenderTargetTexture===!1?-1:1,h.material.uniforms.backgroundBlurriness.value=p.backgroundBlurriness,h.material.uniforms.backgroundIntensity.value=p.backgroundIntensity,h.material.toneMapped=Qe.getTransfer(x.colorSpace)!==nt,(u!==x||d!==x.version||f!==s.toneMapping)&&(h.material.needsUpdate=!0,u=x,d=x.version,f=s.toneMapping),h.layers.enableAll(),g.unshift(h,h.geometry,h.material,0,0,null)):x&&x.isTexture&&(l===void 0&&(l=new Mt(new $r(2,2),new jt({name:"BackgroundMaterial",uniforms:$i(nn.background.uniforms),vertexShader:nn.background.vertexShader,fragmentShader:nn.background.fragmentShader,side:Bn,depthTest:!1,depthWrite:!1,fog:!1})),l.geometry.deleteAttribute("normal"),Object.defineProperty(l.material,"map",{get:function(){return this.uniforms.t2D.value}}),i.update(l)),l.material.uniforms.t2D.value=x,l.material.uniforms.backgroundIntensity.value=p.backgroundIntensity,l.material.toneMapped=Qe.getTransfer(x.colorSpace)!==nt,x.matrixAutoUpdate===!0&&x.updateMatrix(),l.material.uniforms.uvTransform.value.copy(x.matrix),(u!==x||d!==x.version||f!==s.toneMapping)&&(l.material.needsUpdate=!0,u=x,d=x.version,f=s.toneMapping),l.layers.enableAll(),g.unshift(l,l.geometry,l.material,0,0,null))}function _(g,p){g.getRGB(cr,bd(s)),n.buffers.color.setClear(cr.r,cr.g,cr.b,p,a)}return{getClearColor:function(){return o},setClearColor:function(g,p=1){o.set(g),c=p,_(o,c)},getClearAlpha:function(){return c},setClearAlpha:function(g){c=g,_(o,c)},render:m}}function n_(s,e,t,n){let i=s.getParameter(s.MAX_VERTEX_ATTRIBS),r=n.isWebGL2?null:e.get("OES_vertex_array_object"),a=n.isWebGL2||r!==null,o={},c=g(null),l=c,h=!1;function u(U,z,q,H,ne){let W=!1;if(a){let K=_(H,q,z);l!==K&&(l=K,f(l.object)),W=p(U,H,q,ne),W&&v(U,H,q,ne)}else{let K=z.wireframe===!0;(l.geometry!==H.id||l.program!==q.id||l.wireframe!==K)&&(l.geometry=H.id,l.program=q.id,l.wireframe=K,W=!0)}ne!==null&&t.update(ne,s.ELEMENT_ARRAY_BUFFER),(W||h)&&(h=!1,I(U,z,q,H),ne!==null&&s.bindBuffer(s.ELEMENT_ARRAY_BUFFER,t.get(ne).buffer))}function d(){return n.isWebGL2?s.createVertexArray():r.createVertexArrayOES()}function f(U){return n.isWebGL2?s.bindVertexArray(U):r.bindVertexArrayOES(U)}function m(U){return n.isWebGL2?s.deleteVertexArray(U):r.deleteVertexArrayOES(U)}function _(U,z,q){let H=q.wireframe===!0,ne=o[U.id];ne===void 0&&(ne={},o[U.id]=ne);let W=ne[z.id];W===void 0&&(W={},ne[z.id]=W);let K=W[H];return K===void 0&&(K=g(d()),W[H]=K),K}function g(U){let z=[],q=[],H=[];for(let ne=0;ne=0){let fe=ne[G],_e=W[G];if(_e===void 0&&(G==="instanceMatrix"&&U.instanceMatrix&&(_e=U.instanceMatrix),G==="instanceColor"&&U.instanceColor&&(_e=U.instanceColor)),fe===void 0||fe.attribute!==_e||_e&&fe.data!==_e.data)return!0;K++}return l.attributesNum!==K||l.index!==H}function v(U,z,q,H){let ne={},W=z.attributes,K=0,D=q.getAttributes();for(let G in D)if(D[G].location>=0){let fe=W[G];fe===void 0&&(G==="instanceMatrix"&&U.instanceMatrix&&(fe=U.instanceMatrix),G==="instanceColor"&&U.instanceColor&&(fe=U.instanceColor));let _e={};_e.attribute=fe,fe&&fe.data&&(_e.data=fe.data),ne[G]=_e,K++}l.attributes=ne,l.attributesNum=K,l.index=H}function x(){let U=l.newAttributes;for(let z=0,q=U.length;z=0){let he=ne[D];if(he===void 0&&(D==="instanceMatrix"&&U.instanceMatrix&&(he=U.instanceMatrix),D==="instanceColor"&&U.instanceColor&&(he=U.instanceColor)),he!==void 0){let fe=he.normalized,_e=he.itemSize,we=t.get(he);if(we===void 0)continue;let Ee=we.buffer,Te=we.type,Ye=we.bytesPerElement,it=n.isWebGL2===!0&&(Te===s.INT||Te===s.UNSIGNED_INT||he.gpuType===dd);if(he.isInterleavedBufferAttribute){let Ce=he.data,L=Ce.stride,oe=he.offset;if(Ce.isInstancedInterleavedBuffer){for(let X=0;X0&&s.getShaderPrecisionFormat(s.FRAGMENT_SHADER,s.HIGH_FLOAT).precision>0)return"highp";R="mediump"}return R==="mediump"&&s.getShaderPrecisionFormat(s.VERTEX_SHADER,s.MEDIUM_FLOAT).precision>0&&s.getShaderPrecisionFormat(s.FRAGMENT_SHADER,s.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let a=typeof WebGL2RenderingContext<"u"&&s.constructor.name==="WebGL2RenderingContext",o=t.precision!==void 0?t.precision:"highp",c=r(o);c!==o&&(console.warn("THREE.WebGLRenderer:",o,"not supported, using",c,"instead."),o=c);let l=a||e.has("WEBGL_draw_buffers"),h=t.logarithmicDepthBuffer===!0,u=s.getParameter(s.MAX_TEXTURE_IMAGE_UNITS),d=s.getParameter(s.MAX_VERTEX_TEXTURE_IMAGE_UNITS),f=s.getParameter(s.MAX_TEXTURE_SIZE),m=s.getParameter(s.MAX_CUBE_MAP_TEXTURE_SIZE),_=s.getParameter(s.MAX_VERTEX_ATTRIBS),g=s.getParameter(s.MAX_VERTEX_UNIFORM_VECTORS),p=s.getParameter(s.MAX_VARYING_VECTORS),v=s.getParameter(s.MAX_FRAGMENT_UNIFORM_VECTORS),x=d>0,y=a||e.has("OES_texture_float"),b=x&&y,w=a?s.getParameter(s.MAX_SAMPLES):0;return{isWebGL2:a,drawBuffers:l,getMaxAnisotropy:i,getMaxPrecision:r,precision:o,logarithmicDepthBuffer:h,maxTextures:u,maxVertexTextures:d,maxTextureSize:f,maxCubemapSize:m,maxAttributes:_,maxVertexUniforms:g,maxVaryings:p,maxFragmentUniforms:v,vertexTextures:x,floatFragmentTextures:y,floatVertexTextures:b,maxSamples:w}}function r_(s){let e=this,t=null,n=0,i=!1,r=!1,a=new mn,o=new He,c={value:null,needsUpdate:!1};this.uniform=c,this.numPlanes=0,this.numIntersection=0,this.init=function(u,d){let f=u.length!==0||d||n!==0||i;return i=d,n=u.length,f},this.beginShadows=function(){r=!0,h(null)},this.endShadows=function(){r=!1},this.setGlobalState=function(u,d){t=h(u,d,0)},this.setState=function(u,d,f){let m=u.clippingPlanes,_=u.clipIntersection,g=u.clipShadows,p=s.get(u);if(!i||m===null||m.length===0||r&&!g)r?h(null):l();else{let v=r?0:n,x=v*4,y=p.clippingState||null;c.value=y,y=h(m,d,x,f);for(let b=0;b!==x;++b)y[b]=t[b];p.clippingState=y,this.numIntersection=_?this.numPlanes:0,this.numPlanes+=v}};function l(){c.value!==t&&(c.value=t,c.needsUpdate=n>0),e.numPlanes=n,e.numIntersection=0}function h(u,d,f,m){let _=u!==null?u.length:0,g=null;if(_!==0){if(g=c.value,m!==!0||g===null){let p=f+_*4,v=d.matrixWorldInverse;o.getNormalMatrix(v),(g===null||g.length0){let l=new xo(c.height/2);return l.fromEquirectangularTexture(s,a),e.set(a,l),a.addEventListener("dispose",i),t(l.texture,a.mapping)}else return null}}return a}function i(a){let o=a.target;o.removeEventListener("dispose",i);let c=e.get(o);c!==void 0&&(e.delete(o),c.dispose())}function r(){e=new WeakMap}return{get:n,dispose:r}}var Ls=class extends Cs{constructor(e=-1,t=1,n=1,i=-1,r=.1,a=2e3){super(),this.isOrthographicCamera=!0,this.type="OrthographicCamera",this.zoom=1,this.view=null,this.left=e,this.right=t,this.top=n,this.bottom=i,this.near=r,this.far=a,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.left=e.left,this.right=e.right,this.top=e.top,this.bottom=e.bottom,this.near=e.near,this.far=e.far,this.zoom=e.zoom,this.view=e.view===null?null:Object.assign({},e.view),this}setViewOffset(e,t,n,i,r,a){this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=a,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){let e=(this.right-this.left)/(2*this.zoom),t=(this.top-this.bottom)/(2*this.zoom),n=(this.right+this.left)/2,i=(this.top+this.bottom)/2,r=n-e,a=n+e,o=i+t,c=i-t;if(this.view!==null&&this.view.enabled){let l=(this.right-this.left)/this.view.fullWidth/this.zoom,h=(this.top-this.bottom)/this.view.fullHeight/this.zoom;r+=l*this.view.offsetX,a=r+l*this.view.width,o-=h*this.view.offsetY,c=o-h*this.view.height}this.projectionMatrix.makeOrthographic(r,a,o,c,this.near,this.far,this.coordinateSystem),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){let t=super.toJSON(e);return t.object.zoom=this.zoom,t.object.left=this.left,t.object.right=this.right,t.object.top=this.top,t.object.bottom=this.bottom,t.object.near=this.near,t.object.far=this.far,this.view!==null&&(t.object.view=Object.assign({},this.view)),t}},Hi=4,hh=[.125,.215,.35,.446,.526,.582],ei=20,$a=new Ls,uh=new pe,Ka=null,jn=(1+Math.sqrt(5))/2,Li=1/jn,dh=[new A(1,1,1),new A(-1,1,1),new A(1,1,-1),new A(-1,1,-1),new A(0,jn,Li),new A(0,jn,-Li),new A(Li,0,jn),new A(-Li,0,jn),new A(jn,Li,0),new A(-jn,Li,0)],Kr=class{constructor(e){this._renderer=e,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._compileMaterial(this._blurMaterial)}fromScene(e,t=0,n=.1,i=100){Ka=this._renderer.getRenderTarget(),this._setSize(256);let r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(e,n,i,r),t>0&&this._blur(r,0,0,t),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(e,t=null){return this._fromTexture(e,t)}fromCubemap(e,t=null){return this._fromTexture(e,t)}compileCubemapShader(){this._cubemapMaterial===null&&(this._cubemapMaterial=mh(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){this._equirectMaterial===null&&(this._equirectMaterial=ph(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),this._cubemapMaterial!==null&&this._cubemapMaterial.dispose(),this._equirectMaterial!==null&&this._equirectMaterial.dispose()}_setSize(e){this._lodMax=Math.floor(Math.log2(e)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){this._blurMaterial!==null&&this._blurMaterial.dispose(),this._pingPongRenderTarget!==null&&this._pingPongRenderTarget.dispose();for(let e=0;e2?x:0,x,x),h.setRenderTarget(i),_&&h.render(m,o),h.render(e,o)}m.geometry.dispose(),m.material.dispose(),h.toneMapping=d,h.autoClear=u,e.background=g}_textureToCubeUV(e,t){let n=this._renderer,i=e.mapping===zn||e.mapping===ci;i?(this._cubemapMaterial===null&&(this._cubemapMaterial=mh()),this._cubemapMaterial.uniforms.flipEnvMap.value=e.isRenderTargetTexture===!1?-1:1):this._equirectMaterial===null&&(this._equirectMaterial=ph());let r=i?this._cubemapMaterial:this._equirectMaterial,a=new Mt(this._lodPlanes[0],r),o=r.uniforms;o.envMap.value=e;let c=this._cubeSize;lr(t,0,0,3*c,2*c),n.setRenderTarget(t),n.render(a,$a)}_applyPMREM(e){let t=this._renderer,n=t.autoClear;t.autoClear=!1;for(let i=1;iei&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${g} samples when the maximum is set to ${ei}`);let p=[],v=0;for(let R=0;Rx-Hi?i-x+Hi:0),w=4*(this._cubeSize-y);lr(t,b,w,3*y,2*y),c.setRenderTarget(t),c.render(u,$a)}};function o_(s){let e=[],t=[],n=[],i=s,r=s-Hi+1+hh.length;for(let a=0;as-Hi?c=hh[a-s+Hi-1]:a===0&&(c=0),n.push(c);let l=1/(o-2),h=-l,u=1+l,d=[h,h,u,h,u,u,h,h,u,u,h,u],f=6,m=6,_=3,g=2,p=1,v=new Float32Array(_*m*f),x=new Float32Array(g*m*f),y=new Float32Array(p*m*f);for(let w=0;w2?0:-1,M=[R,I,0,R+2/3,I,0,R+2/3,I+1,0,R,I,0,R+2/3,I+1,0,R,I+1,0];v.set(M,_*m*w),x.set(d,g*m*w);let T=[w,w,w,w,w,w];y.set(T,p*m*w)}let b=new Ge;b.setAttribute("position",new et(v,_)),b.setAttribute("uv",new et(x,g)),b.setAttribute("faceIndex",new et(y,p)),e.push(b),i>Hi&&i--}return{lodPlanes:e,sizeLods:t,sigmas:n}}function fh(s,e,t){let n=new qt(s,e,t);return n.texture.mapping=Vs,n.texture.name="PMREM.cubeUv",n.scissorTest=!0,n}function lr(s,e,t,n,i){s.viewport.set(e,t,n,i),s.scissor.set(e,t,n,i)}function c_(s,e,t){let n=new Float32Array(ei),i=new A(0,1,0);return new jt({name:"SphericalGaussianBlur",defines:{n:ei,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/t,CUBEUV_MAX_MIP:`${s}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:n},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:i}},vertexShader:Zc(),fragmentShader:` + + precision mediump float; + precision mediump int; + + varying vec3 vOutputDirection; + + uniform sampler2D envMap; + uniform int samples; + uniform float weights[ n ]; + uniform bool latitudinal; + uniform float dTheta; + uniform float mipInt; + uniform vec3 poleAxis; + + #define ENVMAP_TYPE_CUBE_UV + #include + + vec3 getSample( float theta, vec3 axis ) { + + float cosTheta = cos( theta ); + // Rodrigues' axis-angle rotation + vec3 sampleDirection = vOutputDirection * cosTheta + + cross( axis, vOutputDirection ) * sin( theta ) + + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); + + return bilinearCubeUV( envMap, sampleDirection, mipInt ); + + } + + void main() { + + vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); + + if ( all( equal( axis, vec3( 0.0 ) ) ) ) { + + axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); + + } + + axis = normalize( axis ); + + gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); + gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); + + for ( int i = 1; i < n; i++ ) { + + if ( i >= samples ) { + + break; + + } + + float theta = dTheta * float( i ); + gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); + gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); + + } + + } + `,blending:Dn,depthTest:!1,depthWrite:!1})}function ph(){return new jt({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:Zc(),fragmentShader:` + + precision mediump float; + precision mediump int; + + varying vec3 vOutputDirection; + + uniform sampler2D envMap; + + #include + + void main() { + + vec3 outputDirection = normalize( vOutputDirection ); + vec2 uv = equirectUv( outputDirection ); + + gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); + + } + `,blending:Dn,depthTest:!1,depthWrite:!1})}function mh(){return new jt({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:Zc(),fragmentShader:` + + precision mediump float; + precision mediump int; + + uniform float flipEnvMap; + + varying vec3 vOutputDirection; + + uniform samplerCube envMap; + + void main() { + + gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); + + } + `,blending:Dn,depthTest:!1,depthWrite:!1})}function Zc(){return` + + precision mediump float; + precision mediump int; + + attribute float faceIndex; + + varying vec3 vOutputDirection; + + // RH coordinate system; PMREM face-indexing convention + vec3 getDirection( vec2 uv, float face ) { + + uv = 2.0 * uv - 1.0; + + vec3 direction = vec3( uv, 1.0 ); + + if ( face == 0.0 ) { + + direction = direction.zyx; // ( 1, v, u ) pos x + + } else if ( face == 1.0 ) { + + direction = direction.xzy; + direction.xz *= -1.0; // ( -u, 1, -v ) pos y + + } else if ( face == 2.0 ) { + + direction.x *= -1.0; // ( -u, v, 1 ) pos z + + } else if ( face == 3.0 ) { + + direction = direction.zyx; + direction.xz *= -1.0; // ( -1, v, -u ) neg x + + } else if ( face == 4.0 ) { + + direction = direction.xzy; + direction.xy *= -1.0; // ( -u, -1, v ) neg y + + } else if ( face == 5.0 ) { + + direction.z *= -1.0; // ( u, v, -1 ) neg z + + } + + return direction; + + } + + void main() { + + vOutputDirection = getDirection( uv, faceIndex ); + gl_Position = vec4( position, 1.0 ); + + } + `}function l_(s){let e=new WeakMap,t=null;function n(o){if(o&&o.isTexture){let c=o.mapping,l=c===Ir||c===Ur,h=c===zn||c===ci;if(l||h)if(o.isRenderTargetTexture&&o.needsPMREMUpdate===!0){o.needsPMREMUpdate=!1;let u=e.get(o);return t===null&&(t=new Kr(s)),u=l?t.fromEquirectangular(o,u):t.fromCubemap(o,u),e.set(o,u),u.texture}else{if(e.has(o))return e.get(o).texture;{let u=o.image;if(l&&u&&u.height>0||h&&u&&i(u)){t===null&&(t=new Kr(s));let d=l?t.fromEquirectangular(o):t.fromCubemap(o);return e.set(o,d),o.addEventListener("dispose",r),d.texture}else return null}}}return o}function i(o){let c=0,l=6;for(let h=0;he.maxTextureSize&&(T=Math.ceil(M/e.maxTextureSize),M=e.maxTextureSize);let O=new Float32Array(M*T*4*m),Y=new As(O,M,T,m);Y.type=xn,Y.needsUpdate=!0;let $=I*4;for(let z=0;z0)return s;let i=e*t,r=gh[i];if(r===void 0&&(r=new Float32Array(i),gh[i]=r),e!==0){n.toArray(r,0);for(let a=1,o=0;a!==e;++a)o+=t,s[a].toArray(r,o)}return r}function gt(s,e){if(s.length!==e.length)return!1;for(let t=0,n=s.length;t":" "} ${o}: ${t[a]}`)}return n.join(` +`)}function o0(s){let e=Qe.getPrimaries(Qe.workingColorSpace),t=Qe.getPrimaries(s),n;switch(e===t?n="":e===kr&&t===Vr?n="LinearDisplayP3ToLinearSRGB":e===Vr&&t===kr&&(n="LinearSRGBToLinearDisplayP3"),s){case Mn:case va:return[n,"LinearTransferOETF"];case vt:case qc:return[n,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space:",s),[n,"LinearTransferOETF"]}}function bh(s,e,t){let n=s.getShaderParameter(e,s.COMPILE_STATUS),i=s.getShaderInfoLog(e).trim();if(n&&i==="")return"";let r=/ERROR: 0:(\d+)/.exec(i);if(r){let a=parseInt(r[1]);return t.toUpperCase()+` + +`+i+` + +`+a0(s.getShaderSource(e),a)}else return i}function c0(s,e){let t=o0(e);return`vec4 ${s}( vec4 value ) { return ${t[0]}( ${t[1]}( value ) ); }`}function l0(s,e){let t;switch(e){case df:t="Linear";break;case ff:t="Reinhard";break;case pf:t="OptimizedCineon";break;case mf:t="ACESFilmic";break;case gf:t="Custom";break;default:console.warn("THREE.WebGLProgram: Unsupported toneMapping:",e),t="Linear"}return"vec3 "+s+"( vec3 color ) { return "+t+"ToneMapping( color ); }"}function h0(s){return[s.extensionDerivatives||s.envMapCubeUVHeight||s.bumpMap||s.normalMapTangentSpace||s.clearcoatNormalMap||s.flatShading||s.shaderID==="physical"?"#extension GL_OES_standard_derivatives : enable":"",(s.extensionFragDepth||s.logarithmicDepthBuffer)&&s.rendererExtensionFragDepth?"#extension GL_EXT_frag_depth : enable":"",s.extensionDrawBuffers&&s.rendererExtensionDrawBuffers?"#extension GL_EXT_draw_buffers : require":"",(s.extensionShaderTextureLOD||s.envMap||s.transmission)&&s.rendererExtensionShaderTextureLod?"#extension GL_EXT_shader_texture_lod : enable":""].filter(vs).join(` +`)}function u0(s){let e=[];for(let t in s){let n=s[t];n!==!1&&e.push("#define "+t+" "+n)}return e.join(` +`)}function d0(s,e){let t={},n=s.getProgramParameter(e,s.ACTIVE_ATTRIBUTES);for(let i=0;i/gm;function So(s){return s.replace(f0,m0)}var p0=new Map([["encodings_fragment","colorspace_fragment"],["encodings_pars_fragment","colorspace_pars_fragment"],["output_fragment","opaque_fragment"]]);function m0(s,e){let t=ke[e];if(t===void 0){let n=p0.get(e);if(n!==void 0)t=ke[n],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,n);else throw new Error("Can not resolve #include <"+e+">")}return So(t)}var g0=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function wh(s){return s.replace(g0,_0)}function _0(s,e,t,n){let i="";for(let r=parseInt(e);r0&&(g+=` +`),p=[f,"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,m].filter(vs).join(` +`),p.length>0&&(p+=` +`)):(g=[Ah(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,m,t.instancing?"#define USE_INSTANCING":"",t.instancingColor?"#define USE_INSTANCING_COLOR":"",t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.map?"#define USE_MAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+h:"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.displacementMap?"#define USE_DISPLACEMENTMAP":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.mapUv?"#define MAP_UV "+t.mapUv:"",t.alphaMapUv?"#define ALPHAMAP_UV "+t.alphaMapUv:"",t.lightMapUv?"#define LIGHTMAP_UV "+t.lightMapUv:"",t.aoMapUv?"#define AOMAP_UV "+t.aoMapUv:"",t.emissiveMapUv?"#define EMISSIVEMAP_UV "+t.emissiveMapUv:"",t.bumpMapUv?"#define BUMPMAP_UV "+t.bumpMapUv:"",t.normalMapUv?"#define NORMALMAP_UV "+t.normalMapUv:"",t.displacementMapUv?"#define DISPLACEMENTMAP_UV "+t.displacementMapUv:"",t.metalnessMapUv?"#define METALNESSMAP_UV "+t.metalnessMapUv:"",t.roughnessMapUv?"#define ROUGHNESSMAP_UV "+t.roughnessMapUv:"",t.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+t.anisotropyMapUv:"",t.clearcoatMapUv?"#define CLEARCOATMAP_UV "+t.clearcoatMapUv:"",t.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+t.clearcoatNormalMapUv:"",t.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+t.clearcoatRoughnessMapUv:"",t.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+t.iridescenceMapUv:"",t.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+t.iridescenceThicknessMapUv:"",t.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+t.sheenColorMapUv:"",t.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+t.sheenRoughnessMapUv:"",t.specularMapUv?"#define SPECULARMAP_UV "+t.specularMapUv:"",t.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+t.specularColorMapUv:"",t.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+t.specularIntensityMapUv:"",t.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+t.transmissionMapUv:"",t.thicknessMapUv?"#define THICKNESSMAP_UV "+t.thicknessMapUv:"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.flatShading?"#define FLAT_SHADED":"",t.skinning?"#define USE_SKINNING":"",t.morphTargets?"#define USE_MORPHTARGETS":"",t.morphNormals&&t.flatShading===!1?"#define USE_MORPHNORMALS":"",t.morphColors&&t.isWebGL2?"#define USE_MORPHCOLORS":"",t.morphTargetsCount>0&&t.isWebGL2?"#define MORPHTARGETS_TEXTURE":"",t.morphTargetsCount>0&&t.isWebGL2?"#define MORPHTARGETS_TEXTURE_STRIDE "+t.morphTextureStride:"",t.morphTargetsCount>0&&t.isWebGL2?"#define MORPHTARGETS_COUNT "+t.morphTargetsCount:"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+c:"",t.sizeAttenuation?"#define USE_SIZEATTENUATION":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.useLegacyLights?"#define LEGACY_LIGHTS":"",t.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",t.logarithmicDepthBuffer&&t.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING"," attribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR"," attribute vec3 instanceColor;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1"," attribute vec2 uv1;","#endif","#ifdef USE_UV2"," attribute vec2 uv2;","#endif","#ifdef USE_UV3"," attribute vec2 uv3;","#endif","#ifdef USE_TANGENT"," attribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )"," attribute vec4 color;","#elif defined( USE_COLOR )"," attribute vec3 color;","#endif","#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )"," attribute vec3 morphTarget0;"," attribute vec3 morphTarget1;"," attribute vec3 morphTarget2;"," attribute vec3 morphTarget3;"," #ifdef USE_MORPHNORMALS"," attribute vec3 morphNormal0;"," attribute vec3 morphNormal1;"," attribute vec3 morphNormal2;"," attribute vec3 morphNormal3;"," #else"," attribute vec3 morphTarget4;"," attribute vec3 morphTarget5;"," attribute vec3 morphTarget6;"," attribute vec3 morphTarget7;"," #endif","#endif","#ifdef USE_SKINNING"," attribute vec4 skinIndex;"," attribute vec4 skinWeight;","#endif",` +`].filter(vs).join(` +`),p=[f,Ah(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,m,t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.map?"#define USE_MAP":"",t.matcap?"#define USE_MATCAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+l:"",t.envMap?"#define "+h:"",t.envMap?"#define "+u:"",d?"#define CUBEUV_TEXEL_WIDTH "+d.texelWidth:"",d?"#define CUBEUV_TEXEL_HEIGHT "+d.texelHeight:"",d?"#define CUBEUV_MAX_MIP "+d.maxMip+".0":"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoat?"#define USE_CLEARCOAT":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.iridescence?"#define USE_IRIDESCENCE":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaTest?"#define USE_ALPHATEST":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.sheen?"#define USE_SHEEN":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors||t.instancingColor?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.gradientMap?"#define USE_GRADIENTMAP":"",t.flatShading?"#define FLAT_SHADED":"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+c:"",t.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.useLegacyLights?"#define LEGACY_LIGHTS":"",t.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",t.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",t.logarithmicDepthBuffer&&t.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",t.toneMapping!==Nn?"#define TONE_MAPPING":"",t.toneMapping!==Nn?ke.tonemapping_pars_fragment:"",t.toneMapping!==Nn?l0("toneMapping",t.toneMapping):"",t.dithering?"#define DITHERING":"",t.opaque?"#define OPAQUE":"",ke.colorspace_pars_fragment,c0("linearToOutputTexel",t.outputColorSpace),t.useDepthPacking?"#define DEPTH_PACKING "+t.depthPacking:"",` +`].filter(vs).join(` +`)),a=So(a),a=Eh(a,t),a=Th(a,t),o=So(o),o=Eh(o,t),o=Th(o,t),a=wh(a),o=wh(o),t.isWebGL2&&t.isRawShaderMaterial!==!0&&(v=`#version 300 es +`,g=["precision mediump sampler2DArray;","#define attribute in","#define varying out","#define texture2D texture"].join(` +`)+` +`+g,p=["#define varying in",t.glslVersion===Ol?"":"layout(location = 0) out highp vec4 pc_fragColor;",t.glslVersion===Ol?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join(` +`)+` +`+p);let x=v+g+a,y=v+p+o,b=Sh(i,i.VERTEX_SHADER,x),w=Sh(i,i.FRAGMENT_SHADER,y);if(i.attachShader(_,b),i.attachShader(_,w),t.index0AttributeName!==void 0?i.bindAttribLocation(_,0,t.index0AttributeName):t.morphTargets===!0&&i.bindAttribLocation(_,0,"position"),i.linkProgram(_),s.debug.checkShaderErrors){let M=i.getProgramInfoLog(_).trim(),T=i.getShaderInfoLog(b).trim(),O=i.getShaderInfoLog(w).trim(),Y=!0,$=!0;if(i.getProgramParameter(_,i.LINK_STATUS)===!1)if(Y=!1,typeof s.debug.onShaderError=="function")s.debug.onShaderError(i,_,b,w);else{let U=bh(i,b,"vertex"),z=bh(i,w,"fragment");console.error("THREE.WebGLProgram: Shader Error "+i.getError()+" - VALIDATE_STATUS "+i.getProgramParameter(_,i.VALIDATE_STATUS)+` + +Program Info Log: `+M+` +`+U+` +`+z)}else M!==""?console.warn("THREE.WebGLProgram: Program Info Log:",M):(T===""||O==="")&&($=!1);$&&(this.diagnostics={runnable:Y,programLog:M,vertexShader:{log:T,prefix:g},fragmentShader:{log:O,prefix:p}})}i.deleteShader(b),i.deleteShader(w);let R;this.getUniforms=function(){return R===void 0&&(R=new qi(i,_)),R};let I;return this.getAttributes=function(){return I===void 0&&(I=d0(i,_)),I},this.destroy=function(){n.releaseStatesOfProgram(this),i.deleteProgram(_),this.program=void 0},this.type=t.shaderType,this.name=t.shaderName,this.id=r0++,this.cacheKey=e,this.usedTimes=1,this.program=_,this.vertexShader=b,this.fragmentShader=w,this}var E0=0,bo=class{constructor(){this.shaderCache=new Map,this.materialCache=new Map}update(e){let t=e.vertexShader,n=e.fragmentShader,i=this._getShaderStage(t),r=this._getShaderStage(n),a=this._getShaderCacheForMaterial(e);return a.has(i)===!1&&(a.add(i),i.usedTimes++),a.has(r)===!1&&(a.add(r),r.usedTimes++),this}remove(e){let t=this.materialCache.get(e);for(let n of t)n.usedTimes--,n.usedTimes===0&&this.shaderCache.delete(n.code);return this.materialCache.delete(e),this}getVertexShaderID(e){return this._getShaderStage(e.vertexShader).id}getFragmentShaderID(e){return this._getShaderStage(e.fragmentShader).id}dispose(){this.shaderCache.clear(),this.materialCache.clear()}_getShaderCacheForMaterial(e){let t=this.materialCache,n=t.get(e);return n===void 0&&(n=new Set,t.set(e,n)),n}_getShaderStage(e){let t=this.shaderCache,n=t.get(e);return n===void 0&&(n=new Eo(e),t.set(e,n)),n}},Eo=class{constructor(e){this.id=E0++,this.code=e,this.usedTimes=0}};function T0(s,e,t,n,i,r,a){let o=new Rs,c=new bo,l=[],h=i.isWebGL2,u=i.logarithmicDepthBuffer,d=i.vertexTextures,f=i.precision,m={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distanceRGBA",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon",MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"};function _(M){return M===0?"uv":`uv${M}`}function g(M,T,O,Y,$){let U=Y.fog,z=$.geometry,q=M.isMeshStandardMaterial?Y.environment:null,H=(M.isMeshStandardMaterial?t:e).get(M.envMap||q),ne=H&&H.mapping===Vs?H.image.height:null,W=m[M.type];M.precision!==null&&(f=i.getMaxPrecision(M.precision),f!==M.precision&&console.warn("THREE.WebGLProgram.getParameters:",M.precision,"not supported, using",f,"instead."));let K=z.morphAttributes.position||z.morphAttributes.normal||z.morphAttributes.color,D=K!==void 0?K.length:0,G=0;z.morphAttributes.position!==void 0&&(G=1),z.morphAttributes.normal!==void 0&&(G=2),z.morphAttributes.color!==void 0&&(G=3);let he,fe,_e,we;if(W){let tt=nn[W];he=tt.vertexShader,fe=tt.fragmentShader}else he=M.vertexShader,fe=M.fragmentShader,c.update(M),_e=c.getVertexShaderID(M),we=c.getFragmentShaderID(M);let Ee=s.getRenderTarget(),Te=$.isInstancedMesh===!0,Ye=!!M.map,it=!!M.matcap,Ce=!!H,L=!!M.aoMap,oe=!!M.lightMap,X=!!M.bumpMap,ie=!!M.normalMap,J=!!M.displacementMap,Se=!!M.emissiveMap,me=!!M.metalnessMap,ye=!!M.roughnessMap,Ne=M.anisotropy>0,qe=M.clearcoat>0,rt=M.iridescence>0,C=M.sheen>0,S=M.transmission>0,B=Ne&&!!M.anisotropyMap,ee=qe&&!!M.clearcoatMap,j=qe&&!!M.clearcoatNormalMap,te=qe&&!!M.clearcoatRoughnessMap,Me=rt&&!!M.iridescenceMap,re=rt&&!!M.iridescenceThicknessMap,de=C&&!!M.sheenColorMap,Le=C&&!!M.sheenRoughnessMap,Ze=!!M.specularMap,se=!!M.specularColorMap,$e=!!M.specularIntensityMap,Oe=S&&!!M.transmissionMap,Ie=S&&!!M.thicknessMap,Re=!!M.gradientMap,P=!!M.alphaMap,ce=M.alphaTest>0,ae=!!M.alphaHash,ge=!!M.extensions,ue=!!z.attributes.uv1,Q=!!z.attributes.uv2,be=!!z.attributes.uv3,Fe=Nn;return M.toneMapped&&(Ee===null||Ee.isXRRenderTarget===!0)&&(Fe=s.toneMapping),{isWebGL2:h,shaderID:W,shaderType:M.type,shaderName:M.name,vertexShader:he,fragmentShader:fe,defines:M.defines,customVertexShaderID:_e,customFragmentShaderID:we,isRawShaderMaterial:M.isRawShaderMaterial===!0,glslVersion:M.glslVersion,precision:f,instancing:Te,instancingColor:Te&&$.instanceColor!==null,supportsVertexTextures:d,outputColorSpace:Ee===null?s.outputColorSpace:Ee.isXRRenderTarget===!0?Ee.texture.colorSpace:Mn,map:Ye,matcap:it,envMap:Ce,envMapMode:Ce&&H.mapping,envMapCubeUVHeight:ne,aoMap:L,lightMap:oe,bumpMap:X,normalMap:ie,displacementMap:d&&J,emissiveMap:Se,normalMapObjectSpace:ie&&M.normalMapType===Lf,normalMapTangentSpace:ie&&M.normalMapType===mi,metalnessMap:me,roughnessMap:ye,anisotropy:Ne,anisotropyMap:B,clearcoat:qe,clearcoatMap:ee,clearcoatNormalMap:j,clearcoatRoughnessMap:te,iridescence:rt,iridescenceMap:Me,iridescenceThicknessMap:re,sheen:C,sheenColorMap:de,sheenRoughnessMap:Le,specularMap:Ze,specularColorMap:se,specularIntensityMap:$e,transmission:S,transmissionMap:Oe,thicknessMap:Ie,gradientMap:Re,opaque:M.transparent===!1&&M.blending===Wi,alphaMap:P,alphaTest:ce,alphaHash:ae,combine:M.combine,mapUv:Ye&&_(M.map.channel),aoMapUv:L&&_(M.aoMap.channel),lightMapUv:oe&&_(M.lightMap.channel),bumpMapUv:X&&_(M.bumpMap.channel),normalMapUv:ie&&_(M.normalMap.channel),displacementMapUv:J&&_(M.displacementMap.channel),emissiveMapUv:Se&&_(M.emissiveMap.channel),metalnessMapUv:me&&_(M.metalnessMap.channel),roughnessMapUv:ye&&_(M.roughnessMap.channel),anisotropyMapUv:B&&_(M.anisotropyMap.channel),clearcoatMapUv:ee&&_(M.clearcoatMap.channel),clearcoatNormalMapUv:j&&_(M.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:te&&_(M.clearcoatRoughnessMap.channel),iridescenceMapUv:Me&&_(M.iridescenceMap.channel),iridescenceThicknessMapUv:re&&_(M.iridescenceThicknessMap.channel),sheenColorMapUv:de&&_(M.sheenColorMap.channel),sheenRoughnessMapUv:Le&&_(M.sheenRoughnessMap.channel),specularMapUv:Ze&&_(M.specularMap.channel),specularColorMapUv:se&&_(M.specularColorMap.channel),specularIntensityMapUv:$e&&_(M.specularIntensityMap.channel),transmissionMapUv:Oe&&_(M.transmissionMap.channel),thicknessMapUv:Ie&&_(M.thicknessMap.channel),alphaMapUv:P&&_(M.alphaMap.channel),vertexTangents:!!z.attributes.tangent&&(ie||Ne),vertexColors:M.vertexColors,vertexAlphas:M.vertexColors===!0&&!!z.attributes.color&&z.attributes.color.itemSize===4,vertexUv1s:ue,vertexUv2s:Q,vertexUv3s:be,pointsUvs:$.isPoints===!0&&!!z.attributes.uv&&(Ye||P),fog:!!U,useFog:M.fog===!0,fogExp2:U&&U.isFogExp2,flatShading:M.flatShading===!0,sizeAttenuation:M.sizeAttenuation===!0,logarithmicDepthBuffer:u,skinning:$.isSkinnedMesh===!0,morphTargets:z.morphAttributes.position!==void 0,morphNormals:z.morphAttributes.normal!==void 0,morphColors:z.morphAttributes.color!==void 0,morphTargetsCount:D,morphTextureStride:G,numDirLights:T.directional.length,numPointLights:T.point.length,numSpotLights:T.spot.length,numSpotLightMaps:T.spotLightMap.length,numRectAreaLights:T.rectArea.length,numHemiLights:T.hemi.length,numDirLightShadows:T.directionalShadowMap.length,numPointLightShadows:T.pointShadowMap.length,numSpotLightShadows:T.spotShadowMap.length,numSpotLightShadowsWithMaps:T.numSpotLightShadowsWithMaps,numLightProbes:T.numLightProbes,numClippingPlanes:a.numPlanes,numClipIntersection:a.numIntersection,dithering:M.dithering,shadowMapEnabled:s.shadowMap.enabled&&O.length>0,shadowMapType:s.shadowMap.type,toneMapping:Fe,useLegacyLights:s._useLegacyLights,decodeVideoTexture:Ye&&M.map.isVideoTexture===!0&&Qe.getTransfer(M.map.colorSpace)===nt,premultipliedAlpha:M.premultipliedAlpha,doubleSided:M.side===gn,flipSided:M.side===Ft,useDepthPacking:M.depthPacking>=0,depthPacking:M.depthPacking||0,index0AttributeName:M.index0AttributeName,extensionDerivatives:ge&&M.extensions.derivatives===!0,extensionFragDepth:ge&&M.extensions.fragDepth===!0,extensionDrawBuffers:ge&&M.extensions.drawBuffers===!0,extensionShaderTextureLOD:ge&&M.extensions.shaderTextureLOD===!0,rendererExtensionFragDepth:h||n.has("EXT_frag_depth"),rendererExtensionDrawBuffers:h||n.has("WEBGL_draw_buffers"),rendererExtensionShaderTextureLod:h||n.has("EXT_shader_texture_lod"),customProgramCacheKey:M.customProgramCacheKey()}}function p(M){let T=[];if(M.shaderID?T.push(M.shaderID):(T.push(M.customVertexShaderID),T.push(M.customFragmentShaderID)),M.defines!==void 0)for(let O in M.defines)T.push(O),T.push(M.defines[O]);return M.isRawShaderMaterial===!1&&(v(T,M),x(T,M),T.push(s.outputColorSpace)),T.push(M.customProgramCacheKey),T.join()}function v(M,T){M.push(T.precision),M.push(T.outputColorSpace),M.push(T.envMapMode),M.push(T.envMapCubeUVHeight),M.push(T.mapUv),M.push(T.alphaMapUv),M.push(T.lightMapUv),M.push(T.aoMapUv),M.push(T.bumpMapUv),M.push(T.normalMapUv),M.push(T.displacementMapUv),M.push(T.emissiveMapUv),M.push(T.metalnessMapUv),M.push(T.roughnessMapUv),M.push(T.anisotropyMapUv),M.push(T.clearcoatMapUv),M.push(T.clearcoatNormalMapUv),M.push(T.clearcoatRoughnessMapUv),M.push(T.iridescenceMapUv),M.push(T.iridescenceThicknessMapUv),M.push(T.sheenColorMapUv),M.push(T.sheenRoughnessMapUv),M.push(T.specularMapUv),M.push(T.specularColorMapUv),M.push(T.specularIntensityMapUv),M.push(T.transmissionMapUv),M.push(T.thicknessMapUv),M.push(T.combine),M.push(T.fogExp2),M.push(T.sizeAttenuation),M.push(T.morphTargetsCount),M.push(T.morphAttributeCount),M.push(T.numDirLights),M.push(T.numPointLights),M.push(T.numSpotLights),M.push(T.numSpotLightMaps),M.push(T.numHemiLights),M.push(T.numRectAreaLights),M.push(T.numDirLightShadows),M.push(T.numPointLightShadows),M.push(T.numSpotLightShadows),M.push(T.numSpotLightShadowsWithMaps),M.push(T.numLightProbes),M.push(T.shadowMapType),M.push(T.toneMapping),M.push(T.numClippingPlanes),M.push(T.numClipIntersection),M.push(T.depthPacking)}function x(M,T){o.disableAll(),T.isWebGL2&&o.enable(0),T.supportsVertexTextures&&o.enable(1),T.instancing&&o.enable(2),T.instancingColor&&o.enable(3),T.matcap&&o.enable(4),T.envMap&&o.enable(5),T.normalMapObjectSpace&&o.enable(6),T.normalMapTangentSpace&&o.enable(7),T.clearcoat&&o.enable(8),T.iridescence&&o.enable(9),T.alphaTest&&o.enable(10),T.vertexColors&&o.enable(11),T.vertexAlphas&&o.enable(12),T.vertexUv1s&&o.enable(13),T.vertexUv2s&&o.enable(14),T.vertexUv3s&&o.enable(15),T.vertexTangents&&o.enable(16),T.anisotropy&&o.enable(17),M.push(o.mask),o.disableAll(),T.fog&&o.enable(0),T.useFog&&o.enable(1),T.flatShading&&o.enable(2),T.logarithmicDepthBuffer&&o.enable(3),T.skinning&&o.enable(4),T.morphTargets&&o.enable(5),T.morphNormals&&o.enable(6),T.morphColors&&o.enable(7),T.premultipliedAlpha&&o.enable(8),T.shadowMapEnabled&&o.enable(9),T.useLegacyLights&&o.enable(10),T.doubleSided&&o.enable(11),T.flipSided&&o.enable(12),T.useDepthPacking&&o.enable(13),T.dithering&&o.enable(14),T.transmission&&o.enable(15),T.sheen&&o.enable(16),T.opaque&&o.enable(17),T.pointsUvs&&o.enable(18),T.decodeVideoTexture&&o.enable(19),M.push(o.mask)}function y(M){let T=m[M.type],O;if(T){let Y=nn[T];O=xp.clone(Y.uniforms)}else O=M.uniforms;return O}function b(M,T){let O;for(let Y=0,$=l.length;Y<$;Y++){let U=l[Y];if(U.cacheKey===T){O=U,++O.usedTimes;break}}return O===void 0&&(O=new b0(s,T,M,r),l.push(O)),O}function w(M){if(--M.usedTimes===0){let T=l.indexOf(M);l[T]=l[l.length-1],l.pop(),M.destroy()}}function R(M){c.remove(M)}function I(){c.dispose()}return{getParameters:g,getProgramCacheKey:p,getUniforms:y,acquireProgram:b,releaseProgram:w,releaseShaderCache:R,programs:l,dispose:I}}function w0(){let s=new WeakMap;function e(r){let a=s.get(r);return a===void 0&&(a={},s.set(r,a)),a}function t(r){s.delete(r)}function n(r,a,o){s.get(r)[a]=o}function i(){s=new WeakMap}return{get:e,remove:t,update:n,dispose:i}}function A0(s,e){return s.groupOrder!==e.groupOrder?s.groupOrder-e.groupOrder:s.renderOrder!==e.renderOrder?s.renderOrder-e.renderOrder:s.material.id!==e.material.id?s.material.id-e.material.id:s.z!==e.z?s.z-e.z:s.id-e.id}function Rh(s,e){return s.groupOrder!==e.groupOrder?s.groupOrder-e.groupOrder:s.renderOrder!==e.renderOrder?s.renderOrder-e.renderOrder:s.z!==e.z?e.z-s.z:s.id-e.id}function Ch(){let s=[],e=0,t=[],n=[],i=[];function r(){e=0,t.length=0,n.length=0,i.length=0}function a(u,d,f,m,_,g){let p=s[e];return p===void 0?(p={id:u.id,object:u,geometry:d,material:f,groupOrder:m,renderOrder:u.renderOrder,z:_,group:g},s[e]=p):(p.id=u.id,p.object=u,p.geometry=d,p.material=f,p.groupOrder=m,p.renderOrder=u.renderOrder,p.z=_,p.group=g),e++,p}function o(u,d,f,m,_,g){let p=a(u,d,f,m,_,g);f.transmission>0?n.push(p):f.transparent===!0?i.push(p):t.push(p)}function c(u,d,f,m,_,g){let p=a(u,d,f,m,_,g);f.transmission>0?n.unshift(p):f.transparent===!0?i.unshift(p):t.unshift(p)}function l(u,d){t.length>1&&t.sort(u||A0),n.length>1&&n.sort(d||Rh),i.length>1&&i.sort(d||Rh)}function h(){for(let u=e,d=s.length;u=r.length?(a=new Ch,r.push(a)):a=r[i],a}function t(){s=new WeakMap}return{get:e,dispose:t}}function C0(){let s={};return{get:function(e){if(s[e.id]!==void 0)return s[e.id];let t;switch(e.type){case"DirectionalLight":t={direction:new A,color:new pe};break;case"SpotLight":t={position:new A,direction:new A,color:new pe,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":t={position:new A,color:new pe,distance:0,decay:0};break;case"HemisphereLight":t={direction:new A,skyColor:new pe,groundColor:new pe};break;case"RectAreaLight":t={color:new pe,position:new A,halfWidth:new A,halfHeight:new A};break}return s[e.id]=t,t}}}function P0(){let s={};return{get:function(e){if(s[e.id]!==void 0)return s[e.id];let t;switch(e.type){case"DirectionalLight":t={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Z};break;case"SpotLight":t={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Z};break;case"PointLight":t={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Z,shadowCameraNear:1,shadowCameraFar:1e3};break}return s[e.id]=t,t}}}var L0=0;function I0(s,e){return(e.castShadow?2:0)-(s.castShadow?2:0)+(e.map?1:0)-(s.map?1:0)}function U0(s,e){let t=new C0,n=P0(),i={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let h=0;h<9;h++)i.probe.push(new A);let r=new A,a=new ze,o=new ze;function c(h,u){let d=0,f=0,m=0;for(let Y=0;Y<9;Y++)i.probe[Y].set(0,0,0);let _=0,g=0,p=0,v=0,x=0,y=0,b=0,w=0,R=0,I=0,M=0;h.sort(I0);let T=u===!0?Math.PI:1;for(let Y=0,$=h.length;Y<$;Y++){let U=h[Y],z=U.color,q=U.intensity,H=U.distance,ne=U.shadow&&U.shadow.map?U.shadow.map.texture:null;if(U.isAmbientLight)d+=z.r*q*T,f+=z.g*q*T,m+=z.b*q*T;else if(U.isLightProbe){for(let W=0;W<9;W++)i.probe[W].addScaledVector(U.sh.coefficients[W],q);M++}else if(U.isDirectionalLight){let W=t.get(U);if(W.color.copy(U.color).multiplyScalar(U.intensity*T),U.castShadow){let K=U.shadow,D=n.get(U);D.shadowBias=K.bias,D.shadowNormalBias=K.normalBias,D.shadowRadius=K.radius,D.shadowMapSize=K.mapSize,i.directionalShadow[_]=D,i.directionalShadowMap[_]=ne,i.directionalShadowMatrix[_]=U.shadow.matrix,y++}i.directional[_]=W,_++}else if(U.isSpotLight){let W=t.get(U);W.position.setFromMatrixPosition(U.matrixWorld),W.color.copy(z).multiplyScalar(q*T),W.distance=H,W.coneCos=Math.cos(U.angle),W.penumbraCos=Math.cos(U.angle*(1-U.penumbra)),W.decay=U.decay,i.spot[p]=W;let K=U.shadow;if(U.map&&(i.spotLightMap[R]=U.map,R++,K.updateMatrices(U),U.castShadow&&I++),i.spotLightMatrix[p]=K.matrix,U.castShadow){let D=n.get(U);D.shadowBias=K.bias,D.shadowNormalBias=K.normalBias,D.shadowRadius=K.radius,D.shadowMapSize=K.mapSize,i.spotShadow[p]=D,i.spotShadowMap[p]=ne,w++}p++}else if(U.isRectAreaLight){let W=t.get(U);W.color.copy(z).multiplyScalar(q),W.halfWidth.set(U.width*.5,0,0),W.halfHeight.set(0,U.height*.5,0),i.rectArea[v]=W,v++}else if(U.isPointLight){let W=t.get(U);if(W.color.copy(U.color).multiplyScalar(U.intensity*T),W.distance=U.distance,W.decay=U.decay,U.castShadow){let K=U.shadow,D=n.get(U);D.shadowBias=K.bias,D.shadowNormalBias=K.normalBias,D.shadowRadius=K.radius,D.shadowMapSize=K.mapSize,D.shadowCameraNear=K.camera.near,D.shadowCameraFar=K.camera.far,i.pointShadow[g]=D,i.pointShadowMap[g]=ne,i.pointShadowMatrix[g]=U.shadow.matrix,b++}i.point[g]=W,g++}else if(U.isHemisphereLight){let W=t.get(U);W.skyColor.copy(U.color).multiplyScalar(q*T),W.groundColor.copy(U.groundColor).multiplyScalar(q*T),i.hemi[x]=W,x++}}v>0&&(e.isWebGL2||s.has("OES_texture_float_linear")===!0?(i.rectAreaLTC1=le.LTC_FLOAT_1,i.rectAreaLTC2=le.LTC_FLOAT_2):s.has("OES_texture_half_float_linear")===!0?(i.rectAreaLTC1=le.LTC_HALF_1,i.rectAreaLTC2=le.LTC_HALF_2):console.error("THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.")),i.ambient[0]=d,i.ambient[1]=f,i.ambient[2]=m;let O=i.hash;(O.directionalLength!==_||O.pointLength!==g||O.spotLength!==p||O.rectAreaLength!==v||O.hemiLength!==x||O.numDirectionalShadows!==y||O.numPointShadows!==b||O.numSpotShadows!==w||O.numSpotMaps!==R||O.numLightProbes!==M)&&(i.directional.length=_,i.spot.length=p,i.rectArea.length=v,i.point.length=g,i.hemi.length=x,i.directionalShadow.length=y,i.directionalShadowMap.length=y,i.pointShadow.length=b,i.pointShadowMap.length=b,i.spotShadow.length=w,i.spotShadowMap.length=w,i.directionalShadowMatrix.length=y,i.pointShadowMatrix.length=b,i.spotLightMatrix.length=w+R-I,i.spotLightMap.length=R,i.numSpotLightShadowsWithMaps=I,i.numLightProbes=M,O.directionalLength=_,O.pointLength=g,O.spotLength=p,O.rectAreaLength=v,O.hemiLength=x,O.numDirectionalShadows=y,O.numPointShadows=b,O.numSpotShadows=w,O.numSpotMaps=R,O.numLightProbes=M,i.version=L0++)}function l(h,u){let d=0,f=0,m=0,_=0,g=0,p=u.matrixWorldInverse;for(let v=0,x=h.length;v=o.length?(c=new Ph(s,e),o.push(c)):c=o[a],c}function i(){t=new WeakMap}return{get:n,dispose:i}}var Qr=class extends bt{constructor(e){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=Cf,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(e)}copy(e){return super.copy(e),this.depthPacking=e.depthPacking,this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this}},jr=class extends bt{constructor(e){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(e)}copy(e){return super.copy(e),this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this}},N0=`void main() { + gl_Position = vec4( position, 1.0 ); +}`,O0=`uniform sampler2D shadow_pass; +uniform vec2 resolution; +uniform float radius; +#include +void main() { + const float samples = float( VSM_SAMPLES ); + float mean = 0.0; + float squared_mean = 0.0; + float uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 ); + float uvStart = samples <= 1.0 ? 0.0 : - 1.0; + for ( float i = 0.0; i < samples; i ++ ) { + float uvOffset = uvStart + i * uvStride; + #ifdef HORIZONTAL_PASS + vec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) ); + mean += distribution.x; + squared_mean += distribution.y * distribution.y + distribution.x * distribution.x; + #else + float depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) ); + mean += depth; + squared_mean += depth * depth; + #endif + } + mean = mean / samples; + squared_mean = squared_mean / samples; + float std_dev = sqrt( squared_mean - mean * mean ); + gl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) ); +}`;function F0(s,e,t){let n=new Ps,i=new Z,r=new Z,a=new je,o=new Qr({depthPacking:Pf}),c=new jr,l={},h=t.maxTextureSize,u={[Bn]:Ft,[Ft]:Bn,[gn]:gn},d=new jt({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new Z},radius:{value:4}},vertexShader:N0,fragmentShader:O0}),f=d.clone();f.defines.HORIZONTAL_PASS=1;let m=new Ge;m.setAttribute("position",new et(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));let _=new Mt(m,d),g=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=cd;let p=this.type;this.render=function(b,w,R){if(g.enabled===!1||g.autoUpdate===!1&&g.needsUpdate===!1||b.length===0)return;let I=s.getRenderTarget(),M=s.getActiveCubeFace(),T=s.getActiveMipmapLevel(),O=s.state;O.setBlending(Dn),O.buffers.color.setClear(1,1,1,1),O.buffers.depth.setTest(!0),O.setScissorTest(!1);let Y=p!==pn&&this.type===pn,$=p===pn&&this.type!==pn;for(let U=0,z=b.length;Uh||i.y>h)&&(i.x>h&&(r.x=Math.floor(h/ne.x),i.x=r.x*ne.x,H.mapSize.x=r.x),i.y>h&&(r.y=Math.floor(h/ne.y),i.y=r.y*ne.y,H.mapSize.y=r.y)),H.map===null||Y===!0||$===!0){let K=this.type!==pn?{minFilter:pt,magFilter:pt}:{};H.map!==null&&H.map.dispose(),H.map=new qt(i.x,i.y,K),H.map.texture.name=q.name+".shadowMap",H.camera.updateProjectionMatrix()}s.setRenderTarget(H.map),s.clear();let W=H.getViewportCount();for(let K=0;K0||w.map&&w.alphaTest>0){let O=M.uuid,Y=w.uuid,$=l[O];$===void 0&&($={},l[O]=$);let U=$[Y];U===void 0&&(U=M.clone(),$[Y]=U),M=U}if(M.visible=w.visible,M.wireframe=w.wireframe,I===pn?M.side=w.shadowSide!==null?w.shadowSide:w.side:M.side=w.shadowSide!==null?w.shadowSide:u[w.side],M.alphaMap=w.alphaMap,M.alphaTest=w.alphaTest,M.map=w.map,M.clipShadows=w.clipShadows,M.clippingPlanes=w.clippingPlanes,M.clipIntersection=w.clipIntersection,M.displacementMap=w.displacementMap,M.displacementScale=w.displacementScale,M.displacementBias=w.displacementBias,M.wireframeLinewidth=w.wireframeLinewidth,M.linewidth=w.linewidth,R.isPointLight===!0&&M.isMeshDistanceMaterial===!0){let O=s.properties.get(M);O.light=R}return M}function y(b,w,R,I,M){if(b.visible===!1)return;if(b.layers.test(w.layers)&&(b.isMesh||b.isLine||b.isPoints)&&(b.castShadow||b.receiveShadow&&M===pn)&&(!b.frustumCulled||n.intersectsObject(b))){b.modelViewMatrix.multiplyMatrices(R.matrixWorldInverse,b.matrixWorld);let Y=e.update(b),$=b.material;if(Array.isArray($)){let U=Y.groups;for(let z=0,q=U.length;z=1):ne.indexOf("OpenGL ES")!==-1&&(H=parseFloat(/^OpenGL ES (\d)/.exec(ne)[1]),q=H>=2);let W=null,K={},D=s.getParameter(s.SCISSOR_BOX),G=s.getParameter(s.VIEWPORT),he=new je().fromArray(D),fe=new je().fromArray(G);function _e(P,ce,ae,ge){let ue=new Uint8Array(4),Q=s.createTexture();s.bindTexture(P,Q),s.texParameteri(P,s.TEXTURE_MIN_FILTER,s.NEAREST),s.texParameteri(P,s.TEXTURE_MAG_FILTER,s.NEAREST);for(let be=0;be"u"?!1:/OculusBrowser/g.test(navigator.userAgent),m=new WeakMap,_,g=new WeakMap,p=!1;try{p=typeof OffscreenCanvas<"u"&&new OffscreenCanvas(1,1).getContext("2d")!==null}catch{}function v(C,S){return p?new OffscreenCanvas(C,S):ws("canvas")}function x(C,S,B,ee){let j=1;if((C.width>ee||C.height>ee)&&(j=ee/Math.max(C.width,C.height)),j<1||S===!0)if(typeof HTMLImageElement<"u"&&C instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&C instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&C instanceof ImageBitmap){let te=S?Wr:Math.floor,Me=te(j*C.width),re=te(j*C.height);_===void 0&&(_=v(Me,re));let de=B?v(Me,re):_;return de.width=Me,de.height=re,de.getContext("2d").drawImage(C,0,0,Me,re),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+C.width+"x"+C.height+") to ("+Me+"x"+re+")."),de}else return"data"in C&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+C.width+"x"+C.height+")."),C;return C}function y(C){return mo(C.width)&&mo(C.height)}function b(C){return o?!1:C.wrapS!==It||C.wrapT!==It||C.minFilter!==pt&&C.minFilter!==mt}function w(C,S){return C.generateMipmaps&&S&&C.minFilter!==pt&&C.minFilter!==mt}function R(C){s.generateMipmap(C)}function I(C,S,B,ee,j=!1){if(o===!1)return S;if(C!==null){if(s[C]!==void 0)return s[C];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+C+"'")}let te=S;if(S===s.RED&&(B===s.FLOAT&&(te=s.R32F),B===s.HALF_FLOAT&&(te=s.R16F),B===s.UNSIGNED_BYTE&&(te=s.R8)),S===s.RED_INTEGER&&(B===s.UNSIGNED_BYTE&&(te=s.R8UI),B===s.UNSIGNED_SHORT&&(te=s.R16UI),B===s.UNSIGNED_INT&&(te=s.R32UI),B===s.BYTE&&(te=s.R8I),B===s.SHORT&&(te=s.R16I),B===s.INT&&(te=s.R32I)),S===s.RG&&(B===s.FLOAT&&(te=s.RG32F),B===s.HALF_FLOAT&&(te=s.RG16F),B===s.UNSIGNED_BYTE&&(te=s.RG8)),S===s.RGBA){let Me=j?zr:Qe.getTransfer(ee);B===s.FLOAT&&(te=s.RGBA32F),B===s.HALF_FLOAT&&(te=s.RGBA16F),B===s.UNSIGNED_BYTE&&(te=Me===nt?s.SRGB8_ALPHA8:s.RGBA8),B===s.UNSIGNED_SHORT_4_4_4_4&&(te=s.RGBA4),B===s.UNSIGNED_SHORT_5_5_5_1&&(te=s.RGB5_A1)}return(te===s.R16F||te===s.R32F||te===s.RG16F||te===s.RG32F||te===s.RGBA16F||te===s.RGBA32F)&&e.get("EXT_color_buffer_float"),te}function M(C,S,B){return w(C,B)===!0||C.isFramebufferTexture&&C.minFilter!==pt&&C.minFilter!==mt?Math.log2(Math.max(S.width,S.height))+1:C.mipmaps!==void 0&&C.mipmaps.length>0?C.mipmaps.length:C.isCompressedTexture&&Array.isArray(C.image)?S.mipmaps.length:1}function T(C){return C===pt||C===fo||C===Lr?s.NEAREST:s.LINEAR}function O(C){let S=C.target;S.removeEventListener("dispose",O),$(S),S.isVideoTexture&&m.delete(S)}function Y(C){let S=C.target;S.removeEventListener("dispose",Y),z(S)}function $(C){let S=n.get(C);if(S.__webglInit===void 0)return;let B=C.source,ee=g.get(B);if(ee){let j=ee[S.__cacheKey];j.usedTimes--,j.usedTimes===0&&U(C),Object.keys(ee).length===0&&g.delete(B)}n.remove(C)}function U(C){let S=n.get(C);s.deleteTexture(S.__webglTexture);let B=C.source,ee=g.get(B);delete ee[S.__cacheKey],a.memory.textures--}function z(C){let S=C.texture,B=n.get(C),ee=n.get(S);if(ee.__webglTexture!==void 0&&(s.deleteTexture(ee.__webglTexture),a.memory.textures--),C.depthTexture&&C.depthTexture.dispose(),C.isWebGLCubeRenderTarget)for(let j=0;j<6;j++){if(Array.isArray(B.__webglFramebuffer[j]))for(let te=0;te=c&&console.warn("THREE.WebGLTextures: Trying to use "+C+" texture units while this GPU supports only "+c),q+=1,C}function W(C){let S=[];return S.push(C.wrapS),S.push(C.wrapT),S.push(C.wrapR||0),S.push(C.magFilter),S.push(C.minFilter),S.push(C.anisotropy),S.push(C.internalFormat),S.push(C.format),S.push(C.type),S.push(C.generateMipmaps),S.push(C.premultiplyAlpha),S.push(C.flipY),S.push(C.unpackAlignment),S.push(C.colorSpace),S.join()}function K(C,S){let B=n.get(C);if(C.isVideoTexture&&qe(C),C.isRenderTargetTexture===!1&&C.version>0&&B.__version!==C.version){let ee=C.image;if(ee===null)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else if(ee.complete===!1)console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete");else{Ye(B,C,S);return}}t.bindTexture(s.TEXTURE_2D,B.__webglTexture,s.TEXTURE0+S)}function D(C,S){let B=n.get(C);if(C.version>0&&B.__version!==C.version){Ye(B,C,S);return}t.bindTexture(s.TEXTURE_2D_ARRAY,B.__webglTexture,s.TEXTURE0+S)}function G(C,S){let B=n.get(C);if(C.version>0&&B.__version!==C.version){Ye(B,C,S);return}t.bindTexture(s.TEXTURE_3D,B.__webglTexture,s.TEXTURE0+S)}function he(C,S){let B=n.get(C);if(C.version>0&&B.__version!==C.version){it(B,C,S);return}t.bindTexture(s.TEXTURE_CUBE_MAP,B.__webglTexture,s.TEXTURE0+S)}let fe={[Dr]:s.REPEAT,[It]:s.CLAMP_TO_EDGE,[Nr]:s.MIRRORED_REPEAT},_e={[pt]:s.NEAREST,[fo]:s.NEAREST_MIPMAP_NEAREST,[Lr]:s.NEAREST_MIPMAP_LINEAR,[mt]:s.LINEAR,[ud]:s.LINEAR_MIPMAP_NEAREST,[li]:s.LINEAR_MIPMAP_LINEAR},we={[Uf]:s.NEVER,[Vf]:s.ALWAYS,[Df]:s.LESS,[Of]:s.LEQUAL,[Nf]:s.EQUAL,[zf]:s.GEQUAL,[Ff]:s.GREATER,[Bf]:s.NOTEQUAL};function Ee(C,S,B){if(B?(s.texParameteri(C,s.TEXTURE_WRAP_S,fe[S.wrapS]),s.texParameteri(C,s.TEXTURE_WRAP_T,fe[S.wrapT]),(C===s.TEXTURE_3D||C===s.TEXTURE_2D_ARRAY)&&s.texParameteri(C,s.TEXTURE_WRAP_R,fe[S.wrapR]),s.texParameteri(C,s.TEXTURE_MAG_FILTER,_e[S.magFilter]),s.texParameteri(C,s.TEXTURE_MIN_FILTER,_e[S.minFilter])):(s.texParameteri(C,s.TEXTURE_WRAP_S,s.CLAMP_TO_EDGE),s.texParameteri(C,s.TEXTURE_WRAP_T,s.CLAMP_TO_EDGE),(C===s.TEXTURE_3D||C===s.TEXTURE_2D_ARRAY)&&s.texParameteri(C,s.TEXTURE_WRAP_R,s.CLAMP_TO_EDGE),(S.wrapS!==It||S.wrapT!==It)&&console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping."),s.texParameteri(C,s.TEXTURE_MAG_FILTER,T(S.magFilter)),s.texParameteri(C,s.TEXTURE_MIN_FILTER,T(S.minFilter)),S.minFilter!==pt&&S.minFilter!==mt&&console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.")),S.compareFunction&&(s.texParameteri(C,s.TEXTURE_COMPARE_MODE,s.COMPARE_REF_TO_TEXTURE),s.texParameteri(C,s.TEXTURE_COMPARE_FUNC,we[S.compareFunction])),e.has("EXT_texture_filter_anisotropic")===!0){let ee=e.get("EXT_texture_filter_anisotropic");if(S.magFilter===pt||S.minFilter!==Lr&&S.minFilter!==li||S.type===xn&&e.has("OES_texture_float_linear")===!1||o===!1&&S.type===Ts&&e.has("OES_texture_half_float_linear")===!1)return;(S.anisotropy>1||n.get(S).__currentAnisotropy)&&(s.texParameterf(C,ee.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(S.anisotropy,i.getMaxAnisotropy())),n.get(S).__currentAnisotropy=S.anisotropy)}}function Te(C,S){let B=!1;C.__webglInit===void 0&&(C.__webglInit=!0,S.addEventListener("dispose",O));let ee=S.source,j=g.get(ee);j===void 0&&(j={},g.set(ee,j));let te=W(S);if(te!==C.__cacheKey){j[te]===void 0&&(j[te]={texture:s.createTexture(),usedTimes:0},a.memory.textures++,B=!0),j[te].usedTimes++;let Me=j[C.__cacheKey];Me!==void 0&&(j[C.__cacheKey].usedTimes--,Me.usedTimes===0&&U(S)),C.__cacheKey=te,C.__webglTexture=j[te].texture}return B}function Ye(C,S,B){let ee=s.TEXTURE_2D;(S.isDataArrayTexture||S.isCompressedArrayTexture)&&(ee=s.TEXTURE_2D_ARRAY),S.isData3DTexture&&(ee=s.TEXTURE_3D);let j=Te(C,S),te=S.source;t.bindTexture(ee,C.__webglTexture,s.TEXTURE0+B);let Me=n.get(te);if(te.version!==Me.__version||j===!0){t.activeTexture(s.TEXTURE0+B);let re=Qe.getPrimaries(Qe.workingColorSpace),de=S.colorSpace===Xt?null:Qe.getPrimaries(S.colorSpace),Le=S.colorSpace===Xt||re===de?s.NONE:s.BROWSER_DEFAULT_WEBGL;s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,S.flipY),s.pixelStorei(s.UNPACK_PREMULTIPLY_ALPHA_WEBGL,S.premultiplyAlpha),s.pixelStorei(s.UNPACK_ALIGNMENT,S.unpackAlignment),s.pixelStorei(s.UNPACK_COLORSPACE_CONVERSION_WEBGL,Le);let Ze=b(S)&&y(S.image)===!1,se=x(S.image,Ze,!1,h);se=rt(S,se);let $e=y(se)||o,Oe=r.convert(S.format,S.colorSpace),Ie=r.convert(S.type),Re=I(S.internalFormat,Oe,Ie,S.colorSpace,S.isVideoTexture);Ee(ee,S,$e);let P,ce=S.mipmaps,ae=o&&S.isVideoTexture!==!0,ge=Me.__version===void 0||j===!0,ue=M(S,se,$e);if(S.isDepthTexture)Re=s.DEPTH_COMPONENT,o?S.type===xn?Re=s.DEPTH_COMPONENT32F:S.type===Ln?Re=s.DEPTH_COMPONENT24:S.type===ii?Re=s.DEPTH24_STENCIL8:Re=s.DEPTH_COMPONENT16:S.type===xn&&console.error("WebGLRenderer: Floating point depth texture requires WebGL2."),S.format===si&&Re===s.DEPTH_COMPONENT&&S.type!==Wc&&S.type!==Ln&&(console.warn("THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture."),S.type=Ln,Ie=r.convert(S.type)),S.format===Yi&&Re===s.DEPTH_COMPONENT&&(Re=s.DEPTH_STENCIL,S.type!==ii&&(console.warn("THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture."),S.type=ii,Ie=r.convert(S.type))),ge&&(ae?t.texStorage2D(s.TEXTURE_2D,1,Re,se.width,se.height):t.texImage2D(s.TEXTURE_2D,0,Re,se.width,se.height,0,Oe,Ie,null));else if(S.isDataTexture)if(ce.length>0&&$e){ae&&ge&&t.texStorage2D(s.TEXTURE_2D,ue,Re,ce[0].width,ce[0].height);for(let Q=0,be=ce.length;Q>=1,be>>=1}}else if(ce.length>0&&$e){ae&&ge&&t.texStorage2D(s.TEXTURE_2D,ue,Re,ce[0].width,ce[0].height);for(let Q=0,be=ce.length;Q0&&ge++,t.texStorage2D(s.TEXTURE_CUBE_MAP,ge,P,se[0].width,se[0].height));for(let Q=0;Q<6;Q++)if(Ze){ce?t.texSubImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+Q,0,0,0,se[Q].width,se[Q].height,Ie,Re,se[Q].data):t.texImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+Q,0,P,se[Q].width,se[Q].height,0,Ie,Re,se[Q].data);for(let be=0;be>te),se=Math.max(1,S.height>>te);j===s.TEXTURE_3D||j===s.TEXTURE_2D_ARRAY?t.texImage3D(j,te,de,Ze,se,S.depth,0,Me,re,null):t.texImage2D(j,te,de,Ze,se,0,Me,re,null)}t.bindFramebuffer(s.FRAMEBUFFER,C),Ne(S)?d.framebufferTexture2DMultisampleEXT(s.FRAMEBUFFER,ee,j,n.get(B).__webglTexture,0,ye(S)):(j===s.TEXTURE_2D||j>=s.TEXTURE_CUBE_MAP_POSITIVE_X&&j<=s.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&s.framebufferTexture2D(s.FRAMEBUFFER,ee,j,n.get(B).__webglTexture,te),t.bindFramebuffer(s.FRAMEBUFFER,null)}function L(C,S,B){if(s.bindRenderbuffer(s.RENDERBUFFER,C),S.depthBuffer&&!S.stencilBuffer){let ee=o===!0?s.DEPTH_COMPONENT24:s.DEPTH_COMPONENT16;if(B||Ne(S)){let j=S.depthTexture;j&&j.isDepthTexture&&(j.type===xn?ee=s.DEPTH_COMPONENT32F:j.type===Ln&&(ee=s.DEPTH_COMPONENT24));let te=ye(S);Ne(S)?d.renderbufferStorageMultisampleEXT(s.RENDERBUFFER,te,ee,S.width,S.height):s.renderbufferStorageMultisample(s.RENDERBUFFER,te,ee,S.width,S.height)}else s.renderbufferStorage(s.RENDERBUFFER,ee,S.width,S.height);s.framebufferRenderbuffer(s.FRAMEBUFFER,s.DEPTH_ATTACHMENT,s.RENDERBUFFER,C)}else if(S.depthBuffer&&S.stencilBuffer){let ee=ye(S);B&&Ne(S)===!1?s.renderbufferStorageMultisample(s.RENDERBUFFER,ee,s.DEPTH24_STENCIL8,S.width,S.height):Ne(S)?d.renderbufferStorageMultisampleEXT(s.RENDERBUFFER,ee,s.DEPTH24_STENCIL8,S.width,S.height):s.renderbufferStorage(s.RENDERBUFFER,s.DEPTH_STENCIL,S.width,S.height),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.DEPTH_STENCIL_ATTACHMENT,s.RENDERBUFFER,C)}else{let ee=S.isWebGLMultipleRenderTargets===!0?S.texture:[S.texture];for(let j=0;j0){B.__webglFramebuffer[re]=[];for(let de=0;de0){B.__webglFramebuffer=[];for(let re=0;re0&&Ne(C)===!1){let re=te?S:[S];B.__webglMultisampledFramebuffer=s.createFramebuffer(),B.__webglColorRenderbuffer=[],t.bindFramebuffer(s.FRAMEBUFFER,B.__webglMultisampledFramebuffer);for(let de=0;de0)for(let de=0;de0)for(let de=0;de0&&Ne(C)===!1){let S=C.isWebGLMultipleRenderTargets?C.texture:[C.texture],B=C.width,ee=C.height,j=s.COLOR_BUFFER_BIT,te=[],Me=C.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,re=n.get(C),de=C.isWebGLMultipleRenderTargets===!0;if(de)for(let Le=0;Le0&&e.has("WEBGL_multisampled_render_to_texture")===!0&&S.__useRenderToTexture!==!1}function qe(C){let S=a.render.frame;m.get(C)!==S&&(m.set(C,S),C.update())}function rt(C,S){let B=C.colorSpace,ee=C.format,j=C.type;return C.isCompressedTexture===!0||C.isVideoTexture===!0||C.format===po||B!==Mn&&B!==Xt&&(Qe.getTransfer(B)===nt?o===!1?e.has("EXT_sRGB")===!0&&ee===Wt?(C.format=po,C.minFilter=mt,C.generateMipmaps=!1):S=Xr.sRGBToLinear(S):(ee!==Wt||j!==On)&&console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",B)),S}this.allocateTextureUnit=ne,this.resetTextureUnits=H,this.setTexture2D=K,this.setTexture2DArray=D,this.setTexture3D=G,this.setTextureCube=he,this.rebindTextures=ie,this.setupRenderTarget=J,this.updateRenderTargetMipmap=Se,this.updateMultisampleRenderTarget=me,this.setupDepthRenderbuffer=X,this.setupFrameBufferTexture=Ce,this.useMultisampledRTT=Ne}function V0(s,e,t){let n=t.isWebGL2;function i(r,a=Xt){let o,c=Qe.getTransfer(a);if(r===On)return s.UNSIGNED_BYTE;if(r===fd)return s.UNSIGNED_SHORT_4_4_4_4;if(r===pd)return s.UNSIGNED_SHORT_5_5_5_1;if(r===_f)return s.BYTE;if(r===xf)return s.SHORT;if(r===Wc)return s.UNSIGNED_SHORT;if(r===dd)return s.INT;if(r===Ln)return s.UNSIGNED_INT;if(r===xn)return s.FLOAT;if(r===Ts)return n?s.HALF_FLOAT:(o=e.get("OES_texture_half_float"),o!==null?o.HALF_FLOAT_OES:null);if(r===vf)return s.ALPHA;if(r===Wt)return s.RGBA;if(r===yf)return s.LUMINANCE;if(r===Mf)return s.LUMINANCE_ALPHA;if(r===si)return s.DEPTH_COMPONENT;if(r===Yi)return s.DEPTH_STENCIL;if(r===po)return o=e.get("EXT_sRGB"),o!==null?o.SRGB_ALPHA_EXT:null;if(r===Sf)return s.RED;if(r===md)return s.RED_INTEGER;if(r===bf)return s.RG;if(r===gd)return s.RG_INTEGER;if(r===_d)return s.RGBA_INTEGER;if(r===wa||r===Aa||r===Ra||r===Ca)if(c===nt)if(o=e.get("WEBGL_compressed_texture_s3tc_srgb"),o!==null){if(r===wa)return o.COMPRESSED_SRGB_S3TC_DXT1_EXT;if(r===Aa)return o.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;if(r===Ra)return o.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;if(r===Ca)return o.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}else return null;else if(o=e.get("WEBGL_compressed_texture_s3tc"),o!==null){if(r===wa)return o.COMPRESSED_RGB_S3TC_DXT1_EXT;if(r===Aa)return o.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(r===Ra)return o.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(r===Ca)return o.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null;if(r===ul||r===dl||r===fl||r===pl)if(o=e.get("WEBGL_compressed_texture_pvrtc"),o!==null){if(r===ul)return o.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(r===dl)return o.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(r===fl)return o.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(r===pl)return o.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(r===Ef)return o=e.get("WEBGL_compressed_texture_etc1"),o!==null?o.COMPRESSED_RGB_ETC1_WEBGL:null;if(r===ml||r===gl)if(o=e.get("WEBGL_compressed_texture_etc"),o!==null){if(r===ml)return c===nt?o.COMPRESSED_SRGB8_ETC2:o.COMPRESSED_RGB8_ETC2;if(r===gl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:o.COMPRESSED_RGBA8_ETC2_EAC}else return null;if(r===_l||r===xl||r===vl||r===yl||r===Ml||r===Sl||r===bl||r===El||r===Tl||r===wl||r===Al||r===Rl||r===Cl||r===Pl)if(o=e.get("WEBGL_compressed_texture_astc"),o!==null){if(r===_l)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:o.COMPRESSED_RGBA_ASTC_4x4_KHR;if(r===xl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:o.COMPRESSED_RGBA_ASTC_5x4_KHR;if(r===vl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:o.COMPRESSED_RGBA_ASTC_5x5_KHR;if(r===yl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:o.COMPRESSED_RGBA_ASTC_6x5_KHR;if(r===Ml)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:o.COMPRESSED_RGBA_ASTC_6x6_KHR;if(r===Sl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:o.COMPRESSED_RGBA_ASTC_8x5_KHR;if(r===bl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:o.COMPRESSED_RGBA_ASTC_8x6_KHR;if(r===El)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:o.COMPRESSED_RGBA_ASTC_8x8_KHR;if(r===Tl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:o.COMPRESSED_RGBA_ASTC_10x5_KHR;if(r===wl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:o.COMPRESSED_RGBA_ASTC_10x6_KHR;if(r===Al)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:o.COMPRESSED_RGBA_ASTC_10x8_KHR;if(r===Rl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:o.COMPRESSED_RGBA_ASTC_10x10_KHR;if(r===Cl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:o.COMPRESSED_RGBA_ASTC_12x10_KHR;if(r===Pl)return c===nt?o.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:o.COMPRESSED_RGBA_ASTC_12x12_KHR}else return null;if(r===Pa||r===Ll||r===Il)if(o=e.get("EXT_texture_compression_bptc"),o!==null){if(r===Pa)return c===nt?o.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:o.COMPRESSED_RGBA_BPTC_UNORM_EXT;if(r===Ll)return o.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;if(r===Il)return o.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT}else return null;if(r===Tf||r===Ul||r===Dl||r===Nl)if(o=e.get("EXT_texture_compression_rgtc"),o!==null){if(r===Pa)return o.COMPRESSED_RED_RGTC1_EXT;if(r===Ul)return o.COMPRESSED_SIGNED_RED_RGTC1_EXT;if(r===Dl)return o.COMPRESSED_RED_GREEN_RGTC2_EXT;if(r===Nl)return o.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT}else return null;return r===ii?n?s.UNSIGNED_INT_24_8:(o=e.get("WEBGL_depth_texture"),o!==null?o.UNSIGNED_INT_24_8_WEBGL:null):s[r]!==void 0?s[r]:null}return{convert:i}}var To=class extends yt{constructor(e=[]){super(),this.isArrayCamera=!0,this.cameras=e}},ti=class extends Je{constructor(){super(),this.isGroup=!0,this.type="Group"}},k0={type:"move"},Ss=class{constructor(){this._targetRay=null,this._grip=null,this._hand=null}getHandSpace(){return this._hand===null&&(this._hand=new ti,this._hand.matrixAutoUpdate=!1,this._hand.visible=!1,this._hand.joints={},this._hand.inputState={pinching:!1}),this._hand}getTargetRaySpace(){return this._targetRay===null&&(this._targetRay=new ti,this._targetRay.matrixAutoUpdate=!1,this._targetRay.visible=!1,this._targetRay.hasLinearVelocity=!1,this._targetRay.linearVelocity=new A,this._targetRay.hasAngularVelocity=!1,this._targetRay.angularVelocity=new A),this._targetRay}getGripSpace(){return this._grip===null&&(this._grip=new ti,this._grip.matrixAutoUpdate=!1,this._grip.visible=!1,this._grip.hasLinearVelocity=!1,this._grip.linearVelocity=new A,this._grip.hasAngularVelocity=!1,this._grip.angularVelocity=new A),this._grip}dispatchEvent(e){return this._targetRay!==null&&this._targetRay.dispatchEvent(e),this._grip!==null&&this._grip.dispatchEvent(e),this._hand!==null&&this._hand.dispatchEvent(e),this}connect(e){if(e&&e.hand){let t=this._hand;if(t)for(let n of e.hand.values())this._getHandJoint(t,n)}return this.dispatchEvent({type:"connected",data:e}),this}disconnect(e){return this.dispatchEvent({type:"disconnected",data:e}),this._targetRay!==null&&(this._targetRay.visible=!1),this._grip!==null&&(this._grip.visible=!1),this._hand!==null&&(this._hand.visible=!1),this}update(e,t,n){let i=null,r=null,a=null,o=this._targetRay,c=this._grip,l=this._hand;if(e&&t.session.visibilityState!=="visible-blurred"){if(l&&e.hand){a=!0;for(let _ of e.hand.values()){let g=t.getJointPose(_,n),p=this._getHandJoint(l,_);g!==null&&(p.matrix.fromArray(g.transform.matrix),p.matrix.decompose(p.position,p.rotation,p.scale),p.matrixWorldNeedsUpdate=!0,p.jointRadius=g.radius),p.visible=g!==null}let h=l.joints["index-finger-tip"],u=l.joints["thumb-tip"],d=h.position.distanceTo(u.position),f=.02,m=.005;l.inputState.pinching&&d>f+m?(l.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!l.inputState.pinching&&d<=f-m&&(l.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:e.handedness,target:this}))}else c!==null&&e.gripSpace&&(r=t.getPose(e.gripSpace,n),r!==null&&(c.matrix.fromArray(r.transform.matrix),c.matrix.decompose(c.position,c.rotation,c.scale),c.matrixWorldNeedsUpdate=!0,r.linearVelocity?(c.hasLinearVelocity=!0,c.linearVelocity.copy(r.linearVelocity)):c.hasLinearVelocity=!1,r.angularVelocity?(c.hasAngularVelocity=!0,c.angularVelocity.copy(r.angularVelocity)):c.hasAngularVelocity=!1));o!==null&&(i=t.getPose(e.targetRaySpace,n),i===null&&r!==null&&(i=r),i!==null&&(o.matrix.fromArray(i.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,i.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(i.linearVelocity)):o.hasLinearVelocity=!1,i.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(i.angularVelocity)):o.hasAngularVelocity=!1,this.dispatchEvent(k0)))}return o!==null&&(o.visible=i!==null),c!==null&&(c.visible=r!==null),l!==null&&(l.visible=a!==null),this}_getHandJoint(e,t){if(e.joints[t.jointName]===void 0){let n=new ti;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}},wo=class extends St{constructor(e,t,n,i,r,a,o,c,l,h){if(h=h!==void 0?h:si,h!==si&&h!==Yi)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");n===void 0&&h===si&&(n=Ln),n===void 0&&h===Yi&&(n=ii),super(null,i,r,a,o,c,h,n,l),this.isDepthTexture=!0,this.image={width:e,height:t},this.magFilter=o!==void 0?o:pt,this.minFilter=c!==void 0?c:pt,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(e){return super.copy(e),this.compareFunction=e.compareFunction,this}toJSON(e){let t=super.toJSON(e);return this.compareFunction!==null&&(t.compareFunction=this.compareFunction),t}},Ao=class extends sn{constructor(e,t){super();let n=this,i=null,r=1,a=null,o="local-floor",c=1,l=null,h=null,u=null,d=null,f=null,m=null,_=t.getContextAttributes(),g=null,p=null,v=[],x=[],y=new yt;y.layers.enable(1),y.viewport=new je;let b=new yt;b.layers.enable(2),b.viewport=new je;let w=[y,b],R=new To;R.layers.enable(1),R.layers.enable(2);let I=null,M=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(D){let G=v[D];return G===void 0&&(G=new Ss,v[D]=G),G.getTargetRaySpace()},this.getControllerGrip=function(D){let G=v[D];return G===void 0&&(G=new Ss,v[D]=G),G.getGripSpace()},this.getHand=function(D){let G=v[D];return G===void 0&&(G=new Ss,v[D]=G),G.getHandSpace()};function T(D){let G=x.indexOf(D.inputSource);if(G===-1)return;let he=v[G];he!==void 0&&(he.update(D.inputSource,D.frame,l||a),he.dispatchEvent({type:D.type,data:D.inputSource}))}function O(){i.removeEventListener("select",T),i.removeEventListener("selectstart",T),i.removeEventListener("selectend",T),i.removeEventListener("squeeze",T),i.removeEventListener("squeezestart",T),i.removeEventListener("squeezeend",T),i.removeEventListener("end",O),i.removeEventListener("inputsourceschange",Y);for(let D=0;D=0&&(x[fe]=null,v[fe].disconnect(he))}for(let G=0;G=x.length){x.push(he),fe=we;break}else if(x[we]===null){x[we]=he,fe=we;break}if(fe===-1)break}let _e=v[fe];_e&&_e.connect(he)}}let $=new A,U=new A;function z(D,G,he){$.setFromMatrixPosition(G.matrixWorld),U.setFromMatrixPosition(he.matrixWorld);let fe=$.distanceTo(U),_e=G.projectionMatrix.elements,we=he.projectionMatrix.elements,Ee=_e[14]/(_e[10]-1),Te=_e[14]/(_e[10]+1),Ye=(_e[9]+1)/_e[5],it=(_e[9]-1)/_e[5],Ce=(_e[8]-1)/_e[0],L=(we[8]+1)/we[0],oe=Ee*Ce,X=Ee*L,ie=fe/(-Ce+L),J=ie*-Ce;G.matrixWorld.decompose(D.position,D.quaternion,D.scale),D.translateX(J),D.translateZ(ie),D.matrixWorld.compose(D.position,D.quaternion,D.scale),D.matrixWorldInverse.copy(D.matrixWorld).invert();let Se=Ee+ie,me=Te+ie,ye=oe-J,Ne=X+(fe-J),qe=Ye*Te/me*Se,rt=it*Te/me*Se;D.projectionMatrix.makePerspective(ye,Ne,qe,rt,Se,me),D.projectionMatrixInverse.copy(D.projectionMatrix).invert()}function q(D,G){G===null?D.matrixWorld.copy(D.matrix):D.matrixWorld.multiplyMatrices(G.matrixWorld,D.matrix),D.matrixWorldInverse.copy(D.matrixWorld).invert()}this.updateCamera=function(D){if(i===null)return;R.near=b.near=y.near=D.near,R.far=b.far=y.far=D.far,(I!==R.near||M!==R.far)&&(i.updateRenderState({depthNear:R.near,depthFar:R.far}),I=R.near,M=R.far);let G=D.parent,he=R.cameras;q(R,G);for(let fe=0;fe0&&(g.alphaTest.value=p.alphaTest);let v=e.get(p).envMap;if(v&&(g.envMap.value=v,g.flipEnvMap.value=v.isCubeTexture&&v.isRenderTargetTexture===!1?-1:1,g.reflectivity.value=p.reflectivity,g.ior.value=p.ior,g.refractionRatio.value=p.refractionRatio),p.lightMap){g.lightMap.value=p.lightMap;let x=s._useLegacyLights===!0?Math.PI:1;g.lightMapIntensity.value=p.lightMapIntensity*x,t(p.lightMap,g.lightMapTransform)}p.aoMap&&(g.aoMap.value=p.aoMap,g.aoMapIntensity.value=p.aoMapIntensity,t(p.aoMap,g.aoMapTransform))}function a(g,p){g.diffuse.value.copy(p.color),g.opacity.value=p.opacity,p.map&&(g.map.value=p.map,t(p.map,g.mapTransform))}function o(g,p){g.dashSize.value=p.dashSize,g.totalSize.value=p.dashSize+p.gapSize,g.scale.value=p.scale}function c(g,p,v,x){g.diffuse.value.copy(p.color),g.opacity.value=p.opacity,g.size.value=p.size*v,g.scale.value=x*.5,p.map&&(g.map.value=p.map,t(p.map,g.uvTransform)),p.alphaMap&&(g.alphaMap.value=p.alphaMap,t(p.alphaMap,g.alphaMapTransform)),p.alphaTest>0&&(g.alphaTest.value=p.alphaTest)}function l(g,p){g.diffuse.value.copy(p.color),g.opacity.value=p.opacity,g.rotation.value=p.rotation,p.map&&(g.map.value=p.map,t(p.map,g.mapTransform)),p.alphaMap&&(g.alphaMap.value=p.alphaMap,t(p.alphaMap,g.alphaMapTransform)),p.alphaTest>0&&(g.alphaTest.value=p.alphaTest)}function h(g,p){g.specular.value.copy(p.specular),g.shininess.value=Math.max(p.shininess,1e-4)}function u(g,p){p.gradientMap&&(g.gradientMap.value=p.gradientMap)}function d(g,p){g.metalness.value=p.metalness,p.metalnessMap&&(g.metalnessMap.value=p.metalnessMap,t(p.metalnessMap,g.metalnessMapTransform)),g.roughness.value=p.roughness,p.roughnessMap&&(g.roughnessMap.value=p.roughnessMap,t(p.roughnessMap,g.roughnessMapTransform)),e.get(p).envMap&&(g.envMapIntensity.value=p.envMapIntensity)}function f(g,p,v){g.ior.value=p.ior,p.sheen>0&&(g.sheenColor.value.copy(p.sheenColor).multiplyScalar(p.sheen),g.sheenRoughness.value=p.sheenRoughness,p.sheenColorMap&&(g.sheenColorMap.value=p.sheenColorMap,t(p.sheenColorMap,g.sheenColorMapTransform)),p.sheenRoughnessMap&&(g.sheenRoughnessMap.value=p.sheenRoughnessMap,t(p.sheenRoughnessMap,g.sheenRoughnessMapTransform))),p.clearcoat>0&&(g.clearcoat.value=p.clearcoat,g.clearcoatRoughness.value=p.clearcoatRoughness,p.clearcoatMap&&(g.clearcoatMap.value=p.clearcoatMap,t(p.clearcoatMap,g.clearcoatMapTransform)),p.clearcoatRoughnessMap&&(g.clearcoatRoughnessMap.value=p.clearcoatRoughnessMap,t(p.clearcoatRoughnessMap,g.clearcoatRoughnessMapTransform)),p.clearcoatNormalMap&&(g.clearcoatNormalMap.value=p.clearcoatNormalMap,t(p.clearcoatNormalMap,g.clearcoatNormalMapTransform),g.clearcoatNormalScale.value.copy(p.clearcoatNormalScale),p.side===Ft&&g.clearcoatNormalScale.value.negate())),p.iridescence>0&&(g.iridescence.value=p.iridescence,g.iridescenceIOR.value=p.iridescenceIOR,g.iridescenceThicknessMinimum.value=p.iridescenceThicknessRange[0],g.iridescenceThicknessMaximum.value=p.iridescenceThicknessRange[1],p.iridescenceMap&&(g.iridescenceMap.value=p.iridescenceMap,t(p.iridescenceMap,g.iridescenceMapTransform)),p.iridescenceThicknessMap&&(g.iridescenceThicknessMap.value=p.iridescenceThicknessMap,t(p.iridescenceThicknessMap,g.iridescenceThicknessMapTransform))),p.transmission>0&&(g.transmission.value=p.transmission,g.transmissionSamplerMap.value=v.texture,g.transmissionSamplerSize.value.set(v.width,v.height),p.transmissionMap&&(g.transmissionMap.value=p.transmissionMap,t(p.transmissionMap,g.transmissionMapTransform)),g.thickness.value=p.thickness,p.thicknessMap&&(g.thicknessMap.value=p.thicknessMap,t(p.thicknessMap,g.thicknessMapTransform)),g.attenuationDistance.value=p.attenuationDistance,g.attenuationColor.value.copy(p.attenuationColor)),p.anisotropy>0&&(g.anisotropyVector.value.set(p.anisotropy*Math.cos(p.anisotropyRotation),p.anisotropy*Math.sin(p.anisotropyRotation)),p.anisotropyMap&&(g.anisotropyMap.value=p.anisotropyMap,t(p.anisotropyMap,g.anisotropyMapTransform))),g.specularIntensity.value=p.specularIntensity,g.specularColor.value.copy(p.specularColor),p.specularColorMap&&(g.specularColorMap.value=p.specularColorMap,t(p.specularColorMap,g.specularColorMapTransform)),p.specularIntensityMap&&(g.specularIntensityMap.value=p.specularIntensityMap,t(p.specularIntensityMap,g.specularIntensityMapTransform))}function m(g,p){p.matcap&&(g.matcap.value=p.matcap)}function _(g,p){let v=e.get(p).light;g.referencePosition.value.setFromMatrixPosition(v.matrixWorld),g.nearDistance.value=v.shadow.camera.near,g.farDistance.value=v.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:i}}function G0(s,e,t,n){let i={},r={},a=[],o=t.isWebGL2?s.getParameter(s.MAX_UNIFORM_BUFFER_BINDINGS):0;function c(v,x){let y=x.program;n.uniformBlockBinding(v,y)}function l(v,x){let y=i[v.id];y===void 0&&(m(v),y=h(v),i[v.id]=y,v.addEventListener("dispose",g));let b=x.program;n.updateUBOMapping(v,b);let w=e.render.frame;r[v.id]!==w&&(d(v),r[v.id]=w)}function h(v){let x=u();v.__bindingPointIndex=x;let y=s.createBuffer(),b=v.__size,w=v.usage;return s.bindBuffer(s.UNIFORM_BUFFER,y),s.bufferData(s.UNIFORM_BUFFER,b,w),s.bindBuffer(s.UNIFORM_BUFFER,null),s.bindBufferBase(s.UNIFORM_BUFFER,x,y),y}function u(){for(let v=0;v0){w=y%b;let Y=b-w;w!==0&&Y-T.boundary<0&&(y+=b-w,M.__offset=y)}y+=T.storage}return w=y%b,w>0&&(y+=b-w),v.__size=y,v.__cache={},this}function _(v){let x={boundary:0,storage:0};return typeof v=="number"?(x.boundary=4,x.storage=4):v.isVector2?(x.boundary=8,x.storage=8):v.isVector3||v.isColor?(x.boundary=16,x.storage=12):v.isVector4?(x.boundary=16,x.storage=16):v.isMatrix3?(x.boundary=48,x.storage=48):v.isMatrix4?(x.boundary=64,x.storage=64):v.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",v),x}function g(v){let x=v.target;x.removeEventListener("dispose",g);let y=a.indexOf(x.__bindingPointIndex);a.splice(y,1),s.deleteBuffer(i[x.id]),delete i[x.id],delete r[x.id]}function p(){for(let v in i)s.deleteBuffer(i[v]);a=[],i={},r={}}return{bind:c,update:l,dispose:p}}var Ro=class{constructor(e={}){let{canvas:t=tp(),context:n=null,depth:i=!0,stencil:r=!0,alpha:a=!1,antialias:o=!1,premultipliedAlpha:c=!0,preserveDrawingBuffer:l=!1,powerPreference:h="default",failIfMajorPerformanceCaveat:u=!1}=e;this.isWebGLRenderer=!0;let d;n!==null?d=n.getContextAttributes().alpha:d=a;let f=new Uint32Array(4),m=new Int32Array(4),_=null,g=null,p=[],v=[];this.domElement=t,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this._outputColorSpace=vt,this._useLegacyLights=!1,this.toneMapping=Nn,this.toneMappingExposure=1;let x=this,y=!1,b=0,w=0,R=null,I=-1,M=null,T=new je,O=new je,Y=null,$=new pe(0),U=0,z=t.width,q=t.height,H=1,ne=null,W=null,K=new je(0,0,z,q),D=new je(0,0,z,q),G=!1,he=new Ps,fe=!1,_e=!1,we=null,Ee=new ze,Te=new Z,Ye=new A,it={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};function Ce(){return R===null?H:1}let L=n;function oe(E,N){for(let V=0;V0?g=v[v.length-1]:g=null,p.pop(),p.length>0?_=p[p.length-1]:_=null};function jc(E,N,V,F){if(E.visible===!1)return;if(E.layers.test(N.layers)){if(E.isGroup)V=E.renderOrder;else if(E.isLOD)E.autoUpdate===!0&&E.update(N);else if(E.isLight)g.pushLight(E),E.castShadow&&g.pushShadow(E);else if(E.isSprite){if(!E.frustumCulled||he.intersectsSprite(E)){F&&Ye.setFromMatrixPosition(E.matrixWorld).applyMatrix4(Ee);let Ae=S.update(E),Ue=E.material;Ue.visible&&_.push(E,Ae,Ue,V,Ye.z,null)}}else if((E.isMesh||E.isLine||E.isPoints)&&(!E.frustumCulled||he.intersectsObject(E))){let Ae=S.update(E),Ue=E.material;if(F&&(E.boundingSphere!==void 0?(E.boundingSphere===null&&E.computeBoundingSphere(),Ye.copy(E.boundingSphere.center)):(Ae.boundingSphere===null&&Ae.computeBoundingSphere(),Ye.copy(Ae.boundingSphere.center)),Ye.applyMatrix4(E.matrixWorld).applyMatrix4(Ee)),Array.isArray(Ue)){let De=Ae.groups;for(let We=0,Pe=De.length;We0&&Od(k,xe,N,V),F&&J.viewport(T.copy(F)),k.length>0&&ks(k,N,V),xe.length>0&&ks(xe,N,V),Ae.length>0&&ks(Ae,N,V),J.buffers.depth.setTest(!0),J.buffers.depth.setMask(!0),J.buffers.color.setMask(!0),J.setPolygonOffset(!1)}function Od(E,N,V,F){let k=ie.isWebGL2;we===null&&(we=new qt(1,1,{generateMipmaps:!0,type:X.has("EXT_color_buffer_half_float")?Ts:On,minFilter:li,samples:k?4:0})),x.getDrawingBufferSize(Te),k?we.setSize(Te.x,Te.y):we.setSize(Wr(Te.x),Wr(Te.y));let xe=x.getRenderTarget();x.setRenderTarget(we),x.getClearColor($),U=x.getClearAlpha(),U<1&&x.setClearColor(16777215,.5),x.clear();let Ae=x.toneMapping;x.toneMapping=Nn,ks(E,V,F),ye.updateMultisampleRenderTarget(we),ye.updateRenderTargetMipmap(we);let Ue=!1;for(let De=0,We=N.length;De0),Ve=!!V.morphAttributes.position,at=!!V.morphAttributes.normal,lt=!!V.morphAttributes.color,Ht=Nn;F.toneMapped&&(R===null||R.isXRRenderTarget===!0)&&(Ht=x.toneMapping);let an=V.morphAttributes.position||V.morphAttributes.normal||V.morphAttributes.color,ut=an!==void 0?an.length:0,Xe=me.get(F),Sa=g.state.lights;if(fe===!0&&(_e===!0||E!==M)){let Bt=E===M&&F.id===I;Me.setState(F,E,Bt)}let dt=!1;F.version===Xe.__version?(Xe.needsLights&&Xe.lightsStateVersion!==Sa.state.version||Xe.outputColorSpace!==Ue||k.isInstancedMesh&&Xe.instancing===!1||!k.isInstancedMesh&&Xe.instancing===!0||k.isSkinnedMesh&&Xe.skinning===!1||!k.isSkinnedMesh&&Xe.skinning===!0||k.isInstancedMesh&&Xe.instancingColor===!0&&k.instanceColor===null||k.isInstancedMesh&&Xe.instancingColor===!1&&k.instanceColor!==null||Xe.envMap!==De||F.fog===!0&&Xe.fog!==xe||Xe.numClippingPlanes!==void 0&&(Xe.numClippingPlanes!==Me.numPlanes||Xe.numIntersection!==Me.numIntersection)||Xe.vertexAlphas!==We||Xe.vertexTangents!==Pe||Xe.morphTargets!==Ve||Xe.morphNormals!==at||Xe.morphColors!==lt||Xe.toneMapping!==Ht||ie.isWebGL2===!0&&Xe.morphTargetsCount!==ut)&&(dt=!0):(dt=!0,Xe.__version=F.version);let Hn=Xe.currentProgram;dt===!0&&(Hn=Hs(F,N,k));let il=!1,os=!1,ba=!1,Ct=Hn.getUniforms(),Gn=Xe.uniforms;if(J.useProgram(Hn.program)&&(il=!0,os=!0,ba=!0),F.id!==I&&(I=F.id,os=!0),il||M!==E){Ct.setValue(L,"projectionMatrix",E.projectionMatrix),Ct.setValue(L,"viewMatrix",E.matrixWorldInverse);let Bt=Ct.map.cameraPosition;Bt!==void 0&&Bt.setValue(L,Ye.setFromMatrixPosition(E.matrixWorld)),ie.logarithmicDepthBuffer&&Ct.setValue(L,"logDepthBufFC",2/(Math.log(E.far+1)/Math.LN2)),(F.isMeshPhongMaterial||F.isMeshToonMaterial||F.isMeshLambertMaterial||F.isMeshBasicMaterial||F.isMeshStandardMaterial||F.isShaderMaterial)&&Ct.setValue(L,"isOrthographic",E.isOrthographicCamera===!0),M!==E&&(M=E,os=!0,ba=!0)}if(k.isSkinnedMesh){Ct.setOptional(L,k,"bindMatrix"),Ct.setOptional(L,k,"bindMatrixInverse");let Bt=k.skeleton;Bt&&(ie.floatVertexTextures?(Bt.boneTexture===null&&Bt.computeBoneTexture(),Ct.setValue(L,"boneTexture",Bt.boneTexture,ye),Ct.setValue(L,"boneTextureSize",Bt.boneTextureSize)):console.warn("THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required."))}let Ea=V.morphAttributes;if((Ea.position!==void 0||Ea.normal!==void 0||Ea.color!==void 0&&ie.isWebGL2===!0)&&Le.update(k,V,Hn),(os||Xe.receiveShadow!==k.receiveShadow)&&(Xe.receiveShadow=k.receiveShadow,Ct.setValue(L,"receiveShadow",k.receiveShadow)),F.isMeshGouraudMaterial&&F.envMap!==null&&(Gn.envMap.value=De,Gn.flipEnvMap.value=De.isCubeTexture&&De.isRenderTargetTexture===!1?-1:1),os&&(Ct.setValue(L,"toneMappingExposure",x.toneMappingExposure),Xe.needsLights&&Bd(Gn,ba),xe&&F.fog===!0&&ee.refreshFogUniforms(Gn,xe),ee.refreshMaterialUniforms(Gn,F,H,q,we),qi.upload(L,Xe.uniformsList,Gn,ye)),F.isShaderMaterial&&F.uniformsNeedUpdate===!0&&(qi.upload(L,Xe.uniformsList,Gn,ye),F.uniformsNeedUpdate=!1),F.isSpriteMaterial&&Ct.setValue(L,"center",k.center),Ct.setValue(L,"modelViewMatrix",k.modelViewMatrix),Ct.setValue(L,"normalMatrix",k.normalMatrix),Ct.setValue(L,"modelMatrix",k.matrixWorld),F.isShaderMaterial||F.isRawShaderMaterial){let Bt=F.uniformsGroups;for(let Ta=0,Vd=Bt.length;Ta0&&ye.useMultisampledRTT(E)===!1?k=me.get(E).__webglMultisampledFramebuffer:Array.isArray(Pe)?k=Pe[V]:k=Pe,T.copy(E.viewport),O.copy(E.scissor),Y=E.scissorTest}else T.copy(K).multiplyScalar(H).floor(),O.copy(D).multiplyScalar(H).floor(),Y=G;if(J.bindFramebuffer(L.FRAMEBUFFER,k)&&ie.drawBuffers&&F&&J.drawBuffers(E,k),J.viewport(T),J.scissor(O),J.setScissorTest(Y),xe){let De=me.get(E.texture);L.framebufferTexture2D(L.FRAMEBUFFER,L.COLOR_ATTACHMENT0,L.TEXTURE_CUBE_MAP_POSITIVE_X+N,De.__webglTexture,V)}else if(Ae){let De=me.get(E.texture),We=N||0;L.framebufferTextureLayer(L.FRAMEBUFFER,L.COLOR_ATTACHMENT0,De.__webglTexture,V||0,We)}I=-1},this.readRenderTargetPixels=function(E,N,V,F,k,xe,Ae){if(!(E&&E.isWebGLRenderTarget)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");return}let Ue=me.get(E).__webglFramebuffer;if(E.isWebGLCubeRenderTarget&&Ae!==void 0&&(Ue=Ue[Ae]),Ue){J.bindFramebuffer(L.FRAMEBUFFER,Ue);try{let De=E.texture,We=De.format,Pe=De.type;if(We!==Wt&&$e.convert(We)!==L.getParameter(L.IMPLEMENTATION_COLOR_READ_FORMAT)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");return}let Ve=Pe===Ts&&(X.has("EXT_color_buffer_half_float")||ie.isWebGL2&&X.has("EXT_color_buffer_float"));if(Pe!==On&&$e.convert(Pe)!==L.getParameter(L.IMPLEMENTATION_COLOR_READ_TYPE)&&!(Pe===xn&&(ie.isWebGL2||X.has("OES_texture_float")||X.has("WEBGL_color_buffer_float")))&&!Ve){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");return}N>=0&&N<=E.width-F&&V>=0&&V<=E.height-k&&L.readPixels(N,V,F,k,$e.convert(We),$e.convert(Pe),xe)}finally{let De=R!==null?me.get(R).__webglFramebuffer:null;J.bindFramebuffer(L.FRAMEBUFFER,De)}}},this.copyFramebufferToTexture=function(E,N,V=0){let F=Math.pow(2,-V),k=Math.floor(N.image.width*F),xe=Math.floor(N.image.height*F);ye.setTexture2D(N,0),L.copyTexSubImage2D(L.TEXTURE_2D,V,0,0,E.x,E.y,k,xe),J.unbindTexture()},this.copyTextureToTexture=function(E,N,V,F=0){let k=N.image.width,xe=N.image.height,Ae=$e.convert(V.format),Ue=$e.convert(V.type);ye.setTexture2D(V,0),L.pixelStorei(L.UNPACK_FLIP_Y_WEBGL,V.flipY),L.pixelStorei(L.UNPACK_PREMULTIPLY_ALPHA_WEBGL,V.premultiplyAlpha),L.pixelStorei(L.UNPACK_ALIGNMENT,V.unpackAlignment),N.isDataTexture?L.texSubImage2D(L.TEXTURE_2D,F,E.x,E.y,k,xe,Ae,Ue,N.image.data):N.isCompressedTexture?L.compressedTexSubImage2D(L.TEXTURE_2D,F,E.x,E.y,N.mipmaps[0].width,N.mipmaps[0].height,Ae,N.mipmaps[0].data):L.texSubImage2D(L.TEXTURE_2D,F,E.x,E.y,Ae,Ue,N.image),F===0&&V.generateMipmaps&&L.generateMipmap(L.TEXTURE_2D),J.unbindTexture()},this.copyTextureToTexture3D=function(E,N,V,F,k=0){if(x.isWebGL1Renderer){console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.");return}let xe=E.max.x-E.min.x+1,Ae=E.max.y-E.min.y+1,Ue=E.max.z-E.min.z+1,De=$e.convert(F.format),We=$e.convert(F.type),Pe;if(F.isData3DTexture)ye.setTexture3D(F,0),Pe=L.TEXTURE_3D;else if(F.isDataArrayTexture)ye.setTexture2DArray(F,0),Pe=L.TEXTURE_2D_ARRAY;else{console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.");return}L.pixelStorei(L.UNPACK_FLIP_Y_WEBGL,F.flipY),L.pixelStorei(L.UNPACK_PREMULTIPLY_ALPHA_WEBGL,F.premultiplyAlpha),L.pixelStorei(L.UNPACK_ALIGNMENT,F.unpackAlignment);let Ve=L.getParameter(L.UNPACK_ROW_LENGTH),at=L.getParameter(L.UNPACK_IMAGE_HEIGHT),lt=L.getParameter(L.UNPACK_SKIP_PIXELS),Ht=L.getParameter(L.UNPACK_SKIP_ROWS),an=L.getParameter(L.UNPACK_SKIP_IMAGES),ut=V.isCompressedTexture?V.mipmaps[0]:V.image;L.pixelStorei(L.UNPACK_ROW_LENGTH,ut.width),L.pixelStorei(L.UNPACK_IMAGE_HEIGHT,ut.height),L.pixelStorei(L.UNPACK_SKIP_PIXELS,E.min.x),L.pixelStorei(L.UNPACK_SKIP_ROWS,E.min.y),L.pixelStorei(L.UNPACK_SKIP_IMAGES,E.min.z),V.isDataTexture||V.isData3DTexture?L.texSubImage3D(Pe,k,N.x,N.y,N.z,xe,Ae,Ue,De,We,ut.data):V.isCompressedArrayTexture?(console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture."),L.compressedTexSubImage3D(Pe,k,N.x,N.y,N.z,xe,Ae,Ue,De,ut.data)):L.texSubImage3D(Pe,k,N.x,N.y,N.z,xe,Ae,Ue,De,We,ut),L.pixelStorei(L.UNPACK_ROW_LENGTH,Ve),L.pixelStorei(L.UNPACK_IMAGE_HEIGHT,at),L.pixelStorei(L.UNPACK_SKIP_PIXELS,lt),L.pixelStorei(L.UNPACK_SKIP_ROWS,Ht),L.pixelStorei(L.UNPACK_SKIP_IMAGES,an),k===0&&F.generateMipmaps&&L.generateMipmap(Pe),J.unbindTexture()},this.initTexture=function(E){E.isCubeTexture?ye.setTextureCube(E,0):E.isData3DTexture?ye.setTexture3D(E,0):E.isDataArrayTexture||E.isCompressedArrayTexture?ye.setTexture2DArray(E,0):ye.setTexture2D(E,0),J.unbindTexture()},this.resetState=function(){b=0,w=0,R=null,J.reset(),Oe.reset()},typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}get coordinateSystem(){return vn}get outputColorSpace(){return this._outputColorSpace}set outputColorSpace(e){this._outputColorSpace=e;let t=this.getContext();t.drawingBufferColorSpace=e===qc?"display-p3":"srgb",t.unpackColorSpace=Qe.workingColorSpace===va?"display-p3":"srgb"}get physicallyCorrectLights(){return console.warn("THREE.WebGLRenderer: The property .physicallyCorrectLights has been removed. Set renderer.useLegacyLights instead."),!this.useLegacyLights}set physicallyCorrectLights(e){console.warn("THREE.WebGLRenderer: The property .physicallyCorrectLights has been removed. Set renderer.useLegacyLights instead."),this.useLegacyLights=!e}get outputEncoding(){return console.warn("THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead."),this.outputColorSpace===vt?ri:vd}set outputEncoding(e){console.warn("THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead."),this.outputColorSpace=e===ri?vt:Mn}get useLegacyLights(){return console.warn("THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733."),this._useLegacyLights}set useLegacyLights(e){console.warn("THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733."),this._useLegacyLights=e}},Co=class extends Ro{};Co.prototype.isWebGL1Renderer=!0;var Po=class s{constructor(e,t=25e-5){this.isFogExp2=!0,this.name="",this.color=new pe(e),this.density=t}clone(){return new s(this.color,this.density)}toJSON(){return{type:"FogExp2",name:this.name,color:this.color.getHex(),density:this.density}}},Lo=class s{constructor(e,t=1,n=1e3){this.isFog=!0,this.name="",this.color=new pe(e),this.near=t,this.far=n}clone(){return new s(this.color,this.near,this.far)}toJSON(){return{type:"Fog",name:this.name,color:this.color.getHex(),near:this.near,far:this.far}}},Io=class extends Je{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.overrideMaterial=null,typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),e.background!==null&&(this.background=e.background.clone()),e.environment!==null&&(this.environment=e.environment.clone()),e.fog!==null&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,e.overrideMaterial!==null&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){let t=super.toJSON(e);return this.fog!==null&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),this.backgroundIntensity!==1&&(t.object.backgroundIntensity=this.backgroundIntensity),t}},Is=class{constructor(e,t){this.isInterleavedBuffer=!0,this.array=e,this.stride=t,this.count=e!==void 0?e.length/t:0,this.usage=Hr,this.updateRange={offset:0,count:-1},this.version=0,this.uuid=kt()}onUploadCallback(){}set needsUpdate(e){e===!0&&this.version++}setUsage(e){return this.usage=e,this}copy(e){return this.array=new e.array.constructor(e.array),this.count=e.count,this.stride=e.stride,this.usage=e.usage,this}copyAt(e,t,n){e*=this.stride,n*=t.stride;for(let i=0,r=this.stride;ie.far||t.push({distance:c,point:ds.clone(),uv:Un.getInterpolation(ds,hr,ps,ur,Lh,ja,Ih,new Z),face:null,object:this})}copy(e,t){return super.copy(e,t),e.center!==void 0&&this.center.copy(e.center),this.material=e.material,this}};function dr(s,e,t,n,i,r){Ni.subVectors(s,t).addScalar(.5).multiply(n),i!==void 0?(fs.x=r*Ni.x-i*Ni.y,fs.y=i*Ni.x+r*Ni.y):fs.copy(Ni),s.copy(e),s.x+=fs.x,s.y+=fs.y,s.applyMatrix4(Cd)}var fr=new A,Uh=new A,Do=class extends Je{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(e){super.copy(e,!1);let t=e.levels;for(let n=0,i=t.length;n0){let n,i;for(n=1,i=t.length;n0){fr.setFromMatrixPosition(this.matrixWorld);let i=e.ray.origin.distanceTo(fr);this.getObjectForDistance(i).raycast(e,t)}}update(e){let t=this.levels;if(t.length>1){fr.setFromMatrixPosition(e.matrixWorld),Uh.setFromMatrixPosition(this.matrixWorld);let n=fr.distanceTo(Uh)/e.zoom;t[0].object.visible=!0;let i,r;for(i=1,r=t.length;i=a)t[i-1].object.visible=!1,t[i].object.visible=!0;else break}for(this._currentLevel=i-1;ic)continue;d.applyMatrix4(this.matrixWorld);let I=e.ray.origin.distanceTo(d);Ie.far||t.push({distance:I,point:u.clone().applyMatrix4(this.matrixWorld),index:x,face:null,faceIndex:null,object:this})}}else{let p=Math.max(0,a.start),v=Math.min(g.count,a.start+a.count);for(let x=p,y=v-1;xc)continue;d.applyMatrix4(this.matrixWorld);let w=e.ray.origin.distanceTo(d);we.far||t.push({distance:w,point:u.clone().applyMatrix4(this.matrixWorld),index:x,face:null,faceIndex:null,object:this})}}}updateMorphTargets(){let t=this.geometry.morphAttributes,n=Object.keys(t);if(n.length>0){let i=t[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,a=i.length;r0){let i=t[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,a=i.length;ri.far)return;r.push({distance:l,distanceToRay:Math.sqrt(o),point:c,index:e,face:null,object:a})}}var Jh=class extends St{constructor(e,t,n,i,r,a,o,c,l){super(e,t,n,i,r,a,o,c,l),this.isVideoTexture=!0,this.minFilter=a!==void 0?a:mt,this.magFilter=r!==void 0?r:mt,this.generateMipmaps=!1;let h=this;function u(){h.needsUpdate=!0,e.requestVideoFrameCallback(u)}"requestVideoFrameCallback"in e&&e.requestVideoFrameCallback(u)}clone(){return new this.constructor(this.image).copy(this)}update(){let e=this.image;"requestVideoFrameCallback"in e===!1&&e.readyState>=e.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}},$h=class extends St{constructor(e,t){super({width:e,height:t}),this.isFramebufferTexture=!0,this.magFilter=pt,this.minFilter=pt,this.generateMipmaps=!1,this.needsUpdate=!0}},Us=class extends St{constructor(e,t,n,i,r,a,o,c,l,h,u,d){super(null,a,o,c,l,h,i,r,u,d),this.isCompressedTexture=!0,this.image={width:t,height:n},this.mipmaps=e,this.flipY=!1,this.generateMipmaps=!1}},Kh=class extends Us{constructor(e,t,n,i,r,a){super(e,t,n,r,a),this.isCompressedArrayTexture=!0,this.image.depth=i,this.wrapR=It}},Qh=class extends Us{constructor(e,t,n){super(void 0,e[0].width,e[0].height,t,n,zn),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=e}},jh=class extends St{constructor(e,t,n,i,r,a,o,c,l){super(e,t,n,i,r,a,o,c,l),this.isCanvasTexture=!0,this.needsUpdate=!0}},Zt=class{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(e,t){let n=this.getUtoTmapping(e);return this.getPoint(n,t)}getPoints(e=5){let t=[];for(let n=0;n<=e;n++)t.push(this.getPoint(n/e));return t}getSpacedPoints(e=5){let t=[];for(let n=0;n<=e;n++)t.push(this.getPointAt(n/e));return t}getLength(){let e=this.getLengths();return e[e.length-1]}getLengths(e=this.arcLengthDivisions){if(this.cacheArcLengths&&this.cacheArcLengths.length===e+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;let t=[],n,i=this.getPoint(0),r=0;t.push(0);for(let a=1;a<=e;a++)n=this.getPoint(a/e),r+=n.distanceTo(i),t.push(r),i=n;return this.cacheArcLengths=t,t}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(e,t){let n=this.getLengths(),i=0,r=n.length,a;t?a=t:a=e*n[r-1];let o=0,c=r-1,l;for(;o<=c;)if(i=Math.floor(o+(c-o)/2),l=n[i]-a,l<0)o=i+1;else if(l>0)c=i-1;else{c=i;break}if(i=c,n[i]===a)return i/(r-1);let h=n[i],d=n[i+1]-h,f=(a-h)/d;return(i+f)/(r-1)}getTangent(e,t){let i=e-1e-4,r=e+1e-4;i<0&&(i=0),r>1&&(r=1);let a=this.getPoint(i),o=this.getPoint(r),c=t||(a.isVector2?new Z:new A);return c.copy(o).sub(a).normalize(),c}getTangentAt(e,t){let n=this.getUtoTmapping(e);return this.getTangent(n,t)}computeFrenetFrames(e,t){let n=new A,i=[],r=[],a=[],o=new A,c=new ze;for(let f=0;f<=e;f++){let m=f/e;i[f]=this.getTangentAt(m,new A)}r[0]=new A,a[0]=new A;let l=Number.MAX_VALUE,h=Math.abs(i[0].x),u=Math.abs(i[0].y),d=Math.abs(i[0].z);h<=l&&(l=h,n.set(1,0,0)),u<=l&&(l=u,n.set(0,1,0)),d<=l&&n.set(0,0,1),o.crossVectors(i[0],n).normalize(),r[0].crossVectors(i[0],o),a[0].crossVectors(i[0],r[0]);for(let f=1;f<=e;f++){if(r[f]=r[f-1].clone(),a[f]=a[f-1].clone(),o.crossVectors(i[f-1],i[f]),o.length()>Number.EPSILON){o.normalize();let m=Math.acos(ct(i[f-1].dot(i[f]),-1,1));r[f].applyMatrix4(c.makeRotationAxis(o,m))}a[f].crossVectors(i[f],r[f])}if(t===!0){let f=Math.acos(ct(r[0].dot(r[e]),-1,1));f/=e,i[0].dot(o.crossVectors(r[0],r[e]))>0&&(f=-f);for(let m=1;m<=e;m++)r[m].applyMatrix4(c.makeRotationAxis(i[m],f*m)),a[m].crossVectors(i[m],r[m])}return{tangents:i,normals:r,binormals:a}}clone(){return new this.constructor().copy(this)}copy(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}toJSON(){let e={metadata:{version:4.6,type:"Curve",generator:"Curve.toJSON"}};return e.arcLengthDivisions=this.arcLengthDivisions,e.type=this.type,e}fromJSON(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}},Ds=class extends Zt{constructor(e=0,t=0,n=1,i=1,r=0,a=Math.PI*2,o=!1,c=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=e,this.aY=t,this.xRadius=n,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=a,this.aClockwise=o,this.aRotation=c}getPoint(e,t){let n=t||new Z,i=Math.PI*2,r=this.aEndAngle-this.aStartAngle,a=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(o)/r)+1)*r:c===0&&o===r-1&&(o=r-2,c=1);let l,h;this.closed||o>0?l=i[(o-1)%r]:(xr.subVectors(i[0],i[1]).add(i[0]),l=xr);let u=i[o%r],d=i[(o+1)%r];if(this.closed||o+2i.length-2?i.length-1:a+1],u=i[a>i.length-3?i.length-1:a+2];return n.set(eu(o,c.x,l.x,h.x,u.x),eu(o,c.y,l.y,h.y,u.y)),n}copy(e){super.copy(e),this.points=[];for(let t=0,n=e.points.length;t=n){let a=i[r]-n,o=this.curves[r],c=o.getLength(),l=c===0?0:1-a/c;return o.getPointAt(l,t)}r++}return null}getLength(){let e=this.getCurveLengths();return e[e.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;let e=[],t=0;for(let n=0,i=this.curves.length;n1&&!t[t.length-1].equals(t[0])&&t.push(t[0]),t}copy(e){super.copy(e),this.curves=[];for(let t=0,n=e.curves.length;t0){let u=l.getPoint(0);u.equals(this.currentPoint)||this.lineTo(u.x,u.y)}this.curves.push(l);let h=l.getPoint(1);return this.currentPoint.copy(h),this}copy(e){return super.copy(e),this.currentPoint.copy(e.currentPoint),this}toJSON(){let e=super.toJSON();return e.currentPoint=this.currentPoint.toArray(),e}fromJSON(e){return super.fromJSON(e),this.currentPoint.fromArray(e.currentPoint),this}},la=class s extends Ge{constructor(e=[new Z(0,-.5),new Z(.5,0),new Z(0,.5)],t=12,n=0,i=Math.PI*2){super(),this.type="LatheGeometry",this.parameters={points:e,segments:t,phiStart:n,phiLength:i},t=Math.floor(t),i=ct(i,0,Math.PI*2);let r=[],a=[],o=[],c=[],l=[],h=1/t,u=new A,d=new Z,f=new A,m=new A,_=new A,g=0,p=0;for(let v=0;v<=e.length-1;v++)switch(v){case 0:g=e[v+1].x-e[v].x,p=e[v+1].y-e[v].y,f.x=p*1,f.y=-g,f.z=p*0,_.copy(f),f.normalize(),c.push(f.x,f.y,f.z);break;case e.length-1:c.push(_.x,_.y,_.z);break;default:g=e[v+1].x-e[v].x,p=e[v+1].y-e[v].y,f.x=p*1,f.y=-g,f.z=p*0,m.copy(f),f.x+=_.x,f.y+=_.y,f.z+=_.z,f.normalize(),c.push(f.x,f.y,f.z),_.copy(m)}for(let v=0;v<=t;v++){let x=n+v*h*i,y=Math.sin(x),b=Math.cos(x);for(let w=0;w<=e.length-1;w++){u.x=e[w].x*y,u.y=e[w].y,u.z=e[w].x*b,a.push(u.x,u.y,u.z),d.x=v/t,d.y=w/(e.length-1),o.push(d.x,d.y);let R=c[3*w+0]*y,I=c[3*w+1],M=c[3*w+0]*b;l.push(R,I,M)}}for(let v=0;v0&&x(!0),t>0&&x(!1)),this.setIndex(h),this.setAttribute("position",new ve(u,3)),this.setAttribute("normal",new ve(d,3)),this.setAttribute("uv",new ve(f,2));function v(){let y=new A,b=new A,w=0,R=(t-e)/n;for(let I=0;I<=r;I++){let M=[],T=I/r,O=T*(t-e)+e;for(let Y=0;Y<=i;Y++){let $=Y/i,U=$*c+o,z=Math.sin(U),q=Math.cos(U);b.x=O*z,b.y=-T*n+g,b.z=O*q,u.push(b.x,b.y,b.z),y.set(z,R,q).normalize(),d.push(y.x,y.y,y.z),f.push($,1-T),M.push(m++)}_.push(M)}for(let I=0;I.9&&R<.1&&(x<.2&&(a[v+0]+=1),y<.2&&(a[v+2]+=1),b<.2&&(a[v+4]+=1))}}function d(v){r.push(v.x,v.y,v.z)}function f(v,x){let y=v*3;x.x=e[y+0],x.y=e[y+1],x.z=e[y+2]}function m(){let v=new A,x=new A,y=new A,b=new A,w=new Z,R=new Z,I=new Z;for(let M=0,T=0;M80*t){o=l=s[0],c=h=s[1];for(let m=t;ml&&(l=u),d>h&&(h=d);f=Math.max(l-o,h-c),f=f!==0?32767/f:0}return Os(r,a,t,o,c,f,0),a}};function Pd(s,e,t,n,i){let r,a;if(i===gx(s,e,t,n)>0)for(r=e;r=e;r-=n)a=tu(r,s[r],s[r+1],a);return a&&Ma(a,a.next)&&(Bs(a),a=a.next),a}function fi(s,e){if(!s)return s;e||(e=s);let t=s,n;do if(n=!1,!t.steiner&&(Ma(t,t.next)||st(t.prev,t,t.next)===0)){if(Bs(t),t=e=t.prev,t===t.next)break;n=!0}else t=t.next;while(n||t!==e);return e}function Os(s,e,t,n,i,r,a){if(!s)return;!a&&r&&hx(s,n,i,r);let o=s,c,l;for(;s.prev!==s.next;){if(c=s.prev,l=s.next,r?nx(s,n,i,r):tx(s)){e.push(c.i/t|0),e.push(s.i/t|0),e.push(l.i/t|0),Bs(s),s=l.next,o=l.next;continue}if(s=l,s===o){a?a===1?(s=ix(fi(s),e,t),Os(s,e,t,n,i,r,2)):a===2&&sx(s,e,t,n,i,r):Os(fi(s),e,t,n,i,r,1);break}}}function tx(s){let e=s.prev,t=s,n=s.next;if(st(e,t,n)>=0)return!1;let i=e.x,r=t.x,a=n.x,o=e.y,c=t.y,l=n.y,h=ir?i>a?i:a:r>a?r:a,f=o>c?o>l?o:l:c>l?c:l,m=n.next;for(;m!==e;){if(m.x>=h&&m.x<=d&&m.y>=u&&m.y<=f&&Gi(i,o,r,c,a,l,m.x,m.y)&&st(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function nx(s,e,t,n){let i=s.prev,r=s,a=s.next;if(st(i,r,a)>=0)return!1;let o=i.x,c=r.x,l=a.x,h=i.y,u=r.y,d=a.y,f=oc?o>l?o:l:c>l?c:l,g=h>u?h>d?h:d:u>d?u:d,p=Ko(f,m,e,t,n),v=Ko(_,g,e,t,n),x=s.prevZ,y=s.nextZ;for(;x&&x.z>=p&&y&&y.z<=v;){if(x.x>=f&&x.x<=_&&x.y>=m&&x.y<=g&&x!==i&&x!==a&&Gi(o,h,c,u,l,d,x.x,x.y)&&st(x.prev,x,x.next)>=0||(x=x.prevZ,y.x>=f&&y.x<=_&&y.y>=m&&y.y<=g&&y!==i&&y!==a&&Gi(o,h,c,u,l,d,y.x,y.y)&&st(y.prev,y,y.next)>=0))return!1;y=y.nextZ}for(;x&&x.z>=p;){if(x.x>=f&&x.x<=_&&x.y>=m&&x.y<=g&&x!==i&&x!==a&&Gi(o,h,c,u,l,d,x.x,x.y)&&st(x.prev,x,x.next)>=0)return!1;x=x.prevZ}for(;y&&y.z<=v;){if(y.x>=f&&y.x<=_&&y.y>=m&&y.y<=g&&y!==i&&y!==a&&Gi(o,h,c,u,l,d,y.x,y.y)&&st(y.prev,y,y.next)>=0)return!1;y=y.nextZ}return!0}function ix(s,e,t){let n=s;do{let i=n.prev,r=n.next.next;!Ma(i,r)&&Ld(i,n,n.next,r)&&Fs(i,r)&&Fs(r,i)&&(e.push(i.i/t|0),e.push(n.i/t|0),e.push(r.i/t|0),Bs(n),Bs(n.next),n=s=r),n=n.next}while(n!==s);return fi(n)}function sx(s,e,t,n,i,r){let a=s;do{let o=a.next.next;for(;o!==a.prev;){if(a.i!==o.i&&fx(a,o)){let c=Id(a,o);a=fi(a,a.next),c=fi(c,c.next),Os(a,e,t,n,i,r,0),Os(c,e,t,n,i,r,0);return}o=o.next}a=a.next}while(a!==s)}function rx(s,e,t,n){let i=[],r,a,o,c,l;for(r=0,a=e.length;r=t.next.y&&t.next.y!==t.y){let d=t.x+(a-t.y)*(t.next.x-t.x)/(t.next.y-t.y);if(d<=r&&d>n&&(n=d,i=t.x=t.x&&t.x>=c&&r!==t.x&&Gi(ai.x||t.x===i.x&&lx(i,t)))&&(i=t,h=u)),t=t.next;while(t!==o);return i}function lx(s,e){return st(s.prev,s,e.prev)<0&&st(e.next,s,s.next)<0}function hx(s,e,t,n){let i=s;do i.z===0&&(i.z=Ko(i.x,i.y,e,t,n)),i.prevZ=i.prev,i.nextZ=i.next,i=i.next;while(i!==s);i.prevZ.nextZ=null,i.prevZ=null,ux(i)}function ux(s){let e,t,n,i,r,a,o,c,l=1;do{for(t=s,s=null,r=null,a=0;t;){for(a++,n=t,o=0,e=0;e0||c>0&&n;)o!==0&&(c===0||!n||t.z<=n.z)?(i=t,t=t.nextZ,o--):(i=n,n=n.nextZ,c--),r?r.nextZ=i:s=i,i.prevZ=r,r=i;t=n}r.nextZ=null,l*=2}while(a>1);return s}function Ko(s,e,t,n,i){return s=(s-t)*i|0,e=(e-n)*i|0,s=(s|s<<8)&16711935,s=(s|s<<4)&252645135,s=(s|s<<2)&858993459,s=(s|s<<1)&1431655765,e=(e|e<<8)&16711935,e=(e|e<<4)&252645135,e=(e|e<<2)&858993459,e=(e|e<<1)&1431655765,s|e<<1}function dx(s){let e=s,t=s;do(e.x=(s-a)*(r-o)&&(s-a)*(n-o)>=(t-a)*(e-o)&&(t-a)*(r-o)>=(i-a)*(n-o)}function fx(s,e){return s.next.i!==e.i&&s.prev.i!==e.i&&!px(s,e)&&(Fs(s,e)&&Fs(e,s)&&mx(s,e)&&(st(s.prev,s,e.prev)||st(s,e.prev,e))||Ma(s,e)&&st(s.prev,s,s.next)>0&&st(e.prev,e,e.next)>0)}function st(s,e,t){return(e.y-s.y)*(t.x-e.x)-(e.x-s.x)*(t.y-e.y)}function Ma(s,e){return s.x===e.x&&s.y===e.y}function Ld(s,e,t,n){let i=br(st(s,e,t)),r=br(st(s,e,n)),a=br(st(t,n,s)),o=br(st(t,n,e));return!!(i!==r&&a!==o||i===0&&Sr(s,t,e)||r===0&&Sr(s,n,e)||a===0&&Sr(t,s,n)||o===0&&Sr(t,e,n))}function Sr(s,e,t){return e.x<=Math.max(s.x,t.x)&&e.x>=Math.min(s.x,t.x)&&e.y<=Math.max(s.y,t.y)&&e.y>=Math.min(s.y,t.y)}function br(s){return s>0?1:s<0?-1:0}function px(s,e){let t=s;do{if(t.i!==s.i&&t.next.i!==s.i&&t.i!==e.i&&t.next.i!==e.i&&Ld(t,t.next,s,e))return!0;t=t.next}while(t!==s);return!1}function Fs(s,e){return st(s.prev,s,s.next)<0?st(s,e,s.next)>=0&&st(s,s.prev,e)>=0:st(s,e,s.prev)<0||st(s,s.next,e)<0}function mx(s,e){let t=s,n=!1,i=(s.x+e.x)/2,r=(s.y+e.y)/2;do t.y>r!=t.next.y>r&&t.next.y!==t.y&&i<(t.next.x-t.x)*(r-t.y)/(t.next.y-t.y)+t.x&&(n=!n),t=t.next;while(t!==s);return n}function Id(s,e){let t=new Qo(s.i,s.x,s.y),n=new Qo(e.i,e.x,e.y),i=s.next,r=e.prev;return s.next=e,e.prev=s,t.next=i,i.prev=t,n.next=t,t.prev=n,r.next=n,n.prev=r,n}function tu(s,e,t,n){let i=new Qo(s,e,t);return n?(i.next=n.next,i.prev=n,n.next.prev=i,n.next=i):(i.prev=i,i.next=i),i}function Bs(s){s.next.prev=s.prev,s.prev.next=s.next,s.prevZ&&(s.prevZ.nextZ=s.nextZ),s.nextZ&&(s.nextZ.prevZ=s.prevZ)}function Qo(s,e,t){this.i=s,this.x=e,this.y=t,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}function gx(s,e,t,n){let i=0;for(let r=e,a=t-n;r2&&s[e-1].equals(s[0])&&s.pop()}function iu(s,e){for(let t=0;tNumber.EPSILON){let S=Math.sqrt(rt),B=Math.sqrt(Ne*Ne+qe*qe),ee=oe.x-ye/S,j=oe.y+me/S,te=X.x-qe/B,Me=X.y+Ne/B,re=((te-ee)*qe-(Me-j)*Ne)/(me*qe-ye*Ne);ie=ee+me*re-L.x,J=j+ye*re-L.y;let de=ie*ie+J*J;if(de<=2)return new Z(ie,J);Se=Math.sqrt(de/2)}else{let S=!1;me>Number.EPSILON?Ne>Number.EPSILON&&(S=!0):me<-Number.EPSILON?Ne<-Number.EPSILON&&(S=!0):Math.sign(ye)===Math.sign(qe)&&(S=!0),S?(ie=-ye,J=me,Se=Math.sqrt(rt)):(ie=me,J=ye,Se=Math.sqrt(rt/2))}return new Z(ie/Se,J/Se)}let W=[];for(let L=0,oe=U.length,X=oe-1,ie=L+1;L=0;L--){let oe=L/g,X=f*Math.cos(oe*Math.PI/2),ie=m*Math.sin(oe*Math.PI/2)+_;for(let J=0,Se=U.length;J=0;){let ie=X,J=X-1;J<0&&(J=L.length-1);for(let Se=0,me=h+g*2;Se0)&&f.push(x,y,w),(p!==n-1||c0!=e>0&&this.version++,this._anisotropy=e}get clearcoat(){return this._clearcoat}set clearcoat(e){this._clearcoat>0!=e>0&&this.version++,this._clearcoat=e}get iridescence(){return this._iridescence}set iridescence(e){this._iridescence>0!=e>0&&this.version++,this._iridescence=e}get sheen(){return this._sheen}set sheen(e){this._sheen>0!=e>0&&this.version++,this._sheen=e}get transmission(){return this._transmission}set transmission(e){this._transmission>0!=e>0&&this.version++,this._transmission=e}copy(e){return super.copy(e),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=e.anisotropy,this.anisotropyRotation=e.anisotropyRotation,this.anisotropyMap=e.anisotropyMap,this.clearcoat=e.clearcoat,this.clearcoatMap=e.clearcoatMap,this.clearcoatRoughness=e.clearcoatRoughness,this.clearcoatRoughnessMap=e.clearcoatRoughnessMap,this.clearcoatNormalMap=e.clearcoatNormalMap,this.clearcoatNormalScale.copy(e.clearcoatNormalScale),this.ior=e.ior,this.iridescence=e.iridescence,this.iridescenceMap=e.iridescenceMap,this.iridescenceIOR=e.iridescenceIOR,this.iridescenceThicknessRange=[...e.iridescenceThicknessRange],this.iridescenceThicknessMap=e.iridescenceThicknessMap,this.sheen=e.sheen,this.sheenColor.copy(e.sheenColor),this.sheenColorMap=e.sheenColorMap,this.sheenRoughness=e.sheenRoughness,this.sheenRoughnessMap=e.sheenRoughnessMap,this.transmission=e.transmission,this.transmissionMap=e.transmissionMap,this.thickness=e.thickness,this.thicknessMap=e.thicknessMap,this.attenuationDistance=e.attenuationDistance,this.attenuationColor.copy(e.attenuationColor),this.specularIntensity=e.specularIntensity,this.specularIntensityMap=e.specularIntensityMap,this.specularColor.copy(e.specularColor),this.specularColorMap=e.specularColorMap,this}},uc=class extends bt{constructor(e){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new pe(16777215),this.specular=new pe(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new pe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=mi,this.normalScale=new Z(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=xa,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.specular.copy(e.specular),this.shininess=e.shininess,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}},dc=class extends bt{constructor(e){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new pe(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new pe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=mi,this.normalScale=new Z(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.gradientMap=e.gradientMap,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}},fc=class extends bt{constructor(e){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=mi,this.normalScale=new Z(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.setValues(e)}copy(e){return super.copy(e),this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.flatShading=e.flatShading,this}},pc=class extends bt{constructor(e){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new pe(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new pe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=mi,this.normalScale=new Z(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=xa,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}},mc=class extends bt{constructor(e){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new pe(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=mi,this.normalScale=new Z(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.defines={MATCAP:""},this.color.copy(e.color),this.matcap=e.matcap,this.map=e.map,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.alphaMap=e.alphaMap,this.flatShading=e.flatShading,this.fog=e.fog,this}},gc=class extends wt{constructor(e){super(),this.isLineDashedMaterial=!0,this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(e)}copy(e){return super.copy(e),this.scale=e.scale,this.dashSize=e.dashSize,this.gapSize=e.gapSize,this}};function ni(s,e,t){return!s||!t&&s.constructor===e?s:typeof e.BYTES_PER_ELEMENT=="number"?new e(s):Array.prototype.slice.call(s)}function Ud(s){return ArrayBuffer.isView(s)&&!(s instanceof DataView)}function Dd(s){function e(i,r){return s[i]-s[r]}let t=s.length,n=new Array(t);for(let i=0;i!==t;++i)n[i]=i;return n.sort(e),n}function _c(s,e,t){let n=s.length,i=new s.constructor(n);for(let r=0,a=0;a!==n;++r){let o=t[r]*e;for(let c=0;c!==e;++c)i[a++]=s[o+c]}return i}function $c(s,e,t,n){let i=1,r=s[0];for(;r!==void 0&&r[n]===void 0;)r=s[i++];if(r===void 0)return;let a=r[n];if(a!==void 0)if(Array.isArray(a))do a=r[n],a!==void 0&&(e.push(r.time),t.push.apply(t,a)),r=s[i++];while(r!==void 0);else if(a.toArray!==void 0)do a=r[n],a!==void 0&&(e.push(r.time),a.toArray(t,t.length)),r=s[i++];while(r!==void 0);else do a=r[n],a!==void 0&&(e.push(r.time),t.push(a)),r=s[i++];while(r!==void 0)}function yx(s,e,t,n,i=30){let r=s.clone();r.name=e;let a=[];for(let c=0;c=n)){u.push(l.times[f]);for(let _=0;_r.tracks[c].times[0]&&(o=r.tracks[c].times[0]);for(let c=0;c=o.times[m]){let p=m*u+h,v=p+u-h;_=o.values.slice(p,v)}else{let p=o.createInterpolant(),v=h,x=u-h;p.evaluate(r),_=p.resultBuffer.slice(v,x)}c==="quaternion"&&new Ut().fromArray(_).normalize().conjugate().toArray(_);let g=l.times.length;for(let p=0;p=r)){let o=t[1];e=r)break t}a=n,n=0;break n}break e}for(;n>>1;et;)--a;if(++a,r!==0||a!==i){r>=a&&(a=Math.max(a,1),r=a-1);let o=this.getValueSize();this.times=n.slice(r,a),this.values=this.values.slice(r*o,a*o)}return this}validate(){let e=!0,t=this.getValueSize();t-Math.floor(t)!==0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),e=!1);let n=this.times,i=this.values,r=n.length;r===0&&(console.error("THREE.KeyframeTrack: Track is empty.",this),e=!1);let a=null;for(let o=0;o!==r;o++){let c=n[o];if(typeof c=="number"&&isNaN(c)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,o,c),e=!1;break}if(a!==null&&a>c){console.error("THREE.KeyframeTrack: Out of order keys.",this,o,c,a),e=!1;break}a=c}if(i!==void 0&&Ud(i))for(let o=0,c=i.length;o!==c;++o){let l=i[o];if(isNaN(l)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,o,l),e=!1;break}}return e}optimize(){let e=this.times.slice(),t=this.values.slice(),n=this.getValueSize(),i=this.getInterpolation()===La,r=e.length-1,a=1;for(let o=1;o0){e[a]=e[r];for(let o=r*n,c=a*n,l=0;l!==n;++l)t[c+l]=t[o+l];++a}return a!==e.length?(this.times=e.slice(0,a),this.values=t.slice(0,a*n)):(this.times=e,this.values=t),this}clone(){let e=this.times.slice(),t=this.values.slice(),n=this.constructor,i=new n(this.name,e,t);return i.createInterpolant=this.createInterpolant,i}};Jt.prototype.TimeBufferType=Float32Array;Jt.prototype.ValueBufferType=Float32Array;Jt.prototype.DefaultInterpolation=Fr;var Vn=class extends Jt{};Vn.prototype.ValueTypeName="bool";Vn.prototype.ValueBufferType=Array;Vn.prototype.DefaultInterpolation=Or;Vn.prototype.InterpolantFactoryMethodLinear=void 0;Vn.prototype.InterpolantFactoryMethodSmooth=void 0;var pa=class extends Jt{};pa.prototype.ValueTypeName="color";var ts=class extends Jt{};ts.prototype.ValueTypeName="number";var yc=class extends es{constructor(e,t,n,i){super(e,t,n,i)}interpolate_(e,t,n,i){let r=this.resultBuffer,a=this.sampleValues,o=this.valueSize,c=(n-t)/(i-t),l=e*o;for(let h=l+o;l!==h;l+=4)Ut.slerpFlat(r,0,a,l-o,a,l,c);return r}},pi=class extends Jt{InterpolantFactoryMethodLinear(e){return new yc(this.times,this.values,this.getValueSize(),e)}};pi.prototype.ValueTypeName="quaternion";pi.prototype.DefaultInterpolation=Fr;pi.prototype.InterpolantFactoryMethodSmooth=void 0;var kn=class extends Jt{};kn.prototype.ValueTypeName="string";kn.prototype.ValueBufferType=Array;kn.prototype.DefaultInterpolation=Or;kn.prototype.InterpolantFactoryMethodLinear=void 0;kn.prototype.InterpolantFactoryMethodSmooth=void 0;var ns=class extends Jt{};ns.prototype.ValueTypeName="vector";var is=class{constructor(e,t=-1,n,i=Xc){this.name=e,this.tracks=n,this.duration=t,this.blendMode=i,this.uuid=kt(),this.duration<0&&this.resetDuration()}static parse(e){let t=[],n=e.tracks,i=1/(e.fps||1);for(let a=0,o=n.length;a!==o;++a)t.push(bx(n[a]).scale(i));let r=new this(e.name,e.duration,t,e.blendMode);return r.uuid=e.uuid,r}static toJSON(e){let t=[],n=e.tracks,i={name:e.name,duration:e.duration,tracks:t,uuid:e.uuid,blendMode:e.blendMode};for(let r=0,a=n.length;r!==a;++r)t.push(Jt.toJSON(n[r]));return i}static CreateFromMorphTargetSequence(e,t,n,i){let r=t.length,a=[];for(let o=0;o1){let u=h[1],d=i[u];d||(i[u]=d=[]),d.push(l)}}let a=[];for(let o in i)a.push(this.CreateFromMorphTargetSequence(o,i[o],t,n));return a}static parseAnimation(e,t){if(!e)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;let n=function(u,d,f,m,_){if(f.length!==0){let g=[],p=[];$c(f,g,p,m),g.length!==0&&_.push(new u(d,g,p))}},i=[],r=e.name||"default",a=e.fps||30,o=e.blendMode,c=e.length||-1,l=e.hierarchy||[];for(let u=0;u{t&&t(r),this.manager.itemEnd(e)},0),r;if(fn[e]!==void 0){fn[e].push({onLoad:t,onProgress:n,onError:i});return}fn[e]=[],fn[e].push({onLoad:t,onProgress:n,onError:i});let a=new Request(e,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),o=this.mimeType,c=this.responseType;fetch(a).then(l=>{if(l.status===200||l.status===0){if(l.status===0&&console.warn("THREE.FileLoader: HTTP Status 0 received."),typeof ReadableStream>"u"||l.body===void 0||l.body.getReader===void 0)return l;let h=fn[e],u=l.body.getReader(),d=l.headers.get("Content-Length")||l.headers.get("X-File-Size"),f=d?parseInt(d):0,m=f!==0,_=0,g=new ReadableStream({start(p){v();function v(){u.read().then(({done:x,value:y})=>{if(x)p.close();else{_+=y.byteLength;let b=new ProgressEvent("progress",{lengthComputable:m,loaded:_,total:f});for(let w=0,R=h.length;w{switch(c){case"arraybuffer":return l.arrayBuffer();case"blob":return l.blob();case"document":return l.text().then(h=>new DOMParser().parseFromString(h,o));case"json":return l.json();default:if(o===void 0)return l.text();{let u=/charset="?([^;"\s]*)"?/i.exec(o),d=u&&u[1]?u[1].toLowerCase():void 0,f=new TextDecoder(d);return l.arrayBuffer().then(m=>f.decode(m))}}}).then(l=>{ss.add(e,l);let h=fn[e];delete fn[e];for(let u=0,d=h.length;u{let h=fn[e];if(h===void 0)throw this.manager.itemError(e),l;delete fn[e];for(let u=0,d=h.length;u{this.manager.itemEnd(e)}),this.manager.itemStart(e)}setResponseType(e){return this.responseType=e,this}setMimeType(e){return this.mimeType=e,this}},au=class extends Dt{constructor(e){super(e)}load(e,t,n,i){let r=this,a=new rn(this.manager);a.setPath(this.path),a.setRequestHeader(this.requestHeader),a.setWithCredentials(this.withCredentials),a.load(e,function(o){try{t(r.parse(JSON.parse(o)))}catch(c){i?i(c):console.error(c),r.manager.itemError(e)}},n,i)}parse(e){let t=[];for(let n=0;n0:i.vertexColors=e.vertexColors),e.uniforms!==void 0)for(let r in e.uniforms){let a=e.uniforms[r];switch(i.uniforms[r]={},a.type){case"t":i.uniforms[r].value=n(a.value);break;case"c":i.uniforms[r].value=new pe().setHex(a.value);break;case"v2":i.uniforms[r].value=new Z().fromArray(a.value);break;case"v3":i.uniforms[r].value=new A().fromArray(a.value);break;case"v4":i.uniforms[r].value=new je().fromArray(a.value);break;case"m3":i.uniforms[r].value=new He().fromArray(a.value);break;case"m4":i.uniforms[r].value=new ze().fromArray(a.value);break;default:i.uniforms[r].value=a.value}}if(e.defines!==void 0&&(i.defines=e.defines),e.vertexShader!==void 0&&(i.vertexShader=e.vertexShader),e.fragmentShader!==void 0&&(i.fragmentShader=e.fragmentShader),e.glslVersion!==void 0&&(i.glslVersion=e.glslVersion),e.extensions!==void 0)for(let r in e.extensions)i.extensions[r]=e.extensions[r];if(e.lights!==void 0&&(i.lights=e.lights),e.clipping!==void 0&&(i.clipping=e.clipping),e.size!==void 0&&(i.size=e.size),e.sizeAttenuation!==void 0&&(i.sizeAttenuation=e.sizeAttenuation),e.map!==void 0&&(i.map=n(e.map)),e.matcap!==void 0&&(i.matcap=n(e.matcap)),e.alphaMap!==void 0&&(i.alphaMap=n(e.alphaMap)),e.bumpMap!==void 0&&(i.bumpMap=n(e.bumpMap)),e.bumpScale!==void 0&&(i.bumpScale=e.bumpScale),e.normalMap!==void 0&&(i.normalMap=n(e.normalMap)),e.normalMapType!==void 0&&(i.normalMapType=e.normalMapType),e.normalScale!==void 0){let r=e.normalScale;Array.isArray(r)===!1&&(r=[r,r]),i.normalScale=new Z().fromArray(r)}return e.displacementMap!==void 0&&(i.displacementMap=n(e.displacementMap)),e.displacementScale!==void 0&&(i.displacementScale=e.displacementScale),e.displacementBias!==void 0&&(i.displacementBias=e.displacementBias),e.roughnessMap!==void 0&&(i.roughnessMap=n(e.roughnessMap)),e.metalnessMap!==void 0&&(i.metalnessMap=n(e.metalnessMap)),e.emissiveMap!==void 0&&(i.emissiveMap=n(e.emissiveMap)),e.emissiveIntensity!==void 0&&(i.emissiveIntensity=e.emissiveIntensity),e.specularMap!==void 0&&(i.specularMap=n(e.specularMap)),e.specularIntensityMap!==void 0&&(i.specularIntensityMap=n(e.specularIntensityMap)),e.specularColorMap!==void 0&&(i.specularColorMap=n(e.specularColorMap)),e.envMap!==void 0&&(i.envMap=n(e.envMap)),e.envMapIntensity!==void 0&&(i.envMapIntensity=e.envMapIntensity),e.reflectivity!==void 0&&(i.reflectivity=e.reflectivity),e.refractionRatio!==void 0&&(i.refractionRatio=e.refractionRatio),e.lightMap!==void 0&&(i.lightMap=n(e.lightMap)),e.lightMapIntensity!==void 0&&(i.lightMapIntensity=e.lightMapIntensity),e.aoMap!==void 0&&(i.aoMap=n(e.aoMap)),e.aoMapIntensity!==void 0&&(i.aoMapIntensity=e.aoMapIntensity),e.gradientMap!==void 0&&(i.gradientMap=n(e.gradientMap)),e.clearcoatMap!==void 0&&(i.clearcoatMap=n(e.clearcoatMap)),e.clearcoatRoughnessMap!==void 0&&(i.clearcoatRoughnessMap=n(e.clearcoatRoughnessMap)),e.clearcoatNormalMap!==void 0&&(i.clearcoatNormalMap=n(e.clearcoatNormalMap)),e.clearcoatNormalScale!==void 0&&(i.clearcoatNormalScale=new Z().fromArray(e.clearcoatNormalScale)),e.iridescenceMap!==void 0&&(i.iridescenceMap=n(e.iridescenceMap)),e.iridescenceThicknessMap!==void 0&&(i.iridescenceThicknessMap=n(e.iridescenceThicknessMap)),e.transmissionMap!==void 0&&(i.transmissionMap=n(e.transmissionMap)),e.thicknessMap!==void 0&&(i.thicknessMap=n(e.thicknessMap)),e.anisotropyMap!==void 0&&(i.anisotropyMap=n(e.anisotropyMap)),e.sheenColorMap!==void 0&&(i.sheenColorMap=n(e.sheenColorMap)),e.sheenRoughnessMap!==void 0&&(i.sheenRoughnessMap=n(e.sheenRoughnessMap)),i}setTextures(e){return this.textures=e,this}static createMaterialFromType(e){let t={ShadowMaterial:cc,SpriteMaterial:ea,RawShaderMaterial:lc,ShaderMaterial:jt,PointsMaterial:na,MeshPhysicalMaterial:hc,MeshStandardMaterial:da,MeshPhongMaterial:uc,MeshToonMaterial:dc,MeshNormalMaterial:fc,MeshLambertMaterial:pc,MeshDepthMaterial:Qr,MeshDistanceMaterial:jr,MeshBasicMaterial:Sn,MeshMatcapMaterial:mc,LineDashedMaterial:gc,LineBasicMaterial:wt,Material:bt};return new t[e]}},ga=class{static decodeText(e){if(typeof TextDecoder<"u")return new TextDecoder().decode(e);let t="";for(let n=0,i=e.length;n0){let c=new ma(t);r=new rs(c),r.setCrossOrigin(this.crossOrigin);for(let l=0,h=e.length;l0){i=new rs(this.manager),i.setCrossOrigin(this.crossOrigin);for(let a=0,o=e.length;a"u"&&console.warn("THREE.ImageBitmapLoader: createImageBitmap() not supported."),typeof fetch>"u"&&console.warn("THREE.ImageBitmapLoader: fetch() not supported."),this.options={premultiplyAlpha:"none"}}setOptions(e){return this.options=e,this}load(e,t,n,i){e===void 0&&(e=""),this.path!==void 0&&(e=this.path+e),e=this.manager.resolveURL(e);let r=this,a=ss.get(e);if(a!==void 0)return r.manager.itemStart(e),setTimeout(function(){t&&t(a),r.manager.itemEnd(e)},0),a;let o={};o.credentials=this.crossOrigin==="anonymous"?"same-origin":"include",o.headers=this.requestHeader,fetch(e,o).then(function(c){return c.blob()}).then(function(c){return createImageBitmap(c,Object.assign(r.options,{colorSpaceConversion:"none"}))}).then(function(c){ss.add(e,c),t&&t(c),r.manager.itemEnd(e)}).catch(function(c){i&&i(c),r.manager.itemError(e),r.manager.itemEnd(e)}),r.manager.itemStart(e)}},Er,_a=class{static getContext(){return Er===void 0&&(Er=new(window.AudioContext||window.webkitAudioContext)),Er}static setContext(e){Er=e}},xu=class extends Dt{constructor(e){super(e)}load(e,t,n,i){let r=this,a=new rn(this.manager);a.setResponseType("arraybuffer"),a.setPath(this.path),a.setRequestHeader(this.requestHeader),a.setWithCredentials(this.withCredentials),a.load(e,function(c){try{let l=c.slice(0);_a.getContext().decodeAudioData(l,function(u){t(u)},o)}catch(l){o(l)}},n,i);function o(c){i?i(c):console.error(c),r.manager.itemError(e)}}},vu=new ze,yu=new ze,Zn=new ze,Mu=class{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new yt,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new yt,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1,this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}update(e){let t=this._cache;if(t.focus!==e.focus||t.fov!==e.fov||t.aspect!==e.aspect*this.aspect||t.near!==e.near||t.far!==e.far||t.zoom!==e.zoom||t.eyeSep!==this.eyeSep){t.focus=e.focus,t.fov=e.fov,t.aspect=e.aspect*this.aspect,t.near=e.near,t.far=e.far,t.zoom=e.zoom,t.eyeSep=this.eyeSep,Zn.copy(e.projectionMatrix);let i=t.eyeSep/2,r=i*t.near/t.focus,a=t.near*Math.tan(ai*t.fov*.5)/t.zoom,o,c;yu.elements[12]=-i,vu.elements[12]=i,o=-a*t.aspect+r,c=a*t.aspect+r,Zn.elements[0]=2*t.near/(c-o),Zn.elements[8]=(c+o)/(c-o),this.cameraL.projectionMatrix.copy(Zn),o=-a*t.aspect-r,c=a*t.aspect-r,Zn.elements[0]=2*t.near/(c-o),Zn.elements[8]=(c+o)/(c-o),this.cameraR.projectionMatrix.copy(Zn)}this.cameraL.matrixWorld.copy(e.matrixWorld).multiply(yu),this.cameraR.matrixWorld.copy(e.matrixWorld).multiply(vu)}},Oc=class{constructor(e=!0){this.autoStart=e,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=Su(),this.oldTime=this.startTime,this.elapsedTime=0,this.running=!0}stop(){this.getElapsedTime(),this.running=!1,this.autoStart=!1}getElapsedTime(){return this.getDelta(),this.elapsedTime}getDelta(){let e=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){let t=Su();e=(t-this.oldTime)/1e3,this.oldTime=t,this.elapsedTime+=e}return e}};function Su(){return(typeof performance>"u"?Date:performance).now()}var Jn=new A,bu=new Ut,wx=new A,$n=new A,Eu=class extends Je{constructor(){super(),this.type="AudioListener",this.context=_a.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new Oc}getInput(){return this.gain}removeFilter(){return this.filter!==null&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(e){return this.filter!==null?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=e,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(e){return this.gain.gain.setTargetAtTime(e,this.context.currentTime,.01),this}updateMatrixWorld(e){super.updateMatrixWorld(e);let t=this.context.listener,n=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Jn,bu,wx),$n.set(0,0,-1).applyQuaternion(bu),t.positionX){let i=this.context.currentTime+this.timeDelta;t.positionX.linearRampToValueAtTime(Jn.x,i),t.positionY.linearRampToValueAtTime(Jn.y,i),t.positionZ.linearRampToValueAtTime(Jn.z,i),t.forwardX.linearRampToValueAtTime($n.x,i),t.forwardY.linearRampToValueAtTime($n.y,i),t.forwardZ.linearRampToValueAtTime($n.z,i),t.upX.linearRampToValueAtTime(n.x,i),t.upY.linearRampToValueAtTime(n.y,i),t.upZ.linearRampToValueAtTime(n.z,i)}else t.setPosition(Jn.x,Jn.y,Jn.z),t.setOrientation($n.x,$n.y,$n.z,n.x,n.y,n.z)}},Fc=class extends Je{constructor(e){super(),this.type="Audio",this.listener=e,this.context=e.context,this.gain=this.context.createGain(),this.gain.connect(e.getInput()),this.autoplay=!1,this.buffer=null,this.detune=0,this.loop=!1,this.loopStart=0,this.loopEnd=0,this.offset=0,this.duration=void 0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.source=null,this.sourceType="empty",this._startedAt=0,this._progress=0,this._connected=!1,this.filters=[]}getOutput(){return this.gain}setNodeSource(e){return this.hasPlaybackControl=!1,this.sourceType="audioNode",this.source=e,this.connect(),this}setMediaElementSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaNode",this.source=this.context.createMediaElementSource(e),this.connect(),this}setMediaStreamSource(e){return this.hasPlaybackControl=!1,this.sourceType="mediaStreamNode",this.source=this.context.createMediaStreamSource(e),this.connect(),this}setBuffer(e){return this.buffer=e,this.sourceType="buffer",this.autoplay&&this.play(),this}play(e=0){if(this.isPlaying===!0){console.warn("THREE.Audio: Audio is already playing.");return}if(this.hasPlaybackControl===!1){console.warn("THREE.Audio: this Audio has no playback control.");return}this._startedAt=this.context.currentTime+e;let t=this.context.createBufferSource();return t.buffer=this.buffer,t.loop=this.loop,t.loopStart=this.loopStart,t.loopEnd=this.loopEnd,t.onended=this.onEnded.bind(this),t.start(this._startedAt,this._progress+this.offset,this.duration),this.isPlaying=!0,this.source=t,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()}pause(){if(this.hasPlaybackControl===!1){console.warn("THREE.Audio: this Audio has no playback control.");return}return this.isPlaying===!0&&(this._progress+=Math.max(this.context.currentTime-this._startedAt,0)*this.playbackRate,this.loop===!0&&(this._progress=this._progress%(this.duration||this.buffer.duration)),this.source.stop(),this.source.onended=null,this.isPlaying=!1),this}stop(){if(this.hasPlaybackControl===!1){console.warn("THREE.Audio: this Audio has no playback control.");return}return this._progress=0,this.source!==null&&(this.source.stop(),this.source.onended=null),this.isPlaying=!1,this}connect(){if(this.filters.length>0){this.source.connect(this.filters[0]);for(let e=1,t=this.filters.length;e0){this.source.disconnect(this.filters[0]);for(let e=1,t=this.filters.length;e0&&this._mixBufferRegionAdditive(n,i,this._addIndex*t,1,t);for(let c=t,l=t+t;c!==l;++c)if(n[c]!==n[c+t]){o.setValue(n,i);break}}saveOriginalState(){let e=this.binding,t=this.buffer,n=this.valueSize,i=n*this._origIndex;e.getValue(t,i);for(let r=n,a=i;r!==a;++r)t[r]=t[i+r%n];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){let e=this.valueSize*3;this.binding.setValue(this.buffer,e)}_setAdditiveIdentityNumeric(){let e=this._addIndex*this.valueSize,t=e+this.valueSize;for(let n=e;n=.5)for(let a=0;a!==r;++a)e[t+a]=e[n+a]}_slerp(e,t,n,i){Ut.slerpFlat(e,t,e,t,e,n,i)}_slerpAdditive(e,t,n,i,r){let a=this._workIndex*r;Ut.multiplyQuaternionsFlat(e,a,e,t,e,n),Ut.slerpFlat(e,t,e,t,e,a,i)}_lerp(e,t,n,i,r){let a=1-i;for(let o=0;o!==r;++o){let c=t+o;e[c]=e[c]*a+e[n+o]*i}}_lerpAdditive(e,t,n,i,r){for(let a=0;a!==r;++a){let o=t+a;e[o]=e[o]+e[n+a]*i}}},Kc="\\[\\]\\.:\\/",Rx=new RegExp("["+Kc+"]","g"),Qc="[^"+Kc+"]",Cx="[^"+Kc.replace("\\.","")+"]",Px=/((?:WC+[\/:])*)/.source.replace("WC",Qc),Lx=/(WCOD+)?/.source.replace("WCOD",Cx),Ix=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",Qc),Ux=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",Qc),Dx=new RegExp("^"+Px+Lx+Ix+Ux+"$"),Nx=["material","materials","bones","map"],zc=class{constructor(e,t,n){let i=n||Ke.parseTrackName(t);this._targetGroup=e,this._bindings=e.subscribe_(t,i)}getValue(e,t){this.bind();let n=this._targetGroup.nCachedObjects_,i=this._bindings[n];i!==void 0&&i.getValue(e,t)}setValue(e,t){let n=this._bindings;for(let i=this._targetGroup.nCachedObjects_,r=n.length;i!==r;++i)n[i].setValue(e,t)}bind(){let e=this._bindings;for(let t=this._targetGroup.nCachedObjects_,n=e.length;t!==n;++t)e[t].bind()}unbind(){let e=this._bindings;for(let t=this._targetGroup.nCachedObjects_,n=e.length;t!==n;++t)e[t].unbind()}},Ke=class s{constructor(e,t,n){this.path=t,this.parsedPath=n||s.parseTrackName(t),this.node=s.findNode(e,this.parsedPath.nodeName),this.rootNode=e,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(e,t,n){return e&&e.isAnimationObjectGroup?new s.Composite(e,t,n):new s(e,t,n)}static sanitizeNodeName(e){return e.replace(/\s/g,"_").replace(Rx,"")}static parseTrackName(e){let t=Dx.exec(e);if(t===null)throw new Error("PropertyBinding: Cannot parse trackName: "+e);let n={nodeName:t[2],objectName:t[3],objectIndex:t[4],propertyName:t[5],propertyIndex:t[6]},i=n.nodeName&&n.nodeName.lastIndexOf(".");if(i!==void 0&&i!==-1){let r=n.nodeName.substring(i+1);Nx.indexOf(r)!==-1&&(n.nodeName=n.nodeName.substring(0,i),n.objectName=r)}if(n.propertyName===null||n.propertyName.length===0)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+e);return n}static findNode(e,t){if(t===void 0||t===""||t==="."||t===-1||t===e.name||t===e.uuid)return e;if(e.skeleton){let n=e.skeleton.getBoneByName(t);if(n!==void 0)return n}if(e.children){let n=function(r){for(let a=0;a=r){let u=r++,d=e[u];t[d.uuid]=h,e[h]=d,t[l]=u,e[u]=c;for(let f=0,m=i;f!==m;++f){let _=n[f],g=_[u],p=_[h];_[h]=g,_[u]=p}}}this.nCachedObjects_=r}uncache(){let e=this._objects,t=this._indicesByUUID,n=this._bindings,i=n.length,r=this.nCachedObjects_,a=e.length;for(let o=0,c=arguments.length;o!==c;++o){let l=arguments[o],h=l.uuid,u=t[h];if(u!==void 0)if(delete t[h],u0&&(t[f.uuid]=u),e[u]=f,e.pop();for(let m=0,_=i;m!==_;++m){let g=n[m];g[u]=g[d],g.pop()}}}this.nCachedObjects_=r}subscribe_(e,t){let n=this._bindingsIndicesByPath,i=n[e],r=this._bindings;if(i!==void 0)return r[i];let a=this._paths,o=this._parsedPaths,c=this._objects,l=c.length,h=this.nCachedObjects_,u=new Array(l);i=r.length,n[e]=i,a.push(e),o.push(t),r.push(u);for(let d=h,f=c.length;d!==f;++d){let m=c[d];u[d]=new Ke(m,e,t)}return u}unsubscribe_(e){let t=this._bindingsIndicesByPath,n=t[e];if(n!==void 0){let i=this._paths,r=this._parsedPaths,a=this._bindings,o=a.length-1,c=a[o],l=e[o];t[l]=n,a[n]=c,a.pop(),r[n]=r[o],r.pop(),i[n]=i[o],i.pop()}}},Vc=class{constructor(e,t,n=null,i=t.blendMode){this._mixer=e,this._clip=t,this._localRoot=n,this.blendMode=i;let r=t.tracks,a=r.length,o=new Array(a),c={endingStart:zi,endingEnd:zi};for(let l=0;l!==a;++l){let h=r[l].createInterpolant(null);o[l]=h,h.settings=c}this._interpolantSettings=c,this._interpolants=o,this._propertyBindings=new Array(a),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=Af,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&this.timeScale!==0&&this._startTime===null&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(e){return this._startTime=e,this}setLoop(e,t){return this.loop=e,this.repetitions=t,this}setEffectiveWeight(e){return this.weight=e,this._effectiveWeight=this.enabled?e:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(e){return this._scheduleFading(e,0,1)}fadeOut(e){return this._scheduleFading(e,1,0)}crossFadeFrom(e,t,n){if(e.fadeOut(t),this.fadeIn(t),n){let i=this._clip.duration,r=e._clip.duration,a=r/i,o=i/r;e.warp(1,a,t),this.warp(o,1,t)}return this}crossFadeTo(e,t,n){return e.crossFadeFrom(this,t,n)}stopFading(){let e=this._weightInterpolant;return e!==null&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}setEffectiveTimeScale(e){return this.timeScale=e,this._effectiveTimeScale=this.paused?0:e,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(e){return this.timeScale=this._clip.duration/e,this.stopWarping()}syncWith(e){return this.time=e.time,this.timeScale=e.timeScale,this.stopWarping()}halt(e){return this.warp(this._effectiveTimeScale,0,e)}warp(e,t,n){let i=this._mixer,r=i.time,a=this.timeScale,o=this._timeScaleInterpolant;o===null&&(o=i._lendControlInterpolant(),this._timeScaleInterpolant=o);let c=o.parameterPositions,l=o.sampleValues;return c[0]=r,c[1]=r+n,l[0]=e/a,l[1]=t/a,this}stopWarping(){let e=this._timeScaleInterpolant;return e!==null&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(e)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(e,t,n,i){if(!this.enabled){this._updateWeight(e);return}let r=this._startTime;if(r!==null){let c=(e-r)*n;c<0||n===0?t=0:(this._startTime=null,t=n*c)}t*=this._updateTimeScale(e);let a=this._updateTime(t),o=this._updateWeight(e);if(o>0){let c=this._interpolants,l=this._propertyBindings;switch(this.blendMode){case xd:for(let h=0,u=c.length;h!==u;++h)c[h].evaluate(a),l[h].accumulateAdditive(o);break;case Xc:default:for(let h=0,u=c.length;h!==u;++h)c[h].evaluate(a),l[h].accumulate(i,o)}}}_updateWeight(e){let t=0;if(this.enabled){t=this.weight;let n=this._weightInterpolant;if(n!==null){let i=n.evaluate(e)[0];t*=i,e>n.parameterPositions[1]&&(this.stopFading(),i===0&&(this.enabled=!1))}}return this._effectiveWeight=t,t}_updateTimeScale(e){let t=0;if(!this.paused){t=this.timeScale;let n=this._timeScaleInterpolant;if(n!==null){let i=n.evaluate(e)[0];t*=i,e>n.parameterPositions[1]&&(this.stopWarping(),t===0?this.paused=!0:this.timeScale=t)}}return this._effectiveTimeScale=t,t}_updateTime(e){let t=this._clip.duration,n=this.loop,i=this.time+e,r=this._loopCount,a=n===Rf;if(e===0)return r===-1?i:a&&(r&1)===1?t-i:i;if(n===wf){r===-1&&(this._loopCount=0,this._setEndings(!0,!0,!1));e:{if(i>=t)i=t;else if(i<0)i=0;else{this.time=i;break e}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e<0?-1:1})}}else{if(r===-1&&(e>=0?(r=0,this._setEndings(!0,this.repetitions===0,a)):this._setEndings(this.repetitions===0,!0,a)),i>=t||i<0){let o=Math.floor(i/t);i-=t*o,r+=Math.abs(o);let c=this.repetitions-r;if(c<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=e>0?t:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:e>0?1:-1});else{if(c===1){let l=e<0;this._setEndings(l,!l,a)}else this._setEndings(!1,!1,a);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:o})}}else this.time=i;if(a&&(r&1)===1)return t-i}return i}_setEndings(e,t,n){let i=this._interpolantSettings;n?(i.endingStart=Vi,i.endingEnd=Vi):(e?i.endingStart=this.zeroSlopeAtStart?Vi:zi:i.endingStart=Br,t?i.endingEnd=this.zeroSlopeAtEnd?Vi:zi:i.endingEnd=Br)}_scheduleFading(e,t,n){let i=this._mixer,r=i.time,a=this._weightInterpolant;a===null&&(a=i._lendControlInterpolant(),this._weightInterpolant=a);let o=a.parameterPositions,c=a.sampleValues;return o[0]=r,c[0]=t,o[1]=r+e,c[1]=n,this}},Ox=new Float32Array(1),Cu=class extends sn{constructor(e){super(),this._root=e,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(e,t){let n=e._localRoot||this._root,i=e._clip.tracks,r=i.length,a=e._propertyBindings,o=e._interpolants,c=n.uuid,l=this._bindingsByRootAndName,h=l[c];h===void 0&&(h={},l[c]=h);for(let u=0;u!==r;++u){let d=i[u],f=d.name,m=h[f];if(m!==void 0)++m.referenceCount,a[u]=m;else{if(m=a[u],m!==void 0){m._cacheIndex===null&&(++m.referenceCount,this._addInactiveBinding(m,c,f));continue}let _=t&&t._propertyBindings[u].binding.parsedPath;m=new Bc(Ke.create(n,f,_),d.ValueTypeName,d.getValueSize()),++m.referenceCount,this._addInactiveBinding(m,c,f),a[u]=m}o[u].resultBuffer=m.buffer}}_activateAction(e){if(!this._isActiveAction(e)){if(e._cacheIndex===null){let n=(e._localRoot||this._root).uuid,i=e._clip.uuid,r=this._actionsByClip[i];this._bindAction(e,r&&r.knownActions[0]),this._addInactiveAction(e,i,n)}let t=e._propertyBindings;for(let n=0,i=t.length;n!==i;++n){let r=t[n];r.useCount++===0&&(this._lendBinding(r),r.saveOriginalState())}this._lendAction(e)}}_deactivateAction(e){if(this._isActiveAction(e)){let t=e._propertyBindings;for(let n=0,i=t.length;n!==i;++n){let r=t[n];--r.useCount===0&&(r.restoreOriginalState(),this._takeBackBinding(r))}this._takeBackAction(e)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;let e=this;this.stats={actions:{get total(){return e._actions.length},get inUse(){return e._nActiveActions}},bindings:{get total(){return e._bindings.length},get inUse(){return e._nActiveBindings}},controlInterpolants:{get total(){return e._controlInterpolants.length},get inUse(){return e._nActiveControlInterpolants}}}}_isActiveAction(e){let t=e._cacheIndex;return t!==null&&t=0;--n)e[n].stop();return this}update(e){e*=this.timeScale;let t=this._actions,n=this._nActiveActions,i=this.time+=e,r=Math.sign(e),a=this._accuIndex^=1;for(let l=0;l!==n;++l)t[l]._update(i,e,r,a);let o=this._bindings,c=this._nActiveBindings;for(let l=0;l!==c;++l)o[l].apply(a);return this}setTime(e){this.time=0;for(let t=0;tthis.max.x||e.ythis.max.y)}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(e){return!(e.max.xthis.max.x||e.max.ythis.max.y)}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,Bu).distanceTo(e)}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}},Vu=new A,Tr=new A,ku=class{constructor(e=new A,t=new A){this.start=e,this.end=t}set(e,t){return this.start.copy(e),this.end.copy(t),this}copy(e){return this.start.copy(e.start),this.end.copy(e.end),this}getCenter(e){return e.addVectors(this.start,this.end).multiplyScalar(.5)}delta(e){return e.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(e,t){return this.delta(t).multiplyScalar(e).add(this.start)}closestPointToPointParameter(e,t){Vu.subVectors(e,this.start),Tr.subVectors(this.end,this.start);let n=Tr.dot(Tr),r=Tr.dot(Vu)/n;return t&&(r=ct(r,0,1)),r}closestPointToPoint(e,t,n){let i=this.closestPointToPointParameter(e,t);return this.delta(n).multiplyScalar(i).add(this.start)}applyMatrix4(e){return this.start.applyMatrix4(e),this.end.applyMatrix4(e),this}equals(e){return e.start.equals(this.start)&&e.end.equals(this.end)}clone(){return new this.constructor().copy(this)}},Hu=new A,Gu=class extends Je{constructor(e,t){super(),this.light=e,this.matrix=e.matrixWorld,this.matrixAutoUpdate=!1,this.color=t,this.type="SpotLightHelper";let n=new Ge,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(let a=0,o=1,c=32;a1)for(let u=0;u.99999)this.quaternion.set(0,0,0,1);else if(e.y<-.99999)this.quaternion.set(1,0,0,0);else{sd.set(e.z,0,-e.x).normalize();let t=Math.acos(e.y);this.quaternion.setFromAxisAngle(sd,t)}}setLength(e,t=e*.2,n=t*.2){this.line.scale.set(1,Math.max(1e-4,e-t),1),this.line.updateMatrix(),this.cone.scale.set(n,t,n),this.cone.position.y=e,this.cone.updateMatrix()}setColor(e){this.line.material.color.set(e),this.cone.material.color.set(e)}copy(e){return super.copy(e,!1),this.line.copy(e.line),this.cone.copy(e.cone),this}dispose(){this.line.geometry.dispose(),this.line.material.dispose(),this.cone.geometry.dispose(),this.cone.material.dispose()}},ad=class extends en{constructor(e=1){let t=[0,0,0,e,0,0,0,0,0,0,e,0,0,0,0,0,0,e],n=[1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],i=new Ge;i.setAttribute("position",new ve(t,3)),i.setAttribute("color",new ve(n,3));let r=new wt({vertexColors:!0,toneMapped:!1});super(i,r),this.type="AxesHelper"}setColors(e,t,n){let i=new pe,r=this.geometry.attributes.color.array;return i.set(e),i.toArray(r,0),i.toArray(r,3),i.set(t),i.toArray(r,6),i.toArray(r,9),i.set(n),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}},od=class{constructor(){this.type="ShapePath",this.color=new pe,this.subPaths=[],this.currentPath=null}moveTo(e,t){return this.currentPath=new ji,this.subPaths.push(this.currentPath),this.currentPath.moveTo(e,t),this}lineTo(e,t){return this.currentPath.lineTo(e,t),this}quadraticCurveTo(e,t,n,i){return this.currentPath.quadraticCurveTo(e,t,n,i),this}bezierCurveTo(e,t,n,i,r,a){return this.currentPath.bezierCurveTo(e,t,n,i,r,a),this}splineThru(e){return this.currentPath.splineThru(e),this}toShapes(e){function t(p){let v=[];for(let x=0,y=p.length;xNumber.EPSILON){if(T<0&&(R=v[w],M=-M,I=v[b],T=-T),p.yI.y)continue;if(p.y===R.y){if(p.x===R.x)return!0}else{let O=T*(p.x-R.x)-M*(p.y-R.y);if(O===0)return!0;if(O<0)continue;y=!y}}else{if(p.y!==R.y)continue;if(I.x<=p.x&&p.x<=R.x||R.x<=p.x&&p.x<=I.x)return!0}}return y}let i=yn.isClockWise,r=this.subPaths;if(r.length===0)return[];let a,o,c,l=[];if(r.length===1)return o=r[0],c=new Fn,c.curves=o.curves,l.push(c),l;let h=!i(r[0].getPoints());h=e?!h:h;let u=[],d=[],f=[],m=0,_;d[m]=void 0,f[m]=[];for(let p=0,v=r.length;p1){let p=!1,v=0;for(let x=0,y=d.length;x0&&p===!1&&(f=u)}let g;for(let p=0,v=d.length;p { @@ -229,15 +303,18 @@ function Makie.colorbuffer(screen::Screen) return session2image(three.session, screen.scene) end - function insert_scene!(disp, screen::Screen, scene::Scene) if js_uuid(scene) in screen.displayed_scenes return true else + if !(js_uuid(scene.parent) in screen.displayed_scenes) + # Parents serialize their child scenes, so we only need to + # serialize & update the parent scene + return insert_scene!(disp, screen, scene.parent) + end scene_ser = serialize_scene(scene) parent = scene.parent parent_uuid = js_uuid(parent) - insert_scene!(disp, screen, parent) # make sure parent is also already displayed err = "Cant find scene js_uuid(scene) == $(parent_uuid)" evaljs_value(disp.session, js""" $(WGL).then(WGL=> { @@ -254,14 +331,23 @@ function insert_scene!(disp, screen::Screen, scene::Scene) end end -function Base.insert!(screen::Screen, scene::Scene, plot::Combined) +function insert_plot!(disp::ThreeDisplay, scene::Scene, @nospecialize(plot::Plot)) + plot_data = serialize_plots(scene, [plot]) + plot_sub = Session(disp.session) + JSServe.init_session(plot_sub) + plot.__wgl_session = plot_sub + js = js""" + $(WGL).then(WGL=> { + WGL.insert_plot($(js_uuid(scene)), $plot_data); + })""" + JSServe.evaljs_value(plot_sub, js; timeout=50) + return +end + +function Base.insert!(screen::Screen, scene::Scene, @nospecialize(plot::Plot)) disp = get_three(screen; error="Plot needs to be displayed to insert additional plots") if js_uuid(scene) in screen.displayed_scenes - plot_data = serialize_plots(scene, [plot]) - JSServe.evaljs_value(disp.session, js""" - $(WGL).then(WGL=> { - WGL.insert_plot($(js_uuid(scene)), $plot_data); - })""") + insert_plot!(disp, scene, plot) else # Newly created scene gets inserted! # This must be a child plot of some parent, otherwise a plot wouldn't be inserted via `insert!(screen, ...)` @@ -279,45 +365,90 @@ function Base.insert!(screen::Screen, scene::Scene, plot::Combined) return end -struct LockfreeQueue{T, F} +function delete_js_objects!(screen::Screen, plot_uuids::Vector{String}, + session::Union{Nothing,Session}) + three = get_three(screen) + isnothing(three) && return # if no session we haven't displayed and dont need to delete + isready(three.session) || return + JSServe.evaljs(three.session, js""" + $(WGL).then(WGL=> { + WGL.delete_plots($(plot_uuids)); + })""") + !isnothing(session) && close(session) + return +end + +function all_plots_scenes(scene::Scene; scene_uuids=String[], plots=Plot[]) + push!(scene_uuids, js_uuid(scene)) + append!(plots, scene.plots) + for child in scene.children + all_plots_scenes(child; plots=plots, scene_uuids=scene_uuids) + end + return scene_uuids, plots +end + +function delete_js_objects!(screen::Screen, scene::Scene) + three = get_three(screen) + isnothing(three) && return # if no session we haven't displayed and dont need to delete + isready(three.session) || return + scene_uuids, plots = all_plots_scenes(scene) + for plot in plots + if haskey(plot, :__wgl_session) + session = plot.__wgl_session[] + close(session) + end + end + JSServe.evaljs(three.session, js""" + $(WGL).then(WGL=> { + WGL.delete_scenes($scene_uuids, $(js_uuid.(plots))); + })""") + return +end + + +struct LockfreeQueue{T,F} # Double buffering to be lock free queue1::Vector{T} queue2::Vector{T} current_queue::Threads.Atomic{Int} - task::Base.RefValue{Union{Nothing, Task}} + task::Base.RefValue{Union{Nothing,Task}} execute_job::F end -function LockfreeQueue{T}(execute_job::F) where {T, F} - return LockfreeQueue{T, F}( - T[], - T[], - Threads.Atomic{Int}(1), - Base.RefValue{Union{Nothing, Task}}(nothing), - execute_job - ) +function LockfreeQueue{T}(execute_job::F) where {T,F} + return LockfreeQueue{T,F}(T[], + T[], + Threads.Atomic{Int}(1), + Base.RefValue{Union{Nothing,Task}}(nothing), + execute_job) end function run_jobs!(queue::LockfreeQueue) # already running: !isnothing(queue.task[]) && !istaskdone(queue.task[]) && return - queue.task[] = @async while true - q = nothing - if !isempty(queue.queue1) - queue.current_queue[] = 1 - q = queue.queue1 - elseif !isempty(queue.queue2) - queue.current_queue[] = 2 - q = queue.queue2 - end - if !isnothing(q) - while !isempty(q) - item = pop!(q) - queue.execute_job(item...) + return queue.task[] = @async while true + try + q = nothing + if !isempty(queue.queue1) + queue.current_queue[] = 1 + q = queue.queue1 + elseif !isempty(queue.queue2) + queue.current_queue[] = 2 + q = queue.queue2 + end + if !isnothing(q) + while !isempty(q) + item = pop!(q) + Base.invokelatest(queue.execute_job, item...) + end + end + sleep(0.1) + catch e + if !(e isa EOFError) + @warn "error while running JS objects" exception = (e, Base.catch_backtrace()) end end - sleep(0.1) end end @@ -331,25 +462,24 @@ function Base.push!(queue::LockfreeQueue, item) end end -function delete_plot!(td::Screen, scene::String, uuids::Vector{String}) - three = get_three(td) - isnothing(three) && return # if no session we haven't displayed and dont need to delete - isready(three.session) || return - JSServe.evaljs(three.session, js""" - $(WGL).then(WGL=> { - WGL.delete_plots($(scene), $(uuids)); - })""") - return -end - const DISABLE_JS_FINALZING = Base.RefValue(false) -const DELETE_QUEUE = LockfreeQueue{Tuple{Screen,String,Vector{String}}}(delete_plot!) +const DELETE_QUEUE = LockfreeQueue{Tuple{Screen, Vector{String}, Union{Session, Nothing}}}(delete_js_objects!) +const SCENE_DELETE_QUEUE = LockfreeQueue{Tuple{Screen,Scene}}(delete_js_objects!) -function Base.delete!(screen::Screen, scene::Scene, plot::Combined) - atomics = Makie.collect_atomic_plots(plot) # delete all atomics +function Base.delete!(screen::Screen, scene::Scene, plot::Plot) # only queue atomics to actually delete on js if !DISABLE_JS_FINALZING[] - push!(DELETE_QUEUE, (screen, js_uuid(scene), js_uuid.(atomics))) + plot_uuids = map(js_uuid, Makie.collect_atomic_plots(plot)) + session = to_value(get(plot, :__wgl_session, nothing)) + push!(DELETE_QUEUE, (screen, plot_uuids, session)) + end + return +end + +function Base.delete!(screen::Screen, scene::Scene) + if !DISABLE_JS_FINALZING[] + push!(SCENE_DELETE_QUEUE, (screen, scene)) end + delete!(screen.displayed_scenes, js_uuid(scene)) return end diff --git a/WGLMakie/src/events.jl b/WGLMakie/src/events.jl index 6db9ccfa831..bd129e83d53 100644 --- a/WGLMakie/src/events.jl +++ b/WGLMakie/src/events.jl @@ -54,7 +54,7 @@ function connect_scene_events!(scene::Scene, comm::Observable) @async try @handle msg.mouseposition begin x, y = Float64.((mouseposition...,)) - e.mouseposition[] = (x, size(scene)[2] - y) + e.mouseposition[] = (x, y) end @handle msg.mousedown begin # This can probably be done better from the JS side? diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index 1fc9426b94e..e5417f19fe7 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -6,29 +6,36 @@ using Makie: el32convert, surface_normals, get_dim nothing_or_color(c) = to_color(c) nothing_or_color(c::Nothing) = RGBAf(0, 0, 0, 1) -lift_or(f, x) = f(x) -lift_or(f, x::Observable) = lift(f, x) - function create_shader(mscene::Scene, plot::Surface) # TODO OWN OPTIMIZED SHADER ... Or at least optimize this a bit more ... px, py, pz = plot[1], plot[2], plot[3] grid(x, y, z, trans, space) = Makie.matrix_grid(p-> apply_transform(trans, p, space), x, y, z) - positions = Buffer(lift(grid, px, py, pz, transform_func_obs(plot), get(plot, :space, :data))) - rect = lift(z -> Tesselation(Rect2(0f0, 0f0, 1f0, 1f0), size(z)), pz) - faces = Buffer(lift(r -> decompose(GLTriangleFace, r), rect)) - uv = Buffer(lift(decompose_uv, rect)) - normals = Buffer(lift(surface_normals, px, py, pz)) - per_vertex = Dict(:positions => positions, :faces => faces, :uv => uv, :normals => normals) + # TODO: Use Makie.surface2mesh + ps = lift(grid, plot, px, py, pz, transform_func_obs(plot), get(plot, :space, :data)) + positions = Buffer(ps) + rect = lift(z -> Tesselation(Rect2(0f0, 0f0, 1f0, 1f0), size(z)), plot, pz) + fs = lift(r -> decompose(QuadFace{Int}, r), plot, rect) + fs = map((ps, fs) -> filter(f -> !any(i -> isnan(ps[i]), f), fs), plot, ps, fs) + faces = Buffer(fs) + # This adjusts uvs (compared to decompose_uv) so texture sampling starts at + # the center of a texture pixel rather than the edge, fixing + # 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] + end) + normals = Buffer(lift(Makie.nan_aware_normals, plot, ps, fs)) + per_vertex = Dict(:positions => positions, :faces => faces, :uv => uv, :normals => normals) uniforms = Dict(:uniform_color => color, :color => false) + return draw_mesh(mscene, per_vertex, plot, uniforms) end function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) - minfilter = to_value(get(plot, :interpolate, false)) ? :linear : :nearest mesh = limits_to_uvmesh(plot) - uniforms = Dict( :normals => Vec3f(0), :shading => false, @@ -45,7 +52,7 @@ function create_shader(mscene::Scene, plot::Volume) x, y, z, vol = plot[1], plot[2], plot[3], plot[4] box = GeometryBasics.mesh(Rect3f(Vec3f(0), Vec3f(1))) cam = cameracontrols(mscene) - model2 = lift(plot.model, x, y, z) do m, xyz... + model2 = lift(plot, plot.model, x, y, z) do m, xyz... mi = minimum.(xyz) maxi = maximum.(xyz) w = maxi .- mi @@ -53,20 +60,20 @@ function create_shader(mscene::Scene, plot::Volume) return convert(Mat4f, m) * m2 end - modelinv = lift(inv, model2) - algorithm = lift(x -> Cuint(convert_attribute(x, key"algorithm"())), plot.algorithm) + modelinv = lift(inv, plot, model2) + algorithm = lift(x -> Cuint(convert_attribute(x, key"algorithm"())), plot, plot.algorithm) - diffuse = lift(x -> convert_attribute(x, Key{:diffuse}()), plot.diffuse) - specular = lift(x -> convert_attribute(x, Key{:specular}()), plot.specular) - shininess = lift(x -> convert_attribute(x, Key{:shininess}()), plot.shininess) + diffuse = lift(x -> convert_attribute(x, Key{:diffuse}()), plot, plot.diffuse) + specular = lift(x -> convert_attribute(x, Key{:specular}()), plot, plot.specular) + shininess = lift(x -> convert_attribute(x, Key{:shininess}()), plot, plot.shininess) uniforms = Dict{Symbol, Any}( :modelinv => modelinv, - :isovalue => lift(Float32, plot.isovalue), - :isorange => lift(Float32, plot.isorange), - :absorption => lift(Float32, get(plot, :absorption, Observable(1.0f0))), + :isovalue => lift(Float32, plot, plot.isovalue), + :isorange => lift(Float32, plot, plot.isorange), + :absorption => lift(Float32, plot, get(plot, :absorption, Observable(1.0f0))), :algorithm => algorithm, :diffuse => diffuse, :specular => specular, @@ -75,7 +82,8 @@ function create_shader(mscene::Scene, plot::Volume) :depth_shift => get(plot, :depth_shift, Observable(0.0f0)), # these get filled in later by serialization, but we need them # as dummy values here, so that the correct uniforms are emitted - :lightposition => Vec3f(1), + :light_direction => Vec3f(1), + :light_color => Vec3f(1), :eyeposition => Vec3f(1), :ambient => Vec3f(1), :picking => false, @@ -128,23 +136,22 @@ function limits_to_uvmesh(plot) # TODO, this branch is only hit by Image, but not for Heatmap with stepranges # because convert_arguments converts x/y to Vector{Float32} if px[] isa StepRangeLen && py[] isa StepRangeLen && Makie.is_identity_transform(t) - rect = lift(px, py) do x, y + rect = lift(plot, px, py) do x, y xmin, xmax = extrema(x) ymin, ymax = extrema(y) return Rect2(xmin, ymin, xmax - xmin, ymax - ymin) end - positions = Buffer(lift(rect -> decompose(Point2f, rect), rect)) - faces = Buffer(lift(rect -> decompose(GLTriangleFace, rect), rect)) - uv = Buffer(lift(decompose_uv, rect)) + positions = Buffer(lift(rect -> decompose(Point2f, rect), plot, rect)) + faces = Buffer(lift(rect -> decompose(GLTriangleFace, rect), plot, rect)) + uv = Buffer(lift(decompose_uv, plot, rect)) else function grid(x, y, trans, space) return Makie.matrix_grid(p -> apply_transform(trans, p, space), x, y, zeros(length(x), length(y))) end - resolution = lift((x, y) -> (length(x), length(y)), px, py; ignore_equal_values=true) - positions = Buffer(lift(grid, px, py, t, get(plot, :space, :data))) - faces = Buffer(lift(fast_faces, resolution)) - uv = Buffer(lift(fast_uv, resolution)) + resolution = lift((x, y) -> (length(x), length(y)), plot, px, py; ignore_equal_values=true) + positions = Buffer(lift(grid, plot, px, py, t, get(plot, :space, :data))) + faces = Buffer(lift(fast_faces, plot, resolution)) + uv = Buffer(lift(fast_uv, plot, resolution)) end - vertices = GeometryBasics.meta(positions; uv=uv) return Dict(:positions => positions, :faces => faces, :uv => uv) end diff --git a/WGLMakie/src/lines.jl b/WGLMakie/src/lines.jl index bfdcfc6f158..9066d676374 100644 --- a/WGLMakie/src/lines.jl +++ b/WGLMakie/src/lines.jl @@ -1,81 +1,45 @@ -topoint(x::AbstractVector{Point{N,Float32}}) where {N} = x - -# GRRR STUPID SubArray, with eltype different from getindex(x, 1) -topoint(x::SubArray) = topoint([el for el in x]) - -function topoint(x::AbstractArray{<:Point{N,T}}) where {T,N} - return topoint(Point{N,Float32}.(x)) -end - -function topoint(x::AbstractArray{<:Tuple{P,P}}) where {P<:Point} - return topoint(reinterpret(P, x)) -end - -function create_shader(scene::Scene, plot::Union{Lines,LineSegments}) - # Potentially per instance attributes - positions = lift(plot[1], transform_func_obs(plot), plot.space) do points, trans, space - points = apply_transform(trans, topoint(points), space) - if plot isa LineSegments - return points - else - # Repeat every second point to connect the lines ! - return topoint(TupleView{2, 1}(points)) +function serialize_three(scene::Scene, plot::Union{Lines, LineSegments}) + Makie.@converted_attribute plot (linewidth,) + uniforms = Dict( + :model => plot.model, + :object_id => 1, + :depth_shift => plot.depth_shift, + :picking => false, + ) + + color = plot.calculated_colors + if color[] isa Makie.ColorMapping + uniforms[:colormap] = Sampler(color[].colormap) + uniforms[:colorrange] = color[].colorrange_scaled + uniforms[:highclip] = Makie.highclip(color[]) + uniforms[:lowclip] = Makie.lowclip(color[]) + uniforms[:nan_color] = color[].nan_color + color = color[].color_scaled + else + for name in [:nan_color, :highclip, :lowclip] + uniforms[name] = RGBAf(0, 0, 0, 0) end - trans - end - - startr = lift(p -> 1:2:(length(p) - 1), positions) - endr = lift(p -> 2:2:length(p), positions) - - p_start_end = lift(positions) do positions - return (positions[startr[]], positions[endr[]]) end - - per_instance = Dict{Symbol,Any}(:segment_start => Buffer(lift(first, p_start_end)), - :segment_end => Buffer(lift(last, p_start_end))) - uniforms = Dict{Symbol,Any}() - - linewidth = converted_attribute(plot, :linewidth) - cmap = plot.calculated_colors[] - - color = cmap isa Makie.ColorMapping ? cmap.color_scaled : plot.calculated_colors - - for (k, attribute) in [:linewidth => linewidth, :color => color] - attribute = lift(attribute) do x - plot isa LineSegments && return x - # Repeat every second point to connect the lines! - return isscalar(x) ? x : reinterpret(eltype(x), TupleView{2, 1}(x)) - end - if isscalar(attribute) - uniforms[k] = attribute - uniforms[Symbol("$(k)_start")] = attribute - uniforms[Symbol("$(k)_end")] = attribute + points_transformed = lift(apply_transform, plot, transform_func_obs(plot), plot[1], plot.space) + positions = lift(serialize_buffer_attribute, plot, points_transformed) + attributes = Dict{Symbol, Any}(:linepoint => positions) + for (name, attr) in [:color => color, :linewidth => linewidth] + if Makie.is_scalar_attribute(to_value(attr)) + uniforms[Symbol("$(name)_start")] = attr + uniforms[Symbol("$(name)_end")] = attr else - if attribute[] isa AbstractVector{<:Number} && k == :color - @assert cmap isa Makie.ColorMapping - attribute = lift(Makie.numbers_to_colors, attribute, cmap.colormap, identity, - cmap.colorrange_scaled, cmap.lowclip, - cmap.highclip, - cmap.nan_color) - end - per_instance[Symbol("$(k)_start")] = Buffer(lift(x -> x[startr[]], attribute)) - per_instance[Symbol("$(k)_end")] = Buffer(lift(x -> x[endr[]], attribute)) + attributes[name] = lift(serialize_buffer_attribute, plot, attr) end end - - uniforms[:resolution] = to_value(scene.camera.resolution) # updates in JS - - uniforms[:model] = plot.model - uniforms[:depth_shift] = get(plot, :depth_shift, Observable(0f0)) - positions = meta(Point2f[(0, -1), (0, 1), (1, -1), (1, 1)], - uv=Vec2f[(0, 0), (0, 0), (0, 0), (0, 0)]) - instance = GeometryBasics.Mesh(positions, GLTriangleFace[(1, 2, 3), (2, 4, 3)]) - - # id + picking gets filled in JS, needs to be here to emit the correct shader uniforms - uniforms[:picking] = false - uniforms[:object_id] = UInt32(0) - - return InstancedProgram(WebGL(), lasset("line_segments.vert"), - lasset("line_segments.frag"), instance, - VertexArray(; per_instance...), uniforms) + attr = Dict( + :name => string(Makie.plotkey(plot)) * "-" * string(objectid(plot)), + :visible => plot.visible, + :uuid => js_uuid(plot), + :plot_type => plot isa LineSegments ? "linesegments" : "lines", + :cam_space => plot.space[], + :uniforms => serialize_uniforms(uniforms), + :uniform_updater => uniform_updater(plot, uniforms), + :attributes => attributes + ) + return attr end diff --git a/WGLMakie/src/mapbox-lines.vert b/WGLMakie/src/mapbox-lines.vert new file mode 100644 index 00000000000..d2912bc4d67 --- /dev/null +++ b/WGLMakie/src/mapbox-lines.vert @@ -0,0 +1,74 @@ +#version 300 es +precision highp float; +// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define EXTRUDE_SCALE 0.015873016 + +in vec2 a_pos_normal; +in vec4 a_data; + +uniform mat4 u_matrix; +uniform mat2 u_pixels_to_tile_units; +uniform vec2 u_units_to_pixels; +uniform lowp float u_device_pixel_ratio; + +out vec2 v_normal; +out vec2 v_width2; +out float v_gamma_scale; + +lowp float floorwidth = 1.0; +mediump float gapwidth = 0.0; +lowp float offset = 0.0; +float width = 1.0; + +void main() { + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist = outset * a_extrude * EXTRUDE_SCALE; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * EXTRUDE_SCALE * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist * u_pixels_to_tile_units, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 * u_pixels_to_tile_units, 0.0, 1.0) + projected_extrude; + + + v_gamma_scale = 1.0; + + v_width2 = vec2(outset, inset); + +} diff --git a/WGLMakie/src/meshes.jl b/WGLMakie/src/meshes.jl index 11922e71647..ded9dee2ab7 100644 --- a/WGLMakie/src/meshes.jl +++ b/WGLMakie/src/meshes.jl @@ -3,8 +3,8 @@ function vertexbuffer(x, trans, space) return apply_transform(trans, pos, space) end -function vertexbuffer(x::Observable, p) - return Buffer(lift(vertexbuffer, x, transform_func_obs(p), get(p, :space, :data))) +function vertexbuffer(x::Observable, @nospecialize(p)) + return Buffer(lift(vertexbuffer, p, x, transform_func_obs(p), get(p, :space, :data))) end facebuffer(x) = faces(x) @@ -12,7 +12,7 @@ facebuffer(x::AbstractArray{<:GLTriangleFace}) = x facebuffer(x::Observable) = Buffer(lift(facebuffer, x)) function converted_attribute(plot::AbstractPlot, key::Symbol) - return lift(plot[key]) do value + return lift(plot, plot[key]) do value return convert_attribute(value, Key{key}(), Key{plotkey(plot)}()) end end @@ -21,7 +21,7 @@ function handle_color!(plot, uniforms, buffers, uniform_color_name = :uniform_co color = plot.calculated_colors minfilter = to_value(get(plot, :interpolate, true)) ? :linear : :nearest - convert_text(x) = permute_tex ? lift(permutedims, x) : x + convert_text(x) = permute_tex ? lift(permutedims, plot, x) : x if color[] isa Colorant uniforms[uniform_color_name] = color @@ -55,28 +55,32 @@ function handle_color!(plot, uniforms, buffers, uniform_color_name = :uniform_co return end +lift_or(f, p, x) = f(x) +lift_or(f, @nospecialize(p), x::Observable) = lift(f, p, x) + function draw_mesh(mscene::Scene, per_vertex, plot, uniforms; permute_tex=true) filter!(kv -> !(kv[2] isa Function), uniforms) handle_color!(plot, uniforms, per_vertex; permute_tex=permute_tex) get!(uniforms, :pattern, false) get!(uniforms, :model, plot.model) - get!(uniforms, :lightposition, Vec3f(1)) get!(uniforms, :ambient, Vec3f(1)) + get!(uniforms, :light_direction, Vec3f(1)) + get!(uniforms, :light_color, Vec3f(1)) uniforms[:interpolate_in_fragment_shader] = get(plot, :interpolate_in_fragment_shader, true) - get!(uniforms, :shading, get(plot, :shading, false)) + get!(uniforms, :shading, to_value(get(plot, :shading, NoShading)) != NoShading) - uniforms[:normalmatrix] = map(mscene.camera.view, plot.model) do v, m + uniforms[:normalmatrix] = map(plot.model) do m i = Vec(1, 2, 3) - return transpose(inv(v[i, i] * m[i, i])) + return transpose(inv(m[i, i])) end for key in (:diffuse, :specular, :shininess, :backlight, :depth_shift) if !haskey(uniforms, key) - uniforms[key] = lift_or(x -> convert_attribute(x, Key{key}()), plot[key]) + uniforms[key] = lift_or(x -> convert_attribute(x, Key{key}()), plot, plot[key]) end end if haskey(uniforms, :color) && haskey(per_vertex, :color) @@ -98,7 +102,7 @@ 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), mesh) + get_attribute(mesh, key) = lift(x -> getproperty(x, key), plot, mesh) data = mattributes(mesh_signal[]) uniforms = Dict{Symbol,Any}() diff --git a/WGLMakie/src/particles.jl b/WGLMakie/src/particles.jl index c62a3f3f68b..5c4a3bc681f 100644 --- a/WGLMakie/src/particles.jl +++ b/WGLMakie/src/particles.jl @@ -38,8 +38,9 @@ end const IGNORE_KEYS = Set([ :shading, :overdraw, :rotation, :distancefield, :space, :markerspace, :fxaa, :visible, :transformation, :alpha, :linewidth, :transparency, :marker, - :lightposition, :cycle, :label, :inspector_clear, :inspector_hover, - :inspector_label + :light_direction, :light_color, + :cycle, :label, :inspector_clear, :inspector_hover, + :inspector_label, :axis_cycler ]) function create_shader(scene::Scene, plot::MeshScatter) @@ -49,7 +50,7 @@ function create_shader(scene::Scene, plot::MeshScatter) return k in per_instance_keys && !(isscalar(v[])) end - per_instance[:offset] = apply_transform(transform_func_obs(plot), plot[1], plot.space) + per_instance[:offset] = lift(apply_transform, plot, transform_func_obs(plot), plot[1], plot.space) for (k, v) in per_instance per_instance[k] = Buffer(lift_convert(k, v, plot)) @@ -77,13 +78,19 @@ function create_shader(scene::Scene, plot::MeshScatter) uniform_dict[:depth_shift] = get(plot, :depth_shift, Observable(0f0)) uniform_dict[:backlight] = plot.backlight - get!(uniform_dict, :ambient, Vec3f(1)) + # Make sure these exist + get!(uniform_dict, :ambient, Vec3f(0.1)) + get!(uniform_dict, :diffuse, Vec3f(0.9)) + get!(uniform_dict, :specular, Vec3f(0.3)) + get!(uniform_dict, :shininess, 8f0) + get!(uniform_dict, :light_direction, Vec3f(1)) + get!(uniform_dict, :light_color, Vec3f(1)) # id + picking gets filled in JS, needs to be here to emit the correct shader uniforms uniform_dict[:picking] = false uniform_dict[:object_id] = UInt32(0) - uniform_dict[:shading] = plot.shading + uniform_dict[:shading] = map(x -> x != NoShading, plot.shading) return InstancedProgram(WebGL(), lasset("particles.vert"), lasset("particles.frag"), instance, VertexArray(; per_instance...), uniform_dict) @@ -114,9 +121,6 @@ function serialize_three(fta::NoDataTextureAtlas) return tex end - - - function scatter_shader(scene::Scene, attributes, plot) # Potentially per instance attributes per_instance_keys = (:pos, :rotations, :markersize, :color, :intensity, @@ -127,19 +131,19 @@ function scatter_shader(scene::Scene, attributes, plot) atlas = wgl_texture_atlas() if haskey(attributes, :marker) font = get(attributes, :font, Observable(Makie.defaultfont())) - marker = lift(attributes[:marker]) do marker + marker = lift(plot, attributes[:marker]) do marker marker isa Makie.FastPixel && return Rect # FastPixel not supported, but same as Rect just slower return Makie.to_spritemarker(marker) end - markersize = lift(Makie.to_2d_scale, attributes[:markersize]) + markersize = lift(Makie.to_2d_scale, plot, attributes[:markersize]) - msize, offset = Makie.marker_attributes(atlas, marker, markersize, font, attributes[:quad_offset]) + msize, offset = Makie.marker_attributes(atlas, marker, markersize, font, attributes[:quad_offset], plot) attributes[:markersize] = msize attributes[:quad_offset] = offset attributes[:uv_offset_width] = Makie.primitive_uv_offset_width(atlas, marker, font) if to_value(marker) isa AbstractMatrix - uniform_dict[:image] = Sampler(lift(el32convert, marker)) + uniform_dict[:image] = Sampler(lift(el32convert, plot, marker)) end end @@ -166,7 +170,9 @@ function scatter_shader(scene::Scene, attributes, plot) if !isnothing(marker) get!(uniform_dict, :shape_type) do - return Makie.marker_to_sdf_shape(marker) + return lift(plot, marker; ignore_equal_values=true) do marker + return Cint(Makie.marker_to_sdf_shape(to_spritemarker(marker))) + end end end @@ -190,6 +196,7 @@ function scatter_shader(scene::Scene, attributes, plot) instance = uv_mesh(Rect2(-0.5f0, -0.5f0, 1f0, 1f0)) # Don't send obs, since it's overwritten in JS to be updated by the camera uniform_dict[:resolution] = to_value(scene.camera.resolution) + uniform_dict[:px_per_unit] = 1f0 # id + picking gets filled in JS, needs to be here to emit the correct shader uniforms uniform_dict[:picking] = false @@ -200,21 +207,15 @@ end function create_shader(scene::Scene, plot::Scatter) # Potentially per instance attributes - per_instance_keys = (:offset, :rotations, :markersize, :color, :intensity, - :quad_offset) - per_instance = filter(plot.attributes.attributes) do (k, v) - return k in per_instance_keys && !(isscalar(v[])) - end attributes = copy(plot.attributes.attributes) space = get(attributes, :space, :data) - cam = scene.camera attributes[:preprojection] = Mat4f(I) # calculate this in JS - attributes[:pos] = apply_transform(transform_func_obs(plot), plot[1], space) + attributes[:pos] = lift(apply_transform, plot, transform_func_obs(plot), plot[1], space) quad_offset = get(attributes, :marker_offset, Observable(Vec2f(0))) attributes[:marker_offset] = Vec3f(0) attributes[:quad_offset] = quad_offset - attributes[:billboard] = map(rot -> isa(rot, Billboard), plot.rotations) + attributes[:billboard] = lift(rot -> isa(rot, Billboard), plot, plot.rotations) attributes[:model] = plot.model attributes[:depth_shift] = get(plot, :depth_shift, Observable(0f0)) @@ -236,16 +237,16 @@ function create_shader(scene::Scene, plot::Makie.Text{<:Tuple{<:Union{<:Makie.Gl offset = plot.offset atlas = wgl_texture_atlas() - glyph_data = map(pos, glyphcollection, offset, transfunc, space; ignore_equal_values=true) do pos, gc, offset, transfunc, space + glyph_data = lift(plot, pos, glyphcollection, offset, transfunc, space; ignore_equal_values=true) do pos, gc, offset, transfunc, space Makie.text_quads(atlas, pos, to_value(gc), offset, transfunc, space) end # unpack values from the one signal: positions, char_offset, quad_offset, uv_offset_width, scale = map((1, 2, 3, 4, 5)) do i - lift(getindex, glyph_data, i) + return lift(getindex, plot, glyph_data, i) end - uniform_color = lift(glyphcollection) do gc + uniform_color = lift(plot, glyphcollection) do gc if gc isa AbstractArray reduce(vcat, (Makie.collect_vector(g.colors, length(g.glyphs)) for g in gc), init = RGBAf[]) @@ -254,7 +255,7 @@ function create_shader(scene::Scene, plot::Makie.Text{<:Tuple{<:Union{<:Makie.Gl end end - uniform_rotation = lift(glyphcollection) do gc + uniform_rotation = lift(plot, glyphcollection) do gc if gc isa AbstractArray reduce(vcat, (Makie.collect_vector(g.rotations, length(g.glyphs)) for g in gc), init = Quaternionf[]) diff --git a/WGLMakie/src/picking.jl b/WGLMakie/src/picking.jl index 4c5589ffe20..1bbf590fdf2 100644 --- a/WGLMakie/src/picking.jl +++ b/WGLMakie/src/picking.jl @@ -48,6 +48,7 @@ end function Makie.pick_sorted(scene::Scene, screen::Screen, xy, range) xy_vec = Cint[round.(Cint, xy)...] range = round(Int, range) + session = get_three(screen; error="Can't do picking!").session selection = JSServe.evaljs_value(session, js""" Promise.all([$(WGL), $(scene)]).then(([WGL, scene]) => WGL.pick_sorted(scene, $(xy_vec), $(range))) diff --git a/WGLMakie/src/precompiles.jl b/WGLMakie/src/precompiles.jl index ea89684a234..0822ed9f3b8 100644 --- a/WGLMakie/src/precompiles.jl +++ b/WGLMakie/src/precompiles.jl @@ -10,7 +10,7 @@ macro compile(block) # So we just do all parts of the stack we can do without browser scene = Makie.get_scene(figlike) session = Session(JSServe.NoConnection(); asset_server=JSServe.NoServer()) - three_display(session, scene) + three_display(Screen(scene), session, scene) JSServe.jsrender(session, figlike) s = serialize_scene(scene) JSServe.SerializedMessage(session, Dict(:data => s)) diff --git a/WGLMakie/src/serialization.jl b/WGLMakie/src/serialization.jl index f8357625fa1..bee88140232 100644 --- a/WGLMakie/src/serialization.jl +++ b/WGLMakie/src/serialization.jl @@ -192,10 +192,10 @@ function serialize_named_buffer(buffer) end) end -function register_geometry_updates(update_buffer::Observable, named_buffers) +function register_geometry_updates(@nospecialize(plot), update_buffer::Observable, named_buffers) for (name, buffer) in _pairs(named_buffers) if buffer isa Buffer - on(ShaderAbstractions.updater(buffer).update) do (f, args) + on(plot, ShaderAbstractions.updater(buffer).update) do (f, args) # update to replace the whole buffer! if f === ShaderAbstractions.update! new_array = args[1] @@ -209,19 +209,19 @@ function register_geometry_updates(update_buffer::Observable, named_buffers) return update_buffer end -function register_geometry_updates(update_buffer::Observable, program::Program) - return register_geometry_updates(update_buffer, program.vertexarray) +function register_geometry_updates(@nospecialize(plot), update_buffer::Observable, program::Program) + return register_geometry_updates(plot, update_buffer, program.vertexarray) end -function register_geometry_updates(update_buffer::Observable, program::InstancedProgram) - return register_geometry_updates(update_buffer, program.per_instance) +function register_geometry_updates(@nospecialize(plot), update_buffer::Observable, program::InstancedProgram) + return register_geometry_updates(plot, update_buffer, program.per_instance) end -function uniform_updater(uniforms::Dict) +function uniform_updater(@nospecialize(plot), uniforms::Dict) updater = Observable(Any[:none, []]) for (name, value) in uniforms if value isa Sampler - on(ShaderAbstractions.updater(value).update) do (f, args) + on(plot, ShaderAbstractions.updater(value).update) do (f, args) if f === ShaderAbstractions.update! updater[] = [name, [Int32[size(value.data)...], serialize_three(args[1])]] end @@ -229,7 +229,7 @@ function uniform_updater(uniforms::Dict) end else value isa Observable || continue - on(value) do value + on(plot, value) do value updater[] = [name, serialize_three(value)] return end @@ -238,51 +238,53 @@ function uniform_updater(uniforms::Dict) return updater end -function serialize_three(ip::InstancedProgram) - program = serialize_three(ip.program) +function serialize_three(@nospecialize(plot), ip::InstancedProgram) + program = serialize_three(plot, ip.program) program[:instance_attributes] = serialize_named_buffer(ip.per_instance) - register_geometry_updates(program[:attribute_updater], ip) + register_geometry_updates(plot, program[:attribute_updater], ip) return program end -reinterpret_faces(faces::AbstractVector) = collect(reinterpret(UInt32, decompose(GLTriangleFace, faces))) +reinterpret_faces(p, faces::AbstractVector) = collect(reinterpret(UInt32, decompose(GLTriangleFace, faces))) -function reinterpret_faces(faces::Buffer) - result = Observable(reinterpret_faces(ShaderAbstractions.data(faces))) - on(ShaderAbstractions.updater(faces).update) do (f, args) +function reinterpret_faces(@nospecialize(plot), faces::Buffer) + result = Observable(reinterpret_faces(plot, ShaderAbstractions.data(faces))) + on(plot, ShaderAbstractions.updater(faces).update) do (f, args) if f === ShaderAbstractions.update! - result[] = reinterpret_faces(args[1]) + result[] = reinterpret_faces(plot, args[1]) end end return result end -function serialize_three(program::Program) - facies = reinterpret_faces(_faces(program.vertexarray)) +function serialize_three(@nospecialize(plot), program::Program) + facies = reinterpret_faces(plot, _faces(program.vertexarray)) indices = convert(Observable, facies) uniforms = serialize_uniforms(program.uniforms) attribute_updater = Observable(["", [], 0]) - register_geometry_updates(attribute_updater, program) + register_geometry_updates(plot, attribute_updater, program) + # TODO, make this configurable in ShaderAbstractions + update_shader(x) = replace(x, "#version 300 es" => "") return Dict(:vertexarrays => serialize_named_buffer(program.vertexarray), :faces => indices, :uniforms => uniforms, - :vertex_source => program.vertex_source, - :fragment_source => program.fragment_source, - :uniform_updater => uniform_updater(program.uniforms), + :vertex_source => update_shader(program.vertex_source), + :fragment_source => update_shader(program.fragment_source), + :uniform_updater => uniform_updater(plot, program.uniforms), :attribute_updater => attribute_updater) end function serialize_scene(scene::Scene) hexcolor(c) = "#" * hex(Colors.color(to_color(c))) - pixel_area = lift(area -> Int32[minimum(area)..., widths(area)...], pixelarea(scene)) + pixel_area = lift(area -> Int32[minimum(area)..., widths(area)...], scene, viewport(scene)) cam_controls = cameracontrols(scene) cam3d_state = if cam_controls isa Camera3D fields = (:lookat, :upvector, :eyeposition, :fov, :near, :far) - dict = Dict((f => serialize_three(getfield(cam_controls, f)[]) for f in fields)) - dict[:resolution] = lift(res -> Int32[res...], scene.camera.resolution) + dict = Dict((f => lift(serialize_three, scene, getfield(cam_controls, f)) for f in fields)) + dict[:resolution] = lift(res -> Int32[res...], scene, scene.camera.resolution) dict else nothing @@ -290,10 +292,17 @@ function serialize_scene(scene::Scene) children = map(child-> serialize_scene(child), scene.children) - serialized = Dict(:pixelarea => pixel_area, - :backgroundcolor => lift(hexcolor, scene.backgroundcolor), + dirlight = Makie.get_directional_light(scene) + light_dir = isnothing(dirlight) ? Observable(Vec3f(1)) : dirlight.direction + cam_rel = isnothing(dirlight) ? false : dirlight.camera_relative + + serialized = Dict(:viewport => pixel_area, + :backgroundcolor => lift(hexcolor, scene, scene.backgroundcolor), + :backgroundcolor_alpha => lift(Colors.alpha, scene, scene.backgroundcolor), :clearscene => scene.clear, :camera => serialize_camera(scene), + :light_direction => light_dir, + :camera_relative_light => cam_rel, :plots => serialize_plots(scene, scene.plots), :cam3d_state => cam3d_state, :visible => scene.visible, @@ -302,8 +311,9 @@ function serialize_scene(scene::Scene) return serialized end -function serialize_plots(scene::Scene, plots::Vector{T}, result=[]) where {T<:AbstractPlot} +function serialize_plots(scene::Scene, @nospecialize(plots::Vector{T}), result=[]) where {T<:AbstractPlot} for plot in plots + plot isa Makie.PlotList && continue # if no plots inserted, this truely is an atomic if isempty(plot.plots) plot_data = serialize_three(scene, plot) @@ -316,9 +326,9 @@ function serialize_plots(scene::Scene, plots::Vector{T}, result=[]) where {T<:Ab return result end -function serialize_three(scene::Scene, plot::AbstractPlot) +function serialize_three(scene::Scene, @nospecialize(plot::AbstractPlot)) program = create_shader(scene, plot) - mesh = serialize_three(program) + mesh = serialize_three(plot, program) mesh[:name] = string(Makie.plotkey(plot)) * "-" * string(objectid(plot)) mesh[:visible] = plot.visible mesh[:uuid] = js_uuid(plot) @@ -328,11 +338,11 @@ function serialize_three(scene::Scene, plot::AbstractPlot) uniforms = mesh[:uniforms] updater = mesh[:uniform_updater] - pointlight = Makie.get_point_light(scene) - if !isnothing(pointlight) - uniforms[:lightposition] = serialize_three(pointlight.position[]) - on(pointlight.position) do value - updater[] = [:lightposition, serialize_three(value)] + dirlight = Makie.get_directional_light(scene) + if !isnothing(dirlight) + uniforms[:light_color] = serialize_three(dirlight.color[]) + on(plot, dirlight.color) do value + updater[] = [:light_color, serialize_three(value)] return end end @@ -340,7 +350,7 @@ function serialize_three(scene::Scene, plot::AbstractPlot) ambientlight = Makie.get_ambient_light(scene) if !isnothing(ambientlight) uniforms[:ambient] = serialize_three(ambientlight.color[]) - on(ambientlight.color) do value + on(plot, ambientlight.color) do value updater[] = [:ambient, serialize_three(value)] return end diff --git a/WGLMakie/src/three_plot.jl b/WGLMakie/src/three_plot.jl index af035faf3a1..539ff7109bb 100644 --- a/WGLMakie/src/three_plot.jl +++ b/WGLMakie/src/three_plot.jl @@ -3,17 +3,6 @@ # We use objectid to find objects on the js side 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.collect_atomic_plots(plot))) - end - for child in scene.children - all_plots_scenes(child, plot_uuids=plot_uuids, scene_uuids=scene_uuids) - end - return scene_uuids, plot_uuids -end - function JSServe.print_js_code(io::IO, plot::AbstractPlot, context::JSServe.JSSourceContext) uuids = js_uuid.(Makie.collect_atomic_plots(plot)) # This is a bit more complicated then it has to be, since evaljs / on_document_load @@ -38,13 +27,12 @@ function JSServe.print_js_code(io::IO, scene::Scene, context::JSServe.JSSourceCo JSServe.print_js_code(io, js"""$(WGL).then(WGL=> WGL.find_scene($(js_uuid(scene))))""", context) end -function three_display(session::Session, scene::Scene; screen_config...) - config = Makie.merge_screen_config(ScreenConfig, screen_config)::ScreenConfig +function three_display(screen::Screen, session::Session, scene::Scene) + config = screen.config scene_serialized = serialize_scene(scene) - window_open = scene.events.window_open width, height = size(scene) - canvas_width = lift(x -> [round.(Int, widths(x))...], pixelarea(scene)) + canvas_width = lift(x -> [round.(Int, widths(x))...], scene, viewport(scene)) canvas = DOM.m("canvas"; tabindex="0", style="display: block") wrapper = DOM.div(canvas; style="width: 100%; height: 100%") comm = Observable(Dict{String,Any}()) @@ -54,7 +42,15 @@ function three_display(session::Session, scene::Scene; screen_config...) evaljs(session, js""" $(WGL).then(WGL => { try { - WGL.create_scene($wrapper, $canvas, $canvas_width, $scene_serialized, $comm, $width, $height, $(ta), $(config.framerate), $(config.resize_to_body)) + const renderer = WGL.create_scene( + $wrapper, $canvas, $canvas_width, $scene_serialized, $comm, $width, $height, + $(ta), $(config.framerate), $(config.resize_to), $(config.px_per_unit), $(config.scalefactor) + ) + const gl = renderer.getContext() + const err = gl.getError() + if (err != gl.NO_ERROR) { + throw new Error("WebGL error: " + WGL.wglerror(gl, err)) + } $(done_init).notify(true) } catch (e) { JSServe.Connection.send_error("error initializing scene", e) @@ -70,3 +66,4 @@ function three_display(session::Session, scene::Scene; screen_config...) three = ThreeDisplay(session) return three, wrapper, done_init end +| diff --git a/WGLMakie/src/wglmakie.bundled.js b/WGLMakie/src/wglmakie.bundled.js index ce41247902c..cd50663ea6c 100644 --- a/WGLMakie/src/wglmakie.bundled.js +++ b/WGLMakie/src/wglmakie.bundled.js @@ -2,19 +2,19 @@ // deno-lint-ignore-file // This code was bundled using `deno bundle` and it's not recommended to edit it manually -var ca = "136", Gy = { +var Hc = "157", zx = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 -}, Vy = { +}, Vx = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 -}, uu = 0, tl = 1, du = 2, Wy = 3, qy = 0, Hc = 1, fu = 2, ir = 3, Ai = 0, it = 1, Ci = 2, kc = 1, Xy = 2, vn = 0, sr = 1, nl = 2, il = 3, rl = 4, pu = 5, _i = 100, mu = 101, gu = 102, sl = 103, ol = 104, xu = 200, yu = 201, vu = 202, _u = 203, Gc = 204, Vc = 205, Mu = 206, bu = 207, wu = 208, Su = 209, Tu = 210, Eu = 0, Au = 1, Cu = 2, ea = 3, Lu = 4, Ru = 5, Pu = 6, Iu = 7, Vs = 0, Du = 1, Fu = 2, _n = 0, Nu = 1, Bu = 2, zu = 3, Uu = 4, Ou = 5, ha = 300, Bi = 301, zi = 302, Ds = 303, Fs = 304, Pr = 306, Ws = 307, Ns = 1e3, vt = 1001, Bs = 1002, rt = 1003, ta = 1004, Jy = 1004, na = 1005, Yy = 1005, tt = 1006, Wc = 1007, Zy = 1007, Ui = 1008, $y = 1008, rn = 1009, Hu = 1010, ku = 1011, cr = 1012, Gu = 1013, Ps = 1014, nn = 1015, kn = 1016, Vu = 1017, Wu = 1018, qu = 1019, Ti = 1020, Xu = 1021, Gn = 1022, ct = 1023, Ju = 1024, Yu = 1025, Vn = 1026, Li = 1027, Zu = 1028, $u = 1029, ju = 1030, Qu = 1031, Ku = 1032, ed = 1033, al = 33776, ll = 33777, cl = 33778, hl = 33779, ul = 35840, dl = 35841, fl = 35842, pl = 35843, td = 36196, ml = 37492, gl = 37496, nd = 37808, id = 37809, rd = 37810, sd = 37811, od = 37812, ad = 37813, ld = 37814, cd = 37815, hd = 37816, ud = 37817, dd = 37818, fd = 37819, pd = 37820, md = 37821, gd = 36492, xd = 37840, yd = 37841, vd = 37842, _d = 37843, Md = 37844, bd = 37845, wd = 37846, Sd = 37847, Td = 37848, Ed = 37849, Ad = 37850, Cd = 37851, Ld = 37852, Rd = 37853, Pd = 2200, Id = 2201, Dd = 2202, zs = 2300, Us = 2301, yo = 2302, Mi = 2400, bi = 2401, Os = 2402, ua = 2500, qc = 2501, Fd = 0, jy = 1, Qy = 2, Nt = 3e3, Oi = 3001, Nd = 3200, Bd = 3201, Hi = 0, zd = 1, Ky = 0, vo = 7680, e0 = 7681, t0 = 7682, n0 = 7683, i0 = 34055, r0 = 34056, s0 = 5386, o0 = 512, a0 = 513, l0 = 514, c0 = 515, h0 = 516, u0 = 517, d0 = 518, Ud = 519, hr = 35044, ur = 35048, f0 = 35040, p0 = 35045, m0 = 35049, g0 = 35041, x0 = 35046, y0 = 35050, v0 = 35042, _0 = "100", xl = "300 es", En = class { +}, kd = 0, rl = 1, Hd = 2, kx = 3, Hx = 0, cd = 1, Gd = 2, pn = 3, Bn = 0, Ft = 1, gn = 2, Gx = 2, Dn = 0, Wi = 1, al = 2, ol = 3, cl = 4, Wd = 5, Bi = 100, Xd = 101, qd = 102, ll = 103, hl = 104, Yd = 200, Zd = 201, Jd = 202, $d = 203, ld = 204, hd = 205, Kd = 206, Qd = 207, jd = 208, ef = 209, tf = 210, nf = 0, sf = 1, rf = 2, uo = 3, af = 4, of = 5, cf = 6, lf = 7, xa = 0, hf = 1, uf = 2, Nn = 0, df = 1, ff = 2, pf = 3, mf = 4, gf = 5, Gc = 300, zn = 301, ci = 302, Ir = 303, Ur = 304, Vs = 306, Dr = 1e3, It = 1001, Nr = 1002, pt = 1003, fo = 1004, Wx = 1004, Lr = 1005, Xx = 1005, mt = 1006, ud = 1007, qx = 1007, li = 1008, Yx = 1008, On = 1009, _f = 1010, xf = 1011, Wc = 1012, dd = 1013, Ln = 1014, xn = 1015, Ts = 1016, fd = 1017, pd = 1018, ii = 1020, vf = 1021, Wt = 1023, yf = 1024, Mf = 1025, si = 1026, Yi = 1027, Sf = 1028, md = 1029, bf = 1030, gd = 1031, _d = 1033, wa = 33776, Aa = 33777, Ra = 33778, Ca = 33779, ul = 35840, dl = 35841, fl = 35842, pl = 35843, Ef = 36196, ml = 37492, gl = 37496, _l = 37808, xl = 37809, vl = 37810, yl = 37811, Ml = 37812, Sl = 37813, bl = 37814, El = 37815, Tl = 37816, wl = 37817, Al = 37818, Rl = 37819, Cl = 37820, Pl = 37821, Pa = 36492, Ll = 36494, Il = 36495, Tf = 36283, Ul = 36284, Dl = 36285, Nl = 36286, wf = 2200, Af = 2201, Rf = 2202, Or = 2300, Fr = 2301, La = 2302, zi = 2400, Vi = 2401, Br = 2402, Xc = 2500, xd = 2501, Zx = 0, Jx = 1, $x = 2, vd = 3e3, ri = 3001, Cf = 3200, Pf = 3201, mi = 0, Lf = 1, Xt = "", vt = "srgb", Mn = "srgb-linear", qc = "display-p3", va = "display-p3-linear", zr = "linear", nt = "srgb", Vr = "rec709", kr = "p3", Kx = 0, Ia = 7680, Qx = 7681, jx = 7682, ev = 7683, tv = 34055, nv = 34056, iv = 5386, sv = 512, rv = 513, av = 514, ov = 515, cv = 516, lv = 517, hv = 518, If = 519, Uf = 512, Df = 513, Nf = 514, Of = 515, Ff = 516, Bf = 517, zf = 518, Vf = 519, Hr = 35044, uv = 35048, dv = 35040, fv = 35045, pv = 35049, mv = 35041, gv = 35046, _v = 35050, xv = 35042, vv = "100", Ol = "300 es", po = 1035, vn = 2e3, Gr = 2001, sn = class { addEventListener(e, t) { this._listeners === void 0 && (this._listeners = {}); let n = this._listeners; @@ -39,123 +39,421 @@ var ca = "136", Gy = { if (n !== void 0) { e.target = this; let i = n.slice(0); - for(let r = 0, o = i.length; r < o; r++)i[r].call(this, e); + for(let r = 0, a = i.length; r < a; r++)i[r].call(this, e); e.target = null; } } -}, pt = []; -for(let s = 0; s < 256; s++)pt[s] = (s < 16 ? "0" : "") + s.toString(16); -var Vr = 1234567, Wn = Math.PI / 180, dr = 180 / Math.PI; -function Et() { - let s = Math.random() * 4294967295 | 0, e = Math.random() * 4294967295 | 0, t = Math.random() * 4294967295 | 0, n = Math.random() * 4294967295 | 0; - return (pt[s & 255] + pt[s >> 8 & 255] + pt[s >> 16 & 255] + pt[s >> 24 & 255] + "-" + pt[e & 255] + pt[e >> 8 & 255] + "-" + pt[e >> 16 & 15 | 64] + pt[e >> 24 & 255] + "-" + pt[t & 63 | 128] + pt[t >> 8 & 255] + "-" + pt[t >> 16 & 255] + pt[t >> 24 & 255] + pt[n & 255] + pt[n >> 8 & 255] + pt[n >> 16 & 255] + pt[n >> 24 & 255]).toUpperCase(); -} -function mt(s, e, t) { - return Math.max(e, Math.min(t, s)); -} -function da(s, e) { - return (s % e + e) % e; -} -function Od(s, e, t, n, i) { - return n + (s - e) * (i - n) / (t - e); -} -function Hd(s, e, t) { - return s !== e ? (t - s) / (e - s) : 0; -} -function or(s, e, t) { - return (1 - t) * s + t * e; -} -function kd(s, e, t, n) { - return or(s, e, 1 - Math.exp(-t * n)); -} -function Gd(s, e = 1) { - return e - Math.abs(da(s, e * 2) - e); -} -function Vd(s, e, t) { - return s <= e ? 0 : s >= t ? 1 : (s = (s - e) / (t - e), s * s * (3 - 2 * s)); -} -function Wd(s, e, t) { - return s <= e ? 0 : s >= t ? 1 : (s = (s - e) / (t - e), s * s * s * (s * (s * 6 - 15) + 10)); -} -function qd(s, e) { - return s + Math.floor(Math.random() * (e - s + 1)); -} -function Xd(s, e) { - return s + Math.random() * (e - s); -} -function Jd(s) { - return s * (.5 - Math.random()); -} -function Yd(s) { - return s !== void 0 && (Vr = s % 2147483647), Vr = Vr * 16807 % 2147483647, (Vr - 1) / 2147483646; -} -function Zd(s) { - return s * Wn; -} -function $d(s) { - return s * dr; -} -function ia(s) { - return (s & s - 1) === 0 && s !== 0; -} -function Xc(s) { - return Math.pow(2, Math.ceil(Math.log(s) / Math.LN2)); -} -function Jc(s) { - return Math.pow(2, Math.floor(Math.log(s) / Math.LN2)); -} -function jd(s, e, t, n, i) { - let r = Math.cos, o = Math.sin, a = r(t / 2), l = o(t / 2), c = r((e + n) / 2), h = o((e + n) / 2), u = r((e - n) / 2), d = o((e - n) / 2), f = r((n - e) / 2), m = o((n - e) / 2); +}, Et = [ + "00", + "01", + "02", + "03", + "04", + "05", + "06", + "07", + "08", + "09", + "0a", + "0b", + "0c", + "0d", + "0e", + "0f", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "1a", + "1b", + "1c", + "1d", + "1e", + "1f", + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "2a", + "2b", + "2c", + "2d", + "2e", + "2f", + "30", + "31", + "32", + "33", + "34", + "35", + "36", + "37", + "38", + "39", + "3a", + "3b", + "3c", + "3d", + "3e", + "3f", + "40", + "41", + "42", + "43", + "44", + "45", + "46", + "47", + "48", + "49", + "4a", + "4b", + "4c", + "4d", + "4e", + "4f", + "50", + "51", + "52", + "53", + "54", + "55", + "56", + "57", + "58", + "59", + "5a", + "5b", + "5c", + "5d", + "5e", + "5f", + "60", + "61", + "62", + "63", + "64", + "65", + "66", + "67", + "68", + "69", + "6a", + "6b", + "6c", + "6d", + "6e", + "6f", + "70", + "71", + "72", + "73", + "74", + "75", + "76", + "77", + "78", + "79", + "7a", + "7b", + "7c", + "7d", + "7e", + "7f", + "80", + "81", + "82", + "83", + "84", + "85", + "86", + "87", + "88", + "89", + "8a", + "8b", + "8c", + "8d", + "8e", + "8f", + "90", + "91", + "92", + "93", + "94", + "95", + "96", + "97", + "98", + "99", + "9a", + "9b", + "9c", + "9d", + "9e", + "9f", + "a0", + "a1", + "a2", + "a3", + "a4", + "a5", + "a6", + "a7", + "a8", + "a9", + "aa", + "ab", + "ac", + "ad", + "ae", + "af", + "b0", + "b1", + "b2", + "b3", + "b4", + "b5", + "b6", + "b7", + "b8", + "b9", + "ba", + "bb", + "bc", + "bd", + "be", + "bf", + "c0", + "c1", + "c2", + "c3", + "c4", + "c5", + "c6", + "c7", + "c8", + "c9", + "ca", + "cb", + "cc", + "cd", + "ce", + "cf", + "d0", + "d1", + "d2", + "d3", + "d4", + "d5", + "d6", + "d7", + "d8", + "d9", + "da", + "db", + "dc", + "dd", + "de", + "df", + "e0", + "e1", + "e2", + "e3", + "e4", + "e5", + "e6", + "e7", + "e8", + "e9", + "ea", + "eb", + "ec", + "ed", + "ee", + "ef", + "f0", + "f1", + "f2", + "f3", + "f4", + "f5", + "f6", + "f7", + "f8", + "f9", + "fa", + "fb", + "fc", + "fd", + "fe", + "ff" +], Fl = 1234567, ai = Math.PI / 180, Zi = 180 / Math.PI; +function kt() { + let s1 = Math.random() * 4294967295 | 0, e = Math.random() * 4294967295 | 0, t = Math.random() * 4294967295 | 0, n = Math.random() * 4294967295 | 0; + return (Et[s1 & 255] + Et[s1 >> 8 & 255] + Et[s1 >> 16 & 255] + Et[s1 >> 24 & 255] + "-" + Et[e & 255] + Et[e >> 8 & 255] + "-" + Et[e >> 16 & 15 | 64] + Et[e >> 24 & 255] + "-" + Et[t & 63 | 128] + Et[t >> 8 & 255] + "-" + Et[t >> 16 & 255] + Et[t >> 24 & 255] + Et[n & 255] + Et[n >> 8 & 255] + Et[n >> 16 & 255] + Et[n >> 24 & 255]).toLowerCase(); +} +function ct(s1, e, t) { + return Math.max(e, Math.min(t, s1)); +} +function Yc(s1, e) { + return (s1 % e + e) % e; +} +function kf(s1, e, t, n, i) { + return n + (s1 - e) * (i - n) / (t - e); +} +function Hf(s1, e, t) { + return s1 !== e ? (t - s1) / (e - s1) : 0; +} +function ys(s1, e, t) { + return (1 - t) * s1 + t * e; +} +function Gf(s1, e, t, n) { + return ys(s1, e, 1 - Math.exp(-t * n)); +} +function Wf(s1, e = 1) { + return e - Math.abs(Yc(s1, e * 2) - e); +} +function Xf(s1, e, t) { + return s1 <= e ? 0 : s1 >= t ? 1 : (s1 = (s1 - e) / (t - e), s1 * s1 * (3 - 2 * s1)); +} +function qf(s1, e, t) { + return s1 <= e ? 0 : s1 >= t ? 1 : (s1 = (s1 - e) / (t - e), s1 * s1 * s1 * (s1 * (s1 * 6 - 15) + 10)); +} +function Yf(s1, e) { + return s1 + Math.floor(Math.random() * (e - s1 + 1)); +} +function Zf(s1, e) { + return s1 + Math.random() * (e - s1); +} +function Jf(s1) { + return s1 * (.5 - Math.random()); +} +function $f(s1) { + s1 !== void 0 && (Fl = s1); + let e = Fl += 1831565813; + return e = Math.imul(e ^ e >>> 15, e | 1), e ^= e + Math.imul(e ^ e >>> 7, e | 61), ((e ^ e >>> 14) >>> 0) / 4294967296; +} +function Kf(s1) { + return s1 * ai; +} +function Qf(s1) { + return s1 * Zi; +} +function mo(s1) { + return (s1 & s1 - 1) === 0 && s1 !== 0; +} +function yd(s1) { + return Math.pow(2, Math.ceil(Math.log(s1) / Math.LN2)); +} +function Wr(s1) { + return Math.pow(2, Math.floor(Math.log(s1) / Math.LN2)); +} +function jf(s1, e, t, n, i) { + let r = Math.cos, a = Math.sin, o = r(t / 2), c = a(t / 2), l = r((e + n) / 2), h = a((e + n) / 2), u = r((e - n) / 2), d = a((e - n) / 2), f = r((n - e) / 2), m = a((n - e) / 2); switch(i){ case "XYX": - s.set(a * h, l * u, l * d, a * c); + s1.set(o * h, c * u, c * d, o * l); break; case "YZY": - s.set(l * d, a * h, l * u, a * c); + s1.set(c * d, o * h, c * u, o * l); break; case "ZXZ": - s.set(l * u, l * d, a * h, a * c); + s1.set(c * u, c * d, o * h, o * l); break; case "XZX": - s.set(a * h, l * m, l * f, a * c); + s1.set(o * h, c * m, c * f, o * l); break; case "YXY": - s.set(l * f, a * h, l * m, a * c); + s1.set(c * f, o * h, c * m, o * l); break; case "ZYZ": - s.set(l * m, l * f, a * h, a * c); + s1.set(c * m, c * f, o * h, o * l); break; default: console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: " + i); } } -var M0 = Object.freeze({ - __proto__: null, - DEG2RAD: Wn, - RAD2DEG: dr, - generateUUID: Et, - clamp: mt, - euclideanModulo: da, - mapLinear: Od, - inverseLerp: Hd, - lerp: or, - damp: kd, - pingpong: Gd, - smoothstep: Vd, - smootherstep: Wd, - randInt: qd, - randFloat: Xd, - randFloatSpread: Jd, - seededRandom: Yd, - degToRad: Zd, - radToDeg: $d, - isPowerOfTwo: ia, - ceilPowerOfTwo: Xc, - floorPowerOfTwo: Jc, - setQuaternionFromProperEuler: jd -}), X = class { +function Ot(s1, e) { + switch(e.constructor){ + case Float32Array: + return s1; + case Uint32Array: + return s1 / 4294967295; + case Uint16Array: + return s1 / 65535; + case Uint8Array: + return s1 / 255; + case Int32Array: + return Math.max(s1 / 2147483647, -1); + case Int16Array: + return Math.max(s1 / 32767, -1); + case Int8Array: + return Math.max(s1 / 127, -1); + default: + throw new Error("Invalid component type."); + } +} +function Be(s1, e) { + switch(e.constructor){ + case Float32Array: + return s1; + case Uint32Array: + return Math.round(s1 * 4294967295); + case Uint16Array: + return Math.round(s1 * 65535); + case Uint8Array: + return Math.round(s1 * 255); + case Int32Array: + return Math.round(s1 * 2147483647); + case Int16Array: + return Math.round(s1 * 32767); + case Int8Array: + return Math.round(s1 * 127); + default: + throw new Error("Invalid component type."); + } +} +var yv = { + DEG2RAD: ai, + RAD2DEG: Zi, + generateUUID: kt, + clamp: ct, + euclideanModulo: Yc, + mapLinear: kf, + inverseLerp: Hf, + lerp: ys, + damp: Gf, + pingpong: Wf, + smoothstep: Xf, + smootherstep: qf, + randInt: Yf, + randFloat: Zf, + randFloatSpread: Jf, + seededRandom: $f, + degToRad: Kf, + radToDeg: Qf, + isPowerOfTwo: mo, + ceilPowerOfTwo: yd, + floorPowerOfTwo: Wr, + setQuaternionFromProperEuler: jf, + normalize: Be, + denormalize: Ot +}, Z = class s1 { constructor(e = 0, t = 0){ - this.x = e, this.y = t; + s1.prototype.isVector2 = !0, this.x = e, this.y = t; } get width() { return this.x; @@ -210,8 +508,8 @@ var M0 = Object.freeze({ copy(e) { return this.x = e.x, this.y = e.y, this; } - add(e, t) { - return t !== void 0 ? (console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."), this.addVectors(e, t)) : (this.x += e.x, this.y += e.y, this); + add(e) { + return this.x += e.x, this.y += e.y, this; } addScalar(e) { return this.x += e, this.y += e, this; @@ -222,8 +520,8 @@ var M0 = Object.freeze({ addScaledVector(e, t) { return this.x += e.x * t, this.y += e.y * t, this; } - sub(e, t) { - return t !== void 0 ? (console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), this.subVectors(e, t)) : (this.x -= e.x, this.y -= e.y, this); + sub(e) { + return this.x -= e.x, this.y -= e.y, this; } subScalar(e) { return this.x -= e, this.y -= e, this; @@ -273,7 +571,7 @@ var M0 = Object.freeze({ return this.x = Math.round(this.x), this.y = Math.round(this.y), this; } roundToZero() { - return this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x), this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y), this; + return this.x = Math.trunc(this.x), this.y = Math.trunc(this.y), this; } negate() { return this.x = -this.x, this.y = -this.y, this; @@ -299,6 +597,12 @@ var M0 = Object.freeze({ angle() { return Math.atan2(-this.y, -this.x) + Math.PI; } + angleTo(e) { + let t = Math.sqrt(this.lengthSq() * e.lengthSq()); + if (t === 0) return Math.PI / 2; + let n = this.dot(e) / t; + return Math.acos(ct(n, -1, 1)); + } distanceTo(e) { return Math.sqrt(this.distanceToSquared(e)); } @@ -327,12 +631,12 @@ var M0 = Object.freeze({ toArray(e = [], t = 0) { return e[t] = this.x, e[t + 1] = this.y, e; } - fromBufferAttribute(e, t, n) { - return n !== void 0 && console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute()."), this.x = e.getX(t), this.y = e.getY(t), this; + fromBufferAttribute(e, t) { + return this.x = e.getX(t), this.y = e.getY(t), this; } rotateAround(e, t) { - let n = Math.cos(t), i = Math.sin(t), r = this.x - e.x, o = this.y - e.y; - return this.x = r * n - o * i + e.x, this.y = r * i + o * n + e.y, this; + let n = Math.cos(t), i = Math.sin(t), r = this.x - e.x, a = this.y - e.y; + return this.x = r * n - a * i + e.x, this.y = r * i + a * n + e.y, this; } random() { return this.x = Math.random(), this.y = Math.random(), this; @@ -340,11 +644,9 @@ var M0 = Object.freeze({ *[Symbol.iterator]() { yield this.x, yield this.y; } -}; -X.prototype.isVector2 = !0; -var lt = class { - constructor(){ - this.elements = [ +}, He = class s1 { + constructor(e, t, n, i, r, a, o, c, l){ + s1.prototype.isMatrix3 = !0, this.elements = [ 1, 0, 0, @@ -354,11 +656,11 @@ var lt = class { 0, 0, 1 - ], arguments.length > 0 && console.error("THREE.Matrix3: the constructor no longer reads arguments. use .set() instead."); + ], e !== void 0 && this.set(e, t, n, i, r, a, o, c, l); } - set(e, t, n, i, r, o, a, l, c) { + set(e, t, n, i, r, a, o, c, l) { let h = this.elements; - return h[0] = e, h[1] = i, h[2] = a, h[3] = t, h[4] = r, h[5] = l, h[6] = n, h[7] = o, h[8] = c, this; + return h[0] = e, h[1] = i, h[2] = o, h[3] = t, h[4] = r, h[5] = c, h[6] = n, h[7] = a, h[8] = l, this; } identity() { return this.set(1, 0, 0, 0, 1, 0, 0, 0, 1), this; @@ -381,22 +683,22 @@ var lt = class { return this.multiplyMatrices(e, this); } multiplyMatrices(e, t) { - let n = e.elements, i = t.elements, r = this.elements, o = n[0], a = n[3], l = n[6], c = n[1], h = n[4], u = n[7], d = n[2], f = n[5], m = n[8], x = i[0], v = i[3], g = i[6], p = i[1], _ = i[4], y = i[7], b = i[2], A = i[5], L = i[8]; - return r[0] = o * x + a * p + l * b, r[3] = o * v + a * _ + l * A, r[6] = o * g + a * y + l * L, r[1] = c * x + h * p + u * b, r[4] = c * v + h * _ + u * A, r[7] = c * g + h * y + u * L, r[2] = d * x + f * p + m * b, r[5] = d * v + f * _ + m * A, r[8] = d * g + f * y + m * L, this; + let n = e.elements, i = t.elements, r = this.elements, a = n[0], o = n[3], c = n[6], l = n[1], h = n[4], u = n[7], d = n[2], f = n[5], m = n[8], _ = i[0], g = i[3], p = i[6], v = i[1], x = i[4], y = i[7], b = i[2], w = i[5], R = i[8]; + return r[0] = a * _ + o * v + c * b, r[3] = a * g + o * x + c * w, r[6] = a * p + o * y + c * R, r[1] = l * _ + h * v + u * b, r[4] = l * g + h * x + u * w, r[7] = l * p + h * y + u * R, r[2] = d * _ + f * v + m * b, r[5] = d * g + f * x + m * w, r[8] = d * p + f * y + m * R, this; } multiplyScalar(e) { let t = this.elements; return t[0] *= e, t[3] *= e, t[6] *= e, t[1] *= e, t[4] *= e, t[7] *= e, t[2] *= e, t[5] *= e, t[8] *= e, this; } determinant() { - let e = this.elements, t = e[0], n = e[1], i = e[2], r = e[3], o = e[4], a = e[5], l = e[6], c = e[7], h = e[8]; - return t * o * h - t * a * c - n * r * h + n * a * l + i * r * c - i * o * l; + let e = this.elements, t = e[0], n = e[1], i = e[2], r = e[3], a = e[4], o = e[5], c = e[6], l = e[7], h = e[8]; + return t * a * h - t * o * l - n * r * h + n * o * c + i * r * l - i * a * c; } invert() { - let e = this.elements, t = e[0], n = e[1], i = e[2], r = e[3], o = e[4], a = e[5], l = e[6], c = e[7], h = e[8], u = h * o - a * c, d = a * l - h * r, f = c * r - o * l, m = t * u + n * d + i * f; + let e = this.elements, t = e[0], n = e[1], i = e[2], r = e[3], a = e[4], o = e[5], c = e[6], l = e[7], h = e[8], u = h * a - o * l, d = o * c - h * r, f = l * r - a * c, m = t * u + n * d + i * f; if (m === 0) return this.set(0, 0, 0, 0, 0, 0, 0, 0, 0); - let x = 1 / m; - return e[0] = u * x, e[1] = (i * c - h * n) * x, e[2] = (a * n - i * o) * x, e[3] = d * x, e[4] = (h * t - i * l) * x, e[5] = (i * r - a * t) * x, e[6] = f * x, e[7] = (n * l - c * t) * x, e[8] = (o * t - n * r) * x, this; + let _ = 1 / m; + return e[0] = u * _, e[1] = (i * l - h * n) * _, e[2] = (o * n - i * a) * _, e[3] = d * _, e[4] = (h * t - i * c) * _, e[5] = (i * r - o * t) * _, e[6] = f * _, e[7] = (n * c - l * t) * _, e[8] = (a * t - n * r) * _, this; } transpose() { let e, t = this.elements; @@ -409,21 +711,28 @@ var lt = class { let t = this.elements; return e[0] = t[0], e[1] = t[3], e[2] = t[6], e[3] = t[1], e[4] = t[4], e[5] = t[7], e[6] = t[2], e[7] = t[5], e[8] = t[8], this; } - setUvTransform(e, t, n, i, r, o, a) { - let l = Math.cos(r), c = Math.sin(r); - return this.set(n * l, n * c, -n * (l * o + c * a) + o + e, -i * c, i * l, -i * (-c * o + l * a) + a + t, 0, 0, 1), this; + setUvTransform(e, t, n, i, r, a, o) { + let c = Math.cos(r), l = Math.sin(r); + return this.set(n * c, n * l, -n * (c * a + l * o) + a + e, -i * l, i * c, -i * (-l * a + c * o) + o + t, 0, 0, 1), this; } scale(e, t) { - let n = this.elements; - return n[0] *= e, n[3] *= e, n[6] *= e, n[1] *= t, n[4] *= t, n[7] *= t, this; + return this.premultiply(Ua.makeScale(e, t)), this; } rotate(e) { - let t = Math.cos(e), n = Math.sin(e), i = this.elements, r = i[0], o = i[3], a = i[6], l = i[1], c = i[4], h = i[7]; - return i[0] = t * r + n * l, i[3] = t * o + n * c, i[6] = t * a + n * h, i[1] = -n * r + t * l, i[4] = -n * o + t * c, i[7] = -n * a + t * h, this; + return this.premultiply(Ua.makeRotation(-e)), this; } translate(e, t) { - let n = this.elements; - return n[0] += e * n[2], n[3] += e * n[5], n[6] += e * n[8], n[1] += t * n[2], n[4] += t * n[5], n[7] += t * n[8], this; + return this.premultiply(Ua.makeTranslation(e, t)), this; + } + makeTranslation(e, t) { + return e.isVector2 ? this.set(1, 0, e.x, 0, 1, e.y, 0, 0, 1) : this.set(1, 0, e, 0, 1, t, 0, 0, 1), this; + } + makeRotation(e) { + let t = Math.cos(e), n = Math.sin(e); + return this.set(t, -n, 0, n, t, 0, 0, 0, 1), this; + } + makeScale(e, t) { + return this.set(e, 0, 0, 0, t, 0, 0, 0, 1), this; } equals(e) { let t = this.elements, n = e.elements; @@ -441,15 +750,12 @@ var lt = class { clone() { return new this.constructor().fromArray(this.elements); } -}; -lt.prototype.isMatrix3 = !0; -function Yc(s) { - if (s.length === 0) return -1 / 0; - let e = s[0]; - for(let t = 1, n = s.length; t < n; ++t)s[t] > e && (e = s[t]); - return e; +}, Ua = new He; +function Md(s1) { + for(let e = s1.length - 1; e >= 0; --e)if (s1[e] >= 65535) return !0; + return !1; } -var Qd = { +var ep = { Int8Array, Uint8Array, Uint8ClampedArray, @@ -460,30 +766,165 @@ var Qd = { Float32Array, Float64Array }; -function wi(s, e) { - return new Qd[s](e); +function ki(s1, e) { + return new ep[s1](e); +} +function ws(s1) { + return document.createElementNS("http://www.w3.org/1999/xhtml", s1); +} +function tp() { + let s1 = ws("canvas"); + return s1.style.display = "block", s1; +} +var Bl = {}; +function Ms(s1) { + s1 in Bl || (Bl[s1] = !0, console.warn(s1)); +} +var zl = new He().set(.8224621, .177538, 0, .0331941, .9668058, 0, .0170827, .0723974, .9105199), Vl = new He().set(1.2249401, -.2249404, 0, -.0420569, 1.0420571, 0, -.0196376, -.0786361, 1.0982735), Gs = { + [Mn]: { + transfer: zr, + primaries: Vr, + toReference: (s1)=>s1, + fromReference: (s1)=>s1 + }, + [vt]: { + transfer: nt, + primaries: Vr, + toReference: (s1)=>s1.convertSRGBToLinear(), + fromReference: (s1)=>s1.convertLinearToSRGB() + }, + [va]: { + transfer: zr, + primaries: kr, + toReference: (s1)=>s1.applyMatrix3(Vl), + fromReference: (s1)=>s1.applyMatrix3(zl) + }, + [qc]: { + transfer: nt, + primaries: kr, + toReference: (s1)=>s1.convertSRGBToLinear().applyMatrix3(Vl), + fromReference: (s1)=>s1.applyMatrix3(zl).convertLinearToSRGB() + } +}, np = new Set([ + Mn, + va +]), Qe = { + enabled: !0, + _workingColorSpace: Mn, + get legacyMode () { + return console.warn("THREE.ColorManagement: .legacyMode=false renamed to .enabled=true in r150."), !this.enabled; + }, + set legacyMode (s){ + console.warn("THREE.ColorManagement: .legacyMode=false renamed to .enabled=true in r150."), this.enabled = !s; + }, + get workingColorSpace () { + return this._workingColorSpace; + }, + set workingColorSpace (s){ + if (!np.has(s)) throw new Error(`Unsupported working color space, "${s}".`); + this._workingColorSpace = s; + }, + convert: function(s1, e, t) { + if (this.enabled === !1 || e === t || !e || !t) return s1; + let n = Gs[e].toReference, i = Gs[t].fromReference; + return i(n(s1)); + }, + fromWorkingColorSpace: function(s1, e) { + return this.convert(s1, this._workingColorSpace, e); + }, + toWorkingColorSpace: function(s1, e) { + return this.convert(s1, e, this._workingColorSpace); + }, + getPrimaries: function(s1) { + return Gs[s1].primaries; + }, + getTransfer: function(s1) { + return s1 === Xt ? zr : Gs[s1].transfer; + } +}; +function Xi(s1) { + return s1 < .04045 ? s1 * .0773993808 : Math.pow(s1 * .9478672986 + .0521327014, 2.4); } -function qs(s) { - return document.createElementNS("http://www.w3.org/1999/xhtml", s); +function Da(s1) { + return s1 < .0031308 ? s1 * 12.92 : 1.055 * Math.pow(s1, .41666) - .055; } -var ti, Yn = class { +var gi, Xr = class { static getDataURL(e) { if (/^data:/i.test(e.src) || typeof HTMLCanvasElement > "u") return e.src; let t; if (e instanceof HTMLCanvasElement) t = e; else { - ti === void 0 && (ti = qs("canvas")), ti.width = e.width, ti.height = e.height; - let n = ti.getContext("2d"); - e instanceof ImageData ? n.putImageData(e, 0, 0) : n.drawImage(e, 0, 0, e.width, e.height), t = ti; + gi === void 0 && (gi = ws("canvas")), gi.width = e.width, gi.height = e.height; + let n = gi.getContext("2d"); + e instanceof ImageData ? n.putImageData(e, 0, 0) : n.drawImage(e, 0, 0, e.width, e.height), t = gi; } return t.width > 2048 || t.height > 2048 ? (console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons", e), t.toDataURL("image/jpeg", .6)) : t.toDataURL("image/png"); } -}, Kd = 0, ot = class extends En { - constructor(e = ot.DEFAULT_IMAGE, t = ot.DEFAULT_MAPPING, n = vt, i = vt, r = tt, o = Ui, a = ct, l = rn, c = 1, h = Nt){ - super(); - Object.defineProperty(this, "id", { - value: Kd++ - }), this.uuid = Et(), this.name = "", this.image = e, this.mipmaps = [], this.mapping = t, this.wrapS = n, this.wrapT = i, this.magFilter = r, this.minFilter = o, this.anisotropy = c, this.format = a, this.internalFormat = null, this.type = l, this.offset = new X(0, 0), this.repeat = new X(1, 1), this.center = new X(0, 0), this.rotation = 0, this.matrixAutoUpdate = !0, this.matrix = new lt, this.generateMipmaps = !0, this.premultiplyAlpha = !1, this.flipY = !0, this.unpackAlignment = 4, this.encoding = h, this.userData = {}, this.version = 0, this.onUpdate = null, this.isRenderTargetTexture = !1; + static sRGBToLinear(e) { + if (typeof HTMLImageElement < "u" && e instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && e instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && e instanceof ImageBitmap) { + let t = ws("canvas"); + t.width = e.width, t.height = e.height; + let n = t.getContext("2d"); + n.drawImage(e, 0, 0, e.width, e.height); + let i = n.getImageData(0, 0, e.width, e.height), r = i.data; + for(let a = 0; a < r.length; a++)r[a] = Xi(r[a] / 255) * 255; + return n.putImageData(i, 0, 0), t; + } else if (e.data) { + let t = e.data.slice(0); + for(let n = 0; n < t.length; n++)t instanceof Uint8Array || t instanceof Uint8ClampedArray ? t[n] = Math.floor(Xi(t[n] / 255) * 255) : t[n] = Xi(t[n]); + return { + data: t, + width: e.width, + height: e.height + }; + } else return console.warn("THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied."), e; + } +}, ip = 0, In = class { + constructor(e = null){ + this.isSource = !0, Object.defineProperty(this, "id", { + value: ip++ + }), this.uuid = kt(), this.data = e, this.version = 0; + } + set needsUpdate(e) { + e === !0 && this.version++; + } + toJSON(e) { + let t = e === void 0 || typeof e == "string"; + if (!t && e.images[this.uuid] !== void 0) return e.images[this.uuid]; + let n = { + uuid: this.uuid, + url: "" + }, i = this.data; + if (i !== null) { + let r; + if (Array.isArray(i)) { + r = []; + for(let a = 0, o = i.length; a < o; a++)i[a].isDataTexture ? r.push(Na(i[a].image)) : r.push(Na(i[a])); + } else r = Na(i); + n.url = r; + } + return t || (e.images[this.uuid] = n), n; + } +}; +function Na(s1) { + return typeof HTMLImageElement < "u" && s1 instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && s1 instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && s1 instanceof ImageBitmap ? Xr.getDataURL(s1) : s1.data ? { + data: Array.from(s1.data), + width: s1.width, + height: s1.height, + type: s1.data.constructor.name + } : (console.warn("THREE.Texture: Unable to serialize Texture."), {}); +} +var sp = 0, St = class s1 extends sn { + constructor(e = s1.DEFAULT_IMAGE, t = s1.DEFAULT_MAPPING, n = It, i = It, r = mt, a = li, o = Wt, c = On, l = s1.DEFAULT_ANISOTROPY, h = Xt){ + super(), this.isTexture = !0, Object.defineProperty(this, "id", { + value: sp++ + }), this.uuid = kt(), this.name = "", this.source = new In(e), this.mipmaps = [], this.mapping = t, this.channel = 0, this.wrapS = n, this.wrapT = i, this.magFilter = r, this.minFilter = a, this.anisotropy = l, this.format = o, this.internalFormat = null, this.type = c, this.offset = new Z(0, 0), this.repeat = new Z(1, 1), this.center = new Z(0, 0), this.rotation = 0, this.matrixAutoUpdate = !0, this.matrix = new He, this.generateMipmaps = !0, this.premultiplyAlpha = !1, this.flipY = !0, this.unpackAlignment = 4, typeof h == "string" ? this.colorSpace = h : (Ms("THREE.Texture: Property .encoding has been replaced by .colorSpace."), this.colorSpace = h === ri ? vt : Xt), this.userData = {}, this.version = 0, this.onUpdate = null, this.isRenderTargetTexture = !1, this.needsPMREMUpdate = !1; + } + get image() { + return this.source.data; + } + set image(e = null) { + this.source.data = e; } updateMatrix() { this.matrix.setUvTransform(this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y); @@ -492,20 +933,22 @@ var ti, Yn = class { return new this.constructor().copy(this); } copy(e) { - return this.name = e.name, this.image = e.image, this.mipmaps = e.mipmaps.slice(0), this.mapping = e.mapping, this.wrapS = e.wrapS, this.wrapT = e.wrapT, this.magFilter = e.magFilter, this.minFilter = e.minFilter, this.anisotropy = e.anisotropy, this.format = e.format, this.internalFormat = e.internalFormat, this.type = e.type, this.offset.copy(e.offset), this.repeat.copy(e.repeat), this.center.copy(e.center), this.rotation = e.rotation, this.matrixAutoUpdate = e.matrixAutoUpdate, this.matrix.copy(e.matrix), this.generateMipmaps = e.generateMipmaps, this.premultiplyAlpha = e.premultiplyAlpha, this.flipY = e.flipY, this.unpackAlignment = e.unpackAlignment, this.encoding = e.encoding, this.userData = JSON.parse(JSON.stringify(e.userData)), this; + return this.name = e.name, this.source = e.source, this.mipmaps = e.mipmaps.slice(0), this.mapping = e.mapping, this.channel = e.channel, this.wrapS = e.wrapS, this.wrapT = e.wrapT, this.magFilter = e.magFilter, this.minFilter = e.minFilter, this.anisotropy = e.anisotropy, this.format = e.format, this.internalFormat = e.internalFormat, this.type = e.type, this.offset.copy(e.offset), this.repeat.copy(e.repeat), this.center.copy(e.center), this.rotation = e.rotation, this.matrixAutoUpdate = e.matrixAutoUpdate, this.matrix.copy(e.matrix), this.generateMipmaps = e.generateMipmaps, this.premultiplyAlpha = e.premultiplyAlpha, this.flipY = e.flipY, this.unpackAlignment = e.unpackAlignment, this.colorSpace = e.colorSpace, this.userData = JSON.parse(JSON.stringify(e.userData)), this.needsUpdate = !0, this; } toJSON(e) { let t = e === void 0 || typeof e == "string"; if (!t && e.textures[this.uuid] !== void 0) return e.textures[this.uuid]; let n = { metadata: { - version: 4.5, + version: 4.6, type: "Texture", generator: "Texture.toJSON" }, uuid: this.uuid, name: this.name, + image: this.source.toJSON(e).uuid, mapping: this.mapping, + channel: this.channel, repeat: [ this.repeat.x, this.repeat.y @@ -524,31 +967,18 @@ var ti, Yn = class { this.wrapT ], format: this.format, + internalFormat: this.internalFormat, type: this.type, - encoding: this.encoding, + colorSpace: this.colorSpace, minFilter: this.minFilter, magFilter: this.magFilter, anisotropy: this.anisotropy, flipY: this.flipY, + generateMipmaps: this.generateMipmaps, premultiplyAlpha: this.premultiplyAlpha, unpackAlignment: this.unpackAlignment }; - if (this.image !== void 0) { - let i = this.image; - if (i.uuid === void 0 && (i.uuid = Et()), !t && e.images[i.uuid] === void 0) { - let r; - if (Array.isArray(i)) { - r = []; - for(let o = 0, a = i.length; o < a; o++)i[o].isDataTexture ? r.push(_o(i[o].image)) : r.push(_o(i[o])); - } else r = _o(i); - e.images[i.uuid] = { - uuid: i.uuid, - url: r - }; - } - n.image = i.uuid; - } - return JSON.stringify(this.userData) !== "{}" && (n.userData = this.userData), t || (e.textures[this.uuid] = n), n; + return Object.keys(this.userData).length > 0 && (n.userData = this.userData), t || (e.textures[this.uuid] = n), n; } dispose() { this.dispatchEvent({ @@ -556,49 +986,47 @@ var ti, Yn = class { }); } transformUv(e) { - if (this.mapping !== ha) return e; + if (this.mapping !== Gc) return e; if (e.applyMatrix3(this.matrix), e.x < 0 || e.x > 1) switch(this.wrapS){ - case Ns: + case Dr: e.x = e.x - Math.floor(e.x); break; - case vt: + case It: e.x = e.x < 0 ? 0 : 1; break; - case Bs: + case Nr: Math.abs(Math.floor(e.x) % 2) === 1 ? e.x = Math.ceil(e.x) - e.x : e.x = e.x - Math.floor(e.x); break; } if (e.y < 0 || e.y > 1) switch(this.wrapT){ - case Ns: + case Dr: e.y = e.y - Math.floor(e.y); break; - case vt: + case It: e.y = e.y < 0 ? 0 : 1; break; - case Bs: + case Nr: Math.abs(Math.floor(e.y) % 2) === 1 ? e.y = Math.ceil(e.y) - e.y : e.y = e.y - Math.floor(e.y); break; } return this.flipY && (e.y = 1 - e.y), e; } set needsUpdate(e) { - e === !0 && this.version++; + e === !0 && (this.version++, this.source.needsUpdate = !0); + } + get encoding() { + return Ms("THREE.Texture: Property .encoding has been replaced by .colorSpace."), this.colorSpace === vt ? ri : vd; + } + set encoding(e) { + Ms("THREE.Texture: Property .encoding has been replaced by .colorSpace."), this.colorSpace = e === ri ? vt : Xt; } }; -ot.DEFAULT_IMAGE = void 0; -ot.DEFAULT_MAPPING = ha; -ot.prototype.isTexture = !0; -function _o(s) { - return typeof HTMLImageElement < "u" && s instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && s instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && s instanceof ImageBitmap ? Yn.getDataURL(s) : s.data ? { - data: Array.prototype.slice.call(s.data), - width: s.width, - height: s.height, - type: s.data.constructor.name - } : (console.warn("THREE.Texture: Unable to serialize Texture."), {}); -} -var Ve = class { +St.DEFAULT_IMAGE = null; +St.DEFAULT_MAPPING = Gc; +St.DEFAULT_ANISOTROPY = 1; +var je = class s1 { constructor(e = 0, t = 0, n = 0, i = 1){ - this.x = e, this.y = t, this.z = n, this.w = i; + s1.prototype.isVector4 = !0, this.x = e, this.y = t, this.z = n, this.w = i; } get width() { return this.z; @@ -669,8 +1097,8 @@ var Ve = class { copy(e) { return this.x = e.x, this.y = e.y, this.z = e.z, this.w = e.w !== void 0 ? e.w : 1, this; } - add(e, t) { - return t !== void 0 ? (console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."), this.addVectors(e, t)) : (this.x += e.x, this.y += e.y, this.z += e.z, this.w += e.w, this); + add(e) { + return this.x += e.x, this.y += e.y, this.z += e.z, this.w += e.w, this; } addScalar(e) { return this.x += e, this.y += e, this.z += e, this.w += e, this; @@ -681,8 +1109,8 @@ var Ve = class { addScaledVector(e, t) { return this.x += e.x * t, this.y += e.y * t, this.z += e.z * t, this.w += e.w * t, this; } - sub(e, t) { - return t !== void 0 ? (console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), this.subVectors(e, t)) : (this.x -= e.x, this.y -= e.y, this.z -= e.z, this.w -= e.w, this); + sub(e) { + return this.x -= e.x, this.y -= e.y, this.z -= e.z, this.w -= e.w, this; } subScalar(e) { return this.x -= e, this.y -= e, this.z -= e, this.w -= e, this; @@ -697,8 +1125,8 @@ var Ve = class { return this.x *= e, this.y *= e, this.z *= e, this.w *= e, this; } applyMatrix4(e) { - let t = this.x, n = this.y, i = this.z, r = this.w, o = e.elements; - return this.x = o[0] * t + o[4] * n + o[8] * i + o[12] * r, this.y = o[1] * t + o[5] * n + o[9] * i + o[13] * r, this.z = o[2] * t + o[6] * n + o[10] * i + o[14] * r, this.w = o[3] * t + o[7] * n + o[11] * i + o[15] * r, this; + let t = this.x, n = this.y, i = this.z, r = this.w, a = e.elements; + return this.x = a[0] * t + a[4] * n + a[8] * i + a[12] * r, this.y = a[1] * t + a[5] * n + a[9] * i + a[13] * r, this.z = a[2] * t + a[6] * n + a[10] * i + a[14] * r, this.w = a[3] * t + a[7] * n + a[11] * i + a[15] * r, this; } divideScalar(e) { return this.multiplyScalar(1 / e); @@ -709,15 +1137,15 @@ var Ve = class { return t < 1e-4 ? (this.x = 1, this.y = 0, this.z = 0) : (this.x = e.x / t, this.y = e.y / t, this.z = e.z / t), this; } setAxisAngleFromRotationMatrix(e) { - let t, n, i, r, l = e.elements, c = l[0], h = l[4], u = l[8], d = l[1], f = l[5], m = l[9], x = l[2], v = l[6], g = l[10]; - if (Math.abs(h - d) < .01 && Math.abs(u - x) < .01 && Math.abs(m - v) < .01) { - if (Math.abs(h + d) < .1 && Math.abs(u + x) < .1 && Math.abs(m + v) < .1 && Math.abs(c + f + g - 3) < .1) return this.set(1, 0, 0, 0), this; + let t, n, i, r, c = e.elements, l = c[0], h = c[4], u = c[8], d = c[1], f = c[5], m = c[9], _ = c[2], g = c[6], p = c[10]; + if (Math.abs(h - d) < .01 && Math.abs(u - _) < .01 && Math.abs(m - g) < .01) { + if (Math.abs(h + d) < .1 && Math.abs(u + _) < .1 && Math.abs(m + g) < .1 && Math.abs(l + f + p - 3) < .1) return this.set(1, 0, 0, 0), this; t = Math.PI; - let _ = (c + 1) / 2, y = (f + 1) / 2, b = (g + 1) / 2, A = (h + d) / 4, L = (u + x) / 4, I = (m + v) / 4; - return _ > y && _ > b ? _ < .01 ? (n = 0, i = .707106781, r = .707106781) : (n = Math.sqrt(_), i = A / n, r = L / n) : y > b ? y < .01 ? (n = .707106781, i = 0, r = .707106781) : (i = Math.sqrt(y), n = A / i, r = I / i) : b < .01 ? (n = .707106781, i = .707106781, r = 0) : (r = Math.sqrt(b), n = L / r, i = I / r), this.set(n, i, r, t), this; + let x = (l + 1) / 2, y = (f + 1) / 2, b = (p + 1) / 2, w = (h + d) / 4, R = (u + _) / 4, I = (m + g) / 4; + return x > y && x > b ? x < .01 ? (n = 0, i = .707106781, r = .707106781) : (n = Math.sqrt(x), i = w / n, r = R / n) : y > b ? y < .01 ? (n = .707106781, i = 0, r = .707106781) : (i = Math.sqrt(y), n = w / i, r = I / i) : b < .01 ? (n = .707106781, i = .707106781, r = 0) : (r = Math.sqrt(b), n = R / r, i = I / r), this.set(n, i, r, t), this; } - let p = Math.sqrt((v - m) * (v - m) + (u - x) * (u - x) + (d - h) * (d - h)); - return Math.abs(p) < .001 && (p = 1), this.x = (v - m) / p, this.y = (u - x) / p, this.z = (d - h) / p, this.w = Math.acos((c + f + g - 1) / 2), this; + let v = Math.sqrt((g - m) * (g - m) + (u - _) * (u - _) + (d - h) * (d - h)); + return Math.abs(v) < .001 && (v = 1), this.x = (g - m) / v, this.y = (u - _) / v, this.z = (d - h) / v, this.w = Math.acos((l + f + p - 1) / 2), this; } min(e) { return this.x = Math.min(this.x, e.x), this.y = Math.min(this.y, e.y), this.z = Math.min(this.z, e.z), this.w = Math.min(this.w, e.w), this; @@ -745,7 +1173,7 @@ var Ve = class { return this.x = Math.round(this.x), this.y = Math.round(this.y), this.z = Math.round(this.z), this.w = Math.round(this.w), this; } roundToZero() { - return this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x), this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y), this.z = this.z < 0 ? Math.ceil(this.z) : Math.floor(this.z), this.w = this.w < 0 ? Math.ceil(this.w) : Math.floor(this.w), this; + return this.x = Math.trunc(this.x), this.y = Math.trunc(this.y), this.z = Math.trunc(this.z), this.w = Math.trunc(this.w), this; } negate() { return this.x = -this.x, this.y = -this.y, this.z = -this.z, this.w = -this.w, this; @@ -783,8 +1211,8 @@ var Ve = class { toArray(e = [], t = 0) { return e[t] = this.x, e[t + 1] = this.y, e[t + 2] = this.z, e[t + 3] = this.w, e; } - fromBufferAttribute(e, t, n) { - return n !== void 0 && console.warn("THREE.Vector4: offset has been removed from .fromBufferAttribute()."), this.x = e.getX(t), this.y = e.getY(t), this.z = e.getZ(t), this.w = e.getW(t), this; + fromBufferAttribute(e, t) { + return this.x = e.getX(t), this.y = e.getY(t), this.z = e.getZ(t), this.w = e.getW(t), this; } random() { return this.x = Math.random(), this.y = Math.random(), this.z = Math.random(), this.w = Math.random(), this; @@ -792,23 +1220,23 @@ var Ve = class { *[Symbol.iterator]() { yield this.x, yield this.y, yield this.z, yield this.w; } -}; -Ve.prototype.isVector4 = !0; -var At = class extends En { - constructor(e, t, n = {}){ - super(); - this.width = e, this.height = t, this.depth = 1, this.scissor = new Ve(0, 0, e, t), this.scissorTest = !1, this.viewport = new Ve(0, 0, e, t), this.texture = new ot(void 0, n.mapping, n.wrapS, n.wrapT, n.magFilter, n.minFilter, n.format, n.type, n.anisotropy, n.encoding), this.texture.isRenderTargetTexture = !0, this.texture.image = { +}, go = class extends sn { + constructor(e = 1, t = 1, n = {}){ + super(), this.isRenderTarget = !0, this.width = e, this.height = t, this.depth = 1, this.scissor = new je(0, 0, e, t), this.scissorTest = !1, this.viewport = new je(0, 0, e, t); + let i = { width: e, height: t, depth: 1 - }, this.texture.generateMipmaps = n.generateMipmaps !== void 0 ? n.generateMipmaps : !1, this.texture.internalFormat = n.internalFormat !== void 0 ? n.internalFormat : null, this.texture.minFilter = n.minFilter !== void 0 ? n.minFilter : tt, this.depthBuffer = n.depthBuffer !== void 0 ? n.depthBuffer : !0, this.stencilBuffer = n.stencilBuffer !== void 0 ? n.stencilBuffer : !1, this.depthTexture = n.depthTexture !== void 0 ? n.depthTexture : null; - } - setTexture(e) { - e.image = { - width: this.width, - height: this.height, - depth: this.depth - }, this.texture = e; + }; + n.encoding !== void 0 && (Ms("THREE.WebGLRenderTarget: option.encoding has been replaced by option.colorSpace."), n.colorSpace = n.encoding === ri ? vt : Xt), n = Object.assign({ + generateMipmaps: !1, + internalFormat: null, + minFilter: mt, + depthBuffer: !0, + stencilBuffer: !1, + depthTexture: null, + samples: 0 + }, n), this.texture = new St(i, n.mapping, n.wrapS, n.wrapT, n.magFilter, n.minFilter, n.format, n.type, n.anisotropy, n.colorSpace), this.texture.isRenderTargetTexture = !0, this.texture.flipY = !1, this.texture.generateMipmaps = n.generateMipmaps, this.texture.internalFormat = n.internalFormat, this.depthBuffer = n.depthBuffer, this.stencilBuffer = n.stencilBuffer, this.depthTexture = n.depthTexture, this.samples = n.samples; } setSize(e, t, n = 1) { (this.width !== e || this.height !== t || this.depth !== n) && (this.width = e, this.height = t, this.depth = n, this.texture.image.width = e, this.texture.image.height = t, this.texture.image.depth = n, this.dispose()), this.viewport.set(0, 0, e, t), this.scissor.set(0, 0, e, t); @@ -817,23 +1245,51 @@ var At = class extends En { return new this.constructor().copy(this); } copy(e) { - return this.width = e.width, this.height = e.height, this.depth = e.depth, this.viewport.copy(e.viewport), this.texture = e.texture.clone(), this.texture.image = { - ...this.texture.image - }, this.depthBuffer = e.depthBuffer, this.stencilBuffer = e.stencilBuffer, this.depthTexture = e.depthTexture, this; + this.width = e.width, this.height = e.height, this.depth = e.depth, this.scissor.copy(e.scissor), this.scissorTest = e.scissorTest, this.viewport.copy(e.viewport), this.texture = e.texture.clone(), this.texture.isRenderTargetTexture = !0; + let t = Object.assign({}, e.texture.image); + return this.texture.source = new In(t), this.depthBuffer = e.depthBuffer, this.stencilBuffer = e.stencilBuffer, e.depthTexture !== null && (this.depthTexture = e.depthTexture.clone()), this.samples = e.samples, this; } dispose() { this.dispatchEvent({ type: "dispose" }); } -}; -At.prototype.isWebGLRenderTarget = !0; -var Zc = class extends At { - constructor(e, t, n){ - super(e, t); - let i = this.texture; +}, qt = class extends go { + constructor(e = 1, t = 1, n = {}){ + super(e, t, n), this.isWebGLRenderTarget = !0; + } +}, As = class extends St { + constructor(e = null, t = 1, n = 1, i = 1){ + super(null), this.isDataArrayTexture = !0, this.image = { + data: e, + width: t, + height: n, + depth: i + }, this.magFilter = pt, this.minFilter = pt, this.wrapR = It, this.generateMipmaps = !1, this.flipY = !1, this.unpackAlignment = 1; + } +}, kl = class extends qt { + constructor(e = 1, t = 1, n = 1){ + super(e, t), this.isWebGLArrayRenderTarget = !0, this.depth = n, this.texture = new As(null, e, t, n), this.texture.isRenderTargetTexture = !0; + } +}, qr = class extends St { + constructor(e = null, t = 1, n = 1, i = 1){ + super(null), this.isData3DTexture = !0, this.image = { + data: e, + width: t, + height: n, + depth: i + }, this.magFilter = pt, this.minFilter = pt, this.wrapR = It, this.generateMipmaps = !1, this.flipY = !1, this.unpackAlignment = 1; + } +}, Hl = class extends qt { + constructor(e = 1, t = 1, n = 1){ + super(e, t), this.isWebGL3DRenderTarget = !0, this.depth = n, this.texture = new qr(null, e, t, n), this.texture.isRenderTargetTexture = !0; + } +}, Gl = class extends qt { + constructor(e = 1, t = 1, n = 1, i = {}){ + super(e, t, i), this.isWebGLMultipleRenderTargets = !0; + let r = this.texture; this.texture = []; - for(let r = 0; r < n; r++)this.texture[r] = i.clone(); + for(let a = 0; a < n; a++)this.texture[a] = r.clone(), this.texture[a].isRenderTargetTexture = !0; } setSize(e, t, n = 1) { if (this.width !== e || this.height !== t || this.depth !== n) { @@ -841,59 +1297,44 @@ var Zc = class extends At { for(let i = 0, r = this.texture.length; i < r; i++)this.texture[i].image.width = e, this.texture[i].image.height = t, this.texture[i].image.depth = n; this.dispose(); } - return this.viewport.set(0, 0, e, t), this.scissor.set(0, 0, e, t), this; + this.viewport.set(0, 0, e, t), this.scissor.set(0, 0, e, t); } copy(e) { - this.dispose(), this.width = e.width, this.height = e.height, this.depth = e.depth, this.viewport.set(0, 0, this.width, this.height), this.scissor.set(0, 0, this.width, this.height), this.depthBuffer = e.depthBuffer, this.stencilBuffer = e.stencilBuffer, this.depthTexture = e.depthTexture, this.texture.length = 0; - for(let t = 0, n = e.texture.length; t < n; t++)this.texture[t] = e.texture[t].clone(); + this.dispose(), this.width = e.width, this.height = e.height, this.depth = e.depth, this.scissor.copy(e.scissor), this.scissorTest = e.scissorTest, this.viewport.copy(e.viewport), this.depthBuffer = e.depthBuffer, this.stencilBuffer = e.stencilBuffer, e.depthTexture !== null && (this.depthTexture = e.depthTexture.clone()), this.texture.length = 0; + for(let t = 0, n = e.texture.length; t < n; t++)this.texture[t] = e.texture[t].clone(), this.texture[t].isRenderTargetTexture = !0; return this; } -}; -Zc.prototype.isWebGLMultipleRenderTargets = !0; -var Xs = class extends At { - constructor(e, t, n = {}){ - super(e, t, n); - this.samples = 4, this.ignoreDepthForMultisampleCopy = n.ignoreDepth !== void 0 ? n.ignoreDepth : !0, this.useRenderToTexture = n.useRenderToTexture !== void 0 ? n.useRenderToTexture : !1, this.useRenderbuffer = this.useRenderToTexture === !1; - } - copy(e) { - return super.copy.call(this, e), this.samples = e.samples, this.useRenderToTexture = e.useRenderToTexture, this.useRenderbuffer = e.useRenderbuffer, this; - } -}; -Xs.prototype.isWebGLMultisampleRenderTarget = !0; -var gt = class { +}, Ut = class { constructor(e = 0, t = 0, n = 0, i = 1){ - this._x = e, this._y = t, this._z = n, this._w = i; - } - static slerp(e, t, n, i) { - return console.warn("THREE.Quaternion: Static .slerp() has been deprecated. Use qm.slerpQuaternions( qa, qb, t ) instead."), n.slerpQuaternions(e, t, i); + this.isQuaternion = !0, this._x = e, this._y = t, this._z = n, this._w = i; } - static slerpFlat(e, t, n, i, r, o, a) { - let l = n[i + 0], c = n[i + 1], h = n[i + 2], u = n[i + 3], d = r[o + 0], f = r[o + 1], m = r[o + 2], x = r[o + 3]; - if (a === 0) { - e[t + 0] = l, e[t + 1] = c, e[t + 2] = h, e[t + 3] = u; + static slerpFlat(e, t, n, i, r, a, o) { + let c = n[i + 0], l = n[i + 1], h = n[i + 2], u = n[i + 3], d = r[a + 0], f = r[a + 1], m = r[a + 2], _ = r[a + 3]; + if (o === 0) { + e[t + 0] = c, e[t + 1] = l, e[t + 2] = h, e[t + 3] = u; return; } - if (a === 1) { - e[t + 0] = d, e[t + 1] = f, e[t + 2] = m, e[t + 3] = x; + if (o === 1) { + e[t + 0] = d, e[t + 1] = f, e[t + 2] = m, e[t + 3] = _; return; } - if (u !== x || l !== d || c !== f || h !== m) { - let v = 1 - a, g = l * d + c * f + h * m + u * x, p = g >= 0 ? 1 : -1, _ = 1 - g * g; - if (_ > Number.EPSILON) { - let b = Math.sqrt(_), A = Math.atan2(b, g * p); - v = Math.sin(v * A) / b, a = Math.sin(a * A) / b; + if (u !== _ || c !== d || l !== f || h !== m) { + let g = 1 - o, p = c * d + l * f + h * m + u * _, v = p >= 0 ? 1 : -1, x = 1 - p * p; + if (x > Number.EPSILON) { + let b = Math.sqrt(x), w = Math.atan2(b, p * v); + g = Math.sin(g * w) / b, o = Math.sin(o * w) / b; } - let y = a * p; - if (l = l * v + d * y, c = c * v + f * y, h = h * v + m * y, u = u * v + x * y, v === 1 - a) { - let b = 1 / Math.sqrt(l * l + c * c + h * h + u * u); - l *= b, c *= b, h *= b, u *= b; + let y = o * v; + if (c = c * g + d * y, l = l * g + f * y, h = h * g + m * y, u = u * g + _ * y, g === 1 - o) { + let b = 1 / Math.sqrt(c * c + l * l + h * h + u * u); + c *= b, l *= b, h *= b, u *= b; } } - e[t] = l, e[t + 1] = c, e[t + 2] = h, e[t + 3] = u; + e[t] = c, e[t + 1] = l, e[t + 2] = h, e[t + 3] = u; } - static multiplyQuaternionsFlat(e, t, n, i, r, o) { - let a = n[i], l = n[i + 1], c = n[i + 2], h = n[i + 3], u = r[o], d = r[o + 1], f = r[o + 2], m = r[o + 3]; - return e[t] = a * m + h * u + l * f - c * d, e[t + 1] = l * m + h * d + c * u - a * f, e[t + 2] = c * m + h * f + a * d - l * u, e[t + 3] = h * m - a * u - l * d - c * f, e; + static multiplyQuaternionsFlat(e, t, n, i, r, a) { + let o = n[i], c = n[i + 1], l = n[i + 2], h = n[i + 3], u = r[a], d = r[a + 1], f = r[a + 2], m = r[a + 3]; + return e[t] = o * m + h * u + c * f - l * d, e[t + 1] = c * m + h * d + l * u - o * f, e[t + 2] = l * m + h * f + o * d - c * u, e[t + 3] = h * m - o * u - c * d - l * f, e; } get x() { return this._x; @@ -929,29 +1370,28 @@ var gt = class { return this._x = e.x, this._y = e.y, this._z = e.z, this._w = e.w, this._onChangeCallback(), this; } setFromEuler(e, t) { - if (!(e && e.isEuler)) throw new Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order."); - let n = e._x, i = e._y, r = e._z, o = e._order, a = Math.cos, l = Math.sin, c = a(n / 2), h = a(i / 2), u = a(r / 2), d = l(n / 2), f = l(i / 2), m = l(r / 2); - switch(o){ + let n = e._x, i = e._y, r = e._z, a = e._order, o = Math.cos, c = Math.sin, l = o(n / 2), h = o(i / 2), u = o(r / 2), d = c(n / 2), f = c(i / 2), m = c(r / 2); + switch(a){ case "XYZ": - this._x = d * h * u + c * f * m, this._y = c * f * u - d * h * m, this._z = c * h * m + d * f * u, this._w = c * h * u - d * f * m; + this._x = d * h * u + l * f * m, this._y = l * f * u - d * h * m, this._z = l * h * m + d * f * u, this._w = l * h * u - d * f * m; break; case "YXZ": - this._x = d * h * u + c * f * m, this._y = c * f * u - d * h * m, this._z = c * h * m - d * f * u, this._w = c * h * u + d * f * m; + this._x = d * h * u + l * f * m, this._y = l * f * u - d * h * m, this._z = l * h * m - d * f * u, this._w = l * h * u + d * f * m; break; case "ZXY": - this._x = d * h * u - c * f * m, this._y = c * f * u + d * h * m, this._z = c * h * m + d * f * u, this._w = c * h * u - d * f * m; + this._x = d * h * u - l * f * m, this._y = l * f * u + d * h * m, this._z = l * h * m + d * f * u, this._w = l * h * u - d * f * m; break; case "ZYX": - this._x = d * h * u - c * f * m, this._y = c * f * u + d * h * m, this._z = c * h * m - d * f * u, this._w = c * h * u + d * f * m; + this._x = d * h * u - l * f * m, this._y = l * f * u + d * h * m, this._z = l * h * m - d * f * u, this._w = l * h * u + d * f * m; break; case "YZX": - this._x = d * h * u + c * f * m, this._y = c * f * u + d * h * m, this._z = c * h * m - d * f * u, this._w = c * h * u - d * f * m; + this._x = d * h * u + l * f * m, this._y = l * f * u + d * h * m, this._z = l * h * m - d * f * u, this._w = l * h * u - d * f * m; break; case "XZY": - this._x = d * h * u - c * f * m, this._y = c * f * u - d * h * m, this._z = c * h * m + d * f * u, this._w = c * h * u + d * f * m; + this._x = d * h * u - l * f * m, this._y = l * f * u - d * h * m, this._z = l * h * m + d * f * u, this._w = l * h * u + d * f * m; break; default: - console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: " + o); + console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: " + a); } return t !== !1 && this._onChangeCallback(), this; } @@ -960,19 +1400,19 @@ var gt = class { return this._x = e.x * i, this._y = e.y * i, this._z = e.z * i, this._w = Math.cos(n), this._onChangeCallback(), this; } setFromRotationMatrix(e) { - let t = e.elements, n = t[0], i = t[4], r = t[8], o = t[1], a = t[5], l = t[9], c = t[2], h = t[6], u = t[10], d = n + a + u; + let t = e.elements, n = t[0], i = t[4], r = t[8], a = t[1], o = t[5], c = t[9], l = t[2], h = t[6], u = t[10], d = n + o + u; if (d > 0) { let f = .5 / Math.sqrt(d + 1); - this._w = .25 / f, this._x = (h - l) * f, this._y = (r - c) * f, this._z = (o - i) * f; - } else if (n > a && n > u) { - let f = 2 * Math.sqrt(1 + n - a - u); - this._w = (h - l) / f, this._x = .25 * f, this._y = (i + o) / f, this._z = (r + c) / f; - } else if (a > u) { - let f = 2 * Math.sqrt(1 + a - n - u); - this._w = (r - c) / f, this._x = (i + o) / f, this._y = .25 * f, this._z = (l + h) / f; + this._w = .25 / f, this._x = (h - c) * f, this._y = (r - l) * f, this._z = (a - i) * f; + } else if (n > o && n > u) { + let f = 2 * Math.sqrt(1 + n - o - u); + this._w = (h - c) / f, this._x = .25 * f, this._y = (i + a) / f, this._z = (r + l) / f; + } else if (o > u) { + let f = 2 * Math.sqrt(1 + o - n - u); + this._w = (r - l) / f, this._x = (i + a) / f, this._y = .25 * f, this._z = (c + h) / f; } else { - let f = 2 * Math.sqrt(1 + u - n - a); - this._w = (o - i) / f, this._x = (r + c) / f, this._y = (l + h) / f, this._z = .25 * f; + let f = 2 * Math.sqrt(1 + u - n - o); + this._w = (a - i) / f, this._x = (r + l) / f, this._y = (c + h) / f, this._z = .25 * f; } return this._onChangeCallback(), this; } @@ -981,7 +1421,7 @@ var gt = class { return n < Number.EPSILON ? (n = 0, Math.abs(e.x) > Math.abs(e.z) ? (this._x = -e.y, this._y = e.x, this._z = 0, this._w = n) : (this._x = 0, this._y = -e.z, this._z = e.y, this._w = n)) : (this._x = e.y * t.z - e.z * t.y, this._y = e.z * t.x - e.x * t.z, this._z = e.x * t.y - e.y * t.x, this._w = n), this.normalize(); } angleTo(e) { - return 2 * Math.acos(Math.abs(mt(this.dot(e), -1, 1))); + return 2 * Math.acos(Math.abs(ct(this.dot(e), -1, 1))); } rotateTowards(e, t) { let n = this.angleTo(e); @@ -1011,31 +1451,31 @@ var gt = class { let e = this.length(); return e === 0 ? (this._x = 0, this._y = 0, this._z = 0, this._w = 1) : (e = 1 / e, this._x = this._x * e, this._y = this._y * e, this._z = this._z * e, this._w = this._w * e), this._onChangeCallback(), this; } - multiply(e, t) { - return t !== void 0 ? (console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."), this.multiplyQuaternions(e, t)) : this.multiplyQuaternions(this, e); + multiply(e) { + return this.multiplyQuaternions(this, e); } premultiply(e) { return this.multiplyQuaternions(e, this); } multiplyQuaternions(e, t) { - let n = e._x, i = e._y, r = e._z, o = e._w, a = t._x, l = t._y, c = t._z, h = t._w; - return this._x = n * h + o * a + i * c - r * l, this._y = i * h + o * l + r * a - n * c, this._z = r * h + o * c + n * l - i * a, this._w = o * h - n * a - i * l - r * c, this._onChangeCallback(), this; + let n = e._x, i = e._y, r = e._z, a = e._w, o = t._x, c = t._y, l = t._z, h = t._w; + return this._x = n * h + a * o + i * l - r * c, this._y = i * h + a * c + r * o - n * l, this._z = r * h + a * l + n * c - i * o, this._w = a * h - n * o - i * c - r * l, this._onChangeCallback(), this; } slerp(e, t) { if (t === 0) return this; if (t === 1) return this.copy(e); - let n = this._x, i = this._y, r = this._z, o = this._w, a = o * e._w + n * e._x + i * e._y + r * e._z; - if (a < 0 ? (this._w = -e._w, this._x = -e._x, this._y = -e._y, this._z = -e._z, a = -a) : this.copy(e), a >= 1) return this._w = o, this._x = n, this._y = i, this._z = r, this; - let l = 1 - a * a; - if (l <= Number.EPSILON) { + let n = this._x, i = this._y, r = this._z, a = this._w, o = a * e._w + n * e._x + i * e._y + r * e._z; + if (o < 0 ? (this._w = -e._w, this._x = -e._x, this._y = -e._y, this._z = -e._z, o = -o) : this.copy(e), o >= 1) return this._w = a, this._x = n, this._y = i, this._z = r, this; + let c = 1 - o * o; + if (c <= Number.EPSILON) { let f = 1 - t; - return this._w = f * o + t * this._w, this._x = f * n + t * this._x, this._y = f * i + t * this._y, this._z = f * r + t * this._z, this.normalize(), this._onChangeCallback(), this; + return this._w = f * a + t * this._w, this._x = f * n + t * this._x, this._y = f * i + t * this._y, this._z = f * r + t * this._z, this.normalize(), this._onChangeCallback(), this; } - let c = Math.sqrt(l), h = Math.atan2(c, a), u = Math.sin((1 - t) * h) / c, d = Math.sin(t * h) / c; - return this._w = o * u + this._w * d, this._x = n * u + this._x * d, this._y = i * u + this._y * d, this._z = r * u + this._z * d, this._onChangeCallback(), this; + let l = Math.sqrt(c), h = Math.atan2(l, o), u = Math.sin((1 - t) * h) / l, d = Math.sin(t * h) / l; + return this._w = a * u + this._w * d, this._x = n * u + this._x * d, this._y = i * u + this._y * d, this._z = r * u + this._z * d, this._onChangeCallback(), this; } slerpQuaternions(e, t, n) { - this.copy(e).slerp(t, n); + return this.copy(e).slerp(t, n); } random() { let e = Math.random(), t = Math.sqrt(1 - e), n = Math.sqrt(e), i = 2 * Math.PI * Math.random(), r = 2 * Math.PI * Math.random(); @@ -1053,15 +1493,19 @@ var gt = class { fromBufferAttribute(e, t) { return this._x = e.getX(t), this._y = e.getY(t), this._z = e.getZ(t), this._w = e.getW(t), this; } + toJSON() { + return this.toArray(); + } _onChange(e) { return this._onChangeCallback = e, this; } _onChangeCallback() {} -}; -gt.prototype.isQuaternion = !0; -var M = class { + *[Symbol.iterator]() { + yield this._x, yield this._y, yield this._z, yield this._w; + } +}, A = class s1 { constructor(e = 0, t = 0, n = 0){ - this.x = e, this.y = t, this.z = n; + s1.prototype.isVector3 = !0, this.x = e, this.y = t, this.z = n; } set(e, t, n) { return n === void 0 && (n = this.z), this.x = e, this.y = t, this.z = n, this; @@ -1112,8 +1556,8 @@ var M = class { copy(e) { return this.x = e.x, this.y = e.y, this.z = e.z, this; } - add(e, t) { - return t !== void 0 ? (console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."), this.addVectors(e, t)) : (this.x += e.x, this.y += e.y, this.z += e.z, this); + add(e) { + return this.x += e.x, this.y += e.y, this.z += e.z, this; } addScalar(e) { return this.x += e, this.y += e, this.z += e, this; @@ -1124,8 +1568,8 @@ var M = class { addScaledVector(e, t) { return this.x += e.x * t, this.y += e.y * t, this.z += e.z * t, this; } - sub(e, t) { - return t !== void 0 ? (console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), this.subVectors(e, t)) : (this.x -= e.x, this.y -= e.y, this.z -= e.z, this); + sub(e) { + return this.x -= e.x, this.y -= e.y, this.z -= e.z, this; } subScalar(e) { return this.x -= e, this.y -= e, this.z -= e, this; @@ -1133,8 +1577,8 @@ var M = class { subVectors(e, t) { return this.x = e.x - t.x, this.y = e.y - t.y, this.z = e.z - t.z, this; } - multiply(e, t) { - return t !== void 0 ? (console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."), this.multiplyVectors(e, t)) : (this.x *= e.x, this.y *= e.y, this.z *= e.z, this); + multiply(e) { + return this.x *= e.x, this.y *= e.y, this.z *= e.z, this; } multiplyScalar(e) { return this.x *= e, this.y *= e, this.z *= e, this; @@ -1143,10 +1587,10 @@ var M = class { return this.x = e.x * t.x, this.y = e.y * t.y, this.z = e.z * t.z, this; } applyEuler(e) { - return e && e.isEuler || console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order."), this.applyQuaternion(yl.setFromEuler(e)); + return this.applyQuaternion(Wl.setFromEuler(e)); } applyAxisAngle(e, t) { - return this.applyQuaternion(yl.setFromAxisAngle(e, t)); + return this.applyQuaternion(Wl.setFromAxisAngle(e, t)); } applyMatrix3(e) { let t = this.x, n = this.y, i = this.z, r = e.elements; @@ -1156,12 +1600,12 @@ var M = class { return this.applyMatrix3(e).normalize(); } applyMatrix4(e) { - let t = this.x, n = this.y, i = this.z, r = e.elements, o = 1 / (r[3] * t + r[7] * n + r[11] * i + r[15]); - return this.x = (r[0] * t + r[4] * n + r[8] * i + r[12]) * o, this.y = (r[1] * t + r[5] * n + r[9] * i + r[13]) * o, this.z = (r[2] * t + r[6] * n + r[10] * i + r[14]) * o, this; + let t = this.x, n = this.y, i = this.z, r = e.elements, a = 1 / (r[3] * t + r[7] * n + r[11] * i + r[15]); + return this.x = (r[0] * t + r[4] * n + r[8] * i + r[12]) * a, this.y = (r[1] * t + r[5] * n + r[9] * i + r[13]) * a, this.z = (r[2] * t + r[6] * n + r[10] * i + r[14]) * a, this; } applyQuaternion(e) { - let t = this.x, n = this.y, i = this.z, r = e.x, o = e.y, a = e.z, l = e.w, c = l * t + o * i - a * n, h = l * n + a * t - r * i, u = l * i + r * n - o * t, d = -r * t - o * n - a * i; - return this.x = c * l + d * -r + h * -a - u * -o, this.y = h * l + d * -o + u * -r - c * -a, this.z = u * l + d * -a + c * -o - h * -r, this; + let t = this.x, n = this.y, i = this.z, r = e.x, a = e.y, o = e.z, c = e.w, l = c * t + a * i - o * n, h = c * n + o * t - r * i, u = c * i + r * n - a * t, d = -r * t - a * n - o * i; + return this.x = l * c + d * -r + h * -o - u * -a, this.y = h * c + d * -a + u * -r - l * -o, this.z = u * c + d * -o + l * -a - h * -r, this; } project(e) { return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix); @@ -1205,7 +1649,7 @@ var M = class { return this.x = Math.round(this.x), this.y = Math.round(this.y), this.z = Math.round(this.z), this; } roundToZero() { - return this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x), this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y), this.z = this.z < 0 ? Math.ceil(this.z) : Math.floor(this.z), this; + return this.x = Math.trunc(this.x), this.y = Math.trunc(this.y), this.z = Math.trunc(this.z), this; } negate() { return this.x = -this.x, this.y = -this.y, this.z = -this.z, this; @@ -1234,12 +1678,12 @@ var M = class { lerpVectors(e, t, n) { return this.x = e.x + (t.x - e.x) * n, this.y = e.y + (t.y - e.y) * n, this.z = e.z + (t.z - e.z) * n, this; } - cross(e, t) { - return t !== void 0 ? (console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."), this.crossVectors(e, t)) : this.crossVectors(this, e); + cross(e) { + return this.crossVectors(this, e); } crossVectors(e, t) { - let n = e.x, i = e.y, r = e.z, o = t.x, a = t.y, l = t.z; - return this.x = i * l - r * a, this.y = r * o - n * l, this.z = n * a - i * o, this; + let n = e.x, i = e.y, r = e.z, a = t.x, o = t.y, c = t.z; + return this.x = i * c - r * o, this.y = r * a - n * c, this.z = n * o - i * a, this; } projectOnVector(e) { let t = e.lengthSq(); @@ -1248,16 +1692,16 @@ var M = class { return this.copy(e).multiplyScalar(n); } projectOnPlane(e) { - return Mo.copy(this).projectOnVector(e), this.sub(Mo); + return Oa.copy(this).projectOnVector(e), this.sub(Oa); } reflect(e) { - return this.sub(Mo.copy(e).multiplyScalar(2 * this.dot(e))); + return this.sub(Oa.copy(e).multiplyScalar(2 * this.dot(e))); } angleTo(e) { let t = Math.sqrt(this.lengthSq() * e.lengthSq()); if (t === 0) return Math.PI / 2; let n = this.dot(e) / t; - return Math.acos(mt(n, -1, 1)); + return Math.acos(ct(n, -1, 1)); } distanceTo(e) { return Math.sqrt(this.distanceToSquared(e)); @@ -1296,6 +1740,12 @@ var M = class { setFromMatrix3Column(e, t) { return this.fromArray(e.elements, t * 3); } + setFromEuler(e) { + return this.x = e._x, this.y = e._y, this.z = e._z, this; + } + setFromColor(e) { + return this.x = e.r, this.y = e.g, this.z = e.b, this; + } equals(e) { return e.x === this.x && e.y === this.y && e.z === this.z; } @@ -1305,8 +1755,8 @@ var M = class { toArray(e = [], t = 0) { return e[t] = this.x, e[t + 1] = this.y, e[t + 2] = this.z, e; } - fromBufferAttribute(e, t, n) { - return n !== void 0 && console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute()."), this.x = e.getX(t), this.y = e.getY(t), this.z = e.getZ(t), this; + fromBufferAttribute(e, t) { + return this.x = e.getX(t), this.y = e.getY(t), this.z = e.getZ(t), this; } random() { return this.x = Math.random(), this.y = Math.random(), this.z = Math.random(), this; @@ -1318,30 +1768,22 @@ var M = class { *[Symbol.iterator]() { yield this.x, yield this.y, yield this.z; } -}; -M.prototype.isVector3 = !0; -var Mo = new M, yl = new gt, Lt = class { - constructor(e = new M(1 / 0, 1 / 0, 1 / 0), t = new M(-1 / 0, -1 / 0, -1 / 0)){ - this.min = e, this.max = t; +}, Oa = new A, Wl = new Ut, Qt = class { + constructor(e = new A(1 / 0, 1 / 0, 1 / 0), t = new A(-1 / 0, -1 / 0, -1 / 0)){ + this.isBox3 = !0, this.min = e, this.max = t; } set(e, t) { return this.min.copy(e), this.max.copy(t), this; } setFromArray(e) { - let t = 1 / 0, n = 1 / 0, i = 1 / 0, r = -1 / 0, o = -1 / 0, a = -1 / 0; - for(let l = 0, c = e.length; l < c; l += 3){ - let h = e[l], u = e[l + 1], d = e[l + 2]; - h < t && (t = h), u < n && (n = u), d < i && (i = d), h > r && (r = h), u > o && (o = u), d > a && (a = d); - } - return this.min.set(t, n, i), this.max.set(r, o, a), this; + this.makeEmpty(); + for(let t = 0, n = e.length; t < n; t += 3)this.expandByPoint(cn.fromArray(e, t)); + return this; } setFromBufferAttribute(e) { - let t = 1 / 0, n = 1 / 0, i = 1 / 0, r = -1 / 0, o = -1 / 0, a = -1 / 0; - for(let l = 0, c = e.count; l < c; l++){ - let h = e.getX(l), u = e.getY(l), d = e.getZ(l); - h < t && (t = h), u < n && (n = u), d < i && (i = d), h > r && (r = h), u > o && (o = u), d > a && (a = d); - } - return this.min.set(t, n, i), this.max.set(r, o, a), this; + this.makeEmpty(); + for(let t = 0, n = e.count; t < n; t++)this.expandByPoint(cn.fromBufferAttribute(e, t)); + return this; } setFromPoints(e) { this.makeEmpty(); @@ -1349,11 +1791,11 @@ var Mo = new M, yl = new gt, Lt = class { return this; } setFromCenterAndSize(e, t) { - let n = Ji.copy(t).multiplyScalar(.5); + let n = cn.copy(t).multiplyScalar(.5); return this.min.copy(e).sub(n), this.max.copy(e).add(n), this; } - setFromObject(e) { - return this.makeEmpty(), this.expandByObject(e); + setFromObject(e, t = !1) { + return this.makeEmpty(), this.expandByObject(e, t); } clone() { return new this.constructor().copy(this); @@ -1382,12 +1824,17 @@ var Mo = new M, yl = new gt, Lt = class { expandByScalar(e) { return this.min.addScalar(-e), this.max.addScalar(e), this; } - expandByObject(e) { - e.updateWorldMatrix(!1, !1); - let t = e.geometry; - t !== void 0 && (t.boundingBox === null && t.computeBoundingBox(), bo.copy(t.boundingBox), bo.applyMatrix4(e.matrixWorld), this.union(bo)); + expandByObject(e, t = !1) { + if (e.updateWorldMatrix(!1, !1), e.boundingBox !== void 0) e.boundingBox === null && e.computeBoundingBox(), _i.copy(e.boundingBox), _i.applyMatrix4(e.matrixWorld), this.union(_i); + else { + let i = e.geometry; + if (i !== void 0) if (t && i.attributes !== void 0 && i.attributes.position !== void 0) { + let r = i.attributes.position; + for(let a = 0, o = r.count; a < o; a++)cn.fromBufferAttribute(r, a).applyMatrix4(e.matrixWorld), this.expandByPoint(cn); + } else i.boundingBox === null && i.computeBoundingBox(), _i.copy(i.boundingBox), _i.applyMatrix4(e.matrixWorld), this.union(_i); + } let n = e.children; - for(let i = 0, r = n.length; i < r; i++)this.expandByObject(n[i]); + for(let i = 0, r = n.length; i < r; i++)this.expandByObject(n[i], t); return this; } containsPoint(e) { @@ -1403,7 +1850,7 @@ var Mo = new M, yl = new gt, Lt = class { return !(e.max.x < this.min.x || e.min.x > this.max.x || e.max.y < this.min.y || e.min.y > this.max.y || e.max.z < this.min.z || e.min.z > this.max.z); } intersectsSphere(e) { - return this.clampPoint(e.center, Ji), Ji.distanceToSquared(e.center) <= e.radius * e.radius; + return this.clampPoint(e.center, cn), cn.distanceToSquared(e.center) <= e.radius * e.radius; } intersectsPlane(e) { let t, n; @@ -1411,37 +1858,37 @@ var Mo = new M, yl = new gt, Lt = class { } intersectsTriangle(e) { if (this.isEmpty()) return !1; - this.getCenter(Yi), Wr.subVectors(this.max, Yi), ni.subVectors(e.a, Yi), ii.subVectors(e.b, Yi), ri.subVectors(e.c, Yi), un.subVectors(ii, ni), dn.subVectors(ri, ii), Pn.subVectors(ni, ri); + this.getCenter(cs), Ws.subVectors(this.max, cs), xi.subVectors(e.a, cs), vi.subVectors(e.b, cs), yi.subVectors(e.c, cs), Tn.subVectors(vi, xi), wn.subVectors(yi, vi), Wn.subVectors(xi, yi); let t = [ 0, - -un.z, - un.y, + -Tn.z, + Tn.y, 0, - -dn.z, - dn.y, + -wn.z, + wn.y, 0, - -Pn.z, - Pn.y, - un.z, + -Wn.z, + Wn.y, + Tn.z, 0, - -un.x, - dn.z, + -Tn.x, + wn.z, 0, - -dn.x, - Pn.z, + -wn.x, + Wn.z, 0, - -Pn.x, - -un.y, - un.x, + -Wn.x, + -Tn.y, + Tn.x, 0, - -dn.y, - dn.x, + -wn.y, + wn.x, 0, - -Pn.y, - Pn.x, + -Wn.y, + Wn.x, 0 ]; - return !wo(t, ni, ii, ri, Wr) || (t = [ + return !Fa(t, xi, vi, yi, Ws) || (t = [ 1, 0, 0, @@ -1451,20 +1898,20 @@ var Mo = new M, yl = new gt, Lt = class { 0, 0, 1 - ], !wo(t, ni, ii, ri, Wr)) ? !1 : (qr.crossVectors(un, dn), t = [ - qr.x, - qr.y, - qr.z - ], wo(t, ni, ii, ri, Wr)); + ], !Fa(t, xi, vi, yi, Ws)) ? !1 : (Xs.crossVectors(Tn, wn), t = [ + Xs.x, + Xs.y, + Xs.z + ], Fa(t, xi, vi, yi, Ws)); } clampPoint(e, t) { return t.copy(e).clamp(this.min, this.max); } distanceToPoint(e) { - return Ji.copy(e).clamp(this.min, this.max).sub(e).length(); + return this.clampPoint(e, cn).distanceTo(e); } getBoundingSphere(e) { - return this.getCenter(e.center), e.radius = this.getSize(Ji).length() * .5, e; + return this.isEmpty() ? e.makeEmpty() : (this.getCenter(e.center), e.radius = this.getSize(cn).length() * .5), e; } intersect(e) { return this.min.max(e.min), this.max.min(e.max), this.isEmpty() && this.makeEmpty(), this; @@ -1473,7 +1920,7 @@ var Mo = new M, yl = new gt, Lt = class { return this.min.min(e.min), this.max.max(e.max), this; } applyMatrix4(e) { - return this.isEmpty() ? this : ($t[0].set(this.min.x, this.min.y, this.min.z).applyMatrix4(e), $t[1].set(this.min.x, this.min.y, this.max.z).applyMatrix4(e), $t[2].set(this.min.x, this.max.y, this.min.z).applyMatrix4(e), $t[3].set(this.min.x, this.max.y, this.max.z).applyMatrix4(e), $t[4].set(this.max.x, this.min.y, this.min.z).applyMatrix4(e), $t[5].set(this.max.x, this.min.y, this.max.z).applyMatrix4(e), $t[6].set(this.max.x, this.max.y, this.min.z).applyMatrix4(e), $t[7].set(this.max.x, this.max.y, this.max.z).applyMatrix4(e), this.setFromPoints($t), this); + return this.isEmpty() ? this : (on[0].set(this.min.x, this.min.y, this.min.z).applyMatrix4(e), on[1].set(this.min.x, this.min.y, this.max.z).applyMatrix4(e), on[2].set(this.min.x, this.max.y, this.min.z).applyMatrix4(e), on[3].set(this.min.x, this.max.y, this.max.z).applyMatrix4(e), on[4].set(this.max.x, this.min.y, this.min.z).applyMatrix4(e), on[5].set(this.max.x, this.min.y, this.max.z).applyMatrix4(e), on[6].set(this.max.x, this.max.y, this.min.z).applyMatrix4(e), on[7].set(this.max.x, this.max.y, this.max.z).applyMatrix4(e), this.setFromPoints(on), this); } translate(e) { return this.min.add(e), this.max.add(e), this; @@ -1481,28 +1928,26 @@ var Mo = new M, yl = new gt, Lt = class { equals(e) { return e.min.equals(this.min) && e.max.equals(this.max); } -}; -Lt.prototype.isBox3 = !0; -var $t = [ - new M, - new M, - new M, - new M, - new M, - new M, - new M, - new M -], Ji = new M, bo = new Lt, ni = new M, ii = new M, ri = new M, un = new M, dn = new M, Pn = new M, Yi = new M, Wr = new M, qr = new M, In = new M; -function wo(s, e, t, n, i) { - for(let r = 0, o = s.length - 3; r <= o; r += 3){ - In.fromArray(s, r); - let a = i.x * Math.abs(In.x) + i.y * Math.abs(In.y) + i.z * Math.abs(In.z), l = e.dot(In), c = t.dot(In), h = n.dot(In); - if (Math.max(-Math.max(l, c, h), Math.min(l, c, h)) > a) return !1; +}, on = [ + new A, + new A, + new A, + new A, + new A, + new A, + new A, + new A +], cn = new A, _i = new Qt, xi = new A, vi = new A, yi = new A, Tn = new A, wn = new A, Wn = new A, cs = new A, Ws = new A, Xs = new A, Xn = new A; +function Fa(s1, e, t, n, i) { + for(let r = 0, a = s1.length - 3; r <= a; r += 3){ + Xn.fromArray(s1, r); + let o = i.x * Math.abs(Xn.x) + i.y * Math.abs(Xn.y) + i.z * Math.abs(Xn.z), c = e.dot(Xn), l = t.dot(Xn), h = n.dot(Xn); + if (Math.max(-Math.max(c, l, h), Math.min(c, l, h)) > o) return !1; } return !0; } -var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { - constructor(e = new M, t = -1){ +var rp = new Qt, ls = new A, Ba = new A, Yt = class { + constructor(e = new A, t = -1){ this.center = e, this.radius = t; } set(e, t) { @@ -1510,9 +1955,9 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { } setFromPoints(e, t) { let n = this.center; - t !== void 0 ? n.copy(t) : ef.setFromPoints(e).getCenter(n); + t !== void 0 ? n.copy(t) : rp.setFromPoints(e).getCenter(n); let i = 0; - for(let r = 0, o = e.length; r < o; r++)i = Math.max(i, n.distanceToSquared(e[r])); + for(let r = 0, a = e.length; r < a; r++)i = Math.max(i, n.distanceToSquared(e[r])); return this.radius = Math.sqrt(i), this; } copy(e) { @@ -1554,16 +1999,17 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { return this.center.add(e), this; } expandByPoint(e) { - So.subVectors(e, this.center); - let t = So.lengthSq(); + if (this.isEmpty()) return this.center.copy(e), this.radius = 0, this; + ls.subVectors(e, this.center); + let t = ls.lengthSq(); if (t > this.radius * this.radius) { let n = Math.sqrt(t), i = (n - this.radius) * .5; - this.center.add(So.multiplyScalar(i / n)), this.radius += i; + this.center.addScaledVector(ls, i / n), this.radius += i; } return this; } union(e) { - return this.center.equals(e.center) === !0 ? Xr.set(0, 0, 1).multiplyScalar(e.radius) : Xr.subVectors(e.center, this.center).normalize().multiplyScalar(e.radius), this.expandByPoint(vl.copy(e.center).add(Xr)), this.expandByPoint(vl.copy(e.center).sub(Xr)), this; + return e.isEmpty() ? this : this.isEmpty() ? (this.copy(e), this) : (this.center.equals(e.center) === !0 ? this.radius = Math.max(this.radius, e.radius) : (Ba.subVectors(e.center, this.center).setLength(e.radius), this.expandByPoint(ls.copy(e.center).add(Ba)), this.expandByPoint(ls.copy(e.center).sub(Ba))), this); } equals(e) { return e.center.equals(this.center) && e.radius === this.radius; @@ -1571,8 +2017,8 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { clone() { return new this.constructor().copy(this); } -}, jt = new M, To = new M, Jr = new M, fn = new M, Eo = new M, Yr = new M, Ao = new M, Cn = class { - constructor(e = new M, t = new M(0, 0, -1)){ +}, ln = new A, za = new A, qs = new A, An = new A, Va = new A, Ys = new A, ka = new A, hi = class { + constructor(e = new A, t = new A(0, 0, -1)){ this.origin = e, this.direction = t; } set(e, t) { @@ -1582,44 +2028,44 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { return this.origin.copy(e.origin), this.direction.copy(e.direction), this; } at(e, t) { - return t.copy(this.direction).multiplyScalar(e).add(this.origin); + return t.copy(this.origin).addScaledVector(this.direction, e); } lookAt(e) { return this.direction.copy(e).sub(this.origin).normalize(), this; } recast(e) { - return this.origin.copy(this.at(e, jt)), this; + return this.origin.copy(this.at(e, ln)), this; } closestPointToPoint(e, t) { t.subVectors(e, this.origin); let n = t.dot(this.direction); - return n < 0 ? t.copy(this.origin) : t.copy(this.direction).multiplyScalar(n).add(this.origin); + return n < 0 ? t.copy(this.origin) : t.copy(this.origin).addScaledVector(this.direction, n); } distanceToPoint(e) { return Math.sqrt(this.distanceSqToPoint(e)); } distanceSqToPoint(e) { - let t = jt.subVectors(e, this.origin).dot(this.direction); - return t < 0 ? this.origin.distanceToSquared(e) : (jt.copy(this.direction).multiplyScalar(t).add(this.origin), jt.distanceToSquared(e)); + let t = ln.subVectors(e, this.origin).dot(this.direction); + return t < 0 ? this.origin.distanceToSquared(e) : (ln.copy(this.origin).addScaledVector(this.direction, t), ln.distanceToSquared(e)); } distanceSqToSegment(e, t, n, i) { - To.copy(e).add(t).multiplyScalar(.5), Jr.copy(t).sub(e).normalize(), fn.copy(this.origin).sub(To); - let r = e.distanceTo(t) * .5, o = -this.direction.dot(Jr), a = fn.dot(this.direction), l = -fn.dot(Jr), c = fn.lengthSq(), h = Math.abs(1 - o * o), u, d, f, m; - if (h > 0) if (u = o * l - a, d = o * a - l, m = r * h, u >= 0) if (d >= -m) if (d <= m) { - let x = 1 / h; - u *= x, d *= x, f = u * (u + o * d + 2 * a) + d * (o * u + d + 2 * l) + c; - } else d = r, u = Math.max(0, -(o * d + a)), f = -u * u + d * (d + 2 * l) + c; - else d = -r, u = Math.max(0, -(o * d + a)), f = -u * u + d * (d + 2 * l) + c; - else d <= -m ? (u = Math.max(0, -(-o * r + a)), d = u > 0 ? -r : Math.min(Math.max(-r, -l), r), f = -u * u + d * (d + 2 * l) + c) : d <= m ? (u = 0, d = Math.min(Math.max(-r, -l), r), f = d * (d + 2 * l) + c) : (u = Math.max(0, -(o * r + a)), d = u > 0 ? r : Math.min(Math.max(-r, -l), r), f = -u * u + d * (d + 2 * l) + c); - else d = o > 0 ? -r : r, u = Math.max(0, -(o * d + a)), f = -u * u + d * (d + 2 * l) + c; - return n && n.copy(this.direction).multiplyScalar(u).add(this.origin), i && i.copy(Jr).multiplyScalar(d).add(To), f; + za.copy(e).add(t).multiplyScalar(.5), qs.copy(t).sub(e).normalize(), An.copy(this.origin).sub(za); + let r = e.distanceTo(t) * .5, a = -this.direction.dot(qs), o = An.dot(this.direction), c = -An.dot(qs), l = An.lengthSq(), h = Math.abs(1 - a * a), u, d, f, m; + if (h > 0) if (u = a * c - o, d = a * o - c, m = r * h, u >= 0) if (d >= -m) if (d <= m) { + let _ = 1 / h; + u *= _, d *= _, f = u * (u + a * d + 2 * o) + d * (a * u + d + 2 * c) + l; + } else d = r, u = Math.max(0, -(a * d + o)), f = -u * u + d * (d + 2 * c) + l; + else d = -r, u = Math.max(0, -(a * d + o)), f = -u * u + d * (d + 2 * c) + l; + else d <= -m ? (u = Math.max(0, -(-a * r + o)), d = u > 0 ? -r : Math.min(Math.max(-r, -c), r), f = -u * u + d * (d + 2 * c) + l) : d <= m ? (u = 0, d = Math.min(Math.max(-r, -c), r), f = d * (d + 2 * c) + l) : (u = Math.max(0, -(a * r + o)), d = u > 0 ? r : Math.min(Math.max(-r, -c), r), f = -u * u + d * (d + 2 * c) + l); + else d = a > 0 ? -r : r, u = Math.max(0, -(a * d + o)), f = -u * u + d * (d + 2 * c) + l; + return n && n.copy(this.origin).addScaledVector(this.direction, u), i && i.copy(za).addScaledVector(qs, d), f; } intersectSphere(e, t) { - jt.subVectors(e.center, this.origin); - let n = jt.dot(this.direction), i = jt.dot(jt) - n * n, r = e.radius * e.radius; + ln.subVectors(e.center, this.origin); + let n = ln.dot(this.direction), i = ln.dot(ln) - n * n, r = e.radius * e.radius; if (i > r) return null; - let o = Math.sqrt(r - i), a = n - o, l = n + o; - return a < 0 && l < 0 ? null : a < 0 ? this.at(l, t) : this.at(a, t); + let a = Math.sqrt(r - i), o = n - a, c = n + a; + return c < 0 ? null : o < 0 ? this.at(c, t) : this.at(o, t); } intersectsSphere(e) { return this.distanceSqToPoint(e.center) <= e.radius * e.radius; @@ -1639,27 +2085,27 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { return t === 0 || e.normal.dot(this.direction) * t < 0; } intersectBox(e, t) { - let n, i, r, o, a, l, c = 1 / this.direction.x, h = 1 / this.direction.y, u = 1 / this.direction.z, d = this.origin; - return c >= 0 ? (n = (e.min.x - d.x) * c, i = (e.max.x - d.x) * c) : (n = (e.max.x - d.x) * c, i = (e.min.x - d.x) * c), h >= 0 ? (r = (e.min.y - d.y) * h, o = (e.max.y - d.y) * h) : (r = (e.max.y - d.y) * h, o = (e.min.y - d.y) * h), n > o || r > i || ((r > n || n !== n) && (n = r), (o < i || i !== i) && (i = o), u >= 0 ? (a = (e.min.z - d.z) * u, l = (e.max.z - d.z) * u) : (a = (e.max.z - d.z) * u, l = (e.min.z - d.z) * u), n > l || a > i) || ((a > n || n !== n) && (n = a), (l < i || i !== i) && (i = l), i < 0) ? null : this.at(n >= 0 ? n : i, t); + let n, i, r, a, o, c, l = 1 / this.direction.x, h = 1 / this.direction.y, u = 1 / this.direction.z, d = this.origin; + return l >= 0 ? (n = (e.min.x - d.x) * l, i = (e.max.x - d.x) * l) : (n = (e.max.x - d.x) * l, i = (e.min.x - d.x) * l), h >= 0 ? (r = (e.min.y - d.y) * h, a = (e.max.y - d.y) * h) : (r = (e.max.y - d.y) * h, a = (e.min.y - d.y) * h), n > a || r > i || ((r > n || isNaN(n)) && (n = r), (a < i || isNaN(i)) && (i = a), u >= 0 ? (o = (e.min.z - d.z) * u, c = (e.max.z - d.z) * u) : (o = (e.max.z - d.z) * u, c = (e.min.z - d.z) * u), n > c || o > i) || ((o > n || n !== n) && (n = o), (c < i || i !== i) && (i = c), i < 0) ? null : this.at(n >= 0 ? n : i, t); } intersectsBox(e) { - return this.intersectBox(e, jt) !== null; + return this.intersectBox(e, ln) !== null; } intersectTriangle(e, t, n, i, r) { - Eo.subVectors(t, e), Yr.subVectors(n, e), Ao.crossVectors(Eo, Yr); - let o = this.direction.dot(Ao), a; - if (o > 0) { + Va.subVectors(t, e), Ys.subVectors(n, e), ka.crossVectors(Va, Ys); + let a = this.direction.dot(ka), o; + if (a > 0) { if (i) return null; - a = 1; - } else if (o < 0) a = -1, o = -o; + o = 1; + } else if (a < 0) o = -1, a = -a; else return null; - fn.subVectors(this.origin, e); - let l = a * this.direction.dot(Yr.crossVectors(fn, Yr)); - if (l < 0) return null; - let c = a * this.direction.dot(Eo.cross(fn)); - if (c < 0 || l + c > o) return null; - let h = -a * fn.dot(Ao); - return h < 0 ? null : this.at(h / o, r); + An.subVectors(this.origin, e); + let c = o * this.direction.dot(Ys.crossVectors(An, Ys)); + if (c < 0) return null; + let l = o * this.direction.dot(Va.cross(An)); + if (l < 0 || c + l > a) return null; + let h = -o * An.dot(ka); + return h < 0 ? null : this.at(h / a, r); } applyMatrix4(e) { return this.origin.applyMatrix4(e), this.direction.transformDirection(e), this; @@ -1670,9 +2116,9 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { clone() { return new this.constructor().copy(this); } -}, pe = class { - constructor(){ - this.elements = [ +}, ze = class s1 { + constructor(e, t, n, i, r, a, o, c, l, h, u, d, f, m, _, g){ + s1.prototype.isMatrix4 = !0, this.elements = [ 1, 0, 0, @@ -1689,17 +2135,17 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { 0, 0, 1 - ], arguments.length > 0 && console.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead."); + ], e !== void 0 && this.set(e, t, n, i, r, a, o, c, l, h, u, d, f, m, _, g); } - set(e, t, n, i, r, o, a, l, c, h, u, d, f, m, x, v) { - let g = this.elements; - return g[0] = e, g[4] = t, g[8] = n, g[12] = i, g[1] = r, g[5] = o, g[9] = a, g[13] = l, g[2] = c, g[6] = h, g[10] = u, g[14] = d, g[3] = f, g[7] = m, g[11] = x, g[15] = v, this; + set(e, t, n, i, r, a, o, c, l, h, u, d, f, m, _, g) { + let p = this.elements; + return p[0] = e, p[4] = t, p[8] = n, p[12] = i, p[1] = r, p[5] = a, p[9] = o, p[13] = c, p[2] = l, p[6] = h, p[10] = u, p[14] = d, p[3] = f, p[7] = m, p[11] = _, p[15] = g, this; } identity() { return this.set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1), this; } clone() { - return new pe().fromArray(this.elements); + return new s1().fromArray(this.elements); } copy(e) { let t = this.elements, n = e.elements; @@ -1720,57 +2166,56 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { return this.set(e.x, t.x, n.x, 0, e.y, t.y, n.y, 0, e.z, t.z, n.z, 0, 0, 0, 0, 1), this; } extractRotation(e) { - let t = this.elements, n = e.elements, i = 1 / si.setFromMatrixColumn(e, 0).length(), r = 1 / si.setFromMatrixColumn(e, 1).length(), o = 1 / si.setFromMatrixColumn(e, 2).length(); - return t[0] = n[0] * i, t[1] = n[1] * i, t[2] = n[2] * i, t[3] = 0, t[4] = n[4] * r, t[5] = n[5] * r, t[6] = n[6] * r, t[7] = 0, t[8] = n[8] * o, t[9] = n[9] * o, t[10] = n[10] * o, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, this; + let t = this.elements, n = e.elements, i = 1 / Mi.setFromMatrixColumn(e, 0).length(), r = 1 / Mi.setFromMatrixColumn(e, 1).length(), a = 1 / Mi.setFromMatrixColumn(e, 2).length(); + return t[0] = n[0] * i, t[1] = n[1] * i, t[2] = n[2] * i, t[3] = 0, t[4] = n[4] * r, t[5] = n[5] * r, t[6] = n[6] * r, t[7] = 0, t[8] = n[8] * a, t[9] = n[9] * a, t[10] = n[10] * a, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, this; } makeRotationFromEuler(e) { - e && e.isEuler || console.error("THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order."); - let t = this.elements, n = e.x, i = e.y, r = e.z, o = Math.cos(n), a = Math.sin(n), l = Math.cos(i), c = Math.sin(i), h = Math.cos(r), u = Math.sin(r); + let t = this.elements, n = e.x, i = e.y, r = e.z, a = Math.cos(n), o = Math.sin(n), c = Math.cos(i), l = Math.sin(i), h = Math.cos(r), u = Math.sin(r); if (e.order === "XYZ") { - let d = o * h, f = o * u, m = a * h, x = a * u; - t[0] = l * h, t[4] = -l * u, t[8] = c, t[1] = f + m * c, t[5] = d - x * c, t[9] = -a * l, t[2] = x - d * c, t[6] = m + f * c, t[10] = o * l; + let d = a * h, f = a * u, m = o * h, _ = o * u; + t[0] = c * h, t[4] = -c * u, t[8] = l, t[1] = f + m * l, t[5] = d - _ * l, t[9] = -o * c, t[2] = _ - d * l, t[6] = m + f * l, t[10] = a * c; } else if (e.order === "YXZ") { - let d = l * h, f = l * u, m = c * h, x = c * u; - t[0] = d + x * a, t[4] = m * a - f, t[8] = o * c, t[1] = o * u, t[5] = o * h, t[9] = -a, t[2] = f * a - m, t[6] = x + d * a, t[10] = o * l; + let d = c * h, f = c * u, m = l * h, _ = l * u; + t[0] = d + _ * o, t[4] = m * o - f, t[8] = a * l, t[1] = a * u, t[5] = a * h, t[9] = -o, t[2] = f * o - m, t[6] = _ + d * o, t[10] = a * c; } else if (e.order === "ZXY") { - let d = l * h, f = l * u, m = c * h, x = c * u; - t[0] = d - x * a, t[4] = -o * u, t[8] = m + f * a, t[1] = f + m * a, t[5] = o * h, t[9] = x - d * a, t[2] = -o * c, t[6] = a, t[10] = o * l; + let d = c * h, f = c * u, m = l * h, _ = l * u; + t[0] = d - _ * o, t[4] = -a * u, t[8] = m + f * o, t[1] = f + m * o, t[5] = a * h, t[9] = _ - d * o, t[2] = -a * l, t[6] = o, t[10] = a * c; } else if (e.order === "ZYX") { - let d = o * h, f = o * u, m = a * h, x = a * u; - t[0] = l * h, t[4] = m * c - f, t[8] = d * c + x, t[1] = l * u, t[5] = x * c + d, t[9] = f * c - m, t[2] = -c, t[6] = a * l, t[10] = o * l; + let d = a * h, f = a * u, m = o * h, _ = o * u; + t[0] = c * h, t[4] = m * l - f, t[8] = d * l + _, t[1] = c * u, t[5] = _ * l + d, t[9] = f * l - m, t[2] = -l, t[6] = o * c, t[10] = a * c; } else if (e.order === "YZX") { - let d = o * l, f = o * c, m = a * l, x = a * c; - t[0] = l * h, t[4] = x - d * u, t[8] = m * u + f, t[1] = u, t[5] = o * h, t[9] = -a * h, t[2] = -c * h, t[6] = f * u + m, t[10] = d - x * u; + let d = a * c, f = a * l, m = o * c, _ = o * l; + t[0] = c * h, t[4] = _ - d * u, t[8] = m * u + f, t[1] = u, t[5] = a * h, t[9] = -o * h, t[2] = -l * h, t[6] = f * u + m, t[10] = d - _ * u; } else if (e.order === "XZY") { - let d = o * l, f = o * c, m = a * l, x = a * c; - t[0] = l * h, t[4] = -u, t[8] = c * h, t[1] = d * u + x, t[5] = o * h, t[9] = f * u - m, t[2] = m * u - f, t[6] = a * h, t[10] = x * u + d; + let d = a * c, f = a * l, m = o * c, _ = o * l; + t[0] = c * h, t[4] = -u, t[8] = l * h, t[1] = d * u + _, t[5] = a * h, t[9] = f * u - m, t[2] = m * u - f, t[6] = o * h, t[10] = _ * u + d; } return t[3] = 0, t[7] = 0, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, this; } makeRotationFromQuaternion(e) { - return this.compose(tf, e, nf); + return this.compose(ap, e, op); } lookAt(e, t, n) { let i = this.elements; - return St.subVectors(e, t), St.lengthSq() === 0 && (St.z = 1), St.normalize(), pn.crossVectors(n, St), pn.lengthSq() === 0 && (Math.abs(n.z) === 1 ? St.x += 1e-4 : St.z += 1e-4, St.normalize(), pn.crossVectors(n, St)), pn.normalize(), Zr.crossVectors(St, pn), i[0] = pn.x, i[4] = Zr.x, i[8] = St.x, i[1] = pn.y, i[5] = Zr.y, i[9] = St.y, i[2] = pn.z, i[6] = Zr.z, i[10] = St.z, this; + return zt.subVectors(e, t), zt.lengthSq() === 0 && (zt.z = 1), zt.normalize(), Rn.crossVectors(n, zt), Rn.lengthSq() === 0 && (Math.abs(n.z) === 1 ? zt.x += 1e-4 : zt.z += 1e-4, zt.normalize(), Rn.crossVectors(n, zt)), Rn.normalize(), Zs.crossVectors(zt, Rn), i[0] = Rn.x, i[4] = Zs.x, i[8] = zt.x, i[1] = Rn.y, i[5] = Zs.y, i[9] = zt.y, i[2] = Rn.z, i[6] = Zs.z, i[10] = zt.z, this; } - multiply(e, t) { - return t !== void 0 ? (console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."), this.multiplyMatrices(e, t)) : this.multiplyMatrices(this, e); + multiply(e) { + return this.multiplyMatrices(this, e); } premultiply(e) { return this.multiplyMatrices(e, this); } multiplyMatrices(e, t) { - let n = e.elements, i = t.elements, r = this.elements, o = n[0], a = n[4], l = n[8], c = n[12], h = n[1], u = n[5], d = n[9], f = n[13], m = n[2], x = n[6], v = n[10], g = n[14], p = n[3], _ = n[7], y = n[11], b = n[15], A = i[0], L = i[4], I = i[8], k = i[12], B = i[1], P = i[5], w = i[9], E = i[13], D = i[2], U = i[6], F = i[10], O = i[14], ne = i[3], ce = i[7], V = i[11], W = i[15]; - return r[0] = o * A + a * B + l * D + c * ne, r[4] = o * L + a * P + l * U + c * ce, r[8] = o * I + a * w + l * F + c * V, r[12] = o * k + a * E + l * O + c * W, r[1] = h * A + u * B + d * D + f * ne, r[5] = h * L + u * P + d * U + f * ce, r[9] = h * I + u * w + d * F + f * V, r[13] = h * k + u * E + d * O + f * W, r[2] = m * A + x * B + v * D + g * ne, r[6] = m * L + x * P + v * U + g * ce, r[10] = m * I + x * w + v * F + g * V, r[14] = m * k + x * E + v * O + g * W, r[3] = p * A + _ * B + y * D + b * ne, r[7] = p * L + _ * P + y * U + b * ce, r[11] = p * I + _ * w + y * F + b * V, r[15] = p * k + _ * E + y * O + b * W, this; + let n = e.elements, i = t.elements, r = this.elements, a = n[0], o = n[4], c = n[8], l = n[12], h = n[1], u = n[5], d = n[9], f = n[13], m = n[2], _ = n[6], g = n[10], p = n[14], v = n[3], x = n[7], y = n[11], b = n[15], w = i[0], R = i[4], I = i[8], M = i[12], T = i[1], O = i[5], Y = i[9], $ = i[13], U = i[2], z = i[6], q = i[10], H = i[14], ne = i[3], W = i[7], K = i[11], D = i[15]; + return r[0] = a * w + o * T + c * U + l * ne, r[4] = a * R + o * O + c * z + l * W, r[8] = a * I + o * Y + c * q + l * K, r[12] = a * M + o * $ + c * H + l * D, r[1] = h * w + u * T + d * U + f * ne, r[5] = h * R + u * O + d * z + f * W, r[9] = h * I + u * Y + d * q + f * K, r[13] = h * M + u * $ + d * H + f * D, r[2] = m * w + _ * T + g * U + p * ne, r[6] = m * R + _ * O + g * z + p * W, r[10] = m * I + _ * Y + g * q + p * K, r[14] = m * M + _ * $ + g * H + p * D, r[3] = v * w + x * T + y * U + b * ne, r[7] = v * R + x * O + y * z + b * W, r[11] = v * I + x * Y + y * q + b * K, r[15] = v * M + x * $ + y * H + b * D, this; } multiplyScalar(e) { let t = this.elements; return t[0] *= e, t[4] *= e, t[8] *= e, t[12] *= e, t[1] *= e, t[5] *= e, t[9] *= e, t[13] *= e, t[2] *= e, t[6] *= e, t[10] *= e, t[14] *= e, t[3] *= e, t[7] *= e, t[11] *= e, t[15] *= e, this; } determinant() { - let e = this.elements, t = e[0], n = e[4], i = e[8], r = e[12], o = e[1], a = e[5], l = e[9], c = e[13], h = e[2], u = e[6], d = e[10], f = e[14], m = e[3], x = e[7], v = e[11], g = e[15]; - return m * (+r * l * u - i * c * u - r * a * d + n * c * d + i * a * f - n * l * f) + x * (+t * l * f - t * c * d + r * o * d - i * o * f + i * c * h - r * l * h) + v * (+t * c * u - t * a * f - r * o * u + n * o * f + r * a * h - n * c * h) + g * (-i * a * h - t * l * u + t * a * d + i * o * u - n * o * d + n * l * h); + let e = this.elements, t = e[0], n = e[4], i = e[8], r = e[12], a = e[1], o = e[5], c = e[9], l = e[13], h = e[2], u = e[6], d = e[10], f = e[14], m = e[3], _ = e[7], g = e[11], p = e[15]; + return m * (+r * c * u - i * l * u - r * o * d + n * l * d + i * o * f - n * c * f) + _ * (+t * c * f - t * l * d + r * a * d - i * a * f + i * l * h - r * c * h) + g * (+t * l * u - t * o * f - r * a * u + n * a * f + r * o * h - n * l * h) + p * (-i * o * h - t * c * u + t * o * d + i * a * u - n * a * d + n * c * h); } transpose() { let e = this.elements, t; @@ -1781,10 +2226,10 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { return e.isVector3 ? (i[12] = e.x, i[13] = e.y, i[14] = e.z) : (i[12] = e, i[13] = t, i[14] = n), this; } invert() { - let e = this.elements, t = e[0], n = e[1], i = e[2], r = e[3], o = e[4], a = e[5], l = e[6], c = e[7], h = e[8], u = e[9], d = e[10], f = e[11], m = e[12], x = e[13], v = e[14], g = e[15], p = u * v * c - x * d * c + x * l * f - a * v * f - u * l * g + a * d * g, _ = m * d * c - h * v * c - m * l * f + o * v * f + h * l * g - o * d * g, y = h * x * c - m * u * c + m * a * f - o * x * f - h * a * g + o * u * g, b = m * u * l - h * x * l - m * a * d + o * x * d + h * a * v - o * u * v, A = t * p + n * _ + i * y + r * b; - if (A === 0) return this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - let L = 1 / A; - return e[0] = p * L, e[1] = (x * d * r - u * v * r - x * i * f + n * v * f + u * i * g - n * d * g) * L, e[2] = (a * v * r - x * l * r + x * i * c - n * v * c - a * i * g + n * l * g) * L, e[3] = (u * l * r - a * d * r - u * i * c + n * d * c + a * i * f - n * l * f) * L, e[4] = _ * L, e[5] = (h * v * r - m * d * r + m * i * f - t * v * f - h * i * g + t * d * g) * L, e[6] = (m * l * r - o * v * r - m * i * c + t * v * c + o * i * g - t * l * g) * L, e[7] = (o * d * r - h * l * r + h * i * c - t * d * c - o * i * f + t * l * f) * L, e[8] = y * L, e[9] = (m * u * r - h * x * r - m * n * f + t * x * f + h * n * g - t * u * g) * L, e[10] = (o * x * r - m * a * r + m * n * c - t * x * c - o * n * g + t * a * g) * L, e[11] = (h * a * r - o * u * r - h * n * c + t * u * c + o * n * f - t * a * f) * L, e[12] = b * L, e[13] = (h * x * i - m * u * i + m * n * d - t * x * d - h * n * v + t * u * v) * L, e[14] = (m * a * i - o * x * i - m * n * l + t * x * l + o * n * v - t * a * v) * L, e[15] = (o * u * i - h * a * i + h * n * l - t * u * l - o * n * d + t * a * d) * L, this; + let e = this.elements, t = e[0], n = e[1], i = e[2], r = e[3], a = e[4], o = e[5], c = e[6], l = e[7], h = e[8], u = e[9], d = e[10], f = e[11], m = e[12], _ = e[13], g = e[14], p = e[15], v = u * g * l - _ * d * l + _ * c * f - o * g * f - u * c * p + o * d * p, x = m * d * l - h * g * l - m * c * f + a * g * f + h * c * p - a * d * p, y = h * _ * l - m * u * l + m * o * f - a * _ * f - h * o * p + a * u * p, b = m * u * c - h * _ * c - m * o * d + a * _ * d + h * o * g - a * u * g, w = t * v + n * x + i * y + r * b; + if (w === 0) return this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + let R = 1 / w; + return e[0] = v * R, e[1] = (_ * d * r - u * g * r - _ * i * f + n * g * f + u * i * p - n * d * p) * R, e[2] = (o * g * r - _ * c * r + _ * i * l - n * g * l - o * i * p + n * c * p) * R, e[3] = (u * c * r - o * d * r - u * i * l + n * d * l + o * i * f - n * c * f) * R, e[4] = x * R, e[5] = (h * g * r - m * d * r + m * i * f - t * g * f - h * i * p + t * d * p) * R, e[6] = (m * c * r - a * g * r - m * i * l + t * g * l + a * i * p - t * c * p) * R, e[7] = (a * d * r - h * c * r + h * i * l - t * d * l - a * i * f + t * c * f) * R, e[8] = y * R, e[9] = (m * u * r - h * _ * r - m * n * f + t * _ * f + h * n * p - t * u * p) * R, e[10] = (a * _ * r - m * o * r + m * n * l - t * _ * l - a * n * p + t * o * p) * R, e[11] = (h * o * r - a * u * r - h * n * l + t * u * l + a * n * f - t * o * f) * R, e[12] = b * R, e[13] = (h * _ * i - m * u * i + m * n * d - t * _ * d - h * n * g + t * u * g) * R, e[14] = (m * o * i - a * _ * i - m * n * c + t * _ * c + a * n * g - t * o * g) * R, e[15] = (a * u * i - h * o * i + h * n * c - t * u * c - a * n * d + t * o * d) * R, this; } scale(e) { let t = this.elements, n = e.x, i = e.y, r = e.z; @@ -1795,7 +2240,7 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { return Math.sqrt(Math.max(t, n, i)); } makeTranslation(e, t, n) { - return this.set(1, 0, 0, e, 0, 1, 0, t, 0, 0, 1, n, 0, 0, 0, 1), this; + return e.isVector3 ? this.set(1, 0, 0, e.x, 0, 1, 0, e.y, 0, 0, 1, e.z, 0, 0, 0, 1) : this.set(1, 0, 0, e, 0, 1, 0, t, 0, 0, 1, n, 0, 0, 0, 1), this; } makeRotationX(e) { let t = Math.cos(e), n = Math.sin(e); @@ -1810,33 +2255,38 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { return this.set(t, -n, 0, 0, n, t, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1), this; } makeRotationAxis(e, t) { - let n = Math.cos(t), i = Math.sin(t), r = 1 - n, o = e.x, a = e.y, l = e.z, c = r * o, h = r * a; - return this.set(c * o + n, c * a - i * l, c * l + i * a, 0, c * a + i * l, h * a + n, h * l - i * o, 0, c * l - i * a, h * l + i * o, r * l * l + n, 0, 0, 0, 0, 1), this; + let n = Math.cos(t), i = Math.sin(t), r = 1 - n, a = e.x, o = e.y, c = e.z, l = r * a, h = r * o; + return this.set(l * a + n, l * o - i * c, l * c + i * o, 0, l * o + i * c, h * o + n, h * c - i * a, 0, l * c - i * o, h * c + i * a, r * c * c + n, 0, 0, 0, 0, 1), this; } makeScale(e, t, n) { return this.set(e, 0, 0, 0, 0, t, 0, 0, 0, 0, n, 0, 0, 0, 0, 1), this; } - makeShear(e, t, n, i, r, o) { - return this.set(1, n, r, 0, e, 1, o, 0, t, i, 1, 0, 0, 0, 0, 1), this; + makeShear(e, t, n, i, r, a) { + return this.set(1, n, r, 0, e, 1, a, 0, t, i, 1, 0, 0, 0, 0, 1), this; } compose(e, t, n) { - let i = this.elements, r = t._x, o = t._y, a = t._z, l = t._w, c = r + r, h = o + o, u = a + a, d = r * c, f = r * h, m = r * u, x = o * h, v = o * u, g = a * u, p = l * c, _ = l * h, y = l * u, b = n.x, A = n.y, L = n.z; - return i[0] = (1 - (x + g)) * b, i[1] = (f + y) * b, i[2] = (m - _) * b, i[3] = 0, i[4] = (f - y) * A, i[5] = (1 - (d + g)) * A, i[6] = (v + p) * A, i[7] = 0, i[8] = (m + _) * L, i[9] = (v - p) * L, i[10] = (1 - (d + x)) * L, i[11] = 0, i[12] = e.x, i[13] = e.y, i[14] = e.z, i[15] = 1, this; + let i = this.elements, r = t._x, a = t._y, o = t._z, c = t._w, l = r + r, h = a + a, u = o + o, d = r * l, f = r * h, m = r * u, _ = a * h, g = a * u, p = o * u, v = c * l, x = c * h, y = c * u, b = n.x, w = n.y, R = n.z; + return i[0] = (1 - (_ + p)) * b, i[1] = (f + y) * b, i[2] = (m - x) * b, i[3] = 0, i[4] = (f - y) * w, i[5] = (1 - (d + p)) * w, i[6] = (g + v) * w, i[7] = 0, i[8] = (m + x) * R, i[9] = (g - v) * R, i[10] = (1 - (d + _)) * R, i[11] = 0, i[12] = e.x, i[13] = e.y, i[14] = e.z, i[15] = 1, this; } decompose(e, t, n) { - let i = this.elements, r = si.set(i[0], i[1], i[2]).length(), o = si.set(i[4], i[5], i[6]).length(), a = si.set(i[8], i[9], i[10]).length(); - this.determinant() < 0 && (r = -r), e.x = i[12], e.y = i[13], e.z = i[14], It.copy(this); - let c = 1 / r, h = 1 / o, u = 1 / a; - return It.elements[0] *= c, It.elements[1] *= c, It.elements[2] *= c, It.elements[4] *= h, It.elements[5] *= h, It.elements[6] *= h, It.elements[8] *= u, It.elements[9] *= u, It.elements[10] *= u, t.setFromRotationMatrix(It), n.x = r, n.y = o, n.z = a, this; - } - makePerspective(e, t, n, i, r, o) { - o === void 0 && console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs."); - let a = this.elements, l = 2 * r / (t - e), c = 2 * r / (n - i), h = (t + e) / (t - e), u = (n + i) / (n - i), d = -(o + r) / (o - r), f = -2 * o * r / (o - r); - return a[0] = l, a[4] = 0, a[8] = h, a[12] = 0, a[1] = 0, a[5] = c, a[9] = u, a[13] = 0, a[2] = 0, a[6] = 0, a[10] = d, a[14] = f, a[3] = 0, a[7] = 0, a[11] = -1, a[15] = 0, this; - } - makeOrthographic(e, t, n, i, r, o) { - let a = this.elements, l = 1 / (t - e), c = 1 / (n - i), h = 1 / (o - r), u = (t + e) * l, d = (n + i) * c, f = (o + r) * h; - return a[0] = 2 * l, a[4] = 0, a[8] = 0, a[12] = -u, a[1] = 0, a[5] = 2 * c, a[9] = 0, a[13] = -d, a[2] = 0, a[6] = 0, a[10] = -2 * h, a[14] = -f, a[3] = 0, a[7] = 0, a[11] = 0, a[15] = 1, this; + let i = this.elements, r = Mi.set(i[0], i[1], i[2]).length(), a = Mi.set(i[4], i[5], i[6]).length(), o = Mi.set(i[8], i[9], i[10]).length(); + this.determinant() < 0 && (r = -r), e.x = i[12], e.y = i[13], e.z = i[14], $t.copy(this); + let l = 1 / r, h = 1 / a, u = 1 / o; + return $t.elements[0] *= l, $t.elements[1] *= l, $t.elements[2] *= l, $t.elements[4] *= h, $t.elements[5] *= h, $t.elements[6] *= h, $t.elements[8] *= u, $t.elements[9] *= u, $t.elements[10] *= u, t.setFromRotationMatrix($t), n.x = r, n.y = a, n.z = o, this; + } + makePerspective(e, t, n, i, r, a, o = vn) { + let c = this.elements, l = 2 * r / (t - e), h = 2 * r / (n - i), u = (t + e) / (t - e), d = (n + i) / (n - i), f, m; + if (o === vn) f = -(a + r) / (a - r), m = -2 * a * r / (a - r); + else if (o === Gr) f = -a / (a - r), m = -a * r / (a - r); + else throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: " + o); + return c[0] = l, c[4] = 0, c[8] = u, c[12] = 0, c[1] = 0, c[5] = h, c[9] = d, c[13] = 0, c[2] = 0, c[6] = 0, c[10] = f, c[14] = m, c[3] = 0, c[7] = 0, c[11] = -1, c[15] = 0, this; + } + makeOrthographic(e, t, n, i, r, a, o = vn) { + let c = this.elements, l = 1 / (t - e), h = 1 / (n - i), u = 1 / (a - r), d = (t + e) * l, f = (n + i) * h, m, _; + if (o === vn) m = (a + r) * u, _ = -2 * u; + else if (o === Gr) m = r * u, _ = -1 * u; + else throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: " + o); + return c[0] = 2 * l, c[4] = 0, c[8] = 0, c[12] = -d, c[1] = 0, c[5] = 2 * h, c[9] = 0, c[13] = -f, c[2] = 0, c[6] = 0, c[10] = _, c[14] = -m, c[3] = 0, c[7] = 0, c[11] = 0, c[15] = 1, this; } equals(e) { let t = this.elements, n = e.elements; @@ -1851,11 +2301,9 @@ var ef = new Lt, vl = new M, Xr = new M, So = new M, An = class { let n = this.elements; return e[t] = n[0], e[t + 1] = n[1], e[t + 2] = n[2], e[t + 3] = n[3], e[t + 4] = n[4], e[t + 5] = n[5], e[t + 6] = n[6], e[t + 7] = n[7], e[t + 8] = n[8], e[t + 9] = n[9], e[t + 10] = n[10], e[t + 11] = n[11], e[t + 12] = n[12], e[t + 13] = n[13], e[t + 14] = n[14], e[t + 15] = n[15], e; } -}; -pe.prototype.isMatrix4 = !0; -var si = new M, It = new pe, tf = new M(0, 0, 0), nf = new M(1, 1, 1), pn = new M, Zr = new M, St = new M, _l = new pe, Ml = new gt, Zn = class { - constructor(e = 0, t = 0, n = 0, i = Zn.DefaultOrder){ - this._x = e, this._y = t, this._z = n, this._order = i; +}, Mi = new A, $t = new ze, ap = new A(0, 0, 0), op = new A(1, 1, 1), Rn = new A, Zs = new A, zt = new A, Xl = new ze, ql = new Ut, Yr = class s1 { + constructor(e = 0, t = 0, n = 0, i = s1.DEFAULT_ORDER){ + this.isEuler = !0, this._x = e, this._y = t, this._z = n, this._order = i; } get x() { return this._x; @@ -1891,25 +2339,25 @@ var si = new M, It = new pe, tf = new M(0, 0, 0), nf = new M(1, 1, 1), pn = new return this._x = e._x, this._y = e._y, this._z = e._z, this._order = e._order, this._onChangeCallback(), this; } setFromRotationMatrix(e, t = this._order, n = !0) { - let i = e.elements, r = i[0], o = i[4], a = i[8], l = i[1], c = i[5], h = i[9], u = i[2], d = i[6], f = i[10]; + let i = e.elements, r = i[0], a = i[4], o = i[8], c = i[1], l = i[5], h = i[9], u = i[2], d = i[6], f = i[10]; switch(t){ case "XYZ": - this._y = Math.asin(mt(a, -1, 1)), Math.abs(a) < .9999999 ? (this._x = Math.atan2(-h, f), this._z = Math.atan2(-o, r)) : (this._x = Math.atan2(d, c), this._z = 0); + this._y = Math.asin(ct(o, -1, 1)), Math.abs(o) < .9999999 ? (this._x = Math.atan2(-h, f), this._z = Math.atan2(-a, r)) : (this._x = Math.atan2(d, l), this._z = 0); break; case "YXZ": - this._x = Math.asin(-mt(h, -1, 1)), Math.abs(h) < .9999999 ? (this._y = Math.atan2(a, f), this._z = Math.atan2(l, c)) : (this._y = Math.atan2(-u, r), this._z = 0); + this._x = Math.asin(-ct(h, -1, 1)), Math.abs(h) < .9999999 ? (this._y = Math.atan2(o, f), this._z = Math.atan2(c, l)) : (this._y = Math.atan2(-u, r), this._z = 0); break; case "ZXY": - this._x = Math.asin(mt(d, -1, 1)), Math.abs(d) < .9999999 ? (this._y = Math.atan2(-u, f), this._z = Math.atan2(-o, c)) : (this._y = 0, this._z = Math.atan2(l, r)); + this._x = Math.asin(ct(d, -1, 1)), Math.abs(d) < .9999999 ? (this._y = Math.atan2(-u, f), this._z = Math.atan2(-a, l)) : (this._y = 0, this._z = Math.atan2(c, r)); break; case "ZYX": - this._y = Math.asin(-mt(u, -1, 1)), Math.abs(u) < .9999999 ? (this._x = Math.atan2(d, f), this._z = Math.atan2(l, r)) : (this._x = 0, this._z = Math.atan2(-o, c)); + this._y = Math.asin(-ct(u, -1, 1)), Math.abs(u) < .9999999 ? (this._x = Math.atan2(d, f), this._z = Math.atan2(c, r)) : (this._x = 0, this._z = Math.atan2(-a, l)); break; case "YZX": - this._z = Math.asin(mt(l, -1, 1)), Math.abs(l) < .9999999 ? (this._x = Math.atan2(-h, c), this._y = Math.atan2(-u, r)) : (this._x = 0, this._y = Math.atan2(a, f)); + this._z = Math.asin(ct(c, -1, 1)), Math.abs(c) < .9999999 ? (this._x = Math.atan2(-h, l), this._y = Math.atan2(-u, r)) : (this._x = 0, this._y = Math.atan2(o, f)); break; case "XZY": - this._z = Math.asin(-mt(o, -1, 1)), Math.abs(o) < .9999999 ? (this._x = Math.atan2(d, c), this._y = Math.atan2(a, r)) : (this._x = Math.atan2(-h, f), this._y = 0); + this._z = Math.asin(-ct(a, -1, 1)), Math.abs(a) < .9999999 ? (this._x = Math.atan2(d, l), this._y = Math.atan2(o, r)) : (this._x = Math.atan2(-h, f), this._y = 0); break; default: console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: " + t); @@ -1917,13 +2365,13 @@ var si = new M, It = new pe, tf = new M(0, 0, 0), nf = new M(1, 1, 1), pn = new return this._order = t, n === !0 && this._onChangeCallback(), this; } setFromQuaternion(e, t, n) { - return _l.makeRotationFromQuaternion(e), this.setFromRotationMatrix(_l, t, n); + return Xl.makeRotationFromQuaternion(e), this.setFromRotationMatrix(Xl, t, n); } setFromVector3(e, t = this._order) { return this.set(e.x, e.y, e.z, t); } reorder(e) { - return Ml.setFromEuler(this), this.setFromQuaternion(Ml, e); + return ql.setFromEuler(this), this.setFromQuaternion(ql, e); } equals(e) { return e._x === this._x && e._y === this._y && e._z === this._z && e._order === this._order; @@ -1934,25 +2382,16 @@ var si = new M, It = new pe, tf = new M(0, 0, 0), nf = new M(1, 1, 1), pn = new toArray(e = [], t = 0) { return e[t] = this._x, e[t + 1] = this._y, e[t + 2] = this._z, e[t + 3] = this._order, e; } - toVector3(e) { - return e ? e.set(this._x, this._y, this._z) : new M(this._x, this._y, this._z); - } _onChange(e) { return this._onChangeCallback = e, this; } _onChangeCallback() {} + *[Symbol.iterator]() { + yield this._x, yield this._y, yield this._z, yield this._order; + } }; -Zn.prototype.isEuler = !0; -Zn.DefaultOrder = "XYZ"; -Zn.RotationOrders = [ - "XYZ", - "YZX", - "ZXY", - "XZY", - "YXZ", - "ZYX" -]; -var Js = class { +Yr.DEFAULT_ORDER = "XYZ"; +var Rs = class { constructor(){ this.mask = 1; } @@ -1980,24 +2419,23 @@ var Js = class { isEnabled(e) { return (this.mask & (1 << e | 0)) !== 0; } -}, rf = 0, bl = new M, oi = new gt, Qt = new pe, $r = new M, Zi = new M, sf = new M, of = new gt, wl = new M(1, 0, 0), Sl = new M(0, 1, 0), Tl = new M(0, 0, 1), af = { +}, cp = 0, Yl = new A, Si = new Ut, hn = new ze, Js = new A, hs = new A, lp = new A, hp = new Ut, Zl = new A(1, 0, 0), Jl = new A(0, 1, 0), $l = new A(0, 0, 1), up = { type: "added" -}, El = { +}, dp = { type: "removed" -}, Ne = class extends En { +}, Je = class s1 extends sn { constructor(){ - super(); - Object.defineProperty(this, "id", { - value: rf++ - }), this.uuid = Et(), this.name = "", this.type = "Object3D", this.parent = null, this.children = [], this.up = Ne.DefaultUp.clone(); - let e = new M, t = new Zn, n = new gt, i = new M(1, 1, 1); + super(), this.isObject3D = !0, Object.defineProperty(this, "id", { + value: cp++ + }), this.uuid = kt(), this.name = "", this.type = "Object3D", this.parent = null, this.children = [], this.up = s1.DEFAULT_UP.clone(); + let e = new A, t = new Yr, n = new Ut, i = new A(1, 1, 1); function r() { n.setFromEuler(t, !1); } - function o() { + function a() { t.setFromQuaternion(n, void 0, !1); } - t._onChange(r), n._onChange(o), Object.defineProperties(this, { + t._onChange(r), n._onChange(a), Object.defineProperties(this, { position: { configurable: !0, enumerable: !0, @@ -2019,12 +2457,12 @@ var Js = class { value: i }, modelViewMatrix: { - value: new pe + value: new ze }, normalMatrix: { - value: new lt + value: new He } - }), this.matrix = new pe, this.matrixWorld = new pe, this.matrixAutoUpdate = Ne.DefaultMatrixAutoUpdate, this.matrixWorldNeedsUpdate = !1, this.layers = new Js, this.visible = !0, this.castShadow = !1, this.receiveShadow = !1, this.frustumCulled = !0, this.renderOrder = 0, this.animations = [], this.userData = {}; + }), this.matrix = new ze, this.matrixWorld = new ze, this.matrixAutoUpdate = s1.DEFAULT_MATRIX_AUTO_UPDATE, this.matrixWorldNeedsUpdate = !1, this.matrixWorldAutoUpdate = s1.DEFAULT_MATRIX_WORLD_AUTO_UPDATE, this.layers = new Rs, this.visible = !0, this.castShadow = !1, this.receiveShadow = !1, this.frustumCulled = !0, this.renderOrder = 0, this.animations = [], this.userData = {}; } onBeforeRender() {} onAfterRender() {} @@ -2047,49 +2485,49 @@ var Js = class { this.quaternion.copy(e); } rotateOnAxis(e, t) { - return oi.setFromAxisAngle(e, t), this.quaternion.multiply(oi), this; + return Si.setFromAxisAngle(e, t), this.quaternion.multiply(Si), this; } rotateOnWorldAxis(e, t) { - return oi.setFromAxisAngle(e, t), this.quaternion.premultiply(oi), this; + return Si.setFromAxisAngle(e, t), this.quaternion.premultiply(Si), this; } rotateX(e) { - return this.rotateOnAxis(wl, e); + return this.rotateOnAxis(Zl, e); } rotateY(e) { - return this.rotateOnAxis(Sl, e); + return this.rotateOnAxis(Jl, e); } rotateZ(e) { - return this.rotateOnAxis(Tl, e); + return this.rotateOnAxis($l, e); } translateOnAxis(e, t) { - return bl.copy(e).applyQuaternion(this.quaternion), this.position.add(bl.multiplyScalar(t)), this; + return Yl.copy(e).applyQuaternion(this.quaternion), this.position.add(Yl.multiplyScalar(t)), this; } translateX(e) { - return this.translateOnAxis(wl, e); + return this.translateOnAxis(Zl, e); } translateY(e) { - return this.translateOnAxis(Sl, e); + return this.translateOnAxis(Jl, e); } translateZ(e) { - return this.translateOnAxis(Tl, e); + return this.translateOnAxis($l, e); } localToWorld(e) { - return e.applyMatrix4(this.matrixWorld); + return this.updateWorldMatrix(!0, !1), e.applyMatrix4(this.matrixWorld); } worldToLocal(e) { - return e.applyMatrix4(Qt.copy(this.matrixWorld).invert()); + return this.updateWorldMatrix(!0, !1), e.applyMatrix4(hn.copy(this.matrixWorld).invert()); } lookAt(e, t, n) { - e.isVector3 ? $r.copy(e) : $r.set(e, t, n); + e.isVector3 ? Js.copy(e) : Js.set(e, t, n); let i = this.parent; - this.updateWorldMatrix(!0, !1), Zi.setFromMatrixPosition(this.matrixWorld), this.isCamera || this.isLight ? Qt.lookAt(Zi, $r, this.up) : Qt.lookAt($r, Zi, this.up), this.quaternion.setFromRotationMatrix(Qt), i && (Qt.extractRotation(i.matrixWorld), oi.setFromRotationMatrix(Qt), this.quaternion.premultiply(oi.invert())); + this.updateWorldMatrix(!0, !1), hs.setFromMatrixPosition(this.matrixWorld), this.isCamera || this.isLight ? hn.lookAt(hs, Js, this.up) : hn.lookAt(Js, hs, this.up), this.quaternion.setFromRotationMatrix(hn), i && (hn.extractRotation(i.matrixWorld), Si.setFromRotationMatrix(hn), this.quaternion.premultiply(Si.invert())); } add(e) { if (arguments.length > 1) { for(let t = 0; t < arguments.length; t++)this.add(arguments[t]); return this; } - return e === this ? (console.error("THREE.Object3D.add: object can't be added as a child of itself.", e), this) : (e && e.isObject3D ? (e.parent !== null && e.parent.remove(e), e.parent = this, this.children.push(e), e.dispatchEvent(af)) : console.error("THREE.Object3D.add: object not an instance of THREE.Object3D.", e), this); + return e === this ? (console.error("THREE.Object3D.add: object can't be added as a child of itself.", e), this) : (e && e.isObject3D ? (e.parent !== null && e.parent.remove(e), e.parent = this, this.children.push(e), e.dispatchEvent(up)) : console.error("THREE.Object3D.add: object not an instance of THREE.Object3D.", e), this); } remove(e) { if (arguments.length > 1) { @@ -2097,21 +2535,17 @@ var Js = class { return this; } let t = this.children.indexOf(e); - return t !== -1 && (e.parent = null, this.children.splice(t, 1), e.dispatchEvent(El)), this; + return t !== -1 && (e.parent = null, this.children.splice(t, 1), e.dispatchEvent(dp)), this; } removeFromParent() { let e = this.parent; return e !== null && e.remove(this), this; } clear() { - for(let e = 0; e < this.children.length; e++){ - let t = this.children[e]; - t.parent = null, t.dispatchEvent(El); - } - return this.children.length = 0, this; + return this.remove(...this.children); } attach(e) { - return this.updateWorldMatrix(!0, !1), Qt.copy(this.matrixWorld).invert(), e.parent !== null && (e.parent.updateWorldMatrix(!0, !1), Qt.multiply(e.parent.matrixWorld)), e.applyMatrix4(Qt), this.add(e), e.updateWorldMatrix(!1, !0), this; + return this.updateWorldMatrix(!0, !1), hn.copy(this.matrixWorld).invert(), e.parent !== null && (e.parent.updateWorldMatrix(!0, !1), hn.multiply(e.parent.matrixWorld)), e.applyMatrix4(hn), this.add(e), e.updateWorldMatrix(!1, !0), this; } getObjectById(e) { return this.getObjectByProperty("id", e); @@ -2122,18 +2556,27 @@ var Js = class { getObjectByProperty(e, t) { if (this[e] === t) return this; for(let n = 0, i = this.children.length; n < i; n++){ - let o = this.children[n].getObjectByProperty(e, t); - if (o !== void 0) return o; + let a = this.children[n].getObjectByProperty(e, t); + if (a !== void 0) return a; + } + } + getObjectsByProperty(e, t) { + let n = []; + this[e] === t && n.push(this); + for(let i = 0, r = this.children.length; i < r; i++){ + let a = this.children[i].getObjectsByProperty(e, t); + a.length > 0 && (n = n.concat(a)); } + return n; } getWorldPosition(e) { return this.updateWorldMatrix(!0, !1), e.setFromMatrixPosition(this.matrixWorld); } getWorldQuaternion(e) { - return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(Zi, e, sf), e; + return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(hs, e, lp), e; } getWorldScale(e) { - return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(Zi, of, e), e; + return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(hs, hp, e), e; } getWorldDirection(e) { this.updateWorldMatrix(!0, !1); @@ -2162,13 +2605,19 @@ var Js = class { updateMatrixWorld(e) { this.matrixAutoUpdate && this.updateMatrix(), (this.matrixWorldNeedsUpdate || e) && (this.parent === null ? this.matrixWorld.copy(this.matrix) : this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix), this.matrixWorldNeedsUpdate = !1, e = !0); let t = this.children; - for(let n = 0, i = t.length; n < i; n++)t[n].updateMatrixWorld(e); + for(let n = 0, i = t.length; n < i; n++){ + let r = t[n]; + (r.matrixWorldAutoUpdate === !0 || e === !0) && r.updateMatrixWorld(e); + } } updateWorldMatrix(e, t) { let n = this.parent; - if (e === !0 && n !== null && n.updateWorldMatrix(!0, !1), this.matrixAutoUpdate && this.updateMatrix(), this.parent === null ? this.matrixWorld.copy(this.matrix) : this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix), t === !0) { + if (e === !0 && n !== null && n.matrixWorldAutoUpdate === !0 && n.updateWorldMatrix(!0, !1), this.matrixAutoUpdate && this.updateMatrix(), this.parent === null ? this.matrixWorld.copy(this.matrix) : this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix), t === !0) { let i = this.children; - for(let r = 0, o = i.length; r < o; r++)i[r].updateWorldMatrix(!1, !0); + for(let r = 0, a = i.length; r < a; r++){ + let o = i[r]; + o.matrixWorldAutoUpdate === !0 && o.updateWorldMatrix(!1, !0); + } } } toJSON(e) { @@ -2180,98 +2629,102 @@ var Js = class { images: {}, shapes: {}, skeletons: {}, - animations: {} + animations: {}, + nodes: {} }, n.metadata = { - version: 4.5, + version: 4.6, type: "Object", generator: "Object3D.toJSON" }); let i = {}; - i.uuid = this.uuid, i.type = this.type, this.name !== "" && (i.name = this.name), this.castShadow === !0 && (i.castShadow = !0), this.receiveShadow === !0 && (i.receiveShadow = !0), this.visible === !1 && (i.visible = !1), this.frustumCulled === !1 && (i.frustumCulled = !1), this.renderOrder !== 0 && (i.renderOrder = this.renderOrder), JSON.stringify(this.userData) !== "{}" && (i.userData = this.userData), i.layers = this.layers.mask, i.matrix = this.matrix.toArray(), this.matrixAutoUpdate === !1 && (i.matrixAutoUpdate = !1), this.isInstancedMesh && (i.type = "InstancedMesh", i.count = this.count, i.instanceMatrix = this.instanceMatrix.toJSON(), this.instanceColor !== null && (i.instanceColor = this.instanceColor.toJSON())); - function r(a, l) { - return a[l.uuid] === void 0 && (a[l.uuid] = l.toJSON(e)), l.uuid; + i.uuid = this.uuid, i.type = this.type, this.name !== "" && (i.name = this.name), this.castShadow === !0 && (i.castShadow = !0), this.receiveShadow === !0 && (i.receiveShadow = !0), this.visible === !1 && (i.visible = !1), this.frustumCulled === !1 && (i.frustumCulled = !1), this.renderOrder !== 0 && (i.renderOrder = this.renderOrder), Object.keys(this.userData).length > 0 && (i.userData = this.userData), i.layers = this.layers.mask, i.matrix = this.matrix.toArray(), i.up = this.up.toArray(), this.matrixAutoUpdate === !1 && (i.matrixAutoUpdate = !1), this.isInstancedMesh && (i.type = "InstancedMesh", i.count = this.count, i.instanceMatrix = this.instanceMatrix.toJSON(), this.instanceColor !== null && (i.instanceColor = this.instanceColor.toJSON())); + function r(o, c) { + return o[c.uuid] === void 0 && (o[c.uuid] = c.toJSON(e)), c.uuid; } - if (this.isScene) this.background && (this.background.isColor ? i.background = this.background.toJSON() : this.background.isTexture && (i.background = this.background.toJSON(e).uuid)), this.environment && this.environment.isTexture && (i.environment = this.environment.toJSON(e).uuid); + if (this.isScene) this.background && (this.background.isColor ? i.background = this.background.toJSON() : this.background.isTexture && (i.background = this.background.toJSON(e).uuid)), this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== !0 && (i.environment = this.environment.toJSON(e).uuid); else if (this.isMesh || this.isLine || this.isPoints) { i.geometry = r(e.geometries, this.geometry); - let a = this.geometry.parameters; - if (a !== void 0 && a.shapes !== void 0) { - let l = a.shapes; - if (Array.isArray(l)) for(let c = 0, h = l.length; c < h; c++){ - let u = l[c]; + let o = this.geometry.parameters; + if (o !== void 0 && o.shapes !== void 0) { + let c = o.shapes; + if (Array.isArray(c)) for(let l = 0, h = c.length; l < h; l++){ + let u = c[l]; r(e.shapes, u); } - else r(e.shapes, l); + else r(e.shapes, c); } } if (this.isSkinnedMesh && (i.bindMode = this.bindMode, i.bindMatrix = this.bindMatrix.toArray(), this.skeleton !== void 0 && (r(e.skeletons, this.skeleton), i.skeleton = this.skeleton.uuid)), this.material !== void 0) if (Array.isArray(this.material)) { - let a = []; - for(let l = 0, c = this.material.length; l < c; l++)a.push(r(e.materials, this.material[l])); - i.material = a; + let o = []; + for(let c = 0, l = this.material.length; c < l; c++)o.push(r(e.materials, this.material[c])); + i.material = o; } else i.material = r(e.materials, this.material); if (this.children.length > 0) { i.children = []; - for(let a = 0; a < this.children.length; a++)i.children.push(this.children[a].toJSON(e).object); + for(let o = 0; o < this.children.length; o++)i.children.push(this.children[o].toJSON(e).object); } if (this.animations.length > 0) { i.animations = []; - for(let a = 0; a < this.animations.length; a++){ - let l = this.animations[a]; - i.animations.push(r(e.animations, l)); + for(let o = 0; o < this.animations.length; o++){ + let c = this.animations[o]; + i.animations.push(r(e.animations, c)); } } if (t) { - let a = o(e.geometries), l = o(e.materials), c = o(e.textures), h = o(e.images), u = o(e.shapes), d = o(e.skeletons), f = o(e.animations); - a.length > 0 && (n.geometries = a), l.length > 0 && (n.materials = l), c.length > 0 && (n.textures = c), h.length > 0 && (n.images = h), u.length > 0 && (n.shapes = u), d.length > 0 && (n.skeletons = d), f.length > 0 && (n.animations = f); + let o = a(e.geometries), c = a(e.materials), l = a(e.textures), h = a(e.images), u = a(e.shapes), d = a(e.skeletons), f = a(e.animations), m = a(e.nodes); + o.length > 0 && (n.geometries = o), c.length > 0 && (n.materials = c), l.length > 0 && (n.textures = l), h.length > 0 && (n.images = h), u.length > 0 && (n.shapes = u), d.length > 0 && (n.skeletons = d), f.length > 0 && (n.animations = f), m.length > 0 && (n.nodes = m); } return n.object = i, n; - function o(a) { - let l = []; - for(let c in a){ - let h = a[c]; - delete h.metadata, l.push(h); + function a(o) { + let c = []; + for(let l in o){ + let h = o[l]; + delete h.metadata, c.push(h); } - return l; + return c; } } clone(e) { return new this.constructor().copy(this, e); } copy(e, t = !0) { - if (this.name = e.name, this.up.copy(e.up), this.position.copy(e.position), this.rotation.order = e.rotation.order, this.quaternion.copy(e.quaternion), this.scale.copy(e.scale), this.matrix.copy(e.matrix), this.matrixWorld.copy(e.matrixWorld), this.matrixAutoUpdate = e.matrixAutoUpdate, this.matrixWorldNeedsUpdate = e.matrixWorldNeedsUpdate, this.layers.mask = e.layers.mask, this.visible = e.visible, this.castShadow = e.castShadow, this.receiveShadow = e.receiveShadow, this.frustumCulled = e.frustumCulled, this.renderOrder = e.renderOrder, this.userData = JSON.parse(JSON.stringify(e.userData)), t === !0) for(let n = 0; n < e.children.length; n++){ + if (this.name = e.name, this.up.copy(e.up), this.position.copy(e.position), this.rotation.order = e.rotation.order, this.quaternion.copy(e.quaternion), this.scale.copy(e.scale), this.matrix.copy(e.matrix), this.matrixWorld.copy(e.matrixWorld), this.matrixAutoUpdate = e.matrixAutoUpdate, this.matrixWorldNeedsUpdate = e.matrixWorldNeedsUpdate, this.matrixWorldAutoUpdate = e.matrixWorldAutoUpdate, this.layers.mask = e.layers.mask, this.visible = e.visible, this.castShadow = e.castShadow, this.receiveShadow = e.receiveShadow, this.frustumCulled = e.frustumCulled, this.renderOrder = e.renderOrder, this.animations = e.animations.slice(), this.userData = JSON.parse(JSON.stringify(e.userData)), t === !0) for(let n = 0; n < e.children.length; n++){ let i = e.children[n]; this.add(i.clone()); } return this; } }; -Ne.DefaultUp = new M(0, 1, 0); -Ne.DefaultMatrixAutoUpdate = !0; -Ne.prototype.isObject3D = !0; -var Dt = new M, Kt = new M, Co = new M, en = new M, ai = new M, li = new M, Al = new M, Lo = new M, Ro = new M, Po = new M, nt = class { - constructor(e = new M, t = new M, n = new M){ +Je.DEFAULT_UP = new A(0, 1, 0); +Je.DEFAULT_MATRIX_AUTO_UPDATE = !0; +Je.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = !0; +var Kt = new A, un = new A, Ha = new A, dn = new A, bi = new A, Ei = new A, Kl = new A, Ga = new A, Wa = new A, Xa = new A, $s = !1, Un = class s1 { + constructor(e = new A, t = new A, n = new A){ this.a = e, this.b = t, this.c = n; } static getNormal(e, t, n, i) { - i.subVectors(n, t), Dt.subVectors(e, t), i.cross(Dt); + i.subVectors(n, t), Kt.subVectors(e, t), i.cross(Kt); let r = i.lengthSq(); return r > 0 ? i.multiplyScalar(1 / Math.sqrt(r)) : i.set(0, 0, 0); } static getBarycoord(e, t, n, i, r) { - Dt.subVectors(i, t), Kt.subVectors(n, t), Co.subVectors(e, t); - let o = Dt.dot(Dt), a = Dt.dot(Kt), l = Dt.dot(Co), c = Kt.dot(Kt), h = Kt.dot(Co), u = o * c - a * a; + Kt.subVectors(i, t), un.subVectors(n, t), Ha.subVectors(e, t); + let a = Kt.dot(Kt), o = Kt.dot(un), c = Kt.dot(Ha), l = un.dot(un), h = un.dot(Ha), u = a * l - o * o; if (u === 0) return r.set(-2, -1, -1); - let d = 1 / u, f = (c * l - a * h) * d, m = (o * h - a * l) * d; + let d = 1 / u, f = (l * c - o * h) * d, m = (a * h - o * c) * d; return r.set(1 - f - m, m, f); } static containsPoint(e, t, n, i) { - return this.getBarycoord(e, t, n, i, en), en.x >= 0 && en.y >= 0 && en.x + en.y <= 1; + return this.getBarycoord(e, t, n, i, dn), dn.x >= 0 && dn.y >= 0 && dn.x + dn.y <= 1; } - static getUV(e, t, n, i, r, o, a, l) { - return this.getBarycoord(e, t, n, i, en), l.set(0, 0), l.addScaledVector(r, en.x), l.addScaledVector(o, en.y), l.addScaledVector(a, en.z), l; + static getUV(e, t, n, i, r, a, o, c) { + return $s === !1 && (console.warn("THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation()."), $s = !0), this.getInterpolation(e, t, n, i, r, a, o, c); + } + static getInterpolation(e, t, n, i, r, a, o, c) { + return this.getBarycoord(e, t, n, i, dn), c.setScalar(0), c.addScaledVector(r, dn.x), c.addScaledVector(a, dn.y), c.addScaledVector(o, dn.z), c; } static isFrontFacing(e, t, n, i) { - return Dt.subVectors(n, t), Kt.subVectors(e, t), Dt.cross(Kt).dot(i) < 0; + return Kt.subVectors(n, t), un.subVectors(e, t), Kt.cross(un).dot(i) < 0; } set(e, t, n) { return this.a.copy(e), this.b.copy(t), this.c.copy(n), this; @@ -2289,61 +2742,63 @@ var Dt = new M, Kt = new M, Co = new M, en = new M, ai = new M, li = new M, Al = return this.a.copy(e.a), this.b.copy(e.b), this.c.copy(e.c), this; } getArea() { - return Dt.subVectors(this.c, this.b), Kt.subVectors(this.a, this.b), Dt.cross(Kt).length() * .5; + return Kt.subVectors(this.c, this.b), un.subVectors(this.a, this.b), Kt.cross(un).length() * .5; } getMidpoint(e) { return e.addVectors(this.a, this.b).add(this.c).multiplyScalar(1 / 3); } getNormal(e) { - return nt.getNormal(this.a, this.b, this.c, e); + return s1.getNormal(this.a, this.b, this.c, e); } getPlane(e) { return e.setFromCoplanarPoints(this.a, this.b, this.c); } getBarycoord(e, t) { - return nt.getBarycoord(e, this.a, this.b, this.c, t); + return s1.getBarycoord(e, this.a, this.b, this.c, t); } getUV(e, t, n, i, r) { - return nt.getUV(e, this.a, this.b, this.c, t, n, i, r); + return $s === !1 && (console.warn("THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation()."), $s = !0), s1.getInterpolation(e, this.a, this.b, this.c, t, n, i, r); + } + getInterpolation(e, t, n, i, r) { + return s1.getInterpolation(e, this.a, this.b, this.c, t, n, i, r); } containsPoint(e) { - return nt.containsPoint(e, this.a, this.b, this.c); + return s1.containsPoint(e, this.a, this.b, this.c); } isFrontFacing(e) { - return nt.isFrontFacing(this.a, this.b, this.c, e); + return s1.isFrontFacing(this.a, this.b, this.c, e); } intersectsBox(e) { return e.intersectsTriangle(this); } closestPointToPoint(e, t) { - let n = this.a, i = this.b, r = this.c, o, a; - ai.subVectors(i, n), li.subVectors(r, n), Lo.subVectors(e, n); - let l = ai.dot(Lo), c = li.dot(Lo); - if (l <= 0 && c <= 0) return t.copy(n); - Ro.subVectors(e, i); - let h = ai.dot(Ro), u = li.dot(Ro); + let n = this.a, i = this.b, r = this.c, a, o; + bi.subVectors(i, n), Ei.subVectors(r, n), Ga.subVectors(e, n); + let c = bi.dot(Ga), l = Ei.dot(Ga); + if (c <= 0 && l <= 0) return t.copy(n); + Wa.subVectors(e, i); + let h = bi.dot(Wa), u = Ei.dot(Wa); if (h >= 0 && u <= h) return t.copy(i); - let d = l * u - h * c; - if (d <= 0 && l >= 0 && h <= 0) return o = l / (l - h), t.copy(n).addScaledVector(ai, o); - Po.subVectors(e, r); - let f = ai.dot(Po), m = li.dot(Po); + let d = c * u - h * l; + if (d <= 0 && c >= 0 && h <= 0) return a = c / (c - h), t.copy(n).addScaledVector(bi, a); + Xa.subVectors(e, r); + let f = bi.dot(Xa), m = Ei.dot(Xa); if (m >= 0 && f <= m) return t.copy(r); - let x = f * c - l * m; - if (x <= 0 && c >= 0 && m <= 0) return a = c / (c - m), t.copy(n).addScaledVector(li, a); - let v = h * m - f * u; - if (v <= 0 && u - h >= 0 && f - m >= 0) return Al.subVectors(r, i), a = (u - h) / (u - h + (f - m)), t.copy(i).addScaledVector(Al, a); - let g = 1 / (v + x + d); - return o = x * g, a = d * g, t.copy(n).addScaledVector(ai, o).addScaledVector(li, a); + let _ = f * l - c * m; + if (_ <= 0 && l >= 0 && m <= 0) return o = l / (l - m), t.copy(n).addScaledVector(Ei, o); + let g = h * m - f * u; + if (g <= 0 && u - h >= 0 && f - m >= 0) return Kl.subVectors(r, i), o = (u - h) / (u - h + (f - m)), t.copy(i).addScaledVector(Kl, o); + let p = 1 / (g + _ + d); + return a = _ * p, o = d * p, t.copy(n).addScaledVector(bi, a).addScaledVector(Ei, o); } equals(e) { return e.a.equals(this.a) && e.b.equals(this.b) && e.c.equals(this.c); } -}, lf = 0, dt = class extends En { +}, fp = 0, bt = class extends sn { constructor(){ - super(); - Object.defineProperty(this, "id", { - value: lf++ - }), this.uuid = Et(), this.name = "", this.type = "Material", this.fog = !0, this.blending = sr, this.side = Ai, this.vertexColors = !1, this.opacity = 1, this.format = ct, this.transparent = !1, this.blendSrc = Gc, this.blendDst = Vc, this.blendEquation = _i, this.blendSrcAlpha = null, this.blendDstAlpha = null, this.blendEquationAlpha = null, this.depthFunc = ea, this.depthTest = !0, this.depthWrite = !0, this.stencilWriteMask = 255, this.stencilFunc = Ud, this.stencilRef = 0, this.stencilFuncMask = 255, this.stencilFail = vo, this.stencilZFail = vo, this.stencilZPass = vo, this.stencilWrite = !1, this.clippingPlanes = null, this.clipIntersection = !1, this.clipShadows = !1, this.shadowSide = null, this.colorWrite = !0, this.precision = null, this.polygonOffset = !1, this.polygonOffsetFactor = 0, this.polygonOffsetUnits = 0, this.dithering = !1, this.alphaToCoverage = !1, this.premultipliedAlpha = !1, this.visible = !0, this.toneMapped = !0, this.userData = {}, this.version = 0, this._alphaTest = 0; + super(), this.isMaterial = !0, Object.defineProperty(this, "id", { + value: fp++ + }), this.uuid = kt(), this.name = "", this.type = "Material", this.blending = Wi, this.side = Bn, this.vertexColors = !1, this.opacity = 1, this.transparent = !1, this.alphaHash = !1, this.blendSrc = ld, this.blendDst = hd, this.blendEquation = Bi, this.blendSrcAlpha = null, this.blendDstAlpha = null, this.blendEquationAlpha = null, this.depthFunc = uo, this.depthTest = !0, this.depthWrite = !0, this.stencilWriteMask = 255, this.stencilFunc = If, this.stencilRef = 0, this.stencilFuncMask = 255, this.stencilFail = Ia, this.stencilZFail = Ia, this.stencilZPass = Ia, this.stencilWrite = !1, this.clippingPlanes = null, this.clipIntersection = !1, this.clipShadows = !1, this.shadowSide = null, this.colorWrite = !0, this.precision = null, this.polygonOffset = !1, this.polygonOffsetFactor = 0, this.polygonOffsetUnits = 0, this.dithering = !1, this.alphaToCoverage = !1, this.premultipliedAlpha = !1, this.forceSinglePass = !1, this.visible = !0, this.toneMapped = !0, this.userData = {}, this.version = 0, this._alphaTest = 0; } get alphaTest() { return this._alphaTest; @@ -2361,16 +2816,12 @@ var Dt = new M, Kt = new M, Co = new M, en = new M, ai = new M, li = new M, Al = if (e !== void 0) for(let t in e){ let n = e[t]; if (n === void 0) { - console.warn("THREE.Material: '" + t + "' parameter is undefined."); - continue; - } - if (t === "shading") { - console.warn("THREE." + this.type + ": .shading has been removed. Use the boolean .flatShading instead."), this.flatShading = n === kc; + console.warn(`THREE.Material: parameter '${t}' has value of undefined.`); continue; } let i = this[t]; if (i === void 0) { - console.warn("THREE." + this.type + ": '" + t + "' is not a property of this material."); + console.warn(`THREE.Material: '${t}' is not a property of THREE.${this.type}.`); continue; } i && i.isColor ? i.set(n) : i && i.isVector3 && n && n.isVector3 ? i.copy(n) : this[t] = n; @@ -2384,23 +2835,23 @@ var Dt = new M, Kt = new M, Co = new M, en = new M, ai = new M, li = new M, Al = }); let n = { metadata: { - version: 4.5, + version: 4.6, type: "Material", generator: "Material.toJSON" } }; - n.uuid = this.uuid, n.type = this.type, this.name !== "" && (n.name = this.name), this.color && this.color.isColor && (n.color = this.color.getHex()), this.roughness !== void 0 && (n.roughness = this.roughness), this.metalness !== void 0 && (n.metalness = this.metalness), this.sheen !== void 0 && (n.sheen = this.sheen), this.sheenColor && this.sheenColor.isColor && (n.sheenColor = this.sheenColor.getHex()), this.sheenRoughness !== void 0 && (n.sheenRoughness = this.sheenRoughness), this.emissive && this.emissive.isColor && (n.emissive = this.emissive.getHex()), this.emissiveIntensity && this.emissiveIntensity !== 1 && (n.emissiveIntensity = this.emissiveIntensity), this.specular && this.specular.isColor && (n.specular = this.specular.getHex()), this.specularIntensity !== void 0 && (n.specularIntensity = this.specularIntensity), this.specularColor && this.specularColor.isColor && (n.specularColor = this.specularColor.getHex()), this.shininess !== void 0 && (n.shininess = this.shininess), this.clearcoat !== void 0 && (n.clearcoat = this.clearcoat), this.clearcoatRoughness !== void 0 && (n.clearcoatRoughness = this.clearcoatRoughness), this.clearcoatMap && this.clearcoatMap.isTexture && (n.clearcoatMap = this.clearcoatMap.toJSON(e).uuid), this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture && (n.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON(e).uuid), this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture && (n.clearcoatNormalMap = this.clearcoatNormalMap.toJSON(e).uuid, n.clearcoatNormalScale = this.clearcoatNormalScale.toArray()), this.map && this.map.isTexture && (n.map = this.map.toJSON(e).uuid), this.matcap && this.matcap.isTexture && (n.matcap = this.matcap.toJSON(e).uuid), this.alphaMap && this.alphaMap.isTexture && (n.alphaMap = this.alphaMap.toJSON(e).uuid), this.lightMap && this.lightMap.isTexture && (n.lightMap = this.lightMap.toJSON(e).uuid, n.lightMapIntensity = this.lightMapIntensity), this.aoMap && this.aoMap.isTexture && (n.aoMap = this.aoMap.toJSON(e).uuid, n.aoMapIntensity = this.aoMapIntensity), this.bumpMap && this.bumpMap.isTexture && (n.bumpMap = this.bumpMap.toJSON(e).uuid, n.bumpScale = this.bumpScale), this.normalMap && this.normalMap.isTexture && (n.normalMap = this.normalMap.toJSON(e).uuid, n.normalMapType = this.normalMapType, n.normalScale = this.normalScale.toArray()), this.displacementMap && this.displacementMap.isTexture && (n.displacementMap = this.displacementMap.toJSON(e).uuid, n.displacementScale = this.displacementScale, n.displacementBias = this.displacementBias), this.roughnessMap && this.roughnessMap.isTexture && (n.roughnessMap = this.roughnessMap.toJSON(e).uuid), this.metalnessMap && this.metalnessMap.isTexture && (n.metalnessMap = this.metalnessMap.toJSON(e).uuid), this.emissiveMap && this.emissiveMap.isTexture && (n.emissiveMap = this.emissiveMap.toJSON(e).uuid), this.specularMap && this.specularMap.isTexture && (n.specularMap = this.specularMap.toJSON(e).uuid), this.specularIntensityMap && this.specularIntensityMap.isTexture && (n.specularIntensityMap = this.specularIntensityMap.toJSON(e).uuid), this.specularColorMap && this.specularColorMap.isTexture && (n.specularColorMap = this.specularColorMap.toJSON(e).uuid), this.envMap && this.envMap.isTexture && (n.envMap = this.envMap.toJSON(e).uuid, this.combine !== void 0 && (n.combine = this.combine)), this.envMapIntensity !== void 0 && (n.envMapIntensity = this.envMapIntensity), this.reflectivity !== void 0 && (n.reflectivity = this.reflectivity), this.refractionRatio !== void 0 && (n.refractionRatio = this.refractionRatio), this.gradientMap && this.gradientMap.isTexture && (n.gradientMap = this.gradientMap.toJSON(e).uuid), this.transmission !== void 0 && (n.transmission = this.transmission), this.transmissionMap && this.transmissionMap.isTexture && (n.transmissionMap = this.transmissionMap.toJSON(e).uuid), this.thickness !== void 0 && (n.thickness = this.thickness), this.thicknessMap && this.thicknessMap.isTexture && (n.thicknessMap = this.thicknessMap.toJSON(e).uuid), this.attenuationDistance !== void 0 && (n.attenuationDistance = this.attenuationDistance), this.attenuationColor !== void 0 && (n.attenuationColor = this.attenuationColor.getHex()), this.size !== void 0 && (n.size = this.size), this.shadowSide !== null && (n.shadowSide = this.shadowSide), this.sizeAttenuation !== void 0 && (n.sizeAttenuation = this.sizeAttenuation), this.blending !== sr && (n.blending = this.blending), this.side !== Ai && (n.side = this.side), this.vertexColors && (n.vertexColors = !0), this.opacity < 1 && (n.opacity = this.opacity), this.format !== ct && (n.format = this.format), this.transparent === !0 && (n.transparent = this.transparent), n.depthFunc = this.depthFunc, n.depthTest = this.depthTest, n.depthWrite = this.depthWrite, n.colorWrite = this.colorWrite, n.stencilWrite = this.stencilWrite, n.stencilWriteMask = this.stencilWriteMask, n.stencilFunc = this.stencilFunc, n.stencilRef = this.stencilRef, n.stencilFuncMask = this.stencilFuncMask, n.stencilFail = this.stencilFail, n.stencilZFail = this.stencilZFail, n.stencilZPass = this.stencilZPass, this.rotation && this.rotation !== 0 && (n.rotation = this.rotation), this.polygonOffset === !0 && (n.polygonOffset = !0), this.polygonOffsetFactor !== 0 && (n.polygonOffsetFactor = this.polygonOffsetFactor), this.polygonOffsetUnits !== 0 && (n.polygonOffsetUnits = this.polygonOffsetUnits), this.linewidth && this.linewidth !== 1 && (n.linewidth = this.linewidth), this.dashSize !== void 0 && (n.dashSize = this.dashSize), this.gapSize !== void 0 && (n.gapSize = this.gapSize), this.scale !== void 0 && (n.scale = this.scale), this.dithering === !0 && (n.dithering = !0), this.alphaTest > 0 && (n.alphaTest = this.alphaTest), this.alphaToCoverage === !0 && (n.alphaToCoverage = this.alphaToCoverage), this.premultipliedAlpha === !0 && (n.premultipliedAlpha = this.premultipliedAlpha), this.wireframe === !0 && (n.wireframe = this.wireframe), this.wireframeLinewidth > 1 && (n.wireframeLinewidth = this.wireframeLinewidth), this.wireframeLinecap !== "round" && (n.wireframeLinecap = this.wireframeLinecap), this.wireframeLinejoin !== "round" && (n.wireframeLinejoin = this.wireframeLinejoin), this.flatShading === !0 && (n.flatShading = this.flatShading), this.visible === !1 && (n.visible = !1), this.toneMapped === !1 && (n.toneMapped = !1), JSON.stringify(this.userData) !== "{}" && (n.userData = this.userData); + n.uuid = this.uuid, n.type = this.type, this.name !== "" && (n.name = this.name), this.color && this.color.isColor && (n.color = this.color.getHex()), this.roughness !== void 0 && (n.roughness = this.roughness), this.metalness !== void 0 && (n.metalness = this.metalness), this.sheen !== void 0 && (n.sheen = this.sheen), this.sheenColor && this.sheenColor.isColor && (n.sheenColor = this.sheenColor.getHex()), this.sheenRoughness !== void 0 && (n.sheenRoughness = this.sheenRoughness), this.emissive && this.emissive.isColor && (n.emissive = this.emissive.getHex()), this.emissiveIntensity && this.emissiveIntensity !== 1 && (n.emissiveIntensity = this.emissiveIntensity), this.specular && this.specular.isColor && (n.specular = this.specular.getHex()), this.specularIntensity !== void 0 && (n.specularIntensity = this.specularIntensity), this.specularColor && this.specularColor.isColor && (n.specularColor = this.specularColor.getHex()), this.shininess !== void 0 && (n.shininess = this.shininess), this.clearcoat !== void 0 && (n.clearcoat = this.clearcoat), this.clearcoatRoughness !== void 0 && (n.clearcoatRoughness = this.clearcoatRoughness), this.clearcoatMap && this.clearcoatMap.isTexture && (n.clearcoatMap = this.clearcoatMap.toJSON(e).uuid), this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture && (n.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON(e).uuid), this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture && (n.clearcoatNormalMap = this.clearcoatNormalMap.toJSON(e).uuid, n.clearcoatNormalScale = this.clearcoatNormalScale.toArray()), this.iridescence !== void 0 && (n.iridescence = this.iridescence), this.iridescenceIOR !== void 0 && (n.iridescenceIOR = this.iridescenceIOR), this.iridescenceThicknessRange !== void 0 && (n.iridescenceThicknessRange = this.iridescenceThicknessRange), this.iridescenceMap && this.iridescenceMap.isTexture && (n.iridescenceMap = this.iridescenceMap.toJSON(e).uuid), this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture && (n.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON(e).uuid), this.anisotropy !== void 0 && (n.anisotropy = this.anisotropy), this.anisotropyRotation !== void 0 && (n.anisotropyRotation = this.anisotropyRotation), this.anisotropyMap && this.anisotropyMap.isTexture && (n.anisotropyMap = this.anisotropyMap.toJSON(e).uuid), this.map && this.map.isTexture && (n.map = this.map.toJSON(e).uuid), this.matcap && this.matcap.isTexture && (n.matcap = this.matcap.toJSON(e).uuid), this.alphaMap && this.alphaMap.isTexture && (n.alphaMap = this.alphaMap.toJSON(e).uuid), this.lightMap && this.lightMap.isTexture && (n.lightMap = this.lightMap.toJSON(e).uuid, n.lightMapIntensity = this.lightMapIntensity), this.aoMap && this.aoMap.isTexture && (n.aoMap = this.aoMap.toJSON(e).uuid, n.aoMapIntensity = this.aoMapIntensity), this.bumpMap && this.bumpMap.isTexture && (n.bumpMap = this.bumpMap.toJSON(e).uuid, n.bumpScale = this.bumpScale), this.normalMap && this.normalMap.isTexture && (n.normalMap = this.normalMap.toJSON(e).uuid, n.normalMapType = this.normalMapType, n.normalScale = this.normalScale.toArray()), this.displacementMap && this.displacementMap.isTexture && (n.displacementMap = this.displacementMap.toJSON(e).uuid, n.displacementScale = this.displacementScale, n.displacementBias = this.displacementBias), this.roughnessMap && this.roughnessMap.isTexture && (n.roughnessMap = this.roughnessMap.toJSON(e).uuid), this.metalnessMap && this.metalnessMap.isTexture && (n.metalnessMap = this.metalnessMap.toJSON(e).uuid), this.emissiveMap && this.emissiveMap.isTexture && (n.emissiveMap = this.emissiveMap.toJSON(e).uuid), this.specularMap && this.specularMap.isTexture && (n.specularMap = this.specularMap.toJSON(e).uuid), this.specularIntensityMap && this.specularIntensityMap.isTexture && (n.specularIntensityMap = this.specularIntensityMap.toJSON(e).uuid), this.specularColorMap && this.specularColorMap.isTexture && (n.specularColorMap = this.specularColorMap.toJSON(e).uuid), this.envMap && this.envMap.isTexture && (n.envMap = this.envMap.toJSON(e).uuid, this.combine !== void 0 && (n.combine = this.combine)), this.envMapIntensity !== void 0 && (n.envMapIntensity = this.envMapIntensity), this.reflectivity !== void 0 && (n.reflectivity = this.reflectivity), this.refractionRatio !== void 0 && (n.refractionRatio = this.refractionRatio), this.gradientMap && this.gradientMap.isTexture && (n.gradientMap = this.gradientMap.toJSON(e).uuid), this.transmission !== void 0 && (n.transmission = this.transmission), this.transmissionMap && this.transmissionMap.isTexture && (n.transmissionMap = this.transmissionMap.toJSON(e).uuid), this.thickness !== void 0 && (n.thickness = this.thickness), this.thicknessMap && this.thicknessMap.isTexture && (n.thicknessMap = this.thicknessMap.toJSON(e).uuid), this.attenuationDistance !== void 0 && this.attenuationDistance !== 1 / 0 && (n.attenuationDistance = this.attenuationDistance), this.attenuationColor !== void 0 && (n.attenuationColor = this.attenuationColor.getHex()), this.size !== void 0 && (n.size = this.size), this.shadowSide !== null && (n.shadowSide = this.shadowSide), this.sizeAttenuation !== void 0 && (n.sizeAttenuation = this.sizeAttenuation), this.blending !== Wi && (n.blending = this.blending), this.side !== Bn && (n.side = this.side), this.vertexColors === !0 && (n.vertexColors = !0), this.opacity < 1 && (n.opacity = this.opacity), this.transparent === !0 && (n.transparent = !0), n.depthFunc = this.depthFunc, n.depthTest = this.depthTest, n.depthWrite = this.depthWrite, n.colorWrite = this.colorWrite, n.stencilWrite = this.stencilWrite, n.stencilWriteMask = this.stencilWriteMask, n.stencilFunc = this.stencilFunc, n.stencilRef = this.stencilRef, n.stencilFuncMask = this.stencilFuncMask, n.stencilFail = this.stencilFail, n.stencilZFail = this.stencilZFail, n.stencilZPass = this.stencilZPass, this.rotation !== void 0 && this.rotation !== 0 && (n.rotation = this.rotation), this.polygonOffset === !0 && (n.polygonOffset = !0), this.polygonOffsetFactor !== 0 && (n.polygonOffsetFactor = this.polygonOffsetFactor), this.polygonOffsetUnits !== 0 && (n.polygonOffsetUnits = this.polygonOffsetUnits), this.linewidth !== void 0 && this.linewidth !== 1 && (n.linewidth = this.linewidth), this.dashSize !== void 0 && (n.dashSize = this.dashSize), this.gapSize !== void 0 && (n.gapSize = this.gapSize), this.scale !== void 0 && (n.scale = this.scale), this.dithering === !0 && (n.dithering = !0), this.alphaTest > 0 && (n.alphaTest = this.alphaTest), this.alphaHash === !0 && (n.alphaHash = !0), this.alphaToCoverage === !0 && (n.alphaToCoverage = !0), this.premultipliedAlpha === !0 && (n.premultipliedAlpha = !0), this.forceSinglePass === !0 && (n.forceSinglePass = !0), this.wireframe === !0 && (n.wireframe = !0), this.wireframeLinewidth > 1 && (n.wireframeLinewidth = this.wireframeLinewidth), this.wireframeLinecap !== "round" && (n.wireframeLinecap = this.wireframeLinecap), this.wireframeLinejoin !== "round" && (n.wireframeLinejoin = this.wireframeLinejoin), this.flatShading === !0 && (n.flatShading = !0), this.visible === !1 && (n.visible = !1), this.toneMapped === !1 && (n.toneMapped = !1), this.fog === !1 && (n.fog = !1), Object.keys(this.userData).length > 0 && (n.userData = this.userData); function i(r) { - let o = []; - for(let a in r){ - let l = r[a]; - delete l.metadata, o.push(l); + let a = []; + for(let o in r){ + let c = r[o]; + delete c.metadata, a.push(c); } - return o; + return a; } if (t) { - let r = i(e.textures), o = i(e.images); - r.length > 0 && (n.textures = r), o.length > 0 && (n.images = o); + let r = i(e.textures), a = i(e.images); + r.length > 0 && (n.textures = r), a.length > 0 && (n.images = a); } return n; } @@ -2408,14 +2859,14 @@ var Dt = new M, Kt = new M, Co = new M, en = new M, ai = new M, li = new M, Al = return new this.constructor().copy(this); } copy(e) { - this.name = e.name, this.fog = e.fog, this.blending = e.blending, this.side = e.side, this.vertexColors = e.vertexColors, this.opacity = e.opacity, this.format = e.format, this.transparent = e.transparent, this.blendSrc = e.blendSrc, this.blendDst = e.blendDst, this.blendEquation = e.blendEquation, this.blendSrcAlpha = e.blendSrcAlpha, this.blendDstAlpha = e.blendDstAlpha, this.blendEquationAlpha = e.blendEquationAlpha, this.depthFunc = e.depthFunc, this.depthTest = e.depthTest, this.depthWrite = e.depthWrite, this.stencilWriteMask = e.stencilWriteMask, this.stencilFunc = e.stencilFunc, this.stencilRef = e.stencilRef, this.stencilFuncMask = e.stencilFuncMask, this.stencilFail = e.stencilFail, this.stencilZFail = e.stencilZFail, this.stencilZPass = e.stencilZPass, this.stencilWrite = e.stencilWrite; + this.name = e.name, this.blending = e.blending, this.side = e.side, this.vertexColors = e.vertexColors, this.opacity = e.opacity, this.transparent = e.transparent, this.blendSrc = e.blendSrc, this.blendDst = e.blendDst, this.blendEquation = e.blendEquation, this.blendSrcAlpha = e.blendSrcAlpha, this.blendDstAlpha = e.blendDstAlpha, this.blendEquationAlpha = e.blendEquationAlpha, this.depthFunc = e.depthFunc, this.depthTest = e.depthTest, this.depthWrite = e.depthWrite, this.stencilWriteMask = e.stencilWriteMask, this.stencilFunc = e.stencilFunc, this.stencilRef = e.stencilRef, this.stencilFuncMask = e.stencilFuncMask, this.stencilFail = e.stencilFail, this.stencilZFail = e.stencilZFail, this.stencilZPass = e.stencilZPass, this.stencilWrite = e.stencilWrite; let t = e.clippingPlanes, n = null; if (t !== null) { let i = t.length; n = new Array(i); for(let r = 0; r !== i; ++r)n[r] = t[r].clone(); } - return this.clippingPlanes = n, this.clipIntersection = e.clipIntersection, this.clipShadows = e.clipShadows, this.shadowSide = e.shadowSide, this.colorWrite = e.colorWrite, this.precision = e.precision, this.polygonOffset = e.polygonOffset, this.polygonOffsetFactor = e.polygonOffsetFactor, this.polygonOffsetUnits = e.polygonOffsetUnits, this.dithering = e.dithering, this.alphaTest = e.alphaTest, this.alphaToCoverage = e.alphaToCoverage, this.premultipliedAlpha = e.premultipliedAlpha, this.visible = e.visible, this.toneMapped = e.toneMapped, this.userData = JSON.parse(JSON.stringify(e.userData)), this; + return this.clippingPlanes = n, this.clipIntersection = e.clipIntersection, this.clipShadows = e.clipShadows, this.shadowSide = e.shadowSide, this.colorWrite = e.colorWrite, this.precision = e.precision, this.polygonOffset = e.polygonOffset, this.polygonOffsetFactor = e.polygonOffsetFactor, this.polygonOffsetUnits = e.polygonOffsetUnits, this.dithering = e.dithering, this.alphaTest = e.alphaTest, this.alphaHash = e.alphaHash, this.alphaToCoverage = e.alphaToCoverage, this.premultipliedAlpha = e.premultipliedAlpha, this.forceSinglePass = e.forceSinglePass, this.visible = e.visible, this.toneMapped = e.toneMapped, this.userData = JSON.parse(JSON.stringify(e.userData)), this; } dispose() { this.dispatchEvent({ @@ -2425,9 +2876,7 @@ var Dt = new M, Kt = new M, Co = new M, en = new M, ai = new M, li = new M, Al = set needsUpdate(e) { e === !0 && this.version++; } -}; -dt.prototype.isMaterial = !0; -var $c = { +}, Sd = { aliceblue: 15792383, antiquewhite: 16444375, aqua: 65535, @@ -2576,79 +3025,77 @@ var $c = { whitesmoke: 16119285, yellow: 16776960, yellowgreen: 10145074 -}, Ft = { +}, Cn = { h: 0, s: 0, l: 0 -}, jr = { +}, Ks = { h: 0, s: 0, l: 0 }; -function Io(s, e, t) { - return t < 0 && (t += 1), t > 1 && (t -= 1), t < 1 / 6 ? s + (e - s) * 6 * t : t < 1 / 2 ? e : t < 2 / 3 ? s + (e - s) * 6 * (2 / 3 - t) : s; -} -function Do(s) { - return s < .04045 ? s * .0773993808 : Math.pow(s * .9478672986 + .0521327014, 2.4); +function qa(s1, e, t) { + return t < 0 && (t += 1), t > 1 && (t -= 1), t < 1 / 6 ? s1 + (e - s1) * 6 * t : t < 1 / 2 ? e : t < 2 / 3 ? s1 + (e - s1) * 6 * (2 / 3 - t) : s1; } -function Fo(s) { - return s < .0031308 ? s * 12.92 : 1.055 * Math.pow(s, .41666) - .055; -} -var ae = class { +var pe = class { constructor(e, t, n){ - return t === void 0 && n === void 0 ? this.set(e) : this.setRGB(e, t, n); + return this.isColor = !0, this.r = 1, this.g = 1, this.b = 1, this.set(e, t, n); } - set(e) { - return e && e.isColor ? this.copy(e) : typeof e == "number" ? this.setHex(e) : typeof e == "string" && this.setStyle(e), this; + set(e, t, n) { + if (t === void 0 && n === void 0) { + let i = e; + i && i.isColor ? this.copy(i) : typeof i == "number" ? this.setHex(i) : typeof i == "string" && this.setStyle(i); + } else this.setRGB(e, t, n); + return this; } setScalar(e) { return this.r = e, this.g = e, this.b = e, this; } - setHex(e) { - return e = Math.floor(e), this.r = (e >> 16 & 255) / 255, this.g = (e >> 8 & 255) / 255, this.b = (e & 255) / 255, this; + setHex(e, t = vt) { + return e = Math.floor(e), this.r = (e >> 16 & 255) / 255, this.g = (e >> 8 & 255) / 255, this.b = (e & 255) / 255, Qe.toWorkingColorSpace(this, t), this; } - setRGB(e, t, n) { - return this.r = e, this.g = t, this.b = n, this; + setRGB(e, t, n, i = Qe.workingColorSpace) { + return this.r = e, this.g = t, this.b = n, Qe.toWorkingColorSpace(this, i), this; } - setHSL(e, t, n) { - if (e = da(e, 1), t = mt(t, 0, 1), n = mt(n, 0, 1), t === 0) this.r = this.g = this.b = n; + setHSL(e, t, n, i = Qe.workingColorSpace) { + if (e = Yc(e, 1), t = ct(t, 0, 1), n = ct(n, 0, 1), t === 0) this.r = this.g = this.b = n; else { - let i = n <= .5 ? n * (1 + t) : n + t - n * t, r = 2 * n - i; - this.r = Io(r, i, e + 1 / 3), this.g = Io(r, i, e), this.b = Io(r, i, e - 1 / 3); + let r = n <= .5 ? n * (1 + t) : n + t - n * t, a = 2 * n - r; + this.r = qa(a, r, e + 1 / 3), this.g = qa(a, r, e), this.b = qa(a, r, e - 1 / 3); } - return this; + return Qe.toWorkingColorSpace(this, i), this; } - setStyle(e) { - function t(i) { - i !== void 0 && parseFloat(i) < 1 && console.warn("THREE.Color: Alpha component of " + e + " will be ignored."); + setStyle(e, t = vt) { + function n(r) { + r !== void 0 && parseFloat(r) < 1 && console.warn("THREE.Color: Alpha component of " + e + " will be ignored."); } - let n; - if (n = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec(e)) { - let i, r = n[1], o = n[2]; - switch(r){ + let i; + if (i = /^(\w+)\(([^\)]*)\)/.exec(e)) { + let r, a = i[1], o = i[2]; + switch(a){ case "rgb": case "rgba": - if (i = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o)) return this.r = Math.min(255, parseInt(i[1], 10)) / 255, this.g = Math.min(255, parseInt(i[2], 10)) / 255, this.b = Math.min(255, parseInt(i[3], 10)) / 255, t(i[4]), this; - if (i = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o)) return this.r = Math.min(100, parseInt(i[1], 10)) / 100, this.g = Math.min(100, parseInt(i[2], 10)) / 100, this.b = Math.min(100, parseInt(i[3], 10)) / 100, t(i[4]), this; + if (r = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o)) return n(r[4]), this.setRGB(Math.min(255, parseInt(r[1], 10)) / 255, Math.min(255, parseInt(r[2], 10)) / 255, Math.min(255, parseInt(r[3], 10)) / 255, t); + if (r = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o)) return n(r[4]), this.setRGB(Math.min(100, parseInt(r[1], 10)) / 100, Math.min(100, parseInt(r[2], 10)) / 100, Math.min(100, parseInt(r[3], 10)) / 100, t); break; case "hsl": case "hsla": - if (i = /^\s*(\d*\.?\d+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o)) { - let a = parseFloat(i[1]) / 360, l = parseInt(i[2], 10) / 100, c = parseInt(i[3], 10) / 100; - return t(i[4]), this.setHSL(a, l, c); - } + if (r = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o)) return n(r[4]), this.setHSL(parseFloat(r[1]) / 360, parseFloat(r[2]) / 100, parseFloat(r[3]) / 100, t); break; + default: + console.warn("THREE.Color: Unknown color model " + e); } - } else if (n = /^\#([A-Fa-f\d]+)$/.exec(e)) { - let i = n[1], r = i.length; - if (r === 3) return this.r = parseInt(i.charAt(0) + i.charAt(0), 16) / 255, this.g = parseInt(i.charAt(1) + i.charAt(1), 16) / 255, this.b = parseInt(i.charAt(2) + i.charAt(2), 16) / 255, this; - if (r === 6) return this.r = parseInt(i.charAt(0) + i.charAt(1), 16) / 255, this.g = parseInt(i.charAt(2) + i.charAt(3), 16) / 255, this.b = parseInt(i.charAt(4) + i.charAt(5), 16) / 255, this; - } - return e && e.length > 0 ? this.setColorName(e) : this; + } else if (i = /^\#([A-Fa-f\d]+)$/.exec(e)) { + let r = i[1], a = r.length; + if (a === 3) return this.setRGB(parseInt(r.charAt(0), 16) / 15, parseInt(r.charAt(1), 16) / 15, parseInt(r.charAt(2), 16) / 15, t); + if (a === 6) return this.setHex(parseInt(r, 16), t); + console.warn("THREE.Color: Invalid hex color " + e); + } else if (e && e.length > 0) return this.setColorName(e, t); + return this; } - setColorName(e) { - let t = $c[e.toLowerCase()]; - return t !== void 0 ? this.setHex(t) : console.warn("THREE.Color: Unknown color " + e), this; + setColorName(e, t = vt) { + let n = Sd[e.toLowerCase()]; + return n !== void 0 ? this.setHex(n, t) : console.warn("THREE.Color: Unknown color " + e), this; } clone() { return new this.constructor(this.r, this.g, this.b); @@ -2657,10 +3104,10 @@ var ae = class { return this.r = e.r, this.g = e.g, this.b = e.b, this; } copySRGBToLinear(e) { - return this.r = Do(e.r), this.g = Do(e.g), this.b = Do(e.b), this; + return this.r = Xi(e.r), this.g = Xi(e.g), this.b = Xi(e.b), this; } copyLinearToSRGB(e) { - return this.r = Fo(e.r), this.g = Fo(e.g), this.b = Fo(e.b), this; + return this.r = Da(e.r), this.g = Da(e.g), this.b = Da(e.b), this; } convertSRGBToLinear() { return this.copySRGBToLinear(this), this; @@ -2668,37 +3115,43 @@ var ae = class { convertLinearToSRGB() { return this.copyLinearToSRGB(this), this; } - getHex() { - return this.r * 255 << 16 ^ this.g * 255 << 8 ^ this.b * 255 << 0; + getHex(e = vt) { + return Qe.fromWorkingColorSpace(Tt.copy(this), e), Math.round(ct(Tt.r * 255, 0, 255)) * 65536 + Math.round(ct(Tt.g * 255, 0, 255)) * 256 + Math.round(ct(Tt.b * 255, 0, 255)); } - getHexString() { - return ("000000" + this.getHex().toString(16)).slice(-6); + getHexString(e = vt) { + return ("000000" + this.getHex(e).toString(16)).slice(-6); } - getHSL(e) { - let t = this.r, n = this.g, i = this.b, r = Math.max(t, n, i), o = Math.min(t, n, i), a, l, c = (o + r) / 2; - if (o === r) a = 0, l = 0; + getHSL(e, t = Qe.workingColorSpace) { + Qe.fromWorkingColorSpace(Tt.copy(this), t); + let n = Tt.r, i = Tt.g, r = Tt.b, a = Math.max(n, i, r), o = Math.min(n, i, r), c, l, h = (o + a) / 2; + if (o === a) c = 0, l = 0; else { - let h = r - o; - switch(l = c <= .5 ? h / (r + o) : h / (2 - r - o), r){ - case t: - a = (n - i) / h + (n < i ? 6 : 0); - break; + let u = a - o; + switch(l = h <= .5 ? u / (a + o) : u / (2 - a - o), a){ case n: - a = (i - t) / h + 2; + c = (i - r) / u + (i < r ? 6 : 0); break; case i: - a = (t - n) / h + 4; + c = (r - n) / u + 2; + break; + case r: + c = (n - i) / u + 4; break; } - a /= 6; + c /= 6; } - return e.h = a, e.s = l, e.l = c, e; + return e.h = c, e.s = l, e.l = h, e; } - getStyle() { - return "rgb(" + (this.r * 255 | 0) + "," + (this.g * 255 | 0) + "," + (this.b * 255 | 0) + ")"; + getRGB(e, t = Qe.workingColorSpace) { + return Qe.fromWorkingColorSpace(Tt.copy(this), t), e.r = Tt.r, e.g = Tt.g, e.b = Tt.b, e; + } + getStyle(e = vt) { + Qe.fromWorkingColorSpace(Tt.copy(this), e); + let t = Tt.r, n = Tt.g, i = Tt.b; + return e !== vt ? `color(${e} ${t.toFixed(3)} ${n.toFixed(3)} ${i.toFixed(3)})` : `rgb(${Math.round(t * 255)},${Math.round(n * 255)},${Math.round(i * 255)})`; } offsetHSL(e, t, n) { - return this.getHSL(Ft), Ft.h += e, Ft.s += t, Ft.l += n, this.setHSL(Ft.h, Ft.s, Ft.l), this; + return this.getHSL(Cn), this.setHSL(Cn.h + e, Cn.s + t, Cn.l + n); } add(e) { return this.r += e.r, this.g += e.g, this.b += e.b, this; @@ -2725,10 +3178,17 @@ var ae = class { return this.r = e.r + (t.r - e.r) * n, this.g = e.g + (t.g - e.g) * n, this.b = e.b + (t.b - e.b) * n, this; } lerpHSL(e, t) { - this.getHSL(Ft), e.getHSL(jr); - let n = or(Ft.h, jr.h, t), i = or(Ft.s, jr.s, t), r = or(Ft.l, jr.l, t); + this.getHSL(Cn), e.getHSL(Ks); + let n = ys(Cn.h, Ks.h, t), i = ys(Cn.s, Ks.s, t), r = ys(Cn.l, Ks.l, t); return this.setHSL(n, i, r), this; } + setFromVector3(e) { + return this.r = e.x, this.g = e.y, this.b = e.z, this; + } + applyMatrix3(e) { + let t = this.r, n = this.g, i = this.b, r = e.elements; + return this.r = r[0] * t + r[3] * n + r[6] * i, this.g = r[1] * t + r[4] * n + r[7] * i, this.b = r[2] * t + r[5] * n + r[8] * i, this; + } equals(e) { return e.r === this.r && e.g === this.g && e.b === this.b; } @@ -2739,34 +3199,71 @@ var ae = class { return e[t] = this.r, e[t + 1] = this.g, e[t + 2] = this.b, e; } fromBufferAttribute(e, t) { - return this.r = e.getX(t), this.g = e.getY(t), this.b = e.getZ(t), e.normalized === !0 && (this.r /= 255, this.g /= 255, this.b /= 255), this; + return this.r = e.getX(t), this.g = e.getY(t), this.b = e.getZ(t), this; } toJSON() { return this.getHex(); } -}; -ae.NAMES = $c; -ae.prototype.isColor = !0; -ae.prototype.r = 1; -ae.prototype.g = 1; -ae.prototype.b = 1; -var hn = class extends dt { + *[Symbol.iterator]() { + yield this.r, yield this.g, yield this.b; + } +}, Tt = new pe; +pe.NAMES = Sd; +var Sn = class extends bt { constructor(e){ - super(); - this.type = "MeshBasicMaterial", this.color = new ae(16777215), this.map = null, this.lightMap = null, this.lightMapIntensity = 1, this.aoMap = null, this.aoMapIntensity = 1, this.specularMap = null, this.alphaMap = null, this.envMap = null, this.combine = Vs, this.reflectivity = 1, this.refractionRatio = .98, this.wireframe = !1, this.wireframeLinewidth = 1, this.wireframeLinecap = "round", this.wireframeLinejoin = "round", this.setValues(e); + super(), this.isMeshBasicMaterial = !0, this.type = "MeshBasicMaterial", this.color = new pe(16777215), this.map = null, this.lightMap = null, this.lightMapIntensity = 1, this.aoMap = null, this.aoMapIntensity = 1, this.specularMap = null, this.alphaMap = null, this.envMap = null, this.combine = xa, this.reflectivity = 1, this.refractionRatio = .98, this.wireframe = !1, this.wireframeLinewidth = 1, this.wireframeLinecap = "round", this.wireframeLinejoin = "round", this.fog = !0, this.setValues(e); } copy(e) { - return super.copy(e), this.color.copy(e.color), this.map = e.map, this.lightMap = e.lightMap, this.lightMapIntensity = e.lightMapIntensity, this.aoMap = e.aoMap, this.aoMapIntensity = e.aoMapIntensity, this.specularMap = e.specularMap, this.alphaMap = e.alphaMap, this.envMap = e.envMap, this.combine = e.combine, this.reflectivity = e.reflectivity, this.refractionRatio = e.refractionRatio, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.wireframeLinecap = e.wireframeLinecap, this.wireframeLinejoin = e.wireframeLinejoin, this; - } -}; -hn.prototype.isMeshBasicMaterial = !0; -var Je = new M, Qr = new X, Ue = class { - constructor(e, t, n){ + return super.copy(e), this.color.copy(e.color), this.map = e.map, this.lightMap = e.lightMap, this.lightMapIntensity = e.lightMapIntensity, this.aoMap = e.aoMap, this.aoMapIntensity = e.aoMapIntensity, this.specularMap = e.specularMap, this.alphaMap = e.alphaMap, this.envMap = e.envMap, this.combine = e.combine, this.reflectivity = e.reflectivity, this.refractionRatio = e.refractionRatio, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.wireframeLinecap = e.wireframeLinecap, this.wireframeLinejoin = e.wireframeLinejoin, this.fog = e.fog, this; + } +}, _n = pp(); +function pp() { + let s1 = new ArrayBuffer(4), e = new Float32Array(s1), t = new Uint32Array(s1), n = new Uint32Array(512), i = new Uint32Array(512); + for(let c = 0; c < 256; ++c){ + let l = c - 127; + l < -27 ? (n[c] = 0, n[c | 256] = 32768, i[c] = 24, i[c | 256] = 24) : l < -14 ? (n[c] = 1024 >> -l - 14, n[c | 256] = 1024 >> -l - 14 | 32768, i[c] = -l - 1, i[c | 256] = -l - 1) : l <= 15 ? (n[c] = l + 15 << 10, n[c | 256] = l + 15 << 10 | 32768, i[c] = 13, i[c | 256] = 13) : l < 128 ? (n[c] = 31744, n[c | 256] = 64512, i[c] = 24, i[c | 256] = 24) : (n[c] = 31744, n[c | 256] = 64512, i[c] = 13, i[c | 256] = 13); + } + let r = new Uint32Array(2048), a = new Uint32Array(64), o = new Uint32Array(64); + for(let c = 1; c < 1024; ++c){ + let l = c << 13, h = 0; + for(; !(l & 8388608);)l <<= 1, h -= 8388608; + l &= -8388609, h += 947912704, r[c] = l | h; + } + for(let c = 1024; c < 2048; ++c)r[c] = 939524096 + (c - 1024 << 13); + for(let c = 1; c < 31; ++c)a[c] = c << 23; + a[31] = 1199570944, a[32] = 2147483648; + for(let c = 33; c < 63; ++c)a[c] = 2147483648 + (c - 32 << 23); + a[63] = 3347054592; + for(let c = 1; c < 64; ++c)c !== 32 && (o[c] = 1024); + return { + floatView: e, + uint32View: t, + baseTable: n, + shiftTable: i, + mantissaTable: r, + exponentTable: a, + offsetTable: o + }; +} +function Nt(s1) { + Math.abs(s1) > 65504 && console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."), s1 = ct(s1, -65504, 65504), _n.floatView[0] = s1; + let e = _n.uint32View[0], t = e >> 23 & 511; + return _n.baseTable[t] + ((e & 8388607) >> _n.shiftTable[t]); +} +function xs(s1) { + let e = s1 >> 10; + return _n.uint32View[0] = _n.mantissaTable[_n.offsetTable[e] + (s1 & 1023)] + _n.exponentTable[e], _n.floatView[0]; +} +var Mv = { + toHalfFloat: Nt, + fromHalfFloat: xs +}, ft = new A, Qs = new Z, et = class { + constructor(e, t, n = !1){ if (Array.isArray(e)) throw new TypeError("THREE.BufferAttribute: array should be a Typed Array."); - this.name = "", this.array = e, this.itemSize = t, this.count = e !== void 0 ? e.length / t : 0, this.normalized = n === !0, this.usage = hr, this.updateRange = { + this.isBufferAttribute = !0, this.name = "", this.array = e, this.itemSize = t, this.count = e !== void 0 ? e.length / t : 0, this.normalized = n, this.usage = Hr, this.updateRange = { offset: 0, count: -1 - }, this.version = 0; + }, this.gpuType = xn, this.version = 0; } onUploadCallback() {} set needsUpdate(e) { @@ -2776,7 +3273,7 @@ var Je = new M, Qr = new X, Ue = class { return this.usage = e, this; } copy(e) { - return this.name = e.name, this.array = new e.array.constructor(e.array), this.itemSize = e.itemSize, this.count = e.count, this.normalized = e.normalized, this.usage = e.usage, this; + return this.name = e.name, this.array = new e.array.constructor(e.array), this.itemSize = e.itemSize, this.count = e.count, this.normalized = e.normalized, this.usage = e.usage, this.gpuType = e.gpuType, this; } copyAt(e, t, n) { e *= this.itemSize, n *= t.itemSize; @@ -2786,90 +3283,69 @@ var Je = new M, Qr = new X, Ue = class { copyArray(e) { return this.array.set(e), this; } - copyColorsArray(e) { - let t = this.array, n = 0; - for(let i = 0, r = e.length; i < r; i++){ - let o = e[i]; - o === void 0 && (console.warn("THREE.BufferAttribute.copyColorsArray(): color is undefined", i), o = new ae), t[n++] = o.r, t[n++] = o.g, t[n++] = o.b; - } - return this; - } - copyVector2sArray(e) { - let t = this.array, n = 0; - for(let i = 0, r = e.length; i < r; i++){ - let o = e[i]; - o === void 0 && (console.warn("THREE.BufferAttribute.copyVector2sArray(): vector is undefined", i), o = new X), t[n++] = o.x, t[n++] = o.y; - } - return this; - } - copyVector3sArray(e) { - let t = this.array, n = 0; - for(let i = 0, r = e.length; i < r; i++){ - let o = e[i]; - o === void 0 && (console.warn("THREE.BufferAttribute.copyVector3sArray(): vector is undefined", i), o = new M), t[n++] = o.x, t[n++] = o.y, t[n++] = o.z; - } - return this; - } - copyVector4sArray(e) { - let t = this.array, n = 0; - for(let i = 0, r = e.length; i < r; i++){ - let o = e[i]; - o === void 0 && (console.warn("THREE.BufferAttribute.copyVector4sArray(): vector is undefined", i), o = new Ve), t[n++] = o.x, t[n++] = o.y, t[n++] = o.z, t[n++] = o.w; - } - return this; - } applyMatrix3(e) { - if (this.itemSize === 2) for(let t = 0, n = this.count; t < n; t++)Qr.fromBufferAttribute(this, t), Qr.applyMatrix3(e), this.setXY(t, Qr.x, Qr.y); - else if (this.itemSize === 3) for(let t = 0, n = this.count; t < n; t++)Je.fromBufferAttribute(this, t), Je.applyMatrix3(e), this.setXYZ(t, Je.x, Je.y, Je.z); + if (this.itemSize === 2) for(let t = 0, n = this.count; t < n; t++)Qs.fromBufferAttribute(this, t), Qs.applyMatrix3(e), this.setXY(t, Qs.x, Qs.y); + else if (this.itemSize === 3) for(let t = 0, n = this.count; t < n; t++)ft.fromBufferAttribute(this, t), ft.applyMatrix3(e), this.setXYZ(t, ft.x, ft.y, ft.z); return this; } applyMatrix4(e) { - for(let t = 0, n = this.count; t < n; t++)Je.x = this.getX(t), Je.y = this.getY(t), Je.z = this.getZ(t), Je.applyMatrix4(e), this.setXYZ(t, Je.x, Je.y, Je.z); + for(let t = 0, n = this.count; t < n; t++)ft.fromBufferAttribute(this, t), ft.applyMatrix4(e), this.setXYZ(t, ft.x, ft.y, ft.z); return this; } applyNormalMatrix(e) { - for(let t = 0, n = this.count; t < n; t++)Je.x = this.getX(t), Je.y = this.getY(t), Je.z = this.getZ(t), Je.applyNormalMatrix(e), this.setXYZ(t, Je.x, Je.y, Je.z); + for(let t = 0, n = this.count; t < n; t++)ft.fromBufferAttribute(this, t), ft.applyNormalMatrix(e), this.setXYZ(t, ft.x, ft.y, ft.z); return this; } transformDirection(e) { - for(let t = 0, n = this.count; t < n; t++)Je.x = this.getX(t), Je.y = this.getY(t), Je.z = this.getZ(t), Je.transformDirection(e), this.setXYZ(t, Je.x, Je.y, Je.z); + for(let t = 0, n = this.count; t < n; t++)ft.fromBufferAttribute(this, t), ft.transformDirection(e), this.setXYZ(t, ft.x, ft.y, ft.z); return this; } set(e, t = 0) { return this.array.set(e, t), this; } + getComponent(e, t) { + let n = this.array[e * this.itemSize + t]; + return this.normalized && (n = Ot(n, this.array)), n; + } + setComponent(e, t, n) { + return this.normalized && (n = Be(n, this.array)), this.array[e * this.itemSize + t] = n, this; + } getX(e) { - return this.array[e * this.itemSize]; + let t = this.array[e * this.itemSize]; + return this.normalized && (t = Ot(t, this.array)), t; } setX(e, t) { - return this.array[e * this.itemSize] = t, this; + return this.normalized && (t = Be(t, this.array)), this.array[e * this.itemSize] = t, this; } getY(e) { - return this.array[e * this.itemSize + 1]; + let t = this.array[e * this.itemSize + 1]; + return this.normalized && (t = Ot(t, this.array)), t; } setY(e, t) { - return this.array[e * this.itemSize + 1] = t, this; + return this.normalized && (t = Be(t, this.array)), this.array[e * this.itemSize + 1] = t, this; } getZ(e) { - return this.array[e * this.itemSize + 2]; + let t = this.array[e * this.itemSize + 2]; + return this.normalized && (t = Ot(t, this.array)), t; } setZ(e, t) { - return this.array[e * this.itemSize + 2] = t, this; + return this.normalized && (t = Be(t, this.array)), this.array[e * this.itemSize + 2] = t, this; } getW(e) { - return this.array[e * this.itemSize + 3]; + let t = this.array[e * this.itemSize + 3]; + return this.normalized && (t = Ot(t, this.array)), t; } setW(e, t) { - return this.array[e * this.itemSize + 3] = t, this; + return this.normalized && (t = Be(t, this.array)), this.array[e * this.itemSize + 3] = t, this; } setXY(e, t, n) { - return e *= this.itemSize, this.array[e + 0] = t, this.array[e + 1] = n, this; + return e *= this.itemSize, this.normalized && (t = Be(t, this.array), n = Be(n, this.array)), this.array[e + 0] = t, this.array[e + 1] = n, this; } setXYZ(e, t, n, i) { - return e *= this.itemSize, this.array[e + 0] = t, this.array[e + 1] = n, this.array[e + 2] = i, this; + return e *= this.itemSize, this.normalized && (t = Be(t, this.array), n = Be(n, this.array), i = Be(i, this.array)), this.array[e + 0] = t, this.array[e + 1] = n, this.array[e + 2] = i, this; } setXYZW(e, t, n, i, r) { - return e *= this.itemSize, this.array[e + 0] = t, this.array[e + 1] = n, this.array[e + 2] = i, this.array[e + 3] = r, this; + return e *= this.itemSize, this.normalized && (t = Be(t, this.array), n = Be(n, this.array), i = Be(i, this.array), r = Be(r, this.array)), this.array[e + 0] = t, this.array[e + 1] = n, this.array[e + 2] = i, this.array[e + 3] = r, this; } onUpload(e) { return this.onUploadCallback = e, this; @@ -2881,61 +3357,93 @@ var Je = new M, Qr = new X, Ue = class { let e = { itemSize: this.itemSize, type: this.array.constructor.name, - array: Array.prototype.slice.call(this.array), + array: Array.from(this.array), normalized: this.normalized }; - return this.name !== "" && (e.name = this.name), this.usage !== hr && (e.usage = this.usage), (this.updateRange.offset !== 0 || this.updateRange.count !== -1) && (e.updateRange = this.updateRange), e; + return this.name !== "" && (e.name = this.name), this.usage !== Hr && (e.usage = this.usage), (this.updateRange.offset !== 0 || this.updateRange.count !== -1) && (e.updateRange = this.updateRange), e; } -}; -Ue.prototype.isBufferAttribute = !0; -var jc = class extends Ue { +}, Ql = class extends et { constructor(e, t, n){ super(new Int8Array(e), t, n); } -}, Qc = class extends Ue { +}, jl = class extends et { constructor(e, t, n){ super(new Uint8Array(e), t, n); } -}, Kc = class extends Ue { +}, eh = class extends et { constructor(e, t, n){ super(new Uint8ClampedArray(e), t, n); } -}, eh = class extends Ue { +}, th = class extends et { constructor(e, t, n){ super(new Int16Array(e), t, n); } -}, Ys = class extends Ue { +}, Zr = class extends et { constructor(e, t, n){ super(new Uint16Array(e), t, n); } -}, th = class extends Ue { +}, nh = class extends et { constructor(e, t, n){ super(new Int32Array(e), t, n); } -}, Zs = class extends Ue { +}, Jr = class extends et { constructor(e, t, n){ super(new Uint32Array(e), t, n); } -}, nh = class extends Ue { +}, ih = class extends et { constructor(e, t, n){ - super(new Uint16Array(e), t, n); + super(new Uint16Array(e), t, n), this.isFloat16BufferAttribute = !0; } -}; -nh.prototype.isFloat16BufferAttribute = !0; -var de = class extends Ue { + getX(e) { + let t = xs(this.array[e * this.itemSize]); + return this.normalized && (t = Ot(t, this.array)), t; + } + setX(e, t) { + return this.normalized && (t = Be(t, this.array)), this.array[e * this.itemSize] = Nt(t), this; + } + getY(e) { + let t = xs(this.array[e * this.itemSize + 1]); + return this.normalized && (t = Ot(t, this.array)), t; + } + setY(e, t) { + return this.normalized && (t = Be(t, this.array)), this.array[e * this.itemSize + 1] = Nt(t), this; + } + getZ(e) { + let t = xs(this.array[e * this.itemSize + 2]); + return this.normalized && (t = Ot(t, this.array)), t; + } + setZ(e, t) { + return this.normalized && (t = Be(t, this.array)), this.array[e * this.itemSize + 2] = Nt(t), this; + } + getW(e) { + let t = xs(this.array[e * this.itemSize + 3]); + return this.normalized && (t = Ot(t, this.array)), t; + } + setW(e, t) { + return this.normalized && (t = Be(t, this.array)), this.array[e * this.itemSize + 3] = Nt(t), this; + } + setXY(e, t, n) { + return e *= this.itemSize, this.normalized && (t = Be(t, this.array), n = Be(n, this.array)), this.array[e + 0] = Nt(t), this.array[e + 1] = Nt(n), this; + } + setXYZ(e, t, n, i) { + return e *= this.itemSize, this.normalized && (t = Be(t, this.array), n = Be(n, this.array), i = Be(i, this.array)), this.array[e + 0] = Nt(t), this.array[e + 1] = Nt(n), this.array[e + 2] = Nt(i), this; + } + setXYZW(e, t, n, i, r) { + return e *= this.itemSize, this.normalized && (t = Be(t, this.array), n = Be(n, this.array), i = Be(i, this.array), r = Be(r, this.array)), this.array[e + 0] = Nt(t), this.array[e + 1] = Nt(n), this.array[e + 2] = Nt(i), this.array[e + 3] = Nt(r), this; + } +}, ve = class extends et { constructor(e, t, n){ super(new Float32Array(e), t, n); } -}, ih = class extends Ue { +}, sh = class extends et { constructor(e, t, n){ super(new Float64Array(e), t, n); } -}, cf = 0, Rt = new pe, No = new Ne, ci = new M, Tt = new Lt, $i = new Lt, ht = new M, _e = class extends En { +}, mp = 0, Gt = new ze, Ya = new Je, Ti = new A, Vt = new Qt, us = new Qt, xt = new A, Ge = class s1 extends sn { constructor(){ - super(); - Object.defineProperty(this, "id", { - value: cf++ - }), this.uuid = Et(), this.name = "", this.type = "BufferGeometry", this.index = null, this.attributes = {}, this.morphAttributes = {}, this.morphTargetsRelative = !1, this.groups = [], this.boundingBox = null, this.boundingSphere = null, this.drawRange = { + super(), this.isBufferGeometry = !0, Object.defineProperty(this, "id", { + value: mp++ + }), this.uuid = kt(), this.name = "", this.type = "BufferGeometry", this.index = null, this.attributes = {}, this.morphAttributes = {}, this.morphTargetsRelative = !1, this.groups = [], this.boundingBox = null, this.boundingSphere = null, this.drawRange = { start: 0, count: 1 / 0 }, this.userData = {}; @@ -2944,7 +3452,7 @@ var de = class extends Ue { return this.index; } setIndex(e) { - return Array.isArray(e) ? this.index = new (Yc(e) > 65535 ? Zs : Ys)(e, 1) : this.index = e, this; + return Array.isArray(e) ? this.index = new (Md(e) ? Jr : Zr)(e, 1) : this.index = e, this; } getAttribute(e) { return this.attributes[e]; @@ -2976,35 +3484,35 @@ var de = class extends Ue { t !== void 0 && (t.applyMatrix4(e), t.needsUpdate = !0); let n = this.attributes.normal; if (n !== void 0) { - let r = new lt().getNormalMatrix(e); + let r = new He().getNormalMatrix(e); n.applyNormalMatrix(r), n.needsUpdate = !0; } let i = this.attributes.tangent; return i !== void 0 && (i.transformDirection(e), i.needsUpdate = !0), this.boundingBox !== null && this.computeBoundingBox(), this.boundingSphere !== null && this.computeBoundingSphere(), this; } applyQuaternion(e) { - return Rt.makeRotationFromQuaternion(e), this.applyMatrix4(Rt), this; + return Gt.makeRotationFromQuaternion(e), this.applyMatrix4(Gt), this; } rotateX(e) { - return Rt.makeRotationX(e), this.applyMatrix4(Rt), this; + return Gt.makeRotationX(e), this.applyMatrix4(Gt), this; } rotateY(e) { - return Rt.makeRotationY(e), this.applyMatrix4(Rt), this; + return Gt.makeRotationY(e), this.applyMatrix4(Gt), this; } rotateZ(e) { - return Rt.makeRotationZ(e), this.applyMatrix4(Rt), this; + return Gt.makeRotationZ(e), this.applyMatrix4(Gt), this; } translate(e, t, n) { - return Rt.makeTranslation(e, t, n), this.applyMatrix4(Rt), this; + return Gt.makeTranslation(e, t, n), this.applyMatrix4(Gt), this; } scale(e, t, n) { - return Rt.makeScale(e, t, n), this.applyMatrix4(Rt), this; + return Gt.makeScale(e, t, n), this.applyMatrix4(Gt), this; } lookAt(e) { - return No.lookAt(e), No.updateMatrix(), this.applyMatrix4(No.matrix), this; + return Ya.lookAt(e), Ya.updateMatrix(), this.applyMatrix4(Ya.matrix), this; } center() { - return this.computeBoundingBox(), this.boundingBox.getCenter(ci).negate(), this.translate(ci.x, ci.y, ci.z), this; + return this.computeBoundingBox(), this.boundingBox.getCenter(Ti).negate(), this.translate(Ti.x, Ti.y, Ti.z), this; } setFromPoints(e) { let t = []; @@ -3012,42 +3520,42 @@ var de = class extends Ue { let r = e[n]; t.push(r.x, r.y, r.z || 0); } - return this.setAttribute("position", new de(t, 3)), this; + return this.setAttribute("position", new ve(t, 3)), this; } computeBoundingBox() { - this.boundingBox === null && (this.boundingBox = new Lt); + this.boundingBox === null && (this.boundingBox = new Qt); let e = this.attributes.position, t = this.morphAttributes.position; if (e && e.isGLBufferAttribute) { - console.error('THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this), this.boundingBox.set(new M(-1 / 0, -1 / 0, -1 / 0), new M(1 / 0, 1 / 0, 1 / 0)); + console.error('THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this), this.boundingBox.set(new A(-1 / 0, -1 / 0, -1 / 0), new A(1 / 0, 1 / 0, 1 / 0)); return; } if (e !== void 0) { if (this.boundingBox.setFromBufferAttribute(e), t) for(let n = 0, i = t.length; n < i; n++){ let r = t[n]; - Tt.setFromBufferAttribute(r), this.morphTargetsRelative ? (ht.addVectors(this.boundingBox.min, Tt.min), this.boundingBox.expandByPoint(ht), ht.addVectors(this.boundingBox.max, Tt.max), this.boundingBox.expandByPoint(ht)) : (this.boundingBox.expandByPoint(Tt.min), this.boundingBox.expandByPoint(Tt.max)); + Vt.setFromBufferAttribute(r), this.morphTargetsRelative ? (xt.addVectors(this.boundingBox.min, Vt.min), this.boundingBox.expandByPoint(xt), xt.addVectors(this.boundingBox.max, Vt.max), this.boundingBox.expandByPoint(xt)) : (this.boundingBox.expandByPoint(Vt.min), this.boundingBox.expandByPoint(Vt.max)); } } else this.boundingBox.makeEmpty(); (isNaN(this.boundingBox.min.x) || isNaN(this.boundingBox.min.y) || isNaN(this.boundingBox.min.z)) && console.error('THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this); } computeBoundingSphere() { - this.boundingSphere === null && (this.boundingSphere = new An); + this.boundingSphere === null && (this.boundingSphere = new Yt); let e = this.attributes.position, t = this.morphAttributes.position; if (e && e.isGLBufferAttribute) { - console.error('THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this), this.boundingSphere.set(new M, 1 / 0); + console.error('THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this), this.boundingSphere.set(new A, 1 / 0); return; } if (e) { let n = this.boundingSphere.center; - if (Tt.setFromBufferAttribute(e), t) for(let r = 0, o = t.length; r < o; r++){ - let a = t[r]; - $i.setFromBufferAttribute(a), this.morphTargetsRelative ? (ht.addVectors(Tt.min, $i.min), Tt.expandByPoint(ht), ht.addVectors(Tt.max, $i.max), Tt.expandByPoint(ht)) : (Tt.expandByPoint($i.min), Tt.expandByPoint($i.max)); + if (Vt.setFromBufferAttribute(e), t) for(let r = 0, a = t.length; r < a; r++){ + let o = t[r]; + us.setFromBufferAttribute(o), this.morphTargetsRelative ? (xt.addVectors(Vt.min, us.min), Vt.expandByPoint(xt), xt.addVectors(Vt.max, us.max), Vt.expandByPoint(xt)) : (Vt.expandByPoint(us.min), Vt.expandByPoint(us.max)); } - Tt.getCenter(n); + Vt.getCenter(n); let i = 0; - for(let r = 0, o = e.count; r < o; r++)ht.fromBufferAttribute(e, r), i = Math.max(i, n.distanceToSquared(ht)); - if (t) for(let r = 0, o = t.length; r < o; r++){ - let a = t[r], l = this.morphTargetsRelative; - for(let c = 0, h = a.count; c < h; c++)ht.fromBufferAttribute(a, c), l && (ci.fromBufferAttribute(e, c), ht.add(ci)), i = Math.max(i, n.distanceToSquared(ht)); + for(let r = 0, a = e.count; r < a; r++)xt.fromBufferAttribute(e, r), i = Math.max(i, n.distanceToSquared(xt)); + if (t) for(let r = 0, a = t.length; r < a; r++){ + let o = t[r], c = this.morphTargetsRelative; + for(let l = 0, h = o.count; l < h; l++)xt.fromBufferAttribute(o, l), c && (Ti.fromBufferAttribute(e, l), xt.add(Ti)), i = Math.max(i, n.distanceToSquared(xt)); } this.boundingSphere.radius = Math.sqrt(i), isNaN(this.boundingSphere.radius) && console.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this); } @@ -3058,15 +3566,15 @@ var de = class extends Ue { console.error("THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)"); return; } - let n = e.array, i = t.position.array, r = t.normal.array, o = t.uv.array, a = i.length / 3; - t.tangent === void 0 && this.setAttribute("tangent", new Ue(new Float32Array(4 * a), 4)); - let l = t.tangent.array, c = [], h = []; - for(let B = 0; B < a; B++)c[B] = new M, h[B] = new M; - let u = new M, d = new M, f = new M, m = new X, x = new X, v = new X, g = new M, p = new M; - function _(B, P, w) { - u.fromArray(i, B * 3), d.fromArray(i, P * 3), f.fromArray(i, w * 3), m.fromArray(o, B * 2), x.fromArray(o, P * 2), v.fromArray(o, w * 2), d.sub(u), f.sub(u), x.sub(m), v.sub(m); - let E = 1 / (x.x * v.y - v.x * x.y); - !isFinite(E) || (g.copy(d).multiplyScalar(v.y).addScaledVector(f, -x.y).multiplyScalar(E), p.copy(f).multiplyScalar(x.x).addScaledVector(d, -v.x).multiplyScalar(E), c[B].add(g), c[P].add(g), c[w].add(g), h[B].add(p), h[P].add(p), h[w].add(p)); + let n = e.array, i = t.position.array, r = t.normal.array, a = t.uv.array, o = i.length / 3; + this.hasAttribute("tangent") === !1 && this.setAttribute("tangent", new et(new Float32Array(4 * o), 4)); + let c = this.getAttribute("tangent").array, l = [], h = []; + for(let T = 0; T < o; T++)l[T] = new A, h[T] = new A; + let u = new A, d = new A, f = new A, m = new Z, _ = new Z, g = new Z, p = new A, v = new A; + function x(T, O, Y) { + u.fromArray(i, T * 3), d.fromArray(i, O * 3), f.fromArray(i, Y * 3), m.fromArray(a, T * 2), _.fromArray(a, O * 2), g.fromArray(a, Y * 2), d.sub(u), f.sub(u), _.sub(m), g.sub(m); + let $ = 1 / (_.x * g.y - g.x * _.y); + isFinite($) && (p.copy(d).multiplyScalar(g.y).addScaledVector(f, -_.y).multiplyScalar($), v.copy(f).multiplyScalar(_.x).addScaledVector(d, -g.x).multiplyScalar($), l[T].add(p), l[O].add(p), l[Y].add(p), h[T].add(v), h[O].add(v), h[Y].add(v)); } let y = this.groups; y.length === 0 && (y = [ @@ -3075,99 +3583,85 @@ var de = class extends Ue { count: n.length } ]); - for(let B = 0, P = y.length; B < P; ++B){ - let w = y[B], E = w.start, D = w.count; - for(let U = E, F = E + D; U < F; U += 3)_(n[U + 0], n[U + 1], n[U + 2]); + for(let T = 0, O = y.length; T < O; ++T){ + let Y = y[T], $ = Y.start, U = Y.count; + for(let z = $, q = $ + U; z < q; z += 3)x(n[z + 0], n[z + 1], n[z + 2]); } - let b = new M, A = new M, L = new M, I = new M; - function k(B) { - L.fromArray(r, B * 3), I.copy(L); - let P = c[B]; - b.copy(P), b.sub(L.multiplyScalar(L.dot(P))).normalize(), A.crossVectors(I, P); - let E = A.dot(h[B]) < 0 ? -1 : 1; - l[B * 4] = b.x, l[B * 4 + 1] = b.y, l[B * 4 + 2] = b.z, l[B * 4 + 3] = E; + let b = new A, w = new A, R = new A, I = new A; + function M(T) { + R.fromArray(r, T * 3), I.copy(R); + let O = l[T]; + b.copy(O), b.sub(R.multiplyScalar(R.dot(O))).normalize(), w.crossVectors(I, O); + let $ = w.dot(h[T]) < 0 ? -1 : 1; + c[T * 4] = b.x, c[T * 4 + 1] = b.y, c[T * 4 + 2] = b.z, c[T * 4 + 3] = $; } - for(let B = 0, P = y.length; B < P; ++B){ - let w = y[B], E = w.start, D = w.count; - for(let U = E, F = E + D; U < F; U += 3)k(n[U + 0]), k(n[U + 1]), k(n[U + 2]); + for(let T = 0, O = y.length; T < O; ++T){ + let Y = y[T], $ = Y.start, U = Y.count; + for(let z = $, q = $ + U; z < q; z += 3)M(n[z + 0]), M(n[z + 1]), M(n[z + 2]); } } computeVertexNormals() { let e = this.index, t = this.getAttribute("position"); if (t !== void 0) { let n = this.getAttribute("normal"); - if (n === void 0) n = new Ue(new Float32Array(t.count * 3), 3), this.setAttribute("normal", n); + if (n === void 0) n = new et(new Float32Array(t.count * 3), 3), this.setAttribute("normal", n); else for(let d = 0, f = n.count; d < f; d++)n.setXYZ(d, 0, 0, 0); - let i = new M, r = new M, o = new M, a = new M, l = new M, c = new M, h = new M, u = new M; + let i = new A, r = new A, a = new A, o = new A, c = new A, l = new A, h = new A, u = new A; if (e) for(let d = 0, f = e.count; d < f; d += 3){ - let m = e.getX(d + 0), x = e.getX(d + 1), v = e.getX(d + 2); - i.fromBufferAttribute(t, m), r.fromBufferAttribute(t, x), o.fromBufferAttribute(t, v), h.subVectors(o, r), u.subVectors(i, r), h.cross(u), a.fromBufferAttribute(n, m), l.fromBufferAttribute(n, x), c.fromBufferAttribute(n, v), a.add(h), l.add(h), c.add(h), n.setXYZ(m, a.x, a.y, a.z), n.setXYZ(x, l.x, l.y, l.z), n.setXYZ(v, c.x, c.y, c.z); + let m = e.getX(d + 0), _ = e.getX(d + 1), g = e.getX(d + 2); + i.fromBufferAttribute(t, m), r.fromBufferAttribute(t, _), a.fromBufferAttribute(t, g), h.subVectors(a, r), u.subVectors(i, r), h.cross(u), o.fromBufferAttribute(n, m), c.fromBufferAttribute(n, _), l.fromBufferAttribute(n, g), o.add(h), c.add(h), l.add(h), n.setXYZ(m, o.x, o.y, o.z), n.setXYZ(_, c.x, c.y, c.z), n.setXYZ(g, l.x, l.y, l.z); } - else for(let d = 0, f = t.count; d < f; d += 3)i.fromBufferAttribute(t, d + 0), r.fromBufferAttribute(t, d + 1), o.fromBufferAttribute(t, d + 2), h.subVectors(o, r), u.subVectors(i, r), h.cross(u), n.setXYZ(d + 0, h.x, h.y, h.z), n.setXYZ(d + 1, h.x, h.y, h.z), n.setXYZ(d + 2, h.x, h.y, h.z); + else for(let d = 0, f = t.count; d < f; d += 3)i.fromBufferAttribute(t, d + 0), r.fromBufferAttribute(t, d + 1), a.fromBufferAttribute(t, d + 2), h.subVectors(a, r), u.subVectors(i, r), h.cross(u), n.setXYZ(d + 0, h.x, h.y, h.z), n.setXYZ(d + 1, h.x, h.y, h.z), n.setXYZ(d + 2, h.x, h.y, h.z); this.normalizeNormals(), n.needsUpdate = !0; } } - merge(e, t) { - if (!(e && e.isBufferGeometry)) { - console.error("THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.", e); - return; - } - t === void 0 && (t = 0, console.warn("THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.")); - let n = this.attributes; - for(let i in n){ - if (e.attributes[i] === void 0) continue; - let o = n[i].array, a = e.attributes[i], l = a.array, c = a.itemSize * t, h = Math.min(l.length, o.length - c); - for(let u = 0, d = c; u < h; u++, d++)o[d] = l[u]; - } - return this; - } normalizeNormals() { let e = this.attributes.normal; - for(let t = 0, n = e.count; t < n; t++)ht.fromBufferAttribute(e, t), ht.normalize(), e.setXYZ(t, ht.x, ht.y, ht.z); + for(let t = 0, n = e.count; t < n; t++)xt.fromBufferAttribute(e, t), xt.normalize(), e.setXYZ(t, xt.x, xt.y, xt.z); } toNonIndexed() { - function e(a, l) { - let c = a.array, h = a.itemSize, u = a.normalized, d = new c.constructor(l.length * h), f = 0, m = 0; - for(let x = 0, v = l.length; x < v; x++){ - a.isInterleavedBufferAttribute ? f = l[x] * a.data.stride + a.offset : f = l[x] * h; - for(let g = 0; g < h; g++)d[m++] = c[f++]; + function e(o, c) { + let l = o.array, h = o.itemSize, u = o.normalized, d = new l.constructor(c.length * h), f = 0, m = 0; + for(let _ = 0, g = c.length; _ < g; _++){ + o.isInterleavedBufferAttribute ? f = c[_] * o.data.stride + o.offset : f = c[_] * h; + for(let p = 0; p < h; p++)d[m++] = l[f++]; } - return new Ue(d, h, u); + return new et(d, h, u); } if (this.index === null) return console.warn("THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed."), this; - let t = new _e, n = this.index.array, i = this.attributes; - for(let a in i){ - let l = i[a], c = e(l, n); - t.setAttribute(a, c); + let t = new s1, n = this.index.array, i = this.attributes; + for(let o in i){ + let c = i[o], l = e(c, n); + t.setAttribute(o, l); } let r = this.morphAttributes; - for(let a in r){ - let l = [], c = r[a]; - for(let h = 0, u = c.length; h < u; h++){ - let d = c[h], f = e(d, n); - l.push(f); + for(let o in r){ + let c = [], l = r[o]; + for(let h = 0, u = l.length; h < u; h++){ + let d = l[h], f = e(d, n); + c.push(f); } - t.morphAttributes[a] = l; + t.morphAttributes[o] = c; } t.morphTargetsRelative = this.morphTargetsRelative; - let o = this.groups; - for(let a = 0, l = o.length; a < l; a++){ - let c = o[a]; - t.addGroup(c.start, c.count, c.materialIndex); + let a = this.groups; + for(let o = 0, c = a.length; o < c; o++){ + let l = a[o]; + t.addGroup(l.start, l.count, l.materialIndex); } return t; } toJSON() { let e = { metadata: { - version: 4.5, + version: 4.6, type: "BufferGeometry", generator: "BufferGeometry.toJSON" } }; if (e.uuid = this.uuid, e.type = this.type, this.name !== "" && (e.name = this.name), Object.keys(this.userData).length > 0 && (e.userData = this.userData), this.parameters !== void 0) { - let l = this.parameters; - for(let c in l)l[c] !== void 0 && (e[c] = l[c]); + let c = this.parameters; + for(let l in c)c[l] !== void 0 && (e[l] = c[l]); return e; } e.data = { @@ -3179,26 +3673,26 @@ var de = class extends Ue { array: Array.prototype.slice.call(t.array) }); let n = this.attributes; - for(let l in n){ - let c = n[l]; - e.data.attributes[l] = c.toJSON(e.data); + for(let c in n){ + let l = n[c]; + e.data.attributes[c] = l.toJSON(e.data); } let i = {}, r = !1; - for(let l in this.morphAttributes){ - let c = this.morphAttributes[l], h = []; - for(let u = 0, d = c.length; u < d; u++){ - let f = c[u]; + for(let c in this.morphAttributes){ + let l = this.morphAttributes[c], h = []; + for(let u = 0, d = l.length; u < d; u++){ + let f = l[u]; h.push(f.toJSON(e.data)); } - h.length > 0 && (i[l] = h, r = !0); + h.length > 0 && (i[c] = h, r = !0); } r && (e.data.morphAttributes = i, e.data.morphTargetsRelative = this.morphTargetsRelative); - let o = this.groups; - o.length > 0 && (e.data.groups = JSON.parse(JSON.stringify(o))); - let a = this.boundingSphere; - return a !== null && (e.data.boundingSphere = { - center: a.center.toArray(), - radius: a.radius + let a = this.groups; + a.length > 0 && (e.data.groups = JSON.parse(JSON.stringify(a))); + let o = this.boundingSphere; + return o !== null && (e.data.boundingSphere = { + center: o.center.toArray(), + radius: o.radius }), e; } clone() { @@ -3211,201 +3705,203 @@ var de = class extends Ue { let n = e.index; n !== null && this.setIndex(n.clone(t)); let i = e.attributes; - for(let c in i){ - let h = i[c]; - this.setAttribute(c, h.clone(t)); + for(let l in i){ + let h = i[l]; + this.setAttribute(l, h.clone(t)); } let r = e.morphAttributes; - for(let c in r){ - let h = [], u = r[c]; + for(let l in r){ + let h = [], u = r[l]; for(let d = 0, f = u.length; d < f; d++)h.push(u[d].clone(t)); - this.morphAttributes[c] = h; + this.morphAttributes[l] = h; } this.morphTargetsRelative = e.morphTargetsRelative; - let o = e.groups; - for(let c = 0, h = o.length; c < h; c++){ - let u = o[c]; + let a = e.groups; + for(let l = 0, h = a.length; l < h; l++){ + let u = a[l]; this.addGroup(u.start, u.count, u.materialIndex); } - let a = e.boundingBox; - a !== null && (this.boundingBox = a.clone()); - let l = e.boundingSphere; - return l !== null && (this.boundingSphere = l.clone()), this.drawRange.start = e.drawRange.start, this.drawRange.count = e.drawRange.count, this.userData = e.userData, e.parameters !== void 0 && (this.parameters = Object.assign({}, e.parameters)), this; + let o = e.boundingBox; + o !== null && (this.boundingBox = o.clone()); + let c = e.boundingSphere; + return c !== null && (this.boundingSphere = c.clone()), this.drawRange.start = e.drawRange.start, this.drawRange.count = e.drawRange.count, this.userData = e.userData, this; } dispose() { this.dispatchEvent({ type: "dispose" }); } -}; -_e.prototype.isBufferGeometry = !0; -var Cl = new pe, hi = new Cn, Bo = new An, mn = new M, gn = new M, xn = new M, zo = new M, Uo = new M, Oo = new M, Kr = new M, es = new M, ts = new M, ns = new X, is = new X, rs = new X, Ho = new M, ss = new M, st = class extends Ne { - constructor(e = new _e, t = new hn){ - super(); - this.type = "Mesh", this.geometry = e, this.material = t, this.updateMorphTargets(); +}, rh = new ze, qn = new hi, js = new Yt, ah = new A, wi = new A, Ai = new A, Ri = new A, Za = new A, er = new A, tr = new Z, nr = new Z, ir = new Z, oh = new A, ch = new A, lh = new A, sr = new A, rr = new A, Mt = class extends Je { + constructor(e = new Ge, t = new Sn){ + super(), this.isMesh = !0, this.type = "Mesh", this.geometry = e, this.material = t, this.updateMorphTargets(); } - copy(e) { - return super.copy(e), e.morphTargetInfluences !== void 0 && (this.morphTargetInfluences = e.morphTargetInfluences.slice()), e.morphTargetDictionary !== void 0 && (this.morphTargetDictionary = Object.assign({}, e.morphTargetDictionary)), this.material = e.material, this.geometry = e.geometry, this; + copy(e, t) { + return super.copy(e, t), e.morphTargetInfluences !== void 0 && (this.morphTargetInfluences = e.morphTargetInfluences.slice()), e.morphTargetDictionary !== void 0 && (this.morphTargetDictionary = Object.assign({}, e.morphTargetDictionary)), this.material = Array.isArray(e.material) ? e.material.slice() : e.material, this.geometry = e.geometry, this; } updateMorphTargets() { - let e = this.geometry; - if (e.isBufferGeometry) { - let t = e.morphAttributes, n = Object.keys(t); - if (n.length > 0) { - let i = t[n[0]]; - if (i !== void 0) { - this.morphTargetInfluences = [], this.morphTargetDictionary = {}; - for(let r = 0, o = i.length; r < o; r++){ - let a = i[r].name || String(r); - this.morphTargetInfluences.push(0), this.morphTargetDictionary[a] = r; - } + let t = this.geometry.morphAttributes, n = Object.keys(t); + if (n.length > 0) { + let i = t[n[0]]; + if (i !== void 0) { + this.morphTargetInfluences = [], this.morphTargetDictionary = {}; + for(let r = 0, a = i.length; r < a; r++){ + let o = i[r].name || String(r); + this.morphTargetInfluences.push(0), this.morphTargetDictionary[o] = r; } } - } else { - let t = e.morphTargets; - t !== void 0 && t.length > 0 && console.error("THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead."); } } + getVertexPosition(e, t) { + let n = this.geometry, i = n.attributes.position, r = n.morphAttributes.position, a = n.morphTargetsRelative; + t.fromBufferAttribute(i, e); + let o = this.morphTargetInfluences; + if (r && o) { + er.set(0, 0, 0); + for(let c = 0, l = r.length; c < l; c++){ + let h = o[c], u = r[c]; + h !== 0 && (Za.fromBufferAttribute(u, e), a ? er.addScaledVector(Za, h) : er.addScaledVector(Za.sub(t), h)); + } + t.add(er); + } + return t; + } raycast(e, t) { let n = this.geometry, i = this.material, r = this.matrixWorld; - if (i === void 0 || (n.boundingSphere === null && n.computeBoundingSphere(), Bo.copy(n.boundingSphere), Bo.applyMatrix4(r), e.ray.intersectsSphere(Bo) === !1) || (Cl.copy(r).invert(), hi.copy(e.ray).applyMatrix4(Cl), n.boundingBox !== null && hi.intersectsBox(n.boundingBox) === !1)) return; - let o; - if (n.isBufferGeometry) { - let a = n.index, l = n.attributes.position, c = n.morphAttributes.position, h = n.morphTargetsRelative, u = n.attributes.uv, d = n.attributes.uv2, f = n.groups, m = n.drawRange; - if (a !== null) if (Array.isArray(i)) for(let x = 0, v = f.length; x < v; x++){ - let g = f[x], p = i[g.materialIndex], _ = Math.max(g.start, m.start), y = Math.min(a.count, Math.min(g.start + g.count, m.start + m.count)); - for(let b = _, A = y; b < A; b += 3){ - let L = a.getX(b), I = a.getX(b + 1), k = a.getX(b + 2); - o = os(this, p, e, hi, l, c, h, u, d, L, I, k), o && (o.faceIndex = Math.floor(b / 3), o.face.materialIndex = g.materialIndex, t.push(o)); - } + i !== void 0 && (n.boundingSphere === null && n.computeBoundingSphere(), js.copy(n.boundingSphere), js.applyMatrix4(r), qn.copy(e.ray).recast(e.near), !(js.containsPoint(qn.origin) === !1 && (qn.intersectSphere(js, ah) === null || qn.origin.distanceToSquared(ah) > (e.far - e.near) ** 2)) && (rh.copy(r).invert(), qn.copy(e.ray).applyMatrix4(rh), !(n.boundingBox !== null && qn.intersectsBox(n.boundingBox) === !1) && this._computeIntersections(e, t, qn))); + } + _computeIntersections(e, t, n) { + let i, r = this.geometry, a = this.material, o = r.index, c = r.attributes.position, l = r.attributes.uv, h = r.attributes.uv1, u = r.attributes.normal, d = r.groups, f = r.drawRange; + if (o !== null) if (Array.isArray(a)) for(let m = 0, _ = d.length; m < _; m++){ + let g = d[m], p = a[g.materialIndex], v = Math.max(g.start, f.start), x = Math.min(o.count, Math.min(g.start + g.count, f.start + f.count)); + for(let y = v, b = x; y < b; y += 3){ + let w = o.getX(y), R = o.getX(y + 1), I = o.getX(y + 2); + i = ar(this, p, e, n, l, h, u, w, R, I), i && (i.faceIndex = Math.floor(y / 3), i.face.materialIndex = g.materialIndex, t.push(i)); } - else { - let x = Math.max(0, m.start), v = Math.min(a.count, m.start + m.count); - for(let g = x, p = v; g < p; g += 3){ - let _ = a.getX(g), y = a.getX(g + 1), b = a.getX(g + 2); - o = os(this, i, e, hi, l, c, h, u, d, _, y, b), o && (o.faceIndex = Math.floor(g / 3), t.push(o)); - } + } + else { + let m = Math.max(0, f.start), _ = Math.min(o.count, f.start + f.count); + for(let g = m, p = _; g < p; g += 3){ + let v = o.getX(g), x = o.getX(g + 1), y = o.getX(g + 2); + i = ar(this, a, e, n, l, h, u, v, x, y), i && (i.faceIndex = Math.floor(g / 3), t.push(i)); } - else if (l !== void 0) if (Array.isArray(i)) for(let x = 0, v = f.length; x < v; x++){ - let g = f[x], p = i[g.materialIndex], _ = Math.max(g.start, m.start), y = Math.min(l.count, Math.min(g.start + g.count, m.start + m.count)); - for(let b = _, A = y; b < A; b += 3){ - let L = b, I = b + 1, k = b + 2; - o = os(this, p, e, hi, l, c, h, u, d, L, I, k), o && (o.faceIndex = Math.floor(b / 3), o.face.materialIndex = g.materialIndex, t.push(o)); - } + } + else if (c !== void 0) if (Array.isArray(a)) for(let m = 0, _ = d.length; m < _; m++){ + let g = d[m], p = a[g.materialIndex], v = Math.max(g.start, f.start), x = Math.min(c.count, Math.min(g.start + g.count, f.start + f.count)); + for(let y = v, b = x; y < b; y += 3){ + let w = y, R = y + 1, I = y + 2; + i = ar(this, p, e, n, l, h, u, w, R, I), i && (i.faceIndex = Math.floor(y / 3), i.face.materialIndex = g.materialIndex, t.push(i)); } - else { - let x = Math.max(0, m.start), v = Math.min(l.count, m.start + m.count); - for(let g = x, p = v; g < p; g += 3){ - let _ = g, y = g + 1, b = g + 2; - o = os(this, i, e, hi, l, c, h, u, d, _, y, b), o && (o.faceIndex = Math.floor(g / 3), t.push(o)); - } + } + else { + let m = Math.max(0, f.start), _ = Math.min(c.count, f.start + f.count); + for(let g = m, p = _; g < p; g += 3){ + let v = g, x = g + 1, y = g + 2; + i = ar(this, a, e, n, l, h, u, v, x, y), i && (i.faceIndex = Math.floor(g / 3), t.push(i)); } - } else n.isGeometry && console.error("THREE.Mesh.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead."); + } } }; -st.prototype.isMesh = !0; -function hf(s, e, t, n, i, r, o, a) { - let l; - if (e.side === it ? l = n.intersectTriangle(o, r, i, !0, a) : l = n.intersectTriangle(i, r, o, e.side !== Ci, a), l === null) return null; - ss.copy(a), ss.applyMatrix4(s.matrixWorld); - let c = t.ray.origin.distanceTo(ss); - return c < t.near || c > t.far ? null : { - distance: c, - point: ss.clone(), - object: s +function gp(s1, e, t, n, i, r, a, o) { + let c; + if (e.side === Ft ? c = n.intersectTriangle(a, r, i, !0, o) : c = n.intersectTriangle(i, r, a, e.side === Bn, o), c === null) return null; + rr.copy(o), rr.applyMatrix4(s1.matrixWorld); + let l = t.ray.origin.distanceTo(rr); + return l < t.near || l > t.far ? null : { + distance: l, + point: rr.clone(), + object: s1 }; } -function os(s, e, t, n, i, r, o, a, l, c, h, u) { - mn.fromBufferAttribute(i, c), gn.fromBufferAttribute(i, h), xn.fromBufferAttribute(i, u); - let d = s.morphTargetInfluences; - if (r && d) { - Kr.set(0, 0, 0), es.set(0, 0, 0), ts.set(0, 0, 0); - for(let m = 0, x = r.length; m < x; m++){ - let v = d[m], g = r[m]; - v !== 0 && (zo.fromBufferAttribute(g, c), Uo.fromBufferAttribute(g, h), Oo.fromBufferAttribute(g, u), o ? (Kr.addScaledVector(zo, v), es.addScaledVector(Uo, v), ts.addScaledVector(Oo, v)) : (Kr.addScaledVector(zo.sub(mn), v), es.addScaledVector(Uo.sub(gn), v), ts.addScaledVector(Oo.sub(xn), v))); - } - mn.add(Kr), gn.add(es), xn.add(ts); - } - s.isSkinnedMesh && (s.boneTransform(c, mn), s.boneTransform(h, gn), s.boneTransform(u, xn)); - let f = hf(s, e, t, n, mn, gn, xn, Ho); - if (f) { - a && (ns.fromBufferAttribute(a, c), is.fromBufferAttribute(a, h), rs.fromBufferAttribute(a, u), f.uv = nt.getUV(Ho, mn, gn, xn, ns, is, rs, new X)), l && (ns.fromBufferAttribute(l, c), is.fromBufferAttribute(l, h), rs.fromBufferAttribute(l, u), f.uv2 = nt.getUV(Ho, mn, gn, xn, ns, is, rs, new X)); - let m = { - a: c, - b: h, - c: u, - normal: new M, +function ar(s1, e, t, n, i, r, a, o, c, l) { + s1.getVertexPosition(o, wi), s1.getVertexPosition(c, Ai), s1.getVertexPosition(l, Ri); + let h = gp(s1, e, t, n, wi, Ai, Ri, sr); + if (h) { + i && (tr.fromBufferAttribute(i, o), nr.fromBufferAttribute(i, c), ir.fromBufferAttribute(i, l), h.uv = Un.getInterpolation(sr, wi, Ai, Ri, tr, nr, ir, new Z)), r && (tr.fromBufferAttribute(r, o), nr.fromBufferAttribute(r, c), ir.fromBufferAttribute(r, l), h.uv1 = Un.getInterpolation(sr, wi, Ai, Ri, tr, nr, ir, new Z), h.uv2 = h.uv1), a && (oh.fromBufferAttribute(a, o), ch.fromBufferAttribute(a, c), lh.fromBufferAttribute(a, l), h.normal = Un.getInterpolation(sr, wi, Ai, Ri, oh, ch, lh, new A), h.normal.dot(n.direction) > 0 && h.normal.multiplyScalar(-1)); + let u = { + a: o, + b: c, + c: l, + normal: new A, materialIndex: 0 }; - nt.getNormal(mn, gn, xn, m.normal), f.face = m; + Un.getNormal(wi, Ai, Ri, u.normal), h.face = u; } - return f; + return h; } -var wn = class extends _e { - constructor(e = 1, t = 1, n = 1, i = 1, r = 1, o = 1){ - super(); - this.type = "BoxGeometry", this.parameters = { +var Ji = class s1 extends Ge { + constructor(e = 1, t = 1, n = 1, i = 1, r = 1, a = 1){ + super(), this.type = "BoxGeometry", this.parameters = { width: e, height: t, depth: n, widthSegments: i, heightSegments: r, - depthSegments: o + depthSegments: a }; - let a = this; - i = Math.floor(i), r = Math.floor(r), o = Math.floor(o); - let l = [], c = [], h = [], u = [], d = 0, f = 0; - m("z", "y", "x", -1, -1, n, t, e, o, r, 0), m("z", "y", "x", 1, -1, n, t, -e, o, r, 1), m("x", "z", "y", 1, 1, e, n, t, i, o, 2), m("x", "z", "y", 1, -1, e, n, -t, i, o, 3), m("x", "y", "z", 1, -1, e, t, n, i, r, 4), m("x", "y", "z", -1, -1, e, t, -n, i, r, 5), this.setIndex(l), this.setAttribute("position", new de(c, 3)), this.setAttribute("normal", new de(h, 3)), this.setAttribute("uv", new de(u, 2)); - function m(x, v, g, p, _, y, b, A, L, I, k) { - let B = y / L, P = b / I, w = y / 2, E = b / 2, D = A / 2, U = L + 1, F = I + 1, O = 0, ne = 0, ce = new M; - for(let V = 0; V < F; V++){ - let W = V * P - E; - for(let he = 0; he < U; he++){ - let le = he * B - w; - ce[x] = le * p, ce[v] = W * _, ce[g] = D, c.push(ce.x, ce.y, ce.z), ce[x] = 0, ce[v] = 0, ce[g] = A > 0 ? 1 : -1, h.push(ce.x, ce.y, ce.z), u.push(he / L), u.push(1 - V / I), O += 1; + let o = this; + i = Math.floor(i), r = Math.floor(r), a = Math.floor(a); + let c = [], l = [], h = [], u = [], d = 0, f = 0; + m("z", "y", "x", -1, -1, n, t, e, a, r, 0), m("z", "y", "x", 1, -1, n, t, -e, a, r, 1), m("x", "z", "y", 1, 1, e, n, t, i, a, 2), m("x", "z", "y", 1, -1, e, n, -t, i, a, 3), m("x", "y", "z", 1, -1, e, t, n, i, r, 4), m("x", "y", "z", -1, -1, e, t, -n, i, r, 5), this.setIndex(c), this.setAttribute("position", new ve(l, 3)), this.setAttribute("normal", new ve(h, 3)), this.setAttribute("uv", new ve(u, 2)); + function m(_, g, p, v, x, y, b, w, R, I, M) { + let T = y / R, O = b / I, Y = y / 2, $ = b / 2, U = w / 2, z = R + 1, q = I + 1, H = 0, ne = 0, W = new A; + for(let K = 0; K < q; K++){ + let D = K * O - $; + for(let G = 0; G < z; G++){ + let he = G * T - Y; + W[_] = he * v, W[g] = D * x, W[p] = U, l.push(W.x, W.y, W.z), W[_] = 0, W[g] = 0, W[p] = w > 0 ? 1 : -1, h.push(W.x, W.y, W.z), u.push(G / R), u.push(1 - K / I), H += 1; } } - for(let V = 0; V < I; V++)for(let W = 0; W < L; W++){ - let he = d + W + U * V, le = d + W + U * (V + 1), fe = d + (W + 1) + U * (V + 1), Be = d + (W + 1) + U * V; - l.push(he, le, Be), l.push(le, fe, Be), ne += 6; + for(let K = 0; K < I; K++)for(let D = 0; D < R; D++){ + let G = d + D + z * K, he = d + D + z * (K + 1), fe = d + (D + 1) + z * (K + 1), _e = d + (D + 1) + z * K; + c.push(G, he, _e), c.push(he, fe, _e), ne += 6; } - a.addGroup(f, ne, k), f += ne, d += O; + o.addGroup(f, ne, M), f += ne, d += H; } } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; + } static fromJSON(e) { - return new wn(e.width, e.height, e.depth, e.widthSegments, e.heightSegments, e.depthSegments); + return new s1(e.width, e.height, e.depth, e.widthSegments, e.heightSegments, e.depthSegments); } }; -function Ri(s) { +function $i(s1) { let e = {}; - for(let t in s){ + for(let t in s1){ e[t] = {}; - for(let n in s[t]){ - let i = s[t][n]; - i && (i.isColor || i.isMatrix3 || i.isMatrix4 || i.isVector2 || i.isVector3 || i.isVector4 || i.isTexture || i.isQuaternion) ? e[t][n] = i.clone() : Array.isArray(i) ? e[t][n] = i.slice() : e[t][n] = i; + for(let n in s1[t]){ + let i = s1[t][n]; + i && (i.isColor || i.isMatrix3 || i.isMatrix4 || i.isVector2 || i.isVector3 || i.isVector4 || i.isTexture || i.isQuaternion) ? i.isRenderTargetTexture ? (console.warn("UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms()."), e[t][n] = null) : e[t][n] = i.clone() : Array.isArray(i) ? e[t][n] = i.slice() : e[t][n] = i; } } return e; } -function yt(s) { +function Lt(s1) { let e = {}; - for(let t = 0; t < s.length; t++){ - let n = Ri(s[t]); + for(let t = 0; t < s1.length; t++){ + let n = $i(s1[t]); for(let i in n)e[i] = n[i]; } return e; } -var uf = { - clone: Ri, - merge: yt -}, df = `void main() { +function _p(s1) { + let e = []; + for(let t = 0; t < s1.length; t++)e.push(s1[t].clone()); + return e; +} +function bd(s1) { + return s1.getRenderTarget() === null ? s1.outputColorSpace : Qe.workingColorSpace; +} +var xp = { + clone: $i, + merge: Lt +}, vp = `void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); -}`, ff = `void main() { +}`, yp = `void main() { gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 ); -}`, sn = class extends dt { +}`, jt = class extends bt { constructor(e){ - super(); - this.type = "ShaderMaterial", this.defines = {}, this.uniforms = {}, this.vertexShader = df, this.fragmentShader = ff, this.linewidth = 1, this.wireframe = !1, this.wireframeLinewidth = 1, this.fog = !1, this.lights = !1, this.clipping = !1, this.extensions = { + super(), this.isShaderMaterial = !0, this.type = "ShaderMaterial", this.defines = {}, this.uniforms = {}, this.uniformsGroups = [], this.vertexShader = vp, this.fragmentShader = yp, this.linewidth = 1, this.wireframe = !1, this.wireframeLinewidth = 1, this.fog = !1, this.lights = !1, this.clipping = !1, this.forceSinglePass = !0, this.extensions = { derivatives: !1, fragDepth: !1, drawBuffers: !1, @@ -3420,64 +3916,59 @@ var uf = { 0, 0 ], - uv2: [ + uv1: [ 0, 0 ] - }, this.index0AttributeName = void 0, this.uniformsNeedUpdate = !1, this.glslVersion = null, e !== void 0 && (e.attributes !== void 0 && console.error("THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead."), this.setValues(e)); + }, this.index0AttributeName = void 0, this.uniformsNeedUpdate = !1, this.glslVersion = null, e !== void 0 && this.setValues(e); } copy(e) { - return super.copy(e), this.fragmentShader = e.fragmentShader, this.vertexShader = e.vertexShader, this.uniforms = Ri(e.uniforms), this.defines = Object.assign({}, e.defines), this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.lights = e.lights, this.clipping = e.clipping, this.extensions = Object.assign({}, e.extensions), this.glslVersion = e.glslVersion, this; + return super.copy(e), this.fragmentShader = e.fragmentShader, this.vertexShader = e.vertexShader, this.uniforms = $i(e.uniforms), this.uniformsGroups = _p(e.uniformsGroups), this.defines = Object.assign({}, e.defines), this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.fog = e.fog, this.lights = e.lights, this.clipping = e.clipping, this.extensions = Object.assign({}, e.extensions), this.glslVersion = e.glslVersion, this; } toJSON(e) { let t = super.toJSON(e); t.glslVersion = this.glslVersion, t.uniforms = {}; for(let i in this.uniforms){ - let o = this.uniforms[i].value; - o && o.isTexture ? t.uniforms[i] = { + let a = this.uniforms[i].value; + a && a.isTexture ? t.uniforms[i] = { type: "t", - value: o.toJSON(e).uuid - } : o && o.isColor ? t.uniforms[i] = { + value: a.toJSON(e).uuid + } : a && a.isColor ? t.uniforms[i] = { type: "c", - value: o.getHex() - } : o && o.isVector2 ? t.uniforms[i] = { + value: a.getHex() + } : a && a.isVector2 ? t.uniforms[i] = { type: "v2", - value: o.toArray() - } : o && o.isVector3 ? t.uniforms[i] = { + value: a.toArray() + } : a && a.isVector3 ? t.uniforms[i] = { type: "v3", - value: o.toArray() - } : o && o.isVector4 ? t.uniforms[i] = { + value: a.toArray() + } : a && a.isVector4 ? t.uniforms[i] = { type: "v4", - value: o.toArray() - } : o && o.isMatrix3 ? t.uniforms[i] = { + value: a.toArray() + } : a && a.isMatrix3 ? t.uniforms[i] = { type: "m3", - value: o.toArray() - } : o && o.isMatrix4 ? t.uniforms[i] = { + value: a.toArray() + } : a && a.isMatrix4 ? t.uniforms[i] = { type: "m4", - value: o.toArray() + value: a.toArray() } : t.uniforms[i] = { - value: o + value: a }; } - Object.keys(this.defines).length > 0 && (t.defines = this.defines), t.vertexShader = this.vertexShader, t.fragmentShader = this.fragmentShader; + Object.keys(this.defines).length > 0 && (t.defines = this.defines), t.vertexShader = this.vertexShader, t.fragmentShader = this.fragmentShader, t.lights = this.lights, t.clipping = this.clipping; let n = {}; for(let i in this.extensions)this.extensions[i] === !0 && (n[i] = !0); return Object.keys(n).length > 0 && (t.extensions = n), t; } -}; -sn.prototype.isShaderMaterial = !0; -var Ir = class extends Ne { +}, Cs = class extends Je { constructor(){ - super(); - this.type = "Camera", this.matrixWorldInverse = new pe, this.projectionMatrix = new pe, this.projectionMatrixInverse = new pe; + super(), this.isCamera = !0, this.type = "Camera", this.matrixWorldInverse = new ze, this.projectionMatrix = new ze, this.projectionMatrixInverse = new ze, this.coordinateSystem = vn; } copy(e, t) { - return super.copy(e, t), this.matrixWorldInverse.copy(e.matrixWorldInverse), this.projectionMatrix.copy(e.projectionMatrix), this.projectionMatrixInverse.copy(e.projectionMatrixInverse), this; + return super.copy(e, t), this.matrixWorldInverse.copy(e.matrixWorldInverse), this.projectionMatrix.copy(e.projectionMatrix), this.projectionMatrixInverse.copy(e.projectionMatrixInverse), this.coordinateSystem = e.coordinateSystem, this; } getWorldDirection(e) { - this.updateWorldMatrix(!0, !1); - let t = this.matrixWorld.elements; - return e.set(-t[8], -t[9], -t[10]).normalize(); + return super.getWorldDirection(e).negate(); } updateMatrixWorld(e) { super.updateMatrixWorld(e), this.matrixWorldInverse.copy(this.matrixWorld).invert(); @@ -3488,26 +3979,23 @@ var Ir = class extends Ne { clone() { return new this.constructor().copy(this); } -}; -Ir.prototype.isCamera = !0; -var ut = class extends Ir { +}, yt = class extends Cs { constructor(e = 50, t = 1, n = .1, i = 2e3){ - super(); - this.type = "PerspectiveCamera", this.fov = e, this.zoom = 1, this.near = n, this.far = i, this.focus = 10, this.aspect = t, this.view = null, this.filmGauge = 35, this.filmOffset = 0, this.updateProjectionMatrix(); + super(), this.isPerspectiveCamera = !0, this.type = "PerspectiveCamera", this.fov = e, this.zoom = 1, this.near = n, this.far = i, this.focus = 10, this.aspect = t, this.view = null, this.filmGauge = 35, this.filmOffset = 0, this.updateProjectionMatrix(); } copy(e, t) { return super.copy(e, t), this.fov = e.fov, this.zoom = e.zoom, this.near = e.near, this.far = e.far, this.focus = e.focus, this.aspect = e.aspect, this.view = e.view === null ? null : Object.assign({}, e.view), this.filmGauge = e.filmGauge, this.filmOffset = e.filmOffset, this; } setFocalLength(e) { let t = .5 * this.getFilmHeight() / e; - this.fov = dr * 2 * Math.atan(t), this.updateProjectionMatrix(); + this.fov = Zi * 2 * Math.atan(t), this.updateProjectionMatrix(); } getFocalLength() { - let e = Math.tan(Wn * .5 * this.fov); + let e = Math.tan(ai * .5 * this.fov); return .5 * this.getFilmHeight() / e; } getEffectiveFOV() { - return dr * 2 * Math.atan(Math.tan(Wn * .5 * this.fov) / this.zoom); + return Zi * 2 * Math.atan(Math.tan(ai * .5 * this.fov) / this.zoom); } getFilmWidth() { return this.filmGauge * Math.min(this.aspect, 1); @@ -3515,7 +4003,7 @@ var ut = class extends Ir { getFilmHeight() { return this.filmGauge / Math.max(this.aspect, 1); } - setViewOffset(e, t, n, i, r, o) { + setViewOffset(e, t, n, i, r, a) { this.aspect = e / t, this.view === null && (this.view = { enabled: !0, fullWidth: 1, @@ -3524,59 +4012,60 @@ var ut = class extends Ir { offsetY: 0, width: 1, height: 1 - }), this.view.enabled = !0, this.view.fullWidth = e, this.view.fullHeight = t, this.view.offsetX = n, this.view.offsetY = i, this.view.width = r, this.view.height = o, this.updateProjectionMatrix(); + }), this.view.enabled = !0, this.view.fullWidth = e, this.view.fullHeight = t, this.view.offsetX = n, this.view.offsetY = i, this.view.width = r, this.view.height = a, this.updateProjectionMatrix(); } clearViewOffset() { this.view !== null && (this.view.enabled = !1), this.updateProjectionMatrix(); } updateProjectionMatrix() { - let e = this.near, t = e * Math.tan(Wn * .5 * this.fov) / this.zoom, n = 2 * t, i = this.aspect * n, r = -.5 * i, o = this.view; + let e = this.near, t = e * Math.tan(ai * .5 * this.fov) / this.zoom, n = 2 * t, i = this.aspect * n, r = -.5 * i, a = this.view; if (this.view !== null && this.view.enabled) { - let l = o.fullWidth, c = o.fullHeight; - r += o.offsetX * i / l, t -= o.offsetY * n / c, i *= o.width / l, n *= o.height / c; + let c = a.fullWidth, l = a.fullHeight; + r += a.offsetX * i / c, t -= a.offsetY * n / l, i *= a.width / c, n *= a.height / l; } - let a = this.filmOffset; - a !== 0 && (r += e * a / this.getFilmWidth()), this.projectionMatrix.makePerspective(r, r + i, t, t - n, e, this.far), this.projectionMatrixInverse.copy(this.projectionMatrix).invert(); + let o = this.filmOffset; + o !== 0 && (r += e * o / this.getFilmWidth()), this.projectionMatrix.makePerspective(r, r + i, t, t - n, e, this.far, this.coordinateSystem), this.projectionMatrixInverse.copy(this.projectionMatrix).invert(); } toJSON(e) { let t = super.toJSON(e); return t.object.fov = this.fov, t.object.zoom = this.zoom, t.object.near = this.near, t.object.far = this.far, t.object.focus = this.focus, t.object.aspect = this.aspect, this.view !== null && (t.object.view = Object.assign({}, this.view)), t.object.filmGauge = this.filmGauge, t.object.filmOffset = this.filmOffset, t; } -}; -ut.prototype.isPerspectiveCamera = !0; -var ui = 90, di = 1, $s = class extends Ne { +}, Ci = -90, Pi = 1, _o = class extends Je { constructor(e, t, n){ - super(); - if (this.type = "CubeCamera", n.isWebGLCubeRenderTarget !== !0) { - console.error("THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter."); - return; - } - this.renderTarget = n; - let i = new ut(ui, di, e, t); - i.layers = this.layers, i.up.set(0, -1, 0), i.lookAt(new M(1, 0, 0)), this.add(i); - let r = new ut(ui, di, e, t); - r.layers = this.layers, r.up.set(0, -1, 0), r.lookAt(new M(-1, 0, 0)), this.add(r); - let o = new ut(ui, di, e, t); - o.layers = this.layers, o.up.set(0, 0, 1), o.lookAt(new M(0, 1, 0)), this.add(o); - let a = new ut(ui, di, e, t); - a.layers = this.layers, a.up.set(0, 0, -1), a.lookAt(new M(0, -1, 0)), this.add(a); - let l = new ut(ui, di, e, t); - l.layers = this.layers, l.up.set(0, -1, 0), l.lookAt(new M(0, 0, 1)), this.add(l); - let c = new ut(ui, di, e, t); - c.layers = this.layers, c.up.set(0, -1, 0), c.lookAt(new M(0, 0, -1)), this.add(c); + super(), this.type = "CubeCamera", this.renderTarget = n, this.coordinateSystem = null, this.activeMipmapLevel = 0; + let i = new yt(Ci, Pi, e, t); + i.layers = this.layers, this.add(i); + let r = new yt(Ci, Pi, e, t); + r.layers = this.layers, this.add(r); + let a = new yt(Ci, Pi, e, t); + a.layers = this.layers, this.add(a); + let o = new yt(Ci, Pi, e, t); + o.layers = this.layers, this.add(o); + let c = new yt(Ci, Pi, e, t); + c.layers = this.layers, this.add(c); + let l = new yt(Ci, Pi, e, t); + l.layers = this.layers, this.add(l); + } + updateCoordinateSystem() { + let e = this.coordinateSystem, t = this.children.concat(), [n, i, r, a, o, c] = t; + for (let l of t)this.remove(l); + if (e === vn) n.up.set(0, 1, 0), n.lookAt(1, 0, 0), i.up.set(0, 1, 0), i.lookAt(-1, 0, 0), r.up.set(0, 0, -1), r.lookAt(0, 1, 0), a.up.set(0, 0, 1), a.lookAt(0, -1, 0), o.up.set(0, 1, 0), o.lookAt(0, 0, 1), c.up.set(0, 1, 0), c.lookAt(0, 0, -1); + else if (e === Gr) n.up.set(0, -1, 0), n.lookAt(-1, 0, 0), i.up.set(0, -1, 0), i.lookAt(1, 0, 0), r.up.set(0, 0, 1), r.lookAt(0, 1, 0), a.up.set(0, 0, -1), a.lookAt(0, -1, 0), o.up.set(0, -1, 0), o.lookAt(0, 0, 1), c.up.set(0, -1, 0), c.lookAt(0, 0, -1); + else throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: " + e); + for (let l of t)this.add(l), l.updateMatrixWorld(); } update(e, t) { this.parent === null && this.updateMatrixWorld(); - let n = this.renderTarget, [i, r, o, a, l, c] = this.children, h = e.xr.enabled, u = e.getRenderTarget(); + let { renderTarget: n , activeMipmapLevel: i } = this; + this.coordinateSystem !== e.coordinateSystem && (this.coordinateSystem = e.coordinateSystem, this.updateCoordinateSystem()); + let [r, a, o, c, l, h] = this.children, u = e.getRenderTarget(), d = e.getActiveCubeFace(), f = e.getActiveMipmapLevel(), m = e.xr.enabled; e.xr.enabled = !1; - let d = n.texture.generateMipmaps; - n.texture.generateMipmaps = !1, e.setRenderTarget(n, 0), e.render(t, i), e.setRenderTarget(n, 1), e.render(t, r), e.setRenderTarget(n, 2), e.render(t, o), e.setRenderTarget(n, 3), e.render(t, a), e.setRenderTarget(n, 4), e.render(t, l), n.texture.generateMipmaps = d, e.setRenderTarget(n, 5), e.render(t, c), e.setRenderTarget(u), e.xr.enabled = h; + let _ = n.texture.generateMipmaps; + n.texture.generateMipmaps = !1, e.setRenderTarget(n, 0, i), e.render(t, r), e.setRenderTarget(n, 1, i), e.render(t, a), e.setRenderTarget(n, 2, i), e.render(t, o), e.setRenderTarget(n, 3, i), e.render(t, c), e.setRenderTarget(n, 4, i), e.render(t, l), n.texture.generateMipmaps = _, e.setRenderTarget(n, 5, i), e.render(t, h), e.setRenderTarget(u, d, f), e.xr.enabled = m, n.texture.needsPMREMUpdate = !0; } -}, ki = class extends ot { - constructor(e, t, n, i, r, o, a, l, c, h){ - e = e !== void 0 ? e : [], t = t !== void 0 ? t : Bi; - super(e, t, n, i, r, o, a, l, c, h); - this.flipY = !1; +}, Ki = class extends St { + constructor(e, t, n, i, r, a, o, c, l, h){ + e = e !== void 0 ? e : [], t = t !== void 0 ? t : zn, super(e, t, n, i, r, a, o, c, l, h), this.isCubeTexture = !0, this.flipY = !1; } get images() { return this.image; @@ -3584,16 +4073,25 @@ var ui = 90, di = 1, $s = class extends Ne { set images(e) { this.image = e; } -}; -ki.prototype.isCubeTexture = !0; -var js = class extends At { - constructor(e, t, n){ - Number.isInteger(t) && (console.warn("THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )"), t = n); - super(e, e, t); - t = t || {}, this.texture = new ki(void 0, t.mapping, t.wrapS, t.wrapT, t.magFilter, t.minFilter, t.format, t.type, t.anisotropy, t.encoding), this.texture.isRenderTargetTexture = !0, this.texture.generateMipmaps = t.generateMipmaps !== void 0 ? t.generateMipmaps : !1, this.texture.minFilter = t.minFilter !== void 0 ? t.minFilter : tt, this.texture._needsFlipEnvMap = !1; +}, xo = class extends qt { + constructor(e = 1, t = {}){ + super(e, e, t), this.isWebGLCubeRenderTarget = !0; + let n = { + width: e, + height: e, + depth: 1 + }, i = [ + n, + n, + n, + n, + n, + n + ]; + t.encoding !== void 0 && (Ms("THREE.WebGLCubeRenderTarget: option.encoding has been replaced by option.colorSpace."), t.colorSpace = t.encoding === ri ? vt : Xt), this.texture = new Ki(i, t.mapping, t.wrapS, t.wrapT, t.magFilter, t.minFilter, t.format, t.type, t.anisotropy, t.colorSpace), this.texture.isRenderTargetTexture = !0, this.texture.generateMipmaps = t.generateMipmaps !== void 0 ? t.generateMipmaps : !1, this.texture.minFilter = t.minFilter !== void 0 ? t.minFilter : mt; } fromEquirectangularTexture(e, t) { - this.texture.type = t.type, this.texture.format = ct, this.texture.encoding = t.encoding, this.texture.generateMipmaps = t.generateMipmaps, this.texture.minFilter = t.minFilter, this.texture.magFilter = t.magFilter; + this.texture.type = t.type, this.texture.colorSpace = t.colorSpace, this.texture.generateMipmaps = t.generateMipmaps, this.texture.minFilter = t.minFilter, this.texture.magFilter = t.magFilter; let n = { uniforms: { tEquirect: { @@ -3637,28 +4135,26 @@ var js = class extends At { } ` - }, i = new wn(5, 5, 5), r = new sn({ + }, i = new Ji(5, 5, 5), r = new jt({ name: "CubemapFromEquirect", - uniforms: Ri(n.uniforms), + uniforms: $i(n.uniforms), vertexShader: n.vertexShader, fragmentShader: n.fragmentShader, - side: it, - blending: vn + side: Ft, + blending: Dn }); r.uniforms.tEquirect.value = t; - let o = new st(i, r), a = t.minFilter; - return t.minFilter === Ui && (t.minFilter = tt), new $s(1, 10, this).update(e, o), t.minFilter = a, o.geometry.dispose(), o.material.dispose(), this; + let a = new Mt(i, r), o = t.minFilter; + return t.minFilter === li && (t.minFilter = mt), new _o(1, 10, this).update(e, a), t.minFilter = o, a.geometry.dispose(), a.material.dispose(), this; } clear(e, t, n, i) { let r = e.getRenderTarget(); - for(let o = 0; o < 6; o++)e.setRenderTarget(this, o), e.clear(t, n, i); + for(let a = 0; a < 6; a++)e.setRenderTarget(this, a), e.clear(t, n, i); e.setRenderTarget(r); } -}; -js.prototype.isWebGLCubeRenderTarget = !0; -var ko = new M, pf = new M, mf = new lt, Wt = class { - constructor(e = new M(1, 0, 0), t = 0){ - this.normal = e, this.constant = t; +}, Ja = new A, Mp = new A, Sp = new He, mn = class { + constructor(e = new A(1, 0, 0), t = 0){ + this.isPlane = !0, this.normal = e, this.constant = t; } set(e, t) { return this.normal.copy(e), this.constant = t, this; @@ -3670,7 +4166,7 @@ var ko = new M, pf = new M, mf = new lt, Wt = class { return this.normal.copy(e), this.constant = -t.dot(this.normal), this; } setFromCoplanarPoints(e, t, n) { - let i = ko.subVectors(n, t).cross(pf.subVectors(e, t)).normalize(); + let i = Ja.subVectors(n, t).cross(Mp.subVectors(e, t)).normalize(); return this.setFromNormalAndCoplanarPoint(i, e), this; } copy(e) { @@ -3690,13 +4186,13 @@ var ko = new M, pf = new M, mf = new lt, Wt = class { return this.distanceToPoint(e.center) - e.radius; } projectPoint(e, t) { - return t.copy(this.normal).multiplyScalar(-this.distanceToPoint(e)).add(e); + return t.copy(e).addScaledVector(this.normal, -this.distanceToPoint(e)); } intersectLine(e, t) { - let n = e.delta(ko), i = this.normal.dot(n); + let n = e.delta(Ja), i = this.normal.dot(n); if (i === 0) return this.distanceToPoint(e.start) === 0 ? t.copy(e.start) : null; let r = -(e.start.dot(this.normal) + this.constant) / i; - return r < 0 || r > 1 ? null : t.copy(n).multiplyScalar(r).add(e.start); + return r < 0 || r > 1 ? null : t.copy(e.start).addScaledVector(n, r); } intersectsLine(e) { let t = this.distanceToPoint(e.start), n = this.distanceToPoint(e.end); @@ -3712,7 +4208,7 @@ var ko = new M, pf = new M, mf = new lt, Wt = class { return e.copy(this.normal).multiplyScalar(-this.constant); } applyMatrix4(e, t) { - let n = t || mf.getNormalMatrix(e), i = this.coplanarPoint(ko).applyMatrix4(e), r = this.normal.applyMatrix3(n).normalize(); + let n = t || Sp.getNormalMatrix(e), i = this.coplanarPoint(Ja).applyMatrix4(e), r = this.normal.applyMatrix3(n).normalize(); return this.constant = -i.dot(r), this; } translate(e) { @@ -3724,38 +4220,43 @@ var ko = new M, pf = new M, mf = new lt, Wt = class { clone() { return new this.constructor().copy(this); } -}; -Wt.prototype.isPlane = !0; -var fi = new An, as = new M, Dr = class { - constructor(e = new Wt, t = new Wt, n = new Wt, i = new Wt, r = new Wt, o = new Wt){ +}, Yn = new Yt, or = new A, Ps = class { + constructor(e = new mn, t = new mn, n = new mn, i = new mn, r = new mn, a = new mn){ this.planes = [ e, t, n, i, r, - o + a ]; } - set(e, t, n, i, r, o) { - let a = this.planes; - return a[0].copy(e), a[1].copy(t), a[2].copy(n), a[3].copy(i), a[4].copy(r), a[5].copy(o), this; + set(e, t, n, i, r, a) { + let o = this.planes; + return o[0].copy(e), o[1].copy(t), o[2].copy(n), o[3].copy(i), o[4].copy(r), o[5].copy(a), this; } copy(e) { let t = this.planes; for(let n = 0; n < 6; n++)t[n].copy(e.planes[n]); return this; } - setFromProjectionMatrix(e) { - let t = this.planes, n = e.elements, i = n[0], r = n[1], o = n[2], a = n[3], l = n[4], c = n[5], h = n[6], u = n[7], d = n[8], f = n[9], m = n[10], x = n[11], v = n[12], g = n[13], p = n[14], _ = n[15]; - return t[0].setComponents(a - i, u - l, x - d, _ - v).normalize(), t[1].setComponents(a + i, u + l, x + d, _ + v).normalize(), t[2].setComponents(a + r, u + c, x + f, _ + g).normalize(), t[3].setComponents(a - r, u - c, x - f, _ - g).normalize(), t[4].setComponents(a - o, u - h, x - m, _ - p).normalize(), t[5].setComponents(a + o, u + h, x + m, _ + p).normalize(), this; + setFromProjectionMatrix(e, t = vn) { + let n = this.planes, i = e.elements, r = i[0], a = i[1], o = i[2], c = i[3], l = i[4], h = i[5], u = i[6], d = i[7], f = i[8], m = i[9], _ = i[10], g = i[11], p = i[12], v = i[13], x = i[14], y = i[15]; + if (n[0].setComponents(c - r, d - l, g - f, y - p).normalize(), n[1].setComponents(c + r, d + l, g + f, y + p).normalize(), n[2].setComponents(c + a, d + h, g + m, y + v).normalize(), n[3].setComponents(c - a, d - h, g - m, y - v).normalize(), n[4].setComponents(c - o, d - u, g - _, y - x).normalize(), t === vn) n[5].setComponents(c + o, d + u, g + _, y + x).normalize(); + else if (t === Gr) n[5].setComponents(o, u, _, x).normalize(); + else throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: " + t); + return this; } intersectsObject(e) { - let t = e.geometry; - return t.boundingSphere === null && t.computeBoundingSphere(), fi.copy(t.boundingSphere).applyMatrix4(e.matrixWorld), this.intersectsSphere(fi); + if (e.boundingSphere !== void 0) e.boundingSphere === null && e.computeBoundingSphere(), Yn.copy(e.boundingSphere).applyMatrix4(e.matrixWorld); + else { + let t = e.geometry; + t.boundingSphere === null && t.computeBoundingSphere(), Yn.copy(t.boundingSphere).applyMatrix4(e.matrixWorld); + } + return this.intersectsSphere(Yn); } intersectsSprite(e) { - return fi.center.set(0, 0, 0), fi.radius = .7071067811865476, fi.applyMatrix4(e.matrixWorld), this.intersectsSphere(fi); + return Yn.center.set(0, 0, 0), Yn.radius = .7071067811865476, Yn.applyMatrix4(e.matrixWorld), this.intersectsSphere(Yn); } intersectsSphere(e) { let t = this.planes, n = e.center, i = -e.radius; @@ -3766,7 +4267,7 @@ var fi = new An, as = new M, Dr = class { let t = this.planes; for(let n = 0; n < 6; n++){ let i = t[n]; - if (as.x = i.normal.x > 0 ? e.max.x : e.min.x, as.y = i.normal.y > 0 ? e.max.y : e.min.y, as.z = i.normal.z > 0 ? e.max.z : e.min.z, i.distanceToPoint(as) < 0) return !1; + if (or.x = i.normal.x > 0 ? e.max.x : e.min.x, or.y = i.normal.y > 0 ? e.max.y : e.min.y, or.z = i.normal.z > 0 ? e.max.z : e.min.z, i.distanceToPoint(or) < 0) return !1; } return !0; } @@ -3779,198 +4280,173 @@ var fi = new An, as = new M, Dr = class { return new this.constructor().copy(this); } }; -function rh() { - let s = null, e = !1, t = null, n = null; - function i(r, o) { - t(r, o), n = s.requestAnimationFrame(i); +function Ed() { + let s1 = null, e = !1, t = null, n = null; + function i(r, a) { + t(r, a), n = s1.requestAnimationFrame(i); } return { start: function() { - e !== !0 && t !== null && (n = s.requestAnimationFrame(i), e = !0); + e !== !0 && t !== null && (n = s1.requestAnimationFrame(i), e = !0); }, stop: function() { - s.cancelAnimationFrame(n), e = !1; + s1.cancelAnimationFrame(n), e = !1; }, setAnimationLoop: function(r) { t = r; }, setContext: function(r) { - s = r; + s1 = r; } }; } -function gf(s, e) { +function bp(s1, e) { let t = e.isWebGL2, n = new WeakMap; - function i(c, h) { - let u = c.array, d = c.usage, f = s.createBuffer(); - s.bindBuffer(h, f), s.bufferData(h, u, d), c.onUploadCallback(); - let m = 5126; - return u instanceof Float32Array ? m = 5126 : u instanceof Float64Array ? console.warn("THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.") : u instanceof Uint16Array ? c.isFloat16BufferAttribute ? t ? m = 5131 : console.warn("THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.") : m = 5123 : u instanceof Int16Array ? m = 5122 : u instanceof Uint32Array ? m = 5125 : u instanceof Int32Array ? m = 5124 : u instanceof Int8Array ? m = 5120 : (u instanceof Uint8Array || u instanceof Uint8ClampedArray) && (m = 5121), { + function i(l, h) { + let u = l.array, d = l.usage, f = s1.createBuffer(); + s1.bindBuffer(h, f), s1.bufferData(h, u, d), l.onUploadCallback(); + let m; + if (u instanceof Float32Array) m = s1.FLOAT; + else if (u instanceof Uint16Array) if (l.isFloat16BufferAttribute) if (t) m = s1.HALF_FLOAT; + else throw new Error("THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2."); + else m = s1.UNSIGNED_SHORT; + else if (u instanceof Int16Array) m = s1.SHORT; + else if (u instanceof Uint32Array) m = s1.UNSIGNED_INT; + else if (u instanceof Int32Array) m = s1.INT; + else if (u instanceof Int8Array) m = s1.BYTE; + else if (u instanceof Uint8Array) m = s1.UNSIGNED_BYTE; + else if (u instanceof Uint8ClampedArray) m = s1.UNSIGNED_BYTE; + else throw new Error("THREE.WebGLAttributes: Unsupported buffer data format: " + u); + return { buffer: f, type: m, bytesPerElement: u.BYTES_PER_ELEMENT, - version: c.version + version: l.version }; } - function r(c, h, u) { + function r(l, h, u) { let d = h.array, f = h.updateRange; - s.bindBuffer(u, c), f.count === -1 ? s.bufferSubData(u, 0, d) : (t ? s.bufferSubData(u, f.offset * d.BYTES_PER_ELEMENT, d, f.offset, f.count) : s.bufferSubData(u, f.offset * d.BYTES_PER_ELEMENT, d.subarray(f.offset, f.offset + f.count)), f.count = -1); + s1.bindBuffer(u, l), f.count === -1 ? s1.bufferSubData(u, 0, d) : (t ? s1.bufferSubData(u, f.offset * d.BYTES_PER_ELEMENT, d, f.offset, f.count) : s1.bufferSubData(u, f.offset * d.BYTES_PER_ELEMENT, d.subarray(f.offset, f.offset + f.count)), f.count = -1), h.onUploadCallback(); } - function o(c) { - return c.isInterleavedBufferAttribute && (c = c.data), n.get(c); - } - function a(c) { - c.isInterleavedBufferAttribute && (c = c.data); - let h = n.get(c); - h && (s.deleteBuffer(h.buffer), n.delete(c)); - } - function l(c, h) { - if (c.isGLBufferAttribute) { - let d = n.get(c); - (!d || d.version < c.version) && n.set(c, { - buffer: c.buffer, - type: c.type, - bytesPerElement: c.elementSize, - version: c.version + function a(l) { + return l.isInterleavedBufferAttribute && (l = l.data), n.get(l); + } + function o(l) { + l.isInterleavedBufferAttribute && (l = l.data); + let h = n.get(l); + h && (s1.deleteBuffer(h.buffer), n.delete(l)); + } + function c(l, h) { + if (l.isGLBufferAttribute) { + let d = n.get(l); + (!d || d.version < l.version) && n.set(l, { + buffer: l.buffer, + type: l.type, + bytesPerElement: l.elementSize, + version: l.version }); return; } - c.isInterleavedBufferAttribute && (c = c.data); - let u = n.get(c); - u === void 0 ? n.set(c, i(c, h)) : u.version < c.version && (r(u.buffer, c, h), u.version = c.version); + l.isInterleavedBufferAttribute && (l = l.data); + let u = n.get(l); + u === void 0 ? n.set(l, i(l, h)) : u.version < l.version && (r(u.buffer, l, h), u.version = l.version); } return { - get: o, - remove: a, - update: l + get: a, + remove: o, + update: c }; } -var Pi = class extends _e { +var $r = class s1 extends Ge { constructor(e = 1, t = 1, n = 1, i = 1){ - super(); - this.type = "PlaneGeometry", this.parameters = { + super(), this.type = "PlaneGeometry", this.parameters = { width: e, height: t, widthSegments: n, heightSegments: i }; - let r = e / 2, o = t / 2, a = Math.floor(n), l = Math.floor(i), c = a + 1, h = l + 1, u = e / a, d = t / l, f = [], m = [], x = [], v = []; - for(let g = 0; g < h; g++){ - let p = g * d - o; - for(let _ = 0; _ < c; _++){ - let y = _ * u - r; - m.push(y, -p, 0), x.push(0, 0, 1), v.push(_ / a), v.push(1 - g / l); + let r = e / 2, a = t / 2, o = Math.floor(n), c = Math.floor(i), l = o + 1, h = c + 1, u = e / o, d = t / c, f = [], m = [], _ = [], g = []; + for(let p = 0; p < h; p++){ + let v = p * d - a; + for(let x = 0; x < l; x++){ + let y = x * u - r; + m.push(y, -v, 0), _.push(0, 0, 1), g.push(x / o), g.push(1 - p / c); } } - for(let g = 0; g < l; g++)for(let p = 0; p < a; p++){ - let _ = p + c * g, y = p + c * (g + 1), b = p + 1 + c * (g + 1), A = p + 1 + c * g; - f.push(_, y, A), f.push(y, b, A); + for(let p = 0; p < c; p++)for(let v = 0; v < o; v++){ + let x = v + l * p, y = v + l * (p + 1), b = v + 1 + l * (p + 1), w = v + 1 + l * p; + f.push(x, y, w), f.push(y, b, w); } - this.setIndex(f), this.setAttribute("position", new de(m, 3)), this.setAttribute("normal", new de(x, 3)), this.setAttribute("uv", new de(v, 2)); + this.setIndex(f), this.setAttribute("position", new ve(m, 3)), this.setAttribute("normal", new ve(_, 3)), this.setAttribute("uv", new ve(g, 2)); } - static fromJSON(e) { - return new Pi(e.width, e.height, e.widthSegments, e.heightSegments); + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; } -}, xf = `#ifdef USE_ALPHAMAP - diffuseColor.a *= texture2D( alphaMap, vUv ).g; -#endif`, yf = `#ifdef USE_ALPHAMAP + static fromJSON(e) { + return new s1(e.width, e.height, e.widthSegments, e.heightSegments); + } +}, Ep = `#ifdef USE_ALPHAHASH + if ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard; +#endif`, Tp = `#ifdef USE_ALPHAHASH + const float ALPHA_HASH_SCALE = 0.05; + float hash2D( vec2 value ) { + return fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) ); + } + float hash3D( vec3 value ) { + return hash2D( vec2( hash2D( value.xy ), value.z ) ); + } + float getAlphaHashThreshold( vec3 position ) { + float maxDeriv = max( + length( dFdx( position.xyz ) ), + length( dFdy( position.xyz ) ) + ); + float pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv ); + vec2 pixScales = vec2( + exp2( floor( log2( pixScale ) ) ), + exp2( ceil( log2( pixScale ) ) ) + ); + vec2 alpha = vec2( + hash3D( floor( pixScales.x * position.xyz ) ), + hash3D( floor( pixScales.y * position.xyz ) ) + ); + float lerpFactor = fract( log2( pixScale ) ); + float x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y; + float a = min( lerpFactor, 1.0 - lerpFactor ); + vec3 cases = vec3( + x * x / ( 2.0 * a * ( 1.0 - a ) ), + ( x - 0.5 * a ) / ( 1.0 - a ), + 1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) ) + ); + float threshold = ( x < ( 1.0 - a ) ) + ? ( ( x < a ) ? cases.x : cases.y ) + : cases.z; + return clamp( threshold , 1.0e-6, 1.0 ); + } +#endif`, wp = `#ifdef USE_ALPHAMAP + diffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g; +#endif`, Ap = `#ifdef USE_ALPHAMAP uniform sampler2D alphaMap; -#endif`, vf = `#ifdef USE_ALPHATEST +#endif`, Rp = `#ifdef USE_ALPHATEST if ( diffuseColor.a < alphaTest ) discard; -#endif`, _f = `#ifdef USE_ALPHATEST +#endif`, Cp = `#ifdef USE_ALPHATEST uniform float alphaTest; -#endif`, Mf = `#ifdef USE_AOMAP - float ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0; +#endif`, Pp = `#ifdef USE_AOMAP + float ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0; reflectedLight.indirectDiffuse *= ambientOcclusion; #if defined( USE_ENVMAP ) && defined( STANDARD ) - float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) ); + float dotNV = saturate( dot( geometryNormal, geometryViewDir ) ); reflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness ); #endif -#endif`, bf = `#ifdef USE_AOMAP +#endif`, Lp = `#ifdef USE_AOMAP uniform sampler2D aoMap; uniform float aoMapIntensity; -#endif`, wf = "vec3 transformed = vec3( position );", Sf = `vec3 objectNormal = vec3( normal ); +#endif`, Ip = `vec3 transformed = vec3( position ); +#ifdef USE_ALPHAHASH + vPosition = vec3( position ); +#endif`, Up = `vec3 objectNormal = vec3( normal ); #ifdef USE_TANGENT vec3 objectTangent = vec3( tangent.xyz ); -#endif`, Tf = `vec3 BRDF_Lambert( const in vec3 diffuseColor ) { - return RECIPROCAL_PI * diffuseColor; -} -vec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) { - float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); - return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); -} -float V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) { - float a2 = pow2( alpha ); - float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) ); - float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) ); - return 0.5 / max( gv + gl, EPSILON ); -} -float D_GGX( const in float alpha, const in float dotNH ) { - float a2 = pow2( alpha ); - float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; - return RECIPROCAL_PI * a2 / pow2( denom ); -} -vec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness ) { - float alpha = pow2( roughness ); - vec3 halfDir = normalize( lightDir + viewDir ); - float dotNL = saturate( dot( normal, lightDir ) ); - float dotNV = saturate( dot( normal, viewDir ) ); - float dotNH = saturate( dot( normal, halfDir ) ); - float dotVH = saturate( dot( viewDir, halfDir ) ); - vec3 F = F_Schlick( f0, f90, dotVH ); - float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); - float D = D_GGX( alpha, dotNH ); - return F * ( V * D ); -} -vec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) { - const float LUT_SIZE = 64.0; - const float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE; - const float LUT_BIAS = 0.5 / LUT_SIZE; - float dotNV = saturate( dot( N, V ) ); - vec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) ); - uv = uv * LUT_SCALE + LUT_BIAS; - return uv; -} -float LTC_ClippedSphereFormFactor( const in vec3 f ) { - float l = length( f ); - return max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 ); -} -vec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) { - float x = dot( v1, v2 ); - float y = abs( x ); - float a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y; - float b = 3.4175940 + ( 4.1616724 + y ) * y; - float v = a / b; - float theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v; - return cross( v1, v2 ) * theta_sintheta; -} -vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) { - vec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ]; - vec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ]; - vec3 lightNormal = cross( v1, v2 ); - if( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 ); - vec3 T1, T2; - T1 = normalize( V - N * dot( V, N ) ); - T2 = - cross( N, T1 ); - mat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) ); - vec3 coords[ 4 ]; - coords[ 0 ] = mat * ( rectCoords[ 0 ] - P ); - coords[ 1 ] = mat * ( rectCoords[ 1 ] - P ); - coords[ 2 ] = mat * ( rectCoords[ 2 ] - P ); - coords[ 3 ] = mat * ( rectCoords[ 3 ] - P ); - coords[ 0 ] = normalize( coords[ 0 ] ); - coords[ 1 ] = normalize( coords[ 1 ] ); - coords[ 2 ] = normalize( coords[ 2 ] ); - coords[ 3 ] = normalize( coords[ 3 ] ); - vec3 vectorFormFactor = vec3( 0.0 ); - vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] ); - vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] ); - vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] ); - vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] ); - float result = LTC_ClippedSphereFormFactor( vectorFormFactor ); - return vec3( result ); -} -float G_BlinnPhong_Implicit( ) { +#endif`, Dp = `float G_BlinnPhong_Implicit( ) { return 0.25; } float D_BlinnPhong( const in float shininess, const in float dotNH ) { @@ -3984,41 +4460,83 @@ vec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in ve float G = G_BlinnPhong_Implicit( ); float D = D_BlinnPhong( shininess, dotNH ); return F * ( G * D ); -} -#if defined( USE_SHEEN ) -float D_Charlie( float roughness, float dotNH ) { - float alpha = pow2( roughness ); - float invAlpha = 1.0 / alpha; - float cos2h = dotNH * dotNH; - float sin2h = max( 1.0 - cos2h, 0.0078125 ); - return ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI ); -} -float V_Neubelt( float dotNV, float dotNL ) { - return saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) ); -} -vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) { - vec3 halfDir = normalize( lightDir + viewDir ); - float dotNL = saturate( dot( normal, lightDir ) ); - float dotNV = saturate( dot( normal, viewDir ) ); - float dotNH = saturate( dot( normal, halfDir ) ); - float D = D_Charlie( sheenRoughness, dotNH ); - float V = V_Neubelt( dotNV, dotNL ); - return sheenColor * ( D * V ); -} -#endif`, Ef = `#ifdef USE_BUMPMAP +} // validated`, Np = `#ifdef USE_IRIDESCENCE + const mat3 XYZ_TO_REC709 = mat3( + 3.2404542, -0.9692660, 0.0556434, + -1.5371385, 1.8760108, -0.2040259, + -0.4985314, 0.0415560, 1.0572252 + ); + vec3 Fresnel0ToIor( vec3 fresnel0 ) { + vec3 sqrtF0 = sqrt( fresnel0 ); + return ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 ); + } + vec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) { + return pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) ); + } + float IorToFresnel0( float transmittedIor, float incidentIor ) { + return pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor )); + } + vec3 evalSensitivity( float OPD, vec3 shift ) { + float phase = 2.0 * PI * OPD * 1.0e-9; + vec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 ); + vec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 ); + vec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 ); + vec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var ); + xyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) ); + xyz /= 1.0685e-7; + vec3 rgb = XYZ_TO_REC709 * xyz; + return rgb; + } + vec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) { + vec3 I; + float iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) ); + float sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) ); + float cosTheta2Sq = 1.0 - sinTheta2Sq; + if ( cosTheta2Sq < 0.0 ) { + return vec3( 1.0 ); + } + float cosTheta2 = sqrt( cosTheta2Sq ); + float R0 = IorToFresnel0( iridescenceIOR, outsideIOR ); + float R12 = F_Schlick( R0, 1.0, cosTheta1 ); + float T121 = 1.0 - R12; + float phi12 = 0.0; + if ( iridescenceIOR < outsideIOR ) phi12 = PI; + float phi21 = PI - phi12; + vec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) ); vec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR ); + vec3 R23 = F_Schlick( R1, 1.0, cosTheta2 ); + vec3 phi23 = vec3( 0.0 ); + if ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI; + if ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI; + if ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI; + float OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2; + vec3 phi = vec3( phi21 ) + phi23; + vec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 ); + vec3 r123 = sqrt( R123 ); + vec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 ); + vec3 C0 = R12 + Rs; + I = C0; + vec3 Cm = Rs - T121; + for ( int m = 1; m <= 2; ++ m ) { + Cm *= r123; + vec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi ); + I += Cm * Sm; + } + return max( I, vec3( 0.0 ) ); + } +#endif`, Op = `#ifdef USE_BUMPMAP uniform sampler2D bumpMap; uniform float bumpScale; vec2 dHdxy_fwd() { - vec2 dSTdx = dFdx( vUv ); - vec2 dSTdy = dFdy( vUv ); - float Hll = bumpScale * texture2D( bumpMap, vUv ).x; - float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll; - float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll; + vec2 dSTdx = dFdx( vBumpMapUv ); + vec2 dSTdy = dFdy( vBumpMapUv ); + float Hll = bumpScale * texture2D( bumpMap, vBumpMapUv ).x; + float dBx = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdx ).x - Hll; + float dBy = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdy ).x - Hll; return vec2( dBx, dBy ); } vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) { - vec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) ); - vec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) ); + vec3 vSigmaX = dFdx( surf_pos.xyz ); + vec3 vSigmaY = dFdy( surf_pos.xyz ); vec3 vN = surf_norm; vec3 R1 = cross( vSigmaY, vN ); vec3 R2 = cross( vN, vSigmaX ); @@ -4026,7 +4544,7 @@ vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 no vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 ); return normalize( abs( fDet ) * surf_norm - vGrad ); } -#endif`, Af = `#if NUM_CLIPPING_PLANES > 0 +#endif`, Fp = `#if NUM_CLIPPING_PLANES > 0 vec4 plane; #pragma unroll_loop_start for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) { @@ -4044,26 +4562,26 @@ vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 no #pragma unroll_loop_end if ( clipped ) discard; #endif -#endif`, Cf = `#if NUM_CLIPPING_PLANES > 0 +#endif`, Bp = `#if NUM_CLIPPING_PLANES > 0 varying vec3 vClipPosition; uniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ]; -#endif`, Lf = `#if NUM_CLIPPING_PLANES > 0 +#endif`, zp = `#if NUM_CLIPPING_PLANES > 0 varying vec3 vClipPosition; -#endif`, Rf = `#if NUM_CLIPPING_PLANES > 0 +#endif`, Vp = `#if NUM_CLIPPING_PLANES > 0 vClipPosition = - mvPosition.xyz; -#endif`, Pf = `#if defined( USE_COLOR_ALPHA ) +#endif`, kp = `#if defined( USE_COLOR_ALPHA ) diffuseColor *= vColor; #elif defined( USE_COLOR ) diffuseColor.rgb *= vColor; -#endif`, If = `#if defined( USE_COLOR_ALPHA ) +#endif`, Hp = `#if defined( USE_COLOR_ALPHA ) varying vec4 vColor; #elif defined( USE_COLOR ) varying vec3 vColor; -#endif`, Df = `#if defined( USE_COLOR_ALPHA ) +#endif`, Gp = `#if defined( USE_COLOR_ALPHA ) varying vec4 vColor; #elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) varying vec3 vColor; -#endif`, Ff = `#if defined( USE_COLOR_ALPHA ) +#endif`, Wp = `#if defined( USE_COLOR_ALPHA ) vColor = vec4( 1.0 ); #elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) vColor = vec3( 1.0 ); @@ -4073,7 +4591,7 @@ vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 no #endif #ifdef USE_INSTANCING_COLOR vColor.xyz *= instanceColor.xyz; -#endif`, Nf = `#define PI 3.141592653589793 +#endif`, Xp = `#define PI 3.141592653589793 #define PI2 6.283185307179586 #define PI_HALF 1.5707963267948966 #define RECIPROCAL_PI 0.3183098861837907 @@ -4084,10 +4602,11 @@ vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 no #endif #define whiteComplement( a ) ( 1.0 - saturate( a ) ) float pow2( const in float x ) { return x*x; } +vec3 pow2( const in vec3 x ) { return x*x; } float pow3( const in float x ) { return x*x*x; } float pow4( const in float x ) { float x2 = x*x; return x2*x2; } float max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); } -float average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); } +float average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); } highp float rand( const in vec2 uv ) { const highp float a = 12.9898, b = 78.233, c = 43758.5453; highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); @@ -4112,14 +4631,9 @@ struct ReflectedLight { vec3 indirectDiffuse; vec3 indirectSpecular; }; -struct GeometricContext { - vec3 position; - vec3 normal; - vec3 viewDir; -#ifdef USE_CLEARCOAT - vec3 clearcoatNormal; +#ifdef USE_ALPHAHASH + varying vec3 vPosition; #endif -}; vec3 transformDirection( in vec3 dir, in mat4 matrix ) { return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); } @@ -4133,9 +4647,9 @@ mat3 transposeMat3( const in mat3 m ) { tmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z ); return tmp; } -float linearToRelativeLuminance( const in vec3 color ) { - vec3 weights = vec3( 0.2126, 0.7152, 0.0722 ); - return dot( weights, color.rgb ); +float luminance( const in vec3 rgb ) { + const vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 ); + return dot( weights, rgb ); } bool isPerspectiveMatrix( mat4 m ) { return m[ 2 ][ 3 ] == - 1.0; @@ -4144,10 +4658,19 @@ vec2 equirectUv( in vec3 dir ) { float u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5; float v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5; return vec2( u, v ); -}`, Bf = `#ifdef ENVMAP_TYPE_CUBE_UV - #define cubeUV_maxMipLevel 8.0 +} +vec3 BRDF_Lambert( const in vec3 diffuseColor ) { + return RECIPROCAL_PI * diffuseColor; +} +vec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) { + float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); + return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); +} +float F_Schlick( const in float f0, const in float f90, const in float dotVH ) { + float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); + return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); +} // validated`, qp = `#ifdef ENVMAP_TYPE_CUBE_UV #define cubeUV_minMipLevel 4.0 - #define cubeUV_maxTileSize 256.0 #define cubeUV_minTileSize 16.0 float getFace( vec3 direction ) { vec3 absDirection = abs( direction ); @@ -4187,52 +4710,53 @@ vec2 equirectUv( in vec3 dir ) { float filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 ); mipInt = max( mipInt, cubeUV_minMipLevel ); float faceSize = exp2( mipInt ); - float texelSize = 1.0 / ( 3.0 * cubeUV_maxTileSize ); - vec2 uv = getUV( direction, face ) * ( faceSize - 1.0 ) + 0.5; + highp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0; if ( face > 2.0 ) { uv.y += faceSize; face -= 3.0; } uv.x += face * faceSize; - if ( mipInt < cubeUV_maxMipLevel ) { - uv.y += 2.0 * cubeUV_maxTileSize; - } - uv.y += filterInt * 2.0 * cubeUV_minTileSize; - uv.x += 3.0 * max( 0.0, cubeUV_maxTileSize - 2.0 * faceSize ); - uv *= texelSize; - return texture2D( envMap, uv ).rgb; + uv.x += filterInt * 3.0 * cubeUV_minTileSize; + uv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize ); + uv.x *= CUBEUV_TEXEL_WIDTH; + uv.y *= CUBEUV_TEXEL_HEIGHT; + #ifdef texture2DGradEXT + return texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb; + #else + return texture2D( envMap, uv ).rgb; + #endif } - #define r0 1.0 - #define v0 0.339 - #define m0 - 2.0 - #define r1 0.8 - #define v1 0.276 - #define m1 - 1.0 - #define r4 0.4 - #define v4 0.046 - #define m4 2.0 - #define r5 0.305 - #define v5 0.016 - #define m5 3.0 - #define r6 0.21 - #define v6 0.0038 - #define m6 4.0 + #define cubeUV_r0 1.0 + #define cubeUV_v0 0.339 + #define cubeUV_m0 - 2.0 + #define cubeUV_r1 0.8 + #define cubeUV_v1 0.276 + #define cubeUV_m1 - 1.0 + #define cubeUV_r4 0.4 + #define cubeUV_v4 0.046 + #define cubeUV_m4 2.0 + #define cubeUV_r5 0.305 + #define cubeUV_v5 0.016 + #define cubeUV_m5 3.0 + #define cubeUV_r6 0.21 + #define cubeUV_v6 0.0038 + #define cubeUV_m6 4.0 float roughnessToMip( float roughness ) { float mip = 0.0; - if ( roughness >= r1 ) { - mip = ( r0 - roughness ) * ( m1 - m0 ) / ( r0 - r1 ) + m0; - } else if ( roughness >= r4 ) { - mip = ( r1 - roughness ) * ( m4 - m1 ) / ( r1 - r4 ) + m1; - } else if ( roughness >= r5 ) { - mip = ( r4 - roughness ) * ( m5 - m4 ) / ( r4 - r5 ) + m4; - } else if ( roughness >= r6 ) { - mip = ( r5 - roughness ) * ( m6 - m5 ) / ( r5 - r6 ) + m5; + if ( roughness >= cubeUV_r1 ) { + mip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0; + } else if ( roughness >= cubeUV_r4 ) { + mip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1; + } else if ( roughness >= cubeUV_r5 ) { + mip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4; + } else if ( roughness >= cubeUV_r6 ) { + mip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5; } else { mip = - 2.0 * log2( 1.16 * roughness ); } return mip; } vec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) { - float mip = clamp( roughnessToMip( roughness ), m0, cubeUV_maxMipLevel ); + float mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP ); float mipF = fract( mip ); float mipInt = floor( mip ); vec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt ); @@ -4243,7 +4767,7 @@ vec2 equirectUv( in vec3 dir ) { return vec4( mix( color0, color1, mipF ), 1.0 ); } } -#endif`, zf = `vec3 transformedNormal = objectNormal; +#endif`, Yp = `vec3 transformedNormal = objectNormal; #ifdef USE_INSTANCING mat3 m = mat3( instanceMatrix ); transformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) ); @@ -4258,27 +4782,46 @@ transformedNormal = normalMatrix * transformedNormal; #ifdef FLIP_SIDED transformedTangent = - transformedTangent; #endif -#endif`, Uf = `#ifdef USE_DISPLACEMENTMAP +#endif`, Zp = `#ifdef USE_DISPLACEMENTMAP uniform sampler2D displacementMap; uniform float displacementScale; uniform float displacementBias; -#endif`, Of = `#ifdef USE_DISPLACEMENTMAP - transformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias ); -#endif`, Hf = `#ifdef USE_EMISSIVEMAP - vec4 emissiveColor = texture2D( emissiveMap, vUv ); - emissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb; +#endif`, Jp = `#ifdef USE_DISPLACEMENTMAP + transformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias ); +#endif`, $p = `#ifdef USE_EMISSIVEMAP + vec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv ); totalEmissiveRadiance *= emissiveColor.rgb; -#endif`, kf = `#ifdef USE_EMISSIVEMAP +#endif`, Kp = `#ifdef USE_EMISSIVEMAP uniform sampler2D emissiveMap; -#endif`, Gf = "gl_FragColor = linearToOutputTexel( gl_FragColor );", Vf = `vec4 LinearToLinear( in vec4 value ) { +#endif`, Qp = "gl_FragColor = linearToOutputTexel( gl_FragColor );", jp = ` +const mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3( + vec3( 0.8224621, 0.177538, 0.0 ), + vec3( 0.0331941, 0.9668058, 0.0 ), + vec3( 0.0170827, 0.0723974, 0.9105199 ) +); +const mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3( + vec3( 1.2249401, - 0.2249404, 0.0 ), + vec3( - 0.0420569, 1.0420571, 0.0 ), + vec3( - 0.0196376, - 0.0786361, 1.0982735 ) +); +vec4 LinearSRGBToLinearDisplayP3( in vec4 value ) { + return vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a ); +} +vec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) { + return vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a ); +} +vec4 LinearTransferOETF( in vec4 value ) { return value; } -vec4 sRGBToLinear( in vec4 value ) { - return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a ); +vec4 sRGBTransferOETF( in vec4 value ) { + return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); +} +vec4 LinearToLinear( in vec4 value ) { + return value; } vec4 LinearTosRGB( in vec4 value ) { - return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); -}`, Wf = `#ifdef USE_ENVMAP + return sRGBTransferOETF( value ); +}`, em = `#ifdef USE_ENVMAP #ifdef ENV_WORLDPOS vec3 cameraToFrag; if ( isOrthographic ) { @@ -4297,9 +4840,6 @@ vec4 LinearTosRGB( in vec4 value ) { #endif #ifdef ENVMAP_TYPE_CUBE vec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) ); - envColor = envMapTexelToLinear( envColor ); - #elif defined( ENVMAP_TYPE_CUBE_UV ) - vec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 ); #else vec4 envColor = vec4( 0.0 ); #endif @@ -4310,7 +4850,7 @@ vec4 LinearTosRGB( in vec4 value ) { #elif defined( ENVMAP_BLENDING_ADD ) outgoingLight += envColor.xyz * specularStrength * reflectivity; #endif -#endif`, qf = `#ifdef USE_ENVMAP +#endif`, tm = `#ifdef USE_ENVMAP uniform float envMapIntensity; uniform float flipEnvMap; #ifdef ENVMAP_TYPE_CUBE @@ -4319,9 +4859,9 @@ vec4 LinearTosRGB( in vec4 value ) { uniform sampler2D envMap; #endif -#endif`, Xf = `#ifdef USE_ENVMAP +#endif`, nm = `#ifdef USE_ENVMAP uniform float reflectivity; - #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) + #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) #define ENV_WORLDPOS #endif #ifdef ENV_WORLDPOS @@ -4330,8 +4870,8 @@ vec4 LinearTosRGB( in vec4 value ) { #else varying vec3 vReflect; #endif -#endif`, Jf = `#ifdef USE_ENVMAP - #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG ) +#endif`, im = `#ifdef USE_ENVMAP + #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) #define ENV_WORLDPOS #endif #ifdef ENV_WORLDPOS @@ -4341,7 +4881,7 @@ vec4 LinearTosRGB( in vec4 value ) { varying vec3 vReflect; uniform float refractionRatio; #endif -#endif`, Yf = `#ifdef USE_ENVMAP +#endif`, sm = `#ifdef USE_ENVMAP #ifdef ENV_WORLDPOS vWorldPosition = worldPosition.xyz; #else @@ -4358,18 +4898,18 @@ vec4 LinearTosRGB( in vec4 value ) { vReflect = refract( cameraToVertex, worldNormal, refractionRatio ); #endif #endif -#endif`, Zf = `#ifdef USE_FOG +#endif`, rm = `#ifdef USE_FOG vFogDepth = - mvPosition.z; -#endif`, $f = `#ifdef USE_FOG +#endif`, am = `#ifdef USE_FOG varying float vFogDepth; -#endif`, jf = `#ifdef USE_FOG +#endif`, om = `#ifdef USE_FOG #ifdef FOG_EXP2 float fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth ); #else float fogFactor = smoothstep( fogNear, fogFar, vFogDepth ); #endif gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor ); -#endif`, Qf = `#ifdef USE_FOG +#endif`, cm = `#ifdef USE_FOG uniform vec3 fogColor; varying float vFogDepth; #ifdef FOG_EXP2 @@ -4378,7 +4918,7 @@ vec4 LinearTosRGB( in vec4 value ) { uniform float fogNear; uniform float fogFar; #endif -#endif`, Kf = `#ifdef USE_GRADIENTMAP +#endif`, lm = `#ifdef USE_GRADIENTMAP uniform sampler2D gradientMap; #endif vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { @@ -4387,93 +4927,37 @@ vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { #ifdef USE_GRADIENTMAP return vec3( texture2D( gradientMap, coord ).r ); #else - return ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 ); - #endif -}`, ep = `#ifdef USE_LIGHTMAP - vec4 lightMapTexel = texture2D( lightMap, vUv2 ); - vec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity; - #ifndef PHYSICALLY_CORRECT_LIGHTS - lightMapIrradiance *= PI; + vec2 fw = fwidth( coord ) * 0.5; + return mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) ); #endif +}`, hm = `#ifdef USE_LIGHTMAP + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity; reflectedLight.indirectDiffuse += lightMapIrradiance; -#endif`, tp = `#ifdef USE_LIGHTMAP +#endif`, um = `#ifdef USE_LIGHTMAP uniform sampler2D lightMap; uniform float lightMapIntensity; -#endif`, np = `vec3 diffuse = vec3( 1.0 ); -GeometricContext geometry; -geometry.position = mvPosition.xyz; -geometry.normal = normalize( transformedNormal ); -geometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz ); -GeometricContext backGeometry; -backGeometry.position = geometry.position; -backGeometry.normal = -geometry.normal; -backGeometry.viewDir = geometry.viewDir; -vLightFront = vec3( 0.0 ); -vIndirectFront = vec3( 0.0 ); -#ifdef DOUBLE_SIDED - vLightBack = vec3( 0.0 ); - vIndirectBack = vec3( 0.0 ); -#endif -IncidentLight directLight; -float dotNL; -vec3 directLightColor_Diffuse; -vIndirectFront += getAmbientLightIrradiance( ambientLightColor ); -vIndirectFront += getLightProbeIrradiance( lightProbe, geometry.normal ); -#ifdef DOUBLE_SIDED - vIndirectBack += getAmbientLightIrradiance( ambientLightColor ); - vIndirectBack += getLightProbeIrradiance( lightProbe, backGeometry.normal ); -#endif -#if NUM_POINT_LIGHTS > 0 - #pragma unroll_loop_start - for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) { - getPointLightInfo( pointLights[ i ], geometry, directLight ); - dotNL = dot( geometry.normal, directLight.direction ); - directLightColor_Diffuse = directLight.color; - vLightFront += saturate( dotNL ) * directLightColor_Diffuse; - #ifdef DOUBLE_SIDED - vLightBack += saturate( - dotNL ) * directLightColor_Diffuse; - #endif - } - #pragma unroll_loop_end -#endif -#if NUM_SPOT_LIGHTS > 0 - #pragma unroll_loop_start - for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) { - getSpotLightInfo( spotLights[ i ], geometry, directLight ); - dotNL = dot( geometry.normal, directLight.direction ); - directLightColor_Diffuse = directLight.color; - vLightFront += saturate( dotNL ) * directLightColor_Diffuse; - #ifdef DOUBLE_SIDED - vLightBack += saturate( - dotNL ) * directLightColor_Diffuse; - #endif - } - #pragma unroll_loop_end -#endif -#if NUM_DIR_LIGHTS > 0 - #pragma unroll_loop_start - for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) { - getDirectionalLightInfo( directionalLights[ i ], geometry, directLight ); - dotNL = dot( geometry.normal, directLight.direction ); - directLightColor_Diffuse = directLight.color; - vLightFront += saturate( dotNL ) * directLightColor_Diffuse; - #ifdef DOUBLE_SIDED - vLightBack += saturate( - dotNL ) * directLightColor_Diffuse; - #endif - } - #pragma unroll_loop_end -#endif -#if NUM_HEMI_LIGHTS > 0 - #pragma unroll_loop_start - for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) { - vIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry.normal ); - #ifdef DOUBLE_SIDED - vIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry.normal ); - #endif - } - #pragma unroll_loop_end -#endif`, ip = `uniform bool receiveShadow; +#endif`, dm = `LambertMaterial material; +material.diffuseColor = diffuseColor.rgb; +material.specularStrength = specularStrength;`, fm = `varying vec3 vViewPosition; +struct LambertMaterial { + vec3 diffuseColor; + float specularStrength; +}; +void RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_Lambert +#define RE_IndirectDiffuse RE_IndirectDiffuse_Lambert`, pm = `uniform bool receiveShadow; uniform vec3 ambientLightColor; -uniform vec3 lightProbe[ 9 ]; +#if defined( USE_LIGHT_PROBES ) + uniform vec3 lightProbe[ 9 ]; +#endif vec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) { float x = normal.x, y = normal.y, z = normal.z; vec3 result = shCoefficients[ 0 ] * 0.886227; @@ -4497,17 +4981,17 @@ vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) { return irradiance; } float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) { - #if defined ( PHYSICALLY_CORRECT_LIGHTS ) + #if defined ( LEGACY_LIGHTS ) + if ( cutoffDistance > 0.0 && decayExponent > 0.0 ) { + return pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent ); + } + return 1.0; + #else float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 ); if ( cutoffDistance > 0.0 ) { distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) ); } return distanceFalloff; - #else - if ( cutoffDistance > 0.0 && decayExponent > 0.0 ) { - return pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent ); - } - return 1.0; #endif } float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) { @@ -4519,7 +5003,7 @@ float getSpotAttenuation( const in float coneCosine, const in float penumbraCosi vec3 color; }; uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ]; - void getDirectionalLightInfo( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight light ) { + void getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) { light.color = directionalLight.color; light.direction = directionalLight.direction; light.visible = true; @@ -4533,8 +5017,8 @@ float getSpotAttenuation( const in float coneCosine, const in float penumbraCosi float decay; }; uniform PointLight pointLights[ NUM_POINT_LIGHTS ]; - void getPointLightInfo( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight light ) { - vec3 lVector = pointLight.position - geometry.position; + void getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) { + vec3 lVector = pointLight.position - geometryPosition; light.direction = normalize( lVector ); float lightDistance = length( lVector ); light.color = pointLight.color; @@ -4553,8 +5037,8 @@ float getSpotAttenuation( const in float coneCosine, const in float penumbraCosi float penumbraCos; }; uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ]; - void getSpotLightInfo( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight light ) { - vec3 lVector = spotLight.position - geometry.position; + void getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) { + vec3 lVector = spotLight.position - geometryPosition; light.direction = normalize( lVector ); float angleCos = dot( light.direction, spotLight.direction ); float spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos ); @@ -4592,12 +5076,9 @@ float getSpotAttenuation( const in float coneCosine, const in float penumbraCosi vec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight ); return irradiance; } -#endif`, rp = `#if defined( USE_ENVMAP ) - #ifdef ENVMAP_MODE_REFRACTION - uniform float refractionRatio; - #endif +#endif`, mm = `#ifdef USE_ENVMAP vec3 getIBLIrradiance( const in vec3 normal ) { - #if defined( ENVMAP_TYPE_CUBE_UV ) + #ifdef ENVMAP_TYPE_CUBE_UV vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); vec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 ); return PI * envMapColor.rgb * envMapIntensity; @@ -4606,14 +5087,9 @@ float getSpotAttenuation( const in float coneCosine, const in float penumbraCosi #endif } vec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) { - #if defined( ENVMAP_TYPE_CUBE_UV ) - vec3 reflectVec; - #ifdef ENVMAP_MODE_REFLECTION - reflectVec = reflect( - viewDir, normal ); - reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) ); - #else - reflectVec = refract( - viewDir, normal, refractionRatio ); - #endif + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 reflectVec = reflect( - viewDir, normal ); + reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) ); reflectVec = inverseTransformDirection( reflectVec, viewMatrix ); vec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness ); return envMapColor.rgb * envMapIntensity; @@ -4621,57 +5097,68 @@ float getSpotAttenuation( const in float coneCosine, const in float penumbraCosi return vec3( 0.0 ); #endif } -#endif`, sp = `ToonMaterial material; -material.diffuseColor = diffuseColor.rgb;`, op = `varying vec3 vViewPosition; + #ifdef USE_ANISOTROPY + vec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 bentNormal = cross( bitangent, viewDir ); + bentNormal = normalize( cross( bentNormal, bitangent ) ); + bentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) ); + return getIBLRadiance( viewDir, bentNormal, roughness ); + #else + return vec3( 0.0 ); + #endif + } + #endif +#endif`, gm = `ToonMaterial material; +material.diffuseColor = diffuseColor.rgb;`, _m = `varying vec3 vViewPosition; struct ToonMaterial { vec3 diffuseColor; }; -void RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { - vec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color; +void RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { + vec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color; reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } -void RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { +void RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } #define RE_Direct RE_Direct_Toon -#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon -#define Material_LightProbeLOD( material ) (0)`, ap = `BlinnPhongMaterial material; +#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon`, xm = `BlinnPhongMaterial material; material.diffuseColor = diffuseColor.rgb; material.specularColor = specular; material.specularShininess = shininess; -material.specularStrength = specularStrength;`, lp = `varying vec3 vViewPosition; +material.specularStrength = specularStrength;`, vm = `varying vec3 vViewPosition; struct BlinnPhongMaterial { vec3 diffuseColor; vec3 specularColor; float specularShininess; float specularStrength; }; -void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { - float dotNL = saturate( dot( geometry.normal, directLight.direction ) ); +void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); vec3 irradiance = dotNL * directLight.color; reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); - reflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularShininess ) * material.specularStrength; + reflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength; } -void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { +void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } #define RE_Direct RE_Direct_BlinnPhong -#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong -#define Material_LightProbeLOD( material ) (0)`, cp = `PhysicalMaterial material; +#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong`, ym = `PhysicalMaterial material; material.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor ); -vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) ); +vec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) ); float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z ); material.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness; material.roughness = min( material.roughness, 1.0 ); #ifdef IOR - #ifdef SPECULAR + material.ior = ior; + #ifdef USE_SPECULAR float specularIntensityFactor = specularIntensity; vec3 specularColorFactor = specularColor; - #ifdef USE_SPECULARINTENSITYMAP - specularIntensityFactor *= texture2D( specularIntensityMap, vUv ).a; + #ifdef USE_SPECULAR_COLORMAP + specularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb; #endif - #ifdef USE_SPECULARCOLORMAP - specularColorFactor *= specularColorMapTexelToLinear( texture2D( specularColorMap, vUv ) ).rgb; + #ifdef USE_SPECULAR_INTENSITYMAP + specularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a; #endif material.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor ); #else @@ -4679,7 +5166,7 @@ material.roughness = min( material.roughness, 1.0 ); vec3 specularColorFactor = vec3( 1.0 ); material.specularF90 = 1.0; #endif - material.specularColor = mix( min( pow2( ( ior - 1.0 ) / ( ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor ); + material.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor ); #else material.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor ); material.specularF90 = 1.0; @@ -4690,25 +5177,52 @@ material.roughness = min( material.roughness, 1.0 ); material.clearcoatF0 = vec3( 0.04 ); material.clearcoatF90 = 1.0; #ifdef USE_CLEARCOATMAP - material.clearcoat *= texture2D( clearcoatMap, vUv ).x; + material.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x; #endif #ifdef USE_CLEARCOAT_ROUGHNESSMAP - material.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y; + material.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y; #endif material.clearcoat = saturate( material.clearcoat ); material.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 ); material.clearcoatRoughness += geometryRoughness; material.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 ); #endif +#ifdef USE_IRIDESCENCE + material.iridescence = iridescence; + material.iridescenceIOR = iridescenceIOR; + #ifdef USE_IRIDESCENCEMAP + material.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r; + #endif + #ifdef USE_IRIDESCENCE_THICKNESSMAP + material.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum; + #else + material.iridescenceThickness = iridescenceThicknessMaximum; + #endif +#endif #ifdef USE_SHEEN material.sheenColor = sheenColor; - #ifdef USE_SHEENCOLORMAP - material.sheenColor *= sheenColorMapTexelToLinear( texture2D( sheenColorMap, vUv ) ).rgb; + #ifdef USE_SHEEN_COLORMAP + material.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb; #endif material.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 ); - #ifdef USE_SHEENROUGHNESSMAP - material.sheenRoughness *= texture2D( sheenRoughnessMap, vUv ).a; + #ifdef USE_SHEEN_ROUGHNESSMAP + material.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a; + #endif +#endif +#ifdef USE_ANISOTROPY + #ifdef USE_ANISOTROPYMAP + mat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x ); + vec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb; + vec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b; + #else + vec2 anisotropyV = anisotropyVector; #endif -#endif`, hp = `struct PhysicalMaterial { + material.anisotropy = length( anisotropyV ); + anisotropyV /= material.anisotropy; + material.anisotropy = saturate( material.anisotropy ); + material.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) ); + material.anisotropyT = tbn[ 0 ] * anisotropyV.x - tbn[ 1 ] * anisotropyV.y; + material.anisotropyB = tbn[ 1 ] * anisotropyV.x + tbn[ 0 ] * anisotropyV.y; +#endif`, Mm = `struct PhysicalMaterial { vec3 diffuseColor; float roughness; vec3 specularColor; @@ -4719,14 +5233,184 @@ material.roughness = min( material.roughness, 1.0 ); vec3 clearcoatF0; float clearcoatF90; #endif + #ifdef USE_IRIDESCENCE + float iridescence; + float iridescenceIOR; + float iridescenceThickness; + vec3 iridescenceFresnel; + vec3 iridescenceF0; + #endif #ifdef USE_SHEEN vec3 sheenColor; float sheenRoughness; #endif + #ifdef IOR + float ior; + #endif + #ifdef USE_TRANSMISSION + float transmission; + float transmissionAlpha; + float thickness; + float attenuationDistance; + vec3 attenuationColor; + #endif + #ifdef USE_ANISOTROPY + float anisotropy; + float alphaT; + vec3 anisotropyT; + vec3 anisotropyB; + #endif }; vec3 clearcoatSpecular = vec3( 0.0 ); vec3 sheenSpecular = vec3( 0.0 ); -float IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness) { +vec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) { + float x = clamp( 1.0 - dotVH, 0.0, 1.0 ); + float x2 = x * x; + float x5 = clamp( x * x2 * x2, 0.0, 0.9999 ); + return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 ); +} +float V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) { + float a2 = pow2( alpha ); + float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) ); + float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) ); + return 0.5 / max( gv + gl, EPSILON ); +} +float D_GGX( const in float alpha, const in float dotNH ) { + float a2 = pow2( alpha ); + float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; + return RECIPROCAL_PI * a2 / pow2( denom ); +} +#ifdef USE_ANISOTROPY + float V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) { + float gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) ); + float gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) ); + float v = 0.5 / ( gv + gl ); + return saturate(v); + } + float D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) { + float a2 = alphaT * alphaB; + highp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH ); + highp float v2 = dot( v, v ); + float w2 = a2 / v2; + return RECIPROCAL_PI * a2 * pow2 ( w2 ); + } +#endif +#ifdef USE_CLEARCOAT + vec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) { + vec3 f0 = material.clearcoatF0; + float f90 = material.clearcoatF90; + float roughness = material.clearcoatRoughness; + float alpha = pow2( roughness ); + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotVH = saturate( dot( viewDir, halfDir ) ); + vec3 F = F_Schlick( f0, f90, dotVH ); + float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + float D = D_GGX( alpha, dotNH ); + return F * ( V * D ); + } +#endif +vec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) { + vec3 f0 = material.specularColor; + float f90 = material.specularF90; + float roughness = material.roughness; + float alpha = pow2( roughness ); + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotVH = saturate( dot( viewDir, halfDir ) ); + vec3 F = F_Schlick( f0, f90, dotVH ); + #ifdef USE_IRIDESCENCE + F = mix( F, material.iridescenceFresnel, material.iridescence ); + #endif + #ifdef USE_ANISOTROPY + float dotTL = dot( material.anisotropyT, lightDir ); + float dotTV = dot( material.anisotropyT, viewDir ); + float dotTH = dot( material.anisotropyT, halfDir ); + float dotBL = dot( material.anisotropyB, lightDir ); + float dotBV = dot( material.anisotropyB, viewDir ); + float dotBH = dot( material.anisotropyB, halfDir ); + float V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL ); + float D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH ); + #else + float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + float D = D_GGX( alpha, dotNH ); + #endif + return F * ( V * D ); +} +vec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) { + const float LUT_SIZE = 64.0; + const float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE; + const float LUT_BIAS = 0.5 / LUT_SIZE; + float dotNV = saturate( dot( N, V ) ); + vec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) ); + uv = uv * LUT_SCALE + LUT_BIAS; + return uv; +} +float LTC_ClippedSphereFormFactor( const in vec3 f ) { + float l = length( f ); + return max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 ); +} +vec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) { + float x = dot( v1, v2 ); + float y = abs( x ); + float a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y; + float b = 3.4175940 + ( 4.1616724 + y ) * y; + float v = a / b; + float theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v; + return cross( v1, v2 ) * theta_sintheta; +} +vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) { + vec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ]; + vec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ]; + vec3 lightNormal = cross( v1, v2 ); + if( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 ); + vec3 T1, T2; + T1 = normalize( V - N * dot( V, N ) ); + T2 = - cross( N, T1 ); + mat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) ); + vec3 coords[ 4 ]; + coords[ 0 ] = mat * ( rectCoords[ 0 ] - P ); + coords[ 1 ] = mat * ( rectCoords[ 1 ] - P ); + coords[ 2 ] = mat * ( rectCoords[ 2 ] - P ); + coords[ 3 ] = mat * ( rectCoords[ 3 ] - P ); + coords[ 0 ] = normalize( coords[ 0 ] ); + coords[ 1 ] = normalize( coords[ 1 ] ); + coords[ 2 ] = normalize( coords[ 2 ] ); + coords[ 3 ] = normalize( coords[ 3 ] ); + vec3 vectorFormFactor = vec3( 0.0 ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] ); + float result = LTC_ClippedSphereFormFactor( vectorFormFactor ); + return vec3( result ); +} +#if defined( USE_SHEEN ) +float D_Charlie( float roughness, float dotNH ) { + float alpha = pow2( roughness ); + float invAlpha = 1.0 / alpha; + float cos2h = dotNH * dotNH; + float sin2h = max( 1.0 - cos2h, 0.0078125 ); + return ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI ); +} +float V_Neubelt( float dotNV, float dotNL ) { + return saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) ); +} +vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) { + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float D = D_Charlie( sheenRoughness, dotNH ); + float V = V_Neubelt( dotNV, dotNL ); + return sheenColor * ( D * V ); +} +#endif +float IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { float dotNV = saturate( dot( normal, viewDir ) ); float r2 = roughness * roughness; float a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95; @@ -4747,20 +5431,29 @@ vec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 vec2 fab = DFGApprox( normal, viewDir, roughness ); return specularColor * fab.x + specularF90 * fab.y; } +#ifdef USE_IRIDESCENCE +void computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) { +#else void computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) { +#endif vec2 fab = DFGApprox( normal, viewDir, roughness ); - vec3 FssEss = specularColor * fab.x + specularF90 * fab.y; + #ifdef USE_IRIDESCENCE + vec3 Fr = mix( specularColor, iridescenceF0, iridescence ); + #else + vec3 Fr = specularColor; + #endif + vec3 FssEss = Fr * fab.x + specularF90 * fab.y; float Ess = fab.x + fab.y; float Ems = 1.0 - Ess; - vec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619; vec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg ); + vec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619; vec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg ); singleScatter += FssEss; multiScatter += Fms * Ems; } #if NUM_RECT_AREA_LIGHTS > 0 - void RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { - vec3 normal = geometry.normal; - vec3 viewDir = geometry.viewDir; - vec3 position = geometry.position; + void RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + vec3 normal = geometryNormal; + vec3 viewDir = geometryViewDir; + vec3 position = geometryPosition; vec3 lightPos = rectAreaLight.position; vec3 halfWidth = rectAreaLight.halfWidth; vec3 halfHeight = rectAreaLight.halfHeight; @@ -4783,35 +5476,40 @@ void computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const reflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords ); } #endif -void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { - float dotNL = saturate( dot( geometry.normal, directLight.direction ) ); +void RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); vec3 irradiance = dotNL * directLight.color; #ifdef USE_CLEARCOAT - float dotNLcc = saturate( dot( geometry.clearcoatNormal, directLight.direction ) ); + float dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) ); vec3 ccIrradiance = dotNLcc * directLight.color; - clearcoatSpecular += ccIrradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.clearcoatNormal, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness ); + clearcoatSpecular += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material ); #endif #ifdef USE_SHEEN - sheenSpecular += irradiance * BRDF_Sheen( directLight.direction, geometry.viewDir, geometry.normal, material.sheenColor, material.sheenRoughness ); + sheenSpecular += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness ); #endif - reflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness ); + reflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material ); reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } -void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { +void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } -void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { +void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { #ifdef USE_CLEARCOAT - clearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometry.clearcoatNormal, geometry.viewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness ); + clearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness ); #endif #ifdef USE_SHEEN - sheenSpecular += irradiance * material.sheenColor * IBLSheenBRDF( geometry.normal, geometry.viewDir, material.sheenRoughness ); + sheenSpecular += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ); #endif vec3 singleScattering = vec3( 0.0 ); vec3 multiScattering = vec3( 0.0 ); vec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI; - computeMultiscattering( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering ); - vec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) ); + #ifdef USE_IRIDESCENCE + computeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering ); + #else + computeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering ); + #endif + vec3 totalScattering = singleScattering + multiScattering; + vec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) ); reflectedLight.indirectSpecular += radiance * singleScattering; reflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance; reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance; @@ -4822,13 +5520,25 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia #define RE_IndirectSpecular RE_IndirectSpecular_Physical float computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) { return saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion ); -}`, up = ` -GeometricContext geometry; -geometry.position = - vViewPosition; -geometry.normal = normal; -geometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition ); +}`, Sm = ` +vec3 geometryPosition = - vViewPosition; +vec3 geometryNormal = normal; +vec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition ); +vec3 geometryClearcoatNormal; #ifdef USE_CLEARCOAT - geometry.clearcoatNormal = clearcoatNormal; + geometryClearcoatNormal = clearcoatNormal; +#endif +#ifdef USE_IRIDESCENCE + float dotNVi = saturate( dot( normal, geometryViewDir ) ); + if ( material.iridescenceThickness == 0.0 ) { + material.iridescence = 0.0; + } else { + material.iridescence = saturate( material.iridescence ); + } + if ( material.iridescence > 0.0 ) { + material.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor ); + material.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi ); + } #endif IncidentLight directLight; #if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct ) @@ -4839,29 +5549,46 @@ IncidentLight directLight; #pragma unroll_loop_start for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) { pointLight = pointLights[ i ]; - getPointLightInfo( pointLight, geometry, directLight ); + getPointLightInfo( pointLight, geometryPosition, directLight ); #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS ) pointLightShadow = pointLightShadows[ i ]; - directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0; + directLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0; #endif - RE_Direct( directLight, geometry, material, reflectedLight ); + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); } #pragma unroll_loop_end #endif #if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct ) SpotLight spotLight; + vec4 spotColor; + vec3 spotLightCoord; + bool inSpotLightMap; #if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0 SpotLightShadow spotLightShadow; #endif #pragma unroll_loop_start for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) { spotLight = spotLights[ i ]; - getSpotLightInfo( spotLight, geometry, directLight ); + getSpotLightInfo( spotLight, geometryPosition, directLight ); + #if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) + #define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX + #elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + #define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS + #else + #define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) + #endif + #if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS ) + spotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w; + inSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) ); + spotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy ); + directLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color; + #endif + #undef SPOT_LIGHT_MAP_INDEX #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) spotLightShadow = spotLightShadows[ i ]; - directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0; + directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; #endif - RE_Direct( directLight, geometry, material, reflectedLight ); + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); } #pragma unroll_loop_end #endif @@ -4873,12 +5600,12 @@ IncidentLight directLight; #pragma unroll_loop_start for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) { directionalLight = directionalLights[ i ]; - getDirectionalLightInfo( directionalLight, geometry, directLight ); + getDirectionalLightInfo( directionalLight, directLight ); #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS ) directionalLightShadow = directionalLightShadows[ i ]; - directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; + directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; #endif - RE_Direct( directLight, geometry, material, reflectedLight ); + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); } #pragma unroll_loop_end #endif @@ -4887,18 +5614,20 @@ IncidentLight directLight; #pragma unroll_loop_start for ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) { rectAreaLight = rectAreaLights[ i ]; - RE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight ); + RE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); } #pragma unroll_loop_end #endif #if defined( RE_IndirectDiffuse ) vec3 iblIrradiance = vec3( 0.0 ); vec3 irradiance = getAmbientLightIrradiance( ambientLightColor ); - irradiance += getLightProbeIrradiance( lightProbe, geometry.normal ); + #if defined( USE_LIGHT_PROBES ) + irradiance += getLightProbeIrradiance( lightProbe, geometryNormal ); + #endif #if ( NUM_HEMI_LIGHTS > 0 ) #pragma unroll_loop_start for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) { - irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry.normal ); + irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal ); } #pragma unroll_loop_end #endif @@ -4906,43 +5635,44 @@ IncidentLight directLight; #if defined( RE_IndirectSpecular ) vec3 radiance = vec3( 0.0 ); vec3 clearcoatRadiance = vec3( 0.0 ); -#endif`, dp = `#if defined( RE_IndirectDiffuse ) +#endif`, bm = `#if defined( RE_IndirectDiffuse ) #ifdef USE_LIGHTMAP - vec4 lightMapTexel = texture2D( lightMap, vUv2 ); - vec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity; - #ifndef PHYSICALLY_CORRECT_LIGHTS - lightMapIrradiance *= PI; - #endif + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity; irradiance += lightMapIrradiance; #endif #if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV ) - iblIrradiance += getIBLIrradiance( geometry.normal ); + iblIrradiance += getIBLIrradiance( geometryNormal ); #endif #endif #if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular ) - radiance += getIBLRadiance( geometry.viewDir, geometry.normal, material.roughness ); + #ifdef USE_ANISOTROPY + radiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy ); + #else + radiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness ); + #endif #ifdef USE_CLEARCOAT - clearcoatRadiance += getIBLRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness ); + clearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness ); #endif -#endif`, fp = `#if defined( RE_IndirectDiffuse ) - RE_IndirectDiffuse( irradiance, geometry, material, reflectedLight ); +#endif`, Em = `#if defined( RE_IndirectDiffuse ) + RE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); #endif #if defined( RE_IndirectSpecular ) - RE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight ); -#endif`, pp = `#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT ) + RE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); +#endif`, Tm = `#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT ) gl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5; -#endif`, mp = `#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT ) +#endif`, wm = `#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT ) uniform float logDepthBufFC; varying float vFragDepth; varying float vIsPerspective; -#endif`, gp = `#ifdef USE_LOGDEPTHBUF +#endif`, Am = `#ifdef USE_LOGDEPTHBUF #ifdef USE_LOGDEPTHBUF_EXT varying float vFragDepth; varying float vIsPerspective; #else uniform float logDepthBufFC; #endif -#endif`, xp = `#ifdef USE_LOGDEPTHBUF +#endif`, Rm = `#ifdef USE_LOGDEPTHBUF #ifdef USE_LOGDEPTHBUF_EXT vFragDepth = 1.0 + gl_Position.w; vIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) ); @@ -4952,40 +5682,59 @@ IncidentLight directLight; gl_Position.z *= gl_Position.w; } #endif -#endif`, yp = `#ifdef USE_MAP - vec4 texelColor = texture2D( map, vUv ); - texelColor = mapTexelToLinear( texelColor ); - diffuseColor *= texelColor; -#endif`, vp = `#ifdef USE_MAP +#endif`, Cm = `#ifdef USE_MAP + vec4 sampledDiffuseColor = texture2D( map, vMapUv ); + #ifdef DECODE_VIDEO_TEXTURE + sampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w ); + + #endif + diffuseColor *= sampledDiffuseColor; +#endif`, Pm = `#ifdef USE_MAP uniform sampler2D map; -#endif`, _p = `#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) - vec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy; +#endif`, Lm = `#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) + #if defined( USE_POINTS_UV ) + vec2 uv = vUv; + #else + vec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy; + #endif #endif #ifdef USE_MAP - vec4 mapTexel = texture2D( map, uv ); - diffuseColor *= mapTexelToLinear( mapTexel ); + diffuseColor *= texture2D( map, uv ); #endif #ifdef USE_ALPHAMAP diffuseColor.a *= texture2D( alphaMap, uv ).g; -#endif`, Mp = `#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) - uniform mat3 uvTransform; +#endif`, Im = `#if defined( USE_POINTS_UV ) + varying vec2 vUv; +#else + #if defined( USE_MAP ) || defined( USE_ALPHAMAP ) + uniform mat3 uvTransform; + #endif #endif #ifdef USE_MAP uniform sampler2D map; #endif #ifdef USE_ALPHAMAP uniform sampler2D alphaMap; -#endif`, bp = `float metalnessFactor = metalness; +#endif`, Um = `float metalnessFactor = metalness; #ifdef USE_METALNESSMAP - vec4 texelMetalness = texture2D( metalnessMap, vUv ); + vec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv ); metalnessFactor *= texelMetalness.b; -#endif`, wp = `#ifdef USE_METALNESSMAP +#endif`, Dm = `#ifdef USE_METALNESSMAP uniform sampler2D metalnessMap; -#endif`, Sp = `#ifdef USE_MORPHNORMALS +#endif`, Nm = `#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE ) + vColor *= morphTargetBaseInfluence; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + #if defined( USE_COLOR_ALPHA ) + if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ]; + #elif defined( USE_COLOR ) + if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ]; + #endif + } +#endif`, Om = `#ifdef USE_MORPHNORMALS objectNormal *= morphTargetBaseInfluence; #ifdef MORPHTARGETS_TEXTURE for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { - if ( morphTargetInfluences[ i ] > 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1, 2 ) * morphTargetInfluences[ i ]; + if ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ]; } #else objectNormal += morphNormal0 * morphTargetInfluences[ 0 ]; @@ -4993,18 +5742,18 @@ IncidentLight directLight; objectNormal += morphNormal2 * morphTargetInfluences[ 2 ]; objectNormal += morphNormal3 * morphTargetInfluences[ 3 ]; #endif -#endif`, Tp = `#ifdef USE_MORPHTARGETS +#endif`, Fm = `#ifdef USE_MORPHTARGETS uniform float morphTargetBaseInfluence; #ifdef MORPHTARGETS_TEXTURE uniform float morphTargetInfluences[ MORPHTARGETS_COUNT ]; uniform sampler2DArray morphTargetsTexture; - uniform vec2 morphTargetsTextureSize; - vec3 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset, const in int stride ) { - float texelIndex = float( vertexIndex * stride + offset ); - float y = floor( texelIndex / morphTargetsTextureSize.x ); - float x = texelIndex - y * morphTargetsTextureSize.x; - vec3 morphUV = vec3( ( x + 0.5 ) / morphTargetsTextureSize.x, y / morphTargetsTextureSize.y, morphTargetIndex ); - return texture( morphTargetsTexture, morphUV ).xyz; + uniform ivec2 morphTargetsTextureSize; + vec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) { + int texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset; + int y = texelIndex / morphTargetsTextureSize.x; + int x = texelIndex - y * morphTargetsTextureSize.x; + ivec3 morphUV = ivec3( x, y, morphTargetIndex ); + return texelFetch( morphTargetsTexture, morphUV, 0 ); } #else #ifndef USE_MORPHNORMALS @@ -5013,15 +5762,11 @@ IncidentLight directLight; uniform float morphTargetInfluences[ 4 ]; #endif #endif -#endif`, Ep = `#ifdef USE_MORPHTARGETS +#endif`, Bm = `#ifdef USE_MORPHTARGETS transformed *= morphTargetBaseInfluence; #ifdef MORPHTARGETS_TEXTURE for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { - #ifndef USE_MORPHNORMALS - if ( morphTargetInfluences[ i ] > 0.0 ) transformed += getMorph( gl_VertexID, i, 0, 1 ) * morphTargetInfluences[ i ]; - #else - if ( morphTargetInfluences[ i ] > 0.0 ) transformed += getMorph( gl_VertexID, i, 0, 2 ) * morphTargetInfluences[ i ]; - #endif + if ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ]; } #else transformed += morphTarget0 * morphTargetInfluences[ 0 ]; @@ -5035,30 +5780,49 @@ IncidentLight directLight; transformed += morphTarget7 * morphTargetInfluences[ 7 ]; #endif #endif -#endif`, Ap = `float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; +#endif`, zm = `float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; #ifdef FLAT_SHADED - vec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) ); - vec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) ); + vec3 fdx = dFdx( vViewPosition ); + vec3 fdy = dFdy( vViewPosition ); vec3 normal = normalize( cross( fdx, fdy ) ); #else vec3 normal = normalize( vNormal ); #ifdef DOUBLE_SIDED - normal = normal * faceDirection; + normal *= faceDirection; #endif +#endif +#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) #ifdef USE_TANGENT - vec3 tangent = normalize( vTangent ); - vec3 bitangent = normalize( vBitangent ); - #ifdef DOUBLE_SIDED - tangent = tangent * faceDirection; - bitangent = bitangent * faceDirection; - #endif - #if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP ) - mat3 vTBN = mat3( tangent, bitangent, normal ); + mat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); + #else + mat3 tbn = getTangentFrame( - vViewPosition, normal, + #if defined( USE_NORMALMAP ) + vNormalMapUv + #elif defined( USE_CLEARCOAT_NORMALMAP ) + vClearcoatNormalMapUv + #else + vUv #endif + ); + #endif + #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED ) + tbn[0] *= faceDirection; + tbn[1] *= faceDirection; + #endif +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + #ifdef USE_TANGENT + mat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); + #else + mat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv ); + #endif + #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED ) + tbn2[0] *= faceDirection; + tbn2[1] *= faceDirection; #endif #endif -vec3 geometryNormal = normal;`, Cp = `#ifdef OBJECTSPACE_NORMALMAP - normal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0; +vec3 nonPerturbedNormal = normal;`, Vm = `#ifdef USE_NORMALMAP_OBJECTSPACE + normal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; #ifdef FLIP_SIDED normal = - normal; #endif @@ -5066,82 +5830,79 @@ vec3 geometryNormal = normal;`, Cp = `#ifdef OBJECTSPACE_NORMALMAP normal = normal * faceDirection; #endif normal = normalize( normalMatrix * normal ); -#elif defined( TANGENTSPACE_NORMALMAP ) - vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0; +#elif defined( USE_NORMALMAP_TANGENTSPACE ) + vec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; mapN.xy *= normalScale; - #ifdef USE_TANGENT - normal = normalize( vTBN * mapN ); - #else - normal = perturbNormal2Arb( - vViewPosition, normal, mapN, faceDirection ); - #endif + normal = normalize( tbn * mapN ); #elif defined( USE_BUMPMAP ) normal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection ); -#endif`, Lp = `#ifndef FLAT_SHADED +#endif`, km = `#ifndef FLAT_SHADED varying vec3 vNormal; #ifdef USE_TANGENT varying vec3 vTangent; varying vec3 vBitangent; #endif -#endif`, Rp = `#ifndef FLAT_SHADED +#endif`, Hm = `#ifndef FLAT_SHADED varying vec3 vNormal; #ifdef USE_TANGENT varying vec3 vTangent; varying vec3 vBitangent; #endif -#endif`, Pp = `#ifndef FLAT_SHADED +#endif`, Gm = `#ifndef FLAT_SHADED vNormal = normalize( transformedNormal ); #ifdef USE_TANGENT vTangent = normalize( transformedTangent ); vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); #endif -#endif`, Ip = `#ifdef USE_NORMALMAP +#endif`, Wm = `#ifdef USE_NORMALMAP uniform sampler2D normalMap; uniform vec2 normalScale; #endif -#ifdef OBJECTSPACE_NORMALMAP +#ifdef USE_NORMALMAP_OBJECTSPACE uniform mat3 normalMatrix; #endif -#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) ) - vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) { - vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) ); - vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) ); - vec2 st0 = dFdx( vUv.st ); - vec2 st1 = dFdy( vUv.st ); +#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) ) + mat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) { + vec3 q0 = dFdx( eye_pos.xyz ); + vec3 q1 = dFdy( eye_pos.xyz ); + vec2 st0 = dFdx( uv.st ); + vec2 st1 = dFdy( uv.st ); vec3 N = surf_norm; vec3 q1perp = cross( q1, N ); vec3 q0perp = cross( N, q0 ); vec3 T = q1perp * st0.x + q0perp * st1.x; vec3 B = q1perp * st0.y + q0perp * st1.y; float det = max( dot( T, T ), dot( B, B ) ); - float scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det ); - return normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z ); + float scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det ); + return mat3( T * scale, B * scale, N ); } -#endif`, Dp = `#ifdef USE_CLEARCOAT - vec3 clearcoatNormal = geometryNormal; -#endif`, Fp = `#ifdef USE_CLEARCOAT_NORMALMAP - vec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0; +#endif`, Xm = `#ifdef USE_CLEARCOAT + vec3 clearcoatNormal = nonPerturbedNormal; +#endif`, qm = `#ifdef USE_CLEARCOAT_NORMALMAP + vec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0; clearcoatMapN.xy *= clearcoatNormalScale; - #ifdef USE_TANGENT - clearcoatNormal = normalize( vTBN * clearcoatMapN ); - #else - clearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection ); - #endif -#endif`, Np = `#ifdef USE_CLEARCOATMAP + clearcoatNormal = normalize( tbn2 * clearcoatMapN ); +#endif`, Ym = `#ifdef USE_CLEARCOATMAP uniform sampler2D clearcoatMap; #endif -#ifdef USE_CLEARCOAT_ROUGHNESSMAP - uniform sampler2D clearcoatRoughnessMap; -#endif #ifdef USE_CLEARCOAT_NORMALMAP uniform sampler2D clearcoatNormalMap; uniform vec2 clearcoatNormalScale; -#endif`, Bp = `#ifdef OPAQUE +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + uniform sampler2D clearcoatRoughnessMap; +#endif`, Zm = `#ifdef USE_IRIDESCENCEMAP + uniform sampler2D iridescenceMap; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + uniform sampler2D iridescenceThicknessMap; +#endif`, Jm = `#ifdef OPAQUE diffuseColor.a = 1.0; #endif #ifdef USE_TRANSMISSION -diffuseColor.a *= transmissionAlpha + 0.1; +diffuseColor.a *= material.transmissionAlpha; #endif -gl_FragColor = vec4( outgoingLight, diffuseColor.a );`, zp = `vec3 packNormalToRGB( const in vec3 normal ) { +gl_FragColor = vec4( outgoingLight, diffuseColor.a );`, $m = `vec3 packNormalToRGB( const in vec3 normal ) { return normalize( normal ) * 0.5 + 0.5; } vec3 unpackRGBToNormal( const in vec3 rgb ) { @@ -5158,6 +5919,12 @@ vec4 packDepthToRGBA( const in float v ) { float unpackRGBAToDepth( const in vec4 v ) { return dot( v, UnpackFactors ); } +vec2 packDepthToRG( in highp float v ) { + return packDepthToRGBA( v ).yx; +} +float unpackRGToDepth( const in highp vec2 v ) { + return unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) ); +} vec4 pack2HalfToRGBA( vec2 v ) { vec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) ); return vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w ); @@ -5168,37 +5935,43 @@ vec2 unpackRGBATo2Half( vec4 v ) { float viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) { return ( viewZ + near ) / ( near - far ); } -float orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) { - return linearClipZ * ( near - far ) - near; +float orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) { + return depth * ( near - far ) - near; } float viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) { return ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ ); } -float perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) { - return ( near * far ) / ( ( far - near ) * invClipZ - far ); -}`, Up = `#ifdef PREMULTIPLIED_ALPHA +float perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) { + return ( near * far ) / ( ( far - near ) * depth - far ); +}`, Km = `#ifdef PREMULTIPLIED_ALPHA gl_FragColor.rgb *= gl_FragColor.a; -#endif`, Op = `vec4 mvPosition = vec4( transformed, 1.0 ); +#endif`, Qm = `vec4 mvPosition = vec4( transformed, 1.0 ); #ifdef USE_INSTANCING mvPosition = instanceMatrix * mvPosition; #endif mvPosition = modelViewMatrix * mvPosition; -gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING +gl_Position = projectionMatrix * mvPosition;`, jm = `#ifdef DITHERING gl_FragColor.rgb = dithering( gl_FragColor.rgb ); -#endif`, kp = `#ifdef DITHERING +#endif`, eg = `#ifdef DITHERING vec3 dithering( vec3 color ) { float grid_position = rand( gl_FragCoord.xy ); vec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 ); dither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position ); return color + dither_shift_RGB; } -#endif`, Gp = `float roughnessFactor = roughness; +#endif`, tg = `float roughnessFactor = roughness; #ifdef USE_ROUGHNESSMAP - vec4 texelRoughness = texture2D( roughnessMap, vUv ); + vec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv ); roughnessFactor *= texelRoughness.g; -#endif`, Vp = `#ifdef USE_ROUGHNESSMAP +#endif`, ng = `#ifdef USE_ROUGHNESSMAP uniform sampler2D roughnessMap; -#endif`, Wp = `#ifdef USE_SHADOWMAP +#endif`, ig = `#if NUM_SPOT_LIGHT_COORDS > 0 + varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; +#endif +#if NUM_SPOT_LIGHT_MAPS > 0 + uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ]; +#endif +#ifdef USE_SHADOWMAP #if NUM_DIR_LIGHT_SHADOWS > 0 uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ]; varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; @@ -5212,7 +5985,6 @@ gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING #endif #if NUM_SPOT_LIGHT_SHADOWS > 0 uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ]; - varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ]; struct SpotLightShadow { float shadowBias; float shadowNormalBias; @@ -5255,10 +6027,8 @@ gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING float shadow = 1.0; shadowCoord.xyz /= shadowCoord.w; shadowCoord.z += shadowBias; - bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 ); - bool inFrustum = all( inFrustumVec ); - bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 ); - bool frustumTest = all( frustumTestVec ); + bool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0; + bool frustumTest = inFrustum && shadowCoord.z <= 1.0; if ( frustumTest ) { #if defined( SHADOWMAP_TYPE_PCF ) vec2 texelSize = vec2( 1.0 ) / shadowMapSize; @@ -5301,22 +6071,22 @@ gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING texture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) + texture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) + texture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) + - mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), + mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ), f.x ) + - mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), + mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ), f.x ) + - mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), + mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ), f.y ) + - mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), + mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ), f.y ) + - mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), + mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ), f.x ), - mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), + mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ), f.x ), f.y ) @@ -5372,7 +6142,11 @@ gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING return texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ); #endif } -#endif`, qp = `#ifdef USE_SHADOWMAP +#endif`, sg = `#if NUM_SPOT_LIGHT_COORDS > 0 + uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ]; + varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; +#endif +#ifdef USE_SHADOWMAP #if NUM_DIR_LIGHT_SHADOWS > 0 uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ]; varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; @@ -5385,8 +6159,6 @@ gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; #endif #if NUM_SPOT_LIGHT_SHADOWS > 0 - uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ]; - varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ]; struct SpotLightShadow { float shadowBias; float shadowNormalBias; @@ -5408,36 +6180,39 @@ gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING }; uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; #endif -#endif`, Xp = `#ifdef USE_SHADOWMAP - #if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 - vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); - vec4 shadowWorldPosition; - #endif +#endif`, rg = `#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 ) + vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); + vec4 shadowWorldPosition; +#endif +#if defined( USE_SHADOWMAP ) #if NUM_DIR_LIGHT_SHADOWS > 0 - #pragma unroll_loop_start - for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { - shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 ); - vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition; - } - #pragma unroll_loop_end - #endif - #if NUM_SPOT_LIGHT_SHADOWS > 0 - #pragma unroll_loop_start - for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) { - shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias, 0 ); - vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition; - } - #pragma unroll_loop_end + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { + shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 ); + vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end #endif #if NUM_POINT_LIGHT_SHADOWS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { + shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 ); + vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end + #endif +#endif +#if NUM_SPOT_LIGHT_COORDS > 0 #pragma unroll_loop_start - for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { - shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 ); - vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition; + for ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) { + shadowWorldPosition = worldPosition; + #if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + shadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias; + #endif + vSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition; } #pragma unroll_loop_end - #endif -#endif`, Jp = `float getShadowMask() { +#endif`, ag = `float getShadowMask() { float shadow = 1.0; #ifdef USE_SHADOWMAP #if NUM_DIR_LIGHT_SHADOWS > 0 @@ -5454,7 +6229,7 @@ gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING #pragma unroll_loop_start for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) { spotLight = spotLightShadows[ i ]; - shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0; + shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; } #pragma unroll_loop_end #endif @@ -5469,39 +6244,31 @@ gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING #endif #endif return shadow; -}`, Yp = `#ifdef USE_SKINNING +}`, og = `#ifdef USE_SKINNING mat4 boneMatX = getBoneMatrix( skinIndex.x ); mat4 boneMatY = getBoneMatrix( skinIndex.y ); mat4 boneMatZ = getBoneMatrix( skinIndex.z ); mat4 boneMatW = getBoneMatrix( skinIndex.w ); -#endif`, Zp = `#ifdef USE_SKINNING +#endif`, cg = `#ifdef USE_SKINNING uniform mat4 bindMatrix; uniform mat4 bindMatrixInverse; - #ifdef BONE_TEXTURE - uniform highp sampler2D boneTexture; - uniform int boneTextureSize; - mat4 getBoneMatrix( const in float i ) { - float j = i * 4.0; - float x = mod( j, float( boneTextureSize ) ); - float y = floor( j / float( boneTextureSize ) ); - float dx = 1.0 / float( boneTextureSize ); - float dy = 1.0 / float( boneTextureSize ); - y = dy * ( y + 0.5 ); - vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) ); - vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) ); - vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) ); - vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) ); - mat4 bone = mat4( v1, v2, v3, v4 ); - return bone; - } - #else - uniform mat4 boneMatrices[ MAX_BONES ]; - mat4 getBoneMatrix( const in float i ) { - mat4 bone = boneMatrices[ int(i) ]; - return bone; - } - #endif -#endif`, $p = `#ifdef USE_SKINNING + uniform highp sampler2D boneTexture; + uniform int boneTextureSize; + mat4 getBoneMatrix( const in float i ) { + float j = i * 4.0; + float x = mod( j, float( boneTextureSize ) ); + float y = floor( j / float( boneTextureSize ) ); + float dx = 1.0 / float( boneTextureSize ); + float dy = 1.0 / float( boneTextureSize ); + y = dy * ( y + 0.5 ); + vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) ); + vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) ); + vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) ); + vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) ); + mat4 bone = mat4( v1, v2, v3, v4 ); + return bone; + } +#endif`, lg = `#ifdef USE_SKINNING vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 ); vec4 skinned = vec4( 0.0 ); skinned += boneMatX * skinVertex * skinWeight.x; @@ -5509,7 +6276,7 @@ gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING skinned += boneMatZ * skinVertex * skinWeight.z; skinned += boneMatW * skinVertex * skinWeight.w; transformed = ( bindMatrixInverse * skinned ).xyz; -#endif`, jp = `#ifdef USE_SKINNING +#endif`, hg = `#ifdef USE_SKINNING mat4 skinMatrix = mat4( 0.0 ); skinMatrix += skinWeight.x * boneMatX; skinMatrix += skinWeight.y * boneMatY; @@ -5520,22 +6287,22 @@ gl_Position = projectionMatrix * mvPosition;`, Hp = `#ifdef DITHERING #ifdef USE_TANGENT objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz; #endif -#endif`, Qp = `float specularStrength; +#endif`, ug = `float specularStrength; #ifdef USE_SPECULARMAP - vec4 texelSpecular = texture2D( specularMap, vUv ); + vec4 texelSpecular = texture2D( specularMap, vSpecularMapUv ); specularStrength = texelSpecular.r; #else specularStrength = 1.0; -#endif`, Kp = `#ifdef USE_SPECULARMAP +#endif`, dg = `#ifdef USE_SPECULARMAP uniform sampler2D specularMap; -#endif`, em = `#if defined( TONE_MAPPING ) +#endif`, fg = `#if defined( TONE_MAPPING ) gl_FragColor.rgb = toneMapping( gl_FragColor.rgb ); -#endif`, tm = `#ifndef saturate +#endif`, pg = `#ifndef saturate #define saturate( a ) clamp( a, 0.0, 1.0 ) #endif uniform float toneMappingExposure; vec3 LinearToneMapping( vec3 color ) { - return toneMappingExposure * color; + return saturate( toneMappingExposure * color ); } vec3 ReinhardToneMapping( vec3 color ) { color *= toneMappingExposure; @@ -5566,26 +6333,28 @@ vec3 ACESFilmicToneMapping( vec3 color ) { color = ACESOutputMat * color; return saturate( color ); } -vec3 CustomToneMapping( vec3 color ) { return color; }`, nm = `#ifdef USE_TRANSMISSION - float transmissionAlpha = 1.0; - float transmissionFactor = transmission; - float thicknessFactor = thickness; +vec3 CustomToneMapping( vec3 color ) { return color; }`, mg = `#ifdef USE_TRANSMISSION + material.transmission = transmission; + material.transmissionAlpha = 1.0; + material.thickness = thickness; + material.attenuationDistance = attenuationDistance; + material.attenuationColor = attenuationColor; #ifdef USE_TRANSMISSIONMAP - transmissionFactor *= texture2D( transmissionMap, vUv ).r; + material.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r; #endif #ifdef USE_THICKNESSMAP - thicknessFactor *= texture2D( thicknessMap, vUv ).g; + material.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g; #endif vec3 pos = vWorldPosition; vec3 v = normalize( cameraPosition - pos ); vec3 n = inverseTransformDirection( normal, viewMatrix ); - vec4 transmission = getIBLVolumeRefraction( - n, v, roughnessFactor, material.diffuseColor, material.specularColor, material.specularF90, - pos, modelMatrix, viewMatrix, projectionMatrix, ior, thicknessFactor, - attenuationColor, attenuationDistance ); - totalDiffuse = mix( totalDiffuse, transmission.rgb, transmissionFactor ); - transmissionAlpha = mix( transmissionAlpha, transmission.a, transmissionFactor ); -#endif`, im = `#ifdef USE_TRANSMISSION + vec4 transmitted = getIBLVolumeRefraction( + n, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90, + pos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness, + material.attenuationColor, material.attenuationDistance ); + material.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission ); + totalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission ); +#endif`, gg = `#ifdef USE_TRANSMISSION uniform float transmission; uniform float thickness; uniform float attenuationDistance; @@ -5601,7 +6370,57 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`, nm = `#ifdef USE_TRANSM uniform mat4 modelMatrix; uniform mat4 projectionMatrix; varying vec3 vWorldPosition; - vec3 getVolumeTransmissionRay( vec3 n, vec3 v, float thickness, float ior, mat4 modelMatrix ) { + float w0( float a ) { + return ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 ); + } + float w1( float a ) { + return ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 ); + } + float w2( float a ){ + return ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 ); + } + float w3( float a ) { + return ( 1.0 / 6.0 ) * ( a * a * a ); + } + float g0( float a ) { + return w0( a ) + w1( a ); + } + float g1( float a ) { + return w2( a ) + w3( a ); + } + float h0( float a ) { + return - 1.0 + w1( a ) / ( w0( a ) + w1( a ) ); + } + float h1( float a ) { + return 1.0 + w3( a ) / ( w2( a ) + w3( a ) ); + } + vec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) { + uv = uv * texelSize.zw + 0.5; + vec2 iuv = floor( uv ); + vec2 fuv = fract( uv ); + float g0x = g0( fuv.x ); + float g1x = g1( fuv.x ); + float h0x = h0( fuv.x ); + float h1x = h1( fuv.x ); + float h0y = h0( fuv.y ); + float h1y = h1( fuv.y ); + vec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; + vec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; + vec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; + vec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; + return g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) + + g1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) ); + } + vec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) { + vec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) ); + vec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) ); + vec2 fLodSizeInv = 1.0 / fLodSize; + vec2 cLodSizeInv = 1.0 / cLodSize; + vec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) ); + vec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) ); + return mix( fSample, cSample, fract( lod ) ); + } + vec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) { vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior ); vec3 modelScale; modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) ); @@ -5609,28 +6428,25 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`, nm = `#ifdef USE_TRANSM modelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) ); return normalize( refractionVector ) * thickness * modelScale; } - float applyIorToRoughness( float roughness, float ior ) { + float applyIorToRoughness( const in float roughness, const in float ior ) { return roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 ); } - vec4 getTransmissionSample( vec2 fragCoord, float roughness, float ior ) { - float framebufferLod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior ); - #ifdef TEXTURE_LOD_EXT - return texture2DLodEXT( transmissionSamplerMap, fragCoord.xy, framebufferLod ); - #else - return texture2D( transmissionSamplerMap, fragCoord.xy, framebufferLod ); - #endif + vec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) { + float lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior ); + return textureBicubic( transmissionSamplerMap, fragCoord.xy, lod ); } - vec3 applyVolumeAttenuation( vec3 radiance, float transmissionDistance, vec3 attenuationColor, float attenuationDistance ) { - if ( attenuationDistance == 0.0 ) { - return radiance; + vec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) { + if ( isinf( attenuationDistance ) ) { + return vec3( 1.0 ); } else { vec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance; - vec3 transmittance = exp( - attenuationCoefficient * transmissionDistance ); return transmittance * radiance; + vec3 transmittance = exp( - attenuationCoefficient * transmissionDistance ); return transmittance; } } - vec4 getIBLVolumeRefraction( vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 specularColor, float specularF90, - vec3 position, mat4 modelMatrix, mat4 viewMatrix, mat4 projMatrix, float ior, float thickness, - vec3 attenuationColor, float attenuationDistance ) { + vec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor, + const in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix, + const in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness, + const in vec3 attenuationColor, const in float attenuationDistance ) { vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); vec3 refractedRayExit = position + transmissionRay; vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); @@ -5638,91 +6454,342 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`, nm = `#ifdef USE_TRANSM refractionCoords += 1.0; refractionCoords /= 2.0; vec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior ); - vec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance ); + vec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ); + vec3 attenuatedColor = transmittance * transmittedLight.rgb; vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness ); - return vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a ); + float transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0; + return vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor ); } -#endif`, rm = `#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) ) +#endif`, _g = `#if defined( USE_UV ) || defined( USE_ANISOTROPY ) varying vec2 vUv; -#endif`, sm = `#ifdef USE_UV - #ifdef UVS_VERTEX_ONLY - vec2 vUv; - #else - varying vec2 vUv; - #endif - uniform mat3 uvTransform; -#endif`, om = `#ifdef USE_UV - vUv = ( uvTransform * vec3( uv, 1 ) ).xy; -#endif`, am = `#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP ) - varying vec2 vUv2; -#endif`, lm = `#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP ) - attribute vec2 uv2; - varying vec2 vUv2; - uniform mat3 uv2Transform; -#endif`, cm = `#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP ) - vUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy; -#endif`, hm = `#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) - vec4 worldPosition = vec4( transformed, 1.0 ); - #ifdef USE_INSTANCING - worldPosition = instanceMatrix * worldPosition; - #endif - worldPosition = modelMatrix * worldPosition; -#endif`, um = `varying vec2 vUv; -uniform mat3 uvTransform; -void main() { - vUv = ( uvTransform * vec3( uv, 1 ) ).xy; - gl_Position = vec4( position.xy, 1.0, 1.0 ); -}`, dm = `uniform sampler2D t2D; -varying vec2 vUv; -void main() { - vec4 texColor = texture2D( t2D, vUv ); - gl_FragColor = mapTexelToLinear( texColor ); - #include - #include -}`, fm = `varying vec3 vWorldDirection; -#include -void main() { - vWorldDirection = transformDirection( position, modelMatrix ); - #include - #include - gl_Position.z = gl_Position.w; -}`, pm = `#include -uniform float opacity; -varying vec3 vWorldDirection; -#include -void main() { - vec3 vReflect = vWorldDirection; - #include - gl_FragColor = envColor; - gl_FragColor.a *= opacity; - #include - #include -}`, mm = `#include -#include -#include -#include -#include -#include -#include -varying vec2 vHighPrecisionZW; -void main() { - #include - #include - #ifdef USE_DISPLACEMENTMAP - #include - #include - #include - #endif - #include - #include - #include - #include - #include - #include - #include - vHighPrecisionZW = gl_Position.zw; -}`, gm = `#if DEPTH_PACKING == 3200 - uniform float opacity; +#endif +#ifdef USE_MAP + varying vec2 vMapUv; +#endif +#ifdef USE_ALPHAMAP + varying vec2 vAlphaMapUv; +#endif +#ifdef USE_LIGHTMAP + varying vec2 vLightMapUv; +#endif +#ifdef USE_AOMAP + varying vec2 vAoMapUv; +#endif +#ifdef USE_BUMPMAP + varying vec2 vBumpMapUv; +#endif +#ifdef USE_NORMALMAP + varying vec2 vNormalMapUv; +#endif +#ifdef USE_EMISSIVEMAP + varying vec2 vEmissiveMapUv; +#endif +#ifdef USE_METALNESSMAP + varying vec2 vMetalnessMapUv; +#endif +#ifdef USE_ROUGHNESSMAP + varying vec2 vRoughnessMapUv; +#endif +#ifdef USE_ANISOTROPYMAP + varying vec2 vAnisotropyMapUv; +#endif +#ifdef USE_CLEARCOATMAP + varying vec2 vClearcoatMapUv; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + varying vec2 vClearcoatNormalMapUv; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + varying vec2 vClearcoatRoughnessMapUv; +#endif +#ifdef USE_IRIDESCENCEMAP + varying vec2 vIridescenceMapUv; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + varying vec2 vIridescenceThicknessMapUv; +#endif +#ifdef USE_SHEEN_COLORMAP + varying vec2 vSheenColorMapUv; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + varying vec2 vSheenRoughnessMapUv; +#endif +#ifdef USE_SPECULARMAP + varying vec2 vSpecularMapUv; +#endif +#ifdef USE_SPECULAR_COLORMAP + varying vec2 vSpecularColorMapUv; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + varying vec2 vSpecularIntensityMapUv; +#endif +#ifdef USE_TRANSMISSIONMAP + uniform mat3 transmissionMapTransform; + varying vec2 vTransmissionMapUv; +#endif +#ifdef USE_THICKNESSMAP + uniform mat3 thicknessMapTransform; + varying vec2 vThicknessMapUv; +#endif`, xg = `#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + varying vec2 vUv; +#endif +#ifdef USE_MAP + uniform mat3 mapTransform; + varying vec2 vMapUv; +#endif +#ifdef USE_ALPHAMAP + uniform mat3 alphaMapTransform; + varying vec2 vAlphaMapUv; +#endif +#ifdef USE_LIGHTMAP + uniform mat3 lightMapTransform; + varying vec2 vLightMapUv; +#endif +#ifdef USE_AOMAP + uniform mat3 aoMapTransform; + varying vec2 vAoMapUv; +#endif +#ifdef USE_BUMPMAP + uniform mat3 bumpMapTransform; + varying vec2 vBumpMapUv; +#endif +#ifdef USE_NORMALMAP + uniform mat3 normalMapTransform; + varying vec2 vNormalMapUv; +#endif +#ifdef USE_DISPLACEMENTMAP + uniform mat3 displacementMapTransform; + varying vec2 vDisplacementMapUv; +#endif +#ifdef USE_EMISSIVEMAP + uniform mat3 emissiveMapTransform; + varying vec2 vEmissiveMapUv; +#endif +#ifdef USE_METALNESSMAP + uniform mat3 metalnessMapTransform; + varying vec2 vMetalnessMapUv; +#endif +#ifdef USE_ROUGHNESSMAP + uniform mat3 roughnessMapTransform; + varying vec2 vRoughnessMapUv; +#endif +#ifdef USE_ANISOTROPYMAP + uniform mat3 anisotropyMapTransform; + varying vec2 vAnisotropyMapUv; +#endif +#ifdef USE_CLEARCOATMAP + uniform mat3 clearcoatMapTransform; + varying vec2 vClearcoatMapUv; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + uniform mat3 clearcoatNormalMapTransform; + varying vec2 vClearcoatNormalMapUv; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + uniform mat3 clearcoatRoughnessMapTransform; + varying vec2 vClearcoatRoughnessMapUv; +#endif +#ifdef USE_SHEEN_COLORMAP + uniform mat3 sheenColorMapTransform; + varying vec2 vSheenColorMapUv; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + uniform mat3 sheenRoughnessMapTransform; + varying vec2 vSheenRoughnessMapUv; +#endif +#ifdef USE_IRIDESCENCEMAP + uniform mat3 iridescenceMapTransform; + varying vec2 vIridescenceMapUv; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + uniform mat3 iridescenceThicknessMapTransform; + varying vec2 vIridescenceThicknessMapUv; +#endif +#ifdef USE_SPECULARMAP + uniform mat3 specularMapTransform; + varying vec2 vSpecularMapUv; +#endif +#ifdef USE_SPECULAR_COLORMAP + uniform mat3 specularColorMapTransform; + varying vec2 vSpecularColorMapUv; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + uniform mat3 specularIntensityMapTransform; + varying vec2 vSpecularIntensityMapUv; +#endif +#ifdef USE_TRANSMISSIONMAP + uniform mat3 transmissionMapTransform; + varying vec2 vTransmissionMapUv; +#endif +#ifdef USE_THICKNESSMAP + uniform mat3 thicknessMapTransform; + varying vec2 vThicknessMapUv; +#endif`, vg = `#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + vUv = vec3( uv, 1 ).xy; +#endif +#ifdef USE_MAP + vMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ALPHAMAP + vAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_LIGHTMAP + vLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_AOMAP + vAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_BUMPMAP + vBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_NORMALMAP + vNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_DISPLACEMENTMAP + vDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_EMISSIVEMAP + vEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_METALNESSMAP + vMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ROUGHNESSMAP + vRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ANISOTROPYMAP + vAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOATMAP + vClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + vClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + vClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_IRIDESCENCEMAP + vIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + vIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SHEEN_COLORMAP + vSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + vSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULARMAP + vSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULAR_COLORMAP + vSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + vSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_TRANSMISSIONMAP + vTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_THICKNESSMAP + vThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy; +#endif`, yg = `#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0 + vec4 worldPosition = vec4( transformed, 1.0 ); + #ifdef USE_INSTANCING + worldPosition = instanceMatrix * worldPosition; + #endif + worldPosition = modelMatrix * worldPosition; +#endif`, Mg = `varying vec2 vUv; +uniform mat3 uvTransform; +void main() { + vUv = ( uvTransform * vec3( uv, 1 ) ).xy; + gl_Position = vec4( position.xy, 1.0, 1.0 ); +}`, Sg = `uniform sampler2D t2D; +uniform float backgroundIntensity; +varying vec2 vUv; +void main() { + vec4 texColor = texture2D( t2D, vUv ); + #ifdef DECODE_VIDEO_TEXTURE + texColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w ); + #endif + texColor.rgb *= backgroundIntensity; + gl_FragColor = texColor; + #include + #include +}`, bg = `varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include + gl_Position.z = gl_Position.w; +}`, Eg = `#ifdef ENVMAP_TYPE_CUBE + uniform samplerCube envMap; +#elif defined( ENVMAP_TYPE_CUBE_UV ) + uniform sampler2D envMap; +#endif +uniform float flipEnvMap; +uniform float backgroundBlurriness; +uniform float backgroundIntensity; +varying vec3 vWorldDirection; +#include +void main() { + #ifdef ENVMAP_TYPE_CUBE + vec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) ); + #elif defined( ENVMAP_TYPE_CUBE_UV ) + vec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness ); + #else + vec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 ); + #endif + texColor.rgb *= backgroundIntensity; + gl_FragColor = texColor; + #include + #include +}`, Tg = `varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include + gl_Position.z = gl_Position.w; +}`, wg = `uniform samplerCube tCube; +uniform float tFlip; +uniform float opacity; +varying vec3 vWorldDirection; +void main() { + vec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) ); + gl_FragColor = texColor; + gl_FragColor.a *= opacity; + #include + #include +}`, Ag = `#include +#include +#include +#include +#include +#include +#include +varying vec2 vHighPrecisionZW; +void main() { + #include + #include + #ifdef USE_DISPLACEMENTMAP + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + vHighPrecisionZW = gl_Position.zw; +}`, Rg = `#if DEPTH_PACKING == 3200 + uniform float opacity; #endif #include #include @@ -5730,6 +6797,7 @@ void main() { #include #include #include +#include #include #include varying vec2 vHighPrecisionZW; @@ -5742,6 +6810,7 @@ void main() { #include #include #include + #include #include float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5; #if DEPTH_PACKING == 3200 @@ -5749,7 +6818,7 @@ void main() { #elif DEPTH_PACKING == 3201 gl_FragColor = packDepthToRGBA( fragCoordZ ); #endif -}`, xm = `#define DISTANCE +}`, Cg = `#define DISTANCE varying vec3 vWorldPosition; #include #include @@ -5773,7 +6842,7 @@ void main() { #include #include vWorldPosition = worldPosition.xyz; -}`, ym = `#define DISTANCE +}`, Pg = `#define DISTANCE uniform vec3 referencePosition; uniform float nearDistance; uniform float farDistance; @@ -5784,6 +6853,7 @@ varying vec3 vWorldPosition; #include #include #include +#include #include void main () { #include @@ -5791,30 +6861,31 @@ void main () { #include #include #include + #include float dist = length( vWorldPosition - referencePosition ); dist = ( dist - nearDistance ) / ( farDistance - nearDistance ); dist = saturate( dist ); gl_FragColor = packDepthToRGBA( dist ); -}`, vm = `varying vec3 vWorldDirection; +}`, Lg = `varying vec3 vWorldDirection; #include void main() { vWorldDirection = transformDirection( position, modelMatrix ); #include #include -}`, _m = `uniform sampler2D tEquirect; +}`, Ig = `uniform sampler2D tEquirect; varying vec3 vWorldDirection; #include void main() { vec3 direction = normalize( vWorldDirection ); vec2 sampleUV = equirectUv( direction ); - vec4 texColor = texture2D( tEquirect, sampleUV ); - gl_FragColor = mapTexelToLinear( texColor ); + gl_FragColor = texture2D( tEquirect, sampleUV ); #include - #include -}`, Mm = `uniform float scale; + #include +}`, Ug = `uniform float scale; attribute float lineDistance; varying float vLineDistance; #include +#include #include #include #include @@ -5822,20 +6893,24 @@ varying float vLineDistance; #include void main() { vLineDistance = scale * lineDistance; + #include #include + #include #include #include #include #include #include #include -}`, bm = `uniform vec3 diffuse; +}`, Dg = `uniform vec3 diffuse; uniform float opacity; uniform float dashSize; uniform float totalSize; varying float vLineDistance; #include #include +#include +#include #include #include #include @@ -5847,16 +6922,16 @@ void main() { vec3 outgoingLight = vec3( 0.0 ); vec4 diffuseColor = vec4( diffuse, opacity ); #include + #include #include outgoingLight = diffuseColor.rgb; - #include + #include #include - #include + #include #include #include -}`, wm = `#include +}`, Ng = `#include #include -#include #include #include #include @@ -5866,8 +6941,8 @@ void main() { #include void main() { #include - #include #include + #include #if defined ( USE_ENVMAP ) || defined ( USE_SKINNING ) #include #include @@ -5884,7 +6959,7 @@ void main() { #include #include #include -}`, Sm = `uniform vec3 diffuse; +}`, Og = `uniform vec3 diffuse; uniform float opacity; #ifndef FLAT_SHADED varying vec3 vNormal; @@ -5893,15 +6968,14 @@ uniform float opacity; #include #include #include -#include #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -5914,11 +6988,12 @@ void main() { #include #include #include + #include #include ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); #ifdef USE_LIGHTMAP - vec4 lightMapTexel= texture2D( lightMap, vUv2 ); - reflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity; + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + reflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI; #else reflectedLight.indirectDiffuse += vec3( 1.0 ); #endif @@ -5926,27 +7001,21 @@ void main() { reflectedLight.indirectDiffuse *= diffuseColor.rgb; vec3 outgoingLight = reflectedLight.indirectDiffuse; #include - #include + #include #include - #include + #include #include #include #include -}`, Tm = `#define LAMBERT -varying vec3 vLightFront; -varying vec3 vIndirectFront; -#ifdef DOUBLE_SIDED - varying vec3 vLightBack; - varying vec3 vIndirectBack; -#endif +}`, Fg = `#define LAMBERT +varying vec3 vViewPosition; #include #include -#include +#include #include -#include -#include #include #include +#include #include #include #include @@ -5954,53 +7023,52 @@ varying vec3 vIndirectFront; #include void main() { #include - #include #include + #include #include #include #include #include #include + #include #include #include #include + #include #include #include #include + vViewPosition = - mvPosition.xyz; #include #include - #include #include #include -}`, Em = `uniform vec3 diffuse; +}`, Bg = `#define LAMBERT +uniform vec3 diffuse; uniform vec3 emissive; uniform float opacity; -varying vec3 vLightFront; -varying vec3 vIndirectFront; -#ifdef DOUBLE_SIDED - varying vec3 vLightBack; - varying vec3 vIndirectBack; -#endif #include #include #include #include #include -#include #include #include #include +#include #include #include #include #include #include -#include +#include #include #include -#include +#include +#include #include -#include +#include +#include #include #include #include @@ -6014,31 +7082,25 @@ void main() { #include #include #include + #include #include + #include + #include #include - #ifdef DOUBLE_SIDED - reflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack; - #else - reflectedLight.indirectDiffuse += vIndirectFront; - #endif - #include - reflectedLight.indirectDiffuse *= BRDF_Lambert( diffuseColor.rgb ); - #ifdef DOUBLE_SIDED - reflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack; - #else - reflectedLight.directDiffuse = vLightFront; - #endif - reflectedLight.directDiffuse *= BRDF_Lambert( diffuseColor.rgb ) * getShadowMask(); + #include + #include + #include + #include #include vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; #include - #include + #include #include - #include + #include #include #include #include -}`, Am = `#define MATCAP +}`, zg = `#define MATCAP varying vec3 vViewPosition; #include #include @@ -6053,6 +7115,7 @@ varying vec3 vViewPosition; void main() { #include #include + #include #include #include #include @@ -6068,7 +7131,7 @@ void main() { #include #include vViewPosition = - mvPosition.xyz; -}`, Cm = `#define MATCAP +}`, Vg = `#define MATCAP uniform vec3 diffuse; uniform float opacity; uniform sampler2D matcap; @@ -6080,6 +7143,7 @@ varying vec3 vViewPosition; #include #include #include +#include #include #include #include @@ -6094,6 +7158,7 @@ void main() { #include #include #include + #include #include #include vec3 viewDir = normalize( vViewPosition ); @@ -6102,19 +7167,18 @@ void main() { vec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5; #ifdef USE_MATCAP vec4 matcapColor = texture2D( matcap, uv ); - matcapColor = matcapTexelToLinear( matcapColor ); #else - vec4 matcapColor = vec4( 1.0 ); + vec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 ); #endif vec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb; - #include + #include #include - #include + #include #include #include #include -}`, Lm = `#define NORMAL -#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP ) +}`, kg = `#define NORMAL +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) varying vec3 vViewPosition; #endif #include @@ -6140,12 +7204,12 @@ void main() { #include #include #include -#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP ) +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) vViewPosition = - mvPosition.xyz; #endif -}`, Rm = `#define NORMAL +}`, Hg = `#define NORMAL uniform float opacity; -#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP ) +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) varying vec3 vViewPosition; #endif #include @@ -6161,11 +7225,13 @@ void main() { #include #include gl_FragColor = vec4( packNormalToRGB( normal ), opacity ); -}`, Pm = `#define PHONG + #ifdef OPAQUE + gl_FragColor.a = 1.0; + #endif +}`, Gg = `#define PHONG varying vec3 vViewPosition; #include #include -#include #include #include #include @@ -6178,8 +7244,8 @@ varying vec3 vViewPosition; #include void main() { #include - #include #include + #include #include #include #include @@ -6198,7 +7264,7 @@ void main() { #include #include #include -}`, Im = `#define PHONG +}`, Wg = `#define PHONG uniform vec3 diffuse; uniform vec3 emissive; uniform vec3 specular; @@ -6209,16 +7275,15 @@ uniform float opacity; #include #include #include -#include #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -6240,6 +7305,7 @@ void main() { #include #include #include + #include #include #include #include @@ -6251,20 +7317,19 @@ void main() { #include vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; #include - #include + #include #include - #include + #include #include #include #include -}`, Dm = `#define STANDARD +}`, Xg = `#define STANDARD varying vec3 vViewPosition; #ifdef USE_TRANSMISSION varying vec3 vWorldPosition; #endif #include #include -#include #include #include #include @@ -6276,8 +7341,8 @@ varying vec3 vViewPosition; #include void main() { #include - #include #include + #include #include #include #include @@ -6298,10 +7363,10 @@ void main() { #ifdef USE_TRANSMISSION vWorldPosition = worldPosition.xyz; #endif -}`, Fm = `#define STANDARD +}`, qg = `#define STANDARD #ifdef PHYSICAL #define IOR - #define SPECULAR + #define USE_SPECULAR #endif uniform vec3 diffuse; uniform vec3 emissive; @@ -6311,44 +7376,56 @@ uniform float opacity; #ifdef IOR uniform float ior; #endif -#ifdef SPECULAR +#ifdef USE_SPECULAR uniform float specularIntensity; uniform vec3 specularColor; - #ifdef USE_SPECULARINTENSITYMAP - uniform sampler2D specularIntensityMap; - #endif - #ifdef USE_SPECULARCOLORMAP + #ifdef USE_SPECULAR_COLORMAP uniform sampler2D specularColorMap; #endif + #ifdef USE_SPECULAR_INTENSITYMAP + uniform sampler2D specularIntensityMap; + #endif #endif #ifdef USE_CLEARCOAT uniform float clearcoat; uniform float clearcoatRoughness; #endif +#ifdef USE_IRIDESCENCE + uniform float iridescence; + uniform float iridescenceIOR; + uniform float iridescenceThicknessMinimum; + uniform float iridescenceThicknessMaximum; +#endif #ifdef USE_SHEEN uniform vec3 sheenColor; uniform float sheenRoughness; - #ifdef USE_SHEENCOLORMAP + #ifdef USE_SHEEN_COLORMAP uniform sampler2D sheenColorMap; #endif - #ifdef USE_SHEENROUGHNESSMAP + #ifdef USE_SHEEN_ROUGHNESSMAP uniform sampler2D sheenRoughnessMap; #endif #endif +#ifdef USE_ANISOTROPY + uniform vec2 anisotropyVector; + #ifdef USE_ANISOTROPYMAP + uniform sampler2D anisotropyMap; + #endif +#endif varying vec3 vViewPosition; #include #include #include #include #include -#include #include #include #include +#include #include #include #include -#include +#include #include #include #include @@ -6361,6 +7438,7 @@ varying vec3 vViewPosition; #include #include #include +#include #include #include #include @@ -6375,6 +7453,7 @@ void main() { #include #include #include + #include #include #include #include @@ -6396,21 +7475,20 @@ void main() { outgoingLight = outgoingLight * sheenEnergyComp + sheenSpecular; #endif #ifdef USE_CLEARCOAT - float dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) ); + float dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) ); vec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc ); outgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + clearcoatSpecular * material.clearcoat; #endif - #include + #include #include - #include + #include #include #include #include -}`, Nm = `#define TOON +}`, Yg = `#define TOON varying vec3 vViewPosition; #include #include -#include #include #include #include @@ -6422,8 +7500,8 @@ varying vec3 vViewPosition; #include void main() { #include - #include #include + #include #include #include #include @@ -6441,7 +7519,7 @@ void main() { #include #include #include -}`, Bm = `#define TOON +}`, Zg = `#define TOON uniform vec3 diffuse; uniform vec3 emissive; uniform float opacity; @@ -6450,10 +7528,10 @@ uniform float opacity; #include #include #include -#include #include #include #include +#include #include #include #include @@ -6478,6 +7556,7 @@ void main() { #include #include #include + #include #include #include #include @@ -6487,13 +7566,13 @@ void main() { #include #include vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; - #include + #include #include - #include + #include #include #include #include -}`, zm = `uniform float size; +}`, Jg = `uniform float size; uniform float scale; #include #include @@ -6501,8 +7580,16 @@ uniform float scale; #include #include #include +#ifdef USE_POINTS_UV + varying vec2 vUv; + uniform mat3 uvTransform; +#endif void main() { + #ifdef USE_POINTS_UV + vUv = ( uvTransform * vec3( uv, 1 ) ).xy; + #endif #include + #include #include #include #include @@ -6515,12 +7602,13 @@ void main() { #include #include #include -}`, Um = `uniform vec3 diffuse; +}`, $g = `uniform vec3 diffuse; uniform float opacity; #include #include #include #include +#include #include #include #include @@ -6532,16 +7620,18 @@ void main() { #include #include #include + #include outgoingLight = diffuseColor.rgb; - #include + #include #include - #include + #include #include #include -}`, Om = `#include +}`, Kg = `#include #include #include #include +#include #include void main() { #include @@ -6553,24 +7643,27 @@ void main() { #include #include #include + #include #include #include #include -}`, Hm = `uniform vec3 color; +}`, Qg = `uniform vec3 color; uniform float opacity; #include #include #include #include #include +#include #include #include void main() { + #include gl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) ); #include - #include + #include #include -}`, km = `uniform float rotation; +}`, jg = `uniform float rotation; uniform vec2 center; #include #include @@ -6596,13 +7689,14 @@ void main() { #include #include #include -}`, Gm = `uniform vec3 diffuse; +}`, e_ = `uniform vec3 diffuse; uniform float opacity; #include #include #include #include #include +#include #include #include #include @@ -6614,150 +7708,156 @@ void main() { #include #include #include + #include outgoingLight = diffuseColor.rgb; - #include + #include #include - #include + #include #include -}`, Fe = { - alphamap_fragment: xf, - alphamap_pars_fragment: yf, - alphatest_fragment: vf, - alphatest_pars_fragment: _f, - aomap_fragment: Mf, - aomap_pars_fragment: bf, - begin_vertex: wf, - beginnormal_vertex: Sf, - bsdfs: Tf, - bumpmap_pars_fragment: Ef, - clipping_planes_fragment: Af, - clipping_planes_pars_fragment: Cf, - clipping_planes_pars_vertex: Lf, - clipping_planes_vertex: Rf, - color_fragment: Pf, - color_pars_fragment: If, - color_pars_vertex: Df, - color_vertex: Ff, - common: Nf, - cube_uv_reflection_fragment: Bf, - defaultnormal_vertex: zf, - displacementmap_pars_vertex: Uf, - displacementmap_vertex: Of, - emissivemap_fragment: Hf, - emissivemap_pars_fragment: kf, - encodings_fragment: Gf, - encodings_pars_fragment: Vf, - envmap_fragment: Wf, - envmap_common_pars_fragment: qf, - envmap_pars_fragment: Xf, - envmap_pars_vertex: Jf, - envmap_physical_pars_fragment: rp, - envmap_vertex: Yf, - fog_vertex: Zf, - fog_pars_vertex: $f, - fog_fragment: jf, - fog_pars_fragment: Qf, - gradientmap_pars_fragment: Kf, - lightmap_fragment: ep, - lightmap_pars_fragment: tp, - lights_lambert_vertex: np, - lights_pars_begin: ip, - lights_toon_fragment: sp, - lights_toon_pars_fragment: op, - lights_phong_fragment: ap, - lights_phong_pars_fragment: lp, - lights_physical_fragment: cp, - lights_physical_pars_fragment: hp, - lights_fragment_begin: up, - lights_fragment_maps: dp, - lights_fragment_end: fp, - logdepthbuf_fragment: pp, - logdepthbuf_pars_fragment: mp, - logdepthbuf_pars_vertex: gp, - logdepthbuf_vertex: xp, - map_fragment: yp, - map_pars_fragment: vp, - map_particle_fragment: _p, - map_particle_pars_fragment: Mp, - metalnessmap_fragment: bp, - metalnessmap_pars_fragment: wp, - morphnormal_vertex: Sp, - morphtarget_pars_vertex: Tp, - morphtarget_vertex: Ep, - normal_fragment_begin: Ap, - normal_fragment_maps: Cp, - normal_pars_fragment: Lp, - normal_pars_vertex: Rp, - normal_vertex: Pp, - normalmap_pars_fragment: Ip, - clearcoat_normal_fragment_begin: Dp, - clearcoat_normal_fragment_maps: Fp, - clearcoat_pars_fragment: Np, - output_fragment: Bp, - packing: zp, - premultiplied_alpha_fragment: Up, - project_vertex: Op, - dithering_fragment: Hp, - dithering_pars_fragment: kp, - roughnessmap_fragment: Gp, - roughnessmap_pars_fragment: Vp, - shadowmap_pars_fragment: Wp, - shadowmap_pars_vertex: qp, - shadowmap_vertex: Xp, - shadowmask_pars_fragment: Jp, - skinbase_vertex: Yp, - skinning_pars_vertex: Zp, - skinning_vertex: $p, - skinnormal_vertex: jp, - specularmap_fragment: Qp, - specularmap_pars_fragment: Kp, - tonemapping_fragment: em, - tonemapping_pars_fragment: tm, - transmission_fragment: nm, - transmission_pars_fragment: im, - uv_pars_fragment: rm, - uv_pars_vertex: sm, - uv_vertex: om, - uv2_pars_fragment: am, - uv2_pars_vertex: lm, - uv2_vertex: cm, - worldpos_vertex: hm, - background_vert: um, - background_frag: dm, - cube_vert: fm, - cube_frag: pm, - depth_vert: mm, - depth_frag: gm, - distanceRGBA_vert: xm, - distanceRGBA_frag: ym, - equirect_vert: vm, - equirect_frag: _m, - linedashed_vert: Mm, - linedashed_frag: bm, - meshbasic_vert: wm, - meshbasic_frag: Sm, - meshlambert_vert: Tm, - meshlambert_frag: Em, - meshmatcap_vert: Am, - meshmatcap_frag: Cm, - meshnormal_vert: Lm, - meshnormal_frag: Rm, - meshphong_vert: Pm, - meshphong_frag: Im, - meshphysical_vert: Dm, - meshphysical_frag: Fm, - meshtoon_vert: Nm, - meshtoon_frag: Bm, - points_vert: zm, - points_frag: Um, - shadow_vert: Om, - shadow_frag: Hm, - sprite_vert: km, - sprite_frag: Gm -}, ie = { +}`, ke = { + alphahash_fragment: Ep, + alphahash_pars_fragment: Tp, + alphamap_fragment: wp, + alphamap_pars_fragment: Ap, + alphatest_fragment: Rp, + alphatest_pars_fragment: Cp, + aomap_fragment: Pp, + aomap_pars_fragment: Lp, + begin_vertex: Ip, + beginnormal_vertex: Up, + bsdfs: Dp, + iridescence_fragment: Np, + bumpmap_pars_fragment: Op, + clipping_planes_fragment: Fp, + clipping_planes_pars_fragment: Bp, + clipping_planes_pars_vertex: zp, + clipping_planes_vertex: Vp, + color_fragment: kp, + color_pars_fragment: Hp, + color_pars_vertex: Gp, + color_vertex: Wp, + common: Xp, + cube_uv_reflection_fragment: qp, + defaultnormal_vertex: Yp, + displacementmap_pars_vertex: Zp, + displacementmap_vertex: Jp, + emissivemap_fragment: $p, + emissivemap_pars_fragment: Kp, + colorspace_fragment: Qp, + colorspace_pars_fragment: jp, + envmap_fragment: em, + envmap_common_pars_fragment: tm, + envmap_pars_fragment: nm, + envmap_pars_vertex: im, + envmap_physical_pars_fragment: mm, + envmap_vertex: sm, + fog_vertex: rm, + fog_pars_vertex: am, + fog_fragment: om, + fog_pars_fragment: cm, + gradientmap_pars_fragment: lm, + lightmap_fragment: hm, + lightmap_pars_fragment: um, + lights_lambert_fragment: dm, + lights_lambert_pars_fragment: fm, + lights_pars_begin: pm, + lights_toon_fragment: gm, + lights_toon_pars_fragment: _m, + lights_phong_fragment: xm, + lights_phong_pars_fragment: vm, + lights_physical_fragment: ym, + lights_physical_pars_fragment: Mm, + lights_fragment_begin: Sm, + lights_fragment_maps: bm, + lights_fragment_end: Em, + logdepthbuf_fragment: Tm, + logdepthbuf_pars_fragment: wm, + logdepthbuf_pars_vertex: Am, + logdepthbuf_vertex: Rm, + map_fragment: Cm, + map_pars_fragment: Pm, + map_particle_fragment: Lm, + map_particle_pars_fragment: Im, + metalnessmap_fragment: Um, + metalnessmap_pars_fragment: Dm, + morphcolor_vertex: Nm, + morphnormal_vertex: Om, + morphtarget_pars_vertex: Fm, + morphtarget_vertex: Bm, + normal_fragment_begin: zm, + normal_fragment_maps: Vm, + normal_pars_fragment: km, + normal_pars_vertex: Hm, + normal_vertex: Gm, + normalmap_pars_fragment: Wm, + clearcoat_normal_fragment_begin: Xm, + clearcoat_normal_fragment_maps: qm, + clearcoat_pars_fragment: Ym, + iridescence_pars_fragment: Zm, + opaque_fragment: Jm, + packing: $m, + premultiplied_alpha_fragment: Km, + project_vertex: Qm, + dithering_fragment: jm, + dithering_pars_fragment: eg, + roughnessmap_fragment: tg, + roughnessmap_pars_fragment: ng, + shadowmap_pars_fragment: ig, + shadowmap_pars_vertex: sg, + shadowmap_vertex: rg, + shadowmask_pars_fragment: ag, + skinbase_vertex: og, + skinning_pars_vertex: cg, + skinning_vertex: lg, + skinnormal_vertex: hg, + specularmap_fragment: ug, + specularmap_pars_fragment: dg, + tonemapping_fragment: fg, + tonemapping_pars_fragment: pg, + transmission_fragment: mg, + transmission_pars_fragment: gg, + uv_pars_fragment: _g, + uv_pars_vertex: xg, + uv_vertex: vg, + worldpos_vertex: yg, + background_vert: Mg, + background_frag: Sg, + backgroundCube_vert: bg, + backgroundCube_frag: Eg, + cube_vert: Tg, + cube_frag: wg, + depth_vert: Ag, + depth_frag: Rg, + distanceRGBA_vert: Cg, + distanceRGBA_frag: Pg, + equirect_vert: Lg, + equirect_frag: Ig, + linedashed_vert: Ug, + linedashed_frag: Dg, + meshbasic_vert: Ng, + meshbasic_frag: Og, + meshlambert_vert: Fg, + meshlambert_frag: Bg, + meshmatcap_vert: zg, + meshmatcap_frag: Vg, + meshnormal_vert: kg, + meshnormal_frag: Hg, + meshphong_vert: Gg, + meshphong_frag: Wg, + meshphysical_vert: Xg, + meshphysical_frag: qg, + meshtoon_vert: Yg, + meshtoon_frag: Zg, + points_vert: Jg, + points_frag: $g, + shadow_vert: Kg, + shadow_frag: Qg, + sprite_vert: jg, + sprite_frag: e_ +}, le = { common: { diffuse: { - value: new ae(16777215) + value: new pe(16777215) }, opacity: { value: 1 @@ -6765,15 +7865,15 @@ void main() { map: { value: null }, - uvTransform: { - value: new lt - }, - uv2Transform: { - value: new lt + mapTransform: { + value: new He }, alphaMap: { value: null }, + alphaMapTransform: { + value: new He + }, alphaTest: { value: 0 } @@ -6781,6 +7881,9 @@ void main() { specularmap: { specularMap: { value: null + }, + specularMapTransform: { + value: new He } }, envmap: { @@ -6806,6 +7909,9 @@ void main() { }, aoMapIntensity: { value: 1 + }, + aoMapTransform: { + value: new He } }, lightmap: { @@ -6814,17 +7920,18 @@ void main() { }, lightMapIntensity: { value: 1 - } - }, - emissivemap: { - emissiveMap: { - value: null + }, + lightMapTransform: { + value: new He } }, bumpmap: { bumpMap: { value: null }, + bumpMapTransform: { + value: new He + }, bumpScale: { value: 1 } @@ -6833,14 +7940,20 @@ void main() { normalMap: { value: null }, + normalMapTransform: { + value: new He + }, normalScale: { - value: new X(1, 1) + value: new Z(1, 1) } }, displacementmap: { displacementMap: { value: null }, + displacementMapTransform: { + value: new He + }, displacementScale: { value: 1 }, @@ -6848,14 +7961,28 @@ void main() { value: 0 } }, - roughnessmap: { - roughnessMap: { + emissivemap: { + emissiveMap: { value: null + }, + emissiveMapTransform: { + value: new He } }, metalnessmap: { metalnessMap: { value: null + }, + metalnessMapTransform: { + value: new He + } + }, + roughnessmap: { + roughnessMap: { + value: null + }, + roughnessMapTransform: { + value: new He } }, gradientmap: { @@ -6874,7 +8001,7 @@ void main() { value: 2e3 }, fogColor: { - value: new ae(16777215) + value: new pe(16777215) } }, lights: { @@ -6927,10 +8054,13 @@ void main() { shadowMapSize: {} } }, + spotLightMap: { + value: [] + }, spotShadowMap: { value: [] }, - spotShadowMatrix: { + spotLightMatrix: { value: [] }, pointLights: { @@ -6985,7 +8115,7 @@ void main() { }, points: { diffuse: { - value: new ae(16777215) + value: new pe(16777215) }, opacity: { value: 1 @@ -7002,22 +8132,25 @@ void main() { alphaMap: { value: null }, + alphaMapTransform: { + value: new He + }, alphaTest: { value: 0 }, uvTransform: { - value: new lt + value: new He } }, sprite: { diffuse: { - value: new ae(16777215) + value: new pe(16777215) }, opacity: { value: 1 }, center: { - value: new X(.5, .5) + value: new Z(.5, .5) }, rotation: { value: 0 @@ -7025,93 +8158,99 @@ void main() { map: { value: null }, + mapTransform: { + value: new He + }, alphaMap: { value: null }, + alphaMapTransform: { + value: new He + }, alphaTest: { value: 0 - }, - uvTransform: { - value: new lt } } -}, qt = { +}, nn = { basic: { - uniforms: yt([ - ie.common, - ie.specularmap, - ie.envmap, - ie.aomap, - ie.lightmap, - ie.fog + uniforms: Lt([ + le.common, + le.specularmap, + le.envmap, + le.aomap, + le.lightmap, + le.fog ]), - vertexShader: Fe.meshbasic_vert, - fragmentShader: Fe.meshbasic_frag + vertexShader: ke.meshbasic_vert, + fragmentShader: ke.meshbasic_frag }, lambert: { - uniforms: yt([ - ie.common, - ie.specularmap, - ie.envmap, - ie.aomap, - ie.lightmap, - ie.emissivemap, - ie.fog, - ie.lights, + uniforms: Lt([ + le.common, + le.specularmap, + le.envmap, + le.aomap, + le.lightmap, + le.emissivemap, + le.bumpmap, + le.normalmap, + le.displacementmap, + le.fog, + le.lights, { emissive: { - value: new ae(0) + value: new pe(0) } } ]), - vertexShader: Fe.meshlambert_vert, - fragmentShader: Fe.meshlambert_frag + vertexShader: ke.meshlambert_vert, + fragmentShader: ke.meshlambert_frag }, phong: { - uniforms: yt([ - ie.common, - ie.specularmap, - ie.envmap, - ie.aomap, - ie.lightmap, - ie.emissivemap, - ie.bumpmap, - ie.normalmap, - ie.displacementmap, - ie.fog, - ie.lights, + uniforms: Lt([ + le.common, + le.specularmap, + le.envmap, + le.aomap, + le.lightmap, + le.emissivemap, + le.bumpmap, + le.normalmap, + le.displacementmap, + le.fog, + le.lights, { emissive: { - value: new ae(0) + value: new pe(0) }, specular: { - value: new ae(1118481) + value: new pe(1118481) }, shininess: { value: 30 } } ]), - vertexShader: Fe.meshphong_vert, - fragmentShader: Fe.meshphong_frag + vertexShader: ke.meshphong_vert, + fragmentShader: ke.meshphong_frag }, standard: { - uniforms: yt([ - ie.common, - ie.envmap, - ie.aomap, - ie.lightmap, - ie.emissivemap, - ie.bumpmap, - ie.normalmap, - ie.displacementmap, - ie.roughnessmap, - ie.metalnessmap, - ie.fog, - ie.lights, + uniforms: Lt([ + le.common, + le.envmap, + le.aomap, + le.lightmap, + le.emissivemap, + le.bumpmap, + le.normalmap, + le.displacementmap, + le.roughnessmap, + le.metalnessmap, + le.fog, + le.lights, { emissive: { - value: new ae(0) + value: new pe(0) }, roughness: { value: 1 @@ -7124,58 +8263,58 @@ void main() { } } ]), - vertexShader: Fe.meshphysical_vert, - fragmentShader: Fe.meshphysical_frag + vertexShader: ke.meshphysical_vert, + fragmentShader: ke.meshphysical_frag }, toon: { - uniforms: yt([ - ie.common, - ie.aomap, - ie.lightmap, - ie.emissivemap, - ie.bumpmap, - ie.normalmap, - ie.displacementmap, - ie.gradientmap, - ie.fog, - ie.lights, + uniforms: Lt([ + le.common, + le.aomap, + le.lightmap, + le.emissivemap, + le.bumpmap, + le.normalmap, + le.displacementmap, + le.gradientmap, + le.fog, + le.lights, { emissive: { - value: new ae(0) + value: new pe(0) } } ]), - vertexShader: Fe.meshtoon_vert, - fragmentShader: Fe.meshtoon_frag + vertexShader: ke.meshtoon_vert, + fragmentShader: ke.meshtoon_frag }, matcap: { - uniforms: yt([ - ie.common, - ie.bumpmap, - ie.normalmap, - ie.displacementmap, - ie.fog, + uniforms: Lt([ + le.common, + le.bumpmap, + le.normalmap, + le.displacementmap, + le.fog, { matcap: { value: null } } ]), - vertexShader: Fe.meshmatcap_vert, - fragmentShader: Fe.meshmatcap_frag + vertexShader: ke.meshmatcap_vert, + fragmentShader: ke.meshmatcap_frag }, points: { - uniforms: yt([ - ie.points, - ie.fog + uniforms: Lt([ + le.points, + le.fog ]), - vertexShader: Fe.points_vert, - fragmentShader: Fe.points_frag + vertexShader: ke.points_vert, + fragmentShader: ke.points_frag }, dashed: { - uniforms: yt([ - ie.common, - ie.fog, + uniforms: Lt([ + le.common, + le.fog, { scale: { value: 1 @@ -7188,80 +8327,104 @@ void main() { } } ]), - vertexShader: Fe.linedashed_vert, - fragmentShader: Fe.linedashed_frag + vertexShader: ke.linedashed_vert, + fragmentShader: ke.linedashed_frag }, depth: { - uniforms: yt([ - ie.common, - ie.displacementmap + uniforms: Lt([ + le.common, + le.displacementmap ]), - vertexShader: Fe.depth_vert, - fragmentShader: Fe.depth_frag + vertexShader: ke.depth_vert, + fragmentShader: ke.depth_frag }, normal: { - uniforms: yt([ - ie.common, - ie.bumpmap, - ie.normalmap, - ie.displacementmap, + uniforms: Lt([ + le.common, + le.bumpmap, + le.normalmap, + le.displacementmap, { opacity: { value: 1 } } ]), - vertexShader: Fe.meshnormal_vert, - fragmentShader: Fe.meshnormal_frag + vertexShader: ke.meshnormal_vert, + fragmentShader: ke.meshnormal_frag }, sprite: { - uniforms: yt([ - ie.sprite, - ie.fog + uniforms: Lt([ + le.sprite, + le.fog ]), - vertexShader: Fe.sprite_vert, - fragmentShader: Fe.sprite_frag + vertexShader: ke.sprite_vert, + fragmentShader: ke.sprite_frag }, background: { uniforms: { uvTransform: { - value: new lt + value: new He }, t2D: { value: null + }, + backgroundIntensity: { + value: 1 } }, - vertexShader: Fe.background_vert, - fragmentShader: Fe.background_frag - }, - cube: { - uniforms: yt([ - ie.envmap, - { - opacity: { - value: 1 - } - } - ]), - vertexShader: Fe.cube_vert, - fragmentShader: Fe.cube_frag + vertexShader: ke.background_vert, + fragmentShader: ke.background_frag }, - equirect: { + backgroundCube: { uniforms: { - tEquirect: { + envMap: { value: null - } - }, - vertexShader: Fe.equirect_vert, - fragmentShader: Fe.equirect_frag - }, + }, + flipEnvMap: { + value: -1 + }, + backgroundBlurriness: { + value: 0 + }, + backgroundIntensity: { + value: 1 + } + }, + vertexShader: ke.backgroundCube_vert, + fragmentShader: ke.backgroundCube_frag + }, + cube: { + uniforms: { + tCube: { + value: null + }, + tFlip: { + value: -1 + }, + opacity: { + value: 1 + } + }, + vertexShader: ke.cube_vert, + fragmentShader: ke.cube_frag + }, + equirect: { + uniforms: { + tEquirect: { + value: null + } + }, + vertexShader: ke.equirect_vert, + fragmentShader: ke.equirect_frag + }, distanceRGBA: { - uniforms: yt([ - ie.common, - ie.displacementmap, + uniforms: Lt([ + le.common, + le.displacementmap, { referencePosition: { - value: new M + value: new A }, nearDistance: { value: 1 @@ -7271,29 +8434,29 @@ void main() { } } ]), - vertexShader: Fe.distanceRGBA_vert, - fragmentShader: Fe.distanceRGBA_frag + vertexShader: ke.distanceRGBA_vert, + fragmentShader: ke.distanceRGBA_frag }, shadow: { - uniforms: yt([ - ie.lights, - ie.fog, + uniforms: Lt([ + le.lights, + le.fog, { color: { - value: new ae(0) + value: new pe(0) }, opacity: { value: 1 } } ]), - vertexShader: Fe.shadow_vert, - fragmentShader: Fe.shadow_frag + vertexShader: ke.shadow_vert, + fragmentShader: ke.shadow_frag } }; -qt.physical = { - uniforms: yt([ - qt.standard.uniforms, +nn.physical = { + uniforms: Lt([ + nn.standard.uniforms, { clearcoat: { value: 0 @@ -7301,41 +8464,83 @@ qt.physical = { clearcoatMap: { value: null }, + clearcoatMapTransform: { + value: new He + }, + clearcoatNormalMap: { + value: null + }, + clearcoatNormalMapTransform: { + value: new He + }, + clearcoatNormalScale: { + value: new Z(1, 1) + }, clearcoatRoughness: { value: 0 }, clearcoatRoughnessMap: { value: null }, - clearcoatNormalScale: { - value: new X(1, 1) + clearcoatRoughnessMapTransform: { + value: new He }, - clearcoatNormalMap: { + iridescence: { + value: 0 + }, + iridescenceMap: { + value: null + }, + iridescenceMapTransform: { + value: new He + }, + iridescenceIOR: { + value: 1.3 + }, + iridescenceThicknessMinimum: { + value: 100 + }, + iridescenceThicknessMaximum: { + value: 400 + }, + iridescenceThicknessMap: { value: null }, + iridescenceThicknessMapTransform: { + value: new He + }, sheen: { value: 0 }, sheenColor: { - value: new ae(0) + value: new pe(0) }, sheenColorMap: { value: null }, + sheenColorMapTransform: { + value: new He + }, sheenRoughness: { - value: 0 + value: 1 }, sheenRoughnessMap: { value: null }, + sheenRoughnessMapTransform: { + value: new He + }, transmission: { value: 0 }, transmissionMap: { value: null }, + transmissionMapTransform: { + value: new He + }, transmissionSamplerSize: { - value: new X + value: new Z }, transmissionSamplerMap: { value: null @@ -7346,386 +8551,413 @@ qt.physical = { thicknessMap: { value: null }, + thicknessMapTransform: { + value: new He + }, attenuationDistance: { value: 0 }, attenuationColor: { - value: new ae(0) + value: new pe(0) + }, + specularColor: { + value: new pe(1, 1, 1) + }, + specularColorMap: { + value: null + }, + specularColorMapTransform: { + value: new He }, specularIntensity: { - value: 0 + value: 1 }, specularIntensityMap: { value: null }, - specularColor: { - value: new ae(1, 1, 1) + specularIntensityMapTransform: { + value: new He }, - specularColorMap: { + anisotropyVector: { + value: new Z + }, + anisotropyMap: { value: null + }, + anisotropyMapTransform: { + value: new He } } ]), - vertexShader: Fe.meshphysical_vert, - fragmentShader: Fe.meshphysical_frag + vertexShader: ke.meshphysical_vert, + fragmentShader: ke.meshphysical_frag }; -function Vm(s, e, t, n, i) { - let r = new ae(0), o = 0, a, l, c = null, h = 0, u = null; - function d(m, x) { - let v = !1, g = x.isScene === !0 ? x.background : null; - g && g.isTexture && (g = e.get(g)); - let p = s.xr, _ = p.getSession && p.getSession(); - _ && _.environmentBlendMode === "additive" && (g = null), g === null ? f(r, o) : g && g.isColor && (f(g, 1), v = !0), (s.autoClear || v) && s.clear(s.autoClearColor, s.autoClearDepth, s.autoClearStencil), g && (g.isCubeTexture || g.mapping === Pr) ? (l === void 0 && (l = new st(new wn(1, 1, 1), new sn({ +var cr = { + r: 0, + b: 0, + g: 0 +}; +function t_(s1, e, t, n, i, r, a) { + let o = new pe(0), c = r === !0 ? 0 : 1, l, h, u = null, d = 0, f = null; + function m(g, p) { + let v = !1, x = p.isScene === !0 ? p.background : null; + x && x.isTexture && (x = (p.backgroundBlurriness > 0 ? t : e).get(x)), x === null ? _(o, c) : x && x.isColor && (_(x, 1), v = !0); + let y = s1.xr.getEnvironmentBlendMode(); + y === "additive" ? n.buffers.color.setClear(0, 0, 0, 1, a) : y === "alpha-blend" && n.buffers.color.setClear(0, 0, 0, 0, a), (s1.autoClear || v) && s1.clear(s1.autoClearColor, s1.autoClearDepth, s1.autoClearStencil), x && (x.isCubeTexture || x.mapping === Vs) ? (h === void 0 && (h = new Mt(new Ji(1, 1, 1), new jt({ name: "BackgroundCubeMaterial", - uniforms: Ri(qt.cube.uniforms), - vertexShader: qt.cube.vertexShader, - fragmentShader: qt.cube.fragmentShader, - side: it, + uniforms: $i(nn.backgroundCube.uniforms), + vertexShader: nn.backgroundCube.vertexShader, + fragmentShader: nn.backgroundCube.fragmentShader, + side: Ft, depthTest: !1, depthWrite: !1, fog: !1 - })), l.geometry.deleteAttribute("normal"), l.geometry.deleteAttribute("uv"), l.onBeforeRender = function(y, b, A) { - this.matrixWorld.copyPosition(A.matrixWorld); - }, Object.defineProperty(l.material, "envMap", { + })), h.geometry.deleteAttribute("normal"), h.geometry.deleteAttribute("uv"), h.onBeforeRender = function(b, w, R) { + this.matrixWorld.copyPosition(R.matrixWorld); + }, Object.defineProperty(h.material, "envMap", { get: function() { return this.uniforms.envMap.value; } - }), n.update(l)), l.material.uniforms.envMap.value = g, l.material.uniforms.flipEnvMap.value = g.isCubeTexture && g.isRenderTargetTexture === !1 ? -1 : 1, (c !== g || h !== g.version || u !== s.toneMapping) && (l.material.needsUpdate = !0, c = g, h = g.version, u = s.toneMapping), m.unshift(l, l.geometry, l.material, 0, 0, null)) : g && g.isTexture && (a === void 0 && (a = new st(new Pi(2, 2), new sn({ + }), i.update(h)), h.material.uniforms.envMap.value = x, h.material.uniforms.flipEnvMap.value = x.isCubeTexture && x.isRenderTargetTexture === !1 ? -1 : 1, h.material.uniforms.backgroundBlurriness.value = p.backgroundBlurriness, h.material.uniforms.backgroundIntensity.value = p.backgroundIntensity, h.material.toneMapped = Qe.getTransfer(x.colorSpace) !== nt, (u !== x || d !== x.version || f !== s1.toneMapping) && (h.material.needsUpdate = !0, u = x, d = x.version, f = s1.toneMapping), h.layers.enableAll(), g.unshift(h, h.geometry, h.material, 0, 0, null)) : x && x.isTexture && (l === void 0 && (l = new Mt(new $r(2, 2), new jt({ name: "BackgroundMaterial", - uniforms: Ri(qt.background.uniforms), - vertexShader: qt.background.vertexShader, - fragmentShader: qt.background.fragmentShader, - side: Ai, + uniforms: $i(nn.background.uniforms), + vertexShader: nn.background.vertexShader, + fragmentShader: nn.background.fragmentShader, + side: Bn, depthTest: !1, depthWrite: !1, fog: !1 - })), a.geometry.deleteAttribute("normal"), Object.defineProperty(a.material, "map", { + })), l.geometry.deleteAttribute("normal"), Object.defineProperty(l.material, "map", { get: function() { return this.uniforms.t2D.value; } - }), n.update(a)), a.material.uniforms.t2D.value = g, g.matrixAutoUpdate === !0 && g.updateMatrix(), a.material.uniforms.uvTransform.value.copy(g.matrix), (c !== g || h !== g.version || u !== s.toneMapping) && (a.material.needsUpdate = !0, c = g, h = g.version, u = s.toneMapping), m.unshift(a, a.geometry, a.material, 0, 0, null)); + }), i.update(l)), l.material.uniforms.t2D.value = x, l.material.uniforms.backgroundIntensity.value = p.backgroundIntensity, l.material.toneMapped = Qe.getTransfer(x.colorSpace) !== nt, x.matrixAutoUpdate === !0 && x.updateMatrix(), l.material.uniforms.uvTransform.value.copy(x.matrix), (u !== x || d !== x.version || f !== s1.toneMapping) && (l.material.needsUpdate = !0, u = x, d = x.version, f = s1.toneMapping), l.layers.enableAll(), g.unshift(l, l.geometry, l.material, 0, 0, null)); } - function f(m, x) { - t.buffers.color.setClear(m.r, m.g, m.b, x, i); + function _(g, p) { + g.getRGB(cr, bd(s1)), n.buffers.color.setClear(cr.r, cr.g, cr.b, p, a); } return { getClearColor: function() { - return r; + return o; }, - setClearColor: function(m, x = 1) { - r.set(m), o = x, f(r, o); + setClearColor: function(g, p = 1) { + o.set(g), c = p, _(o, c); }, getClearAlpha: function() { - return o; + return c; }, - setClearAlpha: function(m) { - o = m, f(r, o); + setClearAlpha: function(g) { + c = g, _(o, c); }, - render: d + render: m }; } -function Wm(s, e, t, n) { - let i = s.getParameter(34921), r = n.isWebGL2 ? null : e.get("OES_vertex_array_object"), o = n.isWebGL2 || r !== null, a = {}, l = x(null), c = l; - function h(E, D, U, F, O) { - let ne = !1; - if (o) { - let ce = m(F, U, D); - c !== ce && (c = ce, d(c.object)), ne = v(F, O), ne && g(F, O); +function n_(s1, e, t, n) { + let i = s1.getParameter(s1.MAX_VERTEX_ATTRIBS), r = n.isWebGL2 ? null : e.get("OES_vertex_array_object"), a = n.isWebGL2 || r !== null, o = {}, c = g(null), l = c, h = !1; + function u(U, z, q, H, ne) { + let W = !1; + if (a) { + let K = _(H, q, z); + l !== K && (l = K, f(l.object)), W = p(U, H, q, ne), W && v(U, H, q, ne); } else { - let ce = D.wireframe === !0; - (c.geometry !== F.id || c.program !== U.id || c.wireframe !== ce) && (c.geometry = F.id, c.program = U.id, c.wireframe = ce, ne = !0); + let K = z.wireframe === !0; + (l.geometry !== H.id || l.program !== q.id || l.wireframe !== K) && (l.geometry = H.id, l.program = q.id, l.wireframe = K, W = !0); } - E.isInstancedMesh === !0 && (ne = !0), O !== null && t.update(O, 34963), ne && (L(E, D, U, F), O !== null && s.bindBuffer(34963, t.get(O).buffer)); + ne !== null && t.update(ne, s1.ELEMENT_ARRAY_BUFFER), (W || h) && (h = !1, I(U, z, q, H), ne !== null && s1.bindBuffer(s1.ELEMENT_ARRAY_BUFFER, t.get(ne).buffer)); } - function u() { - return n.isWebGL2 ? s.createVertexArray() : r.createVertexArrayOES(); + function d() { + return n.isWebGL2 ? s1.createVertexArray() : r.createVertexArrayOES(); } - function d(E) { - return n.isWebGL2 ? s.bindVertexArray(E) : r.bindVertexArrayOES(E); + function f(U) { + return n.isWebGL2 ? s1.bindVertexArray(U) : r.bindVertexArrayOES(U); } - function f(E) { - return n.isWebGL2 ? s.deleteVertexArray(E) : r.deleteVertexArrayOES(E); + function m(U) { + return n.isWebGL2 ? s1.deleteVertexArray(U) : r.deleteVertexArrayOES(U); } - function m(E, D, U) { - let F = U.wireframe === !0, O = a[E.id]; - O === void 0 && (O = {}, a[E.id] = O); - let ne = O[D.id]; - ne === void 0 && (ne = {}, O[D.id] = ne); - let ce = ne[F]; - return ce === void 0 && (ce = x(u()), ne[F] = ce), ce; + function _(U, z, q) { + let H = q.wireframe === !0, ne = o[U.id]; + ne === void 0 && (ne = {}, o[U.id] = ne); + let W = ne[z.id]; + W === void 0 && (W = {}, ne[z.id] = W); + let K = W[H]; + return K === void 0 && (K = g(d()), W[H] = K), K; } - function x(E) { - let D = [], U = [], F = []; - for(let O = 0; O < i; O++)D[O] = 0, U[O] = 0, F[O] = 0; + function g(U) { + let z = [], q = [], H = []; + for(let ne = 0; ne < i; ne++)z[ne] = 0, q[ne] = 0, H[ne] = 0; return { geometry: null, program: null, wireframe: !1, - newAttributes: D, - enabledAttributes: U, - attributeDivisors: F, - object: E, + newAttributes: z, + enabledAttributes: q, + attributeDivisors: H, + object: U, attributes: {}, index: null }; } - function v(E, D) { - let U = c.attributes, F = E.attributes, O = 0; - for(let ne in F){ - let ce = U[ne], V = F[ne]; - if (ce === void 0 || ce.attribute !== V || ce.data !== V.data) return !0; - O++; + function p(U, z, q, H) { + let ne = l.attributes, W = z.attributes, K = 0, D = q.getAttributes(); + for(let G in D)if (D[G].location >= 0) { + let fe = ne[G], _e = W[G]; + if (_e === void 0 && (G === "instanceMatrix" && U.instanceMatrix && (_e = U.instanceMatrix), G === "instanceColor" && U.instanceColor && (_e = U.instanceColor)), fe === void 0 || fe.attribute !== _e || _e && fe.data !== _e.data) return !0; + K++; } - return c.attributesNum !== O || c.index !== D; + return l.attributesNum !== K || l.index !== H; } - function g(E, D) { - let U = {}, F = E.attributes, O = 0; - for(let ne in F){ - let ce = F[ne], V = {}; - V.attribute = ce, ce.data && (V.data = ce.data), U[ne] = V, O++; + function v(U, z, q, H) { + let ne = {}, W = z.attributes, K = 0, D = q.getAttributes(); + for(let G in D)if (D[G].location >= 0) { + let fe = W[G]; + fe === void 0 && (G === "instanceMatrix" && U.instanceMatrix && (fe = U.instanceMatrix), G === "instanceColor" && U.instanceColor && (fe = U.instanceColor)); + let _e = {}; + _e.attribute = fe, fe && fe.data && (_e.data = fe.data), ne[G] = _e, K++; } - c.attributes = U, c.attributesNum = O, c.index = D; + l.attributes = ne, l.attributesNum = K, l.index = H; } - function p() { - let E = c.newAttributes; - for(let D = 0, U = E.length; D < U; D++)E[D] = 0; - } - function _(E) { - y(E, 0); - } - function y(E, D) { - let U = c.newAttributes, F = c.enabledAttributes, O = c.attributeDivisors; - U[E] = 1, F[E] === 0 && (s.enableVertexAttribArray(E), F[E] = 1), O[E] !== D && ((n.isWebGL2 ? s : e.get("ANGLE_instanced_arrays"))[n.isWebGL2 ? "vertexAttribDivisor" : "vertexAttribDivisorANGLE"](E, D), O[E] = D); - } - function b() { - let E = c.newAttributes, D = c.enabledAttributes; - for(let U = 0, F = D.length; U < F; U++)D[U] !== E[U] && (s.disableVertexAttribArray(U), D[U] = 0); - } - function A(E, D, U, F, O, ne) { - n.isWebGL2 === !0 && (U === 5124 || U === 5125) ? s.vertexAttribIPointer(E, D, U, O, ne) : s.vertexAttribPointer(E, D, U, F, O, ne); - } - function L(E, D, U, F) { - if (n.isWebGL2 === !1 && (E.isInstancedMesh || F.isInstancedBufferGeometry) && e.get("ANGLE_instanced_arrays") === null) return; - p(); - let O = F.attributes, ne = U.getAttributes(), ce = D.defaultAttributeValues; - for(let V in ne){ - let W = ne[V]; - if (W.location >= 0) { - let he = O[V]; - if (he === void 0 && (V === "instanceMatrix" && E.instanceMatrix && (he = E.instanceMatrix), V === "instanceColor" && E.instanceColor && (he = E.instanceColor)), he !== void 0) { - let le = he.normalized, fe = he.itemSize, Be = t.get(he); - if (Be === void 0) continue; - let Y = Be.buffer, Ce = Be.type, ye = Be.bytesPerElement; + function x() { + let U = l.newAttributes; + for(let z = 0, q = U.length; z < q; z++)U[z] = 0; + } + function y(U) { + b(U, 0); + } + function b(U, z) { + let q = l.newAttributes, H = l.enabledAttributes, ne = l.attributeDivisors; + q[U] = 1, H[U] === 0 && (s1.enableVertexAttribArray(U), H[U] = 1), ne[U] !== z && ((n.isWebGL2 ? s1 : e.get("ANGLE_instanced_arrays"))[n.isWebGL2 ? "vertexAttribDivisor" : "vertexAttribDivisorANGLE"](U, z), ne[U] = z); + } + function w() { + let U = l.newAttributes, z = l.enabledAttributes; + for(let q = 0, H = z.length; q < H; q++)z[q] !== U[q] && (s1.disableVertexAttribArray(q), z[q] = 0); + } + function R(U, z, q, H, ne, W, K) { + K === !0 ? s1.vertexAttribIPointer(U, z, q, ne, W) : s1.vertexAttribPointer(U, z, q, H, ne, W); + } + function I(U, z, q, H) { + if (n.isWebGL2 === !1 && (U.isInstancedMesh || H.isInstancedBufferGeometry) && e.get("ANGLE_instanced_arrays") === null) return; + x(); + let ne = H.attributes, W = q.getAttributes(), K = z.defaultAttributeValues; + for(let D in W){ + let G = W[D]; + if (G.location >= 0) { + let he = ne[D]; + if (he === void 0 && (D === "instanceMatrix" && U.instanceMatrix && (he = U.instanceMatrix), D === "instanceColor" && U.instanceColor && (he = U.instanceColor)), he !== void 0) { + let fe = he.normalized, _e = he.itemSize, we = t.get(he); + if (we === void 0) continue; + let Ee = we.buffer, Te = we.type, Ye = we.bytesPerElement, it = n.isWebGL2 === !0 && (Te === s1.INT || Te === s1.UNSIGNED_INT || he.gpuType === dd); if (he.isInterleavedBufferAttribute) { - let ge = he.data, xe = ge.stride, Oe = he.offset; - if (ge && ge.isInstancedInterleavedBuffer) { - for(let G = 0; G < W.locationSize; G++)y(W.location + G, ge.meshPerAttribute); - E.isInstancedMesh !== !0 && F._maxInstanceCount === void 0 && (F._maxInstanceCount = ge.meshPerAttribute * ge.count); - } else for(let G = 0; G < W.locationSize; G++)_(W.location + G); - s.bindBuffer(34962, Y); - for(let G = 0; G < W.locationSize; G++)A(W.location + G, fe / W.locationSize, Ce, le, xe * ye, (Oe + fe / W.locationSize * G) * ye); + let Ce = he.data, L = Ce.stride, oe = he.offset; + if (Ce.isInstancedInterleavedBuffer) { + for(let X = 0; X < G.locationSize; X++)b(G.location + X, Ce.meshPerAttribute); + U.isInstancedMesh !== !0 && H._maxInstanceCount === void 0 && (H._maxInstanceCount = Ce.meshPerAttribute * Ce.count); + } else for(let X = 0; X < G.locationSize; X++)y(G.location + X); + s1.bindBuffer(s1.ARRAY_BUFFER, Ee); + for(let X = 0; X < G.locationSize; X++)R(G.location + X, _e / G.locationSize, Te, fe, L * Ye, (oe + _e / G.locationSize * X) * Ye, it); } else { if (he.isInstancedBufferAttribute) { - for(let ge = 0; ge < W.locationSize; ge++)y(W.location + ge, he.meshPerAttribute); - E.isInstancedMesh !== !0 && F._maxInstanceCount === void 0 && (F._maxInstanceCount = he.meshPerAttribute * he.count); - } else for(let ge = 0; ge < W.locationSize; ge++)_(W.location + ge); - s.bindBuffer(34962, Y); - for(let ge = 0; ge < W.locationSize; ge++)A(W.location + ge, fe / W.locationSize, Ce, le, fe * ye, fe / W.locationSize * ge * ye); + for(let Ce = 0; Ce < G.locationSize; Ce++)b(G.location + Ce, he.meshPerAttribute); + U.isInstancedMesh !== !0 && H._maxInstanceCount === void 0 && (H._maxInstanceCount = he.meshPerAttribute * he.count); + } else for(let Ce = 0; Ce < G.locationSize; Ce++)y(G.location + Ce); + s1.bindBuffer(s1.ARRAY_BUFFER, Ee); + for(let Ce = 0; Ce < G.locationSize; Ce++)R(G.location + Ce, _e / G.locationSize, Te, fe, _e * Ye, _e / G.locationSize * Ce * Ye, it); } - } else if (ce !== void 0) { - let le = ce[V]; - if (le !== void 0) switch(le.length){ + } else if (K !== void 0) { + let fe = K[D]; + if (fe !== void 0) switch(fe.length){ case 2: - s.vertexAttrib2fv(W.location, le); + s1.vertexAttrib2fv(G.location, fe); break; case 3: - s.vertexAttrib3fv(W.location, le); + s1.vertexAttrib3fv(G.location, fe); break; case 4: - s.vertexAttrib4fv(W.location, le); + s1.vertexAttrib4fv(G.location, fe); break; default: - s.vertexAttrib1fv(W.location, le); + s1.vertexAttrib1fv(G.location, fe); } } } } - b(); + w(); } - function I() { - P(); - for(let E in a){ - let D = a[E]; - for(let U in D){ - let F = D[U]; - for(let O in F)f(F[O].object), delete F[O]; - delete D[U]; + function M() { + Y(); + for(let U in o){ + let z = o[U]; + for(let q in z){ + let H = z[q]; + for(let ne in H)m(H[ne].object), delete H[ne]; + delete z[q]; } - delete a[E]; + delete o[U]; } } - function k(E) { - if (a[E.id] === void 0) return; - let D = a[E.id]; - for(let U in D){ - let F = D[U]; - for(let O in F)f(F[O].object), delete F[O]; - delete D[U]; + function T(U) { + if (o[U.id] === void 0) return; + let z = o[U.id]; + for(let q in z){ + let H = z[q]; + for(let ne in H)m(H[ne].object), delete H[ne]; + delete z[q]; } - delete a[E.id]; + delete o[U.id]; } - function B(E) { - for(let D in a){ - let U = a[D]; - if (U[E.id] === void 0) continue; - let F = U[E.id]; - for(let O in F)f(F[O].object), delete F[O]; - delete U[E.id]; + function O(U) { + for(let z in o){ + let q = o[z]; + if (q[U.id] === void 0) continue; + let H = q[U.id]; + for(let ne in H)m(H[ne].object), delete H[ne]; + delete q[U.id]; } } - function P() { - w(), c !== l && (c = l, d(c.object)); + function Y() { + $(), h = !0, l !== c && (l = c, f(l.object)); } - function w() { - l.geometry = null, l.program = null, l.wireframe = !1; + function $() { + c.geometry = null, c.program = null, c.wireframe = !1; } return { - setup: h, - reset: P, - resetDefaultState: w, - dispose: I, - releaseStatesOfGeometry: k, - releaseStatesOfProgram: B, - initAttributes: p, - enableAttribute: _, - disableUnusedAttributes: b + setup: u, + reset: Y, + resetDefaultState: $, + dispose: M, + releaseStatesOfGeometry: T, + releaseStatesOfProgram: O, + initAttributes: x, + enableAttribute: y, + disableUnusedAttributes: w }; } -function qm(s, e, t, n) { +function i_(s1, e, t, n) { let i = n.isWebGL2, r; - function o(c) { - r = c; + function a(l) { + r = l; } - function a(c, h) { - s.drawArrays(r, c, h), t.update(h, r, 1); + function o(l, h) { + s1.drawArrays(r, l, h), t.update(h, r, 1); } - function l(c, h, u) { + function c(l, h, u) { if (u === 0) return; let d, f; - if (i) d = s, f = "drawArraysInstanced"; + if (i) d = s1, f = "drawArraysInstanced"; else if (d = e.get("ANGLE_instanced_arrays"), f = "drawArraysInstancedANGLE", d === null) { console.error("THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays."); return; } - d[f](r, c, h, u), t.update(h, r, u); + d[f](r, l, h, u), t.update(h, r, u); } - this.setMode = o, this.render = a, this.renderInstances = l; + this.setMode = a, this.render = o, this.renderInstances = c; } -function Xm(s, e, t) { +function s_(s1, e, t) { let n; function i() { if (n !== void 0) return n; if (e.has("EXT_texture_filter_anisotropic") === !0) { - let L = e.get("EXT_texture_filter_anisotropic"); - n = s.getParameter(L.MAX_TEXTURE_MAX_ANISOTROPY_EXT); + let R = e.get("EXT_texture_filter_anisotropic"); + n = s1.getParameter(R.MAX_TEXTURE_MAX_ANISOTROPY_EXT); } else n = 0; return n; } - function r(L) { - if (L === "highp") { - if (s.getShaderPrecisionFormat(35633, 36338).precision > 0 && s.getShaderPrecisionFormat(35632, 36338).precision > 0) return "highp"; - L = "mediump"; + function r(R) { + if (R === "highp") { + if (s1.getShaderPrecisionFormat(s1.VERTEX_SHADER, s1.HIGH_FLOAT).precision > 0 && s1.getShaderPrecisionFormat(s1.FRAGMENT_SHADER, s1.HIGH_FLOAT).precision > 0) return "highp"; + R = "mediump"; } - return L === "mediump" && s.getShaderPrecisionFormat(35633, 36337).precision > 0 && s.getShaderPrecisionFormat(35632, 36337).precision > 0 ? "mediump" : "lowp"; + return R === "mediump" && s1.getShaderPrecisionFormat(s1.VERTEX_SHADER, s1.MEDIUM_FLOAT).precision > 0 && s1.getShaderPrecisionFormat(s1.FRAGMENT_SHADER, s1.MEDIUM_FLOAT).precision > 0 ? "mediump" : "lowp"; } - let o = typeof WebGL2RenderingContext < "u" && s instanceof WebGL2RenderingContext || typeof WebGL2ComputeRenderingContext < "u" && s instanceof WebGL2ComputeRenderingContext, a = t.precision !== void 0 ? t.precision : "highp", l = r(a); - l !== a && (console.warn("THREE.WebGLRenderer:", a, "not supported, using", l, "instead."), a = l); - let c = o || e.has("WEBGL_draw_buffers"), h = t.logarithmicDepthBuffer === !0, u = s.getParameter(34930), d = s.getParameter(35660), f = s.getParameter(3379), m = s.getParameter(34076), x = s.getParameter(34921), v = s.getParameter(36347), g = s.getParameter(36348), p = s.getParameter(36349), _ = d > 0, y = o || e.has("OES_texture_float"), b = _ && y, A = o ? s.getParameter(36183) : 0; + let a = typeof WebGL2RenderingContext < "u" && s1.constructor.name === "WebGL2RenderingContext", o = t.precision !== void 0 ? t.precision : "highp", c = r(o); + c !== o && (console.warn("THREE.WebGLRenderer:", o, "not supported, using", c, "instead."), o = c); + let l = a || e.has("WEBGL_draw_buffers"), h = t.logarithmicDepthBuffer === !0, u = s1.getParameter(s1.MAX_TEXTURE_IMAGE_UNITS), d = s1.getParameter(s1.MAX_VERTEX_TEXTURE_IMAGE_UNITS), f = s1.getParameter(s1.MAX_TEXTURE_SIZE), m = s1.getParameter(s1.MAX_CUBE_MAP_TEXTURE_SIZE), _ = s1.getParameter(s1.MAX_VERTEX_ATTRIBS), g = s1.getParameter(s1.MAX_VERTEX_UNIFORM_VECTORS), p = s1.getParameter(s1.MAX_VARYING_VECTORS), v = s1.getParameter(s1.MAX_FRAGMENT_UNIFORM_VECTORS), x = d > 0, y = a || e.has("OES_texture_float"), b = x && y, w = a ? s1.getParameter(s1.MAX_SAMPLES) : 0; return { - isWebGL2: o, - drawBuffers: c, + isWebGL2: a, + drawBuffers: l, getMaxAnisotropy: i, getMaxPrecision: r, - precision: a, + precision: o, logarithmicDepthBuffer: h, maxTextures: u, maxVertexTextures: d, maxTextureSize: f, maxCubemapSize: m, - maxAttributes: x, - maxVertexUniforms: v, - maxVaryings: g, - maxFragmentUniforms: p, - vertexTextures: _, + maxAttributes: _, + maxVertexUniforms: g, + maxVaryings: p, + maxFragmentUniforms: v, + vertexTextures: x, floatFragmentTextures: y, floatVertexTextures: b, - maxSamples: A + maxSamples: w }; } -function Jm(s) { - let e = this, t = null, n = 0, i = !1, r = !1, o = new Wt, a = new lt, l = { +function r_(s1) { + let e = this, t = null, n = 0, i = !1, r = !1, a = new mn, o = new He, c = { value: null, needsUpdate: !1 }; - this.uniform = l, this.numPlanes = 0, this.numIntersection = 0, this.init = function(u, d, f) { - let m = u.length !== 0 || d || n !== 0 || i; - return i = d, t = h(u, f, 0), n = u.length, m; + this.uniform = c, this.numPlanes = 0, this.numIntersection = 0, this.init = function(u, d) { + let f = u.length !== 0 || d || n !== 0 || i; + return i = d, n = u.length, f; }, this.beginShadows = function() { r = !0, h(null); }, this.endShadows = function() { - r = !1, c(); + r = !1; + }, this.setGlobalState = function(u, d) { + t = h(u, d, 0); }, this.setState = function(u, d, f) { - let m = u.clippingPlanes, x = u.clipIntersection, v = u.clipShadows, g = s.get(u); - if (!i || m === null || m.length === 0 || r && !v) r ? h(null) : c(); + let m = u.clippingPlanes, _ = u.clipIntersection, g = u.clipShadows, p = s1.get(u); + if (!i || m === null || m.length === 0 || r && !g) r ? h(null) : l(); else { - let p = r ? 0 : n, _ = p * 4, y = g.clippingState || null; - l.value = y, y = h(m, d, _, f); - for(let b = 0; b !== _; ++b)y[b] = t[b]; - g.clippingState = y, this.numIntersection = x ? this.numPlanes : 0, this.numPlanes += p; + let v = r ? 0 : n, x = v * 4, y = p.clippingState || null; + c.value = y, y = h(m, d, x, f); + for(let b = 0; b !== x; ++b)y[b] = t[b]; + p.clippingState = y, this.numIntersection = _ ? this.numPlanes : 0, this.numPlanes += v; } }; - function c() { - l.value !== t && (l.value = t, l.needsUpdate = n > 0), e.numPlanes = n, e.numIntersection = 0; + function l() { + c.value !== t && (c.value = t, c.needsUpdate = n > 0), e.numPlanes = n, e.numIntersection = 0; } function h(u, d, f, m) { - let x = u !== null ? u.length : 0, v = null; - if (x !== 0) { - if (v = l.value, m !== !0 || v === null) { - let g = f + x * 4, p = d.matrixWorldInverse; - a.getNormalMatrix(p), (v === null || v.length < g) && (v = new Float32Array(g)); - for(let _ = 0, y = f; _ !== x; ++_, y += 4)o.copy(u[_]).applyMatrix4(p, a), o.normal.toArray(v, y), v[y + 3] = o.constant; + let _ = u !== null ? u.length : 0, g = null; + if (_ !== 0) { + if (g = c.value, m !== !0 || g === null) { + let p = f + _ * 4, v = d.matrixWorldInverse; + o.getNormalMatrix(v), (g === null || g.length < p) && (g = new Float32Array(p)); + for(let x = 0, y = f; x !== _; ++x, y += 4)a.copy(u[x]).applyMatrix4(v, o), a.normal.toArray(g, y), g[y + 3] = a.constant; } - l.value = v, l.needsUpdate = !0; + c.value = g, c.needsUpdate = !0; } - return e.numPlanes = x, e.numIntersection = 0, v; + return e.numPlanes = _, e.numIntersection = 0, g; } } -function Ym(s) { +function a_(s1) { let e = new WeakMap; - function t(o, a) { - return a === Ds ? o.mapping = Bi : a === Fs && (o.mapping = zi), o; + function t(a, o) { + return o === Ir ? a.mapping = zn : o === Ur && (a.mapping = ci), a; } - function n(o) { - if (o && o.isTexture && o.isRenderTargetTexture === !1) { - let a = o.mapping; - if (a === Ds || a === Fs) if (e.has(o)) { - let l = e.get(o).texture; - return t(l, o.mapping); + function n(a) { + if (a && a.isTexture && a.isRenderTargetTexture === !1) { + let o = a.mapping; + if (o === Ir || o === Ur) if (e.has(a)) { + let c = e.get(a).texture; + return t(c, a.mapping); } else { - let l = o.image; - if (l && l.height > 0) { - let c = s.getRenderTarget(), h = new js(l.height / 2); - return h.fromEquirectangularTexture(s, o), e.set(o, h), s.setRenderTarget(c), o.addEventListener("dispose", i), t(h.texture, o.mapping); + let c = a.image; + if (c && c.height > 0) { + let l = new xo(c.height / 2); + return l.fromEquirectangularTexture(s1, a), e.set(a, l), a.addEventListener("dispose", i), t(l.texture, a.mapping); } else return null; } } - return o; + return a; } - function i(o) { - let a = o.target; - a.removeEventListener("dispose", i); - let l = e.get(a); - l !== void 0 && (e.delete(a), l.dispose()); + function i(a) { + let o = a.target; + o.removeEventListener("dispose", i); + let c = e.get(o); + c !== void 0 && (e.delete(o), c.dispose()); } function r() { e = new WeakMap; @@ -7735,15 +8967,14 @@ function Ym(s) { dispose: r }; } -var Fr = class extends Ir { - constructor(e = -1, t = 1, n = 1, i = -1, r = .1, o = 2e3){ - super(); - this.type = "OrthographicCamera", this.zoom = 1, this.view = null, this.left = e, this.right = t, this.top = n, this.bottom = i, this.near = r, this.far = o, this.updateProjectionMatrix(); +var Ls = class extends Cs { + constructor(e = -1, t = 1, n = 1, i = -1, r = .1, a = 2e3){ + super(), this.isOrthographicCamera = !0, this.type = "OrthographicCamera", this.zoom = 1, this.view = null, this.left = e, this.right = t, this.top = n, this.bottom = i, this.near = r, this.far = a, this.updateProjectionMatrix(); } copy(e, t) { return super.copy(e, t), this.left = e.left, this.right = e.right, this.top = e.top, this.bottom = e.bottom, this.near = e.near, this.far = e.far, this.zoom = e.zoom, this.view = e.view === null ? null : Object.assign({}, e.view), this; } - setViewOffset(e, t, n, i, r, o) { + setViewOffset(e, t, n, i, r, a) { this.view === null && (this.view = { enabled: !0, fullWidth: 1, @@ -7752,111 +8983,110 @@ var Fr = class extends Ir { offsetY: 0, width: 1, height: 1 - }), this.view.enabled = !0, this.view.fullWidth = e, this.view.fullHeight = t, this.view.offsetX = n, this.view.offsetY = i, this.view.width = r, this.view.height = o, this.updateProjectionMatrix(); + }), this.view.enabled = !0, this.view.fullWidth = e, this.view.fullHeight = t, this.view.offsetX = n, this.view.offsetY = i, this.view.width = r, this.view.height = a, this.updateProjectionMatrix(); } clearViewOffset() { this.view !== null && (this.view.enabled = !1), this.updateProjectionMatrix(); } updateProjectionMatrix() { - let e = (this.right - this.left) / (2 * this.zoom), t = (this.top - this.bottom) / (2 * this.zoom), n = (this.right + this.left) / 2, i = (this.top + this.bottom) / 2, r = n - e, o = n + e, a = i + t, l = i - t; + let e = (this.right - this.left) / (2 * this.zoom), t = (this.top - this.bottom) / (2 * this.zoom), n = (this.right + this.left) / 2, i = (this.top + this.bottom) / 2, r = n - e, a = n + e, o = i + t, c = i - t; if (this.view !== null && this.view.enabled) { - let c = (this.right - this.left) / this.view.fullWidth / this.zoom, h = (this.top - this.bottom) / this.view.fullHeight / this.zoom; - r += c * this.view.offsetX, o = r + c * this.view.width, a -= h * this.view.offsetY, l = a - h * this.view.height; + let l = (this.right - this.left) / this.view.fullWidth / this.zoom, h = (this.top - this.bottom) / this.view.fullHeight / this.zoom; + r += l * this.view.offsetX, a = r + l * this.view.width, o -= h * this.view.offsetY, c = o - h * this.view.height; } - this.projectionMatrix.makeOrthographic(r, o, a, l, this.near, this.far), this.projectionMatrixInverse.copy(this.projectionMatrix).invert(); + this.projectionMatrix.makeOrthographic(r, a, o, c, this.near, this.far, this.coordinateSystem), this.projectionMatrixInverse.copy(this.projectionMatrix).invert(); } toJSON(e) { let t = super.toJSON(e); return t.object.zoom = this.zoom, t.object.left = this.left, t.object.right = this.right, t.object.top = this.top, t.object.bottom = this.bottom, t.object.near = this.near, t.object.far = this.far, this.view !== null && (t.object.view = Object.assign({}, this.view)), t; } -}; -Fr.prototype.isOrthographicCamera = !0; -var Gi = class extends sn { - constructor(e){ - super(e); - this.type = "RawShaderMaterial"; - } -}; -Gi.prototype.isRawShaderMaterial = !0; -var Ei = 4, Mn = 8, Vt = Math.pow(2, Mn), sh = [ +}, Hi = 4, hh = [ .125, .215, .35, .446, .526, .582 -], oh = Mn - Ei + 1 + sh.length, pi = 20, Hs = { - [Nt]: 0, - [Oi]: 1 -}, Go = new Fr, { _lodPlanes: ji , _sizeLods: Ll , _sigmas: ls } = Zm(), Rl = new ae, Vo = null, On = (1 + Math.sqrt(5)) / 2, mi = 1 / On, Pl = [ - new M(1, 1, 1), - new M(-1, 1, 1), - new M(1, 1, -1), - new M(-1, 1, -1), - new M(0, On, mi), - new M(0, On, -mi), - new M(mi, 0, On), - new M(-mi, 0, On), - new M(On, mi, 0), - new M(-On, mi, 0) -], ah = class { +], ei = 20, $a = new Ls, uh = new pe, Ka = null, jn = (1 + Math.sqrt(5)) / 2, Li = 1 / jn, dh = [ + new A(1, 1, 1), + new A(-1, 1, 1), + new A(1, 1, -1), + new A(-1, 1, -1), + new A(0, jn, Li), + new A(0, jn, -Li), + new A(Li, 0, jn), + new A(-Li, 0, jn), + new A(jn, Li, 0), + new A(-jn, Li, 0) +], Kr = class { constructor(e){ - this._renderer = e, this._pingPongRenderTarget = null, this._blurMaterial = $m(pi), this._equirectShader = null, this._cubemapShader = null, this._compileMaterial(this._blurMaterial); + this._renderer = e, this._pingPongRenderTarget = null, this._lodMax = 0, this._cubeSize = 0, this._lodPlanes = [], this._sizeLods = [], this._sigmas = [], this._blurMaterial = null, this._cubemapMaterial = null, this._equirectMaterial = null, this._compileMaterial(this._blurMaterial); } fromScene(e, t = 0, n = .1, i = 100) { - Vo = this._renderer.getRenderTarget(); + Ka = this._renderer.getRenderTarget(), this._setSize(256); let r = this._allocateTargets(); - return this._sceneToCubeUV(e, n, i, r), t > 0 && this._blur(r, 0, 0, t), this._applyPMREM(r), this._cleanup(r), r; + return r.depthBuffer = !0, this._sceneToCubeUV(e, n, i, r), t > 0 && this._blur(r, 0, 0, t), this._applyPMREM(r), this._cleanup(r), r; } - fromEquirectangular(e) { - return this._fromTexture(e); + fromEquirectangular(e, t = null) { + return this._fromTexture(e, t); } - fromCubemap(e) { - return this._fromTexture(e); + fromCubemap(e, t = null) { + return this._fromTexture(e, t); } compileCubemapShader() { - this._cubemapShader === null && (this._cubemapShader = Fl(), this._compileMaterial(this._cubemapShader)); + this._cubemapMaterial === null && (this._cubemapMaterial = mh(), this._compileMaterial(this._cubemapMaterial)); } compileEquirectangularShader() { - this._equirectShader === null && (this._equirectShader = Dl(), this._compileMaterial(this._equirectShader)); + this._equirectMaterial === null && (this._equirectMaterial = ph(), this._compileMaterial(this._equirectMaterial)); } dispose() { - this._blurMaterial.dispose(), this._cubemapShader !== null && this._cubemapShader.dispose(), this._equirectShader !== null && this._equirectShader.dispose(); - for(let e = 0; e < ji.length; e++)ji[e].dispose(); + this._dispose(), this._cubemapMaterial !== null && this._cubemapMaterial.dispose(), this._equirectMaterial !== null && this._equirectMaterial.dispose(); + } + _setSize(e) { + this._lodMax = Math.floor(Math.log2(e)), this._cubeSize = Math.pow(2, this._lodMax); + } + _dispose() { + this._blurMaterial !== null && this._blurMaterial.dispose(), this._pingPongRenderTarget !== null && this._pingPongRenderTarget.dispose(); + for(let e = 0; e < this._lodPlanes.length; e++)this._lodPlanes[e].dispose(); } _cleanup(e) { - this._pingPongRenderTarget.dispose(), this._renderer.setRenderTarget(Vo), e.scissorTest = !1, cs(e, 0, 0, e.width, e.height); + this._renderer.setRenderTarget(Ka), e.scissorTest = !1, lr(e, 0, 0, e.width, e.height); } - _fromTexture(e) { - Vo = this._renderer.getRenderTarget(); - let t = this._allocateTargets(e); - return this._textureToCubeUV(e, t), this._applyPMREM(t), this._cleanup(t), t; + _fromTexture(e, t) { + e.mapping === zn || e.mapping === ci ? this._setSize(e.image.length === 0 ? 16 : e.image[0].width || e.image[0].image.width) : this._setSize(e.image.width / 4), Ka = this._renderer.getRenderTarget(); + let n = t || this._allocateTargets(); + return this._textureToCubeUV(e, n), this._applyPMREM(n), this._cleanup(n), n; } - _allocateTargets(e) { - let t = { - magFilter: tt, - minFilter: tt, + _allocateTargets() { + let e = 3 * Math.max(this._cubeSize, 112), t = 4 * this._cubeSize, n = { + magFilter: mt, + minFilter: mt, generateMipmaps: !1, - type: kn, - format: ct, - encoding: Nt, + type: Ts, + format: Wt, + colorSpace: Mn, depthBuffer: !1 - }, n = Il(t); - return n.depthBuffer = !e, this._pingPongRenderTarget = Il(t), n; + }, i = fh(e, t, n); + if (this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== e || this._pingPongRenderTarget.height !== t) { + this._pingPongRenderTarget !== null && this._dispose(), this._pingPongRenderTarget = fh(e, t, n); + let { _lodMax: r } = this; + ({ sizeLods: this._sizeLods , lodPlanes: this._lodPlanes , sigmas: this._sigmas } = o_(r)), this._blurMaterial = c_(r, e, t); + } + return i; } _compileMaterial(e) { - let t = new st(ji[0], e); - this._renderer.compile(t, Go); + let t = new Mt(this._lodPlanes[0], e); + this._renderer.compile(t, $a); } _sceneToCubeUV(e, t, n, i) { - let a = new ut(90, 1, t, n), l = [ + let o = new yt(90, 1, t, n), c = [ 1, -1, 1, 1, 1, 1 - ], c = [ + ], l = [ 1, 1, 1, @@ -7864,133 +9094,139 @@ var Ei = 4, Mn = 8, Vt = Math.pow(2, Mn), sh = [ -1, -1 ], h = this._renderer, u = h.autoClear, d = h.toneMapping; - h.getClearColor(Rl), h.toneMapping = _n, h.autoClear = !1; - let f = new hn({ + h.getClearColor(uh), h.toneMapping = Nn, h.autoClear = !1; + let f = new Sn({ name: "PMREM.Background", - side: it, + side: Ft, depthWrite: !1, depthTest: !1 - }), m = new st(new wn, f), x = !1, v = e.background; - v ? v.isColor && (f.color.copy(v), e.background = null, x = !0) : (f.color.copy(Rl), x = !0); - for(let g = 0; g < 6; g++){ - let p = g % 3; - p == 0 ? (a.up.set(0, l[g], 0), a.lookAt(c[g], 0, 0)) : p == 1 ? (a.up.set(0, 0, l[g]), a.lookAt(0, c[g], 0)) : (a.up.set(0, l[g], 0), a.lookAt(0, 0, c[g])), cs(i, p * Vt, g > 2 ? Vt : 0, Vt, Vt), h.setRenderTarget(i), x && h.render(m, a), h.render(e, a); + }), m = new Mt(new Ji, f), _ = !1, g = e.background; + g ? g.isColor && (f.color.copy(g), e.background = null, _ = !0) : (f.color.copy(uh), _ = !0); + for(let p = 0; p < 6; p++){ + let v = p % 3; + v === 0 ? (o.up.set(0, c[p], 0), o.lookAt(l[p], 0, 0)) : v === 1 ? (o.up.set(0, 0, c[p]), o.lookAt(0, l[p], 0)) : (o.up.set(0, c[p], 0), o.lookAt(0, 0, l[p])); + let x = this._cubeSize; + lr(i, v * x, p > 2 ? x : 0, x, x), h.setRenderTarget(i), _ && h.render(m, o), h.render(e, o); } - m.geometry.dispose(), m.material.dispose(), h.toneMapping = d, h.autoClear = u, e.background = v; - } - _setEncoding(e, t) { - this._renderer.capabilities.isWebGL2 === !0 && t.format === ct && t.type === rn && t.encoding === Oi ? e.value = Hs[Nt] : e.value = Hs[t.encoding]; + m.geometry.dispose(), m.material.dispose(), h.toneMapping = d, h.autoClear = u, e.background = g; } _textureToCubeUV(e, t) { - let n = this._renderer, i = e.mapping === Bi || e.mapping === zi; - i ? this._cubemapShader == null && (this._cubemapShader = Fl()) : this._equirectShader == null && (this._equirectShader = Dl()); - let r = i ? this._cubemapShader : this._equirectShader, o = new st(ji[0], r), a = r.uniforms; - a.envMap.value = e, i || a.texelSize.value.set(1 / e.image.width, 1 / e.image.height), this._setEncoding(a.inputEncoding, e), cs(t, 0, 0, 3 * Vt, 2 * Vt), n.setRenderTarget(t), n.render(o, Go); + let n = this._renderer, i = e.mapping === zn || e.mapping === ci; + i ? (this._cubemapMaterial === null && (this._cubemapMaterial = mh()), this._cubemapMaterial.uniforms.flipEnvMap.value = e.isRenderTargetTexture === !1 ? -1 : 1) : this._equirectMaterial === null && (this._equirectMaterial = ph()); + let r = i ? this._cubemapMaterial : this._equirectMaterial, a = new Mt(this._lodPlanes[0], r), o = r.uniforms; + o.envMap.value = e; + let c = this._cubeSize; + lr(t, 0, 0, 3 * c, 2 * c), n.setRenderTarget(t), n.render(a, $a); } _applyPMREM(e) { let t = this._renderer, n = t.autoClear; t.autoClear = !1; - for(let i = 1; i < oh; i++){ - let r = Math.sqrt(ls[i] * ls[i] - ls[i - 1] * ls[i - 1]), o = Pl[(i - 1) % Pl.length]; - this._blur(e, i - 1, i, r, o); + for(let i = 1; i < this._lodPlanes.length; i++){ + let r = Math.sqrt(this._sigmas[i] * this._sigmas[i] - this._sigmas[i - 1] * this._sigmas[i - 1]), a = dh[(i - 1) % dh.length]; + this._blur(e, i - 1, i, r, a); } t.autoClear = n; } _blur(e, t, n, i, r) { - let o = this._pingPongRenderTarget; - this._halfBlur(e, o, t, n, i, "latitudinal", r), this._halfBlur(o, e, n, n, i, "longitudinal", r); - } - _halfBlur(e, t, n, i, r, o, a) { - let l = this._renderer, c = this._blurMaterial; - o !== "latitudinal" && o !== "longitudinal" && console.error("blur direction must be either latitudinal or longitudinal!"); - let h = 3, u = new st(ji[i], c), d = c.uniforms, f = Ll[n] - 1, m = isFinite(r) ? Math.PI / (2 * f) : 2 * Math.PI / (2 * pi - 1), x = r / m, v = isFinite(r) ? 1 + Math.floor(h * x) : pi; - v > pi && console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${v} samples when the maximum is set to ${pi}`); - let g = [], p = 0; - for(let A = 0; A < pi; ++A){ - let L = A / x, I = Math.exp(-L * L / 2); - g.push(I), A == 0 ? p += I : A < v && (p += 2 * I); - } - for(let A = 0; A < g.length; A++)g[A] = g[A] / p; - d.envMap.value = e.texture, d.samples.value = v, d.weights.value = g, d.latitudinal.value = o === "latitudinal", a && (d.poleAxis.value = a), d.dTheta.value = m, d.mipInt.value = Mn - n; - let _ = Ll[i], y = 3 * Math.max(0, Vt - 2 * _), b = (i === 0 ? 0 : 2 * Vt) + 2 * _ * (i > Mn - Ei ? i - Mn + Ei : 0); - cs(t, y, b, 3 * _, 2 * _), l.setRenderTarget(t), l.render(u, Go); - } -}; -function Zm() { - let s = [], e = [], t = [], n = Mn; - for(let i = 0; i < oh; i++){ - let r = Math.pow(2, n); - e.push(r); - let o = 1 / r; - i > Mn - Ei ? o = sh[i - Mn + Ei - 1] : i == 0 && (o = 0), t.push(o); - let a = 1 / (r - 1), l = -a / 2, c = 1 + a / 2, h = [ - l, - l, - c, - l, - c, - c, - l, - l, - c, - c, - l, - c - ], u = 6, d = 6, f = 3, m = 2, x = 1, v = new Float32Array(f * d * u), g = new Float32Array(m * d * u), p = new Float32Array(x * d * u); - for(let y = 0; y < u; y++){ - let b = y % 3 * 2 / 3 - 1, A = y > 2 ? 0 : -1, L = [ - b, - A, + let a = this._pingPongRenderTarget; + this._halfBlur(e, a, t, n, i, "latitudinal", r), this._halfBlur(a, e, n, n, i, "longitudinal", r); + } + _halfBlur(e, t, n, i, r, a, o) { + let c = this._renderer, l = this._blurMaterial; + a !== "latitudinal" && a !== "longitudinal" && console.error("blur direction must be either latitudinal or longitudinal!"); + let h = 3, u = new Mt(this._lodPlanes[i], l), d = l.uniforms, f = this._sizeLods[n] - 1, m = isFinite(r) ? Math.PI / (2 * f) : 2 * Math.PI / (2 * ei - 1), _ = r / m, g = isFinite(r) ? 1 + Math.floor(h * _) : ei; + g > ei && console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${g} samples when the maximum is set to ${ei}`); + let p = [], v = 0; + for(let R = 0; R < ei; ++R){ + let I = R / _, M = Math.exp(-I * I / 2); + p.push(M), R === 0 ? v += M : R < g && (v += 2 * M); + } + for(let R = 0; R < p.length; R++)p[R] = p[R] / v; + d.envMap.value = e.texture, d.samples.value = g, d.weights.value = p, d.latitudinal.value = a === "latitudinal", o && (d.poleAxis.value = o); + let { _lodMax: x } = this; + d.dTheta.value = m, d.mipInt.value = x - n; + let y = this._sizeLods[i], b = 3 * y * (i > x - Hi ? i - x + Hi : 0), w = 4 * (this._cubeSize - y); + lr(t, b, w, 3 * y, 2 * y), c.setRenderTarget(t), c.render(u, $a); + } +}; +function o_(s1) { + let e = [], t = [], n = [], i = s1, r = s1 - Hi + 1 + hh.length; + for(let a = 0; a < r; a++){ + let o = Math.pow(2, i); + t.push(o); + let c = 1 / o; + a > s1 - Hi ? c = hh[a - s1 + Hi - 1] : a === 0 && (c = 0), n.push(c); + let l = 1 / (o - 2), h = -l, u = 1 + l, d = [ + h, + h, + u, + h, + u, + u, + h, + h, + u, + u, + h, + u + ], f = 6, m = 6, _ = 3, g = 2, p = 1, v = new Float32Array(_ * m * f), x = new Float32Array(g * m * f), y = new Float32Array(p * m * f); + for(let w = 0; w < f; w++){ + let R = w % 3 * 2 / 3 - 1, I = w > 2 ? 0 : -1, M = [ + R, + I, 0, - b + 2 / 3, - A, + R + 2 / 3, + I, 0, - b + 2 / 3, - A + 1, + R + 2 / 3, + I + 1, 0, - b, - A, + R, + I, 0, - b + 2 / 3, - A + 1, + R + 2 / 3, + I + 1, 0, - b, - A + 1, + R, + I + 1, 0 ]; - v.set(L, f * d * y), g.set(h, m * d * y); - let I = [ - y, - y, - y, - y, - y, - y + v.set(M, _ * m * w), x.set(d, g * m * w); + let T = [ + w, + w, + w, + w, + w, + w ]; - p.set(I, x * d * y); + y.set(T, p * m * w); } - let _ = new _e; - _.setAttribute("position", new Ue(v, f)), _.setAttribute("uv", new Ue(g, m)), _.setAttribute("faceIndex", new Ue(p, x)), s.push(_), n > Ei && n--; + let b = new Ge; + b.setAttribute("position", new et(v, _)), b.setAttribute("uv", new et(x, g)), b.setAttribute("faceIndex", new et(y, p)), e.push(b), i > Hi && i--; } return { - _lodPlanes: s, - _sizeLods: e, - _sigmas: t + lodPlanes: e, + sizeLods: t, + sigmas: n }; } -function Il(s) { - let e = new At(3 * Vt, 3 * Vt, s); - return e.texture.mapping = Pr, e.texture.name = "PMREM.cubeUv", e.scissorTest = !0, e; +function fh(s1, e, t) { + let n = new qt(s1, e, t); + return n.texture.mapping = Vs, n.texture.name = "PMREM.cubeUv", n.scissorTest = !0, n; } -function cs(s, e, t, n, i) { - s.viewport.set(e, t, n, i), s.scissor.set(e, t, n, i); +function lr(s1, e, t, n, i) { + s1.viewport.set(e, t, n, i), s1.scissor.set(e, t, n, i); } -function $m(s) { - let e = new Float32Array(s), t = new M(0, 1, 0); - return new Gi({ +function c_(s1, e, t) { + let n = new Float32Array(ei), i = new A(0, 1, 0); + return new jt({ name: "SphericalGaussianBlur", defines: { - n: s + n: ei, + CUBEUV_TEXEL_WIDTH: 1 / e, + CUBEUV_TEXEL_HEIGHT: 1 / t, + CUBEUV_MAX_MIP: `${s1}.0` }, uniforms: { envMap: { @@ -8000,7 +9236,7 @@ function $m(s) { value: 1 }, weights: { - value: e + value: n }, latitudinal: { value: !1 @@ -8012,10 +9248,10 @@ function $m(s) { value: 0 }, poleAxis: { - value: t + value: i } }, - vertexShader: fa(), + vertexShader: Zc(), fragmentShader: ` precision mediump float; @@ -8031,8 +9267,6 @@ function $m(s) { uniform float mipInt; uniform vec3 poleAxis; - ${pa()} - #define ENVMAP_TYPE_CUBE_UV #include @@ -8079,27 +9313,20 @@ function $m(s) { } `, - blending: vn, + blending: Dn, depthTest: !1, depthWrite: !1 }); } -function Dl() { - let s = new X(1, 1); - return new Gi({ +function ph() { + return new jt({ name: "EquirectangularToCubeUV", uniforms: { envMap: { value: null - }, - texelSize: { - value: s - }, - inputEncoding: { - value: Hs[Nt] } }, - vertexShader: fa(), + vertexShader: Zc(), fragmentShader: ` precision mediump float; @@ -8108,82 +9335,63 @@ function Dl() { varying vec3 vOutputDirection; uniform sampler2D envMap; - uniform vec2 texelSize; - - ${pa()} #include void main() { - gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); - vec3 outputDirection = normalize( vOutputDirection ); vec2 uv = equirectUv( outputDirection ); - vec2 f = fract( uv / texelSize - 0.5 ); - uv -= f * texelSize; - vec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb; - uv.x += texelSize.x; - vec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb; - uv.y += texelSize.y; - vec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb; - uv.x -= texelSize.x; - vec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb; - - vec3 tm = mix( tl, tr, f.x ); - vec3 bm = mix( bl, br, f.x ); - gl_FragColor.rgb = mix( tm, bm, f.y ); + gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); } `, - blending: vn, + blending: Dn, depthTest: !1, depthWrite: !1 }); } -function Fl() { - return new Gi({ +function mh() { + return new jt({ name: "CubemapToCubeUV", uniforms: { envMap: { value: null }, - inputEncoding: { - value: Hs[Nt] + flipEnvMap: { + value: -1 } }, - vertexShader: fa(), + vertexShader: Zc(), fragmentShader: ` precision mediump float; precision mediump int; + uniform float flipEnvMap; + varying vec3 vOutputDirection; uniform samplerCube envMap; - ${pa()} - void main() { - gl_FragColor = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ); + gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); } `, - blending: vn, + blending: Dn, depthTest: !1, depthWrite: !1 }); } -function fa() { +function Zc() { return ` precision mediump float; precision mediump int; - attribute vec3 position; - attribute vec2 uv; attribute float faceIndex; varying vec3 vOutputDirection; @@ -8236,93 +9444,68 @@ function fa() { } `; } -function pa() { - return ` - - uniform int inputEncoding; - - #include - - vec4 inputTexelToLinear( vec4 value ) { - - if ( inputEncoding == 0 ) { - - return value; - - } else { - - return sRGBToLinear( value ); - - } - - } - - vec4 envMapTexelToLinear( vec4 color ) { - - return inputTexelToLinear( color ); - - } - `; -} -function jm(s) { +function l_(s1) { let e = new WeakMap, t = null; - function n(a) { - if (a && a.isTexture && a.isRenderTargetTexture === !1) { - let l = a.mapping, c = l === Ds || l === Fs, h = l === Bi || l === zi; - if (c || h) { - if (e.has(a)) return e.get(a).texture; + function n(o) { + if (o && o.isTexture) { + let c = o.mapping, l = c === Ir || c === Ur, h = c === zn || c === ci; + if (l || h) if (o.isRenderTargetTexture && o.needsPMREMUpdate === !0) { + o.needsPMREMUpdate = !1; + let u = e.get(o); + return t === null && (t = new Kr(s1)), u = l ? t.fromEquirectangular(o, u) : t.fromCubemap(o, u), e.set(o, u), u.texture; + } else { + if (e.has(o)) return e.get(o).texture; { - let u = a.image; - if (c && u && u.height > 0 || h && u && i(u)) { - let d = s.getRenderTarget(); - t === null && (t = new ah(s)); - let f = c ? t.fromEquirectangular(a) : t.fromCubemap(a); - return e.set(a, f), s.setRenderTarget(d), a.addEventListener("dispose", r), f.texture; + let u = o.image; + if (l && u && u.height > 0 || h && u && i(u)) { + t === null && (t = new Kr(s1)); + let d = l ? t.fromEquirectangular(o) : t.fromCubemap(o); + return e.set(o, d), o.addEventListener("dispose", r), d.texture; } else return null; } } } - return a; + return o; } - function i(a) { - let l = 0, c = 6; - for(let h = 0; h < c; h++)a[h] !== void 0 && l++; - return l === c; + function i(o) { + let c = 0, l = 6; + for(let h = 0; h < l; h++)o[h] !== void 0 && c++; + return c === l; } - function r(a) { - let l = a.target; - l.removeEventListener("dispose", r); - let c = e.get(l); - c !== void 0 && (e.delete(l), c.dispose()); + function r(o) { + let c = o.target; + c.removeEventListener("dispose", r); + let l = e.get(c); + l !== void 0 && (e.delete(c), l.dispose()); } - function o() { + function a() { e = new WeakMap, t !== null && (t.dispose(), t = null); } return { get: n, - dispose: o + dispose: a }; } -function Qm(s) { +function h_(s1) { let e = {}; function t(n) { if (e[n] !== void 0) return e[n]; let i; switch(n){ case "WEBGL_depth_texture": - i = s.getExtension("WEBGL_depth_texture") || s.getExtension("MOZ_WEBGL_depth_texture") || s.getExtension("WEBKIT_WEBGL_depth_texture"); + i = s1.getExtension("WEBGL_depth_texture") || s1.getExtension("MOZ_WEBGL_depth_texture") || s1.getExtension("WEBKIT_WEBGL_depth_texture"); break; case "EXT_texture_filter_anisotropic": - i = s.getExtension("EXT_texture_filter_anisotropic") || s.getExtension("MOZ_EXT_texture_filter_anisotropic") || s.getExtension("WEBKIT_EXT_texture_filter_anisotropic"); + i = s1.getExtension("EXT_texture_filter_anisotropic") || s1.getExtension("MOZ_EXT_texture_filter_anisotropic") || s1.getExtension("WEBKIT_EXT_texture_filter_anisotropic"); break; case "WEBGL_compressed_texture_s3tc": - i = s.getExtension("WEBGL_compressed_texture_s3tc") || s.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || s.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc"); + i = s1.getExtension("WEBGL_compressed_texture_s3tc") || s1.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || s1.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc"); break; case "WEBGL_compressed_texture_pvrtc": - i = s.getExtension("WEBGL_compressed_texture_pvrtc") || s.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc"); + i = s1.getExtension("WEBGL_compressed_texture_pvrtc") || s1.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc"); break; default: - i = s.getExtension(n); + i = s1.getExtension(n); } return e[n] = i, i; } @@ -8339,89 +9522,93 @@ function Qm(s) { } }; } -function Km(s, e, t, n) { +function u_(s1, e, t, n) { let i = {}, r = new WeakMap; - function o(u) { + function a(u) { let d = u.target; d.index !== null && e.remove(d.index); for(let m in d.attributes)e.remove(d.attributes[m]); - d.removeEventListener("dispose", o), delete i[d.id]; + for(let m in d.morphAttributes){ + let _ = d.morphAttributes[m]; + for(let g = 0, p = _.length; g < p; g++)e.remove(_[g]); + } + d.removeEventListener("dispose", a), delete i[d.id]; let f = r.get(d); f && (e.remove(f), r.delete(d)), n.releaseStatesOfGeometry(d), d.isInstancedBufferGeometry === !0 && delete d._maxInstanceCount, t.memory.geometries--; } - function a(u, d) { - return i[d.id] === !0 || (d.addEventListener("dispose", o), i[d.id] = !0, t.memory.geometries++), d; + function o(u, d) { + return i[d.id] === !0 || (d.addEventListener("dispose", a), i[d.id] = !0, t.memory.geometries++), d; } - function l(u) { + function c(u) { let d = u.attributes; - for(let m in d)e.update(d[m], 34962); + for(let m in d)e.update(d[m], s1.ARRAY_BUFFER); let f = u.morphAttributes; for(let m in f){ - let x = f[m]; - for(let v = 0, g = x.length; v < g; v++)e.update(x[v], 34962); + let _ = f[m]; + for(let g = 0, p = _.length; g < p; g++)e.update(_[g], s1.ARRAY_BUFFER); } } - function c(u) { - let d = [], f = u.index, m = u.attributes.position, x = 0; + function l(u) { + let d = [], f = u.index, m = u.attributes.position, _ = 0; if (f !== null) { - let p = f.array; - x = f.version; - for(let _ = 0, y = p.length; _ < y; _ += 3){ - let b = p[_ + 0], A = p[_ + 1], L = p[_ + 2]; - d.push(b, A, A, L, L, b); + let v = f.array; + _ = f.version; + for(let x = 0, y = v.length; x < y; x += 3){ + let b = v[x + 0], w = v[x + 1], R = v[x + 2]; + d.push(b, w, w, R, R, b); } - } else { - let p = m.array; - x = m.version; - for(let _ = 0, y = p.length / 3 - 1; _ < y; _ += 3){ - let b = _ + 0, A = _ + 1, L = _ + 2; - d.push(b, A, A, L, L, b); + } else if (m !== void 0) { + let v = m.array; + _ = m.version; + for(let x = 0, y = v.length / 3 - 1; x < y; x += 3){ + let b = x + 0, w = x + 1, R = x + 2; + d.push(b, w, w, R, R, b); } - } - let v = new (Yc(d) > 65535 ? Zs : Ys)(d, 1); - v.version = x; - let g = r.get(u); - g && e.remove(g), r.set(u, v); + } else return; + let g = new (Md(d) ? Jr : Zr)(d, 1); + g.version = _; + let p = r.get(u); + p && e.remove(p), r.set(u, g); } function h(u) { let d = r.get(u); if (d) { let f = u.index; - f !== null && d.version < f.version && c(u); - } else c(u); + f !== null && d.version < f.version && l(u); + } else l(u); return r.get(u); } return { - get: a, - update: l, + get: o, + update: c, getWireframeAttribute: h }; } -function eg(s, e, t, n) { +function d_(s1, e, t, n) { let i = n.isWebGL2, r; - function o(d) { + function a(d) { r = d; } - let a, l; - function c(d) { - a = d.type, l = d.bytesPerElement; + let o, c; + function l(d) { + o = d.type, c = d.bytesPerElement; } function h(d, f) { - s.drawElements(r, f, a, d * l), t.update(f, r, 1); + s1.drawElements(r, f, o, d * c), t.update(f, r, 1); } function u(d, f, m) { if (m === 0) return; - let x, v; - if (i) x = s, v = "drawElementsInstanced"; - else if (x = e.get("ANGLE_instanced_arrays"), v = "drawElementsInstancedANGLE", x === null) { + let _, g; + if (i) _ = s1, g = "drawElementsInstanced"; + else if (_ = e.get("ANGLE_instanced_arrays"), g = "drawElementsInstancedANGLE", _ === null) { console.error("THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays."); return; } - x[v](r, f, a, d * l, m), t.update(f, r, m); + _[g](r, f, o, d * c, m), t.update(f, r, m); } - this.setMode = o, this.setIndex = c, this.render = h, this.renderInstances = u; + this.setMode = a, this.setIndex = l, this.render = h, this.renderInstances = u; } -function tg(s) { +function f_(s1) { let e = { geometries: 0, textures: 0 @@ -8432,30 +9619,30 @@ function tg(s) { points: 0, lines: 0 }; - function n(r, o, a) { - switch(t.calls++, o){ - case 4: - t.triangles += a * (r / 3); + function n(r, a, o) { + switch(t.calls++, a){ + case s1.TRIANGLES: + t.triangles += o * (r / 3); break; - case 1: - t.lines += a * (r / 2); + case s1.LINES: + t.lines += o * (r / 2); break; - case 3: - t.lines += a * (r - 1); + case s1.LINE_STRIP: + t.lines += o * (r - 1); break; - case 2: - t.lines += a * r; + case s1.LINE_LOOP: + t.lines += o * r; break; - case 0: - t.points += a * r; + case s1.POINTS: + t.points += o * r; break; default: - console.error("THREE.WebGLInfo: Unknown draw mode:", o); + console.error("THREE.WebGLInfo: Unknown draw mode:", a); break; } } function i() { - t.frame++, t.calls = 0, t.triangles = 0, t.points = 0, t.lines = 0; + t.calls = 0, t.triangles = 0, t.points = 0, t.lines = 0; } return { memory: e, @@ -8466,710 +9653,749 @@ function tg(s) { update: n }; } -var Qs = class extends ot { - constructor(e = null, t = 1, n = 1, i = 1){ - super(null); - this.image = { - data: e, - width: t, - height: n, - depth: i - }, this.magFilter = rt, this.minFilter = rt, this.wrapR = vt, this.generateMipmaps = !1, this.flipY = !1, this.unpackAlignment = 1; - } -}; -Qs.prototype.isDataTexture2DArray = !0; -function ng(s, e) { - return s[0] - e[0]; -} -function ig(s, e) { - return Math.abs(e[1]) - Math.abs(s[1]); +function p_(s1, e) { + return s1[0] - e[0]; } -function Nl(s, e) { - let t = 1, n = e.isInterleavedBufferAttribute ? e.data.array : e.array; - n instanceof Int8Array ? t = 127 : n instanceof Int16Array ? t = 32767 : n instanceof Int32Array ? t = 2147483647 : console.error("THREE.WebGLMorphtargets: Unsupported morph attribute data type: ", n), s.divideScalar(t); +function m_(s1, e) { + return Math.abs(e[1]) - Math.abs(s1[1]); } -function rg(s, e, t) { - let n = {}, i = new Float32Array(8), r = new WeakMap, o = new M, a = []; - for(let c = 0; c < 8; c++)a[c] = [ - c, +function g_(s1, e, t) { + let n = {}, i = new Float32Array(8), r = new WeakMap, a = new je, o = []; + for(let l = 0; l < 8; l++)o[l] = [ + l, 0 ]; - function l(c, h, u, d) { - let f = c.morphTargetInfluences; + function c(l, h, u) { + let d = l.morphTargetInfluences; if (e.isWebGL2 === !0) { - let m = h.morphAttributes.position.length, x = r.get(h); - if (x === void 0 || x.count !== m) { - x !== void 0 && x.texture.dispose(); - let p = h.morphAttributes.normal !== void 0, _ = h.morphAttributes.position, y = h.morphAttributes.normal || [], b = h.attributes.position.count, A = p === !0 ? 2 : 1, L = b * A, I = 1; - L > e.maxTextureSize && (I = Math.ceil(L / e.maxTextureSize), L = e.maxTextureSize); - let k = new Float32Array(L * I * 4 * m), B = new Qs(k, L, I, m); - B.format = ct, B.type = nn, B.needsUpdate = !0; - let P = A * 4; - for(let w = 0; w < m; w++){ - let E = _[w], D = y[w], U = L * I * 4 * w; - for(let F = 0; F < E.count; F++){ - o.fromBufferAttribute(E, F), E.normalized === !0 && Nl(o, E); - let O = F * P; - k[U + O + 0] = o.x, k[U + O + 1] = o.y, k[U + O + 2] = o.z, k[U + O + 3] = 0, p === !0 && (o.fromBufferAttribute(D, F), D.normalized === !0 && Nl(o, D), k[U + O + 4] = o.x, k[U + O + 5] = o.y, k[U + O + 6] = o.z, k[U + O + 7] = 0); + let f = h.morphAttributes.position || h.morphAttributes.normal || h.morphAttributes.color, m = f !== void 0 ? f.length : 0, _ = r.get(h); + if (_ === void 0 || _.count !== m) { + let U = function() { + Y.dispose(), r.delete(h), h.removeEventListener("dispose", U); + }; + _ !== void 0 && _.texture.dispose(); + let v = h.morphAttributes.position !== void 0, x = h.morphAttributes.normal !== void 0, y = h.morphAttributes.color !== void 0, b = h.morphAttributes.position || [], w = h.morphAttributes.normal || [], R = h.morphAttributes.color || [], I = 0; + v === !0 && (I = 1), x === !0 && (I = 2), y === !0 && (I = 3); + let M = h.attributes.position.count * I, T = 1; + M > e.maxTextureSize && (T = Math.ceil(M / e.maxTextureSize), M = e.maxTextureSize); + let O = new Float32Array(M * T * 4 * m), Y = new As(O, M, T, m); + Y.type = xn, Y.needsUpdate = !0; + let $ = I * 4; + for(let z = 0; z < m; z++){ + let q = b[z], H = w[z], ne = R[z], W = M * T * 4 * z; + for(let K = 0; K < q.count; K++){ + let D = K * $; + v === !0 && (a.fromBufferAttribute(q, K), O[W + D + 0] = a.x, O[W + D + 1] = a.y, O[W + D + 2] = a.z, O[W + D + 3] = 0), x === !0 && (a.fromBufferAttribute(H, K), O[W + D + 4] = a.x, O[W + D + 5] = a.y, O[W + D + 6] = a.z, O[W + D + 7] = 0), y === !0 && (a.fromBufferAttribute(ne, K), O[W + D + 8] = a.x, O[W + D + 9] = a.y, O[W + D + 10] = a.z, O[W + D + 11] = ne.itemSize === 4 ? a.w : 1); } } - x = { + _ = { count: m, - texture: B, - size: new X(L, I) - }, r.set(h, x); - } - let v = 0; - for(let p = 0; p < f.length; p++)v += f[p]; - let g = h.morphTargetsRelative ? 1 : 1 - v; - d.getUniforms().setValue(s, "morphTargetBaseInfluence", g), d.getUniforms().setValue(s, "morphTargetInfluences", f), d.getUniforms().setValue(s, "morphTargetsTexture", x.texture, t), d.getUniforms().setValue(s, "morphTargetsTextureSize", x.size); + texture: Y, + size: new Z(M, T) + }, r.set(h, _), h.addEventListener("dispose", U); + } + let g = 0; + for(let v = 0; v < d.length; v++)g += d[v]; + let p = h.morphTargetsRelative ? 1 : 1 - g; + u.getUniforms().setValue(s1, "morphTargetBaseInfluence", p), u.getUniforms().setValue(s1, "morphTargetInfluences", d), u.getUniforms().setValue(s1, "morphTargetsTexture", _.texture, t), u.getUniforms().setValue(s1, "morphTargetsTextureSize", _.size); } else { - let m = f === void 0 ? 0 : f.length, x = n[h.id]; - if (x === void 0 || x.length !== m) { - x = []; - for(let y = 0; y < m; y++)x[y] = [ - y, + let f = d === void 0 ? 0 : d.length, m = n[h.id]; + if (m === void 0 || m.length !== f) { + m = []; + for(let x = 0; x < f; x++)m[x] = [ + x, 0 ]; - n[h.id] = x; + n[h.id] = m; } - for(let y = 0; y < m; y++){ - let b = x[y]; - b[0] = y, b[1] = f[y]; + for(let x = 0; x < f; x++){ + let y = m[x]; + y[0] = x, y[1] = d[x]; } - x.sort(ig); - for(let y = 0; y < 8; y++)y < m && x[y][1] ? (a[y][0] = x[y][0], a[y][1] = x[y][1]) : (a[y][0] = Number.MAX_SAFE_INTEGER, a[y][1] = 0); - a.sort(ng); - let v = h.morphAttributes.position, g = h.morphAttributes.normal, p = 0; - for(let y = 0; y < 8; y++){ - let b = a[y], A = b[0], L = b[1]; - A !== Number.MAX_SAFE_INTEGER && L ? (v && h.getAttribute("morphTarget" + y) !== v[A] && h.setAttribute("morphTarget" + y, v[A]), g && h.getAttribute("morphNormal" + y) !== g[A] && h.setAttribute("morphNormal" + y, g[A]), i[y] = L, p += L) : (v && h.hasAttribute("morphTarget" + y) === !0 && h.deleteAttribute("morphTarget" + y), g && h.hasAttribute("morphNormal" + y) === !0 && h.deleteAttribute("morphNormal" + y), i[y] = 0); + m.sort(m_); + for(let x = 0; x < 8; x++)x < f && m[x][1] ? (o[x][0] = m[x][0], o[x][1] = m[x][1]) : (o[x][0] = Number.MAX_SAFE_INTEGER, o[x][1] = 0); + o.sort(p_); + let _ = h.morphAttributes.position, g = h.morphAttributes.normal, p = 0; + for(let x = 0; x < 8; x++){ + let y = o[x], b = y[0], w = y[1]; + b !== Number.MAX_SAFE_INTEGER && w ? (_ && h.getAttribute("morphTarget" + x) !== _[b] && h.setAttribute("morphTarget" + x, _[b]), g && h.getAttribute("morphNormal" + x) !== g[b] && h.setAttribute("morphNormal" + x, g[b]), i[x] = w, p += w) : (_ && h.hasAttribute("morphTarget" + x) === !0 && h.deleteAttribute("morphTarget" + x), g && h.hasAttribute("morphNormal" + x) === !0 && h.deleteAttribute("morphNormal" + x), i[x] = 0); } - let _ = h.morphTargetsRelative ? 1 : 1 - p; - d.getUniforms().setValue(s, "morphTargetBaseInfluence", _), d.getUniforms().setValue(s, "morphTargetInfluences", i); + let v = h.morphTargetsRelative ? 1 : 1 - p; + u.getUniforms().setValue(s1, "morphTargetBaseInfluence", v), u.getUniforms().setValue(s1, "morphTargetInfluences", i); } } return { - update: l + update: c }; } -function sg(s, e, t, n) { +function __(s1, e, t, n) { let i = new WeakMap; - function r(l) { - let c = n.render.frame, h = l.geometry, u = e.get(l, h); - return i.get(u) !== c && (e.update(u), i.set(u, c)), l.isInstancedMesh && (l.hasEventListener("dispose", a) === !1 && l.addEventListener("dispose", a), t.update(l.instanceMatrix, 34962), l.instanceColor !== null && t.update(l.instanceColor, 34962)), u; + function r(c) { + let l = n.render.frame, h = c.geometry, u = e.get(c, h); + if (i.get(u) !== l && (e.update(u), i.set(u, l)), c.isInstancedMesh && (c.hasEventListener("dispose", o) === !1 && c.addEventListener("dispose", o), i.get(c) !== l && (t.update(c.instanceMatrix, s1.ARRAY_BUFFER), c.instanceColor !== null && t.update(c.instanceColor, s1.ARRAY_BUFFER), i.set(c, l))), c.isSkinnedMesh) { + let d = c.skeleton; + i.get(d) !== l && (d.update(), i.set(d, l)); + } + return u; } - function o() { + function a() { i = new WeakMap; } - function a(l) { - let c = l.target; - c.removeEventListener("dispose", a), t.remove(c.instanceMatrix), c.instanceColor !== null && t.remove(c.instanceColor); + function o(c) { + let l = c.target; + l.removeEventListener("dispose", o), t.remove(l.instanceMatrix), l.instanceColor !== null && t.remove(l.instanceColor); } return { update: r, - dispose: o + dispose: a }; } -var ma = class extends ot { - constructor(e = null, t = 1, n = 1, i = 1){ - super(null); - this.image = { - data: e, - width: t, - height: n, - depth: i - }, this.magFilter = rt, this.minFilter = rt, this.wrapR = vt, this.generateMipmaps = !1, this.flipY = !1, this.unpackAlignment = 1; - } -}; -ma.prototype.isDataTexture3D = !0; -var lh = new ot, ch = new Qs, hh = new ma, uh = new ki, Bl = [], zl = [], Ul = new Float32Array(16), Ol = new Float32Array(9), Hl = new Float32Array(4); -function Vi(s, e, t) { - let n = s[0]; - if (n <= 0 || n > 0) return s; - let i = e * t, r = Bl[i]; - if (r === void 0 && (r = new Float32Array(i), Bl[i] = r), e !== 0) { +var Td = new St, wd = new As, Ad = new qr, Rd = new Ki, gh = [], _h = [], xh = new Float32Array(16), vh = new Float32Array(9), yh = new Float32Array(4); +function as(s1, e, t) { + let n = s1[0]; + if (n <= 0 || n > 0) return s1; + let i = e * t, r = gh[i]; + if (r === void 0 && (r = new Float32Array(i), gh[i] = r), e !== 0) { n.toArray(r, 0); - for(let o = 1, a = 0; o !== e; ++o)a += t, s[o].toArray(r, a); + for(let a = 1, o = 0; a !== e; ++a)o += t, s1[a].toArray(r, o); } return r; } -function Mt(s, e) { - if (s.length !== e.length) return !1; - for(let t = 0, n = s.length; t < n; t++)if (s[t] !== e[t]) return !1; +function gt(s1, e) { + if (s1.length !== e.length) return !1; + for(let t = 0, n = s1.length; t < n; t++)if (s1[t] !== e[t]) return !1; return !0; } -function _t(s, e) { - for(let t = 0, n = e.length; t < n; t++)s[t] = e[t]; +function _t(s1, e) { + for(let t = 0, n = e.length; t < n; t++)s1[t] = e[t]; } -function Ks(s, e) { - let t = zl[e]; - t === void 0 && (t = new Int32Array(e), zl[e] = t); - for(let n = 0; n !== e; ++n)t[n] = s.allocateTextureUnit(); +function ya(s1, e) { + let t = _h[e]; + t === void 0 && (t = new Int32Array(e), _h[e] = t); + for(let n = 0; n !== e; ++n)t[n] = s1.allocateTextureUnit(); return t; } -function og(s, e) { +function x_(s1, e) { let t = this.cache; - t[0] !== e && (s.uniform1f(this.addr, e), t[0] = e); + t[0] !== e && (s1.uniform1f(this.addr, e), t[0] = e); } -function ag(s, e) { +function v_(s1, e) { let t = this.cache; - if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y) && (s.uniform2f(this.addr, e.x, e.y), t[0] = e.x, t[1] = e.y); + if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y) && (s1.uniform2f(this.addr, e.x, e.y), t[0] = e.x, t[1] = e.y); else { - if (Mt(t, e)) return; - s.uniform2fv(this.addr, e), _t(t, e); + if (gt(t, e)) return; + s1.uniform2fv(this.addr, e), _t(t, e); } } -function lg(s, e) { +function y_(s1, e) { let t = this.cache; - if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y || t[2] !== e.z) && (s.uniform3f(this.addr, e.x, e.y, e.z), t[0] = e.x, t[1] = e.y, t[2] = e.z); - else if (e.r !== void 0) (t[0] !== e.r || t[1] !== e.g || t[2] !== e.b) && (s.uniform3f(this.addr, e.r, e.g, e.b), t[0] = e.r, t[1] = e.g, t[2] = e.b); + if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y || t[2] !== e.z) && (s1.uniform3f(this.addr, e.x, e.y, e.z), t[0] = e.x, t[1] = e.y, t[2] = e.z); + else if (e.r !== void 0) (t[0] !== e.r || t[1] !== e.g || t[2] !== e.b) && (s1.uniform3f(this.addr, e.r, e.g, e.b), t[0] = e.r, t[1] = e.g, t[2] = e.b); else { - if (Mt(t, e)) return; - s.uniform3fv(this.addr, e), _t(t, e); + if (gt(t, e)) return; + s1.uniform3fv(this.addr, e), _t(t, e); } } -function cg(s, e) { +function M_(s1, e) { let t = this.cache; - if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y || t[2] !== e.z || t[3] !== e.w) && (s.uniform4f(this.addr, e.x, e.y, e.z, e.w), t[0] = e.x, t[1] = e.y, t[2] = e.z, t[3] = e.w); + if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y || t[2] !== e.z || t[3] !== e.w) && (s1.uniform4f(this.addr, e.x, e.y, e.z, e.w), t[0] = e.x, t[1] = e.y, t[2] = e.z, t[3] = e.w); else { - if (Mt(t, e)) return; - s.uniform4fv(this.addr, e), _t(t, e); + if (gt(t, e)) return; + s1.uniform4fv(this.addr, e), _t(t, e); } } -function hg(s, e) { +function S_(s1, e) { let t = this.cache, n = e.elements; if (n === void 0) { - if (Mt(t, e)) return; - s.uniformMatrix2fv(this.addr, !1, e), _t(t, e); + if (gt(t, e)) return; + s1.uniformMatrix2fv(this.addr, !1, e), _t(t, e); } else { - if (Mt(t, n)) return; - Hl.set(n), s.uniformMatrix2fv(this.addr, !1, Hl), _t(t, n); + if (gt(t, n)) return; + yh.set(n), s1.uniformMatrix2fv(this.addr, !1, yh), _t(t, n); } } -function ug(s, e) { +function b_(s1, e) { let t = this.cache, n = e.elements; if (n === void 0) { - if (Mt(t, e)) return; - s.uniformMatrix3fv(this.addr, !1, e), _t(t, e); + if (gt(t, e)) return; + s1.uniformMatrix3fv(this.addr, !1, e), _t(t, e); } else { - if (Mt(t, n)) return; - Ol.set(n), s.uniformMatrix3fv(this.addr, !1, Ol), _t(t, n); + if (gt(t, n)) return; + vh.set(n), s1.uniformMatrix3fv(this.addr, !1, vh), _t(t, n); } } -function dg(s, e) { +function E_(s1, e) { let t = this.cache, n = e.elements; if (n === void 0) { - if (Mt(t, e)) return; - s.uniformMatrix4fv(this.addr, !1, e), _t(t, e); + if (gt(t, e)) return; + s1.uniformMatrix4fv(this.addr, !1, e), _t(t, e); } else { - if (Mt(t, n)) return; - Ul.set(n), s.uniformMatrix4fv(this.addr, !1, Ul), _t(t, n); + if (gt(t, n)) return; + xh.set(n), s1.uniformMatrix4fv(this.addr, !1, xh), _t(t, n); } } -function fg(s, e) { +function T_(s1, e) { let t = this.cache; - t[0] !== e && (s.uniform1i(this.addr, e), t[0] = e); + t[0] !== e && (s1.uniform1i(this.addr, e), t[0] = e); } -function pg(s, e) { +function w_(s1, e) { let t = this.cache; - Mt(t, e) || (s.uniform2iv(this.addr, e), _t(t, e)); + if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y) && (s1.uniform2i(this.addr, e.x, e.y), t[0] = e.x, t[1] = e.y); + else { + if (gt(t, e)) return; + s1.uniform2iv(this.addr, e), _t(t, e); + } } -function mg(s, e) { +function A_(s1, e) { let t = this.cache; - Mt(t, e) || (s.uniform3iv(this.addr, e), _t(t, e)); + if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y || t[2] !== e.z) && (s1.uniform3i(this.addr, e.x, e.y, e.z), t[0] = e.x, t[1] = e.y, t[2] = e.z); + else { + if (gt(t, e)) return; + s1.uniform3iv(this.addr, e), _t(t, e); + } } -function gg(s, e) { +function R_(s1, e) { let t = this.cache; - Mt(t, e) || (s.uniform4iv(this.addr, e), _t(t, e)); + if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y || t[2] !== e.z || t[3] !== e.w) && (s1.uniform4i(this.addr, e.x, e.y, e.z, e.w), t[0] = e.x, t[1] = e.y, t[2] = e.z, t[3] = e.w); + else { + if (gt(t, e)) return; + s1.uniform4iv(this.addr, e), _t(t, e); + } } -function xg(s, e) { +function C_(s1, e) { let t = this.cache; - t[0] !== e && (s.uniform1ui(this.addr, e), t[0] = e); + t[0] !== e && (s1.uniform1ui(this.addr, e), t[0] = e); } -function yg(s, e) { +function P_(s1, e) { let t = this.cache; - Mt(t, e) || (s.uniform2uiv(this.addr, e), _t(t, e)); + if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y) && (s1.uniform2ui(this.addr, e.x, e.y), t[0] = e.x, t[1] = e.y); + else { + if (gt(t, e)) return; + s1.uniform2uiv(this.addr, e), _t(t, e); + } } -function vg(s, e) { +function L_(s1, e) { let t = this.cache; - Mt(t, e) || (s.uniform3uiv(this.addr, e), _t(t, e)); + if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y || t[2] !== e.z) && (s1.uniform3ui(this.addr, e.x, e.y, e.z), t[0] = e.x, t[1] = e.y, t[2] = e.z); + else { + if (gt(t, e)) return; + s1.uniform3uiv(this.addr, e), _t(t, e); + } } -function _g(s, e) { +function I_(s1, e) { let t = this.cache; - Mt(t, e) || (s.uniform4uiv(this.addr, e), _t(t, e)); + if (e.x !== void 0) (t[0] !== e.x || t[1] !== e.y || t[2] !== e.z || t[3] !== e.w) && (s1.uniform4ui(this.addr, e.x, e.y, e.z, e.w), t[0] = e.x, t[1] = e.y, t[2] = e.z, t[3] = e.w); + else { + if (gt(t, e)) return; + s1.uniform4uiv(this.addr, e), _t(t, e); + } } -function Mg(s, e, t) { +function U_(s1, e, t) { let n = this.cache, i = t.allocateTextureUnit(); - n[0] !== i && (s.uniform1i(this.addr, i), n[0] = i), t.safeSetTexture2D(e || lh, i); + n[0] !== i && (s1.uniform1i(this.addr, i), n[0] = i), t.setTexture2D(e || Td, i); } -function bg(s, e, t) { +function D_(s1, e, t) { let n = this.cache, i = t.allocateTextureUnit(); - n[0] !== i && (s.uniform1i(this.addr, i), n[0] = i), t.setTexture3D(e || hh, i); + n[0] !== i && (s1.uniform1i(this.addr, i), n[0] = i), t.setTexture3D(e || Ad, i); } -function wg(s, e, t) { +function N_(s1, e, t) { let n = this.cache, i = t.allocateTextureUnit(); - n[0] !== i && (s.uniform1i(this.addr, i), n[0] = i), t.safeSetTextureCube(e || uh, i); + n[0] !== i && (s1.uniform1i(this.addr, i), n[0] = i), t.setTextureCube(e || Rd, i); } -function Sg(s, e, t) { +function O_(s1, e, t) { let n = this.cache, i = t.allocateTextureUnit(); - n[0] !== i && (s.uniform1i(this.addr, i), n[0] = i), t.setTexture2DArray(e || ch, i); + n[0] !== i && (s1.uniform1i(this.addr, i), n[0] = i), t.setTexture2DArray(e || wd, i); } -function Tg(s) { - switch(s){ +function F_(s1) { + switch(s1){ case 5126: - return og; + return x_; case 35664: - return ag; + return v_; case 35665: - return lg; + return y_; case 35666: - return cg; + return M_; case 35674: - return hg; + return S_; case 35675: - return ug; + return b_; case 35676: - return dg; + return E_; case 5124: case 35670: - return fg; + return T_; case 35667: case 35671: - return pg; + return w_; case 35668: case 35672: - return mg; + return A_; case 35669: case 35673: - return gg; + return R_; case 5125: - return xg; + return C_; case 36294: - return yg; + return P_; case 36295: - return vg; + return L_; case 36296: - return _g; + return I_; case 35678: case 36198: case 36298: case 36306: case 35682: - return Mg; + return U_; case 35679: case 36299: case 36307: - return bg; + return D_; case 35680: case 36300: case 36308: case 36293: - return wg; + return N_; case 36289: case 36303: case 36311: case 36292: - return Sg; + return O_; } } -function Eg(s, e) { - s.uniform1fv(this.addr, e); +function B_(s1, e) { + s1.uniform1fv(this.addr, e); } -function Ag(s, e) { - let t = Vi(e, this.size, 2); - s.uniform2fv(this.addr, t); +function z_(s1, e) { + let t = as(e, this.size, 2); + s1.uniform2fv(this.addr, t); } -function Cg(s, e) { - let t = Vi(e, this.size, 3); - s.uniform3fv(this.addr, t); +function V_(s1, e) { + let t = as(e, this.size, 3); + s1.uniform3fv(this.addr, t); } -function Lg(s, e) { - let t = Vi(e, this.size, 4); - s.uniform4fv(this.addr, t); +function k_(s1, e) { + let t = as(e, this.size, 4); + s1.uniform4fv(this.addr, t); } -function Rg(s, e) { - let t = Vi(e, this.size, 4); - s.uniformMatrix2fv(this.addr, !1, t); +function H_(s1, e) { + let t = as(e, this.size, 4); + s1.uniformMatrix2fv(this.addr, !1, t); } -function Pg(s, e) { - let t = Vi(e, this.size, 9); - s.uniformMatrix3fv(this.addr, !1, t); +function G_(s1, e) { + let t = as(e, this.size, 9); + s1.uniformMatrix3fv(this.addr, !1, t); } -function Ig(s, e) { - let t = Vi(e, this.size, 16); - s.uniformMatrix4fv(this.addr, !1, t); +function W_(s1, e) { + let t = as(e, this.size, 16); + s1.uniformMatrix4fv(this.addr, !1, t); } -function Dg(s, e) { - s.uniform1iv(this.addr, e); +function X_(s1, e) { + s1.uniform1iv(this.addr, e); } -function Fg(s, e) { - s.uniform2iv(this.addr, e); +function q_(s1, e) { + s1.uniform2iv(this.addr, e); } -function Ng(s, e) { - s.uniform3iv(this.addr, e); +function Y_(s1, e) { + s1.uniform3iv(this.addr, e); } -function Bg(s, e) { - s.uniform4iv(this.addr, e); +function Z_(s1, e) { + s1.uniform4iv(this.addr, e); } -function zg(s, e) { - s.uniform1uiv(this.addr, e); +function J_(s1, e) { + s1.uniform1uiv(this.addr, e); } -function Ug(s, e) { - s.uniform2uiv(this.addr, e); +function $_(s1, e) { + s1.uniform2uiv(this.addr, e); } -function Og(s, e) { - s.uniform3uiv(this.addr, e); +function K_(s1, e) { + s1.uniform3uiv(this.addr, e); } -function Hg(s, e) { - s.uniform4uiv(this.addr, e); +function Q_(s1, e) { + s1.uniform4uiv(this.addr, e); } -function kg(s, e, t) { - let n = e.length, i = Ks(t, n); - s.uniform1iv(this.addr, i); - for(let r = 0; r !== n; ++r)t.safeSetTexture2D(e[r] || lh, i[r]); +function j_(s1, e, t) { + let n = this.cache, i = e.length, r = ya(t, i); + gt(n, r) || (s1.uniform1iv(this.addr, r), _t(n, r)); + for(let a = 0; a !== i; ++a)t.setTexture2D(e[a] || Td, r[a]); } -function Gg(s, e, t) { - let n = e.length, i = Ks(t, n); - s.uniform1iv(this.addr, i); - for(let r = 0; r !== n; ++r)t.setTexture3D(e[r] || hh, i[r]); +function e0(s1, e, t) { + let n = this.cache, i = e.length, r = ya(t, i); + gt(n, r) || (s1.uniform1iv(this.addr, r), _t(n, r)); + for(let a = 0; a !== i; ++a)t.setTexture3D(e[a] || Ad, r[a]); } -function Vg(s, e, t) { - let n = e.length, i = Ks(t, n); - s.uniform1iv(this.addr, i); - for(let r = 0; r !== n; ++r)t.safeSetTextureCube(e[r] || uh, i[r]); +function t0(s1, e, t) { + let n = this.cache, i = e.length, r = ya(t, i); + gt(n, r) || (s1.uniform1iv(this.addr, r), _t(n, r)); + for(let a = 0; a !== i; ++a)t.setTextureCube(e[a] || Rd, r[a]); } -function Wg(s, e, t) { - let n = e.length, i = Ks(t, n); - s.uniform1iv(this.addr, i); - for(let r = 0; r !== n; ++r)t.setTexture2DArray(e[r] || ch, i[r]); +function n0(s1, e, t) { + let n = this.cache, i = e.length, r = ya(t, i); + gt(n, r) || (s1.uniform1iv(this.addr, r), _t(n, r)); + for(let a = 0; a !== i; ++a)t.setTexture2DArray(e[a] || wd, r[a]); } -function qg(s) { - switch(s){ +function i0(s1) { + switch(s1){ case 5126: - return Eg; + return B_; case 35664: - return Ag; + return z_; case 35665: - return Cg; + return V_; case 35666: - return Lg; + return k_; case 35674: - return Rg; + return H_; case 35675: - return Pg; + return G_; case 35676: - return Ig; + return W_; case 5124: case 35670: - return Dg; + return X_; case 35667: case 35671: - return Fg; + return q_; case 35668: case 35672: - return Ng; + return Y_; case 35669: case 35673: - return Bg; + return Z_; case 5125: - return zg; + return J_; case 36294: - return Ug; + return $_; case 36295: - return Og; + return K_; case 36296: - return Hg; + return Q_; case 35678: case 36198: case 36298: case 36306: case 35682: - return kg; + return j_; case 35679: case 36299: case 36307: - return Gg; + return e0; case 35680: case 36300: case 36308: case 36293: - return Vg; + return t0; case 36289: case 36303: case 36311: case 36292: - return Wg; + return n0; } } -function Xg(s, e, t) { - this.id = s, this.addr = t, this.cache = [], this.setValue = Tg(e.type); -} -function dh(s, e, t) { - this.id = s, this.addr = t, this.cache = [], this.size = e.size, this.setValue = qg(e.type); -} -dh.prototype.updateCache = function(s) { - let e = this.cache; - s instanceof Float32Array && e.length !== s.length && (this.cache = new Float32Array(s.length)), _t(e, s); -}; -function fh(s) { - this.id = s, this.seq = [], this.map = {}; -} -fh.prototype.setValue = function(s, e, t) { - let n = this.seq; - for(let i = 0, r = n.length; i !== r; ++i){ - let o = n[i]; - o.setValue(s, e[o.id], t); +var vo = class { + constructor(e, t, n){ + this.id = e, this.addr = n, this.cache = [], this.setValue = F_(t.type); } -}; -var Wo = /(\w+)(\])?(\[|\.)?/g; -function kl(s, e) { - s.seq.push(e), s.map[e.id] = e; -} -function Jg(s, e, t) { - let n = s.name, i = n.length; - for(Wo.lastIndex = 0;;){ - let r = Wo.exec(n), o = Wo.lastIndex, a = r[1], l = r[2] === "]", c = r[3]; - if (l && (a = a | 0), c === void 0 || c === "[" && o + 2 === i) { - kl(t, c === void 0 ? new Xg(a, s, e) : new dh(a, s, e)); +}, yo = class { + constructor(e, t, n){ + this.id = e, this.addr = n, this.cache = [], this.size = t.size, this.setValue = i0(t.type); + } +}, Mo = class { + constructor(e){ + this.id = e, this.seq = [], this.map = {}; + } + setValue(e, t, n) { + let i = this.seq; + for(let r = 0, a = i.length; r !== a; ++r){ + let o = i[r]; + o.setValue(e, t[o.id], n); + } + } +}, Qa = /(\w+)(\])?(\[|\.)?/g; +function Mh(s1, e) { + s1.seq.push(e), s1.map[e.id] = e; +} +function s0(s1, e, t) { + let n = s1.name, i = n.length; + for(Qa.lastIndex = 0;;){ + let r = Qa.exec(n), a = Qa.lastIndex, o = r[1], c = r[2] === "]", l = r[3]; + if (c && (o = o | 0), l === void 0 || l === "[" && a + 2 === i) { + Mh(t, l === void 0 ? new vo(o, s1, e) : new yo(o, s1, e)); break; } else { - let u = t.map[a]; - u === void 0 && (u = new fh(a), kl(t, u)), t = u; + let u = t.map[o]; + u === void 0 && (u = new Mo(o), Mh(t, u)), t = u; } } } -function bn(s, e) { - this.seq = [], this.map = {}; - let t = s.getProgramParameter(e, 35718); - for(let n = 0; n < t; ++n){ - let i = s.getActiveUniform(e, n), r = s.getUniformLocation(e, i.name); - Jg(i, r, this); +var qi = class { + constructor(e, t){ + this.seq = [], this.map = {}; + let n = e.getProgramParameter(t, e.ACTIVE_UNIFORMS); + for(let i = 0; i < n; ++i){ + let r = e.getActiveUniform(t, i), a = e.getUniformLocation(t, r.name); + s0(r, a, this); + } } -} -bn.prototype.setValue = function(s, e, t, n) { - let i = this.map[e]; - i !== void 0 && i.setValue(s, t, n); -}; -bn.prototype.setOptional = function(s, e, t) { - let n = e[t]; - n !== void 0 && this.setValue(s, t, n); -}; -bn.upload = function(s, e, t, n) { - for(let i = 0, r = e.length; i !== r; ++i){ - let o = e[i], a = t[o.id]; - a.needsUpdate !== !1 && o.setValue(s, a.value, n); + setValue(e, t, n, i) { + let r = this.map[t]; + r !== void 0 && r.setValue(e, n, i); } -}; -bn.seqWithValue = function(s, e) { - let t = []; - for(let n = 0, i = s.length; n !== i; ++n){ - let r = s[n]; - r.id in e && t.push(r); + setOptional(e, t, n) { + let i = t[n]; + i !== void 0 && this.setValue(e, n, i); + } + static upload(e, t, n, i) { + for(let r = 0, a = t.length; r !== a; ++r){ + let o = t[r], c = n[o.id]; + c.needsUpdate !== !1 && o.setValue(e, c.value, i); + } + } + static seqWithValue(e, t) { + let n = []; + for(let i = 0, r = e.length; i !== r; ++i){ + let a = e[i]; + a.id in t && n.push(a); + } + return n; } - return t; }; -function Gl(s, e, t) { - let n = s.createShader(e); - return s.shaderSource(n, t), s.compileShader(n), n; +function Sh(s1, e, t) { + let n = s1.createShader(e); + return s1.shaderSource(n, t), s1.compileShader(n), n; } -var Yg = 0; -function Zg(s) { - let e = s.split(` -`); - for(let t = 0; t < e.length; t++)e[t] = t + 1 + ": " + e[t]; - return e.join(` +var r0 = 0; +function a0(s1, e) { + let t = s1.split(` +`), n = [], i = Math.max(e - 6, 0), r = Math.min(e + 6, t.length); + for(let a = i; a < r; a++){ + let o = a + 1; + n.push(`${o === e ? ">" : " "} ${o}: ${t[a]}`); + } + return n.join(` `); } -function ph(s) { - switch(s){ - case Nt: +function o0(s1) { + let e = Qe.getPrimaries(Qe.workingColorSpace), t = Qe.getPrimaries(s1), n; + switch(e === t ? n = "" : e === kr && t === Vr ? n = "LinearDisplayP3ToLinearSRGB" : e === Vr && t === kr && (n = "LinearSRGBToLinearDisplayP3"), s1){ + case Mn: + case va: return [ - "Linear", - "( value )" + n, + "LinearTransferOETF" ]; - case Oi: + case vt: + case qc: return [ - "sRGB", - "( value )" + n, + "sRGBTransferOETF" ]; default: - return console.warn("THREE.WebGLProgram: Unsupported encoding:", s), [ - "Linear", - "( value )" + return console.warn("THREE.WebGLProgram: Unsupported color space:", s1), [ + n, + "LinearTransferOETF" ]; } } -function Vl(s, e, t) { - let n = s.getShaderParameter(e, 35713), i = s.getShaderInfoLog(e).trim(); - return n && i === "" ? "" : t.toUpperCase() + ` +function bh(s1, e, t) { + let n = s1.getShaderParameter(e, s1.COMPILE_STATUS), i = s1.getShaderInfoLog(e).trim(); + if (n && i === "") return ""; + let r = /ERROR: 0:(\d+)/.exec(i); + if (r) { + let a = parseInt(r[1]); + return t.toUpperCase() + ` ` + i + ` -` + Zg(s.getShaderSource(e)); -} -function Dn(s, e) { - let t = ph(e); - return "vec4 " + s + "( vec4 value ) { return " + t[0] + "ToLinear" + t[1] + "; }"; +` + a0(s1.getShaderSource(e), a); + } else return i; } -function $g(s, e) { - let t = ph(e); - return "vec4 " + s + "( vec4 value ) { return LinearTo" + t[0] + t[1] + "; }"; +function c0(s1, e) { + let t = o0(e); + return `vec4 ${s1}( vec4 value ) { return ${t[0]}( ${t[1]}( value ) ); }`; } -function jg(s, e) { +function l0(s1, e) { let t; switch(e){ - case Nu: + case df: t = "Linear"; break; - case Bu: + case ff: t = "Reinhard"; break; - case zu: + case pf: t = "OptimizedCineon"; break; - case Uu: + case mf: t = "ACESFilmic"; break; - case Ou: + case gf: t = "Custom"; break; default: console.warn("THREE.WebGLProgram: Unsupported toneMapping:", e), t = "Linear"; } - return "vec3 " + s + "( vec3 color ) { return " + t + "ToneMapping( color ); }"; + return "vec3 " + s1 + "( vec3 color ) { return " + t + "ToneMapping( color ); }"; } -function Qg(s) { +function h0(s1) { return [ - s.extensionDerivatives || s.envMapCubeUV || s.bumpMap || s.tangentSpaceNormalMap || s.clearcoatNormalMap || s.flatShading || s.shaderID === "physical" ? "#extension GL_OES_standard_derivatives : enable" : "", - (s.extensionFragDepth || s.logarithmicDepthBuffer) && s.rendererExtensionFragDepth ? "#extension GL_EXT_frag_depth : enable" : "", - s.extensionDrawBuffers && s.rendererExtensionDrawBuffers ? "#extension GL_EXT_draw_buffers : require" : "", - (s.extensionShaderTextureLOD || s.envMap || s.transmission) && s.rendererExtensionShaderTextureLod ? "#extension GL_EXT_shader_texture_lod : enable" : "" - ].filter(rr).join(` + s1.extensionDerivatives || s1.envMapCubeUVHeight || s1.bumpMap || s1.normalMapTangentSpace || s1.clearcoatNormalMap || s1.flatShading || s1.shaderID === "physical" ? "#extension GL_OES_standard_derivatives : enable" : "", + (s1.extensionFragDepth || s1.logarithmicDepthBuffer) && s1.rendererExtensionFragDepth ? "#extension GL_EXT_frag_depth : enable" : "", + s1.extensionDrawBuffers && s1.rendererExtensionDrawBuffers ? "#extension GL_EXT_draw_buffers : require" : "", + (s1.extensionShaderTextureLOD || s1.envMap || s1.transmission) && s1.rendererExtensionShaderTextureLod ? "#extension GL_EXT_shader_texture_lod : enable" : "" + ].filter(vs).join(` `); } -function Kg(s) { +function u0(s1) { let e = []; - for(let t in s){ - let n = s[t]; + for(let t in s1){ + let n = s1[t]; n !== !1 && e.push("#define " + t + " " + n); } return e.join(` `); } -function ex(s, e) { - let t = {}, n = s.getProgramParameter(e, 35721); +function d0(s1, e) { + let t = {}, n = s1.getProgramParameter(e, s1.ACTIVE_ATTRIBUTES); for(let i = 0; i < n; i++){ - let r = s.getActiveAttrib(e, i), o = r.name, a = 1; - r.type === 35674 && (a = 2), r.type === 35675 && (a = 3), r.type === 35676 && (a = 4), t[o] = { + let r = s1.getActiveAttrib(e, i), a = r.name, o = 1; + r.type === s1.FLOAT_MAT2 && (o = 2), r.type === s1.FLOAT_MAT3 && (o = 3), r.type === s1.FLOAT_MAT4 && (o = 4), t[a] = { type: r.type, - location: s.getAttribLocation(e, o), - locationSize: a + location: s1.getAttribLocation(e, a), + locationSize: o }; } return t; } -function rr(s) { - return s !== ""; +function vs(s1) { + return s1 !== ""; } -function Wl(s, e) { - return s.replace(/NUM_DIR_LIGHTS/g, e.numDirLights).replace(/NUM_SPOT_LIGHTS/g, e.numSpotLights).replace(/NUM_RECT_AREA_LIGHTS/g, e.numRectAreaLights).replace(/NUM_POINT_LIGHTS/g, e.numPointLights).replace(/NUM_HEMI_LIGHTS/g, e.numHemiLights).replace(/NUM_DIR_LIGHT_SHADOWS/g, e.numDirLightShadows).replace(/NUM_SPOT_LIGHT_SHADOWS/g, e.numSpotLightShadows).replace(/NUM_POINT_LIGHT_SHADOWS/g, e.numPointLightShadows); +function Eh(s1, e) { + let t = e.numSpotLightShadows + e.numSpotLightMaps - e.numSpotLightShadowsWithMaps; + return s1.replace(/NUM_DIR_LIGHTS/g, e.numDirLights).replace(/NUM_SPOT_LIGHTS/g, e.numSpotLights).replace(/NUM_SPOT_LIGHT_MAPS/g, e.numSpotLightMaps).replace(/NUM_SPOT_LIGHT_COORDS/g, t).replace(/NUM_RECT_AREA_LIGHTS/g, e.numRectAreaLights).replace(/NUM_POINT_LIGHTS/g, e.numPointLights).replace(/NUM_HEMI_LIGHTS/g, e.numHemiLights).replace(/NUM_DIR_LIGHT_SHADOWS/g, e.numDirLightShadows).replace(/NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, e.numSpotLightShadowsWithMaps).replace(/NUM_SPOT_LIGHT_SHADOWS/g, e.numSpotLightShadows).replace(/NUM_POINT_LIGHT_SHADOWS/g, e.numPointLightShadows); } -function ql(s, e) { - return s.replace(/NUM_CLIPPING_PLANES/g, e.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g, e.numClippingPlanes - e.numClipIntersection); +function Th(s1, e) { + return s1.replace(/NUM_CLIPPING_PLANES/g, e.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g, e.numClippingPlanes - e.numClipIntersection); } -var tx = /^[ \t]*#include +<([\w\d./]+)>/gm; -function ra(s) { - return s.replace(tx, nx); +var f0 = /^[ \t]*#include +<([\w\d./]+)>/gm; +function So(s1) { + return s1.replace(f0, m0); } -function nx(s, e) { - let t = Fe[e]; - if (t === void 0) throw new Error("Can not resolve #include <" + e + ">"); - return ra(t); -} -var ix = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g, rx = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g; -function Xl(s) { - return s.replace(rx, mh).replace(ix, sx); +var p0 = new Map([ + [ + "encodings_fragment", + "colorspace_fragment" + ], + [ + "encodings_pars_fragment", + "colorspace_pars_fragment" + ], + [ + "output_fragment", + "opaque_fragment" + ] +]); +function m0(s1, e) { + let t = ke[e]; + if (t === void 0) { + let n = p0.get(e); + if (n !== void 0) t = ke[n], console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', e, n); + else throw new Error("Can not resolve #include <" + e + ">"); + } + return So(t); } -function sx(s, e, t, n) { - return console.warn("WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead."), mh(s, e, t, n); +var g0 = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g; +function wh(s1) { + return s1.replace(g0, _0); } -function mh(s, e, t, n) { +function _0(s1, e, t, n) { let i = ""; for(let r = parseInt(e); r < parseInt(t); r++)i += n.replace(/\[\s*i\s*\]/g, "[ " + r + " ]").replace(/UNROLLED_LOOP_INDEX/g, r); return i; } -function Jl(s) { - let e = "precision " + s.precision + ` float; -precision ` + s.precision + " int;"; - return s.precision === "highp" ? e += ` -#define HIGH_PRECISION` : s.precision === "mediump" ? e += ` -#define MEDIUM_PRECISION` : s.precision === "lowp" && (e += ` +function Ah(s1) { + let e = "precision " + s1.precision + ` float; +precision ` + s1.precision + " int;"; + return s1.precision === "highp" ? e += ` +#define HIGH_PRECISION` : s1.precision === "mediump" ? e += ` +#define MEDIUM_PRECISION` : s1.precision === "lowp" && (e += ` #define LOW_PRECISION`), e; } -function ox(s) { +function x0(s1) { let e = "SHADOWMAP_TYPE_BASIC"; - return s.shadowMapType === Hc ? e = "SHADOWMAP_TYPE_PCF" : s.shadowMapType === fu ? e = "SHADOWMAP_TYPE_PCF_SOFT" : s.shadowMapType === ir && (e = "SHADOWMAP_TYPE_VSM"), e; + return s1.shadowMapType === cd ? e = "SHADOWMAP_TYPE_PCF" : s1.shadowMapType === Gd ? e = "SHADOWMAP_TYPE_PCF_SOFT" : s1.shadowMapType === pn && (e = "SHADOWMAP_TYPE_VSM"), e; } -function ax(s) { +function v0(s1) { let e = "ENVMAP_TYPE_CUBE"; - if (s.envMap) switch(s.envMapMode){ - case Bi: - case zi: + if (s1.envMap) switch(s1.envMapMode){ + case zn: + case ci: e = "ENVMAP_TYPE_CUBE"; break; - case Pr: - case Ws: + case Vs: e = "ENVMAP_TYPE_CUBE_UV"; break; } return e; } -function lx(s) { +function y0(s1) { let e = "ENVMAP_MODE_REFLECTION"; - if (s.envMap) switch(s.envMapMode){ - case zi: - case Ws: + if (s1.envMap) switch(s1.envMapMode){ + case ci: e = "ENVMAP_MODE_REFRACTION"; break; } return e; } -function cx(s) { +function M0(s1) { let e = "ENVMAP_BLENDING_NONE"; - if (s.envMap) switch(s.combine){ - case Vs: + if (s1.envMap) switch(s1.combine){ + case xa: e = "ENVMAP_BLENDING_MULTIPLY"; break; - case Du: + case hf: e = "ENVMAP_BLENDING_MIX"; break; - case Fu: + case uf: e = "ENVMAP_BLENDING_ADD"; break; } return e; } -function hx(s, e, t, n) { - let i = s.getContext(), r = t.defines, o = t.vertexShader, a = t.fragmentShader, l = ox(t), c = ax(t), h = lx(t), u = cx(t), d = t.isWebGL2 ? "" : Qg(t), f = Kg(r), m = i.createProgram(), x, v, g = t.glslVersion ? "#version " + t.glslVersion + ` +function S0(s1) { + let e = s1.envMapCubeUVHeight; + if (e === null) return null; + let t = Math.log2(e) - 2, n = 1 / e; + return { + texelWidth: 1 / (3 * Math.max(Math.pow(2, t), 7 * 16)), + texelHeight: n, + maxMip: t + }; +} +function b0(s1, e, t, n) { + let i = s1.getContext(), r = t.defines, a = t.vertexShader, o = t.fragmentShader, c = x0(t), l = v0(t), h = y0(t), u = M0(t), d = S0(t), f = t.isWebGL2 ? "" : h0(t), m = u0(r), _ = i.createProgram(), g, p, v = t.glslVersion ? "#version " + t.glslVersion + ` ` : ""; - t.isRawShaderMaterial ? (x = [ - f - ].filter(rr).join(` -`), x.length > 0 && (x += ` -`), v = [ - d, - f - ].filter(rr).join(` -`), v.length > 0 && (v += ` -`)) : (x = [ - Jl(t), + t.isRawShaderMaterial ? (g = [ + "#define SHADER_TYPE " + t.shaderType, "#define SHADER_NAME " + t.shaderName, + m + ].filter(vs).join(` +`), g.length > 0 && (g += ` +`), p = [ f, + "#define SHADER_TYPE " + t.shaderType, + "#define SHADER_NAME " + t.shaderName, + m + ].filter(vs).join(` +`), p.length > 0 && (p += ` +`)) : (g = [ + Ah(t), + "#define SHADER_TYPE " + t.shaderType, + "#define SHADER_NAME " + t.shaderName, + m, t.instancing ? "#define USE_INSTANCING" : "", t.instancingColor ? "#define USE_INSTANCING_COLOR" : "", - t.supportsVertexTextures ? "#define VERTEX_TEXTURES" : "", - "#define MAX_BONES " + t.maxBones, t.useFog && t.fog ? "#define USE_FOG" : "", t.useFog && t.fogExp2 ? "#define FOG_EXP2" : "", t.map ? "#define USE_MAP" : "", @@ -9177,43 +10403,76 @@ function hx(s, e, t, n) { t.envMap ? "#define " + h : "", t.lightMap ? "#define USE_LIGHTMAP" : "", t.aoMap ? "#define USE_AOMAP" : "", - t.emissiveMap ? "#define USE_EMISSIVEMAP" : "", t.bumpMap ? "#define USE_BUMPMAP" : "", t.normalMap ? "#define USE_NORMALMAP" : "", - t.normalMap && t.objectSpaceNormalMap ? "#define OBJECTSPACE_NORMALMAP" : "", - t.normalMap && t.tangentSpaceNormalMap ? "#define TANGENTSPACE_NORMALMAP" : "", + t.normalMapObjectSpace ? "#define USE_NORMALMAP_OBJECTSPACE" : "", + t.normalMapTangentSpace ? "#define USE_NORMALMAP_TANGENTSPACE" : "", + t.displacementMap ? "#define USE_DISPLACEMENTMAP" : "", + t.emissiveMap ? "#define USE_EMISSIVEMAP" : "", + t.anisotropy ? "#define USE_ANISOTROPY" : "", + t.anisotropyMap ? "#define USE_ANISOTROPYMAP" : "", t.clearcoatMap ? "#define USE_CLEARCOATMAP" : "", t.clearcoatRoughnessMap ? "#define USE_CLEARCOAT_ROUGHNESSMAP" : "", t.clearcoatNormalMap ? "#define USE_CLEARCOAT_NORMALMAP" : "", - t.displacementMap && t.supportsVertexTextures ? "#define USE_DISPLACEMENTMAP" : "", + t.iridescenceMap ? "#define USE_IRIDESCENCEMAP" : "", + t.iridescenceThicknessMap ? "#define USE_IRIDESCENCE_THICKNESSMAP" : "", t.specularMap ? "#define USE_SPECULARMAP" : "", - t.specularIntensityMap ? "#define USE_SPECULARINTENSITYMAP" : "", - t.specularColorMap ? "#define USE_SPECULARCOLORMAP" : "", + t.specularColorMap ? "#define USE_SPECULAR_COLORMAP" : "", + t.specularIntensityMap ? "#define USE_SPECULAR_INTENSITYMAP" : "", t.roughnessMap ? "#define USE_ROUGHNESSMAP" : "", t.metalnessMap ? "#define USE_METALNESSMAP" : "", t.alphaMap ? "#define USE_ALPHAMAP" : "", + t.alphaHash ? "#define USE_ALPHAHASH" : "", t.transmission ? "#define USE_TRANSMISSION" : "", t.transmissionMap ? "#define USE_TRANSMISSIONMAP" : "", t.thicknessMap ? "#define USE_THICKNESSMAP" : "", - t.sheenColorMap ? "#define USE_SHEENCOLORMAP" : "", - t.sheenRoughnessMap ? "#define USE_SHEENROUGHNESSMAP" : "", - t.vertexTangents ? "#define USE_TANGENT" : "", + t.sheenColorMap ? "#define USE_SHEEN_COLORMAP" : "", + t.sheenRoughnessMap ? "#define USE_SHEEN_ROUGHNESSMAP" : "", + t.mapUv ? "#define MAP_UV " + t.mapUv : "", + t.alphaMapUv ? "#define ALPHAMAP_UV " + t.alphaMapUv : "", + t.lightMapUv ? "#define LIGHTMAP_UV " + t.lightMapUv : "", + t.aoMapUv ? "#define AOMAP_UV " + t.aoMapUv : "", + t.emissiveMapUv ? "#define EMISSIVEMAP_UV " + t.emissiveMapUv : "", + t.bumpMapUv ? "#define BUMPMAP_UV " + t.bumpMapUv : "", + t.normalMapUv ? "#define NORMALMAP_UV " + t.normalMapUv : "", + t.displacementMapUv ? "#define DISPLACEMENTMAP_UV " + t.displacementMapUv : "", + t.metalnessMapUv ? "#define METALNESSMAP_UV " + t.metalnessMapUv : "", + t.roughnessMapUv ? "#define ROUGHNESSMAP_UV " + t.roughnessMapUv : "", + t.anisotropyMapUv ? "#define ANISOTROPYMAP_UV " + t.anisotropyMapUv : "", + t.clearcoatMapUv ? "#define CLEARCOATMAP_UV " + t.clearcoatMapUv : "", + t.clearcoatNormalMapUv ? "#define CLEARCOAT_NORMALMAP_UV " + t.clearcoatNormalMapUv : "", + t.clearcoatRoughnessMapUv ? "#define CLEARCOAT_ROUGHNESSMAP_UV " + t.clearcoatRoughnessMapUv : "", + t.iridescenceMapUv ? "#define IRIDESCENCEMAP_UV " + t.iridescenceMapUv : "", + t.iridescenceThicknessMapUv ? "#define IRIDESCENCE_THICKNESSMAP_UV " + t.iridescenceThicknessMapUv : "", + t.sheenColorMapUv ? "#define SHEEN_COLORMAP_UV " + t.sheenColorMapUv : "", + t.sheenRoughnessMapUv ? "#define SHEEN_ROUGHNESSMAP_UV " + t.sheenRoughnessMapUv : "", + t.specularMapUv ? "#define SPECULARMAP_UV " + t.specularMapUv : "", + t.specularColorMapUv ? "#define SPECULAR_COLORMAP_UV " + t.specularColorMapUv : "", + t.specularIntensityMapUv ? "#define SPECULAR_INTENSITYMAP_UV " + t.specularIntensityMapUv : "", + t.transmissionMapUv ? "#define TRANSMISSIONMAP_UV " + t.transmissionMapUv : "", + t.thicknessMapUv ? "#define THICKNESSMAP_UV " + t.thicknessMapUv : "", + t.vertexTangents && t.flatShading === !1 ? "#define USE_TANGENT" : "", t.vertexColors ? "#define USE_COLOR" : "", t.vertexAlphas ? "#define USE_COLOR_ALPHA" : "", - t.vertexUvs ? "#define USE_UV" : "", - t.uvsVertexOnly ? "#define UVS_VERTEX_ONLY" : "", + t.vertexUv1s ? "#define USE_UV1" : "", + t.vertexUv2s ? "#define USE_UV2" : "", + t.vertexUv3s ? "#define USE_UV3" : "", + t.pointsUvs ? "#define USE_POINTS_UV" : "", t.flatShading ? "#define FLAT_SHADED" : "", t.skinning ? "#define USE_SKINNING" : "", - t.useVertexTexture ? "#define BONE_TEXTURE" : "", t.morphTargets ? "#define USE_MORPHTARGETS" : "", t.morphNormals && t.flatShading === !1 ? "#define USE_MORPHNORMALS" : "", - t.morphTargets && t.isWebGL2 ? "#define MORPHTARGETS_TEXTURE" : "", - t.morphTargets && t.isWebGL2 ? "#define MORPHTARGETS_COUNT " + t.morphTargetsCount : "", + t.morphColors && t.isWebGL2 ? "#define USE_MORPHCOLORS" : "", + t.morphTargetsCount > 0 && t.isWebGL2 ? "#define MORPHTARGETS_TEXTURE" : "", + t.morphTargetsCount > 0 && t.isWebGL2 ? "#define MORPHTARGETS_TEXTURE_STRIDE " + t.morphTextureStride : "", + t.morphTargetsCount > 0 && t.isWebGL2 ? "#define MORPHTARGETS_COUNT " + t.morphTargetsCount : "", t.doubleSided ? "#define DOUBLE_SIDED" : "", t.flipSided ? "#define FLIP_SIDED" : "", t.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", - t.shadowMapEnabled ? "#define " + l : "", + t.shadowMapEnabled ? "#define " + c : "", t.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "", + t.numLightProbes > 0 ? "#define USE_LIGHT_PROBES" : "", + t.useLegacyLights ? "#define LEGACY_LIGHTS" : "", t.logarithmicDepthBuffer ? "#define USE_LOGDEPTHBUF" : "", t.logarithmicDepthBuffer && t.rendererExtensionFragDepth ? "#define USE_LOGDEPTHBUF_EXT" : "", "uniform mat4 modelMatrix;", @@ -9232,6 +10491,15 @@ function hx(s, e, t, n) { "attribute vec3 position;", "attribute vec3 normal;", "attribute vec2 uv;", + "#ifdef USE_UV1", + " attribute vec2 uv1;", + "#endif", + "#ifdef USE_UV2", + " attribute vec2 uv2;", + "#endif", + "#ifdef USE_UV3", + " attribute vec2 uv3;", + "#endif", "#ifdef USE_TANGENT", " attribute vec4 tangent;", "#endif", @@ -9263,93 +10531,99 @@ function hx(s, e, t, n) { "#endif", ` ` - ].filter(rr).join(` -`), v = [ - d, - Jl(t), - "#define SHADER_NAME " + t.shaderName, + ].filter(vs).join(` +`), p = [ f, + Ah(t), + "#define SHADER_TYPE " + t.shaderType, + "#define SHADER_NAME " + t.shaderName, + m, t.useFog && t.fog ? "#define USE_FOG" : "", t.useFog && t.fogExp2 ? "#define FOG_EXP2" : "", t.map ? "#define USE_MAP" : "", t.matcap ? "#define USE_MATCAP" : "", t.envMap ? "#define USE_ENVMAP" : "", - t.envMap ? "#define " + c : "", + t.envMap ? "#define " + l : "", t.envMap ? "#define " + h : "", t.envMap ? "#define " + u : "", + d ? "#define CUBEUV_TEXEL_WIDTH " + d.texelWidth : "", + d ? "#define CUBEUV_TEXEL_HEIGHT " + d.texelHeight : "", + d ? "#define CUBEUV_MAX_MIP " + d.maxMip + ".0" : "", t.lightMap ? "#define USE_LIGHTMAP" : "", t.aoMap ? "#define USE_AOMAP" : "", - t.emissiveMap ? "#define USE_EMISSIVEMAP" : "", t.bumpMap ? "#define USE_BUMPMAP" : "", t.normalMap ? "#define USE_NORMALMAP" : "", - t.normalMap && t.objectSpaceNormalMap ? "#define OBJECTSPACE_NORMALMAP" : "", - t.normalMap && t.tangentSpaceNormalMap ? "#define TANGENTSPACE_NORMALMAP" : "", + t.normalMapObjectSpace ? "#define USE_NORMALMAP_OBJECTSPACE" : "", + t.normalMapTangentSpace ? "#define USE_NORMALMAP_TANGENTSPACE" : "", + t.emissiveMap ? "#define USE_EMISSIVEMAP" : "", + t.anisotropy ? "#define USE_ANISOTROPY" : "", + t.anisotropyMap ? "#define USE_ANISOTROPYMAP" : "", t.clearcoat ? "#define USE_CLEARCOAT" : "", t.clearcoatMap ? "#define USE_CLEARCOATMAP" : "", t.clearcoatRoughnessMap ? "#define USE_CLEARCOAT_ROUGHNESSMAP" : "", t.clearcoatNormalMap ? "#define USE_CLEARCOAT_NORMALMAP" : "", + t.iridescence ? "#define USE_IRIDESCENCE" : "", + t.iridescenceMap ? "#define USE_IRIDESCENCEMAP" : "", + t.iridescenceThicknessMap ? "#define USE_IRIDESCENCE_THICKNESSMAP" : "", t.specularMap ? "#define USE_SPECULARMAP" : "", - t.specularIntensityMap ? "#define USE_SPECULARINTENSITYMAP" : "", - t.specularColorMap ? "#define USE_SPECULARCOLORMAP" : "", + t.specularColorMap ? "#define USE_SPECULAR_COLORMAP" : "", + t.specularIntensityMap ? "#define USE_SPECULAR_INTENSITYMAP" : "", t.roughnessMap ? "#define USE_ROUGHNESSMAP" : "", t.metalnessMap ? "#define USE_METALNESSMAP" : "", t.alphaMap ? "#define USE_ALPHAMAP" : "", t.alphaTest ? "#define USE_ALPHATEST" : "", + t.alphaHash ? "#define USE_ALPHAHASH" : "", t.sheen ? "#define USE_SHEEN" : "", - t.sheenColorMap ? "#define USE_SHEENCOLORMAP" : "", - t.sheenRoughnessMap ? "#define USE_SHEENROUGHNESSMAP" : "", + t.sheenColorMap ? "#define USE_SHEEN_COLORMAP" : "", + t.sheenRoughnessMap ? "#define USE_SHEEN_ROUGHNESSMAP" : "", t.transmission ? "#define USE_TRANSMISSION" : "", t.transmissionMap ? "#define USE_TRANSMISSIONMAP" : "", t.thicknessMap ? "#define USE_THICKNESSMAP" : "", - t.vertexTangents ? "#define USE_TANGENT" : "", + t.vertexTangents && t.flatShading === !1 ? "#define USE_TANGENT" : "", t.vertexColors || t.instancingColor ? "#define USE_COLOR" : "", t.vertexAlphas ? "#define USE_COLOR_ALPHA" : "", - t.vertexUvs ? "#define USE_UV" : "", - t.uvsVertexOnly ? "#define UVS_VERTEX_ONLY" : "", + t.vertexUv1s ? "#define USE_UV1" : "", + t.vertexUv2s ? "#define USE_UV2" : "", + t.vertexUv3s ? "#define USE_UV3" : "", + t.pointsUvs ? "#define USE_POINTS_UV" : "", t.gradientMap ? "#define USE_GRADIENTMAP" : "", t.flatShading ? "#define FLAT_SHADED" : "", t.doubleSided ? "#define DOUBLE_SIDED" : "", t.flipSided ? "#define FLIP_SIDED" : "", t.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", - t.shadowMapEnabled ? "#define " + l : "", + t.shadowMapEnabled ? "#define " + c : "", t.premultipliedAlpha ? "#define PREMULTIPLIED_ALPHA" : "", - t.physicallyCorrectLights ? "#define PHYSICALLY_CORRECT_LIGHTS" : "", + t.numLightProbes > 0 ? "#define USE_LIGHT_PROBES" : "", + t.useLegacyLights ? "#define LEGACY_LIGHTS" : "", + t.decodeVideoTexture ? "#define DECODE_VIDEO_TEXTURE" : "", t.logarithmicDepthBuffer ? "#define USE_LOGDEPTHBUF" : "", t.logarithmicDepthBuffer && t.rendererExtensionFragDepth ? "#define USE_LOGDEPTHBUF_EXT" : "", - (t.extensionShaderTextureLOD || t.envMap) && t.rendererExtensionShaderTextureLod ? "#define TEXTURE_LOD_EXT" : "", "uniform mat4 viewMatrix;", "uniform vec3 cameraPosition;", "uniform bool isOrthographic;", - t.toneMapping !== _n ? "#define TONE_MAPPING" : "", - t.toneMapping !== _n ? Fe.tonemapping_pars_fragment : "", - t.toneMapping !== _n ? jg("toneMapping", t.toneMapping) : "", + t.toneMapping !== Nn ? "#define TONE_MAPPING" : "", + t.toneMapping !== Nn ? ke.tonemapping_pars_fragment : "", + t.toneMapping !== Nn ? l0("toneMapping", t.toneMapping) : "", t.dithering ? "#define DITHERING" : "", - t.format === Gn ? "#define OPAQUE" : "", - Fe.encodings_pars_fragment, - t.map ? Dn("mapTexelToLinear", t.mapEncoding) : "", - t.matcap ? Dn("matcapTexelToLinear", t.matcapEncoding) : "", - t.envMap ? Dn("envMapTexelToLinear", t.envMapEncoding) : "", - t.emissiveMap ? Dn("emissiveMapTexelToLinear", t.emissiveMapEncoding) : "", - t.specularColorMap ? Dn("specularColorMapTexelToLinear", t.specularColorMapEncoding) : "", - t.sheenColorMap ? Dn("sheenColorMapTexelToLinear", t.sheenColorMapEncoding) : "", - t.lightMap ? Dn("lightMapTexelToLinear", t.lightMapEncoding) : "", - $g("linearToOutputTexel", t.outputEncoding), - t.depthPacking ? "#define DEPTH_PACKING " + t.depthPacking : "", + t.opaque ? "#define OPAQUE" : "", + ke.colorspace_pars_fragment, + c0("linearToOutputTexel", t.outputColorSpace), + t.useDepthPacking ? "#define DEPTH_PACKING " + t.depthPacking : "", ` ` - ].filter(rr).join(` -`)), o = ra(o), o = Wl(o, t), o = ql(o, t), a = ra(a), a = Wl(a, t), a = ql(a, t), o = Xl(o), a = Xl(a), t.isWebGL2 && t.isRawShaderMaterial !== !0 && (g = `#version 300 es -`, x = [ + ].filter(vs).join(` +`)), a = So(a), a = Eh(a, t), a = Th(a, t), o = So(o), o = Eh(o, t), o = Th(o, t), a = wh(a), o = wh(o), t.isWebGL2 && t.isRawShaderMaterial !== !0 && (v = `#version 300 es +`, g = [ "precision mediump sampler2DArray;", "#define attribute in", "#define varying out", "#define texture2D texture" ].join(` `) + ` -` + x, v = [ +` + g, p = [ "#define varying in", - t.glslVersion === xl ? "" : "layout(location = 0) out highp vec4 pc_fragColor;", - t.glslVersion === xl ? "" : "#define gl_FragColor pc_fragColor", + t.glslVersion === Ol ? "" : "layout(location = 0) out highp vec4 pc_fragColor;", + t.glslVersion === Ol ? "" : "#define gl_FragColor pc_fragColor", "#define gl_FragDepthEXT gl_FragDepth", "#define texture2D texture", "#define textureCube texture", @@ -9362,55 +10636,56 @@ function hx(s, e, t, n) { "#define textureCubeGradEXT textureGrad" ].join(` `) + ` -` + v); - let p = g + x + o, _ = g + v + a, y = Gl(i, 35633, p), b = Gl(i, 35632, _); - if (i.attachShader(m, y), i.attachShader(m, b), t.index0AttributeName !== void 0 ? i.bindAttribLocation(m, 0, t.index0AttributeName) : t.morphTargets === !0 && i.bindAttribLocation(m, 0, "position"), i.linkProgram(m), s.debug.checkShaderErrors) { - let I = i.getProgramInfoLog(m).trim(), k = i.getShaderInfoLog(y).trim(), B = i.getShaderInfoLog(b).trim(), P = !0, w = !0; - if (i.getProgramParameter(m, 35714) === !1) { - P = !1; - let E = Vl(i, y, "vertex"), D = Vl(i, b, "fragment"); - console.error("THREE.WebGLProgram: Shader Error " + i.getError() + " - VALIDATE_STATUS " + i.getProgramParameter(m, 35715) + ` +` + p); + let x = v + g + a, y = v + p + o, b = Sh(i, i.VERTEX_SHADER, x), w = Sh(i, i.FRAGMENT_SHADER, y); + if (i.attachShader(_, b), i.attachShader(_, w), t.index0AttributeName !== void 0 ? i.bindAttribLocation(_, 0, t.index0AttributeName) : t.morphTargets === !0 && i.bindAttribLocation(_, 0, "position"), i.linkProgram(_), s1.debug.checkShaderErrors) { + let M = i.getProgramInfoLog(_).trim(), T = i.getShaderInfoLog(b).trim(), O = i.getShaderInfoLog(w).trim(), Y = !0, $ = !0; + if (i.getProgramParameter(_, i.LINK_STATUS) === !1) if (Y = !1, typeof s1.debug.onShaderError == "function") s1.debug.onShaderError(i, _, b, w); + else { + let U = bh(i, b, "vertex"), z = bh(i, w, "fragment"); + console.error("THREE.WebGLProgram: Shader Error " + i.getError() + " - VALIDATE_STATUS " + i.getProgramParameter(_, i.VALIDATE_STATUS) + ` -Program Info Log: ` + I + ` -` + E + ` -` + D); - } else I !== "" ? console.warn("THREE.WebGLProgram: Program Info Log:", I) : (k === "" || B === "") && (w = !1); - w && (this.diagnostics = { - runnable: P, - programLog: I, +Program Info Log: ` + M + ` +` + U + ` +` + z); + } + else M !== "" ? console.warn("THREE.WebGLProgram: Program Info Log:", M) : (T === "" || O === "") && ($ = !1); + $ && (this.diagnostics = { + runnable: Y, + programLog: M, vertexShader: { - log: k, - prefix: x + log: T, + prefix: g }, fragmentShader: { - log: B, - prefix: v + log: O, + prefix: p } }); } - i.deleteShader(y), i.deleteShader(b); - let A; + i.deleteShader(b), i.deleteShader(w); + let R; this.getUniforms = function() { - return A === void 0 && (A = new bn(i, m)), A; + return R === void 0 && (R = new qi(i, _)), R; }; - let L; + let I; return this.getAttributes = function() { - return L === void 0 && (L = ex(i, m)), L; + return I === void 0 && (I = d0(i, _)), I; }, this.destroy = function() { - n.releaseStatesOfProgram(this), i.deleteProgram(m), this.program = void 0; - }, this.name = t.shaderName, this.id = Yg++, this.cacheKey = e, this.usedTimes = 1, this.program = m, this.vertexShader = y, this.fragmentShader = b, this; + n.releaseStatesOfProgram(this), i.deleteProgram(_), this.program = void 0; + }, this.type = t.shaderType, this.name = t.shaderName, this.id = r0++, this.cacheKey = e, this.usedTimes = 1, this.program = _, this.vertexShader = b, this.fragmentShader = w, this; } -var ux = 0, gh = class { +var E0 = 0, bo = class { constructor(){ this.shaderCache = new Map, this.materialCache = new Map; } update(e) { - let t = e.vertexShader, n = e.fragmentShader, i = this._getShaderStage(t), r = this._getShaderStage(n), o = this._getShaderCacheForMaterial(e); - return o.has(i) === !1 && (o.add(i), i.usedTimes++), o.has(r) === !1 && (o.add(r), r.usedTimes++), this; + let t = e.vertexShader, n = e.fragmentShader, i = this._getShaderStage(t), r = this._getShaderStage(n), a = this._getShaderCacheForMaterial(e); + return a.has(i) === !1 && (a.add(i), i.usedTimes++), a.has(r) === !1 && (a.add(r), r.usedTimes++), this; } remove(e) { let t = this.materialCache.get(e); - for (let n of t)n.usedTimes--, n.usedTimes === 0 && this.shaderCache.delete(n); + for (let n of t)n.usedTimes--, n.usedTimes === 0 && this.shaderCache.delete(n.code); return this.materialCache.delete(e), this; } getVertexShaderID(e) { @@ -9423,24 +10698,20 @@ var ux = 0, gh = class { this.shaderCache.clear(), this.materialCache.clear(); } _getShaderCacheForMaterial(e) { - let t = this.materialCache; - return t.has(e) === !1 && t.set(e, new Set), t.get(e); + let t = this.materialCache, n = t.get(e); + return n === void 0 && (n = new Set, t.set(e, n)), n; } _getShaderStage(e) { - let t = this.shaderCache; - if (t.has(e) === !1) { - let n = new xh; - t.set(e, n); - } - return t.get(e); + let t = this.shaderCache, n = t.get(e); + return n === void 0 && (n = new Eo(e), t.set(e, n)), n; } -}, xh = class { - constructor(){ - this.id = ux++, this.usedTimes = 0; +}, Eo = class { + constructor(e){ + this.id = E0++, this.code = e, this.usedTimes = 0; } }; -function dx(s, e, t, n, i, r, o) { - let a = new Js, l = new gh, c = [], h = i.isWebGL2, u = i.logarithmicDepthBuffer, d = i.floatVertexTextures, f = i.maxVertexUniforms, m = i.vertexTextures, x = i.precision, v = { +function T0(s1, e, t, n, i, r, a) { + let o = new Rs, c = new bo, l = [], h = i.isWebGL2, u = i.logarithmicDepthBuffer, d = i.vertexTextures, f = i.precision, m = { MeshDepthMaterial: "depth", MeshDistanceMaterial: "distanceRGBA", MeshNormalMaterial: "normal", @@ -9457,197 +10728,220 @@ function dx(s, e, t, n, i, r, o) { ShadowMaterial: "shadow", SpriteMaterial: "sprite" }; - function g(w) { - let D = w.skeleton.bones; - if (d) return 1024; - { - let F = Math.floor((f - 20) / 4), O = Math.min(F, D.length); - return O < D.length ? (console.warn("THREE.WebGLRenderer: Skeleton has " + D.length + " bones. This GPU supports " + O + "."), 0) : O; - } - } - function p(w) { - let E; - return w && w.isTexture ? E = w.encoding : w && w.isWebGLRenderTarget ? (console.warn("THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead."), E = w.texture.encoding) : E = Nt, h && w && w.isTexture && w.format === ct && w.type === rn && w.encoding === Oi && (E = Nt), E; - } - function _(w, E, D, U, F) { - let O = U.fog, ne = w.isMeshStandardMaterial ? U.environment : null, ce = (w.isMeshStandardMaterial ? t : e).get(w.envMap || ne), V = v[w.type], W = F.isSkinnedMesh ? g(F) : 0; - w.precision !== null && (x = i.getMaxPrecision(w.precision), x !== w.precision && console.warn("THREE.WebGLProgram.getParameters:", w.precision, "not supported, using", x, "instead.")); - let he, le, fe, Be; - if (V) { - let xe = qt[V]; - he = xe.vertexShader, le = xe.fragmentShader; - } else he = w.vertexShader, le = w.fragmentShader, l.update(w), fe = l.getVertexShaderID(w), Be = l.getFragmentShaderID(w); - let Y = s.getRenderTarget(), Ce = w.alphaTest > 0, ye = w.clearcoat > 0; - return { + function _(M) { + return M === 0 ? "uv" : `uv${M}`; + } + function g(M, T, O, Y, $) { + let U = Y.fog, z = $.geometry, q = M.isMeshStandardMaterial ? Y.environment : null, H = (M.isMeshStandardMaterial ? t : e).get(M.envMap || q), ne = H && H.mapping === Vs ? H.image.height : null, W = m[M.type]; + M.precision !== null && (f = i.getMaxPrecision(M.precision), f !== M.precision && console.warn("THREE.WebGLProgram.getParameters:", M.precision, "not supported, using", f, "instead.")); + let K = z.morphAttributes.position || z.morphAttributes.normal || z.morphAttributes.color, D = K !== void 0 ? K.length : 0, G = 0; + z.morphAttributes.position !== void 0 && (G = 1), z.morphAttributes.normal !== void 0 && (G = 2), z.morphAttributes.color !== void 0 && (G = 3); + let he, fe, _e, we; + if (W) { + let tt = nn[W]; + he = tt.vertexShader, fe = tt.fragmentShader; + } else he = M.vertexShader, fe = M.fragmentShader, c.update(M), _e = c.getVertexShaderID(M), we = c.getFragmentShaderID(M); + let Ee = s1.getRenderTarget(), Te = $.isInstancedMesh === !0, Ye = !!M.map, it = !!M.matcap, Ce = !!H, L = !!M.aoMap, oe = !!M.lightMap, X = !!M.bumpMap, ie = !!M.normalMap, J = !!M.displacementMap, Se = !!M.emissiveMap, me = !!M.metalnessMap, ye = !!M.roughnessMap, Ne = M.anisotropy > 0, qe = M.clearcoat > 0, rt = M.iridescence > 0, C = M.sheen > 0, S = M.transmission > 0, B = Ne && !!M.anisotropyMap, ee = qe && !!M.clearcoatMap, j = qe && !!M.clearcoatNormalMap, te = qe && !!M.clearcoatRoughnessMap, Me = rt && !!M.iridescenceMap, re = rt && !!M.iridescenceThicknessMap, de = C && !!M.sheenColorMap, Le = C && !!M.sheenRoughnessMap, Ze = !!M.specularMap, se = !!M.specularColorMap, $e = !!M.specularIntensityMap, Oe = S && !!M.transmissionMap, Ie = S && !!M.thicknessMap, Re = !!M.gradientMap, P = !!M.alphaMap, ce = M.alphaTest > 0, ae = !!M.alphaHash, ge = !!M.extensions, ue = !!z.attributes.uv1, Q = !!z.attributes.uv2, be = !!z.attributes.uv3, Fe = Nn; + return M.toneMapped && (Ee === null || Ee.isXRRenderTarget === !0) && (Fe = s1.toneMapping), { isWebGL2: h, - shaderID: V, - shaderName: w.type, + shaderID: W, + shaderType: M.type, + shaderName: M.name, vertexShader: he, - fragmentShader: le, - defines: w.defines, - customVertexShaderID: fe, - customFragmentShaderID: Be, - isRawShaderMaterial: w.isRawShaderMaterial === !0, - glslVersion: w.glslVersion, - precision: x, - instancing: F.isInstancedMesh === !0, - instancingColor: F.isInstancedMesh === !0 && F.instanceColor !== null, - supportsVertexTextures: m, - outputEncoding: Y !== null ? p(Y.texture) : s.outputEncoding, - map: !!w.map, - mapEncoding: p(w.map), - matcap: !!w.matcap, - matcapEncoding: p(w.matcap), - envMap: !!ce, - envMapMode: ce && ce.mapping, - envMapEncoding: p(ce), - envMapCubeUV: !!ce && (ce.mapping === Pr || ce.mapping === Ws), - lightMap: !!w.lightMap, - lightMapEncoding: p(w.lightMap), - aoMap: !!w.aoMap, - emissiveMap: !!w.emissiveMap, - emissiveMapEncoding: p(w.emissiveMap), - bumpMap: !!w.bumpMap, - normalMap: !!w.normalMap, - objectSpaceNormalMap: w.normalMapType === zd, - tangentSpaceNormalMap: w.normalMapType === Hi, - clearcoat: ye, - clearcoatMap: ye && !!w.clearcoatMap, - clearcoatRoughnessMap: ye && !!w.clearcoatRoughnessMap, - clearcoatNormalMap: ye && !!w.clearcoatNormalMap, - displacementMap: !!w.displacementMap, - roughnessMap: !!w.roughnessMap, - metalnessMap: !!w.metalnessMap, - specularMap: !!w.specularMap, - specularIntensityMap: !!w.specularIntensityMap, - specularColorMap: !!w.specularColorMap, - specularColorMapEncoding: p(w.specularColorMap), - alphaMap: !!w.alphaMap, - alphaTest: Ce, - gradientMap: !!w.gradientMap, - sheen: w.sheen > 0, - sheenColorMap: !!w.sheenColorMap, - sheenColorMapEncoding: p(w.sheenColorMap), - sheenRoughnessMap: !!w.sheenRoughnessMap, - transmission: w.transmission > 0, - transmissionMap: !!w.transmissionMap, - thicknessMap: !!w.thicknessMap, - combine: w.combine, - vertexTangents: !!w.normalMap && !!F.geometry && !!F.geometry.attributes.tangent, - vertexColors: w.vertexColors, - vertexAlphas: w.vertexColors === !0 && !!F.geometry && !!F.geometry.attributes.color && F.geometry.attributes.color.itemSize === 4, - vertexUvs: !!w.map || !!w.bumpMap || !!w.normalMap || !!w.specularMap || !!w.alphaMap || !!w.emissiveMap || !!w.roughnessMap || !!w.metalnessMap || !!w.clearcoatMap || !!w.clearcoatRoughnessMap || !!w.clearcoatNormalMap || !!w.displacementMap || !!w.transmissionMap || !!w.thicknessMap || !!w.specularIntensityMap || !!w.specularColorMap || !!w.sheenColorMap || !!w.sheenRoughnessMap, - uvsVertexOnly: !(!!w.map || !!w.bumpMap || !!w.normalMap || !!w.specularMap || !!w.alphaMap || !!w.emissiveMap || !!w.roughnessMap || !!w.metalnessMap || !!w.clearcoatNormalMap || w.transmission > 0 || !!w.transmissionMap || !!w.thicknessMap || !!w.specularIntensityMap || !!w.specularColorMap || w.sheen > 0 || !!w.sheenColorMap || !!w.sheenRoughnessMap) && !!w.displacementMap, - fog: !!O, - useFog: w.fog, - fogExp2: O && O.isFogExp2, - flatShading: !!w.flatShading, - sizeAttenuation: w.sizeAttenuation, + fragmentShader: fe, + defines: M.defines, + customVertexShaderID: _e, + customFragmentShaderID: we, + isRawShaderMaterial: M.isRawShaderMaterial === !0, + glslVersion: M.glslVersion, + precision: f, + instancing: Te, + instancingColor: Te && $.instanceColor !== null, + supportsVertexTextures: d, + outputColorSpace: Ee === null ? s1.outputColorSpace : Ee.isXRRenderTarget === !0 ? Ee.texture.colorSpace : Mn, + map: Ye, + matcap: it, + envMap: Ce, + envMapMode: Ce && H.mapping, + envMapCubeUVHeight: ne, + aoMap: L, + lightMap: oe, + bumpMap: X, + normalMap: ie, + displacementMap: d && J, + emissiveMap: Se, + normalMapObjectSpace: ie && M.normalMapType === Lf, + normalMapTangentSpace: ie && M.normalMapType === mi, + metalnessMap: me, + roughnessMap: ye, + anisotropy: Ne, + anisotropyMap: B, + clearcoat: qe, + clearcoatMap: ee, + clearcoatNormalMap: j, + clearcoatRoughnessMap: te, + iridescence: rt, + iridescenceMap: Me, + iridescenceThicknessMap: re, + sheen: C, + sheenColorMap: de, + sheenRoughnessMap: Le, + specularMap: Ze, + specularColorMap: se, + specularIntensityMap: $e, + transmission: S, + transmissionMap: Oe, + thicknessMap: Ie, + gradientMap: Re, + opaque: M.transparent === !1 && M.blending === Wi, + alphaMap: P, + alphaTest: ce, + alphaHash: ae, + combine: M.combine, + mapUv: Ye && _(M.map.channel), + aoMapUv: L && _(M.aoMap.channel), + lightMapUv: oe && _(M.lightMap.channel), + bumpMapUv: X && _(M.bumpMap.channel), + normalMapUv: ie && _(M.normalMap.channel), + displacementMapUv: J && _(M.displacementMap.channel), + emissiveMapUv: Se && _(M.emissiveMap.channel), + metalnessMapUv: me && _(M.metalnessMap.channel), + roughnessMapUv: ye && _(M.roughnessMap.channel), + anisotropyMapUv: B && _(M.anisotropyMap.channel), + clearcoatMapUv: ee && _(M.clearcoatMap.channel), + clearcoatNormalMapUv: j && _(M.clearcoatNormalMap.channel), + clearcoatRoughnessMapUv: te && _(M.clearcoatRoughnessMap.channel), + iridescenceMapUv: Me && _(M.iridescenceMap.channel), + iridescenceThicknessMapUv: re && _(M.iridescenceThicknessMap.channel), + sheenColorMapUv: de && _(M.sheenColorMap.channel), + sheenRoughnessMapUv: Le && _(M.sheenRoughnessMap.channel), + specularMapUv: Ze && _(M.specularMap.channel), + specularColorMapUv: se && _(M.specularColorMap.channel), + specularIntensityMapUv: $e && _(M.specularIntensityMap.channel), + transmissionMapUv: Oe && _(M.transmissionMap.channel), + thicknessMapUv: Ie && _(M.thicknessMap.channel), + alphaMapUv: P && _(M.alphaMap.channel), + vertexTangents: !!z.attributes.tangent && (ie || Ne), + vertexColors: M.vertexColors, + vertexAlphas: M.vertexColors === !0 && !!z.attributes.color && z.attributes.color.itemSize === 4, + vertexUv1s: ue, + vertexUv2s: Q, + vertexUv3s: be, + pointsUvs: $.isPoints === !0 && !!z.attributes.uv && (Ye || P), + fog: !!U, + useFog: M.fog === !0, + fogExp2: U && U.isFogExp2, + flatShading: M.flatShading === !0, + sizeAttenuation: M.sizeAttenuation === !0, logarithmicDepthBuffer: u, - skinning: F.isSkinnedMesh === !0 && W > 0, - maxBones: W, - useVertexTexture: d, - morphTargets: !!F.geometry && !!F.geometry.morphAttributes.position, - morphNormals: !!F.geometry && !!F.geometry.morphAttributes.normal, - morphTargetsCount: !!F.geometry && !!F.geometry.morphAttributes.position ? F.geometry.morphAttributes.position.length : 0, - numDirLights: E.directional.length, - numPointLights: E.point.length, - numSpotLights: E.spot.length, - numRectAreaLights: E.rectArea.length, - numHemiLights: E.hemi.length, - numDirLightShadows: E.directionalShadowMap.length, - numPointLightShadows: E.pointShadowMap.length, - numSpotLightShadows: E.spotShadowMap.length, - numClippingPlanes: o.numPlanes, - numClipIntersection: o.numIntersection, - format: w.format, - dithering: w.dithering, - shadowMapEnabled: s.shadowMap.enabled && D.length > 0, - shadowMapType: s.shadowMap.type, - toneMapping: w.toneMapped ? s.toneMapping : _n, - physicallyCorrectLights: s.physicallyCorrectLights, - premultipliedAlpha: w.premultipliedAlpha, - doubleSided: w.side === Ci, - flipSided: w.side === it, - depthPacking: w.depthPacking !== void 0 ? w.depthPacking : !1, - index0AttributeName: w.index0AttributeName, - extensionDerivatives: w.extensions && w.extensions.derivatives, - extensionFragDepth: w.extensions && w.extensions.fragDepth, - extensionDrawBuffers: w.extensions && w.extensions.drawBuffers, - extensionShaderTextureLOD: w.extensions && w.extensions.shaderTextureLOD, + skinning: $.isSkinnedMesh === !0, + morphTargets: z.morphAttributes.position !== void 0, + morphNormals: z.morphAttributes.normal !== void 0, + morphColors: z.morphAttributes.color !== void 0, + morphTargetsCount: D, + morphTextureStride: G, + numDirLights: T.directional.length, + numPointLights: T.point.length, + numSpotLights: T.spot.length, + numSpotLightMaps: T.spotLightMap.length, + numRectAreaLights: T.rectArea.length, + numHemiLights: T.hemi.length, + numDirLightShadows: T.directionalShadowMap.length, + numPointLightShadows: T.pointShadowMap.length, + numSpotLightShadows: T.spotShadowMap.length, + numSpotLightShadowsWithMaps: T.numSpotLightShadowsWithMaps, + numLightProbes: T.numLightProbes, + numClippingPlanes: a.numPlanes, + numClipIntersection: a.numIntersection, + dithering: M.dithering, + shadowMapEnabled: s1.shadowMap.enabled && O.length > 0, + shadowMapType: s1.shadowMap.type, + toneMapping: Fe, + useLegacyLights: s1._useLegacyLights, + decodeVideoTexture: Ye && M.map.isVideoTexture === !0 && Qe.getTransfer(M.map.colorSpace) === nt, + premultipliedAlpha: M.premultipliedAlpha, + doubleSided: M.side === gn, + flipSided: M.side === Ft, + useDepthPacking: M.depthPacking >= 0, + depthPacking: M.depthPacking || 0, + index0AttributeName: M.index0AttributeName, + extensionDerivatives: ge && M.extensions.derivatives === !0, + extensionFragDepth: ge && M.extensions.fragDepth === !0, + extensionDrawBuffers: ge && M.extensions.drawBuffers === !0, + extensionShaderTextureLOD: ge && M.extensions.shaderTextureLOD === !0, rendererExtensionFragDepth: h || n.has("EXT_frag_depth"), rendererExtensionDrawBuffers: h || n.has("WEBGL_draw_buffers"), rendererExtensionShaderTextureLod: h || n.has("EXT_shader_texture_lod"), - customProgramCacheKey: w.customProgramCacheKey() + customProgramCacheKey: M.customProgramCacheKey() }; } - function y(w) { - let E = []; - if (w.shaderID ? E.push(w.shaderID) : (E.push(w.customVertexShaderID), E.push(w.customFragmentShaderID)), w.defines !== void 0) for(let D in w.defines)E.push(D), E.push(w.defines[D]); - return w.isRawShaderMaterial === !1 && (b(E, w), A(E, w), E.push(s.outputEncoding)), E.push(w.customProgramCacheKey), E.join(); - } - function b(w, E) { - w.push(E.precision), w.push(E.outputEncoding), w.push(E.mapEncoding), w.push(E.matcapEncoding), w.push(E.envMapMode), w.push(E.envMapEncoding), w.push(E.lightMapEncoding), w.push(E.emissiveMapEncoding), w.push(E.combine), w.push(E.vertexUvs), w.push(E.fogExp2), w.push(E.sizeAttenuation), w.push(E.maxBones), w.push(E.morphTargetsCount), w.push(E.numDirLights), w.push(E.numPointLights), w.push(E.numSpotLights), w.push(E.numHemiLights), w.push(E.numRectAreaLights), w.push(E.numDirLightShadows), w.push(E.numPointLightShadows), w.push(E.numSpotLightShadows), w.push(E.shadowMapType), w.push(E.toneMapping), w.push(E.numClippingPlanes), w.push(E.numClipIntersection), w.push(E.format), w.push(E.specularColorMapEncoding), w.push(E.sheenColorMapEncoding); - } - function A(w, E) { - a.disableAll(), E.isWebGL2 && a.enable(0), E.supportsVertexTextures && a.enable(1), E.instancing && a.enable(2), E.instancingColor && a.enable(3), E.map && a.enable(4), E.matcap && a.enable(5), E.envMap && a.enable(6), E.envMapCubeUV && a.enable(7), E.lightMap && a.enable(8), E.aoMap && a.enable(9), E.emissiveMap && a.enable(10), E.bumpMap && a.enable(11), E.normalMap && a.enable(12), E.objectSpaceNormalMap && a.enable(13), E.tangentSpaceNormalMap && a.enable(14), E.clearcoat && a.enable(15), E.clearcoatMap && a.enable(16), E.clearcoatRoughnessMap && a.enable(17), E.clearcoatNormalMap && a.enable(18), E.displacementMap && a.enable(19), E.specularMap && a.enable(20), E.roughnessMap && a.enable(21), E.metalnessMap && a.enable(22), E.gradientMap && a.enable(23), E.alphaMap && a.enable(24), E.alphaTest && a.enable(25), E.vertexColors && a.enable(26), E.vertexAlphas && a.enable(27), E.vertexUvs && a.enable(28), E.vertexTangents && a.enable(29), E.uvsVertexOnly && a.enable(30), E.fog && a.enable(31), w.push(a.mask), a.disableAll(), E.useFog && a.enable(0), E.flatShading && a.enable(1), E.logarithmicDepthBuffer && a.enable(2), E.skinning && a.enable(3), E.useVertexTexture && a.enable(4), E.morphTargets && a.enable(5), E.morphNormals && a.enable(6), E.premultipliedAlpha && a.enable(7), E.shadowMapEnabled && a.enable(8), E.physicallyCorrectLights && a.enable(9), E.doubleSided && a.enable(10), E.flipSided && a.enable(11), E.depthPacking && a.enable(12), E.dithering && a.enable(13), E.specularIntensityMap && a.enable(14), E.specularColorMap && a.enable(15), E.transmission && a.enable(16), E.transmissionMap && a.enable(17), E.thicknessMap && a.enable(18), E.sheen && a.enable(19), E.sheenColorMap && a.enable(20), E.sheenRoughnessMap && a.enable(21), w.push(a.mask); - } - function L(w) { - let E = v[w.type], D; - if (E) { - let U = qt[E]; - D = uf.clone(U.uniforms); - } else D = w.uniforms; - return D; - } - function I(w, E) { - let D; - for(let U = 0, F = c.length; U < F; U++){ - let O = c[U]; - if (O.cacheKey === E) { - D = O, ++D.usedTimes; + function p(M) { + let T = []; + if (M.shaderID ? T.push(M.shaderID) : (T.push(M.customVertexShaderID), T.push(M.customFragmentShaderID)), M.defines !== void 0) for(let O in M.defines)T.push(O), T.push(M.defines[O]); + return M.isRawShaderMaterial === !1 && (v(T, M), x(T, M), T.push(s1.outputColorSpace)), T.push(M.customProgramCacheKey), T.join(); + } + function v(M, T) { + M.push(T.precision), M.push(T.outputColorSpace), M.push(T.envMapMode), M.push(T.envMapCubeUVHeight), M.push(T.mapUv), M.push(T.alphaMapUv), M.push(T.lightMapUv), M.push(T.aoMapUv), M.push(T.bumpMapUv), M.push(T.normalMapUv), M.push(T.displacementMapUv), M.push(T.emissiveMapUv), M.push(T.metalnessMapUv), M.push(T.roughnessMapUv), M.push(T.anisotropyMapUv), M.push(T.clearcoatMapUv), M.push(T.clearcoatNormalMapUv), M.push(T.clearcoatRoughnessMapUv), M.push(T.iridescenceMapUv), M.push(T.iridescenceThicknessMapUv), M.push(T.sheenColorMapUv), M.push(T.sheenRoughnessMapUv), M.push(T.specularMapUv), M.push(T.specularColorMapUv), M.push(T.specularIntensityMapUv), M.push(T.transmissionMapUv), M.push(T.thicknessMapUv), M.push(T.combine), M.push(T.fogExp2), M.push(T.sizeAttenuation), M.push(T.morphTargetsCount), M.push(T.morphAttributeCount), M.push(T.numDirLights), M.push(T.numPointLights), M.push(T.numSpotLights), M.push(T.numSpotLightMaps), M.push(T.numHemiLights), M.push(T.numRectAreaLights), M.push(T.numDirLightShadows), M.push(T.numPointLightShadows), M.push(T.numSpotLightShadows), M.push(T.numSpotLightShadowsWithMaps), M.push(T.numLightProbes), M.push(T.shadowMapType), M.push(T.toneMapping), M.push(T.numClippingPlanes), M.push(T.numClipIntersection), M.push(T.depthPacking); + } + function x(M, T) { + o.disableAll(), T.isWebGL2 && o.enable(0), T.supportsVertexTextures && o.enable(1), T.instancing && o.enable(2), T.instancingColor && o.enable(3), T.matcap && o.enable(4), T.envMap && o.enable(5), T.normalMapObjectSpace && o.enable(6), T.normalMapTangentSpace && o.enable(7), T.clearcoat && o.enable(8), T.iridescence && o.enable(9), T.alphaTest && o.enable(10), T.vertexColors && o.enable(11), T.vertexAlphas && o.enable(12), T.vertexUv1s && o.enable(13), T.vertexUv2s && o.enable(14), T.vertexUv3s && o.enable(15), T.vertexTangents && o.enable(16), T.anisotropy && o.enable(17), M.push(o.mask), o.disableAll(), T.fog && o.enable(0), T.useFog && o.enable(1), T.flatShading && o.enable(2), T.logarithmicDepthBuffer && o.enable(3), T.skinning && o.enable(4), T.morphTargets && o.enable(5), T.morphNormals && o.enable(6), T.morphColors && o.enable(7), T.premultipliedAlpha && o.enable(8), T.shadowMapEnabled && o.enable(9), T.useLegacyLights && o.enable(10), T.doubleSided && o.enable(11), T.flipSided && o.enable(12), T.useDepthPacking && o.enable(13), T.dithering && o.enable(14), T.transmission && o.enable(15), T.sheen && o.enable(16), T.opaque && o.enable(17), T.pointsUvs && o.enable(18), T.decodeVideoTexture && o.enable(19), M.push(o.mask); + } + function y(M) { + let T = m[M.type], O; + if (T) { + let Y = nn[T]; + O = xp.clone(Y.uniforms); + } else O = M.uniforms; + return O; + } + function b(M, T) { + let O; + for(let Y = 0, $ = l.length; Y < $; Y++){ + let U = l[Y]; + if (U.cacheKey === T) { + O = U, ++O.usedTimes; break; } } - return D === void 0 && (D = new hx(s, E, w, r), c.push(D)), D; + return O === void 0 && (O = new b0(s1, T, M, r), l.push(O)), O; } - function k(w) { - if (--w.usedTimes === 0) { - let E = c.indexOf(w); - c[E] = c[c.length - 1], c.pop(), w.destroy(); + function w(M) { + if (--M.usedTimes === 0) { + let T = l.indexOf(M); + l[T] = l[l.length - 1], l.pop(), M.destroy(); } } - function B(w) { - l.remove(w); + function R(M) { + c.remove(M); } - function P() { - l.dispose(); + function I() { + c.dispose(); } return { - getParameters: _, - getProgramCacheKey: y, - getUniforms: L, - acquireProgram: I, - releaseProgram: k, - releaseShaderCache: B, - programs: c, - dispose: P + getParameters: g, + getProgramCacheKey: p, + getUniforms: y, + acquireProgram: b, + releaseProgram: w, + releaseShaderCache: R, + programs: l, + dispose: I }; } -function fx() { - let s = new WeakMap; +function w0() { + let s1 = new WeakMap; function e(r) { - let o = s.get(r); - return o === void 0 && (o = {}, s.set(r, o)), o; + let a = s1.get(r); + return a === void 0 && (a = {}, s1.set(r, a)), a; } function t(r) { - s.delete(r); + s1.delete(r); } - function n(r, o, a) { - s.get(r)[o] = a; + function n(r, a, o) { + s1.get(r)[a] = o; } function i() { - s = new WeakMap; + s1 = new WeakMap; } return { get: e, @@ -9656,44 +10950,44 @@ function fx() { dispose: i }; } -function px(s, e) { - return s.groupOrder !== e.groupOrder ? s.groupOrder - e.groupOrder : s.renderOrder !== e.renderOrder ? s.renderOrder - e.renderOrder : s.material.id !== e.material.id ? s.material.id - e.material.id : s.z !== e.z ? s.z - e.z : s.id - e.id; +function A0(s1, e) { + return s1.groupOrder !== e.groupOrder ? s1.groupOrder - e.groupOrder : s1.renderOrder !== e.renderOrder ? s1.renderOrder - e.renderOrder : s1.material.id !== e.material.id ? s1.material.id - e.material.id : s1.z !== e.z ? s1.z - e.z : s1.id - e.id; } -function Yl(s, e) { - return s.groupOrder !== e.groupOrder ? s.groupOrder - e.groupOrder : s.renderOrder !== e.renderOrder ? s.renderOrder - e.renderOrder : s.z !== e.z ? e.z - s.z : s.id - e.id; +function Rh(s1, e) { + return s1.groupOrder !== e.groupOrder ? s1.groupOrder - e.groupOrder : s1.renderOrder !== e.renderOrder ? s1.renderOrder - e.renderOrder : s1.z !== e.z ? e.z - s1.z : s1.id - e.id; } -function Zl() { - let s = [], e = 0, t = [], n = [], i = []; +function Ch() { + let s1 = [], e = 0, t = [], n = [], i = []; function r() { e = 0, t.length = 0, n.length = 0, i.length = 0; } - function o(u, d, f, m, x, v) { - let g = s[e]; - return g === void 0 ? (g = { + function a(u, d, f, m, _, g) { + let p = s1[e]; + return p === void 0 ? (p = { id: u.id, object: u, geometry: d, material: f, groupOrder: m, renderOrder: u.renderOrder, - z: x, - group: v - }, s[e] = g) : (g.id = u.id, g.object = u, g.geometry = d, g.material = f, g.groupOrder = m, g.renderOrder = u.renderOrder, g.z = x, g.group = v), e++, g; + z: _, + group: g + }, s1[e] = p) : (p.id = u.id, p.object = u, p.geometry = d, p.material = f, p.groupOrder = m, p.renderOrder = u.renderOrder, p.z = _, p.group = g), e++, p; } - function a(u, d, f, m, x, v) { - let g = o(u, d, f, m, x, v); - f.transmission > 0 ? n.push(g) : f.transparent === !0 ? i.push(g) : t.push(g); + function o(u, d, f, m, _, g) { + let p = a(u, d, f, m, _, g); + f.transmission > 0 ? n.push(p) : f.transparent === !0 ? i.push(p) : t.push(p); } - function l(u, d, f, m, x, v) { - let g = o(u, d, f, m, x, v); - f.transmission > 0 ? n.unshift(g) : f.transparent === !0 ? i.unshift(g) : t.unshift(g); + function c(u, d, f, m, _, g) { + let p = a(u, d, f, m, _, g); + f.transmission > 0 ? n.unshift(p) : f.transparent === !0 ? i.unshift(p) : t.unshift(p); } - function c(u, d) { - t.length > 1 && t.sort(u || px), n.length > 1 && n.sort(d || Yl), i.length > 1 && i.sort(d || Yl); + function l(u, d) { + t.length > 1 && t.sort(u || A0), n.length > 1 && n.sort(d || Rh), i.length > 1 && i.sort(d || Rh); } function h() { - for(let u = e, d = s.length; u < d; u++){ - let f = s[u]; + for(let u = e, d = s1.length; u < d; u++){ + let f = s1[u]; if (f.id === null) break; f.id = null, f.object = null, f.geometry = null, f.material = null, f.group = null; } @@ -9703,46 +10997,46 @@ function Zl() { transmissive: n, transparent: i, init: r, - push: a, - unshift: l, + push: o, + unshift: c, finish: h, - sort: c + sort: l }; } -function mx() { - let s = new WeakMap; +function R0() { + let s1 = new WeakMap; function e(n, i) { - let r; - return s.has(n) === !1 ? (r = new Zl, s.set(n, [ - r - ])) : i >= s.get(n).length ? (r = new Zl, s.get(n).push(r)) : r = s.get(n)[i], r; + let r = s1.get(n), a; + return r === void 0 ? (a = new Ch, s1.set(n, [ + a + ])) : i >= r.length ? (a = new Ch, r.push(a)) : a = r[i], a; } function t() { - s = new WeakMap; + s1 = new WeakMap; } return { get: e, dispose: t }; } -function gx() { - let s = {}; +function C0() { + let s1 = {}; return { get: function(e) { - if (s[e.id] !== void 0) return s[e.id]; + if (s1[e.id] !== void 0) return s1[e.id]; let t; switch(e.type){ case "DirectionalLight": t = { - direction: new M, - color: new ae + direction: new A, + color: new pe }; break; case "SpotLight": t = { - position: new M, - direction: new M, - color: new ae, + position: new A, + direction: new A, + color: new pe, distance: 0, coneCos: 0, penumbraCos: 0, @@ -9751,37 +11045,37 @@ function gx() { break; case "PointLight": t = { - position: new M, - color: new ae, + position: new A, + color: new pe, distance: 0, decay: 0 }; break; case "HemisphereLight": t = { - direction: new M, - skyColor: new ae, - groundColor: new ae + direction: new A, + skyColor: new pe, + groundColor: new pe }; break; case "RectAreaLight": t = { - color: new ae, - position: new M, - halfWidth: new M, - halfHeight: new M + color: new pe, + position: new A, + halfWidth: new A, + halfHeight: new A }; break; } - return s[e.id] = t, t; + return s1[e.id] = t, t; } }; } -function xx() { - let s = {}; +function P0() { + let s1 = {}; return { get: function(e) { - if (s[e.id] !== void 0) return s[e.id]; + if (s1[e.id] !== void 0) return s1[e.id]; let t; switch(e.type){ case "DirectionalLight": @@ -9789,7 +11083,7 @@ function xx() { shadowBias: 0, shadowNormalBias: 0, shadowRadius: 1, - shadowMapSize: new X + shadowMapSize: new Z }; break; case "SpotLight": @@ -9797,7 +11091,7 @@ function xx() { shadowBias: 0, shadowNormalBias: 0, shadowRadius: 1, - shadowMapSize: new X + shadowMapSize: new Z }; break; case "PointLight": @@ -9805,22 +11099,22 @@ function xx() { shadowBias: 0, shadowNormalBias: 0, shadowRadius: 1, - shadowMapSize: new X, + shadowMapSize: new Z, shadowCameraNear: 1, shadowCameraFar: 1e3 }; break; } - return s[e.id] = t, t; + return s1[e.id] = t, t; } }; } -var yx = 0; -function vx(s, e) { - return (e.castShadow ? 1 : 0) - (s.castShadow ? 1 : 0); +var L0 = 0; +function I0(s1, e) { + return (e.castShadow ? 2 : 0) - (s1.castShadow ? 2 : 0) + (e.map ? 1 : 0) - (s1.map ? 1 : 0); } -function _x(s, e) { - let t = new gx, n = xx(), i = { +function U0(s1, e) { + let t = new C0, n = P0(), i = { version: 0, hash: { directionalLength: -1, @@ -9830,7 +11124,9 @@ function _x(s, e) { hemiLength: -1, numDirectionalShadows: -1, numPointShadows: -1, - numSpotShadows: -1 + numSpotShadows: -1, + numSpotMaps: -1, + numLightProbes: -1 }, ambient: [ 0, @@ -9843,9 +11139,10 @@ function _x(s, e) { directionalShadowMap: [], directionalShadowMatrix: [], spot: [], + spotLightMap: [], spotShadow: [], spotShadowMap: [], - spotShadowMatrix: [], + spotLightMatrix: [], rectArea: [], rectAreaLTC1: null, rectAreaLTC2: null, @@ -9853,96 +11150,102 @@ function _x(s, e) { pointShadow: [], pointShadowMap: [], pointShadowMatrix: [], - hemi: [] + hemi: [], + numSpotLightShadowsWithMaps: 0, + numLightProbes: 0 }; - for(let h = 0; h < 9; h++)i.probe.push(new M); - let r = new M, o = new pe, a = new pe; - function l(h, u) { + for(let h = 0; h < 9; h++)i.probe.push(new A); + let r = new A, a = new ze, o = new ze; + function c(h, u) { let d = 0, f = 0, m = 0; - for(let k = 0; k < 9; k++)i.probe[k].set(0, 0, 0); - let x = 0, v = 0, g = 0, p = 0, _ = 0, y = 0, b = 0, A = 0; - h.sort(vx); - let L = u !== !0 ? Math.PI : 1; - for(let k = 0, B = h.length; k < B; k++){ - let P = h[k], w = P.color, E = P.intensity, D = P.distance, U = P.shadow && P.shadow.map ? P.shadow.map.texture : null; - if (P.isAmbientLight) d += w.r * E * L, f += w.g * E * L, m += w.b * E * L; - else if (P.isLightProbe) for(let F = 0; F < 9; F++)i.probe[F].addScaledVector(P.sh.coefficients[F], E); - else if (P.isDirectionalLight) { - let F = t.get(P); - if (F.color.copy(P.color).multiplyScalar(P.intensity * L), P.castShadow) { - let O = P.shadow, ne = n.get(P); - ne.shadowBias = O.bias, ne.shadowNormalBias = O.normalBias, ne.shadowRadius = O.radius, ne.shadowMapSize = O.mapSize, i.directionalShadow[x] = ne, i.directionalShadowMap[x] = U, i.directionalShadowMatrix[x] = P.shadow.matrix, y++; + for(let Y = 0; Y < 9; Y++)i.probe[Y].set(0, 0, 0); + let _ = 0, g = 0, p = 0, v = 0, x = 0, y = 0, b = 0, w = 0, R = 0, I = 0, M = 0; + h.sort(I0); + let T = u === !0 ? Math.PI : 1; + for(let Y = 0, $ = h.length; Y < $; Y++){ + let U = h[Y], z = U.color, q = U.intensity, H = U.distance, ne = U.shadow && U.shadow.map ? U.shadow.map.texture : null; + if (U.isAmbientLight) d += z.r * q * T, f += z.g * q * T, m += z.b * q * T; + else if (U.isLightProbe) { + for(let W = 0; W < 9; W++)i.probe[W].addScaledVector(U.sh.coefficients[W], q); + M++; + } else if (U.isDirectionalLight) { + let W = t.get(U); + if (W.color.copy(U.color).multiplyScalar(U.intensity * T), U.castShadow) { + let K = U.shadow, D = n.get(U); + D.shadowBias = K.bias, D.shadowNormalBias = K.normalBias, D.shadowRadius = K.radius, D.shadowMapSize = K.mapSize, i.directionalShadow[_] = D, i.directionalShadowMap[_] = ne, i.directionalShadowMatrix[_] = U.shadow.matrix, y++; } - i.directional[x] = F, x++; - } else if (P.isSpotLight) { - let F = t.get(P); - if (F.position.setFromMatrixPosition(P.matrixWorld), F.color.copy(w).multiplyScalar(E * L), F.distance = D, F.coneCos = Math.cos(P.angle), F.penumbraCos = Math.cos(P.angle * (1 - P.penumbra)), F.decay = P.decay, P.castShadow) { - let O = P.shadow, ne = n.get(P); - ne.shadowBias = O.bias, ne.shadowNormalBias = O.normalBias, ne.shadowRadius = O.radius, ne.shadowMapSize = O.mapSize, i.spotShadow[g] = ne, i.spotShadowMap[g] = U, i.spotShadowMatrix[g] = P.shadow.matrix, A++; + i.directional[_] = W, _++; + } else if (U.isSpotLight) { + let W = t.get(U); + W.position.setFromMatrixPosition(U.matrixWorld), W.color.copy(z).multiplyScalar(q * T), W.distance = H, W.coneCos = Math.cos(U.angle), W.penumbraCos = Math.cos(U.angle * (1 - U.penumbra)), W.decay = U.decay, i.spot[p] = W; + let K = U.shadow; + if (U.map && (i.spotLightMap[R] = U.map, R++, K.updateMatrices(U), U.castShadow && I++), i.spotLightMatrix[p] = K.matrix, U.castShadow) { + let D = n.get(U); + D.shadowBias = K.bias, D.shadowNormalBias = K.normalBias, D.shadowRadius = K.radius, D.shadowMapSize = K.mapSize, i.spotShadow[p] = D, i.spotShadowMap[p] = ne, w++; } - i.spot[g] = F, g++; - } else if (P.isRectAreaLight) { - let F = t.get(P); - F.color.copy(w).multiplyScalar(E), F.halfWidth.set(P.width * .5, 0, 0), F.halfHeight.set(0, P.height * .5, 0), i.rectArea[p] = F, p++; - } else if (P.isPointLight) { - let F = t.get(P); - if (F.color.copy(P.color).multiplyScalar(P.intensity * L), F.distance = P.distance, F.decay = P.decay, P.castShadow) { - let O = P.shadow, ne = n.get(P); - ne.shadowBias = O.bias, ne.shadowNormalBias = O.normalBias, ne.shadowRadius = O.radius, ne.shadowMapSize = O.mapSize, ne.shadowCameraNear = O.camera.near, ne.shadowCameraFar = O.camera.far, i.pointShadow[v] = ne, i.pointShadowMap[v] = U, i.pointShadowMatrix[v] = P.shadow.matrix, b++; + p++; + } else if (U.isRectAreaLight) { + let W = t.get(U); + W.color.copy(z).multiplyScalar(q), W.halfWidth.set(U.width * .5, 0, 0), W.halfHeight.set(0, U.height * .5, 0), i.rectArea[v] = W, v++; + } else if (U.isPointLight) { + let W = t.get(U); + if (W.color.copy(U.color).multiplyScalar(U.intensity * T), W.distance = U.distance, W.decay = U.decay, U.castShadow) { + let K = U.shadow, D = n.get(U); + D.shadowBias = K.bias, D.shadowNormalBias = K.normalBias, D.shadowRadius = K.radius, D.shadowMapSize = K.mapSize, D.shadowCameraNear = K.camera.near, D.shadowCameraFar = K.camera.far, i.pointShadow[g] = D, i.pointShadowMap[g] = ne, i.pointShadowMatrix[g] = U.shadow.matrix, b++; } - i.point[v] = F, v++; - } else if (P.isHemisphereLight) { - let F = t.get(P); - F.skyColor.copy(P.color).multiplyScalar(E * L), F.groundColor.copy(P.groundColor).multiplyScalar(E * L), i.hemi[_] = F, _++; + i.point[g] = W, g++; + } else if (U.isHemisphereLight) { + let W = t.get(U); + W.skyColor.copy(U.color).multiplyScalar(q * T), W.groundColor.copy(U.groundColor).multiplyScalar(q * T), i.hemi[x] = W, x++; } } - p > 0 && (e.isWebGL2 || s.has("OES_texture_float_linear") === !0 ? (i.rectAreaLTC1 = ie.LTC_FLOAT_1, i.rectAreaLTC2 = ie.LTC_FLOAT_2) : s.has("OES_texture_half_float_linear") === !0 ? (i.rectAreaLTC1 = ie.LTC_HALF_1, i.rectAreaLTC2 = ie.LTC_HALF_2) : console.error("THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.")), i.ambient[0] = d, i.ambient[1] = f, i.ambient[2] = m; - let I = i.hash; - (I.directionalLength !== x || I.pointLength !== v || I.spotLength !== g || I.rectAreaLength !== p || I.hemiLength !== _ || I.numDirectionalShadows !== y || I.numPointShadows !== b || I.numSpotShadows !== A) && (i.directional.length = x, i.spot.length = g, i.rectArea.length = p, i.point.length = v, i.hemi.length = _, i.directionalShadow.length = y, i.directionalShadowMap.length = y, i.pointShadow.length = b, i.pointShadowMap.length = b, i.spotShadow.length = A, i.spotShadowMap.length = A, i.directionalShadowMatrix.length = y, i.pointShadowMatrix.length = b, i.spotShadowMatrix.length = A, I.directionalLength = x, I.pointLength = v, I.spotLength = g, I.rectAreaLength = p, I.hemiLength = _, I.numDirectionalShadows = y, I.numPointShadows = b, I.numSpotShadows = A, i.version = yx++); + v > 0 && (e.isWebGL2 || s1.has("OES_texture_float_linear") === !0 ? (i.rectAreaLTC1 = le.LTC_FLOAT_1, i.rectAreaLTC2 = le.LTC_FLOAT_2) : s1.has("OES_texture_half_float_linear") === !0 ? (i.rectAreaLTC1 = le.LTC_HALF_1, i.rectAreaLTC2 = le.LTC_HALF_2) : console.error("THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.")), i.ambient[0] = d, i.ambient[1] = f, i.ambient[2] = m; + let O = i.hash; + (O.directionalLength !== _ || O.pointLength !== g || O.spotLength !== p || O.rectAreaLength !== v || O.hemiLength !== x || O.numDirectionalShadows !== y || O.numPointShadows !== b || O.numSpotShadows !== w || O.numSpotMaps !== R || O.numLightProbes !== M) && (i.directional.length = _, i.spot.length = p, i.rectArea.length = v, i.point.length = g, i.hemi.length = x, i.directionalShadow.length = y, i.directionalShadowMap.length = y, i.pointShadow.length = b, i.pointShadowMap.length = b, i.spotShadow.length = w, i.spotShadowMap.length = w, i.directionalShadowMatrix.length = y, i.pointShadowMatrix.length = b, i.spotLightMatrix.length = w + R - I, i.spotLightMap.length = R, i.numSpotLightShadowsWithMaps = I, i.numLightProbes = M, O.directionalLength = _, O.pointLength = g, O.spotLength = p, O.rectAreaLength = v, O.hemiLength = x, O.numDirectionalShadows = y, O.numPointShadows = b, O.numSpotShadows = w, O.numSpotMaps = R, O.numLightProbes = M, i.version = L0++); } - function c(h, u) { - let d = 0, f = 0, m = 0, x = 0, v = 0, g = u.matrixWorldInverse; - for(let p = 0, _ = h.length; p < _; p++){ - let y = h[p]; + function l(h, u) { + let d = 0, f = 0, m = 0, _ = 0, g = 0, p = u.matrixWorldInverse; + for(let v = 0, x = h.length; v < x; v++){ + let y = h[v]; if (y.isDirectionalLight) { let b = i.directional[d]; - b.direction.setFromMatrixPosition(y.matrixWorld), r.setFromMatrixPosition(y.target.matrixWorld), b.direction.sub(r), b.direction.transformDirection(g), d++; + b.direction.setFromMatrixPosition(y.matrixWorld), r.setFromMatrixPosition(y.target.matrixWorld), b.direction.sub(r), b.direction.transformDirection(p), d++; } else if (y.isSpotLight) { let b = i.spot[m]; - b.position.setFromMatrixPosition(y.matrixWorld), b.position.applyMatrix4(g), b.direction.setFromMatrixPosition(y.matrixWorld), r.setFromMatrixPosition(y.target.matrixWorld), b.direction.sub(r), b.direction.transformDirection(g), m++; + b.position.setFromMatrixPosition(y.matrixWorld), b.position.applyMatrix4(p), b.direction.setFromMatrixPosition(y.matrixWorld), r.setFromMatrixPosition(y.target.matrixWorld), b.direction.sub(r), b.direction.transformDirection(p), m++; } else if (y.isRectAreaLight) { - let b = i.rectArea[x]; - b.position.setFromMatrixPosition(y.matrixWorld), b.position.applyMatrix4(g), a.identity(), o.copy(y.matrixWorld), o.premultiply(g), a.extractRotation(o), b.halfWidth.set(y.width * .5, 0, 0), b.halfHeight.set(0, y.height * .5, 0), b.halfWidth.applyMatrix4(a), b.halfHeight.applyMatrix4(a), x++; + let b = i.rectArea[_]; + b.position.setFromMatrixPosition(y.matrixWorld), b.position.applyMatrix4(p), o.identity(), a.copy(y.matrixWorld), a.premultiply(p), o.extractRotation(a), b.halfWidth.set(y.width * .5, 0, 0), b.halfHeight.set(0, y.height * .5, 0), b.halfWidth.applyMatrix4(o), b.halfHeight.applyMatrix4(o), _++; } else if (y.isPointLight) { let b = i.point[f]; - b.position.setFromMatrixPosition(y.matrixWorld), b.position.applyMatrix4(g), f++; + b.position.setFromMatrixPosition(y.matrixWorld), b.position.applyMatrix4(p), f++; } else if (y.isHemisphereLight) { - let b = i.hemi[v]; - b.direction.setFromMatrixPosition(y.matrixWorld), b.direction.transformDirection(g), b.direction.normalize(), v++; + let b = i.hemi[g]; + b.direction.setFromMatrixPosition(y.matrixWorld), b.direction.transformDirection(p), g++; } } } return { - setup: l, - setupView: c, + setup: c, + setupView: l, state: i }; } -function $l(s, e) { - let t = new _x(s, e), n = [], i = []; +function Ph(s1, e) { + let t = new U0(s1, e), n = [], i = []; function r() { n.length = 0, i.length = 0; } - function o(u) { + function a(u) { n.push(u); } - function a(u) { + function o(u) { i.push(u); } - function l(u) { + function c(u) { t.setup(n, u); } - function c(u) { + function l(u) { t.setupView(n, u); } return { @@ -9952,19 +11255,19 @@ function $l(s, e) { shadowsArray: i, lights: t }, - setupLights: l, - setupLightsView: c, - pushLight: o, - pushShadow: a + setupLights: c, + setupLightsView: l, + pushLight: a, + pushShadow: o }; } -function Mx(s, e) { +function D0(s1, e) { let t = new WeakMap; - function n(r, o = 0) { - let a; - return t.has(r) === !1 ? (a = new $l(s, e), t.set(r, [ - a - ])) : o >= t.get(r).length ? (a = new $l(s, e), t.get(r).push(a)) : a = t.get(r)[o], a; + function n(r, a = 0) { + let o = t.get(r), c; + return o === void 0 ? (c = new Ph(s1, e), t.set(r, [ + c + ])) : a >= o.length ? (c = new Ph(s1, e), o.push(c)) : c = o[a], c; } function i() { t = new WeakMap; @@ -9974,29 +11277,23 @@ function Mx(s, e) { dispose: i }; } -var eo = class extends dt { +var Qr = class extends bt { constructor(e){ - super(); - this.type = "MeshDepthMaterial", this.depthPacking = Nd, this.map = null, this.alphaMap = null, this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.wireframe = !1, this.wireframeLinewidth = 1, this.fog = !1, this.setValues(e); + super(), this.isMeshDepthMaterial = !0, this.type = "MeshDepthMaterial", this.depthPacking = Cf, this.map = null, this.alphaMap = null, this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.wireframe = !1, this.wireframeLinewidth = 1, this.setValues(e); } copy(e) { return super.copy(e), this.depthPacking = e.depthPacking, this.map = e.map, this.alphaMap = e.alphaMap, this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this; } -}; -eo.prototype.isMeshDepthMaterial = !0; -var to = class extends dt { +}, jr = class extends bt { constructor(e){ - super(); - this.type = "MeshDistanceMaterial", this.referencePosition = new M, this.nearDistance = 1, this.farDistance = 1e3, this.map = null, this.alphaMap = null, this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.fog = !1, this.setValues(e); + super(), this.isMeshDistanceMaterial = !0, this.type = "MeshDistanceMaterial", this.map = null, this.alphaMap = null, this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.setValues(e); } copy(e) { - return super.copy(e), this.referencePosition.copy(e.referencePosition), this.nearDistance = e.nearDistance, this.farDistance = e.farDistance, this.map = e.map, this.alphaMap = e.alphaMap, this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this; + return super.copy(e), this.map = e.map, this.alphaMap = e.alphaMap, this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this; } -}; -to.prototype.isMeshDistanceMaterial = !0; -var bx = `void main() { +}, N0 = `void main() { gl_Position = vec4( position, 1.0 ); -}`, wx = `uniform sampler2D shadow_pass; +}`, O0 = `uniform sampler2D shadow_pass; uniform vec2 resolution; uniform float radius; #include @@ -10023,14 +11320,14 @@ void main() { float std_dev = sqrt( squared_mean - mean * mean ); gl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) ); }`; -function yh(s, e, t) { - let n = new Dr, i = new X, r = new X, o = new Ve, a = new eo({ - depthPacking: Bd - }), l = new to, c = {}, h = t.maxTextureSize, u = { - 0: it, - 1: Ai, - 2: Ci - }, d = new sn({ +function F0(s1, e, t) { + let n = new Ps, i = new Z, r = new Z, a = new je, o = new Qr({ + depthPacking: Pf + }), c = new jr, l = {}, h = t.maxTextureSize, u = { + [Bn]: Ft, + [Ft]: Bn, + [gn]: gn + }, d = new jt({ defines: { VSM_SAMPLES: 8 }, @@ -10039,18 +11336,18 @@ function yh(s, e, t) { value: null }, resolution: { - value: new X + value: new Z }, radius: { value: 4 } }, - vertexShader: bx, - fragmentShader: wx + vertexShader: N0, + fragmentShader: O0 }), f = d.clone(); f.defines.HORIZONTAL_PASS = 1; - let m = new _e; - m.setAttribute("position", new Ue(new Float32Array([ + let m = new Ge; + m.setAttribute("position", new et(new Float32Array([ -1, -1, .5, @@ -10061,764 +11358,928 @@ function yh(s, e, t) { 3, .5 ]), 3)); - let x = new st(m, d), v = this; - this.enabled = !1, this.autoUpdate = !0, this.needsUpdate = !1, this.type = Hc, this.render = function(y, b, A) { - if (v.enabled === !1 || v.autoUpdate === !1 && v.needsUpdate === !1 || y.length === 0) return; - let L = s.getRenderTarget(), I = s.getActiveCubeFace(), k = s.getActiveMipmapLevel(), B = s.state; - B.setBlending(vn), B.buffers.color.setClear(1, 1, 1, 1), B.buffers.depth.setTest(!0), B.setScissorTest(!1); - for(let P = 0, w = y.length; P < w; P++){ - let E = y[P], D = E.shadow; - if (D === void 0) { - console.warn("THREE.WebGLShadowMap:", E, "has no shadow."); + let _ = new Mt(m, d), g = this; + this.enabled = !1, this.autoUpdate = !0, this.needsUpdate = !1, this.type = cd; + let p = this.type; + this.render = function(b, w, R) { + if (g.enabled === !1 || g.autoUpdate === !1 && g.needsUpdate === !1 || b.length === 0) return; + let I = s1.getRenderTarget(), M = s1.getActiveCubeFace(), T = s1.getActiveMipmapLevel(), O = s1.state; + O.setBlending(Dn), O.buffers.color.setClear(1, 1, 1, 1), O.buffers.depth.setTest(!0), O.setScissorTest(!1); + let Y = p !== pn && this.type === pn, $ = p === pn && this.type !== pn; + for(let U = 0, z = b.length; U < z; U++){ + let q = b[U], H = q.shadow; + if (H === void 0) { + console.warn("THREE.WebGLShadowMap:", q, "has no shadow."); continue; } - if (D.autoUpdate === !1 && D.needsUpdate === !1) continue; - i.copy(D.mapSize); - let U = D.getFrameExtents(); - if (i.multiply(U), r.copy(D.mapSize), (i.x > h || i.y > h) && (i.x > h && (r.x = Math.floor(h / U.x), i.x = r.x * U.x, D.mapSize.x = r.x), i.y > h && (r.y = Math.floor(h / U.y), i.y = r.y * U.y, D.mapSize.y = r.y)), D.map === null && !D.isPointLightShadow && this.type === ir) { - let O = { - minFilter: tt, - magFilter: tt, - format: ct - }; - D.map = new At(i.x, i.y, O), D.map.texture.name = E.name + ".shadowMap", D.mapPass = new At(i.x, i.y, O), D.camera.updateProjectionMatrix(); - } - if (D.map === null) { - let O = { - minFilter: rt, - magFilter: rt, - format: ct - }; - D.map = new At(i.x, i.y, O), D.map.texture.name = E.name + ".shadowMap", D.camera.updateProjectionMatrix(); + if (H.autoUpdate === !1 && H.needsUpdate === !1) continue; + i.copy(H.mapSize); + let ne = H.getFrameExtents(); + if (i.multiply(ne), r.copy(H.mapSize), (i.x > h || i.y > h) && (i.x > h && (r.x = Math.floor(h / ne.x), i.x = r.x * ne.x, H.mapSize.x = r.x), i.y > h && (r.y = Math.floor(h / ne.y), i.y = r.y * ne.y, H.mapSize.y = r.y)), H.map === null || Y === !0 || $ === !0) { + let K = this.type !== pn ? { + minFilter: pt, + magFilter: pt + } : {}; + H.map !== null && H.map.dispose(), H.map = new qt(i.x, i.y, K), H.map.texture.name = q.name + ".shadowMap", H.camera.updateProjectionMatrix(); } - s.setRenderTarget(D.map), s.clear(); - let F = D.getViewportCount(); - for(let O = 0; O < F; O++){ - let ne = D.getViewport(O); - o.set(r.x * ne.x, r.y * ne.y, r.x * ne.z, r.y * ne.w), B.viewport(o), D.updateMatrices(E, O), n = D.getFrustum(), _(b, A, D.camera, E, this.type); + s1.setRenderTarget(H.map), s1.clear(); + let W = H.getViewportCount(); + for(let K = 0; K < W; K++){ + let D = H.getViewport(K); + a.set(r.x * D.x, r.y * D.y, r.x * D.z, r.y * D.w), O.viewport(a), H.updateMatrices(q, K), n = H.getFrustum(), y(w, R, H.camera, q, this.type); } - !D.isPointLightShadow && this.type === ir && g(D, A), D.needsUpdate = !1; + H.isPointLightShadow !== !0 && this.type === pn && v(H, R), H.needsUpdate = !1; } - v.needsUpdate = !1, s.setRenderTarget(L, I, k); + p = this.type, g.needsUpdate = !1, s1.setRenderTarget(I, M, T); }; - function g(y, b) { - let A = e.update(x); - d.defines.VSM_SAMPLES !== y.blurSamples && (d.defines.VSM_SAMPLES = y.blurSamples, f.defines.VSM_SAMPLES = y.blurSamples, d.needsUpdate = !0, f.needsUpdate = !0), d.uniforms.shadow_pass.value = y.map.texture, d.uniforms.resolution.value = y.mapSize, d.uniforms.radius.value = y.radius, s.setRenderTarget(y.mapPass), s.clear(), s.renderBufferDirect(b, null, A, d, x, null), f.uniforms.shadow_pass.value = y.mapPass.texture, f.uniforms.resolution.value = y.mapSize, f.uniforms.radius.value = y.radius, s.setRenderTarget(y.map), s.clear(), s.renderBufferDirect(b, null, A, f, x, null); - } - function p(y, b, A, L, I, k, B) { - let P = null, w = L.isPointLight === !0 ? y.customDistanceMaterial : y.customDepthMaterial; - if (w !== void 0 ? P = w : P = L.isPointLight === !0 ? l : a, s.localClippingEnabled && A.clipShadows === !0 && A.clippingPlanes.length !== 0 || A.displacementMap && A.displacementScale !== 0 || A.alphaMap && A.alphaTest > 0) { - let E = P.uuid, D = A.uuid, U = c[E]; - U === void 0 && (U = {}, c[E] = U); - let F = U[D]; - F === void 0 && (F = P.clone(), U[D] = F), P = F; - } - return P.visible = A.visible, P.wireframe = A.wireframe, B === ir ? P.side = A.shadowSide !== null ? A.shadowSide : A.side : P.side = A.shadowSide !== null ? A.shadowSide : u[A.side], P.alphaMap = A.alphaMap, P.alphaTest = A.alphaTest, P.clipShadows = A.clipShadows, P.clippingPlanes = A.clippingPlanes, P.clipIntersection = A.clipIntersection, P.displacementMap = A.displacementMap, P.displacementScale = A.displacementScale, P.displacementBias = A.displacementBias, P.wireframeLinewidth = A.wireframeLinewidth, P.linewidth = A.linewidth, L.isPointLight === !0 && P.isMeshDistanceMaterial === !0 && (P.referencePosition.setFromMatrixPosition(L.matrixWorld), P.nearDistance = I, P.farDistance = k), P; - } - function _(y, b, A, L, I) { - if (y.visible === !1) return; - if (y.layers.test(b.layers) && (y.isMesh || y.isLine || y.isPoints) && (y.castShadow || y.receiveShadow && I === ir) && (!y.frustumCulled || n.intersectsObject(y))) { - y.modelViewMatrix.multiplyMatrices(A.matrixWorldInverse, y.matrixWorld); - let P = e.update(y), w = y.material; - if (Array.isArray(w)) { - let E = P.groups; - for(let D = 0, U = E.length; D < U; D++){ - let F = E[D], O = w[F.materialIndex]; - if (O && O.visible) { - let ne = p(y, P, O, L, A.near, A.far, I); - s.renderBufferDirect(A, null, P, ne, y, F); + function v(b, w) { + let R = e.update(_); + d.defines.VSM_SAMPLES !== b.blurSamples && (d.defines.VSM_SAMPLES = b.blurSamples, f.defines.VSM_SAMPLES = b.blurSamples, d.needsUpdate = !0, f.needsUpdate = !0), b.mapPass === null && (b.mapPass = new qt(i.x, i.y)), d.uniforms.shadow_pass.value = b.map.texture, d.uniforms.resolution.value = b.mapSize, d.uniforms.radius.value = b.radius, s1.setRenderTarget(b.mapPass), s1.clear(), s1.renderBufferDirect(w, null, R, d, _, null), f.uniforms.shadow_pass.value = b.mapPass.texture, f.uniforms.resolution.value = b.mapSize, f.uniforms.radius.value = b.radius, s1.setRenderTarget(b.map), s1.clear(), s1.renderBufferDirect(w, null, R, f, _, null); + } + function x(b, w, R, I) { + let M = null, T = R.isPointLight === !0 ? b.customDistanceMaterial : b.customDepthMaterial; + if (T !== void 0) M = T; + else if (M = R.isPointLight === !0 ? c : o, s1.localClippingEnabled && w.clipShadows === !0 && Array.isArray(w.clippingPlanes) && w.clippingPlanes.length !== 0 || w.displacementMap && w.displacementScale !== 0 || w.alphaMap && w.alphaTest > 0 || w.map && w.alphaTest > 0) { + let O = M.uuid, Y = w.uuid, $ = l[O]; + $ === void 0 && ($ = {}, l[O] = $); + let U = $[Y]; + U === void 0 && (U = M.clone(), $[Y] = U), M = U; + } + if (M.visible = w.visible, M.wireframe = w.wireframe, I === pn ? M.side = w.shadowSide !== null ? w.shadowSide : w.side : M.side = w.shadowSide !== null ? w.shadowSide : u[w.side], M.alphaMap = w.alphaMap, M.alphaTest = w.alphaTest, M.map = w.map, M.clipShadows = w.clipShadows, M.clippingPlanes = w.clippingPlanes, M.clipIntersection = w.clipIntersection, M.displacementMap = w.displacementMap, M.displacementScale = w.displacementScale, M.displacementBias = w.displacementBias, M.wireframeLinewidth = w.wireframeLinewidth, M.linewidth = w.linewidth, R.isPointLight === !0 && M.isMeshDistanceMaterial === !0) { + let O = s1.properties.get(M); + O.light = R; + } + return M; + } + function y(b, w, R, I, M) { + if (b.visible === !1) return; + if (b.layers.test(w.layers) && (b.isMesh || b.isLine || b.isPoints) && (b.castShadow || b.receiveShadow && M === pn) && (!b.frustumCulled || n.intersectsObject(b))) { + b.modelViewMatrix.multiplyMatrices(R.matrixWorldInverse, b.matrixWorld); + let Y = e.update(b), $ = b.material; + if (Array.isArray($)) { + let U = Y.groups; + for(let z = 0, q = U.length; z < q; z++){ + let H = U[z], ne = $[H.materialIndex]; + if (ne && ne.visible) { + let W = x(b, ne, I, M); + s1.renderBufferDirect(R, null, Y, W, b, H); } } - } else if (w.visible) { - let E = p(y, P, w, L, A.near, A.far, I); - s.renderBufferDirect(A, null, P, E, y, null); + } else if ($.visible) { + let U = x(b, $, I, M); + s1.renderBufferDirect(R, null, Y, U, b, null); } } - let B = y.children; - for(let P = 0, w = B.length; P < w; P++)_(B[P], b, A, L, I); + let O = b.children; + for(let Y = 0, $ = O.length; Y < $; Y++)y(O[Y], w, R, I, M); } } -function Sx(s, e, t) { +function B0(s1, e, t) { let n = t.isWebGL2; function i() { - let R = !1, ee = new Ve, Q = null, Ee = new Ve(0, 0, 0, 0); + let P = !1, ce = new je, ae = null, ge = new je(0, 0, 0, 0); return { - setMask: function(me) { - Q !== me && !R && (s.colorMask(me, me, me, me), Q = me); + setMask: function(ue) { + ae !== ue && !P && (s1.colorMask(ue, ue, ue, ue), ae = ue); }, - setLocked: function(me) { - R = me; + setLocked: function(ue) { + P = ue; }, - setClear: function(me, Re, oe, Le, Xe) { - Xe === !0 && (me *= Le, Re *= Le, oe *= Le), ee.set(me, Re, oe, Le), Ee.equals(ee) === !1 && (s.clearColor(me, Re, oe, Le), Ee.copy(ee)); + setClear: function(ue, Q, be, Fe, At) { + At === !0 && (ue *= Fe, Q *= Fe, be *= Fe), ce.set(ue, Q, be, Fe), ge.equals(ce) === !1 && (s1.clearColor(ue, Q, be, Fe), ge.copy(ce)); }, reset: function() { - R = !1, Q = null, Ee.set(-1, 0, 0, 0); + P = !1, ae = null, ge.set(-1, 0, 0, 0); } }; } function r() { - let R = !1, ee = null, Q = null, Ee = null; + let P = !1, ce = null, ae = null, ge = null; return { - setTest: function(me) { - me ? le(2929) : fe(2929); + setTest: function(ue) { + ue ? Ee(s1.DEPTH_TEST) : Te(s1.DEPTH_TEST); }, - setMask: function(me) { - ee !== me && !R && (s.depthMask(me), ee = me); + setMask: function(ue) { + ce !== ue && !P && (s1.depthMask(ue), ce = ue); }, - setFunc: function(me) { - if (Q !== me) { - if (me) switch(me){ - case Eu: - s.depthFunc(512); + setFunc: function(ue) { + if (ae !== ue) { + switch(ue){ + case nf: + s1.depthFunc(s1.NEVER); break; - case Au: - s.depthFunc(519); + case sf: + s1.depthFunc(s1.ALWAYS); break; - case Cu: - s.depthFunc(513); + case rf: + s1.depthFunc(s1.LESS); break; - case ea: - s.depthFunc(515); + case uo: + s1.depthFunc(s1.LEQUAL); break; - case Lu: - s.depthFunc(514); + case af: + s1.depthFunc(s1.EQUAL); break; - case Ru: - s.depthFunc(518); + case of: + s1.depthFunc(s1.GEQUAL); break; - case Pu: - s.depthFunc(516); + case cf: + s1.depthFunc(s1.GREATER); break; - case Iu: - s.depthFunc(517); + case lf: + s1.depthFunc(s1.NOTEQUAL); break; default: - s.depthFunc(515); + s1.depthFunc(s1.LEQUAL); } - else s.depthFunc(515); - Q = me; + ae = ue; } }, - setLocked: function(me) { - R = me; + setLocked: function(ue) { + P = ue; }, - setClear: function(me) { - Ee !== me && (s.clearDepth(me), Ee = me); + setClear: function(ue) { + ge !== ue && (s1.clearDepth(ue), ge = ue); }, reset: function() { - R = !1, ee = null, Q = null, Ee = null; + P = !1, ce = null, ae = null, ge = null; } }; } - function o() { - let R = !1, ee = null, Q = null, Ee = null, me = null, Re = null, oe = null, Le = null, Xe = null; + function a() { + let P = !1, ce = null, ae = null, ge = null, ue = null, Q = null, be = null, Fe = null, At = null; return { - setTest: function(We) { - R || (We ? le(2960) : fe(2960)); + setTest: function(tt) { + P || (tt ? Ee(s1.STENCIL_TEST) : Te(s1.STENCIL_TEST)); }, - setMask: function(We) { - ee !== We && !R && (s.stencilMask(We), ee = We); + setMask: function(tt) { + ce !== tt && !P && (s1.stencilMask(tt), ce = tt); }, - setFunc: function(We, Ut, Ot) { - (Q !== We || Ee !== Ut || me !== Ot) && (s.stencilFunc(We, Ut, Ot), Q = We, Ee = Ut, me = Ot); + setFunc: function(tt, tn, Rt) { + (ae !== tt || ge !== tn || ue !== Rt) && (s1.stencilFunc(tt, tn, Rt), ae = tt, ge = tn, ue = Rt); }, - setOp: function(We, Ut, Ot) { - (Re !== We || oe !== Ut || Le !== Ot) && (s.stencilOp(We, Ut, Ot), Re = We, oe = Ut, Le = Ot); + setOp: function(tt, tn, Rt) { + (Q !== tt || be !== tn || Fe !== Rt) && (s1.stencilOp(tt, tn, Rt), Q = tt, be = tn, Fe = Rt); }, - setLocked: function(We) { - R = We; + setLocked: function(tt) { + P = tt; }, - setClear: function(We) { - Xe !== We && (s.clearStencil(We), Xe = We); + setClear: function(tt) { + At !== tt && (s1.clearStencil(tt), At = tt); }, reset: function() { - R = !1, ee = null, Q = null, Ee = null, me = null, Re = null, oe = null, Le = null, Xe = null; + P = !1, ce = null, ae = null, ge = null, ue = null, Q = null, be = null, Fe = null, At = null; } }; } - let a = new i, l = new r, c = new o, h = {}, u = {}, d = null, f = !1, m = null, x = null, v = null, g = null, p = null, _ = null, y = null, b = !1, A = null, L = null, I = null, k = null, B = null, P = s.getParameter(35661), w = !1, E = 0, D = s.getParameter(7938); - D.indexOf("WebGL") !== -1 ? (E = parseFloat(/^WebGL (\d)/.exec(D)[1]), w = E >= 1) : D.indexOf("OpenGL ES") !== -1 && (E = parseFloat(/^OpenGL ES (\d)/.exec(D)[1]), w = E >= 2); - let U = null, F = {}, O = s.getParameter(3088), ne = s.getParameter(2978), ce = new Ve().fromArray(O), V = new Ve().fromArray(ne); - function W(R, ee, Q) { - let Ee = new Uint8Array(4), me = s.createTexture(); - s.bindTexture(R, me), s.texParameteri(R, 10241, 9728), s.texParameteri(R, 10240, 9728); - for(let Re = 0; Re < Q; Re++)s.texImage2D(ee + Re, 0, 6408, 1, 1, 0, 6408, 5121, Ee); - return me; - } - let he = {}; - he[3553] = W(3553, 3553, 1), he[34067] = W(34067, 34069, 6), a.setClear(0, 0, 0, 1), l.setClear(1), c.setClear(0), le(2929), l.setFunc(ea), Oe(!1), G(tl), le(2884), ge(vn); - function le(R) { - h[R] !== !0 && (s.enable(R), h[R] = !0); - } - function fe(R) { - h[R] !== !1 && (s.disable(R), h[R] = !1); - } - function Be(R, ee) { - return u[R] !== ee ? (s.bindFramebuffer(R, ee), u[R] = ee, n && (R === 36009 && (u[36160] = ee), R === 36160 && (u[36009] = ee)), !0) : !1; - } - function Y(R) { - return d !== R ? (s.useProgram(R), d = R, !0) : !1; - } - let Ce = { - [_i]: 32774, - [mu]: 32778, - [gu]: 32779 + let o = new i, c = new r, l = new a, h = new WeakMap, u = new WeakMap, d = {}, f = {}, m = new WeakMap, _ = [], g = null, p = !1, v = null, x = null, y = null, b = null, w = null, R = null, I = null, M = !1, T = null, O = null, Y = null, $ = null, U = null, z = s1.getParameter(s1.MAX_COMBINED_TEXTURE_IMAGE_UNITS), q = !1, H = 0, ne = s1.getParameter(s1.VERSION); + ne.indexOf("WebGL") !== -1 ? (H = parseFloat(/^WebGL (\d)/.exec(ne)[1]), q = H >= 1) : ne.indexOf("OpenGL ES") !== -1 && (H = parseFloat(/^OpenGL ES (\d)/.exec(ne)[1]), q = H >= 2); + let W = null, K = {}, D = s1.getParameter(s1.SCISSOR_BOX), G = s1.getParameter(s1.VIEWPORT), he = new je().fromArray(D), fe = new je().fromArray(G); + function _e(P, ce, ae, ge) { + let ue = new Uint8Array(4), Q = s1.createTexture(); + s1.bindTexture(P, Q), s1.texParameteri(P, s1.TEXTURE_MIN_FILTER, s1.NEAREST), s1.texParameteri(P, s1.TEXTURE_MAG_FILTER, s1.NEAREST); + for(let be = 0; be < ae; be++)n && (P === s1.TEXTURE_3D || P === s1.TEXTURE_2D_ARRAY) ? s1.texImage3D(ce, 0, s1.RGBA, 1, 1, ge, 0, s1.RGBA, s1.UNSIGNED_BYTE, ue) : s1.texImage2D(ce + be, 0, s1.RGBA, 1, 1, 0, s1.RGBA, s1.UNSIGNED_BYTE, ue); + return Q; + } + let we = {}; + we[s1.TEXTURE_2D] = _e(s1.TEXTURE_2D, s1.TEXTURE_2D, 1), we[s1.TEXTURE_CUBE_MAP] = _e(s1.TEXTURE_CUBE_MAP, s1.TEXTURE_CUBE_MAP_POSITIVE_X, 6), n && (we[s1.TEXTURE_2D_ARRAY] = _e(s1.TEXTURE_2D_ARRAY, s1.TEXTURE_2D_ARRAY, 1, 1), we[s1.TEXTURE_3D] = _e(s1.TEXTURE_3D, s1.TEXTURE_3D, 1, 1)), o.setClear(0, 0, 0, 1), c.setClear(1), l.setClear(0), Ee(s1.DEPTH_TEST), c.setFunc(uo), J(!1), Se(rl), Ee(s1.CULL_FACE), X(Dn); + function Ee(P) { + d[P] !== !0 && (s1.enable(P), d[P] = !0); + } + function Te(P) { + d[P] !== !1 && (s1.disable(P), d[P] = !1); + } + function Ye(P, ce) { + return f[P] !== ce ? (s1.bindFramebuffer(P, ce), f[P] = ce, n && (P === s1.DRAW_FRAMEBUFFER && (f[s1.FRAMEBUFFER] = ce), P === s1.FRAMEBUFFER && (f[s1.DRAW_FRAMEBUFFER] = ce)), !0) : !1; + } + function it(P, ce) { + let ae = _, ge = !1; + if (P) if (ae = m.get(ce), ae === void 0 && (ae = [], m.set(ce, ae)), P.isWebGLMultipleRenderTargets) { + let ue = P.texture; + if (ae.length !== ue.length || ae[0] !== s1.COLOR_ATTACHMENT0) { + for(let Q = 0, be = ue.length; Q < be; Q++)ae[Q] = s1.COLOR_ATTACHMENT0 + Q; + ae.length = ue.length, ge = !0; + } + } else ae[0] !== s1.COLOR_ATTACHMENT0 && (ae[0] = s1.COLOR_ATTACHMENT0, ge = !0); + else ae[0] !== s1.BACK && (ae[0] = s1.BACK, ge = !0); + ge && (t.isWebGL2 ? s1.drawBuffers(ae) : e.get("WEBGL_draw_buffers").drawBuffersWEBGL(ae)); + } + function Ce(P) { + return g !== P ? (s1.useProgram(P), g = P, !0) : !1; + } + let L = { + [Bi]: s1.FUNC_ADD, + [Xd]: s1.FUNC_SUBTRACT, + [qd]: s1.FUNC_REVERSE_SUBTRACT }; - if (n) Ce[sl] = 32775, Ce[ol] = 32776; + if (n) L[ll] = s1.MIN, L[hl] = s1.MAX; else { - let R = e.get("EXT_blend_minmax"); - R !== null && (Ce[sl] = R.MIN_EXT, Ce[ol] = R.MAX_EXT); - } - let ye = { - [xu]: 0, - [yu]: 1, - [vu]: 768, - [Gc]: 770, - [Tu]: 776, - [wu]: 774, - [Mu]: 772, - [_u]: 769, - [Vc]: 771, - [Su]: 775, - [bu]: 773 + let P = e.get("EXT_blend_minmax"); + P !== null && (L[ll] = P.MIN_EXT, L[hl] = P.MAX_EXT); + } + let oe = { + [Yd]: s1.ZERO, + [Zd]: s1.ONE, + [Jd]: s1.SRC_COLOR, + [ld]: s1.SRC_ALPHA, + [tf]: s1.SRC_ALPHA_SATURATE, + [jd]: s1.DST_COLOR, + [Kd]: s1.DST_ALPHA, + [$d]: s1.ONE_MINUS_SRC_COLOR, + [hd]: s1.ONE_MINUS_SRC_ALPHA, + [ef]: s1.ONE_MINUS_DST_COLOR, + [Qd]: s1.ONE_MINUS_DST_ALPHA }; - function ge(R, ee, Q, Ee, me, Re, oe, Le) { - if (R === vn) { - f === !0 && (fe(3042), f = !1); + function X(P, ce, ae, ge, ue, Q, be, Fe) { + if (P === Dn) { + p === !0 && (Te(s1.BLEND), p = !1); return; } - if (f === !1 && (le(3042), f = !0), R !== pu) { - if (R !== m || Le !== b) { - if ((x !== _i || p !== _i) && (s.blendEquation(32774), x = _i, p = _i), Le) switch(R){ - case sr: - s.blendFuncSeparate(1, 771, 1, 771); + if (p === !1 && (Ee(s1.BLEND), p = !0), P !== Wd) { + if (P !== v || Fe !== M) { + if ((x !== Bi || w !== Bi) && (s1.blendEquation(s1.FUNC_ADD), x = Bi, w = Bi), Fe) switch(P){ + case Wi: + s1.blendFuncSeparate(s1.ONE, s1.ONE_MINUS_SRC_ALPHA, s1.ONE, s1.ONE_MINUS_SRC_ALPHA); break; - case nl: - s.blendFunc(1, 1); + case al: + s1.blendFunc(s1.ONE, s1.ONE); break; - case il: - s.blendFuncSeparate(0, 0, 769, 771); + case ol: + s1.blendFuncSeparate(s1.ZERO, s1.ONE_MINUS_SRC_COLOR, s1.ZERO, s1.ONE); break; - case rl: - s.blendFuncSeparate(0, 768, 0, 770); + case cl: + s1.blendFuncSeparate(s1.ZERO, s1.SRC_COLOR, s1.ZERO, s1.SRC_ALPHA); break; default: - console.error("THREE.WebGLState: Invalid blending: ", R); + console.error("THREE.WebGLState: Invalid blending: ", P); break; } - else switch(R){ - case sr: - s.blendFuncSeparate(770, 771, 1, 771); + else switch(P){ + case Wi: + s1.blendFuncSeparate(s1.SRC_ALPHA, s1.ONE_MINUS_SRC_ALPHA, s1.ONE, s1.ONE_MINUS_SRC_ALPHA); break; - case nl: - s.blendFunc(770, 1); + case al: + s1.blendFunc(s1.SRC_ALPHA, s1.ONE); break; - case il: - s.blendFunc(0, 769); + case ol: + s1.blendFuncSeparate(s1.ZERO, s1.ONE_MINUS_SRC_COLOR, s1.ZERO, s1.ONE); break; - case rl: - s.blendFunc(0, 768); + case cl: + s1.blendFunc(s1.ZERO, s1.SRC_COLOR); break; default: - console.error("THREE.WebGLState: Invalid blending: ", R); + console.error("THREE.WebGLState: Invalid blending: ", P); break; } - v = null, g = null, _ = null, y = null, m = R, b = Le; + y = null, b = null, R = null, I = null, v = P, M = Fe; } return; } - me = me || ee, Re = Re || Q, oe = oe || Ee, (ee !== x || me !== p) && (s.blendEquationSeparate(Ce[ee], Ce[me]), x = ee, p = me), (Q !== v || Ee !== g || Re !== _ || oe !== y) && (s.blendFuncSeparate(ye[Q], ye[Ee], ye[Re], ye[oe]), v = Q, g = Ee, _ = Re, y = oe), m = R, b = null; + ue = ue || ce, Q = Q || ae, be = be || ge, (ce !== x || ue !== w) && (s1.blendEquationSeparate(L[ce], L[ue]), x = ce, w = ue), (ae !== y || ge !== b || Q !== R || be !== I) && (s1.blendFuncSeparate(oe[ae], oe[ge], oe[Q], oe[be]), y = ae, b = ge, R = Q, I = be), v = P, M = !1; } - function xe(R, ee) { - R.side === Ci ? fe(2884) : le(2884); - let Q = R.side === it; - ee && (Q = !Q), Oe(Q), R.blending === sr && R.transparent === !1 ? ge(vn) : ge(R.blending, R.blendEquation, R.blendSrc, R.blendDst, R.blendEquationAlpha, R.blendSrcAlpha, R.blendDstAlpha, R.premultipliedAlpha), l.setFunc(R.depthFunc), l.setTest(R.depthTest), l.setMask(R.depthWrite), a.setMask(R.colorWrite); - let Ee = R.stencilWrite; - c.setTest(Ee), Ee && (c.setMask(R.stencilWriteMask), c.setFunc(R.stencilFunc, R.stencilRef, R.stencilFuncMask), c.setOp(R.stencilFail, R.stencilZFail, R.stencilZPass)), K(R.polygonOffset, R.polygonOffsetFactor, R.polygonOffsetUnits), R.alphaToCoverage === !0 ? le(32926) : fe(32926); + function ie(P, ce) { + P.side === gn ? Te(s1.CULL_FACE) : Ee(s1.CULL_FACE); + let ae = P.side === Ft; + ce && (ae = !ae), J(ae), P.blending === Wi && P.transparent === !1 ? X(Dn) : X(P.blending, P.blendEquation, P.blendSrc, P.blendDst, P.blendEquationAlpha, P.blendSrcAlpha, P.blendDstAlpha, P.premultipliedAlpha), c.setFunc(P.depthFunc), c.setTest(P.depthTest), c.setMask(P.depthWrite), o.setMask(P.colorWrite); + let ge = P.stencilWrite; + l.setTest(ge), ge && (l.setMask(P.stencilWriteMask), l.setFunc(P.stencilFunc, P.stencilRef, P.stencilFuncMask), l.setOp(P.stencilFail, P.stencilZFail, P.stencilZPass)), ye(P.polygonOffset, P.polygonOffsetFactor, P.polygonOffsetUnits), P.alphaToCoverage === !0 ? Ee(s1.SAMPLE_ALPHA_TO_COVERAGE) : Te(s1.SAMPLE_ALPHA_TO_COVERAGE); } - function Oe(R) { - A !== R && (R ? s.frontFace(2304) : s.frontFace(2305), A = R); + function J(P) { + T !== P && (P ? s1.frontFace(s1.CW) : s1.frontFace(s1.CCW), T = P); } - function G(R) { - R !== uu ? (le(2884), R !== L && (R === tl ? s.cullFace(1029) : R === du ? s.cullFace(1028) : s.cullFace(1032))) : fe(2884), L = R; + function Se(P) { + P !== kd ? (Ee(s1.CULL_FACE), P !== O && (P === rl ? s1.cullFace(s1.BACK) : P === Hd ? s1.cullFace(s1.FRONT) : s1.cullFace(s1.FRONT_AND_BACK))) : Te(s1.CULL_FACE), O = P; } - function j(R) { - R !== I && (w && s.lineWidth(R), I = R); + function me(P) { + P !== Y && (q && s1.lineWidth(P), Y = P); } - function K(R, ee, Q) { - R ? (le(32823), (k !== ee || B !== Q) && (s.polygonOffset(ee, Q), k = ee, B = Q)) : fe(32823); + function ye(P, ce, ae) { + P ? (Ee(s1.POLYGON_OFFSET_FILL), ($ !== ce || U !== ae) && (s1.polygonOffset(ce, ae), $ = ce, U = ae)) : Te(s1.POLYGON_OFFSET_FILL); } - function ue(R) { - R ? le(3089) : fe(3089); + function Ne(P) { + P ? Ee(s1.SCISSOR_TEST) : Te(s1.SCISSOR_TEST); } - function se(R) { - R === void 0 && (R = 33984 + P - 1), U !== R && (s.activeTexture(R), U = R); + function qe(P) { + P === void 0 && (P = s1.TEXTURE0 + z - 1), W !== P && (s1.activeTexture(P), W = P); } - function Se(R, ee) { - U === null && se(); - let Q = F[U]; - Q === void 0 && (Q = { + function rt(P, ce, ae) { + ae === void 0 && (W === null ? ae = s1.TEXTURE0 + z - 1 : ae = W); + let ge = K[ae]; + ge === void 0 && (ge = { type: void 0, texture: void 0 - }, F[U] = Q), (Q.type !== R || Q.texture !== ee) && (s.bindTexture(R, ee || he[R]), Q.type = R, Q.texture = ee); + }, K[ae] = ge), (ge.type !== P || ge.texture !== ce) && (W !== ae && (s1.activeTexture(ae), W = ae), s1.bindTexture(P, ce || we[P]), ge.type = P, ge.texture = ce); } - function Te() { - let R = F[U]; - R !== void 0 && R.type !== void 0 && (s.bindTexture(R.type, null), R.type = void 0, R.texture = void 0); + function C() { + let P = K[W]; + P !== void 0 && P.type !== void 0 && (s1.bindTexture(P.type, null), P.type = void 0, P.texture = void 0); } - function Pe() { + function S() { try { - s.compressedTexImage2D.apply(s, arguments); - } catch (R) { - console.error("THREE.WebGLState:", R); + s1.compressedTexImage2D.apply(s1, arguments); + } catch (P) { + console.error("THREE.WebGLState:", P); } } - function Ye() { + function B() { try { - s.texSubImage2D.apply(s, arguments); - } catch (R) { - console.error("THREE.WebGLState:", R); + s1.compressedTexImage3D.apply(s1, arguments); + } catch (P) { + console.error("THREE.WebGLState:", P); } } - function C() { + function ee() { try { - s.texSubImage3D.apply(s, arguments); - } catch (R) { - console.error("THREE.WebGLState:", R); + s1.texSubImage2D.apply(s1, arguments); + } catch (P) { + console.error("THREE.WebGLState:", P); } } - function T() { + function j() { try { - s.compressedTexSubImage2D.apply(s, arguments); - } catch (R) { - console.error("THREE.WebGLState:", R); + s1.texSubImage3D.apply(s1, arguments); + } catch (P) { + console.error("THREE.WebGLState:", P); } } - function J() { + function te() { try { - s.texStorage2D.apply(s, arguments); - } catch (R) { - console.error("THREE.WebGLState:", R); + s1.compressedTexSubImage2D.apply(s1, arguments); + } catch (P) { + console.error("THREE.WebGLState:", P); } } - function $() { + function Me() { try { - s.texStorage3D.apply(s, arguments); - } catch (R) { - console.error("THREE.WebGLState:", R); + s1.compressedTexSubImage3D.apply(s1, arguments); + } catch (P) { + console.error("THREE.WebGLState:", P); } } function re() { try { - s.texImage2D.apply(s, arguments); - } catch (R) { - console.error("THREE.WebGLState:", R); + s1.texStorage2D.apply(s1, arguments); + } catch (P) { + console.error("THREE.WebGLState:", P); + } + } + function de() { + try { + s1.texStorage3D.apply(s1, arguments); + } catch (P) { + console.error("THREE.WebGLState:", P); } } - function Z() { + function Le() { try { - s.texImage3D.apply(s, arguments); - } catch (R) { - console.error("THREE.WebGLState:", R); + s1.texImage2D.apply(s1, arguments); + } catch (P) { + console.error("THREE.WebGLState:", P); } } - function Me(R) { - ce.equals(R) === !1 && (s.scissor(R.x, R.y, R.z, R.w), ce.copy(R)); + function Ze() { + try { + s1.texImage3D.apply(s1, arguments); + } catch (P) { + console.error("THREE.WebGLState:", P); + } } - function ve(R) { - V.equals(R) === !1 && (s.viewport(R.x, R.y, R.z, R.w), V.copy(R)); + function se(P) { + he.equals(P) === !1 && (s1.scissor(P.x, P.y, P.z, P.w), he.copy(P)); } - function te() { - s.disable(3042), s.disable(2884), s.disable(2929), s.disable(32823), s.disable(3089), s.disable(2960), s.disable(32926), s.blendEquation(32774), s.blendFunc(1, 0), s.blendFuncSeparate(1, 0, 1, 0), s.colorMask(!0, !0, !0, !0), s.clearColor(0, 0, 0, 0), s.depthMask(!0), s.depthFunc(513), s.clearDepth(1), s.stencilMask(4294967295), s.stencilFunc(519, 0, 4294967295), s.stencilOp(7680, 7680, 7680), s.clearStencil(0), s.cullFace(1029), s.frontFace(2305), s.polygonOffset(0, 0), s.activeTexture(33984), s.bindFramebuffer(36160, null), n === !0 && (s.bindFramebuffer(36009, null), s.bindFramebuffer(36008, null)), s.useProgram(null), s.lineWidth(1), s.scissor(0, 0, s.canvas.width, s.canvas.height), s.viewport(0, 0, s.canvas.width, s.canvas.height), h = {}, U = null, F = {}, u = {}, d = null, f = !1, m = null, x = null, v = null, g = null, p = null, _ = null, y = null, b = !1, A = null, L = null, I = null, k = null, B = null, ce.set(0, 0, s.canvas.width, s.canvas.height), V.set(0, 0, s.canvas.width, s.canvas.height), a.reset(), l.reset(), c.reset(); + function $e(P) { + fe.equals(P) === !1 && (s1.viewport(P.x, P.y, P.z, P.w), fe.copy(P)); + } + function Oe(P, ce) { + let ae = u.get(ce); + ae === void 0 && (ae = new WeakMap, u.set(ce, ae)); + let ge = ae.get(P); + ge === void 0 && (ge = s1.getUniformBlockIndex(ce, P.name), ae.set(P, ge)); + } + function Ie(P, ce) { + let ge = u.get(ce).get(P); + h.get(ce) !== ge && (s1.uniformBlockBinding(ce, ge, P.__bindingPointIndex), h.set(ce, ge)); + } + function Re() { + s1.disable(s1.BLEND), s1.disable(s1.CULL_FACE), s1.disable(s1.DEPTH_TEST), s1.disable(s1.POLYGON_OFFSET_FILL), s1.disable(s1.SCISSOR_TEST), s1.disable(s1.STENCIL_TEST), s1.disable(s1.SAMPLE_ALPHA_TO_COVERAGE), s1.blendEquation(s1.FUNC_ADD), s1.blendFunc(s1.ONE, s1.ZERO), s1.blendFuncSeparate(s1.ONE, s1.ZERO, s1.ONE, s1.ZERO), s1.colorMask(!0, !0, !0, !0), s1.clearColor(0, 0, 0, 0), s1.depthMask(!0), s1.depthFunc(s1.LESS), s1.clearDepth(1), s1.stencilMask(4294967295), s1.stencilFunc(s1.ALWAYS, 0, 4294967295), s1.stencilOp(s1.KEEP, s1.KEEP, s1.KEEP), s1.clearStencil(0), s1.cullFace(s1.BACK), s1.frontFace(s1.CCW), s1.polygonOffset(0, 0), s1.activeTexture(s1.TEXTURE0), s1.bindFramebuffer(s1.FRAMEBUFFER, null), n === !0 && (s1.bindFramebuffer(s1.DRAW_FRAMEBUFFER, null), s1.bindFramebuffer(s1.READ_FRAMEBUFFER, null)), s1.useProgram(null), s1.lineWidth(1), s1.scissor(0, 0, s1.canvas.width, s1.canvas.height), s1.viewport(0, 0, s1.canvas.width, s1.canvas.height), d = {}, W = null, K = {}, f = {}, m = new WeakMap, _ = [], g = null, p = !1, v = null, x = null, y = null, b = null, w = null, R = null, I = null, M = !1, T = null, O = null, Y = null, $ = null, U = null, he.set(0, 0, s1.canvas.width, s1.canvas.height), fe.set(0, 0, s1.canvas.width, s1.canvas.height), o.reset(), c.reset(), l.reset(); } return { buffers: { - color: a, - depth: l, - stencil: c + color: o, + depth: c, + stencil: l }, - enable: le, - disable: fe, - bindFramebuffer: Be, - useProgram: Y, - setBlending: ge, - setMaterial: xe, - setFlipSided: Oe, - setCullFace: G, - setLineWidth: j, - setPolygonOffset: K, - setScissorTest: ue, - activeTexture: se, - bindTexture: Se, - unbindTexture: Te, - compressedTexImage2D: Pe, - texImage2D: re, - texImage3D: Z, - texStorage2D: J, - texStorage3D: $, - texSubImage2D: Ye, - texSubImage3D: C, - compressedTexSubImage2D: T, - scissor: Me, - viewport: ve, - reset: te + enable: Ee, + disable: Te, + bindFramebuffer: Ye, + drawBuffers: it, + useProgram: Ce, + setBlending: X, + setMaterial: ie, + setFlipSided: J, + setCullFace: Se, + setLineWidth: me, + setPolygonOffset: ye, + setScissorTest: Ne, + activeTexture: qe, + bindTexture: rt, + unbindTexture: C, + compressedTexImage2D: S, + compressedTexImage3D: B, + texImage2D: Le, + texImage3D: Ze, + updateUBOMapping: Oe, + uniformBlockBinding: Ie, + texStorage2D: re, + texStorage3D: de, + texSubImage2D: ee, + texSubImage3D: j, + compressedTexSubImage2D: te, + compressedTexSubImage3D: Me, + scissor: se, + viewport: $e, + reset: Re }; } -function Tx(s, e, t, n, i, r, o) { - let a = i.isWebGL2, l = i.maxTextures, c = i.maxCubemapSize, h = i.maxTextureSize, u = i.maxSamples, f = e.has("WEBGL_multisampled_render_to_texture") ? e.get("WEBGL_multisampled_render_to_texture") : void 0, m = new WeakMap, x, v = !1; +function z0(s1, e, t, n, i, r, a) { + let o = i.isWebGL2, c = i.maxTextures, l = i.maxCubemapSize, h = i.maxTextureSize, u = i.maxSamples, d = e.has("WEBGL_multisampled_render_to_texture") ? e.get("WEBGL_multisampled_render_to_texture") : null, f = typeof navigator > "u" ? !1 : /OculusBrowser/g.test(navigator.userAgent), m = new WeakMap, _, g = new WeakMap, p = !1; try { - v = typeof OffscreenCanvas < "u" && new OffscreenCanvas(1, 1).getContext("2d") !== null; + p = typeof OffscreenCanvas < "u" && new OffscreenCanvas(1, 1).getContext("2d") !== null; } catch {} - function g(C, T) { - return v ? new OffscreenCanvas(C, T) : qs("canvas"); - } - function p(C, T, J, $) { - let re = 1; - if ((C.width > $ || C.height > $) && (re = $ / Math.max(C.width, C.height)), re < 1 || T === !0) if (typeof HTMLImageElement < "u" && C instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && C instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && C instanceof ImageBitmap) { - let Z = T ? Jc : Math.floor, Me = Z(re * C.width), ve = Z(re * C.height); - x === void 0 && (x = g(Me, ve)); - let te = J ? g(Me, ve) : x; - return te.width = Me, te.height = ve, te.getContext("2d").drawImage(C, 0, 0, Me, ve), console.warn("THREE.WebGLRenderer: Texture has been resized from (" + C.width + "x" + C.height + ") to (" + Me + "x" + ve + ")."), te; + function v(C, S) { + return p ? new OffscreenCanvas(C, S) : ws("canvas"); + } + function x(C, S, B, ee) { + let j = 1; + if ((C.width > ee || C.height > ee) && (j = ee / Math.max(C.width, C.height)), j < 1 || S === !0) if (typeof HTMLImageElement < "u" && C instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && C instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && C instanceof ImageBitmap) { + let te = S ? Wr : Math.floor, Me = te(j * C.width), re = te(j * C.height); + _ === void 0 && (_ = v(Me, re)); + let de = B ? v(Me, re) : _; + return de.width = Me, de.height = re, de.getContext("2d").drawImage(C, 0, 0, Me, re), console.warn("THREE.WebGLRenderer: Texture has been resized from (" + C.width + "x" + C.height + ") to (" + Me + "x" + re + ")."), de; } else return "data" in C && console.warn("THREE.WebGLRenderer: Image in DataTexture is too big (" + C.width + "x" + C.height + ")."), C; return C; } - function _(C) { - return ia(C.width) && ia(C.height); - } function y(C) { - return a ? !1 : C.wrapS !== vt || C.wrapT !== vt || C.minFilter !== rt && C.minFilter !== tt; + return mo(C.width) && mo(C.height); } - function b(C, T) { - return C.generateMipmaps && T && C.minFilter !== rt && C.minFilter !== tt; + function b(C) { + return o ? !1 : C.wrapS !== It || C.wrapT !== It || C.minFilter !== pt && C.minFilter !== mt; } - function A(C) { - s.generateMipmap(C); + function w(C, S) { + return C.generateMipmaps && S && C.minFilter !== pt && C.minFilter !== mt; } - function L(C, T, J, $) { - if (a === !1) return T; + function R(C) { + s1.generateMipmap(C); + } + function I(C, S, B, ee, j = !1) { + if (o === !1) return S; if (C !== null) { - if (s[C] !== void 0) return s[C]; + if (s1[C] !== void 0) return s1[C]; console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '" + C + "'"); } - let re = T; - return T === 6403 && (J === 5126 && (re = 33326), J === 5131 && (re = 33325), J === 5121 && (re = 33321)), T === 6407 && (J === 5126 && (re = 34837), J === 5131 && (re = 34843), J === 5121 && (re = 32849)), T === 6408 && (J === 5126 && (re = 34836), J === 5131 && (re = 34842), J === 5121 && (re = $ === Oi ? 35907 : 32856)), (re === 33325 || re === 33326 || re === 34842 || re === 34836) && e.get("EXT_color_buffer_float"), re; - } - function I(C, T, J) { - return b(C, J) === !0 || C.isFramebufferTexture && C.minFilter !== rt && C.minFilter !== tt ? Math.log2(Math.max(T.width, T.height)) + 1 : C.mipmaps !== void 0 && C.mipmaps.length > 0 ? C.mipmaps.length : C.isCompressedTexture && Array.isArray(C.image) ? T.mipmaps.length : 1; + let te = S; + if (S === s1.RED && (B === s1.FLOAT && (te = s1.R32F), B === s1.HALF_FLOAT && (te = s1.R16F), B === s1.UNSIGNED_BYTE && (te = s1.R8)), S === s1.RED_INTEGER && (B === s1.UNSIGNED_BYTE && (te = s1.R8UI), B === s1.UNSIGNED_SHORT && (te = s1.R16UI), B === s1.UNSIGNED_INT && (te = s1.R32UI), B === s1.BYTE && (te = s1.R8I), B === s1.SHORT && (te = s1.R16I), B === s1.INT && (te = s1.R32I)), S === s1.RG && (B === s1.FLOAT && (te = s1.RG32F), B === s1.HALF_FLOAT && (te = s1.RG16F), B === s1.UNSIGNED_BYTE && (te = s1.RG8)), S === s1.RGBA) { + let Me = j ? zr : Qe.getTransfer(ee); + B === s1.FLOAT && (te = s1.RGBA32F), B === s1.HALF_FLOAT && (te = s1.RGBA16F), B === s1.UNSIGNED_BYTE && (te = Me === nt ? s1.SRGB8_ALPHA8 : s1.RGBA8), B === s1.UNSIGNED_SHORT_4_4_4_4 && (te = s1.RGBA4), B === s1.UNSIGNED_SHORT_5_5_5_1 && (te = s1.RGB5_A1); + } + return (te === s1.R16F || te === s1.R32F || te === s1.RG16F || te === s1.RG32F || te === s1.RGBA16F || te === s1.RGBA32F) && e.get("EXT_color_buffer_float"), te; } - function k(C) { - return C === rt || C === ta || C === na ? 9728 : 9729; + function M(C, S, B) { + return w(C, B) === !0 || C.isFramebufferTexture && C.minFilter !== pt && C.minFilter !== mt ? Math.log2(Math.max(S.width, S.height)) + 1 : C.mipmaps !== void 0 && C.mipmaps.length > 0 ? C.mipmaps.length : C.isCompressedTexture && Array.isArray(C.image) ? S.mipmaps.length : 1; } - function B(C) { - let T = C.target; - T.removeEventListener("dispose", B), w(T), T.isVideoTexture && m.delete(T), o.memory.textures--; + function T(C) { + return C === pt || C === fo || C === Lr ? s1.NEAREST : s1.LINEAR; } - function P(C) { - let T = C.target; - T.removeEventListener("dispose", P), E(T); + function O(C) { + let S = C.target; + S.removeEventListener("dispose", O), $(S), S.isVideoTexture && m.delete(S); } - function w(C) { - let T = n.get(C); - T.__webglInit !== void 0 && (s.deleteTexture(T.__webglTexture), n.remove(C)); + function Y(C) { + let S = C.target; + S.removeEventListener("dispose", Y), z(S); } - function E(C) { - let T = C.texture, J = n.get(C), $ = n.get(T); - if (!!C) { - if ($.__webglTexture !== void 0 && (s.deleteTexture($.__webglTexture), o.memory.textures--), C.depthTexture && C.depthTexture.dispose(), C.isWebGLCubeRenderTarget) for(let re = 0; re < 6; re++)s.deleteFramebuffer(J.__webglFramebuffer[re]), J.__webglDepthbuffer && s.deleteRenderbuffer(J.__webglDepthbuffer[re]); - else s.deleteFramebuffer(J.__webglFramebuffer), J.__webglDepthbuffer && s.deleteRenderbuffer(J.__webglDepthbuffer), J.__webglMultisampledFramebuffer && s.deleteFramebuffer(J.__webglMultisampledFramebuffer), J.__webglColorRenderbuffer && s.deleteRenderbuffer(J.__webglColorRenderbuffer), J.__webglDepthRenderbuffer && s.deleteRenderbuffer(J.__webglDepthRenderbuffer); - if (C.isWebGLMultipleRenderTargets) for(let re = 0, Z = T.length; re < Z; re++){ - let Me = n.get(T[re]); - Me.__webglTexture && (s.deleteTexture(Me.__webglTexture), o.memory.textures--), n.remove(T[re]); - } - n.remove(T), n.remove(C); + function $(C) { + let S = n.get(C); + if (S.__webglInit === void 0) return; + let B = C.source, ee = g.get(B); + if (ee) { + let j = ee[S.__cacheKey]; + j.usedTimes--, j.usedTimes === 0 && U(C), Object.keys(ee).length === 0 && g.delete(B); } + n.remove(C); } - let D = 0; - function U() { - D = 0; + function U(C) { + let S = n.get(C); + s1.deleteTexture(S.__webglTexture); + let B = C.source, ee = g.get(B); + delete ee[S.__cacheKey], a.memory.textures--; } - function F() { - let C = D; - return C >= l && console.warn("THREE.WebGLTextures: Trying to use " + C + " texture units while this GPU supports only " + l), D += 1, C; - } - function O(C, T) { - let J = n.get(C); - if (C.isVideoTexture && se(C), C.version > 0 && J.__version !== C.version) { - let $ = C.image; - if ($ === void 0) console.warn("THREE.WebGLRenderer: Texture marked for update but image is undefined"); - else if ($.complete === !1) console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete"); + function z(C) { + let S = C.texture, B = n.get(C), ee = n.get(S); + if (ee.__webglTexture !== void 0 && (s1.deleteTexture(ee.__webglTexture), a.memory.textures--), C.depthTexture && C.depthTexture.dispose(), C.isWebGLCubeRenderTarget) for(let j = 0; j < 6; j++){ + if (Array.isArray(B.__webglFramebuffer[j])) for(let te = 0; te < B.__webglFramebuffer[j].length; te++)s1.deleteFramebuffer(B.__webglFramebuffer[j][te]); + else s1.deleteFramebuffer(B.__webglFramebuffer[j]); + B.__webglDepthbuffer && s1.deleteRenderbuffer(B.__webglDepthbuffer[j]); + } + else { + if (Array.isArray(B.__webglFramebuffer)) for(let j = 0; j < B.__webglFramebuffer.length; j++)s1.deleteFramebuffer(B.__webglFramebuffer[j]); + else s1.deleteFramebuffer(B.__webglFramebuffer); + if (B.__webglDepthbuffer && s1.deleteRenderbuffer(B.__webglDepthbuffer), B.__webglMultisampledFramebuffer && s1.deleteFramebuffer(B.__webglMultisampledFramebuffer), B.__webglColorRenderbuffer) for(let j = 0; j < B.__webglColorRenderbuffer.length; j++)B.__webglColorRenderbuffer[j] && s1.deleteRenderbuffer(B.__webglColorRenderbuffer[j]); + B.__webglDepthRenderbuffer && s1.deleteRenderbuffer(B.__webglDepthRenderbuffer); + } + if (C.isWebGLMultipleRenderTargets) for(let j = 0, te = S.length; j < te; j++){ + let Me = n.get(S[j]); + Me.__webglTexture && (s1.deleteTexture(Me.__webglTexture), a.memory.textures--), n.remove(S[j]); + } + n.remove(S), n.remove(C); + } + let q = 0; + function H() { + q = 0; + } + function ne() { + let C = q; + return C >= c && console.warn("THREE.WebGLTextures: Trying to use " + C + " texture units while this GPU supports only " + c), q += 1, C; + } + function W(C) { + let S = []; + return S.push(C.wrapS), S.push(C.wrapT), S.push(C.wrapR || 0), S.push(C.magFilter), S.push(C.minFilter), S.push(C.anisotropy), S.push(C.internalFormat), S.push(C.format), S.push(C.type), S.push(C.generateMipmaps), S.push(C.premultiplyAlpha), S.push(C.flipY), S.push(C.unpackAlignment), S.push(C.colorSpace), S.join(); + } + function K(C, S) { + let B = n.get(C); + if (C.isVideoTexture && qe(C), C.isRenderTargetTexture === !1 && C.version > 0 && B.__version !== C.version) { + let ee = C.image; + if (ee === null) console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found."); + else if (ee.complete === !1) console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete"); else { - Be(J, C, T); + Ye(B, C, S); return; } } - t.activeTexture(33984 + T), t.bindTexture(3553, J.__webglTexture); + t.bindTexture(s1.TEXTURE_2D, B.__webglTexture, s1.TEXTURE0 + S); } - function ne(C, T) { - let J = n.get(C); - if (C.version > 0 && J.__version !== C.version) { - Be(J, C, T); + function D(C, S) { + let B = n.get(C); + if (C.version > 0 && B.__version !== C.version) { + Ye(B, C, S); return; } - t.activeTexture(33984 + T), t.bindTexture(35866, J.__webglTexture); + t.bindTexture(s1.TEXTURE_2D_ARRAY, B.__webglTexture, s1.TEXTURE0 + S); } - function ce(C, T) { - let J = n.get(C); - if (C.version > 0 && J.__version !== C.version) { - Be(J, C, T); + function G(C, S) { + let B = n.get(C); + if (C.version > 0 && B.__version !== C.version) { + Ye(B, C, S); return; } - t.activeTexture(33984 + T), t.bindTexture(32879, J.__webglTexture); + t.bindTexture(s1.TEXTURE_3D, B.__webglTexture, s1.TEXTURE0 + S); } - function V(C, T) { - let J = n.get(C); - if (C.version > 0 && J.__version !== C.version) { - Y(J, C, T); + function he(C, S) { + let B = n.get(C); + if (C.version > 0 && B.__version !== C.version) { + it(B, C, S); return; } - t.activeTexture(33984 + T), t.bindTexture(34067, J.__webglTexture); - } - let W = { - [Ns]: 10497, - [vt]: 33071, - [Bs]: 33648 - }, he = { - [rt]: 9728, - [ta]: 9984, - [na]: 9986, - [tt]: 9729, - [Wc]: 9985, - [Ui]: 9987 + t.bindTexture(s1.TEXTURE_CUBE_MAP, B.__webglTexture, s1.TEXTURE0 + S); + } + let fe = { + [Dr]: s1.REPEAT, + [It]: s1.CLAMP_TO_EDGE, + [Nr]: s1.MIRRORED_REPEAT + }, _e = { + [pt]: s1.NEAREST, + [fo]: s1.NEAREST_MIPMAP_NEAREST, + [Lr]: s1.NEAREST_MIPMAP_LINEAR, + [mt]: s1.LINEAR, + [ud]: s1.LINEAR_MIPMAP_NEAREST, + [li]: s1.LINEAR_MIPMAP_LINEAR + }, we = { + [Uf]: s1.NEVER, + [Vf]: s1.ALWAYS, + [Df]: s1.LESS, + [Of]: s1.LEQUAL, + [Nf]: s1.EQUAL, + [zf]: s1.GEQUAL, + [Ff]: s1.GREATER, + [Bf]: s1.NOTEQUAL }; - function le(C, T, J) { - if (J ? (s.texParameteri(C, 10242, W[T.wrapS]), s.texParameteri(C, 10243, W[T.wrapT]), (C === 32879 || C === 35866) && s.texParameteri(C, 32882, W[T.wrapR]), s.texParameteri(C, 10240, he[T.magFilter]), s.texParameteri(C, 10241, he[T.minFilter])) : (s.texParameteri(C, 10242, 33071), s.texParameteri(C, 10243, 33071), (C === 32879 || C === 35866) && s.texParameteri(C, 32882, 33071), (T.wrapS !== vt || T.wrapT !== vt) && console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping."), s.texParameteri(C, 10240, k(T.magFilter)), s.texParameteri(C, 10241, k(T.minFilter)), T.minFilter !== rt && T.minFilter !== tt && console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.")), e.has("EXT_texture_filter_anisotropic") === !0) { - let $ = e.get("EXT_texture_filter_anisotropic"); - if (T.type === nn && e.has("OES_texture_float_linear") === !1 || a === !1 && T.type === kn && e.has("OES_texture_half_float_linear") === !1) return; - (T.anisotropy > 1 || n.get(T).__currentAnisotropy) && (s.texParameterf(C, $.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(T.anisotropy, i.getMaxAnisotropy())), n.get(T).__currentAnisotropy = T.anisotropy); - } - } - function fe(C, T) { - C.__webglInit === void 0 && (C.__webglInit = !0, T.addEventListener("dispose", B), C.__webglTexture = s.createTexture(), o.memory.textures++); - } - function Be(C, T, J) { - let $ = 3553; - T.isDataTexture2DArray && ($ = 35866), T.isDataTexture3D && ($ = 32879), fe(C, T), t.activeTexture(33984 + J), t.bindTexture($, C.__webglTexture), s.pixelStorei(37440, T.flipY), s.pixelStorei(37441, T.premultiplyAlpha), s.pixelStorei(3317, T.unpackAlignment), s.pixelStorei(37443, 0); - let re = y(T) && _(T.image) === !1, Z = p(T.image, re, !1, h), Me = _(Z) || a, ve = r.convert(T.format), te = r.convert(T.type), R = L(T.internalFormat, ve, te, T.encoding); - le($, T, Me); - let ee, Q = T.mipmaps, Ee = a && T.isVideoTexture !== !0, me = C.__version === void 0, Re = I(T, Z, Me); - if (T.isDepthTexture) R = 6402, a ? T.type === nn ? R = 36012 : T.type === Ps ? R = 33190 : T.type === Ti ? R = 35056 : R = 33189 : T.type === nn && console.error("WebGLRenderer: Floating point depth texture requires WebGL2."), T.format === Vn && R === 6402 && T.type !== cr && T.type !== Ps && (console.warn("THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture."), T.type = cr, te = r.convert(T.type)), T.format === Li && R === 6402 && (R = 34041, T.type !== Ti && (console.warn("THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture."), T.type = Ti, te = r.convert(T.type))), Ee && me ? t.texStorage2D(3553, 1, R, Z.width, Z.height) : t.texImage2D(3553, 0, R, Z.width, Z.height, 0, ve, te, null); - else if (T.isDataTexture) if (Q.length > 0 && Me) { - Ee && me && t.texStorage2D(3553, Re, R, Q[0].width, Q[0].height); - for(let oe = 0, Le = Q.length; oe < Le; oe++)ee = Q[oe], Ee ? t.texSubImage2D(3553, 0, 0, 0, ee.width, ee.height, ve, te, ee.data) : t.texImage2D(3553, oe, R, ee.width, ee.height, 0, ve, te, ee.data); - T.generateMipmaps = !1; - } else Ee ? (me && t.texStorage2D(3553, Re, R, Z.width, Z.height), t.texSubImage2D(3553, 0, 0, 0, Z.width, Z.height, ve, te, Z.data)) : t.texImage2D(3553, 0, R, Z.width, Z.height, 0, ve, te, Z.data); - else if (T.isCompressedTexture) { - Ee && me && t.texStorage2D(3553, Re, R, Q[0].width, Q[0].height); - for(let oe = 0, Le = Q.length; oe < Le; oe++)ee = Q[oe], T.format !== ct && T.format !== Gn ? ve !== null ? Ee ? t.compressedTexSubImage2D(3553, oe, 0, 0, ee.width, ee.height, ve, ee.data) : t.compressedTexImage2D(3553, oe, R, ee.width, ee.height, 0, ee.data) : console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()") : Ee ? t.texSubImage2D(3553, oe, 0, 0, ee.width, ee.height, ve, te, ee.data) : t.texImage2D(3553, oe, R, ee.width, ee.height, 0, ve, te, ee.data); - } else if (T.isDataTexture2DArray) Ee ? (me && t.texStorage3D(35866, Re, R, Z.width, Z.height, Z.depth), t.texSubImage3D(35866, 0, 0, 0, 0, Z.width, Z.height, Z.depth, ve, te, Z.data)) : t.texImage3D(35866, 0, R, Z.width, Z.height, Z.depth, 0, ve, te, Z.data); - else if (T.isDataTexture3D) Ee ? (me && t.texStorage3D(32879, Re, R, Z.width, Z.height, Z.depth), t.texSubImage3D(32879, 0, 0, 0, 0, Z.width, Z.height, Z.depth, ve, te, Z.data)) : t.texImage3D(32879, 0, R, Z.width, Z.height, Z.depth, 0, ve, te, Z.data); - else if (T.isFramebufferTexture) Ee && me ? t.texStorage2D(3553, Re, R, Z.width, Z.height) : t.texImage2D(3553, 0, R, Z.width, Z.height, 0, ve, te, null); - else if (Q.length > 0 && Me) { - Ee && me && t.texStorage2D(3553, Re, R, Q[0].width, Q[0].height); - for(let oe = 0, Le = Q.length; oe < Le; oe++)ee = Q[oe], Ee ? t.texSubImage2D(3553, oe, 0, 0, ve, te, ee) : t.texImage2D(3553, oe, R, ve, te, ee); - T.generateMipmaps = !1; - } else Ee ? (me && t.texStorage2D(3553, Re, R, Z.width, Z.height), t.texSubImage2D(3553, 0, 0, 0, ve, te, Z)) : t.texImage2D(3553, 0, R, ve, te, Z); - b(T, Me) && A($), C.__version = T.version, T.onUpdate && T.onUpdate(T); - } - function Y(C, T, J) { - if (T.image.length !== 6) return; - fe(C, T), t.activeTexture(33984 + J), t.bindTexture(34067, C.__webglTexture), s.pixelStorei(37440, T.flipY), s.pixelStorei(37441, T.premultiplyAlpha), s.pixelStorei(3317, T.unpackAlignment), s.pixelStorei(37443, 0); - let $ = T && (T.isCompressedTexture || T.image[0].isCompressedTexture), re = T.image[0] && T.image[0].isDataTexture, Z = []; - for(let oe = 0; oe < 6; oe++)!$ && !re ? Z[oe] = p(T.image[oe], !1, !0, c) : Z[oe] = re ? T.image[oe].image : T.image[oe]; - let Me = Z[0], ve = _(Me) || a, te = r.convert(T.format), R = r.convert(T.type), ee = L(T.internalFormat, te, R, T.encoding), Q = a && T.isVideoTexture !== !0, Ee = C.__version === void 0, me = I(T, Me, ve); - le(34067, T, ve); - let Re; - if ($) { - Q && Ee && t.texStorage2D(34067, me, ee, Me.width, Me.height); - for(let oe = 0; oe < 6; oe++){ - Re = Z[oe].mipmaps; - for(let Le = 0; Le < Re.length; Le++){ - let Xe = Re[Le]; - T.format !== ct && T.format !== Gn ? te !== null ? Q ? t.compressedTexSubImage2D(34069 + oe, Le, 0, 0, Xe.width, Xe.height, te, Xe.data) : t.compressedTexImage2D(34069 + oe, Le, ee, Xe.width, Xe.height, 0, Xe.data) : console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()") : Q ? t.texSubImage2D(34069 + oe, Le, 0, 0, Xe.width, Xe.height, te, R, Xe.data) : t.texImage2D(34069 + oe, Le, ee, Xe.width, Xe.height, 0, te, R, Xe.data); - } + function Ee(C, S, B) { + if (B ? (s1.texParameteri(C, s1.TEXTURE_WRAP_S, fe[S.wrapS]), s1.texParameteri(C, s1.TEXTURE_WRAP_T, fe[S.wrapT]), (C === s1.TEXTURE_3D || C === s1.TEXTURE_2D_ARRAY) && s1.texParameteri(C, s1.TEXTURE_WRAP_R, fe[S.wrapR]), s1.texParameteri(C, s1.TEXTURE_MAG_FILTER, _e[S.magFilter]), s1.texParameteri(C, s1.TEXTURE_MIN_FILTER, _e[S.minFilter])) : (s1.texParameteri(C, s1.TEXTURE_WRAP_S, s1.CLAMP_TO_EDGE), s1.texParameteri(C, s1.TEXTURE_WRAP_T, s1.CLAMP_TO_EDGE), (C === s1.TEXTURE_3D || C === s1.TEXTURE_2D_ARRAY) && s1.texParameteri(C, s1.TEXTURE_WRAP_R, s1.CLAMP_TO_EDGE), (S.wrapS !== It || S.wrapT !== It) && console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping."), s1.texParameteri(C, s1.TEXTURE_MAG_FILTER, T(S.magFilter)), s1.texParameteri(C, s1.TEXTURE_MIN_FILTER, T(S.minFilter)), S.minFilter !== pt && S.minFilter !== mt && console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.")), S.compareFunction && (s1.texParameteri(C, s1.TEXTURE_COMPARE_MODE, s1.COMPARE_REF_TO_TEXTURE), s1.texParameteri(C, s1.TEXTURE_COMPARE_FUNC, we[S.compareFunction])), e.has("EXT_texture_filter_anisotropic") === !0) { + let ee = e.get("EXT_texture_filter_anisotropic"); + if (S.magFilter === pt || S.minFilter !== Lr && S.minFilter !== li || S.type === xn && e.has("OES_texture_float_linear") === !1 || o === !1 && S.type === Ts && e.has("OES_texture_half_float_linear") === !1) return; + (S.anisotropy > 1 || n.get(S).__currentAnisotropy) && (s1.texParameterf(C, ee.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(S.anisotropy, i.getMaxAnisotropy())), n.get(S).__currentAnisotropy = S.anisotropy); + } + } + function Te(C, S) { + let B = !1; + C.__webglInit === void 0 && (C.__webglInit = !0, S.addEventListener("dispose", O)); + let ee = S.source, j = g.get(ee); + j === void 0 && (j = {}, g.set(ee, j)); + let te = W(S); + if (te !== C.__cacheKey) { + j[te] === void 0 && (j[te] = { + texture: s1.createTexture(), + usedTimes: 0 + }, a.memory.textures++, B = !0), j[te].usedTimes++; + let Me = j[C.__cacheKey]; + Me !== void 0 && (j[C.__cacheKey].usedTimes--, Me.usedTimes === 0 && U(S)), C.__cacheKey = te, C.__webglTexture = j[te].texture; + } + return B; + } + function Ye(C, S, B) { + let ee = s1.TEXTURE_2D; + (S.isDataArrayTexture || S.isCompressedArrayTexture) && (ee = s1.TEXTURE_2D_ARRAY), S.isData3DTexture && (ee = s1.TEXTURE_3D); + let j = Te(C, S), te = S.source; + t.bindTexture(ee, C.__webglTexture, s1.TEXTURE0 + B); + let Me = n.get(te); + if (te.version !== Me.__version || j === !0) { + t.activeTexture(s1.TEXTURE0 + B); + let re = Qe.getPrimaries(Qe.workingColorSpace), de = S.colorSpace === Xt ? null : Qe.getPrimaries(S.colorSpace), Le = S.colorSpace === Xt || re === de ? s1.NONE : s1.BROWSER_DEFAULT_WEBGL; + s1.pixelStorei(s1.UNPACK_FLIP_Y_WEBGL, S.flipY), s1.pixelStorei(s1.UNPACK_PREMULTIPLY_ALPHA_WEBGL, S.premultiplyAlpha), s1.pixelStorei(s1.UNPACK_ALIGNMENT, S.unpackAlignment), s1.pixelStorei(s1.UNPACK_COLORSPACE_CONVERSION_WEBGL, Le); + let Ze = b(S) && y(S.image) === !1, se = x(S.image, Ze, !1, h); + se = rt(S, se); + let $e = y(se) || o, Oe = r.convert(S.format, S.colorSpace), Ie = r.convert(S.type), Re = I(S.internalFormat, Oe, Ie, S.colorSpace, S.isVideoTexture); + Ee(ee, S, $e); + let P, ce = S.mipmaps, ae = o && S.isVideoTexture !== !0, ge = Me.__version === void 0 || j === !0, ue = M(S, se, $e); + if (S.isDepthTexture) Re = s1.DEPTH_COMPONENT, o ? S.type === xn ? Re = s1.DEPTH_COMPONENT32F : S.type === Ln ? Re = s1.DEPTH_COMPONENT24 : S.type === ii ? Re = s1.DEPTH24_STENCIL8 : Re = s1.DEPTH_COMPONENT16 : S.type === xn && console.error("WebGLRenderer: Floating point depth texture requires WebGL2."), S.format === si && Re === s1.DEPTH_COMPONENT && S.type !== Wc && S.type !== Ln && (console.warn("THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture."), S.type = Ln, Ie = r.convert(S.type)), S.format === Yi && Re === s1.DEPTH_COMPONENT && (Re = s1.DEPTH_STENCIL, S.type !== ii && (console.warn("THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture."), S.type = ii, Ie = r.convert(S.type))), ge && (ae ? t.texStorage2D(s1.TEXTURE_2D, 1, Re, se.width, se.height) : t.texImage2D(s1.TEXTURE_2D, 0, Re, se.width, se.height, 0, Oe, Ie, null)); + else if (S.isDataTexture) if (ce.length > 0 && $e) { + ae && ge && t.texStorage2D(s1.TEXTURE_2D, ue, Re, ce[0].width, ce[0].height); + for(let Q = 0, be = ce.length; Q < be; Q++)P = ce[Q], ae ? t.texSubImage2D(s1.TEXTURE_2D, Q, 0, 0, P.width, P.height, Oe, Ie, P.data) : t.texImage2D(s1.TEXTURE_2D, Q, Re, P.width, P.height, 0, Oe, Ie, P.data); + S.generateMipmaps = !1; + } else ae ? (ge && t.texStorage2D(s1.TEXTURE_2D, ue, Re, se.width, se.height), t.texSubImage2D(s1.TEXTURE_2D, 0, 0, 0, se.width, se.height, Oe, Ie, se.data)) : t.texImage2D(s1.TEXTURE_2D, 0, Re, se.width, se.height, 0, Oe, Ie, se.data); + else if (S.isCompressedTexture) if (S.isCompressedArrayTexture) { + ae && ge && t.texStorage3D(s1.TEXTURE_2D_ARRAY, ue, Re, ce[0].width, ce[0].height, se.depth); + for(let Q = 0, be = ce.length; Q < be; Q++)P = ce[Q], S.format !== Wt ? Oe !== null ? ae ? t.compressedTexSubImage3D(s1.TEXTURE_2D_ARRAY, Q, 0, 0, 0, P.width, P.height, se.depth, Oe, P.data, 0, 0) : t.compressedTexImage3D(s1.TEXTURE_2D_ARRAY, Q, Re, P.width, P.height, se.depth, 0, P.data, 0, 0) : console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()") : ae ? t.texSubImage3D(s1.TEXTURE_2D_ARRAY, Q, 0, 0, 0, P.width, P.height, se.depth, Oe, Ie, P.data) : t.texImage3D(s1.TEXTURE_2D_ARRAY, Q, Re, P.width, P.height, se.depth, 0, Oe, Ie, P.data); + } else { + ae && ge && t.texStorage2D(s1.TEXTURE_2D, ue, Re, ce[0].width, ce[0].height); + for(let Q = 0, be = ce.length; Q < be; Q++)P = ce[Q], S.format !== Wt ? Oe !== null ? ae ? t.compressedTexSubImage2D(s1.TEXTURE_2D, Q, 0, 0, P.width, P.height, Oe, P.data) : t.compressedTexImage2D(s1.TEXTURE_2D, Q, Re, P.width, P.height, 0, P.data) : console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()") : ae ? t.texSubImage2D(s1.TEXTURE_2D, Q, 0, 0, P.width, P.height, Oe, Ie, P.data) : t.texImage2D(s1.TEXTURE_2D, Q, Re, P.width, P.height, 0, Oe, Ie, P.data); } - } else { - Re = T.mipmaps, Q && Ee && (Re.length > 0 && me++, t.texStorage2D(34067, me, ee, Z[0].width, Z[0].height)); - for(let oe = 0; oe < 6; oe++)if (re) { - Q ? t.texSubImage2D(34069 + oe, 0, 0, 0, Z[oe].width, Z[oe].height, te, R, Z[oe].data) : t.texImage2D(34069 + oe, 0, ee, Z[oe].width, Z[oe].height, 0, te, R, Z[oe].data); - for(let Le = 0; Le < Re.length; Le++){ - let We = Re[Le].image[oe].image; - Q ? t.texSubImage2D(34069 + oe, Le + 1, 0, 0, We.width, We.height, te, R, We.data) : t.texImage2D(34069 + oe, Le + 1, ee, We.width, We.height, 0, te, R, We.data); + else if (S.isDataArrayTexture) ae ? (ge && t.texStorage3D(s1.TEXTURE_2D_ARRAY, ue, Re, se.width, se.height, se.depth), t.texSubImage3D(s1.TEXTURE_2D_ARRAY, 0, 0, 0, 0, se.width, se.height, se.depth, Oe, Ie, se.data)) : t.texImage3D(s1.TEXTURE_2D_ARRAY, 0, Re, se.width, se.height, se.depth, 0, Oe, Ie, se.data); + else if (S.isData3DTexture) ae ? (ge && t.texStorage3D(s1.TEXTURE_3D, ue, Re, se.width, se.height, se.depth), t.texSubImage3D(s1.TEXTURE_3D, 0, 0, 0, 0, se.width, se.height, se.depth, Oe, Ie, se.data)) : t.texImage3D(s1.TEXTURE_3D, 0, Re, se.width, se.height, se.depth, 0, Oe, Ie, se.data); + else if (S.isFramebufferTexture) { + if (ge) if (ae) t.texStorage2D(s1.TEXTURE_2D, ue, Re, se.width, se.height); + else { + let Q = se.width, be = se.height; + for(let Fe = 0; Fe < ue; Fe++)t.texImage2D(s1.TEXTURE_2D, Fe, Re, Q, be, 0, Oe, Ie, null), Q >>= 1, be >>= 1; + } + } else if (ce.length > 0 && $e) { + ae && ge && t.texStorage2D(s1.TEXTURE_2D, ue, Re, ce[0].width, ce[0].height); + for(let Q = 0, be = ce.length; Q < be; Q++)P = ce[Q], ae ? t.texSubImage2D(s1.TEXTURE_2D, Q, 0, 0, Oe, Ie, P) : t.texImage2D(s1.TEXTURE_2D, Q, Re, Oe, Ie, P); + S.generateMipmaps = !1; + } else ae ? (ge && t.texStorage2D(s1.TEXTURE_2D, ue, Re, se.width, se.height), t.texSubImage2D(s1.TEXTURE_2D, 0, 0, 0, Oe, Ie, se)) : t.texImage2D(s1.TEXTURE_2D, 0, Re, Oe, Ie, se); + w(S, $e) && R(ee), Me.__version = te.version, S.onUpdate && S.onUpdate(S); + } + C.__version = S.version; + } + function it(C, S, B) { + if (S.image.length !== 6) return; + let ee = Te(C, S), j = S.source; + t.bindTexture(s1.TEXTURE_CUBE_MAP, C.__webglTexture, s1.TEXTURE0 + B); + let te = n.get(j); + if (j.version !== te.__version || ee === !0) { + t.activeTexture(s1.TEXTURE0 + B); + let Me = Qe.getPrimaries(Qe.workingColorSpace), re = S.colorSpace === Xt ? null : Qe.getPrimaries(S.colorSpace), de = S.colorSpace === Xt || Me === re ? s1.NONE : s1.BROWSER_DEFAULT_WEBGL; + s1.pixelStorei(s1.UNPACK_FLIP_Y_WEBGL, S.flipY), s1.pixelStorei(s1.UNPACK_PREMULTIPLY_ALPHA_WEBGL, S.premultiplyAlpha), s1.pixelStorei(s1.UNPACK_ALIGNMENT, S.unpackAlignment), s1.pixelStorei(s1.UNPACK_COLORSPACE_CONVERSION_WEBGL, de); + let Le = S.isCompressedTexture || S.image[0].isCompressedTexture, Ze = S.image[0] && S.image[0].isDataTexture, se = []; + for(let Q = 0; Q < 6; Q++)!Le && !Ze ? se[Q] = x(S.image[Q], !1, !0, l) : se[Q] = Ze ? S.image[Q].image : S.image[Q], se[Q] = rt(S, se[Q]); + let $e = se[0], Oe = y($e) || o, Ie = r.convert(S.format, S.colorSpace), Re = r.convert(S.type), P = I(S.internalFormat, Ie, Re, S.colorSpace), ce = o && S.isVideoTexture !== !0, ae = te.__version === void 0 || ee === !0, ge = M(S, $e, Oe); + Ee(s1.TEXTURE_CUBE_MAP, S, Oe); + let ue; + if (Le) { + ce && ae && t.texStorage2D(s1.TEXTURE_CUBE_MAP, ge, P, $e.width, $e.height); + for(let Q = 0; Q < 6; Q++){ + ue = se[Q].mipmaps; + for(let be = 0; be < ue.length; be++){ + let Fe = ue[be]; + S.format !== Wt ? Ie !== null ? ce ? t.compressedTexSubImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, be, 0, 0, Fe.width, Fe.height, Ie, Fe.data) : t.compressedTexImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, be, P, Fe.width, Fe.height, 0, Fe.data) : console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()") : ce ? t.texSubImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, be, 0, 0, Fe.width, Fe.height, Ie, Re, Fe.data) : t.texImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, be, P, Fe.width, Fe.height, 0, Ie, Re, Fe.data); + } } } else { - Q ? t.texSubImage2D(34069 + oe, 0, 0, 0, te, R, Z[oe]) : t.texImage2D(34069 + oe, 0, ee, te, R, Z[oe]); - for(let Le = 0; Le < Re.length; Le++){ - let Xe = Re[Le]; - Q ? t.texSubImage2D(34069 + oe, Le + 1, 0, 0, te, R, Xe.image[oe]) : t.texImage2D(34069 + oe, Le + 1, ee, te, R, Xe.image[oe]); + ue = S.mipmaps, ce && ae && (ue.length > 0 && ge++, t.texStorage2D(s1.TEXTURE_CUBE_MAP, ge, P, se[0].width, se[0].height)); + for(let Q = 0; Q < 6; Q++)if (Ze) { + ce ? t.texSubImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, 0, 0, 0, se[Q].width, se[Q].height, Ie, Re, se[Q].data) : t.texImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, 0, P, se[Q].width, se[Q].height, 0, Ie, Re, se[Q].data); + for(let be = 0; be < ue.length; be++){ + let At = ue[be].image[Q].image; + ce ? t.texSubImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, be + 1, 0, 0, At.width, At.height, Ie, Re, At.data) : t.texImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, be + 1, P, At.width, At.height, 0, Ie, Re, At.data); + } + } else { + ce ? t.texSubImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, 0, 0, 0, Ie, Re, se[Q]) : t.texImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, 0, P, Ie, Re, se[Q]); + for(let be = 0; be < ue.length; be++){ + let Fe = ue[be]; + ce ? t.texSubImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, be + 1, 0, 0, Ie, Re, Fe.image[Q]) : t.texImage2D(s1.TEXTURE_CUBE_MAP_POSITIVE_X + Q, be + 1, P, Ie, Re, Fe.image[Q]); + } } } - } - b(T, ve) && A(34067), C.__version = T.version, T.onUpdate && T.onUpdate(T); - } - function Ce(C, T, J, $, re) { - let Z = r.convert(J.format), Me = r.convert(J.type), ve = L(J.internalFormat, Z, Me, J.encoding); - n.get(T).__hasExternalTextures || (re === 32879 || re === 35866 ? t.texImage3D(re, 0, ve, T.width, T.height, T.depth, 0, Z, Me, null) : t.texImage2D(re, 0, ve, T.width, T.height, 0, Z, Me, null)), t.bindFramebuffer(36160, C), T.useRenderToTexture ? f.framebufferTexture2DMultisampleEXT(36160, $, re, n.get(J).__webglTexture, 0, ue(T)) : s.framebufferTexture2D(36160, $, re, n.get(J).__webglTexture, 0), t.bindFramebuffer(36160, null); - } - function ye(C, T, J) { - if (s.bindRenderbuffer(36161, C), T.depthBuffer && !T.stencilBuffer) { - let $ = 33189; - if (J || T.useRenderToTexture) { - let re = T.depthTexture; - re && re.isDepthTexture && (re.type === nn ? $ = 36012 : re.type === Ps && ($ = 33190)); - let Z = ue(T); - T.useRenderToTexture ? f.renderbufferStorageMultisampleEXT(36161, Z, $, T.width, T.height) : s.renderbufferStorageMultisample(36161, Z, $, T.width, T.height); - } else s.renderbufferStorage(36161, $, T.width, T.height); - s.framebufferRenderbuffer(36160, 36096, 36161, C); - } else if (T.depthBuffer && T.stencilBuffer) { - let $ = ue(T); - J && T.useRenderbuffer ? s.renderbufferStorageMultisample(36161, $, 35056, T.width, T.height) : T.useRenderToTexture ? f.renderbufferStorageMultisampleEXT(36161, $, 35056, T.width, T.height) : s.renderbufferStorage(36161, 34041, T.width, T.height), s.framebufferRenderbuffer(36160, 33306, 36161, C); + w(S, Oe) && R(s1.TEXTURE_CUBE_MAP), te.__version = j.version, S.onUpdate && S.onUpdate(S); + } + C.__version = S.version; + } + function Ce(C, S, B, ee, j, te) { + let Me = r.convert(B.format, B.colorSpace), re = r.convert(B.type), de = I(B.internalFormat, Me, re, B.colorSpace); + if (!n.get(S).__hasExternalTextures) { + let Ze = Math.max(1, S.width >> te), se = Math.max(1, S.height >> te); + j === s1.TEXTURE_3D || j === s1.TEXTURE_2D_ARRAY ? t.texImage3D(j, te, de, Ze, se, S.depth, 0, Me, re, null) : t.texImage2D(j, te, de, Ze, se, 0, Me, re, null); + } + t.bindFramebuffer(s1.FRAMEBUFFER, C), Ne(S) ? d.framebufferTexture2DMultisampleEXT(s1.FRAMEBUFFER, ee, j, n.get(B).__webglTexture, 0, ye(S)) : (j === s1.TEXTURE_2D || j >= s1.TEXTURE_CUBE_MAP_POSITIVE_X && j <= s1.TEXTURE_CUBE_MAP_NEGATIVE_Z) && s1.framebufferTexture2D(s1.FRAMEBUFFER, ee, j, n.get(B).__webglTexture, te), t.bindFramebuffer(s1.FRAMEBUFFER, null); + } + function L(C, S, B) { + if (s1.bindRenderbuffer(s1.RENDERBUFFER, C), S.depthBuffer && !S.stencilBuffer) { + let ee = o === !0 ? s1.DEPTH_COMPONENT24 : s1.DEPTH_COMPONENT16; + if (B || Ne(S)) { + let j = S.depthTexture; + j && j.isDepthTexture && (j.type === xn ? ee = s1.DEPTH_COMPONENT32F : j.type === Ln && (ee = s1.DEPTH_COMPONENT24)); + let te = ye(S); + Ne(S) ? d.renderbufferStorageMultisampleEXT(s1.RENDERBUFFER, te, ee, S.width, S.height) : s1.renderbufferStorageMultisample(s1.RENDERBUFFER, te, ee, S.width, S.height); + } else s1.renderbufferStorage(s1.RENDERBUFFER, ee, S.width, S.height); + s1.framebufferRenderbuffer(s1.FRAMEBUFFER, s1.DEPTH_ATTACHMENT, s1.RENDERBUFFER, C); + } else if (S.depthBuffer && S.stencilBuffer) { + let ee = ye(S); + B && Ne(S) === !1 ? s1.renderbufferStorageMultisample(s1.RENDERBUFFER, ee, s1.DEPTH24_STENCIL8, S.width, S.height) : Ne(S) ? d.renderbufferStorageMultisampleEXT(s1.RENDERBUFFER, ee, s1.DEPTH24_STENCIL8, S.width, S.height) : s1.renderbufferStorage(s1.RENDERBUFFER, s1.DEPTH_STENCIL, S.width, S.height), s1.framebufferRenderbuffer(s1.FRAMEBUFFER, s1.DEPTH_STENCIL_ATTACHMENT, s1.RENDERBUFFER, C); } else { - let $ = T.isWebGLMultipleRenderTargets === !0 ? T.texture[0] : T.texture, re = r.convert($.format), Z = r.convert($.type), Me = L($.internalFormat, re, Z, $.encoding), ve = ue(T); - J && T.useRenderbuffer ? s.renderbufferStorageMultisample(36161, ve, Me, T.width, T.height) : T.useRenderToTexture ? f.renderbufferStorageMultisampleEXT(36161, ve, Me, T.width, T.height) : s.renderbufferStorage(36161, Me, T.width, T.height); - } - s.bindRenderbuffer(36161, null); - } - function ge(C, T) { - if (T && T.isWebGLCubeRenderTarget) throw new Error("Depth Texture with cube render targets is not supported"); - if (t.bindFramebuffer(36160, C), !(T.depthTexture && T.depthTexture.isDepthTexture)) throw new Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture"); - (!n.get(T.depthTexture).__webglTexture || T.depthTexture.image.width !== T.width || T.depthTexture.image.height !== T.height) && (T.depthTexture.image.width = T.width, T.depthTexture.image.height = T.height, T.depthTexture.needsUpdate = !0), O(T.depthTexture, 0); - let $ = n.get(T.depthTexture).__webglTexture, re = ue(T); - if (T.depthTexture.format === Vn) T.useRenderToTexture ? f.framebufferTexture2DMultisampleEXT(36160, 36096, 3553, $, 0, re) : s.framebufferTexture2D(36160, 36096, 3553, $, 0); - else if (T.depthTexture.format === Li) T.useRenderToTexture ? f.framebufferTexture2DMultisampleEXT(36160, 33306, 3553, $, 0, re) : s.framebufferTexture2D(36160, 33306, 3553, $, 0); + let ee = S.isWebGLMultipleRenderTargets === !0 ? S.texture : [ + S.texture + ]; + for(let j = 0; j < ee.length; j++){ + let te = ee[j], Me = r.convert(te.format, te.colorSpace), re = r.convert(te.type), de = I(te.internalFormat, Me, re, te.colorSpace), Le = ye(S); + B && Ne(S) === !1 ? s1.renderbufferStorageMultisample(s1.RENDERBUFFER, Le, de, S.width, S.height) : Ne(S) ? d.renderbufferStorageMultisampleEXT(s1.RENDERBUFFER, Le, de, S.width, S.height) : s1.renderbufferStorage(s1.RENDERBUFFER, de, S.width, S.height); + } + } + s1.bindRenderbuffer(s1.RENDERBUFFER, null); + } + function oe(C, S) { + if (S && S.isWebGLCubeRenderTarget) throw new Error("Depth Texture with cube render targets is not supported"); + if (t.bindFramebuffer(s1.FRAMEBUFFER, C), !(S.depthTexture && S.depthTexture.isDepthTexture)) throw new Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture"); + (!n.get(S.depthTexture).__webglTexture || S.depthTexture.image.width !== S.width || S.depthTexture.image.height !== S.height) && (S.depthTexture.image.width = S.width, S.depthTexture.image.height = S.height, S.depthTexture.needsUpdate = !0), K(S.depthTexture, 0); + let ee = n.get(S.depthTexture).__webglTexture, j = ye(S); + if (S.depthTexture.format === si) Ne(S) ? d.framebufferTexture2DMultisampleEXT(s1.FRAMEBUFFER, s1.DEPTH_ATTACHMENT, s1.TEXTURE_2D, ee, 0, j) : s1.framebufferTexture2D(s1.FRAMEBUFFER, s1.DEPTH_ATTACHMENT, s1.TEXTURE_2D, ee, 0); + else if (S.depthTexture.format === Yi) Ne(S) ? d.framebufferTexture2DMultisampleEXT(s1.FRAMEBUFFER, s1.DEPTH_STENCIL_ATTACHMENT, s1.TEXTURE_2D, ee, 0, j) : s1.framebufferTexture2D(s1.FRAMEBUFFER, s1.DEPTH_STENCIL_ATTACHMENT, s1.TEXTURE_2D, ee, 0); else throw new Error("Unknown depthTexture format"); } - function xe(C) { - let T = n.get(C), J = C.isWebGLCubeRenderTarget === !0; - if (C.depthTexture && !T.__autoAllocateDepthBuffer) { - if (J) throw new Error("target.depthTexture not supported in Cube render targets"); - ge(T.__webglFramebuffer, C); - } else if (J) { - T.__webglDepthbuffer = []; - for(let $ = 0; $ < 6; $++)t.bindFramebuffer(36160, T.__webglFramebuffer[$]), T.__webglDepthbuffer[$] = s.createRenderbuffer(), ye(T.__webglDepthbuffer[$], C, !1); - } else t.bindFramebuffer(36160, T.__webglFramebuffer), T.__webglDepthbuffer = s.createRenderbuffer(), ye(T.__webglDepthbuffer, C, !1); - t.bindFramebuffer(36160, null); - } - function Oe(C, T, J) { - let $ = n.get(C); - T !== void 0 && Ce($.__webglFramebuffer, C, C.texture, 36064, 3553), J !== void 0 && xe(C); - } - function G(C) { - let T = C.texture, J = n.get(C), $ = n.get(T); - C.addEventListener("dispose", P), C.isWebGLMultipleRenderTargets !== !0 && ($.__webglTexture === void 0 && ($.__webglTexture = s.createTexture()), $.__version = T.version, o.memory.textures++); - let re = C.isWebGLCubeRenderTarget === !0, Z = C.isWebGLMultipleRenderTargets === !0, Me = T.isDataTexture3D || T.isDataTexture2DArray, ve = _(C) || a; - if (a && T.format === Gn && (T.type === nn || T.type === kn) && (T.format = ct, console.warn("THREE.WebGLRenderer: Rendering to textures with RGB format is not supported. Using RGBA format instead.")), re) { - J.__webglFramebuffer = []; - for(let te = 0; te < 6; te++)J.__webglFramebuffer[te] = s.createFramebuffer(); - } else if (J.__webglFramebuffer = s.createFramebuffer(), Z) if (i.drawBuffers) { - let te = C.texture; - for(let R = 0, ee = te.length; R < ee; R++){ - let Q = n.get(te[R]); - Q.__webglTexture === void 0 && (Q.__webglTexture = s.createTexture(), o.memory.textures++); - } - } else console.warn("THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension."); - else if (C.useRenderbuffer) if (a) { - J.__webglMultisampledFramebuffer = s.createFramebuffer(), J.__webglColorRenderbuffer = s.createRenderbuffer(), s.bindRenderbuffer(36161, J.__webglColorRenderbuffer); - let te = r.convert(T.format), R = r.convert(T.type), ee = L(T.internalFormat, te, R, T.encoding), Q = ue(C); - s.renderbufferStorageMultisample(36161, Q, ee, C.width, C.height), t.bindFramebuffer(36160, J.__webglMultisampledFramebuffer), s.framebufferRenderbuffer(36160, 36064, 36161, J.__webglColorRenderbuffer), s.bindRenderbuffer(36161, null), C.depthBuffer && (J.__webglDepthRenderbuffer = s.createRenderbuffer(), ye(J.__webglDepthRenderbuffer, C, !0)), t.bindFramebuffer(36160, null); - } else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2."); - if (re) { - t.bindTexture(34067, $.__webglTexture), le(34067, T, ve); - for(let te = 0; te < 6; te++)Ce(J.__webglFramebuffer[te], C, T, 36064, 34069 + te); - b(T, ve) && A(34067), t.unbindTexture(); - } else if (Z) { - let te = C.texture; - for(let R = 0, ee = te.length; R < ee; R++){ - let Q = te[R], Ee = n.get(Q); - t.bindTexture(3553, Ee.__webglTexture), le(3553, Q, ve), Ce(J.__webglFramebuffer, C, Q, 36064 + R, 3553), b(Q, ve) && A(3553); + function X(C) { + let S = n.get(C), B = C.isWebGLCubeRenderTarget === !0; + if (C.depthTexture && !S.__autoAllocateDepthBuffer) { + if (B) throw new Error("target.depthTexture not supported in Cube render targets"); + oe(S.__webglFramebuffer, C); + } else if (B) { + S.__webglDepthbuffer = []; + for(let ee = 0; ee < 6; ee++)t.bindFramebuffer(s1.FRAMEBUFFER, S.__webglFramebuffer[ee]), S.__webglDepthbuffer[ee] = s1.createRenderbuffer(), L(S.__webglDepthbuffer[ee], C, !1); + } else t.bindFramebuffer(s1.FRAMEBUFFER, S.__webglFramebuffer), S.__webglDepthbuffer = s1.createRenderbuffer(), L(S.__webglDepthbuffer, C, !1); + t.bindFramebuffer(s1.FRAMEBUFFER, null); + } + function ie(C, S, B) { + let ee = n.get(C); + S !== void 0 && Ce(ee.__webglFramebuffer, C, C.texture, s1.COLOR_ATTACHMENT0, s1.TEXTURE_2D, 0), B !== void 0 && X(C); + } + function J(C) { + let S = C.texture, B = n.get(C), ee = n.get(S); + C.addEventListener("dispose", Y), C.isWebGLMultipleRenderTargets !== !0 && (ee.__webglTexture === void 0 && (ee.__webglTexture = s1.createTexture()), ee.__version = S.version, a.memory.textures++); + let j = C.isWebGLCubeRenderTarget === !0, te = C.isWebGLMultipleRenderTargets === !0, Me = y(C) || o; + if (j) { + B.__webglFramebuffer = []; + for(let re = 0; re < 6; re++)if (o && S.mipmaps && S.mipmaps.length > 0) { + B.__webglFramebuffer[re] = []; + for(let de = 0; de < S.mipmaps.length; de++)B.__webglFramebuffer[re][de] = s1.createFramebuffer(); + } else B.__webglFramebuffer[re] = s1.createFramebuffer(); + } else { + if (o && S.mipmaps && S.mipmaps.length > 0) { + B.__webglFramebuffer = []; + for(let re = 0; re < S.mipmaps.length; re++)B.__webglFramebuffer[re] = s1.createFramebuffer(); + } else B.__webglFramebuffer = s1.createFramebuffer(); + if (te) if (i.drawBuffers) { + let re = C.texture; + for(let de = 0, Le = re.length; de < Le; de++){ + let Ze = n.get(re[de]); + Ze.__webglTexture === void 0 && (Ze.__webglTexture = s1.createTexture(), a.memory.textures++); + } + } else console.warn("THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension."); + if (o && C.samples > 0 && Ne(C) === !1) { + let re = te ? S : [ + S + ]; + B.__webglMultisampledFramebuffer = s1.createFramebuffer(), B.__webglColorRenderbuffer = [], t.bindFramebuffer(s1.FRAMEBUFFER, B.__webglMultisampledFramebuffer); + for(let de = 0; de < re.length; de++){ + let Le = re[de]; + B.__webglColorRenderbuffer[de] = s1.createRenderbuffer(), s1.bindRenderbuffer(s1.RENDERBUFFER, B.__webglColorRenderbuffer[de]); + let Ze = r.convert(Le.format, Le.colorSpace), se = r.convert(Le.type), $e = I(Le.internalFormat, Ze, se, Le.colorSpace, C.isXRRenderTarget === !0), Oe = ye(C); + s1.renderbufferStorageMultisample(s1.RENDERBUFFER, Oe, $e, C.width, C.height), s1.framebufferRenderbuffer(s1.FRAMEBUFFER, s1.COLOR_ATTACHMENT0 + de, s1.RENDERBUFFER, B.__webglColorRenderbuffer[de]); + } + s1.bindRenderbuffer(s1.RENDERBUFFER, null), C.depthBuffer && (B.__webglDepthRenderbuffer = s1.createRenderbuffer(), L(B.__webglDepthRenderbuffer, C, !0)), t.bindFramebuffer(s1.FRAMEBUFFER, null); + } + } + if (j) { + t.bindTexture(s1.TEXTURE_CUBE_MAP, ee.__webglTexture), Ee(s1.TEXTURE_CUBE_MAP, S, Me); + for(let re = 0; re < 6; re++)if (o && S.mipmaps && S.mipmaps.length > 0) for(let de = 0; de < S.mipmaps.length; de++)Ce(B.__webglFramebuffer[re][de], C, S, s1.COLOR_ATTACHMENT0, s1.TEXTURE_CUBE_MAP_POSITIVE_X + re, de); + else Ce(B.__webglFramebuffer[re], C, S, s1.COLOR_ATTACHMENT0, s1.TEXTURE_CUBE_MAP_POSITIVE_X + re, 0); + w(S, Me) && R(s1.TEXTURE_CUBE_MAP), t.unbindTexture(); + } else if (te) { + let re = C.texture; + for(let de = 0, Le = re.length; de < Le; de++){ + let Ze = re[de], se = n.get(Ze); + t.bindTexture(s1.TEXTURE_2D, se.__webglTexture), Ee(s1.TEXTURE_2D, Ze, Me), Ce(B.__webglFramebuffer, C, Ze, s1.COLOR_ATTACHMENT0 + de, s1.TEXTURE_2D, 0), w(Ze, Me) && R(s1.TEXTURE_2D); } t.unbindTexture(); } else { - let te = 3553; - Me && (a ? te = T.isDataTexture3D ? 32879 : 35866 : console.warn("THREE.DataTexture3D and THREE.DataTexture2DArray only supported with WebGL2.")), t.bindTexture(te, $.__webglTexture), le(te, T, ve), Ce(J.__webglFramebuffer, C, T, 36064, te), b(T, ve) && A(te), t.unbindTexture(); + let re = s1.TEXTURE_2D; + if ((C.isWebGL3DRenderTarget || C.isWebGLArrayRenderTarget) && (o ? re = C.isWebGL3DRenderTarget ? s1.TEXTURE_3D : s1.TEXTURE_2D_ARRAY : console.error("THREE.WebGLTextures: THREE.Data3DTexture and THREE.DataArrayTexture only supported with WebGL2.")), t.bindTexture(re, ee.__webglTexture), Ee(re, S, Me), o && S.mipmaps && S.mipmaps.length > 0) for(let de = 0; de < S.mipmaps.length; de++)Ce(B.__webglFramebuffer[de], C, S, s1.COLOR_ATTACHMENT0, re, de); + else Ce(B.__webglFramebuffer, C, S, s1.COLOR_ATTACHMENT0, re, 0); + w(S, Me) && R(re), t.unbindTexture(); } - C.depthBuffer && xe(C); + C.depthBuffer && X(C); } - function j(C) { - let T = _(C) || a, J = C.isWebGLMultipleRenderTargets === !0 ? C.texture : [ + function Se(C) { + let S = y(C) || o, B = C.isWebGLMultipleRenderTargets === !0 ? C.texture : [ C.texture ]; - for(let $ = 0, re = J.length; $ < re; $++){ - let Z = J[$]; - if (b(Z, T)) { - let Me = C.isWebGLCubeRenderTarget ? 34067 : 3553, ve = n.get(Z).__webglTexture; - t.bindTexture(Me, ve), A(Me), t.unbindTexture(); + for(let ee = 0, j = B.length; ee < j; ee++){ + let te = B[ee]; + if (w(te, S)) { + let Me = C.isWebGLCubeRenderTarget ? s1.TEXTURE_CUBE_MAP : s1.TEXTURE_2D, re = n.get(te).__webglTexture; + t.bindTexture(Me, re), R(Me), t.unbindTexture(); } } } - function K(C) { - if (C.useRenderbuffer) if (a) { - let T = C.width, J = C.height, $ = 16384, re = [ - 36064 - ], Z = C.stencilBuffer ? 33306 : 36096; - C.depthBuffer && re.push(Z), C.ignoreDepthForMultisampleCopy || (C.depthBuffer && ($ |= 256), C.stencilBuffer && ($ |= 1024)); - let Me = n.get(C); - t.bindFramebuffer(36008, Me.__webglMultisampledFramebuffer), t.bindFramebuffer(36009, Me.__webglFramebuffer), C.ignoreDepthForMultisampleCopy && (s.invalidateFramebuffer(36008, [ - Z - ]), s.invalidateFramebuffer(36009, [ - Z - ])), s.blitFramebuffer(0, 0, T, J, 0, 0, T, J, $, 9728), s.invalidateFramebuffer(36008, re), t.bindFramebuffer(36008, null), t.bindFramebuffer(36009, Me.__webglMultisampledFramebuffer); - } else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2."); + function me(C) { + if (o && C.samples > 0 && Ne(C) === !1) { + let S = C.isWebGLMultipleRenderTargets ? C.texture : [ + C.texture + ], B = C.width, ee = C.height, j = s1.COLOR_BUFFER_BIT, te = [], Me = C.stencilBuffer ? s1.DEPTH_STENCIL_ATTACHMENT : s1.DEPTH_ATTACHMENT, re = n.get(C), de = C.isWebGLMultipleRenderTargets === !0; + if (de) for(let Le = 0; Le < S.length; Le++)t.bindFramebuffer(s1.FRAMEBUFFER, re.__webglMultisampledFramebuffer), s1.framebufferRenderbuffer(s1.FRAMEBUFFER, s1.COLOR_ATTACHMENT0 + Le, s1.RENDERBUFFER, null), t.bindFramebuffer(s1.FRAMEBUFFER, re.__webglFramebuffer), s1.framebufferTexture2D(s1.DRAW_FRAMEBUFFER, s1.COLOR_ATTACHMENT0 + Le, s1.TEXTURE_2D, null, 0); + t.bindFramebuffer(s1.READ_FRAMEBUFFER, re.__webglMultisampledFramebuffer), t.bindFramebuffer(s1.DRAW_FRAMEBUFFER, re.__webglFramebuffer); + for(let Le = 0; Le < S.length; Le++){ + te.push(s1.COLOR_ATTACHMENT0 + Le), C.depthBuffer && te.push(Me); + let Ze = re.__ignoreDepthValues !== void 0 ? re.__ignoreDepthValues : !1; + if (Ze === !1 && (C.depthBuffer && (j |= s1.DEPTH_BUFFER_BIT), C.stencilBuffer && (j |= s1.STENCIL_BUFFER_BIT)), de && s1.framebufferRenderbuffer(s1.READ_FRAMEBUFFER, s1.COLOR_ATTACHMENT0, s1.RENDERBUFFER, re.__webglColorRenderbuffer[Le]), Ze === !0 && (s1.invalidateFramebuffer(s1.READ_FRAMEBUFFER, [ + Me + ]), s1.invalidateFramebuffer(s1.DRAW_FRAMEBUFFER, [ + Me + ])), de) { + let se = n.get(S[Le]).__webglTexture; + s1.framebufferTexture2D(s1.DRAW_FRAMEBUFFER, s1.COLOR_ATTACHMENT0, s1.TEXTURE_2D, se, 0); + } + s1.blitFramebuffer(0, 0, B, ee, 0, 0, B, ee, j, s1.NEAREST), f && s1.invalidateFramebuffer(s1.READ_FRAMEBUFFER, te); + } + if (t.bindFramebuffer(s1.READ_FRAMEBUFFER, null), t.bindFramebuffer(s1.DRAW_FRAMEBUFFER, null), de) for(let Le = 0; Le < S.length; Le++){ + t.bindFramebuffer(s1.FRAMEBUFFER, re.__webglMultisampledFramebuffer), s1.framebufferRenderbuffer(s1.FRAMEBUFFER, s1.COLOR_ATTACHMENT0 + Le, s1.RENDERBUFFER, re.__webglColorRenderbuffer[Le]); + let Ze = n.get(S[Le]).__webglTexture; + t.bindFramebuffer(s1.FRAMEBUFFER, re.__webglFramebuffer), s1.framebufferTexture2D(s1.DRAW_FRAMEBUFFER, s1.COLOR_ATTACHMENT0 + Le, s1.TEXTURE_2D, Ze, 0); + } + t.bindFramebuffer(s1.DRAW_FRAMEBUFFER, re.__webglMultisampledFramebuffer); + } } - function ue(C) { - return a && (C.useRenderbuffer || C.useRenderToTexture) ? Math.min(u, C.samples) : 0; + function ye(C) { + return Math.min(u, C.samples); } - function se(C) { - let T = o.render.frame; - m.get(C) !== T && (m.set(C, T), C.update()); + function Ne(C) { + let S = n.get(C); + return o && C.samples > 0 && e.has("WEBGL_multisampled_render_to_texture") === !0 && S.__useRenderToTexture !== !1; } - let Se = !1, Te = !1; - function Pe(C, T) { - C && C.isWebGLRenderTarget && (Se === !1 && (console.warn("THREE.WebGLTextures.safeSetTexture2D: don't use render targets as textures. Use their .texture property instead."), Se = !0), C = C.texture), O(C, T); + function qe(C) { + let S = a.render.frame; + m.get(C) !== S && (m.set(C, S), C.update()); } - function Ye(C, T) { - C && C.isWebGLCubeRenderTarget && (Te === !1 && (console.warn("THREE.WebGLTextures.safeSetTextureCube: don't use cube render targets as textures. Use their .texture property instead."), Te = !0), C = C.texture), V(C, T); + function rt(C, S) { + let B = C.colorSpace, ee = C.format, j = C.type; + return C.isCompressedTexture === !0 || C.isVideoTexture === !0 || C.format === po || B !== Mn && B !== Xt && (Qe.getTransfer(B) === nt ? o === !1 ? e.has("EXT_sRGB") === !0 && ee === Wt ? (C.format = po, C.minFilter = mt, C.generateMipmaps = !1) : S = Xr.sRGBToLinear(S) : (ee !== Wt || j !== On) && console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.") : console.error("THREE.WebGLTextures: Unsupported texture color space:", B)), S; } - this.allocateTextureUnit = F, this.resetTextureUnits = U, this.setTexture2D = O, this.setTexture2DArray = ne, this.setTexture3D = ce, this.setTextureCube = V, this.rebindTextures = Oe, this.setupRenderTarget = G, this.updateRenderTargetMipmap = j, this.updateMultisampleRenderTarget = K, this.setupDepthRenderbuffer = xe, this.setupFrameBufferTexture = Ce, this.safeSetTexture2D = Pe, this.safeSetTextureCube = Ye; + this.allocateTextureUnit = ne, this.resetTextureUnits = H, this.setTexture2D = K, this.setTexture2DArray = D, this.setTexture3D = G, this.setTextureCube = he, this.rebindTextures = ie, this.setupRenderTarget = J, this.updateRenderTargetMipmap = Se, this.updateMultisampleRenderTarget = me, this.setupDepthRenderbuffer = X, this.setupFrameBufferTexture = Ce, this.useMultisampledRTT = Ne; } -function Ex(s, e, t) { +function V0(s1, e, t) { let n = t.isWebGL2; - function i(r) { - let o; - if (r === rn) return 5121; - if (r === Vu) return 32819; - if (r === Wu) return 32820; - if (r === qu) return 33635; - if (r === Hu) return 5120; - if (r === ku) return 5122; - if (r === cr) return 5123; - if (r === Gu) return 5124; - if (r === Ps) return 5125; - if (r === nn) return 5126; - if (r === kn) return n ? 5131 : (o = e.get("OES_texture_half_float"), o !== null ? o.HALF_FLOAT_OES : null); - if (r === Xu) return 6406; - if (r === Gn) return 6407; - if (r === ct) return 6408; - if (r === Ju) return 6409; - if (r === Yu) return 6410; - if (r === Vn) return 6402; - if (r === Li) return 34041; - if (r === Zu) return 6403; - if (r === $u) return 36244; - if (r === ju) return 33319; - if (r === Qu) return 33320; - if (r === Ku) return 36248; - if (r === ed) return 36249; - if (r === al || r === ll || r === cl || r === hl) if (o = e.get("WEBGL_compressed_texture_s3tc"), o !== null) { - if (r === al) return o.COMPRESSED_RGB_S3TC_DXT1_EXT; - if (r === ll) return o.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if (r === cl) return o.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if (r === hl) return o.COMPRESSED_RGBA_S3TC_DXT5_EXT; + function i(r, a = Xt) { + let o, c = Qe.getTransfer(a); + if (r === On) return s1.UNSIGNED_BYTE; + if (r === fd) return s1.UNSIGNED_SHORT_4_4_4_4; + if (r === pd) return s1.UNSIGNED_SHORT_5_5_5_1; + if (r === _f) return s1.BYTE; + if (r === xf) return s1.SHORT; + if (r === Wc) return s1.UNSIGNED_SHORT; + if (r === dd) return s1.INT; + if (r === Ln) return s1.UNSIGNED_INT; + if (r === xn) return s1.FLOAT; + if (r === Ts) return n ? s1.HALF_FLOAT : (o = e.get("OES_texture_half_float"), o !== null ? o.HALF_FLOAT_OES : null); + if (r === vf) return s1.ALPHA; + if (r === Wt) return s1.RGBA; + if (r === yf) return s1.LUMINANCE; + if (r === Mf) return s1.LUMINANCE_ALPHA; + if (r === si) return s1.DEPTH_COMPONENT; + if (r === Yi) return s1.DEPTH_STENCIL; + if (r === po) return o = e.get("EXT_sRGB"), o !== null ? o.SRGB_ALPHA_EXT : null; + if (r === Sf) return s1.RED; + if (r === md) return s1.RED_INTEGER; + if (r === bf) return s1.RG; + if (r === gd) return s1.RG_INTEGER; + if (r === _d) return s1.RGBA_INTEGER; + if (r === wa || r === Aa || r === Ra || r === Ca) if (c === nt) if (o = e.get("WEBGL_compressed_texture_s3tc_srgb"), o !== null) { + if (r === wa) return o.COMPRESSED_SRGB_S3TC_DXT1_EXT; + if (r === Aa) return o.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + if (r === Ra) return o.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + if (r === Ca) return o.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + } else return null; + else if (o = e.get("WEBGL_compressed_texture_s3tc"), o !== null) { + if (r === wa) return o.COMPRESSED_RGB_S3TC_DXT1_EXT; + if (r === Aa) return o.COMPRESSED_RGBA_S3TC_DXT1_EXT; + if (r === Ra) return o.COMPRESSED_RGBA_S3TC_DXT3_EXT; + if (r === Ca) return o.COMPRESSED_RGBA_S3TC_DXT5_EXT; } else return null; if (r === ul || r === dl || r === fl || r === pl) if (o = e.get("WEBGL_compressed_texture_pvrtc"), o !== null) { if (r === ul) return o.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; @@ -10826,53 +12287,82 @@ function Ex(s, e, t) { if (r === fl) return o.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; if (r === pl) return o.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; } else return null; - if (r === td) return o = e.get("WEBGL_compressed_texture_etc1"), o !== null ? o.COMPRESSED_RGB_ETC1_WEBGL : null; - if ((r === ml || r === gl) && (o = e.get("WEBGL_compressed_texture_etc"), o !== null)) { - if (r === ml) return o.COMPRESSED_RGB8_ETC2; - if (r === gl) return o.COMPRESSED_RGBA8_ETC2_EAC; - } - if (r === nd || r === id || r === rd || r === sd || r === od || r === ad || r === ld || r === cd || r === hd || r === ud || r === dd || r === fd || r === pd || r === md || r === xd || r === yd || r === vd || r === _d || r === Md || r === bd || r === wd || r === Sd || r === Td || r === Ed || r === Ad || r === Cd || r === Ld || r === Rd) return o = e.get("WEBGL_compressed_texture_astc"), o !== null ? r : null; - if (r === gd) return o = e.get("EXT_texture_compression_bptc"), o !== null ? r : null; - if (r === Ti) return n ? 34042 : (o = e.get("WEBGL_depth_texture"), o !== null ? o.UNSIGNED_INT_24_8_WEBGL : null); + if (r === Ef) return o = e.get("WEBGL_compressed_texture_etc1"), o !== null ? o.COMPRESSED_RGB_ETC1_WEBGL : null; + if (r === ml || r === gl) if (o = e.get("WEBGL_compressed_texture_etc"), o !== null) { + if (r === ml) return c === nt ? o.COMPRESSED_SRGB8_ETC2 : o.COMPRESSED_RGB8_ETC2; + if (r === gl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : o.COMPRESSED_RGBA8_ETC2_EAC; + } else return null; + if (r === _l || r === xl || r === vl || r === yl || r === Ml || r === Sl || r === bl || r === El || r === Tl || r === wl || r === Al || r === Rl || r === Cl || r === Pl) if (o = e.get("WEBGL_compressed_texture_astc"), o !== null) { + if (r === _l) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : o.COMPRESSED_RGBA_ASTC_4x4_KHR; + if (r === xl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : o.COMPRESSED_RGBA_ASTC_5x4_KHR; + if (r === vl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : o.COMPRESSED_RGBA_ASTC_5x5_KHR; + if (r === yl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : o.COMPRESSED_RGBA_ASTC_6x5_KHR; + if (r === Ml) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : o.COMPRESSED_RGBA_ASTC_6x6_KHR; + if (r === Sl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : o.COMPRESSED_RGBA_ASTC_8x5_KHR; + if (r === bl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : o.COMPRESSED_RGBA_ASTC_8x6_KHR; + if (r === El) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : o.COMPRESSED_RGBA_ASTC_8x8_KHR; + if (r === Tl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : o.COMPRESSED_RGBA_ASTC_10x5_KHR; + if (r === wl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : o.COMPRESSED_RGBA_ASTC_10x6_KHR; + if (r === Al) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : o.COMPRESSED_RGBA_ASTC_10x8_KHR; + if (r === Rl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : o.COMPRESSED_RGBA_ASTC_10x10_KHR; + if (r === Cl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : o.COMPRESSED_RGBA_ASTC_12x10_KHR; + if (r === Pl) return c === nt ? o.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : o.COMPRESSED_RGBA_ASTC_12x12_KHR; + } else return null; + if (r === Pa || r === Ll || r === Il) if (o = e.get("EXT_texture_compression_bptc"), o !== null) { + if (r === Pa) return c === nt ? o.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : o.COMPRESSED_RGBA_BPTC_UNORM_EXT; + if (r === Ll) return o.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; + if (r === Il) return o.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; + } else return null; + if (r === Tf || r === Ul || r === Dl || r === Nl) if (o = e.get("EXT_texture_compression_rgtc"), o !== null) { + if (r === Pa) return o.COMPRESSED_RED_RGTC1_EXT; + if (r === Ul) return o.COMPRESSED_SIGNED_RED_RGTC1_EXT; + if (r === Dl) return o.COMPRESSED_RED_GREEN_RGTC2_EXT; + if (r === Nl) return o.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; + } else return null; + return r === ii ? n ? s1.UNSIGNED_INT_24_8 : (o = e.get("WEBGL_depth_texture"), o !== null ? o.UNSIGNED_INT_24_8_WEBGL : null) : s1[r] !== void 0 ? s1[r] : null; } return { convert: i }; } -var ga = class extends ut { +var To = class extends yt { constructor(e = []){ - super(); - this.cameras = e; + super(), this.isArrayCamera = !0, this.cameras = e; } -}; -ga.prototype.isArrayCamera = !0; -var Hn = class extends Ne { +}, ti = class extends Je { constructor(){ - super(); - this.type = "Group"; + super(), this.isGroup = !0, this.type = "Group"; } -}; -Hn.prototype.isGroup = !0; -var Ax = { +}, k0 = { type: "move" -}, Is = class { +}, Ss = class { constructor(){ this._targetRay = null, this._grip = null, this._hand = null; } getHandSpace() { - return this._hand === null && (this._hand = new Hn, this._hand.matrixAutoUpdate = !1, this._hand.visible = !1, this._hand.joints = {}, this._hand.inputState = { + return this._hand === null && (this._hand = new ti, this._hand.matrixAutoUpdate = !1, this._hand.visible = !1, this._hand.joints = {}, this._hand.inputState = { pinching: !1 }), this._hand; } getTargetRaySpace() { - return this._targetRay === null && (this._targetRay = new Hn, this._targetRay.matrixAutoUpdate = !1, this._targetRay.visible = !1, this._targetRay.hasLinearVelocity = !1, this._targetRay.linearVelocity = new M, this._targetRay.hasAngularVelocity = !1, this._targetRay.angularVelocity = new M), this._targetRay; + return this._targetRay === null && (this._targetRay = new ti, this._targetRay.matrixAutoUpdate = !1, this._targetRay.visible = !1, this._targetRay.hasLinearVelocity = !1, this._targetRay.linearVelocity = new A, this._targetRay.hasAngularVelocity = !1, this._targetRay.angularVelocity = new A), this._targetRay; } getGripSpace() { - return this._grip === null && (this._grip = new Hn, this._grip.matrixAutoUpdate = !1, this._grip.visible = !1, this._grip.hasLinearVelocity = !1, this._grip.linearVelocity = new M, this._grip.hasAngularVelocity = !1, this._grip.angularVelocity = new M), this._grip; + return this._grip === null && (this._grip = new ti, this._grip.matrixAutoUpdate = !1, this._grip.visible = !1, this._grip.hasLinearVelocity = !1, this._grip.linearVelocity = new A, this._grip.hasAngularVelocity = !1, this._grip.angularVelocity = new A), this._grip; } dispatchEvent(e) { return this._targetRay !== null && this._targetRay.dispatchEvent(e), this._grip !== null && this._grip.dispatchEvent(e), this._hand !== null && this._hand.dispatchEvent(e), this; } + connect(e) { + if (e && e.hand) { + let t = this._hand; + if (t) for (let n of e.hand.values())this._getHandJoint(t, n); + } + return this.dispatchEvent({ + type: "connected", + data: e + }), this; + } disconnect(e) { return this.dispatchEvent({ type: "disconnected", @@ -10880,777 +12370,933 @@ var Ax = { }), this._targetRay !== null && (this._targetRay.visible = !1), this._grip !== null && (this._grip.visible = !1), this._hand !== null && (this._hand.visible = !1), this; } update(e, t, n) { - let i = null, r = null, o = null, a = this._targetRay, l = this._grip, c = this._hand; - if (e && t.session.visibilityState !== "visible-blurred") if (a !== null && (i = t.getPose(e.targetRaySpace, n), i !== null && (a.matrix.fromArray(i.transform.matrix), a.matrix.decompose(a.position, a.rotation, a.scale), i.linearVelocity ? (a.hasLinearVelocity = !0, a.linearVelocity.copy(i.linearVelocity)) : a.hasLinearVelocity = !1, i.angularVelocity ? (a.hasAngularVelocity = !0, a.angularVelocity.copy(i.angularVelocity)) : a.hasAngularVelocity = !1, this.dispatchEvent(Ax))), c && e.hand) { - o = !0; - for (let x of e.hand.values()){ - let v = t.getJointPose(x, n); - if (c.joints[x.jointName] === void 0) { - let p = new Hn; - p.matrixAutoUpdate = !1, p.visible = !1, c.joints[x.jointName] = p, c.add(p); + let i = null, r = null, a = null, o = this._targetRay, c = this._grip, l = this._hand; + if (e && t.session.visibilityState !== "visible-blurred") { + if (l && e.hand) { + a = !0; + for (let _ of e.hand.values()){ + let g = t.getJointPose(_, n), p = this._getHandJoint(l, _); + g !== null && (p.matrix.fromArray(g.transform.matrix), p.matrix.decompose(p.position, p.rotation, p.scale), p.matrixWorldNeedsUpdate = !0, p.jointRadius = g.radius), p.visible = g !== null; } - let g = c.joints[x.jointName]; - v !== null && (g.matrix.fromArray(v.transform.matrix), g.matrix.decompose(g.position, g.rotation, g.scale), g.jointRadius = v.radius), g.visible = v !== null; - } - let h = c.joints["index-finger-tip"], u = c.joints["thumb-tip"], d = h.position.distanceTo(u.position), f = .02, m = .005; - c.inputState.pinching && d > f + m ? (c.inputState.pinching = !1, this.dispatchEvent({ - type: "pinchend", - handedness: e.handedness, - target: this - })) : !c.inputState.pinching && d <= f - m && (c.inputState.pinching = !0, this.dispatchEvent({ - type: "pinchstart", - handedness: e.handedness, - target: this - })); - } else l !== null && e.gripSpace && (r = t.getPose(e.gripSpace, n), r !== null && (l.matrix.fromArray(r.transform.matrix), l.matrix.decompose(l.position, l.rotation, l.scale), r.linearVelocity ? (l.hasLinearVelocity = !0, l.linearVelocity.copy(r.linearVelocity)) : l.hasLinearVelocity = !1, r.angularVelocity ? (l.hasAngularVelocity = !0, l.angularVelocity.copy(r.angularVelocity)) : l.hasAngularVelocity = !1)); - return a !== null && (a.visible = i !== null), l !== null && (l.visible = r !== null), c !== null && (c.visible = o !== null), this; - } -}, ks = class extends ot { - constructor(e, t, n, i, r, o, a, l, c, h){ - if (h = h !== void 0 ? h : Vn, h !== Vn && h !== Li) throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat"); - n === void 0 && h === Vn && (n = cr), n === void 0 && h === Li && (n = Ti); - super(null, i, r, o, a, l, h, n, c); - this.image = { + let h = l.joints["index-finger-tip"], u = l.joints["thumb-tip"], d = h.position.distanceTo(u.position), f = .02, m = .005; + l.inputState.pinching && d > f + m ? (l.inputState.pinching = !1, this.dispatchEvent({ + type: "pinchend", + handedness: e.handedness, + target: this + })) : !l.inputState.pinching && d <= f - m && (l.inputState.pinching = !0, this.dispatchEvent({ + type: "pinchstart", + handedness: e.handedness, + target: this + })); + } else c !== null && e.gripSpace && (r = t.getPose(e.gripSpace, n), r !== null && (c.matrix.fromArray(r.transform.matrix), c.matrix.decompose(c.position, c.rotation, c.scale), c.matrixWorldNeedsUpdate = !0, r.linearVelocity ? (c.hasLinearVelocity = !0, c.linearVelocity.copy(r.linearVelocity)) : c.hasLinearVelocity = !1, r.angularVelocity ? (c.hasAngularVelocity = !0, c.angularVelocity.copy(r.angularVelocity)) : c.hasAngularVelocity = !1)); + o !== null && (i = t.getPose(e.targetRaySpace, n), i === null && r !== null && (i = r), i !== null && (o.matrix.fromArray(i.transform.matrix), o.matrix.decompose(o.position, o.rotation, o.scale), o.matrixWorldNeedsUpdate = !0, i.linearVelocity ? (o.hasLinearVelocity = !0, o.linearVelocity.copy(i.linearVelocity)) : o.hasLinearVelocity = !1, i.angularVelocity ? (o.hasAngularVelocity = !0, o.angularVelocity.copy(i.angularVelocity)) : o.hasAngularVelocity = !1, this.dispatchEvent(k0))); + } + return o !== null && (o.visible = i !== null), c !== null && (c.visible = r !== null), l !== null && (l.visible = a !== null), this; + } + _getHandJoint(e, t) { + if (e.joints[t.jointName] === void 0) { + let n = new ti; + n.matrixAutoUpdate = !1, n.visible = !1, e.joints[t.jointName] = n, e.add(n); + } + return e.joints[t.jointName]; + } +}, wo = class extends St { + constructor(e, t, n, i, r, a, o, c, l, h){ + if (h = h !== void 0 ? h : si, h !== si && h !== Yi) throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat"); + n === void 0 && h === si && (n = Ln), n === void 0 && h === Yi && (n = ii), super(null, i, r, a, o, c, h, n, l), this.isDepthTexture = !0, this.image = { width: e, height: t - }, this.magFilter = a !== void 0 ? a : rt, this.minFilter = l !== void 0 ? l : rt, this.flipY = !1, this.generateMipmaps = !1; + }, this.magFilter = o !== void 0 ? o : pt, this.minFilter = c !== void 0 ? c : pt, this.flipY = !1, this.generateMipmaps = !1, this.compareFunction = null; } -}; -ks.prototype.isDepthTexture = !0; -var vh = class extends En { + copy(e) { + return super.copy(e), this.compareFunction = e.compareFunction, this; + } + toJSON(e) { + let t = super.toJSON(e); + return this.compareFunction !== null && (t.compareFunction = this.compareFunction), t; + } +}, Ao = class extends sn { constructor(e, t){ super(); - let n = this, i = null, r = 1, o = null, a = "local-floor", l = e.extensions.has("WEBGL_multisampled_render_to_texture"), c = null, h = null, u = null, d = null, f = !1, m = null, x = t.getContextAttributes(), v = null, g = null, p = [], _ = new Map, y = new ut; - y.layers.enable(1), y.viewport = new Ve; - let b = new ut; - b.layers.enable(2), b.viewport = new Ve; - let A = [ + let n = this, i = null, r = 1, a = null, o = "local-floor", c = 1, l = null, h = null, u = null, d = null, f = null, m = null, _ = t.getContextAttributes(), g = null, p = null, v = [], x = [], y = new yt; + y.layers.enable(1), y.viewport = new je; + let b = new yt; + b.layers.enable(2), b.viewport = new je; + let w = [ y, b - ], L = new ga; - L.layers.enable(1), L.layers.enable(2); - let I = null, k = null; - this.cameraAutoUpdate = !0, this.enabled = !1, this.isPresenting = !1, this.getController = function(V) { - let W = p[V]; - return W === void 0 && (W = new Is, p[V] = W), W.getTargetRaySpace(); - }, this.getControllerGrip = function(V) { - let W = p[V]; - return W === void 0 && (W = new Is, p[V] = W), W.getGripSpace(); - }, this.getHand = function(V) { - let W = p[V]; - return W === void 0 && (W = new Is, p[V] = W), W.getHandSpace(); + ], R = new To; + R.layers.enable(1), R.layers.enable(2); + let I = null, M = null; + this.cameraAutoUpdate = !0, this.enabled = !1, this.isPresenting = !1, this.getController = function(D) { + let G = v[D]; + return G === void 0 && (G = new Ss, v[D] = G), G.getTargetRaySpace(); + }, this.getControllerGrip = function(D) { + let G = v[D]; + return G === void 0 && (G = new Ss, v[D] = G), G.getGripSpace(); + }, this.getHand = function(D) { + let G = v[D]; + return G === void 0 && (G = new Ss, v[D] = G), G.getHandSpace(); }; - function B(V) { - let W = _.get(V.inputSource); - W && W.dispatchEvent({ - type: V.type, - data: V.inputSource - }); + function T(D) { + let G = x.indexOf(D.inputSource); + if (G === -1) return; + let he = v[G]; + he !== void 0 && (he.update(D.inputSource, D.frame, l || a), he.dispatchEvent({ + type: D.type, + data: D.inputSource + })); } - function P() { - _.forEach(function(V, W) { - V.disconnect(W); - }), _.clear(), I = null, k = null, e.setRenderTarget(v), d = null, u = null, h = null, i = null, g = null, ce.stop(), n.isPresenting = !1, n.dispatchEvent({ + function O() { + i.removeEventListener("select", T), i.removeEventListener("selectstart", T), i.removeEventListener("selectend", T), i.removeEventListener("squeeze", T), i.removeEventListener("squeezestart", T), i.removeEventListener("squeezeend", T), i.removeEventListener("end", O), i.removeEventListener("inputsourceschange", Y); + for(let D = 0; D < v.length; D++){ + let G = x[D]; + G !== null && (x[D] = null, v[D].disconnect(G)); + } + I = null, M = null, e.setRenderTarget(g), f = null, d = null, u = null, i = null, p = null, K.stop(), n.isPresenting = !1, n.dispatchEvent({ type: "sessionend" }); } - this.setFramebufferScaleFactor = function(V) { - r = V, n.isPresenting === !0 && console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting."); - }, this.setReferenceSpaceType = function(V) { - a = V, n.isPresenting === !0 && console.warn("THREE.WebXRManager: Cannot change reference space type while presenting."); + this.setFramebufferScaleFactor = function(D) { + r = D, n.isPresenting === !0 && console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting."); + }, this.setReferenceSpaceType = function(D) { + o = D, n.isPresenting === !0 && console.warn("THREE.WebXRManager: Cannot change reference space type while presenting."); }, this.getReferenceSpace = function() { - return o; + return l || a; + }, this.setReferenceSpace = function(D) { + l = D; }, this.getBaseLayer = function() { - return u !== null ? u : d; + return d !== null ? d : f; }, this.getBinding = function() { - return h; + return u; }, this.getFrame = function() { return m; }, this.getSession = function() { return i; - }, this.setSession = async function(V) { - if (i = V, i !== null) { - if (v = e.getRenderTarget(), i.addEventListener("select", B), i.addEventListener("selectstart", B), i.addEventListener("selectend", B), i.addEventListener("squeeze", B), i.addEventListener("squeezestart", B), i.addEventListener("squeezeend", B), i.addEventListener("end", P), i.addEventListener("inputsourceschange", w), x.xrCompatible !== !0 && await t.makeXRCompatible(), i.renderState.layers === void 0 || e.capabilities.isWebGL2 === !1) { - let W = { - antialias: i.renderState.layers === void 0 ? x.antialias : !0, - alpha: x.alpha, - depth: x.depth, - stencil: x.stencil, + }, this.setSession = async function(D) { + if (i = D, i !== null) { + if (g = e.getRenderTarget(), i.addEventListener("select", T), i.addEventListener("selectstart", T), i.addEventListener("selectend", T), i.addEventListener("squeeze", T), i.addEventListener("squeezestart", T), i.addEventListener("squeezeend", T), i.addEventListener("end", O), i.addEventListener("inputsourceschange", Y), _.xrCompatible !== !0 && await t.makeXRCompatible(), i.renderState.layers === void 0 || e.capabilities.isWebGL2 === !1) { + let G = { + antialias: i.renderState.layers === void 0 ? _.antialias : !0, + alpha: !0, + depth: _.depth, + stencil: _.stencil, framebufferScaleFactor: r }; - d = new XRWebGLLayer(i, t, W), i.updateRenderState({ - baseLayer: d - }), g = new At(d.framebufferWidth, d.framebufferHeight, { - format: ct, - type: rn, - encoding: e.outputEncoding + f = new XRWebGLLayer(i, t, G), i.updateRenderState({ + baseLayer: f + }), p = new qt(f.framebufferWidth, f.framebufferHeight, { + format: Wt, + type: On, + colorSpace: e.outputColorSpace, + stencilBuffer: _.stencil }); } else { - f = x.antialias; - let W = null, he = null, le = null; - x.depth && (le = x.stencil ? 35056 : 33190, W = x.stencil ? Li : Vn, he = x.stencil ? Ti : cr); - let fe = { - colorFormat: x.alpha || f ? 32856 : 32849, - depthFormat: le, + let G = null, he = null, fe = null; + _.depth && (fe = _.stencil ? t.DEPTH24_STENCIL8 : t.DEPTH_COMPONENT24, G = _.stencil ? Yi : si, he = _.stencil ? ii : Ln); + let _e = { + colorFormat: t.RGBA8, + depthFormat: fe, scaleFactor: r }; - h = new XRWebGLBinding(i, t), u = h.createProjectionLayer(fe), i.updateRenderState({ + u = new XRWebGLBinding(i, t), d = u.createProjectionLayer(_e), i.updateRenderState({ layers: [ - u + d ] - }), f ? g = new Xs(u.textureWidth, u.textureHeight, { - format: ct, - type: rn, - depthTexture: new ks(u.textureWidth, u.textureHeight, he, void 0, void 0, void 0, void 0, void 0, void 0, W), - stencilBuffer: x.stencil, - ignoreDepth: u.ignoreDepthValues, - useRenderToTexture: l, - encoding: e.outputEncoding - }) : g = new At(u.textureWidth, u.textureHeight, { - format: x.alpha ? ct : Gn, - type: rn, - depthTexture: new ks(u.textureWidth, u.textureHeight, he, void 0, void 0, void 0, void 0, void 0, void 0, W), - stencilBuffer: x.stencil, - ignoreDepth: u.ignoreDepthValues, - encoding: e.outputEncoding + }), p = new qt(d.textureWidth, d.textureHeight, { + format: Wt, + type: On, + depthTexture: new wo(d.textureWidth, d.textureHeight, he, void 0, void 0, void 0, void 0, void 0, void 0, G), + stencilBuffer: _.stencil, + colorSpace: e.outputColorSpace, + samples: _.antialias ? 4 : 0 }); + let we = e.properties.get(p); + we.__ignoreDepthValues = d.ignoreDepthValues; } - this.setFoveation(1), o = await i.requestReferenceSpace(a), ce.setContext(i), ce.start(), n.isPresenting = !0, n.dispatchEvent({ + p.isXRRenderTarget = !0, this.setFoveation(c), l = null, a = await i.requestReferenceSpace(o), K.setContext(i), K.start(), n.isPresenting = !0, n.dispatchEvent({ type: "sessionstart" }); } + }, this.getEnvironmentBlendMode = function() { + if (i !== null) return i.environmentBlendMode; }; - function w(V) { - let W = i.inputSources; - for(let he = 0; he < p.length; he++)_.set(W[he], p[he]); - for(let he = 0; he < V.removed.length; he++){ - let le = V.removed[he], fe = _.get(le); - fe && (fe.dispatchEvent({ - type: "disconnected", - data: le - }), _.delete(le)); - } - for(let he = 0; he < V.added.length; he++){ - let le = V.added[he], fe = _.get(le); - fe && fe.dispatchEvent({ - type: "connected", - data: le - }); + function Y(D) { + for(let G = 0; G < D.removed.length; G++){ + let he = D.removed[G], fe = x.indexOf(he); + fe >= 0 && (x[fe] = null, v[fe].disconnect(he)); + } + for(let G = 0; G < D.added.length; G++){ + let he = D.added[G], fe = x.indexOf(he); + if (fe === -1) { + for(let we = 0; we < v.length; we++)if (we >= x.length) { + x.push(he), fe = we; + break; + } else if (x[we] === null) { + x[we] = he, fe = we; + break; + } + if (fe === -1) break; + } + let _e = v[fe]; + _e && _e.connect(he); } } - let E = new M, D = new M; - function U(V, W, he) { - E.setFromMatrixPosition(W.matrixWorld), D.setFromMatrixPosition(he.matrixWorld); - let le = E.distanceTo(D), fe = W.projectionMatrix.elements, Be = he.projectionMatrix.elements, Y = fe[14] / (fe[10] - 1), Ce = fe[14] / (fe[10] + 1), ye = (fe[9] + 1) / fe[5], ge = (fe[9] - 1) / fe[5], xe = (fe[8] - 1) / fe[0], Oe = (Be[8] + 1) / Be[0], G = Y * xe, j = Y * Oe, K = le / (-xe + Oe), ue = K * -xe; - W.matrixWorld.decompose(V.position, V.quaternion, V.scale), V.translateX(ue), V.translateZ(K), V.matrixWorld.compose(V.position, V.quaternion, V.scale), V.matrixWorldInverse.copy(V.matrixWorld).invert(); - let se = Y + K, Se = Ce + K, Te = G - ue, Pe = j + (le - ue), Ye = ye * Ce / Se * se, C = ge * Ce / Se * se; - V.projectionMatrix.makePerspective(Te, Pe, Ye, C, se, Se); + let $ = new A, U = new A; + function z(D, G, he) { + $.setFromMatrixPosition(G.matrixWorld), U.setFromMatrixPosition(he.matrixWorld); + let fe = $.distanceTo(U), _e = G.projectionMatrix.elements, we = he.projectionMatrix.elements, Ee = _e[14] / (_e[10] - 1), Te = _e[14] / (_e[10] + 1), Ye = (_e[9] + 1) / _e[5], it = (_e[9] - 1) / _e[5], Ce = (_e[8] - 1) / _e[0], L = (we[8] + 1) / we[0], oe = Ee * Ce, X = Ee * L, ie = fe / (-Ce + L), J = ie * -Ce; + G.matrixWorld.decompose(D.position, D.quaternion, D.scale), D.translateX(J), D.translateZ(ie), D.matrixWorld.compose(D.position, D.quaternion, D.scale), D.matrixWorldInverse.copy(D.matrixWorld).invert(); + let Se = Ee + ie, me = Te + ie, ye = oe - J, Ne = X + (fe - J), qe = Ye * Te / me * Se, rt = it * Te / me * Se; + D.projectionMatrix.makePerspective(ye, Ne, qe, rt, Se, me), D.projectionMatrixInverse.copy(D.projectionMatrix).invert(); } - function F(V, W) { - W === null ? V.matrixWorld.copy(V.matrix) : V.matrixWorld.multiplyMatrices(W.matrixWorld, V.matrix), V.matrixWorldInverse.copy(V.matrixWorld).invert(); + function q(D, G) { + G === null ? D.matrixWorld.copy(D.matrix) : D.matrixWorld.multiplyMatrices(G.matrixWorld, D.matrix), D.matrixWorldInverse.copy(D.matrixWorld).invert(); } - this.updateCamera = function(V) { + this.updateCamera = function(D) { if (i === null) return; - L.near = b.near = y.near = V.near, L.far = b.far = y.far = V.far, (I !== L.near || k !== L.far) && (i.updateRenderState({ - depthNear: L.near, - depthFar: L.far - }), I = L.near, k = L.far); - let W = V.parent, he = L.cameras; - F(L, W); - for(let fe = 0; fe < he.length; fe++)F(he[fe], W); - L.matrixWorld.decompose(L.position, L.quaternion, L.scale), V.position.copy(L.position), V.quaternion.copy(L.quaternion), V.scale.copy(L.scale), V.matrix.copy(L.matrix), V.matrixWorld.copy(L.matrixWorld); - let le = V.children; - for(let fe = 0, Be = le.length; fe < Be; fe++)le[fe].updateMatrixWorld(!0); - he.length === 2 ? U(L, y, b) : L.projectionMatrix.copy(y.projectionMatrix); - }, this.getCamera = function() { - return L; + R.near = b.near = y.near = D.near, R.far = b.far = y.far = D.far, (I !== R.near || M !== R.far) && (i.updateRenderState({ + depthNear: R.near, + depthFar: R.far + }), I = R.near, M = R.far); + let G = D.parent, he = R.cameras; + q(R, G); + for(let fe = 0; fe < he.length; fe++)q(he[fe], G); + he.length === 2 ? z(R, y, b) : R.projectionMatrix.copy(y.projectionMatrix), H(D, R, G); + }; + function H(D, G, he) { + he === null ? D.matrix.copy(G.matrixWorld) : (D.matrix.copy(he.matrixWorld), D.matrix.invert(), D.matrix.multiply(G.matrixWorld)), D.matrix.decompose(D.position, D.quaternion, D.scale), D.updateMatrixWorld(!0), D.projectionMatrix.copy(G.projectionMatrix), D.projectionMatrixInverse.copy(G.projectionMatrixInverse), D.isPerspectiveCamera && (D.fov = Zi * 2 * Math.atan(1 / D.projectionMatrix.elements[5]), D.zoom = 1); + } + this.getCamera = function() { + return R; }, this.getFoveation = function() { - if (u !== null) return u.fixedFoveation; - if (d !== null) return d.fixedFoveation; - }, this.setFoveation = function(V) { - u !== null && (u.fixedFoveation = V), d !== null && d.fixedFoveation !== void 0 && (d.fixedFoveation = V); + if (!(d === null && f === null)) return c; + }, this.setFoveation = function(D) { + c = D, d !== null && (d.fixedFoveation = D), f !== null && f.fixedFoveation !== void 0 && (f.fixedFoveation = D); }; - let O = null; - function ne(V, W) { - if (c = W.getViewerPose(o), m = W, c !== null) { - let le = c.views; - d !== null && (e.setRenderTargetFramebuffer(g, d.framebuffer), e.setRenderTarget(g)); + let ne = null; + function W(D, G) { + if (h = G.getViewerPose(l || a), m = G, h !== null) { + let he = h.views; + f !== null && (e.setRenderTargetFramebuffer(p, f.framebuffer), e.setRenderTarget(p)); let fe = !1; - le.length !== L.cameras.length && (L.cameras.length = 0, fe = !0); - for(let Be = 0; Be < le.length; Be++){ - let Y = le[Be], Ce = null; - if (d !== null) Ce = d.getViewport(Y); + he.length !== R.cameras.length && (R.cameras.length = 0, fe = !0); + for(let _e = 0; _e < he.length; _e++){ + let we = he[_e], Ee = null; + if (f !== null) Ee = f.getViewport(we); else { - let ge = h.getViewSubImage(u, Y); - Ce = ge.viewport, Be === 0 && (e.setRenderTargetTextures(g, ge.colorTexture, u.ignoreDepthValues ? void 0 : ge.depthStencilTexture), e.setRenderTarget(g)); + let Ye = u.getViewSubImage(d, we); + Ee = Ye.viewport, _e === 0 && (e.setRenderTargetTextures(p, Ye.colorTexture, d.ignoreDepthValues ? void 0 : Ye.depthStencilTexture), e.setRenderTarget(p)); } - let ye = A[Be]; - ye.matrix.fromArray(Y.transform.matrix), ye.projectionMatrix.fromArray(Y.projectionMatrix), ye.viewport.set(Ce.x, Ce.y, Ce.width, Ce.height), Be === 0 && L.matrix.copy(ye.matrix), fe === !0 && L.cameras.push(ye); + let Te = w[_e]; + Te === void 0 && (Te = new yt, Te.layers.enable(_e), Te.viewport = new je, w[_e] = Te), Te.matrix.fromArray(we.transform.matrix), Te.matrix.decompose(Te.position, Te.quaternion, Te.scale), Te.projectionMatrix.fromArray(we.projectionMatrix), Te.projectionMatrixInverse.copy(Te.projectionMatrix).invert(), Te.viewport.set(Ee.x, Ee.y, Ee.width, Ee.height), _e === 0 && (R.matrix.copy(Te.matrix), R.matrix.decompose(R.position, R.quaternion, R.scale)), fe === !0 && R.cameras.push(Te); } } - let he = i.inputSources; - for(let le = 0; le < p.length; le++){ - let fe = p[le], Be = he[le]; - fe.update(Be, W, o); + for(let he = 0; he < v.length; he++){ + let fe = x[he], _e = v[he]; + fe !== null && _e !== void 0 && _e.update(fe, G, l || a); } - O && O(V, W), m = null; - } - let ce = new rh; - ce.setAnimationLoop(ne), this.setAnimationLoop = function(V) { - O = V; + ne && ne(D, G), G.detectedPlanes && n.dispatchEvent({ + type: "planesdetected", + data: G + }), m = null; + } + let K = new Ed; + K.setAnimationLoop(W), this.setAnimationLoop = function(D) { + ne = D; }, this.dispose = function() {}; } }; -function Cx(s) { - function e(g, p) { - g.fogColor.value.copy(p.color), p.isFog ? (g.fogNear.value = p.near, g.fogFar.value = p.far) : p.isFogExp2 && (g.fogDensity.value = p.density); - } - function t(g, p, _, y, b) { - p.isMeshBasicMaterial ? n(g, p) : p.isMeshLambertMaterial ? (n(g, p), l(g, p)) : p.isMeshToonMaterial ? (n(g, p), h(g, p)) : p.isMeshPhongMaterial ? (n(g, p), c(g, p)) : p.isMeshStandardMaterial ? (n(g, p), p.isMeshPhysicalMaterial ? d(g, p, b) : u(g, p)) : p.isMeshMatcapMaterial ? (n(g, p), f(g, p)) : p.isMeshDepthMaterial ? (n(g, p), m(g, p)) : p.isMeshDistanceMaterial ? (n(g, p), x(g, p)) : p.isMeshNormalMaterial ? (n(g, p), v(g, p)) : p.isLineBasicMaterial ? (i(g, p), p.isLineDashedMaterial && r(g, p)) : p.isPointsMaterial ? o(g, p, _, y) : p.isSpriteMaterial ? a(g, p) : p.isShadowMaterial ? (g.color.value.copy(p.color), g.opacity.value = p.opacity) : p.isShaderMaterial && (p.uniformsNeedUpdate = !1); +function H0(s1, e) { + function t(g, p) { + g.matrixAutoUpdate === !0 && g.updateMatrix(), p.value.copy(g.matrix); } function n(g, p) { - g.opacity.value = p.opacity, p.color && g.diffuse.value.copy(p.color), p.emissive && g.emissive.value.copy(p.emissive).multiplyScalar(p.emissiveIntensity), p.map && (g.map.value = p.map), p.alphaMap && (g.alphaMap.value = p.alphaMap), p.specularMap && (g.specularMap.value = p.specularMap), p.alphaTest > 0 && (g.alphaTest.value = p.alphaTest); - let _ = s.get(p).envMap; - _ && (g.envMap.value = _, g.flipEnvMap.value = _.isCubeTexture && _.isRenderTargetTexture === !1 ? -1 : 1, g.reflectivity.value = p.reflectivity, g.ior.value = p.ior, g.refractionRatio.value = p.refractionRatio), p.lightMap && (g.lightMap.value = p.lightMap, g.lightMapIntensity.value = p.lightMapIntensity), p.aoMap && (g.aoMap.value = p.aoMap, g.aoMapIntensity.value = p.aoMapIntensity); - let y; - p.map ? y = p.map : p.specularMap ? y = p.specularMap : p.displacementMap ? y = p.displacementMap : p.normalMap ? y = p.normalMap : p.bumpMap ? y = p.bumpMap : p.roughnessMap ? y = p.roughnessMap : p.metalnessMap ? y = p.metalnessMap : p.alphaMap ? y = p.alphaMap : p.emissiveMap ? y = p.emissiveMap : p.clearcoatMap ? y = p.clearcoatMap : p.clearcoatNormalMap ? y = p.clearcoatNormalMap : p.clearcoatRoughnessMap ? y = p.clearcoatRoughnessMap : p.specularIntensityMap ? y = p.specularIntensityMap : p.specularColorMap ? y = p.specularColorMap : p.transmissionMap ? y = p.transmissionMap : p.thicknessMap ? y = p.thicknessMap : p.sheenColorMap ? y = p.sheenColorMap : p.sheenRoughnessMap && (y = p.sheenRoughnessMap), y !== void 0 && (y.isWebGLRenderTarget && (y = y.texture), y.matrixAutoUpdate === !0 && y.updateMatrix(), g.uvTransform.value.copy(y.matrix)); - let b; - p.aoMap ? b = p.aoMap : p.lightMap && (b = p.lightMap), b !== void 0 && (b.isWebGLRenderTarget && (b = b.texture), b.matrixAutoUpdate === !0 && b.updateMatrix(), g.uv2Transform.value.copy(b.matrix)); + p.color.getRGB(g.fogColor.value, bd(s1)), p.isFog ? (g.fogNear.value = p.near, g.fogFar.value = p.far) : p.isFogExp2 && (g.fogDensity.value = p.density); } - function i(g, p) { - g.diffuse.value.copy(p.color), g.opacity.value = p.opacity; + function i(g, p, v, x, y) { + p.isMeshBasicMaterial || p.isMeshLambertMaterial ? r(g, p) : p.isMeshToonMaterial ? (r(g, p), u(g, p)) : p.isMeshPhongMaterial ? (r(g, p), h(g, p)) : p.isMeshStandardMaterial ? (r(g, p), d(g, p), p.isMeshPhysicalMaterial && f(g, p, y)) : p.isMeshMatcapMaterial ? (r(g, p), m(g, p)) : p.isMeshDepthMaterial ? r(g, p) : p.isMeshDistanceMaterial ? (r(g, p), _(g, p)) : p.isMeshNormalMaterial ? r(g, p) : p.isLineBasicMaterial ? (a(g, p), p.isLineDashedMaterial && o(g, p)) : p.isPointsMaterial ? c(g, p, v, x) : p.isSpriteMaterial ? l(g, p) : p.isShadowMaterial ? (g.color.value.copy(p.color), g.opacity.value = p.opacity) : p.isShaderMaterial && (p.uniformsNeedUpdate = !1); } function r(g, p) { - g.dashSize.value = p.dashSize, g.totalSize.value = p.dashSize + p.gapSize, g.scale.value = p.scale; - } - function o(g, p, _, y) { - g.diffuse.value.copy(p.color), g.opacity.value = p.opacity, g.size.value = p.size * _, g.scale.value = y * .5, p.map && (g.map.value = p.map), p.alphaMap && (g.alphaMap.value = p.alphaMap), p.alphaTest > 0 && (g.alphaTest.value = p.alphaTest); - let b; - p.map ? b = p.map : p.alphaMap && (b = p.alphaMap), b !== void 0 && (b.matrixAutoUpdate === !0 && b.updateMatrix(), g.uvTransform.value.copy(b.matrix)); + g.opacity.value = p.opacity, p.color && g.diffuse.value.copy(p.color), p.emissive && g.emissive.value.copy(p.emissive).multiplyScalar(p.emissiveIntensity), p.map && (g.map.value = p.map, t(p.map, g.mapTransform)), p.alphaMap && (g.alphaMap.value = p.alphaMap, t(p.alphaMap, g.alphaMapTransform)), p.bumpMap && (g.bumpMap.value = p.bumpMap, t(p.bumpMap, g.bumpMapTransform), g.bumpScale.value = p.bumpScale, p.side === Ft && (g.bumpScale.value *= -1)), p.normalMap && (g.normalMap.value = p.normalMap, t(p.normalMap, g.normalMapTransform), g.normalScale.value.copy(p.normalScale), p.side === Ft && g.normalScale.value.negate()), p.displacementMap && (g.displacementMap.value = p.displacementMap, t(p.displacementMap, g.displacementMapTransform), g.displacementScale.value = p.displacementScale, g.displacementBias.value = p.displacementBias), p.emissiveMap && (g.emissiveMap.value = p.emissiveMap, t(p.emissiveMap, g.emissiveMapTransform)), p.specularMap && (g.specularMap.value = p.specularMap, t(p.specularMap, g.specularMapTransform)), p.alphaTest > 0 && (g.alphaTest.value = p.alphaTest); + let v = e.get(p).envMap; + if (v && (g.envMap.value = v, g.flipEnvMap.value = v.isCubeTexture && v.isRenderTargetTexture === !1 ? -1 : 1, g.reflectivity.value = p.reflectivity, g.ior.value = p.ior, g.refractionRatio.value = p.refractionRatio), p.lightMap) { + g.lightMap.value = p.lightMap; + let x = s1._useLegacyLights === !0 ? Math.PI : 1; + g.lightMapIntensity.value = p.lightMapIntensity * x, t(p.lightMap, g.lightMapTransform); + } + p.aoMap && (g.aoMap.value = p.aoMap, g.aoMapIntensity.value = p.aoMapIntensity, t(p.aoMap, g.aoMapTransform)); } function a(g, p) { - g.diffuse.value.copy(p.color), g.opacity.value = p.opacity, g.rotation.value = p.rotation, p.map && (g.map.value = p.map), p.alphaMap && (g.alphaMap.value = p.alphaMap), p.alphaTest > 0 && (g.alphaTest.value = p.alphaTest); - let _; - p.map ? _ = p.map : p.alphaMap && (_ = p.alphaMap), _ !== void 0 && (_.matrixAutoUpdate === !0 && _.updateMatrix(), g.uvTransform.value.copy(_.matrix)); + g.diffuse.value.copy(p.color), g.opacity.value = p.opacity, p.map && (g.map.value = p.map, t(p.map, g.mapTransform)); } - function l(g, p) { - p.emissiveMap && (g.emissiveMap.value = p.emissiveMap); + function o(g, p) { + g.dashSize.value = p.dashSize, g.totalSize.value = p.dashSize + p.gapSize, g.scale.value = p.scale; + } + function c(g, p, v, x) { + g.diffuse.value.copy(p.color), g.opacity.value = p.opacity, g.size.value = p.size * v, g.scale.value = x * .5, p.map && (g.map.value = p.map, t(p.map, g.uvTransform)), p.alphaMap && (g.alphaMap.value = p.alphaMap, t(p.alphaMap, g.alphaMapTransform)), p.alphaTest > 0 && (g.alphaTest.value = p.alphaTest); } - function c(g, p) { - g.specular.value.copy(p.specular), g.shininess.value = Math.max(p.shininess, 1e-4), p.emissiveMap && (g.emissiveMap.value = p.emissiveMap), p.bumpMap && (g.bumpMap.value = p.bumpMap, g.bumpScale.value = p.bumpScale, p.side === it && (g.bumpScale.value *= -1)), p.normalMap && (g.normalMap.value = p.normalMap, g.normalScale.value.copy(p.normalScale), p.side === it && g.normalScale.value.negate()), p.displacementMap && (g.displacementMap.value = p.displacementMap, g.displacementScale.value = p.displacementScale, g.displacementBias.value = p.displacementBias); + function l(g, p) { + g.diffuse.value.copy(p.color), g.opacity.value = p.opacity, g.rotation.value = p.rotation, p.map && (g.map.value = p.map, t(p.map, g.mapTransform)), p.alphaMap && (g.alphaMap.value = p.alphaMap, t(p.alphaMap, g.alphaMapTransform)), p.alphaTest > 0 && (g.alphaTest.value = p.alphaTest); } function h(g, p) { - p.gradientMap && (g.gradientMap.value = p.gradientMap), p.emissiveMap && (g.emissiveMap.value = p.emissiveMap), p.bumpMap && (g.bumpMap.value = p.bumpMap, g.bumpScale.value = p.bumpScale, p.side === it && (g.bumpScale.value *= -1)), p.normalMap && (g.normalMap.value = p.normalMap, g.normalScale.value.copy(p.normalScale), p.side === it && g.normalScale.value.negate()), p.displacementMap && (g.displacementMap.value = p.displacementMap, g.displacementScale.value = p.displacementScale, g.displacementBias.value = p.displacementBias); + g.specular.value.copy(p.specular), g.shininess.value = Math.max(p.shininess, 1e-4); } function u(g, p) { - g.roughness.value = p.roughness, g.metalness.value = p.metalness, p.roughnessMap && (g.roughnessMap.value = p.roughnessMap), p.metalnessMap && (g.metalnessMap.value = p.metalnessMap), p.emissiveMap && (g.emissiveMap.value = p.emissiveMap), p.bumpMap && (g.bumpMap.value = p.bumpMap, g.bumpScale.value = p.bumpScale, p.side === it && (g.bumpScale.value *= -1)), p.normalMap && (g.normalMap.value = p.normalMap, g.normalScale.value.copy(p.normalScale), p.side === it && g.normalScale.value.negate()), p.displacementMap && (g.displacementMap.value = p.displacementMap, g.displacementScale.value = p.displacementScale, g.displacementBias.value = p.displacementBias), s.get(p).envMap && (g.envMapIntensity.value = p.envMapIntensity); + p.gradientMap && (g.gradientMap.value = p.gradientMap); } - function d(g, p, _) { - u(g, p), g.ior.value = p.ior, p.sheen > 0 && (g.sheenColor.value.copy(p.sheenColor).multiplyScalar(p.sheen), g.sheenRoughness.value = p.sheenRoughness, p.sheenColorMap && (g.sheenColorMap.value = p.sheenColorMap), p.sheenRoughnessMap && (g.sheenRoughnessMap.value = p.sheenRoughnessMap)), p.clearcoat > 0 && (g.clearcoat.value = p.clearcoat, g.clearcoatRoughness.value = p.clearcoatRoughness, p.clearcoatMap && (g.clearcoatMap.value = p.clearcoatMap), p.clearcoatRoughnessMap && (g.clearcoatRoughnessMap.value = p.clearcoatRoughnessMap), p.clearcoatNormalMap && (g.clearcoatNormalScale.value.copy(p.clearcoatNormalScale), g.clearcoatNormalMap.value = p.clearcoatNormalMap, p.side === it && g.clearcoatNormalScale.value.negate())), p.transmission > 0 && (g.transmission.value = p.transmission, g.transmissionSamplerMap.value = _.texture, g.transmissionSamplerSize.value.set(_.width, _.height), p.transmissionMap && (g.transmissionMap.value = p.transmissionMap), g.thickness.value = p.thickness, p.thicknessMap && (g.thicknessMap.value = p.thicknessMap), g.attenuationDistance.value = p.attenuationDistance, g.attenuationColor.value.copy(p.attenuationColor)), g.specularIntensity.value = p.specularIntensity, g.specularColor.value.copy(p.specularColor), p.specularIntensityMap && (g.specularIntensityMap.value = p.specularIntensityMap), p.specularColorMap && (g.specularColorMap.value = p.specularColorMap); + function d(g, p) { + g.metalness.value = p.metalness, p.metalnessMap && (g.metalnessMap.value = p.metalnessMap, t(p.metalnessMap, g.metalnessMapTransform)), g.roughness.value = p.roughness, p.roughnessMap && (g.roughnessMap.value = p.roughnessMap, t(p.roughnessMap, g.roughnessMapTransform)), e.get(p).envMap && (g.envMapIntensity.value = p.envMapIntensity); } - function f(g, p) { - p.matcap && (g.matcap.value = p.matcap), p.bumpMap && (g.bumpMap.value = p.bumpMap, g.bumpScale.value = p.bumpScale, p.side === it && (g.bumpScale.value *= -1)), p.normalMap && (g.normalMap.value = p.normalMap, g.normalScale.value.copy(p.normalScale), p.side === it && g.normalScale.value.negate()), p.displacementMap && (g.displacementMap.value = p.displacementMap, g.displacementScale.value = p.displacementScale, g.displacementBias.value = p.displacementBias); + function f(g, p, v) { + g.ior.value = p.ior, p.sheen > 0 && (g.sheenColor.value.copy(p.sheenColor).multiplyScalar(p.sheen), g.sheenRoughness.value = p.sheenRoughness, p.sheenColorMap && (g.sheenColorMap.value = p.sheenColorMap, t(p.sheenColorMap, g.sheenColorMapTransform)), p.sheenRoughnessMap && (g.sheenRoughnessMap.value = p.sheenRoughnessMap, t(p.sheenRoughnessMap, g.sheenRoughnessMapTransform))), p.clearcoat > 0 && (g.clearcoat.value = p.clearcoat, g.clearcoatRoughness.value = p.clearcoatRoughness, p.clearcoatMap && (g.clearcoatMap.value = p.clearcoatMap, t(p.clearcoatMap, g.clearcoatMapTransform)), p.clearcoatRoughnessMap && (g.clearcoatRoughnessMap.value = p.clearcoatRoughnessMap, t(p.clearcoatRoughnessMap, g.clearcoatRoughnessMapTransform)), p.clearcoatNormalMap && (g.clearcoatNormalMap.value = p.clearcoatNormalMap, t(p.clearcoatNormalMap, g.clearcoatNormalMapTransform), g.clearcoatNormalScale.value.copy(p.clearcoatNormalScale), p.side === Ft && g.clearcoatNormalScale.value.negate())), p.iridescence > 0 && (g.iridescence.value = p.iridescence, g.iridescenceIOR.value = p.iridescenceIOR, g.iridescenceThicknessMinimum.value = p.iridescenceThicknessRange[0], g.iridescenceThicknessMaximum.value = p.iridescenceThicknessRange[1], p.iridescenceMap && (g.iridescenceMap.value = p.iridescenceMap, t(p.iridescenceMap, g.iridescenceMapTransform)), p.iridescenceThicknessMap && (g.iridescenceThicknessMap.value = p.iridescenceThicknessMap, t(p.iridescenceThicknessMap, g.iridescenceThicknessMapTransform))), p.transmission > 0 && (g.transmission.value = p.transmission, g.transmissionSamplerMap.value = v.texture, g.transmissionSamplerSize.value.set(v.width, v.height), p.transmissionMap && (g.transmissionMap.value = p.transmissionMap, t(p.transmissionMap, g.transmissionMapTransform)), g.thickness.value = p.thickness, p.thicknessMap && (g.thicknessMap.value = p.thicknessMap, t(p.thicknessMap, g.thicknessMapTransform)), g.attenuationDistance.value = p.attenuationDistance, g.attenuationColor.value.copy(p.attenuationColor)), p.anisotropy > 0 && (g.anisotropyVector.value.set(p.anisotropy * Math.cos(p.anisotropyRotation), p.anisotropy * Math.sin(p.anisotropyRotation)), p.anisotropyMap && (g.anisotropyMap.value = p.anisotropyMap, t(p.anisotropyMap, g.anisotropyMapTransform))), g.specularIntensity.value = p.specularIntensity, g.specularColor.value.copy(p.specularColor), p.specularColorMap && (g.specularColorMap.value = p.specularColorMap, t(p.specularColorMap, g.specularColorMapTransform)), p.specularIntensityMap && (g.specularIntensityMap.value = p.specularIntensityMap, t(p.specularIntensityMap, g.specularIntensityMapTransform)); } function m(g, p) { - p.displacementMap && (g.displacementMap.value = p.displacementMap, g.displacementScale.value = p.displacementScale, g.displacementBias.value = p.displacementBias); - } - function x(g, p) { - p.displacementMap && (g.displacementMap.value = p.displacementMap, g.displacementScale.value = p.displacementScale, g.displacementBias.value = p.displacementBias), g.referencePosition.value.copy(p.referencePosition), g.nearDistance.value = p.nearDistance, g.farDistance.value = p.farDistance; + p.matcap && (g.matcap.value = p.matcap); } - function v(g, p) { - p.bumpMap && (g.bumpMap.value = p.bumpMap, g.bumpScale.value = p.bumpScale, p.side === it && (g.bumpScale.value *= -1)), p.normalMap && (g.normalMap.value = p.normalMap, g.normalScale.value.copy(p.normalScale), p.side === it && g.normalScale.value.negate()), p.displacementMap && (g.displacementMap.value = p.displacementMap, g.displacementScale.value = p.displacementScale, g.displacementBias.value = p.displacementBias); + function _(g, p) { + let v = e.get(p).light; + g.referencePosition.value.setFromMatrixPosition(v.matrixWorld), g.nearDistance.value = v.shadow.camera.near, g.farDistance.value = v.shadow.camera.far; } return { - refreshFogUniforms: e, - refreshMaterialUniforms: t + refreshFogUniforms: n, + refreshMaterialUniforms: i }; } -function Lx() { - let s = qs("canvas"); - return s.style.display = "block", s; -} -function qe(s = {}) { - let e = s.canvas !== void 0 ? s.canvas : Lx(), t = s.context !== void 0 ? s.context : null, n = s.alpha !== void 0 ? s.alpha : !1, i = s.depth !== void 0 ? s.depth : !0, r = s.stencil !== void 0 ? s.stencil : !0, o = s.antialias !== void 0 ? s.antialias : !1, a = s.premultipliedAlpha !== void 0 ? s.premultipliedAlpha : !0, l = s.preserveDrawingBuffer !== void 0 ? s.preserveDrawingBuffer : !1, c = s.powerPreference !== void 0 ? s.powerPreference : "default", h = s.failIfMajorPerformanceCaveat !== void 0 ? s.failIfMajorPerformanceCaveat : !1, u = null, d = null, f = [], m = []; - this.domElement = e, this.debug = { - checkShaderErrors: !0 - }, this.autoClear = !0, this.autoClearColor = !0, this.autoClearDepth = !0, this.autoClearStencil = !0, this.sortObjects = !0, this.clippingPlanes = [], this.localClippingEnabled = !1, this.outputEncoding = Nt, this.physicallyCorrectLights = !1, this.toneMapping = _n, this.toneMappingExposure = 1; - let x = this, v = !1, g = 0, p = 0, _ = null, y = -1, b = null, A = new Ve, L = new Ve, I = null, k = e.width, B = e.height, P = 1, w = null, E = null, D = new Ve(0, 0, k, B), U = new Ve(0, 0, k, B), F = !1, O = [], ne = new Dr, ce = !1, V = !1, W = null, he = new pe, le = new M, fe = { - background: null, - fog: null, - environment: null, - overrideMaterial: null, - isScene: !0 - }; - function Be() { - return _ === null ? P : 1; +function G0(s1, e, t, n) { + let i = {}, r = {}, a = [], o = t.isWebGL2 ? s1.getParameter(s1.MAX_UNIFORM_BUFFER_BINDINGS) : 0; + function c(v, x) { + let y = x.program; + n.uniformBlockBinding(v, y); + } + function l(v, x) { + let y = i[v.id]; + y === void 0 && (m(v), y = h(v), i[v.id] = y, v.addEventListener("dispose", g)); + let b = x.program; + n.updateUBOMapping(v, b); + let w = e.render.frame; + r[v.id] !== w && (d(v), r[v.id] = w); + } + function h(v) { + let x = u(); + v.__bindingPointIndex = x; + let y = s1.createBuffer(), b = v.__size, w = v.usage; + return s1.bindBuffer(s1.UNIFORM_BUFFER, y), s1.bufferData(s1.UNIFORM_BUFFER, b, w), s1.bindBuffer(s1.UNIFORM_BUFFER, null), s1.bindBufferBase(s1.UNIFORM_BUFFER, x, y), y; } - let Y = t; - function Ce(S, N) { - for(let H = 0; H < S.length; H++){ - let z = S[H], q = e.getContext(z, N); - if (q !== null) return q; + function u() { + for(let v = 0; v < o; v++)if (a.indexOf(v) === -1) return a.push(v), v; + return console.error("THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached."), 0; + } + function d(v) { + let x = i[v.id], y = v.uniforms, b = v.__cache; + s1.bindBuffer(s1.UNIFORM_BUFFER, x); + for(let w = 0, R = y.length; w < R; w++){ + let I = y[w]; + if (f(I, w, b) === !0) { + let M = I.__offset, T = Array.isArray(I.value) ? I.value : [ + I.value + ], O = 0; + for(let Y = 0; Y < T.length; Y++){ + let $ = T[Y], U = _($); + typeof $ == "number" ? (I.__data[0] = $, s1.bufferSubData(s1.UNIFORM_BUFFER, M + O, I.__data)) : $.isMatrix3 ? (I.__data[0] = $.elements[0], I.__data[1] = $.elements[1], I.__data[2] = $.elements[2], I.__data[3] = $.elements[0], I.__data[4] = $.elements[3], I.__data[5] = $.elements[4], I.__data[6] = $.elements[5], I.__data[7] = $.elements[0], I.__data[8] = $.elements[6], I.__data[9] = $.elements[7], I.__data[10] = $.elements[8], I.__data[11] = $.elements[0]) : ($.toArray(I.__data, O), O += U.storage / Float32Array.BYTES_PER_ELEMENT); + } + s1.bufferSubData(s1.UNIFORM_BUFFER, M, I.__data); + } } - return null; + s1.bindBuffer(s1.UNIFORM_BUFFER, null); } - try { - let S = { - alpha: n, - depth: i, - stencil: r, - antialias: o, - premultipliedAlpha: a, - preserveDrawingBuffer: l, - powerPreference: c, - failIfMajorPerformanceCaveat: h - }; - if ("setAttribute" in e && e.setAttribute("data-engine", `three.js r${ca}`), e.addEventListener("webglcontextlost", Ee, !1), e.addEventListener("webglcontextrestored", me, !1), Y === null) { - let N = [ - "webgl2", - "webgl", - "experimental-webgl" + function f(v, x, y) { + let b = v.value; + if (y[x] === void 0) { + if (typeof b == "number") y[x] = b; + else { + let w = Array.isArray(b) ? b : [ + b + ], R = []; + for(let I = 0; I < w.length; I++)R.push(w[I].clone()); + y[x] = R; + } + return !0; + } else if (typeof b == "number") { + if (y[x] !== b) return y[x] = b, !0; + } else { + let w = Array.isArray(y[x]) ? y[x] : [ + y[x] + ], R = Array.isArray(b) ? b : [ + b ]; - if (x.isWebGL1Renderer === !0 && N.shift(), Y = Ce(N, S), Y === null) throw Ce(N) ? new Error("Error creating WebGL context with your selected attributes.") : new Error("Error creating WebGL context."); + for(let I = 0; I < w.length; I++){ + let M = w[I]; + if (M.equals(R[I]) === !1) return M.copy(R[I]), !0; + } } - Y.getShaderPrecisionFormat === void 0 && (Y.getShaderPrecisionFormat = function() { - return { - rangeMin: 1, - rangeMax: 1, - precision: 1 - }; - }); - } catch (S) { - throw console.error("THREE.WebGLRenderer: " + S.message), S; + return !1; } - let ye, ge, xe, Oe, G, j, K, ue, se, Se, Te, Pe, Ye, C, T, J, $, re, Z, Me, ve, te, R; - function ee() { - ye = new Qm(Y), ge = new Xm(Y, ye, s), ye.init(ge), te = new Ex(Y, ye, ge), xe = new Sx(Y, ye, ge), O[0] = 1029, Oe = new tg(Y), G = new fx, j = new Tx(Y, ye, xe, G, ge, te, Oe), K = new Ym(x), ue = new jm(x), se = new gf(Y, ge), R = new Wm(Y, ye, se, ge), Se = new Km(Y, se, Oe, R), Te = new sg(Y, Se, se, Oe), Z = new rg(Y, ge, j), J = new Jm(G), Pe = new dx(x, K, ue, ye, ge, R, J), Ye = new Cx(G), C = new mx, T = new Mx(ye, ge), re = new Vm(x, K, xe, Te, a), $ = new yh(x, Te, ge), Me = new qm(Y, ye, Oe, ge), ve = new eg(Y, ye, Oe, ge), Oe.programs = Pe.programs, x.capabilities = ge, x.extensions = ye, x.properties = G, x.renderLists = C, x.shadowMap = $, x.state = xe, x.info = Oe; - } - ee(); - let Q = new vh(x, Y); - this.xr = Q, this.getContext = function() { - return Y; - }, this.getContextAttributes = function() { - return Y.getContextAttributes(); - }, this.forceContextLoss = function() { - let S = ye.get("WEBGL_lose_context"); - S && S.loseContext(); - }, this.forceContextRestore = function() { - let S = ye.get("WEBGL_lose_context"); - S && S.restoreContext(); - }, this.getPixelRatio = function() { - return P; - }, this.setPixelRatio = function(S) { - S !== void 0 && (P = S, this.setSize(k, B, !1)); - }, this.getSize = function(S) { - return S.set(k, B); - }, this.setSize = function(S, N, H) { - if (Q.isPresenting) { - console.warn("THREE.WebGLRenderer: Can't change size while VR device is presenting."); - return; + function m(v) { + let x = v.uniforms, y = 0, b = 16, w = 0; + for(let R = 0, I = x.length; R < I; R++){ + let M = x[R], T = { + boundary: 0, + storage: 0 + }, O = Array.isArray(M.value) ? M.value : [ + M.value + ]; + for(let Y = 0, $ = O.length; Y < $; Y++){ + let U = O[Y], z = _(U); + T.boundary += z.boundary, T.storage += z.storage; + } + if (M.__data = new Float32Array(T.storage / Float32Array.BYTES_PER_ELEMENT), M.__offset = y, R > 0) { + w = y % b; + let Y = b - w; + w !== 0 && Y - T.boundary < 0 && (y += b - w, M.__offset = y); + } + y += T.storage; } - k = S, B = N, e.width = Math.floor(S * P), e.height = Math.floor(N * P), H !== !1 && (e.style.width = S + "px", e.style.height = N + "px"), this.setViewport(0, 0, S, N); - }, this.getDrawingBufferSize = function(S) { - return S.set(k * P, B * P).floor(); - }, this.setDrawingBufferSize = function(S, N, H) { - k = S, B = N, P = H, e.width = Math.floor(S * H), e.height = Math.floor(N * H), this.setViewport(0, 0, S, N); - }, this.getCurrentViewport = function(S) { - return S.copy(A); - }, this.getViewport = function(S) { - return S.copy(D); - }, this.setViewport = function(S, N, H, z) { - S.isVector4 ? D.set(S.x, S.y, S.z, S.w) : D.set(S, N, H, z), xe.viewport(A.copy(D).multiplyScalar(P).floor()); - }, this.getScissor = function(S) { - return S.copy(U); - }, this.setScissor = function(S, N, H, z) { - S.isVector4 ? U.set(S.x, S.y, S.z, S.w) : U.set(S, N, H, z), xe.scissor(L.copy(U).multiplyScalar(P).floor()); - }, this.getScissorTest = function() { - return F; - }, this.setScissorTest = function(S) { - xe.setScissorTest(F = S); - }, this.setOpaqueSort = function(S) { - w = S; - }, this.setTransparentSort = function(S) { - E = S; - }, this.getClearColor = function(S) { - return S.copy(re.getClearColor()); - }, this.setClearColor = function() { - re.setClearColor.apply(re, arguments); - }, this.getClearAlpha = function() { - return re.getClearAlpha(); - }, this.setClearAlpha = function() { - re.setClearAlpha.apply(re, arguments); - }, this.clear = function(S, N, H) { - let z = 0; - (S === void 0 || S) && (z |= 16384), (N === void 0 || N) && (z |= 256), (H === void 0 || H) && (z |= 1024), Y.clear(z); - }, this.clearColor = function() { - this.clear(!0, !1, !1); - }, this.clearDepth = function() { - this.clear(!1, !0, !1); - }, this.clearStencil = function() { - this.clear(!1, !1, !0); - }, this.dispose = function() { - e.removeEventListener("webglcontextlost", Ee, !1), e.removeEventListener("webglcontextrestored", me, !1), C.dispose(), T.dispose(), G.dispose(), K.dispose(), ue.dispose(), Te.dispose(), R.dispose(), Pe.dispose(), Q.dispose(), Q.removeEventListener("sessionstart", Ut), Q.removeEventListener("sessionend", Ot), W && (W.dispose(), W = null), Ln.stop(); - }; - function Ee(S) { - S.preventDefault(), console.log("THREE.WebGLRenderer: Context Lost."), v = !0; - } - function me() { - console.log("THREE.WebGLRenderer: Context Restored."), v = !1; - let S = Oe.autoReset, N = $.enabled, H = $.autoUpdate, z = $.needsUpdate, q = $.type; - ee(), Oe.autoReset = S, $.enabled = N, $.autoUpdate = H, $.needsUpdate = z, $.type = q; - } - function Re(S) { - let N = S.target; - N.removeEventListener("dispose", Re), oe(N); - } - function oe(S) { - Le(S), G.remove(S); - } - function Le(S) { - let N = G.get(S).programs; - N !== void 0 && (N.forEach(function(H) { - Pe.releaseProgram(H); - }), S.isShaderMaterial && Pe.releaseShaderCache(S)); - } - this.renderBufferDirect = function(S, N, H, z, q, be) { - N === null && (N = fe); - let Ae = q.isMesh && q.matrixWorld.determinant() < 0, Ie = lu(S, N, H, z, q); - xe.setMaterial(z, Ae); - let we = H.index, He = H.attributes.position; - if (we === null) { - if (He === void 0 || He.count === 0) return; - } else if (we.count === 0) return; - let De = 1; - z.wireframe === !0 && (we = Se.getWireframeAttribute(H), De = 2), R.setup(q, z, Ie, H, we); - let ze, je = Me; - we !== null && (ze = se.get(we), je = ve, je.setIndex(ze)); - let Rn = we !== null ? we.count : He.count, ei = H.drawRange.start * De, Ge = H.drawRange.count * De, Ht = be !== null ? be.start * De : 0, at = be !== null ? be.count * De : 1 / 0, kt = Math.max(ei, Ht), Gr = Math.min(Rn, ei + Ge, Ht + at) - 1, Gt = Math.max(0, Gr - kt + 1); - if (Gt !== 0) { - if (q.isMesh) z.wireframe === !0 ? (xe.setLineWidth(z.wireframeLinewidth * Be()), je.setMode(1)) : je.setMode(4); - else if (q.isLine) { - let Zt = z.linewidth; - Zt === void 0 && (Zt = 1), xe.setLineWidth(Zt * Be()), q.isLineSegments ? je.setMode(1) : q.isLineLoop ? je.setMode(2) : je.setMode(3); - } else q.isPoints ? je.setMode(0) : q.isSprite && je.setMode(4); - if (q.isInstancedMesh) je.renderInstances(kt, Gt, q.count); - else if (H.isInstancedBufferGeometry) { - let Zt = Math.min(H.instanceCount, H._maxInstanceCount); - je.renderInstances(kt, Gt, Zt); - } else je.render(kt, Gt); - } - }, this.compile = function(S, N) { - d = T.get(S), d.init(), m.push(d), S.traverseVisible(function(H) { - H.isLight && H.layers.test(N.layers) && (d.pushLight(H), H.castShadow && d.pushShadow(H)); - }), d.setupLights(x.physicallyCorrectLights), S.traverse(function(H) { - let z = H.material; - if (z) if (Array.isArray(z)) for(let q = 0; q < z.length; q++){ - let be = z[q]; - xo(be, S, H); - } - else xo(z, S, H); - }), m.pop(), d = null; + return w = y % b, w > 0 && (y += b - w), v.__size = y, v.__cache = {}, this; + } + function _(v) { + let x = { + boundary: 0, + storage: 0 + }; + return typeof v == "number" ? (x.boundary = 4, x.storage = 4) : v.isVector2 ? (x.boundary = 8, x.storage = 8) : v.isVector3 || v.isColor ? (x.boundary = 16, x.storage = 12) : v.isVector4 ? (x.boundary = 16, x.storage = 16) : v.isMatrix3 ? (x.boundary = 48, x.storage = 48) : v.isMatrix4 ? (x.boundary = 64, x.storage = 64) : v.isTexture ? console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.") : console.warn("THREE.WebGLRenderer: Unsupported uniform value type.", v), x; + } + function g(v) { + let x = v.target; + x.removeEventListener("dispose", g); + let y = a.indexOf(x.__bindingPointIndex); + a.splice(y, 1), s1.deleteBuffer(i[x.id]), delete i[x.id], delete r[x.id]; + } + function p() { + for(let v in i)s1.deleteBuffer(i[v]); + a = [], i = {}, r = {}; + } + return { + bind: c, + update: l, + dispose: p }; - let Xe = null; - function We(S) { - Xe && Xe(S); - } - function Ut() { - Ln.stop(); - } - function Ot() { - Ln.start(); - } - let Ln = new rh; - Ln.setAnimationLoop(We), typeof window < "u" && Ln.setContext(window), this.setAnimationLoop = function(S) { - Xe = S, Q.setAnimationLoop(S), S === null ? Ln.stop() : Ln.start(); - }, Q.addEventListener("sessionstart", Ut), Q.addEventListener("sessionend", Ot), this.render = function(S, N) { - if (N !== void 0 && N.isCamera !== !0) { - console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera."); - return; +} +var Ro = class { + constructor(e = {}){ + let { canvas: t = tp() , context: n = null , depth: i = !0 , stencil: r = !0 , alpha: a = !1 , antialias: o = !1 , premultipliedAlpha: c = !0 , preserveDrawingBuffer: l = !1 , powerPreference: h = "default" , failIfMajorPerformanceCaveat: u = !1 } = e; + this.isWebGLRenderer = !0; + let d; + n !== null ? d = n.getContextAttributes().alpha : d = a; + let f = new Uint32Array(4), m = new Int32Array(4), _ = null, g = null, p = [], v = []; + this.domElement = t, this.debug = { + checkShaderErrors: !0, + onShaderError: null + }, this.autoClear = !0, this.autoClearColor = !0, this.autoClearDepth = !0, this.autoClearStencil = !0, this.sortObjects = !0, this.clippingPlanes = [], this.localClippingEnabled = !1, this._outputColorSpace = vt, this._useLegacyLights = !1, this.toneMapping = Nn, this.toneMappingExposure = 1; + let x = this, y = !1, b = 0, w = 0, R = null, I = -1, M = null, T = new je, O = new je, Y = null, $ = new pe(0), U = 0, z = t.width, q = t.height, H = 1, ne = null, W = null, K = new je(0, 0, z, q), D = new je(0, 0, z, q), G = !1, he = new Ps, fe = !1, _e = !1, we = null, Ee = new ze, Te = new Z, Ye = new A, it = { + background: null, + fog: null, + environment: null, + overrideMaterial: null, + isScene: !0 + }; + function Ce() { + return R === null ? H : 1; + } + let L = n; + function oe(E, N) { + for(let V = 0; V < E.length; V++){ + let F = E[V], k = t.getContext(F, N); + if (k !== null) return k; + } + return null; } - if (v === !0) return; - S.autoUpdate === !0 && S.updateMatrixWorld(), N.parent === null && N.updateMatrixWorld(), Q.enabled === !0 && Q.isPresenting === !0 && (Q.cameraAutoUpdate === !0 && Q.updateCamera(N), N = Q.getCamera()), S.isScene === !0 && S.onBeforeRender(x, S, N, _), d = T.get(S, m.length), d.init(), m.push(d), he.multiplyMatrices(N.projectionMatrix, N.matrixWorldInverse), ne.setFromProjectionMatrix(he), V = this.localClippingEnabled, ce = J.init(this.clippingPlanes, V, N), u = C.get(S, f.length), u.init(), f.push(u), Qa(S, N, 0, x.sortObjects), u.finish(), x.sortObjects === !0 && u.sort(w, E), ce === !0 && J.beginShadows(); - let H = d.state.shadowsArray; - if ($.render(H, S, N), ce === !0 && J.endShadows(), this.info.autoReset === !0 && this.info.reset(), re.render(u, S), d.setupLights(x.physicallyCorrectLights), N.isArrayCamera) { - let z = N.cameras; - for(let q = 0, be = z.length; q < be; q++){ - let Ae = z[q]; - Ka(u, S, Ae, Ae.viewport); - } - } else Ka(u, S, N); - _ !== null && (j.updateMultisampleRenderTarget(_), j.updateRenderTargetMipmap(_)), S.isScene === !0 && S.onAfterRender(x, S, N), xe.buffers.depth.setTest(!0), xe.buffers.depth.setMask(!0), xe.buffers.color.setMask(!0), xe.setPolygonOffset(!1), R.resetDefaultState(), y = -1, b = null, m.pop(), m.length > 0 ? d = m[m.length - 1] : d = null, f.pop(), f.length > 0 ? u = f[f.length - 1] : u = null; - }; - function Qa(S, N, H, z) { - if (S.visible === !1) return; - if (S.layers.test(N.layers)) { - if (S.isGroup) H = S.renderOrder; - else if (S.isLOD) S.autoUpdate === !0 && S.update(N); - else if (S.isLight) d.pushLight(S), S.castShadow && d.pushShadow(S); - else if (S.isSprite) { - if (!S.frustumCulled || ne.intersectsSprite(S)) { - z && le.setFromMatrixPosition(S.matrixWorld).applyMatrix4(he); - let Ae = Te.update(S), Ie = S.material; - Ie.visible && u.push(S, Ae, Ie, H, le.z, null); + try { + let E = { + alpha: !0, + depth: i, + stencil: r, + antialias: o, + premultipliedAlpha: c, + preserveDrawingBuffer: l, + powerPreference: h, + failIfMajorPerformanceCaveat: u + }; + if ("setAttribute" in t && t.setAttribute("data-engine", `three.js r${Hc}`), t.addEventListener("webglcontextlost", ce, !1), t.addEventListener("webglcontextrestored", ae, !1), t.addEventListener("webglcontextcreationerror", ge, !1), L === null) { + let N = [ + "webgl2", + "webgl", + "experimental-webgl" + ]; + if (x.isWebGL1Renderer === !0 && N.shift(), L = oe(N, E), L === null) throw oe(N) ? new Error("Error creating WebGL context with your selected attributes.") : new Error("Error creating WebGL context."); + } + typeof WebGLRenderingContext < "u" && L instanceof WebGLRenderingContext && console.warn("THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163."), L.getShaderPrecisionFormat === void 0 && (L.getShaderPrecisionFormat = function() { + return { + rangeMin: 1, + rangeMax: 1, + precision: 1 + }; + }); + } catch (E) { + throw console.error("THREE.WebGLRenderer: " + E.message), E; + } + let X, ie, J, Se, me, ye, Ne, qe, rt, C, S, B, ee, j, te, Me, re, de, Le, Ze, se, $e, Oe, Ie; + function Re() { + X = new h_(L), ie = new s_(L, X, e), X.init(ie), $e = new V0(L, X, ie), J = new B0(L, X, ie), Se = new f_(L), me = new w0, ye = new z0(L, X, J, me, ie, $e, Se), Ne = new a_(x), qe = new l_(x), rt = new bp(L, ie), Oe = new n_(L, X, rt, ie), C = new u_(L, rt, Se, Oe), S = new __(L, C, rt, Se), Le = new g_(L, ie, ye), Me = new r_(me), B = new T0(x, Ne, qe, X, ie, Oe, Me), ee = new H0(x, me), j = new R0, te = new D0(X, ie), de = new t_(x, Ne, qe, J, S, d, c), re = new F0(x, S, ie), Ie = new G0(L, Se, ie, J), Ze = new i_(L, X, Se, ie), se = new d_(L, X, Se, ie), Se.programs = B.programs, x.capabilities = ie, x.extensions = X, x.properties = me, x.renderLists = j, x.shadowMap = re, x.state = J, x.info = Se; + } + Re(); + let P = new Ao(x, L); + this.xr = P, this.getContext = function() { + return L; + }, this.getContextAttributes = function() { + return L.getContextAttributes(); + }, this.forceContextLoss = function() { + let E = X.get("WEBGL_lose_context"); + E && E.loseContext(); + }, this.forceContextRestore = function() { + let E = X.get("WEBGL_lose_context"); + E && E.restoreContext(); + }, this.getPixelRatio = function() { + return H; + }, this.setPixelRatio = function(E) { + E !== void 0 && (H = E, this.setSize(z, q, !1)); + }, this.getSize = function(E) { + return E.set(z, q); + }, this.setSize = function(E, N, V = !0) { + if (P.isPresenting) { + console.warn("THREE.WebGLRenderer: Can't change size while VR device is presenting."); + return; + } + z = E, q = N, t.width = Math.floor(E * H), t.height = Math.floor(N * H), V === !0 && (t.style.width = E + "px", t.style.height = N + "px"), this.setViewport(0, 0, E, N); + }, this.getDrawingBufferSize = function(E) { + return E.set(z * H, q * H).floor(); + }, this.setDrawingBufferSize = function(E, N, V) { + z = E, q = N, H = V, t.width = Math.floor(E * V), t.height = Math.floor(N * V), this.setViewport(0, 0, E, N); + }, this.getCurrentViewport = function(E) { + return E.copy(T); + }, this.getViewport = function(E) { + return E.copy(K); + }, this.setViewport = function(E, N, V, F) { + E.isVector4 ? K.set(E.x, E.y, E.z, E.w) : K.set(E, N, V, F), J.viewport(T.copy(K).multiplyScalar(H).floor()); + }, this.getScissor = function(E) { + return E.copy(D); + }, this.setScissor = function(E, N, V, F) { + E.isVector4 ? D.set(E.x, E.y, E.z, E.w) : D.set(E, N, V, F), J.scissor(O.copy(D).multiplyScalar(H).floor()); + }, this.getScissorTest = function() { + return G; + }, this.setScissorTest = function(E) { + J.setScissorTest(G = E); + }, this.setOpaqueSort = function(E) { + ne = E; + }, this.setTransparentSort = function(E) { + W = E; + }, this.getClearColor = function(E) { + return E.copy(de.getClearColor()); + }, this.setClearColor = function() { + de.setClearColor.apply(de, arguments); + }, this.getClearAlpha = function() { + return de.getClearAlpha(); + }, this.setClearAlpha = function() { + de.setClearAlpha.apply(de, arguments); + }, this.clear = function(E = !0, N = !0, V = !0) { + let F = 0; + if (E) { + let k = !1; + if (R !== null) { + let xe = R.texture.format; + k = xe === _d || xe === gd || xe === md; + } + if (k) { + let xe = R.texture.type, Ae = xe === On || xe === Ln || xe === Wc || xe === ii || xe === fd || xe === pd, Ue = de.getClearColor(), De = de.getClearAlpha(), We = Ue.r, Pe = Ue.g, Ve = Ue.b; + Ae ? (f[0] = We, f[1] = Pe, f[2] = Ve, f[3] = De, L.clearBufferuiv(L.COLOR, 0, f)) : (m[0] = We, m[1] = Pe, m[2] = Ve, m[3] = De, L.clearBufferiv(L.COLOR, 0, m)); + } else F |= L.COLOR_BUFFER_BIT; + } + N && (F |= L.DEPTH_BUFFER_BIT), V && (F |= L.STENCIL_BUFFER_BIT), L.clear(F); + }, this.clearColor = function() { + this.clear(!0, !1, !1); + }, this.clearDepth = function() { + this.clear(!1, !0, !1); + }, this.clearStencil = function() { + this.clear(!1, !1, !0); + }, this.dispose = function() { + t.removeEventListener("webglcontextlost", ce, !1), t.removeEventListener("webglcontextrestored", ae, !1), t.removeEventListener("webglcontextcreationerror", ge, !1), j.dispose(), te.dispose(), me.dispose(), Ne.dispose(), qe.dispose(), S.dispose(), Oe.dispose(), Ie.dispose(), B.dispose(), P.dispose(), P.removeEventListener("sessionstart", tt), P.removeEventListener("sessionend", tn), we && (we.dispose(), we = null), Rt.stop(); + }; + function ce(E) { + E.preventDefault(), console.log("THREE.WebGLRenderer: Context Lost."), y = !0; + } + function ae() { + console.log("THREE.WebGLRenderer: Context Restored."), y = !1; + let E = Se.autoReset, N = re.enabled, V = re.autoUpdate, F = re.needsUpdate, k = re.type; + Re(), Se.autoReset = E, re.enabled = N, re.autoUpdate = V, re.needsUpdate = F, re.type = k; + } + function ge(E) { + console.error("THREE.WebGLRenderer: A WebGL context could not be created. Reason: ", E.statusMessage); + } + function ue(E) { + let N = E.target; + N.removeEventListener("dispose", ue), Q(N); + } + function Q(E) { + be(E), me.remove(E); + } + function be(E) { + let N = me.get(E).programs; + N !== void 0 && (N.forEach(function(V) { + B.releaseProgram(V); + }), E.isShaderMaterial && B.releaseShaderCache(E)); + } + this.renderBufferDirect = function(E, N, V, F, k, xe) { + N === null && (N = it); + let Ae = k.isMesh && k.matrixWorld.determinant() < 0, Ue = Fd(E, N, V, F, k); + J.setMaterial(F, Ae); + let De = V.index, We = 1; + if (F.wireframe === !0) { + if (De = C.getWireframeAttribute(V), De === void 0) return; + We = 2; + } + let Pe = V.drawRange, Ve = V.attributes.position, at = Pe.start * We, lt = (Pe.start + Pe.count) * We; + xe !== null && (at = Math.max(at, xe.start * We), lt = Math.min(lt, (xe.start + xe.count) * We)), De !== null ? (at = Math.max(at, 0), lt = Math.min(lt, De.count)) : Ve != null && (at = Math.max(at, 0), lt = Math.min(lt, Ve.count)); + let Ht = lt - at; + if (Ht < 0 || Ht === 1 / 0) return; + Oe.setup(k, F, Ue, V, De); + let an, ut = Ze; + if (De !== null && (an = rt.get(De), ut = se, ut.setIndex(an)), k.isMesh) F.wireframe === !0 ? (J.setLineWidth(F.wireframeLinewidth * Ce()), ut.setMode(L.LINES)) : ut.setMode(L.TRIANGLES); + else if (k.isLine) { + let Xe = F.linewidth; + Xe === void 0 && (Xe = 1), J.setLineWidth(Xe * Ce()), k.isLineSegments ? ut.setMode(L.LINES) : k.isLineLoop ? ut.setMode(L.LINE_LOOP) : ut.setMode(L.LINE_STRIP); + } else k.isPoints ? ut.setMode(L.POINTS) : k.isSprite && ut.setMode(L.TRIANGLES); + if (k.isInstancedMesh) ut.renderInstances(at, Ht, k.count); + else if (V.isInstancedBufferGeometry) { + let Xe = V._maxInstanceCount !== void 0 ? V._maxInstanceCount : 1 / 0, Sa = Math.min(V.instanceCount, Xe); + ut.renderInstances(at, Ht, Sa); + } else ut.render(at, Ht); + }, this.compile = function(E, N) { + function V(F, k, xe) { + F.transparent === !0 && F.side === gn && F.forceSinglePass === !1 ? (F.side = Ft, F.needsUpdate = !0, Hs(F, k, xe), F.side = Bn, F.needsUpdate = !0, Hs(F, k, xe), F.side = gn) : Hs(F, k, xe); + } + g = te.get(E), g.init(), v.push(g), E.traverseVisible(function(F) { + F.isLight && F.layers.test(N.layers) && (g.pushLight(F), F.castShadow && g.pushShadow(F)); + }), g.setupLights(x._useLegacyLights), E.traverse(function(F) { + let k = F.material; + if (k) if (Array.isArray(k)) for(let xe = 0; xe < k.length; xe++){ + let Ae = k[xe]; + V(Ae, E, F); + } + else V(k, E, F); + }), v.pop(), g = null; + }; + let Fe = null; + function At(E) { + Fe && Fe(E); + } + function tt() { + Rt.stop(); + } + function tn() { + Rt.start(); + } + let Rt = new Ed; + Rt.setAnimationLoop(At), typeof self < "u" && Rt.setContext(self), this.setAnimationLoop = function(E) { + Fe = E, P.setAnimationLoop(E), E === null ? Rt.stop() : Rt.start(); + }, P.addEventListener("sessionstart", tt), P.addEventListener("sessionend", tn), this.render = function(E, N) { + if (N !== void 0 && N.isCamera !== !0) { + console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera."); + return; + } + if (y === !0) return; + E.matrixWorldAutoUpdate === !0 && E.updateMatrixWorld(), N.parent === null && N.matrixWorldAutoUpdate === !0 && N.updateMatrixWorld(), P.enabled === !0 && P.isPresenting === !0 && (P.cameraAutoUpdate === !0 && P.updateCamera(N), N = P.getCamera()), E.isScene === !0 && E.onBeforeRender(x, E, N, R), g = te.get(E, v.length), g.init(), v.push(g), Ee.multiplyMatrices(N.projectionMatrix, N.matrixWorldInverse), he.setFromProjectionMatrix(Ee), _e = this.localClippingEnabled, fe = Me.init(this.clippingPlanes, _e), _ = j.get(E, p.length), _.init(), p.push(_), jc(E, N, 0, x.sortObjects), _.finish(), x.sortObjects === !0 && _.sort(ne, W), this.info.render.frame++, fe === !0 && Me.beginShadows(); + let V = g.state.shadowsArray; + if (re.render(V, E, N), fe === !0 && Me.endShadows(), this.info.autoReset === !0 && this.info.reset(), de.render(_, E), g.setupLights(x._useLegacyLights), N.isArrayCamera) { + let F = N.cameras; + for(let k = 0, xe = F.length; k < xe; k++){ + let Ae = F[k]; + el(_, E, Ae, Ae.viewport); } - } else if ((S.isMesh || S.isLine || S.isPoints) && (S.isSkinnedMesh && S.skeleton.frame !== Oe.render.frame && (S.skeleton.update(), S.skeleton.frame = Oe.render.frame), !S.frustumCulled || ne.intersectsObject(S))) { - z && le.setFromMatrixPosition(S.matrixWorld).applyMatrix4(he); - let Ae = Te.update(S), Ie = S.material; - if (Array.isArray(Ie)) { - let we = Ae.groups; - for(let He = 0, De = we.length; He < De; He++){ - let ze = we[He], je = Ie[ze.materialIndex]; - je && je.visible && u.push(S, Ae, je, H, le.z, ze); + } else el(_, E, N); + R !== null && (ye.updateMultisampleRenderTarget(R), ye.updateRenderTargetMipmap(R)), E.isScene === !0 && E.onAfterRender(x, E, N), Oe.resetDefaultState(), I = -1, M = null, v.pop(), v.length > 0 ? g = v[v.length - 1] : g = null, p.pop(), p.length > 0 ? _ = p[p.length - 1] : _ = null; + }; + function jc(E, N, V, F) { + if (E.visible === !1) return; + if (E.layers.test(N.layers)) { + if (E.isGroup) V = E.renderOrder; + else if (E.isLOD) E.autoUpdate === !0 && E.update(N); + else if (E.isLight) g.pushLight(E), E.castShadow && g.pushShadow(E); + else if (E.isSprite) { + if (!E.frustumCulled || he.intersectsSprite(E)) { + F && Ye.setFromMatrixPosition(E.matrixWorld).applyMatrix4(Ee); + let Ae = S.update(E), Ue = E.material; + Ue.visible && _.push(E, Ae, Ue, V, Ye.z, null); } - } else Ie.visible && u.push(S, Ae, Ie, H, le.z, null); + } else if ((E.isMesh || E.isLine || E.isPoints) && (!E.frustumCulled || he.intersectsObject(E))) { + let Ae = S.update(E), Ue = E.material; + if (F && (E.boundingSphere !== void 0 ? (E.boundingSphere === null && E.computeBoundingSphere(), Ye.copy(E.boundingSphere.center)) : (Ae.boundingSphere === null && Ae.computeBoundingSphere(), Ye.copy(Ae.boundingSphere.center)), Ye.applyMatrix4(E.matrixWorld).applyMatrix4(Ee)), Array.isArray(Ue)) { + let De = Ae.groups; + for(let We = 0, Pe = De.length; We < Pe; We++){ + let Ve = De[We], at = Ue[Ve.materialIndex]; + at && at.visible && _.push(E, Ae, at, V, Ye.z, Ve); + } + } else Ue.visible && _.push(E, Ae, Ue, V, Ye.z, null); + } } + let xe = E.children; + for(let Ae = 0, Ue = xe.length; Ae < Ue; Ae++)jc(xe[Ae], N, V, F); } - let be = S.children; - for(let Ae = 0, Ie = be.length; Ae < Ie; Ae++)Qa(be[Ae], N, H, z); - } - function Ka(S, N, H, z) { - let q = S.opaque, be = S.transmissive, Ae = S.transparent; - d.setupLightsView(H), be.length > 0 && ou(q, N, H), z && xe.viewport(A.copy(z)), q.length > 0 && kr(q, N, H), be.length > 0 && kr(be, N, H), Ae.length > 0 && kr(Ae, N, H); - } - function ou(S, N, H) { - if (W === null) { - let Ae = o === !0 && ge.isWebGL2 === !0 ? Xs : At; - W = new Ae(1024, 1024, { - generateMipmaps: !0, - type: te.convert(kn) !== null ? kn : rn, - minFilter: Ui, - magFilter: rt, - wrapS: vt, - wrapT: vt, - useRenderToTexture: ye.has("WEBGL_multisampled_render_to_texture") - }); + function el(E, N, V, F) { + let k = E.opaque, xe = E.transmissive, Ae = E.transparent; + g.setupLightsView(V), fe === !0 && Me.setGlobalState(x.clippingPlanes, V), xe.length > 0 && Od(k, xe, N, V), F && J.viewport(T.copy(F)), k.length > 0 && ks(k, N, V), xe.length > 0 && ks(xe, N, V), Ae.length > 0 && ks(Ae, N, V), J.buffers.depth.setTest(!0), J.buffers.depth.setMask(!0), J.buffers.color.setMask(!0), J.setPolygonOffset(!1); } - let z = x.getRenderTarget(); - x.setRenderTarget(W), x.clear(); - let q = x.toneMapping; - x.toneMapping = _n, kr(S, N, H), x.toneMapping = q, j.updateMultisampleRenderTarget(W), j.updateRenderTargetMipmap(W), x.setRenderTarget(z); - } - function kr(S, N, H) { - let z = N.isScene === !0 ? N.overrideMaterial : null; - for(let q = 0, be = S.length; q < be; q++){ - let Ae = S[q], Ie = Ae.object, we = Ae.geometry, He = z === null ? Ae.material : z, De = Ae.group; - Ie.layers.test(H.layers) && au(Ie, N, H, we, He, De); - } - } - function au(S, N, H, z, q, be) { - S.onBeforeRender(x, N, H, z, q, be), S.modelViewMatrix.multiplyMatrices(H.matrixWorldInverse, S.matrixWorld), S.normalMatrix.getNormalMatrix(S.modelViewMatrix), q.onBeforeRender(x, N, H, z, S, be), q.transparent === !0 && q.side === Ci ? (q.side = it, q.needsUpdate = !0, x.renderBufferDirect(H, N, z, q, S, be), q.side = Ai, q.needsUpdate = !0, x.renderBufferDirect(H, N, z, q, S, be), q.side = Ci) : x.renderBufferDirect(H, N, z, q, S, be), S.onAfterRender(x, N, H, z, q, be); - } - function xo(S, N, H) { - N.isScene !== !0 && (N = fe); - let z = G.get(S), q = d.state.lights, be = d.state.shadowsArray, Ae = q.state.version, Ie = Pe.getParameters(S, q.state, be, N, H), we = Pe.getProgramCacheKey(Ie), He = z.programs; - z.environment = S.isMeshStandardMaterial ? N.environment : null, z.fog = N.fog, z.envMap = (S.isMeshStandardMaterial ? ue : K).get(S.envMap || z.environment), He === void 0 && (S.addEventListener("dispose", Re), He = new Map, z.programs = He); - let De = He.get(we); - if (De !== void 0) { - if (z.currentProgram === De && z.lightsStateVersion === Ae) return el(S, Ie), De; - } else Ie.uniforms = Pe.getUniforms(S), S.onBuild(H, Ie, x), S.onBeforeCompile(Ie, x), De = Pe.acquireProgram(Ie, we), He.set(we, De), z.uniforms = Ie.uniforms; - let ze = z.uniforms; - (!S.isShaderMaterial && !S.isRawShaderMaterial || S.clipping === !0) && (ze.clippingPlanes = J.uniform), el(S, Ie), z.needsLights = hu(S), z.lightsStateVersion = Ae, z.needsLights && (ze.ambientLightColor.value = q.state.ambient, ze.lightProbe.value = q.state.probe, ze.directionalLights.value = q.state.directional, ze.directionalLightShadows.value = q.state.directionalShadow, ze.spotLights.value = q.state.spot, ze.spotLightShadows.value = q.state.spotShadow, ze.rectAreaLights.value = q.state.rectArea, ze.ltc_1.value = q.state.rectAreaLTC1, ze.ltc_2.value = q.state.rectAreaLTC2, ze.pointLights.value = q.state.point, ze.pointLightShadows.value = q.state.pointShadow, ze.hemisphereLights.value = q.state.hemi, ze.directionalShadowMap.value = q.state.directionalShadowMap, ze.directionalShadowMatrix.value = q.state.directionalShadowMatrix, ze.spotShadowMap.value = q.state.spotShadowMap, ze.spotShadowMatrix.value = q.state.spotShadowMatrix, ze.pointShadowMap.value = q.state.pointShadowMap, ze.pointShadowMatrix.value = q.state.pointShadowMatrix); - let je = De.getUniforms(), Rn = bn.seqWithValue(je.seq, ze); - return z.currentProgram = De, z.uniformsList = Rn, De; - } - function el(S, N) { - let H = G.get(S); - H.outputEncoding = N.outputEncoding, H.instancing = N.instancing, H.skinning = N.skinning, H.morphTargets = N.morphTargets, H.morphNormals = N.morphNormals, H.morphTargetsCount = N.morphTargetsCount, H.numClippingPlanes = N.numClippingPlanes, H.numIntersection = N.numClipIntersection, H.vertexAlphas = N.vertexAlphas, H.vertexTangents = N.vertexTangents, H.toneMapping = N.toneMapping; - } - function lu(S, N, H, z, q) { - N.isScene !== !0 && (N = fe), j.resetTextureUnits(); - let be = N.fog, Ae = z.isMeshStandardMaterial ? N.environment : null, Ie = _ === null ? x.outputEncoding : _.texture.encoding, we = (z.isMeshStandardMaterial ? ue : K).get(z.envMap || Ae), He = z.vertexColors === !0 && !!H.attributes.color && H.attributes.color.itemSize === 4, De = !!z.normalMap && !!H.attributes.tangent, ze = !!H.morphAttributes.position, je = !!H.morphAttributes.normal, Rn = H.morphAttributes.position ? H.morphAttributes.position.length : 0, ei = z.toneMapped ? x.toneMapping : _n, Ge = G.get(z), Ht = d.state.lights; - if (ce === !0 && (V === !0 || S !== b)) { - let Pt = S === b && z.id === y; - J.setState(z, S, Pt); - } - let at = !1; - z.version === Ge.__version ? (Ge.needsLights && Ge.lightsStateVersion !== Ht.state.version || Ge.outputEncoding !== Ie || q.isInstancedMesh && Ge.instancing === !1 || !q.isInstancedMesh && Ge.instancing === !0 || q.isSkinnedMesh && Ge.skinning === !1 || !q.isSkinnedMesh && Ge.skinning === !0 || Ge.envMap !== we || z.fog && Ge.fog !== be || Ge.numClippingPlanes !== void 0 && (Ge.numClippingPlanes !== J.numPlanes || Ge.numIntersection !== J.numIntersection) || Ge.vertexAlphas !== He || Ge.vertexTangents !== De || Ge.morphTargets !== ze || Ge.morphNormals !== je || Ge.toneMapping !== ei || ge.isWebGL2 === !0 && Ge.morphTargetsCount !== Rn) && (at = !0) : (at = !0, Ge.__version = z.version); - let kt = Ge.currentProgram; - at === !0 && (kt = xo(z, N, q)); - let Gr = !1, Gt = !1, Zt = !1, xt = kt.getUniforms(), Xi = Ge.uniforms; - if (xe.useProgram(kt.program) && (Gr = !0, Gt = !0, Zt = !0), z.id !== y && (y = z.id, Gt = !0), Gr || b !== S) { - if (xt.setValue(Y, "projectionMatrix", S.projectionMatrix), ge.logarithmicDepthBuffer && xt.setValue(Y, "logDepthBufFC", 2 / (Math.log(S.far + 1) / Math.LN2)), b !== S && (b = S, Gt = !0, Zt = !0), z.isShaderMaterial || z.isMeshPhongMaterial || z.isMeshToonMaterial || z.isMeshStandardMaterial || z.envMap) { - let Pt = xt.map.cameraPosition; - Pt !== void 0 && Pt.setValue(Y, le.setFromMatrixPosition(S.matrixWorld)); - } - (z.isMeshPhongMaterial || z.isMeshToonMaterial || z.isMeshLambertMaterial || z.isMeshBasicMaterial || z.isMeshStandardMaterial || z.isShaderMaterial) && xt.setValue(Y, "isOrthographic", S.isOrthographicCamera === !0), (z.isMeshPhongMaterial || z.isMeshToonMaterial || z.isMeshLambertMaterial || z.isMeshBasicMaterial || z.isMeshStandardMaterial || z.isShaderMaterial || z.isShadowMaterial || q.isSkinnedMesh) && xt.setValue(Y, "viewMatrix", S.matrixWorldInverse); - } - if (q.isSkinnedMesh) { - xt.setOptional(Y, q, "bindMatrix"), xt.setOptional(Y, q, "bindMatrixInverse"); - let Pt = q.skeleton; - Pt && (ge.floatVertexTextures ? (Pt.boneTexture === null && Pt.computeBoneTexture(), xt.setValue(Y, "boneTexture", Pt.boneTexture, j), xt.setValue(Y, "boneTextureSize", Pt.boneTextureSize)) : xt.setOptional(Y, Pt, "boneMatrices")); - } - return !!H && (H.morphAttributes.position !== void 0 || H.morphAttributes.normal !== void 0) && Z.update(q, H, z, kt), (Gt || Ge.receiveShadow !== q.receiveShadow) && (Ge.receiveShadow = q.receiveShadow, xt.setValue(Y, "receiveShadow", q.receiveShadow)), Gt && (xt.setValue(Y, "toneMappingExposure", x.toneMappingExposure), Ge.needsLights && cu(Xi, Zt), be && z.fog && Ye.refreshFogUniforms(Xi, be), Ye.refreshMaterialUniforms(Xi, z, P, B, W), bn.upload(Y, Ge.uniformsList, Xi, j)), z.isShaderMaterial && z.uniformsNeedUpdate === !0 && (bn.upload(Y, Ge.uniformsList, Xi, j), z.uniformsNeedUpdate = !1), z.isSpriteMaterial && xt.setValue(Y, "center", q.center), xt.setValue(Y, "modelViewMatrix", q.modelViewMatrix), xt.setValue(Y, "normalMatrix", q.normalMatrix), xt.setValue(Y, "modelMatrix", q.matrixWorld), kt; - } - function cu(S, N) { - S.ambientLightColor.needsUpdate = N, S.lightProbe.needsUpdate = N, S.directionalLights.needsUpdate = N, S.directionalLightShadows.needsUpdate = N, S.pointLights.needsUpdate = N, S.pointLightShadows.needsUpdate = N, S.spotLights.needsUpdate = N, S.spotLightShadows.needsUpdate = N, S.rectAreaLights.needsUpdate = N, S.hemisphereLights.needsUpdate = N; - } - function hu(S) { - return S.isMeshLambertMaterial || S.isMeshToonMaterial || S.isMeshPhongMaterial || S.isMeshStandardMaterial || S.isShadowMaterial || S.isShaderMaterial && S.lights === !0; - } - this.getActiveCubeFace = function() { - return g; - }, this.getActiveMipmapLevel = function() { - return p; - }, this.getRenderTarget = function() { - return _; - }, this.setRenderTargetTextures = function(S, N, H) { - G.get(S.texture).__webglTexture = N, G.get(S.depthTexture).__webglTexture = H; - let z = G.get(S); - z.__hasExternalTextures = !0, z.__hasExternalTextures && (z.__autoAllocateDepthBuffer = H === void 0, z.__autoAllocateDepthBuffer || S.useRenderToTexture && (console.warn("render-to-texture extension was disabled because an external texture was provided"), S.useRenderToTexture = !1, S.useRenderbuffer = !0)); - }, this.setRenderTargetFramebuffer = function(S, N) { - let H = G.get(S); - H.__webglFramebuffer = N, H.__useDefaultFramebuffer = N === void 0; - }, this.setRenderTarget = function(S, N = 0, H = 0) { - _ = S, g = N, p = H; - let z = !0; - if (S) { - let we = G.get(S); - we.__useDefaultFramebuffer !== void 0 ? (xe.bindFramebuffer(36160, null), z = !1) : we.__webglFramebuffer === void 0 ? j.setupRenderTarget(S) : we.__hasExternalTextures && j.rebindTextures(S, G.get(S.texture).__webglTexture, G.get(S.depthTexture).__webglTexture); - } - let q = null, be = !1, Ae = !1; - if (S) { - let we = S.texture; - (we.isDataTexture3D || we.isDataTexture2DArray) && (Ae = !0); - let He = G.get(S).__webglFramebuffer; - S.isWebGLCubeRenderTarget ? (q = He[N], be = !0) : S.useRenderbuffer ? q = G.get(S).__webglMultisampledFramebuffer : q = He, A.copy(S.viewport), L.copy(S.scissor), I = S.scissorTest; - } else A.copy(D).multiplyScalar(P).floor(), L.copy(U).multiplyScalar(P).floor(), I = F; - if (xe.bindFramebuffer(36160, q) && ge.drawBuffers && z) { - let we = !1; - if (S) if (S.isWebGLMultipleRenderTargets) { - let He = S.texture; - if (O.length !== He.length || O[0] !== 36064) { - for(let De = 0, ze = He.length; De < ze; De++)O[De] = 36064 + De; - O.length = He.length, we = !0; + function Od(E, N, V, F) { + let k = ie.isWebGL2; + we === null && (we = new qt(1, 1, { + generateMipmaps: !0, + type: X.has("EXT_color_buffer_half_float") ? Ts : On, + minFilter: li, + samples: k ? 4 : 0 + })), x.getDrawingBufferSize(Te), k ? we.setSize(Te.x, Te.y) : we.setSize(Wr(Te.x), Wr(Te.y)); + let xe = x.getRenderTarget(); + x.setRenderTarget(we), x.getClearColor($), U = x.getClearAlpha(), U < 1 && x.setClearColor(16777215, .5), x.clear(); + let Ae = x.toneMapping; + x.toneMapping = Nn, ks(E, V, F), ye.updateMultisampleRenderTarget(we), ye.updateRenderTargetMipmap(we); + let Ue = !1; + for(let De = 0, We = N.length; De < We; De++){ + let Pe = N[De], Ve = Pe.object, at = Pe.geometry, lt = Pe.material, Ht = Pe.group; + if (lt.side === gn && Ve.layers.test(F.layers)) { + let an = lt.side; + lt.side = Ft, lt.needsUpdate = !0, tl(Ve, V, F, at, lt, Ht), lt.side = an, lt.needsUpdate = !0, Ue = !0; } - } else (O.length !== 1 || O[0] !== 36064) && (O[0] = 36064, O.length = 1, we = !0); - else (O.length !== 1 || O[0] !== 1029) && (O[0] = 1029, O.length = 1, we = !0); - we && (ge.isWebGL2 ? Y.drawBuffers(O) : ye.get("WEBGL_draw_buffers").drawBuffersWEBGL(O)); - } - if (xe.viewport(A), xe.scissor(L), xe.setScissorTest(I), be) { - let we = G.get(S.texture); - Y.framebufferTexture2D(36160, 36064, 34069 + N, we.__webglTexture, H); - } else if (Ae) { - let we = G.get(S.texture), He = N || 0; - Y.framebufferTextureLayer(36160, 36064, we.__webglTexture, H || 0, He); - } - y = -1; - }, this.readRenderTargetPixels = function(S, N, H, z, q, be, Ae) { - if (!(S && S.isWebGLRenderTarget)) { - console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget."); - return; + } + Ue === !0 && (ye.updateMultisampleRenderTarget(we), ye.updateRenderTargetMipmap(we)), x.setRenderTarget(xe), x.setClearColor($, U), x.toneMapping = Ae; } - let Ie = G.get(S).__webglFramebuffer; - if (S.isWebGLCubeRenderTarget && Ae !== void 0 && (Ie = Ie[Ae]), Ie) { - xe.bindFramebuffer(36160, Ie); - try { - let we = S.texture, He = we.format, De = we.type; - if (He !== ct && te.convert(He) !== Y.getParameter(35739)) { - console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format."); - return; - } - let ze = De === kn && (ye.has("EXT_color_buffer_half_float") || ge.isWebGL2 && ye.has("EXT_color_buffer_float")); - if (De !== rn && te.convert(De) !== Y.getParameter(35738) && !(De === nn && (ge.isWebGL2 || ye.has("OES_texture_float") || ye.has("WEBGL_color_buffer_float"))) && !ze) { - console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type."); - return; - } - Y.checkFramebufferStatus(36160) === 36053 ? N >= 0 && N <= S.width - z && H >= 0 && H <= S.height - q && Y.readPixels(N, H, z, q, te.convert(He), te.convert(De), be) : console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete."); - } finally{ - let we = _ !== null ? G.get(_).__webglFramebuffer : null; - xe.bindFramebuffer(36160, we); + function ks(E, N, V) { + let F = N.isScene === !0 ? N.overrideMaterial : null; + for(let k = 0, xe = E.length; k < xe; k++){ + let Ae = E[k], Ue = Ae.object, De = Ae.geometry, We = F === null ? Ae.material : F, Pe = Ae.group; + Ue.layers.test(V.layers) && tl(Ue, N, V, De, We, Pe); } } - }, this.copyFramebufferToTexture = function(S, N, H = 0) { - if (N.isFramebufferTexture !== !0) { - console.error("THREE.WebGLRenderer: copyFramebufferToTexture() can only be used with FramebufferTexture."); - return; + function tl(E, N, V, F, k, xe) { + E.onBeforeRender(x, N, V, F, k, xe), E.modelViewMatrix.multiplyMatrices(V.matrixWorldInverse, E.matrixWorld), E.normalMatrix.getNormalMatrix(E.modelViewMatrix), k.onBeforeRender(x, N, V, F, E, xe), k.transparent === !0 && k.side === gn && k.forceSinglePass === !1 ? (k.side = Ft, k.needsUpdate = !0, x.renderBufferDirect(V, N, F, k, E, xe), k.side = Bn, k.needsUpdate = !0, x.renderBufferDirect(V, N, F, k, E, xe), k.side = gn) : x.renderBufferDirect(V, N, F, k, E, xe), E.onAfterRender(x, N, V, F, k, xe); + } + function Hs(E, N, V) { + N.isScene !== !0 && (N = it); + let F = me.get(E), k = g.state.lights, xe = g.state.shadowsArray, Ae = k.state.version, Ue = B.getParameters(E, k.state, xe, N, V), De = B.getProgramCacheKey(Ue), We = F.programs; + F.environment = E.isMeshStandardMaterial ? N.environment : null, F.fog = N.fog, F.envMap = (E.isMeshStandardMaterial ? qe : Ne).get(E.envMap || F.environment), We === void 0 && (E.addEventListener("dispose", ue), We = new Map, F.programs = We); + let Pe = We.get(De); + if (Pe !== void 0) { + if (F.currentProgram === Pe && F.lightsStateVersion === Ae) return nl(E, Ue), Pe; + } else Ue.uniforms = B.getUniforms(E), E.onBuild(V, Ue, x), E.onBeforeCompile(Ue, x), Pe = B.acquireProgram(Ue, De), We.set(De, Pe), F.uniforms = Ue.uniforms; + let Ve = F.uniforms; + (!E.isShaderMaterial && !E.isRawShaderMaterial || E.clipping === !0) && (Ve.clippingPlanes = Me.uniform), nl(E, Ue), F.needsLights = zd(E), F.lightsStateVersion = Ae, F.needsLights && (Ve.ambientLightColor.value = k.state.ambient, Ve.lightProbe.value = k.state.probe, Ve.directionalLights.value = k.state.directional, Ve.directionalLightShadows.value = k.state.directionalShadow, Ve.spotLights.value = k.state.spot, Ve.spotLightShadows.value = k.state.spotShadow, Ve.rectAreaLights.value = k.state.rectArea, Ve.ltc_1.value = k.state.rectAreaLTC1, Ve.ltc_2.value = k.state.rectAreaLTC2, Ve.pointLights.value = k.state.point, Ve.pointLightShadows.value = k.state.pointShadow, Ve.hemisphereLights.value = k.state.hemi, Ve.directionalShadowMap.value = k.state.directionalShadowMap, Ve.directionalShadowMatrix.value = k.state.directionalShadowMatrix, Ve.spotShadowMap.value = k.state.spotShadowMap, Ve.spotLightMatrix.value = k.state.spotLightMatrix, Ve.spotLightMap.value = k.state.spotLightMap, Ve.pointShadowMap.value = k.state.pointShadowMap, Ve.pointShadowMatrix.value = k.state.pointShadowMatrix); + let at = Pe.getUniforms(), lt = qi.seqWithValue(at.seq, Ve); + return F.currentProgram = Pe, F.uniformsList = lt, Pe; + } + function nl(E, N) { + let V = me.get(E); + V.outputColorSpace = N.outputColorSpace, V.instancing = N.instancing, V.instancingColor = N.instancingColor, V.skinning = N.skinning, V.morphTargets = N.morphTargets, V.morphNormals = N.morphNormals, V.morphColors = N.morphColors, V.morphTargetsCount = N.morphTargetsCount, V.numClippingPlanes = N.numClippingPlanes, V.numIntersection = N.numClipIntersection, V.vertexAlphas = N.vertexAlphas, V.vertexTangents = N.vertexTangents, V.toneMapping = N.toneMapping; + } + function Fd(E, N, V, F, k) { + N.isScene !== !0 && (N = it), ye.resetTextureUnits(); + let xe = N.fog, Ae = F.isMeshStandardMaterial ? N.environment : null, Ue = R === null ? x.outputColorSpace : R.isXRRenderTarget === !0 ? R.texture.colorSpace : Mn, De = (F.isMeshStandardMaterial ? qe : Ne).get(F.envMap || Ae), We = F.vertexColors === !0 && !!V.attributes.color && V.attributes.color.itemSize === 4, Pe = !!V.attributes.tangent && (!!F.normalMap || F.anisotropy > 0), Ve = !!V.morphAttributes.position, at = !!V.morphAttributes.normal, lt = !!V.morphAttributes.color, Ht = Nn; + F.toneMapped && (R === null || R.isXRRenderTarget === !0) && (Ht = x.toneMapping); + let an = V.morphAttributes.position || V.morphAttributes.normal || V.morphAttributes.color, ut = an !== void 0 ? an.length : 0, Xe = me.get(F), Sa = g.state.lights; + if (fe === !0 && (_e === !0 || E !== M)) { + let Bt = E === M && F.id === I; + Me.setState(F, E, Bt); + } + let dt = !1; + F.version === Xe.__version ? (Xe.needsLights && Xe.lightsStateVersion !== Sa.state.version || Xe.outputColorSpace !== Ue || k.isInstancedMesh && Xe.instancing === !1 || !k.isInstancedMesh && Xe.instancing === !0 || k.isSkinnedMesh && Xe.skinning === !1 || !k.isSkinnedMesh && Xe.skinning === !0 || k.isInstancedMesh && Xe.instancingColor === !0 && k.instanceColor === null || k.isInstancedMesh && Xe.instancingColor === !1 && k.instanceColor !== null || Xe.envMap !== De || F.fog === !0 && Xe.fog !== xe || Xe.numClippingPlanes !== void 0 && (Xe.numClippingPlanes !== Me.numPlanes || Xe.numIntersection !== Me.numIntersection) || Xe.vertexAlphas !== We || Xe.vertexTangents !== Pe || Xe.morphTargets !== Ve || Xe.morphNormals !== at || Xe.morphColors !== lt || Xe.toneMapping !== Ht || ie.isWebGL2 === !0 && Xe.morphTargetsCount !== ut) && (dt = !0) : (dt = !0, Xe.__version = F.version); + let Hn = Xe.currentProgram; + dt === !0 && (Hn = Hs(F, N, k)); + let il = !1, os = !1, ba = !1, Ct = Hn.getUniforms(), Gn = Xe.uniforms; + if (J.useProgram(Hn.program) && (il = !0, os = !0, ba = !0), F.id !== I && (I = F.id, os = !0), il || M !== E) { + Ct.setValue(L, "projectionMatrix", E.projectionMatrix), Ct.setValue(L, "viewMatrix", E.matrixWorldInverse); + let Bt = Ct.map.cameraPosition; + Bt !== void 0 && Bt.setValue(L, Ye.setFromMatrixPosition(E.matrixWorld)), ie.logarithmicDepthBuffer && Ct.setValue(L, "logDepthBufFC", 2 / (Math.log(E.far + 1) / Math.LN2)), (F.isMeshPhongMaterial || F.isMeshToonMaterial || F.isMeshLambertMaterial || F.isMeshBasicMaterial || F.isMeshStandardMaterial || F.isShaderMaterial) && Ct.setValue(L, "isOrthographic", E.isOrthographicCamera === !0), M !== E && (M = E, os = !0, ba = !0); + } + if (k.isSkinnedMesh) { + Ct.setOptional(L, k, "bindMatrix"), Ct.setOptional(L, k, "bindMatrixInverse"); + let Bt = k.skeleton; + Bt && (ie.floatVertexTextures ? (Bt.boneTexture === null && Bt.computeBoneTexture(), Ct.setValue(L, "boneTexture", Bt.boneTexture, ye), Ct.setValue(L, "boneTextureSize", Bt.boneTextureSize)) : console.warn("THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.")); + } + let Ea = V.morphAttributes; + if ((Ea.position !== void 0 || Ea.normal !== void 0 || Ea.color !== void 0 && ie.isWebGL2 === !0) && Le.update(k, V, Hn), (os || Xe.receiveShadow !== k.receiveShadow) && (Xe.receiveShadow = k.receiveShadow, Ct.setValue(L, "receiveShadow", k.receiveShadow)), F.isMeshGouraudMaterial && F.envMap !== null && (Gn.envMap.value = De, Gn.flipEnvMap.value = De.isCubeTexture && De.isRenderTargetTexture === !1 ? -1 : 1), os && (Ct.setValue(L, "toneMappingExposure", x.toneMappingExposure), Xe.needsLights && Bd(Gn, ba), xe && F.fog === !0 && ee.refreshFogUniforms(Gn, xe), ee.refreshMaterialUniforms(Gn, F, H, q, we), qi.upload(L, Xe.uniformsList, Gn, ye)), F.isShaderMaterial && F.uniformsNeedUpdate === !0 && (qi.upload(L, Xe.uniformsList, Gn, ye), F.uniformsNeedUpdate = !1), F.isSpriteMaterial && Ct.setValue(L, "center", k.center), Ct.setValue(L, "modelViewMatrix", k.modelViewMatrix), Ct.setValue(L, "normalMatrix", k.normalMatrix), Ct.setValue(L, "modelMatrix", k.matrixWorld), F.isShaderMaterial || F.isRawShaderMaterial) { + let Bt = F.uniformsGroups; + for(let Ta = 0, Vd = Bt.length; Ta < Vd; Ta++)if (ie.isWebGL2) { + let sl = Bt[Ta]; + Ie.update(sl, Hn), Ie.bind(sl, Hn); + } else console.warn("THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2."); + } + return Hn; } - let z = Math.pow(2, -H), q = Math.floor(N.image.width * z), be = Math.floor(N.image.height * z); - j.setTexture2D(N, 0), Y.copyTexSubImage2D(3553, H, 0, 0, S.x, S.y, q, be), xe.unbindTexture(); - }, this.copyTextureToTexture = function(S, N, H, z = 0) { - let q = N.image.width, be = N.image.height, Ae = te.convert(H.format), Ie = te.convert(H.type); - j.setTexture2D(H, 0), Y.pixelStorei(37440, H.flipY), Y.pixelStorei(37441, H.premultiplyAlpha), Y.pixelStorei(3317, H.unpackAlignment), N.isDataTexture ? Y.texSubImage2D(3553, z, S.x, S.y, q, be, Ae, Ie, N.image.data) : N.isCompressedTexture ? Y.compressedTexSubImage2D(3553, z, S.x, S.y, N.mipmaps[0].width, N.mipmaps[0].height, Ae, N.mipmaps[0].data) : Y.texSubImage2D(3553, z, S.x, S.y, Ae, Ie, N.image), z === 0 && H.generateMipmaps && Y.generateMipmap(3553), xe.unbindTexture(); - }, this.copyTextureToTexture3D = function(S, N, H, z, q = 0) { - if (x.isWebGL1Renderer) { - console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2."); - return; + function Bd(E, N) { + E.ambientLightColor.needsUpdate = N, E.lightProbe.needsUpdate = N, E.directionalLights.needsUpdate = N, E.directionalLightShadows.needsUpdate = N, E.pointLights.needsUpdate = N, E.pointLightShadows.needsUpdate = N, E.spotLights.needsUpdate = N, E.spotLightShadows.needsUpdate = N, E.rectAreaLights.needsUpdate = N, E.hemisphereLights.needsUpdate = N; } - let be = S.max.x - S.min.x + 1, Ae = S.max.y - S.min.y + 1, Ie = S.max.z - S.min.z + 1, we = te.convert(z.format), He = te.convert(z.type), De; - if (z.isDataTexture3D) j.setTexture3D(z, 0), De = 32879; - else if (z.isDataTexture2DArray) j.setTexture2DArray(z, 0), De = 35866; - else { - console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray."); - return; + function zd(E) { + return E.isMeshLambertMaterial || E.isMeshToonMaterial || E.isMeshPhongMaterial || E.isMeshStandardMaterial || E.isShadowMaterial || E.isShaderMaterial && E.lights === !0; } - Y.pixelStorei(37440, z.flipY), Y.pixelStorei(37441, z.premultiplyAlpha), Y.pixelStorei(3317, z.unpackAlignment); - let ze = Y.getParameter(3314), je = Y.getParameter(32878), Rn = Y.getParameter(3316), ei = Y.getParameter(3315), Ge = Y.getParameter(32877), Ht = H.isCompressedTexture ? H.mipmaps[0] : H.image; - Y.pixelStorei(3314, Ht.width), Y.pixelStorei(32878, Ht.height), Y.pixelStorei(3316, S.min.x), Y.pixelStorei(3315, S.min.y), Y.pixelStorei(32877, S.min.z), H.isDataTexture || H.isDataTexture3D ? Y.texSubImage3D(De, q, N.x, N.y, N.z, be, Ae, Ie, we, He, Ht.data) : H.isCompressedTexture ? (console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture."), Y.compressedTexSubImage3D(De, q, N.x, N.y, N.z, be, Ae, Ie, we, Ht.data)) : Y.texSubImage3D(De, q, N.x, N.y, N.z, be, Ae, Ie, we, He, Ht), Y.pixelStorei(3314, ze), Y.pixelStorei(32878, je), Y.pixelStorei(3316, Rn), Y.pixelStorei(3315, ei), Y.pixelStorei(32877, Ge), q === 0 && z.generateMipmaps && Y.generateMipmap(De), xe.unbindTexture(); - }, this.initTexture = function(S) { - j.setTexture2D(S, 0), xe.unbindTexture(); - }, this.resetState = function() { - g = 0, p = 0, _ = null, xe.reset(), R.reset(); - }, typeof __THREE_DEVTOOLS__ < "u" && __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe", { - detail: this - })); -} -qe.prototype.isWebGLRenderer = !0; -var _h = class extends qe { + this.getActiveCubeFace = function() { + return b; + }, this.getActiveMipmapLevel = function() { + return w; + }, this.getRenderTarget = function() { + return R; + }, this.setRenderTargetTextures = function(E, N, V) { + me.get(E.texture).__webglTexture = N, me.get(E.depthTexture).__webglTexture = V; + let F = me.get(E); + F.__hasExternalTextures = !0, F.__hasExternalTextures && (F.__autoAllocateDepthBuffer = V === void 0, F.__autoAllocateDepthBuffer || X.has("WEBGL_multisampled_render_to_texture") === !0 && (console.warn("THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided"), F.__useRenderToTexture = !1)); + }, this.setRenderTargetFramebuffer = function(E, N) { + let V = me.get(E); + V.__webglFramebuffer = N, V.__useDefaultFramebuffer = N === void 0; + }, this.setRenderTarget = function(E, N = 0, V = 0) { + R = E, b = N, w = V; + let F = !0, k = null, xe = !1, Ae = !1; + if (E) { + let De = me.get(E); + De.__useDefaultFramebuffer !== void 0 ? (J.bindFramebuffer(L.FRAMEBUFFER, null), F = !1) : De.__webglFramebuffer === void 0 ? ye.setupRenderTarget(E) : De.__hasExternalTextures && ye.rebindTextures(E, me.get(E.texture).__webglTexture, me.get(E.depthTexture).__webglTexture); + let We = E.texture; + (We.isData3DTexture || We.isDataArrayTexture || We.isCompressedArrayTexture) && (Ae = !0); + let Pe = me.get(E).__webglFramebuffer; + E.isWebGLCubeRenderTarget ? (Array.isArray(Pe[N]) ? k = Pe[N][V] : k = Pe[N], xe = !0) : ie.isWebGL2 && E.samples > 0 && ye.useMultisampledRTT(E) === !1 ? k = me.get(E).__webglMultisampledFramebuffer : Array.isArray(Pe) ? k = Pe[V] : k = Pe, T.copy(E.viewport), O.copy(E.scissor), Y = E.scissorTest; + } else T.copy(K).multiplyScalar(H).floor(), O.copy(D).multiplyScalar(H).floor(), Y = G; + if (J.bindFramebuffer(L.FRAMEBUFFER, k) && ie.drawBuffers && F && J.drawBuffers(E, k), J.viewport(T), J.scissor(O), J.setScissorTest(Y), xe) { + let De = me.get(E.texture); + L.framebufferTexture2D(L.FRAMEBUFFER, L.COLOR_ATTACHMENT0, L.TEXTURE_CUBE_MAP_POSITIVE_X + N, De.__webglTexture, V); + } else if (Ae) { + let De = me.get(E.texture), We = N || 0; + L.framebufferTextureLayer(L.FRAMEBUFFER, L.COLOR_ATTACHMENT0, De.__webglTexture, V || 0, We); + } + I = -1; + }, this.readRenderTargetPixels = function(E, N, V, F, k, xe, Ae) { + if (!(E && E.isWebGLRenderTarget)) { + console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget."); + return; + } + let Ue = me.get(E).__webglFramebuffer; + if (E.isWebGLCubeRenderTarget && Ae !== void 0 && (Ue = Ue[Ae]), Ue) { + J.bindFramebuffer(L.FRAMEBUFFER, Ue); + try { + let De = E.texture, We = De.format, Pe = De.type; + if (We !== Wt && $e.convert(We) !== L.getParameter(L.IMPLEMENTATION_COLOR_READ_FORMAT)) { + console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format."); + return; + } + let Ve = Pe === Ts && (X.has("EXT_color_buffer_half_float") || ie.isWebGL2 && X.has("EXT_color_buffer_float")); + if (Pe !== On && $e.convert(Pe) !== L.getParameter(L.IMPLEMENTATION_COLOR_READ_TYPE) && !(Pe === xn && (ie.isWebGL2 || X.has("OES_texture_float") || X.has("WEBGL_color_buffer_float"))) && !Ve) { + console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type."); + return; + } + N >= 0 && N <= E.width - F && V >= 0 && V <= E.height - k && L.readPixels(N, V, F, k, $e.convert(We), $e.convert(Pe), xe); + } finally{ + let De = R !== null ? me.get(R).__webglFramebuffer : null; + J.bindFramebuffer(L.FRAMEBUFFER, De); + } + } + }, this.copyFramebufferToTexture = function(E, N, V = 0) { + let F = Math.pow(2, -V), k = Math.floor(N.image.width * F), xe = Math.floor(N.image.height * F); + ye.setTexture2D(N, 0), L.copyTexSubImage2D(L.TEXTURE_2D, V, 0, 0, E.x, E.y, k, xe), J.unbindTexture(); + }, this.copyTextureToTexture = function(E, N, V, F = 0) { + let k = N.image.width, xe = N.image.height, Ae = $e.convert(V.format), Ue = $e.convert(V.type); + ye.setTexture2D(V, 0), L.pixelStorei(L.UNPACK_FLIP_Y_WEBGL, V.flipY), L.pixelStorei(L.UNPACK_PREMULTIPLY_ALPHA_WEBGL, V.premultiplyAlpha), L.pixelStorei(L.UNPACK_ALIGNMENT, V.unpackAlignment), N.isDataTexture ? L.texSubImage2D(L.TEXTURE_2D, F, E.x, E.y, k, xe, Ae, Ue, N.image.data) : N.isCompressedTexture ? L.compressedTexSubImage2D(L.TEXTURE_2D, F, E.x, E.y, N.mipmaps[0].width, N.mipmaps[0].height, Ae, N.mipmaps[0].data) : L.texSubImage2D(L.TEXTURE_2D, F, E.x, E.y, Ae, Ue, N.image), F === 0 && V.generateMipmaps && L.generateMipmap(L.TEXTURE_2D), J.unbindTexture(); + }, this.copyTextureToTexture3D = function(E, N, V, F, k = 0) { + if (x.isWebGL1Renderer) { + console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2."); + return; + } + let xe = E.max.x - E.min.x + 1, Ae = E.max.y - E.min.y + 1, Ue = E.max.z - E.min.z + 1, De = $e.convert(F.format), We = $e.convert(F.type), Pe; + if (F.isData3DTexture) ye.setTexture3D(F, 0), Pe = L.TEXTURE_3D; + else if (F.isDataArrayTexture) ye.setTexture2DArray(F, 0), Pe = L.TEXTURE_2D_ARRAY; + else { + console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray."); + return; + } + L.pixelStorei(L.UNPACK_FLIP_Y_WEBGL, F.flipY), L.pixelStorei(L.UNPACK_PREMULTIPLY_ALPHA_WEBGL, F.premultiplyAlpha), L.pixelStorei(L.UNPACK_ALIGNMENT, F.unpackAlignment); + let Ve = L.getParameter(L.UNPACK_ROW_LENGTH), at = L.getParameter(L.UNPACK_IMAGE_HEIGHT), lt = L.getParameter(L.UNPACK_SKIP_PIXELS), Ht = L.getParameter(L.UNPACK_SKIP_ROWS), an = L.getParameter(L.UNPACK_SKIP_IMAGES), ut = V.isCompressedTexture ? V.mipmaps[0] : V.image; + L.pixelStorei(L.UNPACK_ROW_LENGTH, ut.width), L.pixelStorei(L.UNPACK_IMAGE_HEIGHT, ut.height), L.pixelStorei(L.UNPACK_SKIP_PIXELS, E.min.x), L.pixelStorei(L.UNPACK_SKIP_ROWS, E.min.y), L.pixelStorei(L.UNPACK_SKIP_IMAGES, E.min.z), V.isDataTexture || V.isData3DTexture ? L.texSubImage3D(Pe, k, N.x, N.y, N.z, xe, Ae, Ue, De, We, ut.data) : V.isCompressedArrayTexture ? (console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture."), L.compressedTexSubImage3D(Pe, k, N.x, N.y, N.z, xe, Ae, Ue, De, ut.data)) : L.texSubImage3D(Pe, k, N.x, N.y, N.z, xe, Ae, Ue, De, We, ut), L.pixelStorei(L.UNPACK_ROW_LENGTH, Ve), L.pixelStorei(L.UNPACK_IMAGE_HEIGHT, at), L.pixelStorei(L.UNPACK_SKIP_PIXELS, lt), L.pixelStorei(L.UNPACK_SKIP_ROWS, Ht), L.pixelStorei(L.UNPACK_SKIP_IMAGES, an), k === 0 && F.generateMipmaps && L.generateMipmap(Pe), J.unbindTexture(); + }, this.initTexture = function(E) { + E.isCubeTexture ? ye.setTextureCube(E, 0) : E.isData3DTexture ? ye.setTexture3D(E, 0) : E.isDataArrayTexture || E.isCompressedArrayTexture ? ye.setTexture2DArray(E, 0) : ye.setTexture2D(E, 0), J.unbindTexture(); + }, this.resetState = function() { + b = 0, w = 0, R = null, J.reset(), Oe.reset(); + }, typeof __THREE_DEVTOOLS__ < "u" && __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe", { + detail: this + })); + } + get coordinateSystem() { + return vn; + } + get outputColorSpace() { + return this._outputColorSpace; + } + set outputColorSpace(e) { + this._outputColorSpace = e; + let t = this.getContext(); + t.drawingBufferColorSpace = e === qc ? "display-p3" : "srgb", t.unpackColorSpace = Qe.workingColorSpace === va ? "display-p3" : "srgb"; + } + get physicallyCorrectLights() { + return console.warn("THREE.WebGLRenderer: The property .physicallyCorrectLights has been removed. Set renderer.useLegacyLights instead."), !this.useLegacyLights; + } + set physicallyCorrectLights(e) { + console.warn("THREE.WebGLRenderer: The property .physicallyCorrectLights has been removed. Set renderer.useLegacyLights instead."), this.useLegacyLights = !e; + } + get outputEncoding() { + return console.warn("THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead."), this.outputColorSpace === vt ? ri : vd; + } + set outputEncoding(e) { + console.warn("THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead."), this.outputColorSpace = e === ri ? vt : Mn; + } + get useLegacyLights() { + return console.warn("THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733."), this._useLegacyLights; + } + set useLegacyLights(e) { + console.warn("THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733."), this._useLegacyLights = e; + } +}, Co = class extends Ro { }; -_h.prototype.isWebGL1Renderer = !0; -var Nr = class { +Co.prototype.isWebGL1Renderer = !0; +var Po = class s1 { constructor(e, t = 25e-5){ - this.name = "", this.color = new ae(e), this.density = t; + this.isFogExp2 = !0, this.name = "", this.color = new pe(e), this.density = t; } clone() { - return new Nr(this.color, this.density); + return new s1(this.color, this.density); } toJSON() { return { type: "FogExp2", + name: this.name, color: this.color.getHex(), density: this.density }; } -}; -Nr.prototype.isFogExp2 = !0; -var Br = class { +}, Lo = class s1 { constructor(e, t = 1, n = 1e3){ - this.name = "", this.color = new ae(e), this.near = t, this.far = n; + this.isFog = !0, this.name = "", this.color = new pe(e), this.near = t, this.far = n; } clone() { - return new Br(this.color, this.near, this.far); + return new s1(this.color, this.near, this.far); } toJSON() { return { type: "Fog", + name: this.name, color: this.color.getHex(), near: this.near, far: this.far }; } -}; -Br.prototype.isFog = !0; -var no = class extends Ne { +}, Io = class extends Je { constructor(){ - super(); - this.type = "Scene", this.background = null, this.environment = null, this.fog = null, this.overrideMaterial = null, this.autoUpdate = !0, typeof __THREE_DEVTOOLS__ < "u" && __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe", { + super(), this.isScene = !0, this.type = "Scene", this.background = null, this.environment = null, this.fog = null, this.backgroundBlurriness = 0, this.backgroundIntensity = 1, this.overrideMaterial = null, typeof __THREE_DEVTOOLS__ < "u" && __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe", { detail: this })); } copy(e, t) { - return super.copy(e, t), e.background !== null && (this.background = e.background.clone()), e.environment !== null && (this.environment = e.environment.clone()), e.fog !== null && (this.fog = e.fog.clone()), e.overrideMaterial !== null && (this.overrideMaterial = e.overrideMaterial.clone()), this.autoUpdate = e.autoUpdate, this.matrixAutoUpdate = e.matrixAutoUpdate, this; + return super.copy(e, t), e.background !== null && (this.background = e.background.clone()), e.environment !== null && (this.environment = e.environment.clone()), e.fog !== null && (this.fog = e.fog.clone()), this.backgroundBlurriness = e.backgroundBlurriness, this.backgroundIntensity = e.backgroundIntensity, e.overrideMaterial !== null && (this.overrideMaterial = e.overrideMaterial.clone()), this.matrixAutoUpdate = e.matrixAutoUpdate, this; } toJSON(e) { let t = super.toJSON(e); - return this.fog !== null && (t.object.fog = this.fog.toJSON()), t; + return this.fog !== null && (t.object.fog = this.fog.toJSON()), this.backgroundBlurriness > 0 && (t.object.backgroundBlurriness = this.backgroundBlurriness), this.backgroundIntensity !== 1 && (t.object.backgroundIntensity = this.backgroundIntensity), t; } -}; -no.prototype.isScene = !0; -var $n = class { +}, Is = class { constructor(e, t){ - this.array = e, this.stride = t, this.count = e !== void 0 ? e.length / t : 0, this.usage = hr, this.updateRange = { + this.isInterleavedBuffer = !0, this.array = e, this.stride = t, this.count = e !== void 0 ? e.length / t : 0, this.usage = Hr, this.updateRange = { offset: 0, count: -1 - }, this.version = 0, this.uuid = Et(); + }, this.version = 0, this.uuid = kt(); } onUploadCallback() {} set needsUpdate(e) { @@ -11671,7 +13317,7 @@ var $n = class { return this.array.set(e, t), this; } clone(e) { - e.arrayBuffers === void 0 && (e.arrayBuffers = {}), this.array.buffer._uuid === void 0 && (this.array.buffer._uuid = Et()), e.arrayBuffers[this.array.buffer._uuid] === void 0 && (e.arrayBuffers[this.array.buffer._uuid] = this.array.slice(0).buffer); + e.arrayBuffers === void 0 && (e.arrayBuffers = {}), this.array.buffer._uuid === void 0 && (this.array.buffer._uuid = kt()), e.arrayBuffers[this.array.buffer._uuid] === void 0 && (e.arrayBuffers[this.array.buffer._uuid] = this.array.slice(0).buffer); let t = new this.array.constructor(e.arrayBuffers[this.array.buffer._uuid]), n = new this.constructor(t, this.stride); return n.setUsage(this.usage), n; } @@ -11679,18 +13325,16 @@ var $n = class { return this.onUploadCallback = e, this; } toJSON(e) { - return e.arrayBuffers === void 0 && (e.arrayBuffers = {}), this.array.buffer._uuid === void 0 && (this.array.buffer._uuid = Et()), e.arrayBuffers[this.array.buffer._uuid] === void 0 && (e.arrayBuffers[this.array.buffer._uuid] = Array.prototype.slice.call(new Uint32Array(this.array.buffer))), { + return e.arrayBuffers === void 0 && (e.arrayBuffers = {}), this.array.buffer._uuid === void 0 && (this.array.buffer._uuid = kt()), e.arrayBuffers[this.array.buffer._uuid] === void 0 && (e.arrayBuffers[this.array.buffer._uuid] = Array.from(new Uint32Array(this.array.buffer))), { uuid: this.uuid, buffer: this.array.buffer._uuid, type: this.array.constructor.name, stride: this.stride }; } -}; -$n.prototype.isInterleavedBuffer = !0; -var Ke = new M, Sn = class { +}, Pt = new A, Qi = class s1 { constructor(e, t, n, i = !1){ - this.name = "", this.data = e, this.itemSize = t, this.offset = n, this.normalized = i === !0; + this.isInterleavedBufferAttribute = !0, this.name = "", this.data = e, this.itemSize = t, this.offset = n, this.normalized = i; } get count() { return this.data.count; @@ -11702,64 +13346,68 @@ var Ke = new M, Sn = class { this.data.needsUpdate = e; } applyMatrix4(e) { - for(let t = 0, n = this.data.count; t < n; t++)Ke.x = this.getX(t), Ke.y = this.getY(t), Ke.z = this.getZ(t), Ke.applyMatrix4(e), this.setXYZ(t, Ke.x, Ke.y, Ke.z); + for(let t = 0, n = this.data.count; t < n; t++)Pt.fromBufferAttribute(this, t), Pt.applyMatrix4(e), this.setXYZ(t, Pt.x, Pt.y, Pt.z); return this; } applyNormalMatrix(e) { - for(let t = 0, n = this.count; t < n; t++)Ke.x = this.getX(t), Ke.y = this.getY(t), Ke.z = this.getZ(t), Ke.applyNormalMatrix(e), this.setXYZ(t, Ke.x, Ke.y, Ke.z); + for(let t = 0, n = this.count; t < n; t++)Pt.fromBufferAttribute(this, t), Pt.applyNormalMatrix(e), this.setXYZ(t, Pt.x, Pt.y, Pt.z); return this; } transformDirection(e) { - for(let t = 0, n = this.count; t < n; t++)Ke.x = this.getX(t), Ke.y = this.getY(t), Ke.z = this.getZ(t), Ke.transformDirection(e), this.setXYZ(t, Ke.x, Ke.y, Ke.z); + for(let t = 0, n = this.count; t < n; t++)Pt.fromBufferAttribute(this, t), Pt.transformDirection(e), this.setXYZ(t, Pt.x, Pt.y, Pt.z); return this; } setX(e, t) { - return this.data.array[e * this.data.stride + this.offset] = t, this; + return this.normalized && (t = Be(t, this.array)), this.data.array[e * this.data.stride + this.offset] = t, this; } setY(e, t) { - return this.data.array[e * this.data.stride + this.offset + 1] = t, this; + return this.normalized && (t = Be(t, this.array)), this.data.array[e * this.data.stride + this.offset + 1] = t, this; } setZ(e, t) { - return this.data.array[e * this.data.stride + this.offset + 2] = t, this; + return this.normalized && (t = Be(t, this.array)), this.data.array[e * this.data.stride + this.offset + 2] = t, this; } setW(e, t) { - return this.data.array[e * this.data.stride + this.offset + 3] = t, this; + return this.normalized && (t = Be(t, this.array)), this.data.array[e * this.data.stride + this.offset + 3] = t, this; } getX(e) { - return this.data.array[e * this.data.stride + this.offset]; + let t = this.data.array[e * this.data.stride + this.offset]; + return this.normalized && (t = Ot(t, this.array)), t; } getY(e) { - return this.data.array[e * this.data.stride + this.offset + 1]; + let t = this.data.array[e * this.data.stride + this.offset + 1]; + return this.normalized && (t = Ot(t, this.array)), t; } getZ(e) { - return this.data.array[e * this.data.stride + this.offset + 2]; + let t = this.data.array[e * this.data.stride + this.offset + 2]; + return this.normalized && (t = Ot(t, this.array)), t; } getW(e) { - return this.data.array[e * this.data.stride + this.offset + 3]; + let t = this.data.array[e * this.data.stride + this.offset + 3]; + return this.normalized && (t = Ot(t, this.array)), t; } setXY(e, t, n) { - return e = e * this.data.stride + this.offset, this.data.array[e + 0] = t, this.data.array[e + 1] = n, this; + return e = e * this.data.stride + this.offset, this.normalized && (t = Be(t, this.array), n = Be(n, this.array)), this.data.array[e + 0] = t, this.data.array[e + 1] = n, this; } setXYZ(e, t, n, i) { - return e = e * this.data.stride + this.offset, this.data.array[e + 0] = t, this.data.array[e + 1] = n, this.data.array[e + 2] = i, this; + return e = e * this.data.stride + this.offset, this.normalized && (t = Be(t, this.array), n = Be(n, this.array), i = Be(i, this.array)), this.data.array[e + 0] = t, this.data.array[e + 1] = n, this.data.array[e + 2] = i, this; } setXYZW(e, t, n, i, r) { - return e = e * this.data.stride + this.offset, this.data.array[e + 0] = t, this.data.array[e + 1] = n, this.data.array[e + 2] = i, this.data.array[e + 3] = r, this; + return e = e * this.data.stride + this.offset, this.normalized && (t = Be(t, this.array), n = Be(n, this.array), i = Be(i, this.array), r = Be(r, this.array)), this.data.array[e + 0] = t, this.data.array[e + 1] = n, this.data.array[e + 2] = i, this.data.array[e + 3] = r, this; } clone(e) { if (e === void 0) { - console.log("THREE.InterleavedBufferAttribute.clone(): Cloning an interlaved buffer attribute will deinterleave buffer data."); + console.log("THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data."); let t = []; for(let n = 0; n < this.count; n++){ let i = n * this.data.stride + this.offset; for(let r = 0; r < this.itemSize; r++)t.push(this.data.array[i + r]); } - return new Ue(new this.array.constructor(t), this.itemSize, this.normalized); - } else return e.interleavedBuffers === void 0 && (e.interleavedBuffers = {}), e.interleavedBuffers[this.data.uuid] === void 0 && (e.interleavedBuffers[this.data.uuid] = this.data.clone(e)), new Sn(e.interleavedBuffers[this.data.uuid], this.itemSize, this.offset, this.normalized); + return new et(new this.array.constructor(t), this.itemSize, this.normalized); + } else return e.interleavedBuffers === void 0 && (e.interleavedBuffers = {}), e.interleavedBuffers[this.data.uuid] === void 0 && (e.interleavedBuffers[this.data.uuid] = this.data.clone(e)), new s1(e.interleavedBuffers[this.data.uuid], this.itemSize, this.offset, this.normalized); } toJSON(e) { if (e === void 0) { - console.log("THREE.InterleavedBufferAttribute.toJSON(): Serializing an interlaved buffer attribute will deinterleave buffer data."); + console.log("THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data."); let t = []; for(let n = 0; n < this.count; n++){ let i = n * this.data.stride + this.offset; @@ -11779,23 +13427,17 @@ var Ke = new M, Sn = class { normalized: this.normalized }; } -}; -Sn.prototype.isInterleavedBufferAttribute = !0; -var io = class extends dt { +}, ea = class extends bt { constructor(e){ - super(); - this.type = "SpriteMaterial", this.color = new ae(16777215), this.map = null, this.alphaMap = null, this.rotation = 0, this.sizeAttenuation = !0, this.transparent = !0, this.setValues(e); + super(), this.isSpriteMaterial = !0, this.type = "SpriteMaterial", this.color = new pe(16777215), this.map = null, this.alphaMap = null, this.rotation = 0, this.sizeAttenuation = !0, this.transparent = !0, this.fog = !0, this.setValues(e); } copy(e) { - return super.copy(e), this.color.copy(e.color), this.map = e.map, this.alphaMap = e.alphaMap, this.rotation = e.rotation, this.sizeAttenuation = e.sizeAttenuation, this; + return super.copy(e), this.color.copy(e.color), this.map = e.map, this.alphaMap = e.alphaMap, this.rotation = e.rotation, this.sizeAttenuation = e.sizeAttenuation, this.fog = e.fog, this; } -}; -io.prototype.isSpriteMaterial = !0; -var gi, Qi = new M, xi = new M, yi = new M, vi = new X, Ki = new X, Mh = new pe, hs = new M, er = new M, us = new M, jl = new X, qo = new X, Ql = new X, ro = class extends Ne { - constructor(e){ - super(); - if (this.type = "Sprite", gi === void 0) { - gi = new _e; +}, Ii, ds = new A, Ui = new A, Di = new A, Ni = new Z, fs = new Z, Cd = new ze, hr = new A, ps = new A, ur = new A, Lh = new Z, ja = new Z, Ih = new Z, Uo = class extends Je { + constructor(e = new ea){ + if (super(), this.isSprite = !0, this.type = "Sprite", Ii === void 0) { + Ii = new Ge; let t = new Float32Array([ -.5, -.5, @@ -11817,47 +13459,45 @@ var gi, Qi = new M, xi = new M, yi = new M, vi = new X, Ki = new X, Mh = new pe, 0, 0, 1 - ]), n = new $n(t, 5); - gi.setIndex([ + ]), n = new Is(t, 5); + Ii.setIndex([ 0, 1, 2, 0, 2, 3 - ]), gi.setAttribute("position", new Sn(n, 3, 0, !1)), gi.setAttribute("uv", new Sn(n, 2, 3, !1)); + ]), Ii.setAttribute("position", new Qi(n, 3, 0, !1)), Ii.setAttribute("uv", new Qi(n, 2, 3, !1)); } - this.geometry = gi, this.material = e !== void 0 ? e : new io, this.center = new X(.5, .5); + this.geometry = Ii, this.material = e, this.center = new Z(.5, .5); } raycast(e, t) { - e.camera === null && console.error('THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.'), xi.setFromMatrixScale(this.matrixWorld), Mh.copy(e.camera.matrixWorld), this.modelViewMatrix.multiplyMatrices(e.camera.matrixWorldInverse, this.matrixWorld), yi.setFromMatrixPosition(this.modelViewMatrix), e.camera.isPerspectiveCamera && this.material.sizeAttenuation === !1 && xi.multiplyScalar(-yi.z); + e.camera === null && console.error('THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.'), Ui.setFromMatrixScale(this.matrixWorld), Cd.copy(e.camera.matrixWorld), this.modelViewMatrix.multiplyMatrices(e.camera.matrixWorldInverse, this.matrixWorld), Di.setFromMatrixPosition(this.modelViewMatrix), e.camera.isPerspectiveCamera && this.material.sizeAttenuation === !1 && Ui.multiplyScalar(-Di.z); let n = this.material.rotation, i, r; n !== 0 && (r = Math.cos(n), i = Math.sin(n)); - let o = this.center; - ds(hs.set(-.5, -.5, 0), yi, o, xi, i, r), ds(er.set(.5, -.5, 0), yi, o, xi, i, r), ds(us.set(.5, .5, 0), yi, o, xi, i, r), jl.set(0, 0), qo.set(1, 0), Ql.set(1, 1); - let a = e.ray.intersectTriangle(hs, er, us, !1, Qi); - if (a === null && (ds(er.set(-.5, .5, 0), yi, o, xi, i, r), qo.set(0, 1), a = e.ray.intersectTriangle(hs, us, er, !1, Qi), a === null)) return; - let l = e.ray.origin.distanceTo(Qi); - l < e.near || l > e.far || t.push({ - distance: l, - point: Qi.clone(), - uv: nt.getUV(Qi, hs, er, us, jl, qo, Ql, new X), + let a = this.center; + dr(hr.set(-.5, -.5, 0), Di, a, Ui, i, r), dr(ps.set(.5, -.5, 0), Di, a, Ui, i, r), dr(ur.set(.5, .5, 0), Di, a, Ui, i, r), Lh.set(0, 0), ja.set(1, 0), Ih.set(1, 1); + let o = e.ray.intersectTriangle(hr, ps, ur, !1, ds); + if (o === null && (dr(ps.set(-.5, .5, 0), Di, a, Ui, i, r), ja.set(0, 1), o = e.ray.intersectTriangle(hr, ur, ps, !1, ds), o === null)) return; + let c = e.ray.origin.distanceTo(ds); + c < e.near || c > e.far || t.push({ + distance: c, + point: ds.clone(), + uv: Un.getInterpolation(ds, hr, ps, ur, Lh, ja, Ih, new Z), face: null, object: this }); } - copy(e) { - return super.copy(e), e.center !== void 0 && this.center.copy(e.center), this.material = e.material, this; + copy(e, t) { + return super.copy(e, t), e.center !== void 0 && this.center.copy(e.center), this.material = e.material, this; } }; -ro.prototype.isSprite = !0; -function ds(s, e, t, n, i, r) { - vi.subVectors(s, t).addScalar(.5).multiply(n), i !== void 0 ? (Ki.x = r * vi.x - i * vi.y, Ki.y = i * vi.x + r * vi.y) : Ki.copy(vi), s.copy(e), s.x += Ki.x, s.y += Ki.y, s.applyMatrix4(Mh); +function dr(s1, e, t, n, i, r) { + Ni.subVectors(s1, t).addScalar(.5).multiply(n), i !== void 0 ? (fs.x = r * Ni.x - i * Ni.y, fs.y = i * Ni.x + r * Ni.y) : fs.copy(Ni), s1.copy(e), s1.x += fs.x, s1.y += fs.y, s1.applyMatrix4(Cd); } -var fs = new M, Kl = new M, bh = class extends Ne { +var fr = new A, Uh = new A, Do = class extends Je { constructor(){ - super(); - this._currentLevel = 0, this.type = "LOD", Object.defineProperties(this, { + super(), this._currentLevel = 0, this.type = "LOD", Object.defineProperties(this, { levels: { enumerable: !0, value: [] @@ -11872,16 +13512,17 @@ var fs = new M, Kl = new M, bh = class extends Ne { let t = e.levels; for(let n = 0, i = t.length; n < i; n++){ let r = t[n]; - this.addLevel(r.object.clone(), r.distance); + this.addLevel(r.object.clone(), r.distance, r.hysteresis); } return this.autoUpdate = e.autoUpdate, this; } - addLevel(e, t = 0) { + addLevel(e, t = 0, n = 0) { t = Math.abs(t); - let n = this.levels, i; - for(i = 0; i < n.length && !(t < n[i].distance); i++); - return n.splice(i, 0, { + let i = this.levels, r; + for(r = 0; r < i.length && !(t < i[r].distance); r++); + return i.splice(r, 0, { distance: t, + hysteresis: n, object: e }), this.add(e), this; } @@ -11892,26 +13533,33 @@ var fs = new M, Kl = new M, bh = class extends Ne { let t = this.levels; if (t.length > 0) { let n, i; - for(n = 1, i = t.length; n < i && !(e < t[n].distance); n++); + for(n = 1, i = t.length; n < i; n++){ + let r = t[n].distance; + if (t[n].object.visible && (r -= r * t[n].hysteresis), e < r) break; + } return t[n - 1].object; } return null; } raycast(e, t) { if (this.levels.length > 0) { - fs.setFromMatrixPosition(this.matrixWorld); - let i = e.ray.origin.distanceTo(fs); + fr.setFromMatrixPosition(this.matrixWorld); + let i = e.ray.origin.distanceTo(fr); this.getObjectForDistance(i).raycast(e, t); } } update(e) { let t = this.levels; if (t.length > 1) { - fs.setFromMatrixPosition(e.matrixWorld), Kl.setFromMatrixPosition(this.matrixWorld); - let n = fs.distanceTo(Kl) / e.zoom; + fr.setFromMatrixPosition(e.matrixWorld), Uh.setFromMatrixPosition(this.matrixWorld); + let n = fr.distanceTo(Uh) / e.zoom; t[0].object.visible = !0; let i, r; - for(i = 1, r = t.length; i < r && n >= t[i].distance; i++)t[i - 1].object.visible = !1, t[i].object.visible = !0; + for(i = 1, r = t.length; i < r; i++){ + let a = t[i].distance; + if (t[i].object.visible && (a -= a * t[i].hysteresis), n >= a) t[i - 1].object.visible = !1, t[i].object.visible = !0; + else break; + } for(this._currentLevel = i - 1; i < r; i++)t[i].object.visible = !1; } } @@ -11920,21 +13568,40 @@ var fs = new M, Kl = new M, bh = class extends Ne { this.autoUpdate === !1 && (t.object.autoUpdate = !1), t.object.levels = []; let n = this.levels; for(let i = 0, r = n.length; i < r; i++){ - let o = n[i]; + let a = n[i]; t.object.levels.push({ - object: o.object.uuid, - distance: o.distance + object: a.object.uuid, + distance: a.distance, + hysteresis: a.hysteresis }); } return t; } -}, ec = new M, tc = new Ve, nc = new Ve, Rx = new M, ic = new pe, so = class extends st { +}, Dh = new A, Nh = new je, Oh = new je, W0 = new A, Fh = new ze, Oi = new A, eo = new Yt, Bh = new ze, to = new hi, No = class extends Mt { constructor(e, t){ - super(e, t); - this.type = "SkinnedMesh", this.bindMode = "attached", this.bindMatrix = new pe, this.bindMatrixInverse = new pe; + super(e, t), this.isSkinnedMesh = !0, this.type = "SkinnedMesh", this.bindMode = "attached", this.bindMatrix = new ze, this.bindMatrixInverse = new ze, this.boundingBox = null, this.boundingSphere = null; } - copy(e) { - return super.copy(e), this.bindMode = e.bindMode, this.bindMatrix.copy(e.bindMatrix), this.bindMatrixInverse.copy(e.bindMatrixInverse), this.skeleton = e.skeleton, this; + computeBoundingBox() { + let e = this.geometry; + this.boundingBox === null && (this.boundingBox = new Qt), this.boundingBox.makeEmpty(); + let t = e.getAttribute("position"); + for(let n = 0; n < t.count; n++)Oi.fromBufferAttribute(t, n), this.applyBoneTransform(n, Oi), this.boundingBox.expandByPoint(Oi); + } + computeBoundingSphere() { + let e = this.geometry; + this.boundingSphere === null && (this.boundingSphere = new Yt), this.boundingSphere.makeEmpty(); + let t = e.getAttribute("position"); + for(let n = 0; n < t.count; n++)Oi.fromBufferAttribute(t, n), this.applyBoneTransform(n, Oi), this.boundingSphere.expandByPoint(Oi); + } + copy(e, t) { + return super.copy(e, t), this.bindMode = e.bindMode, this.bindMatrix.copy(e.bindMatrix), this.bindMatrixInverse.copy(e.bindMatrixInverse), this.skeleton = e.skeleton, e.boundingBox !== null && (this.boundingBox = e.boundingBox.clone()), e.boundingSphere !== null && (this.boundingSphere = e.boundingSphere.clone()), this; + } + raycast(e, t) { + let n = this.material, i = this.matrixWorld; + n !== void 0 && (this.boundingSphere === null && this.computeBoundingSphere(), eo.copy(this.boundingSphere), eo.applyMatrix4(i), e.ray.intersectsSphere(eo) !== !1 && (Bh.copy(i).invert(), to.copy(e.ray).applyMatrix4(Bh), !(this.boundingBox !== null && to.intersectsBox(this.boundingBox) === !1) && this._computeIntersections(e, t, to))); + } + getVertexPosition(e, t) { + return super.getVertexPosition(e, t), this.applyBoneTransform(e, t), t; } bind(e, t) { this.skeleton = e, t === void 0 && (this.updateMatrixWorld(!0), this.skeleton.calculateInverses(), t = this.matrixWorld), this.bindMatrix.copy(t), this.bindMatrixInverse.copy(t).invert(); @@ -11943,9 +13610,9 @@ var fs = new M, Kl = new M, bh = class extends Ne { this.skeleton.pose(); } normalizeSkinWeights() { - let e = new Ve, t = this.geometry.attributes.skinWeight; + let e = new je, t = this.geometry.attributes.skinWeight; for(let n = 0, i = t.count; n < i; n++){ - e.x = t.getX(n), e.y = t.getY(n), e.z = t.getZ(n), e.w = t.getW(n); + e.fromBufferAttribute(t, n); let r = 1 / e.manhattanLength(); r !== 1 / 0 ? e.multiplyScalar(r) : e.set(1, 0, 0, 0), t.setXYZW(n, e.x, e.y, e.z, e.w); } @@ -11953,54 +13620,49 @@ var fs = new M, Kl = new M, bh = class extends Ne { updateMatrixWorld(e) { super.updateMatrixWorld(e), this.bindMode === "attached" ? this.bindMatrixInverse.copy(this.matrixWorld).invert() : this.bindMode === "detached" ? this.bindMatrixInverse.copy(this.bindMatrix).invert() : console.warn("THREE.SkinnedMesh: Unrecognized bindMode: " + this.bindMode); } - boneTransform(e, t) { + applyBoneTransform(e, t) { let n = this.skeleton, i = this.geometry; - tc.fromBufferAttribute(i.attributes.skinIndex, e), nc.fromBufferAttribute(i.attributes.skinWeight, e), ec.copy(t).applyMatrix4(this.bindMatrix), t.set(0, 0, 0); + Nh.fromBufferAttribute(i.attributes.skinIndex, e), Oh.fromBufferAttribute(i.attributes.skinWeight, e), Dh.copy(t).applyMatrix4(this.bindMatrix), t.set(0, 0, 0); for(let r = 0; r < 4; r++){ - let o = nc.getComponent(r); - if (o !== 0) { - let a = tc.getComponent(r); - ic.multiplyMatrices(n.bones[a].matrixWorld, n.boneInverses[a]), t.addScaledVector(Rx.copy(ec).applyMatrix4(ic), o); + let a = Oh.getComponent(r); + if (a !== 0) { + let o = Nh.getComponent(r); + Fh.multiplyMatrices(n.bones[o].matrixWorld, n.boneInverses[o]), t.addScaledVector(W0.copy(Dh).applyMatrix4(Fh), a); } } return t.applyMatrix4(this.bindMatrixInverse); } -}; -so.prototype.isSkinnedMesh = !0; -var oo = class extends Ne { + boneTransform(e, t) { + return console.warn("THREE.SkinnedMesh: .boneTransform() was renamed to .applyBoneTransform() in r151."), this.applyBoneTransform(e, t); + } +}, ta = class extends Je { constructor(){ - super(); - this.type = "Bone"; + super(), this.isBone = !0, this.type = "Bone"; } -}; -oo.prototype.isBone = !0; -var qn = class extends ot { - constructor(e = null, t = 1, n = 1, i, r, o, a, l, c = rt, h = rt, u, d){ - super(null, o, a, l, c, h, i, r, u, d); - this.image = { +}, oi = class extends St { + constructor(e = null, t = 1, n = 1, i, r, a, o, c, l = pt, h = pt, u, d){ + super(null, a, o, c, l, h, i, r, u, d), this.isDataTexture = !0, this.image = { data: e, width: t, height: n - }, this.magFilter = c, this.minFilter = h, this.generateMipmaps = !1, this.flipY = !1, this.unpackAlignment = 1; + }, this.generateMipmaps = !1, this.flipY = !1, this.unpackAlignment = 1; } -}; -qn.prototype.isDataTexture = !0; -var rc = new pe, Px = new pe, ao = class { +}, zh = new ze, X0 = new ze, Oo = class s1 { constructor(e = [], t = []){ - this.uuid = Et(), this.bones = e.slice(0), this.boneInverses = t, this.boneMatrices = null, this.boneTexture = null, this.boneTextureSize = 0, this.frame = -1, this.init(); + this.uuid = kt(), this.bones = e.slice(0), this.boneInverses = t, this.boneMatrices = null, this.boneTexture = null, this.boneTextureSize = 0, this.init(); } init() { let e = this.bones, t = this.boneInverses; if (this.boneMatrices = new Float32Array(e.length * 16), t.length === 0) this.calculateInverses(); else if (e.length !== t.length) { console.warn("THREE.Skeleton: Number of inverse bone matrices does not match amount of bones."), this.boneInverses = []; - for(let n = 0, i = this.bones.length; n < i; n++)this.boneInverses.push(new pe); + for(let n = 0, i = this.bones.length; n < i; n++)this.boneInverses.push(new ze); } } calculateInverses() { this.boneInverses.length = 0; for(let e = 0, t = this.bones.length; e < t; e++){ - let n = new pe; + let n = new ze; this.bones[e] && n.copy(this.bones[e].matrixWorld).invert(), this.boneInverses.push(n); } } @@ -12016,21 +13678,21 @@ var rc = new pe, Px = new pe, ao = class { } update() { let e = this.bones, t = this.boneInverses, n = this.boneMatrices, i = this.boneTexture; - for(let r = 0, o = e.length; r < o; r++){ - let a = e[r] ? e[r].matrixWorld : Px; - rc.multiplyMatrices(a, t[r]), rc.toArray(n, r * 16); + for(let r = 0, a = e.length; r < a; r++){ + let o = e[r] ? e[r].matrixWorld : X0; + zh.multiplyMatrices(o, t[r]), zh.toArray(n, r * 16); } i !== null && (i.needsUpdate = !0); } clone() { - return new ao(this.bones, this.boneInverses); + return new s1(this.bones, this.boneInverses); } computeBoneTexture() { let e = Math.sqrt(this.bones.length * 4); - e = Xc(e), e = Math.max(e, 4); + e = yd(e), e = Math.max(e, 4); let t = new Float32Array(e * e * 4); t.set(this.boneMatrices); - let n = new qn(t, e, e, ct, nn); + let n = new oi(t, e, e, Wt, xn); return n.needsUpdate = !0, this.boneMatrices = t, this.boneTexture = n, this.boneTextureSize = e, this; } getBoneByName(e) { @@ -12045,15 +13707,15 @@ var rc = new pe, Px = new pe, ao = class { fromJSON(e, t) { this.uuid = e.uuid; for(let n = 0, i = e.bones.length; n < i; n++){ - let r = e.bones[n], o = t[r]; - o === void 0 && (console.warn("THREE.Skeleton: No bone found with UUID:", r), o = new oo), this.bones.push(o), this.boneInverses.push(new pe().fromArray(e.boneInverses[n])); + let r = e.bones[n], a = t[r]; + a === void 0 && (console.warn("THREE.Skeleton: No bone found with UUID:", r), a = new ta), this.bones.push(a), this.boneInverses.push(new ze().fromArray(e.boneInverses[n])); } return this.init(), this; } toJSON() { let e = { metadata: { - version: 4.5, + version: 4.6, type: "Skeleton", generator: "Skeleton.toJSON" }, @@ -12063,18 +13725,16 @@ var rc = new pe, Px = new pe, ao = class { e.uuid = this.uuid; let t = this.bones, n = this.boneInverses; for(let i = 0, r = t.length; i < r; i++){ - let o = t[i]; - e.bones.push(o.uuid); - let a = n[i]; - e.boneInverses.push(a.toArray()); + let a = t[i]; + e.bones.push(a.uuid); + let o = n[i]; + e.boneInverses.push(o.toArray()); } return e; } -}, Xn = class extends Ue { +}, ui = class extends et { constructor(e, t, n, i = 1){ - typeof n == "number" && (i = n, n = !1, console.error("THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument.")); - super(e, t, n); - this.meshPerAttribute = i; + super(e, t, n), this.isInstancedBufferAttribute = !0, this.meshPerAttribute = i; } copy(e) { return super.copy(e), this.meshPerAttribute = e.meshPerAttribute, this; @@ -12083,15 +13743,23 @@ var rc = new pe, Px = new pe, ao = class { let e = super.toJSON(); return e.meshPerAttribute = this.meshPerAttribute, e.isInstancedBufferAttribute = !0, e; } -}; -Xn.prototype.isInstancedBufferAttribute = !0; -var sc = new pe, oc = new pe, ps = [], tr = new st, xa = class extends st { +}, Fi = new ze, Vh = new ze, pr = [], kh = new Qt, q0 = new ze, ms = new Mt, gs = new Yt, Fo = class extends Mt { constructor(e, t, n){ - super(e, t); - this.instanceMatrix = new Xn(new Float32Array(n * 16), 16), this.instanceColor = null, this.count = n, this.frustumCulled = !1; + super(e, t), this.isInstancedMesh = !0, this.instanceMatrix = new ui(new Float32Array(n * 16), 16), this.instanceColor = null, this.count = n, this.boundingBox = null, this.boundingSphere = null; + for(let i = 0; i < n; i++)this.setMatrixAt(i, q0); } - copy(e) { - return super.copy(e), this.instanceMatrix.copy(e.instanceMatrix), e.instanceColor !== null && (this.instanceColor = e.instanceColor.clone()), this.count = e.count, this; + computeBoundingBox() { + let e = this.geometry, t = this.count; + this.boundingBox === null && (this.boundingBox = new Qt), e.boundingBox === null && e.computeBoundingBox(), this.boundingBox.makeEmpty(); + for(let n = 0; n < t; n++)this.getMatrixAt(n, Fi), kh.copy(e.boundingBox).applyMatrix4(Fi), this.boundingBox.union(kh); + } + computeBoundingSphere() { + let e = this.geometry, t = this.count; + this.boundingSphere === null && (this.boundingSphere = new Yt), e.boundingSphere === null && e.computeBoundingSphere(), this.boundingSphere.makeEmpty(); + for(let n = 0; n < t; n++)this.getMatrixAt(n, Fi), gs.copy(e.boundingSphere).applyMatrix4(Fi), this.boundingSphere.union(gs); + } + copy(e, t) { + return super.copy(e, t), this.instanceMatrix.copy(e.instanceMatrix), e.instanceColor !== null && (this.instanceColor = e.instanceColor.clone()), this.count = e.count, e.boundingBox !== null && (this.boundingBox = e.boundingBox.clone()), e.boundingSphere !== null && (this.boundingSphere = e.boundingSphere.clone()), this; } getColorAt(e, t) { t.fromArray(this.instanceColor.array, e * 3); @@ -12101,17 +13769,17 @@ var sc = new pe, oc = new pe, ps = [], tr = new st, xa = class extends st { } raycast(e, t) { let n = this.matrixWorld, i = this.count; - if (tr.geometry = this.geometry, tr.material = this.material, tr.material !== void 0) for(let r = 0; r < i; r++){ - this.getMatrixAt(r, sc), oc.multiplyMatrices(n, sc), tr.matrixWorld = oc, tr.raycast(e, ps); - for(let o = 0, a = ps.length; o < a; o++){ - let l = ps[o]; - l.instanceId = r, l.object = this, t.push(l); + if (ms.geometry = this.geometry, ms.material = this.material, ms.material !== void 0 && (this.boundingSphere === null && this.computeBoundingSphere(), gs.copy(this.boundingSphere), gs.applyMatrix4(n), e.ray.intersectsSphere(gs) !== !1)) for(let r = 0; r < i; r++){ + this.getMatrixAt(r, Fi), Vh.multiplyMatrices(n, Fi), ms.matrixWorld = Vh, ms.raycast(e, pr); + for(let a = 0, o = pr.length; a < o; a++){ + let c = pr[a]; + c.instanceId = r, c.object = this, t.push(c); } - ps.length = 0; + pr.length = 0; } } setColorAt(e, t) { - this.instanceColor === null && (this.instanceColor = new Xn(new Float32Array(this.instanceMatrix.count * 3), 3)), t.toArray(this.instanceColor.array, e * 3); + this.instanceColor === null && (this.instanceColor = new ui(new Float32Array(this.instanceMatrix.count * 3), 3)), t.toArray(this.instanceColor.array, e * 3); } setMatrixAt(e, t) { t.toArray(this.instanceMatrix.array, e * 16); @@ -12122,203 +13790,163 @@ var sc = new pe, oc = new pe, ps = [], tr = new st, xa = class extends st { type: "dispose" }); } -}; -xa.prototype.isInstancedMesh = !0; -var ft = class extends dt { +}, wt = class extends bt { constructor(e){ - super(); - this.type = "LineBasicMaterial", this.color = new ae(16777215), this.linewidth = 1, this.linecap = "round", this.linejoin = "round", this.setValues(e); + super(), this.isLineBasicMaterial = !0, this.type = "LineBasicMaterial", this.color = new pe(16777215), this.map = null, this.linewidth = 1, this.linecap = "round", this.linejoin = "round", this.fog = !0, this.setValues(e); } copy(e) { - return super.copy(e), this.color.copy(e.color), this.linewidth = e.linewidth, this.linecap = e.linecap, this.linejoin = e.linejoin, this; + return super.copy(e), this.color.copy(e.color), this.map = e.map, this.linewidth = e.linewidth, this.linecap = e.linecap, this.linejoin = e.linejoin, this.fog = e.fog, this; } -}; -ft.prototype.isLineBasicMaterial = !0; -var ac = new M, lc = new M, cc = new pe, Xo = new Cn, ms = new An, on = class extends Ne { - constructor(e = new _e, t = new ft){ - super(); - this.type = "Line", this.geometry = e, this.material = t, this.updateMorphTargets(); +}, Hh = new A, Gh = new A, Wh = new ze, no = new hi, mr = new Yt, bn = class extends Je { + constructor(e = new Ge, t = new wt){ + super(), this.isLine = !0, this.type = "Line", this.geometry = e, this.material = t, this.updateMorphTargets(); } - copy(e) { - return super.copy(e), this.material = e.material, this.geometry = e.geometry, this; + copy(e, t) { + return super.copy(e, t), this.material = Array.isArray(e.material) ? e.material.slice() : e.material, this.geometry = e.geometry, this; } computeLineDistances() { let e = this.geometry; - if (e.isBufferGeometry) if (e.index === null) { + if (e.index === null) { let t = e.attributes.position, n = [ 0 ]; - for(let i = 1, r = t.count; i < r; i++)ac.fromBufferAttribute(t, i - 1), lc.fromBufferAttribute(t, i), n[i] = n[i - 1], n[i] += ac.distanceTo(lc); - e.setAttribute("lineDistance", new de(n, 1)); + for(let i = 1, r = t.count; i < r; i++)Hh.fromBufferAttribute(t, i - 1), Gh.fromBufferAttribute(t, i), n[i] = n[i - 1], n[i] += Hh.distanceTo(Gh); + e.setAttribute("lineDistance", new ve(n, 1)); } else console.warn("THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry."); - else e.isGeometry && console.error("THREE.Line.computeLineDistances() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead."); return this; } raycast(e, t) { - let n = this.geometry, i = this.matrixWorld, r = e.params.Line.threshold, o = n.drawRange; - if (n.boundingSphere === null && n.computeBoundingSphere(), ms.copy(n.boundingSphere), ms.applyMatrix4(i), ms.radius += r, e.ray.intersectsSphere(ms) === !1) return; - cc.copy(i).invert(), Xo.copy(e.ray).applyMatrix4(cc); - let a = r / ((this.scale.x + this.scale.y + this.scale.z) / 3), l = a * a, c = new M, h = new M, u = new M, d = new M, f = this.isLineSegments ? 2 : 1; - if (n.isBufferGeometry) { - let m = n.index, v = n.attributes.position; - if (m !== null) { - let g = Math.max(0, o.start), p = Math.min(m.count, o.start + o.count); - for(let _ = g, y = p - 1; _ < y; _ += f){ - let b = m.getX(_), A = m.getX(_ + 1); - if (c.fromBufferAttribute(v, b), h.fromBufferAttribute(v, A), Xo.distanceSqToSegment(c, h, d, u) > l) continue; - d.applyMatrix4(this.matrixWorld); - let I = e.ray.origin.distanceTo(d); - I < e.near || I > e.far || t.push({ - distance: I, - point: u.clone().applyMatrix4(this.matrixWorld), - index: _, - face: null, - faceIndex: null, - object: this - }); - } - } else { - let g = Math.max(0, o.start), p = Math.min(v.count, o.start + o.count); - for(let _ = g, y = p - 1; _ < y; _ += f){ - if (c.fromBufferAttribute(v, _), h.fromBufferAttribute(v, _ + 1), Xo.distanceSqToSegment(c, h, d, u) > l) continue; - d.applyMatrix4(this.matrixWorld); - let A = e.ray.origin.distanceTo(d); - A < e.near || A > e.far || t.push({ - distance: A, - point: u.clone().applyMatrix4(this.matrixWorld), - index: _, - face: null, - faceIndex: null, - object: this - }); - } + let n = this.geometry, i = this.matrixWorld, r = e.params.Line.threshold, a = n.drawRange; + if (n.boundingSphere === null && n.computeBoundingSphere(), mr.copy(n.boundingSphere), mr.applyMatrix4(i), mr.radius += r, e.ray.intersectsSphere(mr) === !1) return; + Wh.copy(i).invert(), no.copy(e.ray).applyMatrix4(Wh); + let o = r / ((this.scale.x + this.scale.y + this.scale.z) / 3), c = o * o, l = new A, h = new A, u = new A, d = new A, f = this.isLineSegments ? 2 : 1, m = n.index, g = n.attributes.position; + if (m !== null) { + let p = Math.max(0, a.start), v = Math.min(m.count, a.start + a.count); + for(let x = p, y = v - 1; x < y; x += f){ + let b = m.getX(x), w = m.getX(x + 1); + if (l.fromBufferAttribute(g, b), h.fromBufferAttribute(g, w), no.distanceSqToSegment(l, h, d, u) > c) continue; + d.applyMatrix4(this.matrixWorld); + let I = e.ray.origin.distanceTo(d); + I < e.near || I > e.far || t.push({ + distance: I, + point: u.clone().applyMatrix4(this.matrixWorld), + index: x, + face: null, + faceIndex: null, + object: this + }); + } + } else { + let p = Math.max(0, a.start), v = Math.min(g.count, a.start + a.count); + for(let x = p, y = v - 1; x < y; x += f){ + if (l.fromBufferAttribute(g, x), h.fromBufferAttribute(g, x + 1), no.distanceSqToSegment(l, h, d, u) > c) continue; + d.applyMatrix4(this.matrixWorld); + let w = e.ray.origin.distanceTo(d); + w < e.near || w > e.far || t.push({ + distance: w, + point: u.clone().applyMatrix4(this.matrixWorld), + index: x, + face: null, + faceIndex: null, + object: this + }); } - } else n.isGeometry && console.error("THREE.Line.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead."); + } } updateMorphTargets() { - let e = this.geometry; - if (e.isBufferGeometry) { - let t = e.morphAttributes, n = Object.keys(t); - if (n.length > 0) { - let i = t[n[0]]; - if (i !== void 0) { - this.morphTargetInfluences = [], this.morphTargetDictionary = {}; - for(let r = 0, o = i.length; r < o; r++){ - let a = i[r].name || String(r); - this.morphTargetInfluences.push(0), this.morphTargetDictionary[a] = r; - } + let t = this.geometry.morphAttributes, n = Object.keys(t); + if (n.length > 0) { + let i = t[n[0]]; + if (i !== void 0) { + this.morphTargetInfluences = [], this.morphTargetDictionary = {}; + for(let r = 0, a = i.length; r < a; r++){ + let o = i[r].name || String(r); + this.morphTargetInfluences.push(0), this.morphTargetDictionary[o] = r; } } - } else { - let t = e.morphTargets; - t !== void 0 && t.length > 0 && console.error("THREE.Line.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead."); } } -}; -on.prototype.isLine = !0; -var hc = new M, uc = new M, wt = class extends on { +}, Xh = new A, qh = new A, en = class extends bn { constructor(e, t){ - super(e, t); - this.type = "LineSegments"; + super(e, t), this.isLineSegments = !0, this.type = "LineSegments"; } computeLineDistances() { let e = this.geometry; - if (e.isBufferGeometry) if (e.index === null) { + if (e.index === null) { let t = e.attributes.position, n = []; - for(let i = 0, r = t.count; i < r; i += 2)hc.fromBufferAttribute(t, i), uc.fromBufferAttribute(t, i + 1), n[i] = i === 0 ? 0 : n[i - 1], n[i + 1] = n[i] + hc.distanceTo(uc); - e.setAttribute("lineDistance", new de(n, 1)); + for(let i = 0, r = t.count; i < r; i += 2)Xh.fromBufferAttribute(t, i), qh.fromBufferAttribute(t, i + 1), n[i] = i === 0 ? 0 : n[i - 1], n[i + 1] = n[i] + Xh.distanceTo(qh); + e.setAttribute("lineDistance", new ve(n, 1)); } else console.warn("THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry."); - else e.isGeometry && console.error("THREE.LineSegments.computeLineDistances() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead."); return this; } -}; -wt.prototype.isLineSegments = !0; -var ya = class extends on { +}, Bo = class extends bn { constructor(e, t){ - super(e, t); - this.type = "LineLoop"; + super(e, t), this.isLineLoop = !0, this.type = "LineLoop"; } -}; -ya.prototype.isLineLoop = !0; -var jn = class extends dt { +}, na = class extends bt { constructor(e){ - super(); - this.type = "PointsMaterial", this.color = new ae(16777215), this.map = null, this.alphaMap = null, this.size = 1, this.sizeAttenuation = !0, this.setValues(e); + super(), this.isPointsMaterial = !0, this.type = "PointsMaterial", this.color = new pe(16777215), this.map = null, this.alphaMap = null, this.size = 1, this.sizeAttenuation = !0, this.fog = !0, this.setValues(e); } copy(e) { - return super.copy(e), this.color.copy(e.color), this.map = e.map, this.alphaMap = e.alphaMap, this.size = e.size, this.sizeAttenuation = e.sizeAttenuation, this; + return super.copy(e), this.color.copy(e.color), this.map = e.map, this.alphaMap = e.alphaMap, this.size = e.size, this.sizeAttenuation = e.sizeAttenuation, this.fog = e.fog, this; } -}; -jn.prototype.isPointsMaterial = !0; -var dc = new pe, sa = new Cn, gs = new An, xs = new M, zr = class extends Ne { - constructor(e = new _e, t = new jn){ - super(); - this.type = "Points", this.geometry = e, this.material = t, this.updateMorphTargets(); +}, Yh = new ze, zo = new hi, gr = new Yt, _r = new A, Vo = class extends Je { + constructor(e = new Ge, t = new na){ + super(), this.isPoints = !0, this.type = "Points", this.geometry = e, this.material = t, this.updateMorphTargets(); } - copy(e) { - return super.copy(e), this.material = e.material, this.geometry = e.geometry, this; + copy(e, t) { + return super.copy(e, t), this.material = Array.isArray(e.material) ? e.material.slice() : e.material, this.geometry = e.geometry, this; } raycast(e, t) { - let n = this.geometry, i = this.matrixWorld, r = e.params.Points.threshold, o = n.drawRange; - if (n.boundingSphere === null && n.computeBoundingSphere(), gs.copy(n.boundingSphere), gs.applyMatrix4(i), gs.radius += r, e.ray.intersectsSphere(gs) === !1) return; - dc.copy(i).invert(), sa.copy(e.ray).applyMatrix4(dc); - let a = r / ((this.scale.x + this.scale.y + this.scale.z) / 3), l = a * a; - if (n.isBufferGeometry) { - let c = n.index, u = n.attributes.position; - if (c !== null) { - let d = Math.max(0, o.start), f = Math.min(c.count, o.start + o.count); - for(let m = d, x = f; m < x; m++){ - let v = c.getX(m); - xs.fromBufferAttribute(u, v), fc(xs, v, l, i, e, t, this); - } - } else { - let d = Math.max(0, o.start), f = Math.min(u.count, o.start + o.count); - for(let m = d, x = f; m < x; m++)xs.fromBufferAttribute(u, m), fc(xs, m, l, i, e, t, this); + let n = this.geometry, i = this.matrixWorld, r = e.params.Points.threshold, a = n.drawRange; + if (n.boundingSphere === null && n.computeBoundingSphere(), gr.copy(n.boundingSphere), gr.applyMatrix4(i), gr.radius += r, e.ray.intersectsSphere(gr) === !1) return; + Yh.copy(i).invert(), zo.copy(e.ray).applyMatrix4(Yh); + let o = r / ((this.scale.x + this.scale.y + this.scale.z) / 3), c = o * o, l = n.index, u = n.attributes.position; + if (l !== null) { + let d = Math.max(0, a.start), f = Math.min(l.count, a.start + a.count); + for(let m = d, _ = f; m < _; m++){ + let g = l.getX(m); + _r.fromBufferAttribute(u, g), Zh(_r, g, c, i, e, t, this); } - } else console.error("THREE.Points.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead."); + } else { + let d = Math.max(0, a.start), f = Math.min(u.count, a.start + a.count); + for(let m = d, _ = f; m < _; m++)_r.fromBufferAttribute(u, m), Zh(_r, m, c, i, e, t, this); + } } updateMorphTargets() { - let e = this.geometry; - if (e.isBufferGeometry) { - let t = e.morphAttributes, n = Object.keys(t); - if (n.length > 0) { - let i = t[n[0]]; - if (i !== void 0) { - this.morphTargetInfluences = [], this.morphTargetDictionary = {}; - for(let r = 0, o = i.length; r < o; r++){ - let a = i[r].name || String(r); - this.morphTargetInfluences.push(0), this.morphTargetDictionary[a] = r; - } + let t = this.geometry.morphAttributes, n = Object.keys(t); + if (n.length > 0) { + let i = t[n[0]]; + if (i !== void 0) { + this.morphTargetInfluences = [], this.morphTargetDictionary = {}; + for(let r = 0, a = i.length; r < a; r++){ + let o = i[r].name || String(r); + this.morphTargetInfluences.push(0), this.morphTargetDictionary[o] = r; } } - } else { - let t = e.morphTargets; - t !== void 0 && t.length > 0 && console.error("THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead."); } } }; -zr.prototype.isPoints = !0; -function fc(s, e, t, n, i, r, o) { - let a = sa.distanceSqToPoint(s); - if (a < t) { - let l = new M; - sa.closestPointToPoint(s, l), l.applyMatrix4(n); - let c = i.ray.origin.distanceTo(l); - if (c < i.near || c > i.far) return; +function Zh(s1, e, t, n, i, r, a) { + let o = zo.distanceSqToPoint(s1); + if (o < t) { + let c = new A; + zo.closestPointToPoint(s1, c), c.applyMatrix4(n); + let l = i.ray.origin.distanceTo(c); + if (l < i.near || l > i.far) return; r.push({ - distance: c, - distanceToRay: Math.sqrt(a), - point: l, + distance: l, + distanceToRay: Math.sqrt(o), + point: c, index: e, face: null, - object: o + object: a }); } } -var wh = class extends ot { - constructor(e, t, n, i, r, o, a, l, c){ - super(e, t, n, i, r, o, a, l, c); - this.format = a !== void 0 ? a : Gn, this.minFilter = o !== void 0 ? o : tt, this.magFilter = r !== void 0 ? r : tt, this.generateMipmaps = !1; +var Jh = class extends St { + constructor(e, t, n, i, r, a, o, c, l){ + super(e, t, n, i, r, a, o, c, l), this.isVideoTexture = !0, this.minFilter = a !== void 0 ? a : mt, this.magFilter = r !== void 0 ? r : mt, this.generateMipmaps = !1; let h = this; function u() { h.needsUpdate = !0, e.requestVideoFrameCallback(u); @@ -12332,714 +13960,320 @@ var wh = class extends ot { let e = this.image; "requestVideoFrameCallback" in e === !1 && e.readyState >= e.HAVE_CURRENT_DATA && (this.needsUpdate = !0); } -}; -wh.prototype.isVideoTexture = !0; -var Sh = class extends ot { - constructor(e, t, n){ +}, $h = class extends St { + constructor(e, t){ super({ width: e, height: t - }); - this.format = n, this.magFilter = rt, this.minFilter = rt, this.generateMipmaps = !1, this.needsUpdate = !0; + }), this.isFramebufferTexture = !0, this.magFilter = pt, this.minFilter = pt, this.generateMipmaps = !1, this.needsUpdate = !0; } -}; -Sh.prototype.isFramebufferTexture = !0; -var va = class extends ot { - constructor(e, t, n, i, r, o, a, l, c, h, u, d){ - super(null, o, a, l, c, h, i, r, u, d); - this.image = { +}, Us = class extends St { + constructor(e, t, n, i, r, a, o, c, l, h, u, d){ + super(null, a, o, c, l, h, i, r, u, d), this.isCompressedTexture = !0, this.image = { width: t, height: n }, this.mipmaps = e, this.flipY = !1, this.generateMipmaps = !1; } -}; -va.prototype.isCompressedTexture = !0; -var Th = class extends ot { - constructor(e, t, n, i, r, o, a, l, c){ - super(e, t, n, i, r, o, a, l, c); - this.needsUpdate = !0; +}, Kh = class extends Us { + constructor(e, t, n, i, r, a){ + super(e, t, n, r, a), this.isCompressedArrayTexture = !0, this.image.depth = i, this.wrapR = It; } -}; -Th.prototype.isCanvasTexture = !0; -var fr = class extends _e { - constructor(e = 1, t = 8, n = 0, i = Math.PI * 2){ - super(); - this.type = "CircleGeometry", this.parameters = { - radius: e, - segments: t, - thetaStart: n, - thetaLength: i - }, t = Math.max(3, t); - let r = [], o = [], a = [], l = [], c = new M, h = new X; - o.push(0, 0, 0), a.push(0, 0, 1), l.push(.5, .5); - for(let u = 0, d = 3; u <= t; u++, d += 3){ - let f = n + u / t * i; - c.x = e * Math.cos(f), c.y = e * Math.sin(f), o.push(c.x, c.y, c.z), a.push(0, 0, 1), h.x = (o[d] / e + 1) / 2, h.y = (o[d + 1] / e + 1) / 2, l.push(h.x, h.y); - } - for(let u = 1; u <= t; u++)r.push(u, u + 1, 0); - this.setIndex(r), this.setAttribute("position", new de(o, 3)), this.setAttribute("normal", new de(a, 3)), this.setAttribute("uv", new de(l, 2)); +}, Qh = class extends Us { + constructor(e, t, n){ + super(void 0, e[0].width, e[0].height, t, n, zn), this.isCompressedCubeTexture = !0, this.isCubeTexture = !0, this.image = e; } - static fromJSON(e) { - return new fr(e.radius, e.segments, e.thetaStart, e.thetaLength); +}, jh = class extends St { + constructor(e, t, n, i, r, a, o, c, l){ + super(e, t, n, i, r, a, o, c, l), this.isCanvasTexture = !0, this.needsUpdate = !0; } -}, Jn = class extends _e { - constructor(e = 1, t = 1, n = 1, i = 8, r = 1, o = !1, a = 0, l = Math.PI * 2){ - super(); - this.type = "CylinderGeometry", this.parameters = { - radiusTop: e, - radiusBottom: t, - height: n, - radialSegments: i, - heightSegments: r, - openEnded: o, - thetaStart: a, - thetaLength: l - }; - let c = this; - i = Math.floor(i), r = Math.floor(r); - let h = [], u = [], d = [], f = [], m = 0, x = [], v = n / 2, g = 0; - p(), o === !1 && (e > 0 && _(!0), t > 0 && _(!1)), this.setIndex(h), this.setAttribute("position", new de(u, 3)), this.setAttribute("normal", new de(d, 3)), this.setAttribute("uv", new de(f, 2)); - function p() { - let y = new M, b = new M, A = 0, L = (t - e) / n; - for(let I = 0; I <= r; I++){ - let k = [], B = I / r, P = B * (t - e) + e; - for(let w = 0; w <= i; w++){ - let E = w / i, D = E * l + a, U = Math.sin(D), F = Math.cos(D); - b.x = P * U, b.y = -B * n + v, b.z = P * F, u.push(b.x, b.y, b.z), y.set(U, L, F).normalize(), d.push(y.x, y.y, y.z), f.push(E, 1 - B), k.push(m++); - } - x.push(k); - } - for(let I = 0; I < i; I++)for(let k = 0; k < r; k++){ - let B = x[k][I], P = x[k + 1][I], w = x[k + 1][I + 1], E = x[k][I + 1]; - h.push(B, P, E), h.push(P, w, E), A += 6; - } - c.addGroup(g, A, 0), g += A; - } - function _(y) { - let b = m, A = new X, L = new M, I = 0, k = y === !0 ? e : t, B = y === !0 ? 1 : -1; - for(let w = 1; w <= i; w++)u.push(0, v * B, 0), d.push(0, B, 0), f.push(.5, .5), m++; - let P = m; - for(let w = 0; w <= i; w++){ - let D = w / i * l + a, U = Math.cos(D), F = Math.sin(D); - L.x = k * F, L.y = v * B, L.z = k * U, u.push(L.x, L.y, L.z), d.push(0, B, 0), A.x = U * .5 + .5, A.y = F * .5 * B + .5, f.push(A.x, A.y), m++; - } - for(let w = 0; w < i; w++){ - let E = b + w, D = P + w; - y === !0 ? h.push(D, D + 1, E) : h.push(D + 1, D, E), I += 3; - } - c.addGroup(g, I, y === !0 ? 1 : 2), g += I; - } +}, Zt = class { + constructor(){ + this.type = "Curve", this.arcLengthDivisions = 200; } - static fromJSON(e) { - return new Jn(e.radiusTop, e.radiusBottom, e.height, e.radialSegments, e.heightSegments, e.openEnded, e.thetaStart, e.thetaLength); + getPoint() { + return console.warn("THREE.Curve: .getPoint() not implemented."), null; } -}, pr = class extends Jn { - constructor(e = 1, t = 1, n = 8, i = 1, r = !1, o = 0, a = Math.PI * 2){ - super(0, e, t, n, i, r, o, a); - this.type = "ConeGeometry", this.parameters = { - radius: e, - height: t, - radialSegments: n, - heightSegments: i, - openEnded: r, - thetaStart: o, - thetaLength: a - }; + getPointAt(e, t) { + let n = this.getUtoTmapping(e); + return this.getPoint(n, t); } - static fromJSON(e) { - return new pr(e.radius, e.height, e.radialSegments, e.heightSegments, e.openEnded, e.thetaStart, e.thetaLength); + getPoints(e = 5) { + let t = []; + for(let n = 0; n <= e; n++)t.push(this.getPoint(n / e)); + return t; } -}, an = class extends _e { - constructor(e = [], t = [], n = 1, i = 0){ - super(); - this.type = "PolyhedronGeometry", this.parameters = { - vertices: e, - indices: t, - radius: n, - detail: i - }; - let r = [], o = []; - a(i), c(n), h(), this.setAttribute("position", new de(r, 3)), this.setAttribute("normal", new de(r.slice(), 3)), this.setAttribute("uv", new de(o, 2)), i === 0 ? this.computeVertexNormals() : this.normalizeNormals(); - function a(p) { - let _ = new M, y = new M, b = new M; - for(let A = 0; A < t.length; A += 3)f(t[A + 0], _), f(t[A + 1], y), f(t[A + 2], b), l(_, y, b, p); - } - function l(p, _, y, b) { - let A = b + 1, L = []; - for(let I = 0; I <= A; I++){ - L[I] = []; - let k = p.clone().lerp(y, I / A), B = _.clone().lerp(y, I / A), P = A - I; - for(let w = 0; w <= P; w++)w === 0 && I === A ? L[I][w] = k : L[I][w] = k.clone().lerp(B, w / P); - } - for(let I = 0; I < A; I++)for(let k = 0; k < 2 * (A - I) - 1; k++){ - let B = Math.floor(k / 2); - k % 2 === 0 ? (d(L[I][B + 1]), d(L[I + 1][B]), d(L[I][B])) : (d(L[I][B + 1]), d(L[I + 1][B + 1]), d(L[I + 1][B])); - } - } - function c(p) { - let _ = new M; - for(let y = 0; y < r.length; y += 3)_.x = r[y + 0], _.y = r[y + 1], _.z = r[y + 2], _.normalize().multiplyScalar(p), r[y + 0] = _.x, r[y + 1] = _.y, r[y + 2] = _.z; + getSpacedPoints(e = 5) { + let t = []; + for(let n = 0; n <= e; n++)t.push(this.getPointAt(n / e)); + return t; + } + getLength() { + let e = this.getLengths(); + return e[e.length - 1]; + } + getLengths(e = this.arcLengthDivisions) { + if (this.cacheArcLengths && this.cacheArcLengths.length === e + 1 && !this.needsUpdate) return this.cacheArcLengths; + this.needsUpdate = !1; + let t = [], n, i = this.getPoint(0), r = 0; + t.push(0); + for(let a = 1; a <= e; a++)n = this.getPoint(a / e), r += n.distanceTo(i), t.push(r), i = n; + return this.cacheArcLengths = t, t; + } + updateArcLengths() { + this.needsUpdate = !0, this.getLengths(); + } + getUtoTmapping(e, t) { + let n = this.getLengths(), i = 0, r = n.length, a; + t ? a = t : a = e * n[r - 1]; + let o = 0, c = r - 1, l; + for(; o <= c;)if (i = Math.floor(o + (c - o) / 2), l = n[i] - a, l < 0) o = i + 1; + else if (l > 0) c = i - 1; + else { + c = i; + break; } - function h() { - let p = new M; - for(let _ = 0; _ < r.length; _ += 3){ - p.x = r[_ + 0], p.y = r[_ + 1], p.z = r[_ + 2]; - let y = v(p) / 2 / Math.PI + .5, b = g(p) / Math.PI + .5; - o.push(y, 1 - b); - } - m(), u(); + if (i = c, n[i] === a) return i / (r - 1); + let h = n[i], d = n[i + 1] - h, f = (a - h) / d; + return (i + f) / (r - 1); + } + getTangent(e, t) { + let i = e - 1e-4, r = e + 1e-4; + i < 0 && (i = 0), r > 1 && (r = 1); + let a = this.getPoint(i), o = this.getPoint(r), c = t || (a.isVector2 ? new Z : new A); + return c.copy(o).sub(a).normalize(), c; + } + getTangentAt(e, t) { + let n = this.getUtoTmapping(e); + return this.getTangent(n, t); + } + computeFrenetFrames(e, t) { + let n = new A, i = [], r = [], a = [], o = new A, c = new ze; + for(let f = 0; f <= e; f++){ + let m = f / e; + i[f] = this.getTangentAt(m, new A); } - function u() { - for(let p = 0; p < o.length; p += 6){ - let _ = o[p + 0], y = o[p + 2], b = o[p + 4], A = Math.max(_, y, b), L = Math.min(_, y, b); - A > .9 && L < .1 && (_ < .2 && (o[p + 0] += 1), y < .2 && (o[p + 2] += 1), b < .2 && (o[p + 4] += 1)); + r[0] = new A, a[0] = new A; + let l = Number.MAX_VALUE, h = Math.abs(i[0].x), u = Math.abs(i[0].y), d = Math.abs(i[0].z); + h <= l && (l = h, n.set(1, 0, 0)), u <= l && (l = u, n.set(0, 1, 0)), d <= l && n.set(0, 0, 1), o.crossVectors(i[0], n).normalize(), r[0].crossVectors(i[0], o), a[0].crossVectors(i[0], r[0]); + for(let f = 1; f <= e; f++){ + if (r[f] = r[f - 1].clone(), a[f] = a[f - 1].clone(), o.crossVectors(i[f - 1], i[f]), o.length() > Number.EPSILON) { + o.normalize(); + let m = Math.acos(ct(i[f - 1].dot(i[f]), -1, 1)); + r[f].applyMatrix4(c.makeRotationAxis(o, m)); } + a[f].crossVectors(i[f], r[f]); } - function d(p) { - r.push(p.x, p.y, p.z); - } - function f(p, _) { - let y = p * 3; - _.x = e[y + 0], _.y = e[y + 1], _.z = e[y + 2]; + if (t === !0) { + let f = Math.acos(ct(r[0].dot(r[e]), -1, 1)); + f /= e, i[0].dot(o.crossVectors(r[0], r[e])) > 0 && (f = -f); + for(let m = 1; m <= e; m++)r[m].applyMatrix4(c.makeRotationAxis(i[m], f * m)), a[m].crossVectors(i[m], r[m]); } - function m() { - let p = new M, _ = new M, y = new M, b = new M, A = new X, L = new X, I = new X; - for(let k = 0, B = 0; k < r.length; k += 9, B += 6){ - p.set(r[k + 0], r[k + 1], r[k + 2]), _.set(r[k + 3], r[k + 4], r[k + 5]), y.set(r[k + 6], r[k + 7], r[k + 8]), A.set(o[B + 0], o[B + 1]), L.set(o[B + 2], o[B + 3]), I.set(o[B + 4], o[B + 5]), b.copy(p).add(_).add(y).divideScalar(3); - let P = v(b); - x(A, B + 0, p, P), x(L, B + 2, _, P), x(I, B + 4, y, P); + return { + tangents: i, + normals: r, + binormals: a + }; + } + clone() { + return new this.constructor().copy(this); + } + copy(e) { + return this.arcLengthDivisions = e.arcLengthDivisions, this; + } + toJSON() { + let e = { + metadata: { + version: 4.6, + type: "Curve", + generator: "Curve.toJSON" } + }; + return e.arcLengthDivisions = this.arcLengthDivisions, e.type = this.type, e; + } + fromJSON(e) { + return this.arcLengthDivisions = e.arcLengthDivisions, this; + } +}, Ds = class extends Zt { + constructor(e = 0, t = 0, n = 1, i = 1, r = 0, a = Math.PI * 2, o = !1, c = 0){ + super(), this.isEllipseCurve = !0, this.type = "EllipseCurve", this.aX = e, this.aY = t, this.xRadius = n, this.yRadius = i, this.aStartAngle = r, this.aEndAngle = a, this.aClockwise = o, this.aRotation = c; + } + getPoint(e, t) { + let n = t || new Z, i = Math.PI * 2, r = this.aEndAngle - this.aStartAngle, a = Math.abs(r) < Number.EPSILON; + for(; r < 0;)r += i; + for(; r > i;)r -= i; + r < Number.EPSILON && (a ? r = 0 : r = i), this.aClockwise === !0 && !a && (r === i ? r = -i : r = r - i); + let o = this.aStartAngle + e * r, c = this.aX + this.xRadius * Math.cos(o), l = this.aY + this.yRadius * Math.sin(o); + if (this.aRotation !== 0) { + let h = Math.cos(this.aRotation), u = Math.sin(this.aRotation), d = c - this.aX, f = l - this.aY; + c = d * h - f * u + this.aX, l = d * u + f * h + this.aY; } - function x(p, _, y, b) { - b < 0 && p.x === 1 && (o[_] = p.x - 1), y.x === 0 && y.z === 0 && (o[_] = b / 2 / Math.PI + .5); + return n.set(c, l); + } + copy(e) { + return super.copy(e), this.aX = e.aX, this.aY = e.aY, this.xRadius = e.xRadius, this.yRadius = e.yRadius, this.aStartAngle = e.aStartAngle, this.aEndAngle = e.aEndAngle, this.aClockwise = e.aClockwise, this.aRotation = e.aRotation, this; + } + toJSON() { + let e = super.toJSON(); + return e.aX = this.aX, e.aY = this.aY, e.xRadius = this.xRadius, e.yRadius = this.yRadius, e.aStartAngle = this.aStartAngle, e.aEndAngle = this.aEndAngle, e.aClockwise = this.aClockwise, e.aRotation = this.aRotation, e; + } + fromJSON(e) { + return super.fromJSON(e), this.aX = e.aX, this.aY = e.aY, this.xRadius = e.xRadius, this.yRadius = e.yRadius, this.aStartAngle = e.aStartAngle, this.aEndAngle = e.aEndAngle, this.aClockwise = e.aClockwise, this.aRotation = e.aRotation, this; + } +}, ko = class extends Ds { + constructor(e, t, n, i, r, a){ + super(e, t, n, n, i, r, a), this.isArcCurve = !0, this.type = "ArcCurve"; + } +}; +function Jc() { + let s1 = 0, e = 0, t = 0, n = 0; + function i(r, a, o, c) { + s1 = r, e = o, t = -3 * r + 3 * a - 2 * o - c, n = 2 * r - 2 * a + o + c; + } + return { + initCatmullRom: function(r, a, o, c, l) { + i(a, o, l * (o - r), l * (c - a)); + }, + initNonuniformCatmullRom: function(r, a, o, c, l, h, u) { + let d = (a - r) / l - (o - r) / (l + h) + (o - a) / h, f = (o - a) / h - (c - a) / (h + u) + (c - o) / u; + d *= h, f *= h, i(a, o, d, f); + }, + calc: function(r) { + let a = r * r, o = a * r; + return s1 + e * r + t * a + n * o; } - function v(p) { - return Math.atan2(p.z, -p.x); + }; +} +var xr = new A, io = new Jc, so = new Jc, ro = new Jc, Ho = class extends Zt { + constructor(e = [], t = !1, n = "centripetal", i = .5){ + super(), this.isCatmullRomCurve3 = !0, this.type = "CatmullRomCurve3", this.points = e, this.closed = t, this.curveType = n, this.tension = i; + } + getPoint(e, t = new A) { + let n = t, i = this.points, r = i.length, a = (r - (this.closed ? 0 : 1)) * e, o = Math.floor(a), c = a - o; + this.closed ? o += o > 0 ? 0 : (Math.floor(Math.abs(o) / r) + 1) * r : c === 0 && o === r - 1 && (o = r - 2, c = 1); + let l, h; + this.closed || o > 0 ? l = i[(o - 1) % r] : (xr.subVectors(i[0], i[1]).add(i[0]), l = xr); + let u = i[o % r], d = i[(o + 1) % r]; + if (this.closed || o + 2 < r ? h = i[(o + 2) % r] : (xr.subVectors(i[r - 1], i[r - 2]).add(i[r - 1]), h = xr), this.curveType === "centripetal" || this.curveType === "chordal") { + let f = this.curveType === "chordal" ? .5 : .25, m = Math.pow(l.distanceToSquared(u), f), _ = Math.pow(u.distanceToSquared(d), f), g = Math.pow(d.distanceToSquared(h), f); + _ < 1e-4 && (_ = 1), m < 1e-4 && (m = _), g < 1e-4 && (g = _), io.initNonuniformCatmullRom(l.x, u.x, d.x, h.x, m, _, g), so.initNonuniformCatmullRom(l.y, u.y, d.y, h.y, m, _, g), ro.initNonuniformCatmullRom(l.z, u.z, d.z, h.z, m, _, g); + } else this.curveType === "catmullrom" && (io.initCatmullRom(l.x, u.x, d.x, h.x, this.tension), so.initCatmullRom(l.y, u.y, d.y, h.y, this.tension), ro.initCatmullRom(l.z, u.z, d.z, h.z, this.tension)); + return n.set(io.calc(c), so.calc(c), ro.calc(c)), n; + } + copy(e) { + super.copy(e), this.points = []; + for(let t = 0, n = e.points.length; t < n; t++){ + let i = e.points[t]; + this.points.push(i.clone()); } - function g(p) { - return Math.atan2(-p.y, Math.sqrt(p.x * p.x + p.z * p.z)); + return this.closed = e.closed, this.curveType = e.curveType, this.tension = e.tension, this; + } + toJSON() { + let e = super.toJSON(); + e.points = []; + for(let t = 0, n = this.points.length; t < n; t++){ + let i = this.points[t]; + e.points.push(i.toArray()); } + return e.closed = this.closed, e.curveType = this.curveType, e.tension = this.tension, e; } - static fromJSON(e) { - return new an(e.vertices, e.indices, e.radius, e.details); + fromJSON(e) { + super.fromJSON(e), this.points = []; + for(let t = 0, n = e.points.length; t < n; t++){ + let i = e.points[t]; + this.points.push(new A().fromArray(i)); + } + return this.closed = e.closed, this.curveType = e.curveType, this.tension = e.tension, this; } -}, mr = class extends an { - constructor(e = 1, t = 0){ - let n = (1 + Math.sqrt(5)) / 2, i = 1 / n, r = [ - -1, - -1, - -1, - -1, - -1, - 1, - -1, - 1, - -1, - -1, - 1, - 1, - 1, - -1, - -1, - 1, - -1, - 1, - 1, - 1, - -1, - 1, - 1, - 1, - 0, - -i, - -n, - 0, - -i, - n, - 0, - i, - -n, - 0, - i, - n, - -i, - -n, - 0, - -i, - n, - 0, - i, - -n, - 0, - i, - n, - 0, - -n, - 0, - -i, - n, - 0, - -i, - -n, - 0, - i, - n, - 0, - i - ], o = [ - 3, - 11, - 7, - 3, - 7, - 15, - 3, - 15, - 13, - 7, - 19, - 17, - 7, - 17, - 6, - 7, - 6, - 15, - 17, - 4, - 8, - 17, - 8, - 10, - 17, - 10, - 6, - 8, - 0, - 16, - 8, - 16, - 2, - 8, - 2, - 10, - 0, - 12, - 1, - 0, - 1, - 18, - 0, - 18, - 16, - 6, - 10, - 2, - 6, - 2, - 13, - 6, - 13, - 15, - 2, - 16, - 18, - 2, - 18, - 3, - 2, - 3, - 13, - 18, - 1, - 9, - 18, - 9, - 11, - 18, - 11, - 3, - 4, - 14, - 12, - 4, - 12, - 0, - 4, - 0, - 8, - 11, - 9, - 5, - 11, - 5, - 19, - 11, - 19, - 7, - 19, - 5, - 14, - 19, - 14, - 4, - 19, - 4, - 17, - 1, - 12, - 14, - 1, - 14, - 5, - 1, - 5, - 9 - ]; - super(r, o, e, t); - this.type = "DodecahedronGeometry", this.parameters = { - radius: e, - detail: t - }; - } - static fromJSON(e) { - return new mr(e.radius, e.detail); +}; +function eu(s1, e, t, n, i) { + let r = (n - e) * .5, a = (i - t) * .5, o = s1 * s1, c = s1 * o; + return (2 * t - 2 * n + r + a) * c + (-3 * t + 3 * n - 2 * r - a) * o + r * s1 + t; +} +function Y0(s1, e) { + let t = 1 - s1; + return t * t * e; +} +function Z0(s1, e) { + return 2 * (1 - s1) * s1 * e; +} +function J0(s1, e) { + return s1 * s1 * e; +} +function bs(s1, e, t, n) { + return Y0(s1, e) + Z0(s1, t) + J0(s1, n); +} +function $0(s1, e) { + let t = 1 - s1; + return t * t * t * e; +} +function K0(s1, e) { + let t = 1 - s1; + return 3 * t * t * s1 * e; +} +function Q0(s1, e) { + return 3 * (1 - s1) * s1 * s1 * e; +} +function j0(s1, e) { + return s1 * s1 * s1 * e; +} +function Es(s1, e, t, n, i) { + return $0(s1, e) + K0(s1, t) + Q0(s1, n) + j0(s1, i); +} +var ia = class extends Zt { + constructor(e = new Z, t = new Z, n = new Z, i = new Z){ + super(), this.isCubicBezierCurve = !0, this.type = "CubicBezierCurve", this.v0 = e, this.v1 = t, this.v2 = n, this.v3 = i; } -}, ys = new M, vs = new M, Jo = new M, _s = new nt, _a = class extends _e { - constructor(e = null, t = 1){ - super(); - if (this.type = "EdgesGeometry", this.parameters = { - geometry: e, - thresholdAngle: t - }, e !== null) { - let i = Math.pow(10, 4), r = Math.cos(Wn * t), o = e.getIndex(), a = e.getAttribute("position"), l = o ? o.count : a.count, c = [ - 0, - 0, - 0 - ], h = [ - "a", - "b", - "c" - ], u = new Array(3), d = {}, f = []; - for(let m = 0; m < l; m += 3){ - o ? (c[0] = o.getX(m), c[1] = o.getX(m + 1), c[2] = o.getX(m + 2)) : (c[0] = m, c[1] = m + 1, c[2] = m + 2); - let { a: x , b: v , c: g } = _s; - if (x.fromBufferAttribute(a, c[0]), v.fromBufferAttribute(a, c[1]), g.fromBufferAttribute(a, c[2]), _s.getNormal(Jo), u[0] = `${Math.round(x.x * i)},${Math.round(x.y * i)},${Math.round(x.z * i)}`, u[1] = `${Math.round(v.x * i)},${Math.round(v.y * i)},${Math.round(v.z * i)}`, u[2] = `${Math.round(g.x * i)},${Math.round(g.y * i)},${Math.round(g.z * i)}`, !(u[0] === u[1] || u[1] === u[2] || u[2] === u[0])) for(let p = 0; p < 3; p++){ - let _ = (p + 1) % 3, y = u[p], b = u[_], A = _s[h[p]], L = _s[h[_]], I = `${y}_${b}`, k = `${b}_${y}`; - k in d && d[k] ? (Jo.dot(d[k].normal) <= r && (f.push(A.x, A.y, A.z), f.push(L.x, L.y, L.z)), d[k] = null) : I in d || (d[I] = { - index0: c[p], - index1: c[_], - normal: Jo.clone() - }); - } - } - for(let m in d)if (d[m]) { - let { index0: x , index1: v } = d[m]; - ys.fromBufferAttribute(a, x), vs.fromBufferAttribute(a, v), f.push(ys.x, ys.y, ys.z), f.push(vs.x, vs.y, vs.z); - } - this.setAttribute("position", new de(f, 3)); - } + getPoint(e, t = new Z) { + let n = t, i = this.v0, r = this.v1, a = this.v2, o = this.v3; + return n.set(Es(e, i.x, r.x, a.x, o.x), Es(e, i.y, r.y, a.y, o.y)), n; } -}, Ct = class { - constructor(){ - this.type = "Curve", this.arcLengthDivisions = 200; + copy(e) { + return super.copy(e), this.v0.copy(e.v0), this.v1.copy(e.v1), this.v2.copy(e.v2), this.v3.copy(e.v3), this; } - getPoint() { - return console.warn("THREE.Curve: .getPoint() not implemented."), null; + toJSON() { + let e = super.toJSON(); + return e.v0 = this.v0.toArray(), e.v1 = this.v1.toArray(), e.v2 = this.v2.toArray(), e.v3 = this.v3.toArray(), e; } - getPointAt(e, t) { - let n = this.getUtoTmapping(e); - return this.getPoint(n, t); + fromJSON(e) { + return super.fromJSON(e), this.v0.fromArray(e.v0), this.v1.fromArray(e.v1), this.v2.fromArray(e.v2), this.v3.fromArray(e.v3), this; } - getPoints(e = 5) { - let t = []; - for(let n = 0; n <= e; n++)t.push(this.getPoint(n / e)); - return t; +}, Go = class extends Zt { + constructor(e = new A, t = new A, n = new A, i = new A){ + super(), this.isCubicBezierCurve3 = !0, this.type = "CubicBezierCurve3", this.v0 = e, this.v1 = t, this.v2 = n, this.v3 = i; } - getSpacedPoints(e = 5) { - let t = []; - for(let n = 0; n <= e; n++)t.push(this.getPointAt(n / e)); - return t; + getPoint(e, t = new A) { + let n = t, i = this.v0, r = this.v1, a = this.v2, o = this.v3; + return n.set(Es(e, i.x, r.x, a.x, o.x), Es(e, i.y, r.y, a.y, o.y), Es(e, i.z, r.z, a.z, o.z)), n; } - getLength() { - let e = this.getLengths(); - return e[e.length - 1]; + copy(e) { + return super.copy(e), this.v0.copy(e.v0), this.v1.copy(e.v1), this.v2.copy(e.v2), this.v3.copy(e.v3), this; } - getLengths(e = this.arcLengthDivisions) { - if (this.cacheArcLengths && this.cacheArcLengths.length === e + 1 && !this.needsUpdate) return this.cacheArcLengths; - this.needsUpdate = !1; - let t = [], n, i = this.getPoint(0), r = 0; - t.push(0); - for(let o = 1; o <= e; o++)n = this.getPoint(o / e), r += n.distanceTo(i), t.push(r), i = n; - return this.cacheArcLengths = t, t; + toJSON() { + let e = super.toJSON(); + return e.v0 = this.v0.toArray(), e.v1 = this.v1.toArray(), e.v2 = this.v2.toArray(), e.v3 = this.v3.toArray(), e; } - updateArcLengths() { - this.needsUpdate = !0, this.getLengths(); + fromJSON(e) { + return super.fromJSON(e), this.v0.fromArray(e.v0), this.v1.fromArray(e.v1), this.v2.fromArray(e.v2), this.v3.fromArray(e.v3), this; } - getUtoTmapping(e, t) { - let n = this.getLengths(), i = 0, r = n.length, o; - t ? o = t : o = e * n[r - 1]; - let a = 0, l = r - 1, c; - for(; a <= l;)if (i = Math.floor(a + (l - a) / 2), c = n[i] - o, c < 0) a = i + 1; - else if (c > 0) l = i - 1; - else { - l = i; - break; - } - if (i = l, n[i] === o) return i / (r - 1); - let h = n[i], d = n[i + 1] - h, f = (o - h) / d; - return (i + f) / (r - 1); +}, sa = class extends Zt { + constructor(e = new Z, t = new Z){ + super(), this.isLineCurve = !0, this.type = "LineCurve", this.v1 = e, this.v2 = t; } - getTangent(e, t) { - let i = e - 1e-4, r = e + 1e-4; - i < 0 && (i = 0), r > 1 && (r = 1); - let o = this.getPoint(i), a = this.getPoint(r), l = t || (o.isVector2 ? new X : new M); - return l.copy(a).sub(o).normalize(), l; + getPoint(e, t = new Z) { + let n = t; + return e === 1 ? n.copy(this.v2) : (n.copy(this.v2).sub(this.v1), n.multiplyScalar(e).add(this.v1)), n; } - getTangentAt(e, t) { - let n = this.getUtoTmapping(e); - return this.getTangent(n, t); + getPointAt(e, t) { + return this.getPoint(e, t); } - computeFrenetFrames(e, t) { - let n = new M, i = [], r = [], o = [], a = new M, l = new pe; - for(let f = 0; f <= e; f++){ - let m = f / e; - i[f] = this.getTangentAt(m, new M); - } - r[0] = new M, o[0] = new M; - let c = Number.MAX_VALUE, h = Math.abs(i[0].x), u = Math.abs(i[0].y), d = Math.abs(i[0].z); - h <= c && (c = h, n.set(1, 0, 0)), u <= c && (c = u, n.set(0, 1, 0)), d <= c && n.set(0, 0, 1), a.crossVectors(i[0], n).normalize(), r[0].crossVectors(i[0], a), o[0].crossVectors(i[0], r[0]); - for(let f = 1; f <= e; f++){ - if (r[f] = r[f - 1].clone(), o[f] = o[f - 1].clone(), a.crossVectors(i[f - 1], i[f]), a.length() > Number.EPSILON) { - a.normalize(); - let m = Math.acos(mt(i[f - 1].dot(i[f]), -1, 1)); - r[f].applyMatrix4(l.makeRotationAxis(a, m)); - } - o[f].crossVectors(i[f], r[f]); - } - if (t === !0) { - let f = Math.acos(mt(r[0].dot(r[e]), -1, 1)); - f /= e, i[0].dot(a.crossVectors(r[0], r[e])) > 0 && (f = -f); - for(let m = 1; m <= e; m++)r[m].applyMatrix4(l.makeRotationAxis(i[m], f * m)), o[m].crossVectors(i[m], r[m]); - } - return { - tangents: i, - normals: r, - binormals: o - }; + getTangent(e, t = new Z) { + return t.subVectors(this.v2, this.v1).normalize(); } - clone() { - return new this.constructor().copy(this); + getTangentAt(e, t) { + return this.getTangent(e, t); } copy(e) { - return this.arcLengthDivisions = e.arcLengthDivisions, this; - } - toJSON() { - let e = { - metadata: { - version: 4.5, - type: "Curve", - generator: "Curve.toJSON" - } - }; - return e.arcLengthDivisions = this.arcLengthDivisions, e.type = this.type, e; - } - fromJSON(e) { - return this.arcLengthDivisions = e.arcLengthDivisions, this; - } -}, Ur = class extends Ct { - constructor(e = 0, t = 0, n = 1, i = 1, r = 0, o = Math.PI * 2, a = !1, l = 0){ - super(); - this.type = "EllipseCurve", this.aX = e, this.aY = t, this.xRadius = n, this.yRadius = i, this.aStartAngle = r, this.aEndAngle = o, this.aClockwise = a, this.aRotation = l; - } - getPoint(e, t) { - let n = t || new X, i = Math.PI * 2, r = this.aEndAngle - this.aStartAngle, o = Math.abs(r) < Number.EPSILON; - for(; r < 0;)r += i; - for(; r > i;)r -= i; - r < Number.EPSILON && (o ? r = 0 : r = i), this.aClockwise === !0 && !o && (r === i ? r = -i : r = r - i); - let a = this.aStartAngle + e * r, l = this.aX + this.xRadius * Math.cos(a), c = this.aY + this.yRadius * Math.sin(a); - if (this.aRotation !== 0) { - let h = Math.cos(this.aRotation), u = Math.sin(this.aRotation), d = l - this.aX, f = c - this.aY; - l = d * h - f * u + this.aX, c = d * u + f * h + this.aY; - } - return n.set(l, c); - } - copy(e) { - return super.copy(e), this.aX = e.aX, this.aY = e.aY, this.xRadius = e.xRadius, this.yRadius = e.yRadius, this.aStartAngle = e.aStartAngle, this.aEndAngle = e.aEndAngle, this.aClockwise = e.aClockwise, this.aRotation = e.aRotation, this; - } - toJSON() { - let e = super.toJSON(); - return e.aX = this.aX, e.aY = this.aY, e.xRadius = this.xRadius, e.yRadius = this.yRadius, e.aStartAngle = this.aStartAngle, e.aEndAngle = this.aEndAngle, e.aClockwise = this.aClockwise, e.aRotation = this.aRotation, e; - } - fromJSON(e) { - return super.fromJSON(e), this.aX = e.aX, this.aY = e.aY, this.xRadius = e.xRadius, this.yRadius = e.yRadius, this.aStartAngle = e.aStartAngle, this.aEndAngle = e.aEndAngle, this.aClockwise = e.aClockwise, this.aRotation = e.aRotation, this; - } -}; -Ur.prototype.isEllipseCurve = !0; -var Ma = class extends Ur { - constructor(e, t, n, i, r, o){ - super(e, t, n, n, i, r, o); - this.type = "ArcCurve"; - } -}; -Ma.prototype.isArcCurve = !0; -function ba() { - let s = 0, e = 0, t = 0, n = 0; - function i(r, o, a, l) { - s = r, e = a, t = -3 * r + 3 * o - 2 * a - l, n = 2 * r - 2 * o + a + l; - } - return { - initCatmullRom: function(r, o, a, l, c) { - i(o, a, c * (a - r), c * (l - o)); - }, - initNonuniformCatmullRom: function(r, o, a, l, c, h, u) { - let d = (o - r) / c - (a - r) / (c + h) + (a - o) / h, f = (a - o) / h - (l - o) / (h + u) + (l - a) / u; - d *= h, f *= h, i(o, a, d, f); - }, - calc: function(r) { - let o = r * r, a = o * r; - return s + e * r + t * o + n * a; - } - }; -} -var Ms = new M, Yo = new ba, Zo = new ba, $o = new ba, wa = class extends Ct { - constructor(e = [], t = !1, n = "centripetal", i = .5){ - super(); - this.type = "CatmullRomCurve3", this.points = e, this.closed = t, this.curveType = n, this.tension = i; - } - getPoint(e, t = new M) { - let n = t, i = this.points, r = i.length, o = (r - (this.closed ? 0 : 1)) * e, a = Math.floor(o), l = o - a; - this.closed ? a += a > 0 ? 0 : (Math.floor(Math.abs(a) / r) + 1) * r : l === 0 && a === r - 1 && (a = r - 2, l = 1); - let c, h; - this.closed || a > 0 ? c = i[(a - 1) % r] : (Ms.subVectors(i[0], i[1]).add(i[0]), c = Ms); - let u = i[a % r], d = i[(a + 1) % r]; - if (this.closed || a + 2 < r ? h = i[(a + 2) % r] : (Ms.subVectors(i[r - 1], i[r - 2]).add(i[r - 1]), h = Ms), this.curveType === "centripetal" || this.curveType === "chordal") { - let f = this.curveType === "chordal" ? .5 : .25, m = Math.pow(c.distanceToSquared(u), f), x = Math.pow(u.distanceToSquared(d), f), v = Math.pow(d.distanceToSquared(h), f); - x < 1e-4 && (x = 1), m < 1e-4 && (m = x), v < 1e-4 && (v = x), Yo.initNonuniformCatmullRom(c.x, u.x, d.x, h.x, m, x, v), Zo.initNonuniformCatmullRom(c.y, u.y, d.y, h.y, m, x, v), $o.initNonuniformCatmullRom(c.z, u.z, d.z, h.z, m, x, v); - } else this.curveType === "catmullrom" && (Yo.initCatmullRom(c.x, u.x, d.x, h.x, this.tension), Zo.initCatmullRom(c.y, u.y, d.y, h.y, this.tension), $o.initCatmullRom(c.z, u.z, d.z, h.z, this.tension)); - return n.set(Yo.calc(l), Zo.calc(l), $o.calc(l)), n; - } - copy(e) { - super.copy(e), this.points = []; - for(let t = 0, n = e.points.length; t < n; t++){ - let i = e.points[t]; - this.points.push(i.clone()); - } - return this.closed = e.closed, this.curveType = e.curveType, this.tension = e.tension, this; - } - toJSON() { - let e = super.toJSON(); - e.points = []; - for(let t = 0, n = this.points.length; t < n; t++){ - let i = this.points[t]; - e.points.push(i.toArray()); - } - return e.closed = this.closed, e.curveType = this.curveType, e.tension = this.tension, e; - } - fromJSON(e) { - super.fromJSON(e), this.points = []; - for(let t = 0, n = e.points.length; t < n; t++){ - let i = e.points[t]; - this.points.push(new M().fromArray(i)); - } - return this.closed = e.closed, this.curveType = e.curveType, this.tension = e.tension, this; - } -}; -wa.prototype.isCatmullRomCurve3 = !0; -function pc(s, e, t, n, i) { - let r = (n - e) * .5, o = (i - t) * .5, a = s * s, l = s * a; - return (2 * t - 2 * n + r + o) * l + (-3 * t + 3 * n - 2 * r - o) * a + r * s + t; -} -function Ix(s, e) { - let t = 1 - s; - return t * t * e; -} -function Dx(s, e) { - return 2 * (1 - s) * s * e; -} -function Fx(s, e) { - return s * s * e; -} -function ar(s, e, t, n) { - return Ix(s, e) + Dx(s, t) + Fx(s, n); -} -function Nx(s, e) { - let t = 1 - s; - return t * t * t * e; -} -function Bx(s, e) { - let t = 1 - s; - return 3 * t * t * s * e; -} -function zx(s, e) { - return 3 * (1 - s) * s * s * e; -} -function Ux(s, e) { - return s * s * s * e; -} -function lr(s, e, t, n, i) { - return Nx(s, e) + Bx(s, t) + zx(s, n) + Ux(s, i); -} -var lo = class extends Ct { - constructor(e = new X, t = new X, n = new X, i = new X){ - super(); - this.type = "CubicBezierCurve", this.v0 = e, this.v1 = t, this.v2 = n, this.v3 = i; - } - getPoint(e, t = new X) { - let n = t, i = this.v0, r = this.v1, o = this.v2, a = this.v3; - return n.set(lr(e, i.x, r.x, o.x, a.x), lr(e, i.y, r.y, o.y, a.y)), n; - } - copy(e) { - return super.copy(e), this.v0.copy(e.v0), this.v1.copy(e.v1), this.v2.copy(e.v2), this.v3.copy(e.v3), this; - } - toJSON() { - let e = super.toJSON(); - return e.v0 = this.v0.toArray(), e.v1 = this.v1.toArray(), e.v2 = this.v2.toArray(), e.v3 = this.v3.toArray(), e; - } - fromJSON(e) { - return super.fromJSON(e), this.v0.fromArray(e.v0), this.v1.fromArray(e.v1), this.v2.fromArray(e.v2), this.v3.fromArray(e.v3), this; - } -}; -lo.prototype.isCubicBezierCurve = !0; -var Sa = class extends Ct { - constructor(e = new M, t = new M, n = new M, i = new M){ - super(); - this.type = "CubicBezierCurve3", this.v0 = e, this.v1 = t, this.v2 = n, this.v3 = i; - } - getPoint(e, t = new M) { - let n = t, i = this.v0, r = this.v1, o = this.v2, a = this.v3; - return n.set(lr(e, i.x, r.x, o.x, a.x), lr(e, i.y, r.y, o.y, a.y), lr(e, i.z, r.z, o.z, a.z)), n; - } - copy(e) { - return super.copy(e), this.v0.copy(e.v0), this.v1.copy(e.v1), this.v2.copy(e.v2), this.v3.copy(e.v3), this; - } - toJSON() { - let e = super.toJSON(); - return e.v0 = this.v0.toArray(), e.v1 = this.v1.toArray(), e.v2 = this.v2.toArray(), e.v3 = this.v3.toArray(), e; - } - fromJSON(e) { - return super.fromJSON(e), this.v0.fromArray(e.v0), this.v1.fromArray(e.v1), this.v2.fromArray(e.v2), this.v3.fromArray(e.v3), this; - } -}; -Sa.prototype.isCubicBezierCurve3 = !0; -var Or = class extends Ct { - constructor(e = new X, t = new X){ - super(); - this.type = "LineCurve", this.v1 = e, this.v2 = t; - } - getPoint(e, t = new X) { - let n = t; - return e === 1 ? n.copy(this.v2) : (n.copy(this.v2).sub(this.v1), n.multiplyScalar(e).add(this.v1)), n; - } - getPointAt(e, t) { - return this.getPoint(e, t); - } - getTangent(e, t) { - let n = t || new X; - return n.copy(this.v2).sub(this.v1).normalize(), n; - } - copy(e) { - return super.copy(e), this.v1.copy(e.v1), this.v2.copy(e.v2), this; + return super.copy(e), this.v1.copy(e.v1), this.v2.copy(e.v2), this; } toJSON() { let e = super.toJSON(); @@ -13048,20 +14282,23 @@ var Or = class extends Ct { fromJSON(e) { return super.fromJSON(e), this.v1.fromArray(e.v1), this.v2.fromArray(e.v2), this; } -}; -Or.prototype.isLineCurve = !0; -var Eh = class extends Ct { - constructor(e = new M, t = new M){ - super(); - this.type = "LineCurve3", this.isLineCurve3 = !0, this.v1 = e, this.v2 = t; +}, Wo = class extends Zt { + constructor(e = new A, t = new A){ + super(), this.isLineCurve3 = !0, this.type = "LineCurve3", this.v1 = e, this.v2 = t; } - getPoint(e, t = new M) { + getPoint(e, t = new A) { let n = t; return e === 1 ? n.copy(this.v2) : (n.copy(this.v2).sub(this.v1), n.multiplyScalar(e).add(this.v1)), n; } getPointAt(e, t) { return this.getPoint(e, t); } + getTangent(e, t = new A) { + return t.subVectors(this.v2, this.v1).normalize(); + } + getTangentAt(e, t) { + return this.getTangent(e, t); + } copy(e) { return super.copy(e), this.v1.copy(e.v1), this.v2.copy(e.v2), this; } @@ -13072,14 +14309,13 @@ var Eh = class extends Ct { fromJSON(e) { return super.fromJSON(e), this.v1.fromArray(e.v1), this.v2.fromArray(e.v2), this; } -}, co = class extends Ct { - constructor(e = new X, t = new X, n = new X){ - super(); - this.type = "QuadraticBezierCurve", this.v0 = e, this.v1 = t, this.v2 = n; +}, ra = class extends Zt { + constructor(e = new Z, t = new Z, n = new Z){ + super(), this.isQuadraticBezierCurve = !0, this.type = "QuadraticBezierCurve", this.v0 = e, this.v1 = t, this.v2 = n; } - getPoint(e, t = new X) { - let n = t, i = this.v0, r = this.v1, o = this.v2; - return n.set(ar(e, i.x, r.x, o.x), ar(e, i.y, r.y, o.y)), n; + getPoint(e, t = new Z) { + let n = t, i = this.v0, r = this.v1, a = this.v2; + return n.set(bs(e, i.x, r.x, a.x), bs(e, i.y, r.y, a.y)), n; } copy(e) { return super.copy(e), this.v0.copy(e.v0), this.v1.copy(e.v1), this.v2.copy(e.v2), this; @@ -13091,16 +14327,13 @@ var Eh = class extends Ct { fromJSON(e) { return super.fromJSON(e), this.v0.fromArray(e.v0), this.v1.fromArray(e.v1), this.v2.fromArray(e.v2), this; } -}; -co.prototype.isQuadraticBezierCurve = !0; -var ho = class extends Ct { - constructor(e = new M, t = new M, n = new M){ - super(); - this.type = "QuadraticBezierCurve3", this.v0 = e, this.v1 = t, this.v2 = n; +}, aa = class extends Zt { + constructor(e = new A, t = new A, n = new A){ + super(), this.isQuadraticBezierCurve3 = !0, this.type = "QuadraticBezierCurve3", this.v0 = e, this.v1 = t, this.v2 = n; } - getPoint(e, t = new M) { - let n = t, i = this.v0, r = this.v1, o = this.v2; - return n.set(ar(e, i.x, r.x, o.x), ar(e, i.y, r.y, o.y), ar(e, i.z, r.z, o.z)), n; + getPoint(e, t = new A) { + let n = t, i = this.v0, r = this.v1, a = this.v2; + return n.set(bs(e, i.x, r.x, a.x), bs(e, i.y, r.y, a.y), bs(e, i.z, r.z, a.z)), n; } copy(e) { return super.copy(e), this.v0.copy(e.v0), this.v1.copy(e.v1), this.v2.copy(e.v2), this; @@ -13112,16 +14345,13 @@ var ho = class extends Ct { fromJSON(e) { return super.fromJSON(e), this.v0.fromArray(e.v0), this.v1.fromArray(e.v1), this.v2.fromArray(e.v2), this; } -}; -ho.prototype.isQuadraticBezierCurve3 = !0; -var uo = class extends Ct { +}, oa = class extends Zt { constructor(e = []){ - super(); - this.type = "SplineCurve", this.points = e; + super(), this.isSplineCurve = !0, this.type = "SplineCurve", this.points = e; } - getPoint(e, t = new X) { - let n = t, i = this.points, r = (i.length - 1) * e, o = Math.floor(r), a = r - o, l = i[o === 0 ? o : o - 1], c = i[o], h = i[o > i.length - 2 ? i.length - 1 : o + 1], u = i[o > i.length - 3 ? i.length - 1 : o + 2]; - return n.set(pc(a, l.x, c.x, h.x, u.x), pc(a, l.y, c.y, h.y, u.y)), n; + getPoint(e, t = new Z) { + let n = t, i = this.points, r = (i.length - 1) * e, a = Math.floor(r), o = r - a, c = i[a === 0 ? a : a - 1], l = i[a], h = i[a > i.length - 2 ? i.length - 1 : a + 1], u = i[a > i.length - 3 ? i.length - 1 : a + 2]; + return n.set(eu(o, c.x, l.x, h.x, u.x), eu(o, c.y, l.y, h.y, u.y)), n; } copy(e) { super.copy(e), this.points = []; @@ -13144,42 +14374,43 @@ var uo = class extends Ct { super.fromJSON(e), this.points = []; for(let t = 0, n = e.points.length; t < n; t++){ let i = e.points[t]; - this.points.push(new X().fromArray(i)); + this.points.push(new Z().fromArray(i)); } return this; } -}; -uo.prototype.isSplineCurve = !0; -var Ta = Object.freeze({ +}, ca = Object.freeze({ __proto__: null, - ArcCurve: Ma, - CatmullRomCurve3: wa, - CubicBezierCurve: lo, - CubicBezierCurve3: Sa, - EllipseCurve: Ur, - LineCurve: Or, - LineCurve3: Eh, - QuadraticBezierCurve: co, - QuadraticBezierCurve3: ho, - SplineCurve: uo -}), Ah = class extends Ct { + ArcCurve: ko, + CatmullRomCurve3: Ho, + CubicBezierCurve: ia, + CubicBezierCurve3: Go, + EllipseCurve: Ds, + LineCurve: sa, + LineCurve3: Wo, + QuadraticBezierCurve: ra, + QuadraticBezierCurve3: aa, + SplineCurve: oa +}), Xo = class extends Zt { constructor(){ - super(); - this.type = "CurvePath", this.curves = [], this.autoClose = !1; + super(), this.type = "CurvePath", this.curves = [], this.autoClose = !1; } add(e) { this.curves.push(e); } closePath() { let e = this.curves[0].getPoint(0), t = this.curves[this.curves.length - 1].getPoint(1); - e.equals(t) || this.curves.push(new Or(t, e)); + if (!e.equals(t)) { + let n = e.isVector2 === !0 ? "LineCurve" : "LineCurve3"; + this.curves.push(new ca[n](t, e)); + } + return this; } getPoint(e, t) { let n = e * this.getLength(), i = this.getCurveLengths(), r = 0; for(; r < i.length;){ if (i[r] >= n) { - let o = i[r] - n, a = this.curves[r], l = a.getLength(), c = l === 0 ? 0 : 1 - o / l; - return a.getPointAt(c, t); + let a = i[r] - n, o = this.curves[r], c = o.getLength(), l = c === 0 ? 0 : 1 - a / c; + return o.getPointAt(l, t); } r++; } @@ -13206,9 +14437,9 @@ var Ta = Object.freeze({ getPoints(e = 12) { let t = [], n; for(let i = 0, r = this.curves; i < r.length; i++){ - let o = r[i], a = o && o.isEllipseCurve ? e * 2 : o && (o.isLineCurve || o.isLineCurve3) ? 1 : o && o.isSplineCurve ? e * o.points.length : e, l = o.getPoints(a); - for(let c = 0; c < l.length; c++){ - let h = l[c]; + let a = r[i], o = a.isEllipseCurve ? e * 2 : a.isLineCurve || a.isLineCurve3 ? 1 : a.isSplineCurve ? e * a.points.length : e, c = a.getPoints(o); + for(let l = 0; l < c.length; l++){ + let h = c[l]; n && n.equals(h) || (t.push(h), n = h); } } @@ -13235,14 +14466,13 @@ var Ta = Object.freeze({ super.fromJSON(e), this.autoClose = e.autoClose, this.curves = []; for(let t = 0, n = e.curves.length; t < n; t++){ let i = e.curves[t]; - this.curves.push(new Ta[i.type]().fromJSON(i)); + this.curves.push(new ca[i.type]().fromJSON(i)); } return this; } -}, gr = class extends Ah { +}, ji = class extends Xo { constructor(e){ - super(); - this.type = "Path", this.currentPoint = new X, e && this.setFromPoints(e); + super(), this.type = "Path", this.currentPoint = new Z, e && this.setFromPoints(e); } setFromPoints(e) { this.moveTo(e[0].x, e[0].y); @@ -13253,58 +14483,498 @@ var Ta = Object.freeze({ return this.currentPoint.set(e, t), this; } lineTo(e, t) { - let n = new Or(this.currentPoint.clone(), new X(e, t)); + let n = new sa(this.currentPoint.clone(), new Z(e, t)); return this.curves.push(n), this.currentPoint.set(e, t), this; } quadraticCurveTo(e, t, n, i) { - let r = new co(this.currentPoint.clone(), new X(e, t), new X(n, i)); + let r = new ra(this.currentPoint.clone(), new Z(e, t), new Z(n, i)); return this.curves.push(r), this.currentPoint.set(n, i), this; } - bezierCurveTo(e, t, n, i, r, o) { - let a = new lo(this.currentPoint.clone(), new X(e, t), new X(n, i), new X(r, o)); - return this.curves.push(a), this.currentPoint.set(r, o), this; + bezierCurveTo(e, t, n, i, r, a) { + let o = new ia(this.currentPoint.clone(), new Z(e, t), new Z(n, i), new Z(r, a)); + return this.curves.push(o), this.currentPoint.set(r, a), this; } splineThru(e) { let t = [ this.currentPoint.clone() - ].concat(e), n = new uo(t); + ].concat(e), n = new oa(t); return this.curves.push(n), this.currentPoint.copy(e[e.length - 1]), this; } - arc(e, t, n, i, r, o) { - let a = this.currentPoint.x, l = this.currentPoint.y; - return this.absarc(e + a, t + l, n, i, r, o), this; + arc(e, t, n, i, r, a) { + let o = this.currentPoint.x, c = this.currentPoint.y; + return this.absarc(e + o, t + c, n, i, r, a), this; } - absarc(e, t, n, i, r, o) { - return this.absellipse(e, t, n, n, i, r, o), this; + absarc(e, t, n, i, r, a) { + return this.absellipse(e, t, n, n, i, r, a), this; } - ellipse(e, t, n, i, r, o, a, l) { - let c = this.currentPoint.x, h = this.currentPoint.y; - return this.absellipse(e + c, t + h, n, i, r, o, a, l), this; + ellipse(e, t, n, i, r, a, o, c) { + let l = this.currentPoint.x, h = this.currentPoint.y; + return this.absellipse(e + l, t + h, n, i, r, a, o, c), this; } - absellipse(e, t, n, i, r, o, a, l) { - let c = new Ur(e, t, n, i, r, o, a, l); + absellipse(e, t, n, i, r, a, o, c) { + let l = new Ds(e, t, n, i, r, a, o, c); if (this.curves.length > 0) { - let u = c.getPoint(0); + let u = l.getPoint(0); u.equals(this.currentPoint) || this.lineTo(u.x, u.y); } - this.curves.push(c); - let h = c.getPoint(1); - return this.currentPoint.copy(h), this; + this.curves.push(l); + let h = l.getPoint(1); + return this.currentPoint.copy(h), this; + } + copy(e) { + return super.copy(e), this.currentPoint.copy(e.currentPoint), this; + } + toJSON() { + let e = super.toJSON(); + return e.currentPoint = this.currentPoint.toArray(), e; + } + fromJSON(e) { + return super.fromJSON(e), this.currentPoint.fromArray(e.currentPoint), this; + } +}, la = class s1 extends Ge { + constructor(e = [ + new Z(0, -.5), + new Z(.5, 0), + new Z(0, .5) + ], t = 12, n = 0, i = Math.PI * 2){ + super(), this.type = "LatheGeometry", this.parameters = { + points: e, + segments: t, + phiStart: n, + phiLength: i + }, t = Math.floor(t), i = ct(i, 0, Math.PI * 2); + let r = [], a = [], o = [], c = [], l = [], h = 1 / t, u = new A, d = new Z, f = new A, m = new A, _ = new A, g = 0, p = 0; + for(let v = 0; v <= e.length - 1; v++)switch(v){ + case 0: + g = e[v + 1].x - e[v].x, p = e[v + 1].y - e[v].y, f.x = p * 1, f.y = -g, f.z = p * 0, _.copy(f), f.normalize(), c.push(f.x, f.y, f.z); + break; + case e.length - 1: + c.push(_.x, _.y, _.z); + break; + default: + g = e[v + 1].x - e[v].x, p = e[v + 1].y - e[v].y, f.x = p * 1, f.y = -g, f.z = p * 0, m.copy(f), f.x += _.x, f.y += _.y, f.z += _.z, f.normalize(), c.push(f.x, f.y, f.z), _.copy(m); + } + for(let v = 0; v <= t; v++){ + let x = n + v * h * i, y = Math.sin(x), b = Math.cos(x); + for(let w = 0; w <= e.length - 1; w++){ + u.x = e[w].x * y, u.y = e[w].y, u.z = e[w].x * b, a.push(u.x, u.y, u.z), d.x = v / t, d.y = w / (e.length - 1), o.push(d.x, d.y); + let R = c[3 * w + 0] * y, I = c[3 * w + 1], M = c[3 * w + 0] * b; + l.push(R, I, M); + } + } + for(let v = 0; v < t; v++)for(let x = 0; x < e.length - 1; x++){ + let y = x + v * e.length, b = y, w = y + e.length, R = y + e.length + 1, I = y + 1; + r.push(b, w, I), r.push(R, I, w); + } + this.setIndex(r), this.setAttribute("position", new ve(a, 3)), this.setAttribute("uv", new ve(o, 2)), this.setAttribute("normal", new ve(l, 3)); + } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; + } + static fromJSON(e) { + return new s1(e.points, e.segments, e.phiStart, e.phiLength); + } +}, qo = class s1 extends la { + constructor(e = 1, t = 1, n = 4, i = 8){ + let r = new ji; + r.absarc(0, -t / 2, e, Math.PI * 1.5, 0), r.absarc(0, t / 2, e, 0, Math.PI * .5), super(r.getPoints(n), i), this.type = "CapsuleGeometry", this.parameters = { + radius: e, + length: t, + capSegments: n, + radialSegments: i + }; + } + static fromJSON(e) { + return new s1(e.radius, e.length, e.capSegments, e.radialSegments); + } +}, Yo = class s1 extends Ge { + constructor(e = 1, t = 32, n = 0, i = Math.PI * 2){ + super(), this.type = "CircleGeometry", this.parameters = { + radius: e, + segments: t, + thetaStart: n, + thetaLength: i + }, t = Math.max(3, t); + let r = [], a = [], o = [], c = [], l = new A, h = new Z; + a.push(0, 0, 0), o.push(0, 0, 1), c.push(.5, .5); + for(let u = 0, d = 3; u <= t; u++, d += 3){ + let f = n + u / t * i; + l.x = e * Math.cos(f), l.y = e * Math.sin(f), a.push(l.x, l.y, l.z), o.push(0, 0, 1), h.x = (a[d] / e + 1) / 2, h.y = (a[d + 1] / e + 1) / 2, c.push(h.x, h.y); + } + for(let u = 1; u <= t; u++)r.push(u, u + 1, 0); + this.setIndex(r), this.setAttribute("position", new ve(a, 3)), this.setAttribute("normal", new ve(o, 3)), this.setAttribute("uv", new ve(c, 2)); + } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; + } + static fromJSON(e) { + return new s1(e.radius, e.segments, e.thetaStart, e.thetaLength); + } +}, Ns = class s1 extends Ge { + constructor(e = 1, t = 1, n = 1, i = 32, r = 1, a = !1, o = 0, c = Math.PI * 2){ + super(), this.type = "CylinderGeometry", this.parameters = { + radiusTop: e, + radiusBottom: t, + height: n, + radialSegments: i, + heightSegments: r, + openEnded: a, + thetaStart: o, + thetaLength: c + }; + let l = this; + i = Math.floor(i), r = Math.floor(r); + let h = [], u = [], d = [], f = [], m = 0, _ = [], g = n / 2, p = 0; + v(), a === !1 && (e > 0 && x(!0), t > 0 && x(!1)), this.setIndex(h), this.setAttribute("position", new ve(u, 3)), this.setAttribute("normal", new ve(d, 3)), this.setAttribute("uv", new ve(f, 2)); + function v() { + let y = new A, b = new A, w = 0, R = (t - e) / n; + for(let I = 0; I <= r; I++){ + let M = [], T = I / r, O = T * (t - e) + e; + for(let Y = 0; Y <= i; Y++){ + let $ = Y / i, U = $ * c + o, z = Math.sin(U), q = Math.cos(U); + b.x = O * z, b.y = -T * n + g, b.z = O * q, u.push(b.x, b.y, b.z), y.set(z, R, q).normalize(), d.push(y.x, y.y, y.z), f.push($, 1 - T), M.push(m++); + } + _.push(M); + } + for(let I = 0; I < i; I++)for(let M = 0; M < r; M++){ + let T = _[M][I], O = _[M + 1][I], Y = _[M + 1][I + 1], $ = _[M][I + 1]; + h.push(T, O, $), h.push(O, Y, $), w += 6; + } + l.addGroup(p, w, 0), p += w; + } + function x(y) { + let b = m, w = new Z, R = new A, I = 0, M = y === !0 ? e : t, T = y === !0 ? 1 : -1; + for(let Y = 1; Y <= i; Y++)u.push(0, g * T, 0), d.push(0, T, 0), f.push(.5, .5), m++; + let O = m; + for(let Y = 0; Y <= i; Y++){ + let U = Y / i * c + o, z = Math.cos(U), q = Math.sin(U); + R.x = M * q, R.y = g * T, R.z = M * z, u.push(R.x, R.y, R.z), d.push(0, T, 0), w.x = z * .5 + .5, w.y = q * .5 * T + .5, f.push(w.x, w.y), m++; + } + for(let Y = 0; Y < i; Y++){ + let $ = b + Y, U = O + Y; + y === !0 ? h.push(U, U + 1, $) : h.push(U + 1, U, $), I += 3; + } + l.addGroup(p, I, y === !0 ? 1 : 2), p += I; + } + } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; + } + static fromJSON(e) { + return new s1(e.radiusTop, e.radiusBottom, e.height, e.radialSegments, e.heightSegments, e.openEnded, e.thetaStart, e.thetaLength); + } +}, Zo = class s1 extends Ns { + constructor(e = 1, t = 1, n = 32, i = 1, r = !1, a = 0, o = Math.PI * 2){ + super(0, e, t, n, i, r, a, o), this.type = "ConeGeometry", this.parameters = { + radius: e, + height: t, + radialSegments: n, + heightSegments: i, + openEnded: r, + thetaStart: a, + thetaLength: o + }; + } + static fromJSON(e) { + return new s1(e.radius, e.height, e.radialSegments, e.heightSegments, e.openEnded, e.thetaStart, e.thetaLength); + } +}, di = class s1 extends Ge { + constructor(e = [], t = [], n = 1, i = 0){ + super(), this.type = "PolyhedronGeometry", this.parameters = { + vertices: e, + indices: t, + radius: n, + detail: i + }; + let r = [], a = []; + o(i), l(n), h(), this.setAttribute("position", new ve(r, 3)), this.setAttribute("normal", new ve(r.slice(), 3)), this.setAttribute("uv", new ve(a, 2)), i === 0 ? this.computeVertexNormals() : this.normalizeNormals(); + function o(v) { + let x = new A, y = new A, b = new A; + for(let w = 0; w < t.length; w += 3)f(t[w + 0], x), f(t[w + 1], y), f(t[w + 2], b), c(x, y, b, v); + } + function c(v, x, y, b) { + let w = b + 1, R = []; + for(let I = 0; I <= w; I++){ + R[I] = []; + let M = v.clone().lerp(y, I / w), T = x.clone().lerp(y, I / w), O = w - I; + for(let Y = 0; Y <= O; Y++)Y === 0 && I === w ? R[I][Y] = M : R[I][Y] = M.clone().lerp(T, Y / O); + } + for(let I = 0; I < w; I++)for(let M = 0; M < 2 * (w - I) - 1; M++){ + let T = Math.floor(M / 2); + M % 2 === 0 ? (d(R[I][T + 1]), d(R[I + 1][T]), d(R[I][T])) : (d(R[I][T + 1]), d(R[I + 1][T + 1]), d(R[I + 1][T])); + } + } + function l(v) { + let x = new A; + for(let y = 0; y < r.length; y += 3)x.x = r[y + 0], x.y = r[y + 1], x.z = r[y + 2], x.normalize().multiplyScalar(v), r[y + 0] = x.x, r[y + 1] = x.y, r[y + 2] = x.z; + } + function h() { + let v = new A; + for(let x = 0; x < r.length; x += 3){ + v.x = r[x + 0], v.y = r[x + 1], v.z = r[x + 2]; + let y = g(v) / 2 / Math.PI + .5, b = p(v) / Math.PI + .5; + a.push(y, 1 - b); + } + m(), u(); + } + function u() { + for(let v = 0; v < a.length; v += 6){ + let x = a[v + 0], y = a[v + 2], b = a[v + 4], w = Math.max(x, y, b), R = Math.min(x, y, b); + w > .9 && R < .1 && (x < .2 && (a[v + 0] += 1), y < .2 && (a[v + 2] += 1), b < .2 && (a[v + 4] += 1)); + } + } + function d(v) { + r.push(v.x, v.y, v.z); + } + function f(v, x) { + let y = v * 3; + x.x = e[y + 0], x.y = e[y + 1], x.z = e[y + 2]; + } + function m() { + let v = new A, x = new A, y = new A, b = new A, w = new Z, R = new Z, I = new Z; + for(let M = 0, T = 0; M < r.length; M += 9, T += 6){ + v.set(r[M + 0], r[M + 1], r[M + 2]), x.set(r[M + 3], r[M + 4], r[M + 5]), y.set(r[M + 6], r[M + 7], r[M + 8]), w.set(a[T + 0], a[T + 1]), R.set(a[T + 2], a[T + 3]), I.set(a[T + 4], a[T + 5]), b.copy(v).add(x).add(y).divideScalar(3); + let O = g(b); + _(w, T + 0, v, O), _(R, T + 2, x, O), _(I, T + 4, y, O); + } + } + function _(v, x, y, b) { + b < 0 && v.x === 1 && (a[x] = v.x - 1), y.x === 0 && y.z === 0 && (a[x] = b / 2 / Math.PI + .5); + } + function g(v) { + return Math.atan2(v.z, -v.x); + } + function p(v) { + return Math.atan2(-v.y, Math.sqrt(v.x * v.x + v.z * v.z)); + } + } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; + } + static fromJSON(e) { + return new s1(e.vertices, e.indices, e.radius, e.details); + } +}, Jo = class s1 extends di { + constructor(e = 1, t = 0){ + let n = (1 + Math.sqrt(5)) / 2, i = 1 / n, r = [ + -1, + -1, + -1, + -1, + -1, + 1, + -1, + 1, + -1, + -1, + 1, + 1, + 1, + -1, + -1, + 1, + -1, + 1, + 1, + 1, + -1, + 1, + 1, + 1, + 0, + -i, + -n, + 0, + -i, + n, + 0, + i, + -n, + 0, + i, + n, + -i, + -n, + 0, + -i, + n, + 0, + i, + -n, + 0, + i, + n, + 0, + -n, + 0, + -i, + n, + 0, + -i, + -n, + 0, + i, + n, + 0, + i + ], a = [ + 3, + 11, + 7, + 3, + 7, + 15, + 3, + 15, + 13, + 7, + 19, + 17, + 7, + 17, + 6, + 7, + 6, + 15, + 17, + 4, + 8, + 17, + 8, + 10, + 17, + 10, + 6, + 8, + 0, + 16, + 8, + 16, + 2, + 8, + 2, + 10, + 0, + 12, + 1, + 0, + 1, + 18, + 0, + 18, + 16, + 6, + 10, + 2, + 6, + 2, + 13, + 6, + 13, + 15, + 2, + 16, + 18, + 2, + 18, + 3, + 2, + 3, + 13, + 18, + 1, + 9, + 18, + 9, + 11, + 18, + 11, + 3, + 4, + 14, + 12, + 4, + 12, + 0, + 4, + 0, + 8, + 11, + 9, + 5, + 11, + 5, + 19, + 11, + 19, + 7, + 19, + 5, + 14, + 19, + 14, + 4, + 19, + 4, + 17, + 1, + 12, + 14, + 1, + 14, + 5, + 1, + 5, + 9 + ]; + super(r, a, e, t), this.type = "DodecahedronGeometry", this.parameters = { + radius: e, + detail: t + }; + } + static fromJSON(e) { + return new s1(e.radius, e.detail); + } +}, vr = new A, yr = new A, ao = new A, Mr = new Un, $o = class extends Ge { + constructor(e = null, t = 1){ + if (super(), this.type = "EdgesGeometry", this.parameters = { + geometry: e, + thresholdAngle: t + }, e !== null) { + let i = Math.pow(10, 4), r = Math.cos(ai * t), a = e.getIndex(), o = e.getAttribute("position"), c = a ? a.count : o.count, l = [ + 0, + 0, + 0 + ], h = [ + "a", + "b", + "c" + ], u = new Array(3), d = {}, f = []; + for(let m = 0; m < c; m += 3){ + a ? (l[0] = a.getX(m), l[1] = a.getX(m + 1), l[2] = a.getX(m + 2)) : (l[0] = m, l[1] = m + 1, l[2] = m + 2); + let { a: _ , b: g , c: p } = Mr; + if (_.fromBufferAttribute(o, l[0]), g.fromBufferAttribute(o, l[1]), p.fromBufferAttribute(o, l[2]), Mr.getNormal(ao), u[0] = `${Math.round(_.x * i)},${Math.round(_.y * i)},${Math.round(_.z * i)}`, u[1] = `${Math.round(g.x * i)},${Math.round(g.y * i)},${Math.round(g.z * i)}`, u[2] = `${Math.round(p.x * i)},${Math.round(p.y * i)},${Math.round(p.z * i)}`, !(u[0] === u[1] || u[1] === u[2] || u[2] === u[0])) for(let v = 0; v < 3; v++){ + let x = (v + 1) % 3, y = u[v], b = u[x], w = Mr[h[v]], R = Mr[h[x]], I = `${y}_${b}`, M = `${b}_${y}`; + M in d && d[M] ? (ao.dot(d[M].normal) <= r && (f.push(w.x, w.y, w.z), f.push(R.x, R.y, R.z)), d[M] = null) : I in d || (d[I] = { + index0: l[v], + index1: l[x], + normal: ao.clone() + }); + } + } + for(let m in d)if (d[m]) { + let { index0: _ , index1: g } = d[m]; + vr.fromBufferAttribute(o, _), yr.fromBufferAttribute(o, g), f.push(vr.x, vr.y, vr.z), f.push(yr.x, yr.y, yr.z); + } + this.setAttribute("position", new ve(f, 3)); + } } copy(e) { - return super.copy(e), this.currentPoint.copy(e.currentPoint), this; - } - toJSON() { - let e = super.toJSON(); - return e.currentPoint = this.currentPoint.toArray(), e; - } - fromJSON(e) { - return super.fromJSON(e), this.currentPoint.fromArray(e.currentPoint), this; + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; } -}, Xt = class extends gr { +}, Fn = class extends ji { constructor(e){ - super(e); - this.uuid = Et(), this.type = "Shape", this.holes = []; + super(e), this.uuid = kt(), this.type = "Shape", this.holes = []; } getPointsHoles(e) { let t = []; @@ -13338,476 +15008,469 @@ var Ta = Object.freeze({ super.fromJSON(e), this.uuid = e.uuid, this.holes = []; for(let t = 0, n = e.holes.length; t < n; t++){ let i = e.holes[t]; - this.holes.push(new gr().fromJSON(i)); + this.holes.push(new ji().fromJSON(i)); } return this; } -}, Ox = { - triangulate: function(s, e, t = 2) { - let n = e && e.length, i = n ? e[0] * t : s.length, r = Ch(s, 0, i, t, !0), o = []; - if (!r || r.next === r.prev) return o; - let a, l, c, h, u, d, f; - if (n && (r = Wx(s, e, r, t)), s.length > 80 * t) { - a = c = s[0], l = h = s[1]; - for(let m = t; m < i; m += t)u = s[m], d = s[m + 1], u < a && (a = u), d < l && (l = d), u > c && (c = u), d > h && (h = d); - f = Math.max(c - a, h - l), f = f !== 0 ? 1 / f : 0; - } - return xr(r, o, t, a, l, f), o; - } -}; -function Ch(s, e, t, n, i) { - let r, o; - if (i === ty(s, e, t, n) > 0) for(r = e; r < t; r += n)o = mc(r, s[r], s[r + 1], o); - else for(r = t - n; r >= e; r -= n)o = mc(r, s[r], s[r + 1], o); - return o && fo(o, o.next) && (vr(o), o = o.next), o; -} -function Tn(s, e) { - if (!s) return s; - e || (e = s); - let t = s, n; - do if (n = !1, !t.steiner && (fo(t, t.next) || $e(t.prev, t, t.next) === 0)) { - if (vr(t), t = e = t.prev, t === t.next) break; +}, ex = { + triangulate: function(s1, e, t = 2) { + let n = e && e.length, i = n ? e[0] * t : s1.length, r = Pd(s1, 0, i, t, !0), a = []; + if (!r || r.next === r.prev) return a; + let o, c, l, h, u, d, f; + if (n && (r = rx(s1, e, r, t)), s1.length > 80 * t) { + o = l = s1[0], c = h = s1[1]; + for(let m = t; m < i; m += t)u = s1[m], d = s1[m + 1], u < o && (o = u), d < c && (c = d), u > l && (l = u), d > h && (h = d); + f = Math.max(l - o, h - c), f = f !== 0 ? 32767 / f : 0; + } + return Os(r, a, t, o, c, f, 0), a; + } +}; +function Pd(s1, e, t, n, i) { + let r, a; + if (i === gx(s1, e, t, n) > 0) for(r = e; r < t; r += n)a = tu(r, s1[r], s1[r + 1], a); + else for(r = t - n; r >= e; r -= n)a = tu(r, s1[r], s1[r + 1], a); + return a && Ma(a, a.next) && (Bs(a), a = a.next), a; +} +function fi(s1, e) { + if (!s1) return s1; + e || (e = s1); + let t = s1, n; + do if (n = !1, !t.steiner && (Ma(t, t.next) || st(t.prev, t, t.next) === 0)) { + if (Bs(t), t = e = t.prev, t === t.next) break; n = !0; } else t = t.next; while (n || t !== e) return e; } -function xr(s, e, t, n, i, r, o) { - if (!s) return; - !o && r && Zx(s, n, i, r); - let a = s, l, c; - for(; s.prev !== s.next;){ - if (l = s.prev, c = s.next, r ? kx(s, n, i, r) : Hx(s)) { - e.push(l.i / t), e.push(s.i / t), e.push(c.i / t), vr(s), s = c.next, a = c.next; +function Os(s1, e, t, n, i, r, a) { + if (!s1) return; + !a && r && hx(s1, n, i, r); + let o = s1, c, l; + for(; s1.prev !== s1.next;){ + if (c = s1.prev, l = s1.next, r ? nx(s1, n, i, r) : tx(s1)) { + e.push(c.i / t | 0), e.push(s1.i / t | 0), e.push(l.i / t | 0), Bs(s1), s1 = l.next, o = l.next; continue; } - if (s = c, s === a) { - o ? o === 1 ? (s = Gx(Tn(s), e, t), xr(s, e, t, n, i, r, 2)) : o === 2 && Vx(s, e, t, n, i, r) : xr(Tn(s), e, t, n, i, r, 1); + if (s1 = l, s1 === o) { + a ? a === 1 ? (s1 = ix(fi(s1), e, t), Os(s1, e, t, n, i, r, 2)) : a === 2 && sx(s1, e, t, n, i, r) : Os(fi(s1), e, t, n, i, r, 1); break; } } } -function Hx(s) { - let e = s.prev, t = s, n = s.next; - if ($e(e, t, n) >= 0) return !1; - let i = s.next.next; - for(; i !== s.prev;){ - if (Si(e.x, e.y, t.x, t.y, n.x, n.y, i.x, i.y) && $e(i.prev, i, i.next) >= 0) return !1; - i = i.next; +function tx(s1) { + let e = s1.prev, t = s1, n = s1.next; + if (st(e, t, n) >= 0) return !1; + let i = e.x, r = t.x, a = n.x, o = e.y, c = t.y, l = n.y, h = i < r ? i < a ? i : a : r < a ? r : a, u = o < c ? o < l ? o : l : c < l ? c : l, d = i > r ? i > a ? i : a : r > a ? r : a, f = o > c ? o > l ? o : l : c > l ? c : l, m = n.next; + for(; m !== e;){ + if (m.x >= h && m.x <= d && m.y >= u && m.y <= f && Gi(i, o, r, c, a, l, m.x, m.y) && st(m.prev, m, m.next) >= 0) return !1; + m = m.next; } return !0; } -function kx(s, e, t, n) { - let i = s.prev, r = s, o = s.next; - if ($e(i, r, o) >= 0) return !1; - let a = i.x < r.x ? i.x < o.x ? i.x : o.x : r.x < o.x ? r.x : o.x, l = i.y < r.y ? i.y < o.y ? i.y : o.y : r.y < o.y ? r.y : o.y, c = i.x > r.x ? i.x > o.x ? i.x : o.x : r.x > o.x ? r.x : o.x, h = i.y > r.y ? i.y > o.y ? i.y : o.y : r.y > o.y ? r.y : o.y, u = oa(a, l, e, t, n), d = oa(c, h, e, t, n), f = s.prevZ, m = s.nextZ; - for(; f && f.z >= u && m && m.z <= d;){ - if (f !== s.prev && f !== s.next && Si(i.x, i.y, r.x, r.y, o.x, o.y, f.x, f.y) && $e(f.prev, f, f.next) >= 0 || (f = f.prevZ, m !== s.prev && m !== s.next && Si(i.x, i.y, r.x, r.y, o.x, o.y, m.x, m.y) && $e(m.prev, m, m.next) >= 0)) return !1; - m = m.nextZ; +function nx(s1, e, t, n) { + let i = s1.prev, r = s1, a = s1.next; + if (st(i, r, a) >= 0) return !1; + let o = i.x, c = r.x, l = a.x, h = i.y, u = r.y, d = a.y, f = o < c ? o < l ? o : l : c < l ? c : l, m = h < u ? h < d ? h : d : u < d ? u : d, _ = o > c ? o > l ? o : l : c > l ? c : l, g = h > u ? h > d ? h : d : u > d ? u : d, p = Ko(f, m, e, t, n), v = Ko(_, g, e, t, n), x = s1.prevZ, y = s1.nextZ; + for(; x && x.z >= p && y && y.z <= v;){ + if (x.x >= f && x.x <= _ && x.y >= m && x.y <= g && x !== i && x !== a && Gi(o, h, c, u, l, d, x.x, x.y) && st(x.prev, x, x.next) >= 0 || (x = x.prevZ, y.x >= f && y.x <= _ && y.y >= m && y.y <= g && y !== i && y !== a && Gi(o, h, c, u, l, d, y.x, y.y) && st(y.prev, y, y.next) >= 0)) return !1; + y = y.nextZ; } - for(; f && f.z >= u;){ - if (f !== s.prev && f !== s.next && Si(i.x, i.y, r.x, r.y, o.x, o.y, f.x, f.y) && $e(f.prev, f, f.next) >= 0) return !1; - f = f.prevZ; + for(; x && x.z >= p;){ + if (x.x >= f && x.x <= _ && x.y >= m && x.y <= g && x !== i && x !== a && Gi(o, h, c, u, l, d, x.x, x.y) && st(x.prev, x, x.next) >= 0) return !1; + x = x.prevZ; } - for(; m && m.z <= d;){ - if (m !== s.prev && m !== s.next && Si(i.x, i.y, r.x, r.y, o.x, o.y, m.x, m.y) && $e(m.prev, m, m.next) >= 0) return !1; - m = m.nextZ; + for(; y && y.z <= v;){ + if (y.x >= f && y.x <= _ && y.y >= m && y.y <= g && y !== i && y !== a && Gi(o, h, c, u, l, d, y.x, y.y) && st(y.prev, y, y.next) >= 0) return !1; + y = y.nextZ; } return !0; } -function Gx(s, e, t) { - let n = s; +function ix(s1, e, t) { + let n = s1; do { let i = n.prev, r = n.next.next; - !fo(i, r) && Lh(i, n, n.next, r) && yr(i, r) && yr(r, i) && (e.push(i.i / t), e.push(n.i / t), e.push(r.i / t), vr(n), vr(n.next), n = s = r), n = n.next; - }while (n !== s) - return Tn(n); + !Ma(i, r) && Ld(i, n, n.next, r) && Fs(i, r) && Fs(r, i) && (e.push(i.i / t | 0), e.push(n.i / t | 0), e.push(r.i / t | 0), Bs(n), Bs(n.next), n = s1 = r), n = n.next; + }while (n !== s1) + return fi(n); } -function Vx(s, e, t, n, i, r) { - let o = s; +function sx(s1, e, t, n, i, r) { + let a = s1; do { - let a = o.next.next; - for(; a !== o.prev;){ - if (o.i !== a.i && Qx(o, a)) { - let l = Rh(o, a); - o = Tn(o, o.next), l = Tn(l, l.next), xr(o, e, t, n, i, r), xr(l, e, t, n, i, r); + let o = a.next.next; + for(; o !== a.prev;){ + if (a.i !== o.i && fx(a, o)) { + let c = Id(a, o); + a = fi(a, a.next), c = fi(c, c.next), Os(a, e, t, n, i, r, 0), Os(c, e, t, n, i, r, 0); return; } - a = a.next; + o = o.next; } - o = o.next; - }while (o !== s) + a = a.next; + }while (a !== s1) } -function Wx(s, e, t, n) { - let i = [], r, o, a, l, c; - for(r = 0, o = e.length; r < o; r++)a = e[r] * n, l = r < o - 1 ? e[r + 1] * n : s.length, c = Ch(s, a, l, n, !1), c === c.next && (c.steiner = !0), i.push(jx(c)); - for(i.sort(qx), r = 0; r < i.length; r++)Xx(i[r], t), t = Tn(t, t.next); +function rx(s1, e, t, n) { + let i = [], r, a, o, c, l; + for(r = 0, a = e.length; r < a; r++)o = e[r] * n, c = r < a - 1 ? e[r + 1] * n : s1.length, l = Pd(s1, o, c, n, !1), l === l.next && (l.steiner = !0), i.push(dx(l)); + for(i.sort(ax), r = 0; r < i.length; r++)t = ox(i[r], t); return t; } -function qx(s, e) { - return s.x - e.x; +function ax(s1, e) { + return s1.x - e.x; } -function Xx(s, e) { - if (e = Jx(s, e), e) { - let t = Rh(e, s); - Tn(e, e.next), Tn(t, t.next); - } +function ox(s1, e) { + let t = cx(s1, e); + if (!t) return e; + let n = Id(t, s1); + return fi(n, n.next), fi(t, t.next); } -function Jx(s, e) { - let t = e, n = s.x, i = s.y, r = -1 / 0, o; +function cx(s1, e) { + let t = e, n = -1 / 0, i, r = s1.x, a = s1.y; do { - if (i <= t.y && i >= t.next.y && t.next.y !== t.y) { - let d = t.x + (i - t.y) * (t.next.x - t.x) / (t.next.y - t.y); - if (d <= n && d > r) { - if (r = d, d === n) { - if (i === t.y) return t; - if (i === t.next.y) return t.next; - } - o = t.x < t.next.x ? t : t.next; - } + if (a <= t.y && a >= t.next.y && t.next.y !== t.y) { + let d = t.x + (a - t.y) * (t.next.x - t.x) / (t.next.y - t.y); + if (d <= r && d > n && (n = d, i = t.x < t.next.x ? t : t.next, d === r)) return i; } t = t.next; }while (t !== e) - if (!o) return null; - if (n === r) return o; - let a = o, l = o.x, c = o.y, h = 1 / 0, u; - t = o; - do n >= t.x && t.x >= l && n !== t.x && Si(i < c ? n : r, i, l, c, i < c ? r : n, i, t.x, t.y) && (u = Math.abs(i - t.y) / (n - t.x), yr(t, s) && (u < h || u === h && (t.x > o.x || t.x === o.x && Yx(o, t))) && (o = t, h = u)), t = t.next; - while (t !== a) - return o; -} -function Yx(s, e) { - return $e(s.prev, s, e.prev) < 0 && $e(e.next, s, s.next) < 0; -} -function Zx(s, e, t, n) { - let i = s; - do i.z === null && (i.z = oa(i.x, i.y, e, t, n)), i.prevZ = i.prev, i.nextZ = i.next, i = i.next; - while (i !== s) - i.prevZ.nextZ = null, i.prevZ = null, $x(i); -} -function $x(s) { - let e, t, n, i, r, o, a, l, c = 1; + if (!i) return null; + let o = i, c = i.x, l = i.y, h = 1 / 0, u; + t = i; + do r >= t.x && t.x >= c && r !== t.x && Gi(a < l ? r : n, a, c, l, a < l ? n : r, a, t.x, t.y) && (u = Math.abs(a - t.y) / (r - t.x), Fs(t, s1) && (u < h || u === h && (t.x > i.x || t.x === i.x && lx(i, t))) && (i = t, h = u)), t = t.next; + while (t !== o) + return i; +} +function lx(s1, e) { + return st(s1.prev, s1, e.prev) < 0 && st(e.next, s1, s1.next) < 0; +} +function hx(s1, e, t, n) { + let i = s1; + do i.z === 0 && (i.z = Ko(i.x, i.y, e, t, n)), i.prevZ = i.prev, i.nextZ = i.next, i = i.next; + while (i !== s1) + i.prevZ.nextZ = null, i.prevZ = null, ux(i); +} +function ux(s1) { + let e, t, n, i, r, a, o, c, l = 1; do { - for(t = s, s = null, r = null, o = 0; t;){ - for(o++, n = t, a = 0, e = 0; e < c && (a++, n = n.nextZ, !!n); e++); - for(l = c; a > 0 || l > 0 && n;)a !== 0 && (l === 0 || !n || t.z <= n.z) ? (i = t, t = t.nextZ, a--) : (i = n, n = n.nextZ, l--), r ? r.nextZ = i : s = i, i.prevZ = r, r = i; + for(t = s1, s1 = null, r = null, a = 0; t;){ + for(a++, n = t, o = 0, e = 0; e < l && (o++, n = n.nextZ, !!n); e++); + for(c = l; o > 0 || c > 0 && n;)o !== 0 && (c === 0 || !n || t.z <= n.z) ? (i = t, t = t.nextZ, o--) : (i = n, n = n.nextZ, c--), r ? r.nextZ = i : s1 = i, i.prevZ = r, r = i; t = n; } - r.nextZ = null, c *= 2; - }while (o > 1) - return s; + r.nextZ = null, l *= 2; + }while (a > 1) + return s1; } -function oa(s, e, t, n, i) { - return s = 32767 * (s - t) * i, e = 32767 * (e - n) * i, s = (s | s << 8) & 16711935, s = (s | s << 4) & 252645135, s = (s | s << 2) & 858993459, s = (s | s << 1) & 1431655765, e = (e | e << 8) & 16711935, e = (e | e << 4) & 252645135, e = (e | e << 2) & 858993459, e = (e | e << 1) & 1431655765, s | e << 1; +function Ko(s1, e, t, n, i) { + return s1 = (s1 - t) * i | 0, e = (e - n) * i | 0, s1 = (s1 | s1 << 8) & 16711935, s1 = (s1 | s1 << 4) & 252645135, s1 = (s1 | s1 << 2) & 858993459, s1 = (s1 | s1 << 1) & 1431655765, e = (e | e << 8) & 16711935, e = (e | e << 4) & 252645135, e = (e | e << 2) & 858993459, e = (e | e << 1) & 1431655765, s1 | e << 1; } -function jx(s) { - let e = s, t = s; +function dx(s1) { + let e = s1, t = s1; do (e.x < t.x || e.x === t.x && e.y < t.y) && (t = e), e = e.next; - while (e !== s) + while (e !== s1) return t; } -function Si(s, e, t, n, i, r, o, a) { - return (i - o) * (e - a) - (s - o) * (r - a) >= 0 && (s - o) * (n - a) - (t - o) * (e - a) >= 0 && (t - o) * (r - a) - (i - o) * (n - a) >= 0; +function Gi(s1, e, t, n, i, r, a, o) { + return (i - a) * (e - o) >= (s1 - a) * (r - o) && (s1 - a) * (n - o) >= (t - a) * (e - o) && (t - a) * (r - o) >= (i - a) * (n - o); } -function Qx(s, e) { - return s.next.i !== e.i && s.prev.i !== e.i && !Kx(s, e) && (yr(s, e) && yr(e, s) && ey(s, e) && ($e(s.prev, s, e.prev) || $e(s, e.prev, e)) || fo(s, e) && $e(s.prev, s, s.next) > 0 && $e(e.prev, e, e.next) > 0); +function fx(s1, e) { + return s1.next.i !== e.i && s1.prev.i !== e.i && !px(s1, e) && (Fs(s1, e) && Fs(e, s1) && mx(s1, e) && (st(s1.prev, s1, e.prev) || st(s1, e.prev, e)) || Ma(s1, e) && st(s1.prev, s1, s1.next) > 0 && st(e.prev, e, e.next) > 0); } -function $e(s, e, t) { - return (e.y - s.y) * (t.x - e.x) - (e.x - s.x) * (t.y - e.y); +function st(s1, e, t) { + return (e.y - s1.y) * (t.x - e.x) - (e.x - s1.x) * (t.y - e.y); } -function fo(s, e) { - return s.x === e.x && s.y === e.y; +function Ma(s1, e) { + return s1.x === e.x && s1.y === e.y; } -function Lh(s, e, t, n) { - let i = ws($e(s, e, t)), r = ws($e(s, e, n)), o = ws($e(t, n, s)), a = ws($e(t, n, e)); - return !!(i !== r && o !== a || i === 0 && bs(s, t, e) || r === 0 && bs(s, n, e) || o === 0 && bs(t, s, n) || a === 0 && bs(t, e, n)); +function Ld(s1, e, t, n) { + let i = br(st(s1, e, t)), r = br(st(s1, e, n)), a = br(st(t, n, s1)), o = br(st(t, n, e)); + return !!(i !== r && a !== o || i === 0 && Sr(s1, t, e) || r === 0 && Sr(s1, n, e) || a === 0 && Sr(t, s1, n) || o === 0 && Sr(t, e, n)); } -function bs(s, e, t) { - return e.x <= Math.max(s.x, t.x) && e.x >= Math.min(s.x, t.x) && e.y <= Math.max(s.y, t.y) && e.y >= Math.min(s.y, t.y); +function Sr(s1, e, t) { + return e.x <= Math.max(s1.x, t.x) && e.x >= Math.min(s1.x, t.x) && e.y <= Math.max(s1.y, t.y) && e.y >= Math.min(s1.y, t.y); } -function ws(s) { - return s > 0 ? 1 : s < 0 ? -1 : 0; +function br(s1) { + return s1 > 0 ? 1 : s1 < 0 ? -1 : 0; } -function Kx(s, e) { - let t = s; +function px(s1, e) { + let t = s1; do { - if (t.i !== s.i && t.next.i !== s.i && t.i !== e.i && t.next.i !== e.i && Lh(t, t.next, s, e)) return !0; + if (t.i !== s1.i && t.next.i !== s1.i && t.i !== e.i && t.next.i !== e.i && Ld(t, t.next, s1, e)) return !0; t = t.next; - }while (t !== s) + }while (t !== s1) return !1; } -function yr(s, e) { - return $e(s.prev, s, s.next) < 0 ? $e(s, e, s.next) >= 0 && $e(s, s.prev, e) >= 0 : $e(s, e, s.prev) < 0 || $e(s, s.next, e) < 0; +function Fs(s1, e) { + return st(s1.prev, s1, s1.next) < 0 ? st(s1, e, s1.next) >= 0 && st(s1, s1.prev, e) >= 0 : st(s1, e, s1.prev) < 0 || st(s1, s1.next, e) < 0; } -function ey(s, e) { - let t = s, n = !1, i = (s.x + e.x) / 2, r = (s.y + e.y) / 2; +function mx(s1, e) { + let t = s1, n = !1, i = (s1.x + e.x) / 2, r = (s1.y + e.y) / 2; do t.y > r != t.next.y > r && t.next.y !== t.y && i < (t.next.x - t.x) * (r - t.y) / (t.next.y - t.y) + t.x && (n = !n), t = t.next; - while (t !== s) + while (t !== s1) return n; } -function Rh(s, e) { - let t = new aa(s.i, s.x, s.y), n = new aa(e.i, e.x, e.y), i = s.next, r = e.prev; - return s.next = e, e.prev = s, t.next = i, i.prev = t, n.next = t, t.prev = n, r.next = n, n.prev = r, n; +function Id(s1, e) { + let t = new Qo(s1.i, s1.x, s1.y), n = new Qo(e.i, e.x, e.y), i = s1.next, r = e.prev; + return s1.next = e, e.prev = s1, t.next = i, i.prev = t, n.next = t, t.prev = n, r.next = n, n.prev = r, n; } -function mc(s, e, t, n) { - let i = new aa(s, e, t); +function tu(s1, e, t, n) { + let i = new Qo(s1, e, t); return n ? (i.next = n.next, i.prev = n, n.next.prev = i, n.next = i) : (i.prev = i, i.next = i), i; } -function vr(s) { - s.next.prev = s.prev, s.prev.next = s.next, s.prevZ && (s.prevZ.nextZ = s.nextZ), s.nextZ && (s.nextZ.prevZ = s.prevZ); +function Bs(s1) { + s1.next.prev = s1.prev, s1.prev.next = s1.next, s1.prevZ && (s1.prevZ.nextZ = s1.nextZ), s1.nextZ && (s1.nextZ.prevZ = s1.prevZ); } -function aa(s, e, t) { - this.i = s, this.x = e, this.y = t, this.prev = null, this.next = null, this.z = null, this.prevZ = null, this.nextZ = null, this.steiner = !1; +function Qo(s1, e, t) { + this.i = s1, this.x = e, this.y = t, this.prev = null, this.next = null, this.z = 0, this.prevZ = null, this.nextZ = null, this.steiner = !1; } -function ty(s, e, t, n) { +function gx(s1, e, t, n) { let i = 0; - for(let r = e, o = t - n; r < t; r += n)i += (s[o] - s[r]) * (s[r + 1] + s[o + 1]), o = r; + for(let r = e, a = t - n; r < t; r += n)i += (s1[a] - s1[r]) * (s1[r + 1] + s1[a + 1]), a = r; return i; } -var Jt = class { +var yn = class s1 { static area(e) { let t = e.length, n = 0; for(let i = t - 1, r = 0; r < t; i = r++)n += e[i].x * e[r].y - e[r].x * e[i].y; return n * .5; } static isClockWise(e) { - return Jt.area(e) < 0; + return s1.area(e) < 0; } static triangulateShape(e, t) { let n = [], i = [], r = []; - gc(e), xc(n, e); - let o = e.length; - t.forEach(gc); - for(let l = 0; l < t.length; l++)i.push(o), o += t[l].length, xc(n, t[l]); - let a = Ox.triangulate(n, i); - for(let l = 0; l < a.length; l += 3)r.push(a.slice(l, l + 3)); + nu(e), iu(n, e); + let a = e.length; + t.forEach(nu); + for(let c = 0; c < t.length; c++)i.push(a), a += t[c].length, iu(n, t[c]); + let o = ex.triangulate(n, i); + for(let c = 0; c < o.length; c += 3)r.push(o.slice(c, c + 3)); return r; } }; -function gc(s) { - let e = s.length; - e > 2 && s[e - 1].equals(s[0]) && s.pop(); -} -function xc(s, e) { - for(let t = 0; t < e.length; t++)s.push(e[t].x), s.push(e[t].y); -} -var ln = class extends _e { - constructor(e = new Xt([ - new X(.5, .5), - new X(-.5, .5), - new X(-.5, -.5), - new X(.5, -.5) +function nu(s1) { + let e = s1.length; + e > 2 && s1[e - 1].equals(s1[0]) && s1.pop(); +} +function iu(s1, e) { + for(let t = 0; t < e.length; t++)s1.push(e[t].x), s1.push(e[t].y); +} +var jo = class s1 extends Ge { + constructor(e = new Fn([ + new Z(.5, .5), + new Z(-.5, .5), + new Z(-.5, -.5), + new Z(.5, -.5) ]), t = {}){ - super(); - this.type = "ExtrudeGeometry", this.parameters = { + super(), this.type = "ExtrudeGeometry", this.parameters = { shapes: e, options: t }, e = Array.isArray(e) ? e : [ e ]; let n = this, i = [], r = []; - for(let a = 0, l = e.length; a < l; a++){ - let c = e[a]; - o(c); - } - this.setAttribute("position", new de(i, 3)), this.setAttribute("uv", new de(r, 2)), this.computeVertexNormals(); - function o(a) { - let l = [], c = t.curveSegments !== void 0 ? t.curveSegments : 12, h = t.steps !== void 0 ? t.steps : 1, u = t.depth !== void 0 ? t.depth : 1, d = t.bevelEnabled !== void 0 ? t.bevelEnabled : !0, f = t.bevelThickness !== void 0 ? t.bevelThickness : .2, m = t.bevelSize !== void 0 ? t.bevelSize : f - .1, x = t.bevelOffset !== void 0 ? t.bevelOffset : 0, v = t.bevelSegments !== void 0 ? t.bevelSegments : 3, g = t.extrudePath, p = t.UVGenerator !== void 0 ? t.UVGenerator : ny; - t.amount !== void 0 && (console.warn("THREE.ExtrudeBufferGeometry: amount has been renamed to depth."), u = t.amount); - let _, y = !1, b, A, L, I; - g && (_ = g.getSpacedPoints(h), y = !0, d = !1, b = g.computeFrenetFrames(h, !1), A = new M, L = new M, I = new M), d || (v = 0, f = 0, m = 0, x = 0); - let k = a.extractPoints(c), B = k.shape, P = k.holes; - if (!Jt.isClockWise(B)) { - B = B.reverse(); - for(let G = 0, j = P.length; G < j; G++){ - let K = P[G]; - Jt.isClockWise(K) && (P[G] = K.reverse()); + for(let o = 0, c = e.length; o < c; o++){ + let l = e[o]; + a(l); + } + this.setAttribute("position", new ve(i, 3)), this.setAttribute("uv", new ve(r, 2)), this.computeVertexNormals(); + function a(o) { + let c = [], l = t.curveSegments !== void 0 ? t.curveSegments : 12, h = t.steps !== void 0 ? t.steps : 1, u = t.depth !== void 0 ? t.depth : 1, d = t.bevelEnabled !== void 0 ? t.bevelEnabled : !0, f = t.bevelThickness !== void 0 ? t.bevelThickness : .2, m = t.bevelSize !== void 0 ? t.bevelSize : f - .1, _ = t.bevelOffset !== void 0 ? t.bevelOffset : 0, g = t.bevelSegments !== void 0 ? t.bevelSegments : 3, p = t.extrudePath, v = t.UVGenerator !== void 0 ? t.UVGenerator : _x, x, y = !1, b, w, R, I; + p && (x = p.getSpacedPoints(h), y = !0, d = !1, b = p.computeFrenetFrames(h, !1), w = new A, R = new A, I = new A), d || (g = 0, f = 0, m = 0, _ = 0); + let M = o.extractPoints(l), T = M.shape, O = M.holes; + if (!yn.isClockWise(T)) { + T = T.reverse(); + for(let L = 0, oe = O.length; L < oe; L++){ + let X = O[L]; + yn.isClockWise(X) && (O[L] = X.reverse()); } } - let E = Jt.triangulateShape(B, P), D = B; - for(let G = 0, j = P.length; G < j; G++){ - let K = P[G]; - B = B.concat(K); - } - function U(G, j, K) { - return j || console.error("THREE.ExtrudeGeometry: vec does not exist"), j.clone().multiplyScalar(K).add(G); - } - let F = B.length, O = E.length; - function ne(G, j, K) { - let ue, se, Se, Te = G.x - j.x, Pe = G.y - j.y, Ye = K.x - G.x, C = K.y - G.y, T = Te * Te + Pe * Pe, J = Te * C - Pe * Ye; - if (Math.abs(J) > Number.EPSILON) { - let $ = Math.sqrt(T), re = Math.sqrt(Ye * Ye + C * C), Z = j.x - Pe / $, Me = j.y + Te / $, ve = K.x - C / re, te = K.y + Ye / re, R = ((ve - Z) * C - (te - Me) * Ye) / (Te * C - Pe * Ye); - ue = Z + Te * R - G.x, se = Me + Pe * R - G.y; - let ee = ue * ue + se * se; - if (ee <= 2) return new X(ue, se); - Se = Math.sqrt(ee / 2); + let $ = yn.triangulateShape(T, O), U = T; + for(let L = 0, oe = O.length; L < oe; L++){ + let X = O[L]; + T = T.concat(X); + } + function z(L, oe, X) { + return oe || console.error("THREE.ExtrudeGeometry: vec does not exist"), L.clone().addScaledVector(oe, X); + } + let q = T.length, H = $.length; + function ne(L, oe, X) { + let ie, J, Se, me = L.x - oe.x, ye = L.y - oe.y, Ne = X.x - L.x, qe = X.y - L.y, rt = me * me + ye * ye, C = me * qe - ye * Ne; + if (Math.abs(C) > Number.EPSILON) { + let S = Math.sqrt(rt), B = Math.sqrt(Ne * Ne + qe * qe), ee = oe.x - ye / S, j = oe.y + me / S, te = X.x - qe / B, Me = X.y + Ne / B, re = ((te - ee) * qe - (Me - j) * Ne) / (me * qe - ye * Ne); + ie = ee + me * re - L.x, J = j + ye * re - L.y; + let de = ie * ie + J * J; + if (de <= 2) return new Z(ie, J); + Se = Math.sqrt(de / 2); } else { - let $ = !1; - Te > Number.EPSILON ? Ye > Number.EPSILON && ($ = !0) : Te < -Number.EPSILON ? Ye < -Number.EPSILON && ($ = !0) : Math.sign(Pe) === Math.sign(C) && ($ = !0), $ ? (ue = -Pe, se = Te, Se = Math.sqrt(T)) : (ue = Te, se = Pe, Se = Math.sqrt(T / 2)); + let S = !1; + me > Number.EPSILON ? Ne > Number.EPSILON && (S = !0) : me < -Number.EPSILON ? Ne < -Number.EPSILON && (S = !0) : Math.sign(ye) === Math.sign(qe) && (S = !0), S ? (ie = -ye, J = me, Se = Math.sqrt(rt)) : (ie = me, J = ye, Se = Math.sqrt(rt / 2)); } - return new X(ue / Se, se / Se); - } - let ce = []; - for(let G = 0, j = D.length, K = j - 1, ue = G + 1; G < j; G++, K++, ue++)K === j && (K = 0), ue === j && (ue = 0), ce[G] = ne(D[G], D[K], D[ue]); - let V = [], W, he = ce.concat(); - for(let G = 0, j = P.length; G < j; G++){ - let K = P[G]; - W = []; - for(let ue = 0, se = K.length, Se = se - 1, Te = ue + 1; ue < se; ue++, Se++, Te++)Se === se && (Se = 0), Te === se && (Te = 0), W[ue] = ne(K[ue], K[Se], K[Te]); - V.push(W), he = he.concat(W); - } - for(let G = 0; G < v; G++){ - let j = G / v, K = f * Math.cos(j * Math.PI / 2), ue = m * Math.sin(j * Math.PI / 2) + x; - for(let se = 0, Se = D.length; se < Se; se++){ - let Te = U(D[se], ce[se], ue); - Ce(Te.x, Te.y, -K); + return new Z(ie / Se, J / Se); + } + let W = []; + for(let L = 0, oe = U.length, X = oe - 1, ie = L + 1; L < oe; L++, X++, ie++)X === oe && (X = 0), ie === oe && (ie = 0), W[L] = ne(U[L], U[X], U[ie]); + let K = [], D, G = W.concat(); + for(let L = 0, oe = O.length; L < oe; L++){ + let X = O[L]; + D = []; + for(let ie = 0, J = X.length, Se = J - 1, me = ie + 1; ie < J; ie++, Se++, me++)Se === J && (Se = 0), me === J && (me = 0), D[ie] = ne(X[ie], X[Se], X[me]); + K.push(D), G = G.concat(D); + } + for(let L = 0; L < g; L++){ + let oe = L / g, X = f * Math.cos(oe * Math.PI / 2), ie = m * Math.sin(oe * Math.PI / 2) + _; + for(let J = 0, Se = U.length; J < Se; J++){ + let me = z(U[J], W[J], ie); + Ee(me.x, me.y, -X); } - for(let se = 0, Se = P.length; se < Se; se++){ - let Te = P[se]; - W = V[se]; - for(let Pe = 0, Ye = Te.length; Pe < Ye; Pe++){ - let C = U(Te[Pe], W[Pe], ue); - Ce(C.x, C.y, -K); + for(let J = 0, Se = O.length; J < Se; J++){ + let me = O[J]; + D = K[J]; + for(let ye = 0, Ne = me.length; ye < Ne; ye++){ + let qe = z(me[ye], D[ye], ie); + Ee(qe.x, qe.y, -X); } } } - let le = m + x; - for(let G = 0; G < F; G++){ - let j = d ? U(B[G], he[G], le) : B[G]; - y ? (L.copy(b.normals[0]).multiplyScalar(j.x), A.copy(b.binormals[0]).multiplyScalar(j.y), I.copy(_[0]).add(L).add(A), Ce(I.x, I.y, I.z)) : Ce(j.x, j.y, 0); + let he = m + _; + for(let L = 0; L < q; L++){ + let oe = d ? z(T[L], G[L], he) : T[L]; + y ? (R.copy(b.normals[0]).multiplyScalar(oe.x), w.copy(b.binormals[0]).multiplyScalar(oe.y), I.copy(x[0]).add(R).add(w), Ee(I.x, I.y, I.z)) : Ee(oe.x, oe.y, 0); } - for(let G = 1; G <= h; G++)for(let j = 0; j < F; j++){ - let K = d ? U(B[j], he[j], le) : B[j]; - y ? (L.copy(b.normals[G]).multiplyScalar(K.x), A.copy(b.binormals[G]).multiplyScalar(K.y), I.copy(_[G]).add(L).add(A), Ce(I.x, I.y, I.z)) : Ce(K.x, K.y, u / h * G); + for(let L = 1; L <= h; L++)for(let oe = 0; oe < q; oe++){ + let X = d ? z(T[oe], G[oe], he) : T[oe]; + y ? (R.copy(b.normals[L]).multiplyScalar(X.x), w.copy(b.binormals[L]).multiplyScalar(X.y), I.copy(x[L]).add(R).add(w), Ee(I.x, I.y, I.z)) : Ee(X.x, X.y, u / h * L); } - for(let G = v - 1; G >= 0; G--){ - let j = G / v, K = f * Math.cos(j * Math.PI / 2), ue = m * Math.sin(j * Math.PI / 2) + x; - for(let se = 0, Se = D.length; se < Se; se++){ - let Te = U(D[se], ce[se], ue); - Ce(Te.x, Te.y, u + K); + for(let L = g - 1; L >= 0; L--){ + let oe = L / g, X = f * Math.cos(oe * Math.PI / 2), ie = m * Math.sin(oe * Math.PI / 2) + _; + for(let J = 0, Se = U.length; J < Se; J++){ + let me = z(U[J], W[J], ie); + Ee(me.x, me.y, u + X); } - for(let se = 0, Se = P.length; se < Se; se++){ - let Te = P[se]; - W = V[se]; - for(let Pe = 0, Ye = Te.length; Pe < Ye; Pe++){ - let C = U(Te[Pe], W[Pe], ue); - y ? Ce(C.x, C.y + _[h - 1].y, _[h - 1].x + K) : Ce(C.x, C.y, u + K); + for(let J = 0, Se = O.length; J < Se; J++){ + let me = O[J]; + D = K[J]; + for(let ye = 0, Ne = me.length; ye < Ne; ye++){ + let qe = z(me[ye], D[ye], ie); + y ? Ee(qe.x, qe.y + x[h - 1].y, x[h - 1].x + X) : Ee(qe.x, qe.y, u + X); } } } - fe(), Be(); + fe(), _e(); function fe() { - let G = i.length / 3; + let L = i.length / 3; if (d) { - let j = 0, K = F * j; - for(let ue = 0; ue < O; ue++){ - let se = E[ue]; - ye(se[2] + K, se[1] + K, se[0] + K); + let oe = 0, X = q * oe; + for(let ie = 0; ie < H; ie++){ + let J = $[ie]; + Te(J[2] + X, J[1] + X, J[0] + X); } - j = h + v * 2, K = F * j; - for(let ue = 0; ue < O; ue++){ - let se = E[ue]; - ye(se[0] + K, se[1] + K, se[2] + K); + oe = h + g * 2, X = q * oe; + for(let ie = 0; ie < H; ie++){ + let J = $[ie]; + Te(J[0] + X, J[1] + X, J[2] + X); } } else { - for(let j = 0; j < O; j++){ - let K = E[j]; - ye(K[2], K[1], K[0]); + for(let oe = 0; oe < H; oe++){ + let X = $[oe]; + Te(X[2], X[1], X[0]); } - for(let j = 0; j < O; j++){ - let K = E[j]; - ye(K[0] + F * h, K[1] + F * h, K[2] + F * h); + for(let oe = 0; oe < H; oe++){ + let X = $[oe]; + Te(X[0] + q * h, X[1] + q * h, X[2] + q * h); } } - n.addGroup(G, i.length / 3 - G, 0); - } - function Be() { - let G = i.length / 3, j = 0; - Y(D, j), j += D.length; - for(let K = 0, ue = P.length; K < ue; K++){ - let se = P[K]; - Y(se, j), j += se.length; + n.addGroup(L, i.length / 3 - L, 0); + } + function _e() { + let L = i.length / 3, oe = 0; + we(U, oe), oe += U.length; + for(let X = 0, ie = O.length; X < ie; X++){ + let J = O[X]; + we(J, oe), oe += J.length; } - n.addGroup(G, i.length / 3 - G, 1); - } - function Y(G, j) { - let K = G.length; - for(; --K >= 0;){ - let ue = K, se = K - 1; - se < 0 && (se = G.length - 1); - for(let Se = 0, Te = h + v * 2; Se < Te; Se++){ - let Pe = F * Se, Ye = F * (Se + 1), C = j + ue + Pe, T = j + se + Pe, J = j + se + Ye, $ = j + ue + Ye; - ge(C, T, J, $); + n.addGroup(L, i.length / 3 - L, 1); + } + function we(L, oe) { + let X = L.length; + for(; --X >= 0;){ + let ie = X, J = X - 1; + J < 0 && (J = L.length - 1); + for(let Se = 0, me = h + g * 2; Se < me; Se++){ + let ye = q * Se, Ne = q * (Se + 1), qe = oe + ie + ye, rt = oe + J + ye, C = oe + J + Ne, S = oe + ie + Ne; + Ye(qe, rt, C, S); } } } - function Ce(G, j, K) { - l.push(G), l.push(j), l.push(K); + function Ee(L, oe, X) { + c.push(L), c.push(oe), c.push(X); } - function ye(G, j, K) { - xe(G), xe(j), xe(K); - let ue = i.length / 3, se = p.generateTopUV(n, i, ue - 3, ue - 2, ue - 1); - Oe(se[0]), Oe(se[1]), Oe(se[2]); + function Te(L, oe, X) { + it(L), it(oe), it(X); + let ie = i.length / 3, J = v.generateTopUV(n, i, ie - 3, ie - 2, ie - 1); + Ce(J[0]), Ce(J[1]), Ce(J[2]); } - function ge(G, j, K, ue) { - xe(G), xe(j), xe(ue), xe(j), xe(K), xe(ue); - let se = i.length / 3, Se = p.generateSideWallUV(n, i, se - 6, se - 3, se - 2, se - 1); - Oe(Se[0]), Oe(Se[1]), Oe(Se[3]), Oe(Se[1]), Oe(Se[2]), Oe(Se[3]); + function Ye(L, oe, X, ie) { + it(L), it(oe), it(ie), it(oe), it(X), it(ie); + let J = i.length / 3, Se = v.generateSideWallUV(n, i, J - 6, J - 3, J - 2, J - 1); + Ce(Se[0]), Ce(Se[1]), Ce(Se[3]), Ce(Se[1]), Ce(Se[2]), Ce(Se[3]); } - function xe(G) { - i.push(l[G * 3 + 0]), i.push(l[G * 3 + 1]), i.push(l[G * 3 + 2]); + function it(L) { + i.push(c[L * 3 + 0]), i.push(c[L * 3 + 1]), i.push(c[L * 3 + 2]); } - function Oe(G) { - r.push(G.x), r.push(G.y); + function Ce(L) { + r.push(L.x), r.push(L.y); } } } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; + } toJSON() { let e = super.toJSON(), t = this.parameters.shapes, n = this.parameters.options; - return iy(t, n, e); + return xx(t, n, e); } static fromJSON(e, t) { let n = []; - for(let r = 0, o = e.shapes.length; r < o; r++){ - let a = t[e.shapes[r]]; - n.push(a); + for(let r = 0, a = e.shapes.length; r < a; r++){ + let o = t[e.shapes[r]]; + n.push(o); } let i = e.options.extrudePath; - return i !== void 0 && (e.options.extrudePath = new Ta[i.type]().fromJSON(i)), new ln(n, e.options); + return i !== void 0 && (e.options.extrudePath = new ca[i.type]().fromJSON(i)), new s1(n, e.options); } -}, ny = { - generateTopUV: function(s, e, t, n, i) { - let r = e[t * 3], o = e[t * 3 + 1], a = e[n * 3], l = e[n * 3 + 1], c = e[i * 3], h = e[i * 3 + 1]; +}, _x = { + generateTopUV: function(s1, e, t, n, i) { + let r = e[t * 3], a = e[t * 3 + 1], o = e[n * 3], c = e[n * 3 + 1], l = e[i * 3], h = e[i * 3 + 1]; return [ - new X(r, o), - new X(a, l), - new X(c, h) + new Z(r, a), + new Z(o, c), + new Z(l, h) ]; }, - generateSideWallUV: function(s, e, t, n, i, r) { - let o = e[t * 3], a = e[t * 3 + 1], l = e[t * 3 + 2], c = e[n * 3], h = e[n * 3 + 1], u = e[n * 3 + 2], d = e[i * 3], f = e[i * 3 + 1], m = e[i * 3 + 2], x = e[r * 3], v = e[r * 3 + 1], g = e[r * 3 + 2]; - return Math.abs(a - h) < Math.abs(o - c) ? [ - new X(o, 1 - l), - new X(c, 1 - u), - new X(d, 1 - m), - new X(x, 1 - g) + generateSideWallUV: function(s1, e, t, n, i, r) { + let a = e[t * 3], o = e[t * 3 + 1], c = e[t * 3 + 2], l = e[n * 3], h = e[n * 3 + 1], u = e[n * 3 + 2], d = e[i * 3], f = e[i * 3 + 1], m = e[i * 3 + 2], _ = e[r * 3], g = e[r * 3 + 1], p = e[r * 3 + 2]; + return Math.abs(o - h) < Math.abs(a - l) ? [ + new Z(a, 1 - c), + new Z(l, 1 - u), + new Z(d, 1 - m), + new Z(_, 1 - p) ] : [ - new X(a, 1 - l), - new X(h, 1 - u), - new X(f, 1 - m), - new X(v, 1 - g) + new Z(o, 1 - c), + new Z(h, 1 - u), + new Z(f, 1 - m), + new Z(g, 1 - p) ]; } }; -function iy(s, e, t) { - if (t.shapes = [], Array.isArray(s)) for(let n = 0, i = s.length; n < i; n++){ - let r = s[n]; +function xx(s1, e, t) { + if (t.shapes = [], Array.isArray(s1)) for(let n = 0, i = s1.length; n < i; n++){ + let r = s1[n]; t.shapes.push(r.uuid); } - else t.shapes.push(s.uuid); - return e.extrudePath !== void 0 && (t.options.extrudePath = e.extrudePath.toJSON()), t; + else t.shapes.push(s1.uuid); + return t.options = Object.assign({}, e), e.extrudePath !== void 0 && (t.options.extrudePath = e.extrudePath.toJSON()), t; } -var _r = class extends an { +var ec = class s1 extends di { constructor(e = 1, t = 0){ let n = (1 + Math.sqrt(5)) / 2, i = [ -1, @@ -13908,57 +15571,15 @@ var _r = class extends an { 8, 1 ]; - super(i, r, e, t); - this.type = "IcosahedronGeometry", this.parameters = { + super(i, r, e, t), this.type = "IcosahedronGeometry", this.parameters = { radius: e, detail: t }; } static fromJSON(e) { - return new _r(e.radius, e.detail); - } -}, Mr = class extends _e { - constructor(e = [ - new X(0, .5), - new X(.5, 0), - new X(0, -.5) - ], t = 12, n = 0, i = Math.PI * 2){ - super(); - this.type = "LatheGeometry", this.parameters = { - points: e, - segments: t, - phiStart: n, - phiLength: i - }, t = Math.floor(t), i = mt(i, 0, Math.PI * 2); - let r = [], o = [], a = [], l = [], c = [], h = 1 / t, u = new M, d = new X, f = new M, m = new M, x = new M, v = 0, g = 0; - for(let p = 0; p <= e.length - 1; p++)switch(p){ - case 0: - v = e[p + 1].x - e[p].x, g = e[p + 1].y - e[p].y, f.x = g * 1, f.y = -v, f.z = g * 0, x.copy(f), f.normalize(), l.push(f.x, f.y, f.z); - break; - case e.length - 1: - l.push(x.x, x.y, x.z); - break; - default: - v = e[p + 1].x - e[p].x, g = e[p + 1].y - e[p].y, f.x = g * 1, f.y = -v, f.z = g * 0, m.copy(f), f.x += x.x, f.y += x.y, f.z += x.z, f.normalize(), l.push(f.x, f.y, f.z), x.copy(m); - } - for(let p = 0; p <= t; p++){ - let _ = n + p * h * i, y = Math.sin(_), b = Math.cos(_); - for(let A = 0; A <= e.length - 1; A++){ - u.x = e[A].x * y, u.y = e[A].y, u.z = e[A].x * b, o.push(u.x, u.y, u.z), d.x = p / t, d.y = A / (e.length - 1), a.push(d.x, d.y); - let L = l[3 * A + 0] * y, I = l[3 * A + 1], k = l[3 * A + 0] * b; - c.push(L, I, k); - } - } - for(let p = 0; p < t; p++)for(let _ = 0; _ < e.length - 1; _++){ - let y = _ + p * e.length, b = y, A = y + e.length, L = y + e.length + 1, I = y + 1; - r.push(b, A, I), r.push(A, L, I); - } - this.setIndex(r), this.setAttribute("position", new de(o, 3)), this.setAttribute("uv", new de(a, 2)), this.setAttribute("normal", new de(c, 3)); - } - static fromJSON(e) { - return new Mr(e.points, e.segments, e.phiStart, e.phiLength); + return new s1(e.radius, e.detail); } -}, Ii = class extends an { +}, ha = class s1 extends di { constructor(e = 1, t = 0){ let n = [ 1, @@ -14005,136 +15626,141 @@ var _r = class extends an { 4, 2 ]; - super(n, i, e, t); - this.type = "OctahedronGeometry", this.parameters = { + super(n, i, e, t), this.type = "OctahedronGeometry", this.parameters = { radius: e, detail: t }; } static fromJSON(e) { - return new Ii(e.radius, e.detail); + return new s1(e.radius, e.detail); } -}, br = class extends _e { - constructor(e = .5, t = 1, n = 8, i = 1, r = 0, o = Math.PI * 2){ - super(); - this.type = "RingGeometry", this.parameters = { +}, tc = class s1 extends Ge { + constructor(e = .5, t = 1, n = 32, i = 1, r = 0, a = Math.PI * 2){ + super(), this.type = "RingGeometry", this.parameters = { innerRadius: e, outerRadius: t, thetaSegments: n, phiSegments: i, thetaStart: r, - thetaLength: o + thetaLength: a }, n = Math.max(3, n), i = Math.max(1, i); - let a = [], l = [], c = [], h = [], u = e, d = (t - e) / i, f = new M, m = new X; - for(let x = 0; x <= i; x++){ - for(let v = 0; v <= n; v++){ - let g = r + v / n * o; - f.x = u * Math.cos(g), f.y = u * Math.sin(g), l.push(f.x, f.y, f.z), c.push(0, 0, 1), m.x = (f.x / t + 1) / 2, m.y = (f.y / t + 1) / 2, h.push(m.x, m.y); + let o = [], c = [], l = [], h = [], u = e, d = (t - e) / i, f = new A, m = new Z; + for(let _ = 0; _ <= i; _++){ + for(let g = 0; g <= n; g++){ + let p = r + g / n * a; + f.x = u * Math.cos(p), f.y = u * Math.sin(p), c.push(f.x, f.y, f.z), l.push(0, 0, 1), m.x = (f.x / t + 1) / 2, m.y = (f.y / t + 1) / 2, h.push(m.x, m.y); } u += d; } - for(let x = 0; x < i; x++){ - let v = x * (n + 1); - for(let g = 0; g < n; g++){ - let p = g + v, _ = p, y = p + n + 1, b = p + n + 2, A = p + 1; - a.push(_, y, A), a.push(y, b, A); + for(let _ = 0; _ < i; _++){ + let g = _ * (n + 1); + for(let p = 0; p < n; p++){ + let v = p + g, x = v, y = v + n + 1, b = v + n + 2, w = v + 1; + o.push(x, y, w), o.push(y, b, w); } } - this.setIndex(a), this.setAttribute("position", new de(l, 3)), this.setAttribute("normal", new de(c, 3)), this.setAttribute("uv", new de(h, 2)); + this.setIndex(o), this.setAttribute("position", new ve(c, 3)), this.setAttribute("normal", new ve(l, 3)), this.setAttribute("uv", new ve(h, 2)); + } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; } static fromJSON(e) { - return new br(e.innerRadius, e.outerRadius, e.thetaSegments, e.phiSegments, e.thetaStart, e.thetaLength); + return new s1(e.innerRadius, e.outerRadius, e.thetaSegments, e.phiSegments, e.thetaStart, e.thetaLength); } -}, Di = class extends _e { - constructor(e = new Xt([ - new X(0, .5), - new X(-.5, -.5), - new X(.5, -.5) +}, nc = class s1 extends Ge { + constructor(e = new Fn([ + new Z(0, .5), + new Z(-.5, -.5), + new Z(.5, -.5) ]), t = 12){ - super(); - this.type = "ShapeGeometry", this.parameters = { + super(), this.type = "ShapeGeometry", this.parameters = { shapes: e, curveSegments: t }; - let n = [], i = [], r = [], o = [], a = 0, l = 0; - if (Array.isArray(e) === !1) c(e); - else for(let h = 0; h < e.length; h++)c(e[h]), this.addGroup(a, l, h), a += l, l = 0; - this.setIndex(n), this.setAttribute("position", new de(i, 3)), this.setAttribute("normal", new de(r, 3)), this.setAttribute("uv", new de(o, 2)); - function c(h) { + let n = [], i = [], r = [], a = [], o = 0, c = 0; + if (Array.isArray(e) === !1) l(e); + else for(let h = 0; h < e.length; h++)l(e[h]), this.addGroup(o, c, h), o += c, c = 0; + this.setIndex(n), this.setAttribute("position", new ve(i, 3)), this.setAttribute("normal", new ve(r, 3)), this.setAttribute("uv", new ve(a, 2)); + function l(h) { let u = i.length / 3, d = h.extractPoints(t), f = d.shape, m = d.holes; - Jt.isClockWise(f) === !1 && (f = f.reverse()); - for(let v = 0, g = m.length; v < g; v++){ - let p = m[v]; - Jt.isClockWise(p) === !0 && (m[v] = p.reverse()); + yn.isClockWise(f) === !1 && (f = f.reverse()); + for(let g = 0, p = m.length; g < p; g++){ + let v = m[g]; + yn.isClockWise(v) === !0 && (m[g] = v.reverse()); } - let x = Jt.triangulateShape(f, m); - for(let v = 0, g = m.length; v < g; v++){ - let p = m[v]; - f = f.concat(p); + let _ = yn.triangulateShape(f, m); + for(let g = 0, p = m.length; g < p; g++){ + let v = m[g]; + f = f.concat(v); } - for(let v = 0, g = f.length; v < g; v++){ - let p = f[v]; - i.push(p.x, p.y, 0), r.push(0, 0, 1), o.push(p.x, p.y); + for(let g = 0, p = f.length; g < p; g++){ + let v = f[g]; + i.push(v.x, v.y, 0), r.push(0, 0, 1), a.push(v.x, v.y); } - for(let v = 0, g = x.length; v < g; v++){ - let p = x[v], _ = p[0] + u, y = p[1] + u, b = p[2] + u; - n.push(_, y, b), l += 3; + for(let g = 0, p = _.length; g < p; g++){ + let v = _[g], x = v[0] + u, y = v[1] + u, b = v[2] + u; + n.push(x, y, b), c += 3; } } } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; + } toJSON() { let e = super.toJSON(), t = this.parameters.shapes; - return ry(t, e); + return vx(t, e); } static fromJSON(e, t) { let n = []; for(let i = 0, r = e.shapes.length; i < r; i++){ - let o = t[e.shapes[i]]; - n.push(o); + let a = t[e.shapes[i]]; + n.push(a); } - return new Di(n, e.curveSegments); + return new s1(n, e.curveSegments); } }; -function ry(s, e) { - if (e.shapes = [], Array.isArray(s)) for(let t = 0, n = s.length; t < n; t++){ - let i = s[t]; +function vx(s1, e) { + if (e.shapes = [], Array.isArray(s1)) for(let t = 0, n = s1.length; t < n; t++){ + let i = s1[t]; e.shapes.push(i.uuid); } - else e.shapes.push(s.uuid); + else e.shapes.push(s1.uuid); return e; } -var Fi = class extends _e { - constructor(e = 1, t = 32, n = 16, i = 0, r = Math.PI * 2, o = 0, a = Math.PI){ - super(); - this.type = "SphereGeometry", this.parameters = { +var ua = class s1 extends Ge { + constructor(e = 1, t = 32, n = 16, i = 0, r = Math.PI * 2, a = 0, o = Math.PI){ + super(), this.type = "SphereGeometry", this.parameters = { radius: e, widthSegments: t, heightSegments: n, phiStart: i, phiLength: r, - thetaStart: o, - thetaLength: a + thetaStart: a, + thetaLength: o }, t = Math.max(3, Math.floor(t)), n = Math.max(2, Math.floor(n)); - let l = Math.min(o + a, Math.PI), c = 0, h = [], u = new M, d = new M, f = [], m = [], x = [], v = []; - for(let g = 0; g <= n; g++){ - let p = [], _ = g / n, y = 0; - g == 0 && o == 0 ? y = .5 / t : g == n && l == Math.PI && (y = -.5 / t); + let c = Math.min(a + o, Math.PI), l = 0, h = [], u = new A, d = new A, f = [], m = [], _ = [], g = []; + for(let p = 0; p <= n; p++){ + let v = [], x = p / n, y = 0; + p === 0 && a === 0 ? y = .5 / t : p === n && c === Math.PI && (y = -.5 / t); for(let b = 0; b <= t; b++){ - let A = b / t; - u.x = -e * Math.cos(i + A * r) * Math.sin(o + _ * a), u.y = e * Math.cos(o + _ * a), u.z = e * Math.sin(i + A * r) * Math.sin(o + _ * a), m.push(u.x, u.y, u.z), d.copy(u).normalize(), x.push(d.x, d.y, d.z), v.push(A + y, 1 - _), p.push(c++); + let w = b / t; + u.x = -e * Math.cos(i + w * r) * Math.sin(a + x * o), u.y = e * Math.cos(a + x * o), u.z = e * Math.sin(i + w * r) * Math.sin(a + x * o), m.push(u.x, u.y, u.z), d.copy(u).normalize(), _.push(d.x, d.y, d.z), g.push(w + y, 1 - x), v.push(l++); } - h.push(p); + h.push(v); } - for(let g = 0; g < n; g++)for(let p = 0; p < t; p++){ - let _ = h[g][p + 1], y = h[g][p], b = h[g + 1][p], A = h[g + 1][p + 1]; - (g !== 0 || o > 0) && f.push(_, y, A), (g !== n - 1 || l < Math.PI) && f.push(y, b, A); + for(let p = 0; p < n; p++)for(let v = 0; v < t; v++){ + let x = h[p][v + 1], y = h[p][v], b = h[p + 1][v], w = h[p + 1][v + 1]; + (p !== 0 || a > 0) && f.push(x, y, w), (p !== n - 1 || c < Math.PI) && f.push(y, b, w); } - this.setIndex(f), this.setAttribute("position", new de(m, 3)), this.setAttribute("normal", new de(x, 3)), this.setAttribute("uv", new de(v, 2)); + this.setIndex(f), this.setAttribute("position", new ve(m, 3)), this.setAttribute("normal", new ve(_, 3)), this.setAttribute("uv", new ve(g, 2)); + } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; } static fromJSON(e) { - return new Fi(e.radius, e.widthSegments, e.heightSegments, e.phiStart, e.phiLength, e.thetaStart, e.thetaLength); + return new s1(e.radius, e.widthSegments, e.heightSegments, e.phiStart, e.phiLength, e.thetaStart, e.thetaLength); } -}, wr = class extends an { +}, ic = class s1 extends di { constructor(e = 1, t = 0){ let n = [ 1, @@ -14163,237 +15789,227 @@ var Fi = class extends _e { 3, 1 ]; - super(n, i, e, t); - this.type = "TetrahedronGeometry", this.parameters = { + super(n, i, e, t), this.type = "TetrahedronGeometry", this.parameters = { radius: e, detail: t }; } static fromJSON(e) { - return new wr(e.radius, e.detail); + return new s1(e.radius, e.detail); } -}, Sr = class extends _e { - constructor(e = 1, t = .4, n = 8, i = 6, r = Math.PI * 2){ - super(); - this.type = "TorusGeometry", this.parameters = { +}, sc = class s1 extends Ge { + constructor(e = 1, t = .4, n = 12, i = 48, r = Math.PI * 2){ + super(), this.type = "TorusGeometry", this.parameters = { radius: e, tube: t, radialSegments: n, tubularSegments: i, arc: r }, n = Math.floor(n), i = Math.floor(i); - let o = [], a = [], l = [], c = [], h = new M, u = new M, d = new M; + let a = [], o = [], c = [], l = [], h = new A, u = new A, d = new A; for(let f = 0; f <= n; f++)for(let m = 0; m <= i; m++){ - let x = m / i * r, v = f / n * Math.PI * 2; - u.x = (e + t * Math.cos(v)) * Math.cos(x), u.y = (e + t * Math.cos(v)) * Math.sin(x), u.z = t * Math.sin(v), a.push(u.x, u.y, u.z), h.x = e * Math.cos(x), h.y = e * Math.sin(x), d.subVectors(u, h).normalize(), l.push(d.x, d.y, d.z), c.push(m / i), c.push(f / n); + let _ = m / i * r, g = f / n * Math.PI * 2; + u.x = (e + t * Math.cos(g)) * Math.cos(_), u.y = (e + t * Math.cos(g)) * Math.sin(_), u.z = t * Math.sin(g), o.push(u.x, u.y, u.z), h.x = e * Math.cos(_), h.y = e * Math.sin(_), d.subVectors(u, h).normalize(), c.push(d.x, d.y, d.z), l.push(m / i), l.push(f / n); } for(let f = 1; f <= n; f++)for(let m = 1; m <= i; m++){ - let x = (i + 1) * f + m - 1, v = (i + 1) * (f - 1) + m - 1, g = (i + 1) * (f - 1) + m, p = (i + 1) * f + m; - o.push(x, v, p), o.push(v, g, p); + let _ = (i + 1) * f + m - 1, g = (i + 1) * (f - 1) + m - 1, p = (i + 1) * (f - 1) + m, v = (i + 1) * f + m; + a.push(_, g, v), a.push(g, p, v); } - this.setIndex(o), this.setAttribute("position", new de(a, 3)), this.setAttribute("normal", new de(l, 3)), this.setAttribute("uv", new de(c, 2)); + this.setIndex(a), this.setAttribute("position", new ve(o, 3)), this.setAttribute("normal", new ve(c, 3)), this.setAttribute("uv", new ve(l, 2)); + } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; } static fromJSON(e) { - return new Sr(e.radius, e.tube, e.radialSegments, e.tubularSegments, e.arc); + return new s1(e.radius, e.tube, e.radialSegments, e.tubularSegments, e.arc); } -}, Tr = class extends _e { - constructor(e = 1, t = .4, n = 64, i = 8, r = 2, o = 3){ - super(); - this.type = "TorusKnotGeometry", this.parameters = { +}, rc = class s1 extends Ge { + constructor(e = 1, t = .4, n = 64, i = 8, r = 2, a = 3){ + super(), this.type = "TorusKnotGeometry", this.parameters = { radius: e, tube: t, tubularSegments: n, radialSegments: i, p: r, - q: o + q: a }, n = Math.floor(n), i = Math.floor(i); - let a = [], l = [], c = [], h = [], u = new M, d = new M, f = new M, m = new M, x = new M, v = new M, g = new M; - for(let _ = 0; _ <= n; ++_){ - let y = _ / n * r * Math.PI * 2; - p(y, r, o, e, f), p(y + .01, r, o, e, m), v.subVectors(m, f), g.addVectors(m, f), x.crossVectors(v, g), g.crossVectors(x, v), x.normalize(), g.normalize(); + let o = [], c = [], l = [], h = [], u = new A, d = new A, f = new A, m = new A, _ = new A, g = new A, p = new A; + for(let x = 0; x <= n; ++x){ + let y = x / n * r * Math.PI * 2; + v(y, r, a, e, f), v(y + .01, r, a, e, m), g.subVectors(m, f), p.addVectors(m, f), _.crossVectors(g, p), p.crossVectors(_, g), _.normalize(), p.normalize(); for(let b = 0; b <= i; ++b){ - let A = b / i * Math.PI * 2, L = -t * Math.cos(A), I = t * Math.sin(A); - u.x = f.x + (L * g.x + I * x.x), u.y = f.y + (L * g.y + I * x.y), u.z = f.z + (L * g.z + I * x.z), l.push(u.x, u.y, u.z), d.subVectors(u, f).normalize(), c.push(d.x, d.y, d.z), h.push(_ / n), h.push(b / i); + let w = b / i * Math.PI * 2, R = -t * Math.cos(w), I = t * Math.sin(w); + u.x = f.x + (R * p.x + I * _.x), u.y = f.y + (R * p.y + I * _.y), u.z = f.z + (R * p.z + I * _.z), c.push(u.x, u.y, u.z), d.subVectors(u, f).normalize(), l.push(d.x, d.y, d.z), h.push(x / n), h.push(b / i); } } - for(let _ = 1; _ <= n; _++)for(let y = 1; y <= i; y++){ - let b = (i + 1) * (_ - 1) + (y - 1), A = (i + 1) * _ + (y - 1), L = (i + 1) * _ + y, I = (i + 1) * (_ - 1) + y; - a.push(b, A, I), a.push(A, L, I); + for(let x = 1; x <= n; x++)for(let y = 1; y <= i; y++){ + let b = (i + 1) * (x - 1) + (y - 1), w = (i + 1) * x + (y - 1), R = (i + 1) * x + y, I = (i + 1) * (x - 1) + y; + o.push(b, w, I), o.push(w, R, I); } - this.setIndex(a), this.setAttribute("position", new de(l, 3)), this.setAttribute("normal", new de(c, 3)), this.setAttribute("uv", new de(h, 2)); - function p(_, y, b, A, L) { - let I = Math.cos(_), k = Math.sin(_), B = b / y * _, P = Math.cos(B); - L.x = A * (2 + P) * .5 * I, L.y = A * (2 + P) * k * .5, L.z = A * Math.sin(B) * .5; + this.setIndex(o), this.setAttribute("position", new ve(c, 3)), this.setAttribute("normal", new ve(l, 3)), this.setAttribute("uv", new ve(h, 2)); + function v(x, y, b, w, R) { + let I = Math.cos(x), M = Math.sin(x), T = b / y * x, O = Math.cos(T); + R.x = w * (2 + O) * .5 * I, R.y = w * (2 + O) * M * .5, R.z = w * Math.sin(T) * .5; } } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; + } static fromJSON(e) { - return new Tr(e.radius, e.tube, e.tubularSegments, e.radialSegments, e.p, e.q); + return new s1(e.radius, e.tube, e.tubularSegments, e.radialSegments, e.p, e.q); } -}, Er = class extends _e { - constructor(e = new ho(new M(-1, -1, 0), new M(-1, 1, 0), new M(1, 1, 0)), t = 64, n = 1, i = 8, r = !1){ - super(); - this.type = "TubeGeometry", this.parameters = { +}, ac = class s1 extends Ge { + constructor(e = new aa(new A(-1, -1, 0), new A(-1, 1, 0), new A(1, 1, 0)), t = 64, n = 1, i = 8, r = !1){ + super(), this.type = "TubeGeometry", this.parameters = { path: e, tubularSegments: t, radius: n, radialSegments: i, closed: r }; - let o = e.computeFrenetFrames(t, r); - this.tangents = o.tangents, this.normals = o.normals, this.binormals = o.binormals; - let a = new M, l = new M, c = new X, h = new M, u = [], d = [], f = [], m = []; - x(), this.setIndex(m), this.setAttribute("position", new de(u, 3)), this.setAttribute("normal", new de(d, 3)), this.setAttribute("uv", new de(f, 2)); - function x() { - for(let _ = 0; _ < t; _++)v(_); - v(r === !1 ? t : 0), p(), g(); - } - function v(_) { - h = e.getPointAt(_ / t, h); - let y = o.normals[_], b = o.binormals[_]; - for(let A = 0; A <= i; A++){ - let L = A / i * Math.PI * 2, I = Math.sin(L), k = -Math.cos(L); - l.x = k * y.x + I * b.x, l.y = k * y.y + I * b.y, l.z = k * y.z + I * b.z, l.normalize(), d.push(l.x, l.y, l.z), a.x = h.x + n * l.x, a.y = h.y + n * l.y, a.z = h.z + n * l.z, u.push(a.x, a.y, a.z); + let a = e.computeFrenetFrames(t, r); + this.tangents = a.tangents, this.normals = a.normals, this.binormals = a.binormals; + let o = new A, c = new A, l = new Z, h = new A, u = [], d = [], f = [], m = []; + _(), this.setIndex(m), this.setAttribute("position", new ve(u, 3)), this.setAttribute("normal", new ve(d, 3)), this.setAttribute("uv", new ve(f, 2)); + function _() { + for(let x = 0; x < t; x++)g(x); + g(r === !1 ? t : 0), v(), p(); + } + function g(x) { + h = e.getPointAt(x / t, h); + let y = a.normals[x], b = a.binormals[x]; + for(let w = 0; w <= i; w++){ + let R = w / i * Math.PI * 2, I = Math.sin(R), M = -Math.cos(R); + c.x = M * y.x + I * b.x, c.y = M * y.y + I * b.y, c.z = M * y.z + I * b.z, c.normalize(), d.push(c.x, c.y, c.z), o.x = h.x + n * c.x, o.y = h.y + n * c.y, o.z = h.z + n * c.z, u.push(o.x, o.y, o.z); } } - function g() { - for(let _ = 1; _ <= t; _++)for(let y = 1; y <= i; y++){ - let b = (i + 1) * (_ - 1) + (y - 1), A = (i + 1) * _ + (y - 1), L = (i + 1) * _ + y, I = (i + 1) * (_ - 1) + y; - m.push(b, A, I), m.push(A, L, I); + function p() { + for(let x = 1; x <= t; x++)for(let y = 1; y <= i; y++){ + let b = (i + 1) * (x - 1) + (y - 1), w = (i + 1) * x + (y - 1), R = (i + 1) * x + y, I = (i + 1) * (x - 1) + y; + m.push(b, w, I), m.push(w, R, I); } } - function p() { - for(let _ = 0; _ <= t; _++)for(let y = 0; y <= i; y++)c.x = _ / t, c.y = y / i, f.push(c.x, c.y); + function v() { + for(let x = 0; x <= t; x++)for(let y = 0; y <= i; y++)l.x = x / t, l.y = y / i, f.push(l.x, l.y); } } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; + } toJSON() { let e = super.toJSON(); return e.path = this.parameters.path.toJSON(), e; } static fromJSON(e) { - return new Er(new Ta[e.path.type]().fromJSON(e.path), e.tubularSegments, e.radius, e.radialSegments, e.closed); + return new s1(new ca[e.path.type]().fromJSON(e.path), e.tubularSegments, e.radius, e.radialSegments, e.closed); } -}, Ea = class extends _e { +}, oc = class extends Ge { constructor(e = null){ - super(); - if (this.type = "WireframeGeometry", this.parameters = { + if (super(), this.type = "WireframeGeometry", this.parameters = { geometry: e }, e !== null) { - let t = [], n = new Set, i = new M, r = new M; + let t = [], n = new Set, i = new A, r = new A; if (e.index !== null) { - let o = e.attributes.position, a = e.index, l = e.groups; - l.length === 0 && (l = [ + let a = e.attributes.position, o = e.index, c = e.groups; + c.length === 0 && (c = [ { start: 0, - count: a.count, + count: o.count, materialIndex: 0 } ]); - for(let c = 0, h = l.length; c < h; ++c){ - let u = l[c], d = u.start, f = u.count; - for(let m = d, x = d + f; m < x; m += 3)for(let v = 0; v < 3; v++){ - let g = a.getX(m + v), p = a.getX(m + (v + 1) % 3); - i.fromBufferAttribute(o, g), r.fromBufferAttribute(o, p), yc(i, r, n) === !0 && (t.push(i.x, i.y, i.z), t.push(r.x, r.y, r.z)); + for(let l = 0, h = c.length; l < h; ++l){ + let u = c[l], d = u.start, f = u.count; + for(let m = d, _ = d + f; m < _; m += 3)for(let g = 0; g < 3; g++){ + let p = o.getX(m + g), v = o.getX(m + (g + 1) % 3); + i.fromBufferAttribute(a, p), r.fromBufferAttribute(a, v), su(i, r, n) === !0 && (t.push(i.x, i.y, i.z), t.push(r.x, r.y, r.z)); } } } else { - let o = e.attributes.position; - for(let a = 0, l = o.count / 3; a < l; a++)for(let c = 0; c < 3; c++){ - let h = 3 * a + c, u = 3 * a + (c + 1) % 3; - i.fromBufferAttribute(o, h), r.fromBufferAttribute(o, u), yc(i, r, n) === !0 && (t.push(i.x, i.y, i.z), t.push(r.x, r.y, r.z)); + let a = e.attributes.position; + for(let o = 0, c = a.count / 3; o < c; o++)for(let l = 0; l < 3; l++){ + let h = 3 * o + l, u = 3 * o + (l + 1) % 3; + i.fromBufferAttribute(a, h), r.fromBufferAttribute(a, u), su(i, r, n) === !0 && (t.push(i.x, i.y, i.z), t.push(r.x, r.y, r.z)); } } - this.setAttribute("position", new de(t, 3)); + this.setAttribute("position", new ve(t, 3)); } } + copy(e) { + return super.copy(e), this.parameters = Object.assign({}, e.parameters), this; + } }; -function yc(s, e, t) { - let n = `${s.x},${s.y},${s.z}-${e.x},${e.y},${e.z}`, i = `${e.x},${e.y},${e.z}-${s.x},${s.y},${s.z}`; - return t.has(n) === !0 || t.has(i) === !0 ? !1 : (t.add(n, i), !0); +function su(s1, e, t) { + let n = `${s1.x},${s1.y},${s1.z}-${e.x},${e.y},${e.z}`, i = `${e.x},${e.y},${e.z}-${s1.x},${s1.y},${s1.z}`; + return t.has(n) === !0 || t.has(i) === !0 ? !1 : (t.add(n), t.add(i), !0); } -var vc = Object.freeze({ +var ru = Object.freeze({ __proto__: null, - BoxGeometry: wn, - BoxBufferGeometry: wn, - CircleGeometry: fr, - CircleBufferGeometry: fr, - ConeGeometry: pr, - ConeBufferGeometry: pr, - CylinderGeometry: Jn, - CylinderBufferGeometry: Jn, - DodecahedronGeometry: mr, - DodecahedronBufferGeometry: mr, - EdgesGeometry: _a, - ExtrudeGeometry: ln, - ExtrudeBufferGeometry: ln, - IcosahedronGeometry: _r, - IcosahedronBufferGeometry: _r, - LatheGeometry: Mr, - LatheBufferGeometry: Mr, - OctahedronGeometry: Ii, - OctahedronBufferGeometry: Ii, - PlaneGeometry: Pi, - PlaneBufferGeometry: Pi, - PolyhedronGeometry: an, - PolyhedronBufferGeometry: an, - RingGeometry: br, - RingBufferGeometry: br, - ShapeGeometry: Di, - ShapeBufferGeometry: Di, - SphereGeometry: Fi, - SphereBufferGeometry: Fi, - TetrahedronGeometry: wr, - TetrahedronBufferGeometry: wr, - TorusGeometry: Sr, - TorusBufferGeometry: Sr, - TorusKnotGeometry: Tr, - TorusKnotBufferGeometry: Tr, - TubeGeometry: Er, - TubeBufferGeometry: Er, - WireframeGeometry: Ea -}), Aa = class extends dt { + BoxGeometry: Ji, + CapsuleGeometry: qo, + CircleGeometry: Yo, + ConeGeometry: Zo, + CylinderGeometry: Ns, + DodecahedronGeometry: Jo, + EdgesGeometry: $o, + ExtrudeGeometry: jo, + IcosahedronGeometry: ec, + LatheGeometry: la, + OctahedronGeometry: ha, + PlaneGeometry: $r, + PolyhedronGeometry: di, + RingGeometry: tc, + ShapeGeometry: nc, + SphereGeometry: ua, + TetrahedronGeometry: ic, + TorusGeometry: sc, + TorusKnotGeometry: rc, + TubeGeometry: ac, + WireframeGeometry: oc +}), cc = class extends bt { constructor(e){ - super(); - this.type = "ShadowMaterial", this.color = new ae(0), this.transparent = !0, this.setValues(e); + super(), this.isShadowMaterial = !0, this.type = "ShadowMaterial", this.color = new pe(0), this.transparent = !0, this.fog = !0, this.setValues(e); } copy(e) { - return super.copy(e), this.color.copy(e.color), this; + return super.copy(e), this.color.copy(e.color), this.fog = e.fog, this; } -}; -Aa.prototype.isShadowMaterial = !0; -var po = class extends dt { +}, lc = class extends jt { constructor(e){ - super(); - this.defines = { + super(e), this.isRawShaderMaterial = !0, this.type = "RawShaderMaterial"; + } +}, da = class extends bt { + constructor(e){ + super(), this.isMeshStandardMaterial = !0, this.defines = { STANDARD: "" - }, this.type = "MeshStandardMaterial", this.color = new ae(16777215), this.roughness = 1, this.metalness = 0, this.map = null, this.lightMap = null, this.lightMapIntensity = 1, this.aoMap = null, this.aoMapIntensity = 1, this.emissive = new ae(0), this.emissiveIntensity = 1, this.emissiveMap = null, this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = Hi, this.normalScale = new X(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.roughnessMap = null, this.metalnessMap = null, this.alphaMap = null, this.envMap = null, this.envMapIntensity = 1, this.refractionRatio = .98, this.wireframe = !1, this.wireframeLinewidth = 1, this.wireframeLinecap = "round", this.wireframeLinejoin = "round", this.flatShading = !1, this.setValues(e); + }, this.type = "MeshStandardMaterial", this.color = new pe(16777215), this.roughness = 1, this.metalness = 0, this.map = null, this.lightMap = null, this.lightMapIntensity = 1, this.aoMap = null, this.aoMapIntensity = 1, this.emissive = new pe(0), this.emissiveIntensity = 1, this.emissiveMap = null, this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = mi, this.normalScale = new Z(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.roughnessMap = null, this.metalnessMap = null, this.alphaMap = null, this.envMap = null, this.envMapIntensity = 1, this.wireframe = !1, this.wireframeLinewidth = 1, this.wireframeLinecap = "round", this.wireframeLinejoin = "round", this.flatShading = !1, this.fog = !0, this.setValues(e); } copy(e) { return super.copy(e), this.defines = { STANDARD: "" - }, this.color.copy(e.color), this.roughness = e.roughness, this.metalness = e.metalness, this.map = e.map, this.lightMap = e.lightMap, this.lightMapIntensity = e.lightMapIntensity, this.aoMap = e.aoMap, this.aoMapIntensity = e.aoMapIntensity, this.emissive.copy(e.emissive), this.emissiveMap = e.emissiveMap, this.emissiveIntensity = e.emissiveIntensity, this.bumpMap = e.bumpMap, this.bumpScale = e.bumpScale, this.normalMap = e.normalMap, this.normalMapType = e.normalMapType, this.normalScale.copy(e.normalScale), this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.roughnessMap = e.roughnessMap, this.metalnessMap = e.metalnessMap, this.alphaMap = e.alphaMap, this.envMap = e.envMap, this.envMapIntensity = e.envMapIntensity, this.refractionRatio = e.refractionRatio, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.wireframeLinecap = e.wireframeLinecap, this.wireframeLinejoin = e.wireframeLinejoin, this.flatShading = e.flatShading, this; + }, this.color.copy(e.color), this.roughness = e.roughness, this.metalness = e.metalness, this.map = e.map, this.lightMap = e.lightMap, this.lightMapIntensity = e.lightMapIntensity, this.aoMap = e.aoMap, this.aoMapIntensity = e.aoMapIntensity, this.emissive.copy(e.emissive), this.emissiveMap = e.emissiveMap, this.emissiveIntensity = e.emissiveIntensity, this.bumpMap = e.bumpMap, this.bumpScale = e.bumpScale, this.normalMap = e.normalMap, this.normalMapType = e.normalMapType, this.normalScale.copy(e.normalScale), this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.roughnessMap = e.roughnessMap, this.metalnessMap = e.metalnessMap, this.alphaMap = e.alphaMap, this.envMap = e.envMap, this.envMapIntensity = e.envMapIntensity, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.wireframeLinecap = e.wireframeLinecap, this.wireframeLinejoin = e.wireframeLinejoin, this.flatShading = e.flatShading, this.fog = e.fog, this; } -}; -po.prototype.isMeshStandardMaterial = !0; -var Ca = class extends po { +}, hc = class extends da { constructor(e){ - super(); - this.defines = { + super(), this.isMeshPhysicalMaterial = !0, this.defines = { STANDARD: "", PHYSICAL: "" - }, this.type = "MeshPhysicalMaterial", this.clearcoatMap = null, this.clearcoatRoughness = 0, this.clearcoatRoughnessMap = null, this.clearcoatNormalScale = new X(1, 1), this.clearcoatNormalMap = null, this.ior = 1.5, Object.defineProperty(this, "reflectivity", { + }, this.type = "MeshPhysicalMaterial", this.anisotropyRotation = 0, this.anisotropyMap = null, this.clearcoatMap = null, this.clearcoatRoughness = 0, this.clearcoatRoughnessMap = null, this.clearcoatNormalScale = new Z(1, 1), this.clearcoatNormalMap = null, this.ior = 1.5, Object.defineProperty(this, "reflectivity", { get: function() { - return mt(2.5 * (this.ior - 1) / (this.ior + 1), 0, 1); + return ct(2.5 * (this.ior - 1) / (this.ior + 1), 0, 1); }, set: function(t) { this.ior = (1 + .4 * t) / (1 - .4 * t); } - }), this.sheenColor = new ae(0), this.sheenColorMap = null, this.sheenRoughness = 1, this.sheenRoughnessMap = null, this.transmissionMap = null, this.thickness = 0, this.thicknessMap = null, this.attenuationDistance = 0, this.attenuationColor = new ae(1, 1, 1), this.specularIntensity = 1, this.specularIntensityMap = null, this.specularColor = new ae(1, 1, 1), this.specularColorMap = null, this._sheen = 0, this._clearcoat = 0, this._transmission = 0, this.setValues(e); + }), this.iridescenceMap = null, this.iridescenceIOR = 1.3, this.iridescenceThicknessRange = [ + 100, + 400 + ], this.iridescenceThicknessMap = null, this.sheenColor = new pe(0), this.sheenColorMap = null, this.sheenRoughness = 1, this.sheenRoughnessMap = null, this.transmissionMap = null, this.thickness = 0, this.thicknessMap = null, this.attenuationDistance = 1 / 0, this.attenuationColor = new pe(1, 1, 1), this.specularIntensity = 1, this.specularIntensityMap = null, this.specularColor = new pe(1, 1, 1), this.specularColorMap = null, this._anisotropy = 0, this._clearcoat = 0, this._iridescence = 0, this._sheen = 0, this._transmission = 0, this.setValues(e); } - get sheen() { - return this._sheen; + get anisotropy() { + return this._anisotropy; } - set sheen(e) { - this._sheen > 0 != e > 0 && this.version++, this._sheen = e; + set anisotropy(e) { + this._anisotropy > 0 != e > 0 && this.version++, this._anisotropy = e; } get clearcoat() { return this._clearcoat; @@ -14401,6 +16017,18 @@ var Ca = class extends po { set clearcoat(e) { this._clearcoat > 0 != e > 0 && this.version++, this._clearcoat = e; } + get iridescence() { + return this._iridescence; + } + set iridescence(e) { + this._iridescence > 0 != e > 0 && this.version++, this._iridescence = e; + } + get sheen() { + return this._sheen; + } + set sheen(e) { + this._sheen > 0 != e > 0 && this.version++, this._sheen = e; + } get transmission() { return this._transmission; } @@ -14411,194 +16039,161 @@ var Ca = class extends po { return super.copy(e), this.defines = { STANDARD: "", PHYSICAL: "" - }, this.clearcoat = e.clearcoat, this.clearcoatMap = e.clearcoatMap, this.clearcoatRoughness = e.clearcoatRoughness, this.clearcoatRoughnessMap = e.clearcoatRoughnessMap, this.clearcoatNormalMap = e.clearcoatNormalMap, this.clearcoatNormalScale.copy(e.clearcoatNormalScale), this.ior = e.ior, this.sheen = e.sheen, this.sheenColor.copy(e.sheenColor), this.sheenColorMap = e.sheenColorMap, this.sheenRoughness = e.sheenRoughness, this.sheenRoughnessMap = e.sheenRoughnessMap, this.transmission = e.transmission, this.transmissionMap = e.transmissionMap, this.thickness = e.thickness, this.thicknessMap = e.thicknessMap, this.attenuationDistance = e.attenuationDistance, this.attenuationColor.copy(e.attenuationColor), this.specularIntensity = e.specularIntensity, this.specularIntensityMap = e.specularIntensityMap, this.specularColor.copy(e.specularColor), this.specularColorMap = e.specularColorMap, this; + }, this.anisotropy = e.anisotropy, this.anisotropyRotation = e.anisotropyRotation, this.anisotropyMap = e.anisotropyMap, this.clearcoat = e.clearcoat, this.clearcoatMap = e.clearcoatMap, this.clearcoatRoughness = e.clearcoatRoughness, this.clearcoatRoughnessMap = e.clearcoatRoughnessMap, this.clearcoatNormalMap = e.clearcoatNormalMap, this.clearcoatNormalScale.copy(e.clearcoatNormalScale), this.ior = e.ior, this.iridescence = e.iridescence, this.iridescenceMap = e.iridescenceMap, this.iridescenceIOR = e.iridescenceIOR, this.iridescenceThicknessRange = [ + ...e.iridescenceThicknessRange + ], this.iridescenceThicknessMap = e.iridescenceThicknessMap, this.sheen = e.sheen, this.sheenColor.copy(e.sheenColor), this.sheenColorMap = e.sheenColorMap, this.sheenRoughness = e.sheenRoughness, this.sheenRoughnessMap = e.sheenRoughnessMap, this.transmission = e.transmission, this.transmissionMap = e.transmissionMap, this.thickness = e.thickness, this.thicknessMap = e.thicknessMap, this.attenuationDistance = e.attenuationDistance, this.attenuationColor.copy(e.attenuationColor), this.specularIntensity = e.specularIntensity, this.specularIntensityMap = e.specularIntensityMap, this.specularColor.copy(e.specularColor), this.specularColorMap = e.specularColorMap, this; } -}; -Ca.prototype.isMeshPhysicalMaterial = !0; -var La = class extends dt { +}, uc = class extends bt { constructor(e){ - super(); - this.type = "MeshPhongMaterial", this.color = new ae(16777215), this.specular = new ae(1118481), this.shininess = 30, this.map = null, this.lightMap = null, this.lightMapIntensity = 1, this.aoMap = null, this.aoMapIntensity = 1, this.emissive = new ae(0), this.emissiveIntensity = 1, this.emissiveMap = null, this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = Hi, this.normalScale = new X(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.specularMap = null, this.alphaMap = null, this.envMap = null, this.combine = Vs, this.reflectivity = 1, this.refractionRatio = .98, this.wireframe = !1, this.wireframeLinewidth = 1, this.wireframeLinecap = "round", this.wireframeLinejoin = "round", this.flatShading = !1, this.setValues(e); + super(), this.isMeshPhongMaterial = !0, this.type = "MeshPhongMaterial", this.color = new pe(16777215), this.specular = new pe(1118481), this.shininess = 30, this.map = null, this.lightMap = null, this.lightMapIntensity = 1, this.aoMap = null, this.aoMapIntensity = 1, this.emissive = new pe(0), this.emissiveIntensity = 1, this.emissiveMap = null, this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = mi, this.normalScale = new Z(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.specularMap = null, this.alphaMap = null, this.envMap = null, this.combine = xa, this.reflectivity = 1, this.refractionRatio = .98, this.wireframe = !1, this.wireframeLinewidth = 1, this.wireframeLinecap = "round", this.wireframeLinejoin = "round", this.flatShading = !1, this.fog = !0, this.setValues(e); } copy(e) { - return super.copy(e), this.color.copy(e.color), this.specular.copy(e.specular), this.shininess = e.shininess, this.map = e.map, this.lightMap = e.lightMap, this.lightMapIntensity = e.lightMapIntensity, this.aoMap = e.aoMap, this.aoMapIntensity = e.aoMapIntensity, this.emissive.copy(e.emissive), this.emissiveMap = e.emissiveMap, this.emissiveIntensity = e.emissiveIntensity, this.bumpMap = e.bumpMap, this.bumpScale = e.bumpScale, this.normalMap = e.normalMap, this.normalMapType = e.normalMapType, this.normalScale.copy(e.normalScale), this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.specularMap = e.specularMap, this.alphaMap = e.alphaMap, this.envMap = e.envMap, this.combine = e.combine, this.reflectivity = e.reflectivity, this.refractionRatio = e.refractionRatio, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.wireframeLinecap = e.wireframeLinecap, this.wireframeLinejoin = e.wireframeLinejoin, this.flatShading = e.flatShading, this; + return super.copy(e), this.color.copy(e.color), this.specular.copy(e.specular), this.shininess = e.shininess, this.map = e.map, this.lightMap = e.lightMap, this.lightMapIntensity = e.lightMapIntensity, this.aoMap = e.aoMap, this.aoMapIntensity = e.aoMapIntensity, this.emissive.copy(e.emissive), this.emissiveMap = e.emissiveMap, this.emissiveIntensity = e.emissiveIntensity, this.bumpMap = e.bumpMap, this.bumpScale = e.bumpScale, this.normalMap = e.normalMap, this.normalMapType = e.normalMapType, this.normalScale.copy(e.normalScale), this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.specularMap = e.specularMap, this.alphaMap = e.alphaMap, this.envMap = e.envMap, this.combine = e.combine, this.reflectivity = e.reflectivity, this.refractionRatio = e.refractionRatio, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.wireframeLinecap = e.wireframeLinecap, this.wireframeLinejoin = e.wireframeLinejoin, this.flatShading = e.flatShading, this.fog = e.fog, this; } -}; -La.prototype.isMeshPhongMaterial = !0; -var Ra = class extends dt { +}, dc = class extends bt { constructor(e){ - super(); - this.defines = { + super(), this.isMeshToonMaterial = !0, this.defines = { TOON: "" - }, this.type = "MeshToonMaterial", this.color = new ae(16777215), this.map = null, this.gradientMap = null, this.lightMap = null, this.lightMapIntensity = 1, this.aoMap = null, this.aoMapIntensity = 1, this.emissive = new ae(0), this.emissiveIntensity = 1, this.emissiveMap = null, this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = Hi, this.normalScale = new X(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.alphaMap = null, this.wireframe = !1, this.wireframeLinewidth = 1, this.wireframeLinecap = "round", this.wireframeLinejoin = "round", this.setValues(e); + }, this.type = "MeshToonMaterial", this.color = new pe(16777215), this.map = null, this.gradientMap = null, this.lightMap = null, this.lightMapIntensity = 1, this.aoMap = null, this.aoMapIntensity = 1, this.emissive = new pe(0), this.emissiveIntensity = 1, this.emissiveMap = null, this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = mi, this.normalScale = new Z(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.alphaMap = null, this.wireframe = !1, this.wireframeLinewidth = 1, this.wireframeLinecap = "round", this.wireframeLinejoin = "round", this.fog = !0, this.setValues(e); } copy(e) { - return super.copy(e), this.color.copy(e.color), this.map = e.map, this.gradientMap = e.gradientMap, this.lightMap = e.lightMap, this.lightMapIntensity = e.lightMapIntensity, this.aoMap = e.aoMap, this.aoMapIntensity = e.aoMapIntensity, this.emissive.copy(e.emissive), this.emissiveMap = e.emissiveMap, this.emissiveIntensity = e.emissiveIntensity, this.bumpMap = e.bumpMap, this.bumpScale = e.bumpScale, this.normalMap = e.normalMap, this.normalMapType = e.normalMapType, this.normalScale.copy(e.normalScale), this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.alphaMap = e.alphaMap, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.wireframeLinecap = e.wireframeLinecap, this.wireframeLinejoin = e.wireframeLinejoin, this; + return super.copy(e), this.color.copy(e.color), this.map = e.map, this.gradientMap = e.gradientMap, this.lightMap = e.lightMap, this.lightMapIntensity = e.lightMapIntensity, this.aoMap = e.aoMap, this.aoMapIntensity = e.aoMapIntensity, this.emissive.copy(e.emissive), this.emissiveMap = e.emissiveMap, this.emissiveIntensity = e.emissiveIntensity, this.bumpMap = e.bumpMap, this.bumpScale = e.bumpScale, this.normalMap = e.normalMap, this.normalMapType = e.normalMapType, this.normalScale.copy(e.normalScale), this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.alphaMap = e.alphaMap, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.wireframeLinecap = e.wireframeLinecap, this.wireframeLinejoin = e.wireframeLinejoin, this.fog = e.fog, this; } -}; -Ra.prototype.isMeshToonMaterial = !0; -var Pa = class extends dt { +}, fc = class extends bt { constructor(e){ - super(); - this.type = "MeshNormalMaterial", this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = Hi, this.normalScale = new X(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.wireframe = !1, this.wireframeLinewidth = 1, this.fog = !1, this.flatShading = !1, this.setValues(e); + super(), this.isMeshNormalMaterial = !0, this.type = "MeshNormalMaterial", this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = mi, this.normalScale = new Z(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.wireframe = !1, this.wireframeLinewidth = 1, this.flatShading = !1, this.setValues(e); } copy(e) { return super.copy(e), this.bumpMap = e.bumpMap, this.bumpScale = e.bumpScale, this.normalMap = e.normalMap, this.normalMapType = e.normalMapType, this.normalScale.copy(e.normalScale), this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.flatShading = e.flatShading, this; } -}; -Pa.prototype.isMeshNormalMaterial = !0; -var Ia = class extends dt { +}, pc = class extends bt { constructor(e){ - super(); - this.type = "MeshLambertMaterial", this.color = new ae(16777215), this.map = null, this.lightMap = null, this.lightMapIntensity = 1, this.aoMap = null, this.aoMapIntensity = 1, this.emissive = new ae(0), this.emissiveIntensity = 1, this.emissiveMap = null, this.specularMap = null, this.alphaMap = null, this.envMap = null, this.combine = Vs, this.reflectivity = 1, this.refractionRatio = .98, this.wireframe = !1, this.wireframeLinewidth = 1, this.wireframeLinecap = "round", this.wireframeLinejoin = "round", this.setValues(e); + super(), this.isMeshLambertMaterial = !0, this.type = "MeshLambertMaterial", this.color = new pe(16777215), this.map = null, this.lightMap = null, this.lightMapIntensity = 1, this.aoMap = null, this.aoMapIntensity = 1, this.emissive = new pe(0), this.emissiveIntensity = 1, this.emissiveMap = null, this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = mi, this.normalScale = new Z(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.specularMap = null, this.alphaMap = null, this.envMap = null, this.combine = xa, this.reflectivity = 1, this.refractionRatio = .98, this.wireframe = !1, this.wireframeLinewidth = 1, this.wireframeLinecap = "round", this.wireframeLinejoin = "round", this.flatShading = !1, this.fog = !0, this.setValues(e); } copy(e) { - return super.copy(e), this.color.copy(e.color), this.map = e.map, this.lightMap = e.lightMap, this.lightMapIntensity = e.lightMapIntensity, this.aoMap = e.aoMap, this.aoMapIntensity = e.aoMapIntensity, this.emissive.copy(e.emissive), this.emissiveMap = e.emissiveMap, this.emissiveIntensity = e.emissiveIntensity, this.specularMap = e.specularMap, this.alphaMap = e.alphaMap, this.envMap = e.envMap, this.combine = e.combine, this.reflectivity = e.reflectivity, this.refractionRatio = e.refractionRatio, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.wireframeLinecap = e.wireframeLinecap, this.wireframeLinejoin = e.wireframeLinejoin, this; + return super.copy(e), this.color.copy(e.color), this.map = e.map, this.lightMap = e.lightMap, this.lightMapIntensity = e.lightMapIntensity, this.aoMap = e.aoMap, this.aoMapIntensity = e.aoMapIntensity, this.emissive.copy(e.emissive), this.emissiveMap = e.emissiveMap, this.emissiveIntensity = e.emissiveIntensity, this.bumpMap = e.bumpMap, this.bumpScale = e.bumpScale, this.normalMap = e.normalMap, this.normalMapType = e.normalMapType, this.normalScale.copy(e.normalScale), this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.specularMap = e.specularMap, this.alphaMap = e.alphaMap, this.envMap = e.envMap, this.combine = e.combine, this.reflectivity = e.reflectivity, this.refractionRatio = e.refractionRatio, this.wireframe = e.wireframe, this.wireframeLinewidth = e.wireframeLinewidth, this.wireframeLinecap = e.wireframeLinecap, this.wireframeLinejoin = e.wireframeLinejoin, this.flatShading = e.flatShading, this.fog = e.fog, this; } -}; -Ia.prototype.isMeshLambertMaterial = !0; -var Da = class extends dt { +}, mc = class extends bt { constructor(e){ - super(); - this.defines = { + super(), this.isMeshMatcapMaterial = !0, this.defines = { MATCAP: "" - }, this.type = "MeshMatcapMaterial", this.color = new ae(16777215), this.matcap = null, this.map = null, this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = Hi, this.normalScale = new X(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.alphaMap = null, this.flatShading = !1, this.setValues(e); + }, this.type = "MeshMatcapMaterial", this.color = new pe(16777215), this.matcap = null, this.map = null, this.bumpMap = null, this.bumpScale = 1, this.normalMap = null, this.normalMapType = mi, this.normalScale = new Z(1, 1), this.displacementMap = null, this.displacementScale = 1, this.displacementBias = 0, this.alphaMap = null, this.flatShading = !1, this.fog = !0, this.setValues(e); } copy(e) { return super.copy(e), this.defines = { MATCAP: "" - }, this.color.copy(e.color), this.matcap = e.matcap, this.map = e.map, this.bumpMap = e.bumpMap, this.bumpScale = e.bumpScale, this.normalMap = e.normalMap, this.normalMapType = e.normalMapType, this.normalScale.copy(e.normalScale), this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.alphaMap = e.alphaMap, this.flatShading = e.flatShading, this; + }, this.color.copy(e.color), this.matcap = e.matcap, this.map = e.map, this.bumpMap = e.bumpMap, this.bumpScale = e.bumpScale, this.normalMap = e.normalMap, this.normalMapType = e.normalMapType, this.normalScale.copy(e.normalScale), this.displacementMap = e.displacementMap, this.displacementScale = e.displacementScale, this.displacementBias = e.displacementBias, this.alphaMap = e.alphaMap, this.flatShading = e.flatShading, this.fog = e.fog, this; } -}; -Da.prototype.isMeshMatcapMaterial = !0; -var Fa = class extends ft { +}, gc = class extends wt { constructor(e){ - super(); - this.type = "LineDashedMaterial", this.scale = 1, this.dashSize = 3, this.gapSize = 1, this.setValues(e); + super(), this.isLineDashedMaterial = !0, this.type = "LineDashedMaterial", this.scale = 1, this.dashSize = 3, this.gapSize = 1, this.setValues(e); } copy(e) { return super.copy(e), this.scale = e.scale, this.dashSize = e.dashSize, this.gapSize = e.gapSize, this; } }; -Fa.prototype.isLineDashedMaterial = !0; -var sy = Object.freeze({ - __proto__: null, - ShadowMaterial: Aa, - SpriteMaterial: io, - RawShaderMaterial: Gi, - ShaderMaterial: sn, - PointsMaterial: jn, - MeshPhysicalMaterial: Ca, - MeshStandardMaterial: po, - MeshPhongMaterial: La, - MeshToonMaterial: Ra, - MeshNormalMaterial: Pa, - MeshLambertMaterial: Ia, - MeshDepthMaterial: eo, - MeshDistanceMaterial: to, - MeshBasicMaterial: hn, - MeshMatcapMaterial: Da, - LineDashedMaterial: Fa, - LineBasicMaterial: ft, - Material: dt -}), Ze = { - arraySlice: function(s, e, t) { - return Ze.isTypedArray(s) ? new s.constructor(s.subarray(e, t !== void 0 ? t : s.length)) : s.slice(e, t); - }, - convertArray: function(s, e, t) { - return !s || !t && s.constructor === e ? s : typeof e.BYTES_PER_ELEMENT == "number" ? new e(s) : Array.prototype.slice.call(s); - }, - isTypedArray: function(s) { - return ArrayBuffer.isView(s) && !(s instanceof DataView); - }, - getKeyframeOrder: function(s) { - function e(i, r) { - return s[i] - s[r]; - } - let t = s.length, n = new Array(t); - for(let i = 0; i !== t; ++i)n[i] = i; - return n.sort(e), n; - }, - sortedArray: function(s, e, t) { - let n = s.length, i = new s.constructor(n); - for(let r = 0, o = 0; o !== n; ++r){ - let a = t[r] * e; - for(let l = 0; l !== e; ++l)i[o++] = s[a + l]; - } - return i; - }, - flattenJSON: function(s, e, t, n) { - let i = 1, r = s[0]; - for(; r !== void 0 && r[n] === void 0;)r = s[i++]; - if (r === void 0) return; - let o = r[n]; - if (o !== void 0) if (Array.isArray(o)) do o = r[n], o !== void 0 && (e.push(r.time), t.push.apply(t, o)), r = s[i++]; - while (r !== void 0) - else if (o.toArray !== void 0) do o = r[n], o !== void 0 && (e.push(r.time), o.toArray(t, t.length)), r = s[i++]; - while (r !== void 0) - else do o = r[n], o !== void 0 && (e.push(r.time), t.push(o)), r = s[i++]; - while (r !== void 0) - }, - subclip: function(s, e, t, n, i = 30) { - let r = s.clone(); - r.name = e; - let o = []; - for(let l = 0; l < r.tracks.length; ++l){ - let c = r.tracks[l], h = c.getValueSize(), u = [], d = []; - for(let f = 0; f < c.times.length; ++f){ - let m = c.times[f] * i; - if (!(m < t || m >= n)) { - u.push(c.times[f]); - for(let x = 0; x < h; ++x)d.push(c.values[f * h + x]); - } +function ni(s1, e, t) { + return !s1 || !t && s1.constructor === e ? s1 : typeof e.BYTES_PER_ELEMENT == "number" ? new e(s1) : Array.prototype.slice.call(s1); +} +function Ud(s1) { + return ArrayBuffer.isView(s1) && !(s1 instanceof DataView); +} +function Dd(s1) { + function e(i, r) { + return s1[i] - s1[r]; + } + let t = s1.length, n = new Array(t); + for(let i = 0; i !== t; ++i)n[i] = i; + return n.sort(e), n; +} +function _c(s1, e, t) { + let n = s1.length, i = new s1.constructor(n); + for(let r = 0, a = 0; a !== n; ++r){ + let o = t[r] * e; + for(let c = 0; c !== e; ++c)i[a++] = s1[o + c]; + } + return i; +} +function $c(s1, e, t, n) { + let i = 1, r = s1[0]; + for(; r !== void 0 && r[n] === void 0;)r = s1[i++]; + if (r === void 0) return; + let a = r[n]; + if (a !== void 0) if (Array.isArray(a)) do a = r[n], a !== void 0 && (e.push(r.time), t.push.apply(t, a)), r = s1[i++]; + while (r !== void 0) + else if (a.toArray !== void 0) do a = r[n], a !== void 0 && (e.push(r.time), a.toArray(t, t.length)), r = s1[i++]; + while (r !== void 0) + else do a = r[n], a !== void 0 && (e.push(r.time), t.push(a)), r = s1[i++]; + while (r !== void 0) +} +function yx(s1, e, t, n, i = 30) { + let r = s1.clone(); + r.name = e; + let a = []; + for(let c = 0; c < r.tracks.length; ++c){ + let l = r.tracks[c], h = l.getValueSize(), u = [], d = []; + for(let f = 0; f < l.times.length; ++f){ + let m = l.times[f] * i; + if (!(m < t || m >= n)) { + u.push(l.times[f]); + for(let _ = 0; _ < h; ++_)d.push(l.values[f * h + _]); } - u.length !== 0 && (c.times = Ze.convertArray(u, c.times.constructor), c.values = Ze.convertArray(d, c.values.constructor), o.push(c)); } - r.tracks = o; - let a = 1 / 0; - for(let l = 0; l < r.tracks.length; ++l)a > r.tracks[l].times[0] && (a = r.tracks[l].times[0]); - for(let l = 0; l < r.tracks.length; ++l)r.tracks[l].shift(-1 * a); - return r.resetDuration(), r; - }, - makeClipAdditive: function(s, e = 0, t = s, n = 30) { - n <= 0 && (n = 30); - let i = t.tracks.length, r = e / n; - for(let o = 0; o < i; ++o){ - let a = t.tracks[o], l = a.ValueTypeName; - if (l === "bool" || l === "string") continue; - let c = s.tracks.find(function(g) { - return g.name === a.name && g.ValueTypeName === l; - }); - if (c === void 0) continue; - let h = 0, u = a.getValueSize(); - a.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline && (h = u / 3); - let d = 0, f = c.getValueSize(); - c.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline && (d = f / 3); - let m = a.times.length - 1, x; - if (r <= a.times[0]) { - let g = h, p = u - h; - x = Ze.arraySlice(a.values, g, p); - } else if (r >= a.times[m]) { - let g = m * u + h, p = g + u - h; - x = Ze.arraySlice(a.values, g, p); - } else { - let g = a.createInterpolant(), p = h, _ = u - h; - g.evaluate(r), x = Ze.arraySlice(g.resultBuffer, p, _); - } - l === "quaternion" && new gt().fromArray(x).normalize().conjugate().toArray(x); - let v = c.times.length; - for(let g = 0; g < v; ++g){ - let p = g * f + d; - if (l === "quaternion") gt.multiplyQuaternionsFlat(c.values, p, x, 0, c.values, p); - else { - let _ = f - d * 2; - for(let y = 0; y < _; ++y)c.values[p + y] -= x[y]; - } + u.length !== 0 && (l.times = ni(u, l.times.constructor), l.values = ni(d, l.values.constructor), a.push(l)); + } + r.tracks = a; + let o = 1 / 0; + for(let c = 0; c < r.tracks.length; ++c)o > r.tracks[c].times[0] && (o = r.tracks[c].times[0]); + for(let c = 0; c < r.tracks.length; ++c)r.tracks[c].shift(-1 * o); + return r.resetDuration(), r; +} +function Mx(s1, e = 0, t = s1, n = 30) { + n <= 0 && (n = 30); + let i = t.tracks.length, r = e / n; + for(let a = 0; a < i; ++a){ + let o = t.tracks[a], c = o.ValueTypeName; + if (c === "bool" || c === "string") continue; + let l = s1.tracks.find(function(p) { + return p.name === o.name && p.ValueTypeName === c; + }); + if (l === void 0) continue; + let h = 0, u = o.getValueSize(); + o.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline && (h = u / 3); + let d = 0, f = l.getValueSize(); + l.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline && (d = f / 3); + let m = o.times.length - 1, _; + if (r <= o.times[0]) { + let p = h, v = u - h; + _ = o.values.slice(p, v); + } else if (r >= o.times[m]) { + let p = m * u + h, v = p + u - h; + _ = o.values.slice(p, v); + } else { + let p = o.createInterpolant(), v = h, x = u - h; + p.evaluate(r), _ = p.resultBuffer.slice(v, x); + } + c === "quaternion" && new Ut().fromArray(_).normalize().conjugate().toArray(_); + let g = l.times.length; + for(let p = 0; p < g; ++p){ + let v = p * f + d; + if (c === "quaternion") Ut.multiplyQuaternionsFlat(l.values, v, _, 0, l.values, v); + else { + let x = f - d * 2; + for(let y = 0; y < x; ++y)l.values[v + y] -= _[y]; } } - return s.blendMode = qc, s; } -}, cn = class { + return s1.blendMode = xd, s1; +} +var Sv = { + convertArray: ni, + isTypedArray: Ud, + getKeyframeOrder: Dd, + sortedArray: _c, + flattenJSON: $c, + subclip: yx, + makeClipAdditive: Mx +}, es = class { constructor(e, t, n, i){ this.parameterPositions = e, this._cachedIndex = 0, this.resultBuffer = i !== void 0 ? i : new t.constructor(n), this.sampleValues = t, this.valueSize = n, this.settings = null, this.DefaultSettings_ = {}; } @@ -14606,39 +16201,39 @@ var sy = Object.freeze({ let t = this.parameterPositions, n = this._cachedIndex, i = t[n], r = t[n - 1]; e: { t: { - let o; + let a; n: { i: if (!(e < i)) { - for(let a = n + 2;;){ + for(let o = n + 2;;){ if (i === void 0) { if (e < r) break i; - return n = t.length, this._cachedIndex = n, this.afterEnd_(n - 1, e, r); + return n = t.length, this._cachedIndex = n, this.copySampleValue_(n - 1); } - if (n === a) break; + if (n === o) break; if (r = i, i = t[++n], e < i) break t; } - o = t.length; + a = t.length; break n; } if (!(e >= r)) { - let a = t[1]; - e < a && (n = 2, r = a); - for(let l = n - 2;;){ - if (r === void 0) return this._cachedIndex = 0, this.beforeStart_(0, e, i); - if (n === l) break; + let o = t[1]; + e < o && (n = 2, r = o); + for(let c = n - 2;;){ + if (r === void 0) return this._cachedIndex = 0, this.copySampleValue_(0); + if (n === c) break; if (i = r, r = t[--n - 1], e >= r) break t; } - o = n, n = 0; + a = n, n = 0; break n; } break e; } - for(; n < o;){ - let a = n + o >>> 1; - e < t[a] ? o = a : n = a + 1; + for(; n < a;){ + let o = n + a >>> 1; + e < t[o] ? a = o : n = o + 1; } - if (i = t[n], r = t[n - 1], r === void 0) return this._cachedIndex = 0, this.beforeStart_(0, e, i); - if (i === void 0) return n = t.length, this._cachedIndex = n, this.afterEnd_(n - 1, r, e); + if (i = t[n], r = t[n - 1], r === void 0) return this._cachedIndex = 0, this.copySampleValue_(0); + if (i === void 0) return n = t.length, this._cachedIndex = n, this.copySampleValue_(n - 1); } this._cachedIndex = n, this.intervalChanged_(n, r, i); } @@ -14649,75 +16244,71 @@ var sy = Object.freeze({ } copySampleValue_(e) { let t = this.resultBuffer, n = this.sampleValues, i = this.valueSize, r = e * i; - for(let o = 0; o !== i; ++o)t[o] = n[r + o]; + for(let a = 0; a !== i; ++a)t[a] = n[r + a]; return t; } interpolate_() { throw new Error("call to abstract method"); } intervalChanged_() {} -}; -cn.prototype.beforeStart_ = cn.prototype.copySampleValue_; -cn.prototype.afterEnd_ = cn.prototype.copySampleValue_; -var Ph = class extends cn { +}, xc = class extends es { constructor(e, t, n, i){ - super(e, t, n, i); - this._weightPrev = -0, this._offsetPrev = -0, this._weightNext = -0, this._offsetNext = -0, this.DefaultSettings_ = { - endingStart: Mi, - endingEnd: Mi + super(e, t, n, i), this._weightPrev = -0, this._offsetPrev = -0, this._weightNext = -0, this._offsetNext = -0, this.DefaultSettings_ = { + endingStart: zi, + endingEnd: zi }; } intervalChanged_(e, t, n) { - let i = this.parameterPositions, r = e - 2, o = e + 1, a = i[r], l = i[o]; - if (a === void 0) switch(this.getSettings_().endingStart){ - case bi: - r = e, a = 2 * t - n; + let i = this.parameterPositions, r = e - 2, a = e + 1, o = i[r], c = i[a]; + if (o === void 0) switch(this.getSettings_().endingStart){ + case Vi: + r = e, o = 2 * t - n; break; - case Os: - r = i.length - 2, a = t + i[r] - i[r + 1]; + case Br: + r = i.length - 2, o = t + i[r] - i[r + 1]; break; default: - r = e, a = n; + r = e, o = n; } - if (l === void 0) switch(this.getSettings_().endingEnd){ - case bi: - o = e, l = 2 * n - t; + if (c === void 0) switch(this.getSettings_().endingEnd){ + case Vi: + a = e, c = 2 * n - t; break; - case Os: - o = 1, l = n + i[1] - i[0]; + case Br: + a = 1, c = n + i[1] - i[0]; break; default: - o = e - 1, l = t; + a = e - 1, c = t; } - let c = (n - t) * .5, h = this.valueSize; - this._weightPrev = c / (t - a), this._weightNext = c / (l - n), this._offsetPrev = r * h, this._offsetNext = o * h; + let l = (n - t) * .5, h = this.valueSize; + this._weightPrev = l / (t - o), this._weightNext = l / (c - n), this._offsetPrev = r * h, this._offsetNext = a * h; } interpolate_(e, t, n, i) { - let r = this.resultBuffer, o = this.sampleValues, a = this.valueSize, l = e * a, c = l - a, h = this._offsetPrev, u = this._offsetNext, d = this._weightPrev, f = this._weightNext, m = (n - t) / (i - t), x = m * m, v = x * m, g = -d * v + 2 * d * x - d * m, p = (1 + d) * v + (-1.5 - 2 * d) * x + (-.5 + d) * m + 1, _ = (-1 - f) * v + (1.5 + f) * x + .5 * m, y = f * v - f * x; - for(let b = 0; b !== a; ++b)r[b] = g * o[h + b] + p * o[c + b] + _ * o[l + b] + y * o[u + b]; + let r = this.resultBuffer, a = this.sampleValues, o = this.valueSize, c = e * o, l = c - o, h = this._offsetPrev, u = this._offsetNext, d = this._weightPrev, f = this._weightNext, m = (n - t) / (i - t), _ = m * m, g = _ * m, p = -d * g + 2 * d * _ - d * m, v = (1 + d) * g + (-1.5 - 2 * d) * _ + (-.5 + d) * m + 1, x = (-1 - f) * g + (1.5 + f) * _ + .5 * m, y = f * g - f * _; + for(let b = 0; b !== o; ++b)r[b] = p * a[h + b] + v * a[l + b] + x * a[c + b] + y * a[u + b]; return r; } -}, Na = class extends cn { +}, fa = class extends es { constructor(e, t, n, i){ super(e, t, n, i); } interpolate_(e, t, n, i) { - let r = this.resultBuffer, o = this.sampleValues, a = this.valueSize, l = e * a, c = l - a, h = (n - t) / (i - t), u = 1 - h; - for(let d = 0; d !== a; ++d)r[d] = o[c + d] * u + o[l + d] * h; + let r = this.resultBuffer, a = this.sampleValues, o = this.valueSize, c = e * o, l = c - o, h = (n - t) / (i - t), u = 1 - h; + for(let d = 0; d !== o; ++d)r[d] = a[l + d] * u + a[c + d] * h; return r; } -}, Ih = class extends cn { +}, vc = class extends es { constructor(e, t, n, i){ super(e, t, n, i); } interpolate_(e) { return this.copySampleValue_(e - 1); } -}, zt = class { +}, Jt = class { constructor(e, t, n, i){ if (e === void 0) throw new Error("THREE.KeyframeTrack: track name is undefined"); if (t === void 0 || t.length === 0) throw new Error("THREE.KeyframeTrack: no keyframes in track named " + e); - this.name = e, this.times = Ze.convertArray(t, this.TimeBufferType), this.values = Ze.convertArray(n, this.ValueBufferType), this.setInterpolation(i || this.DefaultInterpolation); + this.name = e, this.times = ni(t, this.TimeBufferType), this.values = ni(n, this.ValueBufferType), this.setInterpolation(i || this.DefaultInterpolation); } static toJSON(e) { let t = e.constructor, n; @@ -14725,8 +16316,8 @@ var Ph = class extends cn { else { n = { name: e.name, - times: Ze.convertArray(e.times, Array), - values: Ze.convertArray(e.values, Array) + times: ni(e.times, Array), + values: ni(e.values, Array) }; let i = e.getInterpolation(); i !== e.DefaultInterpolation && (n.interpolation = i); @@ -14734,24 +16325,24 @@ var Ph = class extends cn { return n.type = e.ValueTypeName, n; } InterpolantFactoryMethodDiscrete(e) { - return new Ih(this.times, this.values, this.getValueSize(), e); + return new vc(this.times, this.values, this.getValueSize(), e); } InterpolantFactoryMethodLinear(e) { - return new Na(this.times, this.values, this.getValueSize(), e); + return new fa(this.times, this.values, this.getValueSize(), e); } InterpolantFactoryMethodSmooth(e) { - return new Ph(this.times, this.values, this.getValueSize(), e); + return new xc(this.times, this.values, this.getValueSize(), e); } setInterpolation(e) { let t; switch(e){ - case zs: + case Or: t = this.InterpolantFactoryMethodDiscrete; break; - case Us: + case Fr: t = this.InterpolantFactoryMethodLinear; break; - case yo: + case La: t = this.InterpolantFactoryMethodSmooth; break; } @@ -14766,11 +16357,11 @@ var Ph = class extends cn { getInterpolation() { switch(this.createInterpolant){ case this.InterpolantFactoryMethodDiscrete: - return zs; + return Or; case this.InterpolantFactoryMethodLinear: - return Us; + return Fr; case this.InterpolantFactoryMethodSmooth: - return yo; + return La; } } getValueSize() { @@ -14791,13 +16382,13 @@ var Ph = class extends cn { return this; } trim(e, t) { - let n = this.times, i = n.length, r = 0, o = i - 1; + let n = this.times, i = n.length, r = 0, a = i - 1; for(; r !== i && n[r] < e;)++r; - for(; o !== -1 && n[o] > t;)--o; - if (++o, r !== 0 || o !== i) { - r >= o && (o = Math.max(o, 1), r = o - 1); - let a = this.getValueSize(); - this.times = Ze.arraySlice(n, r, o), this.values = Ze.arraySlice(this.values, r * a, o * a); + for(; a !== -1 && n[a] > t;)--a; + if (++a, r !== 0 || a !== i) { + r >= a && (a = Math.max(a, 1), r = a - 1); + let o = this.getValueSize(); + this.times = n.slice(r, a), this.values = this.values.slice(r * o, a * o); } return this; } @@ -14806,114 +16397,114 @@ var Ph = class extends cn { t - Math.floor(t) !== 0 && (console.error("THREE.KeyframeTrack: Invalid value size in track.", this), e = !1); let n = this.times, i = this.values, r = n.length; r === 0 && (console.error("THREE.KeyframeTrack: Track is empty.", this), e = !1); - let o = null; - for(let a = 0; a !== r; a++){ - let l = n[a]; - if (typeof l == "number" && isNaN(l)) { - console.error("THREE.KeyframeTrack: Time is not a valid number.", this, a, l), e = !1; + let a = null; + for(let o = 0; o !== r; o++){ + let c = n[o]; + if (typeof c == "number" && isNaN(c)) { + console.error("THREE.KeyframeTrack: Time is not a valid number.", this, o, c), e = !1; break; } - if (o !== null && o > l) { - console.error("THREE.KeyframeTrack: Out of order keys.", this, a, l, o), e = !1; + if (a !== null && a > c) { + console.error("THREE.KeyframeTrack: Out of order keys.", this, o, c, a), e = !1; break; } - o = l; + a = c; } - if (i !== void 0 && Ze.isTypedArray(i)) for(let a = 0, l = i.length; a !== l; ++a){ - let c = i[a]; - if (isNaN(c)) { - console.error("THREE.KeyframeTrack: Value is not a valid number.", this, a, c), e = !1; + if (i !== void 0 && Ud(i)) for(let o = 0, c = i.length; o !== c; ++o){ + let l = i[o]; + if (isNaN(l)) { + console.error("THREE.KeyframeTrack: Value is not a valid number.", this, o, l), e = !1; break; } } return e; } optimize() { - let e = Ze.arraySlice(this.times), t = Ze.arraySlice(this.values), n = this.getValueSize(), i = this.getInterpolation() === yo, r = e.length - 1, o = 1; - for(let a = 1; a < r; ++a){ - let l = !1, c = e[a], h = e[a + 1]; - if (c !== h && (a !== 1 || c !== e[0])) if (i) l = !0; + let e = this.times.slice(), t = this.values.slice(), n = this.getValueSize(), i = this.getInterpolation() === La, r = e.length - 1, a = 1; + for(let o = 1; o < r; ++o){ + let c = !1, l = e[o], h = e[o + 1]; + if (l !== h && (o !== 1 || l !== e[0])) if (i) c = !0; else { - let u = a * n, d = u - n, f = u + n; + let u = o * n, d = u - n, f = u + n; for(let m = 0; m !== n; ++m){ - let x = t[u + m]; - if (x !== t[d + m] || x !== t[f + m]) { - l = !0; + let _ = t[u + m]; + if (_ !== t[d + m] || _ !== t[f + m]) { + c = !0; break; } } } - if (l) { - if (a !== o) { - e[o] = e[a]; - let u = a * n, d = o * n; + if (c) { + if (o !== a) { + e[a] = e[o]; + let u = o * n, d = a * n; for(let f = 0; f !== n; ++f)t[d + f] = t[u + f]; } - ++o; + ++a; } } if (r > 0) { - e[o] = e[r]; - for(let a = r * n, l = o * n, c = 0; c !== n; ++c)t[l + c] = t[a + c]; - ++o; + e[a] = e[r]; + for(let o = r * n, c = a * n, l = 0; l !== n; ++l)t[c + l] = t[o + l]; + ++a; } - return o !== e.length ? (this.times = Ze.arraySlice(e, 0, o), this.values = Ze.arraySlice(t, 0, o * n)) : (this.times = e, this.values = t), this; + return a !== e.length ? (this.times = e.slice(0, a), this.values = t.slice(0, a * n)) : (this.times = e, this.values = t), this; } clone() { - let e = Ze.arraySlice(this.times, 0), t = Ze.arraySlice(this.values, 0), n = this.constructor, i = new n(this.name, e, t); + let e = this.times.slice(), t = this.values.slice(), n = this.constructor, i = new n(this.name, e, t); return i.createInterpolant = this.createInterpolant, i; } }; -zt.prototype.TimeBufferType = Float32Array; -zt.prototype.ValueBufferType = Float32Array; -zt.prototype.DefaultInterpolation = Us; -var Qn = class extends zt { +Jt.prototype.TimeBufferType = Float32Array; +Jt.prototype.ValueBufferType = Float32Array; +Jt.prototype.DefaultInterpolation = Fr; +var Vn = class extends Jt { }; -Qn.prototype.ValueTypeName = "bool"; -Qn.prototype.ValueBufferType = Array; -Qn.prototype.DefaultInterpolation = zs; -Qn.prototype.InterpolantFactoryMethodLinear = void 0; -Qn.prototype.InterpolantFactoryMethodSmooth = void 0; -var Ba = class extends zt { +Vn.prototype.ValueTypeName = "bool"; +Vn.prototype.ValueBufferType = Array; +Vn.prototype.DefaultInterpolation = Or; +Vn.prototype.InterpolantFactoryMethodLinear = void 0; +Vn.prototype.InterpolantFactoryMethodSmooth = void 0; +var pa = class extends Jt { }; -Ba.prototype.ValueTypeName = "color"; -var Ar = class extends zt { +pa.prototype.ValueTypeName = "color"; +var ts = class extends Jt { }; -Ar.prototype.ValueTypeName = "number"; -var Dh = class extends cn { +ts.prototype.ValueTypeName = "number"; +var yc = class extends es { constructor(e, t, n, i){ super(e, t, n, i); } interpolate_(e, t, n, i) { - let r = this.resultBuffer, o = this.sampleValues, a = this.valueSize, l = (n - t) / (i - t), c = e * a; - for(let h = c + a; c !== h; c += 4)gt.slerpFlat(r, 0, o, c - a, o, c, l); + let r = this.resultBuffer, a = this.sampleValues, o = this.valueSize, c = (n - t) / (i - t), l = e * o; + for(let h = l + o; l !== h; l += 4)Ut.slerpFlat(r, 0, a, l - o, a, l, c); return r; } -}, Wi = class extends zt { +}, pi = class extends Jt { InterpolantFactoryMethodLinear(e) { - return new Dh(this.times, this.values, this.getValueSize(), e); + return new yc(this.times, this.values, this.getValueSize(), e); } }; -Wi.prototype.ValueTypeName = "quaternion"; -Wi.prototype.DefaultInterpolation = Us; -Wi.prototype.InterpolantFactoryMethodSmooth = void 0; -var Kn = class extends zt { +pi.prototype.ValueTypeName = "quaternion"; +pi.prototype.DefaultInterpolation = Fr; +pi.prototype.InterpolantFactoryMethodSmooth = void 0; +var kn = class extends Jt { }; -Kn.prototype.ValueTypeName = "string"; -Kn.prototype.ValueBufferType = Array; -Kn.prototype.DefaultInterpolation = zs; -Kn.prototype.InterpolantFactoryMethodLinear = void 0; -Kn.prototype.InterpolantFactoryMethodSmooth = void 0; -var Cr = class extends zt { +kn.prototype.ValueTypeName = "string"; +kn.prototype.ValueBufferType = Array; +kn.prototype.DefaultInterpolation = Or; +kn.prototype.InterpolantFactoryMethodLinear = void 0; +kn.prototype.InterpolantFactoryMethodSmooth = void 0; +var ns = class extends Jt { }; -Cr.prototype.ValueTypeName = "vector"; -var Lr = class { - constructor(e, t = -1, n, i = ua){ - this.name = e, this.tracks = n, this.duration = t, this.blendMode = i, this.uuid = Et(), this.duration < 0 && this.resetDuration(); +ns.prototype.ValueTypeName = "vector"; +var is = class { + constructor(e, t = -1, n, i = Xc){ + this.name = e, this.tracks = n, this.duration = t, this.blendMode = i, this.uuid = kt(), this.duration < 0 && this.resetDuration(); } static parse(e) { let t = [], n = e.tracks, i = 1 / (e.fps || 1); - for(let o = 0, a = n.length; o !== a; ++o)t.push(ay(n[o]).scale(i)); + for(let a = 0, o = n.length; a !== o; ++a)t.push(bx(n[a]).scale(i)); let r = new this(e.name, e.duration, t, e.blendMode); return r.uuid = e.uuid, r; } @@ -14925,18 +16516,18 @@ var Lr = class { uuid: e.uuid, blendMode: e.blendMode }; - for(let r = 0, o = n.length; r !== o; ++r)t.push(zt.toJSON(n[r])); + for(let r = 0, a = n.length; r !== a; ++r)t.push(Jt.toJSON(n[r])); return i; } static CreateFromMorphTargetSequence(e, t, n, i) { - let r = t.length, o = []; - for(let a = 0; a < r; a++){ - let l = [], c = []; - l.push((a + r - 1) % r, a, (a + 1) % r), c.push(0, 1, 0); - let h = Ze.getKeyframeOrder(l); - l = Ze.sortedArray(l, 1, h), c = Ze.sortedArray(c, 1, h), !i && l[0] === 0 && (l.push(r), c.push(c[0])), o.push(new Ar(".morphTargetInfluences[" + t[a].name + "]", l, c).scale(1 / n)); + let r = t.length, a = []; + for(let o = 0; o < r; o++){ + let c = [], l = []; + c.push((o + r - 1) % r, o, (o + 1) % r), l.push(0, 1, 0); + let h = Dd(c); + c = _c(c, 1, h), l = _c(l, 1, h), !i && c[0] === 0 && (c.push(r), l.push(l[0])), a.push(new ts(".morphTargetInfluences[" + t[o].name + "]", c, l).scale(1 / n)); } - return new this(e, -1, o); + return new this(e, -1, a); } static findByName(e, t) { let n = e; @@ -14949,45 +16540,45 @@ var Lr = class { } static CreateClipsFromMorphTargetSequences(e, t, n) { let i = {}, r = /^([\w-]*?)([\d]+)$/; - for(let a = 0, l = e.length; a < l; a++){ - let c = e[a], h = c.name.match(r); + for(let o = 0, c = e.length; o < c; o++){ + let l = e[o], h = l.name.match(r); if (h && h.length > 1) { let u = h[1], d = i[u]; - d || (i[u] = d = []), d.push(c); + d || (i[u] = d = []), d.push(l); } } - let o = []; - for(let a in i)o.push(this.CreateFromMorphTargetSequence(a, i[a], t, n)); - return o; + let a = []; + for(let o in i)a.push(this.CreateFromMorphTargetSequence(o, i[o], t, n)); + return a; } static parseAnimation(e, t) { if (!e) return console.error("THREE.AnimationClip: No animation in JSONLoader data."), null; - let n = function(u, d, f, m, x) { + let n = function(u, d, f, m, _) { if (f.length !== 0) { - let v = [], g = []; - Ze.flattenJSON(f, v, g, m), v.length !== 0 && x.push(new u(d, v, g)); + let g = [], p = []; + $c(f, g, p, m), g.length !== 0 && _.push(new u(d, g, p)); } - }, i = [], r = e.name || "default", o = e.fps || 30, a = e.blendMode, l = e.length || -1, c = e.hierarchy || []; - for(let u = 0; u < c.length; u++){ - let d = c[u].keys; + }, i = [], r = e.name || "default", a = e.fps || 30, o = e.blendMode, c = e.length || -1, l = e.hierarchy || []; + for(let u = 0; u < l.length; u++){ + let d = l[u].keys; if (!(!d || d.length === 0)) if (d[0].morphTargets) { let f = {}, m; - for(m = 0; m < d.length; m++)if (d[m].morphTargets) for(let x = 0; x < d[m].morphTargets.length; x++)f[d[m].morphTargets[x]] = -1; - for(let x in f){ - let v = [], g = []; - for(let p = 0; p !== d[m].morphTargets.length; ++p){ - let _ = d[m]; - v.push(_.time), g.push(_.morphTarget === x ? 1 : 0); + for(m = 0; m < d.length; m++)if (d[m].morphTargets) for(let _ = 0; _ < d[m].morphTargets.length; _++)f[d[m].morphTargets[_]] = -1; + for(let _ in f){ + let g = [], p = []; + for(let v = 0; v !== d[m].morphTargets.length; ++v){ + let x = d[m]; + g.push(x.time), p.push(x.morphTarget === _ ? 1 : 0); } - i.push(new Ar(".morphTargetInfluence[" + x + "]", v, g)); + i.push(new ts(".morphTargetInfluence[" + _ + "]", g, p)); } - l = f.length * (o || 1); + c = f.length * a; } else { let f = ".bones[" + t[u].name + "]"; - n(Cr, f + ".position", d, "pos", i), n(Wi, f + ".quaternion", d, "rot", i), n(Cr, f + ".scale", d, "scl", i); + n(ns, f + ".position", d, "pos", i), n(pi, f + ".quaternion", d, "rot", i), n(ns, f + ".scale", d, "scl", i); } } - return i.length === 0 ? null : new this(r, l, i, a); + return i.length === 0 ? null : new this(r, c, i, o); } resetDuration() { let e = this.tracks, t = 0; @@ -15019,84 +16610,84 @@ var Lr = class { return this.constructor.toJSON(this); } }; -function oy(s) { - switch(s.toLowerCase()){ +function Sx(s1) { + switch(s1.toLowerCase()){ case "scalar": case "double": case "float": case "number": case "integer": - return Ar; + return ts; case "vector": case "vector2": case "vector3": case "vector4": - return Cr; + return ns; case "color": - return Ba; + return pa; case "quaternion": - return Wi; + return pi; case "bool": case "boolean": - return Qn; + return Vn; case "string": - return Kn; + return kn; } - throw new Error("THREE.KeyframeTrack: Unsupported typeName: " + s); + throw new Error("THREE.KeyframeTrack: Unsupported typeName: " + s1); } -function ay(s) { - if (s.type === void 0) throw new Error("THREE.KeyframeTrack: track type undefined, can not parse"); - let e = oy(s.type); - if (s.times === void 0) { +function bx(s1) { + if (s1.type === void 0) throw new Error("THREE.KeyframeTrack: track type undefined, can not parse"); + let e = Sx(s1.type); + if (s1.times === void 0) { let t = [], n = []; - Ze.flattenJSON(s.keys, t, n, "value"), s.times = t, s.values = n; + $c(s1.keys, t, n, "value"), s1.times = t, s1.values = n; } - return e.parse !== void 0 ? e.parse(s) : new e(s.name, s.times, s.values, s.interpolation); + return e.parse !== void 0 ? e.parse(s1) : new e(s1.name, s1.times, s1.values, s1.interpolation); } -var Ni = { +var ss = { enabled: !1, files: {}, - add: function(s, e) { - this.enabled !== !1 && (this.files[s] = e); + add: function(s1, e) { + this.enabled !== !1 && (this.files[s1] = e); }, - get: function(s) { - if (this.enabled !== !1) return this.files[s]; + get: function(s1) { + if (this.enabled !== !1) return this.files[s1]; }, - remove: function(s) { - delete this.files[s]; + remove: function(s1) { + delete this.files[s1]; }, clear: function() { this.files = {}; } -}, za = class { +}, ma = class { constructor(e, t, n){ - let i = this, r = !1, o = 0, a = 0, l, c = []; + let i = this, r = !1, a = 0, o = 0, c, l = []; this.onStart = void 0, this.onLoad = e, this.onProgress = t, this.onError = n, this.itemStart = function(h) { - a++, r === !1 && i.onStart !== void 0 && i.onStart(h, o, a), r = !0; + o++, r === !1 && i.onStart !== void 0 && i.onStart(h, a, o), r = !0; }, this.itemEnd = function(h) { - o++, i.onProgress !== void 0 && i.onProgress(h, o, a), o === a && (r = !1, i.onLoad !== void 0 && i.onLoad()); + a++, i.onProgress !== void 0 && i.onProgress(h, a, o), a === o && (r = !1, i.onLoad !== void 0 && i.onLoad()); }, this.itemError = function(h) { i.onError !== void 0 && i.onError(h); }, this.resolveURL = function(h) { - return l ? l(h) : h; + return c ? c(h) : h; }, this.setURLModifier = function(h) { - return l = h, this; + return c = h, this; }, this.addHandler = function(h, u) { - return c.push(h, u), this; + return l.push(h, u), this; }, this.removeHandler = function(h) { - let u = c.indexOf(h); - return u !== -1 && c.splice(u, 2), this; + let u = l.indexOf(h); + return u !== -1 && l.splice(u, 2), this; }, this.getHandler = function(h) { - for(let u = 0, d = c.length; u < d; u += 2){ - let f = c[u], m = c[u + 1]; + for(let u = 0, d = l.length; u < d; u += 2){ + let f = l[u], m = l[u + 1]; if (f.global && (f.lastIndex = 0), f.test(h)) return m; } return null; }; } -}, ly = new za, bt = class { +}, Ex = new ma, Dt = class { constructor(e){ - this.manager = e !== void 0 ? e : ly, this.crossOrigin = "anonymous", this.withCredentials = !1, this.path = "", this.resourcePath = "", this.requestHeader = {}; + this.manager = e !== void 0 ? e : Ex, this.crossOrigin = "anonymous", this.withCredentials = !1, this.path = "", this.resourcePath = "", this.requestHeader = {}; } load() {} loadAsync(e, t) { @@ -15121,89 +16712,99 @@ var Ni = { setRequestHeader(e) { return this.requestHeader = e, this; } -}, tn = {}, Yt = class extends bt { +}; +Dt.DEFAULT_MATERIAL_NAME = "__DEFAULT"; +var fn = {}, Mc = class extends Error { + constructor(e, t){ + super(e), this.response = t; + } +}, rn = class extends Dt { constructor(e){ super(e); } load(e, t, n, i) { e === void 0 && (e = ""), this.path !== void 0 && (e = this.path + e), e = this.manager.resolveURL(e); - let r = Ni.get(e); + let r = ss.get(e); if (r !== void 0) return this.manager.itemStart(e), setTimeout(()=>{ t && t(r), this.manager.itemEnd(e); }, 0), r; - if (tn[e] !== void 0) { - tn[e].push({ + if (fn[e] !== void 0) { + fn[e].push({ onLoad: t, onProgress: n, onError: i }); return; } - tn[e] = [], tn[e].push({ + fn[e] = [], fn[e].push({ onLoad: t, onProgress: n, onError: i }); - let o = new Request(e, { + let a = new Request(e, { headers: new Headers(this.requestHeader), credentials: this.withCredentials ? "include" : "same-origin" - }); - fetch(o).then((a)=>{ - if (a.status === 200 || a.status === 0) { - if (a.status === 0 && console.warn("THREE.FileLoader: HTTP Status 0 received."), typeof ReadableStream > "u" || a.body.getReader === void 0) return a; - let l = tn[e], c = a.body.getReader(), h = a.headers.get("Content-Length"), u = h ? parseInt(h) : 0, d = u !== 0, f = 0, m = new ReadableStream({ - start (x) { + }), o = this.mimeType, c = this.responseType; + fetch(a).then((l)=>{ + if (l.status === 200 || l.status === 0) { + if (l.status === 0 && console.warn("THREE.FileLoader: HTTP Status 0 received."), typeof ReadableStream > "u" || l.body === void 0 || l.body.getReader === void 0) return l; + let h = fn[e], u = l.body.getReader(), d = l.headers.get("Content-Length") || l.headers.get("X-File-Size"), f = d ? parseInt(d) : 0, m = f !== 0, _ = 0, g = new ReadableStream({ + start (p) { v(); function v() { - c.read().then(({ done: g , value: p })=>{ - if (g) x.close(); + u.read().then(({ done: x , value: y })=>{ + if (x) p.close(); else { - f += p.byteLength; - let _ = new ProgressEvent("progress", { - lengthComputable: d, - loaded: f, - total: u + _ += y.byteLength; + let b = new ProgressEvent("progress", { + lengthComputable: m, + loaded: _, + total: f }); - for(let y = 0, b = l.length; y < b; y++){ - let A = l[y]; - A.onProgress && A.onProgress(_); + for(let w = 0, R = h.length; w < R; w++){ + let I = h[w]; + I.onProgress && I.onProgress(b); } - x.enqueue(p), v(); + p.enqueue(y), v(); } }); } } }); - return new Response(m); - } else throw Error(`fetch for "${a.url}" responded with ${a.status}: ${a.statusText}`); - }).then((a)=>{ - switch(this.responseType){ + return new Response(g); + } else throw new Mc(`fetch for "${l.url}" responded with ${l.status}: ${l.statusText}`, l); + }).then((l)=>{ + switch(c){ case "arraybuffer": - return a.arrayBuffer(); + return l.arrayBuffer(); case "blob": - return a.blob(); + return l.blob(); case "document": - return a.text().then((l)=>new DOMParser().parseFromString(l, this.mimeType)); + return l.text().then((h)=>new DOMParser().parseFromString(h, o)); case "json": - return a.json(); + return l.json(); default: - return a.text(); - } - }).then((a)=>{ - Ni.add(e, a); - let l = tn[e]; - delete tn[e]; - for(let c = 0, h = l.length; c < h; c++){ - let u = l[c]; - u.onLoad && u.onLoad(a); - } - }).catch((a)=>{ - let l = tn[e]; - if (l === void 0) throw this.manager.itemError(e), a; - delete tn[e]; - for(let c = 0, h = l.length; c < h; c++){ - let u = l[c]; - u.onError && u.onError(a); + if (o === void 0) return l.text(); + { + let u = /charset="?([^;"\s]*)"?/i.exec(o), d = u && u[1] ? u[1].toLowerCase() : void 0, f = new TextDecoder(d); + return l.arrayBuffer().then((m)=>f.decode(m)); + } + } + }).then((l)=>{ + ss.add(e, l); + let h = fn[e]; + delete fn[e]; + for(let u = 0, d = h.length; u < d; u++){ + let f = h[u]; + f.onLoad && f.onLoad(l); + } + }).catch((l)=>{ + let h = fn[e]; + if (h === void 0) throw this.manager.itemError(e), l; + delete fn[e]; + for(let u = 0, d = h.length; u < d; u++){ + let f = h[u]; + f.onError && f.onError(l); } this.manager.itemError(e); }).finally(()=>{ @@ -15216,152 +16817,157 @@ var Ni = { setMimeType(e) { return this.mimeType = e, this; } -}, cy = class extends bt { +}, au = class extends Dt { constructor(e){ super(e); } load(e, t, n, i) { - let r = this, o = new Yt(this.manager); - o.setPath(this.path), o.setRequestHeader(this.requestHeader), o.setWithCredentials(this.withCredentials), o.load(e, function(a) { + let r = this, a = new rn(this.manager); + a.setPath(this.path), a.setRequestHeader(this.requestHeader), a.setWithCredentials(this.withCredentials), a.load(e, function(o) { try { - t(r.parse(JSON.parse(a))); - } catch (l) { - i ? i(l) : console.error(l), r.manager.itemError(e); + t(r.parse(JSON.parse(o))); + } catch (c) { + i ? i(c) : console.error(c), r.manager.itemError(e); } }, n, i); } parse(e) { let t = []; for(let n = 0; n < e.length; n++){ - let i = Lr.parse(e[n]); + let i = is.parse(e[n]); t.push(i); } return t; } -}, hy = class extends bt { +}, ou = class extends Dt { constructor(e){ super(e); } load(e, t, n, i) { - let r = this, o = [], a = new va, l = new Yt(this.manager); - l.setPath(this.path), l.setResponseType("arraybuffer"), l.setRequestHeader(this.requestHeader), l.setWithCredentials(r.withCredentials); - let c = 0; + let r = this, a = [], o = new Us, c = new rn(this.manager); + c.setPath(this.path), c.setResponseType("arraybuffer"), c.setRequestHeader(this.requestHeader), c.setWithCredentials(r.withCredentials); + let l = 0; function h(u) { - l.load(e[u], function(d) { + c.load(e[u], function(d) { let f = r.parse(d, !0); - o[u] = { + a[u] = { width: f.width, height: f.height, format: f.format, mipmaps: f.mipmaps - }, c += 1, c === 6 && (f.mipmapCount === 1 && (a.minFilter = tt), a.image = o, a.format = f.format, a.needsUpdate = !0, t && t(a)); + }, l += 1, l === 6 && (f.mipmapCount === 1 && (o.minFilter = mt), o.image = a, o.format = f.format, o.needsUpdate = !0, t && t(o)); }, n, i); } if (Array.isArray(e)) for(let u = 0, d = e.length; u < d; ++u)h(u); - else l.load(e, function(u) { + else c.load(e, function(u) { let d = r.parse(u, !0); if (d.isCubemap) { let f = d.mipmaps.length / d.mipmapCount; for(let m = 0; m < f; m++){ - o[m] = { + a[m] = { mipmaps: [] }; - for(let x = 0; x < d.mipmapCount; x++)o[m].mipmaps.push(d.mipmaps[m * d.mipmapCount + x]), o[m].format = d.format, o[m].width = d.width, o[m].height = d.height; + for(let _ = 0; _ < d.mipmapCount; _++)a[m].mipmaps.push(d.mipmaps[m * d.mipmapCount + _]), a[m].format = d.format, a[m].width = d.width, a[m].height = d.height; } - a.image = o; - } else a.image.width = d.width, a.image.height = d.height, a.mipmaps = d.mipmaps; - d.mipmapCount === 1 && (a.minFilter = tt), a.format = d.format, a.needsUpdate = !0, t && t(a); + o.image = a; + } else o.image.width = d.width, o.image.height = d.height, o.mipmaps = d.mipmaps; + d.mipmapCount === 1 && (o.minFilter = mt), o.format = d.format, o.needsUpdate = !0, t && t(o); }, n, i); - return a; + return o; } -}, Rr = class extends bt { +}, rs = class extends Dt { constructor(e){ super(e); } load(e, t, n, i) { this.path !== void 0 && (e = this.path + e), e = this.manager.resolveURL(e); - let r = this, o = Ni.get(e); - if (o !== void 0) return r.manager.itemStart(e), setTimeout(function() { - t && t(o), r.manager.itemEnd(e); - }, 0), o; - let a = qs("img"); - function l() { - h(), Ni.add(e, this), t && t(this), r.manager.itemEnd(e); - } - function c(u) { + let r = this, a = ss.get(e); + if (a !== void 0) return r.manager.itemStart(e), setTimeout(function() { + t && t(a), r.manager.itemEnd(e); + }, 0), a; + let o = ws("img"); + function c() { + h(), ss.add(e, this), t && t(this), r.manager.itemEnd(e); + } + function l(u) { h(), i && i(u), r.manager.itemError(e), r.manager.itemEnd(e); } function h() { - a.removeEventListener("load", l, !1), a.removeEventListener("error", c, !1); + o.removeEventListener("load", c, !1), o.removeEventListener("error", l, !1); } - return a.addEventListener("load", l, !1), a.addEventListener("error", c, !1), e.substr(0, 5) !== "data:" && this.crossOrigin !== void 0 && (a.crossOrigin = this.crossOrigin), r.manager.itemStart(e), a.src = e, a; + return o.addEventListener("load", c, !1), o.addEventListener("error", l, !1), e.slice(0, 5) !== "data:" && this.crossOrigin !== void 0 && (o.crossOrigin = this.crossOrigin), r.manager.itemStart(e), o.src = e, o; } -}, Fh = class extends bt { +}, cu = class extends Dt { constructor(e){ super(e); } load(e, t, n, i) { - let r = new ki, o = new Rr(this.manager); - o.setCrossOrigin(this.crossOrigin), o.setPath(this.path); - let a = 0; - function l(c) { - o.load(e[c], function(h) { - r.images[c] = h, a++, a === 6 && (r.needsUpdate = !0, t && t(r)); + let r = new Ki; + r.colorSpace = vt; + let a = new rs(this.manager); + a.setCrossOrigin(this.crossOrigin), a.setPath(this.path); + let o = 0; + function c(l) { + a.load(e[l], function(h) { + r.images[l] = h, o++, o === 6 && (r.needsUpdate = !0, t && t(r)); }, void 0, i); } - for(let c = 0; c < e.length; ++c)l(c); + for(let l = 0; l < e.length; ++l)c(l); return r; } -}, Nh = class extends bt { +}, lu = class extends Dt { constructor(e){ super(e); } load(e, t, n, i) { - let r = this, o = new qn, a = new Yt(this.manager); - return a.setResponseType("arraybuffer"), a.setRequestHeader(this.requestHeader), a.setPath(this.path), a.setWithCredentials(r.withCredentials), a.load(e, function(l) { - let c = r.parse(l); - !c || (c.image !== void 0 ? o.image = c.image : c.data !== void 0 && (o.image.width = c.width, o.image.height = c.height, o.image.data = c.data), o.wrapS = c.wrapS !== void 0 ? c.wrapS : vt, o.wrapT = c.wrapT !== void 0 ? c.wrapT : vt, o.magFilter = c.magFilter !== void 0 ? c.magFilter : tt, o.minFilter = c.minFilter !== void 0 ? c.minFilter : tt, o.anisotropy = c.anisotropy !== void 0 ? c.anisotropy : 1, c.encoding !== void 0 && (o.encoding = c.encoding), c.flipY !== void 0 && (o.flipY = c.flipY), c.format !== void 0 && (o.format = c.format), c.type !== void 0 && (o.type = c.type), c.mipmaps !== void 0 && (o.mipmaps = c.mipmaps, o.minFilter = Ui), c.mipmapCount === 1 && (o.minFilter = tt), c.generateMipmaps !== void 0 && (o.generateMipmaps = c.generateMipmaps), o.needsUpdate = !0, t && t(o, c)); - }, n, i), o; + let r = this, a = new oi, o = new rn(this.manager); + return o.setResponseType("arraybuffer"), o.setRequestHeader(this.requestHeader), o.setPath(this.path), o.setWithCredentials(r.withCredentials), o.load(e, function(c) { + let l; + try { + l = r.parse(c); + } catch (h) { + if (i !== void 0) i(h); + else { + console.error(h); + return; + } + } + l.image !== void 0 ? a.image = l.image : l.data !== void 0 && (a.image.width = l.width, a.image.height = l.height, a.image.data = l.data), a.wrapS = l.wrapS !== void 0 ? l.wrapS : It, a.wrapT = l.wrapT !== void 0 ? l.wrapT : It, a.magFilter = l.magFilter !== void 0 ? l.magFilter : mt, a.minFilter = l.minFilter !== void 0 ? l.minFilter : mt, a.anisotropy = l.anisotropy !== void 0 ? l.anisotropy : 1, l.colorSpace !== void 0 ? a.colorSpace = l.colorSpace : l.encoding !== void 0 && (a.encoding = l.encoding), l.flipY !== void 0 && (a.flipY = l.flipY), l.format !== void 0 && (a.format = l.format), l.type !== void 0 && (a.type = l.type), l.mipmaps !== void 0 && (a.mipmaps = l.mipmaps, a.minFilter = li), l.mipmapCount === 1 && (a.minFilter = mt), l.generateMipmaps !== void 0 && (a.generateMipmaps = l.generateMipmaps), a.needsUpdate = !0, t && t(a, l); + }, n, i), a; } -}, Bh = class extends bt { +}, hu = class extends Dt { constructor(e){ super(e); } load(e, t, n, i) { - let r = new ot, o = new Rr(this.manager); - return o.setCrossOrigin(this.crossOrigin), o.setPath(this.path), o.load(e, function(a) { - r.image = a, r.needsUpdate = !0, t !== void 0 && t(r); + let r = new St, a = new rs(this.manager); + return a.setCrossOrigin(this.crossOrigin), a.setPath(this.path), a.load(e, function(o) { + r.image = o, r.needsUpdate = !0, t !== void 0 && t(r); }, n, i), r; } -}, Bt = class extends Ne { +}, En = class extends Je { constructor(e, t = 1){ - super(); - this.type = "Light", this.color = new ae(e), this.intensity = t; + super(), this.isLight = !0, this.type = "Light", this.color = new pe(e), this.intensity = t; } dispose() {} - copy(e) { - return super.copy(e), this.color.copy(e.color), this.intensity = e.intensity, this; + copy(e, t) { + return super.copy(e, t), this.color.copy(e.color), this.intensity = e.intensity, this; } toJSON(e) { let t = super.toJSON(e); return t.object.color = this.color.getHex(), t.object.intensity = this.intensity, this.groundColor !== void 0 && (t.object.groundColor = this.groundColor.getHex()), this.distance !== void 0 && (t.object.distance = this.distance), this.angle !== void 0 && (t.object.angle = this.angle), this.decay !== void 0 && (t.object.decay = this.decay), this.penumbra !== void 0 && (t.object.penumbra = this.penumbra), this.shadow !== void 0 && (t.object.shadow = this.shadow.toJSON()), t; } -}; -Bt.prototype.isLight = !0; -var Ua = class extends Bt { +}, Sc = class extends En { constructor(e, t, n){ - super(e, n); - this.type = "HemisphereLight", this.position.copy(Ne.DefaultUp), this.updateMatrix(), this.groundColor = new ae(t); + super(e, n), this.isHemisphereLight = !0, this.type = "HemisphereLight", this.position.copy(Je.DEFAULT_UP), this.updateMatrix(), this.groundColor = new pe(t); } - copy(e) { - return Bt.prototype.copy.call(this, e), this.groundColor.copy(e.groundColor), this; + copy(e, t) { + return super.copy(e, t), this.groundColor.copy(e.groundColor), this; } -}; -Ua.prototype.isHemisphereLight = !0; -var _c = new pe, Mc = new M, bc = new M, mo = class { +}, oo = new ze, uu = new A, du = new A, zs = class { constructor(e){ - this.camera = e, this.bias = 0, this.normalBias = 0, this.radius = 1, this.blurSamples = 8, this.mapSize = new X(512, 512), this.map = null, this.mapPass = null, this.matrix = new pe, this.autoUpdate = !0, this.needsUpdate = !1, this._frustum = new Dr, this._frameExtents = new X(1, 1), this._viewportCount = 1, this._viewports = [ - new Ve(0, 0, 1, 1) + this.camera = e, this.bias = 0, this.normalBias = 0, this.radius = 1, this.blurSamples = 8, this.mapSize = new Z(512, 512), this.map = null, this.mapPass = null, this.matrix = new ze, this.autoUpdate = !0, this.needsUpdate = !1, this._frustum = new Ps, this._frameExtents = new Z(1, 1), this._viewportCount = 1, this._viewports = [ + new je(0, 0, 1, 1) ]; } getViewportCount() { @@ -15372,7 +16978,7 @@ var _c = new pe, Mc = new M, bc = new M, mo = class { } updateMatrices(e) { let t = this.camera, n = this.matrix; - Mc.setFromMatrixPosition(e.matrixWorld), t.position.copy(Mc), bc.setFromMatrixPosition(e.target.matrixWorld), t.lookAt(bc), t.updateMatrixWorld(), _c.multiplyMatrices(t.projectionMatrix, t.matrixWorldInverse), this._frustum.setFromProjectionMatrix(_c), n.set(.5, 0, 0, .5, 0, .5, 0, .5, 0, 0, .5, .5, 0, 0, 0, 1), n.multiply(t.projectionMatrix), n.multiply(t.matrixWorldInverse); + uu.setFromMatrixPosition(e.matrixWorld), t.position.copy(uu), du.setFromMatrixPosition(e.target.matrixWorld), t.lookAt(du), t.updateMatrixWorld(), oo.multiplyMatrices(t.projectionMatrix, t.matrixWorldInverse), this._frustum.setFromProjectionMatrix(oo), n.set(.5, 0, 0, .5, 0, .5, 0, .5, 0, 0, .5, .5, 0, 0, 0, 1), n.multiply(oo); } getViewport(e) { return this._viewports[e]; @@ -15393,24 +16999,20 @@ var _c = new pe, Mc = new M, bc = new M, mo = class { let e = {}; return this.bias !== 0 && (e.bias = this.bias), this.normalBias !== 0 && (e.normalBias = this.normalBias), this.radius !== 1 && (e.radius = this.radius), (this.mapSize.x !== 512 || this.mapSize.y !== 512) && (e.mapSize = this.mapSize.toArray()), e.camera = this.camera.toJSON(!1).object, delete e.camera.matrix, e; } -}, Oa = class extends mo { +}, bc = class extends zs { constructor(){ - super(new ut(50, 1, .5, 500)); - this.focus = 1; + super(new yt(50, 1, .5, 500)), this.isSpotLightShadow = !0, this.focus = 1; } updateMatrices(e) { - let t = this.camera, n = dr * 2 * e.angle * this.focus, i = this.mapSize.width / this.mapSize.height, r = e.distance || t.far; + let t = this.camera, n = Zi * 2 * e.angle * this.focus, i = this.mapSize.width / this.mapSize.height, r = e.distance || t.far; (n !== t.fov || i !== t.aspect || r !== t.far) && (t.fov = n, t.aspect = i, t.far = r, t.updateProjectionMatrix()), super.updateMatrices(e); } copy(e) { return super.copy(e), this.focus = e.focus, this; } -}; -Oa.prototype.isSpotLightShadow = !0; -var Ha = class extends Bt { - constructor(e, t, n = 0, i = Math.PI / 3, r = 0, o = 1){ - super(e, t); - this.type = "SpotLight", this.position.copy(Ne.DefaultUp), this.updateMatrix(), this.target = new Ne, this.distance = n, this.angle = i, this.penumbra = r, this.decay = o, this.shadow = new Oa; +}, Ec = class extends En { + constructor(e, t, n = 0, i = Math.PI / 3, r = 0, a = 2){ + super(e, t), this.isSpotLight = !0, this.type = "SpotLight", this.position.copy(Je.DEFAULT_UP), this.updateMatrix(), this.target = new Je, this.distance = n, this.angle = i, this.penumbra = r, this.decay = a, this.map = null, this.shadow = new bc; } get power() { return this.intensity * Math.PI; @@ -15421,47 +17023,41 @@ var Ha = class extends Bt { dispose() { this.shadow.dispose(); } - copy(e) { - return super.copy(e), this.distance = e.distance, this.angle = e.angle, this.penumbra = e.penumbra, this.decay = e.decay, this.target = e.target.clone(), this.shadow = e.shadow.clone(), this; + copy(e, t) { + return super.copy(e, t), this.distance = e.distance, this.angle = e.angle, this.penumbra = e.penumbra, this.decay = e.decay, this.target = e.target.clone(), this.shadow = e.shadow.clone(), this; } -}; -Ha.prototype.isSpotLight = !0; -var wc = new pe, nr = new M, jo = new M, ka = class extends mo { +}, fu = new ze, _s = new A, co = new A, Tc = class extends zs { constructor(){ - super(new ut(90, 1, .5, 500)); - this._frameExtents = new X(4, 2), this._viewportCount = 6, this._viewports = [ - new Ve(2, 1, 1, 1), - new Ve(0, 1, 1, 1), - new Ve(3, 1, 1, 1), - new Ve(1, 1, 1, 1), - new Ve(3, 0, 1, 1), - new Ve(1, 0, 1, 1) + super(new yt(90, 1, .5, 500)), this.isPointLightShadow = !0, this._frameExtents = new Z(4, 2), this._viewportCount = 6, this._viewports = [ + new je(2, 1, 1, 1), + new je(0, 1, 1, 1), + new je(3, 1, 1, 1), + new je(1, 1, 1, 1), + new je(3, 0, 1, 1), + new je(1, 0, 1, 1) ], this._cubeDirections = [ - new M(1, 0, 0), - new M(-1, 0, 0), - new M(0, 0, 1), - new M(0, 0, -1), - new M(0, 1, 0), - new M(0, -1, 0) + new A(1, 0, 0), + new A(-1, 0, 0), + new A(0, 0, 1), + new A(0, 0, -1), + new A(0, 1, 0), + new A(0, -1, 0) ], this._cubeUps = [ - new M(0, 1, 0), - new M(0, 1, 0), - new M(0, 1, 0), - new M(0, 1, 0), - new M(0, 0, 1), - new M(0, 0, -1) + new A(0, 1, 0), + new A(0, 1, 0), + new A(0, 1, 0), + new A(0, 1, 0), + new A(0, 0, 1), + new A(0, 0, -1) ]; } updateMatrices(e, t = 0) { let n = this.camera, i = this.matrix, r = e.distance || n.far; - r !== n.far && (n.far = r, n.updateProjectionMatrix()), nr.setFromMatrixPosition(e.matrixWorld), n.position.copy(nr), jo.copy(n.position), jo.add(this._cubeDirections[t]), n.up.copy(this._cubeUps[t]), n.lookAt(jo), n.updateMatrixWorld(), i.makeTranslation(-nr.x, -nr.y, -nr.z), wc.multiplyMatrices(n.projectionMatrix, n.matrixWorldInverse), this._frustum.setFromProjectionMatrix(wc); + r !== n.far && (n.far = r, n.updateProjectionMatrix()), _s.setFromMatrixPosition(e.matrixWorld), n.position.copy(_s), co.copy(n.position), co.add(this._cubeDirections[t]), n.up.copy(this._cubeUps[t]), n.lookAt(co), n.updateMatrixWorld(), i.makeTranslation(-_s.x, -_s.y, -_s.z), fu.multiplyMatrices(n.projectionMatrix, n.matrixWorldInverse), this._frustum.setFromProjectionMatrix(fu); } -}; -ka.prototype.isPointLightShadow = !0; -var Ga = class extends Bt { - constructor(e, t, n = 0, i = 1){ - super(e, t); - this.type = "PointLight", this.distance = n, this.decay = i, this.shadow = new ka; +}, wc = class extends En { + constructor(e, t, n = 0, i = 2){ + super(e, t), this.isPointLight = !0, this.type = "PointLight", this.distance = n, this.decay = i, this.shadow = new Tc; } get power() { return this.intensity * 4 * Math.PI; @@ -15472,21 +17068,16 @@ var Ga = class extends Bt { dispose() { this.shadow.dispose(); } - copy(e) { - return super.copy(e), this.distance = e.distance, this.decay = e.decay, this.shadow = e.shadow.clone(), this; + copy(e, t) { + return super.copy(e, t), this.distance = e.distance, this.decay = e.decay, this.shadow = e.shadow.clone(), this; } -}; -Ga.prototype.isPointLight = !0; -var Va = class extends mo { +}, Ac = class extends zs { constructor(){ - super(new Fr(-5, 5, 5, -5, .5, 500)); + super(new Ls(-5, 5, 5, -5, .5, 500)), this.isDirectionalLightShadow = !0; } -}; -Va.prototype.isDirectionalLightShadow = !0; -var Wa = class extends Bt { +}, Rc = class extends En { constructor(e, t){ - super(e, t); - this.type = "DirectionalLight", this.position.copy(Ne.DefaultUp), this.updateMatrix(), this.target = new Ne, this.shadow = new Va; + super(e, t), this.isDirectionalLight = !0, this.type = "DirectionalLight", this.position.copy(Je.DEFAULT_UP), this.updateMatrix(), this.target = new Je, this.shadow = new Ac; } dispose() { this.shadow.dispose(); @@ -15494,19 +17085,13 @@ var Wa = class extends Bt { copy(e) { return super.copy(e), this.target = e.target.clone(), this.shadow = e.shadow.clone(), this; } -}; -Wa.prototype.isDirectionalLight = !0; -var qa = class extends Bt { +}, Cc = class extends En { constructor(e, t){ - super(e, t); - this.type = "AmbientLight"; + super(e, t), this.isAmbientLight = !0, this.type = "AmbientLight"; } -}; -qa.prototype.isAmbientLight = !0; -var Xa = class extends Bt { +}, Pc = class extends En { constructor(e, t, n = 10, i = 10){ - super(e, t); - this.type = "RectAreaLight", this.width = n, this.height = i; + super(e, t), this.isRectAreaLight = !0, this.type = "RectAreaLight", this.width = n, this.height = i; } get power() { return this.intensity * this.width * this.height * Math.PI; @@ -15521,12 +17106,10 @@ var Xa = class extends Bt { let t = super.toJSON(e); return t.object.width = this.width, t.object.height = this.height, t; } -}; -Xa.prototype.isRectAreaLight = !0; -var Ja = class { +}, Lc = class { constructor(){ - this.coefficients = []; - for(let e = 0; e < 9; e++)this.coefficients.push(new M); + this.isSphericalHarmonics3 = !0, this.coefficients = []; + for(let e = 0; e < 9; e++)this.coefficients.push(new A); } set(e) { for(let t = 0; t < 9; t++)this.coefficients[t].copy(e[t]); @@ -15537,12 +17120,12 @@ var Ja = class { return this; } getAt(e, t) { - let n = e.x, i = e.y, r = e.z, o = this.coefficients; - return t.copy(o[0]).multiplyScalar(.282095), t.addScaledVector(o[1], .488603 * i), t.addScaledVector(o[2], .488603 * r), t.addScaledVector(o[3], .488603 * n), t.addScaledVector(o[4], 1.092548 * (n * i)), t.addScaledVector(o[5], 1.092548 * (i * r)), t.addScaledVector(o[6], .315392 * (3 * r * r - 1)), t.addScaledVector(o[7], 1.092548 * (n * r)), t.addScaledVector(o[8], .546274 * (n * n - i * i)), t; + let n = e.x, i = e.y, r = e.z, a = this.coefficients; + return t.copy(a[0]).multiplyScalar(.282095), t.addScaledVector(a[1], .488603 * i), t.addScaledVector(a[2], .488603 * r), t.addScaledVector(a[3], .488603 * n), t.addScaledVector(a[4], 1.092548 * (n * i)), t.addScaledVector(a[5], 1.092548 * (i * r)), t.addScaledVector(a[6], .315392 * (3 * r * r - 1)), t.addScaledVector(a[7], 1.092548 * (n * r)), t.addScaledVector(a[8], .546274 * (n * n - i * i)), t; } getIrradianceAt(e, t) { - let n = e.x, i = e.y, r = e.z, o = this.coefficients; - return t.copy(o[0]).multiplyScalar(.886227), t.addScaledVector(o[1], 2 * .511664 * i), t.addScaledVector(o[2], 2 * .511664 * r), t.addScaledVector(o[3], 2 * .511664 * n), t.addScaledVector(o[4], 2 * .429043 * n * i), t.addScaledVector(o[5], 2 * .429043 * i * r), t.addScaledVector(o[6], .743125 * r * r - .247708), t.addScaledVector(o[7], 2 * .429043 * n * r), t.addScaledVector(o[8], .429043 * (n * n - i * i)), t; + let n = e.x, i = e.y, r = e.z, a = this.coefficients; + return t.copy(a[0]).multiplyScalar(.886227), t.addScaledVector(a[1], 2 * .511664 * i), t.addScaledVector(a[2], 2 * .511664 * r), t.addScaledVector(a[3], 2 * .511664 * n), t.addScaledVector(a[4], 2 * .429043 * n * i), t.addScaledVector(a[5], 2 * .429043 * i * r), t.addScaledVector(a[6], .743125 * r * r - .247708), t.addScaledVector(a[7], 2 * .429043 * n * r), t.addScaledVector(a[8], .429043 * (n * n - i * i)), t; } add(e) { for(let t = 0; t < 9; t++)this.coefficients[t].add(e.coefficients[t]); @@ -15584,12 +17167,9 @@ var Ja = class { let n = e.x, i = e.y, r = e.z; t[0] = .282095, t[1] = .488603 * i, t[2] = .488603 * r, t[3] = .488603 * n, t[4] = 1.092548 * n * i, t[5] = 1.092548 * i * r, t[6] = .315392 * (3 * r * r - 1), t[7] = 1.092548 * n * r, t[8] = .546274 * (n * n - i * i); } -}; -Ja.prototype.isSphericalHarmonics3 = !0; -var Hr = class extends Bt { - constructor(e = new Ja, t = 1){ - super(void 0, t); - this.sh = e; +}, Ic = class extends En { + constructor(e = new Lc, t = 1){ + super(void 0, t), this.isLightProbe = !0, this.sh = e; } copy(e) { return super.copy(e), this.sh.copy(e.sh), this; @@ -15601,20 +17181,17 @@ var Hr = class extends Bt { let t = super.toJSON(e); return t.object.sh = this.sh.toArray(), t; } -}; -Hr.prototype.isLightProbe = !0; -var zh = class extends bt { +}, Uc = class s1 extends Dt { constructor(e){ - super(e); - this.textures = {}; + super(e), this.textures = {}; } load(e, t, n, i) { - let r = this, o = new Yt(r.manager); - o.setPath(r.path), o.setRequestHeader(r.requestHeader), o.setWithCredentials(r.withCredentials), o.load(e, function(a) { + let r = this, a = new rn(r.manager); + a.setPath(r.path), a.setRequestHeader(r.requestHeader), a.setWithCredentials(r.withCredentials), a.load(e, function(o) { try { - t(r.parse(JSON.parse(a))); - } catch (l) { - i ? i(l) : console.error(l), r.manager.itemError(e); + t(r.parse(JSON.parse(o))); + } catch (c) { + i ? i(c) : console.error(c), r.manager.itemError(e); } }, n, i); } @@ -15623,49 +17200,72 @@ var zh = class extends bt { function n(r) { return t[r] === void 0 && console.warn("THREE.MaterialLoader: Undefined texture", r), t[r]; } - let i = new sy[e.type]; - if (e.uuid !== void 0 && (i.uuid = e.uuid), e.name !== void 0 && (i.name = e.name), e.color !== void 0 && i.color !== void 0 && i.color.setHex(e.color), e.roughness !== void 0 && (i.roughness = e.roughness), e.metalness !== void 0 && (i.metalness = e.metalness), e.sheen !== void 0 && (i.sheen = e.sheen), e.sheenColor !== void 0 && (i.sheenColor = new ae().setHex(e.sheenColor)), e.sheenRoughness !== void 0 && (i.sheenRoughness = e.sheenRoughness), e.emissive !== void 0 && i.emissive !== void 0 && i.emissive.setHex(e.emissive), e.specular !== void 0 && i.specular !== void 0 && i.specular.setHex(e.specular), e.specularIntensity !== void 0 && (i.specularIntensity = e.specularIntensity), e.specularColor !== void 0 && i.specularColor !== void 0 && i.specularColor.setHex(e.specularColor), e.shininess !== void 0 && (i.shininess = e.shininess), e.clearcoat !== void 0 && (i.clearcoat = e.clearcoat), e.clearcoatRoughness !== void 0 && (i.clearcoatRoughness = e.clearcoatRoughness), e.transmission !== void 0 && (i.transmission = e.transmission), e.thickness !== void 0 && (i.thickness = e.thickness), e.attenuationDistance !== void 0 && (i.attenuationDistance = e.attenuationDistance), e.attenuationColor !== void 0 && i.attenuationColor !== void 0 && i.attenuationColor.setHex(e.attenuationColor), e.fog !== void 0 && (i.fog = e.fog), e.flatShading !== void 0 && (i.flatShading = e.flatShading), e.blending !== void 0 && (i.blending = e.blending), e.combine !== void 0 && (i.combine = e.combine), e.side !== void 0 && (i.side = e.side), e.shadowSide !== void 0 && (i.shadowSide = e.shadowSide), e.opacity !== void 0 && (i.opacity = e.opacity), e.format !== void 0 && (i.format = e.format), e.transparent !== void 0 && (i.transparent = e.transparent), e.alphaTest !== void 0 && (i.alphaTest = e.alphaTest), e.depthTest !== void 0 && (i.depthTest = e.depthTest), e.depthWrite !== void 0 && (i.depthWrite = e.depthWrite), e.colorWrite !== void 0 && (i.colorWrite = e.colorWrite), e.stencilWrite !== void 0 && (i.stencilWrite = e.stencilWrite), e.stencilWriteMask !== void 0 && (i.stencilWriteMask = e.stencilWriteMask), e.stencilFunc !== void 0 && (i.stencilFunc = e.stencilFunc), e.stencilRef !== void 0 && (i.stencilRef = e.stencilRef), e.stencilFuncMask !== void 0 && (i.stencilFuncMask = e.stencilFuncMask), e.stencilFail !== void 0 && (i.stencilFail = e.stencilFail), e.stencilZFail !== void 0 && (i.stencilZFail = e.stencilZFail), e.stencilZPass !== void 0 && (i.stencilZPass = e.stencilZPass), e.wireframe !== void 0 && (i.wireframe = e.wireframe), e.wireframeLinewidth !== void 0 && (i.wireframeLinewidth = e.wireframeLinewidth), e.wireframeLinecap !== void 0 && (i.wireframeLinecap = e.wireframeLinecap), e.wireframeLinejoin !== void 0 && (i.wireframeLinejoin = e.wireframeLinejoin), e.rotation !== void 0 && (i.rotation = e.rotation), e.linewidth !== 1 && (i.linewidth = e.linewidth), e.dashSize !== void 0 && (i.dashSize = e.dashSize), e.gapSize !== void 0 && (i.gapSize = e.gapSize), e.scale !== void 0 && (i.scale = e.scale), e.polygonOffset !== void 0 && (i.polygonOffset = e.polygonOffset), e.polygonOffsetFactor !== void 0 && (i.polygonOffsetFactor = e.polygonOffsetFactor), e.polygonOffsetUnits !== void 0 && (i.polygonOffsetUnits = e.polygonOffsetUnits), e.dithering !== void 0 && (i.dithering = e.dithering), e.alphaToCoverage !== void 0 && (i.alphaToCoverage = e.alphaToCoverage), e.premultipliedAlpha !== void 0 && (i.premultipliedAlpha = e.premultipliedAlpha), e.visible !== void 0 && (i.visible = e.visible), e.toneMapped !== void 0 && (i.toneMapped = e.toneMapped), e.userData !== void 0 && (i.userData = e.userData), e.vertexColors !== void 0 && (typeof e.vertexColors == "number" ? i.vertexColors = e.vertexColors > 0 : i.vertexColors = e.vertexColors), e.uniforms !== void 0) for(let r in e.uniforms){ - let o = e.uniforms[r]; - switch(i.uniforms[r] = {}, o.type){ + let i = s1.createMaterialFromType(e.type); + if (e.uuid !== void 0 && (i.uuid = e.uuid), e.name !== void 0 && (i.name = e.name), e.color !== void 0 && i.color !== void 0 && i.color.setHex(e.color), e.roughness !== void 0 && (i.roughness = e.roughness), e.metalness !== void 0 && (i.metalness = e.metalness), e.sheen !== void 0 && (i.sheen = e.sheen), e.sheenColor !== void 0 && (i.sheenColor = new pe().setHex(e.sheenColor)), e.sheenRoughness !== void 0 && (i.sheenRoughness = e.sheenRoughness), e.emissive !== void 0 && i.emissive !== void 0 && i.emissive.setHex(e.emissive), e.specular !== void 0 && i.specular !== void 0 && i.specular.setHex(e.specular), e.specularIntensity !== void 0 && (i.specularIntensity = e.specularIntensity), e.specularColor !== void 0 && i.specularColor !== void 0 && i.specularColor.setHex(e.specularColor), e.shininess !== void 0 && (i.shininess = e.shininess), e.clearcoat !== void 0 && (i.clearcoat = e.clearcoat), e.clearcoatRoughness !== void 0 && (i.clearcoatRoughness = e.clearcoatRoughness), e.iridescence !== void 0 && (i.iridescence = e.iridescence), e.iridescenceIOR !== void 0 && (i.iridescenceIOR = e.iridescenceIOR), e.iridescenceThicknessRange !== void 0 && (i.iridescenceThicknessRange = e.iridescenceThicknessRange), e.transmission !== void 0 && (i.transmission = e.transmission), e.thickness !== void 0 && (i.thickness = e.thickness), e.attenuationDistance !== void 0 && (i.attenuationDistance = e.attenuationDistance), e.attenuationColor !== void 0 && i.attenuationColor !== void 0 && i.attenuationColor.setHex(e.attenuationColor), e.anisotropy !== void 0 && (i.anisotropy = e.anisotropy), e.anisotropyRotation !== void 0 && (i.anisotropyRotation = e.anisotropyRotation), e.fog !== void 0 && (i.fog = e.fog), e.flatShading !== void 0 && (i.flatShading = e.flatShading), e.blending !== void 0 && (i.blending = e.blending), e.combine !== void 0 && (i.combine = e.combine), e.side !== void 0 && (i.side = e.side), e.shadowSide !== void 0 && (i.shadowSide = e.shadowSide), e.opacity !== void 0 && (i.opacity = e.opacity), e.transparent !== void 0 && (i.transparent = e.transparent), e.alphaTest !== void 0 && (i.alphaTest = e.alphaTest), e.alphaHash !== void 0 && (i.alphaHash = e.alphaHash), e.depthTest !== void 0 && (i.depthTest = e.depthTest), e.depthWrite !== void 0 && (i.depthWrite = e.depthWrite), e.colorWrite !== void 0 && (i.colorWrite = e.colorWrite), e.stencilWrite !== void 0 && (i.stencilWrite = e.stencilWrite), e.stencilWriteMask !== void 0 && (i.stencilWriteMask = e.stencilWriteMask), e.stencilFunc !== void 0 && (i.stencilFunc = e.stencilFunc), e.stencilRef !== void 0 && (i.stencilRef = e.stencilRef), e.stencilFuncMask !== void 0 && (i.stencilFuncMask = e.stencilFuncMask), e.stencilFail !== void 0 && (i.stencilFail = e.stencilFail), e.stencilZFail !== void 0 && (i.stencilZFail = e.stencilZFail), e.stencilZPass !== void 0 && (i.stencilZPass = e.stencilZPass), e.wireframe !== void 0 && (i.wireframe = e.wireframe), e.wireframeLinewidth !== void 0 && (i.wireframeLinewidth = e.wireframeLinewidth), e.wireframeLinecap !== void 0 && (i.wireframeLinecap = e.wireframeLinecap), e.wireframeLinejoin !== void 0 && (i.wireframeLinejoin = e.wireframeLinejoin), e.rotation !== void 0 && (i.rotation = e.rotation), e.linewidth !== void 0 && (i.linewidth = e.linewidth), e.dashSize !== void 0 && (i.dashSize = e.dashSize), e.gapSize !== void 0 && (i.gapSize = e.gapSize), e.scale !== void 0 && (i.scale = e.scale), e.polygonOffset !== void 0 && (i.polygonOffset = e.polygonOffset), e.polygonOffsetFactor !== void 0 && (i.polygonOffsetFactor = e.polygonOffsetFactor), e.polygonOffsetUnits !== void 0 && (i.polygonOffsetUnits = e.polygonOffsetUnits), e.dithering !== void 0 && (i.dithering = e.dithering), e.alphaToCoverage !== void 0 && (i.alphaToCoverage = e.alphaToCoverage), e.premultipliedAlpha !== void 0 && (i.premultipliedAlpha = e.premultipliedAlpha), e.forceSinglePass !== void 0 && (i.forceSinglePass = e.forceSinglePass), e.visible !== void 0 && (i.visible = e.visible), e.toneMapped !== void 0 && (i.toneMapped = e.toneMapped), e.userData !== void 0 && (i.userData = e.userData), e.vertexColors !== void 0 && (typeof e.vertexColors == "number" ? i.vertexColors = e.vertexColors > 0 : i.vertexColors = e.vertexColors), e.uniforms !== void 0) for(let r in e.uniforms){ + let a = e.uniforms[r]; + switch(i.uniforms[r] = {}, a.type){ case "t": - i.uniforms[r].value = n(o.value); + i.uniforms[r].value = n(a.value); break; case "c": - i.uniforms[r].value = new ae().setHex(o.value); + i.uniforms[r].value = new pe().setHex(a.value); break; case "v2": - i.uniforms[r].value = new X().fromArray(o.value); + i.uniforms[r].value = new Z().fromArray(a.value); break; case "v3": - i.uniforms[r].value = new M().fromArray(o.value); + i.uniforms[r].value = new A().fromArray(a.value); break; case "v4": - i.uniforms[r].value = new Ve().fromArray(o.value); + i.uniforms[r].value = new je().fromArray(a.value); break; case "m3": - i.uniforms[r].value = new lt().fromArray(o.value); + i.uniforms[r].value = new He().fromArray(a.value); break; case "m4": - i.uniforms[r].value = new pe().fromArray(o.value); + i.uniforms[r].value = new ze().fromArray(a.value); break; default: - i.uniforms[r].value = o.value; + i.uniforms[r].value = a.value; } } - if (e.defines !== void 0 && (i.defines = e.defines), e.vertexShader !== void 0 && (i.vertexShader = e.vertexShader), e.fragmentShader !== void 0 && (i.fragmentShader = e.fragmentShader), e.extensions !== void 0) for(let r in e.extensions)i.extensions[r] = e.extensions[r]; - if (e.shading !== void 0 && (i.flatShading = e.shading === 1), e.size !== void 0 && (i.size = e.size), e.sizeAttenuation !== void 0 && (i.sizeAttenuation = e.sizeAttenuation), e.map !== void 0 && (i.map = n(e.map)), e.matcap !== void 0 && (i.matcap = n(e.matcap)), e.alphaMap !== void 0 && (i.alphaMap = n(e.alphaMap)), e.bumpMap !== void 0 && (i.bumpMap = n(e.bumpMap)), e.bumpScale !== void 0 && (i.bumpScale = e.bumpScale), e.normalMap !== void 0 && (i.normalMap = n(e.normalMap)), e.normalMapType !== void 0 && (i.normalMapType = e.normalMapType), e.normalScale !== void 0) { + if (e.defines !== void 0 && (i.defines = e.defines), e.vertexShader !== void 0 && (i.vertexShader = e.vertexShader), e.fragmentShader !== void 0 && (i.fragmentShader = e.fragmentShader), e.glslVersion !== void 0 && (i.glslVersion = e.glslVersion), e.extensions !== void 0) for(let r in e.extensions)i.extensions[r] = e.extensions[r]; + if (e.lights !== void 0 && (i.lights = e.lights), e.clipping !== void 0 && (i.clipping = e.clipping), e.size !== void 0 && (i.size = e.size), e.sizeAttenuation !== void 0 && (i.sizeAttenuation = e.sizeAttenuation), e.map !== void 0 && (i.map = n(e.map)), e.matcap !== void 0 && (i.matcap = n(e.matcap)), e.alphaMap !== void 0 && (i.alphaMap = n(e.alphaMap)), e.bumpMap !== void 0 && (i.bumpMap = n(e.bumpMap)), e.bumpScale !== void 0 && (i.bumpScale = e.bumpScale), e.normalMap !== void 0 && (i.normalMap = n(e.normalMap)), e.normalMapType !== void 0 && (i.normalMapType = e.normalMapType), e.normalScale !== void 0) { let r = e.normalScale; Array.isArray(r) === !1 && (r = [ r, r - ]), i.normalScale = new X().fromArray(r); + ]), i.normalScale = new Z().fromArray(r); } - return e.displacementMap !== void 0 && (i.displacementMap = n(e.displacementMap)), e.displacementScale !== void 0 && (i.displacementScale = e.displacementScale), e.displacementBias !== void 0 && (i.displacementBias = e.displacementBias), e.roughnessMap !== void 0 && (i.roughnessMap = n(e.roughnessMap)), e.metalnessMap !== void 0 && (i.metalnessMap = n(e.metalnessMap)), e.emissiveMap !== void 0 && (i.emissiveMap = n(e.emissiveMap)), e.emissiveIntensity !== void 0 && (i.emissiveIntensity = e.emissiveIntensity), e.specularMap !== void 0 && (i.specularMap = n(e.specularMap)), e.specularIntensityMap !== void 0 && (i.specularIntensityMap = n(e.specularIntensityMap)), e.specularColorMap !== void 0 && (i.specularColorMap = n(e.specularColorMap)), e.envMap !== void 0 && (i.envMap = n(e.envMap)), e.envMapIntensity !== void 0 && (i.envMapIntensity = e.envMapIntensity), e.reflectivity !== void 0 && (i.reflectivity = e.reflectivity), e.refractionRatio !== void 0 && (i.refractionRatio = e.refractionRatio), e.lightMap !== void 0 && (i.lightMap = n(e.lightMap)), e.lightMapIntensity !== void 0 && (i.lightMapIntensity = e.lightMapIntensity), e.aoMap !== void 0 && (i.aoMap = n(e.aoMap)), e.aoMapIntensity !== void 0 && (i.aoMapIntensity = e.aoMapIntensity), e.gradientMap !== void 0 && (i.gradientMap = n(e.gradientMap)), e.clearcoatMap !== void 0 && (i.clearcoatMap = n(e.clearcoatMap)), e.clearcoatRoughnessMap !== void 0 && (i.clearcoatRoughnessMap = n(e.clearcoatRoughnessMap)), e.clearcoatNormalMap !== void 0 && (i.clearcoatNormalMap = n(e.clearcoatNormalMap)), e.clearcoatNormalScale !== void 0 && (i.clearcoatNormalScale = new X().fromArray(e.clearcoatNormalScale)), e.transmissionMap !== void 0 && (i.transmissionMap = n(e.transmissionMap)), e.thicknessMap !== void 0 && (i.thicknessMap = n(e.thicknessMap)), e.sheenColorMap !== void 0 && (i.sheenColorMap = n(e.sheenColorMap)), e.sheenRoughnessMap !== void 0 && (i.sheenRoughnessMap = n(e.sheenRoughnessMap)), i; + return e.displacementMap !== void 0 && (i.displacementMap = n(e.displacementMap)), e.displacementScale !== void 0 && (i.displacementScale = e.displacementScale), e.displacementBias !== void 0 && (i.displacementBias = e.displacementBias), e.roughnessMap !== void 0 && (i.roughnessMap = n(e.roughnessMap)), e.metalnessMap !== void 0 && (i.metalnessMap = n(e.metalnessMap)), e.emissiveMap !== void 0 && (i.emissiveMap = n(e.emissiveMap)), e.emissiveIntensity !== void 0 && (i.emissiveIntensity = e.emissiveIntensity), e.specularMap !== void 0 && (i.specularMap = n(e.specularMap)), e.specularIntensityMap !== void 0 && (i.specularIntensityMap = n(e.specularIntensityMap)), e.specularColorMap !== void 0 && (i.specularColorMap = n(e.specularColorMap)), e.envMap !== void 0 && (i.envMap = n(e.envMap)), e.envMapIntensity !== void 0 && (i.envMapIntensity = e.envMapIntensity), e.reflectivity !== void 0 && (i.reflectivity = e.reflectivity), e.refractionRatio !== void 0 && (i.refractionRatio = e.refractionRatio), e.lightMap !== void 0 && (i.lightMap = n(e.lightMap)), e.lightMapIntensity !== void 0 && (i.lightMapIntensity = e.lightMapIntensity), e.aoMap !== void 0 && (i.aoMap = n(e.aoMap)), e.aoMapIntensity !== void 0 && (i.aoMapIntensity = e.aoMapIntensity), e.gradientMap !== void 0 && (i.gradientMap = n(e.gradientMap)), e.clearcoatMap !== void 0 && (i.clearcoatMap = n(e.clearcoatMap)), e.clearcoatRoughnessMap !== void 0 && (i.clearcoatRoughnessMap = n(e.clearcoatRoughnessMap)), e.clearcoatNormalMap !== void 0 && (i.clearcoatNormalMap = n(e.clearcoatNormalMap)), e.clearcoatNormalScale !== void 0 && (i.clearcoatNormalScale = new Z().fromArray(e.clearcoatNormalScale)), e.iridescenceMap !== void 0 && (i.iridescenceMap = n(e.iridescenceMap)), e.iridescenceThicknessMap !== void 0 && (i.iridescenceThicknessMap = n(e.iridescenceThicknessMap)), e.transmissionMap !== void 0 && (i.transmissionMap = n(e.transmissionMap)), e.thicknessMap !== void 0 && (i.thicknessMap = n(e.thicknessMap)), e.anisotropyMap !== void 0 && (i.anisotropyMap = n(e.anisotropyMap)), e.sheenColorMap !== void 0 && (i.sheenColorMap = n(e.sheenColorMap)), e.sheenRoughnessMap !== void 0 && (i.sheenRoughnessMap = n(e.sheenRoughnessMap)), i; } setTextures(e) { return this.textures = e, this; } -}, Gs = class { + static createMaterialFromType(e) { + let t = { + ShadowMaterial: cc, + SpriteMaterial: ea, + RawShaderMaterial: lc, + ShaderMaterial: jt, + PointsMaterial: na, + MeshPhysicalMaterial: hc, + MeshStandardMaterial: da, + MeshPhongMaterial: uc, + MeshToonMaterial: dc, + MeshNormalMaterial: fc, + MeshLambertMaterial: pc, + MeshDepthMaterial: Qr, + MeshDistanceMaterial: jr, + MeshBasicMaterial: Sn, + MeshMatcapMaterial: mc, + LineDashedMaterial: gc, + LineBasicMaterial: wt, + Material: bt + }; + return new t[e]; + } +}, ga = class { static decodeText(e) { if (typeof TextDecoder < "u") return new TextDecoder().decode(e); let t = ""; @@ -15678,39 +17278,33 @@ var zh = class extends bt { } static extractUrlBase(e) { let t = e.lastIndexOf("/"); - return t === -1 ? "./" : e.substr(0, t + 1); + return t === -1 ? "./" : e.slice(0, t + 1); } static resolveURL(e, t) { return typeof e != "string" || e === "" ? "" : (/^https?:\/\//i.test(t) && /^\//.test(e) && (t = t.replace(/(^https?:\/\/[^\/]+).*/i, "$1")), /^(https?:)?\/\//i.test(e) || /^data:.*,.*$/i.test(e) || /^blob:.*$/i.test(e) ? e : t + e); } -}, Ya = class extends _e { +}, Dc = class extends Ge { constructor(){ - super(); - this.type = "InstancedBufferGeometry", this.instanceCount = 1 / 0; + super(), this.isInstancedBufferGeometry = !0, this.type = "InstancedBufferGeometry", this.instanceCount = 1 / 0; } copy(e) { return super.copy(e), this.instanceCount = e.instanceCount, this; } - clone() { - return new this.constructor().copy(this); - } toJSON() { - let e = super.toJSON(this); + let e = super.toJSON(); return e.instanceCount = this.instanceCount, e.isInstancedBufferGeometry = !0, e; } -}; -Ya.prototype.isInstancedBufferGeometry = !0; -var Uh = class extends bt { +}, Nc = class extends Dt { constructor(e){ super(e); } load(e, t, n, i) { - let r = this, o = new Yt(r.manager); - o.setPath(r.path), o.setRequestHeader(r.requestHeader), o.setWithCredentials(r.withCredentials), o.load(e, function(a) { + let r = this, a = new rn(r.manager); + a.setPath(r.path), a.setRequestHeader(r.requestHeader), a.setWithCredentials(r.withCredentials), a.load(e, function(o) { try { - t(r.parse(JSON.parse(a))); - } catch (l) { - i ? i(l) : console.error(l), r.manager.itemError(e); + t(r.parse(JSON.parse(o))); + } catch (c) { + i ? i(c) : console.error(c), r.manager.itemError(e); } }, n, i); } @@ -15718,115 +17312,115 @@ var Uh = class extends bt { let t = {}, n = {}; function i(f, m) { if (t[m] !== void 0) return t[m]; - let v = f.interleavedBuffers[m], g = r(f, v.buffer), p = wi(v.type, g), _ = new $n(p, v.stride); - return _.uuid = v.uuid, t[m] = _, _; + let g = f.interleavedBuffers[m], p = r(f, g.buffer), v = ki(g.type, p), x = new Is(v, g.stride); + return x.uuid = g.uuid, t[m] = x, x; } function r(f, m) { if (n[m] !== void 0) return n[m]; - let v = f.arrayBuffers[m], g = new Uint32Array(v).buffer; - return n[m] = g, g; + let g = f.arrayBuffers[m], p = new Uint32Array(g).buffer; + return n[m] = p, p; } - let o = e.isInstancedBufferGeometry ? new Ya : new _e, a = e.data.index; - if (a !== void 0) { - let f = wi(a.type, a.array); - o.setIndex(new Ue(f, 1)); + let a = e.isInstancedBufferGeometry ? new Dc : new Ge, o = e.data.index; + if (o !== void 0) { + let f = ki(o.type, o.array); + a.setIndex(new et(f, 1)); } - let l = e.data.attributes; - for(let f in l){ - let m = l[f], x; + let c = e.data.attributes; + for(let f in c){ + let m = c[f], _; if (m.isInterleavedBufferAttribute) { - let v = i(e.data, m.data); - x = new Sn(v, m.itemSize, m.offset, m.normalized); + let g = i(e.data, m.data); + _ = new Qi(g, m.itemSize, m.offset, m.normalized); } else { - let v = wi(m.type, m.array), g = m.isInstancedBufferAttribute ? Xn : Ue; - x = new g(v, m.itemSize, m.normalized); - } - m.name !== void 0 && (x.name = m.name), m.usage !== void 0 && x.setUsage(m.usage), m.updateRange !== void 0 && (x.updateRange.offset = m.updateRange.offset, x.updateRange.count = m.updateRange.count), o.setAttribute(f, x); - } - let c = e.data.morphAttributes; - if (c) for(let f in c){ - let m = c[f], x = []; - for(let v = 0, g = m.length; v < g; v++){ - let p = m[v], _; - if (p.isInterleavedBufferAttribute) { - let y = i(e.data, p.data); - _ = new Sn(y, p.itemSize, p.offset, p.normalized); + let g = ki(m.type, m.array), p = m.isInstancedBufferAttribute ? ui : et; + _ = new p(g, m.itemSize, m.normalized); + } + m.name !== void 0 && (_.name = m.name), m.usage !== void 0 && _.setUsage(m.usage), m.updateRange !== void 0 && (_.updateRange.offset = m.updateRange.offset, _.updateRange.count = m.updateRange.count), a.setAttribute(f, _); + } + let l = e.data.morphAttributes; + if (l) for(let f in l){ + let m = l[f], _ = []; + for(let g = 0, p = m.length; g < p; g++){ + let v = m[g], x; + if (v.isInterleavedBufferAttribute) { + let y = i(e.data, v.data); + x = new Qi(y, v.itemSize, v.offset, v.normalized); } else { - let y = wi(p.type, p.array); - _ = new Ue(y, p.itemSize, p.normalized); + let y = ki(v.type, v.array); + x = new et(y, v.itemSize, v.normalized); } - p.name !== void 0 && (_.name = p.name), x.push(_); + v.name !== void 0 && (x.name = v.name), _.push(x); } - o.morphAttributes[f] = x; + a.morphAttributes[f] = _; } - e.data.morphTargetsRelative && (o.morphTargetsRelative = !0); + e.data.morphTargetsRelative && (a.morphTargetsRelative = !0); let u = e.data.groups || e.data.drawcalls || e.data.offsets; if (u !== void 0) for(let f = 0, m = u.length; f !== m; ++f){ - let x = u[f]; - o.addGroup(x.start, x.count, x.materialIndex); + let _ = u[f]; + a.addGroup(_.start, _.count, _.materialIndex); } let d = e.data.boundingSphere; if (d !== void 0) { - let f = new M; - d.center !== void 0 && f.fromArray(d.center), o.boundingSphere = new An(f, d.radius); + let f = new A; + d.center !== void 0 && f.fromArray(d.center), a.boundingSphere = new Yt(f, d.radius); } - return e.name && (o.name = e.name), e.userData && (o.userData = e.userData), o; + return e.name && (a.name = e.name), e.userData && (a.userData = e.userData), a; } -}, uy = class extends bt { +}, pu = class extends Dt { constructor(e){ super(e); } load(e, t, n, i) { - let r = this, o = this.path === "" ? Gs.extractUrlBase(e) : this.path; - this.resourcePath = this.resourcePath || o; - let a = new Yt(this.manager); - a.setPath(this.path), a.setRequestHeader(this.requestHeader), a.setWithCredentials(this.withCredentials), a.load(e, function(l) { - let c = null; + let r = this, a = this.path === "" ? ga.extractUrlBase(e) : this.path; + this.resourcePath = this.resourcePath || a; + let o = new rn(this.manager); + o.setPath(this.path), o.setRequestHeader(this.requestHeader), o.setWithCredentials(this.withCredentials), o.load(e, function(c) { + let l = null; try { - c = JSON.parse(l); + l = JSON.parse(c); } catch (u) { i !== void 0 && i(u), console.error("THREE:ObjectLoader: Can't parse " + e + ".", u.message); return; } - let h = c.metadata; + let h = l.metadata; if (h === void 0 || h.type === void 0 || h.type.toLowerCase() === "geometry") { - console.error("THREE.ObjectLoader: Can't load " + e); + i !== void 0 && i(new Error("THREE.ObjectLoader: Can't load " + e)), console.error("THREE.ObjectLoader: Can't load " + e); return; } - r.parse(c, t); + r.parse(l, t); }, n, i); } async loadAsync(e, t) { - let n = this, i = this.path === "" ? Gs.extractUrlBase(e) : this.path; + let n = this, i = this.path === "" ? ga.extractUrlBase(e) : this.path; this.resourcePath = this.resourcePath || i; - let r = new Yt(this.manager); + let r = new rn(this.manager); r.setPath(this.path), r.setRequestHeader(this.requestHeader), r.setWithCredentials(this.withCredentials); - let o = await r.loadAsync(e, t), a = JSON.parse(o), l = a.metadata; - if (l === void 0 || l.type === void 0 || l.type.toLowerCase() === "geometry") throw new Error("THREE.ObjectLoader: Can't load " + e); - return await n.parseAsync(a); + let a = await r.loadAsync(e, t), o = JSON.parse(a), c = o.metadata; + if (c === void 0 || c.type === void 0 || c.type.toLowerCase() === "geometry") throw new Error("THREE.ObjectLoader: Can't load " + e); + return await n.parseAsync(o); } parse(e, t) { - let n = this.parseAnimations(e.animations), i = this.parseShapes(e.shapes), r = this.parseGeometries(e.geometries, i), o = this.parseImages(e.images, function() { - t !== void 0 && t(c); - }), a = this.parseTextures(e.textures, o), l = this.parseMaterials(e.materials, a), c = this.parseObject(e.object, r, l, a, n), h = this.parseSkeletons(e.skeletons, c); - if (this.bindSkeletons(c, h), t !== void 0) { + let n = this.parseAnimations(e.animations), i = this.parseShapes(e.shapes), r = this.parseGeometries(e.geometries, i), a = this.parseImages(e.images, function() { + t !== void 0 && t(l); + }), o = this.parseTextures(e.textures, a), c = this.parseMaterials(e.materials, o), l = this.parseObject(e.object, r, c, o, n), h = this.parseSkeletons(e.skeletons, l); + if (this.bindSkeletons(l, h), t !== void 0) { let u = !1; - for(let d in o)if (o[d] instanceof HTMLImageElement) { + for(let d in a)if (a[d].data instanceof HTMLImageElement) { u = !0; break; } - u === !1 && t(c); + u === !1 && t(l); } - return c; + return l; } async parseAsync(e) { - let t = this.parseAnimations(e.animations), n = this.parseShapes(e.shapes), i = this.parseGeometries(e.geometries, n), r = await this.parseImagesAsync(e.images), o = this.parseTextures(e.textures, r), a = this.parseMaterials(e.materials, o), l = this.parseObject(e.object, i, a, o, t), c = this.parseSkeletons(e.skeletons, l); - return this.bindSkeletons(l, c), l; + let t = this.parseAnimations(e.animations), n = this.parseShapes(e.shapes), i = this.parseGeometries(e.geometries, n), r = await this.parseImagesAsync(e.images), a = this.parseTextures(e.textures, r), o = this.parseMaterials(e.materials, a), c = this.parseObject(e.object, i, o, a, t), l = this.parseSkeletons(e.skeletons, c); + return this.bindSkeletons(c, l), c; } parseShapes(e) { let t = {}; if (e !== void 0) for(let n = 0, i = e.length; n < i; n++){ - let r = new Xt().fromJSON(e[n]); + let r = new Fn().fromJSON(e[n]); t[r.uuid] = r; } return t; @@ -15835,30 +17429,27 @@ var Uh = class extends bt { let n = {}, i = {}; if (t.traverse(function(r) { r.isBone && (i[r.uuid] = r); - }), e !== void 0) for(let r = 0, o = e.length; r < o; r++){ - let a = new ao().fromJSON(e[r], i); - n[a.uuid] = a; + }), e !== void 0) for(let r = 0, a = e.length; r < a; r++){ + let o = new Oo().fromJSON(e[r], i); + n[o.uuid] = o; } return n; } parseGeometries(e, t) { let n = {}; if (e !== void 0) { - let i = new Uh; - for(let r = 0, o = e.length; r < o; r++){ - let a, l = e[r]; - switch(l.type){ + let i = new Nc; + for(let r = 0, a = e.length; r < a; r++){ + let o, c = e[r]; + switch(c.type){ case "BufferGeometry": case "InstancedBufferGeometry": - a = i.parse(l); - break; - case "Geometry": - console.error("THREE.ObjectLoader: The legacy Geometry type is no longer supported."); + o = i.parse(c); break; default: - l.type in vc ? a = vc[l.type].fromJSON(l, t) : console.warn(`THREE.ObjectLoader: Unsupported geometry type "${l.type}"`); + c.type in ru ? o = ru[c.type].fromJSON(c, t) : console.warn(`THREE.ObjectLoader: Unsupported geometry type "${c.type}"`); } - a.uuid = l.uuid, l.name !== void 0 && (a.name = l.name), a.isBufferGeometry === !0 && l.userData !== void 0 && (a.userData = l.userData), n[l.uuid] = a; + o.uuid = c.uuid, c.name !== void 0 && (o.name = c.name), c.userData !== void 0 && (o.userData = c.userData), n[c.uuid] = o; } } return n; @@ -15866,18 +17457,11 @@ var Uh = class extends bt { parseMaterials(e, t) { let n = {}, i = {}; if (e !== void 0) { - let r = new zh; + let r = new Uc; r.setTextures(t); - for(let o = 0, a = e.length; o < a; o++){ - let l = e[o]; - if (l.type === "MultiMaterial") { - let c = []; - for(let h = 0; h < l.materials.length; h++){ - let u = l.materials[h]; - n[u.uuid] === void 0 && (n[u.uuid] = r.parse(u)), c.push(n[u.uuid]); - } - i[l.uuid] = c; - } else n[l.uuid] === void 0 && (n[l.uuid] = r.parse(l)), i[l.uuid] = n[l.uuid]; + for(let a = 0, o = e.length; a < o; a++){ + let c = e[a]; + n[c.uuid] === void 0 && (n[c.uuid] = r.parse(c)), i[c.uuid] = n[c.uuid]; } } return i; @@ -15885,44 +17469,45 @@ var Uh = class extends bt { parseAnimations(e) { let t = {}; if (e !== void 0) for(let n = 0; n < e.length; n++){ - let i = e[n], r = Lr.parse(i); + let i = e[n], r = is.parse(i); t[r.uuid] = r; } return t; } parseImages(e, t) { let n = this, i = {}, r; - function o(l) { - return n.manager.itemStart(l), r.load(l, function() { - n.manager.itemEnd(l); + function a(c) { + return n.manager.itemStart(c), r.load(c, function() { + n.manager.itemEnd(c); }, void 0, function() { - n.manager.itemError(l), n.manager.itemEnd(l); + n.manager.itemError(c), n.manager.itemEnd(c); }); } - function a(l) { - if (typeof l == "string") { - let c = l, h = /^(\/\/)|([a-z]+:(\/\/)?)/i.test(c) ? c : n.resourcePath + c; - return o(h); - } else return l.data ? { - data: wi(l.type, l.data), - width: l.width, - height: l.height + function o(c) { + if (typeof c == "string") { + let l = c, h = /^(\/\/)|([a-z]+:(\/\/)?)/i.test(l) ? l : n.resourcePath + l; + return a(h); + } else return c.data ? { + data: ki(c.type, c.data), + width: c.width, + height: c.height } : null; } if (e !== void 0 && e.length > 0) { - let l = new za(t); - r = new Rr(l), r.setCrossOrigin(this.crossOrigin); - for(let c = 0, h = e.length; c < h; c++){ - let u = e[c], d = u.url; + let c = new ma(t); + r = new rs(c), r.setCrossOrigin(this.crossOrigin); + for(let l = 0, h = e.length; l < h; l++){ + let u = e[l], d = u.url; if (Array.isArray(d)) { - i[u.uuid] = []; - for(let f = 0, m = d.length; f < m; f++){ - let x = d[f], v = a(x); - v !== null && (v instanceof HTMLImageElement ? i[u.uuid].push(v) : i[u.uuid].push(new qn(v.data, v.width, v.height))); + let f = []; + for(let m = 0, _ = d.length; m < _; m++){ + let g = d[m], p = o(g); + p !== null && (p instanceof HTMLImageElement ? f.push(p) : f.push(new oi(p.data, p.width, p.height))); } + i[u.uuid] = new In(f); } else { - let f = a(u.url); - f !== null && (i[u.uuid] = f); + let f = o(u.url); + i[u.uuid] = new In(f); } } } @@ -15930,159 +17515,160 @@ var Uh = class extends bt { } async parseImagesAsync(e) { let t = this, n = {}, i; - async function r(o) { - if (typeof o == "string") { - let a = o, l = /^(\/\/)|([a-z]+:(\/\/)?)/i.test(a) ? a : t.resourcePath + a; - return await i.loadAsync(l); - } else return o.data ? { - data: wi(o.type, o.data), - width: o.width, - height: o.height + async function r(a) { + if (typeof a == "string") { + let o = a, c = /^(\/\/)|([a-z]+:(\/\/)?)/i.test(o) ? o : t.resourcePath + o; + return await i.loadAsync(c); + } else return a.data ? { + data: ki(a.type, a.data), + width: a.width, + height: a.height } : null; } if (e !== void 0 && e.length > 0) { - i = new Rr(this.manager), i.setCrossOrigin(this.crossOrigin); - for(let o = 0, a = e.length; o < a; o++){ - let l = e[o], c = l.url; - if (Array.isArray(c)) { - n[l.uuid] = []; - for(let h = 0, u = c.length; h < u; h++){ - let d = c[h], f = await r(d); - f !== null && (f instanceof HTMLImageElement ? n[l.uuid].push(f) : n[l.uuid].push(new qn(f.data, f.width, f.height))); + i = new rs(this.manager), i.setCrossOrigin(this.crossOrigin); + for(let a = 0, o = e.length; a < o; a++){ + let c = e[a], l = c.url; + if (Array.isArray(l)) { + let h = []; + for(let u = 0, d = l.length; u < d; u++){ + let f = l[u], m = await r(f); + m !== null && (m instanceof HTMLImageElement ? h.push(m) : h.push(new oi(m.data, m.width, m.height))); } + n[c.uuid] = new In(h); } else { - let h = await r(l.url); - h !== null && (n[l.uuid] = h); + let h = await r(c.url); + n[c.uuid] = new In(h); } } } return n; } parseTextures(e, t) { - function n(r, o) { - return typeof r == "number" ? r : (console.warn("THREE.ObjectLoader.parseTexture: Constant should be in numeric form.", r), o[r]); + function n(r, a) { + return typeof r == "number" ? r : (console.warn("THREE.ObjectLoader.parseTexture: Constant should be in numeric form.", r), a[r]); } let i = {}; - if (e !== void 0) for(let r = 0, o = e.length; r < o; r++){ - let a = e[r]; - a.image === void 0 && console.warn('THREE.ObjectLoader: No "image" specified for', a.uuid), t[a.image] === void 0 && console.warn("THREE.ObjectLoader: Undefined image", a.image); - let l, c = t[a.image]; - Array.isArray(c) ? (l = new ki(c), c.length === 6 && (l.needsUpdate = !0)) : (c && c.data ? l = new qn(c.data, c.width, c.height) : l = new ot(c), c && (l.needsUpdate = !0)), l.uuid = a.uuid, a.name !== void 0 && (l.name = a.name), a.mapping !== void 0 && (l.mapping = n(a.mapping, dy)), a.offset !== void 0 && l.offset.fromArray(a.offset), a.repeat !== void 0 && l.repeat.fromArray(a.repeat), a.center !== void 0 && l.center.fromArray(a.center), a.rotation !== void 0 && (l.rotation = a.rotation), a.wrap !== void 0 && (l.wrapS = n(a.wrap[0], Sc), l.wrapT = n(a.wrap[1], Sc)), a.format !== void 0 && (l.format = a.format), a.type !== void 0 && (l.type = a.type), a.encoding !== void 0 && (l.encoding = a.encoding), a.minFilter !== void 0 && (l.minFilter = n(a.minFilter, Tc)), a.magFilter !== void 0 && (l.magFilter = n(a.magFilter, Tc)), a.anisotropy !== void 0 && (l.anisotropy = a.anisotropy), a.flipY !== void 0 && (l.flipY = a.flipY), a.premultiplyAlpha !== void 0 && (l.premultiplyAlpha = a.premultiplyAlpha), a.unpackAlignment !== void 0 && (l.unpackAlignment = a.unpackAlignment), a.userData !== void 0 && (l.userData = a.userData), i[a.uuid] = l; + if (e !== void 0) for(let r = 0, a = e.length; r < a; r++){ + let o = e[r]; + o.image === void 0 && console.warn('THREE.ObjectLoader: No "image" specified for', o.uuid), t[o.image] === void 0 && console.warn("THREE.ObjectLoader: Undefined image", o.image); + let c = t[o.image], l = c.data, h; + Array.isArray(l) ? (h = new Ki, l.length === 6 && (h.needsUpdate = !0)) : (l && l.data ? h = new oi : h = new St, l && (h.needsUpdate = !0)), h.source = c, h.uuid = o.uuid, o.name !== void 0 && (h.name = o.name), o.mapping !== void 0 && (h.mapping = n(o.mapping, Tx)), o.channel !== void 0 && (h.channel = o.channel), o.offset !== void 0 && h.offset.fromArray(o.offset), o.repeat !== void 0 && h.repeat.fromArray(o.repeat), o.center !== void 0 && h.center.fromArray(o.center), o.rotation !== void 0 && (h.rotation = o.rotation), o.wrap !== void 0 && (h.wrapS = n(o.wrap[0], mu), h.wrapT = n(o.wrap[1], mu)), o.format !== void 0 && (h.format = o.format), o.internalFormat !== void 0 && (h.internalFormat = o.internalFormat), o.type !== void 0 && (h.type = o.type), o.colorSpace !== void 0 && (h.colorSpace = o.colorSpace), o.encoding !== void 0 && (h.encoding = o.encoding), o.minFilter !== void 0 && (h.minFilter = n(o.minFilter, gu)), o.magFilter !== void 0 && (h.magFilter = n(o.magFilter, gu)), o.anisotropy !== void 0 && (h.anisotropy = o.anisotropy), o.flipY !== void 0 && (h.flipY = o.flipY), o.generateMipmaps !== void 0 && (h.generateMipmaps = o.generateMipmaps), o.premultiplyAlpha !== void 0 && (h.premultiplyAlpha = o.premultiplyAlpha), o.unpackAlignment !== void 0 && (h.unpackAlignment = o.unpackAlignment), o.compareFunction !== void 0 && (h.compareFunction = o.compareFunction), o.userData !== void 0 && (h.userData = o.userData), i[o.uuid] = h; } return i; } parseObject(e, t, n, i, r) { - let o; - function a(d) { + let a; + function o(d) { return t[d] === void 0 && console.warn("THREE.ObjectLoader: Undefined geometry", d), t[d]; } - function l(d) { + function c(d) { if (d !== void 0) { if (Array.isArray(d)) { let f = []; - for(let m = 0, x = d.length; m < x; m++){ - let v = d[m]; - n[v] === void 0 && console.warn("THREE.ObjectLoader: Undefined material", v), f.push(n[v]); + for(let m = 0, _ = d.length; m < _; m++){ + let g = d[m]; + n[g] === void 0 && console.warn("THREE.ObjectLoader: Undefined material", g), f.push(n[g]); } return f; } return n[d] === void 0 && console.warn("THREE.ObjectLoader: Undefined material", d), n[d]; } } - function c(d) { + function l(d) { return i[d] === void 0 && console.warn("THREE.ObjectLoader: Undefined texture", d), i[d]; } let h, u; switch(e.type){ case "Scene": - o = new no, e.background !== void 0 && (Number.isInteger(e.background) ? o.background = new ae(e.background) : o.background = c(e.background)), e.environment !== void 0 && (o.environment = c(e.environment)), e.fog !== void 0 && (e.fog.type === "Fog" ? o.fog = new Br(e.fog.color, e.fog.near, e.fog.far) : e.fog.type === "FogExp2" && (o.fog = new Nr(e.fog.color, e.fog.density))); + a = new Io, e.background !== void 0 && (Number.isInteger(e.background) ? a.background = new pe(e.background) : a.background = l(e.background)), e.environment !== void 0 && (a.environment = l(e.environment)), e.fog !== void 0 && (e.fog.type === "Fog" ? a.fog = new Lo(e.fog.color, e.fog.near, e.fog.far) : e.fog.type === "FogExp2" && (a.fog = new Po(e.fog.color, e.fog.density)), e.fog.name !== "" && (a.fog.name = e.fog.name)), e.backgroundBlurriness !== void 0 && (a.backgroundBlurriness = e.backgroundBlurriness), e.backgroundIntensity !== void 0 && (a.backgroundIntensity = e.backgroundIntensity); break; case "PerspectiveCamera": - o = new ut(e.fov, e.aspect, e.near, e.far), e.focus !== void 0 && (o.focus = e.focus), e.zoom !== void 0 && (o.zoom = e.zoom), e.filmGauge !== void 0 && (o.filmGauge = e.filmGauge), e.filmOffset !== void 0 && (o.filmOffset = e.filmOffset), e.view !== void 0 && (o.view = Object.assign({}, e.view)); + a = new yt(e.fov, e.aspect, e.near, e.far), e.focus !== void 0 && (a.focus = e.focus), e.zoom !== void 0 && (a.zoom = e.zoom), e.filmGauge !== void 0 && (a.filmGauge = e.filmGauge), e.filmOffset !== void 0 && (a.filmOffset = e.filmOffset), e.view !== void 0 && (a.view = Object.assign({}, e.view)); break; case "OrthographicCamera": - o = new Fr(e.left, e.right, e.top, e.bottom, e.near, e.far), e.zoom !== void 0 && (o.zoom = e.zoom), e.view !== void 0 && (o.view = Object.assign({}, e.view)); + a = new Ls(e.left, e.right, e.top, e.bottom, e.near, e.far), e.zoom !== void 0 && (a.zoom = e.zoom), e.view !== void 0 && (a.view = Object.assign({}, e.view)); break; case "AmbientLight": - o = new qa(e.color, e.intensity); + a = new Cc(e.color, e.intensity); break; case "DirectionalLight": - o = new Wa(e.color, e.intensity); + a = new Rc(e.color, e.intensity); break; case "PointLight": - o = new Ga(e.color, e.intensity, e.distance, e.decay); + a = new wc(e.color, e.intensity, e.distance, e.decay); break; case "RectAreaLight": - o = new Xa(e.color, e.intensity, e.width, e.height); + a = new Pc(e.color, e.intensity, e.width, e.height); break; case "SpotLight": - o = new Ha(e.color, e.intensity, e.distance, e.angle, e.penumbra, e.decay); + a = new Ec(e.color, e.intensity, e.distance, e.angle, e.penumbra, e.decay); break; case "HemisphereLight": - o = new Ua(e.color, e.groundColor, e.intensity); + a = new Sc(e.color, e.groundColor, e.intensity); break; case "LightProbe": - o = new Hr().fromJSON(e); + a = new Ic().fromJSON(e); break; case "SkinnedMesh": - h = a(e.geometry), u = l(e.material), o = new so(h, u), e.bindMode !== void 0 && (o.bindMode = e.bindMode), e.bindMatrix !== void 0 && o.bindMatrix.fromArray(e.bindMatrix), e.skeleton !== void 0 && (o.skeleton = e.skeleton); + h = o(e.geometry), u = c(e.material), a = new No(h, u), e.bindMode !== void 0 && (a.bindMode = e.bindMode), e.bindMatrix !== void 0 && a.bindMatrix.fromArray(e.bindMatrix), e.skeleton !== void 0 && (a.skeleton = e.skeleton); break; case "Mesh": - h = a(e.geometry), u = l(e.material), o = new st(h, u); + h = o(e.geometry), u = c(e.material), a = new Mt(h, u); break; case "InstancedMesh": - h = a(e.geometry), u = l(e.material); + h = o(e.geometry), u = c(e.material); let d = e.count, f = e.instanceMatrix, m = e.instanceColor; - o = new xa(h, u, d), o.instanceMatrix = new Xn(new Float32Array(f.array), 16), m !== void 0 && (o.instanceColor = new Xn(new Float32Array(m.array), m.itemSize)); + a = new Fo(h, u, d), a.instanceMatrix = new ui(new Float32Array(f.array), 16), m !== void 0 && (a.instanceColor = new ui(new Float32Array(m.array), m.itemSize)); break; case "LOD": - o = new bh; + a = new Do; break; case "Line": - o = new on(a(e.geometry), l(e.material)); + a = new bn(o(e.geometry), c(e.material)); break; case "LineLoop": - o = new ya(a(e.geometry), l(e.material)); + a = new Bo(o(e.geometry), c(e.material)); break; case "LineSegments": - o = new wt(a(e.geometry), l(e.material)); + a = new en(o(e.geometry), c(e.material)); break; case "PointCloud": case "Points": - o = new zr(a(e.geometry), l(e.material)); + a = new Vo(o(e.geometry), c(e.material)); break; case "Sprite": - o = new ro(l(e.material)); + a = new Uo(c(e.material)); break; case "Group": - o = new Hn; + a = new ti; break; case "Bone": - o = new oo; + a = new ta; break; default: - o = new Ne; + a = new Je; } - if (o.uuid = e.uuid, e.name !== void 0 && (o.name = e.name), e.matrix !== void 0 ? (o.matrix.fromArray(e.matrix), e.matrixAutoUpdate !== void 0 && (o.matrixAutoUpdate = e.matrixAutoUpdate), o.matrixAutoUpdate && o.matrix.decompose(o.position, o.quaternion, o.scale)) : (e.position !== void 0 && o.position.fromArray(e.position), e.rotation !== void 0 && o.rotation.fromArray(e.rotation), e.quaternion !== void 0 && o.quaternion.fromArray(e.quaternion), e.scale !== void 0 && o.scale.fromArray(e.scale)), e.castShadow !== void 0 && (o.castShadow = e.castShadow), e.receiveShadow !== void 0 && (o.receiveShadow = e.receiveShadow), e.shadow && (e.shadow.bias !== void 0 && (o.shadow.bias = e.shadow.bias), e.shadow.normalBias !== void 0 && (o.shadow.normalBias = e.shadow.normalBias), e.shadow.radius !== void 0 && (o.shadow.radius = e.shadow.radius), e.shadow.mapSize !== void 0 && o.shadow.mapSize.fromArray(e.shadow.mapSize), e.shadow.camera !== void 0 && (o.shadow.camera = this.parseObject(e.shadow.camera))), e.visible !== void 0 && (o.visible = e.visible), e.frustumCulled !== void 0 && (o.frustumCulled = e.frustumCulled), e.renderOrder !== void 0 && (o.renderOrder = e.renderOrder), e.userData !== void 0 && (o.userData = e.userData), e.layers !== void 0 && (o.layers.mask = e.layers), e.children !== void 0) { + if (a.uuid = e.uuid, e.name !== void 0 && (a.name = e.name), e.matrix !== void 0 ? (a.matrix.fromArray(e.matrix), e.matrixAutoUpdate !== void 0 && (a.matrixAutoUpdate = e.matrixAutoUpdate), a.matrixAutoUpdate && a.matrix.decompose(a.position, a.quaternion, a.scale)) : (e.position !== void 0 && a.position.fromArray(e.position), e.rotation !== void 0 && a.rotation.fromArray(e.rotation), e.quaternion !== void 0 && a.quaternion.fromArray(e.quaternion), e.scale !== void 0 && a.scale.fromArray(e.scale)), e.up !== void 0 && a.up.fromArray(e.up), e.castShadow !== void 0 && (a.castShadow = e.castShadow), e.receiveShadow !== void 0 && (a.receiveShadow = e.receiveShadow), e.shadow && (e.shadow.bias !== void 0 && (a.shadow.bias = e.shadow.bias), e.shadow.normalBias !== void 0 && (a.shadow.normalBias = e.shadow.normalBias), e.shadow.radius !== void 0 && (a.shadow.radius = e.shadow.radius), e.shadow.mapSize !== void 0 && a.shadow.mapSize.fromArray(e.shadow.mapSize), e.shadow.camera !== void 0 && (a.shadow.camera = this.parseObject(e.shadow.camera))), e.visible !== void 0 && (a.visible = e.visible), e.frustumCulled !== void 0 && (a.frustumCulled = e.frustumCulled), e.renderOrder !== void 0 && (a.renderOrder = e.renderOrder), e.userData !== void 0 && (a.userData = e.userData), e.layers !== void 0 && (a.layers.mask = e.layers), e.children !== void 0) { let d = e.children; - for(let f = 0; f < d.length; f++)o.add(this.parseObject(d[f], t, n, i, r)); + for(let f = 0; f < d.length; f++)a.add(this.parseObject(d[f], t, n, i, r)); } if (e.animations !== void 0) { let d = e.animations; for(let f = 0; f < d.length; f++){ let m = d[f]; - o.animations.push(r[m]); + a.animations.push(r[m]); } } if (e.type === "LOD") { - e.autoUpdate !== void 0 && (o.autoUpdate = e.autoUpdate); + e.autoUpdate !== void 0 && (a.autoUpdate = e.autoUpdate); let d = e.levels; for(let f = 0; f < d.length; f++){ - let m = d[f], x = o.getObjectByProperty("uuid", m.object); - x !== void 0 && o.addLevel(x, m.distance); + let m = d[f], _ = a.getObjectByProperty("uuid", m.object); + _ !== void 0 && a.addLevel(_, m.distance, m.hysteresis); } } - return o; + return a; } bindSkeletons(e, t) { Object.keys(t).length !== 0 && e.traverse(function(n) { @@ -16092,32 +17678,27 @@ var Uh = class extends bt { } }); } - setTexturePath(e) { - return console.warn("THREE.ObjectLoader: .setTexturePath() has been renamed to .setResourcePath()."), this.setResourcePath(e); - } -}, dy = { - UVMapping: ha, - CubeReflectionMapping: Bi, - CubeRefractionMapping: zi, - EquirectangularReflectionMapping: Ds, - EquirectangularRefractionMapping: Fs, - CubeUVReflectionMapping: Pr, - CubeUVRefractionMapping: Ws -}, Sc = { - RepeatWrapping: Ns, - ClampToEdgeWrapping: vt, - MirroredRepeatWrapping: Bs -}, Tc = { - NearestFilter: rt, - NearestMipmapNearestFilter: ta, - NearestMipmapLinearFilter: na, - LinearFilter: tt, - LinearMipmapNearestFilter: Wc, - LinearMipmapLinearFilter: Ui -}, Oh = class extends bt { +}, Tx = { + UVMapping: Gc, + CubeReflectionMapping: zn, + CubeRefractionMapping: ci, + EquirectangularReflectionMapping: Ir, + EquirectangularRefractionMapping: Ur, + CubeUVReflectionMapping: Vs +}, mu = { + RepeatWrapping: Dr, + ClampToEdgeWrapping: It, + MirroredRepeatWrapping: Nr +}, gu = { + NearestFilter: pt, + NearestMipmapNearestFilter: fo, + NearestMipmapLinearFilter: Lr, + LinearFilter: mt, + LinearMipmapNearestFilter: ud, + LinearMipmapLinearFilter: li +}, _u = class extends Dt { constructor(e){ - super(e); - typeof createImageBitmap > "u" && console.warn("THREE.ImageBitmapLoader: createImageBitmap() not supported."), typeof fetch > "u" && console.warn("THREE.ImageBitmapLoader: fetch() not supported."), this.options = { + super(e), this.isImageBitmapLoader = !0, typeof createImageBitmap > "u" && console.warn("THREE.ImageBitmapLoader: createImageBitmap() not supported."), typeof fetch > "u" && console.warn("THREE.ImageBitmapLoader: fetch() not supported."), this.options = { premultiplyAlpha: "none" }; } @@ -16126,68 +17707,53 @@ var Uh = class extends bt { } load(e, t, n, i) { e === void 0 && (e = ""), this.path !== void 0 && (e = this.path + e), e = this.manager.resolveURL(e); - let r = this, o = Ni.get(e); - if (o !== void 0) return r.manager.itemStart(e), setTimeout(function() { - t && t(o), r.manager.itemEnd(e); - }, 0), o; - let a = {}; - a.credentials = this.crossOrigin === "anonymous" ? "same-origin" : "include", a.headers = this.requestHeader, fetch(e, a).then(function(l) { - return l.blob(); - }).then(function(l) { - return createImageBitmap(l, Object.assign(r.options, { + let r = this, a = ss.get(e); + if (a !== void 0) return r.manager.itemStart(e), setTimeout(function() { + t && t(a), r.manager.itemEnd(e); + }, 0), a; + let o = {}; + o.credentials = this.crossOrigin === "anonymous" ? "same-origin" : "include", o.headers = this.requestHeader, fetch(e, o).then(function(c) { + return c.blob(); + }).then(function(c) { + return createImageBitmap(c, Object.assign(r.options, { colorSpaceConversion: "none" })); - }).then(function(l) { - Ni.add(e, l), t && t(l), r.manager.itemEnd(e); - }).catch(function(l) { - i && i(l), r.manager.itemError(e), r.manager.itemEnd(e); + }).then(function(c) { + ss.add(e, c), t && t(c), r.manager.itemEnd(e); + }).catch(function(c) { + i && i(c), r.manager.itemError(e), r.manager.itemEnd(e); }), r.manager.itemStart(e); } -}; -Oh.prototype.isImageBitmapLoader = !0; -var Ss, Hh = { - getContext: function() { - return Ss === void 0 && (Ss = new (window.AudioContext || window.webkitAudioContext)), Ss; - }, - setContext: function(s) { - Ss = s; +}, Er, _a = class { + static getContext() { + return Er === void 0 && (Er = new (window.AudioContext || window.webkitAudioContext)), Er; + } + static setContext(e) { + Er = e; } -}, kh = class extends bt { +}, xu = class extends Dt { constructor(e){ super(e); } load(e, t, n, i) { - let r = this, o = new Yt(this.manager); - o.setResponseType("arraybuffer"), o.setPath(this.path), o.setRequestHeader(this.requestHeader), o.setWithCredentials(this.withCredentials), o.load(e, function(a) { + let r = this, a = new rn(this.manager); + a.setResponseType("arraybuffer"), a.setPath(this.path), a.setRequestHeader(this.requestHeader), a.setWithCredentials(this.withCredentials), a.load(e, function(c) { try { - let l = a.slice(0); - Hh.getContext().decodeAudioData(l, function(h) { - t(h); - }); + let l = c.slice(0); + _a.getContext().decodeAudioData(l, function(u) { + t(u); + }, o); } catch (l) { - i ? i(l) : console.error(l), r.manager.itemError(e); + o(l); } }, n, i); + function o(c) { + i ? i(c) : console.error(c), r.manager.itemError(e); + } } -}, Gh = class extends Hr { - constructor(e, t, n = 1){ - super(void 0, n); - let i = new ae().set(e), r = new ae().set(t), o = new M(i.r, i.g, i.b), a = new M(r.r, r.g, r.b), l = Math.sqrt(Math.PI), c = l * Math.sqrt(.75); - this.sh.coefficients[0].copy(o).add(a).multiplyScalar(l), this.sh.coefficients[1].copy(o).sub(a).multiplyScalar(c); - } -}; -Gh.prototype.isHemisphereLightProbe = !0; -var Vh = class extends Hr { - constructor(e, t = 1){ - super(void 0, t); - let n = new ae().set(e); - this.sh.coefficients[0].set(n.r, n.g, n.b).multiplyScalar(2 * Math.sqrt(Math.PI)); - } -}; -Vh.prototype.isAmbientLightProbe = !0; -var Ec = new pe, Ac = new pe, Fn = new pe, fy = class { +}, vu = new ze, yu = new ze, Zn = new ze, Mu = class { constructor(){ - this.type = "StereoCamera", this.aspect = 1, this.eyeSep = .064, this.cameraL = new ut, this.cameraL.layers.enable(1), this.cameraL.matrixAutoUpdate = !1, this.cameraR = new ut, this.cameraR.layers.enable(2), this.cameraR.matrixAutoUpdate = !1, this._cache = { + this.type = "StereoCamera", this.aspect = 1, this.eyeSep = .064, this.cameraL = new yt, this.cameraL.layers.enable(1), this.cameraL.matrixAutoUpdate = !1, this.cameraR = new yt, this.cameraR.layers.enable(2), this.cameraR.matrixAutoUpdate = !1, this._cache = { focus: null, fov: null, aspect: null, @@ -16200,18 +17766,18 @@ var Ec = new pe, Ac = new pe, Fn = new pe, fy = class { update(e) { let t = this._cache; if (t.focus !== e.focus || t.fov !== e.fov || t.aspect !== e.aspect * this.aspect || t.near !== e.near || t.far !== e.far || t.zoom !== e.zoom || t.eyeSep !== this.eyeSep) { - t.focus = e.focus, t.fov = e.fov, t.aspect = e.aspect * this.aspect, t.near = e.near, t.far = e.far, t.zoom = e.zoom, t.eyeSep = this.eyeSep, Fn.copy(e.projectionMatrix); - let i = t.eyeSep / 2, r = i * t.near / t.focus, o = t.near * Math.tan(Wn * t.fov * .5) / t.zoom, a, l; - Ac.elements[12] = -i, Ec.elements[12] = i, a = -o * t.aspect + r, l = o * t.aspect + r, Fn.elements[0] = 2 * t.near / (l - a), Fn.elements[8] = (l + a) / (l - a), this.cameraL.projectionMatrix.copy(Fn), a = -o * t.aspect - r, l = o * t.aspect - r, Fn.elements[0] = 2 * t.near / (l - a), Fn.elements[8] = (l + a) / (l - a), this.cameraR.projectionMatrix.copy(Fn); + t.focus = e.focus, t.fov = e.fov, t.aspect = e.aspect * this.aspect, t.near = e.near, t.far = e.far, t.zoom = e.zoom, t.eyeSep = this.eyeSep, Zn.copy(e.projectionMatrix); + let i = t.eyeSep / 2, r = i * t.near / t.focus, a = t.near * Math.tan(ai * t.fov * .5) / t.zoom, o, c; + yu.elements[12] = -i, vu.elements[12] = i, o = -a * t.aspect + r, c = a * t.aspect + r, Zn.elements[0] = 2 * t.near / (c - o), Zn.elements[8] = (c + o) / (c - o), this.cameraL.projectionMatrix.copy(Zn), o = -a * t.aspect - r, c = a * t.aspect - r, Zn.elements[0] = 2 * t.near / (c - o), Zn.elements[8] = (c + o) / (c - o), this.cameraR.projectionMatrix.copy(Zn); } - this.cameraL.matrixWorld.copy(e.matrixWorld).multiply(Ac), this.cameraR.matrixWorld.copy(e.matrixWorld).multiply(Ec); + this.cameraL.matrixWorld.copy(e.matrixWorld).multiply(yu), this.cameraR.matrixWorld.copy(e.matrixWorld).multiply(vu); } -}, Wh = class { +}, Oc = class { constructor(e = !0){ this.autoStart = e, this.startTime = 0, this.oldTime = 0, this.elapsedTime = 0, this.running = !1; } start() { - this.startTime = Cc(), this.oldTime = this.startTime, this.elapsedTime = 0, this.running = !0; + this.startTime = Su(), this.oldTime = this.startTime, this.elapsedTime = 0, this.running = !0; } stop() { this.getElapsedTime(), this.running = !1, this.autoStart = !1; @@ -16223,19 +17789,18 @@ var Ec = new pe, Ac = new pe, Fn = new pe, fy = class { let e = 0; if (this.autoStart && !this.running) return this.start(), 0; if (this.running) { - let t = Cc(); + let t = Su(); e = (t - this.oldTime) / 1e3, this.oldTime = t, this.elapsedTime += e; } return e; } }; -function Cc() { +function Su() { return (typeof performance > "u" ? Date : performance).now(); } -var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { +var Jn = new A, bu = new Ut, wx = new A, $n = new A, Eu = class extends Je { constructor(){ - super(); - this.type = "AudioListener", this.context = Hh.getContext(), this.gain = this.context.createGain(), this.gain.connect(this.context.destination), this.filter = null, this.timeDelta = 0, this._clock = new Wh; + super(), this.type = "AudioListener", this.context = _a.getContext(), this.gain = this.context.createGain(), this.gain.connect(this.context.destination), this.filter = null, this.timeDelta = 0, this._clock = new Oc; } getInput() { return this.gain; @@ -16258,15 +17823,14 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { updateMatrixWorld(e) { super.updateMatrixWorld(e); let t = this.context.listener, n = this.up; - if (this.timeDelta = this._clock.getDelta(), this.matrixWorld.decompose(Nn, Lc, py), Bn.set(0, 0, -1).applyQuaternion(Lc), t.positionX) { + if (this.timeDelta = this._clock.getDelta(), this.matrixWorld.decompose(Jn, bu, wx), $n.set(0, 0, -1).applyQuaternion(bu), t.positionX) { let i = this.context.currentTime + this.timeDelta; - t.positionX.linearRampToValueAtTime(Nn.x, i), t.positionY.linearRampToValueAtTime(Nn.y, i), t.positionZ.linearRampToValueAtTime(Nn.z, i), t.forwardX.linearRampToValueAtTime(Bn.x, i), t.forwardY.linearRampToValueAtTime(Bn.y, i), t.forwardZ.linearRampToValueAtTime(Bn.z, i), t.upX.linearRampToValueAtTime(n.x, i), t.upY.linearRampToValueAtTime(n.y, i), t.upZ.linearRampToValueAtTime(n.z, i); - } else t.setPosition(Nn.x, Nn.y, Nn.z), t.setOrientation(Bn.x, Bn.y, Bn.z, n.x, n.y, n.z); + t.positionX.linearRampToValueAtTime(Jn.x, i), t.positionY.linearRampToValueAtTime(Jn.y, i), t.positionZ.linearRampToValueAtTime(Jn.z, i), t.forwardX.linearRampToValueAtTime($n.x, i), t.forwardY.linearRampToValueAtTime($n.y, i), t.forwardZ.linearRampToValueAtTime($n.z, i), t.upX.linearRampToValueAtTime(n.x, i), t.upY.linearRampToValueAtTime(n.y, i), t.upZ.linearRampToValueAtTime(n.z, i); + } else t.setPosition(Jn.x, Jn.y, Jn.z), t.setOrientation($n.x, $n.y, $n.z, n.x, n.y, n.z); } -}, Za = class extends Ne { +}, Fc = class extends Je { constructor(e){ - super(); - this.type = "Audio", this.listener = e, this.context = e.context, this.gain = this.context.createGain(), this.gain.connect(e.getInput()), this.autoplay = !1, this.buffer = null, this.detune = 0, this.loop = !1, this.loopStart = 0, this.loopEnd = 0, this.offset = 0, this.duration = void 0, this.playbackRate = 1, this.isPlaying = !1, this.hasPlaybackControl = !0, this.source = null, this.sourceType = "empty", this._startedAt = 0, this._progress = 0, this._connected = !1, this.filters = []; + super(), this.type = "Audio", this.listener = e, this.context = e.context, this.gain = this.context.createGain(), this.gain.connect(e.getInput()), this.autoplay = !1, this.buffer = null, this.detune = 0, this.loop = !1, this.loopStart = 0, this.loopEnd = 0, this.offset = 0, this.duration = void 0, this.playbackRate = 1, this.isPlaying = !1, this.hasPlaybackControl = !0, this.source = null, this.sourceType = "empty", this._startedAt = 0, this._progress = 0, this._connected = !1, this.filters = []; } getOutput() { return this.gain; @@ -16308,7 +17872,7 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { console.warn("THREE.Audio: this Audio has no playback control."); return; } - return this._progress = 0, this.source.stop(), this.source.onended = null, this.isPlaying = !1, this; + return this._progress = 0, this.source !== null && (this.source.stop(), this.source.onended = null), this.isPlaying = !1, this; } connect() { if (this.filters.length > 0) { @@ -16319,12 +17883,14 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { return this._connected = !0, this; } disconnect() { - if (this.filters.length > 0) { - this.source.disconnect(this.filters[0]); - for(let e = 1, t = this.filters.length; e < t; e++)this.filters[e - 1].disconnect(this.filters[e]); - this.filters[this.filters.length - 1].disconnect(this.getOutput()); - } else this.source.disconnect(this.getOutput()); - return this._connected = !1, this; + if (this._connected !== !1) { + if (this.filters.length > 0) { + this.source.disconnect(this.filters[0]); + for(let e = 1, t = this.filters.length; e < t; e++)this.filters[e - 1].disconnect(this.filters[e]); + this.filters[this.filters.length - 1].disconnect(this.getOutput()); + } else this.source.disconnect(this.getOutput()); + return this._connected = !1, this; + } } getFilters() { return this.filters; @@ -16381,10 +17947,15 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { setVolume(e) { return this.gain.gain.setTargetAtTime(e, this.context.currentTime, .01), this; } -}, zn = new M, Rc = new gt, gy = new M, Un = new M, xy = class extends Za { +}, Kn = new A, Tu = new Ut, Ax = new A, Qn = new A, wu = class extends Fc { constructor(e){ - super(e); - this.panner = this.context.createPanner(), this.panner.panningModel = "HRTF", this.panner.connect(this.gain); + super(e), this.panner = this.context.createPanner(), this.panner.panningModel = "HRTF", this.panner.connect(this.gain); + } + connect() { + super.connect(), this.panner.connect(this.gain); + } + disconnect() { + super.disconnect(), this.panner.disconnect(this.gain); } getOutput() { return this.panner; @@ -16418,14 +17989,14 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { } updateMatrixWorld(e) { if (super.updateMatrixWorld(e), this.hasPlaybackControl === !0 && this.isPlaying === !1) return; - this.matrixWorld.decompose(zn, Rc, gy), Un.set(0, 0, 1).applyQuaternion(Rc); + this.matrixWorld.decompose(Kn, Tu, Ax), Qn.set(0, 0, 1).applyQuaternion(Tu); let t = this.panner; if (t.positionX) { let n = this.context.currentTime + this.listener.timeDelta; - t.positionX.linearRampToValueAtTime(zn.x, n), t.positionY.linearRampToValueAtTime(zn.y, n), t.positionZ.linearRampToValueAtTime(zn.z, n), t.orientationX.linearRampToValueAtTime(Un.x, n), t.orientationY.linearRampToValueAtTime(Un.y, n), t.orientationZ.linearRampToValueAtTime(Un.z, n); - } else t.setPosition(zn.x, zn.y, zn.z), t.setOrientation(Un.x, Un.y, Un.z); + t.positionX.linearRampToValueAtTime(Kn.x, n), t.positionY.linearRampToValueAtTime(Kn.y, n), t.positionZ.linearRampToValueAtTime(Kn.z, n), t.orientationX.linearRampToValueAtTime(Qn.x, n), t.orientationY.linearRampToValueAtTime(Qn.y, n), t.orientationZ.linearRampToValueAtTime(Qn.z, n); + } else t.setPosition(Kn.x, Kn.y, Kn.z), t.setOrientation(Qn.x, Qn.y, Qn.z); } -}, qh = class { +}, Au = class { constructor(e, t = 2048){ this.analyser = e.context.createAnalyser(), this.analyser.fftSize = t, this.data = new Uint8Array(this.analyser.frequencyBinCount), e.getOutput().connect(this.analyser); } @@ -16437,55 +18008,55 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { for(let n = 0; n < t.length; n++)e += t[n]; return e / t.length; } -}, Xh = class { +}, Bc = class { constructor(e, t, n){ this.binding = e, this.valueSize = n; - let i, r, o; + let i, r, a; switch(t){ case "quaternion": - i = this._slerp, r = this._slerpAdditive, o = this._setAdditiveIdentityQuaternion, this.buffer = new Float64Array(n * 6), this._workIndex = 5; + i = this._slerp, r = this._slerpAdditive, a = this._setAdditiveIdentityQuaternion, this.buffer = new Float64Array(n * 6), this._workIndex = 5; break; case "string": case "bool": - i = this._select, r = this._select, o = this._setAdditiveIdentityOther, this.buffer = new Array(n * 5); + i = this._select, r = this._select, a = this._setAdditiveIdentityOther, this.buffer = new Array(n * 5); break; default: - i = this._lerp, r = this._lerpAdditive, o = this._setAdditiveIdentityNumeric, this.buffer = new Float64Array(n * 5); + i = this._lerp, r = this._lerpAdditive, a = this._setAdditiveIdentityNumeric, this.buffer = new Float64Array(n * 5); } - this._mixBufferRegion = i, this._mixBufferRegionAdditive = r, this._setIdentity = o, this._origIndex = 3, this._addIndex = 4, this.cumulativeWeight = 0, this.cumulativeWeightAdditive = 0, this.useCount = 0, this.referenceCount = 0; + this._mixBufferRegion = i, this._mixBufferRegionAdditive = r, this._setIdentity = a, this._origIndex = 3, this._addIndex = 4, this.cumulativeWeight = 0, this.cumulativeWeightAdditive = 0, this.useCount = 0, this.referenceCount = 0; } accumulate(e, t) { - let n = this.buffer, i = this.valueSize, r = e * i + i, o = this.cumulativeWeight; - if (o === 0) { - for(let a = 0; a !== i; ++a)n[r + a] = n[a]; - o = t; + let n = this.buffer, i = this.valueSize, r = e * i + i, a = this.cumulativeWeight; + if (a === 0) { + for(let o = 0; o !== i; ++o)n[r + o] = n[o]; + a = t; } else { - o += t; - let a = t / o; - this._mixBufferRegion(n, r, 0, a, i); + a += t; + let o = t / a; + this._mixBufferRegion(n, r, 0, o, i); } - this.cumulativeWeight = o; + this.cumulativeWeight = a; } accumulateAdditive(e) { let t = this.buffer, n = this.valueSize, i = n * this._addIndex; this.cumulativeWeightAdditive === 0 && this._setIdentity(), this._mixBufferRegionAdditive(t, i, 0, e, n), this.cumulativeWeightAdditive += e; } apply(e) { - let t = this.valueSize, n = this.buffer, i = e * t + t, r = this.cumulativeWeight, o = this.cumulativeWeightAdditive, a = this.binding; + let t = this.valueSize, n = this.buffer, i = e * t + t, r = this.cumulativeWeight, a = this.cumulativeWeightAdditive, o = this.binding; if (this.cumulativeWeight = 0, this.cumulativeWeightAdditive = 0, r < 1) { - let l = t * this._origIndex; - this._mixBufferRegion(n, i, l, 1 - r, t); + let c = t * this._origIndex; + this._mixBufferRegion(n, i, c, 1 - r, t); } - o > 0 && this._mixBufferRegionAdditive(n, i, this._addIndex * t, 1, t); - for(let l = t, c = t + t; l !== c; ++l)if (n[l] !== n[l + t]) { - a.setValue(n, i); + a > 0 && this._mixBufferRegionAdditive(n, i, this._addIndex * t, 1, t); + for(let c = t, l = t + t; c !== l; ++c)if (n[c] !== n[c + t]) { + o.setValue(n, i); break; } } saveOriginalState() { let e = this.binding, t = this.buffer, n = this.valueSize, i = n * this._origIndex; e.getValue(t, i); - for(let r = n, o = i; r !== o; ++r)t[r] = t[i + r % n]; + for(let r = n, a = i; r !== a; ++r)t[r] = t[i + r % n]; this._setIdentity(), this.cumulativeWeight = 0, this.cumulativeWeightAdditive = 0; } restoreOriginalState() { @@ -16504,35 +18075,36 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { for(let n = 0; n < this.valueSize; n++)this.buffer[t + n] = this.buffer[e + n]; } _select(e, t, n, i, r) { - if (i >= .5) for(let o = 0; o !== r; ++o)e[t + o] = e[n + o]; + if (i >= .5) for(let a = 0; a !== r; ++a)e[t + a] = e[n + a]; } _slerp(e, t, n, i) { - gt.slerpFlat(e, t, e, t, e, n, i); + Ut.slerpFlat(e, t, e, t, e, n, i); } _slerpAdditive(e, t, n, i, r) { - let o = this._workIndex * r; - gt.multiplyQuaternionsFlat(e, o, e, t, e, n), gt.slerpFlat(e, t, e, t, e, o, i); + let a = this._workIndex * r; + Ut.multiplyQuaternionsFlat(e, a, e, t, e, n), Ut.slerpFlat(e, t, e, t, e, a, i); } _lerp(e, t, n, i, r) { - let o = 1 - i; - for(let a = 0; a !== r; ++a){ - let l = t + a; - e[l] = e[l] * o + e[n + a] * i; + let a = 1 - i; + for(let o = 0; o !== r; ++o){ + let c = t + o; + e[c] = e[c] * a + e[n + o] * i; } } _lerpAdditive(e, t, n, i, r) { - for(let o = 0; o !== r; ++o){ - let a = t + o; - e[a] = e[a] + e[n + o] * i; + for(let a = 0; a !== r; ++a){ + let o = t + a; + e[o] = e[o] + e[n + a] * i; } } -}, $a = "\\[\\]\\.:\\/", yy = new RegExp("[" + $a + "]", "g"), ja = "[^" + $a + "]", vy = "[^" + $a.replace("\\.", "") + "]", _y = /((?:WC+[\/:])*)/.source.replace("WC", ja), My = /(WCOD+)?/.source.replace("WCOD", vy), by = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC", ja), wy = /\.(WC+)(?:\[(.+)\])?/.source.replace("WC", ja), Sy = new RegExp("^" + _y + My + by + wy + "$"), Ty = [ +}, Kc = "\\[\\]\\.:\\/", Rx = new RegExp("[" + Kc + "]", "g"), Qc = "[^" + Kc + "]", Cx = "[^" + Kc.replace("\\.", "") + "]", Px = /((?:WC+[\/:])*)/.source.replace("WC", Qc), Lx = /(WCOD+)?/.source.replace("WCOD", Cx), Ix = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC", Qc), Ux = /\.(WC+)(?:\[(.+)\])?/.source.replace("WC", Qc), Dx = new RegExp("^" + Px + Lx + Ix + Ux + "$"), Nx = [ "material", "materials", - "bones" -], Jh = class { + "bones", + "map" +], zc = class { constructor(e, t, n){ - let i = n || ke.parseTrackName(t); + let i = n || Ke.parseTrackName(t); this._targetGroup = e, this._bindings = e.subscribe_(t, i); } getValue(e, t) { @@ -16552,19 +18124,19 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { let e = this._bindings; for(let t = this._targetGroup.nCachedObjects_, n = e.length; t !== n; ++t)e[t].unbind(); } -}, ke = class { +}, Ke = class s1 { constructor(e, t, n){ - this.path = t, this.parsedPath = n || ke.parseTrackName(t), this.node = ke.findNode(e, this.parsedPath.nodeName) || e, this.rootNode = e, this.getValue = this._getValue_unbound, this.setValue = this._setValue_unbound; + this.path = t, this.parsedPath = n || s1.parseTrackName(t), this.node = s1.findNode(e, this.parsedPath.nodeName), this.rootNode = e, this.getValue = this._getValue_unbound, this.setValue = this._setValue_unbound; } static create(e, t, n) { - return e && e.isAnimationObjectGroup ? new ke.Composite(e, t, n) : new ke(e, t, n); + return e && e.isAnimationObjectGroup ? new s1.Composite(e, t, n) : new s1(e, t, n); } static sanitizeNodeName(e) { - return e.replace(/\s/g, "_").replace(yy, ""); + return e.replace(/\s/g, "_").replace(Rx, ""); } static parseTrackName(e) { - let t = Sy.exec(e); - if (!t) throw new Error("PropertyBinding: Cannot parse trackName: " + e); + let t = Dx.exec(e); + if (t === null) throw new Error("PropertyBinding: Cannot parse trackName: " + e); let n = { nodeName: t[2], objectName: t[3], @@ -16574,24 +18146,24 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { }, i = n.nodeName && n.nodeName.lastIndexOf("."); if (i !== void 0 && i !== -1) { let r = n.nodeName.substring(i + 1); - Ty.indexOf(r) !== -1 && (n.nodeName = n.nodeName.substring(0, i), n.objectName = r); + Nx.indexOf(r) !== -1 && (n.nodeName = n.nodeName.substring(0, i), n.objectName = r); } if (n.propertyName === null || n.propertyName.length === 0) throw new Error("PropertyBinding: can not parse propertyName from trackName: " + e); return n; } static findNode(e, t) { - if (!t || t === "" || t === "." || t === -1 || t === e.name || t === e.uuid) return e; + if (t === void 0 || t === "" || t === "." || t === -1 || t === e.name || t === e.uuid) return e; if (e.skeleton) { let n = e.skeleton.getBoneByName(t); if (n !== void 0) return n; } if (e.children) { let n = function(r) { - for(let o = 0; o < r.length; o++){ - let a = r[o]; - if (a.name === t || a.uuid === t) return a; - let l = n(a.children); - if (l) return l; + for(let a = 0; a < r.length; a++){ + let o = r[a]; + if (o.name === t || o.uuid === t) return o; + let c = n(o.children); + if (c) return c; } return null; }, i = n(e.children); @@ -16663,12 +18235,12 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { } bind() { let e = this.node, t = this.parsedPath, n = t.objectName, i = t.propertyName, r = t.propertyIndex; - if (e || (e = ke.findNode(this.rootNode, t.nodeName) || this.rootNode, this.node = e), this.getValue = this._getValue_unavailable, this.setValue = this._setValue_unavailable, !e) { - console.error("THREE.PropertyBinding: Trying to update node for track: " + this.path + " but it wasn't found."); + if (e || (e = s1.findNode(this.rootNode, t.nodeName), this.node = e), this.getValue = this._getValue_unavailable, this.setValue = this._setValue_unavailable, !e) { + console.warn("THREE.PropertyBinding: No target node found for track: " + this.path + "."); return; } if (n) { - let c = t.objectIndex; + let l = t.objectIndex; switch(n){ case "materials": if (!e.material) { @@ -16687,10 +18259,25 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { return; } e = e.skeleton.bones; - for(let h = 0; h < e.length; h++)if (e[h].name === c) { - c = h; + for(let h = 0; h < e.length; h++)if (e[h].name === l) { + l = h; + break; + } + break; + case "map": + if ("map" in e) { + e = e.map; break; } + if (!e.material) { + console.error("THREE.PropertyBinding: Can not bind to material as node does not have a material.", this); + return; + } + if (!e.material.map) { + console.error("THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.", this); + return; + } + e = e.material.map; break; default: if (e[n] === void 0) { @@ -16699,91 +18286,86 @@ var Nn = new M, Lc = new gt, py = new M, Bn = new M, my = class extends Ne { } e = e[n]; } - if (c !== void 0) { - if (e[c] === void 0) { + if (l !== void 0) { + if (e[l] === void 0) { console.error("THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.", this, e); return; } - e = e[c]; + e = e[l]; } } - let o = e[i]; - if (o === void 0) { - let c = t.nodeName; - console.error("THREE.PropertyBinding: Trying to update property for track: " + c + "." + i + " but it wasn't found.", e); + let a = e[i]; + if (a === void 0) { + let l = t.nodeName; + console.error("THREE.PropertyBinding: Trying to update property for track: " + l + "." + i + " but it wasn't found.", e); return; } - let a = this.Versioning.None; - this.targetObject = e, e.needsUpdate !== void 0 ? a = this.Versioning.NeedsUpdate : e.matrixWorldNeedsUpdate !== void 0 && (a = this.Versioning.MatrixWorldNeedsUpdate); - let l = this.BindingType.Direct; + let o = this.Versioning.None; + this.targetObject = e, e.needsUpdate !== void 0 ? o = this.Versioning.NeedsUpdate : e.matrixWorldNeedsUpdate !== void 0 && (o = this.Versioning.MatrixWorldNeedsUpdate); + let c = this.BindingType.Direct; if (r !== void 0) { if (i === "morphTargetInfluences") { if (!e.geometry) { console.error("THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.", this); return; } - if (e.geometry.isBufferGeometry) { - if (!e.geometry.morphAttributes) { - console.error("THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.", this); - return; - } - e.morphTargetDictionary[r] !== void 0 && (r = e.morphTargetDictionary[r]); - } else { - console.error("THREE.PropertyBinding: Can not bind to morphTargetInfluences on THREE.Geometry. Use THREE.BufferGeometry instead.", this); + if (!e.geometry.morphAttributes) { + console.error("THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.", this); return; } + e.morphTargetDictionary[r] !== void 0 && (r = e.morphTargetDictionary[r]); } - l = this.BindingType.ArrayElement, this.resolvedProperty = o, this.propertyIndex = r; - } else o.fromArray !== void 0 && o.toArray !== void 0 ? (l = this.BindingType.HasFromToArray, this.resolvedProperty = o) : Array.isArray(o) ? (l = this.BindingType.EntireArray, this.resolvedProperty = o) : this.propertyName = i; - this.getValue = this.GetterByBindingType[l], this.setValue = this.SetterByBindingTypeAndVersioning[l][a]; + c = this.BindingType.ArrayElement, this.resolvedProperty = a, this.propertyIndex = r; + } else a.fromArray !== void 0 && a.toArray !== void 0 ? (c = this.BindingType.HasFromToArray, this.resolvedProperty = a) : Array.isArray(a) ? (c = this.BindingType.EntireArray, this.resolvedProperty = a) : this.propertyName = i; + this.getValue = this.GetterByBindingType[c], this.setValue = this.SetterByBindingTypeAndVersioning[c][o]; } unbind() { this.node = null, this.getValue = this._getValue_unbound, this.setValue = this._setValue_unbound; } }; -ke.Composite = Jh; -ke.prototype.BindingType = { +Ke.Composite = zc; +Ke.prototype.BindingType = { Direct: 0, EntireArray: 1, ArrayElement: 2, HasFromToArray: 3 }; -ke.prototype.Versioning = { +Ke.prototype.Versioning = { None: 0, NeedsUpdate: 1, MatrixWorldNeedsUpdate: 2 }; -ke.prototype.GetterByBindingType = [ - ke.prototype._getValue_direct, - ke.prototype._getValue_array, - ke.prototype._getValue_arrayElement, - ke.prototype._getValue_toArray +Ke.prototype.GetterByBindingType = [ + Ke.prototype._getValue_direct, + Ke.prototype._getValue_array, + Ke.prototype._getValue_arrayElement, + Ke.prototype._getValue_toArray ]; -ke.prototype.SetterByBindingTypeAndVersioning = [ +Ke.prototype.SetterByBindingTypeAndVersioning = [ [ - ke.prototype._setValue_direct, - ke.prototype._setValue_direct_setNeedsUpdate, - ke.prototype._setValue_direct_setMatrixWorldNeedsUpdate + Ke.prototype._setValue_direct, + Ke.prototype._setValue_direct_setNeedsUpdate, + Ke.prototype._setValue_direct_setMatrixWorldNeedsUpdate ], [ - ke.prototype._setValue_array, - ke.prototype._setValue_array_setNeedsUpdate, - ke.prototype._setValue_array_setMatrixWorldNeedsUpdate + Ke.prototype._setValue_array, + Ke.prototype._setValue_array_setNeedsUpdate, + Ke.prototype._setValue_array_setMatrixWorldNeedsUpdate ], [ - ke.prototype._setValue_arrayElement, - ke.prototype._setValue_arrayElement_setNeedsUpdate, - ke.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate + Ke.prototype._setValue_arrayElement, + Ke.prototype._setValue_arrayElement_setNeedsUpdate, + Ke.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate ], [ - ke.prototype._setValue_fromArray, - ke.prototype._setValue_fromArray_setNeedsUpdate, - ke.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate + Ke.prototype._setValue_fromArray, + Ke.prototype._setValue_fromArray_setNeedsUpdate, + Ke.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate ] ]; -var Yh = class { +var Ru = class { constructor(){ - this.uuid = Et(), this._objects = Array.prototype.slice.call(arguments), this.nCachedObjects_ = 0; + this.isAnimationObjectGroup = !0, this.uuid = kt(), this._objects = Array.prototype.slice.call(arguments), this.nCachedObjects_ = 0; let e = {}; this._indicesByUUID = e; for(let n = 0, i = arguments.length; n !== i; ++n)e[arguments[n].uuid] = n; @@ -16804,56 +18386,56 @@ var Yh = class { }; } add() { - let e = this._objects, t = this._indicesByUUID, n = this._paths, i = this._parsedPaths, r = this._bindings, o = r.length, a, l = e.length, c = this.nCachedObjects_; + let e = this._objects, t = this._indicesByUUID, n = this._paths, i = this._parsedPaths, r = this._bindings, a = r.length, o, c = e.length, l = this.nCachedObjects_; for(let h = 0, u = arguments.length; h !== u; ++h){ let d = arguments[h], f = d.uuid, m = t[f]; if (m === void 0) { - m = l++, t[f] = m, e.push(d); - for(let x = 0, v = o; x !== v; ++x)r[x].push(new ke(d, n[x], i[x])); - } else if (m < c) { - a = e[m]; - let x = --c, v = e[x]; - t[v.uuid] = m, e[m] = v, t[f] = x, e[x] = d; - for(let g = 0, p = o; g !== p; ++g){ - let _ = r[g], y = _[x], b = _[m]; - _[m] = y, b === void 0 && (b = new ke(d, n[g], i[g])), _[x] = b; + m = c++, t[f] = m, e.push(d); + for(let _ = 0, g = a; _ !== g; ++_)r[_].push(new Ke(d, n[_], i[_])); + } else if (m < l) { + o = e[m]; + let _ = --l, g = e[_]; + t[g.uuid] = m, e[m] = g, t[f] = _, e[_] = d; + for(let p = 0, v = a; p !== v; ++p){ + let x = r[p], y = x[_], b = x[m]; + x[m] = y, b === void 0 && (b = new Ke(d, n[p], i[p])), x[_] = b; } - } else e[m] !== a && console.error("THREE.AnimationObjectGroup: Different objects with the same UUID detected. Clean the caches or recreate your infrastructure when reloading scenes."); + } else e[m] !== o && console.error("THREE.AnimationObjectGroup: Different objects with the same UUID detected. Clean the caches or recreate your infrastructure when reloading scenes."); } - this.nCachedObjects_ = c; + this.nCachedObjects_ = l; } remove() { let e = this._objects, t = this._indicesByUUID, n = this._bindings, i = n.length, r = this.nCachedObjects_; - for(let o = 0, a = arguments.length; o !== a; ++o){ - let l = arguments[o], c = l.uuid, h = t[c]; + for(let a = 0, o = arguments.length; a !== o; ++a){ + let c = arguments[a], l = c.uuid, h = t[l]; if (h !== void 0 && h >= r) { let u = r++, d = e[u]; - t[d.uuid] = h, e[h] = d, t[c] = u, e[u] = l; + t[d.uuid] = h, e[h] = d, t[l] = u, e[u] = c; for(let f = 0, m = i; f !== m; ++f){ - let x = n[f], v = x[u], g = x[h]; - x[h] = v, x[u] = g; + let _ = n[f], g = _[u], p = _[h]; + _[h] = g, _[u] = p; } } } this.nCachedObjects_ = r; } uncache() { - let e = this._objects, t = this._indicesByUUID, n = this._bindings, i = n.length, r = this.nCachedObjects_, o = e.length; - for(let a = 0, l = arguments.length; a !== l; ++a){ - let c = arguments[a], h = c.uuid, u = t[h]; + let e = this._objects, t = this._indicesByUUID, n = this._bindings, i = n.length, r = this.nCachedObjects_, a = e.length; + for(let o = 0, c = arguments.length; o !== c; ++o){ + let l = arguments[o], h = l.uuid, u = t[h]; if (u !== void 0) if (delete t[h], u < r) { - let d = --r, f = e[d], m = --o, x = e[m]; - t[f.uuid] = u, e[u] = f, t[x.uuid] = d, e[d] = x, e.pop(); - for(let v = 0, g = i; v !== g; ++v){ - let p = n[v], _ = p[d], y = p[m]; - p[u] = _, p[d] = y, p.pop(); + let d = --r, f = e[d], m = --a, _ = e[m]; + t[f.uuid] = u, e[u] = f, t[_.uuid] = d, e[d] = _, e.pop(); + for(let g = 0, p = i; g !== p; ++g){ + let v = n[g], x = v[d], y = v[m]; + v[u] = x, v[d] = y, v.pop(); } } else { - let d = --o, f = e[d]; + let d = --a, f = e[d]; d > 0 && (t[f.uuid] = u), e[u] = f, e.pop(); - for(let m = 0, x = i; m !== x; ++m){ - let v = n[m]; - v[u] = v[d], v.pop(); + for(let m = 0, _ = i; m !== _; ++m){ + let g = n[m]; + g[u] = g[d], g.pop(); } } } @@ -16862,35 +18444,33 @@ var Yh = class { subscribe_(e, t) { let n = this._bindingsIndicesByPath, i = n[e], r = this._bindings; if (i !== void 0) return r[i]; - let o = this._paths, a = this._parsedPaths, l = this._objects, c = l.length, h = this.nCachedObjects_, u = new Array(c); - i = r.length, n[e] = i, o.push(e), a.push(t), r.push(u); - for(let d = h, f = l.length; d !== f; ++d){ - let m = l[d]; - u[d] = new ke(m, e, t); + let a = this._paths, o = this._parsedPaths, c = this._objects, l = c.length, h = this.nCachedObjects_, u = new Array(l); + i = r.length, n[e] = i, a.push(e), o.push(t), r.push(u); + for(let d = h, f = c.length; d !== f; ++d){ + let m = c[d]; + u[d] = new Ke(m, e, t); } return u; } unsubscribe_(e) { let t = this._bindingsIndicesByPath, n = t[e]; if (n !== void 0) { - let i = this._paths, r = this._parsedPaths, o = this._bindings, a = o.length - 1, l = o[a], c = e[a]; - t[c] = n, o[n] = l, o.pop(), r[n] = r[a], r.pop(), i[n] = i[a], i.pop(); + let i = this._paths, r = this._parsedPaths, a = this._bindings, o = a.length - 1, c = a[o], l = e[o]; + t[l] = n, a[n] = c, a.pop(), r[n] = r[o], r.pop(), i[n] = i[o], i.pop(); } } -}; -Yh.prototype.isAnimationObjectGroup = !0; -var Zh = class { +}, Vc = class { constructor(e, t, n = null, i = t.blendMode){ this._mixer = e, this._clip = t, this._localRoot = n, this.blendMode = i; - let r = t.tracks, o = r.length, a = new Array(o), l = { - endingStart: Mi, - endingEnd: Mi + let r = t.tracks, a = r.length, o = new Array(a), c = { + endingStart: zi, + endingEnd: zi }; - for(let c = 0; c !== o; ++c){ - let h = r[c].createInterpolant(null); - a[c] = h, h.settings = l; + for(let l = 0; l !== a; ++l){ + let h = r[l].createInterpolant(null); + o[l] = h, h.settings = c; } - this._interpolantSettings = l, this._interpolants = a, this._propertyBindings = new Array(o), this._cacheIndex = null, this._byClipCacheIndex = null, this._timeScaleInterpolant = null, this._weightInterpolant = null, this.loop = Id, this._loopCount = -1, this._startTime = null, this.time = 0, this.timeScale = 1, this._effectiveTimeScale = 1, this.weight = 1, this._effectiveWeight = 1, this.repetitions = 1 / 0, this.paused = !1, this.enabled = !0, this.clampWhenFinished = !1, this.zeroSlopeAtStart = !0, this.zeroSlopeAtEnd = !0; + this._interpolantSettings = c, this._interpolants = o, this._propertyBindings = new Array(a), this._cacheIndex = null, this._byClipCacheIndex = null, this._timeScaleInterpolant = null, this._weightInterpolant = null, this.loop = Af, this._loopCount = -1, this._startTime = null, this.time = 0, this.timeScale = 1, this._effectiveTimeScale = 1, this.weight = 1, this._effectiveWeight = 1, this.repetitions = 1 / 0, this.paused = !1, this.enabled = !0, this.clampWhenFinished = !1, this.zeroSlopeAtStart = !0, this.zeroSlopeAtEnd = !0; } play() { return this._mixer._activateAction(this), this; @@ -16927,8 +18507,8 @@ var Zh = class { } crossFadeFrom(e, t, n) { if (e.fadeOut(t), this.fadeIn(t), n) { - let i = this._clip.duration, r = e._clip.duration, o = r / i, a = i / r; - e.warp(1, o, t), this.warp(a, 1, t); + let i = this._clip.duration, r = e._clip.duration, a = r / i, o = i / r; + e.warp(1, a, t), this.warp(o, 1, t); } return this; } @@ -16955,10 +18535,10 @@ var Zh = class { return this.warp(this._effectiveTimeScale, 0, e); } warp(e, t, n) { - let i = this._mixer, r = i.time, o = this.timeScale, a = this._timeScaleInterpolant; - a === null && (a = i._lendControlInterpolant(), this._timeScaleInterpolant = a); - let l = a.parameterPositions, c = a.sampleValues; - return l[0] = r, l[1] = r + n, c[0] = e / o, c[1] = t / o, this; + let i = this._mixer, r = i.time, a = this.timeScale, o = this._timeScaleInterpolant; + o === null && (o = i._lendControlInterpolant(), this._timeScaleInterpolant = o); + let c = o.parameterPositions, l = o.sampleValues; + return c[0] = r, c[1] = r + n, l[0] = e / a, l[1] = t / a, this; } stopWarping() { let e = this._timeScaleInterpolant; @@ -16980,21 +18560,20 @@ var Zh = class { } let r = this._startTime; if (r !== null) { - let l = (e - r) * n; - if (l < 0 || n === 0) return; - this._startTime = null, t = n * l; + let c = (e - r) * n; + c < 0 || n === 0 ? t = 0 : (this._startTime = null, t = n * c); } t *= this._updateTimeScale(e); - let o = this._updateTime(t), a = this._updateWeight(e); - if (a > 0) { - let l = this._interpolants, c = this._propertyBindings; + let a = this._updateTime(t), o = this._updateWeight(e); + if (o > 0) { + let c = this._interpolants, l = this._propertyBindings; switch(this.blendMode){ - case qc: - for(let h = 0, u = l.length; h !== u; ++h)l[h].evaluate(o), c[h].accumulateAdditive(a); + case xd: + for(let h = 0, u = c.length; h !== u; ++h)c[h].evaluate(a), l[h].accumulateAdditive(o); break; - case ua: + case Xc: default: - for(let h = 0, u = l.length; h !== u; ++h)l[h].evaluate(o), c[h].accumulate(i, a); + for(let h = 0, u = c.length; h !== u; ++h)c[h].evaluate(a), l[h].accumulate(i, o); } } } @@ -17015,14 +18594,17 @@ var Zh = class { if (!this.paused) { t = this.timeScale; let n = this._timeScaleInterpolant; - n !== null && (t *= n.evaluate(e)[0], e > n.parameterPositions[1] && (this.stopWarping(), t === 0 ? this.paused = !0 : this.timeScale = t)); + if (n !== null) { + let i = n.evaluate(e)[0]; + t *= i, e > n.parameterPositions[1] && (this.stopWarping(), t === 0 ? this.paused = !0 : this.timeScale = t); + } } return this._effectiveTimeScale = t, t; } _updateTime(e) { - let t = this._clip.duration, n = this.loop, i = this.time + e, r = this._loopCount, o = n === Dd; - if (e === 0) return r === -1 ? i : o && (r & 1) === 1 ? t - i : i; - if (n === Pd) { + let t = this._clip.duration, n = this.loop, i = this.time + e, r = this._loopCount, a = n === Rf; + if (e === 0) return r === -1 ? i : a && (r & 1) === 1 ? t - i : i; + if (n === wf) { r === -1 && (this._loopCount = 0, this._setEndings(!0, !0, !1)); e: { if (i >= t) i = t; @@ -17038,61 +18620,60 @@ var Zh = class { }); } } else { - if (r === -1 && (e >= 0 ? (r = 0, this._setEndings(!0, this.repetitions === 0, o)) : this._setEndings(this.repetitions === 0, !0, o)), i >= t || i < 0) { - let a = Math.floor(i / t); - i -= t * a, r += Math.abs(a); - let l = this.repetitions - r; - if (l <= 0) this.clampWhenFinished ? this.paused = !0 : this.enabled = !1, i = e > 0 ? t : 0, this.time = i, this._mixer.dispatchEvent({ + if (r === -1 && (e >= 0 ? (r = 0, this._setEndings(!0, this.repetitions === 0, a)) : this._setEndings(this.repetitions === 0, !0, a)), i >= t || i < 0) { + let o = Math.floor(i / t); + i -= t * o, r += Math.abs(o); + let c = this.repetitions - r; + if (c <= 0) this.clampWhenFinished ? this.paused = !0 : this.enabled = !1, i = e > 0 ? t : 0, this.time = i, this._mixer.dispatchEvent({ type: "finished", action: this, direction: e > 0 ? 1 : -1 }); else { - if (l === 1) { - let c = e < 0; - this._setEndings(c, !c, o); - } else this._setEndings(!1, !1, o); + if (c === 1) { + let l = e < 0; + this._setEndings(l, !l, a); + } else this._setEndings(!1, !1, a); this._loopCount = r, this.time = i, this._mixer.dispatchEvent({ type: "loop", action: this, - loopDelta: a + loopDelta: o }); } } else this.time = i; - if (o && (r & 1) === 1) return t - i; + if (a && (r & 1) === 1) return t - i; } return i; } _setEndings(e, t, n) { let i = this._interpolantSettings; - n ? (i.endingStart = bi, i.endingEnd = bi) : (e ? i.endingStart = this.zeroSlopeAtStart ? bi : Mi : i.endingStart = Os, t ? i.endingEnd = this.zeroSlopeAtEnd ? bi : Mi : i.endingEnd = Os); + n ? (i.endingStart = Vi, i.endingEnd = Vi) : (e ? i.endingStart = this.zeroSlopeAtStart ? Vi : zi : i.endingStart = Br, t ? i.endingEnd = this.zeroSlopeAtEnd ? Vi : zi : i.endingEnd = Br); } _scheduleFading(e, t, n) { - let i = this._mixer, r = i.time, o = this._weightInterpolant; - o === null && (o = i._lendControlInterpolant(), this._weightInterpolant = o); - let a = o.parameterPositions, l = o.sampleValues; - return a[0] = r, l[0] = t, a[1] = r + e, l[1] = n, this; + let i = this._mixer, r = i.time, a = this._weightInterpolant; + a === null && (a = i._lendControlInterpolant(), this._weightInterpolant = a); + let o = a.parameterPositions, c = a.sampleValues; + return o[0] = r, c[0] = t, o[1] = r + e, c[1] = n, this; } -}, $h = class extends En { +}, Ox = new Float32Array(1), Cu = class extends sn { constructor(e){ - super(); - this._root = e, this._initMemoryManager(), this._accuIndex = 0, this.time = 0, this.timeScale = 1; + super(), this._root = e, this._initMemoryManager(), this._accuIndex = 0, this.time = 0, this.timeScale = 1; } _bindAction(e, t) { - let n = e._localRoot || this._root, i = e._clip.tracks, r = i.length, o = e._propertyBindings, a = e._interpolants, l = n.uuid, c = this._bindingsByRootAndName, h = c[l]; - h === void 0 && (h = {}, c[l] = h); + let n = e._localRoot || this._root, i = e._clip.tracks, r = i.length, a = e._propertyBindings, o = e._interpolants, c = n.uuid, l = this._bindingsByRootAndName, h = l[c]; + h === void 0 && (h = {}, l[c] = h); for(let u = 0; u !== r; ++u){ let d = i[u], f = d.name, m = h[f]; - if (m !== void 0) o[u] = m; + if (m !== void 0) ++m.referenceCount, a[u] = m; else { - if (m = o[u], m !== void 0) { - m._cacheIndex === null && (++m.referenceCount, this._addInactiveBinding(m, l, f)); + if (m = a[u], m !== void 0) { + m._cacheIndex === null && (++m.referenceCount, this._addInactiveBinding(m, c, f)); continue; } - let x = t && t._propertyBindings[u].binding.parsedPath; - m = new Xh(ke.create(n, f, x), d.ValueTypeName, d.getValueSize()), ++m.referenceCount, this._addInactiveBinding(m, l, f), o[u] = m; + let _ = t && t._propertyBindings[u].binding.parsedPath; + m = new Bc(Ke.create(n, f, _), d.ValueTypeName, d.getValueSize()), ++m.referenceCount, this._addInactiveBinding(m, c, f), a[u] = m; } - a[u].resultBuffer = m.buffer; + o[u].resultBuffer = m.buffer; } } _activateAction(e) { @@ -17154,26 +18735,26 @@ var Zh = class { return t !== null && t < this._nActiveActions; } _addInactiveAction(e, t, n) { - let i = this._actions, r = this._actionsByClip, o = r[t]; - if (o === void 0) o = { + let i = this._actions, r = this._actionsByClip, a = r[t]; + if (a === void 0) a = { knownActions: [ e ], actionByRoot: {} - }, e._byClipCacheIndex = 0, r[t] = o; + }, e._byClipCacheIndex = 0, r[t] = a; else { - let a = o.knownActions; - e._byClipCacheIndex = a.length, a.push(e); + let o = a.knownActions; + e._byClipCacheIndex = o.length, o.push(e); } - e._cacheIndex = i.length, i.push(e), o.actionByRoot[n] = e; + e._cacheIndex = i.length, i.push(e), a.actionByRoot[n] = e; } _removeInactiveAction(e) { let t = this._actions, n = t[t.length - 1], i = e._cacheIndex; n._cacheIndex = i, t[i] = n, t.pop(), e._cacheIndex = null; - let r = e._clip.uuid, o = this._actionsByClip, a = o[r], l = a.knownActions, c = l[l.length - 1], h = e._byClipCacheIndex; - c._byClipCacheIndex = h, l[h] = c, l.pop(), e._byClipCacheIndex = null; - let u = a.actionByRoot, d = (e._localRoot || this._root).uuid; - delete u[d], l.length === 0 && delete o[r], this._removeInactiveBindingsForAction(e); + let r = e._clip.uuid, a = this._actionsByClip, o = a[r], c = o.knownActions, l = c[c.length - 1], h = e._byClipCacheIndex; + l._byClipCacheIndex = h, c[h] = l, c.pop(), e._byClipCacheIndex = null; + let u = o.actionByRoot, d = (e._localRoot || this._root).uuid; + delete u[d], c.length === 0 && delete a[r], this._removeInactiveBindingsForAction(e); } _removeInactiveBindingsForAction(e) { let t = e._propertyBindings; @@ -17191,12 +18772,12 @@ var Zh = class { e._cacheIndex = i, t[i] = e, r._cacheIndex = n, t[n] = r; } _addInactiveBinding(e, t, n) { - let i = this._bindingsByRootAndName, r = this._bindings, o = i[t]; - o === void 0 && (o = {}, i[t] = o), o[n] = e, e._cacheIndex = r.length, r.push(e); + let i = this._bindingsByRootAndName, r = this._bindings, a = i[t]; + a === void 0 && (a = {}, i[t] = a), a[n] = e, e._cacheIndex = r.length, r.push(e); } _removeInactiveBinding(e) { - let t = this._bindings, n = e.binding, i = n.rootNode.uuid, r = n.path, o = this._bindingsByRootAndName, a = o[i], l = t[t.length - 1], c = e._cacheIndex; - l._cacheIndex = c, t[c] = l, t.pop(), delete a[r], Object.keys(a).length === 0 && delete o[i]; + let t = this._bindings, n = e.binding, i = n.rootNode.uuid, r = n.path, a = this._bindingsByRootAndName, o = a[i], c = t[t.length - 1], l = e._cacheIndex; + c._cacheIndex = l, t[l] = c, t.pop(), delete o[r], Object.keys(o).length === 0 && delete a[i]; } _lendBinding(e) { let t = this._bindings, n = e._cacheIndex, i = this._nActiveBindings++, r = t[i]; @@ -17208,26 +18789,26 @@ var Zh = class { } _lendControlInterpolant() { let e = this._controlInterpolants, t = this._nActiveControlInterpolants++, n = e[t]; - return n === void 0 && (n = new Na(new Float32Array(2), new Float32Array(2), 1, this._controlInterpolantsResultBuffer), n.__cacheIndex = t, e[t] = n), n; + return n === void 0 && (n = new fa(new Float32Array(2), new Float32Array(2), 1, Ox), n.__cacheIndex = t, e[t] = n), n; } _takeBackControlInterpolant(e) { let t = this._controlInterpolants, n = e.__cacheIndex, i = --this._nActiveControlInterpolants, r = t[i]; e.__cacheIndex = i, t[i] = e, r.__cacheIndex = n, t[n] = r; } clipAction(e, t, n) { - let i = t || this._root, r = i.uuid, o = typeof e == "string" ? Lr.findByName(i, e) : e, a = o !== null ? o.uuid : e, l = this._actionsByClip[a], c = null; - if (n === void 0 && (o !== null ? n = o.blendMode : n = ua), l !== void 0) { - let u = l.actionByRoot[r]; + let i = t || this._root, r = i.uuid, a = typeof e == "string" ? is.findByName(i, e) : e, o = a !== null ? a.uuid : e, c = this._actionsByClip[o], l = null; + if (n === void 0 && (a !== null ? n = a.blendMode : n = Xc), c !== void 0) { + let u = c.actionByRoot[r]; if (u !== void 0 && u.blendMode === n) return u; - c = l.knownActions[0], o === null && (o = c._clip); + l = c.knownActions[0], a === null && (a = l._clip); } - if (o === null) return null; - let h = new Zh(this, o, t, n); - return this._bindAction(h, c), this._addInactiveAction(h, a, r), h; + if (a === null) return null; + let h = new Vc(this, a, t, n); + return this._bindAction(h, l), this._addInactiveAction(h, o, r), h; } existingAction(e, t) { - let n = t || this._root, i = n.uuid, r = typeof e == "string" ? Lr.findByName(n, e) : e, o = r ? r.uuid : e, a = this._actionsByClip[o]; - return a !== void 0 && a.actionByRoot[i] || null; + let n = t || this._root, i = n.uuid, r = typeof e == "string" ? is.findByName(n, e) : e, a = r ? r.uuid : e, o = this._actionsByClip[a]; + return o !== void 0 && o.actionByRoot[i] || null; } stopAllAction() { let e = this._actions, t = this._nActiveActions; @@ -17236,10 +18817,10 @@ var Zh = class { } update(e) { e *= this.timeScale; - let t = this._actions, n = this._nActiveActions, i = this.time += e, r = Math.sign(e), o = this._accuIndex ^= 1; - for(let c = 0; c !== n; ++c)t[c]._update(i, e, r, o); - let a = this._bindings, l = this._nActiveBindings; - for(let c = 0; c !== l; ++c)a[c].apply(o); + let t = this._actions, n = this._nActiveActions, i = this.time += e, r = Math.sign(e), a = this._accuIndex ^= 1; + for(let l = 0; l !== n; ++l)t[l]._update(i, e, r, a); + let o = this._bindings, c = this._nActiveBindings; + for(let l = 0; l !== c; ++l)o[l].apply(a); return this; } setTime(e) { @@ -17253,45 +18834,76 @@ var Zh = class { uncacheClip(e) { let t = this._actions, n = e.uuid, i = this._actionsByClip, r = i[n]; if (r !== void 0) { - let o = r.knownActions; - for(let a = 0, l = o.length; a !== l; ++a){ - let c = o[a]; - this._deactivateAction(c); - let h = c._cacheIndex, u = t[t.length - 1]; - c._cacheIndex = null, c._byClipCacheIndex = null, u._cacheIndex = h, t[h] = u, t.pop(), this._removeInactiveBindingsForAction(c); + let a = r.knownActions; + for(let o = 0, c = a.length; o !== c; ++o){ + let l = a[o]; + this._deactivateAction(l); + let h = l._cacheIndex, u = t[t.length - 1]; + l._cacheIndex = null, l._byClipCacheIndex = null, u._cacheIndex = h, t[h] = u, t.pop(), this._removeInactiveBindingsForAction(l); } delete i[n]; } } uncacheRoot(e) { let t = e.uuid, n = this._actionsByClip; - for(let o in n){ - let a = n[o].actionByRoot, l = a[t]; - l !== void 0 && (this._deactivateAction(l), this._removeInactiveAction(l)); + for(let a in n){ + let o = n[a].actionByRoot, c = o[t]; + c !== void 0 && (this._deactivateAction(c), this._removeInactiveAction(c)); } let i = this._bindingsByRootAndName, r = i[t]; - if (r !== void 0) for(let o in r){ - let a = r[o]; - a.restoreOriginalState(), this._removeInactiveBinding(a); + if (r !== void 0) for(let a in r){ + let o = r[a]; + o.restoreOriginalState(), this._removeInactiveBinding(o); } } uncacheAction(e, t) { let n = this.existingAction(e, t); n !== null && (this._deactivateAction(n), this._removeInactiveAction(n)); } -}; -$h.prototype._controlInterpolantsResultBuffer = new Float32Array(1); -var go = class { +}, Pu = class s1 { constructor(e){ - typeof e == "string" && (console.warn("THREE.Uniform: Type parameter is no longer needed."), e = arguments[1]), this.value = e; + this.value = e; + } + clone() { + return new s1(this.value.clone === void 0 ? this.value : this.value.clone()); + } +}, Fx = 0, Lu = class extends sn { + constructor(){ + super(), this.isUniformsGroup = !0, Object.defineProperty(this, "id", { + value: Fx++ + }), this.name = "", this.usage = Hr, this.uniforms = []; + } + add(e) { + return this.uniforms.push(e), this; + } + remove(e) { + let t = this.uniforms.indexOf(e); + return t !== -1 && this.uniforms.splice(t, 1), this; + } + setName(e) { + return this.name = e, this; + } + setUsage(e) { + return this.usage = e, this; + } + dispose() { + return this.dispatchEvent({ + type: "dispose" + }), this; + } + copy(e) { + this.name = e.name, this.usage = e.usage; + let t = e.uniforms; + this.uniforms.length = 0; + for(let n = 0, i = t.length; n < i; n++)this.uniforms.push(t[n].clone()); + return this; } clone() { - return new go(this.value.clone === void 0 ? this.value : this.value.clone()); + return new this.constructor().copy(this); } -}, jh = class extends $n { +}, Iu = class extends Is { constructor(e, t, n = 1){ - super(e, t); - this.meshPerAttribute = n; + super(e, t), this.isInstancedInterleavedBuffer = !0, this.meshPerAttribute = n; } copy(e) { return super.copy(e), this.meshPerAttribute = e.meshPerAttribute, this; @@ -17304,11 +18916,9 @@ var go = class { let t = super.toJSON(e); return t.isInstancedInterleavedBuffer = !0, t.meshPerAttribute = this.meshPerAttribute, t; } -}; -jh.prototype.isInstancedInterleavedBuffer = !0; -var Qh = class { +}, Uu = class { constructor(e, t, n, i, r){ - this.buffer = e, this.type = t, this.itemSize = n, this.elementSize = i, this.count = r, this.version = 0; + this.isGLBufferAttribute = !0, this.name = "", this.buffer = e, this.type = t, this.itemSize = n, this.elementSize = i, this.count = r, this.version = 0; } set needsUpdate(e) { e === !0 && this.version++; @@ -17325,11 +18935,9 @@ var Qh = class { setCount(e) { return this.count = e, this; } -}; -Qh.prototype.isGLBufferAttribute = !0; -var Ey = class { +}, Du = class { constructor(e, t, n = 0, i = 1 / 0){ - this.ray = new Cn(e, t), this.near = n, this.far = i, this.camera = null, this.layers = new Js, this.params = { + this.ray = new hi(e, t), this.near = n, this.far = i, this.camera = null, this.layers = new Rs, this.params = { Mesh: {}, Line: { threshold: 1 @@ -17345,26 +18953,26 @@ var Ey = class { this.ray.set(e, t); } setFromCamera(e, t) { - t && t.isPerspectiveCamera ? (this.ray.origin.setFromMatrixPosition(t.matrixWorld), this.ray.direction.set(e.x, e.y, .5).unproject(t).sub(this.ray.origin).normalize(), this.camera = t) : t && t.isOrthographicCamera ? (this.ray.origin.set(e.x, e.y, (t.near + t.far) / (t.near - t.far)).unproject(t), this.ray.direction.set(0, 0, -1).transformDirection(t.matrixWorld), this.camera = t) : console.error("THREE.Raycaster: Unsupported camera type: " + t.type); + t.isPerspectiveCamera ? (this.ray.origin.setFromMatrixPosition(t.matrixWorld), this.ray.direction.set(e.x, e.y, .5).unproject(t).sub(this.ray.origin).normalize(), this.camera = t) : t.isOrthographicCamera ? (this.ray.origin.set(e.x, e.y, (t.near + t.far) / (t.near - t.far)).unproject(t), this.ray.direction.set(0, 0, -1).transformDirection(t.matrixWorld), this.camera = t) : console.error("THREE.Raycaster: Unsupported camera type: " + t.type); } intersectObject(e, t = !0, n = []) { - return la(e, this, n, t), n.sort(Pc), n; + return kc(e, this, n, t), n.sort(Nu), n; } intersectObjects(e, t = !0, n = []) { - for(let i = 0, r = e.length; i < r; i++)la(e[i], this, n, t); - return n.sort(Pc), n; + for(let i = 0, r = e.length; i < r; i++)kc(e[i], this, n, t); + return n.sort(Nu), n; } }; -function Pc(s, e) { - return s.distance - e.distance; +function Nu(s1, e) { + return s1.distance - e.distance; } -function la(s, e, t, n) { - if (s.layers.test(e.layers) && s.raycast(e, t), n === !0) { - let i = s.children; - for(let r = 0, o = i.length; r < o; r++)la(i[r], e, t, !0); +function kc(s1, e, t, n) { + if (s1.layers.test(e.layers) && s1.raycast(e, t), n === !0) { + let i = s1.children; + for(let r = 0, a = i.length; r < a; r++)kc(i[r], e, t, !0); } } -var Ay = class { +var Ou = class { constructor(e = 1, t = 0, n = 0){ return this.radius = e, this.phi = t, this.theta = n, this; } @@ -17381,12 +18989,12 @@ var Ay = class { return this.setFromCartesianCoords(e.x, e.y, e.z); } setFromCartesianCoords(e, t, n) { - return this.radius = Math.sqrt(e * e + t * t + n * n), this.radius === 0 ? (this.theta = 0, this.phi = 0) : (this.theta = Math.atan2(e, n), this.phi = Math.acos(mt(t / this.radius, -1, 1))), this; + return this.radius = Math.sqrt(e * e + t * t + n * n), this.radius === 0 ? (this.theta = 0, this.phi = 0) : (this.theta = Math.atan2(e, n), this.phi = Math.acos(ct(t / this.radius, -1, 1))), this; } clone() { return new this.constructor().copy(this); } -}, Cy = class { +}, Fu = class { constructor(e = 1, t = 0, n = 0){ return this.radius = e, this.theta = t, this.y = n, this; } @@ -17405,9 +19013,9 @@ var Ay = class { clone() { return new this.constructor().copy(this); } -}, Ic = new X, qi = class { - constructor(e = new X(1 / 0, 1 / 0), t = new X(-1 / 0, -1 / 0)){ - this.min = e, this.max = t; +}, Bu = new Z, zu = class { + constructor(e = new Z(1 / 0, 1 / 0), t = new Z(-1 / 0, -1 / 0)){ + this.isBox2 = !0, this.min = e, this.max = t; } set(e, t) { return this.min.copy(e), this.max.copy(t), this; @@ -17418,7 +19026,7 @@ var Ay = class { return this; } setFromCenterAndSize(e, t) { - let n = Ic.copy(t).multiplyScalar(.5); + let n = Bu.copy(t).multiplyScalar(.5); return this.min.copy(e).sub(n), this.max.copy(e).add(n), this; } clone() { @@ -17464,10 +19072,10 @@ var Ay = class { return t.copy(e).clamp(this.min, this.max); } distanceToPoint(e) { - return Ic.copy(e).clamp(this.min, this.max).sub(e).length(); + return this.clampPoint(e, Bu).distanceTo(e); } intersect(e) { - return this.min.max(e.min), this.max.min(e.max), this; + return this.min.max(e.min), this.max.min(e.max), this.isEmpty() && this.makeEmpty(), this; } union(e) { return this.min.min(e.min), this.max.max(e.max), this; @@ -17478,10 +19086,8 @@ var Ay = class { equals(e) { return e.min.equals(this.min) && e.max.equals(this.max); } -}; -qi.prototype.isBox2 = !0; -var Dc = new M, Ts = new M, Kh = class { - constructor(e = new M, t = new M){ +}, Vu = new A, Tr = new A, ku = class { + constructor(e = new A, t = new A){ this.start = e, this.end = t; } set(e, t) { @@ -17506,9 +19112,9 @@ var Dc = new M, Ts = new M, Kh = class { return this.delta(t).multiplyScalar(e).add(this.start); } closestPointToPointParameter(e, t) { - Dc.subVectors(e, this.start), Ts.subVectors(this.end, this.start); - let n = Ts.dot(Ts), r = Ts.dot(Dc) / n; - return t && (r = mt(r, 0, 1)), r; + Vu.subVectors(e, this.start), Tr.subVectors(this.end, this.start); + let n = Tr.dot(Tr), r = Tr.dot(Vu) / n; + return t && (r = ct(r, 0, 1)), r; } closestPointToPoint(e, t, n) { let i = this.closestPointToPointParameter(e, t); @@ -17523,11 +19129,10 @@ var Dc = new M, Ts = new M, Kh = class { clone() { return new this.constructor().copy(this); } -}, Fc = new M, Ly = class extends Ne { +}, Hu = new A, Gu = class extends Je { constructor(e, t){ - super(); - this.light = e, this.light.updateMatrixWorld(), this.matrix = e.matrixWorld, this.matrixAutoUpdate = !1, this.color = t; - let n = new _e, i = [ + super(), this.light = e, this.matrix = e.matrixWorld, this.matrixAutoUpdate = !1, this.color = t, this.type = "SpotLightHelper"; + let n = new Ge, i = [ 0, 0, 0, @@ -17559,87 +19164,87 @@ var Dc = new M, Ts = new M, Kh = class { -1, 1 ]; - for(let o = 0, a = 1, l = 32; o < l; o++, a++){ - let c = o / l * Math.PI * 2, h = a / l * Math.PI * 2; - i.push(Math.cos(c), Math.sin(c), 1, Math.cos(h), Math.sin(h), 1); + for(let a = 0, o = 1, c = 32; a < c; a++, o++){ + let l = a / c * Math.PI * 2, h = o / c * Math.PI * 2; + i.push(Math.cos(l), Math.sin(l), 1, Math.cos(h), Math.sin(h), 1); } - n.setAttribute("position", new de(i, 3)); - let r = new ft({ + n.setAttribute("position", new ve(i, 3)); + let r = new wt({ fog: !1, toneMapped: !1 }); - this.cone = new wt(n, r), this.add(this.cone), this.update(); + this.cone = new en(n, r), this.add(this.cone), this.update(); } dispose() { this.cone.geometry.dispose(), this.cone.material.dispose(); } update() { - this.light.updateMatrixWorld(); + this.light.updateWorldMatrix(!0, !1), this.light.target.updateWorldMatrix(!0, !1); let e = this.light.distance ? this.light.distance : 1e3, t = e * Math.tan(this.light.angle); - this.cone.scale.set(t, t, e), Fc.setFromMatrixPosition(this.light.target.matrixWorld), this.cone.lookAt(Fc), this.color !== void 0 ? this.cone.material.color.set(this.color) : this.cone.material.color.copy(this.light.color); + this.cone.scale.set(t, t, e), Hu.setFromMatrixPosition(this.light.target.matrixWorld), this.cone.lookAt(Hu), this.color !== void 0 ? this.cone.material.color.set(this.color) : this.cone.material.color.copy(this.light.color); } -}, yn = new M, Es = new pe, Qo = new pe, eu = class extends wt { +}, Pn = new A, wr = new ze, lo = new ze, Wu = class extends en { constructor(e){ - let t = tu(e), n = new _e, i = [], r = [], o = new ae(0, 0, 1), a = new ae(0, 1, 0); - for(let c = 0; c < t.length; c++){ - let h = t[c]; - h.parent && h.parent.isBone && (i.push(0, 0, 0), i.push(0, 0, 0), r.push(o.r, o.g, o.b), r.push(a.r, a.g, a.b)); + let t = Nd(e), n = new Ge, i = [], r = [], a = new pe(0, 0, 1), o = new pe(0, 1, 0); + for(let l = 0; l < t.length; l++){ + let h = t[l]; + h.parent && h.parent.isBone && (i.push(0, 0, 0), i.push(0, 0, 0), r.push(a.r, a.g, a.b), r.push(o.r, o.g, o.b)); } - n.setAttribute("position", new de(i, 3)), n.setAttribute("color", new de(r, 3)); - let l = new ft({ + n.setAttribute("position", new ve(i, 3)), n.setAttribute("color", new ve(r, 3)); + let c = new wt({ vertexColors: !0, depthTest: !1, depthWrite: !1, toneMapped: !1, transparent: !0 }); - super(n, l); - this.type = "SkeletonHelper", this.isSkeletonHelper = !0, this.root = e, this.bones = t, this.matrix = e.matrixWorld, this.matrixAutoUpdate = !1; + super(n, c), this.isSkeletonHelper = !0, this.type = "SkeletonHelper", this.root = e, this.bones = t, this.matrix = e.matrixWorld, this.matrixAutoUpdate = !1; } updateMatrixWorld(e) { let t = this.bones, n = this.geometry, i = n.getAttribute("position"); - Qo.copy(this.root.matrixWorld).invert(); - for(let r = 0, o = 0; r < t.length; r++){ - let a = t[r]; - a.parent && a.parent.isBone && (Es.multiplyMatrices(Qo, a.matrixWorld), yn.setFromMatrixPosition(Es), i.setXYZ(o, yn.x, yn.y, yn.z), Es.multiplyMatrices(Qo, a.parent.matrixWorld), yn.setFromMatrixPosition(Es), i.setXYZ(o + 1, yn.x, yn.y, yn.z), o += 2); + lo.copy(this.root.matrixWorld).invert(); + for(let r = 0, a = 0; r < t.length; r++){ + let o = t[r]; + o.parent && o.parent.isBone && (wr.multiplyMatrices(lo, o.matrixWorld), Pn.setFromMatrixPosition(wr), i.setXYZ(a, Pn.x, Pn.y, Pn.z), wr.multiplyMatrices(lo, o.parent.matrixWorld), Pn.setFromMatrixPosition(wr), i.setXYZ(a + 1, Pn.x, Pn.y, Pn.z), a += 2); } n.getAttribute("position").needsUpdate = !0, super.updateMatrixWorld(e); } + dispose() { + this.geometry.dispose(), this.material.dispose(); + } }; -function tu(s) { +function Nd(s1) { let e = []; - s && s.isBone && e.push(s); - for(let t = 0; t < s.children.length; t++)e.push.apply(e, tu(s.children[t])); + s1.isBone === !0 && e.push(s1); + for(let t = 0; t < s1.children.length; t++)e.push.apply(e, Nd(s1.children[t])); return e; } -var Ry = class extends st { +var Xu = class extends Mt { constructor(e, t, n){ - let i = new Fi(t, 4, 2), r = new hn({ + let i = new ua(t, 4, 2), r = new Sn({ wireframe: !0, fog: !1, toneMapped: !1 }); - super(i, r); - this.light = e, this.light.updateMatrixWorld(), this.color = n, this.type = "PointLightHelper", this.matrix = this.light.matrixWorld, this.matrixAutoUpdate = !1, this.update(); + super(i, r), this.light = e, this.color = n, this.type = "PointLightHelper", this.matrix = this.light.matrixWorld, this.matrixAutoUpdate = !1, this.update(); } dispose() { this.geometry.dispose(), this.material.dispose(); } update() { - this.color !== void 0 ? this.material.color.set(this.color) : this.material.color.copy(this.light.color); + this.light.updateWorldMatrix(!0, !1), this.color !== void 0 ? this.material.color.set(this.color) : this.material.color.copy(this.light.color); } -}, Py = new M, Nc = new ae, Bc = new ae, Iy = class extends Ne { +}, Bx = new A, qu = new pe, Yu = new pe, Zu = class extends Je { constructor(e, t, n){ - super(); - this.light = e, this.light.updateMatrixWorld(), this.matrix = e.matrixWorld, this.matrixAutoUpdate = !1, this.color = n; - let i = new Ii(t); - i.rotateY(Math.PI * .5), this.material = new hn({ + super(), this.light = e, this.matrix = e.matrixWorld, this.matrixAutoUpdate = !1, this.color = n, this.type = "HemisphereLightHelper"; + let i = new ha(t); + i.rotateY(Math.PI * .5), this.material = new Sn({ wireframe: !0, fog: !1, toneMapped: !1 }), this.color === void 0 && (this.material.vertexColors = !0); - let r = i.getAttribute("position"), o = new Float32Array(r.count * 3); - i.setAttribute("color", new Ue(o, 3)), this.add(new st(i, this.material)), this.update(); + let r = i.getAttribute("position"), a = new Float32Array(r.count * 3); + i.setAttribute("color", new et(a, 3)), this.add(new Mt(i, this.material)), this.update(); } dispose() { this.children[0].geometry.dispose(), this.children[0].material.dispose(); @@ -17649,65 +19254,68 @@ var Ry = class extends st { if (this.color !== void 0) this.material.color.set(this.color); else { let t = e.geometry.getAttribute("color"); - Nc.copy(this.light.color), Bc.copy(this.light.groundColor); + qu.copy(this.light.color), Yu.copy(this.light.groundColor); for(let n = 0, i = t.count; n < i; n++){ - let r = n < i / 2 ? Nc : Bc; + let r = n < i / 2 ? qu : Yu; t.setXYZ(n, r.r, r.g, r.b); } t.needsUpdate = !0; } - e.lookAt(Py.setFromMatrixPosition(this.light.matrixWorld).negate()); + this.light.updateWorldMatrix(!0, !1), e.lookAt(Bx.setFromMatrixPosition(this.light.matrixWorld).negate()); } -}, nu = class extends wt { +}, Ju = class extends en { constructor(e = 10, t = 10, n = 4473924, i = 8947848){ - n = new ae(n), i = new ae(i); - let r = t / 2, o = e / t, a = e / 2, l = [], c = []; - for(let d = 0, f = 0, m = -a; d <= t; d++, m += o){ - l.push(-a, 0, m, a, 0, m), l.push(m, 0, -a, m, 0, a); - let x = d === r ? n : i; - x.toArray(c, f), f += 3, x.toArray(c, f), f += 3, x.toArray(c, f), f += 3, x.toArray(c, f), f += 3; - } - let h = new _e; - h.setAttribute("position", new de(l, 3)), h.setAttribute("color", new de(c, 3)); - let u = new ft({ + n = new pe(n), i = new pe(i); + let r = t / 2, a = e / t, o = e / 2, c = [], l = []; + for(let d = 0, f = 0, m = -o; d <= t; d++, m += a){ + c.push(-o, 0, m, o, 0, m), c.push(m, 0, -o, m, 0, o); + let _ = d === r ? n : i; + _.toArray(l, f), f += 3, _.toArray(l, f), f += 3, _.toArray(l, f), f += 3, _.toArray(l, f), f += 3; + } + let h = new Ge; + h.setAttribute("position", new ve(c, 3)), h.setAttribute("color", new ve(l, 3)); + let u = new wt({ vertexColors: !0, toneMapped: !1 }); - super(h, u); - this.type = "GridHelper"; - } -}, Dy = class extends wt { - constructor(e = 10, t = 16, n = 8, i = 64, r = 4473924, o = 8947848){ - r = new ae(r), o = new ae(o); - let a = [], l = []; - for(let u = 0; u <= t; u++){ + super(h, u), this.type = "GridHelper"; + } + dispose() { + this.geometry.dispose(), this.material.dispose(); + } +}, $u = class extends en { + constructor(e = 10, t = 16, n = 8, i = 64, r = 4473924, a = 8947848){ + r = new pe(r), a = new pe(a); + let o = [], c = []; + if (t > 1) for(let u = 0; u < t; u++){ let d = u / t * (Math.PI * 2), f = Math.sin(d) * e, m = Math.cos(d) * e; - a.push(0, 0, 0), a.push(f, 0, m); - let x = u & 1 ? r : o; - l.push(x.r, x.g, x.b), l.push(x.r, x.g, x.b); + o.push(0, 0, 0), o.push(f, 0, m); + let _ = u & 1 ? r : a; + c.push(_.r, _.g, _.b), c.push(_.r, _.g, _.b); } - for(let u = 0; u <= n; u++){ - let d = u & 1 ? r : o, f = e - e / n * u; + for(let u = 0; u < n; u++){ + let d = u & 1 ? r : a, f = e - e / n * u; for(let m = 0; m < i; m++){ - let x = m / i * (Math.PI * 2), v = Math.sin(x) * f, g = Math.cos(x) * f; - a.push(v, 0, g), l.push(d.r, d.g, d.b), x = (m + 1) / i * (Math.PI * 2), v = Math.sin(x) * f, g = Math.cos(x) * f, a.push(v, 0, g), l.push(d.r, d.g, d.b); + let _ = m / i * (Math.PI * 2), g = Math.sin(_) * f, p = Math.cos(_) * f; + o.push(g, 0, p), c.push(d.r, d.g, d.b), _ = (m + 1) / i * (Math.PI * 2), g = Math.sin(_) * f, p = Math.cos(_) * f, o.push(g, 0, p), c.push(d.r, d.g, d.b); } } - let c = new _e; - c.setAttribute("position", new de(a, 3)), c.setAttribute("color", new de(l, 3)); - let h = new ft({ + let l = new Ge; + l.setAttribute("position", new ve(o, 3)), l.setAttribute("color", new ve(c, 3)); + let h = new wt({ vertexColors: !0, toneMapped: !1 }); - super(c, h); - this.type = "PolarGridHelper"; + super(l, h), this.type = "PolarGridHelper"; + } + dispose() { + this.geometry.dispose(), this.material.dispose(); } -}, zc = new M, As = new M, Uc = new M, Fy = class extends Ne { +}, Ku = new A, Ar = new A, Qu = new A, ju = class extends Je { constructor(e, t, n){ - super(); - this.light = e, this.light.updateMatrixWorld(), this.matrix = e.matrixWorld, this.matrixAutoUpdate = !1, this.color = n, t === void 0 && (t = 1); - let i = new _e; - i.setAttribute("position", new de([ + super(), this.light = e, this.matrix = e.matrixWorld, this.matrixAutoUpdate = !1, this.color = n, this.type = "DirectionalLightHelper", t === void 0 && (t = 1); + let i = new Ge; + i.setAttribute("position", new ve([ -t, t, 0, @@ -17724,60 +19332,64 @@ var Ry = class extends st { t, 0 ], 3)); - let r = new ft({ + let r = new wt({ fog: !1, toneMapped: !1 }); - this.lightPlane = new on(i, r), this.add(this.lightPlane), i = new _e, i.setAttribute("position", new de([ + this.lightPlane = new bn(i, r), this.add(this.lightPlane), i = new Ge, i.setAttribute("position", new ve([ 0, 0, 0, 0, 0, 1 - ], 3)), this.targetLine = new on(i, r), this.add(this.targetLine), this.update(); + ], 3)), this.targetLine = new bn(i, r), this.add(this.targetLine), this.update(); } dispose() { this.lightPlane.geometry.dispose(), this.lightPlane.material.dispose(), this.targetLine.geometry.dispose(), this.targetLine.material.dispose(); } update() { - zc.setFromMatrixPosition(this.light.matrixWorld), As.setFromMatrixPosition(this.light.target.matrixWorld), Uc.subVectors(As, zc), this.lightPlane.lookAt(As), this.color !== void 0 ? (this.lightPlane.material.color.set(this.color), this.targetLine.material.color.set(this.color)) : (this.lightPlane.material.color.copy(this.light.color), this.targetLine.material.color.copy(this.light.color)), this.targetLine.lookAt(As), this.targetLine.scale.z = Uc.length(); + this.light.updateWorldMatrix(!0, !1), this.light.target.updateWorldMatrix(!0, !1), Ku.setFromMatrixPosition(this.light.matrixWorld), Ar.setFromMatrixPosition(this.light.target.matrixWorld), Qu.subVectors(Ar, Ku), this.lightPlane.lookAt(Ar), this.color !== void 0 ? (this.lightPlane.material.color.set(this.color), this.targetLine.material.color.set(this.color)) : (this.lightPlane.material.color.copy(this.light.color), this.targetLine.material.color.copy(this.light.color)), this.targetLine.lookAt(Ar), this.targetLine.scale.z = Qu.length(); } -}, Cs = new M, Qe = new Ir, Ny = class extends wt { +}, Rr = new A, ot = new Cs, ed = class extends en { constructor(e){ - let t = new _e, n = new ft({ + let t = new Ge, n = new wt({ color: 16777215, vertexColors: !0, toneMapped: !1 - }), i = [], r = [], o = {}, a = new ae(16755200), l = new ae(16711680), c = new ae(43775), h = new ae(16777215), u = new ae(3355443); - d("n1", "n2", a), d("n2", "n4", a), d("n4", "n3", a), d("n3", "n1", a), d("f1", "f2", a), d("f2", "f4", a), d("f4", "f3", a), d("f3", "f1", a), d("n1", "f1", a), d("n2", "f2", a), d("n3", "f3", a), d("n4", "f4", a), d("p", "n1", l), d("p", "n2", l), d("p", "n3", l), d("p", "n4", l), d("u1", "u2", c), d("u2", "u3", c), d("u3", "u1", c), d("c", "t", h), d("p", "c", u), d("cn1", "cn2", u), d("cn3", "cn4", u), d("cf1", "cf2", u), d("cf3", "cf4", u); - function d(m, x, v) { - f(m, v), f(x, v); + }), i = [], r = [], a = {}; + o("n1", "n2"), o("n2", "n4"), o("n4", "n3"), o("n3", "n1"), o("f1", "f2"), o("f2", "f4"), o("f4", "f3"), o("f3", "f1"), o("n1", "f1"), o("n2", "f2"), o("n3", "f3"), o("n4", "f4"), o("p", "n1"), o("p", "n2"), o("p", "n3"), o("p", "n4"), o("u1", "u2"), o("u2", "u3"), o("u3", "u1"), o("c", "t"), o("p", "c"), o("cn1", "cn2"), o("cn3", "cn4"), o("cf1", "cf2"), o("cf3", "cf4"); + function o(m, _) { + c(m), c(_); } - function f(m, x) { - i.push(0, 0, 0), r.push(x.r, x.g, x.b), o[m] === void 0 && (o[m] = []), o[m].push(i.length / 3 - 1); + function c(m) { + i.push(0, 0, 0), r.push(0, 0, 0), a[m] === void 0 && (a[m] = []), a[m].push(i.length / 3 - 1); } - t.setAttribute("position", new de(i, 3)), t.setAttribute("color", new de(r, 3)); - super(t, n); - this.type = "CameraHelper", this.camera = e, this.camera.updateProjectionMatrix && this.camera.updateProjectionMatrix(), this.matrix = e.matrixWorld, this.matrixAutoUpdate = !1, this.pointMap = o, this.update(); + t.setAttribute("position", new ve(i, 3)), t.setAttribute("color", new ve(r, 3)), super(t, n), this.type = "CameraHelper", this.camera = e, this.camera.updateProjectionMatrix && this.camera.updateProjectionMatrix(), this.matrix = e.matrixWorld, this.matrixAutoUpdate = !1, this.pointMap = a, this.update(); + let l = new pe(16755200), h = new pe(16711680), u = new pe(43775), d = new pe(16777215), f = new pe(3355443); + this.setColors(l, h, u, d, f); + } + setColors(e, t, n, i, r) { + let o = this.geometry.getAttribute("color"); + o.setXYZ(0, e.r, e.g, e.b), o.setXYZ(1, e.r, e.g, e.b), o.setXYZ(2, e.r, e.g, e.b), o.setXYZ(3, e.r, e.g, e.b), o.setXYZ(4, e.r, e.g, e.b), o.setXYZ(5, e.r, e.g, e.b), o.setXYZ(6, e.r, e.g, e.b), o.setXYZ(7, e.r, e.g, e.b), o.setXYZ(8, e.r, e.g, e.b), o.setXYZ(9, e.r, e.g, e.b), o.setXYZ(10, e.r, e.g, e.b), o.setXYZ(11, e.r, e.g, e.b), o.setXYZ(12, e.r, e.g, e.b), o.setXYZ(13, e.r, e.g, e.b), o.setXYZ(14, e.r, e.g, e.b), o.setXYZ(15, e.r, e.g, e.b), o.setXYZ(16, e.r, e.g, e.b), o.setXYZ(17, e.r, e.g, e.b), o.setXYZ(18, e.r, e.g, e.b), o.setXYZ(19, e.r, e.g, e.b), o.setXYZ(20, e.r, e.g, e.b), o.setXYZ(21, e.r, e.g, e.b), o.setXYZ(22, e.r, e.g, e.b), o.setXYZ(23, e.r, e.g, e.b), o.setXYZ(24, t.r, t.g, t.b), o.setXYZ(25, t.r, t.g, t.b), o.setXYZ(26, t.r, t.g, t.b), o.setXYZ(27, t.r, t.g, t.b), o.setXYZ(28, t.r, t.g, t.b), o.setXYZ(29, t.r, t.g, t.b), o.setXYZ(30, t.r, t.g, t.b), o.setXYZ(31, t.r, t.g, t.b), o.setXYZ(32, n.r, n.g, n.b), o.setXYZ(33, n.r, n.g, n.b), o.setXYZ(34, n.r, n.g, n.b), o.setXYZ(35, n.r, n.g, n.b), o.setXYZ(36, n.r, n.g, n.b), o.setXYZ(37, n.r, n.g, n.b), o.setXYZ(38, i.r, i.g, i.b), o.setXYZ(39, i.r, i.g, i.b), o.setXYZ(40, r.r, r.g, r.b), o.setXYZ(41, r.r, r.g, r.b), o.setXYZ(42, r.r, r.g, r.b), o.setXYZ(43, r.r, r.g, r.b), o.setXYZ(44, r.r, r.g, r.b), o.setXYZ(45, r.r, r.g, r.b), o.setXYZ(46, r.r, r.g, r.b), o.setXYZ(47, r.r, r.g, r.b), o.setXYZ(48, r.r, r.g, r.b), o.setXYZ(49, r.r, r.g, r.b), o.needsUpdate = !0; } update() { let e = this.geometry, t = this.pointMap, n = 1, i = 1; - Qe.projectionMatrixInverse.copy(this.camera.projectionMatrixInverse), et("c", t, e, Qe, 0, 0, -1), et("t", t, e, Qe, 0, 0, 1), et("n1", t, e, Qe, -n, -i, -1), et("n2", t, e, Qe, n, -i, -1), et("n3", t, e, Qe, -n, i, -1), et("n4", t, e, Qe, n, i, -1), et("f1", t, e, Qe, -n, -i, 1), et("f2", t, e, Qe, n, -i, 1), et("f3", t, e, Qe, -n, i, 1), et("f4", t, e, Qe, n, i, 1), et("u1", t, e, Qe, n * .7, i * 1.1, -1), et("u2", t, e, Qe, -n * .7, i * 1.1, -1), et("u3", t, e, Qe, 0, i * 2, -1), et("cf1", t, e, Qe, -n, 0, 1), et("cf2", t, e, Qe, n, 0, 1), et("cf3", t, e, Qe, 0, -i, 1), et("cf4", t, e, Qe, 0, i, 1), et("cn1", t, e, Qe, -n, 0, -1), et("cn2", t, e, Qe, n, 0, -1), et("cn3", t, e, Qe, 0, -i, -1), et("cn4", t, e, Qe, 0, i, -1), e.getAttribute("position").needsUpdate = !0; + ot.projectionMatrixInverse.copy(this.camera.projectionMatrixInverse), ht("c", t, e, ot, 0, 0, -1), ht("t", t, e, ot, 0, 0, 1), ht("n1", t, e, ot, -n, -i, -1), ht("n2", t, e, ot, n, -i, -1), ht("n3", t, e, ot, -n, i, -1), ht("n4", t, e, ot, n, i, -1), ht("f1", t, e, ot, -n, -i, 1), ht("f2", t, e, ot, n, -i, 1), ht("f3", t, e, ot, -n, i, 1), ht("f4", t, e, ot, n, i, 1), ht("u1", t, e, ot, n * .7, i * 1.1, -1), ht("u2", t, e, ot, -n * .7, i * 1.1, -1), ht("u3", t, e, ot, 0, i * 2, -1), ht("cf1", t, e, ot, -n, 0, 1), ht("cf2", t, e, ot, n, 0, 1), ht("cf3", t, e, ot, 0, -i, 1), ht("cf4", t, e, ot, 0, i, 1), ht("cn1", t, e, ot, -n, 0, -1), ht("cn2", t, e, ot, n, 0, -1), ht("cn3", t, e, ot, 0, -i, -1), ht("cn4", t, e, ot, 0, i, -1), e.getAttribute("position").needsUpdate = !0; } dispose() { this.geometry.dispose(), this.material.dispose(); } }; -function et(s, e, t, n, i, r, o) { - Cs.set(i, r, o).unproject(n); - let a = e[s]; - if (a !== void 0) { - let l = t.getAttribute("position"); - for(let c = 0, h = a.length; c < h; c++)l.setXYZ(a[c], Cs.x, Cs.y, Cs.z); +function ht(s1, e, t, n, i, r, a) { + Rr.set(i, r, a).unproject(n); + let o = e[s1]; + if (o !== void 0) { + let c = t.getAttribute("position"); + for(let l = 0, h = o.length; l < h; l++)c.setXYZ(o[l], Rr.x, Rr.y, Rr.z); } } -var Ls = new Lt, iu = class extends wt { +var Cr = new Qt, td = class extends en { constructor(e, t = 16776960){ let n = new Uint16Array([ 0, @@ -17804,26 +19416,27 @@ var Ls = new Lt, iu = class extends wt { 6, 3, 7 - ]), i = new Float32Array(8 * 3), r = new _e; - r.setIndex(new Ue(n, 1)), r.setAttribute("position", new Ue(i, 3)); - super(r, new ft({ + ]), i = new Float32Array(8 * 3), r = new Ge; + r.setIndex(new et(n, 1)), r.setAttribute("position", new et(i, 3)), super(r, new wt({ color: t, toneMapped: !1 - })); - this.object = e, this.type = "BoxHelper", this.matrixAutoUpdate = !1, this.update(); + })), this.object = e, this.type = "BoxHelper", this.matrixAutoUpdate = !1, this.update(); } update(e) { - if (e !== void 0 && console.warn("THREE.BoxHelper: .update() has no longer arguments."), this.object !== void 0 && Ls.setFromObject(this.object), Ls.isEmpty()) return; - let t = Ls.min, n = Ls.max, i = this.geometry.attributes.position, r = i.array; + if (e !== void 0 && console.warn("THREE.BoxHelper: .update() has no longer arguments."), this.object !== void 0 && Cr.setFromObject(this.object), Cr.isEmpty()) return; + let t = Cr.min, n = Cr.max, i = this.geometry.attributes.position, r = i.array; r[0] = n.x, r[1] = n.y, r[2] = n.z, r[3] = t.x, r[4] = n.y, r[5] = n.z, r[6] = t.x, r[7] = t.y, r[8] = n.z, r[9] = n.x, r[10] = t.y, r[11] = n.z, r[12] = n.x, r[13] = n.y, r[14] = t.z, r[15] = t.x, r[16] = n.y, r[17] = t.z, r[18] = t.x, r[19] = t.y, r[20] = t.z, r[21] = n.x, r[22] = t.y, r[23] = t.z, i.needsUpdate = !0, this.geometry.computeBoundingSphere(); } setFromObject(e) { return this.object = e, this.update(), this; } - copy(e) { - return wt.prototype.copy.call(this, e), this.object = e.object, this; + copy(e, t) { + return super.copy(e, t), this.object = e.object, this; + } + dispose() { + this.geometry.dispose(), this.material.dispose(); } -}, By = class extends wt { +}, nd = class extends en { constructor(e, t = 16776960){ let n = new Uint16Array([ 0, @@ -17875,79 +19488,72 @@ var Ls = new Lt, iu = class extends wt { 1, -1, -1 - ], r = new _e; - r.setIndex(new Ue(n, 1)), r.setAttribute("position", new de(i, 3)); - super(r, new ft({ + ], r = new Ge; + r.setIndex(new et(n, 1)), r.setAttribute("position", new ve(i, 3)), super(r, new wt({ color: t, toneMapped: !1 - })); - this.box = e, this.type = "Box3Helper", this.geometry.computeBoundingSphere(); + })), this.box = e, this.type = "Box3Helper", this.geometry.computeBoundingSphere(); } updateMatrixWorld(e) { let t = this.box; t.isEmpty() || (t.getCenter(this.position), t.getSize(this.scale), this.scale.multiplyScalar(.5), super.updateMatrixWorld(e)); } -}, zy = class extends on { + dispose() { + this.geometry.dispose(), this.material.dispose(); + } +}, id = class extends bn { constructor(e, t = 1, n = 16776960){ let i = n, r = [ 1, -1, - 1, + 0, -1, 1, - 1, + 0, -1, -1, + 0, 1, 1, - 1, - 1, + 0, -1, 1, - 1, + 0, -1, -1, - 1, + 0, 1, -1, - 1, - 1, - 1, - 1, - 0, 0, 1, - 0, - 0, + 1, 0 - ], o = new _e; - o.setAttribute("position", new de(r, 3)), o.computeBoundingSphere(); - super(o, new ft({ + ], a = new Ge; + a.setAttribute("position", new ve(r, 3)), a.computeBoundingSphere(), super(a, new wt({ color: i, toneMapped: !1 - })); - this.type = "PlaneHelper", this.plane = e, this.size = t; - let a = [ - 1, + })), this.type = "PlaneHelper", this.plane = e, this.size = t; + let o = [ 1, 1, + 0, -1, 1, - 1, + 0, -1, -1, + 0, 1, 1, - 1, - 1, + 0, -1, -1, - 1, + 0, 1, -1, - 1 - ], l = new _e; - l.setAttribute("position", new de(a, 3)), l.computeBoundingSphere(), this.add(new st(l, new hn({ + 0 + ], c = new Ge; + c.setAttribute("position", new ve(o, 3)), c.computeBoundingSphere(), this.add(new Mt(c, new Sn({ color: i, opacity: .2, transparent: !0, @@ -17956,34 +19562,35 @@ var Ls = new Lt, iu = class extends wt { }))); } updateMatrixWorld(e) { - let t = -this.plane.constant; - Math.abs(t) < 1e-8 && (t = 1e-8), this.scale.set(.5 * this.size, .5 * this.size, t), this.children[0].material.side = t < 0 ? it : Ai, this.lookAt(this.plane.normal), super.updateMatrixWorld(e); + this.position.set(0, 0, 0), this.scale.set(.5 * this.size, .5 * this.size, 1), this.lookAt(this.plane.normal), this.translateZ(-this.plane.constant), super.updateMatrixWorld(e); } -}, Oc = new M, Rs, Ko, Uy = class extends Ne { - constructor(e = new M(0, 0, 1), t = new M(0, 0, 0), n = 1, i = 16776960, r = n * .2, o = r * .2){ - super(); - this.type = "ArrowHelper", Rs === void 0 && (Rs = new _e, Rs.setAttribute("position", new de([ + dispose() { + this.geometry.dispose(), this.material.dispose(), this.children[0].geometry.dispose(), this.children[0].material.dispose(); + } +}, sd = new A, Pr, ho, rd = class extends Je { + constructor(e = new A(0, 0, 1), t = new A(0, 0, 0), n = 1, i = 16776960, r = n * .2, a = r * .2){ + super(), this.type = "ArrowHelper", Pr === void 0 && (Pr = new Ge, Pr.setAttribute("position", new ve([ 0, 0, 0, 0, 1, 0 - ], 3)), Ko = new Jn(0, .5, 1, 5, 1), Ko.translate(0, -.5, 0)), this.position.copy(t), this.line = new on(Rs, new ft({ + ], 3)), ho = new Ns(0, .5, 1, 5, 1), ho.translate(0, -.5, 0)), this.position.copy(t), this.line = new bn(Pr, new wt({ color: i, toneMapped: !1 - })), this.line.matrixAutoUpdate = !1, this.add(this.line), this.cone = new st(Ko, new hn({ + })), this.line.matrixAutoUpdate = !1, this.add(this.line), this.cone = new Mt(ho, new Sn({ color: i, toneMapped: !1 - })), this.cone.matrixAutoUpdate = !1, this.add(this.cone), this.setDirection(e), this.setLength(n, r, o); + })), this.cone.matrixAutoUpdate = !1, this.add(this.cone), this.setDirection(e), this.setLength(n, r, a); } setDirection(e) { if (e.y > .99999) this.quaternion.set(0, 0, 0, 1); else if (e.y < -.99999) this.quaternion.set(1, 0, 0, 0); else { - Oc.set(e.z, 0, -e.x).normalize(); + sd.set(e.z, 0, -e.x).normalize(); let t = Math.acos(e.y); - this.quaternion.setFromAxisAngle(Oc, t); + this.quaternion.setFromAxisAngle(sd, t); } } setLength(e, t = e * .2, n = t * .2) { @@ -17995,7 +19602,10 @@ var Ls = new Lt, iu = class extends wt { copy(e) { return super.copy(e, !1), this.line.copy(e.line), this.cone.copy(e.cone), this; } -}, ru = class extends wt { + dispose() { + this.line.geometry.dispose(), this.line.material.dispose(), this.cone.geometry.dispose(), this.cone.material.dispose(); + } +}, ad = class extends en { constructor(e = 1){ let t = [ 0, @@ -18035,28 +19645,27 @@ var Ls = new Lt, iu = class extends wt { 0, .6, 1 - ], i = new _e; - i.setAttribute("position", new de(t, 3)), i.setAttribute("color", new de(n, 3)); - let r = new ft({ + ], i = new Ge; + i.setAttribute("position", new ve(t, 3)), i.setAttribute("color", new ve(n, 3)); + let r = new wt({ vertexColors: !0, toneMapped: !1 }); - super(i, r); - this.type = "AxesHelper"; + super(i, r), this.type = "AxesHelper"; } setColors(e, t, n) { - let i = new ae, r = this.geometry.attributes.color.array; + let i = new pe, r = this.geometry.attributes.color.array; return i.set(e), i.toArray(r, 0), i.toArray(r, 3), i.set(t), i.toArray(r, 6), i.toArray(r, 9), i.set(n), i.toArray(r, 12), i.toArray(r, 15), this.geometry.attributes.color.needsUpdate = !0, this; } dispose() { this.geometry.dispose(), this.material.dispose(); } -}, Oy = class { +}, od = class { constructor(){ - this.type = "ShapePath", this.color = new ae, this.subPaths = [], this.currentPath = null; + this.type = "ShapePath", this.color = new pe, this.subPaths = [], this.currentPath = null; } moveTo(e, t) { - return this.currentPath = new gr, this.subPaths.push(this.currentPath), this.currentPath.moveTo(e, t), this; + return this.currentPath = new ji, this.subPaths.push(this.currentPath), this.currentPath.moveTo(e, t), this; } lineTo(e, t) { return this.currentPath.lineTo(e, t), this; @@ -18064,1497 +19673,1352 @@ var Ls = new Lt, iu = class extends wt { quadraticCurveTo(e, t, n, i) { return this.currentPath.quadraticCurveTo(e, t, n, i), this; } - bezierCurveTo(e, t, n, i, r, o) { - return this.currentPath.bezierCurveTo(e, t, n, i, r, o), this; + bezierCurveTo(e, t, n, i, r, a) { + return this.currentPath.bezierCurveTo(e, t, n, i, r, a), this; } splineThru(e) { return this.currentPath.splineThru(e), this; } - toShapes(e, t) { - function n(p) { - let _ = []; - for(let y = 0, b = p.length; y < b; y++){ - let A = p[y], L = new Xt; - L.curves = A.curves, _.push(L); - } - return _; - } - function i(p, _) { - let y = _.length, b = !1; - for(let A = y - 1, L = 0; L < y; A = L++){ - let I = _[A], k = _[L], B = k.x - I.x, P = k.y - I.y; - if (Math.abs(P) > Number.EPSILON) { - if (P < 0 && (I = _[L], B = -B, k = _[A], P = -P), p.y < I.y || p.y > k.y) continue; - if (p.y === I.y) { - if (p.x === I.x) return !0; + toShapes(e) { + function t(p) { + let v = []; + for(let x = 0, y = p.length; x < y; x++){ + let b = p[x], w = new Fn; + w.curves = b.curves, v.push(w); + } + return v; + } + function n(p, v) { + let x = v.length, y = !1; + for(let b = x - 1, w = 0; w < x; b = w++){ + let R = v[b], I = v[w], M = I.x - R.x, T = I.y - R.y; + if (Math.abs(T) > Number.EPSILON) { + if (T < 0 && (R = v[w], M = -M, I = v[b], T = -T), p.y < R.y || p.y > I.y) continue; + if (p.y === R.y) { + if (p.x === R.x) return !0; } else { - let w = P * (p.x - I.x) - B * (p.y - I.y); - if (w === 0) return !0; - if (w < 0) continue; - b = !b; + let O = T * (p.x - R.x) - M * (p.y - R.y); + if (O === 0) return !0; + if (O < 0) continue; + y = !y; } } else { - if (p.y !== I.y) continue; - if (k.x <= p.x && p.x <= I.x || I.x <= p.x && p.x <= k.x) return !0; + if (p.y !== R.y) continue; + if (I.x <= p.x && p.x <= R.x || R.x <= p.x && p.x <= I.x) return !0; } } - return b; - } - let r = Jt.isClockWise, o = this.subPaths; - if (o.length === 0) return []; - if (t === !0) return n(o); - let a, l, c, h = []; - if (o.length === 1) return l = o[0], c = new Xt, c.curves = l.curves, h.push(c), h; - let u = !r(o[0].getPoints()); - u = e ? !u : u; - let d = [], f = [], m = [], x = 0, v; - f[x] = void 0, m[x] = []; - for(let p = 0, _ = o.length; p < _; p++)l = o[p], v = l.getPoints(), a = r(v), a = e ? !a : a, a ? (!u && f[x] && x++, f[x] = { - s: new Xt, - p: v - }, f[x].s.curves = l.curves, u && x++, m[x] = []) : m[x].push({ - h: l, - p: v[0] + return y; + } + let i = yn.isClockWise, r = this.subPaths; + if (r.length === 0) return []; + let a, o, c, l = []; + if (r.length === 1) return o = r[0], c = new Fn, c.curves = o.curves, l.push(c), l; + let h = !i(r[0].getPoints()); + h = e ? !h : h; + let u = [], d = [], f = [], m = 0, _; + d[m] = void 0, f[m] = []; + for(let p = 0, v = r.length; p < v; p++)o = r[p], _ = o.getPoints(), a = i(_), a = e ? !a : a, a ? (!h && d[m] && m++, d[m] = { + s: new Fn, + p: _ + }, d[m].s.curves = o.curves, h && m++, f[m] = []) : f[m].push({ + h: o, + p: _[0] }); - if (!f[0]) return n(o); - if (f.length > 1) { - let p = !1, _ = []; - for(let y = 0, b = f.length; y < b; y++)d[y] = []; - for(let y = 0, b = f.length; y < b; y++){ - let A = m[y]; - for(let L = 0; L < A.length; L++){ - let I = A[L], k = !0; - for(let B = 0; B < f.length; B++)i(I.p, f[B].p) && (y !== B && _.push({ - froms: y, - tos: B, - hole: L - }), k ? (k = !1, d[B].push(I)) : p = !0); - k && d[y].push(I); + if (!d[0]) return t(r); + if (d.length > 1) { + let p = !1, v = 0; + for(let x = 0, y = d.length; x < y; x++)u[x] = []; + for(let x = 0, y = d.length; x < y; x++){ + let b = f[x]; + for(let w = 0; w < b.length; w++){ + let R = b[w], I = !0; + for(let M = 0; M < d.length; M++)n(R.p, d[M].p) && (x !== M && v++, I ? (I = !1, u[M].push(R)) : p = !0); + I && u[x].push(R); } } - _.length > 0 && (p || (m = d)); - } - let g; - for(let p = 0, _ = f.length; p < _; p++){ - c = f[p].s, h.push(c), g = m[p]; - for(let y = 0, b = g.length; y < b; y++)c.holes.push(g[y].h); - } - return h; - } -}, su = new Float32Array(1), Hy = new Int32Array(su.buffer), ky = class { - static toHalfFloat(e) { - e > 65504 && (console.warn("THREE.DataUtils.toHalfFloat(): value exceeds 65504."), e = 65504), su[0] = e; - let t = Hy[0], n = t >> 16 & 32768, i = t >> 12 & 2047, r = t >> 23 & 255; - return r < 103 ? n : r > 142 ? (n |= 31744, n |= (r == 255 ? 0 : 1) && t & 8388607, n) : r < 113 ? (i |= 2048, n |= (i >> 114 - r) + (i >> 113 - r & 1), n) : (n |= r - 112 << 10 | i >> 1, n += i & 1, n); - } -}, b0 = 0, w0 = 1, S0 = 0, T0 = 1, E0 = 2; -function A0(s) { - return console.warn("THREE.MeshFaceMaterial has been removed. Use an Array instead."), s; -} -function C0(s = []) { - return console.warn("THREE.MultiMaterial has been removed. Use an Array instead."), s.isMultiMaterial = !0, s.materials = s, s.clone = function() { - return s.slice(); - }, s; -} -function L0(s, e) { - return console.warn("THREE.PointCloud has been renamed to THREE.Points."), new zr(s, e); -} -function R0(s) { - return console.warn("THREE.Particle has been renamed to THREE.Sprite."), new ro(s); -} -function P0(s, e) { - return console.warn("THREE.ParticleSystem has been renamed to THREE.Points."), new zr(s, e); -} -function I0(s) { - return console.warn("THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial."), new jn(s); -} -function D0(s) { - return console.warn("THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial."), new jn(s); -} -function F0(s) { - return console.warn("THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial."), new jn(s); -} -function N0(s, e, t) { - return console.warn("THREE.Vertex has been removed. Use THREE.Vector3 instead."), new M(s, e, t); -} -function B0(s, e) { - return console.warn("THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setUsage( THREE.DynamicDrawUsage ) instead."), new Ue(s, e).setUsage(ur); -} -function z0(s, e) { - return console.warn("THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead."), new jc(s, e); -} -function U0(s, e) { - return console.warn("THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead."), new Qc(s, e); -} -function O0(s, e) { - return console.warn("THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead."), new Kc(s, e); -} -function H0(s, e) { - return console.warn("THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead."), new eh(s, e); -} -function k0(s, e) { - return console.warn("THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead."), new Ys(s, e); -} -function G0(s, e) { - return console.warn("THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead."), new th(s, e); -} -function V0(s, e) { - return console.warn("THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead."), new Zs(s, e); -} -function W0(s, e) { - return console.warn("THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead."), new de(s, e); -} -function q0(s, e) { - return console.warn("THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead."), new ih(s, e); -} -Ct.create = function(s, e) { - return console.log("THREE.Curve.create() has been deprecated"), s.prototype = Object.create(Ct.prototype), s.prototype.constructor = s, s.prototype.getPoint = e, s; -}; -gr.prototype.fromPoints = function(s) { - return console.warn("THREE.Path: .fromPoints() has been renamed to .setFromPoints()."), this.setFromPoints(s); -}; -function X0(s) { - return console.warn("THREE.AxisHelper has been renamed to THREE.AxesHelper."), new ru(s); -} -function J0(s, e) { - return console.warn("THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead."), new iu(s, e); -} -function Y0(s, e) { - return console.warn("THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead."), new wt(new _a(s.geometry), new ft({ - color: e !== void 0 ? e : 16777215 - })); -} -nu.prototype.setColors = function() { - console.error("THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead."); -}; -eu.prototype.update = function() { - console.error("THREE.SkeletonHelper: update() no longer needs to be called."); -}; -function Z0(s, e) { - return console.warn("THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead."), new wt(new Ea(s.geometry), new ft({ - color: e !== void 0 ? e : 16777215 - })); -} -bt.prototype.extractUrlBase = function(s) { - return console.warn("THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead."), Gs.extractUrlBase(s); -}; -bt.Handlers = { - add: function() { - console.error("THREE.Loader: Handlers.add() has been removed. Use LoadingManager.addHandler() instead."); - }, - get: function() { - console.error("THREE.Loader: Handlers.get() has been removed. Use LoadingManager.getHandler() instead."); - } -}; -function $0(s) { - return console.warn("THREE.XHRLoader has been renamed to THREE.FileLoader."), new Yt(s); -} -function j0(s) { - return console.warn("THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader."), new Nh(s); -} -qi.prototype.center = function(s) { - return console.warn("THREE.Box2: .center() has been renamed to .getCenter()."), this.getCenter(s); -}; -qi.prototype.empty = function() { - return console.warn("THREE.Box2: .empty() has been renamed to .isEmpty()."), this.isEmpty(); -}; -qi.prototype.isIntersectionBox = function(s) { - return console.warn("THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox()."), this.intersectsBox(s); -}; -qi.prototype.size = function(s) { - return console.warn("THREE.Box2: .size() has been renamed to .getSize()."), this.getSize(s); -}; -Lt.prototype.center = function(s) { - return console.warn("THREE.Box3: .center() has been renamed to .getCenter()."), this.getCenter(s); -}; -Lt.prototype.empty = function() { - return console.warn("THREE.Box3: .empty() has been renamed to .isEmpty()."), this.isEmpty(); -}; -Lt.prototype.isIntersectionBox = function(s) { - return console.warn("THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox()."), this.intersectsBox(s); -}; -Lt.prototype.isIntersectionSphere = function(s) { - return console.warn("THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere()."), this.intersectsSphere(s); -}; -Lt.prototype.size = function(s) { - return console.warn("THREE.Box3: .size() has been renamed to .getSize()."), this.getSize(s); -}; -An.prototype.empty = function() { - return console.warn("THREE.Sphere: .empty() has been renamed to .isEmpty()."), this.isEmpty(); -}; -Dr.prototype.setFromMatrix = function(s) { - return console.warn("THREE.Frustum: .setFromMatrix() has been renamed to .setFromProjectionMatrix()."), this.setFromProjectionMatrix(s); -}; -Kh.prototype.center = function(s) { - return console.warn("THREE.Line3: .center() has been renamed to .getCenter()."), this.getCenter(s); -}; -lt.prototype.flattenToArrayOffset = function(s, e) { - return console.warn("THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead."), this.toArray(s, e); -}; -lt.prototype.multiplyVector3 = function(s) { - return console.warn("THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead."), s.applyMatrix3(this); -}; -lt.prototype.multiplyVector3Array = function() { - console.error("THREE.Matrix3: .multiplyVector3Array() has been removed."); -}; -lt.prototype.applyToBufferAttribute = function(s) { - return console.warn("THREE.Matrix3: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix3( matrix ) instead."), s.applyMatrix3(this); -}; -lt.prototype.applyToVector3Array = function() { - console.error("THREE.Matrix3: .applyToVector3Array() has been removed."); -}; -lt.prototype.getInverse = function(s) { - return console.warn("THREE.Matrix3: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead."), this.copy(s).invert(); -}; -pe.prototype.extractPosition = function(s) { - return console.warn("THREE.Matrix4: .extractPosition() has been renamed to .copyPosition()."), this.copyPosition(s); -}; -pe.prototype.flattenToArrayOffset = function(s, e) { - return console.warn("THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead."), this.toArray(s, e); -}; -pe.prototype.getPosition = function() { - return console.warn("THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead."), new M().setFromMatrixColumn(this, 3); -}; -pe.prototype.setRotationFromQuaternion = function(s) { - return console.warn("THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion()."), this.makeRotationFromQuaternion(s); -}; -pe.prototype.multiplyToArray = function() { - console.warn("THREE.Matrix4: .multiplyToArray() has been removed."); -}; -pe.prototype.multiplyVector3 = function(s) { - return console.warn("THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead."), s.applyMatrix4(this); -}; -pe.prototype.multiplyVector4 = function(s) { - return console.warn("THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead."), s.applyMatrix4(this); -}; -pe.prototype.multiplyVector3Array = function() { - console.error("THREE.Matrix4: .multiplyVector3Array() has been removed."); -}; -pe.prototype.rotateAxis = function(s) { - console.warn("THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead."), s.transformDirection(this); -}; -pe.prototype.crossVector = function(s) { - return console.warn("THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead."), s.applyMatrix4(this); -}; -pe.prototype.translate = function() { - console.error("THREE.Matrix4: .translate() has been removed."); -}; -pe.prototype.rotateX = function() { - console.error("THREE.Matrix4: .rotateX() has been removed."); -}; -pe.prototype.rotateY = function() { - console.error("THREE.Matrix4: .rotateY() has been removed."); -}; -pe.prototype.rotateZ = function() { - console.error("THREE.Matrix4: .rotateZ() has been removed."); -}; -pe.prototype.rotateByAxis = function() { - console.error("THREE.Matrix4: .rotateByAxis() has been removed."); -}; -pe.prototype.applyToBufferAttribute = function(s) { - return console.warn("THREE.Matrix4: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix4( matrix ) instead."), s.applyMatrix4(this); -}; -pe.prototype.applyToVector3Array = function() { - console.error("THREE.Matrix4: .applyToVector3Array() has been removed."); -}; -pe.prototype.makeFrustum = function(s, e, t, n, i, r) { - return console.warn("THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead."), this.makePerspective(s, e, n, t, i, r); -}; -pe.prototype.getInverse = function(s) { - return console.warn("THREE.Matrix4: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead."), this.copy(s).invert(); -}; -Wt.prototype.isIntersectionLine = function(s) { - return console.warn("THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine()."), this.intersectsLine(s); -}; -gt.prototype.multiplyVector3 = function(s) { - return console.warn("THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead."), s.applyQuaternion(this); -}; -gt.prototype.inverse = function() { - return console.warn("THREE.Quaternion: .inverse() has been renamed to invert()."), this.invert(); -}; -Cn.prototype.isIntersectionBox = function(s) { - return console.warn("THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox()."), this.intersectsBox(s); -}; -Cn.prototype.isIntersectionPlane = function(s) { - return console.warn("THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane()."), this.intersectsPlane(s); -}; -Cn.prototype.isIntersectionSphere = function(s) { - return console.warn("THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere()."), this.intersectsSphere(s); -}; -nt.prototype.area = function() { - return console.warn("THREE.Triangle: .area() has been renamed to .getArea()."), this.getArea(); -}; -nt.prototype.barycoordFromPoint = function(s, e) { - return console.warn("THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord()."), this.getBarycoord(s, e); -}; -nt.prototype.midpoint = function(s) { - return console.warn("THREE.Triangle: .midpoint() has been renamed to .getMidpoint()."), this.getMidpoint(s); -}; -nt.prototypenormal = function(s) { - return console.warn("THREE.Triangle: .normal() has been renamed to .getNormal()."), this.getNormal(s); -}; -nt.prototype.plane = function(s) { - return console.warn("THREE.Triangle: .plane() has been renamed to .getPlane()."), this.getPlane(s); -}; -nt.barycoordFromPoint = function(s, e, t, n, i) { - return console.warn("THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord()."), nt.getBarycoord(s, e, t, n, i); -}; -nt.normal = function(s, e, t, n) { - return console.warn("THREE.Triangle: .normal() has been renamed to .getNormal()."), nt.getNormal(s, e, t, n); -}; -Xt.prototype.extractAllPoints = function(s) { - return console.warn("THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead."), this.extractPoints(s); -}; -Xt.prototype.extrude = function(s) { - return console.warn("THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead."), new ln(this, s); -}; -Xt.prototype.makeGeometry = function(s) { - return console.warn("THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead."), new Di(this, s); -}; -X.prototype.fromAttribute = function(s, e, t) { - return console.warn("THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute()."), this.fromBufferAttribute(s, e, t); -}; -X.prototype.distanceToManhattan = function(s) { - return console.warn("THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo()."), this.manhattanDistanceTo(s); -}; -X.prototype.lengthManhattan = function() { - return console.warn("THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength()."), this.manhattanLength(); -}; -M.prototype.setEulerFromRotationMatrix = function() { - console.error("THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead."); -}; -M.prototype.setEulerFromQuaternion = function() { - console.error("THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead."); -}; -M.prototype.getPositionFromMatrix = function(s) { - return console.warn("THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition()."), this.setFromMatrixPosition(s); -}; -M.prototype.getScaleFromMatrix = function(s) { - return console.warn("THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale()."), this.setFromMatrixScale(s); -}; -M.prototype.getColumnFromMatrix = function(s, e) { - return console.warn("THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn()."), this.setFromMatrixColumn(e, s); -}; -M.prototype.applyProjection = function(s) { - return console.warn("THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead."), this.applyMatrix4(s); -}; -M.prototype.fromAttribute = function(s, e, t) { - return console.warn("THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute()."), this.fromBufferAttribute(s, e, t); -}; -M.prototype.distanceToManhattan = function(s) { - return console.warn("THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo()."), this.manhattanDistanceTo(s); -}; -M.prototype.lengthManhattan = function() { - return console.warn("THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength()."), this.manhattanLength(); -}; -Ve.prototype.fromAttribute = function(s, e, t) { - return console.warn("THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute()."), this.fromBufferAttribute(s, e, t); -}; -Ve.prototype.lengthManhattan = function() { - return console.warn("THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength()."), this.manhattanLength(); -}; -Ne.prototype.getChildByName = function(s) { - return console.warn("THREE.Object3D: .getChildByName() has been renamed to .getObjectByName()."), this.getObjectByName(s); -}; -Ne.prototype.renderDepth = function() { - console.warn("THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead."); -}; -Ne.prototype.translate = function(s, e) { - return console.warn("THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead."), this.translateOnAxis(e, s); -}; -Ne.prototype.getWorldRotation = function() { - console.error("THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead."); -}; -Ne.prototype.applyMatrix = function(s) { - return console.warn("THREE.Object3D: .applyMatrix() has been renamed to .applyMatrix4()."), this.applyMatrix4(s); -}; -Object.defineProperties(Ne.prototype, { - eulerOrder: { - get: function() { - return console.warn("THREE.Object3D: .eulerOrder is now .rotation.order."), this.rotation.order; - }, - set: function(s) { - console.warn("THREE.Object3D: .eulerOrder is now .rotation.order."), this.rotation.order = s; - } - }, - useQuaternion: { - get: function() { - console.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default."); - }, - set: function() { - console.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default."); - } - } -}); -st.prototype.setDrawMode = function() { - console.error("THREE.Mesh: .setDrawMode() has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary."); -}; -Object.defineProperties(st.prototype, { - drawMode: { - get: function() { - return console.error("THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode."), Fd; - }, - set: function() { - console.error("THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary."); - } - } -}); -so.prototype.initBones = function() { - console.error("THREE.SkinnedMesh: initBones() has been removed."); -}; -ut.prototype.setLens = function(s, e) { - console.warn("THREE.PerspectiveCamera.setLens is deprecated. Use .setFocalLength and .filmGauge for a photographic setup."), e !== void 0 && (this.filmGauge = e), this.setFocalLength(s); -}; -Object.defineProperties(Bt.prototype, { - onlyShadow: { - set: function() { - console.warn("THREE.Light: .onlyShadow has been removed."); - } - }, - shadowCameraFov: { - set: function(s) { - console.warn("THREE.Light: .shadowCameraFov is now .shadow.camera.fov."), this.shadow.camera.fov = s; - } - }, - shadowCameraLeft: { - set: function(s) { - console.warn("THREE.Light: .shadowCameraLeft is now .shadow.camera.left."), this.shadow.camera.left = s; - } - }, - shadowCameraRight: { - set: function(s) { - console.warn("THREE.Light: .shadowCameraRight is now .shadow.camera.right."), this.shadow.camera.right = s; - } - }, - shadowCameraTop: { - set: function(s) { - console.warn("THREE.Light: .shadowCameraTop is now .shadow.camera.top."), this.shadow.camera.top = s; - } - }, - shadowCameraBottom: { - set: function(s) { - console.warn("THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom."), this.shadow.camera.bottom = s; - } - }, - shadowCameraNear: { - set: function(s) { - console.warn("THREE.Light: .shadowCameraNear is now .shadow.camera.near."), this.shadow.camera.near = s; - } - }, - shadowCameraFar: { - set: function(s) { - console.warn("THREE.Light: .shadowCameraFar is now .shadow.camera.far."), this.shadow.camera.far = s; - } - }, - shadowCameraVisible: { - set: function() { - console.warn("THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead."); - } - }, - shadowBias: { - set: function(s) { - console.warn("THREE.Light: .shadowBias is now .shadow.bias."), this.shadow.bias = s; - } - }, - shadowDarkness: { - set: function() { - console.warn("THREE.Light: .shadowDarkness has been removed."); - } - }, - shadowMapWidth: { - set: function(s) { - console.warn("THREE.Light: .shadowMapWidth is now .shadow.mapSize.width."), this.shadow.mapSize.width = s; - } - }, - shadowMapHeight: { - set: function(s) { - console.warn("THREE.Light: .shadowMapHeight is now .shadow.mapSize.height."), this.shadow.mapSize.height = s; - } - } -}); -Object.defineProperties(Ue.prototype, { - length: { - get: function() { - return console.warn("THREE.BufferAttribute: .length has been deprecated. Use .count instead."), this.array.length; - } - }, - dynamic: { - get: function() { - return console.warn("THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead."), this.usage === ur; - }, - set: function() { - console.warn("THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead."), this.setUsage(ur); - } - } -}); -Ue.prototype.setDynamic = function(s) { - return console.warn("THREE.BufferAttribute: .setDynamic() has been deprecated. Use .setUsage() instead."), this.setUsage(s === !0 ? ur : hr), this; -}; -Ue.prototype.copyIndicesArray = function() { - console.error("THREE.BufferAttribute: .copyIndicesArray() has been removed."); -}, Ue.prototype.setArray = function() { - console.error("THREE.BufferAttribute: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers"); -}; -_e.prototype.addIndex = function(s) { - console.warn("THREE.BufferGeometry: .addIndex() has been renamed to .setIndex()."), this.setIndex(s); -}; -_e.prototype.addAttribute = function(s, e) { - return console.warn("THREE.BufferGeometry: .addAttribute() has been renamed to .setAttribute()."), !(e && e.isBufferAttribute) && !(e && e.isInterleavedBufferAttribute) ? (console.warn("THREE.BufferGeometry: .addAttribute() now expects ( name, attribute )."), this.setAttribute(s, new Ue(arguments[1], arguments[2]))) : s === "index" ? (console.warn("THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute."), this.setIndex(e), this) : this.setAttribute(s, e); -}; -_e.prototype.addDrawCall = function(s, e, t) { - t !== void 0 && console.warn("THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset."), console.warn("THREE.BufferGeometry: .addDrawCall() is now .addGroup()."), this.addGroup(s, e); -}; -_e.prototype.clearDrawCalls = function() { - console.warn("THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups()."), this.clearGroups(); -}; -_e.prototype.computeOffsets = function() { - console.warn("THREE.BufferGeometry: .computeOffsets() has been removed."); -}; -_e.prototype.removeAttribute = function(s) { - return console.warn("THREE.BufferGeometry: .removeAttribute() has been renamed to .deleteAttribute()."), this.deleteAttribute(s); -}; -_e.prototype.applyMatrix = function(s) { - return console.warn("THREE.BufferGeometry: .applyMatrix() has been renamed to .applyMatrix4()."), this.applyMatrix4(s); -}; -Object.defineProperties(_e.prototype, { - drawcalls: { - get: function() { - return console.error("THREE.BufferGeometry: .drawcalls has been renamed to .groups."), this.groups; + v > 0 && p === !1 && (f = u); } - }, - offsets: { - get: function() { - return console.warn("THREE.BufferGeometry: .offsets has been renamed to .groups."), this.groups; + let g; + for(let p = 0, v = d.length; p < v; p++){ + c = d[p].s, l.push(c), g = f[p]; + for(let x = 0, y = g.length; x < y; x++)c.holes.push(g[x].h); } + return l; } -}); -$n.prototype.setDynamic = function(s) { - return console.warn("THREE.InterleavedBuffer: .setDynamic() has been deprecated. Use .setUsage() instead."), this.setUsage(s === !0 ? ur : hr), this; -}; -$n.prototype.setArray = function() { - console.error("THREE.InterleavedBuffer: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers"); -}; -ln.prototype.getArrays = function() { - console.error("THREE.ExtrudeGeometry: .getArrays() has been removed."); }; -ln.prototype.addShapeList = function() { - console.error("THREE.ExtrudeGeometry: .addShapeList() has been removed."); -}; -ln.prototype.addShape = function() { - console.error("THREE.ExtrudeGeometry: .addShape() has been removed."); -}; -no.prototype.dispose = function() { - console.error("THREE.Scene: .dispose() has been removed."); -}; -go.prototype.onUpdate = function() { - return console.warn("THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead."), this; +typeof __THREE_DEVTOOLS__ < "u" && __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("register", { + detail: { + revision: Hc + } +})); +typeof window < "u" && (window.__THREE__ ? console.warn("WARNING: Multiple instances of Three.js being imported.") : window.__THREE__ = Hc); +const mod = { + ACESFilmicToneMapping: mf, + AddEquation: Bi, + AddOperation: uf, + AdditiveAnimationBlendMode: xd, + AdditiveBlending: al, + AlphaFormat: vf, + AlwaysCompare: Vf, + AlwaysDepth: sf, + AlwaysStencilFunc: If, + AmbientLight: Cc, + AnimationAction: Vc, + AnimationClip: is, + AnimationLoader: au, + AnimationMixer: Cu, + AnimationObjectGroup: Ru, + AnimationUtils: Sv, + ArcCurve: ko, + ArrayCamera: To, + ArrowHelper: rd, + Audio: Fc, + AudioAnalyser: Au, + AudioContext: _a, + AudioListener: Eu, + AudioLoader: xu, + AxesHelper: ad, + BackSide: Ft, + BasicDepthPacking: Cf, + BasicShadowMap: Hx, + Bone: ta, + BooleanKeyframeTrack: Vn, + Box2: zu, + Box3: Qt, + Box3Helper: nd, + BoxGeometry: Ji, + BoxHelper: td, + BufferAttribute: et, + BufferGeometry: Ge, + BufferGeometryLoader: Nc, + ByteType: _f, + Cache: ss, + Camera: Cs, + CameraHelper: ed, + CanvasTexture: jh, + CapsuleGeometry: qo, + CatmullRomCurve3: Ho, + CineonToneMapping: pf, + CircleGeometry: Yo, + ClampToEdgeWrapping: It, + Clock: Oc, + Color: pe, + ColorKeyframeTrack: pa, + ColorManagement: Qe, + CompressedArrayTexture: Kh, + CompressedCubeTexture: Qh, + CompressedTexture: Us, + CompressedTextureLoader: ou, + ConeGeometry: Zo, + CubeCamera: _o, + CubeReflectionMapping: zn, + CubeRefractionMapping: ci, + CubeTexture: Ki, + CubeTextureLoader: cu, + CubeUVReflectionMapping: Vs, + CubicBezierCurve: ia, + CubicBezierCurve3: Go, + CubicInterpolant: xc, + CullFaceBack: rl, + CullFaceFront: Hd, + CullFaceFrontBack: kx, + CullFaceNone: kd, + Curve: Zt, + CurvePath: Xo, + CustomBlending: Wd, + CustomToneMapping: gf, + CylinderGeometry: Ns, + Cylindrical: Fu, + Data3DTexture: qr, + DataArrayTexture: As, + DataTexture: oi, + DataTextureLoader: lu, + DataUtils: Mv, + DecrementStencilOp: ev, + DecrementWrapStencilOp: nv, + DefaultLoadingManager: Ex, + DepthFormat: si, + DepthStencilFormat: Yi, + DepthTexture: wo, + DirectionalLight: Rc, + DirectionalLightHelper: ju, + DiscreteInterpolant: vc, + DisplayP3ColorSpace: qc, + DodecahedronGeometry: Jo, + DoubleSide: gn, + DstAlphaFactor: Kd, + DstColorFactor: jd, + DynamicCopyUsage: _v, + DynamicDrawUsage: uv, + DynamicReadUsage: pv, + EdgesGeometry: $o, + EllipseCurve: Ds, + EqualCompare: Nf, + EqualDepth: af, + EqualStencilFunc: av, + EquirectangularReflectionMapping: Ir, + EquirectangularRefractionMapping: Ur, + Euler: Yr, + EventDispatcher: sn, + ExtrudeGeometry: jo, + FileLoader: rn, + Float16BufferAttribute: ih, + Float32BufferAttribute: ve, + Float64BufferAttribute: sh, + FloatType: xn, + Fog: Lo, + FogExp2: Po, + FramebufferTexture: $h, + FrontSide: Bn, + Frustum: Ps, + GLBufferAttribute: Uu, + GLSL1: vv, + GLSL3: Ol, + GreaterCompare: Ff, + GreaterDepth: cf, + GreaterEqualCompare: zf, + GreaterEqualDepth: of, + GreaterEqualStencilFunc: hv, + GreaterStencilFunc: cv, + GridHelper: Ju, + Group: ti, + HalfFloatType: Ts, + HemisphereLight: Sc, + HemisphereLightHelper: Zu, + IcosahedronGeometry: ec, + ImageBitmapLoader: _u, + ImageLoader: rs, + ImageUtils: Xr, + IncrementStencilOp: jx, + IncrementWrapStencilOp: tv, + InstancedBufferAttribute: ui, + InstancedBufferGeometry: Dc, + InstancedInterleavedBuffer: Iu, + InstancedMesh: Fo, + Int16BufferAttribute: th, + Int32BufferAttribute: nh, + Int8BufferAttribute: Ql, + IntType: dd, + InterleavedBuffer: Is, + InterleavedBufferAttribute: Qi, + Interpolant: es, + InterpolateDiscrete: Or, + InterpolateLinear: Fr, + InterpolateSmooth: La, + InvertStencilOp: iv, + KeepStencilOp: Ia, + KeyframeTrack: Jt, + LOD: Do, + LatheGeometry: la, + Layers: Rs, + LessCompare: Df, + LessDepth: rf, + LessEqualCompare: Of, + LessEqualDepth: uo, + LessEqualStencilFunc: ov, + LessStencilFunc: rv, + Light: En, + LightProbe: Ic, + Line: bn, + Line3: ku, + LineBasicMaterial: wt, + LineCurve: sa, + LineCurve3: Wo, + LineDashedMaterial: gc, + LineLoop: Bo, + LineSegments: en, + LinearDisplayP3ColorSpace: va, + LinearEncoding: vd, + LinearFilter: mt, + LinearInterpolant: fa, + LinearMipMapLinearFilter: Yx, + LinearMipMapNearestFilter: qx, + LinearMipmapLinearFilter: li, + LinearMipmapNearestFilter: ud, + LinearSRGBColorSpace: Mn, + LinearToneMapping: df, + LinearTransfer: zr, + Loader: Dt, + LoaderUtils: ga, + LoadingManager: ma, + LoopOnce: wf, + LoopPingPong: Rf, + LoopRepeat: Af, + LuminanceAlphaFormat: Mf, + LuminanceFormat: yf, + MOUSE: zx, + Material: bt, + MaterialLoader: Uc, + MathUtils: yv, + Matrix3: He, + Matrix4: ze, + MaxEquation: hl, + Mesh: Mt, + MeshBasicMaterial: Sn, + MeshDepthMaterial: Qr, + MeshDistanceMaterial: jr, + MeshLambertMaterial: pc, + MeshMatcapMaterial: mc, + MeshNormalMaterial: fc, + MeshPhongMaterial: uc, + MeshPhysicalMaterial: hc, + MeshStandardMaterial: da, + MeshToonMaterial: dc, + MinEquation: ll, + MirroredRepeatWrapping: Nr, + MixOperation: hf, + MultiplyBlending: cl, + MultiplyOperation: xa, + NearestFilter: pt, + NearestMipMapLinearFilter: Xx, + NearestMipMapNearestFilter: Wx, + NearestMipmapLinearFilter: Lr, + NearestMipmapNearestFilter: fo, + NeverCompare: Uf, + NeverDepth: nf, + NeverStencilFunc: sv, + NoBlending: Dn, + NoColorSpace: Xt, + NoToneMapping: Nn, + NormalAnimationBlendMode: Xc, + NormalBlending: Wi, + NotEqualCompare: Bf, + NotEqualDepth: lf, + NotEqualStencilFunc: lv, + NumberKeyframeTrack: ts, + Object3D: Je, + ObjectLoader: pu, + ObjectSpaceNormalMap: Lf, + OctahedronGeometry: ha, + OneFactor: Zd, + OneMinusDstAlphaFactor: Qd, + OneMinusDstColorFactor: ef, + OneMinusSrcAlphaFactor: hd, + OneMinusSrcColorFactor: $d, + OrthographicCamera: Ls, + P3Primaries: kr, + PCFShadowMap: cd, + PCFSoftShadowMap: Gd, + PMREMGenerator: Kr, + Path: ji, + PerspectiveCamera: yt, + Plane: mn, + PlaneGeometry: $r, + PlaneHelper: id, + PointLight: wc, + PointLightHelper: Xu, + Points: Vo, + PointsMaterial: na, + PolarGridHelper: $u, + PolyhedronGeometry: di, + PositionalAudio: wu, + PropertyBinding: Ke, + PropertyMixer: Bc, + QuadraticBezierCurve: ra, + QuadraticBezierCurve3: aa, + Quaternion: Ut, + QuaternionKeyframeTrack: pi, + QuaternionLinearInterpolant: yc, + RED_GREEN_RGTC2_Format: Dl, + RED_RGTC1_Format: Tf, + REVISION: Hc, + RGBADepthPacking: Pf, + RGBAFormat: Wt, + RGBAIntegerFormat: _d, + RGBA_ASTC_10x10_Format: Rl, + RGBA_ASTC_10x5_Format: Tl, + RGBA_ASTC_10x6_Format: wl, + RGBA_ASTC_10x8_Format: Al, + RGBA_ASTC_12x10_Format: Cl, + RGBA_ASTC_12x12_Format: Pl, + RGBA_ASTC_4x4_Format: _l, + RGBA_ASTC_5x4_Format: xl, + RGBA_ASTC_5x5_Format: vl, + RGBA_ASTC_6x5_Format: yl, + RGBA_ASTC_6x6_Format: Ml, + RGBA_ASTC_8x5_Format: Sl, + RGBA_ASTC_8x6_Format: bl, + RGBA_ASTC_8x8_Format: El, + RGBA_BPTC_Format: Pa, + RGBA_ETC2_EAC_Format: gl, + RGBA_PVRTC_2BPPV1_Format: pl, + RGBA_PVRTC_4BPPV1_Format: fl, + RGBA_S3TC_DXT1_Format: Aa, + RGBA_S3TC_DXT3_Format: Ra, + RGBA_S3TC_DXT5_Format: Ca, + RGB_BPTC_SIGNED_Format: Ll, + RGB_BPTC_UNSIGNED_Format: Il, + RGB_ETC1_Format: Ef, + RGB_ETC2_Format: ml, + RGB_PVRTC_2BPPV1_Format: dl, + RGB_PVRTC_4BPPV1_Format: ul, + RGB_S3TC_DXT1_Format: wa, + RGFormat: bf, + RGIntegerFormat: gd, + RawShaderMaterial: lc, + Ray: hi, + Raycaster: Du, + Rec709Primaries: Vr, + RectAreaLight: Pc, + RedFormat: Sf, + RedIntegerFormat: md, + ReinhardToneMapping: ff, + RenderTarget: go, + RepeatWrapping: Dr, + ReplaceStencilOp: Qx, + ReverseSubtractEquation: qd, + RingGeometry: tc, + SIGNED_RED_GREEN_RGTC2_Format: Nl, + SIGNED_RED_RGTC1_Format: Ul, + SRGBColorSpace: vt, + SRGBTransfer: nt, + Scene: Io, + ShaderChunk: ke, + ShaderLib: nn, + ShaderMaterial: jt, + ShadowMaterial: cc, + Shape: Fn, + ShapeGeometry: nc, + ShapePath: od, + ShapeUtils: yn, + ShortType: xf, + Skeleton: Oo, + SkeletonHelper: Wu, + SkinnedMesh: No, + Source: In, + Sphere: Yt, + SphereGeometry: ua, + Spherical: Ou, + SphericalHarmonics3: Lc, + SplineCurve: oa, + SpotLight: Ec, + SpotLightHelper: Gu, + Sprite: Uo, + SpriteMaterial: ea, + SrcAlphaFactor: ld, + SrcAlphaSaturateFactor: tf, + SrcColorFactor: Jd, + StaticCopyUsage: gv, + StaticDrawUsage: Hr, + StaticReadUsage: fv, + StereoCamera: Mu, + StreamCopyUsage: xv, + StreamDrawUsage: dv, + StreamReadUsage: mv, + StringKeyframeTrack: kn, + SubtractEquation: Xd, + SubtractiveBlending: ol, + TOUCH: Vx, + TangentSpaceNormalMap: mi, + TetrahedronGeometry: ic, + Texture: St, + TextureLoader: hu, + TorusGeometry: sc, + TorusKnotGeometry: rc, + Triangle: Un, + TriangleFanDrawMode: $x, + TriangleStripDrawMode: Jx, + TrianglesDrawMode: Zx, + TubeGeometry: ac, + TwoPassDoubleSide: Gx, + UVMapping: Gc, + Uint16BufferAttribute: Zr, + Uint32BufferAttribute: Jr, + Uint8BufferAttribute: jl, + Uint8ClampedBufferAttribute: eh, + Uniform: Pu, + UniformsGroup: Lu, + UniformsLib: le, + UniformsUtils: xp, + UnsignedByteType: On, + UnsignedInt248Type: ii, + UnsignedIntType: Ln, + UnsignedShort4444Type: fd, + UnsignedShort5551Type: pd, + UnsignedShortType: Wc, + VSMShadowMap: pn, + Vector2: Z, + Vector3: A, + Vector4: je, + VectorKeyframeTrack: ns, + VideoTexture: Jh, + WebGL1Renderer: Co, + WebGL3DRenderTarget: Hl, + WebGLArrayRenderTarget: kl, + WebGLCoordinateSystem: vn, + WebGLCubeRenderTarget: xo, + WebGLMultipleRenderTargets: Gl, + WebGLRenderTarget: qt, + WebGLRenderer: Ro, + WebGLUtils: V0, + WebGPUCoordinateSystem: Gr, + WireframeGeometry: oc, + WrapAroundEnding: Br, + ZeroCurvatureEnding: zi, + ZeroFactor: Yd, + ZeroSlopeEnding: Vi, + ZeroStencilOp: Kx, + _SRGBAFormat: po, + createCanvasElement: tp, + sRGBEncoding: ri }; -Object.defineProperties(dt.prototype, { - wrapAround: { - get: function() { - console.warn("THREE.Material: .wrapAround has been removed."); - }, - set: function() { - console.warn("THREE.Material: .wrapAround has been removed."); - } - }, - overdraw: { - get: function() { - console.warn("THREE.Material: .overdraw has been removed."); - }, - set: function() { - console.warn("THREE.Material: .overdraw has been removed."); - } - }, - wrapRGB: { - get: function() { - return console.warn("THREE.Material: .wrapRGB has been removed."), new ae; - } - }, - shading: { - get: function() { - console.error("THREE." + this.type + ": .shading has been removed. Use the boolean .flatShading instead."); - }, - set: function(s) { - console.warn("THREE." + this.type + ": .shading has been removed. Use the boolean .flatShading instead."), this.flatShading = s === kc; - } - }, - stencilMask: { - get: function() { - return console.warn("THREE." + this.type + ": .stencilMask has been removed. Use .stencilFuncMask instead."), this.stencilFuncMask; - }, - set: function(s) { - console.warn("THREE." + this.type + ": .stencilMask has been removed. Use .stencilFuncMask instead."), this.stencilFuncMask = s; - } - }, - vertexTangents: { - get: function() { - console.warn("THREE." + this.type + ": .vertexTangents has been removed."); - }, - set: function() { - console.warn("THREE." + this.type + ": .vertexTangents has been removed."); - } +function getWebGLErrorMessage() { + return getErrorMessage(1); +} +function getErrorMessage(version) { + var names = { + 1: "WebGL", + 2: "WebGL 2" + }; + var contexts = { + 1: window.WebGLRenderingContext, + 2: window.WebGL2RenderingContext + }; + var message = 'Your $0 does not seem to support $1'; + var element = document.createElement("div"); + element.id = "webglmessage"; + element.style.fontFamily = "monospace"; + element.style.fontSize = "13px"; + element.style.fontWeight = "normal"; + element.style.textAlign = "center"; + element.style.background = "#fff"; + element.style.color = "#000"; + element.style.padding = "1.5em"; + element.style.width = "400px"; + element.style.margin = "5em auto 0"; + if (contexts[version]) { + message = message.replace("$0", "graphics card"); + } else { + message = message.replace("$0", "browser"); } -}); -Object.defineProperties(sn.prototype, { - derivatives: { - get: function() { - return console.warn("THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives."), this.extensions.derivatives; - }, - set: function(s) { - console.warn("THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives."), this.extensions.derivatives = s; - } + message = message.replace("$1", names[version]); + element.innerHTML = message; + return element; +} +function typedarray_to_vectype(typedArray, ndim) { + if (ndim === 1) { + return "float"; + } else if (typedArray instanceof Float32Array) { + return "vec" + ndim; + } else if (typedArray instanceof Int32Array) { + return "ivec" + ndim; + } else if (typedArray instanceof Uint32Array) { + return "uvec" + ndim; + } else { + return; } -}); -qe.prototype.clearTarget = function(s, e, t, n) { - console.warn("THREE.WebGLRenderer: .clearTarget() has been deprecated. Use .setRenderTarget() and .clear() instead."), this.setRenderTarget(s), this.clear(e, t, n); -}; -qe.prototype.animate = function(s) { - console.warn("THREE.WebGLRenderer: .animate() is now .setAnimationLoop()."), this.setAnimationLoop(s); -}; -qe.prototype.getCurrentRenderTarget = function() { - return console.warn("THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget()."), this.getRenderTarget(); -}; -qe.prototype.getMaxAnisotropy = function() { - return console.warn("THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy()."), this.capabilities.getMaxAnisotropy(); -}; -qe.prototype.getPrecision = function() { - return console.warn("THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision."), this.capabilities.precision; -}; -qe.prototype.resetGLState = function() { - return console.warn("THREE.WebGLRenderer: .resetGLState() is now .state.reset()."), this.state.reset(); -}; -qe.prototype.supportsFloatTextures = function() { - return console.warn("THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( 'OES_texture_float' )."), this.extensions.get("OES_texture_float"); -}; -qe.prototype.supportsHalfFloatTextures = function() { - return console.warn("THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( 'OES_texture_half_float' )."), this.extensions.get("OES_texture_half_float"); -}; -qe.prototype.supportsStandardDerivatives = function() { - return console.warn("THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( 'OES_standard_derivatives' )."), this.extensions.get("OES_standard_derivatives"); -}; -qe.prototype.supportsCompressedTextureS3TC = function() { - return console.warn("THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( 'WEBGL_compressed_texture_s3tc' )."), this.extensions.get("WEBGL_compressed_texture_s3tc"); -}; -qe.prototype.supportsCompressedTexturePVRTC = function() { - return console.warn("THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( 'WEBGL_compressed_texture_pvrtc' )."), this.extensions.get("WEBGL_compressed_texture_pvrtc"); -}; -qe.prototype.supportsBlendMinMax = function() { - return console.warn("THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( 'EXT_blend_minmax' )."), this.extensions.get("EXT_blend_minmax"); -}; -qe.prototype.supportsVertexTextures = function() { - return console.warn("THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures."), this.capabilities.vertexTextures; -}; -qe.prototype.supportsInstancedArrays = function() { - return console.warn("THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( 'ANGLE_instanced_arrays' )."), this.extensions.get("ANGLE_instanced_arrays"); -}; -qe.prototype.enableScissorTest = function(s) { - console.warn("THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest()."), this.setScissorTest(s); -}; -qe.prototype.initMaterial = function() { - console.warn("THREE.WebGLRenderer: .initMaterial() has been removed."); -}; -qe.prototype.addPrePlugin = function() { - console.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed."); -}; -qe.prototype.addPostPlugin = function() { - console.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed."); -}; -qe.prototype.updateShadowMap = function() { - console.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed."); -}; -qe.prototype.setFaceCulling = function() { - console.warn("THREE.WebGLRenderer: .setFaceCulling() has been removed."); -}; -qe.prototype.allocTextureUnit = function() { - console.warn("THREE.WebGLRenderer: .allocTextureUnit() has been removed."); -}; -qe.prototype.setTexture = function() { - console.warn("THREE.WebGLRenderer: .setTexture() has been removed."); -}; -qe.prototype.setTexture2D = function() { - console.warn("THREE.WebGLRenderer: .setTexture2D() has been removed."); +} +function attribute_type(attribute) { + if (attribute) { + return typedarray_to_vectype(attribute.array, attribute.itemSize); + } else { + return; + } +} +function uniform_type(obj) { + if (obj instanceof THREE.Uniform) { + return uniform_type(obj.value); + } else if (typeof obj === "number") { + return "float"; + } else if (typeof obj === "boolean") { + return "bool"; + } else if (obj instanceof THREE.Vector2) { + return "vec2"; + } else if (obj instanceof THREE.Vector3) { + return "vec3"; + } else if (obj instanceof THREE.Vector4) { + return "vec4"; + } else if (obj instanceof THREE.Color) { + return "vec4"; + } else if (obj instanceof THREE.Matrix3) { + return "mat3"; + } else if (obj instanceof THREE.Matrix4) { + return "mat4"; + } else if (obj instanceof THREE.Texture) { + return "sampler2D"; + } else { + return; + } +} +function uniforms_to_type_declaration(uniform_dict) { + let result = ""; + for(const name in uniform_dict){ + const uniform = uniform_dict[name]; + const type = uniform_type(uniform); + result += `uniform ${type} ${name};\n`; + } + return result; +} +function attributes_to_type_declaration(attributes_dict) { + let result = ""; + for(const name in attributes_dict){ + const attribute = attributes_dict[name]; + const type = attribute_type(attribute); + result += `in ${type} ${name};\n`; + } + return result; +} +const _changeEvent = { + type: "change" }; -qe.prototype.setTextureCube = function() { - console.warn("THREE.WebGLRenderer: .setTextureCube() has been removed."); +const _startEvent = { + type: "start" }; -qe.prototype.getActiveMipMapLevel = function() { - return console.warn("THREE.WebGLRenderer: .getActiveMipMapLevel() is now .getActiveMipmapLevel()."), this.getActiveMipmapLevel(); +const _endEvent = { + type: "end" }; -Object.defineProperties(qe.prototype, { - shadowMapEnabled: { - get: function() { - return this.shadowMap.enabled; - }, - set: function(s) { - console.warn("THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled."), this.shadowMap.enabled = s; +const _ray = new hi(); +const _plane = new mn(); +const TILT_LIMIT = Math.cos(70 * yv.DEG2RAD); +class OrbitControls extends sn { + constructor(object, domElement, allow_update, is_in_scene){ + super(); + this.object = object; + this.domElement = domElement; + this.domElement.style.touchAction = "none"; + this.enabled = true; + this.target = new A(); + this.cursor = new A(); + this.minDistance = 0; + this.maxDistance = Infinity; + this.minZoom = 0; + this.maxZoom = Infinity; + this.minTargetRadius = 0; + this.maxTargetRadius = Infinity; + this.minPolarAngle = 0; + this.maxPolarAngle = Math.PI; + this.minAzimuthAngle = -Infinity; + this.maxAzimuthAngle = Infinity; + this.enableDamping = false; + this.dampingFactor = 0.05; + this.enableZoom = true; + this.zoomSpeed = 1.0; + this.enableRotate = true; + this.rotateSpeed = 1.0; + this.enablePan = true; + this.panSpeed = 1.0; + this.screenSpacePanning = true; + this.keyPanSpeed = 7.0; + this.zoomToCursor = false; + this.autoRotate = false; + this.autoRotateSpeed = 2.0; + this.keys = { + LEFT: "ArrowLeft", + UP: "ArrowUp", + RIGHT: "ArrowRight", + BOTTOM: "ArrowDown" + }; + this.mouseButtons = { + LEFT: zx.ROTATE, + MIDDLE: zx.DOLLY, + RIGHT: zx.PAN + }; + this.touches = { + ONE: Vx.ROTATE, + TWO: Vx.DOLLY_PAN + }; + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; + this._domElementKeyEvents = null; + this.getPolarAngle = function() { + return spherical.phi; + }; + this.getAzimuthalAngle = function() { + return spherical.theta; + }; + this.getDistance = function() { + return this.object.position.distanceTo(this.target); + }; + this.listenToKeyEvents = function(domElement) { + domElement.addEventListener("keydown", onKeyDown); + this._domElementKeyEvents = domElement; + }; + this.stopListenToKeyEvents = function() { + this._domElementKeyEvents.removeEventListener("keydown", onKeyDown); + this._domElementKeyEvents = null; + }; + this.saveState = function() { + scope.target0.copy(scope.target); + scope.position0.copy(scope.object.position); + scope.zoom0 = scope.object.zoom; + }; + this.reset = function() { + scope.target.copy(scope.target0); + scope.object.position.copy(scope.position0); + scope.object.zoom = scope.zoom0; + scope.object.updateProjectionMatrix(); + scope.dispatchEvent(_changeEvent); + scope.update(); + state = STATE.NONE; + }; + this.update = function() { + const offset = new A(); + const quat = new Ut().setFromUnitVectors(object.up, new A(0, 1, 0)); + const quatInverse = quat.clone().invert(); + const lastPosition = new A(); + const lastQuaternion = new Ut(); + const lastTargetPosition = new A(); + const twoPI = 2 * Math.PI; + return function update(deltaTime = null) { + if (!allow_update()) { + return; + } + const position = scope.object.position; + offset.copy(position).sub(scope.target); + offset.applyQuaternion(quat); + spherical.setFromVector3(offset); + if (scope.autoRotate && state === STATE.NONE) { + rotateLeft(getAutoRotationAngle(deltaTime)); + } + if (scope.enableDamping) { + spherical.theta += sphericalDelta.theta * scope.dampingFactor; + spherical.phi += sphericalDelta.phi * scope.dampingFactor; + } else { + spherical.theta += sphericalDelta.theta; + spherical.phi += sphericalDelta.phi; + } + let min = scope.minAzimuthAngle; + let max = scope.maxAzimuthAngle; + if (isFinite(min) && isFinite(max)) { + if (min < -Math.PI) min += twoPI; + else if (min > Math.PI) min -= twoPI; + if (max < -Math.PI) max += twoPI; + else if (max > Math.PI) max -= twoPI; + if (min <= max) { + spherical.theta = Math.max(min, Math.min(max, spherical.theta)); + } else { + spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta); + } + } + spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi)); + spherical.makeSafe(); + if (scope.enableDamping === true) { + scope.target.addScaledVector(panOffset, scope.dampingFactor); + } else { + scope.target.add(panOffset); + } + scope.target.sub(scope.cursor); + scope.target.clampLength(scope.minTargetRadius, scope.maxTargetRadius); + scope.target.add(scope.cursor); + if (scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera) { + spherical.radius = clampDistance(spherical.radius); + } else { + spherical.radius = clampDistance(spherical.radius * scale); + } + offset.setFromSpherical(spherical); + offset.applyQuaternion(quatInverse); + position.copy(scope.target).add(offset); + scope.object.lookAt(scope.target); + if (scope.enableDamping === true) { + sphericalDelta.theta *= 1 - scope.dampingFactor; + sphericalDelta.phi *= 1 - scope.dampingFactor; + panOffset.multiplyScalar(1 - scope.dampingFactor); + } else { + sphericalDelta.set(0, 0, 0); + panOffset.set(0, 0, 0); + } + let zoomChanged = false; + if (scope.zoomToCursor && performCursorZoom) { + let newRadius = null; + if (scope.object.isPerspectiveCamera) { + const prevRadius = offset.length(); + newRadius = clampDistance(prevRadius * scale); + const radiusDelta = prevRadius - newRadius; + scope.object.position.addScaledVector(dollyDirection, radiusDelta); + scope.object.updateMatrixWorld(); + } else if (scope.object.isOrthographicCamera) { + const mouseBefore = new A(mouse.x, mouse.y, 0); + mouseBefore.unproject(scope.object); + scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / scale)); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + const mouseAfter = new A(mouse.x, mouse.y, 0); + mouseAfter.unproject(scope.object); + scope.object.position.sub(mouseAfter).add(mouseBefore); + scope.object.updateMatrixWorld(); + newRadius = offset.length(); + } else { + console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."); + scope.zoomToCursor = false; + } + if (newRadius !== null) { + if (this.screenSpacePanning) { + scope.target.set(0, 0, -1).transformDirection(scope.object.matrix).multiplyScalar(newRadius).add(scope.object.position); + } else { + _ray.origin.copy(scope.object.position); + _ray.direction.set(0, 0, -1).transformDirection(scope.object.matrix); + if (Math.abs(scope.object.up.dot(_ray.direction)) < TILT_LIMIT) { + object.lookAt(scope.target); + } else { + _plane.setFromNormalAndCoplanarPoint(scope.object.up, scope.target); + _ray.intersectPlane(_plane, scope.target); + } + } + } + } else if (scope.object.isOrthographicCamera) { + scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / scale)); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + } + scale = 1; + performCursorZoom = false; + if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS || lastTargetPosition.distanceToSquared(scope.target) > 0) { + scope.dispatchEvent(_changeEvent); + lastPosition.copy(scope.object.position); + lastQuaternion.copy(scope.object.quaternion); + lastTargetPosition.copy(scope.target); + zoomChanged = false; + return true; + } + return false; + }; + }(); + this.dispose = function() { + scope.domElement.removeEventListener("contextmenu", onContextMenu); + scope.domElement.removeEventListener("pointerdown", onPointerDown); + scope.domElement.removeEventListener("pointercancel", onPointerUp); + scope.domElement.removeEventListener("wheel", onMouseWheel); + scope.domElement.removeEventListener("pointermove", onPointerMove); + scope.domElement.removeEventListener("pointerup", onPointerUp); + if (scope._domElementKeyEvents !== null) { + scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown); + scope._domElementKeyEvents = null; + } + }; + const scope = this; + const STATE = { + NONE: -1, + ROTATE: 0, + DOLLY: 1, + PAN: 2, + TOUCH_ROTATE: 3, + TOUCH_PAN: 4, + TOUCH_DOLLY_PAN: 5, + TOUCH_DOLLY_ROTATE: 6 + }; + let state = STATE.NONE; + const EPS = 0.000001; + const spherical = new Ou(); + const sphericalDelta = new Ou(); + let scale = 1; + const panOffset = new A(); + const rotateStart = new Z(); + const rotateEnd = new Z(); + const rotateDelta = new Z(); + const panStart = new Z(); + const panEnd = new Z(); + const panDelta = new Z(); + const dollyStart = new Z(); + const dollyEnd = new Z(); + const dollyDelta = new Z(); + const dollyDirection = new A(); + const mouse = new Z(); + let performCursorZoom = false; + const pointers = []; + const pointerPositions = {}; + function getAutoRotationAngle(deltaTime) { + if (deltaTime !== null) { + return 2 * Math.PI / 60 * scope.autoRotateSpeed * deltaTime; + } else { + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + } } - }, - shadowMapType: { - get: function() { - return this.shadowMap.type; - }, - set: function(s) { - console.warn("THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type."), this.shadowMap.type = s; + function getZoomScale() { + return Math.pow(0.95, scope.zoomSpeed); } - }, - shadowMapCullFace: { - get: function() { - console.warn("THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead."); - }, - set: function() { - console.warn("THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead."); + function rotateLeft(angle) { + sphericalDelta.theta -= angle; } - }, - context: { - get: function() { - return console.warn("THREE.WebGLRenderer: .context has been removed. Use .getContext() instead."), this.getContext(); + function rotateUp(angle) { + sphericalDelta.phi -= angle; } - }, - vr: { - get: function() { - return console.warn("THREE.WebGLRenderer: .vr has been renamed to .xr"), this.xr; + const panLeft = function() { + const v = new A(); + return function panLeft(distance, objectMatrix) { + v.setFromMatrixColumn(objectMatrix, 0); + v.multiplyScalar(-distance); + panOffset.add(v); + }; + }(); + const panUp = function() { + const v = new A(); + return function panUp(distance, objectMatrix) { + if (scope.screenSpacePanning === true) { + v.setFromMatrixColumn(objectMatrix, 1); + } else { + v.setFromMatrixColumn(objectMatrix, 0); + v.crossVectors(scope.object.up, v); + } + v.multiplyScalar(distance); + panOffset.add(v); + }; + }(); + const pan = function() { + const offset = new A(); + return function pan(deltaX, deltaY) { + const element = scope.domElement; + if (scope.object.isPerspectiveCamera) { + const position = scope.object.position; + offset.copy(position).sub(scope.target); + let targetDistance = offset.length(); + targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180.0); + panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix); + panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix); + } else if (scope.object.isOrthographicCamera) { + panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix); + panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix); + } else { + console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."); + scope.enablePan = false; + } + }; + }(); + function dollyOut(dollyScale) { + if (scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera) { + scale /= dollyScale; + } else { + console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."); + scope.enableZoom = false; + } } - }, - gammaInput: { - get: function() { - return console.warn("THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead."), !1; - }, - set: function() { - console.warn("THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead."); + function dollyIn(dollyScale) { + if (scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera) { + scale *= dollyScale; + } else { + console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."); + scope.enableZoom = false; + } } - }, - gammaOutput: { - get: function() { - return console.warn("THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead."), !1; - }, - set: function(s) { - console.warn("THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead."), this.outputEncoding = s === !0 ? Oi : Nt; + function updateMouseParameters(event) { + if (!scope.zoomToCursor) { + return; + } + performCursorZoom = true; + const rect = scope.domElement.getBoundingClientRect(); + const x = event.clientX - rect.left; + const y = event.clientY - rect.top; + const w = rect.width; + const h = rect.height; + mouse.x = x / w * 2 - 1; + mouse.y = -(y / h) * 2 + 1; + dollyDirection.set(mouse.x, mouse.y, 1).unproject(scope.object).sub(scope.object.position).normalize(); + } + function clampDistance(dist) { + return Math.max(scope.minDistance, Math.min(scope.maxDistance, dist)); + } + function handleMouseDownRotate(event) { + rotateStart.set(event.clientX, event.clientY); + } + function handleMouseDownDolly(event) { + updateMouseParameters(event); + dollyStart.set(event.clientX, event.clientY); + } + function handleMouseDownPan(event) { + panStart.set(event.clientX, event.clientY); + } + function handleMouseMoveRotate(event) { + rotateEnd.set(event.clientX, event.clientY); + rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed); + const element = scope.domElement; + rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight); + rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight); + rotateStart.copy(rotateEnd); + scope.update(); + } + function handleMouseMoveDolly(event) { + dollyEnd.set(event.clientX, event.clientY); + dollyDelta.subVectors(dollyEnd, dollyStart); + if (dollyDelta.y > 0) { + dollyOut(getZoomScale()); + } else if (dollyDelta.y < 0) { + dollyIn(getZoomScale()); + } + dollyStart.copy(dollyEnd); + scope.update(); + } + function handleMouseMovePan(event) { + panEnd.set(event.clientX, event.clientY); + panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed); + pan(panDelta.x, panDelta.y); + panStart.copy(panEnd); + scope.update(); + } + function handleMouseWheel(event) { + updateMouseParameters(event); + if (event.deltaY < 0) { + dollyIn(getZoomScale()); + } else if (event.deltaY > 0) { + dollyOut(getZoomScale()); + } + scope.update(); + } + function handleKeyDown(event) { + let needsUpdate = false; + switch(event.code){ + case scope.keys.UP: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + rotateUp(2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight); + } else { + pan(0, scope.keyPanSpeed); + } + needsUpdate = true; + break; + case scope.keys.BOTTOM: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + rotateUp(-2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight); + } else { + pan(0, -scope.keyPanSpeed); + } + needsUpdate = true; + break; + case scope.keys.LEFT: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + rotateLeft(2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight); + } else { + pan(scope.keyPanSpeed, 0); + } + needsUpdate = true; + break; + case scope.keys.RIGHT: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + rotateLeft(-2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight); + } else { + pan(-scope.keyPanSpeed, 0); + } + needsUpdate = true; + break; + } + if (needsUpdate) { + event.preventDefault(); + scope.update(); + } } - }, - toneMappingWhitePoint: { - get: function() { - return console.warn("THREE.WebGLRenderer: .toneMappingWhitePoint has been removed."), 1; - }, - set: function() { - console.warn("THREE.WebGLRenderer: .toneMappingWhitePoint has been removed."); + function handleTouchStartRotate() { + if (pointers.length === 1) { + rotateStart.set(pointers[0].pageX, pointers[0].pageY); + } else { + const x = 0.5 * (pointers[0].pageX + pointers[1].pageX); + const y = 0.5 * (pointers[0].pageY + pointers[1].pageY); + rotateStart.set(x, y); + } } - }, - gammaFactor: { - get: function() { - return console.warn("THREE.WebGLRenderer: .gammaFactor has been removed."), 2; - }, - set: function() { - console.warn("THREE.WebGLRenderer: .gammaFactor has been removed."); + function handleTouchStartPan() { + if (pointers.length === 1) { + panStart.set(pointers[0].pageX, pointers[0].pageY); + } else { + const x = 0.5 * (pointers[0].pageX + pointers[1].pageX); + const y = 0.5 * (pointers[0].pageY + pointers[1].pageY); + panStart.set(x, y); + } } - } -}); -Object.defineProperties(yh.prototype, { - cullFace: { - get: function() { - console.warn("THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead."); - }, - set: function() { - console.warn("THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead."); + function handleTouchStartDolly() { + const dx = pointers[0].pageX - pointers[1].pageX; + const dy = pointers[0].pageY - pointers[1].pageY; + const distance = Math.sqrt(dx * dx + dy * dy); + dollyStart.set(0, distance); } - }, - renderReverseSided: { - get: function() { - console.warn("THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead."); - }, - set: function() { - console.warn("THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead."); + function handleTouchStartDollyPan() { + if (scope.enableZoom) handleTouchStartDolly(); + if (scope.enablePan) handleTouchStartPan(); } - }, - renderSingleSided: { - get: function() { - console.warn("THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead."); - }, - set: function() { - console.warn("THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead."); + function handleTouchStartDollyRotate() { + if (scope.enableZoom) handleTouchStartDolly(); + if (scope.enableRotate) handleTouchStartRotate(); } - } -}); -function Q0(s, e, t) { - return console.warn("THREE.WebGLRenderTargetCube( width, height, options ) is now WebGLCubeRenderTarget( size, options )."), new js(s, t); -} -Object.defineProperties(At.prototype, { - wrapS: { - get: function() { - return console.warn("THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS."), this.texture.wrapS; - }, - set: function(s) { - console.warn("THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS."), this.texture.wrapS = s; + function handleTouchMoveRotate(event) { + if (pointers.length == 1) { + rotateEnd.set(event.pageX, event.pageY); + } else { + const position = getSecondPointerPosition(event); + const x = 0.5 * (event.pageX + position.x); + const y = 0.5 * (event.pageY + position.y); + rotateEnd.set(x, y); + } + rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed); + const element = scope.domElement; + rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight); + rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight); + rotateStart.copy(rotateEnd); + } + function handleTouchMovePan(event) { + if (pointers.length === 1) { + panEnd.set(event.pageX, event.pageY); + } else { + const position = getSecondPointerPosition(event); + const x = 0.5 * (event.pageX + position.x); + const y = 0.5 * (event.pageY + position.y); + panEnd.set(x, y); + } + panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed); + pan(panDelta.x, panDelta.y); + panStart.copy(panEnd); + } + function handleTouchMoveDolly(event) { + const position = getSecondPointerPosition(event); + const dx = event.pageX - position.x; + const dy = event.pageY - position.y; + const distance = Math.sqrt(dx * dx + dy * dy); + dollyEnd.set(0, distance); + dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed)); + dollyOut(dollyDelta.y); + dollyStart.copy(dollyEnd); + } + function handleTouchMoveDollyPan(event) { + if (scope.enableZoom) handleTouchMoveDolly(event); + if (scope.enablePan) handleTouchMovePan(event); + } + function handleTouchMoveDollyRotate(event) { + if (scope.enableZoom) handleTouchMoveDolly(event); + if (scope.enableRotate) handleTouchMoveRotate(event); + } + function onPointerDown(event) { + if (scope.enabled === false) return; + if (pointers.length === 0) { + scope.domElement.setPointerCapture(event.pointerId); + scope.domElement.addEventListener("pointermove", onPointerMove); + scope.domElement.addEventListener("pointerup", onPointerUp); + } + addPointer(event); + if (event.pointerType === "touch") { + onTouchStart(event); + } else { + onMouseDown(event); + } } - }, - wrapT: { - get: function() { - return console.warn("THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT."), this.texture.wrapT; - }, - set: function(s) { - console.warn("THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT."), this.texture.wrapT = s; + function onPointerMove(event) { + if (scope.enabled === false) return; + if (!is_in_scene(event)) return; + if (event.pointerType === "touch") { + onTouchMove(event); + } else { + onMouseMove(event); + } } - }, - magFilter: { - get: function() { - return console.warn("THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter."), this.texture.magFilter; - }, - set: function(s) { - console.warn("THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter."), this.texture.magFilter = s; + function onPointerUp(event) { + removePointer(event); + if (pointers.length === 0) { + scope.domElement.releasePointerCapture(event.pointerId); + scope.domElement.removeEventListener("pointermove", onPointerMove); + scope.domElement.removeEventListener("pointerup", onPointerUp); + } + scope.dispatchEvent(_endEvent); + state = STATE.NONE; + } + function onMouseDown(event) { + let mouseAction; + switch(event.button){ + case 0: + mouseAction = scope.mouseButtons.LEFT; + break; + case 1: + mouseAction = scope.mouseButtons.MIDDLE; + break; + case 2: + mouseAction = scope.mouseButtons.RIGHT; + break; + default: + mouseAction = -1; + } + switch(mouseAction){ + case zx.DOLLY: + if (scope.enableZoom === false) return; + handleMouseDownDolly(event); + state = STATE.DOLLY; + break; + case zx.ROTATE: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + if (scope.enablePan === false) return; + handleMouseDownPan(event); + state = STATE.PAN; + } else { + if (scope.enableRotate === false) return; + handleMouseDownRotate(event); + state = STATE.ROTATE; + } + break; + case zx.PAN: + if (event.ctrlKey || event.metaKey || event.shiftKey) { + if (scope.enableRotate === false) return; + handleMouseDownRotate(event); + state = STATE.ROTATE; + } else { + if (scope.enablePan === false) return; + handleMouseDownPan(event); + state = STATE.PAN; + } + break; + default: + state = STATE.NONE; + } + if (state !== STATE.NONE) { + scope.dispatchEvent(_startEvent); + } } - }, - minFilter: { - get: function() { - return console.warn("THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter."), this.texture.minFilter; - }, - set: function(s) { - console.warn("THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter."), this.texture.minFilter = s; + function onMouseMove(event) { + switch(state){ + case STATE.ROTATE: + if (scope.enableRotate === false) return; + handleMouseMoveRotate(event); + break; + case STATE.DOLLY: + if (scope.enableZoom === false) return; + handleMouseMoveDolly(event); + break; + case STATE.PAN: + if (scope.enablePan === false) return; + handleMouseMovePan(event); + break; + } } - }, - anisotropy: { - get: function() { - return console.warn("THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy."), this.texture.anisotropy; - }, - set: function(s) { - console.warn("THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy."), this.texture.anisotropy = s; + function onMouseWheel(event) { + if (scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE || !is_in_scene(event)) return; + event.preventDefault(); + scope.dispatchEvent(_startEvent); + handleMouseWheel(event); + scope.dispatchEvent(_endEvent); + } + function onKeyDown(event) { + if (scope.enabled === false || scope.enablePan === false) return; + handleKeyDown(event); + } + function onTouchStart(event) { + trackPointer(event); + switch(pointers.length){ + case 1: + switch(scope.touches.ONE){ + case Vx.ROTATE: + if (scope.enableRotate === false) return; + handleTouchStartRotate(); + state = STATE.TOUCH_ROTATE; + break; + case Vx.PAN: + if (scope.enablePan === false) return; + handleTouchStartPan(); + state = STATE.TOUCH_PAN; + break; + default: + state = STATE.NONE; + } + break; + case 2: + switch(scope.touches.TWO){ + case Vx.DOLLY_PAN: + if (scope.enableZoom === false && scope.enablePan === false) return; + handleTouchStartDollyPan(); + state = STATE.TOUCH_DOLLY_PAN; + break; + case Vx.DOLLY_ROTATE: + if (scope.enableZoom === false && scope.enableRotate === false) return; + handleTouchStartDollyRotate(); + state = STATE.TOUCH_DOLLY_ROTATE; + break; + default: + state = STATE.NONE; + } + break; + default: + state = STATE.NONE; + } + if (state !== STATE.NONE) { + scope.dispatchEvent(_startEvent); + } + } + function onTouchMove(event) { + trackPointer(event); + switch(state){ + case STATE.TOUCH_ROTATE: + if (scope.enableRotate === false) return; + handleTouchMoveRotate(event); + scope.update(); + break; + case STATE.TOUCH_PAN: + if (scope.enablePan === false) return; + handleTouchMovePan(event); + scope.update(); + break; + case STATE.TOUCH_DOLLY_PAN: + if (scope.enableZoom === false && scope.enablePan === false) return; + handleTouchMoveDollyPan(event); + scope.update(); + break; + case STATE.TOUCH_DOLLY_ROTATE: + if (scope.enableZoom === false && scope.enableRotate === false) return; + handleTouchMoveDollyRotate(event); + scope.update(); + break; + default: + state = STATE.NONE; + } } - }, - offset: { - get: function() { - return console.warn("THREE.WebGLRenderTarget: .offset is now .texture.offset."), this.texture.offset; - }, - set: function(s) { - console.warn("THREE.WebGLRenderTarget: .offset is now .texture.offset."), this.texture.offset = s; + function onContextMenu(event) { + if (scope.enabled === false) return; + event.preventDefault(); } - }, - repeat: { - get: function() { - return console.warn("THREE.WebGLRenderTarget: .repeat is now .texture.repeat."), this.texture.repeat; - }, - set: function(s) { - console.warn("THREE.WebGLRenderTarget: .repeat is now .texture.repeat."), this.texture.repeat = s; + function addPointer(event) { + pointers.push(event); } - }, - format: { - get: function() { - return console.warn("THREE.WebGLRenderTarget: .format is now .texture.format."), this.texture.format; - }, - set: function(s) { - console.warn("THREE.WebGLRenderTarget: .format is now .texture.format."), this.texture.format = s; + function removePointer(event) { + delete pointerPositions[event.pointerId]; + for(let i = 0; i < pointers.length; i++){ + if (pointers[i].pointerId == event.pointerId) { + pointers.splice(i, 1); + return; + } + } } - }, - type: { - get: function() { - return console.warn("THREE.WebGLRenderTarget: .type is now .texture.type."), this.texture.type; - }, - set: function(s) { - console.warn("THREE.WebGLRenderTarget: .type is now .texture.type."), this.texture.type = s; + function trackPointer(event) { + let position = pointerPositions[event.pointerId]; + if (position === undefined) { + position = new Z(); + pointerPositions[event.pointerId] = position; + } + position.set(event.pageX, event.pageY); } - }, - generateMipmaps: { - get: function() { - return console.warn("THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps."), this.texture.generateMipmaps; - }, - set: function(s) { - console.warn("THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps."), this.texture.generateMipmaps = s; + function getSecondPointerPosition(event) { + const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0]; + return pointerPositions[pointer.pointerId]; } + scope.domElement.addEventListener("contextmenu", onContextMenu); + scope.domElement.addEventListener("pointerdown", onPointerDown); + scope.domElement.addEventListener("pointercancel", onPointerUp); + scope.domElement.addEventListener("wheel", onMouseWheel, { + passive: false + }); + this.update(); } -}); -Za.prototype.load = function(s) { - console.warn("THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead."); - let e = this; - return new kh().load(s, function(n) { - e.setBuffer(n); - }), this; -}; -qh.prototype.getData = function() { - return console.warn("THREE.AudioAnalyser: .getData() is now .getFrequencyData()."), this.getFrequencyData(); -}; -$s.prototype.updateCubeMap = function(s, e) { - return console.warn("THREE.CubeCamera: .updateCubeMap() is now .update()."), this.update(s, e); -}; -$s.prototype.clear = function(s, e, t, n) { - return console.warn("THREE.CubeCamera: .clear() is now .renderTarget.clear()."), this.renderTarget.clear(s, e, t, n); -}; -Yn.crossOrigin = void 0; -Yn.loadTexture = function(s, e, t, n) { - console.warn("THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead."); - let i = new Bh; - i.setCrossOrigin(this.crossOrigin); - let r = i.load(s, t, void 0, n); - return e && (r.mapping = e), r; -}; -Yn.loadTextureCube = function(s, e, t, n) { - console.warn("THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead."); - let i = new Fh; - i.setCrossOrigin(this.crossOrigin); - let r = i.load(s, t, void 0, n); - return e && (r.mapping = e), r; -}; -Yn.loadCompressedTexture = function() { - console.error("THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead."); -}; -Yn.loadCompressedTextureCube = function() { - console.error("THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead."); -}; -function K0() { - console.error("THREE.CanvasRenderer has been removed"); -} -function ev() { - console.error("THREE.JSONLoader has been removed."); -} -var tv = { - createMultiMaterialObject: function() { - console.error("THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js"); - }, - detach: function() { - console.error("THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js"); - }, - attach: function() { - console.error("THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js"); - } -}; -function nv() { - console.error("THREE.LensFlare has been moved to /examples/jsm/objects/Lensflare.js"); -} -function iv() { - return console.error("THREE.ParametricGeometry has been moved to /examples/jsm/geometries/ParametricGeometry.js"), new _e; -} -function rv() { - return console.error("THREE.TextGeometry has been moved to /examples/jsm/geometries/TextGeometry.js"), new _e; -} -function sv() { - console.error("THREE.FontLoader has been moved to /examples/jsm/loaders/FontLoader.js"); -} -function ov() { - console.error("THREE.Font has been moved to /examples/jsm/loaders/FontLoader.js"); -} -function av() { - console.error("THREE.ImmediateRenderObject has been removed."); -} -typeof __THREE_DEVTOOLS__ < "u" && __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("register", { - detail: { - revision: ca - } -})); -typeof window < "u" && (window.__THREE__ ? console.warn("WARNING: Multiple instances of Three.js being imported.") : window.__THREE__ = ca); -const mod = { - ACESFilmicToneMapping: Uu, - AddEquation: _i, - AddOperation: Fu, - AdditiveAnimationBlendMode: qc, - AdditiveBlending: nl, - AlphaFormat: Xu, - AlwaysDepth: Au, - AlwaysStencilFunc: Ud, - AmbientLight: qa, - AmbientLightProbe: Vh, - AnimationClip: Lr, - AnimationLoader: cy, - AnimationMixer: $h, - AnimationObjectGroup: Yh, - AnimationUtils: Ze, - ArcCurve: Ma, - ArrayCamera: ga, - ArrowHelper: Uy, - Audio: Za, - AudioAnalyser: qh, - AudioContext: Hh, - AudioListener: my, - AudioLoader: kh, - AxesHelper: ru, - AxisHelper: X0, - BackSide: it, - BasicDepthPacking: Nd, - BasicShadowMap: qy, - BinaryTextureLoader: j0, - Bone: oo, - BooleanKeyframeTrack: Qn, - BoundingBoxHelper: J0, - Box2: qi, - Box3: Lt, - Box3Helper: By, - BoxBufferGeometry: wn, - BoxGeometry: wn, - BoxHelper: iu, - BufferAttribute: Ue, - BufferGeometry: _e, - BufferGeometryLoader: Uh, - ByteType: Hu, - Cache: Ni, - Camera: Ir, - CameraHelper: Ny, - CanvasRenderer: K0, - CanvasTexture: Th, - CatmullRomCurve3: wa, - CineonToneMapping: zu, - CircleBufferGeometry: fr, - CircleGeometry: fr, - ClampToEdgeWrapping: vt, - Clock: Wh, - Color: ae, - ColorKeyframeTrack: Ba, - CompressedTexture: va, - CompressedTextureLoader: hy, - ConeBufferGeometry: pr, - ConeGeometry: pr, - CubeCamera: $s, - CubeReflectionMapping: Bi, - CubeRefractionMapping: zi, - CubeTexture: ki, - CubeTextureLoader: Fh, - CubeUVReflectionMapping: Pr, - CubeUVRefractionMapping: Ws, - CubicBezierCurve: lo, - CubicBezierCurve3: Sa, - CubicInterpolant: Ph, - CullFaceBack: tl, - CullFaceFront: du, - CullFaceFrontBack: Wy, - CullFaceNone: uu, - Curve: Ct, - CurvePath: Ah, - CustomBlending: pu, - CustomToneMapping: Ou, - CylinderBufferGeometry: Jn, - CylinderGeometry: Jn, - Cylindrical: Cy, - DataTexture: qn, - DataTexture2DArray: Qs, - DataTexture3D: ma, - DataTextureLoader: Nh, - DataUtils: ky, - DecrementStencilOp: n0, - DecrementWrapStencilOp: r0, - DefaultLoadingManager: ly, - DepthFormat: Vn, - DepthStencilFormat: Li, - DepthTexture: ks, - DirectionalLight: Wa, - DirectionalLightHelper: Fy, - DiscreteInterpolant: Ih, - DodecahedronBufferGeometry: mr, - DodecahedronGeometry: mr, - DoubleSide: Ci, - DstAlphaFactor: Mu, - DstColorFactor: wu, - DynamicBufferAttribute: B0, - DynamicCopyUsage: y0, - DynamicDrawUsage: ur, - DynamicReadUsage: m0, - EdgesGeometry: _a, - EdgesHelper: Y0, - EllipseCurve: Ur, - EqualDepth: Lu, - EqualStencilFunc: l0, - EquirectangularReflectionMapping: Ds, - EquirectangularRefractionMapping: Fs, - Euler: Zn, - EventDispatcher: En, - ExtrudeBufferGeometry: ln, - ExtrudeGeometry: ln, - FaceColors: T0, - FileLoader: Yt, - FlatShading: kc, - Float16BufferAttribute: nh, - Float32Attribute: W0, - Float32BufferAttribute: de, - Float64Attribute: q0, - Float64BufferAttribute: ih, - FloatType: nn, - Fog: Br, - FogExp2: Nr, - Font: ov, - FontLoader: sv, - FramebufferTexture: Sh, - FrontSide: Ai, - Frustum: Dr, - GLBufferAttribute: Qh, - GLSL1: _0, - GLSL3: xl, - GreaterDepth: Pu, - GreaterEqualDepth: Ru, - GreaterEqualStencilFunc: d0, - GreaterStencilFunc: h0, - GridHelper: nu, - Group: Hn, - HalfFloatType: kn, - HemisphereLight: Ua, - HemisphereLightHelper: Iy, - HemisphereLightProbe: Gh, - IcosahedronBufferGeometry: _r, - IcosahedronGeometry: _r, - ImageBitmapLoader: Oh, - ImageLoader: Rr, - ImageUtils: Yn, - ImmediateRenderObject: av, - IncrementStencilOp: t0, - IncrementWrapStencilOp: i0, - InstancedBufferAttribute: Xn, - InstancedBufferGeometry: Ya, - InstancedInterleavedBuffer: jh, - InstancedMesh: xa, - Int16Attribute: H0, - Int16BufferAttribute: eh, - Int32Attribute: G0, - Int32BufferAttribute: th, - Int8Attribute: z0, - Int8BufferAttribute: jc, - IntType: Gu, - InterleavedBuffer: $n, - InterleavedBufferAttribute: Sn, - Interpolant: cn, - InterpolateDiscrete: zs, - InterpolateLinear: Us, - InterpolateSmooth: yo, - InvertStencilOp: s0, - JSONLoader: ev, - KeepStencilOp: vo, - KeyframeTrack: zt, - LOD: bh, - LatheBufferGeometry: Mr, - LatheGeometry: Mr, - Layers: Js, - LensFlare: nv, - LessDepth: Cu, - LessEqualDepth: ea, - LessEqualStencilFunc: c0, - LessStencilFunc: a0, - Light: Bt, - LightProbe: Hr, - Line: on, - Line3: Kh, - LineBasicMaterial: ft, - LineCurve: Or, - LineCurve3: Eh, - LineDashedMaterial: Fa, - LineLoop: ya, - LinePieces: w0, - LineSegments: wt, - LineStrip: b0, - LinearEncoding: Nt, - LinearFilter: tt, - LinearInterpolant: Na, - LinearMipMapLinearFilter: $y, - LinearMipMapNearestFilter: Zy, - LinearMipmapLinearFilter: Ui, - LinearMipmapNearestFilter: Wc, - LinearToneMapping: Nu, - Loader: bt, - LoaderUtils: Gs, - LoadingManager: za, - LoopOnce: Pd, - LoopPingPong: Dd, - LoopRepeat: Id, - LuminanceAlphaFormat: Yu, - LuminanceFormat: Ju, - MOUSE: Gy, - Material: dt, - MaterialLoader: zh, - Math: M0, - MathUtils: M0, - Matrix3: lt, - Matrix4: pe, - MaxEquation: ol, - Mesh: st, - MeshBasicMaterial: hn, - MeshDepthMaterial: eo, - MeshDistanceMaterial: to, - MeshFaceMaterial: A0, - MeshLambertMaterial: Ia, - MeshMatcapMaterial: Da, - MeshNormalMaterial: Pa, - MeshPhongMaterial: La, - MeshPhysicalMaterial: Ca, - MeshStandardMaterial: po, - MeshToonMaterial: Ra, - MinEquation: sl, - MirroredRepeatWrapping: Bs, - MixOperation: Du, - MultiMaterial: C0, - MultiplyBlending: rl, - MultiplyOperation: Vs, - NearestFilter: rt, - NearestMipMapLinearFilter: Yy, - NearestMipMapNearestFilter: Jy, - NearestMipmapLinearFilter: na, - NearestMipmapNearestFilter: ta, - NeverDepth: Eu, - NeverStencilFunc: o0, - NoBlending: vn, - NoColors: S0, - NoToneMapping: _n, - NormalAnimationBlendMode: ua, - NormalBlending: sr, - NotEqualDepth: Iu, - NotEqualStencilFunc: u0, - NumberKeyframeTrack: Ar, - Object3D: Ne, - ObjectLoader: uy, - ObjectSpaceNormalMap: zd, - OctahedronBufferGeometry: Ii, - OctahedronGeometry: Ii, - OneFactor: yu, - OneMinusDstAlphaFactor: bu, - OneMinusDstColorFactor: Su, - OneMinusSrcAlphaFactor: Vc, - OneMinusSrcColorFactor: _u, - OrthographicCamera: Fr, - PCFShadowMap: Hc, - PCFSoftShadowMap: fu, - PMREMGenerator: ah, - ParametricGeometry: iv, - Particle: R0, - ParticleBasicMaterial: D0, - ParticleSystem: P0, - ParticleSystemMaterial: F0, - Path: gr, - PerspectiveCamera: ut, - Plane: Wt, - PlaneBufferGeometry: Pi, - PlaneGeometry: Pi, - PlaneHelper: zy, - PointCloud: L0, - PointCloudMaterial: I0, - PointLight: Ga, - PointLightHelper: Ry, - Points: zr, - PointsMaterial: jn, - PolarGridHelper: Dy, - PolyhedronBufferGeometry: an, - PolyhedronGeometry: an, - PositionalAudio: xy, - PropertyBinding: ke, - PropertyMixer: Xh, - QuadraticBezierCurve: co, - QuadraticBezierCurve3: ho, - Quaternion: gt, - QuaternionKeyframeTrack: Wi, - QuaternionLinearInterpolant: Dh, - REVISION: ca, - RGBADepthPacking: Bd, - RGBAFormat: ct, - RGBAIntegerFormat: ed, - RGBA_ASTC_10x10_Format: fd, - RGBA_ASTC_10x5_Format: hd, - RGBA_ASTC_10x6_Format: ud, - RGBA_ASTC_10x8_Format: dd, - RGBA_ASTC_12x10_Format: pd, - RGBA_ASTC_12x12_Format: md, - RGBA_ASTC_4x4_Format: nd, - RGBA_ASTC_5x4_Format: id, - RGBA_ASTC_5x5_Format: rd, - RGBA_ASTC_6x5_Format: sd, - RGBA_ASTC_6x6_Format: od, - RGBA_ASTC_8x5_Format: ad, - RGBA_ASTC_8x6_Format: ld, - RGBA_ASTC_8x8_Format: cd, - RGBA_BPTC_Format: gd, - RGBA_ETC2_EAC_Format: gl, - RGBA_PVRTC_2BPPV1_Format: pl, - RGBA_PVRTC_4BPPV1_Format: fl, - RGBA_S3TC_DXT1_Format: ll, - RGBA_S3TC_DXT3_Format: cl, - RGBA_S3TC_DXT5_Format: hl, - RGBFormat: Gn, - RGBIntegerFormat: Ku, - RGB_ETC1_Format: td, - RGB_ETC2_Format: ml, - RGB_PVRTC_2BPPV1_Format: dl, - RGB_PVRTC_4BPPV1_Format: ul, - RGB_S3TC_DXT1_Format: al, - RGFormat: ju, - RGIntegerFormat: Qu, - RawShaderMaterial: Gi, - Ray: Cn, - Raycaster: Ey, - RectAreaLight: Xa, - RedFormat: Zu, - RedIntegerFormat: $u, - ReinhardToneMapping: Bu, - RepeatWrapping: Ns, - ReplaceStencilOp: e0, - ReverseSubtractEquation: gu, - RingBufferGeometry: br, - RingGeometry: br, - SRGB8_ALPHA8_ASTC_10x10_Format: Cd, - SRGB8_ALPHA8_ASTC_10x5_Format: Td, - SRGB8_ALPHA8_ASTC_10x6_Format: Ed, - SRGB8_ALPHA8_ASTC_10x8_Format: Ad, - SRGB8_ALPHA8_ASTC_12x10_Format: Ld, - SRGB8_ALPHA8_ASTC_12x12_Format: Rd, - SRGB8_ALPHA8_ASTC_4x4_Format: xd, - SRGB8_ALPHA8_ASTC_5x4_Format: yd, - SRGB8_ALPHA8_ASTC_5x5_Format: vd, - SRGB8_ALPHA8_ASTC_6x5_Format: _d, - SRGB8_ALPHA8_ASTC_6x6_Format: Md, - SRGB8_ALPHA8_ASTC_8x5_Format: bd, - SRGB8_ALPHA8_ASTC_8x6_Format: wd, - SRGB8_ALPHA8_ASTC_8x8_Format: Sd, - Scene: no, - SceneUtils: tv, - ShaderChunk: Fe, - ShaderLib: qt, - ShaderMaterial: sn, - ShadowMaterial: Aa, - Shape: Xt, - ShapeBufferGeometry: Di, - ShapeGeometry: Di, - ShapePath: Oy, - ShapeUtils: Jt, - ShortType: ku, - Skeleton: ao, - SkeletonHelper: eu, - SkinnedMesh: so, - SmoothShading: Xy, - Sphere: An, - SphereBufferGeometry: Fi, - SphereGeometry: Fi, - Spherical: Ay, - SphericalHarmonics3: Ja, - SplineCurve: uo, - SpotLight: Ha, - SpotLightHelper: Ly, - Sprite: ro, - SpriteMaterial: io, - SrcAlphaFactor: Gc, - SrcAlphaSaturateFactor: Tu, - SrcColorFactor: vu, - StaticCopyUsage: x0, - StaticDrawUsage: hr, - StaticReadUsage: p0, - StereoCamera: fy, - StreamCopyUsage: v0, - StreamDrawUsage: f0, - StreamReadUsage: g0, - StringKeyframeTrack: Kn, - SubtractEquation: mu, - SubtractiveBlending: il, - TOUCH: Vy, - TangentSpaceNormalMap: Hi, - TetrahedronBufferGeometry: wr, - TetrahedronGeometry: wr, - TextGeometry: rv, - Texture: ot, - TextureLoader: Bh, - TorusBufferGeometry: Sr, - TorusGeometry: Sr, - TorusKnotBufferGeometry: Tr, - TorusKnotGeometry: Tr, - Triangle: nt, - TriangleFanDrawMode: Qy, - TriangleStripDrawMode: jy, - TrianglesDrawMode: Fd, - TubeBufferGeometry: Er, - TubeGeometry: Er, - UVMapping: ha, - Uint16Attribute: k0, - Uint16BufferAttribute: Ys, - Uint32Attribute: V0, - Uint32BufferAttribute: Zs, - Uint8Attribute: U0, - Uint8BufferAttribute: Qc, - Uint8ClampedAttribute: O0, - Uint8ClampedBufferAttribute: Kc, - Uniform: go, - UniformsLib: ie, - UniformsUtils: uf, - UnsignedByteType: rn, - UnsignedInt248Type: Ti, - UnsignedIntType: Ps, - UnsignedShort4444Type: Vu, - UnsignedShort5551Type: Wu, - UnsignedShort565Type: qu, - UnsignedShortType: cr, - VSMShadowMap: ir, - Vector2: X, - Vector3: M, - Vector4: Ve, - VectorKeyframeTrack: Cr, - Vertex: N0, - VertexColors: E0, - VideoTexture: wh, - WebGL1Renderer: _h, - WebGLCubeRenderTarget: js, - WebGLMultipleRenderTargets: Zc, - WebGLMultisampleRenderTarget: Xs, - WebGLRenderTarget: At, - WebGLRenderTargetCube: Q0, - WebGLRenderer: qe, - WebGLUtils: Ex, - WireframeGeometry: Ea, - WireframeHelper: Z0, - WrapAroundEnding: Os, - XHRLoader: $0, - ZeroCurvatureEnding: Mi, - ZeroFactor: xu, - ZeroSlopeEnding: bi, - ZeroStencilOp: Ky, - sRGBEncoding: Oi -}; -function getWebGLErrorMessage() { - return getErrorMessage(1); -} -function getErrorMessage(version) { - var names = { - 1: "WebGL", - 2: "WebGL 2" - }; - var contexts = { - 1: window.WebGLRenderingContext, - 2: window.WebGL2RenderingContext - }; - var message = 'Your $0 does not seem to support $1'; - var element = document.createElement("div"); - element.id = "webglmessage"; - element.style.fontFamily = "monospace"; - element.style.fontSize = "13px"; - element.style.fontWeight = "normal"; - element.style.textAlign = "center"; - element.style.background = "#fff"; - element.style.color = "#000"; - element.style.padding = "1.5em"; - element.style.width = "400px"; - element.style.margin = "5em auto 0"; - if (contexts[version]) { - message = message.replace("$0", "graphics card"); - } else { - message = message.replace("$0", "browser"); - } - message = message.replace("$1", names[version]); - element.innerHTML = message; - return element; } -const pixelRatio = window.devicePixelRatio || 1.0; -function event2scene_pixel(scene, event) { - const { canvas } = scene.screen; +function events2unitless(screen, event) { + const { canvas , winscale , renderer } = screen; const rect = canvas.getBoundingClientRect(); - const x = (event.clientX - rect.left) * pixelRatio; - const y = (rect.height - (event.clientY - rect.top)) * pixelRatio; + const x = (event.clientX - rect.left) / winscale; + const y = (event.clientY - rect.top) / winscale; return [ x, - y + renderer._height - y ]; } function Identity4x4() { - return new pe(); + return new ze(); } function in_scene(scene, mouse_event) { - const [x, y] = event2scene_pixel(scene, mouse_event); - const [sx, sy, sw, sh] = scene.pixelarea.value; + const [x, y] = events2unitless(scene.screen, mouse_event); + const [sx, sy, sw, sh] = scene.viewport.value; return x >= sx && x < sx + sw && y >= sy && y < sy + sh; } -function attach_3d_camera(canvas, makie_camera, cam3d, scene) { +function attach_3d_camera(canvas, makie_camera, cam3d, light_dir, scene) { if (cam3d === undefined) { return; } const [w, h] = makie_camera.resolution.value; - const camera = new ut(cam3d.fov, w / h, cam3d.near, cam3d.far); - const center = new M(...cam3d.lookat); - camera.up = new M(...cam3d.upvector); - camera.position.set(...cam3d.eyeposition); + const camera = new yt(cam3d.fov.value, w / h, 0.01, 100.0); + const center = new A(...cam3d.lookat.value); + camera.up = new A(...cam3d.upvector.value); + camera.position.set(...cam3d.eyeposition.value); camera.lookAt(center); - function update() { + const use_orbit_cam = ()=>!(JSServe.can_send_to_julia && JSServe.can_send_to_julia()); + const controls = new OrbitControls(camera, canvas, use_orbit_cam, (e)=>in_scene(scene, e)); + controls.addEventListener("change", (e)=>{ const view = camera.matrixWorldInverse; const projection = camera.projectionMatrix; const [width, height] = cam3d.resolution.value; @@ -19570,82 +21034,8 @@ function attach_3d_camera(canvas, makie_camera, cam3d, scene) { y, z ]); - } - cam3d.resolution.on(update); - function addMouseHandler(domObject, drag, zoomIn, zoomOut) { - let startDragX = null; - let startDragY = null; - function mouseWheelHandler(e) { - e = window.event || e; - if (!in_scene(scene, e)) { - return; - } - const delta = Math.sign(e.deltaY); - if (delta == -1) { - zoomOut(); - } else if (delta == 1) { - zoomIn(); - } - e.preventDefault(); - } - function mouseDownHandler(e) { - if (!in_scene(scene, e)) { - return; - } - startDragX = e.clientX; - startDragY = e.clientY; - e.preventDefault(); - } - function mouseMoveHandler(e) { - if (!in_scene(scene, e)) { - return; - } - if (startDragX === null || startDragY === null) return; - if (drag) drag(e.clientX - startDragX, e.clientY - startDragY); - startDragX = e.clientX; - startDragY = e.clientY; - e.preventDefault(); - } - function mouseUpHandler(e) { - if (!in_scene(scene, e)) { - return; - } - mouseMoveHandler.call(this, e); - startDragX = null; - startDragY = null; - e.preventDefault(); - } - domObject.addEventListener("wheel", mouseWheelHandler); - domObject.addEventListener("mousedown", mouseDownHandler); - domObject.addEventListener("mousemove", mouseMoveHandler); - domObject.addEventListener("mouseup", mouseUpHandler); - } - function drag(deltaX, deltaY) { - const radPerPixel = Math.PI / 450; - const deltaPhi = radPerPixel * deltaX; - const deltaTheta = radPerPixel * deltaY; - const pos = camera.position.sub(center); - const radius = pos.length(); - let theta = Math.acos(pos.z / radius); - let phi = Math.atan2(pos.y, pos.x); - theta = Math.min(Math.max(theta - deltaTheta, 0), Math.PI); - phi -= deltaPhi; - pos.x = radius * Math.sin(theta) * Math.cos(phi); - pos.y = radius * Math.sin(theta) * Math.sin(phi); - pos.z = radius * Math.cos(theta); - camera.position.add(center); - camera.lookAt(center); - update(); - } - function zoomIn() { - camera.position.sub(center).multiplyScalar(0.9).add(center); - update(); - } - function zoomOut() { - camera.position.sub(center).multiplyScalar(1.1).add(center); - update(); - } - addMouseHandler(canvas, drag, zoomIn, zoomOut); + makie_camera.update_light_dir(light_dir.value); + }); } function mul(a, b) { return b.clone().multiply(a); @@ -19714,18 +21104,19 @@ function relative_space() { } class MakieCamera { constructor(){ - this.view = new go(Identity4x4()); - this.projection = new go(Identity4x4()); - this.projectionview = new go(Identity4x4()); - this.pixel_space = new go(Identity4x4()); - this.pixel_space_inverse = new go(Identity4x4()); - this.projectionview_inverse = new go(Identity4x4()); - this.relative_space = new go(relative_space()); - this.relative_inverse = new go(relative_space().invert()); - this.clip_space = new go(Identity4x4()); - this.resolution = new go(new X()); - this.eyeposition = new go(new M()); + this.view = new Pu(Identity4x4()); + this.projection = new Pu(Identity4x4()); + this.projectionview = new Pu(Identity4x4()); + this.pixel_space = new Pu(Identity4x4()); + this.pixel_space_inverse = new Pu(Identity4x4()); + this.projectionview_inverse = new Pu(Identity4x4()); + this.relative_space = new Pu(relative_space()); + this.relative_inverse = new Pu(relative_space().invert()); + this.clip_space = new Pu(Identity4x4()); + this.resolution = new Pu(new Z()); + this.eyeposition = new Pu(new A()); this.preprojections = {}; + this.light_direction = new Pu(new A(-1, -1, -1).normalize()); } calculate_matrices() { const [w, h] = this.resolution.value; @@ -19748,6 +21139,12 @@ class MakieCamera { this.calculate_matrices(); return; } + update_light_dir(light_dir) { + const T = new He().setFromMatrix4(this.view.value).invert(); + const new_dir = new A().fromArray(light_dir); + new_dir.applyMatrix3(T).normalize(); + this.light_direction.value = new_dir; + } clip_to_space(space) { if (space === "data") { return this.projectionview_inverse.value; @@ -19789,13 +21186,25 @@ class MakieCamera { return matrix_uniform; } else { const matrix = this.calculate_preprojection_matrix(space, markerspace); - const uniform = new go(matrix); + const uniform = new Pu(matrix); this.preprojections[key] = uniform; return uniform; } } } const scene_cache = {}; +function filter_by_key(dict, keys, default_value = false) { + const result = {}; + keys.forEach((key)=>{ + const val = dict[key]; + if (val) { + result[key] = val; + } else { + result[key] = default_value; + } + }); + return result; +} const plot_cache = {}; const TEXTURE_ATLAS = [ undefined @@ -19811,6 +21220,7 @@ function delete_scene(scene_id) { if (!scene) { return; } + delete_three_scene(scene); while(scene.children.length > 0){ scene.remove(scene.children[0]); } @@ -19828,7 +21238,10 @@ function find_plots(plot_uuids) { } function delete_scenes(scene_uuids, plot_uuids) { plot_uuids.forEach((plot_id)=>{ - delete plot_cache[plot_id]; + const plot = plot_cache[plot_id]; + if (plot) { + delete_plot(plot); + } }); scene_uuids.forEach((scene_id)=>{ delete_scene(scene_id); @@ -19840,14 +21253,9 @@ function insert_plot(scene_id, plot_data) { add_plot(scene, plot); }); } -function delete_plots(scene_id, plot_uuids) { - console.log(`deleting plots!: ${plot_uuids}`); - const scene = find_scene(scene_id); +function delete_plots(plot_uuids) { const plots = find_plots(plot_uuids); - plots.forEach((p)=>{ - scene.remove(p); - delete plot_cache[p]; - }); + plots.forEach(delete_plot); } function convert_texture(data) { const tex = create_texture(data); @@ -19908,9 +21316,236 @@ function deserialize_uniforms(data) { } return result; } +function linesegments_vertex_shader(uniforms, attributes) { + const attribute_decl = attributes_to_type_declaration(attributes); + const uniform_decl = uniforms_to_type_declaration(uniforms); + const color = attribute_type(attributes.color_start) || uniform_type(uniforms.color_start); + return `precision mediump int; + precision highp float; + + ${attribute_decl} + ${uniform_decl} + + out vec2 f_uv; + out ${color} f_color; + + vec2 get_resolution() { + // 2 * px_per_unit doesn't make any sense, but works + // TODO, figure out what's going on! + return resolution / 2.0 * px_per_unit; + } + + vec3 screen_space(vec3 point) { + vec4 vertex = projectionview * model * vec4(point, 1); + return vec3(vertex.xy * get_resolution(), vertex.z + vertex.w * depth_shift) / vertex.w; + } + + vec3 screen_space(vec2 point) { + return screen_space(vec3(point, 0)); + } + + void main() { + vec3 p_a = screen_space(linepoint_start); + vec3 p_b = screen_space(linepoint_end); + float width = (px_per_unit * (position.x == 1.0 ? linewidth_end : linewidth_start)); + f_color = position.x == 1.0 ? color_end : color_start; + f_uv = vec2(position.x, position.y + 0.5); + + vec2 pointA = p_a.xy; + vec2 pointB = p_b.xy; + + vec2 xBasis = pointB - pointA; + vec2 yBasis = normalize(vec2(-xBasis.y, xBasis.x)); + vec2 point = pointA + xBasis * position.x + yBasis * width * position.y; + + gl_Position = vec4(point.xy / get_resolution(), position.x == 1.0 ? p_b.z : p_a.z, 1.0); + } + `; +} +function lines_fragment_shader(uniforms, attributes) { + const color = attribute_type(attributes.color_start) || uniform_type(uniforms.color_start); + const color_uniforms = filter_by_key(uniforms, [ + "colorrange", + "colormap", + "nan_color", + "highclip", + "lowclip" + ]); + const uniform_decl = uniforms_to_type_declaration(color_uniforms); + return `#extension GL_OES_standard_derivatives : enable + + precision mediump int; + precision highp float; + precision mediump sampler2D; + precision mediump sampler3D; + + in vec2 f_uv; + in ${color} f_color; + ${uniform_decl} + + out vec4 fragment_color; + + // Half width of antialiasing smoothstep + #define ANTIALIAS_RADIUS 0.7071067811865476 + + vec4 get_color_from_cmap(float value, sampler2D colormap, vec2 colorrange) { + float cmin = colorrange.x; + float cmax = colorrange.y; + if (value <= cmax && value >= cmin) { + // in value range, continue! + } else if (value < cmin) { + return lowclip; + } else if (value > cmax) { + return highclip; + } else { + // isnan CAN be broken (of course) -.- + // so if outside value range and not smaller/bigger min/max we assume NaN + return nan_color; + } + float i01 = clamp((value - cmin) / (cmax - cmin), 0.0, 1.0); + // 1/0 corresponds to the corner of the colormap, so to properly interpolate + // between the colors, we need to scale it, so that the ends are at 1 - (stepsize/2) and 0+(stepsize/2). + float stepsize = 1.0 / float(textureSize(colormap, 0)); + i01 = (1.0 - stepsize) * i01 + 0.5 * stepsize; + return texture(colormap, vec2(i01, 0.0)); + } + + vec4 get_color(float color, sampler2D colormap, vec2 colorrange) { + return get_color_from_cmap(color, colormap, colorrange); + } + + vec4 get_color(vec4 color, bool colormap, bool colorrange) { + return color; + } + vec4 get_color(vec3 color, bool colormap, bool colorrange) { + return vec4(color, 1.0); + } + + float aastep(float threshold, float value) { + float afwidth = length(vec2(dFdx(value), dFdy(value))) * ANTIALIAS_RADIUS; + return smoothstep(threshold-afwidth, threshold+afwidth, value); + } + + float aastep(float threshold1, float threshold2, float dist) { + return aastep(threshold1, dist) * aastep(threshold2, 1.0 - dist); + } + + void main(){ + float xalpha = aastep(0.0, 0.0, f_uv.x); + float yalpha = aastep(0.0, 0.0, f_uv.y); + vec4 color = get_color(f_color, colormap, colorrange); + fragment_color = vec4(color.rgb, color.a); + } + `; +} +function create_line_material(uniforms, attributes) { + const uniforms_des = deserialize_uniforms(uniforms); + return new THREE.RawShaderMaterial({ + uniforms: uniforms_des, + glslVersion: THREE.GLSL3, + vertexShader: linesegments_vertex_shader(uniforms_des, attributes), + fragmentShader: lines_fragment_shader(uniforms_des, attributes), + transparent: true + }); +} +function attach_interleaved_line_buffer(attr_name, geometry, points, ndim, is_segments) { + const skip_elems = is_segments ? 2 * ndim : ndim; + const buffer = new THREE.InstancedInterleavedBuffer(points, skip_elems, 1); + geometry.setAttribute(attr_name + "_start", new THREE.InterleavedBufferAttribute(buffer, ndim, 0)); + geometry.setAttribute(attr_name + "_end", new THREE.InterleavedBufferAttribute(buffer, ndim, ndim)); + return buffer; +} +function create_line_instance_geometry() { + const geometry = new THREE.InstancedBufferGeometry(); + const instance_positions = [ + 0, + -0.5, + 1, + -0.5, + 1, + 0.5, + 0, + -0.5, + 1, + 0.5, + 0, + 0.5 + ]; + geometry.setAttribute("position", new THREE.Float32BufferAttribute(instance_positions, 2)); + geometry.boundingSphere = new THREE.Sphere(); + geometry.boundingSphere.radius = 10000000000000; + geometry.frustumCulled = false; + return geometry; +} +function create_line_buffer(geometry, buffers, name, attr, is_segments) { + const flat_buffer = attr.value.flat; + const ndims = attr.value.type_length; + const linebuffer = attach_interleaved_line_buffer(name, geometry, flat_buffer, ndims, is_segments); + buffers[name] = linebuffer; + return flat_buffer; +} +function create_line_buffers(geometry, buffers, attributes, is_segments) { + for(let name in attributes){ + const attr = attributes[name]; + create_line_buffer(geometry, buffers, name, attr, is_segments); + } +} +function attach_updates(mesh, buffers, attributes, is_segments) { + let geometry = mesh.geometry; + for(let name in attributes){ + const attr = attributes[name]; + attr.on((new_points)=>{ + let buff = buffers[name]; + const ndims = new_points.type_length; + const new_line_points = new_points.flat; + const old_count = buff.array.length; + const new_count = new_line_points.length / ndims; + if (old_count < new_line_points.length) { + mesh.geometry.dispose(); + geometry = create_line_instance_geometry(); + buff = attach_interleaved_line_buffer(name, geometry, new_line_points, ndims, is_segments); + mesh.geometry = geometry; + buffers[name] = buff; + } else { + buff.set(new_line_points); + } + const ls_factor = is_segments ? 2 : 1; + const offset = is_segments ? 0 : 1; + mesh.geometry.instanceCount = Math.max(0, new_count / ls_factor - offset); + buff.needsUpdate = true; + mesh.needsUpdate = true; + }); + } +} +function _create_line(line_data, is_segments) { + const geometry = create_line_instance_geometry(); + const buffers = {}; + create_line_buffers(geometry, buffers, line_data.attributes, is_segments); + const material = create_line_material(line_data.uniforms, geometry.attributes); + const mesh = new THREE.Mesh(geometry, material); + const offset = is_segments ? 0 : 1; + const new_count = geometry.attributes.linepoint_start.count; + mesh.geometry.instanceCount = Math.max(0, new_count - offset); + attach_updates(mesh, buffers, line_data.attributes, is_segments); + return mesh; +} +function create_line(line_data) { + return _create_line(line_data, false); +} +function create_linesegments(line_data) { + return _create_line(line_data, true); +} function deserialize_plot(data) { let mesh; - if ("instance_attributes" in data) { + const update_visible = (v)=>{ + mesh.visible = v; + return; + }; + if (data.plot_type === "lines") { + mesh = create_line(data); + } else if (data.plot_type === "linesegments") { + mesh = create_linesegments(data); + } else if ("instance_attributes" in data) { mesh = create_instanced_mesh(data); } else { mesh = create_mesh(data); @@ -19919,14 +21554,12 @@ function deserialize_plot(data) { mesh.frustumCulled = false; mesh.matrixAutoUpdate = false; mesh.plot_uuid = data.uuid; - const update_visible = (v)=>{ - mesh.visible = v; - return; - }; update_visible(data.visible.value); data.visible.on(update_visible); connect_uniforms(mesh, data.uniform_updater); - connect_attributes(mesh, data.attribute_updater); + if (!(data.plot_type === "lines" || data.plot_type === "linesegments")) { + connect_attributes(mesh, data.attribute_updater); + } return mesh; } const ON_NEXT_INSERT = new Set(); @@ -19954,13 +21587,27 @@ function add_plot(scene, plot_data) { plot_data.uniforms.projection = identity; plot_data.uniforms.projectionview = identity; } + const { px_per_unit } = scene.screen; plot_data.uniforms.resolution = cam.resolution; + plot_data.uniforms.px_per_unit = new mod.Uniform(px_per_unit); if (plot_data.uniforms.preprojection) { const { space , markerspace } = plot_data; plot_data.uniforms.preprojection = cam.preprojection_matrix(space.value, markerspace.value); } + if (scene.camera_relative_light) { + plot_data.uniforms.light_direction = cam.light_direction; + scene.light_direction.on((value)=>{ + cam.update_light_dir(value); + }); + } else { + const light_dir = new mod.Vector3().fromArray(scene.light_direction.value); + plot_data.uniforms.light_direction = new mod.Uniform(light_dir); + scene.light_direction.on((value)=>{ + plot_data.uniforms.light_direction.value.fromArray(value); + }); + } const p = deserialize_plot(plot_data); - plot_cache[plot_data.uuid] = p; + plot_cache[p.plot_uuid] = p; scene.add(p); const next_insert = new Set(ON_NEXT_INSERT); next_insert.forEach((f)=>f()); @@ -19991,22 +21638,43 @@ function connect_uniforms(mesh, updater) { } }); } +function convert_RGB_to_RGBA(rgbArray) { + const length = rgbArray.length; + const rgbaArray = new Float32Array(length / 3 * 4); + 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; + } + return rgbaArray; +} function create_texture(data) { const buffer = data.data; if (data.size.length == 3) { - const tex = new mod.DataTexture3D(buffer, data.size[0], data.size[1], data.size[2]); + const tex = new mod.Data3DTexture(buffer, data.size[0], data.size[1], data.size[2]); tex.format = mod[data.three_format]; tex.type = mod[data.three_type]; return tex; } else { - const tex_data = buffer == "texture_atlas" ? TEXTURE_ATLAS[0].value : buffer; - return new mod.DataTexture(tex_data, data.size[0], data.size[1], mod[data.three_format], mod[data.three_type]); + let tex_data; + if (buffer == "texture_atlas") { + tex_data = TEXTURE_ATLAS[0].value; + } else { + tex_data = buffer; + } + let format = mod[data.three_format]; + if (data.three_format == "RGBFormat") { + tex_data = convert_RGB_to_RGBA(tex_data); + format = mod.RGBAFormat; + } + return new mod.DataTexture(tex_data, data.size[0], data.size[1], format, mod[data.three_type]); } } function re_create_texture(old_texture, buffer, size) { let tex; if (size.length == 3) { - tex = new mod.DataTexture3D(buffer, size[0], size[1], size[2]); + tex = new mod.Data3DTexture(buffer, size[0], size[1], size[2]); tex.format = old_texture.format; tex.type = old_texture.type; } else { @@ -20100,6 +21768,7 @@ function create_material(program) { fragmentShader: program.fragment_source, side: is_volume ? mod.BackSide : mod.DoubleSide, transparent: true, + glslVersion: mod.GLSL3, depthTest: !program.overdraw.value, depthWrite: !program.transparency.value }); @@ -20203,26 +21872,37 @@ function deserialize_scene(data, screen) { add_scene(data.uuid, scene); scene.scene_uuid = data.uuid; scene.frustumCulled = false; - scene.pixelarea = data.pixelarea; + scene.viewport = data.viewport; scene.backgroundcolor = data.backgroundcolor; + scene.backgroundcolor_alpha = data.backgroundcolor_alpha; scene.clearscene = data.clearscene; scene.visible = data.visible; + scene.camera_relative_light = data.camera_relative_light; + scene.light_direction = data.light_direction; const camera = new MakieCamera(); scene.wgl_camera = camera; - function update_cam(camera_matrices) { + function update_cam(camera_matrices, force) { + if (!force) { + if (!(JSServe.can_send_to_julia && JSServe.can_send_to_julia())) { + return; + } + } const [view, projection, resolution, eyepos] = camera_matrices; camera.update_matrices(view, projection, resolution, eyepos); } - update_cam(data.camera.value); if (data.cam3d_state) { - attach_3d_camera(canvas, camera, data.cam3d_state, scene); - } else { - data.camera.on(update_cam); + attach_3d_camera(canvas, camera, data.cam3d_state, data.light_direction, scene); } + update_cam(data.camera.value, true); + camera.update_light_dir(data.light_direction.value); + data.camera.on(update_cam); data.plots.forEach((plot_data)=>{ add_plot(scene, plot_data); }); - scene.scene_children = data.children.map((child)=>deserialize_scene(child, screen)); + scene.scene_children = data.children.map((child)=>{ + const childscene = deserialize_scene(child, screen); + return childscene; + }); return scene; } function delete_plot(plot) { @@ -20242,24 +21922,23 @@ function delete_three_scene(scene) { } } window.THREE = mod; -const pixelRatio1 = window.devicePixelRatio || 1.0; function render_scene(scene, picking = false) { - const { camera , renderer } = scene.screen; + const { camera , renderer , px_per_unit } = scene.screen; const canvas = renderer.domElement; if (!document.body.contains(canvas)) { console.log("EXITING WGL"); + delete_three_scene(scene); renderer.state.reset(); renderer.dispose(); - delete_three_scene(scene); return false; } if (!scene.visible.value) { return true; } renderer.autoClear = scene.clearscene.value; - const area = scene.pixelarea.value; + const area = scene.viewport.value; if (area) { - const [x, y, w, h] = area.map((t)=>t / pixelRatio1); + const [x, y, w, h] = area.map((x)=>x * px_per_unit); renderer.setViewport(x, y, w, h); renderer.setScissor(x, y, w, h); renderer.setScissorTest(true); @@ -20267,7 +21946,8 @@ function render_scene(scene, picking = false) { renderer.setClearAlpha(0); renderer.setClearColor(new mod.Color(0), 0.0); } else { - renderer.setClearColor(scene.backgroundcolor.value); + const alpha = scene.backgroundcolor_alpha.value; + renderer.setClearColor(scene.backgroundcolor.value, alpha); } renderer.render(scene, camera); } @@ -20308,40 +21988,88 @@ function throttle_function(func, delay) { } return inner_throttle; } -function threejs_module(canvas, comm, width, height, resize_to_body) { - let context = canvas.getContext("webgl2", { - preserveDrawingBuffer: true - }); - if (!context) { - console.warn("WebGL 2.0 not supported by browser, falling back to WebGL 1.0 (Volume plots will not work)"); - context = canvas.getContext("webgl", { - preserveDrawingBuffer: true - }); - } - if (!context) { - return; - } - const renderer = new mod.WebGLRenderer({ - antialias: true, - canvas: canvas, - context: context, - powerPreference: "high-performance" - }); - renderer.setClearColor("#ffffff"); - renderer.setPixelRatio(pixelRatio1); - renderer.setSize(width / pixelRatio1, height / pixelRatio1); - const mouse_callback = (x, y)=>comm.notify({ +function get_body_size() { + const bodyStyle = window.getComputedStyle(document.body); + const width_padding = parseInt(bodyStyle.paddingLeft, 10) + parseInt(bodyStyle.paddingRight, 10) + parseInt(bodyStyle.marginLeft, 10) + parseInt(bodyStyle.marginRight, 10); + const height_padding = parseInt(bodyStyle.paddingTop, 10) + parseInt(bodyStyle.paddingBottom, 10) + parseInt(bodyStyle.marginTop, 10) + parseInt(bodyStyle.marginBottom, 10); + const width = window.innerWidth - width_padding; + const height = window.innerHeight - height_padding; + return [ + width, + height + ]; +} +function get_parent_size(canvas) { + const rect = canvas.parentElement.getBoundingClientRect(); + return [ + rect.width, + rect.height + ]; +} +function wglerror(gl, error) { + switch(error){ + case gl.NO_ERROR: + return "No error"; + case gl.INVALID_ENUM: + return "Invalid enum"; + case gl.INVALID_VALUE: + return "Invalid value"; + case gl.INVALID_OPERATION: + return "Invalid operation"; + case gl.OUT_OF_MEMORY: + return "Out of memory"; + case gl.CONTEXT_LOST_WEBGL: + return "Context lost"; + default: + return "Unknown error"; + } +} +function handleSource(string, errorLine) { + const lines = string.split("\n"); + const lines2 = []; + const from = Math.max(errorLine - 6, 0); + const to = Math.min(errorLine + 6, lines.length); + for(let i = from; i < to; i++){ + const line = i + 1; + lines2.push(`${line === errorLine ? ">" : " "} ${line}: ${lines[i]}`); + } + return lines2.join("\n"); +} +function getShaderErrors(gl, shader, type) { + const status = gl.getShaderParameter(shader, gl.COMPILE_STATUS); + const errors = gl.getShaderInfoLog(shader).trim(); + if (status && errors === "") return ""; + const errorMatches = /ERROR: 0:(\d+)/.exec(errors); + if (errorMatches) { + const errorLine = parseInt(errorMatches[1]); + return type.toUpperCase() + "\n\n" + errors + "\n\n" + handleSource(gl.getShaderSource(shader), errorLine); + } else { + return errors; + } +} +function on_shader_error(gl, program, glVertexShader, glFragmentShader) { + const programLog = gl.getProgramInfoLog(program).trim(); + const vertexErrors = getShaderErrors(gl, glVertexShader, "vertex"); + const fragmentErrors = getShaderErrors(gl, glFragmentShader, "fragment"); + const vertexLog = gl.getShaderInfoLog(glVertexShader).trim(); + const fragmentLog = gl.getShaderInfoLog(glFragmentShader).trim(); + const err = "THREE.WebGLProgram: Shader Error " + wglerror(gl, gl.getError()) + " - " + "VALIDATE_STATUS " + gl.getProgramParameter(program, gl.VALIDATE_STATUS) + "\n\n" + "Program Info Log:\n" + programLog + "\n" + vertexErrors + "\n" + fragmentErrors + "\n" + "Fragment log:\n" + fragmentLog + "Vertex log:\n" + vertexLog; + JSServe.Connection.send_warning(err); +} +function add_canvas_events(screen, comm, resize_to) { + const { canvas , winscale } = screen; + function mouse_callback(event) { + const [x, y] = events2unitless(screen, event); + comm.notify({ mouseposition: [ x, y ] }); + } const notify_mouse_throttled = throttle_function(mouse_callback, 40); function mousemove(event) { - var rect = canvas.getBoundingClientRect(); - var x = (event.clientX - rect.left) * pixelRatio1; - var y = (event.clientY - rect.top) * pixelRatio1; - notify_mouse_throttled(x, y); + notify_mouse_throttled(event); return false; } canvas.addEventListener("mousemove", mousemove); @@ -20393,52 +22121,116 @@ function threejs_module(canvas, comm, width, height, resize_to_body) { canvas.addEventListener("contextmenu", (e)=>e.preventDefault()); canvas.addEventListener("focusout", contextmenu); function resize_callback() { - const bodyStyle = window.getComputedStyle(document.body); - const width_padding = parseInt(bodyStyle.paddingLeft, 10) + parseInt(bodyStyle.paddingRight, 10) + parseInt(bodyStyle.marginLeft, 10) + parseInt(bodyStyle.marginRight, 10); - const height_padding = parseInt(bodyStyle.paddingTop, 10) + parseInt(bodyStyle.paddingBottom, 10) + parseInt(bodyStyle.marginTop, 10) + parseInt(bodyStyle.marginBottom, 10); - const width = (window.innerWidth - width_padding) * pixelRatio1; - const height = (window.innerHeight - height_padding) * pixelRatio1; + let width, height; + if (resize_to == "body") { + [width, height] = get_body_size(); + } else if (resize_to == "parent") { + [width, height] = get_parent_size(canvas); + } comm.notify({ resize: [ - width, - height + width / winscale, + height / winscale ] }); } - if (resize_to_body) { + if (resize_to) { const resize_callback_throttled = throttle_function(resize_callback, 100); window.addEventListener("resize", (event)=>resize_callback_throttled()); resize_callback_throttled(); } +} +function threejs_module(canvas) { + let context = canvas.getContext("webgl2", { + preserveDrawingBuffer: true + }); + if (!context) { + console.warn("WebGL 2.0 not supported by browser, falling back to WebGL 1.0 (Volume plots will not work)"); + context = canvas.getContext("webgl", { + preserveDrawingBuffer: true + }); + } + if (!context) { + return; + } + const renderer = new mod.WebGLRenderer({ + antialias: true, + canvas: canvas, + context: context, + powerPreference: "high-performance" + }); + renderer.debug.onShaderError = on_shader_error; + renderer.setClearColor("#ffffff"); return renderer; } -function create_scene(wrapper, canvas, canvas_width, scenes, comm, width, height, texture_atlas_obs, fps, resize_to_body) { - const renderer = threejs_module(canvas, comm, width, height, resize_to_body); +function set_render_size(screen, width, height) { + const { renderer , canvas , scalefactor , winscale , px_per_unit } = screen; + const [swidth, sheight] = [ + winscale * width, + winscale * height + ]; + const real_pixel_width = Math.ceil(width * px_per_unit); + const real_pixel_height = Math.ceil(height * px_per_unit); + renderer._width = width; + renderer._height = height; + canvas.width = real_pixel_width; + canvas.height = real_pixel_height; + canvas.style.width = swidth + "px"; + canvas.style.height = sheight + "px"; + renderer.setViewport(0, 0, real_pixel_width, real_pixel_height); + add_picking_target(screen); + return; +} +function add_picking_target(screen) { + const { picking_target , canvas } = screen; + const [w, h] = [ + canvas.width, + canvas.height + ]; + if (picking_target) { + if (picking_target.width == w && picking_target.height == h) { + return; + } else { + picking_target.dispose(); + } + } + screen.picking_target = new mod.WebGLRenderTarget(w, h); + return; +} +function create_scene(wrapper, canvas, canvas_width, scenes, comm, width, height, texture_atlas_obs, fps, resize_to, px_per_unit, scalefactor) { + if (!scalefactor) { + scalefactor = window.devicePixelRatio || 1.0; + } + if (!px_per_unit) { + px_per_unit = scalefactor; + } + const renderer = threejs_module(canvas); TEXTURE_ATLAS[0] = texture_atlas_obs; - if (renderer) { - const camera = new mod.PerspectiveCamera(45, 1, 0, 100); - camera.updateProjectionMatrix(); - const size = new mod.Vector2(); - renderer.getDrawingBufferSize(size); - const picking_target = new mod.WebGLRenderTarget(size.x, size.y); - const screen = { - renderer, - picking_target, - camera, - fps, - canvas - }; - const three_scene = deserialize_scene(scenes, screen); - console.log(three_scene); - start_renderloop(three_scene); - canvas_width.on((w_h)=>{ - const pixelRatio = renderer.getPixelRatio(); - renderer.setSize(w_h[0] / pixelRatio, w_h[1] / pixelRatio); - }); - } else { + if (!renderer) { const warning = getWebGLErrorMessage(); wrapper.appendChild(warning); } + const camera = new mod.PerspectiveCamera(45, 1, 0, 100); + camera.updateProjectionMatrix(); + const pixel_ratio = window.devicePixelRatio || 1.0; + const winscale = scalefactor / pixel_ratio; + const screen = { + renderer, + camera, + fps, + canvas, + px_per_unit, + scalefactor, + winscale + }; + add_canvas_events(screen, comm, resize_to); + set_render_size(screen, width, height); + const three_scene = deserialize_scene(scenes, screen); + start_renderloop(three_scene); + canvas_width.on((w_h)=>{ + set_render_size(screen, ...w_h); + }); + return renderer; } function set_picking_uniforms(scene, last_id, picking, picked_plots, plots, id_to_plot) { scene.children.forEach((plot, index)=>{ @@ -20467,8 +22259,20 @@ function set_picking_uniforms(scene, last_id, picking, picked_plots, plots, id_t }); return next_id; } -function pick_native(scene, x, y, w, h) { - const { renderer , picking_target } = scene.screen; +function pick_native(scene, _x, _y, _w, _h) { + const { renderer , picking_target , px_per_unit } = scene.screen; + [_x, _y, _w, _h] = [ + _x, + _y, + _w, + _h + ].map((x)=>Math.ceil(x * px_per_unit)); + const [x, y, w, h] = [ + _x, + _y, + _w, + _h + ]; renderer.setRenderTarget(picking_target); set_picking_uniforms(scene, 1, true); render_scene(scene, true); @@ -20511,8 +22315,11 @@ function pick_native(scene, x, y, w, h) { ]; } function pick_closest(scene, xy, range) { - const { picking_target } = scene.screen; - const { width , height } = picking_target; + const { renderer } = scene.screen; + const [width, height] = [ + renderer._width, + renderer._height + ]; if (!(1.0 <= xy[0] <= width && 1.0 <= xy[1] <= height)) { return [ null, @@ -20552,8 +22359,11 @@ function pick_closest(scene, xy, range) { return selection; } function pick_sorted(scene, xy, range) { - const { picking_target } = scene.screen; - const { width , height } = picking_target; + const { renderer } = scene.screen; + const [width, height] = [ + renderer._width, + renderer._height + ]; if (!(1.0 <= xy[0] <= width && 1.0 <= xy[1] <= height)) { return null; } @@ -20575,6 +22385,9 @@ function pick_sorted(scene, xy, range) { for(let i = 1; i <= dx; i++){ for(let j = 1; j <= dx; j++){ const d = x - i ^ 2 + (y - j) ^ 2; + if (plot_matrix.length <= pindex) { + continue; + } const [plot_uuid, index] = plot_matrix[pindex]; pindex = pindex + 1; const plot_index = selected.findIndex((x)=>x[0].plot_uuid == plot_uuid); @@ -20609,17 +22422,17 @@ function register_popup(popup, scene, plots_to_pick, callback) { } const { canvas } = scene.screen; canvas.addEventListener("mousedown", (event)=>{ - if (!popup.classList.contains("show")) { - popup.classList.add("show"); - } - popup.style.left = event.pageX + "px"; - popup.style.top = event.pageY + "px"; - const [x, y] = event2scene_pixel(scene, event); + const [x, y] = events2unitless(scene.screen, event); const [_, picks] = pick_native(scene, x, y, 1, 1); if (picks.length == 1) { const [plot, index] = picks[0]; if (plots_to_pick.has(plot.plot_uuid)) { const result = callback(plot, index); + if (!popup.classList.contains("show")) { + popup.classList.add("show"); + } + popup.style.left = event.pageX + "px"; + popup.style.top = event.pageY + "px"; if (typeof result === "string" || result instanceof String) { popup.innerText = result; } else { @@ -20649,13 +22462,14 @@ window.WGL = { plot_cache, delete_scenes, create_scene, - event2scene_pixel, + events2unitless, on_next_insert, register_popup, render_scene }; -export { deserialize_scene as deserialize_scene, threejs_module as threejs_module, start_renderloop as start_renderloop, delete_plots as delete_plots, insert_plot as insert_plot, find_plots as find_plots, delete_scene as delete_scene, find_scene as find_scene, scene_cache as scene_cache, plot_cache as plot_cache, delete_scenes as delete_scenes, create_scene as create_scene, event2scene_pixel as event2scene_pixel, on_next_insert as on_next_insert }; +export { deserialize_scene as deserialize_scene, threejs_module as threejs_module, start_renderloop as start_renderloop, delete_plots as delete_plots, insert_plot as insert_plot, find_plots as find_plots, delete_scene as delete_scene, find_scene as find_scene, scene_cache as scene_cache, plot_cache as plot_cache, delete_scenes as delete_scenes, create_scene as create_scene, events2unitless as events2unitless, on_next_insert as on_next_insert }; export { render_scene as render_scene }; +export { wglerror as wglerror }; export { pick_native as pick_native }; export { pick_closest as pick_closest }; export { pick_sorted as pick_sorted }; diff --git a/WGLMakie/src/wglmakie.js b/WGLMakie/src/wglmakie.js index d87a13face0..a9986046845 100644 --- a/WGLMakie/src/wglmakie.js +++ b/WGLMakie/src/wglmakie.js @@ -1,4 +1,4 @@ -import * as THREE from "https://cdn.esm.sh/v66/three@0.136/es2021/three.js"; +import * as THREE from "./THREE.js"; import { getWebGLErrorMessage } from "./WEBGL.js"; import { delete_scenes, @@ -15,20 +15,18 @@ import { find_scene, } from "./Serialization.js"; -import { event2scene_pixel } from "./Camera.js"; +import { events2unitless } from "./Camera.js"; window.THREE = THREE; -const pixelRatio = window.devicePixelRatio || 1.0; - export function render_scene(scene, picking = false) { - const { camera, renderer } = scene.screen; + const { camera, renderer, px_per_unit } = scene.screen; const canvas = renderer.domElement; if (!document.body.contains(canvas)) { console.log("EXITING WGL"); + delete_three_scene(scene); renderer.state.reset(); renderer.dispose(); - delete_three_scene(scene); return false; } // dont render invisible scenes @@ -36,9 +34,9 @@ export function render_scene(scene, picking = false) { return true; } renderer.autoClear = scene.clearscene.value; - const area = scene.pixelarea.value; + const area = scene.viewport.value; if (area) { - const [x, y, w, h] = area.map((t) => t / pixelRatio); + const [x, y, w, h] = area.map((x) => x * px_per_unit); renderer.setViewport(x, y, w, h); renderer.setScissor(x, y, w, h); renderer.setScissorTest(true); @@ -46,7 +44,8 @@ export function render_scene(scene, picking = false) { renderer.setClearAlpha(0); renderer.setClearColor(new THREE.Color(0), 0.0); } else { - renderer.setClearColor(scene.backgroundcolor.value); + const alpha = scene.backgroundcolor_alpha.value; + renderer.setClearColor(scene.backgroundcolor.value, alpha); } renderer.render(scene, camera); } @@ -106,52 +105,135 @@ function throttle_function(func, delay) { // to occur at some later later time, so that it // does not get lost; we'll schedule it so that it // fires just a bit after our choke ends. - future_id = setTimeout(() => inner_throttle(...args), now - prev + 1); + future_id = setTimeout( + () => inner_throttle(...args), + now - prev + 1 + ); } - }; + } return inner_throttle; } -function threejs_module(canvas, comm, width, height, resize_to_body) { - let context = canvas.getContext("webgl2", { - preserveDrawingBuffer: true, - }); - if (!context) { - console.warn( - "WebGL 2.0 not supported by browser, falling back to WebGL 1.0 (Volume plots will not work)" - ); - context = canvas.getContext("webgl", { - preserveDrawingBuffer: true, - }); +function get_body_size() { + const bodyStyle = window.getComputedStyle(document.body); + // Subtract padding that is added by VSCode + const width_padding = + parseInt(bodyStyle.paddingLeft, 10) + + parseInt(bodyStyle.paddingRight, 10) + + parseInt(bodyStyle.marginLeft, 10) + + parseInt(bodyStyle.marginRight, 10); + const height_padding = + parseInt(bodyStyle.paddingTop, 10) + + parseInt(bodyStyle.paddingBottom, 10) + + parseInt(bodyStyle.marginTop, 10) + + parseInt(bodyStyle.marginBottom, 10); + const width = (window.innerWidth - width_padding); + const height = (window.innerHeight - height_padding); + return [width, height]; +} +function get_parent_size(canvas) { + const rect = canvas.parentElement.getBoundingClientRect(); + return [rect.width, rect.height]; +} + +export function wglerror(gl, error) { + switch (error) { + case gl.NO_ERROR: + return "No error"; + case gl.INVALID_ENUM: + return "Invalid enum"; + case gl.INVALID_VALUE: + return "Invalid value"; + case gl.INVALID_OPERATION: + return "Invalid operation"; + case gl.OUT_OF_MEMORY: + return "Out of memory"; + case gl.CONTEXT_LOST_WEBGL: + return "Context lost"; + default: + return "Unknown error"; } - if (!context) { - // Sigh, safari or something - // we return nothing which will be handled by caller - return; +} +// taken from THREEJS: +//https://github.com/mrdoob/three.js/blob/5303ef2d46b02e7c503ca63cedca0b93cd9c853e/src/renderers/webgl/WebGLProgram.js#L67C1-L89C2 +function handleSource(string, errorLine) { + const lines = string.split("\n"); + const lines2 = []; + + const from = Math.max(errorLine - 6, 0); + const to = Math.min(errorLine + 6, lines.length); + + for (let i = from; i < to; i++) { + const line = i + 1; + lines2.push(`${line === errorLine ? ">" : " "} ${line}: ${lines[i]}`); } - const renderer = new THREE.WebGLRenderer({ - antialias: true, - canvas: canvas, - context: context, - powerPreference: "high-performance", - }); - renderer.setClearColor("#ffffff"); + return lines2.join("\n"); +} + +function getShaderErrors(gl, shader, type) { + const status = gl.getShaderParameter(shader, gl.COMPILE_STATUS); + const errors = gl.getShaderInfoLog(shader).trim(); - // The following handles high-DPI devices - // `renderer.setSize` also updates `canvas` size - renderer.setPixelRatio(pixelRatio); - renderer.setSize(width / pixelRatio, height / pixelRatio); + if (status && errors === "") return ""; + + const errorMatches = /ERROR: 0:(\d+)/.exec(errors); + if (errorMatches) { + // --enable-privileged-webgl-extension + // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); + + const errorLine = parseInt(errorMatches[1]); + return ( + type.toUpperCase() + + "\n\n" + + errors + + "\n\n" + + handleSource(gl.getShaderSource(shader), errorLine) + ); + } else { + return errors; + } +} +function on_shader_error(gl, program, glVertexShader, glFragmentShader) { + const programLog = gl.getProgramInfoLog(program).trim(); + const vertexErrors = getShaderErrors(gl, glVertexShader, "vertex"); + const fragmentErrors = getShaderErrors(gl, glFragmentShader, "fragment"); + const vertexLog = gl.getShaderInfoLog(glVertexShader).trim(); + const fragmentLog = gl.getShaderInfoLog(glFragmentShader).trim(); + + const err = + "THREE.WebGLProgram: Shader Error " + + wglerror(gl, gl.getError()) + + " - " + + "VALIDATE_STATUS " + + gl.getProgramParameter(program, gl.VALIDATE_STATUS) + + "\n\n" + + "Program Info Log:\n" + + programLog + + "\n" + + vertexErrors + + "\n" + + fragmentErrors + + "\n" + + "Fragment log:\n" + + fragmentLog + + "Vertex log:\n" + + vertexLog; + + JSServe.Connection.send_warning(err); +} + +function add_canvas_events(screen, comm, resize_to) { + const { canvas, winscale } = screen; + function mouse_callback(event) { + const [x, y] = events2unitless(screen, event); + comm.notify({ mouseposition: [x, y] }); + } - const mouse_callback = (x, y) => comm.notify({ mouseposition: [x, y] }); const notify_mouse_throttled = throttle_function(mouse_callback, 40); function mousemove(event) { - var rect = canvas.getBoundingClientRect(); - var x = (event.clientX - rect.left) * pixelRatio; - var y = (event.clientY - rect.top) * pixelRatio; - - notify_mouse_throttled(x, y); + notify_mouse_throttled(event); return false; } @@ -217,34 +299,106 @@ function threejs_module(canvas, comm, width, height, resize_to_body) { canvas.addEventListener("focusout", contextmenu); function resize_callback() { - const bodyStyle = window.getComputedStyle(document.body); - // Subtract padding that is added by VSCode - const width_padding = - parseInt(bodyStyle.paddingLeft, 10) + - parseInt(bodyStyle.paddingRight, 10) + - parseInt(bodyStyle.marginLeft, 10) + - parseInt(bodyStyle.marginRight, 10); - const height_padding = - parseInt(bodyStyle.paddingTop, 10) + - parseInt(bodyStyle.paddingBottom, 10) + - parseInt(bodyStyle.marginTop, 10) + - parseInt(bodyStyle.marginBottom, 10); - const width = (window.innerWidth - width_padding) * pixelRatio; - const height = (window.innerHeight - height_padding) * pixelRatio; - + let width, height; + if (resize_to == "body") { + [width, height] = get_body_size(); + } else if (resize_to == "parent") { + [width, height] = get_parent_size(canvas); + } // Send the resize event to Julia - comm.notify({ resize: [width, height] }); + comm.notify({ resize: [width / winscale, height / winscale] }); } - if (resize_to_body) { - const resize_callback_throttled = throttle_function(resize_callback, 100); - window.addEventListener("resize", (event) => resize_callback_throttled()); + if (resize_to) { + const resize_callback_throttled = throttle_function( + resize_callback, + 100 + ); + window.addEventListener("resize", (event) => + resize_callback_throttled() + ); // Fire the resize event once at the start to auto-size our window resize_callback_throttled(); } +} + +function threejs_module(canvas) { + + let context = canvas.getContext("webgl2", { + preserveDrawingBuffer: true, + }); + if (!context) { + console.warn( + "WebGL 2.0 not supported by browser, falling back to WebGL 1.0 (Volume plots will not work)" + ); + context = canvas.getContext("webgl", { + preserveDrawingBuffer: true, + }); + } + if (!context) { + // Sigh, safari or something + // we return nothing which will be handled by caller + return; + } + + const renderer = new THREE.WebGLRenderer({ + antialias: true, + canvas: canvas, + context: context, + powerPreference: "high-performance", + }); + + renderer.debug.onShaderError = on_shader_error; + renderer.setClearColor("#ffffff"); return renderer; } +function set_render_size(screen, width, height) { + const { renderer, canvas, scalefactor, winscale, px_per_unit } = screen; + // The displayed size of the canvas, in CSS pixels - which get scaled by the device pixel ratio + const [swidth, sheight] = [winscale * width, winscale * height]; + + const real_pixel_width = Math.ceil(width * px_per_unit); + const real_pixel_height = Math.ceil(height * px_per_unit); + + renderer._width = width; + renderer._height = height; + + canvas.width = real_pixel_width; + canvas.height = real_pixel_height; + + canvas.style.width = swidth + "px"; + canvas.style.height = sheight + "px"; + + renderer.setViewport(0, 0, real_pixel_width, real_pixel_height); + add_picking_target(screen); + return; +} + +function add_picking_target(screen) { + const { picking_target, canvas } = screen; + const [w, h] = [canvas.width, canvas.height]; + if (picking_target) { + if (picking_target.width == w && picking_target.height == h) { + return + } else { + picking_target.dispose(); + } + } + // BIG TODO here... + // We should only make the picking target as big as the area we're picking + // e.g. for just the mouse position it should be 1x1 + // Or we should just always bind the target and render to it in one pass + // 1) One Pass: + // Only works on WebGL 2.0, which is still not as widely supported + // Also it's a bit more complicated to setup + // 2) Only Area we pick + // It's currently not as easy to change the offset + area of the camera + // So, we'll need to make that easier first + screen.picking_target = new THREE.WebGLRenderTarget(w, h); + return; +} + function create_scene( wrapper, canvas, @@ -255,49 +409,52 @@ function create_scene( height, texture_atlas_obs, fps, - resize_to_body + resize_to, + px_per_unit, + scalefactor ) { - const renderer = threejs_module( - canvas, - comm, - width, - height, - resize_to_body - ); + if (!scalefactor) { + scalefactor = window.devicePixelRatio || 1.0; + } + if (!px_per_unit) { + px_per_unit = scalefactor; + } + + const renderer = threejs_module(canvas); + TEXTURE_ATLAS[0] = texture_atlas_obs; - if (renderer) { - const camera = new THREE.PerspectiveCamera(45, 1, 0, 100); - camera.updateProjectionMatrix(); - const size = new THREE.Vector2(); - renderer.getDrawingBufferSize(size); - // BIG TODO here... - // We should only make the picking target as big as the area we're picking - // e.g. for just the mouse position it should be 1x1 - // Or we should just always bind the target and render to it in one pass - // 1) One Pass: - // Only works on WebGL 2.0, which is still not as widely supported - // Also it's a bit more complicated to setup - // 2) Only Area we pick - // It's currently not as easy to change the offset + area of the camera - // So, we'll need to make that easier first - const picking_target = new THREE.WebGLRenderTarget(size.x, size.y); - const screen = { renderer, picking_target, camera, fps, canvas }; - - const three_scene = deserialize_scene(scenes, screen); - console.log(three_scene); - start_renderloop(three_scene); - - canvas_width.on((w_h) => { - // `renderer.setSize` correctly updates `canvas` dimensions - const pixelRatio = renderer.getPixelRatio(); - renderer.setSize(w_h[0] / pixelRatio, w_h[1] / pixelRatio); - }); - } else { + if (!renderer) { const warning = getWebGLErrorMessage(); // wrapper.removeChild(canvas) wrapper.appendChild(warning); } + + const camera = new THREE.PerspectiveCamera(45, 1, 0, 100); + camera.updateProjectionMatrix(); + const pixel_ratio = window.devicePixelRatio || 1.0; + const winscale = scalefactor / pixel_ratio; + const screen = { + renderer, + camera, + fps, + canvas, + px_per_unit, + scalefactor, + winscale, + }; + add_canvas_events(screen, comm, resize_to); + set_render_size(screen, width, height); + + const three_scene = deserialize_scene(scenes, screen); + + start_renderloop(three_scene); + + canvas_width.on((w_h) => { + // `renderer.setSize` correctly updates `canvas` dimensions + set_render_size(screen, ...w_h); + }); + return renderer; } function set_picking_uniforms( @@ -341,14 +498,24 @@ function set_picking_uniforms( return next_id; } -export function pick_native(scene, x, y, w, h) { - const { renderer, picking_target } = scene.screen; +/** + * + * @param {*} scene + * @param {*} x in scene unitless pixel space + * @param {*} y in scene unitless pixel space + * @param {*} w in scene unitless pixel space + * @param {*} h in scene unitless pixel space + * @returns + */ +export function pick_native(scene, _x, _y, _w, _h) { + const { renderer, picking_target, px_per_unit } = scene.screen; + [_x, _y, _w, _h] = [_x, _y, _w, _h].map((x) => Math.ceil(x * px_per_unit)); + const [x, y, w, h] = [_x, _y, _w, _h]; // render the scene renderer.setRenderTarget(picking_target); set_picking_uniforms(scene, 1, true); render_scene(scene, true); renderer.setRenderTarget(null); // reset render target - const nbytes = w * h * 4; const pixel_bytes = new Uint8Array(nbytes); //read the pixel @@ -360,6 +527,8 @@ export function pick_native(scene, x, y, w, h) { h, // height pixel_bytes ); + + const picked_plots = {}; const picked_plots_array = []; @@ -385,8 +554,8 @@ export function pick_native(scene, x, y, w, h) { } export function pick_closest(scene, xy, range) { - const { picking_target } = scene.screen; - const { width, height } = picking_target; + const { renderer } = scene.screen; + const [ width, height ] = [renderer._width, renderer._height]; if (!(1.0 <= xy[0] <= width && 1.0 <= xy[1] <= height)) { return [null, 0]; @@ -396,6 +565,7 @@ export function pick_closest(scene, xy, range) { const y0 = Math.max(1, xy[1] - range); const x1 = Math.min(width, Math.floor(xy[0] + range)); const y1 = Math.min(height, Math.floor(xy[1] + range)); + const dx = x1 - x0; const dy = y1 - y0; const [plot_data, _] = pick_native(scene, x0, y0, dx, dy); @@ -420,8 +590,8 @@ export function pick_closest(scene, xy, range) { } export function pick_sorted(scene, xy, range) { - const { picking_target } = scene.screen; - const { width, height } = picking_target; + const { renderer } = scene.screen; + const [width, height] = [renderer._width, renderer._height]; if (!(1.0 <= xy[0] <= width && 1.0 <= xy[1] <= height)) { return null; @@ -434,11 +604,11 @@ export function pick_sorted(scene, xy, range) { const dx = x1 - x0; const dy = y1 - y0; + const [plot_data, selected] = pick_native(scene, x0, y0, dx, dy); if (selected.length == 0) { return null; } - const plot_matrix = plot_data.data; const distances = selected.map((x) => range ^ 2); const x = xy[0] + 1 - x0; @@ -447,6 +617,9 @@ export function pick_sorted(scene, xy, range) { for (let i = 1; i <= dx; i++) { for (let j = 1; j <= dx; j++) { const d = (x - i) ^ (2 + (y - j)) ^ 2; + if (plot_matrix.length <= pindex) { + continue; + } const [plot_uuid, index] = plot_matrix[pindex]; pindex = pindex + 1; const plot_index = selected.findIndex( @@ -455,6 +628,7 @@ export function pick_sorted(scene, xy, range) { if (plot_index >= 0 && d < distances[plot_index]) { distances[plot_index] = d; } + } } @@ -485,17 +659,17 @@ export function register_popup(popup, scene, plots_to_pick, callback) { } const { canvas } = scene.screen; canvas.addEventListener("mousedown", (event) => { - if (!popup.classList.contains("show")) { - popup.classList.add("show"); - } - popup.style.left = event.pageX + "px"; - popup.style.top = event.pageY + "px"; - const [x, y] = event2scene_pixel(scene, event); + const [x, y] = events2unitless(scene.screen, event); const [_, picks] = pick_native(scene, x, y, 1, 1); if (picks.length == 1) { const [plot, index] = picks[0]; if (plots_to_pick.has(plot.plot_uuid)) { const result = callback(plot, index); + if (!popup.classList.contains("show")) { + popup.classList.add("show"); + } + popup.style.left = event.pageX + "px"; + popup.style.top = event.pageY + "px"; if (typeof result === "string" || result instanceof String) { popup.innerText = result; } else { @@ -513,8 +687,6 @@ export function register_popup(popup, scene, plots_to_pick, callback) { }); } - - window.WGL = { deserialize_scene, threejs_module, @@ -528,7 +700,7 @@ window.WGL = { plot_cache, delete_scenes, create_scene, - event2scene_pixel, + events2unitless, on_next_insert, register_popup, render_scene, @@ -547,6 +719,6 @@ export { plot_cache, delete_scenes, create_scene, - event2scene_pixel, + events2unitless, on_next_insert, }; diff --git a/WGLMakie/test/runtests.jl b/WGLMakie/test/runtests.jl index 3d13c3cb842..22135765afd 100644 --- a/WGLMakie/test/runtests.jl +++ b/WGLMakie/test/runtests.jl @@ -1,13 +1,13 @@ using FileIO using WGLMakie, Makie, Test using WGLMakie.JSServe -import Electron using ReferenceTests +import Electron @testset "mimes" begin Makie.inline!(true) f, ax, pl = scatter(1:4) - @testset for mime in WGLMakie.WEB_MIMES + @testset for mime in Makie.WEB_MIMES @test showable(mime(), f) end # I guess we explicitely don't say we can show those since it's highly Inefficient compared to html @@ -31,20 +31,16 @@ excludes = Set([ "FEM mesh 2D", "FEM polygon 2D", # missing transparency & image - "Wireframe of a Surface", "Image on Surface Sphere", - "Surface with image", # Marker size seems wrong in some occasions: "Hbox", "UnicodeMarker", # Not sure, looks pretty similar to me! Maybe blend mode? "Test heatmap + image overlap", - "heatmaps & surface", - "OldAxis + Surface", + # "heatmaps & surface", # TODO: fix direct NaN -> nancolor conversion "Order Independent Transparency", "Record Video", "fast pixel marker", - "Animated surface and wireframe", "Array of Images Scatter", "Image Scatter different sizes", "scatter with stroke", @@ -55,11 +51,36 @@ excludes = Set([ ]) Makie.inline!(Makie.automatic) +edisplay = JSServe.use_electron_display(devtools=true) @testset "refimages" begin WGLMakie.activate!() - d = JSServe.use_electron_display() ReferenceTests.mark_broken_tests(excludes) recorded_files, recording_dir = @include_reference_tests "refimages.jl" missing_images, scores = ReferenceTests.record_comparison(recording_dir) ReferenceTests.test_comparison(scores; threshold = 0.032) end + +@testset "memory leaks" begin + Makie.CURRENT_FIGURE[] = nothing + app = App(nothing) + display(edisplay, app) + GC.gc(true); + # Somehow this may take a while to get emptied completely + JSServe.wait_for(() -> (GC.gc(true);isempty(run(edisplay.window, "Object.keys(WGL.plot_cache)")));timeout=20) + wgl_plots = run(edisplay.window, "Object.keys(WGL.scene_cache)") + @test isempty(wgl_plots) + + session = edisplay.browserdisplay.handler.session + session_size = Base.summarysize(session) / 10^6 + texture_atlas_size = Base.summarysize(WGLMakie.TEXTURE_ATLAS) / 10^6 + @show session_size texture_atlas_size + @test session_size / 10^6 < 6 + @test texture_atlas_size < 6 + s_keys = "Object.keys(JSServe.Sessions.SESSIONS)" + JSServe.wait_for(() -> (GC.gc(true); 2 == length(run(edisplay.window, s_keys))); timeout=30) + js_sessions = run(edisplay.window, "JSServe.Sessions.SESSIONS") + js_objects = run(edisplay.window, "JSServe.Sessions.GLOBAL_OBJECT_CACHE") + # @test Set([app.session[].id, app.session[].parent.id]) == keys(js_sessions) + # we used Retain for global_obs, so it should stay as long as root session is open + @test keys(js_objects) == Set([WGLMakie.TEXTURE_ATLAS.id]) +end diff --git a/docs/_css/franklin.css b/docs/_css/franklin.css index 61dd8dcd2ee..d389bd0568d 100644 --- a/docs/_css/franklin.css +++ b/docs/_css/franklin.css @@ -296,6 +296,7 @@ td { margin: auto; display: block; text-align: center; + object-fit: contain; } .franklin-content video { diff --git a/docs/buildutils/relative_links.jl b/docs/buildutils/relative_links.jl index dd42d4a4565..62d3ddaa3af 100644 --- a/docs/buildutils/relative_links.jl +++ b/docs/buildutils/relative_links.jl @@ -44,13 +44,39 @@ Replaces all absolute links in all html files in the __site folder with relative links. """ function make_links_relative() + invalid_relative_links = Dict{String,Pair{String,String}}() + + function check_local_link!(invalid_relative_links, file_location, link) + link_without_id = replace(link, r"#[a-zA-Z0-9!_\-\(\)]*$" => "") + absolute_link = if startswith(link, "/") + replace(link_without_id, r"^/+" => "") + else + normpath(joinpath(file_location, link_without_id)) + end + _, ext = splitext(absolute_link) + if !isempty(ext) + if !isfile(absolute_link) + push!(invalid_relative_links, absolute_link => (file_location => link)) + end + else + if !isfile(joinpath(absolute_link, "index.html")) + push!(invalid_relative_links, absolute_link => (file_location => link)) + end + end + end + + function is_local_link(link) + !startswith(link, "data:") && !startswith(link, r"https?") && !startswith(link, "#") + end + cd("__site") do for (root, _, files) in walkdir(".") path = join(splitpath(root)[2:end], "/") html_files = filter(endswith(".html"), files) for file in html_files - s = read(joinpath(root, file), String) + file_location = joinpath(root, file) + s = read(file_location, String) s = replace(s, '\0' => "\\0") html = parsehtml(s) @@ -59,15 +85,27 @@ function make_links_relative() if (e isa HTMLElement{:script} || e isa HTMLElement{:img} || e isa HTMLElement{:video}) && haskey(e.attributes, "src") link = e.attributes["src"] - e.attributes["src"] = make_relative(link, path) + if is_local_link(link) + relative_link = make_relative(link, path) + check_local_link!(invalid_relative_links, root, link) + e.attributes["src"] = relative_link + end elseif (e isa HTMLElement{:link} || e isa HTMLElement{:a}) && haskey(e.attributes, "href") link = e.attributes["href"] - e.attributes["href"] = make_relative(link, path) + if is_local_link(link) + relative_link = make_relative(link, path) + check_local_link!(invalid_relative_links, root, link) + e.attributes["href"] = relative_link + end elseif e isa HTMLElement{:form} && haskey(e.attributes, "action") link = e.attributes["action"] - e.attributes["action"] = make_relative(link, path) + if is_local_link(link) + relative_link = make_relative(link, path) + check_local_link!(invalid_relative_links, root, link) + e.attributes["action"] = relative_link + end end end @@ -77,4 +115,21 @@ function make_links_relative() end end end -end \ No newline at end of file + + # these two are generated only in deployment + delete!(invalid_relative_links, "siteinfo.js") + delete!(invalid_relative_links, "../versions.js") + + for (key, value) in invalid_relative_links + if startswith(key, "api/@ref") + @warn "Ignoring an invalid `@ref` link on the API page, this should be fixed: $key $value" + delete!(invalid_relative_links, key) + end + end + + if !isempty(invalid_relative_links) + error("Found invalid relative links: \n$(join(invalid_relative_links, "\n"))") + end + + return +end diff --git a/docs/colormap_generation.jl b/docs/colormap_generation.jl index 38519e22f4f..ef10b4fda3c 100644 --- a/docs/colormap_generation.jl +++ b/docs/colormap_generation.jl @@ -47,7 +47,7 @@ end function generate_colorschemes_table(ks) extra_dir = get(ENV, "CI", "false") == "true" ? "../" : "" - html = "" + html = "
" for header in ["NAME", "Categorical variant", "Continuous variant"] html *= "" end @@ -68,7 +68,7 @@ function generate_colorschemes_table(ks) # html *= colors_svg(cp7, 35, h) html *= "" end - html *= "
$header
" + html *= "" return html end diff --git a/docs/explanations/backends.md b/docs/explanations/backends.md index 2cbac21b304..f6b9ac7fc0d 100644 --- a/docs/explanations/backends.md +++ b/docs/explanations/backends.md @@ -7,10 +7,10 @@ There are four backends which concretely implement all abstract rendering capabi | Package | Description | | :------------------------------------------------------------- | :------------------------------------------------------------------------------------ | -| [`GLMakie.jl`](/documentation/backends/glmakie/) | GPU-powered, interactive 2D and 3D plotting in standalone `GLFW.jl` windows. | -| [`CairoMakie.jl`](/documentation/backends/cairomakie/) | `Cairo.jl` based, non-interactive 2D (and some 3D) backend for publication-quality vector graphics. | -| [`WGLMakie.jl`](/documentation/backends/wglmakie/) | WebGL-based interactive 2D and 3D plotting that runs within browsers. | -| [`RPRMakie.jl`](/documentation/backends/rprmakie/) | An experimental ray tracing backend. | +| [`GLMakie.jl`](/explanations/backends/glmakie/) | GPU-powered, interactive 2D and 3D plotting in standalone `GLFW.jl` windows. | +| [`CairoMakie.jl`](/explanations/backends/cairomakie/) | `Cairo.jl` based, non-interactive 2D (and some 3D) backend for publication-quality vector graphics. | +| [`WGLMakie.jl`](/explanations/backends/wglmakie/) | WebGL-based interactive 2D and 3D plotting that runs within browsers. | +| [`RPRMakie.jl`](/explanations/backends/rprmakie/) | An experimental ray tracing backend. | ### Activating Backends diff --git a/docs/explanations/backends/cairomakie.md b/docs/explanations/backends/cairomakie.md index d31748bcd57..2619d3f79c8 100644 --- a/docs/explanations/backends/cairomakie.md +++ b/docs/explanations/backends/cairomakie.md @@ -24,31 +24,6 @@ CairoMakie.activate!(type = "png") CairoMakie.activate!(type = "svg") ``` -#### Resolution Scaling - -When you save a CairoMakie figure, you can change the mapping from figure resolution to pixels (when saving to png) or points (when saving to svg or pdf). -This way you can easily scale the resulting image up or down without having to change any plot element sizes. - -Just specify `pt_per_unit` when saving vector formats and `px_per_unit` when saving pngs. -`px_per_unit` defaults to 1 and `pt_per_unit` defaults to 0.75. -When embedding svgs in websites, `1px` is equivalent to `0.75pt`. -This means that by default, saving a png or an svg results in an embedded image of the same apparent size. -If you require an exact size in `pt`, consider setting `pt_per_unit = 1`. - -Here's an example: - -```julia -fig = Figure(resolution = (800, 600)) - -save("normal.pdf", fig) # size = 600 x 450 pt -save("larger.pdf", fig, pt_per_unit = 2) # size = 1600 x 1200 pt -save("smaller.pdf", fig, pt_per_unit = 0.5) # size = 400 x 300 pt - -save("normal.png", fig) # size = 800 x 600 px -save("larger.png", fig, px_per_unit = 2) # size = 1600 x 1200 px -save("smaller.png", fig, px_per_unit = 0.5) # size = 400 x 300 px -``` - #### Z-Order CairoMakie as a 2D engine has no concept of z-clipping, therefore its 3D capabilities are quite limited. @@ -62,7 +37,7 @@ By setting the `rasterize` attribute of a plot, you can tell CairoMakie that thi Assuming that you have a `Plot` object `plt`, you can set `plt.rasterize = true` for simple rasterization, or you can set `plt.rasterize = scale::Int`, where `scale` represents the scaling factor for the image surface. -For example, if your Scene's resolution is `(800, 600)`, by setting `scale=2`, the rasterized image will have a resolution of `(1600, 1200)`. +For example, if your Scene's size is `(800, 600)`, by setting `scale=2`, the rasterized image embedded in the vector graphic will have a resolution of `(1600, 1200)`. You can deactivate this rasterization by setting `plt.rasterize = false`. diff --git a/docs/explanations/backends/glmakie.md b/docs/explanations/backends/glmakie.md index 353113bf44a..e3b9a722258 100644 --- a/docs/explanations/backends/glmakie.md +++ b/docs/explanations/backends/glmakie.md @@ -15,10 +15,53 @@ println("~~~") ``` \textoutput{docs} -#### Multiple Windows +#### Window Scaling + +The sizes of figures are given in display-independent "logical" dimensions, and the +GLMakie backend will scale the size of the displayed window on HiDPI/Retina displays +automatically. +For example, the default `size = (800, 600)` will be shown in a 1600 × 1200 window +on a HiDPI display which is configured with a 200% scaling factor. + +The scaling factor may be overridden by displaying the figure with a different +`scalefactor` value: +```julia +fig = Figure(size = (800, 600)) +# ... +display(fig, scalefactor = 1.5) +``` + +If the scale factor is not changed from its default automatic configuration, the window +will be resized to maintain its apparent size when moved across displays with different +scaling factors on Windows and OSX. +(Independent scaling factors are not supported by X11, and at this time the underlying +GLFW library is not compiled with Wayland support.) + +#### Resolution Scaling + +Related to the window scaling factor, the mapping from figure sizes and positions to pixels +can be scaled to achieve HiDPI/Retina resolution renderings. +The resolution scaling defaults to the same factor as the window scaling, but it may +be independently overridden with the `px_per_unit` argument when showing a figure: +```julia +fig = Figure(size = (800, 600)) +# ... +display(fig, px_per_unit = 2) +``` + +The resolution scale factor may also be changed when saving pngs: +```julia +save("hires.png", fig, px_per_unit = 2) # 1600 × 1200 px png +save("lores.png", fig, px_per_unit = 0.5) # 400 × 300 px png +``` +If a script may run in interactive environments where the native screen DPI can vary, +you may want to explicitly set `px_per_unit = 1` when saving figures to ensure consistency +of results. + -GLMakie has experimental support for displaying multiple independent figures (or scenes). To open a new window, use `display(GLMakie.Screen(), figure_or_scene)`. +#### Multiple Windows +GLMakie has experimental support for displaying multiple independent figures (or scenes). To open a new window, use `display(GLMakie.Screen(), figure_or_scene)`. To close all windows, use `GLMakie.closeall()`. ## Forcing Dedicated GPU Use In Linux @@ -43,7 +86,7 @@ You can find a demo on how to set that up in this [nextjournal article](https:// GLMakie's CI has no GPU, so you can also look at [.github/workflows/glmakie.yaml](https://github.com/MakieOrg/Makie.jl/blob/master/.github/workflows/glmakie.yaml) for a working setup. -If none of these work for you, take a look at the other [backends](/documentation/backends/), which all work without a GPU. +If none of these work for you, take a look at the other [backends](/explanations/backends/), which all work without a GPU. If you get an error pointing to [GLFW.jl](https://github.com/JuliaGL/GLFW.jl), please look into the existing [GLFW issues](https://github.com/JuliaGL/GLFW.jl/issues), and also google for those errors. This is then very likely something that needs fixing in the [glfw c library](https://github.com/glfw/glfw) or in the GPU drivers. @@ -73,3 +116,9 @@ Troubleshooting: 2.) WSL has some problems with passing through localhost, so one may need to use: `export DISPLAY=192.168.178.31:0`, with the local ip of the pcs network adapter, which runs VcXsrv 3.) One may need `mv /opt/julia-1.5.2/lib/julia/libstdc++.so.6 /opt/julia-1.5.2/lib/julia/libcpp.backup`, another form of [GLFW#198](https://github.com/JuliaGL/GLFW.jl/issues/198) + +## GLMakie does not show Figure or crashes on full screen mode on macOS + +MacOS gives a warning if a graphical user interface (GUI) is not started from an AppBundle and this exception can crash the Julia process that initiated the GUI. +This warning only occurs if macOS Settings->Desktop & Dock->Menu Bar->Automatically hide and show the menu bar is not set to Never. +Therefore make sure this setting is set to `Never` to enable the use of GLMakie on macOS. diff --git a/docs/explanations/backends/rprmakie.md b/docs/explanations/backends/rprmakie.md index bbd4f31903c..8120a42dcc2 100644 --- a/docs/explanations/backends/rprmakie.md +++ b/docs/explanations/backends/rprmakie.md @@ -94,7 +94,7 @@ using Colors: N0f8 radiance = 500 lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1))] -fig = Figure(; resolution=(1500, 700)); +fig = Figure(; size=(1500, 700)); ax = LScene(fig[1, 1]; show_axis=false, scenekw=(; lights=lights)) screen = RPRMakie.Screen(ax.scene; plugin=RPR.Northstar, iterations=400) @@ -178,7 +178,7 @@ function glow_material(data_normed) end RPRMakie.activate!(iterations=32, plugin=RPR.Northstar) -fig = Figure(; resolution=(2000, 800)) +fig = Figure(; size=(2000, 800)) radiance = 30000 lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), PointLight(Vec3f(0, 100, 100), RGBf(radiance, radiance, radiance))] @@ -232,7 +232,7 @@ radiance = 500 lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1))] -fig = Figure(; resolution=(1500, 1000)) +fig = Figure(; size=(1500, 1000)) ax = LScene(fig[1, 1]; show_axis=false, scenekw=(; lights=lights)) screen = RPRMakie.Screen(size(ax.scene); plugin=RPR.Tahoe) material = RPR.UberMaterial(screen.matsys) @@ -397,7 +397,7 @@ lights = [ EnvironmentLight(1.5, rotl90(load(assetpath("sunflowers_1k.hdr"))')), PointLight(Vec3f(50, 0, 200), RGBf(radiance, radiance, radiance*1.1)), ] -s = Scene(resolution=(500, 500), lights=lights) +s = Scene(size=(500, 500), lights=lights) cam3d!(s) c = cameracontrols(s) @@ -491,7 +491,7 @@ earth_img = load(Downloads.download("https://upload.wikimedia.org/wikipedia/comm # the actual plot ! RPRMakie.activate!(; iterations=100) scene = with_theme(theme_dark()) do - fig = Figure(; resolution=(1000, 1000)) + fig = Figure(; size=(1000, 1000)) radiance = 30 lights = [EnvironmentLight(0.5, load(RPR.assetpath("starmap_4k.tif"))), PointLight(Vec3f(1, 1, 3), RGBf(radiance, radiance, radiance))] diff --git a/docs/explanations/backends/wglmakie.md b/docs/explanations/backends/wglmakie.md index 39c05e215bd..ad521bea170 100644 --- a/docs/explanations/backends/wglmakie.md +++ b/docs/explanations/backends/wglmakie.md @@ -306,7 +306,7 @@ end ``` Or also specify a proxy URL, if you have a more complex proxy setup. For more advanced setups consult the `?Page` docs and `JSServe.configure_server!`. -In the [headless](/documentation/headless/index.html#wglmakie) documentation, you can also read more about setting up the JSServe server and port forwarding. +In the [headless](/explanations/headless/index.html#wglmakie) documentation, you can also read more about setting up the JSServe server and port forwarding. ## Styling @@ -378,7 +378,7 @@ end App() do session::Session # We can now use this wherever we want: - fig = Figure(resolution=(200, 200)) + fig = Figure(size=(200, 200)) contour(fig[1,1], rand(4,4)) card = GridCard( Slider(1:100), diff --git a/docs/explanations/cameras.md b/docs/explanations/cameras.md index f935c92c29c..54d87983041 100644 --- a/docs/explanations/cameras.md +++ b/docs/explanations/cameras.md @@ -1,13 +1,15 @@ # Cameras -A `Camera` is simply a viewport through which the Scene is visualized. `Makie` offers 2D and 3D projections, and 2D plots can be projected in 3D! +A `Camera` is simply a viewport through which the Scene is visualized. `Makie` offers 2D and 3D projections, and 2D plots can be projected in 3D! -To specify the camera you want to use for your Scene, you can set the `camera` attribute. Currently, we offer four types of camera: +To specify the camera you want to use for your Scene, you can set the `camera` attribute. Currently, we offer the following cameras/constructors \apilink{campixel!} +\apilink{cam_relative!} \apilink{cam2d!} -`cam3d!` -`cam3d_cad!` +\apilink{Camera3D} +\apilink{cam3d!} +\apilink{cam3d_cad!} which will mutate the camera of the Scene into the specified type. @@ -15,6 +17,10 @@ which will mutate the camera of the Scene into the specified type. The pixel camera (\apilink{campixel!(scene)}) projects the scene in pixel space, i.e. each integer step in the displayed data will correspond to one pixel. There are no controls for this camera. The clipping limits are set to `(-10_000, 10_000)`. +## Relative Camera + +The relative camera (\apilink{cam_relative!(scene)}) projects the scene into a 0..1 by 0..1 space. There are no controls for this camera. The clipping limits are set to `(-10_000, 10_000)`. + ## 2D Camera The 2D camera (\apilink{cam2d!(scene)}) uses an orthographic projection with a fixed rotation and aspect ratio. You can set the following attributes via keyword arguments in `cam2d!` or by accessing the camera struct `cam = cameracontrols(scene)`: @@ -30,6 +36,61 @@ Note that this camera is not used by `Axis`. It is used, by default, for 2D `LSc {{doc Camera3D}} +`cam3d!` and `cam3d_cad!` but create a `Camera3D` with some specific options. + +## Example - Visualizing the cameras view box + +```julia +using GeometryBasics, LinearAlgebra + +function frustum_snapshot(cam) + r = Rect3f(Point3f(-1, -1, -1), Vec3f(2, 2, 2)) + rect_ps = coordinates(r) .|> Point3f + insert!(rect_ps, 13, Point3f(1, -1, 1)) # fix bad line + + inv_pv = inv(cam.projectionview[]) + return map(rect_ps) do p + p = inv_pv * to_ndim(Point4f, p, 1) + return p[Vec(1,2,3)] / p[4] + end +end + + +ex = Point3f(1,0,0) +ey = Point3f(0,1,0) +ez = Point3f(0,0,1) + +fig = Figure() +scene = LScene(fig[1, 1]) +cc = Makie.Camera3D(scene.scene, projectiontype = Makie.Perspective) + +linesegments!(scene, Rect3f(Point3f(-1), Vec3f(2)), color = :black) +linesegments!(scene, + [-ex, ex, -ey, ey, -ez, ez], + color = [:red, :red, :green, :green, :blue, :blue] +) +center!(scene.scene) + +cam = scene.scene.camera +eyeposition = cc.eyeposition +lookat = cc.lookat +frustum = map(pv -> frustum_snapshot(cam), cam.projectionview) + +scene = LScene(fig[1, 2]) +_cc = Makie.Camera3D(scene.scene, projectiontype = Makie.Orthographic) +lines!(scene, frustum, color = :blue, linestyle = :dot) +scatter!(scene, eyeposition, color = :black) +scatter!(scene, lookat, color = :black) + +linesegments!(scene, + [-ex, ex, -ey, ey, -ez, ez], + color = [:red, :red, :green, :green, :blue, :blue] +) +linesegments!(scene, Rect3f(Point3f(-1), Vec3f(2)), color = :black) + +fig +``` + ## General Remarks To force a plot to be visualized in 3D, you can set the limits to have a nonzero \(z\)-axis interval, or ensure that a 3D camera type is used. diff --git a/docs/explanations/colors.md b/docs/explanations/colors.md index 77b39c0e6ea..995ee1da1a6 100644 --- a/docs/explanations/colors.md +++ b/docs/explanations/colors.md @@ -36,7 +36,7 @@ theme = Attributes( with_theme(theme) do - f = Figure(resolution = (800, 1200)) + f = Figure(size = (800, 1200)) ax = Axis(f[1, 1], xautolimitmargin = (0.2, 0.2), yautolimitmargin = (0.1, 0.1)) hidedecorations!(ax) hidespines!(ax) diff --git a/docs/explanations/events.md b/docs/explanations/events.md index d477c32bd88..99ff8e4fc22 100644 --- a/docs/explanations/events.md +++ b/docs/explanations/events.md @@ -376,6 +376,8 @@ Furthermore you can wrap any of the above in `Exclusively` to discard matches wh - `hotkey = Keyboard.left_control & Keyboard.a` is equivalent to `(Keyboard.left_control, Keyboard.a)` - `hotkey = (Keyboard.left_control | Keyboard.right_control) & Keyboard.a` allows either left or right control with a. +Note that the way we used `ispressed` above, the condition will be true for "press" and "repeat" events. You can further restrict to one or the other by checking `event.action`. If you wish to react to a "release" event, you will need to pass `event.key`/`event.button` as a third argument to `ispressed(fig, hotkey, event.key)`. This will tell `ispressed` to assume the key or button is pressed if it is part of the hotkey. + ## Interactive Widgets Makie has a couple of useful interactive widgets like sliders, buttons and menus, which you can learn about in the \myreflink{Blocks} section. diff --git a/docs/explanations/faq.md b/docs/explanations/faq.md index 261d1fcc68d..58bb69d0aef 100644 --- a/docs/explanations/faq.md +++ b/docs/explanations/faq.md @@ -118,13 +118,12 @@ f ### Columns or rows are shrunk to the size of Text or another element Columns or rows that have size `Auto(true)` try to determine the width or height of all -single-spanned elements that are placed in them, and if any elements report their -size the row or column will shrink to the maximum reported size. This is so smaller +single-spanned elements that are placed in them, and if any elements "tell" the layout their own height or width, +the row or column will shrink to the maximum reported size. This is so smaller elements with a known size take as little space as needed. But if there is other content in the row that should take more space, you can give the offending element -the attribute `tellheight = false` or `tellwidth = false`. This way, its own size -can be determined automatically, but -it doesn't report it to the row or column of the layout. Alternatively, you can set the size +the attribute `tellheight = false` or `tellwidth = false`. This way, its own height +or width doesn't influence the automatic sizing of the layout. Alternatively, you can set the size of that row or column to `Auto(false)` (or any other value than `Auto(true)`). \begin{examplefigure}{svg = true} @@ -135,8 +134,8 @@ f = Figure() Axis(f[1, 1], title = "Shrunk") Axis(f[2, 1], title = "Expanded") -Label(f[1, 2], "tellheight = true", tellheight = true) -Label(f[2, 2], "tellheight = false", tellheight = false) +Label(f[1, 2], "This Label has the setting\ntellheight = true\ntherefore the row it is in has\nadjusted to match its height.", tellheight = true) +Label(f[2, 2], "This Label has the setting\ntellheight = false.\nThe row it is in can use\nall the remaining space.", tellheight = false) f ``` @@ -163,7 +162,7 @@ using CairoMakie set_theme!(backgroundcolor = :gray90) -f = Figure(resolution = (800, 600)) +f = Figure(size = (800, 600)) for i in 1:3, j in 1:3 ax = Axis(f[i, j], title = "$i, $j", width = 100, height = 100) diff --git a/docs/explanations/figure.md b/docs/explanations/figure.md index 8117bcc4fbf..8d7e878191a 100644 --- a/docs/explanations/figure.md +++ b/docs/explanations/figure.md @@ -3,14 +3,14 @@ The `Figure` object contains a top-level `Scene` and a `GridLayout`, as well as a list of blocks that have been placed into it, like `Axis`, `Colorbar`, `Slider`, `Legend`, etc. -## Creating a `Figure` +## Creating a Figure You can create a figure explicitly with the `Figure()` function, and set attributes of the underlying scene. -The most important one of which is the `resolution`. +The most important one of which is the `size`. ```julia f = Figure() -f = Figure(resolution = (600, 400)) +f = Figure(size = (600, 400)) ``` A figure is also created implicitly when you use simple, non-mutating plotting commands like `plot()`, `scatter()`, `lines()`, etc. @@ -31,12 +31,12 @@ figure, = scatter(rand(100, 2)) You can pass arguments to the created figure in a dict-like object to the special `figure` keyword: ```julia -scatter(rand(100, 2), figure = (resolution = (600, 400),)) +scatter(rand(100, 2), figure = (size = (600, 400),)) ``` -## Placing blocks into a `Figure` +## Placing Blocks into a Figure -All blocks take their parent figure as the first argument, then you can place them in the figure layout via indexing syntax. +All Blocks take their parent figure as the first argument, then you can place them in the figure layout via indexing syntax. ```julia f = Figure() @@ -166,3 +166,53 @@ ax = f[1, 1] = Axis(f) contents(f[1, 1]) == [ax] content(f[1, 1]) == ax ``` + +## Figure size and units + +In Makie, figure size and attributes like line widths, font sizes, scatter marker extents, or layout column and row gaps are usually given as plain numbers, without an explicit unit attached. +What does it mean to have a `Figure` with `size = (600, 450)`, a line with `linewidth = 10` or a column gap of `30`? + +The first underlying idea is that, no matter what your final output format is, these numbers are _relative_. +You can expect a `linewidth = 10` to cover 1/60th of the width `600` of the `Figure` and a column gap of `30` to span 1/20th of the Figure. +This holds, no matter if you later export that `Figure` as an image made out of pixels, or as a vector graphic that doesn't have pixels at all. + +The second idea is that, given some `Figure`, we want to be able to export an image at arbitrary resolution, or a vector graphic at any size from it, as long as the relative sizes of all elements stay intact. +So we need to _translate_ our abstract sizes to real sizes when we render. +In Makie, this is done with two scaling factors: `px_per_unit` for images and `pt_per_unit` for vector graphics. + +A line with `linewidth = 10` will be 10 pixels wide if rendered to an image file with `px_per_unit = 1`. It will be 5 pixels wide if `px_per_unit = 0.5` and 20 pixels if `px_per_unit = 2`. A `Figure` with `size = (600, 450)` will have 600 x 450 pixels when exported with `px_per_unit = 1`, 300 x 225 with `px_per_unit = 0.5` and 1200 x 900 with `px_per_unit = 2`. + +It works exactly the same for vector graphics, just with a different target unit. A `pt` or point is a typographic unit that is defined as 1/72 of an inch, which comes out to about 0.353 mm. A line with `linewidth = 10` will be 10 points wide if rendered to an svg file with `pt_per_unit = 1`, it will be 5 points wide for `pt_per_unit = 0.5` and 20 points wide if `pt_per_unit = 2`. A `Figure` with `size = (600, 450)` will be 600 x 450 points in size when exported with `pt_per_unit = 1`, 300 x 225 with `pt_per_unit = 0.5` and 1200 x 900 with `pt_per_unit = 2`. + +### Defaults of `px_per_unit` and `pt_per_unit` + +What are the default values of `px_per_unit` and `pt_per_unit` in each Makie backend, and why are they set that way? + +Let us start with `pt_per_unit` because this value is only relevant for one backend, which is CairoMakie. +The default value in CairoMakie is `pt_per_unit = 0.75`. So if you `save(figure, "output.svg")` a `Figure` with `size = (600, 450)`, this comes out as a vector graphic that is 450 x 337.5 pt large. + +Why 0.75 and not simply 1? This has to do with web standards and device-independent pixels. Websites mix vector graphics and images, so they need some way to relate the sizes of both types to each other. In principle, a pixel in an image doesn't have a real-world width. But you don't want the images on your site to shrink relative to the other content when device pixels are small, or grow when device pixels are large. So web browsers don't directly map image pixels to device pixels. Instead, they use a concept called device-independent pixels. If you place an image with 600 x 450 pixels in a website, this image is interpreted by default to be 600 x 450 device-independent pixels wide. One device-independent pixel is defined to be 0.75 pt wide, that's where the factor 0.75 comes in. So an image with 600 x 450 device-independent pixels is the same apparent size as a vector graphic with size 450 x 337.5 pt. On high-resolution screens, browsers then simply render one device-independent pixel with multiple device pixels (for example 2x2 on an Apple Retina display) so that content stays at readable sizes and doesn't look tiny. + +For Makie, we decided that we want our abstract units to match device-independent pixels when used in web contexts, because that's very convenient and easy to predict for the end user. If you have a Jupyter or Pluto notebook, it's nice if a `Figure` comes out at the same apparent size, no matter if you're currently in CairoMakie's svg mode, or in the bitmap mode of any backend. Therefore, we annotate images with the original `Figure` size in device-independent pixels, so they are of the same apparent size, no matter what the `px_per_unit` value and therefore the effective pixel size is. And we give svg files the default scaling factor of 0.75 so that svgs always match images in apparent size. + +Now let us look at the default values for `px_per_unit`. In CairoMakie, the default is `px_per_unit = 2`. This means, a `Figure` with `size = (600, 450)` will be rendered as a 1200 x 900 pixel image. The reason it isn't `px_per_unit = 1` is that CairoMakie plots are often embedded in notebooks or websites, or looked at in image viewers or IDEs like VSCode. On websites, you don't know in advance what the pixel density of a reader's display is going to be. And in image viewers and IDEs, people like to zoom in to look at details. To cover these use cases by default, we decided `px_per_unit = 2` is a good compromise between sharp resolution and appropriate file size. Again, the _apparent_ size of output images in notebooks and websites (wherever the `MIME"text/html"` type is used) depends only on the `size`, because the output images are embedded with ` S.Density(x * randn(200) .+ 3x, color=:y), 1:5) +brain_mesh = S.Mesh(brain, colormap=:Spectral, color=[tri[1][2] for tri in brain for i in 1:3]) +volcano_contour = S.Contourf(volcano; colormap=:inferno) +cube_contour = S.Contour(cube, alpha=0.5) + +ax_densities = S.Axis(; plots=density_plots, yautolimitmargin = (0, 0.1)) +ax_volcano = S.Axis(; plots=[volcano_contour]) +ax_brain = S.Axis3(; plots=[brain_mesh], protrusions = (50, 20, 10, 0)) +ax_cube = S.Axis3(; plots=[cube_contour], protrusions = (50, 20, 10, 0)) + +spec_column_vector = S.GridLayout([ax_densities, ax_volcano, ax_brain]); +spec_matrix = S.GridLayout([ax_densities ax_volcano; ax_brain ax_cube]); +spec_row = S.GridLayout([spec_column_vector spec_matrix], colsizes = [Auto(), Auto(4)]) + +f, ax, pl = plot(S.GridLayout(spec_row); figure = (; fontsize = 10)) +``` +\end{examplefigure} + +## Advanced spec layouting + +If you need even more control, you can pass the position of each object in your layout to `S.GridLayout` directly. +These positions are specified as a tuple of `(rows, columns [, side])` where `side` is `Inside()` by default. +For `rows` and `columns` you can either use integers like `2`, ranges like `1:3` or the colon operator `:` which spans across all rows or columns that are specified for other elements. +Rows and columns start at `1` by default but you can also use numbers lower than `1` if necessary. + +\begin{examplefigure}{svg = true} +```julia +using CairoMakie +import Makie.SpecApi as S +Makie.inline!(true) # hide +CairoMakie.activate!() # hide + +plot( + S.GridLayout([ + (1, 1) => S.Axis(), + (1, 2) => S.Axis(), + (2, :) => S.Axis(), + (2, 2, Right()) => S.Box(), + (2, 2, Right()) => S.Label( + text = "Label", + rotation = pi/2, + padding = (10, 10, 10, 10) + ), + ]) +) +``` +\end{examplefigure} + +You can also use manual positions with nested `GridLayout`s. + +\begin{examplefigure}{} +```julia +using CairoMakie +import Makie.SpecApi as S +Makie.inline!(true) # hide +CairoMakie.activate!() # hide + +plot(S.GridLayout([ + (1, 1) => S.Axis(), + (1, 2) => S.Axis(), + (2, :) => S.GridLayout(fill(S.Axis(), 1, 3)), +])) +``` +\end{examplefigure} + +Here are all the keyword arguments that `S.GridLayout` accepts. + +```julia +S.GridLayout([...], + colsizes = [Auto(), Auto(), 300], + rowsizes = [Relative(0.4), Relative(0.6)], + colgaps, + rowgaps, + alignmode, + halign, + valign, + tellheight, + tellwidth, +) +``` + +## Using specs in `convert_arguments` + +!!! warning + It's not decided yet how to forward keyword arguments from `plots(...; kw...)` to `convert_arguments` for the SpecApi in a more convenient and performant way. Until then, you need to mark attributes you want to use in `convert_arguments` with `Makie.used_attributes`, but this will completely redraw the entire spec on change of any attribute. We also may require users to overload a different function in future versions. + +You can overload `convert_arguments` and return an array of `PlotSpecs` or a `GridLayoutSpec`. +The main difference between those is, that returning an array of `PlotSpecs` may be plotted like any recipe into axes, while overloads returning `GridLayoutSpec` may not. + +## `convert_arguments` for `GridLayoutSpec` + +In this example, we overload `convert_arguments` for a custom type to create facet grids easily. + +\begin{examplefigure}{svg = true} +```julia +using CairoMakie +import Makie.SpecApi as S +CairoMakie.activate!() # hide + +# Our custom type we want to write a conversion method for +struct PlotGrid + nplots::Tuple{Int,Int} +end + +# If we want to use the `color` attribute in the conversion, we have to +# mark it via `used_attributes` +Makie.used_attributes(::PlotGrid) = (:color,) + +# The conversion method creates a grid of `Axis` objects with `Lines` plot inside +# We restrict to Plot{plot}, so that only `plot(PlotGrid(...))` works, but not e.g. `scatter(PlotGrid(...))`. +function Makie.convert_arguments(::Type{Plot{plot}}, obj::PlotGrid; color=:black) + axes = [ + S.Axis(plots=[S.Lines(cumsum(randn(1000)); color=color)]) + for i in 1:obj.nplots[1], + j in 1:obj.nplots[2] + ] + return S.GridLayout(axes) +end + +# Now, when we plot `PlotGrid` we get a whole facet layout +plot(PlotGrid((3, 4))) +``` +\end{examplefigure} + +We can also plot into existing `Figure`s with our new `plot` method: + +\begin{examplefigure}{svg = true} +```julia +f = Figure() +plot(f[1, 1], PlotGrid((2, 2)); color=Cycled(1)) +plot(f[1, 2], PlotGrid((3, 2)); color=Cycled(2)) +f +``` +\end{examplefigure} + +## `convert_arguments` for `PlotSpec`s + +We can return a vector of `PlotSpec`s from `convert_arguments` which allows us to dynamically choose the plot objects we want to add given the input data. +While you could choose plot types based on input data with the old recipe API as well, this did not easily work for observable updates that changed these plot types in an existing figure. +For this, users had to do tedious manual bookkeeping which is now abstracted away. + +Note, that this method currently doesn't allow to forward keyword arguments from the `plot` command to `convert_arguments`, so we put the plot arguments into the `LineScatter` object in the following example: + +\begin{examplefigure}{} +```julia +using CairoMakie +import Makie.SpecApi as S +using Random +CairoMakie.activate!() # hide + +Random.seed!(123) + +# define a struct for `convert_arguments` +struct CustomMatrix + data::Matrix{Float32} + style::Symbol + kw::Dict{Symbol,Any} +end +CustomMatrix(data; style, kw...) = CustomMatrix(data, style, Dict{Symbol,Any}(kw)) + +function Makie.convert_arguments(::Type{<:AbstractPlot}, obj::CustomMatrix) + plots = PlotSpec[] + if obj.style === :heatmap + push!(plots, S.Heatmap(obj.data; obj.kw...)) + elseif obj.style === :contourf + push!(plots, S.Contourf(obj.data; obj.kw...)) + end + max_position = Tuple(argmax(obj.data)) + push!(plots, S.Scatter(max_position; markersize = 30, strokecolor = :white, color = :transparent, strokewidth = 4)) + return plots +end + +data = randn(30, 30) + +f = Figure() +ax = Axis(f[1, 1]) +# We can either plot into an existing Axis +plot!(ax, CustomMatrix(data, style = :heatmap, colormap = :Blues)) +# Or create a new one automatically as we are used to from the standard API +plot(f[1, 2], CustomMatrix(data, style = :contourf, colormap = :inferno)) +f +``` +\end{examplefigure} + + +## Interactive example + +The SpecApi is geared towards dashboards and interactively creating complex plots. +Here is an example using a `Slider` and a `Menu`, to visualize a fake simulation: + +~~~ + +~~~ +```julia:simulation +using GLMakie +import Makie.SpecApi as S +GLMakie.activate!() # hide + +struct MySimulation + plottype::Symbol + arguments::AbstractVector +end + +function Makie.convert_arguments(::Type{<:AbstractPlot}, sim::MySimulation) + return map(enumerate(sim.arguments)) do (i, data) + return PlotSpec(sim.plottype, data) + end +end +f = Figure() +s = Slider(f[1, 1], range=1:10) +m = Menu(f[1, 2], options=[:Scatter, :Lines, :BarPlot]) +sim = lift(s.value, m.selection) do n_plots, p + Random.seed!(123) + args = [cumsum(randn(100)) for i in 1:n_plots] + return MySimulation(p, args) +end +ax, pl = plot(f[2, :], sim) +tight_ticklabel_spacing!(ax) +# lower priority to make sure the call back is always called last +on(sim; priority=-1) do x + autolimits!(ax) +end + +record(f, "interactive_specapi.mp4", framerate=1) do io + pause = 0.1 + m.i_selected[] = 1 + for i in 1:4 + set_close_to!(s, i) + sleep(pause) + recordframe!(io) + end + m.i_selected[] = 2 + sleep(pause) + recordframe!(io) + for i in 5:7 + set_close_to!(s, i) + sleep(pause) + recordframe!(io) + end + m.i_selected[] = 3 + sleep(pause) + recordframe!(io) + for i in 7:10 + set_close_to!(s, i) + sleep(pause) + recordframe!(io) + end +end +``` +~~~ + +~~~ + +\video{interactive_specapi, autoplay = true} diff --git a/docs/explanations/theming.md b/docs/explanations/theming.md index 95cd152857a..b4204170118 100644 --- a/docs/explanations/theming.md +++ b/docs/explanations/theming.md @@ -279,7 +279,7 @@ CairoMakie.activate!() # hide set_theme!() # hide -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) Axis(f[1, 1], title = "Default cycle palette") diff --git a/docs/explanations/transparency.md b/docs/explanations/transparency.md index 6347938c2c7..03f49a05685 100644 --- a/docs/explanations/transparency.md +++ b/docs/explanations/transparency.md @@ -37,7 +37,7 @@ The color generated from two overlapping transparent objects depends on their or using CairoMakie CairoMakie.activate!() # hide -scene = Scene(resolution = (400, 275)) +scene = Scene(size = (400, 275)) campixel!(scene) scatter!( scene, [100, 200, 300], [100, 100, 100], @@ -66,8 +66,8 @@ CairoMakie.activate!() # hide fig = Figure() ax = LScene(fig[1, 1], show_axis=false) -p1 = mesh!(ax, Rect2f(-1.5, -1, 3, 3), color = (:red, 0.5), shading = false) -p2 = mesh!(ax, Rect2f(-1.5, -2, 3, 3), color = (:blue, 0.5), shading = false) +p1 = mesh!(ax, Rect2f(-1.5, -1, 3, 3), color = (:red, 0.5), shading = NoShading) +p2 = mesh!(ax, Rect2f(-1.5, -2, 3, 3), color = (:blue, 0.5), shading = NoShading) rotate!(p1, Vec3f(0, 1, 0), 0.1) rotate!(p2, Vec3f(0, 1, 0), -0.1) fig @@ -81,8 +81,8 @@ GLMakie.activate!() # hide fig = Figure() ax = LScene(fig[1, 1], show_axis=false) -p1 = mesh!(ax, Rect2f(-1.5, -1, 3, 3), color = (:red, 0.5), shading = false) -p2 = mesh!(ax, Rect2f(-1.5, -2, 3, 3), color = (:blue, 0.5), shading = false) +p1 = mesh!(ax, Rect2f(-1.5, -1, 3, 3), color = (:red, 0.5), shading = NoShading) +p2 = mesh!(ax, Rect2f(-1.5, -2, 3, 3), color = (:blue, 0.5), shading = NoShading) rotate!(p1, Vec3f(0, 1, 0), 0.1) rotate!(p2, Vec3f(0, 1, 0), -0.1) fig @@ -105,9 +105,9 @@ GLMakie.activate!() # hide fig = Figure() ax = LScene(fig[1, 1], show_axis=false) -p1 = mesh!(ax, Rect2f(-2, -2, 4, 4), color = (:red, 0.5), shading = false, transparency = true) -p2 = mesh!(ax, Rect2f(-2, -2, 4, 4), color = (:blue, 0.5), shading = false, transparency = true) -p3 = mesh!(ax, Rect2f(-2, -2, 4, 4), color = (:red, 0.5), shading = false, transparency = true) +p1 = mesh!(ax, Rect2f(-2, -2, 4, 4), color = (:red, 0.5), shading = NoShading, transparency = true) +p2 = mesh!(ax, Rect2f(-2, -2, 4, 4), color = (:blue, 0.5), shading = NoShading, transparency = true) +p3 = mesh!(ax, Rect2f(-2, -2, 4, 4), color = (:red, 0.5), shading = NoShading, transparency = true) for (dz, p) in zip((-1, 0, 1), (p1, p2, p3)) translate!(p, 0, 0, dz) end @@ -124,18 +124,18 @@ Being an approximate scheme OIT has some strengths and weaknesses. There are two using GLMakie GLMakie.activate!() # hide -fig = Figure(resolution = (800, 400)) +fig = Figure(size = (800, 400)) ax1 = LScene(fig[1, 1], show_axis=false) -p1 = mesh!(ax1, Rect2f(-2, -2, 4, 4), color = :red, shading = false, transparency = true) -p2 = mesh!(ax1, Rect2f(-2, -2, 4, 4), color = :blue, shading = false, transparency = true) -p3 = mesh!(ax1, Rect2f(-2, -2, 4, 4), color = :red, shading = false, transparency = true) +p1 = mesh!(ax1, Rect2f(-2, -2, 4, 4), color = :red, shading = NoShading, transparency = true) +p2 = mesh!(ax1, Rect2f(-2, -2, 4, 4), color = :blue, shading = NoShading, transparency = true) +p3 = mesh!(ax1, Rect2f(-2, -2, 4, 4), color = :red, shading = NoShading, transparency = true) for (dz, p) in zip((-1, 0, 1), (p1, p2, p3)) translate!(p, 0, 0, dz) end ax2 = LScene(fig[1, 2], show_axis=false) -p1 = mesh!(ax2, Rect2f(-1.5, -1, 3, 3), color = (:red, 0.5), shading = false, transparency=true) -p2 = mesh!(ax2, Rect2f(-1.5, -2, 3, 3), color = (:blue, 0.5), shading = false, transparency=true) +p1 = mesh!(ax2, Rect2f(-1.5, -1, 3, 3), color = (:red, 0.5), shading = NoShading, transparency=true) +p2 = mesh!(ax2, Rect2f(-1.5, -2, 3, 3), color = (:blue, 0.5), shading = NoShading, transparency=true) rotate!(p1, Vec3f(0, 1, 0), 0.1) rotate!(p2, Vec3f(0, 1, 0), -0.1) fig diff --git a/docs/index.md b/docs/index.md index 099a02316fd..f9ce442b2f7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -69,9 +69,9 @@ set_theme!() # hide ## Installation and Import -Add one or more of the Makie backend packages [`GLMakie.jl`](/documentation/backends/glmakie/) (OpenGL), [`CairoMakie.jl`](/documentation/backends/cairomakie/) (Cairo), or [`WGLMakie.jl`](/documentation/backends/wglmakie/) (WebGL), [`RPRMakie`](/documentation/backends/rprmakie/) (RadeonProRender) using Julia's inbuilt package manager. Each backend re-exports `Makie` so there's no need to install it separately. +Add one or more of the Makie backend packages [`GLMakie.jl`](/explanations/backends/glmakie/) (OpenGL), [`CairoMakie.jl`](/explanations/backends/cairomakie/) (Cairo), or [`WGLMakie.jl`](/explanations/backends/wglmakie/) (WebGL), [`RPRMakie`](/explanations/backends/rprmakie/) (RadeonProRender) using Julia's inbuilt package manager. Each backend re-exports `Makie` so there's no need to install it separately. -Makie is the core package, and the backends have no user facing functionality. They only render the final result. See the [Backends](@ref) page for more information! +Makie is the core package, and the backends have no user facing functionality. They only render the final result. See the \myreflink{Backends} page for more information! ```julia ]add GLMakie @@ -133,7 +133,7 @@ There are four backends, each of which has particular strengths. You can switch @@box-container @@box - ~~~~~~ + ~~~~~~ @@title GLMakie.jl@@ @@box-content @@description @@ -147,7 +147,7 @@ There are four backends, each of which has particular strengths. You can switch @@ @@box - ~~~~~~ + ~~~~~~ @@title CairoMakie.jl @@ @@box-content @@description @@ -161,7 +161,7 @@ There are four backends, each of which has particular strengths. You can switch @@ @@box - ~~~~~~ + ~~~~~~ @@title WGLMakie.jl @@ @@box-content @@description @@ -174,7 +174,7 @@ There are four backends, each of which has particular strengths. You can switch ~~~~~~ @@ @@box - ~~~~~~ + ~~~~~~ @@title RPRMakie.jl @@ @@box-content @@description diff --git a/docs/misc/banner/banner.jl b/docs/misc/banner/banner.jl index f2c9e9bb6b5..e67d6c9dd91 100644 --- a/docs/misc/banner/banner.jl +++ b/docs/misc/banner/banner.jl @@ -6,7 +6,7 @@ GLMakie.activate!() function copy_scene_settings(s) cc = cameracontrols(s) ( - px_area = s.px_area[], + viewport = s.viewport[], eyeposition = cc.eyeposition[], lookat = cc.lookat[], upvector = cc.upvector[], @@ -30,7 +30,7 @@ function apply_camera_settings!(s, settings) cc.pulser[] = settings.pulser Makie.update!(s) Makie.update!(s) - resize!(s, settings.px_area) + resize!(s, settings.viewport) return end diff --git a/docs/misc/mandelbrot/mandelbrot_video.jl b/docs/misc/mandelbrot/mandelbrot_video.jl index 978760a8ae0..b909d7aa75a 100644 --- a/docs/misc/mandelbrot/mandelbrot_video.jl +++ b/docs/misc/mandelbrot/mandelbrot_video.jl @@ -7,7 +7,7 @@ x = Observable(range(-2, 1, length = 400)) y = Observable(range(-1, 1, length = 300)) fig, ax, img = heatmap(x, y, mandelbrot, colormap = Reverse(:deep), - figure = (resolution = (400, 300),)) + figure = (size = (400, 300),)) hidedecorations!(ax) record(fig, "mandelbrot.mp4", 1:200) do frame diff --git a/docs/reference/blocks/axis.md b/docs/reference/blocks/axis.md index b59f91d4647..00f7a059cee 100644 --- a/docs/reference/blocks/axis.md +++ b/docs/reference/blocks/axis.md @@ -298,7 +298,7 @@ mutable struct MyInteraction end function Makie.process_interaction(interaction::MyInteraction, event::MouseEvent, axis) - if interaction.use_left_click && event.type === MouseEventTypes.leftclick + if interaction.allow_left_click && event.type === MouseEventTypes.leftclick println("Left click in correct mode") end if interaction.allow_right_click && event.type === MouseEventTypes.rightclick @@ -322,4 +322,4 @@ For those purposes, you can overload the methods `registration_setup!(parent, in ## Attributes -\attrdocs{Axis} \ No newline at end of file +\attrdocs{Axis} diff --git a/docs/reference/blocks/axis3.md b/docs/reference/blocks/axis3.md index d11ea8c5cd5..5b478575934 100644 --- a/docs/reference/blocks/axis3.md +++ b/docs/reference/blocks/axis3.md @@ -2,4 +2,4 @@ ## Attributes -\attrdocs{Axis3} \ No newline at end of file +\attrdocs{Axis3} diff --git a/docs/reference/blocks/box.md b/docs/reference/blocks/box.md index be3a2c41ac4..edbfbdee03a 100644 --- a/docs/reference/blocks/box.md +++ b/docs/reference/blocks/box.md @@ -1,25 +1,7 @@ - - # Box -A simple rectangle poly that is block. This can be useful to make boxes for -facet plots or when a rectangular placeholder is needed. - -\begin{examplefigure}{} -```julia -using CairoMakie -using ColorSchemes -CairoMakie.activate!() # hide - -fig = Figure() - -rects = fig[1:4, 1:6] = [ - Box(fig, color = c) - for c in get.(Ref(ColorSchemes.rainbow), (0:23) ./ 23)] - -fig -``` -\end{examplefigure} +A simple rectangle with optionally rounded corners. +This can be useful to visually group parts of a layout, or as a placeholder. ## Attributes diff --git a/docs/reference/blocks/gridlayout.md b/docs/reference/blocks/gridlayout.md index a0eeaba8519..2efebae2f19 100644 --- a/docs/reference/blocks/gridlayout.md +++ b/docs/reference/blocks/gridlayout.md @@ -158,7 +158,7 @@ grid with Inside alignment, and they are both effectively aligned exactly the sa ```julia using CairoMakie -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) Axis(f[1, 1], title = "No grid layout") Axis(f[2, 1], title = "No grid layout") @@ -206,7 +206,7 @@ side titles. ```julia using CairoMakie -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) Axis(f[1, 1]) for i in 1:3 @@ -233,7 +233,7 @@ This behavior has changed since GridLayoutBase.jl `v0.7.0`. ```julia using CairoMakie -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) for i in 1:3, j in 1:3 Axis(f[i, j]) diff --git a/docs/reference/blocks/intervalslider.md b/docs/reference/blocks/intervalslider.md index 9d69babf4f7..964c547fe71 100644 --- a/docs/reference/blocks/intervalslider.md +++ b/docs/reference/blocks/intervalslider.md @@ -51,7 +51,7 @@ colors = lift(rs_h.interval, rs_v.interval) do h_int, v_int end end -scatter!(points, color = colors, colormap = [:black, :orange], strokewidth = 0) +scatter!(points, color = colors, colormap = [:gray90, :dodgerblue], strokewidth = 0) f ``` diff --git a/docs/reference/blocks/label.md b/docs/reference/blocks/label.md index 3960ad602fe..fe8451a64c0 100644 --- a/docs/reference/blocks/label.md +++ b/docs/reference/blocks/label.md @@ -19,7 +19,7 @@ fig[1:2, 1:3] = [Axis(fig) for _ in 1:6] supertitle = Label(fig[0, :], "Six plots", fontsize = 30) -sideinfo = Label(fig[2:3, 0], "This text is vertical", rotation = pi/2) +sideinfo = Label(fig[1:2, 0], "This text is vertical", rotation = pi/2) fig ``` @@ -35,19 +35,21 @@ CairoMakie.activate!() # hide f = Figure() Label(f[1, 1], - "Left Justified\nMultiline\nLabel\nLineheight 0.9", + "Multiline label\nwith\njustification = :left\nand\nlineheight = 0.9", justification = :left, lineheight = 0.9 ) Label(f[1, 2], - "Center Justified\nMultiline\nLabel\nLineheight 1.1", + "Multiline label\nwith\njustification = :center\nand\nlineheight = 1.1", justification = :center, - lineheight = 1.1 + lineheight = 1.1, + color = :dodgerblue, ) Label(f[1, 3], - "Right Justified\nMultiline\nLabel\nLineheight 1.3", + "Multiline label\nwith\njustification = :right\nand\nlineheight = 1.3", justification = :right, - lineheight = 1.3 + lineheight = 1.3, + color = :firebrick ) f diff --git a/docs/reference/blocks/legend.md b/docs/reference/blocks/legend.md index 1d4e5b3ba0f..ac606452b54 100644 --- a/docs/reference/blocks/legend.md +++ b/docs/reference/blocks/legend.md @@ -279,15 +279,9 @@ using CairoMakie f = Figure() -Axis(f[1, 1]) - markersizes = [5, 10, 15, 20] colors = [:red, :green, :blue, :orange] -for ms in markersizes, color in colors - scatter!(randn(5, 2), markersize = ms, color = color) -end - group_size = [MarkerElement(marker = :circle, color = :black, strokecolor = :transparent, markersize = ms) for ms in markersizes] @@ -298,23 +292,28 @@ group_color = [PolyElement(color = color, strokecolor = :transparent) legends = [Legend(f, [group_size, group_color], [string.(markersizes), string.(colors)], - ["Size", "Color"]) for _ in 1:6] + ["Size", "Color"], tellheight = true) for _ in 1:4] -f[1, 2:4] = legends[1:3] -f[2:4, 2] = legends[4:6] +f[1, 1:2] = legends[1:2] +f[2, :] = legends[3] +f[3, :] = legends[4] -for l in legends[4:6] +for l in legends[3:4] l.orientation = :horizontal l.tellheight = true l.tellwidth = false end legends[2].titleposition = :left -legends[5].titleposition = :left +legends[4].titleposition = :left + +legends[1].nbanks = 2 +legends[4].nbanks = 2 -legends[3].nbanks = 2 -legends[5].nbanks = 2 -legends[6].nbanks = 2 +Label(f[1, 1, Left()], "titleposition = :top\norientation = :vertical\nnbanks = 2", font = :italic, padding = (0, 10, 0, 0)) +Label(f[1, 2, Right()], "titleposition = :left\norientation = :vertical\nnbanks = 1", font = :italic, padding = (10, 0, 0, 0)) +Label(f[2, 1:2, Top()], "titleposition = :top, orientation = :horizontal\nnbanks = 1", font = :italic) +Label(f[3, 1:2, Top()], "titleposition = :left, orientation = :horizontal\nnbanks = 2", font = :italic) f ``` @@ -322,4 +321,4 @@ f ## Attributes -\attrdocs{Legend} \ No newline at end of file +\attrdocs{Legend} diff --git a/docs/reference/blocks/lscene.md b/docs/reference/blocks/lscene.md index 01575f777bd..7a41cde93a4 100644 --- a/docs/reference/blocks/lscene.md +++ b/docs/reference/blocks/lscene.md @@ -9,7 +9,7 @@ You can plot into the `LScene` directly, though. You can pass keyword arguments to the underlying `Scene` object to the `scenekw` keyword. Currently, it can be necessary to pass a couple of attributes explicitly to make sure they are not inherited from the main scene. -To see what parameters are applicable, have a look at the [scene docs](/documentation/scenes) +To see what parameters are applicable, have a look at the [scene docs](/explanations/scenes) \begin{examplefigure}{} ```julia diff --git a/docs/reference/blocks/polaraxis.md b/docs/reference/blocks/polaraxis.md index 1ca6d919833..5c1e1877f2f 100644 --- a/docs/reference/blocks/polaraxis.md +++ b/docs/reference/blocks/polaraxis.md @@ -28,7 +28,7 @@ The order of a arguments can be changed with `ax.theta_as_x`. \begin{examplefigure}{svg = true} ```julia -f = Figure(resolution = (800, 400)) +f = Figure(size = (800, 400)) ax = PolarAxis(f[1, 1], title = "Theta as x") lineobject = lines!(ax, 0..2pi, sin, color = :red) @@ -48,7 +48,7 @@ For example, we can limit `thetalimits` to a smaller range to generate a circle \begin{examplefigure}{svg = true} ```julia -f = Figure(resolution = (600, 600)) +f = Figure(size = (600, 600)) ax = PolarAxis(f[1, 1], title = "Default") lines!(ax, range(0, 8pi, length=300), range(0, 10, length=300)) @@ -92,19 +92,18 @@ Not every plot type is compatible with the polar transform. For example `image` is not as it expects to be drawn on a rectangle. `heatmap` works to a degree in CairoMakie, but not GLMakie due to differences in the backend implementation. `surface` can be used as a replacement for `image` as it generates a triangle mesh. -However it also has a component in z-direction which will affect drawing order. -You can use `translate!(plot, 0, 0, z_shift)` to work around that. +To avoid having the `surface` plot extend in z-direction and thus messing with render order it is recommended to pass the color-data through the `color` attribute and use a matrix of zeros for the z-data. As a replacement for `heatmap` you can use `voronoiplot`, which generates cells of arbitrary shape around points given to it. Here you will generally need to set `rlims!(ax, rmax)` yourself. \begin{examplefigure}{svg = false} ```julia -f = Figure(resolution = (800, 500)) +f = Figure(size = (800, 500)) ax = PolarAxis(f[1, 1], title = "Surface") rs = 0:10 phis = range(0, 2pi, 37) cs = [r+cos(4phi) for phi in phis, r in rs] -p = surface!(ax, 0..2pi, 0..10, cs, shading = false, colormap = :coolwarm) +p = surface!(ax, 0..2pi, 0..10, zeros(size(cs)), color = cs, shading = NoShading, colormap = :coolwarm) ax.gridz[] = 100 tightlimits!(ax) # surface plots include padding by default Colorbar(f[2, 1], p, vertical = false, flipaxis = false) @@ -131,7 +130,7 @@ axis spine. You can manipulate it with the `spine...` attributes. \begin{examplefigure}{svg = true} ```julia -f = Figure(resolution = (800, 400)) +f = Figure(size = (800, 400)) ax1 = PolarAxis(f[1, 1], title = "No spine", spinevisible = false) scatterlines!(ax1, range(0, 1, length=100), range(0, 10pi, length=100), color = 1:100) @@ -150,7 +149,7 @@ attributes in much the same way. \begin{examplefigure}{svg = true} ```julia -f = Figure(resolution = (600, 600), backgroundcolor = :black) +f = Figure(size = (600, 600), backgroundcolor = :black) ax = PolarAxis( f[1, 1], backgroundcolor = :black, @@ -204,9 +203,9 @@ clipping via the `clip` attribute. For reference, the z values used by `PolarAxis` are `po.griddepth[] = 8999` for grid lines, 9000 for the clip polygons, 9001 for spines and 9002 for tick labels. -### Radial Distortion +### Radial Offset -If you have a plot with a large rmin and rmax over a wide range of angles you will end up with a narrow PolarAxis. +If you have a plot with rlimits far away from 0 you will end up with a lot of empty space in the PolarAxis. Consider for example: \begin{examplefigure}{svg = true} @@ -218,22 +217,68 @@ fig ``` \end{examplefigure} -In this case you may want to distort the r-direction to make more of your data visible. -This can be done by setting `ax.radial_distortion_threshold` to a value between 0 and 1. +In this case you may want to offset the r-direction to make more of your data visible. +This can be done by setting `ax.radius_at_origin` which translates radii as `r_out = r_in - radius_at_origin`. \begin{examplefigure}{svg = true} ```julia fig = Figure() -ax = PolarAxis(fig[1, 1], thetalimits = (0, pi), radial_distortion_threshold = 0.2, rlimits = (nothing, nothing)) +ax = PolarAxis(fig[1, 1], thetalimits = (0, pi), radius_at_origin = 8) lines!(ax, range(0, pi, length=100), 10 .+ sin.(0.3 .* (1:100))) fig ``` \end{examplefigure} -Internally PolarAxis will check `rmin/rmax` against the set threshold. -If that ratio exceed the threshold, the polar transform is adjusted to shift all radii by some `r0` such that `(rmin - r0) / rmax - r0) == ax.radial_distortion_threshold`. -In effect this will hold the inner cutout/clip radius at a fraction of the outer radius. -Note that at `ax.radial_distortion_threshold >= 1.0` (default) this will never distort your data. +This can also be used to show a plot with negative radii: + +\begin{examplefigure}{svg = true} +```julia +fig = Figure() +ax = PolarAxis(fig[1, 1], thetalimits = (0, pi), radius_at_origin = -12) +lines!(ax, range(0, pi, length=100), sin.(0.3 .* (1:100)) .- 10) +fig +``` +\end{examplefigure} + +Note however that translating radii results in some level of distortion: + +\begin{examplefigure}{svg = true} +```julia +phis = range(pi/4, 9pi/4, length=201) +rs = 1.0 ./ sin.(range(pi/4, 3pi/4, length=51)[1:end-1]) +rs = vcat(rs, rs, rs, rs, rs[1]) + +fig = Figure(size = (900, 300)) +ax1 = PolarAxis(fig[1, 1], radius_at_origin = -2, title = "radius_at_origin = -2") +ax2 = PolarAxis(fig[1, 2], radius_at_origin = 0, title = "radius_at_origin = 0") +ax3 = PolarAxis(fig[1, 3], radius_at_origin = 0.5, title = "radius_at_origin = 0.5") +for ax in (ax1, ax2, ax3) + lines!(ax, phis, rs .- 2, color = :red, linewidth = 4) + lines!(ax, phis, rs, color = :black, linewidth = 4) + lines!(ax, phis, rs .+ 0.5, color = :blue, linewidth = 4) +end +fig +``` +\end{examplefigure} + +### Radial clipping + +By default radii `r_out = r_in - radius_at_origin < 0` are clipped by the Polar transform. +This can be disabled by setting `ax.clip_r = false`. +With that setting `r_out < 0` will pass through the polar transform as is, resulting in a coordinate at $(|r_{out}|, \theta - pi)$. + +\begin{examplefigure}{svg = true} +```julia +fig = Figure(size = (600, 300)) +ax1 = PolarAxis(fig[1, 1], radius_at_origin = 0.0, clip_r = true, title = "clip_r = true") +ax2 = PolarAxis(fig[1, 2], radius_at_origin = 0.0, clip_r = false, title = "clip_r = false") +for ax in (ax1, ax2) + lines!(ax, 0..2pi, phi -> cos(2phi) - 0.5, color = :red, linewidth = 4) + lines!(ax, 0..2pi, phi -> sin(2phi), color = :black, linewidth = 4) +end +fig +``` +\end{examplefigure} ## Attributes diff --git a/docs/reference/plots/arrows.md b/docs/reference/plots/arrows.md index 041dceaa2e6..54cef0bb62b 100644 --- a/docs/reference/plots/arrows.md +++ b/docs/reference/plots/arrows.md @@ -42,7 +42,7 @@ using CairoMakie CairoMakie.activate!() # hide -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) Axis(f[1, 1], backgroundcolor = "black") xs = LinRange(0, 2pi, 20) @@ -103,7 +103,7 @@ using CairoMakie CairoMakie.activate!() # hide -fig = Figure(resolution = (800, 800)) +fig = Figure(size = (800, 800)) ax = Axis(fig[1, 1], backgroundcolor = "black") xs = LinRange(0, 2pi, 20) ys = LinRange(0, 3pi, 20) diff --git a/docs/reference/plots/contourf.md b/docs/reference/plots/contourf.md index bf8539a0b49..27e94fb28d7 100644 --- a/docs/reference/plots/contourf.md +++ b/docs/reference/plots/contourf.md @@ -85,7 +85,7 @@ CairoMakie.activate!() # hide volcano = readdlm(Makie.assetpath("volcano.csv"), ',', Float64) -f = Figure(resolution = (800, 400)) +f = Figure(size = (800, 400)) Axis(f[1, 1], title = "Relative mode, drop lowest 30%") contourf!(volcano, levels = 0.3:0.1:1, mode = :relative) diff --git a/docs/reference/plots/datashader.md b/docs/reference/plots/datashader.md index f8bde5f5414..7a113d9c679 100644 --- a/docs/reference/plots/datashader.md +++ b/docs/reference/plots/datashader.md @@ -21,7 +21,7 @@ fig, ax, ds = datashader(airports, # for documentation output we shouldn't calculate the image async, # since it won't wait for the render to finish and inline a blank image async = false, - figure = (; figurepadding=0, resolution=(360*3, 160*3)) + figure = (; figurepadding=0, size=(360*2, 160*2)) ) Colorbar(fig[1, 2], ds, label="Number of airports") hidedecorations!(ax); hidespines!(ax) @@ -60,7 +60,7 @@ cargs = [[0, 0, -1.3, -1.3, -1.8, -1.9], [0, 0, -1.7, 1.5, -0.5, 0.7] ] -fig = Figure(resolution=(1000, 1000)) +fig = Figure(size=(1000, 1000)) fig_grid = CartesianIndices((3, 4)) cmap = to_colormap(:BuPu_9) cmap[1] = RGBAf(1, 1, 1, 1) # make sure background is white @@ -120,7 +120,7 @@ end f, ax, dsplot = datashader(points; colormap=:fire, axis=(; type=Axis, autolimitaspect = 1), - figure=(;figure_padding=0, resolution=(1200, 600)) + figure=(;figure_padding=0, size=(1200, 600)) ) # make image fill the whole screen hidedecorations!(ax) @@ -158,7 +158,7 @@ points = Mmap.mmap(open(path, "r"), Vector{Point2f}); =# point_transform=reverse, axis=(; type=Axis, autolimitaspect = 1), - figure=(;figure_padding=0, resolution=(1200, 600)) + figure=(;figure_padding=0, size=(1200, 600)) ) hidedecorations!(ax) hidespines!(ax) @@ -206,7 +206,7 @@ fig We can also re-use the previous NYC example for a categorical plot: ```julia @time begin - f = Figure(figure_padding=0, resolution=(1200, 600)) + f = Figure(figure_padding=0, size=(1200, 600)) ax = Axis( f[1, 1], autolimitaspect=1, @@ -217,7 +217,7 @@ We can also re-use the previous NYC example for a categorical plot: hidedecorations!(ax) hidespines!(ax) # Create a styled legend - axislegend("Vendor ID"; titlecolor=:white, framecolor=:grey, polystrokewidth=2, polystrokecolor=(:white, 0.5), rowgap=10, bgcolor=:black, labelcolor=:white) + axislegend("Vendor ID"; titlecolor=:white, framecolor=:grey, polystrokewidth=2, polystrokecolor=(:white, 0.5), rowgap=10, backgroundcolor=:black, labelcolor=:white) display(f) end ``` diff --git a/docs/reference/plots/hexbin.md b/docs/reference/plots/hexbin.md index 2c2452d1ed0..afe042dd7ad 100644 --- a/docs/reference/plots/hexbin.md +++ b/docs/reference/plots/hexbin.md @@ -17,7 +17,7 @@ CairoMakie.activate!() # hide using Random Random.seed!(1234) -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) x = rand(300) y = rand(300) @@ -43,7 +43,7 @@ CairoMakie.activate!() # hide using Random Random.seed!(1234) -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) x = rand(300) y = rand(300) @@ -75,7 +75,7 @@ CairoMakie.activate!() # hide using Random Random.seed!(1234) -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) x = rand(300) y = rand(300) @@ -103,7 +103,7 @@ CairoMakie.activate!() # hide using Random Random.seed!(1234) -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) x = rand(300) y = rand(300) @@ -131,7 +131,7 @@ CairoMakie.activate!() # hide using Random Random.seed!(1234) -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) x = randn(100000) y = randn(100000) @@ -216,7 +216,7 @@ CairoMakie.activate!() # hide using Random Random.seed!(1234) -f = Figure(resolution = (800, 800)) +f = Figure(size = (800, 800)) x = 1:100 y = 1:100 diff --git a/docs/reference/plots/mesh.md b/docs/reference/plots/mesh.md index 9f7941e0cc4..3340ed595d7 100644 --- a/docs/reference/plots/mesh.md +++ b/docs/reference/plots/mesh.md @@ -24,7 +24,7 @@ faces = [ colors = [:red, :green, :blue, :orange] -scene = mesh(vertices, faces, color = colors, shading = false) +scene = mesh(vertices, faces, color = colors, shading = NoShading) ``` \end{examplefigure} @@ -40,8 +40,7 @@ brain = load(assetpath("brain.stl")) mesh( brain, color = [tri[1][2] for tri in brain for i in 1:3], - colormap = Reverse(:Spectral), - figure = (resolution = (1000, 1000),) + colormap = Reverse(:Spectral) ) ``` \end{examplefigure} diff --git a/docs/reference/plots/rainclouds.md b/docs/reference/plots/rainclouds.md index 13756770aa7..2a5f434bcee 100644 --- a/docs/reference/plots/rainclouds.md +++ b/docs/reference/plots/rainclouds.md @@ -142,7 +142,7 @@ With and Without Box Plot \begin{examplefigure}{} ```julia -fig = Figure(resolution = (800*2, 600*5)) +fig = Figure(size = (800*2, 600*5)) colors = [Makie.wong_colors(); Makie.wong_colors()] category_labels, data_array = mockup_categories_and_data_array(3) diff --git a/docs/reference/plots/scatter.md b/docs/reference/plots/scatter.md index 947e1c06c81..a507cf49a7b 100644 --- a/docs/reference/plots/scatter.md +++ b/docs/reference/plots/scatter.md @@ -243,7 +243,7 @@ scatter(1:5, #### Construction from svg path strings You can also create a bezier path from an [svg path specification string](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#path_commands). -You can automatically resize the path and flip the y- and x-axes (svgs usually have a coordinate system where y increases downwards) with the keywords `fit`, `yflip`, and `xflip`. +You can automatically resize the path and flip the y- and x-axes (svgs usually have a coordinate system where y increases downwards) with the keywords `fit`, `flipy`, and `flipx`. By default, the bounding box for the fitted path is a square of width 1 centered on zero. You can pass a different bounding `Rect` with the `bbox` keyword argument. By default, the aspect of the path is left intact, and if it's not matching the new bounding box, the path is centered so it fits inside. diff --git a/docs/reference/plots/surface.md b/docs/reference/plots/surface.md index ffaa7f07926..04a702c0e99 100644 --- a/docs/reference/plots/surface.md +++ b/docs/reference/plots/surface.md @@ -79,7 +79,7 @@ data = 0.1randn(d,d) + reshape( d, d ) -surface(data; shading=false, colormap = :deep) -surface(data; shading=false, colormap = :deep) +surface(data; shading = NoShading, colormap = :deep) +surface(data; shading = NoShading, colormap = :deep) ``` \end{examplefigure} diff --git a/docs/reference/plots/text.md b/docs/reference/plots/text.md index 582e4466f67..103c497002c 100644 --- a/docs/reference/plots/text.md +++ b/docs/reference/plots/text.md @@ -99,7 +99,7 @@ using CairoMakie CairoMakie.activate!() # hide -scene = Scene(camera = campixel!, resolution = (800, 800)) +scene = Scene(camera = campixel!, size = (800, 800)) points = [Point(x, y) .* 200 for x in 1:3 for y in 1:3] scatter!(scene, points, marker = :circle, markersize = 10px) diff --git a/docs/reference/plots/volume.md b/docs/reference/plots/volume.md index e0d67f28f40..e2c7ff51464 100644 --- a/docs/reference/plots/volume.md +++ b/docs/reference/plots/volume.md @@ -28,7 +28,7 @@ brain = niread(Makie.assetpath("brain.nii.gz")).raw mini, maxi = extrema(brain) normed = Float32.((brain .- mini) ./ (maxi - mini)) -fig = Figure(resolution=(1000, 450)) +fig = Figure(size=(1000, 450)) # Make a colormap, with the first value being transparent colormap = to_colormap(:plasma) colormap[1] = RGBAf(0,0,0,0) diff --git a/docs/reference/plots/voronoiplot.md b/docs/reference/plots/voronoiplot.md index cf6cbbfb36d..f957a2973bb 100644 --- a/docs/reference/plots/voronoiplot.md +++ b/docs/reference/plots/voronoiplot.md @@ -17,7 +17,7 @@ using Random Random.seed!(1234) -f = Figure(resolution=(1200, 450)) +f = Figure(size=(1200, 450)) ax = Axis(f[1, 1]) voronoiplot!(ax, rand(Point2f, 50)) diff --git a/docs/reference/plotting-2.7-billion-points.jl b/docs/reference/plotting-2.7-billion-points.jl index d4f72794dc9..c9ae61305c1 100644 --- a/docs/reference/plotting-2.7-billion-points.jl +++ b/docs/reference/plotting-2.7-billion-points.jl @@ -61,7 +61,7 @@ points = Mmap.mmap(open(path, "r"), Vector{Point2f}); =# point_func=reverse, axis=(; type=Axis, autolimitaspect=1), - figure=(; figure_padding=0, resolution=(1200, 600))) + figure=(; figure_padding=0, size=(1200, 600))) hidedecorations!(ax) hidespines!(ax) display(f) diff --git a/docs/reference/scene.md b/docs/reference/scene.md new file mode 100644 index 00000000000..fe7252d7605 --- /dev/null +++ b/docs/reference/scene.md @@ -0,0 +1,5 @@ +# Scene + +{{list_folder_with_images scene}} + +See also: [Scene page](https://docs.makie.org/stable/explanations/scenes/) \ No newline at end of file diff --git a/docs/reference/scene/SSAO.md b/docs/reference/scene/SSAO.md new file mode 100644 index 00000000000..653789af1a5 --- /dev/null +++ b/docs/reference/scene/SSAO.md @@ -0,0 +1,43 @@ +# SSAO + +GLMakie also implements [_screen-space ambient occlusion_](https://learnopengl.com/Advanced-Lighting/SSAO), which is an algorithm to more accurately simulate the scattering of light. There are a couple of controllable scene attributes nested within the `SSAO` toplevel attribute: + +- `radius` sets the range of SSAO. You may want to scale this up or + down depending on the limits of your coordinate system +- `bias` sets the minimum difference in depth required for a pixel to + be occluded. Increasing this will typically make the occlusion + effect stronger. +- `blur` sets the (pixel) range of the blur applied to the occlusion texture. + The texture contains a (random) pattern, which is washed out by + blurring. Small `blur` will be faster, sharper and more patterned. + Large `blur` will be slower and smoother. Typically `blur = 2` is + a good compromise. + +!!! note + The SSAO postprocessor is turned off by default to save on resources. To turn it on, set `GLMakie.activate!(ssao=true)`, close any existing GLMakie window and reopen it. + +## Example + +\begin{examplefigure}{} +```julia +using GLMakie +GLMakie.activate!(ssao=true) +GLMakie.closeall() # close any open screen + +fig = Figure() +ssao = Makie.SSAO(radius = 5.0, blur = 3) +ax = LScene(fig[1, 1], scenekw = (ssao=ssao,)) +# SSAO attributes are per scene +ax.scene.ssao.bias[] = 0.025 + +box = Rect3(Point3f(-0.5), Vec3f(1)) +positions = [Point3f(x, y, rand()) for x in -5:5 for y in -5:5] +meshscatter!(ax, positions, marker=box, markersize=1, color=:lightblue, ssao=true) +fig +``` +\end{examplefigure} + +```julia:disable-ssao +GLMakie.activate!(ssao=false) # hide +GLMakie.closeall() # hide +``` diff --git a/docs/reference/scene/lighting.md b/docs/reference/scene/lighting.md new file mode 100644 index 00000000000..91ee1447e32 --- /dev/null +++ b/docs/reference/scene/lighting.md @@ -0,0 +1,279 @@ +# Lighting + +The Lighting capabilities of Makie differ between backends and plot types. +They are implemented for mesh related plot types (`mesh`, `meshscatter`, `surface`), their derivatives (e.g. 3D `arrows`) and to some degree `volume` plots (and `contour3d`). +With respect to Backends: + +- GLMakie implements the baseline lighting model and will act as our default for this page. +- WGLMakie implements a simplified version of GLMakie's lighting. +- CairoMakie implements limited lighting due to its limited 3D capabilities +- RPRMakie implements parts of Makies lighting model but can also use more sophisticated methods from RadeonProRender. + +## Material Attributes + +In 3D rendering a material describes how an object reacts to light. +This can include the color of an object, how bright and sharp specular reflections are, how metallic it looks, how rough it is and more. +In Makie however the model is still fairly simple and limited. +Currently the following material attributes are available: +- `diffuse::Vec3f = Vec3f(1.0)`: controls how strong the diffuse reflections of an object are in the red, green and blue color channel. A diffuse reflection is one where incoming light is scattered in every direction. The strength of this reflection is based on the amount of light hitting the surface, which is proportional to `dot(light_direction, -normal)`. It generally makes up the main color of an object in light. +- `specular::Vec3f = Vec3f(0.4)`: controls the strength of specular reflection in the red, green and blue color channels. A specular reflection is a direct reflection of light, i.e. one where the incoming angle `dot(light_direction, -normal)` matches the outgoing angle `dot(camera_direction, -normal)`. It responsible for bright spots on objects. Note that this does not take the color of the object into account, as specular reflections typically match the light color. +- `shininess::Float32 = 32f0`: controls how sharp specular reflections are. Low shininess will allow a larger difference between incoming outgoing angle to take effect, creating a larger and smoother bright spot. High shininess will respectively reduce the size of the bright spot and increase its sharpness. This value must be positive. +- `backlight::Real = 0` controls how strongly light interacts with the backside of an object. Setting this to a value `> 0` can be helpful when visualizing a surface. (More precisely the light calculation is repeated with inverted normals and the result is mixed in with `backlight` as a prefactor.) + +!!! note + RPRMakie does not use these material attributes. + Instead it relies on RadeonProRender's material system, which is passed through the `material` attribute. + See the [RPRMakie page](https://docs.makie.org/stable/documentation/backends/rprmakie/) for examples. + + +## Lighting algorithm + +Lights are controlled through the `lights` vector in a `scene` and by the `shading` attribute in a plot. +Generally you will not need to set `shading` yourself, as it is derived based on the lights vector. +The possible options for `shading` are: +- `shading = NoShading` disables light calculations, resulting in the plain color of an object being shown. +- `shading = FastShading` enables a simplified lighting model which only allows for one `AmbientLight` and one `DirectionalLight`. +- `shading = MultiLightShading` is a GLMakie exclusive option which enables multiple light sources (as set in the `ScreenConfig`, default up to 64) as well as `PointLight` and `SpotLight`. + +!!! note + You can access the underlying scene of an `Axis3` with `ax.scene`. + +For reference all the lighting calculations (except ambient) in GLMakie, WGLMakie and to some extend CairoMakie end up using the [Blinn-Phong reflection model](https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_reflection_model) which boils down to + +```julia +function blinn_phong( + diffuse, specular, shininess, normal, object_color, + light_color, light_direction, camera_direction + ) + diffuse_coefficient = max(dot(light_direction, -normal), 0.0) + H = normalize(light_direction + camera_direction) + specular_coefficient = max(dot(H, -normal), 0.0)^shininess + return light_color * ( + diffuse * diffuse_coefficient * object_color + + specular * specular_coefficient + ) +end +``` + +The different light sources control the `light_direction` and may further adjust the result of this function. For example, `SpotLight` adds a factor which reduces light intensity outside its area. + + +## Types of Light + + +### AmbientLight + +{{doc AmbientLight}} + +\begin{examplefigure}{} +```julia +using CairoMakie +CairoMakie.activate!() # hide + +fig = Figure(size = (600, 600)) +ax11 = LScene(fig[1, 1], scenekw = (lights = [],)) +ax12 = LScene(fig[1, 2], scenekw = (lights = [AmbientLight(RGBf(0, 0, 0))],)) +ax21 = LScene(fig[2, 1], scenekw = (lights = [AmbientLight(RGBf(0.7, 0.7, 0.7))],)) +ax22 = LScene(fig[2, 2], scenekw = (lights = [AmbientLight(RGBf(0.8, 0.3, 0))],)) +for ax in (ax11, ax12, ax21, ax22) + mesh!(ax, Sphere(Point3f(0), 1f0), color = :white) +end +fig +``` +\end{examplefigure} + + +### DirectionalLight + +{{doc DirectionalLight}} + +\begin{examplefigure}{} +```julia +using GLMakie +GLMakie.activate!() # hide + +fig = Figure(size = (600, 600)) +ax11 = LScene(fig[1, 1], scenekw = (lights = [DirectionalLight(RGBf(0, 0, 0), Vec3f(-1, 0, 0))],)) +ax12 = LScene(fig[1, 2], scenekw = (lights = [DirectionalLight(RGBf(1, 1, 1), Vec3f(-1, 0, 0))],)) +lights = [ + DirectionalLight(RGBf(0, 0, 0.7), Vec3f(-1, -1, 0)), + DirectionalLight(RGBf(0.7, 0.2, 0), Vec3f(-1, 1, -1)), + DirectionalLight(RGBf(0.7, 0.7, 0.7), Vec3f(1, -1, -1)) +] +ax21 = LScene(fig[2, 1], scenekw = (lights = lights,)) +ax22 = LScene(fig[2, 2], scenekw = (lights = [DirectionalLight(RGBf(4, 2, 1), Vec3f(0, 0, -1))],)) +for ax in (ax11, ax12, ax21, ax22) + mesh!(ax, Sphere(Point3f(0), 1f0), color = :white) +end +fig +``` +\end{examplefigure} + +### PointLight + +{{doc PointLight}} + +\begin{examplefigure}{} +```julia +using GLMakie +GLMakie.activate!() # hide + +fig = Figure(size = (600, 600)) +ax = LScene(fig[1, 1], scenekw = (lights = [PointLight(RGBf(1, 1, 1), Point3f(0, 0, 0))],)) +ps = [Point3f(x, y, z) for x in (-1, 0, 1) for y in (-1, 0, 1) for z in (-1, 0, 1)] +meshscatter!(ax, ps, color = :white) +fig +``` +\end{examplefigure} + +\begin{examplefigure}{} +```julia +using GLMakie +GLMakie.activate!() # hide + +lights = [ + PointLight(RGBf(1, 1, 1), Point3f(0, 0, 5), 50), + PointLight(RGBf(2, 0, 0), Point3f(-3, -3, 2), 10), + PointLight(RGBf(0, 2, 0), Point3f(-3, 3, 2), 10), + PointLight(RGBf(0, 0, 2), Point3f( 3, 3, 2), 10), + PointLight(RGBf(2, 2, 0), Point3f( 3, -3, 2), 10), +] + +fig = Figure(size = (600, 600)) +ax = LScene(fig[1, 1], scenekw = (lights = lights,)) +ps = [Point3f(x, y, 0) for x in -5:5 for y in -5:5] +meshscatter!(ax, ps, color = :white, markersize = 0.75) +scatter!(ax, map(l -> l.position[], lights), color = map(l -> l.color[], lights), strokewidth = 1, strokecolor = :black) +fig +``` +\end{examplefigure} + +With a strong PointLight and Attenuation you can create different colors at different distances. + +\begin{examplefigure}{} +```julia +using GLMakie, GeometryBasics +GLMakie.activate!() # hide + +ps = [ + Point3f(cosd(phi) * cosd(theta), sind(phi) * cosd(theta), sind(theta)) + 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)) + +lights = [PointLight(RGBf(10, 4, 2), Point3f(0, 0, 0), 5)] + +fig = Figure(size = (600, 600), backgroundcolor = :black) +ax = LScene(fig[1, 1], scenekw = (lights = lights,), show_axis = false) +update_cam!(ax.scene, ax.scene.camera_controls, Rect3f(Point3f(-2), Vec3f(4))) +meshscatter!( + ax, [Point3f(0) for _ in 1:14], marker = marker_mesh, markersize = 0.1:0.2:3.0, + color = :white, backlight = 1, transparency = false) +fig +``` +\end{examplefigure} + + +### SpotLight + +{{doc SpotLight}} + +\begin{examplefigure}{} +```julia +using GLMakie +GLMakie.activate!() # hide +GLMakie.closeall() # hide + +lights = [ + SpotLight(RGBf(1, 0, 0), Point3f(-3, 0, 3), Vec3f(0, 0, -1), Vec2f(0.0, 0.3pi)), + SpotLight(RGBf(0, 1, 0), Point3f( 0, 3, 3), Vec3f(0, -0.5, -1), Vec2f(0.2pi, 0.25pi)), + SpotLight(RGBf(0, 0, 1), Point3f( 3, 0, 3), Vec3f(0, 0, -1), Vec2f(0.25pi, 0.25pi)), +] + +fig = Figure(size = (600, 600)) +ax = LScene(fig[1, 1], scenekw = (lights = lights,)) +ps = [Point3f(x, y, 0) for x in -5:5 for y in -5:5] +meshscatter!(ax, ps, color = :white, markersize = 0.75) +scatter!(ax, map(l -> l.position[], lights), color = map(l -> l.color[], lights), strokewidth = 1, strokecolor = :black) +fig +``` +\end{examplefigure} + +### RectLight + +{{doc RectLight}} + +\begin{examplefigure}{} +```julia +using FileIO, GeometryBasics, LinearAlgebra, GLMakie + +# Create mesh from RectLight parameters +function to_mesh(l::RectLight) + n = -normalize(cross(l.u1[], l.u2[])) + p = l.position[] - 0.5 * l.u1[] - 0.5 * l.u2[] + 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) +end + +fig = Figure(backgroundcolor = :black) + +# Prepare lights +lights = Makie.AbstractLight[ + AmbientLight(RGBf(0.1, 0.1, 0.1)), + RectLight(RGBf(0.9, 1, 0.8), Rect2f(-1.9, -1.9, 1.8, 1.8)), + RectLight(RGBf(0.9, 1, 0.8), Rect2f(-1.9, 0.1, 1.8, 1.8)), + RectLight(RGBf(0.9, 1, 0.8), Rect2f( 0.1, 0.1, 1.8, 1.8)), + RectLight(RGBf(0.9, 1, 0.8), Rect2f( 0.1, -1.9, 1.8, 1.8)), +] + +for l in lights + if l isa RectLight + angle = pi/4 + p = l.position[] + Makie.rotate!(l, Vec3f(0, 1, 0), angle) + + p = 3 * Vec3f(1+sin(angle), 0, cos(angle)) + + p[1] * normalize(l.u1[]) + + p[2] * normalize(l.u2[]) + translate!(l, p) + end +end + +# Set scene +scene = LScene( + fig[1, 1], show_axis = false, + scenekw=(lights = lights, backgroundcolor = :black, center = false), +) + +# floor +msh = mesh!(scene, Rect3f(Point3f(-10, -10, 0.01), Vec3f(20, 20, 0.02)), color = :white) +translate!(msh, 0, 0, -5) + +# Cat +cat_mesh = FileIO.load(Makie.assetpath("cat.obj")) +cat_texture = FileIO.load(Makie.assetpath("diffusemap.png")) +p2 = mesh!(scene, cat_mesh, color = cat_texture) +Makie.rotate!(p2, Vec3f(1,0,0), pi/2) +translate!(p2, -2, 2, -5) +scale!(p2, Vec3f(4)) + +# Window/light source markers +for l in lights + if l isa RectLight + mesh!(to_mesh(l), color = :white, backlight = 1) + end +end + +# place camera +update_cam!(scene.scene, Vec3f(1.5, -13, 2), Vec3f(1, -2, 0), Vec3f(0, 0, 1)) + +fig +``` +\end{examplefigure} + +### EnvironmentLight + +{{doc EnvironmentLight}} diff --git a/docs/reference/scene/matcap.md b/docs/reference/scene/matcap.md new file mode 100644 index 00000000000..a9b320dc29b --- /dev/null +++ b/docs/reference/scene/matcap.md @@ -0,0 +1,17 @@ +# Matcap + +A matcap (material capture) is a texture which is applied based on the normals of a given mesh. They typically include complex materials and lighting and offer a cheap way to apply those to any mesh. You may pass a matcap via the `matcap` attribute of a `mesh`, `meshscatter` or `surface` plot. Setting `shading = NoShading` is suggested. You can find a lot matcaps [here](https://github.com/nidorx/matcaps). + +## Example + +\begin{examplefigure}{} +```julia +using FileIO +using GLMakie +GLMakie.activate!() # hide +catmesh = FileIO.load(assetpath("cat.obj")) +gold = FileIO.load(download("https://raw.githubusercontent.com/nidorx/matcaps/master/1024/E6BF3C_5A4719_977726_FCFC82.png")) + +mesh(catmesh, matcap=gold, shading = NoShading) +``` +\end{examplefigure} \ No newline at end of file diff --git a/docs/tutorials/aspect-tutorial.md b/docs/tutorials/aspect-tutorial.md index b0e2f2c1a1a..9249e97daa1 100644 --- a/docs/tutorials/aspect-tutorial.md +++ b/docs/tutorials/aspect-tutorial.md @@ -16,7 +16,7 @@ CairoMakie.activate!() # hide set_theme!(backgroundcolor = :gray90) -f = Figure(resolution = (800, 500)) +f = Figure(size = (800, 500)) ax = Axis(f[1, 1], aspect = 1) Colorbar(f[1, 2]) f @@ -61,7 +61,7 @@ Let's try the example from above again, but this time we force the column of the \begin{examplefigure}{svg = true} ```julia -f = Figure(resolution = (800, 500)) +f = Figure(size = (800, 500)) ax = Axis(f[1, 1]) Colorbar(f[1, 2]) colsize!(f.layout, 1, Aspect(1, 1.0)) @@ -113,7 +113,7 @@ Let's return to our previous state with a square axis: \begin{examplefigure}{svg = true} ```julia # hide -f = Figure(resolution = (800, 500)) +f = Figure(size = (800, 500)) ax = Axis(f[1, 1]) Colorbar(f[1, 2]) colsize!(f.layout, 1, Aspect(1, 1.0)) diff --git a/docs/tutorials/basic-tutorial.md b/docs/tutorials/basic-tutorial.md index e3c5b65f302..c933635e7e9 100644 --- a/docs/tutorials/basic-tutorial.md +++ b/docs/tutorials/basic-tutorial.md @@ -55,12 +55,12 @@ f = Figure(backgroundcolor = :tomato) ``` \end{examplefigure} -Another common thing to do is to give a figure a different size or resolution. +Another common thing to do is to give a figure a different size. The default is 800x600, let's try halving the height: \begin{examplefigure}{svg = true} ```julia -f = Figure(backgroundcolor = :tomato, resolution = (800, 300)) +f = Figure(backgroundcolor = :tomato, size = (800, 300)) ``` \end{examplefigure} @@ -178,13 +178,13 @@ You can pass any kind of object with symbol-value pairs and these will be used a x = range(0, 10, length=100) y = sin.(x) scatter(x, y; - figure = (; resolution = (400, 400)), + figure = (; size = (400, 400)), axis = (; title = "Scatter plot", xlabel = "x label") ) ``` \end{examplefigure} -The `;` in `(; resolution = (400, 400))` is nothing special, it just clarifies that we want a one-element `NamedTuple` and not a variable called `resolution`. +The `;` in `(; size = (400, 400))` is nothing special, it just clarifies that we want a one-element `NamedTuple` and not a variable called `size`. It's good habit to include it but it's not needed for `NamedTuple`s with more than one entry. ## Argument conversions @@ -221,7 +221,7 @@ lines([Point(0, 0), Point(5, 10), Point(10, 5)]) The input arguments you can use with `lines` and `scatter` are mostly the same because they have the same conversion trait `PointBased`. Other plotting functions have different conversion traits, \myreflink{heatmap} for example expects two-dimensional grid data. -The respective trait is called `DiscreteSurface`. +The respective trait is called `CellGrid`. ## Layering multiple plots diff --git a/docs/tutorials/layout-tutorial.md b/docs/tutorials/layout-tutorial.md index c968e804212..c558940d868 100644 --- a/docs/tutorials/layout-tutorial.md +++ b/docs/tutorials/layout-tutorial.md @@ -17,7 +17,7 @@ using Makie.FileIO CairoMakie.activate!() # hide f = Figure(backgroundcolor = RGBf(0.98, 0.98, 0.98), - resolution = (1000, 700)) + size = (1000, 700)) ga = f[1, 1] = GridLayout() gb = f[2, 1] = GridLayout() gcd = f[1:2, 2] = GridLayout() @@ -163,14 +163,14 @@ We could say that A and B are in one column, and C and D are in one column. We c Ok, let's create the figure first with a gray backgroundcolor, and a predefined font: -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia using CairoMakie using FileIO CairoMakie.activate!() # hide f = Figure(backgroundcolor = RGBf(0.98, 0.98, 0.98), - resolution = (1000, 700)) + size = (1000, 700)) ``` \end{examplefigure} @@ -195,7 +195,7 @@ Now we can start placing objects into the figure. We start with A. There are three axes and a legend. We can place the axes first, link them appropriately, and plot the first data into them. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia axtop = Axis(ga[1, 1]) axmain = Axis(ga[2, 1], xlabel = "before", ylabel = "after") @@ -219,7 +219,7 @@ f There's a small gap between the density plots and their axes, which we can remove by fixing one side of the limits. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia ylims!(axtop, low = 0) xlims!(axright, low = 0) @@ -230,7 +230,7 @@ f We can also choose different x ticks with whole numbers. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia axmain.xticks = 0:3:9 axtop.xticks = 0:3:9 @@ -243,7 +243,7 @@ f We have set the `label` attribute in the scatter call so it's easier to construct the legend. We can just pass `axmain` as the second argument to `Legend`. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia leg = Legend(ga[1, 2], axmain) @@ -257,7 +257,7 @@ There are a couple things we want to change. There are unnecessary decorations f Also, the top axis does not have the same height as the legend. That's because a legend is usually used on the right of an `Axis` and is therefore preset with `tellheight = false`. We set this attribute to `true` so the row in which the legend sits can contract to its known size. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia hidedecorations!(axtop, grid = false) hidedecorations!(axright, grid = false) @@ -269,7 +269,7 @@ f The axes are still a bit too far apart, so we reduce column and row gaps. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia colgap!(ga, 10) rowgap!(ga, 10) @@ -280,7 +280,7 @@ f We can make a title by placing a label across the top two elements. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia Label(ga[1, 1:2, Top()], "Stimulus ratings", valign = :bottom, font = :bold, @@ -294,7 +294,7 @@ f Let's move to B. We have two axes stacked on top of each other, and a colorbar alongside them. This time, we create the axes by just plotting into the right `GridLayout` slots. This can be more convenient than creating an `Axis` first. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia xs = LinRange(0.5, 6, 50) ys = LinRange(0.5, 6, 50) @@ -320,7 +320,7 @@ f Now we need a colorbar. Because we haven't set specific edges for the two contour plots, just how many levels there are, we can make a colorbar using one of the contour plots and then label the bins in there from one to six. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia cb = Colorbar(gb[1:2, 2], hm, label = "cell group") low, high = extrema(data1) @@ -339,7 +339,7 @@ This can later cause a bit of a gap between the density plot and content on the In order to improve this, we can pull the colorbar labels into its layout cell using the `Mixed` alignmode. The keyword `right = 0` means that the right side of the colorbar should pull its protrusion content inward with an additional padding of `0`. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia cb.alignmode = Mixed(right = 0) @@ -349,7 +349,7 @@ f As in A, the axes are a bit too far apart. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia colgap!(gb, 10) rowgap!(gb, 10) @@ -362,7 +362,7 @@ f Now, we move on to panel C. This is just an `Axis3` with a colorbar on the side. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia brain = load(assetpath("brain.stl")) @@ -387,7 +387,7 @@ You can set the attribute `ax3.protrusions` to a tuple of four values (left, rig We move on to Panel D, which has a grid of 3x2 axes. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia axs = [Axis(gd[row, col]) for row in 1:3, col in 1:2] hidedecorations!.(axs, grid = false, label = false) @@ -410,7 +410,7 @@ f We can make a little title for the six axes by placing a `Label` in the top protrusion of row 1 and across both columns. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia Label(gd[1, :, Top()], "EEG traces", valign = :bottom, font = :bold, @@ -422,7 +422,7 @@ f Again, we bring the subplots closer together by reducing gap sizes. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia rowgap!(gd, 10) colgap!(gd, 10) @@ -435,7 +435,7 @@ f Now, we add three boxes on the side with labels in them. In this case, we just place them in another column to the right. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia for (i, label) in enumerate(["sleep", "awake", "test"]) Box(gd[i, 3], color = :gray90) @@ -448,7 +448,7 @@ f The boxes are in the correct positions, but we still need to remove the column gap. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia colgap!(gd, 2, 0) @@ -463,7 +463,7 @@ We want to scale the axes so that they both have the same zoom level. We can do this by setting the column widths to `Auto(x)` where x is a number proportional to the number of data points of the axis. This way, both will have the same relative scaling. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia n_day_1 = length(0:0.1:6pi) n_day_2 = length(0:0.1:10pi) @@ -480,7 +480,7 @@ f Now, we can add the subplot labels. We already have our four `GridLayout` objects that enclose each panel's content, so the easiest way is to create `Label`s in the top left protrusion of these layouts. That will leave all other alignments intact, because we're not creating any new columns or rows. The labels belong to the gaps between the layouts instead. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia for (label, layout) in zip(["A", "B", "C", "D"], [ga, gb, gc, gd]) Label(layout[1, 1, TopLeft()], label, @@ -502,7 +502,7 @@ This gives the column a smaller weight when distributing widths between all colu You can also use `Relative` or `Fixed` but they are not as flexible if you add more things later, so I prefer using `Auto`. -\begin{examplefigure}{px_per_unit = 1.5} +\begin{examplefigure}{} ```julia colsize!(f.layout, 1, Auto(0.5)) @@ -514,7 +514,7 @@ The EEG traces are currently as high as the brain axis, let's increase the size And that is the final result: -\begin{examplefigure}{name = "final_result", px_per_unit = 1.5} +\begin{examplefigure}{name = "final_result"} ```julia rowsize!(gcd, 1, Auto(1.5)) diff --git a/docs/tutorials/scenes.md b/docs/tutorials/scenes.md index 2b5538f1094..99d4ff306f6 100644 --- a/docs/tutorials/scenes.md +++ b/docs/tutorials/scenes.md @@ -14,7 +14,7 @@ scene = Scene(; # set_theme!(lightposition=:eyeposition, ambient=RGBf(0.5, 0.5, 0.5))` lights = Makie.automatic, backgroundcolor = :gray, - resolution = (500, 500); + size = (500, 500); # gets filled in with the currently set global theme theme_kw... ) @@ -36,7 +36,7 @@ With scenes, one can create subwindows. The window extends are given by a `Rect{ using GLMakie, Makie GLMakie.activate!() scene = Scene(backgroundcolor=:gray) -subwindow = Scene(scene, px_area=Rect(100, 100, 200, 200), clear=true, backgroundcolor=:white) +subwindow = Scene(scene, viewport=Rect(100, 100, 200, 200), clear=true, backgroundcolor=:white) scene ``` \end{examplefigure} @@ -128,7 +128,7 @@ We can use those events to e.g. move the subwindow. If you execute the below in ```julia on(scene.events.mouseposition) do mousepos if ispressed(subwindow, Mouse.left & Keyboard.left_control) - subwindow.px_area[] = Rect(Int.(mousepos)..., 200, 200) + subwindow.viewport[] = Rect(Int.(mousepos)..., 200, 200) end end ``` @@ -249,12 +249,14 @@ The scene graph can be used to create rigid transformations, like for a robot ar ```julia GLMakie.activate!() # hide parent = Scene() -cam3d!(parent) +cam3d!(parent; clipping_mode = :static) # One can set the camera lookat and eyeposition, by getting the camera controls and using `update_cam!` camc = cameracontrols(parent) update_cam!(parent, camc, Vec3f(0, 8, 0), Vec3f(4.0, 0, 0)) - +# One may need to adjust the +# near and far clip plane when adjusting the camera manually +camc.far[] = 100f0 s1 = Scene(parent, camera=parent.camera) mesh!(s1, Rect3f(Vec3f(0, -0.1, -0.1), Vec3f(5, 0.2, 0.2))) s2 = Scene(s1, camera=parent.camera) @@ -368,7 +370,7 @@ lights = [ EnvironmentLight(1.5, rotl90(load(assetpath("sunflowers_1k.hdr"))')), PointLight(Vec3f(50, 0, 200), RGBf(radiance, radiance, radiance*1.1)), ] -s = Scene(resolution=(500, 500), lights=lights) +s = Scene(size=(500, 500), lights=lights) cam3d!(s) c = cameracontrols(s) c.near[] = 5 diff --git a/docs/utils.jl b/docs/utils.jl index 50b3d35f39b..e07b38d6eab 100644 --- a/docs/utils.jl +++ b/docs/utils.jl @@ -20,7 +20,10 @@ end using Makie function html_docstring(fname) - doc = Base.doc(getfield(Makie, Symbol(fname))) + fname == :SpecApi && return "" + obj = getfield(Makie, Symbol(fname)) + obj isa Module && return "" # modules usually don't have docstrings and have READMEs copied in otherwise, which is messy + doc = Base.doc(obj) body = Markdown.html(doc) # body = fd2html(replace(txt, raw"$" => raw"\$"), internal = true) @@ -66,7 +69,8 @@ function env_examplefigure(com, _) kwargs = eval(Meta.parse("Dict(pairs((;" * Franklin.content(com.braces[1]) * ")))")) - name = pop!(kwargs, :name, "example_" * string(hash(content))) + hash_8 = repr(hash(content))[3:10] + name = pop!(kwargs, :name, "example_" * hash_8) svg = pop!(kwargs, :svg, false) rest_kwargs_str = join(("$key = $(repr(val))" for (key, val) in kwargs), ", ") @@ -81,19 +85,23 @@ function env_examplefigure(com, _) push!(pngsvec, pngfile) str = """ - ```julia:example_figure - using Makie.LaTeXStrings: @L_str # hide - __result = begin # hide + ```julia:$name + using Makie.LaTeXStrings: @L_str # hide + __result = begin # hide $code - end # hide - save(joinpath(@OUTPUT, "$pngfile"), __result; $rest_kwargs_str) # hide - $(svg ? "save(joinpath(@OUTPUT, \"$svgfile\"), __result; $rest_kwargs_str) # hide" : "") + end # hide + sz = size(Makie.parent_scene(__result)) # hide + open(joinpath(@OUTPUT, "$(name)_size.txt"), "w") do io # hide + print(io, sz[1], " ", sz[2]) # hide + end # hide + save(joinpath(@OUTPUT, "$pngfile"), __result; px_per_unit = 2, pt_per_unit = 0.75, $rest_kwargs_str) # hide + $(svg ? "save(joinpath(@OUTPUT, \"$svgfile\"), __result; px_per_unit = 2, pt_per_unit = 0.75, $rest_kwargs_str)" : "") # hide nothing # hide ``` ~~~ ~~~ - \\fig{$name.$(svg ? "svg" : "png")} + {{examplefig $name.$(svg ? "svg" : "png")}} ~~~ ~~~ @@ -101,6 +109,33 @@ function env_examplefigure(com, _) return str end +# this function inserts an image generated within `env_examplefigure` and annotates +# the img tag with the size of the source figure, which it reads from a text file that +# `env_examplefigure` writes into the output folder when running the code. +# this is a bit convoluted but we don't have direct access to Franklin's code running mechanism. +# Maybe in the future, it wouldn't be too hard to just run the code ourselves from within `env_examplefigure` +# and then we could use the resulting size directly +@delay function hfun_examplefig(params) + if length(params) != 1 + error("\\examplefig needs exactly one argument, got $params") + end + filename = only(params) + name, ext = splitext(filename) + + file_location = locvar("fd_rpath") + pathparts = split(file_location, r"\\|/") + relative_site_path, _ = splitext(joinpath(pathparts)) + relative_asset_path = joinpath("assets", relative_site_path, "code", "output") + asset_path = joinpath(Franklin.path(:site), relative_asset_path) + size_file = joinpath(asset_path, name * "_size.txt") + width, height = parse.(Int, split(read(size_file, String))) + relative_figure_path = joinpath(relative_asset_path, filename) + + """ + + """ +end + # \video{name [, autoplay = false, loop = true, controls = true]} function lx_video(lxc, _) params = split(Franklin.stent(lxc.braces[1]), ",", limit = 2) diff --git a/metrics/ttfp/benchmark-ttfp.jl b/metrics/ttfp/benchmark-ttfp.jl index 9c422f774aa..74a76215495 100644 --- a/metrics/ttfp/benchmark-ttfp.jl +++ b/metrics/ttfp/benchmark-ttfp.jl @@ -8,24 +8,15 @@ macro ctime(x) end t_using = @ctime @eval using $Package -function get_colorbuffer(fig) - # We need to handle old versions of Makie - if isdefined(Makie, :CURRENT_BACKEND) # new version after display refactor - return Makie.colorbuffer(fig) # easy :) - else - Makie.inline!(false) - screen = display(fig; visible=false) - return Makie.colorbuffer(screen) - end -end - if Package === :WGLMakie import Electron WGLMakie.JSServe.use_electron_display() end +set_theme!(size=(800, 600)) + create_time = @ctime fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true) -display_time = @ctime get_colorbuffer(fig) +display_time = @ctime colorbuffer(fig; px_per_unit=1) using BenchmarkTools using BenchmarkTools.JSON @@ -39,7 +30,7 @@ old = isfile(result) ? JSON.parse(read(result, String)) : [[], [], [], [], []] push!.(old[1:3], [t_using, create_time, display_time]) b1 = @benchmark fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true) -b2 = @benchmark get_colorbuffer(fig) setup=(fig=scatter(1:4)) +b2 = @benchmark colorbuffer(fig; px_per_unit=1) using Statistics diff --git a/metrics/ttfp/run-benchmark.jl b/metrics/ttfp/run-benchmark.jl index 46c11b19319..f7560f36246 100644 --- a/metrics/ttfp/run-benchmark.jl +++ b/metrics/ttfp/run-benchmark.jl @@ -34,7 +34,7 @@ create_time = @ctime fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=2 display_time = @ctime Makie.colorbuffer(display(fig)) # Runtime create_time = @benchmark fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true) -display_time = @benchmark Makie.colorbuffer(display(fig)) +display_time = @benchmark Makie.colorbuffer(fig) ``` | | using | create | display | create | display | @@ -87,27 +87,28 @@ function analyze(pr, master) std_p = (std(pr) + std(master)) / 2 m_pr = mean(pr) m_m = mean(master) - mean_diff = mean(m_pr) - mean(m_m) - percent = (1 - (m_m / m_pr)) * 100 + mean_diff = m_pr - m_m + speedup = m_m / m_pr p = pvalue(tt) mean_diff_str = string(round(mean_diff; digits=2), unit) - + percent_change = (speedup - 1) * 100 result = if p < 0.05 if abs(d) > 0.2 - indicator = abs(percent) < 5 ? ["faster ✓", "slower X"] : ["**faster**✅", "**slower**❌"] + indicator = abs(percent_change) < 5 ? ["faster ✓", "slower X"] : ["**faster**✅", "**slower**❌"] indicator[d < 0 ? 1 : 2] else "*invariant*" end else - if abs(percent) < 5 + if abs(percent_change) < 5 "*invariant*" else "*noisy*🤷‍♀️" end end - return @sprintf("%s%.2f%s, %s %s (%.2fd, %.2fp, %.2fstd)", percent > 0 ? "+" : "-", abs(percent), "%", mean_diff_str, result, d, p, std_p) + return @sprintf("%.2fx %s, %s (%.2fd, %.2fp, %.2fstd)", speedup, result, mean_diff_str, d, p, + std_p) end function summarize_stats(timings) @@ -153,6 +154,9 @@ function update_comment(old_comment, package_name, (pr_bench, master_bench, eval for (i, value) in enumerate(evaluation) rows[idx + 2][i + 1] = [value] end + open("benchmark.md", "w") do io + return show(io, md) + end return sprint(show, md) end @@ -171,9 +175,12 @@ function make_or_edit_comment(ctx, pr, package_name, benchmarks) end end + +using Random + function run_benchmarks(projects; n=n_samples) benchmark_file = joinpath(@__DIR__, "benchmark-ttfp.jl") - for project in repeat(projects; outer=n) + for project in shuffle!(repeat(projects; outer=n)) run(`$(Base.julia_cmd()) --startup-file=no --project=$(project) $benchmark_file $Package`) project_name = basename(project) end diff --git a/precompile/shared-precompile.jl b/precompile/shared-precompile.jl index 923eff489a3..efa7a3999cd 100644 --- a/precompile/shared-precompile.jl +++ b/precompile/shared-precompile.jl @@ -1,6 +1,5 @@ # File to run to snoop/trace all functions to compile using GeometryBasics - @compile poly(Recti(0, 0, 200, 200), strokewidth=20, strokecolor=:red, color=(:black, 0.4)) @compile scatter(0..1, rand(10), markersize=rand(10) .* 20) @@ -55,7 +54,7 @@ end @compile begin res = 200 - s = Scene(camera=campixel!, resolution=(res, res)) + s = Scene(camera=campixel!, size=(res, res)) half = res / 2 linewidth = 10 xstart = half - (half/2) diff --git a/src/Makie.jl b/src/Makie.jl index 36500312839..ef40b64c0eb 100644 --- a/src/Makie.jl +++ b/src/Makie.jl @@ -12,6 +12,12 @@ using .ContoursHygiene const Contours = ContoursHygiene.Contour using Base64 +# Import FilePaths for invalidations +# 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 using Random @@ -72,20 +78,22 @@ using Base.Iterators: repeated, drop import Base: getindex, setindex!, push!, append!, parent, get, get!, delete!, haskey using Observables: listeners, to_value, notify -using MakieCore: SceneLike, MakieScreen, ScenePlot, AbstractScene, AbstractPlot, Transformable, Attributes, Combined, Theme, Plot +using MakieCore: SceneLike, MakieScreen, ScenePlot, AbstractScene, AbstractPlot, Transformable, Attributes, Plot, Theme, Plot using MakieCore: Arrows, Heatmap, Image, Lines, LineSegments, Mesh, MeshScatter, Poly, Scatter, Surface, Text, Volume, Wireframe -using MakieCore: ConversionTrait, NoConversion, PointBased, SurfaceLike, ContinuousSurface, DiscreteSurface, VolumeLike +using MakieCore: ConversionTrait, NoConversion, PointBased, GridBased, VertexGrid, CellGrid, ImageLike, VolumeLike using MakieCore: Key, @key_str, Automatic, automatic, @recipe using MakieCore: Pixel, px, Unit, Billboard +using MakieCore: NoShading, FastShading, MultiLightShading using MakieCore: not_implemented_for import MakieCore: plot, plot!, theme, plotfunc, plottype, merge_attributes!, calculated_attributes!, -get_attribute, plotsym, plotkey, attributes, used_attributes + get_attribute, plotsym, plotkey, attributes, used_attributes +import MakieCore: create_axis_like, create_axis_like!, figurelike_return, figurelike_return! import MakieCore: arrows, heatmap, image, lines, linesegments, mesh, meshscatter, poly, scatter, surface, text, volume import MakieCore: arrows!, heatmap!, image!, lines!, linesegments!, mesh!, meshscatter!, poly!, scatter!, surface!, text!, volume! import MakieCore: convert_arguments, convert_attribute, default_theme, conversion_trait export @L_str, @colorant_str -export ConversionTrait, NoConversion, PointBased, SurfaceLike, ContinuousSurface, DiscreteSurface, VolumeLike +export ConversionTrait, NoConversion, PointBased, GridBased, VertexGrid, CellGrid, ImageLike, VolumeLike export Pixel, px, Unit, plotkey, attributes, used_attributes export Linestyle @@ -107,6 +115,7 @@ include("interaction/liftmacro.jl") include("colorsampler.jl") include("patterns.jl") include("utilities/utilities.jl") # need Makie.AbstractPattern +include("lighting.jl") # Basic scene/plot/recipe interfaces + types include("scenes.jl") @@ -167,6 +176,10 @@ include("layouting/transformation.jl") include("layouting/data_limits.jl") include("layouting/layouting.jl") include("layouting/boundingbox.jl") + +# Declaritive SpecApi +include("specapi.jl") + # more default recipes # statistical recipes include("stats/conversions.jl") @@ -201,7 +214,7 @@ export help, help_attributes, help_arguments # Abstract/Concrete scene + plot types export AbstractScene, SceneLike, Scene, MakieScreen -export AbstractPlot, Combined, Atomic, OldAxis +export AbstractPlot, Plot, Atomic, OldAxis # Theming, working with Plots export Attributes, Theme, attributes, default_theme, theme, set_theme!, with_theme, update_theme! @@ -222,7 +235,7 @@ export xtickrotation, ytickrotation, ztickrotation export xtickrotation!, ytickrotation!, ztickrotation! # Observable/Signal related -export Observable, Observable, lift, map_once, to_value, on, onany, @lift, off, connect! +export Observable, Observable, lift, to_value, on, onany, @lift, off, connect! # utilities and macros export @recipe, @extract, @extractvalue, @key_str, @get_attribute @@ -245,11 +258,11 @@ export SceneSpace, PixelSpace, Pixel export AbstractCamera, EmptyCamera, Camera, Camera2D, Camera3D, cam2d!, cam2d export campixel!, campixel, cam3d!, cam3d_cad!, old_cam3d!, old_cam3d_cad!, cam_relative! export update_cam!, rotate_cam!, translate_cam!, zoom! -export pixelarea, plots, cameracontrols, cameracontrols!, camera, events +export viewport, plots, cameracontrols, cameracontrols!, camera, events export to_world # picking + interactive use cases + events -export mouseover, onpick, pick, Events, Keyboard, Mouse, mouse_selection, is_mouseinside +export mouseover, onpick, pick, Events, Keyboard, Mouse, is_mouseinside export ispressed, Exclusively export connect_screen export window_area, window_open, mouse_buttons, mouse_position, mouseposition_px, @@ -261,6 +274,7 @@ export Consume # Raymarching algorithms export RaymarchAlgorithm, IsoValue, Absorption, MaximumIntensityProjection, AbsorptionRGBA, IndexedAbsorptionRGBA export Billboard +export NoShading, FastShading, MultiLightShading # Reexports of # Color/Vector types convenient for 3d/2d graphics @@ -338,7 +352,7 @@ export Arrows , Heatmap , Image , Lines , LineSegments , Mesh , MeshScatte export arrows , heatmap , image , lines , linesegments , mesh , meshscatter , poly , scatter , surface , text , volume , wireframe export arrows! , heatmap! , image! , lines! , linesegments! , mesh! , meshscatter! , poly! , scatter! , surface! , text! , volume! , wireframe! -export PointLight, EnvironmentLight, AmbientLight, SSAO +export AmbientLight, PointLight, DirectionalLight, SpotLight, EnvironmentLight, RectLight, SSAO include("precompiles.jl") diff --git a/src/basic_recipes/arrows.jl b/src/basic_recipes/arrows.jl index 83a2a38f76c..c9a04553ea6 100644 --- a/src/basic_recipes/arrows.jl +++ b/src/basic_recipes/arrows.jl @@ -118,7 +118,7 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) wher arrowtail, color, linecolor, linestyle, linewidth, lengthscale, arrowhead, arrowsize, arrowcolor, quality, # passthrough - diffuse, specular, shininess, + diffuse, specular, shininess, shading, fxaa, ssao, transparency, visible, inspectable ) @@ -146,7 +146,7 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) wher # for 2D arrows, compute the correct marker rotation given the projection / scene size # for the screen-space marker if is_pixel_space(arrowplot.markerspace[]) - rotations = lift(arrowplot, scene.camera.projectionview, scene.px_area, headstart) do pv, pxa, hs + rotations = lift(arrowplot, scene.camera.projectionview, scene.viewport, headstart) do pv, pxa, hs angles = map(hs) do (start, stop) pstart = project(scene, start) pstop = project(scene, stop) @@ -210,25 +210,21 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) wher marker_tail = lift((at, q) -> arrow_tail(3, at, q), arrowplot, arrowtail, quality) meshscatter!( arrowplot, - start, rotations = directions, - marker=marker_tail, - markersize = msize, - color=line_c, colormap=colormap, colorscale=colorscale, colorrange=arrowplot.colorrange, - fxaa = fxaa_bool, ssao = ssao, - diffuse = diffuse, - specular = specular, shininess = shininess, inspectable = inspectable, - transparency = transparency, visible = visible + start, rotations = directions, markersize = msize, + marker = marker_tail, + color = line_c, colormap = colormap, colorscale = colorscale, colorrange = arrowplot.colorrange, + fxaa = fxaa_bool, ssao = ssao, shading = shading, + diffuse = diffuse, specular = specular, shininess = shininess, + inspectable = inspectable, transparency = transparency, visible = visible ) meshscatter!( arrowplot, - start, rotations = directions, - marker=marker_head, - markersize = markersize, - color=arrow_c, colormap=colormap, colorscale=colorscale, colorrange=arrowplot.colorrange, - fxaa = fxaa_bool, ssao = ssao, - diffuse = diffuse, - specular = specular, shininess = shininess, inspectable = inspectable, - transparency = transparency, visible = visible + start, rotations = directions, markersize = markersize, + marker = marker_head, + color = arrow_c, colormap = colormap, colorscale = colorscale, colorrange = arrowplot.colorrange, + fxaa = fxaa_bool, ssao = ssao, shading = shading, + diffuse = diffuse, specular = specular, shininess = shininess, + inspectable = inspectable, transparency = transparency, visible = visible ) end diff --git a/src/basic_recipes/axis.jl b/src/basic_recipes/axis.jl index f9744a8efb5..fcb4f803539 100644 --- a/src/basic_recipes/axis.jl +++ b/src/basic_recipes/axis.jl @@ -317,8 +317,8 @@ function draw_axis3d(textbuffer, linebuffer, scale, limits, ranges_labels, fonts return end -function plot!(scene::SceneLike, ::Type{<: Axis3D}, attributes::Attributes, args...) - axis = Axis3D(scene, attributes, args) +function plot!(axis::Axis3D) + scene = get_scene(axis) # Disable any non linear transform for the axis plot! axis.transformation.transform_func[] = identity textbuffer = TextBuffer(axis, Point3, transparency = true, markerspace = :data, @@ -334,12 +334,11 @@ function plot!(scene::SceneLike, ::Type{<: Axis3D}, attributes::Attributes, args getindex.(axis, (:showaxis, :showticks, :showgrid))..., titlevals..., framevals..., tvals..., axis.padding ) - map_once( + onany( draw_axis3d, Observable(textbuffer), Observable(linebuffer), scale(scene), - axis[1], axis.ticks.ranges_labels, Observable(axis.fonts), args... + axis[1], axis.ticks.ranges_labels, Observable(axis.fonts), args...; update=true ) - push!(scene, axis) return axis end diff --git a/src/basic_recipes/band.jl b/src/basic_recipes/band.jl index b0434868c1a..9a8de39b48d 100644 --- a/src/basic_recipes/band.jl +++ b/src/basic_recipes/band.jl @@ -13,7 +13,7 @@ $(ATTRIBUTES) default_theme(scene, Mesh)..., colorrange = automatic, ) - attr[:shading][] = false + attr[:shading][] = NoShading attr end diff --git a/src/basic_recipes/barplot.jl b/src/basic_recipes/barplot.jl index 99430e1a4ce..9aba359429b 100644 --- a/src/basic_recipes/barplot.jl +++ b/src/basic_recipes/barplot.jl @@ -141,21 +141,24 @@ function stack_from_to(i_stack, y) end function stack_grouped_from_to(i_stack, y, grp) - from = Array{Float64}(undef, length(y)) to = Array{Float64}(undef, length(y)) - groupby = StructArray((; grp..., is_pos = y .> 0)) - + groupby = StructArray((; grp...)) grps = StructArrays.finduniquesorted(groupby) + last_pos = map(grps) do (g, inds) + g => any(y[inds] .> 0) || all(y[inds] .== 0) + end |> Dict + is_pos = map(y, groupby) do v, g + last_pos[g] = iszero(v) ? last_pos[g] : v > 0 + end + groupby = StructArray((; grp..., is_pos)) + grps = StructArrays.finduniquesorted(groupby) for (grp, inds) in grps - fromto = stack_from_to(i_stack[inds], y[inds]) - from[inds] .= fromto.from to[inds] .= fromto.to - end (from = from, to = to) diff --git a/src/basic_recipes/bracket.jl b/src/basic_recipes/bracket.jl index 34c2691bf85..c1d2dff71bb 100644 --- a/src/basic_recipes/bracket.jl +++ b/src/basic_recipes/bracket.jl @@ -55,7 +55,7 @@ function Makie.plot!(pl::Bracket) end onany(pl, points, scene.camera.projectionview, pl.model, transform_func(pl), - scene.px_area, pl.offset, pl.width, pl.orientation, realtextoffset, + scene.viewport, pl.offset, pl.width, pl.orientation, realtextoffset, pl.style) do points, _, _, _, _, offset, width, orientation, textoff, style empty!(bp[]) diff --git a/src/basic_recipes/contourf.jl b/src/basic_recipes/contourf.jl index d2e0d7a8f55..89ff2ae4da3 100644 --- a/src/basic_recipes/contourf.jl +++ b/src/basic_recipes/contourf.jl @@ -55,6 +55,9 @@ function _get_isoband_levels(levels::AbstractVector{<:Real}, mi, ma) @assert issorted(edges) edges end + +conversion_trait(::Type{<:Contourf}) = VertexGrid() + function _get_isoband_levels(::Val{:normal}, levels, values) return _get_isoband_levels(levels, extrema_nan(values)...) end @@ -64,9 +67,6 @@ function _get_isoband_levels(::Val{:relative}, levels::AbstractVector, values) return Float32.(levels .* (ma - mi) .+ mi) end -conversion_trait(::Type{<:Contourf}) = ContinuousSurface() - - function Makie.plot!(c::Contourf{<:Tuple{<:AbstractVector{<:Real}, <:AbstractVector{<:Real}, <:AbstractMatrix{<:Real}}}) xs, ys, zs = c[1:3] @@ -141,7 +141,7 @@ function Makie.plot!(c::Contourf{<:Tuple{<:AbstractVector{<:Real}, <:AbstractVec color = colors, strokewidth = 0, strokecolor = :transparent, - shading = false, + shading = NoShading, inspectable = c.inspectable, transparency = c.transparency ) diff --git a/src/basic_recipes/contours.jl b/src/basic_recipes/contours.jl index ed02afc1e69..de5d45da706 100644 --- a/src/basic_recipes/contours.jl +++ b/src/basic_recipes/contours.jl @@ -22,26 +22,26 @@ To add contour labels, use `labels = true`, and pass additional label attributes $(ATTRIBUTES) """ @recipe(Contour) do scene - default = default_theme(scene) - # pop!(default, :color) - Attributes(; - default..., + attr = Attributes(; color = nothing, - colormap = theme(scene, :colormap), - colorscale = identity, - colorrange = Makie.automatic, levels = 5, linewidth = 1.0, linestyle = nothing, - alpha = 1.0, enable_depth = true, transparency = false, labels = false, + labelfont = theme(scene, :font), labelcolor = nothing, # matches color by default labelformatter = contour_label_formatter, labelsize = 10, # arbitrary ) + + + MakieCore.colormap_attributes!(attr, theme(scene, :colormap)) + MakieCore.generic_plot_attributes!(attr) + + return attr end """ @@ -110,10 +110,10 @@ function to_levels(n::Integer, cnorm) range(zmin + dz; step = dz, length = n) end -conversion_trait(::Type{<: Contour3d}) = ContinuousSurface() -conversion_trait(::Type{<: Contour}) = ContinuousSurface() -conversion_trait(::Type{<: Contour{<: Tuple{X, Y, Z, Vol}}}) where {X, Y, Z, Vol} = VolumeLike() -conversion_trait(::Type{<: Contour{<: Tuple{<: AbstractArray{T, 3}}}}) where T = VolumeLike() +conversion_trait(::Type{<: Contour3d}) = VertexGrid() +conversion_trait(::Type{<: Contour}) = VertexGrid() +conversion_trait(::Type{<:Contour}, x, y, z, ::Union{Function, AbstractArray{<: Number, 3}}) = VolumeLike() +conversion_trait(::Type{<: Contour}, ::AbstractArray{<: Number, 3}) = VolumeLike() function plot!(plot::Contour{<: Tuple{X, Y, Z, Vol}}) where {X, Y, Z, Vol} x, y, z, volume = plot[1:4] @@ -145,12 +145,14 @@ function plot!(plot::Contour{<: Tuple{X, Y, Z, Vol}}) where {X, Y, Z, Vol} end end - attr = Attributes(plot) + attr = copy(Attributes(plot)) + attr[:colorrange] = cliprange attr[:colormap] = cmap attr[:algorithm] = 7 pop!(attr, :levels) pop!(attr, :alpha) # don't apply alpha 2 times + # unused attributes pop!(attr, :labels) pop!(attr, :labelfont) @@ -247,10 +249,12 @@ function plot!(plot::T) where T <: Union{Contour, Contour3d} align = (:center, :center), fontsize = labelsize, font = labelfont, + transform_marker = false ) - lift(scene.camera.projectionview, scene.px_area, labels, labelcolor, labelformatter, - lev_pos_col) do _, _, labels, labelcolor, labelformatter, lev_pos_col + lift(scene.camera.projectionview, transformationmatrix(plot), scene.viewport, + labels, labelcolor, labelformatter, lev_pos_col + ) do _, _, _, labels, labelcolor, labelformatter, lev_pos_col labels || return pos = texts.positions.val; empty!(pos) rot = texts.rotation.val; empty!(rot) @@ -316,9 +320,13 @@ function plot!(plot::T) where T <: Union{Contour, Contour3d} plot, masked_lines; color = colors, linewidth = plot.linewidth, - inspectable = plot.inspectable, - transparency = plot.transparency, - linestyle = plot.linestyle + linestyle = plot.linestyle, + visible=plot.visible, + transparency=plot.transparency, + overdraw=plot.overdraw, + inspectable=plot.inspectable, + depth_shift=plot.depth_shift, + space=plot.space ) plot end diff --git a/src/basic_recipes/convenience_functions.jl b/src/basic_recipes/convenience_functions.jl index 66d8b9702a7..dab4e6d0947 100644 --- a/src/basic_recipes/convenience_functions.jl +++ b/src/basic_recipes/convenience_functions.jl @@ -16,7 +16,7 @@ end showgradients( cgrads::AbstractVector{Symbol}; h = 0.0, offset = 0.2, fontsize = 0.7, - resolution = (800, length(cgrads) * 84) + size = (800, length(cgrads) * 84) )::Scene Plots the given colour gradients arranged as horizontal colourbars. @@ -27,11 +27,11 @@ function showgradients( h = 0.0, offset = 0.4, fontsize = 0.7, - resolution = (800, length(cgrads) * 84), + size = (800, length(cgrads) * 84), monospace = true )::Scene - scene = Scene(resolution = resolution) + scene = Scene(size = resolution) map(collect(cgrads)) do cmap c = to_colormap(cmap) diff --git a/src/basic_recipes/datashader.jl b/src/basic_recipes/datashader.jl index 27123b672be..d9bf42b2244 100644 --- a/src/basic_recipes/datashader.jl +++ b/src/basic_recipes/datashader.jl @@ -377,8 +377,8 @@ end function Makie.plot!(p::DataShader{<: Tuple{<: AbstractVector{<: Point}}}) scene = parent_scene(p) limits = lift(projview_to_2d_limits, p, scene.camera.projectionview; ignore_equal_values=true) - px_area = lift(identity, p, scene.px_area; ignore_equal_values=true) - canvas = canvas_obs(limits, px_area, p.agg, p.binsize) + viewport = lift(identity, p, scene.viewport; ignore_equal_values=true) + canvas = canvas_obs(limits, viewport, p.agg, p.binsize) p._boundingbox = lift(fast_bb, p.points, p.point_transform) on_func = p.async[] ? onany_latest : onany canvas_with_aggregation = Observable(canvas[]) # Canvas that only gets notified after get_aggregation happened @@ -432,8 +432,8 @@ end function Makie.plot!(p::DataShader{<:Tuple{Dict{String, Vector{Point{2, Float32}}}}}) scene = parent_scene(p) limits = lift(projview_to_2d_limits, p, scene.camera.projectionview; ignore_equal_values=true) - px_area = lift(identity, p, scene.px_area; ignore_equal_values=true) - canvas = canvas_obs(limits, px_area, Observable(AggCount{Float32}()), p.binsize) + viewport = lift(identity, p, scene.viewport; ignore_equal_values=true) + canvas = canvas_obs(limits, viewport, Observable(AggCount{Float32}()), p.binsize) p._boundingbox = lift(p.points, p.point_transform) do cats, func rects = map(points -> fast_bb(points, func), values(cats)) return reduce(union, rects) @@ -468,15 +468,13 @@ end data_limits(p::DataShader) = p._boundingbox[] -used_attributes(::Type{<:Any}, ::Canvas) = (:operation, :local_operation) +used_attributes(::Canvas) = (:operation, :local_operation) function convert_arguments(P::Type{<:Union{MeshScatter,Image,Surface,Contour,Contour3d}}, canvas::Canvas; operation=automatic, local_operation=identity) pixel = Aggregation.get_aggregation(canvas; operation=operation, local_operation=local_operation) (xmin, ymin), (xmax, ymax) = extrema(canvas.bounds) - xrange = range(xmin, stop = xmax, length = size(pixel, 1)) - yrange = range(ymin, stop = ymax, length = size(pixel, 2)) - return convert_arguments(P, xrange, yrange, pixel) + return convert_arguments(P, xmin .. xmax, ymin .. ymax, pixel) end # TODO improve color legend API, to not need a fake plot like this diff --git a/src/basic_recipes/error_and_rangebars.jl b/src/basic_recipes/error_and_rangebars.jl index e8c11cb98e6..95dc2ec39e1 100644 --- a/src/basic_recipes/error_and_rangebars.jl +++ b/src/basic_recipes/error_and_rangebars.jl @@ -28,7 +28,8 @@ $(ATTRIBUTES) colorscale = identity, colorrange = automatic, inspectable = theme(scene, :inspectable), - transparency = false + transparency = false, + cycle = [:color] ) end @@ -57,7 +58,8 @@ $(ATTRIBUTES) colorscale = identity, colorrange = automatic, inspectable = theme(scene, :inspectable), - transparency = false + transparency = false, + cycle = [:color] ) end @@ -198,7 +200,7 @@ function _plot_bars!(plot, linesegpairs, is_in_y_direction) scene = parent_scene(plot) whiskers = lift(plot, linesegpairs, scene.camera.projectionview, plot.model, - scene.px_area, transform_func(plot), whiskerwidth) do endpoints, _, _, _, _, whiskerwidth + scene.viewport, transform_func(plot), whiskerwidth) do endpoints, _, _, _, _, whiskerwidth screenendpoints = plot_to_screen(plot, endpoints) diff --git a/src/basic_recipes/hvlines.jl b/src/basic_recipes/hvlines.jl index 23be173580a..a919629d6b6 100644 --- a/src/basic_recipes/hvlines.jl +++ b/src/basic_recipes/hvlines.jl @@ -83,7 +83,25 @@ function Makie.plot!(p::Union{HLines, VLines}) line_attributes = copy(p.attributes) foreach(key-> delete!(line_attributes, key), [:ymin, :ymax, :xmin, :xmax, :xautolimits, :yautolimits]) # Drop transform_func because we handle it manually - T = Transformation(p, transform_func = identity) - linesegments!(p, line_attributes, points, transformation = T) + line_attributes[:transformation] = Transformation(p, transform_func = identity) + linesegments!(p, line_attributes, points) p end + +function data_limits(p::HLines) + scene = parent_scene(p) + limits = projview_to_2d_limits(scene.camera.projectionview[]) + itf = inverse_transform(p.transformation.transform_func[]) + xmin, xmax = apply_transform.(itf[1], first.(extrema(limits))) + ymin, ymax = extrema(p[1][]) + return Rect3f(Point3f(xmin, ymin, 0), Vec3f(xmax - xmin, ymax - ymin, 0)) +end + +function data_limits(p::VLines) + scene = parent_scene(p) + limits = projview_to_2d_limits(scene.camera.projectionview[]) + itf = inverse_transform(p.transformation.transform_func[]) + xmin, xmax = extrema(p[1][]) + ymin, ymax = apply_transform.(itf[2], getindex.(extrema(limits), 2)) + return Rect3f(Point3f(xmin, ymin, 0), Vec3f(xmax - xmin, ymax - ymin, 0)) +end \ No newline at end of file diff --git a/src/basic_recipes/hvspan.jl b/src/basic_recipes/hvspan.jl index 3ecd9589551..cb082347705 100644 --- a/src/basic_recipes/hvspan.jl +++ b/src/basic_recipes/hvspan.jl @@ -77,8 +77,8 @@ function Makie.plot!(p::Union{HSpan, VSpan}) foreach(x-> delete!(poly_attributes, x), [:ymin, :ymax, :xmin, :xmax, :xautolimits, :yautolimits]) # we handle transform_func manually - T = Transformation(p, transform_func = identity) - poly!(p, poly_attributes, rects; transformation = T) + poly_attributes[:transformation] = Transformation(p, transform_func = identity) + poly!(p, poly_attributes, rects) p end @@ -88,3 +88,24 @@ _apply_x_transform(other, v) = error("x transform not defined for transform func _apply_y_transform(t::Tuple, v) = apply_transform(t[2], v) _apply_y_transform(other, v) = error("y transform not defined for transform function $(typeof(other))") _apply_y_transform(::typeof(identity), v) = v + + +function data_limits(p::HSpan) + scene = parent_scene(p) + limits = projview_to_2d_limits(scene.camera.projectionview[]) + itf = inverse_transform(p.transformation.transform_func[]) + xmin, xmax = apply_transform.(itf[1], first.(extrema(limits))) + ymin = minimum(p[1][]) + ymax = maximum(p[2][]) + return Rect3f(Point3f(xmin, ymin, 0), Vec3f(xmax - xmin, ymax - ymin, 0)) +end + +function data_limits(p::VSpan) + scene = parent_scene(p) + limits = projview_to_2d_limits(scene.camera.projectionview[]) + itf = inverse_transform(p.transformation.transform_func[]) + xmin = minimum(p[1][]) + xmax = maximum(p[2][]) + ymin, ymax = apply_transform.(itf[2], getindex.(extrema(limits), 2)) + return Rect3f(Point3f(xmin, ymin, 0), Vec3f(xmax - xmin, ymax - ymin, 0)) +end \ No newline at end of file diff --git a/src/basic_recipes/poly.jl b/src/basic_recipes/poly.jl index 038f9be82a1..8792eadfb0c 100644 --- a/src/basic_recipes/poly.jl +++ b/src/basic_recipes/poly.jl @@ -9,13 +9,14 @@ convert_arguments(::Type{<: Poly}, m::GeometryBasics.Mesh) = (m,) convert_arguments(::Type{<: Poly}, m::GeometryBasics.GeometryPrimitive) = (m,) function plot!(plot::Poly{<: Tuple{Union{GeometryBasics.Mesh, GeometryPrimitive}}}) + mesh!( plot, lift(triangle_mesh, plot, plot[1]), color = plot.color, colormap = plot.colormap, colorscale = plot.colorscale, - colorrange=plot.colorrange, - alpha=plot.alpha, + colorrange = plot.colorrange, + alpha = plot.alpha, lowclip = plot.lowclip, highclip = plot.highclip, nan_color = plot.nan_color, @@ -36,33 +37,57 @@ function plot!(plot::Poly{<: Tuple{Union{GeometryBasics.Mesh, GeometryPrimitive} end # Poly conversion -function poly_convert(geometries) +function poly_convert(geometries::AbstractVector, transform_func=identity) isempty(geometries) && return typeof(GeometryBasics.Mesh(Point2f[], GLTriangleFace[]))[] - return triangle_mesh.(geometries) + return poly_convert.(geometries, (transform_func,)) end -poly_convert(meshes::AbstractVector{<:AbstractMesh}) = meshes -function poly_convert(polys::AbstractVector{<:Polygon}) + +function poly_convert(geometry::AbstractGeometry, transform_func=identity) + return GeometryBasics.triangle_mesh(geometry) +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? T = GeometryBasics.Mesh{2, Float32, GeometryBasics.Ngon{2, Float32, 3, Point2f}, SimpleFaceView{2, Float32, 3, GLIndex, Point2f, GLTriangleFace}} - return isempty(polys) ? T[] : triangle_mesh.(polys) + return isempty(polys) ? T[] : poly_convert.(polys, (transform_func,)) end -function poly_convert(multipolygons::AbstractVector{<:MultiPolygon}) - return [merge(triangle_mesh.(multipoly.polygons)) for multipoly in multipolygons] + +function poly_convert(multipolygons::AbstractVector{<:MultiPolygon}, transform_func=identity) + return [merge(poly_convert.(multipoly.polygons, (transform_func,))) for multipoly in multipolygons] end -poly_convert(mesh::GeometryBasics.Mesh) = mesh +poly_convert(mesh::GeometryBasics.Mesh, transform_func=identity) = mesh -poly_convert(polygon::Polygon) = triangle_mesh(polygon) +function poly_convert(polygon::Polygon, transform_func=identity) + outer = metafree(coordinates(polygon.exterior)) + points = Vector{Point2f}[apply_transform(transform_func, outer)] + points_flat = Point2f[outer;] + for inner in polygon.interiors + inner_points = metafree(coordinates(inner)) + append!(points_flat, inner_points) + push!(points, apply_transform(transform_func, inner_points)) + end + # Triangulate on transformed points, but leave the original points in the mesh + # We sadly need to do this right now, since otherwise + # The transformed points will mess with data_limits and the axes. + # TODO, leave triangulations to the backend, and just pass the untransformed points + faces = GeometryBasics.earcut_triangulate(points) + return GeometryBasics.Mesh(points_flat, faces) +end -function poly_convert(polygon::AbstractVector{<: VecTypes}) - return poly_convert([convert_arguments(Scatter, polygon)[1]]) +function poly_convert(polygon::AbstractVector{<:VecTypes}, transform_func=identity) + point2f = convert(Vector{Point2f}, polygon) + points_transformed = apply_transform(transform_func, point2f) + faces = GeometryBasics.earcut_triangulate([points_transformed]) + # TODO, same as above! + return GeometryBasics.Mesh(point2f, faces) end -function poly_convert(polygons::AbstractVector{<: AbstractVector{<: VecTypes}}) +function poly_convert(polygons::AbstractVector{<:AbstractVector{<:VecTypes}}, transform_func=identity) return map(polygons) do poly - point2f = convert(Vector{Point2f}, poly) - faces = GeometryBasics.earcut_triangulate([point2f]) - return GeometryBasics.Mesh(point2f, faces) + return poly_convert(poly, transform_func) end end @@ -92,7 +117,8 @@ end function plot!(plot::Poly{<: Tuple{<: Union{Polygon, AbstractVector{<: PolyElements}}}}) geometries = plot[1] - meshes = lift(poly_convert, plot, geometries) + transform_func = plot.transformation.transform_func + meshes = lift(poly_convert, plot, geometries, transform_func) mesh!(plot, meshes; visible = plot.visible, shading = plot.shading, @@ -108,7 +134,7 @@ function plot!(plot::Poly{<: Tuple{<: Union{Polygon, AbstractVector{<: PolyEleme fxaa = plot.fxaa, transparency = plot.transparency, inspectable = plot.inspectable, - space = plot.space + space = plot.space, ) outline = lift(to_lines, plot, geometries) @@ -179,12 +205,14 @@ function plot!(plot::Mesh{<: Tuple{<: AbstractVector{P}}}) where P <: Union{Abst end end attributes[:color] = mesh_colors - bigmesh = lift(plot, meshes) do meshes + transform_func = plot.transformation.transform_func + bigmesh = lift(plot, meshes, transform_func) do meshes, tf if isempty(meshes) return GeometryBasics.Mesh(Point2f[], GLTriangleFace[]) else - return merge(GeometryBasics.triangle_mesh.(meshes)) + triangle_meshes = map(mesh -> poly_convert(mesh, tf), meshes) + return merge(triangle_meshes) end end - mesh!(plot, attributes, bigmesh) + return mesh!(plot, attributes, bigmesh) end diff --git a/src/basic_recipes/scatterlines.jl b/src/basic_recipes/scatterlines.jl index b6b0327e17a..3808e6ae01a 100644 --- a/src/basic_recipes/scatterlines.jl +++ b/src/basic_recipes/scatterlines.jl @@ -29,11 +29,11 @@ $(ATTRIBUTES) end -function plot!(p::Combined{scatterlines, <:NTuple{N, Any}}) where N +function plot!(p::Plot{scatterlines, <:NTuple{N, Any}}) where N # markercolor is the same as linecolor if left automatic # RGBColors -> union of all colortypes that `to_color` accepts + returns - real_markercolor = Observable{RGBColors}() + real_markercolor = Observable{RGBColors}() map!(real_markercolor, p.color, p.markercolor) do col, mcol if mcol === automatic return to_color(col) diff --git a/src/basic_recipes/streamplot.jl b/src/basic_recipes/streamplot.jl index 9a999d27300..6fd20d88d3b 100644 --- a/src/basic_recipes/streamplot.jl +++ b/src/basic_recipes/streamplot.jl @@ -194,7 +194,7 @@ function plot!(p::StreamPlot) # Calculate arrow head rotations as angles. To avoid distortions from # (extreme) aspect ratios we need to project to pixel space and renormalize. scene = parent_scene(p) - rotations = lift(p, scene.camera.projectionview, scene.px_area, data) do pv, pxa, data + rotations = lift(p, scene.camera.projectionview, scene.viewport, data) do pv, pxa, data angles = map(data[1], data[2]) do pos, dir pstart = project(scene, pos) pstop = project(scene, pos + dir) diff --git a/src/basic_recipes/text.jl b/src/basic_recipes/text.jl index d713e45c7b8..ef23d1d14d5 100644 --- a/src/basic_recipes/text.jl +++ b/src/basic_recipes/text.jl @@ -1,13 +1,20 @@ +function check_textsize_deprecation(@nospecialize(dictlike)) + if haskey(dictlike, :textsize) + throw(ArgumentError("The attribute `textsize` has been renamed to `fontsize` in Makie v0.19. Please change all occurrences of `textsize` to `fontsize` or revert back to an earlier version.")) + end +end + function plot!(plot::Text) + check_textsize_deprecation(plot) positions = plot[1] # attach a function to any text that calculates the glyph layout and stores it - glyphcollections = Observable(GlyphCollection[]) - linesegs = Observable(Point2f[]) - linewidths = Observable(Float32[]) - linecolors = Observable(RGBAf[]) + glyphcollections = Observable(GlyphCollection[]; ignore_equal_values=true) + linesegs = Observable(Point2f[]; ignore_equal_values=true) + linewidths = Observable(Float32[]; ignore_equal_values=true) + linecolors = Observable(RGBAf[]; ignore_equal_values=true) lineindices = Ref(Int[]) - onany(plot.text, plot.fontsize, plot.font, plot.fonts, plot.align, + onany(plot, plot.text, plot.fontsize, plot.font, plot.fonts, plot.align, plot.rotation, plot.justification, plot.lineheight, plot.calculated_colors, plot.strokecolor, plot.strokewidth, plot.word_wrap_width, plot.offset) do str, ts, f, fs, al, rot, jus, lh, col, scol, swi, www, offs @@ -23,7 +30,8 @@ function plot!(plot::Text) lwidths = Float32[] lcolors = RGBAf[] lindices = Int[] - function push_args((gc, ls, lw, lc, lindex)) + function push_args(args...) + gc, ls, lw, lc, lindex = _get_glyphcollection_and_linesegments(args...) push!(gcs, gc) append!(lsegs, ls) append!(lwidths, lw) @@ -31,18 +39,15 @@ function plot!(plot::Text) append!(lindices, lindex) return end - func = push_args ∘ _get_glyphcollection_and_linesegments if str isa Vector # If we have a Vector of strings, Vector arguments are interpreted # as per string. - broadcast_foreach( - func, - str, 1:attr_broadcast_length(str), ts, f, fs, al, rot, jus, lh, col, scol, swi, www, offs + broadcast_foreach(push_args, str, 1:attr_broadcast_length(str), ts, f, fs, al, rot, jus, lh, col, scol, swi, www, offs ) else # Otherwise Vector arguments are interpreted by layout_text/ # glyph_collection as per character. - func(str, 1, ts, f, fs, al, rot, jus, lh, col, scol, swi, www, offs) + push_args(str, 1, ts, f, fs, al, rot, jus, lh, col, scol, swi, www, offs) end glyphcollections[] = gcs linewidths[] = lwidths @@ -51,11 +56,11 @@ function plot!(plot::Text) linesegs[] = lsegs end - linesegs_shifted = Observable(Point2f[]) + linesegs_shifted = Observable(Point2f[]; ignore_equal_values=true) sc = parent_scene(plot) - onany(linesegs, positions, sc.camera.projectionview, sc.px_area, + onany(plot, linesegs, positions, sc.camera.projectionview, sc.viewport, transform_func_obs(sc), get(plot, :space, :data)) do segs, pos, _, _, transf, space pos_transf = plot_to_screen(plot, pos) linesegs_shifted[] = map(segs, lineindices[]) do seg, index @@ -157,7 +162,7 @@ function plot!(plot::Text{<:Tuple{<:AbstractArray{<:Tuple{<:Any, <:Point}}}}) text!(plot, positions; text = strings, attrs...) # update both text and positions together - on(strings_and_positions) do str_pos + on(plot, strings_and_positions) do str_pos strs = first.(str_pos) poss = to_ndim.(Ref(Point3f), last.(str_pos), 0) diff --git a/src/basic_recipes/tooltip.jl b/src/basic_recipes/tooltip.jl index ae0a516f04c..74c75241062 100644 --- a/src/basic_recipes/tooltip.jl +++ b/src/basic_recipes/tooltip.jl @@ -36,13 +36,13 @@ Creates a tooltip pointing at `position` displaying the given `string` """ @recipe(Tooltip, position) do scene Attributes(; - # General - text = "", + # General + text = "", offset = 10, placement = :above, align = 0.5, - xautolimits = false, - yautolimits = false, + xautolimits = false, + yautolimits = false, zautolimits = false, overdraw = false, depth_shift = 0f0, @@ -62,7 +62,7 @@ Creates a tooltip pointing at `position` displaying the given `string` # Background backgroundcolor = :white, triangle_size = 10, - + # Outline outline_color = :black, outline_linewidth = 2f0, @@ -103,7 +103,7 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) text_offset = map(p.offset, textpadding, p.triangle_size, p.placement, p.align) do o, pad, ts, placement, align l, r, b, t = pad - if placement === :left + if placement === :left return Vec2f(-o - r - ts, b - align * (b + t)) elseif placement === :right return Vec2f( o + l + ts, b - align * (b + t)) @@ -118,7 +118,7 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) end text_align = map(p.placement, p.align) do placement, align - if placement === :left + if placement === :left return (1.0, align) elseif placement === :right return (0.0, align) @@ -155,9 +155,9 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) # Text background mesh mesh!( - p, bbox, shading = false, space = :pixel, + p, bbox, shading = NoShading, space = :pixel, color = p.backgroundcolor, fxaa = false, - transparency = p.transparency, visible = p.visible, + transparency = p.transparency, visible = p.visible, overdraw = p.overdraw, depth_shift = p.depth_shift, inspectable = p.inspectable ) @@ -170,8 +170,8 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) ) mp = mesh!( - p, triangle, shading = false, space = :pixel, - color = p.backgroundcolor, + p, triangle, shading = NoShading, space = :pixel, + color = p.backgroundcolor, transparency = p.transparency, visible = p.visible, overdraw = p.overdraw, depth_shift = p.depth_shift, inspectable = p.inspectable @@ -179,8 +179,8 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) onany(bbox, p.triangle_size, p.placement, p.align) do bb, s, placement, align o = origin(bb); w = widths(bb) scale!(mp, s, s, s) - - if placement === :left + + if placement === :left translate!(mp, Vec3f(o[1] + w[1], o[2] + align * w[2], 0)) rotate!(mp, qrotation(Vec3f(0,0,1), 0.5pi)) elseif placement === :right @@ -212,45 +212,45 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) # | ____ # | | - shift = if placement === :left + shift = if placement === :left Vec2f[ - (l, b + 0.5h), (l, t), (r, t), - (r, b + align * h + 0.5s), - (r + s, b + align * h), + (l, b + 0.5h), (l, t), (r, t), + (r, b + align * h + 0.5s), + (r + s, b + align * h), (r, b + align * h - 0.5s), (r, b), (l, b), (l, b + 0.5h) ] elseif placement === :right Vec2f[ - (l + 0.5w, b), (l, b), - (l, b + align * h - 0.5s), - (l-s, b + align * h), + (l + 0.5w, b), (l, b), + (l, b + align * h - 0.5s), + (l-s, b + align * h), (l, b + align * h + 0.5s), (l, t), (r, t), (r, b), (l + 0.5w, b) ] elseif placement in (:below, :down, :bottom) Vec2f[ - (l, b + 0.5h), (l, t), - (l + align * w - 0.5s, t), - (l + align * w, t+s), - (l + align * w + 0.5s, t), + (l, b + 0.5h), (l, t), + (l + align * w - 0.5s, t), + (l + align * w, t+s), + (l + align * w + 0.5s, t), (r, t), (r, b), (l, b), (l, b + 0.5h) ] elseif placement in (:above, :up, :top) Vec2f[ - (l, b + 0.5h), (l, t), (r, t), (r, b), - (l + align * w + 0.5s, b), - (l + align * w, b-s), - (l + align * w - 0.5s, b), + (l, b + 0.5h), (l, t), (r, t), (r, b), + (l + align * w + 0.5s, b), + (l + align * w, b-s), + (l + align * w - 0.5s, b), (l, b), (l, b + 0.5h) ] else @error "Tooltip placement $placement invalid. Assuming :above" Vec2f[ - (l, b + 0.5h), (l, t), (r, t), (r, b), - (l + align * w + 0.5s, b), - (l + align * w, b-s), - (l + align * w - 0.5s, b), + (l, b + 0.5h), (l, t), (r, t), (r, b), + (l + align * w + 0.5s, b), + (l + align * w, b-s), + (l + align * w - 0.5s, b), (l, b), (l, b + 0.5h) ] end @@ -259,8 +259,8 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) end lines!( - p, outline, - color = p.outline_color, space = :pixel, + p, outline, + color = p.outline_color, space = :pixel, linewidth = p.outline_linewidth, linestyle = p.outline_linestyle, transparency = p.transparency, visible = p.visible, overdraw = p.overdraw, depth_shift = p.depth_shift, diff --git a/src/basic_recipes/tricontourf.jl b/src/basic_recipes/tricontourf.jl index e808c34103e..e711345735d 100644 --- a/src/basic_recipes/tricontourf.jl +++ b/src/basic_recipes/tricontourf.jl @@ -4,7 +4,7 @@ struct DelaunayTriangulation end tricontourf(triangles::Triangulation, zs; kwargs...) tricontourf(xs, ys, zs; kwargs...) -Plots a filled tricontour of the height information in `zs` at the horizontal positions `xs` and +Plots a filled tricontour of the height information in `zs` at the horizontal positions `xs` and vertical positions `ys`. A `Triangulation` from DelaunayTriangulation.jl can also be provided instead of `xs` and `ys` for specifying the triangles, otherwise an unconstrained triangulation of `xs` and `ys` is computed. @@ -54,16 +54,16 @@ function Makie.used_attributes(::Type{<:Tricontourf}, ::AbstractVector{<:Real}, return (:triangulation,) end -function Makie.convert_arguments(::Type{<:Tricontourf}, x::AbstractVector{<:Real}, y::AbstractVector{<:Real}, z::AbstractVector{<:Real}; +function Makie.convert_arguments(::Type{<:Tricontourf}, x::AbstractVector{<:Real}, y::AbstractVector{<:Real}, z::AbstractVector{<:Real}; triangulation=DelaunayTriangulation()) z = elconvert(Float32, z) points = [x'; y'] if triangulation isa DelaunayTriangulation tri = DelTri.triangulate(points) elseif !(triangulation isa DelTri.Triangulation) - # Wrap user's provided triangulation into a Triangulation. Their triangulation must be such that DelTri.add_triangle! is defined. - if typeof(triangulation) <: AbstractMatrix{<:Int} && size(triangulation, 1) != 3 - triangulation = triangulation' + # Wrap user's provided triangulation into a Triangulation. Their triangulation must be such that DelTri.add_triangle! is defined. + if typeof(triangulation) <: AbstractMatrix{<:Int} && size(triangulation, 1) != 3 + triangulation = triangulation' end tri = DelTri.Triangulation(points) triangles = DelTri.get_triangles(tri) @@ -198,7 +198,6 @@ function Makie.plot!(c::Tricontourf{<:Tuple{<:DelTri.Triangulation, <:AbstractVe color = colors, strokewidth = 0, strokecolor = :transparent, - shading = false, inspectable = c.inspectable, transparency = c.transparency ) diff --git a/src/basic_recipes/triplot.jl b/src/basic_recipes/triplot.jl index d4e72e34284..917e3ff4265 100644 --- a/src/basic_recipes/triplot.jl +++ b/src/basic_recipes/triplot.jl @@ -189,8 +189,9 @@ function Makie.plot!(p::Triplot{<:Tuple{<:Vector{<:Point}}}) return DelTri.triangulate(transformed) end - transform = Transformation(p.transformation; transform_func=identity) - return triplot!(p, attr, tri; transformation=transform) + attr[:transformation] = Transformation(p.transformation; transform_func=identity) + triplot!(p, attr, tri) + return end function Makie.plot!(p::Triplot{<:Tuple{<:DelTri.Triangulation}}) @@ -237,4 +238,18 @@ function Makie.plot!(p::Triplot{<:Tuple{<:DelTri.Triangulation}}) scatter!(p, present_points_2f; markersize=p.markersize, color=p.markercolor, strokecolor=p.strokecolor, marker=p.marker, visible=p.show_points, depth_shift=-3.0f-5) return p +end + + +function data_limits(p::Triplot{<:Tuple{<:Vector{<:Point}}}) + if transform_func(p) isa Polar + # Because the Polar transform is handled explicitly we cannot rely + # on the default data_limits. (data limits are pre transform) + iter = (to_ndim(Point3f, p, 0f0) for p in p.converted[1][]) + limits_from_transformed_points(iter) + else + # First component is either another Voronoiplot or a poly plot. Both + # cases span the full limits of the plot + data_limits(p.plots[1]) + end end \ No newline at end of file diff --git a/src/basic_recipes/voronoiplot.jl b/src/basic_recipes/voronoiplot.jl index 0a2dd133ec3..7ce3d6f87b2 100644 --- a/src/basic_recipes/voronoiplot.jl +++ b/src/basic_recipes/voronoiplot.jl @@ -163,9 +163,8 @@ function plot!(p::Voronoiplot{<:Tuple{<:Vector{<:Point{N}}}}) where {N} return bb end end - - transform = Transformation(p.transformation; transform_func=identity) - return voronoiplot!(p, attr, vorn; transformation=transform) + attr[:transformation] = Transformation(p.transformation; transform_func=identity) + return voronoiplot!(p, attr, vorn) end function data_limits(p::Voronoiplot{<:Tuple{<:Vector{<:Point{N}}}}) where {N} diff --git a/src/bezier.jl b/src/bezier.jl index 81f18f506cc..a7754525fea 100644 --- a/src/bezier.jl +++ b/src/bezier.jl @@ -1,29 +1,31 @@ using StableHashTraits +const Point2d = Point2{Float64} + struct MoveTo - p::Point2{Float64} + p::Point2d end -MoveTo(x, y) = MoveTo(Point(x, y)) +MoveTo(x, y) = MoveTo(Point2d(x, y)) struct LineTo - p::Point2{Float64} + p::Point2d end -LineTo(x, y) = LineTo(Point(x, y)) +LineTo(x, y) = LineTo(Point2d(x, y)) struct CurveTo - c1::Point2{Float64} - c2::Point2{Float64} - p::Point2{Float64} + c1::Point2d + c2::Point2d + p::Point2d end CurveTo(cx1, cy1, cx2, cy2, p1, p2) = CurveTo( - Point(cx1, cy1), Point(cx2, cy2), Point(p1, p2) + Point2d(cx1, cy1), Point2d(cx2, cy2), Point2d(p1, p2) ) struct EllipticalArc - c::Point2{Float64} + c::Point2d r1::Float64 r2::Float64 angle::Float64 @@ -31,16 +33,88 @@ struct EllipticalArc a2::Float64 end -EllipticalArc(cx, cy, r1, r2, angle, a1, a2) = EllipticalArc(Point(cx, cy), +EllipticalArc(cx, cy, r1, r2, angle, a1, a2) = EllipticalArc(Point2d(cx, cy), r1, r2, angle, a1, a2) struct ClosePath end - const PathCommand = Union{MoveTo, LineTo, CurveTo, EllipticalArc, ClosePath} +function bbox(commands::Vector{PathCommand}) + prev = commands[1] + bb = nothing + for comm in @view(commands[2:end]) + if comm isa MoveTo || comm isa ClosePath + continue + else + endp = endpoint(prev) + _bb = cleanup_bbox(bbox(endp, comm)) + bb = bb === nothing ? _bb : union(bb, _bb) + end + prev = comm + end + return bb +end + +function elliptical_arc_to_beziers(arc::EllipticalArc) + delta_a = abs(arc.a2 - arc.a1) + n_beziers = ceil(Int, delta_a / 0.5pi) + angles = range(arc.a1, arc.a2; length=n_beziers + 1) + + startpoint = Point2f(cos(arc.a1), sin(arc.a1)) + curves = map(angles[1:(end - 1)], angles[2:end]) do start, stop + theta = stop - start + kappa = 4 / 3 * tan(theta / 4) + c1 = Point2f(cos(start) - kappa * sin(start), sin(start) + kappa * cos(start)) + c2 = Point2f(cos(stop) + kappa * sin(stop), sin(stop) - kappa * cos(stop)) + b = Point2f(cos(stop), sin(stop)) + return CurveTo(c1, c2, b) + end + + path = BezierPath([LineTo(startpoint), curves...]) + path = scale(path, Vec2{Float64}(arc.r1, arc.r2)) + path = rotate(path, arc.angle) + return translate(path, arc.c) +end + +bbox(p, x::Union{LineTo,CurveTo}) = bbox(segment(p, x)) +function bbox(p, e::EllipticalArc) + return bbox(elliptical_arc_to_beziers(e)) +end + +endpoint(m::MoveTo) = m.p +endpoint(l::LineTo) = l.p +endpoint(c::CurveTo) = c.p +function endpoint(e::EllipticalArc) + return point_at_angle(e, e.a2) +end + +function point_at_angle(e::EllipticalArc, theta) + M = abs(e.r1) * cos(theta) + N = abs(e.r2) * sin(theta) + return Point2f(e.c[1] + cos(e.angle) * M - sin(e.angle) * N, + e.c[2] + sin(e.angle) * M + cos(e.angle) * N) +end + +function cleanup_bbox(bb::Rect2f) + if any(x -> x < 0, bb.widths) + p = bb.origin .+ (bb.widths .< 0) .* bb.widths + return Rect2f(p, abs.(bb.widths)) + end + return bb +end + struct BezierPath commands::Vector{PathCommand} + boundingbox::Rect2f + hash::UInt32 + function BezierPath(commands::Vector) + c = convert(Vector{PathCommand}, commands) + return new(c, bbox(c), StableHashTraits.stable_hash(c; alg=crc32c, version=2)) + end end +bbox(x::BezierPath) = x.boundingbox +fast_stable_hash(x::BezierPath) = x.hash + # so that the same bezierpath with a different instance of a vector hashes the same # and we don't create the same texture atlas entry twice @@ -52,7 +126,7 @@ function Base.:+(pc::P, p::Point2) where P <: PathCommand return P(map(f -> getfield(pc, f) + p, fnames)...) end -scale(bp::BezierPath, s::Real) = BezierPath([scale(x, Vec(s, s)) for x in bp.commands]) +scale(bp::BezierPath, s::Real) = BezierPath([scale(x, Vec2{Float64}(s, s)) for x in bp.commands]) scale(bp::BezierPath, v::VecTypes{2}) = BezierPath([scale(x, v) for x in bp.commands]) translate(bp::BezierPath, v::VecTypes{2}) = BezierPath([translate(x, v) for x in bp.commands]) @@ -114,7 +188,7 @@ function fit_to_bbox(b::BezierPath, bb_target::Rect2; keep_aspect = true) scale_factor end - bb_t = translate(scale(translate(b, -center_path), scale_factor_aspect), center_target) + return translate(scale(translate(b, -center_path), scale_factor_aspect), center_target) end function fit_to_unit_square(b::BezierPath, keep_aspect = true) @@ -127,74 +201,13 @@ Base.:+(bp::BezierPath, p::Point2) = BezierPath(bp.commands .+ Ref(p)) # markers that fit into a square with sidelength 1 centered on (0, 0) -const BezierCircle = let - r = 0.47 # sqrt(1/pi) - BezierPath([ - MoveTo(Point(r, 0.0)), - EllipticalArc(Point(0.0, 0), r, r, 0.0, 0.0, 2pi), - ClosePath(), - ]) -end - -const BezierUTriangle = let - aspect = 1 - h = 0.97 # sqrt(aspect) * sqrt(2) - w = 0.97 # 1/sqrt(aspect) * sqrt(2) - # r = Float32(sqrt(1 / (3 * sqrt(3) / 4))) - p1 = Point(0, h/2) - p2 = Point2(-w/2, -h/2) - p3 = Point2(w/2, -h/2) - centroid = (p1 + p2 + p3) / 3 - bp = BezierPath([ - MoveTo(p1 - centroid), - LineTo(p2 - centroid), - LineTo(p3 - centroid), - ClosePath() - ]) -end - -const BezierLTriangle = rotate(BezierUTriangle, pi/2) -const BezierDTriangle = rotate(BezierUTriangle, pi) -const BezierRTriangle = rotate(BezierUTriangle, 3pi/2) - - -const BezierSquare = let - r = 0.95 * sqrt(pi)/2/2 # this gives a little less area as the r=0.5 circle - BezierPath([ - MoveTo(Point2(r, -r)), - LineTo(Point2(r, r)), - LineTo(Point2(-r, r)), - LineTo(Point2(-r, -r)), - ClosePath() - ]) -end - -const BezierCross = let - cutfraction = 2/3 - r = 0.5 # 1/(2 * sqrt(1 - cutfraction^2)) - ri = 0.166 #r * (1 - cutfraction) - - first_three = Point2[(r, ri), (ri, ri), (ri, r)] - all = map(0:pi/2:3pi/2) do a - m = Mat2f(sin(a), cos(a), cos(a), -sin(a)) - Ref(m) .* first_three - end |> x -> reduce(vcat, x) - - BezierPath([ - MoveTo(all[1]), - LineTo.(all[2:end])..., - ClosePath() - ]) -end - -const BezierX = rotate(BezierCross, pi/4) function bezier_ngon(n, radius, angle) points = [radius * Point2f(cos(a + angle), sin(a + angle)) for a in range(0, 2pi, length = n+1)[1:end-1]] BezierPath([ MoveTo(points[1]); - LineTo.(points[2:end]); + LineTo.(@view points[2:end]); ClosePath() ]) end @@ -239,10 +252,10 @@ function BezierPath(svg::AbstractString; fit = false, bbox = nothing, flipy = fa commands = parse_bezier_commands(svg) p = BezierPath(commands) if flipy - p = scale(p, Vec(1, -1)) + p = scale(p, Vec2{Float64}(1, -1)) end if flipx - p = scale(p, Vec(-1, 1)) + p = scale(p, Vec2{Float64}(-1, 1)) end if fit if bbox === nothing @@ -264,27 +277,29 @@ function parse_bezier_commands(svg) commands = PathCommand[] lastcomm = nothing function lastp() - c = commands[end] if isnothing(lastcomm) - Point(0, 0) - elseif c isa ClosePath - r = reverse(commands) - backto = findlast(x -> !(x isa ClosePath), r) - if isnothing(backto) - error("No point to go back to") - end - r[backto].p - elseif c isa EllipticalArc - let - ϕ = c.angle - a2 = c.a2 - rx = c.r1 - ry = c.r2 - m = Mat2(cos(ϕ), sin(ϕ), -sin(ϕ), cos(ϕ)) - m * Point(rx * cos(a2), ry * sin(a2)) + c.c - end + Point2d(0, 0) else - c.p + c = commands[end] + if c isa ClosePath + r = reverse(commands) + backto = findlast(x -> !(x isa ClosePath), r) + if isnothing(backto) + error("No point to go back to") + end + r[backto].p + elseif c isa EllipticalArc + let + ϕ = c.angle + a2 = c.a2 + rx = c.r1 + ry = c.r2 + m = Mat2(cos(ϕ), sin(ϕ), -sin(ϕ), cos(ϕ)) + return m * Point2d(rx * cos(a2), ry * sin(a2)) + c.c + end + else + return c.p + end end end @@ -300,27 +315,27 @@ function parse_bezier_commands(svg) if comm == "M" x, y = parse.(Float64, args[i+1:i+2]) - push!(commands, MoveTo(Point2(x, y))) + push!(commands, MoveTo(Point2d(x, y))) i += 3 elseif comm == "m" x, y = parse.(Float64, args[i+1:i+2]) - push!(commands, MoveTo(Point2(x, y) + lastp())) + push!(commands, MoveTo(Point2d(x, y) + lastp())) i += 3 elseif comm == "L" x, y = parse.(Float64, args[i+1:i+2]) - push!(commands, LineTo(Point2(x, y))) + push!(commands, LineTo(Point2d(x, y))) i += 3 elseif comm == "l" x, y = parse.(Float64, args[i+1:i+2]) - push!(commands, LineTo(Point2(x, y) + lastp())) + push!(commands, LineTo(Point2d(x, y) + lastp())) i += 3 elseif comm == "H" x = parse(Float64, args[i+1]) - push!(commands, LineTo(Point2(x, lastp()[2]))) + push!(commands, LineTo(Point2d(x, lastp()[2]))) i += 2 elseif comm == "h" x = parse(Float64, args[i+1]) - push!(commands, LineTo(X(x) + lastp())) + push!(commands, LineTo(Point2d(x, 0) + lastp())) i += 2 elseif comm == "Z" push!(commands, ClosePath()) @@ -330,25 +345,25 @@ function parse_bezier_commands(svg) i += 1 elseif comm == "C" x1, y1, x2, y2, x3, y3 = parse.(Float64, args[i+1:i+6]) - push!(commands, CurveTo(Point2(x1, y1), Point2(x2, y2), Point2(x3, y3))) + push!(commands, CurveTo(Point2d(x1, y1), Point2d(x2, y2), Point2d(x3, y3))) i += 7 elseif comm == "c" x1, y1, x2, y2, x3, y3 = parse.(Float64, args[i+1:i+6]) l = lastp() - push!(commands, CurveTo(Point2(x1, y1) + l, Point2(x2, y2) + l, Point2(x3, y3) + l)) + push!(commands, CurveTo(Point2d(x1, y1) + l, Point2d(x2, y2) + l, Point2d(x3, y3) + l)) i += 7 elseif comm == "S" x1, y1, x2, y2 = parse.(Float64, args[i+1:i+4]) prev = commands[end] reflected = prev.p + (prev.p - prev.c2) - push!(commands, CurveTo(reflected, Point2(x1, y1), Point2(x2, y2))) + push!(commands, CurveTo(reflected, Point2d(x1, y1), Point2d(x2, y2))) i += 5 elseif comm == "s" x1, y1, x2, y2 = parse.(Float64, args[i+1:i+4]) prev = commands[end] reflected = prev.p + (prev.p - prev.c2) l = lastp() - push!(commands, CurveTo(reflected, Point2(x1, y1) + l, Point2(x2, y2) + l)) + push!(commands, CurveTo(reflected, Point2d(x1, y1) + l, Point2d(x2, y2) + l)) i += 5 elseif comm == "A" args[i+1:i+7] @@ -374,12 +389,12 @@ function parse_bezier_commands(svg) elseif comm == "v" dy = parse(Float64, args[i+1]) l = lastp() - push!(commands, LineTo(Point2(l[1], l[2] + dy))) + push!(commands, LineTo(Point2d(l[1], l[2] + dy))) i += 2 elseif comm == "V" y = parse(Float64, args[i+1]) l = lastp() - push!(commands, LineTo(Point2(l[1], y))) + push!(commands, LineTo(Point2d(l[1], y))) i += 2 else for c in commands @@ -398,8 +413,8 @@ end function EllipticalArc(x1, y1, x2, y2, rx, ry, ϕ, largearc::Bool, sweepflag::Bool) # https://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - p1 = Point(x1, y1) - p2 = Point(x2, y2) + p1 = Point2d(x1, y1) + p2 = Point2d(x2, y2) m1 = Mat2(cos(ϕ), -sin(ϕ), sin(ϕ), cos(ϕ)) x1′, y1′ = m1 * (0.5 * (p1 - p2)) @@ -408,16 +423,16 @@ function EllipticalArc(x1, y1, x2, y2, rx, ry, ϕ, largearc::Bool, sweepflag::Bo (rx^2 * y1′^2 + ry^2 * x1′^2) c′ = (largearc == sweepflag ? -1 : 1) * - sqrt(tempsqrt) * Point(rx * y1′ / ry, -ry * x1′ / rx) + sqrt(tempsqrt) * Point2d(rx * y1′ / ry, -ry * x1′ / rx) c = Mat2(cos(ϕ), sin(ϕ), -sin(ϕ), cos(ϕ)) * c′ + 0.5 * (p1 + p2) vecangle(u, v) = sign(u[1] * v[2] - u[2] * v[1]) * acos(dot(u, v) / (norm(u) * norm(v))) - px(sign) = Point((sign * x1′ - c′[1]) / rx, (sign * y1′ - c′[2]) / rx) + px(sign) = Point2d((sign * x1′ - c′[1]) / rx, (sign * y1′ - c′[2]) / rx) - θ1 = vecangle(Point(1.0, 0.0), px(1)) + θ1 = vecangle(Point2d(1.0, 0.0), px(1)) Δθ_pre = mod(vecangle(px(1), px(-1)), 2pi) Δθ = if Δθ_pre > 0 && !sweepflag Δθ_pre - 2pi @@ -440,7 +455,6 @@ function make_outline(path) points = FT_Vector[] tags = Int8[] contours = Int16[] - flags = Int32(0) for command in path.commands new_contour, n_newpoints, newpoints, newtags = convert_command(command) if new_contour @@ -489,13 +503,13 @@ function render_path(path, bitmap_size_px = 256) scale_factor = bitmap_size_px * 64 # We transform the path into a rectangle of size (aspect, 1) or (1, aspect) - # such that aspect ≤ 1. We then scale that rectangle up to a size of 4096 by + # such that aspect ≤ 1. We then scale that rectangle up to a size of 4096 by # 4096 * aspect, which results in at most a 64px by 64px bitmap # freetype has no ClosePath and EllipticalArc, so those need to be replaced path_replaced = replace_nonfreetype_commands(path) - # Minimal size that becomes integer when mutliplying by 64 (target size for + # Minimal size that becomes integer when mutliplying by 64 (target size for # atlas). This adds padding to avoid blurring/scaling factors from rounding # during sdf generation path_size = widths(bbox(path)) / maximum(widths(bbox(path))) @@ -512,7 +526,7 @@ function render_path(path, bitmap_size_px = 256) # Adjust bitmap size to match path size w = ceil(Int, bitmap_size_px * path_size[1]) h = ceil(Int, bitmap_size_px * path_size[2]) - + pitch = w * 1 # 8 bit gray pixelbuffer = zeros(UInt8, h * pitch) bitmap_ref = Ref{FT_Bitmap}() @@ -579,60 +593,12 @@ struct LineSegment to::Point2f end -function bbox(b::BezierPath) - prev = b.commands[1] - bb = nothing - for comm in b.commands[2:end] - if comm isa MoveTo || comm isa ClosePath - continue - else - endp = endpoint(prev) - _bb = cleanup_bbox(bbox(endp, comm)) - bb = bb === nothing ? _bb : union(bb, _bb) - end - prev = comm - end - bb -end - -segment(p, l::LineTo) = LineSegment(p, l.p) -segment(p, c::CurveTo) = BezierSegment(p, c.c1, c.c2, c.p) - -endpoint(m::MoveTo) = m.p -endpoint(l::LineTo) = l.p -endpoint(c::CurveTo) = c.p -function endpoint(e::EllipticalArc) - point_at_angle(e, e.a2) -end - -function point_at_angle(e::EllipticalArc, theta) - M = abs(e.r1) * cos(theta) - N = abs(e.r2) * sin(theta) - Point2f( - e.c[1] + cos(e.angle) * M - sin(e.angle) * N, - e.c[2] + sin(e.angle) * M + cos(e.angle) * N - ) -end - -function cleanup_bbox(bb::Rect2f) - if any(x -> x < 0, bb.widths) - p = bb.origin .+ (bb.widths .< 0) .* bb.widths - return Rect2f(p, abs.(bb.widths)) - end - return bb -end - -bbox(p, x::Union{LineTo, CurveTo}) = bbox(segment(p, x)) -function bbox(p, e::EllipticalArc) - bbox(elliptical_arc_to_beziers(e)) -end function bbox(ls::LineSegment) - Rect2f(ls.from, ls.to - ls.from) + return Rect2f(ls.from, ls.to - ls.from) end function bbox(b::BezierSegment) - p0 = b.from p1 = b.c1 p2 = b.c2 @@ -642,68 +608,103 @@ function bbox(b::BezierSegment) ma = [max.(p0, p3)...] c = -p0 + p1 - b = p0 - 2p1 + p2 + b = p0 - 2p1 + p2 a = -p0 + 3p1 - 3p2 + 1p3 - h = [(b.*b - a.*c)...] + h = [(b .* b - a .* c)...] if h[1] > 0 h[1] = sqrt(h[1]) t = (-b[1] - h[1]) / a[1] if t > 0 && t < 1 - s = 1.0-t - q = s*s*s*p0[1] + 3.0*s*s*t*p1[1] + 3.0*s*t*t*p2[1] + t*t*t*p3[1] - mi[1] = min(mi[1],q) - ma[1] = max(ma[1],q) + s = 1.0 - t + q = s * s * s * p0[1] + 3.0 * s * s * t * p1[1] + 3.0 * s * t * t * p2[1] + t * t * t * p3[1] + mi[1] = min(mi[1], q) + ma[1] = max(ma[1], q) end - t = (-b[1] + h[1])/a[1] - if t>0 && t<1 - s = 1.0-t - q = s*s*s*p0[1] + 3.0*s*s*t*p1[1] + 3.0*s*t*t*p2[1] + t*t*t*p3[1] - mi[1] = min(mi[1],q) - ma[1] = max(ma[1],q) + t = (-b[1] + h[1]) / a[1] + if t > 0 && t < 1 + s = 1.0 - t + q = s * s * s * p0[1] + 3.0 * s * s * t * p1[1] + 3.0 * s * t * t * p2[1] + t * t * t * p3[1] + mi[1] = min(mi[1], q) + ma[1] = max(ma[1], q) end end - if h[2]>0.0 + if h[2] > 0.0 h[2] = sqrt(h[2]) - t = (-b[2] - h[2])/a[2] - if t>0.0 && t<1.0 - s = 1.0-t - q = s*s*s*p0[2] + 3.0*s*s*t*p1[2] + 3.0*s*t*t*p2[2] + t*t*t*p3[2] - mi[2] = min(mi[2],q) - ma[2] = max(ma[2],q) + t = (-b[2] - h[2]) / a[2] + if t > 0.0 && t < 1.0 + s = 1.0 - t + q = s * s * s * p0[2] + 3.0 * s * s * t * p1[2] + 3.0 * s * t * t * p2[2] + t * t * t * p3[2] + mi[2] = min(mi[2], q) + ma[2] = max(ma[2], q) end - t = (-b[2] + h[2])/a[2] - if t>0.0 && t<1.0 - s = 1.0-t - q = s*s*s*p0[2] + 3.0*s*s*t*p1[2] + 3.0*s*t*t*p2[2] + t*t*t*p3[2] - mi[2] = min(mi[2],q) - ma[2] = max(ma[2],q) + t = (-b[2] + h[2]) / a[2] + if t > 0.0 && t < 1.0 + s = 1.0 - t + q = s * s * s * p0[2] + 3.0 * s * s * t * p1[2] + 3.0 * s * t * t * p2[2] + t * t * t * p3[2] + mi[2] = min(mi[2], q) + ma[2] = max(ma[2], q) end end - Rect2f(Point(mi...), Point(ma...) - Point(mi...)) + return Rect2f(Point(mi...), Point(ma...) - Point(mi...)) end +segment(p, l::LineTo) = LineSegment(p, l.p) +segment(p, c::CurveTo) = BezierSegment(p, c.c1, c.c2, c.p) -function elliptical_arc_to_beziers(arc::EllipticalArc) - delta_a = abs(arc.a2 - arc.a1) - n_beziers = ceil(Int, delta_a / 0.5pi) - angles = range(arc.a1, arc.a2, length = n_beziers + 1) - startpoint = Point2f(cos(arc.a1), sin(arc.a1)) - curves = map(angles[1:end-1], angles[2:end]) do start, stop - theta = stop - start - kappa = 4/3 * tan(theta/4) - c1 = Point2f(cos(start) - kappa * sin(start), sin(start) + kappa * cos(start)) - c2 = Point2f(cos(stop) + kappa * sin(stop), sin(stop) - kappa * cos(stop)) - b = Point2f(cos(stop), sin(stop)) - CurveTo(c1, c2, b) - end +const BezierCircle = let + r = 0.47 # sqrt(1/pi) + BezierPath([MoveTo(Point(r, 0.0)), + EllipticalArc(Point(0.0, 0), r, r, 0.0, 0.0, 2pi), + ClosePath()]) +end - path = BezierPath([LineTo(startpoint), curves...]) - path = scale(path, Vec(arc.r1, arc.r2)) - path = rotate(path, arc.angle) - path = translate(path, arc.c) +const BezierUTriangle = let + aspect = 1 + h = 0.97 # sqrt(aspect) * sqrt(2) + w = 0.97 # 1/sqrt(aspect) * sqrt(2) + # r = Float32(sqrt(1 / (3 * sqrt(3) / 4))) + p1 = Point(0, h / 2) + p2 = Point2d(-w / 2, -h / 2) + p3 = Point2d(w / 2, -h / 2) + centroid = (p1 + p2 + p3) / 3 + bp = BezierPath([MoveTo(p1 - centroid), + LineTo(p2 - centroid), + LineTo(p3 - centroid), + ClosePath()]) end + +const BezierLTriangle = rotate(BezierUTriangle, pi / 2) +const BezierDTriangle = rotate(BezierUTriangle, pi) +const BezierRTriangle = rotate(BezierUTriangle, 3pi / 2) + +const BezierSquare = let + r = 0.95 * sqrt(pi) / 2 / 2 # this gives a little less area as the r=0.5 circle + BezierPath([MoveTo(Point2d(r, -r)), + LineTo(Point2d(r, r)), + LineTo(Point2d(-r, r)), + LineTo(Point2d(-r, -r)), + ClosePath()]) +end + +const BezierCross = let + cutfraction = 2 / 3 + r = 0.5 # 1/(2 * sqrt(1 - cutfraction^2)) + ri = 0.166 #r * (1 - cutfraction) + + first_three = Point2d[(r, ri), (ri, ri), (ri, r)] + all = (x -> reduce(vcat, x))(map(0:(pi / 2):(3pi / 2)) do a + m = Mat2f(sin(a), cos(a), cos(a), -sin(a)) + return Ref(m) .* first_three + end) + + BezierPath([MoveTo(all[1]), + LineTo.(all[2:end])..., + ClosePath()]) +end + +const BezierX = rotate(BezierCross, pi / 4) diff --git a/src/camera/camera.jl b/src/camera/camera.jl index 48d63063fa7..2d75f3dc9ca 100644 --- a/src/camera/camera.jl +++ b/src/camera/camera.jl @@ -1,5 +1,5 @@ function Base.copy(x::Camera) - Camera(ntuple(7) do i + Camera(ntuple(9) do i getfield(x, i) end...) end @@ -18,6 +18,7 @@ function Base.show(io::IO, camera::Camera) println(io, " projection: ", camera.projection[]) println(io, " projectionview: ", camera.projectionview[]) println(io, " resolution: ", camera.resolution[]) + println(io, " lookat: ", camera.lookat[]) println(io, " eyeposition: ", camera.eyeposition[]) end @@ -67,8 +68,8 @@ function Observables.on(f, camera::Camera, observables::AbstractObservable...; p return f end -function Camera(px_area) - pixel_space = lift(px_area) do window_size +function Camera(viewport) + pixel_space = lift(viewport) do window_size nearclip = -10_000f0 farclip = 10_000f0 w, h = Float32.(widths(window_size)) @@ -82,9 +83,11 @@ function Camera(px_area) view, proj, proj_view, - lift(a-> Vec2f(widths(a)), px_area), + lift(a-> Vec2f(widths(a)), viewport), + Observable(Vec3f(0)), Observable(Vec3f(1)), - ObserverFunction[] + ObserverFunction[], + Dict{Symbol, Observable}() ) end @@ -100,7 +103,7 @@ end is_mouseinside(x, target) = is_mouseinside(get_scene(x), target) function is_mouseinside(scene::Scene, target) scene === target && return false - Vec(scene.events.mouseposition[]) in pixelarea(scene)[] || return false + Vec(scene.events.mouseposition[]) in viewport(scene)[] || return false for child in r.children is_mouseinside(child, target) && return true end @@ -114,7 +117,7 @@ Returns true if the current mouseposition is inside the given scene. """ is_mouseinside(x) = is_mouseinside(get_scene(x)) function is_mouseinside(scene::Scene) - return Vec(scene.events.mouseposition[]) in pixelarea(scene)[] + return Vec(scene.events.mouseposition[]) in viewport(scene)[] # Check that mouse is not inside any other screen # for child in scene.children # is_mouseinside(child) && return false diff --git a/src/camera/camera2d.jl b/src/camera/camera2d.jl index ff276348d94..d9d354a180f 100644 --- a/src/camera/camera2d.jl +++ b/src/camera/camera2d.jl @@ -1,8 +1,8 @@ struct Camera2D <: AbstractCamera area::Observable{Rect2f} zoomspeed::Observable{Float32} - zoombutton::Observable{ButtonTypes} - panbutton::Observable{Union{ButtonTypes, Vector{ButtonTypes}}} + zoombutton::Observable{IsPressedInputType} + panbutton::Observable{IsPressedInputType} padding::Observable{Float32} last_area::Observable{Vec{2, Int}} update_limits::Observable{Bool} @@ -11,14 +11,23 @@ end """ cam2d!(scene::SceneLike, kwargs...) -Creates a 2D camera for the given Scene. +Creates a 2D camera for the given `scene`. The camera implements zooming by +scrolling and translation using mouse drag. It also implements rectangle +selections. + +## Keyword Arguments + +- `zoomspeed = 0.1f0` sets the zoom speed. +- `zoombutton = true` sets a button (combination) which needs to be pressed to enable zooming. By default no button needs to be pressed. +- `panbutton = Mouse.right` sets the button used to translate the camera. This must include a mouse button. +- `selectionbutton = (Keyboard.space, Mouse.left)` sets the button used for rectangle selection. This must include a mouse button. """ function cam2d!(scene::SceneLike; kw_args...) cam_attributes = merged_get!(:cam2d, scene, Attributes(kw_args)) do Attributes( area = Observable(Rectf(0, 0, 1, 1)), zoomspeed = 0.10f0, - zoombutton = nothing, + zoombutton = true, panbutton = Mouse.right, selectionbutton = (Keyboard.space, Mouse.left), padding = 0.001, @@ -37,6 +46,7 @@ function cam2d!(scene::SceneLike; kw_args...) cam end +get_space(::Camera2D) = :data wscale(screenrect, viewrect) = widths(viewrect) ./ widths(screenrect) @@ -45,7 +55,14 @@ wscale(screenrect, viewrect) = widths(viewrect) ./ widths(screenrect) Updates the camera for the given `scene` to cover the given `area` in 2d. """ -update_cam!(scene::SceneLike, area) = update_cam!(scene, cameracontrols(scene), area) +function update_cam!(scene::SceneLike, area::Rect) + return update_cam!(scene, cameracontrols(scene), area) +end +function update_cam!(scene::SceneLike, area::Rect, center::Bool) + return update_cam!(scene, cameracontrols(scene), area, center) +end + + """ update_cam!(scene::SceneLike) @@ -60,7 +77,7 @@ function update_cam!(scene::Scene, cam::Camera2D, area3d::Rect) # ignore rects with width almost 0 any(x-> x ≈ 0.0, widths(area)) && return - pa = pixelarea(scene)[] + pa = viewport(scene)[] px_wh = normalize(widths(pa)) wh = normalize(widths(area)) ratio = px_wh ./ wh @@ -89,7 +106,7 @@ function update_cam!(scene::SceneLike, cam::Camera2D) end function correct_ratio!(scene, cam) - on(camera(scene), pixelarea(scene)) do area + on(camera(scene), viewport(scene)) do area neww = widths(area) change = neww .- cam.last_area[] if !(change ≈ Vec(0.0, 0.0)) @@ -123,7 +140,7 @@ function add_pan!(scene::SceneLike, cam::Camera2D) diff = startpos[] .- mp startpos[] = mp area = cam.area[] - diff = Vec(diff) .* wscale(pixelarea(scene)[], area) + diff = Vec(diff) .* wscale(viewport(scene)[], area) cam.area[] = Rectf(minimum(area) .+ diff, widths(area)) update_cam!(scene, cam) active[] = false @@ -141,7 +158,7 @@ function add_pan!(scene::SceneLike, cam::Camera2D) diff = startpos[] .- pos startpos[] = pos area = cam.area[] - diff = Vec(diff) .* wscale(pixelarea(scene)[], area) + diff = Vec(diff) .* wscale(viewport(scene)[], area) cam.area[] = Rectf(minimum(area) .+ diff, widths(area)) update_cam!(scene, cam) return Consume(true) @@ -156,7 +173,7 @@ function add_zoom!(scene::SceneLike, cam::Camera2D) @extractvalue cam (zoomspeed, zoombutton, area) zoom = Float32(x[2]) if zoom != 0 && ispressed(scene, zoombutton) && is_mouseinside(scene) - pa = pixelarea(scene)[] + pa = viewport(scene)[] z = (1f0 - zoomspeed)^zoom mp = Vec2f(e.mouseposition[]) - minimum(pa) mp = (mp .* wscale(pa, area)) + minimum(area) @@ -173,7 +190,7 @@ function add_zoom!(scene::SceneLike, cam::Camera2D) end function camspace(scene::SceneLike, cam::Camera2D, point) - point = Vec(point) .* wscale(pixelarea(scene)[], cam.area[]) + point = Vec(point) .* wscale(viewport(scene)[], cam.area[]) return Vec(point) .+ Vec(minimum(cam.area[])) end @@ -301,6 +318,7 @@ function add_restriction!(cam, window, rarea::Rect2, minwidths::Vec) end struct PixelCamera <: AbstractCamera end +get_space(::PixelCamera) = :pixel struct UpdatePixelCam @@ -308,6 +326,7 @@ struct UpdatePixelCam near::Float32 far::Float32 end +get_space(::UpdatePixelCam) = :pixel function (cam::UpdatePixelCam)(window_size) w, h = Float32.(widths(window_size)) @@ -318,27 +337,31 @@ end """ campixel!(scene; nearclip=-1000f0, farclip=1000f0) -Creates a pixel-level camera for the `Scene`. No controls! +Creates a pixel camera for the given `scene`. This means that the positional +data of a plot will be interpreted in pixel units. This camera does not feature +controls. """ function campixel!(scene::Scene; nearclip=-10_000f0, farclip=10_000f0) disconnect!(camera(scene)) update_once = Observable(false) closure = UpdatePixelCam(camera(scene), nearclip, farclip) - on(closure, camera(scene), pixelarea(scene)) + on(closure, camera(scene), viewport(scene)) cam = PixelCamera() # update once - closure(pixelarea(scene)[]) + closure(viewport(scene)[]) cameracontrols!(scene, cam) update_once[] = true return cam end struct RelativeCamera <: AbstractCamera end +get_space(::RelativeCamera) = :relative """ cam_relative!(scene) -Creates a pixel-level camera for the `Scene`. No controls! +Creates a camera for the given `scene` which maps the scene area to a 0..1 by +0..1 range. This camera does not feature controls. """ function cam_relative!(scene::Scene; nearclip=-10_000f0, farclip=10_000f0) projection = orthographicprojection(0f0, 1f0, 0f0, 1f0, nearclip, farclip) diff --git a/src/camera/camera3d.jl b/src/camera/camera3d.jl index d1e6fe43ee0..2232cb35208 100644 --- a/src/camera/camera3d.jl +++ b/src/camera/camera3d.jl @@ -1,36 +1,66 @@ -struct Camera3D <: AbstractCamera +abstract type AbstractCamera3D <: AbstractCamera end + +get_space(::AbstractCamera3D) = :data + +struct Camera3D <: AbstractCamera3D + # User settings + settings::Attributes + controls::Attributes + + # Interactivity + pulser::Observable{Float64} + selected::Observable{Bool} + + # view matrix eyeposition::Observable{Vec3f} lookat::Observable{Vec3f} upvector::Observable{Vec3f} - zoom_mult::Observable{Float32} - fov::Observable{Float32} # WGLMakie compat + # perspective projection matrix + fov::Observable{Float32} near::Observable{Float32} far::Observable{Float32} - pulser::Observable{Float64} - - attributes::Attributes + bounding_sphere::Observable{Sphere{Float32}} end """ - Camera3D(scene[; attributes...]) + Camera3D(scene[; kwargs...]) -Creates a 3d camera with a lot of controls. +Sets up a 3D camera with mouse and keyboard controls. -The 3D camera is (or can be) unrestricted in terms of rotations and translations. Both `cam3d!(scene)` and `cam3d_cad!(scene)` create this camera type. Unlike the 2D camera, settings and controls are stored in the `cam.attributes` field rather than in the struct directly, but can still be passed as keyword arguments. The general camera settings include +The behavior of the camera can be adjusted via keyword arguments or the fields +`settings` and `controls`. + +## Settings + +Settings include anything that isn't a mouse or keyboard button. -- `fov = 45f0` sets the "neutral" field of view, i.e. the fov corresponding to no zoom. This is irrelevant if the camera uses an orthographic projection. -- `near = automatic` sets the value of the near clip. By default this will be chosen based on the scenes bounding box. The final value is in `cam.near`. -- `far = automatic` sets the value of the far clip. By default this will be chosen based on the scenes bounding box. The final value is in `cam.far`. -- `rotation_center = :lookat` sets the default center for camera rotations. Currently allows `:lookat` or `:eyeposition`. - `projectiontype = Perspective` sets the type of the projection. Can be `Orthographic` or `Perspective`. -- `fixed_axis = false`: If true panning uses the (world/plot) z-axis instead of the camera up direction. -- `zoom_shift_lookat = true`: If true attempts to keep data under the cursor in view when zooming. +- `rotation_center = :lookat` sets the default center for camera rotations. Currently allows `:lookat` or `:eyeposition`. +- `fixed_axis = true`: If true panning uses the (world/plot) z-axis instead of the camera up direction. +- `zoom_shift_lookat = true`: If true keeps the data under the cursor when zooming. - `cad = false`: If true rotates the view around `lookat` when zooming off-center. +- `clipping_mode = :adaptive`: Controls how `near` and `far` get processed. Options: + - `:static` passes `near` and `far` as is + - `:adaptive` scales `near` by `norm(eyeposition - lookat)` and passes `far` as is + - `:view_relative` scales `near` and `far` by `norm(eyeposition - lookat)` + - `:bbox_relative` scales `near` and `far` to the scene bounding box as passed to the camera with `update_cam!(..., bbox)`. (More specifically `far = 1` is scaled to the furthest point of a bounding sphere and `near` is generally overwritten to be the closest point.) +- `center = true`: Controls whether the camera placement gets reset when calling `update_cam!(scene[, cam], bbox)`, which is called when a new plot is added. This is automatically set to `false` after calling `update_cam!(scene[, cam], eyepos, lookat[, up])`. -The camera view follows from the position of the camera `eyeposition`, the point which the camera focuses `lookat` and the up direction of the camera `upvector`. These can be accessed as `cam.eyeposition` etc and adjusted via `update_cam!(scene, cameracontrols(scene), eyeposition, lookat[, upvector = Vec3f(0, 0, 1)])`. They can also be passed as keyword arguments when the camera is constructed. +- `keyboard_rotationspeed = 1f0` sets the speed of keyboard based rotations. +- `keyboard_translationspeed = 0.5f0` sets the speed of keyboard based translations. +- `keyboard_zoomspeed = 1f0` sets the speed of keyboard based zooms. -The camera can be controlled by keyboard and mouse. The keyboard has the following available attributes +- `mouse_rotationspeed = 1f0` sets the speed of mouse rotations. +- `mouse_translationspeed = 0.5f0` sets the speed of mouse translations. +- `mouse_zoomspeed = 1f0` sets the speed of mouse zooming (mousewheel). + +- `update_rate = 1/30` sets the rate at which keyboard based camera updates are evaluated. +- `circular_rotation = (true, true, true)` enables circular rotations for (fixed x, fixed y, fixed z) rotation axis. (This means drawing a circle with your mouse around the center of the scene will result in a continuous rotation.) + +## Controls + +Controls include any kind of hotkey setting. - `up_key = Keyboard.r` sets the key for translations towards the top of the screen. - `down_key = Keyboard.f` sets the key for translations towards the bottom of the screen. @@ -39,10 +69,10 @@ The camera can be controlled by keyboard and mouse. The keyboard has the followi - `forward_key = Keyboard.w` sets the key for translations into the screen. - `backward_key = Keyboard.s` sets the key for translations out of the screen. -- `zoom_in_key = Keyboard.u` sets the key for zooming into the scene (enlarge, via fov). -- `zoom_out_key = Keyboard.o` sets the key for zooming out of the scene (shrink, via fov). -- `stretch_view_key = Keyboard.page_up` sets the key for moving `eyepostion` away from `lookat`. -- `contract_view_key = Keyboard.page_down` sets the key for moving `eyeposition` towards `lookat`. +- `zoom_in_key = Keyboard.u` sets the key for zooming into the scene (translate eyeposition towards lookat). +- `zoom_out_key = Keyboard.o` sets the key for zooming out of the scene (translate eyeposition away from lookat). +- `increase_fov_key = Keyboard.b` sets the key for increasing the fov. +- `decrease_fov_key = Keyboard.n` sets the key for decreasing the fov. - `pan_left_key = Keyboard.j` sets the key for rotations around the screens vertical axis. - `pan_right_key = Keyboard.l` sets the key for rotations around the screens vertical axis. @@ -51,101 +81,123 @@ The camera can be controlled by keyboard and mouse. The keyboard has the followi - `roll_clockwise_key = Keyboard.e` sets the key for rotations of the screen. - `roll_counterclockwise_key = Keyboard.q` sets the key for rotations of the screen. -- `keyboard_rotationspeed = 1f0` sets the speed of keyboard based rotations. -- `keyboard_translationspeed = 0.5f0` sets the speed of keyboard based translations. -- `keyboard_zoomspeed = 1f0` sets the speed of keyboard based zooms. -- `update_rate = 1/30` sets the rate at which keyboard based camera updates are evaluated. - -and mouse interactions are controlled by +- `fix_x_key = Keyboard.x` sets the key for fixing translations and rotations to the (world/plot) x-axis. +- `fix_y_key = Keyboard.y` sets the key for fixing translations and rotations to the (world/plot) y-axis. +- `fix_z_key = Keyboard.z` sets the key for fixing translations and rotations to the (world/plot) z-axis. +- `reset = Keyboard.left_control & Mouse.left` sets the key for resetting the camera. This equivalent to calling `center!(scene)`. +- `reposition_button = Keyboard.left_alt & Mouse.left` sets the key for focusing the camera on a plot object. - `translation_button = Mouse.right` sets the mouse button for drag-translations. (up/down/left/right) - `scroll_mod = true` sets an additional modifier button for scroll-based zoom. (true being neutral) - `rotation_button = Mouse.left` sets the mouse button for drag-rotations. (pan, tilt) -- `mouse_rotationspeed = 1f0` sets the speed of mouse rotations. -- `mouse_translationspeed = 0.5f0` sets the speed of mouse translations. -- `mouse_zoomspeed = 1f0` sets the speed of mouse zooming (mousewheel). -- `circular_rotation = (true, true, true)` enables circular rotations for (fixed x, fixed y, fixed z) rotation axis. (This means drawing a circle with your mouse around the center of the scene will result in a continuous rotation.) +## Other kwargs -There are also a few generally applicable controls: +Some keyword arguments are used to initialize fields. These include -- `fix_x_key = Keyboard.x` sets the key for fixing translations and rotations to the (world/plot) x-axis. -- `fix_y_key = Keyboard.y` sets the key for fixing translations and rotations to the (world/plot) y-axis. -- `fix_z_key = Keyboard.z` sets the key for fixing translations and rotations to the (world/plot) z-axis. -- `reset = Keyboard.home` sets the key for fully resetting the camera. This equivalent to setting `lookat = Vec3f(0)`, `upvector = Vec3f(0, 0, 1)`, `eyeposition = Vec3f(3)` and then calling `center!(scene)`. +- `eyeposition = Vec3f(3)`: The position of the camera. +- `lookat = Vec3f(0)`: The point the camera is focused on. +- `upvector = Vec3f(0, 0, 1)`: The world direction corresponding to the up direction of the screen. -You can also make adjustments to the camera position, rotation and zoom by calling relevant functions: +- `fov = 45.0` is the field of view. This is irrelevant if the camera uses an orthographic projection. +- `near = automatic` sets the position of the near clip plane. Anything between the camera and the near clip plane is hidden. Must be greater 0. Usage depends on `clipping_mode`. +- `far = automatic` sets the position of the far clip plane. Anything further away than the far clip plane is hidden. Usage depends on `clipping_mode`. Defaults to `1` for `clipping_mode = :bbox_relative`, `2` for `:view_relative` or a value derived from limits for `:static`. + +Note that updating these observables in an active camera requires a call to `update_cam(scene)` +for them to be applied. For updating `eyeposition`, `lookat` and/or upvector +`update_cam!(scene, eyeposition, lookat, upvector = Vec3f(0,0,1))` is preferred. + +The camera position and orientation can also be adjusted via the functions - `translate_cam!(scene, v)` will translate the camera by the given world/plot space vector `v`. - `rotate_cam!(scene, angles)` will rotate the camera around its axes with the corresponding angles. The first angle will rotate around the cameras "right" that is the screens horizontal axis, the second around the up vector/vertical axis or `Vec3f(0, 0, +-1)` if `fixed_axis = true`, and the third will rotate around the view direction i.e. the axis out of the screen. The rotation respects the current `rotation_center` of the camera. - `zoom!(scene, zoom_step)` will change the zoom level of the scene without translating or rotating the scene. `zoom_step` applies multiplicatively to `cam.zoom_mult` which is used as a multiplier to the fov (perspective projection) or width and height (orthographic projection). """ function Camera3D(scene::Scene; kwargs...) - attr = merged_get!(:cam3d, scene, Attributes(kwargs)) do - Attributes( - # Keyboard controls - # Translations - up_key = Keyboard.r, - down_key = Keyboard.f, - left_key = Keyboard.a, - right_key = Keyboard.d, - forward_key = Keyboard.w, - backward_key = Keyboard.s, - # Zooms - zoom_in_key = Keyboard.u, - zoom_out_key = Keyboard.o, - stretch_view_key = Keyboard.page_up, - contract_view_key = Keyboard.page_down, - # Rotations - pan_left_key = Keyboard.j, - pan_right_key = Keyboard.l, - tilt_up_key = Keyboard.i, - tilt_down_key = Keyboard.k, - roll_clockwise_key = Keyboard.e, - roll_counterclockwise_key = Keyboard.q, - # Mouse controls - translation_button = Mouse.right, - scroll_mod = true, - rotation_button = Mouse.left, - # Shared controls - fix_x_key = Keyboard.x, - fix_y_key = Keyboard.y, - fix_z_key = Keyboard.z, - reset = Keyboard.home, - # Settings - keyboard_rotationspeed = 1f0, - keyboard_translationspeed = 0.5f0, - keyboard_zoomspeed = 1f0, - mouse_rotationspeed = 1f0, - mouse_translationspeed = 1f0, - mouse_zoomspeed = 1f0, - circular_rotation = (true, true, true), - fov = 45f0, # base fov - near = automatic, - far = automatic, - rotation_center = :lookat, - update_rate = 1/30, - projectiontype = Perspective, - fixed_axis = true, - zoom_shift_lookat = false, # doesn't really work with fov - cad = false, - # internal - selected = true - ) + overwrites = Attributes(kwargs) + + controls = Attributes( + # Keyboard controls + # Translations + up_key = Keyboard.r, + down_key = Keyboard.f, + left_key = Keyboard.a, + right_key = Keyboard.d, + forward_key = Keyboard.w, + backward_key = Keyboard.s, + # Zooms + zoom_in_key = Keyboard.u, + zoom_out_key = Keyboard.o, + increase_fov_key = Keyboard.b, + decrease_fov_key = Keyboard.n, + # Rotations + pan_left_key = Keyboard.j, + pan_right_key = Keyboard.l, + tilt_up_key = Keyboard.i, + tilt_down_key = Keyboard.k, + roll_clockwise_key = Keyboard.e, + roll_counterclockwise_key = Keyboard.q, + # Mouse controls + translation_button = Mouse.right, + rotation_button = Mouse.left, + scroll_mod = true, + reposition_button = Keyboard.left_alt & Mouse.left, + # Shared controls + fix_x_key = Keyboard.x, + fix_y_key = Keyboard.y, + fix_z_key = Keyboard.z, + reset = Keyboard.left_control & Mouse.left + ) + + replace!(controls, :Camera3D, scene, overwrites) + + settings = Attributes( + keyboard_rotationspeed = 1f0, + keyboard_translationspeed = 0.5f0, + keyboard_zoomspeed = 1f0, + + mouse_rotationspeed = 1f0, + mouse_translationspeed = 1f0, + mouse_zoomspeed = 1f0, + + projectiontype = Makie.Perspective, + circular_rotation = (true, true, true), + rotation_center = :lookat, + update_rate = 1/30, + zoom_shift_lookat = true, + fixed_axis = true, + cad = false, + center = true, + clipping_mode = :adaptive + ) + + replace!(settings, :Camera3D, scene, overwrites) + + if settings.clipping_mode[] === :view_relative + far_default = 2f0 + elseif settings.clipping_mode[] === :bbox_relative + far_default = 1f0 + else + far_default = 100f0 # will be set when inserting a plot end cam = Camera3D( - pop!(attr, :eyeposition, Vec3f(3)), - pop!(attr, :lookat, Vec3f(0)), - pop!(attr, :upvector, Vec3f(0, 0, 1)), - - Observable(1f0), - Observable(attr[:fov][]), - Observable(attr[:near][] === automatic ? 0.1f0 : attr[:near][]), - Observable(attr[:far][] === automatic ? 100f0 : attr[:far][]), - Observable(-1.0), + settings, controls, - attr + # Internals - controls + Observable(-1.0), + Observable(true), + + # Semi-Internal - view matrix + get(overwrites, :eyeposition, Observable(Vec3f(3, 3, 3))), + get(overwrites, :lookat, Observable(Vec3f(0, 0, 0))), + get(overwrites, :upvector, Observable(Vec3f(0, 0, 1))), + + # Semi-Internal - projection matrix + get(overwrites, :fov, Observable(45.0)), + get(overwrites, :near, Observable(0.1)), + get(overwrites, :far, Observable(far_default)), + Sphere(Point3f(0), 1f0) ) disconnect!(camera(scene)) @@ -154,9 +206,9 @@ function Camera3D(scene::Scene; kwargs...) # ticks every so often to get consistent position updates. on(cam.pulser) do prev_time current_time = time() - active = on_pulse(scene, cam, Float32(current_time - prev_time)) - @async if active && attr.selected[] - sleep(attr.update_rate[]) + active = on_pulse(scene, cam, current_time - prev_time) + @async if active && cam.selected[] + sleep(settings.update_rate[]) cam.pulser[] = current_time else cam.pulser.val = -1.0 @@ -165,7 +217,7 @@ function Camera3D(scene::Scene; kwargs...) keynames = ( :up_key, :down_key, :left_key, :right_key, :forward_key, :backward_key, - :zoom_in_key, :zoom_out_key, :stretch_view_key, :contract_view_key, + :zoom_in_key, :zoom_out_key, :increase_fov_key, :decrease_fov_key, :pan_left_key, :pan_right_key, :tilt_up_key, :tilt_down_key, :roll_clockwise_key, :roll_counterclockwise_key ) @@ -173,7 +225,7 @@ function Camera3D(scene::Scene; kwargs...) # Start ticking if relevant keys are pressed on(camera(scene), events(scene).keyboardbutton) do event if event.action in (Keyboard.press, Keyboard.repeat) && cam.pulser[] == -1.0 && - attr.selected[] && any(key -> ispressed(scene, attr[key][]), keynames) + cam.selected[] && any(key -> ispressed(scene, controls[key][]), keynames) cam.pulser[] = time() return Consume(true) end @@ -185,37 +237,33 @@ function Camera3D(scene::Scene; kwargs...) deselect_all_cameras!(root(scene)) on(camera(scene), events(scene).mousebutton, priority = 100) do event if event.action == Mouse.press - attr.selected[] = is_mouseinside(scene) + cam.selected[] = is_mouseinside(scene) end return Consume(false) end # Mouse controls - add_translation!(scene, cam) - add_rotation!(scene, cam) + add_mouse_controls!(scene, cam) # add camera controls to scene cameracontrols!(scene, cam) # Trigger updates on scene resize and settings change - on(camera(scene), scene.px_area, attr[:fov], attr[:projectiontype]) do _, _, _ - update_cam!(scene, cam) + on(camera(scene), cam.fov) do _ + if settings.projectiontype[] == Makie.Perspective + update_cam!(scene, cam) + end end - on(camera(scene), attr[:near], attr[:far]) do near, far - near === automatic || (cam.near[] = near) - far === automatic || (cam.far[] = far) + on(camera(scene), scene.viewport, cam.near, cam.far, settings.projectiontype) do _, _, _, _ update_cam!(scene, cam) end # reset on(camera(scene), events(scene).keyboardbutton) do event - if attr.selected[] && event.key == attr[:reset][] && event.action == Keyboard.release + if cam.selected[] && ispressed(scene, controls[:reset][]) # center keeps the rotation of the camera so we reset that here # might make sense to keep user set lookat, upvector, eyeposition # around somewhere for this? - cam.lookat[] = Vec3f(0) - cam.upvector[] = Vec3f(0,0,1) - cam.eyeposition[] = Vec3f(3) center!(scene) return Consume(true) end @@ -226,9 +274,21 @@ function Camera3D(scene::Scene; kwargs...) end # These imitate the old camera +""" + cam3d!(scene[; kwargs...]) + +Creates a `Camera3D` with `zoom_shift_lookat = true` and `fixed_axis = true`. +For more information, see [`Camera3D`](@ref) +""" cam3d!(scene; zoom_shift_lookat = true, fixed_axis = true, kwargs...) = Camera3D(scene, zoom_shift_lookat = zoom_shift_lookat, fixed_axis = fixed_axis; kwargs...) +""" + cam3d_cad!(scene[; kwargs...]) + +Creates a `Camera3D` with `cad = true`, `zoom_shift_lookat = false` and +`fixed_axis = false`. For more information, see [`Camera3D`](@ref) +""" cam3d_cad!(scene; cad = true, zoom_shift_lookat = false, fixed_axis = false, kwargs...) = Camera3D(scene, cad = cad, zoom_shift_lookat = zoom_shift_lookat, fixed_axis = fixed_axis; kwargs...) @@ -243,101 +303,187 @@ deselect_camera!(cam::Camera3D) = cam.attributes.selected[] = false deselect_camera!(::AbstractCamera) = nothing -function add_translation!(scene, cam::Camera3D) - translationspeed = cam.attributes[:mouse_translationspeed] - zoomspeed = cam.attributes[:mouse_zoomspeed] - shift_lookat = cam.attributes[:zoom_shift_lookat] - cad = cam.attributes[:cad] - button = cam.attributes[:translation_button] - scroll_mod = cam.attributes[:scroll_mod] +################################################################################ +### Interactivity init +################################################################################ - last_mousepos = RefValue(Vec2f(0, 0)) - dragging = RefValue(false) - function compute_diff(delta) - if cam.attributes[:projectiontype][] == Orthographic - aspect = Float32((/)(widths(scene.px_area[])...)) - aspect_scale = Vec2f(1f0 + aspect, 1f0 + 1f0 / aspect) - return cam.zoom_mult[] * delta .* aspect_scale ./ widths(scene.px_area[]) + +function on_pulse(scene, cam::Camera3D, timestep) + @extractvalue cam.controls ( + right_key, left_key, up_key, down_key, backward_key, forward_key, + tilt_up_key, tilt_down_key, pan_left_key, pan_right_key, roll_counterclockwise_key, roll_clockwise_key, + zoom_out_key, zoom_in_key, increase_fov_key, decrease_fov_key + ) + @extractvalue cam.settings ( + keyboard_translationspeed, keyboard_rotationspeed, keyboard_zoomspeed, projectiontype + ) + + # translation + right = ispressed(scene, right_key) + left = ispressed(scene, left_key) + up = ispressed(scene, up_key) + down = ispressed(scene, down_key) + backward = ispressed(scene, backward_key) + forward = ispressed(scene, forward_key) + translating = right || left || up || down || backward || forward + + if translating + # translation in camera space x/y/z direction + if projectiontype == Perspective + viewnorm = norm(cam.lookat[] - cam.eyeposition[]) + xynorm = 2 * viewnorm * tand(0.5 * cam.fov[]) + translation = keyboard_translationspeed * timestep * Vec3f( + xynorm * (right - left), + xynorm * (up - down), + viewnorm * (backward - forward) + ) else - viewdir = cam.lookat[] - cam.eyeposition[] - return 0.002f0 * cam.zoom_mult[] * norm(viewdir) * delta + # translation in camera space x/y/z direction + viewnorm = norm(cam.eyeposition[] - cam.lookat[]) + translation = 2 * viewnorm * keyboard_translationspeed * timestep * Vec3f( + right - left, up - down, backward - forward + ) end + _translate_cam!(scene, cam, translation) end - # drag start/stop - on(camera(scene), scene.events.mousebutton) do event - if ispressed(scene, button[]) - if event.action == Mouse.press && is_mouseinside(scene) && !dragging[] - last_mousepos[] = mouseposition_px(scene) - dragging[] = true - return Consume(true) - end - elseif event.action == Mouse.release && dragging[] - mousepos = mouseposition_px(scene) - diff = compute_diff(last_mousepos[] .- mousepos) - last_mousepos[] = mousepos - dragging[] = false - translate_cam!(scene, cam, translationspeed[] .* Vec3f(diff[1], diff[2], 0f0)) - return Consume(true) - end - return Consume(false) + # rotation + up = ispressed(scene, tilt_up_key) + down = ispressed(scene, tilt_down_key) + left = ispressed(scene, pan_left_key) + right = ispressed(scene, pan_right_key) + counterclockwise = ispressed(scene, roll_counterclockwise_key) + clockwise = ispressed(scene, roll_clockwise_key) + rotating = up || down || left || right || counterclockwise || clockwise + + if rotating + # rotations around camera space x/y/z axes + angles = keyboard_rotationspeed * timestep * + Vec3f(up - down, left - right, counterclockwise - clockwise) + + _rotate_cam!(scene, cam, angles) end - # in drag - on(camera(scene), scene.events.mouseposition) do mp - if dragging[] && ispressed(scene, button[]) - mousepos = screen_relative(scene, mp) - diff = compute_diff(last_mousepos[] .- mousepos) - last_mousepos[] = mousepos - translate_cam!(scene, cam, translationspeed[] * Vec3f(diff[1], diff[2], 0f0)) - return Consume(true) - end - return Consume(false) + # zoom + zoom_out = ispressed(scene, zoom_out_key) + zoom_in = ispressed(scene, zoom_in_key) + zooming = zoom_out || zoom_in + + if zooming + zoom_step = (1f0 + keyboard_zoomspeed * timestep) ^ (zoom_out - zoom_in) + _zoom!(scene, cam, zoom_step, false, false) end - on(camera(scene), scene.events.scroll) do scroll - if is_mouseinside(scene) && ispressed(scene, scroll_mod[]) - zoom_step = (1f0 + 0.1f0 * zoomspeed[]) ^ -scroll[2] - zoom!(scene, cam, zoom_step, shift_lookat[], cad[]) - return Consume(true) - end - return Consume(false) + # fov + fov_inc = ispressed(scene, increase_fov_key) + fov_dec = ispressed(scene, decrease_fov_key) + fov_adjustment = fov_inc || fov_dec + + if fov_adjustment + step = (1 + keyboard_zoomspeed * timestep) ^ (fov_inc - fov_dec) + cam.fov[] = clamp(cam.fov[] * step, 0.1, 179) + end + + # if any are active, update matrices, else stop clock + if translating || rotating || zooming || fov_adjustment + update_cam!(scene, cam) + return true + else + return false end end -function add_rotation!(scene, cam::Camera3D) - rotationspeed = cam.attributes[:mouse_rotationspeed] - button = cam.attributes[:rotation_button] + +function add_mouse_controls!(scene, cam::Camera3D) + @extract cam.controls (translation_button, rotation_button, reposition_button, scroll_mod) + @extract cam.settings ( + mouse_translationspeed, mouse_rotationspeed, mouse_zoomspeed, + cad, projectiontype, zoom_shift_lookat + ) + last_mousepos = RefValue(Vec2f(0, 0)) - dragging = RefValue(false) + dragging = RefValue((false, false)) # rotation, translation + e = events(scene) + function compute_diff(delta) + if projectiontype[] == Perspective + # TODO wrong scaling? :( + ynorm = 2 * norm(cam.lookat[] - cam.eyeposition[]) * tand(0.5 * cam.fov[]) + return ynorm / size(scene, 2) * delta + else + viewnorm = norm(cam.eyeposition[] - cam.lookat[]) + return 2 * viewnorm / size(scene, 2) * delta + end + end + # drag start/stop on(camera(scene), e.mousebutton) do event - if ispressed(scene, button[]) - if event.action == Mouse.press && is_mouseinside(scene) && !dragging[] + # Drag start translation/rotation + if event.action == Mouse.press && is_mouseinside(scene) + if ispressed(scene, translation_button[]) + last_mousepos[] = mouseposition_px(scene) + dragging[] = (false, true) + return Consume(true) + elseif ispressed(scene, rotation_button[]) last_mousepos[] = mouseposition_px(scene) - dragging[] = true + dragging[] = (true, false) return Consume(true) end - elseif event.action == Mouse.release && dragging[] - mousepos = mouseposition_px(scene) - dragging[] = false - rot_scaling = rotationspeed[] * (e.window_dpi[] * 0.005) - mp = (last_mousepos[] .- mousepos) .* 0.01f0 .* rot_scaling - last_mousepos[] = mousepos - rotate_cam!(scene, cam, Vec3f(-mp[2], mp[1], 0f0), true) - return Consume(true) + # drag stop & repostion + elseif event.action == Mouse.release + consume = false + + # Drag stop translation/rotation + if dragging[][1] + mousepos = mouseposition_px(scene) + diff = compute_diff(last_mousepos[] .- mousepos) + last_mousepos[] = mousepos + dragging[] = (false, false) + translate_cam!(scene, cam, mouse_translationspeed[] .* Vec3f(diff[1], diff[2], 0f0)) + consume = true + elseif dragging[][2] + mousepos = mouseposition_px(scene) + dragging[] = (false, false) + rot_scaling = mouse_rotationspeed[] * (e.window_dpi[] * 0.005) + mp = (last_mousepos[] .- mousepos) .* 0.01f0 .* rot_scaling + last_mousepos[] = mousepos + rotate_cam!(scene, cam, Vec3f(-mp[2], mp[1], 0f0), true) + consume = true + end + + # reposition + if ispressed(scene, reposition_button[], event.button) && is_mouseinside(scene) + plt, _, p = ray_assisted_pick(scene) + p3d = to_ndim(Point3f, p, 0f0) + if !isnan(p3d) && to_value(get(plt, :space, :data)) == :data && parent_scene(plt) == scene + # if translation/rotation happens with on-click reposition, + # try uncommenting this + # dragging[] = (false, false) + shift = p3d - cam.lookat[] + update_cam!(scene, cam, cam.eyeposition[] + shift, p3d) + end + consume = true + end + + return Consume(consume) end + return Consume(false) end # in drag on(camera(scene), e.mouseposition) do mp - if dragging[] && ispressed(scene, button[]) + if dragging[][2] && ispressed(scene, translation_button[]) + mousepos = screen_relative(scene, mp) + diff = compute_diff(last_mousepos[] .- mousepos) + last_mousepos[] = mousepos + translate_cam!(scene, cam, mouse_translationspeed[] * Vec3f(diff[1], diff[2], 0f0)) + return Consume(true) + elseif dragging[][1] && ispressed(scene, rotation_button[]) mousepos = screen_relative(scene, mp) - rot_scaling = rotationspeed[] * (e.window_dpi[] * 0.005) + rot_scaling = mouse_rotationspeed[] * (e.window_dpi[] * 0.005) mp = (last_mousepos[] .- mousepos) * 0.01f0 * rot_scaling last_mousepos[] = mousepos rotate_cam!(scene, cam, Vec3f(-mp[2], mp[1], 0f0), true) @@ -345,80 +491,82 @@ function add_rotation!(scene, cam::Camera3D) end return Consume(false) end -end + #zoom + on(camera(scene), e.scroll) do scroll + if is_mouseinside(scene) && ispressed(scene, scroll_mod[]) + zoom_step = (1f0 + 0.1f0 * mouse_zoomspeed[]) ^ -scroll[2] + zoom!(scene, cam, zoom_step, cad[], zoom_shift_lookat[]) + return Consume(true) + end + return Consume(false) + end -function on_pulse(scene, cam, timestep) - attr = cam.attributes - # translation - right = ispressed(scene, attr[:right_key][]) - left = ispressed(scene, attr[:left_key][]) - up = ispressed(scene, attr[:up_key][]) - down = ispressed(scene, attr[:down_key][]) - backward = ispressed(scene, attr[:backward_key][]) - forward = ispressed(scene, attr[:forward_key][]) - translating = right || left || up || down || backward || forward +end - if translating - # translation in camera space x/y/z direction - translation = attr[:keyboard_translationspeed][] * timestep * - Vec3f(right - left, up - down, backward - forward) - viewdir = cam.lookat[] - cam.eyeposition[] - _translate_cam!(scene, cam, cam.zoom_mult[] * norm(viewdir) * translation) - end - # rotation - up = ispressed(scene, attr[:tilt_up_key][]) - down = ispressed(scene, attr[:tilt_down_key][]) - left = ispressed(scene, attr[:pan_left_key][]) - right = ispressed(scene, attr[:pan_right_key][]) - counterclockwise = ispressed(scene, attr[:roll_counterclockwise_key][]) - clockwise = ispressed(scene, attr[:roll_clockwise_key][]) - rotating = up || down || left || right || counterclockwise || clockwise +################################################################################ +### Camera transformations +################################################################################ - if rotating - # rotations around camera space x/y/z axes - angles = attr[:keyboard_rotationspeed][] * timestep * - Vec3f(up - down, left - right, counterclockwise - clockwise) - _rotate_cam!(scene, cam, angles) - end +# Simplified methods +""" + translate_cam!(scene, cam::Camera3D, v::Vec3) - # zoom - zoom_out = ispressed(scene, attr[:zoom_out_key][]) - zoom_in = ispressed(scene, attr[:zoom_in_key][]) - zooming = zoom_out || zoom_in +Translates the camera by the given vector in camera space, i.e. by `v[1]` to +the right, `v[2]` to the top and `v[3]` forward. - if zooming - zoom_step = (1f0 + attr[:keyboard_zoomspeed][] * timestep) ^ (zoom_out - zoom_in) - _zoom!(scene, cam, zoom_step, false) - end +Note that this method reacts to `fix_x_key` etc. If any of those keys are +pressed the translation will be restricted to act in these directions. +""" +function translate_cam!(scene, cam::Camera3D, t::VecTypes) + _translate_cam!(scene, cam, t) + update_cam!(scene, cam) + nothing +end - stretch = ispressed(scene, attr[:stretch_view_key][]) - contract = ispressed(scene, attr[:contract_view_key][]) - if stretch || contract - zoom_step = (1f0 + attr[:keyboard_zoomspeed][] * timestep) ^ (stretch - contract) - cam.eyeposition[] = cam.lookat[] + zoom_step * (cam.eyeposition[] - cam.lookat[]) - end - zooming = zooming || stretch || contract +""" + rotate_cam!(scene, cam::Camera3D, angles::Vec3) - # if any are active, update matrices, else stop clock - if translating || rotating || zooming - update_cam!(scene, cam) - return true - else - return false - end +Rotates the camera by the given `angles` around the camera x- (left, right), +y- (up, down) and z-axis (in out). The rotation around the y axis is applied +first, then x, then y. + +Note that this method reacts to `fix_x_key` etc and `fixed_axis`. The former +restrict the rotation around a specific axis when a given key is pressed. The +latter keeps the camera y axis fixed as the data space z axis. +""" +function rotate_cam!(scene, cam::Camera3D, angles::VecTypes, from_mouse=false) + _rotate_cam!(scene, cam, angles, from_mouse) + update_cam!(scene, cam) + nothing end -function translate_cam!(scene::Scene, cam::Camera3D, t::VecTypes) - _translate_cam!(scene, cam, t) +zoom!(scene, zoom_step) = zoom!(scene, cameracontrols(scene), zoom_step, false, false) +""" + zoom!(scene, cam::Camera3D, zoom_step[, cad = false, zoom_shift_lookat = false]) + +Zooms the camera in or out based on the multiplier `zoom_step`. A `zoom_step` +of 1.0 is neutral, larger zooms out and lower zooms in. + +If `cad = true` zooming will also apply a rotation based on how far the cursor +is from the center of the scene. If `zoom_shift_lookat = true` and +`projectiontype = Orthographic` zooming will keep the data under the cursor at +the same screen space position. +""" +function zoom!(scene, cam::Camera3D, zoom_step, cad = false, zoom_shift_lookat = false) + _zoom!(scene, cam, zoom_step, cad, zoom_shift_lookat) update_cam!(scene, cam) nothing end -function _translate_cam!(scene, cam, t) + + +function _translate_cam!(scene, cam::Camera3D, t) + @extractvalue cam.controls (fix_x_key, fix_y_key, fix_z_key) + # This uses a camera based coordinate system where # x expands right, y expands up and z expands towards the screen lookat = cam.lookat[] @@ -431,9 +579,9 @@ function _translate_cam!(scene, cam, t) trans = u_x * t[1] + u_y * t[2] + u_z * t[3] # apply world space restrictions - fix_x = ispressed(scene, cam.attributes[:fix_x_key][]) - fix_y = ispressed(scene, cam.attributes[:fix_y_key][]) - fix_z = ispressed(scene, cam.attributes[:fix_z_key][]) + fix_x = ispressed(scene, fix_x_key)::Bool + fix_y = ispressed(scene, fix_y_key)::Bool + fix_z = ispressed(scene, fix_z_key)::Bool if fix_x || fix_y || fix_z trans = Vec3f(fix_x, fix_y, fix_z) .* trans end @@ -444,12 +592,10 @@ function _translate_cam!(scene, cam, t) end -function rotate_cam!(scene, cam::Camera3D, angles::VecTypes, from_mouse=false) - _rotate_cam!(scene, cam, angles, from_mouse) - update_cam!(scene, cam) - nothing -end function _rotate_cam!(scene, cam::Camera3D, angles::VecTypes, from_mouse=false) + @extractvalue cam.controls (fix_x_key, fix_y_key, fix_z_key) + @extractvalue cam.settings (fixed_axis, circular_rotation, rotation_center) + # This applies rotations around the x/y/z axis of the camera coordinate system # x expands right, y expands up and z expands towards the screen lookat = cam.lookat[] @@ -459,32 +605,35 @@ function _rotate_cam!(scene, cam::Camera3D, angles::VecTypes, from_mouse=false) right = cross(viewdir, up) # +x x_axis = right - y_axis = cam.attributes[:fixed_axis][] ? Vec3f(0, 0, ifelse(up[3] < 0, -1, 1)) : up + y_axis = fixed_axis ? Vec3f(0, 0, ifelse(up[3] < 0, -1, 1)) : up z_axis = -viewdir - fix_x = ispressed(scene, cam.attributes[:fix_x_key][]) - fix_y = ispressed(scene, cam.attributes[:fix_y_key][]) - fix_z = ispressed(scene, cam.attributes[:fix_z_key][]) - cx, cy, cz = cam.attributes[:circular_rotation][] + fix_x = ispressed(scene, fix_x_key)::Bool + fix_y = ispressed(scene, fix_y_key)::Bool + fix_z = ispressed(scene, fix_z_key)::Bool + cx, cy, cz = circular_rotation + rotation = Quaternionf(0, 0, 0, 1) if !xor(fix_x, fix_y, fix_z) # if there are more or less than one restriction apply all rotations + # Note that the y rotation needs to happen first here so that + # fixed_axis = true actually keeps the the axis fixed. rotation *= qrotation(y_axis, angles[2]) rotation *= qrotation(x_axis, angles[1]) rotation *= qrotation(z_axis, angles[3]) else # apply world space restrictions - if from_mouse && ((fix_x && (fix_x == cx)) || (fix_y && (fix_y == cy)) || (fix_z && (fix_z == cz))) + if from_mouse && ((fix_x && cx) || (fix_y && cy) || (fix_z && cz)) # recontextualize the (dy, dx, 0) from mouse rotations so that # drawing circles creates continuous rotations around the fixed axis mp = mouseposition_px(scene) - past_half = 0.5f0 .* widths(scene.px_area[]) .> mp + past_half = 0.5f0 .* size(scene) .> mp flip = 2f0 * past_half .- 1f0 angle = flip[1] * angles[1] + flip[2] * angles[2] - angles = Vec3f(-angle, angle, -angle) + angles = Vec3f(-angle, -angle, angle) # only one fix is true so this only rotates around one axis rotation *= qrotation( - Vec3f(fix_x, fix_z, fix_y) .* Vec3f(sign(right[1]), viewdir[2], sign(up[3])), + Vec3f(fix_x, fix_y, fix_z) .* Vec3f(sign(right[1]), viewdir[2], sign(up[3])), dot(Vec3f(fix_x, fix_y, fix_z), angles) ) else @@ -502,138 +651,175 @@ function _rotate_cam!(scene, cam::Camera3D, angles::VecTypes, from_mouse=false) # TODO maybe generalize this to arbitrary center? # calculate positions from rotated vectors - if cam.attributes[:rotation_center][] === :lookat + if rotation_center === :lookat cam.eyeposition[] = lookat - viewdir else cam.lookat[] = eyepos + viewdir end + return end -""" - zoom!(scene, zoom_step) - -Zooms the camera in or out based on the multiplier `zoom_step`. A `zoom_step` -of 1.0 is neutral, larger zooms out and lower zooms in. - -Note that this method only applies to Camera3D. -""" -zoom!(scene::Scene, zoom_step) = zoom!(scene, cameracontrols(scene), zoom_step, false, false) -function zoom!(scene::Scene, cam::Camera3D, zoom_step, shift_lookat = false, cad = false) - _zoom!(scene, cam, zoom_step, shift_lookat, cad) - update_cam!(scene, cam) - nothing -end -function _zoom!(scene::Scene, cam::Camera3D, zoom_step, shift_lookat = false, cad = false) +function _zoom!(scene, cam::Camera3D, zoom_step, cad = false, zoom_shift_lookat = false) + lookat = cam.lookat[] + eyepos = cam.eyeposition[] + viewdir = lookat - eyepos # -z + vp = viewport(scene)[] + scene_width = widths(vp) if cad - # move exeposition if mouse is not over the center - lookat = cam.lookat[] - eyepos = cam.eyeposition[] - up = cam.upvector[] # +y - viewdir = lookat - eyepos # -z - right = cross(viewdir, up) # +x - - rel_pos = 2f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1f0 - shift = rel_pos[1] * normalize(right) + rel_pos[2] * normalize(up) - shifted = eyepos + 0.1f0 * sign(1f0 - zoom_step) * norm(viewdir) * shift - cam.eyeposition[] = lookat + norm(viewdir) * normalize(shifted - lookat) - elseif shift_lookat - lookat = cam.lookat[] - eyepos = cam.eyeposition[] - up = normalize(cam.upvector[]) - viewdir = lookat - eyepos - u_z = normalize(-viewdir) - u_x = normalize(cross(up, u_z)) - u_y = normalize(cross(u_z, u_x)) - - if cam.attributes[:projectiontype][] == Perspective - # translate both eyeposition and lookat to more or less keep data - # under the mouse in view - fov = cam.attributes[:fov][] - before = tan(clamp(cam.zoom_mult[] * fov, 0.01f0, 175f0) / 360f0 * Float32(pi)) - after = tan(clamp(cam.zoom_mult[] * zoom_step * fov, 0.01f0, 175f0) / 360f0 * Float32(pi)) - - aspect = Float32((/)(widths(scene.px_area[])...)) - rel_pos = 2f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1f0 - shift = rel_pos[1] * u_x + rel_pos[2] * u_y - shift = -(after - before) * norm(viewdir) * normalize(aspect .* shift) + # Rotate view based on offset from center + u_z = normalize(viewdir) + u_x = normalize(cross(u_z, cam.upvector[])) + u_y = normalize(cross(u_x, u_z)) + + rel_pos = 2.0f0 * mouseposition_px(scene) ./ scene_width .- 1.0f0 + shift = rel_pos[1] * u_x + rel_pos[2] * u_y + shift *= 0.1 * sign(1 - zoom_step) * norm(viewdir) + + cam.eyeposition[] = lookat - zoom_step * viewdir + shift + elseif zoom_shift_lookat + # keep data under cursor + u_z = normalize(viewdir) + u_x = normalize(cross(u_z, cam.upvector[])) + u_y = normalize(cross(u_x, u_z)) + + rel_pos = (2.0 .* mouseposition_px(scene) .- scene_width) ./ scene_width[2] + shift = (1 - zoom_step) * (rel_pos[1] * u_x + rel_pos[2] * u_y) + + if cam.settings.projectiontype[] == Makie.Orthographic + scale = norm(viewdir) else - mx, my = 2f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1f0 - aspect = Float32((/)(widths(scene.px_area[])...)) - w = 0.5f0 * (1f0 + aspect) * cam.zoom_mult[] - h = 0.5f0 * (1f0 + 1f0 / aspect) * cam.zoom_mult[] - shift = (1f0 - zoom_step) * (mx * w * u_x + my * h * u_y) + # With perspective projection depth scales shift, but there is no way + # to tell which depth the user may want to keep in view. So we just + # assume it's the same depth as "lookat". + scale = norm(viewdir) * tand(0.5 * cam.fov[]) end - cam.lookat[] = lookat + shift - cam.eyeposition[] = eyepos + shift + cam.lookat[] = lookat + scale * shift + cam.eyeposition[] = lookat - zoom_step * viewdir + scale * shift + else + # just zoom in/out + cam.eyeposition[] = lookat - zoom_step * viewdir end - # apply zoom - cam.zoom_mult[] = cam.zoom_mult[] * zoom_step - return end +################################################################################ +### update_cam! methods +################################################################################ + + +# Update camera matrices function update_cam!(scene::Scene, cam::Camera3D) - @extractvalue cam (lookat, eyeposition, upvector) + @extractvalue cam (lookat, eyeposition, upvector, near, far, fov, bounding_sphere) + + view = Makie.lookat(eyeposition, lookat, upvector) - near = cam.near[]; far = cam.far[] - aspect = Float32((/)(widths(scene.px_area[])...)) + if cam.settings.clipping_mode[] === :view_relative + view_dist = norm(eyeposition - lookat) + near = view_dist * near; far = view_dist * far + elseif cam.settings.clipping_mode[] === :bbox_relative + view_dist = norm(eyeposition - lookat) + center_dist = norm(eyeposition - origin(bounding_sphere)) + far_dist = center_dist + radius(bounding_sphere) + near = max(view_dist * near, center_dist - radius(bounding_sphere)) + far = far_dist * far + elseif cam.settings.clipping_mode[] === :adaptive + view_dist = norm(eyeposition - lookat) + near = view_dist * near; far = max(1f0, view_dist) * far + elseif cam.settings.clipping_mode[] !== :static + @error "clipping_mode = $(cam.settings.clipping_mode[]) not recognized, using :static." + end - if cam.attributes[:projectiontype][] == Perspective - fov = clamp(cam.zoom_mult[] * cam.attributes[:fov][], 0.01f0, 175f0) - cam.fov[] = fov + aspect = Float32((/)(widths(scene)...)) + if cam.settings.projectiontype[] == Makie.Perspective proj = perspectiveprojection(fov, aspect, near, far) else - w = 0.5f0 * (1f0 + aspect) * cam.zoom_mult[] - h = 0.5f0 * (1f0 + 1f0 / aspect) * cam.zoom_mult[] + h = norm(eyeposition - lookat); w = h * aspect proj = orthographicprojection(-w, w, -h, h, near, far) end - view = Makie.lookat(eyeposition, lookat, upvector) - set_proj_view!(camera(scene), proj, view) scene.camera.eyeposition[] = cam.eyeposition[] + scene.camera.lookat[] = cam.lookat[] end -function update_cam!(scene::Scene, camera::Camera3D, area3d::Rect) - @extractvalue camera (lookat, eyeposition, upvector) + +# Update camera position via bbox +function update_cam!(scene::Scene, cam::Camera3D, area3d::Rect, recenter::Bool = cam.settings.center[]) bb = Rect3f(area3d) width = widths(bb) - half_width = width ./ 2f0 - middle = maximum(bb) - half_width - old_dir = normalize(eyeposition .- lookat) - camera.lookat[] = middle - neweyepos = middle .+ (1.2*norm(width) .* old_dir) - camera.eyeposition[] = neweyepos - camera.upvector[] = Vec3f(0,0,1) - if camera.attributes[:near][] === automatic - camera.near[] = 0.1f0 * norm(widths(bb)) + center = maximum(bb) - 0.5f0 * width + radius = 0.5f0 * norm(width) + (isnan(radius) || (radius == 0)) && return + cam.bounding_sphere[] = Sphere(Point3f(center), radius) + + old_dir = normalize(cam.eyeposition[] .- cam.lookat[]) + if cam.settings.projectiontype[] == Makie.Perspective + dist = radius / tand(0.5f0 * cam.fov[]) + else + dist = radius end - if camera.attributes[:far][] === automatic - camera.far[] = 3f0 * norm(widths(bb)) + + if recenter + cam.lookat[] = center + cam.eyeposition[] = cam.lookat[] .+ dist * old_dir + cam.upvector[] = normalize(cross(old_dir, cross(cam.upvector[], old_dir))) end - if camera.attributes[:projectiontype][] == Orthographic - camera.zoom_mult[] = 0.6 * norm(width) - else - camera.zoom_mult[] = 1f0 + + if cam.settings.clipping_mode[] === :static + cam.near[] = 0.1f0 * dist + cam.far[] = 2f0 * dist + elseif cam.settings.clipping_mode[] === :adaptive + cam.near[] = 0.1f0 * dist / norm(cam.eyeposition[] - cam.lookat[]) + cam.far[] = 2.2f0 * dist / norm(cam.eyeposition[] - cam.lookat[]) end - update_cam!(scene, camera) + + update_cam!(scene, cam) + return end -function update_cam!(scene::Scene, camera::Camera3D, eyeposition, lookat, up = Vec3f(0, 0, 1)) - camera.lookat[] = Vec3f(lookat) +# Update camera position via camera Position & Orientation +function update_cam!(scene::Scene, camera::Camera3D, eyeposition::VecTypes, lookat::VecTypes, up::VecTypes = camera.upvector[]) + camera.settings.center[] = false + camera.lookat[] = Vec3f(lookat) camera.eyeposition[] = Vec3f(eyeposition) - camera.upvector[] = Vec3f(up) + camera.upvector[] = Vec3f(up) + update_cam!(scene, camera) + return +end + +update_cam!(scene::Scene, args::Real...) = update_cam!(scene, cameracontrols(scene), args...) + +""" + update_cam!(scene, cam::Camera3D, ϕ, θ[, radius]) + +Set the camera position based on two angles `0 ≤ ϕ ≤ 2π` and `-pi/2 ≤ θ ≤ pi/2` +and an optional radius around the current `cam.lookat[]`. +""" +function update_cam!( + scene::Scene, camera::Camera3D, phi::Real, theta::Real, + radius::Real = norm(camera.eyeposition[] - camera.lookat[]), + center = camera.lookat[] + ) + camera.settings.center[] = false + st, ct = sincos(theta) + sp, cp = sincos(phi) + v = Vec3f(ct * cp, ct * sp, st) + u = Vec3f(-st * cp, -st * sp, ct) + camera.lookat[] = center + camera.eyeposition[] = center .+ radius * v + camera.upvector[] = u update_cam!(scene, camera) return end + function show_cam(scene) cam = cameracontrols(scene) println("cam=cameracontrols(scene)") diff --git a/src/camera/old_camera3d.jl b/src/camera/old_camera3d.jl index 2d5f424cccf..33d381d2e45 100644 --- a/src/camera/old_camera3d.jl +++ b/src/camera/old_camera3d.jl @@ -46,13 +46,15 @@ function old_cam3d_cad!(scene::Scene; kw_args...) add_translation!(scene, cam, cam.pan_button, cam.move_key, false) add_rotation!(scene, cam, cam.rotate_button, cam.move_key, false) cameracontrols!(scene, cam) - on(camera(scene), scene.px_area) do area + on(camera(scene), scene.viewport) do area # update cam when screen ratio changes update_cam!(scene, cam) end cam end +get_space(::OldCamera3D) = :data + """ old_cam3d_turntable!(scene; kw_args...) @@ -82,7 +84,7 @@ function old_cam3d_turntable!(scene::Scene; kw_args...) add_translation!(scene, cam, cam.pan_button, cam.move_key, true) add_rotation!(scene, cam, cam.rotate_button, cam.move_key, true) cameracontrols!(scene, cam) - on(camera(scene), scene.px_area) do area + on(camera(scene), scene.viewport) do area # update cam when screen ratio changes update_cam!(scene, cam) end @@ -96,7 +98,12 @@ An alias to [`old_cam3d_turntable!`](@ref). Creates a 3D camera for `scene`, which rotates around the plot's axis. """ -const old_cam3d! = old_cam3d_turntable! +old_cam3d!(scene::Scene; kwargs...) = old_cam3d_turntable!(scene; kwargs...) + +@deprecate old_cam3d! cam3d! +@deprecate old_cam3d_turntable! cam3d! +@deprecate old_cam3d_cad! cam3d_cad! + function projection_switch( wh::Rect2, @@ -171,7 +178,7 @@ function add_translation!(scene, cam, key, button, zoom_shift_lookat::Bool) on(camera(scene), scene.events.scroll) do scroll if ispressed(scene, button[]) && is_mouseinside(scene) - cam_res = Vec2f(widths(scene.px_area[])) + cam_res = Vec2f(widths(scene)) mouse_pos_normalized = mouseposition_px(scene) ./ cam_res mouse_pos_normalized = 2*mouse_pos_normalized .- 1f0 zoom_step = scroll[2] @@ -232,7 +239,7 @@ function translate_cam!(scene::Scene, cam::OldCamera3D, _translation::VecTypes) dir = eyeposition - lookat dir_len = norm(dir) - cam_res = Vec2f(widths(scene.px_area[])) + cam_res = Vec2f(widths(scene)) z, x, y = translation z *= 0.1f0 * dir_len @@ -323,7 +330,7 @@ function update_cam!(scene::Scene, cam::OldCamera3D) # TODO this means you can't set FarClip... SAD! # TODO use boundingbox(scene) for optimal far/near far = max(zoom * 5f0, 30f0) - proj = projection_switch(scene.px_area[], fov, near, far, projectiontype, zoom) + proj = projection_switch(scene.viewport[], fov, near, far, projectiontype, zoom) view = Makie.lookat(eyeposition, lookat, upvector) set_proj_view!(camera(scene), proj, view) scene.camera.eyeposition[] = cam.eyeposition[] @@ -351,7 +358,9 @@ end Updates the camera's controls to point to the specified location. """ -update_cam!(scene::Scene, eyeposition, lookat, up = Vec3f(0, 0, 1)) = update_cam!(scene, cameracontrols(scene), eyeposition, lookat, up) +function update_cam!(scene::Scene, eyeposition::VecTypes{3}, lookat::VecTypes{3}, up::VecTypes{3} = Vec3f(0, 0, 1)) + return update_cam!(scene, cameracontrols(scene), eyeposition, lookat, up) +end function update_cam!(scene::Scene, camera::OldCamera3D, eyeposition, lookat, up = Vec3f(0, 0, 1)) camera.lookat[] = Vec3f(lookat) diff --git a/src/camera/projection_math.jl b/src/camera/projection_math.jl index 717224c6a6a..eada9918c2e 100644 --- a/src/camera/projection_math.jl +++ b/src/camera/projection_math.jl @@ -245,7 +245,7 @@ function to_world(scene::Scene, point::T) where T <: StaticVector inv(transformationmatrix(scene)[]) * inv(cam.view[]) * inv(cam.projection[]), - T(widths(pixelarea(scene)[])) + T(size(scene)) ) Point2f(x[1], x[2]) end @@ -280,7 +280,7 @@ end function project(scene::Scene, point::T) where T<:StaticVector cam = scene.camera - area = pixelarea(scene)[] + area = viewport(scene)[] # TODO, I think we need .+ minimum(area) # Which would be semi breaking at this point though, I suppose return project( @@ -344,6 +344,22 @@ function clip_to_space(cam::Camera, space::Symbol) end end +function get_space(scene::Scene) + space = get_space(cameracontrols(scene))::Symbol + space === :data ? (:data,) : (:data, space) +end +get_space(::AbstractCamera) = :data +# TODO: Should this be less specialized? ScenePlot? AbstractPlot? +get_space(plot::Plot) = to_value(get(plot, :space, :data))::Symbol + +is_space_compatible(a, b) = is_space_compatible(get_space(a), get_space(b)) +is_space_compatible(a::Symbol, b::Symbol) = a === b +is_space_compatible(a::Symbol, b::Union{Tuple, Vector}) = a in b +function is_space_compatible(a::Union{Tuple, Vector}, b::Union{Tuple, Vector}) + any(x -> is_space_compatible(x, b), a) +end +is_space_compatible(a::Union{Tuple, Vector}, b::Symbol) = is_space_compatible(b, a) + function project(cam::Camera, input_space::Symbol, output_space::Symbol, pos) input_space === output_space && return to_ndim(Point3f, pos, 0) clip_from_input = space_to_clip(cam, input_space) diff --git a/src/colorsampler.jl b/src/colorsampler.jl index 99deb026186..a8800b46b69 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -244,13 +244,19 @@ colormapping_type(@nospecialize(colormap)) = continuous colormapping_type(::PlotUtils.CategoricalColorGradient) = banded colormapping_type(::Categorical) = categorical -function ColorMapping( - color::AbstractArray{<:Number, N}, colors_obs, colormap, colorrange, - colorscale, alpha, lowclip, highclip, nan_color, - color_mapping_type=lift(colormapping_type, colormap; ignore_equal_values=true)) where {N} - T = _array_value_type(color) - color_tight = convert(Observable{T}, colors_obs) +function _colormapping( + color_tight::Observable{V}, + @nospecialize(colors_obs), + @nospecialize(colormap), + @nospecialize(colorrange), + @nospecialize(colorscale), + @nospecialize(alpha), + @nospecialize(lowclip), + @nospecialize(highclip), + @nospecialize(nan_color), + color_mapping_type) where {V <: AbstractArray{T, N}} where {N, T} + map_colors = Observable(RGBAf[]; ignore_equal_values=true) raw_colormap = Observable(RGBAf[]; ignore_equal_values=true) mapping = Observable{Union{Nothing,Vector{Float64}}}(nothing; ignore_equal_values=true) @@ -276,7 +282,7 @@ function ColorMapping( _lowclip = Observable{Union{Automatic,RGBAf}}(automatic; ignore_equal_values=true) on(lowclip; update=true) do lc - _lowclip[] = lc isa Union{Nothing, Automatic} ? automatic : to_color(lc) + _lowclip[] = lc isa Union{Nothing,Automatic} ? automatic : to_color(lc) return end _highclip = Observable{Union{Automatic,RGBAf}}(automatic; ignore_equal_values=true) @@ -296,21 +302,38 @@ function ColorMapping( color_scaled = lift(color_tight, colorscale) do color, scale return el32convert(apply_scale(scale, color)) end - CT = ColorMapping{N,T,typeof(color_scaled[])} - - return CT( - color_tight, - map_colors, - raw_colormap, - colorscale, - mapping, - colorrange, - _lowclip, - _highclip, - lift(to_color, nan_color), - color_mapping_type, - colorrange_scaled, - color_scaled) + CT = ColorMapping{N,V,typeof(color_scaled[])} + + return CT(color_tight, + map_colors, + raw_colormap, + colorscale, + mapping, + colorrange, + _lowclip, + _highclip, + lift(to_color, nan_color), + color_mapping_type, + colorrange_scaled, + color_scaled) +end + +function ColorMapping( + color::AbstractArray{<:Number, N}, + @nospecialize(colors_obs), + @nospecialize(colormap), + @nospecialize(colorrange), + @nospecialize(colorscale), + @nospecialize(alpha), + @nospecialize(lowclip), + @nospecialize(highclip), + @nospecialize(nan_color), + color_mapping_type=lift(colormapping_type, colormap; ignore_equal_values=true)) where {N} + + T = _array_value_type(color) + color_tight = convert(Observable{T}, colors_obs)::Observable{T} + _colormapping(color_tight, colors_obs, colormap, colorrange, + colorscale, alpha, lowclip, highclip, nan_color, color_mapping_type) end function assemble_colors(c::AbstractArray{<:Number}, @nospecialize(color), @nospecialize(plot)) diff --git a/src/conversions.jl b/src/conversions.jl index 6fb0d945499..4727f2715f5 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -1,11 +1,11 @@ ################################################################################ # Type Conversions # ################################################################################ -const RangeLike = Union{AbstractRange, AbstractVector, ClosedInterval} +const RangeLike = Union{AbstractVector, ClosedInterval, Tuple{Any,Any}} # if no plot type based conversion is defined, we try using a trait function convert_arguments(T::PlotFunc, args...; kw...) - ct = conversion_trait(T) + ct = conversion_trait(T, args...) try convert_arguments(ct, args...; kw...) catch e @@ -41,7 +41,7 @@ end # and reconvert the whole tuple in order to handle missings centrally, e.g. function convert_arguments_individually(T::PlotFunc, args...) # convert each single argument until it doesn't change type anymore - single_converted = recursively_convert_argument.(args) + single_converted = map(recursively_convert_argument, args) # if the type of args hasn't changed this function call didn't help and we error if typeof(single_converted) == typeof(args) throw(MethodError(convert_arguments, (T, args...))) @@ -54,9 +54,9 @@ end function recursively_convert_argument(x) newx = convert_single_argument(x) if typeof(newx) == typeof(x) - x + return x else - recursively_convert_argument(newx) + return recursively_convert_argument(newx) end end @@ -109,7 +109,7 @@ end Enables to use scatter like a surface plot with x::Vector, y::Vector, z::Matrix spanning z over the grid spanned by x y """ -function convert_arguments(::PointBased, x::AbstractArray, y::AbstractVector, z::AbstractMatrix) +function convert_arguments(::PointBased, x::AbstractArray, y::AbstractVector, z::AbstractArray) (vec(Point3f.(x, y', z)),) end @@ -163,7 +163,6 @@ from `x` and `y`. `P` is the plot Type (it is optional). """ -#convert_arguments(::PointBased, x::RealVector, y::RealVector) = (Point2f.(x, y),) convert_arguments(P::PointBased, x::ClosedInterval, y::RealVector) = convert_arguments(P, LinRange(extrema(x)..., length(y)), y) convert_arguments(P::PointBased, x::RealVector, y::ClosedInterval) = convert_arguments(P, x, LinRange(extrema(y)..., length(x))) @@ -311,7 +310,7 @@ end ################################################################################ -# SurfaceLike # +# GridBased # ################################################################################ function edges(v::AbstractVector) @@ -329,62 +328,76 @@ function edges(v::AbstractVector) end end -function adjust_axes(::DiscreteSurface, x::AbstractVector{<:Number}, y::AbstractVector{<:Number}, z::AbstractMatrix) +function adjust_axes(::CellGrid, x::AbstractVector{<:Number}, y::AbstractVector{<:Number}, z::AbstractMatrix) x̂, ŷ = map((x, y), size(z)) do v, sz return length(v) == sz ? edges(v) : v end return x̂, ŷ, z end -adjust_axes(::SurfaceLike, x, y, z) = x, y, z +adjust_axes(::VertexGrid, x, y, z) = x, y, z """ - convert_arguments(SL::SurfaceLike, x::VecOrMat, y::VecOrMat, z::Matrix) + convert_arguments(ct::GridBased, x::VecOrMat, y::VecOrMat, z::Matrix) -If `SL` is `Heatmap` and `x` and `y` are vectors, infer from length of `x` and `y` +If `ct` is `Heatmap` and `x` and `y` are vectors, infer from length of `x` and `y` whether they represent edges or centers of the heatmap bins. If they are centers, convert to edges. Convert eltypes to `Float32` and return outputs as a `Tuple`. """ -function convert_arguments(SL::SurfaceLike, x::AbstractVecOrMat{<: Number}, y::AbstractVecOrMat{<: Number}, z::AbstractMatrix{<: Union{Number, Colorant}}) - return map(el32convert, adjust_axes(SL, x, y, z)) +function convert_arguments(ct::GridBased, x::AbstractVecOrMat{<: Number}, y::AbstractVecOrMat{<: Number}, z::AbstractMatrix{<: Union{Number, Colorant}}) + return map(el32convert, adjust_axes(ct, x, y, z)) end -function convert_arguments(SL::SurfaceLike, x::AbstractVecOrMat{<: Number}, y::AbstractVecOrMat{<: Number}, z::AbstractMatrix{<:Number}) - return map(el32convert, adjust_axes(SL, x, y, z)) +function convert_arguments(ct::GridBased, x::AbstractVecOrMat{<: Number}, y::AbstractVecOrMat{<: Number}, z::AbstractMatrix{<:Number}) + return map(el32convert, adjust_axes(ct, x, y, z)) end -convert_arguments(sl::SurfaceLike, x::AbstractMatrix, y::AbstractMatrix) = convert_arguments(sl, x, y, zeros(size(y))) +convert_arguments(ct::VertexGrid, x::AbstractMatrix, y::AbstractMatrix) = convert_arguments(ct, x, y, zeros(size(y))) """ - convert_arguments(P, x, y, z)::Tuple{ClosedInterval, ClosedInterval, Matrix} + convert_arguments(P, x::RangeLike, y::RangeLike, z::AbstractMatrix) -Takes 2 ClosedIntervals's `x`, `y`, and an AbstractMatrix `z`, and converts the closed range to -linspaces with size(z, 1/2) -`P` is the plot Type (it is optional). +Takes one or two ClosedIntervals `x` and `y` and converts them to closed ranges +with size(z, 1/2). """ -function convert_arguments(P::SurfaceLike, x::ClosedInterval, y::ClosedInterval, z::AbstractMatrix) +function convert_arguments(P::GridBased, x::RangeLike, y::RangeLike, z::AbstractMatrix) convert_arguments(P, to_linspace(x, size(z, 1)), to_linspace(y, size(z, 2)), z) end """ - convert_arguments(P, Matrix)::Tuple{ClosedInterval, ClosedInterval, Matrix} - -Takes an `AbstractMatrix`, converts the dimesions `n` and `m` into `ClosedInterval`, -and stores the `ClosedInterval` to `n` and `m`, plus the original matrix in a Tuple. + convert_arguments(::ImageLike, mat::AbstractMatrix) -`P` is the plot Type (it is optional). +Generates `ClosedInterval`s of size `0 .. size(mat, 1/2)` as x and y values. """ -function convert_arguments(sl::SurfaceLike, data::AbstractMatrix) +function convert_arguments(::ImageLike, data::AbstractMatrix) n, m = Float32.(size(data)) - convert_arguments(sl, 0f0 .. n, 0f0 .. m, el32convert(data)) + return (0f0 .. n, 0f0 .. m, el32convert(data)) +end + +function print_range_warning(side::String, value) + @warn "Encountered an `AbstractVector` with value $value on side $side in `convert_arguments` for the `ImageLike` trait. Using an `AbstractVector` to specify one dimension of an `ImageLike` is deprecated because `ImageLike` sides always need exactly two values, start and stop. Use interval notation `start .. stop` or a two-element tuple `(start, stop)` instead." end -function convert_arguments(ds::DiscreteSurface, data::AbstractMatrix) +function convert_arguments(::ImageLike, xs::RangeLike, ys::RangeLike, data::AbstractMatrix) + if xs isa AbstractVector + print_range_warning("x", xs) + end + if ys isa AbstractVector + print_range_warning("y", ys) + end + _interval(v::Union{Interval,AbstractVector}) = Float32(minimum(v)) .. Float32(maximum(v)) # having minimum and maximum here actually invites bugs + _interval(t::Tuple{Any, Any}) = Float32(t[1]) .. Float32(t[2]) + x = _interval(xs) + y = _interval(ys) + return (x, y, el32convert(data)) +end + +function convert_arguments(ct::GridBased, data::AbstractMatrix) n, m = Float32.(size(data)) - convert_arguments(ds, edges(1:n), edges(1:m), el32convert(data)) + convert_arguments(ct, 1f0 .. n, 1f0 .. m, el32convert(data)) end -function convert_arguments(SL::SurfaceLike, x::AbstractVector{<:Number}, y::AbstractVector{<:Number}, z::AbstractVector{<:Number}) +function convert_arguments(ct::GridBased, x::AbstractVector{<:Number}, y::AbstractVector{<:Number}, z::AbstractVector{<:Number}) if !(length(x) == length(y) == length(z)) error("x, y and z need to have the same length. Lengths are $(length.((x, y, z)))") end @@ -406,7 +419,7 @@ function convert_arguments(SL::SurfaceLike, x::AbstractVector{<:Number}, y::Abst j = searchsortedfirst(y_centers, yi) @inbounds zs[i, j] = zi end - convert_arguments(SL, x_centers, y_centers, zs) + convert_arguments(ct, x_centers, y_centers, zs) end @@ -417,14 +430,14 @@ Takes vectors `x` and `y` and the function `f`, and applies `f` on the grid that This is equivalent to `f.(x, y')`. `P` is the plot Type (it is optional). """ -function convert_arguments(sl::SurfaceLike, x::AbstractVector{T1}, y::AbstractVector{T2}, f::Function) where {T1, T2} +function convert_arguments(ct::Union{GridBased, ImageLike}, x::AbstractVector{T1}, y::AbstractVector{T2}, f::Function) where {T1, T2} if !applicable(f, x[1], y[1]) error("You need to pass a function with signature f(x::$T1, y::$T2). Found: $f") end T = typeof(f(x[1], y[1])) z = similar(x, T, (length(x), length(y))) z .= f.(x, y') - return convert_arguments(sl, x, y, z) + return convert_arguments(ct, x, y, z) end ################################################################################ @@ -458,26 +471,6 @@ function convert_arguments(::VolumeLike, x::AbstractVector, y::AbstractVector, z (x, y, z, el32convert(i)) end - -""" - convert_arguments(P, x, y, z, f)::(Vector, Vector, Vector, Matrix) - -Takes `AbstractVector` `x`, `y`, and `z` and the function `f`, evaluates `f` on the volume -spanned by `x`, `y` and `z`, and puts `x`, `y`, `z` and `f(x,y,z)` in a Tuple. - -`P` is the plot Type (it is optional). -""" -function convert_arguments(::VolumeLike, x::AbstractVector, y::AbstractVector, z::AbstractVector, f::Function) - if !applicable(f, x[1], y[1], z[1]) - error("You need to pass a function with signature f(x, y, z). Found: $f") - end - _x, _y, _z = ntuple(Val(3)) do i - A = (x, y, z)[i] - reshape(A, ntuple(j-> j != i ? 1 : length(A), Val(3))) - end - return (x, y, z, el32convert.(f.(_x, _y, _z))) -end - ################################################################################ # <:Lines # ################################################################################ @@ -613,44 +606,69 @@ function convert_arguments( vertices::AbstractArray, indices::AbstractArray ) - m = normal_mesh(to_vertices(vertices), to_triangles(indices)) - (m,) + vs = to_vertices(vertices) + fs = to_triangles(indices) + if eltype(vs) <: Point{3} + ns = normals(vs, fs) + m = GeometryBasics.Mesh(meta(vs; normals=ns), fs) + 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) + end + return (m,) end + ################################################################################ -# <:Arrows # +# Function Conversions # ################################################################################ # Allow the user to pass a function to `arrows` which determines the direction # and magnitude of the arrows. The function must accept `Point2f` as input. # and return Point2f or Vec2f or some array like structure as output. -function convert_arguments(::Type{<: Arrows}, x::AbstractVector, y::AbstractVector, f::Function) +function convert_arguments(::Type{<:Arrows}, x::AbstractVector, y::AbstractVector, f::Function) points = Point2f.(x, y') f_out = Vec2f.(f.(points)) return (vec(points), vec(f_out)) end -function convert_arguments(::Type{<: Arrows}, x::AbstractVector, y::AbstractVector, z::AbstractVector, f::Function) +function convert_arguments(::Type{<:Arrows}, x::AbstractVector, y::AbstractVector, z::AbstractVector, + f::Function) points = [Point3f(x, y, z) for x in x, y in y, z in z] f_out = Vec3f.(f.(points)) return (vec(points), vec(f_out)) end -################################################################################ -# Function Conversions # -################################################################################ +""" + convert_arguments(P, x, y, z, f)::(Vector, Vector, Vector, Matrix) + +Takes `AbstractVector` `x`, `y`, and `z` and the function `f`, evaluates `f` on the volume +spanned by `x`, `y` and `z`, and puts `x`, `y`, `z` and `f(x,y,z)` in a Tuple. + +`P` is the plot Type (it is optional). +""" +function convert_arguments(::VolumeLike, x::AbstractVector, y::AbstractVector, z::AbstractVector, f::Function) + if !applicable(f, x[1], y[1], z[1]) + error("You need to pass a function with signature f(x, y, z). Found: $f") + end + _x, _y, _z = ntuple(Val(3)) do i + A = (x, y, z)[i] + return reshape(A, ntuple(j -> j != i ? 1 : length(A), Val(3))) + end + return (x, y, z, el32convert.(f.(_x, _y, _z))) +end function convert_arguments(P::PlotFunc, r::AbstractVector, f::Function) - ptype = plottype(P, Lines) - to_plotspec(ptype, convert_arguments(ptype, r, f.(r))) + return convert_arguments(P, r, map(f, r)) end function convert_arguments(P::PlotFunc, i::AbstractInterval, f::Function) x, y = PlotUtils.adapted_grid(f, endpoints(i)) - ptype = plottype(P, Lines) - to_plotspec(ptype, convert_arguments(ptype, x, y)) + return convert_arguments(P, x, y) end + + # The following `tryrange` code was copied from Plots.jl # https://github.com/MakieOrg/Plots.jl/blob/15dc61feb57cba1df524ce5d69f68c2c4ea5b942/src/series.jl#L399-L416 @@ -673,8 +691,9 @@ function tryrange(F, vec) error("$F is not a Function, or is not defined at any of the values $vec") end + # OffsetArrays conversions -function convert_arguments(sl::SurfaceLike, wm::OffsetArray) +function convert_arguments(sl::GridBased, wm::OffsetArray) x1, y1 = wm.offsets .+ 1 nx, ny = size(wm) x = range(x1, length = nx) @@ -755,12 +774,12 @@ Converts a representation of vertices `v` to its canonical representation as a - otherwise if `v` has 2 or 3 columns, it will treat each row as a vertex. """ function to_vertices(verts::AbstractVector{<: VecTypes{3, T}}) where T - vert3f0 = T != Float32 ? Point3f.(verts) : verts + vert3f0 = T != Float32 ? map(Point3f, verts) : verts return reinterpret(Point3f, vert3f0) end -function to_vertices(verts::AbstractVector{<: VecTypes}) - to_vertices(to_ndim.(Point3f, verts, 0.0)) +function to_vertices(verts::AbstractVector{<: VecTypes{N}}) where {N} + return map(Point{N, Float32}, verts) end function to_vertices(verts::AbstractMatrix{<: Number}) @@ -780,7 +799,7 @@ function to_vertices(verts::AbstractMatrix{T}, ::Val{1}) where T <: Number else let N = Val(N), lverts = verts broadcast(1:size(verts, 2), N) do vidx, n - to_ndim(Point3f, ntuple(i-> lverts[i, vidx], n), 0.0) + Point(ntuple(i-> Float32(lverts[i, vidx]), n)) end end end @@ -789,7 +808,7 @@ end function to_vertices(verts::AbstractMatrix{T}, ::Val{2}) where T <: Number let N = Val(size(verts, 2)), lverts = verts broadcast(1:size(verts, 1), N) do vidx, n - to_ndim(Point3f, ntuple(i-> lverts[vidx, i], n), 0.0) + Point(ntuple(i-> Float32(verts[vidx, i]), n)) end end end @@ -1334,42 +1353,263 @@ function convert_attribute(value::Union{Symbol, String}, k::key"algorithm") end, k) end -const DEFAULT_MARKER_MAP = Dict{Symbol, BezierPath}() +#= +The below is the output from: +```julia +# The bezier markers should not look out of place when used together with text +# where both markers and text are given the same size, i.e. the marker and fontsizes +# should correspond approximately in a visual sense. + +# All the basic bezier shapes are approximately built in a 1 by 1 square centered +# around the origin, with slight deviations to match them better to each other. + +# An 'x' of DejaVu sans is only about 55pt high at 100pt font size, so if the marker +# shapes are just used as is, they look much too large in comparison. +# To me, a factor of 0.75 looks ok compared to both uppercase and lowercase letters of Dejavu. +size_factor = 0.75 +DEFAULT_MARKER_MAP[:rect] = scale(BezierSquare, size_factor) +DEFAULT_MARKER_MAP[:diamond] = scale(rotate(BezierSquare, pi/4), size_factor) +DEFAULT_MARKER_MAP[:hexagon] = scale(bezier_ngon(6, 0.5, pi/2), size_factor) +DEFAULT_MARKER_MAP[:cross] = scale(BezierCross, size_factor) +DEFAULT_MARKER_MAP[:xcross] = scale(BezierX, size_factor) +DEFAULT_MARKER_MAP[:utriangle] = scale(BezierUTriangle, size_factor) +DEFAULT_MARKER_MAP[:dtriangle] = scale(BezierDTriangle, size_factor) +DEFAULT_MARKER_MAP[:ltriangle] = scale(BezierLTriangle, size_factor) +DEFAULT_MARKER_MAP[:rtriangle] = scale(BezierRTriangle, size_factor) +DEFAULT_MARKER_MAP[:pentagon] = scale(bezier_ngon(5, 0.5, pi/2), size_factor) +DEFAULT_MARKER_MAP[:octagon] = scale(bezier_ngon(8, 0.5, pi/2), size_factor) +DEFAULT_MARKER_MAP[:star4] = scale(bezier_star(4, 0.25, 0.6, pi/2), size_factor) +DEFAULT_MARKER_MAP[:star5] = scale(bezier_star(5, 0.28, 0.6, pi/2), size_factor) +DEFAULT_MARKER_MAP[:star6] = scale(bezier_star(6, 0.30, 0.6, pi/2), size_factor) +DEFAULT_MARKER_MAP[:star8] = scale(bezier_star(8, 0.33, 0.6, pi/2), size_factor) +DEFAULT_MARKER_MAP[:vline] = scale(scale(BezierSquare, (0.2, 1.0)), size_factor) +DEFAULT_MARKER_MAP[:hline] = scale(scale(BezierSquare, (1.0, 0.2)), size_factor) +DEFAULT_MARKER_MAP[:+] = scale(BezierCross, size_factor) +DEFAULT_MARKER_MAP[:x] = scale(BezierX, size_factor) +DEFAULT_MARKER_MAP[:circle] = scale(BezierCircle, size_factor) +``` +We have to write this out to make sure we rotate/scale don't generate slightly different values between Julia versions. +This would create different hashes, making the caching in the texture atlas fail! +See: https://github.com/MakieOrg/Makie.jl/pull/3394 +=# + +const DEFAULT_MARKER_MAP = Dict(:+ => BezierPath([Makie.MoveTo([0.1245, 0.375]), + Makie.LineTo([0.1245, 0.1245]), + Makie.LineTo([0.375, 0.1245]), + Makie.LineTo([0.375, -0.12449999999999999]), + Makie.LineTo([0.1245, -0.1245]), + Makie.LineTo([0.12450000000000003, -0.375]), + Makie.LineTo([-0.12449999999999997, -0.375]), + Makie.LineTo([-0.12449999999999999, -0.12450000000000003]), + Makie.LineTo([-0.375, -0.12450000000000006]), + Makie.LineTo([-0.375, 0.12449999999999994]), + Makie.LineTo([-0.12450000000000003, 0.12449999999999999]), + Makie.LineTo([-0.12450000000000007, 0.37499999999999994]), + Makie.ClosePath()]), + :diamond => BezierPath([Makie.MoveTo([0.4464931614186469, + -5.564531862779532e-17]), + Makie.LineTo([2.10398220755128e-17, + 0.4464931614186469]), + Makie.LineTo([-0.4464931614186469, + 5.564531862779532e-17]), + Makie.LineTo([-2.10398220755128e-17, + -0.4464931614186469]), + Makie.ClosePath()]), + :star4 => BezierPath([Makie.MoveTo([2.7554554183166277e-17, + 0.44999999999999996]), + Makie.LineTo([-0.13258251920342445, + 0.13258251920342445]), + Makie.LineTo([-0.44999999999999996, + 5.5109108366332553e-17]), + Makie.LineTo([-0.13258251920342445, + -0.13258251920342445]), + Makie.LineTo([-8.266365659379842e-17, + -0.44999999999999996]), + Makie.LineTo([0.13258251920342445, + -0.13258251920342445]), + Makie.LineTo([0.44999999999999996, + -1.1021821673266511e-16]), + Makie.LineTo([0.13258251920342445, 0.13258251920342445]), + Makie.ClosePath()]), + :star8 => BezierPath([Makie.MoveTo([2.7554554183166277e-17, + 0.44999999999999996]), + Makie.LineTo([-0.09471414797008038, 0.2286601772904396]), + Makie.LineTo([-0.31819804608821867, + 0.31819804608821867]), + Makie.LineTo([-0.2286601772904396, 0.09471414797008038]), + Makie.LineTo([-0.44999999999999996, + 5.5109108366332553e-17]), + Makie.LineTo([-0.2286601772904396, + -0.09471414797008038]), + Makie.LineTo([-0.31819804608821867, + -0.31819804608821867]), + Makie.LineTo([-0.09471414797008038, + -0.2286601772904396]), + Makie.LineTo([-8.266365659379842e-17, + -0.44999999999999996]), + Makie.LineTo([0.09471414797008038, -0.2286601772904396]), + Makie.LineTo([0.31819804608821867, + -0.31819804608821867]), + Makie.LineTo([0.2286601772904396, -0.09471414797008038]), + Makie.LineTo([0.44999999999999996, + -1.1021821673266511e-16]), + Makie.LineTo([0.2286601772904396, 0.09471414797008038]), + Makie.LineTo([0.31819804608821867, 0.31819804608821867]), + Makie.LineTo([0.09471414797008038, 0.2286601772904396]), + Makie.ClosePath()]), + :star6 => BezierPath([Makie.MoveTo([2.7554554183166277e-17, + 0.44999999999999996]), + Makie.LineTo([-0.11249999999999999, 0.1948557123541832]), + Makie.LineTo([-0.3897114247083664, 0.22499999999999998]), + Makie.LineTo([-0.22499999999999998, + 2.7554554183166277e-17]), + Makie.LineTo([-0.3897114247083664, + -0.22499999999999998]), + Makie.LineTo([-0.11249999999999999, + -0.1948557123541832]), + Makie.LineTo([-8.266365659379842e-17, + -0.44999999999999996]), + Makie.LineTo([0.11249999999999999, -0.1948557123541832]), + Makie.LineTo([0.3897114247083664, -0.22499999999999998]), + Makie.LineTo([0.22499999999999998, + -5.5109108366332553e-17]), + Makie.LineTo([0.3897114247083664, 0.22499999999999998]), + Makie.LineTo([0.11249999999999999, 0.1948557123541832]), + Makie.ClosePath()]), + :rtriangle => BezierPath([Makie.MoveTo([0.485, -8.909305463796994e-17]), + Makie.LineTo([-0.24249999999999994, 0.36375]), + Makie.LineTo([-0.2425000000000001, + -0.36374999999999996]), + Makie.ClosePath()]), + :x => BezierPath([Makie.MoveTo([-0.1771302486872301, 0.35319983720268056]), + Makie.LineTo([1.39759596452057e-17, 0.17606958851545035]), + Makie.LineTo([0.17713024868723018, 0.3531998372026805]), + Makie.LineTo([0.3531998372026805, 0.17713024868723012]), + Makie.LineTo([0.17606958851545035, -1.025465786723834e-17]), + Makie.LineTo([0.3531998372026805, -0.17713024868723015]), + Makie.LineTo([0.17713024868723015, -0.3531998372026805]), + Makie.LineTo([1.1151998010815531e-17, -0.17606958851545035]), + Makie.LineTo([-0.17713024868723015, -0.3531998372026805]), + Makie.LineTo([-0.35319983720268044, -0.17713024868723018]), + Makie.LineTo([-0.17606958851545035, + -1.4873299788782892e-17]), + Makie.LineTo([-0.3531998372026805, 0.1771302486872301]), + Makie.ClosePath()]), + :circle => BezierPath([Makie.MoveTo([0.3525, 0.0]), + EllipticalArc([0.0, 0.0], 0.3525, 0.3525, 0.0, 0.0, + 6.283185307179586), Makie.ClosePath()]), + :pentagon => BezierPath([Makie.MoveTo([2.2962128485971897e-17, 0.375]), + Makie.LineTo([-0.35664620250463486, + 0.11588137596845627]), + Makie.LineTo([-0.22041946649551392, + -0.30338137596845627]), + Makie.LineTo([0.22041946649551392, + -0.30338137596845627]), + Makie.LineTo([0.35664620250463486, + 0.11588137596845627]), + Makie.ClosePath()]), + :vline => BezierPath([Makie.MoveTo([0.063143668438509, -0.315718342192545]), + Makie.LineTo([0.063143668438509, 0.315718342192545]), + Makie.LineTo([-0.063143668438509, 0.315718342192545]), + Makie.LineTo([-0.063143668438509, -0.315718342192545]), + Makie.ClosePath()]), + :cross => BezierPath([Makie.MoveTo([0.1245, 0.375]), + Makie.LineTo([0.1245, 0.1245]), + Makie.LineTo([0.375, 0.1245]), + Makie.LineTo([0.375, -0.12449999999999999]), + Makie.LineTo([0.1245, -0.1245]), + Makie.LineTo([0.12450000000000003, -0.375]), + Makie.LineTo([-0.12449999999999997, -0.375]), + Makie.LineTo([-0.12449999999999999, + -0.12450000000000003]), + Makie.LineTo([-0.375, -0.12450000000000006]), + Makie.LineTo([-0.375, 0.12449999999999994]), + Makie.LineTo([-0.12450000000000003, + 0.12449999999999999]), + Makie.LineTo([-0.12450000000000007, + 0.37499999999999994]), + Makie.ClosePath()]), + :xcross => BezierPath([Makie.MoveTo([-0.1771302486872301, + 0.35319983720268056]), + Makie.LineTo([1.39759596452057e-17, + 0.17606958851545035]), + Makie.LineTo([0.17713024868723018, 0.3531998372026805]), + Makie.LineTo([0.3531998372026805, 0.17713024868723012]), + Makie.LineTo([0.17606958851545035, + -1.025465786723834e-17]), + Makie.LineTo([0.3531998372026805, + -0.17713024868723015]), + Makie.LineTo([0.17713024868723015, + -0.3531998372026805]), + Makie.LineTo([1.1151998010815531e-17, + -0.17606958851545035]), + Makie.LineTo([-0.17713024868723015, + -0.3531998372026805]), + Makie.LineTo([-0.35319983720268044, + -0.17713024868723018]), + Makie.LineTo([-0.17606958851545035, + -1.4873299788782892e-17]), + Makie.LineTo([-0.3531998372026805, 0.1771302486872301]), + Makie.ClosePath()]), + :rect => BezierPath([Makie.MoveTo([0.315718342192545, -0.315718342192545]), + Makie.LineTo([0.315718342192545, 0.315718342192545]), + Makie.LineTo([-0.315718342192545, 0.315718342192545]), + Makie.LineTo([-0.315718342192545, -0.315718342192545]), + Makie.ClosePath()]), + :ltriangle => BezierPath([Makie.MoveTo([-0.485, 2.969768487932331e-17]), + Makie.LineTo([0.2425, -0.36375]), + Makie.LineTo([0.24250000000000005, 0.36375]), + Makie.ClosePath()]), + :dtriangle => BezierPath([Makie.MoveTo([-0.0, -0.485]), + Makie.LineTo([0.36375, 0.24250000000000002]), + Makie.LineTo([-0.36375, 0.24250000000000002]), + Makie.ClosePath()]), + :utriangle => BezierPath([Makie.MoveTo([0.0, 0.485]), + Makie.LineTo([-0.36375, -0.24250000000000002]), + Makie.LineTo([0.36375, -0.24250000000000002]), + Makie.ClosePath()]), + :star5 => BezierPath([Makie.MoveTo([2.7554554183166277e-17, + 0.44999999999999996]), + Makie.LineTo([-0.12343490123748782, + 0.16989357054233553]), + Makie.LineTo([-0.4279754430055618, 0.13905765116214752]), + Makie.LineTo([-0.19972187340259556, + -0.06489357054233552]), + Makie.LineTo([-0.2645033597946167, -0.3640576511621475]), + Makie.LineTo([-3.8576373077105933e-17, + -0.21000000000000002]), + Makie.LineTo([0.2645033597946167, -0.3640576511621475]), + Makie.LineTo([0.19972187340259556, + -0.06489357054233552]), + Makie.LineTo([0.4279754430055618, 0.13905765116214752]), + Makie.LineTo([0.12343490123748782, 0.16989357054233553]), + Makie.ClosePath()]), + :octagon => BezierPath([Makie.MoveTo([2.2962128485971897e-17, 0.375]), + Makie.LineTo([-0.2651650384068489, + 0.2651650384068489]), + Makie.LineTo([-0.375, 4.5924256971943795e-17]), + Makie.LineTo([-0.2651650384068489, + -0.2651650384068489]), + Makie.LineTo([-6.888638049483202e-17, -0.375]), + Makie.LineTo([0.2651650384068489, + -0.2651650384068489]), + Makie.LineTo([0.375, -9.184851394388759e-17]), + Makie.LineTo([0.2651650384068489, 0.2651650384068489]), + Makie.ClosePath()]), + :hline => BezierPath([Makie.MoveTo([0.315718342192545, -0.063143668438509]), + Makie.LineTo([0.315718342192545, 0.063143668438509]), + Makie.LineTo([-0.315718342192545, 0.063143668438509]), + Makie.LineTo([-0.315718342192545, -0.063143668438509]), + Makie.ClosePath()]), + :hexagon => BezierPath([Makie.MoveTo([2.2962128485971897e-17, 0.375]), + Makie.LineTo([-0.32475952059030533, 0.1875]), + Makie.LineTo([-0.32475952059030533, -0.1875]), + Makie.LineTo([-6.888638049483202e-17, -0.375]), + Makie.LineTo([0.32475952059030533, -0.1875]), + Makie.LineTo([0.32475952059030533, 0.1875]), + Makie.ClosePath()])) function default_marker_map() - # The bezier markers should not look out of place when used together with text - # where both markers and text are given the same size, i.e. the marker and fontsizes - # should correspond approximately in a visual sense. - - # All the basic bezier shapes are approximately built in a 1 by 1 square centered - # around the origin, with slight deviations to match them better to each other. - - # An 'x' of DejaVu sans is only about 55pt high at 100pt font size, so if the marker - # shapes are just used as is, they look much too large in comparison. - # To me, a factor of 0.75 looks ok compared to both uppercase and lowercase letters of Dejavu. - if isempty(DEFAULT_MARKER_MAP) - size_factor = 0.75 - DEFAULT_MARKER_MAP[:rect] = scale(BezierSquare, size_factor) - DEFAULT_MARKER_MAP[:diamond] = scale(rotate(BezierSquare, pi/4), size_factor) - DEFAULT_MARKER_MAP[:hexagon] = scale(bezier_ngon(6, 0.5, pi/2), size_factor) - DEFAULT_MARKER_MAP[:cross] = scale(BezierCross, size_factor) - DEFAULT_MARKER_MAP[:xcross] = scale(BezierX, size_factor) - DEFAULT_MARKER_MAP[:utriangle] = scale(BezierUTriangle, size_factor) - DEFAULT_MARKER_MAP[:dtriangle] = scale(BezierDTriangle, size_factor) - DEFAULT_MARKER_MAP[:ltriangle] = scale(BezierLTriangle, size_factor) - DEFAULT_MARKER_MAP[:rtriangle] = scale(BezierRTriangle, size_factor) - DEFAULT_MARKER_MAP[:pentagon] = scale(bezier_ngon(5, 0.5, pi/2), size_factor) - DEFAULT_MARKER_MAP[:octagon] = scale(bezier_ngon(8, 0.5, pi/2), size_factor) - DEFAULT_MARKER_MAP[:star4] = scale(bezier_star(4, 0.25, 0.6, pi/2), size_factor) - DEFAULT_MARKER_MAP[:star5] = scale(bezier_star(5, 0.28, 0.6, pi/2), size_factor) - DEFAULT_MARKER_MAP[:star6] = scale(bezier_star(6, 0.30, 0.6, pi/2), size_factor) - DEFAULT_MARKER_MAP[:star8] = scale(bezier_star(8, 0.33, 0.6, pi/2), size_factor) - DEFAULT_MARKER_MAP[:vline] = scale(scale(BezierSquare, (0.2, 1.0)), size_factor) - DEFAULT_MARKER_MAP[:hline] = scale(scale(BezierSquare, (1.0, 0.2)), size_factor) - DEFAULT_MARKER_MAP[:+] = scale(BezierCross, size_factor) - DEFAULT_MARKER_MAP[:x] = scale(BezierX, size_factor) - DEFAULT_MARKER_MAP[:circle] = scale(BezierCircle, size_factor) - end return DEFAULT_MARKER_MAP end @@ -1413,6 +1653,7 @@ to_spritemarker(x::Rect) = x to_spritemarker(b::BezierPath) = b to_spritemarker(b::Polygon) = BezierPath(b) to_spritemarker(b) = error("Not a valid scatter marker: $(typeof(b))") +to_spritemarker(x::Shape) = x function to_spritemarker(str::String) error("Using strings for multiple char markers is deprecated. Use `collect(string)` or `['x', 'o', ...]` instead. Found: $(str)") @@ -1469,6 +1710,8 @@ end convert_attribute(value, ::key"diffuse") = Vec3f(value) convert_attribute(value, ::key"specular") = Vec3f(value) +convert_attribute(value, ::key"backlight") = Float32(value) + # SAMPLER overloads diff --git a/src/deprecated.jl b/src/deprecated.jl index 5bc7fe2b141..de9cbdc9fed 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -1,9 +1,16 @@ -function register_backend!(backend) - @warn("`register_backend!` is an internal deprecated function, which shouldn't be used outside Makie. - if you must really use this function, it's now `set_active_backend!(::Module)") -end +########################################### +# v0.20 deprecations: +## +Base.@deprecate_binding DiscreteSurface CellGrid true +Base.@deprecate_binding ContinuousSurface VertexGrid true -function backend_display(args...) - @warn("`backend_display` is an internal deprecated function, which shouldn't be used outside Makie. - if you must really use this function, it's now just `display(::Backend.Screen, figlike)`") +function Base.getproperty(scene::Scene, field::Symbol) + if field === :px_area + @warn "`.px_area` got renamed to `.viewport`, and means the area the scene maps to in device independent units, not pixels. Note, `size(scene) == widths(scene.viewport[])`" + return scene.viewport + end + return getfield(scene, field) end + +@deprecate pixelarea viewport true +Base.@deprecate_binding Combined Plot true diff --git a/src/display.jl b/src/display.jl index 30b7c10ef74..1ec5c5d0120 100644 --- a/src/display.jl +++ b/src/display.jl @@ -66,14 +66,13 @@ function set_screen_config!(backend::Module, new_values) return backend_defaults end -function merge_screen_config(::Type{Config}, screen_config_kw) where Config +function merge_screen_config(::Type{Config}, config::Dict) where Config backend = parentmodule(Config) key = nameof(backend) backend_defaults = CURRENT_DEFAULT_THEME[key] - kw_nt = values(screen_config_kw) arguments = map(fieldnames(Config)) do name - if haskey(kw_nt, name) - return getfield(kw_nt, name) + if haskey(config, name) + return config[name] else return to_value(backend_defaults[name]) end @@ -110,9 +109,9 @@ end can_show_inline(::Missing) = false # no backend function can_show_inline(Backend) - for mime in [MIME"juliavscode/html"(), MIME"text/html"(), MIME"image/png"(), MIME"image/svg+xml"()] - if backend_showable(Backend.Screen, mime) - return has_mime_display(mime) + for mime in (MIME"juliavscode/html"(), MIME"text/html"(), MIME"image/png"(), MIME"image/svg+xml"()) + if backend_showable(Backend.Screen, mime) && has_mime_display(mime) + return true end end return false @@ -130,6 +129,7 @@ see `?Backend.Screen` or `Base.doc(Backend.Screen)` for applicable options. """ function Base.display(figlike::FigureLike; backend=current_backend(), inline=ALWAYS_INLINE_PLOTS[], update = true, screen_config...) + config = Dict{Symbol, Any}(screen_config) if ismissing(backend) error(""" No backend available! @@ -141,10 +141,15 @@ function Base.display(figlike::FigureLike; backend=current_backend(), end # We show inline if explicitely requested or if automatic and we can actually show something inline! + scene = get_scene(figlike) if (inline === true || inline === automatic) && can_show_inline(backend) + # We can't forward the screenconfig to show, but show uses the current screen if there is any + # We use that, to create a screen before show and rely on show picking up that screen + screen = getscreen(backend, scene, config) + push_screen!(scene, screen) Core.invoke(display, Tuple{Any}, figlike) # In WGLMakie, we need to wait for the display being done - screen = getscreen(get_scene(figlike)) + screen = getscreen(scene) wait_for_display(screen) return screen else @@ -156,9 +161,8 @@ function Base.display(figlike::FigureLike; backend=current_backend(), If this wasn't set on purpose, call `Makie.inline!()` to restore the default. """ end - scene = get_scene(figlike) update && update_state_before_display!(figlike) - screen = getscreen(backend, scene; screen_config...) + screen = getscreen(backend, scene, config) display(screen, scene) return screen end @@ -204,9 +208,16 @@ end Base.showable(mime::MIME, fig::FigureLike) = _backend_showable(mime) -# need to define this to resolve ambiguoity issue +# need to define this to resolve ambiguity issue Base.showable(mime::MIME"application/json", fig::FigureLike) = _backend_showable(mime) +const WEB_MIMES = ( + MIME"text/html", + MIME"application/vnd.webio.application+html", + MIME"application/prs.juno.plotpane+html", + MIME"juliavscode/html") + + backend_showable(@nospecialize(screen), @nospecialize(mime)) = false # fallback show when no backend is selected @@ -244,7 +255,7 @@ function Base.show(io::IO, m::MIME, figlike::FigureLike) backend = current_backend() # get current screen the scene is already displayed on, or create a new screen update_state_before_display!(figlike) - screen = getscreen(backend, scene, io, m; visible=false) + screen = getscreen(backend, scene, Dict(:visible=>false), io, m) backend_show(screen, io, m, scene) return screen end @@ -263,7 +274,7 @@ filetype(::FileIO.File{F}) where F = F # Allow format to be overridden with first argument """ - FileIO.save(filename, scene; resolution = size(scene), pt_per_unit = 0.75, px_per_unit = 1.0) + FileIO.save(filename, scene; size = size(scene), pt_per_unit = 0.75, px_per_unit = 1.0) Save a `Scene` with the specified filename and format. @@ -277,7 +288,7 @@ Save a `Scene` with the specified filename and format. ## All Backends -- `resolution`: `(width::Int, height::Int)` of the scene in dimensionless units (equivalent to `px` for GLMakie and WGLMakie). +- `size`: `(width::Int, height::Int)` of the scene in dimensionless units. - `update`: Whether the figure should be updated before saving. This resets the limits of all Axes in the figure. Defaults to `true`. - `backend`: Specify the `Makie` backend that should be used for saving. Defaults to the current backend. - Further keywords will be forwarded to the screen. @@ -296,14 +307,19 @@ end function FileIO.save( file::FileIO.Formatted, fig::FigureLike; - resolution = size(get_scene(fig)), + size = Base.size(get_scene(fig)), + resolution = nothing, backend = current_backend(), update = true, screen_config... ) scene = get_scene(fig) - if resolution != size(scene) - resize!(scene, resolution) + if resolution !== nothing + @warn "The keyword argument `resolution` for `save()` has been deprecated. Use `size` instead, which better reflects that this is a unitless size and not a pixel resolution." + size = resolution + end + if size != Base.size(scene) + resize!(scene, size) end filename = FileIO.filename(file) # Delete previous file if it exists and query only the file string for type. @@ -315,13 +331,16 @@ function FileIO.save( # query the filetype only from the file extension F = filetype(file) mime = format2mime(F) + try return open(filename, "w") do io # If the scene already got displayed, we get the current screen its displayed on # Else, we create a new scene and update the state of the fig update && update_state_before_display!(fig) - visible = !isnothing(getscreen(scene)) # if already has a screen, don't hide it! - screen = getscreen(backend, scene, io, mime; visible=visible, screen_config...) + visible = isvisible(getscreen(scene)) # if already has a screen, don't hide it! + config = Dict{Symbol, Any}(screen_config) + get!(config, :visible, visible) + screen = getscreen(backend, scene, config, io, mime) backend_show(screen, io, mime, scene) end catch e @@ -388,9 +407,9 @@ end getscreen(scene::SceneLike, backend=current_backend()) = getscreen(get_scene(scene), backend) -function getscreen(backend::Union{Missing, Module}, scene::Scene, args...; screen_config...) +function getscreen(backend::Union{Missing, Module}, scene::Scene, _config::Dict, args...) screen = getscreen(scene, backend) - config = Makie.merge_screen_config(backend.ScreenConfig, screen_config) + config = merge_screen_config(backend.ScreenConfig, _config) if !isnothing(screen) && parentmodule(typeof(screen)) == backend new_screen = apply_screen_config!(screen, config, scene, args...) if new_screen !== screen @@ -410,13 +429,17 @@ function getscreen(backend::Union{Missing, Module}, scene::Scene, args...; scree end function get_sub_picture(image, format::ImageStorageFormat, rect) - xmin, ymin = minimum(rect) .- (1, 0) + xmin, ymin = minimum(rect) .- Vec(1, 0) xmax, ymax = maximum(rect) start = size(image, 1) - ymax stop = size(image, 1) - ymin return image[start:stop, xmin:xmax] end +# Needs to be overloaded by backends, with fallback true +isvisible(screen::MakieScreen) = true +isvisible(::Nothing) = false + """ colorbuffer(scene, format::ImageStorageFormat = JuliaNative; update=true, backend=current_backend(), screen_config...) @@ -434,25 +457,38 @@ or RGBA. function colorbuffer(fig::FigureLike, format::ImageStorageFormat = JuliaNative; update=true, backend = current_backend(), screen_config...) scene = get_scene(fig) update && update_state_before_display!(fig) - visible = !isnothing(getscreen(scene)) # if already has a screen, don't hide it! - screen = getscreen(backend, scene; start_renderloop=false, visible=visible, screen_config...) + # if already has a screen, use their visibility value, if no screen, returns false + visible = isvisible(getscreen(scene)) + config = Dict{Symbol,Any}(screen_config) + get!(config, :visible, visible) + get!(config, :start_renderloop, false) + screen = getscreen(backend, scene, config) img = colorbuffer(screen, format) if !isroot(scene) - return get_sub_picture(img, format, pixelarea(scene)[]) + return get_sub_picture(img, format, viewport(scene)[]) else return img end end # Fallback for any backend that will just use colorbuffer to write out an image -function backend_show(screen::MakieScreen, io::IO, m::MIME"image/png", scene::Scene) +function backend_show(screen::MakieScreen, io::IO, ::MIME"image/png", scene::Scene) img = colorbuffer(screen) FileIO.save(FileIO.Stream{FileIO.format"PNG"}(Makie.raw_io(io)), img) return end -function backend_show(screen::MakieScreen, io::IO, m::MIME"image/jpeg", scene::Scene) - img = colorbuffer(scene) +function backend_show(screen::MakieScreen, io::IO, ::MIME"image/jpeg", scene::Scene) + img = colorbuffer(screen) FileIO.save(FileIO.Stream{FileIO.format"JPEG"}(Makie.raw_io(io)), img) return end + +function backend_show(screen::MakieScreen, io::IO, ::Union{WEB_MIMES...}, scene::Scene) + w, h = size(scene) + png_io = IOBuffer() + backend_show(screen, png_io, MIME"image/png"(), scene) + b64 = Base64.base64encode(String(take!(png_io))) + print(io, "") + return +end diff --git a/src/documentation/documentation.jl b/src/documentation/documentation.jl index ce83835cd4c..31001416569 100644 --- a/src/documentation/documentation.jl +++ b/src/documentation/documentation.jl @@ -186,7 +186,7 @@ to_func(func::Function) = func Maps the input of a function name to its cooresponding Type. """ -to_type(func::Function) = Combined{func} +to_type(func::Function) = Plot{func} to_type(Typ::Type{T}) where T <: AbstractPlot = Typ diff --git a/src/ffmpeg-util.jl b/src/ffmpeg-util.jl index 2ae838e6d6d..a3f5eed6fc1 100644 --- a/src/ffmpeg-util.jl +++ b/src/ffmpeg-util.jl @@ -221,7 +221,10 @@ function VideoStream(fig::FigureLike; path = joinpath(dir, "$(gensym(:video)).$(format)") scene = get_scene(fig) update_state_before_display!(fig) - screen = getscreen(backend, scene, GLNative; visible=visible, start_renderloop=false, screen_config...) + config = Dict{Symbol,Any}(screen_config) + get!(config, :visible, visible) + get!(config, :start_renderloop, false) + screen = getscreen(backend, scene, config, GLNative) _xdim, _ydim = size(screen) xdim = iseven(_xdim) ? _xdim : _xdim + 1 ydim = iseven(_ydim) ? _ydim : _ydim + 1 diff --git a/src/figureplotting.jl b/src/figureplotting.jl index 968758dacfd..4abfc12e42c 100644 --- a/src/figureplotting.jl +++ b/src/figureplotting.jl @@ -3,6 +3,11 @@ struct AxisPlot plot::AbstractPlot end +struct FigureAxis + figure::Figure + axis::Any +end + Base.show(io::IO, fap::FigureAxisPlot) = show(io, fap.figure) Base.show(io::IO, ::MIME"text/plain", fap::FigureAxisPlot) = print(io, "FigureAxisPlot()") @@ -27,91 +32,151 @@ function _disallow_keyword(kw, attributes) end end -@nospecialize -function get_axis(fig, P, axis_kw::Dict, plot_attr, plot_args) - if haskey(axis_kw, :type) - axtype = axis_kw[:type] - pop!(axis_kw, :type) - ax = axtype(fig; axis_kw...) - else - proxyscene = Scene() - # We dont forward the attributes to the plot, since we only need the arguments to determine the axis type - # Remove arguments may not work with plotting into the scene - delete!(plot_attr, :show_axis) - delete!(plot_attr, :limits) - delete!(plot_attr, :color) # Color may contain Cycled(1), which needs the axis to get resolved to a color - plot!(proxyscene, P, Attributes(plot_attr), plot_args...) - if is2d(proxyscene) - ax = Axis(fig; axis_kw...) - else - ax = LScene(fig; axis_kw...) - end - empty!(proxyscene) +# For plots that dont require an axis, +# E.g. BlockSpec +struct FigureOnly end + + +function args_preferred_axis(::Type{<:Union{Wireframe,Surface,Contour3d}}, x::AbstractArray, y::AbstractArray, + z::AbstractArray) + return all(x -> z[1] ≈ x, z) ? Axis : LScene +end + +args_preferred_axis(x) = nothing + +function args_preferred_axis(@nospecialize(args...)) + # Fallback: check each single arg if they have a favorite axis type + for arg in args + r = args_preferred_axis(arg) + isnothing(r) || return r end - return ax + return nothing +end + +args_preferred_axis(::AbstractVector, ::AbstractVector, ::AbstractVector, ::Function) = LScene +args_preferred_axis(::AbstractArray{T,3}) where {T} = LScene + +function args_preferred_axis(::AbstractVector{<:Union{AbstractGeometry{DIM},GeometryBasics.Mesh{DIM}}}) where {DIM} + return DIM === 2 ? Axis : LScene +end + +function args_preferred_axis(::Union{AbstractGeometry{DIM},GeometryBasics.Mesh{DIM}}) where {DIM} + return DIM === 2 ? Axis : LScene +end + +args_preferred_axis(::AbstractVector{<:Point3}) = LScene +args_preferred_axis(::AbstractVector{<:Point2}) = Axis + + +preferred_axis_type(::Volume) = LScene +preferred_axis_type(::Union{Image,Heatmap}) = Axis + +function preferred_axis_type(p::Plot{F}) where F + # Otherwise, we check the arguments + input_args = map(to_value, p.args) + result = args_preferred_axis(Plot{F}, input_args...) + isnothing(result) || return result + conv_args = map(to_value, p.converted) + result = args_preferred_axis(Plot{F}, conv_args...) + isnothing(result) && return Axis # Fallback to Axis if nothing found + return result end -@specialize -function plot(P::PlotFunc, args...; axis=NamedTuple(), figure=NamedTuple(), kw_attributes...) - _validate_nt_like_keyword(axis, "axis") - _validate_nt_like_keyword(figure, "figure") +to_dict(dict::Dict) = dict +to_dict(nt::NamedTuple) = Dict{Symbol,Any}(pairs(nt)) +to_dict(attr::Attributes) = attributes(attr) - fig = Figure(; figure...) +function extract_attributes(dict, key) + attributes = pop!(dict, key, Dict{Symbol,Any}()) + _validate_nt_like_keyword(attributes, key) + return to_dict(attributes) +end - axis = Dict(pairs(axis)) - ax = get_axis(fig, P, axis, Dict{Symbol, Any}(kw_attributes), args) +function create_axis_for_plot(figure::Figure, plot::AbstractPlot, attributes::Dict) + axis_kw = extract_attributes(attributes, :axis) + AxType = if haskey(axis_kw, :type) + pop!(axis_kw, :type) + else + preferred_axis_type(plot) + end + if AxType == FigureOnly # For FigureSpec, which creates Axes dynamically + return nothing + end + bbox = pop!(axis_kw, :bbox, nothing) + return _block(AxType, figure, [], axis_kw, bbox) +end - fig[1, 1] = ax - p = plot!(ax, P, Attributes(kw_attributes), args...) - return FigureAxisPlot(fig, ax, p) +function create_axis_like(plot::AbstractPlot, attributes::Dict, ::Nothing) + figure_kw = extract_attributes(attributes, :figure) + figure = Figure(; figure_kw...) + ax = create_axis_for_plot(figure, plot, attributes) + if isnothing(ax) # For FigureSpec + return figure + else + figure[1, 1] = ax + return FigureAxis(figure, ax) + end end -# without scenelike, use current axis of current figure +MakieCore.create_axis_like!(@nospecialize(::AbstractPlot), attributes::Dict, s::Union{Plot, Scene}) = s -function plot!(P::PlotFunc, args...; kw_attributes...) +function MakieCore.create_axis_like!(@nospecialize(::AbstractPlot), attributes::Dict, ::Nothing) figure = current_figure() isnothing(figure) && error("There is no current figure to plot into.") + _disallow_keyword(:figure, attributes) ax = current_axis(figure) isnothing(ax) && error("There is no current axis to plot into.") - return plot!(P, ax, args...; kw_attributes...) + _disallow_keyword(:axis, attributes) + return ax end -function plot(P::PlotFunc, gp::GridPosition, args...; axis=NamedTuple(), kw_attributes...) - _validate_nt_like_keyword(axis, "axis") +function MakieCore.create_axis_like!(@nospecialize(::AbstractPlot), attributes::Dict, gp::GridPosition) + _disallow_keyword(:figure, attributes) + c = contents(gp; exact=true) + if !(length(c) == 1 && can_be_current_axis(c[1])) + error("There needs to be a single axis-like object at $(gp.span), $(gp.side) to plot into.\nUse a non-mutating plotting command to create an axis implicitly.") + end + ax = first(c) + _disallow_keyword(:axis, attributes) + return ax +end + +function create_axis_like(plot::AbstractPlot, attributes::Dict, gp::GridPosition) + _disallow_keyword(:figure, attributes) + figure = get_top_parent(gp) c = contents(gp; exact=true) if !isempty(c) error(""" You have used the non-mutating plotting syntax with a GridPosition, which requires an empty GridLayout slot to create an axis in, but there are already the following objects at this layout position: - $(c) - If you meant to plot into an axis at this position, use the plotting function with `!` (e.g. `func!` instead of `func`). If you really want to place an axis on top of other blocks, make your intention clear and create it manually. """) end - - axis = Dict(pairs(axis)) - fig = get_top_parent(gp) - ax = get_axis(fig, P, axis, Dict{Symbol,Any}(kw_attributes), args) - - gp[] = ax - p = plot!(P, ax, args...; kw_attributes...) - return AxisPlot(ax, p) + ax = create_axis_for_plot(figure, plot, attributes) + if isnothing(ax) # For FigureSpec + return gp + else + gp[] = ax + return ax + end end -function plot!(P::PlotFunc, gp::GridPosition, args...; kwargs...) +function MakieCore.create_axis_like!(@nospecialize(::AbstractPlot), attributes::Dict, gsp::GridSubposition) + _disallow_keyword(:figure, attributes) + layout = GridLayoutBase.get_layout_at!(gsp.parent; createmissing=false) + gp = layout[gsp.rows, gsp.cols, gsp.side] c = contents(gp; exact=true) if !(length(c) == 1 && can_be_current_axis(c[1])) - error("There needs to be a single axis-like object at $(gp.span), $(gp.side) to plot into.\nUse a non-mutating plotting command to create an axis implicitly.") + error("There is not just one axis at $(gp).") end - ax = first(c) - return plot!(P, ax, args...; kwargs...) + _disallow_keyword(:axis, attributes) + return first(c) end -function plot(P::PlotFunc, gsp::GridSubposition, args...; axis=NamedTuple(), kw_attributes...) - _validate_nt_like_keyword(axis, "axis") - +function create_axis_like(plot::AbstractPlot, attributes::Dict, gsp::GridSubposition) + _disallow_keyword(:figure, attributes) GridLayoutBase.get_layout_at!(gsp.parent; createmissing=true) c = contents(gsp; exact=true) if !isempty(c) @@ -125,28 +190,26 @@ function plot(P::PlotFunc, gsp::GridSubposition, args...; axis=NamedTuple(), kw_ """) end - fig = get_top_parent(gsp) - axis = Dict(pairs(axis)) - ax = get_axis(fig, P, axis, Dict{Symbol,Any}(kw_attributes), args) - + figure = get_top_parent(gsp) + ax = create_axis_for_plot(figure, plot, attributes) gsp.parent[gsp.rows, gsp.cols, gsp.side] = ax - p = plot!(P, ax, args...; kw_attributes...) - return AxisPlot(ax, p) + return ax end -function plot!(P::PlotFunc, gsp::GridSubposition, args...; kwargs...) - layout = GridLayoutBase.get_layout_at!(gsp.parent; createmissing=false) - - gp = layout[gsp.rows, gsp.cols, gsp.side] +function create_axis_like!(@nospecialize(::AbstractPlot), attributes::Dict, ax::AbstractAxis) + _disallow_keyword(:axis, attributes) + return ax +end - c = contents(gp; exact=true) - if !(length(c) == 1 && can_be_current_axis(c[1])) - error("There is not just one axis at $(gp).") - end - ax = first(c) - return plot!(P, ax, args...; kwargs...) +function create_axis_like(@nospecialize(::AbstractPlot), ::Dict, ::Union{Scene,AbstractAxis}) + return error("Plotting into an axis without !") end +figurelike_return(fa::FigureAxis, plot::AbstractPlot) = FigureAxisPlot(fa.figure, fa.axis, plot) +figurelike_return(ax::AbstractAxis, plot::AbstractPlot) = AxisPlot(ax, plot) +figurelike_return!(::AbstractAxis, plot::AbstractPlot) = plot +figurelike_return!(::Union{Plot, Scene}, plot::AbstractPlot) = plot + update_state_before_display!(f::FigureAxisPlot) = update_state_before_display!(f.figure) function update_state_before_display!(f::Figure) @@ -155,3 +218,94 @@ function update_state_before_display!(f::Figure) end return end + + + +@inline plot_args(args...) = (nothing, args) +@inline function plot_args(a::Union{Figure,AbstractAxis,Scene,Plot,GridSubposition,GridPosition}, + args...) + return (a, args) +end +function fig_keywords!(kws) + figkws = Dict{Symbol,Any}() + if haskey(kws, :axis) + figkws[:axis] = pop!(kws, :axis) + end + if haskey(kws, :figure) + figkws[:figure] = pop!(kws, :figure) + end + return figkws +end + +# Narrows down the default plotfunc early on, if `plot` is used +default_plot_func(f::F, args) where {F} = f +default_plot_func(::typeof(plot), args) = plotfunc(plottype(map(to_value, args)...)) + +# Don't inline these, since they will get called from `scatter!(args...; kw...)` which gets specialized to all kw args +@noinline function MakieCore._create_plot(F, attributes::Dict, args...) + figarg, pargs = plot_args(args...) + figkws = fig_keywords!(attributes) + plot = Plot{default_plot_func(F, pargs)}(pargs, attributes) + ax = create_axis_like(plot, figkws, figarg) + plot!(ax, plot) + return figurelike_return(ax, plot) +end + +@noinline function MakieCore._create_plot!(F, attributes::Dict, args...) + figarg, pargs = plot_args(args...) + figkws = fig_keywords!(attributes) + plot = Plot{default_plot_func(F, pargs)}(pargs, attributes) + ax = create_axis_like!(plot, figkws, figarg) + plot!(ax, plot) + return figurelike_return!(ax, plot) +end + +@noinline function MakieCore._create_plot!(F, attributes::Dict, scene::SceneLike, args...) + plot = Plot{default_plot_func(F, args)}(args, attributes) + plot!(scene, plot) + return plot +end + +# This enables convert_arguments(::Type{<:AbstractPlot}, ::X) -> FigureSpec +# Which skips axis creation +# TODO, what to return for the dynamically created axes? +const PlotSpecPlot = Plot{plot, Tuple{<: GridLayoutSpec}} + +figurelike_return(f::GridPosition, p::PlotSpecPlot) = p +figurelike_return(f::Figure, p::PlotSpecPlot) = FigureAxisPlot(f, nothing, p) +MakieCore.create_axis_like!(::PlotSpecPlot, attributes::Dict, fig::Figure) = fig +MakieCore.create_axis_like!(::AbstractPlot, attributes::Dict, fig::Figure) = nothing + +# Axis interface + +Makie.can_be_current_axis(ax::AbstractAxis) = true + +function update_state_before_display!(ax::AbstractAxis) + reset_limits!(ax) + return +end + +plot!(fa::FigureAxis, plot) = plot!(fa.axis, plot) + +function plot!(ax::AbstractAxis, plot::AbstractPlot) + plot!(ax.scene, plot) + # some area-like plots basically always look better if they cover the whole plot area. + # adjust the limit margins in those cases automatically. + needs_tight_limits(plot) && tightlimits!(ax) + if is_open_or_any_parent(ax.scene) + reset_limits!(ax) + end + return plot +end + +function Base.delete!(ax::AbstractAxis, plot::AbstractPlot) + delete!(ax.scene, plot) + return ax +end + +function Base.empty!(ax::AbstractAxis) + while !isempty(ax.scene.plots) + delete!(ax, ax.scene.plots[end]) + end + return ax +end diff --git a/src/figures.jl b/src/figures.jl index 6590571dfec..b349ca71635 100644 --- a/src/figures.jl +++ b/src/figures.jl @@ -26,11 +26,12 @@ if an axis is placed at that position (if not it errors) or it can reference an get_scene(fig::Figure) = fig.scene get_scene(fap::FigureAxisPlot) = fap.figure.scene +get_scene(gp::GridLayoutBase.GridPosition) = get_scene(get_figure(gp)) +get_scene(gp::GridLayoutBase.GridSubposition) = get_scene(get_figure(gp)) -const CURRENT_FIGURE = Ref{Union{Nothing, Figure}}(nothing) -Base.@deprecate_binding _current_figure CURRENT_FIGURE +const CURRENT_FIGURE = Ref{Union{Nothing, Figure}}(nothing) const CURRENT_FIGURE_LOCK = Base.ReentrantLock() """ @@ -183,10 +184,7 @@ function resize_to_layout!(fig::Figure) end function Base.empty!(fig::Figure) - screens = copy(fig.scene.current_screens) empty!(fig.scene) - # The empty! api doesn't gracefully handle screens for e.g. the figure scene which is supposed to be still used! - append!(fig.scene.current_screens, screens) empty!(fig.scene.events) foreach(GridLayoutBase.remove_from_gridlayout!, reverse(fig.layout.content)) trim!(fig.layout) @@ -199,7 +197,7 @@ end # Layouts are already hooked up to this, so it's very simple. """ resize!(fig::Figure, width, height) -Resizes the given `Figure` to the resolution given by `width` and `height`. +Resizes the given `Figure` to the size given by `width` and `height`. If you want to resize the figure to its current layout content, use `resize_to_layout!(fig)` instead. """ Makie.resize!(figure::Figure, width::Integer, height::Integer) = resize!(figure.scene, width, height) diff --git a/src/interaction/events.jl b/src/interaction/events.jl index 9fedf07127f..fbc08f862a5 100644 --- a/src/interaction/events.jl +++ b/src/interaction/events.jl @@ -13,7 +13,7 @@ entered_window(scene, native_window) = not_implemented_for(native_window) function connect_screen(scene::Scene, screen) - on(screen.window_open) do open + on(scene, screen.window_open) do open events(scene).window_open[] = open end @@ -75,8 +75,6 @@ function onpick end ################################################################################ -abstract type BooleanOperator end - """ And(left, right[, rest...]) @@ -224,10 +222,10 @@ create_sets(s::Set) = [Set{Union{Keyboard.Button, Mouse.Button}}(s)] # ispressed and logic evaluation """ - ispressed(parent, result::Bool) - ispressed(parent, button::Union{Mouse.Button, Keyboard.Button) - ispressed(parent, collection::Union{Set, Vector, Tuple}) - ispressed(parent, op::BooleanOperator) +ispressed(parent, result::Bool[, waspressed = nothing]) +ispressed(parent, button::Union{Mouse.Button, Keyboard.Button[, waspressed = nothing]) + ispressed(parent, collection::Union{Set, Vector, Tuple}[, waspressed = nothing]) + ispressed(parent, op::BooleanOperator[, waspressed = nothing]) This function checks if a button or combination of buttons is pressed. @@ -251,25 +249,31 @@ Furthermore you can also make any button, button collection or boolean expression exclusive by wrapping it in `Exclusively(...)`. With that `ispressed` will only return true if the currently pressed buttons match the request exactly. -See also: [`And`](@ref), [`Or`](@ref), [`Not`](@ref), [`Exclusively`](@ref), +For cases where you want to react to a release event you can optionally add +a key or mousebutton `waspressed` which is then assumed to be pressed regardless +of it's current state. For example, when reacting to a mousebutton event, you can +pass `event.button` so that a key combination including that button still evaluates +as true. + +See also: [`waspressed`](@ref) [`And`](@ref), [`Or`](@ref), [`Not`](@ref), [`Exclusively`](@ref), [`&`](@ref), [`|`](@ref), [`!`](@ref) """ -ispressed(events::Events, mb::Mouse.Button) = mb in events.mousebuttonstate -ispressed(events::Events, key::Keyboard.Button) = key in events.keyboardstate -ispressed(parent, result::Bool) = result +ispressed(events::Events, mb::Mouse.Button, waspressed = nothing) = mb in events.mousebuttonstate || mb == waspressed +ispressed(events::Events, key::Keyboard.Button, waspressed = nothing) = key in events.keyboardstate || key == waspressed +ispressed(parent, result::Bool, waspressed = nothing) = result -ispressed(parent, mb::Mouse.Button) = ispressed(events(parent), mb) -ispressed(parent, key::Keyboard.Button) = ispressed(events(parent), key) -@deprecate ispressed(scene, ::Nothing) ispressed(parent, true) +ispressed(parent, mb::Mouse.Button, waspressed = nothing) = ispressed(events(parent), mb, waspressed) +ispressed(parent, key::Keyboard.Button, waspressed = nothing) = ispressed(events(parent), key, waspressed) # Boolean Operator evaluation -ispressed(parent, op::And) = ispressed(parent, op.left) && ispressed(parent, op.right) -ispressed(parent, op::Or) = ispressed(parent, op.left) || ispressed(parent, op.right) -ispressed(parent, op::Not) = !ispressed(parent, op.x) -ispressed(parent, op::Exclusively) = ispressed(events(parent), op) -ispressed(e::Events, op::Exclusively) = op.x == union(e.keyboardstate, e.mousebuttonstate) +ispressed(parent, op::And, waspressed = nothing) = ispressed(parent, op.left, waspressed) && ispressed(parent, op.right, waspressed) +ispressed(parent, op::Or, waspressed = nothing) = ispressed(parent, op.left, waspressed) || ispressed(parent, op.right, waspressed) +ispressed(parent, op::Not, waspressed = nothing) = !ispressed(parent, op.x, waspressed) +ispressed(parent, op::Exclusively, waspressed = nothing) = ispressed(events(parent), op, waspressed) +ispressed(e::Events, op::Exclusively, waspressed::Union{Mouse.Button, Keyboard.Button}) = op.x == union(e.keyboardstate, e.mousebuttonstate, waspressed) +ispressed(e::Events, op::Exclusively, waspressed = nothing) = op.x == union(e.keyboardstate, e.mousebuttonstate) # collections -ispressed(parent, set::Set) = all(x -> ispressed(parent, x), set) -ispressed(parent, set::Vector) = all(x -> ispressed(parent, x), set) -ispressed(parent, set::Tuple) = all(x -> ispressed(parent, x), set) +ispressed(parent, set::Set, waspressed = nothing) = all(x -> ispressed(parent, x, waspressed), set) +ispressed(parent, set::Vector, waspressed = nothing) = all(x -> ispressed(parent, x, waspressed), set) +ispressed(parent, set::Tuple, waspressed = nothing) = all(x -> ispressed(parent, x, waspressed), set) diff --git a/src/interaction/inspector.jl b/src/interaction/inspector.jl index 393d91f6fc1..228ea7c6e20 100644 --- a/src/interaction/inspector.jl +++ b/src/interaction/inspector.jl @@ -125,12 +125,12 @@ A --- B | | D --- C -this computes parameter `f` such that the line from `A + f * (B - A)` to -`D + f * (C - D)` crosses through the given point `P`. This assumes that `P` is +this computes parameter `f` such that the line from `A + f * (B - A)` to +`D + f * (C - D)` crosses through the given point `P`. This assumes that `P` is inside the quad and that none of the edges cross. """ function point_in_quad_parameter( - A::Point2, B::Point2, C::Point2, D::Point2, P::Point2; + A::Point2, B::Point2, C::Point2, D::Point2, P::Point2; iterations = 50, epsilon = 1e-6 ) @@ -166,9 +166,9 @@ end function shift_project(scene, pos) project( camera(scene).projectionview[], - Vec2f(widths(pixelarea(scene)[])), + Vec2f(size(scene)), pos - ) .+ Vec2f(origin(pixelarea(scene)[])) + ) .+ Vec2f(origin(viewport(scene)[])) end @@ -236,7 +236,7 @@ returning a label. See Makie documentation for more detail. - `enable_indicators = true)`: Enables or disables indicators - `depth = 9e3`: Depth value of the tooltip. This should be high so that the tooltip is always in front. -- `apply_tooltip_offset = true`: Enables or disables offsetting tooltips based +- `apply_tooltip_offset = true`: Enables or disables offsetting tooltips based on, for example, markersize. - and all attributes from `Tooltip` """ @@ -246,7 +246,7 @@ end function DataInspector(scene::Scene; priority = 100, kwargs...) parent = root(scene) - @assert origin(pixelarea(parent)[]) == Vec2f(0) + @assert origin(viewport(parent)[]) == Vec2f(0) attrib_dict = Dict(kwargs) base_attrib = Attributes( @@ -397,7 +397,7 @@ end function update_tooltip_alignment!(inspector, proj_pos) inspector.plot[1][] = proj_pos - wx, wy = widths(pixelarea(inspector.root)[]) + wx, wy = widths(viewport(inspector.root)[]) px, py = proj_pos placement = py < 0.75wy ? (:above) : (:below) @@ -511,13 +511,12 @@ function show_data(inspector::DataInspector, plot::Union{Lines, LineSegments}, i # cast ray from cursor into screen, find closest point to line pos = position_on_plot(plot, idx) - proj_pos = shift_project(scene, pos) update_tooltip_alignment!(inspector, proj_pos) tt.offset[] = ifelse( - a.apply_tooltip_offset[], - sv_getindex(plot.linewidth[], idx) + 2, + a.apply_tooltip_offset[], + sv_getindex(plot.linewidth[], idx) + 2, a.offset[] ) @@ -561,7 +560,7 @@ function show_data(inspector::DataInspector, plot::Mesh, idx) end p = wireframe!( - scene, bbox, color = a.indicator_color, + scene, bbox, color = a.indicator_color, transformation = Transformation(), linewidth = a.indicator_linewidth, linestyle = a.indicator_linestyle, visible = a.indicator_visible, inspectable = false @@ -662,7 +661,7 @@ function show_imagelike(inspector, plot, name, edge_based) a._color[] = if z isa AbstractFloat interpolated_getindex( to_colormap(plot.colormap[]), z, - to_value(get(plot.attributes, :colorrange, (0, 1))) + extract_colorrange(plot) ) else z @@ -673,16 +672,16 @@ function show_imagelike(inspector, plot, name, edge_based) if a.enable_indicators[] if plot.interpolate[] - if inspector.selection != plot || (length(inspector.temp_plots) != 1) || + if inspector.selection != plot || (length(inspector.temp_plots) != 1) || !(inspector.temp_plots[1] isa Scatter) clear_temporary_plots!(inspector, plot) p = scatter!( scene, pos, color = a._color, visible = a.indicator_visible, inspectable = false, model = plot.model, - # TODO switch to Rect with 2r-1 or 2r-2 markersize to have + # TODO switch to Rect with 2r-1 or 2r-2 markersize to have # just enough space to always detect the underlying image - marker=:rect, markersize = map(r -> 2r, a.range), + marker=:rect, markersize = map(r -> 2r, a.range), strokecolor = a.indicator_color, strokewidth = a.indicator_linewidth, depth_shift = -1f-3 @@ -695,7 +694,7 @@ function show_imagelike(inspector, plot, name, edge_based) end else bbox = _pixelated_image_bbox(plot[1][], plot[2][], plot[3][], i, j, edge_based) - if inspector.selection != plot || (length(inspector.temp_plots) != 1) || + if inspector.selection != plot || (length(inspector.temp_plots) != 1) || !(inspector.temp_plots[1] isa Wireframe) clear_temporary_plots!(inspector, plot) p = wireframe!( @@ -791,7 +790,7 @@ end ################################################################################ -### show_data for Combined/recipe plots +### show_data for Plot/recipe plots ################################################################################ @@ -919,7 +918,7 @@ function show_poly(inspector, plot, poly, idx, source) clear_temporary_plots!(inspector, plot) p = lines!( - scene, line_collection, color = a.indicator_color, + scene, line_collection, color = a.indicator_color, transformation = Transformation(source), strokewidth = a.indicator_linewidth, linestyle = a.indicator_linestyle, visible = a.indicator_visible, inspectable = false, depth_shift = -1f-3 @@ -954,7 +953,7 @@ function show_data(inspector::DataInspector, plot::VolumeSlices, idx, child::Hea proj_pos = Point2f(mouseposition_px(inspector.root)) update_tooltip_alignment!(inspector, proj_pos) tt[1][] = proj_pos - + world_pos = apply_transform_and_model(child, pos) if haskey(plot, :inspector_label) @@ -1004,7 +1003,7 @@ function show_data(inspector::DataInspector, plot::Band, idx::Integer, mesh::Mes clear_temporary_plots!(inspector, plot) p = lines!( scene, [P1, P2], transformation = Transformation(plot.transformation), - color = a.indicator_color, strokewidth = a.indicator_linewidth, + color = a.indicator_color, strokewidth = a.indicator_linewidth, linestyle = a.indicator_linestyle, visible = a.indicator_visible, inspectable = false, depth_shift = -1f-3 diff --git a/src/interaction/interactive_api.jl b/src/interaction/interactive_api.jl index 7ea6243d497..4fea246ad69 100644 --- a/src/interaction/interactive_api.jl +++ b/src/interaction/interactive_api.jl @@ -31,8 +31,6 @@ function onpick(f, scene::Scene, plots::AbstractPlot...; range=1) end end -@deprecate mouse_selection pick - """ mouse_in_scene(fig/ax/scene[, priority = 0]) @@ -44,7 +42,7 @@ function mouse_in_scene(scene::Scene; priority = 0) p = rootparent(scene) output = Observable(Vec2(0.0)) on(events(scene).mouseposition, priority = priority) do mp - output[] = Vec(mp) .- minimum(pixelarea(scene)[]) + output[] = Vec(mp) .- minimum(viewport(scene)[]) return Consume(false) end output @@ -175,7 +173,7 @@ Normalizes mouse position `pos` relative to the screen rectangle. """ screen_relative(x, mpos) = screen_relative(get_scene(x), mpos) function screen_relative(scene::Scene, mpos) - return Point2f(mpos) .- Point2f(minimum(pixelarea(scene)[])) + return Point2f(mpos) .- Point2f(minimum(viewport(scene)[])) end """ diff --git a/src/interaction/observables.jl b/src/interaction/observables.jl index a1d7b2d4465..6b384efa4d0 100644 --- a/src/interaction/observables.jl +++ b/src/interaction/observables.jl @@ -17,34 +17,11 @@ function safe_off(o::Observables.AbstractObservable, f) end end -""" - map_once(closure, inputs::Observable....)::Observable - -Like Reactive.foreach, in the sense that it will be preserved even if no reference is kept. -The difference is, that you can call map once multiple times with the same closure and it will -close the old result Observable and register a new one instead. - -``` -function test(s1::Observable) - s3 = map_once(x-> (println("1 ", x); x), s1) - s3 = map_once(x-> (println("2 ", x); x), s1) - -end -test(Observable(1), Observable(2)) -> - -""" -function map_once( - f, input::Observable, inputrest::Observable... - ) - for arg in (input, inputrest...) - safe_off(arg, f) - end - lift(f, input, inputrest...) +function on_latest(f, observable::Observable; update=false, spawn=false) + return on_latest(f, nothing, observable; update=update, spawn=spawn) end -function on_latest(f, observable; update=false, spawn=false) - # How does one create a finished task?? +function on_latest(f, to_track, observable::Observable; update=false, spawn=false) last_task = nothing has_changed = Threads.Atomic{Bool}(false) function run_f(new_value) @@ -61,15 +38,12 @@ function on_latest(f, observable; update=false, spawn=false) # we assume for now that `==` is prohibitive as the default if has_changed[] has_changed[] = false - run_f(observable[]) # needs to recursive + run_f(observable[]) # needs to be recursive end end - return on(observable; update=update) do new_value - if isnothing(last_task) - # run first task in sync - last_task = update ? (@async f(observable[])) : @async(nothing) - wait(last_task) - elseif istaskdone(last_task) + + function on_callback(new_value) + if isnothing(last_task) || istaskdone(last_task) if spawn last_task = Threads.@spawn run_f(new_value) else @@ -80,6 +54,14 @@ function on_latest(f, observable; update=false, spawn=false) return # Do nothing if working end end + + update && f(observable[]) + + if isnothing(to_track) + return on(on_callback, observable) + else + return on(on_callback, to_track, observable) + end end function onany_latest(f, observables...; update=false, spawn=false) @@ -87,3 +69,14 @@ function onany_latest(f, observables...; update=false, spawn=false) onany((args...)-> (result[] = args), observables...) on_latest((args)-> f(args...), result; update=update, spawn=spawn) end + +function map_latest!(f, result::Observable, observables...; update=false, spawn=false) + callback = Observables.MapCallback(f, result, observables) + return onany_latest(callback, observables...; update=update, spawn=spawn) +end + +function map_latest(f, observables...; spawn=false, ignore_equal_values=false) + result = Observable(f(map(to_value, observables)...); ignore_equal_values=ignore_equal_values) + map_latest!(f, result, observables...; update=update, spawn=spawn) + return result +end diff --git a/src/interaction/ray_casting.jl b/src/interaction/ray_casting.jl index f87ffe4bae3..8b3c67f2515 100644 --- a/src/interaction/ray_casting.jl +++ b/src/interaction/ray_casting.jl @@ -21,7 +21,7 @@ end Ray(scene[, cam = cameracontrols(scene)], xy) Returns a `Ray` into the given `scene` passing through pixel position `xy`. Note -that the pixel position should be relative to the origin of the scene, as it is +that the pixel position should be relative to the origin of the scene, as it is when calling `mouseposition_px(scene)`. """ Ray(scene::Scene, xy::VecTypes{2}) = Ray(scene, cameracontrols(scene), xy) @@ -35,12 +35,12 @@ function Ray(scene::Scene, cam::Camera3D, xy::VecTypes{2}) u_z = normalize(viewdir) u_x = normalize(cross(u_z, cam.upvector[])) u_y = normalize(cross(u_x, u_z)) - - px_width, px_height = widths(scene.px_area[]) + + px_width, px_height = widths(scene) aspect = px_width / px_height rel_pos = 2 .* xy ./ (px_width, px_height) .- 1 - if cam.attributes.projectiontype[] === Perspective + if cam.settings.projectiontype[] === Perspective dir = (rel_pos[1] * aspect * u_x + rel_pos[2] * u_y) * tand(0.5 * cam.fov[]) + u_z return Ray(cam.eyeposition[], normalize(dir)) else @@ -51,7 +51,7 @@ function Ray(scene::Scene, cam::Camera3D, xy::VecTypes{2}) end function Ray(scene::Scene, cam::Camera2D, xy::VecTypes{2}) - rel_pos = xy ./ widths(scene.px_area[]) + rel_pos = xy ./ widths(scene) pv = scene.camera.projectionview[] m = Vec2f(pv[1, 1], pv[2, 2]) b = Vec2f(pv[1, 4], pv[2, 4]) @@ -64,16 +64,16 @@ function Ray(::Scene, ::PixelCamera, xy::VecTypes{2}) end function Ray(scene::Scene, ::RelativeCamera, xy::VecTypes{2}) - origin = xy ./ widths(scene.px_area[]) + origin = xy ./ widths(scene) return Ray(to_ndim(Point3f, origin, 10_000f0), Vec3f(0,0,-1)) end Ray(scene::Scene, cam, xy::VecTypes{2}) = ray_from_projectionview(scene, xy) -# This method should always work +# This method should always work function ray_from_projectionview(scene::Scene, xy::VecTypes{2}) inv_view_proj = inv(camera(scene).projectionview[]) - area = pixelarea(scene)[] + area = viewport(scene)[] # This figures out the camera view direction from the projectionview matrix # and computes a ray from a near and a far point. @@ -124,6 +124,12 @@ function closest_point_on_line(A::Point3f, B::Point3f, ray::Ray) return A .+ clamp(t, 0.0, AB_norm) * u_AB end +function ray_triangle_intersection(A::VecTypes, B::VecTypes, C::VecTypes, ray::Ray, ϵ = 1e-6) + return ray_triangle_intersection( + to_ndim(Point3f, A, 0f0), to_ndim(Point3f, B, 0f0), to_ndim(Point3f, C, 0f0), + ray, ϵ + ) +end function ray_triangle_intersection(A::VecTypes{3}, B::VecTypes{3}, C::VecTypes{3}, ray::Ray, ϵ = 1e-6) # See: https://www.iue.tuwien.ac.at/phd/ertl/node114.html @@ -182,7 +188,7 @@ This function performs a `pick` at the given pixel position `xy` and returns the picked `plot`, `index` and world or input space `position::Point3f`. It is equivalent to ``` plot, idx = pick(fig/ax/scene, xy) -ray = Ray(parent_scene(plot), xy .- minimum(pixelarea(parent_scene(plot))[])) +ray = Ray(parent_scene(plot), xy .- minimum(viewport(parent_scene(plot))[])) position = position_on_plot(plot, idx, ray, apply_transform = true) ``` See [`position_on_plot`](@ref) for more information. @@ -191,7 +197,7 @@ function ray_assisted_pick(obj, xy = events(obj).mouseposition[]; apply_transfor plot, idx = pick(get_scene(obj), xy) isnothing(plot) && return (plot, idx, Point3f(NaN)) scene = parent_scene(plot) - ray = Ray(scene, xy .- minimum(pixelarea(scene)[])) + ray = Ray(scene, xy .- minimum(viewport(scene)[])) pos = position_on_plot(plot, idx, ray, apply_transform = apply_transform) return (plot, idx, pos) end @@ -200,23 +206,23 @@ end """ position_on_plot(plot, index[, ray::Ray; apply_transform = true]) -This function calculates the world or input space position of a ray - plot -intersection with the result `plot, idx = pick(...)` and a ray cast from the +This function calculates the world or input space position of a ray - plot +intersection with the result `plot, idx = pick(...)` and a ray cast from the picked position. If there is no intersection `Point3f(NaN)` will be returned. This should be called as ``` plot, idx = pick(ax, px_pos) -pos_in_ax = position_on_plot(plot, idx, Ray(ax, px_pos .- minimum(pixelarea(ax.scene)[]))) +pos_in_ax = position_on_plot(plot, idx, Ray(ax, px_pos .- minimum(viewport(ax.scene)[]))) ``` or more simply `plot, idx, pos_in_ax = ray_assisted_pick(ax, px_pos)`. -You can switch between getting a position in world space (after applying -transformations like `log`, `translate!()`, `rotate!()` and `scale!()`) and +You can switch between getting a position in world space (after applying +transformations like `log`, `translate!()`, `rotate!()` and `scale!()`) and input space (the raw position data of the plot) by adjusting `apply_transform`. -Note that `position_on_plot` is only implemented for primitive plot types, i.e. -the possible return types of `pick`. Depending on the plot type the calculation +Note that `position_on_plot` is only implemented for primitive plot types, i.e. +the possible return types of `pick`. Depending on the plot type the calculation differs: - `scatter` and `meshscatter` return the position of the picked marker/mesh - `text` is excluded, always returning `Point3f(NaN)` @@ -227,26 +233,28 @@ differs: """ function position_on_plot(plot::AbstractPlot, idx::Integer; apply_transform = true) return position_on_plot( - plot, idx, ray_at_cursor(parent_scene(plot)); + plot, idx, ray_at_cursor(parent_scene(plot)); apply_transform = apply_transform ) end function position_on_plot(plot::Union{Scatter, MeshScatter}, idx, ray::Ray; apply_transform = true) - pos = to_ndim(Point3f, plot[1][][idx], 0f0) - if apply_transform && !isnan(pos) - return apply_transform_and_model(plot, pos) + point = plot[1][][idx] + point3f = to_ndim(Point3f, point, 0.0f0) + point_t = if apply_transform && !isnan(point3f) + apply_transform_and_model(plot, point3f) else - return pos + point3f end + return to_ndim(typeof(point), point_t, 0.0f0) end function position_on_plot(plot::Union{Lines, LineSegments}, idx, ray::Ray; apply_transform = true) p0, p1 = apply_transform_and_model(plot, plot[1][][idx-1:idx]) pos = closest_point_on_line(p0, p1, ray) - + if apply_transform return pos else @@ -258,8 +266,8 @@ function position_on_plot(plot::Union{Lines, LineSegments}, idx, ray::Ray; apply end function position_on_plot(plot::Union{Heatmap, Image}, idx, ray::Ray; apply_transform = true) - # Heatmap and Image are always a Rect2f. The transform function is currently - # not allowed to change this, so applying it should be fine. Applying the + # Heatmap and Image are always a Rect2f. The transform function is currently + # not allowed to change this, so applying it should be fine. Applying the # model matrix may add a z component to the Rect2f, which we can't represent. # So we instead inverse-transform the ray space = to_value(get(plot, :space, :data)) @@ -268,7 +276,7 @@ function position_on_plot(plot::Union{Heatmap, Image}, idx, ray::Ray; apply_tran end ray = transform(inv(plot.model[]), ray) pos = ray_rect_intersection(Rect2f(p0, p1 - p0), ray) - + if apply_transform p4d = plot.model[] * to_ndim(Point4f, to_ndim(Point3f, pos, 0), 1) return p4d[Vec(1, 2, 3)] / p4d[4] @@ -300,7 +308,7 @@ function position_on_plot(plot::Mesh, idx, ray::Ray; apply_transform = true) end end - @info "Did not find $idx" + @debug "Did not find intersection for index = $idx when casting a ray on mesh." return Point3f(NaN) end @@ -329,7 +337,7 @@ function position_on_plot(plot::Surface, idx, ray::Ray; apply_transform = true) ray = transform(inv(plot.model[]), ray) tf = transform_func(plot) space = to_value(get(plot, :space, :data)) - + # This isn't the most accurate so we include some neighboring faces pos = Point3f(NaN) for i in _i-1:_i+1, j in _j-1:_j+1 @@ -387,4 +395,4 @@ function position_on_plot(plot::Volume, idx, ray::Ray; apply_transform = true) end position_on_plot(plot::Text, args...; kwargs...) = Point3f(NaN) -position_on_plot(plot::Nothing, args...; kwargs...) = Point3f(NaN) \ No newline at end of file +position_on_plot(plot::Nothing, args...; kwargs...) = Point3f(NaN) diff --git a/src/interfaces.jl b/src/interfaces.jl index c040da6cdd3..19c35941eb0 100644 --- a/src/interfaces.jl +++ b/src/interfaces.jl @@ -1,9 +1,28 @@ + +function add_cycle_attribute!(plot::Plot, scene::Scene, cycle=get_cycle_for_plottype(plot.cycle[])) + cycler = scene.cycler + palette = scene.theme.palette + add_cycle_attributes!(plot, cycle, cycler, palette) + return +end + function color_and_colormap!(plot, colors = plot.color) + scene = parent_scene(plot) + if !isnothing(scene) && haskey(plot, :cycle) + add_cycle_attribute!(plot, scene) + end colors = assemble_colors(colors[], colors, plot) attributes(plot.attributes)[:calculated_colors] = colors end -function calculated_attributes!(T::Type{<: Mesh}, plot) +function calculated_attributes!(::Type{<: AbstractPlot}, plot) + scene = parent_scene(plot) + if !isnothing(scene) && haskey(plot, :cycle) + add_cycle_attribute!(plot, scene) + end +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_and_colormap!(plot, color) @@ -69,7 +88,8 @@ function calculated_attributes!(::Type{T}, plot) where {T<:Union{Lines, LineSegm for attr in [:color, :linewidth] # taken from @edljk in PR #77 if haskey(plot, attr) && isa(plot[attr][], AbstractVector) && (length(pos) ÷ 2) == length(plot[attr][]) - plot[attr] = lift(plot, plot[attr]) do cols + # TODO, this is actually buggy for `plot.color = new_colors`, since we're overwriting the origin color input + attributes(plot.attributes)[attr] = lift(plot, plot[attr]) do cols map(i -> cols[(i + 1) ÷ 2], 1:(length(cols) * 2)) end end @@ -79,16 +99,56 @@ function calculated_attributes!(::Type{T}, plot) where {T<:Union{Lines, LineSegm return end -const atomic_function_symbols = ( - :text, :meshscatter, :scatter, :mesh, :linesegments, - :lines, :surface, :volume, :heatmap, :image +const atomic_functions = ( + text, meshscatter, scatter, mesh, linesegments, + lines, surface, volume, heatmap, image ) +const Atomic{Arg} = Union{map(x-> Plot{x, Arg}, atomic_functions)...} + +function convert_arguments!(plot::Plot{F}) where {F} + P = Plot{F,Any} + function on_update(kw, args...) + nt = convert_arguments(P, args...; kw...) + pnew, converted = apply_convert!(P, plot.attributes, nt) + @assert plotfunc(pnew) === F "Changed the plot type in convert_arguments. This isn't allowed!" + for (obs, new_val) in zip(plot.converted, converted) + obs[] = new_val + end + end + used_attrs = used_attributes(P, to_value.(plot.args)...) + convert_keys = intersect(used_attrs, keys(plot.attributes)) + kw_signal = if isempty(convert_keys) + # lift(f) isn't supported so we need to catch the empty case + Observable(()) + else + # Remove used attributes from `attributes` and collect them in a `Tuple` to pass them more easily + lift((args...) -> Pair.(convert_keys, args), plot, pop!.(plot.attributes, convert_keys)...) + end + onany(on_update, plot, kw_signal, plot.args...) + return +end -const atomic_functions = getfield.(Ref(Makie), atomic_function_symbols) -const Atomic{Arg} = Union{map(x-> Combined{x, Arg}, atomic_functions)...} +function Plot{Func}(args::Tuple, plot_attributes::Dict) where {Func} + if !isempty(args) && first(args) isa Attributes + merge!(plot_attributes, attributes(first(args))) + return Plot{Func}(Base.tail(args), plot_attributes) + end + P = Plot{Func} + used_attrs = used_attributes(P, to_value.(args)...) + if used_attrs === () + args_converted = convert_arguments(P, map(to_value, args)...) + else + kw = [Pair(k, to_value(v)) for (k, v) in plot_attributes if k in used_attrs] + args_converted = convert_arguments(P, map(to_value, args)...; kw...) + end + PNew, converted = apply_convert!(P, Attributes(), args_converted) -function (PT::Type{<: Combined})(parent, transformation, attributes, input_args, converted) - PT(parent, transformation, attributes, input_args, converted, AbstractPlot[]) + obs_args = Any[convert(Observable, x) for x in args] + + ArgTyp = MakieCore.argtypes(converted) + converted_obs = map(Observable, converted) + FinalPlotFunc = plotfunc(plottype(PNew, converted...)) + return Plot{FinalPlotFunc,ArgTyp}(plot_attributes, obs_args, converted_obs) end """ @@ -113,107 +173,32 @@ Usage: end ``` """ -used_attributes(PlotType, args...) = () +used_attributes(::Type{<:Plot}, args...) = used_attributes(args...) +used_attributes(args...) = () -""" -apply for return type - (args...,) -""" -function apply_convert!(P, attributes::Attributes, x::Tuple) - return (plottype(P, x...), x) -end +## generic definitions +# Chose the more specific plot type from arguments or input type +# Note the plottype(Scatter, Plot{plot}) will return Scatter +# And plottype(args...) falls back to Plot{plot} +plottype(P::Type{<: Plot{T}}, argvalues...) where T = plottype(P, plottype(argvalues...)) +plottype(P::Type{<:Plot{T}}) where {T} = P +plottype(P1::Type{<:Plot{T1}}, ::Type{<:Plot{T2}}) where {T1, T2} = P1 +plottype(::Type{Plot{plot}}, ::Type{Plot{plot}}) = Plot{plot} """ -apply for return type PlotSpec -""" -function apply_convert!(P, attributes::Attributes, x::PlotSpec{S}) where S - args, kwargs = x.args, x.kwargs - # Note that kw_args in the plot spec that are not part of the target plot type - # will end in the "global plot" kw_args (rest) - for (k, v) in pairs(kwargs) - attributes[k] = v - end - return (plottype(S, P), args) -end - -function seperate_tuple(args::Observable{<: NTuple{N, Any}}) where N - ntuple(N) do i - lift(args) do x - if i <= length(x) - x[i] - else - error("You changed the number of arguments. This isn't allowed!") - end - end - end -end - -function (PlotType::Type{<: AbstractPlot{Typ}})(scene::SceneLike, attributes::Attributes, args) where Typ - input = convert.(Observable, args) - aconvert(args...) = convert_arguments(PlotType, args...) - argnodes = lift(aconvert, input...) - plot = PlotType(scene, attributes, input, argnodes) - # Manually register obsfuncs, since we can't do lift(aconvert, plot, input...) - for arg in input - push!(plot.deregister_callbacks, Observables.ObserverFunction(aconvert, arg, false)) - end - return plot -end - -function plot(scene::Scene, plot::AbstractPlot) - # plot object contains local theme (default values), and user given values (from constructor) - # fill_theme now goes through all values that are missing from the user, and looks if the scene - # contains any theming values for them (via e.g. css rules). If nothing founds, the values will - # be taken from local theme! This will connect any values in the scene's theme - # with the plot values and track those connection, so that we can separate them - # when doing delete!(scene, plot)! - complete_theme!(scene, plot) - # we just return the plot... whoever calls plot (our pipeline usually) - # will need to push!(scene, plot) etc! - return plot -end + plottype(P1::Type{<: Plot{T1}}, P2::Type{<: Plot{T2}}) -function (PlotType::Type{<: AbstractPlot{Typ}})(scene::SceneLike, attributes::Attributes, input, args) where Typ - # The argument type of the final plot object is the assumened to stay constant after - # argument conversion. This might not always hold, but it simplifies - # things quite a bit - ArgTyp = typeof(to_value(args)) - # construct the fully qualified plot type, from the possible incomplete (abstract) - # PlotType - - FinalType = Combined{Typ, ArgTyp} - plot_attributes = merged_get!( - ()-> default_theme(scene, FinalType), - plotsym(FinalType), scene, attributes - ) - - # Transformation is a field of the plot type, but can be given as an attribute - trans = get(plot_attributes, :transformation, automatic) - transval = to_value(trans) - transformation = if transval === automatic - Transformation(scene) - elseif isa(transval, Transformation) - transval - else - t = Transformation(scene) - transform!(t, transval) - t - end - replace_automatic!(plot_attributes, :model) do - transformation.model - end - # create the plot, with the full attributes, the input signals, and the final signals. - plot_obj = FinalType(scene, transformation, plot_attributes, input, seperate_tuple(args)) - calculated_attributes!(plot_obj) - plot_obj +Chooses the more concrete plot type +```julia +function convert_arguments(P::PlotFunc, args...) + ptype = plottype(P, Lines) + ... end +``` +""" +plottype(::Type{Plot{plot}}, P::Type{<:Plot{T}}) where {T} = P +plottype(P::Type{<:Plot{T}}, ::Type{Plot{plot}}) where {T} = P -## generic definitions -# If the Combined has no plot func, calculate them -plottype(::Type{<: Combined{Any}}, argvalues...) = plottype(argvalues...) -plottype(::Type{Any}, argvalues...) = plottype(argvalues...) -# If it has something more concrete than Any, use it directly -plottype(P::Type{<: Combined{T}}, argvalues...) where T = P ## specialized definitions for types plottype(::AbstractVector, ::AbstractVector, ::AbstractVector) = Scatter @@ -232,180 +217,65 @@ plottype(::GeometryBasics.AbstractPolygon) = Poly plottype(::AbstractVector{<:GeometryBasics.AbstractPolygon}) = Poly plottype(::MultiPolygon) = Lines -""" - plottype(P1::Type{<: Combined{T1}}, P2::Type{<: Combined{T2}}) -Chooses the more concrete plot type -```julia -function convert_arguments(P::PlotFunc, args...) - ptype = plottype(P, Lines) - ... -end -``` -""" -plottype(P1::Type{<: Combined{Any}}, P2::Type{<: Combined{T}}) where T = P2 -plottype(P1::Type{<: Combined{T}}, P2::Type{<: Combined}) where T = P1 # all the plotting functions that get a plot type -const PlotFunc = Union{Type{Any}, Type{<: AbstractPlot}} - - -###################################################################### -# In this section, the plotting functions have P as the first argument -# These are called from type recipes - -function plot!(P::PlotFunc, scene::SceneLike, args...; kw_attributes...) - attributes = Attributes(kw_attributes) - plot!(scene, P, attributes, args...) -end +const PlotFunc = Union{Type{Any},Type{<:AbstractPlot}} -# with positional attributes - -function plot!(P::PlotFunc, scene::SceneLike, attrs::Attributes, args...; kw_attributes...) - attributes = merge!(Attributes(kw_attributes), attrs) - plot!(scene, P, attributes, args...) +function plot!(::Plot{F}) where {F} + if !(F in atomic_functions) + error("No recipe for $(F)") + end end -###################################################################### -# plots to scene +function connect_plot!(parent::SceneLike, plot::Plot{F}) where {F} + plot.parent = parent -""" -Main plotting signatures that plot/plot! route to if no Plot Type is given -""" -function plot!(scene::Union{Combined, SceneLike}, P::PlotFunc, attributes::Attributes, args...; kw_attributes...) - attributes = merge!(Attributes(kw_attributes), attributes) - argvalues = to_value.(args) - pre_type_no_args = plottype(P, argvalues...) - # plottype will lose the argument types, so we just extract the plot func - # type and recreate the type with the argument type - PreType = Combined{plotfunc(pre_type_no_args), typeof(argvalues)} - used_attrs = used_attributes(PreType, argvalues...) - convert_keys = intersect(used_attrs, keys(attributes)) - kw_signal = if isempty(convert_keys) - # lift(f) isn't supported so we need to catch the empty case - Observable(()) + apply_theme!(parent_scene(parent), plot) + t_user = to_value(get(attributes(plot), :transformation, automatic)) + if t_user isa Transformation + plot.transformation = t_user else - # Remove used attributes from `attributes` and collect them in a `Tuple` to pass them more easily - lift((args...) -> Pair.(convert_keys, args), scene, pop!.(attributes, convert_keys)...) - end - # call convert_arguments for a first time to get things started - converted = convert_arguments(PreType, argvalues...; kw_signal[]...) - # convert_arguments can return different things depending on the recipe type - # apply_conversion deals with that! - - FinalType, argsconverted = apply_convert!(PreType, attributes, converted) - converted_node = Observable(argsconverted) - input_nodes = convert.(Observable, args) - obs_funcs = onany(kw_signal, input_nodes...) do kwargs, args... - # do the argument conversion inside a lift - result = convert_arguments(FinalType, args...; kwargs...) - finaltype, argsconverted_ = apply_convert!(FinalType, attributes, result) # avoid a Core.Box (https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured) - if finaltype != FinalType - error("Plot type changed from $FinalType to $finaltype after conversion. - Changing the plot type based on values in convert_arguments is not allowed" - ) + if t_user isa Automatic + plot.transformation = Transformation() + else + t = Transformation() + transform!(t, t_user) + plot.transformation = t end - converted_node[] = argsconverted_ - end - plot_object = plot!(scene, FinalType, attributes, input_nodes, converted_node) - # bind observable clean up to plot object: - append!(plot_object.deregister_callbacks, obs_funcs) - return plot_object -end - -plot!(p::Combined) = _plot!(p) - -_plot!(p::Atomic{T}) where T = p - -function _plot!(p::Combined{fn, T}) where {fn, T} - throw(PlotMethodError(fn, T)) -end - -struct PlotMethodError <: Exception - fn - T -end - -function Base.showerror(io::IO, err::PlotMethodError) - fn = err.fn - T = err.T - args = (T.parameters...,) - typed_args = join(string.("::", args), ", ") - - print(io, "PlotMethodError: no ") - printstyled(io, fn == Any ? "plot" : fn; color=:cyan) - print(io, " method for arguments ") - printstyled(io, "($typed_args)"; color=:cyan) - print(io, ". To support these arguments, define\n ") - printstyled(io, "plot!(::$(Combined{fn,S} where {S<:T}))"; color=:cyan) - print(io, "\nAvailable methods are:\n") - for m in methods(plot!) - if m.sig <: Tuple{typeof(plot!), Combined{fn}} - println(io, " ", m) + if is_space_compatible(plot, parent) + obsfunc = connect!(transformation(parent), transformation(plot)) + append!(plot.deregister_callbacks, obsfunc) end end + plot.model = transformationmatrix(plot) + convert_arguments!(plot) + calculated_attributes!(Plot{F}, plot) + default_shading!(plot, parent_scene(parent)) + plot!(plot) + return plot end -function show_attributes(attributes) - for (k, v) in attributes - println(" ", k, ": ", v[] == nothing ? "nothing" : v[]) - end +function plot!(scene::SceneLike, plot::Plot) + connect_plot!(scene, plot) + push!(scene, plot) + return plot end -""" - extract_scene_attributes!(attributes) - -removes all scene attributes from `attributes` and returns them in a new -Attribute dict. -""" -function extract_scene_attributes!(attributes) - scene_attributes = ( - :backgroundcolor, - :resolution, - :show_axis, - :show_legend, - :scale_plot, - :center, - :axis, - :axis2d, - :axis3d, - :legend, - :camera, - :limits, - :padding, - :raw, - :SSAO - ) - result = Attributes() - for k in scene_attributes - haskey(attributes, k) && (result[k] = pop!(attributes, k)) +function apply_theme!(scene::Scene, plot::P) where {P<: Plot} + raw_attr = attributes(plot.attributes) + plot_theme = default_theme(scene, P) + plot_sym = plotsym(P) + if haskey(theme(scene), plot_sym) + merge_without_obs_reverse!(plot_theme, theme(scene, plot_sym)) end - return result -end -function plot!(scene::SceneLike, P::PlotFunc, attributes::Attributes, input::NTuple{N, Observable}, args::Observable) where {N} - # create "empty" plot type - empty meaning containing no plots, just attributes + arguments - scene_attributes = extract_scene_attributes!(attributes) - if haskey(attributes, :textsize) - throw(ArgumentError("The attribute `textsize` has been renamed to `fontsize` in Makie v0.19. Please change all occurrences of `textsize` to `fontsize` or revert back to an earlier version.")) - end - plot_object = P(scene, attributes, input, args) - # transfer the merged attributes from theme and user defined to the scene - for (k, v) in scene_attributes - error("setting $k for scene via plot attribute not supported anymore") + for (k, v) in plot.kw + if v isa NamedTuple + raw_attr[k] = Attributes(v) + else + raw_attr[k] = convert(Observable{Any}, v) + end end - # call user defined recipe overload to fill the plot type - plot!(plot_object) - push!(scene, plot_object) - return plot_object -end - -function plot!(scene::Combined, P::PlotFunc, attributes::Attributes, input::NTuple{N,Observable}, args::Observable) where {N} - # create "empty" plot type - empty meaning containing no plots, just attributes + arguments - - plot_object = P(scene, attributes, input, args) - # call user defined recipe overload to fill the plot type - plot!(plot_object) - push!(scene.plots, plot_object) - plot_object + return merge!(plot.attributes, plot_theme) end diff --git a/src/layouting/data_limits.jl b/src/layouting/data_limits.jl index 676368c76fb..92d4e94a38b 100644 --- a/src/layouting/data_limits.jl +++ b/src/layouting/data_limits.jl @@ -106,7 +106,7 @@ end foreach_plot(f, s::Figure) = foreach_plot(f, s.scene) foreach_plot(f, s::FigureAxisPlot) = foreach_plot(f, s.figure) foreach_plot(f, list::AbstractVector) = foreach(f, list) -function foreach_plot(f, plot::Combined) +function foreach_plot(f, plot::Plot) if isempty(plot.plots) f(plot) else @@ -166,13 +166,14 @@ function update_boundingbox!(bb_ref, bb::Rect) return end +# Default data_limits function data_limits(plot::AbstractPlot) # Assume primitive plot if isempty(plot.plots) return limits_from_transformed_points(iterate_transformed(plot)) end - # Assume Combined Plot + # Assume Plot Plot bb_ref = Base.RefValue(data_limits(plot.plots[1])) for i in 2:length(plot.plots) update_boundingbox!(bb_ref, data_limits(plot.plots[i])) @@ -181,7 +182,7 @@ function data_limits(plot::AbstractPlot) return bb_ref[] end -function _update_rect(rect::Rect{N, T}, point::Point{N, T}) where {N, T} +function _update_rect(rect::Rect{N, T}, point::VecTypes{N, T}) where {N, T} mi = minimum(rect) ma = maximum(rect) mis_mas = map(mi, ma, point) do _mi, _ma, _p @@ -201,6 +202,22 @@ function limits_from_transformed_points(points_iterator) return bb end +# include bbox from scaled markers +function limits_from_transformed_points(positions, scales, rotations, element_bbox) + isempty(positions) && return Rect3f() + + first_scale = attr_broadcast_getindex(scales, 1) + first_rot = attr_broadcast_getindex(rotations, 1) + full_bbox = Ref(first_rot * (element_bbox * first_scale) + first(positions)) + for (i, pos) in enumerate(positions) + scale, rot = attr_broadcast_getindex(scales, i), attr_broadcast_getindex(rotations, i) + transformed_bbox = rot * (element_bbox * scale) + pos + update_boundingbox!(full_bbox, transformed_bbox) + end + + return full_bbox[] +end + function data_limits(scenelike, exclude=(p)-> false) bb_ref = Base.RefValue(Rect3f()) foreach_plot(scenelike) do plot @@ -232,3 +249,20 @@ function data_limits(plot::Image) maxi = Vec3f(last.(mini_maxi)..., 0) return Rect3f(mini, maxi .- mini) end + +function data_limits(plot::MeshScatter) + # TODO: avoid mesh generation here if possible + @get_attribute plot (marker, markersize, rotations) + marker_bb = Rect3f(marker) + positions = iterate_transformed(plot) + scales = markersize + # fast path for constant markersize + if scales isa VecTypes{3} && rotations isa Quaternion + bb = limits_from_transformed_points(positions) + marker_bb = rotations * (marker_bb * scales) + return Rect3f(minimum(bb) + minimum(marker_bb), widths(bb) + widths(marker_bb)) + else + # TODO: optimize const scale, var rot and var scale, const rot + return limits_from_transformed_points(positions, scales, rotations, marker_bb) + end +end diff --git a/src/layouting/transformation.jl b/src/layouting/transformation.jl index 18a640704cc..bde0e8b3340 100644 --- a/src/layouting/transformation.jl +++ b/src/layouting/transformation.jl @@ -1,49 +1,20 @@ Base.parent(t::Transformation) = isassigned(t.parent) ? t.parent[] : nothing -function Transformation(transform_func=identity; - scale=Vec3f(1), - translation=Vec3f(0), - rotation=Quaternionf(0, 0, 0, 1)) - - scale_o = convert(Observable{Vec3f}, scale) - translation_o = convert(Observable{Vec3f}, translation) - rotation_o = convert(Observable{Quaternionf}, rotation) - model = map(transformationmatrix, translation_o, scale_o, rotation_o) - return Transformation( - translation_o, - scale_o, - rotation_o, - model, - convert(Observable{Any}, transform_func) - ) -end - -function Transformation(transformable::Transformable; - scale=Vec3f(1), - translation=Vec3f(0), - rotation=Quaternionf(0, 0, 0, 1), - transform_func = copy(transformation(transformable).transform_func)) - - scale_o = convert(Observable{Vec3f}, scale) - translation_o = convert(Observable{Vec3f}, translation) - rotation_o = convert(Observable{Quaternionf}, rotation) - parent_transform = transformation(transformable) - - pmodel = parent_transform.model - model = map(translation_o, scale_o, rotation_o, pmodel) do t, s, r, p - return p * transformationmatrix(t, s, r) +function Observables.connect!(parent::Transformation, child::Transformation; connect_func=true) + tfuncs = [] + obsfunc = on(parent.model; update=true) do m + return child.parent_model[] = m end - - trans = Transformation( - translation_o, - scale_o, - rotation_o, - model, - convert(Observable{Any}, transform_func) - ) - - trans.parent[] = parent_transform - return trans + push!(tfuncs, obsfunc) + if connect_func + t2 = on(parent.transform_func; update=true) do f + child.transform_func[] = f + return + end + push!(tfuncs, t2) + end + child.parent[] = parent + return tfuncs end function free(transformation::Transformation) @@ -69,7 +40,7 @@ end function translated(scene::Scene; kw_args...) tscene = Scene(scene, transformation = Transformation()) transform!(tscene; kw_args...) - tscene + tscene end function transform!( @@ -84,7 +55,7 @@ function transform!( end function transform!( - scene::Transformable, attributes::Union{Attributes, AbstractDict} + scene::Transformable, attributes::Union{Attributes, AbstractDict, NamedTuple} ) transform!(scene; attributes...) end @@ -407,26 +378,36 @@ end ################################################################################ """ - Polar(theta_0::Float64 = 0.0, direction::Int = +1, r0::Float64 = 0) + Polar(theta_as_x = true, clip_r = true, theta_0::Float64 = 0.0, direction::Int = +1, r0::Float64 = 0) + +This struct defines a general polar-to-cartesian transformation, i.e. -This struct defines a general polar-to-cartesian transformation, i.e., ```math (r, θ) -> ((r - r₀) ⋅ \\cos(direction ⋅ (θ + θ₀)), (r - r₀) ⋅ \\sin(direction \\cdot (θ + θ₀))) ``` -where theta is assumed to be in radians. - -`direction` should be either -1 or +1, `r0` should be positive and `theta_0` may be any value. - -Note that for `r0 != 0` the inversion may return wrong results. +where θ is assumed to be in radians. + +Controls: +- `theta_as_x = true` controls the order of incoming arguments. If true, a `Point2f` +is interpreted as `(θ, r)`, otherwise `(r, θ)`. +- `clip_r = true` controls whether negative radii are clipped. If true, `r < 0` +produces `NaN`, otherwise they simply enter in the formula above as is. Note that +the inversion only returns `r ≥ 0` +- `theta_0 = 0` offsets angles by the specified amount. +- `direction = +1` inverts the direction of θ. +- `r0 = 0` offsets radii by the specified amount. Not that this will affect the +shape of transformed objects. """ struct Polar theta_as_x::Bool + clip_r::Bool theta_0::Float64 direction::Int r0::Float64 - function Polar(theta_as_x = true, theta_0 = 0.0, direction = +1, r0 = 0) - return new(theta_as_x, theta_0, direction, r0) + + function Polar(theta_0::Real = 0.0, direction::Int = +1, r0::Real = 0, theta_as_x::Bool = true, clip_r::Bool = true) + return new(theta_as_x, clip_r, theta_0, direction, r0) end end @@ -434,12 +415,15 @@ Base.broadcastable(x::Polar) = (x,) function apply_transform(trans::Polar, point::VecTypes{2, T}) where T <: Real if trans.theta_as_x - r = max(0.0, point[2] - trans.r0) - θ = trans.direction * (point[1] + trans.theta_0) + θ, r = point else - r = max(0.0, point[1] - trans.r0) - θ = trans.direction * (point[2] + trans.theta_0) + r, θ = point + end + r = r - trans.r0 + if trans.clip_r && (r < 0.0) + return Point2{T}(NaN) end + θ = trans.direction * (θ + trans.theta_0) y, x = r .* sincos(θ) return Point2{T}(x, y) end diff --git a/src/lighting.jl b/src/lighting.jl new file mode 100644 index 00000000000..c4a0a814dd6 --- /dev/null +++ b/src/lighting.jl @@ -0,0 +1,278 @@ +abstract type AbstractLight end + +# GLMakie interface + +# These need to match up with light shaders to differentiate light types +module LightType + const UNDEFINED = 0 + const Ambient = 1 + const PointLight = 2 + const DirectionalLight = 3 + const SpotLight = 4 + const RectLight = 5 +end + +# Each light should implement +light_type(::AbstractLight) = LightType.UNDEFINED +light_color(::AbstractLight) = RGBf(0, 0, 0) +# Other attributes need to be handled explicitly in backends + + +""" + AmbientLight(color) <: AbstractLight + +A simple ambient light that uniformly lights every object based on its light color. + +Availability: +- All backends with `shading = FastShading` or `MultiLightShading` +""" +struct AmbientLight <: AbstractLight + color::Observable{RGBf} +end + +light_type(::AmbientLight) = LightType.Ambient +light_color(l::AmbientLight) = l.color[] + + +""" + PointLight(color, position[, attenuation = Vec2f(0)]) + PointLight(color, position, range::Real) + +A point-like light source placed at the given `position` with the given light +`color`. + +Optionally an attenuation parameter can be used to reduce the brightness of the +light source with distance. The reduction is given by +`1 / (1 + attenuation[1] * distance + attenuation[2] * distance^2)`. +Alternatively you can pass a light `range` to generate matching default +attenuation parameters. Note that you may need to set the light intensity, i.e. +the light color to values greater than 1 to get satisfying results. + +Availability: +- GLMakie with `shading = MultiLightShading` +- RPRMakie +""" +struct PointLight <: AbstractLight + color::Observable{RGBf} + position::Observable{Vec3f} + attenuation::Observable{Vec2f} +end + +# no attenuation +function PointLight(color::Union{Colorant, Observable{<: Colorant}}, position::Union{VecTypes{3}, Observable{<: VecTypes{3}}}) + return PointLight(color, position, Vec2f(0)) +end +# automatic attenuation +function PointLight(color::Union{Colorant, Observable{<: Colorant}}, position::Union{VecTypes{3}, Observable{<: VecTypes{3}}}, range::Real) + return PointLight(color, position, default_attenuation(range)) +end + +@deprecate PointLight(position::Union{VecTypes{3}, Observable{<: VecTypes{3}}}, color::Union{Colorant, Observable{<: Colorant}}) PointLight(color, position) + +light_type(::PointLight) = LightType.PointLight +light_color(l::PointLight) = l.color[] + +# fit of values used on learnopengl/ogre3d +function default_attenuation(range::Real) + return Vec2f( + 4.690507869767646 * range ^ -1.009712247799057, + 82.4447791934059 * range ^ -2.0192061630628966 + ) +end + + +""" + DirectionalLight(color, direction[, camera_relative = false]) + +A light type which simulates a distant light source with parallel light rays +going in the given `direction`. + +Availability: +- All backends with `shading = FastShading` or `MultiLightShading` +""" +struct DirectionalLight <: AbstractLight + color::Observable{RGBf} + direction::Observable{Vec3f} + + # Usually a light source is placed in world space, i.e. unrelated to the + # camera. As a default however, we want to make sure that an object is + # always reasonably lit, which requires the light source to move with the + # camera. To keep this in sync in WGLMakie, the calculation needs to happen + # in javascript. This flag notives WGLMakie and other backends that this + # calculation needs to happen. + camera_relative::Bool + + DirectionalLight(col, dir, rel = false) = new(col, dir, rel) +end +light_type(::DirectionalLight) = LightType.DirectionalLight +light_color(l::DirectionalLight) = l.color[] + + +""" + SpotLight(color, position, direction, angles) + +Creates a spot light which illuminates objects in a light cone starting at +`position` pointing in `direction`. The opening angle is defined by an inner +and outer angle given in `angles`, between which the light intensity drops off. + +Availability: +- GLMakie with `shading = MultiLightShading` +- RPRMakie +""" +struct SpotLight <: AbstractLight + color::Observable{RGBf} + position::Observable{Vec3f} + direction::Observable{Vec3f} + angles::Observable{Vec2f} +end + +light_type(::SpotLight) = LightType.SpotLight +light_color(l::SpotLight) = l.color[] + + +""" + EnvironmentLight(intensity, image) + +An environment light that uses a spherical environment map to provide lighting. +See: https://en.wikipedia.org/wiki/Reflection_mapping + +Availability: +- RPRMakie +""" +struct EnvironmentLight <: AbstractLight + intensity::Observable{Float32} + image::Observable{Matrix{RGBf}} +end + +""" + RectLight(color, r::Rect2[, direction = -normal]) + RectLight(color, center::Point3f, b1::Vec3f, b2::Vec3f[, direction = -normal]) + +Creates a RectLight with a given color. The first constructor derives the light +from a `Rect2` extending in x and y direction. The second specifies the `center` +of the rect (or more accurately parallelogram) with `b1` and `b2` specifying the +width and height vectors (including scale). + +Note that RectLight implements `translate!`, `rotate!` and `scale!` to simplify +adjusting the light. + +Availability: +- GLMakie with `Shading = MultiLightShading` +""" +struct RectLight <: AbstractLight + color::Observable{RGBf} + position::Observable{Point3f} + u1::Observable{Vec3f} + u2::Observable{Vec3f} + direction::Observable{Vec3f} +end + +RectLight(color, pos, u1, u2) = RectLight(color, pos, u1, u2, -normalize(cross(u1, u2))) +function RectLight(color, r::Rect2) + mini = minimum(r); ws = widths(r) + position = Observable(to_ndim(Point3f, mini + 0.5 * ws, 0)) + u1 = Observable(Vec3f(ws[1], 0, 0)) + u2 = Observable(Vec3f(0, ws[2], 0)) + return RectLight(color, position, u1, u2, normalize(Vec3f(0,0,-1))) +end + +# Implement Transformable interface (more or less) to simplify working with +# RectLights + +function translate!(::Type{T}, l::RectLight, v) where T + offset = to_ndim(Vec3f, Float32.(v), 0) + if T === Accum + l.position[] = l.position[] + offset + elseif T === Absolute + l.position[] = offset + else + error("Unknown translation type: $T") + end +end +translate!(l::RectLight, v) = translate!(Absolute, l, v) + +function rotate!(l::RectLight, q...) + rot = convert_attribute(q, key"rotation"()) + l.u1[] = rot * l.u1[] + l.u2[] = rot * l.u2[] + l.direction[] = rot * l.direction[] +end + +function scale!(::Type{T}, l::RectLight, s) where T + scale = to_ndim(Vec2f, Float32.(s), 0) + if T === Accum + l.u1[] = scale[1] * l.u1[] + l.u2[] = scale[2] * l.u2[] + elseif T === Absolute + l.u1[] = scale[1] * normalize(l.u1[]) + l.u2[] = scale[2] * normalize(l.u2[]) + else + error("Unknown translation type: $T") + end +end +scale!(l::RectLight, x::Real, y::Real) = scale!(Accum, l, Vec2f(x, y)) +scale!(l::RectLight, xy::VecTypes) = scale!(Accum, l, xy) + + +light_type(::RectLight) = LightType.RectLight +light_color(l::RectLight) = l.color[] + + +################################################################################ + + +function get_one_light(lights, Typ) + indices = findall(x-> x isa Typ, lights) + isempty(indices) && return nothing + return lights[indices[1]] +end + +function default_shading!(plot, lights::Vector{<: AbstractLight}) + # if the plot does not have :shading we assume the plot doesn't support it + haskey(plot.attributes, :shading) || return + + # Bad type + shading = to_value(plot.attributes[:shading]) + if !(shading isa MakieCore.ShadingAlgorithm || shading === automatic) + prev = shading + if (shading isa Bool) && (shading == false) + shading = NoShading + else + shading = automatic + end + @warn "`shading = $prev` is not valid. Use `automatic`, `NoShading`, `FastShading` or `MultiLightShading`. Defaulting to `$shading`." + end + + # automatic conversion + if shading === automatic + ambient_count = 0 + dir_light_count = 0 + + for light in lights + if light isa AmbientLight + ambient_count += 1 + elseif light isa DirectionalLight + dir_light_count += 1 + elseif light isa EnvironmentLight + continue + else + plot.attributes[:shading] = MultiLightShading + return + end + if ambient_count > 1 || dir_light_count > 1 + plot.attributes[:shading] = MultiLightShading + return + end + end + + if dir_light_count + ambient_count == 0 + shading = NoShading + else + shading = FastShading + end + end + + plot.attributes[:shading] = shading + + return +end \ No newline at end of file diff --git a/src/makielayout/MakieLayout.jl b/src/makielayout/MakieLayout.jl index 50f8bb47abd..9ba11fa0569 100644 --- a/src/makielayout/MakieLayout.jl +++ b/src/makielayout/MakieLayout.jl @@ -1,5 +1,4 @@ import Formatting -using Match import Animations using GridLayoutBase using GridLayoutBase: GridSubposition @@ -69,7 +68,6 @@ export Cycled # from GridLayoutBase export GridLayout, GridPosition, GridSubposition -export GridLayoutSpec export BBox export LayoutObservables export Inside, Outside, Mixed @@ -94,5 +92,3 @@ export grid!, hgrid!, vgrid! export swap! export ncols, nrows export contents, content - -Base.@deprecate_binding MakieLayout Makie true "The module `MakieLayout` has been removed and integrated into Makie, so simply replace all usage of `MakieLayout` with `Makie`." diff --git a/src/makielayout/blocks.jl b/src/makielayout/blocks.jl index 855c28627ae..3d3d70efc79 100644 --- a/src/makielayout/blocks.jl +++ b/src/makielayout/blocks.jl @@ -1,4 +1,4 @@ -abstract type Block end + function is_attribute end function default_attribute_values end @@ -6,13 +6,14 @@ function attribute_default_expressions end function _attribute_docs end function has_forwarded_layout end - -macro Block(name::Symbol, body::Expr = Expr(:block)) +macro Block(_name::Union{Expr, Symbol}, body::Expr = Expr(:block)) body.head === :block || error("A Block needs to be defined within a `begin end` block") + type_expr = _name isa Expr ? _name : :($_name <: Makie.Block) + name = _name isa Symbol ? _name : _name.args[1] structdef = quote - mutable struct $name <: Makie.Block + mutable struct $(type_expr) parent::Union{Figure, Scene, Nothing} layoutobservables::Makie.LayoutObservables{GridLayout} blockscene::Scene @@ -64,7 +65,7 @@ macro Block(name::Symbol, body::Expr = Expr(:block)) function Makie.default_attribute_values(::Type{$(name)}, scene::Union{Scene, Nothing}) sceneattrs = scene === nothing ? Attributes() : theme(scene) - curdeftheme = fast_deepcopy($(Makie).CURRENT_DEFAULT_THEME) + curdeftheme = Makie.fast_deepcopy($(Makie).CURRENT_DEFAULT_THEME) $(make_attr_dict_expr(attrs, :sceneattrs, :curdeftheme)) end @@ -255,6 +256,7 @@ end can_be_current_axis(x) = false +get_top_parent(gp::GridLayout) = GridLayoutBase.top_parent(gp) get_top_parent(gp::GridPosition) = GridLayoutBase.top_parent(gp.layout) get_top_parent(gp::GridSubposition) = get_top_parent(gp.parent) @@ -269,50 +271,62 @@ function _block(T::Type{<:Block}, b end -function _block(T::Type{<:Block}, fig_or_scene::Union{Figure, Scene}, - args...; bbox = nothing, kwargs...) - - # first sort out all user kwargs that correspond to block attributes - kwdict = Dict(kwargs) - - if haskey(kwdict, :textsize) - throw(ArgumentError("The attribute `textsize` has been renamed to `fontsize` in Makie v0.19. Please change all occurrences of `textsize` to `fontsize` or revert back to an earlier version.")) - end - attribute_kwargs = Dict{Symbol, Any}() - for (key, value) in kwdict - if is_attribute(T, key) - attribute_kwargs[key] = pop!(kwdict, key) - end - end - # the non-attribute kwargs will be passed to the block later - non_attribute_kwargs = kwdict +function _block(T::Type{<:Block}, fig_or_scene::Union{Figure, Scene}, args...; bbox = nothing, kwargs...) + return _block(T, fig_or_scene, Any[args...], Dict{Symbol,Any}(kwargs), bbox) +end - topscene = get_topscene(fig_or_scene) - # retrieve the default attributes for this block given the scene theme - # and also the `Block = (...` style attributes from scene and global theme - default_attrs = default_attribute_values(T, topscene) - typekey_scene_attrs = get(theme(topscene), nameof(T), Attributes())::Attributes - typekey_attrs = theme(nameof(T); default=Attributes())::Attributes +function block_defaults(blockname::Symbol, attribute_kwargs::Dict, scene::Union{Nothing, Scene}) + return block_defaults(getfield(Makie, blockname), attribute_kwargs, scene) +end +function block_defaults(::Type{B}, attribute_kwargs::Dict, scene::Union{Nothing, Scene}) where {B <: Block} + default_attrs = default_attribute_values(B, scene) + blockname = nameof(B) + typekey_scene_attrs = get(theme(scene), blockname, Attributes()) + typekey_attrs = theme(blockname; default=Attributes())::Attributes + attributes = Dict{Symbol,Any}() # make a final attribute dictionary using different priorities # for the different themes - attributes = Dict{Symbol, Any}() for (key, val) in default_attrs # give kwargs priority if haskey(attribute_kwargs, key) attributes[key] = attribute_kwargs[key] - # otherwise scene theme + # otherwise scene theme elseif haskey(typekey_scene_attrs, key) attributes[key] = typekey_scene_attrs[key] - # otherwise global theme + # otherwise global theme elseif haskey(typekey_attrs, key) attributes[key] = typekey_attrs[key] - # otherwise its the value from the type default theme + # otherwise its the value from the type default theme else attributes[key] = val end end + return attributes +end + +function _block(T::Type{<:Block}, fig_or_scene::Union{Figure,Scene}, args, kwdict::Dict, bbox; kwdict_complete=false) + + # first sort out all user kwargs that correspond to block attributes + check_textsize_deprecation(kwdict) + + attribute_kwargs = Dict{Symbol, Any}() + for (key, value) in kwdict + if is_attribute(T, key) + attribute_kwargs[key] = pop!(kwdict, key) + end + end + # the non-attribute kwargs will be passed to the block later + non_attribute_kwargs = kwdict + topscene = get_topscene(fig_or_scene) + # retrieve the default attributes for this block given the scene theme + # and also the `Block = (...` style attributes from scene and global theme + if kwdict_complete + attributes = attribute_kwargs + else + attributes = block_defaults(T, attribute_kwargs, topscene) + end # create basic layout observables and connect attribute observables further down # after creating the block with its observable fields @@ -404,6 +418,7 @@ end """ Get the scene which blocks need from their parent to plot stuff into """ +get_topscene(f::Union{GridPosition, GridSubposition}) = get_topscene(get_top_parent(f)) get_topscene(f::Figure) = f.scene function get_topscene(s::Scene) if !(Makie.cameracontrols(s) isa Makie.PixelCamera) @@ -465,7 +480,7 @@ free(::Block) = nothing function Base.delete!(block::Block) free(block) block.parent === nothing && return - # detach plots, cameras, transformations, px_area + # detach plots, cameras, transformations, viewport empty!(block.blockscene) gc = GridLayoutBase.gridcontent(block) @@ -509,22 +524,22 @@ end # if a non-observable is passed, its value is converted and placed into an observable of # the correct type which is then used as the block field -function init_observable!(@nospecialize(x), key, @nospecialize(OT), @nospecialize(value)) +function init_observable!(@nospecialize(block), key::Symbol, @nospecialize(OT), @nospecialize(value)) o = convert_for_attribute(observable_type(OT), value) - setfield!(x, key, OT(o)) - return x + setfield!(block, key, OT(o)) + return block end # if an observable is passed, a converted type is lifted off of it, so it is # not used directly as a block field -function init_observable!(@nospecialize(x), key, @nospecialize(OT), @nospecialize(value::Observable)) +function init_observable!(@nospecialize(block), key::Symbol, @nospecialize(OT), @nospecialize(value::Observable)) obstype = observable_type(OT) o = Observable{obstype}() map!(o, value) do v convert_for_attribute(obstype, v) end - setfield!(x, key, o) - return x + setfield!(block, key, o) + return block end observable_type(x::Type{Observable{T}}) where T = T diff --git a/src/makielayout/blocks/axis.jl b/src/makielayout/blocks/axis.jl index 71e117ef2eb..ccad1873578 100644 --- a/src/makielayout/blocks/axis.jl +++ b/src/makielayout/blocks/axis.jl @@ -158,17 +158,11 @@ function compute_protrusions(title, titlesize, titlegap, titlevisible, spinewidt end function initialize_block!(ax::Axis; palette = nothing) - blockscene = ax.blockscene elements = Dict{Symbol, Any}() ax.elements = elements - if palette === nothing - palette = fast_deepcopy(get(blockscene.theme, :palette, Makie.DEFAULT_PALETTES)) - end - ax.palette = palette isa Attributes ? palette : Attributes(palette) - # initialize either with user limits, or pick defaults based on scales # so that we don't immediately error targetlimits = Observable{Rect2f}(defaultlimits(ax.limits[], ax.xscale[], ax.yscale[])) @@ -176,8 +170,6 @@ function initialize_block!(ax::Axis; palette = nothing) setfield!(ax, :targetlimits, targetlimits) setfield!(ax, :finallimits, finallimits) - ax.cycler = Cycler() - on(blockscene, targetlimits) do lims # this should validate the targetlimits before anything else happens with them # so there should be nothing before this lifting `targetlimits` @@ -190,12 +182,18 @@ function initialize_block!(ax::Axis; palette = nothing) scenearea = sceneareanode!(ax.layoutobservables.computedbbox, finallimits, ax.aspect) - scene = Scene(blockscene, px_area=scenearea) + scene = Scene(blockscene, viewport=scenearea) ax.scene = scene + if !isnothing(palette) + # Backwards compatibility for when palette was part of axis! + palette_attr = palette isa Attributes ? palette : Attributes(palette) + ax.scene.theme.palette = palette_attr + end + # TODO: replace with mesh, however, CairoMakie needs a poly path for this signature # so it doesn't rasterize the scene - background = poly!(blockscene, scenearea; color=ax.backgroundcolor, inspectable=false, shading=false, strokecolor=:transparent) + background = poly!(blockscene, scenearea; color=ax.backgroundcolor, inspectable=false, shading=NoShading, strokecolor=:transparent) translate!(background, 0, 0, -100) elements[:background] = background @@ -259,7 +257,7 @@ function initialize_block!(ax::Axis; palette = nothing) # 3. Update the view onto the plot (camera matrices) onany(update_axis_camera, camera(scene), scene.transformation.transform_func, finallimits, ax.xreversed, ax.yreversed, priority = -2) - xaxis_endpoints = lift(blockscene, ax.xaxisposition, scene.px_area; + xaxis_endpoints = lift(blockscene, ax.xaxisposition, scene.viewport; ignore_equal_values=true) do xaxisposition, area if xaxisposition === :bottom return bottomline(Rect2f(area)) @@ -270,7 +268,7 @@ function initialize_block!(ax::Axis; palette = nothing) end end - yaxis_endpoints = lift(blockscene, ax.yaxisposition, scene.px_area; + yaxis_endpoints = lift(blockscene, ax.yaxisposition, scene.viewport; ignore_equal_values=true) do yaxisposition, area if yaxisposition === :left return leftline(Rect2f(area)) @@ -347,7 +345,7 @@ function initialize_block!(ax::Axis; palette = nothing) ax.yaxis = yaxis - xoppositelinepoints = lift(blockscene, scene.px_area, ax.spinewidth, ax.xaxisposition; + xoppositelinepoints = lift(blockscene, scene.viewport, ax.spinewidth, ax.xaxisposition; ignore_equal_values=true) do r, sw, xaxpos if xaxpos === :top y = bottom(r) @@ -362,7 +360,7 @@ function initialize_block!(ax::Axis; palette = nothing) end end - yoppositelinepoints = lift(blockscene, scene.px_area, ax.spinewidth, ax.yaxisposition; + yoppositelinepoints = lift(blockscene, scene.viewport, ax.spinewidth, ax.yaxisposition; ignore_equal_values=true) do r, sw, yaxpos if yaxpos === :right x = left(r) @@ -378,22 +376,22 @@ function initialize_block!(ax::Axis; palette = nothing) end xticksmirrored = lift(mirror_ticks, blockscene, xaxis.tickpositions, ax.xticksize, ax.xtickalign, - Ref(scene.px_area), :x, ax.xaxisposition[]) + Ref(scene.viewport), :x, ax.xaxisposition[]) xticksmirrored_lines = linesegments!(blockscene, xticksmirrored, visible = @lift($(ax.xticksmirrored) && $(ax.xticksvisible)), linewidth = ax.xtickwidth, color = ax.xtickcolor) translate!(xticksmirrored_lines, 0, 0, 10) yticksmirrored = lift(mirror_ticks, blockscene, yaxis.tickpositions, ax.yticksize, ax.ytickalign, - Ref(scene.px_area), :y, ax.yaxisposition[]) + Ref(scene.viewport), :y, ax.yaxisposition[]) yticksmirrored_lines = linesegments!(blockscene, yticksmirrored, visible = @lift($(ax.yticksmirrored) && $(ax.yticksvisible)), linewidth = ax.ytickwidth, color = ax.ytickcolor) translate!(yticksmirrored_lines, 0, 0, 10) xminorticksmirrored = lift(mirror_ticks, blockscene, xaxis.minortickpositions, ax.xminorticksize, - ax.xminortickalign, Ref(scene.px_area), :x, ax.xaxisposition[]) + ax.xminortickalign, Ref(scene.viewport), :x, ax.xaxisposition[]) xminorticksmirrored_lines = linesegments!(blockscene, xminorticksmirrored, visible = @lift($(ax.xticksmirrored) && $(ax.xminorticksvisible)), linewidth = ax.xminortickwidth, color = ax.xminortickcolor) translate!(xminorticksmirrored_lines, 0, 0, 10) yminorticksmirrored = lift(mirror_ticks, blockscene, yaxis.minortickpositions, ax.yminorticksize, - ax.yminortickalign, Ref(scene.px_area), :y, ax.yaxisposition[]) + ax.yminortickalign, Ref(scene.viewport), :y, ax.yaxisposition[]) yminorticksmirrored_lines = linesegments!(blockscene, yminorticksmirrored, visible = @lift($(ax.yticksmirrored) && $(ax.yminorticksvisible)), linewidth = ax.yminortickwidth, color = ax.yminortickcolor) translate!(yminorticksmirrored_lines, 0, 0, 10) @@ -410,31 +408,31 @@ function initialize_block!(ax::Axis; palette = nothing) elements[:yoppositeline] = yoppositeline translate!(yoppositeline, 0, 0, 20) - onany(blockscene, xaxis.tickpositions, scene.px_area) do tickpos, area + onany(blockscene, xaxis.tickpositions, scene.viewport) do tickpos, area local pxheight::Float32 = height(area) local offset::Float32 = ax.xaxisposition[] === :bottom ? pxheight : -pxheight update_gridlines!(xgridnode, Point2f(0, offset), tickpos) end - onany(blockscene, yaxis.tickpositions, scene.px_area) do tickpos, area + onany(blockscene, yaxis.tickpositions, scene.viewport) do tickpos, area local pxwidth::Float32 = width(area) local offset::Float32 = ax.yaxisposition[] === :left ? pxwidth : -pxwidth update_gridlines!(ygridnode, Point2f(offset, 0), tickpos) end - onany(blockscene, xaxis.minortickpositions, scene.px_area) do tickpos, area - local pxheight::Float32 = height(scene.px_area[]) + onany(blockscene, xaxis.minortickpositions, scene.viewport) do tickpos, area + local pxheight::Float32 = height(scene.viewport[]) local offset::Float32 = ax.xaxisposition[] === :bottom ? pxheight : -pxheight update_gridlines!(xminorgridnode, Point2f(0, offset), tickpos) end - onany(blockscene, yaxis.minortickpositions, scene.px_area) do tickpos, area - local pxwidth::Float32 = width(scene.px_area[]) + onany(blockscene, yaxis.minortickpositions, scene.viewport) do tickpos, area + local pxwidth::Float32 = width(scene.viewport[]) local offset::Float32 = ax.yaxisposition[] === :left ? pxwidth : -pxwidth update_gridlines!(yminorgridnode, Point2f(offset, 0), tickpos) end - subtitlepos = lift(blockscene, scene.px_area, ax.titlegap, ax.titlealign, ax.xaxisposition, + subtitlepos = lift(blockscene, scene.viewport, ax.titlegap, ax.titlealign, ax.xaxisposition, xaxis.protrusion; ignore_equal_values=true) do a, titlegap, align, xaxisposition, xaxisprotrusion @@ -463,7 +461,7 @@ function initialize_block!(ax::Axis; palette = nothing) markerspace = :data, inspectable = false) - titlepos = lift(calculate_title_position, blockscene, scene.px_area, ax.titlegap, ax.subtitlegap, + titlepos = lift(calculate_title_position, blockscene, scene.viewport, ax.titlegap, ax.subtitlegap, ax.titlealign, ax.xaxisposition, xaxis.protrusion, ax.subtitlelineheight, ax, subtitlet; ignore_equal_values=true) titlet = text!( @@ -506,7 +504,7 @@ function initialize_block!(ax::Axis; palette = nothing) # compute limits that adhere to the limit aspect ratio whenever the targeted # limits or the scene size change, because both influence the displayed ratio - onany(blockscene, scene.px_area, targetlimits) do pxa, lims + onany(blockscene, scene.viewport, targetlimits) do pxa, lims adjustlimits!(ax) end @@ -522,8 +520,8 @@ function initialize_block!(ax::Axis; palette = nothing) return ax end -function mirror_ticks(tickpositions, ticksize, tickalign, px_area, side, axisposition) - a = px_area[][] +function mirror_ticks(tickpositions, ticksize, tickalign, viewport, side, axisposition) + a = viewport[][] if side === :x opp = axisposition === :bottom ? top(a) : bottom(a) sign = axisposition === :bottom ? 1 : -1 @@ -651,7 +649,6 @@ end function convert_limit_attribute(lims::Tuple{Any, Any}) lims end -can_be_current_axis(ax::Axis) = true function validate_limits_for_scales(lims::Rect, xsc, ysc) mi = minimum(lims) @@ -675,61 +672,55 @@ attrsyms(cycle::Cycle) = [c[1] for c in cycle.cycle] function get_cycler_index!(c::Cycler, P::Type) if !haskey(c.counters, P) - c.counters[P] = 1 + return c.counters[P] = 1 else - c.counters[P] += 1 + return c.counters[P] += 1 end end -function get_cycle_for_plottype(allattrs, P)::Cycle - psym = MakieCore.plotsym(P) - - plottheme = Makie.default_theme(nothing, P) - - cycle_raw = if haskey(allattrs, :cycle) - allattrs.cycle[] - else - global_theme_cycle = theme(psym) - if !isnothing(global_theme_cycle) && haskey(global_theme_cycle, :cycle) - global_theme_cycle.cycle[] - else - haskey(plottheme, :cycle) ? plottheme.cycle[] : nothing - end - end - +function get_cycle_for_plottype(cycle_raw)::Cycle if isnothing(cycle_raw) - Cycle([]) + return Cycle([]) elseif cycle_raw isa Cycle - cycle_raw + return cycle_raw else - Cycle(cycle_raw) + return Cycle(cycle_raw) end end -function add_cycle_attributes!(allattrs, P, cycle::Cycle, cycler::Cycler, palette::Attributes) +function to_color(scene::Scene, attribute_name, cycled::Cycled) + palettes = to_value(scene.theme.palette) + attr_palette = to_value(palettes[attribute_name]) + index = cycled.i + return attr_palette[mod1(index, length(attr_palette))] +end + +function add_cycle_attributes!(@nospecialize(plot), cycle::Cycle, cycler::Cycler, palette::Attributes) # check if none of the cycled attributes of this plot # were passed manually, because we don't use the cycler # if any of the cycled attributes were specified manually - no_cycle_attribute_passed = !any(keys(allattrs)) do key + user_attributes = plot.kw + no_cycle_attribute_passed = !any(keys(user_attributes)) do key any(syms -> key in syms, attrsyms(cycle)) end # check if any attributes were passed as `Cycled` entries # because if there were any, these are looked up directly # in the cycler without advancing the counter etc. - manually_cycled_attributes = filter(keys(allattrs)) do key - to_value(allattrs[key]) isa Cycled + manually_cycled_attributes = filter(keys(user_attributes)) do key + return to_value(user_attributes[key]) isa Cycled end # if there are any manually cycled attributes, we don't do the normal # cycling but only look up exactly the passed attributes cycle_attrsyms = attrsyms(cycle) + if !isempty(manually_cycled_attributes) # an attribute given as Cycled needs to be present in the cycler, # otherwise there's no cycle in which to look up a value for k in manually_cycled_attributes if !any(x -> k in x, cycle_attrsyms) - error("Attribute `$k` was passed with an explicit `Cycled` value, but $k is not specified in the cycler for this plot type $P.") + error("Attribute `$k` was passed with an explicit `Cycled` value, but $k is not specified in the cycler for this plot type $(typeof(plot)).") end end @@ -737,10 +728,10 @@ function add_cycle_attributes!(allattrs, P, cycle::Cycle, cycler::Cycler, palett for sym in manually_cycled_attributes isym = findfirst(syms -> sym in syms, attrsyms(cycle)) - index = allattrs[sym][].i + index = plot[sym][].i # replace the Cycled values with values from the correct palettes # at the index inside the Cycled object - allattrs[sym] = if cycle.covary + plot[sym] = if cycle.covary palettes[isym][mod1(index, length(palettes[isym]))] else cis = CartesianIndices(Tuple(length(p) for p in palettes)) @@ -752,13 +743,13 @@ function add_cycle_attributes!(allattrs, P, cycle::Cycle, cycler::Cycler, palett end elseif no_cycle_attribute_passed - index = get_cycler_index!(cycler, P) + index = get_cycler_index!(cycler, typeof(plot)) palettes = [palette[sym][] for sym in palettesyms(cycle)] for (isym, syms) in enumerate(attrsyms(cycle)) for sym in syms - allattrs[sym] = if cycle.covary + plot[sym] = if cycle.covary palettes[isym][mod1(index, length(palettes[isym]))] else cis = CartesianIndices(Tuple(length(p) for p in palettes)) @@ -772,37 +763,10 @@ function add_cycle_attributes!(allattrs, P, cycle::Cycle, cycler::Cycler, palett end end -function Makie.plot!( - la::Axis, P::Makie.PlotFunc, - attributes::Makie.Attributes, args...; - kw_attributes...) - - allattrs = merge(attributes, Attributes(kw_attributes)) - - _disallow_keyword(:axis, allattrs) - _disallow_keyword(:figure, allattrs) - cycle = get_cycle_for_plottype(allattrs, P) - add_cycle_attributes!(allattrs, P, cycle, la.cycler, la.palette) - - plot = Makie.plot!(la.scene, P, allattrs, args...) - - # some area-like plots basically always look better if they cover the whole plot area. - # adjust the limit margins in those cases automatically. - needs_tight_limits(plot) && tightlimits!(la) - - if is_open_or_any_parent(la.scene) - reset_limits!(la) - end - plot -end - is_open_or_any_parent(s::Scene) = isopen(s) || is_open_or_any_parent(s.parent) is_open_or_any_parent(::Nothing) = false -function Makie.plot!(P::Makie.PlotFunc, ax::Axis, args...; kw_attributes...) - attributes = Makie.Attributes(kw_attributes) - Makie.plot!(ax, P, attributes, args...) -end + needs_tight_limits(@nospecialize any) = false needs_tight_limits(::Union{Heatmap, Image}) = true @@ -991,7 +955,7 @@ end function adjustlimits!(la) asp = la.autolimitaspect[] target = la.targetlimits[] - area = la.scene.px_area[] + area = la.scene.viewport[] # in the simplest case, just update the final limits with the target limits if isnothing(asp) || width(area) == 0 || height(area) == 0 @@ -1106,7 +1070,8 @@ end hidexdecorations!(la::Axis; label = true, ticklabels = true, ticks = true, grid = true, minorgrid = true, minorticks = true) -Hide decorations of the x-axis: label, ticklabels, ticks and grid. +Hide decorations of the x-axis: label, ticklabels, ticks and grid. Keyword +arguments can be used to disable hiding of certain types of decorations. """ function hidexdecorations!(la::Axis; label = true, ticklabels = true, ticks = true, grid = true, minorgrid = true, minorticks = true) @@ -1134,7 +1099,8 @@ end hideydecorations!(la::Axis; label = true, ticklabels = true, ticks = true, grid = true, minorgrid = true, minorticks = true) -Hide decorations of the y-axis: label, ticklabels, ticks and grid. +Hide decorations of the y-axis: label, ticklabels, ticks and grid. Keyword +arguments can be used to disable hiding of certain types of decorations. """ function hideydecorations!(la::Axis; label = true, ticklabels = true, ticks = true, grid = true, minorgrid = true, minorticks = true) @@ -1159,9 +1125,13 @@ function hideydecorations!(la::Axis; label = true, ticklabels = true, ticks = tr end """ - hidedecorations!(la::Axis) + hidedecorations!(la::Axis; label = true, ticklabels = true, ticks = true, + grid = true, minorgrid = true, minorticks = true) Hide decorations of both x and y-axis: label, ticklabels, ticks and grid. +Keyword arguments can be used to disable hiding of certain types of decorations. + +See also [`hidexdecorations!`], [`hideydecorations!`], [`hidezdecorations!`] """ function hidedecorations!(la::Axis; label = true, ticklabels = true, ticks = true, grid = true, minorgrid = true, minorticks = true) @@ -1175,24 +1145,29 @@ end hidespines!(la::Axis, spines::Symbol... = (:l, :r, :b, :t)...) Hide all specified axis spines. Hides all spines by default, otherwise choose -with the symbols :l, :r, :b and :t. +which sides to hide with the symbols :l (left), :r (right), :b (bottom) and +:t (top). """ function hidespines!(la::Axis, spines::Symbol... = (:l, :r, :b, :t)...) for s in spines - @match s begin - :l => (la.leftspinevisible = false) - :r => (la.rightspinevisible = false) - :b => (la.bottomspinevisible = false) - :t => (la.topspinevisible = false) - x => error("Invalid spine identifier $x. Valid options are :l, :r, :b and :t.") + if s === :l + la.leftspinevisible = false + elseif s === :r + la.rightspinevisible = false + elseif s === :b + la.bottomspinevisible = false + elseif s === :t + la.topspinevisible = false + else + error("Invalid spine identifier $s. Valid options are :l, :r, :b and :t.") end end end """ - space = tight_xticklabel_spacing!(ax::Axis) + space = tight_yticklabel_spacing!(ax::Axis) -Sets the space allocated for the xticklabels of the `Axis` to the minimum that is needed and returns that value. +Sets the space allocated for the yticklabels of the `Axis` to the minimum that is needed and returns that value. """ function tight_yticklabel_spacing!(ax::Axis) space = tight_ticklabel_spacing!(ax.yaxis) @@ -1202,7 +1177,7 @@ end """ space = tight_xticklabel_spacing!(ax::Axis) -Sets the space allocated for the yticklabels of the `Axis` to the minimum that is needed and returns that value. +Sets the space allocated for the xticklabels of the `Axis` to the minimum that is needed and returns that value. """ function tight_xticklabel_spacing!(ax::Axis) space = tight_ticklabel_spacing!(ax.xaxis) @@ -1210,6 +1185,8 @@ function tight_xticklabel_spacing!(ax::Axis) end """ + tight_ticklabel_spacing!(ax::Axis) + Sets the space allocated for the xticklabels and yticklabels of the `Axis` to the minimum that is needed. """ function tight_ticklabel_spacing!(ax::Axis) @@ -1235,7 +1212,7 @@ end function Makie.xlims!(ax::Axis, xlims) if length(xlims) != 2 error("Invalid xlims length of $(length(xlims)), must be 2.") - elseif xlims[1] == xlims[2] + elseif xlims[1] == xlims[2] && xlims[1] !== nothing error("Can't set x limits to the same value $(xlims[1]).") elseif all(x -> x isa Real, xlims) && xlims[1] > xlims[2] xlims = reverse(xlims) @@ -1243,8 +1220,9 @@ function Makie.xlims!(ax::Axis, xlims) else ax.xreversed[] = false end + mlims = convert_limit_attribute(ax.limits[]) - ax.limits.val = (xlims, ax.limits[][2]) + ax.limits.val = (xlims, mlims[2]) reset_limits!(ax, yauto = false) nothing end @@ -1252,7 +1230,7 @@ end function Makie.ylims!(ax::Axis, ylims) if length(ylims) != 2 error("Invalid ylims length of $(length(ylims)), must be 2.") - elseif ylims[1] == ylims[2] + elseif ylims[1] == ylims[2] && ylims[1] !== nothing error("Can't set y limits to the same value $(ylims[1]).") elseif all(x -> x isa Real, ylims) && ylims[1] > ylims[2] ylims = reverse(ylims) @@ -1260,22 +1238,95 @@ function Makie.ylims!(ax::Axis, ylims) else ax.yreversed[] = false end + mlims = convert_limit_attribute(ax.limits[]) - ax.limits.val = (ax.limits[][1], ylims) + ax.limits.val = (mlims[1], ylims) reset_limits!(ax, xauto = false) nothing end +""" + xlims!(ax, low, high) + xlims!(ax; low = nothing, high = nothing) + xlims!(ax, xlims) + +Set the x-axis limits of axis `ax` to `low` and `high` or a tuple +`xlims = (low,high)`. If the limits are ordered high-low, the axis orientation +will be reversed. If a limit is `nothing` it will be determined automatically +from the plots in the axis. +""" Makie.xlims!(ax, low, high) = Makie.xlims!(ax, (low, high)) +""" + ylims!(ax, low, high) + ylims!(ax; low = nothing, high = nothing) + ylims!(ax, ylims) + +Set the y-axis limits of axis `ax` to `low` and `high` or a tuple +`ylims = (low,high)`. If the limits are ordered high-low, the axis orientation +will be reversed. If a limit is `nothing` it will be determined automatically +from the plots in the axis. +""" Makie.ylims!(ax, low, high) = Makie.ylims!(ax, (low, high)) +""" + zlims!(ax, low, high) + zlims!(ax; low = nothing, high = nothing) + zlims!(ax, zlims) + +Set the z-axis limits of axis `ax` to `low` and `high` or a tuple +`zlims = (low,high)`. If the limits are ordered high-low, the axis orientation +will be reversed. If a limit is `nothing` it will be determined automatically +from the plots in the axis. +""" Makie.zlims!(ax, low, high) = Makie.zlims!(ax, (low, high)) +""" + xlims!(low, high) + xlims!(; low = nothing, high = nothing) + +Set the x-axis limits of the current axis to `low` and `high`. If the limits +are ordered high-low, this reverses the axis orientation. A limit set to +`nothing` will be determined automatically from the plots in the axis. +""" Makie.xlims!(low::Optional{<:Real}, high::Optional{<:Real}) = Makie.xlims!(current_axis(), low, high) +""" + ylims!(low, high) + ylims!(; low = nothing, high = nothing) + +Set the y-axis limits of the current axis to `low` and `high`. If the limits +are ordered high-low, this reverses the axis orientation. A limit set to +`nothing` will be determined automatically from the plots in the axis. +""" Makie.ylims!(low::Optional{<:Real}, high::Optional{<:Real}) = Makie.ylims!(current_axis(), low, high) +""" + zlims!(low, high) + zlims!(; low = nothing, high = nothing) + +Set the z-axis limits of the current axis to `low` and `high`. If the limits +are ordered high-low, this reverses the axis orientation. A limit set to +`nothing` will be determined automatically from the plots in the axis. +""" Makie.zlims!(low::Optional{<:Real}, high::Optional{<:Real}) = Makie.zlims!(current_axis(), low, high) +""" + xlims!(ax = current_axis()) + +Reset the x-axis limits to be determined automatically from the plots in the +axis. +""" Makie.xlims!(ax = current_axis(); low = nothing, high = nothing) = Makie.xlims!(ax, low, high) +""" + ylims!(ax = current_axis()) + +Reset the y-axis limits to be determined automatically from the plots in the +axis. +""" Makie.ylims!(ax = current_axis(); low = nothing, high = nothing) = Makie.ylims!(ax, low, high) +""" + zlims!(ax = current_axis()) + +Reset the z-axis limits to be determined automatically from the plots in the +axis. +""" Makie.zlims!(ax = current_axis(); low = nothing, high = nothing) = Makie.zlims!(ax, low, high) """ @@ -1317,18 +1368,6 @@ function limits!(args...) limits!(current_axis(), args...) end -function Base.delete!(ax::Axis, plot::AbstractPlot) - delete!(ax.scene, plot) - ax -end - -function Base.empty!(ax::Axis) - while !isempty(ax.scene.plots) - delete!(ax, ax.scene.plots[end]) - end - ax -end - Makie.transform_func(ax::Axis) = Makie.transform_func(ax.scene) # these functions pick limits for different x and y scales, so that @@ -1365,10 +1404,6 @@ defined_interval(::LogFunctions) = OpenInterval(0.0, Inf) defined_interval(::typeof(sqrt)) = Interval{:closed,:open}(0, Inf) defined_interval(::typeof(Makie.logit)) = OpenInterval(0.0, 1.0) -function update_state_before_display!(ax::Axis) - reset_limits!(ax) - return -end function attribute_examples(::Type{Axis}) Dict( @@ -1805,7 +1840,7 @@ function colorbuffer(ax::Axis; include_decorations=true, update=true, colorbuffe bb = axis_bounds_with_decoration(ax) Rect2{Int}(round.(Int, minimum(bb)) .+ 1, round.(Int, widths(bb))) else - pixelarea(ax.scene)[] + viewport(ax.scene)[] end img = colorbuffer(root(ax.scene); update=false, colorbuffer_kws...) diff --git a/src/makielayout/blocks/axis3d.jl b/src/makielayout/blocks/axis3d.jl index b96f840efc8..ec72eb0dce7 100644 --- a/src/makielayout/blocks/axis3d.jl +++ b/src/makielayout/blocks/axis3d.jl @@ -38,12 +38,13 @@ function initialize_block!(ax::Axis3) return end - matrices = lift(calculate_matrices, scene, finallimits, scene.px_area, ax.elevation, ax.azimuth, + matrices = lift(calculate_matrices, scene, finallimits, scene.viewport, ax.elevation, ax.azimuth, ax.perspectiveness, ax.aspect, ax.viewmode, ax.xreversed, ax.yreversed, ax.zreversed) - on(scene, matrices) do (view, proj, eyepos) + on(scene, matrices) do (model, view, proj, eyepos) cam = camera(scene) Makie.set_proj_view!(cam, proj, view) + scene.transformation.model[] = model cam.eyeposition[] = eyepos end @@ -80,7 +81,7 @@ function initialize_block!(ax::Axis3) zticks, zticklabels, zlabel = add_ticks_and_ticklabels!(blockscene, scene, ax, 3, finallimits, ticknode_3, mi3, mi1, mi2, ax.azimuth, ax.xreversed, ax.yreversed, ax.zreversed) - titlepos = lift(scene, scene.px_area, ax.titlegap, ax.titlealign) do a, titlegap, align + titlepos = lift(scene, scene.viewport, ax.titlegap, ax.titlealign) do a, titlegap, align align_factor = halign2num(align, "Horizontal title align $align not supported.") x = a.origin[1] + align_factor * a.widths[1] @@ -105,9 +106,6 @@ function initialize_block!(ax::Axis3) markerspace = :data, inspectable = false) - ax.cycler = Cycler() - ax.palette = Makie.DEFAULT_PALETTES - ax.mouseeventhandle = addmouseevents!(scene) scrollevents = Observable(ScrollEvent(0, 0)) setfield!(ax, :scrollevents, scrollevents) @@ -164,9 +162,7 @@ function initialize_block!(ax::Axis3) return end -can_be_current_axis(ax3::Axis3) = true - -function calculate_matrices(limits, px_area, elev, azim, perspectiveness, aspect, +function calculate_matrices(limits, viewport, elev, azim, perspectiveness, aspect, viewmode, xreversed, yreversed, zreversed) ori = limits.origin @@ -199,7 +195,7 @@ function calculate_matrices(limits, px_area, elev, azim, perspectiveness, aspect end |> Makie.scalematrix t2 = Makie.translationmatrix(-0.5 .* ws .* scales) - scale_matrix = t2 * s * t + model = t2 * s * t ang_max = 90 ang_min = 0.5 @@ -220,23 +216,16 @@ function calculate_matrices(limits, px_area, elev, azim, perspectiveness, aspect eyepos = Vec3{Float64}(x, y, z) - lookat_matrix = Makie.lookat( - eyepos, - Vec3{Float64}(0, 0, 0), - Vec3{Float64}(0, 0, 1)) - - w = width(px_area) - h = height(px_area) + lookat_matrix = lookat(eyepos, Vec3{Float64}(0), Vec3{Float64}(0, 0, 1)) - view_matrix = lookat_matrix * scale_matrix + w = width(viewport) + h = height(viewport) - projection_matrix = projectionmatrix(view_matrix, limits, eyepos, radius, azim, elev, angle, w, h, scales, viewmode) + projection_matrix = projectionmatrix( + lookat_matrix * model, limits, eyepos, radius, azim, elev, angle, + w, h, scales, viewmode) - # for eyeposition dependent algorithms, we need to present the position as if - # there was no scaling applied - eyeposition = Vec3f(inv(scale_matrix) * Vec4f(eyepos..., 1)) - - view_matrix, projection_matrix, eyeposition + return model, lookat_matrix, projection_matrix, eyepos end function projectionmatrix(viewmatrix, limits, eyepos, radius, azim, elev, angle, width, height, scales, viewmode) @@ -278,33 +267,6 @@ function projectionmatrix(viewmatrix, limits, eyepos, radius, azim, elev, angle, end end - -function Makie.plot!( - ax::Axis3, P::Makie.PlotFunc, - attributes::Makie.Attributes, args...; - kw_attributes...) - - allattrs = merge(attributes, Attributes(kw_attributes)) - - _disallow_keyword(:axis, allattrs) - _disallow_keyword(:figure, allattrs) - - cycle = get_cycle_for_plottype(allattrs, P) - add_cycle_attributes!(allattrs, P, cycle, ax.cycler, ax.palette) - - plot = Makie.plot!(ax.scene, P, allattrs, args...) - - if is_open_or_any_parent(ax.scene) - reset_limits!(ax) - end - plot -end - -function Makie.plot!(P::Makie.PlotFunc, ax::Axis3, args...; kw_attributes...) - attributes = Makie.Attributes(kw_attributes) - Makie.plot!(ax, P, attributes, args...) -end - function update_state_before_display!(ax::Axis3) reset_limits!(ax) return @@ -358,10 +320,6 @@ function getlimits(ax::Axis3, dim) templim end -# mutable struct LineAxis3D - -# end - function dimpoint(dim, v, v1, v2) if dim == 1 Point(v, v1, v2) @@ -439,7 +397,7 @@ function add_gridlines_and_frames!(topscene, scene, ax, dim::Int, limits, tickno visible = attr(:gridvisible), inspectable = false) - framepoints = lift(limits, scene.camera.projectionview, scene.px_area, min1, min2, xreversed, yreversed, zreversed + framepoints = lift(limits, scene.camera.projectionview, scene.viewport, min1, min2, xreversed, yreversed, zreversed ) do lims, _, pxa, mi1, mi2, xrev, yrev, zrev o = pxa.origin @@ -476,7 +434,7 @@ end # this function projects a point from a 3d subscene into the parent space with a really # small z value function to_topscene_z_2d(p3d, scene) - o = scene.px_area[].origin + o = scene.viewport[].origin p2d = Point2f(o + Makie.project(scene, p3d)) # -10000 is an arbitrary weird constant that in preliminary testing didn't seem # to clip into plot objects anymore @@ -500,7 +458,7 @@ function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, tickno ticksize = attr(:ticksize) tick_segments = lift(topscene, limits, tickvalues, miv, min1, min2, - scene.camera.projectionview, scene.px_area, ticksize, xreversed, yreversed, zreversed) do lims, ticks, miv, min1, min2, + scene.camera.projectionview, scene.viewport, ticksize, xreversed, yreversed, zreversed) do lims, ticks, miv, min1, min2, pview, pxa, tsize, xrev, yrev, zrev rev1 = (xrev, yrev, zrev)[d1] @@ -540,7 +498,7 @@ function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, tickno # we are going to transform the 3d tick segments into 2d of the topscene # because otherwise they # be cut when they extend beyond the scene boundary - tick_segments_2dz = lift(topscene, tick_segments, scene.camera.projectionview, scene.px_area) do ts, _, _ + tick_segments_2dz = lift(topscene, tick_segments, scene.camera.projectionview, scene.viewport) do ts, _, _ map(ts) do p1_p2 to_topscene_z_2d.(p1_p2, Ref(scene)) end @@ -555,7 +513,7 @@ function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, tickno translate!(ticks, 0, 0, -10000) labels_positions = Observable{Any}() - map!(topscene, labels_positions, scene.px_area, scene.camera.projectionview, + map!(topscene, labels_positions, scene.viewport, scene.camera.projectionview, tick_segments, ticklabels, attr(:ticklabelpad)) do pxa, pv, ticksegs, ticklabs, pad o = pxa.origin @@ -591,7 +549,7 @@ function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, tickno label_align = Observable((:center, :top)) onany(topscene, - scene.px_area, scene.camera.projectionview, limits, miv, min1, min2, + scene.viewport, scene.camera.projectionview, limits, miv, min1, min2, attr(:labeloffset), attr(:labelrotation), attr(:labelalign), xreversed, yreversed, zreversed ) do pxa, pv, lims, miv, min1, min2, labeloffset, lrotation, lalign, xrev, yrev, zrev @@ -719,7 +677,7 @@ function add_panel!(scene, ax, dim1, dim2, dim3, limits, min3) faces = [1 2 3; 3 4 1] - panel = mesh!(scene, vertices, faces, shading = false, inspectable = false, + panel = mesh!(scene, vertices, faces, shading = NoShading, inspectable = false, xautolimits = false, yautolimits = false, zautolimits = false, color = attr(:panelcolor), visible = attr(:panelvisible)) return panel @@ -775,6 +733,12 @@ function hideydecorations!(ax::Axis3; ax end +""" + hidezdecorations!(ax::Axis3; label = true, ticklabels = true, ticks = true, grid = true) + +Hide decorations of the z-axis: label, ticklabels, ticks and grid. Keyword +arguments can be used to disable hiding of certain types of decorations. +""" function hidezdecorations!(ax::Axis3; label = true, ticklabels = true, ticks = true, grid = true) @@ -877,7 +841,7 @@ end function Makie.xlims!(ax::Axis3, xlims::Tuple{Union{Real, Nothing}, Union{Real, Nothing}}) if length(xlims) != 2 error("Invalid xlims length of $(length(xlims)), must be 2.") - elseif xlims[1] == xlims[2] + elseif xlims[1] == xlims[2] && xlims[1] !== nothing error("Can't set x limits to the same value $(xlims[1]).") elseif all(x -> x isa Real, xlims) && xlims[1] > xlims[2] xlims = reverse(xlims) @@ -885,8 +849,9 @@ function Makie.xlims!(ax::Axis3, xlims::Tuple{Union{Real, Nothing}, Union{Real, else ax.xreversed[] = false end + mlims = convert_limit_attribute(ax.limits[]) - ax.limits.val = (xlims, ax.limits[][2], ax.limits[][3]) + ax.limits.val = (xlims, mlims[2], mlims[3]) reset_limits!(ax, yauto = false, zauto = false) nothing end @@ -894,7 +859,7 @@ end function Makie.ylims!(ax::Axis3, ylims::Tuple{Union{Real, Nothing}, Union{Real, Nothing}}) if length(ylims) != 2 error("Invalid ylims length of $(length(ylims)), must be 2.") - elseif ylims[1] == ylims[2] + elseif ylims[1] == ylims[2] && ylims[1] !== nothing error("Can't set y limits to the same value $(ylims[1]).") elseif all(x -> x isa Real, ylims) && ylims[1] > ylims[2] ylims = reverse(ylims) @@ -902,8 +867,9 @@ function Makie.ylims!(ax::Axis3, ylims::Tuple{Union{Real, Nothing}, Union{Real, else ax.yreversed[] = false end + mlims = convert_limit_attribute(ax.limits[]) - ax.limits.val = (ax.limits[][1], ylims, ax.limits[][3]) + ax.limits.val = (mlims[1], ylims, mlims[3]) reset_limits!(ax, xauto = false, zauto = false) nothing end @@ -911,25 +877,26 @@ end function Makie.zlims!(ax::Axis3, zlims) if length(zlims) != 2 error("Invalid zlims length of $(length(zlims)), must be 2.") - elseif zlims[1] == zlims[2] - error("Can't set y limits to the same value $(zlims[1]).") + elseif zlims[1] == zlims[2] && zlims[1] !== nothing + error("Can't set z limits to the same value $(zlims[1]).") elseif all(x -> x isa Real, zlims) && zlims[1] > zlims[2] zlims = reverse(zlims) ax.zreversed[] = true else ax.zreversed[] = false end + mlims = convert_limit_attribute(ax.limits[]) - ax.limits.val = (ax.limits[][1], ax.limits[][2], zlims) + ax.limits.val = (mlims[1], mlims[2], zlims) reset_limits!(ax, xauto = false, yauto = false) nothing end """ - limits!(ax::Axis3, xlims, ylims) + limits!(ax::Axis3, xlims, ylims, zlims) -Set the axis limits to `xlims` and `ylims`. +Set the axis limits to `xlims`, `ylims`, and `zlims`. If limits are ordered high-low, this reverses the axis orientation. """ function limits!(ax::Axis3, xlims, ylims, zlims) @@ -941,7 +908,8 @@ end """ limits!(ax::Axis3, x1, x2, y1, y2, z1, z2) -Set the axis x-limits to `x1` and `x2` and the y-limits to `y1` and `y2`. +Set the axis x-limits to `x1` and `x2`, the y-limits to `y1` and `y2`, and the +z-limits to `z1` and `z2`. If limits are ordered high-low, this reverses the axis orientation. """ function limits!(ax::Axis3, x1, x2, y1, y2, z1, z2) @@ -1155,3 +1123,8 @@ function attribute_examples(::Type{Axis3}) ] ) end + + +# Axis interface + +tightlimits!(ax::Axis3) = nothing # TODO, not implemented yet diff --git a/src/makielayout/blocks/box.jl b/src/makielayout/blocks/box.jl index 11f9a115231..77dd49be62f 100644 --- a/src/makielayout/blocks/box.jl +++ b/src/makielayout/blocks/box.jl @@ -5,14 +5,108 @@ function initialize_block!(box::Box) vis ? col : RGBAf(0, 0, 0, 0) end - ibbox = lift(round_to_IRect2D, blockscene, box.layoutobservables.computedbbox) + path = lift(blockscene, box.layoutobservables.computedbbox, box.cornerradius) do bbox, r + if r == 0 + BezierPath([ + MoveTo(topright(bbox)), + LineTo(topleft(bbox)), + LineTo(bottomleft(bbox)), + LineTo(bottomright(bbox)), + ClosePath() + ]) + else + w, h = widths(bbox) + _max = min(w/2, h/2) + r1, r2, r3, r4 = r isa NTuple{4, Real} ? r : r isa Real ? (r, r, r, r) : throw(ArgumentError("Invalid cornerradius value $r. Must be a `Real` or a tuple with 4 `Real`s.")) - poly!(blockscene, ibbox, color = box.color, visible = box.visible, + r1, r2, r3, r4 = min.(_max, (r1, r2, r3, r4)) + BezierPath([ + MoveTo(bbox.origin + Point(w, h/2)), + EllipticalArc(topright(bbox) - Point2f(r1, r1), r1, r1, 0.0, 0, pi/2), + EllipticalArc(topleft(bbox) + Point2f(r4, -r4), r4, r4, 0.0, pi/2, pi), + EllipticalArc(bottomleft(bbox) + Point2f(r3, r3), r3, r3, 0.0, pi, 3/2 * pi), + EllipticalArc(bottomright(bbox) + Point2f(-r2, r2), r2, r2, 0.0, 3/2 * pi, 2pi), + ClosePath(), + ]) + end + end + + + + poly!(blockscene, path, color = box.color, visible = box.visible, strokecolor = strokecolor_with_visibility, strokewidth = box.strokewidth, - inspectable = false) + inspectable = false, linestyle = box.linestyle) # trigger bbox box.layoutobservables.suggestedbbox[] = box.layoutobservables.suggestedbbox[] return end + + +function attribute_examples(::Type{Box}) + Dict( + :color => [ + Example( + name = "Colors", + code = """ + fig = Figure() + Box(fig[1, 1], color = :red) + Box(fig[1, 2], color = (:red, 0.5)) + Box(fig[2, 1], color = RGBf(0.2, 0.5, 0.7)) + Box(fig[2, 2], color = RGBAf(0.2, 0.5, 0.7, 0.5)) + fig + """ + ) + ], + :strokecolor => [ + Example( + name = "Stroke colors", + code = """ + fig = Figure() + Box(fig[1, 1], strokecolor = :red) + Box(fig[1, 2], strokecolor = (:red, 0.5)) + Box(fig[2, 1], strokecolor = RGBf(0.2, 0.5, 0.7)) + Box(fig[2, 2], strokecolor = RGBAf(0.2, 0.5, 0.7, 0.5)) + fig + """ + ) + ], + :strokewidth => [ + Example( + name = "Stroke widths", + code = """ + fig = Figure() + Box(fig[1, 1], strokewidth = 1) + Box(fig[1, 2], strokewidth = 10) + Box(fig[1, 3], strokewidth = 0) + fig + """ + ) + ], + :linestyle => [ + Example( + name = "Stroke style", + code = """ + fig = Figure() + Box(fig[1, 1], linestyle = :solid) + Box(fig[1, 2], linestyle = :dot) + Box(fig[1, 3], linestyle = :dash) + fig + """ + ) + ], + :cornerradius => [ + Example( + name = "Corner radius", + code = """ + fig = Figure() + Box(fig[1, 1], cornerradius = 0) + Box(fig[1, 2], cornerradius = 20) + Box(fig[1, 3], cornerradius = (0, 10, 20, 30)) + fig + """ + ) + ], + ) +end \ No newline at end of file diff --git a/src/makielayout/blocks/colorbar.jl b/src/makielayout/blocks/colorbar.jl index 1330308e364..9032a15a888 100644 --- a/src/makielayout/blocks/colorbar.jl +++ b/src/makielayout/blocks/colorbar.jl @@ -25,6 +25,16 @@ function colorbar_check(keys, kwargs_keys) end end +function extract_colorrange(@nospecialize(plot::AbstractPlot))::Vec2{Float64} + if haskey(plot, :calculated_colors) && plot.calculated_colors[] isa Makie.ColorMapping + return plot.calculated_colors[].colorrange[] + elseif haskey(plot, :colorrange) && !(plot.colorrange[] isa Makie.Automatic) + return plot.colorrange[] + else + error("colorrange not found and calculated_colors for the plot is missing or is not a proper color map. Heatmaps and images should always contain calculated_colors[].colorrange") + end +end + function extract_colormap(@nospecialize(plot::AbstractPlot)) has_colorrange = haskey(plot, :colorrange) && !(plot.colorrange[] isa Makie.Automatic) if haskey(plot, :calculated_colors) && plot.calculated_colors[] isa Makie.ColorMapping @@ -47,7 +57,7 @@ function extract_colormap(plot::Union{Arrows, StreamPlot}) return extract_colormap(plot.plots[1]) end -function extract_colormap(plot::Combined{volumeslices}) +function extract_colormap(plot::Plot{volumeslices}) return extract_colormap(plot.plots[1]) end @@ -91,10 +101,10 @@ function Colorbar(fig_or_scene, plot::AbstractPlot; kwargs...) func = plotfunc(plot) if isnothing(cmap) error("Neither $(func) nor any of its children use a colormap. Cannot create a Colorbar from this plot, please create it manually. - If this is a recipe, one needs to overload `Makie.extract_colormap(::$(Combined{func}))` to allow for the automatical creation of a Colorbar.") + If this is a recipe, one needs to overload `Makie.extract_colormap(::$(Plot{func}))` to allow for the automatical creation of a Colorbar.") end if !(cmap isa ColorMapping) - error("extract_colormap(::$(Combined{func})) returned an invalid value: $cmap. Needs to return either a `Makie.ColorMapping`.") + error("extract_colormap(::$(Plot{func})) returned an invalid value: $cmap. Needs to return either a `Makie.ColorMapping`.") end if to_value(cmap.color) isa Union{AbstractVector{<: Colorant}, Colorant} @@ -243,7 +253,6 @@ function initialize_block!(cb::Colorbar) show_cats[] = true end end - heatmap!(blockscene, xrange, yrange, continous_pixels; colormap=colormap, @@ -251,7 +260,7 @@ function initialize_block!(cb::Colorbar) inspectable=false ) image!(blockscene, - lift(x-> LinRange(extrema(x)..., 2), xrange), lift(y-> LinRange(extrema(y)..., 2), yrange), continous_pixels; + lift(extrema, xrange), lift(extrema, yrange), continous_pixels; colormap = colormap, visible = show_continous, inspectable = false @@ -401,11 +410,13 @@ function initialize_block!(cb::Colorbar) # trigger protrusions with one of the attributes notify(cb.vertical) # We set everything via the ColorMapping now. To be backwards compatible, we always set those fields: - setfield!(cb, :limits, convert(Observable{Any}, limits)) - setfield!(cb, :colormap, convert(Observable{Any}, cmap.colormap)) - setfield!(cb, :highclip, convert(Observable{Any}, cmap.highclip)) - setfield!(cb, :lowclip, convert(Observable{Any}, cmap.lowclip)) - setfield!(cb, :scale, convert(Observable{Any}, cmap.scale)) + if (cb.colormap[] isa ColorMapping) + setfield!(cb, :limits, convert(Observable{Any}, limits)) + setfield!(cb, :colormap, convert(Observable{Any}, cmap.colormap)) + setfield!(cb, :highclip, convert(Observable{Any}, cmap.highclip)) + setfield!(cb, :lowclip, convert(Observable{Any}, cmap.lowclip)) + setfield!(cb, :scale, convert(Observable{Any}, cmap.scale)) + end # trigger bbox notify(cb.layoutobservables.suggestedbbox) notify(barbox) diff --git a/src/makielayout/blocks/intervalslider.jl b/src/makielayout/blocks/intervalslider.jl index d5e850ac059..01c456ca210 100644 --- a/src/makielayout/blocks/intervalslider.jl +++ b/src/makielayout/blocks/intervalslider.jl @@ -88,7 +88,7 @@ function initialize_block!(isl::IntervalSlider) end endbuttons = scatter!(blockscene, endpoints, color = endbuttoncolors, - markersize = isl.linewidth, strokewidth = 0, inspectable = false) + markersize = isl.linewidth, strokewidth = 0, inspectable = false, marker = Circle) linesegs = linesegments!(blockscene, linepoints, color = linecolors, linewidth = isl.linewidth, inspectable = false) @@ -107,7 +107,7 @@ function initialize_block!(isl::IntervalSlider) end buttonsizes = @lift($(isl.linewidth) .* $button_magnifications) buttons = scatter!(blockscene, middlepoints, color = isl.color_active, strokewidth = 0, - markersize = buttonsizes, inspectable = false) + markersize = buttonsizes, inspectable = false, marker = Circle) mouseevents = addmouseevents!(blockscene, isl.layoutobservables.computedbbox) diff --git a/src/makielayout/blocks/label.jl b/src/makielayout/blocks/label.jl index a755cc54e05..adc7de7fbc7 100644 --- a/src/makielayout/blocks/label.jl +++ b/src/makielayout/blocks/label.jl @@ -11,12 +11,13 @@ function initialize_block!(l::Label) t = text!( topscene, textpos, text = l.text, fontsize = l.fontsize, font = l.font, color = l.color, visible = l.visible, align = (:center, :center), rotation = l.rotation, markerspace = :data, - justification = l.justification, lineheight = l.lineheight, word_wrap_width = word_wrap_width, + justification = l.justification, lineheight = l.lineheight, word_wrap_width = word_wrap_width, inspectable = false) textbb = Ref(BBox(0, 1, 0, 1)) - onany(l.text, l.fontsize, l.font, l.rotation, word_wrap_width, l.padding) do _, _, _, _, _, padding + onany(topscene, l.text, l.fontsize, l.font, l.rotation, word_wrap_width, + l.padding) do _, _, _, _, _, padding textbb[] = Rect2f(boundingbox(t)) autowidth = width(textbb[]) + padding[1] + padding[2] autoheight = height(textbb[]) + padding[3] + padding[4] @@ -28,7 +29,7 @@ function initialize_block!(l::Label) return end - onany(layoutobservables.computedbbox, l.padding) do bbox, padding + onany(topscene, layoutobservables.computedbbox, l.padding) do bbox, padding if l.word_wrap[] tw = width(bbox) - padding[1] - padding[2] else diff --git a/src/makielayout/blocks/legend.jl b/src/makielayout/blocks/legend.jl index 8d995e774f6..8d9310f8ba4 100644 --- a/src/makielayout/blocks/legend.jl +++ b/src/makielayout/blocks/legend.jl @@ -1,6 +1,5 @@ -function initialize_block!(leg::Legend, - entry_groups::Observable{Vector{Tuple{Any, Vector{LegendEntry}}}}) - +function initialize_block!(leg::Legend; entrygroups) + entry_groups = convert(Observable{Vector{Tuple{Any,Vector{LegendEntry}}}}, entrygroups) blockscene = leg.blockscene # by default, `tellwidth = true` and `tellheight = false` for vertical legends @@ -12,16 +11,23 @@ function initialize_block!(leg::Legend, legend_area = lift(round_to_IRect2D, blockscene, leg.layoutobservables.computedbbox) - scene = Scene(blockscene, blockscene.px_area, camera = campixel!) + scene = Scene(blockscene, blockscene.viewport, camera = campixel!) # the rectangle in which the legend is drawn when margins are removed legendrect = lift(blockscene, legend_area, leg.margin) do la, lm enlarge(la, -lm[1], -lm[2], -lm[3], -lm[4]) end + backgroundcolor = if !isnothing(leg.bgcolor[]) + @warn("Keyword argument `bgcolor` is deprecated, use `backgroundcolor` instead.") + leg.bgcolor + else + leg.backgroundcolor + end + bg = poly!(scene, legendrect, - color = leg.bgcolor, strokewidth = leg.framewidth, visible = leg.framevisible, + color = backgroundcolor, strokewidth = leg.framewidth, visible = leg.framevisible, strokecolor = leg.framecolor, inspectable = false) translate!(bg, 0, 0, -7) # bg behind patches but before content at 0 (legend is at +10) @@ -461,7 +467,24 @@ function Base.propertynames(legendelement::T) where T <: LegendElement [fieldnames(T)..., keys(legendelement.attributes)...] end +function to_entry_group(legend_defaults, contents::AbstractVector, labels::AbstractVector, title=nothing) + if length(contents) != length(labels) + error("Number of elements not equal: $(length(contents)) content elements and $(length(labels)) labels.") + end + entries = [LegendEntry(label, content, legend_defaults) for (content, label) in zip(contents, labels)] + return [(title, entries)] +end +function to_entry_group( + legend_defaults, contentgroups::AbstractVector{<:AbstractVector}, + labelgroups::AbstractVector{<:AbstractVector}, titles::AbstractVector) + if !(length(titles) == length(contentgroups) == length(labelgroups)) + error("Number of elements not equal: $(length(titles)) titles, $(length(contentgroups)) content groups and $(length(labelgroups)) label groups.") + end + entries = [[LegendEntry(l, pg, legend_defaults) for (l, pg) in zip(labelgroup, contentgroup)] + for (labelgroup, contentgroup) in zip(labelgroups, contentgroups)] + return [(t, en) for (t, en) in zip(titles, entries)] +end """ Legend( @@ -480,17 +503,15 @@ function Legend(fig_or_scene, contents::AbstractVector, labels::AbstractVector, title = nothing; - kwargs...) - - if length(contents) != length(labels) - error("Number of elements not equal: $(length(contents)) content elements and $(length(labels)) labels.") - end + bbox=nothing, kwargs...) - entrygroups = Observable{Vector{EntryGroup}}([]) - legend = Legend(fig_or_scene, entrygroups; kwargs...) - entries = [LegendEntry(label, content, legend) for (content, label) in zip(contents, labels)] - entrygroups[] = [(title, entries)] - legend + scene = get_topscene(fig_or_scene) + legend_defaults = block_defaults(:Legend, Dict{Symbol, Any}(kwargs), scene) + entry_groups = to_entry_group(Attributes(legend_defaults), contents, labels, title) + entrygroups = Observable(entry_groups) + legend_defaults[:entrygroups] = entrygroups + # Use low-level constructor to not calculate legend_defaults a second time + return _block(Legend, fig_or_scene, (), legend_defaults, bbox; kwdict_complete=true) end @@ -515,19 +536,14 @@ function Legend(fig_or_scene, contentgroups::AbstractVector{<:AbstractVector}, labelgroups::AbstractVector{<:AbstractVector}, titles::AbstractVector; - kwargs...) + bbox=nothing, kwargs...) - if !(length(titles) == length(contentgroups) == length(labelgroups)) - error("Number of elements not equal: $(length(titles)) titles, $(length(contentgroups)) content groups and $(length(labelgroups)) label groups.") - end - - - entrygroups = Observable{Vector{EntryGroup}}([]) - legend = Legend(fig_or_scene, entrygroups; kwargs...) - entries = [[LegendEntry(l, pg, legend) for (l, pg) in zip(labelgroup, contentgroup)] - for (labelgroup, contentgroup) in zip(labelgroups, contentgroups)] - entrygroups[] = [(t, en) for (t, en) in zip(titles, entries)] - legend + scene = get_scene(fig_or_scene) + legend_defaults = block_defaults(:Legend, Dict{Symbol,Any}(kwargs), scene) + entry_groups = to_entry_group(legend_defaults, contentgroups, labelgroups, titles) + entrygroups = Observable(entry_groups) + legend_defaults[:entrygroups] = entrygroups + return _block(Legend, fig_or_scene, (), legend_defaults, bbox; kwdict_complete=true) end @@ -609,8 +625,8 @@ to one occurrence. """ function axislegend(ax, args...; position = :rt, kwargs...) Legend(ax.parent, args...; - bbox = ax.scene.px_area, - margin = (10, 10, 10, 10), + bbox = ax.scene.viewport, + margin = (6, 6, 6, 6), legend_position_to_aligns(position)..., kwargs...) end diff --git a/src/makielayout/blocks/menu.jl b/src/makielayout/blocks/menu.jl index d114ccb022a..a88471351ff 100644 --- a/src/makielayout/blocks/menu.jl +++ b/src/makielayout/blocks/menu.jl @@ -59,7 +59,7 @@ function initialize_block!(m::Menu; default = 1) map!(blockscene, _direction, m.layoutobservables.computedbbox, m.direction) do bb, dir if dir == Makie.automatic - pxa = pixelarea(blockscene)[] + pxa = viewport(blockscene)[] bottomspace = abs(bottom(pxa) - bottom(bb)) topspace = abs(top(pxa) - top(bb)) # slight preference for down @@ -81,7 +81,7 @@ function initialize_block!(m::Menu; default = 1) left(bbox), right(bbox), d === :down ? max(0, bottom(bbox) - h) : top(bbox), - d === :down ? bottom(bbox) : min(top(bbox) + h, top(blockscene.px_area[])))) + d === :down ? bottom(bbox) : min(top(bbox) + h, top(blockscene.viewport[])))) end menuscene = Scene(blockscene, scenearea, camera = campixel!, clear=true) @@ -256,7 +256,7 @@ function initialize_block!(m::Menu; default = 1) m.is_open[] = !m.is_open[] if m.is_open[] t = translation(menuscene)[] - y_for_top_align = height(menuscene.px_area[]) - listheight[] + y_for_top_align = height(menuscene.viewport[]) - listheight[] translate!(menuscene, t[1], y_for_top_align, t[3]) end return Consume(true) @@ -295,7 +295,7 @@ function initialize_block!(m::Menu; default = 1) t = translation(menuscene)[] # Hack to differentiate mousewheel and trackpad scrolling step = m.scroll_speed[] * y - new_y = max(min(t[2] - step, 0), height(menuscene.px_area[]) - listheight[]) + new_y = max(min(t[2] - step, 0), height(menuscene.viewport[]) - listheight[]) translate!(menuscene, t[1], new_y, t[3]) return Consume(true) else @@ -330,7 +330,7 @@ function initialize_block!(m::Menu; default = 1) end dropdown_arrow = scatter!( blockscene, symbol_pos; - marker=lift(iso -> iso ? '▴' : '▾', blockscene, m.is_open), + marker=lift(iso -> iso ? :utriangle : :dtriangle, blockscene, m.is_open), markersize = m.dropdown_arrow_size, color = m.dropdown_arrow_color, strokecolor = :transparent, diff --git a/src/makielayout/blocks/polaraxis.jl b/src/makielayout/blocks/polaraxis.jl index 805b473c596..40dbcb9db5f 100644 --- a/src/makielayout/blocks/polaraxis.jl +++ b/src/makielayout/blocks/polaraxis.jl @@ -2,9 +2,6 @@ ### Main Block Intialization ################################################################################ - -can_be_current_axis(ax::PolarAxis) = true - function initialize_block!(po::PolarAxis; palette=nothing) # Setup Scenes cb = po.layoutobservables.computedbbox @@ -22,29 +19,26 @@ function initialize_block!(po::PolarAxis; palette=nothing) transformation = Transformation(po.scene, transform_func = identity) ) - - # Setup Cycler - po.cycler = Cycler() - if palette === nothing - palette = fast_deepcopy(get(po.blockscene.theme, :palette, DEFAULT_PALETTES)) + if !isnothing(palette) + # Backwards compatibility for when palette was part of axis! + palette_attr = palette isa Attributes ? palette : Attributes(palette) + po.scene.theme.palette = palette_attr end - po.palette = palette isa Attributes ? palette : Attributes(palette) - # Setup camera/limits and Polar transform - usable_fraction, radius_at_origin = setup_camera_matrices!(po) + usable_fraction = setup_camera_matrices!(po) Observables.connect!( po.scene.transformation.transform_func, - @lift(Polar($(po.theta_as_x), $(po.target_theta_0), $(po.direction), $(radius_at_origin))) + @lift(Polar($(po.target_theta_0), $(po.direction), $(po.target_r0), $(po.theta_as_x), $(po.clip_r))) ) Observables.connect!( po.overlay.transformation.transform_func, - @lift(Polar(false, $(po.target_theta_0), $(po.direction))) + @lift(Polar($(po.target_theta_0), $(po.direction), 0.0, false)) ) # Draw clip, grid lines, spine, ticks - rticklabelplot, thetaticklabelplot = draw_axis!(po, radius_at_origin) + rticklabelplot, thetaticklabelplot = draw_axis!(po) # Calculate fraction of screen usable after reserving space for theta ticks # TODO: Should we include rticks here? @@ -59,7 +53,7 @@ function initialize_block!(po::PolarAxis; palette=nothing) thetaticklabelplot.plots[1].fontsize, thetaticklabelplot.plots[1].font, po.thetaticklabelpad, - po.overlay.px_area + po.overlay.viewport ) do _, _, _, rpad, _, _, _, tpad, area # get maximum size of tick label @@ -90,7 +84,7 @@ function initialize_block!(po::PolarAxis; palette=nothing) po.target_rlims, po.target_thetalims, po.target_theta_0, po.direction, po.rticklabelsize, po.rticklabelpad, po.thetaticklabelsize, po.thetaticklabelpad, - po.overlay.px_area, po.overlay.camera.projectionview, + po.overlay.viewport, po.overlay.camera.projectionview, po.titlegap, po.titlesize, po.titlealign ) do rlims, thetalims, theta_0, dir, r_fs, r_pad, t_fs, t_pad, area, pv, gap, size, align @@ -219,21 +213,17 @@ function setup_camera_matrices!(po::PolarAxis) setfield!(po, :target_rlims, Observable{Tuple{Float64, Float64}}((0.0, 10.0))) setfield!(po, :target_thetalims, Observable{Tuple{Float64, Float64}}((0.0, 2pi))) setfield!(po, :target_theta_0, map(identity, po.theta_0)) + setfield!(po, :target_r0, Observable{Float32}(po.radius_at_origin[] isa Real ? po.radius_at_origin[] : 0f0)) reset_limits!(po) onany((_, _) -> reset_limits!(po), po.blockscene, po.rlimits, po.thetalimits) - # To keep the inner clip radius below a certain fraction of the outer clip - # radius we map all r > r0 to 0. This computes that r0. - radius_at_origin = map(po.blockscene, po.target_rlims, po.radial_distortion_threshold) do (rmin, rmax), max_fraction - # max_fraction = (rmin - r0) / (rmax - r0) solved for r0 - return max(0.0, (rmin - max_fraction * rmax) / (1 - max_fraction)) - end - # get cartesian bbox defined by axis limits - # OPT: target_radius update triggers radius_at_origin update - data_bbox = map(po.blockscene, po.target_thetalims, radius_at_origin, po.direction, po.target_theta_0) do tlims, ro, dir, t0 - return polaraxis_bbox(po.target_rlims[], tlims, ro, dir, t0) - end + data_bbox = map( + polaraxis_bbox, + po.blockscene, + po.target_rlims, po.target_thetalims, + po.target_r0, po.direction, po.target_theta_0 + ) # fit data_bbox into the usable area of PolarAxis (i.e. with tick space subtracted) onany(po.blockscene, usable_fraction, data_bbox) do usable_fraction, bb @@ -245,9 +235,10 @@ function setup_camera_matrices!(po::PolarAxis) end # same as above, but with rmax scaled to 1 + # OPT: data_bbox triggers on target_r0, target_rlims updates onany(po.blockscene, usable_fraction, data_bbox) do usable_fraction, bb mini = minimum(bb); ws = widths(bb) - rmax = po.target_rlims[][2] - radius_at_origin[] # both update data_bbox + rmax = po.target_rlims[][2] - po.target_r0[] scale = minimum(2usable_fraction ./ ws) trans = to_ndim(Vec3f, -scale .* (mini .+ 0.5ws), 0) scale *= rmax @@ -258,14 +249,14 @@ function setup_camera_matrices!(po::PolarAxis) # update projection matrices # this just aspect-aware clip space (-1 .. 1, -h/w ... h/w, -max_z ... max_z) - on(po.blockscene, po.scene.px_area) do area + on(po.blockscene, po.scene.viewport) do area aspect = Float32((/)(widths(area)...)) w = 1f0 h = 1f0 / aspect camera(po.scene).projection[] = orthographicprojection(-w, w, -h, h, -max_z, max_z) end - on(po.blockscene, po.overlay.px_area) do area + on(po.blockscene, po.overlay.viewport) do area aspect = Float32((/)(widths(area)...)) w = 1f0 h = 1f0 / aspect @@ -386,7 +377,7 @@ function setup_camera_matrices!(po::PolarAxis) on(po.blockscene, e.mouseposition) do _ if drag_state[][3] - w = widths(po.scene.px_area[]) + w = widths(po.scene) p0 = (last_px_pos[] .- 0.5w) ./ w p1 = Point2f(mouseposition_px(po.scene) .- 0.5w) ./ w if norm(p0) * norm(p1) < 1e-6 @@ -466,12 +457,16 @@ function setup_camera_matrices!(po::PolarAxis) return Consume(false) end - return usable_fraction, radius_at_origin + return usable_fraction end function reset_limits!(po::PolarAxis) + # Resolve automatic as origin + rmin_to_origin = po.rlimits[][1] === :origin + rlimits = ifelse.(rmin_to_origin, nothing, po.rlimits[]) + # at least one derived limit - if any(isnothing, po.rlimits[]) || any(isnothing, po.thetalimits[]) + if any(isnothing, rlimits) || any(isnothing, po.thetalimits[]) if !isempty(po.scene.plots) # TODO: Why does this include child scenes by default? @@ -486,13 +481,28 @@ function reset_limits!(po::PolarAxis) rmax, thetamax = maximum(lims2d) end - # cleanup autolimits (0 width, negative rmin) + # Determine automatic target_r0 + if po.radius_at_origin[] isa Real + po.target_r0[] = po.radius_at_origin[] + else + po.target_r0[] = min(0.0, rmin) + end + + # cleanup autolimits (0 width, rmin ≥ target_r0) if rmin == rmax - rmin = max(0.0, rmin - 5.0) + if rmin_to_origin + rmin = po.target_r0[] + else + rmin = max(po.target_r0[], rmin - 5.0) + end rmax = rmin + 10.0 else dr = rmax - rmin - rmin = max(0.0, rmin - po.rautolimitmargin[][1] * dr) + if rmin_to_origin + rmin = po.target_r0[] + else + rmin = max(po.target_r0[], rmin - po.rautolimitmargin[][1] * dr) + end rmax += po.rautolimitmargin[][2] * dr end @@ -512,11 +522,11 @@ function reset_limits!(po::PolarAxis) end # apply - po.target_rlims[] = ifelse.(isnothing.(po.rlimits[]), (rmin, rmax), po.rlimits[]) + po.target_rlims[] = ifelse.(isnothing.(rlimits), (rmin, rmax), rlimits) po.target_thetalims[] = ifelse.(isnothing.(po.thetalimits[]), (thetamin, thetamax), po.thetalimits[]) else # all limits set - if po.target_rlims[] != po.rlimits[] - po.target_rlims[] = po.rlimits[] + if po.target_rlims[] != rlimits + po.target_rlims[] = rlimits end if po.target_thetalims[] != po.thetalimits[] po.target_thetalims[] = po.thetalimits[] @@ -543,7 +553,7 @@ function _polar_clip_polygon( return [Polygon(exterior, [interior])] end -function draw_axis!(po::PolarAxis, radius_at_origin) +function draw_axis!(po::PolarAxis) rtick_pos_lbl = Observable{Vector{<:Tuple{AbstractString, Point2f}}}() rtick_align = Observable{Point2f}() rtick_offset = Observable{Point2f}() @@ -563,19 +573,17 @@ function draw_axis!(po::PolarAxis, radius_at_origin) end end - # OPT: target_radius update triggers radius_at_origin update onany( po.blockscene, po.rticks, po.rminorticks, po.rtickformat, po.rtickangle, - po.direction, po.target_thetalims, po.sample_density, radius_at_origin + po.direction, po.target_rlims, po.target_thetalims, po.sample_density, po.target_r0 ) do rticks, rminorticks, rtickformat, rtickangle, - dir, thetalims, sample_density, radius_at_origin + dir, rlims, thetalims, sample_density, target_r0 # For text: - rlims = po.target_rlims[] - rmaxinv = 1.0 / (rlims[2] - radius_at_origin) + rmaxinv = 1.0 / (rlims[2] - target_r0) _rtickvalues, _rticklabels = get_ticks(rticks, identity, rtickformat, rlims...) - _rtickradius = (_rtickvalues .- radius_at_origin) .* rmaxinv + _rtickradius = (_rtickvalues .- target_r0) .* rmaxinv _rtickangle = default_rtickangle(rtickangle, dir, thetalims) rtick_pos_lbl[] = tuple.(_rticklabels, Point2f.(_rtickradius, _rtickangle)) @@ -584,7 +592,7 @@ function draw_axis!(po::PolarAxis, radius_at_origin) rgridpoints[] = GeometryBasics.LineString.([Point2f.(r, thetas) for r in _rtickradius]) _rminortickvalues = get_minor_tickvalues(rminorticks, identity, _rtickvalues, rlims...) - _rminortickvalues .= (_rminortickvalues .- radius_at_origin) .* rmaxinv + _rminortickvalues .= (_rminortickvalues .- target_r0) .* rmaxinv rminorgridpoints[] = GeometryBasics.LineString.([Point2f.(r, thetas) for r in _rminortickvalues]) return @@ -631,8 +639,8 @@ function draw_axis!(po::PolarAxis, radius_at_origin) onany( po.blockscene, po.thetaticks, po.thetaminorticks, po.thetatickformat, po.thetaticklabelpad, - po.direction, po.target_theta_0, po.target_rlims, po.target_thetalims, po.radial_distortion_threshold - ) do thetaticks, thetaminorticks, thetatickformat, px_pad, dir, theta_0, rlims, thetalims, max_clip + po.direction, po.target_theta_0, po.target_rlims, po.target_thetalims, po.target_r0 + ) do thetaticks, thetaminorticks, thetatickformat, px_pad, dir, theta_0, rlims, thetalims, r0 _thetatickvalues, _thetaticklabels = get_ticks(thetaticks, identity, thetatickformat, thetalims...) @@ -658,7 +666,7 @@ function draw_axis!(po::PolarAxis, radius_at_origin) thetatick_pos_lbl[] = tuple.(_thetaticklabels, Point2f.(1, _thetatickvalues)) # Grid lines - rmin = min(rlims[1] / rlims[2], max_clip) + rmin = (rlims[1] - r0) / (rlims[2] - r0) thetagridpoints[] = [Point2f(r, theta) for theta in _thetatickvalues for r in (rmin, 1)] _thetaminortickvalues = get_minor_tickvalues(thetaminorticks, identity, _thetatickvalues, thetalims...) @@ -769,7 +777,7 @@ function draw_axis!(po::PolarAxis, radius_at_origin) visible = po.clip, fxaa = false, transformation = Transformation(), # no polar transform for this - shading = false + shading = NoShading ) # inner clip is a (filled) circle sector which also needs to regenerate with @@ -791,7 +799,7 @@ function draw_axis!(po::PolarAxis, radius_at_origin) visible = po.clip, fxaa = false, transformation = Transformation(), - shading = false + shading = NoShading ) # handle placement with transform @@ -801,19 +809,19 @@ function draw_axis!(po::PolarAxis, radius_at_origin) rotate!.((outer_clip_plot, inner_clip_plot), (Vec3f(0,0,1),), angle) end - onany(po.blockscene, po.target_rlims, po.radial_distortion_threshold) do lims, maxclip - s = min(lims[1] / lims[2], maxclip) + onany(po.blockscene, po.target_rlims, po.target_r0) do lims, r0 + s = (lims[1] - r0) / (lims[2] - r0) scale!(inner_clip_plot, Vec3f(s, s, 1)) end - notify(po.radial_distortion_threshold) + notify(po.target_r0) # spine traces circle sector - inner circle spine_points = map(po.blockscene, - po.target_rlims, po.target_thetalims, po.radial_distortion_threshold, po.sample_density - ) do (rmin, rmax), thetalims, max_clip, N + po.target_rlims, po.target_thetalims, po.target_r0, po.sample_density + ) do (rmin, rmax), thetalims, r0, N thetamin, thetamax = thetalims - rmin = min(rmin/rmax, max_clip) + rmin = (rmin - r0) / (rmax - r0) rmax = 1.0 # make sure we have 2+ points per arc @@ -857,48 +865,13 @@ function draw_axis!(po::PolarAxis, radius_at_origin) return rticklabelplot, thetaticklabelplot end - -################################################################################ -### Plotting -################################################################################ - -# TODO: consider enabling this -# needs_tight_limits(::Surface) = true - -function plot!( - po::PolarAxis, P::PlotFunc, - attributes::Attributes, args...; - kw_attributes...) - - allattrs = merge(attributes, Attributes(kw_attributes)) - - cycle = get_cycle_for_plottype(allattrs, P) - add_cycle_attributes!(allattrs, P, cycle, po.cycler, po.palette) - - plot = plot!(po.scene, P, allattrs, args...) - - needs_tight_limits(plot) && tightlimits!(po) - - if is_open_or_any_parent(po.scene) - reset_limits!(po) - end - - plot -end - - -function plot!(P::PlotFunc, po::PolarAxis, args...; kw_attributes...) - attributes = Attributes(kw_attributes) - plot!(po, P, attributes, args...) -end - -delete!(ax::PolarAxis, p::AbstractPlot) = delete!(ax.scene, p) - function update_state_before_display!(ax::PolarAxis) reset_limits!(ax) return end +delete!(ax::PolarAxis, p::AbstractPlot) = delete!(ax.scene, p) + ################################################################################ ### Utilities ################################################################################ @@ -947,9 +920,9 @@ end Sets the radial limits of a given `PolarAxis`. """ -rlims!(po::PolarAxis, r::Union{Nothing, Real}) = rlims!(po, po.rlimits[][1], r) +rlims!(po::PolarAxis, r::Union{Symbol, Nothing, Real}) = rlims!(po, po.rlimits[][1], r) -function rlims!(po::PolarAxis, rmin::Union{Nothing, Real}, rmax::Union{Nothing, Real}) +function rlims!(po::PolarAxis, rmin::Union{Symbol, Nothing, Real}, rmax::Union{Nothing, Real}) po.rlimits[] = (rmin, rmax) return end diff --git a/src/makielayout/blocks/scene.jl b/src/makielayout/blocks/scene.jl index 8ecbad040c6..e5cac177b0f 100644 --- a/src/makielayout/blocks/scene.jl +++ b/src/makielayout/blocks/scene.jl @@ -1,20 +1,9 @@ -function Makie.plot!( - lscene::LScene, P::Makie.PlotFunc, - attributes::Makie.Attributes, args...; - kw_attributes...) - - plot = Makie.plot!(lscene.scene, P, attributes, args...; kw_attributes...) +function reset_limits!(lscene::LScene) notify(lscene.scene.theme.limits) center!(lscene.scene) - plot -end - -function Makie.plot!(P::Makie.PlotFunc, ls::LScene, args...; kw_attributes...) - attributes = Makie.Attributes(kw_attributes) - _disallow_keyword(:axis, attributes) - _disallow_keyword(:figure, attributes) - Makie.plot!(ls, P, attributes, args...) + return end +tightlimits!(::LScene) = nothing # TODO implement!? function initialize_block!(ls::LScene; scenekw = NamedTuple()) blockscene = ls.blockscene @@ -61,8 +50,6 @@ function Base.delete!(ax::LScene, plot::AbstractPlot) ax end -can_be_current_axis(ls::LScene) = true - Makie.cam2d!(ax::LScene; kwargs...) = Makie.cam2d!(ax.scene; kwargs...) Makie.campixel!(ax::LScene; kwargs...) = Makie.campixel!(ax.scene; kwargs...) Makie.cam_relative!(ax::LScene; kwargs...) = Makie.cam_relative!(ax.scene; kwargs...) diff --git a/src/makielayout/blocks/textbox.jl b/src/makielayout/blocks/textbox.jl index 761ae53cd28..f679c7a9222 100644 --- a/src/makielayout/blocks/textbox.jl +++ b/src/makielayout/blocks/textbox.jl @@ -99,7 +99,7 @@ function initialize_block!(tbox::Textbox) end end - cursor = linesegments!(scene, cursorpoints, color = tbox.cursorcolor, linewidth = 2, inspectable = false) + cursor = linesegments!(scene, cursorpoints, color = tbox.cursorcolor, linewidth = 1, inspectable = false) tbox.cursoranimtask = nothing diff --git a/src/makielayout/helpers.jl b/src/makielayout/helpers.jl index 378d067f231..2732f804cc9 100644 --- a/src/makielayout/helpers.jl +++ b/src/makielayout/helpers.jl @@ -138,7 +138,7 @@ function tightlimits!(la::Axis, ::Top) end function GridLayoutBase.GridLayout(scene::Scene, args...; kwargs...) - return GridLayout(args...; bbox=lift(Rect2f, pixelarea(scene)), kwargs...) + return GridLayout(args...; bbox=lift(Rect2f, viewport(scene)), kwargs...) end function axislines!(scene, rect, spinewidth, topspinevisible, rightspinevisible, diff --git a/src/makielayout/interactions.jl b/src/makielayout/interactions.jl index 505b9d8c247..3945f0ba86e 100644 --- a/src/makielayout/interactions.jl +++ b/src/makielayout/interactions.jl @@ -123,7 +123,7 @@ end function _selection_vertices(ax_scene, outer, inner) _clamp(p, plow, phigh) = Point2f(clamp(p[1], plow[1], phigh[1]), clamp(p[2], plow[2], phigh[2])) - proj(point) = project(ax_scene, point) .+ minimum(ax_scene.px_area[]) + proj(point) = project(ax_scene, point) .+ minimum(ax_scene.viewport[]) transf = Makie.transform_func(ax_scene) outer = positivize(Makie.apply_transform(transf, outer)) inner = positivize(Makie.apply_transform(transf, inner)) @@ -242,7 +242,7 @@ function process_interaction(s::ScrollZoom, event::ScrollEvent, ax::Axis) cam = camera(scene) if zoom != 0 - pa = pixelarea(scene)[] + pa = viewport(scene)[] z = (1f0 - s.speed)^zoom @@ -305,7 +305,7 @@ function process_interaction(dp::DragPan, event::MouseEvent, ax) scene = ax.scene cam = camera(scene) - pa = pixelarea(scene)[] + pa = viewport(scene)[] mp_axscene = Vec4f((event.px .- pa.origin)..., 0, 1) mp_axscene_prev = Vec4f((event.prev_px .- pa.origin)..., 0, 1) diff --git a/src/makielayout/lineaxis.jl b/src/makielayout/lineaxis.jl index 2e0a41122b8..38ec8004042 100644 --- a/src/makielayout/lineaxis.jl +++ b/src/makielayout/lineaxis.jl @@ -1,3 +1,8 @@ +# the hyphen which is usually used to store negative number strings +# is shorter than the dedicated minus in most fonts, the minus glyph +# looks more balanced with numbers, especially in superscripts or subscripts +const MINUS_SIGN = "−" # == "\u2212" (Unicode minus) + function LineAxis(parent::Scene; @nospecialize(kwargs...)) attrs = merge!(Attributes(kwargs), generic_plot_attributes(LineAxis)) return LineAxis(parent, attrs) @@ -78,8 +83,8 @@ function create_linepoints( return [from, to] else x = position - pstart = Point2f(-0.5f0 * tickwidth, 0) - pend = Point2f(0.5f0 * tickwidth, 0) + pstart = Point2f(0, -0.5f0 * tickwidth) + pend = Point2f(0, 0.5f0 * tickwidth) from = trimspine[1] ? tickpositions[1] .+ pstart : Point2f(x, extents_oriented[1] - 0.5spine_width) to = trimspine[2] ? tickpositions[end] .+ pend : Point2f(x, extents_oriented[2] + 0.5spine_width) return [from, to] @@ -600,7 +605,7 @@ function get_ticks(l::LogTicks, scale::LogFunctions, ::Automatic, vmin, vmax) xs -> Showoff.showoff(xs, :plain), ticks_scaled ) - labels = rich.(_logbase(scale), superscript.(labels_scaled, offset = Vec2f(0.1f0, 0f0))) + labels = rich.(_logbase(scale), superscript.(replace.(labels_scaled, "-" => MINUS_SIGN), offset = Vec2f(0.1f0, 0f0))) ticks, labels end @@ -663,9 +668,9 @@ end """ get_ticklabels(::Automatic, values) -Gets tick labels by applying `showoff` to `values`. +Gets tick labels by applying `showoff_minus` to `values`. """ -get_ticklabels(::Automatic, values) = Showoff.showoff(values) +get_ticklabels(::Automatic, values) = showoff_minus(values) """ get_ticklabels(formatfunction::Function, values) @@ -686,7 +691,7 @@ function get_ticks(m::MultiplesTicks, any_scale, ::Automatic, vmin, vmax) dvmax = vmax / m.multiple multiples = Makie.get_tickvalues(LinearTicks(m.n_ideal), dvmin, dvmax) - multiples .* m.multiple, Showoff.showoff(multiples) .* m.suffix + multiples .* m.multiple, showoff_minus(multiples) .* m.suffix end function get_ticks(m::AngularTicks, any_scale, ::Automatic, vmin, vmax) @@ -718,7 +723,13 @@ function get_ticks(m::AngularTicks, any_scale, ::Automatic, vmin, vmax) # We also need to be careful that we don't remove significant digits sigdigits = ceil(Int, log10(1000 * max(abs(vmin), abs(vmax)) / delta)) - return multiples, Showoff.showoff(round.(multiples .* m.label_factor, sigdigits = sigdigits)) .* m.suffix + return multiples, showoff_minus(round.(multiples .* m.label_factor, sigdigits = sigdigits)) .* m.suffix +end + +# Replaces hyphens in negative numbers with the unicode MINUS_SIGN +function showoff_minus(x::AbstractVector) + # TODO: don't use the `replace` workaround + replace.(Showoff.showoff(x), r"-(?=\d)" => MINUS_SIGN) end # identity or unsupported scales diff --git a/src/makielayout/mousestatemachine.jl b/src/makielayout/mousestatemachine.jl index 472db916485..c7fe0ddadd1 100644 --- a/src/makielayout/mousestatemachine.jl +++ b/src/makielayout/mousestatemachine.jl @@ -3,27 +3,35 @@ module MouseEventTypes out enter over + leftdown rightdown middledown + leftup rightup middleup + leftdragstart rightdragstart middledragstart + leftdrag rightdrag middledrag + leftdragstop rightdragstop middledragstop + leftclick rightclick middleclick + leftdoubleclick rightdoubleclick middledoubleclick + downoutside end export MouseEventType @@ -125,6 +133,58 @@ end # don't react to buttons beyond the first three _isstandardmousebutton(b) = (b == Mouse.left || b == Mouse.middle || b == Mouse.right) +# TODO +# Make these enums so we can just do `Mouse.left & Mouse.drag` + +function to_drag_event(b::Mouse.Button) + b === Mouse.left && return MouseEventTypes.leftdrag + b === Mouse.right && return MouseEventTypes.rightdrag + b === Mouse.middle && return MouseEventTypes.middledrag + error("No recognized mouse button $b") +end + +function to_drag_start_event(b::Mouse.Button) + b === Mouse.left && return MouseEventTypes.leftdragstart + b === Mouse.right && return MouseEventTypes.rightdragstart + b === Mouse.middle && return MouseEventTypes.middledragstart + return error("No recognized mouse button $b") +end + +function to_drag_stop_event(b::Mouse.Button) + b === Mouse.left && return MouseEventTypes.leftdragstop + b === Mouse.right && return MouseEventTypes.rightdragstop + b === Mouse.middle && return MouseEventTypes.middledragstop + return error("No recognized mouse button $b") +end + +function to_down_event(b::Mouse.Button) + b === Mouse.left && return MouseEventTypes.leftdown + b === Mouse.right && return MouseEventTypes.rightdown + b === Mouse.middle && return MouseEventTypes.middledown + return error("No recognized mouse button $b") +end + +function to_up_event(b::Mouse.Button) + b === Mouse.left && return MouseEventTypes.leftup + b === Mouse.right && return MouseEventTypes.rightup + b === Mouse.middle && return MouseEventTypes.middleup + return error("No recognized mouse button $b") +end + +function to_doubleclick_event(b::Mouse.Button) + b === Mouse.left && return MouseEventTypes.leftdoubleclick + b === Mouse.right && return MouseEventTypes.rightdoubleclick + b === Mouse.middle && return MouseEventTypes.middledoubleclick + return error("No recognized mouse button $b") +end + +function to_click_event(b::Mouse.Button) + b === Mouse.left && return MouseEventTypes.leftclick + b === Mouse.right && return MouseEventTypes.rightclick + b === Mouse.middle && return MouseEventTypes.middleclick + return error("No recognized mouse button $b") +end + function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) Mouse = Makie.Mouse dblclick_max_interval = 0.2 @@ -163,12 +223,7 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) if drag_ongoing[] # continue the drag - event = @match mouse_downed_button[] begin - Mouse.left => MouseEventTypes.leftdrag - Mouse.right => MouseEventTypes.rightdrag - Mouse.middle => MouseEventTypes.middledrag - x => error("No recognized mouse button $x") - end + event = to_drag_event(mouse_downed_button[]) x = setindex!(mouseevent, MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) ) @@ -178,23 +233,13 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) # that means a drag started if mouse_downed_inside[] drag_ongoing[] = true - event = @match mouse_downed_button[] begin - Mouse.left => MouseEventTypes.leftdragstart - Mouse.right => MouseEventTypes.rightdragstart - Mouse.middle => MouseEventTypes.middledragstart - x => error("No recognized mouse button $x") - end + event = to_drag_start_event(mouse_downed_button[]) x = setindex!(mouseevent, MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) ) consumed = consumed || x - event = @match mouse_downed_button[] begin - Mouse.left => MouseEventTypes.leftdrag - Mouse.right => MouseEventTypes.rightdrag - Mouse.middle => MouseEventTypes.middledrag - x => error("No recognized mouse button $x") - end + event = to_drag_event(mouse_downed_button[]) x = setindex!(mouseevent, MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) ) @@ -250,12 +295,7 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) mouse_downed_button[] = button if mouse_was_inside[] - event = @match mouse_downed_button[] begin - Mouse.left => MouseEventTypes.leftdown - Mouse.right => MouseEventTypes.rightdown - Mouse.middle => MouseEventTypes.middledown - x => error("No recognized mouse button $x") - end + event = to_down_event(mouse_downed_button[]) x = setindex!(mouseevent, MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) ) @@ -281,12 +321,7 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) if downed_button_missing_from_pressed && some_mouse_button_had_been_downed if drag_ongoing[] - event = @match mouse_downed_button[] begin - Mouse.left => MouseEventTypes.leftdragstop - Mouse.right => MouseEventTypes.rightdragstop - Mouse.middle => MouseEventTypes.middledragstop - x => error("No recognized mouse button $x") - end + event = to_drag_stop_event(mouse_downed_button[]) x = setindex!(mouseevent, MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) ) @@ -295,13 +330,7 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) if mouse_was_inside[] # up after drag done over element - event = @match mouse_downed_button[] begin - Mouse.left => MouseEventTypes.leftup - Mouse.right => MouseEventTypes.rightup - Mouse.middle => MouseEventTypes.middleup - x => error("No recognized mouse button $x") - end - + event = to_up_event(mouse_downed_button[]) x = setindex!(mouseevent, MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) ) @@ -323,24 +352,14 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) if dt_last_click < dblclick_max_interval && !last_click_was_double[] && mouse_downed_button[] == b_last_click[] - event = @match mouse_downed_button[] begin - Mouse.left => MouseEventTypes.leftdoubleclick - Mouse.right => MouseEventTypes.rightdoubleclick - Mouse.middle => MouseEventTypes.middledoubleclick - x => error("No recognized mouse button $x") - end + event = to_doubleclick_event(mouse_downed_button[]) x = setindex!(mouseevent, MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) ) consumed = consumed || x last_click_was_double[] = true else - event = @match mouse_downed_button[] begin - Mouse.left => MouseEventTypes.leftclick - Mouse.right => MouseEventTypes.rightclick - Mouse.middle => MouseEventTypes.middleclick - x => error("No recognized mouse button $x") - end + event = to_click_event(mouse_downed_button[]) x = setindex!(mouseevent, MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) ) @@ -353,13 +372,7 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) mouse_downed_inside[] = false # up after click - event = @match mouse_downed_button[] begin - Mouse.left => MouseEventTypes.leftup - Mouse.right => MouseEventTypes.rightup - Mouse.middle => MouseEventTypes.middleup - x => error("No recognized mouse button $x") - end - + event = to_up_event(mouse_downed_button[]) x = setindex!(mouseevent, MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) ) diff --git a/src/makielayout/types.jl b/src/makielayout/types.jl index 0c7a0c02dde..477bdf61b38 100644 --- a/src/makielayout/types.jl +++ b/src/makielayout/types.jl @@ -8,14 +8,6 @@ end struct DataAspect end - -struct Cycler - counters::IdDict{Type, Int} -end - -Cycler() = Cycler(IdDict{Type, Int}()) - - struct Cycle cycle::Vector{Pair{Vector{Symbol}, Symbol}} covary::Bool @@ -205,14 +197,12 @@ struct KeysEvent keys::Set{Makie.Keyboard.Button} end -@Block Axis begin +@Block Axis <: AbstractAxis begin scene::Scene xaxislinks::Vector{Axis} yaxislinks::Vector{Axis} targetlimits::Observable{Rect2f} finallimits::Observable{Rect2f} - cycler::Cycler - palette::Attributes block_limit_linking::Observable{Bool} mouseeventhandle::MouseEventHandle scrollevents::Observable{ScrollEvent} @@ -330,9 +320,9 @@ end "The horizontal and vertical alignment of the yticklabels." yticklabelalign::Union{Makie.Automatic, Tuple{Symbol, Symbol}} = Makie.automatic "The size of the xtick marks." - xticksize::Float64 = 6f0 + xticksize::Float64 = 5f0 "The size of the ytick marks." - yticksize::Float64 = 6f0 + yticksize::Float64 = 5f0 "Controls if the xtick marks are visible." xticksvisible::Bool = true "Controls if the ytick marks are visible." @@ -589,7 +579,7 @@ end "The alignment of x minor ticks on the axis spine" xminortickalign::Float64 = 0f0 "The tick size of x minor ticks" - xminorticksize::Float64 = 4f0 + xminorticksize::Float64 = 3f0 "The tick width of x minor ticks" xminortickwidth::Float64 = 1f0 "The tick color of x minor ticks" @@ -608,7 +598,7 @@ end "The alignment of y minor ticks on the axis spine" yminortickalign::Float64 = 0f0 "The tick size of y minor ticks" - yminorticksize::Float64 = 4f0 + yminorticksize::Float64 = 3f0 "The tick width of y minor ticks" yminortickwidth::Float64 = 1f0 "The tick color of y minor ticks" @@ -671,7 +661,7 @@ function RectangleZoom(f::Function, ax::Axis; kw...) faces = [1 2 5; 5 2 6; 2 3 6; 6 3 7; 3 4 7; 7 4 8; 4 1 8; 8 1 5] # plot to blockscene, so ax.scene stays exclusive for user plots # That's also why we need to pass `ax.scene` to _selection_vertices, so it can project to that space - mesh = mesh!(ax.blockscene, selection_vertices, faces, color = (:black, 0.2), shading = false, + mesh = mesh!(ax.blockscene, selection_vertices, faces, color = (:black, 0.2), shading = NoShading, inspectable = false, visible=r.active, transparency=true) # translate forward so selection mesh and frame are never behind data translate!(mesh, 0, 0, 100) @@ -713,7 +703,7 @@ end "The color of the tick labels." ticklabelcolor = @inherit(:textcolor, :black) "The size of the tick marks." - ticksize = 6f0 + ticksize = 5f0 "Controls if the tick marks are visible." ticksvisible = true "The ticks." @@ -795,7 +785,7 @@ end "The alignment of minor ticks on the axis spine" minortickalign = 0f0 "The tick size of minor ticks" - minorticksize = 4f0 + minorticksize = 3f0 "The tick width of minor ticks" minortickwidth = 1f0 "The tick color of minor ticks" @@ -803,7 +793,7 @@ end "The tick locator for the minor ticks" minorticks = IntervalsBetween(5) "The width or height of the colorbar, depending on if it's vertical or horizontal, unless overridden by `width` / `height`" - size = 16 + size = 12 end end @@ -856,14 +846,16 @@ end valign = :center "The horizontal alignment of the rectangle in its suggested boundingbox" halign = :center - "The extra space added to the sides of the rectangle boundingbox." - padding = (0f0, 0f0, 0f0, 0f0) "The line width of the rectangle's border." strokewidth = 1f0 "Controls if the border of the rectangle is visible." strokevisible = true "The color of the border." strokecolor = RGBf(0, 0, 0) + "The linestyle of the rectangle border" + linestyle = nothing + "The radius of the rounded corner. One number is for all four corners, four numbers for going clockwise from top-right." + cornerradius = 0.0 "The width setting of the rectangle." width = nothing "The height setting of the rectangle." @@ -899,7 +891,7 @@ end "The current value of the slider. Don't set this manually, use the function `set_close_to!`." value = 0 "The width of the slider line" - linewidth::Float32 = 15 + linewidth::Float32 = 10 "The color of the slider when the mouse hovers over it." color_active_dimmed::RGBAf = COLOR_ACCENT_DIMMED[] "The color of the slider when the mouse clicks and drags the slider." @@ -963,7 +955,7 @@ end "The current interval of the slider. Don't set this manually, use the function `set_close_to!`." interval = (0, 0) "The width of the slider line" - linewidth::Float64 = 15.0 + linewidth::Float64 = 10.0 "The color of the slider when the mouse hovers over it." color_active_dimmed::RGBAf = COLOR_ACCENT_DIMMED[] "The color of the slider when the mouse clicks and drags the slider." @@ -986,7 +978,7 @@ end "The vertical alignment of the button in its suggested boundingbox" valign = :center "The extra space added to the sides of the button label's boundingbox." - padding = (10f0, 10f0, 10f0, 10f0) + padding = (8f0, 8f0, 8f0, 8f0) "The font size of the button label." fontsize = @inherit(:fontsize, 16f0) "The text of the button label." @@ -1035,9 +1027,9 @@ end "The vertical alignment of the toggle in its suggested bounding box." valign = :center "The width of the toggle." - width = 60 + width = 32 "The height of the toggle." - height = 28 + height = 18 "Controls if the parent layout can adjust to this element's width" tellwidth = true "Controls if the parent layout can adjust to this element's height" @@ -1099,13 +1091,13 @@ end "Color of the dropdown arrow" dropdown_arrow_color = (:black, 0.2) "Size of the dropdown arrow" - dropdown_arrow_size = 20 + dropdown_arrow_size = 10 "The list of options selectable in the menu. This can be any iterable of a mixture of strings and containers with one string and one other value. If an entry is just a string, that string is both label and selection. If an entry is a container with one string and one other value, the string is the label and the other value is the selection." options = ["no options"] "Font size of the cell texts" fontsize = @inherit(:fontsize, 16f0) "Padding of entry texts" - textpadding = (10, 10, 10, 10) + textpadding = (8, 10, 8, 8) "Color of entry texts" textcolor = :black "The opening direction of the menu (:up or :down)" @@ -1184,11 +1176,13 @@ const EntryGroup = Tuple{Any, Vector{LegendEntry}} "The vertical alignment of the entry labels." labelvalign = :center "The additional space between the legend content and the border." - padding = (10f0, 10f0, 8f0, 8f0) + padding = (6f0, 6f0, 6f0, 6f0) "The additional space between the legend and its suggested boundingbox." margin = (0f0, 0f0, 0f0, 0f0) + "The background color of the legend. DEPRECATED - use `backgroundcolor` instead." + bgcolor = nothing "The background color of the legend." - bgcolor = :white + backgroundcolor = :white "The color of the legend border." framecolor = :black "The line width of the legend border." @@ -1256,7 +1250,7 @@ const EntryGroup = Tuple{Any, Vector{LegendEntry}} end end -@Block LScene begin +@Block LScene <: AbstractAxis begin scene::Scene @attributes begin "The height setting of the scene." @@ -1331,13 +1325,13 @@ end "Color of the box border when focused and invalid." bordercolor_focused_invalid = RGBf(1, 0, 0) "Width of the box border." - borderwidth = 2f0 + borderwidth = 1f0 "Padding of the text against the box." - textpadding = (10, 10, 10, 10) + textpadding = (8, 8, 8, 8) "If the textbox is focused and receives text input." focused = false "Corner radius of text box." - cornerradius = 8 + cornerradius = 5 "Corner segments of one rounded corner." cornersegments = 20 "Validator that is called with validate_textbox(string, validator) to determine if the current string is valid. Can by default be a RegEx that needs to match the complete string, or a function taking a string as input and returning a Bool. If the validator is a type T (for example Float64), validation will be `tryparse(string, T)`." @@ -1349,15 +1343,13 @@ end end end -@Block Axis3 begin +@Block Axis3 <: AbstractAxis begin scene::Scene finallimits::Observable{Rect3f} mouseeventhandle::MouseEventHandle scrollevents::Observable{ScrollEvent} keysevents::Observable{KeysEvent} interactions::Dict{Symbol, Tuple{Bool, Any}} - cycler::Cycler - palette::Attributes @attributes begin "The height setting of the scene." height = nothing @@ -1638,14 +1630,13 @@ end end end -@Block PolarAxis begin +@Block PolarAxis <: AbstractAxis begin scene::Scene overlay::Scene target_rlims::Observable{Tuple{Float64, Float64}} target_thetalims::Observable{Tuple{Float64, Float64}} target_theta_0::Observable{Float32} - cycler::Cycler - palette::Attributes + target_r0::Observable{Float32} @attributes begin # Generic @@ -1674,21 +1665,23 @@ end clip::Bool = true "Sets the color of the clip polygon. Mainly for debug purposes." clipcolor = automatic - "Sets a threshold relative to `rmin/rmax` after which radii are distorted to fit more on the screen. No distortion is applied if `radial_distortion_threshold ≥ 1`" - radial_distortion_threshold::Float64 = 1.0 # Limits & transformation settings - "The radial limits of the PolarAxis." - rlimits = (0.0, nothing) + "The radial limits of the PolarAxis. " + rlimits = (:origin, nothing) "The angle limits of the PolarAxis. (0.0, 2pi) results a full circle. (nothing, nothing) results in limits picked based on plot limits." thetalimits = (0.0, 2pi) "The direction of rotation. Can be -1 (clockwise) or 1 (counterclockwise)." direction::Int = 1 "The angular offset for (1, 0) in the PolarAxis. This rotates the axis." theta_0::Float32 = 0f0 + "Sets the radius at the origin of the PolarAxis such that `r_out = r_in - radius_at_origin`. Can be set to `automatic` to match rmin. Note that this will affect the shape of plotted objects." + radius_at_origin = automatic "Controls the argument order of the Polar transform. If `theta_as_x = true` it is (θ, r), otherwise (r, θ)." theta_as_x::Bool = true + "Controls whether `r < 0` (after applying `radius_at_origin`) gets clipped (true) or not (false)." + clip_r::Bool = true "The relative margins added to the autolimits in r direction." rautolimitmargin::Tuple{Float64, Float64} = (0.05, 0.05) "The relative margins added to the autolimits in theta direction." diff --git a/src/precompiles.jl b/src/precompiles.jl index 7b71d31148d..1ed6f3e0054 100644 --- a/src/precompiles.jl +++ b/src/precompiles.jl @@ -44,3 +44,11 @@ for T in (DragPan, RectangleZoom, LimitReset) end precompile(process_axis_event, (Axis, MouseEvent)) precompile(process_interaction, (ScrollZoom, ScrollEvent, Axis)) +precompile(el32convert, (Vector{Int64},)) +precompile(translate, (MoveTo, Vec2{Float64})) +precompile(scale, (MoveTo, Vec{2,Float32})) +precompile(append!, (Vector{FreeType.FT_Vector_}, Vector{FreeType.FT_Vector_})) +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})) diff --git a/src/recording.jl b/src/recording.jl index 18cc72b0d6f..a06999a8251 100644 --- a/src/recording.jl +++ b/src/recording.jl @@ -27,13 +27,19 @@ mutable struct RamStepper end function Stepper(figlike::FigureLike; backend=current_backend(), format=:png, visible=false, connect=false, screen_kw...) - screen = getscreen(backend, get_scene(figlike), JuliaNative; visible=visible, start_renderloop=false, screen_kw...) + config = Dict{Symbol,Any}(screen_kw) + get!(config, :visible, visible) + get!(config, :start_renderloop, false) + screen = getscreen(backend, get_scene(figlike), config, JuliaNative) display(screen, figlike; connect=connect) return RamStepper(figlike, screen, Matrix{RGBf}[], format) end function Stepper(figlike::FigureLike, path::String, step::Int; format=:png, backend=current_backend(), visible=false, connect=false, screen_kw...) - screen = getscreen(backend, get_scene(figlike), JuliaNative; visible=visible, start_renderloop=false, screen_kw...) + config = Dict{Symbol,Any}(screen_kw) + get!(config, :visible, visible) + get!(config, :start_renderloop, false) + screen = getscreen(backend, get_scene(figlike), config, JuliaNative) display(screen, figlike; connect=connect) return FolderStepper(figlike, screen, path, format, step) end diff --git a/src/scenes.jl b/src/scenes.jl index 319286b993d..cf4a5b65b06 100644 --- a/src/scenes.jl +++ b/src/scenes.jl @@ -37,33 +37,6 @@ function SSAO(; radius=nothing, bias=nothing, blur=nothing) return SSAO(_radius, _bias, _blur) end -abstract type AbstractLight end - -""" -A positional point light, shining at a certain color. -Color values can be bigger than 1 for brighter lights. -""" -struct PointLight <: AbstractLight - position::Observable{Vec3f} - radiance::Observable{RGBf} -end - -""" -An environment Light, that uses a spherical environment map to provide lighting. -See: https://en.wikipedia.org/wiki/Reflection_mapping -""" -struct EnvironmentLight <: AbstractLight - intensity::Observable{Float32} - image::Observable{Matrix{RGBf}} -end - -""" -A simple, one color ambient light. -""" -struct AmbientLight <: AbstractLight - color::Observable{RGBf} -end - """ Scene TODO document this @@ -81,7 +54,7 @@ mutable struct Scene <: AbstractScene events::Events "The current pixel area of the Scene." - px_area::Observable{Rect2i} + viewport::Observable{Rect2i} "Whether the scene should be cleared." clear::Observable{Bool} @@ -114,11 +87,12 @@ mutable struct Scene <: AbstractScene ssao::SSAO lights::Vector{AbstractLight} deregister_callbacks::Vector{Observables.ObserverFunction} + cycler::Cycler function Scene( parent::Union{Nothing, Scene}, events::Events, - px_area::Observable{Rect2i}, + viewport::Observable{Rect2i}, clear::Observable{Bool}, camera::Camera, camera_controls::AbstractCamera, @@ -130,12 +104,12 @@ mutable struct Scene <: AbstractScene backgroundcolor::Observable{RGBAf}, visible::Observable{Bool}, ssao::SSAO, - lights::Vector{AbstractLight} + lights::Vector ) scene = new( parent, events, - px_area, + viewport, clear, camera, camera_controls, @@ -147,8 +121,9 @@ mutable struct Scene <: AbstractScene backgroundcolor, visible, ssao, - lights, - Observables.ObserverFunction[] + convert(Vector{AbstractLight}, lights), + Observables.ObserverFunction[], + Cycler() ) finalizer(free, scene) return scene @@ -156,19 +131,19 @@ mutable struct Scene <: AbstractScene end # on & map versions that deregister when scene closes! -function Observables.on(f, scene::Union{Combined,Scene}, observable::Observable; update=false, priority=0) - to_deregister = on(f, observable; update=update, priority=priority) - push!(scene.deregister_callbacks, to_deregister) +function Observables.on(@nospecialize(f), @nospecialize(scene::Union{Plot,Scene}), @nospecialize(observable::Observable); update=false, priority=0) + to_deregister = on(f, observable; update=update, priority=priority)::Observables.ObserverFunction + push!(scene.deregister_callbacks::Vector{Observables.ObserverFunction}, to_deregister) return to_deregister end -function Observables.onany(f, scene::Union{Combined,Scene}, observables...; priority=0) - to_deregister = onany(f, observables...; priority=priority) - append!(scene.deregister_callbacks, to_deregister) +function Observables.onany(@nospecialize(f), @nospecialize(scene::Union{Plot,Scene}), @nospecialize(observables...); update=false, priority=0) + to_deregister = onany(f, observables...; priority=priority, update=update) + append!(scene.deregister_callbacks::Vector{Observables.ObserverFunction}, to_deregister) return to_deregister end -@inline function Base.map!(@nospecialize(f), scene::Union{Combined,Scene}, result::AbstractObservable, os...; +@inline function Base.map!(f, @nospecialize(scene::Union{Plot,Scene}), result::AbstractObservable, os...; update::Bool=true, priority = 0) # note: the @inline prevents de-specialization due to the splatting callback = Observables.MapCallback(f, result, os) @@ -179,7 +154,7 @@ end return result end -@inline function Base.map(f::F, scene::Union{Combined,Scene}, arg1::AbstractObservable, args...; +@inline function Base.map(f::F, @nospecialize(scene::Union{Plot,Scene}), arg1::AbstractObservable, args...; ignore_equal_values=false, priority = 0) where {F} # note: the @inline prevents de-specialization due to the splatting obs = Observable(f(arg1[], map(Observables.to_value, args)...); ignore_equal_values=ignore_equal_values) @@ -216,7 +191,7 @@ function Base.show(io::IO, scene::Scene) end function Scene(; - px_area::Union{Observable{Rect2i}, Nothing} = nothing, + viewport::Union{Observable{Rect2i}, Nothing} = nothing, events::Events = Events(), clear::Union{Automatic, Observable{Bool}, Bool} = automatic, transform_func=identity, @@ -239,12 +214,18 @@ function Scene(; bg = Observable{RGBAf}(to_color(m_theme.backgroundcolor[]); ignore_equal_values=true) - wasnothing = isnothing(px_area) + wasnothing = isnothing(viewport) if wasnothing - px_area = Observable(Recti(0, 0, m_theme.resolution[]); ignore_equal_values=true) + sz = if haskey(m_theme, :resolution) + @warn "Found `resolution` in the theme when creating a `Scene`. The `resolution` keyword for `Scene`s and `Figure`s has been deprecated. Use `Figure(; size = ...` or `Scene(; size = ...)` instead, which better reflects that this is a unitless size and not a pixel resolution. The key could also come from `set_theme!` calls or related theming functions." + m_theme.resolution[] + else + m_theme.size[] + end + viewport = Observable(Recti(0, 0, sz); ignore_equal_values=true) end - cam = camera isa Camera ? camera : Camera(px_area) + cam = camera isa Camera ? camera : Camera(viewport) _lights = lights isa Automatic ? AbstractLight[] : lights # if we have an opaque background, automatically set clear to true! @@ -254,7 +235,7 @@ function Scene(; clear = convert(Observable{Bool}, clear) end scene = Scene( - parent, events, px_area, clear, cam, camera_controls, + parent, events, viewport, clear, cam, camera_controls, transformation, plots, m_theme, children, current_screens, bg, visible, ssao, _lights ) @@ -262,51 +243,46 @@ function Scene(; if wasnothing on(events.window_area, priority = typemax(Int)) do w_area - if !any(x -> x ≈ 0.0, widths(w_area)) && px_area[] != w_area - px_area[] = w_area + if !any(x -> x ≈ 0.0, widths(w_area)) && viewport[] != w_area + viewport[] = w_area end return Consume(false) end end if lights isa Automatic - lightposition = to_value(get(m_theme, :lightposition, nothing)) - if !isnothing(lightposition) - position = if lightposition === :eyeposition - scene.camera.eyeposition - elseif lightposition isa Vec3 - m_theme.lightposition - else - error("Wrong lightposition type, use `:eyeposition` or `Vec3f(...)`") + haskey(m_theme, :lightposition) && @warn("`lightposition` is deprecated. Set `light_direction` instead.") + + if haskey(m_theme, :lights) + copyto!(scene.lights, m_theme.lights[]) + else + haskey(m_theme, :light_direction) || error("Theme must contain `light_direction::Vec3f` or an explicit `lights::Vector`!") + haskey(m_theme, :light_color) || error("Theme must contain `light_color::RGBf` or an explicit `lights::Vector`!") + haskey(m_theme, :camera_relative_light) || @warn("Theme should contain `camera_relative_light::Bool`.") + + if haskey(m_theme, :ambient) + push!(scene.lights, AmbientLight(m_theme[:ambient][])) end - push!(scene.lights, PointLight(position, RGBf(1, 1, 1))) - end - ambient = to_value(get(m_theme, :ambient, nothing)) - if !isnothing(ambient) - push!(scene.lights, AmbientLight(ambient)) + + push!(scene.lights, DirectionalLight( + m_theme[:light_color][], m_theme[:light_direction], + to_value(get(m_theme, :camera_relative_light, false)) + )) end end return scene end -function get_one_light(scene::Scene, Typ) - indices = findall(x-> x isa Typ, scene.lights) - isempty(indices) && return nothing - if length(indices) > 1 - @warn("Only one light supported by backend right now. Using only first light") - end - return scene.lights[indices[1]] -end - -get_point_light(scene::Scene) = get_one_light(scene, PointLight) -get_ambient_light(scene::Scene) = get_one_light(scene, AmbientLight) - +get_directional_light(scene::Scene) = get_one_light(scene.lights, DirectionalLight) +get_point_light(scene::Scene) = get_one_light(scene.lights, PointLight) +get_ambient_light(scene::Scene) = get_one_light(scene.lights, AmbientLight) +default_shading!(plot, scene::Scene) = default_shading!(plot, scene.lights) function Scene( parent::Scene; events=parent.events, - px_area=nothing, + viewport=nothing, clear=false, camera=nothing, camera_controls=parent.camera_controls, @@ -317,10 +293,10 @@ function Scene( if camera !== parent.camera camera_controls = EmptyCamera() end - child_px_area = px_area isa Observable ? px_area : Observable(Rect2i(0, 0, 0, 0); ignore_equal_values=true) + child_px_area = viewport isa Observable ? viewport : Observable(Rect2i(0, 0, 0, 0); ignore_equal_values=true) child = Scene(; events=events, - px_area=child_px_area, + viewport=child_px_area, clear=convert(Observable{Bool}, clear), camera=camera, camera_controls=camera_controls, @@ -330,13 +306,13 @@ function Scene( theme=theme(parent), kw... ) - if isnothing(px_area) - map!(identity, child, child_px_area, parent.px_area) - elseif px_area isa Rect2 - child_px_area[] = Rect2i(px_area) + if isnothing(viewport) + map!(identity, child, child_px_area, parent.viewport) + elseif viewport isa Rect2 + child_px_area[] = Rect2i(viewport) else - if !(px_area isa Observable) - error("px_area must be an Observable{Rect2} or a Rect2") + if !(viewport isa Observable) + error("viewport must be an Observable{Rect2} or a Rect2") end end push!(parent.children, child) @@ -346,7 +322,7 @@ end # legacy constructor function Scene(parent::Scene, area; kw...) - return Scene(parent; px_area=area, kw...) + return Scene(parent; viewport=area, kw...) end # Base overloads for Scene @@ -363,16 +339,17 @@ function root(scene::Scene) end parent_or_self(scene::Scene) = isroot(scene) ? scene : parent(scene) -GeometryBasics.widths(scene::Scene) = widths(to_value(pixelarea(scene))) +GeometryBasics.widths(scene::Scene) = widths(to_value(viewport(scene))) Base.size(scene::Scene) = Tuple(widths(scene)) Base.size(x::Scene, i) = size(x)[i] + function Base.resize!(scene::Scene, xy::Tuple{Number,Number}) resize!(scene, Recti(0, 0, xy)) end Base.resize!(scene::Scene, x::Number, y::Number) = resize!(scene, (x, y)) function Base.resize!(scene::Scene, rect::Rect2) - pixelarea(scene)[] = rect + viewport(scene)[] = rect if isroot(scene) for screen in scene.current_screens resize!(screen, widths(rect)...) @@ -423,7 +400,7 @@ end function free(scene::Scene) empty!(scene; free=true) - for field in [:backgroundcolor, :px_area, :visible] + for field in [:backgroundcolor, :viewport, :visible] Observables.clear(getfield(scene, field)) end for screen in copy(scene.current_screens) @@ -465,20 +442,22 @@ function Base.empty!(scene::Scene; free=false) return nothing end +function Base.push!(plot::Plot, subplot) + subplot.parent = plot + push!(plot.plots, subplot) +end -Base.push!(scene::Combined, subscene) = nothing # Combined plots add themselves uppon creation - -function Base.push!(scene::Scene, plot::AbstractPlot) +function Base.push!(scene::Scene, @nospecialize(plot::AbstractPlot)) push!(scene.plots, plot) - plot isa Combined || (plot.parent[] = scene) for screen in scene.current_screens - insert!(screen, scene, plot) + Base.invokelatest(insert!, screen, scene, plot) end end function Base.delete!(screen::MakieScreen, ::Scene, ::AbstractPlot) - @warn "Deleting plots not implemented for backend: $(typeof(screen))" + @debug "Deleting plots not implemented for backend: $(typeof(screen))" end + function Base.delete!(screen::MakieScreen, ::Scene) # This may not be necessary for every backed @debug "Deleting scenes not implemented for backend: $(typeof(screen))" @@ -488,6 +467,9 @@ function free(plot::AbstractPlot) for f in plot.deregister_callbacks Observables.off(f) end + for arg in plot.args + Observables.clear(arg) + end foreach(free, plot.plots) empty!(plot.plots) empty!(plot.deregister_callbacks) @@ -508,21 +490,6 @@ function Base.delete!(scene::Scene, plot::AbstractPlot) free(plot) end -function Base.push!(scene::Scene, child::Scene) - push!(scene.children, child) - disconnect!(child.camera) - observables = map([:view, :projection, :projectionview, :resolution, :eyeposition]) do field - return lift(getfield(scene.camera, field)) do val - getfield(child.camera, field)[] = val - getfield(child.camera, field)[] = val - return - end - end - cameracontrols!(child, observables) - child.parent = scene - return scene -end - events(x) = events(get_scene(x)) events(scene::Scene) = scene.events events(scene::SceneLike) = events(scene.parent) @@ -542,9 +509,14 @@ end cameracontrols!(scene::SceneLike, cam) = cameracontrols!(parent(scene), cam) cameracontrols!(x, cam) = cameracontrols!(get_scene(x), cam) -pixelarea(x) = pixelarea(get_scene(x)) -pixelarea(scene::Scene) = scene.px_area -pixelarea(scene::SceneLike) = pixelarea(scene.parent) +viewport(x) = viewport(get_scene(x)) +""" + viewport(scene::Scene) + +Gets the viewport of the scene in device independent units as an `Observable{Rect2{Int}}`. +""" +viewport(scene::Scene) = scene.viewport +viewport(scene::SceneLike) = viewport(scene.parent) plots(x) = plots(get_scene(x)) plots(scene::SceneLike) = scene.plots @@ -562,7 +534,7 @@ function plots_from_camera(scene::Scene, camera::Camera, list=AbstractPlot[]) end -function insertplots!(screen::AbstractDisplay, scene::Scene) +function insertplots!(@nospecialize(screen::AbstractDisplay), scene::Scene) for elem in scene.plots insert!(screen, scene, elem) end @@ -587,7 +559,7 @@ function center!(scene::Scene, padding=0.01, exclude = not_in_data_space) end parent_scene(x) = parent_scene(get_scene(x)) -parent_scene(x::Combined) = parent_scene(parent(x)) +parent_scene(x::Plot) = parent_scene(parent(x)) parent_scene(x::Scene) = x Base.isopen(x::SceneLike) = events(x).window_open[] @@ -627,22 +599,22 @@ end const FigureLike = Union{Scene, Figure, FigureAxisPlot} """ - is_atomic_plot(plot::Combined) + is_atomic_plot(plot::Plot) Defines what Makie considers an atomic plot, used in `collect_atomic_plots`. Backends may have a different definition of what is considered an atomic plot, but instead of overloading this function, they should create their own definition and pass it to `collect_atomic_plots` """ -is_atomic_plot(plot::Combined) = isempty(plot.plots) +is_atomic_plot(plot::Plot) = isempty(plot.plots) """ collect_atomic_plots(scene::Scene, plots = AbstractPlot[]; is_atomic_plot = is_atomic_plot) - collect_atomic_plots(x::Combined, plots = AbstractPlot[]; is_atomic_plot = is_atomic_plot) + collect_atomic_plots(x::Plot, plots = AbstractPlot[]; is_atomic_plot = is_atomic_plot) Collects all plots in the provided `<: ScenePlot` and returns a vector of all plots which satisfy `is_atomic_plot`, which defaults to Makie's definition of `Makie.is_atomic_plot`. """ -function collect_atomic_plots(xplot::Combined, plots=AbstractPlot[]; is_atomic_plot=is_atomic_plot) +function collect_atomic_plots(xplot::Plot, plots=AbstractPlot[]; is_atomic_plot=is_atomic_plot) if is_atomic_plot(xplot) # Atomic plot! push!(plots, xplot) @@ -666,5 +638,3 @@ function collect_atomic_plots(scene::Scene, plots=AbstractPlot[]; is_atomic_plot collect_atomic_plots(scene.children, plots; is_atomic_plot=is_atomic_plot) plots end - -Base.@deprecate flatten_plots(scenelike) collect_atomic_plots(scenelike) diff --git a/src/specapi.jl b/src/specapi.jl new file mode 100644 index 00000000000..fe6eec19b61 --- /dev/null +++ b/src/specapi.jl @@ -0,0 +1,742 @@ + +using GridLayoutBase: GridLayoutBase + +import GridLayoutBase: GridPosition, Side, ContentSize, GapSize, AlignMode, Inner, GridLayout, GridSubposition + + +function get_recipe_function(name::Symbol) + if hasproperty(Makie, name) + return getfield(Makie, name) + else + return nothing + end +end + +@nospecialize +""" + PlotSpec(plottype, args...; kwargs...) + +Object encoding positional arguments (`args`), a `NamedTuple` of attributes (`kwargs`) +as well as plot type `P` of a basic plot. +""" +struct PlotSpec + type::Symbol + args::Vector{Any} + kwargs::Dict{Symbol, Any} + function PlotSpec(type::Symbol, args...; kwargs...) + type_str = string(type) + if type_str[end] == '!' + error("PlotSpec objects are supposed to be used without !, unless when using `S.$(type)(axis::P.Axis, args...; kwargs...)`") + end + if !isuppercase(type_str[1]) + func = get_recipe_function(type) + func === nothing && error("PlotSpec need to be existing recipes or Makie plot objects. Found: $(type_str)") + plot_type = Plot{func} + type = plotsym(plot_type) + @warn("PlotSpec objects are supposed to be title case. Found: $(type_str). Please use $(type) instead.") + end + kw = Dict{Symbol,Any}() + for (k, v) in kwargs + # convert eagerly, so that we have stable types for matching later + # E.g. so that PlotSpec(; color = :red) has the same type as PlotSpec(; color = RGBA(1, 0, 0, 1)) + if v isa Cycled # special case for conversions needing a scene + kw[k] = v + elseif v isa Observable + error("PlotSpec are supposed to be used without Observables") + else + try + # Really unfortunate! + # Recipes don't have convert_attribute + # (e.g. band(...; color=:y)) + # So on error we don't convert for now via try catch + # Since we also dont have an API to figure out if a convert is defined correctly + # TODO, I think we can do this more elegantly but will need a bit of a convert_attribute refactor + kw[k] = convert_attribute(v, Key{k}(), Key{type}()) + catch e + kw[k] = v + end + end + end + return new(type, Any[args...], kw) + end + PlotSpec(args...; kwargs...) = new(:plot, args...; kwargs...) +end +@specialize + +Base.getindex(p::PlotSpec, i::Int) = getindex(p.args, i) +Base.getindex(p::PlotSpec, i::Symbol) = getproperty(p.kwargs, i) + +to_plotspec(::Type{P}, args; kwargs...) where {P} = PlotSpec(plotsym(P), args...; kwargs...) + +function to_plotspec(::Type{P}, p::PlotSpec; kwargs...) where {P} + S = plottype(p) + return PlotSpec(plotsym(plottype(P, S)), p.args...; p.kwargs..., kwargs...) +end + +plottype(p::PlotSpec) = getfield(Makie, p.type) + +struct BlockSpec + type::Symbol # Type as :Scatter, :BarPlot + kwargs::Dict{Symbol,Any} + plots::Vector{PlotSpec} +end + +function BlockSpec(typ::Symbol, args...; plots::Vector{PlotSpec}=PlotSpec[], kw...) + attr = Dict{Symbol,Any}(kw) + if typ == :Legend + # TODO, this is hacky and works around the fact, + # that legend gets its legend elements from the positional arguments + # But we can only update them via legend.entrygroups + defaults = block_defaults(:Legend, attr, nothing) + entrygroups = to_entry_group(Attributes(defaults), args...) + attr[:entrygroups] = entrygroups + return BlockSpec(typ, attr, plots) + else + if !isempty(args) + error("BlockSpecs, with an exception for Legend, don't support positional arguments yet.") + end + return BlockSpec(typ, attr, plots) + end +end + +const GridLayoutPosition = Tuple{UnitRange{Int},UnitRange{Int},Side} + +to_span(range::UnitRange{Int}, span::UnitRange{Int}) = (range.start < span.start || range.stop > span.stop) ? error("Range $range not completely covered by spanning range $span.") : range +to_span(range::Int, span::UnitRange{Int}) = (range < span.start || range > span.stop) ? error("Range $range not completely covered by spanning range $span.") : range:range +to_span(::Colon, span::UnitRange{Int}) = span +to_gridposition(rows_cols::Tuple{Any,Any}, rowspan, colspan) = to_gridposition((rows_cols..., Inner()), rowspan, colspan) +to_gridposition(rows_cols_side::Tuple{Any,Any,Any}, rowspan, colspan) = (to_span(rows_cols_side[1], rowspan), to_span(rows_cols_side[2], colspan), rows_cols_side[3]) + +rangeunion(r1, r2::UnitRange) = min(r1.start, r2.start):max(r1.stop, r2.stop) +rangeunion(r1, r2::Int) = min(r1.start, r2):max(r1.stop, r2) +rangeunion(r1, r2::Colon) = r1 + +struct GridLayoutSpec + content::Vector{Pair{GridLayoutPosition,Union{GridLayoutSpec,BlockSpec}}} + + size::Tuple{Int, Int} + offsets::Tuple{Int, Int} + + colsizes::Vector{ContentSize} + rowsizes::Vector{ContentSize} + colgaps::Vector{GapSize} + rowgaps::Vector{GapSize} + alignmode::AlignMode + tellheight::Bool + tellwidth::Bool + halign::Float64 + valign::Float64 + + function GridLayoutSpec( + content::AbstractVector{<:Pair}; + colsizes = nothing, + rowsizes = nothing, + colgaps = nothing, + rowgaps = nothing, + alignmode::AlignMode = GridLayoutBase.Inside(), + tellheight::Bool = true, + tellwidth::Bool = true, + halign::Union{Symbol,Real} = :center, + valign::Union{Symbol,Real} = :center, + ) + + rowspan, colspan = foldl(content; init = (1:1, 1:1)) do (rows, cols), ((_rows, _cols, _...), _) + rangeunion(rows, _rows), rangeunion(cols, _cols) + end + + content = map(content) do (position, x) + p = Pair{GridLayoutPosition,Union{GridLayoutSpec,BlockSpec}}(to_gridposition(position, rowspan, colspan), x) + return p + end + + nrows = length(rowspan) + ncols = length(colspan) + colsizes = GridLayoutBase.convert_contentsizes(ncols, colsizes) + rowsizes = GridLayoutBase.convert_contentsizes(nrows, rowsizes) + default_rowgap = Fixed(16) # TODO: where does this come from? + default_colgap = Fixed(16) # TODO: where does this come from? + colgaps = GridLayoutBase.convert_gapsizes(ncols - 1, colgaps, default_colgap) + rowgaps = GridLayoutBase.convert_gapsizes(nrows - 1, rowgaps, default_rowgap) + + halign = GridLayoutBase.halign2shift(halign) + valign = GridLayoutBase.valign2shift(valign) + + return new( + content, + (nrows, ncols), + (rowspan[1] - 1, colspan[1] - 1), + colsizes, + rowsizes, + colgaps, + rowgaps, + alignmode, + tellheight, + tellwidth, + halign, + valign, + ) + end +end + +const Layoutable = Union{GridLayout,Block} +const LayoutableSpec = Union{GridLayoutSpec,BlockSpec} +const LayoutEntry = Pair{GridLayoutPosition,LayoutableSpec} + +GridLayoutSpec(v::AbstractVector; kwargs...) = GridLayoutSpec(reshape(v, :, 1); kwargs...) +function GridLayoutSpec(v::AbstractMatrix; kwargs...) + indices = vec([Tuple(c) for c in CartesianIndices(v)]) + pairs = [ + LayoutEntry((i:i, j:j, GridLayoutBase.Inner()), v[i, j]) for (i, j) in indices + ] + return GridLayoutSpec(pairs; kwargs...) +end + +GridLayoutSpec(contents...; kwargs...) = GridLayoutSpec([contents...]; kwargs...) + +""" +apply for return type PlotSpec +""" +function apply_convert!(P, attributes::Attributes, x::PlotSpec) + args, kwargs = x.args, x.kwargs + # Note that kw_args in the plot spec that are not part of the target plot type + # will end in the "global plot" kw_args (rest) + for (k, v) in pairs(kwargs) + attributes[k] = v + end + return (plottype(plottype(x), P), (args...,)) +end + +function apply_convert!(P, ::Attributes, x::AbstractVector{PlotSpec}) + return (PlotList, (x,)) +end + +""" +apply for return type + (args...,) +""" +apply_convert!(P, ::Attributes, x::Tuple) = (P, x) + +function MakieCore.argtypes(plot::PlotSpec) + args_converted = convert_arguments(plottype(plot), plot.args...) + return MakieCore.argtypes(args_converted) +end + +""" +See documentation for specapi. +""" +struct _SpecApi end +const SpecApi = _SpecApi() + +function Base.getproperty(::_SpecApi, field::Symbol) + field === :GridLayout && return GridLayoutSpec + # TODO, we wanted to track all recipe names in a set + # in MakieCore via the recipe macro, but due to precompilation & caching + # It seems impossible to merge the recipes from all modules + # Since precompilation will cache only MakieCore's state + # And once everything is compiled, and MakieCore is loaded into a package + # The names are loaded from cache and dont contain anything after MakieCore. + func = get_recipe_function(field) + if isnothing(func) + error("$(field) neither a recipe, Makie plotting object or a Block (like Axis, Legend, etc).") + elseif func isa Function + sym = plotsym(Plot{func}) + if (sym === :plot) # fallback for plotsym, so not found! + error("$(field) neither a recipe, Makie plotting object or a Block (like Axis, Legend, etc).") + end + @warn("PlotSpec objects are supposed to be title case. Found: $(field). Please use $(sym) instead.") + return (args...; kw...) -> PlotSpec(sym, args...; kw...) + elseif func <: Plot + return (args...; kw...) -> PlotSpec(field, args...; kw...) + elseif func <: Block + return (args...; kw...) -> BlockSpec(field, args...; kw...) + else + error("$(field) not a valid Block or Plot function") + end +end + +# We use this function to decide which plots to reuse + update instead of re-creating. +# Comparison based entirely of types inside args + kwargs. +# This will return false for the same plotspec with a new attribute +# E.g. `compare_spec(S.Scatter(1:4; color=:red), S.Scatter(1:4; marker=:circle))` +# While we could easily update this, we don't want to, since we're +# pessimistic about what's updatable and to avoid issues with +# Needing to reset attributes to their defaults, at the cost of re-creating more plots than necessary. +# TODO when focussing better performance, this is one of the first things we want to try +function compare_specs(a::PlotSpec, b::PlotSpec) + a.type === b.type || return false + length(a.args) == length(b.args) || return false + all(i-> typeof(a.args[i]) == typeof(b.args[i]), 1:length(a.args)) || return false + + length(a.kwargs) == length(b.kwargs) || return false + ka = keys(a.kwargs) + kb = keys(b.kwargs) + ka == kb || return false + all(k -> typeof(a.kwargs[k]) == typeof(b.kwargs[k]), ka) || return false + return true +end + +@inline function is_different(a, b) + # First check if they are the same object + # This disallows mutating PlotSpec arguments in place + a === b && return false + # If they're not the same objcets, we see if they contain the same values + a == b && return false + return true +end + +function update_plot!(obs_to_notify, plot::AbstractPlot, oldspec::PlotSpec, spec::PlotSpec) + # Update args in plot `input_args` list + for i in eachindex(spec.args) + # we should only call update_plot!, if compare_spec(spec_plot_got_created_from, spec) == true, + # Which should guarantee, that args + kwargs have the same length and types! + arg_obs = plot.args[i] + prev_val = oldspec.args[i] + if is_different(prev_val, spec.args[i]) # only update if different + arg_obs.val = spec.args[i] + push!(obs_to_notify, arg_obs) + end + end + scene = parent_scene(plot) + # Update attributes + for (attribute, new_value) in spec.kwargs + old_attr = plot[attribute] + # only update if different + if is_different(old_attr[], new_value) + if new_value isa Cycled + old_attr.val = to_color(scene, attribute, new_value) + else + @debug("updating kw $attribute") + old_attr.val = new_value + end + push!(obs_to_notify, old_attr) + end + end + # Cycling needs to be handled separately sadly, + # since they're implicitely mutating attributes, e.g. if I re-use a plot + # that has been on cycling position 2, and now I re-use it for the first plot in the list + # it will need to change to the color of cycling position 1 + if haskey(plot, :cycle) + cycle = get_cycle_for_plottype(plot.cycle[]) + uncycled = Set{Symbol}() + for (attr_vec, _) in cycle.cycle + for attr in attr_vec + if !haskey(spec.kwargs, attr) + push!(uncycled, attr) + end + end + end + + if !isempty(uncycled) + # remove all attributes that don't need cycling + for (attr_vec, _) in cycle.cycle + filter!(x -> x in uncycled, attr_vec) + end + add_cycle_attribute!(plot, scene, cycle) + append!(obs_to_notify, (plot[k] for k in uncycled)) + end + end + return +end + +""" + plotlist!( + [ + PlotSpec(:scatter, args...; kwargs...), + PlotSpec(:lines, args...; kwargs...), + ] + ) + +Plots a list of PlotSpec's, which can be an observable, making it possible to create efficiently animated plots with the following API: + +## Example +```julia +using GLMakie +import Makie.SpecApi as S + +fig = Figure() +ax = Axis(fig[1, 1]) +plots = Observable([S.heatmap(0 .. 1, 0 .. 1, Makie.peaks()), S.lines(0 .. 1, sin.(0:0.01:1); color=:blue)]) +pl = plot!(ax, plots) +display(fig) + +# Updating the plot dynamically +plots[] = [S.heatmap(0 .. 1, 0 .. 1, Makie.peaks()), S.lines(0 .. 1, sin.(0:0.01:1); color=:red)] +plots[] = [ + S.image(0 .. 1, 0 .. 1, Makie.peaks()), + S.poly(Rect2f(0.45, 0.45, 0.1, 0.1)), + S.lines(0 .. 1, sin.(0:0.01:1); linewidth=10, color=Makie.resample_cmap(:viridis, 101)), +] + +plots[] = [ + S.surface(0..1, 0..1, Makie.peaks(); colormap = :viridis, translation = Vec3f(0, 0, -1)), +] +``` +""" +@recipe(PlotList, plotspecs) do scene + Attributes() +end + +convert_arguments(::Type{<:AbstractPlot}, args::AbstractArray{<:PlotSpec}) = (args,) +plottype(::AbstractVector{PlotSpec}) = PlotList + +# Since we directly plot into the parent scene (hacky), we need to overload these +Base.insert!(::MakieScreen, ::Scene, ::PlotList) = nothing + +function Base.show(io::IO, ::MIME"text/plain", spec::PlotSpec) + args = join(map(x -> string("::", typeof(x)), spec.args), ", ") + kws = join([string(k, " = ", typeof(v)) for (k, v) in spec.kwargs], ", ") + println(io, "S.", spec.type, "($args; $kws)") + return +end + +function Base.show(io::IO, spec::PlotSpec) + args = join(map(x -> string("::", typeof(x)), spec.args), ", ") + kws = join([string(k, " = ", typeof(v)) for (k, v) in spec.kwargs], ", ") + println(io, "S.", spec.type, "($args; $kws)") + return +end + +function to_plot_object(ps::PlotSpec) + P = plottype(ps) + return P((ps.args...,), copy(ps.kwargs)) +end + +function find_reusable_plot(plotspec::PlotSpec, reusable_plots::IdDict{PlotSpec,Plot}) + for (spec, plot) in reusable_plots + if compare_specs(spec, plotspec) + return plot, spec + end + end + return nothing, nothing +end + +function diff_plotlist!(scene::Scene, plotspecs::Vector{PlotSpec}, obs_to_notify, reusable_plots, + plotlist::Union{Nothing,PlotList}=nothing) + new_plots = IdDict{PlotSpec,Plot}() # needed to be mutated + empty!(scene.cycler.counters) + # Global list of observables that need updating + # Updating them all at once in the end avoids problems with triggering updates while updating + # And at some point we may be able to optimize notify(list_of_observables) + empty!(obs_to_notify) + for plotspec in plotspecs + # we need to compare by types with compare_specs, since we can only update plots if the types of all attributes match + reused_plot, old_spec = find_reusable_plot(plotspec, reusable_plots) + if isnothing(reused_plot) + @debug("Creating new plot for spec") + # Create new plot, store it into our `cached_plots` dictionary + plot = plot!(scene, to_plot_object(plotspec)) + if !isnothing(plotlist) + push!(plotlist.plots, plot) + end + new_plots[plotspec] = plot + else + @debug("updating old plot with spec") + # Delete the plots from reusable_plots, so that we don't re-use it multiple times! + delete!(reusable_plots, old_spec) + update_plot!(obs_to_notify, reused_plot, old_spec, plotspec) + new_plots[plotspec] = reused_plot + end + end + return new_plots +end + +function update_plotspecs!(scene::Scene, list_of_plotspecs::Observable, plotlist::Union{Nothing, PlotList}=nothing) + # Cache plots here so that we aren't re-creating plots every time; + # if a plot still exists from last time, update it accordingly. + # If the plot is removed from `plotspecs`, we'll delete it from here + # and re-create it if it ever returns. + unused_plots = IdDict{PlotSpec,Plot}() + obs_to_notify = Observable[] + function update_plotlist(plotspecs) + # Global list of observables that need updating + # Updating them all at once in the end avoids problems with triggering updates while updating + # And at some point we may be able to optimize notify(list_of_observables) + empty!(obs_to_notify) + empty!(scene.cycler.counters) # Reset Cycler + # diff_plotlist! deletes all plots that get re-used from unused_plots + # so, this will become our list of unused plots! + new_plots = diff_plotlist!(scene, plotspecs, obs_to_notify, unused_plots, plotlist) + # Next, delete all plots that we haven't used + # TODO, we could just hide them, until we reach some max_plots_to_be_cached, so that we re-create less plots. + for (_, plot) in unused_plots + if !isnothing(plotlist) + filter!(x -> x !== plot, plotlist.plots) + end + delete!(scene, plot) + end + # Transfer all new plots into unused_plots for the next update! + @assert !any(x-> x in unused_plots, new_plots) + empty!(unused_plots) + merge!(unused_plots, new_plots) + # finally, notify all changes at once + foreach(notify, obs_to_notify) + return + end + l = Base.ReentrantLock() + on(scene, list_of_plotspecs; update=true) do plotspecs + lock(l) do + update_plotlist(plotspecs) + end + return + end + return +end + +function Makie.plot!(p::PlotList{<: Tuple{<: AbstractArray{PlotSpec}}}) + scene = Makie.parent_scene(p) + update_plotspecs!(scene, p[1], p) + return +end + +## BlockSpec + +function compare_layout_slot((anesting, ap, a)::Tuple{Int,GP,BlockSpec}, (bnesting, bp, b)::Tuple{Int,GP,BlockSpec}) where {GP<:GridLayoutPosition} + anesting !== bnesting && return false + a.type !== b.type && return false + ap !== bp && return false + return true +end + +function compare_layout_slot((anesting, ap, a)::Tuple{Int,GP, GridLayoutSpec}, (bnesting, bp, b)::Tuple{Int,GP, GridLayoutSpec}) where {GP <: GridLayoutPosition} + anesting !== bnesting && return false + ap !== bp && return false + for (ac, bc) in zip(a.content, b.content) + compare_layout_slot((anesting + 1, ac[1], ac[2]), (bnesting + 1, bc[1], bc[2])) || return false + end + return true +end + +compare_layout_slot(a, b) = false # types dont match + +function to_layoutable(parent, position::GridLayoutPosition, spec::BlockSpec) + BType = getfield(Makie, spec.type) + # TODO forward kw + block = BType(get_top_parent(parent); spec.kwargs...) + parent[position...] = block + return block +end + +function to_layoutable(parent, position::GridLayoutPosition, spec::GridLayoutSpec) + # TODO pass colsizes etc + gl = GridLayout(length(spec.rowsizes), length(spec.colsizes); + colsizes=spec.colsizes, + rowsizes=spec.rowsizes, + colgaps=spec.colgaps, + rowgaps=spec.rowgaps, + alignmode=spec.alignmode, + tellwidth=spec.tellwidth, + tellheight=spec.tellheight, + halign=spec.halign, + valign=spec.valign) + parent[position...] = gl + return gl +end + +function update_layoutable!(block::T, plot_obs, old_spec::BlockSpec, spec::BlockSpec) where T <: Block + old_attr = keys(old_spec.kwargs) + new_attr = keys(spec.kwargs) + # attributes that have been set previously and need to get unset now + reset_to_defaults = setdiff(old_attr, new_attr) + if !isempty(reset_to_defaults) + default_attrs = default_attribute_values(T, block.blockscene) + for attr in reset_to_defaults + setproperty!(block, attr, default_attrs[attr]) + end + end + # Attributes needing an update + to_update = setdiff(new_attr, reset_to_defaults) + for key in to_update + val = spec.kwargs[key] + prev_val = to_value(getproperty(block, key)) + if is_different(val, prev_val) + setproperty!(block, key, val) + end + end + # Reset the cycler + if hasproperty(block, :scene) + empty!(block.scene.cycler.counters) + end + if T <: AbstractAxis + plot_obs[] = spec.plots + scene = get_scene(block) + if any(needs_tight_limits, scene.plots) + tightlimits!(block) + end + end + return +end + +function to_gl_key(key::Symbol) + key === :colgaps && return :addedcolgaps + key === :rowgaps && return :addedrowgaps + return key +end + +function update_layoutable!(layout::GridLayout, obs, old_spec::Union{GridLayoutSpec, Nothing}, spec::GridLayoutSpec) + # Block updates until very end where all children etc got deleted! + layout.block_updates = true + keys = (:alignmode, :tellwidth, :tellheight, :halign, :valign) + layout.size = spec.size + layout.offsets = spec.offsets + for k in keys + # TODO! The gridlayout in the top parent figure has a padding from the Figure + # Since in the SpecApi we can do nested specs with whole figure, we can't create the default there since + # We don't know which GridLayout will be the main parent. + # So for now, we just ignore the padding for the top level gridlayout, since we assume the padding in the figurespec is wrong! + if layout.parent isa Figure && k == :alignmode + continue + end + old_val = isnothing(old_spec) ? nothing : getproperty(old_spec, k) + new_val = getproperty(spec, k) + if is_different(old_val, new_val) + value_obs = getfield(layout, k) + if value_obs isa Observable + value_obs[] = new_val + end + end + end + # TODO update colsizes etc + for field in [:size, :offsets, :colsizes, :rowsizes, :colgaps, :rowgaps] + old_val = isnothing(old_spec) ? nothing : getfield(old_spec, field) + new_val = getfield(spec, field) + if is_different(old_val, new_val) + setfield!(layout, to_gl_key(field), new_val) + end + end + return +end + +function find_layoutable(spec, layoutables) + for (i, (key, value)) in enumerate(layoutables) + if compare_layout_slot(key, spec) + return i, key, value + end + end + return 0, nothing, nothing +end + + +function update_gridlayout!(gridlayout::GridLayout, nesting::Int, oldgridspec::Union{Nothing, GridLayoutSpec}, + gridspec::GridLayoutSpec, previous_contents, new_layoutables) + + update_layoutable!(gridlayout, nothing, oldgridspec, gridspec) + + for (position, spec) in gridspec.content + # we need to compare by types with compare_specs, since we can only update plots if the types of all attributes match + idx, old_key, layoutable_obs = find_layoutable((nesting, position, spec), previous_contents) + if isnothing(layoutable_obs) + @debug("Creating new content for spec") + # Create new plot, store it into `new_layoutables` + new_layoutable = to_layoutable(gridlayout, position, spec) + obs = Observable(PlotSpec[]) + if new_layoutable isa AbstractAxis + obs = Observable(spec.plots) + scene = get_scene(new_layoutable) + update_plotspecs!(scene, obs) + if any(needs_tight_limits, scene.plots) + tightlimits!(new_layoutable) + end + update_state_before_display!(new_layoutable) + elseif new_layoutable isa GridLayout + # Make sure all plots & blocks are inserted + update_gridlayout!(new_layoutable, nesting + 1, spec, spec, previous_contents, + new_layoutables) + end + push!(new_layoutables, (nesting, position, spec) => (new_layoutable, obs)) + else + @debug("updating old block with spec") + # Make sure we don't double re-use a layoutable + splice!(previous_contents, idx) + (_, _, old_spec) = old_key + (layoutable, plot_obs) = layoutable_obs + gridlayout[position...] = layoutable + if layoutable isa GridLayout + update_gridlayout!(layoutable, nesting + 1, old_spec, spec, previous_contents, new_layoutables) + else + update_layoutable!(layoutable, plot_obs, old_spec, spec) + update_state_before_display!(layoutable) + end + # Carry over to cache it in new_layoutables + push!(new_layoutables, (nesting, position, spec) => (layoutable, plot_obs)) + end + end +end + +get_layout!(fig::Figure) = fig.layout +get_layout!(gp::Union{GridSubposition,GridPosition}) = GridLayoutBase.get_layout_at!(gp; createmissing=true) + +# We use this to decide if we can re-use a plot. +# (nesting_level_in_layout, position_in_layout, spec) +const LayoutableKey = Tuple{Int,GridLayoutPosition,LayoutableSpec} + +delete_layoutable!(block::Block) = delete!(block) +function delete_layoutable!(grid::GridLayout) + gc = grid.layoutobservables.gridcontent[] + if !isnothing(gc) + GridLayoutBase.remove_from_gridlayout!(gc) + end + return +end + +function update_fig!(fig::Union{Figure,GridPosition,GridSubposition}, layout_obs::Observable{GridLayoutSpec}) + # Global list of all layoutables. The LayoutableKey includes a nesting, so that we can keep even nested layouts in one global list. + # Vector of Pairs should allow to have an identical key without overwriting the previous value + unused_layoutables = Pair{LayoutableKey, Tuple{Layoutable,Observable{Vector{PlotSpec}}}}[] + new_layoutables = Pair{LayoutableKey,Tuple{Layoutable,Observable{Vector{PlotSpec}}}}[] + sizehint!(unused_layoutables, 50) + sizehint!(new_layoutables, 50) + l = Base.ReentrantLock() + layout = get_layout!(fig) + + on(get_topscene(fig), layout_obs; update=true) do layout_spec + lock(l) do + # For each update we look into `unused_layoutables` to see if we can re-use a layoutable (GridLayout/Block). + # Every re-used layoutable and every newly created gets pushed into `new_layoutables`, + # while it gets removed from `unused_layoutables`. + empty!(new_layoutables) + update_gridlayout!(layout, 1, nothing, layout_spec, unused_layoutables, new_layoutables) + # Everything that still is in unused_layoutables is not used anymore and can be deleted + for (key, (layoutable, obs)) in unused_layoutables + delete_layoutable!(layoutable) + Observables.clear(obs) + end + layouts_to_update = Set{GridLayout}([layout]) + for (_, (content, _)) in new_layoutables + if content isa GridLayout + push!(layouts_to_update, content) + else + gc = GridLayoutBase.gridcontent(content) + push!(layouts_to_update, gc.parent) + end + end + for l in layouts_to_update + l.block_updates = false + GridLayoutBase.update!(l) + end + # Finally transfer all new_layoutables into reusable_layoutables, + # since in the next update they will be the once we re-use + # TODO: Is this actually more efficent for GC then `reusable_layoutables=new_layoutables` ? + empty!(unused_layoutables) + append!(unused_layoutables, new_layoutables) + return + end + end + return fig +end + +args_preferred_axis(::GridLayoutSpec) = FigureOnly + +plot!(plot::Plot{MakieCore.plot,Tuple{GridLayoutSpec}}) = plot + +function plot!(fig::Union{Figure, GridLayoutBase.GridPosition}, plot::Plot{MakieCore.plot,Tuple{GridLayoutSpec}}) + figure = fig isa Figure ? fig : get_top_parent(fig) + connect_plot!(figure.scene, plot) + update_fig!(fig, plot[1]) + return fig +end + +function apply_convert!(P, ::Attributes, x::GridLayoutSpec) + return (Plot{plot}, (x,)) +end + +MakieCore.argtypes(::GridLayoutSpec) = Tuple{Nothing} diff --git a/src/stats/distributions.jl b/src/stats/distributions.jl index 0e219fb0bd9..6f2221119f3 100644 --- a/src/stats/distributions.jl +++ b/src/stats/distributions.jl @@ -113,7 +113,7 @@ maybefit(x, _) = x function convert_arguments(::Type{<:QQPlot}, x′, y; qqline = :none) x = maybefit(x′, y) points, line = fit_qqplot(x, y; qqline = qqline) - return PlotSpec{QQPlot}(points, line) + return PlotSpec(:QQPlot, points, line) end convert_arguments(::Type{<:QQNorm}, y; qqline = :none) = diff --git a/src/stats/ecdf.jl b/src/stats/ecdf.jl index 6494ca58df9..f8038456a9e 100644 --- a/src/stats/ecdf.jl +++ b/src/stats/ecdf.jl @@ -19,11 +19,13 @@ function convert_arguments(P::PlotFunc, ecdf::StatsBase.ECDF; npoints=10_000) end return to_plotspec(ptype, convert_arguments(ptype, x, ecdf(x)); kwargs...) end + function convert_arguments(P::PlotFunc, x::AbstractVector, ecdf::StatsBase.ECDF) ptype = plottype(P, Stairs) kwargs = ptype <: Stairs ? (; step=:post) : NamedTuple() return to_plotspec(ptype, convert_arguments(ptype, x, ecdf(x)); kwargs...) end + function convert_arguments(P::PlotFunc, x0::AbstractInterval, ecdf::StatsBase.ECDF) xmin, xmax = extrema(x0) z = ecdf_xvalues(ecdf, Inf) diff --git a/src/stats/hexbin.jl b/src/stats/hexbin.jl index 17501642235..c163f29bf0a 100644 --- a/src/stats/hexbin.jl +++ b/src/stats/hexbin.jl @@ -60,7 +60,7 @@ function spacings_offsets_nbins(bins, cellsizes::Tuple{<:Real,<:Real}, xmi, xma, ymi - (resty > 0 ? (yspacing - resty) / 2 : 0), Int(nx) + (restx > 0), Int(ny) + (resty > 0) end -Makie.conversion_trait(::Type{<:Hexbin}) = PointBased() +conversion_trait(::Type{<:Hexbin}) = PointBased() function data_limits(hb::Hexbin) bb = Rect3f(hb.plots[1][1][]) @@ -78,7 +78,7 @@ get_weight(weights, i) = Float64(weights[i]) get_weight(::StatsBase.UnitWeights, i) = 1e0 get_weight(::Nothing, i) = 1e0 -function Makie.plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) +function plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) xy = hb[1] points = Observable(Point2f[]) diff --git a/src/stats/hist.jl b/src/stats/hist.jl index bf5cd7e5bf8..165f361bc07 100644 --- a/src/stats/hist.jl +++ b/src/stats/hist.jl @@ -1,10 +1,10 @@ -const histogram_plot_types = [BarPlot, Heatmap, Volume] +const histogram_plot_types = (BarPlot, Heatmap, Volume) function convert_arguments(P::Type{<:AbstractPlot}, h::StatsBase.Histogram{<:Any, N}) where N ptype = plottype(P, histogram_plot_types[N]) f(edges) = edges[1:end-1] .+ diff(edges)./2 kwargs = N == 1 ? (; width = step(h.edges[1]), gap = 0, dodge_gap = 0) : NamedTuple() - to_plotspec(ptype, convert_arguments(ptype, map(f, h.edges)..., Float64.(h.weights)); kwargs...) + return to_plotspec(ptype, convert_arguments(ptype, map(f, h.edges)..., Float64.(h.weights)); kwargs...) end function _hist_center_weights(values, edges, normalization, scale_to, wgts) @@ -78,8 +78,8 @@ function Makie.plot!(plot::StepHist) pop!(attr, :normalization) pop!(attr, :scale_to) pop!(attr, :bins) - # plot the values, not the observables, to be in control of updating - stairs!(plot, points[]; attr..., color=color) + stairs!(plot, points; attr..., color=color) + plot end """ @@ -144,7 +144,7 @@ function pick_hist_edges(vals, bins) if bins isa Int mi, ma = float.(extrema(vals)) if mi == ma - return [mi - 0.5, ma + 0.5] + return (mi - 0.5):(ma + 0.5) end # hist is right-open, so to include the upper data point, make the last bin a tiny bit bigger ma = nextfloat(ma) @@ -187,5 +187,8 @@ function Makie.plot!(plot::Hist) bp[1].val = points[] bp.width = w end + onany(plot, plot.normalization, plot.scale_to, plot.weights) do _, _, _ + bp[1][] = points[] + end plot end diff --git a/src/stats/violin.jl b/src/stats/violin.jl index ef6e6f5ff99..d3d7d5c9707 100644 --- a/src/stats/violin.jl +++ b/src/stats/violin.jl @@ -35,7 +35,7 @@ Draw a violin plot. ) end -conversion_trait(x::Type{<:Violin}) = SampleBased() +conversion_trait(::Type{<:Violin}) = SampleBased() getuniquevalue(v, idxs) = v diff --git a/src/themes/theme_black.jl b/src/themes/theme_black.jl index 1f0b9965b59..3ee6e7fb23d 100644 --- a/src/themes/theme_black.jl +++ b/src/themes/theme_black.jl @@ -16,7 +16,7 @@ function theme_black() ), Legend = ( framecolor = :white, - bgcolor = :black, + backgroundcolor = :black, ), Axis3 = ( xgridcolor = RGBAf(1, 1, 1, 0.16), diff --git a/src/theming.jl b/src/theming.jl index 79ed248882f..5eb76a75567 100644 --- a/src/theming.jl +++ b/src/theming.jl @@ -23,8 +23,6 @@ const DEFAULT_PALETTES = Attributes( side = [:left, :right] ) -Base.@deprecate_binding default_palettes DEFAULT_PALETTES - const MAKIE_DEFAULT_THEME = Attributes( palette = DEFAULT_PALETTES, font = :regular, @@ -34,16 +32,16 @@ const MAKIE_DEFAULT_THEME = Attributes( italic = "TeX Gyre Heros Makie Italic", bold_italic = "TeX Gyre Heros Makie Bold Italic", ), - fontsize = 16, + fontsize = 14, textcolor = :black, padding = Vec3f(0.05), figure_padding = 16, - rowgap = 24, - colgap = 24, + rowgap = 18, + colgap = 18, backgroundcolor = :white, colormap = :viridis, marker = :circle, - markersize = 12, + markersize = 9, markercolor = :black, markerstrokecolor = :black, markerstrokewidth = 0, @@ -53,7 +51,7 @@ const MAKIE_DEFAULT_THEME = Attributes( patchcolor = RGBAf(0, 0, 0, 0.6), patchstrokecolor = :black, patchstrokewidth = 0, - resolution = (800, 600), # 4/3 aspect ratio + size = (600, 450), # 4/3 aspect ratio visible = true, Axis = Attributes(), Axis3 = Attributes(), @@ -68,12 +66,23 @@ const MAKIE_DEFAULT_THEME = Attributes( blur = Int32(2), # A (2blur+1) by (2blur+1) range is used for blurring # N_samples = 64, # number of samples (requires shader reload) ), - ambient = RGBf(0.55, 0.55, 0.55), - lightposition = :eyeposition, inspectable = true, + # Vec is equvalent to 36° right/east, 39° up/north from camera position + # The order here is Vec3f(right of, up from, towards) viewer/camera + light_direction = Vec3f(-0.45679495, -0.6293204, -0.6287243), + camera_relative_light = true, # Only applies to default DirectionalLight + light_color = RGBf(0.5, 0.5, 0.5), + ambient = RGBf(0.45, 0.45, 0.45), + + # Note: this can be set too + # lights = AbstractLight[ + # AmbientLight(RGBf(0.55, 0.55, 0.55)), + # DirectionalLight(RGBf(0.8, 0.8, 0.8), Vec3f(2/3, 2/3, 1/3)) + # ], + CairoMakie = Attributes( - px_per_unit = 1.0, + px_per_unit = 2.0, pt_per_unit = 0.75, antialias = :best, visible = true, @@ -87,6 +96,8 @@ const MAKIE_DEFAULT_THEME = Attributes( vsync = false, render_on_demand = true, framerate = 30.0, + px_per_unit = automatic, + scalefactor = automatic, # GLFW window attributes float = false, @@ -98,19 +109,27 @@ const MAKIE_DEFAULT_THEME = Attributes( monitor = nothing, visible = true, - # Postproccessor + # Shader constants & Postproccessor oit = true, fxaa = true, ssao = false, # This adjusts a factor in the rendering shaders for order independent # transparency. This should be the same for all of them (within one rendering # pipeline) otherwise depth "order" will be broken. - transparency_weight_scale = 1000f0 + transparency_weight_scale = 1000f0, + # maximum number of lights with shading = :verbose + max_lights = 64, + max_light_parameters = 5 * 64 ), WGLMakie = Attributes( framerate = 30.0, - resize_to_body = false + resize_to = nothing, + # DEPRECATED in favor of resize_to + # still needs to be here to gracefully deprecate it + resize_to_body = nothing, + px_per_unit = automatic, + scalefactor = automatic ), RPRMakie = Attributes( @@ -121,9 +140,6 @@ const MAKIE_DEFAULT_THEME = Attributes( ) ) -Base.@deprecate_binding minimal_default MAKIE_DEFAULT_THEME - - const CURRENT_DEFAULT_THEME = deepcopy(MAKIE_DEFAULT_THEME) const THEME_LOCK = Base.ReentrantLock() @@ -144,6 +160,26 @@ function merge_without_obs!(result::Attributes, theme::Attributes) end return result end + +# Same as above, but second argument gets priority so, `merge_without_obs_reverse!(Attributes(a=22), Attributes(a=33)) -> Attributes(a=33)` +function merge_without_obs_reverse!(result::Attributes, priority::Attributes) + result_dict = attributes(result) + for (key, value) in priority + if !haskey(result_dict, key) + result_dict[key] = Observable{Any}(to_value(value)) # the deepcopy part for observables + else + current_value = result[key] + if value isa Attributes && current_value isa Attributes + # if nested attribute, we merge recursively + merge_without_obs_reverse!(current_value, value) + else + result_dict[key] = Observable{Any}(to_value(value)) + end + end + end + return result +end + # Use copy with no obs to quickly deepcopy fast_deepcopy(attributes) = merge_without_obs!(Attributes(), attributes) @@ -177,7 +213,7 @@ restored afterwards, no matter if `f` succeeds or fails. Example: ```julia -my_theme = Theme(resolution = (500, 500), color = :red) +my_theme = Theme(size = (500, 500), color = :red) with_theme(my_theme, color = :blue, linestyle = :dashed) do scatter(randn(100, 2)) end @@ -198,6 +234,7 @@ function with_theme(f, theme = Theme(); kwargs...) end theme(::Nothing, key::Symbol; default=nothing) = theme(key; default) +theme(::Nothing) = CURRENT_DEFAULT_THEME function theme(key::Symbol; default=nothing) if haskey(CURRENT_DEFAULT_THEME, key) val = to_value(CURRENT_DEFAULT_THEME[key]) diff --git a/src/types.jl b/src/types.jl index b91dd552cce..a3144183a7b 100644 --- a/src/types.jl +++ b/src/types.jl @@ -1,4 +1,6 @@ abstract type AbstractCamera end +abstract type Block end +abstract type AbstractAxis <: Block end # placeholder if no camera is present struct EmptyCamera <: AbstractCamera end @@ -194,6 +196,14 @@ function Base.empty!(events::Events) return end +abstract type BooleanOperator end + +""" + IsPressedInputType + +Union containing possible input types for `ispressed`. +""" +const IsPressedInputType = Union{Bool,BooleanOperator,Mouse.Button,Keyboard.Button,Set,Vector,Tuple} """ Camera(pixel_area) @@ -231,7 +241,12 @@ struct Camera resolution::Observable{Vec2f} """ - Eye position of the camera, sued for e.g. ray tracing. + Focal point of the camera, used for e.g. camera synchronized light direction. + """ + lookat::Observable{Vec3f} + + """ + Eye position of the camera, used for e.g. ray tracing. """ eyeposition::Observable{Vec3f} @@ -240,6 +255,8 @@ struct Camera We need to keep track of them, so, that we can connect and disconnect them. """ steering_nodes::Vector{ObserverFunction} + + calculated_values::Dict{Symbol, Observable} end """ @@ -253,41 +270,48 @@ struct Transformation <: Transformable scale::Observable{Vec3f} rotation::Observable{Quaternionf} model::Observable{Mat4f} + parent_model::Observable{Mat4f} # data conversion observable, for e.g. log / log10 etc transform_func::Observable{Any} - function Transformation(translation, scale, rotation, model, transform_func) - return new( - RefValue{Transformation}(), - translation, scale, rotation, model, transform_func - ) + function Transformation(translation, scale, rotation, transform_func) + translation_o = convert(Observable{Vec3f}, translation) + scale_o = convert(Observable{Vec3f}, scale) + rotation_o = convert(Observable{Quaternionf}, rotation) + parent_model = Observable(Mat4f(I)) + model = map(translation_o, scale_o, rotation_o, parent_model) do t, s, r, p + return p * transformationmatrix(t, s, r) + end + transform_func_o = convert(Observable{Any}, transform_func) + return new(RefValue{Transformation}(), + translation_o, scale_o, rotation_o, model, parent_model, transform_func_o) end end -""" -`PlotSpec{P<:AbstractPlot}(args...; kwargs...)` - -Object encoding positional arguments (`args`), a `NamedTuple` of attributes (`kwargs`) -as well as plot type `P` of a basic plot. -""" -struct PlotSpec{P<:AbstractPlot} - args::Tuple - kwargs::NamedTuple - PlotSpec{P}(args...; kwargs...) where {P<:AbstractPlot} = new{P}(args, values(kwargs)) +function Transformation(transform_func=identity; + scale=Vec3f(1), + translation=Vec3f(0), + rotation=Quaternionf(0, 0, 0, 1)) + return Transformation(translation, + scale, + rotation, + transform_func) end -PlotSpec(args...; kwargs...) = PlotSpec{Combined{Any}}(args...; kwargs...) - -Base.getindex(p::PlotSpec, i::Int) = getindex(p.args, i) -Base.getindex(p::PlotSpec, i::Symbol) = getproperty(p.kwargs, i) - -to_plotspec(::Type{P}, args; kwargs...) where {P} = - PlotSpec{P}(args...; kwargs...) - -to_plotspec(::Type{P}, p::PlotSpec{S}; kwargs...) where {P, S} = - PlotSpec{plottype(P, S)}(p.args...; p.kwargs..., kwargs...) - -plottype(::PlotSpec{P}) where {P} = P - +function Transformation(parent::Transformable; + scale=Vec3f(1), + translation=Vec3f(0), + rotation=Quaternionf(0, 0, 0, 1), + transform_func=nothing) + connect_func = isnothing(transform_func) + trans = isnothing(transform_func) ? identity : transform_func + + trans = Transformation(translation, + scale, + rotation, + trans) + connect!(transformation(parent), trans; connect_func=connect_func) + return trans +end struct ScalarOrVector{T} sv::Union{T, Vector{T}} @@ -430,3 +454,10 @@ end (s::ReversibleScale)(args...) = s.forward(args...) # functor Base.show(io::IO, s::ReversibleScale) = print(io, "ReversibleScale($(s.name))") Base.show(io::IO, ::MIME"text/plain", s::ReversibleScale) = print(io, "ReversibleScale($(s.name))") + + +struct Cycler + counters::IdDict{Type,Int} +end + +Cycler() = Cycler(IdDict{Type,Int}()) diff --git a/src/units.jl b/src/units.jl index d93d71f8331..7105410199e 100644 --- a/src/units.jl +++ b/src/units.jl @@ -18,7 +18,7 @@ ######### function to_screen(scene::Scene, mpos) - return Point2f(mpos) .- Point2f(minimum(pixelarea(scene)[])) + return Point2f(mpos) .- Point2f(minimum(viewport(scene)[])) end number(x::Unit) = x.value diff --git a/src/utilities/quaternions.jl b/src/utilities/quaternions.jl index bcae57f50de..f5ccf832bc3 100644 --- a/src/utilities/quaternions.jl +++ b/src/utilities/quaternions.jl @@ -81,6 +81,17 @@ function Base.:(*)(quat::Quaternion{T}, vec::P) where {T, P <: StaticVector{3}} (num8 - num11) * vec[1] + (num9 + num10) * vec[2] + (1f0 - (num4 + num5)) * vec[3] ) end + +function Base.:(*)(quat::Quaternion, bb::Rect3{T}) where {T} + points = corners(bb) + first = points[1] + bb = Ref(Rect3{T}(quat * first, zero(first))) + for i in 2:length(points) + bb[] = _update_rect(bb[], Point3{T}(quat * points[i])) + end + return bb[] +end + Base.conj(q::Quaternion) = Quaternion(-q[1], -q[2], -q[3], q[4]) function Base.:(*)(q::Quaternion, w::Quaternion) diff --git a/src/utilities/texture_atlas.jl b/src/utilities/texture_atlas.jl index 00b6727330c..d38085821b6 100644 --- a/src/utilities/texture_atlas.jl +++ b/src/utilities/texture_atlas.jl @@ -1,4 +1,4 @@ -const SERIALIZATION_FORMAT_VERSION = "v4" +const SERIALIZATION_FORMAT_VERSION = "v6" struct TextureAtlas rectangle_packer::RectanglePacker{Int32} @@ -157,7 +157,7 @@ function get_texture_atlas(resolution::Int = 2048, pix_per_glyph::Int = 64) end end -const CACHE_DOWNLOAD_URL = "https://github.com/MakieOrg/Makie.jl/releases/download/v0.19.0/" +const CACHE_DOWNLOAD_URL = "https://github.com/MakieOrg/Makie.jl/releases/download/v0.20.0/" function cached_load(resolution::Int, pix_per_glyph::Int) path = get_cache_path(resolution, pix_per_glyph) @@ -187,8 +187,6 @@ end const DEFAULT_FONT = NativeFont[] const ALTERNATIVE_FONTS = NativeFont[] const FONT_LOCK = Base.ReentrantLock() -Base.@deprecate_binding _default_font DEFAULT_FONT -Base.@deprecate_binding _alternative_fonts ALTERNATIVE_FONTS function defaultfont() lock(FONT_LOCK) do @@ -219,9 +217,8 @@ function alternativefonts() end function render_default_glyphs!(atlas) - font = defaultfont() - chars = ['a':'z'..., 'A':'Z'..., '0':'9'..., '.', '-'] - fonts = to_font.(to_value.(values(Makie.MAKIE_DEFAULT_THEME.fonts))) + chars = ['a':'z'..., 'A':'Z'..., '0':'9'..., '.', '-', MINUS_SIGN] + fonts = map(x-> to_font(to_value(x)), values(MAKIE_DEFAULT_THEME.fonts)) for font in fonts for c in chars insert_glyph!(atlas, c, font) @@ -291,19 +288,26 @@ function glyph_uv_width!(atlas::TextureAtlas, b::BezierPath) return atlas.uv_rectangles[glyph_index!(atlas, b)] end -crc(x, seed=UInt32(0)) = crc32c(collect(x), seed) + +# Seems like StableHashTraits is so slow, that it's worthwhile to memoize the hashes +const MEMOIZED_HASHES = Dict{Any, UInt32}() + +function fast_stable_hash(x) + return get!(MEMOIZED_HASHES, x) do + return StableHashTraits.stable_hash(x; alg=crc32c, version=2) + end +end + function insert_glyph!(atlas::TextureAtlas, glyph, font::NativeFont) glyphindex = FreeTypeAbstraction.glyph_index(font, glyph) - hash = StableHashTraits.stable_hash((glyphindex, FreeTypeAbstraction.fontname(font)); - alg=crc) + hash = fast_stable_hash((glyphindex, FreeTypeAbstraction.fontname(font))) return insert_glyph!(atlas, hash, (glyphindex, font)) end function insert_glyph!(atlas::TextureAtlas, path::BezierPath) - return insert_glyph!(atlas, StableHashTraits.stable_hash(path; alg=crc), path) + return insert_glyph!(atlas, fast_stable_hash(path), path) end - function insert_glyph!(atlas::TextureAtlas, hash::UInt32, path_or_glyp::Union{BezierPath, Tuple{UInt64, NativeFont}}) return get!(atlas.mapping, hash) do uv_pixel = render(atlas, path_or_glyp) @@ -434,6 +438,7 @@ function marker_to_sdf_shape(arr::AbstractVector) shape1 = marker_to_sdf_shape(first(arr)) for elem in arr shape2 = marker_to_sdf_shape(elem) + shape2 isa Shape && shape1 isa Shape && continue shape1 !== shape2 && error("Can't use an array of markers that require different primitive_shapes $(typeof.(arr)).") end return shape1 @@ -552,10 +557,11 @@ end offset_marker(atlas, marker, font, markersize, markeroffset) = markeroffset -function marker_attributes(atlas::TextureAtlas, marker, markersize, font, marker_offset) +function marker_attributes(atlas::TextureAtlas, marker, markersize, font, marker_offset, plot_object) atlas_obs = Observable(atlas) # for map to work - scale = map(rescale_marker, atlas_obs, marker, font, markersize; ignore_equal_values=true) - quad_offset = map(offset_marker, atlas_obs, marker, font, markersize, marker_offset; ignore_equal_values=true) + scale = map(rescale_marker, plot_object, atlas_obs, marker, font, markersize; ignore_equal_values=true) + quad_offset = map(offset_marker, plot_object, atlas_obs, marker, font, markersize, marker_offset; + ignore_equal_values=true) return scale, quad_offset end diff --git a/src/utilities/utilities.jl b/src/utilities/utilities.jl index 137c720d329..fd2d653eb56 100644 --- a/src/utilities/utilities.jl +++ b/src/utilities/utilities.jl @@ -35,23 +35,6 @@ function resample_cmap(cmap, ncolors::Integer; alpha=1.0) end end -""" - resampled_colors(attributes::Attributes, levels::Integer) - -Resample the color attribute from `attributes`. Resamples `:colormap` if present, -or repeats `:color`. -""" -function resampled_colors(attributes, levels::Integer) - cols = if haskey(attributes, :color) - c = get_attribute(attributes, :color) - c isa AbstractVector ? resample(c, levels) : repeated(c, levels) - else - c = get_attribute(attributes, :colormap) - resample(c, levels) - end -end - - """ Like `get!(f, dict, key)` but also calls `f` and replaces `key` when the corresponding value is nothing @@ -106,7 +89,19 @@ function extract_expr(extract_func, dictlike, args) end """ -usage @extract scene (a, b, c, d) + @extract scene (a, b, c, d) + +This becomes + +```julia +begin + a = scene[:a] + b = scene[:b] + c = scene[:d] + d = scene[:d] + (a, b, c, d) +end +``` """ macro extract(scene, args) extract_expr(getindex, scene, args) @@ -184,6 +179,7 @@ attr_broadcast_getindex(x::Ref, i) = x[] # unwrap Refs just like in normal broad attr_broadcast_getindex(x::ScalarOrVector, i) = x.sv isa Vector ? x.sv[i] : x.sv is_vector_attribute(x::AbstractVector) = true +is_vector_attribute(x::Base.Generator) = is_vector_attribute(x.iter) is_vector_attribute(x::NativeFont) = false is_vector_attribute(x::Quaternion) = false is_vector_attribute(x::VecTypes) = false @@ -266,6 +262,22 @@ function merged_get!(defaults::Function, key, scene::SceneLike, input::Attribute return merge!(input, d) end +function Base.replace!(target::Attributes, key, scene::SceneLike, overwrite::Attributes) + if haskey(theme(scene), key) + _replace!(target, theme(scene, key)) + end + return _replace!(target, overwrite) +end + +function _replace!(target::Attributes, overwrite::Attributes) + for k in keys(target) + haskey(overwrite, k) && (target[k] = overwrite[k]) + end + return +end + + + to_vector(x::AbstractVector, len, T) = convert(Vector{T}, x) function to_vector(x::AbstractArray, len, T) if length(x) in size(x) # assert that just one dim != 1 @@ -320,6 +332,80 @@ function surface_normals(x, y, z) return vec(map(normal, CartesianIndices(z))) end + +############################################################ +# NaN-aware normal & mesh handling # +############################################################ + +""" + nan_aware_orthogonal_vector(v1, v2, v3) where N + +Returns an un-normalized normal vector for the triangle formed by the three input points. +Skips any combination of the inputs for which any point has a NaN component. +""" +function nan_aware_orthogonal_vector(v1, v2, v3) + (isnan(v1) || isnan(v2) || isnan(v3)) && return Vec3f(0) + return Vec3f(cross(v2 - v1, v3 - v1)) +end + +""" + nan_aware_normals(vertices::AbstractVector{<: Union{Point, PointMeta}}, faces::AbstractVector{F}) + +Computes the normals of a mesh defined by `vertices` and `faces` (a vector of `GeometryBasics.NgonFace`) +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} + normals_result = zeros(Vec3f, length(vertices)) + free_verts = GeometryBasics.metafree.(vertices) + + for face in faces + + v1, v2, v3 = free_verts[face] + # we can get away with two edges since faces are planar. + n = nan_aware_orthogonal_vector(v1, v2, v3) + + for i in 1:length(F) + fi = face[i] + normals_result[fi] = normals_result[fi] + n + end + end + normals_result .= GeometryBasics.normalize.(normals_result) + return normals_result +end + +function nan_aware_normals(vertices::AbstractVector{<:AbstractPoint{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) + ps = matrix_grid(p -> apply_transform(transform_func, p, space), xs, ys, zs) + # create valid tessellations (triangulations) for the mesh + # knowing that it is a regular grid makes this simple + rect = Tesselation(Rect2f(0, 0, 1, 1), size(zs)) + # we use quad faces so that color handling is consistent + faces = decompose(QuadFace{Int}, rect) + # and remove quads that contain a NaN coordinate to avoid drawing triangles + faces = filter(f -> !any(i -> isnan(ps[i]), f), faces) + # create the uv (texture) vectors + uv = map(x-> Vec2f(1f0 - x[2], 1f0 - x[1]), 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, ) +end + + +############################################################ +# Matrix grid method for surface handling # +############################################################ + """ matrix_grid(f, x::AbstractArray, y::AbstractArray, z::AbstractMatrix)::Vector{Point3f} @@ -337,6 +423,10 @@ function matrix_grid(f, x::ClosedInterval, y::ClosedInterval, z::AbstractMatrix) matrix_grid(f, LinRange(extrema(x)..., size(z, 1)), LinRange(extrema(x)..., size(z, 2)), z) end +############################################################ +# Attribute key extraction # +############################################################ + function extract_keys(attributes, keys) attr = Attributes() for key in keys @@ -346,5 +436,21 @@ function extract_keys(attributes, keys) end # Scalar - Vector getindex -sv_getindex(v::Vector, i::Integer) = v[i] -sv_getindex(x, i::Integer) = x \ No newline at end of file +sv_getindex(v::AbstractVector, i::Integer) = v[i] +sv_getindex(x, ::Integer) = x +sv_getindex(x::VecTypes, ::Integer) = x + +# TODO: move to GeometryBasics +function corners(rect::Rect2{T}) where T + o = minimum(rect) + w = widths(rect) + T0 = zero(T) + return Point{3,T}[o .+ Vec2{T}(x, y) for x in (T0, w[1]) for y in (T0, w[2])] +end + +function corners(rect::Rect3{T}) where T + o = minimum(rect) + w = widths(rect) + T0 = zero(T) + return Point{3,T}[o .+ Vec3{T}(x, y, z) for x in (T0, w[1]) for y in (T0, w[2]) for z in (T0, w[3])] +end diff --git a/test/PolarAxis.jl b/test/PolarAxis.jl index 1866f439743..8029e1835f1 100644 --- a/test/PolarAxis.jl +++ b/test/PolarAxis.jl @@ -68,7 +68,7 @@ @test ax.thetaautolimitmargin[] == (0.05, 0.05) # default should have mostly set default limits - @test ax.rlimits[] == (0.0, nothing) + @test ax.rlimits[] == (:origin, nothing) @test ax.thetalimits[] == (0.0, 2pi) @test ax.target_rlims[] == (0.0, 10.0) @test ax.target_thetalims[] == (0.0, 2pi) @@ -130,7 +130,7 @@ # with default limits reset_limits!(ax) - @test ax.rlimits[] == (0.0, nothing) + @test ax.rlimits[] == (:origin, nothing) @test ax.thetalimits[] == (0.0, 2pi) @test ax.target_rlims[] == (0.0, 5.0) @test ax.target_thetalims[] == (0.0, 2pi) @@ -144,17 +144,9 @@ @test all(isapprox.(ax.target_thetalims[], (0.5pi, 1.0pi), rtol=1e-6)) end - @testset "Radial Distortion" begin + @testset "Radial Offset" begin fig = Figure() - ax = PolarAxis(fig[1, 1], radial_distortion_threshold = 0.2, rlimits = (0, 10)) - tf = ax.scene.transformation.transform_func - @test /(ax.target_rlims[]...) == 0.0 - @test /((ax.target_rlims[] .- tf[].r0)...) == 0.0 - rlims!(ax, 1, 10) - @test /(ax.target_rlims[]...) == 0.1 - @test /((ax.target_rlims[] .- tf[].r0)...) == 0.1 - rlims!(ax, 5, 10) - @test /(ax.target_rlims[]...) == 0.5 - @test /((ax.target_rlims[] .- tf[].r0)...) ≈ 0.2 + ax = PolarAxis(fig[1, 1], radius_at_origin = -1.0, rlimits = (0, 10)) + @test ax.scene.transformation.transform_func[].r0 == -1.0 end end \ No newline at end of file diff --git a/test/barplot.jl b/test/barplot.jl new file mode 100644 index 00000000000..2a1e6bf9a79 --- /dev/null +++ b/test/barplot.jl @@ -0,0 +1,130 @@ +@testset "Barplot" begin + @testset "label align" begin + @testset "automatic" begin + # for more info see https://github.com/MakieOrg/Makie.jl/issues/3160 + # below is the best square angles behavior for bar labels + + al = Makie.automatic + + y_dir, flip = false, false + @test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(0.0, 0.5) + @test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(1.0, 0.5) + @test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(0.5, 1.0) + @test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(0.5, 0.0) + + y_dir, flip = true, false + @test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(0.5, 0.0) + @test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(0.5, 1.0) + @test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(0.0, 0.5) + @test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(1.0, 0.5) + + y_dir, flip = false, true + @test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(1.0, 0.5) + @test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(0.0, 0.5) + @test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(0.5, 0.0) + @test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(0.5, 1.0) + + y_dir, flip = true, true + @test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(0.5, 1.0) + @test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(0.5, 0.0) + @test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(1.0, 0.5) + @test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(0.0, 0.5) + end + + @testset "manual" begin + input = 0.0, false, false + for align in (Vec2f(1.0, 0.5), Point2f(1.0, 0.5), (1.0, 0.5), (1, 0), (1.0, 0)) + @test Makie.calculate_bar_label_align(align, input...) ≈ Vec2f(align) + end + end + + @testset "symbols" begin + input = 0.0, false, false + @test Makie.calculate_bar_label_align((:center, :center), input...) ≈ Makie.calculate_bar_label_align((0.5, 0.5), input...) + end + + @testset "error" begin + input = 0.0, false, false + for align in ("center", 0.5, ("center", "center")) + @test_throws ErrorException Makie.calculate_bar_label_align(align, input...) + end + end + end + + @testset "stack" begin + x1 = [1, 1, 1, 1] + grp_dodge1 = [2, 2, 1, 1] + grp_stack1 = [1, 2, 1, 2] + y1 = [2, 3, -3, -2] + + x2 = [2, 2, 2, 2] + grp_dodge2 = [3, 4, 3, 4] + grp_stack2 = [3, 4, 3, 4] + y2 = [2, 3, -3, -2] + + from, to = Makie.stack_grouped_from_to(grp_stack1, y1, (; x1 = x1, grp_dodge1 = grp_dodge1)) + from1 = [0.0, 2.0, 0.0, -3.0] + to1 = [2.0, 5.0, -3.0, -5.0] + @test from == from1 + @test to == to1 + + from, to = Makie.stack_grouped_from_to(grp_stack2, y2, (; x2 = x2, grp_dodge2 = grp_dodge2)) + from2 = [0.0, 0.0, 0.0, 0.0] + to2 = [2.0, 3.0, -3.0, -2.0] + @test from == from2 + @test to == to2 + + perm = [1, 4, 2, 7, 5, 3, 8, 6] + x = [x1; x2][perm] + y = [y1; y2][perm] + grp_dodge = [grp_dodge1; grp_dodge2][perm] + grp_stack = [grp_stack1; grp_stack2][perm] + + from_test = [from1; from2][perm] + to_test = [to1; to2][perm] + + from, to = Makie.stack_grouped_from_to(grp_stack, y, (; x = x, grp_dodge = grp_dodge)) + @test from == from_test + @test to == to_test + end + + @testset "zero-height" begin + grp_stack = [1, 2, 1, 2] + x = [1, 1, 2, 2] + + y = [1.0, 0.0, -1.0, -1.0] + from = [0.0, 1.0, 0.0, -1.0] + to = [1.0, 1.0, -1.0, -2.0] + from_, to_ = Makie.stack_grouped_from_to(grp_stack, y, (; x)) + @test from == from_ + @test to == to_ + + y = [-1.0, 0.0, -1.0, -1.0] + from = [0.0, -1.0, 0.0, -1.0] + to = [-1.0, -1.0, -1.0, -2.0] + from_, to_ = Makie.stack_grouped_from_to(grp_stack, y, (; x)) + @test from == from_ + @test to == to_ + + y = [0.0, 1.0, -1.0, -1.0] + from = [0.0, 0.0, 0.0, -1.0] + to = [0.0, 1.0, -1.0, -2.0] + from_, to_ = Makie.stack_grouped_from_to(grp_stack, y, (; x)) + @test from == from_ + @test to == to_ + + y = [0.0, -1.0, -1.0, -1.0] + from = [0.0, 0.0, 0.0, -1.0] + to = [0.0, -1.0, -1.0, -2.0] + from_, to_ = Makie.stack_grouped_from_to(grp_stack, y, (; x)) + @test from == from_ + @test to == to_ + + y = [0.0, 1.0, -1.0, -1.0] + from = [0.0, 0.0, 0.0, -1.0] + to = [0.0, 1.0, -1.0, -2.0] + from_, to_ = Makie.stack_grouped_from_to(1:4, y, (; x=ones(4))) + @test from == from_ + @test to == to_ + end +end diff --git a/test/barplot_labels.jl b/test/barplot_labels.jl deleted file mode 100644 index f99bcf1347e..00000000000 --- a/test/barplot_labels.jl +++ /dev/null @@ -1,52 +0,0 @@ -@testset "Barplot label align" begin - @testset "automatic" begin - # for more info see https://github.com/MakieOrg/Makie.jl/issues/3160 - # below is the best square angles behavior for bar labels - - al = Makie.automatic - - y_dir, flip = false, false - @test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(0.0, 0.5) - @test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(1.0, 0.5) - @test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(0.5, 1.0) - @test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(0.5, 0.0) - - y_dir, flip = true, false - @test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(0.5, 0.0) - @test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(0.5, 1.0) - @test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(0.0, 0.5) - @test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(1.0, 0.5) - - y_dir, flip = false, true - @test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(1.0, 0.5) - @test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(0.0, 0.5) - @test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(0.5, 0.0) - @test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(0.5, 1.0) - - y_dir, flip = true, true - @test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(0.5, 1.0) - @test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(0.5, 0.0) - @test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(1.0, 0.5) - @test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(0.0, 0.5) - end - - @testset "manual" begin - input = 0.0, false, false - for align in (Vec2f(1.0, 0.5), Point2f(1.0, 0.5), (1.0, 0.5), (1, 0), (1.0, 0)) - @test Makie.calculate_bar_label_align(align, input...) ≈ Vec2f(align) - end - end - - @testset "symbols" begin - input = 0.0, false, false - @test Makie.calculate_bar_label_align((:center, :center), input...) ≈ Makie.calculate_bar_label_align((0.5, 0.5), input...) - end - - @testset "error" begin - input = 0.0, false, false - for align in ("center", 0.5, ("center", "center")) - @test_throws ErrorException Makie.calculate_bar_label_align(align, input...) - end - end - -end \ No newline at end of file diff --git a/test/bezier.jl b/test/bezier.jl new file mode 100644 index 00000000000..2111b8f235e --- /dev/null +++ b/test/bezier.jl @@ -0,0 +1,10 @@ +using Makie, Test + +# nice reference: https://www.nan.fyi/svg-paths +@testset "BezierPath construction" begin + @test_nowarn BezierPath("m 0,9 L 0,5138 0,9 z") + @test_broken BezierPath("m 0,1e-5 L 0,5138 0,9 z") isa BezierPath + @test_nowarn BezierPath("M 100,100 C 100,200 200,100 200,200 z") + @test_broken BezierPath("M 100,100 Q 50,150,100,100 z") isa BezierPath + @test_broken BezierPath("M 3.0 10.0 A 10.0 7.5 0.0 0.0 0.0 20.0 15.0 z") isa BezierPath +end diff --git a/test/boundingboxes.jl b/test/boundingboxes.jl index 99fbf8cdd57..e7a83fb34fd 100644 --- a/test/boundingboxes.jl +++ b/test/boundingboxes.jl @@ -15,6 +15,23 @@ end fig, ax, p = bracket(ps...) @test data_limits(p) ≈ Rect3f(Point3f(0), Vec3f(1, 1, 0)) + + fig = Figure() + ax = Axis(fig[1, 1], yscale=log, xscale=log) + scatter!(ax, [0.5, 1, 2], [0.5, 1, 2]) + p1 = vlines!(ax, [0.5]) + p2 = hlines!(ax, [0.5]) + p3 = vspan!(ax, [0.25], [0.75]) + p4 = hspan!(ax, [0.25], [0.75]) + Makie.reset_limits!(ax) + + lims = ax.finallimits[] + x, y = minimum(lims); w, h = widths(lims) + + @test data_limits(p1) ≈ Rect3f(Point3f(0.5, y, 0), Vec3f(0, h, 0)) + @test data_limits(p2) ≈ Rect3f(Point3f(x, 0.5, 0), Vec3f(w, 0, 0)) + @test data_limits(p3) ≈ Rect3f(Point3f(0.25, y, 0), Vec3f(0.5, h, 0)) + @test data_limits(p4) ≈ Rect3f(Point3f(x, 0.25, 0), Vec3f(w, 0.5, 0)) end @testset "boundingbox(plot)" begin @@ -29,13 +46,24 @@ end fig, ax, p = surface([x*y for x in 1:10, y in 1:10]) bb = boundingbox(p) - @test bb.origin ≈ Point3f(0.0, 0.0, 1.0) - @test bb.widths ≈ Vec3f(10.0, 10.0, 99.0) + @test bb.origin ≈ Point3f(1.0, 1.0, 1.0) + @test bb.widths ≈ Vec3f(9.0, 9.0, 99.0) fig, ax, p = meshscatter([Point3f(x, y, z) for x in 1:5 for y in 1:5 for z in 1:5]) bb = boundingbox(p) - @test bb.origin ≈ Point3f(1) - @test bb.widths ≈ Vec3f(4) + # Note: awkwards numbers come from using mesh over Sphere + @test bb.origin ≈ Point3f(0.9011624, 0.9004657, 0.9) + @test bb.widths ≈ Vec3f(4.1986046, 4.199068, 4.2) + + fig, ax, p = meshscatter( + [Point3f(0) for _ in 1:3], + marker = Rect3f(Point3f(-0.1, -0.1, -0.1), Vec3f(0.2, 0.2, 1.2)), + markersize = Vec3f(1, 1, 2), + rotations = Makie.rotation_between.((Vec3f(0,0,1),), Vec3f[(1,0,0), (0,1,0), (0,0,1)]) + ) + bb = boundingbox(p) + @test bb.origin ≈ Point3f(-0.2) + @test bb.widths ≈ Vec3f(2.4) fig, ax, p = volume(rand(5, 5, 5)) bb = boundingbox(p) @@ -68,10 +96,10 @@ end @test bb.widths ≈ Vec3f(10.0, 10.0, 0) # text transforms to pixel space atm (TODO) - fig = Figure(resolution = (400, 400)) + fig = Figure(size = (400, 400)) ax = Axis(fig[1, 1]) p = text!(ax, Point2f(10), text = "test", fontsize = 20) bb = boundingbox(p) - @test bb.origin ≈ Point3f(340, 341, 0) + @test bb.origin ≈ Point3f(343.0, 345.0, 0) @test bb.widths ≈ Vec3f(32.24, 23.3, 0) end \ No newline at end of file diff --git a/test/conversions.jl b/test/conversions.jl index c735ed4735b..4d27bf4de6f 100644 --- a/test/conversions.jl +++ b/test/conversions.jl @@ -38,7 +38,6 @@ end X4 = rand(2,10) V4 = to_vertices(X4) @test Float32(X4[1,7]) == V4[7][1] - @test V4[7][3] == 0 X5 = rand(3,10) V5 = to_vertices(X5) @@ -47,7 +46,6 @@ end X6 = rand(10,2) V6 = to_vertices(X6) @test Float32(X6[7,1]) == V6[7][1] - @test V6[7][3] == 0 X7 = rand(10,3) V7 = to_vertices(X7) @@ -117,8 +115,7 @@ end @testset "functions" begin x = -pi..pi - s = convert_arguments(Lines, x, sin) - xy = s.args[1] + (xy,) = convert_arguments(Lines, x, sin) @test xy[1][1] ≈ -pi @test xy[end][1] ≈ pi for (val, fval) in xy @@ -126,8 +123,7 @@ end end x = range(-pi, stop=pi, length=100) - s = convert_arguments(Lines, x, sin) - xy = s.args[1] + (xy,) = convert_arguments(Lines, x, sin) @test xy[1][1] ≈ -pi @test xy[end][1] ≈ pi for (val, fval) in xy @@ -300,7 +296,69 @@ end f, ax, pl = poly(Vector{Point2f}[]) pl[1] = [points] - @test pl.plots[1][1][] == Makie.poly_convert(points) + @test pl.plots[1][1][][1] == Makie.poly_convert(points) +end + +@testset "GridBased and ImageLike conversions" begin + # type tree + @test GridBased <: ConversionTrait + @test CellGrid <: GridBased + @test VertexGrid <: GridBased + @test ImageLike <: ConversionTrait + + # Plot to trait + @test conversion_trait(Image) === ImageLike() + @test conversion_trait(Heatmap) === CellGrid() + @test conversion_trait(Surface) === VertexGrid() + @test conversion_trait(Contour) === VertexGrid() + @test conversion_trait(Contourf) === VertexGrid() + + m1 = [x for x in 1:10, y in 1:6] + m2 = [y for x in 1:10, y in 1:6] + m3 = rand(10, 6) + + r1 = 1:10 + r2 = 1:6 + + v1 = collect(1:10) + v2 = collect(1:6) + + i1 = 1..10 + i2 = 1..6 + + o3 = Float32.(m3) + + # Conversions + @testset "ImageLike conversion" begin + @test convert_arguments(Image, m3) == (0f0..10f0, 0f0..6f0, o3) + @test convert_arguments(Image, v1, r2, m3) == (1f0..10f0, 1f0..6f0, o3) + @test convert_arguments(Image, i1, v2, m3) == (1f0..10f0, 1f0..6f0, o3) + @test_throws ErrorException convert_arguments(Image, m1, m2, m3) + @test_throws ErrorException convert_arguments(Heatmap, m1, m2) + end + + @testset "VertexGrid conversion" begin + vo1 = Float32.(v1) + vo2 = Float32.(v2) + mo1 = Float32.(m1) + mo2 = Float32.(m2) + @test convert_arguments(Surface, m3) == (vo1, vo2, o3) + @test convert_arguments(Contour, i1, v2, m3) == (vo1, vo2, o3) + @test convert_arguments(Contourf, v1, r2, m3) == (vo1, vo2, o3) + @test convert_arguments(Surface, m1, m2, m3) == (mo1, mo2, o3) + @test convert_arguments(Surface, m1, m2) == (mo1, mo2, zeros(Float32, size(o3))) + end + + @testset "CellGrid conversion" begin + o1 = Float32.(0.5:1:10.5) + o2 = Float32.(0.5:1:6.5) + @test convert_arguments(Heatmap, m3) == (o1, o2, o3) + @test convert_arguments(Heatmap, r1, i2, m3) == (o1, o2, o3) + @test convert_arguments(Heatmap, v1, r2, m3) == (o1, o2, o3) + @test convert_arguments(Heatmap, 0:10, v2, m3) == (collect(0f0:10f0), o2, o3) + @test_throws ErrorException convert_arguments(Heatmap, m1, m2, m3) + @test_throws ErrorException convert_arguments(Heatmap, m1, m2) + end end @testset "Triplot" begin @@ -382,4 +440,4 @@ end # sanity checks @test isapprox(Makie.angle2align(pi/4), Vec2f(1, 1), atol = 1e-12) @test isapprox(Makie.angle2align(5pi/4), Vec2f(0, 0), atol = 1e-12) -end \ No newline at end of file +end diff --git a/test/deprecated.jl b/test/deprecated.jl new file mode 100644 index 00000000000..8c0ef0db74e --- /dev/null +++ b/test/deprecated.jl @@ -0,0 +1,55 @@ +# @test_deprecated seems broken on 1.9 + 1.10 +macro depwarn_message(expr) + quote + logger = Test.TestLogger() + Base.with_logger(logger) do + $(esc(expr)) + end + if length(logger.logs) == 1 + return logger.logs[1].message + else + return nothing + end + end +end + +@testset "deprecations" begin + @testset "Scene" begin + # test that deprecated `resolution keyword still works but throws warning` + logger = Test.TestLogger() + Base.with_logger(logger) do + scene = Scene(; resolution=(999, 999), size=(123, 123)) + @test scene.viewport[] == Rect2i((0, 0), (999, 999)) + end + @test occursin("The `resolution` keyword for `Scene`s and `Figure`s has been deprecated", + logger.logs[1].message) + scene = Scene(; size=(600, 450)) + msg = @depwarn_message scene.px_area + @test occursin(".px_area` got renamed to `.viewport`, and means the area the scene maps to in device independent units", + msg) + # @test_deprecated seems to be broken on 1.10?! + msg = @depwarn_message pixelarea(scene) + # only works with depwarn on + @test occursin("`pixelarea` is deprecated, use `viewport` instead.", msg) + end + @testset "Plot -> Combined" begin + logger = Test.TestLogger() + msg = @depwarn_message Combined + @test occursin("Combined is deprecated", msg) + @test Combined == Plot + end + @testset "Surface Traits" begin + @test DiscreteSurface == CellGrid + @test ContinuousSurface == VertexGrid + msg = @depwarn_message DiscreteSurface() + @test occursin("DiscreteSurface is deprecated", msg) + msg = @depwarn_message ContinuousSurface() + @test occursin("ContinuousSurface is deprecated", msg) + end + @testset "AbstractVector ImageLike" begin + msg = @depwarn_message image(1:10, 1..10, zeros(10, 10)) + @test occursin("Encountered an `AbstractVector` with value 1:10 on side x", msg) + msg = @depwarn_message image(1..10, 1:10, zeros(10, 10)) + @test occursin("Encountered an `AbstractVector` with value 1:10 on side y", msg) + end +end diff --git a/test/events.jl b/test/events.jl index 7a8491080ac..41b7a94d440 100644 --- a/test/events.jl +++ b/test/events.jl @@ -135,7 +135,7 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right clipboard() = CLIP[] end @testset "copy_paste" begin - f = Figure(resolution=(640,480)) + f = Figure(size=(640,480)) tb = Textbox(f[1,1], placeholder="Copy/paste into me") e = events(f.scene) @@ -166,7 +166,7 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right # Refresh figure to test right control + v combination empty!(f) - f = Figure(resolution=(640,480)) + f = Figure(size=(640,480)) tb = Textbox(f[1,1], placeholder="Copy/paste into me") e = events(f.scene) @@ -196,11 +196,11 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right # This testset is based on the results the current camera system has. If # cam3d! is updated this is likely to break. @testset "cam3d!" begin - scene = Scene(resolution=(800, 600)); + scene = Scene(size=(800, 600)); e = events(scene) cam3d!(scene, fixed_axis=true, cad=false, zoom_shift_lookat=false) cc = cameracontrols(scene) - + # Verify initial camera state @test cc.lookat[] == Vec3f(0) @test cc.eyeposition[] == Vec3f(3) @@ -218,20 +218,20 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right # 2) Outside scene, in drag e.mouseposition[] = (1000, 450) @test cc.lookat[] ≈ Vec3f(0) - @test cc.eyeposition[] ≈ Vec3f(-2.8912058, -3.8524969, -1.9491522) + @test cc.eyeposition[] ≈ Vec3f(-2.8912058, -3.8524969, -1.9491514) @test cc.upvector[] ≈ Vec3f(-0.5050875, -0.6730229, 0.5403024) # 3) not in drag e.mousebutton[] = MouseButtonEvent(Mouse.left, Mouse.release) e.mouseposition[] = (400, 250) @test cc.lookat[] ≈ Vec3f(0) - @test cc.eyeposition[] ≈ Vec3f(-2.8912058, -3.8524969, -1.9491522) + @test cc.eyeposition[] ≈ Vec3f(-2.8912058, -3.8524969, -1.9491514) @test cc.upvector[] ≈ Vec3f(-0.5050875, -0.6730229, 0.5403024) # Reset state so this is indepentent from the last checks - scene = Scene(resolution=(800, 600)); + scene = Scene(size=(800, 600)); e = events(scene) cam3d!(scene, fixed_axis=true, cad=false, zoom_shift_lookat=false) cc = cameracontrols(scene) @@ -243,29 +243,30 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right # translation # 1) In scene, in drag + e.mouseposition[] = (400, 250) e.mousebutton[] = MouseButtonEvent(Mouse.right, Mouse.press) e.mouseposition[] = (600, 250) - @test cc.lookat[] ≈ Vec3f(5.4697413, -3.3484206, -2.1213205) - @test cc.eyeposition[] ≈ Vec3f(8.469742, -0.34842062, 0.8786795) + @test cc.lookat[] ≈ Vec3f(1.0146117, -1.0146117, 0.0) + @test cc.eyeposition[] ≈ Vec3f(4.0146117, 1.9853883, 3.0) @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) # 2) Outside scene, in drag e.mouseposition[] = (1000, 450) - @test cc.lookat[] ≈ Vec3f(9.257657, -5.4392805, -3.818377) - @test cc.eyeposition[] ≈ Vec3f(12.257658, -2.4392805, -0.81837714) + @test cc.lookat[] ≈ Vec3f(3.6296215, -2.4580488, -1.1715729) + @test cc.eyeposition[] ≈ Vec3f(6.6296215, 0.5419513, 1.8284271) @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) # 3) not in drag e.mousebutton[] = MouseButtonEvent(Mouse.right, Mouse.release) e.mouseposition[] = (400, 250) - @test cc.lookat[] ≈ Vec3f(9.257657, -5.4392805, -3.818377) - @test cc.eyeposition[] ≈ Vec3f(12.257658, -2.4392805, -0.81837714) + @test cc.lookat[] ≈ Vec3f(3.6296215, -2.4580488, -1.1715729) + @test cc.eyeposition[] ≈ Vec3f(6.6296215, 0.5419513, 1.8284271) @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) # Reset state - scene = Scene(resolution=(800, 600)); + scene = Scene(size=(800, 600)); e = events(scene) cam3d!(scene, fixed_axis=true, cad=false, zoom_shift_lookat=false) cc = cameracontrols(scene) @@ -274,26 +275,24 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right @test cc.lookat[] == Vec3f(0) @test cc.eyeposition[] == Vec3f(3) @test cc.upvector[] == Vec3f(0, 0, 1) - @test cc.zoom_mult[] == 1f0 # Zoom + e.mouseposition[] = (400, 250) # for debugging e.scroll[] = (0.0, 4.0) @test cc.lookat[] ≈ Vec3f(0) - @test cc.eyeposition[] ≈ Vec3f(3) + @test cc.eyeposition[] ≈ 0.6830134f0 * Vec3f(3) @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) - @test cc.zoom_mult[] ≈ 0.6830134f0 # should not work outside the scene e.mouseposition[] = (1000, 450) e.scroll[] = (0.0, 4.0) @test cc.lookat[] ≈ Vec3f(0) - @test cc.eyeposition[] ≈ Vec3f(3) + @test cc.eyeposition[] ≈ 0.6830134f0 * Vec3f(3) @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) - @test cc.zoom_mult[] ≈ 0.6830134f0 end @testset "mouse state machine" begin - scene = Scene(resolution=(800, 600)); + scene = Scene(size=(800, 600)); e = events(scene) bbox = Observable(Rect2(200, 200, 400, 300)) msm = addmouseevents!(scene, bbox, priority=typemax(Int)) @@ -444,7 +443,7 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right # TODO: test more @testset "Axis Interactions" begin - f = Figure(resolution = (400, 400)) + f = Figure(size = (400, 400)) a = Axis(f[1, 1]) e = events(f) diff --git a/test/figures.jl b/test/figures.jl index 4d844d115af..f9018b8b39f 100644 --- a/test/figures.jl +++ b/test/figures.jl @@ -62,6 +62,7 @@ end current_axis!(ax2) @test current_axis() === ax2 @test current_figure() === fig + end @testset "Deleting from figures" begin @@ -155,10 +156,10 @@ end end @testset "Figure and axis kwargs validation" begin - @test_throws ArgumentError lines(1:10, axis = (aspect = DataAspect()), figure = (resolution = (100, 100))) - @test_throws ArgumentError lines(1:10, figure = (resolution = (100, 100))) + @test_throws ArgumentError lines(1:10, axis = (aspect = DataAspect()), figure = (size = (100, 100))) + @test_throws ArgumentError lines(1:10, figure = (size = (100, 100))) @test_throws ArgumentError lines(1:10, axis = (aspect = DataAspect())) - + # these just shouldn't error lines(1:10, axis = (aspect = DataAspect(),)) lines(1:10, axis = Attributes(aspect = DataAspect())) @@ -167,4 +168,4 @@ end f = Figure() @test_throws ArgumentError lines(f[1, 1], 1:10, axis = (aspect = DataAspect())) @test_throws ArgumentError lines(f[1, 1][2, 2], 1:10, axis = (aspect = DataAspect())) -end \ No newline at end of file +end diff --git a/test/hist.jl b/test/hist.jl new file mode 100644 index 00000000000..96cbc15b01f --- /dev/null +++ b/test/hist.jl @@ -0,0 +1,16 @@ +@testset "Histogram plotting" begin + unequal_vec = [1; rand(2:9, rand(1:9))] + allequal_vec = fill(rand(1:9), rand(1:9)) + # normal range + @test_nowarn hist(0:rand(1:9)) + # initialize with unequal observable vector + v = Observable(unequal_vec) + @test_nowarn hist(v) + # change to allequal vector + @test_nowarn v[] = allequal_vec + # initialize with allequal observable vector + v = Observable(allequal_vec) + @test_nowarn hist(v) + # change to unequal vector + @test_nowarn v[] = unequal_vec +end diff --git a/test/makielayout.jl b/test/makielayout.jl index 4366a1081ff..29f2335bf26 100644 --- a/test/makielayout.jl +++ b/test/makielayout.jl @@ -115,6 +115,47 @@ end @test ax.finallimits[] == BBox(-5, 11, 5, 7) end +# issue 3240 +@testset "Axis limits 4-tuple" begin + fig = Figure() + ax = Axis(fig[1,1],limits=(0,600,0,15)) + xlims!(ax,100,400) + @test ax.limits[] == ((100,400),(0,15)) + xlims!() + @test ax.limits[] == ((nothing,nothing),(0,15)) + + ax = Axis(fig[1,1],limits=(0,600,0,15)) + ylims!(ax,1,13) + @test ax.limits[] == ((0,600),(1,13)) + ylims!() + @test ax.limits[] == ((0,600),(nothing,nothing)) + + ax = Axis(fig[1,1],limits=(0,600,0,15)) + limits!(ax,350,700,2,14) + @test ax.limits[] == ((350,700),(2,14)) +end + +@testset "Axis3 limits 6-tuple" begin + fig = Figure() + ax = Axis3(fig[1,1],limits=(0,1,0,2,0,3)) + xlims!(ax,1,2) + @test ax.limits[] == ((1,2),(0,2),(0,3)) + xlims!() + @test ax.limits[] == ((nothing,nothing),(0,2),(0,3)) + + ax = Axis3(fig[1,1],limits=(0,1,0,2,0,3)) + ylims!(ax,1,3) + @test ax.limits[] == ((0,1),(1,3),(0,3)) + ylims!() + @test ax.limits[] == ((0,1),(nothing,nothing),(0,3)) + + ax = Axis3(fig[1,1],limits=(0,1,0,2,0,3)) + zlims!(ax,1,5) + @test ax.limits[] == ((0,1),(0,2),(1,5)) + zlims!() + @test ax.limits[] == ((0,1),(0,2),(nothing,nothing)) +end + @testset "Colorbar plot object kwarg clash" begin for attr in (:colormap, :limits) f, ax, p = scatter(1:10, 1:10, color = 1:10, colorrange = (1, 10)) diff --git a/test/pipeline.jl b/test/pipeline.jl index 9412face4ff..6f18bc98729 100644 --- a/test/pipeline.jl +++ b/test/pipeline.jl @@ -30,16 +30,120 @@ end xmax = Observable{Any}([0.25, 0.5, 0.75, 1]) p = hlines!(ax, list, xmax = xmax, color = :blue) - @test getfield(p, :input_args)[1] === list + @test getfield(p, :args)[1] === list @test p.xmax === xmax fig end + +@testset "Figure / Axis / Gridposition creation test" begin + @testset "proper errors for wrongly used (non) mutating plot functions" begin + f = Figure() + x = range(0, 10, length=100) + @test_throws ErrorException scatter!(f[1, 1], x, sin) + @test_throws ErrorException scatter!(f[1, 2][1, 1], x, sin) + @test_throws ErrorException scatter!(f[1, 2][1, 2], x, sin) + + @test_throws ErrorException meshscatter!(f[2, 1], x, sin; axis=(type=Axis3,)) + @test_throws ErrorException meshscatter!(f[2, 2][1, 1], x, sin; axis=(type=Axis3,)) + @test_throws ErrorException meshscatter!(f[2, 2][1, 2], x, sin; axis=(type=Axis3,)) + + @test_throws ErrorException meshscatter!(f[3, 1], rand(Point3f, 10); axis=(type=LScene,)) + @test_throws ErrorException meshscatter!(f[3, 2][1, 1], rand(Point3f, 10); axis=(type=LScene,)) + @test_throws ErrorException meshscatter!(f[3, 2][1, 2], rand(Point3f, 10); axis=(type=LScene,)) + + sub = f[4, :] + f = Figure() + @test_throws ErrorException scatter(Axis(f[1, 1]), x, sin) + @test_throws ErrorException meshscatter(Axis3(f[1, 1]), x, sin) + @test_throws ErrorException meshscatter(LScene(f[1, 1]), rand(Point3f, 10)) + + f + end + + @testset "creating plot object for different (non) mutating plotting functions into figure" begin + f = Figure() + x = range(0, 10; length=100) + ax, pl = scatter(f[1, 1], x, sin) + @test ax isa Axis + @test pl isa AbstractPlot + + ax, pl = scatter(f[1, 2][1, 1], x, sin) + @test ax isa Axis + @test pl isa AbstractPlot + + ax, pl = scatter(f[1, 2][1, 2], x, sin) + @test ax isa Axis + @test pl isa AbstractPlot + + ax, pl = meshscatter(f[2, 1], x, sin; axis=(type=Axis3,)) + @test ax isa Axis3 + @test pl isa AbstractPlot + + ax, pl = meshscatter(f[2, 2][1, 1], x, sin; axis=(type=Axis3,)) + @test ax isa Axis3 + @test pl isa AbstractPlot + ax, pl = meshscatter(f[2, 2][1, 2], x, sin; axis=(type=Axis3,)) + @test ax isa Axis3 + @test pl isa AbstractPlot + + ax, pl = meshscatter(f[3, 1], rand(Point3f, 10); axis=(type=LScene,)) + @test ax isa LScene + @test pl isa AbstractPlot + ax, pl = meshscatter(f[3, 2][1, 1], rand(Point3f, 10); axis=(type=LScene,)) + @test ax isa LScene + @test pl isa AbstractPlot + ax, pl = meshscatter(f[3, 2][1, 2], rand(Point3f, 10); axis=(type=LScene,)) + @test ax isa LScene + @test pl isa AbstractPlot + + sub = f[4, :] + + pl = scatter!(Axis(sub[1, 1]), x, sin) + @test pl isa AbstractPlot + pl = meshscatter!(Axis3(sub[1, 2]), x, sin) + @test pl isa AbstractPlot + pl = meshscatter!(LScene(sub[1, 3]), rand(Point3f, 10)) + @test pl isa AbstractPlot + + f = Figure() + @test_throws ErrorException lines!(f, [1, 2]) + end +end + @testset "Cycled" begin # Test for https://github.com/MakieOrg/Makie.jl/issues/3266 f, ax, pl = lines(1:4; color=Cycled(2)) - cpalette = ax.palette[:color][] + cpalette = ax.scene.theme.palette[:color][] @test pl.calculated_colors[] == cpalette[2] pl2 = lines!(ax, 1:4; color=Cycled(1)) @test pl2.calculated_colors[] == cpalette[1] end + +function test_default(arg) + _, _, pl1 = plot(arg) + + fig = Figure() + _, pl2 = plot(fig[1, 1], arg) + + fig = Figure() + ax = Axis(fig[1, 1]) + pl3 = plot!(ax, arg) + return [pl1, pl2, pl3] +end + +@testset "plot defaults" begin + plots = test_default([10, 15, 20]) + @test all(x-> x isa Scatter, plots) + + plots = test_default(rand(4, 4)) + @test all(x -> x isa Heatmap, plots) + + poly = Polygon(decompose(Point, Circle(Point2f(0), 1.0f0))) + + plots = test_default(poly) + @test all(x -> x isa Poly, plots) + + plots = test_default(rand(4, 4, 4)) + @test all(x -> x isa Volume, plots) +end diff --git a/test/ray_casting.jl b/test/ray_casting.jl index ec88508ba18..73b5beaa20a 100644 --- a/test/ray_casting.jl +++ b/test/ray_casting.jl @@ -1,7 +1,7 @@ @testset "Ray Casting" begin @testset "View Rays" begin scene = Scene() - xy = 0.5 * widths(pixelarea(scene)[]) + xy = 0.5 * widths(viewport(scene)[]) orthographic_cam3d!(x) = cam3d!(x, perspectiveprojection = Makie.Orthographic) @@ -20,13 +20,13 @@ end - # transform() is used to apply a translation-rotation-scale matrix to rays + # transform() is used to apply a translation-rotation-scale matrix to rays # instead of point like data # Generate random point + transform rot = Makie.rotation_between(rand(Vec3f), rand(Vec3f)) model = Makie.transformationmatrix(rand(Vec3f), rand(Vec3f), rot) point = Point3f(1) + rand(Point3f) - + # Generate rate that passes through transformed point transformed = Point3f(model * Point4f(point..., 1)) direction = (1 + 10*rand()) * rand(Vec3f) @@ -71,76 +71,76 @@ end - # Note that these tests depend on the exact placement of plots and may + # Note that these tests depend on the exact placement of plots and may # error when cameras are adjusted @testset "position_on_plot()" begin - + # Lines (2D) & Linesegments (3D) ps = [exp(-0.01phi) * Point2f(cos(phi), sin(phi)) for phi in range(0, 20pi, length = 501)] - scene = Scene(resolution = (400, 400)) + scene = Scene(size = (400, 400)) p = lines!(scene, ps) cam2d!(scene) ray = Makie.Ray(scene, (325.0, 313.0)) pos = Makie.position_on_plot(p, 157, ray) @test pos ≈ Point3f(0.6087957666683925, 0.5513198993583837, 0.0) - - scene = Scene(resolution = (400, 400)) + + scene = Scene(size = (400, 400)) p = linesegments!(scene, ps) cam3d!(scene) ray = Makie.Ray(scene, (238.0, 233.0)) pos = Makie.position_on_plot(p, 178, ray) @test pos ≈ Point3f(-0.7850463447725504, -0.15125213957100314, 0.0) - - + + # Heatmap (2D) & Image (3D) - scene = Scene(resolution = (400, 400)) + scene = Scene(size = (400, 400)) p = heatmap!(scene, 0..1, -1..1, rand(10, 10)) cam2d!(scene) ray = Makie.Ray(scene, (228.0, 91.0)) pos = Makie.position_on_plot(p, 0, ray) @test pos ≈ Point3f(0.13999999, -0.54499996, 0.0) - - scene = Scene(resolution = (400, 400)) + + scene = Scene(size = (400, 400)) p = image!(scene, -1..1, -1..1, rand(10, 10)) cam3d!(scene) ray = Makie.Ray(scene, (309.0, 197.0)) pos = Makie.position_on_plot(p, 3, ray) @test pos ≈ Point3f(-0.7830243, 0.8614166, 0.0) - - + + # Mesh (3D) - scene = Scene(resolution = (400, 400)) + scene = Scene(size = (400, 400)) p = mesh!(scene, Rect3f(Point3f(0), Vec3f(1))) cam3d!(scene) ray = Makie.Ray(scene, (201.0, 283.0)) pos = Makie.position_on_plot(p, 15, ray) @test pos ≈ Point3f(0.029754717, 0.043159597, 1.0) - + # Surface (3D) - scene = Scene(resolution = (400, 400)) + scene = Scene(size = (400, 400)) p = surface!(scene, -2..2, -2..2, [sin(x) * cos(y) for x in -10:10, y in -10:10]) cam3d!(scene) ray = Makie.Ray(scene, (52.0, 238.0)) pos = Makie.position_on_plot(p, 57, ray) @test pos ≈ Point3f(0.80910987, -1.6090667, 0.137722) - + # Volume (3D) - scene = Scene(resolution = (400, 400)) + scene = Scene(size = (400, 400)) p = volume!(scene, rand(10, 10, 10)) cam3d!(scene) center!(scene) ray = Makie.Ray(scene, (16.0, 306.0)) pos = Makie.position_on_plot(p, 0, ray) - @test pos ≈ Point3f(10.0, 0.18444633, 9.989262) + @test pos ≈ Point3f(10.0, 0.08616829, 9.989262) end # For recreating the above: - #= + #= # Scene setup from tests: - scene = Scene(resolution = (400, 400)) + scene = Scene(size = (400, 400)) p = surface!(scene, -2..2, -2..2, [sin(x) * cos(y) for x in -10:10, y in -10:10]) cam3d!(scene) - + pos = Observable(Point3f(0.5)) on(events(scene).mousebutton, priority = 100) do event if event.button == Mouse.left && event.action == Mouse.press @@ -160,4 +160,4 @@ scene =# -end \ No newline at end of file +end diff --git a/test/runtests.jl b/test/runtests.jl index 6b0ce30ad40..929f8d4d473 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -18,6 +18,8 @@ using Makie: volume @test all(hi .>= (8,8,10)) end + include("deprecated.jl") + include("specapi.jl") include("primitives.jl") include("pipeline.jl") include("record.jl") @@ -29,11 +31,12 @@ using Makie: volume include("makielayout.jl") include("figures.jl") include("transformations.jl") - include("stack.jl") include("events.jl") include("text.jl") include("boundingboxes.jl") include("ray_casting.jl") include("PolarAxis.jl") - include("barplot_labels.jl") + include("barplot.jl") + include("bezier.jl") + include("hist.jl") end diff --git a/test/scenes.jl b/test/scenes.jl index b28a6dd51b8..a2c26e96b92 100644 --- a/test/scenes.jl +++ b/test/scenes.jl @@ -7,3 +7,59 @@ @test theme(nothing, :nonexistant, default=1) == 1 @test theme(scene, :nonexistant, default=1) == 1 end + +@testset "Lighting" begin + @testset "Shading default" begin + plot = (attributes = Attributes(), ) # simplified "plot" + + # Based on number of lights + lights = Makie.AbstractLight[] + Makie.default_shading!(plot, lights) + @test !haskey(plot.attributes, :shading) + + plot.attributes[:shading] = Observable(Makie.automatic) + Makie.default_shading!(plot, lights) + @test to_value(plot.attributes[:shading]) === NoShading + + plot.attributes[:shading] = Observable(Makie.automatic) + push!(lights, AmbientLight(RGBf(0.1, 0.1, 0.1))) + Makie.default_shading!(plot, lights) + @test to_value(plot.attributes[:shading]) === FastShading + + plot.attributes[:shading] = Observable(Makie.automatic) + push!(lights, DirectionalLight(RGBf(0.1, 0.1, 0.1), Vec3f(1))) + Makie.default_shading!(plot, lights) + @test to_value(plot.attributes[:shading]) === FastShading + + plot.attributes[:shading] = Observable(Makie.automatic) + push!(lights, PointLight(RGBf(0.1, 0.1, 0.1), Point3f(0))) + Makie.default_shading!(plot, lights) + @test to_value(plot.attributes[:shading]) === MultiLightShading + + # Based on light types + plot.attributes[:shading] = Observable(Makie.automatic) + lights = [SpotLight(RGBf(0.1, 0.1, 0.1), Point3f(0), Vec3f(1), Vec2f(0.2, 0.3))] + Makie.default_shading!(plot, lights) + @test to_value(plot.attributes[:shading]) === MultiLightShading + + plot.attributes[:shading] = Observable(Makie.automatic) + lights = [EnvironmentLight(1.0, rand(2,2))] + Makie.default_shading!(plot, lights) + @test to_value(plot.attributes[:shading]) === NoShading # only affects RPRMakie so skipped here + + plot.attributes[:shading] = Observable(Makie.automatic) + lights = [PointLight(RGBf(0.1, 0.1, 0.1), Point3f(0))] + Makie.default_shading!(plot, lights) + @test to_value(plot.attributes[:shading]) === MultiLightShading + + plot.attributes[:shading] = Observable(Makie.automatic) + lights = [PointLight(RGBf(0.1, 0.1, 0.1), Point3f(0), Vec2f(0.1, 0.2))] + Makie.default_shading!(plot, lights) + @test to_value(plot.attributes[:shading]) === MultiLightShading + + # keep existing shading type + lights = Makie.AbstractLight[] + Makie.default_shading!(plot, lights) + @test to_value(plot.attributes[:shading]) === MultiLightShading + end +end diff --git a/test/specapi.jl b/test/specapi.jl new file mode 100644 index 00000000000..3cff1e024ba --- /dev/null +++ b/test/specapi.jl @@ -0,0 +1,73 @@ +import Makie.SpecApi as S + +@testset "diffing" begin + @testset "update_plot!" begin + obs = Observable[] + oldspec = S.Scatter(1:4; cycle=[]) + newspec = S.Scatter(1:4; cycle=[]) + p = Makie.to_plot_object(newspec) + s = Scene() + plot!(s, p) + Makie.update_plot!(obs, p, oldspec, newspec) + @test isempty(obs) + + newspec = S.Scatter(1:4; color=:red) + Makie.update_plot!(obs, p, oldspec, newspec) + oldspec = newspec + @test length(obs) == 1 + @test obs[1] === p.color + + newspec = S.Scatter(1:4; color=:green, cycle=[]) + empty!(obs) + Makie.update_plot!(obs, p, oldspec, newspec) + oldspec = newspec + @test length(obs) == 1 + @test obs[1] === p.color + @test obs[1].val == to_color(:green) + + newspec = S.Scatter(1:5; color=:green, cycle=[]) + empty!(obs) + Makie.update_plot!(obs, p, oldspec, newspec) + oldspec = newspec + @test length(obs) == 1 + @test obs[1] === p.args[1] + + oldspec = S.Scatter(1:5; color=:green, marker=:rect, cycle=[]) + newspec = S.Scatter(1:4; color=:red, marker=:circle, cycle=[]) + empty!(obs) + p = Makie.to_plot_object(oldspec) + s = Scene() + plot!(s, p) + Makie.update_plot!(obs, p, oldspec, newspec) + @test length(obs) == 3 + @test obs[1] === p.args[1] + @test obs[2] === p.color + @test obs[3] === p.marker + end + + @testset "diff_plotlist!" begin + scene = Scene(); + plotspecs = [S.Scatter(1:4; color=:red), S.Scatter(1:4; color=:red)] + reusable_plots = IdDict{PlotSpec,Plot}() + obs_to_notify = Observable[] + new_plots = Makie.diff_plotlist!(scene, plotspecs, obs_to_notify, reusable_plots) + @test length(new_plots) == 2 + @test Set(scene.plots) == Set(values(new_plots)) + @test isempty(obs_to_notify) + + new_plots2 = Makie.diff_plotlist!(scene, plotspecs, obs_to_notify, new_plots) + + @test isempty(new_plots) # they got all used up + @test Set(scene.plots) == Set(values(new_plots2)) + @test isempty(obs_to_notify) + + plotspecs = [S.Scatter(1:4; color=:yellow), S.Scatter(1:4; color=:green)] + new_plots3 = Makie.diff_plotlist!(scene, plotspecs, obs_to_notify, new_plots2) + + @test isempty(new_plots) # they got all used up + @test Set(scene.plots) == Set(values(new_plots3)) + # TODO, and some point we should try to find the matching plot and just + # switch them, so we don't need an update! + @test Set(obs_to_notify) == Set([scene.plots[1].color, scene.plots[2].color]) + end +end diff --git a/test/stack.jl b/test/stack.jl deleted file mode 100644 index e03b5779a8b..00000000000 --- a/test/stack.jl +++ /dev/null @@ -1,38 +0,0 @@ -using Makie: stack_grouped_from_to - -@testset "grouped bar: stack" begin - x1 = [1, 1, 1, 1] - grp_dodge1 = [2, 2, 1, 1] - grp_stack1 = [1, 2, 1, 2] - y1 = [2, 3, -3, -2] - - x2 = [2, 2, 2, 2] - grp_dodge2 = [3, 4, 3, 4] - grp_stack2 = [3, 4, 3, 4] - y2 = [2, 3, -3, -2] - - from, to = stack_grouped_from_to(grp_stack1, y1, (; x1 = x1, grp_dodge1 = grp_dodge1)) - from1 = [0.0, 2.0, 0.0, -3.0] - to1 = [2.0, 5.0, -3.0, -5.0] - @test from == from1 - @test to == to1 - - from, to = stack_grouped_from_to(grp_stack2, y2, (; x2 = x2, grp_dodge2 = grp_dodge2)) - from2 = [0.0, 0.0, 0.0, 0.0] - to2 = [2.0, 3.0, -3.0, -2.0] - @test from == from2 - @test to == to2 - - perm = [1, 4, 2, 7, 5, 3, 8, 6] - x = [x1; x2][perm] - y = [y1; y2][perm] - grp_dodge = [grp_dodge1; grp_dodge2][perm] - grp_stack = [grp_stack1; grp_stack2][perm] - - from_test = [from1; from2][perm] - to_test = [to1; to2][perm] - - from, to = stack_grouped_from_to(grp_stack, y, (; x = x, grp_dodge = grp_dodge)) - @test from == from_test - @test to == to_test -end diff --git a/test/text.jl b/test/text.jl index c0b1f427eae..4881afa3a12 100644 --- a/test/text.jl +++ b/test/text.jl @@ -1,3 +1,20 @@ +@testset "texture atlas" begin + @testset "defaults" for arg in [(1024, 32), (2048, 64)] + # Makes sure hashing and downloading default texture atlas works: + atlas = Makie.get_texture_atlas(arg...) + data = copy(atlas.data) + len = length(atlas.mapping) + # Make sure that all default glyphs are already in there + Makie.render_default_glyphs!(atlas) + # So no rendering & no change of data should happen in default glyphs are present! + @test data == atlas.data + @test length(atlas.mapping) == len + + @test haskey(Makie.TEXTURE_ATLASES, arg) # gets into global texture atlas cache + @test Makie.TEXTURE_ATLASES[arg] === atlas + end +end + @testset "Glyph Collections" begin using Makie.FreeTypeAbstraction diff --git a/test/transformations.jl b/test/transformations.jl index 6033d5f3381..ff3366a9737 100644 --- a/test/transformations.jl +++ b/test/transformations.jl @@ -88,39 +88,49 @@ end end @testset "Polar Transform" begin - tf = Makie.Polar(false) - @test tf.theta_as_x == false + tf = Makie.Polar() + @test tf.theta_as_x == true + @test tf.clip_r == true @test tf.theta_0 == 0.0 @test tf.direction == 1 @test tf.r0 == 0.0 - input = Point2f.(1:6, [0, pi/3, pi/2, pi, 2pi, 3pi]) - output = [r * Point2f(cos(phi), sin(phi)) for (r, phi) in input] - inv = Point2f.(1:6, mod.([0, pi/3, pi/2, pi, 2pi, 3pi], (0..2pi,))) + input = Point2f.([0, pi/3, pi/2, pi, 2pi, 3pi], 1:6) + output = [r * Point2f(cos(phi), sin(phi)) for (phi, r) in input] + inv = Point2f.(mod.([0, pi/3, pi/2, pi, 2pi, 3pi], (0..2pi,)), 1:6) @test apply_transform(tf, input) ≈ output @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv - tf = Makie.Polar(false, pi/2) + tf = Makie.Polar(pi/2, 1, 0, false) + input = Point2f.(1:6, [0, pi/3, pi/2, pi, 2pi, 3pi]) output = [r * Point2f(cos(phi+pi/2), sin(phi+pi/2)) for (r, phi) in input] + inv = Point2f.(1:6, mod.([0, pi/3, pi/2, pi, 2pi, 3pi], (0..2pi,))) @test apply_transform(tf, input) ≈ output @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv - tf = Makie.Polar(false, pi/2, -1) + tf = Makie.Polar(pi/2, -1, 0, false) output = [r * Point2f(cos(-phi-pi/2), sin(-phi-pi/2)) for (r, phi) in input] @test apply_transform(tf, input) ≈ output @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv - tf = Makie.Polar(false, pi/2, -1, 0.5) + tf = Makie.Polar(pi/2, -1, 0.5, false) output = [(r - 0.5) * Point2f(cos(-phi-pi/2), sin(-phi-pi/2)) for (r, phi) in input] @test apply_transform(tf, input) ≈ output @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv - tf = Makie.Polar(true) + tf = Makie.Polar(0, 1, 0, true) input = Point2f.([0, pi/3, pi/2, pi, 2pi, 3pi], 1:6) output = [r * Point2f(cos(phi), sin(phi)) for (phi, r) in input] inv = Point2f.(mod.([0, pi/3, pi/2, pi, 2pi, 3pi], (0..2pi,)), 1:6) @test apply_transform(tf, input) ≈ output @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv + + tf = Makie.Polar(0, 1, 0, true, false) + input = Point2f.([0, pi/3, pi/2, pi, 2pi, 3pi], -6:-1) + output = [r * Point2f(cos(phi), sin(phi)) for (phi, r) in input] + inv = Point2f.(mod.([0, pi/3, pi/2, pi, 2pi, 3pi] .+ pi, (0..2pi,)), 6:-1:1) + @test apply_transform(tf, input) ≈ output + @test apply_transform(Makie.inverse_transform(tf), output) ≈ inv end @testset "Coordinate Systems" begin diff --git a/test/zoom_pan.jl b/test/zoom_pan.jl index 8a5a3e5daa7..5fd708e80df 100644 --- a/test/zoom_pan.jl +++ b/test/zoom_pan.jl @@ -4,7 +4,7 @@ using Observables function cleanaxes() fig = Figure() ax = Axis(fig[1, 1]) - axbox = pixelarea(ax.scene)[] + axbox = viewport(ax.scene)[] lim = ax.finallimits[] e = events(ax.scene) return ax, axbox, lim, e @@ -79,7 +79,7 @@ end fig = Figure() ax = Axis(fig[1, 1]) plot!(ax, [10, 15, 20]) - axbox = pixelarea(ax.scene)[] + axbox = viewport(ax.scene)[] lim = ax.finallimits[] e = events(ax.scene) diff --git a/tooling/bump_versions.jl b/tooling/bump_versions.jl index 430e684de54..752a44b1331 100644 --- a/tooling/bump_versions.jl +++ b/tooling/bump_versions.jl @@ -94,10 +94,10 @@ function bump_versions() new_toml["version"] = new_version compat = new_toml["compat"] - if haskey(compat, "Makie") + if haskey(new_versions, "Makie") compat["Makie"] = "=$(new_versions["Makie"])" end - if haskey(compat, "MakieCore") + if haskey(new_versions, "MakieCore") compat["MakieCore"] = "=$(new_versions["MakieCore"])" end