|
|
|
extern char __heap_base;
|
|
|
|
static int allocated;
|
|
|
|
|
|
|
|
void
|
|
|
|
total_free(void)
|
|
|
|
{
|
|
|
|
allocated = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
alloc(int size)
|
|
|
|
{
|
|
|
|
void *result = &__heap_base + allocated;
|
|
|
|
allocated += size;
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 = __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];
|
|
|
|
|
|
|
|
float apx = px - ax;
|
|
|
|
float apy = py - ay;
|
|
|
|
|
|
|
|
float dist = __builtin_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)
|
|
|
|
{
|
|
|
|
if (clipped_count == 0) {
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
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_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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
segments_from[clipped_count] = segments_head;
|
|
|
|
|
|
|
|
return(segments_head);
|
|
|
|
}
|