RSS

(root)/iphone/common : 61 : Jigs/source/JigView.m

« back to all changes in this revision

Viewing changes to Jigs/source/JigView.m

Dömötör Gulyás
2010-01-18 09:03:51
Revision ID: dognotdog@gmail.com-20100118080351-ib2knxvk4w8ssw3h
made common a nested tree

Show diffs side-by-side

added added

removed removed

1
 
//
2
 
//  JigView.m
3
 
//  Jigs
4
 
//
5
 
//  Created by döme on 03.08.2009.
6
 
//  Copyright 2009 __MyCompanyName__. All rights reserved.
7
 
//
8
 
 
9
 
#import "JigView.h"
10
 
 
11
 
#import "VertexArray.h"
12
 
#import "ES1Shader.h"
13
 
#import "ES2Shader.h"
14
 
#import "JigsawGenerator.h"
15
 
#import "Triangulation.h"
16
 
#import "JigsawPiece.h"
17
 
#import "MersenneTwister.h"
18
 
#import "SimplexNoise.h"
19
 
#import "ElAnimation.h"
20
 
#import "JigsAppDelegate.h"
21
 
 
22
 
@implementation JigView
23
 
 
24
 
/*
25
 
- (void) initChipmunk
26
 
{
27
 
        cpInitChipmunk();
28
 
 
29
 
        cpResetShapeIdCounter();
30
 
        
31
 
        space = cpSpaceNew();
32
 
        space->iterations = 20;
33
 
        cpSpaceResizeStaticHash(space, 40.0, 1000);
34
 
        cpSpaceResizeActiveHash(space, 40.0, 1000);
35
 
//      space->gravity = cpv(0, -GRAVITY);
36
 
        space->damping = 0.01;
37
 
        
38
 
        staticBody = cpBodyNew(INFINITY, INFINITY);
39
 
        mouseBody = cpBodyNew(INFINITY, INFINITY);
40
 
        mouseConstraint = cpPinJointAlloc();
41
 
 
42
 
        cpShape *shape = NULL;
43
 
 
44
 
 
45
 
        CGRect bounds = [self bounds];
46
 
        
47
 
        // Create segments around the edge of the screen.
48
 
        shape = cpSegmentShapeNew(staticBody, cpv(CGRectGetMinX(bounds) - 5.0f, CGRectGetMinY(bounds) - 5.0f), cpv(CGRectGetMaxX(bounds) + 5.0f, CGRectGetMinY(bounds) - 5.0f), 5.0f);
49
 
        shape->e = 0.1; shape->u = 1.0;
50
 
        cpSpaceAddStaticShape(space, shape);
51
 
 
52
 
        shape = cpSegmentShapeNew(staticBody, cpv(CGRectGetMaxX(bounds) + 5.0f, CGRectGetMinY(bounds) - 5.0f), cpv(CGRectGetMaxX(bounds) + 5.0f, CGRectGetMaxY(bounds) + 5.0f), 5.0f);
53
 
        shape->e = 0.1; shape->u = 1.0;
54
 
        cpSpaceAddStaticShape(space, shape);
55
 
 
56
 
        shape = cpSegmentShapeNew(staticBody, cpv(CGRectGetMaxX(bounds) + 5.0f, CGRectGetMaxY(bounds) + 5.0f), cpv(CGRectGetMinX(bounds) - 5.0f, CGRectGetMaxY(bounds) + 5.0f), 5.0f);
57
 
        shape->e = 0.1; shape->u = 1.0;
58
 
        cpSpaceAddStaticShape(space, shape);
59
 
 
60
 
        shape = cpSegmentShapeNew(staticBody, cpv(CGRectGetMinX(bounds) - 5.0f, CGRectGetMaxY(bounds) + 5.0f), cpv(CGRectGetMinX(bounds) - 5.0f, CGRectGetMinY(bounds) - 5.0f), 5.0f);
61
 
        shape->e = 0.1; shape->u = 1.0;
62
 
        cpSpaceAddStaticShape(space, shape);
63
 
        
64
 
/*
65
 
        cpSpaceAddCollisionPairFunc(space->value, COLLTYPE_TOWER, COLLTYPE_NORMALBALL, towerBallCollisionFunc, space->value);
66
 
        cpSpaceAddCollisionPairFunc(space->value, COLLTYPE_NORMALBALL, COLLTYPE_NORMALBALL, ballBallCollisionFunc, space->value);
67
 
        cpSpaceAddCollisionPairFunc(space->value, COLLTYPE_NORMALBALL, COLLTYPE_SPLODEBALL, ballSplosionCollisionFunc, space->value);
68
 
        cpSpaceAddCollisionPairFunc(space->value, COLLTYPE_DETACHEDBALL, COLLTYPE_SPLODEBALL, detachedBallSplosionCollisionFunc, space->value);
69
 
        cpSpaceAddCollisionPairFunc(space->value, COLLTYPE_TOWER, COLLTYPE_SPLODEBALL, towerSplosionCollisionFunc, space->value);
70
 
        cpSpaceAddCollisionPairFunc(space->value, COLLTYPE_SPLODEBALL, COLLTYPE_SPLODEBALL, voidCollisionFunc, space->value);
71
 
*
72
 
}
73
 
*/
74
 
 
75
 
float diminishingBoxWeight(CGPoint p, CGSize size)
76
 
{
77
 
        float wx = 1.0f - fclampf(fabsf(0.5f*size.width - p.x)/(0.5f*size.width), 0.0f, 1.0f);
78
 
        float wy = 1.0f - fclampf(fabsf(0.5f*size.height - p.y)/(0.5f*size.height), 0.0f, 1.0f);
79
 
        return fminf(wx,wy);
80
 
}
81
 
 
82
 
- (UIImage*) simplexImageWithSize: (CGSize) size frequency: (float) freq
83
 
{
84
 
        SimplexNoise* noise = [[[SimplexNoise alloc] init] autorelease];
85
 
        
86
 
        int width = size.width;
87
 
        int height = size.height;
88
 
 
89
 
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
90
 
        uint8_t* data = malloc(4*width*height);
91
 
        
92
 
        
93
 
        for(int i = 0; i < height; ++i)
94
 
        {
95
 
                //float y = size.height - (float)i;
96
 
                for(int j = 0; j < width; ++j)
97
 
                {
98
 
                        //float x = size.width - (float)j;
99
 
                        //float n = diminishingBoxWeight(CGPointMake(x,y), size)*[noise noise3dWithX: (float)i*freq Y: (float)j*freq Z: 0.0f];
100
 
                        float n = [noise noise3dWithX: (float)(i-height/2)*freq Y: (float)(j-width/2)*freq Z: 0.0f];
101
 
//                      NSLog(@"%.2f", n);
102
 
                        data[(i*width+j)*4 + 0] = 127.0f + n*127.0f;
103
 
                        data[(i*width+j)*4 + 1] = 127.0f + n*127.0f;
104
 
                        data[(i*width+j)*4 + 2] = 127.0f + n*127.0f;
105
 
                        data[(i*width+j)*4 + 3] = 255;
106
 
                }
107
 
        }
108
 
        CGContextRef bitmapContext = CGBitmapContextCreate(data, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast);
109
 
        CGColorSpaceRelease(colorSpace);
110
 
 
111
 
        if(!bitmapContext)
112
 
        {
113
 
                free(data);
114
 
                return NULL;
115
 
        }
116
 
 
117
 
 
118
 
 
119
 
 
120
 
        CGImageRef image = CGBitmapContextCreateImage(bitmapContext);
121
 
        CFRelease(bitmapContext);
122
 
        free(data);
123
 
        id img = [UIImage imageWithCGImage: image];
124
 
        CGImageRelease(image);
125
 
        return img;
126
 
 
127
 
}
128
 
 
129
 
- (int) numCellsForImageSize: (float) imgSize density: (float) density
130
 
