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

Langage Delphi Discussion :

Rotation de bitmap : problème de trigo avec PlgBlt


Sujet :

Langage Delphi

  1. #1
    Membre habitué Avatar de Laskar
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    228
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2002
    Messages : 228
    Points : 139
    Points
    139
    Par défaut Rotation de bitmap : problème de trigo avec PlgBlt
    Salut à tous.
    Un petit souci avec PlgBlt que j’utilise pour faire la rotation d’une bitmap. J’ai trouvé un bout de code sur le net très sympa qui propose de précalculer la valeur sin et cos des 360 angles possibles autour d’un axe central. Cette méthode est vraiment très rapide.
    J’utilise PlgBlt pour faire la rotation d’un sprite. L’affichage du sprite utilise un masque qui permet de le déplacer de manière fluide sur un fond sans laisser de trace. Dans ses arguments, PlgBlt accepte une bitmap monochrome qui tient lieu de masque. Voici l’instruction qui affiche le sprite avec son masque :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PlgBlt(HdcWork, rSel, img.Canvas.Handle, 0, 0, img.Width, img.Height, Mask.Handle, 0, 0)
    Vous pouvez télécharger l’exécutable ici : miret.casas.free.fr/Calques.zip
    (Usage : chargez un sprite et utilisez la trackbar pour faire la rotation)

    Tout ça fonctionne bien MAIS, je m’aperçois d’un bug quand le sprite possède un angle de 180°. En effet, à cette valeur, le masque s’affiche, lui, à 0° ! (tous les autres angles sont ok).
    Comprends pas pourquoi !
    Mes vieux souvenirs de trigo me donnent une piste : sin(180) = 0 et cos(180) = -1. A votre avis, est-ce là la cause de mes ennuis ?

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 693
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    J'ai montré ici comment faire tourner le DC plutôt que de recalculer l'image en utilisant SetWorldTransform. Je privilégierais cette approche. Ça n'empêche pas d'utiliser PlgBlt pour masquer l'image (sans toutefois recalculer les points, uniquement des constantes) mais je passerais plutôt par des images 32 bits (avec canal alpha) à l'aide d'AlphaBlend

  3. #3
    Membre habitué Avatar de Laskar
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    228
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2002
    Messages : 228
    Points : 139
    Points
    139
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    J'ai montré ici comment faire tourner le DC plutôt que de recalculer l'image en utilisant SetWorldTransform.
    J'ai le crâne qui fume à force de trouver dans cette solution de quoi faire un masque. J'arrive à afficher un sprite sur un fond en semi-transparence, j'arrive même à faire rotation, translation et tout le toutime mais impossible de masquer les pixels blancs du sprite. Si tu as sous la main un bout de code ou un lien qui pourrait m'aider, je prends !

  4. #4
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 693
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Bon, j'ai essayé avec PlgBlt mais ça ne fonctionne pas non plus avec un angle égal à PI.
    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    type
      TForm1 = class(TForm)
        Timer1: TTimer;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure FormPaint(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
      private
        Image   :TBitmap;
        Mask    :TBitmap;
        Angle   :extended;
        Corners :array[0..2] of TPoint;
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      Image := TBitmap.Create;
      Image.LoadFromFile('d:\temp\Image.bmp');
     
      Mask := TBitmap.Create;
      Mask.LoadFromFile('d:\temp\Mask.bmp');
     
      ZeroMemory(@Corners, Length(Corners));
      Corners[1].X := Image.Width;
      Corners[2].Y := Image.Height;
    end;
     
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      Image.Free;
      Mask.Free;
    end;
     
    procedure TForm1.FormPaint(Sender: TObject);
    var
      XF :tagXForm;
     
    begin
      with XF do
      begin
        eM11 := cos(Angle);
        eM12 := sin(Angle);
        eM21 := -eM12;
        eM22 := eM11;
     
        eDX := Width div 2  -eM11 *(Image.Width div 2) +eM12 *(Image.Height div 2);
        eDY := Height div 2 -eM12 *(Image.Width div 2) -eM11 *(Image.Height div 2);
      end;
     
      SetGraphicsMode(Canvas.Handle, GM_Advanced);
      SetWorldTransform(Canvas.Handle, XF);
      PlgBlt(Canvas.Handle, Corners, Image.Canvas.Handle, 0, 0, Image.Width, Image.Height, Mask.Handle, 0, 0);
      ModifyWorldTransform(Canvas.Handle, XF, MWT_IDENTITY);
    end;
     
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      Angle := pi;//Angle +0.1;
      Invalidate;
    end;
    donc oublie le masque et ajoute un canal alpha. Puis AlphaBlend
    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    type
      TForm1 = class(TForm)
        Timer1: TTimer;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure FormPaint(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
      private
        Image :TBitmap;
        Angle :extended;
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
      i :integer;
      p :PRGBQuad;
     
    begin
      Image := TBitmap.Create;
      Image.LoadFromFile('d:\temp\Image.bmp');
     
      //Couche alpha
      Image.PixelFormat := pf32bit;
      p := Image.ScanLine[Image.Height -1];
     
      for i := 0 to Image.Width *Image.Height -1 do
      begin
        if dword(p^) <> clWhite then
          p.rgbReserved := $FF;
     
        inc(p);
      end;
    end;
     
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      Image.Free;
    end;
     
    procedure TForm1.FormPaint(Sender: TObject);
    var
      XF :tagXForm;
    const
      Blend :TBlendFunction = (BlendOp:AC_SRC_OVER; BlendFlags:0; SourceConstantAlpha:255; AlphaFormat:AC_SRC_ALPHA);
     
    begin
      with XF do
      begin
        eM11 := cos(Angle);
        eM12 := sin(Angle);
        eM21 := -eM12;
        eM22 := eM11;
     
        eDX := Width div 2  -eM11 *(Image.Width div 2) +eM12 *(Image.Height div 2);
        eDY := Height div 2 -eM12 *(Image.Width div 2) -eM11 *(Image.Height div 2);
      end;
     
      SetGraphicsMode(Canvas.Handle, GM_Advanced);
      SetWorldTransform(Canvas.Handle, XF);
      Windows.AlphaBlend(Canvas.Handle, 0, 0, Image.Width, Image.Height, Image.Canvas.Handle, 0, 0, Image.Width, Image.Height, Blend);
      ModifyWorldTransform(Canvas.Handle, XF, MWT_IDENTITY);
    end;
     
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      Angle := pi;//Angle +0.1;
      Invalidate;
    end;

  5. #5
    Membre habitué Avatar de Laskar
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    228
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2002
    Messages : 228
    Points : 139
    Points
    139
    Par défaut
    Merci Andnotor de t'intéresser à mon projet. Dans ton code, j'ai une erreur à la compilation sur l'instruction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Windows.AlphaBlend(Canvas.Handle, 0, 0, Image.Width, Image.Height, Image.Canvas.Handle, 0, 0, Image.Width, Image.Height, Blend);
    Le compilateur me dit : Erreur 2003 : Identificateur non déclaré : 'windows'


    C'est quoi cet objet 'windows' ??
    (Je travaille avec Delphi XE6)


    Edit : Le 'USES' de XE6 se nomme Winapi.windows
    ... au temps pour moi !

    Je vais creuser la piste que tu me donnes. Merci mille fois.

  6. #6
    Membre habitué Avatar de Laskar
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    228
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2002
    Messages : 228
    Points : 139
    Points
    139
    Par défaut Hourra !
    Andnotor, ton code marche nickel ! Exactement ce que je cherchais ...

    Il ne me reste plus qu'à me plonger dans la recherche fondamentale. En particulier concernant cette effrayante constante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Blend :TBlendFunction = (BlendOp:AC_SRC_OVER; BlendFlags:0; SourceConstantAlpha:255; AlphaFormat:AC_SRC_ALPHA);
    ... mais j'apprends vite.

    Encore un grand merci, Ô maître !


+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 11/05/2010, 09h27
  2. Problème de mémoire avec Bitmap (c++/cli)
    Par bonofred dans le forum Windows Forms
    Réponses: 9
    Dernier message: 21/01/2009, 15h58
  3. Dessiner avec rotation un bitmap
    Par Andry dans le forum Delphi
    Réponses: 6
    Dernier message: 04/05/2007, 15h15
  4. Réponses: 2
    Dernier message: 31/07/2006, 15h28
  5. [BitMap] Problème avec BitMap.LoadFromStream
    Par Philippe Gormand dans le forum Delphi
    Réponses: 3
    Dernier message: 22/07/2006, 18h53

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