Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Rendering in a Canvas in .NET  (Read 10672 times)

0 Members and 1 Guest are viewing this topic.

diRe

  • Newbie
  • *
  • Posts: 13
    • View Profile
Rendering in a Canvas in .NET
« on: September 16, 2009, 12:30:31 pm »
Hi,

I am currently working on a map editor (.NET) for my racing game. I encounted the problem of not being able to render something in the Windows Form (I want to have a canvas, where I render things, I do not want to be the Windows Form the sf::RenderWindow).
I tried the native approach: Create a "Label" (which is simply a "STATIC" with WinAPI), deactivate Autosizing, get the Handle of that label, pass it to the sf::RenderWindow and Clear() and Display() it's contents. While this works perfectly with the WinAPI, it will not do anything with Windows Forms.

My problem now is: I do not know, why this does not work, whether it is because of the "magic code" behind the scenes of the Visual Studio Designer or if the native approach simply does not go with Windows Forms.

If someone knows how to get this work, I would be very thankful.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Rendering in a Canvas in .NET
« Reply #1 on: September 16, 2009, 12:34:19 pm »
Have you tried something other than a Label? Like a Form?

If it doesn't help, you'll have to show us your code ;)
Laurent Gomila - SFML developer

diRe

  • Newbie
  • *
  • Posts: 13
    • View Profile
Rendering in a Canvas in .NET
« Reply #2 on: September 16, 2009, 02:43:52 pm »
Ok, I figured out, the Label can be used as a render target (infact, I can see a black box for a very short time). The problem now is, the label seems to redraw itself, so the sf::RenderWindow is not displaying anything.

That's my code (part of it):
Code: [Select]
// Constructor of my Form
Form1(void) : renderView(NULL)
{
InitializeComponent(); // Visual Studio Designer Stuff
HWND ptr = (HWND)renderWindow->Handle.ToPointer(); // Get the Label's handle (renderWindow is a Label)
renderView = new sf::RenderWindow(ptr); // Pass it to the sf::RenderWindow
this->Paint += gcnew PaintEventHandler(this, &Form1::Form1OnPaint); // Does not really work
}


So nothing that special about it. My main problem are two things:
1) The label redraws itself. Can I disable this behavior somehow?
2) Where to put renderView->Clear() and renderView->Display() (and of course the rest of rendering)? I put it into the method Form1OnPaint, which is called at the beginning of the program (if I place a Sleep() there, you can clearly see that the renderView displays it's content properly (a black void)), but after the method leaves, the label redraws itself - so the renderView's content is not shown.

PS.: If you are wondering: Yes, that is C++/CLI with .NET.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Rendering in a Canvas in .NET
« Reply #3 on: September 16, 2009, 03:01:00 pm »
1) That's probably possible, but I don't know how, sorry.

2) Form1OnPaint looks like a good place for rendering. The only thing you have to do is to trigger refreshes manually (using a timer or the "idle" event), so that the label gets repainted continuously.
Laurent Gomila - SFML developer

diRe

  • Newbie
  • *
  • Posts: 13
    • View Profile
Rendering in a Canvas in .NET
« Reply #4 on: September 16, 2009, 03:31:44 pm »
OK, I fixed it.

Apparently you can disable the drawing of the Label with one easy change to my code above. Instead of
Code: [Select]
this->Paint += gcnew PaintEventHandler(...); one has to write
Code: [Select]
renderWindow->Paint += gcnew PaintEventHandler(...)This seems to override the Label's painting.
2nd: I implemented your suggestion, although I am not that happy with it, because I dislike working with timers :). But it works, there is a flickering sometimes, but I guess with double buffering I can get rid of that as well.

Thanks for your help.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Rendering in a Canvas in .NET
« Reply #5 on: September 16, 2009, 03:40:46 pm »
I'm glad you found a solution :)

I don't understand your first fix, what are "this" and "renderWindow" in this context?

Quote
2nd: I implemented your suggestion, although I am not that happy with it, because I dislike working with timers

I think this is the best solution, don't be afraid to use timers in this kind of situations ;)