{
131
 
        float maxSize = 200.0f;
132
 
        float minSize = 50.0f;
133
 
 
134
 
        float targetSize = minSize + (maxSize-minSize)*(1.0f - density);
135
 
 
136
 
        return ceilf(imgSize/targetSize);
137
 
}
138
 
 
139
 
- (void) generateJigsaw
140
 
{
141
 
        if (imageTexture)
142
 
                glDeleteTextures(1, &imageTexture);
143
 
        imageTexture = 0;
144
 
 
145
 
        NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
146
 
        
147
 
        [defaults setInteger: [NSDate timeIntervalSinceReferenceDate] forKey: JigsawSeedKey];
148
 
 
149
 
        UIImage* image = [UIImage imageWithData: [defaults objectForKey: JigsawImageKey]];
150
 
        
151
 
        imageSize = CGSizeFitIntoSize([image size], CGSizeMake(400.0f, 400.0f));
152
 
        
153
 
        
154
 
        
155
 
        int hcells = [self numCellsForImageSize: imageSize.width density: [defaults floatForKey: JigsawDensityKey]];
156
 
        int vcells = [self numCellsForImageSize: imageSize.height density: [defaults floatForKey: JigsawDensityKey]];
157
 
        float jigWidth = imageSize.width;
158
 
        float jigHeight = imageSize.height;
159
 
        pieceSize = sqrtf(jigWidth*jigHeight/((float)(hcells*vcells)));
160
 
//      float cellWidth = jigWidth/(float)hcells;
161
 
//      float cellHeight = jigHeight/(float)vcells;
162
 
        
163
 
        float noiseFreq = 1.0f/MAX(jigWidth, jigHeight);
164
 
 
165
 
        JigsawGenerator* jgen = [[[JigsawGenerator alloc] init] autorelease];
166
 
        [jgen setWidth: jigWidth];
167
 
        [jgen setHeight: jigHeight];
168
 
        [jgen setHcells: hcells];
169
 
        [jgen setVcells: vcells];
170
 
        [jgen setSeed: [defaults integerForKey: JigsawSeedKey]];
171
 
        [jgen setDistortion: 0.1f*MIN(jigWidth, jigHeight)];
172
 
        [jgen setFrequency: noiseFreq];
173
 
        [jgen setOctaves: 0];
174
 
        [jgen setNoiseType: 0];
175
 
        
176
 
        [jgen setEdgeFiles: [NSMutableArray arrayWithArray: [NSBundle pathsForResourcesOfType: @"jigedge" inDirectory: [[NSBundle mainBundle] bundlePath]]]];
177
 
        [jgen setEnabledEdges: [NSMutableDictionary dictionaryWithObject: [NSNumber numberWithInt: 1] forKey:[[jgen edgeFiles] objectAtIndex: 0]]];
178
 
        [jgen setSmoothedEdges: [NSMutableDictionary dictionaryWithObject: [NSNumber numberWithInt: 1] forKey:[[jgen edgeFiles] objectAtIndex: 0]]];
179
 
 
180
 
        JigPieces pieces = [jgen generateJigsaw];
181
 
 
182
 
 
183
 
 
184
 
        
185
 
//      image = [self simplexImageWithSize: imageSize frequency: noiseFreq];
186
 
 
187
 
        CGImageRef cgImage = image.CGImage;
188
 
        [self textureFromCgImage: cgImage texName: &imageTexture width: 512 height: 512 repeat: NO mipmap: YES filter: YES];
189
 
 
190
 
 
191
 
 
192
 
        //[pieceVertexArrays release];
193
 
        [jigsawPieces release];
194
 
        //pieceVertexArrays = [[NSMutableArray alloc] init];
195
 
        jigsawPieces = [[NSMutableArray alloc] init];
196
 
        
197
 
/*
198
 
        CGPoint testPoints[6] = {
199
 
                {0.0f,0.0f},
200
 
                {50.0f,0.0f},
201
 
                {100.0f,0.0f},
202
 
                {100.0f,100.0f},
203
 
                {50.0f,100.0f},
204
 
                {0.0f,100.0f},
205
 
        };
206
 
 
207
 
        VertexArray* var = TriangulateOutline(testPoints,  6);
208
 
                        
209
 
        [pieceVertexArrays addObject: var];
210
 
*/
211
 
 
212
 
//      [self initChipmunk];
213
 
 
214
 
        CGRect bounds = [self bounds];
215
 
 
216
 
        //NSLog(@"bounds %f %f %f %f", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
217
 
//      CGPoint bc = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
218
 
        
219
 
        // need to transform the vertices from puzzle space to piece local space
220
 
        
221
 
        for (int i = 0; i < pieces.hcells; ++i)
222
 
        {
223
 
                for (int j = 0; j < pieces.vcells; ++j)
224
 
                {
225
 
                        CGPoint* points = NULL;
226
 
                        size_t numPoints = 0;
227
 
 
228
 
                        SimpleBezierPathToPolyline(pieces.cells[i][j].outline, &points, &numPoints);
229
 
                        
230
 
                        if (CGPointEqualToPoint(points[0], points[numPoints-1]))
231
 
                                numPoints--;
232
 
 
233
 
                        CGPoint* outlinePoints = createOutline(points, numPoints, 4.0f);
234
 
 
235
 
                        JigsawPiece* jig = [[[JigsawPiece alloc] init] autorelease];
236
 
                        
237
 
                        
238
 
                                                
239
 
                        CGPoint drawpos = pieces.cells[i][j].pos;
240
 
                        CGPoint jigpos = pieces.cells[i][j].pos;
241
 
                        
242
 
                        {
243
 
                                VertexArray* var = TriangulateOutline(points,  numPoints);
244
 
                                [var applyVertexTransform: mtranslate(vcreate(-drawpos.x, -drawpos.y, 0.0f))];
245
 
                                [[jig fillDrawables] addObject: var];
246
 
                        }
247
 
 
248
 
                        CGAffineTransform cgm = CGAffineTransformMakeTranslation(-drawpos.x, -drawpos.y);
249
 
                        CGPathRef newPath = CreateTransformedPathFromCGPath(pieces.cells[i][j].outline, cgm);
250
 
 
251
 
                        
252
 
                        //jigpos = CGPointMake(bc.x, bc.y);
253
 
                        //jigpos = CGPointMake(0.0, 0.0);
254
 
 
255
 
 
256
 
                        [[jig outlines] addObject: (id)newPath];
257
 
                        CGPathRelease(newPath);
258
 
                        
259
 
                        [jig setInitialPos: jigpos];
260
 
                        [jig setPosition: jigpos];
261
 
                        //cpSpaceAddBody(space, [jig body]);
262
 
                        
263
 
                        [jigsawPieces addObject: jig];
264
 
                        
265
 
#ifdef OLDSCHOOL_OUTLINE                        
266
 
                        VertexArray* ovar = [[[VertexArray alloc] init] autorelease];
267
 
                        ovar->numVertices = 3*numPoints;
268
 
                        ovar->vertices = calloc(sizeof(*ovar->vertices), ovar->numVertices);
269
 
                        for (size_t ii = 0; ii < numPoints; ++ii)
270
 
                        {
271
 
                                size_t vi = ii*3;
272
 
                                CGPoint p0 = outlinePoints[ii];
273
 
                                CGPoint p1 = points[ii];
274
 
                                CGPoint p2 = outlinePoints[ii+numPoints];
275
 
                                ovar->vertices[vi+0].pos[0] = p0.x;
276
 
                                ovar->vertices[vi+0].pos[1] = p0.y;
277
 
                                ovar->vertices[vi+1].pos[0] = p1.x;
278
 
                                ovar->vertices[vi+1].pos[1] = p1.y;
279
 
                                ovar->vertices[vi+2].pos[0] = p2.x;
280
 
                                ovar->vertices[vi+2].pos[1] = p2.y;
281
 
 
282
 
                                ovar->vertices[vi+0].normal[2] = 1.0;
283
 
                                ovar->vertices[vi+1].normal[2] = 1.0;
284
 
                                ovar->vertices[vi+2].normal[2] = 1.0;
285
 
                                ovar->vertices[vi+0].texcoord[0] = 0.0f;
286
 
                                ovar->vertices[vi+1].texcoord[0] = 0.5f;
287
 
                                ovar->vertices[vi+2].texcoord[0] = 1.0f;
288
 
                        }
289
 
                        
290
 
                        ovar->numIndices = 12*(numPoints);
291
 
                        ovar->indices = calloc(sizeof(*ovar->indices), ovar->numIndices);
292
 
                        
293
 
                        
294
 
                        size_t k = 0;
295
 
                        for (size_t ii = 0; ii < numPoints; ++ii)
296
 
                        {
297
 
                                /*
298
 
                                ovar->indices[k++] = (2*ii+0) % (numPoints*2);
299
 
                                ovar->indices[k++] = (2*ii+1) % (numPoints*2);
300
 
                                ovar->indices[k++] = (2*ii+2) % (numPoints*2);
301
 
                                ovar->indices[k++] = (2*ii+3) % (numPoints*2);
302
 
                                ovar->indices[k++] = (2*ii+2) % (numPoints*2);
303
 
                                ovar->indices[k++] = (2*ii+1) % (numPoints*2);
304
 
                                */
305
 
                                ovar->indices[k++] = (3*ii+0) % (numPoints*3);
306
 
                                ovar->indices[k++] = (3*ii+1) % (numPoints*3);
307
 
                                ovar->indices[k++] = (3*ii+3) % (numPoints*3);
308
 
                                ovar->indices[k++] = (3*ii+4) % (numPoints*3);
309
 
                                ovar->indices[k++] = (3*ii+3) % (numPoints*3);
310
 
                                ovar->indices[k++] = (3*ii+1) % (numPoints*3);
311
 
                                
312
 
                                ovar->indices[k++] = (3*ii+1) % (numPoints*3);
313
 
                                ovar->indices[k++] = (3*ii+2) % (numPoints*3);
314
 
                                ovar->indices[k++] = (3*ii+4) % (numPoints*3);
315
 
                                ovar->indices[k++] = (3*ii+5) % (numPoints*3);
316
 
                                ovar->indices[k++] = (3*ii+4) % (numPoints*3);
317
 
                                ovar->indices[k++] = (3*ii+2) % (numPoints*3);
318
 
                        }
319
 
                        
320
 
 
321
 
                        ovar->mode = GL_TRIANGLES;
322
 
                #ifdef SHOW_LINES
323
 
                        ovar->mode = GL_LINES;
324
 
                #endif
325
 
                        //ovar->numIndices = 0;
326
 
#else
327
 
                        VertexArray* ovar = ThickenOutline(points, numPoints, 2.0f, kThickenNoSplitting | kThickenInside | kThickenOutside);
328
 
#endif                  
329
 
                        [ovar applyVertexTransform: mtranslate(vcreate(-drawpos.x, -drawpos.y, 0.0f))];
330
 
                        [[jig outlineDrawables] addObject: ovar];
331
 
                        
332
 
                        free(points);
333
 
                        free(outlinePoints);
334
 
                        
335
 
                }
336
 
//              break;
337
 
        }
338
 
 
339
 
        // setup neighbours
340
 
 
341
 
        size_t k = 0;
342
 
        for (int i = 0; i < pieces.hcells; ++i)
343
 
        {
344
 
                for (int j = 0; j < pieces.vcells; ++j)
345
 
                {
346
 
                        JigsawPiece* jig = [jigsawPieces objectAtIndex: k];
347
 
                        
348
 
                        if (i != 0)
349
 
                        {
350
 
                                JigsawPiece* leftn = [jigsawPieces objectAtIndex: k - vcells];
351
 
                                
352
 
                                JigsawNeighbour* n = [[[JigsawNeighbour alloc] init] autorelease];
353
 
                                [n setAttachmentPoint: CGPointSub(pieces.cells[i][j].attachmentPoints[2], pieces.cells[i][j].pos)];
354
 
                                [n setDirection: 2];
355
 
                                [[jig neighbours] setObject: [NSMutableArray arrayWithObject: n] forKey: [NSValue valueWithPointer: leftn]];
356
 
                        }
357
 
                        if (i+1 < pieces.hcells)
358
 
                        {
359
 
                                JigsawPiece* rightn = [jigsawPieces objectAtIndex: k + vcells];
360
 
                                
361
 
                                JigsawNeighbour* n = [[[JigsawNeighbour alloc] init] autorelease];
362
 
                                [n setAttachmentPoint: CGPointSub(pieces.cells[i][j].attachmentPoints[0], pieces.cells[i][j].pos)];
363
 
                                [n setDirection: 0];
364
 
                                [[jig neighbours] setObject: [NSMutableArray arrayWithObject: n] forKey: [NSValue valueWithPointer: rightn]];
365
 
                        }
366
 
                        if (j != 0)
367
 
                        {
368
 
                                JigsawPiece* bottomn = [jigsawPieces objectAtIndex: k - 1];
369
 
                                
370
 
                                JigsawNeighbour* n = [[[JigsawNeighbour alloc] init] autorelease];
371
 
                                [n setAttachmentPoint: CGPointSub(pieces.cells[i][j].attachmentPoints[3], pieces.cells[i][j].pos)];
372
 
                                [n setDirection: 3];
373
 
                                [[jig neighbours] setObject: [NSMutableArray arrayWithObject: n] forKey: [NSValue valueWithPointer: bottomn]];
374
 
                        }
375
 
                        if (j+1 < pieces.vcells)
376
 
                        {
377
 
                                JigsawPiece* topn = [jigsawPieces objectAtIndex: k + 1];
378
 
                                
379
 
                                JigsawNeighbour* n = [[[JigsawNeighbour alloc] init] autorelease];
380
 
                                [n setAttachmentPoint: CGPointSub(pieces.cells[i][j].attachmentPoints[1], pieces.cells[i][j].pos)];
381
 
                                [n setDirection: 1];
382
 
                                [[jig neighbours] setObject: [NSMutableArray arrayWithObject: n] forKey: [NSValue valueWithPointer: topn]];
383
 
                        }
384
 
                        
385
 
                        k++;
386
 
                }
387
 
        }
388
 
        
389
 
 
390
 
        MersenneTwister* rgen = [MersenneTwister sharedTwister];
391
 
        for (JigsawPiece* jig in jigsawPieces)
392
 
        {
393
 
                CGPoint randomPos = CGPointMake([rgen randomFloatWithFloor: -0.5f*bounds.size.width ceiling: 0.5f*bounds.size.width], [rgen randomFloatWithFloor: -0.5f*bounds.size.height ceiling: 0.5f*bounds.size.height]);
394
 
                [jig setPosition: randomPos];
395
 
                [jig setOrientation: [rgen randomFloatWithFloor: 0.0f ceiling: (float)(2.0*M_PI)]];
396
 
        }
397
 
 
398
 
        FreeJigPieces(pieces);
399
 
        
400
 
        piecesChangedSinceLastRedraw = YES;
401
 
}
402
 
 
403
 
