1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-16 14:00:40 +00:00

Merge pull request #61568 from lawnjelly/merge_node

[3.x] Add MergeGroup node to simplify merging Meshes at runtime
This commit is contained in:
Rémi Verschelde
2024-02-07 09:49:45 +01:00
34 changed files with 4179 additions and 602 deletions

View File

@@ -1030,47 +1030,28 @@ void VisualServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int
}
}
void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, uint32_t p_compress_format) {
ERR_FAIL_INDEX(p_primitive, VS::PRIMITIVE_MAX);
ERR_FAIL_COND(p_arrays.size() != VS::ARRAY_MAX);
bool use_split_stream = GLOBAL_GET("rendering/misc/mesh_storage/split_stream") && !(p_compress_format & VS::ARRAY_FLAG_USE_DYNAMIC_UPDATE);
uint32_t format = 0;
// validation
int index_array_len = 0;
int array_len = 0;
// This function is separated from the main mesh_add_surface_from_arrays() to allow finding the format WITHOUT creating data.
// This is necessary for CPU meshes, where we may want to know the final format without creating final data.
bool VisualServer::_mesh_find_format(VS::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, uint32_t p_compress_format, bool p_use_split_stream, uint32_t r_offsets[], int &r_attributes_base_offset, int &r_attributes_stride, int &r_positions_stride, uint32_t &r_format, int &r_index_array_len, int &r_array_len) {
ERR_FAIL_INDEX_V(p_primitive, VS::PRIMITIVE_MAX, false);
ERR_FAIL_COND_V(p_arrays.size() != VS::ARRAY_MAX, false);
for (int i = 0; i < p_arrays.size(); i++) {
if (p_arrays[i].get_type() == Variant::NIL) {
continue;
}
format |= (1 << i);
r_format |= (1 << i);
if (i == VS::ARRAY_VERTEX) {
Variant var = p_arrays[i];
switch (var.get_type()) {
case Variant::POOL_VECTOR2_ARRAY: {
PoolVector<Vector2> v2 = var;
} break;
case Variant::POOL_VECTOR3_ARRAY: {
PoolVector<Vector3> v3 = var;
} break;
default: {
Array v = var;
} break;
}
array_len = PoolVector3Array(p_arrays[i]).size();
ERR_FAIL_COND(array_len == 0);
r_array_len = PoolVector3Array(p_arrays[i]).size();
ERR_FAIL_COND_V(r_array_len == 0, false);
} else if (i == VS::ARRAY_INDEX) {
index_array_len = PoolIntArray(p_arrays[i]).size();
r_index_array_len = PoolIntArray(p_arrays[i]).size();
}
}
ERR_FAIL_COND((format & VS::ARRAY_FORMAT_VERTEX) == 0); // mandatory
ERR_FAIL_COND_V((r_format & VS::ARRAY_FORMAT_VERTEX) == 0, false); // mandatory
if (p_blend_shapes.size()) {
//validate format for morphs
@@ -1083,21 +1064,14 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim
}
}
ERR_FAIL_COND((bsformat) != (format & (VS::ARRAY_FORMAT_INDEX - 1)));
ERR_FAIL_COND_V((bsformat) != (r_format & (VS::ARRAY_FORMAT_INDEX - 1)), false);
}
}
uint32_t offsets[VS::ARRAY_MAX];
uint32_t strides[VS::ARRAY_MAX];
int attributes_base_offset = 0;
int attributes_stride = 0;
int positions_stride = 0;
for (int i = 0; i < VS::ARRAY_MAX; i++) {
offsets[i] = 0; //reset
r_offsets[i] = 0; //reset
if (!(format & (1 << i))) { // no array
if (!(r_format & (1 << i))) { // no array
continue;
}
@@ -1108,15 +1082,15 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim
Variant arr = p_arrays[0];
if (arr.get_type() == Variant::POOL_VECTOR2_ARRAY) {
elem_size = 2;
p_compress_format |= ARRAY_FLAG_USE_2D_VERTICES;
p_compress_format |= VS::ARRAY_FLAG_USE_2D_VERTICES;
} else if (arr.get_type() == Variant::POOL_VECTOR3_ARRAY) {
p_compress_format &= ~ARRAY_FLAG_USE_2D_VERTICES;
p_compress_format &= ~VS::ARRAY_FLAG_USE_2D_VERTICES;
elem_size = 3;
} else {
elem_size = (p_compress_format & ARRAY_FLAG_USE_2D_VERTICES) ? 2 : 3;
elem_size = (p_compress_format & VS::ARRAY_FLAG_USE_2D_VERTICES) ? 2 : 3;
}
if (p_compress_format & ARRAY_COMPRESS_VERTEX) {
if (p_compress_format & VS::ARRAY_COMPRESS_VERTEX) {
elem_size *= sizeof(int16_t);
} else {
elem_size *= sizeof(float);
@@ -1127,94 +1101,94 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim
elem_size = 8;
}
offsets[i] = 0;
positions_stride = elem_size;
if (use_split_stream) {
attributes_base_offset = elem_size * array_len;
r_offsets[i] = 0;
r_positions_stride = elem_size;
if (p_use_split_stream) {
r_attributes_base_offset = elem_size * r_array_len;
} else {
attributes_base_offset = elem_size;
r_attributes_base_offset = elem_size;
}
} break;
case VS::ARRAY_NORMAL: {
if (p_compress_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_compress_format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
// normal will always be oct32 (4 byte) encoded
// UNLESS tangent exists and is also compressed
// then it will be oct16 encoded along with tangent
if ((p_compress_format & ARRAY_COMPRESS_NORMAL) && (format & ARRAY_FORMAT_TANGENT) && (p_compress_format & ARRAY_COMPRESS_TANGENT)) {
if ((p_compress_format & VS::ARRAY_COMPRESS_NORMAL) && (r_format & VS::ARRAY_FORMAT_TANGENT) && (p_compress_format & VS::ARRAY_COMPRESS_TANGENT)) {
elem_size = sizeof(uint8_t) * 2;
} else {
elem_size = sizeof(uint16_t) * 2;
}
} else {
if (p_compress_format & ARRAY_COMPRESS_NORMAL) {
if (p_compress_format & VS::ARRAY_COMPRESS_NORMAL) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 3;
}
}
offsets[i] = attributes_base_offset + attributes_stride;
attributes_stride += elem_size;
r_offsets[i] = r_attributes_base_offset + r_attributes_stride;
r_attributes_stride += elem_size;
} break;
case VS::ARRAY_TANGENT: {
if (p_compress_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_compress_format & ARRAY_COMPRESS_TANGENT && (format & ARRAY_FORMAT_NORMAL) && (p_compress_format & ARRAY_COMPRESS_NORMAL)) {
if (p_compress_format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
if (p_compress_format & VS::ARRAY_COMPRESS_TANGENT && (r_format & VS::ARRAY_FORMAT_NORMAL) && (p_compress_format & VS::ARRAY_COMPRESS_NORMAL)) {
elem_size = sizeof(uint8_t) * 2;
} else {
elem_size = sizeof(uint16_t) * 2;
}
} else {
if (p_compress_format & ARRAY_COMPRESS_TANGENT) {
if (p_compress_format & VS::ARRAY_COMPRESS_TANGENT) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 4;
}
}
offsets[i] = attributes_base_offset + attributes_stride;
attributes_stride += elem_size;
r_offsets[i] = r_attributes_base_offset + r_attributes_stride;
r_attributes_stride += elem_size;
} break;
case VS::ARRAY_COLOR: {
if (p_compress_format & ARRAY_COMPRESS_COLOR) {
if (p_compress_format & VS::ARRAY_COMPRESS_COLOR) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 4;
}
offsets[i] = attributes_base_offset + attributes_stride;
attributes_stride += elem_size;
r_offsets[i] = r_attributes_base_offset + r_attributes_stride;
r_attributes_stride += elem_size;
} break;
case VS::ARRAY_TEX_UV: {
if (p_compress_format & ARRAY_COMPRESS_TEX_UV) {
if (p_compress_format & VS::ARRAY_COMPRESS_TEX_UV) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 2;
}
offsets[i] = attributes_base_offset + attributes_stride;
attributes_stride += elem_size;
r_offsets[i] = r_attributes_base_offset + r_attributes_stride;
r_attributes_stride += elem_size;
} break;
case VS::ARRAY_TEX_UV2: {
if (p_compress_format & ARRAY_COMPRESS_TEX_UV2) {
if (p_compress_format & VS::ARRAY_COMPRESS_TEX_UV2) {
elem_size = sizeof(uint32_t);
} else {
elem_size = sizeof(float) * 2;
}
offsets[i] = attributes_base_offset + attributes_stride;
attributes_stride += elem_size;
r_offsets[i] = r_attributes_base_offset + r_attributes_stride;
r_attributes_stride += elem_size;
} break;
case VS::ARRAY_WEIGHTS: {
if (p_compress_format & ARRAY_COMPRESS_WEIGHTS) {
if (p_compress_format & VS::ARRAY_COMPRESS_WEIGHTS) {
elem_size = sizeof(uint16_t) * 4;
} else {
elem_size = sizeof(float) * 4;
}
offsets[i] = attributes_base_offset + attributes_stride;
attributes_stride += elem_size;
r_offsets[i] = r_attributes_base_offset + r_attributes_stride;
r_attributes_stride += elem_size;
} break;
case VS::ARRAY_BONES: {
@@ -1230,37 +1204,83 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim
}
if (max_bone > 255) {
p_compress_format |= ARRAY_FLAG_USE_16_BIT_BONES;
p_compress_format |= VS::ARRAY_FLAG_USE_16_BIT_BONES;
elem_size = sizeof(uint16_t) * 4;
} else {
p_compress_format &= ~ARRAY_FLAG_USE_16_BIT_BONES;
p_compress_format &= ~VS::ARRAY_FLAG_USE_16_BIT_BONES;
elem_size = sizeof(uint32_t);
}
offsets[i] = attributes_base_offset + attributes_stride;
attributes_stride += elem_size;
r_offsets[i] = r_attributes_base_offset + r_attributes_stride;
r_attributes_stride += elem_size;
} break;
case VS::ARRAY_INDEX: {
if (index_array_len <= 0) {
if (r_index_array_len <= 0) {
ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
break;
}
/* determine whether using 16 or 32 bits indices */
if (array_len >= (1 << 16)) {
if (r_array_len >= (1 << 16)) {
elem_size = 4;
} else {
elem_size = 2;
}
offsets[i] = elem_size;
r_offsets[i] = elem_size;
continue;
}
default: {
ERR_FAIL();
ERR_FAIL_V(false);
}
}
}
uint32_t mask = (1 << VS::ARRAY_MAX) - 1;
r_format |= (~mask) & p_compress_format; //make the full format
return true;
}
uint32_t VisualServer::mesh_find_format_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, uint32_t p_compress_format) {
bool use_split_stream = GLOBAL_GET("rendering/misc/mesh_storage/split_stream") && !(p_compress_format & VS::ARRAY_FLAG_USE_DYNAMIC_UPDATE);
uint32_t offsets[VS::ARRAY_MAX];
int attributes_base_offset = 0;
int attributes_stride = 0;
int positions_stride = 0;
uint32_t format = 0;
// validation
int index_array_len = 0;
int array_len = 0;
bool res = _mesh_find_format(p_primitive, p_arrays, p_blend_shapes, p_compress_format, use_split_stream, offsets, attributes_base_offset, attributes_stride, positions_stride, format, index_array_len, array_len);
ERR_FAIL_COND_V(!res, 0);
return format;
}
void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, uint32_t p_compress_format) {
bool use_split_stream = GLOBAL_GET("rendering/misc/mesh_storage/split_stream") && !(p_compress_format & VS::ARRAY_FLAG_USE_DYNAMIC_UPDATE);
uint32_t offsets[VS::ARRAY_MAX];
int attributes_base_offset = 0;
int attributes_stride = 0;
int positions_stride = 0;
uint32_t format = 0;
// validation
int index_array_len = 0;
int array_len = 0;
bool res = _mesh_find_format(p_primitive, p_arrays, p_blend_shapes, p_compress_format, use_split_stream, offsets, attributes_base_offset, attributes_stride, positions_stride, format, index_array_len, array_len);
ERR_FAIL_COND(!res);
uint32_t strides[VS::ARRAY_MAX];
if (use_split_stream) {
strides[VS::ARRAY_VERTEX] = positions_stride;
for (int i = 1; i < VS::ARRAY_MAX - 1; i++) {
@@ -1272,9 +1292,6 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim
}
}
uint32_t mask = (1 << ARRAY_MAX) - 1;
format |= (~mask) & p_compress_format; //make the full format
int array_size = (positions_stride + attributes_stride) * array_len;
PoolVector<uint8_t> vertex_array;