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.
186 lines
5.1 KiB
186 lines
5.1 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, 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, |
|
float *line_threshold, |
|
float *coordinates, |
|
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, 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); |
|
|
|
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; |
|
|
|
if (j != to - 1) { |
|
ids[ihead++] = stroke_index; |
|
} else { |
|
ids[ihead++] = stroke_index | (1 << 31); |
|
} |
|
} |
|
} |
|
|
|
return(segments_head); |
|
}
|
|
|