- (void) setupGraphicsForApi: (EAGLRenderingAPI) glApi
404
 
{
405
 
        glClearColor(0.38f,0.38f,0.38f,1.0f);
406
 
        
407
 
        //CGImageRef image = [UIImage imageNamed: @"coding1.jpg"].CGImage;
408
 
        //CGImageRef image = [UIImage imageNamed: @"white.png"].CGImage;
409
 
 
410
 
        [self doubleGradientTexture: &blackGradientTexture red: 0.0f green: 0.0f blue: 0.0f];
411
 
        [self doubleGradientTexture: &whiteGradientTexture red: 1.0f green: 1.0f blue: 1.0f];
412
 
        
413
 
        [self loadTextureFromPDFNamed: @"move-icon.pdf" texName: &moveIconTexture width: 32 height: 32 repeat: NO mipmap: NO filter: NO];
414
 
        [self loadTextureFromPDFNamed: @"rotate-icon.pdf" texName: &rotateIconTexture width: 32 height: 32 repeat: NO mipmap: NO filter: NO];
415
 
        [self loadTextureFromPDFNamed: @"scale-icon.pdf" texName: &scaleIconTexture width: 32 height: 32 repeat: NO mipmap: NO filter: NO];
416
 
        [self loadTextureFromBitmapNamed: @"white.png" texName: &whiteTexture repeat: NO mipmap: NO filter: NO];
417
 
 
418
 
        if ([[EAGLContext currentContext] API] == kEAGLRenderingAPIOpenGLES2)
419
 
        {
420
 
                jigsawShader = [[[ESShader shader] initWithVertexShaderFile: @"jigsawPiece.vs" fragmentShaderFile: @"jigsawPiece.fs"] retain];
421
 
        }
422
 
        else
423
 
        {
424
 
                jigsawShader = [[[ESShader shader] init] retain];
425
 
        }
426
 
        
427
 
        //CGRect bounds = [self bounds];
428
 
        oneTouchRotationThreshold = 10.0f;
429
 
        oneTouchRotationFactor = 0.02f;
430
 
        zoomTouchThreshold = 0.0f;
431
 
//      zoomCenter = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
432
 
        zoomCenter = CGPointZero;
433
 
        zoomFactor = 1.0f;
434
 
        
435
 
        targetGhostSize = 160.0f;
436
 
        
437
 
//      [self generateJigsaw];
438
 
        
439
 
}
440
 
 
441
 
