Skip to content

Commit

Permalink
atlas: finally settled on an xml schema
Browse files Browse the repository at this point in the history
This is the format that TexturePacker (texturepacker.com) uses, which includes
many options like rotation, trimming, resizing, heuristic masks, etc. Sadly it
is non-free so we will have to rewrite the features.

This allows us to solve the chicken/egg problem by putting off writing our own
packer until we've settled on an unpacking feature-set.

In its most basic form, the format looks like this:

<TextureAtlas imagePath="TextureAtlas-2048-0.png" width="2048" height="2048">
    <sprite n="ArrowDown.png" x="484" y="2032" w="16" h="16" />
    <sprite n="ArrowUp.png" x="2031" y="496" w="16" h="16" />
    ...
</TextureAtlas>
  • Loading branch information
theuni committed May 22, 2012
1 parent e643429 commit 467ec0b
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 66 deletions.
63 changes: 20 additions & 43 deletions tools/atlas/texture-atlas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,40 +228,16 @@ void CImageTree::AddIndex(TiXmlElement *root, std::string filename)
CImageNode *node = (*i).second;
if(!node)
continue;

CRect rect = node->Rect();

TiXmlElement * texture = new TiXmlElement("texture");
TiXmlElement * texture = new TiXmlElement("sprite");
root->LinkEndChild(texture);

msg = new TiXmlElement("texturename");
msg->LinkEndChild( new TiXmlText(name.substr(name.find_last_of('/') +1).c_str()));
texture->LinkEndChild(msg);

sprintf(elementvalue,"%i",(int)rect.x1);
msg = new TiXmlElement("x");
msg->LinkEndChild( new TiXmlText(elementvalue));
texture->LinkEndChild(msg);

sprintf(elementvalue,"%i",(int)(rect.y1));
msg = new TiXmlElement("y");
msg->LinkEndChild( new TiXmlText(elementvalue));
texture->LinkEndChild(msg);

sprintf(elementvalue,"%i",(int)(int)(rect.x2 - rect.x1));
msg = new TiXmlElement("width");
msg->LinkEndChild( new TiXmlText(elementvalue));
texture->LinkEndChild(msg);

sprintf(elementvalue,"%i",(int)(rect.y2 - rect.y1));
msg = new TiXmlElement("height");
msg->LinkEndChild( new TiXmlText(elementvalue));
texture->LinkEndChild(msg);

sprintf(elementvalue,"%i",(int)0);
msg = new TiXmlElement("rotated");
msg->LinkEndChild( new TiXmlText(elementvalue));
texture->LinkEndChild(msg);
texture->SetAttribute("n",name.substr(name.find_last_of('/') +1).c_str());
texture->SetAttribute("x",rect.x1);
texture->SetAttribute("y",rect.y1);
texture->SetAttribute("w",rect.x2 - rect.x1);
texture->SetAttribute("h",rect.y2 - rect.y1);
}
}

