GXS.ProjectedTextures.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.ProjectedTextures;
  5. (* Implements projected textures through a GLScene object *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. Winapi.OpenGL,
  10. System.Classes,
  11. GXS.XOpenGL,
  12. Stage.VectorTypes,
  13. GXS.Scene,
  14. GXS.PersistentClasses,
  15. GXS.Texture,
  16. Stage.VectorGeometry,
  17. GXS.RenderContextInfo,
  18. GXS.State,
  19. GXS.Context;
  20. type
  21. (* Possible styles of texture projection. Possible values:
  22. ptsOriginal: Original projection method (first pass,
  23. is default scene render, second pass is texture projection).
  24. ptsInverse: Inverse projection method (first pass
  25. is texture projection, sencond pass is regular scene render).
  26. This method is useful if you want to simulate
  27. lighting only through projected textures (the textures
  28. of the scene are "masked" into the white areas of
  29. the projection textures). *)
  30. TgxProjectedTexturesStyle = (ptsOriginal, ptsInverse);
  31. TgxProjectedTextures = class;
  32. (* A projected texture emmiter.
  33. It's material property will be used as the projected texture.
  34. Can be places anywhere in the scene. *)
  35. TgxTextureEmitter = class(TgxSceneObject)
  36. private
  37. FFOVy: single;
  38. FAspect: single;
  39. protected
  40. (* Sets up the base texture matrix for this emitter
  41. Should be called whenever a change on its properties is made.*)
  42. procedure SetupTexMatrix(var ARci: TgxRenderContextInfo);
  43. public
  44. constructor Create(AOwner: TComponent); override;
  45. published
  46. // Indicates the field-of-view of the projection frustum.
  47. property FOVy: single read FFOVy write FFOVy;
  48. (* x/y ratio. For no distortion, this should be set to
  49. texture.width/texture.height.*)
  50. property Aspect: single read FAspect write FAspect;
  51. end;
  52. // Specifies an item on the TgxTextureEmitters collection.
  53. TgxTextureEmitterItem = class(TCollectionItem)
  54. private
  55. FEmitter: TgxTextureEmitter;
  56. protected
  57. procedure SetEmitter(const val: TgxTextureEmitter);
  58. procedure RemoveNotification(aComponent: TComponent);
  59. function GetDisplayName: string; override;
  60. public
  61. constructor Create(ACollection: TCollection); override;
  62. procedure Assign(Source: TPersistent); override;
  63. published
  64. property Emitter: TgxTextureEmitter read FEmitter write SetEmitter;
  65. end;
  66. // Collection of TgxTextureEmitter.
  67. TgxTextureEmitters = class(TCollection)
  68. private
  69. FOwner: TgxProjectedTextures;
  70. protected
  71. function GetOwner: TPersistent; override;
  72. function GetItems(index: Integer): TgxTextureEmitterItem;
  73. procedure RemoveNotification(aComponent: TComponent);
  74. public
  75. procedure AddEmitter(texEmitter: TgxTextureEmitter);
  76. property Items[index: Integer]: TgxTextureEmitterItem read GetItems; default;
  77. end;
  78. (* Projected Textures Manager.
  79. Specifies active texture Emitters (whose texture will be projected)
  80. and receivers (children of this object). *)
  81. TgxProjectedTextures = class(TgxImmaterialSceneObject)
  82. private
  83. FEmitters: TgxTextureEmitters;
  84. FStyle: TgxProjectedTexturesStyle;
  85. public
  86. constructor Create(AOwner: TComponent); override;
  87. destructor Destroy; override;
  88. procedure DoRender(var ARci: TgxRenderContextInfo;
  89. ARenderSelf, ARenderChildren: Boolean); override;
  90. published
  91. // List of texture emitters.
  92. property Emitters: TgxTextureEmitters read FEmitters write FEmitters;
  93. // Indicates the style of the projected textures.
  94. property Style: TgxProjectedTexturesStyle read FStyle write FStyle;
  95. end;
  96. //==============================================================
  97. implementation
  98. //==============================================================
  99. // ------------------
  100. // ------------------ TgxTextureEmitter ------------------
  101. // ------------------
  102. constructor TgxTextureEmitter.Create(aOwner: TComponent);
  103. begin
  104. inherited Create(aOwner);
  105. FFOVy := 90;
  106. FAspect := 1;
  107. end;
  108. procedure TgxTextureEmitter.SetupTexMatrix(var ARci: TgxRenderContextInfo);
  109. const
  110. cBaseMat: TMatrix4f =
  111. (V:((X:0.5; Y:0; Z:0; W:0),
  112. (X:0; Y:0.5; Z:0; W:0),
  113. (X:0; Y:0; Z:1; W:0),
  114. (X:0.5; Y:0.5; Z:0; W:1)));
  115. var
  116. PM: TMatrix4f;
  117. begin
  118. // Set the projector's "perspective" (i.e. the "spotlight cone"):.
  119. PM := MatrixMultiply(CreatePerspectiveMatrix(FFOVy, FAspect, 0.1, 1), cBaseMat);
  120. PM := MatrixMultiply(invAbsoluteMatrix, PM);
  121. Arci.gxStates.SetTextureMatrix(PM);
  122. end;
  123. // ------------------
  124. // ------------------ TgxTextureEmitterItem ------------------
  125. // ------------------
  126. constructor TgxTextureEmitterItem.Create(ACollection: TCollection);
  127. begin
  128. inherited Create(ACollection);
  129. end;
  130. procedure TgxTextureEmitterItem.Assign(Source: TPersistent);
  131. begin
  132. if Source is TgxTextureEmitterItem then
  133. begin
  134. FEmitter := TgxTextureEmitterItem(Source).FEmitter;
  135. TgxProjectedTextures(TgxTextureEmitters(Collection).GetOwner).StructureChanged;
  136. end;
  137. inherited;
  138. end;
  139. procedure TgxTextureEmitterItem.SetEmitter(const val: TgxTextureEmitter);
  140. begin
  141. if FEmitter <> val then
  142. begin
  143. FEmitter := val;
  144. TgxProjectedTextures(TgxTextureEmitters(Collection).GetOwner).StructureChanged;
  145. end;
  146. end;
  147. procedure TgxTextureEmitterItem.RemoveNotification(aComponent: TComponent);
  148. begin
  149. if aComponent = FEmitter then
  150. FEmitter := nil;
  151. end;
  152. function TgxTextureEmitterItem.GetDisplayName: string;
  153. begin
  154. if Assigned(FEmitter) then
  155. begin
  156. Result := '[TexEmitter] ' + FEmitter.Name;
  157. end
  158. else
  159. Result := 'nil';
  160. end;
  161. // ------------------
  162. // ------------------ TgxTextureEmitters ------------------
  163. // ------------------
  164. function TgxTextureEmitters.GetOwner: TPersistent;
  165. begin
  166. Result := FOwner;
  167. end;
  168. function TgxTextureEmitters.GetItems(index: Integer): TgxTextureEmitterItem;
  169. begin
  170. Result := TgxTextureEmitterItem(inherited Items[index]);
  171. end;
  172. procedure TgxTextureEmitters.RemoveNotification(aComponent: TComponent);
  173. var
  174. i: Integer;
  175. begin
  176. for i := 0 to Count - 1 do
  177. Items[i].RemoveNotification(aComponent);
  178. end;
  179. procedure TgxTextureEmitters.AddEmitter(texEmitter: TgxTextureEmitter);
  180. var
  181. item: TgxTextureEmitterItem;
  182. begin
  183. item := TgxTextureEmitterItem(self.Add);
  184. item.Emitter := texEmitter;
  185. end;
  186. // ------------------
  187. // ------------------ TgxProjectedTextures ------------------
  188. // ------------------
  189. constructor TgxProjectedTextures.Create(AOwner: TComponent);
  190. begin
  191. inherited Create(aOWner);
  192. FEmitters := TgxTextureEmitters.Create(TgxTextureEmitterItem);
  193. FEmitters.FOwner := self;
  194. end;
  195. destructor TgxProjectedTextures.Destroy;
  196. begin
  197. FEmitters.Free;
  198. inherited destroy;
  199. end;
  200. procedure TgxProjectedTextures.DoRender(var ARci: TgxRenderContextInfo;
  201. ARenderSelf, ARenderChildren: boolean);
  202. const
  203. PS: array[0..3] of Single = (1, 0, 0, 0);
  204. PT: array[0..3] of Single = (0, 1, 0, 0);
  205. PR: array[0..3] of Single = (0, 0, 1, 0);
  206. PQ: array[0..3] of Single = (0, 0, 0, 1);
  207. var
  208. i: integer;
  209. emitter: TgxTextureEmitter;
  210. begin
  211. if not (ARenderSelf or ARenderChildren) then
  212. Exit;
  213. if (csDesigning in ComponentState) then
  214. begin
  215. inherited;
  216. Exit;
  217. end;
  218. //First pass of original style: render regular scene
  219. if Style = ptsOriginal then
  220. self.RenderChildren(0, Count - 1, ARci);
  221. //generate planes
  222. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  223. glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  224. glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  225. glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  226. glTexGenfv(GL_S, GL_EYE_PLANE, @PS);
  227. glTexGenfv(GL_T, GL_EYE_PLANE, @PT);
  228. glTexGenfv(GL_R, GL_EYE_PLANE, @PR);
  229. glTexGenfv(GL_Q, GL_EYE_PLANE, @PQ);
  230. //options
  231. Arci.gxStates.Disable(stLighting);
  232. Arci.gxStates.DepthFunc := cfLEqual;
  233. Arci.gxStates.Enable(stBlend);
  234. glEnable(GL_TEXTURE_GEN_S);
  235. glEnable(GL_TEXTURE_GEN_T);
  236. glEnable(GL_TEXTURE_GEN_R);
  237. glEnable(GL_TEXTURE_GEN_Q);
  238. //second pass (original) first pass (inverse): for each emiter,
  239. //render projecting the texture summing all emitters
  240. for i := 0 to Emitters.Count - 1 do
  241. begin
  242. emitter := Emitters[i].Emitter;
  243. if not assigned(emitter) then
  244. continue;
  245. if not emitter.Visible then
  246. continue;
  247. emitter.Material.Apply(ARci);
  248. ARci.gxStates.Enable(stBlend);
  249. if Style = ptsOriginal then
  250. begin
  251. //on the original style, render blending the textures
  252. if emitter.Material.Texture.TextureMode <> tmBlend then
  253. ARci.gxStates.SetBlendFunc(bfDstColor, bfOne)
  254. else
  255. ARci.gxStates.SetBlendFunc(bfDstColor, bfZero);
  256. end
  257. else
  258. begin
  259. //on inverse style: the first texture projector should
  260. //be a regular rendering (i.e. no blending). All others
  261. //are "added" together creating an "illumination mask"
  262. if i = 0 then
  263. Arci.gxStates.SetBlendFunc(bfOne, bfZero)
  264. else
  265. ARci.gxStates.SetBlendFunc(bfOne, bfOne);
  266. end;
  267. //get this emitter's tex matrix
  268. emitter.SetupTexMatrix(ARci);
  269. repeat
  270. ARci.ignoreMaterials := true;
  271. Self.RenderChildren(0, Count - 1, ARci);
  272. ARci.ignoreMaterials := false;
  273. until not emitter.Material.UnApply(ARci);
  274. end;
  275. // LoseTexMatrix
  276. ARci.gxStates.SetBlendFunc(bfOne, bfZero);
  277. glDisable(GL_TEXTURE_GEN_S);
  278. glDisable(GL_TEXTURE_GEN_T);
  279. glDisable(GL_TEXTURE_GEN_R);
  280. glDisable(GL_TEXTURE_GEN_Q);
  281. glMatrixMode(GL_TEXTURE);
  282. glLoadIdentity;
  283. glMatrixMode(GL_MODELVIEW);
  284. ARci.gxStates.DepthFunc := cfLEqual;
  285. //second pass (inverse): render regular scene, blending it
  286. //with the "mask"
  287. if Style = ptsInverse then
  288. begin
  289. Arci.gxStates.Enable(stBlend);
  290. ARci.gxStates.SetBlendFunc(bfDstColor, bfSrcColor);
  291. //second pass: render everything, blending with what is
  292. //already there
  293. ARci.ignoreBlendingRequests := true;
  294. self.RenderChildren(0, Count - 1, ARci);
  295. ARci.ignoreBlendingRequests := false;
  296. end;
  297. end;
  298. //------------------------------------------
  299. initialization
  300. //------------------------------------------
  301. RegisterClasses([TgxTextureEmitter, TgxProjectedTextures]);
  302. end.