- 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>
<SmartLinkUnit Value="True"/>
<Optimizations>
<OptimizationLevel Value="3"/>
<OptimizationLevel Value="0"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="True"/>
<UseHeaptrc Value="True"/>
</Debugging>
<LinkSmart Value="True"/>
<Options>
<Win32>
<GraphicApplication Value="True"/>

View File

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

View File

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