QuelSolaarHxA/hxa_util_font_process.c
2020-05-03 14:16:33 +02:00

1535 lines
50 KiB
C

#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#define MO_EDIT_PROCESS_LINE_SWIGGLE 0.02
#define FALSE 0
#define TRUE !FALSE
typedef struct{
float *vertex_array;
unsigned int vertex_count;
unsigned int ref_count;
unsigned int *ref;
unsigned int *material;
}ProcessOutput;
typedef enum{
MO_LST_GROUND,
MO_LST_HOLE,
MO_LST_ROCK,
MO_LST_BUILDING,
MO_LST_INDOORS,
MO_LST_FACTORY_UNASIGNED,
MO_LST_COUNT
}MOLevelSurfaceType;
typedef struct{
unsigned int ref[2];
unsigned int type[2];
unsigned int next[2];
unsigned int prev[2];
}MoEditEdge;
typedef struct{
unsigned int *loop;
unsigned int loop_count;
unsigned int material;
unsigned int start;
int used;
unsigned int generation;
int direction;
}MoEditLoop;
typedef struct{
MoEditEdge *edges;
unsigned int edges_allocated;
unsigned int edge_count;
float *vertex_array;
unsigned int *vertex_users;
unsigned int vertex_allocated;
unsigned int vertex_count;
MoEditLoop *loops;
unsigned int loop_count;
unsigned int loop_alloc;
unsigned int ref_count;
unsigned int *ref;
unsigned int *material;
}MoEditProcess;
#define MO_EDIT_PROCESS_COLAPSE_SIZE (1.0 / 5120.0)
extern void mo_edit_process_edge_end_extracate(MoEditProcess *edit, unsigned int edge, unsigned int end);
extern void mo_edit_process_edge_set(MoEditProcess *edit, unsigned int ref_a, unsigned int ref_b, unsigned int material_a, unsigned int material_b);
#define f_sqrt_step(shift) \
if((0x40000000l >> shift) + root <= value) \
{ \
value -= (0x40000000l >> shift) + root; \
root = (root >> 1) | (0x40000000l >> shift); \
} \
else \
{ \
root = root >> 1; \
}
long f_sqrti(long value)
{
long root = 0;
f_sqrt_step(0);
f_sqrt_step(2);
f_sqrt_step(4);
f_sqrt_step(6);
f_sqrt_step(8);
f_sqrt_step(10);
f_sqrt_step(12);
f_sqrt_step(14);
f_sqrt_step(16);
f_sqrt_step(18);
f_sqrt_step(20);
f_sqrt_step(22);
f_sqrt_step(24);
f_sqrt_step(26);
f_sqrt_step(28);
f_sqrt_step(30);
if(root < value)
++root;
return root;
}
unsigned long long f_sqrti64(unsigned long long value)
{
unsigned long long i, root = 0, add;
for(i = 32; i > 0;)
{
i--;
add = (((unsigned long long)1) << i) + root;
if(add * add <= value)
root = add;
}
return root;
}
unsigned char f_normalize_2di(int *point, int fixed_point_multiplyer)
{
int length;
length = f_sqrti(point[0] * point[0] + point[1] * point[1]);
if(length != 0)
{
point[0] = (point[0] * fixed_point_multiplyer) / length;
point[1] = (point[1] * fixed_point_multiplyer) / length;
return 1;
}
return 0;
}
float f_normalize2f(float *vec)
{
float f;
f = sqrtf(vec[0] * vec[0] + vec[1] * vec[1]);
vec[0] /= f;
vec[1] /= f;
return f;
}
void mo_edit_process_make_sure(MoEditProcess *edit)
{
unsigned int i, error;
for(i = 0; i < edit->edge_count; i++)
{
if(edit->edges[i].next[0] >= edit->edge_count * 2 ||
edit->edges[i].next[1] >= edit->edge_count * 2 ||
edit->edges[i].prev[0] >= edit->edge_count * 2 ||
edit->edges[i].prev[1] >= edit->edge_count * 2)
error = 0;
if(edit->edges[i].ref[0] >= edit->vertex_count ||
edit->edges[i].ref[1] >= edit->vertex_count)
error = 0;
}
}
int mo_edit_process_inside_test(unsigned int test_ref, float *pos, unsigned int *loop, unsigned int size, float *vertex)
{
unsigned int i, count = 0;
float *b, *b2;
for(i = 0; i < size; i++)
{
if(loop[i] == test_ref)
return FALSE;
b = &vertex[loop[i] * 2];
b2 = &vertex[loop[(i + 1) % size] * 2];
if(b[0] > pos[0] != b2[0] > pos[0])
if(((b[1] - b2[1]) * (pos[0] - b2[0]) - (b[0] - b2[0]) * (pos[1] - b2[1]) > 0) !=
((b[1] - b2[1]) * (pos[0] - b2[0]) - (b[0] - b2[0]) * (1000.0 - b2[1]) > 0))
count++;
}
return count % 2 == 1;
}
unsigned int mo_edit_process_material_dominat(unsigned int mat_a, unsigned int mat_b)
{
unsigned int tmp;
if(mat_a == -1)
return mat_b;
if(mat_b == -1)
return mat_a;
if(mat_b == MO_LST_HOLE)
return mat_a;
if(mat_a == MO_LST_HOLE)
return mat_b;
if(mat_a == -3 || mat_b == -3)
return -3;
/* if(mat_a == MO_LST_GROUND && mat_b == MO_LST_INDOORS)
return MO_LST_GROUND;
if(mat_b == MO_LST_GROUND && mat_a == MO_LST_INDOORS)
return MO_LST_GROUND;*/
if(mat_a > mat_b)
return mat_a;
return mat_b;
}
unsigned int mo_edit_process_vertex_allocate(MoEditProcess *edit, float x, float y)
{
float vec[2], f;
unsigned int i;
for(i = 0; i < edit->vertex_count; i++)
{
vec[0] = edit->vertex_array[i * 2] - x;
vec[1] = edit->vertex_array[i * 2 + 1] - y;
f = vec[0] * vec[0] + vec[1] * vec[1];
if(f < MO_EDIT_PROCESS_COLAPSE_SIZE * MO_EDIT_PROCESS_COLAPSE_SIZE)
return i;
}
if(edit->vertex_allocated == edit->vertex_count)
{
edit->vertex_allocated *= 2;
edit->vertex_array = realloc(edit->vertex_array, (sizeof *edit->vertex_array) * edit->vertex_allocated * 4);
edit->vertex_users = realloc(edit->vertex_users, (sizeof *edit->vertex_users) * edit->vertex_allocated * 2);
}
edit->vertex_array[edit->vertex_count * 2 + 0] = x;
edit->vertex_array[edit->vertex_count * 2 + 1] = y;
edit->vertex_users[edit->vertex_count] = -1;
edit->vertex_count++;
return edit->vertex_count - 1;
}
unsigned int mo_edit_find_loop(MoEditProcess *edit, unsigned int start, unsigned int *buffer)
{
unsigned int pos, next, count = 0, last = -1;
pos = start;
while(TRUE)
{
if(edit->edges[pos / 2].type[0] == edit->edges[pos / 2].type[1] ||
edit->edges[pos / 2].type[pos % 2] == -2)
return -1;
next = edit->edges[pos / 2].next[pos % 2];
edit->edges[pos / 2].type[pos % 2] = -2;
if(next / 2 == pos / 2)
return -1;
if(last != edit->edges[pos / 2].ref[pos % 2])
buffer[count++] = last = edit->edges[pos / 2].ref[pos % 2];
if(next == start)
{
if(buffer[0] == buffer[count - 1])
return count - 1;
else
return count;
}
pos = next;
}
}
void mo_edit_process_edge_end_integrate(MoEditProcess *edit, unsigned int edge, unsigned int end)
{
float center[2], vec[2], last_vec[2], test[2];
unsigned int vertex, ref, pos, start, prevoius, i = 0;
vertex = edit->edges[edge].ref[end];
start = pos = edit->vertex_users[vertex];
if(pos == -1) /* First to connect */
{
edit->edges[edge].next[end] = edge * 2 + (end + 1) % 2;
edit->edges[edge].prev[(end + 1) % 2] = edge * 2 + end;
edit->vertex_users[vertex] = edge * 2 + end;
return;
}
if(edit->vertex_users[vertex] / 2 != edge &&
edit->edges[pos / 2].next[pos % 2] / 2 == pos / 2) /* Second to connect */
{
edit->edges[pos / 2].next[pos % 2] = edge * 2 + (end + 1) % 2;
edit->edges[pos / 2].prev[(pos + 1) % 2] = edge * 2 + end;
edit->edges[edge].next[end] = (pos / 2) * 2 + (pos + 1) % 2;
edit->edges[edge].prev[(end + 1) % 2] = pos;
return;
}
center[0] = edit->vertex_array[vertex * 2 + 0];
center[1] = edit->vertex_array[vertex * 2 + 1];
ref = edit->edges[edge].ref[(end + 1) % 2];
test[0] = edit->vertex_array[ref * 2 + 0] - center[0];
test[1] = edit->vertex_array[ref * 2 + 1] - center[1];
ref = edit->edges[pos / 2].ref[(pos + 1) % 2];
last_vec[0] = edit->vertex_array[ref * 2 + 0] - center[0];
last_vec[1] = edit->vertex_array[ref * 2 + 1] - center[1];
while(TRUE)
{
prevoius = pos;
pos = edit->edges[pos / 2].next[pos % 2];
if(pos == -1)
printf("Error");
ref = edit->edges[pos / 2].ref[pos % 2];
vec[0] = edit->vertex_array[ref * 2 + 0] - center[0];
vec[1] = edit->vertex_array[ref * 2 + 1] - center[1];
if(vec[0] * last_vec[1] - vec[1] * last_vec[0] <= 0)
{
if(test[0] * vec[1] - test[1] * vec[0] < 0 ||
test[0] * last_vec[1] - test[1] * last_vec[0] >= 0)
{
edit->edges[edge].next[end % 2] = pos;
edit->edges[edge].prev[(end + 1) % 2] = edit->edges[pos / 2].prev[pos % 2];
edit->edges[pos / 2].prev[pos % 2] = edge * 2 + end % 2;
pos = edit->edges[edge].prev[(end + 1) % 2];
edit->edges[pos / 2].next[pos % 2] = edge * 2 + (end + 1) % 2;
return;
}
}else
{
if(test[0] * vec[1] - test[1] * vec[0] < 0 &&
test[0] * last_vec[1] - test[1] * last_vec[0] > 0)
{
edit->edges[edge].next[end % 2] = pos;
edit->edges[edge].prev[(end + 1) % 2] = edit->edges[pos / 2].prev[pos % 2];
edit->edges[pos / 2].prev[pos % 2] = edge * 2 + end % 2;
pos = edit->edges[edge].prev[(end + 1) % 2];
edit->edges[pos / 2].next[pos % 2] = edge * 2 + (end + 1) % 2;
return;
}
}
pos = (pos / 2) * 2 + (pos + 1) % 2;
if(pos == start)
i++;
last_vec[0] = vec[0];
last_vec[1] = vec[1];
i++;
}
}
/*
uint mo_edit_process_vertex_dominance(MoEditProcess *edit)
{
uint pos, start, next, i, dom;
for(i = 0; i < edit->edge_count; i++)
{
edit->edges[i].type2[0] = edit->edges[i].type[0];
edit->edges[i].type2[1] = edit->edges[i].type[1];
}
for(i = 0; i < edit->vertex_count; i++)
{
pos = start = edit->vertex_users[i];
if(pos != -1)
{
while(TRUE)
{
next = edit->edges[pos / 2].next[pos % 2];
dom = mo_edit_process_material_dominat(edit->edges[pos / 2].type[pos % 2],
edit->edges[next / 2].type[next % 2]);
edit->edges[pos / 2].type2[pos % 2] = mo_edit_process_material_dominat(edit->edges[pos / 2].type2[pos % 2], dom);
edit->edges[next / 2].type2[next % 2] = mo_edit_process_material_dominat(edit->edges[next / 2].type2[next % 2], dom);
next = (next / 2) * 2 + (next + 1) % 2;
pos = next;
if(pos == start)
break;
}
}
}
for(i = 0; i < edit->edge_count; i++)
{
edit->edges[i].type[0] = edit->edges[i].type2[0];
edit->edges[i].type[1] = edit->edges[i].type2[1];
}
for(i = 0; i < edit->edge_count; i++)
{
if(edit->edges[i].type[0] == edit->edges[i].type[1])
{
pos = i * 2;
while(TRUE)
{
next = edit->edges[pos / 2].next[pos % 2];
if(next / 2 == pos / 2)
break;
if(next / 2 != edit->edges[pos / 2].prev[(pos + 1) % 2] / 2)
{
mo_edit_process_edge_end_extracate(edit, pos / 2, pos % 2);
break;
}
edit->edges[next / 2].type[0] = edit->edges[next / 2].type[1];
mo_edit_process_edge_end_extracate(edit, pos / 2, pos % 2);
pos = next;
}
pos = i * 2 + 1;
while(TRUE)
{
next = edit->edges[pos / 2].next[pos % 2];
if(next / 2 == pos / 2)
break;
if(next / 2 != edit->edges[pos / 2].prev[(pos + 1) % 2] / 2)
{
mo_edit_process_edge_end_extracate(edit, pos / 2, pos % 2);
break;
}
edit->edges[next / 2].type[0] = edit->edges[next / 2].type[1];
mo_edit_process_edge_end_extracate(edit, pos / 2, pos % 2);
pos = next;
}
mo_edit_process_edge_end_extracate(edit, i, 0);
mo_edit_process_edge_end_extracate(edit, i, 1);
}
}
}
*/
void mo_edit_process_vertex_dominance2(MoEditProcess *edit)
{
unsigned int i, j, dom;
float point[4], vec[2], f;
for(i = 0; i < edit->edge_count; i++)
{
vec[0] = edit->vertex_array[edit->edges[i].ref[0] * 2] - edit->vertex_array[edit->edges[i].ref[1] * 2];
vec[1] = edit->vertex_array[edit->edges[i].ref[0] * 2 + 1] - edit->vertex_array[edit->edges[i].ref[1] * 2 + 1];
f = sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
point[0] = vec[0] * 0.5 + edit->vertex_array[edit->edges[i].ref[1] * 2] - MO_EDIT_PROCESS_COLAPSE_SIZE * 0.5 * vec[1] / f;
point[1] = vec[1] * 0.5 + edit->vertex_array[edit->edges[i].ref[1] * 2 + 1] + MO_EDIT_PROCESS_COLAPSE_SIZE * 0.5 * vec[0] / f;
point[2] = vec[0] * 0.5 + edit->vertex_array[edit->edges[i].ref[1] * 2] + MO_EDIT_PROCESS_COLAPSE_SIZE * 0.5 * vec[1] / f;
point[3] = vec[1] * 0.5 + edit->vertex_array[edit->edges[i].ref[1] * 2 + 1] - MO_EDIT_PROCESS_COLAPSE_SIZE * 0.5 * vec[0] / f;
for(j = 0; j < edit->loop_count && edit->edges[i].type[0] != edit->edges[i].type[1]; j++)
{
dom = mo_edit_process_material_dominat(edit->edges[i].type[0], edit->loops[j].material);
if(dom != edit->edges[i].type[0])
if(mo_edit_process_inside_test(-1, point, edit->loops[j].loop, edit->loops[j].loop_count, edit->vertex_array))
edit->edges[i].type[0] = dom;
dom = mo_edit_process_material_dominat(edit->edges[i].type[1], edit->loops[j].material);
if(dom != edit->edges[i].type[1])
if(mo_edit_process_inside_test(-1, &point[2], edit->loops[j].loop, edit->loops[j].loop_count, edit->vertex_array))
edit->edges[i].type[1] = dom;
}
if(edit->edges[i].type[0] == edit->edges[i].type[1])
{
mo_edit_process_edge_end_extracate(edit, i, 0);
mo_edit_process_edge_end_extracate(edit, i, 1);
}
}
/*Special case the outer box */
/* for(i = 0; i < edit->edge_count; i++)
{
if(edit->edges[i].type[0] == -1)
edit->edges[i].type[0] = MO_LST_HOLE;
else if(edit->edges[i].type[0] == -3)
edit->edges[i].type[0] = -1;
if(edit->edges[i].type[1] == -1)
edit->edges[i].type[1] = MO_LST_HOLE;
else if(edit->edges[i].type[1] == -3)
edit->edges[i].type[1] = -1;
}*/
}
void mo_edit_process_reduce(MoEditProcess *edit)
{
unsigned int i, j, edge, ref[3], next;
float point[4], vec[4], f;
for(i = 0; i < edit->vertex_count; i++)
{
edge = edit->vertex_users[i];
if(edge != -1 && edge / 2 != edit->edges[edge / 2].next[edge % 2] / 2 && edit->edges[edge / 2].prev[(edge + 1) % 2] / 2 == edit->edges[edge / 2].next[edge % 2] / 2)
{
ref[0] = edit->edges[edge / 2].ref[(edge + 1) % 2];
ref[1] = edit->edges[edge / 2].ref[edge % 2];
next = edit->edges[edge / 2].next[edge % 2];
ref[2] = edit->edges[next / 2].ref[next % 2];
vec[0] = edit->vertex_array[ref[0] * 2 + 0] - edit->vertex_array[ref[2] * 2 + 0];
vec[1] = edit->vertex_array[ref[0] * 2 + 1] - edit->vertex_array[ref[2] * 2 + 1];
vec[2] = edit->vertex_array[ref[1] * 2 + 0] - edit->vertex_array[ref[2] * 2 + 0];
vec[3] = edit->vertex_array[ref[1] * 2 + 1] - edit->vertex_array[ref[2] * 2 + 1];
f_normalize2f(vec);
f = vec[2] * vec[1] - vec[3] * vec[0];
if(f < MO_EDIT_PROCESS_COLAPSE_SIZE && f > -MO_EDIT_PROCESS_COLAPSE_SIZE)
{
mo_edit_process_edge_end_extracate(edit, edge / 2, edge % 2);
edit->edges[edge / 2].ref[edge % 2] = ref[2];
mo_edit_process_edge_end_extracate(edit, next / 2, 0);
mo_edit_process_edge_end_extracate(edit, next / 2, 1);
mo_edit_process_edge_end_integrate(edit, edge / 2, edge % 2);
}
}
/* if(edit->edges[i].type[0] == edit->edges[i].type[1])
{
mo_edit_process_edge_end_extracate(edit, i, 0);
mo_edit_process_edge_end_extracate(edit, i, 1);
}*/
}
}
/*
When a intersection is found:
Detach user of existing and attach to new vertex:
Add second edge bewean other and and new vertex.
Recursively create 2 new edges form the new edge.
Run Material dominance check on new vertex.
Clean up:
Remove all non conecting ends and all edges with identical sides.
Polygonize:
Extract all lops including outer loops.
see if outer looks fit in to each look.
Merge these loops.
Polygonize.
Be happy!!!
*/
void mo_edit_process_edge_end_extracate(MoEditProcess *edit, unsigned int edge, unsigned int end)
{
unsigned int vertex, pos;
vertex = edit->edges[edge].ref[end];
pos = edit->vertex_users[vertex];
if(edit->edges[edge].next[end] == edge * 2 + (end + 1) % 2 && edit->vertex_users[vertex] / 2 == edge)
{
edit->vertex_users[vertex] = -1;
return;
}
pos = edit->edges[edge].next[end];
edit->edges[pos / 2].prev[pos % 2] = edit->edges[edge].prev[(end + 1) % 2];
pos = edit->edges[edge].prev[(end + 1) % 2];
if(edit->vertex_users[vertex] / 2 == edge)
edit->vertex_users[vertex] = pos;
edit->edges[pos / 2].next[pos % 2] = edit->edges[edge].next[end];
edit->edges[edge].next[end] = edge * 2 + (end + 1) % 2;
edit->edges[edge].prev[(end + 1) % 2] = edge * 2 + end;
}
int mo_edit_process_split_edge(MoEditProcess *edit, unsigned int ref_a, unsigned int ref_b, unsigned int material_a, unsigned int material_b)
{
float *point_a, *point_b, vector[2], *a, *b, v[2], draw[2];
unsigned int i, edge_count, ref[2];
edge_count = edit->edge_count;
point_a = &edit->vertex_array[ref_a * 2];
point_b = &edit->vertex_array[ref_b * 2];
vector[0] = point_b[0] - point_a[0];
vector[1] = point_b[1] - point_a[1];
f_normalize2f(vector);
for(i = 0; i < edge_count; i++)
{
a = &edit->vertex_array[edit->edges[i].ref[0] * 2];
b = &edit->vertex_array[edit->edges[i].ref[1] * 2];
if((a[0] - point_a[0]) * vector[1] - (a[1] - point_a[1]) * vector[0] > MO_EDIT_PROCESS_COLAPSE_SIZE * 1)
{
if((b[0] - point_a[0]) * vector[1] - (b[1] - point_a[1]) * vector[0] < MO_EDIT_PROCESS_COLAPSE_SIZE * -1)
{
v[0] = b[0] - a[0];
v[1] = b[1] - a[1];
f_normalize2f(v);
if((point_a[0] - a[0]) * v[1] - (point_a[1] - a[1]) * v[0] < -0.0/*MO_EDIT_PROCESS_COLAPSE_SIZE * -0.1*/)
{
if((point_b[0] - a[0]) * v[1] - (point_b[1] - a[1]) * v[0] > 0.0/*MO_EDIT_PROCESS_COLAPSE_SIZE * 0.1*/)
{
mo_edit_process_make_sure(edit);
f_intersect2f(draw, a, b, point_a, point_b);
ref[0] = edit->edges[i].ref[0];
ref[1] = mo_edit_process_vertex_allocate(edit, draw[0], draw[1]);
if(ref[1] != edit->edges[i].ref[0] && ref[1] != edit->edges[i].ref[0])
{
mo_edit_process_edge_end_extracate(edit, i, 0);
edit->edges[i].ref[0] = ref[1];
mo_edit_process_edge_end_integrate(edit, i, 0);
mo_edit_process_make_sure(edit);
mo_edit_process_edge_set(edit, ref[0], ref[1], edit->edges[i].type[0], edit->edges[i].type[1]);
mo_edit_process_make_sure(edit);
mo_edit_process_edge_set(edit, ref_a, ref[1], material_a, material_b);
mo_edit_process_make_sure(edit);
mo_edit_process_edge_set(edit, ref[1], ref_b, material_a, material_b);
mo_edit_process_make_sure(edit);
return TRUE;
}
}
}
}
}else if((a[0] - point_a[0]) * vector[1] - (a[1] - point_a[1]) * vector[0] < MO_EDIT_PROCESS_COLAPSE_SIZE * -1)
{
if((b[0] - point_a[0]) * vector[1] - (b[1] - point_a[1]) * vector[0] > MO_EDIT_PROCESS_COLAPSE_SIZE * 1)
{
v[0] = b[0] - a[0];
v[1] = b[1] - a[1];
f_normalize2f(v);
if((point_a[0] - a[0]) * v[1] - (point_a[1] - a[1]) * v[0] > MO_EDIT_PROCESS_COLAPSE_SIZE * 1)
{
if((point_b[0] - a[0]) * v[1] - (point_b[1] - a[1]) * v[0] < MO_EDIT_PROCESS_COLAPSE_SIZE * -1)
{
mo_edit_process_make_sure(edit);
f_intersect2f(draw, a, b, point_a, point_b);
ref[0] = edit->edges[i].ref[0];
ref[1] = mo_edit_process_vertex_allocate(edit, draw[0], draw[1]);
if(ref[1] != edit->edges[i].ref[0] && ref[1] != edit->edges[i].ref[0])
{
mo_edit_process_edge_end_extracate(edit, i, 0);
edit->edges[i].ref[0] = ref[1];
mo_edit_process_edge_end_integrate(edit, i, 0);
mo_edit_process_make_sure(edit);
mo_edit_process_edge_set(edit, ref[0], ref[1], edit->edges[i].type[0], edit->edges[i].type[1]);
mo_edit_process_make_sure(edit);
mo_edit_process_edge_set(edit, ref_a, ref[1], material_a, material_b);
mo_edit_process_make_sure(edit);
mo_edit_process_edge_set(edit, ref[1], ref_b, material_a, material_b);
mo_edit_process_make_sure(edit);
return TRUE;
}
}
}
}
}
}
return FALSE;
}
void mo_edit_process_edge_set(MoEditProcess *edit, unsigned int ref_a, unsigned int ref_b, unsigned int material_a, unsigned int material_b)
{
float vec[2], tmp[2], f, length;
unsigned int i, edge;
if(ref_a == ref_b)
return;
vec[0] = edit->vertex_array[ref_b * 2 + 0] - edit->vertex_array[ref_a * 2 + 0];
vec[1] = edit->vertex_array[ref_b * 2 + 1] - edit->vertex_array[ref_a * 2 + 1];
length = sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
vec[0] /= length;
vec[1] /= length;
for(i = 0; i < edit->vertex_count; i++)
{
if(i != ref_a && i != ref_b)
{
tmp[0] = edit->vertex_array[i * 2 + 0] - edit->vertex_array[ref_a * 2 + 0];
tmp[1] = edit->vertex_array[i * 2 + 1] - edit->vertex_array[ref_a * 2 + 1];
f = tmp[0] * vec[1] - tmp[1] * vec[0];
if(f < MO_EDIT_PROCESS_COLAPSE_SIZE && f > -MO_EDIT_PROCESS_COLAPSE_SIZE)
{
f = tmp[0] * vec[0] + tmp[1] * vec[1];
if(f > MO_EDIT_PROCESS_COLAPSE_SIZE && f < length - MO_EDIT_PROCESS_COLAPSE_SIZE)
{
mo_edit_process_edge_set(edit, ref_a, i, material_a, material_b);
mo_edit_process_edge_set(edit, i, ref_b, material_a, material_b);
return;
}
}
}
}
if(edit->vertex_users[ref_a] != -1)
{
unsigned int start, pos;
start = pos = edit->vertex_users[ref_a];
while(TRUE)
{
pos = edit->edges[pos / 2].next[pos % 2];
if(edit->edges[pos / 2].ref[0] == ref_a &&
edit->edges[pos / 2].ref[1] == ref_b)
{
edit->edges[pos / 2].type[0] = mo_edit_process_material_dominat(edit->edges[pos / 2].type[0], material_a);
edit->edges[pos / 2].type[1] = mo_edit_process_material_dominat(edit->edges[pos / 2].type[1], material_b);
return;
}
if(edit->edges[pos / 2].ref[0] == ref_b &&
edit->edges[pos / 2].ref[1] == ref_a)
{
edit->edges[pos / 2].type[0] = mo_edit_process_material_dominat(edit->edges[pos / 2].type[0], material_b);
edit->edges[pos / 2].type[1] = mo_edit_process_material_dominat(edit->edges[pos / 2].type[1], material_a);
return;
}
pos = (pos / 2) * 2 + (pos + 1) % 2;
if(pos == start)
break;
}
}
if(mo_edit_process_split_edge(edit, ref_a, ref_b, material_a, material_b))
return;
// EDGE test
if(edit->edges_allocated == edit->edge_count)
{
edit->edges_allocated *= 2;
edit->edges = realloc(edit->edges, (sizeof *edit->edges) * edit->edges_allocated);
}
edge = edit->edge_count++;
edit->edges[edge].type[0] = material_a;
edit->edges[edge].type[1] = material_b;
edit->edges[edge].ref[0] = ref_a;
edit->edges[edge].ref[1] = ref_b;
edit->edges[edge].next[0] = -1;
edit->edges[edge].prev[0] = -1;
edit->edges[edge].next[1] = -1;
edit->edges[edge].prev[1] = -1;
/* if(edit->vertex_users[ref_a] == -1)
{
edit->edges[edge].next[0] = edge * 2 + 1;
edit->edges[edge].prev[1] = edge * 2;
edit->vertex_users[ref_a] = edge * 2;
}else*/
mo_edit_process_edge_end_integrate(edit, edge, 0);
/* if(edit->vertex_users[ref_b] == -1)
{
edit->edges[edge].prev[0] = edge * 2 + 1;
edit->edges[edge].next[1] = edge * 2;
edit->vertex_users[ref_b] = edge * 2 + 1;
}else*/
mo_edit_process_edge_end_integrate(edit, edge, 1);
if(edit->edges[edge].next[0] == -1 ||
edit->edges[edge].prev[0] == -1 ||
edit->edges[edge].next[1] == -1 ||
edit->edges[edge].prev[1] == -1)
{
printf("ERROR");
}
}
MoEditProcess *mo_edit_process_init(float *vertex_array, unsigned int *loop_sizes, unsigned int loop_count)
{
unsigned int mirror_count[] = {1, 2, 3, 4, 2, 4};
MoEditProcess *edit;
unsigned int i, j, k, size;
size = loop_sizes[loop_count - 1];
edit = malloc(sizeof *edit);
edit->edges_allocated = size * 2 * 256;
edit->edges = malloc((sizeof *edit->edges) * edit->edges_allocated);
edit->edge_count = 0;
edit->vertex_allocated = size * 2;
edit->vertex_array = malloc((sizeof *edit->vertex_array) * edit->vertex_allocated * 2);
edit->vertex_users = malloc((sizeof *edit->vertex_users) * edit->vertex_allocated);
edit->vertex_count = 0;
edit->loop_alloc = loop_count;
edit->loops = malloc((sizeof *edit->loops) * edit->loop_alloc);
edit->loop_count = loop_count;
for(i = j = 0; i < loop_count; i++)
{
edit->loops[i].loop = malloc((sizeof *edit->loops) * (loop_sizes[i] - j));
edit->loops[i].direction = 0;
edit->loops[i].material = 0;
edit->loops[i].loop_count = 0;
for(; j < loop_sizes[i]; j++)
edit->loops[i].loop[edit->loops[i].loop_count++] = mo_edit_process_vertex_allocate(edit, vertex_array[j * 2], vertex_array[j * 2 + 1]);
}
for(i = 0; i < edit->loop_count; i++)
for(j = 0; j < edit->loops[i].loop_count; j++)
mo_edit_process_edge_set(edit, edit->loops[i].loop[j], edit->loops[i].loop[(j + 1) % edit->loops[i].loop_count], edit->loops[i].material, -2);
return edit;
}
void mo_edit_process_surround(MoEditProcess *edit)
{
float max[2], min[2];
unsigned int square[4];
unsigned int i, j, k, size, *ids;
for(i = 0; i < edit->edge_count; i++)
{
if(edit->edges[i].type[0] == -1)
edit->edges[i].type[0] = MO_LST_HOLE;
if(edit->edges[i].type[1] == -1)
edit->edges[i].type[1] = MO_LST_HOLE;
}
max[0] = min[0] = edit->vertex_array[0];
max[1] = min[1] = edit->vertex_array[1];
for(i = 1; i < edit->vertex_count; i++)
{
if(edit->vertex_array[i * 2 + 0] > max[0])
max[0] = edit->vertex_array[i * 2 + 0];
if(edit->vertex_array[i * 2 + 0] < min[0])
min[0] = edit->vertex_array[i * 2 + 0];
if(edit->vertex_array[i * 2 + 1] > max[1])
max[1] = edit->vertex_array[i * 2 + 1];
if(edit->vertex_array[i * 2 + 1] < min[1])
min[1] = edit->vertex_array[i * 2 + 1];
}
square[0] = mo_edit_process_vertex_allocate(edit, min[0] - 0.1, min[1] - 0.1);
square[1] = mo_edit_process_vertex_allocate(edit, min[0] - 0.1, max[1] + 0.1);
square[2] = mo_edit_process_vertex_allocate(edit, max[0] + 0.1, max[1] + 0.1);
square[3] = mo_edit_process_vertex_allocate(edit, max[0] + 0.1, min[1] - 0.1);
mo_edit_process_edge_set(edit, square[0], square[1], MO_LST_HOLE, -1);
mo_edit_process_edge_set(edit, square[1], square[2], MO_LST_HOLE, -1);
mo_edit_process_edge_set(edit, square[2], square[3], MO_LST_HOLE, -1);
mo_edit_process_edge_set(edit, square[3], square[0], MO_LST_HOLE, -1);
}
void mo_edit_process_loop_extract(MoEditProcess *edit, unsigned int material_id)
{
float vec[2], f, test[2];
unsigned int *buffer, count;
unsigned int i, j, type, uint_;
buffer = malloc((sizeof *buffer) * edit->edge_count * 2);
for(i = 0; i < edit->loop_count; i++)
{
free(edit->loops[i].loop);
}
edit->loop_count = 0;
for(i = 0; i < edit->edge_count * 2; i++)
{
type = edit->edges[i / 2].type[i % 2];
if(type != -2)
{
count = mo_edit_find_loop(edit, i, buffer);
if(count != -1)
{
if(edit->loop_count == edit->edges_allocated)
{
edit->edges_allocated += 16;
edit->loops = realloc(edit->loops, (sizeof *edit->loops) * edit->edges_allocated);
}
edit->loops[edit->loop_count].loop = buffer;
edit->loops[edit->loop_count].loop_count = count;
edit->loops[edit->loop_count].material = type;
edit->loops[edit->loop_count].used = FALSE;
edit->loop_count++;
buffer = malloc((sizeof *buffer) * edit->edge_count);
}
}
}
free(buffer);
}
void mo_edit_process_re_ingest(MoEditProcess *edit)
{
unsigned int i, j;
for(i = 0; i < edit->vertex_count; i++)
edit->vertex_users[i] = -1;
for(i = 0; i < edit->loop_count; i++)
{
if(edit->loops[i].used)
for(j = 0; j < edit->loops[i].loop_count; j++)
mo_edit_process_edge_set(edit, edit->loops[i].loop[(j + 1) % edit->loops[i].loop_count], edit->loops[i].loop[j], edit->loops[i].material, -1);
free(edit->loops[i].loop);
}
edit->loop_count = 0;
}
void mo_edit_process_free(MoEditProcess *edit)
{
free(edit->edges);
free(edit->vertex_array);
free(edit->vertex_users);
free(edit->loops);
free(edit);
}
int mo_edit_process_loop_direction(unsigned int *loop, unsigned int loop_length, float *vertex)
{
unsigned int i;
float sum;
loop_length--;
sum = (vertex[loop[0] * 2] - vertex[loop[loop_length] * 2]) * (vertex[loop[0] * 2 + 1] + vertex[loop[loop_length] * 2 + 1]);
for(i = 0; i < loop_length; i++)
sum += (vertex[loop[i + 1] * 2] - vertex[loop[i] * 2]) * (vertex[loop[i + 1] * 2 + 1] + vertex[loop[i] * 2 + 1]);
return sum > 0;
}
void mo_edit_reloop(MoEditProcess *edit)
{
unsigned int i, j, k, pos, next, start_edge, edge, count = 0, vertex_id, goal_id, *buffer, buffer_use;
float goal_vec[2], vec[2], f, best;
buffer = malloc((sizeof *buffer) * edit->edge_count * 2);
for(i = 0; i < edit->loop_count; i++)
{
buffer_use = 0;
for(j = 0; j < edit->loops[i].loop_count; j++)
{
vertex_id = edit->loops[i].loop[j];
goal_id = edit->loops[i].loop[(j + 1) % edit->loops[i].loop_count];
while(vertex_id != goal_id)
{
start_edge = edge = edit->vertex_users[vertex_id];
while(TRUE)
{
if(edit->edges[edge / 2].ref[(edge + 1) % 2] == goal_id)
{
vertex_id = goal_id;
break;
}
edge = edit->edges[edge / 2].next[edge % 2];
edge = (edge / 2) * 2 + (edge + 1) % 2;
if(start_edge == edge)
break;
}
if(start_edge == edge)
{
goal_vec[0] = edit->vertex_array[goal_id * 2 + 0] - edit->vertex_array[vertex_id * 2 + 0];
goal_vec[1] = edit->vertex_array[goal_id * 2 + 1] - edit->vertex_array[vertex_id * 2 + 1];
best = 0;
while(TRUE)
{
vec[0] = edit->vertex_array[edit->edges[edge / 2].ref[(edge + 1) % 2] * 2 + 0] - edit->vertex_array[edit->edges[edge / 2].ref[edge % 2] * 2 + 0];
vec[1] = edit->vertex_array[edit->edges[edge / 2].ref[(edge + 1) % 2] * 2 + 1] - edit->vertex_array[edit->edges[edge / 2].ref[edge % 2] * 2 + 1];
f_normalize2f(vec);
f = goal_vec[0] * vec[0] + goal_vec[1] * vec[1];
if(f > best)
{
best = f;
vertex_id = edit->edges[edge / 2].ref[(edge + 1) % 2];
}
edge = edit->edges[edge / 2].next[edge % 2];
edge = (edge / 2) * 2 + (edge + 1) % 2;
if(start_edge == edge)
break;
}
}
buffer[buffer_use++] = vertex_id;
}
}
free(edit->loops[i].loop);
edit->loops[i].loop = malloc((sizeof *edit->loops[i].loop) * buffer_use);
for(j = 0; j < buffer_use; j++)
edit->loops[i].loop[j] = buffer[j];
edit->loops[i].loop_count = buffer_use;
}
free(buffer);
}
void mo_edit_process_sort(MoEditProcess *edit)
{
unsigned int i, j, generation;
for(i = 0; i < edit->loop_count; i++)
edit->loops[i].used = TRUE;
for(i = 0; i < edit->loop_count; i++)
{
if(edit->loops[i].used && !mo_edit_process_loop_direction(edit->loops[i].loop, edit->loops[i].loop_count, edit->vertex_array)) /* if an outside shape */
{
generation = 0;
for(j = 0; j < edit->loop_count; j++) /* see how many layers we are inside */
if(edit->loops[i].material == edit->loops[j].material)
if(mo_edit_process_inside_test(edit->loops[i].loop[0], &edit->vertex_array[edit->loops[i].loop[0] * 2], edit->loops[j].loop, edit->loops[j].loop_count, edit->vertex_array))
generation++;
if(generation != 0) /* we are on the inside of something */
{
edit->loops[i].used = FALSE;
for(j = 0; j < edit->loop_count; j++) /* remove anything uinside of this one */
if(edit->loops[i].material == edit->loops[j].material)
if(mo_edit_process_inside_test(edit->loops[j].loop[0], &edit->vertex_array[edit->loops[j].loop[0] * 2], edit->loops[i].loop, edit->loops[i].loop_count, edit->vertex_array))
edit->loops[j].used = FALSE;
}
}
// edit->loops[i].used = mo_edit_process_loop_direction(edit->loops[i].loop, edit->loops[i].loop_count, edit->vertex_array);
}
}
unsigned int mo_edit_loop_connect_intersect_test(MoEditProcess *edit, unsigned int other_point, unsigned int target_vertex, unsigned int *loop, unsigned int loop_count)
{
float *a, *b, *point_a, *point_b, vector[2], v[2], x;
unsigned int i, ii;
point_a = &edit->vertex_array[other_point * 2];
x = point_a[0];
point_b = &edit->vertex_array[target_vertex * 2];
vector[0] = point_b[0] - point_a[0];
vector[1] = point_b[1] - point_a[1];
for(i = 0; i < loop_count; i++)
{
ii = (i + 1) % loop_count;
a = &edit->vertex_array[loop[i] * 2];
b = &edit->vertex_array[loop[ii] * 2];
if(a[0] > x || b[0] > x)
{
if((a[0] - point_a[0]) * vector[1] - (a[1] - point_a[1]) * vector[0] > 0)
{
if((b[0] - point_a[0]) * vector[1] - (b[1] - point_a[1]) * vector[0] < 0)
{
v[0] = b[0] - a[0];
v[1] = b[1] - a[1];
if((point_a[0] - a[0]) * v[1] - (point_a[1] - a[1]) * v[0] < 0)
{
if((point_b[0] - a[0]) * v[1] - (point_b[1] - a[1]) * v[0] > 0)
{
if(loop[i] != target_vertex && loop[ii] != target_vertex)
{
f_intersect2f(vector, a, b, point_a, point_b);
if(a[0] > b[0])
return i;
else
return ii;
}
}
}
}
}
}
}
return -1;
}
unsigned int mo_edit_loop_merge_loops(MoEditProcess *edit, unsigned int *ref, unsigned int *outer, unsigned int outer_count, unsigned int *inner, unsigned int inner_count, unsigned int inner_start, int direction)
{
float x, y, tmp, vec[2], vec1[2], vec2[2], best = 100000000000;
unsigned int i, found = -1, id = 0, count;
x = edit->vertex_array[inner[inner_start] * 2 + 0];
y = edit->vertex_array[inner[inner_start] * 2 + 1];
for(i = 0; i < outer_count; i++)
{
tmp = edit->vertex_array[outer[i] * 2 + 0];
if(tmp >= x)
{
vec[0] = x - tmp;
vec[1] = (y - edit->vertex_array[outer[i] * 2 + 1]) / 2.0;
tmp = vec[0] * vec[0] + vec[1] * vec[1];
if(tmp < best)
{
best = tmp;
found = i;
}
}
}
i = found;
while(i != -1)
{
found = i;
i = mo_edit_loop_connect_intersect_test(edit, inner[inner_start], outer[found], outer, outer_count);
}
best = 10000000;
for(i = 0; i < outer_count; i++)
{
if(outer[found] == outer[i])
{
vec[0] = edit->vertex_array[outer[i] * 2 + 0];
vec[1] = edit->vertex_array[outer[i] * 2 + 1];
vec1[0] = edit->vertex_array[outer[(i + 1) % outer_count] * 2 + 0] - vec[0];
vec1[1] = edit->vertex_array[outer[(i + 1) % outer_count] * 2 + 1] - vec[1];
f_normalize2f(vec1);
vec2[0] = edit->vertex_array[outer[(i + outer_count - 1) % outer_count] * 2 + 0] - vec[0];
vec2[1] = edit->vertex_array[outer[(i + outer_count - 1) % outer_count] * 2 + 1] - vec[1];
f_normalize2f(vec2);
vec[0] = vec[0] - x + vec1[0] + vec2[0];
vec[1] = vec[1] - y + vec1[1] + vec2[1];
tmp = vec[0] * vec[0] + vec[1] * vec[1];
if(tmp < best)
{
if(found != i)
found = i;
best = tmp;
}
}
}
for(i = 0; i < outer_count; i++)
ref[id++] = outer[(i + found) % outer_count];
if(direction)
{
if(outer[found] != inner[(i + inner_start) % inner_count])
ref[id++] = outer[found];
for(i = 0; i < inner_count; i++)
ref[id++] = inner[(i + inner_start) % inner_count];
if(ref[0] != inner[inner_start])
ref[id++] = inner[inner_start];
}else
{
ref[id++] = outer[found];
if(outer[found] != inner[inner_start])
ref[id++] = inner[inner_start];
for(i = inner_count; i > 1; i--)
ref[id++] = inner[(i - 1 + inner_start) % inner_count];
if(ref[0] != inner[(i - 1 + inner_start) % inner_count])
ref[id++] = inner[(i - 1 + inner_start) % inner_count];
}
for(i = 0; i < id; i++)
if(ref[i] == ref[(i + 1) % id])
i = 0;
if(outer_count + inner_count + 2 != id)
i = 0;
return id;
}
void mo_edit_loop_remove_inside(MoEditProcess *edit)
{
unsigned int i, j, k;
float vec[2], *p, *p2, point[2], f;
for(i = 0; i < edit->loop_count; i++)
edit->loops[i].used = FALSE;
for(i = 0; i < edit->loop_count; i++)
if(edit->loops[i].material != -1)
for(j = 0; j < edit->loop_count; j++)
if(edit->loops[j].material == edit->loops[j].material && !edit->loops[i].used && !edit->loops[j].used)
if(mo_edit_process_inside_test(edit->loops[j].loop[0], &edit->vertex_array[edit->loops[j].loop[0] * 2], edit->loops[i].loop, edit->loops[i].loop_count, edit->vertex_array))
{
p = &edit->vertex_array[edit->loops[j].loop[0] * 2];
p2 = &edit->vertex_array[edit->loops[j].loop[1] * 2];
vec[0] = p[0] - p2[0];
vec[1] = p[1] - p2[1];
f = sqrt(vec[0] * vec[0] + vec[1] + vec[1]);
point[0] = (p[0] + p2[0]) * 0.5 + vec[1] / f * MO_EDIT_PROCESS_COLAPSE_SIZE;
point[1] = (p[1] + p2[1]) * 0.5 - vec[0] / f * MO_EDIT_PROCESS_COLAPSE_SIZE;
if(mo_edit_process_inside_test(-1, point, edit->loops[j].loop, edit->loops[j].loop_count, edit->vertex_array))
edit->loops[j].used = TRUE;
}
}
/*
if(edit->loops[i].used && !mo_edit_process_loop_direction(edit->loops[i].loop, edit->loops[i].loop_count, edit->vertex_array))
{
generation = 0;
for(j = 0; j < edit->loop_count; j++)
if(edit->loops[i].material == edit->loops[j].material)
if(mo_edit_process_inside_test(edit->loops[i].loop[0], &edit->vertex_array[edit->loops[i].loop[0] * 2], edit->loops[j].loop, edit->loops[j].loop_count, edit->vertex_array))
generation++;
*/
void mo_edit_loop_connect(MoEditProcess *edit)
{
unsigned int i, j, k, *holes, hole_count, *loop, start, size, **original_loops, *original_loop_size, *original_loop_material, original_loop_count = 0;
float best, test[2];
int first;
holes = malloc((sizeof *holes) * edit->loop_count);
original_loops = malloc((sizeof *original_loops) * edit->loop_count);
original_loop_size = malloc((sizeof *original_loop_size) * edit->loop_count);
original_loop_material = malloc((sizeof *original_loop_material) * edit->loop_count);
for(i = 0; i < edit->loop_count; i++)
edit->loops[i].direction = mo_edit_process_loop_direction(edit->loops[i].loop, edit->loops[i].loop_count, edit->vertex_array);
for(i = 0; i < edit->loop_count; i++)
{
best = edit->vertex_array[edit->loops[i].loop[0] * 2];
edit->loops[i].start = 0;
for(j = 1; j < edit->loops[i].loop_count; j++)
{
if(best < edit->vertex_array[edit->loops[i].loop[j] * 2])
{
best = edit->vertex_array[edit->loops[i].loop[j] * 2];
edit->loops[i].start = j;
}
}
}
for(i = 0; i < edit->loop_count; i++)
{
edit->loops[i].used = FALSE;
edit->loops[i].generation = 0;
}
for(i = 0; i < edit->loop_count; i++)
{
// printf("[%u] material %u %u lenght %u\n", i, edit->loops[i].material, -1, edit->loops[i].loop_count);
if(!edit->loops[i].used && !edit->loops[i].direction)
{
hole_count = 0;
for(j = 0; j < edit->loop_count; j++)
if(!edit->loops[j].used && edit->loops[i].material == edit->loops[j].material)
if(mo_edit_process_inside_test(edit->loops[j].loop[0], &edit->vertex_array[edit->loops[j].loop[0] * 2], edit->loops[i].loop, edit->loops[i].loop_count, edit->vertex_array))
holes[hole_count++] = j;
for(j = 0; j < hole_count; j++)
{
for(k = 0; k < hole_count; k++)
{
if(j != k && mo_edit_process_inside_test(edit->loops[holes[k]].loop[0], &edit->vertex_array[edit->loops[holes[k]].loop[0] * 2], edit->loops[holes[j]].loop, edit->loops[holes[j]].loop_count, edit->vertex_array))
{
holes[k--] = holes[--hole_count];
break;
}
}
}
for(j = 0; j < original_loop_count; j++)
{
if(mo_edit_process_inside_test(original_loops[j][0], &edit->vertex_array[original_loops[j][0] * 2], edit->loops[i].loop, edit->loops[i].loop_count, edit->vertex_array))
{
for(k = 0; k < hole_count; k++)
{
if(j != k && mo_edit_process_inside_test(edit->loops[holes[k]].loop[0], &edit->vertex_array[edit->loops[holes[k]].loop[0] * 2], original_loops[j], original_loop_size[j], edit->vertex_array))
{
holes[k--] = holes[--hole_count];
break;
}
}
}
}
/* for(j = 0; j < hole_count; j++)
{
free(original_loops[i]);
free(original_loops);
free(original_loop_size);*/
// printf("holes found %u\n", hole_count);
first = TRUE;
while(hole_count > 0)
{
k = 0;
for(j = 1; j < hole_count; j++)
if(edit->vertex_array[edit->loops[holes[k]].loop[edit->loops[holes[k]].start] * 2] < edit->vertex_array[edit->loops[holes[j]].loop[edit->loops[holes[j]].start] * 2])
k = j;
first = FALSE;
test[0] = edit->vertex_array[edit->loops[holes[k]].loop[edit->loops[holes[k]].start] * 2];
test[1] = edit->vertex_array[edit->loops[holes[k]].loop[edit->loops[holes[k]].start] * 2 + 1];
loop = malloc((sizeof *loop) * (edit->loops[i].loop_count + 2 + edit->loops[holes[k]].loop_count));
size = mo_edit_loop_merge_loops(edit, loop, edit->loops[i].loop, edit->loops[i].loop_count,
edit->loops[holes[k]].loop, edit->loops[holes[k]].loop_count, edit->loops[holes[k]].start, edit->loops[holes[k]].direction);
original_loops[original_loop_count] = edit->loops[i].loop;
original_loop_material[original_loop_count] = edit->loops[i].material;
original_loop_size[original_loop_count++] = edit->loops[i].loop_count;
edit->loops[i].loop = loop;
edit->loops[i].loop_count = size;
edit->loops[holes[k]].used = TRUE;
holes[k] = holes[--hole_count];
}
}
}
for(i = 0; i < original_loop_count; i++)
free(original_loops[i]);
free(original_loops);
free(original_loop_size);
free(holes);
}
void mo_edit_loop_polygonize(MoEditProcess *edit, unsigned int *loop, unsigned int size, unsigned int *ref)
{
unsigned int i = 0, a = 0, b = 1, c = 2, vertex, count = 2, found[3], output = 0, ref_length = 0, save[2];
float *array, vec[2], *v, *base, *back, sides[4], f, dist, best;
array = edit->vertex_array;
for(i = 0; i < (size - 2) * 3; i++)
ref[i] = 0;
while(count < size)
{
save[1] = -1;
if(count + 1 < size)
{
best = 1000000;
for(i = 0; i < size; i++)
{
a = b;
b = c;
c = (c + 1) % size;
while(loop[c] == -1)
c = (c + 1) % size;
base = &array[loop[c] * 2];
vec[0] = array[loop[a] * 2 + 0] - base[0];
vec[1] = array[loop[a] * 2 + 1] - base[1];
f_normalize2f(vec);
back = &array[loop[b] * 2 + 0];
dist = (vec[1] * (back[0] - base[0]) - vec[0] * (back[1] - base[1]));
sides[0] = array[loop[a] * 2 + 0] - back[0];
sides[1] = array[loop[a] * 2 + 1] - back[1];
sides[2] = array[loop[c] * 2 + 0] - back[0];
sides[3] = array[loop[c] * 2 + 1] - back[1];
save[0] = -1;
for(vertex = (c + 1) % size; vertex != a; vertex = (vertex + 1) % size)
{
if(loop[vertex] != -1)
{
v = &array[loop[vertex] * 2];
if(0 <= sides[1] * (v[0] - back[0]) - sides[0] * (v[1] - back[1]) &&
0 >= sides[3] * (v[0] - back[0]) - sides[2] * (v[1] - back[1]))
{
f = (vec[1] * (base[0] - v[0]) - vec[0] * (base[1] - v[1]));
if(f > dist)
{
if(f < 0.0 || (0 < sides[1] * (v[0] - back[0]) - sides[0] * (v[1] - back[1]) && 0 > sides[3] * (v[0] - back[0]) - sides[2] * (v[1] - back[1])))
{
save[0] = loop[vertex];
dist = f;
}
}
}
}
}
if(dist < best)
{
save[1] = save[0];
best = dist;
found[0] = a;
found[1] = b;
found[2] = c;
}
}
a = found[0];
b = found[1];
c = found[2];
}
ref[ref_length++] = loop[a];
ref[ref_length++] = loop[b];
ref[ref_length++] = loop[c];
loop[b] = -1;
b = c;
c = (c + 1) % size;
while(loop[c] == -1)
c = (c + 1) % size;
count++;
}
}
void mo_edit_process_polygon_turn(unsigned int *neighbor, unsigned int *reference, unsigned int polygon, unsigned int edge)
{
unsigned int n_poly, n_edge, tmp;
n_poly = neighbor[polygon * 3 + edge];
n_edge = n_poly % 3;
n_poly = n_poly / 3;
tmp = reference[polygon * 3 + (edge + 2) % 3];
reference[polygon * 3 + (edge + 1) % 3] = reference[n_poly * 3 + (n_edge + 2) % 3];
reference[n_poly * 3 + (n_edge + 1) % 3] = tmp;
tmp = neighbor[polygon * 3 + (edge + 1) % 3];
if(tmp != -1)
{
neighbor[tmp] = n_poly * 3 + (n_edge + 0) % 3;
neighbor[neighbor[tmp]] = tmp;
}else
neighbor[n_poly * 3 + (n_edge + 0) % 3] = -1;
tmp = neighbor[n_poly * 3 + (n_edge + 1) % 3];
if(tmp != -1)
{
neighbor[tmp] = polygon * 3 + (edge + 0) % 3;
neighbor[neighbor[tmp]] = tmp;
}else
neighbor[polygon * 3 + (edge + 0) % 3] = -1;
tmp = n_poly * 3 + (n_edge + 1) % 3;
neighbor[tmp] = polygon * 3 + (edge + 1) % 3;
neighbor[neighbor[tmp]] = tmp;
}
#define MOON_FIXED_POINT 1024
int mo_edit_process_polygon_turn_test(unsigned int *neighbor, unsigned int *reference, int *vertexi, unsigned char *poly_type, unsigned int polygon, unsigned int edge)
{
int *corners[4], edge_vec[4][2], center_vec[2][2], n, tmp, a, b;
if(neighbor[polygon * 3 + edge] == -1 ||
poly_type[polygon] != poly_type[neighbor[polygon * 3 + edge] / 3])
return FALSE;
corners[0] = &vertexi[reference[polygon * 3 + (edge + 0) % 3] * 3];
n = neighbor[polygon * 3 + edge];
corners[1] = &vertexi[reference[(n / 3) * 3 + (n + 2) % 3] * 3];
corners[2] = &vertexi[reference[polygon * 3 + (edge + 1) % 3] * 3];
corners[3] = &vertexi[reference[polygon * 3 + (edge + 2) % 3] * 3];
edge_vec[0][0] = corners[1][0] - corners[0][0];
edge_vec[0][1] = corners[1][2] - corners[0][2];
edge_vec[1][0] = corners[2][0] - corners[1][0];
edge_vec[1][1] = corners[2][2] - corners[1][2];
edge_vec[2][0] = corners[3][0] - corners[2][0];
edge_vec[2][1] = corners[3][2] - corners[2][2];
edge_vec[3][0] = corners[0][0] - corners[3][0];
edge_vec[3][1] = corners[0][2] - corners[3][2];
center_vec[0][0] = corners[2][0] - corners[0][0];
center_vec[0][1] = corners[2][2] - corners[0][2];
center_vec[1][0] = corners[3][0] - corners[1][0];
center_vec[1][1] = corners[3][2] - corners[1][2];
f_normalize_2di(center_vec[0], MOON_FIXED_POINT);
f_normalize_2di(center_vec[1], MOON_FIXED_POINT);
if((corners[0][0] - corners[1][0]) * center_vec[1][1] - (corners[0][2] - corners[1][2]) * center_vec[1][0] > 0)
return FALSE;
if((corners[2][0] - corners[1][0]) * center_vec[1][1] - (corners[2][2] - corners[1][2]) * center_vec[1][0] < 0)
return FALSE;
f_normalize_2di(edge_vec[0], MOON_FIXED_POINT);
f_normalize_2di(edge_vec[1], MOON_FIXED_POINT);
f_normalize_2di(edge_vec[2], MOON_FIXED_POINT);
f_normalize_2di(edge_vec[3], MOON_FIXED_POINT);
/* need convex test here*/
a = edge_vec[0][0] * center_vec[0][0] + edge_vec[0][1] * center_vec[0][1];
tmp = -edge_vec[3][0] * center_vec[0][0] + -edge_vec[3][1] * center_vec[0][1];
if(tmp > a)
a = tmp;
tmp = -edge_vec[1][0] * -center_vec[0][0] + -edge_vec[1][1] * -center_vec[0][1];
if(tmp > a)
a = tmp;
tmp = edge_vec[2][0] * -center_vec[0][0] + edge_vec[2][1] * -center_vec[0][1];
if(tmp > a)
a = tmp;
b = -edge_vec[0][0] * center_vec[1][0] + -edge_vec[0][1] * center_vec[1][1];
// b = edge_vec[0][0] * center_vec[1][0] + edge_vec[0][1] * center_vec[1][1];
tmp = edge_vec[1][0] * center_vec[1][0] + edge_vec[1][1] * center_vec[1][1];
// tmp = -edge_vec[3][0] * center_vec[1][0] + -edge_vec[3][1] * center_vec[1][1];
if(tmp > b)
b = tmp;
tmp = edge_vec[3][0] * -center_vec[1][0] + edge_vec[3][1] * -center_vec[1][1];
// tmp = -edge_vec[1][0] * -center_vec[1][0] + -edge_vec[1][1] * -center_vec[1][1];
if(tmp > b)
b = tmp;
tmp = -edge_vec[2][0] * -center_vec[1][0] + -edge_vec[2][1] * -center_vec[1][1];
// tmp = edge_vec[2][0] * -center_vec[1][0] + edge_vec[2][1] * -center_vec[1][1];
if(tmp > b)
b = tmp;
if(a > b)
{
mo_edit_process_polygon_turn(neighbor, reference, polygon, edge);
return TRUE;
}
return FALSE;
}
void mo_edit_process_polygon_turn_all(unsigned int *neighbor, unsigned int *reference, int *vertexi, unsigned char *poly_type, unsigned int tri_length)
{
int *buffer, found;
unsigned int i, j, k, next, poly_count;
poly_count = tri_length / 3;
buffer = malloc((sizeof *buffer) * poly_count);
for(j = 0; j < poly_count; j++)
buffer[j] = TRUE;
for(i = 0; i < poly_count;)
{
for(j = 0; j < poly_count; j++)
{
i++;
if(buffer[j])
{
found = FALSE;
for(k = 0; k < 3; k++)
{
next = neighbor[j * 3 + k];
if(mo_edit_process_polygon_turn_test(neighbor, reference, vertexi, poly_type, j, k))
{
buffer[next / 3] = TRUE;
buffer[j] = TRUE;
i = 0;
}
}
}
}
}
free(buffer);
}
void mo_edit_process_polygonize(MoEditProcess *edit)
{
unsigned int i, j, size, *ref, *neighbor, building = MO_LST_FACTORY_UNASIGNED;
int *vertex_array;
unsigned char *type;
for(i = size = 0; i < edit->loop_count; i++)
if(!edit->loops[i].direction && !edit->loops[i].used && edit->loops[i].material != -1)
size += (edit->loops[i].loop_count - 2) * 3;
ref = malloc((sizeof *ref) * size);
type = malloc((sizeof *type) * size / 3);
for(i = size = 0; i < edit->loop_count; i++)
{
if(!edit->loops[i].direction && !edit->loops[i].used && edit->loops[i].material != -1)
{
for(j = 0; j < edit->loops[i].loop_count; j++)
if(edit->loops[i].loop[j] == edit->loops[i].loop[(j + 1) % edit->loops[i].loop_count])
j = 0;
mo_edit_loop_polygonize(edit, edit->loops[i].loop, edit->loops[i].loop_count, &ref[size]);
for(j = 0; j < (edit->loops[i].loop_count - 2); j++)
type[size / 3 + j] = edit->loops[i].material;
size += (edit->loops[i].loop_count - 2) * 3;
}
}
edit->ref_count = size;
edit->ref = ref;
edit->material = type;
return;
}
void mo_edit_process_deploy(float *vertex_array, unsigned int *loop_sizes, unsigned int loop_count, ProcessOutput *output)
{
MoEditProcess *edit;
float offset[2] = {0, 0};
edit = mo_edit_process_init(vertex_array, loop_sizes, loop_count);
mo_edit_reloop(edit);
mo_edit_process_vertex_dominance2(edit);
mo_edit_process_reduce(edit);
mo_edit_process_loop_extract(edit, -1);
// mo_edit_process_test_draw(edit);
mo_edit_loop_connect(edit);
// mo_edit_process_loop_draw(edit);
mo_edit_process_polygonize(edit);
output->vertex_array = edit->vertex_array;
output->vertex_count = edit->vertex_count;
output->ref_count = edit->ref_count;
output->ref = edit->ref;
output->material = edit->material;
free(edit->edges);
free(edit->vertex_users);
free(edit->loops);
free(edit);
}