IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Framework .NET Discussion :

[dotnet] gdi+ rafraichissement


Sujet :

Framework .NET

  1. #1
    Membre régulier
    Inscrit en
    Novembre 2002
    Messages
    291
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 291
    Points : 81
    Points
    81
    Par défaut [dotnet] gdi+ rafraichissement
    Bonjour,

    Comment faire pour raffraichir seulement une partie d'une image avec gdi+ ?

    J'ai une Bitmap que j'affiche masi pas forcement avec ses dimensions d'origine :
    par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    Bitmap^ texture = gcnew Bitmap("test.png");
     
    /* ... */
    Rectangle tailleEcran = Rectangle(0, 0, 50, 100);
     
    if (tailleEcran.IntersectWith(e->ClipRectangle)
        g->DrawImage(texture, tailleEcran, 0, 0, texture->Width, texture->Height, GraphicsUnit::Pixel, mImageAttr)
    j'affiche donc toute mon image. Seulement je ne l'affiche pas avec ses dimensions d'origine (donc l'image est deformée)

    Donc maintenant, mon prob :
    J'ai une boule qui se deplace, et quand elle se deplace sur l'image, je redessine cette image en entier (dans OnPaint)... et ca ne me plait pas, je voudrais juste raffraichir la zone de l'image où la balle passe.. (et je m'embrouille avec les 30 declarations différentes de drawimage )

    voilà j'espere que c'est compréhensible ?
    merci de votre aide

    P.S. si qqun connait des liens vers l'optimisation de l'affichage avec gdi+, je suis preneur...merci

  2. #2
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    1 - C'est bien DrawImage qu'il faut utiliser.
    Je te suggère l'overload avec x, y et un rectangle source :

    * x et y sont les coordonnées, dans ton Graphics, où tu veux dessiner ton image.
    * le rectangle source est la portion de l'image à coller dans le Graphics.

    2 - Pour animer un sprite, sans tout redessiner, il n'y a qu'un méthode : en rajoutant un buffer.
    * Tu as un premier buffer ("back") qui représente le fond de ton image
    * Tu en as un second buffer ("frame") qui contient la frame : l'image à un instant t

    2.1 - le dessin de la frame se fait en deux étapes :
    * Tu copies "back" dans "frame"
    * Tu dessines ton sprite par dessus

    2.2 - Sinon, méthode plus évoluée (plus lourde à gérer) :
    * Au départ tu initializes "frame" en copiant "back" dedans"
    * Au moment T
    * * Si tu as dessiné un sprite en T-1, tu copies dans "frame" uniquement la portion de "back" nécessaire à recouvrir ton sprite
    * * Tu dessines ensuite ton nouveau sprite là où tu veux
    (Note : ça t'oblige à savoir où était le sprite en T-1)

    2.3 - Sinon, encore plus evolué :
    * Tu fais un buffer "back" qui fait la taille maximale de ton sprite
    * Au départ tu dessines directement dans "frame"
    * Au moment T :
    * * tu sauvegarde dans "back" la portion de "frame" qui va se faire recouvrir par le sprite
    * * tu dessines ton sprite
    * Au moment T+1
    * * tu restaures dans "frame" le contenu de "back" là où tu l'as pris, pour effacer ton sprite
    * * etc.

    Note : je ne suis pas sûr de savoir laquelle de ces méthodes est la plus rapide.
    2.1 : la plus rapide à coder
    2.2 : évite une copie par frame (probablement la plus rapide IMHO)
    2.3 : la moins lourde en mémoire

    3 - GDI accéléré : voir dans la FAQ du forum.

  3. #3
    Membre régulier
    Inscrit en
    Novembre 2002
    Messages
    291
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 291
    Points : 81
    Points
    81
    Par défaut
    merci de ta reponse :
    Pour le drawimage aurais tu un exemple car je dois aussi mettre mon ImgAttr dans drawImage... donc je dois utiliser une des surchages avec ImageAttributes..

    Ensuite pour l'animation : dessiner une autre image pour la balle : ca ok mais dessiner que la partie caché du fond.. voilà ce que j'aimerai !!!

    Et enfin pour l'acceleration de GDI+ je n'ai pas trouvé la FAQ du forum, ou un post parlant de l'acceleration de GDI...
    Est ce une bonne methode de tout mettre dans OnPaint ? ou existe t'il une autre methode ?

    merci

  4. #4
    Membre régulier
    Inscrit en
    Novembre 2002
    Messages
    291
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 291
    Points : 81
    Points
    81
    Par défaut
    voilà en fait j'ai un souci et je ne sais pas si c'est moi qui fait mal qqchose ou si c'est GDI+ qui rame !!!

    Donc j'ai plusieurs balles qui se deplacent entre 4 murs.

    Le prob dès qu'il y a plus de 3 balles, elles ralentissent et j'ai l'impression que ca rame !!! :00000010:

    Voici un extrait de mon code :

    Code de mis à jour des balles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
     
    	ControleurObjets^ cObjets = ControleurObjets::GetInstance();
     
    	Rectangle rectPos, rectPosPrec, rectEnglob;
    	// Rafraichissement des objets mobiles
    	for each(Balle^ b in cObjets->GetListeBalles())
    	{
    		Point pos		= b->GetPosition();
    		Point posPrec	= b->GetPositionPrec();
     
    		// calcule du rectangle englobant ancienne+nouvelle position
    		rectPos	    = Rectangle(b->GetPosition(), b->GetDimensions());
    		rectPosPrec = Rectangle(b->GetPositionPrec(), b->GetDimensions());
    		rectEnglob  = rectPos.Union(rectPos, rectPosPrec);
     
    		// on ne met à jour que la zone qui en a besoin
    		mFenetre->Invalidate(rectEnglob);
     
    	}
    Code d'affichage des balles :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    	ControleurObjets^ cObjets = ControleurObjets::GetInstance();
     
    	for each(Balle^ b in cObjets->GetListeBalles())
    	{
    		// si l'objet se trouve dans le rectangle de raffraichissement : on le reaffiche
    		Rectangle tailleImg = Rectangle(b->GetPosition(), b->GetDimensions());
    		if (tailleImg.IntersectsWith(rectAff))
    		{
    	Bitmap^ texture     = mListeTextures[b->GetTexture()];
    	Rectangle tailleImg = Rectangle(b->GetPosition(), b->GetDimensions());
     
     
    	// on definit la transparence (1 = opaque, 0 = tranparent)
    	mColorMatrix->Matrix33 = 1.f - b->GetTransparence();
    	mImageAttr->SetColorMatrix(mColorMatrix, ColorMatrixFlag::Default,ColorAdjustType::Bitmap);
     
    	g->DrawImage(texture, tailleImg, 0, 0, texture->Width, texture->Height, GraphicsUnit::Pixel, mImageAttr);
     
    		}		
    	}
    y a t'il qqchose qui ne va pas ?

    pour info : pour faire avancer la balle c'est position = position+vitesse et j'appelle la fonction deplacement toutes les 15ms...

    mercide votre aide

    P.S : pas de reponse du type : utilise DirectX ou OpenGl, merci

  5. #5
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    J'ai pas d'exemples pour DrawImage, mais je crois avoir donné assez d'explication pour ne pas avoir à faire cette recherche à ta place. Allez courage, y'a que 9 surcharges.

    Pour l'accélération de GDI+, recherche les forums/tuto qui parlent de code unsafe avec GDI+, j'ai pas de tuto sous la main, mais voici un exemple complet sur code project

    Pour le dessin : attention... ne pas confondre dessiner et copier.
    Relis les algos que je que j'ai donné dans mon post précédent. J'ai pas passé 20mn à écrire tout ça pour que tu me dise le contraire de ce que j'ai expliqué.
    Je t'ai donné les techniques utilisé dans les jeux en 2D depuis des années, ce sont des techniques sûres et efficaces. Je veux bien détailler ce que tu ne comprend pas, mais fait l'effort d'essayer de comprendre.

    Pour ton problème de ralentissements, c'est parce que tu ne dois pas utiliser pas le double buffering. Il y a des tas de tuto sur la question un peu partout.

  6. #6
    Membre régulier
    Inscrit en
    Novembre 2002
    Messages
    291
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 291
    Points : 81
    Points
    81
    Par défaut
    merci de tes reponses,

    Excuse moi, j'ai du mal expliqué qqchose, en effet, je suis en c++.net, donc pas de code unsafe ...
    Ensuite il y a bcp plus que 9 surcharges :
    http://msdn2.microsoft.com/fr-fr/lib...ge(VS.80).aspx


    Sinon le double buffering est normelement géré par .NET 2 (avec setStyles avec optimzeddoublebuffered...) je ne revalide donc que les zones necessaires (qui correspond à ta solution 2.2 si j'ai bien compris ?) : je n'invalide que les zones necessaires t je reaffiche que si besoin..
    Il y a donc quelque chose que j'ai soit mal comprise, soit pas compris du tout ?

    Ensuite en effet je dois confondre copier et afficher. Car je ne vois pas ce que je copie ? je ne fais que afficher non ? la copie se fait automatiquement avec le double buffer géré par le framework, non ?

    Cependant ce qui m'inquiete le plus : certe gdi+ est peut etre lent, cependant je n'affiche que 3images de 2ko et ca commence deja à ramer....je pense que ca vient plus de moi je pense...


    Merci de ton aide, j'ai relus au moins 10 fois ce que tu as ecrit et je ne vois pas si j'ai mal fait qqchose !

  7. #7
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 381
    Points
    20 381
    Par défaut
    Citation Envoyé par CaptainChoc
    Excuse moi, j'ai du mal expliqué qqchose, en effet, je suis en c++.net, donc pas de code unsafe ...
    unsafe signifie unmanaged code donc appels d'APIs win32.
    <TROLL>
    le framework .NET cela n'empêche pas les belles boites de messages d'exceptions
    </TROLL>

    Et des techniques d'animations sous win32 cela se fait en moins de 2.
    Tu peux faire une dll en code "non managed" regarder dans le forum C++/VC++ c'est un sujet maintes fois abordé.
    Il faut faire une bitmap et HDC en mémoire

  8. #8
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 381
    Points
    20 381
    Par défaut
    Citation Envoyé par CaptainChoc
    Ensuite en effet je dois confondre copier et afficher. Car je ne vois pas ce que je copie ? je ne fais que afficher non ? la copie se fait automatiquement avec le double buffer géré par le framework, non ?

    Cependant ce qui m'inquiete le plus : certe gdi+ est peut etre lent, cependant je n'affiche que 3images de 2ko et ca commence deja à ramer....je pense que ca vient plus de moi je pense...
    La technique du double-buffering cela consiste à dessiner dans des tampons mémoires les uns distincts des autres et les copier les uns sur les autres puis vers un tampon final qui est envoyé à l'écran pour éviter les scintillements et "flashes" des images.
    C'est un peu le principe des images sur un tourniquet que l'on fait tourner à grande vitesse et qui donne la sensation d'animation , méthode du 19ième siécle

    Si GDI+ est trop lent prends le GDI carrément sinon SDL.
    Mais GDI et SDL ne sont pas accessible en code managed ; ( à part que je crois qu'il y ait une version .NET de SDL )

  9. #9
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    Citation Envoyé par CaptainChoc
    Ensuite il y a bcp plus que 9 surcharges :
    http://msdn2.microsoft.com/fr-fr/lib...ge(VS.80).aspx
    Et bah y'en a une qui prend un rectangle source, un rectangle destination et un format d'image.

    T'as compris la notion de source et destination ?
    Si ces deux rectangles ont la même taille, alors l'image ne sera pas déformée.
    Après il te reste à jouer sur les positions x et y de ces rectangles pour coller ton image où tu veux.

    Citation Envoyé par CaptainChoc
    Sinon le double buffering est normelement géré par .NET 2 (avec setStyles avec optimzeddoublebuffered...) je ne revalide donc que les zones necessaires (qui correspond à ta solution 2.2 si j'ai bien compris ?) : je n'invalide que les zones necessaires t je reaffiche que si besoin..
    Il y a donc quelque chose que j'ai soit mal comprise, soit pas compris du tout ?
    "Normallement géré", effectivement.
    Je ne peux rien te dire sur la question, perso j'utilise les mêmes techniques que j'utilisais il y a 8 ans en X-Window, et ça ne rame pas (enfin si, si je met vraiment beaucoup de balles)
    Ces techniques, c'est le double buffering "maison", à savoir :
    * je dessine tout dans le buffer frame
    * quand l'appli à besoin de rafraichir l'écran (à chaque frame), je ne fais que coller le buffer fr

    Ensuite en effet je dois confondre copier et afficher. Car je ne vois pas ce que je copie ? je ne fais que afficher non ? la copie se fait automatiquement avec le double buffer géré par le framework, non ?

    Cependant ce qui m'inquiete le plus : certe gdi+ est peut etre lent, cependant je n'affiche que 3images de 2ko et ca commence deja à ramer....je pense que ca vient plus de moi je pense...


    Merci de ton aide, j'ai relus au moins 10 fois ce que tu as ecrit et je ne vois pas si j'ai mal fait qqchose ![/QUOTE]

  10. #10
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    Citation Envoyé par CaptainChoc
    Ensuite il y a bcp plus que 9 surcharges :
    http://msdn2.microsoft.com/fr-fr/lib...ge(VS.80).aspx
    Et bah y'en a une qui prend un rectangle source, un rectangle destination et un format d'image.

    T'as compris la notion de source et destination ?
    Si ces deux rectangles ont la même taille, alors l'image ne sera pas déformée.
    Après il te reste à jouer sur les positions x et y de ces rectangles pour coller ton image où tu veux.

    Citation Envoyé par CaptainChoc
    Sinon le double buffering est normelement géré par .NET 2 (avec setStyles avec optimzeddoublebuffered...) je ne revalide donc que les zones necessaires (qui correspond à ta solution 2.2 si j'ai bien compris ?) : je n'invalide que les zones necessaires t je reaffiche que si besoin..
    Il y a donc quelque chose que j'ai soit mal comprise, soit pas compris du tout ?
    "Normallement géré", effectivement.
    Je ne peux rien te dire sur la question, perso j'utilise les mêmes techniques que j'utilisais il y a 8 ans en X-Window, et ça ne rame pas (enfin si, si je met vraiment beaucoup de balles)
    Ces techniques, c'est le double buffering "maison", à savoir :
    * je dessine tout dans le buffer frame
    * quand l'appli à besoin de rafraichir l'écran (à chaque frame), je ne fais que coller le buffer frame dans le Graphics du contrôle. Surtout pas de logique de dessin à ce moment là, c'est ça qui provoque les ralentissement.

    Citation Envoyé par CaptainChoc
    Ensuite en effet je dois confondre copier et afficher. Car je ne vois pas ce que je copie ? je ne fais que afficher non ? la copie se fait automatiquement avec le double buffer géré par le framework, non ?
    Quand je dis dessiner, je pense aux DrawRectangle, etc...
    Quand je dit copier, je pense au DrawImage.
    J'ai ptet pas non plus les bons mots
    Et oui, c'est "normallement géré par le double buffering du framework", mais j'ai jamais fait trop confiance au framework pour ça, je fais tout à la main. Ptet qqn peut t'en dire plus.
    Citation Envoyé par CaptainChoc
    Cependant ce qui m'inquiete le plus : certe gdi+ est peut etre lent, cependant je n'affiche que 3images de 2ko et ca commence deja à ramer....je pense que ca vient plus de moi je pense...
    Je pense aussi. J'ai déjà codé des ptits jeux en .Net, y'a pas trop de pb. C'est pas DirectX, c'est sûr, mais ça va...
    Tient, un pti exemple qui fait ça tès bien sur Code Project

  11. #11
    Membre régulier
    Inscrit en
    Novembre 2002
    Messages
    291
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 291
    Points : 81
    Points
    81
    Par défaut
    alors j'ai regardé le ptit exemple et j'ai essayé de faire pareil

    j'ai donc un timer qui se met a jour tout le tps (toutes les 1ms) et qui mets à jour mes objets, une fois la mise à jour faite, il appelle la methode afficher :

    voilà ce que ca donne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
     
    	ControleurObjets^ cObjets = ControleurObjets::GetInstance();
     
    	Graphics^ g= Graphics::FromImage(mBuffer);
    	g->Clear(Color::White);
     
    	// Rafraichissement des objets mobiles
    	for each(Balle^ b in cObjets->GetListeBalles())
    	{
     
                Rectangle tailleImg = Rectangle(b->GetPosition(),b->GetDimensions());
    	    g->DrawImage(texture, TailleImage)
     
    	}
                MaFenetre->CreateGraphic()->DrawImage(mBuffer,MaFenetre->GetTaille());
    c'est un test donc je ne fait que effacer le fond, mais j'ai deja pas les memes resultats : deja je n'utilise plus de invalidate, ensuite cette fois que j'ai une ou 10 balles la vitesse est la même mais je ne suis qu'à 20images par seconde...
    Apres quelques test, les temps perdu se trouve au moment ou je fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     MaFenetre->CreateGraphic()->DrawImage(mBuffer,MaFenetre->GetTaille());
    j'y suis presque lol il doit encore me manquer qqchose....

  12. #12
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    Bon, tu as ce qu'on appelle une gestion custom du double buffering
    C'est comme ça que je bosse aussi. L'avantage c'est que tu sais mieux ce qui se passe.

    Maintenant, pour gagner du temps, j'essayerais de désactiver le double buffering de .Net, et de jouer un peu avec les autres ControlStylepour trouver ceux qui conviennent le mieux. Je pense qu'il faut UserPaint et AllPaintingInWmPaint à true

    T'as fais un compteur de fps ? Très pratique pour tunner une appli graphique

  13. #13
    Membre régulier
    Inscrit en
    Novembre 2002
    Messages
    291
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 291
    Points : 81
    Points
    81
    Par défaut
    oui un ptit compteur simple... cependant je regarde l'exemple de progs que tu as donné et le fps est à 50.. alors que pour mes balles je ne depasse pas le 20.. et 20 images par seconde ce n'est pas assez...
    Mais ce qui m'mbete c'est que je redessine toujours tous, par exemple j'ai des ptit image qui delimite les murs, ben là je les redessine alors qu'il n'y a pas besoin... mais bon juste avec 1 balle : 20images par secondes je trouve cela trop peu..

  14. #14
    Membre régulier
    Inscrit en
    Novembre 2002
    Messages
    291
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 291
    Points : 81
    Points
    81
    Par défaut
    Euh petite question que je me pose car là je suis bloqué.... si je mets un thread qqpart ca changera qqchose car 20images par secondes c'est vraiment vriment trop peu !!! et j'ai pas encore de fond, et d'autre objets, que 3 balles...

  15. #15
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    T'as enlevé le double buffer optimisé dans les styles ?

Discussions similaires

  1. rafraichissement avec GDI+
    Par sdecorme dans le forum C#
    Réponses: 4
    Dernier message: 11/07/2012, 11h09
  2. [gdi] problème de zone de rafraichissement
    Par NiamorH dans le forum Windows
    Réponses: 2
    Dernier message: 06/08/2007, 11h45
  3. [C# + GDI]Panel transparent:Pb de rafraichissement
    Par Wolverin dans le forum Windows Forms
    Réponses: 9
    Dernier message: 26/06/2007, 10h57
  4. Probleme de rafraichissement d'un BDGrid
    Par marmotte dans le forum Bases de données
    Réponses: 10
    Dernier message: 28/05/2004, 18h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo