What do the blend modes in pygame mean? - pygame

Surface.blit has a new parameter in 1.8: blend. The following values are defined:
BLEND_ADD
BLEND_SUB
BLEND_MULT
BLEND_MIN
BLEND_MAX
BLEND_RGBA_ADD
BLEND_RGBA_SUB
BLEND_RGBA_MULT
BLEND_RGBA_MIN
BLEND_RGBA_MAX
BLEND_RGB_ADD
BLEND_RGB_SUB
BLEND_RGB_MULT
BLEND_RGB_MIN
BLEND_RGB_MAX
Can someone explain what these modes mean?

You can find the source for the blend operations here: surface.h
Basically, ADD adds the two source pixels and clips the result at 255. SUB subtracts the two pixels and clips at 0.
MULT: result = (p1 * p2) / 256
MIN: Select the lower value of each channel (not the whole pixel), so if pixel1 is (100,10,0) and pixel2 is (0,10,100), you get (0,10,0)
MAX: Opposite of MIN (i.e. (100,10,100))
And there is an additional blend mode which isn't obvious from the docs: 0 (or just leave the parameter out). This mode will "stamp" source surface into the destination. If the source surface has an alpha channel, this will be determine how "strong" each pixel is (0=no effect, 255=copy pixel, 128: result = .5*source + .5*destination).
Useful effects: To darken a certain area, use blend mode 0, fill the source/stamp surface black and set alpha to 10: (0,0,0,10).
To lighten it, use white (255,255,255,10).

Those are blending modes for compositing images on top of each other. The name of the blending mode already tells you the underlying operation.
The BLEND_* constants are simply aliases for the BLEND_RGB_* constants and the BLEND_RGBA_* variants operate on all four channels (including the alpha channel) as opposed to only RGB.
For general information about the different blending modes and their respective effects, see here.

Related

Html Canvas Clip - Speed issues

I split my canvas into two. I need to draw on each side, defining a clipping region for both. Each side has to do similar things, like drawing text in colours, drawing circles etc.
I have read that you should keep your fillStyle and strokeStyle changes to a minimum. However I have also read you must keep your save and restores to a minimum as well.
So what is faster?
Save the canvas, clip the left hand side, do ALL the drawing for that side for the multiple colours, then restore and repeat for the right hand side?
Or ... Set the first text colour. Clip the left hand side. Draw all text for this colour. Then clip the right hand side (without restting fillStyle) and draw all the same colour text for the right hand side. Then set the next fillStyle and then clip each side and draw text for this colour? Etc
Anyone know?
Also if I set one clip region, then set another clip region without saving and restoring, what actually happens?
As always, you must performance test with your own project's code.
The context maintains internal variables relating to its current state (colors, transforms, current path, compositing applied, etc).
You can save a copy of the current context state using context.save. Then after altering the context state, you can restore the original context state with context.restore. Note: you can nest multiple save/restore if needed.
fillStyle is a context state so changing fillStyle='green' followed later by fillStyle='blue' is faster than save/restore because just 1 state variable is being reset rather than every state variable that's done during save/restore.
The point is that you often gain performance by saving+resetting individual state values rather than doing a full context.save/context.restore.
Minimizing state changes will maximize performance, so for example, batching all green drawings will help performance.
Clipping is a complex operation and is more expensive than simple state changes like changing fillStyle. With GPU acceleration the clipping is accomplished much more efficiently and is therefore considerably less costly than clipping without a GPU.
About changing clipping regions: Clipping is always done only on the last path defined. So setting another clipping region will undo the previous clipping region (unless the previous and current path are identical).
About left and right clipping regions: If your design permits, you might want to define both the left and right clipping regions at once into 1 combined clipping region. Since paths can be disconnected, defining 1 clipping path with 2 non-intersecting parts is allowed.
As the car companies warn: "Your mileage may vary". But you might perf test this method:
Define your left and right clipping regions in 1 clipping path
Set fillStyle="red" and do all your red drawings at once (both right and left)
Reset fillStyle="blue" and do all your blue drawings at once, etc, etc.
One final thought: All projects have their own distinct requirements so you must perf test your actual code rather than relying exclusively on general rules. Don't skip the perf tests--especially if you will be deploying on mobile where canvas is slow by nature.
Good luck with your project!
[ Additional note about clipping ]
A clipping region is semi-permanent. Once it is set it remains even if the context.clip command is issued again. The new clip command will further restrict all previous clipping regions.
To clear a clipping path you must wrap your clips inside context.save & context.restore(). Alternatively, resizing the canvas will force the context state to be restored to defaults--but resizing will also clear all canvas content: canvas.width=canvas.width
Here's and example of a single path consisting of a left and right square:
// left square
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(150,50);
ctx.lineTo(150,150);
ctx.lineTo(50,150);
ctx.closePath();
// right square
ctx.moveTo(200,50);
ctx.lineTo(300,50);
ctx.lineTo(300,150);
ctx.lineTo(200,150);
ctx.closePath();
ctx.strokeStyle="red";
ctx.stroke();
Create a clipping region from this left+right path.
// create a clipping region from the left+right path
ctx.clip();
Fill the entire canvas with green. The green will only be drawn inside the clipping region (inside the left and right squares).
// draw a green rect over the entire canvas
// the green will only be drawn inside the clipping region
ctx.fillStyle="green";
ctx.fillRect(0,0,canvas.width,canvas.height);
If you add a second clipping region, the result is that drawing will only be visible in the union of all clipping paths.
So if the second clipping region slightly overlaps the first, all drawings will only be visible inside the union of the first and second clipping regions. The blue section in the following illustration is the union of the 2 clipping paths.
ctx.beginPath();
ctx.moveTo(0,115);
ctx.lineTo(canvas.width,115);
ctx.lineTo(canvas.width,135);
ctx.lineTo(0,135);
ctx.clip();
ctx.closePath();
ctx.fillStyle="blue";
ctx.fillRect(0,0,canvas.width,canvas.height);
A few ideas :
To handle your two screens, you might use two canvases side by side.
Even if you keep only one canvas, you can reduce the use of clipping by doing :
- erase left half of screen
- draw left part
- erase right part
- clip on right half
- draw right part
Thus you clip only once.
For your color vs clip concern, clipping is much costly than changing color.
And if one keeps on clipping with no save/restore, clipping zones will add-up.
For your strokeStyle/fillStyle, yes there's a cost, especially if using color names ('blue'), or rgb 'rgb()' strings or worse 'hsl()' strings.
So here's a trick : pre-compute and store the colors whenever you can. Simply use the context to convert !
var blue = 'hsl(23, 75%, 75%)';
context.fillStyle = blue ;
blue = context.fillStyle ;

