diff -r 31570b766315 -r ed5a6478e710 hedgewars/uTextures.pas --- a/hedgewars/uTextures.pas Tue Nov 10 18:16:35 2015 +0100 +++ b/hedgewars/uTextures.pas Tue Nov 10 20:43:13 2015 +0100 @@ -1,6 +1,6 @@ (* * Hedgewars, a free turn based strategy game - * Copyright (c) 2004-2013 Andrey Korotaev + * Copyright (c) 2004-2015 Andrey Korotaev * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *) {$INCLUDE "options.inc"} @@ -25,7 +25,8 @@ function NewTexture(width, height: Longword; buf: Pointer): PTexture; procedure Surface2GrayScale(surf: PSDL_Surface); function Surface2Tex(surf: PSDL_Surface; enableClamp: boolean): PTexture; -procedure FreeTexture(tex: PTexture); +procedure PrettifySurfaceAlpha(surf: PSDL_Surface; pixels: PLongwordArray); +procedure PrettifyAlpha2D(pixels: TLandArray; height, width: LongWord); procedure FreeAndNilTexture(var tex: PTexture); procedure initModule; @@ -107,20 +108,102 @@ fromP4:= Surf^.pixels; for y:= 0 to Pred(Surf^.h) do begin - for x:= 0 to Pred(Surf^.w) do + for x:= 0 to Pred(Surf^.w) do begin tw:= fromP4^[x]; - tw:= round((tw shr RShift and $FF) * RGB_LUMINANCE_RED + - (tw shr GShift and $FF) * RGB_LUMINANCE_GREEN + + tw:= round((tw shr RShift and $FF) * RGB_LUMINANCE_RED + + (tw shr GShift and $FF) * RGB_LUMINANCE_GREEN + (tw shr BShift and $FF) * RGB_LUMINANCE_BLUE); if tw > 255 then tw:= 255; tw:= (tw and $FF shl RShift) or (tw and $FF shl BShift) or (tw and $FF shl GShift) or (fromP4^[x] and AMask); fromP4^[x]:= tw; end; - fromP4:= @(fromP4^[Surf^.pitch div 4]) + fromP4:= PLongWordArray(@(fromP4^[Surf^.pitch div 4])) end; end; +{ this will make invisible pixels that have a visible neighbor have the + same color as their visible neighbor, so that bilinear filtering won't + display a "wrongly" colored border when zoomed in } +procedure PrettifyAlpha(row1, row2: PLongwordArray; firsti, lasti, ioffset: LongWord); +var + i: Longword; + lpi, cpi, bpi: boolean; // was last/current/bottom neighbor pixel invisible? +begin + // suppress incorrect warning + lpi:= true; + for i:=firsti to lasti do + begin + // use first pixel in row1 as starting point + if i = firsti then + cpi:= ((row1^[i] and AMask) = 0) + else + begin + cpi:= ((row1^[i] and AMask) = 0); + if cpi <> lpi then + begin + // invisible pixels get colors from visible neighbors + if cpi then + begin + row1^[i]:= row1^[i-1] and (not AMask); + // as this pixel is invisible and already colored correctly now, no point in further comparing it + lpi:= cpi; + continue; + end + else + row1^[i-1]:= row1^[i] and (not AMask); + end; + end; + lpi:= cpi; + // also check bottom neighbor + if row2 <> nil then + begin + bpi:= ((row2^[i+ioffset] and AMask) = 0); + if cpi <> bpi then + begin + if cpi then + row1^[i]:= row2^[i+ioffset] and (not AMask) + else + row2^[i+ioffset]:= row1^[i] and (not AMask); + end; + end; + end; +end; + +procedure PrettifySurfaceAlpha(surf: PSDL_Surface; pixels: PLongwordArray); +var + // current row index, second last row index of array, width and first/last i of row + r, slr, w, si, li: LongWord; +begin + w:= surf^.w; + slr:= surf^.h - 2; + si:= 0; + li:= w - 1; + for r:= 0 to slr do + begin + PrettifyAlpha(pixels, pixels, si, li, w); + // move indices to next row + si:= si + w; + li:= li + w; + end; + // don't forget last row + PrettifyAlpha(pixels, nil, si, li, w); +end; + +procedure PrettifyAlpha2D(pixels: TLandArray; height, width: LongWord); +var + // current y; last x, second last y of array; + y, lx, sly: LongWord; +begin + sly:= height - 2; + lx:= width - 1; + for y:= 0 to sly do + begin + PrettifyAlpha(PLongWordArray(pixels[y]), PLongWordArray(pixels[y+1]), 0, lx, 0); + end; + // don't forget last row + PrettifyAlpha(PLongWordArray(pixels[sly+1]), nil, 0, lx, 0); +end; function Surface2Tex(surf: PSDL_Surface; enableClamp: boolean): PTexture; var tw, th, x, y: Longword; @@ -148,7 +231,6 @@ exit end; - glGenTextures(1, @Surface2Tex^.id); glBindTexture(GL_TEXTURE_2D, Surface2Tex^.id); @@ -161,6 +243,8 @@ if GrayScale then Surface2GrayScale(Surf); +PrettifySurfaceAlpha(surf, fromP4); + if (not SupportNPOTT) and (not (isPowerOf2(Surf^.w) and isPowerOf2(Surf^.h))) then begin tw:= toPowerOf2(Surf^.w); @@ -179,16 +263,16 @@ for x:= 0 to Pred(Surf^.w) do toP4^[x]:= fromP4^[x]; for x:= Surf^.w to Pred(tw) do - toP4^[x]:= 0; - toP4:= @(toP4^[tw]); - fromP4:= @(fromP4^[Surf^.pitch div 4]) + toP4^[x]:= fromP4^[0]; + toP4:= PLongWordArray(@(toP4^[tw])); + fromP4:= PLongWordArray(@(fromP4^[Surf^.pitch div 4])) end; for y:= Surf^.h to Pred(th) do begin for x:= 0 to Pred(tw) do toP4^[x]:= 0; - toP4:= @(toP4^[tw]) + toP4:= PLongWordArray(@(toP4^[tw])) end; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_BYTE, tmpp); @@ -212,25 +296,20 @@ // deletes texture and frees the memory allocated for it. // if nil is passed nothing is done -procedure FreeTexture(tex: PTexture); -begin -if tex <> nil then - begin - if tex^.NextTexture <> nil then - tex^.NextTexture^.PrevTexture:= tex^.PrevTexture; - if tex^.PrevTexture <> nil then - tex^.PrevTexture^.NextTexture:= tex^.NextTexture - else - TextureList:= tex^.NextTexture; - glDeleteTextures(1, @tex^.id); - Dispose(tex); - end -end; - procedure FreeAndNilTexture(var tex: PTexture); begin - FreeTexture(tex); - tex:= nil + if tex <> nil then + begin + if tex^.NextTexture <> nil then + tex^.NextTexture^.PrevTexture:= tex^.PrevTexture; + if tex^.PrevTexture <> nil then + tex^.PrevTexture^.NextTexture:= tex^.NextTexture + else + TextureList:= tex^.NextTexture; + glDeleteTextures(1, @tex^.id); + Dispose(tex); + tex:= nil; + end; end; procedure initModule; @@ -239,13 +318,15 @@ end; procedure freeModule; +var tex: PTexture; begin if TextureList <> nil then WriteToConsole('FIXME FIXME FIXME. App shutdown without full cleanup of texture list; read game0.log and please report this problem'); - while TextureList <> nil do + while TextureList <> nil do begin - AddFileLog('Texture not freed: width='+inttostr(LongInt(TextureList^.w))+' height='+inttostr(LongInt(TextureList^.h))+' priority='+inttostr(round(TextureList^.priority*1000))); - FreeTexture(TextureList); + tex:= TextureList; + AddFileLog('Texture not freed: width='+inttostr(LongInt(tex^.w))+' height='+inttostr(LongInt(tex^.h))+' priority='+inttostr(round(tex^.priority*1000))); + FreeAndNilTexture(tex); end end;