GXS.Mirror.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.Mirror;
  5. (*
  6. Implements a basic, stencil-based mirror (as in Mark Kilgard's demo).
  7. It is strongly recommended to read and understand the explanations in the
  8. materials/mirror demo before using this component.
  9. *)
  10. interface
  11. {$I Stage.Defines.inc}
  12. uses
  13. Winapi.OpenGL,
  14. System.Classes,
  15. GXS.XCollection,
  16. GXS.PersistentClasses,
  17. GXS.Scene,
  18. Stage.PipelineTransform,
  19. Stage.VectorGeometry,
  20. GXS.Context,
  21. GXS.Material,
  22. GXS.Color,
  23. GXS.RenderContextInfo,
  24. GXS.State,
  25. Stage.VectorTypes;
  26. type
  27. TMirrorOption = (moUseStencil, moOpaque, moMirrorPlaneClip, moClearZBuffer);
  28. TMirrorOptions = set of TMirrorOption;
  29. const
  30. cDefaultMirrorOptions = [moUseStencil];
  31. type
  32. TMirrorShapes = (msRect, msDisk);
  33. { A simple plane mirror.
  34. This mirror requires a stencil buffer for optimal rendering!
  35. The object is a mix between a plane and a proxy object, in that the plane
  36. defines the mirror's surface, while the proxy part is used to reference
  37. the objects that should be mirrored (it is legal to self-mirror, but no
  38. self-mirror visuals will be rendered).
  39. It is strongly recommended to read and understand the explanations in the
  40. materials/mirror demo before using this component. }
  41. TgxMirror = class(TgxSceneObject)
  42. private
  43. FRendering: Boolean;
  44. FMirrorObject: TgxBaseSceneObject;
  45. FWidth, FHeight: Single;
  46. FMirrorOptions: TMirrorOptions;
  47. FOnBeginRenderingMirrors, FOnEndRenderingMirrors: TNotifyEvent;
  48. FShape: TMirrorShapes; //ORL
  49. FRadius: Single; //ORL
  50. FSlices: Integer; //ORL
  51. protected
  52. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  53. procedure SetMirrorObject(const val: TgxBaseSceneObject);
  54. procedure SetMirrorOptions(const val: TMirrorOptions);
  55. procedure ClearZBufferArea(aBuffer: TgxSceneBuffer);
  56. procedure SetHeight(AValue: Single);
  57. procedure SetWidth(AValue: Single);
  58. procedure SetRadius(const aValue: Single); //ORL
  59. procedure SetSlices(const aValue: Integer); //ORL
  60. procedure SetShape(aValue: TMirrorShapes); //ORL
  61. function GetRadius: Single; //ORL
  62. function GetSlices: Integer; //ORL
  63. public
  64. constructor Create(AOwner: TComponent); override;
  65. procedure DoRender(var ARci: TgxRenderContextInfo;
  66. ARenderSelf, ARenderChildren: Boolean); override;
  67. procedure BuildList(var ARci: TgxRenderContextInfo); override;
  68. procedure Assign(Source: TPersistent); override;
  69. function AxisAlignedDimensionsUnscaled: TVector4f; override;
  70. published
  71. { Selects the object to mirror. If nil, the whole scene is mirrored. }
  72. property MirrorObject: TgxBaseSceneObject read FMirrorObject write
  73. SetMirrorObject;
  74. { Controls rendering options.
  75. moUseStencil: mirror area is stenciled, prevents reflected
  76. objects to be visible on the sides of the mirror (stencil buffer
  77. must be active in the viewer)
  78. moOpaque: mirror is opaque (ie. painted with background color)
  79. moMirrorPlaneClip: a ClipPlane is defined to prevent reflections
  80. from popping out of the mirror (for objects behind or halfway through)
  81. moClearZBuffer: mirror area's ZBuffer is cleared so that background
  82. objects don't interfere with reflected objects (reflected objects
  83. must be rendered AFTER the mirror in the hierarchy). Works only
  84. along with stenciling. }
  85. property MirrorOptions: TMirrorOptions read FMirrorOptions write
  86. SetMirrorOptions default cDefaultMirrorOptions;
  87. property Height: Single read FHeight write SetHeight;
  88. property Width: Single read FWidth write SetWidth;
  89. { Fired before the object's mirror images are rendered. }
  90. property OnBeginRenderingMirrors: TNotifyEvent read FOnBeginRenderingMirrors
  91. write FOnBeginRenderingMirrors;
  92. { Fired after the object's mirror images are rendered. }
  93. property OnEndRenderingMirrors: TNotifyEvent read FOnEndRenderingMirrors
  94. write FOnEndRenderingMirrors;
  95. property Radius: Single read FRadius write SetRadius; //ORL
  96. property Slices: GLint read FSlices write SetSlices default 16; //ORL
  97. property Shape: TMirrorShapes read FShape write SetShape default msRect;
  98. //ORL
  99. end;
  100. //-------------------------------------------------------------
  101. implementation
  102. //-------------------------------------------------------------
  103. // ------------------
  104. // ------------------ TgxMirror ------------------
  105. // ------------------
  106. constructor TgxMirror.Create(AOwner: Tcomponent);
  107. begin
  108. inherited Create(AOwner);
  109. FWidth := 1;
  110. FHeight := 1;
  111. FMirrorOptions := cDefaultMirrorOptions;
  112. ObjectStyle := ObjectStyle + [osDirectDraw];
  113. Material.FrontProperties.Diffuse.Initialize(VectorMake(1, 1, 1, 0.1));
  114. Material.BlendingMode := bmTransparency;
  115. FRadius := 1; //ORL
  116. FSlices := 16; //ORL
  117. Shape := msRect; //ORL
  118. end;
  119. procedure TgxMirror.DoRender(var ARci: TgxRenderContextInfo;
  120. ARenderSelf, ARenderChildren: Boolean);
  121. var
  122. oldProxySubObject: Boolean;
  123. refMat, curMat, ModelMat: TMatrix4f;
  124. clipPlane: TDoubleHmgPlane;
  125. bgColor: TgxColorVector;
  126. cameraPosBackup, cameraDirectionBackup: TVector4f;
  127. CurrentBuffer: TgxSceneBuffer;
  128. begin
  129. if FRendering then
  130. Exit;
  131. FRendering := True;
  132. try
  133. oldProxySubObject := ARci.proxySubObject;
  134. ARci.proxySubObject := True;
  135. CurrentBuffer := TgxSceneBuffer(ARci.buffer);
  136. if VectorDotProduct(VectorSubtract(ARci.cameraPosition, AbsolutePosition),
  137. AbsoluteDirection) > 0 then
  138. with ARci.gxStates do
  139. begin
  140. // "Render" stencil mask
  141. if MirrorOptions <> [] then
  142. begin
  143. if (moUseStencil in MirrorOptions) then
  144. begin
  145. Enable(stStencilTest);
  146. ARci.gxStates.StencilClearValue := 0;
  147. glClear(GL_STENCIL_BUFFER_BIT);
  148. SetStencilFunc(cfAlways, 1, 1);
  149. SetStencilOp(soReplace, soZero, soReplace);
  150. end;
  151. if (moOpaque in MirrorOptions) then
  152. begin
  153. bgColor := ConvertWinColor(CurrentBuffer.BackgroundColor);
  154. ARci.gxStates.SetMaterialColors(cmFront, bgColor, clrBlack,
  155. clrBlack, clrBlack, 0);
  156. end
  157. else
  158. SetColorWriting(False);
  159. Enable(stDepthTest);
  160. DepthWriteMask := False;
  161. BuildList(ARci);
  162. DepthWriteMask := True;
  163. if (moUseStencil in MirrorOptions) then
  164. begin
  165. SetStencilFunc(cfEqual, 1, 1);
  166. SetStencilOp(soKeep, soKeep, soKeep);
  167. end;
  168. if (moClearZBuffer in MirrorOptions) then
  169. ClearZBufferArea(CurrentBuffer);
  170. if not (moOpaque in MirrorOptions) then
  171. SetColorWriting(True);
  172. end;
  173. ARci.PipelineTransformation.Push;
  174. ARci.PipelineTransformation.SetModelMatrix(IdentityHmgMatrix);
  175. Disable(stCullFace);
  176. Enable(stNormalize);
  177. if moMirrorPlaneClip in MirrorOptions then
  178. begin
  179. glEnable(GL_CLIP_PLANE0);
  180. SetPlane(clipPlane, PlaneMake(AffineVectorMake(AbsolutePosition),
  181. VectorNegate(AffineVectorMake(AbsoluteDirection))));
  182. glClipPlane(GL_CLIP_PLANE0, @clipPlane);
  183. end;
  184. // Mirror lights
  185. refMat := MakeReflectionMatrix(
  186. AffineVectorMake(AbsolutePosition),
  187. AffineVectorMake(AbsoluteDirection));
  188. curMat := MatrixMultiply(refMat, ARci.PipelineTransformation.ViewMatrix^);
  189. ARci.PipelineTransformation.SetViewMatrix(curMat);
  190. Scene.SetupLights(CurrentBuffer.LimitOf[limLights]);
  191. // mirror geometry and render master
  192. cameraPosBackup := ARci.cameraPosition;
  193. cameraDirectionBackup := ARci.cameraDirection;
  194. ARci.cameraPosition := VectorTransform(ARci.cameraPosition, refMat);
  195. ARci.cameraDirection := VectorTransform(ARci.cameraDirection, refMat);
  196. // temporary fix? (some objects don't respect culling options, or ?)
  197. CullFaceMode := cmFront;
  198. if Assigned(FOnBeginRenderingMirrors) then
  199. FOnBeginRenderingMirrors(Self);
  200. if Assigned(FMirrorObject) then
  201. begin
  202. ModelMat := IdentityHmgMatrix;
  203. if FMirrorObject.Parent <> nil then
  204. MatrixMultiply(ModelMat, FMirrorObject.Parent.AbsoluteMatrix, ModelMat);
  205. MatrixMultiply(ModelMat, FMirrorObject.LocalMatrix^, ModelMat);
  206. ARci.PipelineTransformation.SetModelMatrix(ModelMat);
  207. FMirrorObject.DoRender(ARci, ARenderSelf, FMirrorObject.Count > 0);
  208. end
  209. else
  210. begin
  211. Scene.Objects.DoRender(ARci, ARenderSelf, True);
  212. end;
  213. if Assigned(FOnEndRenderingMirrors) then
  214. FOnEndRenderingMirrors(Self);
  215. // Restore to "normal"
  216. ARci.cameraPosition := cameraPosBackup;
  217. ARci.cameraDirection := cameraDirectionBackup;
  218. ARci.gxStates.CullFaceMode := cmBack;
  219. ARci.PipelineTransformation.ReplaceFromStack;
  220. Scene.SetupLights(CurrentBuffer.LimitOf[limLights]);
  221. ARci.PipelineTransformation.Pop;
  222. if moMirrorPlaneClip in MirrorOptions then
  223. glDisable(GL_CLIP_PLANE0);
  224. ARci.gxStates.Disable(stStencilTest);
  225. ARci.proxySubObject := oldProxySubObject;
  226. // start rendering self
  227. if ARenderSelf then
  228. begin
  229. Material.Apply(ARci);
  230. repeat
  231. BuildList(ARci);
  232. until not Material.UnApply(ARci);
  233. end;
  234. end;
  235. if ARenderChildren then
  236. Self.RenderChildren(0, Count - 1, ARci);
  237. if Assigned(FMirrorObject) then
  238. FMirrorObject.Effects.RenderPostEffects(ARci);
  239. finally
  240. FRendering := False;
  241. end;
  242. end;
  243. procedure TgxMirror.BuildList(var ARci: TgxRenderContextInfo);
  244. var
  245. hw, hh: Single;
  246. quadric: GLUquadricObj;
  247. begin
  248. if msRect = FShape then
  249. begin
  250. hw := FWidth * 0.5;
  251. hh := FHeight * 0.5;
  252. glNormal3fv(@ZVector);
  253. glBegin(GL_QUADS);
  254. glVertex3f(hw, hh, 0);
  255. glVertex3f(-hw, hh, 0);
  256. glVertex3f(-hw, -hh, 0);
  257. glVertex3f(hw, -hh, 0);
  258. glEnd;
  259. end
  260. else
  261. begin
  262. quadric := gluNewQuadric;
  263. gluDisk(Quadric, 0, FRadius, FSlices, 1); //radius. slices, loops
  264. end;
  265. end;
  266. procedure TgxMirror.ClearZBufferArea(aBuffer: TgxSceneBuffer);
  267. var
  268. worldMat: TMatrix4f;
  269. p: TAffineVector;
  270. begin
  271. with aBuffer do
  272. begin
  273. glPushMatrix;
  274. worldMat := Self.AbsoluteMatrix;
  275. glMatrixMode(GL_PROJECTION);
  276. glPushMatrix;
  277. glLoadIdentity;
  278. glOrtho(0, Width, 0, Height, 1, -1);
  279. glMatrixMode(GL_MODELVIEW);
  280. glLoadIdentity;
  281. with aBuffer.RenderingContext.gxStates do
  282. begin
  283. DepthFunc := cfAlways;
  284. SetColorWriting(False);
  285. end;
  286. glBegin(GL_QUADS);
  287. p := WorldToScreen(VectorTransform(AffineVectorMake(Self.Width * 0.5,
  288. Self.Height * 0.5, 0), worldMat));
  289. glVertex3f(p.X, p.Y, 0.999);
  290. p := WorldToScreen(VectorTransform(AffineVectorMake(-Self.Width * 0.5,
  291. Self.Height * 0.5, 0), worldMat));
  292. glVertex3f(p.X, p.Y, 0.999);
  293. p := WorldToScreen(VectorTransform(AffineVectorMake(-Self.Width * 0.5,
  294. -Self.Height * 0.5, 0), worldMat));
  295. glVertex3f(p.X, p.Y, 0.999);
  296. p := WorldToScreen(VectorTransform(AffineVectorMake(Self.Width * 0.5,
  297. -Self.Height * 0.5, 0), worldMat));
  298. glVertex3f(p.X, p.Y, 0.999);
  299. glEnd;
  300. with aBuffer.RenderingContext.gxStates do
  301. begin
  302. DepthFunc := cfLess;
  303. SetColorWriting(True);
  304. end;
  305. glMatrixMode(GL_PROJECTION);
  306. glPopMatrix;
  307. glMatrixMode(GL_MODELVIEW);
  308. glPopMatrix;
  309. end;
  310. end;
  311. procedure TgxMirror.Notification(AComponent: TComponent; Operation: TOperation);
  312. begin
  313. if (Operation = opRemove) and (AComponent = FMirrorObject) then
  314. MirrorObject := nil;
  315. inherited;
  316. end;
  317. procedure TgxMirror.SetMirrorObject(const val: TgxBaseSceneObject);
  318. begin
  319. if FMirrorObject <> val then
  320. begin
  321. if Assigned(FMirrorObject) then
  322. FMirrorObject.RemoveFreeNotification(Self);
  323. FMirrorObject := val;
  324. if Assigned(FMirrorObject) then
  325. FMirrorObject.FreeNotification(Self);
  326. NotifyChange(Self);
  327. end;
  328. end;
  329. procedure TgxMirror.SetWidth(AValue: Single);
  330. begin
  331. if AValue <> FWidth then
  332. begin
  333. FWidth := AValue;
  334. NotifyChange(Self);
  335. end;
  336. end;
  337. procedure TgxMirror.SetHeight(AValue: Single);
  338. begin
  339. if AValue <> FHeight then
  340. begin
  341. FHeight := AValue;
  342. NotifyChange(Self);
  343. end;
  344. end;
  345. procedure TgxMirror.Assign(Source: TPersistent);
  346. begin
  347. if Assigned(Source) and (Source is TgxMirror) then
  348. begin
  349. FWidth := TgxMirror(Source).FWidth;
  350. FHeight := TgxMirror(Source).FHeight;
  351. FMirrorOptions := TgxMirror(Source).FMirrorOptions;
  352. MirrorObject := TgxMirror(Source).MirrorObject;
  353. end;
  354. inherited Assign(Source);
  355. end;
  356. function TgxMirror.AxisAlignedDimensionsUnscaled: TVector4f;
  357. begin
  358. Result := VectorMake(0.5 * Abs(FWidth),
  359. 0.5 * Abs(FHeight), 0);
  360. end;
  361. procedure TgxMirror.SetMirrorOptions(const val: TMirrorOptions);
  362. begin
  363. if FMirrorOptions <> val then
  364. begin
  365. FMirrorOptions := val;
  366. NotifyChange(Self);
  367. end;
  368. end;
  369. //ORL add-ons
  370. procedure TgxMirror.SetRadius(const aValue: Single);
  371. begin
  372. if aValue <> FRadius then
  373. begin
  374. FRadius := aValue;
  375. StructureChanged;
  376. end;
  377. end;
  378. function TgxMirror.GetRadius: single;
  379. begin
  380. result := FRadius;
  381. end;
  382. procedure TgxMirror.SetSlices(const aValue: GLint);
  383. begin
  384. if aValue <> FSlices then
  385. begin
  386. if aValue > 2 then
  387. FSlices := aValue;
  388. StructureChanged;
  389. end
  390. else
  391. begin
  392. end;
  393. end;
  394. function TgxMirror.GetSlices: GLint;
  395. begin
  396. result := FSlices;
  397. end;
  398. procedure TgxMirror.SetShape(aValue: TMirrorShapes);
  399. begin
  400. if aValue <> FShape then
  401. begin
  402. FShape := aValue;
  403. StructureChanged;
  404. end;
  405. end;
  406. //-------------------------------------------------------------
  407. initialization
  408. //-------------------------------------------------------------
  409. RegisterClasses([TgxMirror]);
  410. end.