Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Спрашивали тут ;)


Страницы:   1 2

homm ©   (2007-10-21 15:05:00) 

Функция AlphaDraw. Принимаемый параметры — 2 32-х битных битмапа, на первый из них рисуется на второй, по альфа маске, которая содержится в резервных битах второго изображения. Изображение копируется на смещение X и Y, которые не должны быть отрицательны.

procedure AlphaDraw(DestBitmap, SourceBitmap: TBitmap; X, Y: Integer);
type
  ARGBQuad = array [0..0] of TRGBQuad;
  PARGBQuad = ^ARGBQuad;
  AByte = array [0..0] of Byte;
  PAByte = ^AByte;
var
  SL1, SL2: PARGBQuad;
  V1, V2: TRGBQuad;
  R: ^TRGBQuad;
  i, j: Integer;
  A_1, A: Integer;
  Delta1, Delta2: DWORD;
  W, H: Integer;
begin
  if (X >= DestBitmap.Width) or (Y >= DestBitmap.Height) then
    exit;
  W := min(SourceBitmap.Width, DestBitmap.Width-X);
  H := min(SourceBitmap.Height, DestBitmap.Height-Y);
  SL1 := DestBitmap.ScanLine[Y];
  SL2 := SourceBitmap.ScanLine[0];
  Delta1 := DWORD(DestBitmap.ScanLine[1]) - DWORD(DestBitmap.ScanLine[0]);
  Delta2 := DWORD(SourceBitmap.ScanLine[1]) - DWORD(SourceBitmap.ScanLine[0]);
  if CPUisMMX then begin
    asm
      pushad

      pxor mm0, mm0
      mov eax, $01010101
      movd mm5, eax
      punpcklbw mm5, mm0
      movq mm6, mm5
      psllw mm5, 8

      mov ecx, H
      push ecx
@@loop1:
        mov esi, [SL2]
        mov edi, [SL1]
        mov eax, [X]
        lea edi, [edi+ eax*4]
        mov ecx, W
@@loop2:

          movd mm1, [esi]
          punpcklbw mm1, mm0
          movd mm2, [edi]
          punpcklbw mm2, mm0

          mov al, [esi + 3]
          mov ah, al
          mov bx, ax
          shl eax, 16
          mov ax, bx

          movd mm4, eax
          punpcklbw mm4, mm0
          paddw mm4, mm6
          movq mm3, mm5
          psubw mm3, mm4

          pmullw mm1, mm3
          pmullw mm2, mm4

          paddw mm1, mm2

          psrlw mm1, 8

          packuswb mm1, mm0
          movd [edi], mm1

          add esi, 4
          add edi, 4
        dec ecx
        jnz @@loop2

        mov eax, [Delta1]
        add [SL1], eax
        mov eax, [Delta2]
        add [SL2], eax
      dec [esp]
      jnz @@loop1

      pop ecx
      emms
      popad
    end;
  end else begin
    for i := 0 to H-1 do begin
      for j := 0 to W-1 do begin
        V1 := SL1[j+X];
        V2 := SL2[j];
        A := V2.rgbReserved+1;
        A_1 := 256-V2.rgbReserved;
        R := @SL1[j+X];
        R.rgbBlue := (V2.rgbBlue*A_1+V1.rgbBlue*A) shr 8;
        R.rgbGreen := (V2.rgbGreen*A_1+V1.rgbGreen*A) shr 8;
        R.rgbRed := (V2.rgbRed*A_1+V1.rgbRed*A) shr 8;
      end;
      SL1 := Pointer(DWORD(SL1) + Delta1);
      SL2 := Pointer(DWORD(SL2) + Delta2);
    end;
  end;
end;


homm   (2007-10-21 21:27:00) [21]

> [14] antonn ©   (21.10.07 21:22)
> а в График32 куча всего и не нужные мне махинации с битмапами
> (в смысле разные битности и все такое)

Да нет, как я посмотрел, там вокруг TBitmap32 все крутится.


> давай, для коррекции:)

procedure GenAlphaTable;
var
  I: Integer;
  P: ^Longword;
begin
  GetMem(AlphaTable, 256*16);
  P := AlphaTable;
  for I := 1 to 256 do begin
    P^ := I + I shl 16;
    Inc(P);
    P^ := I;
    //PWORD(P)^ := $0;
    Inc(P);
  end;
  for I := 256 downto 1 do begin
    P^ := I + I shl 16;
    Inc(P);
    P^ := I + $1000000;
    Inc(P);
  end;
