320 lines
10 KiB
Julia
320 lines
10 KiB
Julia
|
|
|
|
# [WEBSITE]
|
|
|
|
supported_args(::GLVisualizeBackend) = merge_with_base_supported([
|
|
# :annotations,
|
|
# :background_color_legend, :background_color_inside, :background_color_outside,
|
|
# :foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
|
# :foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
|
# :label,
|
|
# :linecolor, :linestyle, :linewidth, :linealpha,
|
|
# :markershape, :markercolor, :markersize, :markeralpha,
|
|
# :markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
|
# :fillrange, :fillcolor, :fillalpha,
|
|
# :bins, :bar_width, :bar_edges, :bar_position,
|
|
# :title, :title_location, :titlefont,
|
|
# :window_title,
|
|
# :guide, :lims, :ticks, :scale, :flip, :rotation,
|
|
# :tickfont, :guidefont, :legendfont,
|
|
# :grid, :legend, :colorbar,
|
|
# :marker_z, :levels,
|
|
# :ribbon, :quiver, :arrow,
|
|
# :orientation,
|
|
# :overwrite_figure,
|
|
# :polar,
|
|
# :normalize, :weights,
|
|
# :contours, :aspect_ratio,
|
|
# :match_dimensions,
|
|
# :clims,
|
|
# :inset_subplots,
|
|
])
|
|
supported_types(::GLVisualizeBackend) = [:surface, :scatter, :scatter3d, :path, :path3d, :shape]
|
|
supported_styles(::GLVisualizeBackend) = [:auto, :solid]
|
|
supported_markers(::GLVisualizeBackend) = vcat([:none, :auto, :circle], collect(keys(_gl_marker_map)))
|
|
supported_scales(::GLVisualizeBackend) = [:identity]
|
|
is_subplot_supported(::GLVisualizeBackend) = true
|
|
|
|
# --------------------------------------------------------------------------------------
|
|
|
|
|
|
function _initialize_backend(::GLVisualizeBackend; kw...)
|
|
@eval begin
|
|
import GLVisualize, GeometryTypes, GLAbstraction, GLWindow
|
|
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0
|
|
export GLVisualize
|
|
|
|
# # TODO: remove this when PlotUtils is registered
|
|
# import PlotUtils
|
|
end
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# initialize the figure/window
|
|
function _create_backend_figure(plt::Plot{GLVisualizeBackend})
|
|
# init a screen
|
|
screen = if isdefined(GLVisualize, :ROOT_SCREEN)
|
|
GLVisualize.ROOT_SCREEN
|
|
else
|
|
s = GLVisualize.glscreen()
|
|
@async GLVisualize.renderloop(s)
|
|
s
|
|
end
|
|
empty!(screen)
|
|
screen
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# size as a percentage of the window size
|
|
function gl_relative_size(plt::Plot{GLVisualizeBackend}, msize::Number)
|
|
winsz = min(plt[:size]...)
|
|
Float32(msize / winsz)
|
|
end
|
|
|
|
const _gl_marker_map = KW(
|
|
:rect => '■',
|
|
:star5 => '★',
|
|
:diamond => '◆',
|
|
:hexagon => '⬢',
|
|
:cross => '✚',
|
|
:xcross => '❌',
|
|
:utriangle => '▲',
|
|
:dtriangle => '▼',
|
|
:pentagon => '⬟',
|
|
:octagon => '⯄',
|
|
:star4 => '✦',
|
|
:star6 => '✶',
|
|
:star8 => '✷',
|
|
:vline => '┃',
|
|
:hline => '━',
|
|
)
|
|
|
|
|
|
# create a marker/shape type
|
|
function gl_marker(shape::Symbol, msize::Number, _3d::Bool)
|
|
GeometryTypes.HyperSphere((_3d ? Point3f0 : Point2f0)(0), msize)
|
|
end
|
|
|
|
gl_color(c::RGBA{Float32}) = c
|
|
|
|
# convert to RGBA
|
|
function gl_color(c, a=nothing)
|
|
@show c, a
|
|
c = convertColor(c, a)
|
|
@show c
|
|
RGBA{Float32}(c)
|
|
end
|
|
|
|
function gl_viewport(bb, rect)
|
|
l, b, bw, bh = bb
|
|
rw, rh = rect.w, rect.h
|
|
GLVisualize.SimpleRectangle(
|
|
round(Int, rect.x + rw * l),
|
|
round(Int, rect.y + rh * b),
|
|
round(Int, rw * bw),
|
|
round(Int, rh * bh)
|
|
)
|
|
end
|
|
|
|
gl_make_points(x, y) = Point2f0[Point2f0(x[i], y[i]) for i=1:length(x)]
|
|
gl_make_points(x, y, z) = Point3f0[Point3f0(x[i], y[i], z[i]) for i=1:length(x)]
|
|
|
|
function gl_draw_lines_2d(x, y, color, linewidth, sp_screen)
|
|
color = gl_color(color)
|
|
thickness = Float32(linewidth)
|
|
for rng in iter_segments(x, y)
|
|
n = length(rng)
|
|
n < 2 && continue
|
|
pts = gl_make_points(x[rng], y[rng])
|
|
@show pts, n
|
|
viz = GLVisualize.visualize(
|
|
pts,
|
|
n==2 ? :linesegment : :lines,
|
|
color = color,
|
|
thickness = thickness
|
|
)
|
|
GLVisualize.view(viz, sp_screen, camera=:orthographic_pixel)
|
|
end
|
|
end
|
|
|
|
function gl_draw_lines_3d(x, y, z, color, linewidth, sp_screen)
|
|
color = gl_color(color)
|
|
thickness = Float32(linewidth)
|
|
for rng in iter_segments(x, y, z)
|
|
n = length(rng)
|
|
n < 2 && continue
|
|
pts = gl_make_points(x[rng], y[rng], z[rng])
|
|
viz = GLVisualize.visualize(
|
|
pts,
|
|
n==2 ? :linesegment : :lines,
|
|
color=color,
|
|
thickness = thickness
|
|
)
|
|
GLVisualize.view(viz, sp_screen, camera=:perspective)
|
|
end
|
|
end
|
|
|
|
function gl_annotate(sp::Subplot{GLVisualizeBackend}, x, y, txt::PlotText)
|
|
end
|
|
|
|
function gl_draw_axes_2d(sp::Subplot{GLVisualizeBackend})
|
|
sp_screen = sp.o
|
|
xaxis = sp[:xaxis]
|
|
xmin, xmax = axis_limits(xaxis)
|
|
yaxis = sp[:yaxis]
|
|
ymin, ymax = axis_limits(yaxis)
|
|
|
|
# x axis
|
|
xsegs, ysegs = Segments(), Segments()
|
|
ticksz = 0.03*(ymax-ymin)
|
|
push!(xsegs, [xmin,xmax]); push!(ysegs, [ymin,ymin])
|
|
for tick in PlotUtils.optimize_ticks(xmin, xmax)[1]
|
|
push!(xsegs, [tick,tick]); push!(ysegs, [ymin,ymin+ticksz])
|
|
# TODO: add the ticklabel
|
|
end
|
|
gl_draw_lines_2d(xsegs.pts, ysegs.pts, xaxis[:foreground_color_border], 1, sp_screen)
|
|
|
|
# y axis
|
|
xsegs, ysegs = Segments(), Segments()
|
|
push!(xsegs, [xmin,xmin]); push!(ysegs, [ymin,ymax])
|
|
for tick in PlotUtils.optimize_ticks(xmin, xmax)[1]
|
|
push!(xsegs, [xmin,xmin+ticksz]); push!(ysegs, [tick,tick])
|
|
# TODO: add the ticklabel
|
|
end
|
|
gl_draw_lines_2d(xsegs.pts, ysegs.pts, yaxis[:foreground_color_border], 1, sp_screen)
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# draw everything
|
|
function gl_display(plt::Plot{GLVisualizeBackend})
|
|
screen = plt.o
|
|
sw, sh = plt[:size]
|
|
sw, sh = sw*px, sh*px
|
|
for (name, sp) in plt.spmap
|
|
|
|
_3d = is3d(sp)
|
|
camera = _3d ? :perspective : :orthographic_pixel
|
|
# camera = :perspective
|
|
|
|
# initialize the sub-screen for this subplot
|
|
# note: we create a lift function to update the size on resize
|
|
rel_bbox = bbox_to_pcts(bbox(sp), sw, sh)
|
|
f = rect -> gl_viewport(rel_bbox, rect)
|
|
sp_screen = GLVisualize.Screen(
|
|
screen,
|
|
name = name,
|
|
area = GLVisualize.const_lift(f, screen.area)
|
|
)
|
|
|
|
sp.o = sp_screen
|
|
if !is3d(sp)
|
|
# gl_draw_axes_2d(sp)
|
|
end
|
|
|
|
# loop over the series and add them to the subplot
|
|
for series in series_list(sp)
|
|
d = series.d
|
|
st = d[:seriestype]
|
|
x, y = map(Float32, d[:x]), map(Float32, d[:y])
|
|
msize = gl_relative_size(plt, d[:markersize])
|
|
|
|
if st == :surface
|
|
# TODO: can pass just the ranges and surface
|
|
ismatrix(x) || (x = repmat(x', length(y), 1))
|
|
ismatrix(y) || (y = repmat(y, 1, length(x)))
|
|
z = transpose_z(d, map(Float32, d[:z].surf), false)
|
|
viz = GLVisualize.visualize((x, y, z), :surface)
|
|
GLVisualize.view(viz, sp_screen, camera = camera)
|
|
|
|
else
|
|
# paths, scatters, and shape
|
|
|
|
_3d && (z = map(Float32, d[:z]))
|
|
|
|
# paths?
|
|
lw = d[:linewidth]
|
|
if lw > 0
|
|
c = gl_color(d[:linecolor], d[:linealpha])
|
|
if _3d
|
|
gl_draw_lines_3d(x, y, z, c, lw, sp_screen)
|
|
else
|
|
gl_draw_lines_2d(x, y, c, lw, sp_screen)
|
|
end
|
|
end
|
|
|
|
# markers?
|
|
if st in (:scatter, :scatter3d) || d[:markershape] != :none
|
|
extrakw = KW()
|
|
c = gl_color(d[:markercolor], d[:markeralpha])
|
|
|
|
# get the marker
|
|
shape = d[:markershape]
|
|
shape = get(_gl_marker_map, shape, shape)
|
|
marker = if isa(shape, Char)
|
|
# extrakw[:scale] = Vec2f0(_3d ? 0.6*d[:markersize] : msize)
|
|
extrakw[:scale] = Vec2f0(msize)
|
|
shape
|
|
else
|
|
gl_marker(d[:markershape], msize, _3d)
|
|
end
|
|
|
|
if !_3d
|
|
extrakw[:billboard] = true
|
|
end
|
|
|
|
points = _3d ? gl_make_points(x,y,z) : gl_make_points(x,y)
|
|
viz = GLVisualize.visualize(
|
|
(marker, points);
|
|
color = c,
|
|
extrakw...
|
|
)
|
|
GLVisualize.view(viz, sp_screen, camera = camera)
|
|
|
|
# TODO: might need to switch to these forms later?
|
|
# GLVisualize.visualize((marker ,(x, y, z)))
|
|
#GLVisualize.visualize((marker , map(Point3f0, zip(x, y, z),
|
|
# billboard=true
|
|
#))
|
|
end
|
|
|
|
if st == :shape
|
|
for rng in iter_segments(x, y)
|
|
pts = Point2f0[Point2f0(x[i], y[i]) for i in rng]
|
|
@show pts
|
|
mesh = GeometryTypes.GLNormalMesh(pts)
|
|
@show mesh
|
|
if !isempty(GeometryTypes.faces(mesh))
|
|
viz = GLVisualize.visualize(
|
|
mesh,
|
|
color = gl_color(d[:fillcolor], d[:fillalpha])
|
|
)
|
|
GLVisualize.view(viz, sp_screen, camera = camera)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
GLAbstraction.center!(sp_screen, camera)
|
|
end
|
|
|
|
# TODO: render one frame at a time? (no renderloop)
|
|
# GLWindow.render_frame(screen)
|
|
end
|
|
|
|
|
|
# ----------------------------------------------------------------
|
|
|
|
function _update_plot_object(plt::Plot{GLVisualizeBackend})
|
|
gl_display(plt)
|
|
end
|
|
|
|
# function _writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{GLVisualizeBackend})
|
|
# # TODO: write a png to io
|
|
# end
|
|
|
|
function _display(plt::Plot{GLVisualizeBackend})
|
|
end
|