2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Implements projected textures through a GLScene object.
8
10/11/12 - PW - Added CPP compatibility: changed const cBase matrix
9
23/08/10 - Yar - Added OpenGLTokens to uses, replaced OpenGL1x functions to OpenGLAdapter
10
22/04/10 - Yar - Fixes after GLState revision
11
05/03/10 - DanB - More state added to TGLStateCache
12
30/03/07 - DaStr - Added $I GLScene.inc
13
28/03/07 - DaStr - Renamed parameters in some methods
14
(thanks Burkhard Carstens) (Bugtracker ID = 1678658)
15
15/06/05 - Mathx - Added the Style property and inverse rendering
16
07/05/05 - Mathx - Support for tmBlend textures (by Ruben Javier)
17
01/10/04 - SG - Initial (by Matheus Degiovani)
20
unit GLProjectedTextures;
37
{ Possible styles of texture projection. Possible values:
38
ptsOriginal: Original projection method (first pass,
39
is default scene render, second pass is texture
41
ptsInverse: Inverse projection method (first pass
42
is texture projection, sencond pass is regular scene
43
render). This method is useful if you want to simulate
44
lighting only through projected textures (the textures
45
of the scene are "masked" into the white areas of
46
the projection textures).
48
TGLProjectedTexturesStyle = (ptsOriginal, ptsInverse);
50
TGLProjectedTextures = class;
54
{ A projected texture emmiter.
55
It's material property will be used as the projected texture.
56
Can be places anywhere in the scene. }
57
TGLTextureEmitter = class(TGLSceneObject)
65
{ Sets up the base texture matrix for this emitter
66
Should be called whenever a change on its properties is made.}
67
procedure SetupTexMatrix(var ARci: TGLRenderContextInfo);
71
constructor Create(AOwner: TComponent); override;
75
{ Indicates the field-of-view of the projection frustum.}
76
property FOVy: single read FFOVy write FFOVy;
78
{ x/y ratio. For no distortion, this should be set to
79
texture.width/texture.height.}
80
property Aspect: single read FAspect write FAspect;
83
// TGLTextureEmitterItem
85
{ Specifies an item on the TGLTextureEmitters collection. }
86
TGLTextureEmitterItem = class(TCollectionItem)
89
FEmitter: TGLTextureEmitter;
93
procedure SetEmitter(const val: TGLTextureEmitter);
94
procedure RemoveNotification(aComponent: TComponent);
95
function GetDisplayName: string; override;
99
constructor Create(ACollection: TCollection); override;
100
procedure Assign(Source: TPersistent); override;
104
property Emitter: TGLTextureEmitter read FEmitter write SetEmitter;
108
// TGLTextureEmitters
110
{ Collection of TGLTextureEmitter. }
111
TGLTextureEmitters = class(TCollection)
114
FOwner: TGLProjectedTextures;
118
function GetOwner: TPersistent; override;
119
function GetItems(index: Integer): TGLTextureEmitterItem;
120
procedure RemoveNotification(aComponent: TComponent);
124
procedure AddEmitter(texEmitter: TGLTextureEmitter);
126
property Items[index: Integer]: TGLTextureEmitterItem read GetItems; default;
130
// TGLProjectedTexture
132
{ Projected Textures Manager.
133
Specifies active texture Emitters (whose texture will be projected)
134
and receivers (children of this object). }
135
TGLProjectedTextures = class(TGLImmaterialSceneObject)
138
FEmitters: TGLTextureEmitters;
139
FStyle: TGLProjectedTexturesStyle;
143
constructor Create(AOwner: TComponent); override;
144
destructor Destroy; override;
145
procedure DoRender(var ARci: TGLRenderContextInfo;
146
ARenderSelf, ARenderChildren: Boolean); override;
151
{ List of texture emitters. }
152
property Emitters: TGLTextureEmitters read FEmitters write FEmitters;
154
{ Indicates the style of the projected textures. }
155
property Style: TGLProjectedTexturesStyle read FStyle write FStyle;
158
//-------------------------------------------------------------
159
//-------------------------------------------------------------
160
//-------------------------------------------------------------
162
//-------------------------------------------------------------
163
//-------------------------------------------------------------
164
//-------------------------------------------------------------
168
// ------------------ TGLTextureEmitter ------------------
174
constructor TGLTextureEmitter.Create(aOwner: TComponent);
176
inherited Create(aOwner);
184
procedure TGLTextureEmitter.SetupTexMatrix(var ARci: TGLRenderContextInfo);
187
(V:((X:0.5; Y:0; Z:0; W:0),
188
(X:0; Y:0.5; Z:0; W:0),
189
(X:0; Y:0; Z:1; W:0),
190
(X:0.5; Y:0.5; Z:0; W:1)));
195
// Set the projector's "perspective" (i.e. the "spotlight cone"):.
196
PM := MatrixMultiply(CreatePerspectiveMatrix(FFOVy, FAspect, 0.1, 1), cBaseMat);
197
PM := MatrixMultiply(invAbsoluteMatrix, PM);
198
Arci.GLStates.SetGLTextureMatrix(PM);
202
// ------------------ TGLTextureEmitterItem ------------------
208
constructor TGLTextureEmitterItem.Create(ACollection: TCollection);
210
inherited Create(ACollection);
216
procedure TGLTextureEmitterItem.Assign(Source: TPersistent);
218
if Source is TGLTextureEmitterItem then
220
FEmitter := TGLTextureEmitterItem(Source).FEmitter;
221
TGLProjectedTextures(TGLTextureEmitters(Collection).GetOwner).StructureChanged;
229
procedure TGLTextureEmitterItem.SetEmitter(const val: TGLTextureEmitter);
231
if FEmitter <> val then
234
TGLProjectedTextures(TGLTextureEmitters(Collection).GetOwner).StructureChanged;
241
procedure TGLTextureEmitterItem.RemoveNotification(aComponent: TComponent);
243
if aComponent = FEmitter then
250
function TGLTextureEmitterItem.GetDisplayName: string;
252
if Assigned(FEmitter) then
254
Result := '[TexEmitter] ' + FEmitter.Name;
261
// ------------------ TGLTextureEmitters ------------------
267
function TGLTextureEmitters.GetOwner: TPersistent;
275
function TGLTextureEmitters.GetItems(index: Integer): TGLTextureEmitterItem;
277
Result := TGLTextureEmitterItem(inherited Items[index]);
283
procedure TGLTextureEmitters.RemoveNotification(aComponent: TComponent);
287
for i := 0 to Count - 1 do
288
Items[i].RemoveNotification(aComponent);
294
procedure TGLTextureEmitters.AddEmitter(texEmitter: TGLTextureEmitter);
296
item: TGLTextureEmitterItem;
298
item := TGLTextureEmitterItem(self.Add);
299
item.Emitter := texEmitter;
303
// ------------------ TGLProjectedTextures ------------------
309
constructor TGLProjectedTextures.Create(AOwner: TComponent);
311
inherited Create(aOWner);
312
FEmitters := TGLTextureEmitters.Create(TGLTextureEmitterItem);
313
FEmitters.FOwner := self;
319
destructor TGLProjectedTextures.Destroy;
328
procedure TGLProjectedTextures.DoRender(var ARci: TGLRenderContextInfo;
329
ARenderSelf, ARenderChildren: boolean);
331
PS: array[0..3] of GLfloat = (1, 0, 0, 0);
332
PT: array[0..3] of GLfloat = (0, 1, 0, 0);
333
PR: array[0..3] of GLfloat = (0, 0, 1, 0);
334
PQ: array[0..3] of GLfloat = (0, 0, 0, 1);
337
emitter: TGLTextureEmitter;
339
if not (ARenderSelf or ARenderChildren) then
341
if (csDesigning in ComponentState) then
347
//First pass of original style: render regular scene
348
if Style = ptsOriginal then
349
self.RenderChildren(0, Count - 1, ARci);
352
GL.TexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
353
GL.TexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
354
GL.TexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
355
GL.TexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
357
GL.TexGenfv(GL_S, GL_EYE_PLANE, @PS);
358
GL.TexGenfv(GL_T, GL_EYE_PLANE, @PT);
359
GL.TexGenfv(GL_R, GL_EYE_PLANE, @PR);
360
GL.TexGenfv(GL_Q, GL_EYE_PLANE, @PQ);
363
Arci.GLStates.Disable(stLighting);
364
Arci.GLStates.DepthFunc := cfLEqual;
365
Arci.GLStates.Enable(stBlend);
366
GL.Enable(GL_TEXTURE_GEN_S);
367
GL.Enable(GL_TEXTURE_GEN_T);
368
GL.Enable(GL_TEXTURE_GEN_R);
369
GL.Enable(GL_TEXTURE_GEN_Q);
371
//second pass (original) first pass (inverse): for each emiter,
372
//render projecting the texture summing all emitters
373
for i := 0 to Emitters.Count - 1 do
375
emitter := Emitters[i].Emitter;
376
if not assigned(emitter) then
378
if not emitter.Visible then
381
emitter.Material.Apply(ARci);
383
ARci.GLStates.Enable(stBlend);
384
if Style = ptsOriginal then
386
//on the original style, render blending the textures
387
if emitter.Material.Texture.TextureMode <> tmBlend then
388
ARci.GLStates.SetBlendFunc(bfDstColor, bfOne)
390
ARci.GLStates.SetBlendFunc(bfDstColor, bfZero);
394
//on inverse style: the first texture projector should
395
//be a regular rendering (i.e. no blending). All others
396
//are "added" together creating an "illumination mask"
398
Arci.GLStates.SetBlendFunc(bfOne, bfZero)
400
ARci.GLStates.SetBlendFunc(bfOne, bfOne);
403
//get this emitter's tex matrix
404
emitter.SetupTexMatrix(ARci);
406
ARci.ignoreMaterials := true;
407
Self.RenderChildren(0, Count - 1, ARci);
408
ARci.ignoreMaterials := false;
409
until not emitter.Material.UnApply(ARci);
413
ARci.GLStates.SetBlendFunc(bfOne, bfZero);
414
GL.Disable(GL_TEXTURE_GEN_S);
415
GL.Disable(GL_TEXTURE_GEN_T);
416
GL.Disable(GL_TEXTURE_GEN_R);
417
GL.Disable(GL_TEXTURE_GEN_Q);
419
GL.MatrixMode(GL_TEXTURE);
421
GL.MatrixMode(GL_MODELVIEW);
423
ARci.GLStates.DepthFunc := cfLEqual;
425
//second pass (inverse): render regular scene, blending it
427
if Style = ptsInverse then
430
Arci.GLStates.Enable(stBlend);
431
ARci.GLStates.SetBlendFunc(bfDstColor, bfSrcColor);
433
//second pass: render everything, blending with what is
435
ARci.ignoreBlendingRequests := true;
436
self.RenderChildren(0, Count - 1, ARci);
437
ARci.ignoreBlendingRequests := false;
444
RegisterClasses([TGLTextureEmitter, TGLProjectedTextures]);