Draw texture using D3D9 - c#

i want to draw bitmap using D3D9.. I got code here and it works out. It does draw me box and image, but when i draw only box i got fps around 60. When i uncomment that code for drawing bitmap i got fps between 5-30 and it's very lagging. What's wrong with my code ?
private void D3D9Render()
{
do
{
Drawing.Device.Clear(D3D9.ClearFlags.Target, Color.FromArgb(0, 0, 0, 0), 1.0f, 0);
Drawing.Device.BeginScene();
Drawing.DrawText("Fps : " + Fps.CalculateFrameRate().ToString(), Drawing.Width - 72, 220, Color.White);
Drawing.DrawBox(v.X, v.Y, 90, 7);
/*
Drawing.DrawTexture(new Bitmap("test.jpg"));
Drawing.Sprite.Begin(D3D9.SpriteFlags.None);
Drawing.Sprite.Draw(Drawing.Texture, Drawing.TextureSize,
new Vector3(0, 0, 0),
new Vector3(v.X-65, v.Y-55, v.Z), Color.White);
Drawing.Sprite.End();
*/
Drawing.Device.EndScene();
Drawing.Device.Present();
} while (true);
}
public static void DrawTexture(Bitmap image)
{
Texture = new Texture(Device, image, Usage.None, Pool.Managed);
using (Surface surface = Texture.GetSurfaceLevel(0))
{
SurfaceDescription surfaceDescription = surface.Description;
TextureSize = new Rectangle(0, 0,
surfaceDescription.Width,
surfaceDescription.Height);
}
}

Have you tried allocating your bitmap outside of your render loop? Depending on the size of the bitmap, it could really slow things down. You're allocating and re-allocating space for that bitmap each iteration of the loop.
Move its allocation outside of the loop and then render it (that one allocation) in your render loop.

Related

Picturebox slider control transparency

I've a PictureBox in my form and load a image in it.
I need this PictureBox to change the transparency (opacity, visibilit..etc), because I need the user to see the image behind this PictureBox better, so when he wants, he just drag the control slider and the image starts to turn invisible, step by step, until he finds its ok, lets say 50% transparency.
I added the control slider but, cant find the way to do the rest. I tried the pictureBox.Opacity, pictureBox.Transparency, nothing works.
In winforms you will have to modify the alpha of the PictureBox.Image.
To do that in a fast way use a ColorMatrix!
Here is an example:
The trackbar code:
Image original = null;
private void trackBar1_Scroll(object sender, EventArgs e)
{
if (original == null) original = (Bitmap) pictureBox1.Image.Clone();
pictureBox1.BackColor = Color.Transparent;
pictureBox1.Image = SetAlpha((Bitmap)original, trackBar1.Value);
}
To use a ColorMatrix we need this using clause:
using System.Drawing.Imaging;
Now for the SetAlpha function; note that it is basically a clone from the MS link..:
static Bitmap SetAlpha(Bitmap bmpIn, int alpha)
{
Bitmap bmpOut = new Bitmap(bmpIn.Width, bmpIn.Height);
float a = alpha / 255f;
Rectangle r = new Rectangle(0, 0, bmpIn.Width, bmpIn.Height);
float[][] matrixItems = {
new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, a, 0},
new float[] {0, 0, 0, 0, 1}};
ColorMatrix colorMatrix = new ColorMatrix(matrixItems);
ImageAttributes imageAtt = new ImageAttributes();
imageAtt.SetColorMatrix( colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
using (Graphics g = Graphics.FromImage(bmpOut))
g.DrawImage(bmpIn, r, r.X, r.Y, r.Width, r.Height, GraphicsUnit.Pixel, imageAtt);
return bmpOut;
}
Note the the ColorMatrix expects its elements to be be scaling factors with 1 being the identity. The TrackBar.Value goes from 0-255, just like a Bitmap alpha channel..
Also note that the function creates a new Bitmap, which may lead to GDI leaking. Here the PictureBox takes care of it, it seems; at least testing it with the taskmanger ('Details' - turn on GDI-objects column!) shows no problems :-)
Final note: This will work if and only if the PictureBox is nested in the control 'behind' it! If it merely overlaps this will not work!! In my example it sits on a TabPage, which is a Container and anything you drop on it gets nested inside. It would work the same if I had dropped it onto a Panel. But PictureBoxes are no containers. So if you want another PictureBox to show up behind it, then you need code to create the nesting: pboxTop.Parent = pBoxBackground; pboxTop.Location = Point.Empty;

MonoGame: stencil buffer not working

