Path: blob/master/editor/import/editor_atlas_packer.cpp
9896 views
/**************************************************************************/1/* editor_atlas_packer.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "editor_atlas_packer.h"3132#include "core/math/geometry_2d.h"33#include "core/math/vector2.h"34#include "core/math/vector2i.h"35#include "scene/resources/bit_map.h"3637void EditorAtlasPacker::chart_pack(Vector<Chart> &charts, int &r_width, int &r_height, int p_atlas_max_size, int p_cell_resolution) {38int divide_by = MIN(64, p_cell_resolution);39Vector<PlottedBitmap> bitmaps;4041int max_w = 0;4243for (int i = 0; i < charts.size(); i++) {44const Chart &chart = charts[i];4546//generate aabb4748Rect2i aabb;49int vertex_count = chart.vertices.size();50const Vector2 *vertices = chart.vertices.ptr();5152for (int j = 0; j < vertex_count; j++) {53if (j == 0) {54aabb.position = vertices[j];55} else {56aabb.expand_to(vertices[j]);57}58}5960Ref<BitMap> src_bitmap;61src_bitmap.instantiate();62src_bitmap->create((aabb.size + Vector2(divide_by - 1, divide_by - 1)) / divide_by);6364int w = src_bitmap->get_size().width;65int h = src_bitmap->get_size().height;6667//plot triangles, using divisor6869for (int j = 0; j < chart.faces.size(); j++) {70Vector2i v[3];71for (int k = 0; k < 3; k++) {72Vector2 vtx = chart.vertices[chart.faces[j].vertex[k]];73vtx -= aabb.position;74vtx /= divide_by;75vtx = vtx.min(Vector2(w - 1, h - 1));76v[k] = vtx;77}7879for (int k = 0; k < 3; k++) {80int l = k == 0 ? 2 : k - 1;81Vector<Point2i> points = Geometry2D::bresenham_line(v[k], v[l]);82for (Point2i point : points) {83src_bitmap->set_bitv(point, true);84}85}86}8788//src_bitmap->convert_to_image()->save_png("bitmap" + itos(i) + ".png");8990//grow by 1 for each side9192int bmw = src_bitmap->get_size().width + 2;93int bmh = src_bitmap->get_size().height + 2;9495int heights_size = -1;96bool transpose = false;97if (chart.can_transpose && bmh > bmw) {98heights_size = bmh;99transpose = true;100} else {101heights_size = bmw;102}103104max_w = MAX(max_w, heights_size);105106Vector<int> top_heights;107Vector<int> bottom_heights;108top_heights.resize(heights_size);109bottom_heights.resize(heights_size);110111for (int x = 0; x < heights_size; x++) {112top_heights.write[x] = -1;113bottom_heights.write[x] = 0x7FFFFFFF;114}115116for (int x = 0; x < bmw; x++) {117for (int y = 0; y < bmh; y++) {118bool found_pixel = false;119for (int lx = x - 1; lx < x + 2 && !found_pixel; lx++) {120for (int ly = y - 1; ly < y + 2 && !found_pixel; ly++) {121int px = lx - 1;122if (px < 0 || px >= w) {123continue;124}125int py = ly - 1;126if (py < 0 || py >= h) {127continue;128}129130if (src_bitmap->get_bit(px, py)) {131found_pixel = true;132}133}134}135if (found_pixel) {136if (transpose) {137if (x > top_heights[y]) {138top_heights.write[y] = x;139}140if (x < bottom_heights[y]) {141bottom_heights.write[y] = x;142}143} else {144if (y > top_heights[x]) {145top_heights.write[x] = y;146}147if (y < bottom_heights[x]) {148bottom_heights.write[x] = y;149}150}151}152}153}154155String row;156for (int j = 0; j < top_heights.size(); j++) {157row += "(" + itos(top_heights[j]) + "-" + itos(bottom_heights[j]) + "),";158}159160PlottedBitmap plotted_bitmap;161plotted_bitmap.offset = aabb.position;162plotted_bitmap.top_heights = top_heights;163plotted_bitmap.bottom_heights = bottom_heights;164plotted_bitmap.chart_index = i;165plotted_bitmap.transposed = transpose;166plotted_bitmap.area = bmw * bmh;167168bitmaps.push_back(plotted_bitmap);169}170171bitmaps.sort();172173int atlas_max_width = nearest_power_of_2_templated(p_atlas_max_size) / divide_by;174int atlas_w = nearest_power_of_2_templated(max_w);175int atlas_h;176while (true) {177atlas_h = 0;178179//do a tetris180Vector<int> heights;181heights.resize(atlas_w);182for (int i = 0; i < atlas_w; i++) {183heights.write[i] = 0;184}185186int *atlas_ptr = heights.ptrw();187188for (int i = 0; i < bitmaps.size(); i++) {189int best_height = 0x7FFFFFFF;190int best_height_offset = -1;191int w = bitmaps[i].top_heights.size();192193const int *top_heights = bitmaps[i].top_heights.ptr();194const int *bottom_heights = bitmaps[i].bottom_heights.ptr();195196for (int j = 0; j <= atlas_w - w; j++) {197int height = 0;198199for (int k = 0; k < w; k++) {200int pixmap_h = bottom_heights[k];201if (pixmap_h == 0x7FFFFFFF) {202continue; //no pixel here, anything is fine203}204205int h = MAX(0, atlas_ptr[j + k] - pixmap_h);206if (h > height) {207height = h;208}209}210211if (height < best_height) {212best_height = height;213best_height_offset = j;214}215}216217for (int j = 0; j < w; j++) { //add218if (top_heights[j] == -1) { //unused219continue;220}221int height = best_height + top_heights[j] + 1;222atlas_ptr[j + best_height_offset] = height;223atlas_h = MAX(atlas_h, height);224}225226// set227Vector2 offset = bitmaps[i].offset;228if (bitmaps[i].transposed) {229SWAP(offset.x, offset.y);230}231232Vector2 final_pos = Vector2(best_height_offset * divide_by, best_height * divide_by) + Vector2(divide_by, divide_by) - offset;233charts.write[bitmaps[i].chart_index].final_offset = final_pos;234charts.write[bitmaps[i].chart_index].transposed = bitmaps[i].transposed;235}236237if (atlas_h <= atlas_w * 2 || atlas_w >= atlas_max_width) {238break; //ok this one is enough239}240241//try again242atlas_w *= 2;243}244245r_width = atlas_w * divide_by;246r_height = atlas_h * divide_by;247}248249250