1 (изменено: Freeman, 05.12.2020 в 17:47)

Тема: Texture Generator

Этот пример генерирует случайным образом изображение.
Рисуется во весь экран, выход по нажатию клавиши.

misc.php?action=pun_attachment&item=64&download=0

Изначальный исходный код под Windows я взял с этого французского сайта

Как написано в Readme, лицензия "Creative Commons"

Generateur de texture---------------------
Url     : http://codes-sources.commentcamarche.ne … de-texture Auteur  : aymenk Date    : 03/08/2013
Licence :
=========

Ce document intitulй « Generateur de texture » issu de CommentCaMarche
(codes-sources.commentcamarche.net) est mis а disposition sous les termes de
la licence Creative Commons. Vous pouvez copier, modifier des copies de cette
source, dans les conditions fixйes par la licence, tant que cette note
apparaоt clairement.

Description :
=============

generateur de texture

И адаптировал его под KolibriOS.
Исходный код:

program TextureGenerator;

uses
  KolibriOS;

const
  WS_NO_DRAW           = $1000000;

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

  PLongA = ^TLongA;
  TLongA = array [0..0] of LongWord;
  PByteA = ^TByteA;
  TByteA = array [Word] of Byte;
  PRGBQuadA = ^TRGBQuadA;
  TRGBQuadA = array [Word] of TRGBQuad;

const
  B:  Integer = $100;
  BM: Integer = $FF;
  N:  Integer = $1000;
  Ni: Integer = $400000;
  NM: Integer = $FFF;
  NP: Integer = 12;
  B2: Integer = $202; // B + B + 2;

var
  P:   array [0..$202] of Integer;
  G1:  array [0..$202] of Double;
  G2:  array [0..$202, 0..1] of Double;
  G2i: array [0..$202, 0..1] of Integer;
  G3:  array [0..$202, 0..2] of Double;
  G3i: array [0..$202, 0..2] of Integer;

  bmg: PLongA;
  Map, Map1: PLongA;

  HighMap:  LongInt;
  MapSizeX: LongWord;
  MapSizeY: LongWord;

  WndHeight, WndWidth: LongWord;

function Random: Extended;
begin
  Random := LongWord(System.Random($FFFFFFFF)) / $FFFFFFFF;
end;

function Round(Value: Extended): Int64;
asm
  FLD Value
  SUB ESP, 8
  FISTP qword ptr [ESP]
  FWAIT
  POP EAX
  POP EDX
end;

function Trunc(Value: Extended): Int64;
asm
  FLD Value
  SUB ESP, 12
  FNSTCW word ptr [ESP]
  FNSTCW word ptr [ESP + 2]
  FWAIT
  OR word ptr [ESP + 2], $0F00
  FLDCW word ptr [ESP + 2]
  FISTP qword ptr [ESP + 4]
  FWAIT
  FLDCW word ptr [ESP]
  POP ECX
  POP EAX
  POP EDX
end;

function Min(A, B: Integer): Integer; overload;
begin
  if A < B then
    Min := A
  else
    Min := B;
end;

function Min(A, B: Extended): Extended; overload;
begin
  if A < B then
    Min := A
  else
    Min := B;
end;

procedure InitNoise;
var
  I, J, T: Integer;
  len: Double;
begin
  Randomize;

  for i := 0 to B - 1 do
  begin
    P[i] := i;

    G1[i] := (Trunc(Random * 2 * B) - B) / B;

    G2[i, 0] := (Trunc(Random * 2 * B) - B) / B;
    G2[i, 1] := (Trunc(Random * 2 * B) - B) / B;
    len := Sqrt(G2[i, 0] * G2[i, 0] + G2[i, 1] * G2[i, 1]);
    if len > 1E-5 then
    begin
      G2[i, 0] := G2[i, 0] / len;
      G2[i, 1] := G2[i, 1] / len;
    end;

    G2i[i, 0] := Trunc(G2[i, 0] * 1024);
    G2i[i, 1] := Trunc(G2[i, 1] * 1024);

    G3[i, 0] := (Trunc(Random * 2 * B) - B) / B;
    G3[i, 1] := (Trunc(Random * 2 * B) - B) / B;
    G3[i, 2] := (Trunc(Random * 2 * B) - B) / B;
    len := Sqrt(G3[i, 0] * G3[i, 0] + G3[i, 1] * G3[i, 1] + G3[i, 2] * G3[i, 2]);
    if len > 1E-5 then
    begin
      G3[i, 0] := G3[i, 0] / len;
      G3[i, 1] := G3[i, 1] / len;
      G3[i, 2] := G3[i, 2] / len;
    end;

    G3i[i, 0] := Trunc(G3[i, 0] * 1024);
    G3i[i, 1] := Trunc(G3[i, 1] * 1024);
    G3i[i, 2] := Trunc(G3[i, 2] * 1024);
  end;

  for i := 0 to B - 1 do
  begin
    j := Trunc(Random * B);
    T := P[i];
    P[i] := P[j];
    P[j] := T;
  end;

  for i := 0 to B + 1 do
  begin
    P[B + i] := P[i];

    G1[B + i] := G1[i];

    G2[B + i][0] := G2[i][0];
    G2[B + i][1] := G2[i][1];

    G2i[B + i][0] := G2i[i][0];
    G2i[B + i][1] := G2i[i][1];

    G3[B + i][0] := G3[i][0];
    G3[B + i][1] := G3[i][1];
    G3[B + i][2] := G3[i][2];

    G3i[B + i][0] := G3i[i][0];
    G3i[B + i][1] := G3i[i][1];
    G3i[B + i][2] := G3i[i][2];
  end;
