diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/bind/core_bind.cpp | 31 | ||||
| -rw-r--r-- | core/bind/core_bind.h | 2 | ||||
| -rw-r--r-- | core/image.h | 8 | ||||
| -rw-r--r-- | core/math/geometry.cpp | 131 | ||||
| -rw-r--r-- | core/math/geometry.h | 4 | ||||
| -rw-r--r-- | core/variant_call.cpp | 25 |
6 files changed, 199 insertions, 2 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 570ed33a5..944bc531f 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -856,6 +856,36 @@ Vector<int> _Geometry::triangulate_polygon(const Vector<Vector2>& p_polygon) { return Geometry::triangulate_polygon(p_polygon); } +Dictionary _Geometry::make_atlas(const Vector<Size2>& p_rects) { + + Dictionary ret; + + Vector<Size2i> rects; + for (int i=0; i<p_rects.size(); i++) { + + rects.push_back(p_rects[i]); + }; + + Vector<Point2i> result; + Size2i size; + + Geometry::make_atlas(rects, result, size); + + Size2 r_size = size; + Vector<Point2> r_result; + for (int i=0; i<result.size(); i++) { + + r_result.push_back(result[i]); + }; + + + ret["points"] = r_result; + ret["size"] = r_size; + + return ret; +}; + + void _Geometry::_bind_methods() { @@ -878,6 +908,7 @@ void _Geometry::_bind_methods() { ObjectTypeDB::bind_method(_MD("triangulate_polygon","polygon"),&_Geometry::triangulate_polygon); + ObjectTypeDB::bind_method(_MD("make_atlas","sizes"),&_Geometry::make_atlas); } diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 0ef70e4b1..298345bfd 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -236,6 +236,8 @@ public: Vector<int> triangulate_polygon(const Vector<Vector2>& p_polygon); + Dictionary make_atlas(const Vector<Size2>& p_rects); + _Geometry(); }; diff --git a/core/image.h b/core/image.h index 7a6ee1e4b..31a815c58 100644 --- a/core/image.h +++ b/core/image.h @@ -216,6 +216,14 @@ public: * Convert the image to another format, as close as it can be done. */ void convert( Format p_new_format ); + + Image converted(int p_new_format) { + ERR_FAIL_INDEX_V(p_new_format, FORMAT_MAX, Image()); + + Image ret = *this; + ret.convert((Format)p_new_format); + return ret; + }; /** * Get the current image format. diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index cb76b9ed0..2d525dd1c 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -1004,3 +1004,134 @@ DVector<Plane> Geometry::build_capsule_planes(float p_radius, float p_height, in } + +struct _AtlasWorkRect { + + Size2i s; + Point2i p; + int idx; + _FORCE_INLINE_ bool operator<(const _AtlasWorkRect& p_r) const { return s.width > p_r.s.width; }; +}; + +struct _AtlasWorkRectResult { + + Vector<_AtlasWorkRect> result; + int max_w; + int max_h; +}; + +void Geometry::make_atlas(const Vector<Size2i>& p_rects,Vector<Point2i>& r_result, Size2i& r_size) { + + //super simple, almost brute force scanline stacking fitter + //it's pretty basic for now, but it tries to make sure that the aspect ratio of the + //resulting atlas is somehow square. This is necesary because video cards have limits + //on texture size (usually 2048 or 4096), so the more square a texture, the more chances + //it will work in every hardware. + // for example, it will prioritize a 1024x1024 atlas (works everywhere) instead of a + // 256x8192 atlas (won't work anywhere). + + ERR_FAIL_COND(p_rects.size()==0); + + Vector<_AtlasWorkRect> wrects; + wrects.resize(p_rects.size()); + for(int i=0;i<p_rects.size();i++) { + wrects[i].s=p_rects[i]; + wrects[i].idx=i; + } + wrects.sort(); + int widest = wrects[0].s.width; + + Vector<_AtlasWorkRectResult> results; + + for(int i=0;i<=12;i++) { + + int w = 1<<i; + int max_h=0; + int max_w=0; + if ( w < widest ) + continue; + + Vector<int> hmax; + hmax.resize(w); + for(int j=0;j<w;j++) + hmax[j]=0; + + //place them + int ofs=0; + int limit_h=0; + for(int j=0;j<wrects.size();j++) { + + + if (ofs+wrects[j].s.width > w) { + + ofs=0; + } + + int from_y=0; + for(int k=0;k<wrects[j].s.width;k++) { + + if (hmax[ofs+k] > from_y) + from_y=hmax[ofs+k]; + } + + wrects[j].p.x=ofs; + wrects[j].p.y=from_y; + int end_h = from_y+wrects[j].s.height; + int end_w = ofs+wrects[j].s.width; + if (ofs==0) + limit_h=end_h; + + for(int k=0;k<wrects[j].s.width;k++) { + + hmax[ofs+k]=end_h; + } + + if (end_h > max_h) + max_h=end_h; + + if (end_w > max_w) + max_w=end_w; + + if (ofs==0 || end_h>limit_h ) //while h limit not reched, keep stacking + ofs+=wrects[j].s.width; + + } + + _AtlasWorkRectResult result; + result.result=wrects; + result.max_h=max_h; + result.max_w=max_w; + results.push_back(result); + + } + + //find the result with the best aspect ratio + + int best=-1; + float best_aspect=1e20; + + for(int i=0;i<results.size();i++) { + + float h = nearest_power_of_2(results[i].max_h); + float w = nearest_power_of_2(results[i].max_w); + float aspect = h>w ? h/w : w/h; + if (aspect < best_aspect) { + best=i; + best_aspect=aspect; + } + } + + r_result.resize(p_rects.size()); + + for(int i=0;i<p_rects.size();i++) { + + r_result[ results[best].result[i].idx ]=results[best].result[i].p; + } + + r_size=Size2(results[best].max_w,results[best].max_h ); + +} + + + + diff --git a/core/math/geometry.h b/core/math/geometry.h index 5b21c25be..48713fb91 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -826,7 +826,9 @@ public: static DVector<Plane> build_box_planes(const Vector3& p_extents); static DVector<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis=Vector3::AXIS_Z); static DVector<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis=Vector3::AXIS_Z); - + + static void make_atlas(const Vector<Size2i>& p_rects,Vector<Point2i>& r_result, Size2i& r_size); + }; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index e0ae7e211..bd731abea 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -515,7 +515,7 @@ static void _call_##m_type##m_method(Variant& r_ret,Variant& p_self,const Varian #define VCALL_PTR0R(m_type,m_method)\ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(); } #define VCALL_PTR1(m_type,m_method)\ -static void _call_##m_type##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0]); } +static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0]); } #define VCALL_PTR1R(m_type,m_method)\ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0]); } #define VCALL_PTR2(m_type,m_method)\ @@ -551,6 +551,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var VCALL_PTR3R(Image, resized); VCALL_PTR0R(Image, get_data); VCALL_PTR3(Image, blit_rect); + VCALL_PTR1R(Image, converted); VCALL_PTR0R( AABB, get_area ); VCALL_PTR0R( AABB, has_no_area ); @@ -605,6 +606,25 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var } } + static void _call_Matrix32_basis_xform(Variant& r_ret,Variant& p_self,const Variant** p_args) { + + switch(p_args[0]->type) { + + case Variant::VECTOR2: r_ret=reinterpret_cast<Matrix32*>(p_self._data._ptr)->basis_xform( p_args[0]->operator Vector2()); return; + default: r_ret=Variant(); + } + + } + + static void _call_Matrix32_basis_xform_inv(Variant& r_ret,Variant& p_self,const Variant** p_args) { + + switch(p_args[0]->type) { + + case Variant::VECTOR2: r_ret=reinterpret_cast<Matrix32*>(p_self._data._ptr)->basis_xform_inv( p_args[0]->operator Vector2()); return; + default: r_ret=Variant(); + } + } + VCALL_PTR0R( Matrix3, inverse ); VCALL_PTR0R( Matrix3, transposed ); @@ -1313,6 +1333,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl ADDFUNC3(IMAGE, IMAGE, Image, resized, INT, "x", INT, "y", INT, "interpolation", varray(((int)Image::INTERPOLATE_BILINEAR))); ADDFUNC0(IMAGE, RAW_ARRAY, Image, get_data, varray()); ADDFUNC3(IMAGE, NIL, Image, blit_rect, IMAGE, "src", RECT2, "src_rect", VECTOR2, "dest", varray(0)); + ADDFUNC1(IMAGE, IMAGE, Image, converted, INT, "format", varray(0)); ADDFUNC0(_RID,INT,RID,get_id,varray()); @@ -1430,6 +1451,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl ADDFUNC1(MATRIX32,MATRIX32,Matrix32,translated,VECTOR2,"offset",varray()); ADDFUNC1(MATRIX32,MATRIX32,Matrix32,xform,NIL,"v",varray()); ADDFUNC1(MATRIX32,MATRIX32,Matrix32,xform_inv,NIL,"v",varray()); + ADDFUNC1(MATRIX32,MATRIX32,Matrix32,basis_xform,NIL,"v",varray()); + ADDFUNC1(MATRIX32,MATRIX32,Matrix32,basis_xform_inv,NIL,"v",varray()); ADDFUNC2(MATRIX32,MATRIX32,Matrix32,interpolate_with,MATRIX32,"m",REAL,"c",varray()); ADDFUNC0(MATRIX3,MATRIX3,Matrix3,inverse,varray()); |
