Skip to content

Instantly share code, notes, and snippets.

@brombres
Last active October 11, 2023 15:51
Show Gist options
  • Save brombres/759d33c17a8dde1620874fcfbdf024c0 to your computer and use it in GitHub Desktop.
Save brombres/759d33c17a8dde1620874fcfbdf024c0 to your computer and use it in GitHub Desktop.
Godot script that allows a MeshInstance2D node to correctly show an atlas texture.
# AtlasMeshInstance2D.gd
#
# ABOUT
# 2023.08.02 by Brom Bresenham
# Tested on Godot 4.2-dev2
#
# USAGE
# 1. Attach to a MeshInstance2D.
# 2. Set the MeshInstance2D's texture by calling .set_atlas_texture(new_texture:Texture2D) instead
# of directly assigning `texture = new_texture'. set_atlas_texture() works whether or not the
# texture is an atlas texture. If an atlas texture, the quad mesh will be recreated with the
# appropriate UV coordinates for the atlas texture.
# 3. You can pass an optional second Vector2i parameter in that indicates the number of horizontal
# and vertical subdivisions that should be made. (0,0) is the default, which creates a mesh
# with 1 quad. (2,3) would create a mesh with 2^2 * 2^3 = 4 * 8 = 32 quads.
extends MeshInstance2D
var _current_texture:Texture2D
var _st = SurfaceTool.new()
var _mesh:ArrayMesh
func set_atlas_texture(_texture:Texture2D, subdivide:Vector2i=Vector2i(0,0)):
if not _texture or not _texture.has_method("get_atlas"):
set_texture(_texture)
return
if _texture == _current_texture: return
_current_texture = _texture
var region = _texture.get_region()
var atlas_w = _texture.get_atlas().get_width()
var atlas_h = _texture.get_atlas().get_height()
var u1 = region.position.x / atlas_w
var u2 = (region.position.x + region.size.x) / atlas_w
var v1 = region.position.y / atlas_h
var v2 = (region.position.y + region.size.y) / atlas_h
var x1 = -0.5
var x2 = 0.5
var y1 = -0.5
var y2 = 0.5
_st.clear()
_st.begin(Mesh.PRIMITIVE_TRIANGLES)
_st.set_color( Color.WHITE )
_generate( x1, y1, x2, y2, u1, v1, u2, v2, subdivide.x, subdivide.y )
if _mesh:
_mesh.clear_surfaces()
_st.commit( _mesh )
else:
_mesh = _st.commit()
set_mesh( _mesh )
set_texture(_texture)
func _generate( x1:float, y1:float, x2:float, y2:float, u1:float, v1:float, u2:float, v2:float, sub_i:int, sub_j:int ):
if sub_i > 0:
_generate( x1, y1, (x1+x2)/2, y2, u1, v1, (u1+u2)/2, v2, sub_i-1, sub_j )
_generate( (x1+x2)/2, y1, x2, y2, (u1+u2)/2, v1, u2, v2, sub_i-1, sub_j )
return
if sub_j > 0:
_generate( x1, y1, x2, (y1+y2)/2, u1, v1, u2, (v1+v2)/2, sub_i, sub_j-1 )
_generate( x1, (y1+y2)/2, x2, y2, u1, (v1+v2)/2, u2, v2, sub_i, sub_j-1 )
return
_st.set_uv( Vector2(u1,v1) ); _st.add_vertex( Vector3( x1, y1,0) )
_st.set_uv( Vector2(u1,v2) ); _st.add_vertex( Vector3( x1, y2,0) )
_st.set_uv( Vector2(u2,v2) ); _st.add_vertex( Vector3( x2, y2,0) )
_st.set_uv( Vector2(u1,v1) ); _st.add_vertex( Vector3( x1, y1,0) )
_st.set_uv( Vector2(u2,v2) ); _st.add_vertex( Vector3( x2, y2,0) )
_st.set_uv( Vector2(u2,v1) ); _st.add_vertex( Vector3( x2, y1,0) )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment