GXS.FBORenderer.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. //
  2. // The graphics engine GXScene https://github.com/glscene
  3. //
  4. unit GXS.FBORenderer;
  5. (* Implements FBO support *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. Winapi.OpenGL,
  10. Winapi.OpenGLext,
  11. System.Classes,
  12. System.SysUtils,
  13. FMX.Dialogs,
  14. GXS.PersistentClasses,
  15. Stage.VectorGeometry,
  16. GXS.Scene,
  17. GXS.Texture,
  18. GXS.Context,
  19. GXS.FBO,
  20. GXS.Color,
  21. GXS.Material,
  22. GXS.RenderContextInfo,
  23. GXS.State,
  24. Stage.PipelineTransform,
  25. Stage.TextureFormat,
  26. Stage.VectorTypes,
  27. GXS.MultisampleImage;
  28. type
  29. TgxEnabledRenderBuffer = (erbDepth, erbStencil);
  30. TgxEnabledRenderBuffers = set of TgxEnabledRenderBuffer;
  31. TgxFBOTargetVisibility = (tvDefault, tvFBOOnly);
  32. TgxFBOClearOption = (coColorBufferClear, coDepthBufferClear, coStencilBufferClear, coUseBufferBackground);
  33. TgxFBOClearOptions = set of TgxFBOClearOption;
  34. TgxTextureArray = array of TgxTexture;
  35. TSetTextureTargetsEvent = procedure(Sender: TObject; var colorTexs: TgxTextureArray) of object;
  36. TgxFBORenderer = class(TgxBaseSceneObject, IgxMaterialLibrarySupported)
  37. private
  38. FFbo: TgxFrameBuffer;
  39. FDepthRBO: TgxDepthRBO;
  40. FStencilRBO: TgxStencilRBO;
  41. FColorAttachment: Integer;
  42. FRendering: Boolean;
  43. FHasColor: Boolean;
  44. FHasDepth: Boolean;
  45. FHasStencil: Boolean;
  46. FMaterialLibrary: TgxMaterialLibrary;
  47. FColorTextureName: TgxLibMaterialName;
  48. FDepthTextureName: TgxLibMaterialName;
  49. FWidth: Integer;
  50. FHeight: Integer;
  51. FForceTextureDimensions: Boolean;
  52. FStencilPrecision: TgxStencilPrecision;
  53. FRootObject: TgxBaseSceneObject;
  54. FRootVisible: Boolean;
  55. FCamera: TgxCamera;
  56. FEnabledRenderBuffers: TgxEnabledRenderBuffers;
  57. FTargetVisibility: TgxFBOTargetVisibility;
  58. FBeforeRender: TDirectRenderEvent;
  59. FPostInitialize: TNotifyEvent;
  60. FAfterRender: TDirectRenderEvent;
  61. FPreInitialize: TNotifyEvent;
  62. FBackgroundColor: TgxColor;
  63. FClearOptions: TgxFBOClearOptions;
  64. FAspect: Single;
  65. FSceneScaleFactor: Single;
  66. FUseLibraryAsMultiTarget: Boolean;
  67. FPostGenerateMipmap: Boolean;
  68. FMaxSize: Integer;
  69. FMaxAttachment: Integer;
  70. FStoreCamera: array [0 .. 2] of TVector4f;
  71. FOnSetTextureTargets: TSetTextureTargetsEvent;
  72. // implementing IGLMaterialLibrarySupported
  73. function GetMaterialLibrary: TgxAbstractMaterialLibrary;
  74. procedure SetMaterialLibrary(const Value: TgxAbstractMaterialLibrary);
  75. procedure SetDepthTextureName(const Value: TgxLibMaterialName);
  76. procedure SetColorTextureName(const Value: TgxLibMaterialName);
  77. procedure SetForceTextureDimentions(const Value: Boolean);
  78. procedure SetHeight(Value: Integer);
  79. procedure SetWidth(Value: Integer);
  80. procedure SetLayer(const Value: Integer);
  81. function GetLayer: Integer;
  82. procedure SetLevel(const Value: Integer);
  83. function GetLevel: Integer;
  84. procedure SetStencilPrecision(const Value: TgxStencilPrecision);
  85. procedure SetRootObject(const Value: TgxBaseSceneObject);
  86. function GetViewport: TRectangle;
  87. procedure SetCamera(const Value: TgxCamera);
  88. procedure SetEnabledRenderBuffers(const Value: TgxEnabledRenderBuffers);
  89. procedure SetTargetVisibility(const Value: TgxFBOTargetVisibility);
  90. procedure SetBackgroundColor(const Value: TgxColor);
  91. function StoreSceneScaleFactor: Boolean;
  92. function StoreAspect: Boolean;
  93. procedure SetUseLibraryAsMultiTarget(Value: Boolean);
  94. procedure SetPostGenerateMipmap(const Value: Boolean);
  95. protected
  96. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  97. procedure Initialize;
  98. procedure ForceDimensions(Texture: TgxTexture);
  99. procedure RenderToFBO(var ARci: TgxRenderContextInfo);
  100. procedure ApplyCamera(var ARci: TgxRenderContextInfo);
  101. procedure UnApplyCamera(var ARci: TgxRenderContextInfo);
  102. procedure DoBeforeRender(var ARci: TgxRenderContextInfo);
  103. procedure DoAfterRender(var ARci: TgxRenderContextInfo);
  104. procedure DoPreInitialize;
  105. procedure DoPostInitialize;
  106. property HasColor: Boolean read FHasColor;
  107. property HasDepth: Boolean read FHasDepth;
  108. property HasStencil: Boolean read FHasStencil;
  109. property Viewport: TRectangle read GetViewport;
  110. public
  111. constructor Create(AOwner: TComponent); override;
  112. destructor Destroy; override;
  113. procedure DoRender(var ARci: TgxRenderContextInfo; ARenderSelf: Boolean; ARenderChildren: Boolean); override;
  114. (* Layer (also cube map face) is activated only on
  115. the volume textures, texture array and cube map.
  116. You can select the layer during the drawing to. *)
  117. property Layer: Integer read GetLayer write SetLayer;
  118. // Mipmap Level where will be rendering
  119. property Level: Integer read GetLevel write SetLevel;
  120. published
  121. property Active: Boolean read GetVisible write SetVisible default True;
  122. property PickableTarget: Boolean read GetPickable write SetPickable default False;
  123. { force texture dimensions when initializing
  124. only works with TgxBlankImage and GLfloatDataImage, otherwise does nothing }
  125. property ForceTextureDimensions: Boolean read FForceTextureDimensions write SetForceTextureDimentions default True;
  126. property Width: Integer read FWidth write SetWidth default 256;
  127. property Height: Integer read FHeight write SetHeight default 256;
  128. property Aspect: Single read FAspect write FAspect stored StoreAspect;
  129. property ColorTextureName: TgxLibMaterialName read FColorTextureName write SetColorTextureName;
  130. property DepthTextureName: TgxLibMaterialName read FDepthTextureName write SetDepthTextureName;
  131. property MaterialLibrary: TgxAbstractMaterialLibrary read GetMaterialLibrary write SetMaterialLibrary;
  132. property BackgroundColor: TgxColor read FBackgroundColor write SetBackgroundColor;
  133. property ClearOptions: TgxFBOClearOptions read FClearOptions write FClearOptions;
  134. { camera used for rendering to the FBO
  135. if not assigned, use the active view's camera }
  136. property Camera: TgxCamera read FCamera write SetCamera;
  137. { adjust the scene scale of the camera so that the rendering
  138. becomes independent of the width of the fbo renderer
  139. 0 = disabled }
  140. property SceneScaleFactor: Single read FSceneScaleFactor write FSceneScaleFactor stored StoreSceneScaleFactor;
  141. { root object used when rendering to the FBO
  142. if not assigned, uses itself as root and renders the child objects to the FBO }
  143. property RootObject: TgxBaseSceneObject read FRootObject write SetRootObject;
  144. { determines if target is rendered to FBO only or rendered normally
  145. in FBO only mode, if RootObject is assigned, the RootObject's Visible flag is modified
  146. in default mode, if RootObject is not assigned, children are rendered normally after being
  147. rendered to the FBO }
  148. property TargetVisibility: TgxFBOTargetVisibility read FTargetVisibility write SetTargetVisibility default tvDefault;
  149. { Enables the use of a render buffer if a texture is not assigned }
  150. property EnabledRenderBuffers: TgxEnabledRenderBuffers read FEnabledRenderBuffers write SetEnabledRenderBuffers;
  151. { use stencil buffer }
  152. property StencilPrecision: TgxStencilPrecision read FStencilPrecision write SetStencilPrecision default spDefault;
  153. { called before rendering to the FBO }
  154. property BeforeRender: TDirectRenderEvent read FBeforeRender write FBeforeRender;
  155. { called after the rendering to the FBO }
  156. property AfterRender: TDirectRenderEvent read FAfterRender write FAfterRender;
  157. { Called before the FBO is initialized
  158. the FBO is bound before calling this event }
  159. property PreInitialize: TNotifyEvent read FPreInitialize write FPreInitialize;
  160. { Called after the FBO is initialized, but before any rendering
  161. the FBO is bound before calling this event }
  162. property PostInitialize: TNotifyEvent read FPostInitialize write FPostInitialize;
  163. property UseLibraryAsMultiTarget: Boolean read FUseLibraryAsMultiTarget write SetUseLibraryAsMultiTarget default False;
  164. { Control mipmap generation after rendering
  165. texture must have MinFilter with mipmaping }
  166. property PostGenerateMipmap: Boolean read FPostGenerateMipmap write SetPostGenerateMipmap default True;
  167. { Allows multiTargeting to different texture sources instead of all coming
  168. from one single MatLib with UseLibraryAsMultiTarget. OnSetTextureTargets
  169. overrides the other method of setting target textures via the MaterialLibrary,
  170. ColorTextureName and DepthTextureName propertes }
  171. property OnSetTextureTargets: TSetTextureTargetsEvent read FOnSetTextureTargets write FOnSetTextureTargets;
  172. end;
  173. //------------------------------------------------------------------------------
  174. implementation
  175. //------------------------------------------------------------------------------
  176. //------------------------------------------------------------------------------
  177. // TgxFBORenderer
  178. //------------------------------------------------------------------------------
  179. procedure TgxFBORenderer.ApplyCamera(var ARci: TgxRenderContextInfo);
  180. var
  181. sc: Single;
  182. begin
  183. with ARci.PipelineTransformation do
  184. begin
  185. Push;
  186. if Assigned(Camera) then
  187. begin
  188. FStoreCamera[0] := ARci.cameraPosition;
  189. FStoreCamera[1] := ARci.cameraDirection;
  190. FStoreCamera[2] := ARci.cameraUp;
  191. IdentityAll;
  192. sc := FCamera.SceneScale;
  193. if FSceneScaleFactor > 0 then
  194. FCamera.SceneScale := Width / FSceneScaleFactor;
  195. FCamera.ApplyPerspective(Viewport, Width, Height, 96);
  196. // 96 is default dpi
  197. FCamera.SceneScale := sc;
  198. SetViewMatrix(CreateScaleMatrix(Vector3fMake(1.0 / FAspect, 1.0, 1.0)));
  199. FCamera.Apply;
  200. end
  201. else
  202. begin
  203. SetViewMatrix(MatrixMultiply(ViewMatrix^, CreateScaleMatrix(Vector3fMake(1.0 / FAspect, 1.0, 1.0))));
  204. end;
  205. end;
  206. end;
  207. procedure TgxFBORenderer.UnApplyCamera(var ARci: TgxRenderContextInfo);
  208. begin
  209. ARci.cameraPosition := FStoreCamera[0];
  210. ARci.cameraDirection := FStoreCamera[1];
  211. ARci.cameraUp := FStoreCamera[2];
  212. ARci.PipelineTransformation.Pop;
  213. end;
  214. constructor TgxFBORenderer.Create(AOwner: TComponent);
  215. begin
  216. inherited;
  217. ObjectStyle := [osDirectDraw, osNoVisibilityCulling];
  218. FFbo := TgxFrameBuffer.Create;
  219. FBackgroundColor := TgxColor.Create(Self);
  220. FUseLibraryAsMultiTarget := False;
  221. FForceTextureDimensions := True;
  222. FWidth := 256;
  223. FHeight := 256;
  224. FEnabledRenderBuffers := [erbDepth];
  225. FClearOptions := [coColorBufferClear, coDepthBufferClear, coStencilBufferClear, coUseBufferBackground];
  226. PickableTarget := False;
  227. FAspect := 1.0;
  228. FSceneScaleFactor := 0.0;
  229. FPostGenerateMipmap := True;
  230. StructureChanged;
  231. end;
  232. destructor TgxFBORenderer.Destroy;
  233. begin
  234. FFbo.Free;
  235. FDepthRBO.Free;
  236. FStencilRBO.Free;
  237. FBackgroundColor.Free;
  238. inherited;
  239. end;
  240. procedure TgxFBORenderer.Notification(AComponent: TComponent; Operation: TOperation);
  241. begin
  242. inherited;
  243. if (AComponent = FRootObject) and (Operation = opRemove) then
  244. FRootObject := nil;
  245. end;
  246. procedure TgxFBORenderer.DoAfterRender(var ARci: TgxRenderContextInfo);
  247. begin
  248. if Assigned(FAfterRender) then
  249. FAfterRender(Self, ARci);
  250. end;
  251. procedure TgxFBORenderer.DoBeforeRender(var ARci: TgxRenderContextInfo);
  252. begin
  253. if Assigned(FBeforeRender) then
  254. FBeforeRender(Self, ARci);
  255. end;
  256. procedure TgxFBORenderer.DoPostInitialize;
  257. begin
  258. if Assigned(FPostInitialize) then
  259. FPostInitialize(Self);
  260. end;
  261. procedure TgxFBORenderer.DoPreInitialize;
  262. begin
  263. if Assigned(FPreInitialize) then
  264. FPreInitialize(Self);
  265. end;
  266. procedure TgxFBORenderer.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
  267. begin
  268. if not(csDesigning in ComponentState) then
  269. RenderToFBO(ARci);
  270. if (not Assigned(FRootObject)) and (TargetVisibility = tvDefault) and ARenderChildren then
  271. RenderChildren(0, Count - 1, ARci);
  272. end;
  273. procedure TgxFBORenderer.ForceDimensions(Texture: TgxTexture);
  274. var
  275. bi: TgxBlankImage;
  276. mi: TgxMultisampleImage;
  277. begin
  278. if Texture.Image is TgxBlankImage then
  279. begin
  280. bi := TgxBlankImage(Texture.Image);
  281. bi.Width := Width;
  282. bi.Height := Height;
  283. end
  284. else if Texture.Image is TgxMultisampleImage then
  285. begin
  286. mi := TgxMultisampleImage(Texture.Image);
  287. mi.Width := Width;
  288. mi.Height := Height;
  289. end;
  290. end;
  291. function TgxFBORenderer.GetViewport: TRectangle;
  292. begin
  293. Result.Left := 0;
  294. Result.Top := 0;
  295. Result.Width := Width;
  296. Result.Height := Height;
  297. end;
  298. procedure TgxFBORenderer.Initialize;
  299. procedure AddOneMultiTarget(colorTex: TgxTexture);
  300. begin
  301. if ForceTextureDimensions then
  302. ForceDimensions(colorTex);
  303. if FColorAttachment >= FMaxAttachment then
  304. begin
  305. ShowMessage('Number of color attachments out of GL_MAX_COLOR_ATTACHMENTS');
  306. Visible := False;
  307. Abort;
  308. end;
  309. FFbo.AttachTexture(FColorAttachment, colorTex);
  310. Inc(FColorAttachment);
  311. end;
  312. const
  313. cDrawBuffers: array [0 .. 15] of GLenum = (GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
  314. GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5, GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7,
  315. GL_COLOR_ATTACHMENT8, GL_COLOR_ATTACHMENT9, GL_COLOR_ATTACHMENT10, GL_COLOR_ATTACHMENT11, GL_COLOR_ATTACHMENT12,
  316. GL_COLOR_ATTACHMENT13, GL_COLOR_ATTACHMENT14, GL_COLOR_ATTACHMENT15);
  317. var
  318. colorTex: TgxTexture;
  319. depthTex: TgxTexture;
  320. I: Integer;
  321. MulTexture: TgxTextureArray;
  322. begin
  323. for I := 0 to MaxColorAttachments - 1 do
  324. FFbo.DetachTexture(I);
  325. if FMaxSize = 0 then
  326. glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, @FMaxSize);
  327. if Width > FMaxSize then
  328. begin
  329. FWidth := FMaxSize;
  330. ShowMessage(Format('%s.Width out of GL_MAX_RENDERBUFFER_SIZE', [Name]));
  331. end;
  332. if Height > FMaxSize then
  333. begin
  334. FHeight := FMaxSize;
  335. ShowMessage(Format('%s.Height out of GL_MAX_RENDERBUFFER_SIZE', [Name]));
  336. end;
  337. FFbo.Width := Width;
  338. FFbo.Height := Height;
  339. FFbo.Bind;
  340. DoPreInitialize;
  341. FFbo.Unbind;
  342. if Assigned(FMaterialLibrary) then
  343. begin
  344. colorTex := FMaterialLibrary.TextureByName(ColorTextureName);
  345. depthTex := FMaterialLibrary.TextureByName(DepthTextureName);
  346. end
  347. else
  348. begin
  349. colorTex := nil;
  350. depthTex := nil;
  351. end;
  352. FHasColor := False;
  353. FHasDepth := False;
  354. FHasStencil := False;
  355. FColorAttachment := 0;
  356. if FUseLibraryAsMultiTarget or Assigned(FOnSetTextureTargets) then
  357. begin
  358. if FMaxAttachment = 0 then
  359. glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, @FMaxAttachment);
  360. if Assigned(FOnSetTextureTargets) then
  361. begin
  362. FOnSetTextureTargets(Self, MulTexture);
  363. for I := 0 to High(MulTexture) do
  364. begin
  365. colorTex := MulTexture[I];
  366. // Skip depth texture
  367. if colorTex = depthTex then
  368. Continue;
  369. AddOneMultiTarget(colorTex);
  370. end;
  371. end
  372. else
  373. // Multicolor attachments
  374. for I := 0 to FMaterialLibrary.Materials.Count - 1 do
  375. begin
  376. colorTex := FMaterialLibrary.Materials[I].Material.Texture;
  377. // Skip depth texture
  378. if colorTex = depthTex then
  379. Continue;
  380. AddOneMultiTarget(colorTex);
  381. end;
  382. FHasColor := FColorAttachment > 0;
  383. end
  384. else
  385. begin
  386. // One color attachment
  387. if Assigned(colorTex) then
  388. begin
  389. if ForceTextureDimensions then
  390. ForceDimensions(colorTex);
  391. FFbo.AttachTexture(0, colorTex);
  392. Inc(FColorAttachment);
  393. FHasColor := True;
  394. end;
  395. end;
  396. if Assigned(depthTex) then
  397. begin
  398. if ForceTextureDimensions then
  399. ForceDimensions(depthTex);
  400. FFbo.AttachDepthTexture(depthTex);
  401. FDepthRBO.Free;
  402. FDepthRBO := nil;
  403. FHasDepth := True;
  404. FHasStencil := depthTex.TextureFormatEx = tfDEPTH24_STENCIL8;
  405. end
  406. else if erbDepth in EnabledRenderBuffers then
  407. begin
  408. if not Assigned(FDepthRBO) then
  409. FDepthRBO := TgxDepthRBO.Create;
  410. FDepthRBO.Width := Width;
  411. FDepthRBO.Height := Height;
  412. FFbo.AttachDepthBuffer(FDepthRBO);
  413. FHasDepth := True;
  414. end
  415. else
  416. begin
  417. FFbo.DetachDepthBuffer;
  418. if Assigned(FDepthRBO) then
  419. begin
  420. FDepthRBO.Free;
  421. FDepthRBO := nil;
  422. end;
  423. end;
  424. if erbStencil in EnabledRenderBuffers then
  425. begin
  426. if not Assigned(FStencilRBO) then
  427. FStencilRBO := TgxStencilRBO.Create;
  428. FStencilRBO.StencilPrecision := FStencilPrecision;
  429. FStencilRBO.Width := Width;
  430. FStencilRBO.Height := Height;
  431. FFbo.AttachStencilBuffer(FStencilRBO);
  432. FHasStencil := True;
  433. end
  434. else
  435. begin
  436. if not FHasStencil then
  437. FFbo.DetachStencilBuffer;
  438. if Assigned(FStencilRBO) then
  439. begin
  440. FStencilRBO.Free;
  441. FStencilRBO := nil;
  442. end;
  443. end;
  444. FFbo.Bind;
  445. if FColorAttachment = 0 then
  446. begin
  447. glDrawBuffer(GL_NONE);
  448. glReadBuffer(GL_NONE);
  449. end
  450. else
  451. glDrawBuffers(FColorAttachment, @cDrawBuffers);
  452. DoPostInitialize;
  453. FFbo.Unbind;
  454. /// CheckOpenGLError;
  455. ClearStructureChanged;
  456. end;
  457. procedure TgxFBORenderer.RenderToFBO(var ARci: TgxRenderContextInfo);
  458. function GetClearBits: cardinal;
  459. begin
  460. Result := 0;
  461. if HasColor and (coColorBufferClear in FClearOptions) then
  462. Result := Result or GL_COLOR_BUFFER_BIT;
  463. if HasDepth and (coDepthBufferClear in FClearOptions) then
  464. Result := Result or GL_DEPTH_BUFFER_BIT;
  465. if HasStencil and (coStencilBufferClear in FClearOptions) then
  466. Result := Result or GL_STENCIL_BUFFER_BIT;
  467. end;
  468. type
  469. TgxStoredStates = record
  470. ColorClearValue: TgxColorVector;
  471. ColorWriteMask: TgxColorMask;
  472. Tests: TgxStates;
  473. end;
  474. function StoreStates: TgxStoredStates;
  475. begin
  476. Result.ColorClearValue := ARci.gxStates.ColorClearValue;
  477. Result.ColorWriteMask := ARci.gxStates.ColorWriteMask[0];
  478. Result.Tests := [stDepthTest, stStencilTest] * ARci.gxStates.States;
  479. end;
  480. procedure RestoreStates(const aStates: TgxStoredStates);
  481. begin
  482. ARci.gxStates.ColorClearValue := aStates.ColorClearValue;
  483. ARci.gxStates.SetColorMask(aStates.ColorWriteMask);
  484. if stDepthTest in aStates.Tests then
  485. ARci.gxStates.Enable(stDepthTest)
  486. else
  487. ARci.gxStates.Disable(stDepthTest);
  488. if stStencilTest in aStates.Tests then
  489. ARci.gxStates.Enable(stStencilTest)
  490. else
  491. ARci.gxStates.Disable(stStencilTest);
  492. end;
  493. var
  494. backColor: TgxColorVector;
  495. buffer: TgxSceneBuffer;
  496. savedStates: TgxStoredStates;
  497. w, h: Integer;
  498. s: string;
  499. begin
  500. if (ARci.drawState = dsPicking) and not PickableTarget then
  501. exit;
  502. if TgxFramebufferHandle.IsSupported = True then
  503. begin
  504. ShowMessage('Framebuffer not supported - deactivated');
  505. Active := False;
  506. exit;
  507. end;
  508. // prevent recursion
  509. if FRendering then
  510. exit;
  511. FRendering := True;
  512. if (ocStructure in Changes) or Assigned(FOnSetTextureTargets) then
  513. begin
  514. Initialize;
  515. if not Active then
  516. exit;
  517. end;
  518. ApplyCamera(ARci);
  519. try
  520. savedStates := StoreStates;
  521. FFbo.Bind;
  522. if FFbo.GetStringStatus(s) <> fsComplete then
  523. begin
  524. ShowMessage(Format('Framebuffer error: %s. Deactivated', [s]));
  525. Active := False;
  526. exit;
  527. end;
  528. DoBeforeRender(ARci);
  529. if Assigned(Camera) then
  530. Camera.Scene.SetupLights(ARci.gxStates.MaxLights);
  531. w := Width;
  532. h := Height;
  533. if FFbo.Level > 0 then
  534. begin
  535. w := w shr FFbo.Level;
  536. h := h shr FFbo.Level;
  537. if w = 0 then
  538. w := 1;
  539. if h = 0 then
  540. h := 1;
  541. end;
  542. ARci.gxStates.Viewport := Vector4iMake(0, 0, w, h);
  543. buffer := ARci.buffer as TgxSceneBuffer;
  544. if HasColor then
  545. ARci.gxStates.SetColorMask(cAllColorComponents)
  546. else
  547. ARci.gxStates.SetColorMask([]);
  548. ARci.gxStates.DepthWriteMask := HasDepth;
  549. if HasStencil then
  550. ARci.gxStates.Enable(stStencilTest)
  551. else
  552. ARci.gxStates.Disable(stStencilTest);
  553. if coUseBufferBackground in FClearOptions then
  554. begin
  555. backColor := ConvertWinColor(buffer.BackgroundColor);
  556. backColor.w := buffer.BackgroundAlpha;
  557. ARci.gxStates.ColorClearValue := backColor;
  558. end
  559. else
  560. begin
  561. ARci.gxStates.ColorClearValue := FBackgroundColor.Color;
  562. end;
  563. glClear(GetClearBits);
  564. FFbo.PreRender;
  565. // render to fbo
  566. if Assigned(RootObject) then
  567. begin
  568. // if object should only be rendered to the fbo
  569. // ensure it's visible before rendering to fbo
  570. if TargetVisibility = tvFBOOnly then
  571. RootObject.Visible := True;
  572. RootObject.Render(ARci);
  573. // then make it invisible afterwards
  574. if TargetVisibility = tvFBOOnly then
  575. RootObject.Visible := False;
  576. end
  577. else if (Count > 0) then
  578. RenderChildren(0, Count - 1, ARci);
  579. FFbo.PostRender(FPostGenerateMipmap);
  580. RestoreStates(savedStates);
  581. ARci.gxStates.Viewport := Vector4iMake(0, 0, ARci.viewPortSize.cx, ARci.viewPortSize.cy);
  582. finally
  583. FFbo.Unbind;
  584. FRendering := False;
  585. DoAfterRender(ARci);
  586. UnApplyCamera(ARci);
  587. if Assigned(Camera) then
  588. Camera.Scene.SetupLights(ARci.gxStates.MaxLights);
  589. end;
  590. end;
  591. procedure TgxFBORenderer.SetBackgroundColor(const Value: TgxColor);
  592. begin
  593. FBackgroundColor.Assign(Value);
  594. end;
  595. procedure TgxFBORenderer.SetCamera(const Value: TgxCamera);
  596. begin
  597. if FCamera <> Value then
  598. begin
  599. FCamera := Value;
  600. StructureChanged;
  601. end;
  602. end;
  603. procedure TgxFBORenderer.SetColorTextureName(const Value: TgxLibMaterialName);
  604. begin
  605. if FColorTextureName <> Value then
  606. begin
  607. FColorTextureName := Value;
  608. StructureChanged;
  609. end;
  610. end;
  611. procedure TgxFBORenderer.SetDepthTextureName(const Value: TgxLibMaterialName);
  612. begin
  613. if FDepthTextureName <> Value then
  614. begin
  615. FDepthTextureName := Value;
  616. StructureChanged;
  617. end;
  618. end;
  619. procedure TgxFBORenderer.SetEnabledRenderBuffers(const Value: TgxEnabledRenderBuffers);
  620. begin
  621. if FEnabledRenderBuffers <> Value then
  622. begin
  623. FEnabledRenderBuffers := Value;
  624. StructureChanged;
  625. end;
  626. end;
  627. procedure TgxFBORenderer.SetForceTextureDimentions(const Value: Boolean);
  628. begin
  629. if FForceTextureDimensions <> Value then
  630. begin
  631. FForceTextureDimensions := Value;
  632. StructureChanged;
  633. end;
  634. end;
  635. function TgxFBORenderer.GetMaterialLibrary: TgxAbstractMaterialLibrary;
  636. begin
  637. Result := FMaterialLibrary;
  638. end;
  639. procedure TgxFBORenderer.SetMaterialLibrary(const Value: TgxAbstractMaterialLibrary);
  640. begin
  641. if FMaterialLibrary <> Value then
  642. begin
  643. if Value is TgxMaterialLibrary then
  644. begin
  645. FMaterialLibrary := TgxMaterialLibrary(Value);
  646. StructureChanged;
  647. end;
  648. end;
  649. end;
  650. procedure TgxFBORenderer.SetUseLibraryAsMultiTarget(Value: Boolean);
  651. begin
  652. if FUseLibraryAsMultiTarget <> Value then
  653. begin
  654. FUseLibraryAsMultiTarget := Value;
  655. StructureChanged;
  656. end;
  657. end;
  658. procedure TgxFBORenderer.SetPostGenerateMipmap(const Value: Boolean);
  659. begin
  660. if FPostGenerateMipmap <> Value then
  661. FPostGenerateMipmap := Value;
  662. end;
  663. procedure TgxFBORenderer.SetRootObject(const Value: TgxBaseSceneObject);
  664. begin
  665. if FRootObject <> Value then
  666. begin
  667. if Assigned(FRootObject) then
  668. FRootObject.RemoveFreeNotification(Self);
  669. FRootObject := Value;
  670. if Assigned(FRootObject) then
  671. FRootObject.FreeNotification(Self);
  672. StructureChanged;
  673. end;
  674. end;
  675. procedure TgxFBORenderer.SetStencilPrecision(const Value: TgxStencilPrecision);
  676. begin
  677. if FStencilPrecision <> Value then
  678. begin
  679. FStencilPrecision := Value;
  680. StructureChanged;
  681. end;
  682. end;
  683. procedure TgxFBORenderer.SetTargetVisibility(const Value: TgxFBOTargetVisibility);
  684. begin
  685. if FTargetVisibility <> Value then
  686. begin
  687. if Assigned(RootObject) then
  688. begin
  689. if (TargetVisibility = tvFBOOnly) then
  690. begin
  691. // we went from fbo only, restore root's old visibility
  692. RootObject.Visible := FRootVisible;
  693. end
  694. else
  695. begin
  696. // we're going to fbo only, save root visibility for later
  697. FRootVisible := RootObject.Visible;
  698. end;
  699. end;
  700. FTargetVisibility := Value;
  701. StructureChanged;
  702. end;
  703. end;
  704. function TgxFBORenderer.StoreSceneScaleFactor: Boolean;
  705. begin
  706. Result := (FSceneScaleFactor <> 0.0);
  707. end;
  708. function TgxFBORenderer.StoreAspect: Boolean;
  709. begin
  710. Result := (FAspect <> 1.0);
  711. end;
  712. procedure TgxFBORenderer.SetWidth(Value: Integer);
  713. begin
  714. if FWidth <> Value then
  715. begin
  716. FWidth := Value;
  717. StructureChanged;
  718. end;
  719. end;
  720. procedure TgxFBORenderer.SetHeight(Value: Integer);
  721. begin
  722. if FHeight <> Value then
  723. begin
  724. FHeight := Value;
  725. StructureChanged;
  726. end;
  727. end;
  728. procedure TgxFBORenderer.SetLayer(const Value: Integer);
  729. begin
  730. if Value <> FFbo.Layer then
  731. begin
  732. if FRendering or (ocStructure in Changes) then
  733. FFbo.Layer := Value
  734. else
  735. begin
  736. FFbo.Bind;
  737. FFbo.Layer := Value;
  738. FFbo.Unbind;
  739. end;
  740. end;
  741. end;
  742. function TgxFBORenderer.GetLayer: Integer;
  743. begin
  744. Result := FFbo.Layer;
  745. end;
  746. procedure TgxFBORenderer.SetLevel(const Value: Integer);
  747. var
  748. w, h: Integer;
  749. begin
  750. if Value <> FFbo.Level then
  751. begin
  752. if FRendering or (ocStructure in Changes) then
  753. begin
  754. FFbo.Level := Value;
  755. w := Width;
  756. h := Height;
  757. if FFbo.Level > 0 then
  758. begin
  759. w := w shr FFbo.Level;
  760. h := h shr FFbo.Level;
  761. if w = 0 then
  762. w := 1;
  763. if h = 0 then
  764. h := 1;
  765. CurrentContext.gxStates.Viewport := Vector4iMake(0, 0, w, h);
  766. end;
  767. end
  768. else
  769. begin
  770. FFbo.Bind;
  771. FFbo.Level := Value;
  772. FFbo.Unbind;
  773. end;
  774. end;
  775. end;
  776. function TgxFBORenderer.GetLevel: Integer;
  777. begin
  778. Result := FFbo.Level;
  779. end;
  780. //-------------------------------------------------------------------
  781. initialization
  782. //-------------------------------------------------------------------
  783. RegisterClasses([TgxFBORenderer]);
  784. end.