end;

function Noise2Di(const x, y: Integer): Integer;
var
  bx0, bx1, by0, by1: Integer;
  b00, b10, b01, b11: Integer;
  rx0, rx1, ry0, ry1: Integer;
  sx, sy, t, a, b, u, v: Integer;
  i, j: Integer;
  r: Integer;
begin
  t := x + $40000000;
  bx0 := (t shr 10) and $FF;
  bx1 := (bx0 + 1) and $FF;
  i := P[bx0];
  rx0 := t and 1023;
  rx1 := rx0 - 1024;

  t := y + $40000000;
  by0 := (t shr 10) and $FF;
  by1 := (by0 + 1) and $FF;
  j := P[bx1];
  ry0 := t and 1023;
  ry1 := ry0 - 1024;

  b00 := P[i + by0];
  b10 := P[j + by0];
  b01 := P[i + by1];
  b11 := P[j + by1];

  sx := (rx0 * rx0 * (3072 - 2 * rx0)) shr 20;
  sy := (ry0 * ry0 * (3072 - 2 * ry0)) shr 20;

  u := (rx0 * G2i[b00][0] + ry0 * G2i[b00][1]);
  v := (rx1 * G2i[b10][0] + ry0 * G2i[b10][1]);
  a := (u shl 10) + sx * (v - u);
  asm
    SAR a, 20
  end;

  u := (rx0 * G2i[b01][0] + ry1 * G2i[b01][1]);
  v := (rx1 * G2i[b11][0] + ry1 * G2i[b11][1]);
  b := (u shl 10)  + sx * (v - u);
  asm
    SAR b, 20
  end;

  r := a shl 10  + sy * (b - a);
  asm
    SAR r, 10
  end;

  Result := r;
end;

function Turbulence2Dia(x, y: Integer; const n: Integer): Integer;
var
  r, i: Integer;
  a: Integer;
begin
  r := 0;
  a := 1;

  for i := n - 1 downto 0 do
  begin
    Inc(r, Abs(Noise2Di(x, y)) div a);
    x := x shl 1;
    y := y shl 1;
    a := a shl 1;
  end;
  Result := r;
end;

procedure FormCreate;
begin
  MapSizeX := WndWidth;
  MapSizeY := WndHeight;

  Randomize;

  bmg := HeapAllocate(MapSizeX * MapSizeY * SizeOf(Map[0]));

  Map := HeapAllocate(MapSizeX * MapSizeY * SizeOf(Map[0]));
  Map1 := HeapAllocate(MapSizeX * MapSizeY * SizeOf(Map1[0]));
  HighMap :=  MapSizeX * MapSizeY - 1;

  InitNoise;
end;

procedure GenerateMap(Map: PLongA; HighMap: LongInt; const SizeX, SizeY: Word;
                      ScaleX: Double = 0; ScaleY: Double = 0; Octaves: Integer = -1;
                      OffsetX: Double = 0; OffSetY: Double = 0);
var
  x, y, i: Integer;
  v: Integer;
  Xi, Yi, DXi, DYi: Integer;
begin
  if (SizeX * SizeY) = 0 then
    Exit;

  if HighMap <> (Sizex * SizeY - 1) then
    Map := HeapAllocate(SizeX * SizeY * SizeOf(Map[0]));


  if octaves < 0 then
    Octaves := Round(Random * 8);

  if ScaleX = 0 then
    ScaleX := Sqrt(Random + 0.5);

  if ScaleY = 0 then
    ScaleY := Sqrt(Random + 0.5);

  if OffsetX = 0 then
    OffsetX := Random * 100;

  if OffsetY = 0 then
    OffsetY := Random * 100;

  Xi := Round(OffsetX * 1024);
  Yi := Round(OffsetY * 1024);
  DXI := Round(1024 * ScaleX / SizeX);
  DYI := Round(1024 * ScaleY / SizeY);

  i := 0;
  for y := 0 to SizeY - 1 do
  begin
    for x := SizeX - 1 downto 0 do
    begin
      v := Turbulence2Dia(XI, YI, Octaves) shr 2;

      Map[i] := (v shl 16) + (v shl 8) + v;
      Inc(i);
      Inc(XI, DXI);
    end;
    XI := Round(OffsetX * 1024);
    Inc(YI, DYI);
  end;
end;

procedure ColorizeBaseMap(Map: PLongA; HighMap: LongInt; Color: Integer = 0);
var
  Pal: array[0..255] of TRGBQuad;
  R, G, B: Integer;
  i: Integer;
begin
  if Color <> 0 then
  begin
    R := (Color and $FF0000) shr 16;
    G := (Color and $FF00) shr 8;
    B := Color and $FF;
  end
  else
    repeat
      R := Round(Random * 255);
      G := Round(Random * 255);
      B := Round(Random * 255);
    until (R + G + B) > 550;

  for i := 0 to 255 do
    with Pal[i] do
    begin
      Red   := Round(Min((i * R) / 127, 255));
      Green := Round(Min((i * G) / 127, 255));
      Blue  := Round(Min((i * B) / 127, 255));
    end;

  for i := 0 to HighMap do
    Map[i] := LongWord(Pal[Map[i] and $FF]);
end;

procedure PowMap(Map: PLongA; HighMap: LongInt);
var
  r, g, b, v, i: Integer;