Quote
But it works, there is a flickering sometimes, but I guess with double buffering I can get rid of that as well.

SFML already uses double-buffering.
Maybe you have to disable something else in your Label; in Qt for example (a GUI library for C++) you have to change a few things like "no system background", "direct painting on screen", "opaque paint event" for this to work.
Laurent Gomila - SFML developer

diRe

  • Newbie
  • *
  • Posts: 13
    • View Profile
Rendering in a Canvas in .NET
« Reply #6 on: September 16, 2009, 06:02:36 pm »
"this" refers to the Form itself. That means, if something on the Form isn't valid in terms of "optic", the Form needs to redraw itself plus it's contents (at least, I think it works this way). So some child controls get the message "Hey, redraw yourself, please!", which is why the Label seems to redraw itself and overlay the renderView.

In my solution, only the Label itself is redrawn, if it needs to be. I came across this idea, when I thought about other controls like buttons etc. If I would have done a timer with the "this->Paint += ...", everything would be redrawn everytime, which... well, THAT would be massive flickering.

It has been a long time since I actually programmed with the native WinAPI, where this whole Invalidate, Redraw thing was clear to me, so I might be totally wrong. But this approach seems to work as intented.

With double buffering, I think it is more a problem of the Windows Form itself. The DB of SFML works fine, but the "Label" flickers. I had this problem in my native WinAPI days, too. AFAIK the problem is, that the content of the Label (the renderView) is first cleared and filled with the control's background color, when the Paint Event is fired. Then the content is drawn and shown.

ptrxyz

  • Newbie
  • *
  • Posts: 32
    • View Profile
Rendering in a Canvas in .NET
« Reply #7 on: September 18, 2009, 11:58:05 am »
You can set a style to most controls:

Using VB.NET it would be done like this:

Code: [Select]
MyControl.SetStyle(ControlStyles.UserPaint Or ControlStyles.AllPaintingInWmPaint _
                                                    Or ControlStyles.Opaque, True)


Adding this line to in the constructor of your form, right there where all properties of your control get set, will cause the control to no draw anything by itself. All drawing will be done in a custom function (--> add an event handler to the .Paint event pointing to a function and add SFML.Display() there.).

Ok, a basic exmaple for your function handling MyControl.Paint() could be (pseudo code, translate it to your .net language):

Code: [Select]

function HandleMyControlPaint(Sender myctrl, PaintEventArgs args) {
    myMainSFMLObject.Display(); // Display SFML's content
    myctrl.Invalidate(); // Immediatly invalidate the control again. This will cause the control to redraw itself again asap. Since this just post a "redraw" message to the event queue you get the fastest performance you can get and other events are still processed. no need to have a sleep or something...
}


And a basic example for the form's initialisation (function InitializeComponent):

Code: [Select]

function InitializeComponent() {
    this.MyCtrl = new system.windows.forms.button(); // for example...a button
    this.MyCtrl.Text="hello";
    this.MyCtrl....blablabla.....//all initialisation will be done here. Usually this should be generated by your designer if you use one.
   
    MyCtrl.SetStyle(.....); // Add this line with the parameters above. This is where you tell the control to not draw anything by itself.
}


Ok, sorry for posting just stupid pseudo code but I guess you got the main idea. You add the setstyle to your control right after its creation and therefore you do all painting on your own and invalidate the control right after it got drawn.

Just google in case you still got trouble....there are plenty of examples out there in combination with D3D/DirectX.

diRe

  • Newbie
  • *
  • Posts: 13
    • View Profile
Rendering in a Canvas in .NET
« Reply #8 on: September 18, 2009, 01:12:56 pm »
Thank you for your reply. The SetStyle method is really what I was looking for, now the annoying flickering has gone. But just to state it: The SetStyle method is protected, so one cannot modify the style of an already existing control (or I did not find out how). Therefore, I simply derived from Forms::Label and Re-Set the style in the constructor.

Also the Invalidate() in the event handling Paint() is very nice and makes the timer I used unnecessary. In fact, now this feels "right", the solution with the timer... well, I dislike them as already stated :)