diff --git a/Project.toml b/Project.toml index 222a8c2..7505678 100644 --- a/Project.toml +++ b/Project.toml @@ -1,14 +1,13 @@ name = "WGLMakie" uuid = "276b4fcb-3e11-5398-bf8b-a0c2d153d008" authors = ["SimonDanisch "] -version = "0.1.14" +version = "0.2.0" [deps] AbstractPlotting = "537997a7-5e4e-5d89-9595-2241ea00577e" Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" -GeometryTypes = "4d00f742-c7ba-57c2-abde-4428a4b178cb" Hyperscript = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" ImageTransformations = "02fcd773-0e25-5acc-982a-7f6622650795" JSServe = "824d6782-a2ef-11e9-3a09-e5662e0c26f9" @@ -18,18 +17,19 @@ ShaderAbstractions = "65257c39-d410-5151-9873-9b3e5be5013e" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" [compat] -AbstractPlotting = "0.9.27" +AbstractPlotting = "0.10.1" Colors = "0.9, 0.10, 0.11, 0.12" FileIO = "1.1" -GeometryBasics = "0.1" -GeometryTypes = "0.7, 0.8" +GeometryBasics = "0.2.3" Hyperscript = "0.0.3" ImageTransformations = "0.7, 0.8" -JSServe = "0.4, 0.5" -MakieGallery = "0.1.10" -Observables = "0.2, 0.3" -ShaderAbstractions = "0.1.1" +MakieGallery = "0.2" +MeshIO = "0.4" +JSServe = "0.6" +Observables = "0.3" +ShaderAbstractions = "0.2.1" StaticArrays = "0.12, 0.1" +StatsMakie = "0.2" julia = "1.0" [extras] diff --git a/assets/line_segments.vert b/assets/line_segments.vert index b4a43d3..b02e927 100644 --- a/assets/line_segments.vert +++ b/assets/line_segments.vert @@ -3,9 +3,9 @@ uniform mat4 modelViewMatrix; #define AA_THICKNESS 2.0 -vec2 screen_space(vec4 vertex) +vec2 screen_space(vec4 position) { - return vec2(vertex.xy / vertex.w) * get_resolution(); + return vec2(position.xy / position.w) * get_resolution(); } vec3 tovec3(vec2 v){return vec3(v, 0.0);} vec3 tovec3(vec3 v){return v;} diff --git a/assets/mesh.vert b/assets/mesh.vert index fd531d5..3f8237e 100644 --- a/assets/mesh.vert +++ b/assets/mesh.vert @@ -15,7 +15,7 @@ vec4 tovec4(vec3 v){return vec4(v, 1.0);} vec4 tovec4(vec4 v){return v;} void main(){ - // get_* gets the global inputs (uniform, sampler, vertex array) + // get_* gets the global inputs (uniform, sampler, position array) // those functions will get inserted by the shader creation pipeline vec3 vertex_position = tovec3(get_position()); vec3 lightpos = get_lightposition(); @@ -24,10 +24,10 @@ void main(){ frag_lightdir = normalize(lightpos - position_world.xyz); // direction to camera frag_position = -position_world.xyz; - frag_uv = get_texturecoordinates(); + frag_uv = get_uv(); frag_uv = vec2(1.0 - frag_uv.y, frag_uv.x); frag_color = tovec4(get_color()); - // screen space coordinates of the vertex + // screen space coordinates of the position gl_Position = projectionMatrix * viewMatrix * position_world; } diff --git a/assets/particles.vert b/assets/particles.vert index b671961..6ed4d08 100644 --- a/assets/particles.vert +++ b/assets/particles.vert @@ -23,20 +23,23 @@ void rotate(vec4 q, inout vec3 V, inout vec3 N){ vec4 to_vec4(vec3 v3){return vec4(v3, 1.0);} vec4 to_vec4(vec4 v4){return v4;} +vec3 to_vec3(vec2 v3){return vec3(v3, 0.0);} +vec3 to_vec3(vec3 v4){return v4;} + void main(){ - // get_* gets the global inputs (uniform, sampler, vertex array) + // get_* gets the global inputs (uniform, sampler, position array) // those functions will get inserted by the shader creation pipeline vec3 vertex_position = get_markersize() * get_position(); vec3 lightpos = vec3(20,20,20); vec3 N = get_normals(); rotate(get_rotations(), vertex_position, N); - vertex_position = get_offset() + vertex_position; + vertex_position = to_vec3(get_offset()) + vertex_position; vec4 position_world = modelMatrix * 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; - // screen space coordinates of the vertex + // screen space coordinates of the position gl_Position = projectionMatrix * viewMatrix * position_world; } diff --git a/assets/simple.vert b/assets/simple.vert index a3726f3..c9d6c3d 100644 --- a/assets/simple.vert +++ b/assets/simple.vert @@ -43,6 +43,9 @@ float distancefield_scale(){ 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;} + mat2 diagm(vec2 v){ return mat2(v.x, 0.0, 0.0, v.y); } @@ -102,10 +105,10 @@ void main(){ float sprite_from_u_scale = abs(get_markersize().x); frag_uvscale = viewport_from_sprite_scale * sprite_from_u_scale; frag_distancefield_scale = distancefield_scale(); - frag_color = get_color(); - frag_uv = get_texturecoordinates(); + frag_color = tovec4(get_color()); + frag_uv = get_uv(); frag_uv_offset_width = get_uv_offset_width(); - // screen space coordinates of the vertex + // screen space coordinates of the position vec4 quad_vertex = (trans * vec4(2.0 * bbox_signed_radius * get_position(), 0.0, 0.0)); gl_Position = vclip + quad_vertex; } diff --git a/assets/volume.frag b/assets/volume.frag index 4f135f5..5fcc8b7 100644 --- a/assets/volume.frag +++ b/assets/volume.frag @@ -232,7 +232,7 @@ void main() { vec4 color; vec3 eye_unit = vec3(modelinv * vec4(eyeposition, 1)); - vec3 back_position = vec3(modelinv * vec4(frag_vert, 1)); + vec3 back_position = frag_vert; vec3 dir = normalize(eye_unit - back_position); // solve back_position + distance * dir == 1 // solve back_position + distance * dir == 0 diff --git a/assets/volume.vert b/assets/volume.vert index 8013df5..fe4e528 100644 --- a/assets/volume.vert +++ b/assets/volume.vert @@ -5,8 +5,8 @@ uniform mat4 projectionMatrix, viewMatrix, modelMatrix; void main() { + frag_vert = position; vec4 world_vert = modelMatrix * vec4(position, 1); - frag_vert = world_vert.xyz; o_light_dir = vec3(modelinv * vec4(get_lightposition(), 1)); gl_Position = projectionMatrix * viewMatrix * world_vert; } diff --git a/src/WGLMakie.jl b/src/WGLMakie.jl index 545b385..7648180 100644 --- a/src/WGLMakie.jl +++ b/src/WGLMakie.jl @@ -2,7 +2,7 @@ module WGLMakie using Hyperscript using JSServe, Observables, AbstractPlotting -using GeometryTypes, Colors +using Colors, GeometryBasics using ShaderAbstractions, LinearAlgebra import GeometryBasics @@ -14,8 +14,8 @@ using ShaderAbstractions: VertexArray, Buffer, Sampler, AbstractSampler using ShaderAbstractions: InstancedProgram import AbstractPlotting.FileIO using StaticArrays +using GeometryBasics: decompose_uv -import GeometryTypes: GLNormalMesh, GLPlainMesh using ImageTransformations struct WebGL <: ShaderAbstractions.AbstractContext end @@ -246,7 +246,8 @@ function three_display(session::Session, scene::Scene) width, height = size(scene) canvas = DOM.um("canvas", width = width, height = height) comm = Observable(Dict{String, Any}()) - threemod, renderer = JSObject(session, :THREE), JSObject(session, :renderer) + threemod = JSObject(session, THREE) + renderer = JSObject(session, :renderer) window = JSObject(session, :window) onload(session, canvas, js""" function threejs_module(canvas){ @@ -267,7 +268,6 @@ function three_display(session::Session, scene::Scene) renderer.setClearColor("#ff00ff"); renderer.setPixelRatio(ratio); - put_on_heap($(uuidstr(threemod)), $THREE); put_on_heap($(uuidstr(renderer)), renderer); put_on_heap($(uuidstr(window)), window); diff --git a/src/imagelike.jl b/src/imagelike.jl index 95cfeb4..601ab5f 100644 --- a/src/imagelike.jl +++ b/src/imagelike.jl @@ -30,7 +30,7 @@ function draw_mesh(jsctx, jsscene, mscene::Scene, mesh, name, plot; uniforms...) WebGL(), lasset("mesh.vert"), lasset("mesh.frag"), - VertexArray(mesh); + mesh; uniforms... ) @@ -46,28 +46,28 @@ function limits_to_uvmesh(plot) rectangle = lift(px, py) do x, y xmin, xmax = extrema(x) ymin, ymax = extrema(y) - SimpleRectangle(xmin, ymin, xmax - xmin, ymax - ymin) + Rect2D(xmin, ymin, xmax - xmin, ymax - ymin) end + positions = Buffer(lift(rectangle) do rect - ps = decompose(Point2f0, rect) - reinterpret(GeometryBasics.Point{2, Float32}, ps) + return decompose(Point2f0, rect) end) + faces = Buffer(lift(rectangle) do rect - tris = decompose(GLTriangle, rect) - convert(Vector{GeometryBasics.TriangleFace{Cuint}}, tris) - end) - uv = Buffer(lift(rectangle) do rect - decompose(UV{Float32}, rect) + return decompose(GLTriangleFace, rect) end) - vertices = GeometryBasics.meta( - positions; texturecoordinates = uv - ) - mesh = GeometryBasics.Mesh(vertices, faces) + + uv = Buffer(lift(decompose_uv, rectangle)) + + vertices = GeometryBasics.meta(positions; uv=uv) + + return GeometryBasics.Mesh(vertices, faces) end function draw_js(jsctx, jsscene, 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] + positions = Buffer(lift(px, py, pz) do x, y, z vec(map(CartesianIndices(z)) do i GeometryBasics.Point{3, Float32}( @@ -77,26 +77,32 @@ function draw_js(jsctx, jsscene, mscene::Scene, plot::Surface) ) end) end) + faces = Buffer(lift(pz) do z - tris = decompose(GLTriangle, SimpleRectangle(0f0, 0f0, 1f0, 1f0), size(z)) - convert(Vector{GeometryBasics.TriangleFace{Cuint}}, tris) + return decompose(GLTriangleFace, Rect2D(0f0, 0f0, 1f0, 1f0), size(z)) end) + uv = Buffer(lift(pz) do z - decompose(UV{Float32}, SimpleRectangle(0f0, 0f0, 1f0, 1f0), size(z)) + decompose_uv(Rect2D(0f0, 0f0, 1f0, 1f0), size(z)) end) + pcolor = if haskey(plot, :color) && plot.color[] isa AbstractArray plot.color else pz end + color = Sampler(lift( (args...)-> (array2color(args...)'), pcolor, plot.colormap, plot.colorrange )) + normals = Buffer(lift(surface_normals, px, py, pz)) + vertices = GeometryBasics.meta( - positions; texturecoordinates = uv, normals = normals + positions; uv=uv, normals=normals ) + mesh = GeometryBasics.Mesh(vertices, faces) draw_mesh(jsctx, jsscene, mscene, mesh, "surface", plot; @@ -138,7 +144,7 @@ end function draw_js(jsctx, jsscene, mscene::Scene, plot::Volume) x, y, z, vol = plot[1], plot[2], plot[3], plot[4] - box = ShaderAbstractions.VertexArray(GLPlainMesh(FRect3D(Vec3f0(0), Vec3f0(1)))) + box = GeometryBasics.mesh(FRect3D(Vec3f0(0), Vec3f0(1))) cam = cameracontrols(mscene) model2 = lift(plot.model, x, y, z) do m, xyz... mi = minimum.(xyz) @@ -156,6 +162,7 @@ function draw_js(jsctx, jsscene, mscene::Scene, plot::Volume) algorithm = lift(x-> Cuint(convert_attribute(x, key"algorithm"())), plot.algorithm) eyepos = getfield(mscene.camera, :eyeposition) + lightposition = lift(plot.lightposition, eyepos, typ=Vec3f0) do pos, eyepos ifelse(pos == :eyeposition, eyepos, pos)::Vec3f0 end @@ -172,7 +179,7 @@ function draw_js(jsctx, jsscene, mscene::Scene, plot::Volume) colorrange = lift(Vec2f0, plot.colorrange), isovalue = lift(Float32, plot.isovalue), isorange = lift(Float32, plot.isorange), - absorption = lift(Float32, plot.absorption), + absorption = lift(Float32, get(plot, :absorption, Observable(1f0))), algorithm = algorithm, eyeposition = eyepos, @@ -191,6 +198,6 @@ function draw_js(jsctx, jsscene, mscene::Scene, plot::Volume) on(model2) do model three_geom.matrix.set((model')...) end - three_geom.material.side = jsctx.FrontSide + three_geom.material.side = jsctx.BackSide jsscene.add(three_geom) end diff --git a/src/lines.jl b/src/lines.jl index ef79031..1c4db98 100644 --- a/src/lines.jl +++ b/src/lines.jl @@ -47,12 +47,10 @@ function create_shader(scene::Scene, plot::LineSegments) end uniforms[:resolution] = scene.camera.resolution - prim = GLUVMesh2D( - vertices = Vec2f0[(0, -1), (0, 1), (1, -1), (1, 1)], - texturecoordinates = UV{Float32}[(0,0), (0,0), (0,0), (0,0)], - faces = GLTriangle[(1, 2, 3), (2, 4, 3)] + instance = GeometryBasics.Mesh( + meta(Point2f0[(0, -1), (0, 1), (1, -1), (1, 1)], uv=Vec2f0[(0,0), (0,0), (0,0), (0,0)]), + GLTriangleFace[(1, 2, 3), (2, 4, 3)] ) - instance = VertexArray(prim) return InstancedProgram( WebGL(), lasset("line_segments.vert"), @@ -145,7 +143,14 @@ function jslines!(THREE, scene, plot, positions_nan, colors, linewidth, model, t // position_buffer.needsUpdate = true; }""") - geometry.computeBoundingSphere() + # ThreeJS does culling by calculating the boundingsphere + # But somehow it doesn't play well with our custom attributes. + # We just set it to a huge sphere, to not get them culled. + # Would be nice to just set them to null or so, but that's + # what triggers threejs to actually calculate the sphere + geometry.boundingSphere = THREE.new.Sphere() + geometry.boundingSphere.radius = 10000000000000f0 + mesh = THREE.new.LineSegments(geometry, material) mesh.matrixAutoUpdate = false; mesh.matrix.set(model[]...) diff --git a/src/meshes.jl b/src/meshes.jl index 51a96e9..299e61f 100644 --- a/src/meshes.jl +++ b/src/meshes.jl @@ -1,13 +1,10 @@ -vertexbuffer(x) = vertexbuffer(GeometryTypes.vertices(x)) - +vertexbuffer(x) = decompose(Point, x) vertexbuffer(x::Observable) = Buffer(lift(vertexbuffer, x)) -function vertexbuffer(x::AbstractArray{Point{N, T}}) where {N, T} - reinterpret(GeometryBasics.Point{N, T}, x) -end -facebuffer(x) = facebuffer(GeometryTypes.faces(x)) + +facebuffer(x) = facebuffer(GeometryBasics.faces(x)) facebuffer(x::Observable) = Buffer(lift(facebuffer, x)) -function facebuffer(x::AbstractArray{GLTriangle}) - convert(Vector{GeometryBasics.TriangleFace{Cuint}}, x) +function facebuffer(x::AbstractArray{GLTriangleFace}) + return x end function array2color(colors, cmap, crange) @@ -16,7 +13,7 @@ function array2color(colors, cmap, crange) end function array2color(colors::AbstractArray{<: Colorant}, cmap, crange) - RGBAf0.(colors) + return RGBAf0.(colors) end function converted_attribute(plot::AbstractPlot, key::Symbol) @@ -25,16 +22,17 @@ function converted_attribute(plot::AbstractPlot, key::Symbol) end end -function create_shader(scene::Scene, plot::Mesh) +function create_shader(scene::Scene, plot::AbstractPlotting.Mesh) # Potentially per instance attributes mesh_signal = plot[1] - mattributes = GeometryTypes.attributes - get_attribute(mesh, key) = lift(x-> mattributes(x)[key], mesh) + mattributes = GeometryBasics.attributes + get_attribute(mesh, key) = lift(x-> getproperty(x, key), mesh) data = mattributes(mesh_signal[]) uniforms = Dict{Symbol, Any}(); attributes = Dict{Symbol, Any}() + for (key, default) in ( - :texturecoordinates => Vec2f0(0), + :uv => Vec2f0(0), :normals => Vec3f0(0) ) if haskey(data, key) @@ -66,7 +64,7 @@ function create_shader(scene::Scene, plot::Mesh) attributes[:color] = Buffer(c_converted) # per vertex colors else uniforms[:uniform_color] = Sampler(c_converted) # Texture - !haskey(attributes, :texturecoordinates) && @warn "Mesh doesn't use Texturecoordinates, but has a Texture. Colors won't map" + !haskey(attributes, :uv) && @warn "Mesh doesn't use Texturecoordinates, but has a Texture. Colors won't map" end elseif color isa Colorant && !haskey(attributes, :color) uniforms[:uniform_color] = color_signal @@ -94,21 +92,19 @@ function create_shader(scene::Scene, plot::Mesh) faces = facebuffer(mesh_signal) positions = vertexbuffer(mesh_signal) - instance = GeometryBasics.Mesh( GeometryBasics.meta(positions; attributes...), faces ) - return Program( WebGL(), lasset("mesh.vert"), lasset("mesh.frag"), - VertexArray(instance); + instance; uniforms... ) end -function draw_js(jsctx, jsscene, scene::Scene, plot::Mesh) +function draw_js(jsctx, jsscene, scene::Scene, plot::AbstractPlotting.Mesh) program = create_shader(scene, plot) mesh = wgl_convert(scene, jsctx, program) debug_shader("mesh", program) diff --git a/src/particles.jl b/src/particles.jl index c788ea2..a1ee675 100644 --- a/src/particles.jl +++ b/src/particles.jl @@ -9,6 +9,7 @@ function handle_color!(uniform_dict, instance_dict) if color isa Colorant || color isa AbstractVector{<: Colorant} || color === nothing delete!(uniform_dict, :colormap) elseif color isa AbstractArray{<:Real} + udict[:color] = lift(x-> convert(Vector{Float32}, x), udict[:color]) uniform_dict[:color_getter] = """ vec4 get_color(){ vec2 norm = get_colorrange(); @@ -51,10 +52,12 @@ function create_shader(scene::Scene, plot::MeshScatter) handle_color!(uniform_dict, per_instance) - instance = VertexArray(map(GLNormalMesh, plot.marker)) - if !GeometryBasics.hascolumn(instance, :texturecoordinate) - uniform_dict[:texturecoordinate] = Vec2f0(0) + instance = normal_mesh(plot.marker[]) + + if !hasproperty(instance, :uv) + uniform_dict[:uv] = Vec2f0(0) end + for key in (:view, :projection, :resolution, :eyeposition, :projectionview) uniform_dict[key] = getfield(scene.camera, key) end @@ -71,18 +74,21 @@ end @enum Shape CIRCLE RECTANGLE ROUNDED_RECTANGLE DISTANCEFIELD TRIANGLE -primitive_shape(::Union{String, Char}) = Cint(DISTANCEFIELD) + +primitive_shape(::Union{String, Char, Vector{Char}}) = Cint(DISTANCEFIELD) primitive_shape(x::X) where X = Cint(primitive_shape(X)) primitive_shape(::Type{<: Circle}) = Cint(CIRCLE) -primitive_shape(::Type{<: SimpleRectangle}) = Cint(RECTANGLE) -primitive_shape(::Type{<: HyperRectangle{2}}) = Cint(RECTANGLE) +primitive_shape(::Type{<: Rect2D}) = Cint(RECTANGLE) +primitive_shape(::Type{T}) where T = error("Type $(T) not supported") primitive_shape(x::Shape) = Cint(x) +using AbstractPlotting: to_spritemarker + function scatter_shader(scene::Scene, attributes) # Potentially per instance attributes per_instance_keys = (:offset, :rotations, :markersize, :color, :intensity, :uv_offset_width, :marker_offset) uniform_dict = Dict{Symbol, Any}() - if haskey(attributes, :marker) && attributes[:marker][] isa String + if haskey(attributes, :marker) && attributes[:marker][] isa Union{Vector{Char}, String} x = pop!(attributes, :marker) attributes[:uv_offset_width] = lift(x-> AbstractPlotting.glyph_uv_width!.(collect(x)), x) uniform_dict[:shape_type] = Cint(3) @@ -90,22 +96,27 @@ function scatter_shader(scene::Scene, attributes) per_instance = filter(attributes) do (k, v) k in per_instance_keys && !(isscalar(v[])) end + for (k, v) in per_instance per_instance[k] = Buffer(lift_convert(k, v, nothing)) end + uniforms = filter(attributes) do (k, v) (!haskey(per_instance, k)) && isscalar(v[]) end + ignore_keys = ( :shading, :overdraw, :rotation, :distancefield, :fxaa, :visible, :transformation, :alpha, :linewidth, :transparency, :marker ) - for (k,v) in uniforms + + for (k, v) in uniforms k in ignore_keys && continue uniform_dict[k] = lift_convert(k, v, nothing) end + get!(uniform_dict, :shape_type) do - lift(x-> primitive_shape(AbstractPlotting.to_spritemarker(x)), attributes[:marker]) + lift(x-> primitive_shape(to_spritemarker(x)), attributes[:marker]) end if uniform_dict[:shape_type][] == 3 atlas = AbstractPlotting.get_texture_atlas() @@ -120,10 +131,11 @@ function scatter_shader(scene::Scene, attributes) uniform_dict[:atlas_texture_size] = 0f0 uniform_dict[:distancefield] = Observable(false) end + if !haskey(per_instance, :uv_offset_width) get!(uniform_dict, :uv_offset_width) do - if haskey(attributes, :marker) && attributes[:marker][] isa Char - lift(AbstractPlotting.glyph_uv_width!, attributes[:marker]) + if haskey(attributes, :marker) && to_spritemarker(attributes[:marker][]) isa Char + lift(x-> AbstractPlotting.glyph_uv_width!(to_spritemarker(x)), attributes[:marker]) else Vec4f0(0) end @@ -142,7 +154,7 @@ function scatter_shader(scene::Scene, attributes) handle_color!(uniform_dict, per_instance) - instance = VertexArray(GLUVMesh2D(GeometryTypes.SimpleRectangle(-0.5f0, -0.5f0, 1f0, 1f0))) + instance = VertexArray(uv_mesh(Rect2D(-0.5f0, -0.5f0, 1f0, 1f0))) for key in (:resolution,)#(:view, :projection, :resolution, :eyeposition, :projectionview) uniform_dict[key] = getfield(scene.camera, key) @@ -173,7 +185,7 @@ function create_shader(scene::Scene, plot::Scatter) end attributes = copy(plot.attributes.attributes) attributes[:offset] = plot[1] - attributes[:billboard] = Observable(true) + attributes[:billboard] = map(rot-> isa(rot, Billboard), plot.rotations) attributes[:pixelspace] = getfield(scene.camera, :pixel_space) delete!(attributes, :uv_offset_width) return scatter_shader(scene, attributes) diff --git a/src/webgl.jl b/src/webgl.jl index 2ccfc77..451b22f 100644 --- a/src/webgl.jl +++ b/src/webgl.jl @@ -1,7 +1,6 @@ using Colors using ShaderAbstractions: InstancedProgram, Program using AbstractPlotting: Key, plotkey -using GeometryTypes: Mat4f0 using Colors: N0f8 tlength(T) = length(T) @@ -23,6 +22,10 @@ function JSServe.serialize_readable(io::IO, jso::JSBuffer) return JSServe.serialize_readable(io, jsbuffer(jso)) end +function JSServe.serialize2string(io::IO, data_dependencies::Vector{Any}, jso::JSBuffer) + return JSServe.serialize2string(io, data_dependencies, jsbuffer(jso)) +end + function Base.setindex!(x::JSBuffer{T}, value::T, index::Int) where T setindex!(x, [value], index:(index+1)) end @@ -103,7 +106,7 @@ end function jl2js(jsctx, color::Sampler{T, 2}) where T # cache texture by their pointer key = reinterpret(UInt, objectid(color.data)) - return get!(jsctx.session_cache, key) do + tex = get!(jsctx.session_cache, key) do data = to_js_buffer(jsctx, color.data) tex = jsctx.THREE.new.DataTexture( @@ -115,7 +118,6 @@ function jl2js(jsctx, color::Sampler{T, 2}) where T tex.wrapS = three_repeat(jsctx, color.repeat[1]) tex.wrapT = three_repeat(jsctx, color.repeat[2]) tex.anisotropy = color.anisotropic - tex.needsUpdate = true # TODO propperly connect on(ShaderAbstractions.updater(color).update) do (f, args) if args[2] isa Colon && f == setindex! @@ -126,6 +128,8 @@ function jl2js(jsctx, color::Sampler{T, 2}) where T end return tex end + tex.needsUpdate = true + return tex end function jl2js(jsctx, color::Sampler{T, 3}) where T @@ -294,17 +298,24 @@ function lift_convert(key, value, plot) end end +function Base.pairs(mesh::GeometryBasics.Mesh) + return GeometryBasics.attributes(mesh) +end + +function GeometryBasics.faces(x::VertexArray) + return GeometryBasics.faces(getfield(x, :data)) +end + function wgl_convert(scene, THREE, ip::InstancedProgram) js_vbo = THREE.new.InstancedBufferGeometry() for (name, buff) in pairs(ip.program.vertexarray) js_buff = JSBuffer(THREE, buff) js_vbo.setAttribute(name, js_buff) end - indices = GeometryBasics.faces(getfield(ip.program.vertexarray, :data)) - indices = reinterpret(UInt32, indices) .- UInt32(1) + indices = GeometryBasics.faces(ip.program.vertexarray) + indices = reinterpret(UInt32, indices) js_vbo.setIndex(indices) js_vbo.maxInstancedCount = length(ip.per_instance) - # per instance data for (name, buff) in pairs(ip.per_instance) js_buff = JSInstanceBuffer(THREE, buff) @@ -312,14 +323,15 @@ function wgl_convert(scene, THREE, ip::InstancedProgram) end uniforms = to_js_uniforms(scene, THREE, ip.program.uniforms) - + js_vbo.boundingSphere = THREE.new.Sphere() + # don't use intersection / culling + js_vbo.boundingSphere.radius = 10000000000000f0 material = create_material( THREE, ip.program.vertex_source, ip.program.fragment_source, uniforms ) - js_vbo.computeBoundingSphere(); mesh = THREE.new.Mesh(js_vbo, material) end @@ -331,29 +343,29 @@ function wgl_convert(scene, jsctx, program::Program) js_vbo.setAttribute(name, js_buff) end - indices = GeometryBasics.faces(getfield(program.vertexarray, :data)) - indices = reinterpret(UInt32, indices) .- UInt32(1) + indices = GeometryBasics.faces(program.vertexarray) + indices = reinterpret(UInt32, indices) js_vbo.setIndex(indices) - # per instance data uniforms = to_js_uniforms(scene, jsctx, program.uniforms) - + # don't use intersection / culling + js_vbo.boundingSphere = jsctx.new.Sphere() + js_vbo.boundingSphere.radius = 10000000000000f0 material = create_material( jsctx.THREE, program.vertex_source, program.fragment_source, uniforms ) - js_vbo.computeBoundingSphere(); return jsctx.THREE.new.Mesh(js_vbo, material) end function debug_shader(name, program) - # dir = joinpath(@__DIR__, "..", "debug") - # isdir(dir) || mkdir(dir) - # write(joinpath(dir, "$(name).frag"), program.fragment_source) - # write(joinpath(dir, "$(name).vert"), program.vertex_source) + dir = joinpath(@__DIR__, "..", "debug") + isdir(dir) || mkdir(dir) + write(joinpath(dir, "$(name).frag"), program.fragment_source) + write(joinpath(dir, "$(name).vert"), program.vertex_source) end function update_model!(geom, plot) diff --git a/test/runtests.jl b/test/runtests.jl index 65c37c7..3f2e3a1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,8 +5,6 @@ ElectronDisplay.CONFIG.focus = false using WGLMakie, AbstractPlotting, JSServe, Test using MakieGallery -win = ElectronDisplay.electrondisplay(scatter(0..1, 1:50, markersize=4px)) -ElectronDisplay.Electron.toggle_devtools(win) tests_wgl_makie = Set(Symbol.([ "twisty_cube_thing", @@ -22,7 +20,8 @@ tests_wgl_makie = Set(Symbol.([ "fem_mesh_2d", "fem_mesh_3d", "fem_polygon_2d", - "fluctuation_3d", + # how did fluctuation_3d ever work? + # "fluctuation_3d", "heatmap_1", "image_1", "image_on_geometry__earth_",