hedgewars/uTextures.pas
changeset 7304 8b3575750cd2
parent 7297 af64b509725c
child 7377 1aceade403ba
equal deleted inserted replaced
7301:bea42438a2ec 7304:8b3575750cd2
    22 interface
    22 interface
    23 uses SDLh, uTypes;
    23 uses SDLh, uTypes;
    24 
    24 
    25 function  NewTexture(width, height: Longword; buf: Pointer): PTexture;
    25 function  NewTexture(width, height: Longword; buf: Pointer): PTexture;
    26 procedure Surface2GrayScale(surf: PSDL_Surface);
    26 procedure Surface2GrayScale(surf: PSDL_Surface);
       
    27 function SurfaceSheet2Atlas(surf: PSDL_Surface; spriteWidth: Integer; spriteHeight: Integer): PTexture;
    27 function  Surface2Atlas(surf: PSDL_Surface; enableClamp: boolean): PTexture;
    28 function  Surface2Atlas(surf: PSDL_Surface; enableClamp: boolean): PTexture;
    28 procedure FreeTexture(tex: PTexture);
    29 procedure FreeTexture(tex: PTexture);
    29 procedure ComputeTexcoords(texture: PTexture; r: PSDL_Rect; tb: PVertexRect);
    30 procedure ComputeTexcoords(texture: PTexture; r: PSDL_Rect; tb: PVertexRect);
    30 
    31 
    31 procedure initModule;
    32 procedure initModule;
    32 procedure freeModule;
    33 procedure freeModule;
    33 
    34 
    34 implementation
    35 implementation
    35 uses GLunit, uUtils, uVariables, uConsts, uDebug, uConsole, uAtlas;
    36 uses GLunit, uUtils, uVariables, uConsts, uDebug, uConsole, uAtlas, SysUtils;
    36 
    37 
    37 var TextureList: PTexture;
    38 var
    38 
    39   logFile: TextFile;
       
    40 
       
    41 function CropSurface(source: PSDL_Surface; rect: PSDL_Rect): PSDL_Surface;
       
    42 var
       
    43     fmt: PSDL_PixelFormat;
       
    44     srcP, dstP: PByte;
       
    45     copySize: Integer;
       
    46     i: Integer;
       
    47 const
       
    48     pixelSize = 4;
       
    49 begin
       
    50     //writeln(stdout, 'Cropping from ' + IntToStr(source^.w) + 'x' + IntToStr(source^.h) + ' -> ' + IntToStr(rect^.w) + 'x' + IntToStr(rect^.h));
       
    51 
       
    52     fmt:= source^.format;
       
    53 
       
    54     CropSurface:= SDL_CreateRGBSurface(source^.flags, rect^.w, rect^.h, 
       
    55         fmt^.BitsPerPixel, fmt^.Rmask, fmt^.Gmask, fmt^.Bmask, fmt^.Amask);
       
    56 
       
    57     if SDL_MustLock(source) then
       
    58         SDLTry(SDL_LockSurface(source) >= 0, true);
       
    59     if SDL_MustLock(CropSurface) then
       
    60         SDLTry(SDL_LockSurface(CropSurface) >= 0, true);
       
    61 
       
    62     srcP:= source^.pixels;
       
    63     dstP:= CropSurface^.pixels;
       
    64 
       
    65     inc(srcP, pixelSize * rect^.x);
       
    66     inc(srcP, source^.pitch * rect^.y);
       
    67     copySize:= rect^.w * pixelSize;
       
    68     for i:= 0 to Pred(rect^.h) do
       
    69     begin
       
    70         Move(srcP^, dstP^, copySize);
       
    71         inc(srcP, source^.pitch);
       
    72         inc(dstP, CropSurface^.pitch);
       
    73     end;
       
    74 
       
    75     if SDL_MustLock(source) then
       
    76         SDL_UnlockSurface(source);
       
    77     if SDL_MustLock(CropSurface) then
       
    78         SDL_UnlockSurface(CropSurface);
       
    79 end;
       
    80 
       
    81 function TransparentLine(p: PByte; stride: Integer; length: Integer): boolean;
       
    82 var
       
    83     i: Integer;
       
    84 begin
       
    85     TransparentLine:= false;
       
    86     for i:=0 to pred(length) do
       
    87     begin
       
    88         if p^ <> 0 then
       
    89             exit;
       
    90         inc(p, stride);
       
    91     end;
       
    92     TransparentLine:= true;
       
    93 end;
       
    94 
       
    95 function AutoCrop(source: PSDL_Surface; var cropinfo: TCropInformation): PSDL_Surface;
       
    96 var
       
    97     l,r,t,b, i: Integer;
       
    98     pixels, p: PByte;
       
    99     scanlineSize: Integer;
       
   100     rect: TSDL_Rect;
       
   101 const
       
   102     pixelSize = 4;
       
   103 begin
       
   104     l:= source^.w; 
       
   105     r:= 0; 
       
   106     t:= source^.h;
       
   107     b:= 0;
       
   108 
       
   109     if SDL_MustLock(source) then
       
   110         SDLTry(SDL_LockSurface(source) >= 0, true);
       
   111 
       
   112     pixels:= source^.pixels;
       
   113     scanlineSize:= source^.pitch;
       
   114 
       
   115     inc(pixels, 3); // advance to alpha value
       
   116 
       
   117     // check top
       
   118     p:= pixels;
       
   119     for i:= 0 to Pred(source^.h) do
       
   120     begin
       
   121         if not TransparentLine(p, pixelSize, source^.w) then
       
   122         begin
       
   123             t:= i;
       
   124             break;
       
   125         end;
       
   126         inc(p, scanlineSize);
       
   127     end;
       
   128 
       
   129 
       
   130     // check bottom
       
   131     p:= pixels;
       
   132     inc(p, scanlineSize * source^.h);
       
   133     for i:= 0 to Pred(source^.h - t) do
       
   134     begin
       
   135         dec(p, scanlineSize);
       
   136         if not TransparentLine(p, pixelSize, source^.w) then
       
   137         begin
       
   138             b:= i;
       
   139             break;
       
   140         end;
       
   141     end;
       
   142 
       
   143     // check left
       
   144     p:= pixels;
       
   145     for i:= 0 to Pred(source^.w) do
       
   146     begin
       
   147         if not TransparentLine(p, scanlineSize, source^.h) then
       
   148         begin
       
   149             l:= i;
       
   150             break;
       
   151         end;
       
   152         inc(p, pixelSize);
       
   153     end;
       
   154 
       
   155     // check right
       
   156     p:= pixels;
       
   157     inc(p, scanlineSize);
       
   158     for i:= 0 to Pred(source^.w - l) do
       
   159     begin
       
   160         dec(p, pixelSize);
       
   161         if not TransparentLine(p, scanlineSize, source^.h) then
       
   162         begin
       
   163             r:= i;
       
   164             break;
       
   165         end;
       
   166     end;
       
   167 
       
   168     if SDL_MustLock(source) then
       
   169         SDL_UnlockSurface(source);
       
   170 
       
   171     rect.x:= l;
       
   172     rect.y:= t;
       
   173 
       
   174     rect.w:= source^.w - r - l;    
       
   175     rect.h:= source^.h - b - t;
       
   176 
       
   177     cropInfo.l:= l;
       
   178     cropInfo.r:= r;
       
   179     cropInfo.t:= t;
       
   180     cropInfo.b:= b;
       
   181     cropInfo.x:= Trunc(source^.w / 2 - l + r);
       
   182     cropInfo.y:= Trunc(source^.h / 2 - t + b);
       
   183 
       
   184     if (l = source^.w) or (t = source^.h) then
       
   185     begin
       
   186         result:= nil;
       
   187         exit;
       
   188     end;
       
   189 
       
   190     if (l <> 0) or (r <> 0) or (t <> 0) or (b <> 0) then
       
   191         result:= CropSurface(source, @rect)
       
   192     else result:= source;
       
   193 end;
    39 
   194 
    40 procedure SetTextureParameters(enableClamp: Boolean);
   195 procedure SetTextureParameters(enableClamp: Boolean);
    41 begin
   196 begin
    42     if enableClamp and ((cReducedQuality and rqClampLess) = 0) then
   197     if enableClamp and ((cReducedQuality and rqClampLess) = 0) then
    43         begin
   198         begin
    47     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   202     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    48     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
   203     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    49 end;
   204 end;
    50 
   205 
    51 procedure ComputeTexcoords(texture: PTexture; r: PSDL_Rect; tb: PVertexRect);
   206 procedure ComputeTexcoords(texture: PTexture; r: PSDL_Rect; tb: PVertexRect);
    52 var x0, y0, x1, y1, tmp: Real;
   207 var 
       
   208     x0, y0, x1, y1, tmp: Real;
    53     w, h, aw, ah: LongInt;
   209     w, h, aw, ah: LongInt;
    54 const texelOffset = 0.0;
   210     p: PChar;
    55 begin
   211 const 
    56 aw:=texture^.atlas^.w;
   212     texelOffset = 0.0;
    57 ah:=texture^.atlas^.h;
   213 begin
    58 
   214     aw:=texture^.atlas^.w;
    59 if texture^.isRotated then
   215     ah:=texture^.atlas^.h;
    60     begin
   216 
    61     w:=r^.h;
   217     if texture^.isRotated then
    62     h:=r^.w;
   218     begin
    63     end 
   219         w:=r^.h;
    64 else
   220         h:=r^.w;
    65     begin
   221     end else
    66     w:=r^.w;
   222     begin
    67     h:=r^.h;        
   223         w:=r^.w;
    68     end;
   224         h:=r^.h;        
    69 
   225     end;
    70 x0:= (texture^.x + r^.x +     texelOffset)/aw;
   226 
    71 x1:= (texture^.x + r^.x + w - texelOffset)/aw;
   227     x0:= (texture^.x + {r^.x} +     texelOffset)/aw;
    72 y0:= (texture^.y + r^.y +     texelOffset)/ah;
   228     x1:= (texture^.x + {r^.x} + w - texelOffset)/aw;
    73 y1:= (texture^.y + r^.y + h - texelOffset)/ah;
   229     y0:= (texture^.y + {r^.y} +     texelOffset)/ah;
    74 
   230     y1:= (texture^.y + {r^.y} + h - texelOffset)/ah;
    75 if (texture^.isRotated) then
   231 
    76 begin
   232     if (texture^.isRotated) then
    77   tb^[0].X:= x0;
   233     begin
    78   tb^[0].Y:= y0;
   234         tb^[0].X:= x0;
    79   tb^[3].X:= x1;
   235         tb^[0].Y:= y0;
    80   tb^[3].Y:= y0;
   236         tb^[3].X:= x1;
    81   tb^[2].X:= x1;
   237         tb^[3].Y:= y0;
    82   tb^[2].Y:= y1;
   238         tb^[2].X:= x1;
    83   tb^[1].X:= x0;
   239         tb^[2].Y:= y1;
    84   tb^[1].Y:= y1
   240         tb^[1].X:= x0;
    85 end else
   241         tb^[1].Y:= y1
    86 begin
   242     end else
    87   tb^[0].X:= x0;
   243     begin
    88   tb^[0].Y:= y0;
   244         tb^[0].X:= x0;
    89   tb^[1].X:= x1;
   245         tb^[0].Y:= y0;
    90   tb^[1].Y:= y0;
   246         tb^[1].X:= x1;
    91   tb^[2].X:= x1;
   247         tb^[1].Y:= y0;
    92   tb^[2].Y:= y1;
   248         tb^[2].X:= x1;
    93   tb^[3].X:= x0;
   249         tb^[2].Y:= y1;
    94   tb^[3].Y:= y1;
   250         tb^[3].X:= x0;
    95 end;
   251         tb^[3].Y:= y1;
       
   252     end;
    96 end;
   253 end;
    97 
   254 
    98 procedure ResetVertexArrays(texture: PTexture);
   255 procedure ResetVertexArrays(texture: PTexture);
    99 var r: TSDL_Rect;
   256 var r: TSDL_Rect;
   100 begin
   257 begin
   101 with texture^ do
   258     with texture^ do
   102 begin
   259     begin
   103     vb[0].X:= 0;
   260         vb[0].X:= texture^.cropInfo.l;
   104     vb[0].Y:= 0;
   261         vb[0].Y:= texture^.cropInfo.t;
   105     vb[1].X:= w;
   262         vb[1].X:= texture^.cropInfo.l + w;
   106     vb[1].Y:= 0;
   263         vb[1].Y:= texture^.cropInfo.t;
   107     vb[2].X:= w;
   264         vb[2].X:= texture^.cropInfo.l + w;
   108     vb[2].Y:= h;
   265         vb[2].Y:= texture^.cropInfo.t + h;
   109     vb[3].X:= 0;
   266         vb[3].X:= texture^.cropInfo.l;
   110     vb[3].Y:= h;
   267         vb[3].Y:= texture^.cropInfo.t + h;
   111 end;
   268     end;
   112 
   269 
   113 r.x:= 0;
   270     r.x:= 0;
   114 r.y:= 0;
   271     r.y:= 0;
   115 r.w:= texture^.w;
   272     r.w:= texture^.w;
   116 r.h:= texture^.h;
   273     r.h:= texture^.h;
   117 ComputeTexcoords(texture, @r, @texture^.tb);
   274     ComputeTexcoords(texture, @r, @texture^.tb);
   118 end;
   275 end;
   119 
   276 
   120 function NewTexture(width, height: Longword; buf: Pointer): PTexture;
   277 function NewTexture(width, height: Longword; buf: Pointer): PTexture;
   121 begin
   278 begin
   122 new(NewTexture);
   279 new(NewTexture);
   123 NewTexture^.PrevTexture:= nil;
       
   124 NewTexture^.NextTexture:= nil;
       
   125 NewTexture^.Scale:= 1;
   280 NewTexture^.Scale:= 1;
   126 if TextureList <> nil then
       
   127     begin
       
   128     TextureList^.PrevTexture:= NewTexture;
       
   129     NewTexture^.NextTexture:= TextureList
       
   130     end;
       
   131 TextureList:= NewTexture;
       
   132 
       
   133 
   281 
   134 // Atlas allocation happens here later on. For now we just allocate one exclusive atlas per sprite
   282 // Atlas allocation happens here later on. For now we just allocate one exclusive atlas per sprite
   135 new(NewTexture^.atlas);
   283 new(NewTexture^.atlas);
   136 NewTexture^.atlas^.w:=width;
   284 NewTexture^.atlas^.w:=width;
   137 NewTexture^.atlas^.h:=height;
   285 NewTexture^.atlas^.h:=height;
   140 NewTexture^.w:=width;
   288 NewTexture^.w:=width;
   141 NewTexture^.h:=height;
   289 NewTexture^.h:=height;
   142 NewTexture^.isRotated:=false;
   290 NewTexture^.isRotated:=false;
   143 NewTexture^.shared:=false;
   291 NewTexture^.shared:=false;
   144 NewTexture^.surface:=nil;
   292 NewTexture^.surface:=nil;
       
   293 NewTexture^.nextFrame:=nil;
       
   294 NewTexture^.cropInfo.l:= 0;
       
   295 NewTexture^.cropInfo.r:= 0;
       
   296 NewTexture^.cropInfo.t:= 0;
       
   297 NewTexture^.cropInfo.b:= 0;
       
   298 NewTexture^.cropInfo.x:= width div 2;
       
   299 NewTexture^.cropInfo.y:= height div 2;
       
   300 
   145 
   301 
   146 ResetVertexArrays(NewTexture);
   302 ResetVertexArrays(NewTexture);
   147 
   303 
   148 glGenTextures(1, @NewTexture^.atlas^.id);
   304 glGenTextures(1, @NewTexture^.atlas^.id);
   149 
   305 
   173     fromP4:= @(fromP4^[Surf^.pitch div 4])
   329     fromP4:= @(fromP4^[Surf^.pitch div 4])
   174     end;
   330     end;
   175 end;
   331 end;
   176 
   332 
   177 
   333 
       
   334 function SurfaceSheet2Atlas(surf: PSDL_Surface; spriteWidth: Integer; spriteHeight: Integer): PTexture;
       
   335 var
       
   336     subSurface: PSDL_Surface;
       
   337     framesX, framesY: Integer;
       
   338     last, current: PTexture;
       
   339     r: TSDL_Rect;
       
   340     x, y: Integer;
       
   341 begin
       
   342     SurfaceSheet2Atlas:= nil;
       
   343     r.x:= 0;
       
   344     r.y:= 0;
       
   345     r.w:= spriteWidth;
       
   346     r.h:= spriteHeight;
       
   347     last:= nil;
       
   348 
       
   349     framesX:= surf^.w div spriteWidth;
       
   350     framesY:= surf^.h div spriteHeight;
       
   351 
       
   352     for x:=0 to Pred(framesX) do
       
   353     begin
       
   354         r.y:= 0;
       
   355         for y:=0 to Pred(framesY) do
       
   356         begin
       
   357             subSurface:= CropSurface(surf, @r);
       
   358             current:= Surface2Atlas(subSurface, false);
       
   359 
       
   360             if last = nil then
       
   361             begin
       
   362                 SurfaceSheet2Atlas:= current;
       
   363                 last:= current;
       
   364             end else
       
   365             begin
       
   366                 last^.nextFrame:= current;
       
   367                 last:= current;
       
   368             end;
       
   369             inc(r.y, spriteHeight);
       
   370         end;
       
   371         inc(r.x, spriteWidth);
       
   372     end;
       
   373 
       
   374     SDL_FreeSurface(surf);
       
   375 end;
       
   376 
   178 function Surface2Atlas(surf: PSDL_Surface; enableClamp: boolean): PTexture;
   377 function Surface2Atlas(surf: PSDL_Surface; enableClamp: boolean): PTexture;
   179 var tw, th, x, y: Longword;
   378 var tw, th, x, y: Longword;
   180     tmpp: pointer;
   379     tmpp: pointer;
       
   380     cropped: PSDL_Surface;
   181     fromP4, toP4: PLongWordArray;
   381     fromP4, toP4: PLongWordArray;
   182 begin
   382     cropInfo: TCropInformation;
   183     if (surf^.w <= 256) and (surf^.h <= 256) then
   383 begin
       
   384     cropped:= AutoCrop(surf, cropInfo);
       
   385     if cropped <> surf then
       
   386     begin
       
   387         SDL_FreeSurface(surf);
       
   388         surf:= cropped;
       
   389     end;
       
   390 
       
   391     if surf = nil then
       
   392     begin
       
   393         new(Surface2Atlas);
       
   394         Surface2Atlas^.w:= 0;
       
   395         Surface2Atlas^.h:= 0;
       
   396         Surface2Atlas^.x:=0 ;
       
   397         Surface2Atlas^.y:=0 ;
       
   398         Surface2Atlas^.isRotated:= false;
       
   399         Surface2Atlas^.surface:= nil;
       
   400         Surface2Atlas^.shared:= false;
       
   401         Surface2Atlas^.nextFrame:= nil;
       
   402         Surface2Atlas^.cropInfo:= cropInfo;
       
   403         exit;
       
   404     end;
       
   405 
       
   406     if (surf^.w <= 512) and (surf^.h <= 512) then
   184     begin
   407     begin
   185         Surface2Atlas:= Surface2Tex_(surf, enableClamp); // run the atlas side by side for debugging
   408         Surface2Atlas:= Surface2Tex_(surf, enableClamp); // run the atlas side by side for debugging
       
   409         Surface2Atlas^.cropInfo:= cropInfo;
   186         ResetVertexArrays(Surface2Atlas);
   410         ResetVertexArrays(Surface2Atlas);
   187         exit;
   411         exit;
   188     end;
   412     end;
   189 new(Surface2Atlas);
   413 new(Surface2Atlas);
   190 Surface2Atlas^.PrevTexture:= nil;
       
   191 Surface2Atlas^.NextTexture:= nil;
       
   192 if TextureList <> nil then
       
   193     begin
       
   194     TextureList^.PrevTexture:= Surface2Atlas;
       
   195     Surface2Atlas^.NextTexture:= TextureList
       
   196     end;
       
   197 TextureList:= Surface2Atlas;
       
   198 
   414 
   199 // Atlas allocation happens here later on. For now we just allocate one exclusive atlas per sprite
   415 // Atlas allocation happens here later on. For now we just allocate one exclusive atlas per sprite
   200 new(Surface2Atlas^.atlas);
   416 new(Surface2Atlas^.atlas);
   201 
   417 
   202 Surface2Atlas^.w:= surf^.w;
   418 Surface2Atlas^.w:= surf^.w;
   204 Surface2Atlas^.x:=0;
   420 Surface2Atlas^.x:=0;
   205 Surface2Atlas^.y:=0;
   421 Surface2Atlas^.y:=0;
   206 Surface2Atlas^.isRotated:=false;
   422 Surface2Atlas^.isRotated:=false;
   207 Surface2Atlas^.surface:= surf;
   423 Surface2Atlas^.surface:= surf;
   208 Surface2Atlas^.shared:= false;
   424 Surface2Atlas^.shared:= false;
       
   425 Surface2Atlas^.nextFrame:= nil;
       
   426 Surface2Atlas^.cropInfo:= cropInfo;
   209 
   427 
   210 
   428 
   211 if (surf^.format^.BytesPerPixel <> 4) then
   429 if (surf^.format^.BytesPerPixel <> 4) then
   212     begin
   430     begin
   213     TryDo(false, 'Surface2Tex failed, expecting 32 bit surface', true);
   431     TryDo(false, 'Surface2Tex failed, expecting 32 bit surface', true);
   214     Surface2Atlas^.atlas^.id:= 0;
   432     Surface2Atlas^.atlas^.id:= 0;
   215     exit
   433     exit;
   216     end;
   434     end;
   217 
   435 
   218 
   436 
   219 glGenTextures(1, @Surface2Atlas^.atlas^.id);
   437 glGenTextures(1, @Surface2Atlas^.atlas^.id);
   220 
   438 
   279 
   497 
   280 // deletes texture and frees the memory allocated for it.
   498 // deletes texture and frees the memory allocated for it.
   281 // if nil is passed nothing is done
   499 // if nil is passed nothing is done
   282 procedure FreeTexture(tex: PTexture);
   500 procedure FreeTexture(tex: PTexture);
   283 begin
   501 begin
   284 if tex <> nil then
   502     if tex <> nil then
   285     begin
   503     begin
       
   504         FreeTexture(tex^.nextFrame); // free all frames linked to this animation
       
   505 
       
   506         if tex^.surface = nil then
       
   507         begin
       
   508             Dispose(tex);
       
   509             exit;
       
   510         end;
       
   511 
   286         if tex^.shared then
   512         if tex^.shared then
   287         begin
   513         begin
       
   514             SDL_FreeSurface(tex^.surface);
   288             FreeTexture_(tex); // run atlas side by side for debugging
   515             FreeTexture_(tex); // run atlas side by side for debugging
   289             SDL_FreeSurface(tex^.surface);
       
   290             exit;
   516             exit;
   291         end;
   517         end;
   292 
   518 
   293     // Atlas cleanup happens here later on. For now we just free as each sprite has one atlas
   519     // Atlas cleanup happens here later on. For now we just free as each sprite has one atlas
       
   520     glDeleteTextures(1, @tex^.atlas^.id);
   294     Dispose(tex^.atlas);
   521     Dispose(tex^.atlas);
   295 
       
   296     if tex^.NextTexture <> nil then
       
   297         tex^.NextTexture^.PrevTexture:= tex^.PrevTexture;
       
   298     if tex^.PrevTexture <> nil then
       
   299         tex^.PrevTexture^.NextTexture:= tex^.NextTexture
       
   300     else
       
   301         TextureList:= tex^.NextTexture;
       
   302     glDeleteTextures(1, @tex^.atlas^.id);
       
   303 
   522 
   304     if (tex^.surface <> nil) then
   523     if (tex^.surface <> nil) then
   305         SDL_FreeSurface(tex^.surface);
   524         SDL_FreeSurface(tex^.surface);
   306     Dispose(tex);
   525     Dispose(tex);
   307     end
   526     end
   308 end;
   527 end;
   309 
   528 
   310 procedure initModule;
   529 procedure initModule;
   311 begin
   530 begin
       
   531 assign(logFile, 'out.log');
       
   532 rewrite(logFile);
   312 uAtlas.initModule;
   533 uAtlas.initModule;
   313 TextureList:= nil;
       
   314 end;
   534 end;
   315 
   535 
   316 procedure freeModule;
   536 procedure freeModule;
   317 begin
   537 begin
   318 if TextureList <> nil then
   538 close(logFile);
   319     WriteToConsole('FIXME FIXME FIXME. App shutdown without full cleanup of texture list; read game0.log and please report this problem');
       
   320     while TextureList <> nil do 
       
   321         begin
       
   322         AddFileLog('Sprite not freed: width='+inttostr(LongInt(TextureList^.w))+' height='+inttostr(LongInt(TextureList^.h))+' priority='+inttostr(round(TextureList^.atlas^.priority*1000)));
       
   323         FreeTexture(TextureList);
       
   324         end
       
   325 end;
   539 end;
   326 
   540 
   327 end.
   541 end.