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