From: kramm Date: Mon, 20 Aug 2007 19:36:30 +0000 (+0000) Subject: first half of Huub Schaek's sweep patch X-Git-Tag: buttons-working~584 X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=commitdiff_plain;h=01d3feb7d0121737b3456a3cfbaf6a02b6362d8d first half of Huub Schaek's sweep patch --- diff --git a/lib/modules/swftext.c b/lib/modules/swftext.c index d7c0470..d9e4115 100644 --- a/lib/modules/swftext.c +++ b/lib/modules/swftext.c @@ -684,7 +684,7 @@ int swf_FontReduce_swfc(SWFFONT * f) } f->use->used_glyphs = j; for (i = 0; i < f->maxascii; i++) { - if(f->ascii2glyph[i] > -1) { + if(f->ascii2glyph[i] > -1) if (f->use->chars[f->ascii2glyph[i]]<0) { f->use->chars[f->ascii2glyph[i]] = 0; f->ascii2glyph[i] = -1; @@ -694,7 +694,6 @@ int swf_FontReduce_swfc(SWFFONT * f) max_unicode = i + 1; } } - } f->maxascii = max_unicode; f->use->is_reduced = 1; f->numchars = j; diff --git a/lib/q.c b/lib/q.c index 0083dcd..e703b93 100644 --- a/lib/q.c +++ b/lib/q.c @@ -389,7 +389,11 @@ stringarray_t* dictionary_index(dictionary_t*dict) dictionary_internal_t*d = (dictionary_internal_t*)dict->internal; return &d->keys; } - +int dictionary_count(dictionary_t* dict) // this count includes entries that have been deleted +{ + dictionary_internal_t*d = (dictionary_internal_t*)dict->internal; + return d->num; +} void* dictionary_lookup(dictionary_t*dict, const char*name) { int s; diff --git a/lib/q.h b/lib/q.h index 35629d8..18e7f3a 100644 --- a/lib/q.h +++ b/lib/q.h @@ -112,6 +112,7 @@ void dictionary_init(dictionary_t*dict); void dictionary_put(dictionary_t*dict, string_t t1, void* t2); void dictionary_put2(dictionary_t*dict, const char* t1, void* t2); stringarray_t* dictionary_index(dictionary_t*dict); +int dictionary_count(dictionary_t* dict); void* dictionary_lookup(dictionary_t*dict, const char*name); void dictionary_dump(dictionary_t*dict, FILE*fi, const char*prefix); void dictionary_del(dictionary_t*dict, const char* name); diff --git a/src/Makefile.in b/src/Makefile.in index 807a6dc..8fe1291 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -39,9 +39,9 @@ swfc.$(O): swfc.c parser.h ../lib/q.h $(C) swfc.c -o $@ swfc-feedback.$(O): swfc-feedback.c swfc-feedback.h $(C) swfc-feedback.c -o $@ -swfc-history.$(O): swfc-history.c swfc-history.h +swfc-history.$(O): swfc-history.c swfc-history.h swfc-interpolation.h $(C) swfc-history.c -o $@ -swfc-interpolation.$(O): swfc-feedback.c swfc-feedback.h +swfc-interpolation.$(O): swfc-interpolation.c swfc-interpolation.h $(C) swfc-interpolation.c -o $@ parser.$(O): parser.yy.c parser.h ../lib/q.h $(C) parser.yy.c -o $@ diff --git a/src/swfc-history.c b/src/swfc-history.c index 0d74463..322c325 100644 --- a/src/swfc-history.c +++ b/src/swfc-history.c @@ -23,84 +23,110 @@ #include #include "swfc-history.h" -change_t* change_new(U16 frame, int function, float value, interpolation_t* inter) +enum { - change_t* newChange = (change_t*)malloc(sizeof(change_t)); - change_init(newChange); - newChange->frame = frame; - newChange->function = function; - newChange->value = value; - newChange->interpolation = inter; - return newChange; + T_BEFORE = 0, + T_AFTER = 1, + T_SYMMETRIC = 2 +}; + +state_t* state_new(U16 frame, int function, float value, interpolation_t* inter) +{ + state_t* newState = (state_t*)malloc(sizeof(state_t)); + state_init(newState); + newState->frame = frame; + newState->function = function; + newState->value = value; + newState->interpolation = inter; + return newState; } -void change_free(change_t *change) +void state_free(state_t* state) { - if (change->next) - change_free(change->next); - free(change); + if (state->next) + state_free(state->next); + free(state); +} + +void state_init(state_t* state) +{ + memset(state, 0, sizeof(state_t)); } -void change_init(change_t* change) +state_t* state_at(state_t* state, U16 frame) { - memset(change, 0, sizeof(change_t)); + while (state->next && state->next->frame < frame) + state = state->next; + return state; } -void change_append(change_t* first, change_t* newChange) +void state_append(state_t* state, state_t* newState) { - change_t* previous = 0; - change_t* start = first; + state_t* previous = 0; + state_t* start = state; float p0, p1, m0, m1; - while (first->next) + while (state->next) { - previous = first; - first = first->next; + previous = state; + state = state->next; } - first->next = newChange; - if (first->function == CF_QCHANGE) + state->next = newState; + if (state->function == CF_SCHANGE) { p0 = previous->value; - p1 = first->value; - if (previous->function == CF_QCHANGE) + p1 = state->value; + if (previous->function == CF_SCHANGE) m0 = (3 * previous->spline.a + 2 * previous->spline.b + previous->spline.c); else - if (previous->function == CF_CHANGE) - m0 = (change_value(start, previous->frame) - change_value(start, previous->frame - 1)) * (first->frame - previous->frame); + if (previous->function == CF_CHANGE || previous->function == CF_SWEEP) + m0 = state_tangent(start, previous->frame, T_BEFORE) * (state->frame - previous->frame); else - m0 = (first->value - previous->value); - if (newChange->function == CF_QCHANGE) - m1 = 0.5 * (newChange->value - previous->value); + m0 = (state->value - previous->value); + if (newState->function == CF_SCHANGE) + m1 = 0.5 * (newState->value - previous->value)/* * (state->frame - previous->frame) / (newState->frame - state->frame)*/; else - if (newChange->function == CF_CHANGE) - m1 = (change_value(previous, first->frame + 1) - change_value(previous, first->frame)) * (first->frame - previous->frame); + if (newState->function == CF_CHANGE || newState->function == CF_SWEEP) + m1 = state_tangent(previous, state->frame, T_AFTER) * (state->frame - previous->frame); else - m1 = (first->value - previous->value); - first->spline.a = 2 * p0 + m0 - 2 * p1 + m1; - first->spline.b = -3 * p0 - 2 * m0 + 3 * p1 - m1; - first->spline.c = m0; - first->spline.d = p0; + m1 = (newState->value - state->value); + state->spline.a = 2 * p0 + m0 - 2 * p1 + m1; + state->spline.b = -3 * p0 - 2 * m0 + 3 * p1 - m1; + state->spline.c = m0; + state->spline.d = p0; +// printf("p0: %f, p1: %f, m0: %f, m1: %f.\n", p0, p1, m0, m1); +// printf("a: %f, b: %f, c: %f, d: %f.\n", state->spline.a, state->spline.b, state->spline.c, state->spline.d); } - if (newChange->function == CF_QCHANGE) + if (newState->function == CF_SCHANGE) { - p0 = first->value; - p1 = newChange->value; - if (first->function == CF_QCHANGE) + p0 = state->value; + p1 = newState->value; + if (state->function == CF_SCHANGE) m0 = m1; else - if (first->function == CF_CHANGE) - m0 = (change_value(start, first->frame) - change_value(start, first->frame - 1)) * (first->frame - previous->frame); + if (state->function == CF_CHANGE || state->function == CF_SWEEP) + m0 = state_tangent(start, state->frame, T_BEFORE) * (state->frame - previous->frame); else - m0 = (newChange->value - first->value); - m1 = (newChange->value - first->value); - newChange->spline.a = 2 * p0 + m0 - 2 * p1 + m1; - newChange->spline.b = -3 * p0 - 2 * m0 + 3 * p1 - m1; - newChange->spline.c = m0; - newChange->spline.d = p0; + m0 = (newState->value - state->value); + m1 = (newState->value - state->value); + newState->spline.a = 2 * p0 + m0 - 2 * p1 + m1; + newState->spline.b = -3 * p0 - 2 * m0 + 3 * p1 - m1; + newState->spline.c = m0; + newState->spline.d = p0; } + } + +void state_insert(state_t* state, state_t* newState) +{ + while (state->next && state->next->frame < newState->frame) + state = state->next; + newState->next = state->next; + state->next = newState; + // if this is going to be used to insert CF_SCHANGE states it will have to be extended + // as in state_append above. I know this is not necessary right now, so I'll be lazy. } -float calculateSpline(change_t* modification, float fraction) +float calculateSpline(state_t* modification, float fraction) { spline_t s = modification->spline; return (((s.a * fraction) + s.b) * fraction + s.c) * fraction + s.d; @@ -113,21 +139,21 @@ float interpolateScalar(float p1, float p2, float fraction, interpolation_t* int switch (inter->function) { case IF_LINEAR: return linear(fraction, p1, p2 - p1); - case IF_QUAD_IN: return quadIn(fraction, p1, p2 - p1); - case IF_QUAD_OUT: return quadOut(fraction, p1, p2 - p1); - case IF_QUAD_IN_OUT: return quadInOut(fraction, p1, p2 - p1); - case IF_CUBIC_IN: return cubicIn(fraction, p1, p2 - p1); - case IF_CUBIC_OUT: return cubicOut(fraction, p1, p2 - p1); - case IF_CUBIC_IN_OUT: return cubicInOut(fraction, p1, p2 - p1); - case IF_QUART_IN: return quartIn(fraction, p1, p2 - p1); - case IF_QUART_OUT: return quartOut(fraction, p1, p2 - p1); - case IF_QUART_IN_OUT: return quartInOut(fraction, p1, p2 - p1); - case IF_QUINT_IN: return quintIn(fraction, p1, p2 - p1); - case IF_QUINT_OUT: return quintOut(fraction, p1, p2 - p1); - case IF_QUINT_IN_OUT: return quintInOut(fraction, p1, p2 - p1); - case IF_CIRCLE_IN: return circleIn(fraction, p1, p2 - p1); - case IF_CIRCLE_OUT: return circleOut(fraction, p1, p2 - p1); - case IF_CIRCLE_IN_OUT: return circleInOut(fraction, p1, p2 - p1); + case IF_QUAD_IN: return quadIn(fraction, p1, p2 - p1, inter->slope); + case IF_QUAD_OUT: return quadOut(fraction, p1, p2 - p1, inter->slope); + case IF_QUAD_IN_OUT: return quadInOut(fraction, p1, p2 - p1, inter->slope); + case IF_CUBIC_IN: return cubicIn(fraction, p1, p2 - p1, inter->slope); + case IF_CUBIC_OUT: return cubicOut(fraction, p1, p2 - p1, inter->slope); + case IF_CUBIC_IN_OUT: return cubicInOut(fraction, p1, p2 - p1, inter->slope); + case IF_QUART_IN: return quartIn(fraction, p1, p2 - p1, inter->slope); + case IF_QUART_OUT: return quartOut(fraction, p1, p2 - p1, inter->slope); + case IF_QUART_IN_OUT: return quartInOut(fraction, p1, p2 - p1, inter->slope); + case IF_QUINT_IN: return quintIn(fraction, p1, p2 - p1, inter->slope); + case IF_QUINT_OUT: return quintOut(fraction, p1, p2 - p1, inter->slope); + case IF_QUINT_IN_OUT: return quintInOut(fraction, p1, p2 - p1, inter->slope); + case IF_CIRCLE_IN: return circleIn(fraction, p1, p2 - p1, inter->slope); + case IF_CIRCLE_OUT: return circleOut(fraction, p1, p2 - p1, inter->slope); + case IF_CIRCLE_IN_OUT: return circleInOut(fraction, p1, p2 - p1, inter->slope); case IF_EXPONENTIAL_IN: return exponentialIn(fraction, p1, p2 - p1); case IF_EXPONENTIAL_OUT: return exponentialOut(fraction, p1, p2 - p1); case IF_EXPONENTIAL_IN_OUT: return exponentialInOut(fraction, p1, p2 - p1); @@ -150,9 +176,20 @@ float interpolateScalar(float p1, float p2, float fraction, interpolation_t* int } } -int change_differs(change_t* modification, U16 frame) +float calculateSweep(state_t* modification, float fraction) { - change_t* previous = modification; + arc_t* a = &(modification->arc); + float angle = a->angle + fraction * a->delta_angle; + if (a->X) + return a->cX + a->r * cos(angle); + else + return a->cY + a->r * sin(angle); + +} + +int state_differs(state_t* modification, U16 frame) +{ + state_t* previous = modification; while (modification && modification->frame < frame) { previous = modification; @@ -165,9 +202,23 @@ int change_differs(change_t* modification, U16 frame) return (modification->function != CF_JUMP); } -float change_value(change_t* modification, U16 frame) +float state_tangent(state_t* modification, U16 frame, int tangent) +{ + float deltaFrame = 0.1; + switch (tangent) { - change_t* previous = modification; + case T_BEFORE: + return (state_value(modification, frame) - state_value(modification, frame - deltaFrame)) / deltaFrame; + case T_AFTER: + return (state_value(modification, frame + deltaFrame) - state_value(modification, frame)) / deltaFrame; + default: + return (state_value(modification, frame + deltaFrame) - state_value(modification, frame - deltaFrame)) / (2 * deltaFrame); + } +} + +float state_value(state_t* modification, float frame) +{ + state_t* previous = modification; while (modification && modification->frame < frame) { previous = modification; @@ -194,11 +245,18 @@ float change_value(change_t* modification, U16 frame) float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame); return interpolateScalar(previous->value, modification->value, fraction, modification->interpolation); } - case CF_QCHANGE: + case CF_SCHANGE: { float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame); + fraction = interpolateScalar(0, 1, fraction, modification->interpolation); return calculateSpline(modification, fraction); } + case CF_SWEEP: + { + float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame); + fraction = interpolateScalar(0, 1, fraction, modification->interpolation); + return calculateSweep(modification, fraction); + } case CF_JUMP: return previous->value; default: @@ -206,10 +264,10 @@ float change_value(change_t* modification, U16 frame) } } -changeFilter_t* changeFilter_new(U16 frame, int function, FILTERLIST* value, interpolation_t* inter) +filterState_t* filterState_new(U16 frame, int function, FILTERLIST* value, interpolation_t* inter) { - changeFilter_t* newChange = (changeFilter_t*)malloc(sizeof(changeFilter_t)); - changeFilter_init(newChange); + filterState_t* newChange = (filterState_t*)malloc(sizeof(filterState_t)); + filterState_init(newChange); newChange->frame = frame; newChange->function = function; newChange->value = value; @@ -217,20 +275,20 @@ changeFilter_t* changeFilter_new(U16 frame, int function, FILTERLIST* value, int return newChange; } -void changeFilter_free(changeFilter_t *change) +void filterState_free(filterState_t *change) { if (change->next) - changeFilter_free(change->next); + filterState_free(change->next); free(change->value); free(change); } -void changeFilter_init(changeFilter_t* change) +void filterState_init(filterState_t* change) { - memset(change, 0, sizeof(changeFilter_t)); + memset(change, 0, sizeof(filterState_t)); } -void changeFilter_append(changeFilter_t* first, changeFilter_t* newChange) +void filterState_append(filterState_t* first, filterState_t* newChange) { while (first->next) first = first->next; @@ -693,9 +751,9 @@ FILTERLIST* interpolateFilterList(FILTERLIST* list1, FILTERLIST* list2, float ra return mixedList; } -int changeFilter_differs(changeFilter_t* modification, U16 frame) +int filterState_differs(filterState_t* modification, U16 frame) { - changeFilter_t* previous = modification; + filterState_t* previous = modification; while (modification && modification->frame < frame) { previous = modification; @@ -708,9 +766,9 @@ int changeFilter_differs(changeFilter_t* modification, U16 frame) return (modification->function != CF_JUMP); } -FILTERLIST* changeFilter_value(changeFilter_t* modification, U16 frame) +FILTERLIST* filterState_value(filterState_t* modification, U16 frame) { - changeFilter_t* previous = modification; + filterState_t* previous = modification; while (modification && modification->frame < frame) { previous = modification; @@ -753,104 +811,345 @@ history_t* history_new() void history_free(history_t* past) { - change_free(dictionary_lookup(past->changes, "x")); - change_free(dictionary_lookup(past->changes, "y")); - change_free(dictionary_lookup(past->changes, "scalex")); - change_free(dictionary_lookup(past->changes, "scaley")); - change_free(dictionary_lookup(past->changes, "cxform.r0")); - change_free(dictionary_lookup(past->changes, "cxform.g0")); - change_free(dictionary_lookup(past->changes, "cxform.b0")); - change_free(dictionary_lookup(past->changes, "cxform.a0")); - change_free(dictionary_lookup(past->changes, "cxform.r1")); - change_free(dictionary_lookup(past->changes, "cxform.g1")); - change_free(dictionary_lookup(past->changes, "cxform.b1")); - change_free(dictionary_lookup(past->changes, "cxform.a1")); - change_free(dictionary_lookup(past->changes, "rotate")); - change_free(dictionary_lookup(past->changes, "shear")); - change_free(dictionary_lookup(past->changes, "pivot.x")); - change_free(dictionary_lookup(past->changes, "pivot.y")); - change_free(dictionary_lookup(past->changes, "pin.x")); - change_free(dictionary_lookup(past->changes, "pin.y")); - change_free(dictionary_lookup(past->changes, "blendmode")); - changeFilter_free(dictionary_lookup(past->changes, "filter")); - dictionary_destroy(past->changes); + state_free(dictionary_lookup(past->states, "x")); + state_free(dictionary_lookup(past->states, "y")); + state_free(dictionary_lookup(past->states, "scalex")); + state_free(dictionary_lookup(past->states, "scaley")); + state_free(dictionary_lookup(past->states, "cxform.r0")); + state_free(dictionary_lookup(past->states, "cxform.g0")); + state_free(dictionary_lookup(past->states, "cxform.b0")); + state_free(dictionary_lookup(past->states, "cxform.a0")); + state_free(dictionary_lookup(past->states, "cxform.r1")); + state_free(dictionary_lookup(past->states, "cxform.g1")); + state_free(dictionary_lookup(past->states, "cxform.b1")); + state_free(dictionary_lookup(past->states, "cxform.a1")); + state_free(dictionary_lookup(past->states, "rotate")); + state_free(dictionary_lookup(past->states, "shear")); + state_free(dictionary_lookup(past->states, "pivot.x")); + state_free(dictionary_lookup(past->states, "pivot.y")); + state_free(dictionary_lookup(past->states, "pin.x")); + state_free(dictionary_lookup(past->states, "pin.y")); + state_free(dictionary_lookup(past->states, "blendmode")); + state_free(dictionary_lookup(past->states, "flags")); + filterState_free(dictionary_lookup(past->states, "filter")); + dictionary_destroy(past->states); free(past); } void history_init(history_t* past) { - past->changes = (dictionary_t*)malloc(sizeof(dictionary_t)); - dictionary_init(past->changes); + past->states = (dictionary_t*)malloc(sizeof(dictionary_t)); + dictionary_init(past->states); } void history_begin(history_t* past, char* parameter, U16 frame, TAG* tag, float value) { - change_t* first = change_new(frame, CF_PUT, value, 0); + state_t* first = state_new(frame, CF_PUT, value, 0); past->firstTag = tag; past->firstFrame = frame; - dictionary_put2(past->changes, parameter, first); + dictionary_put2(past->states, parameter, first); } void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTERLIST* value) { - changeFilter_t* first = changeFilter_new(frame, CF_PUT, value, 0); + filterState_t* first = filterState_new(frame, CF_PUT, value, 0); past->firstTag = tag; past->firstFrame = frame; - dictionary_put2(past->changes, "filter", first); + dictionary_put2(past->states, "filter", first); } void history_remember(history_t* past, char* parameter, U16 frame, int function, float value, interpolation_t* inter) { - change_t* first = dictionary_lookup(past->changes, parameter); - if (first) //should always be true + past->lastFrame = frame; + state_t* state = dictionary_lookup(past->states, parameter); + if (state) //should always be true + { + state_t* next = state_new(frame, function, value, inter); + state_append(state, next); + } + else + syntaxerror("Internal error: changing parameter %s, which is unknown for the instance.", parameter); +} + +static float getAngle(float dX, float dY) +{ + float radius = sqrt(dX * dX + dY * dY); + if (radius == 0) + return 0.0; + if (dX >= 0) + if (dY > 0) + return acos(dX / radius); + else + return 2 * M_PI - acos(dX / radius); + else + if (dY > 0) + return M_PI - acos(-dX / radius); + else + return M_PI + acos(-dX / radius); +} + +static float getDeltaAngle(float angle1, float angle2, int clockwise) { - change_t* next = change_new(frame, function, value, inter); - change_append(first, next); + if (!clockwise) + { + if (angle1 > angle2) + return angle2 - angle1; + else + return angle2 - angle1 - 2 * M_PI; + } + else + { + if (angle1 > angle2) + return 2 * M_PI - angle1 + angle2; + else + return angle2 - angle1; } } +void history_rememberSweep(history_t* past, U16 frame, float x, float y, float r, int clockwise, int short_arc, interpolation_t* inter) +{ + float lastX, lastY, dX, dY; + U16 lastFrame; + + past->lastFrame = frame; + state_t* change = dictionary_lookup(past->states, "x"); + if (change) //should always be true + { + while (change->next) + change = change->next; + lastFrame = change->frame; + lastX = change->value; + change = dictionary_lookup(past->states, "y"); + if (change) //should always be true + { + while (change->next) + change = change->next; + lastY = change->value; + dX = x - lastX; + dY = y - lastY; + if (dX == 0 && dY == 0) + syntaxerror("sweep not possible: startpoint and endpoint must not be equal"); + if ((dX) * (dX) + (dY) * (dY) > 4 * r * r) + syntaxerror("sweep not possible: radius is to small"); + if (change->frame > lastFrame) + { + lastFrame = change->frame; + history_remember(past, "x", lastFrame, CF_JUMP, lastX, 0); + } + else + if (change->frame < lastFrame) + history_remember(past, "y", lastFrame, CF_JUMP, lastY, 0); + float c1X, c1Y, c2X, c2Y; + if (dX == 0) //vertical + { + c1Y = c2Y = (lastY + y) / 2; + c1X = x + sqrt(r * r - (c1Y - y) * (c1Y - y)); + c2X = 2 * x -c1X; + } + else + if (dY == 0) //horizontal + { + c1X = c2X = (lastX + x) / 2; + c1Y = y +sqrt(r * r - (c1X - x) * (c1X - x)); + c2Y = 2 * y -c1Y; + } + else + { + c1X = sqrt((r * r - (dX * dX + dY * dY) / 4) / (1 + dX * dX / dY / dY)); + c2X = -c1X; + c1Y = -dX / dY * c1X; + c2Y = -c1Y; + c1X += (x + lastX) / 2; + c2X += (x + lastX) / 2; + c1Y += (y + lastY) / 2; + c2Y += (y + lastY) / 2; + } + float angle1, angle2, delta_angle, centerX, centerY; + angle1 = getAngle(lastX - c1X, lastY - c1Y); + angle2 = getAngle(x - c1X, y - c1Y); + delta_angle = getDeltaAngle(angle1, angle2, clockwise); + if ((short_arc && fabs(delta_angle) <= M_PI) || (! short_arc && fabs(delta_angle) >= M_PI)) + { + centerX = c1X; + centerY = c1Y; + } + else + { + angle1 = getAngle(lastX - c2X, lastY - c2Y); + angle2 = getAngle(x - c2X, y - c2Y); + delta_angle = getDeltaAngle(angle1, angle2, clockwise); + centerX = c2X; + centerY = c2Y; + } + change = dictionary_lookup(past->states, "x"); + state_t* nextX = state_new(frame, CF_SWEEP, x, inter); + nextX->arc.r = r; + nextX->arc.angle = angle1; + nextX->arc.delta_angle = delta_angle; + nextX->arc.cX = centerX; + nextX->arc.cY = centerY; + nextX->arc.X = 1; + state_append(change, nextX); + change = dictionary_lookup(past->states, "y"); + state_t* nextY = state_new(frame, CF_SWEEP, y, inter); + nextY->arc.r = r; + nextY->arc.angle = angle1; + nextY->arc.delta_angle = delta_angle; + nextY->arc.cX = centerX; + nextY->arc.cY = centerY; + nextY->arc.X = 0; + state_append(change, nextY); + } + else + syntaxerror("Internal error: changing parameter y in sweep, which is unknown for the instance."); + } + else + syntaxerror("Internal error: changing parameter x in sweep, which is unknown for the instance."); +} + void history_rememberFilter(history_t* past, U16 frame, int function, FILTERLIST* value, interpolation_t* inter) { - changeFilter_t* first = dictionary_lookup(past->changes, "filter"); + past->lastFrame = frame; + filterState_t* first = dictionary_lookup(past->states, "filter"); if (first) //should always be true { - changeFilter_t* next = changeFilter_new(frame, function, value, inter); - changeFilter_append(first, next); + filterState_t* next = filterState_new(frame, function, value, inter); + filterState_append(first, next); + } + else + syntaxerror("Internal error: changing a filter not set for the instance."); +} + +void history_processFlags(history_t* past) +// to be called after completely recording this history, before calculating any values. +{ + state_t* flagState = dictionary_lookup(past->states, "flags"); + state_t* nextState; + U16 nextFlags, toggledFlags, currentFlags = (U16)flagState->value; + while (flagState->next) + { + nextState = flagState->next; + nextFlags = (U16)nextState->value; + toggledFlags = currentFlags ^ nextFlags; + if (toggledFlags & IF_FIXED_ALIGNMENT) + { // the IF_FIXED_ALIGNMENT bit will change in the next state + if (nextFlags & IF_FIXED_ALIGNMENT) + { // the IF_FIXED_ALIGNMENT bit will be set + int onFrame = nextState->frame; + state_t* rotations = dictionary_lookup(past->states, "rotate"); + nextState->params.instanceAngle = state_value(rotations, onFrame); + state_t* resetRotate = state_new(onFrame, CF_JUMP, 0, 0); + state_insert(rotations, resetRotate); + if (onFrame == past->firstFrame) + onFrame++; + state_t *x, *y; + float dx, dy; + do + { + x = dictionary_lookup(past->states, "x"); + dx = state_tangent(x, onFrame, T_SYMMETRIC); + y = dictionary_lookup(past->states, "y"); + dy = state_tangent(y, onFrame, T_SYMMETRIC); + onFrame++; + } + while (dx == 0 && dy == 0 && onFrame < past->lastFrame); + if (onFrame == past->lastFrame) + nextState->params.pathAngle = 0; + else + nextState->params.pathAngle = getAngle(dx, dy) / M_PI * 180; + } + else // the IF_FIXED_ALIGNMENT bit will be reset + { + int offFrame = nextState->frame; + state_t* rotations = dictionary_lookup(past->states, "rotate"); + state_t* setRotate = state_new(offFrame, CF_JUMP, flagState->params.instanceAngle + state_value(rotations, offFrame), 0); + state_insert(rotations, setRotate); + } + } + else // the IF_FIXED_ALIGNMENT bit will not change but some processing may be + // required just the same + { + if (nextFlags & IF_FIXED_ALIGNMENT) + { + nextState->params.instanceAngle = flagState->params.instanceAngle; + nextState->params.pathAngle = flagState->params.pathAngle; + } + } +// and so on for all the other bits. + flagState = nextState; + currentFlags = nextFlags; } } int history_change(history_t* past, U16 frame, char* parameter) { - change_t* first = dictionary_lookup(past->changes, parameter); + state_t* first = dictionary_lookup(past->states, parameter); if (first) //should always be true. - return change_differs(first, frame); - printf("no history found for parameter %s\n", parameter); + return state_differs(first, frame); + syntaxerror("no history found to predict changes for parameter %s.\n", parameter); return 0; } float history_value(history_t* past, U16 frame, char* parameter) { - change_t* first = dictionary_lookup(past->changes, parameter); - if (first) //should always be true. - return change_value(first, frame); - printf("no history found for parameter %s\n", parameter); + state_t* state = dictionary_lookup(past->states, parameter); + if (state) //should always be true. + return state_value(state, frame); + syntaxerror("no history found to get a value for parameter %s.\n", parameter); + return 0; +} + +float history_rotateValue(history_t* past, U16 frame) +{ + state_t* rotations = dictionary_lookup(past->states, "rotate"); + if (rotations) //should always be true. + { + float angle = state_value(rotations, frame); + state_t* flags = dictionary_lookup(past->states, "flags"); + U16 currentflags = state_value(flags, frame); + if (currentflags & IF_FIXED_ALIGNMENT) + { + flags = state_at(flags, frame); + if (frame == past->firstFrame) + frame++; + state_t *x, *y; + float dx, dy, pathAngle; + do + { + x = dictionary_lookup(past->states, "x"); + dx = state_value(x, frame) - state_value(x, frame - 1); + y = dictionary_lookup(past->states, "y"); + dy = state_value(y, frame) - state_value(y, frame - 1); + frame--; + } + while (dx == 0 && dy == 0 && frame > past->firstFrame); + if (frame == past->firstFrame) + pathAngle = 0; + else + pathAngle = getAngle(dx, dy) / M_PI * 180; + return angle + flags->params.instanceAngle + pathAngle - flags->params.pathAngle; + } + else + return angle; + } + syntaxerror("no history found to get a value for parameter rotate.\n"); return 0; } int history_changeFilter(history_t* past, U16 frame) { - changeFilter_t* first = dictionary_lookup(past->changes, "filter"); + filterState_t* first = dictionary_lookup(past->states, "filter"); if (first) //should always be true. - return changeFilter_differs(first, frame); - printf("no history found for parameter filter\n"); + return filterState_differs(first, frame); + syntaxerror("no history found to predict changes for parameter filter.\n"); return 0; } -FILTERLIST* history_valueFilter(history_t* past, U16 frame) +FILTERLIST* history_filterValue(history_t* past, U16 frame) { - changeFilter_t* first = dictionary_lookup(past->changes, "filter"); + filterState_t* first = dictionary_lookup(past->states, "filter"); if (first) //should always be true. - return changeFilter_value(first, frame); - printf("no history found for parameter filter\n"); + return filterState_value(first, frame); + syntaxerror("no history found to get a value for parameter filter.\n"); return 0; } diff --git a/src/swfc-history.h b/src/swfc-history.h index 55c212e..093db69 100644 --- a/src/swfc-history.h +++ b/src/swfc-history.h @@ -32,8 +32,8 @@ enum { CF_PUT = 1, CF_CHANGE = 2, - CF_QCHANGE = 3, - CF_ARCCHANGE = 4, + CF_SCHANGE = 3, + CF_SWEEP = 4, CF_JUMP = 5 }; @@ -53,6 +53,8 @@ enum #define SF_FILTER 0x2000 #define SF_ALL 0x3fff +#define IF_FIXED_ALIGNMENT 0x0001 + FILTER* noFilters; FILTER_BLUR* noBlur; FILTER_BEVEL* noBevel; @@ -64,43 +66,58 @@ typedef struct _spline float a, b, c, d; } spline_t; -typedef struct _change +typedef struct _arc +{ + float r, angle, delta_angle, cX, cY; + int X; // boolean: 1 if this is for x; 0 if this is for y; +} arc_t; + +typedef struct _flagparms +{ + float pathAngle, instanceAngle; +} flagparams_t; + +typedef struct _state { U16 frame; float value; int function; interpolation_t* interpolation; spline_t spline; - struct _change* next; -} change_t; - -change_t* change_new(U16 frame, int function, float value, interpolation_t* inter); -void change_free(change_t* change); -void change_init(change_t* change); -void change_append(change_t* first, change_t* newChange); -float change_value(change_t* first, U16 frame); - -typedef struct _changeFilter + arc_t arc; + flagparams_t params; + struct _state* next; +} state_t; + +state_t* state_new(U16 frame, int function, float value, interpolation_t* inter); +void state_free(state_t* state); +void state_init(state_t* state); +state_t* state_at(state_t* state, U16 frame); +void state_append(state_t* state, state_t* newState); +void state_insert(state_t* state, state_t* newState); +float state_value(state_t* first, float frame); +float state_tangent(state_t* modification, U16 frame, int tangent); + +typedef struct _filterState { U16 frame; FILTERLIST* value; int function; interpolation_t* interpolation; - struct _changeFilter* next; - spline_t spline; -} changeFilter_t; + struct _filterState* next; +} filterState_t; -changeFilter_t* changeFilter_new(U16 frame, int function, FILTERLIST* value, interpolation_t* inter); -void changeFilter_free(changeFilter_t* change); -void changeFilter_init(changeFilter_t* change); -void changeFilter_append(changeFilter_t* first, changeFilter_t* newChange); -FILTERLIST* changeFilter_value(changeFilter_t* first, U16 frame); +filterState_t* filterState_new(U16 frame, int function, FILTERLIST* value, interpolation_t* inter); +void filterState_free(filterState_t* change); +void filterState_init(filterState_t* change); +void filterState_append(filterState_t* first, filterState_t* newChange); +FILTERLIST* filterState_value(filterState_t* first, U16 frame); typedef struct _history { - U16 firstFrame; + U16 firstFrame, lastFrame; TAG* firstTag; - dictionary_t* changes; + dictionary_t* states; } history_t; history_t* history_new(); @@ -109,10 +126,13 @@ void history_init(history_t* past); void history_begin(history_t* past, char* parameter, U16 frame, TAG* tag, float value); void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTERLIST* value); void history_remember(history_t* past, char* parameter, U16 frame, int function, float value, interpolation_t* inter); +void history_rememberSweep(history_t* past, U16 frame, float x, float y, float r, int clockwise, int short_arc, interpolation_t* inter); void history_rememberFilter(history_t* past, U16 frame, int function, FILTERLIST* value, interpolation_t* inter); +void history_processFlags(history_t* past); int history_change(history_t* past, U16 frame, char* parameter); float history_value(history_t* past, U16 frame, char* parameter); +float history_rotateValue(history_t* past, U16 frame); int history_changeFilter(history_t* past, U16 frame); -FILTERLIST* history_valueFilter(history_t* past, U16 frame); +FILTERLIST* history_filterValue(history_t* past, U16 frame); #endif diff --git a/src/swfc-interpolation.c b/src/swfc-interpolation.c index 7e845ae..b3a0c35 100644 --- a/src/swfc-interpolation.c +++ b/src/swfc-interpolation.c @@ -24,99 +24,99 @@ #include #include "swfc-interpolation.h" -static inline float poly(float fraction, float start, float delta, int degree) +static inline float poly(float fraction, float start, float delta, float slope, int degree) { - return delta * pow(fraction, degree) + start; + return delta * ((1 - slope) * pow(fraction, degree) + slope * fraction) + start; } float linear(float fraction, float start, float delta) { - return poly(fraction, start, delta, 1); + return poly(fraction, start, delta, 0, 1); } -float quadIn(float fraction, float start, float delta) +float quadIn(float fraction, float start, float delta, float slope) { - return poly(fraction, start, delta, 2); + return poly(fraction, start, delta, slope, 2); } -float quadOut(float fraction, float start, float delta) +float quadOut(float fraction, float start, float delta, float slope) { - return quadIn(1 - fraction, start + delta, -delta); + return quadIn(1 - fraction, start + delta, -delta, slope); } -float quadInOut(float fraction, float start, float delta) +float quadInOut(float fraction, float start, float delta, float slope) { if (fraction < 0.5) - return quadIn(2 * fraction, start, delta / 2); - return quadOut(2 * fraction - 1, start + delta / 2, delta / 2); + return quadIn(2 * fraction, start, delta / 2, slope); + return quadOut(2 * fraction - 1, start + delta / 2, delta / 2, slope); } -float cubicIn(float fraction, float start, float delta) +float cubicIn(float fraction, float start, float delta, float slope) { - return poly(fraction, start, delta, 3); + return poly(fraction, start, delta, slope, 3); } -float cubicOut(float fraction, float start, float delta) +float cubicOut(float fraction, float start, float delta, float slope) { - return cubicIn(1 - fraction, start + delta, -delta); + return cubicIn(1 - fraction, start + delta, -delta, slope); } -float cubicInOut(float fraction, float start, float delta) +float cubicInOut(float fraction, float start, float delta, float slope) { if (fraction < 0.5) - return cubicIn(2 * fraction, start, delta / 2); - return cubicOut(2 * fraction - 1, start + delta / 2, delta / 2); + return cubicIn(2 * fraction, start, delta / 2, slope); + return cubicOut(2 * fraction - 1, start + delta / 2, delta / 2, slope); } -float quartIn(float fraction, float start, float delta) +float quartIn(float fraction, float start, float delta, float slope) { - return poly(fraction, start, delta, 4); + return poly(fraction, start, delta, slope, 4); } -float quartOut(float fraction, float start, float delta) +float quartOut(float fraction, float start, float delta, float slope) { - return quartIn(1 - fraction, start + delta, -delta); + return quartIn(1 - fraction, start + delta, -delta, slope); } -float quartInOut(float fraction, float start, float delta) +float quartInOut(float fraction, float start, float delta, float slope) { if (fraction < 0.5) - return quartIn(2 * fraction, start, delta / 2); - return quartOut(2 * fraction - 1, start + delta / 2, delta / 2); + return quartIn(2 * fraction, start, delta / 2, slope); + return quartOut(2 * fraction - 1, start + delta / 2, delta / 2, slope); } -float quintIn(float fraction, float start, float delta) +float quintIn(float fraction, float start, float delta, float slope) { - return poly(fraction, start, delta, 5); + return poly(fraction, start, delta, slope, 5); } -float quintOut(float fraction, float start, float delta) +float quintOut(float fraction, float start, float delta, float slope) { - return quintIn(1 - fraction, start + delta, -delta); + return quintIn(1 - fraction, start + delta, -delta, slope); } -float quintInOut(float fraction, float start, float delta) +float quintInOut(float fraction, float start, float delta, float slope) { if (fraction < 0.5) - return quintIn(2 * fraction, start, delta / 2); - return quintOut(2 * fraction - 1, start + delta / 2, delta / 2); + return quintIn(2 * fraction, start, delta / 2, slope); + return quintOut(2 * fraction - 1, start + delta / 2, delta / 2, slope); } -float circleIn(float fraction, float start, float delta) +float circleIn(float fraction, float start, float delta, float slope) { - return delta * (1 - sqrt(1 - fraction * fraction)) + start; + return delta * (1 - sqrt(1 - (1 - 2 * slope) * fraction * fraction - 2 * slope * fraction)) + start; } -float circleOut(float fraction, float start, float delta) +float circleOut(float fraction, float start, float delta, float slope) { - return circleIn(1 - fraction, start + delta, -delta); + return circleIn(1 - fraction, start + delta, -delta, slope); } -float circleInOut(float fraction, float start, float delta) +float circleInOut(float fraction, float start, float delta, float slope) { if (fraction < 0.5) - return circleIn(2 * fraction, start, delta / 2); - return circleOut(2 * fraction - 1, start + delta / 2, delta / 2); + return circleIn(2 * fraction, start, delta / 2, slope); + return circleOut(2 * fraction - 1, start + delta / 2, delta / 2, slope); } float exponentialIn(float fraction, float start, float delta) diff --git a/src/swfc-interpolation.h b/src/swfc-interpolation.h index 5e0b59a..f29e950 100644 --- a/src/swfc-interpolation.h +++ b/src/swfc-interpolation.h @@ -24,7 +24,7 @@ typedef struct _interpolation { int function; - float speed, amplitude, growth, damping; + float slope, speed, amplitude, growth, damping; int bounces; } interpolation_t; @@ -67,25 +67,25 @@ enum { float linear(float fraction, float start, float delta); -float quadIn(float fraction, float start, float delta); -float quadOut(float fraction, float start, float delta); -float quadInOut(float fraction, float start, float delta); +float quadIn(float fraction, float start, float delta, float slope); +float quadOut(float fraction, float start, float delta, float slope); +float quadInOut(float fraction, float start, float delta, float slope); -float cubicIn(float fraction, float start, float delta); -float cubicOut(float fraction, float start, float delta); -float cubicInOut(float fraction, float start, float delta); +float cubicIn(float fraction, float start, float delta, float slope); +float cubicOut(float fraction, float start, float delta, float slope); +float cubicInOut(float fraction, float start, float delta, float slope); -float quartIn(float fraction, float start, float delta); -float quartOut(float fraction, float start, float delta); -float quartInOut(float fraction, float start, float delta); +float quartIn(float fraction, float start, float delta, float slope); +float quartOut(float fraction, float start, float delta, float slope); +float quartInOut(float fraction, float start, float delta, float slope); -float quintIn(float fraction, float start, float delta); -float quintOut(float fraction, float start, float delta); -float quintInOut(float fraction, float start, float delta); +float quintIn(float fraction, float start, float delta, float slope); +float quintOut(float fraction, float start, float delta, float slope); +float quintInOut(float fraction, float start, float delta, float slope); -float circleIn(float fraction, float start, float delta); -float circleOut(float fraction, float start, float delta); -float circleInOut(float fraction, float start, float delta); +float circleIn(float fraction, float start, float delta, float slope); +float circleOut(float fraction, float start, float delta, float slope); +float circleInOut(float fraction, float start, float delta, float slope); float exponentialIn(float fraction, float start, float delta); float exponentialOut(float fraction, float start, float delta);