widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #05200
Re: [Merge] lp:~widelands-dev/widelands/full_texture_atlas into lp:widelands
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.
References