begin
  for i := 0 to HighMap do
  begin
    v := Map[i];
    r := 255 - ((v and $FF0000) shr 16);
    g := 255 - ((v and $FF00) shr 8);
    b := 255 - (v and $FF);

    r := r * r div 256;
    g := g * g div 256;
    b := b * b div 256;
    Map[i] := r shl 16 + g shl 8 + b;
  end;
end;

procedure MultMap(Map1, Map2: PLongA; HighMap: LongInt);
var
  v, w, i: Integer;
  rv, gv, bv, rw, gw, bw, r, g, b: Integer;
begin
  for i := 0 to HighMap do
  begin
    v := Map1[i];
    w := Map2[i];
    rv := (v and $FF0000) shr 16;
    gv := (v and $FF00) shr 8;
    bv := v and $FF;
    rw := (w and $FF0000) shr 16;
    gw := (w and $FF00) shr 8;
    bw := w and $FF;
    r := Min(255, (((rv * 3) div 2 + 127) * rw) div 256);
    g := Min(255, (((gv * 3) div 2 + 127) * gw) div 256);
    b := Min(255, (((bv * 3) div 2 + 127) * bw) div 256);
    Map1[i] := r shl 16 + g shl 8 + b;
  end;
end;

procedure CreateMap;
var
  x, y, i: LongWord;
  Row: PRGBQuadA;
begin
  GenerateMap(Map, HighMap, MapSizeX, MapSizeY);
  ColorizeBaseMap(Map, HighMap);
  PowMap(Map, HighMap);
  GenerateMap(Map1, HighMap, MapSizeX, MapSizeY);
  ColorizeBaseMap(Map1, HighMap);
  PowMap(Map1, HighMap);
  MultMap(Map, Map1, HighMap);
  GenerateMap(Map1, HighMap, MapSizeX, MapSizeY);
  ColorizeBaseMap(Map1, HighMap);
  PowMap(Map1, HighMap);
  MultMap(Map, Map1, HighMap);

  i := 0;
  for y := 0 to MapSizeY - 1 do
  begin
    Row := PRGBQuadA(LongWord(bmg) + y * MapSizeX * SizeOf(Map[0]));
    for x := 0 to MapSizeX - 1 do
    begin
      Row[x] := TRGBQuad(Map[i]);
      Inc(i);
    end;
  end;
end;

procedure FormPaint;
begin
  CreateMap;
  // DrawImageEx(bmg^, 0, 0, WndWidth, WndHeight, 32, nil, 0); // this line is equivalent to the line below
  Blit(bmg^, 0, 0, WndWidth, WndHeight, 0, 0, WndWidth, WndHeight, WndWidth * SizeOf(TRGBQuad), BLIT_CLIENT_RELATIVE);
end;

begin
  with GetScreenSize do
  begin
    WndHeight := Height;
    WndWidth  := Width;
  end;
  SetEventMask(EM_REDRAW or EM_KEY);
  HeapInit;
  FormCreate;
  while True do
    case CheckEvent of
      REDRAW_EVENT:
        begin
          BeginDraw;
          DrawWindow(0, 0, WndWidth, WndHeight, nil, 0, WS_NO_DRAW, CAPTION_NONMOVABLE);
          EndDraw;
        end;
      KEY_EVENT:
        Break;
    else
      FormPaint;
    end;
end.

Я лишь адаптировал пример, так что, скорость генерации изображения зависит от мощности вашей системы.

Здесь используются функции Round, Trunc

Они должны быть реализованы в модуле System.
На данный момент этих функций в System нет, поэтому они находятся в самом проекте.

Кстати, это не в первый раз уже, когда я нахожу на том французском сайте интересный пример.
Ранее уже был Plasma Effect Demo, но тогда я переписал исходный код с Delphi на ассемблер UASM.
Прикладываю уже скомпилированное приложение TextureGenerator.kex

Post's attachments

texture.gif, 303.94 Кб, 256 x 192
texture.gif 303.94 Кб, 83 скачиваний с 2020-10-24 

Иконка вложений TextureGenerator.kex 2.41 Кб, 109 скачиваний с 2020-10-24 

2 (изменено: Leency, 27.11.2020 в 01:15)

Re: Texture Generator

Было бы прикольно иметь кнопку "generate" и "set as wallpapper".

3 (изменено: Freeman, 05.12.2020 в 17:49)

Re: Texture Generator

Leency, да можно добавить и такой функционал.
Только тогда, наверное, это должно быть не полноэкранное приложение.
А ещё можно добавить возможность сохранения сгенерированного изображения в файл.
А можно и как скринсейвер полноэкранный использовать.

Кстати, тут используются только функции

Noise2Di 
Turbulence2Dia

хотя в оригинальном исходнике также есть и такие

noise1D, noise2D, noise2Di, noise3D, noise3Di
turbulence1D, turbulence2D, turbulence2Di, turbulence3D, turbulence3Di

но они не были задействованы, поэтому и не были включены в этот пример.
Но, думаю, что они могли бы дать некоторые другие эффекты.

Добавлено 2020-11-29 в 15:15

Сделал оконную версию приложения.
Исходный код:

program TextureGenerator;

uses
  KolibriOS;

const
  WINDOW_BORDER_SIZE = 5;

  WALLPAPER_BUTTON = 10;
  GENERATE_BUTTON  = 20;
  SAVE_BUTTON      = 30;

  SCAN_CODE_W = #17;
  SCAN_CODE_S = #31;
  SCAN_CODE_N = #49;

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

  PLongA = ^TLongA;
  TLongA = array [0..0] of LongWord;
  PByteA = ^TByteA;
  TByteA = array [Word] of Byte;
  PRGBQuadA = ^TRGBQuadA;
  TRGBQuadA = array [Word] of TRGBQuad;

