[C#] Crosshair tekenen op desktop.

Pagina: 1
Acties:

  • peke
  • Registratie: Februari 2002
  • Laatst online: 19-05 15:21
Ik wil permanent een crosshair tekenen op het scherm.
Deze crosshair mag door niets worden overtekent en heeft als doel de crosshair in games te vervangen met als meerwaarde dat de kleur vd crosshair variabel is naargelang de kleur waarover de crosshair zit bevindt.


C#:
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
 * Author: Frederik De Ruyck
 * Copyrighted
*/
using System;
using System.Runtime.InteropServices;

namespace A_dots
{
    static class Program
    {

        [DllImport("user32.dll", ExactSpelling = true, SetLastError = false)]
        private static extern IntPtr GetDC(IntPtr hWnd);

        [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = false)]
        private static extern UInt32 GetPixel(IntPtr hdc, int x, int y);

        [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = false)]
        private static extern UInt32 SetPixel(IntPtr hdc, int x, int y, UInt32 color);

        [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = false)]
        private static extern int GetDeviceCaps(IntPtr hdc, int index);

        private static IntPtr _display = GetDC(IntPtr.Zero);

        [STAThread]
        static void Main()
        {
            int width = GetDeviceCaps(_display, 8);//HORZRES
            int height = GetDeviceCaps(_display, 10);//VERTRES
            int x = width / 2;
            int y = height / 2;
            while (true)
            {
                //System.Threading.Thread.Sleep(1);
                //PatBlt(_display, x - 5, y - 1, 10, 2, 3);
                UInt32 pix = GetPixel(_display, x, y);
                //quad 1 midden + rechtsonder
                SetPixel(_display, x + 0, y + 1, CalcColorComplement(pix));
                SetPixel(_display, x + 1, y + 1, CalcColorComplement(pix));
                SetPixel(_display, x + 0, y + 2, CalcColorComplement(pix));
                SetPixel(_display, x + 1, y + 2, CalcColorComplement(pix));
                //
                //quad 2 midden + linksonder
                SetPixel(_display, x - 1, y + 1, CalcColorComplement(pix));
                SetPixel(_display, x - 2, y + 1, CalcColorComplement(pix));
                SetPixel(_display, x - 1, y + 2, CalcColorComplement(pix));
                SetPixel(_display, x - 2, y + 2, CalcColorComplement(pix));
                //
                //quad 3 midden + rechtsboven
                //SetPixel(_display, x + 0, y - 0, CalcColorComplement(pix));//<-SamplePixel
                SetPixel(_display, x + 1, y - 0, CalcColorComplement(pix));
                SetPixel(_display, x + 0, y - 1, CalcColorComplement(pix));
                SetPixel(_display, x + 1, y - 1, CalcColorComplement(pix));
                //
                //quad 3 midden + linksboven
                SetPixel(_display, x - 1, y - 0, CalcColorComplement(pix));
                SetPixel(_display, x - 2, y - 0, CalcColorComplement(pix));
                SetPixel(_display, x - 1, y - 1, CalcColorComplement(pix));
                SetPixel(_display, x - 2, y - 1, CalcColorComplement(pix));
            }
        }


        private static UInt32 CalcColorComplement(int x, int y)
        {
            UInt32 pix = GetPixel(_display, x, y);
            return CalcColorComplement(pix);
        }

        private static UInt32 CalcColorComplement(UInt32 pix)
        {

            //rgb to hsl from http://www.geekymonkey.com/Programming/CSharp/RGB2HSL_HSL2RGB.htm
            //hsl to rgb from http://www.bobpowell.net/RGBHSB.htm
            //0x00bbggrr
            int P = (int)pix;
            int R = P & (255);
            int G = P & (65536 - 255);
            int B = P & (16777215 - 65536 - 255);

            G = G >> 8;
            B = B >> 16;

            float H = 0f, S = 0f, L = 0f;
            float r = R / 255f;
            float g = G / 255f;
            float b = B / 255f;
            float v;
            float m;
            float vm;
            float r2, g2, b2;
            H = 0; // default to black
            S = 0;
            L = 0;
            v = Math.Max(r, g);
            v = Math.Max(v, b);
            m = Math.Min(r, g);
            m = Math.Min(m, b);
            L = (m + v) / 2f;
            if (L > 0f)
            {
                vm = v - m;
                S = vm;
                if (S > 0f)
                {
                    S /= (L <= 0.5f) ? (v + m) : (2f - v - m);
                    r2 = (v - r) / vm;
                    g2 = (v - g) / vm;
                    b2 = (v - b) / vm;
                    if (r == v)
                    {
                        H = (g == m ? 5f + b2 : 1f - g2);
                    }
                    else if (g == v)
                    {
                        H = (b == m ? 1f + r2 : 3f - b2);
                    }
                    else
                    {
                        H = (r == m ? 3f + g2 : 5f - r2);
                    }
                    H /= 6f;
                }
            }

            H = 1f - H;
            S = 1f - S;
            L = 1f - L;

            float temp1, temp2;
            if (L == 0)
            {
                r = g = b = 0;
            }
            else
            {
                if (S == 0)
                {
                    r = g = b = L;
                }
                else
                {
                    temp2 = ((L <= 0.5f) ? L * (1f + S) : L + S - (L * S));
                    temp1 = 2f * L - temp2;
                    float[] t3 = new float[] { H + 1f / 3f, H, H - 1f / 3f };
                    float[] clr = new float[] { 0, 0, 0 };
                    for (int i = 0; i < 3; i++)
                    {
                        if (t3[i] < 0)
                            t3[i] += 1f;
                        if (t3[i] > 1)
                            t3[i] -= 1f;
                        if (6.0 * t3[i] < 1.0)
                            clr[i] = temp1 + (temp2 - temp1) * t3[i] * 6f;
                        else if (2.0 * t3[i] < 1.0)
                            clr[i] = temp2;
                        else if (3.0 * t3[i] < 2.0)
                            clr[i] = (temp1 + (temp2 - temp1) * ((2f / 3f) - t3[i]) * 6f);
                        else
                            clr[i] = temp1;
                    }
                    r = clr[0];
                    g = clr[1];
                    b = clr[2];
                }
            }
            R = (int)(255 * r);
            G = (int)(255 * g);
            B = (int)(255 * b);
            G = G << 8;
            B = B << 16;
            UInt32 result = (UInt32)(R + G + B);
            return result;
        }
    }
}