end;



procedure AlphaDraw(DestBitmap, SourceBitmap: TBitmap; X, Y: Integer);
type
  ARGBQuad = array [0..0] of TRGBQuad;
  PARGBQuad = ^ARGBQuad;
  AByte = array [0..0] of Byte;
  PAByte = ^AByte;
var
  SL1, SL2: PARGBQuad;
  V1, V2: TRGBQuad;
  R: ^TRGBQuad;
  i, j: Integer;
  A_1, A: Integer;
  Delta1, Delta2: DWORD;
  W, H: Integer;
begin
  if AlphaTable = nil then
    GenAlphaTable;
  if (X >= DestBitmap.Width) or (Y >= DestBitmap.Height) then
    exit;
  W := min(SourceBitmap.Width, DestBitmap.Width-X);
  H := min(SourceBitmap.Height, DestBitmap.Height-Y);
  SL1 := Pointer(Integer(DestBitmap.ScanLine[Y])+X*4);
  SL2 := SourceBitmap.ScanLine[0];
  Delta1 := DWORD(DestBitmap.ScanLine[1]) - DWORD(DestBitmap.ScanLine[0]);
  Delta2 := DWORD(SourceBitmap.ScanLine[1]) - DWORD(SourceBitmap.ScanLine[0]);
  if CPUisMMX then begin
    asm
      pushad

      //pxor mm0, mm0
      db $0F, $EF, $C0
      mov eax, $01010101
      //movd mm5, eax
      db $0F, $6E, $E8
      //punpcklbw mm5, mm0
      db $0F, $60, $E8
      //movq mm6, mm5
      db $0F, $6F, $F5
      //psllw mm5, 8
      db $0F, $71, $F5, $08

      xor edx, edx
      mov ecx, H
      push ecx
@@loop1:
        mov esi, [SL2]
        mov edi, [SL1]
        mov ecx, W
@@loop2:

          //movd mm1, [esi]
          db $0F, $6E, $0E
          //punpcklbw mm1, mm0
          db $0F, $60, $C8
          //movd mm2, [edi]
          db $0F, $6E, $17
          //punpcklbw mm2, mm0
          db $0F, $60, $D0

          mov dl, [esi+3]
          mov ebx, [AlphaTable]
          lea ebx, [ebx+edx*8]
          movq mm3, [ebx]
          add ebx, 256*8
          movq mm4, [ebx]

          //pmullw mm1, mm3
          db $0F, $D5, $CB
          //pmullw mm2, mm4
          db $0F, $D5, $D4

          //paddw mm1, mm2
          db $0F, $FD, $CA

          //psrlw mm1, 8
          db $0F, $71, $D1, $08

          //packuswb mm1, mm0
          db $0F, $67, $C8
          //movd [edi], mm1
          db $0F, $7E, $0F

          add esi, 4
          add edi, 4
        dec ecx
        jnz @@loop2

        mov eax, [Delta1]
        add [SL1], eax
        mov eax, [Delta2]
        add [SL2], eax
      dec dword ptr [esp]
      jnz @@loop1

      pop ecx
      //emms
      db $0F, $77
      popad
    end;
  end else begin
    for i := 0 to H-1 do begin
      for j := 0 to W-1 do begin
        V1 := SL1[j];
        V2 := SL2[j];
        A_1 := V2.rgbReserved+1;
        if A_1 = 1 then
        else if A_1 = $100 then begin
          SL1[j] := SL2[j];
        end else begin
          A := 256-V2.rgbReserved;
          R := @SL1[j];
          R.rgbBlue := (V2.rgbBlue*A_1+V1.rgbBlue*A) shr 8;
          R.rgbGreen := (V2.rgbGreen*A_1+V1.rgbGreen*A) shr 8;
          R.rgbRed := (V2.rgbRed*A_1+V1.rgbRed*A) shr 8;
        end;
      end;
      SL1 := Pointer(DWORD(SL1) + Delta1);
      SL2 := Pointer(DWORD(SL2) + Delta2);
    end;
  end;
end;


По хорошему еше в конце обработки нужно где-то пристроить   FreeMem(AlphaTable);

ЗЫ Идея с GenAlphaTable полностью слизана с Graphics32, реализация осмыслена и переработана.


antonn   (2007-10-21 21:22:00) [22]


> antonn, а ты зачем сам решил велоспортом занятся? :)

