Чертеж многострочный текст быстро в C++, MLTextOut


Мне нужно нарисовать много многострочный текст на экране, так что я впервые использовал то drawtext , но это было немного медленно... так что я смотрю на несколько вариантов: сохранить нарисованный текст в памяти контроллера, использующих Direct3D/с Direct2D, написать свою собственную функцию. Я не хочу, чтобы мои программы, чтобы быть свиньей памяти, используя память тока не слишком велика. Я не хочу быть зависимой в D3D, так что я остался с один вариант.

Вот мой распорядок рисовать многострочный текст, используя стандартный Windows интерфейс GDI. Он разбивает текст на строки (сплит \р\н'С), а затем вычисляет длину полной строки и оценкам, где он должен останавливаться.

Поскольку скорость имеет решающее значение, кто-нибудь видит оптимизации, я могу совершить, чтобы увеличить скорость?

bool MLTextOut(HDC hDC, int x, int y, int cx, int cy, CString str, int nLineHeight = 0)
{
    if (!hDC || cx <= 0 || cy <= 0)
        return false;

    if (str.IsEmpty() || x + cx <= 0 || y + cy <= 0)
        return true;

    const TCHAR *lpszEnd = (const TCHAR *)str + str.GetLength();
    const TCHAR *p1 = str, *p2, *p3, *p4;
    SIZE sz;
    int yInc = 0, n;
    RECT rc = {x, y, x + cx, y + cy};
    bool bContinue;

    while (true)
    {
        p2 = _tcsstr(p1, _T("\r\n"));
        if (!p2)
            p2 = lpszEnd;

        // check if we're already out of the rect

        if (y + yInc >= rc.bottom)
            break;

        // calculate line length

        GetTextExtentPoint32(hDC, p1, p2 - p1, &sz);

        // if line fits

        if (sz.cx <= cx)
        {
            //TextOut(hDC, x, y + yInc, p1, p2 - p1);
            ExtTextOut(hDC, x, y + yInc, ETO_CLIPPED, &rc, p1, p2 - p1, NULL);
            yInc += (nLineHeight ? nLineHeight : sz.cy);
        }

        // when line does not fit

        else
        {
            // estimate the line break point in characters

            n = ((p2 - p1) * cx) / sz.cx;
            if (n < 0)
                n = 0;

            // reverse find nearest space

            for (p3 = p1 + n; p3 > p1; p3--)
                if (*p3 == _T(' '))
                    break;

            // if it's one word spanning this line, but it doesn't fit... let's clip it

            if (p3 == p1)
            {
                // find first space on line

                for (p3 = p1; p3 < p2; p3++)
                    if (*p3 == _T(' '))
                        break;

                ExtTextOut(hDC, x, y + yInc, ETO_CLIPPED, &rc, p1, p3 - p1, NULL);
                yInc += (nLineHeight ? nLineHeight : sz.cy);

                p1 = (p3 == p2 ? p2 + 2 : p3 + 1);
                continue;
            }

            // see if p3 as line end fits

            GetTextExtentPoint32(hDC, p1, p3 - p1, &sz);
            if (sz.cx <= cx)
            {
                // try to add another word until it doesn't fit anymore

                p4 = p3;
                do
                {
                    p3 = p4; // save last position that was valid
                    for (p4 = p4+1; p4 < p2; p4++)
                        if (*p4 == _T(' '))
                            break;
                    if (p4 == p2)
                        break;

                    GetTextExtentPoint32(hDC, p1, p4 - p1, &sz);

                } while (sz.cx <= cx);

                ExtTextOut(hDC, x, y + yInc, ETO_CLIPPED, &rc, p1, p3 - p1, NULL);
                yInc += (nLineHeight ? nLineHeight : sz.cy);
                p1 = p3 + 1;
                continue;
            }
            else
            {
                // try to strip another word until it fits

                bContinue = false;

                do
                {
                    for (p4 = p3-1; p4 > p1; p4--)
                        if (*p4 == _T(' '))
                            break;

                    // if it's one word spanning this line, but it doesn't fit... let's clip it

                    if (p4 == p1)
                    {
                        // find first space on line

                        for (p3 = p1; p3 < p2; p3++)
                            if (*p3 == _T(' '))
                                break;

                        ExtTextOut(hDC, x, y + yInc, ETO_CLIPPED, &rc, p1, p3 - p1, NULL);
                        yInc += (nLineHeight ? nLineHeight : sz.cy);

                        p1 = (p3 == p2 ? p2 + 2 : p3 + 1);
                        bContinue = true;
                        break;
                    }
                    p3 = p4;
                    GetTextExtentPoint32(hDC, p1, p3 - p1, &sz);

                } while (sz.cx > cx);

                if (bContinue)
                    continue;

                ExtTextOut(hDC, x, y + yInc, ETO_CLIPPED, &rc, p1, p3 - p1, NULL);
                yInc += (nLineHeight ? nLineHeight : sz.cy);
                p1 = p3 + 1;
                continue;
            }
        }

        if (p2 == lpszEnd)
            break;
        p1 = p2 + 2;
    }
    return true;
}


2556
8
c++
задан 11 сентября 2011 в 03:09 Источник Поделиться
Комментарии
3 ответа

Я бы разделил эту функцию на две части:


  1. Текст макета часть - найти позиции текста / строк текста. Вы
    можете использовать GetTextExtentPoint32 , как вы делали.

  2. И рисунок с помощью одного вызова PolyTextOut

Это позволит пропустить #1 Если текст не меняется между WM_PAINTs - в этом случае вы получите только один PolyTextOut звонок.

3
ответ дан 11 сентября 2011 в 03:09 Источник Поделиться

Я не принимать какие-либо время, чтобы попытаться выяснить, что вы метод или нет, но я бы посоветовал, при рисовании текста он почти всегда (я говорю амост, потому что можно нарваться на пограничные случаи, в которых ограничения по ресурсам сделать следующие не соответствующие действительности) быстрее, чтобы сохранить ваш текст, и обратить в большие куски, в зависимости от ваших потребностей, можно сделать синхронизируется с частотой кадров или на основе обратного вызова в вашем потоке пользовательского интерфейса.

0
ответ дан 11 сентября 2011 в 03:09 Источник Поделиться


  1. Время ваше решение, чтобы увидеть, если это действительно значительно быстрее, чем то drawtext. Я ожидал, что то drawtext, чтобы быть очень хорошо оптимизирован.

  2. Я написал такой код, используя бинарный поиск по длине, а не измерять длину. Это может быть не так быстро, как оценка количества символов, но это трудно понять без профилирования.

  3. Поскольку похоже, что вы не заботитесь о сложных скриптов (Вы делаете простой разрывы на местах), проверьте в разделе getcharacterplacement. Хотя он делает много вещей, которые вам не нужны, это может быть быстрее, поскольку вы можете установить ограничение на ширину в пикселях и оно прекратится как только превышается. Это может найти строку из текста в один звонок (только обратно до последнего места). Также, если вы держите дополнительная информация от этого вызова, вы можете использовать более быструю версию ExtTextOut, которые в противном случае пришлось бы пересчитывать кучу метрик.

  4. В PolyTextOut вызов, вероятно, хорошая идея. Вычислительной как только ломается и чертежа на одном дыхании, скорее всего, будет большая победа.

  5. При добавлении слова до перелива, рекомендуется замерять просто новое слово и прибавить их к общей сумме. В противном случае, вы измеряете большую часть линии несколько раз. (Опять же, это касается потому, что ты не можешь справиться со сложными скриптами.)

0
ответ дан 17 ноября 2011 в 12:11 Источник Поделиться