Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

actually update texture atlas on change #3737

Merged
merged 5 commits into from Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -9,6 +9,7 @@
- Added `scale` attribute to `violin` [#3352](https://github.com/MakieOrg/Makie.jl/pull/3352).
- Use label formatter in barplot [#3718](https://github.com/MakieOrg/Makie.jl/pull/3718).
- Fix the incorrect shading with non uniform markerscale in meshscatter [#3722](https://github.com/MakieOrg/Makie.jl/pull/3722)
- Fixed an issue with the texture atlas not updating in WGLMakie after display, causing new symbols to not show up [#3737](https://github.com/MakieOrg/Makie.jl/pull/3737)

## [0.20.8] - 2024-02-22

Expand Down
12 changes: 12 additions & 0 deletions ReferenceTests/src/tests/text.jl
Expand Up @@ -368,3 +368,15 @@ end
ax.zlabel[] = L"\sum_{n=1}^{\infty} 2^{-n} = 1"
fig
end

# test #3232
@reference_test "texture atlas update" begin
scene = Scene(size = (250, 100))
campixel!(scene)
p = text!(scene, "test", fontsize = 85)
st = Stepper(scene)
Makie.step!(st)
p[1][] = "-!ħ█?-" # "!ħ█?" are all new symbols
Makie.step!(st)
st
end
15 changes: 8 additions & 7 deletions WGLMakie/src/Lines.js
Expand Up @@ -178,8 +178,8 @@ function lines_fragment_shader(uniforms, attributes) {
`;
}

function create_line_material(uniforms, attributes) {
const uniforms_des = deserialize_uniforms(uniforms);
function create_line_material(scene, uniforms, attributes) {
const uniforms_des = deserialize_uniforms(scene, uniforms);
const mat = new THREE.RawShaderMaterial({
uniforms: uniforms_des,
glslVersion: THREE.GLSL3,
Expand Down Expand Up @@ -278,7 +278,7 @@ function attach_updates(mesh, buffers, attributes, is_segments) {
}
}

export function _create_line(line_data, is_segments) {
export function _create_line(scene, line_data, is_segments) {
const geometry = create_line_instance_geometry();
const buffers = {};
create_line_buffers(
Expand All @@ -288,6 +288,7 @@ export function _create_line(line_data, is_segments) {
is_segments
);
const material = create_line_material(
scene,
line_data.uniforms,
geometry.attributes
);
Expand All @@ -301,10 +302,10 @@ export function _create_line(line_data, is_segments) {
return mesh;
}

export function create_line(line_data) {
return _create_line(line_data, false)
export function create_line(scene, line_data) {
return _create_line(scene, line_data, false)
}

export function create_linesegments(line_data) {
return _create_line(line_data, true)
export function create_linesegments(scene, line_data) {
return _create_line(scene, line_data, true)
}
84 changes: 55 additions & 29 deletions WGLMakie/src/Serialization.js
Expand Up @@ -63,8 +63,8 @@ export function delete_plots(plot_uuids) {
plots.forEach(delete_plot);
}

function convert_texture(data) {
const tex = create_texture(data);
function convert_texture(scene, data) {
const tex = create_texture(scene, data);
tex.needsUpdate = true;
tex.minFilter = THREE[data.minFilter];
tex.magFilter = THREE[data.magFilter];
Expand All @@ -88,10 +88,10 @@ function is_three_fixed_array(value) {
);
}

function to_uniform(data) {
function to_uniform(scene, data) {
if (data.type !== undefined) {
if (data.type == "Sampler") {
return convert_texture(data);
return convert_texture(scene, data);
}
throw new Error(`Type ${data.type} not known`);
}
Expand Down Expand Up @@ -120,7 +120,7 @@ function to_uniform(data) {
return data;
}

export function deserialize_uniforms(data) {
export function deserialize_uniforms(scene, data) {
const result = {};
// Deno may change constructor names..so...

Expand All @@ -132,28 +132,28 @@ export function deserialize_uniforms(data) {
// nothing needs to be converted
result[name] = value;
} else {
const ser = to_uniform(value);
const ser = to_uniform(scene, value);
result[name] = new THREE.Uniform(ser);
}
}
return result;
}

export function deserialize_plot(data) {
export function deserialize_plot(scene, data) {
let mesh;
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);
mesh = create_line(scene, data);
} else if (data.plot_type === "linesegments") {
mesh = create_linesegments(data);
mesh = create_linesegments(scene, data);
} else if ("instance_attributes" in data) {
mesh = create_instanced_mesh(data);
mesh = create_instanced_mesh(scene, data);
} else {
mesh = create_mesh(data);
mesh = create_mesh(scene, data);
}
mesh.name = data.name;
mesh.frustumCulled = false;
Expand Down Expand Up @@ -225,7 +225,7 @@ export function add_plot(scene, plot_data) {
});
}

const p = deserialize_plot(plot_data);
const p = deserialize_plot(scene, plot_data);
plot_cache[p.plot_uuid] = p;
scene.add(p);
// execute all next insert callbacks
Expand Down Expand Up @@ -276,8 +276,8 @@ function convert_RGB_to_RGBA(rgbArray) {
return rgbaArray;
}

function create_texture(data) {
const buffer = data.data;
function create_texture_from_data(data) {
let buffer = data.data;
if (data.size.length == 3) {
const tex = new THREE.Data3DTexture(
buffer,
Expand All @@ -289,20 +289,13 @@ function create_texture(data) {
tex.type = THREE[data.three_type];
return tex;
} else {
// a little optimization to not send the texture atlas over & over again
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);
buffer = convert_RGB_to_RGBA(buffer);
format = THREE.RGBAFormat;
}
return new THREE.DataTexture(
tex_data,
buffer,
data.size[0],
data.size[1],
format,
Expand All @@ -311,6 +304,39 @@ function create_texture(data) {
}
}

function create_texture(scene, data) {
const buffer = data.data;
// we allow to have a global texture atlas which gets only uploaded once to the browser
// it's not the nicest way, but by setting buffer to "texture_atlas" on the julia side
// instead of actual data, we just get the texture atlas from the global.
// Special care has to be taken to deregister the callback when the context gets destroyed
// Since TEXTURE_ATLAS uses "Bonito.Retain" and will live for the whole browser session.
if (buffer == "texture_atlas") {
const {texture_atlas} = scene.screen
if (texture_atlas) {
return texture_atlas;
} else {
data.data = TEXTURE_ATLAS[0].value
const texture = create_texture_from_data(data);
scene.screen.texture_atlas = texture;
TEXTURE_ATLAS[0].on((new_data) => {
if (new_data === texture) {
// if the data is our texture, it means the WGL context got destroyed and we want to deregister
// TODO, better Observables.js API for this
return false; // deregisters the callback
} else {
texture.image.data.set(new_data);
texture.needsUpdate = true;
return
}
});
return texture;
}
} else {
return create_texture_from_data(data);
}
}

function re_create_texture(old_texture, buffer, size) {
let tex;
if (size.length == 3) {
Expand Down Expand Up @@ -417,10 +443,10 @@ function recreate_instanced_geometry(mesh) {
mesh.needsUpdate = true;
}

function create_material(program) {
function create_material(scene, program) {
const is_volume = "volumedata" in program.uniforms;
return new THREE.RawShaderMaterial({
uniforms: deserialize_uniforms(program.uniforms),
uniforms: deserialize_uniforms(scene, program.uniforms),
vertexShader: program.vertex_source,
fragmentShader: program.fragment_source,
side: is_volume ? THREE.BackSide : THREE.DoubleSide,
Expand All @@ -431,24 +457,24 @@ function create_material(program) {
});
}

function create_mesh(program) {
function create_mesh(scene, program) {
const buffer_geometry = new THREE.BufferGeometry();
const faces = new THREE.BufferAttribute(program.faces.value, 1);
attach_geometry(buffer_geometry, program.vertexarrays, faces);
const material = create_material(program);
const material = create_material(scene, program);
const mesh = new THREE.Mesh(buffer_geometry, material);
program.faces.on((x) => {
mesh.geometry.setIndex(new THREE.BufferAttribute(x, 1));
});
return mesh;
}

function create_instanced_mesh(program) {
function create_instanced_mesh(scene, program) {
const buffer_geometry = new THREE.InstancedBufferGeometry();
const faces = new THREE.BufferAttribute(program.faces.value, 1);
attach_geometry(buffer_geometry, program.vertexarrays, faces);
attach_instanced_geometry(buffer_geometry, program.instance_attributes);
const material = create_material(program);
const material = create_material(scene, program);
const mesh = new THREE.Mesh(buffer_geometry, material);
program.faces.on((x) => {
mesh.geometry.setIndex(new THREE.BufferAttribute(x, 1));
Expand Down
3 changes: 2 additions & 1 deletion WGLMakie/src/WGLMakie.jl
Expand Up @@ -78,7 +78,8 @@ function __init__()
atlas = wgl_texture_atlas()
TEXTURE_ATLAS[] = convert(Vector{Float32}, vec(atlas.data))
Makie.font_render_callback!(atlas) do sd, uv
TEXTURE_ATLAS[] = convert(Vector{Float32}, vec(wgl_texture_atlas().data))
TEXTURE_ATLAS[] = convert(Vector{Float32}, vec(atlas.data))
return
end
DISABLE_JS_FINALZING[] = false
return
Expand Down