Salut à tous

Dans le cadre d'un de mes projets (Pro), j'ai une galère sans nom avec les performances et GDI...

Bref, dès que j'ai 1000 objets à dessiner (avec des points et du remplissage), je tombe sur mon "vieux" PC à un temps de dessin autour de 180 ms...

Ce qui fait que si je déplace mes objets, ca suit "lentement", mais gentiment !!!

Pour remplir, j'utilise un bete Graphics.FillPath(...)

Comme je suis du genre tétu et parfois un peu geek sur les bords, je me suis dit, bon OK, et si j'attaquais directement ce remplissage à la "OldSchool"...

Et voilà...


Le code suivant permet de remplir un "path" (un contour in French) directement en appelant les méthodes C++ (via interop).

Gain de temps : X2 (voir un poil plus)

Le code (cadeau, no licence, rien du tout... c'est noël quoi )


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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
 
 
[DllImport("gdi32.dll")]
        static extern bool LineTo(IntPtr hdc, int nXEnd, int nYEnd);
 
        [DllImport("gdi32.dll")]
        static extern bool BeginPath(IntPtr hdc);
 
        [DllImport("gdi32.dll")]
        static extern bool EndPath(IntPtr hdc);
 
        [DllImport("gdi32.dll", SetLastError = true)]
        static extern IntPtr CreateCompatibleDC(IntPtr hdc);
 
        [DllImport("gdi32.dll")]
        static extern bool MoveToEx(IntPtr hdc, int X, int Y, IntPtr lpPoint);
 
        [DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
        static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
 
        [DllImport("gdi32.dll")]
        static extern bool DeleteObject(IntPtr hObject);
 
        [DllImport("gdi32.dll")]
        static extern bool DeleteDC(IntPtr hdc);
 
        [DllImport("gdi32.dll")]
        static extern IntPtr CreatePen(PenStyle fnPenStyle, int nWidth, uint crColor);
 
        public enum PenStyle
        {
 
            PS_SOLID = 0, //The pen is solid.
            PS_DASH = 1, //The pen is dashed.
            PS_DOT = 2, //The pen is dotted.
            PS_DASHDOT = 3, //The pen has alternating dashes and dots.
            PS_DASHDOTDOT = 4, //The pen has alternating dashes and double dots.
            PS_NULL = 5, //The pen is invisible.
            PS_INSIDEFRAME = 6,
            PS_USERSTYLE = 7,
            PS_ALTERNATE = 8,
            PS_STYLE_MASK = 0x0000000F,
 
            PS_ENDCAP_ROUND = 0x00000000,
            PS_ENDCAP_SQUARE = 0x00000100,
            PS_ENDCAP_FLAT = 0x00000200,
            PS_ENDCAP_MASK = 0x00000F00,
 
            PS_JOIN_ROUND = 0x00000000,
            PS_JOIN_BEVEL = 0x00001000,
            PS_JOIN_MITER = 0x00002000,
            PS_JOIN_MASK = 0x0000F000,
 
            PS_COSMETIC = 0x00000000,
            PS_GEOMETRIC = 0x00010000,
            PS_TYPE_MASK = 0x000F0000
 
        }
 
        [DllImport("gdi32.dll")]
        static extern bool FillPath(IntPtr hdc);
 
        [DllImport("gdi32.dll")]
        static extern IntPtr CreateBrushIndirect([In] ref LOGBRUSH lplb);
 
        [StructLayout(LayoutKind.Sequential)]
        struct LOGBRUSH
        {
            public BrushStyle lbStyle;        //brush style
            public UInt32 lbColor;    //colorref RGB(...)
            public HatchStyle lbHatch;        //hatch style
        }
 
        public enum BrushStyle : uint
        {
            BS_SOLID = 0,
            BS_HOLLOW = 1,
            BS_NULL = 1,
            BS_HATCHED = 2,
            BS_PATTERN = 3,
            BS_INDEXED = 4,
            BS_DIBPATTERN = 5,
            BS_DIBPATTERNPT = 6,
            BS_PATTERN8X8 = 7,
            BS_DIBPATTERN8X8 = 8,
            BS_MONOPATTERN = 9
        }
 
        public enum HatchStyle : int
        {
            HS_HORIZONTAL = 0,       /* ----- */
            HS_VERTICAL = 1,       /* ||||| */
            HS_FDIAGONAL = 2,       /* \\\\\ */
            HS_BDIAGONAL = 3,       /* ///// */
            HS_CROSS = 4,       /* +++++ */
            HS_DIAGCROSS = 5       /* xxxxx */
        }
 
 
private void myFillPath(Graphics g, Color c, List<PointF> p)
        {
            IntPtr pDC = g.GetHdc();
            IntPtr pen;
            LOGBRUSH brush = new LOGBRUSH();
            brush.lbStyle = BrushStyle.BS_SOLID;
            brush.lbColor = 16711935;
            brush.lbColor = (uint)ColorTranslator.ToWin32(c);
            pen = CreateBrushIndirect(ref brush);
 
            BeginPath(pDC);
            MoveToEx(pDC, (int)p[0].X + (int)offset.X, (int)p[0].Y + (int)offset.Y, IntPtr.Zero);
            for (int i = 1; i < p.Count; i++)
            {
                LineTo(pDC, (int)p[i].X + (int)offset.X, (int)p[i].Y + (int)offset.Y);
            }
            // Et on ferme le contour
            LineTo(pDC, (int)(p[0].X + offset.X), (int)(p[0].Y + offset.Y));
            EndPath(pDC);
 
            SelectObject(pDC, pen);
            FillPath(pDC);
            DeleteObject(pen);
            g.ReleaseHdc();
        }
PS : j'ai tout mis (même les DllImport histoire de faire du Ready to use )

PS2 : offset est un PointF que j'utilise pour "déplacer" mes points.

Avertissement: En faisant ainsi, on écrit "brutalement" dans le GDI donc, faut pas escompter tenir compte lors du Draw du Scale, Translate, etc que le Graphics pourrait fournir (ni même les modes de rendu "HighQuality, etc..."), mais bon, ca speed quand même bien

Pour info finale, sur mon PC, je dessine 1000 formes (composées de 6 points formant une maison) en 80 ms... (en release) et je les déplaces à ce frame Rate là (pas exceptionnel mais correcte sur un PC : 1.73 GHz avec 1 Go de ram