I'm trying to add shadows to my MonoGame-based 2D game. At first I just rendered semitransparent black textures to the frame, but they sometimes overlap and it looks nasty:
I tried to render all shadows into the stencil buffer first, and then use a single semitransparent texture to draw all shadows at once using the stencil buffer. However, it doesn't work as expected:
The two problems are:
The shadows are rendered into the scene
The stencil buffer is seemingly unaffected: the semitransparent black texture covers the entire screen
Here's the initialization code:
StencilCreator = new DepthStencilState
{
StencilEnable = true,
StencilFunction = CompareFunction.Always,
StencilPass = StencilOperation.Replace,
ReferenceStencil = 1
};
StencilRenderer = new DepthStencilState
{
StencilEnable = true,
StencilFunction = CompareFunction.Equal,
ReferenceStencil = 1,
StencilPass = StencilOperation.Keep
};
var projection = Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
var halfPixel = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
AlphaEffect = new AlphaTestEffect(GraphicsDevice)
{
DiffuseColor = Color.White.ToVector3(),
AlphaFunction = CompareFunction.Greater,
ReferenceAlpha = 0,
World = Matrix.Identity,
View = Matrix.Identity,
Projection = halfPixel * projection
};
MaskingTexture = new Texture2D(GameEngine.GraphicsDevice, 1, 1);
MaskingTexture.SetData(new[] { new Color(0f, 0f, 0f, 0.3f) });
ShadowTexture = ResourceCache.Get<Texture2D>("Skins/Common/wall-shadow");
And the following code is the body of my Draw method:
// create stencil
GraphicsDevice.Clear(ClearOptions.Stencil, Color.Black, 0f, 0);
var batch = new SpriteBatch(GraphicsDevice);
batch.Begin(SpriteSortMode.Immediate, null, null, StencilCreator, null, AlphaEffect);
foreach (Vector2 loc in ShadowLocations)
{
newBatch.Draw(
ShadowTexture,
loc,
null,
Color.White,
0f,
Vector2.Zero,
2f,
SpriteEffects.None,
0f
);
}
batch.End();
// render shadow texture through stencil
batch.Begin(SpriteSortMode.Immediate, null, null, StencilRenderer, null);
batch.Draw(MaskingTexture, GraphicsDevice.Viewport.Bounds, Color.White);
batch.End();
What could possibly be the problem? The same code worked fine in my XNA project.
I worked around the issue by using a RenderTarget2D instead of the stencil buffer. Drawing solid black shadows to a RT2D and then drawing the RT2D itself into the scene with a semitransparent color does the trick and is much simplier to implement.

Problem in tiling image starting at different height using TextureBrush in C#

I am trying to tile an image(16x16) over a Rectangle area of dimensions width=1000, height=16 using TextureBrush to get a strip like UI.
Rectangle myIconDrawingRectangle = new Rectangle(x, y, 1000, 16);
using (TextureBrush brush = new TextureBrush(myIcon, WrapMode.Tile))
{
e.Graphics.FillRectangle(brush, myIconDrawingRectangle );
}
When I draw with x=0, y=0 tiling happens as expected starting from (0,0).
When I draw with x=0, y=50 tiling starts at (0,50) but the the painting rectangle does not start with the start of the image. It starts with cropped portion of the image and then repeats.
How to solve this?
P.S: I do not want to tile it manually looping repeatedly over DrawImage.
To ensure that start of the rectangle starts with start of the image we have use transforms as shown in below code.
Rectangle myIconDrawingRectangle = new Rectangle(x, y, 1000, 16);
using (TextureBrush brush = new TextureBrush(myIcon, WrapMode.Tile))
{
brush.TranslateTransform(x,y);
e.Graphics.FillRectangle(brush, myIconDrawingRectangle);
}
I found this link helpful. This explains about brushes and transforms in detail.
I tried this in a Windows Forms application, and it works as expected, drawing at (0, 14) when y == 14. Is it possible y is being set to 16, 32, etc. between the time you assign it and the time the rectangle is created?
Here is the code I used to test:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Image myIcon = Image.FromFile(#"C:\Users\me\Pictures\test.jpg");
int x = 0;
int y = 14;
Rectangle myIconDrawingRectangle = new Rectangle(x, y, 1000, 16);
using (TextureBrush brush = new TextureBrush(myIcon, WrapMode.Tile))
{
e.Graphics.FillRectangle(brush, myIconDrawingRectangle);
}
e.Graphics.DrawLine(Pens.Black, 0, 16, 1000, 16);
}
and the result:
using TransalteTransform() to set up start point,if u do not do this, tiling would have some offset, to corect this, like below:
brush.TranslateTransform(0,50);

Best way to fade in/out image

