Jump to content

Genie Effect Library


Recommended Posts

Hi, I'm trying to use RKLauncher RKGenieEffectDX DLLibrary

I found out that it has the following exports

- EffectCreate

- EffectDestroy

- EffectGetDisplayName

- EffectNextStep

But 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 here

http://www.aqua-soft.org/forum/index.php?s...st&p=526090

as a DLL would be perfect, so anyone could use at any dock/docklet

Link to comment

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 :P

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

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 to

accelerate 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

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.

aquasoft-separator.png

Edit

Ok, made some changes...

Added my unitLayeredWindow.pas:

unit unitLayeredWindow;

interface

uses 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';


implementation

var
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.1
Author: vhanla
This is a Genie Effect animation library sample
}
unit GenieFXsrc;

interface

uses
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 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 edi
end;


{
sl : start left
sr: start right
st: start top
sb: start bottom
el: end left
er: end right
et: end top
eb: end bottom
pgrap: pointer to bitmap

all 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;
begin
Form1:=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;
begin
end.

The library still needs a lot of improvement, but at least it runs smooth now. :)

aquasoft-separator.png

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; )

aquasoft-separator.png

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.1
Author: vhanla
This is a Genie Effect animation library sample
}
unit GenieFXsrc;

interface

uses
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 eax
end;
*)

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 edi
end;


{
sl : start left
sr: start right
st: start top
sb: start bottom
el: end left
er: end right
et: end top
eb: end bottom
pgrap: pointer to bitmap

all 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; // bordes

const
//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.

aquasoft-separator.png

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 eax
end;

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...

aquasoft-separator.png

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 eax
end;

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;

aquasoft-separator.png

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

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 fun

Source Code included, so anyone can improve, port to other languages, etc...

XDock.zip

Link to comment

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
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

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 :P sorry.

Link to comment

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 :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
popad
end;

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
popad
end;

procedure CopyBuffer(dst, src: pointer; count:cardinal);stdcall;assembler;
asm
pushad
cld
mov ecx, count
mov esi, src
mov edi, dst
rep movsd
popad
end;


{
sl : start left
sr: start right
st: start top
sb: start bottom
el: end left
er: end right
et: end top
eb: end bottom
pgrap: pointer to bitmap

all relative to screen size
}

procedure TForm1.GenieFX(pbmp: pgrap;sl,sr,st,sb,el,er,et,eb:integer);
const
DURATION = 1000; // animation duration in milliseconds
var
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 by vhanla
Link to comment
  • 3 weeks later...

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.

Edit

This was tested on XP only. http://codigobit.net/download/TaskFX.zip

Edited by vhanla
Link to comment

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

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...