мне нужна функция, которая обработает массив (в котором битмап, вообще это небольшая унификация некоторых вещей, но да ладно), а в График32 куча всего и не нужные мне махинации с битмапами (в смысле разные битности и все такое), короче я за велосипедный спорт! :)


> Выкладывать версию, которая не портит фоновую прозрачность?

давай, для коррекции:)
(обожаю ассемблерные процедурки, прям гоню на них:))


DVM   (2007-10-21 21:19:00) [23]

без MMX уже найти сложно. PentiumPRO может еще где.


homm   (2007-10-21 21:18:00) [24]

> [9] antonn ©   (21.10.07 20:58)
> не, я бы предпочел ту, которая берет наиболее яркую - если
> фон боле яркий - берем фон, если у накладываемого более
> яркая - берем ее (яркая - где более непрозрачная получается)
> . В версии без ММХ все пучком, но хочется в ММХ :)

С ММХ такое — врятли. Там всего 57 команд, вся суть в конвеерной обработке данных, без ветвлений.

Выкладывать версию, которая не портит фоновую прозрачность?


homm   (2007-10-21 21:16:00) [25]

antonn, а ты зачем сам решил велоспортом занятся? :)

Чем Graphics32 не устроил?


antonn   (2007-10-21 21:11:00) [26]

кстати, а сейчас вообще есть процессоры без поддержки ММХ, но наботающие под управлением вин2к минимум? :)


antonn   (2007-10-21 20:58:00) [27]

не, я бы предпочел ту, которая берет наиболее яркую - если фон боле яркий - берем фон, если у накладываемого более яркая - берем ее (яркая - где более непрозрачная получается). В версии без ММХ все пучком, но хочется в ММХ :)
procedure Bliting_alpha(BTSourc,BTDest:TBT; x,y:integer);
var SrcBits: DWORD; DstBits: DWORD;
   xTo, sx, YTo, ddx, ddy, sy, w, h, dstw, dsth: integer;
   inc1, inc2: integer;
begin
 w:= BTSourc.DIBWidth;
 h:= BTSourc.DIBHeight;
 dstw:= BTDest.DIBWidth;
 dsth:= BTDest.DIBHeight;
 XTo:= x+W-1;
 YTo:= y+H-1;
 if (y>=dstH) or (x>=dstW) or (YTo<0) or (XTo<0) then exit;
 asm
   xor  eax, eax
   mov  ddx, eax
   mov  ddy, eax
 end;
 sx:= W;
 sy:= H;

 if X<0 then
   begin
     ddx:= -X;
     inc( sx, X);
     x:= 0;
   end;

 if Y<0 then
   begin
     ddy:= -Y;
     inc( sy, Y);
     y:= 0;
   end;

 if XTo>=dstw then
   dec( sx, XTo-dstw+1);

 if YTo>=dsth then
   dec( sy, YTo-dsth+1);

 if (sx<=0) or (sy<=0) then exit;

     SrcBits := DWORD(@BTSourc.P^[ (ddy*BTSourc.DIBWidth)+ddx ]);
     DstBits := DWORD(@BTDest.P^[(y*BTDest.DIBWidth)+x ]);
     inc1:=BTDest.DIBWidth*SizeOf(BTElement);
     inc2:=BTSourc.DIBWidth*SizeOf(BTElement);

 asm
   push  ebx
   push  edi
   push  esi

 @outer_loop:
   mov   ecx, sx
   mov   edi, DstBits
   mov   esi, SrcBits
 @loop:
   mov   bl, byte ptr [esi+3]
   mov   bh, byte ptr [esi+3]
   and   bl, bl
   je    @skiptransparent

   mov   al, [esi]
   not   bh

   mul   al, bl
   mov   dl, ah
   mov   al, [edi]
   mul   al, bh
   add   dl, ah
   mov   [edi], dl

   mov   al, [esi+1]
   mul   al, bl
   mov   dl, ah
   mov   al, [edi+1]
   mul   al, bh
   add   dl, ah
   mov   [edi+1], dl

   mov   al, [esi+2]
   mul   al, bl
   mov   dl, ah
   mov   al, [edi+2]
   mul   al, bh
   add   dl, ah
   mov   [edi+2], dl

 @skiptransparent:
   add   esi, 4
   add   edi, 4
   dec   ecx
   jnz   @loop

 @l1:
   mov   ecx, inc1
   mov   eax, inc2
   add   DstBits, ecx
   add   SrcBits, eax
   dec   sy
   jnz   @outer_loop

   pop   esi
   pop   edi
   pop   ebx
 end;