static inline CGPoint cpvToCGPoint(cpVect p)
442
 
{
443
 
        return CGPointMake(p.x, p.y);
444
 
}
445
 
 
446
 
static inline cpVect CGPointToCpv(CGPoint p)
447
 
{
448
 
        return cpv(p.x, p.y);
449
 
}
450
 
 
451
 
- (BOOL) checkPiece: (JigsawPiece*) piece0 againstPiece: (JigsawPiece*) piece1
452
 
{
453
 
        NSArray* connections0 = [[piece0 neighbours] objectForKey: [NSValue valueWithPointer: piece1]];
454
 
        if (connections0)
455
 
        {       // if the object exists, its established the piece can be connected
456
 
                // next step is to find matching connection records
457
 
                NSArray* connections1 = [[piece1 neighbours] objectForKey: [NSValue valueWithPointer: piece0]];
458
 
                for (JigsawNeighbour* n0 in connections0)
459
 
                {
460
 
                        for (JigsawNeighbour* n1 in connections1)
461
 
                        {
462
 
                                if (([n0 direction] != [n1 direction]) && (([n0 direction] + [n1 direction]) % 2 == 0))
463
 
                                {
464
 
                                        CGAffineTransform R0 = CGAffineTransformMakeRotation([piece0 orientation]);
465
 
                                        CGAffineTransform R1 = CGAffineTransformMakeRotation([piece1 orientation]);
466
 
                                        
467
 
                                        float da = fmodf([piece1 orientation] - [piece0 orientation] + 2.0*M_PI, 2.0*M_PI);
468
 
                                        if (da > M_PI)
469
 
                                                da -= 2.0*M_PI;
470
 
                                        
471
 
                                        CGPoint r0 = CGPointTransform([n0 attachmentPoint], R0);
472
 
                                        CGPoint r1 = CGPointTransform([n1 attachmentPoint], R1);
473
 
                                        
474
 
                                        
475
 
                                        CGPoint x0 = CGPointAdd([piece0 position], r0);
476
 
                                        CGPoint x1 = CGPointAdd([piece1 position], r1);
477
 
                                        
478
 
                                        float snapRR = 10.0*10.0/(zoomFactor*zoomFactor);
479
 
                                        
480
 
                                        float realRR = CGPointDoubleDot(CGPointSub(x1,x0));
481
 
                                                                                
482
 
                                        //if ((snapRR > realRR))
483
 
                                        if ((fabsf(da) < 15.0f/180.0f*M_PI) && (snapRR > realRR))
484
 
                                                return YES;
485
 
                                }
486
 
                        }
487
 
                }
488
 
        }
489
 
        
490
 
        return NO;
491
 
}
492
 
 
493
 
- (void) animateUnhighlightPiece: (JigsawPiece*) piece withZoom: (BOOL) withZoom
494
 
{
495
 
        float duration = 0.3f;
496
 
        id anim = [[[ElV3Animation alloc] init] autorelease];
497
 
        [anim setSetter: @selector(setOutlineColor:)];
498
 
        [anim setTarget: piece];
499
 
        [anim setStartv: vcreate(1.0f,1.0f,1.0f)];
500
 
        [anim setEndv: vcreate(0.0f,0.0f,0.0f)];
501
 
        [anim setDuration: duration];
502
 
 
503
 
        [anim queueForKey: [NSString stringWithFormat: @"pieceAnimation %p", piece] atBeginning: NO cancelPending: NO];
504
 
        
505
 
        anim = [[[ElCallbackAnimation alloc] init] autorelease];
506
 
        [anim setCallback: @selector(piecesChanged)];
507
 
        [anim setTarget: self];
508
 
        [anim setDuration: duration];
509
 
 
510
 
        [anim queueForKey: [NSString stringWithFormat: @"pieceAnimationRefresh %p", piece] atBeginning: NO cancelPending: NO];
511
 
        
512
 
        if (withZoom)
513
 
        {
514
 
                anim = [[[ElFloatAnimation alloc] init] autorelease];
515
 
                [anim setProperty: @"ghostZoom"];
516
 
                [anim setTarget: piece];
517
 
                [anim setStartValue: [piece ghostZoom]];
518
 
                [anim setEndValue: 1.0f];
519
 
                [anim setDuration: duration];
520
 
 
521
 
                [anim queueForKey: [NSString stringWithFormat: @"pieceZoom %p", piece] atBeginning: NO cancelPending: NO];
522
 
        }
523
 
}
524
 
- (void) animateHighlightPiece: (JigsawPiece*) piece withZoom: (BOOL) withZoom
525
 
{
526
 
        float duration = 0.2f;
527
 
        id anim = [[[ElV3Animation alloc] init] autorelease];
528
 
        [anim setSetter: @selector(setOutlineColor:)];
529
 
        [anim setTarget: piece];
530
 
        [anim setStartv: vcreate(0.0f,0.0f,0.0f)];
531
 
        [anim setEndv: vcreate(1.0f,1.0f,1.0f)];
532
 
        [anim setDuration: duration];
533
 
 
534
 
        [anim queueForKey: [NSString stringWithFormat: @"pieceAnimation %p", piece] atBeginning: NO cancelPending: NO];
535
 
        
536
 
        if (withZoom)
537
 
        {
538
 
                anim = [[[ElFloatAnimation alloc] init] autorelease];
539
 
                [anim setProperty: @"ghostZoom"];
540
 
                [anim setTarget: piece];
541
 
                [anim setStartValue: 1.0f];
542
 
                [anim setEndValue: targetGhostSize/pieceSize/zoomFactor > 1.41f ? targetGhostSize/pieceSize/zoomFactor : 1.0f];
543
 
                [anim setDuration: duration];
544
 
 
545
 
                [anim queueForKey: [NSString stringWithFormat: @"pieceZoom %p", piece] atBeginning: NO cancelPending: NO];
546
 
        }
547
 
 
548
 
        anim = [[[ElCallbackAnimation alloc] init] autorelease];
549
 
        [anim setCallback: @selector(piecesChanged)];
550
 
        [anim setTarget: self];
551
 
        [anim setDuration: duration];
552
 
 
553
 
        [anim queueForKey: [NSString stringWithFormat: @"pieceAnimationRefresh %p", piece] atBeginning: NO cancelPending: NO];
554
 
}
555
 
 
556
 
 
557
 