const
  B:  Integer = $100;
  BM: Integer = $FF;
  N:  Integer = $1000;
  Ni: Integer = $400000;
  NM: Integer = $FFF;
  NP: Integer = 12;
  B2: Integer = $202; // B + B + 2;

var
  P:   array [0..$202] of Integer;
  G1:  array [0..$202] of Double;
  G2:  array [0..$202, 0..1] of Double;
  G2i: array [0..$202, 0..1] of Integer;
  G3:  array [0..$202, 0..2] of Double;
  G3i: array [0..$202, 0..2] of Integer;

  bmg: PLongA;
  Map, Map1: PLongA;

  HighMap:  LongInt;
  MapSizeX: LongWord;
  MapSizeY: LongWord;

  WndHeight, WndWidth: LongWord;
  WndLeft, WndTop: LongInt;

  Preview: PRGBQuadA;       // this image will be drawn in the window
  BackgroundImage: Pointer; // and this - as wallpaper on the background

function Random: Extended;
begin
  Random := LongWord(System.Random($FFFFFFFF)) / $FFFFFFFF;
end;

function Round(Value: Extended): Int64;
asm
  FLD Value
  SUB ESP, 8
  FISTP qword ptr [ESP]
  FWAIT
  POP EAX
  POP EDX
end;

function Trunc(Value: Extended): Int64;
asm
  FLD Value
  SUB ESP, 12
  FNSTCW word ptr [ESP]
  FNSTCW word ptr [ESP + 2]
  FWAIT
  OR word ptr [ESP + 2], $0F00
  FLDCW word ptr [ESP + 2]
  FISTP qword ptr [ESP + 4]
  FWAIT
  FLDCW word ptr [ESP]
  POP ECX
  POP EAX
  POP EDX
end;

function Min(A, B: Integer): Integer; overload;
begin
  if A < B then
    Min := A
  else
    Min := B;
end;

function Min(A, B: Extended): Extended; overload;
begin
  if A < B then
    Min := A
  else
    Min := B;
end;

procedure InitNoise;
var
  I, J, T: Integer;
  len: Double;
begin
  Randomize;

  for i := 0 to B - 1 do
  begin
    P[i] := i;

    G1[i] := (Trunc(Random * 2 * B) - B) / B;

    G2[i, 0] := (Trunc(Random * 2 * B) - B) / B;
    G2[i, 1] := (Trunc(Random * 2 * B) - B) / B;
    len := Sqrt(G2[i, 0] * G2[i, 0] + G2[i, 1] * G2[i, 1]);
    if len > 1E-5 then
    begin
      G2[i, 0] := G2[i, 0] / len;
      G2[i, 1] := G2[i, 1] / len;
    end;

    G2i[i, 0] := Trunc(G2[i, 0] * 1024);
    G2i[i, 1] := Trunc(G2[i, 1] * 1024);

    G3[i, 0] := (Trunc(Random * 2 * B) - B) / B;
    G3[i, 1] := (Trunc(Random * 2 * B) - B) / B;
    G3[i, 2] := (Trunc(Random * 2 * B) - B) / B;
    len := Sqrt(G3[i, 0] * G3[i, 0] + G3[i, 1] * G3[i, 1] + G3[i, 2] * G3[i, 2]);
    if len > 1E-5 then
    begin
      G3[i, 0] := G3[i, 0] / len;
      G3[i, 1] := G3[i, 1] / len;
      G3[i, 2] := G3[i, 2] / len;
    end;

    G3i[i, 0] := Trunc(G3[i, 0] * 1024);
    G3i[i, 1] := Trunc(G3[i, 1] * 1024);
    G3i[i, 2] := Trunc(G3[i, 2] * 1024);
  end;

  for i := 0 to B - 1 do
  begin
    j := Trunc(Random * B);
    T := P[i];
    P[i] := P[j];
    P[j] := T;
  end;

  for i := 0 to B + 1 do
  begin
    P[B + i] := P[i];

    G1[B + i] := G1[i];

    G2[B + i][0] := G2[i][0];
    G2[B + i][1] := G2[i][1];

    G2i[B + i][0] := G2i[i][0];
    G2i[B + i][1] := G2i[i][1];

    G3[B + i][0] := G3[i][0];
    G3[B + i][1] := G3[i][1];
    G3[B + i][2] := G3[i][2];

    G3i[B + i][0] := G3i[i][0];
    G3i[B + i][1] := G3i[i][1];
    G3i[B + i][2] := G3i[i][2];
  end;
end;

function Noise2Di(const x, y: Integer): Integer;
var
  bx0, bx1, by0, by1: Integer;
  b00, b10, b01, b11: Integer;
  rx0, rx1, ry0, ry1: Integer;
  sx, sy, t, a, b, u, v: Integer;
  i, j: Integer;
  r: Integer;
begin
  t := x + $40000000;
  bx0 := (t shr 10) and $FF;
  bx1 := (bx0 + 1) and $FF;
  i := P[bx0];
  rx0 := t and 1023;
  rx1 := rx0 - 1024;

  t := y + $40000000;
  by0 := (t shr 10) and $FF;
  by1 := (by0 + 1) and $FF;
  j := P[bx1];
  ry0 := t and 1023;
  ry1 := ry0 - 1024;

  b00 := P[i + by0];
  b10 := P[j + by0];
  b01 := P[i + by1];
  b11 := P[j + by1];

  sx := (rx0 * rx0 * (3072 - 2 * rx0)) shr 20;
  sy := (ry0 * ry0 * (3072 - 2 * ry0)) shr 20;

  u := (rx0 * G2i[b00][0] + ry0 * G2i[b00][1]);
  v := (rx1 * G2i[b10][0] + ry0 * G2i[b10][1]);
  a := (u shl 10) + sx * (v - u);
  asm
    SAR a, 20
  end;

  u := (rx0 * G2i[b01][0] + ry1 * G2i[b01][1]);
  v := (rx1 * G2i[b11][0] + ry1 * G2i[b11][1]);
  b := (u shl 10)  + sx * (v - u);
  asm
    SAR b, 20
  end;

  r := a shl 10  + sy * (b - a);
  asm
    SAR r, 10
  end;

  Result := r;
end;

function Turbulence2Dia(x, y: Integer; const n: Integer): Integer;
var
  r, i: Integer;
  a: Integer;
begin
  r := 0;
  a := 1;

  for i := n - 1 downto 0 do
  begin
    Inc(r, Abs(Noise2Di(x, y)) div a);
    x := x shl 1;
    y := y shl 1;
    a := a shl 1;
  end;
  Result := r;
end;

procedure FormCreate;
begin
  with GetScreenSize do
  begin
    MapSizeX := Width;
    MapSizeY := Height;
  end;

  Randomize;

  bmg := HeapAllocate(MapSizeX * MapSizeY * SizeOf(Map[0]));
  Preview := HeapAllocate(MapSizeX * MapSizeY * SizeOf(Map[0]) div 4);

  Map := HeapAllocate(MapSizeX * MapSizeY * SizeOf(Map[0]));
  Map1 := HeapAllocate(MapSizeX * MapSizeY * SizeOf(Map1[0]));
  HighMap :=  MapSizeX * MapSizeY - 1;

  InitNoise;
end;

procedure GenerateMap(Map: PLongA; HighMap: LongInt; const SizeX, SizeY: Word;
                      ScaleX: Double = 0; ScaleY: Double = 0; Octaves: Integer = -1;
                      OffsetX: Double = 0; OffSetY: Double = 0);
var
  x, y, i: Integer;
  v: Integer;
  Xi, Yi, DXi, DYi: Integer;
begin
  if (SizeX * SizeY) = 0 then
    Exit;

  if HighMap <> (Sizex * SizeY - 1) then
    Map := HeapAllocate(SizeX * SizeY * SizeOf(Map[0]));


  if octaves < 0 then
    Octaves := Round(Random * 8);

  if ScaleX = 0 then
    ScaleX := Sqrt(Random + 0.5);

  if ScaleY = 0 then
    ScaleY := Sqrt(Random + 0.5);

  if OffsetX = 0 then
    OffsetX := Random * 100;

  if OffsetY = 0 then
    OffsetY := Random * 100;

  Xi := Round(OffsetX * 1024);
  Yi := Round(OffsetY * 1024);
  DXI := Round(1024 * ScaleX / SizeX);
  DYI := Round(1024 * ScaleY / SizeY);

  i := 0;
  for y := 0 to SizeY - 1 do
  begin
    for x := SizeX - 1 downto 0 do
    begin
      v := Turbulence2Dia(XI, YI, Octaves) shr 2;

      Map[i] := (v shl 16) + (v shl 8) + v;
      Inc(i);
      Inc(XI, DXI);
    end;
    XI := Round(OffsetX * 1024);
    Inc(YI, DYI);
  end;
end;

procedure ColorizeBaseMap(Map: PLongA; HighMap: LongInt; Color: Integer = 0);
var
  Pal: array[0..255] of TRGBQuad;
  R, G, B: Integer;
  i: Integer;
begin
  if Color <> 0 then
  begin
    R := (Color and $FF0000) shr 16;
    G := (Color and $FF00) shr 8;
    B := Color and $FF;
  end
  else
    repeat
      R := Round(Random * 255);
      G := Round(Random * 255);
      B := Round(Random * 255);
    until (R + G + B) > 550;

  for i := 0 to 255 do
    with Pal[i] do
    begin
      Red   := Round(Min((i * R) / 127, 255));
      Green := Round(Min((i * G) / 127, 255));
      Blue  := Round(Min((i * B) / 127, 255));
    end;

  for i := 0 to HighMap do
    Map[i] := LongWord(Pal[Map[i] and $FF]);
end;

procedure PowMap(Map: PLongA; HighMap: LongInt);
var
  r, g, b, v, i: Integer;
begin
  for i := 0 to HighMap do
  begin
    v := Map[i];
    r := 255 - ((v and $FF0000) shr 16);
    g := 255 - ((v and $FF00) shr 8);
    b := 255 - (v and $FF);

    r := r * r div 256;
    g := g * g div 256;
    b := b * b div 256;
    Map[i] := r shl 16 + g shl 8 + b;
  end;
end;

procedure MultMap(Map1, Map2: PLongA; HighMap: LongInt);
var
  v, w, i: Integer;
  rv, gv, bv, rw, gw, bw, r, g, b: Integer;
begin
  for i := 0 to HighMap do
  begin
    v := Map1[i];
    w := Map2[i];
    rv := (v and $FF0000) shr 16;
    gv := (v and $FF00) shr 8;
    bv := v and $FF;
    rw := (w and $FF0000) shr 16;
    gw := (w and $FF00) shr 8;
    bw := w and $FF;
    r := Min(255, (((rv * 3) div 2 + 127) * rw) div 256);
    g := Min(255, (((gv * 3) div 2 + 127) * gw) div 256);
    b := Min(255, (((bv * 3) div 2 + 127) * bw) div 256);
    Map1[i] := r shl 16 + g shl 8 + b;
  end;
