You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
12 KiB
GDScript

2 years ago
const VoxFile = preload("./VoxFile.gd");
const VoxData = preload("./VoxFormat/VoxData.gd");
const VoxNode = preload("./VoxFormat/VoxNode.gd");
const VoxMaterial = preload("./VoxFormat/VoxMaterial.gd");
const VoxLayer = preload("./VoxFormat/VoxLayer.gd");
const CulledMeshGenerator = preload("./CulledMeshGenerator.gd");
const GreedyMeshGenerator = preload("./GreedyMeshGenerator.gd");
const debug_file = false;
const debug_models = false;
var fileKeyframeIds = [];
func import(source_path, destination_path, options, _platforms, _gen_files):
var scale = 0.1
if options.Scale:
scale = float(options.Scale)
var greedy = true
if options.has("GreedyMeshGenerator"):
greedy = bool(options.GreedyMeshGenerator)
var snaptoground = false
if options.has("SnapToGround"):
snaptoground = bool(options.SnapToGround)
var mergeKeyframes = false
if options.has("FirstKeyframeOnly"):
mergeKeyframes = not bool(options.FirstKeyframeOnly)
var file = FileAccess.open(source_path, FileAccess.READ)
if file == null:
return FileAccess.get_open_error()
var identifier = PackedByteArray([ file.get_8(), file.get_8(), file.get_8(), file.get_8() ]).get_string_from_ascii()
var version = file.get_32()
print('Importing: ', source_path, ' (scale: ', scale, ', file version: ', version, ', greedy mesh: ', greedy, ', snap to ground: ', snaptoground, ')');
var vox = VoxData.new();
if identifier == 'VOX ':
var voxFile = VoxFile.new(file);
while voxFile.has_data_to_read():
read_chunk(vox, voxFile);
file = null
fileKeyframeIds.sort()
var voxel_data = unify_voxels(vox, mergeKeyframes);
var meshes = []
for keyframeVoxels in voxel_data:
if greedy:
meshes.append(GreedyMeshGenerator.new().generate(vox, voxel_data[keyframeVoxels], scale, snaptoground))
else:
meshes.append(CulledMeshGenerator.new().generate(vox, voxel_data[keyframeVoxels], scale, snaptoground))
return meshes
2 years ago
func string_to_vector3(input: String) -> Vector3:
var data = input.split_floats(' ');
return Vector3(data[0], data[1], data[2]);
2 years ago
func byte_to_basis(data: int):
var x_ind = ((data >> 0) & 0x03);
var y_ind = ((data >> 2) & 0x03);
var indexes = [0, 1, 2];
indexes.erase(x_ind);
indexes.erase(y_ind);
var z_ind = indexes[0];
var x_sign = 1 if ((data >> 4) & 0x01) == 0 else -1;
var y_sign = 1 if ((data >> 5) & 0x01) == 0 else -1;
var z_sign = 1 if ((data >> 6) & 0x01) == 0 else -1;
var result = Basis();
result.x[0] = x_sign if x_ind == 0 else 0;
result.x[1] = x_sign if x_ind == 1 else 0;
result.x[2] = x_sign if x_ind == 2 else 0;
result.y[0] = y_sign if y_ind == 0 else 0;
result.y[1] = y_sign if y_ind == 1 else 0;
result.y[2] = y_sign if y_ind == 2 else 0;
result.z[0] = z_sign if z_ind == 0 else 0;
result.z[1] = z_sign if z_ind == 1 else 0;
result.z[2] = z_sign if z_ind == 2 else 0;
return result;
2 years ago
func read_chunk(vox: VoxData, file: VoxFile):
var chunk_id = file.get_string(4);
var chunk_size = file.get_32();
var childChunks = file.get_32()
file.set_chunk_size(chunk_size);
match chunk_id:
'SIZE':
vox.current_index += 1;
var model = vox.get_model();
var x = file.get_32();
var y = file.get_32();
var z = file.get_32();
model.size = Vector3(x, y, z);
if debug_file: print('SIZE ', model.size);
'XYZI':
var model = vox.get_model();
if debug_file: print('XYZI');
for _i in range(file.get_32()):
var x = file.get_8()
var y = file.get_8()
var z = file.get_8()
var c = file.get_8()
var voxel = Vector3(x, y, z)
model.voxels[voxel] = c - 1
if debug_file && debug_models: print('\t', voxel, ' ', c-1);
'RGBA':
vox.colors = []
for _i in range(256):
var r = float(file.get_8() / 255.0)
var g = float(file.get_8() / 255.0)
var b = float(file.get_8() / 255.0)
var a = float(file.get_8() / 255.0)
vox.colors.append(Color(r, g, b, a))
'nTRN':
var node_id = file.get_32();
var attributes = file.get_vox_dict();
var node = VoxNode.new(node_id, attributes);
vox.nodes[node_id] = node;
var child = file.get_32();
node.child_nodes.append(child);
file.get_32();
node.layerId = file.get_32();
var num_of_frames = file.get_32();
if debug_file:
print('nTRN[', node_id, '] -> ', child);
if (!attributes.is_empty()): print('\t', attributes);
if num_of_frames > 0:
node.transforms = {};
for _frame in range(num_of_frames):
var keyframe = 0;
var newTransform = { "position": Vector3(), "rotation": Basis() };
var frame_attributes = file.get_vox_dict();
if (frame_attributes.has('_f')):
keyframe = int(frame_attributes['_f']);
if (frame_attributes.has('_t')):
var trans = frame_attributes['_t'];
newTransform.position = string_to_vector3(trans);
if debug_file: print('\tT: ', newTransform.position);
if (frame_attributes.has('_r')):
var rot = frame_attributes['_r'];
newTransform.rotation = byte_to_basis(int(rot)).inverse();
if debug_file: print('\tR: ', newTransform.rotation);
node.transforms[keyframe] = newTransform;
if not fileKeyframeIds.has(keyframe):
fileKeyframeIds.append(keyframe);
'nGRP':
var node_id = file.get_32();
var attributes = file.get_vox_dict();
var node = VoxNode.new(node_id, attributes);
vox.nodes[node_id] = node;
var num_children = file.get_32();
for _c in num_children:
node.child_nodes.append(file.get_32());
if debug_file:
print('nGRP[', node_id, '] -> ', node.child_nodes);
if (!attributes.is_empty()): print('\t', attributes);
'nSHP':
var node_id = file.get_32();
var attributes = file.get_vox_dict();
var node = VoxNode.new(node_id, attributes);
vox.nodes[node_id] = node;
var num_models = file.get_32();
for _i in range(num_models):
var keyframe = 0;
var modelId = file.get_32();
var model_attributes = file.get_vox_dict();
if (model_attributes.has('_f')):
keyframe = int(model_attributes['_f']);
node.models[keyframe] = modelId;
if not fileKeyframeIds.has(keyframe):
fileKeyframeIds.append(keyframe);
if debug_file:
print('nSHP[', node_id,'] -> ', node.models);
if (!attributes.is_empty()): print('\t', attributes);
'MATL':
var material_id = file.get_32() - 1;
var properties = file.get_vox_dict();
vox.materials[material_id] = VoxMaterial.new(properties);
if debug_file:
print("MATL ", material_id);
print("\t", properties);
'LAYR':
var layer_id = file.get_32();
var attributes = file.get_vox_dict();
var isVisible = true;
if '_hidden' in attributes and attributes['_hidden'] == '1':
isVisible = false;
var layer = VoxLayer.new(layer_id, isVisible);
vox.layers[layer_id] = layer;
_:
if debug_file: print(chunk_id);
file.read_remaining();
2 years ago
func unify_voxels(vox: VoxData, mergeKeyframes: bool):
var node = vox.nodes[0];
var layeredVoxelData = get_layeredVoxels(node, vox, -1, mergeKeyframes)
return layeredVoxelData.getDataMergedFromLayers();
2 years ago
class LayeredVoxelData:
var data_keyframed_layered = {};
func combine(keyframeId, layerId, model):
# Make sure there's space
if not keyframeId in data_keyframed_layered:
data_keyframed_layered[keyframeId] = {}
if not layerId in data_keyframed_layered[keyframeId]:
data_keyframed_layered[keyframeId][layerId] = {}
# Add the model voxels to the data
var offset = (model.size / 2.0).floor();
for voxel in model.voxels:
data_keyframed_layered[keyframeId][layerId][voxel - offset] = model.voxels[voxel];
func combine_data(other):
for keyframeId in other.data_keyframed_layered:
if not keyframeId in data_keyframed_layered:
data_keyframed_layered[keyframeId] = {}
for layerId in other.data_keyframed_layered[keyframeId]:
if not layerId in data_keyframed_layered[keyframeId]:
data_keyframed_layered[keyframeId][layerId] = {}
for voxel in other.data_keyframed_layered[keyframeId][layerId]:
data_keyframed_layered[keyframeId][layerId][voxel] = (
other.data_keyframed_layered[keyframeId][layerId][voxel]);
func transform(transforms):
var new_data = {};
for keyframeId in data_keyframed_layered:
new_data[keyframeId] = {}
var transform = get_input_for_keyframe(keyframeId, transforms);
for layerId in data_keyframed_layered[keyframeId]:
new_data[keyframeId][layerId] = {}
for voxel in data_keyframed_layered[keyframeId][layerId]:
var half_step = Vector3(0.5, 0.5, 0.5);
var new_voxel = (
(transform.rotation * voxel+half_step-half_step).floor() +
transform.position);
new_data[keyframeId][layerId][new_voxel] = (
data_keyframed_layered[keyframeId][layerId][voxel]);
data_keyframed_layered = new_data;
func getDataMergedFromLayers():
# The result of this function
var result = {};
for keyframeId in data_keyframed_layered:
result[keyframeId] = {}
# Merge all layer data in layerId order (highest layer overrides all)
var layerIds = data_keyframed_layered[keyframeId].keys();
layerIds.sort();
for layerId in layerIds:
for voxel in data_keyframed_layered[keyframeId][layerId]:
result[keyframeId][voxel] = data_keyframed_layered[keyframeId][layerId][voxel];
# Return the merged data
return result;
static func get_input_for_keyframe(focusKeyframeId, inputCollection):
var inputKeyframeIds = inputCollection.keys();
inputKeyframeIds.sort();
inputKeyframeIds.reverse();
var result = inputKeyframeIds.back();
for inputKeyframeId in inputKeyframeIds:
if inputKeyframeId <= focusKeyframeId:
result = inputKeyframeId;
break;
return inputCollection[result];
2 years ago
func get_layeredVoxels(node: VoxNode, vox: VoxData, layerId: int, mergeKeyframes: bool):
var result = LayeredVoxelData.new();
# Handle layers (keeping separated and ignoring hidden)
if node.layerId in vox.layers:
if vox.layers[node.layerId].isVisible:
layerId = node.layerId;
else:
return result;
# Add all models in this node
if mergeKeyframes:
for model_index in node.models:
var modelId = node.models[model_index];
var model = vox.models[modelId];
result.combine(0, layerId, model);
elif node.models.size() > 0:
for fileKeyframeId in fileKeyframeIds:
var frameModelId = LayeredVoxelData.get_input_for_keyframe(fileKeyframeId, node.models);
var model = vox.models[frameModelId];
result.combine(fileKeyframeId, layerId, model);
# Process child nodes
for child_index in node.child_nodes:
var child = vox.nodes[child_index];
var child_data = get_layeredVoxels(child, vox, layerId, mergeKeyframes);
result.combine_data(child_data);
# Run transforms
result.transform(node.transforms);
return result;