- (void) snapPiece: (JigsawPiece*) piece toPiece: (JigsawPiece*) lump
558
 
{
559
 
        CGPoint d = CGPointSub([piece initialPos], [lump initialPos]);
560
 
        CGAffineTransform       T = CGAffineTransformMakeTranslation(d.x, d.y);
561
 
        m16                                     TM = mtranslate(vcreate(d.x, d.y, 0.0));
562
 
        
563
 
        NSValue* lkey = [NSValue valueWithPointer: lump];
564
 
        NSValue* pkey = [NSValue valueWithPointer: piece];
565
 
 
566
 
        for (VertexArray* var in [piece fillDrawables])
567
 
                [var applyVertexTransform: TM];
568
 
        for (VertexArray* var in [piece outlineDrawables])
569
 
                [var applyVertexTransform: TM];
570
 
        
571
 
        [[lump fillDrawables] addObjectsFromArray: [piece fillDrawables]];
572
 
        [[lump outlineDrawables] addObjectsFromArray: [piece outlineDrawables]];
573
 
 
574
 
        for (id outline in [piece outlines])
575
 
        {       
576
 
                CGPathRef path = CreateTransformedPathFromCGPath((CGPathRef)outline, T);
577
 
                [[lump outlines] addObject: (id)path];
578
 
                CGPathRelease(path);
579
 
        }
580
 
        
581
 
        // update neighbours of old piece ot point to new, combined one
582
 
        for (id nkey in [piece neighbours])
583
 
        {
584
 
                JigsawPiece* npiece = [nkey pointerValue];
585
 
                if (npiece == lump)
586
 
                        continue;
587
 
                
588
 
                //  update neighbours of piece to point to lump
589
 
                NSArray* oldNeighbourConnections = [[npiece neighbours] objectForKey: pkey];
590
 
                [[npiece neighbours] setObject: oldNeighbourConnections forKey: lkey];
591
 
                [[npiece neighbours] removeObjectForKey: pkey];
592
 
                
593
 
                // update pointers from piece to its neighbours with new coordinates
594
 
                NSMutableArray* neighbours = [[piece neighbours] objectForKey: nkey];
595
 
                for (JigsawNeighbour* n in neighbours)
596
 
                {
597
 
                        [n setAttachmentPoint: CGPointAdd([n attachmentPoint], d)];
598
 
                }
599
 
                
600
 
                // add to neighbours
601
 
                
602
 
                NSMutableArray* existingNeighbours = [[lump neighbours] objectForKey: nkey];
603
 
                if (!existingNeighbours)
604
 
                        [[lump neighbours] setObject: neighbours forKey: nkey];
605
 
                else
606
 
                        [existingNeighbours addObjectsFromArray: neighbours];
607
 
        }
608
 
        
609
 
        [[lump neighbours] removeObjectForKey: pkey];
610
 
        [jigsawPieces removeObject: piece];
611
 
        if (selectedPiece == piece)
612
 
        {
613
 
                [self animateHighlightPiece: lump withZoom: YES];
614
 
                selectedPiece = lump;
615
 
        }
616
 
}
617
 
 
618
 
 
619
 
- (BOOL) snapPieceIfRequired: (JigsawPiece*) piece0
620
 
{
621
 
        for (id key0 in [[[piece0 neighbours] copy] autorelease])
622
 
        {
623
 
                JigsawPiece* snappedPiece = [key0 pointerValue];
624
 
                
625
 
                if ([self checkPiece: piece0 againstPiece: snappedPiece])
626
 
                {
627
 
                        [self snapPiece: piece0 toPiece: snappedPiece];
628
 
                        return YES;
629
 
                }
630
 
        }
631
 
        return NO;
632
 
}
633
 
 
634
 
- (m16) inverseCanvasTransform
635
 
{
636
 
        //CGRect bounds = [self bounds];
637
 
        v3 c = vcreate(zoomCenter.x, zoomCenter.y, 0.0f);
638
 
        
639
 
        //m16 M = mmul(mtranslate(c), mmul(mscale(vcreate(zoomFactor, zoomFactor, 1.0)), mtranslate(vmul(c, -1.0f))));
640
 
        m16 M = mmul(mtranslate(c), mmul(mscale(vcreate(1.0f/zoomFactor, 1.0f/zoomFactor, 1.0)), mtranslate(vmul(c, -1.0f))));
641
 
        
642
 
        return M;
643
 
}
644
 
 
645
 
- (m16) canvasTransform
646
 
{
647
 
        //CGRect bounds = [self bounds];
648
 
        v3 c = vcreate(zoomCenter.x, zoomCenter.y, 0.0f);
649
 
        
650
 
        m16 M = mmul(mtranslate(c), mmul(mscale(vcreate(zoomFactor, zoomFactor, 1.0)), mtranslate(vmul(c, -1.0f))));
651
 
        
652
 
        return M;
653
 
}
654
 
 
655
 
 
656
 
- (CGAffineTransform) inverseCanvasTransformCG
657
 
{
658
 
        m16 M = [self inverseCanvasTransform];
659
 
        
660
 
        CGAffineTransform m = {M.m[0][0], M.m[0][1], M.m[1][0], M.m[1][1], M.m[3][0], M.m[3][1]};
661
 
        
662
 
        return m;
663
 
}
664
 
 
665
 
- (CGAffineTransform) inverseViewTransformCG
666
 
{       
667
 
        CGRect bounds = [self bounds];
668
 
        CGAffineTransform m = {1.0, 0.0, 0.0, -1.0, -0.5*bounds.size.width, 0.5*bounds.size.height};
669
 
        
670
 
        return m;
671
 
}
672
 
 
673
 
- (void) drawGhostPiece: (JigsawPiece*) piece withZoom: (float) ghostZoom
674
 
{
675
 
        
676
 
}
677
 
 
678
 
- (void) drawPiece: (JigsawPiece*) piece tableMatrix: (m16*) tableM textureMatrix: (m16*) textureM gradientMatrix: (m16*) gradientM zoom: (float) pieceZoom alpha: (float) pieceAlpha
679
 
{
680
 
        CGPoint ppos = [piece position];
681
 
        float a = [piece orientation];
682
 
        m16 R = mcreatefrombases(vcreate(cosf(a), sinf(a), 0.0), vcreate(-sinf(a), cosf(a), 0.0), vcreate(0.0,0.0,1.0));
683
 
        m16 pieceTransform = mmul(*tableM, mmul(mtranslate(vcreate(ppos.x, ppos.y,0.0)), R));
684
 
        //m16 pieceTransform = mtranslate(vcreate(0.0, 0.0,0.0));
685
 
        
686
 
        pieceTransform = mmul(pieceTransform, mscale(vcreate(pieceZoom, pieceZoom, 1.0)));
687
 
        
688
 
 
689
 
        [jigsawShader setModelviewMatrix: &pieceTransform];
690
 
        
691
 
        glBindTexture(GL_TEXTURE_2D, imageTexture);
692
 
        [jigsawShader setColorRed: pieceAlpha green: pieceAlpha blue: pieceAlpha alpha: pieceAlpha];
693
 
        [jigsawShader setTextureMatrix: textureM];
694
 
        for (VertexArray* var in [piece fillDrawables])
695
 
                [var draw];
696
 
 
697
 
/*
698
 
        if (selectedPiece == piece)
699
 
                glBindTexture(GL_TEXTURE_2D, whiteGradientTexture);
700
 
        else
701
 
                glBindTexture(GL_TEXTURE_2D, blackGradientTexture);
702
 
*/              
703
 
        glBindTexture(GL_TEXTURE_2D, whiteGradientTexture);
704
 
        v3 outlineColor = [piece outlineColor];
705
 
        [jigsawShader setColorRed: outlineColor.v.x*pieceAlpha green: outlineColor.v.y*pieceAlpha blue: outlineColor.v.z*pieceAlpha alpha: pieceAlpha];
706
 
 
707
 
#ifdef SHOW_LINES
708
 
        glBindTexture(GL_TEXTURE_2D, whiteTexture);
709
 
        glDisable(GL_DEPTH_TEST);
710
 
#endif
711
 
 
712
 
        [jigsawShader setTextureMatrix: gradientM];
713
 
        for (VertexArray* var in [piece outlineDrawables])
714
 
                [var draw];
715
 
}
716
 
 
717
 
