GLS.Blur.pas 26 KB

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