1# 2# CIBevelView.rb 3# CIBevelSample 4# 5# Created by Laurent Sansonetti on 12/15/06. 6# Copyright (c) 2006 Apple Computer. All rights reserved. 7# 8 9require 'SampleCIView' 10 11class CIBevelView < SampleCIView 12 13 def initWithFrame(frameRect) 14 return nil if super_initWithFrame(frameRect).nil? 15 16 @points = [] 17 @points << CGPoint.new(0.5 * frameRect.size.width, frameRect.size.height - 100.0) 18 @points << CGPoint.new(150.0, 100.0) 19 @points << CGPoint.new(frameRect.size.width - 150.0, 100.0) 20 @points << CGPoint.new(0.7 * @points[0].x + 0.3 * @points[2].x, 0.7 * @points[0].y + 0.3 * @points[2].y) 21 22 url = NSURL.fileURLWithPath(NSBundle.mainBundle.pathForResource_ofType('lightball', 'tiff')) 23 lightball = CIImage.imageWithContentsOfURL(url) 24 25 @heightFieldFilter = CIFilter.filterWithName('CIHeightFieldFromMask') 26 @heightFieldFilter.setValue_forKey(NSNumber.numberWithFloat(15.0), 'inputRadius') 27 28 @twirlFilter = CIFilter.filterWithName('CITwirlDistortion') 29 @twirlFilter.setValue_forKey(CIVector.vectorWithX_Y(0.5 * frameRect.size.width, 0.5 * frameRect.size.height), 'inputCenter') 30 @twirlFilter.setValue_forKey(NSNumber.numberWithFloat(300.0), 'inputRadius') 31 @twirlFilter.setValue_forKey(NSNumber.numberWithFloat(0.0), 'inputAngle') 32 33 @shadedFilter = CIFilter.filterWithName('CIShadedMaterial') 34 @shadedFilter.setValue_forKey(lightball, 'inputShadingImage') 35 @shadedFilter.setValue_forKey(NSNumber.numberWithFloat(20.0), 'inputScale') 36 37 # 1/30 second should give us decent animation 38 @angleTime = 0 39 @currentPoint = 0 40 NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats( 41 1.0 / 30.0, self, 'changeTwirlAngle:', nil, true) 42 43 return self 44 end 45 46 def changeTwirlAngle(timer) 47 @angleTime += timer.timeInterval 48 @twirlFilter.setValue_forKey(NSNumber.numberWithFloat(-0.2 * Math.sin(@angleTime * 5.0)), 'inputAngle') 49 updateImage 50 end 51 52 def mouseDragged(event) 53 loc = convertPoint_fromView(event.locationInWindow, nil) 54 point = @points[@currentPoint] 55 point.x = loc.x 56 point.y = loc.y 57 @lineImage = nil 58 59 # normally we'd want this, but the timer will cause us to redisplay anyway 60 setNeedsDisplay(true) 61 end 62 63 def mouseDown(event) 64 loc = convertPoint_fromView(event.locationInWindow, nil) 65 d = 1e4 66 @points.each_with_index do |point, i| 67 x = point.x - loc.x 68 y = point.y - loc.y 69 t = x * x + y * y 70 71 if t < d 72 @currentPoint = i 73 d = t 74 end 75 end 76 mouseDragged(event) 77 end 78 79 def updateImage 80 context = NSGraphicsContext.currentContext.CIContext 81 unless @lineImage 82 bounds = self.bounds 83 layer = context.createCGLayerWithSize_info(CGSize.new(bounds.size.width, bounds.size.height), nil) 84 cg = CGLayerGetContext(layer) 85 86 CGContextSetRGBStrokeColor(cg, 1,1,1,1) 87 CGContextSetLineCap(cg, KCGLineCapRound) 88 89 CGContextSetLineWidth(cg, 60.0) 90 CGContextMoveToPoint(cg, @points[0].x, @points[0].y) 91 @points[1..-1].each { |point| CGContextAddLineToPoint(cg, point.x, point.y) } 92 CGContextStrokePath(cg); 93 94 @lineImage = CIImage.alloc.initWithCGLayer(layer) 95 end 96 97 @heightFieldFilter.setValue_forKey(@lineImage, 'inputImage') 98 @twirlFilter.setValue_forKey(@heightFieldFilter.valueForKey('outputImage'), 'inputImage') 99 @shadedFilter.setValue_forKey(@twirlFilter.valueForKey('outputImage'), 'inputImage') 100 101 setImage(@shadedFilter.valueForKey('outputImage')) 102 end 103end 104