Skip to content

Commit

Permalink
Merge branch 'master' into jk/mesh-example
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonDanisch authored Jul 19, 2023
2 parents 5f9c079 + 4224c08 commit 94bab3a
Show file tree
Hide file tree
Showing 59 changed files with 1,222 additions and 1,126 deletions.
53 changes: 15 additions & 38 deletions CairoMakie/src/primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio
space = to_value(get(primitive, :space, :data))
projected_positions = project_position.(Ref(scene), (Makie.transform_func(primitive),), Ref(space), positions, Ref(model))

color = to_cairo_color(color, primitive)
color = to_color(primitive.calculated_colors[])

# color is now a color or an array of colors
# if it's an array of colors, each segment must be stroked separately
Expand Down Expand Up @@ -208,18 +208,18 @@ end
################################################################################

function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Scatter))
fields = @get_attribute(primitive, (color, markersize, strokecolor, strokewidth, marker, marker_offset, rotations))
fields = @get_attribute(primitive, (markersize, strokecolor, strokewidth, marker, marker_offset, rotations))
@get_attribute(primitive, (transform_marker,))

ctx = screen.context
model = primitive[:model][]
model = primitive.model[]
positions = primitive[1][]
isempty(positions) && return
size_model = transform_marker ? model : Mat4f(I)

font = to_font(to_value(get(primitive, :font, Makie.defaultfont())))

colors = to_cairo_color(color, primitive)
colors = to_color(primitive.calculated_colors[])

markerspace = to_value(get(primitive, :markerspace, :pixel))
space = to_value(get(primitive, :space, :data))
Expand Down Expand Up @@ -392,7 +392,7 @@ function draw_marker(ctx, marker::Matrix{T}, pos, scale,

# convert marker to Cairo compatible image data
marker = permutedims(marker, (2,1))
marker_surf = to_cairo_image(marker, ())
marker_surf = to_cairo_image(marker)

w, h = size(marker)

Expand Down Expand Up @@ -640,7 +640,7 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio
use_fast_path = can_use_fast_path && !disable_fast_path

if use_fast_path
s = to_cairo_image(image, primitive)
s = to_cairo_image(to_color(primitive.calculated_colors[]))

weird_cairo_limit = (2^15) - 23
if s.width > weird_cairo_limit || s.height > weird_cairo_limit
Expand All @@ -663,7 +663,7 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio
# this already takes care of flipping the image to correct cairo orientation
space = to_value(get(primitive, :space, :data))
xys = project_position.(scene, (Makie.transform_func(primitive),), space, [Point2f(x, y) for x in xs, y in ys], (model,))
colors = to_rgba_image(image, primitive)
colors = to_color(primitive.calculated_colors[])

# Note: xs and ys should have size ni+1, nj+1
ni, nj = size(image)
Expand Down Expand Up @@ -728,23 +728,12 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki
end

function draw_mesh2D(scene, screen, @nospecialize(plot), @nospecialize(mesh))
@get_attribute(plot, (color,))
color = to_color(hasproperty(mesh, :color) ? mesh.color : color)
vs = decompose(Point2f, mesh)::Vector{Point2f}
fs = decompose(GLTriangleFace, mesh)::Vector{GLTriangleFace}
uv = decompose_uv(mesh)::Union{Nothing, Vector{Vec2f}}
model = plot.model[]::Mat4f
colormap = haskey(plot, :colormap) ? to_colormap(plot.colormap[]) : nothing
colorrange = convert_attribute(to_value(get(plot, :colorrange, nothing)), key"colorrange"())::Union{Nothing, Vec2f}

lowclip = get_color_attr(plot, :lowclip)
highclip = get_color_attr(plot, :highclip)
nan_color = get_color_attr(plot, :nan_color)

cols = per_face_colors(
color, colormap, colorrange, nothing, fs, nothing, uv,
lowclip, highclip, nan_color)

color = hasproperty(mesh, :color) ? to_color(mesh.color) : plot.calculated_colors[]
cols = per_face_colors(color, nothing, fs, nothing, uv)
space = to_value(get(plot, :space, :data))::Symbol
transform_func = Makie.transform_func(plot)
return draw_mesh2D(scene, screen, cols, space, transform_func, vs, fs, model)
Expand Down Expand Up @@ -791,24 +780,16 @@ function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f
# Priorize colors of the mesh if present
@get_attribute(attributes, (color,))

colormap = haskey(attributes, :colormap) ? to_colormap(attributes.colormap[]) : nothing
colorrange = convert_attribute(to_value(get(attributes, :colorrange, nothing)), key"colorrange"())::Union{Nothing, Vec2f}
matcap = to_value(get(attributes, :matcap, nothing))

color = hasproperty(mesh, :color) ? mesh.color : color
meshpoints = decompose(Point3f, mesh)::Vector{Point3f}
meshfaces = decompose(GLTriangleFace, mesh)::Vector{GLTriangleFace}
meshnormals = decompose_normals(mesh)::Vector{Vec3f}
meshuvs = texturecoordinates(mesh)::Union{Nothing, Vector{Vec2f}}

lowclip = get_color_attr(attributes, :lowclip)
highclip = get_color_attr(attributes, :highclip)
nan_color = get_color_attr(attributes, :nan_color)
color = hasproperty(mesh, :color) ? mesh.color : to_value(attributes.calculated_colors)

per_face_col = per_face_colors(
color, colormap, colorrange, matcap, meshfaces, meshnormals, meshuvs,
lowclip, highclip, nan_color
)
per_face_col = per_face_colors(color, matcap, meshfaces, meshnormals, meshuvs)

@get_attribute(attributes, (shading, diffuse,
specular, shininess, faceculling))
Expand Down Expand Up @@ -985,11 +966,7 @@ end


function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Makie.MeshScatter))
@get_attribute(primitive, (color, model, marker, markersize, rotations))

