GXS.ProxyObjects.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  1. //
  2. // The graphics engine GXScene https://github.com/glscene
  3. //
  4. unit GXS.ProxyObjects;
  5. (* Implements specific proxying classes *)
  6. interface
  7. {$I GLScene.Defines.inc}
  8. uses
  9. Winapi.OpenGL,
  10. System.Classes,
  11. System.SysUtils,
  12. GXS.XCollection,
  13. GXS.BaseClasses,
  14. GXS.PersistentClasses,
  15. GLScene.VectorGeometry,
  16. GLScene.VectorTypes,
  17. GLScene.Strings,
  18. GXS.Scene,
  19. GXS.Texture,
  20. GXS.VectorFileObjects,
  21. GXS.RenderContextInfo,
  22. GXS.Material,
  23. GXS.Context,
  24. GXS.PipelineTransformation;
  25. type
  26. EProxyException = class(Exception);
  27. (* A proxy object with its own color.
  28. This proxy object can have a unique color. Note that multi-material
  29. objects (Freeforms linked to a material library f.i.) won't honour
  30. the color. *)
  31. TgxColorProxy = class(TgxProxyObject)
  32. private
  33. FFrontColor: TgxFaceProperties;
  34. function GetMasterMaterialObject: TgxCustomSceneObject;
  35. procedure SetMasterMaterialObject(const Value: TgxCustomSceneObject);
  36. procedure SetFrontColor(AValue: TgxFaceProperties);
  37. public
  38. constructor Create(AOwner: TComponent); override;
  39. destructor Destroy; override;
  40. procedure DoRender(var ARci: TgxRenderContextInfo;
  41. ARenderSelf, ARenderChildren: Boolean); override;
  42. published
  43. property FrontColor: TgxFaceProperties read FFrontColor write
  44. SetFrontColor;
  45. // Redeclare as TgxCustomSceneObject.
  46. property MasterObject: TgxCustomSceneObject read GetMasterMaterialObject
  47. write SetMasterMaterialObject;
  48. end;
  49. { A proxy object with its own material.
  50. This proxy object can take a mesh from one master and a materia from
  51. a material library. }
  52. TgxMaterialProxy = class(TgxProxyObject, IgxMaterialLibrarySupported)
  53. private
  54. FTempLibMaterialName: string;
  55. FMasterLibMaterial: TgxLibMaterial;
  56. FMaterialLibrary: TgxMaterialLibrary;
  57. procedure SetMaterialLibrary(const Value: TgxMaterialLibrary);
  58. function GetMasterLibMaterialName: TgxLibMaterialName;
  59. procedure SetMasterLibMaterialName(const Value: TgxLibMaterialName);
  60. function GetMasterMaterialObject: TgxCustomSceneObject;
  61. procedure SetMasterMaterialObject(const Value: TgxCustomSceneObject);
  62. // Implementing IGLMaterialLibrarySupported.
  63. function GetMaterialLibrary: TgxAbstractMaterialLibrary;
  64. public
  65. constructor Create(AOwner: TComponent); override;
  66. procedure Notification(AComponent: TComponent; Operation: TOperation);
  67. override;
  68. destructor Destroy; override;
  69. procedure DoRender(var ARci: TgxRenderContextInfo;
  70. ARenderSelf, ARenderChildren: Boolean); override;
  71. { Specifies the Material, that current master object will use.
  72. Provides a faster way to access FMasterLibMaterial, compared to
  73. MasterLibMaterialName }
  74. property MasterLibMaterial: TgxLibMaterial read FMasterLibMaterial write
  75. FMasterLibMaterial stored False;
  76. published
  77. property MaterialLibrary: TgxMaterialLibrary read FMaterialLibrary write
  78. SetMaterialLibrary;
  79. // Specifies the Material, that current master object will use.
  80. property MasterLibMaterialName: TgxLibMaterialName read
  81. GetMasterLibMaterialName write SetMasterLibMaterialName;
  82. // Redeclare as TgxCustomSceneObject.
  83. property MasterObject: TgxCustomSceneObject read GetMasterMaterialObject
  84. write SetMasterMaterialObject;
  85. end;
  86. // A proxy object specialized for FreeForms.
  87. TgxFreeFormProxy = class(TgxProxyObject)
  88. private
  89. function GetMasterFreeFormObject: TgxFreeForm;
  90. procedure SetMasterFreeFormObject(const Value: TgxFreeForm);
  91. public
  92. (* If the MasterObject is a FreeForm, you can raycast against the Octree,
  93. which is alot faster. You must build the octree before using. *)
  94. function OctreeRayCastIntersect(const rayStart, rayVector: TVector4f;
  95. intersectPoint: PVector4f = nil;
  96. intersectNormal: PVector4f = nil): Boolean;
  97. // WARNING: This function is not yet 100% reliable with scale+rotation.
  98. function OctreeSphereSweepIntersect(const rayStart, rayVector: TVector4f;
  99. const velocity, radius, modelscale: Single;
  100. intersectPoint: PVector4f = nil;
  101. intersectNormal: PVector4f = nil): Boolean;
  102. published
  103. // Redeclare as TgxFreeForm.
  104. property MasterObject: TgxFreeForm read GetMasterFreeFormObject write
  105. SetMasterFreeFormObject;
  106. end;
  107. // An object containing the bone matrix for TgxActorProxy.
  108. TBoneMatrixObj = class
  109. public
  110. Matrix: TMatrix4f;
  111. BoneName: string;
  112. BoneIndex: integer;
  113. end;
  114. // pamLoop mode was too difficalt to implement, so it was discarded ...for now.
  115. // pamPlayOnce only works if Actor.AnimationMode <> aamNone.
  116. TgxActorProxyAnimationMode = (pamInherited, pamNone, pamPlayOnce);
  117. // A proxy object specialized for Actors.
  118. TgxActorProxy = class(TgxProxyObject, IgxMaterialLibrarySupported)
  119. private
  120. FCurrentFrame: Integer;
  121. FStartFrame: Integer;
  122. FEndFrame: Integer;
  123. FLastFrame: Integer;
  124. FCurrentFrameDelta: Single;
  125. FCurrentTime: TgxProgressTimes;
  126. FAnimation: TgxActorAnimationName;
  127. FTempLibMaterialName: string;
  128. FMasterLibMaterial: TgxLibMaterial;
  129. FMaterialLibrary: TgxMaterialLibrary;
  130. FBonesMatrices: TStringList;
  131. FStoreBonesMatrix: boolean;
  132. FStoredBoneNames: TStrings;
  133. FOnBeforeRender: TgxProgressEvent;
  134. FAnimationMode: TgxActorProxyAnimationMode;
  135. procedure SetAnimation(const Value: TgxActorAnimationName);
  136. procedure SetMasterActorObject(const Value: TgxActor);
  137. function GetMasterActorObject: TgxActor;
  138. function GetLibMaterialName: TgxLibMaterialName;
  139. procedure SetLibMaterialName(const Value: TgxLibMaterialName);
  140. procedure SetMaterialLibrary(const Value: TgxMaterialLibrary);
  141. // Implementing IGLMaterialLibrarySupported.
  142. function GetMaterialLibrary: TgxAbstractMaterialLibrary;
  143. procedure SetStoreBonesMatrix(const Value: boolean);
  144. procedure SetStoredBoneNames(const Value: TStrings);
  145. procedure SetOnBeforeRender(const Value: TgxProgressEvent);
  146. protected
  147. procedure DoStoreBonesMatrices;
  148. // stores matrices of bones of the current frame rendered
  149. public
  150. constructor Create(AOwner: TComponent); override;
  151. destructor Destroy; override;
  152. procedure Notification(AComponent: TComponent; Operation: TOperation);
  153. override;
  154. procedure DoRender(var ARci: TgxRenderContextInfo;
  155. ARenderSelf, ARenderChildren: Boolean); override;
  156. procedure DoProgress(const progressTime: TgxProgressTimes); override;
  157. property CurrentFrame: Integer read FCurrentFrame;
  158. property StartFrame: Integer read FStartFrame;
  159. property EndFrame: Integer read FEndFrame;
  160. property CurrentFrameDelta: Single read FCurrentFrameDelta;
  161. property CurrentTime: TgxProgressTimes read FCurrentTime;
  162. { Gets the Bones Matrix in the current animation frame.
  163. (since the masterobject is shared between all proxies, each proxy will have it's bones matrices) }
  164. function BoneMatrix(BoneIndex: integer): TMatrix4f; overload;
  165. function BoneMatrix(BoneName: string): TMatrix4f; overload;
  166. procedure BoneMatricesClear;
  167. { A standard version of the RayCastIntersect function. }
  168. function RayCastIntersect(const rayStart, rayVector: TVector4f;
  169. intersectPoint: PVector4f = nil;
  170. intersectNormal: PVector4f = nil): Boolean; override;
  171. (* Raycasts on self, but actually on the "RefActor" Actor.
  172. Note that the "RefActor" parameter does not necessarily have to be
  173. the same Actor refernced by the MasterObject property:
  174. This allows to pass a low-low-low-poly Actor to raycast in the "RefActor" parameter,
  175. while using a high-poly Actor in the "MasterObject" property,
  176. of course we assume that the two Masterobject Actors have same animations. *)
  177. function RayCastIntersectEx(RefActor: TgxActor; const rayStart, rayVector:
  178. TVector4f;
  179. intersectPoint: PVector4f = nil;
  180. intersectNormal: PVector4f = nil): Boolean; overload;
  181. published
  182. property AnimationMode: TgxActorProxyAnimationMode read FAnimationMode write
  183. FAnimationMode default pamInherited;
  184. property Animation: TgxActorAnimationName read FAnimation write SetAnimation;
  185. // Redeclare as TgxActor.
  186. property MasterObject: TgxActor read GetMasterActorObject write
  187. SetMasterActorObject;
  188. (* Redeclare without pooTransformation
  189. (Don't know why it causes the object to be oriented incorrecly.) *)
  190. property ProxyOptions default [pooEffects, pooObjects];
  191. // Specifies the MaterialLibrary, that current proxy will use.
  192. property MaterialLibrary: TgxMaterialLibrary read FMaterialLibrary write
  193. SetMaterialLibrary;
  194. // Specifies the Material, that current proxy will use.
  195. property LibMaterialName: TgxLibMaterialName read GetLibMaterialName write
  196. SetLibMaterialName;
  197. (* Specifies if it will store the Bones Matrices, accessible via the BoneMatrix function
  198. (since the masterobject is shared between all proxies, each proxy will have it's bones matrices) *)
  199. property StoreBonesMatrix: boolean read FStoreBonesMatrix write
  200. SetStoreBonesMatrix;
  201. (* Specifies the names of the bones we want the matrices to be stored. If empty, all bones will be stored
  202. (since the masterobject is shared between all proxies, each proxy will have it's bones matrices) *)
  203. property StoredBoneNames: TStrings read FStoredBoneNames write
  204. SetStoredBoneNames;
  205. (* Event allowing to apply extra transformations (f.ex: bone rotations) to the referenced
  206. Actor on order to have the proxy render these changes. *)
  207. property OnBeforeRender: TgxProgressEvent read FOnBeforeRender write
  208. SetOnBeforeRender;
  209. end;
  210. //-------------------------------------------------------------
  211. implementation
  212. //-------------------------------------------------------------
  213. // ------------------
  214. // ------------------ TgxColorProxy ------------------
  215. // ------------------
  216. constructor TgxColorProxy.Create(AOwner: TComponent);
  217. begin
  218. inherited Create(AOwner);
  219. FFrontColor := TgxFaceProperties.Create(Self);
  220. end;
  221. destructor TgxColorProxy.Destroy;
  222. begin
  223. FFrontColor.Free;
  224. inherited Destroy;
  225. end;
  226. procedure TgxColorProxy.DoRender(var ARci: TgxRenderContextInfo;
  227. ARenderSelf, ARenderChildren: Boolean);
  228. var
  229. gotMaster, masterGotEffects, oldProxySubObject: Boolean;
  230. begin
  231. if FRendering then
  232. Exit;
  233. FRendering := True;
  234. try
  235. gotMaster := Assigned(MasterObject);
  236. masterGotEffects := gotMaster and (pooEffects in ProxyOptions)
  237. and (MasterObject.Effects.Count > 0);
  238. if gotMaster then
  239. begin
  240. if pooObjects in ProxyOptions then
  241. begin
  242. oldProxySubObject := ARci.proxySubObject;
  243. ARci.proxySubObject := True;
  244. if pooTransformation in ProxyOptions then
  245. glMultMatrixf(PGLFloat(MasterObject.Matrix));
  246. GetMasterMaterialObject.Material.FrontProperties.Assign(FFrontColor);
  247. MasterObject.DoRender(ARci, ARenderSelf, MasterObject.Count > 0);
  248. ARci.proxySubObject := oldProxySubObject;
  249. end;
  250. end;
  251. // now render self stuff (our children, our effects, etc.)
  252. if ARenderChildren and (Count > 0) then
  253. Self.RenderChildren(0, Count - 1, ARci);
  254. if masterGotEffects then
  255. MasterObject.Effects.RenderPostEffects(ARci);
  256. finally
  257. FRendering := False;
  258. end;
  259. ClearStructureChanged;
  260. end;
  261. function TgxColorProxy.GetMasterMaterialObject: TgxCustomSceneObject;
  262. begin
  263. Result := TgxCustomSceneObject(inherited MasterObject);
  264. end;
  265. procedure TgxColorProxy.SetFrontColor(AValue: TgxFaceProperties);
  266. begin
  267. FFrontColor.Assign(AValue);
  268. end;
  269. procedure TgxColorProxy.SetMasterMaterialObject(
  270. const Value: TgxCustomSceneObject);
  271. begin
  272. inherited SetMasterObject(Value);
  273. end;
  274. // ------------------
  275. // ------------------ TgxFreeFormProxy ------------------
  276. // ------------------
  277. function TgxFreeFormProxy.OctreeRayCastIntersect(const rayStart, rayVector:
  278. TVector4f;
  279. intersectPoint: PVector4f = nil;
  280. intersectNormal: PVector4f = nil): Boolean;
  281. var
  282. localRayStart, localRayVector: TVector4f;
  283. begin
  284. if Assigned(MasterObject) then
  285. begin
  286. SetVector(localRayStart, AbsoluteToLocal(rayStart));
  287. SetVector(localRayStart, MasterObject.LocalToAbsolute(localRayStart));
  288. SetVector(localRayVector, AbsoluteToLocal(rayVector));
  289. SetVector(localRayVector, MasterObject.LocalToAbsolute(localRayVector));
  290. NormalizeVector(localRayVector);
  291. Result := GetMasterFreeFormObject.OctreeRayCastIntersect(localRayStart,
  292. localRayVector,
  293. intersectPoint, intersectNormal);
  294. if Result then
  295. begin
  296. if Assigned(intersectPoint) then
  297. begin
  298. SetVector(intersectPoint^,
  299. MasterObject.AbsoluteToLocal(intersectPoint^));
  300. SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
  301. end;
  302. if Assigned(intersectNormal) then
  303. begin
  304. SetVector(intersectNormal^,
  305. MasterObject.AbsoluteToLocal(intersectNormal^));
  306. SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
  307. end;
  308. end;
  309. end
  310. else
  311. Result := False;
  312. end;
  313. function TgxFreeFormProxy.OctreeSphereSweepIntersect(const rayStart, rayVector:
  314. TVector4f;
  315. const velocity, radius, modelscale: Single;
  316. intersectPoint: PVector4f = nil;
  317. intersectNormal: PVector4f = nil): Boolean;
  318. var
  319. localRayStart, localRayVector: TVector4f;
  320. localVelocity, localRadius: single;
  321. begin
  322. Result := False;
  323. if Assigned(MasterObject) then
  324. begin
  325. localVelocity := velocity * modelscale;
  326. localRadius := radius * modelscale;
  327. SetVector(localRayStart, AbsoluteToLocal(rayStart));
  328. SetVector(localRayStart, MasterObject.LocalToAbsolute(localRayStart));
  329. SetVector(localRayVector, AbsoluteToLocal(rayVector));
  330. SetVector(localRayVector, MasterObject.LocalToAbsolute(localRayVector));
  331. NormalizeVector(localRayVector);
  332. Result := GetMasterFreeFormObject.OctreeSphereSweepIntersect(localRayStart,
  333. localRayVector,
  334. localVelocity, localRadius,
  335. intersectPoint, intersectNormal);
  336. if Result then
  337. begin
  338. if Assigned(intersectPoint) then
  339. begin
  340. SetVector(intersectPoint^,
  341. MasterObject.AbsoluteToLocal(intersectPoint^));
  342. SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
  343. end;
  344. if Assigned(intersectNormal) then
  345. begin
  346. SetVector(intersectNormal^,
  347. MasterObject.AbsoluteToLocal(intersectNormal^));
  348. SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
  349. end;
  350. end;
  351. end;
  352. end;
  353. function TgxFreeFormProxy.GetMasterFreeFormObject: TgxFreeForm;
  354. begin
  355. Result := TgxFreeForm(inherited MasterObject);
  356. end;
  357. procedure TgxFreeFormProxy.SetMasterFreeFormObject(
  358. const Value: TgxFreeForm);
  359. begin
  360. inherited SetMasterObject(Value);
  361. end;
  362. // ------------------
  363. // ------------------ TgxActorProxy ------------------
  364. // ------------------
  365. function TgxActorProxy.BoneMatrix(BoneIndex: integer): TMatrix4f;
  366. begin
  367. if BoneIndex < FBonesMatrices.count then
  368. result := TBoneMatrixObj(FBonesMatrices.Objects[BoneIndex]).Matrix;
  369. end;
  370. function TgxActorProxy.BoneMatrix(BoneName: string): TMatrix4f;
  371. var
  372. i: Integer;
  373. begin
  374. i := FBonesMatrices.IndexOf(BoneName);
  375. if i > -1 then
  376. result := TBoneMatrixObj(FBonesMatrices.Objects[i]).Matrix;
  377. end;
  378. procedure TgxActorProxy.BoneMatricesClear;
  379. var
  380. i: Integer;
  381. begin
  382. for i := 0 to FBonesMatrices.Count - 1 do
  383. begin
  384. TBoneMatrixObj(FBonesMatrices.Objects[i]).free;
  385. end;
  386. FBonesMatrices.Clear;
  387. end;
  388. constructor TgxActorProxy.Create(AOwner: TComponent);
  389. begin
  390. inherited;
  391. FAnimationMode := pamInherited;
  392. ProxyOptions := ProxyOptions - [pooTransformation];
  393. FBonesMatrices := TStringList.create;
  394. FStoredBoneNames := TStringList.create;
  395. FStoreBonesMatrix := false;
  396. // default is false to speed up a little if we don't need bones info
  397. end;
  398. destructor TgxActorProxy.Destroy;
  399. begin
  400. BoneMatricesClear;
  401. FBonesMatrices.free;
  402. FStoredBoneNames.free;
  403. inherited;
  404. end;
  405. procedure TgxActorProxy.DoProgress(const progressTime: TgxProgressTimes);
  406. begin
  407. inherited;
  408. FCurrentTime := progressTime;
  409. end;
  410. procedure TgxActorProxy.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf,
  411. ARenderChildren: Boolean);
  412. var
  413. // TgxActorProxy specific
  414. cf, sf, ef: Integer;
  415. cfd: Single;
  416. // General proxy stuff.
  417. gotMaster, masterGotEffects, oldProxySubObject: Boolean;
  418. MasterActor: TgxActor;
  419. begin
  420. try
  421. MasterActor := GetMasterActorObject;
  422. gotMaster := MasterActor <> nil;
  423. masterGotEffects := gotMaster and (pooEffects in ProxyOptions) and
  424. (MasterObject.Effects.Count > 0);
  425. if gotMaster then
  426. begin
  427. if pooObjects in ProxyOptions then
  428. begin
  429. oldProxySubObject := ARci.proxySubObject;
  430. ARci.proxySubObject := True;
  431. if pooTransformation in ProxyOptions then
  432. with ARci.PipelineTransformation do
  433. SetModelMatrix(MatrixMultiply(MasterActor.Matrix^, ModelMatrix^));
  434. // At last TgxActorProxy specific stuff!
  435. with MasterActor do
  436. begin
  437. cfd := CurrentFrameDelta;
  438. cf := CurrentFrame;
  439. sf := startframe;
  440. ef := endframe;
  441. case FAnimationMode of
  442. pamInherited: CurrentFrameDelta := FCurrentFrameDelta;
  443. pamPlayOnce:
  444. begin
  445. if (FLastFrame <> FEndFrame - 1) then
  446. CurrentFrameDelta := FCurrentFrameDelta
  447. else
  448. begin
  449. FCurrentFrameDelta := 0;
  450. FAnimationMode := pamNone;
  451. end;
  452. end;
  453. pamNone: CurrentFrameDelta := 0;
  454. else
  455. Assert(False, strUnknownType);
  456. end;
  457. SetCurrentFrameDirect(FCurrentFrame);
  458. FLastFrame := FCurrentFrame;
  459. StartFrame := FStartFrame;
  460. EndFrame := FEndFrame;
  461. if (FMasterLibMaterial <> nil) and (FMaterialLibrary <> nil) then
  462. MasterActor.Material.QuickAssignMaterial(
  463. FMaterialLibrary, FMasterLibMaterial);
  464. DoProgress(FCurrentTime);
  465. if Assigned(FOnBeforeRender) then
  466. FOnBeforeRender(self, FCurrentTime.deltaTime, FCurrentTime.newTime);
  467. DoRender(ARci, ARenderSelf, Count > 0);
  468. // Stores Bones matrices of the current frame
  469. if (FStoreBonesMatrix) and (MasterActor.Skeleton <> nil) then
  470. DoStoreBonesMatrices;
  471. FCurrentFrameDelta := CurrentFrameDelta;
  472. FCurrentFrame := CurrentFrame;
  473. CurrentFrameDelta := cfd;
  474. SetCurrentFrameDirect(cf);
  475. startframe := sf;
  476. endframe := ef;
  477. end;
  478. ARci.proxySubObject := oldProxySubObject;
  479. end;
  480. end;
  481. // now render self stuff (our children, our effects, etc.)
  482. oldProxySubObject := ARci.proxySubObject;
  483. ARci.proxySubObject := True;
  484. if ARenderChildren and (Count > 0) then
  485. Self.RenderChildren(0, Count - 1, ARci);
  486. if masterGotEffects then
  487. MasterActor.Effects.RenderPostEffects(ARci);
  488. ARci.proxySubObject := oldProxySubObject;
  489. finally
  490. ClearStructureChanged;
  491. end;
  492. end;
  493. procedure TgxActorProxy.DoStoreBonesMatrices;
  494. var
  495. i, n: integer;
  496. Bmo: TBoneMatrixObj;
  497. Bone: TgxSkeletonBone;
  498. begin
  499. if FStoredBoneNames.count > 0 then
  500. begin
  501. // If we specified some bone names, only those bones matrices will be stored (save some cpu)
  502. if FBonesMatrices.Count < FStoredBoneNames.Count then
  503. begin
  504. n := FBonesMatrices.Count;
  505. for i := n to FStoredBoneNames.Count - 1 do
  506. begin
  507. Bone := MasterObject.Skeleton.BoneByName(FStoredBoneNames[i]);
  508. if Bone <> nil then
  509. begin
  510. Bmo := TBoneMatrixObj.Create;
  511. Bmo.BoneName := Bone.Name;
  512. Bmo.BoneIndex := Bone.BoneID;
  513. FBonesMatrices.AddObject(Bone.Name, Bmo);
  514. end;
  515. end;
  516. end;
  517. end
  518. else
  519. begin
  520. // Add (missing) TBoneMatrixObjects (actually ony 1st time) from all bones in skeleton
  521. if FBonesMatrices.Count < MasterObject.Skeleton.BoneCount - 1 then
  522. // note : BoneCount actually returns 1 count more.
  523. begin
  524. n := FBonesMatrices.Count;
  525. for i := n to MasterObject.Skeleton.BoneCount - 2 do
  526. // note : BoneCount actually returns 1 count more.
  527. begin
  528. Bone := MasterObject.Skeleton.BoneByID(i);
  529. if Bone <> nil then
  530. begin
  531. Bmo := TBoneMatrixObj.Create;
  532. Bmo.BoneName := Bone.Name;
  533. Bmo.BoneIndex := Bone.BoneID;
  534. FBonesMatrices.AddObject(Bone.Name, Bmo);
  535. end;
  536. end;
  537. end;
  538. end;
  539. // fill FBonesMatrices list
  540. for i := 0 to FBonesMatrices.count - 1 do
  541. begin
  542. Bmo := TBoneMatrixObj(FBonesMatrices.Objects[i]);
  543. Bmo.Matrix := MasterObject.Skeleton.BoneByID(Bmo.BoneIndex).GlobalMatrix;
  544. end;
  545. end;
  546. function TgxActorProxy.GetMasterActorObject: TgxActor;
  547. begin
  548. Result := TgxActor(inherited MasterObject);
  549. end;
  550. function TgxActorProxy.GetLibMaterialName: TgxLibMaterialName;
  551. begin
  552. Result := FMaterialLibrary.GetNameOfLibMaterial(FMasterLibMaterial);
  553. if Result = '' then
  554. Result := FTempLibMaterialName;
  555. end;
  556. function TgxActorProxy.GetMaterialLibrary: TgxAbstractMaterialLibrary;
  557. begin
  558. Result := FMaterialLibrary;
  559. end;
  560. procedure TgxActorProxy.Notification(AComponent: TComponent;
  561. Operation: TOperation);
  562. begin
  563. inherited;
  564. if Operation = opRemove then
  565. begin
  566. if AComponent = FMaterialLibrary then
  567. FMaterialLibrary := nil;
  568. end;
  569. end;
  570. function TgxActorProxy.RayCastIntersect(const rayStart, rayVector: TVector4f;
  571. intersectPoint, intersectNormal: PVector4f): Boolean;
  572. begin
  573. if MasterObject <> nil then
  574. Result := RayCastIntersectEx(GetMasterActorObject, rayStart, rayVector,
  575. intersectPoint, intersectNormal)
  576. else
  577. Result := inherited RayCastIntersect(rayStart, rayVector, intersectPoint,
  578. intersectNormal);
  579. end;
  580. // Gain access to TgxDummyActor.DoAnimate().
  581. type
  582. TgxDummyActor = class(TgxActor);
  583. function TgxActorProxy.RayCastIntersectEx(RefActor: TgxActor; const rayStart,
  584. rayVector: TVector4f; intersectPoint, intersectNormal: PVector4f): Boolean;
  585. var
  586. localRayStart, localRayVector: TVector4f;
  587. cf, sf, ef: Integer;
  588. cfd: Single;
  589. HaspooTransformation: boolean;
  590. begin
  591. // Set RefObject frame as current ActorProxy frame
  592. with RefActor do
  593. begin
  594. // VARS FOR ACTOR TO ASSUME ACTORPROXY CURRENT ANIMATION FRAME
  595. cfd := RefActor.CurrentFrameDelta;
  596. cf := RefActor.CurrentFrame;
  597. sf := RefActor.startframe;
  598. ef := RefActor.endframe;
  599. RefActor.CurrentFrameDelta := self.CurrentFrameDelta;
  600. RefActor.SetCurrentFrameDirect(self.CurrentFrame);
  601. RefActor.StartFrame := self.StartFrame;
  602. RefActor.EndFrame := self.EndFrame;
  603. RefActor.CurrentFrame := self.CurrentFrame;
  604. // FORCE ACTOR TO ASSUME ACTORPROXY CURRENT ANIMATION FRAME
  605. TgxDummyActor(RefActor).DoAnimate();
  606. HaspooTransformation := pooTransformation in self.ProxyOptions;
  607. // transform RAYSTART
  608. SetVector(localRayStart, self.AbsoluteToLocal(rayStart));
  609. if not HaspooTransformation then
  610. SetVector(localRayStart, RefActor.LocalToAbsolute(localRayStart));
  611. // transform RAYVECTOR
  612. SetVector(localRayVector, self.AbsoluteToLocal(rayVector));
  613. if not HaspooTransformation then
  614. SetVector(localRayVector, RefActor.LocalToAbsolute(localRayVector));
  615. NormalizeVector(localRayVector);
  616. Result := RefActor.RayCastIntersect(localRayStart, localRayVector,
  617. intersectPoint, intersectNormal);
  618. if Result then
  619. begin
  620. if Assigned(intersectPoint) then
  621. begin
  622. if not HaspooTransformation then
  623. SetVector(intersectPoint^, RefActor.AbsoluteToLocal(intersectPoint^));
  624. SetVector(intersectPoint^, self.LocalToAbsolute(intersectPoint^));
  625. end;
  626. if Assigned(intersectNormal) then
  627. begin
  628. if not HaspooTransformation then
  629. SetVector(intersectNormal^,
  630. RefActor.AbsoluteToLocal(intersectNormal^));
  631. SetVector(intersectNormal^, self.LocalToAbsolute(intersectNormal^));
  632. end;
  633. end;
  634. // Return RefObject to it's old time
  635. CurrentFrameDelta := cfd;
  636. SetCurrentFrameDirect(cf);
  637. CurrentFrame := cf;
  638. startframe := sf;
  639. endframe := ef;
  640. // REVERT ACTOR TO ASSUME ORIGINAL ANIMATION FRAME
  641. TgxDummyActor(RefActor).DoAnimate();
  642. end;
  643. end;
  644. procedure TgxActorProxy.SetAnimation(const Value: TgxActorAnimationName);
  645. var
  646. anAnimation: TgxActorAnimation;
  647. begin
  648. // We first assign the value (for persistency support), then check it.
  649. FAnimation := Value;
  650. if Assigned(MasterObject) then
  651. begin
  652. anAnimation := GetMasterActorObject.Animations.FindName(Value);
  653. if Assigned(anAnimation) then
  654. begin
  655. FStartFrame := anAnimation.StartFrame;
  656. FEndFrame := anAnimation.EndFrame;
  657. FCurrentFrame := FStartFrame;
  658. FLastFrame := FCurrentFrame;
  659. end;
  660. end;
  661. end;
  662. procedure TgxActorProxy.SetStoredBoneNames(const Value: TStrings);
  663. begin
  664. if value <> nil then
  665. FStoredBoneNames.Assign(Value);
  666. end;
  667. procedure TgxActorProxy.SetMasterActorObject(const Value: TgxActor);
  668. begin
  669. inherited SetMasterObject(Value);
  670. BoneMatricesClear;
  671. end;
  672. procedure TgxActorProxy.SetLibMaterialName(
  673. const Value: TgxLibMaterialName);
  674. begin
  675. if FMaterialLibrary = nil then
  676. begin
  677. FTempLibMaterialName := Value;
  678. if not (csLoading in ComponentState) then
  679. raise ETexture.Create(strErrorEx + strMatLibNotDefined);
  680. end
  681. else
  682. begin
  683. FMasterLibMaterial := FMaterialLibrary.LibMaterialByName(Value);
  684. FTempLibMaterialName := '';
  685. end;
  686. end;
  687. procedure TgxActorProxy.SetMaterialLibrary(const Value: TgxMaterialLibrary);
  688. begin
  689. if FMaterialLibrary <> Value then
  690. begin
  691. if FMaterialLibrary <> nil then
  692. FMaterialLibrary.RemoveFreeNotification(Self);
  693. FMaterialLibrary := Value;
  694. if FMaterialLibrary <> nil then
  695. begin
  696. FMaterialLibrary.FreeNotification(Self);
  697. if FTempLibMaterialName <> '' then
  698. SetLibMaterialName(FTempLibMaterialName);
  699. end
  700. else
  701. begin
  702. FTempLibMaterialName := '';
  703. end;
  704. end;
  705. end;
  706. procedure TgxActorProxy.SetOnBeforeRender(const Value: TgxProgressEvent);
  707. begin
  708. FOnBeforeRender := Value;
  709. end;
  710. procedure TgxActorProxy.SetStoreBonesMatrix(const Value: boolean);
  711. begin
  712. FStoreBonesMatrix := Value;
  713. end;
  714. { TgxMaterialProxy }
  715. constructor TgxMaterialProxy.Create(AOwner: TComponent);
  716. begin
  717. inherited;
  718. // Nothing here.
  719. end;
  720. destructor TgxMaterialProxy.Destroy;
  721. begin
  722. // Nothing here.
  723. inherited;
  724. end;
  725. procedure TgxMaterialProxy.DoRender(var ARci: TgxRenderContextInfo;
  726. ARenderSelf, ARenderChildren: Boolean);
  727. var
  728. gotMaster, masterGotEffects, oldProxySubObject: Boolean;
  729. begin
  730. if FRendering then
  731. Exit;
  732. FRendering := True;
  733. try
  734. gotMaster := Assigned(MasterObject);
  735. masterGotEffects := gotMaster and (pooEffects in ProxyOptions)
  736. and (MasterObject.Effects.Count > 0);
  737. if gotMaster then
  738. begin
  739. if pooObjects in ProxyOptions then
  740. begin
  741. oldProxySubObject := ARci.proxySubObject;
  742. ARci.proxySubObject := True;
  743. if pooTransformation in ProxyOptions then
  744. glMultMatrixf(PGLFloat(MasterObject.Matrix));
  745. if (FMasterLibMaterial <> nil) and (FMaterialLibrary <> nil) then
  746. GetMasterMaterialObject.Material.QuickAssignMaterial(
  747. FMaterialLibrary, FMasterLibMaterial);
  748. MasterObject.DoRender(ARci, ARenderSelf, MasterObject.Count > 0);
  749. ARci.proxySubObject := oldProxySubObject;
  750. end;
  751. end;
  752. // now render self stuff (our children, our effects, etc.)
  753. if ARenderChildren and (Count > 0) then
  754. Self.RenderChildren(0, Count - 1, ARci);
  755. if masterGotEffects then
  756. MasterObject.Effects.RenderPostEffects(ARci);
  757. finally
  758. FRendering := False;
  759. end;
  760. ClearStructureChanged;
  761. end;
  762. function TgxMaterialProxy.GetMasterLibMaterialName: TgxLibMaterialName;
  763. begin
  764. Result := FMaterialLibrary.GetNameOfLibMaterial(FMasterLibMaterial);
  765. if Result = '' then
  766. Result := FTempLibMaterialName;
  767. end;
  768. function TgxMaterialProxy.GetMasterMaterialObject: TgxCustomSceneObject;
  769. begin
  770. Result := TgxCustomSceneObject(inherited MasterObject);
  771. end;
  772. function TgxMaterialProxy.GetMaterialLibrary: TgxAbstractMaterialLibrary;
  773. begin
  774. Result := FMaterialLibrary;
  775. end;
  776. procedure TgxMaterialProxy.Notification(AComponent: TComponent;
  777. Operation: TOperation);
  778. begin
  779. inherited;
  780. if Operation = opRemove then
  781. begin
  782. if AComponent = FMaterialLibrary then
  783. FMaterialLibrary := nil;
  784. end;
  785. end;
  786. procedure TgxMaterialProxy.SetMasterLibMaterialName(
  787. const Value: TgxLibMaterialName);
  788. begin
  789. if FMaterialLibrary = nil then
  790. begin
  791. FTempLibMaterialName := Value;
  792. if not (csLoading in ComponentState) then
  793. raise ETexture.Create(strErrorEx + strMatLibNotDefined);
  794. end
  795. else
  796. begin
  797. FMasterLibMaterial := FMaterialLibrary.LibMaterialByName(Value);
  798. FTempLibMaterialName := '';
  799. end;
  800. end;
  801. procedure TgxMaterialProxy.SetMasterMaterialObject(
  802. const Value: TgxCustomSceneObject);
  803. begin
  804. inherited SetMasterObject(Value);
  805. end;
  806. procedure TgxMaterialProxy.SetMaterialLibrary(
  807. const Value: TgxMaterialLibrary);
  808. begin
  809. if FMaterialLibrary <> Value then
  810. begin
  811. if FMaterialLibrary <> nil then
  812. FMaterialLibrary.RemoveFreeNotification(Self);
  813. FMaterialLibrary := Value;
  814. if FMaterialLibrary <> nil then
  815. begin
  816. FMaterialLibrary.FreeNotification(Self);
  817. if FTempLibMaterialName <> '' then
  818. SetMasterLibMaterialName(FTempLibMaterialName);
  819. end
  820. else
  821. begin
  822. FTempLibMaterialName := '';
  823. end;
  824. end;
  825. end;
  826. //-------------------------------------------------------------
  827. initialization
  828. //-------------------------------------------------------------
  829. RegisterClasses([TgxColorProxy, TgxFreeFormProxy, TgxActorProxy,
  830. TgxMaterialProxy]);
  831. end.