CIBevelSample¶
A PyObjC Example without documentation
Sources¶
CIBevelView.py¶
from math import sin
import objc
import Quartz
import Cocoa
from objc import super # noqa: A004
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().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):
param = 1
# Enable beam-synced updates.
self.openGLContext().setValues_forParameter_(
(param,), 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"],
)