LPD3DXFONT DrawText Scrolling



  • Hallo,

    ich suche gerade nach einer Möglichkeit Text Boxen in DirectX abzubilden.
    Das Problem welches ich habe ist eigentlich nur die Text Ausgabe.

    z.B. eine Textbox an Position x = 50 y = 50 mit einer Höhe x Breite von 100 x 100...
    Jetzt nehmen wir mal an, das der Text der in der Box drin ist, die doppelte höhe braucht um komplett sichtbar zu sein. Ich würde die Scrollbars einblenden und den Text "oben links" ausgerichtet Rendern. Soweit ok...

    INT DrawText(
    [in] LPD3DXSPRITE pSprite,
    [in] LPCTSTR pString,
    [in] INT Count,
    [in] LPRECT pRect,
    [in] DWORD Format,
    [in] D3DCOLOR Color
    );

    Mit den 4 Parameter kann ich ja die Position und Breite / Höhe festlegen. Was größer ist, wird abgeschnitten.
    Sobald aber gescrolled wird, weiss ich nicht wie ich das Offset von z.b. -10 Pixel handhaben soll.
    Ich müsste ja jetzt die ersten 10 Pixel (oder einfach die erste Zeile) nicht Zeichnen. Wenn ich von rect.top einfach 10 abziehe, fängt er eben zu hoch mit dem malen an.

    Die einzige Idee, welche mir gekommen ist, wäre eine Texture mit 100x100 zu erzeugen und auf diese als RenderTarget mit rect.top = -10; zu Rendern. Aber mir grausst es davor für jede Scrollbox ein Render Target zu erzeugen (Speicher) und dann auch wieder bei DeviceLost richtig damit umzugehen.

    Hat jemand eine bessere Idee?



  • keiner eine Idee oder war es zu wirr was ich erklärt hab? 😃



  • Hi,

    sorry das ich das noch mal aufgreife, aber ich hab immer noch keine Idee...
    Hat keiner einen Anhaltspunkt für mich?



  • Bessere Idee:
    Wenn der Text statisch ist, vorher 1x auf eine Textur rendern und diese darstellen und scrollen?



  • Oder vielleicht das Scissor Rect oder Clipplanes verwenden!?



  • @Scorcher24: Der Text ist leider variable...

    @dot: Das werde ich mir mal anschauen

    Danke schon mal euch beiden!



  • Scissor war was ich gesucht habe 🙂
    thx!



  • ok, necroposting is böse, aber das ist hier genau das problem, was ich auch habe.

    habe auch direkt nach scissor rect und dergleichen gegoogled, nur stoße ich da auf weitere probleme, die darauf schließen lassen, das ich das ganze doch etwas anders angehen sollte, wie ich es im moment tue.

    mein problem ist eigentlich, das eben jenes scissor rect mein kompletten backbuffer beinflusst. d.h. wenn ich eben sage, scissor rect = { 0, 0, 50, 20 };
    draw process aufrufe, und dann wieder zu full screen setze, juckt das meinen backbuffer überhaupt nicht, und er draw trotzdem alles so, wie wenn ich das nicht gesetzt hätte.

    ok, klingt plausiebel, da ->present() ja auch erst später aufgerufen wird.
    Nur würde mich als angehenden amateur doch mal interessieren, wie der TE das gemacht haben könnte. Da ich jetzt nicht davon ausgehe, das er noch sonderlich aktiv ist, oder zumindest die mölichkeit besteht, das er das nicht ist, halte ich mich mal nicht mit pns auf, sondern frage fröhlich in die runde.

    um meine frage ein wenig zu spezifizieren:
    wie bekomm ich es also hin, das ich meinen text frei scrollbar mache?

    mfg



  • Na du setzt eben dein Scissor Rect und zeichnest den Text!?



  • ich dachte, das wäre verständlich, was ich oben geschrieben habe:

    angenommen wir haben folgendes

    RECT pRect = { 0, 0, ScreenSize.x, ScreenSize.y };
    device->SetScissorRect(&pRect);
    Font->DrawText("blahblubb",......);
    RECT pRect = { 0, 0, ScreenSize.x, ScreenSize.y };
    device->SetScissorRect(&pRect);
    

    jetzt wird der text an sich nicht wirklich geclipped, da ich danach das rect ja wieder groß setzen muss, damit mein restlicher screen nicht darunter leidet.

    wenn das der richtige weg ist, was mach ich falsch?



  • anti-freak schrieb:

    wenn das der richtige weg ist, was mach ich falsch?

    Du vergisst den Scissor Test auch einzuschalten (SetRenderState)...



  • muss ich das nach jedem mal machen, wenn ich ein neues RECT setze?
    am anfang des Projekts hatte ich das aktiviert.

    aber es funktioniert trotzdem nicht...

    Habe auch damit noch ein wenig herum probiert, funktionieren tut es ja, wenn ich das rect danach nicht wieder zurück setze.



  • anti-freak schrieb:

    muss ich das nach jedem mal machen, wenn ich ein neues RECT setze?

    Nun, vielleicht schaltet dein Font Objekt es wieder ab?



  • Wie gesagt, es liegt nicht am SetRenderState(). Das Clippen funktioniert, wenn ich das Rect nach meinem Draw Font nicht wieder zurück setze, aber das ist nicht Sinn der Sache, weil dann der restliche Teil des Bildschirms auch nicht mehr gedrawt wird.

    ist das so schwer zu verstehen, was ich meine?^^

    im moment besitzt eigentlich jede größere draw routine ein eigenes LPD3DXSPRITE (also, die map, die layer der Objecte, die Textbox), wird aber schlussendlich alles zusammen auf den Backbuffer gedrawt.
    Muss ich hier irgendwo ansetzen, und was verändern?



  • Nein, es ist absolut klar was du meinst. Das Problem ist, dass du einfach zu wenig Information darüber gibst, wie du die von dir beschriebenen Abläufe jetzt genau implementiert hast. Nur weil du denkst dass du was machst, heißt das noch lange nicht, dass dein Code auch wirklich tut was du denkst...

    Verwendest du ein ID3DXFont? Wenn ja: Gibt dem mal beim Draw ein eigenes ID3DXSprite mit und ruf bei dem explizit Begin und End() auf.



  • hat so leider auch nicht funktioniert.

    letztendlich sieht der draw so aus:

    void TextBox::DrawTextboxMsg()
    {
        if (m_sTextMsg.empty())
            return;
    
        CDirect3D *pDirect3D = CDirect3D::Get();
        if (!pDirect3D)
            return;
    
        // set scissor rect to msgbox area
        RECT pRect = { 50, 400, 300, 450};
        if (LPDIRECT3DDEVICE9 pDevice = pDirect3D->GetDevice())
            pDevice->SetScissorRect(&pRect);
    
        LPD3DXSPRITE pSprite = pDirect3D->GetSpriteForDraw();
    
        UINT uiBorderSize = 0;
        if (m_pTexture)
        {
            if (m_pTexture->m_TextureInfo.m_uiSpriteType == (UINT)SPRITE_TYPE_TEXTBOX)
                uiBorderSize = m_pTexture->m_TextureInfo.Type.Textbox.m_uiBorderSize;
        }
    
        std::string sMsg = m_sTextMsg.substr(0, m_uiShownLetters);
    
        RECT pos = {m_Position.x + uiBorderSize, m_Position.y + uiBorderSize, m_Position.x + m_uiSize.x - uiBorderSize, m_Position.y + m_uiSize.y - uiBorderSize };
        DirectFont::DrawFont(sMsg, pos, D3DXCOLOR(0.5f, 0.4f, 0.6f, 1), m_uiFontSize, 1000, m_sFontName, DT_LEFT, false, pSprite);
    
        pDirect3D->EndSpriteDraw();
        // set scissor rect to window size
        if (CGame *pGame = CGame::Get())
        {
            if (CGameInfo *pInfo = pGame->GetGameInfo())
            {
                Point<UINT> ScreenSize;
                pInfo->GetWindowSize(ScreenSize.x, ScreenSize.y);
                pRect.left = 0;
                pRect.top = 0;
                pRect.right = ScreenSize.x;
                pRect.bottom = ScreenSize.y;
                if (LPDIRECT3DDEVICE9 pDevice = pDirect3D->GetDevice())
                    pDevice->SetScissorRect(&pRect);
            }
        }
    }
    

    GetSpriteForDraw() fordert einfach nur ein Sprite an und startet ruft gleichzeitig ->Begin() auf.
    EndSpriteDraw() ruft ->End() für das letzte so übergebene Sprite auf.
    Die DrawFont Methode sieht so aus:

    void DirectFont::DrawFont(std::string sText, RECT pos, D3DXCOLOR color, UINT uiTextSize, UINT uiBoldness, std::string font, DWORD format, bool bItalic, LPD3DXSPRITE pSprite)
    {
        LPD3DXFONT m_pFontObj = NULL;
        CDirect3D *pDirect3D = CDirect3D::Get();
        if (!pDirect3D)
            return;
    
        D3DXFONT_DESC FontDesc = {uiTextSize, 0, uiBoldness, 1, bItalic, DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_PITCH, ""};
        strcpy_s(FontDesc.FaceName, font.c_str());
        HRESULT hr = D3DXCreateFontIndirect(pDirect3D->GetDevice(),&FontDesc,&m_pFontObj);
        if (hr != S_OK)
            return;
    
        m_pFontObj->DrawText(pSprite, sText.c_str(), -1, &pos, format, color);
    
        // release
        if(m_pFontObj != NULL)
        {
            m_pFontObj->Release();
            m_pFontObj = NULL;
        }
    }
    

    (ich weiß, nicht sonderlich performan, aber zum Testen reicht es erst einmal so, wenn ich jedes mal das Font obj neu erstelle).

    Ist eigentlich alles wichtige.

    mfg

    EDIT: das oben eingestellte ScissorRect sollte nur einen kleinen Teil des Textes sichtbar werden lassen, die Punkte stimmen soweit.



  • Also prinzipiell sollte RenderState aktivieren und Scissor Rect setzen passen.
    Aber ich hab keinen Einblick in dein State-Management und daher ist es eben leider schwer zu sagen was du da genau falsch machst, das müsste man einfach mal selber debuggen um da draufzukommen.
    Vor allem die D3DX Objekte verwenden intern State Blöcke, gut möglich dass dir das Sprite selbst also am Ende alles zusammenhaut.
    Ich kann dir nur empfehlen, dir mal PIX anzuschauen (kommt mit dem DirectX SDK) 😉



  • ok, danke für den tipp mit PIX, es lag tatsächlich am nicht gesetzten scissor test, obwohl ich ihn am anfang gesetzt habe o.O
    naja, ist erledigt 🙂


Anmelden zum Antworten