[SlimDX] Texture not rendered on UserControl

Started by
16 comments, last by Boneless1988 12 years, 5 months ago
Hi,
in my project I need to render textures on UserControl objects. The only problem is, that the textures are not rendered. Instead a white box with red borders and a red cross on it is rendered (see image).

[attachment=6063:UserControl.png]

What can cause this problem?

Here's my code:


/// <summary>
/// Abstract base class for all DirectX controls.
/// </summary>
public abstract partial class ControlBase : UserControl
{
/// <summary>
/// Blending action of the control.
/// </summary>
protected enum AlphaBlendAction
{
None,
BlendIn,
BlendOut
};

/// <summary>
/// Graphical device instance.
/// </summary>
protected Device Device;

/// <summary>
/// Sprite used to render textures.
/// </summary>
protected Sprite Sprite;

/// <summary>
/// Alpha value of the control.
/// </summary>
protected int iAlpha;

/// <summary>
/// Indicates if alpha blending should be used.
/// </summary>
protected bool bUseBlendingEffect;

/// <summary>
/// Blending action.
/// </summary>
protected AlphaBlendAction eBlendAction;

/// <summary>
/// Minimal alpha value of control's background texture.
/// </summary>
public int MinAlpha
{
get;
set;
}

/// <summary>
/// Maximal alpha value of control's background texture.
/// </summary>
public int MaxAlpha
{
get;
set;
}

/// <summary>
/// Indicates if blending should be used.
/// </summary>
public bool UseBlendingEffect
{
get
{
return this.bUseBlendingEffect;
}

set
{
this.bUseBlendingEffect = value;

if ( this.bUseBlendingEffect )
{
this.iAlpha = this.MinAlpha;
}
else
{
this.iAlpha = this.MaxAlpha;
}
}
}

/// <summary>
/// Creates a new instance of ControlBase.
/// </summary>
public ControlBase()
: base()
{
this.MinAlpha = 150;
this.MaxAlpha = 255;
this.UseBlendingEffect = false;
this.eBlendAction = AlphaBlendAction.None;

this.MouseHover += new EventHandler( OnMouseHover );
this.MouseLeave += new EventHandler( OnMouseLeave );

InitializeGraphicDevice();
}

/// <summary>
/// Initializes the graphical device.
/// </summary>
protected virtual void InitializeGraphicDevice()
{
PresentParameters PresentParams = new PresentParameters();
PresentParams.SwapEffect = SwapEffect.Discard;
PresentParams.DeviceWindowHandle = this.Handle;
PresentParams.Windowed = true;
PresentParams.BackBufferWidth = this.ClientSize.Width;
PresentParams.BackBufferHeight = this.ClientSize.Height;
PresentParams.BackBufferFormat = Format.A8R8G8B8;

try
{
this.Device = new Device( new Direct3D(), 0, DeviceType.Hardware, this.Handle, CreateFlags.HardwareVertexProcessing, PresentParams );
}
catch ( Exception e )
{
MessageBox.Show( e.Message );
}

this.Device.SetRenderState( RenderState.AlphaBlendEnable, true );
this.Device.SetRenderState( RenderState.Lighting, false );
this.Device.SetRenderState( RenderState.SourceBlend, Blend.One );
this.Device.SetRenderState( RenderState.DestinationBlend, Blend.One );

// Create sprite
this.Sprite = new Sprite( this.Device );
}

/// <summary>
/// Update method of the control. Can be overridden by derived classes.
/// </summary>
new public virtual void Update()
{
if ( AlphaBlendAction.BlendIn == this.eBlendAction )
{
if ( this.MaxAlpha - this.iAlpha >= 5 )
{
this.iAlpha += 5;
}
else
{
this.iAlpha = this.MaxAlpha;
this.eBlendAction = AlphaBlendAction.None;
}
}
else if ( AlphaBlendAction.BlendOut == this.eBlendAction )
{
if ( this.iAlpha - this.MinAlpha >= 5 )
{
this.iAlpha -= 5;
}
else
{
this.iAlpha = this.MinAlpha;
this.eBlendAction = AlphaBlendAction.None;
}
}
}

/// <summary>
/// Render method of the control. Must be overridden by derived classes.
/// </summary>
public abstract void Render();

/// <summary>
/// Releases all unmanaged Resources of the object.
/// </summary>
new public virtual void Dispose()
{
this.Device.Direct3D.Dispose();
this.Device.Dispose();
this.Sprite.Dispose();
}

/// <summary>
/// Eventhandler for event MouseHover. Starts the blending in if blending is activated.
/// </summary>
/// <param name="sender">Sender of event.</param>
/// <param name="e">Event argument.</param>
protected void OnMouseHover( object sender, EventArgs e )
{
if ( this.UseBlendingEffect )
{
this.eBlendAction = AlphaBlendAction.BlendIn;
}
}

/// <summary>
/// Eventhandler for event MouseLeave. Starts the blending out if blending is activated.
/// </summary>
/// <param name="sender">Sender of event.</param>
/// <param name="e">Event argument.</param>
protected void OnMouseLeave( object sender, EventArgs e )
{
if ( this.UseBlendingEffect )
{
this.eBlendAction = AlphaBlendAction.BlendOut;
}
}

/// <summary>
/// Called when control must be redrawn.
/// </summary>
/// <param name="e">Event argument.</param>
protected override void OnPaint( PaintEventArgs e )
{
this.Device.Clear( ClearFlags.Target, new Color4( Color.Black ), 1f, 0 );

if ( this.Visible )
{
this.Device.BeginScene();

this.Render();

this.Device.EndScene();
}

this.Device.Present();
}

/// <summary>
/// Does nothing. Overridden to prevent flickering.
/// </summary>
/// <param name="e">Event argument.</param>
protected override void OnPaintBackground( PaintEventArgs e )
{
// Do nothing to prevent flickering.
}

/// <summary>
/// Called when control has been resized.
/// </summary>
/// <param name="e">Event argument.</param>
protected override void OnSizeChanged( EventArgs e )
{
InitializeGraphicDevice();
}
}

