GLS.ProjectedTextures.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit GLS.ProjectedTextures;
  5. (* Implements projected textures through an object. *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. Winapi.OpenGL,
  10. System.Classes,
  11. Stage.OpenGLTokens,
  12. GLS.Scene,
  13. GLS.PersistentClasses,
  14. Stage.VectorTypes,
  15. GLS.Texture,
  16. Stage.VectorGeometry,
  17. GLS.RenderContextInfo,
  18. GLS.State,
  19. GLS.Material;
  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 is texture projection,
  25. 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. TGLProjectedTexturesStyle = (ptsOriginal, ptsInverse);
  31. TGLProjectedTextures = 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. TGLTextureEmitter = class(TGLSceneObject)
  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: TGLRenderContextInfo);
  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 TGLTextureEmitters collection.
  53. TGLTextureEmitterItem = class(TCollectionItem)
  54. private
  55. FEmitter: TGLTextureEmitter;
  56. protected
  57. procedure SetEmitter(const val: TGLTextureEmitter);
  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: TGLTextureEmitter read FEmitter write SetEmitter;
  65. end;
  66. // Collection of TGLTextureEmitter.
  67. TGLTextureEmitters = class(TCollection)
  68. private
  69. FOwner: TGLProjectedTextures;
  70. protected
  71. function GetOwner: TPersistent; override;
  72. function GetItems(index: Integer): TGLTextureEmitterItem;
  73. procedure RemoveNotification(aComponent: TComponent);
  74. public
  75. procedure AddEmitter(texEmitter: TGLTextureEmitter);
  76. property Items[index: Integer]: TGLTextureEmitterItem 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. TGLProjectedTextures = class(TGLImmaterialSceneObject)
  82. private
  83. FEmitters: TGLTextureEmitters;
  84. FStyle: TGLProjectedTexturesStyle;
  85. public
  86. constructor Create(AOwner: TComponent); override;
  87. destructor Destroy; override;
  88. procedure DoRender(var ARci: TGLRenderContextInfo;
  89. ARenderSelf, ARenderChildren: Boolean); override;
  90. published
  91. // List of texture emitters.
  92. property Emitters: TGLTextureEmitters read FEmitters write FEmitters;
  93. // Indicates the style of the projected textures.
  94. property Style: TGLProjectedTexturesStyle read FStyle write FStyle;
  95. end;
  96. //-------------------------------------------------------------
  97. implementation
  98. //-------------------------------------------------------------
  99. uses
  100. GLS.Context;
  101. // ------------------
  102. // ------------------ TGLTextureEmitter ------------------
  103. // ------------------
  104. constructor TGLTextureEmitter.Create(aOwner: TComponent);
  105. begin
  106. inherited Create(aOwner);
  107. FFOVy := 90;
  108. FAspect := 1;
  109. end;
  110. procedure TGLTextureEmitter.SetupTexMatrix(var ARci: TGLRenderContextInfo);
  111. const
  112. cBaseMat: TGLMatrix =
  113. (V:((X:0.5; Y:0; Z:0; W:0),
  114. (X:0; Y:0.5; Z:0; W:0),
  115. (X:0; Y:0; Z:1; W:0),
  116. (X:0.5; Y:0.5; Z:0; W:1)));
  117. var
  118. PM: TGLMatrix;
  119. begin
  120. // Set the projector's "perspective" (i.e. the "spotlight cone"):.
  121. PM := MatrixMultiply(CreatePerspectiveMatrix(FFOVy, FAspect, 0.1, 1), cBaseMat);
  122. PM := MatrixMultiply(invAbsoluteMatrix, PM);
  123. Arci.GLStates.SetTextureMatrix(PM);
  124. end;
  125. // ------------------
  126. // ------------------ TGLTextureEmitterItem ------------------
  127. // ------------------
  128. constructor TGLTextureEmitterItem.Create(ACollection: TCollection);
  129. begin
  130. inherited Create(ACollection);
  131. end;
  132. procedure TGLTextureEmitterItem.Assign(Source: TPersistent);
  133. begin
  134. if Source is TGLTextureEmitterItem then
  135. begin
  136. FEmitter := TGLTextureEmitterItem(Source).FEmitter;
  137. TGLProjectedTextures(TGLTextureEmitters(Collection).GetOwner).StructureChanged;
  138. end;
  139. inherited;
  140. end;
  141. procedure TGLTextureEmitterItem.SetEmitter(const val: TGLTextureEmitter);
  142. begin
  143. if FEmitter <> val then
  144. begin
  145. FEmitter := val;
  146. TGLProjectedTextures(TGLTextureEmitters(Collection).GetOwner).StructureChanged;
  147. end;
  148. end;
  149. procedure TGLTextureEmitterItem.RemoveNotification(aComponent: TComponent);
  150. begin
  151. if aComponent = FEmitter then
  152. FEmitter := nil;
  153. end;
  154. function TGLTextureEmitterItem.GetDisplayName: string;
  155. begin
  156. if Assigned(FEmitter) then
  157. begin
  158. Result := '[TexEmitter] ' + FEmitter.Name;
  159. end
  160. else
  161. Result := 'nil';
  162. end;
  163. // ------------------
  164. // ------------------ TGLTextureEmitters ------------------
  165. // ------------------
  166. function TGLTextureEmitters.GetOwner: TPersistent;
  167. begin
  168. Result := FOwner;
  169. end;
  170. function TGLTextureEmitters.GetItems(index: Integer): TGLTextureEmitterItem;
  171. begin
  172. Result := TGLTextureEmitterItem(inherited Items[index]);
  173. end;
  174. procedure TGLTextureEmitters.RemoveNotification(aComponent: TComponent);
  175. var
  176. i: Integer;
  177. begin
  178. for i := 0 to Count - 1 do
  179. Items[i].RemoveNotification(aComponent);
  180. end;
  181. procedure TGLTextureEmitters.AddEmitter(texEmitter: TGLTextureEmitter);
  182. var
  183. item: TGLTextureEmitterItem;
  184. begin
  185. item := TGLTextureEmitterItem(self.Add);
  186. item.Emitter := texEmitter;
  187. end;
  188. // ------------------
  189. // ------------------ TGLProjectedTextures ------------------
  190. // ------------------
  191. constructor TGLProjectedTextures.Create(AOwner: TComponent);
  192. begin
  193. inherited Create(aOWner);
  194. FEmitters := TGLTextureEmitters.Create(TGLTextureEmitterItem);
  195. FEmitters.FOwner := self;
  196. end;
  197. destructor TGLProjectedTextures.Destroy;
  198. begin
  199. FEmitters.Free;
  200. inherited destroy;
  201. end;
  202. procedure TGLProjectedTextures.DoRender(var ARci: TGLRenderContextInfo;
  203. ARenderSelf, ARenderChildren: boolean);
  204. const
  205. PS: array[0..3] of Single = (1, 0, 0, 0);
  206. PT: array[0..3] of Single = (0, 1, 0, 0);
  207. PR: array[0..3] of Single = (0, 0, 1, 0);
  208. PQ: array[0..3] of Single = (0, 0, 0, 1);
  209. var
  210. i: integer;
  211. emitter: TGLTextureEmitter;
  212. begin
  213. if not (ARenderSelf or ARenderChildren) then
  214. Exit;
  215. if (csDesigning in ComponentState) then
  216. begin
  217. inherited;
  218. Exit;
  219. end;
  220. //First pass of original style: render regular scene
  221. if Style = ptsOriginal then
  222. self.RenderChildren(0, Count - 1, ARci);
  223. //generate planes
  224. gl.TexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  225. gl.TexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  226. gl.TexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  227. gl.TexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  228. gl.TexGenfv(GL_S, GL_EYE_PLANE, @PS);
  229. gl.TexGenfv(GL_T, GL_EYE_PLANE, @PT);
  230. gl.TexGenfv(GL_R, GL_EYE_PLANE, @PR);
  231. gl.TexGenfv(GL_Q, GL_EYE_PLANE, @PQ);
  232. //options
  233. Arci.GLStates.Disable(stLighting);
  234. Arci.GLStates.DepthFunc := cfLEqual;
  235. Arci.GLStates.Enable(stBlend);
  236. gl.Enable(GL_TEXTURE_GEN_S);
  237. gl.Enable(GL_TEXTURE_GEN_T);
  238. gl.Enable(GL_TEXTURE_GEN_R);
  239. gl.Enable(GL_TEXTURE_GEN_Q);
  240. //second pass (original) first pass (inverse): for each emiter,
  241. //render projecting the texture summing all emitters
  242. for i := 0 to Emitters.Count - 1 do
  243. begin
  244. emitter := Emitters[i].Emitter;
  245. if not assigned(emitter) then
  246. continue;
  247. if not emitter.Visible then
  248. continue;
  249. emitter.Material.Apply(ARci);
  250. ARci.GLStates.Enable(stBlend);
  251. if Style = ptsOriginal then
  252. begin
  253. //on the original style, render blending the textures
  254. if emitter.Material.Texture.TextureMode <> tmBlend then
  255. ARci.GLStates.SetBlendFunc(bfDstColor, bfOne)
  256. else
  257. ARci.GLStates.SetBlendFunc(bfDstColor, bfZero);
  258. end
  259. else
  260. begin
  261. //on inverse style: the first texture projector should
  262. //be a regular rendering (i.e. no blending). All others
  263. //are "added" together creating an "illumination mask"
  264. if i = 0 then
  265. Arci.GLStates.SetBlendFunc(bfOne, bfZero)
  266. else
  267. ARci.GLStates.SetBlendFunc(bfOne, bfOne);
  268. end;
  269. //get this emitter's tex matrix
  270. emitter.SetupTexMatrix(ARci);
  271. repeat
  272. ARci.ignoreMaterials := true;
  273. Self.RenderChildren(0, Count - 1, ARci);
  274. ARci.ignoreMaterials := false;
  275. until not emitter.Material.UnApply(ARci);
  276. end;
  277. // LoseTexMatrix
  278. ARci.GLStates.SetBlendFunc(bfOne, bfZero);
  279. gl.Disable(GL_TEXTURE_GEN_S);
  280. gl.Disable(GL_TEXTURE_GEN_T);
  281. gl.Disable(GL_TEXTURE_GEN_R);
  282. gl.Disable(GL_TEXTURE_GEN_Q);
  283. gl.MatrixMode(GL_TEXTURE);
  284. gl.LoadIdentity;
  285. gl.MatrixMode(GL_MODELVIEW);
  286. ARci.GLStates.DepthFunc := cfLEqual;
  287. //second pass (inverse): render regular scene, blending it
  288. //with the "mask"
  289. if Style = ptsInverse then
  290. begin
  291. Arci.GLStates.Enable(stBlend);
  292. ARci.GLStates.SetBlendFunc(bfDstColor, bfSrcColor);
  293. //second pass: render everything, blending with what is
  294. //already there
  295. ARci.ignoreBlendingRequests := true;
  296. self.RenderChildren(0, Count - 1, ARci);
  297. ARci.ignoreBlendingRequests := false;
  298. end;
  299. end;
  300. //----------------------------------
  301. initialization
  302. //----------------------------------
  303. RegisterClasses([TGLTextureEmitter, TGLProjectedTextures]);
  304. end.