end;


homm   (2007-10-21 20:53:00) [28]

> [7] antonn ©   (21.10.07 20:38)
> а еще в ней плохо то, что она обнуляет альфу конечного изображения
> в местах блитинга первого :(

Моя тоже обновляет. Хочешь версию, которая не обновляет? Счас попробуя состряпать.


antonn   (2007-10-21 20:38:00) [29]

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


homm   (2007-10-21 20:30:00) [30]

> [5] antonn ©   (21.10.07 20:22)
> if BTSourc.CPUisMMX then begin

А если нет, что будешь делать ;) ?


antonn   (2007-10-21 20:22:00) [31]

я уже нашел, для моего велосипедного класса:
procedure Bliting_alpha_MMX(BTSourc,BTDest:TBT; x,y:integer);
var SrcBits: DWORD;
     DstBits: DWORD;
     xTo, sx, YTo, ddx, ddy, sy, w, h, dstw, dsth: integer;
     inc1, inc2: integer;
begin
if BTSourc.CPUisMMX then begin
     SrcBits := DWORD(BTSourc.P);
     DstBits := DWORD(BTDest.p);
 w:= BTSourc.DIBWidth;
 h:= BTSourc.DIBHeight;
 dstw:= BTDest.DIBWidth;
 dsth:= BTDest.DIBHeight;
 XTo:= x+W-1;
 YTo:= y+H-1;
 if (y>=dstH) or (x>=dstW) or (YTo<0) or (XTo<0) then exit;
 asm
   xor  eax, eax
   mov  ddx, eax
   mov  ddy, eax
 end;
 sx:= W;
 sy:= H;

 if X<0 then
   begin
     ddx:= -X;
     inc( sx, X);
     x:= 0;
   end;

 if Y<0 then
   begin
     ddy:= -Y;
     inc( sy, Y);
     y:= 0;
   end;

 if XTo>=dstw then
   dec( sx, XTo-dstw+1);

 if YTo>=dsth then
   dec( sy, YTo-dsth+1);

 if (sx<=0) or (sy<=0) then exit;

     SrcBits := DWORD(@BTSourc.P^[ (ddy*BTSourc.DIBWidth)+ddx ]);
     DstBits := DWORD(@BTDest.P^[(y*BTDest.DIBWidth)+x ]);
     inc1:=BTDest.DIBWidth*SizeOf(BTElement);
     inc2:=BTSourc.DIBWidth*SizeOf(BTElement);
     asm
   push      edi
   push      esi

   pxor      mm7, mm7  

   mov       edx, $10101

   push      $000000FF  
   push      $00FF00FF
   movq      mm5, [esp]  

 @outer_loop:
   mov       esi, SrcBits
   mov       edi, DstBits
   mov       ecx, sx

 @inner_loop:
   mov       eax, [esi]
   movd      mm0, [esi]
   test      eax, $FF000000
   jz        @noblend
   shr       eax, 24
   add       esi, 4
   imul      eax, edx    
   punpcklbw mm0, mm7

   movd      mm6, eax
   movd      mm1, [edi]
   punpcklbw mm6, mm7
   punpcklbw mm1, mm7
   pmullw    mm0, mm6    
   pxor      mm6, mm5  
   pmullw    mm1, mm6  

   paddw     mm0, mm1  
   psrlw     mm0, 8    
   add       edi, 4

   packuswb  mm0, mm7    
   movd      [edi-4], mm0
   dec       ecx
   jnz       @inner_loop
   jmp       @endline

 @noblend:
   add       edi, 4
   add       esi, 4
   dec       ecx
   jnz       @inner_loop

 @endline:
   mov       ecx, inc1
   mov       eax, inc2
   add       DstBits, ecx
   add       SrcBits, eax
   dec       sy
   jnz       @outer_loop

   add       esp, 8
   emms
   pop       esi
   pop       edi
 end;
end;
end;


homm   (2007-10-21 17:30:00) [32]

Черт, зачем писал %)

Глянул Graphics32.

Их асемблерный вариант без ММХ работает даже быстрее моего ММХ-а. А уж их ММХ и подавно %)

Моя в печале.


homm   (2007-10-21 15:54:00) [33]

