diff options
Diffstat (limited to 'addons/voxel-core/classes')
-rw-r--r-- | addons/voxel-core/classes/reader.gd | 21 | ||||
-rw-r--r-- | addons/voxel-core/classes/readers/gpl.gd | 48 | ||||
-rw-r--r-- | addons/voxel-core/classes/readers/image.gd | 40 | ||||
-rw-r--r-- | addons/voxel-core/classes/readers/vox.gd | 86 | ||||
-rw-r--r-- | addons/voxel-core/classes/voxel.gd | 330 | ||||
-rw-r--r-- | addons/voxel-core/classes/voxel_mesh.gd | 124 | ||||
-rw-r--r-- | addons/voxel-core/classes/voxel_object.gd | 501 | ||||
-rw-r--r-- | addons/voxel-core/classes/voxel_set.gd | 234 | ||||
-rw-r--r-- | addons/voxel-core/classes/voxel_tool.gd | 227 |
9 files changed, 0 insertions, 1611 deletions
diff --git a/addons/voxel-core/classes/reader.gd b/addons/voxel-core/classes/reader.gd deleted file mode 100644 index 7c17b8a..0000000 --- a/addons/voxel-core/classes/reader.gd +++ /dev/null @@ -1,21 +0,0 @@ -class_name Reader -extends Reference -# Makeshift interface class inhereted by all file readers. - - - -## Public Methods -# Calls on appropriate file reader according to file_path's extension. -# file_path : String : path to file to be read -# return : Dictionary : read results, contains: { error : int, voxels : Dictionary<Vec3, int>, palette : Dictionary<int, Dictionary<String, Variant> } -static func read_file(file_path : String) -> Dictionary: - var result = { "error": ERR_FILE_UNRECOGNIZED } - match file_path.get_extension(): - "png", "bmp", "dds", "exr", "hdr", "jpg", "jpeg", "tga", "svg", "svgz", "webp": - result = ImageReader.read_file(file_path) - "vox": result = VoxReader.read_file(file_path) - "qb": continue - "qbt": continue - "vxm": continue - "gpl": result = GPLReader.read_file(file_path) - return result diff --git a/addons/voxel-core/classes/readers/gpl.gd b/addons/voxel-core/classes/readers/gpl.gd deleted file mode 100644 index 4a6b943..0000000 --- a/addons/voxel-core/classes/readers/gpl.gd +++ /dev/null @@ -1,48 +0,0 @@ -class_name GPLReader -extends Reference -# GIMP palette file reader - - - -# Public Methods -# Reads GPL file, and returns voxel palette -static func read(gpl_file : File) -> Dictionary: - var result := { - "error": OK, - "voxels": {}, - "palette": [], - } - - if gpl_file.get_line() == "GIMP Palette": - while not gpl_file.eof_reached(): - var line = gpl_file.get_line() - if typeof(line) == TYPE_STRING and not line.empty() and (line[0].is_valid_integer() or line[0] == " "): - var tokens = line.split("\t") - var name = "" - var color = tokens[0].split_floats(" ") - color = Color(color[0] / 255, color[1] / 255, color[2] / 255) - if tokens.size() > 1: - name = tokens[1] - var end = name.find("(") - name = name.substr(0, end) - - if not result["palette"].has(color): - var voxel := Voxel.colored(color) - result["palette"].append(voxel) - if not name.empty(): - Voxel.set_name(voxel, name.strip_edges()) - else: - result["error"] = ERR_FILE_UNRECOGNIZED - - return result - - -static func read_file(gpl_path : String) -> Dictionary: - var result := { "error": OK } - var file := File.new() - var error = file.open(gpl_path, File.READ) - if error == OK: - result = read(file) - if file.is_open(): - file.close() - return result diff --git a/addons/voxel-core/classes/readers/image.gd b/addons/voxel-core/classes/readers/image.gd deleted file mode 100644 index 3c19d2f..0000000 --- a/addons/voxel-core/classes/readers/image.gd +++ /dev/null @@ -1,40 +0,0 @@ -class_name ImageReader, "res://addons/voxel-core/assets/logos/MagicaVoxel.png" -extends Reference -# Image file reader - - - -## Public Methods -# Reads images pixels, returns voxel content and voxel palette -static func read(image : Image) -> Dictionary: - var result := { - "error": OK, - "voxels": {}, - "palette": [], - } - - image.lock() - for x in range(image.get_width()): - for y in range(image.get_height()): - if image.get_pixel(x, y).a > 0: - var color := image.get_pixel(x, y) - color.a = 1.0 - var index = result["palette"].find(color) - if index == -1: - index = result["palette"].size() - result["palette"].append(color) - result["voxels"][Vector3(x, -y, 0).round()] = index - image.unlock() - - for index in range(result["palette"].size()): - result["palette"][index] = Voxel.colored(result["palette"][index]) - - return result - - -static func read_file(image_path : String) -> Dictionary: - var image := Image.new() - var err = image.load(image_path) - if err == OK: - return read(image) - return { "error": err } diff --git a/addons/voxel-core/classes/readers/vox.gd b/addons/voxel-core/classes/readers/vox.gd deleted file mode 100644 index 51dfa86..0000000 --- a/addons/voxel-core/classes/readers/vox.gd +++ /dev/null @@ -1,86 +0,0 @@ -class_name VoxReader, "res://addons/voxel-core/assets/logos/MagicaVoxel.png" -extends Reference -# MagicaVoxel file reader - - - -# Constants -const magicavoxel_default_palette := [ - Color("00000000"), Color("ffffffff"), Color("ffccffff"), Color("ff99ffff"), Color("ff66ffff"), Color("ff33ffff"), Color("ff00ffff"), Color("ffffccff"), Color("ffccccff"), Color("ff99ccff"), Color("ff66ccff"), Color("ff33ccff"), Color("ff00ccff"), Color("ffff99ff"), Color("ffcc99ff"), Color("ff9999ff"), - Color("ff6699ff"), Color("ff3399ff"), Color("ff0099ff"), Color("ffff66ff"), Color("ffcc66ff"), Color("ff9966ff"), Color("ff6666ff"), Color("ff3366ff"), Color("ff0066ff"), Color("ffff33ff"), Color("ffcc33ff"), Color("ff9933ff"), Color("ff6633ff"), Color("ff3333ff"), Color("ff0033ff"), Color("ffff00ff"), - Color("ffcc00ff"), Color("ff9900ff"), Color("ff6600ff"), Color("ff3300ff"), Color("ff0000ff"), Color("ffffffcc"), Color("ffccffcc"), Color("ff99ffcc"), Color("ff66ffcc"), Color("ff33ffcc"), Color("ff00ffcc"), Color("ffffcccc"), Color("ffcccccc"), Color("ff99cccc"), Color("ff66cccc"), Color("ff33cccc"), - Color("ff00cccc"), Color("ffff99cc"), Color("ffcc99cc"), Color("ff9999cc"), Color("ff6699cc"), Color("ff3399cc"), Color("ff0099cc"), Color("ffff66cc"), Color("ffcc66cc"), Color("ff9966cc"), Color("ff6666cc"), Color("ff3366cc"), Color("ff0066cc"), Color("ffff33cc"), Color("ffcc33cc"), Color("ff9933cc"), - Color("ff6633cc"), Color("ff3333cc"), Color("ff0033cc"), Color("ffff00cc"), Color("ffcc00cc"), Color("ff9900cc"), Color("ff6600cc"), Color("ff3300cc"), Color("ff0000cc"), Color("ffffff99"), Color("ffccff99"), Color("ff99ff99"), Color("ff66ff99"), Color("ff33ff99"), Color("ff00ff99"), Color("ffffcc99"), - Color("ffcccc99"), Color("ff99cc99"), Color("ff66cc99"), Color("ff33cc99"), Color("ff00cc99"), Color("ffff9999"), Color("ffcc9999"), Color("ff999999"), Color("ff669999"), Color("ff339999"), Color("ff009999"), Color("ffff6699"), Color("ffcc6699"), Color("ff996699"), Color("ff666699"), Color("ff336699"), - Color("ff006699"), Color("ffff3399"), Color("ffcc3399"), Color("ff993399"), Color("ff663399"), Color("ff333399"), Color("ff003399"), Color("ffff0099"), Color("ffcc0099"), Color("ff990099"), Color("ff660099"), Color("ff330099"), Color("ff000099"), Color("ffffff66"), Color("ffccff66"), Color("ff99ff66"), - Color("ff66ff66"), Color("ff33ff66"), Color("ff00ff66"), Color("ffffcc66"), Color("ffcccc66"), Color("ff99cc66"), Color("ff66cc66"), Color("ff33cc66"), Color("ff00cc66"), Color("ffff9966"), Color("ffcc9966"), Color("ff999966"), Color("ff669966"), Color("ff339966"), Color("ff009966"), Color("ffff6666"), - Color("ffcc6666"), Color("ff996666"), Color("ff666666"), Color("ff336666"), Color("ff006666"), Color("ffff3366"), Color("ffcc3366"), Color("ff993366"), Color("ff663366"), Color("ff333366"), Color("ff003366"), Color("ffff0066"), Color("ffcc0066"), Color("ff990066"), Color("ff660066"), Color("ff330066"), - Color("ff000066"), Color("ffffff33"), Color("ffccff33"), Color("ff99ff33"), Color("ff66ff33"), Color("ff33ff33"), Color("ff00ff33"), Color("ffffcc33"), Color("ffcccc33"), Color("ff99cc33"), Color("ff66cc33"), Color("ff33cc33"), Color("ff00cc33"), Color("ffff9933"), Color("ffcc9933"), Color("ff999933"), - Color("ff669933"), Color("ff339933"), Color("ff009933"), Color("ffff6633"), Color("ffcc6633"), Color("ff996633"), Color("ff666633"), Color("ff336633"), Color("ff006633"), Color("ffff3333"), Color("ffcc3333"), Color("ff993333"), Color("ff663333"), Color("ff333333"), Color("ff003333"), Color("ffff0033"), - Color("ffcc0033"), Color("ff990033"), Color("ff660033"), Color("ff330033"), Color("ff000033"), Color("ffffff00"), Color("ffccff00"), Color("ff99ff00"), Color("ff66ff00"), Color("ff33ff00"), Color("ff00ff00"), Color("ffffcc00"), Color("ffcccc00"), Color("ff99cc00"), Color("ff66cc00"), Color("ff33cc00"), - Color("ff00cc00"), Color("ffff9900"), Color("ffcc9900"), Color("ff999900"), Color("ff669900"), Color("ff339900"), Color("ff009900"), Color("ffff6600"), Color("ffcc6600"), Color("ff996600"), Color("ff666600"), Color("ff336600"), Color("ff006600"), Color("ffff3300"), Color("ffcc3300"), Color("ff993300"), - Color("ff663300"), Color("ff333300"), Color("ff003300"), Color("ffff0000"), Color("ffcc0000"), Color("ff990000"), Color("ff660000"), Color("ff330000"), Color("ff0000ee"), Color("ff0000dd"), Color("ff0000bb"), Color("ff0000aa"), Color("ff000088"), Color("ff000077"), Color("ff000055"), Color("ff000044"), - Color("ff000022"), Color("ff000011"), Color("ff00ee00"), Color("ff00dd00"), Color("ff00bb00"), Color("ff00aa00"), Color("ff008800"), Color("ff007700"), Color("ff005500"), Color("ff004400"), Color("ff002200"), Color("ff001100"), Color("ffee0000"), Color("ffdd0000"), Color("ffbb0000"), Color("ffaa0000"), - Color("ff880000"), Color("ff770000"), Color("ff550000"), Color("ff440000"), Color("ff220000"), Color("ff110000"), Color("ffeeeeee"), Color("ffdddddd"), Color("ffbbbbbb"), Color("ffaaaaaa"), Color("ff888888"), Color("ff777777"), Color("ff555555"), Color("ff444444"), Color("ff222222"), Color("ff111111") -] - - - -# Public Methods -# Reads vox file, returns voxel content and voxel palette -static func read(vox_file : File) -> Dictionary: - var result := { - "error": OK, - "voxels": {}, - "palette": [], - } - - var magic := vox_file.get_buffer(4).get_string_from_ascii() - var magic_version := vox_file.get_32() - if magic == "VOX " and magic_version == 150: - var nodes := {} - while vox_file.get_position() < vox_file.get_len(): - var chunk_name = vox_file.get_buffer(4).get_string_from_ascii() - var chunk_size = vox_file.get_32() - var chunk_children = vox_file.get_32() - - match chunk_name: - "XYZI": - for i in range(0, vox_file.get_32()): - var x := vox_file.get_8() - var z := -vox_file.get_8() - var y := vox_file.get_8() - result["voxels"][Vector3( - x, y, z).floor()] = vox_file.get_8() - 1 - "RGBA": - for i in range(0,256): - var color := Color( - float(vox_file.get_8() / 255.0), - float(vox_file.get_8() / 255.0), - float(vox_file.get_8() / 255.0), - float(vox_file.get_8() / 255.0)) - color.a = 1.0 - result["palette"].append(color) - _: - vox_file.get_buffer(chunk_size) - - if result["palette"].empty(): - result["palette"] = magicavoxel_default_palette.duplicate() - else: - result["error"] = ERR_FILE_UNRECOGNIZED - - for index in range(result["palette"].size()): - result["palette"][index] = Voxel.colored(result["palette"][index]) - - return result - - -static func read_file(vox_path : String) -> Dictionary: - var result := { "error": OK } - var vox_file := File.new() - var error = vox_file.open(vox_path, File.READ) - if error == OK: - result = read(vox_file) - if vox_file.is_open(): - vox_file.close() - return result diff --git a/addons/voxel-core/classes/voxel.gd b/addons/voxel-core/classes/voxel.gd deleted file mode 100644 index f9bc7bb..0000000 --- a/addons/voxel-core/classes/voxel.gd +++ /dev/null @@ -1,330 +0,0 @@ -tool -class_name Voxel, "res://addons/voxel-core/assets/classes/voxel.png" -extends Object -# Utility class containing various properties and methods to do with voxels. -# -# Voxel Schema: -# Every voxel is a Dictionary, not every Dictionary is a voxel, only by following -# the voxel scheme indicated below can wide varieties of voxels be produced. -# Note that voxel dictionaries may have additions, but they must be done in such -# a way as to respect the original structure so as to avoid conflicts. -# -# { -# name : String ~ Used in VoxelSets, should always be lowercase -# color : Color ~ Default color used for all voxel faces, if not present fallback is Transparent color -# colors : Dictionary = { ~ Color used on a per face bases, if not present fallback is voxel color -# Vector3.UP : Color -# Vector3.DOWN : Color -# Vector3.RIGHT : Color -# Vector3.LEFT : Color -# Vector3.FORWARD : Color -# Vector3.BACK : Color -# } -# uv : Vector2 ~ Default uv position used for all voxel faces, if not present fallback is (-1.0, -1.0) -# uvs : Dictionary = { ~ uv position used on a per face bases, if not present fallback to voxel uv -# Vector3.UP : Vector2 -# Vector3.DOWN : Vector2 -# Vector3.RIGHT : Vector2 -# Vector3.LEFT : Vector2 -# Vector3.FORWARD : Vector2 -# Vector3.BACK : Vector2 -# } -# metallic : float ~ Metallic value used for all voxel face's material, must be between 0.0 and 1.0 and if not present fallback is 0.0 -# specular : float ~ Specular value used for all voxel faces, must be between 0.0 and 1.0 and if not present fallback is 0.5 -# roughness : float ~ Roughness value used for all voxel faces, must be between 0.0 and 1.0 and if not present fallback is 1.0 -# energy : float ~ Emission energy value used for all voxel faces, must be between 0.0 and 16.0 and if not present fallback is 0.0 -# energy_color : Color ~ Emission color used for all voxel faces, if not present fallback is white -# material : int ~ ID of the VoxelSet material used for this voxel, if not present fallback is -1 -# } -# - - - -## Constants -# Lists of all voxel faces, and their adjacent directions -const Faces := { - Vector3.RIGHT: [ Vector3.FORWARD, Vector3.BACK, Vector3.DOWN, Vector3.UP ], - Vector3.UP: [ Vector3.LEFT, Vector3.RIGHT, Vector3.FORWARD, Vector3.BACK ], - Vector3.FORWARD: [ Vector3.LEFT, Vector3.RIGHT, Vector3.DOWN, Vector3.UP ], - Vector3.LEFT: [ Vector3.FORWARD, Vector3.BACK, Vector3.DOWN, Vector3.UP ], - Vector3.DOWN: [ Vector3.LEFT, Vector3.RIGHT, Vector3.FORWARD, Vector3.BACK ], - Vector3.BACK: [ Vector3.LEFT, Vector3.RIGHT, Vector3.DOWN, Vector3.UP ], -} - -# 0.5 means that voxels will have the dimensions of 0.5 x 0.5 x 0.5 -const VoxelWorldSize := 0.5 - - - -## Public Methods -# Returns Dictionary representation of a colored voxel -# color : Color : color to set -# colors : Dictionary<Vector3, Color> : face colors to set -# return : Dictionary<String, Variant> : Dictionary representing voxel -static func colored(color : Color, colors := {}) -> Dictionary: - var voxel = {} - voxel["color"] = color - if not colors.empty(): - voxel["colors"] = colors.duplicate() - return voxel - - -# Returns true if voxel has color defined -static func has_color(voxel : Dictionary) -> bool: - return voxel.has("color") - - -# Returns the defined color within given voxel if present, otherwise returns transparent color -static func get_color(voxel : Dictionary) -> Color: - return voxel.get("color", Color.transparent) - - -# Sets the given color to the given voxel -static func set_color(voxel : Dictionary, color : Color) -> void: - voxel["color"] = color - - -# Returns true if voxel has specified color at given face -static func has_face_color(voxel : Dictionary, face : Vector3) -> bool: - return voxel.has("colors") and voxel["colors"].has(face) - - -# Returns the defined color at given face if present, otherwise returns color -static func get_face_color(voxel : Dictionary, face : Vector3) -> Color: - return voxel["colors"].get(face, get_color(voxel)) if voxel.has("colors") else get_color(voxel) - - -# Sets the given color at the given face to the given voxel -static func set_face_color(voxel : Dictionary, face : Vector3, color : Color) -> void: - if not voxel.has("colors"): voxel["colors"] = {} - voxel["colors"][face] = color - - -# Removes color at given face from given voxel -static func remove_face_color(voxel : Dictionary, face : Vector3) -> void: - if voxel.has("colors"): - voxel["colors"].erase(face) - if voxel["colors"].empty(): - voxel.erase("colors") - - -# Returns Dictionary representation of a uvd voxel -# uv : Vector2 : uv to set -# uvs : Dictionary<Vector3, Vector2> : face uv to set -# color : Color : color to set -# colors : Dictionary<Vector3, Color> : face colors to set -# return : Dictionary<String, Variant> : Dictionary representing voxel -static func uvd(uv : Vector2, uvs := {}, color := Color.white, colors := {}) -> Dictionary: - var voxel = colored(color, colors) - voxel["uv"] = uv - if not uvs.empty(): - voxel["uvs"] = uvs - return voxel - - -# Returns true if voxel has uv defined -static func has_uv(voxel : Dictionary) -> bool: - return voxel.has("uv") - - -# Returns the defined uv within given voxel if present, otherwise returns a negative vector -static func get_uv(voxel : Dictionary) -> Vector2: - return voxel.get("uv", -Vector2.ONE) - - -# Sets the given uv to the given voxel -static func set_uv(voxel : Dictionary, uv : Vector2) -> void: - voxel["uv"] = uv - - -# Removes uv from given voxel -static func remove_uv(voxel : Dictionary) -> void: - voxel.erase("uv") - - -# Returns true if voxel has specified uv at given face -static func has_face_uv(voxel : Dictionary, face : Vector3) -> bool: - return voxel.has("uvs") and voxel["uvs"].has(face) - - -# Returns the defined uv at given face if present, otherwise returns uv -static func get_face_uv(voxel : Dictionary, face : Vector3) -> Vector2: - return voxel["uvs"].get(face, get_uv(voxel)) if voxel.has("uvs") else get_uv(voxel) - - -# Sets the given uv at the given face to the given voxel -static func set_face_uv(voxel : Dictionary, face : Vector3, uv : Vector2) -> void: - if not voxel.has("uvs"): - voxel["uvs"] = {} - voxel["uvs"][face] = uv - - -# Removes uv at given face from given voxel -static func remove_face_uv(voxel : Dictionary, face : Vector3) -> void: - if voxel.has("uvs"): - voxel["uvs"].erase(face) - if voxel["uvs"].empty(): - voxel.erase("uvs") - - -# Returns true if given name is valid -static func is_valid_name(name : String) -> bool: - return not name.empty() - - -# Returns the defined name within given voxel if present, otherwise returns an empty string -static func get_name(voxel : Dictionary) -> String: - return voxel.get("name", "") - - -# Sets the given name to the given voxel -static func set_name(voxel : Dictionary, name : String) -> void: - voxel["name"] = name.to_lower() - - -# Removes name from given voxel -static func remove_name(voxel : Dictionary) -> void: - voxel.erase("name") - - -# Returns the defined metallic within given voxel if present, otherwise returns 0 -static func get_metallic(voxel : Dictionary) -> float: - return voxel.get("metallic", 0.0) - - -# Sets the given metallic to the given voxel -static func set_metallic(voxel : Dictionary, metallic : float) -> void: - voxel["metallic"] = metallic - - -# Removes metallic from given voxel -static func remove_metallic(voxel : Dictionary) -> void: - voxel.erase("metallic") - - -# Returns the defined specular within given voxel if present, otherwise returns 0.5 -static func get_specular(voxel : Dictionary) -> float: - return voxel.get("specular", 0.5) - - -# Sets the given specular to the given voxel -static func set_specular(voxel : Dictionary, specular : float) -> void: - voxel["specular"] = specular - - -# Removes specular from given voxel -static func remove_specular(voxel : Dictionary) -> void: - voxel.erase("specular") - - -# Returns the defined roughness within given voxel if present, otherwise returns 1 -static func get_roughness(voxel : Dictionary) -> float: - return voxel.get("roughness", 1.0) - - -# Sets the given roughness to the given voxel -static func set_roughness(voxel : Dictionary, roughness : float) -> void: - voxel["roughness"] = roughness - - -# Removes roughness from given voxel -static func remove_roughness(voxel : Dictionary) -> void: - voxel.erase("roughness") - - -# Returns the defined energy within given voxel if present, otherwise returns 0 -static func get_energy(voxel : Dictionary) -> float: - return voxel.get("energy", 0.0) - - -# Sets the given energy to the given voxel -static func set_energy(voxel : Dictionary, energy : float) -> void: - voxel["energy"] = energy - - -# Removes energy from given voxel -static func remove_energy(voxel : Dictionary) -> void: - voxel.erase("energy") - - -# Returns the defined energy_color within given voxel if present, otherwise returns Color.white -static func get_energy_color(voxel : Dictionary) -> Color: - return voxel.get("energy_color", Color.white) - - -# Sets the given energy_color to the given voxel -static func set_energy_color(voxel : Dictionary, energy_color : Color) -> void: - voxel["energy_color"] = energy_color - - -# Removes energy_color from given voxel -static func remove_energy_color(voxel : Dictionary) -> void: - voxel.erase("energy_color") - - -# Returns the defined material within given voxel if present, otherwise returns -1 -static func get_material(voxel : Dictionary) -> int: - return voxel.get("material", -1) - - -# Sets the given material to the given voxel -static func set_material(voxel : Dictionary, material : int) -> void: - voxel["material"] = material - - -# Removes material from given voxel -static func remove_material(voxel : Dictionary) -> void: - voxel.erase("material") - - -# Removes unnecessary properties of given voxel in accordance to Voxel schema -static func clean(voxel : Dictionary) -> void: - if not is_valid_name(get_name(voxel)): - remove_name(voxel) - - if get_uv(voxel) == get_uv({}): - remove_uv(voxel) - - for face in Faces: - if get_face_color(voxel, face) == get_color({}): - remove_face_color(voxel, face) - if get_face_uv(voxel, face) == get_uv({}): - remove_face_uv(voxel, face) - - if get_material(voxel) == get_material({}): - remove_material(voxel) - - if get_metallic(voxel) == get_metallic({}): - remove_metallic(voxel) - - if get_specular(voxel) == get_specular({}): - remove_specular(voxel) - - if get_roughness(voxel) == get_roughness({}): - remove_roughness(voxel) - - if get_energy(voxel) == get_energy({}): - remove_energy(voxel) - - if get_energy_color(voxel) == get_energy_color({}): - remove_energy_color(voxel) - - -# Returns the world position as snapped world position -static func world_to_snapped(world : Vector3) -> Vector3: - return (world / VoxelWorldSize).floor() * VoxelWorldSize - - -# Returns the snapped world position as voxel grid position -static func snapped_to_grid(snapped : Vector3) -> Vector3: - return snapped / VoxelWorldSize - - -# Returns world position as voxel grid position -static func world_to_grid(world : Vector3) -> Vector3: - return snapped_to_grid(world_to_snapped(world)) - - -# Returns voxel grid position as snapped world position -static func grid_to_snapped(grid : Vector3) -> Vector3: - return grid * VoxelWorldSize diff --git a/addons/voxel-core/classes/voxel_mesh.gd b/addons/voxel-core/classes/voxel_mesh.gd deleted file mode 100644 index 0191deb..0000000 --- a/addons/voxel-core/classes/voxel_mesh.gd +++ /dev/null @@ -1,124 +0,0 @@ -tool -class_name VoxelMesh, "res://addons/voxel-core/assets/classes/voxel_mesh.png" -extends "res://addons/voxel-core/classes/voxel_object.gd" -# The most basic voxel visualization object, for a moderate amount of voxels. - - - -## Private Variables -# Used voxels, Dictionary<Vector3, int> -var _voxels := {} - - - -## Built-In Virtual Methods -func _get(property : String): - if property == "VOXELS": - return _voxels - - -func _set(property : String, value): - if property == "VOXELS": - _voxels = value - return true - return false - - -func _get_property_list(): - var properties = [] - - properties.append({ - "name": "VOXELS", - "type": TYPE_DICTIONARY, - "hint": PROPERTY_HINT_NONE, - "usage": PROPERTY_USAGE_STORAGE, - }) - - return properties - - - -## Public Methods -func empty() -> bool: - return _voxels.empty() - - -func set_voxel(grid : Vector3, voxel : int) -> void: - _voxels[grid] = voxel - - -func set_voxels(voxels : Dictionary) -> void: - erase_voxels() - _voxels = voxels - - -func get_voxel_id(grid : Vector3) -> int: - return _voxels.get(grid, -1) - - -func get_voxels() -> Array: - return _voxels.keys() - - -func erase_voxel(grid : Vector3) -> void: - _voxels.erase(grid) - - -func erase_voxels() -> void: - _voxels.clear() - - -func update_mesh() -> void: - if not _voxels.empty(): - var vt := VoxelTool.new() - var materials := {} - if is_instance_valid(mesh) and mesh is ArrayMesh: - for index in get_surface_material_count(): - var material := get_surface_material(index) - if is_instance_valid(material): - materials[mesh.surface_get_name(index)] = material - - match MeshModes.NAIVE if edit_hint > 0 else mesh_mode: - MeshModes.GREEDY: - mesh = greed_volume(_voxels.keys(), vt) - _: - mesh = naive_volume(_voxels.keys(), vt) - - for material_name in materials: - var material_index = mesh.surface_find_by_name(material_name) - if material_index > -1: - set_surface_material(material_index, materials[material_name]) - else: - mesh = null - .update_mesh() - - -func update_static_body() -> void: - var staticBody = get_node_or_null("StaticBody") - - if (edit_hint >= 2 or static_body) and is_instance_valid(mesh): - if not is_instance_valid(staticBody): - staticBody = StaticBody.new() - staticBody.set_name("StaticBody") - add_child(staticBody) - - var collisionShape - if staticBody.has_node("CollisionShape"): - collisionShape = staticBody.get_node("CollisionShape") - else: - collisionShape = CollisionShape.new() - collisionShape.set_name("CollisionShape") - staticBody.add_child(collisionShape) - collisionShape.shape = mesh.create_trimesh_shape() - - if static_body and not staticBody.owner: - staticBody.set_owner(get_tree().get_edited_scene_root()) - elif not static_body and staticBody.owner: - staticBody.set_owner(null) - if static_body and not collisionShape.owner: - collisionShape.set_owner(get_tree().get_edited_scene_root()) - elif not static_body and staticBody.owner: - collisionShape.set_owner(null) - elif is_instance_valid(staticBody): - remove_child(staticBody) - staticBody.queue_free() diff --git a/addons/voxel-core/classes/voxel_object.gd b/addons/voxel-core/classes/voxel_object.gd deleted file mode 100644 index 8d12633..0000000 --- a/addons/voxel-core/classes/voxel_object.gd +++ /dev/null @@ -1,501 +0,0 @@ -tool -extends MeshInstance -# Makeshift interface class inhereted by all voxel visualization objects. - - - -## Signals -# Emitted when VoxelSet is changed -signal set_voxel_set(voxel_set) - - - -## Enums -# Defines the modes in which Mesh can be constructed -enum MeshModes { - # Naive meshing, simple culling of voxel faces; http://web.archive.org/web/20200428085802/https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/ - NAIVE, - # Greedy meshing, culls and merges similar voxel faces; http://web.archive.org/web/20201112011204/https://www.gedge.ca/dev/2014/08/17/greedy-voxel-meshing - GREEDY, - # Marching Cubes meshing, https://en.wikipedia.org/wiki/Marching_cubes - #MARCHING_CUBES, - # Transvoxel meshing, http://web.archive.org/web/20201112033736/http://transvoxel.org/ - #TRANSVOXEL, -} - - - -## Exported Variables -# The meshing mode by which Mesh is generated -export(MeshModes) var mesh_mode := MeshModes.NAIVE setget set_mesh_mode - -# Flag indicating that UV Mapping should be applied when generating meshes if applicable -export var uv_map := false setget set_uv_map - -# Flag indicating the persitant attachment and maintenance of a StaticBody -export var static_body := false setget set_static_body - -# The VoxelSet for this VoxelObject -export(Resource) var voxel_set = null setget set_voxel_set - - - -## Public Variables -# Flag indicating that edits to voxel data will be frequent -# NOTE: When true will only allow naive meshing -var edit_hint := 0 setget set_edit_hint - - - -# Public Methods -# Sets the EditHint flag, calls update_mesh if needed and not told otherwise -func set_edit_hint(value : int, update := is_inside_tree()) -> void: - edit_hint = value - - if update: - update_mesh() - - -# Sets the mesh_mode, calls update_mesh if needed and not told otherwise -func set_mesh_mode(value : int, update := is_inside_tree()) -> void: - mesh_mode = value - - if update: - update_mesh() - - -# Sets the uv_map, calls update_mesh if needed and not told otherwise -func set_uv_map(value : bool, update := is_inside_tree()) -> void: - uv_map = value - - if update: - update_mesh() - - -# Sets static_body, calls update_static_body if needed and not told otherwise -func set_static_body(value : bool, update := is_inside_tree()) -> void: - static_body = value - - if update: - update_static_body() - - -# Sets voxel_set, calls update_mesh if needed and not told otherwise -func set_voxel_set(value : Resource, update := is_inside_tree()) -> void: - if not (typeof(value) == TYPE_NIL or value is VoxelSet): - printerr("Invalid Resource given expected VoxelSet") - return - - if is_instance_valid(voxel_set): - if voxel_set.is_connected("requested_refresh", self, "update_mesh"): - voxel_set.disconnect("requested_refresh", self, "update_mesh") - - voxel_set = value - if is_instance_valid(voxel_set): - if not voxel_set.is_connected("requested_refresh", self, "update_mesh"): - voxel_set.connect("requested_refresh", self, "update_mesh") - - if update: - update_mesh() - emit_signal("set_voxel_set", voxel_set) - - -# Return true if no voxels are present -func empty() -> bool: - return true - - -# Sets given voxel id at the given grid position -func set_voxel(grid : Vector3, voxel_id : int) -> void: - pass - - -# Replace current voxel data with given voxel data -# voxels : Dictionary<Vector3, int> : voxels to set -func set_voxels(voxels : Dictionary) -> void: - erase_voxels() - for grid in voxels: - set_voxel(grid, voxels[grid]) - - -# Returns voxel id at given grid position if present; otherwise returns -1 -func get_voxel_id(grid : Vector3) -> int: - return -1 - - -# Returns voxel Dictionary representing voxel id at given grid position -func get_voxel(grid : Vector3) -> Dictionary: - return voxel_set.get_voxel(get_voxel_id(grid)) - - -# Returns Array of all voxel grid positions -# return : Array<Vector3> : Array of Vector3 each represents a grid position of a voxel -func get_voxels() -> Array: - return [] - - -# Erase voxel id at given grid position -func erase_voxel(grid : Vector3) -> void: - pass - - -# Erase all voxels -func erase_voxels() -> void: - for grid in get_voxels(): - erase_voxel(grid) - - -# Returns 3D axis-aligned bounding box -# volume : Array<Vector3> : Array of grid positions from which to calculate bounds -# return : Dictionary : bounding box, contains: { position : Vector3, size: Vector3 } -func get_box(volume := get_voxels()) -> Dictionary: - var box := { "position": Vector3.ZERO, "size": Vector3.ZERO } - - if not volume.empty(): - box["position"] = Vector3.INF - box["size"] = -Vector3.INF - - for voxel_grid in volume: - if voxel_grid.x < box["position"].x: - box["position"].x = voxel_grid.x - if voxel_grid.y < box["position"].y: - box["position"].y = voxel_grid.y - if voxel_grid.z < box["position"].z: - box["position"].z = voxel_grid.z - - if voxel_grid.x > box["size"].x: - box["size"].x = voxel_grid.x - if voxel_grid.y > box["size"].y: - box["size"].y = voxel_grid.y - if voxel_grid.z > box["size"].z: - box["size"].z = voxel_grid.z - - box["size"] = (box["size"] - box["position"]).abs() + Vector3.ONE - - return box - - -# Moves voxels in given volume by given translation -# translation : Vector3 : translation to move voxels by -# volume : Array<Vector3> : Array of grid positions representing voxels to move -func move(translation := Vector3(), volume := get_voxels()) -> void: - var translated := {} - for voxel_grid in volume: - translated[voxel_grid + translation] = get_voxel_id(voxel_grid) - erase_voxel(voxel_grid) - for voxel_grid in translated: - set_voxel(voxel_grid, translated[voxel_grid]) - - -# Centers voxels in given volume with respect to axis origin with the given alignment -# alignment : Vector3 : Alignment to center voxels by -# volume : Array<Vector3> : Array of grid positions representing voxels to center -func center(alignment := Vector3(0.5, 0.5, 0.5), volume := get_voxels()) -> void: - move(vec_to_center(alignment, volume), volume) - - -# Flips voxels in given volume over set axis -func flip(x : bool, y : bool, z : bool, volume := get_voxels()) -> void: - var flipped := {} - for voxel_grid in volume: - flipped[Vector3( - (voxel_grid.x + (1 if z else 0)) * (-1 if z else 1), - (voxel_grid.y + (1 if y else 0)) * (-1 if y else 1), - (voxel_grid.z + (1 if x else 0)) * (-1 if x else 1))] = get_voxel_id(voxel_grid) - erase_voxel(voxel_grid) - for voxel_grid in flipped: - set_voxel(voxel_grid, flipped[voxel_grid]) - - -# Returns the translation necessary to center given volume by -# alignment : Vector3 : Alignment to center voxels by -# volume : Array<Vector3> : Array of grid positions representing voxels to center -# return : Vector3 : Translation necessary to center -func vec_to_center(alignment := Vector3(0.5, 0.5, 0.5), volume := get_voxels()) -> Vector3: - var box := get_box(volume) - alignment = Vector3.ONE - Vector3( - clamp(alignment.x, 0.0, 1.0), - clamp(alignment.y, 0.0, 1.0), - clamp(alignment.z, 0.0, 1.0)) - return -box["position"] - (box["size"] * alignment).floor() - -# A Fast Voxel Traversal Algorithm for Ray Tracing, by John Amanatides -# Algorithm paper: https://web.archive.org/web/20201108160724/http://www.cse.chalmers.se/edu/year/2010/course/TDA361/grid.pdf -# from : Vector3 : World position from which to start raycast -# direction : Vector3 : Direction of raycast -# max_distance : int : Maximum distance of ray cast -# stop : FuncRef : Calls on function, that receives "hit" and returns bool, as raycast is projected, if it returns true raycast is returned -# return : Dictionary<String, Vector3> : If voxel is "hit", returns Dictionary with grid position and face normal; else empty -func intersect_ray( - from : Vector3, - direction : Vector3, - max_distance := 64, - stop : FuncRef = null) -> Dictionary: - var hit := { - "normal": Vector3(), - } - var grid := Voxel.world_to_grid(from) - var step := Vector3( - 1 if direction.x > 0 else -1, - 1 if direction.y > 0 else -1, - 1 if direction.z > 0 else -1) - var t_delta := direction.inverse().abs() - var dist := from.distance_to(Voxel.world_to_snapped(from)) - var t_max := t_delta * dist - var step_index := -1 - - var t = 0.0 - var valid := false - while t < max_distance: - hit["position"] = grid - hit["normal"].x = -step.x if step_index == 0 else 0 - hit["normal"].y = -step.y if step_index == 1 else 0 - hit["normal"].z = -step.z if step_index == 2 else 0 - if get_voxel_id(grid) > -1 or (is_instance_valid(stop) and stop.call_func(hit)): - valid = true - break - - match t_max.min_axis(): - Vector3.AXIS_X: - grid.x += step.x - t = t_max.x - t_max.x += t_delta.x - step_index = 0 - Vector3.AXIS_Y: - grid.y += step.y - t = t_max.y - t_max.y += t_delta.y - step_index = 1 - Vector3.AXIS_Z: - grid.z += step.z - t = t_max.z - t_max.z += t_delta.z - step_index = 2 - if not valid: - hit.clear() - return hit - - -# Returns Array of all voxel grid positions connected to given target -# target : Vector3 : Grid position at which to start flood select -# selected : Array : Array to add selected voxel grid positions to -# return : Array<Vector3> : Array of all voxel grid positions connected to given target -func select_flood(target : Vector3, selected := []) -> Array: - selected.append(get_voxel_id(target)) - - for direction in Voxel.Faces: - var next = target + direction - if get_voxel_id(next) == get_voxel_id(selected[0]): - if not selected.has(next): - select_flood(next, selected) - - return selected - - -# Returns Array of all voxel grid positions connected to given target that aren't obstructed at the given face normal -# target : Vector3 : Grid position at which to start flood select -# face_normal : Vector3 : Normal of face to check for obstruction -# selected : Array : Array to add selected voxel grid positions to -# return : Array<Vector3> : Array of all voxel grid positions connected to given target -func select_face(target : Vector3, face_normal : Vector3, selected := []) -> Array: - selected.append(target) - - for direction in Voxel.Faces[face_normal]: - var next = target + direction - if get_voxel_id(next) > -1: - if get_voxel_id(next + face_normal) == -1: - if not selected.has(next): - select_face(next, face_normal, selected) - - return selected - - -# Returns Array of all voxel grid positions connected to given target that are similar and aren't obstructed at the given face normal -# target : Vector3 : Grid position at which to start flood select -# face_normal : Vector3 : Normal of face to check for obstruction -# selected : Array : Array to add selected voxel grid positions to -# return : Array<Vector3> : Array of all voxel grid positions connected to given target -func select_face_similar(target : Vector3, face_normal : Vector3, selected := []) -> Array: - selected.append(target) - - for direction in Voxel.Faces[face_normal]: - var next = target + direction - if get_voxel_id(next) == get_voxel_id(selected[0]): - if get_voxel_id(next + face_normal) == -1: - if not selected.has(next): - select_face_similar(next, face_normal, selected) - - return selected - - -# Loads and sets voxels and replaces VoxelSet with given file -# NOTE: Reference Reader.gd for valid file imports -# source_file : String : Path to file to be loaded -# new_voxel_set : bool : If true new VoxelSet is created, else overwrite current one -# return int : int : Error code -func load_file(source_file : String, new_voxel_set := true) -> int: - var read := Reader.read_file(source_file) - var error : int = read.get("error", FAILED) - if error == OK: - if new_voxel_set or not is_instance_valid(voxel_set): - set_voxel_set(VoxelSet.new(), false) - voxel_set.set_voxels(read["palette"]) - - set_voxels(read["voxels"]) - return error - - -# Makes a naive mesh out of volume of voxels given -# volume : Array<Vector3> : Array of grid positions representing volume of voxels from which to buid ArrayMesh -# vt : VoxelTool : VoxelTool with which ArrayMesh will be built -# return : ArrayMesh : Naive voxel mesh -func naive_volume(volume : Array, vt := VoxelTool.new()) -> ArrayMesh: - if not is_instance_valid(voxel_set): - return null - - vt.begin(voxel_set, uv_map) - - for position in volume: - for direction in Voxel.Faces: - if get_voxel_id(position + direction) == -1: - vt.add_face(get_voxel(position), direction, position) - - return vt.commit() - - -# Greedy meshing -# volume : Array<Vector3> : Array of grid positions representing volume of voxels from which to buid ArrayMesh -# vt : VoxelTool : VoxelTool with which ArrayMesh will be built -# return : ArrayMesh : Greedy voxel mesh -func greed_volume(volume : Array, vt := VoxelTool.new()) -> ArrayMesh: - if not is_instance_valid(voxel_set): - return null - - vt.begin(voxel_set, uv_map) - - var faces = Voxel.Faces.duplicate() - for face in faces: - faces[face] = [] - for position in volume: - if get_voxel_id(position + face) == -1: - faces[face].append(position) - - for face in faces: - while not faces[face].empty(): - var bottom_right : Vector3 = faces[face].pop_front() - var bottom_left : Vector3 = bottom_right - var top_right : Vector3 = bottom_right - var top_left : Vector3 = bottom_right - var voxel : Dictionary = get_voxel(bottom_right) - - - if not uv_map or Voxel.get_face_uv(voxel, face) == -Vector2.ONE: - var width := 1 - - while true: - var index = faces[face].find(top_right + Voxel.Faces[face][1]) - if index > -1: - var _voxel = get_voxel(faces[face][index]) - if Voxel.get_face_color(_voxel, face) == Voxel.get_face_color(voxel, face) and (not uv_map or Voxel.get_face_uv(_voxel, face) == -Vector2.ONE): - width += 1 - faces[face].remove(index) - top_right += Voxel.Faces[face][1] - bottom_right += Voxel.Faces[face][1] - else: - break - else: - break - - while true: - var index = faces[face].find(top_left + Voxel.Faces[face][0]) - if index > -1: - var _voxel = get_voxel(faces[face][index]) - if Voxel.get_face_color(_voxel, face) == Voxel.get_face_color(voxel, face) and (not uv_map or Voxel.get_face_uv(_voxel, face) == -Vector2.ONE): - width += 1 - faces[face].remove(index) - top_left += Voxel.Faces[face][0] - bottom_left += Voxel.Faces[face][0] - else: - break - else: - break - - while true: - var used := [] - var current := top_right - var index = faces[face].find(current + Voxel.Faces[face][3]) - if index > -1: - var _voxel = get_voxel(faces[face][index]) - if Voxel.get_face_color(_voxel, face) == Voxel.get_face_color(voxel, face) and (not uv_map or Voxel.get_face_uv(_voxel, face) == -Vector2.ONE): - current += Voxel.Faces[face][3] - used.append(current) - while true: - index = faces[face].find(current + Voxel.Faces[face][0]) - if index > -1: - _voxel = get_voxel(faces[face][index]) - if Voxel.get_face_color(_voxel, face) == Voxel.get_face_color(voxel, face) and (not uv_map or Voxel.get_face_uv(_voxel, face) == -Vector2.ONE): - current += Voxel.Faces[face][0] - used.append(current) - else: - break - else: - break - if used.size() == width: - top_right += Voxel.Faces[face][3] - top_left += Voxel.Faces[face][3] - for use in used: - faces[face].erase(use) - else: - break - else: - break - else: - break - - while true: - var used := [] - var current := bottom_right - var index = faces[face].find(current + Voxel.Faces[face][2]) - if index > -1: - var _voxel = get_voxel(faces[face][index]) - if Voxel.get_face_color(_voxel, face) == Voxel.get_face_color(voxel, face) and (not uv_map or Voxel.get_face_uv(_voxel, face) == -Vector2.ONE): - current += Voxel.Faces[face][2] - used.append(current) - while true: - index = faces[face].find(current + Voxel.Faces[face][0]) - if index > -1: - _voxel = get_voxel(faces[face][index]) - if Voxel.get_face_color(_voxel, face) == Voxel.get_face_color(voxel, face) and (not uv_map or Voxel.get_face_uv(_voxel, face) == -Vector2.ONE): - current += Voxel.Faces[face][0] - used.append(current) - else: - break - else: - break - if used.size() == width: - bottom_right += Voxel.Faces[face][2] - bottom_left += Voxel.Faces[face][2] - for use in used: - faces[face].erase(use) - else: - break - else: - break - else: - break - - vt.add_face(voxel,face, - bottom_right, bottom_left, top_right, top_left) - - return vt.commit() - - -# Updates Mesh and calls on save and update_static_body if needed -# save : bool : Save voxels on update -func update_mesh() -> void: - update_static_body() - - -# Sets and updates StaticMesh if demanded -func update_static_body() -> void: - pass diff --git a/addons/voxel-core/classes/voxel_set.gd b/addons/voxel-core/classes/voxel_set.gd deleted file mode 100644 index d0bccac..0000000 --- a/addons/voxel-core/classes/voxel_set.gd +++ /dev/null @@ -1,234 +0,0 @@ -tool -class_name VoxelSet, "res://addons/voxel-core/assets/classes/voxel_set.png" -extends Resource -# Library of Voxels used by VoxelObjects. - - - -## Signals -# Emitted on request_refresh -signal requested_refresh - - - -## Exported Variables -# Size of each tile in tiles in pixels -export var tile_size := Vector2(32.0, 32.0) setget set_tile_size - -# Texture used for tiles / uv mapping -export var tiles : Texture = null setget set_tiles - -# Materials used by voxels -export(Array, Material) var materials := [ - SpatialMaterial.new(), -] setget set_materials - - - -## Private Variables -# Voxels stored by their id -var _voxels := [] - -# Flag indicating whether _uv_scale, tile_size and tiles texture is set -var _uv_ready := false - -# World UV Scale, calculated on request_refresh -var _uv_scale := Vector2.ONE - - - -## Built-In Virtual Methods -func _get(property : String): - if property == "VOXELS": - return _voxels - - -func _set(property : String, value) -> bool: - if property == "VOXELS": - if typeof(value) == TYPE_DICTIONARY: - for key in value: - var voxel : Dictionary = value[key] - if voxel.has("vsn"): - Voxel.set_name(voxel, voxel["vsn"]) - voxel.erase("vsn") - _voxels.append(value[key]) - else: - _voxels = value - return true - return false - - -func _get_property_list(): - var properties = [] - - properties.append({ - "name": "VOXELS", - "type": TYPE_ARRAY, - "hint": PROPERTY_HINT_NONE, - "usage": PROPERTY_USAGE_STORAGE, - }) - - return properties - - - -## Public Methods -# Sets tile_size, calls on request_refresh by default -func set_tile_size(value : Vector2, refresh := true) -> void: - tile_size = Vector2( - floor(clamp(value.x, 1, 256)), - floor(clamp(value.y, 1, 256))) - - if refresh: - request_refresh() - - -# Sets tiles, calls on request_refresh by default -func set_tiles(value : Texture, refresh := true) -> void: - tiles = value - - if refresh: - request_refresh() - - -# Sets materials used by voxels in VoxelSet -func set_materials(values : Array, refresh := true) -> void: - for index in range(values.size()): - var material = values[index] - if is_instance_valid(material) and not (material is SpatialMaterial or material is ShaderMaterial): - printerr("VoxelSet : Expected Spatial or Shader material got " + str(material)) - values[index] = null - - if values.empty(): - materials.resize(1) - else: - materials = values - property_list_changed_notify() - - if refresh: - request_refresh() - - -# Returns VoxelSet material with id if present, otherwise returns null -func get_material(id : int) -> Material: - return materials[id] if id > -1 and id < materials.size() else null - - -# Returns number of voxels in VoxelSet -func size() -> int: - return _voxels.size() - - -# Returns true if VoxelSet has no voxels -func empty() -> bool: - return _voxels.empty() - - -# Returns true if VoxelSet has voxel with given id -func has_id(id : int) -> bool: - return id > -1 and id < _voxels.size() - - -# Returns true if VoxelSet has everything necessary for uv mapping -func uv_ready() -> bool: - return _uv_ready - - -# Returns the uv scale -func uv_scale() -> Vector2: - return _uv_scale - - -# Returns true if given id is valid -static func is_valid_id(id : int) -> bool: - return id > -1 - - -# Returns a list of all the voxel ids -# returns : Array<int> : contained voxel ids -func get_ids() -> Array: - return range(_voxels.size()) - - -# Returns name associated with the given id, returns a empty string if id isn't found -func id_to_name(id : int) -> String: - return Voxel.get_name(get_voxel(id)) - - -# Returns the id of the voxel with the given name, returns -1 if not found -func name_to_id(name : String) -> int: - name = name.to_lower() - for id in get_ids(): - if id_to_name(id) == name: - return id - return -1 - - -# Appends voxel to end of VoxelSet -func add_voxel(voxel : Dictionary) -> void: - _voxels.append(voxel) - - -# Sets the voxel at given id -func set_voxel(id : int, voxel : Dictionary) -> void: - if not has_id(id): - printerr("VoxelSet : given id `" + str(id) + "` is out of range") - return - - _voxels[id] = voxel - - -# Insert voxel with given id -func insert_voxel(id : int, voxel : Dictionary) -> void: - if id < -1 and id > _voxels.size(): - printerr("VoxelSet : given id `" + str(id) + "` is out of range") - return - - _voxels.insert(id, voxel) - - -# Replaces all _voxels -func set_voxels(voxels : Array) -> void: - _voxels = voxels - - -# Gets voxel Dictionary by their id, returns an empty Dictionary if not found -func get_voxel(id : int) -> Dictionary: - return _voxels[id] if has_id(id) else {} - - -# Erase voxel from VoxelSet -func erase_voxel(id : int) -> void: - _voxels.remove(id) - - -# Erases all voxels in VoxelSet -func erase_voxels() -> void: - _voxels.clear() - - -# Should be called when noticable changes have been committed to voxels. -# Emits requested_refresh, calculates _uv_scale and updates _uv_ready -func request_refresh() -> void: - _uv_ready = is_instance_valid(tiles) - if _uv_ready: - _uv_scale = Vector2.ONE / (tiles.get_size() / tile_size) - else: - _uv_scale = Vector2.ONE - emit_signal("requested_refresh") - - -# Loads file's content as voxels -# NOTE: Reference Reader.gd for valid file imports -# source_file : String : Path to file to be loaded -# return int : int : Error code -func load_file(source_file : String, append := false) -> int: - var read := Reader.read_file(source_file) - var error : int = read.get("error", FAILED) - if error == OK: - if append: - for voxel in read["palette"]: - add_voxel(voxel) - else: - set_voxels(read["palette"]) - return error diff --git a/addons/voxel-core/classes/voxel_tool.gd b/addons/voxel-core/classes/voxel_tool.gd deleted file mode 100644 index bba14aa..0000000 --- a/addons/voxel-core/classes/voxel_tool.gd +++ /dev/null @@ -1,227 +0,0 @@ -tool -class_name VoxelTool -extends Reference -# Used to construct a Mesh with provided VoxelSet -# and by specifying voxel faces individually. - - - -class Surface: - ## Public Variables - # Index of the last vertex in Mesh being constructed - var index : int - - var material : SpatialMaterial - - # SurfaceTool used to construct Mesh - var surface_tool : SurfaceTool - - - - ## Built-In Virtual Methods - func _init() -> void: - index = 0 - surface_tool = SurfaceTool.new() - surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES) - - - -## Private Variables -# Flag indicating whether uv mapping should be applied to constructed mesh -var _uv_voxels := false - -# Contains Surfaces being constructed -var _surfaces := {} - -# VoxelSet used when constructing Mesh, is set on begin -var _voxel_set : VoxelSet = null - - - -## Public Methods -# Called before constructing mesh, takes the VoxelSet with which Mesh will be constructed -func begin(voxel_set : VoxelSet = null, uv_voxels := false) -> void: - clear() - _uv_voxels = uv_voxels and voxel_set.uv_ready() - _voxel_set = voxel_set - - -# Clear all information -func clear() -> void: - _uv_voxels = false - _surfaces.clear() - _voxel_set = null - - -# Returns a constructed ArrayMesh -func commit() -> ArrayMesh: - var mesh := ArrayMesh.new() - for surface_id in _surfaces: - var surface : Surface = _surfaces[surface_id] - var submesh = surface.surface_tool.commit_to_arrays() - mesh.add_surface_from_arrays( - Mesh.PRIMITIVE_TRIANGLES, - submesh) - mesh.surface_set_name(mesh.get_surface_count() - 1, surface_id) - mesh.surface_set_material(mesh.get_surface_count() - 1, surface.material) - clear() - return mesh - - -# Adds a voxel face to Mesh with given vertex positions and voxel data -# voxel : Dictioanry<String, Variant> : voxel data to use -# face : Vector3 : face of voxel to generate -# bottom_right : Vector3 : grid position of bottom right vertex pertaining to face -# bottom_left : Vector3 : grid position of bottom left vertex pertaining to face, if not given botttom right is used -# top_right : Vector3 : grid position of top right vertex pertaining to face, if not given botttom right is used -# top_left : Vector3 : grid position of top left vertex pertaining to face, if not given botttom right is used -func add_face( - voxel : Dictionary, - face : Vector3, - bottom_right : Vector3, - bottom_left := Vector3.INF, - top_right := Vector3.INF, - top_left := Vector3.INF) -> void: - bottom_right = bottom_right - if bottom_left == Vector3.INF: bottom_left = bottom_right - if top_right == Vector3.INF: top_right = bottom_right - if top_left == Vector3.INF: top_left = bottom_right - - var color := Voxel.get_face_color(voxel, face) - var uv := Voxel.get_face_uv(voxel, face) if _uv_voxels else -Vector2.ONE - var uv_surface := uv != -Vector2.ONE - - var material := Voxel.get_material(voxel) - - var metal := Voxel.get_metallic(voxel) - var specular := Voxel.get_specular(voxel) - var rough := Voxel.get_roughness(voxel) - var energy := Voxel.get_energy(voxel) - var energy_color := Voxel.get_energy_color(voxel) - - var surface_id := str(material) if material > -1 else (str(metal) + "," + str(specular) + "," + str(rough) + "," + str(energy) + "," + str(energy_color)) - if uv_surface: - surface_id += "_uv" - var surface : Surface = _surfaces.get(surface_id) - if not is_instance_valid(surface): - surface = Surface.new() - - surface.material = _voxel_set.get_material(material) if is_instance_valid(_voxel_set) else null - if is_instance_valid(surface.material): - surface.material = surface.material.duplicate() - else: - surface.material = SpatialMaterial.new() - - surface.material.metallic = metal - surface.material.metallic_specular = specular - surface.material.roughness = rough - if energy > 0.0: - surface.material.emission_enabled = true - surface.material.emission = energy_color - surface.material.emission_energy = energy - - if surface.material is SpatialMaterial: - surface.material.vertex_color_use_as_albedo = true - if uv_surface: - surface.material.albedo_texture = _voxel_set.tiles - - _surfaces[surface_id] = surface - - surface.surface_tool.add_normal(face) - surface.surface_tool.add_color(color) - - match face: - Vector3.RIGHT: - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.RIGHT) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_left + Vector3.RIGHT + Vector3.UP) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.ONE) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_left + Vector3.RIGHT) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_right + Vector3.ONE) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.DOWN) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_right + Vector3.RIGHT + Vector3.BACK) * Voxel.VoxelWorldSize) - Vector3.LEFT: - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.DOWN) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_left) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_left + Vector3.UP) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.ONE) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_right + Vector3.BACK) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.RIGHT) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_right + Vector3.UP + Vector3.BACK) * Voxel.VoxelWorldSize) - Vector3.UP: - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.DOWN) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_left + Vector3.UP + Vector3.BACK) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_left + Vector3.UP) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.ONE) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_right + Vector3.ONE) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.RIGHT) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_right + Vector3.RIGHT + Vector3.UP) * Voxel.VoxelWorldSize) - Vector3.DOWN: - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.DOWN) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_right + Vector3.RIGHT + Vector3.BACK) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_right + Vector3.RIGHT) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.ONE) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_left + Vector3.BACK) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.RIGHT) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_left) * Voxel.VoxelWorldSize) - Vector3.FORWARD: - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.ONE) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_right + Vector3.RIGHT) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.RIGHT) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_right + Vector3.RIGHT + Vector3.UP) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.DOWN) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_left) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_left + Vector3.UP) * Voxel.VoxelWorldSize) - Vector3.BACK: - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.RIGHT) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_right + Vector3.ONE) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.ONE) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_right + Vector3.RIGHT + Vector3.BACK) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((top_left + Vector3.UP + Vector3.BACK) * Voxel.VoxelWorldSize) - if uv_surface: - surface.surface_tool.add_uv((uv + Vector2.DOWN) * _voxel_set.uv_scale()) - surface.surface_tool.add_vertex((bottom_left + Vector3.BACK) * Voxel.VoxelWorldSize) - - surface.index += 4 - surface.surface_tool.add_index(surface.index - 4) - surface.surface_tool.add_index(surface.index - 3) - surface.surface_tool.add_index(surface.index - 2) - surface.surface_tool.add_index(surface.index - 3) - surface.surface_tool.add_index(surface.index - 1) - surface.surface_tool.add_index(surface.index - 2) - - -# Adds all the faces of a voxel to Mesh at given position and with voxel data -# voxel : Dictioanry<String, Variant> : voxel data to use -# grid : Vector3 : voxel grid position of voxel -func add_faces(voxel : Dictionary, grid : Vector3) -> void: - for face in Voxel.Faces: - add_face(voxel, face, grid) |