- (void) drawView
718
 
{
719
 
        m16 I = midentity();
720
 
                
721
 
        CGRect bounds = [self bounds];
722
 
        
723
 
        m16 tableM = [self canvasTransform];
724
 
        m16 viewM = mortho(-0.5f*bounds.size.width, 0.5f*bounds.size.width, -0.5f*bounds.size.height, 0.5f*bounds.size.height, 1.0, -1.0);
725
 
        //m16 viewM = mortho(CGRectGetMinX(bounds), CGRectGetMaxX(bounds), CGRectGetMinY(bounds), CGRectGetMaxY(bounds), 1.0, -1.0);
726
 
        m16 textureM = mscale(vcreate(1.0/imageSize.width,-1.0/imageSize.height,1.0));
727
 
        textureM.m[3][0] = 0.5f;
728
 
        textureM.m[3][1] = 0.5f;
729
 
        [self setupViewDrawing];
730
 
        
731
 
        glDisable(GL_CULL_FACE);
732
 
        glEnable(GL_TEXTURE_2D);
733
 
        glDisable(GL_DEPTH_TEST);
734
 
        glEnable(GL_BLEND);
735
 
        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
736
 
        
737
 
        glBindTexture(GL_TEXTURE_2D, imageTexture);
738
 
        
739
 
        [jigsawShader bindShader];
740
 
        
741
 
        [jigsawShader setColorRed: 1.0f green: 1.0f blue: 1.0f alpha: 1.0f];
742
 
        
743
 
        [jigsawShader setTextureMatrix: &I];
744
 
        [jigsawShader setProjectionMatrix: &I];
745
 
        [jigsawShader setModelviewMatrix: &I];
746
 
        
747
 
//      [[VertexArray sharedDisk] draw];
748
 
        
749
 
        [jigsawShader setTextureMatrix: &textureM];
750
 
        [jigsawShader setProjectionMatrix: &viewM];
751
 
 
752
 
//      for (VertexArray* var in pieceVertexArrays)
753
 
//              [var draw];
754
 
 
755
 
        m16 gradientM = mmul(mtranslate(vcreate(0.5f - 1.0f*zoomFactor, 0.0f, 0.0f)), mscale(vcreate(2.0f*zoomFactor, 1.0f, 1.0f)));
756
 
        for (JigsawPiece* piece in [jigsawPieces reverseObjectEnumerator])
757
 
        {
758
 
                if ((selectedPiece == piece) && ([[piece outlines] count] < 2))
759
 
                        [self drawPiece: piece tableMatrix: &tableM textureMatrix: &textureM gradientMatrix: &gradientM zoom: [piece ghostZoom] alpha: 0.2f];
760
 
                [self drawPiece: piece tableMatrix: &tableM textureMatrix: &textureM gradientMatrix: &gradientM zoom: 1.0f alpha: 1.0f];
761
 
        }
762
 
        
763
 
 
764
 
        piecesChangedSinceLastRedraw = NO;
765
 
        
766
 
        if (initialTouch)
767
 
        {
768
 
                m16 quadS = mscale(vcreate(16.0,16.0,1.0));
769
 
                m16 quadT = mtranslate(vcreate(0.5*bounds.size.width+16.0, 0.5*bounds.size.height-16.0, 0.0));
770
 
 
771
 
                m16 T = mtranslate(vcreate(-32.0f, 0.0f, 0.0f));
772
 
 
773
 
                m16 quadM = mmul(quadT, quadS);
774
 
                
775
 
                [jigsawShader setTextureMatrix: &I];
776
 
                [jigsawShader setColorRed: 0.5f green: 0.5f blue: 0.5f alpha: 0.5f];
777
 
                glBlendFunc(GL_ONE, GL_ONE);
778
 
 
779
 
                if (selectedPiece)
780
 
                {       
781
 
                        quadM = mmul(T, quadM);
782
 
                        [jigsawShader setModelviewMatrix: &quadM];
783
 
                        glBindTexture(GL_TEXTURE_2D, moveIconTexture);
784
 
                        [[VertexArray sharedQuad] draw];
785
 
                }
786
 
                if (((fabsf(oneTouchRotationAccumulator) > oneTouchRotationThreshold) || secondaryTouch) && selectedPiece)
787
 
                {
788
 
                        quadM = mmul(T, quadM);
789
 
                        //float strength = 0.5f*fminf(fabsf(oneTouchRotationAccumulator*0.01), 1.0);
790
 
                        float strength = 0.5f;
791
 
                        [jigsawShader setColorRed: strength     green: strength blue: strength alpha: strength];
792
 
                        [jigsawShader setModelviewMatrix: &quadM];
793
 
                        glBindTexture(GL_TEXTURE_2D, rotateIconTexture);
794
 
                        [[VertexArray sharedQuad] draw];
795
 
                }
796
 
                if (initialTouch && secondaryTouch && !selectedPiece)
797
 
                {
798
 
                        quadM = mmul(T, quadM);
799
 
                        //float strength = 0.5f*fminf(fabsf(oneTouchRotationAccumulator*0.01), 1.0);
800
 
                        float strength = 0.5f;
801
 
                        [jigsawShader setColorRed: strength     green: strength blue: strength alpha: strength];
802
 
                        [jigsawShader setModelviewMatrix: &quadM];
803
 
                        glBindTexture(GL_TEXTURE_2D, scaleIconTexture);
804
 
                        [[VertexArray sharedQuad] draw];
805
 
                }
806
 
        }
807
 
        
808
 
        [self finishViewDrawing];
809
 
}
810
 
 
811
 
- (void) animationCallback: (id) info
812
 
{
813
 
//      float h = 0.01;
814
 
//      cpSpaceStep(space, h);
815
 
 
816
 
        float delta = [[info objectForKey: AnimationDeltaTimeKey] floatValue];
817
 
 
818
 
        zoomTouchAccumulator *= 1.0f - 0.5f*delta;
819
 
        nonZoomTouchAccumulator *= 1.0f - 0.5f*delta;
820
 
 
821
 
        if (selectedPiece)
822
 
        {
823
 
                oneTouchRotationAccumulator *= 1.0f - fclampf(10.0*delta, 0.0, 1.0);
824
 
 
825
 
                if ((fabsf(oneTouchRotationAccumulator) > oneTouchRotationThreshold) && (fabs(oneTouchRotationCirclelation) > 2.0*M_PI))
826
 
                {
827
 
                        float touchy = oneTouchRotationAccumulator > 0 ? oneTouchRotationAccumulator - oneTouchRotationThreshold : oneTouchRotationAccumulator + oneTouchRotationThreshold;
828
 
                        [selectedPiece rotateByAngle: delta*touchy*oneTouchRotationFactor aroundPoint: oneTouchRotationCenter];
829
 
                        [self piecesChanged];
830
 
                }
831
 
        }
832
 
        if (piecesChangedSinceLastRedraw)
833
 
                [self drawView];
834
 
}
835
 
 
836
 
- (void) secondaryTouch: (UITouch*) touch 
837
 
