2
0

GLS.Blur.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.Blur;
  5. (* Applies a blur effect over the viewport *)
  6. interface
  7. {$I GLScene.inc}
  8. uses
  9. Winapi.OpenGL,
  10. Winapi.OpenGLext,
  11. System.Classes,
  12. System.SysUtils,
  13. VCL.Graphics,
  14. GLS.VectorTypes,
  15. GLS.VectorGeometry,
  16. GLS.BaseClasses,
  17. GLS.Scene,
  18. GLS.Objects,
  19. GLS.BitmapFont,
  20. GLS.Texture,
  21. GLS.Material,
  22. GLS.HudObjects,
  23. GLS.Color,
  24. GLS.Graphics,
  25. GLS.Context,
  26. GLS.XOpenGL,
  27. GLS.State,
  28. GLS.TextureFormat,
  29. GLS.RenderContextInfo;
  30. type
  31. TGLBlurPreset = (pNone, pGlossy, pBeastView, pOceanDepth, pDream, pOverBlur, pAdvancedBlur);
  32. TGLBlurkind = (bNone, bSimple, bAdvanced);
  33. TRGBPixel = record
  34. R, G, B: TGLubyte;
  35. end;
  36. TRGBPixelBuffer = array of TRGBPixel;
  37. TGLAdvancedBlurImagePrepareEvent = procedure(Sender: TObject; BMP32: TGLImage; var DoBlur: boolean) of object;
  38. EGLMotionBlurException = class(Exception);
  39. TGLBlur = class(TGLHUDSprite)
  40. private
  41. FViewer: TGLMemoryViewer;
  42. OldTime: Double;
  43. FDoingMemView: boolean;
  44. FBlurDeltaTime: Double;
  45. FBlurTop: Single;
  46. FBlurBottom: Single;
  47. FBlurLeft: Single;
  48. FBlurRight: Single;
  49. FRenderHeight: Integer;
  50. FRenderWidth: Integer;
  51. FPreset: TGLBlurPreset;
  52. FTargetObject: TGLbaseSceneObject;
  53. FOnAdvancedBlurImagePrepareEvent: TGLAdvancedBlurImagePrepareEvent;
  54. FBlur: TGLBlurKind;
  55. Pixelbuffer: TRGBPixelBuffer;
  56. FAdvancedBlurPasses: integer;
  57. FOnAfterTargetRender: TNotifyEvent;
  58. FOnBeforeTargetRender: TNotifyEvent;
  59. FAdvancedBlurAmp: single;
  60. FBlurSelf: boolean;
  61. FAdvancedBlurLowClamp: byte;
  62. FAdvancedBlurHiClamp: byte;
  63. FRenderBackgroundColor: TColor;
  64. procedure DoMemView(baseObject: TGLBaseSceneObject);
  65. procedure SetRenderHeight(const Value: Integer);
  66. procedure SetRenderWidth(const Value: Integer);
  67. procedure UpdateImageSettings;
  68. procedure SetPreset(const Value: TGLBlurPreset);
  69. function StoreBlurBottom: Boolean;
  70. function StoreBlurDeltaTime: Boolean;
  71. function StoreBlurRight: Boolean;
  72. function StoreBlurTop: Boolean;
  73. function StoreBlurLeft: Boolean;
  74. procedure SetTargetObject(const Value: TGLbaseSceneObject);
  75. procedure SetOnAdvancedBlurImagePrepareEvent(const Value: TGLAdvancedBlurImagePrepareEvent);
  76. procedure SetBlur(const Value: TGLBlurKind);
  77. procedure SetAdvancedBlurPasses(const Value: integer);
  78. procedure SetOnAfterTargetRender(const Value: TNotifyEvent);
  79. procedure SetOnBeforeTargetRender(const Value: TNotifyEvent);
  80. procedure SetAdvancedBlurAmp(const Value: single);
  81. procedure SetBlurSelf(const Value: boolean);
  82. procedure SetAdvancedBlurLowClamp(const Value: byte);
  83. procedure SetAdvancedBlurHiClamp(const Value: byte);
  84. procedure SetRenderBackgroundColor(const Value: TColor);
  85. public
  86. constructor Create(AOwner: TComponent); override;
  87. destructor Destroy; override;
  88. procedure DoProgress(const progressTime: TGLProgressTimes); override;
  89. procedure DoRender(var ARci: TGLRenderContextInfo;
  90. ARenderSelf, ARenderChildren: Boolean); override;
  91. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  92. published
  93. property Blur: TGLBlurKind read FBlur write SetBlur;
  94. property BlurDeltaTime: Double read FBlurDeltaTime write FBlurDeltaTime stored StoreBlurDeltaTime;
  95. property BlurLeft: Single read FBlurLeft write FBlurLeft stored StoreBlurLeft;
  96. property BlurTop: Single read FBlurTop write FBlurTop stored StoreBlurTop;
  97. property BlurRight: Single read FBlurRight write FBlurRight stored StoreBlurRight;
  98. property BlurBottom: Single read FBlurBottom write FBlurBottom stored StoreBlurBottom;
  99. property RenderWidth: Integer read FRenderWidth write SetRenderWidth default 256;
  100. property RenderHeight: Integer read FRenderHeight write SetRenderHeight default 256;
  101. property Preset: TGLBlurPreset read FPreset write SetPreset stored false;
  102. property TargetObject: TGLbaseSceneObject read FTargetObject write SetTargetObject;
  103. property AdvancedBlurPasses: integer read FAdvancedBlurPasses write SetAdvancedBlurPasses;
  104. property AdvancedBlurAmp: single read FAdvancedBlurAmp write SetAdvancedBlurAmp;
  105. property AdvancedBlurLowClamp: byte read FAdvancedBlurLowClamp write SetAdvancedBlurLowClamp;
  106. property AdvancedBlurHiClamp: byte read FAdvancedBlurHiClamp write SetAdvancedBlurHiClamp;
  107. property BlurSelf: boolean read FBlurSelf write SetBlurSelf;
  108. property RenderBackgroundColor: TColor read FRenderBackgroundColor write SetRenderBackgroundColor;
  109. property OnAdvancedBlurImagePrepareEvent: TGLAdvancedBlurImagePrepareEvent read FOnAdvancedBlurImagePrepareEvent write SetOnAdvancedBlurImagePrepareEvent;
  110. property OnBeforeTargetRender: TNotifyEvent read FOnBeforeTargetRender write SetOnBeforeTargetRender;
  111. property OnAfterTargetRender: TNotifyEvent read FOnAfterTargetRender write SetOnAfterTargetRender;
  112. end;
  113. (*This component blurs everything thatis rendered BEFORE it. So if you want part
  114. of your scene blured, the other not blured, make sure that the other part is
  115. rendered after this component. It is fast and does not require shaders.
  116. Note: it is FPS-dependant. Also also can produce a "blury trail effect", which
  117. stays on the screen until something new is rendered over it. It can be overcome
  118. by changing the Material.FrontProperties.Diffuse property. This, however, also
  119. has a drawback - the picture becomes more blured altogether. For example, if
  120. your backgroud color is Black, set the Material.FrontProperties.Diffuse to White.
  121. If it is White, set Material.FrontProperties.Diffuse to Black. I haven't tried
  122. any others, but I hope you get the idea ;)
  123. I've seen this effect in different Bruring components, even in shaders, but if
  124. anyone knows another way to fix this issue - please post it on the glscene
  125. newsgroup. *)
  126. TGLMotionBlur = class(TGLCustomSceneObject, IGLInitializable)
  127. private
  128. FIntensity: Single;
  129. function StoreIntensity: Boolean;
  130. protected
  131. procedure DoOnAddedToParent; override;
  132. procedure InitializeObject(ASender: TObject; const ARci: TGLRenderContextInfo); virtual;
  133. public
  134. // This function is only valid AFTER OpenGL has been initialized.
  135. function SupportsRequiredExtensions: Boolean;
  136. procedure DoRender(var ARci: TGLRenderContextInfo; ARenderSelf, ARenderChildren: Boolean); override;
  137. constructor Create(aOwner: TComponent); override;
  138. procedure Assign(Source: TPersistent); override;
  139. published
  140. // The more the intensity, the more blur you have.
  141. property Intensity: Single read FIntensity write FIntensity stored StoreIntensity;
  142. // From TGLBaseSceneObject.
  143. property Visible;
  144. property OnProgress;
  145. property Behaviours;
  146. property Effects;
  147. property Hint;
  148. end;
  149. //------------------------------------------------------------------------
  150. implementation
  151. //------------------------------------------------------------------------
  152. uses
  153. GLS.Coordinates,
  154. GLS.PersistentClasses,
  155. GLS.Strings,
  156. GLS.OpenGLAdapter;
  157. const
  158. EPS = 0.001;
  159. constructor TGLBlur.Create(AOwner: TComponent);
  160. begin
  161. inherited;
  162. FBlurDeltaTime := 0.02;
  163. FBlurTop := 0.01;
  164. FBlurLeft := 0.01;
  165. FBlurRight := 0.01;
  166. FBlurBottom := 0.01;
  167. FRenderHeight := 256;
  168. FRenderWidth := 256;
  169. FViewer := TGLMemoryViewer.Create(Self);
  170. FPreset := pNone;
  171. Material.Texture.Disabled := False;
  172. FAdvancedBlurPasses := 1;
  173. FAdvancedBlurAmp := 1.1;
  174. FBlurSelf := true;
  175. FAdvancedBlurLowClamp := 0;
  176. FAdvancedBlurHiClamp := 255;
  177. FRenderBackgroundColor := ClBlack;
  178. end;
  179. destructor TGLBlur.Destroy;
  180. begin
  181. FViewer.Free;
  182. inherited;
  183. end;
  184. procedure TGLBlur.UpdateImageSettings;
  185. var
  186. B: TBitmap;
  187. begin
  188. if Material.Texture.Image is TGLBlankImage then
  189. with TGLBlankImage(Material.Texture.Image) do
  190. begin
  191. Width := RenderWidth;
  192. Height := Renderheight;
  193. end
  194. else if Material.Texture.Image is TGLPersistentImage then
  195. begin
  196. B := TGLPersistentImage(Material.Texture.Image).Picture.Bitmap;
  197. B.Width := 0;
  198. B.Height := 0;
  199. B.Width := RenderWidth;
  200. B.Height := RenderHeight;
  201. end;
  202. with FViewer do
  203. begin
  204. Width := RenderWidth;
  205. Height := Renderheight;
  206. end;
  207. SetLength(Pixelbuffer, RenderWidth * RenderHeight);
  208. end;
  209. procedure TGLBlur.DoProgress(const progressTime: TGLProgressTimes);
  210. begin
  211. inherited;
  212. if self.Visible and (progressTime.newTime - OldTime > FBlurDeltaTime) then
  213. begin
  214. OldTime := progressTime.newTime;
  215. if TargetObject <> nil then
  216. DoMemView(TargetObject);
  217. end;
  218. end;
  219. procedure TGLBlur.DoMemView(baseObject: TGLBaseSceneObject);
  220. var
  221. OldFocalLength: single;
  222. refsiz: single;
  223. BMP: TGLImage;
  224. x, y: integer;
  225. line: PGLPixel32Array;
  226. by: Integer;
  227. bp: Integer;
  228. DoBlur: Boolean;
  229. procedure ApplyBlur(const passes: integer);
  230. var
  231. t: integer;
  232. x, y: integer;
  233. lin, linu, lind, linuu, lindd: PGLPixel32Array;
  234. r, g, b: single;
  235. procedure ApplyBlurClampAndSetPixel;
  236. var
  237. ir, ig, ib: Smallint;
  238. begin
  239. // 0.1111 = 1/7 (where 7 is the times each pixel is summed with neighbours or self)
  240. ir := round(r * FAdvancedBlurAmp * 0.1111);
  241. ig := round(g * FAdvancedBlurAmp * 0.1111);
  242. ib := round(b * FAdvancedBlurAmp * 0.1111);
  243. // Hi Clamp
  244. if ir > FAdvancedBlurHiClamp then
  245. ir := FAdvancedBlurHiClamp;
  246. if ig > FAdvancedBlurHiClamp then
  247. ig := FAdvancedBlurHiClamp;
  248. if ib > FAdvancedBlurHiClamp then
  249. ib := FAdvancedBlurHiClamp;
  250. lin^[x].r := ir;
  251. lin^[x].g := ig;
  252. lin^[x].b := ib;
  253. end;
  254. begin
  255. for t := 0 to passes do
  256. begin
  257. for y := 2 to BMP.Height - 3 do
  258. begin
  259. linuu := BMP.ScanLine[y - 2];
  260. linu := BMP.ScanLine[y - 1];
  261. lin := BMP.ScanLine[y];
  262. lind := BMP.ScanLine[y + 1];
  263. lindd := BMP.ScanLine[y + 2];
  264. by := y * BMP.Height;
  265. // X = 0 PART:
  266. x := 0;
  267. r := lin^[x].r + lin^[x + 1].r + lin^[x + 2].r + linu^[x].r + lind^[x].r + linuu^[x].r + lindd^[x].r;
  268. g := lin^[x].g + lin^[x + 1].g + lin^[x + 2].g + linu^[x].g + lind^[x].g + linuu^[x].g + lindd^[x].g;
  269. b := lin^[x].b + lin^[x + 1].b + lin^[x + 2].b + linu^[x].b + lind^[x].b + linuu^[x].b + lindd^[x].b;
  270. ApplyBlurClampAndSetPixel;
  271. // X = 1 PART:
  272. x := 1;
  273. r := lin^[x].r + lin^[x + 1].r + lin^[x - 1].r + lin^[x + 2].r + linu^[x].r + lind^[x].r + linuu^[x].r + lindd^[x].r;
  274. g := lin^[x].g + lin^[x + 1].g + lin^[x - 1].g + lin^[x + 2].g + linu^[x].g + lind^[x].g + linuu^[x].g + lindd^[x].g;
  275. b := lin^[x].b + lin^[x + 1].b + lin^[x - 1].b + lin^[x + 2].b + linu^[x].b + lind^[x].b + linuu^[x].b + lindd^[x].b;
  276. ApplyBlurClampAndSetPixel;
  277. // ALL X IN MIDDLE PART:
  278. for x := 2 to BMP.Width - 3 do
  279. begin
  280. r := lin^[x].r + lin^[x + 1].r + lin^[x - 1].r + lin^[x + 2].r + lin^[x - 2].r + linu^[x].r + lind^[x].r + linuu^[x].r + lindd^[x].r;
  281. g := lin^[x].g + lin^[x + 1].g + lin^[x - 1].g + lin^[x + 2].g + lin^[x - 2].g + linu^[x].g + lind^[x].g + linuu^[x].g + lindd^[x].g;
  282. b := lin^[x].b + lin^[x + 1].b + lin^[x - 1].b + lin^[x + 2].b + lin^[x - 2].b + linu^[x].b + lind^[x].b + linuu^[x].b + lindd^[x].b;
  283. ApplyBlurClampAndSetPixel;
  284. end;
  285. //X = NEXT TO LAST PART:
  286. x := BMP.Width - 2;
  287. r := lin^[x].r + lin^[x + 1].r + lin^[x - 1].r + lin^[x - 2].r + linu^[x].r + lind^[x].r + linuu^[x].r + lindd^[x].r;
  288. g := lin^[x].g + lin^[x + 1].g + lin^[x - 1].g + lin^[x - 2].g + linu^[x].g + lind^[x].g + linuu^[x].g + lindd^[x].g;
  289. b := lin^[x].b + lin^[x + 1].b + lin^[x - 1].b + lin^[x - 2].b + linu^[x].b + lind^[x].b + linuu^[x].b + lindd^[x].b;
  290. ApplyBlurClampAndSetPixel;
  291. //X = LAST PART:
  292. x := BMP.Width - 1;
  293. r := lin^[x].r + lin^[x - 1].r + lin^[x - 2].r + linu^[x].r + lind^[x].r + linuu^[x].r + lindd^[x].r;
  294. g := lin^[x].g + lin^[x - 1].g + lin^[x - 2].g + linu^[x].g + lind^[x].g + linuu^[x].g + lindd^[x].g;
  295. b := lin^[x].b + lin^[x - 1].b + lin^[x - 2].b + linu^[x].b + lind^[x].b + linuu^[x].b + lindd^[x].b;
  296. ApplyBlurClampAndSetPixel;
  297. end;
  298. end;
  299. end;
  300. begin
  301. if FViewer.Camera <> Scene.CurrentGLCamera then
  302. FViewer.Camera := Scene.CurrentGLCamera;
  303. if FViewer.Camera <> nil then
  304. begin
  305. FDoingMemView := true;
  306. //Scene.RenderScene(FViewer.Buffer,FViewer.Width,FViewer.Height,dsRendering,baseObject);
  307. FViewer.Camera.BeginUpdate;
  308. OldFocalLength := FViewer.Camera.FocalLength;
  309. // CALCULATE SCALED FOCAL LENGTH FOR VIEWER
  310. if SCene.CurrentBuffer.Width > SCene.CurrentBuffer.height then
  311. refsiz := Scene.CurrentBuffer.Width
  312. else
  313. refsiz := Scene.CurrentBuffer.height;
  314. FViewer.Camera.FocalLength := FViewer.Camera.FocalLength * FViewer.Buffer.Width / refsiz;
  315. if FViewer.Buffer.BackgroundColor <> FRenderBackgroundColor then
  316. FViewer.Buffer.BackgroundColor := FRenderBackgroundColor;
  317. try
  318. case FBlur of
  319. bNone:
  320. begin
  321. // do nothing
  322. end;
  323. bSimple:
  324. begin
  325. if Assigned(FOnBeforeTargetRender) then
  326. FOnBeforeTargetRender(self);
  327. // RENDER
  328. FViewer.Render(baseObject);
  329. // Copy to texture (unfortunatelly, after this, the bitmap cannot be red back from the hardware.. i think)
  330. FViewer.CopyToTexture(Material.Texture);
  331. if Assigned(FOnAfterTargetRender) then
  332. FOnAfterTargetRender(self);
  333. end;
  334. bAdvanced:
  335. begin
  336. if Assigned(FOnBeforeTargetRender) then
  337. FOnBeforeTargetRender(self);
  338. // RENDER
  339. FViewer.Render(baseObject);
  340. // Read pixels from buffer. This is slow, but ok with reasonably small render size.
  341. FViewer.Buffer.RenderingContext.Activate;
  342. try
  343. gl.ReadPixels(0, 0, FViewer.Buffer.Width, FViewer.Buffer.Height, GL_RGB, GL_UNSIGNED_BYTE, Pixelbuffer);
  344. except
  345. FViewer.Buffer.RenderingContext.Deactivate;
  346. end;
  347. if Assigned(FOnAfterTargetRender) then
  348. FOnAfterTargetRender(self);
  349. BMP := Material.Texture.Image.GetBitmap32;
  350. BMP.Narrow;
  351. FViewer.Buffer.RenderingContext.Deactivate;
  352. // FILLS THE BITMAP with the pixelbuffer captured from the internal memoryViewer
  353. for y := 0 to RenderHeight - 1 do
  354. begin
  355. line := BMP.ScanLine[y];
  356. by := y * RenderHeight;
  357. for x := 0 to RenderWidth - 1 do
  358. begin
  359. bp := x + by;
  360. line^[x].r := Pixelbuffer[bp].R;
  361. line^[x].g := Pixelbuffer[bp].G;
  362. line^[x].b := Pixelbuffer[bp].B;
  363. // Low clamp
  364. if line^[x].r < FAdvancedBlurLowClamp then
  365. line^[x].r := 0;
  366. if line^[x].g < FAdvancedBlurLowClamp then
  367. line^[x].g := 0;
  368. if line^[x].b < FAdvancedBlurLowClamp then
  369. line^[x].b := 0;
  370. end;
  371. end;
  372. DoBlur := true;
  373. if Assigned(FOnAdvancedBlurImagePrepareEvent) then
  374. begin
  375. FOnAdvancedBlurImagePrepareEvent(self, BMP, DoBlur);
  376. end;
  377. if DoBlur then
  378. ApplyBlur(FAdvancedBlurPasses);
  379. Material.Texture.Image.NotifyChange(self);
  380. end;
  381. end;
  382. finally
  383. FViewer.Camera.FocalLength := OldFocalLength;
  384. FViewer.Camera.EndUpdate;
  385. FDoingMemView := false;
  386. end;
  387. end;
  388. end;
  389. {$WARNINGS Off} //Suppress "unsafe" warning
  390. procedure TGLBlur.DoRender(var ARci: TGLRenderContextInfo;
  391. ARenderSelf, ARenderChildren: Boolean);
  392. var
  393. vx, vy, vx1, vy1, f: Single;
  394. offsx, offsy: single;
  395. MaxMeasure: integer;
  396. begin
  397. if FDoingMemView and (FBlurSelf = false) then
  398. Exit;
  399. if (csDesigning in ComponentState) then
  400. begin
  401. if Count > 0 then
  402. Self.RenderChildren(0, Count - 1, ARci);
  403. exit;
  404. end;
  405. if ARci.ignoreMaterials then
  406. Exit;
  407. gl.CheckError;
  408. Material.Apply(ARci);
  409. gl.CheckError;
  410. repeat
  411. if AlphaChannel <> 1 then
  412. ARci.GLStates.SetGLMaterialAlphaChannel(GL_FRONT, AlphaChannel);
  413. // Prepare matrices
  414. gl.MatrixMode(GL_MODELVIEW);
  415. gl.PushMatrix;
  416. gl.LoadMatrixf(@TGLSceneBuffer(ARci.buffer).BaseProjectionMatrix);
  417. if ARci.renderDPI = 96 then
  418. f := 1
  419. else
  420. f := ARci.renderDPI / 96;
  421. gl.Scalef(2 / ARci.viewPortSize.cx, 2 / ARci.viewPortSize.cy, 1);
  422. // center of viewport:
  423. gl.Translatef(0, 0, Position.Z);
  424. if Rotation <> 0 then
  425. gl.Rotatef(Rotation, 0, 0, 1);
  426. gl.MatrixMode(GL_PROJECTION);
  427. gl.PushMatrix;
  428. gl.LoadIdentity;
  429. ARci.GLStates.Disable(stDepthTest);
  430. ARci.GLStates.DepthWriteMask := False;
  431. // calculate offsets in order to keep the quad a square centered in the view
  432. if ARci.viewPortSize.cx > ARci.viewPortSize.cy then
  433. begin
  434. offsx := 0;
  435. offsy := (ARci.viewPortSize.cx - ARci.viewPortSize.cy) * 0.5;
  436. MaxMeasure := ARci.viewPortSize.cx;
  437. end
  438. else
  439. begin
  440. offsx := (ARci.viewPortSize.cy - ARci.viewPortSize.cx) * 0.5;
  441. offsy := 0;
  442. MaxMeasure := ARci.viewPortSize.cy;
  443. end;
  444. // precalc coordinates
  445. vx := -ARci.viewPortSize.cx * 0.5 * f;
  446. vx1 := vx + ARci.viewPortSize.cx * f;
  447. vy := +ARci.viewPortSize.cy * 0.5 * f;
  448. vy1 := vy - ARci.viewPortSize.cy * f;
  449. vx := vx - offsx;
  450. vx1 := vx1 + offsx;
  451. vy := vy + offsy;
  452. vy1 := vy1 - offsy;
  453. // Cause the radial scaling
  454. if FDoingMemView then
  455. begin
  456. vx := vx - FBlurLeft * MaxMeasure;
  457. vx1 := vx1 + FBlurRight * MaxMeasure;
  458. vy := vy + FBlurTop * MaxMeasure;
  459. vy1 := vy1 - FBlurBottom * MaxMeasure;
  460. end;
  461. // issue quad
  462. gl.Begin_(GL_QUADS);
  463. gl.Normal3fv(@YVector);
  464. gl.TexCoord2f(0, 0);
  465. gl.Vertex2f(vx, vy1);
  466. gl.TexCoord2f(XTiles, 0);
  467. gl.Vertex2f(vx1, vy1);
  468. gl.TexCoord2f(XTiles, YTiles);
  469. gl.Vertex2f(vx1, vy);
  470. gl.TexCoord2f(0, YTiles);
  471. gl.Vertex2f(vx, vy);
  472. gl.End_;
  473. // restore state
  474. gl.PopMatrix;
  475. gl.MatrixMode(GL_MODELVIEW);
  476. gl.PopMatrix;
  477. until not Material.UnApply(ARci);
  478. if Count > 0 then
  479. Self.RenderChildren(0, Count - 1, ARci);
  480. end;
  481. procedure TGLBlur.Notification(AComponent: TComponent; Operation: TOperation);
  482. begin
  483. inherited;
  484. if Operation = opRemove then
  485. if AComponent = FTargetObject then
  486. FTargetObject := nil;
  487. inherited;
  488. end;
  489. {$WARNINGS On}
  490. procedure TGLBlur.SetRenderBackgroundColor(const Value: TColor);
  491. begin
  492. FRenderBackgroundColor := Value;
  493. end;
  494. procedure TGLBlur.SetRenderHeight(const Value: integer);
  495. begin
  496. FRenderHeight := Value;
  497. UpdateImageSettings;
  498. end;
  499. procedure TGLBlur.SetRenderWidth(const Value: integer);
  500. begin
  501. FRenderWidth := Value;
  502. UpdateImageSettings;
  503. end;
  504. procedure TGLBlur.SetTargetObject(const Value: TGLbaseSceneObject);
  505. begin
  506. FTargetObject := Value;
  507. end;
  508. procedure TGLBlur.SetAdvancedBlurAmp(const Value: single);
  509. begin
  510. FAdvancedBlurAmp := Value;
  511. end;
  512. procedure TGLBlur.SetAdvancedBlurHiClamp(const Value: byte);
  513. begin
  514. FAdvancedBlurHiClamp := Value;
  515. end;
  516. procedure TGLBlur.SetAdvancedBlurLowClamp(const Value: byte);
  517. begin
  518. FAdvancedBlurLowClamp := Value;
  519. end;
  520. procedure TGLBlur.SetAdvancedBlurPasses(const Value: integer);
  521. begin
  522. FAdvancedBlurPasses := Value;
  523. end;
  524. procedure TGLBlur.SetBlur(const Value: TGLBlurKind);
  525. begin
  526. if FBlur <> Value then
  527. begin
  528. case Value of
  529. bnone:
  530. begin
  531. // do Nothing
  532. end;
  533. bSimple:
  534. begin
  535. Material.Texture.ImageClassName := TGLBlankImage.ClassName;
  536. end;
  537. bAdvanced:
  538. begin
  539. Material.Texture.ImageClassName := TGLPersistentImage.ClassName;
  540. end;
  541. end;
  542. UpdateImageSettings;
  543. end;
  544. FBlur := Value;
  545. end;
  546. procedure TGLBlur.SetBlurSelf(const Value: boolean);
  547. begin
  548. FBlurSelf := Value;
  549. end;
  550. procedure TGLBlur.SetOnAdvancedBlurImagePrepareEvent(const Value: TGLAdvancedBlurImagePrepareEvent);
  551. begin
  552. FOnAdvancedBlurImagePrepareEvent := Value;
  553. end;
  554. procedure TGLBlur.SetOnAfterTargetRender(const Value: TNotifyEvent);
  555. begin
  556. FOnAfterTargetRender := Value;
  557. end;
  558. procedure TGLBlur.SetOnBeforeTargetRender(const Value: TNotifyEvent);
  559. begin
  560. FOnBeforeTargetRender := Value;
  561. end;
  562. procedure TGLBlur.SetPreset(const Value: TGLBlurPreset);
  563. begin
  564. FPreset := Value;
  565. case FPreset of
  566. pNone:
  567. begin
  568. // do nothing
  569. end;
  570. pAdvancedBlur:
  571. begin
  572. Blur := bAdvanced;
  573. Material.BlendingMode := bmAdditive;
  574. Material.FrontProperties.Diffuse.SetColor(1, 1, 1, 1);
  575. BlurTop := 0;
  576. BlurLeft := 0;
  577. BlurRight := 0;
  578. BlurBottom := 0;
  579. BlurDeltaTime := 0;
  580. BlurSelf := false;
  581. AdvancedBlurPasses := 1;
  582. AdvancedBlurAmp := 1.2;
  583. RenderWidth := 64;
  584. RenderHeight := 64;
  585. end;
  586. pGlossy:
  587. begin
  588. Material.BlendingMode := bmAdditive;
  589. Material.FrontProperties.Diffuse.SetColor(1, 1, 1, 0.7);
  590. BlurTop := 0.02;
  591. BlurLeft := 0.02;
  592. BlurRight := 0.02;
  593. BlurBottom := 0.02;
  594. BlurDeltaTime := 0.02;
  595. BlurSelf := true;
  596. end;
  597. pBeastView:
  598. begin
  599. Blur := bSimple;
  600. Material.BlendingMode := bmAdditive;
  601. Material.FrontProperties.Diffuse.SetColor(1, 0, 0, 0.8);
  602. BlurTop := 0.001;
  603. BlurLeft := 0.03;
  604. BlurRight := 0.03;
  605. BlurBottom := 0.001;
  606. BlurDeltaTime := 0.02;
  607. BlurSelf := true;
  608. end;
  609. pOceanDepth:
  610. begin
  611. Blur := bSimple;
  612. Material.BlendingMode := bmTransparency;
  613. Material.FrontProperties.Diffuse.SetColor(0.2, 0.2, 1, 0.99);
  614. BlurTop := 0.04;
  615. BlurLeft := 0.02;
  616. BlurRight := 0.02;
  617. BlurBottom := 0.04;
  618. BlurDeltaTime := 0.02;
  619. BlurSelf := true;
  620. end;
  621. pDream:
  622. begin
  623. Blur := bSimple;
  624. Material.BlendingMode := bmTransparency;
  625. Material.FrontProperties.Diffuse.SetColor(1, 1, 1, 0.992);
  626. BlurTop := 0.02;
  627. BlurLeft := 0.02;
  628. BlurRight := 0.02;
  629. BlurBottom := 0.02;
  630. BlurDeltaTime := 0.1;
  631. BlurSelf := true;
  632. end;
  633. pOverBlur:
  634. begin
  635. Blur := bSimple;
  636. Material.BlendingMode := bmAdditive;
  637. Material.FrontProperties.Diffuse.SetColor(0.95, 0.95, 0.95, 0.98);
  638. BlurTop := 0.01;
  639. BlurLeft := 0.01;
  640. BlurRight := 0.01;
  641. BlurBottom := 0.01;
  642. BlurDeltaTime := 0.02;
  643. BlurSelf := true;
  644. end;
  645. end;
  646. end;
  647. function TGLBlur.StoreBlurBottom: Boolean;
  648. begin
  649. Result := Abs(FBlurBottom - 0.01) > EPS;
  650. end;
  651. function TGLBlur.StoreBlurDeltaTime: Boolean;
  652. begin
  653. Result := Abs(FBlurDeltaTime - 0.02) > EPS;
  654. end;
  655. function TGLBlur.StoreBlurLeft: Boolean;
  656. begin
  657. Result := Abs(FBlurLeft - 0.01) > EPS;
  658. end;
  659. function TGLBlur.StoreBlurRight: Boolean;
  660. begin
  661. Result := Abs(FBlurRight - 0.01) > EPS;
  662. end;
  663. function TGLBlur.StoreBlurTop: Boolean;
  664. begin
  665. Result := Abs(FBlurTop - 0.01) > EPS;
  666. end;
  667. //-------------------------------------------------
  668. { TGLMotionBlur }
  669. //-------------------------------------------------
  670. procedure TGLMotionBlur.Assign(Source: TPersistent);
  671. begin
  672. inherited;
  673. if Source is TGLMotionBlur then
  674. begin
  675. FIntensity := TGLMotionBlur(Source).FIntensity;
  676. end;
  677. end;
  678. constructor TGLMotionBlur.Create(aOwner: TComponent);
  679. begin
  680. inherited Create(aOwner);
  681. Material.FrontProperties.Diffuse.Initialize(clrBlack);
  682. Material.MaterialOptions := [moNoLighting, moIgnoreFog];
  683. Material.Texture.Disabled := False;
  684. Material.BlendingMode := bmTransparency;
  685. FIntensity := 0.975;
  686. end;
  687. procedure TGLMotionBlur.DoOnAddedToParent;
  688. begin
  689. inherited;
  690. // Request to be initialized on next render.
  691. if Scene <> nil then
  692. Scene.InitializableObjects.Add(Self);
  693. end;
  694. procedure TGLMotionBlur.DoRender(var ARci: TGLRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
  695. begin
  696. if not (ARci.ignoreMaterials or (csDesigning in ComponentState) or
  697. (ARci.drawState = dsPicking)) then
  698. with ARci.GLStates do
  699. begin
  700. ARci.ignoreDepthRequests := True;
  701. Material.Apply(ARci);
  702. ActiveTextureEnabled[ttTextureRect] := True;
  703. gl.MatrixMode(GL_PROJECTION);
  704. gl.PushMatrix;
  705. gl.LoadIdentity;
  706. gl.Ortho(0, ARci.viewPortSize.cx, ARci.viewPortSize.cy, 0, 0, 1);
  707. gl.MatrixMode(GL_MODELVIEW);
  708. gl.PushMatrix;
  709. gl.LoadIdentity;
  710. Disable(stDepthTest);
  711. DepthWriteMask := False;
  712. gl.Begin_(GL_QUADS);
  713. gl.TexCoord2f(0.0, ARci.viewPortSize.cy);
  714. gl.Vertex2f(0, 0);
  715. gl.TexCoord2f(0.0, 0.0);
  716. gl.Vertex2f(0, ARci.viewPortSize.cy);
  717. gl.TexCoord2f(ARci.viewPortSize.cx, 0.0);
  718. gl.Vertex2f(ARci.viewPortSize.cx, ARci.viewPortSize.cy);
  719. gl.TexCoord2f(ARci.viewPortSize.cx, ARci.viewPortSize.cy);
  720. gl.Vertex2f(ARci.viewPortSize.cx, 0);
  721. gl.End_;
  722. gl.PopMatrix;
  723. gl.MatrixMode(GL_PROJECTION);
  724. gl.PopMatrix;
  725. gl.MatrixMode(GL_MODELVIEW);
  726. ActiveTextureEnabled[ttTextureRect] := False;
  727. Material.UnApply(ARci);
  728. ARci.ignoreDepthRequests := False;
  729. gl.CopyTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGB, 0, 0, ARci.viewPortSize.cx, ARci.viewPortSize.cy, 0);
  730. Material.FrontProperties.Diffuse.Alpha := FIntensity;
  731. end;
  732. if Count <> 0 then
  733. Self.RenderChildren(0, Count - 1, ARci);
  734. end;
  735. procedure TGLMotionBlur.InitializeObject(ASender: TObject;
  736. const ARci: TGLRenderContextInfo);
  737. begin
  738. // If extension is not supported, silently disable this component.
  739. if not (csDesigning in ComponentState) then
  740. if not SupportsRequiredExtensions then
  741. Visible := False;
  742. end;
  743. function TGLMotionBlur.StoreIntensity: Boolean;
  744. begin
  745. Result := Abs(FIntensity - 0.975) > EPS;
  746. end;
  747. function TGLMotionBlur.SupportsRequiredExtensions: Boolean;
  748. begin
  749. Result :=
  750. gl.ARB_texture_rectangle or gl.EXT_texture_rectangle or gl.NV_texture_rectangle;
  751. end;
  752. // ------------------------------------------------------------------
  753. initialization
  754. // ------------------------------------------------------------------
  755. RegisterClass(TGLBlur);
  756. RegisterClass(TGLMotionBlur);
  757. end.