Вариант №2
производительность MMX версии +2%
производительность Pascal версии +11%
Добавлена совместимость с компилятором пятой дельфи.

procedure AlphaDraw(DestBitmap, SourceBitmap: TBitmap; X, Y: Integer);
type
  ARGBQuad = array [0..0] of TRGBQuad;
  PARGBQuad = ^ARGBQuad;
  AByte = array [0..0] of Byte;
  PAByte = ^AByte;
var
  SL1, SL2: PARGBQuad;
  V1, V2: TRGBQuad;
  R: ^TRGBQuad;
  i, j: Integer;
  A_1, A: Integer;
  Delta1, Delta2: DWORD;
  W, H: Integer;
begin
  if (X >= DestBitmap.Width) or (Y >= DestBitmap.Height) then
    exit;
  W := min(SourceBitmap.Width, DestBitmap.Width-X);
  H := min(SourceBitmap.Height, DestBitmap.Height-Y);
  SL1 := Pointer(DWORD(DestBitmap.ScanLine[Y])+X*4);
  SL2 := SourceBitmap.ScanLine[0];
  Delta1 := DWORD(DestBitmap.ScanLine[1]) - DWORD(DestBitmap.ScanLine[0]);
  Delta2 := DWORD(SourceBitmap.ScanLine[1]) - DWORD(SourceBitmap.ScanLine[0]);
  if CPUisMMX then begin
    asm
      pushad

      //pxor mm0, mm0
      db $0F, $EF, $C0
      mov eax, $01010101
      //movd mm5, eax
      db $0F, $6E, $E8
      //punpcklbw mm5, mm0
      db $0F, $60, $E8
      //movq mm6, mm5
      db $0F, $6F, $F5
      //psllw mm5, 8
      db $0F, $71, $F5, $08

      mov ecx, H
      push ecx
@@loop1:
        mov esi, [SL2]
        mov edi, [SL1]
        mov ecx, W
@@loop2:

          //movd mm1, [esi]
          db $0F, $6E, $0E
          //punpcklbw mm1, mm0
          db $0F, $60, $C8
          //movd mm2, [edi]
          db $0F, $6E, $17
          //punpcklbw mm2, mm0
          db $0F, $60, $D0

          mov ah, [esi + 3]
          mov al, ah
          shl eax, 8
          mov al, ah

          //movd mm4, eax
          db $0F, $6E, $E0
          //punpcklbw mm4, mm0
          db $0F, $60, $E0
          //paddw mm4, mm6
          db $0F, $FD, $E6
          //movq mm3, mm5
          db $0F, $6F, $DD
          //psubw mm3, mm4
          db $0F, $F9, $DC

          //pmullw mm1, mm3
          db $0F, $D5, $CB
          //pmullw mm2, mm4
          db $0F, $D5, $D4

          //paddw mm1, mm2
          db $0F, $FD, $CA

          //psrlw mm1, 8
          db $0F, $71, $D1, $08

          //packuswb mm1, mm0
          db $0F, $67, $C8
          //movd [edi], mm1
          db $0F, $7E, $0F

          add esi, 4
          add edi, 4
        dec ecx
        jnz @@loop2

        mov eax, [Delta1]
        add [SL1], eax
        mov eax, [Delta2]
        add [SL2], eax
      dec dword ptr [esp]
      jnz @@loop1

      pop ecx
      //emms
      db $0F, $77
      popad
    end;
  end else begin
    for i := 0 to H-1 do begin
      for j := 0 to W-1 do begin
        V1 := SL1[j];
        V2 := SL2[j];
        A := V2.rgbReserved+1;
        A_1 := 256-V2.rgbReserved;
        R := @SL1[j];
        R.rgbBlue := (V2.rgbBlue*A_1+V1.rgbBlue*A) shr 8;
        R.rgbGreen := (V2.rgbGreen*A_1+V1.rgbGreen*A) shr 8;
        R.rgbRed := (V2.rgbRed*A_1+V1.rgbRed*A) shr 8;
      end;
      SL1 := Pointer(DWORD(SL1) + Delta1);
      SL2 := Pointer(DWORD(SL2) + Delta2);
    end;
  end;
end;


homm   (2007-10-21 15:07:00) [34]

Ах, да, самое главное забыл :)
MMX версия работатет в 2,7 раз быстрее паскалевской.


homm   (2007-10-21 15:05:00) [35]

> на первый из них рисуется на второй

на первый из них рисуется второй


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо