-
- 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
- s32 padding = 16;
-
- s32 column_width = 256;
- s32 column_padding = 16;
-
- /*
- First pass: generate almost everything
- */
- core::position2d<s32> pos_in_atlas(0,0);
-
- pos_in_atlas.Y = padding;
-
- for(core::map<std::string, bool>::Iterator
- i = sourcelist.getIterator();
- i.atEnd() == false; i++)
- {
- std::string name = i.getNode()->getKey();
-
- // Generate image by name
- video::IImage *img2 = generate_image_from_scratch(name, m_device,
- &m_sourcecache);
- if(img2 == NULL)
- {
- errorstream<<"TextureSource::buildMainAtlas(): "
- <<"Couldn't generate image \""<<name<<"\""<<std::endl;
- continue;
- }
-
- core::dimension2d<u32> dim = img2->getDimension();
-
- // Don't add to atlas if image is large
- core::dimension2d<u32> max_size_in_atlas(32,32);
- if(dim.Width > max_size_in_atlas.Width
- || dim.Height > max_size_in_atlas.Height)
- {
- infostream<<"TextureSource::buildMainAtlas(): Not adding "
- <<"\""<<name<<"\" because image is large"<<std::endl;
- continue;
- }
-
- // Wrap columns and stop making atlas if atlas is full
- if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
- {
- if(pos_in_atlas.X > (s32)atlas_dim.Width - 256 - padding){
- errorstream<<"TextureSource::buildMainAtlas(): "
- <<"Atlas is full, not adding more textures."
- <<std::endl;
- break;
- }
- pos_in_atlas.Y = padding;
- pos_in_atlas.X += column_width + column_padding;
- }
-
- /*infostream<<"TextureSource::buildMainAtlas(): Adding \""<<name
- <<"\" to texture atlas"<<std::endl;*/
-
- // Tile it a few times in the X direction
- 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++)
- {
- // Copy the copy to the atlas
- /*img2->copyToWithAlpha(atlas_img,
- pos_in_atlas + v2s32(j*dim.Width,0),
- core::rect<s32>(v2s32(0,0), dim),
- video::SColor(255,255,255,255),
- NULL);*/
- img2->copyTo(atlas_img,
- pos_in_atlas + v2s32(j*dim.Width,0),
- core::rect<s32>(v2s32(0,0), dim),
- NULL);
- }
-
- // Copy the borders a few times to disallow texture bleeding
- for(u32 side=0; side<2; side++) // top and bottom
- for(s32 y0=0; y0<padding; y0++)
- for(s32 x0=0; x0<(s32)xwise_tiling*(s32)dim.Width; x0++)
- {
- s32 dst_y;
- s32 src_y;
- if(side==0)
- {
- dst_y = y0 + pos_in_atlas.Y + dim.Height;
- src_y = pos_in_atlas.Y + dim.Height - 1;
- }
- else
- {
- dst_y = -y0 + pos_in_atlas.Y-1;
- src_y = pos_in_atlas.Y;
- }
- s32 x = x0 + pos_in_atlas.X;
- video::SColor c = atlas_img->getPixel(x, src_y);
- atlas_img->setPixel(x,dst_y,c);
- }
-
- img2->drop();
-
- /*
- Add texture to caches
- */
-
- bool reuse_old_id = false;
- u32 id = m_atlaspointer_cache.size();
- // Check old id without fetching a texture
- core::map<std::string, u32>::Node *n;
- n = m_name_to_id.find(name);
- // If it exists, we will replace the old definition
- if(n){
- id = n->getValue();
- reuse_old_id = true;
- /*infostream<<"TextureSource::buildMainAtlas(): "
- <<"Replacing old AtlasPointer"<<std::endl;*/
- }
-
- // Create AtlasPointer
- AtlasPointer ap(id);
- ap.atlas = NULL; // Set on the second pass
- ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
- (float)pos_in_atlas.Y/(float)atlas_dim.Height);
- ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
- (float)dim.Width/(float)atlas_dim.Height);
- ap.tiled = xwise_tiling;
-
- // Create SourceAtlasPointer and add to containers
- SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
- if(reuse_old_id)
- m_atlaspointer_cache[id] = nap;
- else
- m_atlaspointer_cache.push_back(nap);
- m_name_to_id[name] = id;
-
- // Increment position
- pos_in_atlas.Y += dim.Height + padding * 2;
- }
-
- /*
- Make texture
- */
- video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
- assert(t);