drawing a line: is there exists a limits of thickness in Graphics.lineStyle()?

I'm developing a simple a graphical editor for my flash-based app. In my editor there's a posibility of scaling, range of scaling is big (maximum scale is 16.0, minimum scale is 0.001 and default scale is 0.2). So it's quite possible that a user can draw a line with thickness 0.1 or 300.0, and it looks that line possible thickness (in Graphics.lineStyle()) has upper border. As I found out from livedocs maximum value is 255. So if thickness is greater then 255.0 there'is drawn a line of thickness 255.0. Whether mentioned upper border exists and how big is it. Here're my questions:
Right now I'm drawing lines with drawPath() or lineTo() methods. Natural walkarround if thickness is greater then 255.0 is to draw a rectange instead of segment and two circles on the ends of segment (instead of lineTo()). Or even to draw two thin segments and two half-circles and fill interior. Maybe there's more elegant/quick solution?
Another question is if the thickness of line is big but less then 255.0 (e.g. 100.0), what is faster drawing a line with lineTo() or drawing two thin segments and two half-circles and fill interior?
And finally, maybe someone knows a good article/book where I can read what's inside all methods of flash.display.Graphics class (or even not flash specific article/book on graphics)?
Any thoughts are appreciated. Thank you in advance!
I agree with f-a that putting the line in a container would probably be better and more efficient than drawing a rectangle and extra circles.
I don't think that the math would be too difficult to work out. For efficiency you should probably only do this if the line style is going to be over 255.
To setup the display object to hold your line I would start by halving the width of your line (the length can stay the same). Then create a new sprite and draw the line in the sprite at half size (e.g. if you wanted 300, just draw it at 150). It would be most simple to just start at (0,0) and draw the segment straight so that all of your transformations can be applied to the new sprite.
From here you can just double the scaleY of the sprite to get the desired line weight. It should keep the same length and the ends should also be rounded correctly.
Hope this helped out!
A cool resource for working with the graphics class is Flash and Math. This site has several cool effects and working examples and source code.
http://www.flashandmath.com/

Blending with HTML background in WebGL