Mijn problemen:

1. De pixels worden in games overschreven door DirectX of OpenGL waardoor de crosshair flikkert.
2. Het complement vd RGB waarden levert niet het maximum contrast op.

Vooral dit 1e is irritant.
De werking zou eingelijk moeten zijn zoals bij bvb Fraps.
Elke mogelijke oplossing of tip is welkom, het gebruik van een direct3d device als het niet anders kan ik ook goed.

Als het opgelost raakt post ik wel even het project + de exe. :)

<update1>
Ondertussen even geprobeerd om rechtstreeks in het actieve window te tekenen door met GetForegroundWindow (uit user32.dll) een window handle op te vragen om daar vervolgens de graphics context van op te vragen met GetDC.
Dit doet echter niets, het lukt blijkbaar niet om in een window te gaan tekenen, enkel op de desktop.
</update1>

<update2>
*knip*
</update2>

</update3>
Even de sourcecode bijgewerkt.
Mensen die het willen testen moeten de source maar copy pasten en compileren. :)
</update3>

[ Voor 67% gewijzigd door peke op 31-01-2007 18:13 ]


  • ZaZ
  • Registratie: Oktober 2002
  • Laatst online: 27-11 15:14

ZaZ

Tweakers abonnee

Als het voor een spelletje is dan ontkom je niet aan het gebruik van een d3d device.
Het gaat een hele zooi schrijfwerk worden dan voor je ben ik bang. Er bestaan wel proxies die je toelaten om een d3d device te jatten en erop te schrijven en tekenen. Slim googlen met termen zoals proxy directx etc. zou je kunnen helpen.
Het gaat je iig niet lukken met gewoon op een normale windows device context te painten.

Lekker op de bank


  • peke
  • Registratie: Februari 2002
  • Laatst online: 19-05 15:21