What is the best (least resource heavy) way to fade an image in and out every 20 seconds with a duration of 1 second, against a black background (screensaver), in C# ?
(an image about 350x130px).
I need this for a simple screensaver that's going to run on some low level computers (xp).
Right now I'm using this method against a pictureBox, but it is too slow:
private Image Lighter(Image imgLight, int level, int nRed, int nGreen, int nBlue)
{
Graphics graphics = Graphics.FromImage(imgLight);
int conversion = (5 * (level - 50));
Pen pLight = new Pen(Color.FromArgb(conversion, nRed,
nGreen, nBlue), imgLight.Width * 2);
graphics.DrawLine(pLight, -1, -1, imgLight.Width, imgLight.Height);
graphics.Save();
graphics.Dispose();
return imgLight;
}
You could probably use a Color Matrix like in this example on msdn
http://msdn.microsoft.com/en-us/library/w177ax15%28VS.71%29.aspx
Instead of using a Pen and the DrawLine() method, you can use Bitmap.LockBits to access the memory of your image directly. Here's a good explanation of how it works.
Put a Timer on your form, and in the constructor, or the Form_Load,
write
timr.Interval = //whatever interval you want it to fire at;
timr.Tick += FadeInAndOut;
timr.Start();
Add a private method
private void FadeInAndOut(object sender, EventArgs e)
{
Opacity -= .01;
timr.Enabled = true;
if (Opacity < .05) Opacity = 1.00;
}
Here's my take on this
private void animateImageOpacity(PictureBox control)
{
for(float i = 0F; i< 1F; i+=.10F)
{
control.Image = ChangeOpacity(itemIcon[selected], i);
Thread.Sleep(40);
}
}
public static Bitmap ChangeOpacity(Image img, float opacityvalue)
{
Bitmap bmp = new Bitmap(img.Width, img.Height); // Determining Width and Height of Source Image
Graphics graphics = Graphics.FromImage(bmp);
ColorMatrix colormatrix = new ColorMatrix {Matrix33 = opacityvalue};
ImageAttributes imgAttribute = new ImageAttributes();
imgAttribute.SetColorMatrix(colormatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
graphics.DrawImage(img, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imgAttribute);
graphics.Dispose(); // Releasing all resource used by graphics
return bmp;
}
It's also recommended to create another thread because this will freeze your main one.

Custom Control to show an Image: move the image inside

I'm developing and C# app for Windows Mobile. I have a custom control with OnPaint overrided to draw an image that the user moves with the pointer. My own OnPaint method is this:
protected override void OnPaint(PaintEventArgs e)
{
Graphics gxOff; //Offscreen graphics
Brush backBrush;
if (m_bmpOffscreen == null) //Bitmap for doublebuffering
{
m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);
}
gxOff = Graphics.FromImage(m_bmpOffscreen);
gxOff.Clear(Color.White);
backBrush = new SolidBrush(Color.White);
gxOff.FillRectangle(backBrush, this.ClientRectangle);
//Draw some bitmap
gxOff.DrawImage(imageToShow, 0, 0, rectImageToShow, GraphicsUnit.Pixel);
//Draw from the memory bitmap
e.Graphics.DrawImage(m_bmpOffscreen, this.Left, this.Top);
base.OnPaint(e);
}
The imageToShow it's the image.
The rectImageToShow it's initialized on event OnResize in this way:
rectImageToShow =
new Rectangle(0, 0, this.ClientSize.Width, this.ClientSize.Height);
this.Top and this.Left are the topLeft corner to draw the image inside the custom control.
I think it'll work fine but when I move the image it never clean all the control. I always see a part of the previous drawing.
What I'm doing wrong?
Thank you!
I think you have not cleared the Control's image buffer. You have only cleared the back buffer. Try this between the 2 DrawImage calls:
e.Graphics.Clear(Color.White);
This should clear any leftover image first.
Alternatively, you can rewrite it so everything is painted on to the back buffer and the back buffer is then paint onto the screen at exactly (0, 0) so any problems will be because of the back buffer drawing logic instead of somewhere in between.
Something like this:
Graphics gxOff; //Offscreen graphics
Brush backBrush;
if (m_bmpOffscreen == null) //Bitmap for doublebuffering
{
m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);
}
// draw back buffer
gxOff = Graphics.FromImage(m_bmpOffscreen);
gxOff.Clear(Color.White);
backBrush = new SolidBrush(Color.White);
gxOff.FillRectangle(backBrush, this.Left, this.Top,
this.ClientRectangle.Width,
this.ClientRectangle.Height);
//Draw some bitmap
gxOff.DrawImage(imageToShow, this.Left, this.Top, rectImageToShow, GraphicsUnit.Pixel);
//Draw from the memory bitmap
e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);
base.OnPaint(e);
Not sure if that is correct, but you should get the idea.

Categories

Resources