I am drawing flat colors and textures into WebGL canvas. My colors and textures have varying alpha values and I want them to be blended correctly. I want to have transparent background (they should be blended with HTML content, which is under canvas).
In WebGL, I use
gl.clearColor(0, 0, 0, 0);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);
It works correctly, when HTML background is black. But when I set a JPG pattern as a background of , I draw black triangle (alpha=1) and white triangle (alpha=0.5), I can see the background pattern in place where triangles intersect each other. Is this correct behavior?
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) means that the resulting alpha is
A_final = A_s * A_s + (1 - A_s) * A_d
In your example, after the black triangle (with alpha=1) is drawn, a drawn pixel in the framebuffer will have an alpha of
1 * 1 + (1 - 1) * 0 == 1 + 0 == 1
So it will be fully opaque. Next, after the white triangle (with alpha=.5) is drawn, a pixel in the intersection of the two triangles will have an alpha of
.5 * .5 + (1 - .5) * 1 == .25 + .5 == .75
That means the final color will be treated as partially transparent, and, when it is composited with the page, the page background will show through.
This is a somewhat uncommon problem in regular OpenGL, since content is usually composited against an empty background. It does come up when you draw to an FBO and have to composite the results with other content in your context, though. There are a few ways to deal with this.
One way is to have your alpha blend with gl.ONE, gl.ONE_MINUS_SRC_ALPHA so you get
A_final = A_s + (1 - A_s) * A_d
which is what you usually want with alpha blending. However, you want your colors to still blend with gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA. You can use gl.blendFuncSeparate instead of gl.blendFunc to set your color blending and alpha blending functions separately. In this case, you would call
gl.BlendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
Another option is to take advantage of colors with premultiplied alpha (which WebGL actually already assumes you are using, for instance, when sampling a color from a texture). If you draw the second triangle with the alpha already multiplied through the color (so a half transparent white triangle would have gl_FragColor set to vec4(.5, .5, .5, .5)), then you can use the blend mode
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
and it will act as you want for both color and alpha.
The second option is what you'll commonly see in WebGL examples, since (as mentioned), WebGL already assumes your colors are premultiplied (so vec4(1., 1., 1., .5) is out of gamut, the rendering output is undefined, and the driver/GPU can output any crazy color it wants). It's far more common to see gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) in regular OpenGL examples, which leads to some confusion.

Finding close colors of a given color

I´d like to know, how, through actionscript 3, to get an array of ARGB (hexadecimal) colors, that is close to a given color.
Example:
0xFF00FF00
A green.
How to get variations of green?
I´m trying to get some green colors of a bitmapdata.
I´ve tried to get it by making a loop getting the colors using getPixels32.
The problem is, I think the bits colors of each position are different from the bits of the bitmap rendered.
It´s for a pathfinder.
Each green bit sets a node in a map, as walkable.
So I need to know what are these colors to set it as walkable for the pathfinder.
Any suggestions?
RGB space is terrible for interpreting whether colors are similar to one another. A different color space that matches closer to human perception of color is HSV (hue saturation and value). Here are the steps you should follow:
Convert your value from RGB space to HSV (http://www.cs.rit.edu/~ncs/color/t_convert.html)
Modify the saturation and value to obtain different shades of the same green hue.
You can even modify the hue a little with a defined tolerance level you specify
Reconvert back to HSV to RGB
I believe technically..one color space is smaller than the other, meaning it is not always a 1:1 conversion - but it should serve your purpose.

Random Non-White Colors That Look Okay As Background for Black Text

I'd like to generate random, non-white colors using hue, saturation and brightness that can be used as a background for black text. I've created a generator for random colors, but when I scan the numbers, I can't see any clear pattern in the colors that look too dark.
How can I generate random non-white background colors for black text? Feel free to answer with code or pseudo-code, but it's definitely not necessary.
Only generate colors with high brightness values - for example, if you were using the range 0-255 for each of {H,S,V}, you'd generate H in [0,255], S in [0,255], V in [168,255]. That should give you colors that are bright enough. You may want to restrict saturation as well (e.g. S in [0,192]), since black on full-bright, full-saturation colors may not be very readable.
You'll probably need to play with the values to get ranges that will give you usable colors.
I don't know color theory, but you can try randomly generating the 3 components in RGB (xxx,xxx,xxx) in a way that the sum of the components is greater than X (X depends of the contrast you want), and the convert to HSB.
HSV and HSL are broken models than have nothing to do with perception. You should generate your colors in YUV space (also known as YCbCr) where the intensity (Y) channel is not simply R+G+B but rather models the perceptual intensities of red, green, and blue. A good starting point would be to try random Y values at least 200 and random U and V values between -50 and 50.