Конференция "Игры" » Быстрый канвас [Delphi, Windows, ХР]
 
  • CSS (06.08.09 19:07) [200]
    А у Вас не бывает ошибки "Canvas does not allow drawing." ? Как с ней бороться?
    Чем быстрее я пытаюсь делать вывод на форму тем больше и больше их выскакивает... =((

    > Beermonza ©   (06.08.09 18:55) [199]

    Было бы интересно... =)
  • Beermonza © (06.08.09 20:53) [201]
    Для начала вывод GDI, ...все знакомы уже ))

    Var
     DCs: HDC;
    ...
    DCs := GetDC(Form1.Handle);
    BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
    ReleaseDC(Form1.Handle, DCs);
    DeleteDC(DCs);



    ...если на экран, то так:

    Var
     DCs: HDC;
    ...
    DCs := GetDC(0);
    BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
    ReleaseDC(0, DCs);
    DeleteDC(DCs);



    X, Y - координаты начала отрисовки;
    W, H - габариты изображения;
    {битмап} - картинка, в указанном формате.

    Теперь как задать битмапы. По идее нужно два по размеру зоны отрисовки, первый - невидимый кадр, что потом выводится на экран, второй - статическая подложка, ...в играх используется как поверхность некоторой игровой карты. Чтобы быстро рисовать нужно двойной доступ к битмапам, как стандартный, в котором можно применить Canvas, так и через указатель на данный в памяти. Это способ через CreateDIBSection():

    Var
     BInfo: tagBITMAPINFO;
     PointerBuf: Pointer;
     BufScr: PChar;
     BufLine: Integer;
    ...
    BInfo.bmiHeader.biSize := SizeOf(tagBITMAPINFOHEADER);
    BInfo.bmiHeader.biWidth := W;         // длина буфера
    BInfo.bmiHeader.biHeight := H;         // высота буфера
    BInfo.bmiHeader.biPlanes := 1;         // как хранить данные (-1 - переворачивает)
    BInfo.bmiHeader.biBitCount := 24;    // глубина цвета (3 байта, R,G,B)
    BInfo.bmiHeader.biCompression := BI_RGB;

    // создается буфер
    Buf := TBitmap.Create();
    Buf.Handle := CreateDIBSection(Canvas.Handle, BInfo, DIB_RGB_COLORS, Pointer(BufScr),0,0);
    PointerBuf := Pointer(BufScr);
    // длина линии буфера в байтах
    BufLine:=W*3;
    // нужно для быстрой и безошибочной работы алгоритма на ассемблере
    If BufLine mod 4 <> 0 then BufLine:=((BufLine div 4)+1)*4;



    А если проще, то вот так:

    GetMem(BufScr, H*W*3);
    PointerBuf := Pointer(BufScr);
    BufLine:=W*3;
    If BufLine mod 4 <> 0 then BufLine:=((BufLine div 4)+1)*4;



    В любой момент заполнить массив буфера можно вот так, правда не быстро, но при возможности:
    // залить черным
    FillChar(BufScr^, W*H*3, 0);



    Теперь трюки. Допустим у нас есть подложка Back и буфер Buf, полный размер буфера известен BufLength := (H*W*3) div 8; - для ровного счета. Указатели мы получили в начале создания. Вот так быстро переносим одно изображение в другое:

     asm
       push esi
       push edx

       mov ecx, BufLength
       mov esi, PointerBack
       mov edx, PointerBuf

     @@mix:
       movq      xmm0, [esi]     // Back -> в регистр
       movq      [edx], xmm0     // Buf <- из регистра

       add esi, 8
       add edx, 8

       loop @@mix

       pop edx
       pop esi

       emms
     end;



    Остальное попробую сначала упростить, потом покажу. Пример работы показать не могу, ибо это игра, делается еще. Вы можете сами проверить без проблем.
  • Beermonza © (06.08.09 22:03) [202]
    Вот так рисуем в памяти на буфере кадра, ...это для целого изображения спрайта, без обрезки:

    type
     TRGB = packed record
       R: Byte;
       B: Byte;
       G: Byte;
     end;

     PRGB = ^TRGB;

    Var
     C, yy: Integer;
     Bits, MapBits: PChar;
     TexLine: Integer;
     TexPoint, MapPoint, BufPoint: PChar;
     TexPixel, MapPixel, BufPixel: PRGB;

    const C1: int64 = $FFFFFFFFFFFFFFFF;

    SW := {длина спрайта};
    SH := {высота спрайта};

    // определим нужно ли отрисовывать спрайт (это часть алгоритма обрезки, тут не показываю)
    C := ((SW+1)*3) div 8;
    If C > 0 then
     Begin
       // массивы изображения, текстуры, маски, и буфера куда отрисовываем
       Bits    := {массив текстуры};
       MapBits := {массив маски};
       TexLine := {длина строки в файтах};

       // координаты в буфере (это должны быть динамические данные)
       X := 10;
       Y := 10;

       // Указатель на певую строку текстуры, маски и фона
       TexPoint  := Bits;
       MapPoint  := MapBits;
       BufPoint  := BufScr + (H - 1 - X) * BufLine + Y * 3;    //формат 24 бита, 3 байта на пиксел

       asm // подготовка маски
         pxor      xmm7, xmm7
         movq      xmm3, C1
         PUNPCKLBW xmm3, xmm7
       end;
       
       // цикл по количеству строк в изображении спрайта
       For yy:=0 to SH-1 do
         Begin
           TexPixel := PRGB(TexPoint);
           MapPixel := PRGB(MapPoint);
           BufPixel := PRGB(BufPoint);

           asm
             push edi
             push esi
             push edx
             push ecx

             mov ecx, C
             mov esi, [TexPixel]
             mov edx, [BufPixel]
             mov edi, [MapPixel]

           @@1:
             // это алгоритм отброса пикселей с полной прозрачностью
             cmp dword ptr [edi], 0
             jne @@mix
             cmp dword ptr [edi+4], 0
             je  @@Next

           @@mix:
             // смешивание
             movq      xmm0, [esi]     // tex
             PUNPCKLBW xmm0, xmm7      // convert to word

             movq      xmm1, [edx]     // Buf
             PUNPCKLBW xmm1, xmm7
             psubw     xmm0, xmm1      // tex-Buf

             movq      xmm2, [edi]     // map
             PUNPCKLBW xmm2, xmm7

             pmullw    xmm0, xmm2      // (tex-Buf)*map
             psrlw     xmm0, 8         // shr 8
             paddw     xmm1, xmm0      // zone + (tex-Buf)*map shr 8

             pand      xmm1, xmm3
             packuswb  xmm1, xmm1      // convert to byte

             movq      [edx], xmm1

           @@next:
             add esi, 8
             add edx, 8
             add edi, 8
             loop @@1

             pop ecx
             pop edx
             pop esi
             pop edi
           end;
           
           // перемещение на следующую строку в изображении
           TexPoint := TexPoint + TexLine;
           MapPoint := MapPoint + TexLine;
           BufPoint := BufPoint - BufLine;
         end;

       asm
         emms
       end;

     end;



    Рисует ООЧЕНЬ быстро. Теперь момент, как и что за текстуры я использую и загружаю. В основном это PNG-файлы, ...полное сохранение цветов, альфа-канал и весят сравнительно мало. Вот так это происходит:

    uses
     PNGImage; // отличная библиотека, советую поискать
     ...

    type
     BGR = packed record
       B: Byte;
       G: Byte;
       R: Byte;
     end;

     TBGR = array [word] of BGR;

    Var
     PNGimg: TPNGObject;
     y: Integer;
     i, j: Word;
     Bits: ^TBGR;
     Alpha: PByteArray;
     TexBits, MapBits: PChar;
     ...

     // загрузка PNG-файла
     PNGimg := TPNGObject.Create;
     PNGimg.LoadFromFile({путь к файлу});
     ...

     // заполняем массив текстуры и маски спрайта
     For i := 0 to PNGimg.Height - 1 do
       Begin
         Bits := PNGimg.Scanline[i];
         Alpha := PNGimg.AlphaScanline[i];

         For j := 0 to PNGimg.Width - 1 do
           Begin
             y := j*3 + (i*(PNGimg.Width*3));  //24 бита, формула позиционирования в одномерном массиве

             TexBits[y]     := Chr(Bits[j].B);
             TexBits[y + 1] := Chr(Bits[j].G);
             TexBits[y + 2] := Chr(Bits[j].R);

             MapBits[y]     := Chr(Alpha[j]);
             MapBits[y + 1] := Chr(Alpha[j]);
             MapBits[y + 2] := Chr(Alpha[j]);
           end;
       end;



    TexBits и MapBits заполняются параллельно, и как видно, на первый взгляд, MapBits не рационально большой, хотя в исходном варианте в PNG он в 3 раза меньше по объему, ...но, это, только вещь кажущаяся ))) ...в отрисовке на ассемблере с MMX очень важно, чтобы данные шли параллельно, тогда легко забирая и обрабатывая по 8 байт скорость отрисовки увеличивается, нежели при расчете 3-х байт текстуры и 1-го байта маски. Есть еще один плюс такого увеличения массива маски, у нас есть независимое управление альфа-каналом по его трем составляющим R, G и B, т.е. можно, например, указать прозрачным какой-то один цвет а остальные оставить не прозрачными, в общем, варианты все, которые существуют.

    Надеюсь нет ошибок, упрощал без проверки, извините, если сразу не заработает, придется изучить и покопаться.
  • antonn © (06.08.09 22:16) [203]
    такой ерундой мы тоже занимались: http://pda.delphimaster.net/?id=1200150296&n=7

    PS я хз сколько ужрет у меня проца полноэкранное формирование кадра (тоже игру пишу :) ), просто там бамп, лайтмапы (причем они так же 32 битные), если надо рефракция (обычно типа колыхания водной поверхности, но тормозит нещадно в больших размерах).
  • Beermonza © (06.08.09 22:22) [204]
    У меня на Core 2 Duo 1,8GHz моя нещадно-огромная сцена ворочиется максимум на 30-40% загрузки CPU и 25 fps, и это еще не победа, работы ведутся.
  • Beermonza © (06.08.09 22:39) [205]
    На счет копирования одного изображения в другое, по одному размеру обоих, то я быстрее алгоритма, что показал, не придумал еще, ...особенно, когда идет массивный цикл сбора кадра, время копирования подложек ощутимо влияет на скорость общего вывода.
    А отрисовка не самая идеальная, ...нужно подумать, отправить за циклы всю статику, или полустатику, пока нет времени этим заниматься. Но и так уже кое-что ))

    Кстати, antonn, а что за формула для линзы применена, ...все искал, как-то не попал на то, от чего оттолкнуться. Заметил формулу, по которой я смешиваю? ...result := buf + (tex-buf)*map shr 8 и по каждой компоненте цвета, грубовато для линзы?
  • CSS (06.08.09 23:16) [206]
    > uses
    >  PNGImage; // отличная библиотека, советую поискать


    Поискал в поисковике...
    Часть ссылок дохлая, а остальные не устанавливаются в мою Делфи 7...

    Где-нибудь есть офф.сайт у него (а то может мне просто какую-то фигню подсунули)? =))
  • antonn © (07.08.09 00:01) [207]

    > Beermonza ©   (06.08.09 22:39) [205]

    у меня для линзы в бенчмарке маска, делал по примеру фастлиба :)


    > CSS   (06.08.09 23:16) [206]

    просто скачай, и не устанавливай, просто подключай модули, вот тут типа пример перегона в Tbitmap c альфой:
    http://forum.vingrad.ru/forum/topic-267153/kw-pngimage.html
  • Beermonza © (07.08.09 00:17) [208]

    > antonn ©   (07.08.09 00:01) [207]
    > у меня для линзы в бенчмарке маска, делал по примеру фастлиба :)

    Переведи )) ...алгоритм посмотреть можно? ...ссылочку? ...я на откровенный гемор натыкаюсь с матрицами, или у тебя тоже так?
  • antonn © (07.08.09 01:22) [209]
    ну вот сам фаст_либ с примерами http://desksoft.ru/index.php?downloads=files&id=90
  • antonn © (07.08.09 01:22) [210]
    Правда это все таки не совсем линза, но похоже :)
  • Beermonza © (07.08.09 15:36) [211]
    Хорошо, спасибо, посмотрю.
  • имя (07.08.09 17:02) [212]
    Удалено модератором
  • CSS (16.08.09 05:20) [213]
    Beermonza, а всегда нужно делать так:

    //на форму
    DCs:=GetDC(Form1.Handle);
    BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
    ReleaseDC(Form1.Handle, DCs);
    DeleteDC(DCs);

    //на экран

    DCs:=GetDC(0);
    BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
    ReleaseDC(0, DCs);
    DeleteDC(DCs);



    Я всегда так делал:

    BitBlt(Form1.Handle, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);


    или так:
    BitBlt({битмап}.Canvas.Handle, 0, 0, W, H, GetDC(0), X, Y, SRCCOPY);



    Это хуже?



    А который ассемблер используется в Делфи? Tasm, Masm или какой-то свой?
    Я нигде не могу найти информацию по применению именно ассемблерных вставок для Делфи, а не просто по трансляторам...
    И не найдётся ли что-нибудь про этот MMX чтоб для начинающих было? Очень хочется разобраться в Ваших примерах... =)

    > очень важно, чтобы данные шли параллельно, тогда легко забирая
    > и обрабатывая по 8 байт скорость отрисовки увеличивается,
    >  нежели при расчете 3-х байт текстуры и 1-го байта маски.


    Может "по 6 байт" или я чего-то не понял? =(


    А как может быть "прозрачным какой-то один цвет" я даже представить не могу... =)
  • antonn © (16.08.09 11:21) [214]

    > Может "по 6 байт" или я чего-то не понял? =(

    там все равно выравнивание будет, до 4х байт, к тому же битмап может быть с альфаканалом и как раз 4 байта на пиксель - ARGB.

    прозрачный цвет - transparentcolor, это св-во у TImage например :)
  • CSS (16.08.09 13:22) [215]
    > antonn ©   (16.08.09 11:21) [214]

    Да я про 202-й пост, предпоследний абзац (в самом конце)... =)
  • antonn © (16.08.09 15:25) [216]
    ну два пикселя разом, видимо :)
  • Beermonza © (19.08.09 23:46) [217]
    > CSS © (16.08.09 05:20) [213]
    > Beermonza, а всегда нужно делать так:

    > //на форму
    > DCs:=GetDC(Form1.Handle);
    > BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
    > ReleaseDC(Form1.Handle, DCs);
    > DeleteDC(DCs);

    Нет, не всегда. Это общее понятие о контексте формы и его использование. Нам нужен быстрый доступ, вот мы и получаем контекст устройства и храним его, зачем каждый раз делать одни и те же не нужные действия. Я беру контекст в OnCreate формы:

    DCs:=GetDC(Form1.Handle);



    ... освобождаю его в OnDestroy формы:

    ReleaseDC(Form1.Handle, DCs);
    DeleteDC(DCs);



    ...сам BitBlt в конце процедуры построения кадра:

    BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);



    > CSS © (16.08.09 05:20) [213]
    > А который ассемблер используется в Делфи? Tasm, Masm или какой-то свой?
    > Я нигде не могу найти информацию по применению именно ассемблерных
    > вставок для Делфи, а не просто по трансляторам...
    > И не найдётся ли что-нибудь про этот MMX чтоб для начинающих было?
    > Очень хочется разобраться в Ваших примерах... =)

    Классический, Tasm не поддерживается. По MMX вот тут есть немного: http://www.gamedev.ru/code/articles/?id=4272
    Примеры не мои, они собраны по описаниям, оптимизированы из кусков, и помогали мне в "поисках правды", в свое время, хорошие люди, за что им спасибо.

    > CSS © (16.08.09 05:20) [213]
    > Может "по 6 байт" или я чего-то не понял? =(

    В MMX-технологии фишка в том, что процессор с ее поддержкой имеет 8 дополнительных 64-разрядных регистра, обычные регистры - 32-разрядные, ...т.е. мы можем ворочить сразу по 8 байт информации, вместо стандартных 4-й, ...от это значительный прирост производительности кода, при обработке параллельных массивов. Мы специально проверяем наши загруженные текстуры на предмет деления строки пикселей на 4, чтобы задать длину таким образом, чтобы было как можно меньше лишних байт, если длина окажется не четной, ...ведь работать нам с текстурами 24-битными - это по 3 байта на пиксел, альфа-канала тут нет, он отдельно. Давайте покажу структурно.

    Вот так идут данные в массиве PChar:
    это наши 8 пикселей изображения, тут 24 байта.
    BGR BGR BGR BGR BGR BGR BGR BGR

    а вот так берет эти же данные код на ассемблере
    BGRBGRBG RBGRBGRB GRBGRBGR - это текстура
    BGRBGRBG RBGRBGRB GRBGRBGR - это альфа-канал
    BGRBGRBG RBGRBGRB GRBGRBGR - это задний фон

    ...т.е. за 3 цикла он обработал по формуле смешивания 8 пикселей и наложил их на задний фон. Этот метод в 6 раз производительнее метода со сканированием ScanLine, судя по загрузке CPU.

    > CSS © (16.08.09 05:20) [213]
    > А как может быть "прозрачным какой-то один цвет" я даже представить
    > не могу... =)

    В FotoShop доводилось работать? ...в принципе это явление, когда в текстуре просвечивается только определенный тон, или все, или по выставленным уровням, эффект вычитания. Например, у вас есть текстура, полупрозрачная, значит в исходном варианте, например в PNG, 1 пиксел альфа-канала это 1 байт, ...а у нас альфа-канал - RGB, ...значит можно задать например врагмент текстуры с прозрачность не 100 100 100, а 50 100 100, в этом случае, фрагмент будет не только полупрозрачный, но и будет иной цвет прозрачности, т.е. этот альфа-канал просвечивает разные цвета по-разному. Если указать 0 100 100, то все красные тона не будет видно, а остальные останутся полупрозрачными, и т.д. и т.п. Разумеется, нужно подготавливать альфа-канал заранее, или как я показал, просто выдергивать его из PNG и разбрасывать на 3 составляющие, последующие эффекты в специальных кодах, матрицах, шаблонах, через которые пропускается массив альфа-канала.
  • Beermonza © (20.08.09 00:01) [218]
    Извините, увлекся, PhotoShop конечно же.
  • antonn © (20.08.09 00:34) [219]

    > Этот метод в 6 раз производительнее метода со сканированием
    > ScanLine, судя по загрузке CPU.
    >

    это если последовательно перебирать строки, в случае с поворотами там разница раз в 20 будет точно :)
 
Конференция "Игры" » Быстрый канвас [Delphi, Windows, ХР]
Есть новые Нет новых   [118456   +59][b:0.001][p:0.006]