Automate texture listing for texture atlas making

This commit is contained in:
Perttu Ahola 2011-10-18 11:31:23 +03:00
parent eae2d35ca5
commit 05ab58cd14
5 changed files with 81 additions and 44 deletions

@ -117,6 +117,7 @@ void content_mapnode_init()
f->setInventoryTextureCube("stone.png", "stone.png", "stone.png"); f->setInventoryTextureCube("stone.png", "stone.png", "stone.png");
f->param_type = CPT_MINERAL; f->param_type = CPT_MINERAL;
f->is_ground_content = true; f->is_ground_content = true;
f->often_contains_mineral = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 1"; f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 1.0); setStoneLikeDiggingProperties(f->digging_properties, 1.0);
if(invisible_stone) if(invisible_stone)

@ -1278,6 +1278,9 @@ int main(int argc, char *argv[])
// Initial call with g_texturesource not set. // Initial call with g_texturesource not set.
init_mapnode(); init_mapnode();
// Must be called before g_texturesource is created
// (for texture atlas making)
init_mineral();
/* /*
Run unit tests Run unit tests
@ -1475,7 +1478,6 @@ int main(int argc, char *argv[])
*/ */
init_mapnode(); // Second call with g_texturesource set init_mapnode(); // Second call with g_texturesource set
init_mineral();
/* /*
GUI stuff GUI stuff

@ -42,6 +42,8 @@ ContentFeatures::~ContentFeatures()
#ifndef SERVER #ifndef SERVER
void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha) void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha)
{ {
used_texturenames[name] = true;
if(g_texturesource) if(g_texturesource)
{ {
tiles[i].texture = g_texturesource->getTexture(name); tiles[i].texture = g_texturesource->getTexture(name);

@ -103,6 +103,9 @@ class NodeMetadata;
struct ContentFeatures struct ContentFeatures
{ {
#ifndef SERVER #ifndef SERVER
// List of all block textures that have been used (value is dummy)
core::map<std::string, bool> used_texturenames;
/* /*
0: up 0: up
1: down 1: down
@ -151,6 +154,10 @@ struct ContentFeatures
// If true, node is equivalent to air. Torches are, air is. Water is not. // If true, node is equivalent to air. Torches are, air is. Water is not.
// Is used for example to check whether a mud block can have grass on. // Is used for example to check whether a mud block can have grass on.
bool air_equivalent; bool air_equivalent;
// Whether this content type often contains mineral.
// Used for texture atlas creation.
// Currently only enabled for CONTENT_STONE.
bool often_contains_mineral;
// Inventory item string as which the node appears in inventory when dug. // Inventory item string as which the node appears in inventory when dug.
// Mineral overrides this. // Mineral overrides this.
@ -207,6 +214,7 @@ struct ContentFeatures
liquid_type = LIQUID_NONE; liquid_type = LIQUID_NONE;
wall_mounted = false; wall_mounted = false;
air_equivalent = false; air_equivalent = false;
often_contains_mineral = false;
dug_item = ""; dug_item = "";
initial_metadata = NULL; initial_metadata = NULL;
liquid_alternative_flowing = CONTENT_IGNORE; liquid_alternative_flowing = CONTENT_IGNORE;

@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h" #include "settings.h"
#include <ICameraSceneNode.h> #include <ICameraSceneNode.h>
#include "log.h" #include "log.h"
#include "mapnode.h" // For texture atlas making
#include "mineral.h" // For texture atlas making
/* /*
A cache from texture name to texture path A cache from texture name to texture path
@ -507,52 +509,62 @@ void TextureSource::buildMainAtlas()
} }
/* /*
A list of stuff to include in the texture atlas. Grab list of stuff to include in the texture atlas from the
main content features
It is a single-dimensional texture atlas due to the need to tile
textures.
It should contain as much of the stuff shown in game as possible,
to minimize texture changes.
It fills up quickly, so do not add anything that isn't contained
in most MapBlocks. E.g. mese isn't suitable but stone is.
*/ */
core::array<std::string> sourcelist; core::map<std::string, bool> sourcelist;
sourcelist.push_back("stone.png"); for(u16 j=0; j<MAX_CONTENT+1; j++)
sourcelist.push_back("mud.png"); {
sourcelist.push_back("sand.png"); if(j == CONTENT_IGNORE || j == CONTENT_AIR)
sourcelist.push_back("grass.png"); continue;
sourcelist.push_back("grass_footsteps.png"); ContentFeatures *f = &content_features(j);
sourcelist.push_back("tree.png"); for(core::map<std::string, bool>::Iterator
sourcelist.push_back("tree_top.png"); i = f->used_texturenames.getIterator();
sourcelist.push_back("water.png"); i.atEnd() == false; i++)
sourcelist.push_back("leaves.png"); {
sourcelist.push_back("glass.png"); std::string name = i.getNode()->getKey();
sourcelist.push_back("mud.png^grass_side.png"); sourcelist[name] = true;
sourcelist.push_back("cobble.png");
sourcelist.push_back("mossycobble.png");
sourcelist.push_back("gravel.png");
sourcelist.push_back("jungletree.png");
sourcelist.push_back("stone.png^mineral_coal.png"); if(f->often_contains_mineral){
sourcelist.push_back("stone.png^mineral_iron.png"); for(int k=1; k<MINERAL_COUNT; k++){
std::string mineraltexture = mineral_block_texture(k);
std::string fulltexture = name + "^" + mineraltexture;
sourcelist[fulltexture] = true;
}
}
}
}
infostream<<"Creating texture atlas out of textures: ";
for(core::map<std::string, bool>::Iterator
i = sourcelist.getIterator();
i.atEnd() == false; i++)
{
std::string name = i.getNode()->getKey();
infostream<<"\""<<name<<"\" ";
}
infostream<<std::endl;
// Padding to disallow texture bleeding // Padding to disallow texture bleeding
s32 padding = 16; s32 padding = 16;
s32 column_width = 256;
s32 column_padding = 16;
/* /*
First pass: generate almost everything First pass: generate almost everything
*/ */
core::position2d<s32> pos_in_atlas(0,0); core::position2d<s32> pos_in_atlas(0,0);
pos_in_atlas.Y += padding; pos_in_atlas.Y = padding;
for(u32 i=0; i<sourcelist.size(); i++) for(core::map<std::string, bool>::Iterator
i = sourcelist.getIterator();
i.atEnd() == false; i++)
{ {
std::string name = sourcelist[i]; std::string name = i.getNode()->getKey();
/*video::IImage *img = driver->createImageFromFile( /*video::IImage *img = driver->createImageFromFile(
getTexturePath(name.c_str()).c_str()); getTexturePath(name.c_str()).c_str());
@ -586,20 +598,26 @@ void TextureSource::buildMainAtlas()
continue; continue;
} }
// Stop making atlas if atlas is full // Wrap columns and stop making atlas if atlas is full
if(pos_in_atlas.Y + dim.Height > atlas_dim.Height) if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
{ {
infostream<<"TextureSource::buildMainAtlas(): " if(pos_in_atlas.X > (s32)atlas_dim.Width - 256 - padding){
errorstream<<"TextureSource::buildMainAtlas(): "
<<"Atlas is full, not adding more textures." <<"Atlas is full, not adding more textures."
<<std::endl; <<std::endl;
break; break;
} }
pos_in_atlas.Y = padding;
pos_in_atlas.X += column_width + column_padding;
}
infostream<<"TextureSource::buildMainAtlas(): Adding \""<<name infostream<<"TextureSource::buildMainAtlas(): Adding \""<<name
<<"\" to texture atlas"<<std::endl; <<"\" to texture atlas"<<std::endl;
// Tile it a few times in the X direction // Tile it a few times in the X direction
u16 xwise_tiling = 16; u16 xwise_tiling = column_width / dim.Width;
if(xwise_tiling > 16) // Limit to 16 (more gives no benefit)
xwise_tiling = 16;
for(u32 j=0; j<xwise_tiling; j++) for(u32 j=0; j<xwise_tiling; j++)
{ {
// Copy the copy to the atlas // Copy the copy to the atlas
@ -627,7 +645,7 @@ void TextureSource::buildMainAtlas()
dst_y = -y0 + pos_in_atlas.Y-1; dst_y = -y0 + pos_in_atlas.Y-1;
src_y = pos_in_atlas.Y; src_y = pos_in_atlas.Y;
} }
s32 x = x0 + pos_in_atlas.X * dim.Width; s32 x = x0 + pos_in_atlas.X;
video::SColor c = atlas_img->getPixel(x, src_y); video::SColor c = atlas_img->getPixel(x, src_y);
atlas_img->setPixel(x,dst_y,c); atlas_img->setPixel(x,dst_y,c);
} }
@ -668,9 +686,11 @@ void TextureSource::buildMainAtlas()
/* /*
Second pass: set texture pointer in generated AtlasPointers Second pass: set texture pointer in generated AtlasPointers
*/ */
for(u32 i=0; i<sourcelist.size(); i++) for(core::map<std::string, bool>::Iterator
i = sourcelist.getIterator();
i.atEnd() == false; i++)
{ {
std::string name = sourcelist[i]; std::string name = i.getNode()->getKey();
if(m_name_to_id.find(name) == NULL) if(m_name_to_id.find(name) == NULL)
continue; continue;
u32 id = m_name_to_id[name]; u32 id = m_name_to_id[name];
@ -681,8 +701,12 @@ void TextureSource::buildMainAtlas()
/* /*
Write image to file so that it can be inspected Write image to file so that it can be inspected
*/ */
/*driver->writeImageToFile(atlas_img, /*std::string atlaspath = porting::path_userdata
getTexturePath("main_atlas.png").c_str());*/ + DIR_DELIM + "generated_texture_atlas.png";
infostream<<"Removing and writing texture atlas for inspection to "
<<atlaspath<<std::endl;
fs::RecursiveDelete(atlaspath);
driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
} }
video::IImage* generate_image_from_scratch(std::string name, video::IImage* generate_image_from_scratch(std::string name,