/// <summary>
/// Textured button control using DirectX.
/// </summary>
public class TextureButton : ControlBase
{
/// <summary>
/// Bitmap of the button.
/// </summary>
//private Bitmap Bitmap;

/// <summary>
/// Texture of the button.
/// </summary>
private TextureItem TextureItem;

/// <summary>
/// Creates a new TextureButton instance.
/// </summary>
/// <param name="Bitmap">Bitmap of the button's texture.</param>
//public TextureButton( Bitmap Bitmap )
public TextureButton(string Filename)
: base()
{
this.TextureItem = new TextureItem( this.Device, Filename );
}

/// <summary>
/// Renders the TextureButton instance.
/// </summary>
public override void Render()
{
// Calculate scaling factor for texture.
Matrix Scaling = Matrix.Scaling( this.Width / (float)this.TextureItem.Width,
this.Height / (float)this.TextureItem.Height,
0f );

this.Sprite.Begin( SpriteFlags.AlphaBlend );
this.Sprite.Transform = Scaling;

this.Sprite.Draw( TextureItem.Texture, Rectangle.Empty, Vector3.Zero, Vector3.Zero, Color.FromArgb( iAlpha, 255, 255, 255 ) );

this.Sprite.End();
}

/// <summary>
/// Releases all unmanaged Resources of the object.
/// </summary>
public override void Dispose()
{
//this.TextureItem.Dispose();

base.Dispose();
}
}

/// <summary>
/// Wrapper class around Texture with additional information.
/// </summary>
public class TextureItem
{
/// <summary>
/// Heigth of the texture.
/// </summary>
public int Height
{
get;
private set;
}

/// <summary>
/// Width of the texture.
/// </summary>
public int Width
{
get;
private set;
}

/// <summary>
/// Texture instance.
/// </summary>
public Texture Texture
{
get;
private set;
}

/// <summary>
/// Creates a new instance of TextureItem.
/// </summary>
/// <param name="Device">Graphical device.</param>
/// <param name="Filename">Name of the texture file.</param>
public TextureItem( Device Device, string Filename )
{
Image Image = Image.FromFile( Filename );

this.Height = Image.Height;
this.Width = Image.Width;

this.Texture = Texture.FromFile( Device, Filename );
}

/// <summary>
/// Creates a new instance of TextureItem.
/// </summary>
/// <param name="Device">Graphical device.</param>
/// <param name="Bitmap">Bitmap of the texture.</param>
//public TextureItem( Device Device, Bitmap Bitmap )
//{
// this.Height = Bitmap.Height;
// this.Width = Bitmap.Width;

// MemoryStream Stream = new MemoryStream();
// Bitmap.Save( Stream, ImageFormat.Png );
// byte[] test = Stream.ToArray();

// this.Texture = Texture.FromMemory( Device, test );
//}

/// <summary>
/// Releases all unmanaged Resources of the object.
/// </summary>
public void Dispose()
{
this.Texture.Dispose();
}
}


