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.

197 lines
5.6 KiB

extern char __heap_base;
static int allocated_static;
static int allocated_dynamic;
void
free_static(void)
{
allocated_static = 0;
}
void
free_dynamic(void)
{
allocated_dynamic = 0;
}
void *
alloc_static(int size)
{
void *result = &__heap_base + allocated_static;
allocated_static += size;
return(result);
}
void *
alloc_dynamic(int size)
{
void *result = &__heap_base + allocated_static + allocated_dynamic;
allocated_dynamic += size;
return(result);
}
static int
rdp_find_max(float *coordinates, unsigned char *pressures, 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];
unsigned char ap = pressures[coords_from / 2 + segment_start];
unsigned char bp = pressures[coords_from / 2 + segment_end];
float dx = bx - ax;
float dy = by - ay;
float dist_ab = __builtin_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];
unsigned char pp = pressures[coords_from + i];
float apx = px - ax;
float apy = py - ay;
float dist = __builtin_fabsf(apx * dir_nx + apy * dir_ny);
//+ __builtin_abs(pp - ap) / 255.0f + __builtin_abs(pp - bp) / 255.0f;
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,
float *line_threshold,
float *coordinates,
unsigned char *pressures,
int coordinates_count)
{
if (clipped_count == 0) {
return(0);
}
int *segments_from = alloc_dynamic((clipped_count + 1) * 4);
int *segments = alloc_dynamic(coordinates_count / 2 * 4);
int segments_head = 0;
int stack[4096]; // TODO: what's a reasonable max size for this?
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_from[stroke_index + 1];
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, pressures, 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;
}
}
segments_from[clipped_count] = segments_head;
// Write actual coordinates (points) and stroke ids
float *points = alloc_dynamic(segments_head * 2 * 4);
int *ids = alloc_dynamic(segments_head * 4);
unsigned char *pressures_res = alloc_dynamic(segments_head);
int phead = 0;
int ihead = 0;
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 base_stroke = stroke_coords_from[stroke_index];
int from = segments_from[i];
int to = segments_from[i + 1];
for (int j = from; j < to; ++j) {
int point_index = segments[j];
float x = coordinates[base_stroke + point_index * 2 + 0];
float y = coordinates[base_stroke + point_index * 2 + 1];
points[phead++] = x;
points[phead++] = y;
pressures_res[ihead] = pressures[base_stroke / 2 + point_index];
if (j != to - 1) {
ids[ihead++] = stroke_index;
} else {
ids[ihead++] = stroke_index | (1 << 31);
}
}
}
return(segments_head);
}