Drawing on CGContext with semi-tranparent color vs opaque color and setting alpha - core-graphics

This may be a simple question, but I couldn't figure it out from docs.
Is there differnece between those two approaches?
let context = makeContext()
let color = CGColor(red: 1, green: 0, blue: 0, alpha: 0.5)
context.setFillColor(color)
and
let context = makeContext()
let color = CGColor(red: 1, green: 0, blue: 0, alpha: 1)
context.setAlpha(0.5)
context.setFillColor(color)
As I understand, setAlpha sets alpha both for filling and stroking, but other than that, are those two equivalent? And if I set alpha to 0.5 and color with alpha 0.5 – will it draw with alpha 0.25?
I checked it in sample project and it appears to be yes, but may be there is some caveats that I don't know.
Thanks!

Related

Cut out a custom shape from an image in P5.js

I am trying to create jigsaw puzzle shapes using P5.js. After creating puzzle shapes, I want to cut areas from main image into pieces. For that I have options of using GET() or COPY():
But both of them take fix height and width as parameter. How can I copy a custom area like given in following shapes:
https://editor.p5js.org/techty/sketches/h7qwatZRb
let cutout = createGraphics(w, h);
cutout.background(255, 255);
cutout.blendMode(REMOVE);
//draw shape on cutout
let newshapeimagegraphic = createGraphics(w, h);
newshapeimagegraphic.image(myImg, 0, 0);
newshapeimagegraphic.blendMode(REMOVE);
newshapeimagegraphic.image(cutout, 0, 0);
image(newshapeimagegraphic, 0, 0);

Fastest way to draw offscreen CALayer content

I'm looking for the fastest way to draw offscreen CALayer content (no alpha needed) on macOS. Note, that these examples aren't threaded, but the point is (and why I'm not just using CALayer.setNeedsDisplay) because I'm doing this drawing on a background thread.
My original code did this:
let bounds = layer.bounds.size
let contents = NSImage(size: size)
contents.lockFocusFlipped(true)
let context = NSGraphicsContext.current()!.cgContext
layer.draw(in: context)
contents.unlockFocus()
layer.contents = contents
My current best is quite a bit faster:
let contentsScale = layer.contentsScale
let width = Int(bounds.width * contentsScale)
let height = Int(bounds.height * contentsScale)
let bytesPerRow = width * 4
let alignedBytesPerRow = ((bytesPerRow + (64 - 1)) / 64) * 64
let context = CGContext(
data: nil,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: alignedBytesPerRow,
space: NSScreen.main()?.colorSpace?.cgColorSpace ?? CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue
)!
context.scaleBy(x: contentsScale, y: contentsScale)
layer.draw(in: context)
layer.contents = context.makeImage()
Tips and recommendations for making it better/faster are welcome.

How do I get the frame of visible content from SKCropNode?

It appears that, in SpriteKit, when I use a mask in a SKCropNode to hide some content, it fails to change the frame calculated by calculateAccumulatedFrame. I'm wondering if there's any way to calculate the visible frame.
A quick example:
import SpriteKit
let par = SKCropNode()
let bigShape = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 100, height: 100))
bigShape.fillColor = UIColor.redColor()
bigShape.strokeColor = UIColor.clearColor()
par.addChild(bigShape)
let smallShape = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 20, height: 20))
smallShape.fillColor = UIColor.greenColor()
smallShape.strokeColor = UIColor.clearColor()
par.maskNode = smallShape
par.calculateAccumulatedFrame() // returns (x=0, y=0, width=100, height=100)
I expected par.calculateAccumulatedFrame() to return (x=0, y=0, width=20, height=20) based on the crop node mask.
I thought maybe I could code the function myself as an extension that basically reimplements calculateAccumulatedFrame with support for checking for SKCropNodes and their masks, but it occurred to me that I would need to consider the alpha of that mask to determine if there's actual content that grows the frame. Sounds difficult.
Is there an easy way to calculate this?

OpenGL ES 2.0 blending

I set glBlendFunc to
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
and for testing purposes I set the color in my fragment shader like this
gl_FragColor = vec4(1.0,0.0,0.0,0.0);
Shouldn't the object be fully transparent? What could the reason be if it's not?
The first argument of glBlendFunc() is the source factor, the second is the destination factor. In your case:
sfactor = 1.0;
dfactor = 1.0 - src.alpha;
being src.alpha = 0.0, from your gl_FragColor:
sfactor = 1.0;
dfactor = 1.0;
So the color put to the buffer will be:
buffer = sfactor * src + dfactor * dst;
Substituting...
buffer = (1.0,0.0,0.0,0.0) + dst;
So, putting it simple, you are adding 1 to the red channel of the existing buffer.
If you want to make the output fully transparent, the usual function is:
glBlendFunc(GL_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
The one you wrote is usually used for pre-multiplied alpha in the source. But (1, 0, 0, 0) is obviously not a premultiplied alpha value!

How to handle the orthographic projection when auto-rotating screen?

I have this method for performing the ortho projection:
void myGL::ApplyOrtho(float maxX, float maxY) const
{
float a = 1.0f / maxX;
float b = 1.0f / maxY;
float ortho[16] = {
a, 0, 0, 0,
0, b, 0, 0,
0, 0, -1, 0,
0, 0, 0, 1};
GLint projectionUniform = glGetUniformLocation(m_simpleProgram, "Projection");
glUniformMatrix4fv(projectionUniform, 1, 0, &ortho[0]);
}
It works fine for iPad screen when I do this:
ApplyOrtho(2, 2*1024/768);
Here's my rendered image:
However, when I rotate to landscape, it looks like this:
Now my assumption is this is because the ApplyOrtho matrix is setting a fixed projection and that projection does not rotate while the image is rotating within that projection, thus getting displayed fatter.
Incidentally, this is the rotation:
void myGL::ApplyRotation(float degrees) const
{
float radians = degrees * 3.14159f / 180.0f;
float s = std::sin(radians);
float c = std::cos(radians);
float zRotation[16] = {
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
GLint modelviewUniform = glGetUniformLocation(m_simpleProgram, "Modelview");
glUniformMatrix4fv(modelviewUniform, 1, 0, &zRotation[0]);
}
It is used right before drawing.
So I experimented and tried this at the same time I rotate:
ApplyOrtho(2*1024/768, 2);
However this has no effect whatsoever, even though the rotation is definitely happening at the same time. My image remains "fat".
Is my interpretation of why the fatness is happening correct?
How to handle the orthographic projection when auto-rotating screen?
UDPATE: Also tried this on iPhone using the 2/3 dimensions of the screen (not iPhone 5) and using ApplyOrtho(2,3) and ApplyOrtho(3,2) but the "fat" triangle in landscape remains.
Also: the viewport is setup just once, before the first Ortho:
glViewport(0, 0, width, height);
Where width and height are the dimensions of the Portrait screen.
The cause of the above discrepancies is that the orthographic projection is not matching the width and height ratio of the screen, thus the X and Y coordinates are not the same screen size. Making the orthographic ratio match the viewport ratio resolves this issue. As a result, when rotating, the image will remain exactly the same shape and size.