if color isa AbstractArray{<: Number}
color = numbers_to_colors(color, primitive)
end
@get_attribute(primitive, (model, marker, markersize, rotations))

m = convert_attribute(marker, key"marker"(), key"meshscatter"())
pos = primitive[1][]
Expand All @@ -1003,9 +980,10 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki
cam_pos[3] / cam_pos[4]
end, rev=false)

color = to_color(primitive.calculated_colors[])
submesh = Attributes(
model=model,
color=color,
calculated_colors = color,
shading=primitive.shading, diffuse=primitive.diffuse,
specular=primitive.specular, shininess=primitive.shininess,
faceculling=get(primitive, :faceculling, -10),
Expand All @@ -1018,11 +996,10 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki
submesh[:model] = model * R
end
scales = primitive[:markersize][]

for i in zorder
p = pos[i]
if color isa AbstractVector
submesh[:color] = color[i]
submesh[:calculated_colors] = color[i]
end
if rotations isa Vector
R = Makie.rotationmatrix4(to_rotation(rotations[i]))
Expand Down
89 changes: 21 additions & 68 deletions CairoMakie/src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ to_uint32_color(c) = reinterpret(UInt32, convert(ARGB32, premultiplied_rgba(c)))
########################################

function to_cairo_color(colors::Union{AbstractVector{<: Number},Number}, plot_object)
return numbers_to_colors(colors, plot_object)
cmap = Makie.assemble_colors(colors, Observable(colors), plot_object)
return to_color(to_value(cmap))
end

function to_cairo_color(color::Makie.AbstractPattern, plot_object)
Expand All @@ -148,40 +149,10 @@ end
# Image/heatmap -> ARGBSurface #
########################################

function to_cairo_image(img::AbstractMatrix{<: AbstractFloat}, attributes)
to_cairo_image(to_rgba_image(img, attributes), attributes)
end

function to_rgba_image(img::AbstractMatrix{<: AbstractFloat}, attributes)
Makie.@get_attribute attributes (colormap, colorrange, nan_color, lowclip, highclip)

nan_color = Makie.to_color(nan_color)
lowclip = isnothing(lowclip) ? lowclip : Makie.to_color(lowclip)
highclip = isnothing(highclip) ? highclip : Makie.to_color(highclip)

[get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in img]
end

to_rgba_image(img::AbstractMatrix{<: Colorant}, attributes) = RGBAf.(img)

function get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip)
vmin, vmax = colorrange
if isnan(pixel)
RGBAf(nan_color)
elseif pixel < vmin && !isnothing(lowclip)
RGBAf(lowclip)
elseif pixel > vmax && !isnothing(highclip)
RGBAf(highclip)
else
RGBAf(Makie.interpolated_getindex(colormap, pixel, colorrange))
end
end

function to_cairo_image(img::AbstractMatrix{<: Colorant}, attributes)
to_cairo_image(to_uint32_color.(img), attributes)
end
to_cairo_image(img::AbstractMatrix{<: Colorant}) = to_cairo_image(to_uint32_color.(img))

function to_cairo_image(img::Matrix{UInt32}, attributes)
function to_cairo_image(img::Matrix{UInt32})
# we need to convert from column-major to row-major storage,
# therefore we permute x and y
return Cairo.CairoARGBSurface(permutedims(img))
Expand Down Expand Up @@ -224,11 +195,9 @@ function get_color_attr(attributes, attribute)::Union{Nothing, RGBAf}
return color_or_nothing(to_value(get(attributes, attribute, nothing)))
end

