vkf_line_chain Module

A growing set of points drawn from a chain of GPU buffers ("chunks"), for the trajectory artists: a line strip, separate segments (pairs of points), markers (one per point) or a ribbon (a translucent surface through pairs of points: a quad between each pair and the next). Points are written in place, as (high, low) float pairs for double precision (see src/vsg/vkf_layer.cpp: EyeRelative), with a strip's distance along it (for dash patterns, see shaders/line.vert; measured from the trajectory's points), and only the chunks written to are uploaded again. A full chain gets new chunks, each as large as the chain so far or as what is needed at once, but at least min_chunk and at most max_chunk points, so nothing is ever copied or reallocated, and changing a point uploads at most max_chunk points again. In a strip, consecutive chunks share their end point so that the line is continuous; in a ribbon, their end pair.

Level of detail (strips): seen from far away, a dense trajectory is mostly segments shorter than a pixel. For each chunk, the chain keeps the bounding sphere of its points and, for strides 2, 4, ... 2^lod_levels, a bound on how far the points skipped can be from the segments drawn (every stride-th point and the last), and gives them to the renderer (vkf_line_set_lod), which picks the stride per view (src/vsg/vkf_layer.cpp: EyeRelative). The bounds are built level by level: a segment at stride 2s is within the larger of its two halves' bounds, plus its middle point's distance from it, of the points it skips (the halves' segments lie within that distance of it). They are updated only for the segments the points written change.

Writing points i1 .. i2 (indices along the whole chain):

call chain%reserve(i2)
do j = 1, chain%num_chunks()
    call chain%slice(j, i1, i2, lo, hi, p)      ! p: points lo .. hi of chunk j
    if (.not. associated(p)) cycle
    ... fill p(1:3, :, 1:hi-lo+1) (e.g. with split_points) ...
end do
call chain%written(i1, i2)                     ! measure (strips) and upload
call chain%draw(i2)

Uses

  • module~~vkf_line_chain~~UsesGraph module~vkf_line_chain vkf_line_chain iso_c_binding iso_c_binding module~vkf_line_chain->iso_c_binding module~vkf_layer vkf_layer module~vkf_line_chain->module~vkf_layer module~vkf_math vkf_math module~vkf_line_chain->module~vkf_math module~vkf_layer->iso_c_binding iso_fortran_env iso_fortran_env module~vkf_math->iso_fortran_env

Used by

  • module~~vkf_line_chain~~UsedByGraph module~vkf_line_chain vkf_line_chain module~vkf_artists vkf_artists module~vkf_artists->module~vkf_line_chain module~vkf_line_segments vkf_line_segments module~vkf_line_segments->module~vkf_line_chain module~vkf_handles vkf_handles module~vkf_handles->module~vkf_artists module~vkf_shapes vkf_shapes module~vkf_shapes->module~vkf_artists module~vkframes vkframes module~vkframes->module~vkf_artists module~vkframes->module~vkf_line_segments module~vkframes->module~vkf_handles module~vkframes->module~vkf_shapes module~vkf_window vkf_window module~vkframes->module~vkf_window module~vkf_window->module~vkf_handles

Variables

Type Visibility Attributes Name Initial
integer, public, parameter :: CHAIN_MARKERS = 2

a marker per point

integer, public, parameter :: CHAIN_RIBBON = 3

a ribbon (a quad between each pair of points and the next)

integer, public, parameter :: CHAIN_SEGMENTS = 1

separate segments (pairs of points)

integer, public, parameter :: CHAIN_STRIP = 0

what a chain draws a line strip

integer, private, parameter :: lod_levels = 12

strides up to 2^12 = 4096 (strips)

integer, public, parameter :: max_chunk = 65536

points in a chunk made for appending (1.5 MB)

integer, private, parameter :: min_chunk = 64

points in the smallest chunk


Derived Types

type, public ::  LineChain

A chain of point buffers (see the module documentation).

Components

Type Visibility Attributes Name Initial
type(LineChunk), private, allocatable :: chunks(:)

(capacity): the chunks, in chain order

real(kind=c_float), private :: color(4) = 1.0_c_float

[r, g, b, a] (0 to 1)

logical, private :: colored = .false.

(lines, markers: a color per point (color_slice))

logical, private :: compile_new = .false.

chunks made from now on are compiled (the group is shown)

real(kind=wp), private :: dash_length = 0.0_wp

(2: the pattern's length, scene units; 0 from the first view)

integer, private :: dash_mode = 0

(lines: 0 anchored, 1 screen-locked, 2 fixed length)

type(c_ptr), private :: group = c_null_ptr

the group node the chunks are under (null: not built)

real(kind=c_float), private :: highlight(12) = [1.0_c_float, 1.0_c_float, 1.0_c_float, 1.0_c_float, 0.0_c_float, 40.0_c_float, 50.0_c_float, 12.0_c_float, 1.5_c_float, 0.0_c_float, 0.0_c_float, 0.0_c_float]

(lines: highlight, see vkf_line_set_highlight)

type(c_ptr), private :: image = c_null_ptr

(markers: the image (shape 10))

integer, private :: kind = CHAIN_STRIP

what is drawn: a CHAIN_* constant

logical, private :: lod = .true.

(strips: level of detail (else every point drawn))

integer, private :: n_chunks = 0

number of chunks

integer, private :: pattern = int(z'FFFF')

(lines: 16-bit dash pattern (z'FFFF': solid))

integer, private :: pattern_factor = 1

(lines: dash pattern (see line_set_pattern))

real(kind=c_float), private :: radius = 0.0_c_float

(markers: attenuation radius)

integer, private :: shape = 0

markers

real(kind=c_float), private :: trail(20) = 0.0_c_float

(strips: the trail, see vkf_line_set_trail; z = 0: none)

real(kind=c_float), private :: width = 1.0_c_float

line width, or marker size

Type-Bound Procedures

procedure, public :: chunk_bounds
procedure, public :: color_slice
procedure, public :: dash_mode_of
procedure, public :: detach
procedure, public :: distance
procedure, public :: draw
procedure, public :: draw_range
procedure, public :: init
procedure, public :: is_built
procedure, public :: is_colored
procedure, public :: lod_error
procedure, public :: num_chunks
procedure, public :: point
procedure, public :: point_color
procedure, public :: release
procedure, public :: reserve
procedure, public :: set_compile
procedure, public :: set_dash_mode
procedure, public :: set_highlight
procedure, public :: set_lod
procedure, public :: set_marker_style
procedure, public :: set_pattern
procedure, public :: set_style
procedure, public :: set_trail
procedure, public :: slice
procedure, public :: style_node
procedure, public :: written

type, private ::  LineChunk

A buffer holding points first .. first+capacity-1 of the chain.

Components

Type Visibility Attributes Name Initial
real(kind=wp), public :: box_hi(3) = 0.0_wp

bounding box of the points written: upper corner

real(kind=wp), public :: box_lo(3) = 0.0_wp

bounding box of the points written: lower corner

integer, public :: capacity = 0

number of points it holds

integer, public :: first = 1

the chain index of its first point

type(c_ptr), public :: line = c_null_ptr

the line, marker or ribbon node

type(LodLevel), public :: lod(lod_levels)

error bounds at strides 2, 4, ... 2^lod_levels

integer, public :: n_written = 0

points written (the bounds are for them)

type, private ::  LodLevel

Error bounds of a strip's segments at one stride (level of detail).

Components

Type Visibility Attributes Name Initial
real(kind=c_float), public, allocatable :: bound(:)

(0 : segments - 1)


Functions

private pure function dash_mode_of(self)

The dashes' layout (set_dash_mode).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self

Return Value integer

private function distance(self, i) result(s)

A strip's distance along it at point i, as written.

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self
integer, intent(in) :: i

chain index

Return Value real(kind=wp)

private pure function is_built(self)

True if the chain has a group to draw under (between init and release).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self

Return Value logical

private pure function is_colored(self)

For lines and markers, whether each point has its own color (init's colored).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self

Return Value logical

private function lod_error(self, j) result(error)

Chunk j's error bounds: how far the points skipped can be from the segments drawn at stride 2^k (k = 1 .. lod_levels; 0 where not known).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self
integer, intent(in) :: j

the chunk (outside 1 to the chunks: zeros)

Return Value real(kind=c_float), (lod_levels)

private pure function num_chunks(self)

Number of chunks.

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self

Return Value integer

private function point(self, i) result(v)

Point i as written: read back from the buffers (zero if not held).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self
integer, intent(in) :: i

chain index

Return Value real(kind=wp), (3)

private function point_color(self, i) result(rgba)

The color of point i of a colored chain, as stored (rgba; white if not colored).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self
integer, intent(in) :: i

chain index

Return Value real(kind=wp), (4)

private pure function segment_distance(v, a, b) result(d)

Distance from point v to the segment from a to b.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: v(3)

the point, and the segment's ends

real(kind=wp), intent(in) :: a(3)

the point, and the segment's ends

real(kind=wp), intent(in) :: b(3)

the point, and the segment's ends

Return Value real(kind=wp)


Subroutines

private subroutine apply_style(self, line)

Give the chain's style (color, width or size, pattern, highlight, marker shape) to the node line.

Arguments

Type IntentOptional Attributes Name
type(LineChain), intent(in) :: self
type(c_ptr), intent(in) :: line

line or marker node

private subroutine chunk_bounds(self, j, first, n, lo, hi)

Chunk j's points (strips: first .. first + n - 1 of the chain) and the bounding box of them (n = 0 if none are measured yet), e.g. to skip a chunk when picking.

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self
integer, intent(in) :: j

the chunk

integer, intent(out) :: first

its first point (chain index), and points written (0: none)

integer, intent(out) :: n

its first point (chain index), and points written (0: none)

real(kind=wp), intent(out) :: lo(3)

the bounding box's corners

real(kind=wp), intent(out) :: hi(3)

the bounding box's corners

private subroutine color_slice(self, j, i1, i2, lo, hi, c)

As slice, for the colors of a colored chain: c(rgba, point) of points lo .. hi of chunk j (null if not colored or nothing there).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self
integer, intent(in) :: j

the chunk, and points i1 .. i2 (chain indices)

integer, intent(in) :: i1

the chunk, and points i1 .. i2 (chain indices)

integer, intent(in) :: i2

the chunk, and points i1 .. i2 (chain indices)

integer, intent(out) :: lo

chain indices (lo > hi: none)

integer, intent(out) :: hi

chain indices (lo > hi: none)

real(kind=c_float), intent(out), dimension(:,:), pointer :: c

(4, hi-lo+1): [r, g, b, a]

private subroutine detach(self)

Remove the chunks from the group (also while running), and release them.

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self

private subroutine draw(self, k)

Draw points 1 .. k (no upload).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self
integer, intent(in) :: k

last point drawn (chain index)

private subroutine draw_range(self, i1, i2)

Draw points i1 .. i2 only (chain indices; none if i2 < i1): e.g. a trace of decreasing times, its last points.

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self
integer, intent(in) :: i1

first and last points drawn (chain indices)

integer, intent(in) :: i2

first and last points drawn (chain indices)

private subroutine init(self, group, kind, image, colored)

Draw under group (a CHAIN_* kind; markers with image, a vkf_image_read handle, for the image shape). Chunks made later are compiled once set_compile says so.

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
type(c_ptr), intent(in) :: group

the group node to draw under

integer, intent(in) :: kind

a CHAIN_* constant

type(c_ptr), intent(in), optional :: image

(markers: a vkf_image_read handle)

logical, intent(in), optional :: colored

(lines, markers: a color per point (color_slice))

public subroutine line_buffer(line, p)

The point buffer of a line or marker node: (xyz and distance, high/low, point).

Arguments

Type IntentOptional Attributes Name
type(c_ptr), intent(in) :: line

line or marker node

real(kind=c_float), intent(out), dimension(:,:,:), pointer :: p

(4, 2, capacity); null if none

private subroutine measure(self, j, lo, hi, x)

The distances along the strip of points lo .. hi of chunk j: from the previous point (in this chunk; the first point of a chunk after the first is the previous chunk's last, measured before), or 0 at point 1. From x (as in written) if given, else from the floats written.

Arguments

Type IntentOptional Attributes Name
type(LineChain), intent(in) :: self
integer, intent(in) :: j

the chunk, and its points lo .. hi (chain indices)

integer, intent(in) :: lo

the chunk, and its points lo .. hi (chain indices)

integer, intent(in) :: hi

the chunk, and its points lo .. hi (chain indices)

real(kind=wp), intent(in), optional :: x(:,:)

(3, chain points): the points, as in written

private subroutine move_chunks(from, to)

Chunks moved to a new array (their level-of-detail bounds moved, not copied).

Arguments

Type IntentOptional Attributes Name
type(LineChunk), intent(inout) :: from(:)

the chunks, and their new array (same size)

type(LineChunk), intent(inout) :: to(:)

the chunks, and their new array (same size)

private subroutine release(self)

Forget the chunks (after their group was removed from the scene): init starts again.

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self

private subroutine reserve(self, n)

Chunks for at least n points (at least one chunk). Separate segments and ribbons: chunks hold whole pairs (n should be even).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
integer, intent(in) :: n

number of points to hold

private subroutine send_lod(self, j)

Give chunk j's level of detail to the renderer (none if switched off).

Arguments

Type IntentOptional Attributes Name
type(LineChain), intent(in) :: self
integer, intent(in) :: j

the chunk

private subroutine set_compile(self, compile)

Compile chunks made from now on (for the windows running): once the group is shown (not while building, when they are compiled with it).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
logical, intent(in) :: compile

true: compile new chunks (once the group is shown)

private subroutine set_dash_mode(self, mode, length)

For lines, how the dashes are laid out: 0 anchored to the line (the default), 1 screen-locked (a constant length in pixels, following the line on screen), 2 a fixed length of the line (strips): length scene units for the pattern, or if 0 its length on screen when first drawn.

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
integer, intent(in) :: mode

0 anchored, 1 screen-locked, 2 fixed length

real(kind=wp), intent(in) :: length

(2) the pattern's length (scene units; 0: from the first view)

private subroutine set_highlight(self, flags, color, spacing, speed, band, period)

For lines, the highlight (see shaders/line.vert): flags (1 pulse, 2 arrows; 0 none), its color (rgba), the arrows' spacing and speed (window units, and per second), the band's width (window units) and the pulse's period (s).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
integer, intent(in) :: flags

1 pulse + 2 arrows (0: none)

real(kind=wp), intent(in) :: color(4)

[r, g, b, a] (0 to 1)

real(kind=wp), intent(in) :: spacing

between arrows (window units)

real(kind=wp), intent(in) :: speed

of the arrows (window units per second)

real(kind=wp), intent(in) :: band

width of the band the arrows are drawn in (window units)

real(kind=wp), intent(in) :: period

of the pulse (s)

private subroutine set_lod(self, enabled)

Level of detail on (the default: seen from far away, a strip is drawn from fewer points, within half a pixel of all of them) or off (every point drawn).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
logical, intent(in) :: enabled

level of detail on (false: every point drawn)

private subroutine set_marker_style(self, color, size, shape, radius)

For markers, the color (rgba), size (window units), shape (shaders/marker.frag) and attenuation radius (scene units, 0 for none).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
real(kind=wp), intent(in) :: color(4)

[r, g, b, a] (0 to 1)

real(kind=wp), intent(in) :: size

(window units)

integer, intent(in) :: shape

marker shape (shaders/marker.frag)

real(kind=wp), intent(in) :: radius

attenuation radius (scene units; 0: none)

private subroutine set_pattern(self, factor, pattern)

For lines, a dash pattern (see line_set_pattern; z'FFFF' solid).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
integer, intent(in) :: factor

repeat count of each bit of the pattern

integer, intent(in) :: pattern

16-bit dash pattern (z'FFFF': solid)

private subroutine set_style(self, color, width)

Color (rgba) and width (window units) of the whole chain.

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
real(kind=wp), intent(in) :: color(4)

[r, g, b, a] (0 to 1)

real(kind=wp), intent(in) :: width

(window units)

private subroutine set_trail(self, values)

For strips, the trail (see vkf_line_set_trail: 20 values; the third 0: none), given to every chunk (changed every frame the time does: a few floats per chunk uploaded).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
real(kind=c_float), intent(in) :: values(20)

the trail (see vkf_line_set_trail)

private subroutine slice(self, j, i1, i2, lo, hi, p)

The part lo .. hi of points i1 .. i2 that chunk j holds, and its buffer p(xyz and distance, high/low, lo:hi) (null if none).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self
integer, intent(in) :: j

the chunk, and points i1 .. i2 (chain indices)

integer, intent(in) :: i1

the chunk, and points i1 .. i2 (chain indices)

integer, intent(in) :: i2

the chunk, and points i1 .. i2 (chain indices)

integer, intent(out) :: lo

chain indices (lo > hi: none)

integer, intent(out) :: hi

chain indices (lo > hi: none)

real(kind=c_float), intent(out), dimension(:,:,:), pointer :: p

(4, 2, hi-lo+1)

public pure subroutine split_distances(s, d)

Distances s(n) into d(high/low, n).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: s(:)

(n)

real(kind=c_float), intent(inout) :: d(:,:)

(2, n)

public pure subroutine split_points(x, p)

Points x(3, n) into p(xyz and distance, high/low, n): the floats nearest, and the rest (the distances are left as they are).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: x(:,:)

(3, n)

real(kind=c_float), intent(inout) :: p(:,:,:)

(4, 2, n)

private subroutine style_node(self, line)

Give the chain's style to line, a node not in the chain (e.g. a curve's trace-mode tail, drawn as part of it).

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(in) :: self
type(c_ptr), intent(in) :: line

node to style (not in the chain)

private subroutine update_lod(self, j, lo, hi, x)

Points lo .. hi of chunk j (a strip's) were written, the last being hi: update the bounding box and the error bounds of the segments they change at each stride, and give them to the renderer. x as in written.

Arguments

Type IntentOptional Attributes Name
type(LineChain), intent(inout) :: self
integer, intent(in) :: j

the chunk, and its points lo .. hi (chain indices)

integer, intent(in) :: lo

the chunk, and its points lo .. hi (chain indices)

integer, intent(in) :: hi

the chunk, and its points lo .. hi (chain indices)

real(kind=wp), intent(in), optional :: x(:,:)

(3, chain points): the points, as in written

private subroutine written(self, i1, i2, x)

Points i1 .. i2 were written: measure a strip's distances along it (from the distance at point i1-1), update its level of detail, and upload the chunks holding them. x: the points in double precision, x(:, i) for chain point i (at least i1-1 .. i2), to measure from; without it, from the floats written. (i2 is the last point written in the chain.)

Arguments

Type IntentOptional Attributes Name
class(LineChain), intent(inout) :: self
integer, intent(in) :: i1

points written (chain indices)

integer, intent(in) :: i2

points written (chain indices)

real(kind=wp), intent(in), optional :: x(:,:)

(3, at least i1-1 .. i2): the points