1

Тема: Заставка\скринсейвер "движущиеся иконки"

Программа использует файл с иконками ICONS32.PNG из дистрибутива KolibriOS.
misc.php?action=pun_attachment&item=155&download=0

Исходный код
program IconsMoves;

uses
  KolibriOS;

var
  WndWidth, WndHeight: LongWord;

const
  WS_NO_DRAW = $1000000;
  DEFAULT_STEP = 6;
  BACK_COLOR = $00555555;

type
  TBuf2DBuffer = packed record
    Img:    Pointer;
    Left:   SmallInt;
    Top:    SmallInt;
    Width:  LongWord;
    Height: LongWord;
    Color:  LongWord;
    BPP:    Byte;
  end;

var
  Buf2D: Pointer;
  Buf2DLibInit:         procedure;
  buf2d_create:         procedure(var Buffer: TBuf2DBuffer); stdcall;
  buf2d_draw:           procedure(var Buffer: TBuf2DBuffer); stdcall;
  buf2d_clear:          procedure(var Buffer: TBuf2DBuffer; Color: LongWord); stdcall;
  buf2d_bit_blt_transp: procedure(var DstBuffer: TBuf2DBuffer; X, Y: LongInt; const SrcBuffer: TBuf2DBuffer); stdcall;

function MemoryAllocate(Bytes: LongWord): Pointer; stdcall;
asm
        push ecx
        push ebx
        mov eax, 68
        mov ebx, 12
        mov ecx, Bytes
        int 64
        pop ebx
        pop ecx
end;

function MemoryReallocate(MemPtr: Pointer; Bytes: LongWord): Pointer; stdcall;
asm
        push ebx
        push ecx
        push edx
        mov eax, 68
        mov ebx, 20
        mov ecx, Bytes
        mov edx, MemPtr
        int 64
        pop edx
        pop ecx
        pop ebx
end;

function MemoryFree(MemPtr: Pointer): LongWord; stdcall;
asm
        push ecx
        push ebx
        mov eax, 68
        mov ebx, 13
        mov ecx, MemPtr
        int 64
        pop ebx
        pop ecx
end;

type
  Proc = procedure;

procedure InitLibrary(LibInit: Proc); stdcall;
const
  LIB_PATH = '/sys/lib/';