function per_face_colors(
color, colormap, colorrange, matcap, faces, normals, uv,
lowclip=nothing, highclip=nothing, nan_color=nothing
)
if matcap !== nothing
function per_face_colors(_color, matcap, faces, normals, uv)
color = to_color(_color)
if !isnothing(matcap)
wsize = reverse(size(matcap))
wh = wsize .- 1
cvec = map(normals) do n
Expand All @@ -239,37 +208,21 @@ function per_face_colors(
return FaceIterator(cvec, faces)
elseif color isa Colorant
return FaceIterator{:Const}(color, faces)
elseif color isa AbstractArray
if color isa AbstractVector{<: Colorant}
return FaceIterator(color, faces)
elseif color isa AbstractArray{<: Number}
low, high = extrema(colorrange)
cvec = map(color[:]) do c
if isnan(c) && nan_color !== nothing
return nan_color
elseif c < low && lowclip !== nothing
return lowclip
elseif c > high && highclip !== nothing
return highclip
else
Makie.interpolated_getindex(colormap, c, colorrange)
end
end
return FaceIterator(cvec, faces)
elseif color isa Makie.AbstractPattern
# let next level extend and fill with CairoPattern
return color
elseif color isa AbstractMatrix{<: Colorant} && uv !== nothing
wsize = reverse(size(color))
wh = wsize .- 1
cvec = map(uv) do uv
x, y = clamp.(round.(Int, Tuple(uv) .* wh) .+ 1, 1, wh)
return color[end - (y - 1), x]
end
# TODO This is wrong and doesn't actually interpolate
# Inside the triangle sampling the color image
return FaceIterator(cvec, faces)
elseif color isa AbstractVector{<: Colorant}
return FaceIterator(color, faces)
elseif color isa Makie.AbstractPattern
# let next level extend and fill with CairoPattern
return color
elseif color isa AbstractMatrix{<: Colorant} && !isnothing(uv)
wsize = reverse(size(color))
wh = wsize .- 1
cvec = map(uv) do uv
x, y = clamp.(round.(Int, Tuple(uv) .* wh) .+ 1, 1, wh)
return color[end - (y - 1), x]
end
# TODO This is wrong and doesn't actually interpolate
# Inside the triangle sampling the color image
return FaceIterator(cvec, faces)
end
error("Unsupported Color type: $(typeof(color))")
end
Expand Down
8 changes: 2 additions & 6 deletions GLMakie/assets/shader/heatmap.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@ in vec2 o_uv;
flat in uvec2 o_objectid;

{{intensity_type}} intensity;
uniform sampler1D color_map;
{{color_map_type}} color_map;
{{color_norm_type}} color_norm;

uniform float stroke_width;
uniform vec4 stroke_color;
uniform float levels;

uniform vec4 highclip;
uniform vec4 lowclip;
uniform vec4 nan_color;
Expand All @@ -38,7 +34,7 @@ vec4 get_color_from_cmap(float value, sampler1D color_map, vec2 colorrange) {
return texture(color_map, i01);
}

vec4 get_color(sampler2D intensity, vec2 uv, Nothing color_norm, sampler1D color_map){
vec4 get_color(sampler2D intensity, vec2 uv, Nothing color_norm, Nothing color_map){
return getindex(intensity, uv);
}

Expand Down
2 changes: 1 addition & 1 deletion GLMakie/assets/shader/line_segment.vert
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ in float lastlen;
{{thickness_type}} thickness;

{{color_type}} color;
{{color_map_type}} color_map;
{{color_map_type}} color_map;
{{color_norm_type}} color_norm;

uniform mat4 projectionview, model;
Expand Down
59 changes: 31 additions & 28 deletions GLMakie/assets/shader/util.vert
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,34 @@ mat4 translate_scale(vec3 xyz, vec3 scale){
vec4(xyz, 1));
}


uniform vec4 highclip;
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);
}


//Mapping 1D index to 1D, 2D and 3D arrays
int ind2sub(int dim, int linearindex){return linearindex;}
ivec2 ind2sub(ivec2 dim, int linearindex){
Expand Down Expand Up @@ -197,13 +225,14 @@ vec4 _color(samplerBuffer color, Nothing intensity, Nothing color_map, Nothing c
return texelFetch(color, index);
}
vec4 _color(Nothing color, sampler1D intensity, sampler1D color_map, vec2 color_norm, int index, int len){
return color_lookup(texture(intensity, float(index)/float(len-1)).x, color_map, color_norm);
float value = texture(intensity, float(index) / float(len - 1)).x;
return get_color_from_cmap(value, color_map, color_norm);
}
vec4 _color(Nothing color, samplerBuffer intensity, sampler1D color_map, vec2 color_norm, int index, int len){
return vec4(texelFetch(intensity, index).x, 0.0, 0.0, 0.0);
}
vec4 _color(Nothing color, float intensity, sampler1D color_map, vec2 color_norm, int index, int len){
return color_lookup(intensity, color_map, color_norm);
return get_color_from_cmap(intensity, color_map, color_norm);
}

out vec3 o_view_pos;
Expand Down Expand Up @@ -353,29 +382,3 @@ vec3 getnormal(Nothing pos, sampler1D xs, sampler1D ys, sampler2D zs, vec2 uv){

return normal_from_points(s0, s1, s2, s3, s4, uv, off1, off2, off3, off4);
}

uniform vec4 highclip;
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);
}
2 changes: 1 addition & 1 deletion GLMakie/src/GLAbstraction/GLRender.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ a lot of objects.
"""
function render(renderobject::RenderObject, vertexarray=renderobject.vertexarray)
renderobject.requires_update = false

if renderobject.visible
renderobject.prerenderfunction()
program = vertexarray.program
Expand Down
Loading

0 comments on commit 94bab3a

Please sign in to comment.