RSS

(root)/iphone/common : /source/GLString.m (revision 100)

To get this branch, use:
bzr branch /browse/iphone/common
Line Revision Contents
1 65
#import "GLString.h"
2
#import "gfx.h"
3
#import "VertexArray.h"
4
5
#import <OpenGLES/ES2/gl.h>
6
#import <CoreGraphics/CoreGraphics.h>
7
8
9
// The following is a NSBezierPath category to allow
10
// for rounded corners of the border
11
12
13
14
#pragma mark -
15
16
@implementation GLQuartzTexture
17
18
- (id) init
19
{
20
	if (!(self = [super init]))
21
		return nil;
22
23
	antialias = YES;
24
	subpixelAA = YES;
25
	filterTexture = NO;
26
	
27
	texturePadding = 1.0;
28
	requiresUpdate = YES;
29
30
	return self;
31
}
32
33
- (void) finalize
34
{
35
	if (texName)
36
		[GLResourceDisposal disposeOfResourcesWithTypes: texName, GL_TEXTURE, NULL];
37
38
	[super finalize];
39
}
40
41
- (void) deleteTexture
42
{
43
	if (texName)
44
	{
45
		glDeleteTextures(1, &texName);
46
		texName = 0;
47
		requiresUpdate = YES;
48
		textureSize = CGSizeZero;
49
	}
50
}
51
52
- (void) freeGLResources
53
{
54
	[self deleteTexture];
55
}
56
57
- (void) updateTextureIfRequired
58
{
59
	if (requiresUpdate)
60
		[self genTexture];
61
}
62
63
- (void) bindTexture
64
{
65
	if (!texName)
66
		[self genTexture];
67
	glBindTexture(GL_TEXTURE_2D, texName);
68
}
69
70
- (void) setAntialias:(BOOL)request
71
{
72
	antialias = request;
73
	requiresUpdate = YES;
74
}
75
76
- (void) setSubpixelAA:(BOOL)request
77
{
78
	subpixelAA = request;
79
	requiresUpdate = YES;
80
}
81
82
- (void) setFilterTexture:(BOOL)request
83
{
84
	filterTexture = request;
85
	requiresUpdate = YES;
86
}
87
88
- (void) setMipmapTexture:(BOOL)request
89
{
90
	mipmapTexture = request;
91
	requiresUpdate = YES;
92
}
93
94
- (void) setTexturePadding:(double)rad
95
{
96
	texturePadding = rad;
97
	requiresUpdate = YES;
98
}
99
100
- (void) doQuartzDrawingInContext: (CGContextRef) context sized: (CGSize) imgSize
101
{
102
}
103
104
- (void) generateTextureSized: (CGSize) texSize; // generates the texture without drawing texture to current context
105
{		
106
	//CGSize previousSize = textureSize;
107 68
	
108 65
	int width = texSize.width;
109
	int height = texSize.height;
110
111
	void* spriteData = calloc(1, width * height * 4);
112
	
113
	
114
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
115
	CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast);
116
	assert(spriteContext);
117
	
118
	UIGraphicsPushContext(spriteContext);
119
120
	CGContextSetShouldSmoothFonts(spriteContext, subpixelAA);
121
122
	[self doQuartzDrawingInContext: spriteContext sized: texSize];
123
124
	UIGraphicsPopContext();
125
	CGContextRelease(spriteContext);
126
	CGColorSpaceRelease(colorSpace);
127
	
128
	if (!texName)
129
		glGenTextures(1, &texName);
130
	glBindTexture(GL_TEXTURE_2D, texName);
131
132
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
133
134
	free(spriteData);
135
136
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
137
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
138
139
	if (mipmapTexture)
140
		glGenerateMipmap(GL_TEXTURE_2D);
141
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterTexture ? (mipmapTexture ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) : GL_NEAREST);
142
143
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterTexture ? GL_LINEAR : GL_NEAREST);
144
	
145
	textureSize = texSize;
146
	
147
	requiresUpdate = NO;
