c# Non-Linear gradient brushes? - c#

Is there a method I can use to generate non-linear Gradient brushes in c#?
To clarify: Im not looking for a gradient that can be applied to a non-linear path. Rather, I am looking for a gradient between 2 colours that fades between the two in a non-linear fashion i.e. the rate of changs is quicker at the start of the gradient and slows down as the brush nears the finishing point.
Is this even remotly possible in c# using gdi+?

Yep, set the blend for the Brush.
LinearGradientBrush blendBrush = new LinearGradientBrush(Rectangle, Color.Red, Color.White, 360f);
Blend blend = new Blend();
blend .Factors = new float[] { 1.0f, 0.9f, 0.8f, 0.7f, 0.6f, 0.5f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f };
blend .Positions = new float[] { 0, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f };
blendBrush.Blend = blend ;
This example will start fading out, then go back to the previous colour. So a kinda fill from centre effect.

Use the Blend property of LinearGradientBrush -
http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.blend(VS.80).aspx

Related

How do I stop a texture from darkening after drawing a colored quad in C# OpenTK?

I am creating my own game graphics engine. I have looked into using others like Unity, but they don't fit my needs. Anyway, I am using OpenTK (This is a 2D game), and the issue is that when i draw a texture to the screen, then draw a quad to the screen, the color darkens on the texture. Here is the method I am using to draw a texture:
public void Texture(int ID, Vector2 size, Vector2 pos, Vector2 texSize, Vector2 texPos)
{
pos.Y = -pos.Y;
GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, ID);
GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(texPos.X, texPos.Y);
GL.Vertex2(pos.X, pos.Y);
GL.TexCoord2(texPos.X + texSize.X, texPos.Y);
GL.Vertex2(pos.X + size.X, pos.Y);
GL.TexCoord2(texPos.X + texSize.X, texPos.Y + texSize.Y);
GL.Vertex2(pos.X + size.X, pos.Y - size.Y);
GL.TexCoord2(texPos.X, texPos.Y + texSize.Y);
GL.Vertex2(pos.X, pos.Y - size.Y);
GL.End();
}
I am inverting the Y because I am used to the Windows Forms coordinate system, where going down is y++. I am calling it like this:
Texture(backdropTextureID, new Vector2(1f, 1f), new Vector2(-0.5f, -0.5f), new Vector2(1f, 1f), new Vector2(0f, 0f));
As expected, if there is nothing else being drawn, it draws a texture with the GL id of backdropTextureID in the center of the screen. When I draw a colored quad also though, the texture is darkened. Here is the method I am using for drawing a quad:
public void Quad(Vector2 pos1, Vector2 pos2, Vector2 pos3, Vector2 pos4, Color color1, Color color2, Color color3, Color color4)
{
GL.Disable(EnableCap.Texture2D);
pos1.Y = -pos1.Y;
pos2.Y = -pos2.Y;
pos3.Y = -pos3.Y;
pos4.Y = -pos4.Y;
GL.Begin(PrimitiveType.Quads);
GL.Color3(color1);
GL.Vertex2(pos1);
GL.Color3(color2);
GL.Vertex2(pos2);
GL.Color3(color3);
GL.Vertex2(pos3);
GL.Color3(color4);
GL.Vertex2(pos4);
GL.End();
}
Again, inverting the Y, for the reason stated above. Also, notice, I am enabling EnableCap.Texture2D in the method for drawing a texture, and disabling it when I draw a colored quad. I am calling the quad method like this:
Quad(new Vector2(0.0f, 0.0f), new Vector2(0.5f, 0.0f), new Vector2(0.5f, 0.5f), new Vector2(0.0f, 0.5f), Color.Gray, Color.Gray, Color.Gray, Color.Gray);
If anyone could help me, thank you in advance. Basically: How do I stop a texture from darkening after drawing a colored quad in C# OpenTK?
For anyone whose having this problem, I figured it out. The same color I was giving to the colored quad i gave to the texture. You just need to add
GL.Color3(Color.Transparent);
to the start of the texture drawing method.

SharpDX Bitmaps

I've been looking around the internet for a while, and I can't seem to find the answer I've been looking for. So what I intend to do with bitmaps is I want to draw them onto the window, and be able properly resize them whenever. Any help would be appreciated!
For those of you who do not know, you can use matrices to translate, resize, and rotate. Here's how to do it. Also be sure to change the Matrix for the RenderTarget before you draw the actual object.
Vector2
RenderTarget.Transform
RenderTarget.DrawBitmap
Matrix.Transformation2D
Vector2 center = new Vector2(bitmap.Size.Width / 2, bitmap.Size.Height / 2);
renderTarget.Transform = Matrix.Transformation2D(center, 0f, new Vector2(width / bitmap.Size.Width, height / bitmap.Size.Height), center, MathHelper.ToRads(rotation), new Vector2(x - center.X, y - center.Y));
renderTarget.DrawBitmap(bitmap, 1f, BitmapInterpolationMode.NearestNeighbor);
renderTarget.Transform = Matrix.Transformation2D(Vector2.Zero, 0f, new Vector2(1f, 1f), Vector2.Zero, MathHelper.ToRads(0), Vector2.Zero);

