Dłubię sobie przy swoim projekcie aplikacji dla Tetrisa i jestem na etapie programowania paska stanu, który docelowo ma wyświetlać krótkie tekstowe informacje (niektóre dodatkowo z małymi obrazkami). Jego zawartość ma się płynnie zmieniać, a sama zmiana wyświetlanej etykiety ma wykorzystywać animowany efekt przejścia – obecny obraz ma płynnie przechodzić w drugi.
Jeśli by ktoś potrzebował kodu łączącego dwa obrazy (bez kanału alfa, np. 24-bitowe bitmapy) w jeden na podstawie poziomu z zadanej skali to niżej podaję przykładowy kod źródłowy procedury łączącej, a w załącznikach źródła testowego projektu dla Lazarusa oraz plik wykonywalny do szybkiego kuknięcia o co chodzi.
Do wykonania ww. czynności potrzebne są dwa obrazy źródłowe oraz jeden docelowy – dla uproszczenia użyłem wszystkich o takim samym rozmiarze. Potrzebna jest też wartość poziomu oraz maksimum skali – dla przykładu posłużę się procentami.
Im mniejszy procent, tym bardziej widoczny będzie pierwszy obraz źródłowy, im wyższy tym drugi. W przypadku wartości brzegowych (minimum i maksimum skali) obraz docelowy będzie taki sam jak pierwszy obraz źródłowy (minimum) lub drugi (maksimum).
procedure CombineImages(AImageA, AImageB, AImageDest: TPortableNetworkGraphic; ALevel, AScale: UInt8);
type
PPNGPixel = ^TPNGPixel;
TPNGPixel = record B, G, R, A: UInt8; end;
type
PPNGLine = ^TPNGLine;
TPNGLine = array [UInt16] of TPNGPixel;
var
LineA, LineB, LineDest: PPNGLine;
PixelA, PixelB, PixelDest: PPNGPixel;
var
LineIndex, PixelIndex: Integer;
begin
AImageDest.BeginUpdate();
try
for LineIndex := 0 to AImageA.Height - 1 do
begin
LineA := AImageA.ScanLine[LineIndex];
LineB := AImageB.ScanLine[LineIndex];
LineDest := AImageDest.ScanLine[LineIndex];
for PixelIndex := 0 to AImageA.Width - 1 do
begin
PixelA := @LineA^[PixelIndex];
PixelB := @LineB^[PixelIndex];
PixelDest := @LineDest^[PixelIndex];
PixelDest^.R := Round(PixelA^.R + (PixelB^.R - PixelA^.R) / AScale * ALevel);
PixelDest^.G := Round(PixelA^.G + (PixelB^.G - PixelA^.G) / AScale * ALevel);
PixelDest^.B := Round(PixelA^.B + (PixelB^.B - PixelA^.B) / AScale * ALevel);
end;
end;
finally
AImageDest.EndUpdate();
end;
end;
Wynik działania prezentuje poniższy zrzut:
Do łączenia dwóch kolorów wykorzystałem te same obliczenia, których użyłem w swoim platformerze do płynnej zmiany koloru tła w animacji staffu – jakiś czas temu pisałem o tej animacji na blogu, więc jeśli ktoś chce zobaczyć w czym rzecz to klikać w link – w dalszej części wpisu jest link do filmiku. ;)