Monitor Elektronenstrahl Position?



  • Mon 75 Hz und alle 40ms, also 25 mal pro sekunde wird das bild bewegt. schon klar, das der monitor öfter ein neues bild erzeugt, als mein programm.
    aber es muss doch trotzdem irgendwie möglich sein, sowas komplett flimmerfrei zu halten....



  • hmmm. unter DOS ging das mit einem wait-for-retrace (direkte programmierung der graka). da wurde das programm so "lange" unterbrochen, bis der elektronenstrahl das untere rechte ende des bildschirms erreicht hat. und in genau dem moment kannst du deine daten im video-RAM aktualisieren, da der strahl ja aus ist, wenn er wieder in die linke obere ecke zurückkehrt. (und das dauert halt (wenn auch nur ganz kurz))

    cu todo



  • vsync 😃



  • Ich glaube eher, dass du was falsch machst, wenn es trotz Backbufer noch flackert. Poste lieber mal etwas Code, damit man sich das anschauen kann, um zu erkennen, wo der Fehler liegt.



  • LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    static HDC hdc,hdcMem,hdcBackbuffer;
    PAINTSTRUCT ps;
    
    static HBITMAP Bild,Backbuffer;
    BITMAP bitmap;
    static ufo_xpos,ufo_ypos=0;
    static float i,j=0;
    static RECT rect;
    
    switch (message)
    {
    case WM_CREATE:
        SetTimer (hwnd,1,40,NULL);
        Bild = LoadImage (hInst,"testbild.bmp",IMAGE_BITMAP,
        100,100,
        LR_LOADFROMFILE | LR_CREATEDIBSECTION);
        GetObject(Bild, sizeof (BITMAP), &bitmap);
    
        hdc=GetDC(hwnd);
        hdcBackbuffer=CreateCompatibleDC(hdc);
        Backbuffer=CreateCompatibleBitmap(hdc,1024,768);
    
        SelectObject(hdcBackbuffer,Backbuffer);
        SetRect (&rect,0,0,1024,768);
        FillRect(hdcBackbuffer, &rect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
    
        DeleteDC(hdcBackbuffer);
        ReleaseDC(hdc,hwnd);
        break;
    case WM_PAINT:
        hdc=BeginPaint (hwnd, &ps);
        hdcBackbuffer=CreateCompatibleDC(hdc);
    
        SelectObject (hdcBackbuffer,Backbuffer);
        BitBlt (hdc,0,0,1024,768,hdcBackbuffer,0,0,SRCCOPY);
    
        EndPaint (hwnd, &ps);
        DeleteDC (hdcBackbuffer);
        break;
    case WM_TIMER:
            switch (wParam)
            {
            case 1:
            if(i>6.27) i=i-6.28;
            ufo_xpos = (sin (i)*300)+450;i=i+0.04;
    
            if(j>=3.13) j=j-3.14;
            ufo_ypos = (sin (j)*200);j=j+0.02;
    
            hdc=GetDC(hwnd);
            hdcMem = CreateCompatibleDC(hdc);
            hdcBackbuffer= CreateCompatibleDC(hdc);
    
            SelectObject (hdcMem, Bild);
            SelectObject (hdcBackbuffer,Backbuffer);
            SetRect (&rect,ufo_xpos-12,ufo_ypos-12,ufo_xpos+112,ufo_ypos+112);
            FillRect(hdcBackbuffer, &rect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
            BitBlt (hdcBackbuffer,ufo_xpos,ufo_ypos,100,100,hdcMem,0,0,SRCCOPY);
            DeleteDC (hdcMem);
            DeleteDC (hdcBackbuffer);
    
            InvalidateRect (hwnd,&rect,FALSE);
            break;
            }
            break;
    
    case WM_DESTROY:
    
        DeleteObject (Bild);
        DeleteObject(Backbuffer);
    
        PostQuitMessage (0);
    
        break;
    }
    
    // ---> return DefWindowProc (...
    

    Ok, entschuldigt aber, daß ich hier soviele konstante Werte benutze, soll nur zum testen sein.



  • Es fehlt noch ein ReleasDC (hwnd,hdc) in WM_TIMER.

    Übrigens, es flackert nicht ständig, nur hin und wieder. Also eigentlich funktioniert das so ja schon, nur halt dann nicht, wenn der Monitor das fliegende Bild schon halb dargestellt hat, und es in dem Moment durch WM_PAINT an eine andere Stelle gezeichnet werden soll.

    Kann man das irgendwie regeln?



  • Füg mal noch

    case WM_ERASEBKGND:
        return 0;
    

    in deine WndProc ein, dann sollte es weg sein, allerdings ist dein Programm-Design nicht gerade günstig. Statt dem InvalidateRect-Aufruf kannst du das Bild auch gleich in WM_TIMER zeichnen!



  • Statt dem InvalidateRect-Aufruf kannst du das Bild auch gleich in WM_TIMER zeichnen!

    Keine gute Idee. Er macht das schon richtig so. Begründung hab ich aber auch nicht. :p



  • Erstmal Danke für eure Antworten 🙂

    Also, ich hab jetzt, nur um es mal zu testen, die WM_ERASEBKGND message eingefügt, aus der WM_TIMER das InvalidateRect() rausgenommen und zeichne das Bild jetzt mit BitBlt(hdc,...) also direkt auf den Bildschirm. Aber das flackert immer noch an den Rändern.

    Wie gesagt, es flackert nicht ständig, es kann gut mal sein, dass es 2-3 Bewegungszyklen (also von einem Bildschirmrand zum anderen und zurück) durchläuft ohne zu flackern, und dann flackerts, und zwar sieht mans an den Rändern und es flackert von oben nach unten. Das muss doch was mit dem Bildaufbau des Monitors zu tun haben, oder?

    Hat denn niemand hier schonmal sowas gesehen, der sich schnell bewegende Bitmaps auf den Screen programmiert hat? Wenn nicht, was mache ich dann nur falsch?



  • benutzt du irgendwo in deinem code CS_HREDRAW oder CS_VREDRAW? vielleicht mal rausnehmen 🙄



  • ja, in der Windowclass... rausnehmen hat aber auch nichts bewirkt



  • Hier mal was zum lesen, ist jedoch englisch:
    http://www.compuphase.com/vretrace.htm#VRETRACE_WHY

    und in Assembler würde man den vertical retrace so abfragen (aus dem Artikel):

    mov     dx, 3dah        ; VGA input status register
    vretrace_loop:
                    in      al, dx
                    test    al, 8           ; bit 3 set?
                    jz      vretrace_loop   ; no, continue waiting
    

    Jemand ne Idee, wie man das in C hinbekommt als Teil eines WinAPI-Programms?



  • quatsch sowas brauchst du nicht



  • @TimTaylor
    Bitte lies Dir doch mal ein Tutorial durch. Da steht überall (und ausserdem wurde es hier im Forum schon häufig behandelt), dass jede Selektierung in einen DC mit einer Deselektierung abgeschlossen werden muss.

    Richtiger und verbesserter Code:

    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    HDC hdc,hdcMem,hdcBackbuffer;
    PAINTSTRUCT ps;
    
    static HBITMAP Bild;
    HBITMAP Backbuffer;
    BITMAP bitmap;
    static ufo_xpos,ufo_ypos=0;
    static float i,j=0;
    static RECT rect;
    HGDIOBJ hBmpOld, hBmpOld2;
    
    switch (message)
    {
    case WM_CREATE:
        SetTimer( hwnd,1,40,NULL);
        Bild = LoadImage (hInst,"testbild.bmp",IMAGE_BITMAP, 100,100, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
        GetObject(Bild, sizeof (BITMAP), &bitmap);
    
        hdc=GetDC(hwnd);
        hdcBackbuffer=CreateCompatibleDC(hdc);
        Backbuffer=CreateCompatibleBitmap(hdc,1024,768);
    
        hBmpOld = SelectObject( hdcBackbuffer,Backbuffer);
        SetRect (&rect,0,0,1024,768);
        FillRect(hdcBackbuffer, &rect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
        // !!! WICHTIG !!!
        SelectObject( hdcBackbuffer, hBmpOld);
    
        DeleteDC(hdcBackbuffer);
        ReleaseDC(hdc,hwnd);
        break;
    case WM_PAINT:
        hdc=BeginPaint (hwnd, &ps);
        hdcBackbuffer=CreateCompatibleDC(hdc);
        hdcMem = CreateCompatibleDC(hdc);
    
        hBmpOld = SelectObject (hdcBackbuffer,Backbuffer);
        hBmpOld2 = SelectObject (hdcMem, Bild);
        FillRect(hdcBackbuffer, &rect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
        BitBlt (hdcBackbuffer,ufo_xpos,ufo_ypos,100,100,hdcMem,0,0,SRCCOPY);
        BitBlt (hdc,0,0,1024,768,hdcBackbuffer,0,0,SRCCOPY);
        // !!! WICHTIG !!!
        SelectObject( hdcMem, hBmpOld2);
        SelectObject( hdcBackbuffer, hBmpOld);
        DeleteDC (hdcBackbuffer);
        DeleteDC (hdcMem);
        EndPaint (hwnd, &ps);
        break;
    case WM_TIMER:
            switch (wParam)
            {
            case 1:
            if(i>6.27) i=i-6.28;
            ufo_xpos = (sin (i)*300)+450;i=i+0.04;
            if(j>=3.13) j=j-3.14;
            ufo_ypos = (sin (j)*200);j=j+0.02;
            InvalidateRect (hwnd,&rect,FALSE);
            // Manchmal besser, um flüssigeren Bewegungsablauf zu garantieren
            UpdateWindow( hwnd);
            break;
            }
            break;
    
    case WM_DESTROY:
    
        DeleteObject (Bild);
        DeleteObject(Backbuffer);
    
        PostQuitMessage (0);
    
        break;
    }
    


  • Wenn ich deinen verbesserten Code benutze wird, das bitmap gar nicht mehr gezeichnet, der screen bleibt schwarz. naja, wenigstens flackert es nicht mehr 😃

    Trotzdem Danke für deinen Tipp, mal sehen ob ich es nicht doch noch ans Laufen bringe...



  • Nagut, ein static vor HBITMAP Backbuffer hat gefehlt... hast du es aus einem bestimmten Grund weggelassen?

    Ansonsten läufts genauso wie vorher, es flackert manchmal... naja, was solls, wenn es denn nicht besser zu realisieren ist, muss ich wohl die Flinte ins Korn werfen. Oder mich mit DirectX befassen, denn da gibts Befehle, um ein Programm mit dem vertikalen Bildaufbau zu synchronisieren.

    Danke nochmal an alle, die hier mitgeschrieben haben.



  • Hallo,

    biste schon mal auf die Idee gekommen, dass der Monitor kaputt sein könnte?



  • Nagut, ein static vor HBITMAP Backbuffer hat gefehlt... hast du es aus einem bestimmten Grund weggelassen?

    Nein, hab ich nur übersehen.

    P.S. Das flackern geht im normalen DC nie ganz weg.


Anmelden zum Antworten