|  |  |  | const Faces = preload("./Faces.gd") | 
					
						
							|  |  |  | const VoxData = preload("./VoxFormat/VoxData.gd") | 
					
						
							|  |  |  | const vox_to_godot = Basis(Vector3.RIGHT, Vector3.FORWARD, Vector3.UP) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Names for the faces by orientation | 
					
						
							|  |  |  | enum FaceOrientation { | 
					
						
							|  |  |  |     Top = 0, | 
					
						
							|  |  |  |     Bottom = 1, | 
					
						
							|  |  |  |     Left = 2, | 
					
						
							|  |  |  |     Right = 3, | 
					
						
							|  |  |  |     Front = 4, | 
					
						
							|  |  |  |     Back = 5, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # An Array(FaceOrientation) of all possible face orientations | 
					
						
							|  |  |  | const face_orientations :Array = [ | 
					
						
							|  |  |  |     FaceOrientation.Top, | 
					
						
							|  |  |  |     FaceOrientation.Bottom, | 
					
						
							|  |  |  |     FaceOrientation.Left, | 
					
						
							|  |  |  |     FaceOrientation.Right, | 
					
						
							|  |  |  |     FaceOrientation.Front, | 
					
						
							|  |  |  |     FaceOrientation.Back | 
					
						
							|  |  |  | ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # An Array(int) of the depth axis by orientation | 
					
						
							|  |  |  | const depth_axis :Array = [ | 
					
						
							|  |  |  |     Vector3.AXIS_Z, | 
					
						
							|  |  |  |     Vector3.AXIS_Z, | 
					
						
							|  |  |  |     Vector3.AXIS_X, | 
					
						
							|  |  |  |     Vector3.AXIS_X, | 
					
						
							|  |  |  |     Vector3.AXIS_Y, | 
					
						
							|  |  |  |     Vector3.AXIS_Y, | 
					
						
							|  |  |  | ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # An Array(int) of the width axis by orientation | 
					
						
							|  |  |  | const width_axis :Array = [ | 
					
						
							|  |  |  |     Vector3.AXIS_Y, | 
					
						
							|  |  |  |     Vector3.AXIS_Y, | 
					
						
							|  |  |  |     Vector3.AXIS_Z, | 
					
						
							|  |  |  |     Vector3.AXIS_Z, | 
					
						
							|  |  |  |     Vector3.AXIS_X, | 
					
						
							|  |  |  |     Vector3.AXIS_X, | 
					
						
							|  |  |  | ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # An Array(int) of height axis by orientation | 
					
						
							|  |  |  | const height_axis :Array = [ | 
					
						
							|  |  |  |     Vector3.AXIS_X, | 
					
						
							|  |  |  |     Vector3.AXIS_X, | 
					
						
							|  |  |  |     Vector3.AXIS_Y, | 
					
						
							|  |  |  |     Vector3.AXIS_Y, | 
					
						
							|  |  |  |     Vector3.AXIS_Z, | 
					
						
							|  |  |  |     Vector3.AXIS_Z, | 
					
						
							|  |  |  | ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # An Array(Vector3) describing what vectors to use to check for face occlusion | 
					
						
							|  |  |  | # by orientation | 
					
						
							|  |  |  | const face_checks :Array = [ | 
					
						
							|  |  |  |     Vector3(0, 0, 1), | 
					
						
							|  |  |  |     Vector3(0, 0, -1), | 
					
						
							|  |  |  |     Vector3(-1, 0, 0), | 
					
						
							|  |  |  |     Vector3(1, 0, 0), | 
					
						
							|  |  |  |     Vector3(0, -1, 0), | 
					
						
							|  |  |  |     Vector3(0, 1, 0), | 
					
						
							|  |  |  | ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # An array of the face meshes by orientation | 
					
						
							|  |  |  | const face_meshes :Array = [ | 
					
						
							|  |  |  |     Faces.Front, | 
					
						
							|  |  |  |     Faces.Back, | 
					
						
							|  |  |  |     Faces.Left, | 
					
						
							|  |  |  |     Faces.Right, | 
					
						
							|  |  |  |     Faces.Bottom, | 
					
						
							|  |  |  |     Faces.Top, | 
					
						
							|  |  |  | ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # An Array(Vector3) describing what normals to use by orientation | 
					
						
							|  |  |  | const normals :Array = [ | 
					
						
							|  |  |  |     Vector3(0, 1, 0), | 
					
						
							|  |  |  |     Vector3(0, -1, 0), | 
					
						
							|  |  |  |     Vector3(-1, 0, 0), | 
					
						
							|  |  |  |     Vector3(1, 0, 0), | 
					
						
							|  |  |  |     Vector3(0, 0, 1), | 
					
						
							|  |  |  |     Vector3(0, 0, -1), | 
					
						
							|  |  |  | ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # The SurfaceTool the object will use to generate the mesh | 
					
						
							|  |  |  | var st :SurfaceTool = SurfaceTool.new() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # A Dictonary[Vector3]int of the voxel data for the visible faces of the | 
					
						
							|  |  |  | # current slice | 
					
						
							|  |  |  | var faces :Dictionary | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Minimum extends of the volume | 
					
						
							|  |  |  | var mins :Vector3 = Vector3(1000000, 1000000, 1000000) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Maximum extends of the volume | 
					
						
							|  |  |  | var maxs :Vector3 = Vector3(-1000000,-1000000,-1000000) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Generate a mesh for the given voxel_data with single-pass greedy face merging | 
					
						
							|  |  |  | # Primary RefCounted: https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/ | 
					
						
							|  |  |  | # Secondary RefCounted: https://www.gedge.ca/dev/2014/08/17/greedy-voxel-meshing | 
					
						
							|  |  |  | # voxel_data is a dict[Vector3]int | 
					
						
							|  |  |  | func generate(vox :VoxData, voxel_data :Dictionary, scale :float, snaptoground : bool): | 
					
						
							|  |  |  |     # Remeber, MagicaVoxel thinks Y is the depth axis. We convert to the correct | 
					
						
							|  |  |  |     # coordinate space when we generate the faces. | 
					
						
							|  |  |  |     st.begin(Mesh.PRIMITIVE_TRIANGLES) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # Short-circut empty models | 
					
						
							|  |  |  |     if voxel_data.size() == 0: | 
					
						
							|  |  |  |         return st.commit() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # Convert voxel data to raw color values | 
					
						
							|  |  |  |     for v in voxel_data: | 
					
						
							|  |  |  |         voxel_data[v] = vox.colors[voxel_data[v]] | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # Find bounds | 
					
						
							|  |  |  |     for v in voxel_data: | 
					
						
							|  |  |  |         mins.x = min(mins.x, v.x) | 
					
						
							|  |  |  |         mins.y = min(mins.y, v.y) | 
					
						
							|  |  |  |         mins.z = min(mins.z, v.z) | 
					
						
							|  |  |  |         maxs.x = max(maxs.x, v.x) | 
					
						
							|  |  |  |         maxs.y = max(maxs.y, v.y) | 
					
						
							|  |  |  |         maxs.z = max(maxs.z, v.z) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # Itterate over all face orientations to reduce problem to 3 dimensions | 
					
						
							|  |  |  |     for o in face_orientations: | 
					
						
							|  |  |  |         generate_geometry_for_orientation(voxel_data, o, scale, snaptoground) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Finish the mesh and material and return | 
					
						
							|  |  |  |     var material = StandardMaterial3D.new() | 
					
						
							|  |  |  |     material.vertex_color_is_srgb = true | 
					
						
							|  |  |  |     material.vertex_color_use_as_albedo = true | 
					
						
							|  |  |  |     material.roughness = 1 | 
					
						
							|  |  |  |     st.set_material(material) | 
					
						
							|  |  |  |     return st.commit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Generates all of the geometry for a given face orientation | 
					
						
							|  |  |  | func generate_geometry_for_orientation(voxel_data :Dictionary, o :int, scale :float, snaptoground :bool) -> void: | 
					
						
							|  |  |  |     # Sweep through the volume along the depth reducing the problem to 2 dimensional | 
					
						
							|  |  |  |     var da :int = depth_axis[o] | 
					
						
							|  |  |  |     for slice in range(mins[da], maxs[da]+1): | 
					
						
							|  |  |  |         var faces :Dictionary = query_slice_faces(voxel_data, o, slice) | 
					
						
							|  |  |  |         if faces.size() > 0: | 
					
						
							|  |  |  |             generate_geometry(faces, o, slice, scale, snaptoground) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Returns the voxels in the set voxel_data with a visible face along the slice | 
					
						
							|  |  |  | # for the given orientation | 
					
						
							|  |  |  | func query_slice_faces(voxel_data :Dictionary, o :int, slice :float) -> Dictionary: | 
					
						
							|  |  |  |     var ret :Dictionary = Dictionary() | 
					
						
							|  |  |  |     var da = depth_axis[o] | 
					
						
							|  |  |  |     for v in voxel_data: | 
					
						
							|  |  |  |         if v[da] == slice and voxel_data.has(v + face_checks[o]) == false: | 
					
						
							|  |  |  |             ret[v] = voxel_data[v] | 
					
						
							|  |  |  |     return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Generates geometry for the given orientation for the set of faces | 
					
						
							|  |  |  | func generate_geometry(faces :Dictionary, o :int, slice :float, scale :float, snaptoground :bool) -> void: | 
					
						
							|  |  |  |     var da :int = depth_axis[o] | 
					
						
							|  |  |  |     var wa :int = width_axis[o] | 
					
						
							|  |  |  |     var ha :int = height_axis[o] | 
					
						
							|  |  |  |     var v :Vector3 = Vector3() | 
					
						
							|  |  |  |     v[da] = slice | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # Itterate the rows of the sparse volume | 
					
						
							|  |  |  |     v[ha] = mins[ha] | 
					
						
							|  |  |  |     while v[ha] <= maxs[ha]: | 
					
						
							|  |  |  |         # Itterate over the voxels of the row | 
					
						
							|  |  |  |         v[wa] = mins[wa] | 
					
						
							|  |  |  |         while v[wa] <= maxs[wa]: | 
					
						
							|  |  |  |             if faces.has(v): | 
					
						
							|  |  |  |                 generate_geometry_for_face(faces, v, o, scale, snaptoground) | 
					
						
							|  |  |  |             v[wa] += 1.0 | 
					
						
							|  |  |  |         v[ha] += 1.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Generates the geometry for the given face and orientation and scale and returns | 
					
						
							|  |  |  | # the set of remaining faces | 
					
						
							|  |  |  | func generate_geometry_for_face(faces :Dictionary, face :Vector3, o :int, scale :float, snaptoground :bool) -> Dictionary: | 
					
						
							|  |  |  |     var da :int = depth_axis[o] | 
					
						
							|  |  |  |     var wa :int = width_axis[o] | 
					
						
							|  |  |  |     var ha :int = height_axis[o] | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # Greedy face merging | 
					
						
							|  |  |  |     var width :int = width_query(faces, face, o) | 
					
						
							|  |  |  |     var height :int = height_query(faces, face, o, width) | 
					
						
							|  |  |  |     var grow :Vector3 = Vector3(1, 1, 1) | 
					
						
							|  |  |  |     grow[wa] *= width | 
					
						
							|  |  |  |     grow[ha] *= height | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # Generate geometry | 
					
						
							|  |  |  |     var yoffset = Vector3(0,0,0); | 
					
						
							|  |  |  |     if snaptoground : yoffset = Vector3(0, -mins.z * scale, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     st.set_color(faces[face]) | 
					
						
							|  |  |  |     st.set_normal(normals[o]) | 
					
						
							|  |  |  |     for vert in face_meshes[o]: | 
					
						
							|  |  |  |         st.add_vertex(yoffset + vox_to_godot * ((vert * grow) + face) * scale) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # Remove these faces from the pool | 
					
						
							|  |  |  |     var v :Vector3 = Vector3() | 
					
						
							|  |  |  |     v[da] = face[da] | 
					
						
							|  |  |  |     for iy in range(height): | 
					
						
							|  |  |  |         v[ha] = face[ha] + float(iy) | 
					
						
							|  |  |  |         for ix in range(width): | 
					
						
							|  |  |  |             v[wa] = face[wa] + float(ix) | 
					
						
							|  |  |  |             faces.erase(v) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     return faces | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Returns the number of voxels wide the run starting at face is with respect to | 
					
						
							|  |  |  | # the set of faces and orientation | 
					
						
							|  |  |  | func width_query(faces :Dictionary, face :Vector3, o :int) -> int: | 
					
						
							|  |  |  |     var wd :int = width_axis[o] | 
					
						
							|  |  |  |     var v :Vector3 = face | 
					
						
							|  |  |  |     while faces.has(v) and faces[v] == faces[face]: | 
					
						
							|  |  |  |         v[wd] += 1.0 | 
					
						
							|  |  |  |     return int(v[wd] - face[wd]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Returns the number of voxels high the run starting at face is with respect to | 
					
						
							|  |  |  | # the set of faces and orientation, with the given width | 
					
						
							|  |  |  | func height_query(faces :Dictionary, face :Vector3, o :int, width :int) -> int: | 
					
						
							|  |  |  |     var hd :int = height_axis[o] | 
					
						
							|  |  |  |     var c :Color = faces[face] | 
					
						
							|  |  |  |     var v :Vector3 = face | 
					
						
							|  |  |  |     v[hd] += 1.0 | 
					
						
							|  |  |  |     while faces.has(v) and faces[v] == c and width_query(faces, v, o) >= width: | 
					
						
							|  |  |  |         v[hd] += 1.0 | 
					
						
							|  |  |  |     return int(v[hd] - face[hd]) |