2
0

GXS.MultiProxy.pas 12 KB

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