end;

procedure CreateMap;
var
  x, y, i: LongWord;
  Row: PRGBQuadA;
begin
  GenerateMap(Map, HighMap, MapSizeX, MapSizeY);
  ColorizeBaseMap(Map, HighMap);
  PowMap(Map, HighMap);
  GenerateMap(Map1, HighMap, MapSizeX, MapSizeY);
  ColorizeBaseMap(Map1, HighMap);
  PowMap(Map1, HighMap);
  MultMap(Map, Map1, HighMap);
  GenerateMap(Map1, HighMap, MapSizeX, MapSizeY);
  ColorizeBaseMap(Map1, HighMap);
  PowMap(Map1, HighMap);
  MultMap(Map, Map1, HighMap);

  i := 0;
  for y := 0 to MapSizeY - 1 do
  begin
    Row := PRGBQuadA(LongWord(bmg) + y * MapSizeX * SizeOf(Map[0]));
    for x := 0 to MapSizeX - 1 do
    begin
      Row[x] := TRGBQuad(Map[i]);
      Inc(i);
    end;
  end;
end;

procedure ResizeImage(Src, Dst: PRGBQuadA; Width, Height: LongWord);
  function Red(A, B: LongWord): LongWord;
  begin
    Red := Src[(Width * B + A)].Red;
  end;
  function Green(A, B: LongWord): LongWord;
  begin
    Green := Src[(Width * B + A)].Green;
  end;
  function Blue(A, B: LongWord): LongWord;
  begin
    Blue := Src[(Width * B + A)].Blue;
  end;
var
  A, B, I: LongWord;
begin
  A := 0;
  while A < Width do
  begin
    B := 0;
    while B < Height do
    begin
      I := ((Width div 2) * B + A) div 2;
      Dst[i].Red   := (Red  (A, B) + Red  (A + 1, B) + Red  (A, B + 1) + Red  (A + 1, B + 1)) div 4;
      Dst[i].Green := (Green(A, B) + Green(A + 1, B) + Green(A, B + 1) + Green(A + 1, B + 1)) div 4;
      Dst[i].Blue  := (Blue (A, B) + Blue (A + 1, B) + Blue (A, B + 1) + Blue (A + 1, B + 1)) div 4;
      Inc(B, 2);
    end;
    Inc(A, 2);
  end;
end;

procedure DrawButtonWithText(ID: LongWord; X, Y: Integer; Width, Height: LongWord; Text: PChar;
                             TextColor, ButtonColor, Flags: LongWord);
const
  TEXT_HEIGHT = 16;
  MARGIN = 4;
begin
  DrawButton(X, Y, Width, Height, ButtonColor, 0, ID);
  DrawText(MARGIN + X, (LongInt(Height - TEXT_HEIGHT + 1)) Shr 1 + Y, Text, TextColor, 0, Flags Or DT_ZSTRING, 0);
end;

procedure FormPaint;
begin
  CreateMap;
  ResizeImage(PRGBQuadA(bmg), Preview, MapSizeX, MapSizeY);
  //DrawImageEx(Preview^, 0, 0, MapSizeX div 2, MapSizeY div 2, 32, nil, 0); // this line is equivalent to the line below
  Blit(Preview^, 0, 0, MapSizeX div 2, MapSizeY div 2, 0, 0, MapSizeX div 2, MapSizeY div 2, MapSizeX div 2 * SizeOf(TRGBQuad), BLIT_CLIENT_RELATIVE);
end;

procedure ConvBMP32To24(Src, Dst: Pointer; Size: LongWord);
{     ->EAX     Pointer to source       }
{       EDX     Pointer to destination  }
{       ECX     Width, Height           }
asm
  PUSH ESI
  PUSH EDI
  MOV ESI, SRC
  MOV EDI, DST
  MOVZX EAX, CX
  SHR ECX, 16
  MUL ECX
  MOV ECX, EAX
@@NEXT:
  MOVSW
  MOVSB
  INC ESI
  LOOP @@NEXT
  POP EDI
  POP ESI
end;

procedure Move(const Src; var Dst; Count: LongInt);
asm // EAX = Src; EDX = Dst; ECX = Count
  PUSH ESI
  PUSH EDI
  MOV ESI, SRC
  MOV EDI, DST
  CMP EDI, ESI
  JNA @MOVE
  LEA ESI, [ESI + COUNT - 1]
  LEA EDI, [EDI + COUNT - 1]
  STD
@MOVE:
  REP MOVSB
  CLD
  POP EDI
  POP ESI
end;

const
  TGA_UNCOMPRESSED_RGB = 2;
  TGA_UPPER_LEFT_ORIGIN = $20;

type
  PTargaFileHeader = ^TTargaFileHeader;
  TTargaFileHeader = packed record
    IDLength:        Byte;
    ColorMapType:    Byte;
    ImageType:       Byte;
    CMapStart:       Word;
    CMapLength:      Word;
    CMapDepth:       Byte;
    XOffset:         Word;
    YOffset:         Word;
    Width:           Word;
    Height:          Word;
    PixelDepth:      Byte;
    ImageDescriptor: Byte;
  end;

const
  BUTTON_HEIGHT = 9 + 10;

var
  ButtonWidth: LongWord;
  BytesWritten: LongWord;
  TargaFile: PTargaFileHeader;

  StandardColors: TStandardColors;

Const
// OpenDialog.Mode constants
  ODM_OPEN = 0;
  ODM_SAVE = 1;
  ODM_DIR  = 2;

// OpenDialog.Status constants
  ODS_CANCEL = 0;
  ODS_OK     = 1;
  ODS_ALTER  = 2;

type
// actually structure is:
//   first four bytes - size of this structure
//   and next are zero separated string values
  TOpenDialogFilter = packed record
    Size: LongWord;
    Text: array [0..SizeOf(ShortString) - 1] of AnsiChar;
  end;

  TOpenDialog = packed record
    Mode:           LongWord;
    ProcInfo:       Pointer;
    ComAreaName:    PAnsiChar;
    ComArea:        Pointer;
    OpenDirPath:    PAnsiChar;
    DirDefaultPath: PAnsiChar;
    StartPath:      PAnsiChar;
    DrawWindow:     procedure;
    Status:         LongWord;
    OpenFilePath:   PAnsiChar;
    FileNameArea:   PAnsiChar;
    FilterArea:     ^TOpenDialogFilter;
    XSize:          Word;     // at least 350
    XStart:         SmallInt;
    YSize:          Word;     // at least 250
    YStart:         SmallInt;
  end;

const
  PROC_INFO_BUFFER_SIZE      = SizeOf(TThreadInfo);
  OPEN_FILE_PATH_BUFFER_SIZE = 4096;
  FILE_NAME_AREA_BUFFER_SIZE = 1024;
  OPEN_DIR_PATH_BUFFER_SIZE  = OPEN_FILE_PATH_BUFFER_SIZE - FILE_NAME_AREA_BUFFER_SIZE;

  DEFAULT_FILE_NAME = 'Texture.tga';

var
  ProcLib: Pointer;
  OpenDialogInit: procedure(var OpenDialog: TOpenDialog); stdcall;
  OpenDialogStart: procedure(var OpenDialog: TOpenDialog); stdcall;
  OpenDialog: TOpenDialog;
  OpenDialogFilter: TOpenDialogFilter;

  FileNameAreaBuffer: array [0..FILE_NAME_AREA_BUFFER_SIZE - 1] of AnsiChar;
  OpenFilePathBuffer: array [0..OPEN_FILE_PATH_BUFFER_SIZE - 1] of AnsiChar;
  OpenDirPathBuffer: array [0..OPEN_DIR_PATH_BUFFER_SIZE - 1] of AnsiChar;
  ProcInfoBuffer: array [0..PROC_INFO_BUFFER_SIZE - 1] of Byte;

// copy comma separated string values from Filter
// to OpenDialogFilter and replace commas with zeroes
// 'txt,png,bmp' -> 'txt'#0'png'#0'bmp'#0
procedure OpenDialogSetFilter(Filter: PAnsiChar);
var
  i: LongWord;
begin
  i := 0;
  with OpenDialogFilter do
  begin
    Text[High(Text)] := #0;
    repeat
      if Filter[i] = ',' then
        Text[i] := #0
      else
        Text[i] := Filter[i];
      Inc(i);
    until (Filter[i - 1] = #0) or (i = High(Text));
    Size := i + SizeOf(Size);
  end;
end;

procedure On_Redraw;
begin
  BeginDraw;
  DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'Texture generator; Keys: N-new, S-save, W-wallpaper', $00FFFFFF,
    WS_SKINNED_FIXED + WS_CLIENT_COORDS + WS_CAPTION + WS_TRANSPARENT_FILL, CAPTION_MOVABLE);
  with StandardColors do
  begin
    DrawButtonWithText(WALLPAPER_BUTTON, 0, MapSizeY div 2, ButtonWidth, BUTTON_HEIGHT, 'Set as wallpaper', WorkButtonText, WorkButton, DT_CP866_8x16);
    DrawButtonWithText(GENERATE_BUTTON, ButtonWidth, MapSizeY div 2, ButtonWidth, BUTTON_HEIGHT, 'Generate new', WorkButtonText, WorkButton, DT_CP866_8x16);
    DrawButtonWithText(SAVE_BUTTON, ButtonWidth * 2, MapSizeY div 2, (WndWidth - WINDOW_BORDER_SIZE * 2) - ButtonWidth * 2, BUTTON_HEIGHT, 'Save to file', WorkButtonText, WorkButton, DT_CP866_8x16);
  end;
  //DrawImageEx(Preview^, 0, 0, MapSizeX div 2, MapSizeY div 2, 32, nil, 0); // this line is equivalent to the line below
  Blit(Preview^, 0, 0, MapSizeX div 2, MapSizeY div 2, 0, 0, MapSizeX div 2, MapSizeY div 2, MapSizeX div 2 * SizeOf(TRGBQuad), BLIT_CLIENT_RELATIVE);
  EndDraw;
end;

procedure SetAsWallpaper;
begin
  with GetScreenSize do
  begin
    BackgroundImage := HeapAllocate(MapSizeX * MapSizeY * SizeOf(Byte) * 3);
    ConvBMP32To24(bmg, BackgroundImage, MapSizeY shl 16 or MapSizeX);
    SetBackgroundSize(MapSizeX, MapSizeY);
    SetBackgroundDrawMode(2);
    DrawBackgroundImage(BackgroundImage^, 0, 0, MapSizeX, MapSizeY);
    DrawBackground;
    HeapFree(BackgroundImage);
  end;
end;