148
}
149
150
- (CGSize) updatedTextureSize
151
{
152
	return CGSizeZero;
153
}
154
155
- (void) genTexture
156
{
157
	[self generateTextureSized: [self updatedTextureSize]];
158
}
159
160
- (CGSize) textureSize
161
{
162
	if (requiresUpdate)
163
		return [self updatedTextureSize];
164
	else
165
		return textureSize;
166
}
167
168
- (void) drawWithBounds:(CGRect)bounds
169
{
170
	[self updateTextureIfRequired];
171
172
	if ([self texName])
173
	{
174
		
175
		//glDisable (GL_DEPTH_TEST); // ensure text is not remove by depth buffer test.
176
		//glEnable (GL_BLEND); // for text fading
177
		//glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // ditto
178
		glEnable (GL_TEXTURE_2D);	
179
		
180
		glBindTexture (GL_TEXTURE_2D, [self texName]);
181
		
182
		[[VertexArray sharedQuad] draw];
183
		
184
	}
185
}
186
187
- (void) drawAtPoint:(CGPoint)point scaled: (double) scale
188
{
189
	[self drawWithBounds: CGRectMake(point.x-[self texturePadding]*scale, point.y-[self texturePadding]*scale, [self textureSize].width*scale, [self textureSize].height*scale)];
190
}
191
- (void) drawAtPoint:(CGPoint)point
192
{
193
	[self drawAtPoint: point scaled: 1.0];
194
}
195
196
- (void) drawCenteredAtPoint:(CGPoint)point scaled: (double) scale
197
{
198
	[self drawWithBounds: CGRectMake(point.x-0.5*[self textureSize].width*scale, point.y-0.5*[self textureSize].height*scale, [self textureSize].width*scale, [self textureSize].height*scale)];
199
}
200
- (void) drawCenteredAtPoint:(CGPoint)point
201
{
202
	[self drawCenteredAtPoint: point scaled: 1.0];
203
}
204
205
206
@synthesize antialias, subpixelAA, texturePadding, filterTexture, mipmapTexture, textureSize, texName;
207
208
@end
209
210
#pragma mark -
211
212
@implementation GLQuartzBox
213
214
- (id) init
215
{
216
	if (!(self = [super init]))
217
		return nil;
218
219
	cornerRadius = 4.0;
220
	borderWidth = 1.0;
221
//	borderColor = [NSColor clearColor];
222
223
	return self;
224
}
225
226
CGPathRef CGPathCreateWithRoundedRect(CGRect rect, CGFloat r)
227 78
{
228 65
	CGMutablePathRef path = CGPathCreateMutable();
229
	CGPathMoveToPoint(path, NULL,
230
		rect.origin.x + rect.size.width - r,	rect.origin.y);
231
	CGPathAddArcToPoint(path, NULL,
232
		rect.origin.x + rect.size.width,		rect.origin.y,
233
		rect.origin.x + rect.size.width,		rect.origin.y + r, r);
234
	CGPathAddLineToPoint(path, NULL,
235
		rect.origin.x + rect.size.width, rect.origin.y + rect.size.height - r);
236
	CGPathAddArcToPoint(path, NULL,
237
		rect.origin.x + rect.size.width,		rect.origin.y + rect.size.height,
238
		rect.origin.x + rect.size.width - r,	rect.origin.y + rect.size.height, r);
239
	CGPathAddLineToPoint(path, NULL,
240
		rect.origin.x + r, rect.origin.y + rect.size.height);
241
	CGPathAddArcToPoint(path, NULL,
242
		rect.origin.x,							rect.origin.y + rect.size.height,
243
		rect.origin.x,							rect.origin.y + rect.size.height - r, r);
244
	CGPathAddLineToPoint(path, NULL,
245
		rect.origin.x, rect.origin.y + r);
246
	CGPathAddArcToPoint(path, NULL,
247
		rect.origin.x,							rect.origin.y,
248
		rect.origin.x + r,						rect.origin.y, r);
249
	CGPathAddLineToPoint(path, NULL,
250
		rect.origin.x + r,						rect.origin.y);
251
252 78
	CGPathCloseSubpath(path);
253 65
	return path;
254
}
255
256
- (void) doQuartzDrawingInContext: (CGContextRef) context sized: (CGSize) imgSize
257
{
258
	float borderAlpha = 0.0;
259
	float boxAlpha = 0.0;
260
		
261
	if (borderColor)
262
		borderAlpha = CGColorGetAlpha([borderColor CGColor]);
263
	if (boxColor)
264
		boxAlpha = CGColorGetAlpha([boxColor CGColor]);
265
266
	double bw = (borderAlpha ? borderWidth : 0.0);
267
	
268
	if (boxAlpha)
269
	{ // this should be == 0.0f but need to make sure
270
		[boxColor set];
271
		CGPathRef path = CGPathCreateWithRoundedRect(CGRectInset(CGRectMake(texturePadding, texturePadding, frameSize.width, frameSize.height), 0.5*borderWidth, 0.5*borderWidth), cornerRadius);
272 78
		CGContextAddPath(context, path);
273 65
		CGContextDrawPath(context, kCGPathFill);
274
		CGPathRelease(path);
275 78
	}
276 65
277
	if (borderAlpha)
278
	{
279
		[borderColor set]; 
280
		CGPathRef path = CGPathCreateWithRoundedRect(CGRectInset(CGRectMake(texturePadding, texturePadding, frameSize.width, frameSize.height), 0.5*borderWidth, 0.5*borderWidth), cornerRadius);
281 78
282 65
		CGContextAddPath(context, path);
283
		CGContextSetLineWidth(context, bw);
284
		CGContextDrawPath(context, kCGPathStroke);
285
		CGPathRelease(path);
286 78
	}
287 65
	
288
}
289
290
- (CGSize) updatedTextureSize
291
{
292
	CGSize texSize = CGSizeMake(ceil(frameSize.width+2.0*texturePadding), ceil(frameSize.height+2.0*texturePadding));
293
	return texSize;
294
}
295
296
- (void) setBoxColor:(UIColor *)color // set default text color
297
{
298
	boxColor = color;
299 94
	requiresUpdate = YES;
300 65
}
301
302
303
- (void) setBorderColor:(UIColor *)color // set default text color
304
{
305
	borderColor = color;
306 94
	requiresUpdate = YES;
307 65
}
308
309
- (void) setCornerRadius:(double)rad
310
{
311
	cornerRadius = rad;
312
	requiresUpdate = YES;
313
}
314
315
- (void) setBorderWidth:(double)rad
316
{
317
	borderWidth = rad;
318
	requiresUpdate = YES;
319
}
320
321
@synthesize cornerRadius, borderWidth, boxColor, borderColor, frameSize;
322
323
@end
324
325
#pragma mark -
326
327
@implementation GLQuartzArc
328
329
- (id) init
330
{
331
	if (!(self = [super init]))
332
		return nil;
333
334
	outerRadius = 10.0;
335
	borderWidth = 1.0;
336
	endAngle = 2.0*M_PI;
337
	cornerRadius = 5.0;
338
339
	return self;
340
}
341
342
- (void) doQuartzDrawingInContext: (CGContextRef) context sized: (CGSize) imgSize // generates the texture without drawing texture to current context
343
{
344
	double bw = (CGColorGetAlpha([borderColor CGColor]) ? borderWidth : 0.0);
345
	
346
//	double meanRadius = 0.5*(innerRadius+outerRadius);
347
//	double rdiff = (outerRadius-innerRadius);
348
	double angleRange = endAngle - startAngle;
349
//	double innerOffset = texturePadding + rdiff;
350
	
351
	double cornerCenterRadius = outerRadius - cornerRadius;
352
	double cornerAngle = cornerRadius/cornerCenterRadius;
353
	
354
	BOOL fullCircle = (angleRange > 2.0*M_PI*(1.0-FLT_EPSILON));
355
	
356
	if (fullCircle)
357
	{
358
		cornerAngle = 0.0;
359
		cornerCenterRadius = outerRadius;
360
		endAngle = 2.0*M_PI + startAngle;
361
	}
362
		
363
	double startArc = startAngle + cornerAngle;
364
	double endArc = endAngle - cornerAngle;
365
	
366
	CGPoint center = CGPointMake(imgSize.width*0.5, imgSize.height*0.5);
367
	
368
	CGMutablePathRef path = CGPathCreateMutable();
369
//	[path setLineJoinStyle: NSRoundLineJoinStyle];
370
//	[path setLineJoinStyle: NSBevelLineJoinStyle];
371
372
	CGPathMoveToPoint(path, NULL, center.x + cos(startAngle)*cornerCenterRadius, center.y + sin(startAngle)*cornerCenterRadius);
373
	
374
	double startArcDegrees = 180.0/M_PI*startArc;
375
	double endArcDegrees = 180.0/M_PI*endArc;
376
	double startAngleDegrees = 180.0/M_PI*startAngle;
377
	double endAngleDegrees = 180.0/M_PI*endAngle;
378
	
379
	if (!fullCircle && (cornerRadius > 0.0))
380
	{
381
		CGPoint cc = CGPointMake(center.x + cos(startArc)*cornerCenterRadius, center.y + sin(startArc)*cornerCenterRadius);
382
		CGPathAddArc(path, NULL, cc.x, cc.y, cornerRadius, startAngleDegrees - 90.0, startArcDegrees, NO);
383
	}
384
	
385
	CGPathAddArc(path, NULL, center.x, center.y, cornerRadius, startArcDegrees, endArcDegrees, NO);
386
387
	if (!fullCircle && (cornerRadius > 0.0))
388
	{
389
		CGPoint cc = CGPointMake(center.x + cos(endArc)*cornerCenterRadius, center.y + sin(endArc)*cornerCenterRadius);
390
		CGPathAddArc(path, NULL, cc.x, cc.y, cornerRadius, endAngleDegrees, endArcDegrees + 90, NO);
391
	}
392
	
393
394
	if (innerRadius > 0.0)
395
	{
396
		if (fullCircle)
397
		{
398
			CGPathCloseSubpath(path);
399
			CGPathMoveToPoint(path, NULL, center.x + cos(endArc)*innerRadius, center.y + sin(endArc)*innerRadius);
400
		}
401
	
402
		CGPathAddArc(path, NULL, center.x, center.y, innerRadius, endArcDegrees, startArcDegrees, YES);
403
404
405
	}
406
	else if (!fullCircle)
407
		CGPathAddLineToPoint(path, NULL, center.x, center.y);
408
409
	CGPathCloseSubpath(path);
410
411
	if (CGColorGetAlpha([fillColor CGColor]))
412
	{ // this should be == 0.0f but need to make sure
413
		[fillColor set];
414
		CGContextAddPath(context, path);
415
		CGContextDrawPath(context, kCGPathFill);
416
	}
417
418
	if (CGColorGetAlpha([borderColor CGColor]))
419
	{
420
		[borderColor set];
421
		CGContextSetLineWidth(context, bw);
422
		CGContextAddPath(context, path);
423
		CGContextDrawPath(context, kCGPathStroke);
424
	}
425
	CGPathRelease(path);
426 68
}
427 65
428
- (CGSize) updatedTextureSize
429
{
430
	CGSize texSize = CGSizeMake(ceil(2.0*outerRadius+2.0*texturePadding), ceil(2.0*outerRadius+2.0*texturePadding));
431
	return texSize;
432
}
433
434
- (void) setFillColor:(UIColor *)color
435
{
436
	fillColor = color;
437 94
	requiresUpdate = YES;
438 65
}
439
440
441
- (void) setBorderColor:(UIColor *)color
442
{
443
	borderColor = color;
444 94
	requiresUpdate = YES;
445 65
}
446
447
- (void) setOuterRadius:(double)rad
448
{
449
	outerRadius = rad;
450
	requiresUpdate = YES;
451
}
452
453
- (void) setInnerRadius:(double)rad
454
{
455
	innerRadius = rad;
456
	requiresUpdate = YES;
457
}
458
459
- (void) setBorderWidth:(double)rad
460
{
461
	borderWidth = rad;
462
	requiresUpdate = YES;
463
}
464
465
- (void) setCornerRadius:(double)rad
466
{
467
	cornerRadius = rad;
468
	requiresUpdate = YES;
469
}
470
471
- (void) setStartAngle:(double)rad
472
{
473
	startAngle = rad;
474
	requiresUpdate = YES;
475
}
476
477
- (void) setEndAngle:(double)rad
478
{
479
	endAngle = rad;
480
	requiresUpdate = YES;
481
}
482
483
@synthesize innerRadius, outerRadius, startAngle, endAngle, borderWidth, cornerRadius, fillColor, borderColor;
484
485
@end
486
487
#pragma mark -
488
489
@implementation GLString
490
491
+ (UIFont*) defaultFont
492
{
493
	UIFont*		font = [UIFont systemFontOfSize: [UIFont systemFontSize]];
494
	return font;
495
}
496
497
498
#pragma mark -
499
#pragma mark Initializers
500
501
// designated initializer
502
- (id) initWithString:(NSString *)aString withFont: (UIFont*) aFont withTextColor:(UIColor *)text withBoxColor:(UIColor *)box withBorderColor:(UIColor *)border
503
{
504
	if (!(self = [super init]))
505
		return nil;
506
507
	string = aString;
508
	
509
	font = aFont;
510 94
511 65
	self.textColor = text;
512
	self.boxColor = box;
513
	self.borderColor = border;
514
	staticFrame = NO;
515
	marginSize.width = 4.0f; // standard margins
516
	marginSize.height = 2.0f;
517
518
	return self;
519
}
520
521
// basic methods that pick up defaults
522
- (id) initWithString:(NSString *)astring;
523
{
524
	return [self initWithString: astring withFont: [GLString defaultFont] withTextColor:[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f] withBoxColor:[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:0.0f] withBorderColor:[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:0.0f]];
525
}
526
527
- (id) initWithString:(NSString *)aString withFont:(UIFont *)aFont
528
{
529
	return [self initWithString: aString withFont: aFont withTextColor: nil withBoxColor: nil withBorderColor: nil];
530
}
531
532
- (CGSize) frameSize
533
{
534
	if (NO == staticFrame)
535
	{ // find frame size if we have not already found it
536
		frameSize = [string sizeWithFont: font]; // current string size
537
		frameSize.width += marginSize.width * 2.0f; // add padding
538
		frameSize.height += marginSize.height * 2.0f;
539
	}
540
	return frameSize;
541
}
542
543
- (CGSize) updatedTextureSize
544
{
545
	if (NO == staticFrame)
546
	{ // find frame size if we have not already found it
547
		frameSize = [string sizeWithFont: font]; // current string size
548
		frameSize.width += marginSize.width * 2.0f; // add padding
549
		frameSize.height += marginSize.height * 2.0f;
550
	}
551
	return [super updatedTextureSize];
552
}
553
554
- (void) doQuartzDrawingInContext: (CGContextRef) context sized: (CGSize) imgSize // generates the texture without drawing texture to current context
555
{
556
	
557
	[super doQuartzDrawingInContext: context sized: imgSize];
558
	
559
	[textColor set]; 
560
	[string drawAtPoint: CGPointMake(marginSize.width+texturePadding, marginSize.height+texturePadding) withFont: font]; // draw at offset position
561
}
562
563
564
- (void) setTextColor:(UIColor *)color // set default text color
565
{
566
	textColor = color;
567 94
	requiresUpdate = YES;
568 65
}
569
570
571
#pragma mark Margin Size
572
573
// these will force the texture to be regenerated at the next draw
574
- (void) setMargins:(CGSize)size // set offset size and size to fit with offset
575
{
576
	marginSize = size;
577
	if (NO == staticFrame) { // ensure dynamic frame sizes will be recalculated
578
		frameSize.width = 0.0f;
579
		frameSize.height = 0.0f;
580
	}
581
	requiresUpdate = YES;
582
}
583
584
- (CGSize) marginSize
585
{
586
	return marginSize;
587
}
588
589
590
#pragma mark Frame
591
592
593
- (BOOL) staticFrame
594
{
595
	return staticFrame;
596
}
597
598
- (void) useStaticFrame:(CGSize)size // set static frame size and size to frame
599
{
600
	requiresUpdate = requiresUpdate || !staticFrame || !CGSizeEqualToSize(frameSize,size);
601
	frameSize = size;
602
	staticFrame = YES;
603
}
604
605
- (void) useDynamicFrame
606
{
607
	if (staticFrame) { // set to dynamic frame and set to regen texture
608
		staticFrame = NO;
609
		frameSize.width = 0.0f; // ensure frame sizes will be recalculated
610
		frameSize.height = 0.0f;
611
		requiresUpdate = YES;
612
	}
613
}
614
615
#pragma mark String
616
617
- (void) setString:(NSString *)theString // set string after initial creation
618
{
619
	string = [theString copy];
620
	if (NO == staticFrame) { // ensure dynamic frame sizes will be recalculated
621
		frameSize.width = 0.0f;
622
		frameSize.height = 0.0f;
623
	}
624
	requiresUpdate = YES;
625
}
626
627
- (void) setFont: (UIFont*) aFont
628
{
629
	font = aFont;
630 94
	if (NO == staticFrame) { // ensure dynamic frame sizes will be recalculated
631 65
		frameSize.width = 0.0f;
632
		frameSize.height = 0.0f;
633
	}
634
	requiresUpdate = YES;
635
}
636
637
@synthesize textColor;
638
639
@end
640

Loggerhead 1.17 is a web-based interface for Bazaar branches