home *** CD-ROM | disk | FTP | other *** search
- // Morpher.m
- //
- // created by Martin Wennerberg on Sun 08-Sep-1996
- //
- // when who modification
-
- #import "Morpher.h"
- #import "MorphLine.h"
- #import <AppKit/AppKit.h>
- #import "algebra.h"
- #import "NSBitmapImageRep_editing.h"
-
- #define SMALL_FLOAT 0.00001
-
- static struct RGBA mixRGBA(struct RGBA a, struct RGBA b, float d)
- {
- struct RGBA res;
-
- res.r = a.r + (b.r - a.r) * d;
- res.g = a.g + (b.g - a.g) * d;
- res.b = a.b + (b.b - a.b) * d;
- res.a = a.a + (b.a - a.a) * d;
-
- return res;
- }
-
- static inline NSPoint transform (NSPoint p, NSAffineTransformStruct m)
- {
- NSPoint res;
-
- res.x = p.x * m.m11 + p.y * m.m21 + m.tX;
- res.y = p.x * m.m12 + p.y * m.m22 + m.tY;
-
- return res;
- }
-
- static NSArray *copyObjectsInArray(NSArray *source)
- {
- NSMutableArray *dest = [NSMutableArray arrayWithCapacity:[source count]];
- NSEnumerator *sourceEnum = [source objectEnumerator];
- MorphLine *sourceObj;
-
- while ((sourceObj = [sourceEnum nextObject]))
- [dest addObject:[[sourceObj copy] autorelease]];
- return dest;
- }
-
- @implementation Morpher
- - initWithFirstBitmap:(NSBitmapImageRep *)im0 lastBitmap:(NSBitmapImageRep *)im1
- {
- self = [super init];
- if (!self)
- return nil;
-
- firstBitmap = [im0 retain];
- lastBitmap = [im1 retain];
-
- return self;
- }
-
- - (void)calcMorphBitmap:(NSBitmapImageRep *) bitmap
- atDelta:(float) delta
- morphLines:(NSArray *) lines
- {
- MorphLine *morphLine;
- NSAffineTransformStruct *trans0; // transformation from 0 to delta
- NSAffineTransformStruct *trans1; // transformation from 1 to delta
- NSPoint dp; // destination point
- NSPoint p0; // source point at 0
- NSPoint p1; // source point at 1
- struct RGBA RGBA0, RGBA1; // color at 0 and 1
- struct RGBA rgba; // destination color (this is what we're trying to calculate)
- int lineCount;
- int i;
- float dissolveDelta;
- struct LineCoords *PdQd;
- struct LineCoords *destLineCoordinates;
- NSPoint D; /* Displacement */
- float weight, weightsum;
- NSPoint DSUM0, DSUM1; /* Displacement sum for the to images */
- float dist;
- float dissolveStartSum, dissolveEndSum;
- float dissolveStartDelta, dissolveEndDelta;
- NSArray *morphLines;
-
- morphLines = copyObjectsInArray(lines);
- lineCount = [morphLines count];
-
- trans0 = (NSAffineTransformStruct *) alloca (lineCount * sizeof(NSAffineTransformStruct));
- trans1 = (NSAffineTransformStruct *) alloca (lineCount * sizeof(NSAffineTransformStruct));
- destLineCoordinates = (struct LineCoords *) alloca (lineCount * sizeof(struct LineCoords));
-
- [self fillTransMatrixes:trans0 withDeltaFrom:delta to:0 morphLines:morphLines];
- [self fillTransMatrixes:trans1 withDeltaFrom:delta to:1 morphLines:morphLines];
- [self fillDestLineCoordinates:destLineCoordinates delta:delta morphLines:morphLines];
-
- // Loop through all pixels in the destination bitmap and set them to the morphed colors
- for (dp.y = 0; dp.y < 1; dp.y += 1.0 / [bitmap size].height)
- {
- progress = dp.y / [bitmap size].height;
-
- for (dp.x = 0; dp.x < 1; dp.x += 1.0 / [bitmap size].width)
- {
- /* Calc the SourcePoints p0 and p1 */
- D = NSZeroPoint;
- weightsum = 0.0;
- DSUM0 = NSZeroPoint;
- DSUM1 = NSZeroPoint;
- dissolveStartSum = 0.0;
- dissolveEndSum = 0.0;
-
- for (i = 0; i < lineCount; ++i)
- {
- morphLine = [morphLines objectAtIndex:i];
- PdQd = &destLineCoordinates[i];
-
- /* calculate the source points to sample */
- p0 = transform (dp, trans0[i]);
- p1 = transform (dp, trans1[i]);
-
- /* calculate the weight */
- D = pt_sub (p0, dp);
- dist = line_dist_to_point (PdQd->start, PdQd->end, dp);
- weight = pow (pt_dist2(PdQd->start, PdQd->end) / (morphLine->control + dist), morphLine->range);
- DSUM0 = pt_sum (DSUM0, pt_scale (D, weight, weight));
- weightsum += weight;
-
- D = pt_sub (p1, dp);
- DSUM1 = pt_sum (DSUM1, pt_scale (D, weight, weight));
-
- dissolveStartSum += morphLine->dissolveStartDelta * weight;
- dissolveEndSum += morphLine->dissolveEndDelta * weight;
- }
- /* average (by weight) the source points */
- p0 = pt_sum(dp, pt_scale(DSUM0, 1.0 / weightsum, 1.0 / weightsum));
- p1 = pt_sum(dp, pt_scale(DSUM1, 1.0 / weightsum, 1.0 / weightsum));
-
- dissolveStartDelta = dissolveStartSum / weightsum;
- dissolveEndDelta = dissolveEndSum / weightsum;
-
- /* make sure 0 <= dissolveDelta <= 1 */
- if (ABS(dissolveEndDelta - dissolveStartDelta) <= SMALL_FLOAT )
- if (dissolveStartDelta == 0.0)
- dissolveDelta = 1.0;
- else if (delta <= dissolveStartDelta)
- dissolveDelta = 0.0;
- else dissolveDelta = 11.0;
- else if (delta <= dissolveStartDelta)
- dissolveDelta = 0.0;
- else
- {
- dissolveDelta = (delta - dissolveStartDelta) / (dissolveEndDelta - dissolveStartDelta);
- dissolveDelta = MIN (dissolveDelta, 1.0);
- dissolveDelta = MAX (dissolveDelta, 0.0);
- }
-
- RGBA0 = [firstBitmap RGBAAtPoint:pt_scale (p0, [firstBitmap size].width, [firstBitmap size].height)];
- RGBA1 = [lastBitmap RGBAAtPoint:pt_scale ( p1, [lastBitmap size].width, [lastBitmap size].height)];
- rgba = mixRGBA (RGBA0, RGBA1, dissolveDelta);
- [bitmap setRGBA:rgba atPoint:pt_scale ( dp, [bitmap size].width, [bitmap size].height)];
- }
- }
- progress = 1.0;
- }
-
- - (void) fillTransMatrixes:(NSAffineTransformStruct *) matrixes
- withDeltaFrom:(float) beforeDelta
- to:(float) afterDelta
- morphLines:(NSArray *)lines
- {
- int i;
- MorphLine *line;
-
- for (i = 0; i < [lines count]; ++i)
- {
- line = [lines objectAtIndex:i];
- matrixes[i] = [[line transformFromDelta:beforeDelta toDelta:afterDelta] transformStruct];
- }
- }
-
- - (void) fillDestLineCoordinates:(struct LineCoords *)lines
- delta:(float)delta
- morphLines:(NSArray *)morphLines
- {
- int i;
- MorphLine *morphLine;
-
- for (i = 0; i < [morphLines count]; ++i)
- {
- morphLine = [morphLines objectAtIndex:i];
- lines[i].start = [morphLine startPointAtDelta:delta];
- lines[i].end = [morphLine endPointAtDelta:delta];
- }
- }
-
- - (float) progress
- {
- return progress;
- }
- @end
-