You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.5 KiB

float sqrtf(float x);
float fabsf(float x);
static int
rdp_find_max(float *coordinates, float zoom, int coords_from,
int segment_start, int segment_end)
{
float EPS = 1.0 / zoom;
int result = -1;
float max_dist = 0.0f;
float ax = coordinates[coords_from + segment_start * 2 + 0];
float ay = coordinates[coords_from + segment_start * 2 + 1];
float bx = coordinates[coords_from + segment_end * 2 + 0];
float by = coordinates[coords_from + segment_end * 2 + 1];
float dx = bx - ax;
float dy = by - ay;
float dist_ab = sqrtf(dx * dx + dy * dy);
float dir_nx = dy / dist_ab;
float dir_ny = -dx / dist_ab;
for (int i = segment_start + 1; i < segment_end; ++i) {
float px = coordinates[coords_from + i * 2 + 0];
float py = coordinates[coords_from + i * 2 + 1];
float apx = px - ax;
float apy = py - ay;
float dist = fabsf(apx * dir_nx + apy * dir_ny);
if (dist > EPS && dist > max_dist) {
result = i;
max_dist = dist;
}
}
return(result);
}
int
do_lod(int *clipped_indices, int clipped_count, float zoom,
int *stroke_coords_from, int *stroke_coords_to,
float *line_threshold, float *coordinates,
int *segments_from, int *segments)
{
int segments_head = 0;
int stack[4096];
for (int i = 0; i < clipped_count; ++i) {
int stroke_index = clipped_indices[i];
// TODO: convert to a proper CSR, save half the memory
int coords_from = stroke_coords_from[stroke_index];
int coords_to = stroke_coords_to[stroke_index];
int point_count = (coords_to - coords_from) / 2;
// Basic CSR crap
segments_from[i] = segments_head;
if (zoom < line_threshold[stroke_index]) {
// Fast paths for collapsing to a single line segment
segments[segments_head++] = 0;
segments[segments_head++] = point_count - 1;
continue;
}
int segment_count = 2;
int stack_head = 0;
segments[segments_head++] = 0;
stack[stack_head++] = 0;
stack[stack_head++] = 0;
stack[stack_head++] = point_count - 1;
while (stack_head > 0) {
int end = stack[--stack_head];
int start = stack[--stack_head];
int type = stack[--stack_head];
if (type == 1) {
segments[segments_head++] = start;
} else {
int max = rdp_find_max(coordinates, zoom, coords_from, start, end);
if (max != -1) {
segment_count += 1;
stack[stack_head++] = 0;
stack[stack_head++] = max;
stack[stack_head++] = end;
stack[stack_head++] = 1;
stack[stack_head++] = max;
stack[stack_head++] = -1;
stack[stack_head++] = 0;
stack[stack_head++] = start;
stack[stack_head++] = max;
}
}
}
segments[segments_head++] = point_count - 1;
if (segment_count == 2 && zoom > line_threshold[stroke_index]) {
line_threshold[stroke_index] = zoom;
}
}
return(segments_head);
}