- Added FBO based light source rendering

- Fixed memory leak in TLightManager.UpdateLightMap
This commit is contained in:
Andreas Schneider 2009-12-22 09:36:35 +01:00
parent a19e23a82e
commit 841061abbb
3 changed files with 110 additions and 63 deletions

View File

@ -350,14 +350,14 @@
<CodeGeneration> <CodeGeneration>
<SmartLinkUnit Value="True"/> <SmartLinkUnit Value="True"/>
<Optimizations> <Optimizations>
<OptimizationLevel Value="3"/> <OptimizationLevel Value="0"/>
</Optimizations> </Optimizations>
</CodeGeneration> </CodeGeneration>
<Linking> <Linking>
<Debugging> <Debugging>
<GenerateDebugInfo Value="True"/> <GenerateDebugInfo Value="True"/>
<UseHeaptrc Value="True"/>
</Debugging> </Debugging>
<LinkSmart Value="True"/>
<Options> <Options>
<Win32> <Win32>
<GraphicApplication Value="True"/> <GraphicApplication Value="True"/>

View File

@ -56,7 +56,7 @@ type
FRealWidth: Integer; FRealWidth: Integer;
FRealHeight: Integer; FRealHeight: Integer;
FGraphic: TMultiImage; FGraphic: TMultiImage;
procedure CalculateTextureDimensions(ACaps: TGLTextureCaps; ARealWidth, class procedure CalculateTextureDimensions(ACaps: TGLTextureCaps; ARealWidth,
ARealHeight: Integer; out AWidth, AHeight: Integer); ARealHeight: Integer; out AWidth, AHeight: Integer);
function GenerateTexture(AImage: TBaseImage): TGLuint; function GenerateTexture(AImage: TBaseImage): TGLuint;
function GetTexture: GLuint; virtual; abstract; function GetTexture: GLuint; virtual; abstract;
@ -1283,7 +1283,7 @@ begin
inherited Destroy; inherited Destroy;
end; end;
procedure TMaterial.CalculateTextureDimensions(ACaps: TGLTextureCaps; class procedure TMaterial.CalculateTextureDimensions(ACaps: TGLTextureCaps;
ARealWidth, ARealHeight: Integer; out AWidth, AHeight: Integer); ARealWidth, ARealHeight: Integer; out AWidth, AHeight: Integer);
begin begin
if ACaps.NonPowerOfTwo then if ACaps.NonPowerOfTwo then

View File

