--- a/hedgewars/uAtlas.pas Mon Jun 25 12:02:54 2012 +0200
+++ b/hedgewars/uAtlas.pas Mon Jun 25 15:46:08 2012 +0200
@@ -11,14 +11,15 @@
function Surface2Tex_(surf: PSDL_Surface; enableClamp: boolean): PTexture;
procedure FreeTexture_(sprite: PTexture);
+procedure DebugAtlas;
implementation
-uses GLunit, uBinPacker, uDebug, png, sysutils;
+uses GLunit, uBinPacker, uDebug, png, sysutils, uTextures;
const
- MaxAtlases = 1; // Maximum number of atlases (textures) to allocate
- MaxTexSize = 4096; // Maximum atlas size in pixels
+ MaxAtlases = 4; // Maximum number of atlases (textures) to allocate
+ MaxTexSize = 1024; // Maximum atlas size in pixels
MinTexSize = 128; // Minimum atlas size in pixels
CompressionThreshold = 0.4; // Try to compact (half the size of) an atlas, when occupancy is less than this
@@ -36,6 +37,40 @@
////////////////////////////////////////////////////////////////////////////////
// Debug routines
+procedure AssertCount(tex: PTexture; count: Integer);
+var
+ i, j: Integer;
+ found: Integer;
+begin
+ found:= 0;
+ for i:= 0 to pred(MaxAtlases) do
+ begin
+ if not Info[i].Allocated then
+ continue;
+ for j:=0 to pred(Info[i].PackerInfo.usedRectangles.count) do
+ begin
+ if Info[i].PackerInfo.usedRectangles.data[j].UserData = tex then
+ inc(found);
+ end;
+ end;
+ if found <> count then
+ begin
+ writeln('AssertCount(', IntToHex(Integer(tex), 8), ') failed, found ', found, ' times');
+
+ for i:= 0 to pred(MaxAtlases) do
+ begin
+ if not Info[i].Allocated then
+ continue;
+ for j:=0 to pred(Info[i].PackerInfo.usedRectangles.count) do
+ begin
+ if Info[i].PackerInfo.usedRectangles.data[j].UserData = tex then
+ writeln(' found in atlas ', i, ' at slot ', j);
+ end;
+ end;
+ halt(-2);
+ end;
+end;
+
var
DumpID: Integer;
DumpFile: File of byte;
@@ -75,6 +110,57 @@
IntToStrPad:=s;
end;
+// GL1 ATLAS DEBUG ONLY CODE!
+procedure DebugAtlas;
+var
+ vp: array[0..3] of GLint;
+ prog: GLint;
+ i: Integer;
+ x, y: Integer;
+const
+ SZ = 512;
+begin
+ x:= 0;
+ y:= 0;
+ for i:= 0 to pred(MaxAtlases) do
+ begin
+ if not Info[i].allocated then
+ continue;
+ glGetIntegerv(GL_VIEWPORT, @vp);
+ glGetIntegerv(GL_CURRENT_PROGRAM, @prog);
+
+ glUseProgram(0);
+ glPushMatrix;
+ glLoadIdentity;
+ glOrtho(0, vp[2], vp[3], 0, -1, 1);
+
+
+ glBindTexture(GL_TEXTURE_2D, Info[i].TextureInfo.id);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0, 0.0);
+ glVertex2i(x * SZ, y * SZ);
+ glTexCoord2f(1.0, 0.0);
+ glVertex2i((x + 1) * SZ, y * SZ);
+ glTexCoord2f(1.0, 1.0);
+ glVertex2i((x + 1) * SZ, (y + 1) * SZ);
+ glTexCoord2f(0.0, 1.0);
+ glVertex2i(x * SZ, (y + 1) * SZ);
+ glEnd();
+
+ glPopMatrix;
+
+ inc(x);
+ if (x = 2) then
+ begin
+ x:=0;
+ inc(y);
+ end;
+
+
+ glUseProgram(prog);
+ end;
+end;
+
procedure DumpAtlas(var info: AtlasInfo);
var
png: png_structp;
@@ -147,6 +233,9 @@
glGenTextures(1, @createTexture.id);
glBindTexture(GL_TEXTURE_2D, createTexture.id);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
GetMem(NullTex, width * height * 4);
@@ -275,6 +364,7 @@
sp: PTexture;
i, j, stride: Integer;
scanline: PByte;
+ r: TSDL_Rect;
begin
writeln('Uploading sprite to ', sprite.x, ',', sprite.y, ',', sprite.width, ',', sprite.height);
sp:= PTexture(sprite.UserData);
@@ -288,7 +378,7 @@
//if GrayScale then
// Surface2GrayScale(surf);
- DebugColorize(surf);
+ //DebugColorize(surf);
glBindTexture(GL_TEXTURE_2D, info.TextureInfo.id);
if (sp^.isRotated) then
@@ -306,9 +396,15 @@
if SDL_MustLock(surf) then
SDL_UnlockSurface(surf);
+
+ r.x:= 0;
+ r.y:= 0;
+ r.w:= sp^.w;
+ r.h:= sp^.h;
+ ComputeTexcoords(sp, @r, @sp^.tb);
end;
-procedure Repack(var info: AtlasInfo; newAtlas: Atlas; newSprite: PTexture; surf: PSDL_Surface);
+procedure Repack(var info: AtlasInfo; newAtlas: Atlas);
var
base: PByte;
oldSize: Integer;
@@ -373,8 +469,7 @@
////////////////////////////////////////////////////////////////////////////////
// Sprite allocation logic
-function TryRepack(var info: AtlasInfo; w, h: Integer; hasNewSprite: boolean;
- newSprite: Size; surf: PSDL_Surface): boolean;
+function TryRepack(var info: AtlasInfo; w, h: Integer; hasNewSprite: boolean; newSprite: Size): boolean;
var
sizes: SizeList;
repackedAtlas: Atlas;
@@ -402,16 +497,12 @@
if atlasInsertSet(repackedAtlas, sizes, rects) then
begin
TryRepack:= true;
- if hasNewSprite then
- sprite:= PTexture(newSprite.UserData)
- else
- sprite:= nil;
- Repack(info, repackedAtlas, sprite, surf);
+ Repack(info, repackedAtlas);
// repack assigns repackedAtlas to the current info and deletes the old one
// thus we wont do atlasDelete(repackedAtlas); here
rectangleListClear(rects);
sizeListClear(sizes);
- DumpAtlas(info);
+ //DumpAtlas(info);
exit;
end;
@@ -431,7 +522,7 @@
begin
// we succeeded adaptivley allocating the sprite to the i'th atlas.
Upload(info, rect, surf);
- DumpAtlas(info);
+ //DumpAtlas(info);
TryInsert:= true;
end;
end;
@@ -460,6 +551,7 @@
sprite^.y:= 0;
sprite^.isRotated:= false;
sprite^.surface:= surf;
+ sprite^.shared:= true;
sz:= SizeForSprite(sprite);
@@ -470,7 +562,7 @@
if not Info[i].Allocated then
continue;
if TryInsert(Info[i], sz, surf) then
- exit;
+ exit;
end;
@@ -481,7 +573,7 @@
if not Info[i].Allocated then
continue;
- if TryRepack(Info[i], Info[i].PackerInfo.width, Info[i].PackerInfo.height, true, sz, surf) then
+ if TryRepack(Info[i], Info[i].PackerInfo.width, Info[i].PackerInfo.height, true, sz) then
exit;
end;
@@ -498,7 +590,7 @@
EnlargeSize(currentWidth, currentHeight);
while (currentWidth <= MaxTexSize) and (currentHeight <= MaxTexSize) do
begin
- if TryRepack(Info[i], currentWidth, currentHeight, true, sz, surf) then
+ if TryRepack(Info[i], currentWidth, currentHeight, true, sz) then
exit;
EnlargeSize(currentWidth, currentHeight);
end;
@@ -555,6 +647,7 @@
if sprite = nil then
exit;
+ deleteAt:= -1;
for i:= 0 to pred(MaxAtlases) do
begin
if sprite^.atlas <> @Info[i].TextureInfo then
@@ -570,7 +663,7 @@
inc(usedArea, r.width * r.height);
end;
- rectangleListRemoveAt(Info[i].PackerInfo.usedRectangles, j);
+ rectangleListRemoveAt(Info[i].PackerInfo.usedRectangles, deleteAt);
dispose(sprite);
while true do
@@ -586,8 +679,10 @@
CompactSize(atlasW, atlasH);
unused:= unused;
- TryRepack(Info[i], atlasW, atlasH, false, unused, nil);
+ TryRepack(Info[i], atlasW, atlasH, false, unused);
end;
+
+ exit;
end;
end;
--- a/hedgewars/uTextures.pas Mon Jun 25 12:02:54 2012 +0200
+++ b/hedgewars/uTextures.pas Mon Jun 25 15:46:08 2012 +0200
@@ -49,12 +49,13 @@
end;
procedure ComputeTexcoords(texture: PTexture; r: PSDL_Rect; tb: PVertexRect);
-var x0, y0, x1, y1: Real;
+var x0, y0, x1, y1, tmp: Real;
w, h, aw, ah: LongInt;
const texelOffset = 0.0;
begin
aw:=texture^.atlas^.w;
ah:=texture^.atlas^.h;
+
if texture^.isRotated then
begin
w:=r^.h;
@@ -66,19 +67,32 @@
h:=r^.h;
end;
-x0:= (r^.x + texelOffset)/aw;
-x1:= (r^.x + w - texelOffset)/aw;
-y0:= (r^.y + texelOffset)/ah;
-y1:= (r^.y + h - texelOffset)/ah;
+x0:= (texture^.x + r^.x + texelOffset)/aw;
+x1:= (texture^.x + r^.x + w - texelOffset)/aw;
+y0:= (texture^.y + r^.y + texelOffset)/ah;
+y1:= (texture^.y + r^.y + h - texelOffset)/ah;
-tb^[0].X:= x0;
-tb^[0].Y:= y0;
-tb^[1].X:= x1;
-tb^[1].Y:= y0;
-tb^[2].X:= x1;
-tb^[2].Y:= y1;
-tb^[3].X:= x0;
-tb^[3].Y:= y1
+if (texture^.isRotated) then
+begin
+ tb^[0].X:= x0;
+ tb^[0].Y:= y0;
+ tb^[3].X:= x1;
+ tb^[3].Y:= y0;
+ tb^[2].X:= x1;
+ tb^[2].Y:= y1;
+ tb^[1].X:= x0;
+ tb^[1].Y:= y1
+end else
+begin
+ tb^[0].X:= x0;
+ tb^[0].Y:= y0;
+ tb^[1].X:= x1;
+ tb^[1].Y:= y0;
+ tb^[2].X:= x1;
+ tb^[2].Y:= y1;
+ tb^[3].X:= x0;
+ tb^[3].Y:= y1;
+end;
end;
procedure ResetVertexArrays(texture: PTexture);
@@ -126,6 +140,8 @@
NewTexture^.w:=width;
NewTexture^.h:=height;
NewTexture^.isRotated:=false;
+NewTexture^.shared:=false;
+NewTexture^.surface:=nil;
ResetVertexArrays(NewTexture);
@@ -164,8 +180,12 @@
tmpp: pointer;
fromP4, toP4: PLongWordArray;
begin
- if (surf^.w <= 128) and (surf^.h <= 128) then
- Surface2Tex_(surf, enableClamp); // run the atlas side by side for debugging
+ if (surf^.w <= 256) and (surf^.h <= 256) then
+ begin
+ Surface2Atlas:= Surface2Tex_(surf, enableClamp); // run the atlas side by side for debugging
+ ResetVertexArrays(Surface2Atlas);
+ exit;
+ end;
new(Surface2Atlas);
Surface2Atlas^.PrevTexture:= nil;
Surface2Atlas^.NextTexture:= nil;
@@ -185,6 +205,7 @@
Surface2Atlas^.y:=0;
Surface2Atlas^.isRotated:=false;
Surface2Atlas^.surface:= surf;
+Surface2Atlas^.shared:= false;
if (surf^.format^.BytesPerPixel <> 4) then
@@ -260,9 +281,15 @@
// if nil is passed nothing is done
procedure FreeTexture(tex: PTexture);
begin
- FreeTexture_(tex); // run atlas side by side for debugging
if tex <> nil then
begin
+ if tex^.shared then
+ begin
+ FreeTexture_(tex); // run atlas side by side for debugging
+ SDL_FreeSurface(tex^.surface);
+ exit;
+ end;
+
// Atlas cleanup happens here later on. For now we just free as each sprite has one atlas
Dispose(tex^.atlas);
@@ -274,7 +301,8 @@
TextureList:= tex^.NextTexture;
glDeleteTextures(1, @tex^.atlas^.id);
- SDL_FreeSurface(tex^.surface);
+ if (tex^.surface <> nil) then
+ SDL_FreeSurface(tex^.surface);
Dispose(tex);
end
end;