vigil Posted June 3, 2009 Report Share Posted June 3, 2009 Hi, I'm trying to use RKLauncher RKGenieEffectDX DLLibraryI found out that it has the following exports- EffectCreate- EffectDestroy- EffectGetDisplayName- EffectNextStepBut I have no idea about the parameters they need.I'd like to use it to animate the minimization to the normal taskbar buttons.It would be good if someone could also improve vhanla's genie effect posted herehttp://www.aqua-soft.org/forum/index.php?s...st&p=526090as a DLL would be perfect, so anyone could use at any dock/docklet Link to comment
vhanla Posted June 3, 2009 Report Share Posted June 3, 2009 Actually that was a sample, and since I'm not good at graphics manipulation, it is very slow... BTW: I also need to know how to use RKLauncher's RKGenieEffectDX plugin if it's possible. However, I have written it to use it as a library Source Code and Sample included http://codigobit.net/download/geniefxlib.rar Messy code, hope you understand It only works from top to bottom minimization's animation Some questions: - I am using a form with a transparent color and painting on its canvas. Is it faster if I use a layered window with alpha image instead? - I'm using StretchBlt to draw line by line, is it faster to use scanlines, or gdiplus lockbits? I suppose yes, but I don't know how to do that, I mean a faster scanline stretch algorithm. BTW: I also included a tasks dock binary (based on Matonga's mirror dock sample) as an example, to give and idea. Link to comment
vigil Posted June 4, 2009 Author Report Share Posted June 4, 2009 Thanks my friend, I tested and works.But it is slow and sometimes while animating, it draws incorrectly. Maybe is because you're using the constant value STEP = 18 as a skip toaccelerate the slow animation, but with STEP=1 it works great, but too slow. I'm not good at graphics too, you know it, so I hope you can improve it.BTW: It would be good to add directions to minimize to. And of course the restore animation too.Regards! Link to comment
matonga Posted June 4, 2009 Report Share Posted June 4, 2009 Mmm... interesting, let's take a look at this code... The only thing I dunno is to render texture contents onto a layered window (WPF would do for Vista, but I'm aiming for something XP compatible ) @vigil & vhanla: The fastest way to do gfx is with hardware acceleration (either 2d or 3d). Of course one can write an MMX / SIMD / SSEx / whatever optimized routine, but video board acceleration is usually much faster. I can't promise anything because of lack of time, but I'll try and see if I can contribute with something. Edit Ok, made some changes... Added my unitLayeredWindow.pas: unit unitLayeredWindow;interfaceuses Windows, SysUtils, Forms, Graphics;procedure LWSetupForm (form : TForm);procedure LWSetImage (form : TForm; bmp : TBitmap);//-----------------------------------------const WS_EX_LAYERED = $80000; LWA_COLORKEY = 1; LWA_ALPHA = 2; ULW_COLORKEY = 1; ULW_ALPHA = 2; ULW_OPAQUE = 4; AC_SRC_ALPHA = 1;function SetLayeredWindowAttributes (hwnd : HWND; crKey : COLORREF; bAlpha : BYTE; dwFlags : DWORD) : BOOL; stdcall;function UpdateLayeredWindow (hwnd : HWND; dstHDC : HDC; ppDst : PPoint; ASize : PSize; srcHDC : HDC; pptSrc : PPoint; crKey : COLORREF; var bf : _BLENDFUNCTION; dwFlag : DWORD) : BOOL; stdcall;function SetLayeredWindowAttributes; external 'user32.dll' name 'SetLayeredWindowAttributes';function UpdateLayeredWindow; external 'user32.dll' name 'UpdateLayeredWindow';implementationvar buffer : TBitmap;procedure Preprocesar (bmp : TBitmap);var x, y : Integer; p : PByteArray;begin If bmp.PixelFormat <> pf32bit Then Exit; For y := 0 To bmp.Height-1 do begin p := bmp.Scanline[y]; For x := 0 To bmp.Width-1 do begin p[x*4 ] := (Integer(p[x*4 ]) * p[x*4+3]) div 255; p[x*4+1] := (Integer(p[x*4+1]) * p[x*4+3]) div 255; p[x*4+2] := (Integer(p[x*4+2]) * p[x*4+3]) div 255; end; end;end;procedure LWSetupForm (form : TForm);begin form.BorderStyle := bsNone; SetWindowLong (form.Handle, GWL_EXSTYLE, GetWindowLong (form.Handle, GWL_EXSTYLE) Or WS_EX_LAYERED);end;procedure LWSetImage (form : TForm; bmp : TBitmap);var y : Integer; bf : TBlendFunction; spt, dpt : TPoint; sz : TSize;begin If bmp.PixelFormat <> pf32bit Then Exit; buffer.PixelFormat := pf32bit; buffer.Width := bmp.Width; buffer.Height := bmp.Height; For y := 0 To bmp.Height-1 do Move (bmp.Scanline[y]^, buffer.Scanline[y]^, bmp.Width*4); Preprocesar (buffer); bf.BlendOp := AC_SRC_OVER; bf.BlendFlags := 0; bf.SourceConstantAlpha := $FF; bf.AlphaFormat := AC_SRC_ALPHA; spt.x := 0; spt.y := 0; sz.cx := buffer.Width; sz.cy := buffer.Height; dpt.x := form.Left; dpt.y := form.Top; UpdateLayeredWindow (form.Handle, form.Canvas.Handle, @dpt, @sz, buffer.Canvas.Handle, @spt, 0, bf, ULW_ALPHA);end;initialization buffer := TBitmap.Create;finalization buffer.Destroy;end. Added window clipping to minimal regions for faster animations, and use layered window with per pixel alpha instead of key color (much smoother because of that too): (GenieFXsrc.pas) {GenieFXLib v0.1Author: vhanlaThis is a Genie Effect animation library sample}unit GenieFXsrc;interfaceuses Windows, Messages, SysUtils, {Variants, }Classes, Graphics, Controls, Forms, Dialogs, WindowsEx, Math, unitLayeredWindow;type pgrap=^TBitmap; TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } procedure GenieFX(pbmp: pgrap;sl,sr,st,sb,el,er,et,eb:integer); end; type (* TRGB32 = packed record B,G,R,A:byte; end; *) TRGB32 = Cardinal; TRGB32Array=packed array[0..MaxInt div sizeof(TRGB32)-1] of TRGB32; PRGB32Array = ^TRGB32Array;var Form1: TForm1;implementation{$R *.dfm}{-$DEFINE USE_STRETCHBLT}// maybe faster than StretchBltprocedure LineBlit (src, dst : PRGB32Array; src_scanline_width, dst_scanline_width, dst_x, dst_width : Integer);var src_p, src_i, x : Integer;begin If dst_width = 0 Then Exit; src_p := 0; src_i := 256 * src_scanline_width div dst_width; // frustrum culling If dst_x + dst_width <= 0 Then Exit; If dst_x >= dst_scanline_width Then Exit; // clipping If dst_x + dst_width >= dst_scanline_width Then dst_width := dst_scanline_width - dst_x; If dst_x < 0 Then begin inc (src_p, src_i * (-dst_x)); dst_x := 0; end; // blitting For x := 0 To dst_width-1 do begin dst[dst_x + x] := src[src_p div 256] Or $FF000000; inc (src_p, src_i); end;end;procedure FillRGB32 (var dst; count : Cardinal); stdcall; assembler;asm push edi push eax push ecx mov edi, dst mov ecx, count //mov eax, $FF00FF sub eax, eax rep stosd pop ecx pop eax pop ediend; {sl : start leftsr: start rightst: start topsb: start bottomel: end lefter: end rightet: end topeb: end bottompgrap: pointer to bitmapall relative to screen size}procedure TForm1.GenieFX(pbmp: pgrap;sl,sr,st,sb,el,er,et,eb:integer);var i,j,w1,w2,h: integer; m1,m2:integer; l,r:array [0..5000]of integer; x,y,ya,y1,y2:real; bmp,bmpout,buffer:tbitmap;const //STEP = 24; //to control speed STEP = 1; (* BAAAAD WAY TO CONTROL SPEED!!! SHOULD SPECIFY DURATION IN SECONDS, INSTEAD Regards, ~ Matonga *)var al, at, ar, ab : Integer;begin // al := Min (sl, el); at := Min (st, et); ar := Max (sr, er); ab := Max (sb, eb); //SetWindowPos (Handle, 0, al, at, ar-al, ab-at, SWP_NOZORDER Or SWP_NOACTIVATE); Left := al; Top := at; Width := ar-al; Height := ab-at; dec (sl, al); dec (st, at); dec (sr, al); dec (sb, at); dec (el, al); dec (et, at); dec (er, al); dec (eb, at); // y1:=0.047425873;//1-1/(1+exp(-3)); y2:=0.952574126;//1-1/(1+exp(3)); h:=(et-st);//total height w1:=round(abs(sl-el)); //left width w2:=round(abs(sr-er)); //right width bmp:=tbitmap.Create; bmp.Height:=h; bmp.Width:=w1; bmp.Canvas.StretchDraw(rect(0,0,w1,h),pbmp^);//image1.Picture.Graphic); bmpout:=tbitmap.Create; bmpout.Height:=sr-sl; bmpout.Width:=w1; bmpout.Canvas.StretchDraw(rect(0,0,w1,sr-sl),pbmp^);//image1.Picture.Graphic); buffer:=tbitmap.Create; //buffer.Height:=canvas.ClipRect.Bottom-canvas.ClipRect.Top; //buffer.Width:=canvas.ClipRect.Right-canvas.ClipRect.Left; buffer.Height := ab - at; buffer.Width := ar - al; //buffer.Canvas.Brush.Color:=clFuchsia; //buffer.Canvas.FillRect(buffer.Canvas.ClipRect); // Force all bitmaps to 32 bits pbmp^.PixelFormat := pf32bit; bmp.PixelFormat := pf32bit; buffer.PixelFormat := pf32bit; bmpout.PixelFormat := pf32bit; //Animamos el encogido m1:=sl; m2:=sr; while (abs(m1-el)>STEP) or (abs(m2-er)>STEP) do begin //limpiamos el buffer {$IFDEF USE_STRETCHBLT} buffer.Canvas.FillRect(buffer.Canvas.ClipRect); {$ELSE} For i := 0 To buffer.Height-1 do FillRGB32 (buffer.Scanline[i]^, buffer.Width); {$ENDIF} for i:=0 to pbmp^.Height-1 do begin x:=i*6/h-3;//pbmp^.Height-3; y:=1-1/(1+exp(x)); ya:=(y-y1)/(y2-y1); if m1<el then l[i]:=sl+round(ya*round(abs(m1-sl))) else l[i]:=sl-round(ya*round(abs(m1-sl))); if m2<er then r[i]:=sr+round(ya*round(abs(m2-sr))) else r[i]:=sr-round(ya*round(abs(m2-sr))); //dibujamos linea por linea {$IFDEF USE_STRETCHBLT} StretchBlt(buffer.Canvas.Handle, l[i], st+i, r[i]-l[i],1, pbmp^.Canvas.Handle,0,i,pbmp^.Width,1,SRCCOPY); {$ELSE} If (st+i >= 0) And (st+i < buffer.Height) And (i >= 0) And (i < pbmp^.Height) Then LineBlit (pbmp^.Scanline[i], buffer.Scanline[st+i], pbmp^.Width, buffer.Width, l[i], r[i]-l[i]); {$ENDIF} end; //canvas.CopyRect(clientrect,buffer.Canvas,clientrect); LWSetImage (self, buffer); Sleep (1); //reducimos el tamanio if abs(m1-el)>STEP then begin if m1>el then m1:=m1-STEP; if m1<el then m1:=m1+STEP; end else begin if m1>el then m1:=m1-1; if m1<el then m1:=m1+1; end; if abs(m2-er)>STEP then begin if m2>er then m2:=m2-STEP; if m2<er then m2:=m2+STEP; end else begin if m2>er then m2:=m2-1; if m2<er then m2:=m2+1; end; end; {primero recolectamos la forma en un array} for i:=0 to h-1 do begin x:=i*6/h-3; y:=1-1/(1+exp(x)); ya:=(y-y1)/(y2-y1); if sl<el then l[h-i]:=el-round(ya*w1) else l[h-i]:=el+round(ya*w1); if sr<er then r[h-i]:=er-round(ya*w2) else r[h-i]:=er+round(ya*w2); end; {ahora dibujamos frames de bajada} j:=h-1; while j>=0 do begin j:=j-STEP; //limpiamos el buffer {$IFDEF USE_STRETCHBLT} buffer.Canvas.FillRect(buffer.Canvas.ClipRect); {$ELSE} For i := 0 To buffer.Height-1 do FillRGB32 (buffer.Scanline[i]^, buffer.Width); {$ENDIF} //dibujamos linea por linea for i:=0 to j-1 do begin {$IFDEF USE_STRETCHBLT} StretchBlt(buffer.Canvas.Handle, l[i+h-j],st+i+h-j,r[i+h-j]-l[i+h-j],1, bmp.Canvas.Handle,0,i,bmp.Width,1,SRCCOPY); {$ELSE} If (st+i+h-j >= 0) And (st+i+h-j < buffer.Height) And (i >= 0) And (i < bmp.Height) Then LineBlit (bmp.Scanline[i], buffer.Scanline[st+i+h-j], bmp.Width, buffer.Width, l[i+h-j], r[i+h-j]-l[i+h-j]); {$ENDIF} end; //canvas.CopyRect(clientrect,buffer.Canvas,clientrect); LWSetImage (self, buffer); Sleep (1); end; bmpout.free; buffer.Free; bmp.Free;end;procedure TForm1.FormCreate(Sender: TObject);begin (* DoubleBuffered:=True; //Application.ShowMainForm:=false; ShowWindow(Handle, SW_HIDE); SetWindowLong(Handle, GWL_EXSTYLE, getWindowLong(Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW); ShowWindow(Handle, SW_SHOW); BorderStyle:=bsNone; //WindowState:=wsMaximized; Height:=screen.Height; Width:=screen.Width; SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) Or WS_EX_LAYERED); SetLayeredWindowAttributes(Handle,$0ff00ff, 0, ULW_COLORKEY); SetWindowLong(Handle, GWL_STYLE, GetWindowLong(handle, GWL_STYLE) And Not WS_BORDER); *) SetWindowLong(Handle, GWL_EXSTYLE, (getWindowLong(Handle, GWL_EXSTYLE) And Not WS_EX_APPWINDOW) or WS_EX_TOOLWINDOW); LWSetupForm (self);end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);begin Action:=caFree;end;end. Made a change in .dpr, I dunno if it's important: (GenieFXLib.dpr) library GenieFXLib;{ Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters. }uses SysUtils, Classes, GenieFXsrc in 'GenieFXsrc.pas' {Form1}, WindowsEx in 'WindowsEx.pas', Windows;{$R *.res}procedure GenieFX(pbmp: pgrap;sl,sr,st,sb,el,er,et,eb:integer);stdcall;beginForm1:=TForm1.Create(nil);//Form1.show;ShowWindow (Form1.Handle, SW_SHOW);Form1.GenieFX(pbmp,sl,sr,st,sb,el,er,et,eb);Form1.Close;end;exports GenieFX;beginend. The library still needs a lot of improvement, but at least it runs smooth now. Edit BTW I forgot to mention in last post: Please don't pass a TBitmap!!! Even Delphi 5 is incompatible with that (I had to recompile both the .dll and the .exe demo to make them work together). Use a pointer to bytes instead, or at least an HBITMAP handle (can get TBitmap.Handle, can then use pbmp := TBitmap.Create; pbmp.Handle := the_handle; ..... do all stuff ..... pbmp.ReleaseHandle; pbmp.Destroy; ) Edit Didn't like the animation, so rewrote it from scratch. Plus now it uses duration (in milliseconds) instead of steps. GenieFXSrc.pas: {GenieFXLib v0.1Author: vhanlaThis is a Genie Effect animation library sample}unit GenieFXsrc;interfaceuses Windows, Messages, SysUtils, {Variants, }Classes, Graphics, Controls, Forms, Dialogs, WindowsEx, Math, unitLayeredWindow;type pgrap=^TBitmap; TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } procedure GenieFX(pbmp: pgrap;sl,sr,st,sb,el,er,et,eb:integer); end; type (* TRGB32 = packed record B,G,R,A:byte; end; *) TRGB32 = Cardinal; TRGB32Array=packed array[0..MaxInt div sizeof(TRGB32)-1] of TRGB32; PRGB32Array = ^TRGB32Array;var Form1: TForm1;implementation{$R *.dfm}{-$DEFINE USE_STRETCHBLT}// maybe faster than StretchBlt(*procedure ABlit (src, dst : Pointer; count, src_ini, src_inc : Cardinal); stdcall; assembler;asm push eax push ebx push ecx push edx push esi push edi mov esi, src mov edi, dst mov ecx, count mov edx, src_ini @loop: mov ebx, edx mov eax, [esi] add edx, src_inc or eax, $FF000000 shr ebx, 8 add esi, 4 shl ebx, 2 mov [edi+ebx], eax inc edi dec ecx jnz @loop pop edi pop esi pop edx pop ecx pop ebx pop eaxend;*)procedure LineBlit (src, dst : PRGB32Array; src_scanline_width, dst_scanline_width, dst_x, dst_width : Integer);var src_p, src_i, x : Integer;begin If dst_width = 0 Then Exit; src_p := 0; src_i := 256 * src_scanline_width div dst_width; // frustrum culling If dst_x + dst_width <= 0 Then Exit; If dst_x >= dst_scanline_width Then Exit; // clipping If dst_x + dst_width >= dst_scanline_width Then dst_width := dst_scanline_width - dst_x; If dst_x < 0 Then begin inc (src_p, src_i * (-dst_x)); dst_x := 0; end; // blitting For x := 0 To dst_width-1 do begin dst[dst_x + x] := src[src_p div 256] Or $FF000000; inc (src_p, src_i); end; //ABlit (src[0], dst[dst_x], dst_width, src_p, src_i); //ABlit (src, dst, dst_width, 0, 256);end;procedure FillRGB32 (var dst; count : Cardinal); stdcall; assembler;asm push edi push eax push ecx mov edi, dst mov ecx, count //mov eax, $FF00FF sub eax, eax rep stosd pop ecx pop eax pop ediend; {sl : start leftsr: start rightst: start topsb: start bottomel: end lefter: end rightet: end topeb: end bottompgrap: pointer to bitmapall relative to screen size}procedure TForm1.GenieFX(pbmp: pgrap;sl,sr,st,sb,el,er,et,eb:integer);var i,j,w1,w2,h: integer; m1,m2:integer; l,r:array [0..5000]of integer; x,y,ya,y1,y2:real; bmp,bmpout,buffer:tbitmap; bl, br : array[0..5000] of Integer; // bordesconst //STEP = 24; //to control speed //STEP = 1; DURATION = 1000; // animation duration in milliseconds (* BAAAAD WAY TO CONTROL SPEED!!! SHOULD SPECIFY DURATION IN SECONDS, INSTEAD Regards, ~ Matonga *)var al, at, ar, ab : Integer; sk, ek : Double; tick_s, tick_t : Cardinal; t : Double; y_ofs : Integer;var cbl, cbr : Integer;begin // al := Min (sl, el); at := Min (st, et); ar := Max (sr, er); ab := Max (sb, eb); //SetWindowPos (Handle, 0, al, at, ar-al, ab-at, SWP_NOZORDER Or SWP_NOACTIVATE); Left := al; Top := at; Width := ar-al; Height := ab-at; dec (sl, al); dec (st, at); dec (sr, al); dec (sb, at); dec (el, al); dec (et, at); dec (er, al); dec (eb, at); // y1:=0.047425873;//1-1/(1+exp(-3)); y2:=0.952574126;//1-1/(1+exp(3)); h:=(et-st);//total height w1:=round(abs(sl-el)); //left width w2:=round(abs(sr-er)); //right width bmp:=tbitmap.Create; bmp.Height:=h; bmp.Width:=w1; bmp.Canvas.StretchDraw(rect(0,0,w1,h),pbmp^);//image1.Picture.Graphic); bmpout:=tbitmap.Create; bmpout.Height:=sr-sl; bmpout.Width:=w1; bmpout.Canvas.StretchDraw(rect(0,0,w1,sr-sl),pbmp^);//image1.Picture.Graphic); buffer:=tbitmap.Create; //buffer.Height:=canvas.ClipRect.Bottom-canvas.ClipRect.Top; //buffer.Width:=canvas.ClipRect.Right-canvas.ClipRect.Left; buffer.Height := ab - at; buffer.Width := ar - al; //buffer.Canvas.Brush.Color:=clFuchsia; //buffer.Canvas.FillRect(buffer.Canvas.ClipRect); // Force all bitmaps to 32 bits pbmp^.PixelFormat := pf32bit; bmp.PixelFormat := pf32bit; buffer.PixelFormat := pf32bit; bmpout.PixelFormat := pf32bit; // Bordes... de otra manera. ~Matonga For i := st To et do begin sk := -Cos((et - i) / (et - st) * PI)*0.5+0.5; ek := 1.0 - sk; bl[i] := Round(sl * sk + el * ek); br[i] := Round(sr * sk + er * ek); end; //Animamos el encogido (* m1:=sl; m2:=sr; while (abs(m1-el)>STEP) or (abs(m2-er)>STEP) do begin //limpiamos el buffer {$IFDEF USE_STRETCHBLT} buffer.Canvas.FillRect(buffer.Canvas.ClipRect); {$ELSE} For i := 0 To buffer.Height-1 do FillRGB32 (buffer.Scanline[i]^, buffer.Width); {$ENDIF} for i:=0 to pbmp^.Height-1 do begin x:=i*6/h-3;//pbmp^.Height-3; y:=1-1/(1+exp(x)); ya:=(y-y1)/(y2-y1); if m1<el then l[i]:=sl+round(ya*round(abs(m1-sl))) else l[i]:=sl-round(ya*round(abs(m1-sl))); if m2<er then r[i]:=sr+round(ya*round(abs(m2-sr))) else r[i]:=sr-round(ya*round(abs(m2-sr))); //dibujamos linea por linea {$IFDEF USE_STRETCHBLT} StretchBlt(buffer.Canvas.Handle, l[i], st+i, r[i]-l[i],1, pbmp^.Canvas.Handle,0,i,pbmp^.Width,1,SRCCOPY); {$ELSE} If (st+i >= 0) And (st+i < buffer.Height) And (i >= 0) And (i < pbmp^.Height) Then LineBlit (pbmp^.Scanline[i], buffer.Scanline[st+i], pbmp^.Width, buffer.Width, l[i], r[i]-l[i]); {$ENDIF} end; //canvas.CopyRect(clientrect,buffer.Canvas,clientrect); LWSetImage (self, buffer); Application.ProcessMessages; //reducimos el tamanio if abs(m1-el)>STEP then begin if m1>el then m1:=m1-STEP; if m1<el then m1:=m1+STEP; end else begin if m1>el then m1:=m1-1; if m1<el then m1:=m1+1; end; if abs(m2-er)>STEP then begin if m2>er then m2:=m2-STEP; if m2<er then m2:=m2+STEP; end else begin if m2>er then m2:=m2-1; if m2<er then m2:=m2+1; end; end; {primero recolectamos la forma en un array} for i:=0 to h-1 do begin x:=i*6/h-3; y:=1-1/(1+exp(x)); ya:=(y-y1)/(y2-y1); if sl<el then l[h-i]:=el-round(ya*w1) else l[h-i]:=el+round(ya*w1); if sr<er then r[h-i]:=er-round(ya*w2) else r[h-i]:=er+round(ya*w2); end; *) tick_s := GetTickCount; tick_t := DURATION div 4; While True do begin t := (GetTickCount - tick_s) / tick_t; If t > 1.0 Then Break; For i := 0 To buffer.Height-1 do FillRGB32 (buffer.Scanline[i]^, buffer.Width); sk := Cos(t * PI)*0.5+0.5; ek := 1.0 - sk; For j := 0 To pbmp^.Height-1 do begin cbl := Round(sl * sk + bl[j+st] * ek); cbr := Round(sr * sk + br[j+st] * ek); If (st+j >= 0) And (st+j < buffer.Height) Then begin LineBlit (pbmp^.Scanline[j], buffer.Scanline[st+j], pbmp^.Width, buffer.Width, cbl, cbr-cbl); end; end; LWSetImage (self, buffer); end; {ahora dibujamos frames de bajada} (* j:=h-1; while j>=0 do begin j:=j-STEP; //limpiamos el buffer {$IFDEF USE_STRETCHBLT} buffer.Canvas.FillRect(buffer.Canvas.ClipRect); {$ELSE} For i := 0 To buffer.Height-1 do FillRGB32 (buffer.Scanline[i]^, buffer.Width); {$ENDIF} //dibujamos linea por linea for i:=0 to j-1 do begin {$IFDEF USE_STRETCHBLT} StretchBlt(buffer.Canvas.Handle, l[i+h-j],st+i+h-j,r[i+h-j]-l[i+h-j],1, bmp.Canvas.Handle,0,i,bmp.Width,1,SRCCOPY); {$ELSE} If (st+i+h-j >= 0) And (st+i+h-j < buffer.Height) And (i >= 0) And (i < bmp.Height) Then LineBlit (bmp.Scanline[i], buffer.Scanline[st+i+h-j], bmp.Width, buffer.Width, l[i+h-j], r[i+h-j]-l[i+h-j]); {$ENDIF} end; //canvas.CopyRect(clientrect,buffer.Canvas,clientrect); LWSetImage (self, buffer); Application.ProcessMessages; end; *) inc (tick_s, tick_t); tick_t := DURATION *3 div 4; While True do begin t := (GetTickCount - tick_s) / tick_t; If t > 1.0 Then Break; For i := 0 To buffer.Height-1 do FillRGB32 (buffer.Scanline[i]^, buffer.Width); y_ofs := st + Round((et-st)*t); For j := 0 To pbmp^.Height-1 do If (y_ofs+j >= st) And (y_ofs+j < et) And (y_ofs+j >= 0) And (y_ofs+j < buffer.Height) Then begin LineBlit (pbmp^.Scanline[j], buffer.Scanline[y_ofs+j], pbmp^.Width, buffer.Width, bl[y_ofs+j], br[y_ofs+j]-bl[y_ofs+j]); end; LWSetImage (self, buffer); end; bmpout.free; buffer.Free; bmp.Free;end;procedure TForm1.FormCreate(Sender: TObject);begin (* DoubleBuffered:=True; //Application.ShowMainForm:=false; ShowWindow(Handle, SW_HIDE); SetWindowLong(Handle, GWL_EXSTYLE, getWindowLong(Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW); ShowWindow(Handle, SW_SHOW); BorderStyle:=bsNone; //WindowState:=wsMaximized; Height:=screen.Height; Width:=screen.Width; SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) Or WS_EX_LAYERED); SetLayeredWindowAttributes(Handle,$0ff00ff, 0, ULW_COLORKEY); SetWindowLong(Handle, GWL_STYLE, GetWindowLong(handle, GWL_STYLE) And Not WS_BORDER); *) SetWindowLong(Handle, GWL_EXSTYLE, (getWindowLong(Handle, GWL_EXSTYLE) And Not WS_EX_APPWINDOW) or WS_EX_TOOLWINDOW); LWSetupForm (self);end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);begin Action:=caFree;end;end. Edit ABlit routine was not working, but now I found mistake, here is corrected version: procedure ABlit (src, dst : Pointer; count, src_ini, src_inc : Cardinal); stdcall; assembler;asm push eax push ebx push ecx push edx push esi push edi mov esi, src mov edi, dst mov ecx, count mov edx, src_ini @loop: mov ebx, edx shr ebx, 8 add edx, src_inc mov eax, [esi+ebx*4] or eax, $FF000000 mov [edi], eax dec ecx lea edi, [edi+4] jnz @loop pop edi pop esi pop edx pop ecx pop ebx pop eaxend;procedure LineBlit (src, dst : PRGB32Array; src_scanline_width, dst_scanline_width, dst_x, dst_width : Integer);var src_p, src_i{, x} : Integer;begin If dst_width = 0 Then Exit; src_p := 0; src_i := 256 * src_scanline_width div dst_width; // frustrum culling If dst_x + dst_width <= 0 Then Exit; If dst_x >= dst_scanline_width Then Exit; // clipping If dst_x + dst_width >= dst_scanline_width Then dst_width := dst_scanline_width - dst_x; If dst_x < 0 Then begin inc (src_p, src_i * (-dst_x)); dst_x := 0; end; // blitting (*For x := 0 To dst_width-1 do begin dst[dst_x + x] := src[src_p div 256] Or $FF000000; inc (src_p, src_i); end;*) ABlit (src, Pointer(Integer(dst)+dst_x*4), dst_width, src_p, src_i); //ABlit (src, dst, dst_width, 0, 256);end; I think it can be made even faster, somehow... Edit Ok, maybe faster: (should do a benchmark) procedure ABlit (src, dst : Pointer; count, src_ini, src_inc : Cardinal); stdcall; assembler;asm push eax push ebx push ecx push edx push esi push edi mov esi, src mov edi, dst mov ecx, count mov edx, src_inc ror edx, 16 mov src_inc, edx mov edx, src_ini ror edx, 16 sub ebx, ebx @loop: mov bx, dx add edx, src_inc mov eax, [esi+ebx*4] adc edx, 0 or eax, $FF000000 mov [edi], eax dec ecx lea edi, [edi+4] jnz @loop pop edi pop esi pop edx pop ecx pop ebx pop eaxend;procedure LineBlit (src, dst : PRGB32Array; src_scanline_width, dst_scanline_width, dst_x, dst_width : Integer);var src_p, src_i : Integer;begin If dst_width = 0 Then Exit; src_p := 0; src_i := 65536 * src_scanline_width div dst_width; // frustrum culling If dst_x + dst_width <= 0 Then Exit; If dst_x >= dst_scanline_width Then Exit; // clipping If dst_x + dst_width >= dst_scanline_width Then dst_width := dst_scanline_width - dst_x; If dst_x < 0 Then begin inc (src_p, src_i * (-dst_x)); dst_x := 0; end; // blitting ABlit (src, Pointer(Integer(dst)+dst_x*4), dst_width, src_p, src_i);end; Edit Ok, made a lot of code cleanup and uploaded at File2Go: http://www.file2go.net/view/7d6b30cdea Edit Forgot to mention: the version I uploaded to File2Go uses HBITMAP instead of ^TBitmap. This is *a lot* more compatible with other programming languages and other versions of Delphi. Link to comment
vhanla Posted June 4, 2009 Report Share Posted June 4, 2009 Wow! Matonga, this is awesome, it's even faster than RKGenieEffectDX animation.I've seen some crashes, I suppose it is due to starting bottom is greater than ending bottom, a minor problem.Some ideas: - It can have a different ending, for example, animate as a sand clock for fill a docklet- warp animation at ending- the limit is your imagination.___________________________________________________BTW: Here goes the Dock sample that uses this library, it is just a mess code, I do this for funSource Code included, so anyone can improve, port to other languages, etc...XDock.zip Link to comment
vigil Posted June 5, 2009 Author Report Share Posted June 5, 2009 Thank you for sharing such amazing source codes, both of you.I've seen Stardock's WindowFX has many other animations, maybe that library could have a bunch of different animations...Though I'm not good at programming, but just some ideas.BTW Systray doesn't work correctly on Vista 64bits, but on my XP pc works great. Hey vhanla, you could add that to that dock. Link to comment
vhanla Posted June 5, 2009 Report Share Posted June 5, 2009 Thank you for sharing such amazing source codes, both of you.Actually the latest Library (geniefx) was completely rewritten by Matonga, so the author becomes him, I gave an idea, tried to make it, but very slow. BTW Systray doesn't work correctly on Vista 64bits, but on my XP pc works great. Hey vhanla, you could add that to that dock.That's from my XWD Systray Docklet, I can't test on Vista 64bit, because I don't have it (OS and Hardware). Link to comment
matonga Posted June 5, 2009 Report Share Posted June 5, 2009 Ok, now it works when picture's bottom border is below the top border of destination (for e.g. Button1 in demo program, if you move it above the picture's bottom border). What does it do? the picture moves upwards while it's bottom border shrinks, it moves up to making bottom border coincide with button's top border (destination top border). This is exactly what Mac OS X does too. I'll post changes here, because I want to add the other three directions too. And BTW it seems I ignored sb at all, so original picture's height is used at all times sorry. Link to comment
Ghostwalker Posted June 5, 2009 Report Share Posted June 5, 2009 Man you guys this is cool,vHanla works with dual monitors also. Looked cool having the genie effect pull the window from one monitor to the dock on the other monitor. Link to comment
vhanla Posted June 5, 2009 Report Share Posted June 5, 2009 (edited) Some other projects about genie effect this is with Qt4 http://labs.trolltech.com/blogs/2008/12/15/genie-fx/ and this other one with Flex http://www.madeinflex.com/2008/01/29/efect...o-genie-effect/ (this one in spanish) Maybe they're of someone's interest BTW: I took code from the first one :P EDIT I don't know how you're dealing with the other directions. I was trying to do the following: 1st make a copy of the bitmap but rotated 90º degrees and change coordinates of sl,sr,st,sb,el,er,et,eb to match the rotation 2nd proceed normally and rotate back the modified buffer to show with LWSetImage Maybe there is a better approach procedure RoR( src,dst: pointer; step, count, starting:cardinal);stdcall;assembler;asm pushad mov ecx, count mov edi, dst mov esi, src mov ebx, step dec ebx sub ebx, starting add ebx, ebx add ebx, ebx xor edx, edx @lll: mov eax,[esi+edx] mov [edi+ebx],eax add ebx, step add ebx, step add ebx, step add ebx, step dec ecx add edx, 4 cmp ecx,0 jnz @lll popadend;procedure RoL( src,dst: pointer; step, count, starting:cardinal);stdcall;assembler;asm pushad mov ecx, count mov edi, dst mov esi, src mov ebx, starting add ebx, ebx add ebx, ebx xor edx, edx @lll: mov eax,[esi+edx] mov [edi+ebx],eax add ebx, step add ebx, step add ebx, step add ebx, step dec ecx add edx, 4 cmp ecx,0 jnz @lll popadend;procedure CopyBuffer(dst, src: pointer; count:cardinal);stdcall;assembler;asm pushad cld mov ecx, count mov esi, src mov edi, dst rep movsd popadend;{sl : start leftsr: start rightst: start topsb: start bottomel: end lefter: end rightet: end topeb: end bottompgrap: pointer to bitmapall relative to screen size}procedure TForm1.GenieFX(pbmp: pgrap;sl,sr,st,sb,el,er,et,eb:integer);const DURATION = 1000; // animation duration in millisecondsvar i, j : Integer; buffer,bmp, dmp:tbitmap; bl, br : array[0..5000] of Integer; // bordes al, at, ar, ab : Integer; sk, ek : Double; tick_s, tick_t : Cardinal; t : Double; y_ofs : Integer; cbl, cbr : Integer; buf: pbyte;begin //bmp is the manipulation buffer bmp:=tbitmap.create; bmp.PixelFormat:=pf32bit; dmp:=tbitmap.create; dmp.PixelFormat:=pf32bit; buffer:=tbitmap.Create; if (et>sb) then begin al := Min (sl, el); at := Min (st, et); ar := Max (sr, er); ab := Max (sb, eb); Left := al; Top := at; Width := ar-al; Height := ab-at; dec (sl, al); dec (st, at); dec (sr, al); dec (sb, at); dec (el, al); dec (et, at); dec (er, al); dec (eb, at); bmp.Height:=sb-st; bmp.Width:=sr-sl; bmp.Canvas.Draw(0,0,pbmp^); buffer.Height := ab - at; buffer.Width := ar - al; // Force all bitmaps to 32 bits pbmp^.PixelFormat := pf32bit; buffer.PixelFormat := pf32bit; // Bordes... de otra manera. ~Matonga For i := st To et do begin sk := -Cos((et - i) / (et - st) * PI)*0.5+0.5; ek := 1.0 - sk; bl[i] := Round(sl * sk + el * ek); br[i] := Round(sr * sk + er * ek); end; //Animamos el encogido tick_s := GetTickCount; tick_t := DURATION div 4; While True do begin t := (GetTickCount - tick_s) / tick_t; If t > 1.0 Then Break; For i := 0 To buffer.Height-1 do FillRGB32 (buffer.Scanline[i]^, buffer.Width); sk := Cos(t * PI)*0.5+0.5; ek := 1.0 - sk; For j := 0 To bmp.Height-1 do begin cbl := Round(sl * sk + bl[j+st] * ek); cbr := Round(sr * sk + br[j+st] * ek); If (st+j >= 0) And (st+j < buffer.Height) Then begin LineBlit (bmp.Scanline[j], buffer.Scanline[st+j], bmp.Width, buffer.Width, cbl, cbr-cbl); end; end; LWSetImage (self, buffer); end; {ahora dibujamos frames de bajada} inc (tick_s, tick_t); tick_t := DURATION *3 div 4; While True do begin t := (GetTickCount - tick_s) / tick_t; If t > 1.0 Then Break; For i := 0 To buffer.Height-1 do FillRGB32 (buffer.Scanline[i]^, buffer.Width); y_ofs := st + Round((et-st)*t); For j := 0 To bmp.Height-1 do If (y_ofs+j >= st) And (y_ofs+j < et) And (y_ofs+j >= 0) And (y_ofs+j < buffer.Height) Then begin LineBlit (bmp.Scanline[j], buffer.Scanline[y_ofs+j], bmp.Width, buffer.Width, bl[y_ofs+j], br[y_ofs+j]-bl[y_ofs+j]); end; LWSetImage (self, buffer); end; end/////////////////////////////// LEFT //////////////////////////////////////////// else if (er<sl) and (et<sb) then begin //animate to left //so we need to make it relative to the rotation Left := el; i:=eb; eb:=screen.Width-el; el:=et; et:=screen.Width-er; er:=i; i:=sb; sb:=screen.Width-sl; sl:=st; st:=screen.Width-sr; sr:=i; al := Min (sl, el); at := Min (st, et); ar := Max (sr, er); ab := Max (sb, eb); Top := al; Width := ab-at; Height := ar-al; dec (sl, al); dec (st, at); dec (sr, al); dec (sb, at); dec (el, al); dec (et, at); dec (er, al); dec (eb, at); bmp.Height:=sb-st; bmp.Width:=sr-sl; buffer.Height := ab - at; buffer.Width := ar - al; // Force all bitmaps to 32 bits pbmp^.PixelFormat := pf32bit; buffer.PixelFormat := pf32bit; dmp.Height:=buffer.Width; dmp.Width:=buffer.Height; GetMem(buf,dmp.width*dmp.Height*4); // rotamos la imagen /rotate image for i:=0 to pbmp^.Height-1 do RoL(pbmp^.ScanLine[i],buf,pbmp^.Height,pbmp^.Width,i); for i:=0 to bmp.Height-1 do CopyBuffer(bmp.scanline[i],pointer(integer(buf)+i*bmp.Width*4),bmp.width); // Bordes... de otra manera. ~Matonga For i := st To et do begin sk := -Cos((et - i) / (et - st) * PI)*0.5+0.5; ek := 1.0 - sk; bl[i] := Round(sl * sk + el * ek); br[i] := Round(sr * sk + er * ek); end; //Animamos el encogido tick_s := GetTickCount; tick_t := DURATION div 4; While True do begin t := (GetTickCount - tick_s) / tick_t; If t > 1.0 Then Break; For i := 0 To buffer.Height-1 do FillRGB32 (buffer.Scanline[i]^, buffer.Width); sk := Cos(t * PI)*0.5+0.5; ek := 1.0 - sk; For j := 0 To bmp.Height-1 do begin cbl := Round(sl * sk + bl[j+st] * ek); cbr := Round(sr * sk + br[j+st] * ek); If (st+j >= 0) And (st+j < buffer.Height) Then begin LineBlit (bmp.Scanline[j], buffer.Scanline[st+j], bmp.Width, buffer.Width, cbl, cbr-cbl); end; end; // rotamos la imagen for i:=0 to buffer.Height-1 do RoR(buffer.ScanLine[i],buf,buffer.Height,buffer.Width,i); for i:=0 to dmp.Height-1 do CopyBuffer(dmp.scanline[i],pointer(integer(buf)+i*dmp.Width*4),dmp.width); LWSetImage (self, dmp); end; {ahora dibujamos frames de bajada} inc (tick_s, tick_t); tick_t := DURATION *3 div 4; While True do begin t := (GetTickCount - tick_s) / tick_t; If t > 1.0 Then Break; For i := 0 To buffer.Height-1 do FillRGB32 (buffer.Scanline[i]^, buffer.Width); y_ofs := st + Round((et-st)*t); For j := 0 To bmp.Height-1 do If (y_ofs+j >= st) And (y_ofs+j < et) And (y_ofs+j >= 0) And (y_ofs+j < buffer.Height) Then begin LineBlit (bmp.Scanline[j], buffer.Scanline[y_ofs+j], bmp.Width, buffer.Width, bl[y_ofs+j], br[y_ofs+j]-bl[y_ofs+j]); end; // rotamos la imagen for i:=0 to buffer.Height-1 do RoR(buffer.ScanLine[i],buf,buffer.Height,buffer.Width,i); for i:=0 to dmp.Height-1 do CopyBuffer(dmp.scanline[i],pointer(integer(buf)+i*dmp.Width*4),dmp.width); LWSetImage (self, dmp); end; freemem(buf); end else if (el>sr) and (et<sb) then begin // animate to right end else if eb<st then begin //animate to top end else begin //?? end; bmp.free; dmp.free; buffer.Free;end; geniefxlibLeft_Bottom.zip BTW: How can it be possible to animate many at the same time? Like this video shows http://is.gd/WhrF EDIT Ha ha ha, I didn't notice the picture mirrored, to fix that, after RoL call it should be CopyBuffer(bmp.scanline[bmp.Height-1-i],pointer(integer(buf)+i*bmp.Width*4),bmp.width); EDIT (Back home after a bored day at the university) I forgot to upload this four side animation approach I did this morning geniefxlib3.zip Edited June 11, 2009 by vhanla Link to comment
vhanla Posted June 24, 2009 Report Share Posted June 24, 2009 (edited) Hi, I did a minmax hook to apply GenieFXLib and it works.However, there are some applications I like, that restores and minimizes some applications, for example, WinExposé (it does that to minimized windows) among others. And when this happens the hook does what it is meant to do (in this case, it interferes).1:I guess those windows are with alpha set to 0 and restored, so I need to find out that in order to not apply the effect, and some other Layered windows, because some of them have their rect different and since PrintWindow returns blank I think a bitblt screenshot must be done.2:In GenieFXLib I'm trying to replace the original window by hiding it and showing the effect window, but I've seen it occurs a little blink, I guess I have to first put the replacement over it and hide the original after that. But I couldn't do that and what I tried to do is to change the alpha (not minimize because my hook triggers again) to 0 of the window for example after the shrinking animation (before the minimization animation) and it doesn't work. I found that after modifying the width of the effect window on geniefx procedure, changing another window's alpha value doesn't work. I don't know why. EditThis was tested on XP only. http://codigobit.net/download/TaskFX.zip Edited June 27, 2009 by vhanla Link to comment
matonga Posted June 30, 2009 Report Share Posted June 30, 2009 Wow, the TaskFX thing looks great!For TaskFX and WinExpose to work together, I think you can do a pretty nasty hack:- Find the PID for any process called WinExpose.exe- Find a window whose class is TForm1, belonging to such PID.- Check if such window has X position = 0. If this is the case, then don't apply the effect.However it would be much better for both TaskFX & WinExpose (and other FX apps too) to use a common library for such stuff. Someone at Aqua-Soft will finally have to write it, maybe based on Compiz-Fusion architecture or whatever.To avoid the flicker, you should print the window (PrintWindow) then create & show the effect window above the original window, with the contents of the original window pre-rendered into it, then hide the original window (all in this exact order). Of course this means you can't just use the .dll as it was written and you'll have to modify it (at least adding a callback in the animation procedure, it would suffice with just that).I'm not sure if the above paragraph is barely understandable for english speakers, please forgive me I'm just out from job. I'll review all this... later. Link to comment
Recommended Posts
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now