@ -31,8 +31,7 @@ interface
uses uses
Classes, SysUtils, Imaging, ImagingTypes, ImagingClasses, ImagingCanvases, Classes, SysUtils, Imaging, ImagingTypes, ImagingClasses, ImagingCanvases,
ImagingOpenGL, GL, fgl, ULandscape, UWorldItem, UCacheManager, ImagingOpenGL, GL, GLu, GLext, fgl, ULandscape, UWorldItem, UCacheManager;
ImagingUtility;
type type
@ -40,22 +39,13 @@ type
{ TLightMaterial } { TLightMaterial }
TLightMaterial = class(ICacheable) TLightMaterial = class(TSimpleMaterial)
constructor Create(AGraphic: TBaseImage); constructor Create(AGraphic: TBaseImage);
destructor Destroy; override; destructor Destroy; override;
protected protected
FRefCount: Integer;
FGraphic: TSingleImage;
FCanvas: TFastARGB32Canvas; FCanvas: TFastARGB32Canvas;
public public
property Graphic: TSingleImage read FGraphic;
property Canvas: TFastARGB32Canvas read FCanvas; property Canvas: TFastARGB32Canvas read FCanvas;
procedure AddRef;
procedure DelRef;
{ICacheable}
function CanBeRemoved: Boolean;
procedure RemoveFromCache;
end; end;
TLightCache = specialize TCacheManager<TLightMaterial>; TLightCache = specialize TCacheManager<TLightMaterial>;
@ -94,11 +84,14 @@ type
FValid: Boolean; FValid: Boolean;
FCalculateOffset: TCalculateOffset; FCalculateOffset: TCalculateOffset;
FLightCache: TLightCache; FLightCache: TLightCache;
FUseFBO: Boolean;
FInitialized: Boolean;
function GetLight(AID: Integer): TLightMaterial; function GetLight(AID: Integer): TLightMaterial;
procedure SetLightLevel(AValue: Byte); procedure SetLightLevel(AValue: Byte);
procedure UpdateOverlay(AScreenRect: TRect); procedure UpdateOverlay(AScreenRect: TRect);
public public
property LightLevel: Byte read FLightLevel write SetLightLevel; property LightLevel: Byte read FLightLevel write SetLightLevel;
procedure InitGL;
procedure UpdateLightMap(ALeft, AWidth, ATop, AHeight: Integer; procedure UpdateLightMap(ALeft, AWidth, ATop, AHeight: Integer;
AScreenBuffer: TScreenBuffer); AScreenBuffer: TScreenBuffer);
procedure Draw(AScreenRect: TRect); procedure Draw(AScreenRect: TRect);
@ -117,6 +110,7 @@ begin
FLightSources := TLightSources.Create(True); FLightSources := TLightSources.Create(True);
FLightLevel := 0; FLightLevel := 0;
FLightCache := TLightCache.Create(32); FLightCache := TLightCache.Create(32);
FInitialized := False;
end; end;
destructor TLightManager.Destroy; destructor TLightManager.Destroy;
@ -157,42 +151,101 @@ var
color: TColor32Rec; color: TColor32Rec;
i: Integer; i: Integer;
lightMaterial: TLightMaterial; lightMaterial: TLightMaterial;
colorGL: GLclampf;
fbo: GLuint;
begin begin
FOverlay.Free;
glDeleteTextures(1, @FOverlayTexture); glDeleteTextures(1, @FOverlayTexture);
if FUseFBO then
begin
glGenTextures(1, @FOverlayTexture);
glBindTexture(GL_TEXTURE_2D, FOverlayTexture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, AScreenRect.Right,
AScreenRect.Bottom, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
glBindTexture(GL_TEXTURE_2D, 0);
color.A := $FF; glGenFramebuffersEXT(1, @fbo);
color.R := ((32 - FLightLevel) * 255) div 32; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
color.G := color.R; glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
color.B := color.R; GL_TEXTURE_2D, FOverlayTexture, 0);
FOverlay := TSingleImage.CreateFromParams(AScreenRect.Right, colorGL :=(32 - lightLevel) / 32;
AScreenRect.Bottom, ifA8R8G8B8); glClearColor(colorGL, colorGL, colorGL, 1);
canvas := TFastARGB32Canvas.CreateForImage(FOverlay); glClear(GL_COLOR_BUFFER_BIT);
try
canvas.FillColor32 := color.Color;
canvas.FillRect(AScreenRect);
glBlendFunc(GL_ONE, GL_ONE);
for i := 0 to FLightSources.Count - 1 do for i := 0 to FLightSources.Count - 1 do
begin
lightMaterial := FLightSources[i].Material;
if lightMaterial <> nil then
begin begin
lightMaterial.Canvas.DrawAdd(lightMaterial.Canvas.ClipRect, canvas, lightMaterial := FLightSources[i].Material;
FLightSources[i].FX - lightMaterial.Graphic.Width div 2, if lightMaterial <> nil then
FLightSources[i].FY - lightMaterial.Graphic.Height div 2); begin
glBindTexture(GL_TEXTURE_2D, lightMaterial.Texture);
glBegin(GL_QUADS);
glTexCoord2i(0, 0);
glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2,
FLightSources[i].FY - lightMaterial.RealHeight div 2);
glTexCoord2i(0, 1);
glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2,
FLightSources[i].FY - lightMaterial.RealHeight div 2 +
lightMaterial.Height);
glTexCoord2i(1, 1);
glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2 +
lightMaterial.Width, FLightSources[i].FY -
lightMaterial.RealHeight div 2 + lightMaterial.Height);
glTexCoord2i(1, 0);
glVertex2i(FLightSources[i].FX - lightMaterial.RealWidth div 2 +
lightMaterial.Width,
FLightSources[i].FY - lightMaterial.RealHeight div 2);
glEnd;
end;
end; end;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1, @fbo);
end else
begin
FOverlay.Free;
color.A := $FF;
color.R := ((32 - FLightLevel) * 255) div 32;
color.G := color.R;
color.B := color.R;
FOverlay := TSingleImage.CreateFromParams(AScreenRect.Right,
AScreenRect.Bottom, ifA8R8G8B8);
canvas := TFastARGB32Canvas.CreateForImage(FOverlay);
try
canvas.FillColor32 := color.Color;
canvas.FillRect(AScreenRect);
for i := 0 to FLightSources.Count - 1 do
begin
lightMaterial := FLightSources[i].Material;
if lightMaterial <> nil then
begin
lightMaterial.Canvas.DrawAdd(lightMaterial.Canvas.ClipRect, canvas,
FLightSources[i].FX - lightMaterial.RealWidth div 2,
FLightSources[i].FY - lightMaterial.RealHeight div 2);
end;
end;
finally
canvas.Free;
end; end;
finally
canvas.Free; FOverlayTexture := CreateGLTextureFromImage(FOverlay.ImageDataPointer^);
end; end;
//TODO : PowerOfTwo!!!
FOverlayTexture := CreateGLTextureFromImage(FOverlay.ImageDataPointer^);
FValid := True; FValid := True;
end; end;
procedure TLightManager.InitGL;
begin
FUseFBO := Load_GL_EXT_framebuffer_object;
end;
procedure TLightManager.UpdateLightMap(ALeft, AWidth, ATop, AHeight: Integer; procedure TLightManager.UpdateLightMap(ALeft, AWidth, ATop, AHeight: Integer;
AScreenBuffer: TScreenBuffer); AScreenBuffer: TScreenBuffer);
var var
@ -249,18 +302,35 @@ begin
for i := 0 to lights.Count - 1 do for i := 0 to lights.Count - 1 do
FLightSources.Add(TLightSource.Create(Self, lights[i])); FLightSources.Add(TLightSource.Create(Self, lights[i]));
lights.Free;
FValid := False; FValid := False;
//Logger.ExitMethod([lcClient, lcDebug], 'UpdateLightMap'); //Logger.ExitMethod([lcClient, lcDebug], 'UpdateLightMap');
end; end;
procedure TLightManager.Draw(AScreenRect: TRect); procedure TLightManager.Draw(AScreenRect: TRect);
begin begin
if not FInitialized then
InitGL;
if not FValid then if not FValid then
UpdateOverlay(AScreenRect); UpdateOverlay(AScreenRect);
glBindTexture(GL_TEXTURE_2D, FOverlayTexture); glBindTexture(GL_TEXTURE_2D, FOverlayTexture);
glBlendFunc(GL_ZERO, GL_SRC_COLOR); glBlendFunc(GL_ZERO, GL_SRC_COLOR);
glBegin(GL_QUADS); glBegin(GL_QUADS);
if FUseFBO then
begin
glTexCoord2i(0, 1);
glVertex2i(AScreenRect.Left, AScreenRect.Top);
glTexCoord2i(0, 0);
glVertex2i(AScreenRect.Left, AScreenRect.Bottom);
glTexCoord2i(1, 0);
glVertex2i(AScreenRect.Right, AScreenRect.Bottom);
glTexCoord2i(1, 1);
glVertex2i(AScreenRect.Right, AScreenRect.Top);
end else
begin
glTexCoord2i(0, 0); glTexCoord2i(0, 0);
glVertex2i(AScreenRect.Left, AScreenRect.Top); glVertex2i(AScreenRect.Left, AScreenRect.Top);
glTexCoord2i(0, 1); glTexCoord2i(0, 1);
@ -269,6 +339,7 @@ begin
glVertex2i(AScreenRect.Right, AScreenRect.Bottom); glVertex2i(AScreenRect.Right, AScreenRect.Bottom);
glTexCoord2i(1, 0); glTexCoord2i(1, 0);
glVertex2i(AScreenRect.Right, AScreenRect.Top); glVertex2i(AScreenRect.Right, AScreenRect.Top);
end;
glEnd; glEnd;
end; end;
@ -300,39 +371,15 @@ end;
constructor TLightMaterial.Create(AGraphic: TBaseImage); constructor TLightMaterial.Create(AGraphic: TBaseImage);
begin begin
FRefCount := 1; inherited Create(AGraphic);
FGraphic := TSingleImage.CreateFromImage(AGraphic);
FCanvas := TFastARGB32Canvas.CreateForImage(FGraphic); FCanvas := TFastARGB32Canvas.CreateForImage(FGraphic);
end; end;
destructor TLightMaterial.Destroy; destructor TLightMaterial.Destroy;
begin begin
FreeAndNil(FCanvas); FreeAndNil(FCanvas);
FreeAndNil(FGraphic);
inherited Destroy; inherited Destroy;
end; end;
procedure TLightMaterial.AddRef;
begin
Inc(FRefCount);
end;
procedure TLightMaterial.DelRef;
begin
Dec(FRefCount);
if FRefCount < 1 then
Free;
end;
function TLightMaterial.CanBeRemoved: Boolean;
begin
Result := (FRefCount <= 1);
end;
procedure TLightMaterial.RemoveFromCache;
begin
DelRef;
end;
end. end.