procedure GenerateNew;
begin
  DrawText((MapSizeX div 2 - Length('generating...') * 6 * 2) div 2, (MapSizeY div 2 - 9 * 2) div 2,
           'generating...', $000000FF, $00FFFFFF, DT_ZSTRING + DT_CP866_6x9 + DT_FILL_OPAQUE + DT_x2, 0);
  FormPaint;
end;

procedure SaveToFile;
begin
  OpenDialogStart(OpenDialog);
  with OpenDialog do
    if Status = ODS_OK then
    begin
      TargaFile := HeapAllocate(SizeOf(TTargaFileHeader) + MapSizeX * MapSizeY * SizeOf(Map[0]));
      with TargaFile^ do
      begin
        IDLength        := 0;
        ColorMapType    := 0;
        ImageType       := TGA_UNCOMPRESSED_RGB;
        CMapStart       := 0;
        CMapLength      := 0;
        CMapDepth       := 0;
        XOffset         := 0;
        YOffset         := 0;
        Width           := MapSizeX;
        Height          := MapSizeY;
        PixelDepth      := 32;
        ImageDescriptor := TGA_UPPER_LEFT_ORIGIN;
      end;

      if CreateFile(OpenFilePath) +
         WriteFile(OpenFilePath, TargaFile^, SizeOf(TTargaFileHeader), 0, BytesWritten) +
         WriteFile(OpenFilePath, bmg^, MapSizeX * MapSizeY * SizeOf(Map[0]), SizeOf(TTargaFileHeader), BytesWritten) = 0
      then
        RunFile('/sys/@Notify', 'Image successfully saved')
      else
        RunFile('/sys/@Notify', 'Error during image saving');

      HeapFree(TargaFile);
    end;
end;

begin
  ProcLib         := LoadLibrary('/sys/lib/proc_lib.obj');
  OpenDialogInit  := GetProcAddress(proclib, 'OpenDialog_init');
  OpenDialogStart := GetProcAddress(proclib, 'OpenDialog_start');

  with OpenDialog do
  begin
    Mode           := ODM_SAVE;
    ProcInfo       := @ProcInfoBuffer;
    ComAreaName    := 'FFFFFFFF_open_dialog';
    OpenDirPath    := @OpenDirPathBuffer[0];
    DirDefaultPath := '/sys';
    StartPath      := '/sys/File managers/opendial';
    DrawWindow     := On_Redraw;
    OpenFilePath   := @OpenFilePathBuffer[0];
    FileNameArea   := @FileNameAreaBuffer[0];
    FilterArea     := @OpenDialogFilter;
    XSize          := 400;
    YSize          := 480;
  end;

  Move(DEFAULT_FILE_NAME, FileNameAreaBuffer, Length(DEFAULT_FILE_NAME));
  OpenDialogInit(OpenDialog);
  OpenDialogSetFilter('tga');

  with GetScreenSize do
  begin
    WndHeight := Height div 2 + GetSkinHeight + WINDOW_BORDER_SIZE + BUTTON_HEIGHT;
    WndWidth  := Width div 2 + WINDOW_BORDER_SIZE * 2 - 1;
    WndLeft := (Width  - WndWidth) div 2;
    WndTop  := (Height - WndHeight) div 2;
  end;
  ButtonWidth := (WndWidth - WINDOW_BORDER_SIZE * 2) div 3;

  GetStandardColors(StandardColors, SizeOf(StandardColors));
  HeapInit;
  FormCreate;
  On_Redraw;
  GenerateNew;

  while True do
    case WaitEvent of
      REDRAW_EVENT:
        On_Redraw;
      KEY_EVENT:
        case GetKey.ScanCode of
          SCAN_CODE_W:
            SetAsWallpaper;
          SCAN_CODE_S:
            SaveToFile;
          SCAN_CODE_N:
            GenerateNew;
        end;
      BUTTON_EVENT:
        case GetButton.ID of
          WALLPAPER_BUTTON:
            SetAsWallpaper;
          GENERATE_BUTTON:
            GenerateNew;
          SAVE_BUTTON:
            SaveToFile;
        else
          Break;
        end;
    end;
end.

Добавил кнопку "generate" и "set as wallpapper".
Добавил возможность сохранения в файл.

misc.php?action=pun_attachment&amp;item=72&amp;download=0

Размер файлов большой(зависит от разрешения вашего экрана), поэтому на рамдиск не поместится.
Например, для разрешения экрана 1280x1024 размер будет 1280*1024*4 = 5242880 байт = 5 Mb

misc.php?action=pun_attachment&amp;item=71&amp;download=0

Хоткеи отображаются в заголовке программы.
Но при низких разрешениях(например, 800x600) текст заголовка полностью не влезает.

misc.php?action=pun_attachment&amp;item=73&amp;download=0

Также прикладываю уже готовое приложение TextureGenerator(Save_and_Wallpaper).kex

Post's attachments

Иконка вложений scr_800x600.PNG 619.1 Кб, 54 скачиваний с 2020-11-29 

screenshot.PNG, 358.52 Кб, 563 x 470
screenshot.PNG 358.52 Кб, 81 скачиваний с 2020-11-29 

Иконка вложений screenshot1.PNG 561.33 Кб, 63 скачиваний с 2020-11-29 

Иконка вложений TextureGenerator(Save_and_Wallpaper).kex 3.67 Кб, 123 скачиваний с 2020-11-29 

4

Re: Texture Generator

Вышло очень классно! Спасибо!

Добавлено 2020-12-02 в 19:22

Добавил в дистр. Кстати для компиляции используется Делфи или XD Pascal?

5

Re: Texture Generator

Leency, для компиляции используется Delphi SDK for KolibriOS