uraintype.pas 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // SPDX-License-Identifier: GPL-3.0-only
  2. unit URainType;
  3. {$mode objfpc}{$H+}
  4. interface
  5. uses
  6. Classes, SysUtils, BGRABitmapTypes, BGRABitmap;
  7. type
  8. { TRainRenderer }
  9. TRainRenderer = class
  10. protected
  11. FWind: single;
  12. FDensity: integer;
  13. rainData: array of record
  14. x,ystart,yend: single;
  15. rainWidth, rainSpeed: single;
  16. grad: TBGRACustomGradient;
  17. active: boolean;
  18. inactiveTime: double;
  19. end;
  20. procedure ClearRainData;
  21. procedure NeedRainArray(w, h, iRainProba: integer; rainSizeX,
  22. rainSizeY: single);
  23. procedure PrepareRainArray(nbRain: integer; ScaleX: single);
  24. function PrepareRainDrop(i: integer; rainSizeX, rainSizeY: single): single;
  25. public
  26. constructor Create(AWind: single; ADensity: integer); //Example: -0.5, 2
  27. procedure RainElapse(elapsed: double; rainProba: single; w, h: integer);
  28. procedure RenderRain(Bitmap: TBGRABitmap);
  29. destructor Destroy; override;
  30. end;
  31. implementation
  32. uses BGRAGradientScanner;
  33. { TRainRenderer }
  34. constructor TRainRenderer.Create(AWind: single; ADensity: integer);
  35. begin
  36. FWind := AWind;
  37. FDensity:= ADensity;
  38. end;
  39. destructor TRainRenderer.Destroy;
  40. begin
  41. ClearRainData;
  42. inherited Destroy;
  43. end;
  44. procedure TRainRenderer.ClearRainData;
  45. var i: integer;
  46. begin
  47. for i := 0 to high(rainData) do
  48. rainData[i].grad.Free;
  49. rainData := nil;
  50. end;
  51. procedure TRainRenderer.RenderRain(Bitmap: TBGRABitmap);
  52. var
  53. i,h2: Integer;
  54. scan: TBGRAGradientScanner;
  55. begin
  56. h2 := Bitmap.Height div 2;
  57. for i:= 0 to high(rainData) do
  58. with rainData[i] do
  59. if active then
  60. begin
  61. scan := TBGRAGradientScanner.Create(grad, gtLinear, PointF(0,ystart),PointF(0,yend));
  62. Bitmap.DrawLineAntialias(x+(ystart-h2)*FWind,ystart,x+(yend-h2)*FWind,yend,scan,rainWidth,true);
  63. scan.Free;
  64. end;
  65. end;
  66. //returns raindrop height
  67. function TRainRenderer.PrepareRainDrop(i: integer; rainSizeX,rainSizeY: single): single;
  68. var dist: single;
  69. begin
  70. with rainData[i] do
  71. begin
  72. dist := (random(100)+10)/10;
  73. rainSpeed := 1/dist;
  74. rainWidth := rainSizeX/dist;
  75. if rainWidth < 1 then rainWidth := 1;
  76. result := rainSizeY/dist*(random(50)+75)/100;
  77. end;
  78. end;
  79. procedure TRainRenderer.NeedRainArray(w, h, iRainProba: integer; rainSizeX,rainSizeY: single);
  80. var
  81. nbRain: Integer;
  82. i: Integer;
  83. begin
  84. nbRain := (w+round(abs(FWind)*h)) *FDensity;
  85. if length(rainData)<> nbRain then
  86. begin
  87. PrepareRainArray(nbRain,1/FDensity);
  88. for i := 0 to high(rainData) do
  89. with rainData[i] do
  90. begin
  91. x -= abs(FWind)*h/2;
  92. if random(1000) < iRainProba then
  93. begin
  94. active := true;
  95. ystart := Random(h*2)-h/2;
  96. yend := ystart + PrepareRainDrop(i, rainSizeX,rainSizeY);
  97. end;
  98. end;
  99. end;
  100. end;
  101. procedure TRainRenderer.RainElapse(elapsed: double; rainProba: single; w,h: integer);
  102. var
  103. i: integer;
  104. rainSizeY,rainSizeX: single;
  105. delta: single;
  106. iRainProba: integer;
  107. begin
  108. iRainProba := round(rainProba*1000);
  109. rainSizeY := 2+h*rainProba;
  110. rainSizeX := 7*rainProba;
  111. if rainSizeX < 4 then rainSizeX := 4;
  112. NeedRainArray(w,h, iRainProba, rainSizeX,rainSizeY);
  113. for i := 0 to high(rainData) do
  114. with rainData[i] do
  115. if active then
  116. begin
  117. delta := h*rainSpeed*elapsed;
  118. ystart += delta;
  119. yend += delta;
  120. if ystart >= h then
  121. begin
  122. if random(1000) < iRainProba then
  123. begin
  124. yend := -(ystart-h);
  125. ystart := yend - PrepareRainDrop(i, rainSizeX,rainSizeY);
  126. end else
  127. begin
  128. active := false;
  129. inactiveTime:= 0;
  130. end;
  131. end;
  132. end else
  133. begin
  134. inactiveTime+= elapsed;
  135. if inactiveTime > 0.5 then
  136. begin
  137. inactiveTime -= 0.5;
  138. if random(1000) < iRainProba then
  139. begin
  140. active := true;
  141. ystart := -random(h)/2;
  142. yend := ystart + PrepareRainDrop(i, rainSizeX,rainSizeY);
  143. end;
  144. end;
  145. end;
  146. end;
  147. procedure TRainRenderer.PrepareRainArray(nbRain: integer; ScaleX: single);
  148. var
  149. i: Integer;
  150. begin
  151. ClearRainData;
  152. setlength(rainData, nbRain);
  153. for i := 0 to high(rainData) do
  154. with rainData[i] do
  155. begin
  156. x := i*scaleX;
  157. grad := TBGRAMultiGradient.Create([BGRAPixelTransparent, BGRA(255,255,255,random(20)+50), BGRAPixelTransparent],[0,0.9,1],True);
  158. active:= false;
  159. inactiveTime := 0;
  160. end;
  161. end;
  162. end.