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. |