type
  PNameAddr = ^TNameAddr;
  TNameAddr = packed record
    Name: PAnsiChar;
    Addr: Pointer;
  end;

  PAddrName = ^TAddrName;
  TAddrName = packed record
    Addr: Pointer;
    Name: PAnsiChar;
  end;

  procedure StrCopy(StrFrom, StrTo: PAnsiChar);
  begin
    repeat
      StrTo^ := StrFrom^;
      Inc(StrFrom);
      Inc(StrTo);
    until PAnsiChar(StrFrom - 1)^ = #0;
  end;

  function StrEqual(Str1, Str2: PAnsiChar): Boolean;
  begin
    while (Str1^ = Str2^) and (Str1^ <> #0) do
    begin
      Inc(Str1);
      Inc(Str2);
    end;
    Result := Str1^ = Str2^;
  end;

  function DLLLoad(ImportTable: PAddrName): LongInt; stdcall;
  var
    ExportTable: PNameAddr;
    ProcAddr: Pointer;
    Name: PPAnsiChar;
    LibPath: array [0..32] of AnsiChar;
  begin
    Result := 1;
    StrCopy(LIB_PATH, LibPath);
    while ImportTable.Addr <> nil do
    begin
      StrCopy(ImportTable.Name, Pointer(LongInt(@LibPath) + Length(LIB_PATH)));
      ExportTable := LoadLibrary(LibPath);
      if ExportTable = nil then
        Exit;
      Name := PPAnsiChar(ImportTable.Addr);
      while Name^ <> nil do
      begin
        ProcAddr := GetProcAddress(ExportTable, Name^);
        if ProcAddr <> nil then
          Pointer(Name^) := ProcAddr
        else
          Exit;
        Inc(Name);
      end;
      if StrEqual(ExportTable.Name, 'lib_init') then
        InitLibrary(ExportTable.Addr);
      Inc(ImportTable);
    end;
    Result := 0;
  end;
asm
  pushad
  mov eax, offset MemoryAllocate
  mov ebx, offset MemoryFree
  mov ecx, offset MemoryReallocate
  mov edx, offset DLLLoad
  call LibInit
  popad
end;

type
  PImage = ^TImage;
  TImage = packed record
    Checksum: LongWord; // ((Width ROL 16) OR Height) XOR Data[0] ; ignored so far
    Width:    LongWord;
    Height:   LongWord;
    Next:     PImage;
    Previous: PImage;
    BPP:      LongWord; // one of IMAGE_BPP
    Data:     Pointer;
    Palette:  Pointer;  // used if BPP = (IMAGE_BPP1 or IMAGE_BPP2 or IMAGE_BPP4 or IMAGE_BPP8I)
    Extended: LongWord;
    Flags:    LongWord; // bitfield
    Delay:    LongWord; // used if Image.IsAnimated is set in Flags
  end;

var
  FileAttributes: TFileAttributes;
  BytesRead: LongWord;
  FilePath: PAnsiChar = '/sys/ICONS32.PNG';

  imgFile: Pointer;
  imgFileSize: LongWord;
  imgData: PImage;
  ImgWidth, ImgHeight: LongWord;

  LibImg: Pointer;
  LibImgLibInit: procedure;

  img_decode:  function(Data: Pointer; Length, Options: LongWord): PImage; stdcall;

type
  PElements = ^TElements;

  PElement = ^TElement;
  TElement = object
    Left: LongInt;
    Top: LongInt;
    Width: LongWord;
    Height: LongWord;
    ImgBuf: TBuf2DBuffer;
    Direction: Byte;
    Step: LongInt;
    Parent: PElements;
    procedure Init(aLeft, aTop: LongInt; aWidth, aHeight: LongWord; aImg: Pointer; aParent: PElements; aStep: LongInt; aDirection: Byte);
    procedure Move;
    procedure Draw;
  end;

  TArrayOfElements = array [0..0] of TElement;
  PArrayOfElements = ^TArrayOfElements;

  TElements = object
    Elements: PArrayOfElements;
    Width: LongWord;
    Height: LongWord;
    Count: LongInt;
    ImgBuf: TBuf2DBuffer;
    procedure Init(aCount: LongInt; Image: Pointer);
    procedure Move;
    procedure Draw;
  end;

procedure TElements.Init(aCount: LongInt; Image: Pointer);
var
  i: LongInt;
begin
  Randomize;
  GetMem(Elements, SizeOf(TElement) * aCount);
  Count := aCount;
  with ImgBuf do
  begin
    Left   := 0;
    Top    := 0;
    Width  := WndWidth;
    Height := WndHeight;
    Color  := BACK_COLOR;
    BPP    := 24;
  end;
  Width  := ImgBuf.Width;
  Height := ImgBuf.Height;
  buf2d_create(ImgBuf);
  for i := 0 to Pred(Count) do
    Elements[i].Init(Random(Width - ImgWidth), Random(Height - ImgWidth),
      ImgWidth, ImgWidth,
      Pointer(LongInt(ImgWidth) * LongInt(ImgWidth) * 4 * i  + LongInt(Image)),
      @Self, Random(DEFAULT_STEP) + 1, Random(4) + 1);
end;

procedure TElements.Move;
var
  i: LongInt;
begin
  for i := 0 to Pred(Count) do
    Elements[i].Move;
  Draw;
end;

procedure TElements.Draw;
begin
  buf2d_draw(ImgBuf); // выводим на экран
  buf2d_clear(ImgBuf, ImgBuf.Color); // закрашиваем буфер цветом фона
end;

procedure TElement.Init(aLeft, aTop: LongInt; aWidth, aHeight: LongWord; aImg: Pointer; aParent: PElements; aStep: LongInt; aDirection: Byte);
begin
  Left   := aLeft;
  Top    := aTop;
  Width  := aWidth;
  Height := aHeight;
  Parent := aParent;
  Step   := aStep;
  Direction := aDirection;
  with ImgBuf do
  begin
    Width  := aWidth;
    Height := aHeight;
    BPP    := 32;
    Img    := aImg;
  end;
end;

procedure TElement.Move;
var
  LastDirection: Byte;
begin
  LastDirection := Direction;
  case Direction of
    1:
      Begin
        Left := Left - Step;
        Top := Top - Step;
        If Left <= 0 Then
          Direction := 2
        Else
          If Top <= 0 Then
            Direction := 4;
      End;
    2:
      Begin
        Left := Left + Step;
        Top := Top - Step;
        If Left >= LongInt(Parent.Width - Width) Then
          Direction := 1
        Else
          If Top <= 0 Then
            Direction := 3;
      End;
    3:
      Begin
        Left := Left + Step;
        Top := Top + Step;
        If Left >= LongInt(Parent.Width - Width) Then
          Direction := 4
        Else
          If Top >= LongInt(Parent.Height - Height) Then
            Direction := 2;
      End;
    4:
      Begin
        Left := Left - Step;
        Top := Top + Step;
        If Left <= 0 Then
          Direction := 3
        Else
          If Top >= LongInt(Parent.Height - Height) Then
            Direction := 1;
      End;
  end;
  if LastDirection <> Direction then
    Step := Random(DEFAULT_STEP) + 1;
  Draw;
end;

procedure TElement.Draw;
begin
  buf2d_bit_blt_transp(Parent.ImgBuf, Left, Top, ImgBuf);
end;

var
  Elements: TElements;

procedure Idle;
begin
  Elements.Move;
end;

type
  TRGBQuad = packed record
    Blue:  Byte;
    Green: Byte;
    Red:   Byte;
    Alpha: Byte;
  end;

  TRGBQuadArray = array [0..0] of TRGBQuad;

procedure PrepareAlpha(Img: Pointer; W, H: LongWord);
var
  X, Y: LongWord;
begin
  for Y := 0 to Pred(H) do
    for X := 0 to Pred(W) do
      with TRGBQuadArray(Img^)[Y * W + X] do
        if Alpha = 0 then // приходится инвертировать альфа-канал
          Alpha := 255    // потому что buf2d работает только с инвертированным
        else
          Alpha := 255 - Alpha * 2 div 3;
end;

begin
  Buf2D                := LoadLibrary('/sys/lib/buf2d.obj');
  buf2dLibInit         := GetProcAddress(Buf2D, 'lib_init');
  buf2d_create         := GetProcAddress(Buf2D, 'buf2d_create');
  buf2d_draw           := GetProcAddress(Buf2D, 'buf2d_draw');
  buf2d_clear          := GetProcAddress(Buf2D, 'buf2d_clear');
  buf2d_bit_blt_transp := GetProcAddress(Buf2D, 'buf2d_bit_blt_transp');

  LibImg        := LoadLibrary('/sys/lib/libimg.obj');
  LibImgLibInit := GetProcAddress(LibImg, 'lib_init');
  img_decode    := GetProcAddress(LibImg, 'img_decode');

  InitLibrary(LibImgLibInit);
  InitLibrary(Buf2DLibInit);

  GetFileAttributes(FilePath, FileAttributes);
  imgFileSize := FileAttributes.Size;
  imgFile := HeapAllocate(imgFileSize);
  ReadFile(FilePath, imgFile^, imgFileSize, 0, BytesRead);
  imgData := img_decode(imgFile, imgFileSize, 0);
  HeapFree(imgFile);
  ImgWidth := imgData.Width;
  ImgHeight := imgData.Height;

  PrepareAlpha(imgData.Data, ImgWidth, ImgHeight);

  with GetScreenSize do
  begin
    WndWidth := Width;
    WndHeight := Height;
  end;

  Elements.Init(ImgHeight div ImgWidth, imgData.data);

  while True do
    case WaitEventByTime(3) of
      REDRAW_EVENT:
        begin
          BeginDraw;
          DrawWindow(0, 0, WndWidth, WndHeight, nil, 0, WS_NO_DRAW, CAPTION_NONMOVABLE);
          EndDraw;
        end;
      KEY_EVENT:
        Break;
      BUTTON_EVENT:
        if GetButton.ID = 1 then
          Break;
    else
      Idle;
    end;
end.

Прикладываю скомпилированное приложение IconsMoves.kex

Post's attachments

Иконка вложений 0.gif 1.58 Мб, 29 скачиваний с 2022-02-15 

Иконка вложений IconsMoves.kex 1.86 Кб, 54 скачиваний с 2022-02-15