#include <memory.h>
#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,
+ T_AFTER,
+ T_SYMMETRIC
+};
+
+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;
+ int previous_frames = 0, state_frames, new_frames;
- while (first->next)
+ while (state->next)
{
- previous = first;
- first = first->next;
+ if (previous)
+ previous_frames = state->frame - previous->frame;
+ previous = state;
+ state = state->next;
}
- first->next = newChange;
- if (first->function == CF_QCHANGE)
+ state->next = newState;
+ new_frames = newState->frame - state->frame;
+ if (state->function == CF_SCHANGE)
{
+ state_frames = state->frame - previous->frame;
p0 = previous->value;
- p1 = first->value;
- if (previous->function == CF_QCHANGE)
- m0 = (3 * previous->spline.a + 2 * previous->spline.b + previous->spline.c);
+ p1 = state->value;
+ if (previous->function == CF_SCHANGE)
+ m0 = (3 * previous->spline.a + 2 * previous->spline.b + previous->spline.c) * state_frames / previous_frames ;
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_frames;
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_frames / (new_frames + state_frames);
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_frames;
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) * new_frames;
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;
+// printf("p0: %f, p1: %f, m0: %f, m1: %f.\n", p0, p1, m0, m1);
+// printf("a: %f, b: %f, c: %f, d: %f.\n", newState->spline.a, newState->spline.b, newState->spline.c, newState->spline.d);
+ }
}
+
+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;
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);
}
}
-int change_differs(change_t* modification, U16 frame)
+float calculateSweep(state_t* modification, float fraction)
+{
+ 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)
{
- change_t* previous = modification;
+ state_t* previous = modification;
while (modification && modification->frame < frame)
{
previous = modification;
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)
+{
+ 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)
{
- change_t* previous = modification;
+ state_t* previous = modification;
while (modification && modification->frame < frame)
{
previous = modification;
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:
}
}
-changeFilter_t* changeFilter_new(U16 frame, int function, FILTER* 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;
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;
+ if (!first->value || !newChange->value)
first->next = newChange;
+ else
+ {
+ int i, mergedCount = 0;
+ int common = first->value->num < newChange->value->num ? first->value->num : newChange->value->num;
+ for (i = 0; i < common; i++)
+ {
+ mergedCount++;
+ if (newChange->value->filter[i]->type != first->value->filter[i]->type)
+ mergedCount++;
+ }
+ mergedCount = mergedCount + first->value->num - common + newChange->value->num - common;
+ if (mergedCount > 8)
+ {
+ char* list1;
+ char* list2;
+ char* newList;
+ list1 = (char*)malloc(1);
+ *list1 = '\0';
+ for (i = 0; i < first->value->num; i++)
+ {
+ newList = (char*)malloc(strlen(list1) + strlen(filtername[first->value->filter[i]->type]) + 2);
+ newList = strcat(strcat(list1, "+"), filtername[first->value->filter[i]->type]);
+ free(list1);
+ list1 = newList;
+ }
+ list2 = (char*)malloc(1);
+ *list2 = '\0';
+ for (i = 0; i < newChange->value->num; i++)
+ {
+ newList = (char*)malloc(strlen(list1) + strlen(filtername[newChange->value->filter[i]->type]) + 2);
+ newList = strcat(strcat(list2, "+"), filtername[newChange->value->filter[i]->type]);
+ free(list2);
+ list2 = newList;
+ }
+ syntaxerror("filterlists %s and %s cannot be interpolated.", list1, list2);
+ }
+ first->next = newChange;
+ }
}
RGBA interpolateColor(RGBA c1, RGBA c2, float ratio, interpolation_t* inter)
return interpolateNodes(g1, g2, fraction, inter);
}
+FILTER* copyFilter(FILTER* original)
+{
+ if (!original)
+ return original;
+ FILTER* copy = swf_NewFilter(original->type);
+ switch (original->type)
+ {
+ case FILTERTYPE_BLUR:
+ memcpy(copy, original, sizeof(FILTER_BLUR));
+ break;
+ case FILTERTYPE_GRADIENTGLOW:
+ {
+ memcpy(copy, original, sizeof(FILTER_GRADIENTGLOW));
+ FILTER_GRADIENTGLOW* ggcopy = (FILTER_GRADIENTGLOW*)copy;
+ ggcopy->gradient = (GRADIENT*)malloc(sizeof(GRADIENT));
+ ggcopy->gradient->ratios = (U8*)malloc(16 * sizeof(U8));
+ ggcopy->gradient->rgba = (RGBA*)malloc(16 * sizeof(RGBA));
+ copyGradient(ggcopy->gradient, ((FILTER_GRADIENTGLOW*)original)->gradient);
+ }
+ break;
+ case FILTERTYPE_DROPSHADOW:
+ memcpy(copy, original, sizeof(FILTER_DROPSHADOW));
+ break;
+ case FILTERTYPE_BEVEL:
+ memcpy(copy, original, sizeof(FILTER_BEVEL));
+ break;
+ default: syntaxerror("Internal error: unsupported filterype, cannot copy");
+ }
+ return copy;
+}
+
FILTER* interpolateBlur(FILTER* filter1, FILTER* filter2, float ratio, interpolation_t* inter)
{
FILTER_BLUR*f1 = (FILTER_BLUR*)filter1;
if (!f2)
f2 = noBlur;
if(f1->blurx == f2->blurx && f1->blury == f2->blury)
- return 0;
+ return copyFilter(filter1);
FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR);
f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
if(!memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength &&
f1->blurx == f2->blurx && f1->blury == f2->blury &&
f1->angle == f2->angle && f1->distance == f2->distance)
- return 0;
+ return copyFilter(filter1);
FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW);
memcpy(f, f1, sizeof(FILTER_DROPSHADOW));
f->color = interpolateColor(f1->color, f2->color, ratio, inter);
if(!memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) &&
!memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) &&
f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
- return 0;
+ return copyFilter(filter1);
FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL);
memcpy(f, f1, sizeof(FILTER_BEVEL));
f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio, inter);
!memcmp(&f1->gradient->ratios,&f2->gradient->ratios,f1->gradient->num * sizeof(U8)) &&
!memcmp(&f1->gradient->rgba,&f2->gradient->rgba,f1->gradient->num * sizeof(RGBA)) &&
f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
- return 0;
+ return copyFilter(filter1);
FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
memcpy(f, f1, sizeof(FILTER_GRADIENTGLOW));
f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
- double d = f->distance;
- double fr;
- if (d < 0)
- fr = ((int)d - d)*65536;
- else
- fr = (d - (int)d)*65536;
- printf("%.3f <> %.3f : %.3f = %.3f [%.3f . %.3f] - %.5u.%.5u\n", f1->distance, f2->distance, ratio, f->distance, d, fr/65536, (U16)d, (U16)fr);
f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
f->gradient= interpolateGradient(f1->gradient, f2->gradient, ratio, inter);
if (f1 == noGradientGlow)
if(!filter1 && !filter2)
return 0;
-
int filter_type;
if (!filter1)
filter_type = filter2->type;
else
filter_type = filter1->type;
-
switch (filter_type)
{
case FILTERTYPE_BLUR:
return 0;
}
-FILTER* copyFilter(FILTER* original)
+FILTERLIST* copyFilterList(FILTERLIST* original)
{
if (!original)
return original;
- FILTER* copy = swf_NewFilter(original->type);
- switch (original->type)
+ int i;
+ FILTERLIST* copy = (FILTERLIST*)malloc(sizeof(FILTERLIST));
+ copy->num = original->num;
+ for (i = 0; i < copy->num; i++)
+ copy->filter[i] = copyFilter(original->filter[i]);
+ return copy;
+}
+
+FILTER* noFilter(int type)
+{
+ switch (type)
{
case FILTERTYPE_BLUR:
- memcpy(copy, original, sizeof(FILTER_BLUR));
+ return (FILTER*)noBlur;
break;
- case FILTERTYPE_GRADIENTGLOW:
- {
- memcpy(copy, original, sizeof(FILTER_GRADIENTGLOW));
- FILTER_GRADIENTGLOW* ggcopy = (FILTER_GRADIENTGLOW*)copy;
- ggcopy->gradient = (GRADIENT*)malloc(sizeof(GRADIENT));
- ggcopy->gradient->ratios = (U8*)malloc(16 * sizeof(U8));
- ggcopy->gradient->rgba = (RGBA*)malloc(16 * sizeof(RGBA));
- copyGradient(ggcopy->gradient, ((FILTER_GRADIENTGLOW*)original)->gradient);
- }
+ case FILTERTYPE_BEVEL:
+ return (FILTER*)noBevel;
break;
case FILTERTYPE_DROPSHADOW:
- memcpy(copy, original, sizeof(FILTER_DROPSHADOW));
+ return (FILTER*)noDropshadow;
break;
- case FILTERTYPE_BEVEL:
- memcpy(copy, original, sizeof(FILTER_BEVEL));
+ case FILTERTYPE_GRADIENTGLOW:
+ return (FILTER*)noGradientGlow;
break;
- default: syntaxerror("Internal error: unsupported filterype");
+ default:
+ syntaxerror("Internal error: unsupported filtertype, cannot match filterlists");
}
- return copy;
+ return 0;
+}
+
+FILTERLIST* interpolateFilterList(FILTERLIST* list1, FILTERLIST* list2, float ratio, interpolation_t* inter)
+{
+ if (!list1 && !list2)
+ return list1;
+ FILTERLIST start, target, dummy;
+ dummy.num = 0;
+ if (!list1)
+ list1 = &dummy;
+ if (!list2)
+ list2 = &dummy;
+ int i, j = 0;
+ int common = list1->num < list2->num ? list1->num : list2->num;
+ for (i = 0; i < common; i++)
+ {
+ start.filter[j] = list1->filter[i];
+ if (list2->filter[i]->type == list1->filter[i]->type)
+ {
+ target.filter[j] = list2->filter[i];
+ j++;
+ }
+ else
+ {
+ target.filter[j] = noFilter(list1->filter[i]->type);
+ j++;
+ start.filter[j] = noFilter(list2->filter[i]->type);
+ target.filter[j] = list2->filter[i];
+ j++;
+ }
+ }
+ if (list1->num > common)
+ for (i = common; i < list1->num; i++)
+ {
+ start.filter[j] = list1->filter[i];
+ target.filter[j] = noFilter(list1->filter[i]->type);
+ j++;
+ }
+ if (list2->num > common)
+ for (i = common; i < list2->num; i++)
+ {
+ start.filter[j] = noFilter(list2->filter[i]->type);
+ target.filter[j] = list2->filter[i];
+ j++;
+ }
+ start.num = j;
+ target.num = j;
+ FILTERLIST* mixedList = (FILTERLIST*)malloc(sizeof(FILTERLIST));
+ mixedList->num = j;
+ for (i = 0; i < j; i++)
+ mixedList->filter[i] = interpolateFilter(start.filter[i], target.filter[i], ratio, inter);
+ 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;
return (modification->function != CF_JUMP);
}
-FILTER* 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;
modification = modification->next;
}
if (!modification)
- return copyFilter(previous->value);
+ return copyFilterList(previous->value);
if (modification->frame == frame)
{
do
modification = modification->next;
}
while (modification && modification->frame == frame);
- return copyFilter(previous->value);
+ return copyFilterList(previous->value);
}
switch (modification->function)
{
case CF_PUT:
- return copyFilter(modification->value);
+ return copyFilterList(modification->value);
case CF_CHANGE:
{
float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame);
- return interpolateFilter(previous->value, modification->value, fraction, modification->interpolation);
+ return interpolateFilterList(previous->value, modification->value, fraction, modification->interpolation);
}
case CF_JUMP:
- return copyFilter(previous->value);
+ return copyFilterList(previous->value);
default:
return 0;
}
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, FILTER* value)
+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_rememberFilter(history_t* past, U16 frame, int function, FILTER* 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)
+{
+ 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;
}
-FILTER* 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;
}