-
Notifications
You must be signed in to change notification settings - Fork 6
/
Splash.pas
187 lines (162 loc) · 4.75 KB
/
Splash.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
unit Splash;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, GDIPAPI, GDIpOBJ, Activex;
type
TFormSplash = class(TForm)
TimerSplash: TTimer;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure TimerSplashTimer(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
procedure FormClick(Sender: TObject);
private
{ Private declarations }
protected
procedure WMNCHitTest(var message: TWMNCHitTest); message WM_NCHITTEST;
public
{ Public declarations }
procedure Execute;
end;
var
FormSplash: TFormSplash;
implementation
{$R *.dfm}
procedure TFormSplash.FormClose(Sender: TObject; var Action: TCloseAction);
begin
TimerSplash.Destroy;
Action := caFree;
end;
procedure TFormSplash.TimerSplashTimer(Sender: TObject);
begin
Close;
end;
procedure TFormSplash.FormKeyPress(Sender: TObject; var Key: Char);
begin
Close;
end;
procedure TFormSplash.WMNCHitTest(var message: TWMNCHitTest);
begin
Message.Result := HTCAPTION;
end;
procedure PremultiplyBitmap(Bitmap: TBitmap);
var
Row, Col: integer;
p: PRGBQuad;
PreMult: array [byte, byte] of byte;
begin
// precalculate all possible values of a*b
for Row := 0 to 255 do
for Col := Row to 255 do
begin
PreMult[Row, Col] := Row * Col div 255;
if (Row <> Col) then
PreMult[Col, Row] := PreMult[Row, Col]; // a*b = b*a
end;
for Row := 0 to Bitmap.Height - 1 do
begin
Col := Bitmap.Width;
p := Bitmap.ScanLine[Row];
while (Col > 0) do
begin
p.rgbBlue := PreMult[p.rgbReserved, p.rgbBlue];
p.rgbGreen := PreMult[p.rgbReserved, p.rgbGreen];
p.rgbRed := PreMult[p.rgbReserved, p.rgbRed];
inc(p);
dec(Col);
end;
end;
end;
type
TFixedStreamAdapter = class(TStreamAdapter)
public
function Stat(out statstg: TStatStg; grfStatFlag: DWORD): HResult;
override; stdcall;
end;
function TFixedStreamAdapter.Stat(out statstg: TStatStg;
grfStatFlag: DWORD): HResult;
begin
Result := inherited Stat(statstg, grfStatFlag);
statstg.pwcsName := nil;
end;
procedure TFormSplash.Execute;
var
Ticks: DWORD;
BlendFunction: TBlendFunction;
BitmapPos: TPoint;
BitmapSize: TSize;
exStyle: DWORD;
Bitmap: TBitmap;
PNGBitmap: TGPBitmap;
BitmapHandle: HBITMAP;
Stream: TStream;
StreamAdapter: IStream;
begin
// Enable window layering
exStyle := GetWindowLongA(Handle, GWL_EXSTYLE);
if (exStyle and WS_EX_LAYERED = 0) then
SetWindowLong(Handle, GWL_EXSTYLE, exStyle or WS_EX_LAYERED);
Bitmap := TBitmap.Create;
try
// Load the PNG from a resource
Stream := TResourceStream.Create(HInstance, 'SPLASH', RT_RCDATA);
try
// Wrap the VCL stream in a COM IStream
StreamAdapter := TFixedStreamAdapter.Create(Stream);
try
// Create and load a GDI+ bitmap from the stream
PNGBitmap := TGPBitmap.Create(StreamAdapter);
try
// Convert the PNG to a 32 bit bitmap
PNGBitmap.GetHBITMAP(MakeColor(0, 0, 0, 0), BitmapHandle);
// Wrap the bitmap in a VCL TBitmap
Bitmap.Handle := BitmapHandle;
finally
PNGBitmap.Free;
end;
finally
StreamAdapter := nil;
end;
finally
Stream.Free;
end;
ASSERT(Bitmap.PixelFormat = pf32bit,
'Wrong bitmap format - must be 32 bits/pixel');
// Perform run-time premultiplication
PremultiplyBitmap(Bitmap);
// Resize form to fit bitmap
ClientWidth := Bitmap.Width;
ClientHeight := Bitmap.Height;
// Position bitmap on form
BitmapPos := Point(0, 0);
BitmapSize.cx := Bitmap.Width;
BitmapSize.cy := Bitmap.Height;
// Setup alpha blending parameters
BlendFunction.BlendOp := AC_SRC_OVER;
BlendFunction.BlendFlags := 0;
BlendFunction.SourceConstantAlpha := 0; // Start completely transparent
BlendFunction.AlphaFormat := AC_SRC_ALPHA;
Show;
// ... and action!
Ticks := 0;
while (BlendFunction.SourceConstantAlpha < 255) do
begin
while (Ticks = GetTickCount) do
Sleep(10); // Don't fade too fast
Ticks := GetTickCount;
inc(BlendFunction.SourceConstantAlpha,
(255 - BlendFunction.SourceConstantAlpha) div 32 + 1); // Fade in
UpdateLayeredWindow(Handle, 0, nil, @BitmapSize, Bitmap.Canvas.Handle,
@BitmapPos, 0, @BlendFunction, ULW_ALPHA);
end;
finally
Bitmap.Free;
end;
// Start timer to hide form after a short while
TimerSplash.Enabled := True;
end;
procedure TFormSplash.FormClick(Sender: TObject);
begin
Close;
end;
end.