{
838
 
        CGAffineTransform vm = [self inverseViewTransformCG];
839
 
        CGAffineTransform cm = [self inverseCanvasTransformCG];
840
 
        CGPoint p0 = CGPointApplyAffineTransform([initialTouch locationInView: self], vm);
841
 
        CGPoint cp0 = CGPointTransform(p0, cm);
842
 
 
843
 
        CGPoint p1 = CGPointApplyAffineTransform([touch locationInView: self], vm);
844
 
        CGPoint cp1 = CGPointTransform(p1, cm);
845
 
 
846
 
        [secondaryTouch release];
847
 
        secondaryTouch = [touch retain];
848
 
 
849
 
        zoomTouchReference = CGPointScale(CGPointAdd(cp0,cp1), 0.5f);
850
 
        
851
 
        //if (selectedPiece)
852
 
        {
853
 
                
854
 
                rotationTouchLastVector = CGPointSub(p1, p0);
855
 
                rotationTouchInitialAngle = [selectedPiece orientation];
856
 
                
857
 
        }
858
 
}
859
 
 
860
 
- (void) initialTouch: (UITouch*) touch 
861
 
{
862
 
        CGAffineTransform vm = [self inverseViewTransformCG];
863
 
        CGAffineTransform cm = [self inverseCanvasTransformCG];
864
 
        CGPoint p = CGPointApplyAffineTransform([touch locationInView: self], vm);
865
 
        CGPoint cp = CGPointTransform(p, cm);
866
 
 
867
 
//      NSLog(@"touch down %.1f %.1f", p.x, p.y);
868
 
 
869
 
        oneTouchRotationAccumulator = 0.0f;
870
 
        oneTouchRotationDelta = CGPointZero;
871
 
 
872
 
        oneTouchRotationCirclelation = 0.0f;    
873
 
 
874
 
        if (selectedPiece)
875
 
        {
876
 
                [self animateUnhighlightPiece: selectedPiece withZoom: YES];
877
 
        }
878
 
 
879
 
        selectedPiece = nil;
880
 
        
881
 
        [self piecesChanged];
882
 
        int i = 0;
883
 
        
884
 
        for (JigsawPiece* piece in jigsawPieces)
885
 
        {
886
 
                CGPoint pos = [piece position];
887
 
                float alpha = [piece orientation];
888
 
//              NSLog(@"pos %.1f %.1f", pos.x, pos.y);
889
 
                CGAffineTransform R = CGAffineTransformMakeRotation(-alpha);
890
 
                CGAffineTransform T = CGAffineTransformMakeTranslation(-pos.x, -pos.y);
891
 
                CGPoint lp = CGPointTransform(cp, T);
892
 
                lp = CGPointTransform(lp, R);
893
 
                
894
 
                for (id _outline in [piece outlines])
895
 
                {
896
 
                        CGPathRef outline = (CGPathRef)_outline;
897
 
 
898
 
                        if (CGPathContainsPoint(outline, NULL, lp, NO))
899
 
                        {
900
 
                                selectedPiece = piece;
901
 
        //                      NSLog(@"selected piece");
902
 
                                break;
903
 
                        }
904
 
                }
905
 
                if (selectedPiece)
906
 
                        break;
907
 
                ++i;
908
 
        }
909
 
        
910
 
        if (selectedPiece)
911
 
        {
912
 
                [jigsawPieces removeObject: [selectedPiece retain]];
913
 
                [jigsawPieces insertObject: [selectedPiece autorelease] atIndex: 0];
914
 
                //v3 white = vcreate(1.0f,1.0f,1.0f);
915
 
                //[selectedPiece setOutlineColor: &white];
916
 
 
917
 
                [self animateHighlightPiece: selectedPiece withZoom: YES];
918
 
 
919
 
                //mouseConstraint = cpPinJointInit(mouseConstraint, mouseBody, [selectedPiece body], cpv(0.0,0.0), cpv(0.0,0.0));
920
 
                //cpSpaceAddConstraint(space, (cpConstraint*)mouseConstraint);
921
 
        }
922
 
        
923
 
        [initialTouch release];
924
 
        initialTouch = [touch retain];
925
 
}
926
 
 
927
 
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
928
 
{
929
 
 
930
 
        if (!initialTouch)
931
 
        {
932
 
                [self initialTouch: [touches anyObject]];
933
 
        }
934
 
        else if (!secondaryTouch)
935
 
        {
936
 
                NSMutableSet* secondaryTouches = [touches mutableCopy];
937
 
                [secondaryTouches removeObject: initialTouch];
938
 
                UITouch* touch = [secondaryTouches anyObject];
939
 
                [self secondaryTouch: touch];
940
 
        }
941
 
}
942
 
 
943
 
- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event
944
 
{
945
 
        CGAffineTransform vm = [self inverseViewTransformCG];
946
 
        CGAffineTransform cm = [self inverseCanvasTransformCG];
947
 
        CGPoint p0 = CGPointApplyAffineTransform([initialTouch locationInView: self], vm);
948
 
        CGPoint cp0 = CGPointTransform(p0, cm);
949
 
        CGPoint pp0 = CGPointApplyAffineTransform([initialTouch previousLocationInView: self], vm);
950
 
        CGPoint cpp0 = CGPointTransform(pp0, cm);
951
 
 
952
 
        CGPoint p1 = CGPointApplyAffineTransform([secondaryTouch locationInView: self], vm);
953
 
        CGPoint cp1 = CGPointTransform(p1, cm);
954
 
        CGPoint pp1 = CGPointApplyAffineTransform([secondaryTouch previousLocationInView: self], vm);
955
 
        CGPoint cpp1 = CGPointTransform(pp1, cm);
956
 
 
957
 
        CGPoint delta0 = CGPointSub(p0,pp0);
958
 
        CGPoint delta1 = CGPointSub(p1,pp1);
959
 
        
960
 
        // c for canvas
961
 
        CGPoint cdelta0 = CGPointSub(cp0,cpp0);
962
 
        CGPoint cdelta1 = CGPointSub(cp1,cpp1);
963
 
 
964
 
        if (initialTouch && selectedPiece)
965
 
        {
966
 
                
967
 
                oneTouchRotationCenter = cp0;
968
 
                
969
 
                if (!secondaryTouch)
970
 
                {
971
 
                        [selectedPiece setPosition: CGPointAdd([selectedPiece position], cdelta0)];
972
 
 
973
 
                        float sinDelta = CGPointCross(oneTouchRotationDelta, delta0);
974
 
                        float cosDelta = CGPointDot(oneTouchRotationDelta, delta0);
975
 
                        
976
 
                        float length = (CGPointLength(delta0)*CGPointLength(oneTouchRotationDelta));
977
 
                        if (length > FLT_EPSILON)
978
 
                        {
979
 
                                float cs = 1.0f/length;
980
 
                                float angle = atan2(sinDelta/cs, cosDelta/cs);
981
 
                                if (angle > M_PI)
982
 
                                        angle -= 2.0*M_PI;
983
 
                                
984
 
                                //NSLog(@"angle %.2f", 180.0/M_PI*angle);
985
 
                                
986
 
                                if (fabs(oneTouchRotationCirclelation) <= 4.0*M_PI)
987
 
                                        oneTouchRotationCirclelation += angle;
988
 
 
989
 
                                //NSLog(@"buffer %.2f", 180.0/M_PI*oneTouchRotationCirclelation);
990
 
                        }
991
 
 
992
 
                        if (fabs(oneTouchRotationCirclelation) > 2.0*M_PI)
993
 
                                oneTouchRotationAccumulator += sinDelta;
994
 
                        
995
 
                        
996
 
                        oneTouchRotationDelta = delta0;
997
 
                        
998
 
                        
999
 
                        
1000
 
                }
1001
 
                else
1002
 
                {
1003
 
                        
1004
 
                        CGPoint rv = CGPointSub(cp1, cp0);
1005
 
                        
1006
 
                        float alpha = atan2(rv.y,rv.x) - atan2(rotationTouchLastVector.y, rotationTouchLastVector.x);
1007
 
                        
1008
 
                        //[selectedPiece setPosition: CGPointAdd([selectedPiece position], cdelta0)];
1009
 
                        //[selectedPiece rotateByAngle: alpha aroundPoint: cp0];
1010
 
                        [selectedPiece setPosition: CGPointAdd([selectedPiece position], CGPointScale(CGPointAdd(cdelta0, cdelta1), 0.5f))];
1011
 
                        //[selectedPiece rotateByAngle: alpha aroundPoint: CGPointScale(CGPointAdd(cp0, cp1), 0.5f)];
1012
 
                        [selectedPiece rotateByAngle: alpha aroundPoint: [selectedPiece position]];
1013
 
                        
1014
 
 
1015
 
                        rotationTouchLastVector = rv;
1016
 
                }
1017
 
        }
1018
 
        
1019
 
        if (initialTouch && secondaryTouch)
1020
 
        {
1021
 
                CGPoint zc0 = CGPointScale(CGPointAdd(p0, p1), 0.5f);
1022
 
                CGPoint zcp0 = CGPointScale(CGPointAdd(pp0, pp1), 0.5f);
1023
 
                CGPoint zoomCenterMovement = CGPointSub(zc0, zcp0);
1024
 
 
1025
 
                CGPoint zoomDelta = CGPointSub(delta0, delta1);
1026
 
                CGPoint zoomAxis = CGPointSub(pp0, pp1);
1027
 
                CGPoint newZoomAxis = CGPointSub(p0, p1);
1028
 
                
1029
 
                float minZoomFactor = 0.5;
1030
 
                float maxZoomFactor = 20.0;
1031
 
                
1032
 
                float zoomTouchFactor = fabsf(CGPointDot(zoomDelta, CGPointNormalize(zoomAxis)));
1033
 
                float nonZoomTouchFactor = fabsf(CGPointCross(zoomDelta, CGPointNormalize(zoomAxis)));
1034
 
                zoomTouchAccumulator += zoomTouchFactor;
1035
 
                nonZoomTouchAccumulator += nonZoomTouchFactor;
1036
 
 
1037
 
                if (!selectedPiece || ((zoomTouchAccumulator > zoomTouchThreshold) && (zoomTouchAccumulator > 2.0*nonZoomTouchAccumulator)))
1038
 
                {
1039
 
                        if (selectedPiece)
1040
 
                                [self animateUnhighlightPiece: selectedPiece withZoom: YES];
1041
 
 
1042
 
                        selectedPiece = nil;
1043
 
                        float scaleFactor = CGPointLength(newZoomAxis)/(CGPointLength(zoomAxis));
1044
 
                        scaleFactor = fclampf(zoomFactor*scaleFactor, minZoomFactor, maxZoomFactor)/zoomFactor;
1045
 
                        
1046
 
                        float newZoomFactor = zoomFactor*scaleFactor;
1047
 
 
1048
 
                        
1049
 
                        CGPoint newZoomCenter = CGPointScale(CGPointAdd(CGPointAdd(zoomCenterMovement, CGPointScale(zoomTouchReference, (1.0-scaleFactor)*zoomFactor)), CGPointScale(zoomCenter, 1.0-zoomFactor)),
1050
 
                                1.0f/(1.0-scaleFactor*zoomFactor));
1051
 
                        
1052
 
                        //CGPoint newZoomCenter = CGPointAdd(zoomCenter, CGPointScale(CGPointSub(zoomTouchCenter, zoomCenter), scaleFactor));
1053
 
                        
1054
 
                        //if (fabsf(1.0f-scaleFactor) > 10.0f*FLT_EPSILON);
1055
 
                                zoomCenter = newZoomCenter;
1056
 
                        zoomFactor = newZoomFactor;
1057
 
                        
1058
 
                }
1059
 
        }
1060
 
 
1061
 
        [self piecesChanged];
1062
 
        
1063
 
}
1064
 
 
1065
 
- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event
1066
 
{       
1067
 
        if (initialTouch)
1068
 
        {
1069
 
                if ([touches containsObject: initialTouch])
1070
 
                {
1071
 
                        [secondaryTouch release];
1072
 
                        secondaryTouch = nil;
1073
 
                        
1074
 
                        [initialTouch release];
1075
 
                        initialTouch = nil;
1076
 
 
1077
 
                        if (selectedPiece)
1078
 
                                [self snapPieceIfRequired: selectedPiece];
1079
 
 
1080
 
                        if (selectedPiece)
1081
 
                                [self animateUnhighlightPiece: selectedPiece withZoom: YES];
1082
 
 
1083
 
                        selectedPiece = nil;    
1084
 
                        [self piecesChanged];
1085
 
                }
1086
 
                else if ([touches containsObject: secondaryTouch])
1087
 
                {
1088
 
                        [secondaryTouch release];
1089
 
                        secondaryTouch = nil;
1090
 
                }
1091
 
        }
1092
 
 
1093
 
}
1094
 
 
1095
 
- (void) touchesCancelled: (NSSet*) touches withEvent: (UIEvent*) event
1096
 
{
1097
 
        if (initialTouch)
1098
 
        {
1099
 
                if ([touches containsObject: initialTouch])
1100
 
                {
1101
 
                        [secondaryTouch release];
1102
 
                        secondaryTouch = nil;
1103
 
                        
1104
 
                        [initialTouch release];
1105
 
                        initialTouch = nil;
1106
 
                        
1107
 
                        if (selectedPiece)
1108
 
                                [self animateUnhighlightPiece: selectedPiece withZoom: YES];
1109
 
                        selectedPiece = nil;    
1110
 
                }
1111
 
                else if ([touches containsObject: secondaryTouch])
1112
 
                {
1113
 
                        [secondaryTouch release];
1114
 
                        secondaryTouch = nil;
1115
 
                }
1116
 
        }
1117
 
        [self piecesChanged];
1118
 
}
1119
 
 
1120
 
- (void) piecesChanged
1121
 
{
1122
 
        piecesChangedSinceLastRedraw = YES;
1123
 
}
1124
 
 
1125
 
- (void) saveJigsawState
1126
 
{
1127
 
        NSMutableData* data = [NSMutableData data];
1128
 
        NSKeyedArchiver* archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData: data] autorelease];
1129
 
        
1130
 
        [archiver encodeObject: jigsawPieces forKey: @"jigsawPieces"];
1131
 
        [archiver encodeFloat: pieceSize forKey: @"pieceSize"];
1132
 
        [archiver finishEncoding];
1133
 
        
1134
 
        NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
1135
 
        
1136
 
        [defaults setObject: data forKey: @"jigsawGameState"];
1137
 
        
1138
 
}
1139
 
 
1140
 
- (void) restoreJigsawState
1141
 
{
1142
 
        NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
1143
 
        NSData* data = [defaults objectForKey: @"jigsawGameState"];
1144
 
        NSKeyedUnarchiver* archiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData: data] autorelease];
1145
 
 
1146
 
 
1147
 
        if (imageTexture)
1148
 
                glDeleteTextures(1, &imageTexture);
1149
 
        imageTexture = 0;
1150
 
 
1151
 
        UIImage* image = [UIImage imageWithData: [defaults objectForKey: JigsawImageKey]];
1152
 
        
1153
 
        imageSize = CGSizeFitIntoSize([image size], CGSizeMake(400.0f, 400.0f));
1154
 
        
1155
 
        [self textureFromCgImage: [image CGImage] texName: &imageTexture width: 512 height: 512 repeat: NO mipmap: YES filter: YES];
1156
 
        
1157
 
        NSArray* pieces = [archiver decodeObjectForKey: @"jigsawPieces"];
1158
 
        pieceSize = [archiver decodeFloatForKey: @"pieceSize"];
1159
 
        
1160
 
        [archiver finishDecoding];
1161
 
        
1162
 
        [jigsawPieces release];
1163
 
        selectedPiece = nil;
1164
 
 
1165
 
        jigsawPieces = [pieces mutableCopy];
1166
 
        
1167
 
        piecesChangedSinceLastRedraw = YES;
1168
 
}
1169
 
 
1170
 
- (void)dealloc
1171
 
{
1172
 
    [super dealloc];
1173
 
}
1174
 
 
1175
 
 
1176
 
@end

Loggerhead 1.17 is a web-based interface for Bazaar branches