How to stretch draw a cairo gdk pixbuf pattern region with an arbitrary opacity? - cairo

How can I stretch draw an area of a gdk pixbuf to a cairo surface with a user defined opacity?
I am trying to write a cross platform interface for working with bitmaps and want to add alpha blending to my cairo stretch draw method. What I have right now works just fine, but I am unable to think up a way of to mold alpha blending into a series of cairo/gdk apis which work somewhat like Microsoft's AlphaBlend function.
What I have so far is this:
procedure TGtkBitmap.Draw(const Source: TRect; Canvas: TCanvas;
const Dest: TRect; Alpha: Byte = $FF);
var
D: PGdkDrawable;
C: Pcairo_t;
M: cairo_matrix_t;
begin
if FBuffer = nil then
Exit;
if (WidthOf(Source) < 1) or (WidthOf(Dest) < 1) then
Exit;
if (HeightOf(Source) < 1) or (HeightOf(Dest) < 1) then
Exit;
D := TGtk2DeviceContext(Canvas.Handle).Drawable;
C := gdk_cairo_create(D);
gdk_cairo_set_source_pixbuf(C, FBuffer, 0, 0);
cairo_matrix_init_identity(#M);
cairo_matrix_translate(#M, Source.Left, Source.Top);
cairo_matrix_scale(#M, WidthOf(Source) / WidthOf(Dest),
HeightOf(Source) / HeightOf(Dest));
cairo_matrix_translate(#M, -Dest.Left, -Dest.Top);
cairo_pattern_set_matrix(cairo_get_source(C), #M);
cairo_rectangle(C, Dest.Left, Dest.Top, WidthOf(Dest), HeightOf(Dest));
// what cairo functions can I combine here to vary
// the opacity of the pattern fill using Alpha argument?
cairo_fill(C);
cairo_destroy(C);
end;
Everything works fine, but I am unsure how to get alpha blending with a pix buff pattern working. I can imagine one way which involves creating a second cairo surface, drawing the entire pixbuf to it with a user defined opacity, then creating pattern for the first surface using the new surface, which all gets a little messy and probably is much slower than something I'd be happy with.
Here is a video recording of what I have working so far. I'd like to know from someone familiar with cairo, what can I insert into my routine above to set the alpha level of the pixbuf source pattern?

Chris Wilson from the cairo mailing lists offered this solution which works perfectly.
Replace the:
cairo_fill(C);
with:
cairo_clip(C);
cairo_paint_with_alpha(C, Alpha / $FF);
Thanks to Chris Wilson from the cairo mailing lists!

Related

Toon shader shadow

I'm currently trying to change my asset style from realistic to low poly / cartoonic.
For example, I have a toon surface shader
half4 LightingRamp(SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot(s.Normal, lightDir);
half diff = NdotL * 0.5 + 0.5;
half3 ramp = tex2D(_LightingTex, float2(diff, 0)).rgb;
half4 c;
c.rgb = _LightColor0.rgb * atten * ramp *_Color;
c.a = s.Alpha;
return c;
}
where _LightingTex is a 2D texture ramp. This works fine for lighting effects on the objects themselfs.
As I have multiple objects with this shader in my scene, some of them are casting a shadow onto my wall.
As you can see, the shadow here is not a ramp but a continuous gradient, as it is (probably) done in some sort of ambient from unity. My question is now: is there an option to create this colorramp effect on the global shadows as well? Something like this:
Can I do it material shader based, or is it a post processing effect?
Thanks
With surface shaders: No, you can't do it in the shader. Actually, I think the best way to get a unified cartoon effect is to use a color grading LUT as a post effect. The great thing about LUTs is that you can create one easily in photoshop by first applying some cool effects to a regular image until it looks the way you want (such as "Posterize"), and then copy the effect stack to apply to a LUT texture, like this one. When you use this LUT in Unity, everything will look as they would with your Photoshop filters applied. One small caveat I've noticed though is that some standard LUT textures need to be flipped vertically to work with the Post Processing Stack. Here is a nice tutorial on how to create posterized LUTs.
If you want to get the toon-like shadows directly in the shader, it is not any harder than making a regular forward rendered vertex/fragment shader, though this by itself requires a bit of knowledge on how these work - i can recommend looking at the standard shader source code, this, or this (somewhat outdated) tutorial. You can find the details surrounding how to add shadow support from my post here. The only thing you need to change is to add a similar color ramp to the shadow mask:
half shadow = SHADOW_ATTENUATION(IN)
shadow = tex2D(_ShadowRamp, float2(shadow, 0));
For this, you can set the shadow ramp as a global shader variable from script, so you won't have to assign it for each material.

Invert text color using glBlendFunc in Cocos2d on CCLabelTTF

I am trying to add a CCLabelTTF to my Cocos2d project and have the text be an inverted version of the graphics behind it.
I am having a hard time figuring out what blend fund to use.
I have to admit I do not really understand the concepts behind this, so I am basically just trying different modes.
I have tried several types:
This one inverts the background of the text, but leaves the text white:
[fontLabel setBlendFunc:(ccBlendFunc){GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA}];
Can you help me in the right direction?
I want the text to be inverted, and the background to be invisible.
You can visually experiment with the various blendfunc methods with the aptly named Visual glBlendFunc tool.
You should also be aware that CCLabelTTF uses 8-Bit (alpha mask, kCCTexture2DPixelFormat_A8) textures on 1st and 2nd generation devices, and 16-Bit (alpha+intensity mask, kCCTexture2DPixelFormat_AI88) textures on 3rd generation and newer devices. This may or may not affect the blend mode results, or even make it impossible because the textures don't contain color information, only alpha.
It can not be done using glBlendFunc. Blending equation looks like this:
result = A * front_color OP B * back_color;
OpenGL allows you to configure A, B - glBlendFunc(A, B);
and OP (operation) - glBlendEquation(OP);
To invert colors, you need
result = 1 - back_color;
You can do that by setting A = 1, B = 1, OP = FUNC_SUBTRACT, but you will have to set front_color to (1,1,1,1) in fragment shader.
P.S. I might be wrong, so write a comment below and I will change my answer.

How do I map a texture to the sides of an icosahedron?

I have been trying to develop a 3D game for a long time now. I went through
this
tutorial and found that I didn't know enough to actually make the game.
I am currently trying trying to add a texture to the icosahedron (in the "Look at Basic Drawing" section) he used in the tutorial, but I cannot get the texture on more than one side. The other sides are completely invisible for no logical reason (they showed up perfectly until I added the texture).
Here are my main questions:
How do I make the texture show up properly without using a million vertices and colors to mimic the results?
How can I move the object based on a variable that I can set in other functions?
Try to think of your icosahedron as a low poly sphere. I suppose Lamarche's icosahedron has it's center at 0,0,0. Look at this tutorial, it is written for directX but it explains the general principle of sphere texture mapping http://www.mvps.org/directx/articles/spheremap.htm. I used it in my project and it works great. You move the 3D object by applying various transformation matrices. You should have something like this
glPushMatrix();
glTranslatef();
draw icosahedron;
glPopMatrix();
Here is my code snippet of how I did texCoords for a semisphere shape, based on the tutorial mentioned above
GLfloat *ellipsoidTexCrds;
Vector3D *ellipsoidNorms;
int numVerts = *numEllipsoidVerticesHandle;
ellipsoidTexCrds = calloc(numVerts * 2, sizeof(GLfloat));
ellipsoidNorms = *ellipsoidNormalsHandle;
for(int i = 0, j = 0; i < numVerts * 2; i+=2, j++)
{
ellipsoidTexCrds[i] = asin(ellipsoidNorms[j].x)/M_PI + 0.5;
ellipsoidTexCrds[i+1] = asin(ellipsoidNorms[j].y)/M_PI + 0.5;
}
I wrote this about a year and a half ago, but I can remember that I calculated my vertex normals as being equal to normalized vertices. That is possible because when you have a spherical shape centered at (0,0,0), then vertices basically describe rays from the center of the sphere. Normalize them, and you got yourself vertex normals.
And by the way if you're planning to use a 3D engine on the iPhone, use Ogre3D, it's really fast.
hope this helps :)

How would I draw something like this in Core Graphics

I want to be able to draw using this as my stroke. How would I do this as efficient as possible, and on the fly drawing, I was thinking CGPatternRef, but I really don't know how to do that.
Edit:
It does not need to warp to the path. I just coultn't fix that issue in Illustrator.
Does the Apple doc help?
See the section in Quartz 2D Programming Guide, How Patterns Work, or Patterns in general.
Here is how to draw a start (from the above docs), PSIZE is the star size:
static void MyDrawStencilStar (void *info, CGContextRef myContext)
{
int k;
double r, theta;
r = 0.8 * PSIZE / 2;
theta = 2 * M_PI * (2.0 / 5.0); // 144 degrees
CGContextTranslateCTM (myContext, PSIZE/2, PSIZE/2);
CGContextMoveToPoint(myContext, 0, r);
for (k = 1; k < 5; k++) {
CGContextAddLineToPoint (myContext,
r * sin(k * theta),
r * cos(k * theta));
}
CGContextClosePath(myContext);
CGContextFillPath(myContext);
}
Just add the curve transformation and at each point draw the star.
Here is a simple C code to calculate points on cubic bezier curve.
You could try importing your Illustrator document into this application: Opacity, and then doing an "Export as source code".
See here: http://likethought.com/opacity/workflow/ for more information.
You will need to walk the path and compute coordinates of the curve at equal distances (along the path). This is inexpensive. Rotation gets a little hairy (rotating about the tangent), but overall, this is a basic bézier curve problem. Simply solve the curve equation and render a star at each vertex.
There's nothing built-in that will do it all. You can query points for intersection, but only rendering solves the curve. This is encapsulated by CoreGraphics, so you can't pull it out or take advantage of what they already have.
This is something you'll should consider writing yourself. It's not difficult; honest. Only a basic understanding of calculus is required... if at all. If you write it yourself, you can even add in the warping effects, if you like.
This looks like a job for OpenGL. CoreGraphics doesn't offer any simple way that I know of to warp the stars according to their proximity to a path.

iPhone clear CGContext

I create a circle with a nice shadow with this code (I use MonoTouch.net for iPhone, Objective-C answers are fine of course)
UIGraphics.PushContext (ctx);
SizeF shadowSize = new SizeF (0f, -3f);
ctx.SetRGBFillColor (194f / 255f, 212f / 255f, 238f / 255f, 1f);
ctx.SetAllowsAntialiasing (true);
ctx.SetShadowWithColor (shadowSize, 20, new CGColor (0.9f, 0.7f));
RectangleF area = new RectangleF (35f, 15f, 210f, 210f);
ctx.FillEllipseInRect (area);
UIGraphics.PopContext ();
Then I want to add to it an arc and lines. When I do, the colors and shadow etc seem to stick around? How do I 'start fresh' while drawing my UIView ? (It's all in the same UIView; I am building up the image)
If you mean to clear everything that's drawn so you have a blank canvas, try CGContextClearRect before drawing anything.
But I think you mean that you want the shadow, fill color, etc. to only apply to that ellipse and not to the things that you draw afterward. To do that, you want to call the same state-setting methods again, but with different arguments. For instance, CGContextSetShadowWithColor expects a shadow color. But if you pass NULL for that argument, it will disable shadowing.
See also the CGContextSetShadow documentation, which has a note about all the ways you can disable shadowing. Pick the best one for you.
I think your main problem is that you're not taking advantage of Apple's excellent documentation. I gather that MonoTouch.net essentially maps Objective-C APIs to .NET modules with similar or identical symbol names. So with a quick Google search, you should be able to find the corresponding documentation in the iPhone OS Reference Library.
Before we begin drawing, save the state:
CGContextSaveGState(ctx);
Then after we are finished, return the state to what it was at the beginning:
CGContextRestoreGState(ctx);