Drawing upscaled image with no smoothing

I want to draw a texture2d 5 times larger than original with no smoothing.
Drawing line:
spriteBatch.Draw(texture, new Vector2(0, 0), null, Color.White, 0, Vector2.Zero,
5f, SpriteEffects.None, 0);
The result is a scaled smoothed image. Adding this.GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp; doesn't help.
What you want is Point Texture filtering. Look here.

How can I create a drop shadow effect on my textures in XNA for Windows Phone?

I'm writing a simple 2D game for Windows Phone 7 using the XNA Framework.
Basically there are multiple items that the user can drag. I create their texture dynamically by drawing stuff on a RenderTarget2D and then just draw the RenderTarget2D afterwards. I use the stencil buffer to draw a part of a bigger texture onto the render target.
Code snippet
util.GraphicsDevice.SetRenderTarget(result);
util.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.Stencil | ClearOptions.DepthBuffer, Color.Transparent, 0, 0);
// The "mask"
spriteBatch.Begin(SpriteSortMode.Deferred, util.DontWriteColorsState, null, util.StencilAlways, null, alphaTestEffect);
spriteBatch.Draw(maskTexture, destination, Color.White);
spriteBatch.End();
// The actual texture
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, util.StencilKeepWhere1, null, alphaTestEffect);
spriteBatch.Draw(bigTexture, destination, source, Color.White);
spriteBatch.End();
util.GraphicsDevice.SetRenderTarget(null);
(util is just an instance of a helper class which I use in order to not have to copy-paste the same code everywhere, it contains the DepthStencilState objects and some other stuff.)
I would like to create a drop shadow effect behind these textures. I'd like to draw the shadow on the render target.
Unfortunately Windows Phone 7 doesn't support custom shader effects so I can't use any examples from the internet. So I decided to try to implement it in software. But I'm completely inexperienced with this kind of thing, so the result was both slow and ugly.
What I did in software was this:
Created a stroke around the mask texture and drew it with a low opacity
Created a stroke around the previous stroke and drew it with a low opacity
... This step was repeated the same number of times as the size of the drop shadow
However, it was VERY slow and basically unacceptably slow.
So the question is
Is it possible to create a dropshadow or a dropshadow-ish effect using the built-in effects in XNA? Also, if not, is there an algorithm that can create a nice-looking drop shadow in software?
Thanks in advance for your answers! :)
EDIT:
I'm taking about this kind of drop shadow:
Obviously, this is just an illustration, I don't want it to be exactly this size. :)
I took the liberty of adjusting your solution, #Venemo, and here is what I've come up with as a good start:
public Texture2D CreateBlurredTexture(Texture2D originalTexture, SpriteEffects effects)
{
var device = originalTexture.GraphicsDevice;
var rt = new RenderTarget2D(device, originalTexture.Width/2, originalTexture.Height/2);
var rt2 = new RenderTarget2D(device, originalTexture.Width, originalTexture.Height);
Color shadowColor = Color.Lerp(Color.Black, Color.Transparent, 0.9f);
using (var spriteBatch = new SpriteBatch(device))
{
device.SetRenderTarget(rt);
device.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(originalTexture, new Rectangle(0, 0, rt.Width, rt.Height), null, shadowColor, 0, Vector2.Zero, effects, 0f);
spriteBatch.Draw(originalTexture, new Rectangle(1, 1, rt.Width - 2, rt.Height - 2), null, shadowColor, 0, Vector2.Zero, effects, 0f);
spriteBatch.Draw(originalTexture, new Rectangle(2, 2, rt.Width - 4, rt.Height - 4), null, shadowColor, 0, Vector2.Zero, effects, 0f);
spriteBatch.Draw(originalTexture, new Rectangle(3, 3, rt.Width - 6, rt.Height - 6), null, shadowColor, 0, Vector2.Zero, effects, 0f);
spriteBatch.Draw(originalTexture, new Rectangle(4, 4, rt.Width - 8, rt.Height - 8), null, shadowColor, 0, Vector2.Zero, effects, 0f);
spriteBatch.End();
device.SetRenderTarget(rt2);
device.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(rt, new Rectangle(0, 0, rt2.Width, rt2.Height), Color.White);
spriteBatch.End();
device.SetRenderTarget(null);
}
return rt2;
}
What it does is creates copies of the texture and adds opacity with each draw, while going towards the center. After this is done, you can offset it and increase its size to create a bigger shadow effect. This should accomplish the task depending on your texture.
To draw a shadow draw the original render target in pure black, maybe with some transparency, offset slightly from the original position.
Next just draw again, as you were before to render the texture over the shadow.
Regarding your edit, create a texture for an edge and a texture for a corner, then draw the drop shadow as 4 edges and 4 corners.
This is what I came up with, eventually.
It is a bit hacky, of course but it sort of does what I needed when I asked the question.
public static Texture2D CreateBlurredTexture(Texture2D originalTexture, SpriteEffects effects)
{
var device = originalTexture.GraphicsDevice;
var rt4 = new RenderTarget2D(device, originalTexture.Width / 4, originalTexture.Height / 4);
using (var rt2 = new RenderTarget2D(device, originalTexture.Width * 3 / 2, originalTexture.Height * 3 / 2))
using (var rt3 = new RenderTarget2D(device, originalTexture.Width / 2, originalTexture.Height / 2))
using (var spriteBatch = new SpriteBatch(device))
{
device.SetRenderTarget(rt2);
device.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(originalTexture, new Rectangle(0, 0, rt2.Width, rt2.Height), null, Color.White, 0, Vector2.Zero, effects, 0f);
spriteBatch.End();
device.SetRenderTarget(rt3);
device.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(rt2, new Rectangle(0, 0, rt3.Width, rt3.Height), Color.White);
spriteBatch.End();
device.SetRenderTarget(rt4);
device.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(rt3, new Rectangle(0, 0, rt4.Width, rt4.Height), Color.White);
spriteBatch.End();
device.SetRenderTarget(null);
}
return rt4;
}

