GLS.MultiProxy.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit GLS.MultiProxy;
  5. (* Implements a multi-proxy objects, useful for discreet LOD. *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. System.Classes,
  10. System.SysUtils,
  11. Stage.OpenGLTokens,
  12. GLS.PersistentClasses,
  13. Stage.VectorGeometry,
  14. GLS.Context,
  15. GLS.Scene,
  16. GLS.Silhouette,
  17. GLS.RenderContextInfo,
  18. GLS.BaseClasses,
  19. Stage.VectorTypes;
  20. type
  21. TGLMultiProxy = class;
  22. // MasterObject description for a MultiProxy object
  23. TGLMultiProxyMaster = class (TCollectionItem)
  24. private
  25. FMasterObject : TGLBaseSceneObject;
  26. FDistanceMin, FDistanceMin2 : Single;
  27. FDistanceMax, FDistanceMax2 : Single;
  28. FVisible : Boolean;
  29. protected
  30. function GetDisplayName : String; override;
  31. procedure SetMasterObject(const val : TGLBaseSceneObject);
  32. procedure SetDistanceMin(const val : Single);
  33. procedure SetDistanceMax(const val : Single);
  34. procedure SetVisible(const val : Boolean);
  35. public
  36. constructor Create(Collection : TCollection); override;
  37. destructor Destroy; override;
  38. procedure Assign(Source: TPersistent); override;
  39. function OwnerObject : TGLMultiProxy;
  40. procedure NotifyChange;
  41. published
  42. // Specifies the Master object which will be proxy'ed.
  43. property MasterObject : TGLBaseSceneObject read FMasterObject write SetMasterObject;
  44. // Minimum visibility distance (inclusive).
  45. property DistanceMin : Single read FDistanceMin write SetDistanceMin;
  46. // Maximum visibility distance (exclusive).
  47. property DistanceMax : Single read FDistanceMax write SetDistanceMax;
  48. (*
  49. Determines if the master object can be visible (proxy'ed).
  50. Note: the master object's distance also has to be within DistanceMin and DistanceMax.
  51. *)
  52. property Visible : Boolean read FVisible write SetVisible default True;
  53. end;
  54. // Collection of TGLMultiProxyMaster.
  55. TGLMultiProxyMasters = class (TOwnedCollection)
  56. protected
  57. procedure SetItems(index : Integer; const val : TGLMultiProxyMaster);
  58. function GetItems(index : Integer) : TGLMultiProxyMaster;
  59. procedure Update(Item: TCollectionItem); override;
  60. public
  61. constructor Create(AOwner : TPersistent);
  62. function Add : TGLMultiProxyMaster; overload;
  63. function Add(master : TGLBaseSceneObject; distanceMin, distanceMax : Single) : TGLMultiProxyMaster; overload;
  64. property Items[index : Integer] : TGLMultiProxyMaster read GetItems write SetItems; default;
  65. procedure Notification(AComponent: TComponent);
  66. procedure NotifyChange;
  67. procedure EndUpdate; override;
  68. end;
  69. (* Multiple Proxy object.
  70. This proxy has multiple master objects, which are individually made visible
  71. depending on a distance to the camera criterion. It can be used to implement
  72. discreet level of detail directly for static objects, or objects that
  73. go through cyclic animation.
  74. For dimensionsn raycasting and silhouette purposes, the first master is used
  75. (item zero in the MasterObjects collection). *)
  76. TGLMultiProxy = class (TGLSceneObject)
  77. private
  78. FMasterObjects : TGLMultiProxyMasters;
  79. FRendering : Boolean; // internal use (loop protection)
  80. protected
  81. procedure SetMasterObjects(const val : TGLMultiProxyMasters);
  82. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  83. function PrimaryMaster : TGLBaseSceneObject;
  84. public
  85. constructor Create(AOwner: TComponent); override;
  86. destructor Destroy; override;
  87. procedure Assign(Source: TPersistent); override;
  88. procedure DoRender(var rci : TGLRenderContextInfo;
  89. renderSelf, renderChildren : Boolean); override;
  90. function AxisAlignedDimensionsUnscaled : TGLVector; override;
  91. function RayCastIntersect(const rayStart, rayVector : TGLVector;
  92. intersectPoint : PGLVector = nil;
  93. intersectNormal : PGLVector = nil) : Boolean; override;
  94. function GenerateSilhouette(const silhouetteParameters : TGLSilhouetteParameters) : TGLSilhouette; override;
  95. published
  96. property MasterObjects : TGLMultiProxyMasters read FMasterObjects write SetMasterObjects;
  97. property ObjectsSorting;
  98. property Direction;
  99. property PitchAngle;
  100. property Position;
  101. property RollAngle;
  102. property Scale;
  103. property ShowAxes;
  104. property TurnAngle;
  105. property Up;
  106. property Visible;
  107. property OnProgress;
  108. property Behaviours;
  109. end;
  110. //-------------------------------------------------------------
  111. implementation
  112. //-------------------------------------------------------------
  113. // ------------------
  114. // ------------------ TGLMultiProxyMaster ------------------
  115. // ------------------
  116. constructor TGLMultiProxyMaster.Create(Collection : TCollection);
  117. begin
  118. inherited Create(Collection);
  119. FVisible:=True;
  120. end;
  121. destructor TGLMultiProxyMaster.Destroy;
  122. begin
  123. MasterObject:=nil;
  124. inherited Destroy;
  125. end;
  126. procedure TGLMultiProxyMaster.Assign(Source: TPersistent);
  127. begin
  128. if Source is TGLMultiProxyMaster then begin
  129. MasterObject:=TGLMultiProxyMaster(Source).MasterObject;
  130. FDistanceMin:=TGLMultiProxyMaster(Source).FDistanceMin;
  131. FDistanceMin2:=TGLMultiProxyMaster(Source).FDistanceMin2;
  132. FDistanceMax:=TGLMultiProxyMaster(Source).FDistanceMax;
  133. FDistanceMax2:=TGLMultiProxyMaster(Source).FDistanceMax2;
  134. FVisible:=TGLMultiProxyMaster(Source).FVisible;
  135. NotifyChange;
  136. end else inherited;
  137. end;
  138. function TGLMultiProxyMaster.OwnerObject : TGLMultiProxy;
  139. begin
  140. Result:=TGLMultiProxy(TGLMultiProxyMasters(Collection).GetOwner);
  141. end;
  142. procedure TGLMultiProxyMaster.NotifyChange;
  143. begin
  144. TGLMultiProxyMasters(Collection).NotifyChange;
  145. end;
  146. function TGLMultiProxyMaster.GetDisplayName : String;
  147. begin
  148. if MasterObject<>nil then
  149. Result:=MasterObject.Name
  150. else Result:='???';
  151. Result:=Result+Format(' [%.2f; %.2f[', [DistanceMin, DistanceMax]);
  152. if not Visible then
  153. Result:=Result+' (hidden)';
  154. end;
  155. procedure TGLMultiProxyMaster.SetMasterObject(const val : TGLBaseSceneObject);
  156. begin
  157. if FMasterObject<>val then begin
  158. if Assigned(FMasterObject) then
  159. FMasterObject.RemoveFreeNotification(OwnerObject);
  160. FMasterObject:=val;
  161. if Assigned(FMasterObject) then
  162. FMasterObject.FreeNotification(OwnerObject);
  163. NotifyChange;
  164. end;
  165. end;
  166. procedure TGLMultiProxyMaster.SetDistanceMin(const val : Single);
  167. begin
  168. if FDistanceMin<>val then begin
  169. FDistanceMin:=val;
  170. FDistanceMin2:=Sqr(val);
  171. NotifyChange;
  172. end;
  173. end;
  174. procedure TGLMultiProxyMaster.SetDistanceMax(const val : Single);
  175. begin
  176. if FDistanceMax<>val then begin
  177. FDistanceMax:=val;
  178. FDistanceMax2:=Sqr(val);
  179. NotifyChange;
  180. end;
  181. end;
  182. procedure TGLMultiProxyMaster.SetVisible(const val : Boolean);
  183. begin
  184. if FVisible<>val then begin
  185. FVisible:=val;
  186. NotifyChange;
  187. end;
  188. end;
  189. // ------------------
  190. // ------------------ TGLMultiProxyMasters ------------------
  191. // ------------------
  192. constructor TGLMultiProxyMasters.Create(AOwner : TPersistent);
  193. begin
  194. inherited Create(AOwner, TGLMultiProxyMaster)
  195. end;
  196. procedure TGLMultiProxyMasters.SetItems(index : Integer; const val : TGLMultiProxyMaster);
  197. begin
  198. inherited Items[index]:=val;
  199. end;
  200. function TGLMultiProxyMasters.GetItems(index : Integer) : TGLMultiProxyMaster;
  201. begin
  202. Result:=TGLMultiProxyMaster(inherited Items[index]);
  203. end;
  204. procedure TGLMultiProxyMasters.Update(Item : TCollectionItem);
  205. begin
  206. inherited;
  207. NotifyChange;
  208. end;
  209. function TGLMultiProxyMasters.Add : TGLMultiProxyMaster;
  210. begin
  211. Result:=(inherited Add) as TGLMultiProxyMaster;
  212. end;
  213. function TGLMultiProxyMasters.Add(master : TGLBaseSceneObject; distanceMin, distanceMax : Single) : TGLMultiProxyMaster;
  214. begin
  215. BeginUpdate;
  216. Result:=(inherited Add) as TGLMultiProxyMaster;
  217. Result.MasterObject:=master;
  218. Result.DistanceMin:=distanceMin;
  219. Result.DistanceMax:=distanceMax;
  220. EndUpdate;
  221. end;
  222. procedure TGLMultiProxyMasters.Notification(AComponent: TComponent);
  223. var
  224. i : Integer;
  225. begin
  226. for i:=0 to Count-1 do with Items[i] do
  227. if FMasterObject=AComponent then FMasterObject:=nil;
  228. end;
  229. procedure TGLMultiProxyMasters.NotifyChange;
  230. begin
  231. if (UpdateCount=0) and (GetOwner<>nil) and (GetOwner is TGLUpdateAbleComponent) then
  232. TGLUpdateAbleComponent(GetOwner).NotifyChange(Self);
  233. end;
  234. procedure TGLMultiProxyMasters.EndUpdate;
  235. begin
  236. inherited EndUpdate;
  237. // Workaround for a bug in VCL's EndUpdate
  238. if UpdateCount=0 then NotifyChange;
  239. end;
  240. // ------------------
  241. // ------------------ TGLMultiProxy ------------------
  242. // ------------------
  243. constructor TGLMultiProxy.Create(AOwner: TComponent);
  244. begin
  245. inherited Create(AOwner);
  246. ObjectStyle:=ObjectStyle+[osDirectDraw];
  247. FMasterObjects:=TGLMultiProxyMasters.Create(Self);
  248. end;
  249. destructor TGLMultiProxy.Destroy;
  250. begin
  251. inherited Destroy;
  252. FMasterObjects.Free;
  253. end;
  254. procedure TGLMultiProxy.Notification(AComponent: TComponent; Operation: TOperation);
  255. begin
  256. if Operation=opRemove then
  257. FMasterObjects.Notification(AComponent);
  258. inherited;
  259. end;
  260. procedure TGLMultiProxy.SetMasterObjects(const val : TGLMultiProxyMasters);
  261. begin
  262. FMasterObjects.Assign(val);
  263. StructureChanged;
  264. end;
  265. procedure TGLMultiProxy.Assign(Source: TPersistent);
  266. begin
  267. if Source is TGLMultiProxy then begin
  268. MasterObjects:=TGLMultiProxy(Source).MasterObjects;
  269. end;
  270. inherited;
  271. end;
  272. procedure TGLMultiProxy.DoRender(var rci : TGLRenderContextInfo;
  273. renderSelf, renderChildren : Boolean);
  274. var
  275. i : Integer;
  276. oldProxySubObject : Boolean;
  277. mpMaster : TGLMultiProxyMaster;
  278. master : TGLBaseSceneObject;
  279. d2 : Single;
  280. begin
  281. if FRendering then Exit;
  282. FRendering:=True;
  283. try
  284. d2:=VectorDistance2(rci.cameraPosition, AbsolutePosition);
  285. for i:=0 to MasterObjects.Count-1 do begin
  286. mpMaster:=MasterObjects[i];
  287. if mpMaster.Visible then begin
  288. master:=mpMaster.MasterObject;
  289. if (master<>nil) and (d2>=mpMaster.FDistanceMin2) and (d2<mpMaster.FDistanceMax2) then begin
  290. oldProxySubObject:=rci.proxySubObject;
  291. rci.proxySubObject:=True;
  292. gl.MultMatrixf(PGLFloat(master.Matrix));
  293. master.DoRender(rci, renderSelf, (master.Count>0));
  294. rci.proxySubObject:=oldProxySubObject;
  295. end;
  296. end;
  297. end;
  298. // now render self stuff (our children, our effects, etc.)
  299. if renderChildren and (Count>0) then
  300. Self.RenderChildren(0, Count-1, rci);
  301. // if masterGotEffects then
  302. // FMasterObject.Effects.RenderPostEffects(Scene.CurrentBuffer, rci);
  303. finally
  304. FRendering:=False;
  305. end;
  306. ClearStructureChanged;
  307. end;
  308. function TGLMultiProxy.PrimaryMaster : TGLBaseSceneObject;
  309. begin
  310. if MasterObjects.Count>0 then
  311. Result:=MasterObjects[0].MasterObject
  312. else Result:=nil;
  313. end;
  314. function TGLMultiProxy.AxisAlignedDimensionsUnscaled : TGLVector;
  315. var
  316. master : TGLBaseSceneObject;
  317. begin
  318. master:=PrimaryMaster;
  319. if Assigned(master) then begin
  320. Result:=master.AxisAlignedDimensionsUnscaled;
  321. end else Result:=inherited AxisAlignedDimensionsUnscaled;
  322. end;
  323. function TGLMultiProxy.RayCastIntersect(const rayStart, rayVector : TGLVector;
  324. intersectPoint : PGLVector = nil;
  325. intersectNormal : PGLVector = nil) : Boolean;
  326. var
  327. localRayStart, localRayVector : TGLVector;
  328. master : TGLBaseSceneObject;
  329. begin
  330. master:=PrimaryMaster;
  331. if Assigned(master) then begin
  332. SetVector(localRayStart, AbsoluteToLocal(rayStart));
  333. SetVector(localRayStart, master.LocalToAbsolute(localRayStart));
  334. SetVector(localRayVector, AbsoluteToLocal(rayVector));
  335. SetVector(localRayVector, master.LocalToAbsolute(localRayVector));
  336. NormalizeVector(localRayVector);
  337. Result:=master.RayCastIntersect(localRayStart, localRayVector,
  338. intersectPoint, intersectNormal);
  339. if Result then begin
  340. if Assigned(intersectPoint) then begin
  341. SetVector(intersectPoint^, master.AbsoluteToLocal(intersectPoint^));
  342. SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
  343. end;
  344. if Assigned(intersectNormal) then begin
  345. SetVector(intersectNormal^, master.AbsoluteToLocal(intersectNormal^));
  346. SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
  347. end;
  348. end;
  349. end else Result:=False;
  350. end;
  351. function TGLMultiProxy.GenerateSilhouette(const silhouetteParameters : TGLSilhouetteParameters) : TGLSilhouette;
  352. var
  353. master : TGLBaseSceneObject;
  354. begin
  355. master:=PrimaryMaster;
  356. if Assigned(master) then
  357. Result:=master.GenerateSilhouette(silhouetteParameters)
  358. else Result:=nil;
  359. end;
  360. //-------------------------------------------------------------
  361. initialization
  362. //-------------------------------------------------------------
  363. RegisterClasses([TGLMultiProxy]);
  364. end.