Review: Approve

Some small nits, otherwise LGTM

Diff comments:

> 
> === modified file 'src/graphic/make_texture_atlas_main.cc'
> --- src/graphic/make_texture_atlas_main.cc    2016-01-04 20:54:08 +0000
> +++ src/graphic/make_texture_atlas_main.cc    2016-01-07 22:08:20 +0000
> @@ -62,11 +88,121 @@
>       g_gr = new Graphic(1, 1, false);
>  }
>  
> +// Returns true if 'filename' is ends with a image extension.

Typos:

// Returns true if 'filename' ends with an image extension.

> +bool is_image(const std::string& filename) {
> +     return boost::ends_with(filename, ".png") || boost::ends_with(filename, 
> ".jpg");
> +}
> +
> +// Recursively adds all images in 'directory' to 'ordered_images' and
> +// 'handled_images' for which 'predicate' returns true. We keep track of the
> +// images twice because we want to make sure that some end up in the same
> +// (first) texture atlas, so we add them first and we use the set to know 
> that
> +// we already added an image.
> +void find_images(const std::string& directory,
> +                 std::unordered_set<std::string>* images,
> +                 std::vector<std::string>* ordered_images) {
> +     for (const std::string& filename : g_fs->list_directory(directory)) {
> +             if (g_fs->is_directory(filename)) {
> +                     find_images(filename, images, ordered_images);
> +                     continue;
> +             }
> +             if (is_image(filename) && !images->count(filename)) {
> +                     images->insert(filename);
> +                     ordered_images->push_back(filename);
> +             }
> +     }
> +}
> +
> +void dump_result(const std::map<std::string, PackInfo>& pack_info,
> +                 std::vector<std::unique_ptr<Texture>>* texture_atlases,
> +                 FileSystem* fs) {
> +
> +     for (size_t i = 0; i < texture_atlases->size(); ++i) {
> +             std::unique_ptr<StreamWrite> sw(
> +                fs->open_stream_write((boost::format("output_%02i.png") % 
> i).str()));
> +             save_to_png(texture_atlases->at(i).get(), sw.get(), 
> ColorType::RGBA);
> +     }
> +
> +     {
> +             std::unique_ptr<StreamWrite> 
> sw(fs->open_stream_write("output.lua"));
> +             sw->text("return {\n");
> +             for (const auto& pair : pack_info) {
> +                     sw->text("   [\"");
> +                     sw->text(pair.first);
> +                     sw->text("\"] = {\n");
> +
> +                     switch (pair.second.type) {
> +                     case PackInfo::Type::kPacked:
> +                             sw->text("       type = \"packed\",\n");
> +                             sw->text(
> +                                (boost::format("       texture_atlas = 
> %d,\n") % pair.second.texture_atlas).str());
> +                             sw->text((boost::format("       rect = { %d, 
> %d, %d, %d },\n") % pair.second.rect.x %
> +                                       pair.second.rect.y % 
> pair.second.rect.w % pair.second.rect.h).str());
> +                             break;
> +
> +                     case PackInfo::Type::kUnpacked:
> +                             sw->text("       type = \"unpacked\",\n");
> +                             break;
> +                     }
> +                     sw->text("   },\n");
> +             }
> +             sw->text("}\n");
> +     }
> +}
> +
> +// Pack the images in 'filenames' into texture atlases.
> +std::vector<std::unique_ptr<Texture>> pack_images(const 
> std::vector<std::string>& filenames,
> +                                                  const int max_size,
> +                                                  std::map<std::string, 
> PackInfo>* pack_info,
> +                                                  Texture* first_texture,
> +                                                                             
>                                                   
> TextureAtlas::PackedTexture* first_atlas_packed_texture) {
> +     std::vector<std::pair<std::string, std::unique_ptr<Texture>>> 
> to_be_packed;
> +     for (const auto& filename : filenames) {
> +             std::unique_ptr<Texture> image = load_image(filename, g_fs);
> +             const auto area = image->width() * image->height();
> +             if (area < kMaxAreaForTextureAtlas) {
> +                     to_be_packed.push_back(std::make_pair(filename, 
> std::move(image)));
> +             } else {
> +                     pack_info->insert(std::make_pair(filename, PackInfo{
> +                                                                   
> PackInfo::Type::kUnpacked, 0, Rect(),
> +                                                                }));
> +             }
> +     }
> +
> +     TextureAtlas atlas;
> +     int packed_texture_index = 0;
> +     if (first_texture != nullptr) {
> +             atlas.add(*first_texture);
> +             packed_texture_index = 1;
> +     }
> +     for (auto& pair : to_be_packed) {
> +             atlas.add(*pair.second);
> +     }
> +
> +     std::vector<std::unique_ptr<Texture>> texture_atlases;
> +     std::vector<TextureAtlas::PackedTexture> packed_textures;
> +     atlas.pack(max_size, &texture_atlases, &packed_textures);
> +
> +     if (first_texture != nullptr) {
> +             assert(first_atlas_packed_texture != nullptr);
> +             *first_atlas_packed_texture = std::move(packed_textures[0]);
> +     }
> +
> +     for (size_t i = 0; i < to_be_packed.size(); ++i) {
> +             const auto& packed_texture = 
> packed_textures.at(packed_texture_index++);
> +             pack_info->insert(
> +                std::make_pair(to_be_packed[i].first, 
> PackInfo{PackInfo::Type::kPacked,
> +                                                               
> packed_texture.texture_atlas,
> +                                                               
> packed_texture.texture->blit_data().rect}));
> +     }
> +     return texture_atlases;
> +}
> +
>  }  // namespace
>  
>  int main(int argc, char** argv) {
> -     std::string input_directory;
> -     if (parse_arguments(argc, argv, &input_directory))
> +     int max_size;
> +     if (parse_arguments(argc, argv, &max_size))
>               return 1;
>  
>       if (SDL_Init(SDL_INIT_VIDEO) < 0) {
> @@ -75,26 +211,64 @@
>       }
>       initialize();
>  
> -     std::vector<std::unique_ptr<Texture>> images;
> -     std::unique_ptr<FileSystem> 
> input_fs(&FileSystem::create(input_directory));
> -     std::vector<std::string> png_filenames;
> -     for (const std::string& filename : input_fs->list_directory("")) {
> -             if (boost::ends_with(filename, ".png")) {
> -                     png_filenames.push_back(filename);
> -                     images.emplace_back(load_image(filename, 
> input_fs.get()));
> -             }
> -     }
> -
> -     TextureAtlas atlas;
> -     for (auto& image : images) {
> -             atlas.add(*image);
> -     }
> -     std::vector<std::unique_ptr<Texture>> new_textures;
> -     auto packed_texture = atlas.pack(&new_textures);
> +
> +     // For performance reasons, we need to have some images in the first 
> texture
> +     // atlas, so that OpenGL texture switches do not happen during (for 
> example)
> +     // terrain or road rendering. To ensure this, we separate all images 
> into
> +     // two disjunct sets. We than pack all images that should go into the 
> first
> +     // texture atlas into a texture atlas. Than, we pack all remaining 
> textures

Typo: Than -> Then

> +     // into a texture atlas, but including the first texture atlas as a 
> singular
> +     // image (which will probaby be the biggest we allow).

Typo: probaby -> probably

> +     //
> +     // We have to adjust the sub rectangle rendering for the images in the 
> first
> +     // texture atlas in 'pack_info' later, before dumping the results.
> +     std::vector<std::string> other_images, 
> images_that_must_be_in_first_atlas;
> +     std::unordered_set<std::string> all_images;
> +
> +     // For terrain textures.
> +     find_images("world/terrains", &all_images, 
> &images_that_must_be_in_first_atlas);
> +     // For flags and roads.
> +     find_images("tribes/images", &all_images, 
> &images_that_must_be_in_first_atlas);
> +     // For UI elements mostly, but we get more than we need really.
> +     find_images("pics", &all_images, &images_that_must_be_in_first_atlas);
> +
> +     // Add all other images, we do not really cares about the order for 
> these.
> +     find_images("pics", &all_images, &other_images);

Haven't these already been loaded in the previous line?

> +     find_images("world", &all_images, &other_images);
> +     find_images("tribes", &all_images, &other_images);
> +     assert(images_that_must_be_in_first_atlas.size() + other_images.size() 
> == all_images.size());
> +
> +     std::map<std::string, PackInfo> first_texture_atlas_pack_info;
> +     auto first_texture_atlas = 
> pack_images(images_that_must_be_in_first_atlas, max_size,
> +                                            &first_texture_atlas_pack_info, 
> nullptr, nullptr);
> +     if (first_texture_atlas.size() != 1) {
> +             std::cout << "Not all images that should fit in the first 
> texture atlas did actually fit."
> +                       << std::endl;
> +             return 1;
> +     }
> +
> +     std::map<std::string, PackInfo> pack_info;
> +     TextureAtlas::PackedTexture first_atlas_packed_texture;
> +     auto texture_atlases = pack_images(other_images, max_size, &pack_info,
> +                                        first_texture_atlas[0].get(), 
> &first_atlas_packed_texture);
> +
> +     const auto& blit_data = first_atlas_packed_texture.texture->blit_data();
> +     for (const auto& pair : first_texture_atlas_pack_info) {
> +             assert(pack_info.count(pair.first) == 0);
> +             pack_info.insert(std::make_pair(pair.first, PackInfo{
> +                                                            pair.second.type,
> +                                                            
> first_atlas_packed_texture.texture_atlas,
> +                                                            
> Rect(blit_data.rect.x + pair.second.rect.x,
> +                                                                 
> blit_data.rect.y + pair.second.rect.y,
> +                                                                 
> pair.second.rect.w, pair.second.rect.h),
> +                                                         }));
> +     }
> +
> +     // Make sure we have all images.
> +     assert(all_images.size() == pack_info.size());
>  
>       std::unique_ptr<FileSystem> output_fs(&FileSystem::create("."));
> -     std::unique_ptr<StreamWrite> 
> sw(output_fs->open_stream_write("output.png"));
> -     save_to_png(packed_texture.get(), sw.get(), ColorType::RGBA);
> +     dump_result(pack_info, &texture_atlases, output_fs.get());
>  
>       SDL_Quit();
>       return 0;


-- 
https://code.launchpad.net/~widelands-dev/widelands/full_texture_atlas/+merge/281909
Your team Widelands Developers is subscribed to branch 
lp:~widelands-dev/widelands/full_texture_atlas.

_______________________________________________
Mailing list: https://launchpad.net/~widelands-dev
Post to     : widelands-dev@lists.launchpad.net
Unsubscribe : https://launchpad.net/~widelands-dev
More help   : https://help.launchpad.net/ListHelp

Reply via email to