Expand Down Expand Up @@ -323,7 +299,7 @@ std::vector<std::string> GetFiles(const std::string & path, std::vector<std::str
int n;
struct stat st;
std::string src_dir_name = ( path[ path.length() - 1 ] != '/' ) ? path + "/" : path;
std::string prefix("media-2048-");
std::string prefix("TextureAtlas-");

n = scandir( src_dir_name.c_str(), &list, 0, alphasort );
if ( n < 1 )
Expand Down Expand Up @@ -355,11 +331,10 @@ std::vector<std::string> GetFiles(const std::string & path, std::vector<std::str
return files;
}

#define ATLAS_WIDTH 2048
#define ATLAS_HEIGHT 2048

int main(int argc, char *argv[])
{
int atlas_width = 2048;
int atlas_height = 2048;
std::vector<std::string> files;
TiXmlDocument doc;

Expand All @@ -380,7 +355,7 @@ int main(int argc, char *argv[])

std::list<CImageTree *> m_imageTree;

CImageTree *imageTree = new CImageTree(ATLAS_WIDTH, ATLAS_HEIGHT);
CImageTree *imageTree = new CImageTree(atlas_width, atlas_height);

m_imageTree.push_back(imageTree);

Expand Down Expand Up @@ -422,7 +397,7 @@ int main(int argc, char *argv[])
CImage *image = (*iimage);

// image does not fit in map at all
if(image->GetWidth() > ATLAS_WIDTH || image->GetHeight() > ATLAS_HEIGHT)
if(image->GetWidth() > atlas_width || image->GetHeight() > atlas_height)
{
printf("Image : %s too big\n", image->GetFileName().c_str());
continue;
Expand All @@ -442,7 +417,7 @@ int main(int argc, char *argv[])
// start a new map if the image was not added to the existing map's
if(image != NULL)
{
CImageTree *imageTree = new CImageTree(ATLAS_WIDTH, ATLAS_HEIGHT);
CImageTree *imageTree = new CImageTree(atlas_width, atlas_height);
m_imageTree.push_back(imageTree);
if(!imageTree->Insert(image, 0))
printf("File : %s does not fit\n", image->GetFileName().c_str());
Expand All @@ -452,20 +427,22 @@ int main(int argc, char *argv[])
int count = 0;
TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
doc.LinkEndChild( decl );
TiXmlElement *root = new TiXmlElement("atlasmap");
doc.LinkEndChild(root);
std::string filename;
for( std::list<CImageTree *>::const_iterator itree = m_imageTree.begin(); itree != m_imageTree.end(); ++itree )
{
CImageTree *imageTree = (*itree);
std::stringstream ss;
ss << count;
filename = std::string(argv[1])+"/media-2048-" + ss.str() + ".png";
char *file = new char[1024];
snprintf(file,1024,"%s/TextureAtlas-%i-%s.png",argv[1],atlas_width,ss.str().c_str());
filename = file;
imageTree->SaveImage(filename);

TiXmlElement *msg = new TiXmlElement("atlas");
root->LinkEndChild(msg);
msg->SetAttribute("filename",filename.substr(filename.find_last_of('/') +1).c_str());
TiXmlElement *msg = new TiXmlElement("TextureAtlas");
doc.LinkEndChild(msg);
msg->SetAttribute("imagePath",filename.substr(filename.find_last_of('/') +1).c_str());
msg->SetAttribute("width",atlas_width);
msg->SetAttribute("height",atlas_height);

imageTree->AddIndex(msg, filename);
imageTree->Print();
Expand Down
48 changes: 30 additions & 18 deletions xbmc/guilib/AtlasReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ bool CAtlasReader::LoadXML(CStdString strFile)
{
TiXmlDocument xmlDoc;
CStdString strFileName;
int atlasWidth;
int atlasHeight;

if(!xmlDoc.LoadFile(strFile))
{
Expand All @@ -58,48 +60,58 @@ bool CAtlasReader::LoadXML(CStdString strFile)
TiXmlElement* pRootElement = xmlDoc.RootElement();

CStdString strValue = pRootElement->Value();
if (strValue != CStdString("atlasmap"))

if (strValue != CStdString("TextureAtlas"))
{
CLog::Log(LOGERROR, "atlasmap file doesnt start with <atlasmap>");
CLog::Log(LOGERROR, "atlasmap file doesn't start with <TextureAtlas>");
return false;
}

const TiXmlElement *pAtlas = pRootElement->FirstChildElement("atlas");
const TiXmlElement *pAtlas = pRootElement;
while (pAtlas)
{
pAtlas->QueryStringAttribute("filename",&strFileName);
const TiXmlElement *pChild = pAtlas->FirstChildElement("texture");
pAtlas->QueryStringAttribute("imagePath",&strFileName);
pAtlas->QueryIntAttribute("width",&atlasWidth);
pAtlas->QueryIntAttribute("height",&atlasHeight);
const TiXmlElement *pChild = pAtlas->FirstChildElement("sprite");
while (pChild)
{

int x = 0, y = 0, width = 0, height = 0;

int origx = 0, origy = 0, origwidth = 0, origheight = 0;
CStdString rotate="n";
CXBTFFile file;
CXBTFFrame frame;

CStdString strTextureName;
XMLUtils::GetString(pChild, "texturename", strTextureName);

XMLUtils::GetInt(pChild, "x", x);
XMLUtils::GetInt(pChild, "y", y);
XMLUtils::GetInt(pChild, "width", width);
XMLUtils::GetInt(pChild, "height", height);
pChild->QueryStringAttribute("n",&strTextureName);
pChild->QueryIntAttribute("x",&x);
pChild->QueryIntAttribute("y",&y);
pChild->QueryIntAttribute("w",&width);
pChild->QueryIntAttribute("h",&height);
pChild->QueryIntAttribute("oX",&origx);
pChild->QueryIntAttribute("oY",&origy);
pChild->QueryIntAttribute("oW",&origwidth);
pChild->QueryIntAttribute("oH",&origheight);
pChild->QueryStringAttribute("r",&rotate);

file.SetPath(strTextureName.ToLower());
file.SetAtlas(strFileName);
// the generator puts a border of 1 around the frame
frame.SetWidth(width - 2);
frame.SetHeight(height - 2);
frame.SetTextureXOffset(x + 1);
frame.SetTextureYOffset(y + 1);
frame.SetWidth(width-2);
frame.SetHeight(height-2);
frame.SetTextureXOffset(x+1);
frame.SetTextureYOffset(y+1);
frame.SetAtlasWidth(atlasWidth);
frame.SetAtlasHeight(atlasHeight);

file.GetFrames().push_back(frame);
m_atlas.GetFiles().push_back(file);
m_filesMap[file.GetPath()] = file;

pChild = pChild->NextSiblingElement("texture");
pChild = pChild->NextSiblingElement("sprite");
}
pAtlas = pAtlas->NextSiblingElement("atlas");
pAtlas = pAtlas->NextSiblingElement("TextureAtlas");
}

return true;
Expand Down
3 changes: 0 additions & 3 deletions xbmc/guilib/AtlasReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@
#include "XBTF.h"
#include "filesystem/File.h"

#define ATLAS_WIDTH 2048
#define ATLAS_HEIGHT 2048

class TiXmlDocument;

class CAtlasReader
Expand Down
4 changes: 2 additions & 2 deletions xbmc/guilib/TextureBundleAtlas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ bool CTextureBundleAtlas::LoadSubTexture(const CStdString& Filename, CTextureArr

ppTextureArray->m_width = frame.GetWidth();
ppTextureArray->m_height = frame.GetHeight();
ppTextureArray->m_texWidth = ATLAS_WIDTH;
ppTextureArray->m_texHeight = ATLAS_HEIGHT;
ppTextureArray->m_texWidth = frame.GetAtlasWidth();
ppTextureArray->m_texHeight = frame.GetAtlasHeight();
ppTextureArray->m_texXOffset = frame.GetTextureXOffset();
ppTextureArray->m_texYOffset = frame.GetTextureYOffset();

Expand Down

0 comments on commit 467ec0b

Please sign in to comment.