Hope for help!

Best regards
Advertisement
Hi!

The red cross on white background is the controls way of saying that something inside the paint method caused an exception. Your output window in visual studio could give you some hint, which exception was raised. (Helping you out is easier, if we identify the culprit. [font="Wingdings"]:)[/font]) If there is an exception, try stepping through the paint method to find the point where you jump out of the function.

Hi!

The red cross on white background is the controls way of saying that something inside the paint method caused an exception. Your output window in visual studio could give you some hint, which exception was raised. (Helping you out is easier, if we identify the culprit. [font="Wingdings"]:)[/font]) If there is an exception, try stepping through the paint method to find the point where you jump out of the function.


Alright, I've managed to locate four calls where a Direct3D9Exception will be thrown:

1. Device.BeginScene() in OnPaint() (class ControlBase)
2. Sprite.End() in Render() (class TextureButton)
3. Device.EndScene() in OnPaint() (class ControlBase)
4. Device.Present() in OnPaint() (class ControlBase). I'm not sure about this one.

Any idea what could cause these exceptions?

P.S.: Why do these exceptions don't interrupt the program execution as other exceptions do?

Best regards
Hi,

Okay, the BeginScene only throws if EndScene is not called (according to the documentation). This is exactly what happens if the Sprite.End() throws since the OnPaint method won’t complete. So, the exception at BeginScene is caused by the exception at Sprite.End(). Now, let’s see. The sprite object (if not specified otherwise), submits the draw calls in the Sprite.End() method. This means, something goes wrong here. (Could you comment the sprite.Draw to check that?) The documentation does not provide a list of things that possibly can go wrong, so here is just a guess of mine. The native Dx9 sprite takes a null as the rectangle argument, if the sprite should be drawn in the original size. I don’t know how SlimDx wraps this, but I assume you should also pass in null, instead of Rectangle.Empty, since this rectangle is actually an object that would be passed on to the native call and then the native call will try to scale the image by dividing through the size – which is 0x0 – so my guess is, that a 0-division will cause the exception.

Could you go to your project properties and set in the debug tab the flag “Enable unmanaged code debugging”? This will give you the original direct3d output. If you turn on the debug layer in the directx control panel (is included in the utilities) you get even more debug information printed to the console.

By the way, the exceptions don’t terminate the program, since the base component catches them and renders the red cross instead.

Greetings
I commented the draw call out. Still the same problem. Where are these utilities?

I commented the draw call out. Still the same problem. Where are these utilities?

Hm, bad news. Hopefully the debug output will be helping.
The utilities are in: Start -> All Programs -> Microsoft DirectX SDK (June 2010) -> DirectX Utilities -> DirectX Control Panel.exe
Can you comment out the sprite.begin and sprite.end as well? It would be nice to find a code path that works.
Hi,
can't find the DirectX Control Panel. I don't have the DirectX SDK installed (only SlimDX).

I commented the calls of Sprite.Begin() and Sprite.End() out. Device.BeginScene() and Device.EndScene() stll are throwing the exception. Maybe there is something wrong in my device creation.

Got to go to bed now. It's 1:15 AM here in germany. I will work on tomorrow. Thanks for your help so far. If you have any further ideas regarding my problem, please post them.

Best regards and good night !
Hi,
I've installed the Microsoft DirectX SDK. Which options shall i activate in the control panel to get the desired debug output?
Hi!
Alright, go to the Direct3D 9 tab, drag the 'Debug Output Level' slider to 'More' and check the "Use debug version of Direct3D 9".
This should give you clearer error messages. Btw, do you get any error code?

Hi!
Alright, go to the Direct3D 9 tab, drag the 'Debug Output Level' slider to 'More' and check the "Use debug version of Direct3D 9".
This should give you clearer error messages. Btw, do you get any error code?


I've done as you said, but I get no additional information in the debug window. Should I see the error code in the debug window?

I'm running on Win 7 64 bit. May this be a problem?

This topic is closed to new replies.

Advertisement