# HG changeset patch # User Wolfgang Steffens # Date 1340631968 -7200 # Node ID af64b509725cfbac7ad87116b7b052594915bf6b # Parent e70b81854fb9e4c7bc1d0f3f57401dcd39fe86d0 using atlas for rendering now diff -r e70b81854fb9 -r af64b509725c hedgewars/uAtlas.pas --- 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; diff -r e70b81854fb9 -r af64b509725c hedgewars/uStore.pas --- a/hedgewars/uStore.pas Mon Jun 25 12:02:54 2012 +0200 +++ b/hedgewars/uStore.pas Mon Jun 25 15:46:08 2012 +0200 @@ -475,7 +475,7 @@ SpritesData[ii].Texture:= nil; if (SpritesData[ii].Surface <> nil) and (not reload) then begin - SDL_FreeSurface(SpritesData[ii].Surface); + //SDL_FreeSurface(SpritesData[ii].Surface); released by FreeTexture SpritesData[ii].Surface:= nil end end; diff -r e70b81854fb9 -r af64b509725c hedgewars/uTextures.pas --- 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; diff -r e70b81854fb9 -r af64b509725c hedgewars/uTypes.pas --- a/hedgewars/uTypes.pas Mon Jun 25 12:02:54 2012 +0200 +++ b/hedgewars/uTypes.pas Mon Jun 25 15:46:08 2012 +0200 @@ -221,6 +221,8 @@ x, y: LongInt; // Offset in the texture atlas isRotated: boolean; // if true sprite is flipped in the atlas taking w pixels along the y and h pixels along the x axis + shared: boolean; // true if in an atlas, false if atlas points to a dedicated texture for this sprite + surface: PSDL_Surface; // retained in memory surface // Cached values for texel coordinates and vertex coordinates diff -r e70b81854fb9 -r af64b509725c hedgewars/uWorld.pas --- a/hedgewars/uWorld.pas Mon Jun 25 12:02:54 2012 +0200 +++ b/hedgewars/uWorld.pas Mon Jun 25 15:46:08 2012 +0200 @@ -60,7 +60,8 @@ uCaptions, uCursor, uCommands, - uMobile + uMobile, + uAtlas ; var cWaveWidth, cWaveHeight: LongInt; @@ -956,7 +957,7 @@ begin glClear(GL_COLOR_BUFFER_BIT); DrawWorldStereo(Lag, rmDefault) - end + end; {$IFNDEF S3D_DISABLED} else if (cStereoMode = smAFR) then begin @@ -1064,8 +1065,9 @@ else glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE); DrawWorldStereo(Lag, rmRightEye); - end + end; {$ENDIF} + DebugAtlas; end; procedure ChangeDepth(rm: TRenderMode; d: GLfloat);