CIBevelSample¶
Translation into python of and ADC example of the same name.
Sources¶
CIBevelView.py¶
from math import sin
import objc
import Quartz
import Cocoa
from objc import super
from SampleCIView import SampleCIView
NUM_POINTS = 4
class CIBevelView(SampleCIView):
currentPoint = objc.ivar(type=objc._C_INT)
points = objc.ivar()
angleTime = objc.ivar(type=objc._C_FLT)
lineImage = objc.ivar()
twirlFilter = objc.ivar()
heightFieldFilter = objc.ivar()
shadedFilter = objc.ivar()
def initWithFrame_(self, frameRect):
self = super(CIBevelView, self).initWithFrame_(frameRect)
if self is None:
return None
self.points = [None] * NUM_POINTS
self.points[0] = Quartz.CGPointMake(
0.5 * frameRect.size.width, frameRect.size.height - 100.0
)
self.points[1] = Quartz.CGPointMake(150.0, 100.0)
self.points[2] = Quartz.CGPointMake(frameRect.size.width - 150.0, 100.0)
self.points[3] = Quartz.CGPointMake(
0.7 * self.points[0].x + 0.3 * self.points[2].x,
0.7 * self.points[0].y + 0.3 * self.points[2].y,
)
url = Cocoa.NSURL.fileURLWithPath_(
Cocoa.NSBundle.mainBundle().pathForResource_ofType_("lightball", "tiff")
)
self.lightball = Quartz.CIImage.imageWithContentsOfURL_(url)
self.heightFieldFilter = Quartz.CIFilter.filterWithName_(
"CIHeightFieldFromMask"
)
self.heightFieldFilter.setDefaults()
self.heightFieldFilter.setValue_forKey_(15.0, "inputRadius")
self.twirlFilter = Quartz.CIFilter.filterWithName_("CITwirlDistortion")
self.twirlFilter.setDefaults()
self.twirlFilter.setValue_forKey_(
Quartz.CIVector.vectorWithX_Y_(
0.5 * frameRect.size.width, 0.5 * frameRect.size.height
),
"inputCenter",
)
self.twirlFilter.setValue_forKey_(300.0, "inputRadius")
self.twirlFilter.setValue_forKey_(0.0, "inputAngle")
self.shadedFilter = Quartz.CIFilter.filterWithName_("CIShadedMaterial")
self.shadedFilter.setDefaults()
self.shadedFilter.setValue_forKey_(self.lightball, "inputShadingImage")
self.shadedFilter.setValue_forKey_(20.0, "inputScale")
# 1/30 second should give us decent animation
Cocoa.NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(
1.0 / 30.0, self, "changeTwirlAngle:", None, True
)
return self
def changeTwirlAngle_(self, timer):
self.angleTime += timer.timeInterval()
self.twirlFilter.setValue_forKey_(
-0.2 * sin(self.angleTime * 5.0), "inputAngle"
)
self.updateImage()
def mouseDragged_(self, event):
loc = self.convertPoint_fromView_(event.locationInWindow(), None)
self.points[self.currentPoint].x = loc.x
self.points[self.currentPoint].y = loc.y
self.lineImage = None
# normally we'd want this, but the timer will cause us to
# redisplay anyway
# self.setNeedsDisplay_(True)
def mouseDown_(self, event):
d = 1e4
loc = self.convertPoint_fromView_(event.locationInWindow(), None)
for i in range(NUM_POINTS):
x = self.points[i].x - loc.x
y = self.points[i].y - loc.y
t = x * x + y * y
if t < d:
self.currentPoint = i
d = t
self.mouseDragged_(event)
def updateImage(self):
context = Cocoa.NSGraphicsContext.currentContext().CIContext()
if self.lineImage is None:
bounds = self.bounds()
layer = context.createCGLayerWithSize_info_(
Quartz.CGSizeMake(Cocoa.NSWidth(bounds), Cocoa.NSHeight(bounds)), None
)
cg = Quartz.CGLayerGetContext(layer)
Quartz.CGContextSetRGBStrokeColor(cg, 1, 1, 1, 1)
Quartz.CGContextSetLineCap(cg, Quartz.kCGLineCapRound)
Quartz.CGContextSetLineWidth(cg, 60.0)
Quartz.CGContextMoveToPoint(cg, self.points[0].x, self.points[0].y)
for i in range(1, NUM_POINTS):
Quartz.CGContextAddLineToPoint(cg, self.points[i].x, self.points[i].y)
Quartz.CGContextStrokePath(cg)
self.lineImage = Quartz.CIImage.alloc().initWithCGLayer_(layer)
self.heightFieldFilter.setValue_forKey_(self.lineImage, "inputImage")
self.twirlFilter.setValue_forKey_(
self.heightFieldFilter.valueForKey_("outputImage"), "inputImage"
)
self.shadedFilter.setValue_forKey_(
self.twirlFilter.valueForKey_("outputImage"), "inputImage"
)
self.setImage_(self.shadedFilter.valueForKey_("outputImage"))
SampleCIView.py¶
"""
SampleCIView - simple OpenGL based CoreImage view
"""
# XXX: Fix me
# flake8: noqa F403, F405
import CGL
import Cocoa
import objc
import Quartz
from OpenGL.GL import *
from OpenGL.GL.APPLE.transform_hint import *
# The default pixel format
_pf = None
class SampleCIView(Cocoa.NSOpenGLView):
_context = objc.ivar()
_image = objc.ivar()
_lastBounds = objc.ivar(type=Cocoa.NSRect.__typestr__)
@classmethod
def defaultPixelFormat(self):
global _pf
if _pf is None:
# Making sure the context's pixel format doesn't have a recovery
# renderer is important - otherwise CoreImage may not be able to
# create deeper context's that share textures with this one.
attr = (
Cocoa.NSOpenGLPFAAccelerated,
Cocoa.NSOpenGLPFANoRecovery,
Cocoa.NSOpenGLPFAColorSize,
32,
)
_pf = Cocoa.NSOpenGLPixelFormat.alloc().initWithAttributes_(attr)
return _pf
def image(self):
return self._image
def setImage_dirtyRect_(self, image, r):
if self._image is not image:
self._image = image
if Quartz.CGRectIsInfinite(r):
self.setNeedsDisplay_(True)
else:
self.setNeedsDisplayInRect_(r)
def setImage_(self, image):
self.setImage_dirtyRect_(image, CGRectInfinite)
def prepareOpenGL(self):
parm = 1
# Enable beam-synced updates.
self.openGLContext().setValues_forParameter_(
(parm,), Cocoa.NSOpenGLCPSwapInterval
)
# Make sure that everything we don't need is disabled. Some of these
# are enabled by default and can slow down rendering.
glDisable(GL_ALPHA_TEST)
glDisable(GL_DEPTH_TEST)
glDisable(GL_SCISSOR_TEST)
glDisable(GL_BLEND)
glDisable(GL_DITHER)
glDisable(GL_CULL_FACE)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
glDepthMask(GL_FALSE)
glStencilMask(0)
glClearColor(0.0, 0.0, 0.0, 0.0)
glHint(GL_TRANSFORM_HINT_APPLE, GL_FASTEST)
def viewBoundsDidChange_(self, bounds):
# For subclasses.
pass
def updateMatrices(self):
r = self.bounds()
if r != self._lastBounds:
self.openGLContext().update()
# Install an orthographic projection matrix (no perspective)
# with the origin in the bottom left and one unit equal to one
# device pixel.
glViewport(0, 0, r.size.width, r.size.height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, r.size.width, 0, r.size.height, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
self._lastBounds = r
self.viewBoundsDidChange_(r)
def drawRect_(self, r):
self.openGLContext().makeCurrentContext()
# Allocate a CoreImage rendering context using the view's OpenGL
# context as its destination if none already exists.
if self._context is None:
pf = self.pixelFormat()
if pf is None:
pf = type(self).defaultPixelFormat()
self._context = Quartz.CIContext.contextWithCGLContext_pixelFormat_options_(
CGL.CGLGetCurrentContext(), pf.CGLPixelFormatObj(), None
)
ir = Cocoa.CGRectIntegral(r)
if Cocoa.NSGraphicsContext.currentContextDrawingToScreen():
self.updateMatrices()
# Clear the specified subrect of the OpenGL surface then
# render the image into the view. Use the GL scissor test to
# clip to * the subrect. Ask CoreImage to generate an extra
# pixel in case * it has to interpolate (allow for hardware
# inaccuracies)
rr = Cocoa.CGRectIntersection(
Cocoa.CGRectInset(ir, -1.0, -1.0), self._lastBounds
)
glScissor(ir.origin.x, ir.origin.y, ir.size.width, ir.size.height)
glEnable(GL_SCISSOR_TEST)
glClear(GL_COLOR_BUFFER_BIT)
if self.respondsToSelector_("drawRect:inCIContext:"):
self.drawRect_inCIContext_(rr, self._context)
elif self._image is not None:
self._context.drawImage_atPoint_fromRect_(self._image, rr.origin, rr)
glDisable(GL_SCISSOR_TEST)
# Flush the OpenGL command stream. If the view is double
# buffered this should be replaced by [[self openGLContext]
# flushBuffer].
glFlush()
else:
# Printing the view contents. Render using CG, not OpenGL.
if self.respondsToSelector_("drawRect:inCIContext:"):
self.drawRect_inCIContext_(ir, self._context)
elif self._image is not None:
cgImage = self._context.createCGImage_fromRect_(self._image, ir)
if cgImage is not None:
Quartz.CGContextDrawImage(
Cocoa.NSGraphicsContext.currentContext().graphicsPort(),
ir,
cgImage,
)
main.py¶
import CIBevelView # noqa: F401
import SampleCIView # noqa: F401
from PyObjCTools import AppHelper
AppHelper.runEventLoop()
setup.py¶
"""
Script for building the example.
Usage:
python3 setup.py py2app
"""
from setuptools import setup
setup(
name="CIBevelSample",
app=["main.py"],
data_files=["English.lproj", "lightball.tiff"],
setup_requires=["py2app", "pyobjc-framework-Cocoa", "pyobjc-framework-Quartz"],
)