Managed DirectX: Specifying the Depth (Z-Order) of Sprites containing Texture and Text

I am using managed DirectX to try and draw a texture and a piece of text to the screen using a Sprite. Unfortunately, if I place the text and the texture in the same sprite, the texture overwrites (overdraws?) the text regardless of the order I do the draw commands.
Since I will eventually want to intersperse textures and text, how do I specify a Z-order for these sprites. Does each layer have to be in a separate sprite?
Here is the current code:
m_device.BeginScene();
m_device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);
m_sprite.Begin(SpriteFlags.SortTexture | SpriteFlags.AlphaBlend);
// Switching the order of following two statements doesn't change the Z-Order!
m_sprite.Draw(m_texture, Vector3.Empty, new Vector3(0, 0, 0),
Color.White.ToArgb());
m_d3dFont.DrawText(m_sprite, m_text, x, y, color);
m_sprite.End();
m_device.EndScene();
m_device.Present();
Note: Using the SpriteFlags.SortDepthBackToFront or SpriteFlags.SortDepthBackToFront does not change the behaviour.
This is probably a conceptual misunderstanding on my part, but if code is useful, I'll gratefully accept samples in unmanaged DirectX using C++ or whatever language.
Many thanks in advance!
If you want to change the Z-Order of rendering then you have to set the Z value in the Draw command. If you set the all to 0 you will get all sorts of weirdness. Your bigger issue is that DrawText doesn't allow you to set a Z-Depth which is all kinds of rubbish.
Thus your only chance is to use ID3DXSprite::SetTransform. You need to shift only the Z-Coordinate back with it for the relevant z ordering position. So you can set your transforms (assuming you are using identity world matrices) as follows (C++ example)
D3DXMATRIX mat( 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, zOrder, 1.0f );
m_Sprite->SetTransform( &mat );
You then carry on passing a position of (0, 0, 0) for rendering and text will also gain the correct depth for z-ordering.
Hope that helps.
Here is the answer I (the poster) went with:
Goz provided most of the information needed to solve the problem. Essentially, for textures, you can specify the z-order using the third parameter of the second Verctor3. Experimentation has made it clear that (1) z order goes from 0.0 to 1.0, with 0.0 being closest and 1.0 being the the furthest away. Anything out of that range doesn't appear at all.
For text, because there's no opportunity to specify the z in the call, you need to use Goz's suggestion of a transform matrix.
In the end, here's roughly the code I used.
m_device.BeginScene();
m_device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);
m_sprite.Begin(SpriteFlags.SortDepthFrontToBack | SpriteFlags.SortTexture | SpriteFlags.AlphaBlend);
// The "1.0f" is the z-order of texture1. This places it at the very back.
m_sprite.Draw(m_texture1, Vector3.Empty, new Vector3(0, 0, 1.0f),
Color.White.ToArgb());
// The text1 is placed at z-order 0.8f, in order to place it in front of texture1
Microsoft.DirectX.Matrix t = Microsoft.DirectX.Matrix.Identity;
t.Translate(new Vector3(0, 0, 0.8f));
m_sprite.Transform = t;
m_d3dFont.DrawText(m_sprite, m_text1, 200, 200, color1);
m_sprite.Transform = Microsoft.DirectX.Matrix.Identity;
// The "0.6f" is the z-order of texture2. This places it at the very back.
m_sprite.Draw(m_texture2, Vector3.Empty, new Vector3(220, 220, 0.6f),
Color.White.ToArgb());
// The text2 is placed at z-order 0.4f, in order to place it in front of texture2
t = Microsoft.DirectX.Matrix.Identity;
t.Translate(new Vector3(0, 0, 0.4f));
m_sprite.Transform = t;
m_d3dFont.DrawText(m_sprite, m_text2, 240, 240, color2);
m_sprite.Transform = Microsoft.DirectX.Matrix.Identity;
m_sprite.End();
m_device.EndScene();
m_device.Present();

Categories