Het lukt wel, alleen is het storend dat het een beetje flikkert.
Zo worden de pixels 1000 keer per seconde hertekend (kost <1% cpu) waardoor ze altijd zichtbaar blijven, alleen overschrijft een gameframe het héél eventjes.
Ik kan er iig prima mee spelen, alleen het kleuralgoritme moet nog wat beter want op rood krijg ik een rode crosshair, alle andere kleuren zijn wel ok.
Maar bedankt voor je tip, ik heb al wat met managed D3D gewerkt dus ik ga dat van die proxie zeker (na mijn ex) opzoeken.

  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 31-10 11:58
Als je met PatBlt tekent kan je met DSTINVERT er gewoon voor zorgen dat de onderliggende rectangle geïnverteerd wordt. Dit heb ik in ieder geval gebruikt om een soort van Spy++ achtige tool toe te voegen aan m'n programma.

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


  • peke
  • Registratie: Februari 2002
  • Laatst online: 19-05 15:21
Zal ik ook eens testen, echter heb ik al gewone inversie toegepast door
R = 255 - R; B = 255 - BR; G = 255 - G;
te doen en dat werkt maar ingame zie je duidelijk dat het dat niet hoort te zijn doordat een hoop kleuren te dicht bij 255/2 liggen waardoor de output bijna hetzelfde is als de input, bvb bij grijstint 127,127,127 etc.
Vandaar dat ik nu het complement neem vd kleuren in HSL. Dit geeft een beter resultaat doch nog niet perfect voor elke kleur(tot nu toe gekend: roodtinten).
Echter kan ik indien het voor de meeste kleuren werkt een offset toevoegen voor de kleuren waar het niet goed is.

Ideaal is tekenen in het gamevenster zodat nog voor dit op het scherm gezet wordt de pixels reeds overschreven zijn.
Nu wisselen crosshair en game elkaar af wat voor een licht flikkeren zorgt.
Er zijn ook functies die de link leggen tussen OpenGL en Windows, de zgn wgl functies, hier zou ik ook nog wat moeten over opzoeken.

  • peke
  • Registratie: Februari 2002
  • Laatst online: 19-05 15:21
http://www.gamedev.net/co...topic.asp?topic_id=359319
http://www.gamedev.net/co...topic.asp?topic_id=367591

Blijkbaar heet de manier van renderen die ik zocht "overlays" en wordt dit bereikt met DirectDraw.
Op de 1e link staat een C++ demo en op de 2e een C# demo.

Morgen maar eens mee bezighouden.
:)

/e/

Demo (C++) getest, op nvidia hardware loopt het niet (InvalidPixelFormat) en op Ati hardware wel.
Dan krijg je een zwart venstertje met wat tekst in, echter verdwijnt het bij een game of loopt de game niet (DirectDraw games) tot het venster weg is.
Maw dit is het ook niet een aangezien DirectDraw deprecated is valt er ook niet meer te vinden hoe het wel moet, op msdn of in de SDK help staat over deprecated do not use blabla dus ik kan niet achterhalen hoe iets werkt.

Wat ik nu in gedachten heb is om iedere keer voordat het beelscherm ververst wordt te gaan tekenen. Maar ja, hoe kan je zoiets gaan detecteren?

[ Voor 48% gewijzigd door peke op 03-02-2007 14:15 ]


  • compie
  • Registratie: November 1999
  • Niet online
Voor OpenGL spellen kun je dit oplossen door een OpenGL wrapper te schrijven. Ik heb dat ooit gedaan voor m'n afstuderen. Je kunt het spel in de backbuffer een frame laten renderen en als het spel dan SwapBuffers aanroept teken jij eerst even je croshair.

http://www.hawksoft.com/gltrace/

GLTrace is opensource, daar kun je eens naar kijken. Hij kan bijvoorbeeld groene tekst op het scherm tekenen. Iets vergelijkbaars wil jij doen met je crosshair.

  • peke
  • Registratie: Februari 2002
  • Laatst online: 19-05 15:21

Win32 module to redirect calls from OPENGL32.DLL to specified provider DLL,
with API function trace to OutputDebugString() or text file


Klink interessant.
Echter zijn de meeste games D3D.
Dan nog vraag ik mij af hoe Fraps en XFire het oplossen, beide werken onder alle omstandigheden.
De Overlays demo heb ik wel aan de praat gekregen op ATI hardware, alleen blijft het niet boven een game, enkel boven de desktop in Windows.
Pagina: 1